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