]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - StdLib/EfiSocketLib/Udp4.c
Merged socket development branch
[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->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Receive;\r
257 pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Transmit;\r
258\r
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
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
280 Receive data from a network connection.\r
281\r
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
286\r
287 This routine is called by ::EslSocketReceive to handle the network\r
288 specific receive operation to support SOCK_DGRAM sockets.\r
289\r
290 @param [in] pPort Address of an ::ESL_PORT structure.\r
291\r
292 @param [in] pPacket Address of an ::ESL_PACKET structure.\r
293 \r
294 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed\r
295 \r
296 @param [in] BufferLength Length of the the buffer\r
297 \r
298 @param [in] pBuffer Address of a buffer to receive the data.\r
299 \r
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
304 @param [out] pSkipBytes Address to receive the number of bytes skipped\r
305\r
306 @return Returns the address of the next free byte in the buffer.\r
307\r
308 **/\r
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
319 )\r
320{\r
321 size_t DataBytes;\r
322 struct sockaddr_in * pRemoteAddress;\r
323 EFI_UDP4_RECEIVE_DATA * pRxData;\r
324\r
325 DBG_ENTER ( );\r
326\r
327 pRxData = pPacket->Op.Udp4Rx.pRxData;\r
328 //\r
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
349 //\r
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
357\r
358 //\r
359 // Determine if the data is being read\r
360 //\r
361 if ( *pbConsumePacket ) {\r
362 //\r
363 // Display for the bytes consumed\r
364 //\r
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
374 }\r
375\r
376 //\r
377 // Return the data length and the buffer address\r
378 //\r
379 *pDataLength = DataBytes;\r
380 DBG_EXIT_HEX ( pBuffer );\r
381 return pBuffer;\r
382}\r
383\r
384\r
385/**\r
386 Get the remote socket address\r
387\r
388 This routine returns the address of the remote connection point\r
389 associated with the SOCK_DGRAM socket.\r
390\r
391 This routine is called by ::EslSocketGetPeerAddress to detemine\r
392 the UDPv4 address and port number associated with the network adapter.\r
393\r
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
397\r
398**/\r
399VOID\r
400EslUdp4RemoteAddressGet (\r
401 IN ESL_PORT * pPort,\r
402 OUT struct sockaddr * pAddress\r
403 )\r
404{\r
405 struct sockaddr_in * pRemoteAddress;\r
406 ESL_UDP4_CONTEXT * pUdp4;\r
407\r
408 DBG_ENTER ( );\r
409\r
410 //\r
411 // Return the remote address\r
412 //\r
413 pUdp4 = &pPort->Context.Udp4;\r
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
420\r
421 DBG_EXIT ( );\r
422}\r
423\r
424\r
425/**\r
426 Set the remote address\r
427\r
428 This routine sets the remote address in the port.\r
429\r
430 This routine is called by ::EslSocketConnect to specify the\r
431 remote network address.\r
432\r
433 @param [in] pPort Address of an ::ESL_PORT structure.\r
434\r
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
438\r
439 @retval EFI_SUCCESS The operation was successful\r
440\r
441 **/\r
442EFI_STATUS\r
443EslUdp4RemoteAddressSet (\r
444 IN ESL_PORT * pPort,\r
445 IN CONST struct sockaddr * pSockAddr,\r
446 IN socklen_t SockAddrLength\r
447 )\r
448{\r
449 CONST struct sockaddr_in * pRemoteAddress;\r
450 ESL_UDP4_CONTEXT * pUdp4;\r
451 EFI_STATUS Status;\r
452\r
453 DBG_ENTER ( );\r
454\r
455 //\r
456 // Set the remote address\r
457 //\r
458 pUdp4 = &pPort->Context.Udp4;\r
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
466\r
467 //\r
468 // Return the operation status\r
469 //\r
470 DBG_EXIT_STATUS ( Status );\r
471 return Status;\r
472}\r
473\r
474\r
475/**\r
476 Process the receive completion\r
477\r
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
482\r
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
489\r
490**/\r
491VOID\r
492EslUdp4RxComplete (\r
493 IN EFI_EVENT Event,\r
494 IN ESL_IO_MGMT * pIo\r
495 )\r
496{\r
497 size_t LengthInBytes;\r
498 ESL_PACKET * pPacket;\r
499 EFI_UDP4_RECEIVE_DATA * pRxData;\r
500 EFI_STATUS Status;\r
501 \r
502 DBG_ENTER ( );\r
503\r
504 //\r
505 // Get the operation status.\r
506 //\r
507 Status = pIo->Token.Udp4Rx.Status;\r
508 \r
509 //\r
510 // Get the packet length\r
511 //\r
512 pRxData = pIo->Token.Udp4Rx.Packet.RxData;\r
513 LengthInBytes = pRxData->DataLength;\r
514\r
515 //\r
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
532 //\r
533 //\r
534 // Save the data in the packet\r
535 //\r
536 pPacket = pIo->pPacket;\r
537 pPacket->Op.Udp4Rx.pRxData = pRxData;\r
538\r
539 //\r
540 // Complete this request\r
541 //\r
542 EslSocketRxComplete ( pIo, Status, LengthInBytes, FALSE );\r
543 DBG_EXIT ( );\r
544}\r
545\r
546\r
547/**\r
548 Determine if the socket is configured.\r
549\r
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
560\r
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
566 EslUdp4SocketIsConfigured (\r
567 IN ESL_SOCKET * pSocket\r
568 )\r
569{\r
570 EFI_UDP4_CONFIG_DATA * pConfigData;\r
571 ESL_PORT * pPort;\r
572 ESL_PORT * pNextPort;\r
573 ESL_UDP4_CONTEXT * pUdp4;\r
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
597 Status = EslSocketBind ( &pSocket->SocketProtocol,\r
598 (struct sockaddr *)&LocalAddress,\r
599 LocalAddress.sin_len,\r
600 &pSocket->errno );\r
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
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
628 Status = pUdp4Protocol->Configure ( pUdp4Protocol,\r
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
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
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
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 }\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
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
736 data for transmission. The data is copied into a local buffer\r
737 freeing the application buffer for reuse upon return. When\r
738 necessary, this routine starts the transmit engine that\r
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
747 @param [in] pSocket Address of an ::ESL_SOCKET structure\r
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
765EslUdp4TxBuffer (\r
766 IN ESL_SOCKET * pSocket,\r
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
775 ESL_PACKET * pPacket;\r
776 ESL_PACKET * pPreviousPacket;\r
777 ESL_PORT * pPort;\r
778 const struct sockaddr_in * pRemoteAddress;\r
779 ESL_UDP4_CONTEXT * pUdp4;\r
780 size_t * pTxBytes;\r
781 ESL_UDP4_TX_DATA * pTxData;\r
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
792 *pDataLength = 0;\r
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
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
821 0,\r
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
834 pTxData->RetransmitCount = 0;\r
835\r
836 //\r
837 // Set the remote system address if necessary\r
838 //\r
839 pTxData->TxData.UdpSessionData = NULL;\r
840 if ( NULL != pAddress ) {\r
841 pRemoteAddress = (const struct sockaddr_in *)pAddress;\r
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
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
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
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
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
968\r
969 @param [in] Event The normal transmit completion event\r
970\r
971 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
972\r
973**/\r
974VOID\r
975EslUdp4TxComplete (\r
976 IN EFI_EVENT Event,\r
977 IN ESL_IO_MGMT * pIo\r
978 )\r
979{\r
980 UINT32 LengthInBytes;\r
981 ESL_PORT * pPort;\r
982 ESL_PACKET * pPacket;\r
983 ESL_SOCKET * pSocket;\r
984 EFI_STATUS Status;\r
985 \r
986 DBG_ENTER ( );\r
987 \r
988 //\r
989 // Locate the active transmit packet\r
990 //\r
991 pPacket = pIo->pPacket;\r
992 pPort = pIo->pPort;\r
993 pSocket = pPort->pSocket;\r
994\r
995 //\r
996 // Get the transmit length and status\r
997 //\r
998 LengthInBytes = pPacket->Op.Udp4Tx.TxData.DataLength;\r
999 pSocket->TxBytes -= LengthInBytes;\r
1000 Status = pIo->Token.Udp4Tx.Status;\r
1001\r
1002 //\r
1003 // Complete the transmit operation\r
1004 //\r
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
1013 DBG_EXIT ( );\r
1014}\r
1015\r
1016\r
1017/**\r
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