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