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 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 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 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 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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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