]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Support.c
Update modules to show real dependencies on the BaseMemoryLib and MemoryAllocationLib
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Support.c
CommitLineData
772db4bb 1/** @file\r
dab714aa 2 Support routines for Mtftp.\r
3 \r
4Copyright (c) 2006 - 2007, Intel Corporation<BR>\r
772db4bb 5All rights reserved. This program and the accompanying materials\r
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
142 gBS->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
212 gBS->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
294 Packet->OpCode = HTONS (Instance->Operation);\r
295 Cur = Packet->Rrq.Filename;\r
687a2e5f 296 Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Token->Filename);\r
b7d3c631 297 Cur += AsciiStrLen ((CHAR8 *) Token->Filename) + 1;\r
687a2e5f 298 Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Mode);\r
b7d3c631 299 Cur += AsciiStrLen ((CHAR8 *) Mode) + 1;\r
772db4bb 300\r
301 for (Index = 0; Index < Token->OptionCount; ++Index) {\r
b61439a7 302 Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Options[Index].OptionStr);\r
b7d3c631 303 Cur += AsciiStrLen ((CHAR8 *) Options[Index].OptionStr) + 1;\r
b61439a7 304\r
305 Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Options[Index].ValueStr);\r
b7d3c631 306 Cur += AsciiStrLen ((CHAR8 *) (CHAR8 *) Options[Index].ValueStr) + 1;\r
772db4bb 307 }\r
308\r
309 return Mtftp4SendPacket (Instance, Nbuf);\r
310}\r
311\r
312\r
313/**\r
dab714aa 314 Build then send an error message.\r
772db4bb 315\r
316 @param Instance The MTFTP session\r
dab714aa 317 @param ErrCode The error code \r
318 @param ErrInfo The error message\r
772db4bb 319\r
320 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the error packet\r
321 @retval EFI_SUCCESS The error packet is transmitted.\r
322 @retval Others Failed to transmit the packet.\r
323\r
324**/\r
325EFI_STATUS\r
326Mtftp4SendError (\r
327 IN MTFTP4_PROTOCOL *Instance,\r
328 IN UINT16 ErrCode,\r
dab714aa 329 IN UINT8 *ErrInfo\r
772db4bb 330 )\r
331{\r
332 NET_BUF *Packet;\r
333 EFI_MTFTP4_PACKET *TftpError;\r
334 UINT32 Len;\r
335\r
687a2e5f 336 Len = (UINT32) (AsciiStrLen ((CHAR8 *) ErrInfo) + sizeof (EFI_MTFTP4_ERROR_HEADER));\r
772db4bb 337 Packet = NetbufAlloc (Len);\r
338\r
339 if (Packet == NULL) {\r
340 return EFI_OUT_OF_RESOURCES;\r
341 }\r
342\r
343 TftpError = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Packet, Len, FALSE);\r
344 TftpError->OpCode = HTONS (EFI_MTFTP4_OPCODE_ERROR);\r
345 TftpError->Error.ErrorCode = HTONS (ErrCode);\r
346\r
687a2e5f 347 AsciiStrCpy ((CHAR8 *) TftpError->Error.ErrorMessage, (CHAR8 *) ErrInfo);\r
772db4bb 348\r
349 return Mtftp4SendPacket (Instance, Packet);\r
350}\r
351\r
352\r
353/**\r
354 The callback function called when the packet is transmitted.\r
dab714aa 355 \r
772db4bb 356 It simply frees the packet.\r
357\r
358 @param Packet The transmitted (or failed to) packet\r
359 @param Points The local and remote UDP access point\r
360 @param IoStatus The result of the transmission\r
361 @param Context Opaque parameter to the callback\r
362\r
772db4bb 363**/\r
772db4bb 364VOID\r
365Mtftp4OnPacketSent (\r
3dc3861a 366 IN NET_BUF *Packet,\r
367 IN UDP_POINTS *Points,\r
368 IN EFI_STATUS IoStatus,\r
369 IN VOID *Context\r
772db4bb 370 )\r
371{\r
372 NetbufFree (Packet);\r
373}\r
374\r
375\r
376/**\r
dab714aa 377 Set the timeout for the instance. User a longer time for passive instances.\r
772db4bb 378\r
379 @param Instance The Mtftp session to set time out\r
380\r
772db4bb 381**/\r
382VOID\r
383Mtftp4SetTimeout (\r
dab714aa 384 IN OUT MTFTP4_PROTOCOL *Instance\r
772db4bb 385 )\r
386{\r
387 if (Instance->Master) {\r
388 Instance->PacketToLive = Instance->Timeout;\r
389 } else {\r
390 Instance->PacketToLive = Instance->Timeout * 2;\r
391 }\r
392}\r
393\r
394\r
395/**\r
dab714aa 396 Send the packet for the instance. \r
397 \r
398 It will first save a reference to the packet for later retransmission. \r
399 Then determine the destination port, listen port for requests, and connected \r
400 port for others. At last, send the packet out.\r
772db4bb 401\r
402 @param Instance The Mtftp instance\r
403 @param Packet The packet to send\r
404\r
405 @retval EFI_SUCCESS The packet is sent out\r
406 @retval Others Failed to transmit the packet.\r
407\r
408**/\r
409EFI_STATUS\r
410Mtftp4SendPacket (\r
dab714aa 411 IN OUT MTFTP4_PROTOCOL *Instance,\r
412 IN OUT NET_BUF *Packet\r
772db4bb 413 )\r
414{\r
415 UDP_POINTS UdpPoint;\r
416 EFI_STATUS Status;\r
417 UINT16 OpCode;\r
687a2e5f 418 UINT16 Value;\r
772db4bb 419\r
420 //\r
421 // Save the packet for retransmission\r
422 //\r
423 if (Instance->LastPacket != NULL) {\r
424 NetbufFree (Instance->LastPacket);\r
425 }\r
426\r
427 Instance->LastPacket = Packet;\r
428\r
429 Instance->CurRetry = 0;\r
430 Mtftp4SetTimeout (Instance);\r
431\r
432 UdpPoint.LocalAddr = 0;\r
433 UdpPoint.LocalPort = 0;\r
434 UdpPoint.RemoteAddr = Instance->ServerIp;\r
435\r
436 //\r
437 // Send the requests to the listening port, other packets\r
438 // to the connected port\r
439 //\r
687a2e5f 440 Value = *((UINT16 *) NetbufGetByte (Packet, 0, NULL));\r
441 OpCode = NTOHS (Value);\r
772db4bb 442\r
dab714aa 443 if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || \r
444 (OpCode == EFI_MTFTP4_OPCODE_DIR) ||\r
772db4bb 445 (OpCode == EFI_MTFTP4_OPCODE_WRQ)) {\r
446 UdpPoint.RemotePort = Instance->ListeningPort;\r
447 } else {\r
448 UdpPoint.RemotePort = Instance->ConnectedPort;\r
449 }\r
450\r
451 NET_GET_REF (Packet);\r
452\r
453 Status = UdpIoSendDatagram (\r
454 Instance->UnicastPort,\r
455 Packet,\r
456 &UdpPoint,\r
c4a62a12 457 0,\r
772db4bb 458 Mtftp4OnPacketSent,\r
459 Instance\r
460 );\r
461\r
462 if (EFI_ERROR (Status)) {\r
463 NET_PUT_REF (Packet);\r
464 }\r
465\r
466 return Status;\r
467}\r
468\r
469\r
470/**\r
dab714aa 471 Retransmit the last packet for the instance.\r
772db4bb 472\r
473 @param Instance The Mtftp instance\r
474\r
475 @retval EFI_SUCCESS The last packet is retransmitted.\r
476 @retval Others Failed to retransmit.\r
477\r
478**/\r
479EFI_STATUS\r
480Mtftp4Retransmit (\r
481 IN MTFTP4_PROTOCOL *Instance\r
482 )\r
483{\r
484 UDP_POINTS UdpPoint;\r
485 EFI_STATUS Status;\r
486 UINT16 OpCode;\r
687a2e5f 487 UINT16 Value;\r
772db4bb 488\r
489 ASSERT (Instance->LastPacket != NULL);\r
490\r
491 UdpPoint.LocalAddr = 0;\r
492 UdpPoint.LocalPort = 0;\r
493 UdpPoint.RemoteAddr = Instance->ServerIp;\r
494\r
495 //\r
496 // Set the requests to the listening port, other packets to the connected port\r
497 //\r
687a2e5f 498 Value = *(UINT16 *) NetbufGetByte (Instance->LastPacket, 0, NULL);\r
499 OpCode = NTOHS (Value);\r
772db4bb 500\r
501 if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||\r
502 (OpCode == EFI_MTFTP4_OPCODE_WRQ)) {\r
503 UdpPoint.RemotePort = Instance->ListeningPort;\r
504 } else {\r
505 UdpPoint.RemotePort = Instance->ConnectedPort;\r
506 }\r
507\r
508 NET_GET_REF (Instance->LastPacket);\r
509\r
510 Status = UdpIoSendDatagram (\r
511 Instance->UnicastPort,\r
512 Instance->LastPacket,\r
513 &UdpPoint,\r
c4a62a12 514 0,\r
772db4bb 515 Mtftp4OnPacketSent,\r
516 Instance\r
517 );\r
518\r
519 if (EFI_ERROR (Status)) {\r
520 NET_PUT_REF (Instance->LastPacket);\r
521 }\r
522\r
523 return Status;\r
524}\r
525\r
526\r
527/**\r
528 The timer ticking function for the Mtftp service instance.\r
529\r
530 @param Event The ticking event\r
531 @param Context The Mtftp service instance\r
532\r
772db4bb 533**/\r
534VOID\r
535EFIAPI\r
536Mtftp4OnTimerTick (\r
537 IN EFI_EVENT Event,\r
538 IN VOID *Context\r
539 )\r
540{\r
541 MTFTP4_SERVICE *MtftpSb;\r
e48e37fc 542 LIST_ENTRY *Entry;\r
543 LIST_ENTRY *Next;\r
772db4bb 544 MTFTP4_PROTOCOL *Instance;\r
545 EFI_MTFTP4_TOKEN *Token;\r
546\r
547 MtftpSb = (MTFTP4_SERVICE *) Context;\r
548\r
549 //\r
550 // Iterate through all the children of the Mtftp service instance. Time\r
551 // out the packet. If maximum retries reached, clean the session up.\r
552 //\r
553 NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {\r
554 Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);\r
555\r
556 if ((Instance->PacketToLive == 0) || (--Instance->PacketToLive > 0)) {\r
557 continue;\r
558 }\r
559\r
560 //\r
561 // Call the user's time out handler\r
562 //\r
563 Token = Instance->Token;\r
564\r
565 if ((Token->TimeoutCallback != NULL) &&\r
566 EFI_ERROR (Token->TimeoutCallback (&Instance->Mtftp4, Token))) {\r
567\r
568 Mtftp4SendError (\r
569 Instance,\r
570 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
67a58d0f 571 (UINT8 *) "User aborted the transfer in time out"\r
772db4bb 572 );\r
573\r
574 Mtftp4CleanOperation (Instance, EFI_ABORTED);\r
575 continue;\r
576 }\r
577\r
578 //\r
579 // Retransmit the packet if haven't reach the maxmium retry count,\r
580 // otherwise exit the transfer.\r
581 //\r
582 if (++Instance->CurRetry < Instance->MaxRetry) {\r
583 Mtftp4Retransmit (Instance);\r
584 Mtftp4SetTimeout (Instance);\r
585 } else {\r
586 Mtftp4CleanOperation (Instance, EFI_TIMEOUT);\r
587 continue;\r
588 }\r
589 }\r
590}\r