]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/EfiSocketLib/Tcp4.c
Merged socket development branch:
[mirror_edk2.git] / StdLib / EfiSocketLib / Tcp4.c
CommitLineData
d7ce7006 1/** @file\r
2 Implement the TCP4 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
a88c3163 13\r
14 \section ConnectionManagement Connection Management\r
15 \r
16 The ::EslTcp4Listen routine initially places the SOCK_STREAM or\r
17 SOCK_SEQPACKET socket into a listen state. When a remote machine\r
18 makes a connection to the socket, the TCPv4 network layer calls\r
19 ::EslTcp4ListenComplete to complete the connection processing.\r
20 EslTcp4ListenComplete manages the connections by placing them in\r
21 FIFO order in a queue to be serviced by the application. When the\r
22 number of connections exceeds the backlog (ESL_SOCKET::MaxFifoDepth),\r
23 the new connection is closed. Eventually, the application indirectly\r
24 calls ::EslTcp4Accept to remove the next connection from the queue\r
25 and get the associated socket.\r
26\r
d7ce7006 27**/\r
28\r
29#include "Socket.h"\r
30\r
31\r
a88c3163 32/**\r
33 Attempt to connect to a remote TCP port\r
34\r
35 This routine starts the connection processing for a SOCK_STREAM\r
36 or SOCK_SEQPAKCET socket using the TCPv4 network layer. It\r
37 configures the local TCPv4 connection point and then attempts to\r
38 connect to a remote system. Upon completion, the\r
39 ::EslTcp4ConnectComplete routine gets called with the connection\r
40 status.\r
41\r
42 This routine is called by ::EslSocketConnect to initiate the TCPv4\r
43 network specific connect operations. The connection processing is\r
44 initiated by this routine and finished by ::EslTcp4ConnectComplete.\r
45 This pair of routines walks through the list of local TCPv4\r
46 connection points until a connection to the remote system is\r
47 made.\r
48\r
49 @param [in] pSocket Address of an ::ESL_SOCKET structure.\r
50\r
51 @retval EFI_SUCCESS The connection was successfully established.\r
52 @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
53 @retval Others The connection attempt failed.\r
54\r
55 **/\r
56EFI_STATUS\r
57EslTcp4ConnectStart (\r
58 IN ESL_SOCKET * pSocket\r
59 );\r
60\r
61\r
62/**\r
63 Process the connection attempt\r
64\r
65 A system has initiated a connection attempt with a socket in the\r
66 listen state. Attempt to complete the connection.\r
67\r
68 The TCPv4 layer calls this routine when a connection is made to\r
69 the socket in the listen state. See the\r
70 \ref ConnectionManagement section.\r
71\r
72 @param [in] Event The listen completion event\r
73\r
74 @param [in] pPort Address of an ::ESL_PORT structure.\r
75\r
76**/\r
77VOID\r
78EslTcp4ListenComplete (\r
79 IN EFI_EVENT Event,\r
80 IN ESL_PORT * pPort\r
81 );\r
82\r
83\r
d7ce7006 84/**\r
85 Accept a network connection.\r
86\r
a88c3163 87 This routine waits for a network connection to the socket and\r
88 returns the remote network address to the caller if requested.\r
89\r
90 This routine is called by ::EslSocketAccept to handle the TCPv4 protocol\r
91 specific accept operations for SOCK_STREAM and SOCK_SEQPACKET sockets.\r
92 See the \ref ConnectionManagement section.\r
d7ce7006 93\r
a88c3163 94 @param [in] pSocket Address of an ::ESL_SOCKET structure.\r
d7ce7006 95\r
96 @param [in] pSockAddr Address of a buffer to receive the remote\r
97 network address.\r
98\r
99 @param [in, out] pSockAddrLength Length in bytes of the address buffer.\r
100 On output specifies the length of the\r
101 remote network address.\r
102\r
103 @retval EFI_SUCCESS Remote address is available\r
104 @retval Others Remote address not available\r
105\r
106 **/\r
107EFI_STATUS\r
a88c3163 108EslTcp4Accept (\r
109 IN ESL_SOCKET * pSocket,\r
d7ce7006 110 IN struct sockaddr * pSockAddr,\r
111 IN OUT socklen_t * pSockAddrLength\r
112 )\r
113{\r
a88c3163 114 ESL_PORT * pPort;\r
d7ce7006 115 struct sockaddr_in * pRemoteAddress;\r
a88c3163 116 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 117 UINT32 RemoteAddress;\r
118 EFI_STATUS Status;\r
119\r
120 DBG_ENTER ( );\r
121\r
122 //\r
123 // Validate the socket length\r
124 //\r
125 pRemoteAddress = (struct sockaddr_in *) pSockAddr;\r
126 if (( NULL == pSockAddrLength )\r
127 || ( sizeof ( *pRemoteAddress ) > *pSockAddrLength )) {\r
128 //\r
129 // Invalid socket address\r
130 //\r
131 Status = EFI_INVALID_PARAMETER;\r
132 pSocket->errno = EINVAL;\r
133 DEBUG (( DEBUG_ACCEPT,\r
134 "ERROR - Invalid address length\r\n" ));\r
135 }\r
136 else {\r
137 //\r
138 // Assume success\r
139 //\r
140 Status = EFI_SUCCESS;\r
141\r
142 //\r
143 // Locate the address context\r
144 //\r
145 pPort = pSocket->pPortList;\r
146 pTcp4 = &pPort->Context.Tcp4;\r
147\r
148 //\r
149 // Fill-in the remote address structure\r
150 //\r
151 ZeroMem ( pRemoteAddress, sizeof ( *pRemoteAddress ));\r
152 pRemoteAddress->sin_len = sizeof ( *pRemoteAddress );\r
153 pRemoteAddress->sin_family = AF_INET;\r
154 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );\r
155 RemoteAddress = pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3];\r
156 RemoteAddress <<= 8;\r
157 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2];\r
158 RemoteAddress <<= 8;\r
159 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1];\r
160 RemoteAddress <<= 8;\r
161 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0];\r
162 pRemoteAddress->sin_addr.s_addr = RemoteAddress;\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
a88c3163 174 Process the remote connection completion event.\r
d7ce7006 175\r
a88c3163 176 This routine handles the completion of a connection attempt. It\r
177 releases the port (TCPv4 adapter connection) in the case of an\r
d7ce7006 178 error and start a connection attempt on the next port. If the\r
a88c3163 179 connection attempt was successful then this routine releases all\r
180 of the other ports.\r
d7ce7006 181\r
a88c3163 182 This routine is called by the TCPv4 layer when a connect request\r
183 completes. It sets the ESL_SOCKET::bConnected flag to notify the\r
184 ::EslTcp4ConnectComplete routine that the connection is available.\r
185 The flag is set when the connection is established or no more ports\r
186 exist in the list. The connection status is passed via\r
187 ESL_SOCKET::ConnectStatus.\r
d7ce7006 188\r
a88c3163 189 @param [in] Event The connect completion event\r
190\r
191 @param [in] pPort Address of an ::ESL_PORT structure.\r
d7ce7006 192\r
193**/\r
194VOID\r
a88c3163 195EslTcp4ConnectComplete (\r
d7ce7006 196 IN EFI_EVENT Event,\r
a88c3163 197 IN ESL_PORT * pPort\r
d7ce7006 198 )\r
199{\r
200 BOOLEAN bRemoveFirstPort;\r
201 BOOLEAN bRemovePorts;\r
a88c3163 202 ESL_PORT * pNextPort;\r
203 ESL_SOCKET * pSocket;\r
204 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 205 EFI_STATUS Status;\r
206\r
207 DBG_ENTER ( );\r
208\r
209 //\r
210 // Locate the TCP context\r
211 //\r
212 pSocket = pPort->pSocket;\r
213 pTcp4 = &pPort->Context.Tcp4;\r
214\r
215 //\r
216 // Get the connection status\r
217 //\r
218 bRemoveFirstPort = FALSE;\r
219 bRemovePorts = FALSE;\r
220 Status = pTcp4->ConnectToken.CompletionToken.Status;\r
221 pSocket->ConnectStatus = Status;\r
222 if ( !EFI_ERROR ( Status )) {\r
223 //\r
224 // The connection was successful\r
225 //\r
226 DEBUG (( DEBUG_CONNECT,\r
227 "0x%08x: Port connected to %d.%d.%d.%d:%d\r\n",\r
228 pPort,\r
a88c3163 229 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
230 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],\r
231 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],\r
232 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],\r
d7ce7006 233 pTcp4->ConfigData.AccessPoint.RemotePort ));\r
234\r
235 //\r
236 // Remove the rest of the ports\r
237 //\r
238 bRemovePorts = TRUE;\r
239 }\r
240 else {\r
241 //\r
242 // The connection failed\r
243 //\r
244 DEBUG (( DEBUG_CONNECT,\r
245 "0x%08x: Port connection to %d.%d.%d.%d:%d failed, Status: %r\r\n",\r
246 pPort,\r
a88c3163 247 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
248 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],\r
249 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],\r
250 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],\r
d7ce7006 251 pTcp4->ConfigData.AccessPoint.RemotePort,\r
252 Status ));\r
253\r
254 //\r
255 // Close the current port\r
256 //\r
a88c3163 257 Status = EslSocketPortClose ( pPort );\r
d7ce7006 258 if ( !EFI_ERROR ( Status )) {\r
259 DEBUG (( DEBUG_CONNECT,\r
260 "0x%08x: Port closed\r\n",\r
261 pPort ));\r
262 }\r
263 else {\r
264 DEBUG (( DEBUG_CONNECT,\r
265 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",\r
266 pPort,\r
267 Status ));\r
268 }\r
269\r
270 //\r
271 // Try to connect using the next port\r
272 //\r
a88c3163 273 Status = EslTcp4ConnectStart ( pSocket );\r
d7ce7006 274 if ( EFI_NOT_READY != Status ) {\r
275 pSocket->ConnectStatus = Status;\r
276 bRemoveFirstPort = TRUE;\r
277 }\r
278 }\r
279\r
280 //\r
281 // Remove the ports if necessary\r
282 //\r
283 if ( bRemoveFirstPort || bRemovePorts ) {\r
284 //\r
285 // Remove the first port if necessary\r
286 //\r
287 pPort = pSocket->pPortList;\r
288 if (( !bRemoveFirstPort ) && ( NULL != pPort )) {\r
289 pPort = pPort->pLinkSocket;\r
290 }\r
291\r
292 //\r
293 // Remove the rest of the list\r
294 //\r
295 while ( NULL != pPort ) {\r
296 pNextPort = pPort->pLinkSocket;\r
a88c3163 297 EslSocketPortClose ( pPort );\r
d7ce7006 298 if ( !EFI_ERROR ( Status )) {\r
299 DEBUG (( DEBUG_CONNECT,\r
300 "0x%08x: Port closed\r\n",\r
301 pPort ));\r
302 }\r
303 else {\r
304 DEBUG (( DEBUG_CONNECT,\r
305 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",\r
306 pPort,\r
307 Status ));\r
308 }\r
309 pPort = pNextPort;\r
310 }\r
311\r
312 //\r
313 // Notify the poll routine\r
314 //\r
315 pSocket->bConnected = TRUE;\r
316 }\r
317\r
318 DBG_EXIT ( );\r
319}\r
320\r
321\r
322/**\r
323 Poll for completion of the connection attempt.\r
324\r
a88c3163 325 This routine polls the ESL_SOCKET::bConnected flag to determine\r
326 when the connection attempt is complete.\r
327\r
328 This routine is called from ::EslSocketConnect to determine when\r
329 the connection is complete. The ESL_SOCKET::bConnected flag is\r
330 set by ::EslTcp4ConnectComplete when the TCPv4 layer establishes\r
331 a connection or runs out of local network adapters. This routine\r
332 gets the connection status from ESL_SOCKET::ConnectStatus.\r
d7ce7006 333\r
a88c3163 334 @param [in] pSocket Address of an ::ESL_SOCKET structure.\r
d7ce7006 335\r
336 @retval EFI_SUCCESS The connection was successfully established.\r
337 @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
338 @retval Others The connection attempt failed.\r
339\r
340 **/\r
341EFI_STATUS\r
a88c3163 342EslTcp4ConnectPoll (\r
343 IN ESL_SOCKET * pSocket\r
d7ce7006 344 )\r
345{\r
346 EFI_STATUS Status;\r
347\r
348 DBG_ENTER ( );\r
349\r
350 //\r
351 // Determine if the connection is complete\r
352 //\r
353 if ( !pSocket->bConnected ) {\r
354 //\r
355 // Not connected\r
356 //\r
357 pSocket->errno = EAGAIN;\r
358 Status = EFI_NOT_READY;\r
359 }\r
360 else {\r
361 //\r
362 // The connection processing is complete\r
363 //\r
364 pSocket->bConnected = FALSE;\r
365\r
366 //\r
367 // Translate the connection status\r
368 //\r
369 Status = pSocket->ConnectStatus;\r
370 switch ( Status ) {\r
371 default:\r
372 case EFI_DEVICE_ERROR:\r
373 pSocket->errno = EIO;\r
374 break;\r
375\r
376 case EFI_ABORTED:\r
377 pSocket->errno = ECONNREFUSED;\r
378 break;\r
379\r
380 case EFI_INVALID_PARAMETER:\r
381 pSocket->errno = EINVAL;\r
382 break;\r
383\r
384 case EFI_NO_MAPPING:\r
385 case EFI_NO_RESPONSE:\r
386 pSocket->errno = EHOSTUNREACH;\r
387 break;\r
388\r
389 case EFI_NO_MEDIA:\r
390 pSocket->errno = ENETDOWN;\r
391 break;\r
392\r
393 case EFI_OUT_OF_RESOURCES:\r
394 pSocket->errno = ENOMEM;\r
395 break;\r
396\r
397 case EFI_SUCCESS:\r
398 pSocket->errno = 0;\r
399 pSocket->bConfigured = TRUE;\r
400 break;\r
401\r
402 case EFI_TIMEOUT:\r
403 pSocket->errno = ETIMEDOUT;\r
404 break;\r
405\r
406 case EFI_UNSUPPORTED:\r
407 pSocket->errno = ENOTSUP;\r
408 break;\r
409\r
410 case 0x80000069:\r
411 pSocket->errno = ECONNRESET;\r
412 break;\r
413 }\r
414 }\r
415\r
416 //\r
417 // Return the initialization status\r
418 //\r
419 DBG_EXIT_STATUS ( Status );\r
420 return Status;\r
421}\r
422\r
423\r
424/**\r
a88c3163 425 Attempt to connect to a remote TCP port\r
d7ce7006 426\r
a88c3163 427 This routine starts the connection processing for a SOCK_STREAM\r
428 or SOCK_SEQPAKCET socket using the TCPv4 network layer. It\r
429 configures the local TCPv4 connection point and then attempts to\r
430 connect to a remote system. Upon completion, the\r
431 ::EslTcp4ConnectComplete routine gets called with the connection\r
432 status.\r
d7ce7006 433\r
a88c3163 434 This routine is called by ::EslSocketConnect to initiate the TCPv4\r
435 network specific connect operations. The connection processing is\r
436 initiated by this routine and finished by ::EslTcp4ConnectComplete.\r
437 This pair of routines walks through the list of local TCPv4\r
438 connection points until a connection to the remote system is\r
439 made.\r
440\r
441 @param [in] pSocket Address of an ::ESL_SOCKET structure.\r
d7ce7006 442\r
d7ce7006 443 @retval EFI_SUCCESS The connection was successfully established.\r
444 @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
445 @retval Others The connection attempt failed.\r
446\r
447 **/\r
448EFI_STATUS\r
a88c3163 449EslTcp4ConnectStart (\r
450 IN ESL_SOCKET * pSocket\r
d7ce7006 451 )\r
452{\r
a88c3163 453 ESL_PORT * pPort;\r
454 ESL_TCP4_CONTEXT * pTcp4;\r
455 EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
d7ce7006 456 EFI_STATUS Status;\r
457\r
458 DBG_ENTER ( );\r
a88c3163 459 \r
d7ce7006 460 //\r
a88c3163 461 // Determine if any more local adapters are available\r
d7ce7006 462 //\r
a88c3163 463 pPort = pSocket->pPortList;\r
464 if ( NULL != pPort ) {\r
d7ce7006 465 //\r
a88c3163 466 // Configure the port\r
d7ce7006 467 //\r
a88c3163 468 pTcp4 = &pPort->Context.Tcp4;\r
469 pTcp4->ConfigData.AccessPoint.ActiveFlag = TRUE;\r
470 pTcp4->ConfigData.TimeToLive = 255;\r
471 pTcp4Protocol = pPort->pProtocol.TCPv4;\r
472 Status = pTcp4Protocol->Configure ( pTcp4Protocol,\r
473 &pTcp4->ConfigData );\r
474 if ( EFI_ERROR ( Status )) {\r
475 DEBUG (( DEBUG_CONNECT,\r
476 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",\r
477 Status ));\r
478 switch ( Status ) {\r
479 case EFI_ACCESS_DENIED:\r
480 pSocket->errno = EACCES;\r
481 break;\r
482 \r
483 default:\r
484 case EFI_DEVICE_ERROR:\r
485 pSocket->errno = EIO;\r
486 break;\r
487 \r
488 case EFI_INVALID_PARAMETER:\r
489 pSocket->errno = EADDRNOTAVAIL;\r
490 break;\r
491 \r
492 case EFI_NO_MAPPING:\r
493 pSocket->errno = EAFNOSUPPORT;\r
494 break;\r
495 \r
496 case EFI_OUT_OF_RESOURCES:\r
497 pSocket->errno = ENOBUFS;\r
498 break;\r
499 \r
500 case EFI_UNSUPPORTED:\r
501 pSocket->errno = EOPNOTSUPP;\r
502 break;\r
503 }\r
d7ce7006 504 }\r
505 else {\r
a88c3163 506 DEBUG (( DEBUG_CONNECT,\r
507 "0x%08x: Port configured\r\n",\r
508 pPort ));\r
509 pPort->bConfigured = TRUE;\r
d7ce7006 510\r
a88c3163 511 //\r
512 // Attempt the connection to the remote system\r
513 //\r
514 Status = pTcp4Protocol->Connect ( pTcp4Protocol,\r
515 &pTcp4->ConnectToken );\r
516 if ( !EFI_ERROR ( Status )) {\r
517 //\r
518 // Connection in progress\r
519 //\r
520 pSocket->errno = EINPROGRESS;\r
521 Status = EFI_NOT_READY;\r
522 DEBUG (( DEBUG_CONNECT,\r
523 "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",\r
524 pPort,\r
525 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
526 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],\r
527 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],\r
528 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],\r
529 pTcp4->ConfigData.AccessPoint.RemotePort ));\r
530 }\r
531 else {\r
532 //\r
533 // Connection error\r
534 //\r
535 DEBUG (( DEBUG_CONNECT,\r
536 "ERROR - Port 0x%08x not connected, Status: %r\r\n",\r
537 pPort,\r
538 Status ));\r
539 //\r
540 // Determine the errno value\r
541 //\r
542 switch ( Status ) {\r
543 default:\r
544 pSocket->errno = EIO;\r
545 break;\r
d7ce7006 546\r
a88c3163 547 case EFI_OUT_OF_RESOURCES:\r
548 pSocket->errno = ENOBUFS;\r
549 break;\r
d7ce7006 550\r
a88c3163 551 case EFI_TIMEOUT:\r
552 pSocket->errno = ETIMEDOUT;\r
553 break;\r
d7ce7006 554\r
a88c3163 555 case EFI_NETWORK_UNREACHABLE:\r
556 pSocket->errno = ENETDOWN;\r
557 break;\r
d7ce7006 558\r
a88c3163 559 case EFI_HOST_UNREACHABLE:\r
560 pSocket->errno = EHOSTUNREACH;\r
561 break;\r
d7ce7006 562\r
a88c3163 563 case EFI_PORT_UNREACHABLE:\r
564 case EFI_PROTOCOL_UNREACHABLE:\r
565 case EFI_CONNECTION_REFUSED:\r
566 pSocket->errno = ECONNREFUSED;\r
567 break;\r
d7ce7006 568\r
a88c3163 569 case EFI_CONNECTION_RESET:\r
570 pSocket->errno = ECONNRESET;\r
571 break;\r
572 }\r
573 }\r
d7ce7006 574 }\r
575 }\r
576 else {\r
a88c3163 577 //\r
578 // No more local adapters available\r
579 //\r
580 pSocket->errno = ENETUNREACH;\r
581 Status = EFI_NO_RESPONSE;\r
d7ce7006 582 }\r
a88c3163 583\r
d7ce7006 584 //\r
585 // Return the operation status\r
586 //\r
587 DBG_EXIT_STATUS ( Status );\r
588 return Status;\r
589}\r
590\r
591\r
592/**\r
593 Establish the known port to listen for network connections.\r
594\r
a88c3163 595 This routine places the port into a state that enables connection\r
596 attempts.\r
597\r
598 This routine is called by ::EslSocketListen to handle the network\r
599 specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET\r
600 sockets. See the \ref ConnectionManagement section.\r
d7ce7006 601\r
a88c3163 602 @param [in] pSocket Address of an ::ESL_SOCKET structure.\r
d7ce7006 603\r
604 @retval EFI_SUCCESS - Socket successfully created\r
605 @retval Other - Failed to enable the socket for listen\r
606\r
607**/\r
608EFI_STATUS\r
a88c3163 609EslTcp4Listen (\r
610 IN ESL_SOCKET * pSocket\r
d7ce7006 611 )\r
612{\r
a88c3163 613 ESL_PORT * pNextPort;\r
614 ESL_PORT * pPort;\r
615 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 616 EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
617 EFI_STATUS Status;\r
618\r
619 DBG_ENTER ( );\r
620\r
621 //\r
622 // Verify the socket layer synchronization\r
623 //\r
624 VERIFY_TPL ( TPL_SOCKETS );\r
625\r
626 //\r
627 // Use for/break instead of goto\r
628 //\r
629 for ( ; ; ) {\r
630 //\r
631 // Assume no ports are available\r
632 //\r
633 pSocket->errno = EOPNOTSUPP;\r
634 Status = EFI_NOT_READY;\r
635\r
636 //\r
637 // Walk the list of ports\r
638 //\r
639 pPort = pSocket->pPortList;\r
640 while ( NULL != pPort ) {\r
641 //\r
642 // Assume success\r
643 //\r
644 pSocket->errno = 0;\r
645\r
646 //\r
647 // Use for/break insteak of goto\r
648 //\r
649 for ( ; ; ) {\r
650 //\r
651 // Create the listen completion event\r
652 //\r
653 pTcp4 = &pPort->Context.Tcp4;\r
654 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
655 TPL_SOCKETS,\r
a88c3163 656 (EFI_EVENT_NOTIFY)EslTcp4ListenComplete,\r
d7ce7006 657 pPort,\r
658 &pTcp4->ListenToken.CompletionToken.Event );\r
659 if ( EFI_ERROR ( Status )) {\r
660 DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,\r
661 "ERROR - Failed to create the listen completion event, Status: %r\r\n",\r
662 Status ));\r
663 pSocket->errno = ENOMEM;\r
664 break;\r
665 }\r
666 DEBUG (( DEBUG_POOL,\r
667 "0x%08x: Created listen completion event\r\n",\r
668 pTcp4->ListenToken.CompletionToken.Event ));\r
669\r
670 //\r
671 // Configure the port\r
672 //\r
a88c3163 673 pTcp4Protocol = pPort->pProtocol.TCPv4;\r
d7ce7006 674 Status = pTcp4Protocol->Configure ( pTcp4Protocol,\r
675 &pTcp4->ConfigData );\r
676 if ( EFI_ERROR ( Status )) {\r
677 DEBUG (( DEBUG_LISTEN,\r
678 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",\r
679 Status ));\r
680 switch ( Status ) {\r
681 case EFI_ACCESS_DENIED:\r
682 pSocket->errno = EACCES;\r
683 break;\r
684\r
685 default:\r
686 case EFI_DEVICE_ERROR:\r
687 pSocket->errno = EIO;\r
688 break;\r
689\r
690 case EFI_INVALID_PARAMETER:\r
691 pSocket->errno = EADDRNOTAVAIL;\r
692 break;\r
693\r
694 case EFI_NO_MAPPING:\r
695 pSocket->errno = EAFNOSUPPORT;\r
696 break;\r
697\r
698 case EFI_OUT_OF_RESOURCES:\r
699 pSocket->errno = ENOBUFS;\r
700 break;\r
701\r
702 case EFI_UNSUPPORTED:\r
703 pSocket->errno = EOPNOTSUPP;\r
704 break;\r
705 }\r
706 break;\r
707 }\r
708 DEBUG (( DEBUG_LISTEN,\r
709 "0x%08x: Port configured\r\n",\r
710 pPort ));\r
a88c3163 711 pPort->bConfigured = TRUE;\r
d7ce7006 712\r
713 //\r
714 // Start the listen operation on the port\r
715 //\r
716 Status = pTcp4Protocol->Accept ( pTcp4Protocol,\r
717 &pTcp4->ListenToken );\r
718 if ( EFI_ERROR ( Status )) {\r
719 DEBUG (( DEBUG_LISTEN,\r
720 "ERROR - Failed Tcp4 accept, Status: %r\r\n",\r
721 Status ));\r
722 switch ( Status ) {\r
723 case EFI_ACCESS_DENIED:\r
724 pSocket->errno = EACCES;\r
725 break;\r
726\r
727 default:\r
728 case EFI_DEVICE_ERROR:\r
729 pSocket->errno = EIO;\r
730 break;\r
731\r
732 case EFI_INVALID_PARAMETER:\r
733 pSocket->errno = EADDRNOTAVAIL;\r
734 break;\r
735\r
736 case EFI_NOT_STARTED:\r
737 pSocket->errno = ENETDOWN;\r
738 break;\r
739\r
740 case EFI_OUT_OF_RESOURCES:\r
741 pSocket->errno = ENOBUFS;\r
742 break;\r
743 }\r
744 break;\r
745 }\r
746 DEBUG (( DEBUG_LISTEN,\r
747 "0x%08x: Listen pending on Port\r\n",\r
748 pPort ));\r
749\r
750 //\r
751 // Listen is pending on this port\r
752 //\r
753 break;\r
754 }\r
755\r
756 //\r
757 // Get the next port\r
758 //\r
759 pNextPort = pPort->pLinkSocket;\r
760\r
761 //\r
762 // Close the port upon error\r
763 //\r
a88c3163 764 if ( EFI_ERROR ( Status )) {\r
765 EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );\r
d7ce7006 766 }\r
767\r
768 //\r
769 // Set the next port\r
770 //\r
771 pPort = pNextPort;\r
772 }\r
773 \r
774 //\r
775 // Determine if any ports are in the listen state\r
776 //\r
777 if ( NULL == pSocket->pPortList ) {\r
778 //\r
779 // No ports in the listen state\r
780 //\r
781 pSocket->MaxFifoDepth = 0;\r
782\r
783 //\r
784 // Return the last error detected\r
785 //\r
786 break;\r
787 }\r
788\r
789 //\r
790 // Mark the socket as configured\r
791 //\r
792 pSocket->bConfigured = TRUE;\r
793\r
794 //\r
795 // All done\r
796 //\r
797 DEBUG (( DEBUG_LISTEN,\r
798 "0x%08x: pSocket - Listen pending on socket\r\n",\r
799 pSocket ));\r
800 break;\r
801 }\r
802\r
803 //\r
804 // Return the operation status\r
805 //\r
806 DBG_EXIT_STATUS ( Status );\r
807 return Status;\r
808}\r
809\r
810\r
811/**\r
812 Process the connection attempt\r
813\r
814 A system has initiated a connection attempt with a socket in the\r
815 listen state. Attempt to complete the connection.\r
816\r
a88c3163 817 The TCPv4 layer calls this routine when a connection is made to\r
818 the socket in the listen state. See the\r
819 \ref ConnectionManagement section.\r
820\r
821 @param [in] Event The listen completion event\r
d7ce7006 822\r
a88c3163 823 @param [in] pPort Address of an ::ESL_PORT structure.\r
d7ce7006 824\r
825**/\r
826VOID\r
a88c3163 827EslTcp4ListenComplete (\r
d7ce7006 828 IN EFI_EVENT Event,\r
a88c3163 829 IN ESL_PORT * pPort\r
d7ce7006 830 )\r
831{\r
832 EFI_HANDLE ChildHandle;\r
a88c3163 833 struct sockaddr_in LocalAddress;\r
d7ce7006 834 EFI_TCP4_CONFIG_DATA * pConfigData;\r
a88c3163 835 ESL_LAYER * pLayer;\r
836 ESL_PORT * pNewPort;\r
837 ESL_SOCKET * pNewSocket;\r
838 ESL_SOCKET * pSocket;\r
839 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 840 EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
841 EFI_STATUS Status;\r
842 EFI_HANDLE TcpPortHandle;\r
843 EFI_STATUS TempStatus;\r
844\r
845 DBG_ENTER ( );\r
a88c3163 846 VERIFY_AT_TPL ( TPL_SOCKETS );\r
d7ce7006 847\r
848 //\r
849 // Assume success\r
850 //\r
851 Status = EFI_SUCCESS;\r
852\r
853 //\r
854 // Determine if this connection fits into the connection FIFO\r
855 //\r
856 pSocket = pPort->pSocket;\r
857 TcpPortHandle = pPort->Context.Tcp4.ListenToken.NewChildHandle;\r
858 if (( SOCKET_STATE_LISTENING == pSocket->State )\r
859 && ( pSocket->MaxFifoDepth > pSocket->FifoDepth )) {\r
860 //\r
861 // Allocate a socket for this connection\r
862 //\r
863 ChildHandle = NULL;\r
864 pLayer = &mEslLayer;\r
865 Status = EslSocketAllocate ( &ChildHandle,\r
866 DEBUG_CONNECTION,\r
867 &pNewSocket );\r
868 if ( !EFI_ERROR ( Status )) {\r
869 //\r
870 // Clone the socket parameters\r
871 //\r
a88c3163 872 pNewSocket->pApi = pSocket->pApi;\r
d7ce7006 873 pNewSocket->Domain = pSocket->Domain;\r
874 pNewSocket->Protocol = pSocket->Protocol;\r
875 pNewSocket->Type = pSocket->Type;\r
876\r
877 //\r
a88c3163 878 // Build the local address\r
d7ce7006 879 //\r
880 pTcp4 = &pPort->Context.Tcp4;\r
a88c3163 881 LocalAddress.sin_len = (uint8_t)pNewSocket->pApi->MinimumAddressLength;\r
882 LocalAddress.sin_family = AF_INET;\r
883 LocalAddress.sin_port = 0;\r
884 LocalAddress.sin_addr.s_addr = *(UINT32 *)&pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0];\r
885\r
886 //\r
887 // Allocate a port for this connection\r
888 // Note in this instance Configure may not be called with NULL!\r
889 //\r
890 Status = EslSocketPortAllocate ( pNewSocket,\r
891 pPort->pService,\r
892 TcpPortHandle,\r
893 (struct sockaddr *)&LocalAddress,\r
894 FALSE,\r
895 DEBUG_CONNECTION,\r
896 &pNewPort );\r
d7ce7006 897 if ( !EFI_ERROR ( Status )) {\r
898 //\r
899 // Restart the listen operation on the port\r
900 //\r
a88c3163 901 pTcp4Protocol = pPort->pProtocol.TCPv4;\r
d7ce7006 902 Status = pTcp4Protocol->Accept ( pTcp4Protocol,\r
903 &pTcp4->ListenToken );\r
904\r
905 //\r
906 // Close the TCP port using SocketClose\r
907 //\r
908 TcpPortHandle = NULL;\r
909 pTcp4 = &pNewPort->Context.Tcp4;\r
d7ce7006 910\r
911 //\r
912 // Check for an accept call error\r
913 //\r
914 if ( !EFI_ERROR ( Status )) {\r
915 //\r
916 // Get the port configuration\r
917 //\r
a88c3163 918 pNewPort->bConfigured = TRUE;\r
d7ce7006 919 pConfigData = &pTcp4->ConfigData;\r
920 pConfigData->ControlOption = &pTcp4->Option;\r
a88c3163 921 pTcp4Protocol = pNewPort->pProtocol.TCPv4;\r
d7ce7006 922 Status = pTcp4Protocol->GetModeData ( pTcp4Protocol,\r
923 NULL,\r
924 pConfigData,\r
925 NULL,\r
926 NULL,\r
927 NULL );\r
928 if ( !EFI_ERROR ( Status )) {\r
929 //\r
930 // Add the new socket to the connection FIFO\r
931 //\r
932 if ( NULL == pSocket->pFifoTail ) {\r
933 //\r
934 // First connection\r
935 //\r
936 pSocket->pFifoHead = pNewSocket;\r
937 }\r
938 else {\r
939 //\r
940 // Add to end of list.\r
941 //\r
942 pSocket->pFifoTail->pNextConnection = pNewSocket;\r
943 }\r
944 pSocket->pFifoTail = pNewSocket;\r
945 pSocket->FifoDepth += 1;\r
946\r
947 //\r
948 // Update the socket state\r
949 //\r
950 pNewSocket->State = SOCKET_STATE_IN_FIFO;\r
951\r
952 //\r
953 // Log the connection\r
954 //\r
955 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,\r
956 "0x%08x: Socket on port %d.%d.%d.%d:%d connected to %d.%d.%d.%d:%d\r\n",\r
957 pNewSocket,\r
958 pConfigData->AccessPoint.StationAddress.Addr[0],\r
959 pConfigData->AccessPoint.StationAddress.Addr[1],\r
960 pConfigData->AccessPoint.StationAddress.Addr[2],\r
961 pConfigData->AccessPoint.StationAddress.Addr[3],\r
962 pConfigData->AccessPoint.StationPort,\r
963 pConfigData->AccessPoint.RemoteAddress.Addr[0],\r
964 pConfigData->AccessPoint.RemoteAddress.Addr[1],\r
965 pConfigData->AccessPoint.RemoteAddress.Addr[2],\r
966 pConfigData->AccessPoint.RemoteAddress.Addr[3],\r
967 pConfigData->AccessPoint.RemotePort ));\r
968 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,\r
969 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",\r
970 pSocket,\r
971 pNewSocket,\r
972 pSocket->FifoDepth ));\r
973\r
974 //\r
975 // Start the receive operation\r
976 //\r
a88c3163 977 EslSocketRxStart ( pNewPort );\r
d7ce7006 978 }\r
979 else {\r
980 DEBUG (( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO,\r
981 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",\r
982 pNewPort,\r
983 Status ));\r
984 }\r
985 }\r
986 else {\r
987 //\r
988 // The listen failed on this port\r
989 //\r
990 DEBUG (( DEBUG_LISTEN | DEBUG_INFO,\r
991 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",\r
992 pPort,\r
993 Status ));\r
994\r
995 //\r
996 // Close the listening port\r
997 //\r
a88c3163 998 EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );\r
d7ce7006 999 }\r
1000 }\r
1001\r
1002 //\r
1003 // Done with the socket if necessary\r
1004 //\r
1005 if ( EFI_ERROR ( Status )) {\r
1006 TempStatus = EslSocketCloseStart ( &pNewSocket->SocketProtocol,\r
1007 TRUE,\r
1008 &pSocket->errno );\r
1009 ASSERT ( EFI_SUCCESS == TempStatus );\r
1010 }\r
1011 }\r
1012 }\r
1013 else {\r
1014 DEBUG (( DEBUG_CONNECTION,\r
1015 "0x%08x: Socket FIFO full, connection refused\r\n",\r
1016 pSocket ));\r
1017\r
1018 //\r
1019 // The FIFO is full or the socket is in the wrong state\r
1020 //\r
1021 Status = EFI_BUFFER_TOO_SMALL;\r
1022 }\r
1023\r
1024 //\r
1025 // Close the connection if necessary\r
1026 //\r
1027 if (( EFI_ERROR ( Status ))\r
1028 && ( NULL == TcpPortHandle )) {\r
1029 //\r
1030 // TODO: Finish this code path\r
1031 // The new connection does not fit into the connection FIFO\r
1032 //\r
1033 // Process:\r
1034 // Call close\r
1035 // Release the resources\r
1036 \r
1037 }\r
1038\r
1039 DBG_EXIT ( );\r
1040}\r
1041\r
1042\r
1043/**\r
a88c3163 1044 Get the local socket address.\r
d7ce7006 1045\r
a88c3163 1046 This routine returns the IPv4 address and TCP port number associated\r
1047 with the local socket.\r
d7ce7006 1048\r
a88c3163 1049 This routine is called by ::EslSocketGetLocalAddress to determine the\r
1050 network address for the SOCK_STREAM or SOCK_SEQPACKET socket.\r
1051\r
1052 @param [in] pPort Address of an ::ESL_PORT structure.\r
1053\r
1054 @param [out] pSockAddr Network address to receive the local system address\r
1055\r
1056**/\r
1057VOID\r
1058EslTcp4LocalAddressGet (\r
1059 IN ESL_PORT * pPort,\r
1060 OUT struct sockaddr * pSockAddr\r
1061 )\r
1062{\r
1063 struct sockaddr_in * pLocalAddress;\r
1064 ESL_TCP4_CONTEXT * pTcp4;\r
1065\r
1066 DBG_ENTER ( );\r
1067\r
1068 //\r
1069 // Return the local address\r
1070 //\r
1071 pTcp4 = &pPort->Context.Tcp4;\r
1072 pLocalAddress = (struct sockaddr_in *)pSockAddr;\r
1073 pLocalAddress->sin_family = AF_INET;\r
1074 pLocalAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.StationPort );\r
1075 CopyMem ( &pLocalAddress->sin_addr,\r
1076 &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],\r
1077 sizeof ( pLocalAddress->sin_addr ));\r
1078\r
1079 DBG_EXIT ( );\r
1080}\r
1081\r
1082\r
1083/**\r
1084 Set the local port address.\r
1085\r
1086 This routine sets the local port address.\r
1087\r
1088 This support routine is called by ::EslSocketPortAllocate.\r
1089\r
1090 @param [in] pPort Address of an ESL_PORT structure\r
1091 @param [in] pSockAddr Address of a sockaddr structure that contains the\r
1092 connection point on the local machine. An IPv4 address\r
1093 of INADDR_ANY specifies that the connection is made to\r
1094 all of the network stacks on the platform. Specifying a\r
1095 specific IPv4 address restricts the connection to the\r
1096 network stack supporting that address. Specifying zero\r
1097 for the port causes the network layer to assign a port\r
1098 number from the dynamic range. Specifying a specific\r
1099 port number causes the network layer to use that port.\r
1100\r
1101 @param [in] bBindTest TRUE = run bind testing\r
1102\r
1103 @retval EFI_SUCCESS The operation was successful\r
d7ce7006 1104\r
1105 **/\r
1106EFI_STATUS\r
a88c3163 1107EslTcp4LocalAddressSet (\r
1108 IN ESL_PORT * pPort,\r
1109 IN CONST struct sockaddr * pSockAddr,\r
1110 IN BOOLEAN bBindTest\r
d7ce7006 1111 )\r
1112{\r
d7ce7006 1113 EFI_TCP4_ACCESS_POINT * pAccessPoint;\r
a88c3163 1114 CONST struct sockaddr_in * pIpAddress;\r
1115 CONST UINT8 * pIpv4Address;\r
d7ce7006 1116 EFI_STATUS Status;\r
1117\r
1118 DBG_ENTER ( );\r
1119\r
1120 //\r
a88c3163 1121 // Validate the address\r
1122 //\r
1123 pIpAddress = (struct sockaddr_in *)pSockAddr;\r
1124 if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {\r
d7ce7006 1125 //\r
a88c3163 1126 // The local address must not be the broadcast address\r
d7ce7006 1127 //\r
a88c3163 1128 Status = EFI_INVALID_PARAMETER;\r
1129 pPort->pSocket->errno = EADDRNOTAVAIL;\r
1130 }\r
1131 else {\r
d7ce7006 1132 //\r
a88c3163 1133 // Set the local address\r
d7ce7006 1134 //\r
a88c3163 1135 pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;\r
1136 pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;\r
1137 pAccessPoint->StationAddress.Addr[0] = pIpv4Address[0];\r
1138 pAccessPoint->StationAddress.Addr[1] = pIpv4Address[1];\r
1139 pAccessPoint->StationAddress.Addr[2] = pIpv4Address[2];\r
1140 pAccessPoint->StationAddress.Addr[3] = pIpv4Address[3];\r
d7ce7006 1141\r
1142 //\r
a88c3163 1143 // Determine if the default address is used\r
d7ce7006 1144 //\r
a88c3163 1145 pAccessPoint->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );\r
1146 \r
d7ce7006 1147 //\r
a88c3163 1148 // Set the subnet mask\r
d7ce7006 1149 //\r
a88c3163 1150 if ( pAccessPoint->UseDefaultAddress ) {\r
1151 pAccessPoint->SubnetMask.Addr[0] = 0;\r
1152 pAccessPoint->SubnetMask.Addr[1] = 0;\r
1153 pAccessPoint->SubnetMask.Addr[2] = 0;\r
1154 pAccessPoint->SubnetMask.Addr[3] = 0;\r
1155 }\r
1156 else {\r
1157 pAccessPoint->SubnetMask.Addr[0] = 0xff;\r
1158 pAccessPoint->SubnetMask.Addr[1] = 0xff;\r
1159 pAccessPoint->SubnetMask.Addr[2] = 0xff;\r
1160 pAccessPoint->SubnetMask.Addr[3] = 0xff;\r
d7ce7006 1161 }\r
d7ce7006 1162\r
1163 //\r
a88c3163 1164 // Validate the IP address\r
d7ce7006 1165 //\r
a88c3163 1166 pAccessPoint->StationPort = 0;\r
1167 Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )\r
1168 : EFI_SUCCESS;\r
1169 if ( !EFI_ERROR ( Status )) {\r
1170 //\r
1171 // Set the port number\r
1172 //\r
1173 pAccessPoint->StationPort = SwapBytes16 ( pIpAddress->sin_port );\r
1174\r
1175 //\r
1176 // Display the local address\r
1177 //\r
1178 DEBUG (( DEBUG_BIND,\r
1179 "0x%08x: Port, Local TCP4 Address: %d.%d.%d.%d:%d\r\n",\r
1180 pPort,\r
1181 pAccessPoint->StationAddress.Addr[0],\r
1182 pAccessPoint->StationAddress.Addr[1],\r
1183 pAccessPoint->StationAddress.Addr[2],\r
1184 pAccessPoint->StationAddress.Addr[3],\r
1185 pAccessPoint->StationPort ));\r
d7ce7006 1186 }\r
a88c3163 1187 }\r
1188\r
1189 //\r
1190 // Return the operation status\r
1191 //\r
1192 DBG_EXIT_STATUS ( Status );\r
1193 return Status;\r
1194}\r
1195\r
1196\r
1197/**\r
1198 Free a receive packet\r
1199\r
1200 This routine performs the network specific operations necessary\r
1201 to free a receive packet.\r
1202\r
1203 This routine is called by ::EslSocketPortCloseTxDone to free a\r
1204 receive packet.\r
1205\r
1206 @param [in] pPacket Address of an ::ESL_PACKET structure.\r
1207 @param [in, out] pRxBytes Address of the count of RX bytes\r
1208\r
1209**/\r
1210VOID\r
1211EslTcp4PacketFree (\r
1212 IN ESL_PACKET * pPacket,\r
1213 IN OUT size_t * pRxBytes\r
1214 )\r
1215{\r
1216 DBG_ENTER ( );\r
1217\r
1218 //\r
1219 // Account for the receive bytes\r
1220 //\r
1221 *pRxBytes -= pPacket->Op.Tcp4Rx.RxData.DataLength;\r
1222 DBG_EXIT ( );\r
1223}\r
1224\r
d7ce7006 1225\r
a88c3163 1226/**\r
1227 Initialize the network specific portions of an ::ESL_PORT structure.\r
1228\r
1229 This routine initializes the network specific portions of an\r
1230 ::ESL_PORT structure for use by the socket.\r
1231\r
1232 This support routine is called by ::EslSocketPortAllocate\r
1233 to connect the socket with the underlying network adapter\r
1234 running the TCPv4 protocol.\r
1235\r
1236 @param [in] pPort Address of an ESL_PORT structure\r
1237 @param [in] DebugFlags Flags for debug messages\r
1238\r
1239 @retval EFI_SUCCESS - Socket successfully created\r
1240\r
1241 **/\r
1242EFI_STATUS\r
1243EslTcp4PortAllocate (\r
1244 IN ESL_PORT * pPort,\r
1245 IN UINTN DebugFlags\r
1246 )\r
1247{\r
1248 EFI_TCP4_ACCESS_POINT * pAccessPoint;\r
1249 ESL_SOCKET * pSocket;\r
1250 ESL_TCP4_CONTEXT * pTcp4;\r
1251 EFI_STATUS Status;\r
1252\r
1253 DBG_ENTER ( );\r
1254\r
1255 //\r
1256 // Use for/break instead of goto\r
1257 for ( ; ; ) {\r
d7ce7006 1258 //\r
1259 // Allocate the close event\r
1260 //\r
a88c3163 1261 pSocket = pPort->pSocket;\r
1262 pTcp4 = &pPort->Context.Tcp4;\r
d7ce7006 1263 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
1264 TPL_SOCKETS,\r
a88c3163 1265 (EFI_EVENT_NOTIFY)EslSocketPortCloseComplete,\r
d7ce7006 1266 pPort,\r
1267 &pTcp4->CloseToken.CompletionToken.Event);\r
1268 if ( EFI_ERROR ( Status )) {\r
1269 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1270 "ERROR - Failed to create the close event, Status: %r\r\n",\r
1271 Status ));\r
1272 pSocket->errno = ENOMEM;\r
1273 break;\r
1274 }\r
1275 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
1276 "0x%08x: Created close event\r\n",\r
1277 pTcp4->CloseToken.CompletionToken.Event ));\r
1278\r
1279 //\r
1280 // Allocate the connection event\r
1281 //\r
1282 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
1283 TPL_SOCKETS,\r
a88c3163 1284 (EFI_EVENT_NOTIFY)EslTcp4ConnectComplete,\r
d7ce7006 1285 pPort,\r
1286 &pTcp4->ConnectToken.CompletionToken.Event);\r
1287 if ( EFI_ERROR ( Status )) {\r
1288 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1289 "ERROR - Failed to create the connect event, Status: %r\r\n",\r
1290 Status ));\r
1291 pSocket->errno = ENOMEM;\r
1292 break;\r
1293 }\r
1294 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
1295 "0x%08x: Created connect event\r\n",\r
1296 pTcp4->ConnectToken.CompletionToken.Event ));\r
1297\r
1298 //\r
a88c3163 1299 // Initialize the port\r
d7ce7006 1300 //\r
a88c3163 1301 pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Tcp4Tx.TxData );\r
1302 pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Tx.CompletionToken.Event );\r
1303 pSocket->TxTokenOffset = OFFSET_OF ( EFI_TCP4_IO_TOKEN, Packet.TxData );\r
d7ce7006 1304\r
1305 //\r
a88c3163 1306 // Save the cancel, receive and transmit addresses\r
1307 // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED\r
d7ce7006 1308 //\r
a88c3163 1309 pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.TCPv4->Configure;\r
3bdf9aae 1310 pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.TCPv4->Poll;\r
a88c3163 1311 pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Receive;\r
1312 pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Transmit;\r
d7ce7006 1313\r
1314 //\r
a88c3163 1315 // Set the configuration flags\r
d7ce7006 1316 //\r
a88c3163 1317 pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;\r
1318 pAccessPoint->ActiveFlag = FALSE;\r
1319 pTcp4->ConfigData.TimeToLive = 255;\r
d7ce7006 1320 break;\r
1321 }\r
1322\r
d7ce7006 1323 //\r
1324 // Return the operation status\r
1325 //\r
1326 DBG_EXIT_STATUS ( Status );\r
1327 return Status;\r
1328}\r
1329\r
1330\r
1331/**\r
1332 Close a TCP4 port.\r
1333\r
a88c3163 1334 This routine releases the network specific resources allocated by\r
1335 ::EslTcp4PortAllocate.\r
1336\r
1337 This routine is called by ::EslSocketPortClose.\r
1338 See the \ref PortCloseStateMachine section.\r
d7ce7006 1339 \r
a88c3163 1340 @param [in] pPort Address of an ::ESL_PORT structure.\r
d7ce7006 1341\r
1342 @retval EFI_SUCCESS The port is closed\r
1343 @retval other Port close error\r
1344\r
1345**/\r
1346EFI_STATUS\r
a88c3163 1347EslTcp4PortClose (\r
1348 IN ESL_PORT * pPort\r
d7ce7006 1349 )\r
1350{\r
1351 UINTN DebugFlags;\r
a88c3163 1352 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 1353 EFI_STATUS Status;\r
1354 \r
1355 DBG_ENTER ( );\r
1356\r
d7ce7006 1357 //\r
1358 // Locate the port in the socket list\r
1359 //\r
1360 Status = EFI_SUCCESS;\r
d7ce7006 1361 DebugFlags = pPort->DebugFlags;\r
d7ce7006 1362 pTcp4 = &pPort->Context.Tcp4;\r
d7ce7006 1363\r
1364 //\r
1365 // Done with the connect event\r
1366 //\r
1367 if ( NULL != pTcp4->ConnectToken.CompletionToken.Event ) {\r
1368 Status = gBS->CloseEvent ( pTcp4->ConnectToken.CompletionToken.Event );\r
1369 if ( !EFI_ERROR ( Status )) {\r
1370 DEBUG (( DebugFlags | DEBUG_POOL,\r
1371 "0x%08x: Closed connect event\r\n",\r
1372 pTcp4->ConnectToken.CompletionToken.Event ));\r
1373 }\r
1374 else {\r
1375 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1376 "ERROR - Failed to close the connect event, Status: %r\r\n",\r
1377 Status ));\r
1378 ASSERT ( EFI_SUCCESS == Status );\r
1379 }\r
1380 }\r
1381\r
1382 //\r
1383 // Done with the close event\r
1384 //\r
1385 if ( NULL != pTcp4->CloseToken.CompletionToken.Event ) {\r
1386 Status = gBS->CloseEvent ( pTcp4->CloseToken.CompletionToken.Event );\r
1387 if ( !EFI_ERROR ( Status )) {\r
1388 DEBUG (( DebugFlags | DEBUG_POOL,\r
1389 "0x%08x: Closed close event\r\n",\r
1390 pTcp4->CloseToken.CompletionToken.Event ));\r
1391 }\r
1392 else {\r
1393 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1394 "ERROR - Failed to close the close event, Status: %r\r\n",\r
1395 Status ));\r
1396 ASSERT ( EFI_SUCCESS == Status );\r
1397 }\r
1398 }\r
1399\r
1400 //\r
1401 // Done with the listen completion event\r
1402 //\r
1403 if ( NULL != pTcp4->ListenToken.CompletionToken.Event ) {\r
1404 Status = gBS->CloseEvent ( pTcp4->ListenToken.CompletionToken.Event );\r
1405 if ( !EFI_ERROR ( Status )) {\r
1406 DEBUG (( DebugFlags | DEBUG_POOL,\r
1407 "0x%08x: Closed listen completion event\r\n",\r
1408 pTcp4->ListenToken.CompletionToken.Event ));\r
1409 }\r
1410 else {\r
1411 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1412 "ERROR - Failed to close the listen completion event, Status: %r\r\n",\r
1413 Status ));\r
1414 ASSERT ( EFI_SUCCESS == Status );\r
1415 }\r
1416 }\r
1417\r
d7ce7006 1418 //\r
1419 // Return the operation status\r
1420 //\r
1421 DBG_EXIT_STATUS ( Status );\r
1422 return Status;\r
1423}\r
1424\r
1425\r
1426/**\r
a88c3163 1427 Perform the network specific close operation on the port.\r
d7ce7006 1428\r
a88c3163 1429 This routine performs a cancel operations on the TCPv4 port to\r
1430 shutdown the receive operations on the port.\r
d7ce7006 1431\r
a88c3163 1432 This routine is called by the ::EslSocketPortCloseTxDone\r
1433 routine after the port completes all of the transmission.\r
1434\r
1435 @param [in] pPort Address of an ::ESL_PORT structure.\r
1436\r
1437 @retval EFI_SUCCESS The port is closed, not normally returned\r
1438 @retval EFI_NOT_READY The port is still closing\r
1439 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
1440 most likely the routine was called already.\r
d7ce7006 1441\r
1442**/\r
a88c3163 1443EFI_STATUS\r
1444EslTcp4PortCloseOp (\r
1445 IN ESL_PORT * pPort\r
d7ce7006 1446 )\r
1447{\r
a88c3163 1448 ESL_TCP4_CONTEXT * pTcp4;\r
1449 EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
d7ce7006 1450 EFI_STATUS Status;\r
1451\r
1452 DBG_ENTER ( );\r
1453\r
1454 //\r
a88c3163 1455 // Close the configured port\r
d7ce7006 1456 //\r
a88c3163 1457 Status = EFI_SUCCESS;\r
1458 pTcp4 = &pPort->Context.Tcp4;\r
1459 pTcp4Protocol = pPort->pProtocol.TCPv4;\r
1460 pTcp4->CloseToken.AbortOnClose = pPort->bCloseNow;\r
1461 Status = pTcp4Protocol->Close ( pTcp4Protocol,\r
1462 &pTcp4->CloseToken );\r
1463 if ( !EFI_ERROR ( Status )) {\r
1464 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
1465 "0x%08x: Port close started\r\n",\r
1466 pPort ));\r
1467 }\r
1468 else {\r
1469 DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
1470 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",\r
1471 pPort,\r
1472 Status ));\r
1473 }\r
d7ce7006 1474\r
1475 //\r
a88c3163 1476 // Return the operation status\r
d7ce7006 1477 //\r
d7ce7006 1478 DBG_EXIT_STATUS ( Status );\r
a88c3163 1479 return Status;\r
d7ce7006 1480}\r
1481\r
1482\r
1483/**\r
a88c3163 1484 Receive data from a network connection.\r
d7ce7006 1485\r
a88c3163 1486 This routine attempts to return buffered data to the caller. The\r
1487 data is removed from the urgent queue if the message flag MSG_OOB\r
1488 is specified, otherwise data is removed from the normal queue.\r
1489 See the \ref ReceiveEngine section.\r
d7ce7006 1490\r
a88c3163 1491 This routine is called by ::EslSocketReceive to handle the network\r
1492 specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET\r
1493 sockets.\r
d7ce7006 1494\r
a88c3163 1495 @param [in] pPort Address of an ::ESL_PORT structure.\r
d7ce7006 1496\r
a88c3163 1497 @param [in] pPacket Address of an ::ESL_PACKET structure.\r
d7ce7006 1498 \r
a88c3163 1499 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed\r
d7ce7006 1500 \r
1501 @param [in] BufferLength Length of the the buffer\r
1502 \r
1503 @param [in] pBuffer Address of a buffer to receive the data.\r
1504 \r
1505 @param [in] pDataLength Number of received data bytes in the buffer.\r
1506\r
1507 @param [out] pAddress Network address to receive the remote system address\r
1508\r
a88c3163 1509 @param [out] pSkipBytes Address to receive the number of bytes skipped\r
d7ce7006 1510\r
a88c3163 1511 @return Returns the address of the next free byte in the buffer.\r
d7ce7006 1512\r
1513 **/\r
a88c3163 1514UINT8 *\r
1515EslTcp4Receive (\r
1516 IN ESL_PORT * pPort,\r
1517 IN ESL_PACKET * pPacket,\r
1518 IN BOOLEAN * pbConsumePacket,\r
d7ce7006 1519 IN size_t BufferLength,\r
1520 IN UINT8 * pBuffer,\r
1521 OUT size_t * pDataLength,\r
1522 OUT struct sockaddr * pAddress,\r
a88c3163 1523 OUT size_t * pSkipBytes\r
d7ce7006 1524 )\r
1525{\r
a88c3163 1526 size_t DataLength;\r
d7ce7006 1527 struct sockaddr_in * pRemoteAddress;\r
a88c3163 1528 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 1529\r
1530 DBG_ENTER ( );\r
1531\r
1532 //\r
a88c3163 1533 // Return the remote system address if requested\r
d7ce7006 1534 //\r
a88c3163 1535 if ( NULL != pAddress ) {\r
d7ce7006 1536 //\r
a88c3163 1537 // Build the remote address\r
d7ce7006 1538 //\r
1539 pTcp4 = &pPort->Context.Tcp4;\r
a88c3163 1540 DEBUG (( DEBUG_RX,\r
1541 "Getting packet remote address: %d.%d.%d.%d:%d\r\n",\r
1542 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
1543 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],\r
1544 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],\r
1545 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],\r
1546 pTcp4->ConfigData.AccessPoint.RemotePort ));\r
1547 pRemoteAddress = (struct sockaddr_in *)pAddress;\r
1548 CopyMem ( &pRemoteAddress->sin_addr,\r
1549 &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
1550 sizeof ( pRemoteAddress->sin_addr ));\r
1551 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );\r
d7ce7006 1552 }\r
1553\r
1554 //\r
a88c3163 1555 // Determine the amount of received data\r
d7ce7006 1556 //\r
a88c3163 1557 DataLength = pPacket->ValidBytes;\r
1558 if ( BufferLength < DataLength ) {\r
1559 DataLength = BufferLength;\r
1560 }\r
d7ce7006 1561\r
1562 //\r
a88c3163 1563 // Move the data into the buffer\r
1564 //\r
1565 DEBUG (( DEBUG_RX,\r
1566 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",\r
1567 pPort,\r
1568 pPacket,\r
1569 pBuffer,\r
1570 DataLength ));\r
1571 CopyMem ( pBuffer, pPacket->pBuffer, DataLength );\r
d7ce7006 1572\r
a88c3163 1573 //\r
1574 // Determine if the data is being read\r
1575 //\r
1576 if ( *pbConsumePacket ) {\r
d7ce7006 1577 //\r
a88c3163 1578 // Account for the bytes consumed\r
d7ce7006 1579 //\r
a88c3163 1580 pPacket->pBuffer += DataLength;\r
1581 pPacket->ValidBytes -= DataLength;\r
1582 DEBUG (( DEBUG_RX,\r
1583 "0x%08x: Port account for 0x%08x bytes\r\n",\r
d7ce7006 1584 pPort,\r
a88c3163 1585 DataLength ));\r
d7ce7006 1586\r
1587 //\r
a88c3163 1588 // Determine if the entire packet was consumed\r
d7ce7006 1589 //\r
a88c3163 1590 if (( 0 == pPacket->ValidBytes )\r
1591 || ( SOCK_STREAM != pPort->pSocket->Type )) {\r
1592 //\r
1593 // All done with this packet\r
1594 // Account for any discarded data\r
1595 //\r
1596 *pSkipBytes = pPacket->ValidBytes;\r
d7ce7006 1597 }\r
a88c3163 1598 else\r
1599 {\r
1600 //\r
1601 // More data to consume later\r
1602 //\r
1603 *pbConsumePacket = FALSE;\r
d7ce7006 1604 }\r
1605 }\r
d7ce7006 1606\r
a88c3163 1607 //\r
1608 // Return the data length and the buffer address\r
1609 //\r
1610 *pDataLength = DataLength;\r
1611 DBG_EXIT_HEX ( pBuffer );\r
1612 return pBuffer;\r
1613}\r
d7ce7006 1614\r
a88c3163 1615\r
1616/**\r
1617 Get the remote socket address.\r
1618\r
1619 This routine returns the address of the remote connection point\r
1620 associated with the SOCK_STREAM or SOCK_SEQPACKET socket.\r
1621\r
1622 This routine is called by ::EslSocketGetPeerAddress to detemine\r
1623 the TCPv4 address and por number associated with the network adapter.\r
1624\r
1625 @param [in] pPort Address of an ::ESL_PORT structure.\r
1626\r
1627 @param [out] pAddress Network address to receive the remote system address\r
1628\r
1629**/\r
1630VOID\r
1631EslTcp4RemoteAddressGet (\r
1632 IN ESL_PORT * pPort,\r
1633 OUT struct sockaddr * pAddress\r
1634 )\r
1635{\r
1636 struct sockaddr_in * pRemoteAddress;\r
1637 ESL_TCP4_CONTEXT * pTcp4;\r
1638\r
1639 DBG_ENTER ( );\r
1640\r
1641 //\r
1642 // Return the remote address\r
1643 //\r
1644 pTcp4 = &pPort->Context.Tcp4;\r
1645 pRemoteAddress = (struct sockaddr_in *)pAddress;\r
1646 pRemoteAddress->sin_family = AF_INET;\r
1647 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );\r
1648 CopyMem ( &pRemoteAddress->sin_addr,\r
1649 &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
1650 sizeof ( pRemoteAddress->sin_addr ));\r
d7ce7006 1651\r
1652 DBG_EXIT ( );\r
1653}\r
1654\r
1655\r
1656/**\r
a88c3163 1657 Set the remote address\r
1658\r
1659 This routine sets the remote address in the port.\r
1660\r
1661 This routine is called by ::EslSocketConnect to specify the\r
1662 remote network address.\r
1663\r
1664 @param [in] pPort Address of an ::ESL_PORT structure.\r
1665\r
1666 @param [in] pSockAddr Network address of the remote system.\r
1667\r
1668 @param [in] SockAddrLength Length in bytes of the network address.\r
d7ce7006 1669\r
a88c3163 1670 @retval EFI_SUCCESS The operation was successful\r
d7ce7006 1671\r
1672 **/\r
a88c3163 1673EFI_STATUS\r
1674EslTcp4RemoteAddressSet (\r
1675 IN ESL_PORT * pPort,\r
1676 IN CONST struct sockaddr * pSockAddr,\r
1677 IN socklen_t SockAddrLength\r
d7ce7006 1678 )\r
1679{\r
a88c3163 1680 CONST struct sockaddr_in * pRemoteAddress;\r
1681 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 1682 EFI_STATUS Status;\r
1683\r
1684 DBG_ENTER ( );\r
1685\r
1686 //\r
a88c3163 1687 // Set the remote address\r
d7ce7006 1688 //\r
d7ce7006 1689 pTcp4 = &pPort->Context.Tcp4;\r
a88c3163 1690 pRemoteAddress = (struct sockaddr_in *)pSockAddr;\r
1691 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );\r
1692 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );\r
1693 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );\r
1694 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );\r
1695 pTcp4->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );\r
1696 Status = EFI_SUCCESS;\r
1697 if ( INADDR_BROADCAST == pRemoteAddress->sin_addr.s_addr ) {\r
1698 DEBUG (( DEBUG_CONNECT,\r
1699 "ERROR - Invalid remote address\r\n" ));\r
1700 Status = EFI_INVALID_PARAMETER;\r
1701 pPort->pSocket->errno = EAFNOSUPPORT;\r
d7ce7006 1702 }\r
1703\r
a88c3163 1704 //\r
1705 // Return the operation status\r
1706 //\r
1707 DBG_EXIT_STATUS ( Status );\r
1708 return Status;\r
d7ce7006 1709}\r
1710\r
1711\r
1712/**\r
a88c3163 1713 Process the receive completion\r
1714\r
1715 This routine queues the data in FIFO order in either the urgent\r
1716 or normal data queues depending upon the type of data received.\r
1717 See the \ref ReceiveEngine section.\r
1718\r
1719 This routine is called by the TCPv4 driver when some data is\r
1720 received.\r
d7ce7006 1721\r
a88c3163 1722 Buffer the data that was just received.\r
1723\r
1724 @param [in] Event The receive completion event\r
d7ce7006 1725\r
a88c3163 1726 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
d7ce7006 1727\r
1728**/\r
1729VOID\r
a88c3163 1730EslTcp4RxComplete (\r
1731 IN EFI_EVENT Event,\r
1732 IN ESL_IO_MGMT * pIo\r
d7ce7006 1733 )\r
1734{\r
a88c3163 1735 BOOLEAN bUrgent;\r
1736 size_t LengthInBytes;\r
1737 ESL_PACKET * pPacket;\r
1738 EFI_STATUS Status;\r
d7ce7006 1739\r
1740 DBG_ENTER ( );\r
1741\r
1742 //\r
a88c3163 1743 // Get the operation status.\r
d7ce7006 1744 //\r
a88c3163 1745 Status = pIo->Token.Tcp4Rx.CompletionToken.Status;\r
d7ce7006 1746\r
1747 //\r
a88c3163 1748 // +--------------------+ +---------------------------+\r
1749 // | ESL_IO_MGMT | | ESL_PACKET |\r
1750 // | | | |\r
1751 // | +---------------+ +-----------------------+ |\r
1752 // | | Token | | EFI_TCP4_RECEIVE_DATA | |\r
1753 // | | RxData --> | | |\r
1754 // | | | +-----------------------+---+\r
1755 // | | Event | | Data Buffer |\r
1756 // +----+---------------+ | |\r
1757 // | |\r
1758 // +---------------------------+\r
d7ce7006 1759 //\r
a88c3163 1760 //\r
1761 // Duplicate the buffer address and length for use by the\r
1762 // buffer handling code in EslTcp4Receive. These fields are\r
1763 // used when a partial read is done of the data from the\r
1764 // packet.\r
1765 //\r
1766 pPacket = pIo->pPacket;\r
1767 pPacket->pBuffer = pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer;\r
1768 LengthInBytes = pPacket->Op.Tcp4Rx.RxData.DataLength;\r
1769 pPacket->ValidBytes = LengthInBytes;\r
d7ce7006 1770\r
a88c3163 1771 //\r
1772 // Get the data type so that it may be linked to the\r
1773 // correct receive buffer list on the ESL_SOCKET structure\r
1774 //\r
1775 bUrgent = pPacket->Op.Tcp4Rx.RxData.UrgentFlag;\r
d7ce7006 1776\r
1777 //\r
a88c3163 1778 // Complete this request\r
d7ce7006 1779 //\r
a88c3163 1780 EslSocketRxComplete ( pIo, Status, LengthInBytes, bUrgent );\r
1781 DBG_EXIT ( );\r
1782}\r
1783\r
1784\r
1785/**\r
1786 Start a receive operation\r
1787\r
1788 This routine posts a receive buffer to the TCPv4 driver.\r
1789 See the \ref ReceiveEngine section.\r
1790\r
1791 This support routine is called by EslSocketRxStart.\r
1792\r
1793 @param [in] pPort Address of an ::ESL_PORT structure.\r
1794 @param [in] pIo Address of an ::ESL_IO_MGMT structure.\r
1795\r
1796 **/\r
1797VOID\r
1798EslTcp4RxStart (\r
1799 IN ESL_PORT * pPort,\r
1800 IN ESL_IO_MGMT * pIo\r
1801 )\r
1802{\r
1803 ESL_PACKET * pPacket;\r
1804\r
1805 DBG_ENTER ( );\r
1806\r
1807 //\r
1808 // Initialize the buffer for receive\r
1809 //\r
1810 pPacket = pIo->pPacket;\r
1811 pIo->Token.Tcp4Rx.Packet.RxData = &pPacket->Op.Tcp4Rx.RxData;\r
1812 pPacket->Op.Tcp4Rx.RxData.DataLength = sizeof ( pPacket->Op.Tcp4Rx.Buffer );\r
1813 pPacket->Op.Tcp4Rx.RxData.FragmentCount = 1;\r
1814 pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentLength = pPacket->Op.Tcp4Rx.RxData.DataLength;\r
1815 pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Rx.Buffer[0];\r
d7ce7006 1816\r
1817 DBG_EXIT ( );\r
1818}\r
1819\r
1820\r
1821/**\r
1822 Determine if the socket is configured.\r
1823\r
a88c3163 1824 This routine uses the flag ESL_SOCKET::bConfigured to determine\r
1825 if the network layer's configuration routine has been called.\r
1826\r
1827 This routine is called by EslSocketIsConfigured to verify\r
1828 that the socket has been configured.\r
1829\r
1830 @param [in] pSocket Address of an ::ESL_SOCKET structure.\r
d7ce7006 1831\r
d7ce7006 1832 @retval EFI_SUCCESS - The port is connected\r
1833 @retval EFI_NOT_STARTED - The port is not connected\r
1834\r
1835 **/\r
1836 EFI_STATUS\r
a88c3163 1837 EslTcp4SocketIsConfigured (\r
1838 IN ESL_SOCKET * pSocket\r
d7ce7006 1839 )\r
1840{\r
1841 EFI_STATUS Status;\r
1842\r
1843 DBG_ENTER ( );\r
1844\r
1845 //\r
1846 // Determine the socket configuration status\r
1847 //\r
1848 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;\r
1849\r
1850 //\r
1851 // Return the port connected state.\r
1852 //\r
1853 DBG_EXIT_STATUS ( Status );\r
1854 return Status;\r
1855}\r
1856\r
1857\r
1858/**\r
1859 Buffer data for transmission over a network connection.\r
1860\r
a88c3163 1861 This routine buffers data for the transmit engine in one of two\r
1862 queues, one for urgent (out-of-band) data and the other for normal\r
1863 data. The urgent data is provided to TCP as soon as it is available,\r
1864 allowing the TCP layer to schedule transmission of the urgent data\r
1865 between packets of normal data.\r
d7ce7006 1866\r
a88c3163 1867 This routine is called by ::EslSocketTransmit to buffer\r
1868 data for transmission. When the \ref TransmitEngine has resources,\r
1869 this routine will start the transmission of the next buffer on\r
1870 the network connection.\r
d7ce7006 1871\r
1872 Transmission errors are returned during the next transmission or\r
1873 during the close operation. Only buffering errors are returned\r
1874 during the current transmission attempt.\r
1875\r
a88c3163 1876 @param [in] pSocket Address of an ::ESL_SOCKET structure\r
d7ce7006 1877 \r
1878 @param [in] Flags Message control flags\r
1879 \r
1880 @param [in] BufferLength Length of the the buffer\r
1881 \r
1882 @param [in] pBuffer Address of a buffer to receive the data.\r
1883 \r
1884 @param [in] pDataLength Number of received data bytes in the buffer.\r
1885\r
a88c3163 1886 @param [in] pAddress Network address of the remote system address\r
1887\r
1888 @param [in] AddressLength Length of the remote network address structure\r
1889\r
d7ce7006 1890 @retval EFI_SUCCESS - Socket data successfully buffered\r
1891\r
1892 **/\r
1893EFI_STATUS\r
a88c3163 1894EslTcp4TxBuffer (\r
1895 IN ESL_SOCKET * pSocket,\r
d7ce7006 1896 IN int Flags,\r
1897 IN size_t BufferLength,\r
1898 IN CONST UINT8 * pBuffer,\r
a88c3163 1899 OUT size_t * pDataLength,\r
1900 IN const struct sockaddr * pAddress,\r
1901 IN socklen_t AddressLength\r
d7ce7006 1902 )\r
1903{\r
1904 BOOLEAN bUrgent;\r
a88c3163 1905 BOOLEAN bUrgentQueue;\r
1906 ESL_PACKET * pPacket;\r
1907 ESL_IO_MGMT ** ppActive;\r
1908 ESL_IO_MGMT ** ppFree;\r
1909 ESL_PORT * pPort;\r
1910 ESL_PACKET ** ppQueueHead;\r
1911 ESL_PACKET ** ppQueueTail;\r
1912 ESL_PACKET * pPreviousPacket;\r
1913 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 1914 size_t * pTxBytes;\r
1915 EFI_TCP4_TRANSMIT_DATA * pTxData;\r
1916 EFI_STATUS Status;\r
1917 EFI_TPL TplPrevious;\r
1918\r
1919 DBG_ENTER ( );\r
1920\r
1921 //\r
1922 // Assume failure\r
1923 //\r
1924 Status = EFI_UNSUPPORTED;\r
1925 pSocket->errno = ENOTCONN;\r
a88c3163 1926 *pDataLength = 0;\r
d7ce7006 1927\r
1928 //\r
1929 // Verify that the socket is connected\r
1930 //\r
1931 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
1932 //\r
1933 // Locate the port\r
1934 //\r
1935 pPort = pSocket->pPortList;\r
1936 if ( NULL != pPort ) {\r
1937 //\r
1938 // Determine the queue head\r
1939 //\r
1940 pTcp4 = &pPort->Context.Tcp4;\r
1941 bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));\r
a88c3163 1942 bUrgentQueue = bUrgent\r
1943 && ( !pSocket->bOobInLine )\r
1944 && pSocket->pApi->bOobSupported;\r
1945 if ( bUrgentQueue ) {\r
d7ce7006 1946 ppQueueHead = &pSocket->pTxOobPacketListHead;\r
1947 ppQueueTail = &pSocket->pTxOobPacketListTail;\r
a88c3163 1948 ppActive = &pPort->pTxOobActive;\r
1949 ppFree = &pPort->pTxOobFree;\r
d7ce7006 1950 pTxBytes = &pSocket->TxOobBytes;\r
1951 }\r
1952 else {\r
1953 ppQueueHead = &pSocket->pTxPacketListHead;\r
1954 ppQueueTail = &pSocket->pTxPacketListTail;\r
a88c3163 1955 ppActive = &pPort->pTxActive;\r
1956 ppFree = &pPort->pTxFree;\r
d7ce7006 1957 pTxBytes = &pSocket->TxBytes;\r
1958 }\r
1959\r
1960 //\r
1961 // Verify that there is enough room to buffer another\r
1962 // transmit operation\r
1963 //\r
1964 if ( pSocket->MaxTxBuf > *pTxBytes ) {\r
a88c3163 1965 if ( pPort->bTxFlowControl ) {\r
1966 DEBUG (( DEBUG_TX,\r
1967 "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",\r
1968 pPort,\r
1969 pSocket->MaxTxBuf,\r
1970 *pTxBytes ));\r
1971 pPort->bTxFlowControl = FALSE;\r
1972 }\r
1973\r
d7ce7006 1974 //\r
1975 // Attempt to allocate the packet\r
1976 //\r
1977 Status = EslSocketPacketAllocate ( &pPacket,\r
1978 sizeof ( pPacket->Op.Tcp4Tx )\r
1979 - sizeof ( pPacket->Op.Tcp4Tx.Buffer )\r
1980 + BufferLength,\r
a88c3163 1981 0,\r
d7ce7006 1982 DEBUG_TX );\r
1983 if ( !EFI_ERROR ( Status )) {\r
1984 //\r
1985 // Initialize the transmit operation\r
1986 //\r
1987 pTxData = &pPacket->Op.Tcp4Tx.TxData;\r
a88c3163 1988 pTxData->Push = TRUE || bUrgent;\r
d7ce7006 1989 pTxData->Urgent = bUrgent;\r
1990 pTxData->DataLength = (UINT32) BufferLength;\r
1991 pTxData->FragmentCount = 1;\r
1992 pTxData->FragmentTable[0].FragmentLength = (UINT32) BufferLength;\r
1993 pTxData->FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Tx.Buffer[0];\r
1994\r
1995 //\r
1996 // Copy the data into the buffer\r
1997 //\r
1998 CopyMem ( &pPacket->Op.Tcp4Tx.Buffer[0],\r
1999 pBuffer,\r
2000 BufferLength );\r
2001\r
2002 //\r
2003 // Synchronize with the socket layer\r
2004 //\r
2005 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2006\r
2007 //\r
2008 // Stop transmission after an error\r
2009 //\r
2010 if ( !EFI_ERROR ( pSocket->TxError )) {\r
2011 //\r
2012 // Display the request\r
2013 //\r
2014 DEBUG (( DEBUG_TX,\r
2015 "Send %d %s bytes from 0x%08x\r\n",\r
2016 BufferLength,\r
2017 bUrgent ? L"urgent" : L"normal",\r
2018 pBuffer ));\r
2019\r
2020 //\r
2021 // Queue the data for transmission\r
2022 //\r
2023 pPacket->pNext = NULL;\r
2024 pPreviousPacket = *ppQueueTail;\r
2025 if ( NULL == pPreviousPacket ) {\r
2026 *ppQueueHead = pPacket;\r
2027 }\r
2028 else {\r
2029 pPreviousPacket->pNext = pPacket;\r
2030 }\r
2031 *ppQueueTail = pPacket;\r
2032 DEBUG (( DEBUG_TX,\r
2033 "0x%08x: Packet on %s transmit list\r\n",\r
2034 pPacket,\r
a88c3163 2035 bUrgentQueue ? L"urgent" : L"normal" ));\r
d7ce7006 2036\r
2037 //\r
2038 // Account for the buffered data\r
2039 //\r
2040 *pTxBytes += BufferLength;\r
2041 *pDataLength = BufferLength;\r
2042\r
2043 //\r
2044 // Start the transmit engine if it is idle\r
2045 //\r
a88c3163 2046 if ( NULL != *ppFree ) {\r
2047 EslSocketTxStart ( pPort,\r
2048 ppQueueHead,\r
2049 ppQueueTail,\r
2050 ppActive,\r
2051 ppFree );\r
d7ce7006 2052 }\r
2053 }\r
2054 else {\r
2055 //\r
2056 // Previous transmit error\r
2057 // Stop transmission\r
2058 //\r
2059 Status = pSocket->TxError;\r
2060 pSocket->errno = EIO;\r
2061\r
2062 //\r
2063 // Free the packet\r
2064 //\r
2065 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
2066 }\r
2067\r
2068 //\r
2069 // Release the socket layer synchronization\r
2070 //\r
2071 RESTORE_TPL ( TplPrevious );\r
2072 }\r
2073 else {\r
2074 //\r
2075 // Packet allocation failed\r
2076 //\r
2077 pSocket->errno = ENOMEM;\r
2078 }\r
2079 }\r
2080 else {\r
a88c3163 2081 if ( !pPort->bTxFlowControl ) {\r
2082 DEBUG (( DEBUG_TX,\r
2083 "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",\r
2084 pPort,\r
2085 pSocket->MaxTxBuf,\r
2086 *pTxBytes ));\r
2087 pPort->bTxFlowControl = TRUE;\r
2088 }\r
d7ce7006 2089 //\r
2090 // Not enough buffer space available\r
2091 //\r
2092 pSocket->errno = EAGAIN;\r
2093 Status = EFI_NOT_READY;\r
2094 }\r
2095 }\r
2096 }\r
2097\r
2098 //\r
2099 // Return the operation status\r
2100 //\r
2101 DBG_EXIT_STATUS ( Status );\r
2102 return Status;\r
2103}\r
2104\r
2105\r
2106/**\r
2107 Process the normal data transmit completion\r
2108\r
a88c3163 2109 This routine use ::EslSocketTxComplete to perform the transmit\r
2110 completion processing for normal data.\r
2111\r
2112 This routine is called by the TCPv4 network layer when a\r
2113 normal data transmit request completes.\r
2114\r
2115 @param [in] Event The normal transmit completion event\r
d7ce7006 2116\r
a88c3163 2117 @param [in] pIo The ESL_IO_MGMT structure address\r
d7ce7006 2118\r
2119**/\r
2120VOID\r
a88c3163 2121EslTcp4TxComplete (\r
d7ce7006 2122 IN EFI_EVENT Event,\r
a88c3163 2123 IN ESL_IO_MGMT * pIo\r
d7ce7006 2124 )\r
2125{\r
2126 UINT32 LengthInBytes;\r
a88c3163 2127 ESL_PACKET * pPacket;\r
2128 ESL_PORT * pPort;\r
2129 ESL_SOCKET * pSocket;\r
d7ce7006 2130 EFI_STATUS Status;\r
2131 \r
2132 DBG_ENTER ( );\r
a88c3163 2133\r
d7ce7006 2134 //\r
2135 // Locate the active transmit packet\r
2136 //\r
a88c3163 2137 pPacket = pIo->pPacket;\r
2138 pPort = pIo->pPort;\r
d7ce7006 2139 pSocket = pPort->pSocket;\r
a88c3163 2140\r
d7ce7006 2141 //\r
a88c3163 2142 // Get the transmit length and status\r
d7ce7006 2143 //\r
d7ce7006 2144 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;\r
2145 pSocket->TxBytes -= LengthInBytes;\r
a88c3163 2146 Status = pIo->Token.Tcp4Tx.CompletionToken.Status;\r
d7ce7006 2147\r
2148 //\r
a88c3163 2149 // Complete the transmit operation\r
d7ce7006 2150 //\r
a88c3163 2151 EslSocketTxComplete ( pIo,\r
2152 LengthInBytes,\r
2153 Status,\r
2154 "Normal ",\r
2155 &pSocket->pTxPacketListHead,\r
2156 &pSocket->pTxPacketListTail,\r
2157 &pPort->pTxActive,\r
2158 &pPort->pTxFree );\r
d7ce7006 2159 DBG_EXIT ( );\r
2160}\r
2161\r
2162\r
2163/**\r
2164 Process the urgent data transmit completion\r
2165\r
a88c3163 2166 This routine use ::EslSocketTxComplete to perform the transmit\r
2167 completion processing for urgent data.\r
d7ce7006 2168\r
a88c3163 2169 This routine is called by the TCPv4 network layer when a\r
2170 urgent data transmit request completes.\r
2171\r
2172 @param [in] Event The urgent transmit completion event\r
2173\r
2174 @param [in] pIo The ESL_IO_MGMT structure address\r
d7ce7006 2175\r
2176**/\r
2177VOID\r
a88c3163 2178EslTcp4TxOobComplete (\r
d7ce7006 2179 IN EFI_EVENT Event,\r
a88c3163 2180 IN ESL_IO_MGMT * pIo\r
d7ce7006 2181 )\r
2182{\r
2183 UINT32 LengthInBytes;\r
a88c3163 2184 ESL_PACKET * pPacket;\r
2185 ESL_PORT * pPort;\r
2186 ESL_SOCKET * pSocket;\r
d7ce7006 2187 EFI_STATUS Status;\r
2188\r
2189 DBG_ENTER ( );\r
2190\r
2191 //\r
2192 // Locate the active transmit packet\r
2193 //\r
a88c3163 2194 pPacket = pIo->pPacket;\r
2195 pPort = pIo->pPort;\r
d7ce7006 2196 pSocket = pPort->pSocket;\r
d7ce7006 2197\r
2198 //\r
a88c3163 2199 // Get the transmit length and status\r
d7ce7006 2200 //\r
d7ce7006 2201 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;\r
2202 pSocket->TxOobBytes -= LengthInBytes;\r
a88c3163 2203 Status = pIo->Token.Tcp4Tx.CompletionToken.Status;\r
d7ce7006 2204\r
2205 //\r
a88c3163 2206 // Complete the transmit operation\r
d7ce7006 2207 //\r
a88c3163 2208 EslSocketTxComplete ( pIo,\r
2209 LengthInBytes,\r
2210 Status,\r
2211 "Urgent ",\r
2212 &pSocket->pTxOobPacketListHead,\r
2213 &pSocket->pTxOobPacketListTail,\r
2214 &pPort->pTxOobActive,\r
2215 &pPort->pTxOobFree );\r
d7ce7006 2216 DBG_EXIT ( );\r
2217}\r
2218\r
2219\r
2220/**\r
a88c3163 2221 Interface between the socket layer and the network specific\r
2222 code that supports SOCK_STREAM and SOCK_SEQPACKET sockets\r
2223 over TCPv4.\r
2224**/\r
2225CONST ESL_PROTOCOL_API cEslTcp4Api = {\r
2226 "TCPv4",\r
2227 IPPROTO_TCP,\r
2228 OFFSET_OF ( ESL_PORT, Context.Tcp4.ConfigData ),\r
2229 OFFSET_OF ( ESL_LAYER, pTcp4List ),\r
2230 OFFSET_OF ( struct sockaddr_in, sin_zero ),\r
2231 sizeof ( struct sockaddr_in ),\r
2232 AF_INET,\r
2233 sizeof (((ESL_PACKET *)0 )->Op.Tcp4Rx ),\r
2234 OFFSET_OF ( ESL_PACKET, Op.Tcp4Rx.Buffer ) - OFFSET_OF ( ESL_PACKET, Op ),\r
2235 OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Rx.Packet.RxData ),\r
2236 TRUE,\r
2237 EADDRINUSE,\r
2238 EslTcp4Accept,\r
2239 EslTcp4ConnectPoll,\r
2240 EslTcp4ConnectStart,\r
2241 EslTcp4SocketIsConfigured,\r
2242 EslTcp4LocalAddressGet,\r
2243 EslTcp4LocalAddressSet,\r
2244 EslTcp4Listen,\r
2245 NULL, // OptionGet\r
2246 NULL, // OptionSet\r
2247 EslTcp4PacketFree,\r
2248 EslTcp4PortAllocate,\r
2249 EslTcp4PortClose,\r
2250 EslTcp4PortCloseOp,\r
2251 FALSE,\r
2252 EslTcp4Receive,\r
2253 EslTcp4RemoteAddressGet,\r
2254 EslTcp4RemoteAddressSet,\r
2255 EslTcp4RxComplete,\r
2256 EslTcp4RxStart,\r
2257 EslTcp4TxBuffer,\r
2258 EslTcp4TxComplete,\r
2259 EslTcp4TxOobComplete\r
2260};\r