TianoCore EDK2 master
Loading...
Searching...
No Matches
Mtftp4Wrq.c
Go to the documentation of this file.
1
9#include "Mtftp4Impl.h"
10
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
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
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 {
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
207BOOLEAN
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
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) {
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
328VOID
329EFIAPI
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) {
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
451ON_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
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}
INT64 INTN
UINT64 EFIAPI MultU64x32(IN UINT64 Multiplicand, IN UINT32 Multiplier)
Definition: MultU64x32.c:27
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
VOID Mtftp4CleanOperation(IN OUT MTFTP4_PROTOCOL *Instance, IN EFI_STATUS Result)
Definition: Mtftp4Impl.c:20
EFI_STATUS Mtftp4ParseOptionOack(IN EFI_MTFTP4_PACKET *Packet, IN UINT32 PacketLen, IN UINT16 Operation, OUT MTFTP4_OPTION *MtftpOption)
Definition: Mtftp4Option.c:512
EFI_STATUS Mtftp4InitBlockRange(IN LIST_ENTRY *Head, IN UINT16 Start, IN UINT16 End)
Definition: Mtftp4Support.c:64
VOID Mtftp4SetLastBlockNum(IN LIST_ENTRY *Head, IN UINT16 Last)
EFI_STATUS Mtftp4SendRequest(IN MTFTP4_PROTOCOL *Instance)
INTN Mtftp4GetNextBlockNum(IN LIST_ENTRY *Head)
Definition: Mtftp4Support.c:91
EFI_STATUS Mtftp4SendError(IN MTFTP4_PROTOCOL *Instance, IN UINT16 ErrCode, IN UINT8 *ErrInfo)
EFI_STATUS Mtftp4RemoveBlockNum(IN LIST_ENTRY *Head, IN UINT16 Num, IN BOOLEAN Completed, OUT UINT64 *BlockCounter)
EFI_STATUS Mtftp4SendPacket(IN OUT MTFTP4_PROTOCOL *Instance, IN OUT NET_BUF *Packet)
EFI_STATUS Mtftp4WrqHandleAck(IN MTFTP4_PROTOCOL *Instance, IN EFI_MTFTP4_PACKET *Packet, IN UINT32 Len, OUT BOOLEAN *Completed)
Definition: Mtftp4Wrq.c:133
EFI_STATUS Mtftp4WrqHandleOack(IN OUT MTFTP4_PROTOCOL *Instance, IN EFI_MTFTP4_PACKET *Packet, IN UINT32 Len, OUT BOOLEAN *Completed)
Definition: Mtftp4Wrq.c:249
EFI_STATUS Mtftp4WrqStart(IN MTFTP4_PROTOCOL *Instance, IN UINT16 Operation)
Definition: Mtftp4Wrq.c:491
VOID EFIAPI Mtftp4WrqInput(IN NET_BUF *UdpPacket, IN UDP_END_POINT *EndPoint, IN EFI_STATUS IoStatus, IN VOID *Context)
Definition: Mtftp4Wrq.c:330
BOOLEAN Mtftp4WrqOackValid(IN MTFTP4_OPTION *Reply, IN MTFTP4_OPTION *Request)
Definition: Mtftp4Wrq.c:208
EFI_STATUS Mtftp4WrqSendBlock(IN OUT MTFTP4_PROTOCOL *Instance, IN UINT16 BlockNum)
Definition: Mtftp4Wrq.c:24
VOID EFIAPI NetbufFree(IN NET_BUF *Nbuf)
Definition: NetBuffer.c:195
UINT32 EFIAPI NetbufCopy(IN NET_BUF *Nbuf, IN UINT32 Offset, IN UINT32 Len, IN UINT8 *Dest)
Definition: NetBuffer.c:1206
NET_BUF *EFIAPI NetbufAlloc(IN UINT32 Len)
Definition: NetBuffer.c:89
UINT8 *EFIAPI NetbufAllocSpace(IN OUT NET_BUF *Nbuf, IN UINT32 Len, IN BOOLEAN FromHead)
Definition: NetBuffer.c:1015
UINT8 *EFIAPI NetbufGetByte(IN NET_BUF *Nbuf, IN UINT32 Offset, OUT UINT32 *Index OPTIONAL)
Definition: NetBuffer.c:359
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
EFI_STATUS EFIAPI UdpIoRecvDatagram(IN UDP_IO *UdpIo, IN UDP_IO_CALLBACK CallBack, IN VOID *Context, IN UINT32 HeadLen)
Definition: DxeUdpIoLib.c:1084
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_MTFTP4_CHECK_PACKET CheckPacket
Definition: Mtftp4.h:562
UINT64 BufferSize
Definition: Mtftp4.h:547
EFI_MTFTP4_PACKET_NEEDED PacketNeeded
Definition: Mtftp4.h:570
VOID * Buffer
Definition: Mtftp4.h:553
EFI_MTFTP4_DATA_HEADER Data
Definition: Mtftp4.h:117
UINT16 OpCode
Definition: Mtftp4.h:101
EFI_MTFTP4_ACK_HEADER Ack
Definition: Mtftp4.h:121