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