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