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