TianoCore EDK2 master
Loading...
Searching...
No Matches
Mtftp6Wrq.c
Go to the documentation of this file.
1
10#include "Mtftp6Impl.h"
11
25 IN MTFTP6_INSTANCE *Instance,
26 IN UINT16 BlockNum
27 )
28{
29 EFI_MTFTP6_PACKET *Packet;
30 EFI_MTFTP6_TOKEN *Token;
31 NET_BUF *UdpPacket;
32 EFI_STATUS Status;
33 UINT16 DataLen;
34 UINT8 *DataBuf;
35 UINT64 Start;
36
37 //
38 // Allocate net buffer to create data packet.
39 //
40 UdpPacket = NetbufAlloc (Instance->BlkSize + MTFTP6_DATA_HEAD_LEN);
41
42 if (UdpPacket == NULL) {
43 return EFI_OUT_OF_RESOURCES;
44 }
45
47 UdpPacket,
48 MTFTP6_DATA_HEAD_LEN,
49 FALSE
50 );
51 ASSERT (Packet != NULL);
52
53 Packet->Data.OpCode = HTONS (EFI_MTFTP6_OPCODE_DATA);
54 Packet->Data.Block = HTONS (BlockNum);
55
56 //
57 // Read the block from either the buffer or PacketNeeded callback
58 //
59 Token = Instance->Token;
60 DataLen = Instance->BlkSize;
61
62 if (Token->Buffer != NULL) {
63 Start = MultU64x32 (BlockNum - 1, Instance->BlkSize);
64
65 if (Token->BufferSize < Start + Instance->BlkSize) {
66 DataLen = (UINT16)(Token->BufferSize - Start);
67 Instance->LastBlk = BlockNum;
68 Mtftp6SetLastBlockNum (&Instance->BlkList, BlockNum);
69 }
70
71 if (DataLen > 0) {
72 NetbufAllocSpace (UdpPacket, DataLen, FALSE);
73 CopyMem (Packet->Data.Data, (UINT8 *)Token->Buffer + Start, DataLen);
74 }
75 } else {
76 //
77 // Get data from PacketNeeded
78 //
79 DataBuf = NULL;
80 Status = Token->PacketNeeded (&Instance->Mtftp6, Token, &DataLen, (VOID *)&DataBuf);
81
82 if (EFI_ERROR (Status) || (DataLen > Instance->BlkSize)) {
83 if (DataBuf != NULL) {
84 gBS->FreePool (DataBuf);
85 }
86
87 //
88 // The received packet has already been freed.
89 //
91 Instance,
93 (UINT8 *)"User aborted the transfer"
94 );
95
96 return EFI_ABORTED;
97 }
98
99 if (DataLen < Instance->BlkSize) {
100 Instance->LastBlk = BlockNum;
101 Mtftp6SetLastBlockNum (&Instance->BlkList, BlockNum);
102 }
103
104 if (DataLen > 0) {
105 NetbufAllocSpace (UdpPacket, DataLen, FALSE);
106 CopyMem (Packet->Data.Data, DataBuf, DataLen);
107 gBS->FreePool (DataBuf);
108 }
109 }
110
111 //
112 // Reset current retry count of the instance.
113 //
114 Instance->CurRetry = 0;
115
116 return Mtftp6TransmitPacket (Instance, UdpPacket);
117}
118
138 IN MTFTP6_INSTANCE *Instance,
139 IN EFI_MTFTP6_PACKET *Packet,
140 IN UINT32 Len,
141 OUT NET_BUF **UdpPacket,
142 OUT BOOLEAN *IsCompleted
143 )
144{
145 UINT16 AckNum;
146 INTN Expected;
147 UINT64 BlockCounter;
148
149 *IsCompleted = FALSE;
150 AckNum = NTOHS (Packet->Ack.Block[0]);
151 Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
152
153 ASSERT (Expected >= 0);
154
155 //
156 // Get an unwanted ACK, return EFI_SUCCESS to let Mtftp6WrqInput
157 // restart receive.
158 //
159 if (Expected != AckNum) {
160 return EFI_SUCCESS;
161 }
162
163 //
164 // Remove the acked block number, if this is the last block number,
165 // tell the Mtftp6WrqInput to finish the transfer. This is the last
166 // block number if the block range are empty.
167 //
168 Mtftp6RemoveBlockNum (&Instance->BlkList, AckNum, *IsCompleted, &BlockCounter);
169
170 Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
171
172 if (Expected < 0) {
173 //
174 // The block range is empty. It may either because the last
175 // block has been ACKed, or the sequence number just looped back,
176 // that is, there is more than 0xffff blocks.
177 //
178 if (Instance->LastBlk == AckNum) {
179 ASSERT (Instance->LastBlk >= 1);
180 *IsCompleted = TRUE;
181 return EFI_SUCCESS;
182 } else {
183 //
184 // Free the received packet before send new packet in ReceiveNotify,
185 // since the udpio might need to be reconfigured.
186 //
187 NetbufFree (*UdpPacket);
188 *UdpPacket = NULL;
189 //
190 // Send the Mtftp6 error message if block number rolls back.
191 //
193 Instance,
195 (UINT8 *)"Block number rolls back, not supported, try blksize option"
196 );
197
198 return EFI_TFTP_ERROR;
199 }
200 }
201
202 //
203 // Free the receive buffer before send new packet since it might need
204 // reconfigure udpio.
205 //
206 NetbufFree (*UdpPacket);
207 *UdpPacket = NULL;
208
209 return Mtftp6WrqSendBlock (Instance, (UINT16)Expected);
210}
211
227BOOLEAN
229 IN MTFTP6_EXT_OPTION_INFO *ReplyInfo,
230 IN MTFTP6_EXT_OPTION_INFO *RequestInfo
231 )
232{
233 //
234 // It is invalid for server to return options we don't request
235 //
236 if ((ReplyInfo->BitMap & ~RequestInfo->BitMap) != 0) {
237 return FALSE;
238 }
239
240 //
241 // Server can only specify a smaller block size to be used and
242 // return the timeout matches that requested.
243 //
244 if ((((ReplyInfo->BitMap & MTFTP6_OPT_BLKSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||
245 (((ReplyInfo->BitMap & MTFTP6_OPT_TIMEOUT_BIT) != 0) && (ReplyInfo->Timeout != RequestInfo->Timeout))
246 )
247 {
248 return FALSE;
249 }
250
251 return TRUE;
252}
253
271 IN MTFTP6_INSTANCE *Instance,
272 IN EFI_MTFTP6_PACKET *Packet,
273 IN UINT32 Len,
274 OUT NET_BUF **UdpPacket,
275 OUT BOOLEAN *IsCompleted
276 )
277{
278 EFI_MTFTP6_OPTION *Options;
279 UINT32 Count;
281 EFI_MTFTP6_PACKET Dummy;
282 EFI_STATUS Status;
283 INTN Expected;
284
285 *IsCompleted = FALSE;
286 Options = NULL;
287
288 //
289 // Ignore the OACK if already started the upload
290 //
291 Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
292
293 if (Expected != 0) {
294 return EFI_SUCCESS;
295 }
296
297 //
298 // Parse and validate the options from server
299 //
300 ZeroMem (&ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));
301
302 Status = Mtftp6ParseStart (Packet, Len, &Count, &Options);
303
304 if (EFI_ERROR (Status)) {
305 return Status;
306 }
307
308 ASSERT (Options != NULL);
309
310 Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, Instance->Operation, &ExtInfo);
311
312 if (EFI_ERROR (Status) || !Mtftp6WrqOackValid (&ExtInfo, &Instance->ExtInfo)) {
313 //
314 // Don't send a MTFTP error packet when out of resource, it can
315 // only make it worse.
316 //
317 if (Status != EFI_OUT_OF_RESOURCES) {
318 //
319 // Free the received packet before send new packet in ReceiveNotify,
320 // since the udpio might need to be reconfigured.
321 //
322 NetbufFree (*UdpPacket);
323 *UdpPacket = NULL;
324 //
325 // Send the Mtftp6 error message if invalid Oack packet received.
326 //
328 Instance,
330 (UINT8 *)"Malformatted OACK packet"
331 );
332 }
333
334 return EFI_TFTP_ERROR;
335 }
336
337 if (ExtInfo.BlkSize != 0) {
338 Instance->BlkSize = ExtInfo.BlkSize;
339 }
340
341 if (ExtInfo.Timeout != 0) {
342 Instance->Timeout = ExtInfo.Timeout;
343 }
344
345 //
346 // Build a bogus ACK0 packet then pass it to the Mtftp6WrqHandleAck,
347 // which will start the transmission of the first data block.
348 //
349 Dummy.Ack.OpCode = HTONS (EFI_MTFTP6_OPCODE_ACK);
350 Dummy.Ack.Block[0] = 0;
351
352 return Mtftp6WrqHandleAck (
353 Instance,
354 &Dummy,
355 sizeof (EFI_MTFTP6_ACK_HEADER),
356 UdpPacket,
357 IsCompleted
358 );
359}
360
370VOID
371EFIAPI
373 IN NET_BUF *UdpPacket,
374 IN UDP_END_POINT *UdpEpt,
375 IN EFI_STATUS IoStatus,
376 IN VOID *Context
377 )
378{
379 MTFTP6_INSTANCE *Instance;
380 EFI_MTFTP6_PACKET *Packet;
381 BOOLEAN IsCompleted;
382 EFI_STATUS Status;
383 UINT32 TotalNum;
384 UINT32 Len;
385 UINT16 Opcode;
386
387 Instance = (MTFTP6_INSTANCE *)Context;
388
389 NET_CHECK_SIGNATURE (Instance, MTFTP6_INSTANCE_SIGNATURE);
390
391 IsCompleted = FALSE;
392 Packet = NULL;
393 Status = EFI_SUCCESS;
394 TotalNum = 0;
395
396 //
397 // Return error status if Udp6 instance failed to receive.
398 //
399 if (EFI_ERROR (IoStatus)) {
400 Status = IoStatus;
401 goto ON_EXIT;
402 }
403
404 ASSERT (UdpPacket != NULL);
405
406 if (UdpPacket->TotalSize < MTFTP6_OPCODE_LEN) {
407 goto ON_EXIT;
408 }
409
410 //
411 // Client send initial request to server's listening port. Server
412 // will select a UDP port to communicate with the client.
413 //
414 if (UdpEpt->RemotePort != Instance->ServerDataPort) {
415 if (Instance->ServerDataPort != 0) {
416 goto ON_EXIT;
417 } else {
418 Instance->ServerDataPort = UdpEpt->RemotePort;
419 }
420 }
421
422 //
423 // Copy the MTFTP packet to a continuous buffer if it isn't already so.
424 //
425 Len = UdpPacket->TotalSize;
426 TotalNum = UdpPacket->BlockOpNum;
427
428 if (TotalNum > 1) {
429 Packet = AllocateZeroPool (Len);
430
431 if (Packet == NULL) {
432 Status = EFI_OUT_OF_RESOURCES;
433 goto ON_EXIT;
434 }
435
436 NetbufCopy (UdpPacket, 0, Len, (UINT8 *)Packet);
437 } else {
438 Packet = (EFI_MTFTP6_PACKET *)NetbufGetByte (UdpPacket, 0, NULL);
439 ASSERT (Packet != NULL);
440 }
441
442 Opcode = NTOHS (Packet->OpCode);
443
444 //
445 // Callback to the user's CheckPacket if provided. Abort the transmission
446 // if CheckPacket returns an EFI_ERROR code.
447 //
448 if ((Instance->Token->CheckPacket != NULL) &&
449 ((Opcode == EFI_MTFTP6_OPCODE_OACK) || (Opcode == EFI_MTFTP6_OPCODE_ERROR))
450 )
451 {
452 Status = Instance->Token->CheckPacket (
453 &Instance->Mtftp6,
454 Instance->Token,
455 (UINT16)Len,
456 Packet
457 );
458
459 if (EFI_ERROR (Status)) {
460 //
461 // Send an error message to the server to inform it
462 //
463 if (Opcode != EFI_MTFTP6_OPCODE_ERROR) {
464 //
465 // Free the received packet before send new packet in ReceiveNotify,
466 // since the udpio might need to be reconfigured.
467 //
468 NetbufFree (UdpPacket);
469 UdpPacket = NULL;
470 //
471 // Send the Mtftp6 error message if user aborted the current session.
472 //
474 Instance,
476 (UINT8 *)"User aborted the transfer"
477 );
478 }
479
480 Status = EFI_ABORTED;
481 goto ON_EXIT;
482 }
483 }
484
485 //
486 // Switch the process routines by the operation code.
487 //
488 switch (Opcode) {
490 if (Len != MTFTP6_OPCODE_LEN + MTFTP6_BLKNO_LEN) {
491 goto ON_EXIT;
492 }
493
494 //
495 // Handle the Ack packet of Wrq.
496 //
497 Status = Mtftp6WrqHandleAck (Instance, Packet, Len, &UdpPacket, &IsCompleted);
498 break;
499
501 if (Len <= MTFTP6_OPCODE_LEN) {
502 goto ON_EXIT;
503 }
504
505 //
506 // Handle the Oack packet of Wrq.
507 //
508 Status = Mtftp6WrqHandleOack (Instance, Packet, Len, &UdpPacket, &IsCompleted);
509 break;
510
511 default:
512 //
513 // Drop and return eror if received error message.
514 //
515 Status = EFI_TFTP_ERROR;
516 break;
517 }
518
519ON_EXIT:
520 //
521 // Free the resources, then if !EFI_ERROR (Status) and not completed,
522 // restart the receive, otherwise end the session.
523 //
524 if ((Packet != NULL) && (TotalNum > 1)) {
525 FreePool (Packet);
526 }
527
528 if (UdpPacket != NULL) {
529 NetbufFree (UdpPacket);
530 }
531
532 if (!EFI_ERROR (Status) && !IsCompleted) {
533 Status = UdpIoRecvDatagram (
534 Instance->UdpIo,
536 Instance,
537 0
538 );
539 }
540
541 //
542 // Clean up the current session if failed to continue.
543 //
544 if (EFI_ERROR (Status) || IsCompleted) {
545 Mtftp6OperationClean (Instance, Status);
546 }
547}
548
562 IN MTFTP6_INSTANCE *Instance,
563 IN UINT16 Operation
564 )
565{
566 EFI_STATUS Status;
567
568 //
569 // The valid block number range are [0, 0xffff]. For example:
570 // the client sends an WRQ request to the server, the server
571 // ACK with an ACK0 to let client start transfer the first
572 // packet.
573 //
574 Status = Mtftp6InitBlockRange (&Instance->BlkList, 0, 0xffff);
575
576 if (EFI_ERROR (Status)) {
577 return Status;
578 }
579
580 Status = Mtftp6SendRequest (Instance, Operation);
581
582 if (EFI_ERROR (Status)) {
583 return Status;
584 }
585
586 return UdpIoRecvDatagram (
587 Instance->UdpIo,
589 Instance,
590 0
591 );
592}
INT64 INTN
UINT64 EFIAPI MultU64x32(IN UINT64 Multiplicand, IN UINT32 Multiplier)
Definition: MultU64x32.c:27
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define EFI_MTFTP6_OPCODE_ERROR
The MTFTPv6 packet is an error packet.
Definition: Mtftp6.h:39
#define EFI_MTFTP6_OPCODE_OACK
The MTFTPv6 packet is an option acknowledgement packet.
Definition: Mtftp6.h:40
#define EFI_MTFTP6_OPCODE_ACK
The MTFTPv6 packet is an acknowledgement packet.
Definition: Mtftp6.h:38
#define EFI_MTFTP6_ERRORCODE_REQUEST_DENIED
Definition: Mtftp6.h:84
#define EFI_MTFTP6_OPCODE_DATA
The MTFTPv6 packet is a data packet.
Definition: Mtftp6.h:37
#define EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION
Definition: Mtftp6.h:68
EFI_STATUS Mtftp6ParseExtensionOption(IN EFI_MTFTP6_OPTION *Options, IN UINT32 Count, IN BOOLEAN IsRequest, IN UINT16 Operation, IN MTFTP6_EXT_OPTION_INFO *ExtInfo)
Definition: Mtftp6Option.c:147
EFI_STATUS Mtftp6ParseStart(IN EFI_MTFTP6_PACKET *Packet, IN UINT32 PacketLen, IN OUT UINT32 *OptionCount, OUT EFI_MTFTP6_OPTION **OptionList OPTIONAL)
Definition: Mtftp6Option.c:340
EFI_STATUS Mtftp6RemoveBlockNum(IN LIST_ENTRY *Head, IN UINT16 Num, IN BOOLEAN Completed, OUT UINT64 *BlockCounter)
EFI_STATUS Mtftp6SendError(IN MTFTP6_INSTANCE *Instance, IN UINT16 ErrCode, IN UINT8 *ErrInfo)
EFI_STATUS Mtftp6TransmitPacket(IN MTFTP6_INSTANCE *Instance, IN NET_BUF *Packet)
EFI_STATUS Mtftp6SendRequest(IN MTFTP6_INSTANCE *Instance, IN UINT16 Operation)
INTN Mtftp6GetNextBlockNum(IN LIST_ENTRY *Head)
Definition: Mtftp6Support.c:92
EFI_STATUS Mtftp6InitBlockRange(IN LIST_ENTRY *Head, IN UINT16 Start, IN UINT16 End)
Definition: Mtftp6Support.c:64
VOID Mtftp6SetLastBlockNum(IN LIST_ENTRY *Head, IN UINT16 Last)
VOID Mtftp6OperationClean(IN MTFTP6_INSTANCE *Instance, IN EFI_STATUS Result)
VOID EFIAPI Mtftp6WrqInput(IN NET_BUF *UdpPacket, IN UDP_END_POINT *UdpEpt, IN EFI_STATUS IoStatus, IN VOID *Context)
Definition: Mtftp6Wrq.c:372
BOOLEAN Mtftp6WrqOackValid(IN MTFTP6_EXT_OPTION_INFO *ReplyInfo, IN MTFTP6_EXT_OPTION_INFO *RequestInfo)
Definition: Mtftp6Wrq.c:228
EFI_STATUS Mtftp6WrqHandleAck(IN MTFTP6_INSTANCE *Instance, IN EFI_MTFTP6_PACKET *Packet, IN UINT32 Len, OUT NET_BUF **UdpPacket, OUT BOOLEAN *IsCompleted)
Definition: Mtftp6Wrq.c:137
EFI_STATUS Mtftp6WrqHandleOack(IN MTFTP6_INSTANCE *Instance, IN EFI_MTFTP6_PACKET *Packet, IN UINT32 Len, OUT NET_BUF **UdpPacket, OUT BOOLEAN *IsCompleted)
Definition: Mtftp6Wrq.c:270
EFI_STATUS Mtftp6WrqSendBlock(IN MTFTP6_INSTANCE *Instance, IN UINT16 BlockNum)
Definition: Mtftp6Wrq.c:24
EFI_STATUS Mtftp6WrqStart(IN MTFTP6_INSTANCE *Instance, IN UINT16 Operation)
Definition: Mtftp6Wrq.c:561
VOID EFIAPI NetbufFree(IN NET_BUF *Nbuf)
Definition: NetBuffer.c:195
UINT32 EFIAPI NetbufCopy(IN NET_BUF *Nbuf, IN UINT32 Offset, IN UINT32 Len, IN UINT8 *Dest)
Definition: NetBuffer.c:1206
NET_BUF *EFIAPI NetbufAlloc(IN UINT32 Len)
Definition: NetBuffer.c:89
UINT8 *EFIAPI NetbufAllocSpace(IN OUT NET_BUF *Nbuf, IN UINT32 Len, IN BOOLEAN FromHead)
Definition: NetBuffer.c:1015
UINT8 *EFIAPI NetbufGetByte(IN NET_BUF *Nbuf, IN UINT32 Offset, OUT UINT32 *Index OPTIONAL)
Definition: NetBuffer.c:359
EFI_STATUS EFIAPI UdpIoRecvDatagram(IN UDP_IO *UdpIo, IN UDP_IO_CALLBACK CallBack, IN VOID *Context, IN UINT32 HeadLen)
Definition: DxeUdpIoLib.c:1084
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
UINT64 BufferSize
Definition: Mtftp6.h:430
EFI_MTFTP6_PACKET_NEEDED PacketNeeded
Definition: Mtftp6.h:455
VOID * Buffer
Definition: Mtftp6.h:436
EFI_MTFTP6_CHECK_PACKET CheckPacket
Definition: Mtftp6.h:446
UINT16 Block[1]
Definition: Mtftp6.h:147
EFI_MTFTP6_DATA_HEADER Data
Data packet header.
Definition: Mtftp6.h:208
EFI_MTFTP6_ACK_HEADER Ack
Acknowledgement packet header.
Definition: Mtftp6.h:209
UINT16 OpCode
Type of packets as defined by the MTFTPv6 packet opcodes.
Definition: Mtftp6.h:204