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