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