]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c
NetworkPkg: Apply uncrustify changes
[mirror_edk2.git] / NetworkPkg / Mtftp6Dxe / Mtftp6Wrq.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 Mtftp6 Wrq process functions implementation.\r
3\r
94866d40 4 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
a3bcde70 5\r
ecf98fbc 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a3bcde70
HT
7\r
8**/\r
9\r
10#include "Mtftp6Impl.h"\r
11\r
a3bcde70
HT
12/**\r
13 Build and send a Mtftp6 data packet for upload.\r
14\r
15 @param[in] Instance The pointer to the Mtftp6 instance.\r
16 @param[in] BlockNum The block num to be sent.\r
17\r
18 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.\r
19 @retval EFI_SUCCESS The data packet was sent.\r
20 @retval EFI_ABORTED The user aborted this process.\r
21\r
22**/\r
23EFI_STATUS\r
24Mtftp6WrqSendBlock (\r
d1050b9d
MK
25 IN MTFTP6_INSTANCE *Instance,\r
26 IN UINT16 BlockNum\r
a3bcde70
HT
27 )\r
28{\r
d1050b9d
MK
29 EFI_MTFTP6_PACKET *Packet;\r
30 EFI_MTFTP6_TOKEN *Token;\r
31 NET_BUF *UdpPacket;\r
32 EFI_STATUS Status;\r
33 UINT16 DataLen;\r
34 UINT8 *DataBuf;\r
35 UINT64 Start;\r
a3bcde70
HT
36\r
37 //\r
38 // Allocate net buffer to create data packet.\r
39 //\r
40 UdpPacket = NetbufAlloc (Instance->BlkSize + MTFTP6_DATA_HEAD_LEN);\r
41\r
42 if (UdpPacket == NULL) {\r
43 return EFI_OUT_OF_RESOURCES;\r
44 }\r
45\r
d1050b9d
MK
46 Packet = (EFI_MTFTP6_PACKET *)NetbufAllocSpace (\r
47 UdpPacket,\r
48 MTFTP6_DATA_HEAD_LEN,\r
49 FALSE\r
50 );\r
a3bcde70
HT
51 ASSERT (Packet != NULL);\r
52\r
53 Packet->Data.OpCode = HTONS (EFI_MTFTP6_OPCODE_DATA);\r
54 Packet->Data.Block = HTONS (BlockNum);\r
55\r
56 //\r
57 // Read the block from either the buffer or PacketNeeded callback\r
58 //\r
59 Token = Instance->Token;\r
60 DataLen = Instance->BlkSize;\r
61\r
62 if (Token->Buffer != NULL) {\r
63 Start = MultU64x32 (BlockNum - 1, Instance->BlkSize);\r
64\r
65 if (Token->BufferSize < Start + Instance->BlkSize) {\r
d1050b9d 66 DataLen = (UINT16)(Token->BufferSize - Start);\r
a3bcde70
HT
67 Instance->LastBlk = BlockNum;\r
68 Mtftp6SetLastBlockNum (&Instance->BlkList, BlockNum);\r
69 }\r
70\r
71 if (DataLen > 0) {\r
72 NetbufAllocSpace (UdpPacket, DataLen, FALSE);\r
d1050b9d 73 CopyMem (Packet->Data.Data, (UINT8 *)Token->Buffer + Start, DataLen);\r
a3bcde70 74 }\r
a3bcde70
HT
75 } else {\r
76 //\r
77 // Get data from PacketNeeded\r
78 //\r
79 DataBuf = NULL;\r
d1050b9d 80 Status = Token->PacketNeeded (&Instance->Mtftp6, Token, &DataLen, (VOID *)&DataBuf);\r
a3bcde70
HT
81\r
82 if (EFI_ERROR (Status) || (DataLen > Instance->BlkSize)) {\r
83 if (DataBuf != NULL) {\r
84 gBS->FreePool (DataBuf);\r
85 }\r
d1050b9d 86\r
a3bcde70
HT
87 //\r
88 // The received packet has already been freed.\r
89 //\r
90 Mtftp6SendError (\r
91 Instance,\r
92 EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,\r
d1050b9d 93 (UINT8 *)"User aborted the transfer"\r
a3bcde70
HT
94 );\r
95\r
96 return EFI_ABORTED;\r
97 }\r
98\r
99 if (DataLen < Instance->BlkSize) {\r
100 Instance->LastBlk = BlockNum;\r
101 Mtftp6SetLastBlockNum (&Instance->BlkList, BlockNum);\r
102 }\r
103\r
104 if (DataLen > 0) {\r
105 NetbufAllocSpace (UdpPacket, DataLen, FALSE);\r
106 CopyMem (Packet->Data.Data, DataBuf, DataLen);\r
107 gBS->FreePool (DataBuf);\r
108 }\r
109 }\r
110\r
111 //\r
112 // Reset current retry count of the instance.\r
113 //\r
114 Instance->CurRetry = 0;\r
115\r
116 return Mtftp6TransmitPacket (Instance, UdpPacket);\r
117}\r
118\r
a3bcde70
HT
119/**\r
120 Function to handle received ACK packet. If the ACK number matches the\r
121 expected block number, with more data pending, send the next\r
122 block. Otherwise, tell the caller that we are done.\r
123\r
124 @param[in] Instance The pointer to the Mtftp6 instance.\r
125 @param[in] Packet The pointer to the received packet.\r
126 @param[in] Len The length of the packet.\r
127 @param[out] UdpPacket The net buf of received packet.\r
128 @param[out] IsCompleted If TRUE, the upload has been completed.\r
129 Otherwise, the upload has not been completed.\r
130\r
131 @retval EFI_SUCCESS The ACK packet successfully processed.\r
132 @retval EFI_TFTP_ERROR The block number loops back.\r
133 @retval Others Failed to transmit the next data packet.\r
134\r
135**/\r
136EFI_STATUS\r
137Mtftp6WrqHandleAck (\r
d1050b9d
MK
138 IN MTFTP6_INSTANCE *Instance,\r
139 IN EFI_MTFTP6_PACKET *Packet,\r
140 IN UINT32 Len,\r
141 OUT NET_BUF **UdpPacket,\r
142 OUT BOOLEAN *IsCompleted\r
a3bcde70
HT
143 )\r
144{\r
d1050b9d
MK
145 UINT16 AckNum;\r
146 INTN Expected;\r
147 UINT64 BlockCounter;\r
a3bcde70
HT
148\r
149 *IsCompleted = FALSE;\r
150 AckNum = NTOHS (Packet->Ack.Block[0]);\r
151 Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);\r
152\r
153 ASSERT (Expected >= 0);\r
154\r
155 //\r
156 // Get an unwanted ACK, return EFI_SUCCESS to let Mtftp6WrqInput\r
157 // restart receive.\r
158 //\r
159 if (Expected != AckNum) {\r
160 return EFI_SUCCESS;\r
161 }\r
162\r
163 //\r
164 // Remove the acked block number, if this is the last block number,\r
165 // tell the Mtftp6WrqInput to finish the transfer. This is the last\r
2f6693c2 166 // block number if the block range are empty.\r
a3bcde70 167 //\r
2f6693c2 168 Mtftp6RemoveBlockNum (&Instance->BlkList, AckNum, *IsCompleted, &BlockCounter);\r
a3bcde70
HT
169\r
170 Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);\r
171\r
172 if (Expected < 0) {\r
173 //\r
f6c8bbbe 174 // The block range is empty. It may either because the last\r
a3bcde70
HT
175 // block has been ACKed, or the sequence number just looped back,\r
176 // that is, there is more than 0xffff blocks.\r
177 //\r
178 if (Instance->LastBlk == AckNum) {\r
179 ASSERT (Instance->LastBlk >= 1);\r
180 *IsCompleted = TRUE;\r
181 return EFI_SUCCESS;\r
a3bcde70
HT
182 } else {\r
183 //\r
184 // Free the received packet before send new packet in ReceiveNotify,\r
185 // since the udpio might need to be reconfigured.\r
186 //\r
187 NetbufFree (*UdpPacket);\r
188 *UdpPacket = NULL;\r
189 //\r
190 // Send the Mtftp6 error message if block number rolls back.\r
191 //\r
192 Mtftp6SendError (\r
193 Instance,\r
194 EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,\r
d1050b9d 195 (UINT8 *)"Block number rolls back, not supported, try blksize option"\r
a3bcde70
HT
196 );\r
197\r
198 return EFI_TFTP_ERROR;\r
199 }\r
200 }\r
201\r
202 //\r
203 // Free the receive buffer before send new packet since it might need\r
204 // reconfigure udpio.\r
205 //\r
206 NetbufFree (*UdpPacket);\r
207 *UdpPacket = NULL;\r
208\r
d1050b9d 209 return Mtftp6WrqSendBlock (Instance, (UINT16)Expected);\r
a3bcde70
HT
210}\r
211\r
a3bcde70
HT
212/**\r
213 Check whether the received OACK is valid. The OACK is valid\r
214 only if:\r
215 1. It only include options requested by us.\r
216 2. It can only include a smaller block size.\r
217 3. It can't change the proposed time out value.\r
218 4. Other requirements of the individal MTFTP6 options as required.\r
219\r
220 @param[in] ReplyInfo The pointer to options information in reply packet.\r
221 @param[in] RequestInfo The pointer to requested options information.\r
222\r
223 @retval TRUE If the option in OACK is valid.\r
224 @retval FALSE If the option is invalid.\r
225\r
226**/\r
227BOOLEAN\r
228Mtftp6WrqOackValid (\r
d1050b9d
MK
229 IN MTFTP6_EXT_OPTION_INFO *ReplyInfo,\r
230 IN MTFTP6_EXT_OPTION_INFO *RequestInfo\r
a3bcde70
HT
231 )\r
232{\r
233 //\r
234 // It is invalid for server to return options we don't request\r
235 //\r
236 if ((ReplyInfo->BitMap & ~RequestInfo->BitMap) != 0) {\r
237 return FALSE;\r
238 }\r
239\r
240 //\r
241 // Server can only specify a smaller block size to be used and\r
242 // return the timeout matches that requested.\r
243 //\r
244 if ((((ReplyInfo->BitMap & MTFTP6_OPT_BLKSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||\r
245 (((ReplyInfo->BitMap & MTFTP6_OPT_TIMEOUT_BIT) != 0) && (ReplyInfo->Timeout != RequestInfo->Timeout))\r
d1050b9d
MK
246 )\r
247 {\r
a3bcde70
HT
248 return FALSE;\r
249 }\r
250\r
251 return TRUE;\r
252}\r
253\r
a3bcde70
HT
254/**\r
255 Process the OACK packet for Wrq.\r
256\r
257 @param[in] Instance The pointer to the Mtftp6 instance.\r
258 @param[in] Packet The pointer to the received packet.\r
259 @param[in] Len The length of the packet.\r
260 @param[out] UdpPacket The net buf of received packet.\r
261 @param[out] IsCompleted If TRUE, the upload has been completed.\r
262 Otherwise, the upload has not been completed.\r
263\r
264 @retval EFI_SUCCESS The OACK packet successfully processed.\r
265 @retval EFI_TFTP_ERROR An TFTP communication error happened.\r
266 @retval Others Failed to process the OACK packet.\r
267\r
268**/\r
269EFI_STATUS\r
270Mtftp6WrqHandleOack (\r
d1050b9d
MK
271 IN MTFTP6_INSTANCE *Instance,\r
272 IN EFI_MTFTP6_PACKET *Packet,\r
273 IN UINT32 Len,\r
274 OUT NET_BUF **UdpPacket,\r
275 OUT BOOLEAN *IsCompleted\r
a3bcde70
HT
276 )\r
277{\r
d1050b9d
MK
278 EFI_MTFTP6_OPTION *Options;\r
279 UINT32 Count;\r
280 MTFTP6_EXT_OPTION_INFO ExtInfo;\r
281 EFI_MTFTP6_PACKET Dummy;\r
282 EFI_STATUS Status;\r
283 INTN Expected;\r
a3bcde70
HT
284\r
285 *IsCompleted = FALSE;\r
d1050b9d 286 Options = NULL;\r
a3bcde70
HT
287\r
288 //\r
289 // Ignore the OACK if already started the upload\r
290 //\r
291 Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);\r
292\r
293 if (Expected != 0) {\r
294 return EFI_SUCCESS;\r
295 }\r
296\r
297 //\r
298 // Parse and validate the options from server\r
299 //\r
300 ZeroMem (&ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));\r
301\r
302 Status = Mtftp6ParseStart (Packet, Len, &Count, &Options);\r
303\r
304 if (EFI_ERROR (Status)) {\r
305 return Status;\r
306 }\r
d1050b9d 307\r
7a49cd08 308 ASSERT (Options != NULL);\r
a3bcde70 309\r
f3427f12 310 Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, Instance->Operation, &ExtInfo);\r
a3bcde70 311\r
d1050b9d 312 if (EFI_ERROR (Status) || !Mtftp6WrqOackValid (&ExtInfo, &Instance->ExtInfo)) {\r
a3bcde70
HT
313 //\r
314 // Don't send a MTFTP error packet when out of resource, it can\r
315 // only make it worse.\r
316 //\r
317 if (Status != EFI_OUT_OF_RESOURCES) {\r
318 //\r
319 // Free the received packet before send new packet in ReceiveNotify,\r
320 // since the udpio might need to be reconfigured.\r
321 //\r
322 NetbufFree (*UdpPacket);\r
323 *UdpPacket = NULL;\r
324 //\r
325 // Send the Mtftp6 error message if invalid Oack packet received.\r
326 //\r
327 Mtftp6SendError (\r
328 Instance,\r
329 EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,\r
d1050b9d 330 (UINT8 *)"Malformatted OACK packet"\r
a3bcde70
HT
331 );\r
332 }\r
333\r
334 return EFI_TFTP_ERROR;\r
335 }\r
336\r
337 if (ExtInfo.BlkSize != 0) {\r
338 Instance->BlkSize = ExtInfo.BlkSize;\r
339 }\r
340\r
341 if (ExtInfo.Timeout != 0) {\r
342 Instance->Timeout = ExtInfo.Timeout;\r
343 }\r
344\r
345 //\r
346 // Build a bogus ACK0 packet then pass it to the Mtftp6WrqHandleAck,\r
347 // which will start the transmission of the first data block.\r
348 //\r
349 Dummy.Ack.OpCode = HTONS (EFI_MTFTP6_OPCODE_ACK);\r
350 Dummy.Ack.Block[0] = 0;\r
351\r
352 return Mtftp6WrqHandleAck (\r
353 Instance,\r
354 &Dummy,\r
355 sizeof (EFI_MTFTP6_ACK_HEADER),\r
356 UdpPacket,\r
357 IsCompleted\r
358 );\r
359}\r
360\r
a3bcde70
HT
361/**\r
362 The packet process callback for Mtftp6 upload.\r
363\r
364 @param[in] UdpPacket The pointer to the packet received.\r
365 @param[in] UdpEpt The pointer to the Udp6 access point.\r
366 @param[in] IoStatus The status from Udp6 instance.\r
367 @param[in] Context The pointer to the context.\r
368\r
369**/\r
370VOID\r
371EFIAPI\r
372Mtftp6WrqInput (\r
d1050b9d
MK
373 IN NET_BUF *UdpPacket,\r
374 IN UDP_END_POINT *UdpEpt,\r
375 IN EFI_STATUS IoStatus,\r
376 IN VOID *Context\r
a3bcde70
HT
377 )\r
378{\r
d1050b9d
MK
379 MTFTP6_INSTANCE *Instance;\r
380 EFI_MTFTP6_PACKET *Packet;\r
381 BOOLEAN IsCompleted;\r
382 EFI_STATUS Status;\r
383 UINT32 TotalNum;\r
384 UINT32 Len;\r
385 UINT16 Opcode;\r
a3bcde70 386\r
d1050b9d 387 Instance = (MTFTP6_INSTANCE *)Context;\r
a3bcde70
HT
388\r
389 NET_CHECK_SIGNATURE (Instance, MTFTP6_INSTANCE_SIGNATURE);\r
390\r
391 IsCompleted = FALSE;\r
392 Packet = NULL;\r
393 Status = EFI_SUCCESS;\r
394 TotalNum = 0;\r
395\r
396 //\r
397 // Return error status if Udp6 instance failed to receive.\r
398 //\r
399 if (EFI_ERROR (IoStatus)) {\r
400 Status = IoStatus;\r
401 goto ON_EXIT;\r
402 }\r
403\r
404 ASSERT (UdpPacket != NULL);\r
405\r
406 if (UdpPacket->TotalSize < MTFTP6_OPCODE_LEN) {\r
407 goto ON_EXIT;\r
408 }\r
409\r
410 //\r
411 // Client send initial request to server's listening port. Server\r
412 // will select a UDP port to communicate with the client.\r
413 //\r
414 if (UdpEpt->RemotePort != Instance->ServerDataPort) {\r
415 if (Instance->ServerDataPort != 0) {\r
416 goto ON_EXIT;\r
417 } else {\r
418 Instance->ServerDataPort = UdpEpt->RemotePort;\r
419 }\r
420 }\r
421\r
422 //\r
423 // Copy the MTFTP packet to a continuous buffer if it isn't already so.\r
424 //\r
425 Len = UdpPacket->TotalSize;\r
426 TotalNum = UdpPacket->BlockOpNum;\r
427\r
428 if (TotalNum > 1) {\r
429 Packet = AllocateZeroPool (Len);\r
430\r
431 if (Packet == NULL) {\r
432 Status = EFI_OUT_OF_RESOURCES;\r
433 goto ON_EXIT;\r
434 }\r
435\r
d1050b9d 436 NetbufCopy (UdpPacket, 0, Len, (UINT8 *)Packet);\r
a3bcde70 437 } else {\r
d1050b9d 438 Packet = (EFI_MTFTP6_PACKET *)NetbufGetByte (UdpPacket, 0, NULL);\r
a3bcde70
HT
439 ASSERT (Packet != NULL);\r
440 }\r
441\r
442 Opcode = NTOHS (Packet->OpCode);\r
443\r
444 //\r
445 // Callback to the user's CheckPacket if provided. Abort the transmission\r
446 // if CheckPacket returns an EFI_ERROR code.\r
447 //\r
d1050b9d
MK
448 if ((Instance->Token->CheckPacket != NULL) &&\r
449 ((Opcode == EFI_MTFTP6_OPCODE_OACK) || (Opcode == EFI_MTFTP6_OPCODE_ERROR))\r
450 )\r
451 {\r
a3bcde70
HT
452 Status = Instance->Token->CheckPacket (\r
453 &Instance->Mtftp6,\r
454 Instance->Token,\r
d1050b9d 455 (UINT16)Len,\r
a3bcde70
HT
456 Packet\r
457 );\r
458\r
459 if (EFI_ERROR (Status)) {\r
460 //\r
461 // Send an error message to the server to inform it\r
462 //\r
463 if (Opcode != EFI_MTFTP6_OPCODE_ERROR) {\r
464 //\r
465 // Free the received packet before send new packet in ReceiveNotify,\r
466 // since the udpio might need to be reconfigured.\r
467 //\r
468 NetbufFree (UdpPacket);\r
469 UdpPacket = NULL;\r
470 //\r
471 // Send the Mtftp6 error message if user aborted the current session.\r
472 //\r
473 Mtftp6SendError (\r
474 Instance,\r
475 EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,\r
d1050b9d 476 (UINT8 *)"User aborted the transfer"\r
a3bcde70
HT
477 );\r
478 }\r
479\r
480 Status = EFI_ABORTED;\r
481 goto ON_EXIT;\r
482 }\r
483 }\r
484\r
485 //\r
486 // Switch the process routines by the operation code.\r
487 //\r
488 switch (Opcode) {\r
d1050b9d
MK
489 case EFI_MTFTP6_OPCODE_ACK:\r
490 if (Len != MTFTP6_OPCODE_LEN + MTFTP6_BLKNO_LEN) {\r
491 goto ON_EXIT;\r
492 }\r
a3bcde70 493\r
d1050b9d
MK
494 //\r
495 // Handle the Ack packet of Wrq.\r
496 //\r
497 Status = Mtftp6WrqHandleAck (Instance, Packet, Len, &UdpPacket, &IsCompleted);\r
498 break;\r
a3bcde70 499\r
d1050b9d
MK
500 case EFI_MTFTP6_OPCODE_OACK:\r
501 if (Len <= MTFTP6_OPCODE_LEN) {\r
502 goto ON_EXIT;\r
503 }\r
504\r
505 //\r
506 // Handle the Oack packet of Wrq.\r
507 //\r
508 Status = Mtftp6WrqHandleOack (Instance, Packet, Len, &UdpPacket, &IsCompleted);\r
509 break;\r
510\r
511 default:\r
512 //\r
513 // Drop and return eror if received error message.\r
514 //\r
515 Status = EFI_TFTP_ERROR;\r
516 break;\r
a3bcde70
HT
517 }\r
518\r
519ON_EXIT:\r
520 //\r
521 // Free the resources, then if !EFI_ERROR (Status) and not completed,\r
522 // restart the receive, otherwise end the session.\r
523 //\r
d1050b9d 524 if ((Packet != NULL) && (TotalNum > 1)) {\r
a3bcde70
HT
525 FreePool (Packet);\r
526 }\r
527\r
528 if (UdpPacket != NULL) {\r
529 NetbufFree (UdpPacket);\r
530 }\r
531\r
532 if (!EFI_ERROR (Status) && !IsCompleted) {\r
533 Status = UdpIoRecvDatagram (\r
534 Instance->UdpIo,\r
535 Mtftp6WrqInput,\r
536 Instance,\r
537 0\r
538 );\r
539 }\r
d1050b9d 540\r
a3bcde70
HT
541 //\r
542 // Clean up the current session if failed to continue.\r
543 //\r
544 if (EFI_ERROR (Status) || IsCompleted) {\r
545 Mtftp6OperationClean (Instance, Status);\r
546 }\r
547}\r
548\r
a3bcde70
HT
549/**\r
550 Start the Mtftp6 instance to upload. It will first init some states,\r
551 then send the WRQ request packet, and start to receive the packet.\r
552\r
553 @param[in] Instance The pointer to the Mtftp6 instance.\r
554 @param[in] Operation The operation code of the current packet.\r
555\r
556 @retval EFI_SUCCESS The Mtftp6 was started to upload.\r
557 @retval Others Failed to start to upload.\r
558\r
559**/\r
560EFI_STATUS\r
561Mtftp6WrqStart (\r
d1050b9d
MK
562 IN MTFTP6_INSTANCE *Instance,\r
563 IN UINT16 Operation\r
a3bcde70
HT
564 )\r
565{\r
d1050b9d 566 EFI_STATUS Status;\r
a3bcde70
HT
567\r
568 //\r
569 // The valid block number range are [0, 0xffff]. For example:\r
570 // the client sends an WRQ request to the server, the server\r
571 // ACK with an ACK0 to let client start transfer the first\r
572 // packet.\r
573 //\r
574 Status = Mtftp6InitBlockRange (&Instance->BlkList, 0, 0xffff);\r
575\r
576 if (EFI_ERROR (Status)) {\r
577 return Status;\r
578 }\r
579\r
580 Status = Mtftp6SendRequest (Instance, Operation);\r
581\r
582 if (EFI_ERROR (Status)) {\r
583 return Status;\r
584 }\r
585\r
586 return UdpIoRecvDatagram (\r
587 Instance->UdpIo,\r
588 Mtftp6WrqInput,\r
589 Instance,\r
590 0\r
591 );\r
592}\r