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