]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Wrq.c
Add 'file not found' debug message to MTFTP.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Wrq.c
CommitLineData
772db4bb 1/** @file\r
dab714aa 2 Routines to process Wrq (upload).\r
3 \r
f1f11ea2 4Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 5This program and the accompanying materials\r
772db4bb 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
772db4bb 13**/\r
14\r
15#include "Mtftp4Impl.h"\r
16\r
772db4bb 17\r
18\r
19/**\r
20 Build then send a MTFTP data packet for the MTFTP upload session.\r
21\r
dab714aa 22 @param Instance The MTFTP upload session.\r
23 @param BlockNum The block number to send.\r
772db4bb 24\r
dab714aa 25 @retval EFI_OUT_OF_RESOURCES Failed to build the packet.\r
772db4bb 26 @retval EFI_ABORTED The consumer of this child directs to abort the\r
dab714aa 27 transmission by return an error through PacketNeeded.\r
772db4bb 28 @retval EFI_SUCCESS The data is sent.\r
29\r
30**/\r
31EFI_STATUS\r
32Mtftp4WrqSendBlock (\r
dab714aa 33 IN OUT MTFTP4_PROTOCOL *Instance,\r
34 IN UINT16 BlockNum\r
772db4bb 35 )\r
36{\r
37 EFI_MTFTP4_PACKET *Packet;\r
38 EFI_MTFTP4_TOKEN *Token;\r
39 NET_BUF *UdpPacket;\r
40 EFI_STATUS Status;\r
41 UINT16 DataLen;\r
42 UINT8 *DataBuf;\r
43 UINT64 Start;\r
44\r
45 //\r
46 // Allocate a buffer to hold the user data\r
47 //\r
48 UdpPacket = NetbufAlloc (Instance->BlkSize + MTFTP4_DATA_HEAD_LEN);\r
49\r
50 if (UdpPacket == NULL) {\r
51 return EFI_OUT_OF_RESOURCES;\r
52 }\r
53\r
dab714aa 54 Packet = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (UdpPacket, MTFTP4_DATA_HEAD_LEN, FALSE);\r
894d038a 55 ASSERT (Packet != NULL);\r
772db4bb 56\r
57 Packet->Data.OpCode = HTONS (EFI_MTFTP4_OPCODE_DATA);\r
58 Packet->Data.Block = HTONS (BlockNum);\r
59\r
60 //\r
61 // Read the block from either the buffer or PacketNeeded callback\r
62 //\r
63 Token = Instance->Token;\r
64 DataLen = Instance->BlkSize;\r
65\r
66 if (Token->Buffer != NULL) {\r
67 Start = MultU64x32 (BlockNum - 1, Instance->BlkSize);\r
68\r
69 if (Token->BufferSize < Start + Instance->BlkSize) {\r
70 DataLen = (UINT16) (Token->BufferSize - Start);\r
71 Instance->LastBlock = BlockNum;\r
72 Mtftp4SetLastBlockNum (&Instance->Blocks, BlockNum);\r
73 }\r
74\r
75 if (DataLen > 0) {\r
76 NetbufAllocSpace (UdpPacket, DataLen, FALSE);\r
e48e37fc 77 CopyMem (Packet->Data.Data, (UINT8 *) Token->Buffer + Start, DataLen);\r
772db4bb 78 }\r
79\r
80 } else {\r
81 //\r
82 // Get data from PacketNeeded\r
83 //\r
84 DataBuf = NULL;\r
dab714aa 85 Status = Token->PacketNeeded (\r
86 &Instance->Mtftp4,\r
87 Token,\r
88 &DataLen,\r
89 (VOID **) &DataBuf\r
90 );\r
772db4bb 91\r
92 if (EFI_ERROR (Status) || (DataLen > Instance->BlkSize)) {\r
93 if (DataBuf != NULL) {\r
766c7483 94 FreePool (DataBuf);\r
772db4bb 95 }\r
96\r
97 Mtftp4SendError (\r
98 Instance,\r
99 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
67a58d0f 100 (UINT8 *) "User aborted the transfer"\r
772db4bb 101 );\r
102\r
103 return EFI_ABORTED;\r
104 }\r
105\r
106 if (DataLen < Instance->BlkSize) {\r
107 Instance->LastBlock = BlockNum;\r
108 Mtftp4SetLastBlockNum (&Instance->Blocks, BlockNum);\r
109 }\r
110\r
111 if (DataLen > 0) {\r
112 NetbufAllocSpace (UdpPacket, DataLen, FALSE);\r
e48e37fc 113 CopyMem (Packet->Data.Data, DataBuf, DataLen);\r
766c7483 114 FreePool (DataBuf);\r
772db4bb 115 }\r
116 }\r
117\r
118 return Mtftp4SendPacket (Instance, UdpPacket);\r
119}\r
120\r
121\r
122/**\r
dab714aa 123 Function to handle received ACK packet. \r
124 \r
125 If the ACK number matches the expected block number, and there are more \r
126 data pending, send the next block. Otherwise tell the caller that we are done.\r
772db4bb 127\r
128 @param Instance The MTFTP upload session\r
129 @param Packet The MTFTP packet received\r
130 @param Len The packet length\r
131 @param Completed Return whether the upload has finished.\r
132\r
133 @retval EFI_SUCCESS The ACK is successfully processed.\r
134 @retval EFI_TFTP_ERROR The block number loops back.\r
135 @retval Others Failed to transmit the next data packet.\r
136\r
137**/\r
138EFI_STATUS\r
139Mtftp4WrqHandleAck (\r
dab714aa 140 IN MTFTP4_PROTOCOL *Instance,\r
141 IN EFI_MTFTP4_PACKET *Packet,\r
142 IN UINT32 Len,\r
143 OUT BOOLEAN *Completed\r
772db4bb 144 )\r
145{\r
146 UINT16 AckNum;\r
147 INTN Expected;\r
f1f11ea2 148 UINT64 TotalBlock;\r
149 \r
772db4bb 150 *Completed = FALSE;\r
151 AckNum = NTOHS (Packet->Ack.Block[0]);\r
152 Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
153\r
154 ASSERT (Expected >= 0);\r
155\r
156 //\r
157 // Get an unwanted ACK, return EFI_SUCCESS to let Mtftp4WrqInput\r
158 // restart receive.\r
159 //\r
160 if (Expected != AckNum) {\r
161 return EFI_SUCCESS;\r
162 }\r
163\r
164 //\r
165 // Remove the acked block number, if this is the last block number,\r
166 // tell the Mtftp4WrqInput to finish the transfer. This is the last\r
167 // block number if the block range are empty..\r
168 //\r
49fd66cb 169 Mtftp4RemoveBlockNum (&Instance->Blocks, AckNum, *Completed,&TotalBlock);\r
772db4bb 170\r
171 Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
172\r
173 if (Expected < 0) {\r
dab714aa 174 \r
772db4bb 175 //\r
176 // The block range is empty. It may either because the the last\r
177 // block has been ACKed, or the sequence number just looped back,\r
178 // that is, there is more than 0xffff blocks.\r
179 //\r
180 if (Instance->LastBlock == AckNum) {\r
181 ASSERT (Instance->LastBlock >= 1);\r
182 *Completed = TRUE;\r
183 return EFI_SUCCESS;\r
184\r
185 } else {\r
186 Mtftp4SendError (\r
187 Instance,\r
188 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
67a58d0f 189 (UINT8 *) "Block number rolls back, not supported, try blksize option"\r
772db4bb 190 );\r
191\r
192 return EFI_TFTP_ERROR;\r
193 }\r
194 }\r
195\r
196 return Mtftp4WrqSendBlock (Instance, (UINT16) Expected);\r
197}\r
198\r
199\r
200/**\r
dab714aa 201 Check whether the received OACK is valid. \r
202 \r
203 The OACK is valid only if:\r
772db4bb 204 1. It only include options requested by us\r
205 2. It can only include a smaller block size\r
206 3. It can't change the proposed time out value.\r
dab714aa 207 4. Other requirements of the individal MTFTP options as required.\r
772db4bb 208\r
209 @param Reply The options included in the OACK\r
210 @param Request The options we requested\r
211\r
dab714aa 212 @retval TRUE The options included in OACK is valid.\r
213 @retval FALSE The options included in OACK is invalid.\r
772db4bb 214\r
215**/\r
216BOOLEAN\r
217Mtftp4WrqOackValid (\r
218 IN MTFTP4_OPTION *Reply,\r
219 IN MTFTP4_OPTION *Request\r
220 )\r
221{\r
222 //\r
223 // It is invalid for server to return options we don't request\r
224 //\r
dab714aa 225 if ((Reply->Exist & ~Request->Exist) != 0) {\r
772db4bb 226 return FALSE;\r
227 }\r
228\r
229 //\r
230 // Server can only specify a smaller block size to be used and\r
231 // return the timeout matches that requested.\r
232 //\r
dab714aa 233 if ((((Reply->Exist & MTFTP4_BLKSIZE_EXIST) != 0) && (Reply->BlkSize > Request->BlkSize)) ||\r
234 (((Reply->Exist & MTFTP4_TIMEOUT_EXIST) != 0) && (Reply->Timeout != Request->Timeout))) {\r
772db4bb 235 return FALSE;\r
236 }\r
237\r
238 return TRUE;\r
239}\r
240\r
241\r
242/**\r
dab714aa 243 Function to handle the MTFTP OACK packet. \r
244 \r
245 It parses the packet's options, and update the internal states of the session.\r
772db4bb 246\r
247 @param Instance The MTFTP session\r
248 @param Packet The received OACK packet\r
249 @param Len The length of the packet\r
250 @param Completed Whether the transmisson has completed. NOT used by\r
251 this function.\r
252\r
253 @retval EFI_SUCCESS The OACK process is OK\r
254 @retval EFI_TFTP_ERROR Some error occured, and the session reset.\r
255\r
256**/\r
257EFI_STATUS\r
258Mtftp4WrqHandleOack (\r
dab714aa 259 IN OUT MTFTP4_PROTOCOL *Instance,\r
260 IN EFI_MTFTP4_PACKET *Packet,\r
261 IN UINT32 Len,\r
262 OUT BOOLEAN *Completed\r
772db4bb 263 )\r
264{\r
265 MTFTP4_OPTION Reply;\r
266 EFI_MTFTP4_PACKET Bogus;\r
267 EFI_STATUS Status;\r
268 INTN Expected;\r
269\r
270 *Completed = FALSE;\r
271\r
272 //\r
273 // Ignore the OACK if already started the upload\r
274 //\r
275 Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
276\r
277 if (Expected != 0) {\r
278 return EFI_SUCCESS;\r
279 }\r
280\r
281 //\r
282 // Parse and validate the options from server\r
283 //\r
e48e37fc 284 ZeroMem (&Reply, sizeof (MTFTP4_OPTION));\r
772db4bb 285 Status = Mtftp4ParseOptionOack (Packet, Len, &Reply);\r
286\r
287 if (EFI_ERROR (Status) || !Mtftp4WrqOackValid (&Reply, &Instance->RequestOption)) {\r
288 //\r
289 // Don't send a MTFTP error packet when out of resource, it can\r
290 // only make it worse.\r
291 //\r
292 if (Status != EFI_OUT_OF_RESOURCES) {\r
293 Mtftp4SendError (\r
294 Instance,\r
295 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,\r
67a58d0f 296 (UINT8 *) "Mal-formated OACK packet"\r
772db4bb 297 );\r
298 }\r
299\r
300 return EFI_TFTP_ERROR;\r
301 }\r
302\r
303 if (Reply.BlkSize != 0) {\r
304 Instance->BlkSize = Reply.BlkSize;\r
305 }\r
306\r
307 if (Reply.Timeout != 0) {\r
308 Instance->Timeout = Reply.Timeout;\r
309 }\r
310\r
311 //\r
312 // Build a bogus ACK0 packet then pass it to the Mtftp4WrqHandleAck,\r
313 // which will start the transmission of the first data block.\r
314 //\r
315 Bogus.Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);\r
316 Bogus.Ack.Block[0] = 0;\r
317\r
dab714aa 318 Status = Mtftp4WrqHandleAck (\r
319 Instance,\r
320 &Bogus,\r
321 sizeof (EFI_MTFTP4_ACK_HEADER),\r
322 Completed\r
323 );\r
324\r
325 return Status;\r
772db4bb 326}\r
327\r
328\r
329/**\r
330 The input process routine for MTFTP upload.\r
331\r
332 @param UdpPacket The received MTFTP packet.\r
b45b45b2 333 @param EndPoint The local/remote access point\r
772db4bb 334 @param IoStatus The result of the packet receiving\r
335 @param Context Opaque parameter for the callback, which is the\r
336 MTFTP session.\r
772db4bb 337**/\r
338VOID\r
e798cd87 339EFIAPI\r
772db4bb 340Mtftp4WrqInput (\r
341 IN NET_BUF *UdpPacket,\r
b45b45b2 342 IN UDP_END_POINT *EndPoint,\r
772db4bb 343 IN EFI_STATUS IoStatus,\r
344 IN VOID *Context\r
345 )\r
346{\r
347 MTFTP4_PROTOCOL *Instance;\r
348 EFI_MTFTP4_PACKET *Packet;\r
349 BOOLEAN Completed;\r
350 EFI_STATUS Status;\r
351 UINT32 Len;\r
352 UINT16 Opcode;\r
353\r
354 Instance = (MTFTP4_PROTOCOL *) Context;\r
355 NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);\r
356\r
357 Completed = FALSE;\r
358 Packet = NULL;\r
359 Status = EFI_SUCCESS;\r
360\r
361 if (EFI_ERROR (IoStatus)) {\r
362 Status = IoStatus;\r
363 goto ON_EXIT;\r
364 }\r
365\r
366 ASSERT (UdpPacket != NULL);\r
367\r
368 if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {\r
369 goto ON_EXIT;\r
370 }\r
371\r
372 //\r
373 // Client send initial request to server's listening port. Server\r
374 // will select a UDP port to communicate with the client.\r
375 //\r
b45b45b2 376 if (EndPoint->RemotePort != Instance->ConnectedPort) {\r
772db4bb 377 if (Instance->ConnectedPort != 0) {\r
378 goto ON_EXIT;\r
379 } else {\r
b45b45b2 380 Instance->ConnectedPort = EndPoint->RemotePort;\r
772db4bb 381 }\r
382 }\r
383\r
384 //\r
385 // Copy the MTFTP packet to a continuous buffer if it isn't already so.\r
386 //\r
387 Len = UdpPacket->TotalSize;\r
388\r
389 if (UdpPacket->BlockOpNum > 1) {\r
e48e37fc 390 Packet = AllocatePool (Len);\r
772db4bb 391\r
392 if (Packet == NULL) {\r
393 Status = EFI_OUT_OF_RESOURCES;\r
394 goto ON_EXIT;\r
395 }\r
396\r
397 NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);\r
398\r
399 } else {\r
400 Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);\r
401 }\r
402\r
403 Opcode = NTOHS (Packet->OpCode);\r
404\r
405 //\r
406 // Call the user's CheckPacket if provided. Abort the transmission\r
407 // if CheckPacket returns an EFI_ERROR code.\r
408 //\r
409 if ((Instance->Token->CheckPacket != NULL) &&\r
410 ((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {\r
411\r
412 Status = Instance->Token->CheckPacket (\r
413 &Instance->Mtftp4,\r
414 Instance->Token,\r
415 (UINT16) Len,\r
416 Packet\r
417 );\r
418\r
419 if (EFI_ERROR (Status)) {\r
420 //\r
421 // Send an error message to the server to inform it\r
422 //\r
423 if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {\r
424 Mtftp4SendError (\r
425 Instance,\r
426 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
67a58d0f 427 (UINT8 *) "User aborted the transfer"\r
772db4bb 428 );\r
429 }\r
430\r
431 Status = EFI_ABORTED;\r
432 goto ON_EXIT;\r
433 }\r
434 }\r
435\r
436 switch (Opcode) {\r
437 case EFI_MTFTP4_OPCODE_ACK:\r
438 if (Len != MTFTP4_OPCODE_LEN + MTFTP4_BLKNO_LEN) {\r
439 goto ON_EXIT;\r
440 }\r
441\r
442 Status = Mtftp4WrqHandleAck (Instance, Packet, Len, &Completed);\r
443 break;\r
444\r
445 case EFI_MTFTP4_OPCODE_OACK:\r
446 if (Len <= MTFTP4_OPCODE_LEN) {\r
447 goto ON_EXIT;\r
448 }\r
449\r
450 Status = Mtftp4WrqHandleOack (Instance, Packet, Len, &Completed);\r
451 break;\r
452\r
453 case EFI_MTFTP4_OPCODE_ERROR:\r
454 Status = EFI_TFTP_ERROR;\r
455 break;\r
dab714aa 456 \r
457 default:\r
458 break;\r
772db4bb 459 }\r
460\r
461ON_EXIT:\r
462 //\r
463 // Free the resources, then if !EFI_ERROR (Status) and not completed,\r
464 // restart the receive, otherwise end the session.\r
465 //\r
466 if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {\r
766c7483 467 FreePool (Packet);\r
772db4bb 468 }\r
469\r
470 if (UdpPacket != NULL) {\r
471 NetbufFree (UdpPacket);\r
472 }\r
473\r
474 if (!EFI_ERROR (Status) && !Completed) {\r
475 Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);\r
476 }\r
477\r
478 //\r
479 // Status may have been updated by UdpIoRecvDatagram\r
480 //\r
481 if (EFI_ERROR (Status) || Completed) {\r
482 Mtftp4CleanOperation (Instance, Status);\r
483 }\r
484}\r
dab714aa 485\r
486\r
487\r
488/**\r
489 Start the MTFTP session for upload.\r
490 \r
491 It will first init some states, then send the WRQ request packet, \r
492 and start receiving the packet.\r
493\r
494 @param Instance The MTFTP session\r
495 @param Operation Redundant parameter, which is always\r
496 EFI_MTFTP4_OPCODE_WRQ here.\r
497\r
498 @retval EFI_SUCCESS The upload process has been started.\r
499 @retval Others Failed to start the upload.\r
500\r
501**/\r
502EFI_STATUS\r
503Mtftp4WrqStart (\r
504 IN MTFTP4_PROTOCOL *Instance,\r
505 IN UINT16 Operation\r
506 )\r
507{\r
508 EFI_STATUS Status;\r
509\r
510 //\r
511 // The valid block number range are [0, 0xffff]. For example:\r
512 // the client sends an WRQ request to the server, the server\r
513 // ACK with an ACK0 to let client start transfer the first\r
514 // packet.\r
515 //\r
516 Status = Mtftp4InitBlockRange (&Instance->Blocks, 0, 0xffff);\r
517\r
518 if (EFI_ERROR (Status)) {\r
519 return Status;\r
520 }\r
521\r
522 Status = Mtftp4SendRequest (Instance);\r
523\r
524 if (EFI_ERROR (Status)) {\r
525 return Status;\r
526 }\r
527\r
528 return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);\r
529}\r
530\r