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