]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Wrq.c
add security check.
[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 gBS->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 gBS->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 Points 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 Mtftp4WrqInput (
339 IN NET_BUF *UdpPacket,
340 IN UDP_POINTS *Points,
341 IN EFI_STATUS IoStatus,
342 IN VOID *Context
343 )
344 {
345 MTFTP4_PROTOCOL *Instance;
346 EFI_MTFTP4_PACKET *Packet;
347 BOOLEAN Completed;
348 EFI_STATUS Status;
349 UINT32 Len;
350 UINT16 Opcode;
351
352 Instance = (MTFTP4_PROTOCOL *) Context;
353 NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);
354
355 Completed = FALSE;
356 Packet = NULL;
357 Status = EFI_SUCCESS;
358
359 if (EFI_ERROR (IoStatus)) {
360 Status = IoStatus;
361 goto ON_EXIT;
362 }
363
364 ASSERT (UdpPacket != NULL);
365
366 if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {
367 goto ON_EXIT;
368 }
369
370 //
371 // Client send initial request to server's listening port. Server
372 // will select a UDP port to communicate with the client.
373 //
374 if (Points->RemotePort != Instance->ConnectedPort) {
375 if (Instance->ConnectedPort != 0) {
376 goto ON_EXIT;
377 } else {
378 Instance->ConnectedPort = Points->RemotePort;
379 }
380 }
381
382 //
383 // Copy the MTFTP packet to a continuous buffer if it isn't already so.
384 //
385 Len = UdpPacket->TotalSize;
386
387 if (UdpPacket->BlockOpNum > 1) {
388 Packet = AllocatePool (Len);
389
390 if (Packet == NULL) {
391 Status = EFI_OUT_OF_RESOURCES;
392 goto ON_EXIT;
393 }
394
395 NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
396
397 } else {
398 Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
399 }
400
401 Opcode = NTOHS (Packet->OpCode);
402
403 //
404 // Call the user's CheckPacket if provided. Abort the transmission
405 // if CheckPacket returns an EFI_ERROR code.
406 //
407 if ((Instance->Token->CheckPacket != NULL) &&
408 ((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {
409
410 Status = Instance->Token->CheckPacket (
411 &Instance->Mtftp4,
412 Instance->Token,
413 (UINT16) Len,
414 Packet
415 );
416
417 if (EFI_ERROR (Status)) {
418 //
419 // Send an error message to the server to inform it
420 //
421 if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {
422 Mtftp4SendError (
423 Instance,
424 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
425 (UINT8 *) "User aborted the transfer"
426 );
427 }
428
429 Status = EFI_ABORTED;
430 goto ON_EXIT;
431 }
432 }
433
434 switch (Opcode) {
435 case EFI_MTFTP4_OPCODE_ACK:
436 if (Len != MTFTP4_OPCODE_LEN + MTFTP4_BLKNO_LEN) {
437 goto ON_EXIT;
438 }
439
440 Status = Mtftp4WrqHandleAck (Instance, Packet, Len, &Completed);
441 break;
442
443 case EFI_MTFTP4_OPCODE_OACK:
444 if (Len <= MTFTP4_OPCODE_LEN) {
445 goto ON_EXIT;
446 }
447
448 Status = Mtftp4WrqHandleOack (Instance, Packet, Len, &Completed);
449 break;
450
451 case EFI_MTFTP4_OPCODE_ERROR:
452 Status = EFI_TFTP_ERROR;
453 break;
454
455 default:
456 break;
457 }
458
459 ON_EXIT:
460 //
461 // Free the resources, then if !EFI_ERROR (Status) and not completed,
462 // restart the receive, otherwise end the session.
463 //
464 if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {
465 gBS->FreePool (Packet);
466 }
467
468 if (UdpPacket != NULL) {
469 NetbufFree (UdpPacket);
470 }
471
472 if (!EFI_ERROR (Status) && !Completed) {
473 Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);
474 }
475
476 //
477 // Status may have been updated by UdpIoRecvDatagram
478 //
479 if (EFI_ERROR (Status) || Completed) {
480 Mtftp4CleanOperation (Instance, Status);
481 }
482 }
483
484
485
486 /**
487 Start the MTFTP session for upload.
488
489 It will first init some states, then send the WRQ request packet,
490 and start receiving the packet.
491
492 @param Instance The MTFTP session
493 @param Operation Redundant parameter, which is always
494 EFI_MTFTP4_OPCODE_WRQ here.
495
496 @retval EFI_SUCCESS The upload process has been started.
497 @retval Others Failed to start the upload.
498
499 **/
500 EFI_STATUS
501 Mtftp4WrqStart (
502 IN MTFTP4_PROTOCOL *Instance,
503 IN UINT16 Operation
504 )
505 {
506 EFI_STATUS Status;
507
508 //
509 // The valid block number range are [0, 0xffff]. For example:
510 // the client sends an WRQ request to the server, the server
511 // ACK with an ACK0 to let client start transfer the first
512 // packet.
513 //
514 Status = Mtftp4InitBlockRange (&Instance->Blocks, 0, 0xffff);
515
516 if (EFI_ERROR (Status)) {
517 return Status;
518 }
519
520 Status = Mtftp4SendRequest (Instance);
521
522 if (EFI_ERROR (Status)) {
523 return Status;
524 }
525
526 return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);
527 }
528