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