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