Better handle transmit errors
[mirror_edk2.git] / StdLib / EfiSocketLib / Socket.c
CommitLineData
d7ce7006 1/** @file\r
2 Implement the socket support for the socket layer.\r
3\r
4 Socket States:\r
5 * Bound - pSocket->PortList is not NULL\r
6 * Listen - AcceptWait event is not NULL\r
7\r
8 Copyright (c) 2011, Intel Corporation\r
9 All rights reserved. This program and the accompanying materials\r
10 are licensed and made available under the terms and conditions of the BSD License\r
11 which accompanies this distribution. The full text of the license may be found at\r
12 http://opensource.org/licenses/bsd-license.php\r
13\r
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16\r
17**/\r
18\r
19#include "Socket.h"\r
20\r
21\r
22/**\r
23 Socket driver connection points\r
24\r
25 List the network stack connection points for the socket driver.\r
26**/\r
27CONST DT_SOCKET_BINDING cEslSocketBinding [] = {\r
28 { L"Tcp4",\r
29 &gEfiTcp4ServiceBindingProtocolGuid,\r
30 &mEslTcp4ServiceGuid,\r
31 EslTcpInitialize4,\r
32 EslTcpShutdown4 },\r
33 { L"Udp4",\r
34 &gEfiUdp4ServiceBindingProtocolGuid,\r
35 &mEslUdp4ServiceGuid,\r
36 EslUdpInitialize4,\r
37 EslUdpShutdown4 }\r
38};\r
39\r
40CONST UINTN cEslSocketBindingEntries = DIM ( cEslSocketBinding );\r
41\r
42DT_LAYER mEslLayer;\r
43\r
44\r
45/**\r
46 Initialize an endpoint for network communication.\r
47\r
48 The ::Socket routine initializes the communication endpoint by providing\r
49 the support for the socket library function ::socket. The\r
50 <a href="http://www.linuxhowtos.org/manpages/2/socket.htm">Linux</a>,\r
51 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html">POSIX</a>\r
52 and <a href="http://msdn.microsoft.com/en-us/library/ms740506(v=VS.85).aspx">Windows</a>\r
53 documentation for the socket routine are available online for reference.\r
54\r
55 @param [in] pSocketProtocol Address of the socket protocol structure.\r
56 @param [in] domain Select the family of protocols for the client or server\r
57 application.\r
58\r
59 @param [in] type Specifies how to make the network connection. The following values\r
60 are supported:\r
61 <ul>\r
62 <li>\r
63 SOCK_STREAM - Connect to TCP, provides a byte stream\r
64 that is manipluated by read, recv, send and write.\r
65 </li>\r
66 <li>\r
67 SOCK_SEQPACKET - Connect to TCP, provides sequenced packet stream\r
68 that is manipulated by read, recv, send and write.\r
69 </li>\r
70 <li>\r
71 SOCK_DGRAM - Connect to UDP, provides a datagram service that is\r
72 manipulated by recvfrom and sendto.\r
73 </li>\r
74 </ul>\r
75\r
76 @param [in] protocol Specifies the lower layer protocol to use. The following\r
77 values are supported:\r
78 <ul>\r
79 <li>IPPROTO_TCP</li> - This value must be combined with SOCK_STREAM.</li>\r
80 <li>IPPROTO_UDP</li> - This value must be combined with SOCK_DGRAM.</li>\r
81 </ul>\r
82\r
83 @param [out] pErrno Address to receive the errno value upon completion.\r
84\r
85 @retval EFI_SUCCESS - Socket successfully created\r
86 @retval EFI_INVALID_PARAMETER - Invalid domain value, errno = EAFNOSUPPORT\r
87 @retval EFI_INVALID_PARAMETER - Invalid type value, errno = EINVAL\r
88 @retval EFI_INVALID_PARAMETER - Invalid protocol value, errno = EINVAL\r
89\r
90 **/\r
91EFI_STATUS\r
92EslSocket (\r
93 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
94 IN int domain,\r
95 IN int type,\r
96 IN int protocol,\r
97 IN int * pErrno\r
98 )\r
99{\r
100 DT_SOCKET * pSocket;\r
101 EFI_STATUS Status;\r
102 int errno;\r
103\r
104 DBG_ENTER ( );\r
105\r
106 //\r
107 // Locate the socket\r
108 //\r
109 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
110\r
111 //\r
112 // Set the default domain if necessary\r
113 //\r
114 if ( AF_UNSPEC == domain ) {\r
115 domain = AF_INET;\r
116 }\r
117\r
118 //\r
119 // Assume success\r
120 //\r
121 errno = 0;\r
122 Status = EFI_SUCCESS;\r
123\r
124 //\r
125 // Use break instead of goto\r
126 //\r
127 for ( ; ; ) {\r
128 //\r
129 // Validate the domain value\r
130 //\r
131 if (( AF_INET != domain )\r
132 && ( AF_LOCAL != domain ))\r
133 {\r
134 DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
135 "ERROR - Invalid domain value" ));\r
136 Status = EFI_INVALID_PARAMETER;\r
137 errno = EAFNOSUPPORT;\r
138 break;\r
139 }\r
140\r
141 //\r
142 // Set the default type if necessary\r
143 //\r
144 if ( 0 == type ) {\r
145 type = SOCK_STREAM;\r
146 }\r
147\r
148 //\r
149 // Validate the type value\r
150 //\r
151 if (( SOCK_STREAM == type )\r
152 || ( SOCK_SEQPACKET == type )) {\r
153 //\r
154 // Set the default protocol if necessary\r
155 //\r
156 if ( 0 == protocol ) {\r
157 protocol = IPPROTO_TCP;\r
158 }\r
159 }\r
160 else if ( SOCK_DGRAM == type ) {\r
161 //\r
162 // Set the default protocol if necessary\r
163 //\r
164 if ( 0 == protocol ) {\r
165 protocol = IPPROTO_UDP;\r
166 }\r
167 }\r
168 else {\r
169 DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
170 "ERROR - Invalid type value" ));\r
171 Status = EFI_INVALID_PARAMETER;\r
172 errno = EINVAL;\r
173 break;\r
174 }\r
175\r
176 //\r
177 // Validate the protocol value\r
178 //\r
179 if (( IPPROTO_TCP != protocol )\r
180 && ( IPPROTO_UDP != protocol )) {\r
181 DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
182 "ERROR - Invalid protocol value" ));\r
183 Status = EFI_INVALID_PARAMETER;\r
184 errno = EINVAL;\r
185 break;\r
186 }\r
187\r
188 //\r
189 // Save the socket attributes\r
190 //\r
191 pSocket->Domain = domain;\r
192 pSocket->Type = type;\r
193 pSocket->Protocol = protocol;\r
194\r
195 //\r
196 // Done\r
197 //\r
198 break;\r
199 }\r
200\r
201 //\r
202 // Return the operation status\r
203 //\r
204 if ( NULL != pErrno ) {\r
205 *pErrno = errno;\r
206 }\r
207 DBG_EXIT_STATUS ( Status );\r
208 return Status;\r
209}\r
210\r
211\r
212/**\r
213 Accept a network connection.\r
214\r
215 The SocketAccept routine waits for a network connection to the socket.\r
216 It is able to return the remote network address to the caller if\r
217 requested.\r
218\r
219 @param [in] pSocketProtocol Address of the socket protocol structure.\r
220\r
221 @param [in] pSockAddr Address of a buffer to receive the remote\r
222 network address.\r
223\r
224 @param [in, out] pSockAddrLength Length in bytes of the address buffer.\r
225 On output specifies the length of the\r
226 remote network address.\r
227\r
228 @param [out] ppSocketProtocol Address of a buffer to receive the socket protocol\r
229 instance associated with the new socket.\r
230\r
231 @param [out] pErrno Address to receive the errno value upon completion.\r
232\r
233 @retval EFI_SUCCESS New connection successfully created\r
234 @retval EFI_NOT_READY No connection is available\r
235\r
236 **/\r
237EFI_STATUS\r
238EslSocketAccept (\r
239 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
240 IN struct sockaddr * pSockAddr,\r
241 IN OUT socklen_t * pSockAddrLength,\r
242 IN EFI_SOCKET_PROTOCOL ** ppSocketProtocol,\r
243 IN int * pErrno\r
244 )\r
245{\r
246 DT_SOCKET * pNewSocket;\r
247 DT_SOCKET * pSocket;\r
248 EFI_STATUS Status;\r
249 EFI_TPL TplPrevious;\r
250\r
251 DBG_ENTER ( );\r
252\r
253 //\r
254 // Assume success\r
255 //\r
256 Status = EFI_SUCCESS;\r
257\r
258 //\r
259 // Validate the socket\r
260 //\r
261 pSocket = NULL;\r
262 pNewSocket = NULL;\r
263 if ( NULL != pSocketProtocol ) {\r
264 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
265\r
266 //\r
267 // Validate the sockaddr\r
268 //\r
269 if (( NULL != pSockAddr )\r
270 && ( NULL == pSockAddrLength )) {\r
271 DEBUG (( DEBUG_ACCEPT,\r
272 "ERROR - pSockAddr is NULL!\r\n" ));\r
273 Status = EFI_INVALID_PARAMETER;\r
274 pSocket->errno = EFAULT;\r
275 }\r
276 else {\r
277 //\r
278 // Synchronize with the socket layer\r
279 //\r
280 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
281\r
282 //\r
283 // Verify that the socket is in the listen state\r
284 //\r
285 if ( SOCKET_STATE_LISTENING != pSocket->State ) {\r
286 DEBUG (( DEBUG_ACCEPT,\r
287 "ERROR - Socket is not listening!\r\n" ));\r
288 Status = EFI_NOT_STARTED;\r
289 pSocket->errno = EOPNOTSUPP;\r
290 }\r
291 else {\r
292 //\r
293 // Determine if a socket is available\r
294 //\r
295 if ( 0 == pSocket->FifoDepth ) {\r
296 //\r
297 // No connections available\r
298 // Determine if any ports are available\r
299 //\r
300 if ( NULL == pSocket->pPortList ) {\r
301 //\r
302 // No ports available\r
303 //\r
304 Status = EFI_DEVICE_ERROR;\r
305 pSocket->errno = EINVAL;\r
306\r
307 //\r
308 // Update the socket state\r
309 //\r
310 pSocket->State = SOCKET_STATE_NO_PORTS;\r
311 }\r
312 else {\r
313 //\r
314 // Ports are available\r
315 // No connection requests at this time\r
316 //\r
317 Status = EFI_NOT_READY;\r
318 pSocket->errno = EAGAIN;\r
319 }\r
320 }\r
321 else {\r
322 \r
323 //\r
324 // Get the remote network address\r
325 //\r
326 pNewSocket = pSocket->pFifoHead;\r
327 ASSERT ( NULL != pNewSocket );\r
328 switch ( pSocket->Domain ) {\r
329 default:\r
330 DEBUG (( DEBUG_ACCEPT,\r
331 "ERROR - Invalid socket address family: %d\r\n",\r
332 pSocket->Domain ));\r
333 Status = EFI_INVALID_PARAMETER;\r
334 pSocket->errno = EADDRNOTAVAIL;\r
335 break;\r
336\r
337 case AF_INET:\r
338 //\r
339 // Determine the connection point within the network stack\r
340 //\r
341 switch ( pSocket->Type ) {\r
342 default:\r
343 DEBUG (( DEBUG_ACCEPT,\r
344 "ERROR - Invalid socket type: %d\r\n",\r
345 pSocket->Type));\r
346 Status = EFI_INVALID_PARAMETER;\r
347 pSocket->errno = EADDRNOTAVAIL;\r
348 break;\r
349\r
350 case SOCK_STREAM:\r
351 case SOCK_SEQPACKET:\r
352 Status = EslTcpAccept4 ( pNewSocket,\r
353 pSockAddr,\r
354 pSockAddrLength );\r
355 break;\r
356\r
357 /*\r
358 case SOCK_DGRAM:\r
359 Status = UdpAccept4 ( pSocket );\r
360 break;\r
361 */\r
362 }\r
363 break;\r
364 }\r
365 if ( !EFI_ERROR ( Status )) {\r
366 //\r
367 // Remove the new socket from the list\r
368 //\r
369 pSocket->pFifoHead = pNewSocket->pNextConnection;\r
370 if ( NULL == pSocket->pFifoHead ) {\r
371 pSocket->pFifoTail = NULL;\r
372 }\r
373\r
374 //\r
375 // Account for this socket\r
376 //\r
377 pSocket->FifoDepth -= 1;\r
378\r
379 //\r
380 // Update the new socket's state\r
381 //\r
382 pNewSocket->State = SOCKET_STATE_CONNECTED;\r
383 pNewSocket->bConfigured = TRUE;\r
384 DEBUG (( DEBUG_ACCEPT,\r
385 "0x%08x: Socket connected\r\n",\r
386 pNewSocket ));\r
387 }\r
388 }\r
389 }\r
390\r
391 //\r
392 // Release the socket layer synchronization\r
393 //\r
394 RESTORE_TPL ( TplPrevious );\r
395 }\r
396 }\r
397\r
398 //\r
399 // Return the new socket\r
400 //\r
401 if (( NULL != ppSocketProtocol )\r
402 && ( NULL != pNewSocket )) {\r
403 *ppSocketProtocol = &pNewSocket->SocketProtocol;\r
404 }\r
405\r
406 //\r
407 // Return the operation status\r
408 //\r
409 if ( NULL != pErrno ) {\r
410 if ( NULL != pSocket ) {\r
411 *pErrno = pSocket->errno;\r
412 }\r
413 else\r
414 {\r
415 Status = EFI_INVALID_PARAMETER;\r
416 *pErrno = EBADF;\r
417 }\r
418 }\r
419 DBG_EXIT_STATUS ( Status );\r
420 return Status;\r
421}\r
422\r
423\r
424/**\r
425 Allocate and initialize a DT_SOCKET structure.\r
426 \r
427 The ::SocketAllocate() function allocates a DT_SOCKET structure\r
428 and installs a protocol on ChildHandle. If pChildHandle is a\r
429 pointer to NULL, then a new handle is created and returned in\r
430 pChildHandle. If pChildHandle is not a pointer to NULL, then\r
431 the protocol installs on the existing pChildHandle.\r
432\r
433 @param [in, out] pChildHandle Pointer to the handle of the child to create.\r
434 If it is NULL, then a new handle is created.\r
435 If it is a pointer to an existing UEFI handle, \r
436 then the protocol is added to the existing UEFI\r
437 handle.\r
438 @param [in] DebugFlags Flags for debug messages\r
439 @param [in, out] ppSocket The buffer to receive the DT_SOCKET structure address.\r
440\r
441 @retval EFI_SUCCESS The protocol was added to ChildHandle.\r
442 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.\r
443 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create\r
444 the child\r
445 @retval other The child handle was not created\r
446 \r
447**/\r
448EFI_STATUS\r
449EFIAPI\r
450EslSocketAllocate (\r
451 IN OUT EFI_HANDLE * pChildHandle,\r
452 IN UINTN DebugFlags,\r
453 IN OUT DT_SOCKET ** ppSocket\r
454 )\r
455{\r
456 UINTN LengthInBytes;\r
457 DT_LAYER * pLayer;\r
458 DT_SOCKET * pSocket;\r
459 EFI_STATUS Status;\r
460 EFI_TPL TplPrevious;\r
461\r
462 DBG_ENTER ( );\r
463\r
464 //\r
465 // Create a socket structure\r
466 //\r
467 LengthInBytes = sizeof ( *pSocket );\r
468 Status = gBS->AllocatePool (\r
469 EfiRuntimeServicesData,\r
470 LengthInBytes,\r
471 (VOID **) &pSocket\r
472 );\r
473 if ( !EFI_ERROR ( Status )) {\r
474 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
475 "0x%08x: Allocate pSocket, %d bytes\r\n",\r
476 pSocket,\r
477 LengthInBytes ));\r
478\r
479 //\r
480 // Initialize the socket protocol\r
481 //\r
482 ZeroMem ( pSocket, LengthInBytes );\r
483\r
484 pSocket->Signature = SOCKET_SIGNATURE;\r
485 pSocket->SocketProtocol.pfnAccept = EslSocketAccept;\r
486 pSocket->SocketProtocol.pfnBind = EslSocketBind;\r
487 pSocket->SocketProtocol.pfnClosePoll = EslSocketClosePoll;\r
488 pSocket->SocketProtocol.pfnCloseStart = EslSocketCloseStart;\r
489 pSocket->SocketProtocol.pfnConnect = EslSocketConnect;\r
490 pSocket->SocketProtocol.pfnGetLocal = EslSocketGetLocalAddress;\r
491 pSocket->SocketProtocol.pfnGetPeer = EslSocketGetPeerAddress;\r
492 pSocket->SocketProtocol.pfnListen = EslSocketListen;\r
493 pSocket->SocketProtocol.pfnOptionGet = EslSocketOptionGet;\r
494 pSocket->SocketProtocol.pfnOptionSet = EslSocketOptionSet;\r
495 pSocket->SocketProtocol.pfnPoll = EslSocketPoll;\r
496 pSocket->SocketProtocol.pfnReceive = EslSocketReceive;\r
497 pSocket->SocketProtocol.pfnSend = EslSocketTransmit;\r
498 pSocket->SocketProtocol.pfnShutdown = EslSocketShutdown;\r
499 pSocket->SocketProtocol.pfnSocket = EslSocket;\r
500\r
501 pSocket->MaxRxBuf = MAX_RX_DATA;\r
502 pSocket->MaxTxBuf = MAX_TX_DATA;\r
503\r
504 //\r
505 // Install the socket protocol on the specified handle\r
506 //\r
507 Status = gBS->InstallMultipleProtocolInterfaces (\r
508 pChildHandle,\r
509 &gEfiSocketProtocolGuid,\r
510 &pSocket->SocketProtocol,\r
511 NULL\r
512 );\r
513 if ( !EFI_ERROR ( Status )) {\r
514 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
515 "Installed: gEfiSocketProtocolGuid on 0x%08x\r\n",\r
516 *pChildHandle ));\r
517 pSocket->SocketProtocol.SocketHandle = *pChildHandle;\r
518\r
519 //\r
520 // Synchronize with the socket layer\r
521 //\r
522 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
523\r
524 //\r
525 // Add this socket to the list\r
526 //\r
527 pLayer = &mEslLayer;\r
528 pSocket->pNext = pLayer->pSocketList;\r
529 pLayer->pSocketList = pSocket;\r
530\r
531 //\r
532 // Release the socket layer synchronization\r
533 //\r
534 RESTORE_TPL ( TplPrevious );\r
535\r
536 //\r
537 // Return the socket structure address\r
538 //\r
539 *ppSocket = pSocket;\r
540 }\r
541 else {\r
542 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
543 "ERROR - Failed to install gEfiSocketProtocolGuid on 0x%08x, Status: %r\r\n",\r
544 *pChildHandle,\r
545 Status ));\r
546 }\r
547\r
548 //\r
549 // Release the socket if necessary\r
550 //\r
551 if ( EFI_ERROR ( Status )) {\r
552 gBS->FreePool ( pSocket );\r
553 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
554 "0x%08x: Free pSocket, %d bytes\r\n",\r
555 pSocket,\r
556 sizeof ( *pSocket )));\r
557 pSocket = NULL;\r
558 }\r
559 }\r
560 else {\r
561 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
562 "ERROR - Failed socket allocation, Status: %r\r\n",\r
563 Status ));\r
564 }\r
565\r
566 //\r
567 // Return the operation status\r
568 //\r
569 DBG_EXIT_STATUS ( Status );\r
570 return Status;\r
571}\r
572\r
573\r
574/**\r
575 Bind a name to a socket.\r
576\r
577 The ::SocketBind routine connects a name to a socket on the local machine. The\r
578 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html">POSIX</a>\r
579 documentation for the bind routine is available online for reference.\r
580\r
581 @param [in] pSocketProtocol Address of the socket protocol structure.\r
582\r
583 @param [in] pSockAddr Address of a sockaddr structure that contains the\r
584 connection point on the local machine. An IPv4 address\r
585 of INADDR_ANY specifies that the connection is made to\r
586 all of the network stacks on the platform. Specifying a\r
587 specific IPv4 address restricts the connection to the\r
588 network stack supporting that address. Specifying zero\r
589 for the port causes the network layer to assign a port\r
590 number from the dynamic range. Specifying a specific\r
591 port number causes the network layer to use that port.\r
592\r
593 @param [in] SockAddrLen Specifies the length in bytes of the sockaddr structure.\r
594\r
595 @param [out] pErrno Address to receive the errno value upon completion.\r
596\r
597 @retval EFI_SUCCESS - Socket successfully created\r
598\r
599 **/\r
600EFI_STATUS\r
601EslSocketBind (\r
602 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
603 IN const struct sockaddr * pSockAddr,\r
604 IN socklen_t SockAddrLength,\r
605 OUT int * pErrno\r
606 )\r
607{\r
608 DT_SOCKET * pSocket;\r
609 EFI_STATUS Status;\r
610 EFI_TPL TplPrevious;\r
611\r
612 DBG_ENTER ( );\r
613\r
614 //\r
615 // Assume success\r
616 //\r
617 Status = EFI_SUCCESS;\r
618\r
619 //\r
620 // Validate the socket\r
621 //\r
622 pSocket = NULL;\r
623 if ( NULL != pSocketProtocol ) {\r
624 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
625\r
626 //\r
627 // Validate the structure pointer\r
628 //\r
629 if ( NULL == pSockAddr ) {\r
630 DEBUG (( DEBUG_BIND,\r
631 "ERROR - pSockAddr is NULL!\r\n" ));\r
632 Status = EFI_INVALID_PARAMETER;\r
633 pSocket->errno = EFAULT;\r
634 }\r
635 else{\r
636 //\r
637 // Validate the name length\r
638 //\r
639 if (( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))\r
640 || ( pSockAddr->sa_len < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))) {\r
641 DEBUG (( DEBUG_BIND,\r
642 "ERROR - Invalid bind name length: %d, sa_len: %d\r\n",\r
643 SockAddrLength,\r
644 pSockAddr->sa_len ));\r
645 Status = EFI_INVALID_PARAMETER;\r
646 pSocket->errno = EINVAL;\r
647 }\r
648 else {\r
649 //\r
650 // Set the socket address length\r
651 //\r
652 if ( SockAddrLength > pSockAddr->sa_len ) {\r
653 SockAddrLength = pSockAddr->sa_len;\r
654 }\r
655\r
656 //\r
657 // Synchronize with the socket layer\r
658 //\r
659 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
660\r
661 //\r
662 // Validate the local address\r
663 //\r
664 switch ( pSockAddr->sa_family ) {\r
665 default:\r
666 DEBUG (( DEBUG_BIND,\r
667 "ERROR - Invalid bind address family: %d\r\n",\r
668 pSockAddr->sa_family ));\r
669 Status = EFI_INVALID_PARAMETER;\r
670 pSocket->errno = EADDRNOTAVAIL;\r
671 break;\r
672\r
673 case AF_INET:\r
674 //\r
675 // Determine the connection point within the network stack\r
676 //\r
677 switch ( pSocket->Type ) {\r
678 default:\r
679 DEBUG (( DEBUG_BIND,\r
680 "ERROR - Invalid socket type: %d\r\n",\r
681 pSocket->Type));\r
682 Status = EFI_INVALID_PARAMETER;\r
683 pSocket->errno = EADDRNOTAVAIL;\r
684 break;\r
685\r
686 case SOCK_STREAM:\r
687 case SOCK_SEQPACKET:\r
688 Status = EslTcpBind4 ( pSocket,\r
689 pSockAddr,\r
690 SockAddrLength );\r
691 break;\r
692\r
693 case SOCK_DGRAM:\r
694 Status = EslUdpBind4 ( pSocket,\r
695 pSockAddr,\r
696 SockAddrLength );\r
697 break;\r
698 }\r
699 break;\r
700 }\r
701\r
702 //\r
703 // Mark this socket as bound if successful\r
704 //\r
705 if ( !EFI_ERROR ( Status )) {\r
706 pSocket->State = SOCKET_STATE_BOUND;\r
707 }\r
708\r
709 //\r
710 // Release the socket layer synchronization\r
711 //\r
712 RESTORE_TPL ( TplPrevious );\r
713 }\r
714 }\r
715 }\r
716\r
717 //\r
718 // Return the operation status\r
719 //\r
720 if ( NULL != pErrno ) {\r
721 if ( NULL != pSocket ) {\r
722 *pErrno = pSocket->errno;\r
723 }\r
724 else\r
725 {\r
726 Status = EFI_INVALID_PARAMETER;\r
727 *pErrno = EBADF;\r
728 }\r
729 }\r
730 DBG_EXIT_STATUS ( Status );\r
731 return Status;\r
732}\r
733\r
734\r
735/**\r
736 Determine if the socket is closed\r
737\r
738 Reverses the operations of the ::SocketAllocate() routine.\r
739\r
740 @param [in] pSocketProtocol Address of the socket protocol structure.\r
741 @param [out] pErrno Address to receive the errno value upon completion.\r
742\r
743 @retval EFI_SUCCESS Socket successfully closed\r
744 @retval EFI_NOT_READY Close still in progress\r
745 @retval EFI_ALREADY Close operation already in progress\r
746 @retval Other Failed to close the socket\r
747\r
748**/\r
749EFI_STATUS\r
750EslSocketClosePoll (\r
751 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
752 IN int * pErrno\r
753 )\r
754{\r
755 int errno;\r
756 DT_LAYER * pLayer;\r
757 DT_SOCKET * pNextSocket;\r
758 DT_SOCKET * pSocket;\r
759 EFI_STATUS Status;\r
760 EFI_TPL TplPrevious;\r
761\r
762 DBG_ENTER ( );\r
763\r
764 //\r
765 // Assume success\r
766 //\r
767 errno = 0;\r
768 Status = EFI_SUCCESS;\r
769\r
770 //\r
771 // Synchronize with the socket layer\r
772 //\r
773 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
774\r
775 //\r
776 // Locate the socket\r
777 //\r
778 pLayer = &mEslLayer;\r
779 pNextSocket = pLayer->pSocketList;\r
780 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
781 while ( NULL != pNextSocket ) {\r
782 if ( pNextSocket == pSocket ) {\r
783 //\r
784 // Determine if the socket is in the closing state\r
785 //\r
786 if ( SOCKET_STATE_CLOSED == pSocket->State ) {\r
787 //\r
788 // Walk the list of ports\r
789 //\r
790 if ( NULL == pSocket->pPortList ) {\r
791 //\r
792 // All the ports are closed\r
793 // Close the WaitAccept event if necessary\r
794 //\r
795 if ( NULL != pSocket->WaitAccept ) {\r
796 Status = gBS->CloseEvent ( pSocket->WaitAccept );\r
797 if ( !EFI_ERROR ( Status )) {\r
798 DEBUG (( DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,\r
799 "0x%08x: Closed WaitAccept event\r\n",\r
800 pSocket->WaitAccept ));\r
801 //\r
802 // Return the transmit status\r
803 //\r
804 Status = pSocket->TxError;\r
805 if ( EFI_ERROR ( Status )) {\r
806 pSocket->errno = EIO;\r
807 }\r
808 }\r
809 else {\r
810 DEBUG (( DEBUG_ERROR | DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,\r
811 "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",\r
812 Status ));\r
813 ASSERT ( EFI_SUCCESS == Status );\r
814 }\r
815 }\r
816 }\r
817 else {\r
818 //\r
819 // At least one port is still open\r
820 //\r
821 Status = EFI_NOT_READY;\r
822 errno = EAGAIN;\r
823 }\r
824 }\r
825 else {\r
826 //\r
827 // SocketCloseStart was not called\r
828 //\r
829 Status = EFI_NOT_STARTED;\r
830 errno = EPERM;\r
831 }\r
832 break;\r
833 }\r
834\r
835 //\r
836 // Set the next socket\r
837 //\r
838 pNextSocket = pNextSocket->pNext;\r
839 }\r
840\r
841 //\r
842 // Handle the error case where the socket was already closed\r
843 //\r
844 if ( NULL == pSocket ) {\r
845 //\r
846 // Socket not found\r
847 //\r
848 Status = EFI_NOT_FOUND;\r
849 errno = ENOTSOCK;\r
850 }\r
851\r
852 //\r
853 // Release the socket layer synchronization\r
854 //\r
855 RESTORE_TPL ( TplPrevious );\r
856\r
857 //\r
858 // Return the operation status\r
859 //\r
860 if ( NULL != pErrno ) {\r
861 *pErrno = errno;\r
862 }\r
863 DBG_EXIT_STATUS ( Status );\r
864 return Status;\r
865}\r
866\r
867\r
868/**\r
869 Start the close operation on the socket\r
870\r
871 Start closing the socket by closing all of the ports. Upon\r
872 completion, the ::SocketPoll() routine finishes closing the\r
873 socket.\r
874\r
875 @param [in] pSocketProtocol Address of the socket protocol structure.\r
876 @param [in] bCloseNow Boolean to control close behavior\r
877 @param [out] pErrno Address to receive the errno value upon completion.\r
878\r
879 @retval EFI_SUCCESS Socket successfully closed\r
880 @retval EFI_NOT_READY Close still in progress\r
881 @retval EFI_ALREADY Close operation already in progress\r
882 @retval Other Failed to close the socket\r
883\r
884**/\r
885EFI_STATUS\r
886EslSocketCloseStart (\r
887 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
888 IN BOOLEAN bCloseNow,\r
889 IN int * pErrno\r
890 )\r
891{\r
892 int errno;\r
893 DT_PORT * pNextPort;\r
894 DT_PORT * pPort;\r
895 DT_SOCKET * pSocket;\r
896 EFI_STATUS Status;\r
897 EFI_TPL TplPrevious;\r
898\r
899 DBG_ENTER ( );\r
900\r
901 //\r
902 // Assume success\r
903 //\r
904 Status = EFI_SUCCESS;\r
905 errno = 0;\r
906\r
907 //\r
908 // Synchronize with the socket layer\r
909 //\r
910 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
911\r
912 //\r
913 // Determine if the socket is already closed\r
914 //\r
915 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
916 if ( SOCKET_STATE_CLOSED > pSocket->State ) {\r
917 //\r
918 // Update the socket state\r
919 //\r
920 pSocket->State = SOCKET_STATE_CLOSED;\r
921\r
922 //\r
923 // Walk the list of ports\r
924 //\r
925 pPort = pSocket->pPortList;\r
926 while ( NULL != pPort ) {\r
927 //\r
928 // Start closing the ports\r
929 //\r
930 pNextPort = pPort->pLinkSocket;\r
931 Status = pPort->pfnCloseStart ( pPort,\r
932 bCloseNow,\r
933 DEBUG_CLOSE | DEBUG_LISTEN | DEBUG_CONNECTION );\r
934 if (( EFI_SUCCESS != Status )\r
935 && ( EFI_NOT_READY != Status )) {\r
936 errno = EIO;\r
937 break;\r
938 }\r
939\r
940 //\r
941 // Set the next port\r
942 //\r
943 pPort = pNextPort;\r
944 }\r
945\r
946 //\r
947 // Attempt to finish closing the socket\r
948 //\r
949 if ( NULL == pPort ) {\r
950 Status = EslSocketClosePoll ( pSocketProtocol, &errno );\r
951 }\r
952 }\r
953 else {\r
954 Status = EFI_ALREADY_STARTED;\r
955 errno = EALREADY;\r
956 }\r
957\r
958 //\r
959 // Release the socket layer synchronization\r
960 //\r
961 RESTORE_TPL ( TplPrevious );\r
962\r
963 //\r
964 // Return the operation status\r
965 //\r
966 if ( NULL != pErrno ) {\r
967 *pErrno = errno;\r
968 }\r
969 DBG_EXIT_STATUS ( Status );\r
970 return Status;\r
971}\r
972\r
973\r
974/**\r
975 Connect to a remote system via the network.\r
976\r
977 The ::SocketConnect routine attempts to establish a connection to a\r
978 socket on the local or remote system using the specified address.\r
979 The POSIX\r
980 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html">connect</a>\r
981 documentation is available online.\r
982\r
983 There are three states associated with a connection:\r
984 <ul>\r
985 <li>Not connected</li>\r
986 <li>Connection in progress</li>\r
987 <li>Connected</li>\r
988 </ul>\r
989 In the "Not connected" state, calls to ::connect start the connection\r
990 processing and update the state to "Connection in progress". During\r
991 the "Connection in progress" state, connect polls for connection completion\r
992 and moves the state to "Connected" after the connection is established.\r
993 Note that these states are only visible when the file descriptor is marked\r
994 with O_NONBLOCK. Also, the POLL_WRITE bit is set when the connection\r
995 completes and may be used by poll or select as an indicator to call\r
996 connect again.\r
997\r
998 @param [in] pSocketProtocol Address of the socket protocol structure.\r
999\r
1000 @param [in] pSockAddr Network address of the remote system.\r
1001 \r
1002 @param [in] SockAddrLength Length in bytes of the network address.\r
1003 \r
1004 @param [out] pErrno Address to receive the errno value upon completion.\r
1005 \r
1006 @retval EFI_SUCCESS The connection was successfully established.\r
1007 @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
1008 @retval Others The connection attempt failed.\r
1009\r
1010 **/\r
1011EFI_STATUS\r
1012EslSocketConnect (\r
1013 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1014 IN const struct sockaddr * pSockAddr,\r
1015 IN socklen_t SockAddrLength,\r
1016 IN int * pErrno\r
1017 )\r
1018{\r
1019 DT_SOCKET * pSocket;\r
1020 EFI_STATUS Status;\r
1021 EFI_TPL TplPrevious;\r
1022 \r
1023 DEBUG (( DEBUG_CONNECT, "Entering SocketConnect\r\n" ));\r
1024\r
1025 //\r
1026 // Assume success\r
1027 //\r
1028 Status = EFI_SUCCESS;\r
1029\r
1030 //\r
1031 // Validate the socket\r
1032 //\r
1033 pSocket = NULL;\r
1034 if ( NULL != pSocketProtocol ) {\r
1035 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1036\r
1037 //\r
1038 // Validate the name length\r
1039 //\r
1040 if (( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))\r
1041 || ( pSockAddr->sa_len < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))) {\r
1042 DEBUG (( DEBUG_CONNECT,\r
1043 "ERROR - Invalid bind name length: %d, sa_len: %d\r\n",\r
1044 SockAddrLength,\r
1045 pSockAddr->sa_len ));\r
1046 Status = EFI_INVALID_PARAMETER;\r
1047 pSocket->errno = EINVAL;\r
1048 }\r
1049 else {\r
1050 //\r
1051 // Assume success\r
1052 //\r
1053 pSocket->errno = 0;\r
1054\r
1055 //\r
1056 // Set the socket address length\r
1057 //\r
1058 if ( SockAddrLength > pSockAddr->sa_len ) {\r
1059 SockAddrLength = pSockAddr->sa_len;\r
1060 }\r
1061\r
1062 //\r
1063 // Synchronize with the socket layer\r
1064 //\r
1065 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1066\r
1067 //\r
1068 // Validate the socket state\r
1069 //\r
1070 switch ( pSocket->State ) {\r
1071 default:\r
1072 //\r
1073 // Wrong socket state\r
1074 //\r
1075 pSocket->errno = EIO;\r
1076 Status = EFI_DEVICE_ERROR;\r
1077 break;\r
1078\r
1079 case SOCKET_STATE_NOT_CONFIGURED:\r
1080 case SOCKET_STATE_BOUND:\r
1081 //\r
1082 // Validate the local address\r
1083 //\r
1084 switch ( pSockAddr->sa_family ) {\r
1085 default:\r
1086 DEBUG (( DEBUG_CONNECT,\r
1087 "ERROR - Invalid bind address family: %d\r\n",\r
1088 pSockAddr->sa_family ));\r
1089 Status = EFI_INVALID_PARAMETER;\r
1090 pSocket->errno = EADDRNOTAVAIL;\r
1091 break;\r
1092\r
1093 case AF_INET:\r
1094 //\r
1095 // Determine the connection point within the network stack\r
1096 //\r
1097 switch ( pSocket->Type ) {\r
1098 default:\r
1099 DEBUG (( DEBUG_CONNECT,\r
1100 "ERROR - Invalid socket type: %d\r\n",\r
1101 pSocket->Type));\r
1102 Status = EFI_INVALID_PARAMETER;\r
1103 pSocket->errno = EADDRNOTAVAIL;\r
1104 break;\r
1105\r
1106 case SOCK_STREAM:\r
1107 case SOCK_SEQPACKET:\r
1108 //\r
1109 // Start the connection processing\r
1110 //\r
1111 Status = EslTcpConnectStart4 ( pSocket,\r
1112 pSockAddr,\r
1113 SockAddrLength );\r
1114\r
1115 //\r
1116 // Set the next state if connecting\r
1117 //\r
1118 if ( EFI_NOT_READY == Status ) {\r
1119 pSocket->State = SOCKET_STATE_CONNECTING;\r
1120 }\r
1121 break;\r
1122\r
1123 case SOCK_DGRAM:\r
1124 Status = EslUdpConnect4 ( pSocket,\r
1125 pSockAddr,\r
1126 SockAddrLength );\r
1127 break;\r
1128 }\r
1129 break;\r
1130 }\r
1131 break;\r
1132\r
1133 case SOCKET_STATE_CONNECTING:\r
1134 //\r
1135 // Validate the local address\r
1136 //\r
1137 switch ( pSockAddr->sa_family ) {\r
1138 default:\r
1139 DEBUG (( DEBUG_CONNECT,\r
1140 "ERROR - Invalid bind address family: %d\r\n",\r
1141 pSockAddr->sa_family ));\r
1142 Status = EFI_INVALID_PARAMETER;\r
1143 pSocket->errno = EADDRNOTAVAIL;\r
1144 break;\r
1145\r
1146 case AF_INET:\r
1147 //\r
1148 // Determine the connection point within the network stack\r
1149 //\r
1150 switch ( pSocket->Type ) {\r
1151 default:\r
1152 DEBUG (( DEBUG_CONNECT,\r
1153 "ERROR - Invalid socket type: %d\r\n",\r
1154 pSocket->Type));\r
1155 Status = EFI_INVALID_PARAMETER;\r
1156 pSocket->errno = EADDRNOTAVAIL;\r
1157 break;\r
1158\r
1159 case SOCK_STREAM:\r
1160 case SOCK_SEQPACKET:\r
1161 //\r
1162 // Determine if the connection processing is completed\r
1163 //\r
1164 Status = EslTcpConnectPoll4 ( pSocket );\r
1165\r
1166 //\r
1167 // Set the next state if connected\r
1168 //\r
1169 if ( EFI_NOT_READY != Status ) {\r
1170 if ( !EFI_ERROR ( Status )) {\r
1171 pSocket->State = SOCKET_STATE_CONNECTED;\r
1172 }\r
1173 else {\r
1174 pSocket->State = SOCKET_STATE_BOUND;\r
1175 }\r
1176 }\r
1177 break;\r
1178\r
1179 case SOCK_DGRAM:\r
1180 //\r
1181 // Already connected\r
1182 //\r
1183 pSocket->errno = EISCONN;\r
1184 Status = EFI_ALREADY_STARTED;\r
1185 break;\r
1186 }\r
1187 break;\r
1188 }\r
1189 break;\r
1190\r
1191 case SOCKET_STATE_CONNECTED:\r
1192 //\r
1193 // Already connected\r
1194 //\r
1195 pSocket->errno = EISCONN;\r
1196 Status = EFI_ALREADY_STARTED;\r
1197 break;\r
1198 }\r
1199\r
1200 //\r
1201 // Release the socket layer synchronization\r
1202 //\r
1203 RESTORE_TPL ( TplPrevious );\r
1204 }\r
1205 }\r
1206\r
1207 //\r
1208 // Return the operation status\r
1209 //\r
1210 if ( NULL != pErrno ) {\r
1211 if ( NULL != pSocket ) {\r
1212 *pErrno = pSocket->errno;\r
1213 }\r
1214 else\r
1215 {\r
1216 //\r
1217 // Bad socket protocol\r
1218 //\r
1219 DEBUG (( DEBUG_ERROR | DEBUG_CONNECT,\r
1220 "ERROR - pSocketProtocol invalid!\r\n" ));\r
1221 Status = EFI_INVALID_PARAMETER;\r
1222 *pErrno = EBADF;\r
1223 }\r
1224 }\r
1225\r
1226 //\r
1227 // Return the operation status\r
1228 //\r
1229 DEBUG (( DEBUG_CONNECT, "Exiting SocketConnect, Status: %r\r\n", Status ));\r
1230 return Status;\r
1231}\r
1232\r
1233\r
1234/**\r
1235 Creates a child handle and installs a protocol.\r
1236 \r
1237 The CreateChild() function installs a protocol on ChildHandle. \r
1238 If pChildHandle is a pointer to NULL, then a new handle is created and returned in pChildHandle. \r
1239 If pChildHandle is not a pointer to NULL, then the protocol installs on the existing pChildHandle.\r
1240\r
1241 @param [in] pThis Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
1242 @param [in] pChildHandle Pointer to the handle of the child to create. If it is NULL,\r
1243 then a new handle is created. If it is a pointer to an existing UEFI handle, \r
1244 then the protocol is added to the existing UEFI handle.\r
1245\r
1246 @retval EFI_SUCCESS The protocol was added to ChildHandle.\r
1247 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.\r
1248 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create\r
1249 the child\r
1250 @retval other The child handle was not created\r
1251\r
1252**/\r
1253EFI_STATUS\r
1254EFIAPI\r
1255EslSocketCreateChild (\r
1256 IN EFI_SERVICE_BINDING_PROTOCOL * pThis,\r
1257 IN OUT EFI_HANDLE * pChildHandle\r
1258 )\r
1259{\r
1260 DT_SOCKET * pSocket;\r
1261 EFI_STATUS Status;\r
1262\r
1263 DBG_ENTER ( );\r
1264\r
1265 //\r
1266 // Create a socket structure\r
1267 //\r
1268 Status = EslSocketAllocate ( pChildHandle,\r
1269 DEBUG_SOCKET,\r
1270 &pSocket );\r
1271\r
1272 //\r
1273 // Return the operation status\r
1274 //\r
1275 DBG_EXIT_STATUS ( Status );\r
1276 return Status;\r
1277}\r
1278\r
1279\r
1280/**\r
1281 Destroys a child handle with a protocol installed on it.\r
1282 \r
1283 The DestroyChild() function does the opposite of CreateChild(). It removes a protocol \r
1284 that was installed by CreateChild() from ChildHandle. If the removed protocol is the \r
1285 last protocol on ChildHandle, then ChildHandle is destroyed.\r
1286\r
1287 @param [in] pThis Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
1288 @param [in] ChildHandle Handle of the child to destroy\r
1289\r
1290 @retval EFI_SUCCESS The protocol was removed from ChildHandle.\r
1291 @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.\r
1292 @retval EFI_INVALID_PARAMETER Child handle is not a valid UEFI Handle.\r
1293 @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle\r
1294 because its services are being used.\r
1295 @retval other The child handle was not destroyed\r
1296\r
1297**/\r
1298EFI_STATUS\r
1299EFIAPI\r
1300EslSocketDestroyChild (\r
1301 IN EFI_SERVICE_BINDING_PROTOCOL * pThis,\r
1302 IN EFI_HANDLE ChildHandle\r
1303 )\r
1304{\r
1305 DT_LAYER * pLayer;\r
1306 DT_SOCKET * pSocket;\r
1307 DT_SOCKET * pSocketPrevious;\r
1308 EFI_SOCKET_PROTOCOL * pSocketProtocol;\r
1309 EFI_STATUS Status;\r
1310 EFI_TPL TplPrevious;\r
1311\r
1312 DBG_ENTER ( );\r
1313\r
1314 //\r
1315 // Locate the socket control structure\r
1316 //\r
1317 pLayer = &mEslLayer;\r
1318 Status = gBS->OpenProtocol (\r
1319 ChildHandle,\r
1320 &gEfiSocketProtocolGuid,\r
1321 (VOID **)&pSocketProtocol,\r
1322 pLayer->ImageHandle,\r
1323 NULL,\r
1324 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1325 );\r
1326 if ( !EFI_ERROR ( Status )) {\r
1327 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1328\r
1329 //\r
1330 // Synchronize with the socket layer\r
1331 //\r
1332 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1333\r
1334 //\r
1335 // Walk the socket list\r
1336 //\r
1337 pSocketPrevious = pLayer->pSocketList;\r
1338 if ( NULL != pSocketPrevious ) {\r
1339 if ( pSocket == pSocketPrevious ) {\r
1340 //\r
1341 // Remove the socket from the head of the list\r
1342 //\r
1343 pLayer->pSocketList = pSocket->pNext;\r
1344 }\r
1345 else {\r
1346 //\r
1347 // Find the socket in the middle of the list\r
1348 //\r
1349 while (( NULL != pSocketPrevious )\r
1350 && ( pSocket != pSocketPrevious->pNext )) {\r
1351 //\r
1352 // Set the next socket\r
1353 //\r
1354 pSocketPrevious = pSocketPrevious->pNext;\r
1355 }\r
1356 if ( NULL != pSocketPrevious ) {\r
1357 //\r
1358 // Remove the socket from the middle of the list\r
1359 //\r
1360 pSocketPrevious = pSocket->pNext;\r
1361 }\r
1362 }\r
1363 }\r
1364 else {\r
1365 DEBUG (( DEBUG_ERROR | DEBUG_POOL,\r
1366 "ERROR - Socket list is empty!\r\n" ));\r
1367 }\r
1368\r
1369 //\r
1370 // Release the socket layer synchronization\r
1371 //\r
1372 RESTORE_TPL ( TplPrevious );\r
1373\r
1374 //\r
1375 // Determine if the socket was found\r
1376 //\r
1377 if ( NULL != pSocketPrevious ) {\r
1378 pSocket->pNext = NULL;\r
1379\r
1380 //\r
1381 // Remove the socket protocol\r
1382 //\r
1383 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1384 ChildHandle,\r
1385 &gEfiSocketProtocolGuid,\r
1386 &pSocket->SocketProtocol,\r
1387 NULL );\r
1388 if ( !EFI_ERROR ( Status )) {\r
1389 DEBUG (( DEBUG_POOL | DEBUG_INFO,\r
1390 "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",\r
1391 ChildHandle ));\r
1392\r
1393 //\r
1394 // Free the socket structure\r
1395 //\r
1396 Status = gBS->FreePool ( pSocket );\r
1397 if ( !EFI_ERROR ( Status )) {\r
1398 DEBUG (( DEBUG_POOL,\r
1399 "0x%08x: Free pSocket, %d bytes\r\n",\r
1400 pSocket,\r
1401 sizeof ( *pSocket )));\r
1402 }\r
1403 else {\r
1404 DEBUG (( DEBUG_ERROR | DEBUG_POOL,\r
1405 "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",\r
1406 pSocket,\r
1407 Status ));\r
1408 }\r
1409 }\r
1410 else {\r
1411 DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INFO,\r
1412 "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",\r
1413 ChildHandle,\r
1414 Status ));\r
1415 }\r
1416 }\r
1417 else {\r
1418 DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
1419 "ERROR - The socket was not in the socket list!\r\n" ));\r
1420 Status = EFI_NOT_FOUND;\r
1421 }\r
1422 }\r
1423 else {\r
1424 DEBUG (( DEBUG_ERROR,\r
1425 "ERROR - Failed to open socket protocol on 0x%08x, Status; %r\r\n",\r
1426 ChildHandle,\r
1427 Status ));\r
1428 }\r
1429\r
1430 //\r
1431 // Return the operation status\r
1432 //\r
1433 DBG_EXIT_STATUS ( Status );\r
1434 return Status;\r
1435}\r
1436\r
1437\r
1438/**\r
1439 Get the local address.\r
1440\r
1441 @param [in] pSocketProtocol Address of the socket protocol structure.\r
1442 \r
1443 @param [out] pAddress Network address to receive the local system address\r
1444\r
1445 @param [in,out] pAddressLength Length of the local network address structure\r
1446\r
1447 @param [out] pErrno Address to receive the errno value upon completion.\r
1448\r
1449 @retval EFI_SUCCESS - Local address successfully returned\r
1450\r
1451 **/\r
1452EFI_STATUS\r
1453EslSocketGetLocalAddress (\r
1454 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1455 OUT struct sockaddr * pAddress,\r
1456 IN OUT socklen_t * pAddressLength,\r
1457 IN int * pErrno\r
1458 )\r
1459{\r
1460 DT_SOCKET * pSocket;\r
1461 EFI_STATUS Status;\r
1462 EFI_TPL TplPrevious;\r
1463 \r
1464 DBG_ENTER ( );\r
1465 \r
1466 //\r
1467 // Assume success\r
1468 //\r
1469 Status = EFI_SUCCESS;\r
1470 \r
1471 //\r
1472 // Validate the socket\r
1473 //\r
1474 pSocket = NULL;\r
1475 if ( NULL != pSocketProtocol ) {\r
1476 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1477\r
1478 //\r
1479 // Verify the address buffer and length address\r
1480 //\r
1481 if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
1482 //\r
1483 // Verify the socket state\r
1484 //\r
1485 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
1486 //\r
1487 // Synchronize with the socket layer\r
1488 //\r
1489 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1490\r
1491 //\r
1492 // Validate the local address\r
1493 //\r
1494 switch ( pSocket->Domain ) {\r
1495 default:\r
1496 DEBUG (( DEBUG_RX,\r
1497 "ERROR - Invalid socket address family: %d\r\n",\r
1498 pSocket->Domain ));\r
1499 Status = EFI_INVALID_PARAMETER;\r
1500 pSocket->errno = EADDRNOTAVAIL;\r
1501 break;\r
1502\r
1503 case AF_INET:\r
1504 //\r
1505 // Determine the connection point within the network stack\r
1506 //\r
1507 switch ( pSocket->Type ) {\r
1508 default:\r
1509 DEBUG (( DEBUG_RX,\r
1510 "ERROR - Invalid socket type: %d\r\n",\r
1511 pSocket->Type));\r
1512 Status = EFI_INVALID_PARAMETER;\r
1513 break;\r
1514\r
1515 case SOCK_STREAM:\r
1516 case SOCK_SEQPACKET:\r
1517 //\r
1518 // Get the local address\r
1519 //\r
1520 Status = EslTcpGetLocalAddress4 ( pSocket,\r
1521 pAddress,\r
1522 pAddressLength );\r
1523 break;\r
1524\r
1525 case SOCK_DGRAM:\r
1526 //\r
1527 // Get the local address\r
1528 //\r
1529 Status = EslUdpGetLocalAddress4 ( pSocket,\r
1530 pAddress,\r
1531 pAddressLength );\r
1532 break;\r
1533 }\r
1534 break;\r
1535 }\r
1536\r
1537 //\r
1538 // Release the socket layer synchronization\r
1539 //\r
1540 RESTORE_TPL ( TplPrevious );\r
1541 }\r
1542 else {\r
1543 pSocket->errno = ENOTCONN;\r
1544 Status = EFI_NOT_STARTED;\r
1545 }\r
1546 }\r
1547 else {\r
1548 pSocket->errno = EINVAL;\r
1549 Status = EFI_INVALID_PARAMETER;\r
1550 }\r
1551 }\r
1552 \r
1553 //\r
1554 // Return the operation status\r
1555 //\r
1556 if ( NULL != pErrno ) {\r
1557 if ( NULL != pSocket ) {\r
1558 *pErrno = pSocket->errno;\r
1559 }\r
1560 else\r
1561 {\r
1562 Status = EFI_INVALID_PARAMETER;\r
1563 *pErrno = EBADF;\r
1564 }\r
1565 }\r
1566 DBG_EXIT_STATUS ( Status );\r
1567 return Status;\r
1568}\r
1569\r
1570\r
1571/**\r
1572 Get the peer address.\r
1573\r
1574 @param [in] pSocketProtocol Address of the socket protocol structure.\r
1575 \r
1576 @param [out] pAddress Network address to receive the remote system address\r
1577\r
1578 @param [in,out] pAddressLength Length of the remote network address structure\r
1579\r
1580 @param [out] pErrno Address to receive the errno value upon completion.\r
1581\r
1582 @retval EFI_SUCCESS - Remote address successfully returned\r
1583\r
1584 **/\r
1585EFI_STATUS\r
1586EslSocketGetPeerAddress (\r
1587 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1588 OUT struct sockaddr * pAddress,\r
1589 IN OUT socklen_t * pAddressLength,\r
1590 IN int * pErrno\r
1591 )\r
1592{\r
1593 DT_SOCKET * pSocket;\r
1594 EFI_STATUS Status;\r
1595 EFI_TPL TplPrevious;\r
1596 \r
1597 DBG_ENTER ( );\r
1598 \r
1599 //\r
1600 // Assume success\r
1601 //\r
1602 Status = EFI_SUCCESS;\r
1603 \r
1604 //\r
1605 // Validate the socket\r
1606 //\r
1607 pSocket = NULL;\r
1608 if ( NULL != pSocketProtocol ) {\r
1609 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1610\r
1611 //\r
1612 // Verify the address buffer and length address\r
1613 //\r
1614 if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
1615 //\r
1616 // Verify the socket state\r
1617 //\r
1618 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
1619 //\r
1620 // Synchronize with the socket layer\r
1621 //\r
1622 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1623\r
1624 //\r
1625 // Validate the local address\r
1626 //\r
1627 switch ( pSocket->Domain ) {\r
1628 default:\r
1629 DEBUG (( DEBUG_RX,\r
1630 "ERROR - Invalid socket address family: %d\r\n",\r
1631 pSocket->Domain ));\r
1632 Status = EFI_INVALID_PARAMETER;\r
1633 pSocket->errno = EADDRNOTAVAIL;\r
1634 break;\r
1635\r
1636 case AF_INET:\r
1637 //\r
1638 // Determine the connection point within the network stack\r
1639 //\r
1640 switch ( pSocket->Type ) {\r
1641 default:\r
1642 DEBUG (( DEBUG_RX,\r
1643 "ERROR - Invalid socket type: %d\r\n",\r
1644 pSocket->Type));\r
1645 Status = EFI_INVALID_PARAMETER;\r
1646 break;\r
1647\r
1648 case SOCK_STREAM:\r
1649 case SOCK_SEQPACKET:\r
1650 //\r
1651 // Verify the port state\r
1652 //\r
1653 Status = EslTcpGetRemoteAddress4 ( pSocket,\r
1654 pAddress,\r
1655 pAddressLength );\r
1656 break;\r
1657\r
1658 case SOCK_DGRAM:\r
1659 //\r
1660 // Verify the port state\r
1661 //\r
1662 Status = EslUdpGetRemoteAddress4 ( pSocket,\r
1663 pAddress,\r
1664 pAddressLength );\r
1665 break;\r
1666 }\r
1667 break;\r
1668 }\r
1669\r
1670 //\r
1671 // Release the socket layer synchronization\r
1672 //\r
1673 RESTORE_TPL ( TplPrevious );\r
1674 }\r
1675 else {\r
1676 pSocket->errno = ENOTCONN;\r
1677 Status = EFI_NOT_STARTED;\r
1678 }\r
1679 }\r
1680 else {\r
1681 pSocket->errno = EINVAL;\r
1682 Status = EFI_INVALID_PARAMETER;\r
1683 }\r
1684 }\r
1685 \r
1686 //\r
1687 // Return the operation status\r
1688 //\r
1689 if ( NULL != pErrno ) {\r
1690 if ( NULL != pSocket ) {\r
1691 *pErrno = pSocket->errno;\r
1692 }\r
1693 else\r
1694 {\r
1695 Status = EFI_INVALID_PARAMETER;\r
1696 *pErrno = EBADF;\r
1697 }\r
1698 }\r
1699 DBG_EXIT_STATUS ( Status );\r
1700 return Status;\r
1701}\r
1702\r
1703\r
1704/**\r
1705 Establish the known port to listen for network connections.\r
1706\r
1707 The ::SocketListen routine places the port into a state that enables connection\r
1708 attempts. Connections are placed into FIFO order in a queue to be serviced\r
1709 by the application. The application calls the ::SocketAccept routine to remove\r
1710 the next connection from the queue and get the associated socket. The\r
1711 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>\r
1712 documentation for the listen routine is available online for reference.\r
1713\r
1714 @param [in] pSocketProtocol Address of the socket protocol structure.\r
1715\r
1716 @param [in] Backlog Backlog specifies the maximum FIFO depth for\r
1717 the connections waiting for the application\r
1718 to call accept. Connection attempts received\r
1719 while the queue is full are refused.\r
1720\r
1721 @param [out] pErrno Address to receive the errno value upon completion.\r
1722\r
1723 @retval EFI_SUCCESS - Socket successfully created\r
1724 @retval Other - Failed to enable the socket for listen\r
1725\r
1726**/\r
1727EFI_STATUS\r
1728EslSocketListen (\r
1729 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1730 IN INT32 Backlog,\r
1731 OUT int * pErrno\r
1732 )\r
1733{\r
1734 DT_SOCKET * pSocket;\r
1735 EFI_STATUS Status;\r
1736 EFI_STATUS TempStatus;\r
1737 EFI_TPL TplPrevious;\r
1738\r
1739 DBG_ENTER ( );\r
1740\r
1741 //\r
1742 // Assume success\r
1743 //\r
1744 Status = EFI_SUCCESS;\r
1745\r
1746 //\r
1747 // Validate the socket\r
1748 //\r
1749 pSocket = NULL;\r
1750 if ( NULL != pSocketProtocol ) {\r
1751 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1752\r
1753 //\r
1754 // Assume success\r
1755 //\r
1756 pSocket->Status = EFI_SUCCESS;\r
1757 pSocket->errno = 0;\r
1758\r
1759 //\r
1760 // Verify that the bind operation was successful\r
1761 //\r
1762 if ( SOCKET_STATE_BOUND == pSocket->State ) {\r
1763 //\r
1764 // Synchronize with the socket layer\r
1765 //\r
1766 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1767\r
1768 //\r
1769 // Create the event for SocketAccept completion\r
1770 //\r
1771 Status = gBS->CreateEvent ( 0,\r
1772 TplPrevious,\r
1773 NULL,\r
1774 NULL,\r
1775 &pSocket->WaitAccept );\r
1776 if ( !EFI_ERROR ( Status )) {\r
1777 DEBUG (( DEBUG_POOL,\r
1778 "0x%08x: Created WaitAccept event\r\n",\r
1779 pSocket->WaitAccept ));\r
1780 //\r
1781 // Set the maximum FIFO depth\r
1782 //\r
1783 if ( 0 >= Backlog ) {\r
1784 Backlog = MAX_PENDING_CONNECTIONS;\r
1785 }\r
1786 else {\r
1787 if ( SOMAXCONN < Backlog ) {\r
1788 Backlog = SOMAXCONN;\r
1789 }\r
1790 else {\r
1791 pSocket->MaxFifoDepth = Backlog;\r
1792 }\r
1793 }\r
1794\r
1795 //\r
1796 // Validate the local address\r
1797 //\r
1798 switch ( pSocket->Domain ) {\r
1799 default:\r
1800 DEBUG (( DEBUG_BIND,\r
1801 "ERROR - Invalid socket address family: %d\r\n",\r
1802 pSocket->Domain ));\r
1803 Status = EFI_INVALID_PARAMETER;\r
1804 pSocket->errno = EADDRNOTAVAIL;\r
1805 break;\r
1806\r
1807 case AF_INET:\r
1808 //\r
1809 // Determine the connection point within the network stack\r
1810 //\r
1811 switch ( pSocket->Type ) {\r
1812 default:\r
1813 DEBUG (( DEBUG_BIND,\r
1814 "ERROR - Invalid socket type: %d\r\n",\r
1815 pSocket->Type));\r
1816 Status = EFI_INVALID_PARAMETER;\r
1817 pSocket->errno = EADDRNOTAVAIL;\r
1818 break;\r
1819\r
1820 case SOCK_STREAM:\r
1821 case SOCK_SEQPACKET:\r
1822 Status = EslTcpListen4 ( pSocket );\r
1823 break;\r
1824\r
1825/*\r
1826 case SOCK_DGRAM:\r
1827 Status = UdpListen4 ( pSocket );\r
1828 break;\r
1829*/\r
1830 }\r
1831 break;\r
1832 }\r
1833\r
1834 //\r
1835 // Place the socket in the listen state if successful\r
1836 //\r
1837 if ( !EFI_ERROR ( Status )) {\r
1838 pSocket->State = SOCKET_STATE_LISTENING;\r
1839 }\r
1840 else {\r
1841 //\r
1842 // Not waiting for SocketAccept to complete\r
1843 //\r
1844 TempStatus = gBS->CloseEvent ( pSocket->WaitAccept );\r
1845 if ( !EFI_ERROR ( TempStatus )) {\r
1846 DEBUG (( DEBUG_POOL,\r
1847 "0x%08x: Closed WaitAccept event\r\n",\r
1848 pSocket->WaitAccept ));\r
1849 pSocket->WaitAccept = NULL;\r
1850 }\r
1851 else {\r
1852 DEBUG (( DEBUG_ERROR | DEBUG_POOL,\r
1853 "ERROR - Failed to close WaitAccept event, Status: %r\r\n",\r
1854 TempStatus ));\r
1855 ASSERT ( EFI_SUCCESS == TempStatus );\r
1856 }\r
1857 }\r
1858 }\r
1859 else {\r
1860 DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,\r
1861 "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",\r
1862 Status ));\r
1863 pSocket->errno = ENOMEM;\r
1864 }\r
1865\r
1866 //\r
1867 // Release the socket layer synchronization\r
1868 //\r
1869 RESTORE_TPL ( TplPrevious );\r
1870 }\r
1871 else {\r
1872 DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,\r
1873 "ERROR - Bind operation must be performed first!\r\n" ));\r
1874 pSocket->errno = EDESTADDRREQ;\r
1875 }\r
1876 }\r
1877\r
1878 //\r
1879 // Return the operation status\r
1880 //\r
1881 if ( NULL != pErrno ) {\r
1882 if ( NULL != pSocket ) {\r
1883 *pErrno = pSocket->errno;\r
1884 }\r
1885 else\r
1886 {\r
1887 Status = EFI_INVALID_PARAMETER;\r
1888 *pErrno = EBADF;\r
1889 }\r
1890 }\r
1891 DBG_EXIT_STATUS ( Status );\r
1892 return Status;\r
1893}\r
1894\r
1895\r
1896/**\r
1897 Get the socket options\r
1898\r
1899 Retrieve the socket options one at a time by name. The\r
1900 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html">POSIX</a>\r
1901 documentation is available online.\r
1902\r
1903 @param [in] pSocketProtocol Address of the socket protocol structure.\r
1904 @param [in] level Option protocol level\r
1905 @param [in] OptionName Name of the option\r
1906 @param [out] pOptionValue Buffer to receive the option value\r
1907 @param [in,out] pOptionLength Length of the buffer in bytes,\r
1908 upon return length of the option value in bytes\r
1909 @param [out] pErrno Address to receive the errno value upon completion.\r
1910\r
1911 @retval EFI_SUCCESS - Socket data successfully received\r
1912\r
1913 **/\r
1914EFI_STATUS\r
1915EslSocketOptionGet (\r
1916 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1917 IN int level,\r
1918 IN int OptionName,\r
1919 OUT void * __restrict pOptionValue,\r
1920 IN OUT socklen_t * __restrict pOptionLength,\r
1921 IN int * pErrno\r
1922 )\r
1923{\r
1924 int errno;\r
1925 socklen_t LengthInBytes;\r
1926 socklen_t MaxBytes;\r
1927 UINT8 * pOptionData;\r
1928 DT_SOCKET * pSocket;\r
1929 EFI_STATUS Status;\r
1930\r
1931 DBG_ENTER ( );\r
1932\r
1933 //\r
1934 // Assume failure\r
1935 //\r
1936 errno = EINVAL;\r
1937 Status = EFI_INVALID_PARAMETER;\r
1938\r
1939 //\r
1940 // Validate the socket\r
1941 //\r
1942 pSocket = NULL;\r
1943 if (( NULL != pSocketProtocol )\r
1944 && ( NULL != pOptionValue )\r
1945 && ( NULL != pOptionLength )) {\r
1946 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1947 LengthInBytes = 0;\r
1948 MaxBytes = *pOptionLength;\r
1949 pOptionData = NULL;\r
1950 switch ( level ) {\r
1951 default:\r
1952 //\r
1953 // Protocol level not supported\r
1954 //\r
1955 errno = ENOTSUP;\r
1956 Status = EFI_UNSUPPORTED;\r
1957 break;\r
1958\r
1959 case SOL_SOCKET:\r
1960 switch ( OptionName ) {\r
1961 default:\r
1962 //\r
1963 // Option not supported\r
1964 //\r
1965 errno = ENOTSUP;\r
1966 Status = EFI_UNSUPPORTED;\r
1967 break;\r
1968\r
1969 case SO_RCVTIMEO:\r
1970 //\r
1971 // Return the receive timeout\r
1972 //\r
1973 pOptionData = (UINT8 *)&pSocket->RxTimeout;\r
1974 LengthInBytes = sizeof ( pSocket->RxTimeout );\r
1975 break;\r
1976 \r
1977 case SO_RCVBUF:\r
1978 //\r
1979 // Return the maximum transmit buffer size\r
1980 //\r
1981 pOptionData = (UINT8 *)&pSocket->MaxRxBuf;\r
1982 LengthInBytes = sizeof ( pSocket->MaxRxBuf );\r
1983 break;\r
1984\r
1985 case SO_SNDBUF:\r
1986 //\r
1987 // Return the maximum transmit buffer size\r
1988 //\r
1989 pOptionData = (UINT8 *)&pSocket->MaxTxBuf;\r
1990 LengthInBytes = sizeof ( pSocket->MaxTxBuf );\r
1991 break;\r
1992\r
1993 case SO_TYPE:\r
1994 //\r
1995 // Return the socket type\r
1996 //\r
1997 pOptionData = (UINT8 *)&pSocket->Type;\r
1998 LengthInBytes = sizeof ( pSocket->Type );\r
1999 break;\r
2000 }\r
2001 break;\r
2002 }\r
2003\r
2004 //\r
2005 // Return the option length\r
2006 //\r
2007 *pOptionLength = LengthInBytes;\r
2008\r
2009 //\r
2010 // Return the option value\r
2011 //\r
2012 if ( NULL != pOptionData ) {\r
2013 //\r
2014 // Silently truncate the value length\r
2015 //\r
2016 if ( LengthInBytes > MaxBytes ) {\r
2017 LengthInBytes = MaxBytes;\r
2018 }\r
2019 CopyMem ( pOptionValue, pOptionData, LengthInBytes );\r
2020 errno = 0;\r
2021 Status = EFI_SUCCESS;\r
2022 }\r
2023 }\r
2024\r
2025 //\r
2026 // Return the operation status\r
2027 //\r
2028 if ( NULL != pErrno ) {\r
2029 *pErrno = errno;\r
2030 }\r
2031 DBG_EXIT_STATUS ( Status );\r
2032 return Status;\r
2033}\r
2034\r
2035\r
2036/**\r
2037 Set the socket options\r
2038\r
2039 Adjust the socket options one at a time by name. The\r
2040 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html">POSIX</a>\r
2041 documentation is available online.\r
2042\r
2043 @param [in] pSocketProtocol Address of the socket protocol structure.\r
2044 @param [in] level Option protocol level\r
2045 @param [in] OptionName Name of the option\r
2046 @param [in] pOptionValue Buffer containing the option value\r
2047 @param [in] OptionLength Length of the buffer in bytes\r
2048 @param [out] pErrno Address to receive the errno value upon completion.\r
2049\r
2050 @retval EFI_SUCCESS - Socket data successfully received\r
2051\r
2052 **/\r
2053EFI_STATUS\r
2054EslSocketOptionSet (\r
2055 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
2056 IN int level,\r
2057 IN int OptionName,\r
2058 IN CONST void * pOptionValue,\r
2059 IN socklen_t OptionLength,\r
2060 IN int * pErrno\r
2061 )\r
2062{\r
2063 int errno;\r
2064 socklen_t LengthInBytes;\r
2065 UINT8 * pOptionData;\r
2066 DT_SOCKET * pSocket;\r
2067 EFI_STATUS Status;\r
2068 \r
2069 DBG_ENTER ( );\r
2070 \r
2071 //\r
2072 // Assume failure\r
2073 //\r
2074 errno = EINVAL;\r
2075 Status = EFI_INVALID_PARAMETER;\r
2076 \r
2077 //\r
2078 // Validate the socket\r
2079 //\r
2080 pSocket = NULL;\r
2081 if (( NULL != pSocketProtocol )\r
2082 && ( NULL != pOptionValue )) {\r
2083 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
2084 LengthInBytes = 0;\r
2085 pOptionData = NULL;\r
2086 switch ( level ) {\r
2087 default:\r
2088 //\r
2089 // Protocol level not supported\r
2090 //\r
2091 errno = ENOTSUP;\r
2092 Status = EFI_UNSUPPORTED;\r
2093 break;\r
2094 \r
2095 case SOL_SOCKET:\r
2096 switch ( OptionName ) {\r
2097 default:\r
2098 //\r
2099 // Option not supported\r
2100 //\r
2101 errno = ENOTSUP;\r
2102 Status = EFI_UNSUPPORTED;\r
2103 break;\r
2104 \r
2105 case SO_RCVTIMEO:\r
2106 //\r
2107 // Return the receive timeout\r
2108 //\r
2109 pOptionData = (UINT8 *)&pSocket->RxTimeout;\r
2110 LengthInBytes = sizeof ( pSocket->RxTimeout );\r
2111 break;\r
2112\r
2113 case SO_RCVBUF:\r
2114 //\r
2115 // Return the maximum transmit buffer size\r
2116 //\r
2117 pOptionData = (UINT8 *)&pSocket->MaxRxBuf;\r
2118 LengthInBytes = sizeof ( pSocket->MaxRxBuf );\r
2119 break;\r
2120\r
2121 case SO_SNDBUF:\r
2122 //\r
2123 // Send buffer size\r
2124 //\r
2125 //\r
2126 // Return the maximum transmit buffer size\r
2127 //\r
2128 pOptionData = (UINT8 *)&pSocket->MaxTxBuf;\r
2129 LengthInBytes = sizeof ( pSocket->MaxTxBuf );\r
2130 break;\r
2131 }\r
2132 break;\r
2133 }\r
2134\r
2135 //\r
2136 // Validate the option length\r
2137 //\r
2138 if ( LengthInBytes <= OptionLength ) {\r
2139 //\r
2140 // Set the option value\r
2141 //\r
2142 if ( NULL != pOptionData ) {\r
2143 CopyMem ( pOptionData, pOptionValue, LengthInBytes );\r
2144 errno = 0;\r
2145 Status = EFI_SUCCESS;\r
2146 }\r
2147 }\r
2148 }\r
2149 \r
2150 //\r
2151 // Return the operation status\r
2152 //\r
2153 if ( NULL != pErrno ) {\r
2154 *pErrno = errno;\r
2155 }\r
2156 DBG_EXIT_STATUS ( Status );\r
2157 return Status;\r
2158}\r
2159\r
2160\r
2161/**\r
2162 Allocate a packet for a receive or transmit operation\r
2163\r
2164 @param [in] ppPacket Address to receive the DT_PACKET structure\r
2165 @param [in] LengthInBytes Length of the packet structure\r
2166 @param [in] DebugFlags Flags for debug messages\r
2167\r
2168 @retval EFI_SUCCESS - The packet was allocated successfully\r
2169\r
2170 **/\r
2171EFI_STATUS\r
2172EslSocketPacketAllocate (\r
2173 IN DT_PACKET ** ppPacket,\r
2174 IN size_t LengthInBytes,\r
2175 IN UINTN DebugFlags\r
2176 )\r
2177{\r
2178 DT_PACKET * pPacket;\r
2179 EFI_STATUS Status;\r
2180\r
2181 DBG_ENTER ( );\r
2182\r
2183 //\r
2184 // Allocate a packet structure\r
2185 //\r
2186 LengthInBytes += sizeof ( *pPacket )\r
2187 - sizeof ( pPacket->Op );\r
2188 Status = gBS->AllocatePool ( EfiRuntimeServicesData,\r
2189 LengthInBytes,\r
2190 (VOID **)&pPacket );\r
2191 if ( !EFI_ERROR ( Status )) {\r
2192 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
2193 "0x%08x: Allocate pPacket, %d bytes\r\n",\r
2194 pPacket,\r
2195 LengthInBytes ));\r
2196 pPacket->PacketSize = LengthInBytes;\r
2197 }\r
2198 else {\r
2199 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,\r
2200 "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",\r
2201 LengthInBytes,\r
2202 Status ));\r
2203 pPacket = NULL;\r
2204 }\r
2205\r
2206 //\r
2207 // Return the packet\r
2208 //\r
2209 *ppPacket = pPacket;\r
2210\r
2211 //\r
2212 // Return the operation status\r
2213 //\r
2214 DBG_EXIT_STATUS ( Status );\r
2215 return Status;\r
2216}\r
2217\r
2218\r
2219/**\r
2220 Free a packet used for receive or transmit operation\r
2221\r
2222 @param [in] pPacket Address of the DT_PACKET structure\r
2223 @param [in] DebugFlags Flags for debug messages\r
2224\r
2225 @retval EFI_SUCCESS - The packet was allocated successfully\r
2226\r
2227 **/\r
2228EFI_STATUS\r
2229EslSocketPacketFree (\r
2230 IN DT_PACKET * pPacket,\r
2231 IN UINTN DebugFlags\r
2232 )\r
2233{\r
2234 UINTN LengthInBytes;\r
2235 EFI_STATUS Status;\r
2236\r
2237 DBG_ENTER ( );\r
2238\r
2239 //\r
2240 // Allocate a packet structure\r
2241 //\r
2242 LengthInBytes = pPacket->PacketSize;\r
2243 Status = gBS->FreePool ( pPacket );\r
2244 if ( !EFI_ERROR ( Status )) {\r
2245 DEBUG (( DebugFlags | DEBUG_POOL,\r
2246 "0x%08x: Free pPacket, %d bytes\r\n",\r
2247 pPacket,\r
2248 LengthInBytes ));\r
2249 }\r
2250 else {\r
2251 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,\r
2252 "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",\r
2253 pPacket,\r
2254 Status ));\r
2255 }\r
2256\r
2257 //\r
2258 // Return the operation status\r
2259 //\r
2260 DBG_EXIT_STATUS ( Status );\r
2261 return Status;\r
2262}\r
2263\r
2264\r
2265/**\r
2266 Poll a socket for pending activity.\r
2267\r
2268 The SocketPoll routine checks a socket for pending activity associated\r
2269 with the event mask. Activity is returned in the detected event buffer.\r
2270\r
2271 @param [in] pSocketProtocol Address of the socket protocol structure.\r
2272\r
2273 @param [in] Events Events of interest for this socket\r
2274\r
2275 @param [in] pEvents Address to receive the detected events\r
2276\r
2277 @param [out] pErrno Address to receive the errno value upon completion.\r
2278\r
2279 @retval EFI_SUCCESS - Socket successfully polled\r
2280 @retval EFI_INVALID_PARAMETER - When pEvents is NULL\r
2281\r
2282 **/\r
2283EFI_STATUS\r
2284EslSocketPoll (\r
2285 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
2286 IN short Events,\r
2287 IN short * pEvents,\r
2288 IN int * pErrno\r
2289 )\r
2290{\r
2291 short DetectedEvents;\r
2292 DT_SOCKET * pSocket;\r
2293 EFI_STATUS Status;\r
2294 EFI_TPL TplPrevious;\r
2295 short ValidEvents;\r
2296\r
2297 DEBUG (( DEBUG_POLL, "Entering SocketPoll\r\n" ));\r
2298\r
2299 //\r
2300 // Assume success\r
2301 //\r
2302 Status = EFI_SUCCESS;\r
2303 DetectedEvents = 0;\r
2304 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
2305 pSocket->errno = 0;\r
2306\r
2307 //\r
2308 // Verify the socket state\r
2309 //\r
2310 if ( !pSocket->bConfigured ) {\r
2311 //\r
2312 // Synchronize with the socket layer\r
2313 //\r
2314 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2315\r
2316 //\r
2317 // Validate the local address\r
2318 //\r
2319 switch ( pSocket->Domain ) {\r
2320 default:\r
2321 DEBUG (( DEBUG_RX,\r
2322 "ERROR - Invalid socket address family: %d\r\n",\r
2323 pSocket->Domain ));\r
2324 Status = EFI_INVALID_PARAMETER;\r
2325 pSocket->errno = EADDRNOTAVAIL;\r
2326 break;\r
2327\r
2328 case AF_INET:\r
2329 //\r
2330 // Determine the connection point within the network stack\r
2331 //\r
2332 switch ( pSocket->Type ) {\r
2333 default:\r
2334 DEBUG (( DEBUG_RX,\r
2335 "ERROR - Invalid socket type: %d\r\n",\r
2336 pSocket->Type));\r
2337 Status = EFI_INVALID_PARAMETER;\r
2338 pSocket->errno = EADDRNOTAVAIL;\r
2339 break;\r
2340\r
2341 case SOCK_STREAM:\r
2342 case SOCK_SEQPACKET:\r
2343 //\r
2344 // Verify the port state\r
2345 //\r
2346 Status = EslTcpSocketIsConfigured4 ( pSocket );\r
2347 break;\r
2348\r
2349 case SOCK_DGRAM:\r
2350 //\r
2351 // Verify the port state\r
2352 //\r
2353 Status = EslUdpSocketIsConfigured4 ( pSocket );\r
2354 break;\r
2355 }\r
2356 break;\r
2357 }\r
2358\r
2359 //\r
2360 // Release the socket layer synchronization\r
2361 //\r
2362 RESTORE_TPL ( TplPrevious );\r
2363 }\r
2364 if ( !EFI_ERROR ( Status )) {\r
2365 //\r
2366 // Check for invalid events\r
2367 //\r
2368 ValidEvents = POLLIN\r
2369 | POLLPRI\r
2370 | POLLOUT | POLLWRNORM\r
2371 | POLLERR\r
2372 | POLLHUP\r
2373 | POLLNVAL\r
2374 | POLLRDNORM\r
2375 | POLLRDBAND\r
2376 | POLLWRBAND ;\r
2377 if ( 0 != ( Events & ( ~ValidEvents ))) {\r
2378 DetectedEvents |= POLLNVAL;\r
2379 DEBUG (( DEBUG_INFO | DEBUG_POLL,\r
2380 "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",\r
2381 Events & ValidEvents,\r
2382 Events & ( ~ValidEvents )));\r
2383 }\r
2384 else {\r
2385 //\r
2386 // Check for pending connections\r
2387 //\r
2388 if ( 0 != pSocket->FifoDepth ) {\r
2389 //\r
2390 // A connection is waiting for an accept call\r
2391 // See posix connect documentation at\r
2392 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm\r
2393 //\r
2394 DetectedEvents |= POLLIN | POLLRDNORM;\r
2395 }\r
2396 if ( pSocket->bConnected ) {\r
2397 //\r
2398 // A connection is present\r
2399 // See posix connect documentation at\r
2400 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm\r
2401 //\r
2402 DetectedEvents |= POLLOUT | POLLWRNORM;\r
2403 }\r
2404\r
2405 //\r
2406 // The following bits are set based upon the POSIX poll documentation at\r
2407 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html\r
2408 //\r
2409\r
2410 //\r
2411 // Check for urgent receive data\r
2412 //\r
2413 if ( 0 < pSocket->RxOobBytes ) {\r
2414 DetectedEvents |= POLLRDBAND | POLLPRI | POLLIN;\r
2415 }\r
2416\r
2417 //\r
2418 // Check for normal receive data\r
2419 //\r
2420 if (( 0 < pSocket->RxBytes )\r
2421 || ( EFI_SUCCESS != pSocket->RxError )) {\r
2422 DetectedEvents |= POLLRDNORM | POLLIN;\r
2423 }\r
2424\r
2425 //\r
2426 // Handle the receive errors\r
2427 //\r
2428 if (( EFI_SUCCESS != pSocket->RxError )\r
2429 && ( 0 == ( DetectedEvents & POLLIN ))) {\r
2430 DetectedEvents |= POLLERR | POLLIN | POLLRDNORM | POLLRDBAND;\r
2431 }\r
2432\r
2433 //\r
2434 // Check for urgent transmit data buffer space\r
2435 //\r
2436 if (( MAX_TX_DATA > pSocket->TxOobBytes )\r
2437 || ( EFI_SUCCESS != pSocket->TxError )) {\r
2438 DetectedEvents |= POLLWRBAND;\r
2439 }\r
2440\r
2441 //\r
2442 // Check for normal transmit data buffer space\r
2443 //\r
2444 if (( MAX_TX_DATA > pSocket->TxBytes )\r
2445 || ( EFI_SUCCESS != pSocket->TxError )) {\r
2446 DetectedEvents |= POLLWRNORM;\r
2447 }\r
2448\r
2449 //\r
2450 // Handle the transmit error\r
2451 //\r
2452 if ( EFI_ERROR ( pSocket->TxError )) {\r
2453 DetectedEvents |= POLLERR;\r
2454 }\r
2455 }\r
2456 }\r
2457\r
2458 //\r
2459 // Return the detected events\r
2460 //\r
2461 *pEvents = DetectedEvents & ( Events\r
2462 | POLLERR\r
2463 | POLLHUP\r
2464 | POLLNVAL );\r
2465\r
2466 //\r
2467 // Return the operation status\r
2468 //\r
2469 DEBUG (( DEBUG_POLL, "Exiting SocketPoll, Status: %r\r\n", Status ));\r
2470 return Status;\r
2471}\r
2472\r
2473\r
2474/**\r
2475 Receive data from a network connection.\r
2476\r
2477\r
2478 @param [in] pSocketProtocol Address of the socket protocol structure.\r
2479 \r
2480 @param [in] Flags Message control flags\r
2481 \r
2482 @param [in] BufferLength Length of the the buffer\r
2483 \r
2484 @param [in] pBuffer Address of a buffer to receive the data.\r
2485 \r
2486 @param [in] pDataLength Number of received data bytes in the buffer.\r
2487\r
2488 @param [out] pAddress Network address to receive the remote system address\r
2489\r
2490 @param [in,out] pAddressLength Length of the remote network address structure\r
2491\r
2492 @param [out] pErrno Address to receive the errno value upon completion.\r
2493\r
2494 @retval EFI_SUCCESS - Socket data successfully received\r
2495\r
2496 **/\r
2497EFI_STATUS\r
2498EslSocketReceive (\r
2499 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
2500 IN INT32 Flags,\r
2501 IN size_t BufferLength,\r
2502 IN UINT8 * pBuffer,\r
2503 OUT size_t * pDataLength,\r
2504 OUT struct sockaddr * pAddress,\r
2505 IN OUT socklen_t * pAddressLength,\r
2506 IN int * pErrno\r
2507 )\r
2508{\r
2509 DT_SOCKET * pSocket;\r
2510 EFI_STATUS Status;\r
2511 EFI_TPL TplPrevious;\r
2512\r
2513 DBG_ENTER ( );\r
2514\r
2515 //\r
2516 // Assume success\r
2517 //\r
2518 Status = EFI_SUCCESS;\r
2519\r
2520 //\r
2521 // Validate the socket\r
2522 //\r
2523 pSocket = NULL;\r
2524 if ( NULL != pSocketProtocol ) {\r
2525 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
2526\r
2527 //\r
1c34b250 2528 // Return the transmit error if necessary\r
d7ce7006 2529 //\r
1c34b250 2530 if ( EFI_SUCCESS != pSocket->TxError ) {\r
2531 pSocket->errno = EIO;\r
2532 Status = pSocket->TxError;\r
2533 pSocket->TxError = EFI_SUCCESS;\r
d7ce7006 2534 }\r
1c34b250 2535 else {\r
d7ce7006 2536 //\r
1c34b250 2537 // Verify the socket state\r
d7ce7006 2538 //\r
1c34b250 2539 if ( !pSocket->bConfigured ) {\r
d7ce7006 2540 //\r
2541 // Synchronize with the socket layer\r
2542 //\r
2543 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2544\r
2545 //\r
2546 // Validate the local address\r
2547 //\r
2548 switch ( pSocket->Domain ) {\r
2549 default:\r
2550 DEBUG (( DEBUG_RX,\r
2551 "ERROR - Invalid socket address family: %d\r\n",\r
2552 pSocket->Domain ));\r
2553 Status = EFI_INVALID_PARAMETER;\r
2554 pSocket->errno = EADDRNOTAVAIL;\r
2555 break;\r
2556\r
2557 case AF_INET:\r
2558 //\r
2559 // Determine the connection point within the network stack\r
2560 //\r
2561 switch ( pSocket->Type ) {\r
2562 default:\r
2563 DEBUG (( DEBUG_RX,\r
2564 "ERROR - Invalid socket type: %d\r\n",\r
2565 pSocket->Type));\r
2566 Status = EFI_INVALID_PARAMETER;\r
d7ce7006 2567 break;\r
2568\r
2569 case SOCK_STREAM:\r
2570 case SOCK_SEQPACKET:\r
1c34b250 2571 //\r
2572 // Verify the port state\r
2573 //\r
2574 Status = EslTcpSocketIsConfigured4 ( pSocket );\r
d7ce7006 2575 break;\r
2576\r
2577 case SOCK_DGRAM:\r
1c34b250 2578 //\r
2579 // Verify the port state\r
2580 //\r
2581 Status = EslUdpSocketIsConfigured4 ( pSocket );\r
d7ce7006 2582 break;\r
2583 }\r
2584 break;\r
2585 }\r
2586\r
2587 //\r
2588 // Release the socket layer synchronization\r
2589 //\r
2590 RESTORE_TPL ( TplPrevious );\r
1c34b250 2591\r
2592 //\r
2593 // Set errno if a failure occurs\r
2594 //\r
2595 if ( EFI_ERROR ( Status )) {\r
2596 pSocket->errno = EADDRNOTAVAIL;\r
2597 }\r
2598 }\r
2599 if ( !EFI_ERROR ( Status )) {\r
2600 //\r
2601 // Validate the buffer length\r
2602 //\r
2603 if (( NULL == pDataLength )\r
2604 && ( 0 > pDataLength )\r
2605 && ( NULL == pBuffer )) {\r
2606 if ( NULL == pDataLength ) {\r
2607 DEBUG (( DEBUG_RX,\r
2608 "ERROR - pDataLength is NULL!\r\n" ));\r
2609 }\r
2610 else if ( NULL == pBuffer ) {\r
2611 DEBUG (( DEBUG_RX,\r
2612 "ERROR - pBuffer is NULL!\r\n" ));\r
2613 }\r
2614 else {\r
2615 DEBUG (( DEBUG_RX,\r
2616 "ERROR - Data length < 0!\r\n" ));\r
2617 }\r
2618 Status = EFI_INVALID_PARAMETER;\r
2619 pSocket->errno = EFAULT;\r
2620 }\r
2621 else{\r
2622 //\r
2623 // Synchronize with the socket layer\r
2624 //\r
2625 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2626\r
2627 //\r
2628 // Validate the local address\r
2629 //\r
2630 switch ( pSocket->Domain ) {\r
2631 default:\r
2632 DEBUG (( DEBUG_RX,\r
2633 "ERROR - Invalid socket address family: %d\r\n",\r
2634 pSocket->Domain ));\r
2635 Status = EFI_INVALID_PARAMETER;\r
2636 pSocket->errno = EADDRNOTAVAIL;\r
2637 break;\r
2638\r
2639 case AF_INET:\r
2640 //\r
2641 // Determine the connection point within the network stack\r
2642 //\r
2643 switch ( pSocket->Type ) {\r
2644 default:\r
2645 DEBUG (( DEBUG_RX,\r
2646 "ERROR - Invalid socket type: %d\r\n",\r
2647 pSocket->Type));\r
2648 Status = EFI_INVALID_PARAMETER;\r
2649 pSocket->errno = EADDRNOTAVAIL;\r
2650 break;\r
2651\r
2652 case SOCK_STREAM:\r
2653 case SOCK_SEQPACKET:\r
2654 Status = EslTcpReceive4 ( pSocket,\r
2655 Flags,\r
2656 BufferLength,\r
2657 pBuffer,\r
2658 pDataLength,\r
2659 pAddress,\r
2660 pAddressLength );\r
2661 break;\r
2662\r
2663 case SOCK_DGRAM:\r
2664 Status = EslUdpReceive4 ( pSocket,\r
2665 Flags,\r
2666 BufferLength,\r
2667 pBuffer,\r
2668 pDataLength,\r
2669 pAddress,\r
2670 pAddressLength);\r
2671 break;\r
2672 }\r
2673 break;\r
2674 }\r
2675\r
2676 //\r
2677 // Release the socket layer synchronization\r
2678 //\r
2679 RESTORE_TPL ( TplPrevious );\r
2680 }\r
d7ce7006 2681 }\r
2682 }\r
2683 }\r
2684\r
2685 //\r
2686 // Return the operation status\r
2687 //\r
2688 if ( NULL != pErrno ) {\r
2689 if ( NULL != pSocket ) {\r
2690 *pErrno = pSocket->errno;\r
2691 }\r
2692 else\r
2693 {\r
2694 Status = EFI_INVALID_PARAMETER;\r
2695 *pErrno = EBADF;\r
2696 }\r
2697 }\r
2698 DBG_EXIT_STATUS ( Status );\r
2699 return Status;\r
2700}\r
2701\r
2702\r
2703/**\r
2704 Shutdown the socket receive and transmit operations\r
2705\r
2706 The SocketShutdown routine stops the socket receive and transmit\r
2707 operations.\r
2708\r
2709 @param [in] pSocketProtocol Address of the socket protocol structure.\r
2710 \r
2711 @param [in] How Which operations to stop\r
2712 \r
2713 @param [out] pErrno Address to receive the errno value upon completion.\r
2714\r
2715 @retval EFI_SUCCESS - Socket operations successfully shutdown\r
2716\r
2717 **/\r
2718EFI_STATUS\r
2719EslSocketShutdown (\r
2720 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
2721 IN int How,\r
2722 IN int * pErrno\r
2723 )\r
2724{\r
2725 DT_SOCKET * pSocket;\r
2726 EFI_STATUS Status;\r
2727 EFI_TPL TplPrevious;\r
2728 \r
2729 DBG_ENTER ( );\r
2730 \r
2731 //\r
2732 // Assume success\r
2733 //\r
2734 Status = EFI_SUCCESS;\r
2735\r
2736 //\r
2737 // Validate the socket\r
2738 //\r
2739 pSocket = NULL;\r
2740 if ( NULL != pSocketProtocol ) {\r
2741 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
2742\r
2743 //\r
2744 // Verify that the socket is connected\r
2745 //\r
2746 if ( pSocket->bConnected ) {\r
2747 //\r
2748 // Validate the How value\r
2749 //\r
2750 if (( SHUT_RD <= How ) && ( SHUT_RDWR >= How )) {\r
2751 //\r
2752 // Synchronize with the socket layer\r
2753 //\r
2754 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2755\r
2756 //\r
2757 // Disable the receiver if requested\r
2758 //\r
2759 if (( SHUT_RD == How ) || ( SHUT_RDWR == How )) {\r
2760 pSocket->bRxDisable = TRUE;\r
2761 }\r
2762\r
2763 //\r
2764 // Disable the transmitter if requested\r
2765 //\r
2766 if (( SHUT_WR == How ) || ( SHUT_RDWR == How )) {\r
2767 pSocket->bTxDisable = TRUE;\r
2768 }\r
2769\r
2770 //\r
2771 // Validate the local address\r
2772 //\r
2773 switch ( pSocket->Domain ) {\r
2774 default:\r
2775 DEBUG (( DEBUG_RX,\r
2776 "ERROR - Invalid socket address family: %d\r\n",\r
2777 pSocket->Domain ));\r
2778 Status = EFI_INVALID_PARAMETER;\r
2779 pSocket->errno = EADDRNOTAVAIL;\r
2780 break;\r
2781 \r
2782 case AF_INET:\r
2783 //\r
2784 // Determine the connection point within the network stack\r
2785 //\r
2786 switch ( pSocket->Type ) {\r
2787 default:\r
2788 DEBUG (( DEBUG_RX,\r
2789 "ERROR - Invalid socket type: %d\r\n",\r
2790 pSocket->Type));\r
2791 Status = EFI_INVALID_PARAMETER;\r
2792 break;\r
2793 \r
2794 case SOCK_STREAM:\r
2795 case SOCK_SEQPACKET:\r
2796 //\r
2797 // Cancel the pending receive operation\r
2798 //\r
2799 Status = EslTcpRxCancel4 ( pSocket );\r
2800 break;\r
2801 \r
2802 case SOCK_DGRAM:\r
2803 //\r
2804 // Cancel the pending receive operation\r
2805 //\r
2806 Status = EslUdpRxCancel4 ( pSocket );\r
2807 break;\r
2808 }\r
2809 break;\r
2810 }\r
2811 \r
2812 //\r
2813 // Release the socket layer synchronization\r
2814 //\r
2815 RESTORE_TPL ( TplPrevious );\r
2816 }\r
2817 else {\r
2818 //\r
2819 // The socket is not connected\r
2820 //\r
2821 pSocket->errno = ENOTCONN;\r
2822 Status = EFI_NOT_STARTED;\r
2823 }\r
2824 }\r
2825 else {\r
2826 //\r
2827 // Invalid How value\r
2828 //\r
2829 pSocket->errno = EINVAL;\r
2830 Status = EFI_INVALID_PARAMETER;\r
2831 }\r
2832 }\r
2833\r
2834 //\r
2835 // Return the operation status\r
2836 //\r
2837 if ( NULL != pErrno ) {\r
2838 if ( NULL != pSocket ) {\r
2839 *pErrno = pSocket->errno;\r
2840 }\r
2841 else\r
2842 {\r
2843 Status = EFI_INVALID_PARAMETER;\r
2844 *pErrno = EBADF;\r
2845 }\r
2846 }\r
2847 DBG_EXIT_STATUS ( Status );\r
2848 return Status;\r
2849}\r
2850\r
2851\r
2852/**\r
2853 Send data using a network connection.\r
2854\r
2855 The SocketTransmit routine queues the data for transmission to the\r
2856 remote network connection.\r
2857\r
2858 @param [in] pSocketProtocol Address of the socket protocol structure.\r
2859 \r
2860 @param [in] Flags Message control flags\r
2861 \r
2862 @param [in] BufferLength Length of the the buffer\r
2863 \r
2864 @param [in] pBuffer Address of a buffer containing the data to send\r
2865 \r
2866 @param [in] pDataLength Address to receive the number of data bytes sent\r
2867\r
2868 @param [in] pAddress Network address of the remote system address\r
2869\r
2870 @param [in] AddressLength Length of the remote network address structure\r
2871\r
2872 @param [out] pErrno Address to receive the errno value upon completion.\r
2873\r
2874 @retval EFI_SUCCESS - Socket data successfully queued for transmit\r
2875\r
2876 **/\r
2877EFI_STATUS\r
2878EslSocketTransmit (\r
2879 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
2880 IN int Flags,\r
2881 IN size_t BufferLength,\r
2882 IN CONST UINT8 * pBuffer,\r
2883 OUT size_t * pDataLength,\r
2884 IN const struct sockaddr * pAddress,\r
2885 IN socklen_t AddressLength,\r
2886 IN int * pErrno\r
2887 )\r
2888{\r
2889 DT_SOCKET * pSocket;\r
2890 EFI_STATUS Status;\r
2891 EFI_TPL TplPrevious;\r
2892\r
2893 DBG_ENTER ( );\r
2894\r
2895 //\r
2896 // Assume success\r
2897 //\r
2898 Status = EFI_SUCCESS;\r
2899\r
2900 //\r
2901 // Validate the socket\r
2902 //\r
2903 pSocket = NULL;\r
2904 if ( NULL != pSocketProtocol ) {\r
2905 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
2906\r
2907 //\r
1c34b250 2908 // Return the transmit error if necessary\r
d7ce7006 2909 //\r
1c34b250 2910 if ( EFI_SUCCESS != pSocket->TxError ) {\r
2911 pSocket->errno = EIO;\r
2912 Status = pSocket->TxError;\r
2913 pSocket->TxError = EFI_SUCCESS;\r
2914 }\r
2915 else {\r
d7ce7006 2916 //\r
1c34b250 2917 // Verify the socket state\r
d7ce7006 2918 //\r
1c34b250 2919 if ( !pSocket->bConfigured ) {\r
2920 //\r
2921 // Synchronize with the socket layer\r
2922 //\r
2923 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2924\r
d7ce7006 2925 //\r
1c34b250 2926 // Validate the local address\r
d7ce7006 2927 //\r
1c34b250 2928 switch ( pSocket->Domain ) {\r
d7ce7006 2929 default:\r
2930 DEBUG (( DEBUG_RX,\r
1c34b250 2931 "ERROR - Invalid socket address family: %d\r\n",\r
2932 pSocket->Domain ));\r
d7ce7006 2933 Status = EFI_INVALID_PARAMETER;\r
1c34b250 2934 pSocket->errno = EADDRNOTAVAIL;\r
d7ce7006 2935 break;\r
1c34b250 2936\r
2937 case AF_INET:\r
d7ce7006 2938 //\r
1c34b250 2939 // Determine the connection point within the network stack\r
d7ce7006 2940 //\r
1c34b250 2941 switch ( pSocket->Type ) {\r
2942 default:\r
2943 DEBUG (( DEBUG_RX,\r
2944 "ERROR - Invalid socket type: %d\r\n",\r
2945 pSocket->Type));\r
2946 Status = EFI_INVALID_PARAMETER;\r
2947 break;\r
2948\r
2949 case SOCK_STREAM:\r
2950 case SOCK_SEQPACKET:\r
2951 //\r
2952 // Verify the port state\r
2953 //\r
2954 Status = EslTcpSocketIsConfigured4 ( pSocket );\r
2955 break;\r
2956\r
2957 case SOCK_DGRAM:\r
2958 //\r
2959 // Verify the port state\r
2960 //\r
2961 Status = EslUdpSocketIsConfigured4 ( pSocket );\r
2962 break;\r
2963 }\r
d7ce7006 2964 break;\r
2965 }\r
1c34b250 2966\r
d7ce7006 2967 //\r
1c34b250 2968 // Release the socket layer synchronization\r
d7ce7006 2969 //\r
1c34b250 2970 RESTORE_TPL ( TplPrevious );\r
2971\r
2972 //\r
2973 // Set errno if a failure occurs\r
2974 //\r
2975 if ( EFI_ERROR ( Status )) {\r
2976 pSocket->errno = EADDRNOTAVAIL;\r
d7ce7006 2977 }\r
1c34b250 2978 }\r
2979 if ( !EFI_ERROR ( Status )) {\r
2980 //\r
2981 // Verify that transmit is still allowed\r
2982 //\r
2983 if ( !pSocket->bTxDisable ) {\r
d7ce7006 2984 //\r
1c34b250 2985 // Validate the buffer length\r
d7ce7006 2986 //\r
1c34b250 2987 if (( NULL == pDataLength )\r
2988 && ( 0 > pDataLength )\r
2989 && ( NULL == pBuffer )) {\r
2990 if ( NULL == pDataLength ) {\r
2991 DEBUG (( DEBUG_RX,\r
2992 "ERROR - pDataLength is NULL!\r\n" ));\r
2993 }\r
2994 else if ( NULL == pBuffer ) {\r
2995 DEBUG (( DEBUG_RX,\r
2996 "ERROR - pBuffer is NULL!\r\n" ));\r
2997 }\r
2998 else {\r
2999 DEBUG (( DEBUG_RX,\r
3000 "ERROR - Data length < 0!\r\n" ));\r
3001 }\r
d7ce7006 3002 Status = EFI_INVALID_PARAMETER;\r
3003 pSocket->errno = EFAULT;\r
3004 }\r
3005 else {\r
3006 //\r
1c34b250 3007 // Validate the remote network address\r
d7ce7006 3008 //\r
1c34b250 3009 if (( NULL != pAddress )\r
3010 && ( AddressLength < pAddress->sa_len )) {\r
3011 DEBUG (( DEBUG_TX,\r
3012 "ERROR - Invalid sin_len field in address\r\n" ));\r
d7ce7006 3013 Status = EFI_INVALID_PARAMETER;\r
1c34b250 3014 pSocket->errno = EFAULT;\r
3015 }\r
3016 else {\r
3017 //\r
3018 // Synchronize with the socket layer\r
3019 //\r
3020 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
d7ce7006 3021\r
d7ce7006 3022 //\r
1c34b250 3023 // Validate the local address\r
d7ce7006 3024 //\r
1c34b250 3025 switch ( pSocket->Domain ) {\r
d7ce7006 3026 default:\r
3027 DEBUG (( DEBUG_RX,\r
1c34b250 3028 "ERROR - Invalid socket address family: %d\r\n",\r
3029 pSocket->Domain ));\r
d7ce7006 3030 Status = EFI_INVALID_PARAMETER;\r
3031 pSocket->errno = EADDRNOTAVAIL;\r
3032 break;\r
3033\r
1c34b250 3034 case AF_INET:\r
3035 //\r
3036 // Determine the connection point within the network stack\r
3037 //\r
3038 switch ( pSocket->Type ) {\r
3039 default:\r
3040 DEBUG (( DEBUG_RX,\r
3041 "ERROR - Invalid socket type: %d\r\n",\r
3042 pSocket->Type));\r
3043 Status = EFI_INVALID_PARAMETER;\r
3044 pSocket->errno = EADDRNOTAVAIL;\r
3045 break;\r
3046\r
3047 case SOCK_STREAM:\r
3048 case SOCK_SEQPACKET:\r
3049 Status = EslTcpTxBuffer4 ( pSocket,\r
3050 Flags,\r
3051 BufferLength,\r
3052 pBuffer,\r
3053 pDataLength );\r
3054 break;\r
3055\r
3056 case SOCK_DGRAM:\r
3057 Status = EslUdpTxBuffer4 ( pSocket,\r
3058 Flags,\r
3059 BufferLength,\r
3060 pBuffer,\r
3061 pDataLength,\r
3062 pAddress,\r
3063 AddressLength );\r
3064 break;\r
3065 }\r
d7ce7006 3066 break;\r
3067 }\r
d7ce7006 3068\r
1c34b250 3069 //\r
3070 // Release the socket layer synchronization\r
3071 //\r
3072 RESTORE_TPL ( TplPrevious );\r
3073 }\r
d7ce7006 3074 }\r
3075 }\r
1c34b250 3076 else {\r
3077 //\r
3078 // The transmitter was shutdown\r
3079 //\r
3080 pSocket->errno = EPIPE;\r
3081 Status = EFI_NOT_STARTED;\r
3082 }\r
d7ce7006 3083 }\r
3084 }\r
3085 }\r
3086\r
3087 //\r
3088 // Return the operation status\r
3089 //\r
3090 if ( NULL != pErrno ) {\r
3091 if ( NULL != pSocket ) {\r
3092 *pErrno = pSocket->errno;\r
3093 }\r
3094 else\r
3095 {\r
3096 Status = EFI_INVALID_PARAMETER;\r
3097 *pErrno = EBADF;\r
3098 }\r
3099 }\r
3100 DBG_EXIT_STATUS ( Status );\r
3101 return Status;\r
3102}\r
3103\r
3104\r
3105/**\r
3106 Socket layer's service binding protocol delcaration.\r
3107**/\r
3108EFI_SERVICE_BINDING_PROTOCOL mEfiServiceBinding = {\r
3109 EslSocketCreateChild,\r
3110 EslSocketDestroyChild\r
3111};\r