]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c
NetworkPkg: Apply uncrustify changes
[mirror_edk2.git] / NetworkPkg / Mtftp6Dxe / Mtftp6Rrq.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 Mtftp6 Rrq process functions implementation.\r
3\r
f3427f12 4 Copyright (c) 2009 - 2018, 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 ACK packet for download.\r
14\r
15 @param[in] Instance The pointer to the Mtftp6 instance.\r
16 @param[in] BlockNum The block number to be acked.\r
17\r
18 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.\r
19 @retval EFI_SUCCESS The ACK has been sent.\r
20 @retval Others Failed to send the ACK.\r
21\r
22**/\r
23EFI_STATUS\r
24Mtftp6RrqSendAck (\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 *Ack;\r
30 NET_BUF *Packet;\r
31 EFI_STATUS Status;\r
f3427f12
JW
32\r
33 Status = EFI_SUCCESS;\r
a3bcde70
HT
34\r
35 //\r
36 // Allocate net buffer to create ack packet.\r
37 //\r
38 Packet = NetbufAlloc (sizeof (EFI_MTFTP6_ACK_HEADER));\r
39\r
40 if (Packet == NULL) {\r
41 return EFI_OUT_OF_RESOURCES;\r
42 }\r
43\r
d1050b9d
MK
44 Ack = (EFI_MTFTP6_PACKET *)NetbufAllocSpace (\r
45 Packet,\r
46 sizeof (EFI_MTFTP6_ACK_HEADER),\r
47 FALSE\r
48 );\r
a3bcde70
HT
49 ASSERT (Ack != NULL);\r
50\r
d1050b9d
MK
51 Ack->Ack.OpCode = HTONS (EFI_MTFTP6_OPCODE_ACK);\r
52 Ack->Ack.Block[0] = HTONS (BlockNum);\r
a3bcde70
HT
53\r
54 //\r
55 // Reset current retry count of the instance.\r
56 //\r
d1050b9d 57 Instance->CurRetry = 0;\r
3aee9940 58 Instance->LastPacket = Packet;\r
a3bcde70 59\r
f3427f12
JW
60 Status = Mtftp6TransmitPacket (Instance, Packet);\r
61 if (!EFI_ERROR (Status)) {\r
62 Instance->AckedBlock = Instance->TotalBlock;\r
63 }\r
64\r
65 return Status;\r
a3bcde70
HT
66}\r
67\r
a3bcde70
HT
68/**\r
69 Deliver the received data block to the user, which can be saved\r
70 in the user provide buffer or through the CheckPacket callback.\r
71\r
72 @param[in] Instance The pointer to the Mtftp6 instance.\r
73 @param[in] Packet The pointer to the received packet.\r
74 @param[in] Len The packet length.\r
75 @param[out] UdpPacket The net buf of the received packet.\r
76\r
77 @retval EFI_SUCCESS The data was saved successfully.\r
78 @retval EFI_ABORTED The user tells to abort by return an error through\r
79 CheckPacket.\r
80 @retval EFI_BUFFER_TOO_SMALL The user's buffer is too small, and buffer length is\r
81 updated to the actual buffer size needed.\r
82\r
83**/\r
84EFI_STATUS\r
85Mtftp6RrqSaveBlock (\r
d1050b9d
MK
86 IN MTFTP6_INSTANCE *Instance,\r
87 IN EFI_MTFTP6_PACKET *Packet,\r
88 IN UINT32 Len,\r
89 OUT NET_BUF **UdpPacket\r
a3bcde70
HT
90 )\r
91{\r
d1050b9d
MK
92 EFI_MTFTP6_TOKEN *Token;\r
93 EFI_STATUS Status;\r
94 UINT16 Block;\r
95 UINT64 Start;\r
96 UINT32 DataLen;\r
97 UINT64 BlockCounter;\r
98 BOOLEAN Completed;\r
a3bcde70
HT
99\r
100 Completed = FALSE;\r
101 Token = Instance->Token;\r
102 Block = NTOHS (Packet->Data.Block);\r
103 DataLen = Len - MTFTP6_DATA_HEAD_LEN;\r
104\r
105 //\r
106 // This is the last block, save the block num\r
107 //\r
108 if (DataLen < Instance->BlkSize) {\r
d1050b9d 109 Completed = TRUE;\r
a3bcde70
HT
110 Instance->LastBlk = Block;\r
111 Mtftp6SetLastBlockNum (&Instance->BlkList, Block);\r
112 }\r
113\r
114 //\r
115 // Remove this block number from the file hole. If Mtftp6RemoveBlockNum\r
116 // returns EFI_NOT_FOUND, the block has been saved, don't save it again.\r
117 // Note that : For bigger files, allowing the block counter to roll over\r
2f6693c2 118 // to accept transfers of unlimited size. So BlockCounter is memorised as\r
a3bcde70
HT
119 // continuous block counter.\r
120 //\r
2f6693c2 121 Status = Mtftp6RemoveBlockNum (&Instance->BlkList, Block, Completed, &BlockCounter);\r
a3bcde70
HT
122\r
123 if (Status == EFI_NOT_FOUND) {\r
124 return EFI_SUCCESS;\r
125 } else if (EFI_ERROR (Status)) {\r
126 return Status;\r
127 }\r
128\r
129 if (Token->CheckPacket != NULL) {\r
130 //\r
131 // Callback to the check packet routine with the received packet.\r
132 //\r
d1050b9d 133 Status = Token->CheckPacket (&Instance->Mtftp6, Token, (UINT16)Len, Packet);\r
a3bcde70
HT
134\r
135 if (EFI_ERROR (Status)) {\r
136 //\r
137 // Free the received packet before send new packet in ReceiveNotify,\r
138 // since the Udp6Io might need to be reconfigured.\r
139 //\r
140 NetbufFree (*UdpPacket);\r
141 *UdpPacket = NULL;\r
142 //\r
143 // Send the Mtftp6 error message if user aborted the current session.\r
144 //\r
145 Mtftp6SendError (\r
146 Instance,\r
147 EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,\r
d1050b9d 148 (UINT8 *)"User aborted download"\r
a3bcde70
HT
149 );\r
150\r
151 return EFI_ABORTED;\r
152 }\r
153 }\r
154\r
155 if (Token->Buffer != NULL) {\r
2f6693c2 156 Start = MultU64x32 (BlockCounter - 1, Instance->BlkSize);\r
a3bcde70 157 if (Start + DataLen <= Token->BufferSize) {\r
d1050b9d 158 CopyMem ((UINT8 *)Token->Buffer + Start, Packet->Data.Data, DataLen);\r
a3bcde70
HT
159 //\r
160 // Update the file size when received the last block\r
161 //\r
162 if ((Instance->LastBlk == Block) && Completed) {\r
163 Token->BufferSize = Start + DataLen;\r
164 }\r
165 } else if (Instance->LastBlk != 0) {\r
166 //\r
167 // Don't save the data if the buffer is too small, return\r
168 // EFI_BUFFER_TOO_SMALL if received the last packet. This\r
169 // will give a accurate file length.\r
170 //\r
171 Token->BufferSize = Start + DataLen;\r
172\r
173 //\r
174 // Free the received packet before send new packet in ReceiveNotify,\r
175 // since the udpio might need to be reconfigured.\r
176 //\r
177 NetbufFree (*UdpPacket);\r
178 *UdpPacket = NULL;\r
179 //\r
180 // Send the Mtftp6 error message if no enough buffer.\r
181 //\r
182 Mtftp6SendError (\r
183 Instance,\r
184 EFI_MTFTP6_ERRORCODE_DISK_FULL,\r
d1050b9d 185 (UINT8 *)"User provided memory block is too small"\r
a3bcde70
HT
186 );\r
187\r
188 return EFI_BUFFER_TOO_SMALL;\r
189 }\r
190 }\r
191\r
192 return EFI_SUCCESS;\r
193}\r
194\r
a3bcde70
HT
195/**\r
196 Process the received data packets. It will save the block\r
197 then send back an ACK if it is active.\r
198\r
199 @param[in] Instance The pointer to the Mtftp6 instance.\r
200 @param[in] Packet The pointer to the received packet.\r
201 @param[in] Len The length of the packet.\r
202 @param[out] UdpPacket The net buf of received packet.\r
203 @param[out] IsCompleted If TRUE, the download has been completed.\r
204 Otherwise, the download has not been completed.\r
205\r
206 @retval EFI_SUCCESS The data packet was successfully processed.\r
207 @retval EFI_ABORTED The download was aborted by the user.\r
208 @retval EFI_BUFFER_TOO_SMALL The user-provided buffer is too small.\r
209\r
210**/\r
211EFI_STATUS\r
212Mtftp6RrqHandleData (\r
d1050b9d
MK
213 IN MTFTP6_INSTANCE *Instance,\r
214 IN EFI_MTFTP6_PACKET *Packet,\r
215 IN UINT32 Len,\r
216 OUT NET_BUF **UdpPacket,\r
217 OUT BOOLEAN *IsCompleted\r
a3bcde70
HT
218 )\r
219{\r
d1050b9d
MK
220 EFI_STATUS Status;\r
221 UINT16 BlockNum;\r
222 INTN Expected;\r
a3bcde70
HT
223\r
224 *IsCompleted = FALSE;\r
f3427f12 225 Status = EFI_SUCCESS;\r
a3bcde70
HT
226 BlockNum = NTOHS (Packet->Data.Block);\r
227 Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);\r
228\r
229 ASSERT (Expected >= 0);\r
230\r
231 //\r
2f6693c2 232 // If we are active (Master) and received an unexpected packet, transmit\r
f3427f12 233 // the ACK for the block we received, then restart receiving the\r
2f6693c2 234 // expected one. If we are passive (Slave), save the block.\r
a3bcde70
HT
235 //\r
236 if (Instance->IsMaster && (Expected != BlockNum)) {\r
237 //\r
238 // Free the received packet before send new packet in ReceiveNotify,\r
239 // since the udpio might need to be reconfigured.\r
240 //\r
241 NetbufFree (*UdpPacket);\r
242 *UdpPacket = NULL;\r
243\r
f3427f12
JW
244 //\r
245 // If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack number (65535).\r
246 //\r
d1050b9d 247 return Mtftp6RrqSendAck (Instance, (UINT16)(Expected - 1));\r
a3bcde70
HT
248 }\r
249\r
250 Status = Mtftp6RrqSaveBlock (Instance, Packet, Len, UdpPacket);\r
251\r
252 if (EFI_ERROR (Status)) {\r
253 return Status;\r
254 }\r
255\r
2f6693c2
JW
256 //\r
257 // Record the total received and saved block number.\r
258 //\r
d1050b9d 259 Instance->TotalBlock++;\r
2f6693c2 260\r
a3bcde70
HT
261 //\r
262 // Reset the passive client's timer whenever it received a valid data packet.\r
263 //\r
264 if (!Instance->IsMaster) {\r
265 Instance->PacketToLive = Instance->Timeout * 2;\r
266 }\r
267\r
268 //\r
269 // Check whether we have received all the blocks. Send the ACK if we\r
270 // are active (unicast client or master client for multicast download).\r
271 // If we have received all the blocks, send an ACK even if we are passive\r
272 // to tell the server that we are done.\r
273 //\r
274 Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);\r
275\r
d1050b9d 276 if (Instance->IsMaster || (Expected < 0)) {\r
a3bcde70
HT
277 if (Expected < 0) {\r
278 //\r
279 // If we are passive client, then the just received Block maybe\r
280 // isn't the last block. We need to send an ACK to the last block\r
281 // to inform the server that we are done. If we are active client,\r
282 // the Block == Instance->LastBlock.\r
283 //\r
284 BlockNum = Instance->LastBlk;\r
285 *IsCompleted = TRUE;\r
a3bcde70 286 } else {\r
d1050b9d 287 BlockNum = (UINT16)(Expected - 1);\r
a3bcde70 288 }\r
d1050b9d 289\r
a3bcde70
HT
290 //\r
291 // Free the received packet before send new packet in ReceiveNotify,\r
292 // since the udpio might need to be reconfigured.\r
293 //\r
294 NetbufFree (*UdpPacket);\r
295 *UdpPacket = NULL;\r
296\r
d1050b9d 297 if ((Instance->WindowSize == (Instance->TotalBlock - Instance->AckedBlock)) || (Expected < 0)) {\r
f3427f12
JW
298 Status = Mtftp6RrqSendAck (Instance, BlockNum);\r
299 }\r
a3bcde70
HT
300 }\r
301\r
f3427f12 302 return Status;\r
a3bcde70
HT
303}\r
304\r
a3bcde70
HT
305/**\r
306 Validate whether the options received in the server's OACK packet is valid.\r
307 The options are valid only if:\r
308 1. The server doesn't include options not requested by us.\r
309 2. The server can only use smaller blksize than that is requested.\r
310 3. The server can only use the same timeout as requested.\r
311 4. The server doesn't change its multicast channel.\r
312\r
313 @param[in] Instance The pointer to the Mtftp6 instance.\r
314 @param[in] ReplyInfo The pointer to options information in reply packet.\r
315 @param[in] RequestInfo The pointer to requested options info.\r
316\r
317 @retval TRUE If the option in the OACK is valid.\r
318 @retval FALSE If the option is invalid.\r
319\r
320**/\r
321BOOLEAN\r
322Mtftp6RrqOackValid (\r
d1050b9d
MK
323 IN MTFTP6_INSTANCE *Instance,\r
324 IN MTFTP6_EXT_OPTION_INFO *ReplyInfo,\r
325 IN MTFTP6_EXT_OPTION_INFO *RequestInfo\r
a3bcde70
HT
326 )\r
327{\r
328 //\r
329 // It is invalid for server to return options we don't request\r
330 //\r
331 if ((ReplyInfo->BitMap & ~RequestInfo->BitMap) != 0) {\r
332 return FALSE;\r
333 }\r
334\r
335 //\r
f3427f12 336 // Server can only specify a smaller block size and windowsize to be used and\r
a3bcde70
HT
337 // return the timeout matches that requested.\r
338 //\r
339 if ((((ReplyInfo->BitMap & MTFTP6_OPT_BLKSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||\r
f3427f12 340 (((ReplyInfo->BitMap & MTFTP6_OPT_WINDOWSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||\r
a3bcde70 341 (((ReplyInfo->BitMap & MTFTP6_OPT_TIMEOUT_BIT) != 0) && (ReplyInfo->Timeout != RequestInfo->Timeout))\r
d1050b9d
MK
342 )\r
343 {\r
a3bcde70
HT
344 return FALSE;\r
345 }\r
346\r
347 //\r
348 // The server can send ",,master" to client to change its master\r
349 // setting. But if it use the specific multicast channel, it can't\r
350 // change the setting.\r
351 //\r
352 if (((ReplyInfo->BitMap & MTFTP6_OPT_MCAST_BIT) != 0) && !NetIp6IsUnspecifiedAddr (&Instance->McastIp)) {\r
d1050b9d
MK
353 if (!NetIp6IsUnspecifiedAddr (&ReplyInfo->McastIp) && (CompareMem (\r
354 &ReplyInfo->McastIp,\r
355 &Instance->McastIp,\r
356 sizeof (EFI_IPv6_ADDRESS)\r
357 ) != 0))\r
358 {\r
a3bcde70
HT
359 return FALSE;\r
360 }\r
361\r
362 if ((ReplyInfo->McastPort != 0) && (ReplyInfo->McastPort != Instance->McastPort)) {\r
363 return FALSE;\r
364 }\r
365 }\r
366\r
367 return TRUE;\r
368}\r
369\r
a3bcde70
HT
370/**\r
371 Configure Udp6Io to receive a packet from a multicast address.\r
372\r
373 @param[in] McastIo The pointer to the mcast Udp6Io.\r
374 @param[in] Context The pointer to the context.\r
375\r
376 @retval EFI_SUCCESS The mcast Udp6Io was successfully configured.\r
377 @retval Others Failed to configure the Udp6Io.\r
378\r
379**/\r
380EFI_STATUS\r
381EFIAPI\r
382Mtftp6RrqConfigMcastUdpIo (\r
d1050b9d
MK
383 IN UDP_IO *McastIo,\r
384 IN VOID *Context\r
a3bcde70
HT
385 )\r
386{\r
d1050b9d
MK
387 EFI_STATUS Status;\r
388 EFI_UDP6_PROTOCOL *Udp6;\r
389 EFI_UDP6_CONFIG_DATA *Udp6Cfg;\r
390 EFI_IPv6_ADDRESS Group;\r
391 MTFTP6_INSTANCE *Instance;\r
a3bcde70
HT
392\r
393 Udp6 = McastIo->Protocol.Udp6;\r
394 Udp6Cfg = &(McastIo->Config.Udp6);\r
d1050b9d 395 Instance = (MTFTP6_INSTANCE *)Context;\r
a3bcde70
HT
396\r
397 //\r
398 // Set the configure data for the mcast Udp6Io.\r
399 //\r
400 ZeroMem (Udp6Cfg, sizeof (EFI_UDP6_CONFIG_DATA));\r
401\r
402 Udp6Cfg->AcceptPromiscuous = FALSE;\r
403 Udp6Cfg->AcceptAnyPort = FALSE;\r
404 Udp6Cfg->AllowDuplicatePort = FALSE;\r
405 Udp6Cfg->TrafficClass = 0;\r
406 Udp6Cfg->HopLimit = 128;\r
407 Udp6Cfg->ReceiveTimeout = 0;\r
408 Udp6Cfg->TransmitTimeout = 0;\r
409 Udp6Cfg->StationPort = Instance->McastPort;\r
410 Udp6Cfg->RemotePort = 0;\r
411\r
412 CopyMem (\r
413 &Udp6Cfg->RemoteAddress,\r
414 &Instance->ServerIp,\r
415 sizeof (EFI_IPv6_ADDRESS)\r
416 );\r
417\r
418 //\r
419 // Configure the mcast Udp6Io.\r
420 //\r
421 Status = Udp6->Configure (Udp6, Udp6Cfg);\r
422\r
423 if (EFI_ERROR (Status)) {\r
424 return Status;\r
425 }\r
426\r
427 //\r
428 // Join the multicast group\r
429 //\r
430 CopyMem (&Group, &Instance->McastIp, sizeof (EFI_IPv6_ADDRESS));\r
431\r
432 return Udp6->Groups (Udp6, TRUE, &Group);\r
433}\r
434\r
a3bcde70
HT
435/**\r
436 Process the OACK packet for Rrq.\r
437\r
438 @param[in] Instance The pointer to the Mtftp6 instance.\r
439 @param[in] Packet The pointer to the received packet.\r
440 @param[in] Len The length of the packet.\r
441 @param[out] UdpPacket The net buf of received packet.\r
442 @param[out] IsCompleted If TRUE, the download has been completed.\r
443 Otherwise, the download has not been completed.\r
444\r
445 @retval EFI_DEVICE_ERROR Failed to create/start a multicast Udp6 child.\r
446 @retval EFI_TFTP_ERROR An error happened during the process.\r
447 @retval EFI_SUCCESS The OACK packet successfully processed.\r
448\r
449**/\r
450EFI_STATUS\r
451Mtftp6RrqHandleOack (\r
d1050b9d
MK
452 IN MTFTP6_INSTANCE *Instance,\r
453 IN EFI_MTFTP6_PACKET *Packet,\r
454 IN UINT32 Len,\r
455 OUT NET_BUF **UdpPacket,\r
456 OUT BOOLEAN *IsCompleted\r
a3bcde70
HT
457 )\r
458{\r
d1050b9d
MK
459 EFI_MTFTP6_OPTION *Options;\r
460 UINT32 Count;\r
461 MTFTP6_EXT_OPTION_INFO ExtInfo;\r
462 EFI_STATUS Status;\r
463 INTN Expected;\r
464 EFI_UDP6_PROTOCOL *Udp6;\r
a3bcde70
HT
465\r
466 *IsCompleted = FALSE;\r
d1050b9d 467 Options = NULL;\r
a3bcde70
HT
468\r
469 //\r
470 // If already started the master download, don't change the\r
471 // setting. Master download always succeeds.\r
472 //\r
473 Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);\r
474 ASSERT (Expected != -1);\r
475\r
d1050b9d 476 if (Instance->IsMaster && (Expected != 1)) {\r
a3bcde70
HT
477 return EFI_SUCCESS;\r
478 }\r
479\r
480 ZeroMem (&ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));\r
481\r
482 //\r
483 // Parse the options in the packet.\r
484 //\r
485 Status = Mtftp6ParseStart (Packet, Len, &Count, &Options);\r
486\r
487 if (EFI_ERROR (Status)) {\r
488 return Status;\r
489 }\r
d1050b9d 490\r
7a49cd08 491 ASSERT (Options != NULL);\r
a3bcde70
HT
492\r
493 //\r
494 // Parse the extensive options in the packet.\r
495 //\r
f3427f12 496 Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, Instance->Operation, &ExtInfo);\r
a3bcde70
HT
497\r
498 if (EFI_ERROR (Status) || !Mtftp6RrqOackValid (Instance, &ExtInfo, &Instance->ExtInfo)) {\r
499 //\r
500 // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.\r
501 //\r
502 if (Status != EFI_OUT_OF_RESOURCES) {\r
503 //\r
504 // Free the received packet before send new packet in ReceiveNotify,\r
505 // since the udpio might need to be reconfigured.\r
506 //\r
507 NetbufFree (*UdpPacket);\r
508 *UdpPacket = NULL;\r
509 //\r
510 // Send the Mtftp6 error message if invalid packet.\r
511 //\r
512 Mtftp6SendError (\r
513 Instance,\r
514 EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,\r
d1050b9d 515 (UINT8 *)"Malformatted OACK packet"\r
a3bcde70
HT
516 );\r
517 }\r
518\r
519 return EFI_TFTP_ERROR;\r
520 }\r
521\r
522 if ((ExtInfo.BitMap & MTFTP6_OPT_MCAST_BIT) != 0) {\r
a3bcde70
HT
523 //\r
524 // Save the multicast info. Always update the Master, only update the\r
f3427f12 525 // multicast IP address, block size, window size, timeoute at the first time. If IP\r
a3bcde70
HT
526 // address is updated, create a UDP child to receive the multicast.\r
527 //\r
528 Instance->IsMaster = ExtInfo.IsMaster;\r
529\r
530 if (NetIp6IsUnspecifiedAddr (&Instance->McastIp)) {\r
d1050b9d 531 if (NetIp6IsUnspecifiedAddr (&ExtInfo.McastIp) || (ExtInfo.McastPort == 0)) {\r
a3bcde70
HT
532 //\r
533 // Free the received packet before send new packet in ReceiveNotify,\r
534 // since the udpio might need to be reconfigured.\r
535 //\r
536 NetbufFree (*UdpPacket);\r
537 *UdpPacket = NULL;\r
538 //\r
539 // Send the Mtftp6 error message if invalid multi-cast setting.\r
540 //\r
541 Mtftp6SendError (\r
542 Instance,\r
543 EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,\r
d1050b9d 544 (UINT8 *)"Illegal multicast setting"\r
a3bcde70
HT
545 );\r
546\r
547 return EFI_TFTP_ERROR;\r
548 }\r
549\r
550 //\r
551 // Create a UDP child then start receive the multicast from it.\r
552 //\r
553 CopyMem (\r
554 &Instance->McastIp,\r
555 &ExtInfo.McastIp,\r
556 sizeof (EFI_IP_ADDRESS)\r
557 );\r
558\r
d1050b9d 559 Instance->McastPort = ExtInfo.McastPort;\r
75dce340 560 if (Instance->McastUdpIo == NULL) {\r
561 Instance->McastUdpIo = UdpIoCreateIo (\r
562 Instance->Service->Controller,\r
563 Instance->Service->Image,\r
564 Mtftp6RrqConfigMcastUdpIo,\r
565 UDP_IO_UDP6_VERSION,\r
566 Instance\r
567 );\r
216f7970 568 if (Instance->McastUdpIo != NULL) {\r
569 Status = gBS->OpenProtocol (\r
570 Instance->McastUdpIo->UdpHandle,\r
571 &gEfiUdp6ProtocolGuid,\r
d1050b9d 572 (VOID **)&Udp6,\r
216f7970 573 Instance->Service->Image,\r
574 Instance->Handle,\r
575 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
576 );\r
577 if (EFI_ERROR (Status)) {\r
578 UdpIoFreeIo (Instance->McastUdpIo);\r
579 Instance->McastUdpIo = NULL;\r
580 return EFI_DEVICE_ERROR;\r
581 }\r
582 }\r
75dce340 583 }\r
a3bcde70
HT
584\r
585 if (Instance->McastUdpIo == NULL) {\r
586 return EFI_DEVICE_ERROR;\r
587 }\r
588\r
589 Status = UdpIoRecvDatagram (\r
590 Instance->McastUdpIo,\r
591 Mtftp6RrqInput,\r
592 Instance,\r
593 0\r
594 );\r
595\r
596 if (EFI_ERROR (Status)) {\r
597 //\r
598 // Free the received packet before send new packet in ReceiveNotify,\r
599 // since the udpio might need to be reconfigured.\r
600 //\r
601 NetbufFree (*UdpPacket);\r
602 *UdpPacket = NULL;\r
603 //\r
604 // Send the Mtftp6 error message if failed to create Udp6Io to receive.\r
605 //\r
606 Mtftp6SendError (\r
607 Instance,\r
608 EFI_MTFTP6_ERRORCODE_ACCESS_VIOLATION,\r
d1050b9d 609 (UINT8 *)"Failed to create socket to receive multicast packet"\r
a3bcde70
HT
610 );\r
611\r
612 return Status;\r
613 }\r
614\r
615 //\r
616 // Update the parameters used.\r
617 //\r
618 if (ExtInfo.BlkSize != 0) {\r
619 Instance->BlkSize = ExtInfo.BlkSize;\r
620 }\r
621\r
f3427f12
JW
622 if (ExtInfo.WindowSize != 0) {\r
623 Instance->WindowSize = ExtInfo.WindowSize;\r
624 }\r
625\r
a3bcde70
HT
626 if (ExtInfo.Timeout != 0) {\r
627 Instance->Timeout = ExtInfo.Timeout;\r
628 }\r
629 }\r
a3bcde70 630 } else {\r
a3bcde70
HT
631 Instance->IsMaster = TRUE;\r
632\r
633 if (ExtInfo.BlkSize != 0) {\r
634 Instance->BlkSize = ExtInfo.BlkSize;\r
635 }\r
636\r
f3427f12
JW
637 if (ExtInfo.WindowSize != 0) {\r
638 Instance->WindowSize = ExtInfo.WindowSize;\r
639 }\r
640\r
a3bcde70
HT
641 if (ExtInfo.Timeout != 0) {\r
642 Instance->Timeout = ExtInfo.Timeout;\r
643 }\r
644 }\r
645\r
646 //\r
647 // Free the received packet before send new packet in ReceiveNotify,\r
648 // since the udpio might need to be reconfigured.\r
649 //\r
650 NetbufFree (*UdpPacket);\r
651 *UdpPacket = NULL;\r
652 //\r
653 // Send an ACK to (Expected - 1) which is 0 for unicast download,\r
654 // or tell the server we want to receive the Expected block.\r
655 //\r
d1050b9d 656 return Mtftp6RrqSendAck (Instance, (UINT16)(Expected - 1));\r
a3bcde70
HT
657}\r
658\r
a3bcde70
HT
659/**\r
660 The packet process callback for Mtftp6 download.\r
661\r
662 @param[in] UdpPacket The pointer to the packet received.\r
663 @param[in] UdpEpt The pointer to the Udp6 access point.\r
664 @param[in] IoStatus The status from Udp6 instance.\r
665 @param[in] Context The pointer to the context.\r
666\r
667**/\r
668VOID\r
669EFIAPI\r
670Mtftp6RrqInput (\r
d1050b9d
MK
671 IN NET_BUF *UdpPacket,\r
672 IN UDP_END_POINT *UdpEpt,\r
673 IN EFI_STATUS IoStatus,\r
674 IN VOID *Context\r
a3bcde70
HT
675 )\r
676{\r
d1050b9d
MK
677 MTFTP6_INSTANCE *Instance;\r
678 EFI_MTFTP6_PACKET *Packet;\r
679 BOOLEAN IsCompleted;\r
680 BOOLEAN IsMcast;\r
681 EFI_STATUS Status;\r
682 UINT16 Opcode;\r
683 UINT32 TotalNum;\r
684 UINT32 Len;\r
a3bcde70 685\r
d1050b9d 686 Instance = (MTFTP6_INSTANCE *)Context;\r
a3bcde70
HT
687\r
688 NET_CHECK_SIGNATURE (Instance, MTFTP6_INSTANCE_SIGNATURE);\r
689\r
690 Status = EFI_SUCCESS;\r
691 Packet = NULL;\r
692 IsCompleted = FALSE;\r
693 IsMcast = FALSE;\r
694 TotalNum = 0;\r
695\r
696 //\r
697 // Return error status if Udp6 instance failed to receive.\r
698 //\r
699 if (EFI_ERROR (IoStatus)) {\r
700 Status = IoStatus;\r
701 goto ON_EXIT;\r
702 }\r
703\r
704 ASSERT (UdpPacket != NULL);\r
705\r
706 if (UdpPacket->TotalSize < MTFTP6_OPCODE_LEN) {\r
707 goto ON_EXIT;\r
708 }\r
709\r
710 //\r
711 // Find the port this packet is from to restart receive correctly.\r
712 //\r
713 if (CompareMem (\r
714 Ip6Swap128 (&UdpEpt->LocalAddr.v6),\r
715 &Instance->McastIp,\r
716 sizeof (EFI_IPv6_ADDRESS)\r
d1050b9d
MK
717 ) == 0)\r
718 {\r
a3bcde70
HT
719 IsMcast = TRUE;\r
720 } else {\r
721 IsMcast = FALSE;\r
722 }\r
723\r
724 //\r
725 // Client send initial request to server's listening port. Server\r
726 // will select a UDP port to communicate with the client. The server\r
727 // is required to use the same port as RemotePort to multicast the\r
728 // data.\r
729 //\r
730 if (UdpEpt->RemotePort != Instance->ServerDataPort) {\r
731 if (Instance->ServerDataPort != 0) {\r
732 goto ON_EXIT;\r
733 } else {\r
734 //\r
735 // For the subsequent exchange of requests, reconfigure the udpio as\r
736 // (serverip, serverport, localip, localport).\r
f6c8bbbe 737 // Usually, the client set serverport as 0 to receive and reset it\r
a3bcde70
HT
738 // once the first packet arrives to send ack.\r
739 //\r
740 Instance->ServerDataPort = UdpEpt->RemotePort;\r
741 }\r
742 }\r
743\r
744 //\r
745 // Copy the MTFTP packet to a continuous buffer if it isn't already so.\r
746 //\r
747 Len = UdpPacket->TotalSize;\r
748 TotalNum = UdpPacket->BlockOpNum;\r
749\r
750 if (TotalNum > 1) {\r
751 Packet = AllocateZeroPool (Len);\r
752\r
753 if (Packet == NULL) {\r
754 Status = EFI_OUT_OF_RESOURCES;\r
755 goto ON_EXIT;\r
756 }\r
757\r
d1050b9d 758 NetbufCopy (UdpPacket, 0, Len, (UINT8 *)Packet);\r
a3bcde70 759 } else {\r
d1050b9d 760 Packet = (EFI_MTFTP6_PACKET *)NetbufGetByte (UdpPacket, 0, NULL);\r
a3bcde70
HT
761 ASSERT (Packet != NULL);\r
762 }\r
763\r
764 Opcode = NTOHS (Packet->OpCode);\r
765\r
766 //\r
767 // Callback to the user's CheckPacket if provided. Abort the transmission\r
768 // if CheckPacket returns an EFI_ERROR code.\r
769 //\r
770 if ((Instance->Token->CheckPacket != NULL) &&\r
d1050b9d
MK
771 ((Opcode == EFI_MTFTP6_OPCODE_OACK) || (Opcode == EFI_MTFTP6_OPCODE_ERROR))\r
772 )\r
773 {\r
a3bcde70
HT
774 Status = Instance->Token->CheckPacket (\r
775 &Instance->Mtftp6,\r
776 Instance->Token,\r
d1050b9d 777 (UINT16)Len,\r
a3bcde70
HT
778 Packet\r
779 );\r
780\r
781 if (EFI_ERROR (Status)) {\r
782 //\r
783 // Send an error message to the server to inform it\r
784 //\r
785 if (Opcode != EFI_MTFTP6_OPCODE_ERROR) {\r
786 //\r
787 // Free the received packet before send new packet in ReceiveNotify,\r
788 // since the udpio might need to be reconfigured.\r
789 //\r
790 NetbufFree (UdpPacket);\r
791 UdpPacket = NULL;\r
792 //\r
793 // Send the Mtftp6 error message if user aborted the current session.\r
794 //\r
795 Mtftp6SendError (\r
796 Instance,\r
797 EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,\r
d1050b9d 798 (UINT8 *)"User aborted the transfer"\r
a3bcde70
HT
799 );\r
800 }\r
801\r
802 Status = EFI_ABORTED;\r
803 goto ON_EXIT;\r
804 }\r
805 }\r
806\r
807 //\r
808 // Switch the process routines by the operation code.\r
809 //\r
810 switch (Opcode) {\r
d1050b9d
MK
811 case EFI_MTFTP6_OPCODE_DATA:\r
812 if ((Len > (UINT32)(MTFTP6_DATA_HEAD_LEN + Instance->BlkSize)) || (Len < (UINT32)MTFTP6_DATA_HEAD_LEN)) {\r
813 goto ON_EXIT;\r
814 }\r
815\r
816 //\r
817 // Handle the data packet of Rrq.\r
818 //\r
819 Status = Mtftp6RrqHandleData (\r
820 Instance,\r
821 Packet,\r
822 Len,\r
823 &UdpPacket,\r
824 &IsCompleted\r
825 );\r
826 break;\r
827\r
828 case EFI_MTFTP6_OPCODE_OACK:\r
829 if (IsMcast || (Len <= MTFTP6_OPCODE_LEN)) {\r
830 goto ON_EXIT;\r
831 }\r
832\r
833 //\r
834 // Handle the Oack packet of Rrq.\r
835 //\r
836 Status = Mtftp6RrqHandleOack (\r
837 Instance,\r
838 Packet,\r
839 Len,\r
840 &UdpPacket,\r
841 &IsCompleted\r
842 );\r
843 break;\r
844\r
845 default:\r
846 //\r
847 // Drop and return error if received error message.\r
848 //\r
849 Status = EFI_TFTP_ERROR;\r
850 break;\r
a3bcde70
HT
851 }\r
852\r
853ON_EXIT:\r
854 //\r
855 // Free the resources, then if !EFI_ERROR (Status), restart the\r
856 // receive, otherwise end the session.\r
857 //\r
d1050b9d 858 if ((Packet != NULL) && (TotalNum > 1)) {\r
a3bcde70
HT
859 FreePool (Packet);\r
860 }\r
d1050b9d 861\r
a3bcde70
HT
862 if (UdpPacket != NULL) {\r
863 NetbufFree (UdpPacket);\r
864 }\r
d1050b9d 865\r
a3bcde70
HT
866 if (!EFI_ERROR (Status) && !IsCompleted) {\r
867 if (IsMcast) {\r
868 Status = UdpIoRecvDatagram (\r
869 Instance->McastUdpIo,\r
870 Mtftp6RrqInput,\r
871 Instance,\r
872 0\r
873 );\r
874 } else {\r
875 Status = UdpIoRecvDatagram (\r
876 Instance->UdpIo,\r
877 Mtftp6RrqInput,\r
878 Instance,\r
879 0\r
880 );\r
881 }\r
882 }\r
d1050b9d 883\r
a3bcde70
HT
884 //\r
885 // Clean up the current session if failed to continue.\r
886 //\r
887 if (EFI_ERROR (Status) || IsCompleted) {\r
888 Mtftp6OperationClean (Instance, Status);\r
889 }\r
890}\r
891\r
a3bcde70
HT
892/**\r
893 Start the Mtftp6 instance to download. It first initializes some\r
f6c8bbbe 894 of the internal states, then builds and sends an RRQ request packet.\r
a3bcde70
HT
895 Finally, it starts receive for the downloading.\r
896\r
897 @param[in] Instance The pointer to the Mtftp6 instance.\r
898 @param[in] Operation The operation code of current packet.\r
899\r
900 @retval EFI_SUCCESS The Mtftp6 is started to download.\r
901 @retval Others Failed to start to download.\r
902\r
903**/\r
904EFI_STATUS\r
905Mtftp6RrqStart (\r
d1050b9d
MK
906 IN MTFTP6_INSTANCE *Instance,\r
907 IN UINT16 Operation\r
a3bcde70
HT
908 )\r
909{\r
d1050b9d 910 EFI_STATUS Status;\r
a3bcde70
HT
911\r
912 //\r
913 // The valid block number range are [1, 0xffff]. For example:\r
914 // the client sends an RRQ request to the server, the server\r
f6c8bbbe 915 // transfers the DATA1 block. If option negotiation is ongoing,\r
a3bcde70
HT
916 // the server will send back an OACK, then client will send ACK0.\r
917 //\r
918 Status = Mtftp6InitBlockRange (&Instance->BlkList, 1, 0xffff);\r
919\r
920 if (EFI_ERROR (Status)) {\r
921 return Status;\r
922 }\r
923\r
924 Status = Mtftp6SendRequest (Instance, Operation);\r
925\r
926 if (EFI_ERROR (Status)) {\r
927 return Status;\r
928 }\r
929\r
930 return UdpIoRecvDatagram (\r
931 Instance->UdpIo,\r
932 Mtftp6RrqInput,\r
933 Instance,\r
934 0\r
935 );\r
936}\r