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