]> git.proxmox.com Git - mirror_edk2.git/blame - 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
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
e798cd87 29EFIAPI\r
772db4bb 30Mtftp4RrqInput (\r
31 IN NET_BUF *UdpPacket,\r
b45b45b2 32 IN UDP_END_POINT *EndPoint,\r
772db4bb 33 IN EFI_STATUS IoStatus,\r
34 IN VOID *Context\r
35 );\r
36\r
37\r
38/**\r
dab714aa 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
772db4bb 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
772db4bb 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
894d038a 112 ASSERT (Ack != NULL);\r
772db4bb 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
dab714aa 138 IN OUT MTFTP4_PROTOCOL *Instance,\r
139 IN EFI_MTFTP4_PACKET *Packet,\r
140 IN UINT32 Len\r
772db4bb 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
67a58d0f 180 (UINT8 *) "User aborted download"\r
772db4bb 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
e48e37fc 191 CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);\r
772db4bb 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
67a58d0f 211 (UINT8 *) "User provided memory block is too small"\r
772db4bb 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
dab714aa 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
772db4bb 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
dab714aa 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
772db4bb 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
dab714aa 313 \r
772db4bb 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
dab714aa 324 @retval TRUE The options in the OACK is OK.\r
325 @retval FALSE The options in the OACK is invalid.\r
772db4bb 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
dab714aa 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
772db4bb 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
dab714aa 357 if (((Reply->Exist & MTFTP4_MCAST_EXIST) != 0) && (This->McastIp != 0)) {\r
772db4bb 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
b45b45b2 374 @param McastIo The UDP IO to configure\r
772db4bb 375 @param Context The opaque parameter to the function which is the\r
376 MTFTP session.\r
377\r
dab714aa 378 @retval EFI_SUCCESS The UDP child is successfully configured.\r
772db4bb 379 @retval Others Failed to configure the UDP child.\r
380\r
381**/\r
772db4bb 382EFI_STATUS\r
e798cd87 383EFIAPI\r
772db4bb 384Mtftp4RrqConfigMcastPort (\r
b45b45b2 385 IN UDP_IO *McastIo,\r
772db4bb 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
e48e37fc 415 CopyMem (&UdpConfig.RemoteAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
772db4bb 416\r
b45b45b2 417 Status = McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, &UdpConfig);\r
772db4bb 418\r
419 if (EFI_ERROR (Status)) {\r
420 return Status;\r
421 }\r
422\r
dab714aa 423 if (!Config->UseDefaultSetting && \r
424 !EFI_IP4_EQUAL (&mZeroIp4Addr, &Config->GatewayIp)) {\r
c4a62a12 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
b45b45b2 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
dab714aa 436 \r
c4a62a12 437 if (EFI_ERROR (Status)) {\r
b45b45b2 438 McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, NULL);\r
c4a62a12 439 return Status;\r
440 }\r
441 }\r
442\r
772db4bb 443 //\r
444 // join the multicast group\r
445 //\r
446 Ip = HTONL (Instance->McastIp);\r
e48e37fc 447 CopyMem (&Group, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
772db4bb 448\r
b45b45b2 449 return McastIo->Protocol.Udp4->Groups (McastIo->Protocol.Udp4, TRUE, &Group);\r
772db4bb 450}\r
451\r
452\r
453/**\r
dab714aa 454 Function to process the OACK. \r
455 \r
456 It will first validate the OACK packet, then update the various negotiated parameters.\r
772db4bb 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
dab714aa 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
772db4bb 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
e48e37fc 499 ZeroMem (&Reply, sizeof (MTFTP4_OPTION));\r
772db4bb 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
67a58d0f 512 (UINT8 *) "Mal-formated OACK packet"\r
772db4bb 513 );\r
514 }\r
515\r
516 return EFI_TFTP_ERROR;\r
517 }\r
518\r
dab714aa 519 if ((Reply.Exist & MTFTP4_MCAST_EXIST) != 0) {\r
772db4bb 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
67a58d0f 533 (UINT8 *) "Illegal multicast setting"\r
772db4bb 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
b45b45b2 544 Instance->McastUdpPort = UdpIoCreateIo (\r
772db4bb 545 Instance->Service->Controller,\r
546 Instance->Service->Image,\r
547 Mtftp4RrqConfigMcastPort,\r
b45b45b2 548 UDP_IO_UDP4_VERSION,\r
772db4bb 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
67a58d0f 562 (UINT8 *) "Failed to create socket to receive multicast packet"\r
772db4bb 563 );\r
564\r
565 return Status;\r
566 }\r
c4a62a12 567 \r
772db4bb 568 //\r
569 // Update the parameters used.\r
570 //\r
571 if (Reply.BlkSize != 0) {\r
572 Instance->BlkSize = Reply.BlkSize;\r
573 }\r
c4a62a12 574 \r
772db4bb 575 if (Reply.Timeout != 0) {\r
576 Instance->Timeout = Reply.Timeout;\r
c4a62a12 577 } \r
578 } \r
579 \r
772db4bb 580 } else {\r
581 Instance->Master = TRUE;\r
c4a62a12 582 \r
772db4bb 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
c4a62a12 591 \r
772db4bb 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
b45b45b2 604 @param EndPoint The local/remote access point of the packet\r
772db4bb 605 @param IoStatus The status of the receiving\r
606 @param Context Opaque parameter, which is the MTFTP session\r
607\r
772db4bb 608**/\r
609VOID\r
e798cd87 610EFIAPI\r
772db4bb 611Mtftp4RrqInput (\r
612 IN NET_BUF *UdpPacket,\r
b45b45b2 613 IN UDP_END_POINT *EndPoint,\r
772db4bb 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
b45b45b2 644 Multicast = (BOOLEAN) (EndPoint->LocalAddr.Addr[0] == Instance->McastIp);\r
772db4bb 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
b45b45b2 656 if (EndPoint->RemotePort != Instance->ConnectedPort) {\r
772db4bb 657 if (Instance->ConnectedPort != 0) {\r
658 goto ON_EXIT;\r
659 } else {\r
b45b45b2 660 Instance->ConnectedPort = EndPoint->RemotePort;\r
772db4bb 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
e48e37fc 670 Packet = AllocatePool (Len);\r
772db4bb 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
67a58d0f 707 (UINT8 *) "User aborted the transfer"\r
772db4bb 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
dab714aa 737 \r
738 default:\r
739 break;\r
772db4bb 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
766c7483 749 FreePool (Packet);\r
772db4bb 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