TianoCore EDK2 master
Loading...
Searching...
No Matches
Mtftp4Support.c
Go to the documentation of this file.
1
9#include "Mtftp4Impl.h"
10
22 IN UINT16 Start,
23 IN UINT16 End
24 )
25{
26 MTFTP4_BLOCK_RANGE *Range;
27
28 Range = AllocateZeroPool (sizeof (MTFTP4_BLOCK_RANGE));
29
30 if (Range == NULL) {
31 return NULL;
32 }
33
34 InitializeListHead (&Range->Link);
35 Range->Start = Start;
36 Range->End = End;
37 Range->Bound = End;
38
39 return Range;
40}
41
65 IN LIST_ENTRY *Head,
66 IN UINT16 Start,
67 IN UINT16 End
68 )
69{
70 MTFTP4_BLOCK_RANGE *Range;
71
72 Range = Mtftp4AllocateRange (Start, End);
73
74 if (Range == NULL) {
75 return EFI_OUT_OF_RESOURCES;
76 }
77
78 InsertTailList (Head, &Range->Link);
79 return EFI_SUCCESS;
80}
81
90INTN
92 IN LIST_ENTRY *Head
93 )
94{
95 MTFTP4_BLOCK_RANGE *Range;
96
97 if (IsListEmpty (Head)) {
98 return -1;
99 }
100
101 Range = NET_LIST_HEAD (Head, MTFTP4_BLOCK_RANGE, Link);
102 return Range->Start;
103}
104
116VOID
118 IN LIST_ENTRY *Head,
119 IN UINT16 Last
120 )
121{
122 MTFTP4_BLOCK_RANGE *Range;
123
124 //
125 // Iterate from the tail to head to remove the block number
126 // after the last.
127 //
128 while (!IsListEmpty (Head)) {
129 Range = NET_LIST_TAIL (Head, MTFTP4_BLOCK_RANGE, Link);
130
131 if (Range->Start > Last) {
132 RemoveEntryList (&Range->Link);
133 FreePool (Range);
134 continue;
135 }
136
137 if (Range->End > Last) {
138 Range->End = Last;
139 }
140
141 return;
142 }
143}
144
160 IN LIST_ENTRY *Head,
161 IN UINT16 Num,
162 IN BOOLEAN Completed,
163 OUT UINT64 *BlockCounter
164 )
165{
166 MTFTP4_BLOCK_RANGE *Range;
167 MTFTP4_BLOCK_RANGE *NewRange;
168 LIST_ENTRY *Entry;
169
170 NET_LIST_FOR_EACH (Entry, Head) {
171 //
172 // Each block represents a hole [Start, End] in the file,
173 // skip to the first range with End >= Num
174 //
175 Range = NET_LIST_USER_STRUCT (Entry, MTFTP4_BLOCK_RANGE, Link);
176
177 if (Range->End < Num) {
178 continue;
179 }
180
181 //
182 // There are three different cases for Start
183 // 1. (Start > Num) && (End >= Num):
184 // because all the holes before this one has the condition of
185 // End < Num, so this block number has been removed.
186 //
187 // 2. (Start == Num) && (End >= Num):
188 // Need to increase the Start by one, and if End == Num, this
189 // hole has been removed completely, remove it.
190 //
191 // 3. (Start < Num) && (End >= Num):
192 // if End == Num, only need to decrease the End by one because
193 // we have (Start < Num) && (Num == End), so (Start <= End - 1).
194 // if (End > Num), the hold is split into two holes, with
195 // [Start, Num - 1] and [Num + 1, End].
196 //
197 if (Range->Start > Num) {
198 return EFI_NOT_FOUND;
199 } else if (Range->Start == Num) {
200 Range->Start++;
201
202 //
203 // Note that: RFC 1350 does not mention block counter roll-over,
204 // but several TFTP hosts implement the roll-over be able to accept
205 // transfers of unlimited size. There is no consensus, however, whether
206 // the counter should wrap around to zero or to one. Many implementations
207 // wrap to zero, because this is the simplest to implement. Here we choose
208 // this solution.
209 //
210 *BlockCounter = Num;
211
212 if (Range->Round > 0) {
213 *BlockCounter += Range->Bound + MultU64x32 ((UINTN)(Range->Round -1), (UINT32)(Range->Bound + 1)) + 1;
214 }
215
216 if (Range->Start > Range->Bound) {
217 Range->Start = 0;
218 Range->Round++;
219 }
220
221 if ((Range->Start > Range->End) || Completed) {
222 RemoveEntryList (&Range->Link);
223 FreePool (Range);
224 }
225
226 return EFI_SUCCESS;
227 } else {
228 if (Range->End == Num) {
229 Range->End--;
230 } else {
231 NewRange = Mtftp4AllocateRange ((UINT16)(Num + 1), (UINT16)Range->End);
232
233 if (NewRange == NULL) {
234 return EFI_OUT_OF_RESOURCES;
235 }
236
237 Range->End = Num - 1;
238 NetListInsertAfter (&Range->Link, &NewRange->Link);
239 }
240
241 return EFI_SUCCESS;
242 }
243 }
244
245 return EFI_NOT_FOUND;
246}
247
260 IN MTFTP4_PROTOCOL *Instance
261 )
262{
263 EFI_MTFTP4_PACKET *Packet;
264 EFI_MTFTP4_OPTION *Options;
265 EFI_MTFTP4_TOKEN *Token;
266 RETURN_STATUS Status;
267 NET_BUF *Nbuf;
268 UINT8 *Mode;
269 UINT8 *Cur;
270 UINTN Index;
271 UINT32 BufferLength;
272 UINTN FileNameLength;
273 UINTN ModeLength;
274 UINTN OptionStrLength;
275 UINTN ValueStrLength;
276
277 Token = Instance->Token;
278 Options = Token->OptionList;
279 Mode = Instance->Token->ModeStr;
280
281 if (Mode == NULL) {
282 Mode = (UINT8 *)"octet";
283 }
284
285 //
286 // Compute the packet length
287 //
288 FileNameLength = AsciiStrLen ((CHAR8 *)Token->Filename);
289 ModeLength = AsciiStrLen ((CHAR8 *)Mode);
290 BufferLength = (UINT32)FileNameLength + (UINT32)ModeLength + 4;
291
292 for (Index = 0; Index < Token->OptionCount; Index++) {
293 OptionStrLength = AsciiStrLen ((CHAR8 *)Options[Index].OptionStr);
294 ValueStrLength = AsciiStrLen ((CHAR8 *)Options[Index].ValueStr);
295 BufferLength += (UINT32)OptionStrLength + (UINT32)ValueStrLength + 2;
296 }
297
298 //
299 // Allocate a packet then copy the data over
300 //
301 if ((Nbuf = NetbufAlloc (BufferLength)) == NULL) {
302 return EFI_OUT_OF_RESOURCES;
303 }
304
305 Packet = (EFI_MTFTP4_PACKET *)NetbufAllocSpace (Nbuf, BufferLength, FALSE);
306 ASSERT (Packet != NULL);
307
308 Packet->OpCode = HTONS (Instance->Operation);
309 BufferLength -= sizeof (Packet->OpCode);
310
311 Cur = Packet->Rrq.Filename;
312 Status = AsciiStrCpyS ((CHAR8 *)Cur, BufferLength, (CHAR8 *)Token->Filename);
313 ASSERT_EFI_ERROR (Status);
314 BufferLength -= (UINT32)(FileNameLength + 1);
315 Cur += FileNameLength + 1;
316 Status = AsciiStrCpyS ((CHAR8 *)Cur, BufferLength, (CHAR8 *)Mode);
317 ASSERT_EFI_ERROR (Status);
318 BufferLength -= (UINT32)(ModeLength + 1);
319 Cur += ModeLength + 1;
320
321 for (Index = 0; Index < Token->OptionCount; ++Index) {
322 OptionStrLength = AsciiStrLen ((CHAR8 *)Options[Index].OptionStr);
323 ValueStrLength = AsciiStrLen ((CHAR8 *)Options[Index].ValueStr);
324
325 Status = AsciiStrCpyS ((CHAR8 *)Cur, BufferLength, (CHAR8 *)Options[Index].OptionStr);
326 ASSERT_EFI_ERROR (Status);
327 BufferLength -= (UINT32)(OptionStrLength + 1);
328 Cur += OptionStrLength + 1;
329
330 Status = AsciiStrCpyS ((CHAR8 *)Cur, BufferLength, (CHAR8 *)Options[Index].ValueStr);
331 ASSERT_EFI_ERROR (Status);
332 BufferLength -= (UINT32)(ValueStrLength + 1);
333 Cur += ValueStrLength + 1;
334 }
335
336 return Mtftp4SendPacket (Instance, Nbuf);
337}
338
353 IN MTFTP4_PROTOCOL *Instance,
354 IN UINT16 ErrCode,
355 IN UINT8 *ErrInfo
356 )
357{
358 NET_BUF *Packet;
359 EFI_MTFTP4_PACKET *TftpError;
360 UINT32 Len;
361
362 Len = (UINT32)(AsciiStrLen ((CHAR8 *)ErrInfo) + sizeof (EFI_MTFTP4_ERROR_HEADER));
363 Packet = NetbufAlloc (Len);
364 if (Packet == NULL) {
365 return EFI_OUT_OF_RESOURCES;
366 }
367
368 TftpError = (EFI_MTFTP4_PACKET *)NetbufAllocSpace (Packet, Len, FALSE);
369 ASSERT (TftpError != NULL);
370
371 TftpError->OpCode = HTONS (EFI_MTFTP4_OPCODE_ERROR);
372 TftpError->Error.ErrorCode = HTONS (ErrCode);
373
374 AsciiStrCpyS ((CHAR8 *)TftpError->Error.ErrorMessage, Len, (CHAR8 *)ErrInfo);
375
376 return Mtftp4SendPacket (Instance, Packet);
377}
378
390VOID
391EFIAPI
393 IN NET_BUF *Packet,
394 IN UDP_END_POINT *EndPoint,
395 IN EFI_STATUS IoStatus,
396 IN VOID *Context
397 )
398{
399 NetbufFree (Packet);
400}
401
408VOID
410 IN OUT MTFTP4_PROTOCOL *Instance
411 )
412{
413 if (Instance->Master) {
414 Instance->PacketToLive = Instance->Timeout;
415 } else {
416 Instance->PacketToLive = Instance->Timeout * 2;
417 }
418}
419
436 IN OUT MTFTP4_PROTOCOL *Instance,
437 IN OUT NET_BUF *Packet
438 )
439{
440 UDP_END_POINT UdpPoint;
441 EFI_STATUS Status;
442 UINT16 OpCode;
443 UINT8 *Buffer;
444
445 //
446 // Save the packet for retransmission
447 //
448 if (Instance->LastPacket != NULL) {
449 NetbufFree (Instance->LastPacket);
450 }
451
452 Instance->LastPacket = Packet;
453
454 Instance->CurRetry = 0;
455 Mtftp4SetTimeout (Instance);
456
457 ZeroMem (&UdpPoint, sizeof (UdpPoint));
458 UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;
459
460 //
461 // Send the requests to the listening port, other packets
462 // to the connected port
463 //
464 Buffer = NetbufGetByte (Packet, 0, NULL);
465 ASSERT (Buffer != NULL);
466 OpCode = NTOHS (*(UINT16 *)Buffer);
467
468 if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) ||
469 (OpCode == EFI_MTFTP4_OPCODE_DIR) ||
470 (OpCode == EFI_MTFTP4_OPCODE_WRQ))
471 {
472 UdpPoint.RemotePort = Instance->ListeningPort;
473 } else {
474 UdpPoint.RemotePort = Instance->ConnectedPort;
475 }
476
477 NET_GET_REF (Packet);
478
479 Status = UdpIoSendDatagram (
480 Instance->UnicastPort,
481 Packet,
482 &UdpPoint,
483 NULL,
485 Instance
486 );
487
488 if (EFI_ERROR (Status)) {
489 NET_PUT_REF (Packet);
490 }
491
492 return Status;
493}
494
506 IN MTFTP4_PROTOCOL *Instance
507 )
508{
509 UDP_END_POINT UdpPoint;
510 EFI_STATUS Status;
511 UINT16 OpCode;
512 UINT8 *Buffer;
513
514 ASSERT (Instance->LastPacket != NULL);
515
516 ZeroMem (&UdpPoint, sizeof (UdpPoint));
517 UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;
518
519 //
520 // Set the requests to the listening port, other packets to the connected port
521 //
522 Buffer = NetbufGetByte (Instance->LastPacket, 0, NULL);
523 ASSERT (Buffer != NULL);
524 OpCode = NTOHS (*(UINT16 *)Buffer);
525
526 if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||
527 (OpCode == EFI_MTFTP4_OPCODE_WRQ))
528 {
529 UdpPoint.RemotePort = Instance->ListeningPort;
530 } else {
531 UdpPoint.RemotePort = Instance->ConnectedPort;
532 }
533
534 NET_GET_REF (Instance->LastPacket);
535
536 Status = UdpIoSendDatagram (
537 Instance->UnicastPort,
538 Instance->LastPacket,
539 &UdpPoint,
540 NULL,
542 Instance
543 );
544
545 if (EFI_ERROR (Status)) {
546 NET_PUT_REF (Instance->LastPacket);
547 }
548
549 return Status;
550}
551
559VOID
560EFIAPI
562 IN EFI_EVENT Event,
563 IN VOID *Context
564 )
565{
566 MTFTP4_SERVICE *MtftpSb;
567 LIST_ENTRY *Entry;
568 LIST_ENTRY *Next;
569 MTFTP4_PROTOCOL *Instance;
570
571 MtftpSb = (MTFTP4_SERVICE *)Context;
572
573 //
574 // Iterate through all the children of the Mtftp service instance. Time
575 // out the current packet transmit.
576 //
577 NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {
578 Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);
579 if ((Instance->PacketToLive == 0) || (--Instance->PacketToLive > 0)) {
580 Instance->HasTimeout = FALSE;
581 } else {
582 Instance->HasTimeout = TRUE;
583 }
584 }
585}
586
594VOID
595EFIAPI
597 IN EFI_EVENT Event,
598 IN VOID *Context
599 )
600{
601 MTFTP4_SERVICE *MtftpSb;
602 LIST_ENTRY *Entry;
603 LIST_ENTRY *Next;
604 MTFTP4_PROTOCOL *Instance;
605 EFI_MTFTP4_TOKEN *Token;
606
607 MtftpSb = (MTFTP4_SERVICE *)Context;
608
609 //
610 // Iterate through all the children of the Mtftp service instance.
611 //
612 NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {
613 Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);
614 if (!Instance->HasTimeout) {
615 continue;
616 }
617
618 Instance->HasTimeout = FALSE;
619
620 //
621 // Call the user's time out handler
622 //
623 Token = Instance->Token;
624
625 if ((Token != NULL) && (Token->TimeoutCallback != NULL) &&
626 EFI_ERROR (Token->TimeoutCallback (&Instance->Mtftp4, Token)))
627 {
629 Instance,
630 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
631 (UINT8 *)"User aborted the transfer in time out"
632 );
633
634 Mtftp4CleanOperation (Instance, EFI_ABORTED);
635 continue;
636 }
637
638 //
639 // Retransmit the packet if haven't reach the maximum retry count,
640 // otherwise exit the transfer.
641 //
642 if (++Instance->CurRetry < Instance->MaxRetry) {
643 Mtftp4Retransmit (Instance);
644 Mtftp4SetTimeout (Instance);
645 } else {
646 Mtftp4CleanOperation (Instance, EFI_TIMEOUT);
647 continue;
648 }
649 }
650}
UINT64 UINTN
INT64 INTN
BOOLEAN EFIAPI IsListEmpty(IN CONST LIST_ENTRY *ListHead)
Definition: LinkedList.c:403
UINTN EFIAPI AsciiStrLen(IN CONST CHAR8 *String)
Definition: String.c:641
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
UINT64 EFIAPI MultU64x32(IN UINT64 Multiplicand, IN UINT32 Multiplier)
Definition: MultU64x32.c:27
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
RETURN_STATUS EFIAPI AsciiStrCpyS(OUT CHAR8 *Destination, IN UINTN DestMax, IN CONST CHAR8 *Source)
Definition: SafeString.c:1797
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
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 ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
VOID Mtftp4CleanOperation(IN OUT MTFTP4_PROTOCOL *Instance, IN EFI_STATUS Result)
Definition: Mtftp4Impl.c:20
EFI_STATUS Mtftp4Retransmit(IN MTFTP4_PROTOCOL *Instance)
VOID EFIAPI Mtftp4OnPacketSent(IN NET_BUF *Packet, IN UDP_END_POINT *EndPoint, IN EFI_STATUS IoStatus, IN VOID *Context)
MTFTP4_BLOCK_RANGE * Mtftp4AllocateRange(IN UINT16 Start, IN UINT16 End)
Definition: Mtftp4Support.c:21
EFI_STATUS Mtftp4InitBlockRange(IN LIST_ENTRY *Head, IN UINT16 Start, IN UINT16 End)
Definition: Mtftp4Support.c:64
VOID Mtftp4SetLastBlockNum(IN LIST_ENTRY *Head, IN UINT16 Last)
EFI_STATUS Mtftp4SendRequest(IN MTFTP4_PROTOCOL *Instance)
VOID Mtftp4SetTimeout(IN OUT MTFTP4_PROTOCOL *Instance)
VOID EFIAPI Mtftp4OnTimerTickNotifyLevel(IN EFI_EVENT Event, IN VOID *Context)
INTN Mtftp4GetNextBlockNum(IN LIST_ENTRY *Head)
Definition: Mtftp4Support.c:91
EFI_STATUS Mtftp4SendError(IN MTFTP4_PROTOCOL *Instance, IN UINT16 ErrCode, IN UINT8 *ErrInfo)
EFI_STATUS Mtftp4RemoveBlockNum(IN LIST_ENTRY *Head, IN UINT16 Num, IN BOOLEAN Completed, OUT UINT64 *BlockCounter)
VOID EFIAPI Mtftp4OnTimerTick(IN EFI_EVENT Event, IN VOID *Context)
EFI_STATUS Mtftp4SendPacket(IN OUT MTFTP4_PROTOCOL *Instance, IN OUT NET_BUF *Packet)
VOID EFIAPI NetbufFree(IN NET_BUF *Nbuf)
Definition: NetBuffer.c:195
VOID EFIAPI NetListInsertAfter(IN OUT LIST_ENTRY *PrevEntry, IN OUT LIST_ENTRY *NewEntry)
Definition: DxeNetLib.c:1172
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 UdpIoSendDatagram(IN UDP_IO *UdpIo, IN NET_BUF *Packet, IN UDP_END_POINT *EndPoint OPTIONAL, IN EFI_IP_ADDRESS *Gateway OPTIONAL, IN UDP_IO_CALLBACK CallBack, IN VOID *Context)
Definition: DxeUdpIoLib.c:971
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
UINT32 OptionCount
Definition: Mtftp4.h:539
EFI_MTFTP4_TIMEOUT_CALLBACK TimeoutCallback
Definition: Mtftp4.h:566
EFI_MTFTP4_OPTION * OptionList
Definition: Mtftp4.h:543
UINT8 * Filename
Definition: Mtftp4.h:531
EFI_MTFTP4_REQ_HEADER Rrq
Definition: Mtftp4.h:105
UINT16 OpCode
Definition: Mtftp4.h:101
EFI_MTFTP4_ERROR_HEADER Error
Definition: Mtftp4.h:133