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