]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c
MdeModulePkg: Source fixes and cleanup for ARMGCC compiles
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Rrq.c
CommitLineData
772db4bb 1/** @file\r
dab714aa 2 Routines to process Rrq (download).\r
3 \r
35f910f0 4(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
523f48e7 5Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 6This program and the accompanying materials\r
772db4bb 7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
dab714aa 9http://opensource.org/licenses/bsd-license.php<BR>\r
772db4bb 10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
dab714aa 14**/\r
772db4bb 15\r
772db4bb 16\r
dab714aa 17#include "Mtftp4Impl.h"\r
772db4bb 18\r
19\r
dab714aa 20/**\r
21 The packet process callback for MTFTP download.\r
772db4bb 22\r
dab714aa 23 @param UdpPacket The packet received\r
b45b45b2 24 @param EndPoint The local/remote access point of the packet\r
dab714aa 25 @param IoStatus The status of the receiving\r
26 @param Context Opaque parameter, which is the MTFTP session\r
772db4bb 27\r
dab714aa 28**/\r
772db4bb 29VOID\r
e798cd87 30EFIAPI\r
772db4bb 31Mtftp4RrqInput (\r
32 IN NET_BUF *UdpPacket,\r
b45b45b2 33 IN UDP_END_POINT *EndPoint,\r
772db4bb 34 IN EFI_STATUS IoStatus,\r
35 IN VOID *Context\r
36 );\r
37\r
38\r
39/**\r
dab714aa 40 Start the MTFTP session to download. \r
41 \r
42 It will first initialize some of the internal states then build and send a RRQ \r
43 reqeuest packet, at last, it will start receive for the downloading.\r
772db4bb 44\r
45 @param Instance The Mtftp session\r
46 @param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ\r
47 or EFI_MTFTP4_OPCODE_DIR.\r
48\r
49 @retval EFI_SUCCESS The mtftp download session is started.\r
50 @retval Others Failed to start downloading.\r
51\r
52**/\r
53EFI_STATUS\r
54Mtftp4RrqStart (\r
55 IN MTFTP4_PROTOCOL *Instance,\r
56 IN UINT16 Operation\r
57 )\r
58{\r
59 EFI_STATUS Status;\r
60\r
61 //\r
62 // The valid block number range are [1, 0xffff]. For example:\r
63 // the client sends an RRQ request to the server, the server\r
64 // transfers the DATA1 block. If option negoitation is ongoing,\r
65 // the server will send back an OACK, then client will send ACK0.\r
66 //\r
67 Status = Mtftp4InitBlockRange (&Instance->Blocks, 1, 0xffff);\r
68\r
69 if (EFI_ERROR (Status)) {\r
70 return Status;\r
71 }\r
72\r
73 Status = Mtftp4SendRequest (Instance);\r
74\r
75 if (EFI_ERROR (Status)) {\r
76 return Status;\r
77 }\r
78\r
79 return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);\r
80}\r
81\r
82\r
83/**\r
84 Build and send a ACK packet for the download session.\r
85\r
86 @param Instance The Mtftp session\r
87 @param BlkNo The BlkNo to ack.\r
88\r
89 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet\r
90 @retval EFI_SUCCESS The ACK has been sent\r
91 @retval Others Failed to send the ACK.\r
92\r
93**/\r
94EFI_STATUS\r
95Mtftp4RrqSendAck (\r
96 IN MTFTP4_PROTOCOL *Instance,\r
97 IN UINT16 BlkNo\r
98 )\r
99{\r
100 EFI_MTFTP4_PACKET *Ack;\r
101 NET_BUF *Packet;\r
102\r
103 Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER));\r
772db4bb 104 if (Packet == NULL) {\r
105 return EFI_OUT_OF_RESOURCES;\r
106 }\r
107\r
108 Ack = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (\r
109 Packet,\r
110 sizeof (EFI_MTFTP4_ACK_HEADER),\r
111 FALSE\r
112 );\r
894d038a 113 ASSERT (Ack != NULL);\r
772db4bb 114\r
115 Ack->Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);\r
116 Ack->Ack.Block[0] = HTONS (BlkNo);\r
117\r
118 return Mtftp4SendPacket (Instance, Packet);\r
119}\r
120\r
121\r
122/**\r
123 Deliver the received data block to the user, which can be saved\r
124 in the user provide buffer or through the CheckPacket callback.\r
125\r
126 @param Instance The Mtftp session\r
127 @param Packet The received data packet\r
128 @param Len The packet length\r
129\r
130 @retval EFI_SUCCESS The data is saved successfully\r
131 @retval EFI_ABORTED The user tells to abort by return an error through\r
132 CheckPacket\r
133 @retval EFI_BUFFER_TOO_SMALL The user's buffer is too small and buffer length is\r
134 updated to the actual buffer size needed.\r
135\r
136**/\r
137EFI_STATUS\r
138Mtftp4RrqSaveBlock (\r
dab714aa 139 IN OUT MTFTP4_PROTOCOL *Instance,\r
140 IN EFI_MTFTP4_PACKET *Packet,\r
141 IN UINT32 Len\r
772db4bb 142 )\r
143{\r
144 EFI_MTFTP4_TOKEN *Token;\r
145 EFI_STATUS Status;\r
146 UINT16 Block;\r
147 UINT64 Start;\r
148 UINT32 DataLen;\r
f1f11ea2 149 UINT64 TotalBlock;\r
150 BOOLEAN Completed;\r
772db4bb 151\r
f1f11ea2 152 Completed = FALSE;\r
153 Token = Instance->Token;\r
154 Block = NTOHS (Packet->Data.Block);\r
155 DataLen = Len - MTFTP4_DATA_HEAD_LEN;\r
772db4bb 156\r
157 //\r
158 // This is the last block, save the block no\r
159 //\r
160 if (DataLen < Instance->BlkSize) {\r
f1f11ea2 161 Completed = TRUE;\r
772db4bb 162 Instance->LastBlock = Block;\r
163 Mtftp4SetLastBlockNum (&Instance->Blocks, Block);\r
164 }\r
165\r
166 //\r
167 // Remove this block number from the file hole. If Mtftp4RemoveBlockNum\r
168 // returns EFI_NOT_FOUND, the block has been saved, don't save it again.\r
f1f11ea2 169 // Note that : For bigger files, allowing the block counter to roll over\r
170 // to accept transfers of unlimited size. So TotalBlock is memorised as \r
171 // continuous block counter.\r
772db4bb 172 //\r
49fd66cb 173 Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block, Completed, &TotalBlock);\r
772db4bb 174\r
175 if (Status == EFI_NOT_FOUND) {\r
176 return EFI_SUCCESS;\r
177 } else if (EFI_ERROR (Status)) {\r
178 return Status;\r
179 }\r
180\r
181 if (Token->CheckPacket != NULL) {\r
182 Status = Token->CheckPacket (&Instance->Mtftp4, Token, (UINT16) Len, Packet);\r
183\r
184 if (EFI_ERROR (Status)) {\r
185 Mtftp4SendError (\r
186 Instance,\r
187 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,\r
67a58d0f 188 (UINT8 *) "User aborted download"\r
772db4bb 189 );\r
190\r
191 return EFI_ABORTED;\r
192 }\r
193 }\r
194\r
195 if (Token->Buffer != NULL) {\r
f1f11ea2 196 Start = MultU64x32 (TotalBlock - 1, Instance->BlkSize);\r
772db4bb 197\r
198 if (Start + DataLen <= Token->BufferSize) {\r
e48e37fc 199 CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);\r
772db4bb 200\r
201 //\r
202 // Update the file size when received the last block\r
203 //\r
f1f11ea2 204 if ((Instance->LastBlock == Block) && Completed) {\r
772db4bb 205 Token->BufferSize = Start + DataLen;\r
206 }\r
207\r
208 } else if (Instance->LastBlock != 0) {\r
209 //\r
210 // Don't save the data if the buffer is too small, return\r
211 // EFI_BUFFER_TOO_SMALL if received the last packet. This\r
212 // will give a accurate file length.\r
213 //\r
214 Token->BufferSize = Start + DataLen;\r
215\r
216 Mtftp4SendError (\r
217 Instance,\r
218 EFI_MTFTP4_ERRORCODE_DISK_FULL,\r
67a58d0f 219 (UINT8 *) "User provided memory block is too small"\r
772db4bb 220 );\r
221\r
222 return EFI_BUFFER_TOO_SMALL;\r
223 }\r
224 }\r
225\r
226 return EFI_SUCCESS;\r
227}\r
228\r
229\r
230/**\r
dab714aa 231 Function to process the received data packets. \r
232 \r
233 It will save the block then send back an ACK if it is active.\r
772db4bb 234\r
235 @param Instance The downloading MTFTP session\r
236 @param Packet The packet received\r
237 @param Len The length of the packet\r
238 @param Multicast Whether this packet is multicast or unicast\r
239 @param Completed Return whether the download has completed\r
240\r
241 @retval EFI_SUCCESS The data packet is successfully processed\r
242 @retval EFI_ABORTED The download is aborted by the user\r
243 @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small\r
244\r
245**/\r
246EFI_STATUS\r
247Mtftp4RrqHandleData (\r
dab714aa 248 IN MTFTP4_PROTOCOL *Instance,\r
249 IN EFI_MTFTP4_PACKET *Packet,\r
250 IN UINT32 Len,\r
251 IN BOOLEAN Multicast,\r
252 OUT BOOLEAN *Completed\r
772db4bb 253 )\r
254{\r
255 EFI_STATUS Status;\r
256 UINT16 BlockNum;\r
257 INTN Expected;\r
258\r
259 *Completed = FALSE;\r
260 BlockNum = NTOHS (Packet->Data.Block);\r
261 Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
262\r
263 ASSERT (Expected >= 0);\r
264\r
265 //\r
266 // If we are active and received an unexpected packet, retransmit\r
267 // the last ACK then restart receiving. If we are passive, save\r
268 // the block.\r
269 //\r
270 if (Instance->Master && (Expected != BlockNum)) {\r
271 Mtftp4Retransmit (Instance);\r
272 return EFI_SUCCESS;\r
273 }\r
274\r
275 Status = Mtftp4RrqSaveBlock (Instance, Packet, Len);\r
276\r
277 if (EFI_ERROR (Status)) {\r
278 return Status;\r
279 }\r
280\r
281 //\r
282 // Reset the passive client's timer whenever it received a\r
283 // valid data packet.\r
284 //\r
285 if (!Instance->Master) {\r
286 Mtftp4SetTimeout (Instance);\r
287 }\r
288\r
289 //\r
290 // Check whether we have received all the blocks. Send the ACK if we\r
291 // are active (unicast client or master client for multicast download).\r
292 // If we have received all the blocks, send an ACK even if we are passive\r
293 // to tell the server that we are done.\r
294 //\r
295 Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
296\r
297 if (Instance->Master || (Expected < 0)) {\r
298 if (Expected < 0) {\r
299 //\r
300 // If we are passive client, then the just received Block maybe\r
301 // isn't the last block. We need to send an ACK to the last block\r
302 // to inform the server that we are done. If we are active client,\r
303 // the Block == Instance->LastBlock.\r
304 //\r
305 BlockNum = Instance->LastBlock;\r
306 *Completed = TRUE;\r
307\r
308 } else {\r
309 BlockNum = (UINT16) (Expected - 1);\r
310 }\r
311\r
312 Mtftp4RrqSendAck (Instance, BlockNum);\r
313 }\r
314\r
315 return EFI_SUCCESS;\r
316}\r
317\r
318\r
319/**\r
320 Validate whether the options received in the server's OACK packet is valid.\r
dab714aa 321 \r
772db4bb 322 The options are valid only if:\r
323 1. The server doesn't include options not requested by us\r
324 2. The server can only use smaller blksize than that is requested\r
325 3. The server can only use the same timeout as requested\r
326 4. The server doesn't change its multicast channel.\r
327\r
328 @param This The downloading Mtftp session\r
329 @param Reply The options in the OACK packet\r
330 @param Request The requested options\r
331\r
dab714aa 332 @retval TRUE The options in the OACK is OK.\r
333 @retval FALSE The options in the OACK is invalid.\r
772db4bb 334\r
335**/\r
336BOOLEAN\r
337Mtftp4RrqOackValid (\r
338 IN MTFTP4_PROTOCOL *This,\r
339 IN MTFTP4_OPTION *Reply,\r
340 IN MTFTP4_OPTION *Request\r
341 )\r
342{\r
343\r
344 //\r
345 // It is invalid for server to return options we don't request\r
346 //\r
347 if ((Reply->Exist &~Request->Exist) != 0) {\r
348 return FALSE;\r
349 }\r
350\r
351 //\r
352 // Server can only specify a smaller block size to be used and\r
353 // return the timeout matches that requested.\r
354 //\r
dab714aa 355 if ((((Reply->Exist & MTFTP4_BLKSIZE_EXIST) != 0)&& (Reply->BlkSize > Request->BlkSize)) ||\r
356 (((Reply->Exist & MTFTP4_TIMEOUT_EXIST) != 0) && (Reply->Timeout != Request->Timeout))) {\r
772db4bb 357 return FALSE;\r
358 }\r
359\r
360 //\r
361 // The server can send ",,master" to client to change its master\r
362 // setting. But if it use the specific multicast channel, it can't\r
363 // change the setting.\r
364 //\r
dab714aa 365 if (((Reply->Exist & MTFTP4_MCAST_EXIST) != 0) && (This->McastIp != 0)) {\r
772db4bb 366 if ((Reply->McastIp != 0) && (Reply->McastIp != This->McastIp)) {\r
367 return FALSE;\r
368 }\r
369\r
370 if ((Reply->McastPort != 0) && (Reply->McastPort != This->McastPort)) {\r
371 return FALSE;\r
372 }\r
373 }\r
374\r
375 return TRUE;\r
376}\r
377\r
378\r
379/**\r
380 Configure a UDP IO port to receive the multicast.\r
381\r
b45b45b2 382 @param McastIo The UDP IO to configure\r
772db4bb 383 @param Context The opaque parameter to the function which is the\r
384 MTFTP session.\r
385\r
dab714aa 386 @retval EFI_SUCCESS The UDP child is successfully configured.\r
772db4bb 387 @retval Others Failed to configure the UDP child.\r
388\r
389**/\r
772db4bb 390EFI_STATUS\r
e798cd87 391EFIAPI\r
772db4bb 392Mtftp4RrqConfigMcastPort (\r
b45b45b2 393 IN UDP_IO *McastIo,\r
772db4bb 394 IN VOID *Context\r
395 )\r
396{\r
397 MTFTP4_PROTOCOL *Instance;\r
398 EFI_MTFTP4_CONFIG_DATA *Config;\r
399 EFI_UDP4_CONFIG_DATA UdpConfig;\r
400 EFI_IPv4_ADDRESS Group;\r
401 EFI_STATUS Status;\r
402 IP4_ADDR Ip;\r
403\r
404 Instance = (MTFTP4_PROTOCOL *) Context;\r
405 Config = &Instance->Config;\r
406\r
407 UdpConfig.AcceptBroadcast = FALSE;\r
408 UdpConfig.AcceptPromiscuous = FALSE;\r
409 UdpConfig.AcceptAnyPort = FALSE;\r
410 UdpConfig.AllowDuplicatePort = FALSE;\r
411 UdpConfig.TypeOfService = 0;\r
412 UdpConfig.TimeToLive = 64;\r
413 UdpConfig.DoNotFragment = FALSE;\r
414 UdpConfig.ReceiveTimeout = 0;\r
415 UdpConfig.TransmitTimeout = 0;\r
416 UdpConfig.UseDefaultAddress = Config->UseDefaultSetting;\r
35f910f0
RP
417 IP4_COPY_ADDRESS (&UdpConfig.StationAddress, &Config->StationIp);\r
418 IP4_COPY_ADDRESS (&UdpConfig.SubnetMask, &Config->SubnetMask);\r
772db4bb 419 UdpConfig.StationPort = Instance->McastPort;\r
420 UdpConfig.RemotePort = 0;\r
421\r
422 Ip = HTONL (Instance->ServerIp);\r
35f910f0 423 IP4_COPY_ADDRESS (&UdpConfig.RemoteAddress, &Ip);\r
772db4bb 424\r
b45b45b2 425 Status = McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, &UdpConfig);\r
772db4bb 426\r
427 if (EFI_ERROR (Status)) {\r
428 return Status;\r
429 }\r
430\r
dab714aa 431 if (!Config->UseDefaultSetting && \r
432 !EFI_IP4_EQUAL (&mZeroIp4Addr, &Config->GatewayIp)) {\r
c4a62a12 433 //\r
434 // The station IP address is manually configured and the Gateway IP is not 0.\r
435 // Add the default route for this UDP instance.\r
436 //\r
b45b45b2 437 Status = McastIo->Protocol.Udp4->Routes (\r
438 McastIo->Protocol.Udp4, \r
439 FALSE,\r
440 &mZeroIp4Addr,\r
441 &mZeroIp4Addr,\r
442 &Config->GatewayIp\r
443 );\r
dab714aa 444 \r
c4a62a12 445 if (EFI_ERROR (Status)) {\r
b45b45b2 446 McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, NULL);\r
c4a62a12 447 return Status;\r
448 }\r
449 }\r
450\r
772db4bb 451 //\r
452 // join the multicast group\r
453 //\r
454 Ip = HTONL (Instance->McastIp);\r
35f910f0 455 IP4_COPY_ADDRESS (&Group, &Ip);\r
772db4bb 456\r
b45b45b2 457 return McastIo->Protocol.Udp4->Groups (McastIo->Protocol.Udp4, TRUE, &Group);\r
772db4bb 458}\r
459\r
460\r
461/**\r
dab714aa 462 Function to process the OACK. \r
463 \r
464 It will first validate the OACK packet, then update the various negotiated parameters.\r
772db4bb 465\r
466 @param Instance The download MTFTP session\r
467 @param Packet The packet received\r
468 @param Len The packet length\r
469 @param Multicast Whether this packet is received as a multicast\r
470 @param Completed Returns whether the download has completed. NOT\r
471 used by this function.\r
472\r
473 @retval EFI_DEVICE_ERROR Failed to create/start a multicast UDP child\r
474 @retval EFI_TFTP_ERROR Some error happened during the process\r
475 @retval EFI_SUCCESS The OACK is successfully processed.\r
476\r
477**/\r
478EFI_STATUS\r
479Mtftp4RrqHandleOack (\r
dab714aa 480 IN OUT MTFTP4_PROTOCOL *Instance,\r
481 IN EFI_MTFTP4_PACKET *Packet,\r
482 IN UINT32 Len,\r
483 IN BOOLEAN Multicast,\r
484 OUT BOOLEAN *Completed\r
772db4bb 485 )\r
486{\r
487 MTFTP4_OPTION Reply;\r
488 EFI_STATUS Status;\r
489 INTN Expected;\r
216f7970 490 EFI_UDP4_PROTOCOL *Udp4;\r
772db4bb 491\r
492 *Completed = FALSE;\r
493\r
494 //\r
495 // If already started the master download, don't change the\r
496 // setting. Master download always succeeds.\r
497 //\r
498 Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
499 ASSERT (Expected != -1);\r
500\r
501 if (Instance->Master && (Expected != 1)) {\r
502 return EFI_SUCCESS;\r
503 }\r
504\r
505 //\r
506 // Parse and validate the options from server\r
507 //\r
e48e37fc 508 ZeroMem (&Reply, sizeof (MTFTP4_OPTION));\r
772db4bb 509\r
510 Status = Mtftp4ParseOptionOack (Packet, Len, &Reply);\r
511\r
512 if (EFI_ERROR (Status) ||\r
513 !Mtftp4RrqOackValid (Instance, &Reply, &Instance->RequestOption)) {\r
514 //\r
515 // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.\r
516 //\r
517 if (Status != EFI_OUT_OF_RESOURCES) {\r
518 Mtftp4SendError (\r
519 Instance,\r
520 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,\r
67a58d0f 521 (UINT8 *) "Mal-formated OACK packet"\r
772db4bb 522 );\r
523 }\r
524\r
525 return EFI_TFTP_ERROR;\r
526 }\r
527\r
dab714aa 528 if ((Reply.Exist & MTFTP4_MCAST_EXIST) != 0) {\r
772db4bb 529\r
530 //\r
531 // Save the multicast info. Always update the Master, only update the\r
532 // multicast IP address, block size, timeoute at the first time. If IP\r
533 // address is updated, create a UDP child to receive the multicast.\r
534 //\r
535 Instance->Master = Reply.Master;\r
536\r
537 if (Instance->McastIp == 0) {\r
538 if ((Reply.McastIp == 0) || (Reply.McastPort == 0)) {\r
539 Mtftp4SendError (\r
540 Instance,\r
541 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,\r
67a58d0f 542 (UINT8 *) "Illegal multicast setting"\r
772db4bb 543 );\r
544\r
545 return EFI_TFTP_ERROR;\r
546 }\r
547\r
548 //\r
549 // Create a UDP child then start receive the multicast from it.\r
550 //\r
551 Instance->McastIp = Reply.McastIp;\r
552 Instance->McastPort = Reply.McastPort;\r
216f7970 553 if (Instance->McastUdpPort == NULL) {\r
554 Instance->McastUdpPort = UdpIoCreateIo (\r
555 Instance->Service->Controller,\r
556 Instance->Service->Image,\r
557 Mtftp4RrqConfigMcastPort,\r
558 UDP_IO_UDP4_VERSION,\r
559 Instance\r
560 );\r
561 if (Instance->McastUdpPort != NULL) {\r
562 Status = gBS->OpenProtocol (\r
563 Instance->McastUdpPort->UdpHandle,\r
564 &gEfiUdp4ProtocolGuid,\r
565 (VOID **) &Udp4,\r
566 Instance->Service->Image,\r
567 Instance->Handle,\r
568 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
569 );\r
570 if (EFI_ERROR (Status)) {\r
571 UdpIoFreeIo (Instance->McastUdpPort);\r
572 Instance->McastUdpPort = NULL;\r
573 return EFI_DEVICE_ERROR;\r
574 }\r
575 }\r
576 }\r
577\r
772db4bb 578\r
579 if (Instance->McastUdpPort == NULL) {\r
580 return EFI_DEVICE_ERROR;\r
581 }\r
582\r
583 Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);\r
584\r
585 if (EFI_ERROR (Status)) {\r
586 Mtftp4SendError (\r
587 Instance,\r
588 EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION,\r
67a58d0f 589 (UINT8 *) "Failed to create socket to receive multicast packet"\r
772db4bb 590 );\r
591\r
592 return Status;\r
593 }\r
c4a62a12 594 \r
772db4bb 595 //\r
596 // Update the parameters used.\r
597 //\r
598 if (Reply.BlkSize != 0) {\r
599 Instance->BlkSize = Reply.BlkSize;\r
600 }\r
c4a62a12 601 \r
772db4bb 602 if (Reply.Timeout != 0) {\r
603 Instance->Timeout = Reply.Timeout;\r
c4a62a12 604 } \r
605 } \r
606 \r
772db4bb 607 } else {\r
608 Instance->Master = TRUE;\r
c4a62a12 609 \r
772db4bb 610 if (Reply.BlkSize != 0) {\r
611 Instance->BlkSize = Reply.BlkSize;\r
612 }\r
613\r
614 if (Reply.Timeout != 0) {\r
615 Instance->Timeout = Reply.Timeout;\r
616 }\r
617 }\r
c4a62a12 618 \r
772db4bb 619 //\r
620 // Send an ACK to (Expected - 1) which is 0 for unicast download,\r
621 // or tell the server we want to receive the Expected block.\r
622 //\r
623 return Mtftp4RrqSendAck (Instance, (UINT16) (Expected - 1));\r
624}\r
625\r
626\r
627/**\r
628 The packet process callback for MTFTP download.\r
629\r
630 @param UdpPacket The packet received\r
b45b45b2 631 @param EndPoint The local/remote access point of the packet\r
772db4bb 632 @param IoStatus The status of the receiving\r
633 @param Context Opaque parameter, which is the MTFTP session\r
634\r
772db4bb 635**/\r
636VOID\r
e798cd87 637EFIAPI\r
772db4bb 638Mtftp4RrqInput (\r
639 IN NET_BUF *UdpPacket,\r
b45b45b2 640 IN UDP_END_POINT *EndPoint,\r
772db4bb 641 IN EFI_STATUS IoStatus,\r
642 IN VOID *Context\r
643 )\r
644{\r
645 MTFTP4_PROTOCOL *Instance;\r
646 EFI_MTFTP4_PACKET *Packet;\r
647 BOOLEAN Completed;\r
648 BOOLEAN Multicast;\r
649 EFI_STATUS Status;\r
650 UINT16 Opcode;\r
651 UINT32 Len;\r
652\r
653 Instance = (MTFTP4_PROTOCOL *) Context;\r
654 NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);\r
655\r
656 Status = EFI_SUCCESS;\r
657 Packet = NULL;\r
658 Completed = FALSE;\r
659 Multicast = FALSE;\r
660\r
661 if (EFI_ERROR (IoStatus)) {\r
662 Status = IoStatus;\r
663 goto ON_EXIT;\r
664 }\r
665\r
666 ASSERT (UdpPacket != NULL);\r
667\r
668 //\r
669 // Find the port this packet is from to restart receive correctly.\r
670 //\r
b45b45b2 671 Multicast = (BOOLEAN) (EndPoint->LocalAddr.Addr[0] == Instance->McastIp);\r
772db4bb 672\r
673 if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {\r
674 goto ON_EXIT;\r
675 }\r
676\r
677 //\r
678 // Client send initial request to server's listening port. Server\r
679 // will select a UDP port to communicate with the client. The server\r
680 // is required to use the same port as RemotePort to multicast the\r
681 // data.\r
682 //\r
b45b45b2 683 if (EndPoint->RemotePort != Instance->ConnectedPort) {\r
772db4bb 684 if (Instance->ConnectedPort != 0) {\r
685 goto ON_EXIT;\r
686 } else {\r
b45b45b2 687 Instance->ConnectedPort = EndPoint->RemotePort;\r
772db4bb 688 }\r
689 }\r
690\r
691 //\r
692 // Copy the MTFTP packet to a continuous buffer if it isn't already so.\r
693 //\r
694 Len = UdpPacket->TotalSize;\r
695\r
696 if (UdpPacket->BlockOpNum > 1) {\r
e48e37fc 697 Packet = AllocatePool (Len);\r
772db4bb 698\r
699 if (Packet == NULL) {\r
700 Status = EFI_OUT_OF_RESOURCES;\r
701 goto ON_EXIT;\r
702 }\r
703\r
704 NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);\r
705\r
706 } else {\r
707 Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);\r
523f48e7 708 ASSERT (Packet != NULL);\r
772db4bb 709 }\r
710\r
711 Opcode = NTOHS (Packet->OpCode);\r
712\r
713 //\r
714 // Call the user's CheckPacket if provided. Abort the transmission\r
715 // if CheckPacket returns an EFI_ERROR code.\r
716 //\r
717 if ((Instance->Token->CheckPacket != NULL) &&\r
718 ((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {\r
719\r
720 Status = Instance->Token->CheckPacket (\r
721 &Instance->Mtftp4,\r
722 Instance->Token,\r
723 (UINT16) Len,\r
724 Packet\r
725 );\r
726\r
727 if (EFI_ERROR (Status)) {\r
728 //\r
729 // Send an error message to the server to inform it\r
730 //\r
731 if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {\r
732 Mtftp4SendError (\r
733 Instance,\r
734 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
67a58d0f 735 (UINT8 *) "User aborted the transfer"\r
772db4bb 736 );\r
737 }\r
738\r
739 Status = EFI_ABORTED;\r
740 goto ON_EXIT;\r
741 }\r
742 }\r
743\r
744 switch (Opcode) {\r
745 case EFI_MTFTP4_OPCODE_DATA:\r
746 if ((Len > (UINT32) (MTFTP4_DATA_HEAD_LEN + Instance->BlkSize)) ||\r
747 (Len < (UINT32) MTFTP4_DATA_HEAD_LEN)) {\r
748 goto ON_EXIT;\r
749 }\r
750\r
751 Status = Mtftp4RrqHandleData (Instance, Packet, Len, Multicast, &Completed);\r
752 break;\r
753\r
754 case EFI_MTFTP4_OPCODE_OACK:\r
755 if (Multicast || (Len <= MTFTP4_OPCODE_LEN)) {\r
756 goto ON_EXIT;\r
757 }\r
758\r
759 Status = Mtftp4RrqHandleOack (Instance, Packet, Len, Multicast, &Completed);\r
760 break;\r
761\r
762 case EFI_MTFTP4_OPCODE_ERROR:\r
763 Status = EFI_TFTP_ERROR;\r
764 break;\r
dab714aa 765 \r
766 default:\r
767 break;\r
772db4bb 768 }\r
769\r
770ON_EXIT:\r
771\r
772 //\r
773 // Free the resources, then if !EFI_ERROR (Status), restart the\r
774 // receive, otherwise end the session.\r
775 //\r
776 if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {\r
766c7483 777 FreePool (Packet);\r
772db4bb 778 }\r
779\r
780 if (UdpPacket != NULL) {\r
781 NetbufFree (UdpPacket);\r
782 }\r
783\r
784 if (!EFI_ERROR (Status) && !Completed) {\r
785 if (Multicast) {\r
786 Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);\r
787 } else {\r
788 Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);\r
789 }\r
790 }\r
791\r
792 if (EFI_ERROR (Status) || Completed) {\r
793 Mtftp4CleanOperation (Instance, Status);\r
794 }\r
795}\r