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