1 /** @file 2 Implement the UDP4 driver support for the socket layer. 3 4 Copyright (c) 2011 - 2015, Intel Corporation 5 All rights reserved. This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "Socket.h" 16 17 18 /** 19 Get the local socket address 20 21 This routine returns the IPv4 address and UDP port number associated 22 with the local socket. 23 24 This routine is called by ::EslSocketGetLocalAddress to determine the 25 network address for the SOCK_DGRAM socket. 26 27 @param [in] pPort Address of an ::ESL_PORT structure. 28 29 @param [out] pSockAddr Network address to receive the local system address 30 31 **/ 32 VOID 33 EslUdp4LocalAddressGet ( 34 IN ESL_PORT * pPort, 35 OUT struct sockaddr * pSockAddr 36 ) 37 { 38 struct sockaddr_in * pLocalAddress; 39 ESL_UDP4_CONTEXT * pUdp4; 40 41 DBG_ENTER ( ); 42 43 // 44 // Return the local address 45 // 46 pUdp4 = &pPort->Context.Udp4; 47 pLocalAddress = (struct sockaddr_in *)pSockAddr; 48 pLocalAddress->sin_family = AF_INET; 49 pLocalAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.StationPort ); 50 CopyMem ( &pLocalAddress->sin_addr, 51 &pUdp4->ConfigData.StationAddress.Addr[0], 52 sizeof ( pLocalAddress->sin_addr )); 53 54 DBG_EXIT ( ); 55 } 56 57 58 /** 59 Set the local port address. 60 61 This routine sets the local port address. 62 63 This support routine is called by ::EslSocketPortAllocate. 64 65 @param [in] pPort Address of an ESL_PORT structure 66 @param [in] pSockAddr Address of a sockaddr structure that contains the 67 connection point on the local machine. An IPv4 address 68 of INADDR_ANY specifies that the connection is made to 69 all of the network stacks on the platform. Specifying a 70 specific IPv4 address restricts the connection to the 71 network stack supporting that address. Specifying zero 72 for the port causes the network layer to assign a port 73 number from the dynamic range. Specifying a specific 74 port number causes the network layer to use that port. 75 76 @param [in] bBindTest TRUE = run bind testing 77 78 @retval EFI_SUCCESS The operation was successful 79 80 **/ 81 EFI_STATUS 82 EslUdp4LocalAddressSet ( 83 IN ESL_PORT * pPort, 84 IN CONST struct sockaddr * pSockAddr, 85 IN BOOLEAN bBindTest 86 ) 87 { 88 EFI_UDP4_CONFIG_DATA * pConfig; 89 CONST struct sockaddr_in * pIpAddress; 90 CONST UINT8 * pIpv4Address; 91 EFI_STATUS Status; 92 93 DBG_ENTER ( ); 94 95 // 96 // Validate the address 97 // 98 pIpAddress = (struct sockaddr_in *)pSockAddr; 99 if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) { 100 // 101 // The local address must not be the broadcast address 102 // 103 Status = EFI_INVALID_PARAMETER; 104 pPort->pSocket->errno = EADDRNOTAVAIL; 105 } 106 else { 107 // 108 // Set the local address 109 // 110 pIpAddress = (struct sockaddr_in *)pSockAddr; 111 pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr; 112 pConfig = &pPort->Context.Udp4.ConfigData; 113 pConfig->StationAddress.Addr[0] = pIpv4Address[0]; 114 pConfig->StationAddress.Addr[1] = pIpv4Address[1]; 115 pConfig->StationAddress.Addr[2] = pIpv4Address[2]; 116 pConfig->StationAddress.Addr[3] = pIpv4Address[3]; 117 118 // 119 // Determine if the default address is used 120 // 121 pConfig->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr ); 122 123 // 124 // Set the subnet mask 125 // 126 if ( pConfig->UseDefaultAddress ) { 127 pConfig->SubnetMask.Addr[0] = 0; 128 pConfig->SubnetMask.Addr[1] = 0; 129 pConfig->SubnetMask.Addr[2] = 0; 130 pConfig->SubnetMask.Addr[3] = 0; 131 } 132 else { 133 pConfig->SubnetMask.Addr[0] = 0xff; 134 pConfig->SubnetMask.Addr[1] = ( 128 <= pConfig->StationAddress.Addr[0]) ? 0xff : 0; 135 pConfig->SubnetMask.Addr[2] = ( 192 <= pConfig->StationAddress.Addr[0]) ? 0xff : 0; 136 pConfig->SubnetMask.Addr[3] = ( 224 <= pConfig->StationAddress.Addr[0]) ? 0xff : 0; 137 } 138 139 // 140 // Validate the IP address 141 // 142 pConfig->StationPort = 0; 143 Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL ) 144 : EFI_SUCCESS; 145 if ( !EFI_ERROR ( Status )) { 146 // 147 // Set the port number 148 // 149 pConfig->StationPort = SwapBytes16 ( pIpAddress->sin_port ); 150 151 // 152 // Display the local address 153 // 154 DEBUG (( DEBUG_BIND, 155 "0x%08x: Port, Local UDP4 Address: %d.%d.%d.%d:%d\r\n", 156 pPort, 157 pConfig->StationAddress.Addr[0], 158 pConfig->StationAddress.Addr[1], 159 pConfig->StationAddress.Addr[2], 160 pConfig->StationAddress.Addr[3], 161 pConfig->StationPort )); 162 } 163 } 164 165 // 166 // Return the operation status 167 // 168 DBG_EXIT_STATUS ( Status ); 169 return Status; 170 } 171 172 173 /** 174 Free a receive packet 175 176 This routine performs the network specific operations necessary 177 to free a receive packet. 178 179 This routine is called by ::EslSocketPortCloseTxDone to free a 180 receive packet. 181 182 @param [in] pPacket Address of an ::ESL_PACKET structure. 183 @param [in, out] pRxBytes Address of the count of RX bytes 184 185 **/ 186 VOID 187 EslUdp4PacketFree ( 188 IN ESL_PACKET * pPacket, 189 IN OUT size_t * pRxBytes 190 ) 191 { 192 EFI_UDP4_RECEIVE_DATA * pRxData; 193 194 DBG_ENTER ( ); 195 196 // 197 // Account for the receive bytes 198 // 199 pRxData = pPacket->Op.Udp4Rx.pRxData; 200 *pRxBytes -= pRxData->DataLength; 201 202 // 203 // Disconnect the buffer from the packet 204 // 205 pPacket->Op.Udp4Rx.pRxData = NULL; 206 207 // 208 // Return the buffer to the UDP4 driver 209 // 210 gBS->SignalEvent ( pRxData->RecycleSignal ); 211 DBG_EXIT ( ); 212 } 213 214 215 /** 216 Initialize the network specific portions of an ::ESL_PORT structure. 217 218 This routine initializes the network specific portions of an 219 ::ESL_PORT structure for use by the socket. 220 221 This support routine is called by ::EslSocketPortAllocate 222 to connect the socket with the underlying network adapter 223 running the UDPv4 protocol. 224 225 @param [in] pPort Address of an ESL_PORT structure 226 @param [in] DebugFlags Flags for debug messages 227 228 @retval EFI_SUCCESS - Socket successfully created 229 230 **/ 231 EFI_STATUS 232 EslUdp4PortAllocate ( 233 IN ESL_PORT * pPort, 234 IN UINTN DebugFlags 235 ) 236 { 237 EFI_UDP4_CONFIG_DATA * pConfig; 238 ESL_SOCKET * pSocket; 239 EFI_STATUS Status; 240 241 DBG_ENTER ( ); 242 243 // 244 // Initialize the port 245 // 246 pSocket = pPort->pSocket; 247 pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Udp4Tx.TxData ); 248 pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Tx.Event ); 249 pSocket->TxTokenOffset = OFFSET_OF ( EFI_UDP4_COMPLETION_TOKEN, Packet.TxData ); 250 251 // 252 // Save the cancel, receive and transmit addresses 253 // 254 pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.UDPv4->Configure; 255 pPort->pfnRxCancel = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Cancel; 256 pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.UDPv4->Poll; 257 pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Receive; 258 pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Transmit; 259 260 // 261 // Set the configuration flags 262 // 263 pConfig = &pPort->Context.Udp4.ConfigData; 264 pConfig->TimeToLive = 255; 265 pConfig->AcceptAnyPort = FALSE; 266 pConfig->AcceptBroadcast = FALSE; 267 pConfig->AcceptPromiscuous = FALSE; 268 pConfig->AllowDuplicatePort = TRUE; 269 pConfig->DoNotFragment = FALSE; 270 Status = EFI_SUCCESS; 271 272 // 273 // Return the operation status 274 // 275 DBG_EXIT_STATUS ( Status ); 276 return Status; 277 } 278 279 280 /** 281 Receive data from a network connection. 282 283 This routine attempts to return buffered data to the caller. The 284 data is removed from the urgent queue if the message flag MSG_OOB 285 is specified, otherwise data is removed from the normal queue. 286 See the \ref ReceiveEngine section. 287 288 This routine is called by ::EslSocketReceive to handle the network 289 specific receive operation to support SOCK_DGRAM sockets. 290 291 @param [in] pPort Address of an ::ESL_PORT structure. 292 293 @param [in] pPacket Address of an ::ESL_PACKET structure. 294 295 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed 296 297 @param [in] BufferLength Length of the the buffer 298 299 @param [in] pBuffer Address of a buffer to receive the data. 300 301 @param [in] pDataLength Number of received data bytes in the buffer. 302 303 @param [out] pAddress Network address to receive the remote system address 304 305 @param [out] pSkipBytes Address to receive the number of bytes skipped 306 307 @return Returns the address of the next free byte in the buffer. 308 309 **/ 310 UINT8 * 311 EslUdp4Receive ( 312 IN ESL_PORT * pPort, 313 IN ESL_PACKET * pPacket, 314 IN BOOLEAN * pbConsumePacket, 315 IN size_t BufferLength, 316 IN UINT8 * pBuffer, 317 OUT size_t * pDataLength, 318 OUT struct sockaddr * pAddress, 319 OUT size_t * pSkipBytes 320 ) 321 { 322 size_t DataBytes; 323 struct sockaddr_in * pRemoteAddress; 324 EFI_UDP4_RECEIVE_DATA * pRxData; 325 326 DBG_ENTER ( ); 327 328 pRxData = pPacket->Op.Udp4Rx.pRxData; 329 // 330 // Return the remote system address if requested 331 // 332 if ( NULL != pAddress ) { 333 // 334 // Build the remote address 335 // 336 DEBUG (( DEBUG_RX, 337 "Getting packet remote address: %d.%d.%d.%d:%d\r\n", 338 pRxData->UdpSession.SourceAddress.Addr[0], 339 pRxData->UdpSession.SourceAddress.Addr[1], 340 pRxData->UdpSession.SourceAddress.Addr[2], 341 pRxData->UdpSession.SourceAddress.Addr[3], 342 pRxData->UdpSession.SourcePort )); 343 pRemoteAddress = (struct sockaddr_in *)pAddress; 344 CopyMem ( &pRemoteAddress->sin_addr, 345 &pRxData->UdpSession.SourceAddress.Addr[0], 346 sizeof ( pRemoteAddress->sin_addr )); 347 pRemoteAddress->sin_port = SwapBytes16 ( pRxData->UdpSession.SourcePort ); 348 } 349 350 // 351 // Copy the received data 352 // 353 pBuffer = EslSocketCopyFragmentedBuffer ( pRxData->FragmentCount, 354 (EFI_IP4_FRAGMENT_DATA *)&pRxData->FragmentTable[0], 355 BufferLength, 356 pBuffer, 357 &DataBytes ); 358 359 // 360 // Determine if the data is being read 361 // 362 if ( *pbConsumePacket ) { 363 // 364 // Display for the bytes consumed 365 // 366 DEBUG (( DEBUG_RX, 367 "0x%08x: Port account for 0x%08x bytes\r\n", 368 pPort, 369 DataBytes )); 370 371 // 372 // Account for any discarded data 373 // 374 *pSkipBytes = pRxData->DataLength - DataBytes; 375 } 376 377 // 378 // Return the data length and the buffer address 379 // 380 *pDataLength = DataBytes; 381 DBG_EXIT_HEX ( pBuffer ); 382 return pBuffer; 383 } 384 385 386 /** 387 Get the remote socket address 388 389 This routine returns the address of the remote connection point 390 associated with the SOCK_DGRAM socket. 391 392 This routine is called by ::EslSocketGetPeerAddress to detemine 393 the UDPv4 address and port number associated with the network adapter. 394 395 @param [in] pPort Address of an ::ESL_PORT structure. 396 397 @param [out] pAddress Network address to receive the remote system address 398 399 **/ 400 VOID 401 EslUdp4RemoteAddressGet ( 402 IN ESL_PORT * pPort, 403 OUT struct sockaddr * pAddress 404 ) 405 { 406 struct sockaddr_in * pRemoteAddress; 407 ESL_UDP4_CONTEXT * pUdp4; 408 409 DBG_ENTER ( ); 410 411 // 412 // Return the remote address 413 // 414 pUdp4 = &pPort->Context.Udp4; 415 pRemoteAddress = (struct sockaddr_in *)pAddress; 416 pRemoteAddress->sin_family = AF_INET; 417 pRemoteAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.RemotePort ); 418 CopyMem ( &pRemoteAddress->sin_addr, 419 &pUdp4->ConfigData.RemoteAddress.Addr[0], 420 sizeof ( pRemoteAddress->sin_addr )); 421 422 DBG_EXIT ( ); 423 } 424 425 426 /** 427 Set the remote address 428 429 This routine sets the remote address in the port. 430 431 This routine is called by ::EslSocketConnect to specify the 432 remote network address. 433 434 @param [in] pPort Address of an ::ESL_PORT structure. 435 436 @param [in] pSockAddr Network address of the remote system. 437 438 @param [in] SockAddrLength Length in bytes of the network address. 439 440 @retval EFI_SUCCESS The operation was successful 441 442 **/ 443 EFI_STATUS 444 EslUdp4RemoteAddressSet ( 445 IN ESL_PORT * pPort, 446 IN CONST struct sockaddr * pSockAddr, 447 IN socklen_t SockAddrLength 448 ) 449 { 450 CONST struct sockaddr_in * pRemoteAddress; 451 ESL_UDP4_CONTEXT * pUdp4; 452 EFI_STATUS Status; 453 454 DBG_ENTER ( ); 455 456 // 457 // Set the remote address 458 // 459 pUdp4 = &pPort->Context.Udp4; 460 pRemoteAddress = (struct sockaddr_in *)pSockAddr; 461 pUdp4->ConfigData.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr ); 462 pUdp4->ConfigData.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 ); 463 pUdp4->ConfigData.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 ); 464 pUdp4->ConfigData.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 ); 465 pUdp4->ConfigData.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port ); 466 pPort->pSocket->bAddressSet = TRUE; 467 Status = EFI_SUCCESS; 468 469 // 470 // Return the operation status 471 // 472 DBG_EXIT_STATUS ( Status ); 473 return Status; 474 } 475 476 477 /** 478 Process the receive completion 479 480 This routine keeps the UDPv4 driver's buffer and queues it in 481 in FIFO order to the data queue. The UDP4 driver's buffer will 482 be returned by either ::EslUdp4Receive or ::EslSocketPortCloseTxDone. 483 See the \ref ReceiveEngine section. 484 485 This routine is called by the UDPv4 driver when data is 486 received. 487 488 @param [in] Event The receive completion event 489 490 @param [in] pIo Address of an ::ESL_IO_MGMT structure 491 492 **/ 493 VOID 494 EslUdp4RxComplete ( 495 IN EFI_EVENT Event, 496 IN ESL_IO_MGMT * pIo 497 ) 498 { 499 size_t LengthInBytes; 500 ESL_PACKET * pPacket; 501 EFI_UDP4_RECEIVE_DATA * pRxData; 502 EFI_STATUS Status; 503 504 DBG_ENTER ( ); 505 506 // 507 // Get the operation status. 508 // 509 Status = pIo->Token.Udp4Rx.Status; 510 511 // 512 // Get the packet length 513 // 514 pRxData = pIo->Token.Udp4Rx.Packet.RxData; 515 LengthInBytes = pRxData->DataLength; 516 517 // 518 // +--------------------+ +-----------------------+ 519 // | ESL_IO_MGMT | | Data Buffer | 520 // | | | (Driver owned) | 521 // | +---------------+ +-----------------------+ 522 // | | Token | ^ 523 // | | Rx Event | | 524 // | | | +-----------------------+ 525 // | | RxData --> | EFI_UDP4_RECEIVE_DATA | 526 // +----+---------------+ | (Driver owned) | 527 // +-----------------------+ 528 // +--------------------+ ^ 529 // | ESL_PACKET | . 530 // | | . 531 // | +---------------+ . 532 // | | pRxData --> NULL ....... 533 // +----+---------------+ 534 // 535 // 536 // Save the data in the packet 537 // 538 pPacket = pIo->pPacket; 539 pPacket->Op.Udp4Rx.pRxData = pRxData; 540 541 // 542 // Complete this request 543 // 544 EslSocketRxComplete ( pIo, Status, LengthInBytes, FALSE ); 545 DBG_EXIT ( ); 546 } 547 548 549 /** 550 Determine if the socket is configured. 551 552 This routine uses the flag ESL_SOCKET::bConfigured to determine 553 if the network layer's configuration routine has been called. 554 This routine calls the bind and configuration routines if they 555 were not already called. After the port is configured, the 556 \ref ReceiveEngine is started. 557 558 This routine is called by EslSocketIsConfigured to verify 559 that the socket is configured. 560 561 @param [in] pSocket Address of an ::ESL_SOCKET structure 562 563 @retval EFI_SUCCESS - The port is connected 564 @retval EFI_NOT_STARTED - The port is not connected 565 566 **/ 567 EFI_STATUS 568 EslUdp4SocketIsConfigured ( 569 IN ESL_SOCKET * pSocket 570 ) 571 { 572 EFI_UDP4_CONFIG_DATA * pConfigData; 573 ESL_PORT * pPort; 574 ESL_PORT * pNextPort; 575 ESL_UDP4_CONTEXT * pUdp4; 576 EFI_UDP4_PROTOCOL * pUdp4Protocol; 577 EFI_STATUS Status; 578 struct sockaddr_in LocalAddress; 579 580 DBG_ENTER ( ); 581 582 // 583 // Assume success 584 // 585 Status = EFI_SUCCESS; 586 587 // 588 // Configure the port if necessary 589 // 590 if ( !pSocket->bConfigured ) { 591 // 592 // Fill in the port list if necessary 593 // 594 pSocket->errno = ENETDOWN; 595 if ( NULL == pSocket->pPortList ) { 596 LocalAddress.sin_len = sizeof ( LocalAddress ); 597 LocalAddress.sin_family = AF_INET; 598 LocalAddress.sin_addr.s_addr = 0; 599 LocalAddress.sin_port = 0; 600 Status = EslSocketBind ( &pSocket->SocketProtocol, 601 (struct sockaddr *)&LocalAddress, 602 LocalAddress.sin_len, 603 &pSocket->errno ); 604 } 605 606 // 607 // Walk the port list 608 // 609 pPort = pSocket->pPortList; 610 while ( NULL != pPort ) { 611 // 612 // Attempt to configure the port 613 // 614 pNextPort = pPort->pLinkSocket; 615 pUdp4 = &pPort->Context.Udp4; 616 pUdp4Protocol = pPort->pProtocol.UDPv4; 617 pConfigData = &pUdp4->ConfigData; 618 DEBUG (( DEBUG_TX, 619 "0x%08x: pPort Configuring for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n", 620 pPort, 621 pConfigData->StationAddress.Addr[0], 622 pConfigData->StationAddress.Addr[1], 623 pConfigData->StationAddress.Addr[2], 624 pConfigData->StationAddress.Addr[3], 625 pConfigData->StationPort, 626 pConfigData->RemoteAddress.Addr[0], 627 pConfigData->RemoteAddress.Addr[1], 628 pConfigData->RemoteAddress.Addr[2], 629 pConfigData->RemoteAddress.Addr[3], 630 pConfigData->RemotePort )); 631 Status = pUdp4Protocol->Configure ( pUdp4Protocol, 632 pConfigData ); 633 if ( !EFI_ERROR ( Status )) { 634 // 635 // Update the configuration data 636 // 637 Status = pUdp4Protocol->GetModeData ( pUdp4Protocol, 638 pConfigData, 639 NULL, 640 NULL, 641 NULL ); 642 } 643 if ( EFI_ERROR ( Status )) { 644 if ( !pSocket->bConfigured ) { 645 DEBUG (( DEBUG_LISTEN, 646 "ERROR - Failed to configure the Udp4 port, Status: %r\r\n", 647 Status )); 648 switch ( Status ) { 649 case EFI_ACCESS_DENIED: 650 pSocket->errno = EACCES; 651 break; 652 653 default: 654 case EFI_DEVICE_ERROR: 655 pSocket->errno = EIO; 656 break; 657 658 case EFI_INVALID_PARAMETER: 659 pSocket->errno = EADDRNOTAVAIL; 660 break; 661 662 case EFI_NO_MAPPING: 663 pSocket->errno = EAFNOSUPPORT; 664 break; 665 666 case EFI_OUT_OF_RESOURCES: 667 pSocket->errno = ENOBUFS; 668 break; 669 670 case EFI_UNSUPPORTED: 671 pSocket->errno = EOPNOTSUPP; 672 break; 673 } 674 } 675 } 676 else { 677 DEBUG (( DEBUG_TX, 678 "0x%08x: pPort Configured for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n", 679 pPort, 680 pConfigData->StationAddress.Addr[0], 681 pConfigData->StationAddress.Addr[1], 682 pConfigData->StationAddress.Addr[2], 683 pConfigData->StationAddress.Addr[3], 684 pConfigData->StationPort, 685 pConfigData->RemoteAddress.Addr[0], 686 pConfigData->RemoteAddress.Addr[1], 687 pConfigData->RemoteAddress.Addr[2], 688 pConfigData->RemoteAddress.Addr[3], 689 pConfigData->RemotePort )); 690 pPort->bConfigured = TRUE; 691 pSocket->bConfigured = TRUE; 692 693 // 694 // Start the first read on the port 695 // 696 EslSocketRxStart ( pPort ); 697 698 // 699 // The socket is connected 700 // 701 pSocket->State = SOCKET_STATE_CONNECTED; 702 pSocket->errno = 0; 703 } 704 705 // 706 // Set the next port 707 // 708 pPort = pNextPort; 709 } 710 } 711 712 // 713 // Determine the socket configuration status 714 // 715 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED; 716 717 // 718 // Return the port connected state. 719 // 720 DBG_EXIT_STATUS ( Status ); 721 return Status; 722 } 723 724 725 /** 726 Buffer data for transmission over a network connection. 727 728 This routine buffers data for the transmit engine in the normal 729 data queue. When the \ref TransmitEngine has resources, this 730 routine will start the transmission of the next buffer on the 731 network connection. 732 733 This routine is called by ::EslSocketTransmit to buffer 734 data for transmission. The data is copied into a local buffer 735 freeing the application buffer for reuse upon return. When 736 necessary, this routine starts the transmit engine that 737 performs the data transmission on the network connection. The 738 transmit engine transmits the data a packet at a time over the 739 network connection. 740 741 Transmission errors are returned during the next transmission or 742 during the close operation. Only buffering errors are returned 743 during the current transmission attempt. 744 745 @param [in] pSocket Address of an ::ESL_SOCKET structure 746 747 @param [in] Flags Message control flags 748 749 @param [in] BufferLength Length of the the buffer 750 751 @param [in] pBuffer Address of a buffer to receive the data. 752 753 @param [in] pDataLength Number of received data bytes in the buffer. 754 755 @param [in] pAddress Network address of the remote system address 756 757 @param [in] AddressLength Length of the remote network address structure 758 759 @retval EFI_SUCCESS - Socket data successfully buffered 760 761 **/ 762 EFI_STATUS 763 EslUdp4TxBuffer ( 764 IN ESL_SOCKET * pSocket, 765 IN int Flags, 766 IN size_t BufferLength, 767 IN CONST UINT8 * pBuffer, 768 OUT size_t * pDataLength, 769 IN const struct sockaddr * pAddress, 770 IN socklen_t AddressLength 771 ) 772 { 773 ESL_PACKET * pPacket; 774 ESL_PACKET * pPreviousPacket; 775 ESL_PORT * pPort; 776 const struct sockaddr_in * pRemoteAddress; 777 ESL_UDP4_CONTEXT * pUdp4; 778 size_t * pTxBytes; 779 ESL_UDP4_TX_DATA * pTxData; 780 EFI_STATUS Status; 781 EFI_TPL TplPrevious; 782 783 DBG_ENTER ( ); 784 785 // 786 // Assume failure 787 // 788 Status = EFI_UNSUPPORTED; 789 pSocket->errno = ENOTCONN; 790 *pDataLength = 0; 791 792 // 793 // Verify that the socket is connected 794 // 795 if ( SOCKET_STATE_CONNECTED == pSocket->State ) { 796 // 797 // Verify that there is enough room to buffer another 798 // transmit operation 799 // 800 pTxBytes = &pSocket->TxBytes; 801 if ( pSocket->MaxTxBuf > *pTxBytes ) { 802 // 803 // Locate the port 804 // 805 pPort = pSocket->pPortList; 806 while ( NULL != pPort ) { 807 // 808 // Determine the queue head 809 // 810 pUdp4 = &pPort->Context.Udp4; 811 812 // 813 // Attempt to allocate the packet 814 // 815 Status = EslSocketPacketAllocate ( &pPacket, 816 sizeof ( pPacket->Op.Udp4Tx ) 817 - sizeof ( pPacket->Op.Udp4Tx.Buffer ) 818 + BufferLength, 819 0, 820 DEBUG_TX ); 821 if ( !EFI_ERROR ( Status )) { 822 // 823 // Initialize the transmit operation 824 // 825 pTxData = &pPacket->Op.Udp4Tx; 826 pTxData->TxData.GatewayAddress = NULL; 827 pTxData->TxData.UdpSessionData = NULL; 828 pTxData->TxData.DataLength = (UINT32) BufferLength; 829 pTxData->TxData.FragmentCount = 1; 830 pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength; 831 pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Udp4Tx.Buffer[0]; 832 pTxData->RetransmitCount = 0; 833 834 // 835 // Set the remote system address if necessary 836 // 837 pTxData->TxData.UdpSessionData = NULL; 838 if ( NULL != pAddress ) { 839 pRemoteAddress = (const struct sockaddr_in *)pAddress; 840 pTxData->Session.SourceAddress.Addr[0] = pUdp4->ConfigData.StationAddress.Addr[0]; 841 pTxData->Session.SourceAddress.Addr[1] = pUdp4->ConfigData.StationAddress.Addr[1]; 842 pTxData->Session.SourceAddress.Addr[2] = pUdp4->ConfigData.StationAddress.Addr[2]; 843 pTxData->Session.SourceAddress.Addr[3] = pUdp4->ConfigData.StationAddress.Addr[3]; 844 pTxData->Session.SourcePort = 0; 845 pTxData->Session.DestinationAddress.Addr[0] = (UINT8)pRemoteAddress->sin_addr.s_addr; 846 pTxData->Session.DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 ); 847 pTxData->Session.DestinationAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 ); 848 pTxData->Session.DestinationAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 ); 849 pTxData->Session.DestinationPort = SwapBytes16 ( pRemoteAddress->sin_port ); 850 851 // 852 // Use the remote system address when sending this packet 853 // 854 pTxData->TxData.UdpSessionData = &pTxData->Session; 855 } 856 857 // 858 // Copy the data into the buffer 859 // 860 CopyMem ( &pPacket->Op.Udp4Tx.Buffer[0], 861 pBuffer, 862 BufferLength ); 863 864 // 865 // Synchronize with the socket layer 866 // 867 RAISE_TPL ( TplPrevious, TPL_SOCKETS ); 868 869 // 870 // Display the request 871 // 872 DEBUG (( DEBUG_TX, 873 "Send %d bytes from 0x%08x to %d.%d.%d.%d:%d\r\n", 874 BufferLength, 875 pBuffer, 876 pTxData->Session.DestinationAddress.Addr[0], 877 pTxData->Session.DestinationAddress.Addr[1], 878 pTxData->Session.DestinationAddress.Addr[2], 879 pTxData->Session.DestinationAddress.Addr[3], 880 pTxData->Session.DestinationPort )); 881 882 // 883 // Queue the data for transmission 884 // 885 pPacket->pNext = NULL; 886 pPreviousPacket = pSocket->pTxPacketListTail; 887 if ( NULL == pPreviousPacket ) { 888 pSocket->pTxPacketListHead = pPacket; 889 } 890 else { 891 pPreviousPacket->pNext = pPacket; 892 } 893 pSocket->pTxPacketListTail = pPacket; 894 DEBUG (( DEBUG_TX, 895 "0x%08x: Packet on transmit list\r\n", 896 pPacket )); 897 898 // 899 // Account for the buffered data 900 // 901 *pTxBytes += BufferLength; 902 *pDataLength = BufferLength; 903 904 // 905 // Start the transmit engine if it is idle 906 // 907 if ( NULL != pPort->pTxFree ) { 908 pPacket = pSocket->pTxPacketListHead; 909 EslSocketTxStart ( pPort, 910 &pSocket->pTxPacketListHead, 911 &pSocket->pTxPacketListTail, 912 &pPort->pTxActive, 913 &pPort->pTxFree ); 914 915 // 916 // Ignore any transmit error 917 // 918 if ( EFI_ERROR ( pSocket->TxError )) { 919 DEBUG (( DEBUG_TX, 920 "0x%08x: Transmit error, Packet: 0x%08x, Status: %r\r\n", 921 pPort, 922 pPacket, 923 pSocket->TxError )); 924 } 925 pSocket->TxError = EFI_SUCCESS; 926 } 927 928 // 929 // Release the socket layer synchronization 930 // 931 RESTORE_TPL ( TplPrevious ); 932 } 933 else { 934 // 935 // Packet allocation failed 936 // 937 pSocket->errno = ENOMEM; 938 break; 939 } 940 941 // 942 // Set the next port 943 // 944 pPort = pPort->pLinkSocket; 945 } 946 } 947 else { 948 // 949 // Not enough buffer space available 950 // 951 pSocket->errno = EAGAIN; 952 Status = EFI_NOT_READY; 953 } 954 } 955 956 // 957 // Return the operation status 958 // 959 DBG_EXIT_STATUS ( Status ); 960 return Status; 961 } 962 963 964 /** 965 Process the transmit completion 966 967 This routine use ::EslSocketTxComplete to perform the transmit 968 completion processing for data packets. 969 970 This routine is called by the UDPv4 network layer when a data 971 transmit request completes. 972 973 @param [in] Event The normal transmit completion event 974 975 @param [in] pIo Address of an ::ESL_IO_MGMT structure 976 977 **/ 978 VOID 979 EslUdp4TxComplete ( 980 IN EFI_EVENT Event, 981 IN ESL_IO_MGMT * pIo 982 ) 983 { 984 UINT32 LengthInBytes; 985 ESL_PORT * pPort; 986 ESL_PACKET * pPacket; 987 ESL_SOCKET * pSocket; 988 EFI_STATUS Status; 989 990 DBG_ENTER ( ); 991 992 // 993 // Locate the active transmit packet 994 // 995 pPacket = pIo->pPacket; 996 pPort = pIo->pPort; 997 pSocket = pPort->pSocket; 998 999 // 1000 // Get the transmit length and status 1001 // 1002 LengthInBytes = pPacket->Op.Udp4Tx.TxData.DataLength; 1003 pSocket->TxBytes -= LengthInBytes; 1004 Status = pIo->Token.Udp4Tx.Status; 1005 1006 // 1007 // Ignore the transmit error 1008 // 1009 if ( EFI_ERROR ( Status )) { 1010 DEBUG (( DEBUG_TX, 1011 "0x%08x: Transmit completion error, Packet: 0x%08x, Status: %r\r\n", 1012 pPort, 1013 pPacket, 1014 Status )); 1015 Status = EFI_SUCCESS; 1016 } 1017 1018 // 1019 // Complete the transmit operation 1020 // 1021 EslSocketTxComplete ( pIo, 1022 LengthInBytes, 1023 Status, 1024 "UDP ", 1025 &pSocket->pTxPacketListHead, 1026 &pSocket->pTxPacketListTail, 1027 &pPort->pTxActive, 1028 &pPort->pTxFree ); 1029 DBG_EXIT ( ); 1030 } 1031 1032 1033 /** 1034 Verify the adapter's IP address 1035 1036 This support routine is called by EslSocketBindTest. 1037 1038 @param [in] pPort Address of an ::ESL_PORT structure. 1039 @param [in] pConfigData Address of the configuration data 1040 1041 @retval EFI_SUCCESS - The IP address is valid 1042 @retval EFI_NOT_STARTED - The IP address is invalid 1043 1044 **/ 1045 EFI_STATUS 1046 EslUdp4VerifyLocalIpAddress ( 1047 IN ESL_PORT * pPort, 1048 IN EFI_UDP4_CONFIG_DATA * pConfigData 1049 ) 1050 { 1051 UINTN DataSize; 1052 EFI_IP4_CONFIG2_INTERFACE_INFO * pIfInfo; 1053 EFI_IP4_CONFIG2_PROTOCOL * pIpConfig2Protocol; 1054 ESL_SERVICE * pService; 1055 EFI_STATUS Status; 1056 1057 DBG_ENTER ( ); 1058 1059 // 1060 // Use break instead of goto 1061 // 1062 pIfInfo = NULL; 1063 for ( ; ; ) { 1064 // 1065 // Determine if the IP address is specified 1066 // 1067 DEBUG (( DEBUG_BIND, 1068 "UseDefaultAddress: %s\r\n", 1069 pConfigData->UseDefaultAddress ? L"TRUE" : L"FALSE" )); 1070 DEBUG (( DEBUG_BIND, 1071 "Requested IP address: %d.%d.%d.%d\r\n", 1072 pConfigData->StationAddress.Addr [ 0 ], 1073 pConfigData->StationAddress.Addr [ 1 ], 1074 pConfigData->StationAddress.Addr [ 2 ], 1075 pConfigData->StationAddress.Addr [ 3 ])); 1076 if ( pConfigData->UseDefaultAddress 1077 || (( 0 == pConfigData->StationAddress.Addr [ 0 ]) 1078 && ( 0 == pConfigData->StationAddress.Addr [ 1 ]) 1079 && ( 0 == pConfigData->StationAddress.Addr [ 2 ]) 1080 && ( 0 == pConfigData->StationAddress.Addr [ 3 ]))) 1081 { 1082 Status = EFI_SUCCESS; 1083 break; 1084 } 1085 1086 // 1087 // Open the configuration protocol 1088 // 1089 pService = pPort->pService; 1090 Status = gBS->OpenProtocol ( 1091 pService->Controller, 1092 &gEfiIp4Config2ProtocolGuid, 1093 (VOID **)&pIpConfig2Protocol, 1094 NULL, 1095 NULL, 1096 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1097 ); 1098 if ( EFI_ERROR ( Status )) { 1099 DEBUG (( DEBUG_ERROR, 1100 "ERROR - IP Configuration Protocol not available, Status: %r\r\n", 1101 Status )); 1102 break; 1103 } 1104 1105 // 1106 // Get the interface information size 1107 // 1108 DataSize = 0; 1109 Status = pIpConfig2Protocol->GetData ( 1110 pIpConfig2Protocol, 1111 Ip4Config2DataTypeInterfaceInfo, 1112 &DataSize, 1113 NULL 1114 ); 1115 if ( EFI_BUFFER_TOO_SMALL != Status ) { 1116 DEBUG (( DEBUG_ERROR, 1117 "ERROR - Failed to get the interface information size, Status: %r\r\n", 1118 Status )); 1119 break; 1120 } 1121 1122 // 1123 // Allocate the interface information buffer 1124 // 1125 pIfInfo = AllocatePool ( DataSize ); 1126 if ( NULL == pIfInfo ) { 1127 DEBUG (( DEBUG_ERROR, 1128 "ERROR - Not enough memory to allocate the interface information buffer!\r\n" )); 1129 Status = EFI_OUT_OF_RESOURCES; 1130 break; 1131 } 1132 1133 // 1134 // Get the interface info. 1135 // 1136 Status = pIpConfig2Protocol->GetData ( 1137 pIpConfig2Protocol, 1138 Ip4Config2DataTypeInterfaceInfo, 1139 &DataSize, 1140 pIfInfo 1141 ); 1142 if ( EFI_ERROR ( Status )) { 1143 DEBUG (( DEBUG_ERROR, 1144 "ERROR - Failed to return the interface info, Status: %r\r\n", 1145 Status )); 1146 break; 1147 } 1148 1149 // 1150 // Display the current configuration 1151 // 1152 DEBUG (( DEBUG_BIND, 1153 "Actual adapter IP address: %d.%d.%d.%d\r\n", 1154 pIfInfo->StationAddress.Addr [ 0 ], 1155 pIfInfo->StationAddress.Addr [ 1 ], 1156 pIfInfo->StationAddress.Addr [ 2 ], 1157 pIfInfo->StationAddress.Addr [ 3 ])); 1158 1159 // 1160 // Assume the port is not configured 1161 // 1162 Status = EFI_SUCCESS; 1163 if (( pConfigData->StationAddress.Addr [ 0 ] == pIfInfo->StationAddress.Addr [ 0 ]) 1164 && ( pConfigData->StationAddress.Addr [ 1 ] == pIfInfo->StationAddress.Addr [ 1 ]) 1165 && ( pConfigData->StationAddress.Addr [ 2 ] == pIfInfo->StationAddress.Addr [ 2 ]) 1166 && ( pConfigData->StationAddress.Addr [ 3 ] == pIfInfo->StationAddress.Addr [ 3 ])) { 1167 break; 1168 } 1169 1170 // 1171 // The IP address did not match 1172 // 1173 Status = EFI_NOT_STARTED; 1174 break; 1175 } 1176 1177 // 1178 // Free the buffer if necessary 1179 // 1180 if ( NULL != pIfInfo ) { 1181 FreePool ( pIfInfo ); 1182 } 1183 1184 // 1185 // Return the IP address status 1186 // 1187 DBG_EXIT_STATUS ( Status ); 1188 return Status; 1189 } 1190 1191 1192 /** 1193 Interface between the socket layer and the network specific 1194 code that supports SOCK_DGRAM sockets over UDPv4. 1195 **/ 1196 CONST ESL_PROTOCOL_API cEslUdp4Api = { 1197 "UDPv4", 1198 IPPROTO_UDP, 1199 OFFSET_OF ( ESL_PORT, Context.Udp4.ConfigData ), 1200 OFFSET_OF ( ESL_LAYER, pUdp4List ), 1201 OFFSET_OF ( struct sockaddr_in, sin_zero ), 1202 sizeof ( struct sockaddr_in ), 1203 AF_INET, 1204 sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ), 1205 sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ), 1206 OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Rx.Packet.RxData ), 1207 FALSE, 1208 EADDRINUSE, 1209 NULL, // Accept 1210 NULL, // ConnectPoll 1211 NULL, // ConnectStart 1212 EslUdp4SocketIsConfigured, 1213 EslUdp4LocalAddressGet, 1214 EslUdp4LocalAddressSet, 1215 NULL, // Listen 1216 NULL, // OptionGet 1217 NULL, // OptionSet 1218 EslUdp4PacketFree, 1219 EslUdp4PortAllocate, 1220 NULL, // PortClose, 1221 NULL, // PortCloseOp 1222 TRUE, 1223 EslUdp4Receive, 1224 EslUdp4RemoteAddressGet, 1225 EslUdp4RemoteAddressSet, 1226 EslUdp4RxComplete, 1227 NULL, // RxStart 1228 EslUdp4TxBuffer, 1229 EslUdp4TxComplete, 1230 NULL, // TxOobComplete 1231 (PFN_API_VERIFY_LOCAL_IP_ADDRESS)EslUdp4VerifyLocalIpAddress 1232 }; 1233