]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Support.c
Update the copyright notice format
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Support.c
CommitLineData
772db4bb 1/** @file\r
dab714aa 2 Support routines for Mtftp.\r
3 \r
e5eed7d3
HT
4Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
772db4bb 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
dab714aa 8http://opensource.org/licenses/bsd-license.php<BR>\r
772db4bb 9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
772db4bb 13**/\r
14\r
15#include "Mtftp4Impl.h"\r
16\r
17\r
18/**\r
dab714aa 19 Allocate a MTFTP4 block range, then init it to the range of [Start, End]\r
772db4bb 20\r
21 @param Start The start block number\r
22 @param End The last block number in the range\r
23\r
dab714aa 24 @return Pointer to the created block range, NULL if failed to allocate memory.\r
772db4bb 25\r
26**/\r
772db4bb 27MTFTP4_BLOCK_RANGE *\r
28Mtftp4AllocateRange (\r
29 IN UINT16 Start,\r
30 IN UINT16 End\r
31 )\r
32{\r
33 MTFTP4_BLOCK_RANGE *Range;\r
34\r
e48e37fc 35 Range = AllocatePool (sizeof (MTFTP4_BLOCK_RANGE));\r
772db4bb 36\r
37 if (Range == NULL) {\r
38 return NULL;\r
39 }\r
40\r
e48e37fc 41 InitializeListHead (&Range->Link);\r
772db4bb 42 Range->Start = Start;\r
43 Range->End = End;\r
44\r
45 return Range;\r
46}\r
47\r
48\r
49/**\r
dab714aa 50 Initialize the block range for either RRQ or WRQ. \r
51 \r
52 RRQ and WRQ have different requirements for Start and End. \r
53 For example, during start up, WRQ initializes its whole valid block range \r
54 to [0, 0xffff]. This is bacause the server will send us a ACK0 to inform us \r
55 to start the upload. When the client received ACK0, it will remove 0 from the \r
56 range, get the next block number, which is 1, then upload the BLOCK1. For RRQ\r
57 without option negotiation, the server will directly send us the BLOCK1 in \r
58 response to the client's RRQ. When received BLOCK1, the client will remove \r
59 it from the block range and send an ACK. It also works if there is option \r
60 negotiation.\r
772db4bb 61\r
62 @param Head The block range head to initialize\r
63 @param Start The Start block number.\r
64 @param End The last block number.\r
65\r
66 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for initial block range\r
67 @retval EFI_SUCCESS The initial block range is created.\r
68\r
69**/\r
70EFI_STATUS\r
71Mtftp4InitBlockRange (\r
e48e37fc 72 IN LIST_ENTRY *Head,\r
772db4bb 73 IN UINT16 Start,\r
74 IN UINT16 End\r
75 )\r
76{\r
77 MTFTP4_BLOCK_RANGE *Range;\r
78\r
79 Range = Mtftp4AllocateRange (Start, End);\r
80\r
81 if (Range == NULL) {\r
82 return EFI_OUT_OF_RESOURCES;\r
83 }\r
84\r
e48e37fc 85 InsertTailList (Head, &Range->Link);\r
772db4bb 86 return EFI_SUCCESS;\r
87}\r
88\r
89\r
90/**\r
91 Get the first valid block number on the range list.\r
92\r
93 @param Head The block range head\r
94\r
dab714aa 95 @return The first valid block number, -1 if the block range is empty. \r
772db4bb 96\r
97**/\r
98INTN\r
99Mtftp4GetNextBlockNum (\r
e48e37fc 100 IN LIST_ENTRY *Head\r
772db4bb 101 )\r
102{\r
103 MTFTP4_BLOCK_RANGE *Range;\r
104\r
e48e37fc 105 if (IsListEmpty (Head)) {\r
772db4bb 106 return -1;\r
107 }\r
108\r
109 Range = NET_LIST_HEAD (Head, MTFTP4_BLOCK_RANGE, Link);\r
110 return Range->Start;\r
111}\r
112\r
113\r
114/**\r
dab714aa 115 Set the last block number of the block range list. \r
116 \r
117 It will remove all the blocks after the Last. MTFTP initialize the block range\r
118 to the maximum possible range, such as [0, 0xffff] for WRQ. When it gets the \r
119 last block number, it will call this function to set the last block number.\r
772db4bb 120\r
121 @param Head The block range list\r
122 @param Last The last block number\r
123\r
772db4bb 124**/\r
125VOID\r
126Mtftp4SetLastBlockNum (\r
e48e37fc 127 IN LIST_ENTRY *Head,\r
772db4bb 128 IN UINT16 Last\r
129 )\r
130{\r
131 MTFTP4_BLOCK_RANGE *Range;\r
132\r
133 //\r
134 // Iterate from the tail to head to remove the block number\r
135 // after the last.\r
136 //\r
e48e37fc 137 while (!IsListEmpty (Head)) {\r
772db4bb 138 Range = NET_LIST_TAIL (Head, MTFTP4_BLOCK_RANGE, Link);\r
139\r
140 if (Range->Start > Last) {\r
e48e37fc 141 RemoveEntryList (&Range->Link);\r
766c7483 142 FreePool (Range);\r
772db4bb 143 continue;\r
144 }\r
145\r
146 if (Range->End > Last) {\r
147 Range->End = Last;\r
148 }\r
149\r
150 return ;\r
151 }\r
152}\r
153\r
154\r
155/**\r
156 Remove the block number from the block range list.\r
157\r
158 @param Head The block range list to remove from\r
159 @param Num The block number to remove\r
160\r
161 @retval EFI_NOT_FOUND The block number isn't in the block range list\r
162 @retval EFI_SUCCESS The block number has been removed from the list\r
163 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource\r
164\r
165**/\r
166EFI_STATUS\r
167Mtftp4RemoveBlockNum (\r
e48e37fc 168 IN LIST_ENTRY *Head,\r
772db4bb 169 IN UINT16 Num\r
170 )\r
171{\r
172 MTFTP4_BLOCK_RANGE *Range;\r
173 MTFTP4_BLOCK_RANGE *NewRange;\r
e48e37fc 174 LIST_ENTRY *Entry;\r
772db4bb 175\r
176 NET_LIST_FOR_EACH (Entry, Head) {\r
177\r
178 //\r
179 // Each block represents a hole [Start, End] in the file,\r
180 // skip to the first range with End >= Num\r
181 //\r
182 Range = NET_LIST_USER_STRUCT (Entry, MTFTP4_BLOCK_RANGE, Link);\r
183\r
184 if (Range->End < Num) {\r
185 continue;\r
186 }\r
187\r
188 //\r
189 // There are three different cases for Start\r
190 // 1. (Start > Num) && (End >= Num):\r
191 // because all the holes before this one has the condition of\r
192 // End < Num, so this block number has been removed.\r
193 //\r
194 // 2. (Start == Num) && (End >= Num):\r
195 // Need to increase the Start by one, and if End == Num, this\r
196 // hole has been removed completely, remove it.\r
197 //\r
198 // 3. (Start < Num) && (End >= Num):\r
199 // if End == Num, only need to decrease the End by one because\r
200 // we have (Start < Num) && (Num == End), so (Start <= End - 1).\r
201 // if (End > Num), the hold is splited into two holes, with\r
202 // [Start, Num - 1] and [Num + 1, End].\r
203 //\r
204 if (Range->Start > Num) {\r
205 return EFI_NOT_FOUND;\r
206\r
207 } else if (Range->Start == Num) {\r
208 Range->Start++;\r
209\r
210 if (Range->Start > Range->End) {\r
e48e37fc 211 RemoveEntryList (&Range->Link);\r
766c7483 212 FreePool (Range);\r
772db4bb 213 }\r
214\r
215 return EFI_SUCCESS;\r
216\r
217 } else {\r
218 if (Range->End == Num) {\r
219 Range->End--;\r
220 } else {\r
687a2e5f 221 NewRange = Mtftp4AllocateRange ((UINT16) (Num + 1), (UINT16) Range->End);\r
772db4bb 222\r
223 if (NewRange == NULL) {\r
224 return EFI_OUT_OF_RESOURCES;\r
225 }\r
226\r
227 Range->End = Num - 1;\r
228 NetListInsertAfter (&Range->Link, &NewRange->Link);\r
229 }\r
230\r
231 return EFI_SUCCESS;\r
232 }\r
233 }\r
234\r
235 return EFI_NOT_FOUND;\r
236}\r
237\r
238\r
239/**\r
240 Build then transmit the request packet for the MTFTP session.\r
241\r
242 @param Instance The Mtftp session\r
243\r
244 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the request\r
245 @retval EFI_SUCCESS The request is built and sent\r
246 @retval Others Failed to transmit the packet.\r
247\r
248**/\r
249EFI_STATUS\r
250Mtftp4SendRequest (\r
251 IN MTFTP4_PROTOCOL *Instance\r
252 )\r
253{\r
254 EFI_MTFTP4_PACKET *Packet;\r
255 EFI_MTFTP4_OPTION *Options;\r
256 EFI_MTFTP4_TOKEN *Token;\r
257 NET_BUF *Nbuf;\r
258 UINT8 *Mode;\r
259 UINT8 *Cur;\r
260 UINT32 Len;\r
261 UINTN Index;\r
687a2e5f 262 UINT32 Len1;\r
263 UINT32 Len2;\r
772db4bb 264\r
265 Token = Instance->Token;\r
266 Options = Token->OptionList;\r
267 Mode = Instance->Token->ModeStr;\r
268\r
269 if (Mode == NULL) {\r
67a58d0f 270 Mode = (UINT8 *) "octet";\r
772db4bb 271 }\r
272\r
273 //\r
274 // Compute the packet length\r
275 //\r
687a2e5f 276 Len1 = (UINT32) AsciiStrLen ((CHAR8 *) Token->Filename);\r
277 Len2 = (UINT32) AsciiStrLen ((CHAR8 *) Mode);\r
278 Len = (Len1 + Len2 + 4);\r
772db4bb 279\r
280 for (Index = 0; Index < Token->OptionCount; Index++) {\r
687a2e5f 281 Len1 = (UINT32) AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);\r
282 Len2 = (UINT32) AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);\r
283 Len += Len1 + Len2 + 2;\r
772db4bb 284 }\r
285\r
286 //\r
287 // Allocate a packet then copy the data over\r
288 //\r
289 if ((Nbuf = NetbufAlloc (Len)) == NULL) {\r
290 return EFI_OUT_OF_RESOURCES;\r
291 }\r
292\r
293 Packet = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Nbuf, Len, FALSE);\r
894d038a 294 ASSERT (Packet != NULL);\r
295\r
772db4bb 296 Packet->OpCode = HTONS (Instance->Operation);\r
297 Cur = Packet->Rrq.Filename;\r
687a2e5f 298 Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Token->Filename);\r
b7d3c631 299 Cur += AsciiStrLen ((CHAR8 *) Token->Filename) + 1;\r
687a2e5f 300 Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Mode);\r
b7d3c631 301 Cur += AsciiStrLen ((CHAR8 *) Mode) + 1;\r
772db4bb 302\r
303 for (Index = 0; Index < Token->OptionCount; ++Index) {\r
b61439a7 304 Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Options[Index].OptionStr);\r
b7d3c631 305 Cur += AsciiStrLen ((CHAR8 *) Options[Index].OptionStr) + 1;\r
b61439a7 306\r
307 Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Options[Index].ValueStr);\r
b7d3c631 308 Cur += AsciiStrLen ((CHAR8 *) (CHAR8 *) Options[Index].ValueStr) + 1;\r
772db4bb 309 }\r
310\r
311 return Mtftp4SendPacket (Instance, Nbuf);\r
312}\r
313\r
314\r
315/**\r
dab714aa 316 Build then send an error message.\r
772db4bb 317\r
318 @param Instance The MTFTP session\r
dab714aa 319 @param ErrCode The error code \r
320 @param ErrInfo The error message\r
772db4bb 321\r
322 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the error packet\r
323 @retval EFI_SUCCESS The error packet is transmitted.\r
324 @retval Others Failed to transmit the packet.\r
325\r
326**/\r
327EFI_STATUS\r
328Mtftp4SendError (\r
329 IN MTFTP4_PROTOCOL *Instance,\r
330 IN UINT16 ErrCode,\r
dab714aa 331 IN UINT8 *ErrInfo\r
772db4bb 332 )\r
333{\r
334 NET_BUF *Packet;\r
335 EFI_MTFTP4_PACKET *TftpError;\r
336 UINT32 Len;\r
337\r
687a2e5f 338 Len = (UINT32) (AsciiStrLen ((CHAR8 *) ErrInfo) + sizeof (EFI_MTFTP4_ERROR_HEADER));\r
772db4bb 339 Packet = NetbufAlloc (Len);\r
772db4bb 340 if (Packet == NULL) {\r
341 return EFI_OUT_OF_RESOURCES;\r
342 }\r
343\r
344 TftpError = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Packet, Len, FALSE);\r
894d038a 345 ASSERT (TftpError != NULL);\r
346\r
772db4bb 347 TftpError->OpCode = HTONS (EFI_MTFTP4_OPCODE_ERROR);\r
348 TftpError->Error.ErrorCode = HTONS (ErrCode);\r
349\r
687a2e5f 350 AsciiStrCpy ((CHAR8 *) TftpError->Error.ErrorMessage, (CHAR8 *) ErrInfo);\r
772db4bb 351\r
352 return Mtftp4SendPacket (Instance, Packet);\r
353}\r
354\r
355\r
356/**\r
357 The callback function called when the packet is transmitted.\r
dab714aa 358 \r
772db4bb 359 It simply frees the packet.\r
360\r
361 @param Packet The transmitted (or failed to) packet\r
b45b45b2 362 @param EndPoint The local and remote UDP access point\r
772db4bb 363 @param IoStatus The result of the transmission\r
364 @param Context Opaque parameter to the callback\r
365\r
772db4bb 366**/\r
772db4bb 367VOID\r
e798cd87 368EFIAPI\r
772db4bb 369Mtftp4OnPacketSent (\r
3dc3861a 370 IN NET_BUF *Packet,\r
b45b45b2 371 IN UDP_END_POINT *EndPoint,\r
3dc3861a 372 IN EFI_STATUS IoStatus,\r
373 IN VOID *Context\r
772db4bb 374 )\r
375{\r
376 NetbufFree (Packet);\r
377}\r
378\r
379\r
380/**\r
dab714aa 381 Set the timeout for the instance. User a longer time for passive instances.\r
772db4bb 382\r
383 @param Instance The Mtftp session to set time out\r
384\r
772db4bb 385**/\r
386VOID\r
387Mtftp4SetTimeout (\r
dab714aa 388 IN OUT MTFTP4_PROTOCOL *Instance\r
772db4bb 389 )\r
390{\r
391 if (Instance->Master) {\r
392 Instance->PacketToLive = Instance->Timeout;\r
393 } else {\r
394 Instance->PacketToLive = Instance->Timeout * 2;\r
395 }\r
396}\r
397\r
398\r
399/**\r
dab714aa 400 Send the packet for the instance. \r
401 \r
402 It will first save a reference to the packet for later retransmission. \r
403 Then determine the destination port, listen port for requests, and connected \r
404 port for others. At last, send the packet out.\r
772db4bb 405\r
406 @param Instance The Mtftp instance\r
407 @param Packet The packet to send\r
408\r
409 @retval EFI_SUCCESS The packet is sent out\r
410 @retval Others Failed to transmit the packet.\r
411\r
412**/\r
413EFI_STATUS\r
414Mtftp4SendPacket (\r
dab714aa 415 IN OUT MTFTP4_PROTOCOL *Instance,\r
416 IN OUT NET_BUF *Packet\r
772db4bb 417 )\r
418{\r
b45b45b2 419 UDP_END_POINT UdpPoint;\r
772db4bb 420 EFI_STATUS Status;\r
421 UINT16 OpCode;\r
687a2e5f 422 UINT16 Value;\r
772db4bb 423\r
424 //\r
425 // Save the packet for retransmission\r
426 //\r
427 if (Instance->LastPacket != NULL) {\r
428 NetbufFree (Instance->LastPacket);\r
429 }\r
430\r
b45b45b2 431 Instance->LastPacket = Packet;\r
772db4bb 432\r
b45b45b2 433 Instance->CurRetry = 0;\r
772db4bb 434 Mtftp4SetTimeout (Instance);\r
435\r
b45b45b2 436 ZeroMem (&UdpPoint, sizeof (UdpPoint));\r
437 UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;\r
772db4bb 438\r
439 //\r
440 // Send the requests to the listening port, other packets\r
441 // to the connected port\r
442 //\r
687a2e5f 443 Value = *((UINT16 *) NetbufGetByte (Packet, 0, NULL));\r
444 OpCode = NTOHS (Value);\r
772db4bb 445\r
dab714aa 446 if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || \r
447 (OpCode == EFI_MTFTP4_OPCODE_DIR) ||\r
772db4bb 448 (OpCode == EFI_MTFTP4_OPCODE_WRQ)) {\r
449 UdpPoint.RemotePort = Instance->ListeningPort;\r
450 } else {\r
451 UdpPoint.RemotePort = Instance->ConnectedPort;\r
452 }\r
453\r
454 NET_GET_REF (Packet);\r
455\r
456 Status = UdpIoSendDatagram (\r
457 Instance->UnicastPort,\r
458 Packet,\r
459 &UdpPoint,\r
b45b45b2 460 NULL,\r
772db4bb 461 Mtftp4OnPacketSent,\r
462 Instance\r
463 );\r
464\r
465 if (EFI_ERROR (Status)) {\r
466 NET_PUT_REF (Packet);\r
467 }\r
468\r
469 return Status;\r
470}\r
471\r
472\r
473/**\r
dab714aa 474 Retransmit the last packet for the instance.\r
772db4bb 475\r
476 @param Instance The Mtftp instance\r
477\r
478 @retval EFI_SUCCESS The last packet is retransmitted.\r
479 @retval Others Failed to retransmit.\r
480\r
481**/\r
482EFI_STATUS\r
483Mtftp4Retransmit (\r
484 IN MTFTP4_PROTOCOL *Instance\r
485 )\r
486{\r
b45b45b2 487 UDP_END_POINT UdpPoint;\r
772db4bb 488 EFI_STATUS Status;\r
489 UINT16 OpCode;\r
687a2e5f 490 UINT16 Value;\r
772db4bb 491\r
492 ASSERT (Instance->LastPacket != NULL);\r
493\r
b45b45b2 494 ZeroMem (&UdpPoint, sizeof (UdpPoint));\r
495 UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;\r
772db4bb 496\r
497 //\r
498 // Set the requests to the listening port, other packets to the connected port\r
499 //\r
687a2e5f 500 Value = *(UINT16 *) NetbufGetByte (Instance->LastPacket, 0, NULL);\r
501 OpCode = NTOHS (Value);\r
772db4bb 502\r
503 if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||\r
504 (OpCode == EFI_MTFTP4_OPCODE_WRQ)) {\r
505 UdpPoint.RemotePort = Instance->ListeningPort;\r
506 } else {\r
507 UdpPoint.RemotePort = Instance->ConnectedPort;\r
508 }\r
509\r
510 NET_GET_REF (Instance->LastPacket);\r
511\r
512 Status = UdpIoSendDatagram (\r
513 Instance->UnicastPort,\r
514 Instance->LastPacket,\r
515 &UdpPoint,\r
b45b45b2 516 NULL,\r
772db4bb 517 Mtftp4OnPacketSent,\r
518 Instance\r
519 );\r
520\r
521 if (EFI_ERROR (Status)) {\r
522 NET_PUT_REF (Instance->LastPacket);\r
523 }\r
524\r
525 return Status;\r
526}\r
527\r
528\r
529/**\r
530 The timer ticking function for the Mtftp service instance.\r
531\r
532 @param Event The ticking event\r
533 @param Context The Mtftp service instance\r
534\r
772db4bb 535**/\r
536VOID\r
537EFIAPI\r
538Mtftp4OnTimerTick (\r
539 IN EFI_EVENT Event,\r
540 IN VOID *Context\r
541 )\r
542{\r
543 MTFTP4_SERVICE *MtftpSb;\r
e48e37fc 544 LIST_ENTRY *Entry;\r
545 LIST_ENTRY *Next;\r
772db4bb 546 MTFTP4_PROTOCOL *Instance;\r
547 EFI_MTFTP4_TOKEN *Token;\r
548\r
549 MtftpSb = (MTFTP4_SERVICE *) Context;\r
550\r
551 //\r
552 // Iterate through all the children of the Mtftp service instance. Time\r
553 // out the packet. If maximum retries reached, clean the session up.\r
554 //\r
555 NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {\r
556 Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);\r
557\r
558 if ((Instance->PacketToLive == 0) || (--Instance->PacketToLive > 0)) {\r
559 continue;\r
560 }\r
561\r
562 //\r
563 // Call the user's time out handler\r
564 //\r
565 Token = Instance->Token;\r
566\r
567 if ((Token->TimeoutCallback != NULL) &&\r
568 EFI_ERROR (Token->TimeoutCallback (&Instance->Mtftp4, Token))) {\r
569\r
570 Mtftp4SendError (\r
571 Instance,\r
572 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
67a58d0f 573 (UINT8 *) "User aborted the transfer in time out"\r
772db4bb 574 );\r
575\r
576 Mtftp4CleanOperation (Instance, EFI_ABORTED);\r
577 continue;\r
578 }\r
579\r
580 //\r
581 // Retransmit the packet if haven't reach the maxmium retry count,\r
582 // otherwise exit the transfer.\r
583 //\r
584 if (++Instance->CurRetry < Instance->MaxRetry) {\r
585 Mtftp4Retransmit (Instance);\r
586 Mtftp4SetTimeout (Instance);\r
587 } else {\r
588 Mtftp4CleanOperation (Instance, EFI_TIMEOUT);\r
589 continue;\r
590 }\r
591 }\r
592}\r