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