]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - NetworkPkg/Mtftp4Dxe/Mtftp4Wrq.c
DynamicTablesPkg: GTDT updates for ACPI 6.3
[mirror_edk2.git] / NetworkPkg / Mtftp4Dxe / Mtftp4Wrq.c
... / ...
CommitLineData
1/** @file\r
2 Routines to process Wrq (upload).\r
3\r
4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
5SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "Mtftp4Impl.h"\r
10\r
11\r
12\r
13/**\r
14 Build then send a MTFTP data packet for the MTFTP upload session.\r
15\r
16 @param Instance The MTFTP upload session.\r
17 @param BlockNum The block number to send.\r
18\r
19 @retval EFI_OUT_OF_RESOURCES Failed to build the packet.\r
20 @retval EFI_ABORTED The consumer of this child directs to abort the\r
21 transmission by return an error through PacketNeeded.\r
22 @retval EFI_SUCCESS The data is sent.\r
23\r
24**/\r
25EFI_STATUS\r
26Mtftp4WrqSendBlock (\r
27 IN OUT MTFTP4_PROTOCOL *Instance,\r
28 IN UINT16 BlockNum\r
29 )\r
30{\r
31 EFI_MTFTP4_PACKET *Packet;\r
32 EFI_MTFTP4_TOKEN *Token;\r
33 NET_BUF *UdpPacket;\r
34 EFI_STATUS Status;\r
35 UINT16 DataLen;\r
36 UINT8 *DataBuf;\r
37 UINT64 Start;\r
38\r
39 //\r
40 // Allocate a buffer to hold the user data\r
41 //\r
42 UdpPacket = NetbufAlloc (Instance->BlkSize + MTFTP4_DATA_HEAD_LEN);\r
43\r
44 if (UdpPacket == NULL) {\r
45 return EFI_OUT_OF_RESOURCES;\r
46 }\r
47\r
48 Packet = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (UdpPacket, MTFTP4_DATA_HEAD_LEN, FALSE);\r
49 ASSERT (Packet != NULL);\r
50\r
51 Packet->Data.OpCode = HTONS (EFI_MTFTP4_OPCODE_DATA);\r
52 Packet->Data.Block = HTONS (BlockNum);\r
53\r
54 //\r
55 // Read the block from either the buffer or PacketNeeded callback\r
56 //\r
57 Token = Instance->Token;\r
58 DataLen = Instance->BlkSize;\r
59\r
60 if (Token->Buffer != NULL) {\r
61 Start = MultU64x32 (BlockNum - 1, Instance->BlkSize);\r
62\r
63 if (Token->BufferSize < Start + Instance->BlkSize) {\r
64 DataLen = (UINT16) (Token->BufferSize - Start);\r
65 Instance->LastBlock = BlockNum;\r
66 Mtftp4SetLastBlockNum (&Instance->Blocks, BlockNum);\r
67 }\r
68\r
69 if (DataLen > 0) {\r
70 NetbufAllocSpace (UdpPacket, DataLen, FALSE);\r
71 CopyMem (Packet->Data.Data, (UINT8 *) Token->Buffer + Start, DataLen);\r
72 }\r
73\r
74 } else {\r
75 //\r
76 // Get data from PacketNeeded\r
77 //\r
78 DataBuf = NULL;\r
79 Status = Token->PacketNeeded (\r
80 &Instance->Mtftp4,\r
81 Token,\r
82 &DataLen,\r
83 (VOID **) &DataBuf\r
84 );\r
85\r
86 if (EFI_ERROR (Status) || (DataLen > Instance->BlkSize)) {\r
87 if (DataBuf != NULL) {\r
88 FreePool (DataBuf);\r
89 }\r
90\r
91 if (UdpPacket != NULL) {\r
92 NetbufFree (UdpPacket);\r
93 }\r
94\r
95 Mtftp4SendError (\r
96 Instance,\r
97 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
98 (UINT8 *) "User aborted the transfer"\r
99 );\r
100\r
101 return EFI_ABORTED;\r
102 }\r
103\r
104 if (DataLen < Instance->BlkSize) {\r
105 Instance->LastBlock = BlockNum;\r
106 Mtftp4SetLastBlockNum (&Instance->Blocks, BlockNum);\r
107 }\r
108\r
109 if (DataLen > 0) {\r
110 NetbufAllocSpace (UdpPacket, DataLen, FALSE);\r
111 CopyMem (Packet->Data.Data, DataBuf, DataLen);\r
112 FreePool (DataBuf);\r
113 }\r
114 }\r
115\r
116 return Mtftp4SendPacket (Instance, UdpPacket);\r
117}\r
118\r
119\r
120/**\r
121 Function to handle received ACK packet.\r
122\r
123 If the ACK number matches the expected block number, and there are more\r
124 data pending, send the next block. Otherwise tell the caller that we are done.\r
125\r
126 @param Instance The MTFTP upload session\r
127 @param Packet The MTFTP packet received\r
128 @param Len The packet length\r
129 @param Completed Return whether the upload has finished.\r
130\r
131 @retval EFI_SUCCESS The ACK is successfully processed.\r
132 @retval EFI_TFTP_ERROR The block number loops back.\r
133 @retval Others Failed to transmit the next data packet.\r
134\r
135**/\r
136EFI_STATUS\r
137Mtftp4WrqHandleAck (\r
138 IN MTFTP4_PROTOCOL *Instance,\r
139 IN EFI_MTFTP4_PACKET *Packet,\r
140 IN UINT32 Len,\r
141 OUT BOOLEAN *Completed\r
142 )\r
143{\r
144 UINT16 AckNum;\r
145 INTN Expected;\r
146 UINT64 BlockCounter;\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, *Completed, &BlockCounter);\r
168\r
169 Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
170\r
171 if (Expected < 0) {\r
172\r
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
187 (UINT8 *) "Block number rolls back, not supported, try blksize option"\r
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
199 Check whether the received OACK is valid.\r
200\r
201 The OACK is valid only if:\r
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
205 4. Other requirements of the individal MTFTP options as required.\r
206\r
207 @param Reply The options included in the OACK\r
208 @param Request The options we requested\r
209\r
210 @retval TRUE The options included in OACK is valid.\r
211 @retval FALSE The options included in OACK is invalid.\r
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
223 if ((Reply->Exist & ~Request->Exist) != 0) {\r
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
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
233 return FALSE;\r
234 }\r
235\r
236 return TRUE;\r
237}\r
238\r
239\r
240/**\r
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
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
257 IN OUT MTFTP4_PROTOCOL *Instance,\r
258 IN EFI_MTFTP4_PACKET *Packet,\r
259 IN UINT32 Len,\r
260 OUT BOOLEAN *Completed\r
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
282 ZeroMem (&Reply, sizeof (MTFTP4_OPTION));\r
283 Status = Mtftp4ParseOptionOack (Packet, Len, Instance->Operation, &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
294 (UINT8 *) "Mal-formated OACK packet"\r
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
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
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 EndPoint 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
335**/\r
336VOID\r
337EFIAPI\r
338Mtftp4WrqInput (\r
339 IN NET_BUF *UdpPacket,\r
340 IN UDP_END_POINT *EndPoint,\r
341 IN EFI_STATUS IoStatus,\r
342 IN VOID *Context\r
343 )\r
344{\r
345 MTFTP4_PROTOCOL *Instance;\r
346 EFI_MTFTP4_PACKET *Packet;\r
347 BOOLEAN Completed;\r
348 EFI_STATUS Status;\r
349 UINT32 Len;\r
350 UINT16 Opcode;\r
351\r
352 Instance = (MTFTP4_PROTOCOL *) Context;\r
353 NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);\r
354\r
355 Completed = FALSE;\r
356 Packet = NULL;\r
357 Status = EFI_SUCCESS;\r
358\r
359 if (EFI_ERROR (IoStatus)) {\r
360 Status = IoStatus;\r
361 goto ON_EXIT;\r
362 }\r
363\r
364 ASSERT (UdpPacket != NULL);\r
365\r
366 if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {\r
367 goto ON_EXIT;\r
368 }\r
369\r
370 //\r
371 // Client send initial request to server's listening port. Server\r
372 // will select a UDP port to communicate with the client.\r
373 //\r
374 if (EndPoint->RemotePort != Instance->ConnectedPort) {\r
375 if (Instance->ConnectedPort != 0) {\r
376 goto ON_EXIT;\r
377 } else {\r
378 Instance->ConnectedPort = EndPoint->RemotePort;\r
379 }\r
380 }\r
381\r
382 //\r
383 // Copy the MTFTP packet to a continuous buffer if it isn't already so.\r
384 //\r
385 Len = UdpPacket->TotalSize;\r
386\r
387 if (UdpPacket->BlockOpNum > 1) {\r
388 Packet = AllocatePool (Len);\r
389\r
390 if (Packet == NULL) {\r
391 Status = EFI_OUT_OF_RESOURCES;\r
392 goto ON_EXIT;\r
393 }\r
394\r
395 NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);\r
396\r
397 } else {\r
398 Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);\r
399 ASSERT (Packet != NULL);\r
400 }\r
401\r
402 Opcode = NTOHS (Packet->OpCode);\r
403\r
404 //\r
405 // Call the user's CheckPacket if provided. Abort the transmission\r
406 // if CheckPacket returns an EFI_ERROR code.\r
407 //\r
408 if ((Instance->Token->CheckPacket != NULL) &&\r
409 ((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {\r
410\r
411 Status = Instance->Token->CheckPacket (\r
412 &Instance->Mtftp4,\r
413 Instance->Token,\r
414 (UINT16) Len,\r
415 Packet\r
416 );\r
417\r
418 if (EFI_ERROR (Status)) {\r
419 //\r
420 // Send an error message to the server to inform it\r
421 //\r
422 if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {\r
423 Mtftp4SendError (\r
424 Instance,\r
425 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
426 (UINT8 *) "User aborted the transfer"\r
427 );\r
428 }\r
429\r
430 Status = EFI_ABORTED;\r
431 goto ON_EXIT;\r
432 }\r
433 }\r
434\r
435 switch (Opcode) {\r
436 case EFI_MTFTP4_OPCODE_ACK:\r
437 if (Len != MTFTP4_OPCODE_LEN + MTFTP4_BLKNO_LEN) {\r
438 goto ON_EXIT;\r
439 }\r
440\r
441 Status = Mtftp4WrqHandleAck (Instance, Packet, Len, &Completed);\r
442 break;\r
443\r
444 case EFI_MTFTP4_OPCODE_OACK:\r
445 if (Len <= MTFTP4_OPCODE_LEN) {\r
446 goto ON_EXIT;\r
447 }\r
448\r
449 Status = Mtftp4WrqHandleOack (Instance, Packet, Len, &Completed);\r
450 break;\r
451\r
452 case EFI_MTFTP4_OPCODE_ERROR:\r
453 Status = EFI_TFTP_ERROR;\r
454 break;\r
455\r
456 default:\r
457 break;\r
458 }\r
459\r
460ON_EXIT:\r
461 //\r
462 // Free the resources, then if !EFI_ERROR (Status) and not completed,\r
463 // restart the receive, otherwise end the session.\r
464 //\r
465 if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {\r
466 FreePool (Packet);\r
467 }\r
468\r
469 if (UdpPacket != NULL) {\r
470 NetbufFree (UdpPacket);\r
471 }\r
472\r
473 if (!EFI_ERROR (Status) && !Completed) {\r
474 Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);\r
475 }\r
476\r
477 //\r
478 // Status may have been updated by UdpIoRecvDatagram\r
479 //\r
480 if (EFI_ERROR (Status) || Completed) {\r
481 Mtftp4CleanOperation (Instance, Status);\r
482 }\r
483}\r
484\r
485\r
486\r
487/**\r
488 Start the MTFTP session for upload.\r
489\r
490 It will first init some states, then send the WRQ request packet,\r
491 and start receiving the packet.\r
492\r
493 @param Instance The MTFTP session\r
494 @param Operation Redundant parameter, which is always\r
495 EFI_MTFTP4_OPCODE_WRQ here.\r
496\r
497 @retval EFI_SUCCESS The upload process has been started.\r
498 @retval Others Failed to start the upload.\r
499\r
500**/\r
501EFI_STATUS\r
502Mtftp4WrqStart (\r
503 IN MTFTP4_PROTOCOL *Instance,\r
504 IN UINT16 Operation\r
505 )\r
506{\r
507 EFI_STATUS Status;\r
508\r
509 //\r
510 // The valid block number range are [0, 0xffff]. For example:\r
511 // the client sends an WRQ request to the server, the server\r
512 // ACK with an ACK0 to let client start transfer the first\r
513 // packet.\r
514 //\r
515 Status = Mtftp4InitBlockRange (&Instance->Blocks, 0, 0xffff);\r
516\r
517 if (EFI_ERROR (Status)) {\r
518 return Status;\r
519 }\r
520\r
521 Status = Mtftp4SendRequest (Instance);\r
522\r
523 if (EFI_ERROR (Status)) {\r
524 return Status;\r
525 }\r
526\r
527 return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);\r
528}\r
529\r