]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c
MdeModulePke/Mtftp4Dxe: Support windowsize in read request operation.
[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
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
d1102dba
LG
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
dab714aa 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
6c047cfa
JW
102 EFI_STATUS Status;\r
103\r
104 Status = EFI_SUCCESS;\r
772db4bb 105\r
106 Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER));\r
772db4bb 107 if (Packet == NULL) {\r
108 return EFI_OUT_OF_RESOURCES;\r
109 }\r
110\r
111 Ack = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (\r
112 Packet,\r
113 sizeof (EFI_MTFTP4_ACK_HEADER),\r
114 FALSE\r
115 );\r
894d038a 116 ASSERT (Ack != NULL);\r
772db4bb 117\r
118 Ack->Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);\r
119 Ack->Ack.Block[0] = HTONS (BlkNo);\r
120\r
6c047cfa
JW
121 Status = Mtftp4SendPacket (Instance, Packet);\r
122 if (!EFI_ERROR (Status)) {\r
123 Instance->AckedBlock = Instance->TotalBlock;\r
124 }\r
125\r
126 return Status;\r
772db4bb 127}\r
128\r
129\r
130/**\r
131 Deliver the received data block to the user, which can be saved\r
132 in the user provide buffer or through the CheckPacket callback.\r
133\r
134 @param Instance The Mtftp session\r
135 @param Packet The received data packet\r
136 @param Len The packet length\r
137\r
138 @retval EFI_SUCCESS The data is saved successfully\r
139 @retval EFI_ABORTED The user tells to abort by return an error through\r
140 CheckPacket\r
141 @retval EFI_BUFFER_TOO_SMALL The user's buffer is too small and buffer length is\r
142 updated to the actual buffer size needed.\r
143\r
144**/\r
145EFI_STATUS\r
146Mtftp4RrqSaveBlock (\r
dab714aa 147 IN OUT MTFTP4_PROTOCOL *Instance,\r
148 IN EFI_MTFTP4_PACKET *Packet,\r
149 IN UINT32 Len\r
772db4bb 150 )\r
151{\r
152 EFI_MTFTP4_TOKEN *Token;\r
153 EFI_STATUS Status;\r
154 UINT16 Block;\r
155 UINT64 Start;\r
156 UINT32 DataLen;\r
f1f11ea2 157 BOOLEAN Completed;\r
772db4bb 158\r
f1f11ea2 159 Completed = FALSE;\r
160 Token = Instance->Token;\r
161 Block = NTOHS (Packet->Data.Block);\r
162 DataLen = Len - MTFTP4_DATA_HEAD_LEN;\r
772db4bb 163\r
164 //\r
165 // This is the last block, save the block no\r
166 //\r
167 if (DataLen < Instance->BlkSize) {\r
6c047cfa 168 Completed = TRUE;\r
772db4bb 169 Instance->LastBlock = Block;\r
170 Mtftp4SetLastBlockNum (&Instance->Blocks, Block);\r
171 }\r
172\r
173 //\r
174 // Remove this block number from the file hole. If Mtftp4RemoveBlockNum\r
175 // returns EFI_NOT_FOUND, the block has been saved, don't save it again.\r
f1f11ea2 176 // Note that : For bigger files, allowing the block counter to roll over\r
d1102dba 177 // to accept transfers of unlimited size. So TotalBlock is memorised as\r
f1f11ea2 178 // continuous block counter.\r
772db4bb 179 //\r
6c047cfa 180 Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block, Completed, &Instance->TotalBlock);\r
772db4bb 181\r
182 if (Status == EFI_NOT_FOUND) {\r
183 return EFI_SUCCESS;\r
184 } else if (EFI_ERROR (Status)) {\r
185 return Status;\r
186 }\r
187\r
188 if (Token->CheckPacket != NULL) {\r
189 Status = Token->CheckPacket (&Instance->Mtftp4, Token, (UINT16) Len, Packet);\r
190\r
191 if (EFI_ERROR (Status)) {\r
192 Mtftp4SendError (\r
193 Instance,\r
194 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,\r
67a58d0f 195 (UINT8 *) "User aborted download"\r
772db4bb 196 );\r
197\r
198 return EFI_ABORTED;\r
199 }\r
200 }\r
201\r
202 if (Token->Buffer != NULL) {\r
6c047cfa 203 Start = MultU64x32 (Instance->TotalBlock - 1, Instance->BlkSize);\r
772db4bb 204\r
205 if (Start + DataLen <= Token->BufferSize) {\r
e48e37fc 206 CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);\r
772db4bb 207\r
208 //\r
209 // Update the file size when received the last block\r
210 //\r
f1f11ea2 211 if ((Instance->LastBlock == Block) && Completed) {\r
772db4bb 212 Token->BufferSize = Start + DataLen;\r
213 }\r
214\r
215 } else if (Instance->LastBlock != 0) {\r
216 //\r
217 // Don't save the data if the buffer is too small, return\r
218 // EFI_BUFFER_TOO_SMALL if received the last packet. This\r
219 // will give a accurate file length.\r
220 //\r
221 Token->BufferSize = Start + DataLen;\r
222\r
223 Mtftp4SendError (\r
224 Instance,\r
225 EFI_MTFTP4_ERRORCODE_DISK_FULL,\r
67a58d0f 226 (UINT8 *) "User provided memory block is too small"\r
772db4bb 227 );\r
228\r
229 return EFI_BUFFER_TOO_SMALL;\r
230 }\r
231 }\r
232\r
233 return EFI_SUCCESS;\r
234}\r
235\r
236\r
237/**\r
d1102dba
LG
238 Function to process the received data packets.\r
239\r
dab714aa 240 It will save the block then send back an ACK if it is active.\r
772db4bb 241\r
242 @param Instance The downloading MTFTP session\r
243 @param Packet The packet received\r
244 @param Len The length of the packet\r
245 @param Multicast Whether this packet is multicast or unicast\r
246 @param Completed Return whether the download has completed\r
247\r
248 @retval EFI_SUCCESS The data packet is successfully processed\r
249 @retval EFI_ABORTED The download is aborted by the user\r
250 @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small\r
251\r
252**/\r
253EFI_STATUS\r
254Mtftp4RrqHandleData (\r
dab714aa 255 IN MTFTP4_PROTOCOL *Instance,\r
256 IN EFI_MTFTP4_PACKET *Packet,\r
257 IN UINT32 Len,\r
258 IN BOOLEAN Multicast,\r
259 OUT BOOLEAN *Completed\r
772db4bb 260 )\r
261{\r
262 EFI_STATUS Status;\r
263 UINT16 BlockNum;\r
264 INTN Expected;\r
265\r
266 *Completed = FALSE;\r
6c047cfa 267 Status = EFI_SUCCESS;\r
772db4bb 268 BlockNum = NTOHS (Packet->Data.Block);\r
269 Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
270\r
271 ASSERT (Expected >= 0);\r
272\r
273 //\r
6c047cfa
JW
274 // If we are active and received an unexpected packet, transmit\r
275 // the ACK for the block we received, then restart receiving the\r
276 // expected one. If we are passive, save the block.\r
772db4bb 277 //\r
278 if (Instance->Master && (Expected != BlockNum)) {\r
6c047cfa
JW
279 //\r
280 // If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack number (65535).\r
281 //\r
282 return Mtftp4RrqSendAck (Instance, (UINT16) (Expected - 1));\r
772db4bb 283 }\r
284\r
285 Status = Mtftp4RrqSaveBlock (Instance, Packet, Len);\r
286\r
287 if (EFI_ERROR (Status)) {\r
288 return Status;\r
289 }\r
290\r
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