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