]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/EfiSocketLib/Udp4.c
Merged socket development branch
[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
134 pConfig->SubnetMask.Addr[1] = 0xff;\r
135 pConfig->SubnetMask.Addr[2] = 0xff;\r
136 pConfig->SubnetMask.Addr[3] = 0xff;\r
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
256 pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Receive;\r
257 pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Transmit;\r
d7ce7006 258\r
a88c3163 259 //\r
260 // Set the configuration flags\r
261 //\r
262 pConfig = &pPort->Context.Udp4.ConfigData;\r
263 pConfig->TimeToLive = 255;\r
264 pConfig->AcceptAnyPort = FALSE;\r
265 pConfig->AcceptBroadcast = FALSE;\r
266 pConfig->AcceptPromiscuous = FALSE;\r
267 pConfig->AllowDuplicatePort = TRUE;\r
268 pConfig->DoNotFragment = TRUE;\r
269 Status = EFI_SUCCESS;\r
d7ce7006 270\r
271 //\r
272 // Return the operation status\r
273 //\r
274 DBG_EXIT_STATUS ( Status );\r
275 return Status;\r
276}\r
277\r
278\r
279/**\r
a88c3163 280 Receive data from a network connection.\r
d7ce7006 281\r
a88c3163 282 This routine attempts to return buffered data to the caller. The\r
283 data is removed from the urgent queue if the message flag MSG_OOB\r
284 is specified, otherwise data is removed from the normal queue.\r
285 See the \ref ReceiveEngine section.\r
d7ce7006 286\r
a88c3163 287 This routine is called by ::EslSocketReceive to handle the network\r
288 specific receive operation to support SOCK_DGRAM sockets.\r
d7ce7006 289\r
a88c3163 290 @param [in] pPort Address of an ::ESL_PORT structure.\r
d7ce7006 291\r
a88c3163 292 @param [in] pPacket Address of an ::ESL_PACKET structure.\r
d7ce7006 293 \r
a88c3163 294 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed\r
d7ce7006 295 \r
d7ce7006 296 @param [in] BufferLength Length of the the buffer\r
a88c3163 297 \r
d7ce7006 298 @param [in] pBuffer Address of a buffer to receive the data.\r
a88c3163 299 \r
d7ce7006 300 @param [in] pDataLength Number of received data bytes in the buffer.\r
301\r
302 @param [out] pAddress Network address to receive the remote system address\r
303\r
a88c3163 304 @param [out] pSkipBytes Address to receive the number of bytes skipped\r
d7ce7006 305\r
a88c3163 306 @return Returns the address of the next free byte in the buffer.\r
d7ce7006 307\r
308 **/\r
a88c3163 309UINT8 *\r
310EslUdp4Receive (\r
311 IN ESL_PORT * pPort,\r
312 IN ESL_PACKET * pPacket,\r
313 IN BOOLEAN * pbConsumePacket,\r
314 IN size_t BufferLength,\r
315 IN UINT8 * pBuffer,\r
316 OUT size_t * pDataLength,\r
317 OUT struct sockaddr * pAddress,\r
318 OUT size_t * pSkipBytes\r
d7ce7006 319 )\r
320{\r
a88c3163 321 size_t DataBytes;\r
322 struct sockaddr_in * pRemoteAddress;\r
323 EFI_UDP4_RECEIVE_DATA * pRxData;\r
d7ce7006 324\r
325 DBG_ENTER ( );\r
326\r
a88c3163 327 pRxData = pPacket->Op.Udp4Rx.pRxData;\r
d7ce7006 328 //\r
a88c3163 329 // Return the remote system address if requested\r
330 //\r
331 if ( NULL != pAddress ) {\r
332 //\r
333 // Build the remote address\r
334 //\r
335 DEBUG (( DEBUG_RX,\r
336 "Getting packet remote address: %d.%d.%d.%d:%d\r\n",\r
337 pRxData->UdpSession.SourceAddress.Addr[0],\r
338 pRxData->UdpSession.SourceAddress.Addr[1],\r
339 pRxData->UdpSession.SourceAddress.Addr[2],\r
340 pRxData->UdpSession.SourceAddress.Addr[3],\r
341 pRxData->UdpSession.SourcePort ));\r
342 pRemoteAddress = (struct sockaddr_in *)pAddress;\r
343 CopyMem ( &pRemoteAddress->sin_addr,\r
344 &pRxData->UdpSession.SourceAddress.Addr[0],\r
345 sizeof ( pRemoteAddress->sin_addr ));\r
346 pRemoteAddress->sin_port = SwapBytes16 ( pRxData->UdpSession.SourcePort );\r
347 }\r
348\r
d7ce7006 349 //\r
a88c3163 350 // Copy the received data\r
351 //\r
352 pBuffer = EslSocketCopyFragmentedBuffer ( pRxData->FragmentCount,\r
353 (EFI_IP4_FRAGMENT_DATA *)&pRxData->FragmentTable[0],\r
354 BufferLength,\r
355 pBuffer,\r
356 &DataBytes );\r
d7ce7006 357\r
358 //\r
a88c3163 359 // Determine if the data is being read\r
d7ce7006 360 //\r
a88c3163 361 if ( *pbConsumePacket ) {\r
d7ce7006 362 //\r
a88c3163 363 // Display for the bytes consumed\r
d7ce7006 364 //\r
a88c3163 365 DEBUG (( DEBUG_RX,\r
366 "0x%08x: Port account for 0x%08x bytes\r\n",\r
367 pPort,\r
368 DataBytes ));\r
369\r
370 //\r
371 // Account for any discarded data\r
372 //\r
373 *pSkipBytes = pRxData->DataLength - DataBytes;\r
d7ce7006 374 }\r
375\r
376 //\r
a88c3163 377 // Return the data length and the buffer address\r
d7ce7006 378 //\r
a88c3163 379 *pDataLength = DataBytes;\r
380 DBG_EXIT_HEX ( pBuffer );\r
381 return pBuffer;\r
d7ce7006 382}\r
383\r
384\r
385/**\r
a88c3163 386 Get the remote socket address\r
d7ce7006 387\r
a88c3163 388 This routine returns the address of the remote connection point\r
389 associated with the SOCK_DGRAM socket.\r
d7ce7006 390\r
a88c3163 391 This routine is called by ::EslSocketGetPeerAddress to detemine\r
392 the UDPv4 address and port number associated with the network adapter.\r
d7ce7006 393\r
a88c3163 394 @param [in] pPort Address of an ::ESL_PORT structure.\r
395\r
396 @param [out] pAddress Network address to receive the remote system address\r
d7ce7006 397\r
398**/\r
399VOID\r
a88c3163 400EslUdp4RemoteAddressGet (\r
401 IN ESL_PORT * pPort,\r
402 OUT struct sockaddr * pAddress\r
d7ce7006 403 )\r
404{\r
a88c3163 405 struct sockaddr_in * pRemoteAddress;\r
406 ESL_UDP4_CONTEXT * pUdp4;\r
407\r
d7ce7006 408 DBG_ENTER ( );\r
a88c3163 409\r
d7ce7006 410 //\r
a88c3163 411 // Return the remote address\r
d7ce7006 412 //\r
413 pUdp4 = &pPort->Context.Udp4;\r
a88c3163 414 pRemoteAddress = (struct sockaddr_in *)pAddress;\r
415 pRemoteAddress->sin_family = AF_INET;\r
416 pRemoteAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.RemotePort );\r
417 CopyMem ( &pRemoteAddress->sin_addr,\r
418 &pUdp4->ConfigData.RemoteAddress.Addr[0],\r
419 sizeof ( pRemoteAddress->sin_addr ));\r
d7ce7006 420\r
a88c3163 421 DBG_EXIT ( );\r
422}\r
d7ce7006 423\r
d7ce7006 424\r
a88c3163 425/**\r
426 Set the remote address\r
d7ce7006 427\r
a88c3163 428 This routine sets the remote address in the port.\r
d7ce7006 429\r
a88c3163 430 This routine is called by ::EslSocketConnect to specify the\r
431 remote network address.\r
d7ce7006 432\r
a88c3163 433 @param [in] pPort Address of an ::ESL_PORT structure.\r
d7ce7006 434\r
a88c3163 435 @param [in] pSockAddr Network address of the remote system.\r
436\r
437 @param [in] SockAddrLength Length in bytes of the network address.\r
d7ce7006 438\r
a88c3163 439 @retval EFI_SUCCESS The operation was successful\r
d7ce7006 440\r
441 **/\r
a88c3163 442EFI_STATUS\r
443EslUdp4RemoteAddressSet (\r
444 IN ESL_PORT * pPort,\r
445 IN CONST struct sockaddr * pSockAddr,\r
446 IN socklen_t SockAddrLength\r
d7ce7006 447 )\r
448{\r
a88c3163 449 CONST struct sockaddr_in * pRemoteAddress;\r
450 ESL_UDP4_CONTEXT * pUdp4;\r
d7ce7006 451 EFI_STATUS Status;\r
452\r
453 DBG_ENTER ( );\r
454\r
455 //\r
a88c3163 456 // Set the remote address\r
d7ce7006 457 //\r
d7ce7006 458 pUdp4 = &pPort->Context.Udp4;\r
a88c3163 459 pRemoteAddress = (struct sockaddr_in *)pSockAddr;\r
460 pUdp4->ConfigData.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );\r
461 pUdp4->ConfigData.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );\r
462 pUdp4->ConfigData.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );\r
463 pUdp4->ConfigData.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );\r
464 pUdp4->ConfigData.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );\r
465 Status = EFI_SUCCESS;\r
d7ce7006 466\r
a88c3163 467 //\r
468 // Return the operation status\r
469 //\r
470 DBG_EXIT_STATUS ( Status );\r
471 return Status;\r
d7ce7006 472}\r
473\r
474\r
475/**\r
a88c3163 476 Process the receive completion\r
d7ce7006 477\r
a88c3163 478 This routine keeps the UDPv4 driver's buffer and queues it in\r
479 in FIFO order to the data queue. The UDP4 driver's buffer will\r
480 be returned by either ::EslUdp4Receive or ::EslSocketPortCloseTxDone.\r
481 See the \ref ReceiveEngine section.\r
d7ce7006 482\r
a88c3163 483 This routine is called by the UDPv4 driver when data is\r
484 received.\r
485\r
486 @param [in] Event The receive completion event\r
487\r
488 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
d7ce7006 489\r
490**/\r
491VOID\r
a88c3163 492EslUdp4RxComplete (\r
493 IN EFI_EVENT Event,\r
494 IN ESL_IO_MGMT * pIo\r
d7ce7006 495 )\r
496{\r
a88c3163 497 size_t LengthInBytes;\r
498 ESL_PACKET * pPacket;\r
499 EFI_UDP4_RECEIVE_DATA * pRxData;\r
500 EFI_STATUS Status;\r
501 \r
d7ce7006 502 DBG_ENTER ( );\r
503\r
504 //\r
a88c3163 505 // Get the operation status.\r
d7ce7006 506 //\r
a88c3163 507 Status = pIo->Token.Udp4Rx.Status;\r
508 \r
d7ce7006 509 //\r
a88c3163 510 // Get the packet length\r
d7ce7006 511 //\r
a88c3163 512 pRxData = pIo->Token.Udp4Rx.Packet.RxData;\r
513 LengthInBytes = pRxData->DataLength;\r
d7ce7006 514\r
515 //\r
a88c3163 516 // +--------------------+ +-----------------------+\r
517 // | ESL_IO_MGMT | | Data Buffer |\r
518 // | | | (Driver owned) |\r
519 // | +---------------+ +-----------------------+\r
520 // | | Token | ^\r
521 // | | Rx Event | |\r
522 // | | | +-----------------------+\r
523 // | | RxData --> | EFI_UDP4_RECEIVE_DATA |\r
524 // +----+---------------+ | (Driver owned) |\r
525 // +-----------------------+\r
526 // +--------------------+ ^\r
527 // | ESL_PACKET | .\r
528 // | | .\r
529 // | +---------------+ .\r
530 // | | pRxData --> NULL .......\r
531 // +----+---------------+\r
d7ce7006 532 //\r
a88c3163 533 //\r
534 // Save the data in the packet\r
535 //\r
536 pPacket = pIo->pPacket;\r
537 pPacket->Op.Udp4Rx.pRxData = pRxData;\r
d7ce7006 538\r
a88c3163 539 //\r
540 // Complete this request\r
541 //\r
542 EslSocketRxComplete ( pIo, Status, LengthInBytes, FALSE );\r
d7ce7006 543 DBG_EXIT ( );\r
544}\r
545\r
546\r
547/**\r
a88c3163 548 Determine if the socket is configured.\r
d7ce7006 549\r
a88c3163 550 This routine uses the flag ESL_SOCKET::bConfigured to determine\r
551 if the network layer's configuration routine has been called.\r
552 This routine calls the bind and configuration routines if they\r
553 were not already called. After the port is configured, the\r
554 \ref ReceiveEngine is started.\r
555\r
556 This routine is called by EslSocketIsConfigured to verify\r
557 that the socket is configured.\r
558\r
559 @param [in] pSocket Address of an ::ESL_SOCKET structure\r
d7ce7006 560\r
d7ce7006 561 @retval EFI_SUCCESS - The port is connected\r
562 @retval EFI_NOT_STARTED - The port is not connected\r
563\r
564 **/\r
565 EFI_STATUS\r
a88c3163 566 EslUdp4SocketIsConfigured (\r
567 IN ESL_SOCKET * pSocket\r
d7ce7006 568 )\r
569{\r
a88c3163 570 EFI_UDP4_CONFIG_DATA * pConfigData;\r
571 ESL_PORT * pPort;\r
572 ESL_PORT * pNextPort;\r
573 ESL_UDP4_CONTEXT * pUdp4;\r
d7ce7006 574 EFI_UDP4_PROTOCOL * pUdp4Protocol;\r
575 EFI_STATUS Status;\r
576 struct sockaddr_in LocalAddress;\r
577\r
578 DBG_ENTER ( );\r
579\r
580 //\r
581 // Assume success\r
582 //\r
583 Status = EFI_SUCCESS;\r
584\r
585 //\r
586 // Configure the port if necessary\r
587 //\r
588 if ( !pSocket->bConfigured ) {\r
589 //\r
590 // Fill in the port list if necessary\r
591 //\r
592 if ( NULL == pSocket->pPortList ) {\r
593 LocalAddress.sin_len = sizeof ( LocalAddress );\r
594 LocalAddress.sin_family = AF_INET;\r
595 LocalAddress.sin_addr.s_addr = 0;\r
596 LocalAddress.sin_port = 0;\r
a88c3163 597 Status = EslSocketBind ( &pSocket->SocketProtocol,\r
598 (struct sockaddr *)&LocalAddress,\r
599 LocalAddress.sin_len,\r
600 &pSocket->errno );\r
d7ce7006 601 }\r
602\r
603 //\r
604 // Walk the port list\r
605 //\r
606 pPort = pSocket->pPortList;\r
607 while ( NULL != pPort ) {\r
608 //\r
609 // Attempt to configure the port\r
610 //\r
611 pNextPort = pPort->pLinkSocket;\r
612 pUdp4 = &pPort->Context.Udp4;\r
a88c3163 613 pUdp4Protocol = pPort->pProtocol.UDPv4;\r
614 pConfigData = &pUdp4->ConfigData;\r
615 DEBUG (( DEBUG_TX,\r
616 "0x%08x: pPort Configuring for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",\r
617 pPort,\r
618 pConfigData->StationAddress.Addr[0],\r
619 pConfigData->StationAddress.Addr[1],\r
620 pConfigData->StationAddress.Addr[2],\r
621 pConfigData->StationAddress.Addr[3],\r
622 pConfigData->StationPort,\r
623 pConfigData->RemoteAddress.Addr[0],\r
624 pConfigData->RemoteAddress.Addr[1],\r
625 pConfigData->RemoteAddress.Addr[2],\r
626 pConfigData->RemoteAddress.Addr[3],\r
627 pConfigData->RemotePort ));\r
d7ce7006 628 Status = pUdp4Protocol->Configure ( pUdp4Protocol,\r
a88c3163 629 pConfigData );\r
630 if ( !EFI_ERROR ( Status )) {\r
631 //\r
632 // Update the configuration data\r
633 //\r
634 Status = pUdp4Protocol->GetModeData ( pUdp4Protocol,\r
635 pConfigData,\r
636 NULL,\r
637 NULL,\r
638 NULL );\r
639 }\r
d7ce7006 640 if ( EFI_ERROR ( Status )) {\r
641 DEBUG (( DEBUG_LISTEN,\r
642 "ERROR - Failed to configure the Udp4 port, Status: %r\r\n",\r
643 Status ));\r
644 switch ( Status ) {\r
645 case EFI_ACCESS_DENIED:\r
646 pSocket->errno = EACCES;\r
647 break;\r
648\r
649 default:\r
650 case EFI_DEVICE_ERROR:\r
651 pSocket->errno = EIO;\r
652 break;\r
653\r
654 case EFI_INVALID_PARAMETER:\r
655 pSocket->errno = EADDRNOTAVAIL;\r
656 break;\r
657\r
658 case EFI_NO_MAPPING:\r
659 pSocket->errno = EAFNOSUPPORT;\r
660 break;\r
661\r
662 case EFI_OUT_OF_RESOURCES:\r
663 pSocket->errno = ENOBUFS;\r
664 break;\r
665\r
666 case EFI_UNSUPPORTED:\r
667 pSocket->errno = EOPNOTSUPP;\r
668 break;\r
669 }\r
670 }\r
671 else {\r
a88c3163 672 DEBUG (( DEBUG_TX,\r
673 "0x%08x: pPort Configured for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",\r
674 pPort,\r
675 pConfigData->StationAddress.Addr[0],\r
676 pConfigData->StationAddress.Addr[1],\r
677 pConfigData->StationAddress.Addr[2],\r
678 pConfigData->StationAddress.Addr[3],\r
679 pConfigData->StationPort,\r
680 pConfigData->RemoteAddress.Addr[0],\r
681 pConfigData->RemoteAddress.Addr[1],\r
682 pConfigData->RemoteAddress.Addr[2],\r
683 pConfigData->RemoteAddress.Addr[3],\r
684 pConfigData->RemotePort ));\r
685 pPort->bConfigured = TRUE;\r
d7ce7006 686\r
687 //\r
688 // Start the first read on the port\r
689 //\r
a88c3163 690 EslSocketRxStart ( pPort );\r
d7ce7006 691\r
692 //\r
693 // The socket is connected\r
694 //\r
695 pSocket->State = SOCKET_STATE_CONNECTED;\r
696 }\r
697\r
698 //\r
699 // Set the next port\r
700 //\r
701 pPort = pNextPort;\r
702 }\r
703\r
704 //\r
705 // Determine the configuration status\r
706 //\r
707 if ( NULL != pSocket->pPortList ) {\r
708 pSocket->bConfigured = TRUE;\r
709 }\r
710 }\r
711\r
712 //\r
713 // Determine the socket configuration status\r
714 //\r
715 if ( !EFI_ERROR ( Status )) {\r
716 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;\r
717 }\r
718 \r
719 //\r
720 // Return the port connected state.\r
721 //\r
722 DBG_EXIT_STATUS ( Status );\r
723 return Status;\r
724}\r
725\r
726\r
727/**\r
728 Buffer data for transmission over a network connection.\r
729\r
a88c3163 730 This routine buffers data for the transmit engine in the normal\r
731 data queue. When the \ref TransmitEngine has resources, this\r
732 routine will start the transmission of the next buffer on the\r
733 network connection.\r
734\r
735 This routine is called by ::EslSocketTransmit to buffer\r
d7ce7006 736 data for transmission. The data is copied into a local buffer\r
737 freeing the application buffer for reuse upon return. When\r
a88c3163 738 necessary, this routine starts the transmit engine that\r
d7ce7006 739 performs the data transmission on the network connection. The\r
740 transmit engine transmits the data a packet at a time over the\r
741 network connection.\r
742\r
743 Transmission errors are returned during the next transmission or\r
744 during the close operation. Only buffering errors are returned\r
745 during the current transmission attempt.\r
746\r
a88c3163 747 @param [in] pSocket Address of an ::ESL_SOCKET structure\r
d7ce7006 748\r
749 @param [in] Flags Message control flags\r
750\r
751 @param [in] BufferLength Length of the the buffer\r
752\r
753 @param [in] pBuffer Address of a buffer to receive the data.\r
754\r
755 @param [in] pDataLength Number of received data bytes in the buffer.\r
756\r
757 @param [in] pAddress Network address of the remote system address\r
758\r
759 @param [in] AddressLength Length of the remote network address structure\r
760\r
761 @retval EFI_SUCCESS - Socket data successfully buffered\r
762\r
763**/\r
764EFI_STATUS\r
a88c3163 765EslUdp4TxBuffer (\r
766 IN ESL_SOCKET * pSocket,\r
d7ce7006 767 IN int Flags,\r
768 IN size_t BufferLength,\r
769 IN CONST UINT8 * pBuffer,\r
770 OUT size_t * pDataLength,\r
771 IN const struct sockaddr * pAddress,\r
772 IN socklen_t AddressLength\r
773 )\r
774{\r
a88c3163 775 ESL_PACKET * pPacket;\r
776 ESL_PACKET * pPreviousPacket;\r
777 ESL_PORT * pPort;\r
d7ce7006 778 const struct sockaddr_in * pRemoteAddress;\r
a88c3163 779 ESL_UDP4_CONTEXT * pUdp4;\r
d7ce7006 780 size_t * pTxBytes;\r
a88c3163 781 ESL_UDP4_TX_DATA * pTxData;\r
d7ce7006 782 EFI_STATUS Status;\r
783 EFI_TPL TplPrevious;\r
784\r
785 DBG_ENTER ( );\r
786\r
787 //\r
788 // Assume failure\r
789 //\r
790 Status = EFI_UNSUPPORTED;\r
791 pSocket->errno = ENOTCONN;\r
a88c3163 792 *pDataLength = 0;\r
d7ce7006 793\r
794 //\r
795 // Verify that the socket is connected\r
796 //\r
797 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
798 //\r
799 // Locate the port\r
800 //\r
801 pPort = pSocket->pPortList;\r
802 if ( NULL != pPort ) {\r
803 //\r
804 // Determine the queue head\r
805 //\r
806 pUdp4 = &pPort->Context.Udp4;\r
d7ce7006 807 pTxBytes = &pSocket->TxBytes;\r
808\r
809 //\r
810 // Verify that there is enough room to buffer another\r
811 // transmit operation\r
812 //\r
813 if ( pSocket->MaxTxBuf > *pTxBytes ) {\r
814 //\r
815 // Attempt to allocate the packet\r
816 //\r
817 Status = EslSocketPacketAllocate ( &pPacket,\r
818 sizeof ( pPacket->Op.Udp4Tx )\r
819 - sizeof ( pPacket->Op.Udp4Tx.Buffer )\r
820 + BufferLength,\r
a88c3163 821 0,\r
d7ce7006 822 DEBUG_TX );\r
823 if ( !EFI_ERROR ( Status )) {\r
824 //\r
825 // Initialize the transmit operation\r
826 //\r
827 pTxData = &pPacket->Op.Udp4Tx;\r
828 pTxData->TxData.GatewayAddress = NULL;\r
829 pTxData->TxData.UdpSessionData = NULL;\r
830 pTxData->TxData.DataLength = (UINT32) BufferLength;\r
831 pTxData->TxData.FragmentCount = 1;\r
832 pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength;\r
833 pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Udp4Tx.Buffer[0];\r
a88c3163 834 pTxData->RetransmitCount = 0;\r
d7ce7006 835\r
836 //\r
837 // Set the remote system address if necessary\r
838 //\r
a88c3163 839 pTxData->TxData.UdpSessionData = NULL;\r
d7ce7006 840 if ( NULL != pAddress ) {\r
841 pRemoteAddress = (const struct sockaddr_in *)pAddress;\r
a88c3163 842 pTxData->Session.SourceAddress.Addr[0] = pUdp4->ConfigData.StationAddress.Addr[0];\r
843 pTxData->Session.SourceAddress.Addr[1] = pUdp4->ConfigData.StationAddress.Addr[1];\r
844 pTxData->Session.SourceAddress.Addr[2] = pUdp4->ConfigData.StationAddress.Addr[2];\r
845 pTxData->Session.SourceAddress.Addr[3] = pUdp4->ConfigData.StationAddress.Addr[3];\r
d7ce7006 846 pTxData->Session.SourcePort = 0;\r
847 pTxData->Session.DestinationAddress.Addr[0] = (UINT8)pRemoteAddress->sin_addr.s_addr;\r
848 pTxData->Session.DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );\r
849 pTxData->Session.DestinationAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );\r
850 pTxData->Session.DestinationAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );\r
851 pTxData->Session.DestinationPort = SwapBytes16 ( pRemoteAddress->sin_port );\r
852\r
853 //\r
854 // Use the remote system address when sending this packet\r
855 //\r
856 pTxData->TxData.UdpSessionData = &pTxData->Session;\r
857 }\r
858\r
859 //\r
860 // Copy the data into the buffer\r
861 //\r
862 CopyMem ( &pPacket->Op.Udp4Tx.Buffer[0],\r
863 pBuffer,\r
864 BufferLength );\r
865\r
866 //\r
867 // Synchronize with the socket layer\r
868 //\r
869 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
870\r
871 //\r
872 // Stop transmission after an error\r
873 //\r
874 if ( !EFI_ERROR ( pSocket->TxError )) {\r
875 //\r
876 // Display the request\r
877 //\r
878 DEBUG (( DEBUG_TX,\r
879 "Send %d %s bytes from 0x%08x\r\n",\r
880 BufferLength,\r
881 pBuffer ));\r
882\r
883 //\r
884 // Queue the data for transmission\r
885 //\r
886 pPacket->pNext = NULL;\r
887 pPreviousPacket = pSocket->pTxPacketListTail;\r
888 if ( NULL == pPreviousPacket ) {\r
889 pSocket->pTxPacketListHead = pPacket;\r
890 }\r
891 else {\r
892 pPreviousPacket->pNext = pPacket;\r
893 }\r
894 pSocket->pTxPacketListTail = pPacket;\r
895 DEBUG (( DEBUG_TX,\r
896 "0x%08x: Packet on transmit list\r\n",\r
897 pPacket ));\r
898\r
899 //\r
900 // Account for the buffered data\r
901 //\r
902 *pTxBytes += BufferLength;\r
903 *pDataLength = BufferLength;\r
904\r
905 //\r
906 // Start the transmit engine if it is idle\r
907 //\r
a88c3163 908 if ( NULL != pPort->pTxFree ) {\r
909 EslSocketTxStart ( pPort,\r
910 &pSocket->pTxPacketListHead,\r
911 &pSocket->pTxPacketListTail,\r
912 &pPort->pTxActive,\r
913 &pPort->pTxFree );\r
d7ce7006 914 }\r
915 }\r
916 else {\r
917 //\r
918 // Previous transmit error\r
919 // Stop transmission\r
920 //\r
921 Status = pSocket->TxError;\r
922 pSocket->errno = EIO;\r
923\r
924 //\r
925 // Free the packet\r
926 //\r
927 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
928 }\r
929\r
930 //\r
931 // Release the socket layer synchronization\r
932 //\r
933 RESTORE_TPL ( TplPrevious );\r
934 }\r
935 else {\r
936 //\r
937 // Packet allocation failed\r
938 //\r
939 pSocket->errno = ENOMEM;\r
940 }\r
941 }\r
942 else {\r
943 //\r
944 // Not enough buffer space available\r
945 //\r
946 pSocket->errno = EAGAIN;\r
947 Status = EFI_NOT_READY;\r
948 }\r
949 }\r
950 }\r
951\r
952 //\r
953 // Return the operation status\r
954 //\r
955 DBG_EXIT_STATUS ( Status );\r
956 return Status;\r
957}\r
958\r
959\r
960/**\r
961 Process the transmit completion\r
962\r
a88c3163 963 This routine use ::EslSocketTxComplete to perform the transmit\r
964 completion processing for data packets.\r
965\r
966 This routine is called by the UDPv4 network layer when a data\r
967 transmit request completes.\r
d7ce7006 968\r
a88c3163 969 @param [in] Event The normal transmit completion event\r
970\r
971 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
d7ce7006 972\r
973**/\r
974VOID\r
a88c3163 975EslUdp4TxComplete (\r
d7ce7006 976 IN EFI_EVENT Event,\r
a88c3163 977 IN ESL_IO_MGMT * pIo\r
d7ce7006 978 )\r
979{\r
980 UINT32 LengthInBytes;\r
a88c3163 981 ESL_PORT * pPort;\r
982 ESL_PACKET * pPacket;\r
983 ESL_SOCKET * pSocket;\r
d7ce7006 984 EFI_STATUS Status;\r
985 \r
986 DBG_ENTER ( );\r
987 \r
988 //\r
989 // Locate the active transmit packet\r
990 //\r
a88c3163 991 pPacket = pIo->pPacket;\r
992 pPort = pIo->pPort;\r
d7ce7006 993 pSocket = pPort->pSocket;\r
a88c3163 994\r
d7ce7006 995 //\r
a88c3163 996 // Get the transmit length and status\r
d7ce7006 997 //\r
d7ce7006 998 LengthInBytes = pPacket->Op.Udp4Tx.TxData.DataLength;\r
999 pSocket->TxBytes -= LengthInBytes;\r
a88c3163 1000 Status = pIo->Token.Udp4Tx.Status;\r
1001\r
d7ce7006 1002 //\r
a88c3163 1003 // Complete the transmit operation\r
d7ce7006 1004 //\r
a88c3163 1005 EslSocketTxComplete ( pIo,\r
1006 LengthInBytes,\r
1007 Status,\r
1008 "UDP ",\r
1009 &pSocket->pTxPacketListHead,\r
1010 &pSocket->pTxPacketListTail,\r
1011 &pPort->pTxActive,\r
1012 &pPort->pTxFree );\r
d7ce7006 1013 DBG_EXIT ( );\r
1014}\r
1015\r
1016\r
1017/**\r
a88c3163 1018 Interface between the socket layer and the network specific\r
1019 code that supports SOCK_DGRAM sockets over UDPv4.\r
1020**/\r
1021CONST ESL_PROTOCOL_API cEslUdp4Api = {\r
1022 "UDPv4",\r
1023 IPPROTO_UDP,\r
1024 OFFSET_OF ( ESL_PORT, Context.Udp4.ConfigData ),\r
1025 OFFSET_OF ( ESL_LAYER, pUdp4List ),\r
1026 OFFSET_OF ( struct sockaddr_in, sin_zero ),\r
1027 sizeof ( struct sockaddr_in ),\r
1028 AF_INET,\r
1029 sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),\r
1030 sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),\r
1031 OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Rx.Packet.RxData ),\r
1032 FALSE,\r
1033 EADDRINUSE,\r
1034 NULL, // Accept\r
1035 NULL, // ConnectPoll\r
1036 NULL, // ConnectStart\r
1037 EslUdp4SocketIsConfigured,\r
1038 EslUdp4LocalAddressGet,\r
1039 EslUdp4LocalAddressSet,\r
1040 NULL, // Listen\r
1041 NULL, // OptionGet\r
1042 NULL, // OptionSet\r
1043 EslUdp4PacketFree,\r
1044 EslUdp4PortAllocate,\r
1045 NULL, // PortClose,\r
1046 NULL, // PortCloseOp\r
1047 TRUE,\r
1048 EslUdp4Receive,\r
1049 EslUdp4RemoteAddressGet,\r
1050 EslUdp4RemoteAddressSet,\r
1051 EslUdp4RxComplete,\r
1052 NULL, // RxStart\r
1053 EslUdp4TxBuffer,\r
1054 EslUdp4TxComplete,\r
1055 NULL // TxOobComplete\r
1056};\r