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