VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c@ 94368

Last change on this file since 94368 was 85718, checked in by vboxsync, 4 years ago

Devices/EFI: Merge edk-stable202005 and make it build, bugref:4643

  • Property svn:eol-style set to native
File size: 15.7 KB
Line 
1/** @file
2 Mtftp6 Wrq process functions implementation.
3
4 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "Mtftp6Impl.h"
11
12
13
14/**
15 Build and send a Mtftp6 data packet for upload.
16
17 @param[in] Instance The pointer to the Mtftp6 instance.
18 @param[in] BlockNum The block num to be sent.
19
20 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.
21 @retval EFI_SUCCESS The data packet was sent.
22 @retval EFI_ABORTED The user aborted this process.
23
24**/
25EFI_STATUS
26Mtftp6WrqSendBlock (
27 IN MTFTP6_INSTANCE *Instance,
28 IN UINT16 BlockNum
29 )
30{
31 EFI_MTFTP6_PACKET *Packet;
32 EFI_MTFTP6_TOKEN *Token;
33 NET_BUF *UdpPacket;
34 EFI_STATUS Status;
35 UINT16 DataLen;
36 UINT8 *DataBuf;
37 UINT64 Start;
38
39 //
40 // Allocate net buffer to create data packet.
41 //
42 UdpPacket = NetbufAlloc (Instance->BlkSize + MTFTP6_DATA_HEAD_LEN);
43
44 if (UdpPacket == NULL) {
45 return EFI_OUT_OF_RESOURCES;
46 }
47
48 Packet = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (
49 UdpPacket,
50 MTFTP6_DATA_HEAD_LEN,
51 FALSE
52 );
53 ASSERT (Packet != NULL);
54
55 Packet->Data.OpCode = HTONS (EFI_MTFTP6_OPCODE_DATA);
56 Packet->Data.Block = HTONS (BlockNum);
57
58 //
59 // Read the block from either the buffer or PacketNeeded callback
60 //
61 Token = Instance->Token;
62 DataLen = Instance->BlkSize;
63
64 if (Token->Buffer != NULL) {
65 Start = MultU64x32 (BlockNum - 1, Instance->BlkSize);
66
67 if (Token->BufferSize < Start + Instance->BlkSize) {
68 DataLen = (UINT16) (Token->BufferSize - Start);
69 Instance->LastBlk = BlockNum;
70 Mtftp6SetLastBlockNum (&Instance->BlkList, BlockNum);
71 }
72
73 if (DataLen > 0) {
74 NetbufAllocSpace (UdpPacket, DataLen, FALSE);
75 CopyMem (Packet->Data.Data, (UINT8 *) Token->Buffer + Start, DataLen);
76 }
77
78 } else {
79 //
80 // Get data from PacketNeeded
81 //
82 DataBuf = NULL;
83 Status = Token->PacketNeeded (&Instance->Mtftp6, Token, &DataLen, (VOID*) &DataBuf);
84
85 if (EFI_ERROR (Status) || (DataLen > Instance->BlkSize)) {
86 if (DataBuf != NULL) {
87 gBS->FreePool (DataBuf);
88 }
89 //
90 // The received packet has already been freed.
91 //
92 Mtftp6SendError (
93 Instance,
94 EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
95 (UINT8 *) "User aborted the transfer"
96 );
97
98 return EFI_ABORTED;
99 }
100
101 if (DataLen < Instance->BlkSize) {
102 Instance->LastBlk = BlockNum;
103 Mtftp6SetLastBlockNum (&Instance->BlkList, BlockNum);
104 }
105
106 if (DataLen > 0) {
107 NetbufAllocSpace (UdpPacket, DataLen, FALSE);
108 CopyMem (Packet->Data.Data, DataBuf, DataLen);
109 gBS->FreePool (DataBuf);
110 }
111 }
112
113 //
114 // Reset current retry count of the instance.
115 //
116 Instance->CurRetry = 0;
117
118 return Mtftp6TransmitPacket (Instance, UdpPacket);
119}
120
121
122/**
123 Function to handle received ACK packet. If the ACK number matches the
124 expected block number, with more data pending, send the next
125 block. Otherwise, tell the caller that we are done.
126
127 @param[in] Instance The pointer to the Mtftp6 instance.
128 @param[in] Packet The pointer to the received packet.
129 @param[in] Len The length of the packet.
130 @param[out] UdpPacket The net buf of received packet.
131 @param[out] IsCompleted If TRUE, the upload has been completed.
132 Otherwise, the upload has not been completed.
133
134 @retval EFI_SUCCESS The ACK packet successfully processed.
135 @retval EFI_TFTP_ERROR The block number loops back.
136 @retval Others Failed to transmit the next data packet.
137
138**/
139EFI_STATUS
140Mtftp6WrqHandleAck (
141 IN MTFTP6_INSTANCE *Instance,
142 IN EFI_MTFTP6_PACKET *Packet,
143 IN UINT32 Len,
144 OUT NET_BUF **UdpPacket,
145 OUT BOOLEAN *IsCompleted
146 )
147{
148 UINT16 AckNum;
149 INTN Expected;
150 UINT64 BlockCounter;
151
152 *IsCompleted = FALSE;
153 AckNum = NTOHS (Packet->Ack.Block[0]);
154 Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
155
156 ASSERT (Expected >= 0);
157
158 //
159 // Get an unwanted ACK, return EFI_SUCCESS to let Mtftp6WrqInput
160 // restart receive.
161 //
162 if (Expected != AckNum) {
163 return EFI_SUCCESS;
164 }
165
166 //
167 // Remove the acked block number, if this is the last block number,
168 // tell the Mtftp6WrqInput to finish the transfer. This is the last
169 // block number if the block range are empty.
170 //
171 Mtftp6RemoveBlockNum (&Instance->BlkList, AckNum, *IsCompleted, &BlockCounter);
172
173 Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
174
175 if (Expected < 0) {
176 //
177 // The block range is empty. It may either because the last
178 // block has been ACKed, or the sequence number just looped back,
179 // that is, there is more than 0xffff blocks.
180 //
181 if (Instance->LastBlk == AckNum) {
182 ASSERT (Instance->LastBlk >= 1);
183 *IsCompleted = TRUE;
184 return EFI_SUCCESS;
185
186 } else {
187 //
188 // Free the received packet before send new packet in ReceiveNotify,
189 // since the udpio might need to be reconfigured.
190 //
191 NetbufFree (*UdpPacket);
192 *UdpPacket = NULL;
193 //
194 // Send the Mtftp6 error message if block number rolls back.
195 //
196 Mtftp6SendError (
197 Instance,
198 EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
199 (UINT8 *) "Block number rolls back, not supported, try blksize option"
200 );
201
202 return EFI_TFTP_ERROR;
203 }
204 }
205
206 //
207 // Free the receive buffer before send new packet since it might need
208 // reconfigure udpio.
209 //
210 NetbufFree (*UdpPacket);
211 *UdpPacket = NULL;
212
213 return Mtftp6WrqSendBlock (Instance, (UINT16) Expected);
214}
215
216
217/**
218 Check whether the received OACK is valid. The OACK is valid
219 only if:
220 1. It only include options requested by us.
221 2. It can only include a smaller block size.
222 3. It can't change the proposed time out value.
223 4. Other requirements of the individal MTFTP6 options as required.
224
225 @param[in] ReplyInfo The pointer to options information in reply packet.
226 @param[in] RequestInfo The pointer to requested options information.
227
228 @retval TRUE If the option in OACK is valid.
229 @retval FALSE If the option is invalid.
230
231**/
232BOOLEAN
233Mtftp6WrqOackValid (
234 IN MTFTP6_EXT_OPTION_INFO *ReplyInfo,
235 IN MTFTP6_EXT_OPTION_INFO *RequestInfo
236 )
237{
238 //
239 // It is invalid for server to return options we don't request
240 //
241 if ((ReplyInfo->BitMap & ~RequestInfo->BitMap) != 0) {
242 return FALSE;
243 }
244
245 //
246 // Server can only specify a smaller block size to be used and
247 // return the timeout matches that requested.
248 //
249 if ((((ReplyInfo->BitMap & MTFTP6_OPT_BLKSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||
250 (((ReplyInfo->BitMap & MTFTP6_OPT_TIMEOUT_BIT) != 0) && (ReplyInfo->Timeout != RequestInfo->Timeout))
251 ) {
252
253 return FALSE;
254 }
255
256 return TRUE;
257}
258
259
260/**
261 Process the OACK packet for Wrq.
262
263 @param[in] Instance The pointer to the Mtftp6 instance.
264 @param[in] Packet The pointer to the received packet.
265 @param[in] Len The length of the packet.
266 @param[out] UdpPacket The net buf of received packet.
267 @param[out] IsCompleted If TRUE, the upload has been completed.
268 Otherwise, the upload has not been completed.
269
270 @retval EFI_SUCCESS The OACK packet successfully processed.
271 @retval EFI_TFTP_ERROR An TFTP communication error happened.
272 @retval Others Failed to process the OACK packet.
273
274**/
275EFI_STATUS
276Mtftp6WrqHandleOack (
277 IN MTFTP6_INSTANCE *Instance,
278 IN EFI_MTFTP6_PACKET *Packet,
279 IN UINT32 Len,
280 OUT NET_BUF **UdpPacket,
281 OUT BOOLEAN *IsCompleted
282 )
283{
284 EFI_MTFTP6_OPTION *Options;
285 UINT32 Count;
286 MTFTP6_EXT_OPTION_INFO ExtInfo;
287 EFI_MTFTP6_PACKET Dummy;
288 EFI_STATUS Status;
289 INTN Expected;
290
291 *IsCompleted = FALSE;
292 Options = NULL;
293
294 //
295 // Ignore the OACK if already started the upload
296 //
297 Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
298
299 if (Expected != 0) {
300 return EFI_SUCCESS;
301 }
302
303 //
304 // Parse and validate the options from server
305 //
306 ZeroMem (&ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));
307
308 Status = Mtftp6ParseStart (Packet, Len, &Count, &Options);
309
310 if (EFI_ERROR (Status)) {
311 return Status;
312 }
313 ASSERT (Options != NULL);
314
315 Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, Instance->Operation, &ExtInfo);
316
317 if (EFI_ERROR(Status) || !Mtftp6WrqOackValid (&ExtInfo, &Instance->ExtInfo)) {
318 //
319 // Don't send a MTFTP error packet when out of resource, it can
320 // only make it worse.
321 //
322 if (Status != EFI_OUT_OF_RESOURCES) {
323 //
324 // Free the received packet before send new packet in ReceiveNotify,
325 // since the udpio might need to be reconfigured.
326 //
327 NetbufFree (*UdpPacket);
328 *UdpPacket = NULL;
329 //
330 // Send the Mtftp6 error message if invalid Oack packet received.
331 //
332 Mtftp6SendError (
333 Instance,
334 EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
335 (UINT8 *) "Malformatted OACK packet"
336 );
337 }
338
339 return EFI_TFTP_ERROR;
340 }
341
342 if (ExtInfo.BlkSize != 0) {
343 Instance->BlkSize = ExtInfo.BlkSize;
344 }
345
346 if (ExtInfo.Timeout != 0) {
347 Instance->Timeout = ExtInfo.Timeout;
348 }
349
350 //
351 // Build a bogus ACK0 packet then pass it to the Mtftp6WrqHandleAck,
352 // which will start the transmission of the first data block.
353 //
354 Dummy.Ack.OpCode = HTONS (EFI_MTFTP6_OPCODE_ACK);
355 Dummy.Ack.Block[0] = 0;
356
357 return Mtftp6WrqHandleAck (
358 Instance,
359 &Dummy,
360 sizeof (EFI_MTFTP6_ACK_HEADER),
361 UdpPacket,
362 IsCompleted
363 );
364}
365
366
367/**
368 The packet process callback for Mtftp6 upload.
369
370 @param[in] UdpPacket The pointer to the packet received.
371 @param[in] UdpEpt The pointer to the Udp6 access point.
372 @param[in] IoStatus The status from Udp6 instance.
373 @param[in] Context The pointer to the context.
374
375**/
376VOID
377EFIAPI
378Mtftp6WrqInput (
379 IN NET_BUF *UdpPacket,
380 IN UDP_END_POINT *UdpEpt,
381 IN EFI_STATUS IoStatus,
382 IN VOID *Context
383 )
384{
385 MTFTP6_INSTANCE *Instance;
386 EFI_MTFTP6_PACKET *Packet;
387 BOOLEAN IsCompleted;
388 EFI_STATUS Status;
389 UINT32 TotalNum;
390 UINT32 Len;
391 UINT16 Opcode;
392
393 Instance = (MTFTP6_INSTANCE *) Context;
394
395 NET_CHECK_SIGNATURE (Instance, MTFTP6_INSTANCE_SIGNATURE);
396
397 IsCompleted = FALSE;
398 Packet = NULL;
399 Status = EFI_SUCCESS;
400 TotalNum = 0;
401
402 //
403 // Return error status if Udp6 instance failed to receive.
404 //
405 if (EFI_ERROR (IoStatus)) {
406 Status = IoStatus;
407 goto ON_EXIT;
408 }
409
410 ASSERT (UdpPacket != NULL);
411
412 if (UdpPacket->TotalSize < MTFTP6_OPCODE_LEN) {
413 goto ON_EXIT;
414 }
415
416 //
417 // Client send initial request to server's listening port. Server
418 // will select a UDP port to communicate with the client.
419 //
420 if (UdpEpt->RemotePort != Instance->ServerDataPort) {
421 if (Instance->ServerDataPort != 0) {
422 goto ON_EXIT;
423 } else {
424 Instance->ServerDataPort = UdpEpt->RemotePort;
425 }
426 }
427
428 //
429 // Copy the MTFTP packet to a continuous buffer if it isn't already so.
430 //
431 Len = UdpPacket->TotalSize;
432 TotalNum = UdpPacket->BlockOpNum;
433
434 if (TotalNum > 1) {
435 Packet = AllocateZeroPool (Len);
436
437 if (Packet == NULL) {
438 Status = EFI_OUT_OF_RESOURCES;
439 goto ON_EXIT;
440 }
441
442 NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
443
444 } else {
445 Packet = (EFI_MTFTP6_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
446 ASSERT (Packet != NULL);
447 }
448
449 Opcode = NTOHS (Packet->OpCode);
450
451 //
452 // Callback to the user's CheckPacket if provided. Abort the transmission
453 // if CheckPacket returns an EFI_ERROR code.
454 //
455 if (Instance->Token->CheckPacket != NULL &&
456 (Opcode == EFI_MTFTP6_OPCODE_OACK || Opcode == EFI_MTFTP6_OPCODE_ERROR)
457 ) {
458
459 Status = Instance->Token->CheckPacket (
460 &Instance->Mtftp6,
461 Instance->Token,
462 (UINT16) Len,
463 Packet
464 );
465
466 if (EFI_ERROR (Status)) {
467 //
468 // Send an error message to the server to inform it
469 //
470 if (Opcode != EFI_MTFTP6_OPCODE_ERROR) {
471 //
472 // Free the received packet before send new packet in ReceiveNotify,
473 // since the udpio might need to be reconfigured.
474 //
475 NetbufFree (UdpPacket);
476 UdpPacket = NULL;
477 //
478 // Send the Mtftp6 error message if user aborted the current session.
479 //
480 Mtftp6SendError (
481 Instance,
482 EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
483 (UINT8 *) "User aborted the transfer"
484 );
485 }
486
487 Status = EFI_ABORTED;
488 goto ON_EXIT;
489 }
490 }
491
492 //
493 // Switch the process routines by the operation code.
494 //
495 switch (Opcode) {
496 case EFI_MTFTP6_OPCODE_ACK:
497 if (Len != MTFTP6_OPCODE_LEN + MTFTP6_BLKNO_LEN) {
498 goto ON_EXIT;
499 }
500 //
501 // Handle the Ack packet of Wrq.
502 //
503 Status = Mtftp6WrqHandleAck (Instance, Packet, Len, &UdpPacket, &IsCompleted);
504 break;
505
506 case EFI_MTFTP6_OPCODE_OACK:
507 if (Len <= MTFTP6_OPCODE_LEN) {
508 goto ON_EXIT;
509 }
510 //
511 // Handle the Oack packet of Wrq.
512 //
513 Status = Mtftp6WrqHandleOack (Instance, Packet, Len, &UdpPacket, &IsCompleted);
514 break;
515
516 default:
517 //
518 // Drop and return eror if received error message.
519 //
520 Status = EFI_TFTP_ERROR;
521 break;
522 }
523
524ON_EXIT:
525 //
526 // Free the resources, then if !EFI_ERROR (Status) and not completed,
527 // restart the receive, otherwise end the session.
528 //
529 if (Packet != NULL && TotalNum > 1) {
530 FreePool (Packet);
531 }
532
533 if (UdpPacket != NULL) {
534 NetbufFree (UdpPacket);
535 }
536
537 if (!EFI_ERROR (Status) && !IsCompleted) {
538 Status = UdpIoRecvDatagram (
539 Instance->UdpIo,
540 Mtftp6WrqInput,
541 Instance,
542 0
543 );
544 }
545 //
546 // Clean up the current session if failed to continue.
547 //
548 if (EFI_ERROR (Status) || IsCompleted) {
549 Mtftp6OperationClean (Instance, Status);
550 }
551}
552
553
554/**
555 Start the Mtftp6 instance to upload. It will first init some states,
556 then send the WRQ request packet, and start to receive the packet.
557
558 @param[in] Instance The pointer to the Mtftp6 instance.
559 @param[in] Operation The operation code of the current packet.
560
561 @retval EFI_SUCCESS The Mtftp6 was started to upload.
562 @retval Others Failed to start to upload.
563
564**/
565EFI_STATUS
566Mtftp6WrqStart (
567 IN MTFTP6_INSTANCE *Instance,
568 IN UINT16 Operation
569 )
570{
571 EFI_STATUS Status;
572
573 //
574 // The valid block number range are [0, 0xffff]. For example:
575 // the client sends an WRQ request to the server, the server
576 // ACK with an ACK0 to let client start transfer the first
577 // packet.
578 //
579 Status = Mtftp6InitBlockRange (&Instance->BlkList, 0, 0xffff);
580
581 if (EFI_ERROR (Status)) {
582 return Status;
583 }
584
585 Status = Mtftp6SendRequest (Instance, Operation);
586
587 if (EFI_ERROR (Status)) {
588 return Status;
589 }
590
591 return UdpIoRecvDatagram (
592 Instance->UdpIo,
593 Mtftp6WrqInput,
594 Instance,
595 0
596 );
597}
598
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette