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