1 /** @file
2 Help functions to access UDP service, it is used by both the DHCP and MTFTP.
3
4 Copyright (c) 2005 - 2016, 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<BR>
8 http://opensource.org/licenses/bsd-license.php
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 #include <Uefi.h>
15
16 #include <Protocol/Udp4.h>
17 #include <Protocol/Udp6.h>
18
19 #include <Library/UdpIoLib.h>
20 #include <Library/BaseLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/MemoryAllocationLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/DpcLib.h>
26
27
28 /**
29 Free a UDP_TX_TOKEN. The TX event is closed.
30
31 @param[in] TxToken The UDP_TX_TOKEN to release.
32
33 **/
34 VOID
UdpIoFreeTxToken(IN UDP_TX_TOKEN * TxToken)35 UdpIoFreeTxToken (
36 IN UDP_TX_TOKEN *TxToken
37 )
38 {
39
40 if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
41 gBS->CloseEvent (TxToken->Token.Udp4.Event);
42 } else if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {
43 gBS->CloseEvent (TxToken->Token.Udp6.Event);
44 } else {
45 ASSERT (FALSE);
46 }
47
48 FreePool (TxToken);
49 }
50
51 /**
52 Free a UDP_RX_TOKEN. The RX event is closed.
53
54 @param[in] RxToken The UDP_RX_TOKEN to release.
55
56 **/
57 VOID
UdpIoFreeRxToken(IN UDP_RX_TOKEN * RxToken)58 UdpIoFreeRxToken (
59 IN UDP_RX_TOKEN *RxToken
60 )
61 {
62 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
63 gBS->CloseEvent (RxToken->Token.Udp4.Event);
64 } else if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {
65 gBS->CloseEvent (RxToken->Token.Udp6.Event);
66 } else {
67 ASSERT (FALSE);
68 }
69
70 FreePool (RxToken);
71 }
72
73 /**
74 The callback function when the packet is sent by UDP.
75
76 It will remove the packet from the local list then call
77 the packet owner's callback function set by UdpIoSendDatagram.
78
79 @param[in] Context The UDP TX Token.
80
81 **/
82 VOID
83 EFIAPI
UdpIoOnDgramSentDpc(IN VOID * Context)84 UdpIoOnDgramSentDpc (
85 IN VOID *Context
86 )
87 {
88 UDP_TX_TOKEN *TxToken;
89
90 TxToken = (UDP_TX_TOKEN *) Context;
91 ASSERT (TxToken->Signature == UDP_IO_TX_SIGNATURE);
92 ASSERT ((TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
93 (TxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
94
95 RemoveEntryList (&TxToken->Link);
96
97 if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
98 TxToken->CallBack (TxToken->Packet, NULL, TxToken->Token.Udp4.Status, TxToken->Context);
99 } else {
100 TxToken->CallBack (TxToken->Packet, NULL, TxToken->Token.Udp6.Status, TxToken->Context);
101 }
102
103 UdpIoFreeTxToken (TxToken);
104 }
105
106 /**
107 Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK.
108
109 @param[in] Event The event signaled.
110 @param[in] Context The UDP TX Token.
111
112 **/
113 VOID
114 EFIAPI
UdpIoOnDgramSent(IN EFI_EVENT Event,IN VOID * Context)115 UdpIoOnDgramSent (
116 IN EFI_EVENT Event,
117 IN VOID *Context
118 )
119 {
120 //
121 // Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK
122 //
123 QueueDpc (TPL_CALLBACK, UdpIoOnDgramSentDpc, Context);
124 }
125
126 /**
127 Recycle the received UDP data.
128
129 @param[in] Context The UDP_RX_TOKEN.
130
131 **/
132 VOID
133 EFIAPI
UdpIoRecycleDgram(IN VOID * Context)134 UdpIoRecycleDgram (
135 IN VOID *Context
136 )
137 {
138 UDP_RX_TOKEN *RxToken;
139
140 RxToken = (UDP_RX_TOKEN *) Context;
141
142 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
143 gBS->SignalEvent (RxToken->Token.Udp4.Packet.RxData->RecycleSignal);
144 } else if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {
145 gBS->SignalEvent (RxToken->Token.Udp6.Packet.RxData->RecycleSignal);
146 } else {
147 ASSERT (FALSE);
148 }
149
150 UdpIoFreeRxToken (RxToken);
151 }
152
153 /**
154 The event handle for UDP receive request.
155
156 It will build a NET_BUF from the recieved UDP data, then deliver it
157 to the receiver.
158
159 @param[in] Context The UDP RX token.
160
161 **/
162 VOID
163 EFIAPI
UdpIoOnDgramRcvdDpc(IN VOID * Context)164 UdpIoOnDgramRcvdDpc (
165 IN VOID *Context
166 )
167 {
168 EFI_STATUS Status;
169 VOID *Token;
170 VOID *RxData;
171 VOID *Session;
172 UDP_RX_TOKEN *RxToken;
173 UDP_END_POINT EndPoint;
174 NET_BUF *Netbuf;
175
176 RxToken = (UDP_RX_TOKEN *) Context;
177
178 ZeroMem (&EndPoint, sizeof(UDP_END_POINT));
179
180 ASSERT ((RxToken->Signature == UDP_IO_RX_SIGNATURE) &&
181 (RxToken == RxToken->UdpIo->RecvRequest));
182
183 ASSERT ((RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
184 (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
185
186 //
187 // Clear the receive request first in case that the caller
188 // wants to restart the receive in the callback.
189 //
190 RxToken->UdpIo->RecvRequest = NULL;
191
192 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
193 Token = &RxToken->Token.Udp4;
194 RxData = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.RxData;
195 Status = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status;
196 } else {
197 Token = &RxToken->Token.Udp6;
198 RxData = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.RxData;
199 Status = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status;
200 }
201
202 if (EFI_ERROR (Status) || RxData == NULL) {
203 if (Status != EFI_ABORTED) {
204 //
205 // Invoke the CallBack only if the reception is not actively aborted.
206 //
207 RxToken->CallBack (NULL, NULL, Status, RxToken->Context);
208 }
209
210 UdpIoFreeRxToken (RxToken);
211 return;
212 }
213
214 //
215 // Build a NET_BUF from the UDP receive data, then deliver it up.
216 //
217 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
218 if (((EFI_UDP4_RECEIVE_DATA *) RxData)->DataLength == 0) {
219 //
220 // Discard zero length data payload packet.
221 //
222 goto Resume;
223 }
224
225 Netbuf = NetbufFromExt (
226 (NET_FRAGMENT *)((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentTable,
227 ((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentCount,
228 0,
229 (UINT32) RxToken->HeadLen,
230 UdpIoRecycleDgram,
231 RxToken
232 );
233
234 if (Netbuf == NULL) {
235 gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal);
236 RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);
237
238 UdpIoFreeRxToken (RxToken);
239 return;
240 }
241
242 Session = &((EFI_UDP4_RECEIVE_DATA *) RxData)->UdpSession;
243 EndPoint.LocalPort = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort;
244 EndPoint.RemotePort = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort;
245
246 CopyMem (
247 &EndPoint.LocalAddr,
248 &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress,
249 sizeof (EFI_IPv4_ADDRESS)
250 );
251
252 CopyMem (
253 &EndPoint.RemoteAddr,
254 &((EFI_UDP4_SESSION_DATA *) Session)->SourceAddress,
255 sizeof (EFI_IPv4_ADDRESS)
256 );
257
258 EndPoint.LocalAddr.Addr[0] = NTOHL (EndPoint.LocalAddr.Addr[0]);
259 EndPoint.RemoteAddr.Addr[0] = NTOHL (EndPoint.RemoteAddr.Addr[0]);
260 } else {
261 if (((EFI_UDP6_RECEIVE_DATA *) RxData)->DataLength == 0) {
262 //
263 // Discard zero length data payload packet.
264 //
265 goto Resume;
266 }
267
268 Netbuf = NetbufFromExt (
269 (NET_FRAGMENT *)((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentTable,
270 ((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentCount,
271 0,
272 (UINT32) RxToken->HeadLen,
273 UdpIoRecycleDgram,
274 RxToken
275 );
276
277 if (Netbuf == NULL) {
278 gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal);
279 RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);
280
281 UdpIoFreeRxToken (RxToken);
282 return;
283 }
284
285 Session = &((EFI_UDP6_RECEIVE_DATA *) RxData)->UdpSession;
286 EndPoint.LocalPort = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort;
287 EndPoint.RemotePort = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort;
288
289 CopyMem (
290 &EndPoint.LocalAddr,
291 &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress,
292 sizeof (EFI_IPv6_ADDRESS)
293 );
294
295 CopyMem (
296 &EndPoint.RemoteAddr,
297 &((EFI_UDP6_SESSION_DATA *) Session)->SourceAddress,
298 sizeof (EFI_IPv6_ADDRESS)
299 );
300
301 Ip6Swap128 (&EndPoint.LocalAddr.v6);
302 Ip6Swap128 (&EndPoint.RemoteAddr.v6);
303 }
304
305 RxToken->CallBack (Netbuf, &EndPoint, EFI_SUCCESS, RxToken->Context);
306 return;
307
308 Resume:
309 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
310 gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal);
311 RxToken->UdpIo->Protocol.Udp4->Receive (RxToken->UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
312 } else {
313 gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal);
314 RxToken->UdpIo->Protocol.Udp6->Receive (RxToken->UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
315 }
316 }
317
318 /**
319 Request UdpIoOnDgramRcvdDpc() as a DPC at TPL_CALLBACK.
320
321 @param[in] Event The UDP receive request event.
322 @param[in] Context The UDP RX token.
323
324 **/
325 VOID
326 EFIAPI
UdpIoOnDgramRcvd(IN EFI_EVENT Event,IN VOID * Context)327 UdpIoOnDgramRcvd (
328 IN EFI_EVENT Event,
329 IN VOID *Context
330 )
331 {
332 //
333 // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
334 //
335 QueueDpc (TPL_CALLBACK, UdpIoOnDgramRcvdDpc, Context);
336 }
337
338 /**
339 Create a UDP_RX_TOKEN to wrap the request.
340
341 @param[in] UdpIo The UdpIo to receive packets from.
342 @param[in] CallBack The function to call when receive finished.
343 @param[in] Context The opaque parameter to the CallBack.
344 @param[in] HeadLen The head length to reserver for the packet.
345
346 @return The Wrapped request or NULL if failed to allocate resources or some errors happened.
347
348 **/
349 UDP_RX_TOKEN *
UdpIoCreateRxToken(IN UDP_IO * UdpIo,IN UDP_IO_CALLBACK CallBack,IN VOID * Context,IN UINT32 HeadLen)350 UdpIoCreateRxToken (
351 IN UDP_IO *UdpIo,
352 IN UDP_IO_CALLBACK CallBack,
353 IN VOID *Context,
354 IN UINT32 HeadLen
355 )
356 {
357 UDP_RX_TOKEN *Token;
358 EFI_STATUS Status;
359
360 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
361 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
362
363 Token = AllocatePool (sizeof (UDP_RX_TOKEN));
364
365 if (Token == NULL) {
366 return NULL;
367 }
368
369 Token->Signature = UDP_IO_RX_SIGNATURE;
370 Token->UdpIo = UdpIo;
371 Token->CallBack = CallBack;
372 Token->Context = Context;
373 Token->HeadLen = HeadLen;
374
375 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
376
377 Token->Token.Udp4.Status = EFI_NOT_READY;
378 Token->Token.Udp4.Packet.RxData = NULL;
379
380 Status = gBS->CreateEvent (
381 EVT_NOTIFY_SIGNAL,
382 TPL_NOTIFY,
383 UdpIoOnDgramRcvd,
384 Token,
385 &Token->Token.Udp4.Event
386 );
387 } else {
388
389 Token->Token.Udp6.Status = EFI_NOT_READY;
390 Token->Token.Udp6.Packet.RxData = NULL;
391
392 Status = gBS->CreateEvent (
393 EVT_NOTIFY_SIGNAL,
394 TPL_NOTIFY,
395 UdpIoOnDgramRcvd,
396 Token,
397 &Token->Token.Udp6.Event
398 );
399 }
400
401
402 if (EFI_ERROR (Status)) {
403 FreePool (Token);
404 return NULL;
405 }
406
407 return Token;
408 }
409
410 /**
411 Wrap a transmit request into a new created UDP_TX_TOKEN.
412
413 @param[in] UdpIo The UdpIo to send packet to.
414 @param[in] Packet The user's packet.
415 @param[in] EndPoint The local and remote access point.
416 @param[in] Gateway The overrided next hop.
417 @param[in] CallBack The function to call when transmission completed.
418 @param[in] Context The opaque parameter to the call back.
419
420 @return The wrapped transmission request or NULL if failed to allocate resources
421 or for some errors.
422
423 **/
424 UDP_TX_TOKEN *
UdpIoCreateTxToken(IN UDP_IO * UdpIo,IN NET_BUF * Packet,IN UDP_END_POINT * EndPoint OPTIONAL,IN EFI_IP_ADDRESS * Gateway OPTIONAL,IN UDP_IO_CALLBACK CallBack,IN VOID * Context)425 UdpIoCreateTxToken (
426 IN UDP_IO *UdpIo,
427 IN NET_BUF *Packet,
428 IN UDP_END_POINT *EndPoint OPTIONAL,
429 IN EFI_IP_ADDRESS *Gateway OPTIONAL,
430 IN UDP_IO_CALLBACK CallBack,
431 IN VOID *Context
432 )
433 {
434 UDP_TX_TOKEN *TxToken;
435 VOID *Token;
436 VOID *Data;
437 EFI_STATUS Status;
438 UINT32 Count;
439 UINTN Size;
440 IP4_ADDR Ip;
441
442 ASSERT (Packet != NULL);
443 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
444 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
445
446 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
447 Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP4_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);
448 } else {
449 Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP6_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);
450 }
451
452 TxToken = AllocatePool (Size);
453
454 if (TxToken == NULL) {
455 return NULL;
456 }
457
458 TxToken->Signature = UDP_IO_TX_SIGNATURE;
459 InitializeListHead (&TxToken->Link);
460
461 TxToken->UdpIo = UdpIo;
462 TxToken->CallBack = CallBack;
463 TxToken->Packet = Packet;
464 TxToken->Context = Context;
465
466 Token = &(TxToken->Token);
467 Count = Packet->BlockOpNum;
468
469 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
470
471 ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;
472
473 Status = gBS->CreateEvent (
474 EVT_NOTIFY_SIGNAL,
475 TPL_NOTIFY,
476 UdpIoOnDgramSent,
477 TxToken,
478 &((EFI_UDP4_COMPLETION_TOKEN *) Token)->Event
479 );
480
481 if (EFI_ERROR (Status)) {
482 FreePool (TxToken);
483 return NULL;
484 }
485
486 Data = &(TxToken->Data.Udp4);
487 ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.TxData = Data;
488
489 ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = NULL;
490 ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = NULL;
491 ((EFI_UDP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
492
493 NetbufBuildExt (
494 Packet,
495 (NET_FRAGMENT *)((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentTable,
496 &Count
497 );
498
499 ((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentCount = Count;
500
501 if (EndPoint != NULL) {
502 Ip = HTONL (EndPoint->LocalAddr.Addr[0]);
503 CopyMem (
504 &TxToken->Session.Udp4.SourceAddress,
505 &Ip,
506 sizeof (EFI_IPv4_ADDRESS)
507 );
508
509 Ip = HTONL (EndPoint->RemoteAddr.Addr[0]);
510 CopyMem (
511 &TxToken->Session.Udp4.DestinationAddress,
512 &Ip,
513 sizeof (EFI_IPv4_ADDRESS)
514 );
515
516 TxToken->Session.Udp4.SourcePort = EndPoint->LocalPort;
517 TxToken->Session.Udp4.DestinationPort = EndPoint->RemotePort;
518 ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp4);
519 }
520
521 if (Gateway != NULL && (Gateway->Addr[0] != 0)) {
522 Ip = HTONL (Gateway->Addr[0]);
523 CopyMem (&TxToken->Gateway, &Ip, sizeof (EFI_IPv4_ADDRESS));
524 ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = &TxToken->Gateway;
525 }
526
527 } else {
528
529 ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;
530
531 Status = gBS->CreateEvent (
532 EVT_NOTIFY_SIGNAL,
533 TPL_NOTIFY,
534 UdpIoOnDgramSent,
535 TxToken,
536 &((EFI_UDP6_COMPLETION_TOKEN *) Token)->Event
537 );
538
539 if (EFI_ERROR (Status)) {
540 FreePool (TxToken);
541 return NULL;
542 }
543
544 Data = &(TxToken->Data.Udp6);
545 ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.TxData = Data;
546 ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = NULL;
547 ((EFI_UDP6_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
548
549 NetbufBuildExt (
550 Packet,
551 (NET_FRAGMENT *)((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentTable,
552 &Count
553 );
554
555 ((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentCount = Count;
556
557 if (EndPoint != NULL) {
558 CopyMem (
559 &TxToken->Session.Udp6.SourceAddress,
560 &EndPoint->LocalAddr.v6,
561 sizeof(EFI_IPv6_ADDRESS)
562 );
563
564 CopyMem (
565 &TxToken->Session.Udp6.DestinationAddress,
566 &EndPoint->RemoteAddr.v6,
567 sizeof(EFI_IPv6_ADDRESS)
568 );
569
570 TxToken->Session.Udp6.SourcePort = EndPoint->LocalPort;
571 TxToken->Session.Udp6.DestinationPort = EndPoint->RemotePort;
572 ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp6);
573 }
574 }
575
576 return TxToken;
577 }
578
579 /**
580 Creates a UDP_IO to access the UDP service. It creates and configures
581 a UDP child.
582
583 It locates the UDP service binding prototype on the Controller parameter
584 uses the UDP service binding prototype to create a UDP child (also known as
585 a UDP instance) configures the UDP child by calling Configure function prototype.
586 Any failures in creating or configuring the UDP child return NULL for failure.
587
588 @param[in] Controller The controller that has the UDP service binding.
589 protocol installed.
590 @param[in] ImageHandle The image handle for the driver.
591 @param[in] Configure The function to configure the created UDP child.
592 @param[in] UdpVersion The UDP protocol version, UDP4 or UDP6.
593 @param[in] Context The opaque parameter for the Configure funtion.
594
595 @return Newly-created UDP_IO or NULL if failed.
596
597 **/
598 UDP_IO *
599 EFIAPI
UdpIoCreateIo(IN EFI_HANDLE Controller,IN EFI_HANDLE ImageHandle,IN UDP_IO_CONFIG Configure,IN UINT8 UdpVersion,IN VOID * Context)600 UdpIoCreateIo (
601 IN EFI_HANDLE Controller,
602 IN EFI_HANDLE ImageHandle,
603 IN UDP_IO_CONFIG Configure,
604 IN UINT8 UdpVersion,
605 IN VOID *Context
606 )
607 {
608 UDP_IO *UdpIo;
609 EFI_STATUS Status;
610
611 ASSERT (Configure != NULL);
612 ASSERT ((UdpVersion == UDP_IO_UDP4_VERSION) || (UdpVersion == UDP_IO_UDP6_VERSION));
613
614 UdpIo = AllocatePool (sizeof (UDP_IO));
615
616 if (UdpIo == NULL) {
617 return NULL;
618 }
619
620 UdpIo->UdpVersion = UdpVersion;
621 UdpIo->Signature = UDP_IO_SIGNATURE;
622 InitializeListHead (&UdpIo->Link);
623 UdpIo->RefCnt = 1;
624
625 UdpIo->Controller = Controller;
626 UdpIo->Image = ImageHandle;
627
628 InitializeListHead (&UdpIo->SentDatagram);
629 UdpIo->RecvRequest = NULL;
630 UdpIo->UdpHandle = NULL;
631
632 if (UdpVersion == UDP_IO_UDP4_VERSION) {
633 //
634 // Create a UDP child then open and configure it
635 //
636 Status = NetLibCreateServiceChild (
637 Controller,
638 ImageHandle,
639 &gEfiUdp4ServiceBindingProtocolGuid,
640 &UdpIo->UdpHandle
641 );
642
643 if (EFI_ERROR (Status)) {
644 goto FREE_MEM;
645 }
646
647 Status = gBS->OpenProtocol (
648 UdpIo->UdpHandle,
649 &gEfiUdp4ProtocolGuid,
650 (VOID **) &UdpIo->Protocol.Udp4,
651 ImageHandle,
652 Controller,
653 EFI_OPEN_PROTOCOL_BY_DRIVER
654 );
655
656 if (EFI_ERROR (Status)) {
657 goto FREE_CHILD;
658 }
659
660 if (EFI_ERROR (Configure (UdpIo, Context))) {
661 goto CLOSE_PROTOCOL;
662 }
663
664 Status = UdpIo->Protocol.Udp4->GetModeData (
665 UdpIo->Protocol.Udp4,
666 NULL,
667 NULL,
668 NULL,
669 &UdpIo->SnpMode
670 );
671
672 if (EFI_ERROR (Status)) {
673 goto CLOSE_PROTOCOL;
674 }
675
676 } else {
677
678 Status = NetLibCreateServiceChild (
679 Controller,
680 ImageHandle,
681 &gEfiUdp6ServiceBindingProtocolGuid,
682 &UdpIo->UdpHandle
683 );
684
685 if (EFI_ERROR (Status)) {
686 goto FREE_MEM;
687 }
688
689 Status = gBS->OpenProtocol (
690 UdpIo->UdpHandle,
691 &gEfiUdp6ProtocolGuid,
692 (VOID **) &UdpIo->Protocol.Udp6,
693 ImageHandle,
694 Controller,
695 EFI_OPEN_PROTOCOL_BY_DRIVER
696 );
697
698 if (EFI_ERROR (Status)) {
699 goto FREE_CHILD;
700 }
701
702 if (EFI_ERROR (Configure (UdpIo, Context))) {
703 goto CLOSE_PROTOCOL;
704 }
705
706 Status = UdpIo->Protocol.Udp6->GetModeData (
707 UdpIo->Protocol.Udp6,
708 NULL,
709 NULL,
710 NULL,
711 &UdpIo->SnpMode
712 );
713
714 if (EFI_ERROR (Status)) {
715 goto CLOSE_PROTOCOL;
716 }
717 }
718
719 return UdpIo;
720
721 CLOSE_PROTOCOL:
722 if (UdpVersion == UDP_IO_UDP4_VERSION) {
723 gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp4ProtocolGuid, ImageHandle, Controller);
724 } else {
725 gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp6ProtocolGuid, ImageHandle, Controller);
726 }
727
728 FREE_CHILD:
729 if (UdpVersion == UDP_IO_UDP4_VERSION) {
730 NetLibDestroyServiceChild (
731 Controller,
732 ImageHandle,
733 &gEfiUdp4ServiceBindingProtocolGuid,
734 UdpIo->UdpHandle
735 );
736 } else {
737 NetLibDestroyServiceChild (
738 Controller,
739 ImageHandle,
740 &gEfiUdp6ServiceBindingProtocolGuid,
741 UdpIo->UdpHandle
742 );
743 }
744
745 FREE_MEM:
746 FreePool (UdpIo);
747 return NULL;
748 }
749
750 /**
751 Cancel all the sent datagram that pass the selection criteria of ToCancel.
752 If ToCancel is NULL, all the datagrams are cancelled.
753
754 @param[in] UdpIo The UDP_IO to cancel packet.
755 @param[in] IoStatus The IoStatus to return to the packet owners.
756 @param[in] ToCancel The select funtion to test whether to cancel this
757 packet or not.
758 @param[in] Context The opaque parameter to the ToCancel.
759
760 **/
761 VOID
762 EFIAPI
UdpIoCancelDgrams(IN UDP_IO * UdpIo,IN EFI_STATUS IoStatus,IN UDP_IO_TO_CANCEL ToCancel,OPTIONAL IN VOID * Context)763 UdpIoCancelDgrams (
764 IN UDP_IO *UdpIo,
765 IN EFI_STATUS IoStatus,
766 IN UDP_IO_TO_CANCEL ToCancel, OPTIONAL
767 IN VOID *Context
768 )
769 {
770 LIST_ENTRY *Entry;
771 LIST_ENTRY *Next;
772 UDP_TX_TOKEN *TxToken;
773
774 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
775 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
776
777 NET_LIST_FOR_EACH_SAFE (Entry, Next, &UdpIo->SentDatagram) {
778 TxToken = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link);
779
780 if ((ToCancel == NULL) || (ToCancel (TxToken, Context))) {
781
782 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
783 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);
784 } else {
785 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);
786 }
787 }
788 }
789 }
790
791 /**
792 Free the UDP_IO and all its related resources.
793
794 The function will cancel all sent datagram and receive request.
795
796 @param[in] UdpIo The UDP_IO to free.
797
798 @retval EFI_SUCCESS The UDP_IO is freed.
799
800 **/
801 EFI_STATUS
802 EFIAPI
UdpIoFreeIo(IN UDP_IO * UdpIo)803 UdpIoFreeIo (
804 IN UDP_IO *UdpIo
805 )
806 {
807 UDP_RX_TOKEN *RxToken;
808
809 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
810 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
811
812 //
813 // Cancel all the sent datagram and receive requests. The
814 // callbacks of transmit requests are executed to allow the
815 // caller to release the resource. The callback of receive
816 // request are NOT executed. This is because it is most
817 // likely that the current user of the UDP IO port is closing
818 // itself.
819 //
820 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
821
822 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
823
824 if ((RxToken = UdpIo->RecvRequest) != NULL) {
825 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
826 }
827
828 //
829 // Close then destroy the Udp4 child
830 //
831 gBS->CloseProtocol (
832 UdpIo->UdpHandle,
833 &gEfiUdp4ProtocolGuid,
834 UdpIo->Image,
835 UdpIo->Controller
836 );
837
838 NetLibDestroyServiceChild (
839 UdpIo->Controller,
840 UdpIo->Image,
841 &gEfiUdp4ServiceBindingProtocolGuid,
842 UdpIo->UdpHandle
843 );
844
845 } else {
846
847 if ((RxToken = UdpIo->RecvRequest) != NULL) {
848 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
849 }
850
851 //
852 // Close then destroy the Udp6 child
853 //
854 gBS->CloseProtocol (
855 UdpIo->UdpHandle,
856 &gEfiUdp6ProtocolGuid,
857 UdpIo->Image,
858 UdpIo->Controller
859 );
860
861 NetLibDestroyServiceChild (
862 UdpIo->Controller,
863 UdpIo->Image,
864 &gEfiUdp6ServiceBindingProtocolGuid,
865 UdpIo->UdpHandle
866 );
867 }
868
869 if (!IsListEmpty(&UdpIo->Link)) {
870 RemoveEntryList (&UdpIo->Link);
871 }
872
873 FreePool (UdpIo);
874 return EFI_SUCCESS;
875 }
876
877
878 /**
879 Clean up the UDP_IO without freeing it. The function is called when
880 user wants to re-use the UDP_IO later.
881
882 It will release all the transmitted datagrams and receive request. It will
883 also configure NULL for the UDP instance.
884
885 @param[in] UdpIo The UDP_IO to clean up.
886
887 **/
888 VOID
889 EFIAPI
UdpIoCleanIo(IN UDP_IO * UdpIo)890 UdpIoCleanIo (
891 IN UDP_IO *UdpIo
892 )
893 {
894 UDP_RX_TOKEN *RxToken;
895
896 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
897 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
898
899 //
900 // Cancel all the sent datagram and receive requests.
901 //
902 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
903
904 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
905 if ((RxToken = UdpIo->RecvRequest) != NULL) {
906 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
907 }
908
909 UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, NULL);
910
911 } else {
912 if ((RxToken = UdpIo->RecvRequest) != NULL) {
913 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
914 }
915
916 UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, NULL);
917 }
918 }
919
920 /**
921 Send a packet through the UDP_IO.
922
923 The packet will be wrapped in UDP_TX_TOKEN. Function Callback will be called
924 when the packet is sent. The optional parameter EndPoint overrides the default
925 address pair if specified.
926
927 @param[in] UdpIo The UDP_IO to send the packet through.
928 @param[in] Packet The packet to send.
929 @param[in] EndPoint The local and remote access point. Override the
930 default address pair set during configuration.
931 @param[in] Gateway The gateway to use.
932 @param[in] CallBack The function being called when packet is
933 transmitted or failed.
934 @param[in] Context The opaque parameter passed to CallBack.
935
936 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet.
937 @retval EFI_SUCCESS The packet is successfully delivered to UDP for
938 transmission.
939
940 **/
941 EFI_STATUS
942 EFIAPI
UdpIoSendDatagram(IN UDP_IO * UdpIo,IN NET_BUF * Packet,IN UDP_END_POINT * EndPoint OPTIONAL,IN EFI_IP_ADDRESS * Gateway OPTIONAL,IN UDP_IO_CALLBACK CallBack,IN VOID * Context)943 UdpIoSendDatagram (
944 IN UDP_IO *UdpIo,
945 IN NET_BUF *Packet,
946 IN UDP_END_POINT *EndPoint OPTIONAL,
947 IN EFI_IP_ADDRESS *Gateway OPTIONAL,
948 IN UDP_IO_CALLBACK CallBack,
949 IN VOID *Context
950 )
951 {
952 UDP_TX_TOKEN *TxToken;
953 EFI_STATUS Status;
954
955 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
956 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
957
958 TxToken = UdpIoCreateTxToken (UdpIo, Packet, EndPoint, Gateway, CallBack, Context);
959
960 if (TxToken == NULL) {
961 return EFI_OUT_OF_RESOURCES;
962 }
963
964 //
965 // Insert the tx token into SendDatagram list before transmitting it. Remove
966 // it from the list if the returned status is not EFI_SUCCESS.
967 //
968 InsertHeadList (&UdpIo->SentDatagram, &TxToken->Link);
969
970 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
971 Status = UdpIo->Protocol.Udp4->Transmit (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);
972 } else {
973 Status = UdpIo->Protocol.Udp6->Transmit (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);
974 }
975
976 if (EFI_ERROR (Status)) {
977 RemoveEntryList (&TxToken->Link);
978 UdpIoFreeTxToken (TxToken);
979 return Status;
980 }
981
982 return EFI_SUCCESS;
983 }
984
985
986 /**
987 The select function to cancel a single sent datagram.
988
989 @param[in] Token The UDP_TX_TOKEN to test against
990 @param[in] Context The NET_BUF of the sent datagram
991
992 @retval TRUE The packet is to be cancelled.
993 @retval FALSE The packet is not to be cancelled.
994 **/
995 BOOLEAN
996 EFIAPI
UdpIoCancelSingleDgram(IN UDP_TX_TOKEN * Token,IN VOID * Context)997 UdpIoCancelSingleDgram (
998 IN UDP_TX_TOKEN *Token,
999 IN VOID *Context
1000 )
1001 {
1002 NET_BUF *Packet;
1003
1004 Packet = (NET_BUF *) Context;
1005
1006 if (Token->Packet == Packet) {
1007 return TRUE;
1008 }
1009
1010 return FALSE;
1011 }
1012
1013 /**
1014 Cancel a single sent datagram.
1015
1016 @param[in] UdpIo The UDP_IO to cancel the packet from
1017 @param[in] Packet The packet to cancel
1018
1019 **/
1020 VOID
1021 EFIAPI
UdpIoCancelSentDatagram(IN UDP_IO * UdpIo,IN NET_BUF * Packet)1022 UdpIoCancelSentDatagram (
1023 IN UDP_IO *UdpIo,
1024 IN NET_BUF *Packet
1025 )
1026 {
1027 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet);
1028 }
1029
1030 /**
1031 Issue a receive request to the UDP_IO.
1032
1033 This function is called when upper-layer needs packet from UDP for processing.
1034 Only one receive request is acceptable at a time so a common usage model is
1035 to invoke this function inside its Callback function when the former packet
1036 is processed.
1037
1038 @param[in] UdpIo The UDP_IO to receive the packet from.
1039 @param[in] CallBack The call back function to execute when the packet
1040 is received.
1041 @param[in] Context The opaque context passed to Callback.
1042 @param[in] HeadLen The length of the upper-layer's protocol header.
1043
1044 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only
1045 one receive request is supported at a time.
1046 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
1047 @retval EFI_SUCCESS The receive request is issued successfully.
1048 @retval EFI_UNSUPPORTED The UDP version in UDP_IO is not supported.
1049
1050 **/
1051 EFI_STATUS
1052 EFIAPI
UdpIoRecvDatagram(IN UDP_IO * UdpIo,IN UDP_IO_CALLBACK CallBack,IN VOID * Context,IN UINT32 HeadLen)1053 UdpIoRecvDatagram (
1054 IN UDP_IO *UdpIo,
1055 IN UDP_IO_CALLBACK CallBack,
1056 IN VOID *Context,
1057 IN UINT32 HeadLen
1058 )
1059 {
1060 UDP_RX_TOKEN *RxToken;
1061 EFI_STATUS Status;
1062
1063 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
1064 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
1065
1066 if (UdpIo->RecvRequest != NULL) {
1067 return EFI_ALREADY_STARTED;
1068 }
1069
1070 RxToken = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);
1071
1072 if (RxToken == NULL) {
1073 return EFI_OUT_OF_RESOURCES;
1074 }
1075
1076 UdpIo->RecvRequest = RxToken;
1077 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
1078 Status = UdpIo->Protocol.Udp4->Receive (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
1079 } else {
1080 Status = UdpIo->Protocol.Udp6->Receive (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
1081 }
1082
1083 if (EFI_ERROR (Status)) {
1084 UdpIo->RecvRequest = NULL;
1085 UdpIoFreeRxToken (RxToken);
1086 }
1087
1088 return Status;
1089 }
1090