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