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