]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/EfiSocketLib/Tcp4.c
StdLib: Replace BSD License with BSD+Patent License
[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
c581e503 4 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
0a2530ea 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
d7ce7006 6\r
a88c3163 7\r
8 \section ConnectionManagement Connection Management\r
0e565888 9\r
a88c3163 10 The ::EslTcp4Listen routine initially places the SOCK_STREAM or\r
11 SOCK_SEQPACKET socket into a listen state. When a remote machine\r
12 makes a connection to the socket, the TCPv4 network layer calls\r
13 ::EslTcp4ListenComplete to complete the connection processing.\r
14 EslTcp4ListenComplete manages the connections by placing them in\r
15 FIFO order in a queue to be serviced by the application. When the\r
16 number of connections exceeds the backlog (ESL_SOCKET::MaxFifoDepth),\r
17 the new connection is closed. Eventually, the application indirectly\r
18 calls ::EslTcp4Accept to remove the next connection from the queue\r
19 and get the associated socket.\r
20\r
d7ce7006 21**/\r
22\r
23#include "Socket.h"\r
24\r
25\r
a88c3163 26/**\r
27 Attempt to connect to a remote TCP port\r
28\r
29 This routine starts the connection processing for a SOCK_STREAM\r
30 or SOCK_SEQPAKCET socket using the TCPv4 network layer. It\r
31 configures the local TCPv4 connection point and then attempts to\r
32 connect to a remote system. Upon completion, the\r
33 ::EslTcp4ConnectComplete routine gets called with the connection\r
34 status.\r
35\r
36 This routine is called by ::EslSocketConnect to initiate the TCPv4\r
37 network specific connect operations. The connection processing is\r
38 initiated by this routine and finished by ::EslTcp4ConnectComplete.\r
39 This pair of routines walks through the list of local TCPv4\r
40 connection points until a connection to the remote system is\r
41 made.\r
42\r
43 @param [in] pSocket Address of an ::ESL_SOCKET structure.\r
44\r
45 @retval EFI_SUCCESS The connection was successfully established.\r
46 @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
47 @retval Others The connection attempt failed.\r
48\r
49 **/\r
50EFI_STATUS\r
51EslTcp4ConnectStart (\r
52 IN ESL_SOCKET * pSocket\r
53 );\r
54\r
55\r
56/**\r
57 Process the connection attempt\r
58\r
59 A system has initiated a connection attempt with a socket in the\r
60 listen state. Attempt to complete the connection.\r
61\r
62 The TCPv4 layer calls this routine when a connection is made to\r
63 the socket in the listen state. See the\r
64 \ref ConnectionManagement section.\r
65\r
66 @param [in] Event The listen completion event\r
67\r
68 @param [in] pPort Address of an ::ESL_PORT structure.\r
69\r
70**/\r
71VOID\r
72EslTcp4ListenComplete (\r
73 IN EFI_EVENT Event,\r
74 IN ESL_PORT * pPort\r
75 );\r
76\r
77\r
d7ce7006 78/**\r
79 Accept a network connection.\r
80\r
a88c3163 81 This routine waits for a network connection to the socket and\r
82 returns the remote network address to the caller if requested.\r
83\r
84 This routine is called by ::EslSocketAccept to handle the TCPv4 protocol\r
85 specific accept operations for SOCK_STREAM and SOCK_SEQPACKET sockets.\r
86 See the \ref ConnectionManagement section.\r
d7ce7006 87\r
a88c3163 88 @param [in] pSocket Address of an ::ESL_SOCKET structure.\r
d7ce7006 89\r
90 @param [in] pSockAddr Address of a buffer to receive the remote\r
91 network address.\r
92\r
93 @param [in, out] pSockAddrLength Length in bytes of the address buffer.\r
94 On output specifies the length of the\r
95 remote network address.\r
96\r
97 @retval EFI_SUCCESS Remote address is available\r
98 @retval Others Remote address not available\r
99\r
100 **/\r
101EFI_STATUS\r
a88c3163 102EslTcp4Accept (\r
103 IN ESL_SOCKET * pSocket,\r
d7ce7006 104 IN struct sockaddr * pSockAddr,\r
105 IN OUT socklen_t * pSockAddrLength\r
106 )\r
107{\r
a88c3163 108 ESL_PORT * pPort;\r
d7ce7006 109 struct sockaddr_in * pRemoteAddress;\r
a88c3163 110 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 111 UINT32 RemoteAddress;\r
112 EFI_STATUS Status;\r
113\r
114 DBG_ENTER ( );\r
115\r
116 //\r
117 // Validate the socket length\r
118 //\r
119 pRemoteAddress = (struct sockaddr_in *) pSockAddr;\r
120 if (( NULL == pSockAddrLength )\r
121 || ( sizeof ( *pRemoteAddress ) > *pSockAddrLength )) {\r
122 //\r
123 // Invalid socket address\r
124 //\r
125 Status = EFI_INVALID_PARAMETER;\r
126 pSocket->errno = EINVAL;\r
127 DEBUG (( DEBUG_ACCEPT,\r
128 "ERROR - Invalid address length\r\n" ));\r
129 }\r
130 else {\r
131 //\r
132 // Assume success\r
133 //\r
134 Status = EFI_SUCCESS;\r
135\r
136 //\r
137 // Locate the address context\r
138 //\r
139 pPort = pSocket->pPortList;\r
140 pTcp4 = &pPort->Context.Tcp4;\r
141\r
142 //\r
143 // Fill-in the remote address structure\r
144 //\r
145 ZeroMem ( pRemoteAddress, sizeof ( *pRemoteAddress ));\r
146 pRemoteAddress->sin_len = sizeof ( *pRemoteAddress );\r
147 pRemoteAddress->sin_family = AF_INET;\r
148 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );\r
149 RemoteAddress = pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3];\r
150 RemoteAddress <<= 8;\r
151 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2];\r
152 RemoteAddress <<= 8;\r
153 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1];\r
154 RemoteAddress <<= 8;\r
155 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0];\r
156 pRemoteAddress->sin_addr.s_addr = RemoteAddress;\r
157 }\r
158\r
159 //\r
160 // Return the operation status\r
161 //\r
162 DBG_EXIT_STATUS ( Status );\r
163 return Status;\r
164}\r
165\r
166\r
167/**\r
a88c3163 168 Process the remote connection completion event.\r
d7ce7006 169\r
a88c3163 170 This routine handles the completion of a connection attempt. It\r
171 releases the port (TCPv4 adapter connection) in the case of an\r
d7ce7006 172 error and start a connection attempt on the next port. If the\r
a88c3163 173 connection attempt was successful then this routine releases all\r
174 of the other ports.\r
d7ce7006 175\r
a88c3163 176 This routine is called by the TCPv4 layer when a connect request\r
177 completes. It sets the ESL_SOCKET::bConnected flag to notify the\r
178 ::EslTcp4ConnectComplete routine that the connection is available.\r
179 The flag is set when the connection is established or no more ports\r
180 exist in the list. The connection status is passed via\r
181 ESL_SOCKET::ConnectStatus.\r
d7ce7006 182\r
a88c3163 183 @param [in] Event The connect completion event\r
184\r
185 @param [in] pPort Address of an ::ESL_PORT structure.\r
d7ce7006 186\r
187**/\r
188VOID\r
a88c3163 189EslTcp4ConnectComplete (\r
d7ce7006 190 IN EFI_EVENT Event,\r
a88c3163 191 IN ESL_PORT * pPort\r
d7ce7006 192 )\r
193{\r
194 BOOLEAN bRemoveFirstPort;\r
195 BOOLEAN bRemovePorts;\r
a88c3163 196 ESL_PORT * pNextPort;\r
197 ESL_SOCKET * pSocket;\r
198 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 199 EFI_STATUS Status;\r
200\r
201 DBG_ENTER ( );\r
202\r
203 //\r
204 // Locate the TCP context\r
205 //\r
206 pSocket = pPort->pSocket;\r
207 pTcp4 = &pPort->Context.Tcp4;\r
208\r
209 //\r
210 // Get the connection status\r
211 //\r
212 bRemoveFirstPort = FALSE;\r
213 bRemovePorts = FALSE;\r
214 Status = pTcp4->ConnectToken.CompletionToken.Status;\r
215 pSocket->ConnectStatus = Status;\r
216 if ( !EFI_ERROR ( Status )) {\r
217 //\r
218 // The connection was successful\r
219 //\r
220 DEBUG (( DEBUG_CONNECT,\r
221 "0x%08x: Port connected to %d.%d.%d.%d:%d\r\n",\r
222 pPort,\r
a88c3163 223 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
224 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],\r
225 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],\r
226 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],\r
d7ce7006 227 pTcp4->ConfigData.AccessPoint.RemotePort ));\r
228\r
ceecdc62 229 //\r
230 // Start the receive operations\r
231 //\r
232 pSocket->bConfigured = TRUE;\r
233 pSocket->State = SOCKET_STATE_CONNECTED;\r
234 EslSocketRxStart ( pPort );\r
235\r
d7ce7006 236 //\r
237 // Remove the rest of the ports\r
238 //\r
239 bRemovePorts = TRUE;\r
240 }\r
241 else {\r
242 //\r
243 // The connection failed\r
244 //\r
44538ba5 245 if ( pPort->bConfigured ) {\r
246 DEBUG (( DEBUG_CONNECT,\r
247 "0x%08x: Port connection to %d.%d.%d.%d:%d failed, Status: %r\r\n",\r
248 pPort,\r
249 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
250 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],\r
251 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],\r
252 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],\r
253 pTcp4->ConfigData.AccessPoint.RemotePort,\r
254 Status ));\r
255 }\r
d7ce7006 256\r
257 //\r
258 // Close the current port\r
259 //\r
a88c3163 260 Status = EslSocketPortClose ( pPort );\r
d7ce7006 261 if ( !EFI_ERROR ( Status )) {\r
262 DEBUG (( DEBUG_CONNECT,\r
263 "0x%08x: Port closed\r\n",\r
264 pPort ));\r
265 }\r
266 else {\r
267 DEBUG (( DEBUG_CONNECT,\r
268 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",\r
269 pPort,\r
270 Status ));\r
271 }\r
272\r
273 //\r
274 // Try to connect using the next port\r
275 //\r
a88c3163 276 Status = EslTcp4ConnectStart ( pSocket );\r
d7ce7006 277 if ( EFI_NOT_READY != Status ) {\r
d7ce7006 278 bRemoveFirstPort = TRUE;\r
279 }\r
280 }\r
281\r
282 //\r
283 // Remove the ports if necessary\r
284 //\r
285 if ( bRemoveFirstPort || bRemovePorts ) {\r
286 //\r
287 // Remove the first port if necessary\r
288 //\r
289 pPort = pSocket->pPortList;\r
290 if (( !bRemoveFirstPort ) && ( NULL != pPort )) {\r
291 pPort = pPort->pLinkSocket;\r
292 }\r
293\r
294 //\r
295 // Remove the rest of the list\r
296 //\r
297 while ( NULL != pPort ) {\r
298 pNextPort = pPort->pLinkSocket;\r
a88c3163 299 EslSocketPortClose ( pPort );\r
d7ce7006 300 if ( !EFI_ERROR ( Status )) {\r
301 DEBUG (( DEBUG_CONNECT,\r
302 "0x%08x: Port closed\r\n",\r
303 pPort ));\r
304 }\r
305 else {\r
306 DEBUG (( DEBUG_CONNECT,\r
307 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",\r
308 pPort,\r
309 Status ));\r
310 }\r
311 pPort = pNextPort;\r
312 }\r
313\r
314 //\r
315 // Notify the poll routine\r
316 //\r
317 pSocket->bConnected = TRUE;\r
318 }\r
319\r
320 DBG_EXIT ( );\r
321}\r
322\r
323\r
324/**\r
325 Poll for completion of the connection attempt.\r
326\r
a88c3163 327 This routine polls the ESL_SOCKET::bConnected flag to determine\r
328 when the connection attempt is complete.\r
329\r
330 This routine is called from ::EslSocketConnect to determine when\r
331 the connection is complete. The ESL_SOCKET::bConnected flag is\r
332 set by ::EslTcp4ConnectComplete when the TCPv4 layer establishes\r
333 a connection or runs out of local network adapters. This routine\r
334 gets the connection status from ESL_SOCKET::ConnectStatus.\r
d7ce7006 335\r
a88c3163 336 @param [in] pSocket Address of an ::ESL_SOCKET structure.\r
d7ce7006 337\r
338 @retval EFI_SUCCESS The connection was successfully established.\r
339 @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
340 @retval Others The connection attempt failed.\r
341\r
342 **/\r
343EFI_STATUS\r
a88c3163 344EslTcp4ConnectPoll (\r
345 IN ESL_SOCKET * pSocket\r
d7ce7006 346 )\r
347{\r
348 EFI_STATUS Status;\r
349\r
350 DBG_ENTER ( );\r
351\r
352 //\r
353 // Determine if the connection is complete\r
354 //\r
355 if ( !pSocket->bConnected ) {\r
356 //\r
357 // Not connected\r
358 //\r
359 pSocket->errno = EAGAIN;\r
360 Status = EFI_NOT_READY;\r
361 }\r
362 else {\r
363 //\r
364 // The connection processing is complete\r
365 //\r
366 pSocket->bConnected = FALSE;\r
367\r
368 //\r
369 // Translate the connection status\r
370 //\r
371 Status = pSocket->ConnectStatus;\r
372 switch ( Status ) {\r
373 default:\r
374 case EFI_DEVICE_ERROR:\r
375 pSocket->errno = EIO;\r
376 break;\r
377\r
378 case EFI_ABORTED:\r
44538ba5 379 pSocket->errno = ECONNABORTED;\r
380 break;\r
381\r
382 case EFI_ACCESS_DENIED:\r
383 pSocket->errno = EACCES;\r
384 break;\r
385\r
386 case EFI_CONNECTION_RESET:\r
387 pSocket->errno = ECONNRESET;\r
d7ce7006 388 break;\r
389\r
390 case EFI_INVALID_PARAMETER:\r
44538ba5 391 pSocket->errno = EADDRNOTAVAIL;\r
d7ce7006 392 break;\r
393\r
44538ba5 394 case EFI_HOST_UNREACHABLE:\r
d7ce7006 395 case EFI_NO_RESPONSE:\r
396 pSocket->errno = EHOSTUNREACH;\r
397 break;\r
398\r
44538ba5 399 case EFI_NO_MAPPING:\r
400 pSocket->errno = EAFNOSUPPORT;\r
401 break;\r
402\r
d7ce7006 403 case EFI_NO_MEDIA:\r
44538ba5 404 case EFI_NETWORK_UNREACHABLE:\r
d7ce7006 405 pSocket->errno = ENETDOWN;\r
406 break;\r
407\r
408 case EFI_OUT_OF_RESOURCES:\r
44538ba5 409 pSocket->errno = ENOBUFS;\r
410 break;\r
411\r
412 case EFI_PORT_UNREACHABLE:\r
413 case EFI_PROTOCOL_UNREACHABLE:\r
414 case EFI_CONNECTION_REFUSED:\r
415 pSocket->errno = ECONNREFUSED;\r
d7ce7006 416 break;\r
417\r
418 case EFI_SUCCESS:\r
419 pSocket->errno = 0;\r
d7ce7006 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
0e565888 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
0e565888 773\r
d7ce7006 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_PORT * pNewPort;\r
838 ESL_SOCKET * pNewSocket;\r
839 ESL_SOCKET * pSocket;\r
840 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 841 EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
842 EFI_STATUS Status;\r
843 EFI_HANDLE TcpPortHandle;\r
844 EFI_STATUS TempStatus;\r
845\r
846 DBG_ENTER ( );\r
a88c3163 847 VERIFY_AT_TPL ( TPL_SOCKETS );\r
d7ce7006 848\r
849 //\r
850 // Assume success\r
851 //\r
852 Status = EFI_SUCCESS;\r
853\r
854 //\r
855 // Determine if this connection fits into the connection FIFO\r
856 //\r
857 pSocket = pPort->pSocket;\r
858 TcpPortHandle = pPort->Context.Tcp4.ListenToken.NewChildHandle;\r
859 if (( SOCKET_STATE_LISTENING == pSocket->State )\r
860 && ( pSocket->MaxFifoDepth > pSocket->FifoDepth )) {\r
861 //\r
862 // Allocate a socket for this connection\r
863 //\r
864 ChildHandle = NULL;\r
d7ce7006 865 Status = EslSocketAllocate ( &ChildHandle,\r
866 DEBUG_CONNECTION,\r
867 &pNewSocket );\r
868 if ( !EFI_ERROR ( Status )) {\r
869 //\r
870 // Clone the socket parameters\r
871 //\r
a88c3163 872 pNewSocket->pApi = pSocket->pApi;\r
d7ce7006 873 pNewSocket->Domain = pSocket->Domain;\r
874 pNewSocket->Protocol = pSocket->Protocol;\r
875 pNewSocket->Type = pSocket->Type;\r
876\r
877 //\r
a88c3163 878 // Build the local address\r
d7ce7006 879 //\r
880 pTcp4 = &pPort->Context.Tcp4;\r
a88c3163 881 LocalAddress.sin_len = (uint8_t)pNewSocket->pApi->MinimumAddressLength;\r
882 LocalAddress.sin_family = AF_INET;\r
883 LocalAddress.sin_port = 0;\r
884 LocalAddress.sin_addr.s_addr = *(UINT32 *)&pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0];\r
885\r
886 //\r
887 // Allocate a port for this connection\r
888 // Note in this instance Configure may not be called with NULL!\r
889 //\r
890 Status = EslSocketPortAllocate ( pNewSocket,\r
891 pPort->pService,\r
892 TcpPortHandle,\r
893 (struct sockaddr *)&LocalAddress,\r
894 FALSE,\r
895 DEBUG_CONNECTION,\r
896 &pNewPort );\r
d7ce7006 897 if ( !EFI_ERROR ( Status )) {\r
898 //\r
899 // Restart the listen operation on the port\r
900 //\r
a88c3163 901 pTcp4Protocol = pPort->pProtocol.TCPv4;\r
d7ce7006 902 Status = pTcp4Protocol->Accept ( pTcp4Protocol,\r
903 &pTcp4->ListenToken );\r
904\r
905 //\r
906 // Close the TCP port using SocketClose\r
907 //\r
908 TcpPortHandle = NULL;\r
909 pTcp4 = &pNewPort->Context.Tcp4;\r
d7ce7006 910\r
911 //\r
912 // Check for an accept call error\r
913 //\r
914 if ( !EFI_ERROR ( Status )) {\r
915 //\r
916 // Get the port configuration\r
917 //\r
a88c3163 918 pNewPort->bConfigured = TRUE;\r
d7ce7006 919 pConfigData = &pTcp4->ConfigData;\r
920 pConfigData->ControlOption = &pTcp4->Option;\r
a88c3163 921 pTcp4Protocol = pNewPort->pProtocol.TCPv4;\r
d7ce7006 922 Status = pTcp4Protocol->GetModeData ( pTcp4Protocol,\r
923 NULL,\r
924 pConfigData,\r
925 NULL,\r
926 NULL,\r
927 NULL );\r
928 if ( !EFI_ERROR ( Status )) {\r
929 //\r
930 // Add the new socket to the connection FIFO\r
931 //\r
932 if ( NULL == pSocket->pFifoTail ) {\r
933 //\r
934 // First connection\r
935 //\r
936 pSocket->pFifoHead = pNewSocket;\r
937 }\r
938 else {\r
939 //\r
940 // Add to end of list.\r
941 //\r
942 pSocket->pFifoTail->pNextConnection = pNewSocket;\r
943 }\r
944 pSocket->pFifoTail = pNewSocket;\r
945 pSocket->FifoDepth += 1;\r
946\r
947 //\r
948 // Update the socket state\r
949 //\r
950 pNewSocket->State = SOCKET_STATE_IN_FIFO;\r
951\r
952 //\r
953 // Log the connection\r
954 //\r
955 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,\r
956 "0x%08x: Socket on port %d.%d.%d.%d:%d connected to %d.%d.%d.%d:%d\r\n",\r
957 pNewSocket,\r
958 pConfigData->AccessPoint.StationAddress.Addr[0],\r
959 pConfigData->AccessPoint.StationAddress.Addr[1],\r
960 pConfigData->AccessPoint.StationAddress.Addr[2],\r
961 pConfigData->AccessPoint.StationAddress.Addr[3],\r
962 pConfigData->AccessPoint.StationPort,\r
963 pConfigData->AccessPoint.RemoteAddress.Addr[0],\r
964 pConfigData->AccessPoint.RemoteAddress.Addr[1],\r
965 pConfigData->AccessPoint.RemoteAddress.Addr[2],\r
966 pConfigData->AccessPoint.RemoteAddress.Addr[3],\r
967 pConfigData->AccessPoint.RemotePort ));\r
968 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,\r
969 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",\r
970 pSocket,\r
971 pNewSocket,\r
972 pSocket->FifoDepth ));\r
973\r
974 //\r
975 // Start the receive operation\r
976 //\r
a88c3163 977 EslSocketRxStart ( pNewPort );\r
d7ce7006 978 }\r
979 else {\r
980 DEBUG (( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO,\r
981 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",\r
982 pNewPort,\r
983 Status ));\r
984 }\r
985 }\r
986 else {\r
987 //\r
988 // The listen failed on this port\r
989 //\r
990 DEBUG (( DEBUG_LISTEN | DEBUG_INFO,\r
991 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",\r
992 pPort,\r
993 Status ));\r
994\r
995 //\r
996 // Close the listening port\r
997 //\r
a88c3163 998 EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );\r
d7ce7006 999 }\r
1000 }\r
1001\r
1002 //\r
1003 // Done with the socket if necessary\r
1004 //\r
1005 if ( EFI_ERROR ( Status )) {\r
1006 TempStatus = EslSocketCloseStart ( &pNewSocket->SocketProtocol,\r
1007 TRUE,\r
1008 &pSocket->errno );\r
1009 ASSERT ( EFI_SUCCESS == TempStatus );\r
1010 }\r
1011 }\r
1012 }\r
1013 else {\r
1014 DEBUG (( DEBUG_CONNECTION,\r
1015 "0x%08x: Socket FIFO full, connection refused\r\n",\r
1016 pSocket ));\r
1017\r
1018 //\r
1019 // The FIFO is full or the socket is in the wrong state\r
1020 //\r
1021 Status = EFI_BUFFER_TOO_SMALL;\r
1022 }\r
1023\r
1024 //\r
1025 // Close the connection if necessary\r
1026 //\r
1027 if (( EFI_ERROR ( Status ))\r
1028 && ( NULL == TcpPortHandle )) {\r
1029 //\r
1030 // TODO: Finish this code path\r
1031 // The new connection does not fit into the connection FIFO\r
1032 //\r
1033 // Process:\r
1034 // Call close\r
1035 // Release the resources\r
0e565888 1036\r
d7ce7006 1037 }\r
1038\r
1039 DBG_EXIT ( );\r
1040}\r
1041\r
1042\r
1043/**\r
a88c3163 1044 Get the local socket address.\r
d7ce7006 1045\r
a88c3163 1046 This routine returns the IPv4 address and TCP port number associated\r
1047 with the local socket.\r
d7ce7006 1048\r
a88c3163 1049 This routine is called by ::EslSocketGetLocalAddress to determine the\r
1050 network address for the SOCK_STREAM or SOCK_SEQPACKET socket.\r
1051\r
1052 @param [in] pPort Address of an ::ESL_PORT structure.\r
1053\r
1054 @param [out] pSockAddr Network address to receive the local system address\r
1055\r
1056**/\r
1057VOID\r
1058EslTcp4LocalAddressGet (\r
1059 IN ESL_PORT * pPort,\r
1060 OUT struct sockaddr * pSockAddr\r
1061 )\r
1062{\r
1063 struct sockaddr_in * pLocalAddress;\r
1064 ESL_TCP4_CONTEXT * pTcp4;\r
1065\r
1066 DBG_ENTER ( );\r
1067\r
1068 //\r
1069 // Return the local address\r
1070 //\r
1071 pTcp4 = &pPort->Context.Tcp4;\r
1072 pLocalAddress = (struct sockaddr_in *)pSockAddr;\r
1073 pLocalAddress->sin_family = AF_INET;\r
1074 pLocalAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.StationPort );\r
1075 CopyMem ( &pLocalAddress->sin_addr,\r
1076 &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],\r
1077 sizeof ( pLocalAddress->sin_addr ));\r
1078\r
1079 DBG_EXIT ( );\r
1080}\r
1081\r
1082\r
1083/**\r
1084 Set the local port address.\r
1085\r
1086 This routine sets the local port address.\r
1087\r
1088 This support routine is called by ::EslSocketPortAllocate.\r
1089\r
1090 @param [in] pPort Address of an ESL_PORT structure\r
1091 @param [in] pSockAddr Address of a sockaddr structure that contains the\r
1092 connection point on the local machine. An IPv4 address\r
1093 of INADDR_ANY specifies that the connection is made to\r
1094 all of the network stacks on the platform. Specifying a\r
1095 specific IPv4 address restricts the connection to the\r
1096 network stack supporting that address. Specifying zero\r
1097 for the port causes the network layer to assign a port\r
1098 number from the dynamic range. Specifying a specific\r
1099 port number causes the network layer to use that port.\r
1100\r
1101 @param [in] bBindTest TRUE = run bind testing\r
1102\r
1103 @retval EFI_SUCCESS The operation was successful\r
d7ce7006 1104\r
1105 **/\r
1106EFI_STATUS\r
a88c3163 1107EslTcp4LocalAddressSet (\r
1108 IN ESL_PORT * pPort,\r
1109 IN CONST struct sockaddr * pSockAddr,\r
1110 IN BOOLEAN bBindTest\r
d7ce7006 1111 )\r
1112{\r
d7ce7006 1113 EFI_TCP4_ACCESS_POINT * pAccessPoint;\r
a88c3163 1114 CONST struct sockaddr_in * pIpAddress;\r
1115 CONST UINT8 * pIpv4Address;\r
d7ce7006 1116 EFI_STATUS Status;\r
1117\r
1118 DBG_ENTER ( );\r
1119\r
1120 //\r
a88c3163 1121 // Validate the address\r
1122 //\r
1123 pIpAddress = (struct sockaddr_in *)pSockAddr;\r
1124 if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {\r
d7ce7006 1125 //\r
a88c3163 1126 // The local address must not be the broadcast address\r
d7ce7006 1127 //\r
a88c3163 1128 Status = EFI_INVALID_PARAMETER;\r
1129 pPort->pSocket->errno = EADDRNOTAVAIL;\r
1130 }\r
1131 else {\r
d7ce7006 1132 //\r
a88c3163 1133 // Set the local address\r
d7ce7006 1134 //\r
a88c3163 1135 pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;\r
1136 pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;\r
1137 pAccessPoint->StationAddress.Addr[0] = pIpv4Address[0];\r
1138 pAccessPoint->StationAddress.Addr[1] = pIpv4Address[1];\r
1139 pAccessPoint->StationAddress.Addr[2] = pIpv4Address[2];\r
1140 pAccessPoint->StationAddress.Addr[3] = pIpv4Address[3];\r
d7ce7006 1141\r
1142 //\r
a88c3163 1143 // Determine if the default address is used\r
d7ce7006 1144 //\r
a88c3163 1145 pAccessPoint->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );\r
0e565888 1146\r
d7ce7006 1147 //\r
a88c3163 1148 // Set the subnet mask\r
d7ce7006 1149 //\r
a88c3163 1150 if ( pAccessPoint->UseDefaultAddress ) {\r
1151 pAccessPoint->SubnetMask.Addr[0] = 0;\r
1152 pAccessPoint->SubnetMask.Addr[1] = 0;\r
1153 pAccessPoint->SubnetMask.Addr[2] = 0;\r
1154 pAccessPoint->SubnetMask.Addr[3] = 0;\r
1155 }\r
1156 else {\r
1157 pAccessPoint->SubnetMask.Addr[0] = 0xff;\r
6e1450f3 1158 pAccessPoint->SubnetMask.Addr[1] = ( 128 <= pAccessPoint->StationAddress.Addr[0]) ? 0xff : 0;\r
1159 pAccessPoint->SubnetMask.Addr[2] = ( 192 <= pAccessPoint->StationAddress.Addr[0]) ? 0xff : 0;\r
1160 pAccessPoint->SubnetMask.Addr[3] = ( 224 <= pAccessPoint->StationAddress.Addr[0]) ? 0xff : 0;\r
d7ce7006 1161 }\r
d7ce7006 1162\r
1163 //\r
a88c3163 1164 // Validate the IP address\r
d7ce7006 1165 //\r
a88c3163 1166 pAccessPoint->StationPort = 0;\r
1167 Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )\r
1168 : EFI_SUCCESS;\r
1169 if ( !EFI_ERROR ( Status )) {\r
1170 //\r
1171 // Set the port number\r
1172 //\r
1173 pAccessPoint->StationPort = SwapBytes16 ( pIpAddress->sin_port );\r
f74dc4bb 1174 pPort->pSocket->bAddressSet = TRUE;\r
a88c3163 1175\r
1176 //\r
1177 // Display the local address\r
1178 //\r
1179 DEBUG (( DEBUG_BIND,\r
1180 "0x%08x: Port, Local TCP4 Address: %d.%d.%d.%d:%d\r\n",\r
1181 pPort,\r
1182 pAccessPoint->StationAddress.Addr[0],\r
1183 pAccessPoint->StationAddress.Addr[1],\r
1184 pAccessPoint->StationAddress.Addr[2],\r
1185 pAccessPoint->StationAddress.Addr[3],\r
1186 pAccessPoint->StationPort ));\r
d7ce7006 1187 }\r
a88c3163 1188 }\r
1189\r
1190 //\r
1191 // Return the operation status\r
1192 //\r
1193 DBG_EXIT_STATUS ( Status );\r
1194 return Status;\r
1195}\r
1196\r
1197\r
1198/**\r
1199 Free a receive packet\r
1200\r
1201 This routine performs the network specific operations necessary\r
1202 to free a receive packet.\r
1203\r
1204 This routine is called by ::EslSocketPortCloseTxDone to free a\r
1205 receive packet.\r
1206\r
1207 @param [in] pPacket Address of an ::ESL_PACKET structure.\r
1208 @param [in, out] pRxBytes Address of the count of RX bytes\r
1209\r
1210**/\r
1211VOID\r
1212EslTcp4PacketFree (\r
1213 IN ESL_PACKET * pPacket,\r
1214 IN OUT size_t * pRxBytes\r
1215 )\r
1216{\r
1217 DBG_ENTER ( );\r
1218\r
1219 //\r
1220 // Account for the receive bytes\r
1221 //\r
1222 *pRxBytes -= pPacket->Op.Tcp4Rx.RxData.DataLength;\r
1223 DBG_EXIT ( );\r
1224}\r
1225\r
d7ce7006 1226\r
a88c3163 1227/**\r
1228 Initialize the network specific portions of an ::ESL_PORT structure.\r
1229\r
1230 This routine initializes the network specific portions of an\r
1231 ::ESL_PORT structure for use by the socket.\r
1232\r
1233 This support routine is called by ::EslSocketPortAllocate\r
1234 to connect the socket with the underlying network adapter\r
1235 running the TCPv4 protocol.\r
1236\r
1237 @param [in] pPort Address of an ESL_PORT structure\r
1238 @param [in] DebugFlags Flags for debug messages\r
1239\r
1240 @retval EFI_SUCCESS - Socket successfully created\r
1241\r
1242 **/\r
1243EFI_STATUS\r
1244EslTcp4PortAllocate (\r
1245 IN ESL_PORT * pPort,\r
1246 IN UINTN DebugFlags\r
1247 )\r
1248{\r
1249 EFI_TCP4_ACCESS_POINT * pAccessPoint;\r
1250 ESL_SOCKET * pSocket;\r
1251 ESL_TCP4_CONTEXT * pTcp4;\r
1252 EFI_STATUS Status;\r
1253\r
1254 DBG_ENTER ( );\r
1255\r
1256 //\r
1257 // Use for/break instead of goto\r
1258 for ( ; ; ) {\r
d7ce7006 1259 //\r
1260 // Allocate the close event\r
1261 //\r
a88c3163 1262 pSocket = pPort->pSocket;\r
1263 pTcp4 = &pPort->Context.Tcp4;\r
d7ce7006 1264 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
1265 TPL_SOCKETS,\r
a88c3163 1266 (EFI_EVENT_NOTIFY)EslSocketPortCloseComplete,\r
d7ce7006 1267 pPort,\r
1268 &pTcp4->CloseToken.CompletionToken.Event);\r
1269 if ( EFI_ERROR ( Status )) {\r
1270 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1271 "ERROR - Failed to create the close event, Status: %r\r\n",\r
1272 Status ));\r
1273 pSocket->errno = ENOMEM;\r
1274 break;\r
1275 }\r
1276 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
1277 "0x%08x: Created close event\r\n",\r
1278 pTcp4->CloseToken.CompletionToken.Event ));\r
1279\r
1280 //\r
1281 // Allocate the connection event\r
1282 //\r
1283 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
1284 TPL_SOCKETS,\r
a88c3163 1285 (EFI_EVENT_NOTIFY)EslTcp4ConnectComplete,\r
d7ce7006 1286 pPort,\r
1287 &pTcp4->ConnectToken.CompletionToken.Event);\r
1288 if ( EFI_ERROR ( Status )) {\r
1289 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1290 "ERROR - Failed to create the connect event, Status: %r\r\n",\r
1291 Status ));\r
1292 pSocket->errno = ENOMEM;\r
1293 break;\r
1294 }\r
1295 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
1296 "0x%08x: Created connect event\r\n",\r
1297 pTcp4->ConnectToken.CompletionToken.Event ));\r
1298\r
1299 //\r
a88c3163 1300 // Initialize the port\r
d7ce7006 1301 //\r
a88c3163 1302 pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Tcp4Tx.TxData );\r
1303 pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Tx.CompletionToken.Event );\r
1304 pSocket->TxTokenOffset = OFFSET_OF ( EFI_TCP4_IO_TOKEN, Packet.TxData );\r
d7ce7006 1305\r
1306 //\r
a88c3163 1307 // Save the cancel, receive and transmit addresses\r
1308 // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED\r
d7ce7006 1309 //\r
a88c3163 1310 pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.TCPv4->Configure;\r
3bdf9aae 1311 pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.TCPv4->Poll;\r
a88c3163 1312 pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Receive;\r
1313 pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Transmit;\r
d7ce7006 1314\r
1315 //\r
a88c3163 1316 // Set the configuration flags\r
d7ce7006 1317 //\r
a88c3163 1318 pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;\r
1319 pAccessPoint->ActiveFlag = FALSE;\r
1320 pTcp4->ConfigData.TimeToLive = 255;\r
d7ce7006 1321 break;\r
1322 }\r
1323\r
d7ce7006 1324 //\r
1325 // Return the operation status\r
1326 //\r
1327 DBG_EXIT_STATUS ( Status );\r
1328 return Status;\r
1329}\r
1330\r
1331\r
1332/**\r
1333 Close a TCP4 port.\r
1334\r
a88c3163 1335 This routine releases the network specific resources allocated by\r
1336 ::EslTcp4PortAllocate.\r
1337\r
1338 This routine is called by ::EslSocketPortClose.\r
1339 See the \ref PortCloseStateMachine section.\r
0e565888 1340\r
a88c3163 1341 @param [in] pPort Address of an ::ESL_PORT structure.\r
d7ce7006 1342\r
1343 @retval EFI_SUCCESS The port is closed\r
1344 @retval other Port close error\r
1345\r
1346**/\r
1347EFI_STATUS\r
a88c3163 1348EslTcp4PortClose (\r
1349 IN ESL_PORT * pPort\r
d7ce7006 1350 )\r
1351{\r
1352 UINTN DebugFlags;\r
a88c3163 1353 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 1354 EFI_STATUS Status;\r
0e565888 1355\r
d7ce7006 1356 DBG_ENTER ( );\r
1357\r
d7ce7006 1358 //\r
1359 // Locate the port in the socket list\r
1360 //\r
1361 Status = EFI_SUCCESS;\r
d7ce7006 1362 DebugFlags = pPort->DebugFlags;\r
d7ce7006 1363 pTcp4 = &pPort->Context.Tcp4;\r
d7ce7006 1364\r
1365 //\r
1366 // Done with the connect event\r
1367 //\r
1368 if ( NULL != pTcp4->ConnectToken.CompletionToken.Event ) {\r
1369 Status = gBS->CloseEvent ( pTcp4->ConnectToken.CompletionToken.Event );\r
1370 if ( !EFI_ERROR ( Status )) {\r
1371 DEBUG (( DebugFlags | DEBUG_POOL,\r
1372 "0x%08x: Closed connect event\r\n",\r
1373 pTcp4->ConnectToken.CompletionToken.Event ));\r
1374 }\r
1375 else {\r
1376 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1377 "ERROR - Failed to close the connect event, Status: %r\r\n",\r
1378 Status ));\r
1379 ASSERT ( EFI_SUCCESS == Status );\r
1380 }\r
1381 }\r
1382\r
1383 //\r
1384 // Done with the close event\r
1385 //\r
1386 if ( NULL != pTcp4->CloseToken.CompletionToken.Event ) {\r
1387 Status = gBS->CloseEvent ( pTcp4->CloseToken.CompletionToken.Event );\r
1388 if ( !EFI_ERROR ( Status )) {\r
1389 DEBUG (( DebugFlags | DEBUG_POOL,\r
1390 "0x%08x: Closed close event\r\n",\r
1391 pTcp4->CloseToken.CompletionToken.Event ));\r
1392 }\r
1393 else {\r
1394 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1395 "ERROR - Failed to close the close event, Status: %r\r\n",\r
1396 Status ));\r
1397 ASSERT ( EFI_SUCCESS == Status );\r
1398 }\r
1399 }\r
1400\r
1401 //\r
1402 // Done with the listen completion event\r
1403 //\r
1404 if ( NULL != pTcp4->ListenToken.CompletionToken.Event ) {\r
1405 Status = gBS->CloseEvent ( pTcp4->ListenToken.CompletionToken.Event );\r
1406 if ( !EFI_ERROR ( Status )) {\r
1407 DEBUG (( DebugFlags | DEBUG_POOL,\r
1408 "0x%08x: Closed listen completion event\r\n",\r
1409 pTcp4->ListenToken.CompletionToken.Event ));\r
1410 }\r
1411 else {\r
1412 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1413 "ERROR - Failed to close the listen completion event, Status: %r\r\n",\r
1414 Status ));\r
1415 ASSERT ( EFI_SUCCESS == Status );\r
1416 }\r
1417 }\r
1418\r
d7ce7006 1419 //\r
1420 // Return the operation status\r
1421 //\r
1422 DBG_EXIT_STATUS ( Status );\r
1423 return Status;\r
1424}\r
1425\r
1426\r
1427/**\r
a88c3163 1428 Perform the network specific close operation on the port.\r
d7ce7006 1429\r
a88c3163 1430 This routine performs a cancel operations on the TCPv4 port to\r
1431 shutdown the receive operations on the port.\r
d7ce7006 1432\r
a88c3163 1433 This routine is called by the ::EslSocketPortCloseTxDone\r
1434 routine after the port completes all of the transmission.\r
1435\r
1436 @param [in] pPort Address of an ::ESL_PORT structure.\r
1437\r
1438 @retval EFI_SUCCESS The port is closed, not normally returned\r
1439 @retval EFI_NOT_READY The port is still closing\r
1440 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
1441 most likely the routine was called already.\r
d7ce7006 1442\r
1443**/\r
a88c3163 1444EFI_STATUS\r
1445EslTcp4PortCloseOp (\r
1446 IN ESL_PORT * pPort\r
d7ce7006 1447 )\r
1448{\r
a88c3163 1449 ESL_TCP4_CONTEXT * pTcp4;\r
1450 EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
d7ce7006 1451 EFI_STATUS Status;\r
1452\r
1453 DBG_ENTER ( );\r
1454\r
1455 //\r
a88c3163 1456 // Close the configured port\r
d7ce7006 1457 //\r
a88c3163 1458 Status = EFI_SUCCESS;\r
1459 pTcp4 = &pPort->Context.Tcp4;\r
1460 pTcp4Protocol = pPort->pProtocol.TCPv4;\r
1461 pTcp4->CloseToken.AbortOnClose = pPort->bCloseNow;\r
1462 Status = pTcp4Protocol->Close ( pTcp4Protocol,\r
1463 &pTcp4->CloseToken );\r
1464 if ( !EFI_ERROR ( Status )) {\r
1465 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
1466 "0x%08x: Port close started\r\n",\r
1467 pPort ));\r
1468 }\r
1469 else {\r
1470 DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
1471 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",\r
1472 pPort,\r
1473 Status ));\r
1474 }\r
d7ce7006 1475\r
1476 //\r
a88c3163 1477 // Return the operation status\r
d7ce7006 1478 //\r
d7ce7006 1479 DBG_EXIT_STATUS ( Status );\r
a88c3163 1480 return Status;\r
d7ce7006 1481}\r
1482\r
1483\r
1484/**\r
a88c3163 1485 Receive data from a network connection.\r
d7ce7006 1486\r
a88c3163 1487 This routine attempts to return buffered data to the caller. The\r
1488 data is removed from the urgent queue if the message flag MSG_OOB\r
1489 is specified, otherwise data is removed from the normal queue.\r
1490 See the \ref ReceiveEngine section.\r
d7ce7006 1491\r
a88c3163 1492 This routine is called by ::EslSocketReceive to handle the network\r
1493 specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET\r
1494 sockets.\r
d7ce7006 1495\r
a88c3163 1496 @param [in] pPort Address of an ::ESL_PORT structure.\r
d7ce7006 1497\r
a88c3163 1498 @param [in] pPacket Address of an ::ESL_PACKET structure.\r
0e565888 1499\r
a88c3163 1500 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed\r
0e565888 1501\r
d7ce7006 1502 @param [in] BufferLength Length of the the buffer\r
0e565888 1503\r
d7ce7006 1504 @param [in] pBuffer Address of a buffer to receive the data.\r
0e565888 1505\r
d7ce7006 1506 @param [in] pDataLength Number of received data bytes in the buffer.\r
1507\r
1508 @param [out] pAddress Network address to receive the remote system address\r
1509\r
a88c3163 1510 @param [out] pSkipBytes Address to receive the number of bytes skipped\r
d7ce7006 1511\r
a88c3163 1512 @return Returns the address of the next free byte in the buffer.\r
d7ce7006 1513\r
1514 **/\r
a88c3163 1515UINT8 *\r
1516EslTcp4Receive (\r
1517 IN ESL_PORT * pPort,\r
1518 IN ESL_PACKET * pPacket,\r
1519 IN BOOLEAN * pbConsumePacket,\r
d7ce7006 1520 IN size_t BufferLength,\r
1521 IN UINT8 * pBuffer,\r
1522 OUT size_t * pDataLength,\r
1523 OUT struct sockaddr * pAddress,\r
a88c3163 1524 OUT size_t * pSkipBytes\r
d7ce7006 1525 )\r
1526{\r
a88c3163 1527 size_t DataLength;\r
d7ce7006 1528 struct sockaddr_in * pRemoteAddress;\r
a88c3163 1529 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 1530\r
1531 DBG_ENTER ( );\r
1532\r
1533 //\r
a88c3163 1534 // Return the remote system address if requested\r
d7ce7006 1535 //\r
a88c3163 1536 if ( NULL != pAddress ) {\r
d7ce7006 1537 //\r
a88c3163 1538 // Build the remote address\r
d7ce7006 1539 //\r
1540 pTcp4 = &pPort->Context.Tcp4;\r
a88c3163 1541 DEBUG (( DEBUG_RX,\r
1542 "Getting packet remote address: %d.%d.%d.%d:%d\r\n",\r
1543 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
1544 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],\r
1545 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],\r
1546 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],\r
1547 pTcp4->ConfigData.AccessPoint.RemotePort ));\r
1548 pRemoteAddress = (struct sockaddr_in *)pAddress;\r
1549 CopyMem ( &pRemoteAddress->sin_addr,\r
1550 &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
1551 sizeof ( pRemoteAddress->sin_addr ));\r
1552 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );\r
d7ce7006 1553 }\r
1554\r
1555 //\r
a88c3163 1556 // Determine the amount of received data\r
d7ce7006 1557 //\r
a88c3163 1558 DataLength = pPacket->ValidBytes;\r
1559 if ( BufferLength < DataLength ) {\r
1560 DataLength = BufferLength;\r
1561 }\r
d7ce7006 1562\r
1563 //\r
a88c3163 1564 // Move the data into the buffer\r
1565 //\r
1566 DEBUG (( DEBUG_RX,\r
1567 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",\r
1568 pPort,\r
1569 pPacket,\r
1570 pBuffer,\r
1571 DataLength ));\r
1572 CopyMem ( pBuffer, pPacket->pBuffer, DataLength );\r
d7ce7006 1573\r
fcb6f89d 1574 //\r
1575 // Set the next buffer address\r
1576 //\r
1577 pBuffer += DataLength;\r
1578\r
a88c3163 1579 //\r
1580 // Determine if the data is being read\r
1581 //\r
1582 if ( *pbConsumePacket ) {\r
d7ce7006 1583 //\r
a88c3163 1584 // Account for the bytes consumed\r
d7ce7006 1585 //\r
a88c3163 1586 pPacket->pBuffer += DataLength;\r
1587 pPacket->ValidBytes -= DataLength;\r
1588 DEBUG (( DEBUG_RX,\r
1589 "0x%08x: Port account for 0x%08x bytes\r\n",\r
d7ce7006 1590 pPort,\r
a88c3163 1591 DataLength ));\r
d7ce7006 1592\r
1593 //\r
a88c3163 1594 // Determine if the entire packet was consumed\r
d7ce7006 1595 //\r
a88c3163 1596 if (( 0 == pPacket->ValidBytes )\r
1597 || ( SOCK_STREAM != pPort->pSocket->Type )) {\r
1598 //\r
1599 // All done with this packet\r
1600 // Account for any discarded data\r
1601 //\r
1602 *pSkipBytes = pPacket->ValidBytes;\r
d7ce7006 1603 }\r
a88c3163 1604 else\r
1605 {\r
1606 //\r
1607 // More data to consume later\r
1608 //\r
1609 *pbConsumePacket = FALSE;\r
d7ce7006 1610 }\r
1611 }\r
d7ce7006 1612\r
a88c3163 1613 //\r
1614 // Return the data length and the buffer address\r
1615 //\r
1616 *pDataLength = DataLength;\r
1617 DBG_EXIT_HEX ( pBuffer );\r
1618 return pBuffer;\r
1619}\r
d7ce7006 1620\r
a88c3163 1621\r
1622/**\r
1623 Get the remote socket address.\r
1624\r
1625 This routine returns the address of the remote connection point\r
1626 associated with the SOCK_STREAM or SOCK_SEQPACKET socket.\r
1627\r
1628 This routine is called by ::EslSocketGetPeerAddress to detemine\r
1629 the TCPv4 address and por number associated with the network adapter.\r
1630\r
1631 @param [in] pPort Address of an ::ESL_PORT structure.\r
1632\r
1633 @param [out] pAddress Network address to receive the remote system address\r
1634\r
1635**/\r
1636VOID\r
1637EslTcp4RemoteAddressGet (\r
1638 IN ESL_PORT * pPort,\r
1639 OUT struct sockaddr * pAddress\r
1640 )\r
1641{\r
1642 struct sockaddr_in * pRemoteAddress;\r
1643 ESL_TCP4_CONTEXT * pTcp4;\r
1644\r
1645 DBG_ENTER ( );\r
1646\r
1647 //\r
1648 // Return the remote address\r
1649 //\r
1650 pTcp4 = &pPort->Context.Tcp4;\r
1651 pRemoteAddress = (struct sockaddr_in *)pAddress;\r
1652 pRemoteAddress->sin_family = AF_INET;\r
1653 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );\r
1654 CopyMem ( &pRemoteAddress->sin_addr,\r
1655 &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
1656 sizeof ( pRemoteAddress->sin_addr ));\r
d7ce7006 1657\r
1658 DBG_EXIT ( );\r
1659}\r
1660\r
1661\r
1662/**\r
a88c3163 1663 Set the remote address\r
1664\r
1665 This routine sets the remote address in the port.\r
1666\r
1667 This routine is called by ::EslSocketConnect to specify the\r
1668 remote network address.\r
1669\r
1670 @param [in] pPort Address of an ::ESL_PORT structure.\r
1671\r
1672 @param [in] pSockAddr Network address of the remote system.\r
1673\r
1674 @param [in] SockAddrLength Length in bytes of the network address.\r
d7ce7006 1675\r
a88c3163 1676 @retval EFI_SUCCESS The operation was successful\r
d7ce7006 1677\r
1678 **/\r
a88c3163 1679EFI_STATUS\r
1680EslTcp4RemoteAddressSet (\r
1681 IN ESL_PORT * pPort,\r
1682 IN CONST struct sockaddr * pSockAddr,\r
1683 IN socklen_t SockAddrLength\r
d7ce7006 1684 )\r
1685{\r
a88c3163 1686 CONST struct sockaddr_in * pRemoteAddress;\r
1687 ESL_TCP4_CONTEXT * pTcp4;\r
d7ce7006 1688 EFI_STATUS Status;\r
1689\r
1690 DBG_ENTER ( );\r
1691\r
1692 //\r
a88c3163 1693 // Set the remote address\r
d7ce7006 1694 //\r
d7ce7006 1695 pTcp4 = &pPort->Context.Tcp4;\r
a88c3163 1696 pRemoteAddress = (struct sockaddr_in *)pSockAddr;\r
1697 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );\r
1698 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );\r
1699 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );\r
1700 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );\r
1701 pTcp4->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );\r
1702 Status = EFI_SUCCESS;\r
1703 if ( INADDR_BROADCAST == pRemoteAddress->sin_addr.s_addr ) {\r
1704 DEBUG (( DEBUG_CONNECT,\r
1705 "ERROR - Invalid remote address\r\n" ));\r
1706 Status = EFI_INVALID_PARAMETER;\r
1707 pPort->pSocket->errno = EAFNOSUPPORT;\r
d7ce7006 1708 }\r
1709\r
a88c3163 1710 //\r
1711 // Return the operation status\r
1712 //\r
1713 DBG_EXIT_STATUS ( Status );\r
1714 return Status;\r
d7ce7006 1715}\r
1716\r
1717\r
1718/**\r
a88c3163 1719 Process the receive completion\r
1720\r
1721 This routine queues the data in FIFO order in either the urgent\r
1722 or normal data queues depending upon the type of data received.\r
1723 See the \ref ReceiveEngine section.\r
1724\r
1725 This routine is called by the TCPv4 driver when some data is\r
1726 received.\r
d7ce7006 1727\r
a88c3163 1728 Buffer the data that was just received.\r
1729\r
1730 @param [in] Event The receive completion event\r
d7ce7006 1731\r
a88c3163 1732 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
d7ce7006 1733\r
1734**/\r
1735VOID\r
a88c3163 1736EslTcp4RxComplete (\r
1737 IN EFI_EVENT Event,\r
1738 IN ESL_IO_MGMT * pIo\r
d7ce7006 1739 )\r
1740{\r
a88c3163 1741 BOOLEAN bUrgent;\r
1742 size_t LengthInBytes;\r
1743 ESL_PACKET * pPacket;\r
1744 EFI_STATUS Status;\r
d7ce7006 1745\r
1746 DBG_ENTER ( );\r
1747\r
1748 //\r
a88c3163 1749 // Get the operation status.\r
d7ce7006 1750 //\r
a88c3163 1751 Status = pIo->Token.Tcp4Rx.CompletionToken.Status;\r
d7ce7006 1752\r
1753 //\r
a88c3163 1754 // +--------------------+ +---------------------------+\r
1755 // | ESL_IO_MGMT | | ESL_PACKET |\r
1756 // | | | |\r
1757 // | +---------------+ +-----------------------+ |\r
1758 // | | Token | | EFI_TCP4_RECEIVE_DATA | |\r
1759 // | | RxData --> | | |\r
1760 // | | | +-----------------------+---+\r
1761 // | | Event | | Data Buffer |\r
1762 // +----+---------------+ | |\r
1763 // | |\r
1764 // +---------------------------+\r
d7ce7006 1765 //\r
a88c3163 1766 //\r
1767 // Duplicate the buffer address and length for use by the\r
1768 // buffer handling code in EslTcp4Receive. These fields are\r
1769 // used when a partial read is done of the data from the\r
1770 // packet.\r
1771 //\r
1772 pPacket = pIo->pPacket;\r
1773 pPacket->pBuffer = pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer;\r
1774 LengthInBytes = pPacket->Op.Tcp4Rx.RxData.DataLength;\r
1775 pPacket->ValidBytes = LengthInBytes;\r
d7ce7006 1776\r
a88c3163 1777 //\r
1778 // Get the data type so that it may be linked to the\r
1779 // correct receive buffer list on the ESL_SOCKET structure\r
1780 //\r
1781 bUrgent = pPacket->Op.Tcp4Rx.RxData.UrgentFlag;\r
d7ce7006 1782\r
1783 //\r
a88c3163 1784 // Complete this request\r
d7ce7006 1785 //\r
a88c3163 1786 EslSocketRxComplete ( pIo, Status, LengthInBytes, bUrgent );\r
1787 DBG_EXIT ( );\r
1788}\r
1789\r
1790\r
1791/**\r
1792 Start a receive operation\r
1793\r
1794 This routine posts a receive buffer to the TCPv4 driver.\r
1795 See the \ref ReceiveEngine section.\r
1796\r
1797 This support routine is called by EslSocketRxStart.\r
1798\r
1799 @param [in] pPort Address of an ::ESL_PORT structure.\r
1800 @param [in] pIo Address of an ::ESL_IO_MGMT structure.\r
1801\r
1802 **/\r
1803VOID\r
1804EslTcp4RxStart (\r
1805 IN ESL_PORT * pPort,\r
1806 IN ESL_IO_MGMT * pIo\r
1807 )\r
1808{\r
1809 ESL_PACKET * pPacket;\r
1810\r
1811 DBG_ENTER ( );\r
1812\r
1813 //\r
1814 // Initialize the buffer for receive\r
1815 //\r
1816 pPacket = pIo->pPacket;\r
1817 pIo->Token.Tcp4Rx.Packet.RxData = &pPacket->Op.Tcp4Rx.RxData;\r
1818 pPacket->Op.Tcp4Rx.RxData.DataLength = sizeof ( pPacket->Op.Tcp4Rx.Buffer );\r
1819 pPacket->Op.Tcp4Rx.RxData.FragmentCount = 1;\r
1820 pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentLength = pPacket->Op.Tcp4Rx.RxData.DataLength;\r
1821 pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Rx.Buffer[0];\r
d7ce7006 1822\r
1823 DBG_EXIT ( );\r
1824}\r
1825\r
1826\r
1827/**\r
1828 Determine if the socket is configured.\r
1829\r
a88c3163 1830 This routine uses the flag ESL_SOCKET::bConfigured to determine\r
1831 if the network layer's configuration routine has been called.\r
1832\r
1833 This routine is called by EslSocketIsConfigured to verify\r
1834 that the socket has been configured.\r
1835\r
1836 @param [in] pSocket Address of an ::ESL_SOCKET structure.\r
d7ce7006 1837\r
d7ce7006 1838 @retval EFI_SUCCESS - The port is connected\r
1839 @retval EFI_NOT_STARTED - The port is not connected\r
1840\r
1841 **/\r
1842 EFI_STATUS\r
a88c3163 1843 EslTcp4SocketIsConfigured (\r
1844 IN ESL_SOCKET * pSocket\r
d7ce7006 1845 )\r
1846{\r
1847 EFI_STATUS Status;\r
1848\r
1849 DBG_ENTER ( );\r
1850\r
1851 //\r
1852 // Determine the socket configuration status\r
1853 //\r
1854 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;\r
1855\r
1856 //\r
1857 // Return the port connected state.\r
1858 //\r
1859 DBG_EXIT_STATUS ( Status );\r
1860 return Status;\r
1861}\r
1862\r
1863\r
1864/**\r
1865 Buffer data for transmission over a network connection.\r
1866\r
a88c3163 1867 This routine buffers data for the transmit engine in one of two\r
1868 queues, one for urgent (out-of-band) data and the other for normal\r
1869 data. The urgent data is provided to TCP as soon as it is available,\r
1870 allowing the TCP layer to schedule transmission of the urgent data\r
1871 between packets of normal data.\r
d7ce7006 1872\r
a88c3163 1873 This routine is called by ::EslSocketTransmit to buffer\r
1874 data for transmission. When the \ref TransmitEngine has resources,\r
1875 this routine will start the transmission of the next buffer on\r
1876 the network connection.\r
d7ce7006 1877\r
1878 Transmission errors are returned during the next transmission or\r
1879 during the close operation. Only buffering errors are returned\r
1880 during the current transmission attempt.\r
1881\r
a88c3163 1882 @param [in] pSocket Address of an ::ESL_SOCKET structure\r
0e565888 1883\r
d7ce7006 1884 @param [in] Flags Message control flags\r
0e565888 1885\r
d7ce7006 1886 @param [in] BufferLength Length of the the buffer\r
0e565888 1887\r
d7ce7006 1888 @param [in] pBuffer Address of a buffer to receive the data.\r
0e565888 1889\r
d7ce7006 1890 @param [in] pDataLength Number of received data bytes in the buffer.\r
1891\r
a88c3163 1892 @param [in] pAddress Network address of the remote system address\r
1893\r
1894 @param [in] AddressLength Length of the remote network address structure\r
1895\r
d7ce7006 1896 @retval EFI_SUCCESS - Socket data successfully buffered\r
1897\r
1898 **/\r
1899EFI_STATUS\r
a88c3163 1900EslTcp4TxBuffer (\r
1901 IN ESL_SOCKET * pSocket,\r
d7ce7006 1902 IN int Flags,\r
1903 IN size_t BufferLength,\r
1904 IN CONST UINT8 * pBuffer,\r
a88c3163 1905 OUT size_t * pDataLength,\r
1906 IN const struct sockaddr * pAddress,\r
1907 IN socklen_t AddressLength\r
d7ce7006 1908 )\r
1909{\r
1910 BOOLEAN bUrgent;\r
a88c3163 1911 BOOLEAN bUrgentQueue;\r
1912 ESL_PACKET * pPacket;\r
1913 ESL_IO_MGMT ** ppActive;\r
1914 ESL_IO_MGMT ** ppFree;\r
1915 ESL_PORT * pPort;\r
1916 ESL_PACKET ** ppQueueHead;\r
1917 ESL_PACKET ** ppQueueTail;\r
1918 ESL_PACKET * pPreviousPacket;\r
d7ce7006 1919 size_t * pTxBytes;\r
1920 EFI_TCP4_TRANSMIT_DATA * pTxData;\r
1921 EFI_STATUS Status;\r
1922 EFI_TPL TplPrevious;\r
1923\r
1924 DBG_ENTER ( );\r
1925\r
1926 //\r
1927 // Assume failure\r
1928 //\r
1929 Status = EFI_UNSUPPORTED;\r
1930 pSocket->errno = ENOTCONN;\r
a88c3163 1931 *pDataLength = 0;\r
d7ce7006 1932\r
1933 //\r
1934 // Verify that the socket is connected\r
1935 //\r
1936 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
1937 //\r
1938 // Locate the port\r
1939 //\r
1940 pPort = pSocket->pPortList;\r
1941 if ( NULL != pPort ) {\r
1942 //\r
1943 // Determine the queue head\r
1944 //\r
d7ce7006 1945 bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));\r
a88c3163 1946 bUrgentQueue = bUrgent\r
1947 && ( !pSocket->bOobInLine )\r
1948 && pSocket->pApi->bOobSupported;\r
1949 if ( bUrgentQueue ) {\r
d7ce7006 1950 ppQueueHead = &pSocket->pTxOobPacketListHead;\r
1951 ppQueueTail = &pSocket->pTxOobPacketListTail;\r
a88c3163 1952 ppActive = &pPort->pTxOobActive;\r
1953 ppFree = &pPort->pTxOobFree;\r
d7ce7006 1954 pTxBytes = &pSocket->TxOobBytes;\r
1955 }\r
1956 else {\r
1957 ppQueueHead = &pSocket->pTxPacketListHead;\r
1958 ppQueueTail = &pSocket->pTxPacketListTail;\r
a88c3163 1959 ppActive = &pPort->pTxActive;\r
1960 ppFree = &pPort->pTxFree;\r
d7ce7006 1961 pTxBytes = &pSocket->TxBytes;\r
1962 }\r
1963\r
1964 //\r
1965 // Verify that there is enough room to buffer another\r
1966 // transmit operation\r
1967 //\r
1968 if ( pSocket->MaxTxBuf > *pTxBytes ) {\r
a88c3163 1969 if ( pPort->bTxFlowControl ) {\r
1970 DEBUG (( DEBUG_TX,\r
1971 "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",\r
1972 pPort,\r
1973 pSocket->MaxTxBuf,\r
1974 *pTxBytes ));\r
1975 pPort->bTxFlowControl = FALSE;\r
1976 }\r
1977\r
d7ce7006 1978 //\r
1979 // Attempt to allocate the packet\r
1980 //\r
1981 Status = EslSocketPacketAllocate ( &pPacket,\r
1982 sizeof ( pPacket->Op.Tcp4Tx )\r
1983 - sizeof ( pPacket->Op.Tcp4Tx.Buffer )\r
1984 + BufferLength,\r
a88c3163 1985 0,\r
d7ce7006 1986 DEBUG_TX );\r
1987 if ( !EFI_ERROR ( Status )) {\r
1988 //\r
1989 // Initialize the transmit operation\r
1990 //\r
1991 pTxData = &pPacket->Op.Tcp4Tx.TxData;\r
a88c3163 1992 pTxData->Push = TRUE || bUrgent;\r
d7ce7006 1993 pTxData->Urgent = bUrgent;\r
1994 pTxData->DataLength = (UINT32) BufferLength;\r
1995 pTxData->FragmentCount = 1;\r
1996 pTxData->FragmentTable[0].FragmentLength = (UINT32) BufferLength;\r
1997 pTxData->FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Tx.Buffer[0];\r
1998\r
1999 //\r
2000 // Copy the data into the buffer\r
2001 //\r
2002 CopyMem ( &pPacket->Op.Tcp4Tx.Buffer[0],\r
2003 pBuffer,\r
2004 BufferLength );\r
2005\r
2006 //\r
2007 // Synchronize with the socket layer\r
2008 //\r
2009 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2010\r
2011 //\r
2012 // Stop transmission after an error\r
2013 //\r
2014 if ( !EFI_ERROR ( pSocket->TxError )) {\r
2015 //\r
2016 // Display the request\r
2017 //\r
2018 DEBUG (( DEBUG_TX,\r
2019 "Send %d %s bytes from 0x%08x\r\n",\r
2020 BufferLength,\r
2021 bUrgent ? L"urgent" : L"normal",\r
2022 pBuffer ));\r
2023\r
2024 //\r
2025 // Queue the data for transmission\r
2026 //\r
2027 pPacket->pNext = NULL;\r
2028 pPreviousPacket = *ppQueueTail;\r
2029 if ( NULL == pPreviousPacket ) {\r
2030 *ppQueueHead = pPacket;\r
2031 }\r
2032 else {\r
2033 pPreviousPacket->pNext = pPacket;\r
2034 }\r
2035 *ppQueueTail = pPacket;\r
2036 DEBUG (( DEBUG_TX,\r
2037 "0x%08x: Packet on %s transmit list\r\n",\r
2038 pPacket,\r
a88c3163 2039 bUrgentQueue ? L"urgent" : L"normal" ));\r
d7ce7006 2040\r
2041 //\r
2042 // Account for the buffered data\r
2043 //\r
2044 *pTxBytes += BufferLength;\r
2045 *pDataLength = BufferLength;\r
2046\r
2047 //\r
2048 // Start the transmit engine if it is idle\r
2049 //\r
a88c3163 2050 if ( NULL != *ppFree ) {\r
2051 EslSocketTxStart ( pPort,\r
2052 ppQueueHead,\r
2053 ppQueueTail,\r
2054 ppActive,\r
2055 ppFree );\r
d7ce7006 2056 }\r
2057 }\r
2058 else {\r
2059 //\r
2060 // Previous transmit error\r
2061 // Stop transmission\r
2062 //\r
2063 Status = pSocket->TxError;\r
2064 pSocket->errno = EIO;\r
2065\r
2066 //\r
2067 // Free the packet\r
2068 //\r
2069 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
2070 }\r
2071\r
2072 //\r
2073 // Release the socket layer synchronization\r
2074 //\r
2075 RESTORE_TPL ( TplPrevious );\r
2076 }\r
2077 else {\r
2078 //\r
2079 // Packet allocation failed\r
2080 //\r
2081 pSocket->errno = ENOMEM;\r
2082 }\r
2083 }\r
2084 else {\r
a88c3163 2085 if ( !pPort->bTxFlowControl ) {\r
2086 DEBUG (( DEBUG_TX,\r
2087 "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",\r
2088 pPort,\r
2089 pSocket->MaxTxBuf,\r
2090 *pTxBytes ));\r
2091 pPort->bTxFlowControl = TRUE;\r
2092 }\r
d7ce7006 2093 //\r
2094 // Not enough buffer space available\r
2095 //\r
2096 pSocket->errno = EAGAIN;\r
2097 Status = EFI_NOT_READY;\r
2098 }\r
2099 }\r
2100 }\r
2101\r
2102 //\r
2103 // Return the operation status\r
2104 //\r
2105 DBG_EXIT_STATUS ( Status );\r
2106 return Status;\r
2107}\r
2108\r
2109\r
2110/**\r
2111 Process the normal data transmit completion\r
2112\r
a88c3163 2113 This routine use ::EslSocketTxComplete to perform the transmit\r
2114 completion processing for normal data.\r
2115\r
2116 This routine is called by the TCPv4 network layer when a\r
2117 normal data transmit request completes.\r
2118\r
2119 @param [in] Event The normal transmit completion event\r
d7ce7006 2120\r
a88c3163 2121 @param [in] pIo The ESL_IO_MGMT structure address\r
d7ce7006 2122\r
2123**/\r
2124VOID\r
a88c3163 2125EslTcp4TxComplete (\r
d7ce7006 2126 IN EFI_EVENT Event,\r
a88c3163 2127 IN ESL_IO_MGMT * pIo\r
d7ce7006 2128 )\r
2129{\r
2130 UINT32 LengthInBytes;\r
a88c3163 2131 ESL_PACKET * pPacket;\r
2132 ESL_PORT * pPort;\r
2133 ESL_SOCKET * pSocket;\r
d7ce7006 2134 EFI_STATUS Status;\r
0e565888 2135\r
d7ce7006 2136 DBG_ENTER ( );\r
a88c3163 2137\r
d7ce7006 2138 //\r
2139 // Locate the active transmit packet\r
2140 //\r
a88c3163 2141 pPacket = pIo->pPacket;\r
2142 pPort = pIo->pPort;\r
d7ce7006 2143 pSocket = pPort->pSocket;\r
a88c3163 2144\r
d7ce7006 2145 //\r
a88c3163 2146 // Get the transmit length and status\r
d7ce7006 2147 //\r
d7ce7006 2148 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;\r
2149 pSocket->TxBytes -= LengthInBytes;\r
a88c3163 2150 Status = pIo->Token.Tcp4Tx.CompletionToken.Status;\r
d7ce7006 2151\r
2152 //\r
a88c3163 2153 // Complete the transmit operation\r
d7ce7006 2154 //\r
a88c3163 2155 EslSocketTxComplete ( pIo,\r
2156 LengthInBytes,\r
2157 Status,\r
2158 "Normal ",\r
2159 &pSocket->pTxPacketListHead,\r
2160 &pSocket->pTxPacketListTail,\r
2161 &pPort->pTxActive,\r
2162 &pPort->pTxFree );\r
d7ce7006 2163 DBG_EXIT ( );\r
2164}\r
2165\r
2166\r
2167/**\r
2168 Process the urgent data transmit completion\r
2169\r
a88c3163 2170 This routine use ::EslSocketTxComplete to perform the transmit\r
2171 completion processing for urgent data.\r
d7ce7006 2172\r
a88c3163 2173 This routine is called by the TCPv4 network layer when a\r
2174 urgent data transmit request completes.\r
2175\r
2176 @param [in] Event The urgent transmit completion event\r
2177\r
2178 @param [in] pIo The ESL_IO_MGMT structure address\r
d7ce7006 2179\r
2180**/\r
2181VOID\r
a88c3163 2182EslTcp4TxOobComplete (\r
d7ce7006 2183 IN EFI_EVENT Event,\r
a88c3163 2184 IN ESL_IO_MGMT * pIo\r
d7ce7006 2185 )\r
2186{\r
2187 UINT32 LengthInBytes;\r
a88c3163 2188 ESL_PACKET * pPacket;\r
2189 ESL_PORT * pPort;\r
2190 ESL_SOCKET * pSocket;\r
d7ce7006 2191 EFI_STATUS Status;\r
2192\r
2193 DBG_ENTER ( );\r
2194\r
2195 //\r
2196 // Locate the active transmit packet\r
2197 //\r
a88c3163 2198 pPacket = pIo->pPacket;\r
2199 pPort = pIo->pPort;\r
d7ce7006 2200 pSocket = pPort->pSocket;\r
d7ce7006 2201\r
2202 //\r
a88c3163 2203 // Get the transmit length and status\r
d7ce7006 2204 //\r
d7ce7006 2205 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;\r
2206 pSocket->TxOobBytes -= LengthInBytes;\r
a88c3163 2207 Status = pIo->Token.Tcp4Tx.CompletionToken.Status;\r
d7ce7006 2208\r
2209 //\r
a88c3163 2210 // Complete the transmit operation\r
d7ce7006 2211 //\r
a88c3163 2212 EslSocketTxComplete ( pIo,\r
2213 LengthInBytes,\r
2214 Status,\r
2215 "Urgent ",\r
2216 &pSocket->pTxOobPacketListHead,\r
2217 &pSocket->pTxOobPacketListTail,\r
2218 &pPort->pTxOobActive,\r
2219 &pPort->pTxOobFree );\r
d7ce7006 2220 DBG_EXIT ( );\r
2221}\r
2222\r
2223\r
2dc09dd5
LL
2224/**\r
2225 Verify the adapter's IP address\r
2226\r
2227 This support routine is called by EslSocketBindTest.\r
2228\r
2229 @param [in] pPort Address of an ::ESL_PORT structure.\r
2230 @param [in] pConfigData Address of the configuration data\r
2231\r
2232 @retval EFI_SUCCESS - The IP address is valid\r
2233 @retval EFI_NOT_STARTED - The IP address is invalid\r
2234\r
2235 **/\r
2236EFI_STATUS\r
2237EslTcp4VerifyLocalIpAddress (\r
2238 IN ESL_PORT * pPort,\r
2239 IN EFI_TCP4_CONFIG_DATA * pConfigData\r
2240 )\r
2241{\r
2242 UINTN DataSize;\r
2243 EFI_TCP4_ACCESS_POINT * pAccess;\r
c581e503 2244 EFI_IP4_CONFIG2_INTERFACE_INFO * pIfInfo;\r
2245 EFI_IP4_CONFIG2_PROTOCOL * pIpConfig2Protocol;\r
2dc09dd5
LL
2246 ESL_SERVICE * pService;\r
2247 EFI_STATUS Status;\r
2248\r
2249 DBG_ENTER ( );\r
2250\r
2251 //\r
2252 // Use break instead of goto\r
2253 //\r
c581e503 2254 pIfInfo = NULL;\r
2dc09dd5
LL
2255 for ( ; ; ) {\r
2256 //\r
2257 // Determine if the IP address is specified\r
2258 //\r
2259 pAccess = &pConfigData->AccessPoint;\r
2260 DEBUG (( DEBUG_BIND,\r
2261 "UseDefaultAddress: %s\r\n",\r
2262 pAccess->UseDefaultAddress ? L"TRUE" : L"FALSE" ));\r
2263 DEBUG (( DEBUG_BIND,\r
2264 "Requested IP address: %d.%d.%d.%d\r\n",\r
2265 pAccess->StationAddress.Addr [ 0 ],\r
2266 pAccess->StationAddress.Addr [ 1 ],\r
2267 pAccess->StationAddress.Addr [ 2 ],\r
2268 pAccess->StationAddress.Addr [ 3 ]));\r
2269 if ( pAccess->UseDefaultAddress\r
2270 || (( 0 == pAccess->StationAddress.Addr [ 0 ])\r
2271 && ( 0 == pAccess->StationAddress.Addr [ 1 ])\r
2272 && ( 0 == pAccess->StationAddress.Addr [ 2 ])\r
2273 && ( 0 == pAccess->StationAddress.Addr [ 3 ])))\r
2274 {\r
2275 Status = EFI_SUCCESS;\r
2276 break;\r
2277 }\r
2278\r
2279 //\r
2280 // Open the configuration protocol\r
2281 //\r
2282 pService = pPort->pService;\r
c581e503 2283 Status = gBS->OpenProtocol ( \r
2284 pService->Controller,\r
2285 &gEfiIp4Config2ProtocolGuid,\r
2286 (VOID **)&pIpConfig2Protocol,\r
2287 NULL,\r
2288 NULL,\r
2289 EFI_OPEN_PROTOCOL_GET_PROTOCOL \r
2290 );\r
2dc09dd5
LL
2291 if ( EFI_ERROR ( Status )) {\r
2292 DEBUG (( DEBUG_ERROR,\r
2293 "ERROR - IP Configuration Protocol not available, Status: %r\r\n",\r
2294 Status ));\r
2295 break;\r
2296 }\r
2297\r
2298 //\r
c581e503 2299 // Get the interface information size.\r
2dc09dd5
LL
2300 //\r
2301 DataSize = 0;\r
c581e503 2302 Status = pIpConfig2Protocol->GetData ( \r
2303 pIpConfig2Protocol,\r
2304 Ip4Config2DataTypeInterfaceInfo,\r
2305 &DataSize,\r
2306 NULL\r
2307 );\r
2dc09dd5
LL
2308 if ( EFI_BUFFER_TOO_SMALL != Status ) {\r
2309 DEBUG (( DEBUG_ERROR,\r
c581e503 2310 "ERROR - Failed to get the interface information size, Status: %r\r\n",\r
2dc09dd5
LL
2311 Status ));\r
2312 break;\r
2313 }\r
2314\r
2315 //\r
c581e503 2316 // Allocate the interface information buffer\r
2dc09dd5 2317 //\r
c581e503 2318 pIfInfo = AllocatePool ( DataSize );\r
2319 if ( NULL == pIfInfo ) {\r
2dc09dd5 2320 DEBUG (( DEBUG_ERROR,\r
c581e503 2321 "ERROR - Not enough memory to allocate the interface information buffer!\r\n" ));\r
2dc09dd5
LL
2322 Status = EFI_OUT_OF_RESOURCES;\r
2323 break;\r
2324 }\r
2325\r
2326 //\r
c581e503 2327 // Get the interface info.\r
2dc09dd5 2328 //\r
c581e503 2329 Status = pIpConfig2Protocol->GetData ( \r
2330 pIpConfig2Protocol,\r
2331 Ip4Config2DataTypeInterfaceInfo,\r
2332 &DataSize,\r
2333 pIfInfo\r
2334 );\r
2dc09dd5
LL
2335 if ( EFI_ERROR ( Status )) {\r
2336 DEBUG (( DEBUG_ERROR,\r
c581e503 2337 "ERROR - Failed to return the interface info, Status: %r\r\n",\r
2dc09dd5
LL
2338 Status ));\r
2339 break;\r
2340 }\r
2341\r
2342 //\r
2343 // Display the current configuration\r
2344 //\r
2345 DEBUG (( DEBUG_BIND,\r
2346 "Actual adapter IP address: %d.%d.%d.%d\r\n",\r
c581e503 2347 pIfInfo->StationAddress.Addr [ 0 ],\r
2348 pIfInfo->StationAddress.Addr [ 1 ],\r
2349 pIfInfo->StationAddress.Addr [ 2 ],\r
2350 pIfInfo->StationAddress.Addr [ 3 ]));\r
2dc09dd5
LL
2351\r
2352 //\r
2353 // Assume the port is not configured\r
2354 //\r
2355 Status = EFI_SUCCESS;\r
c581e503 2356 if (( pAccess->StationAddress.Addr [ 0 ] == pIfInfo->StationAddress.Addr [ 0 ])\r
2357 && ( pAccess->StationAddress.Addr [ 1 ] == pIfInfo->StationAddress.Addr [ 1 ])\r
2358 && ( pAccess->StationAddress.Addr [ 2 ] == pIfInfo->StationAddress.Addr [ 2 ])\r
2359 && ( pAccess->StationAddress.Addr [ 3 ] == pIfInfo->StationAddress.Addr [ 3 ])) {\r
2dc09dd5
LL
2360 break;\r
2361 }\r
2362\r
2363 //\r
2364 // The IP address did not match\r
2365 //\r
2366 Status = EFI_NOT_STARTED;\r
2367 break;\r
2368 }\r
2369\r
2370 //\r
2371 // Free the buffer if necessary\r
2372 //\r
c581e503 2373 if ( NULL != pIfInfo ) {\r
2374 FreePool ( pIfInfo );\r
2dc09dd5
LL
2375 }\r
2376\r
2377 //\r
2378 // Return the IP address status\r
2379 //\r
2380 DBG_EXIT_STATUS ( Status );\r
2381 return Status;\r
2382}\r
2383\r
2384\r
d7ce7006 2385/**\r
a88c3163 2386 Interface between the socket layer and the network specific\r
2387 code that supports SOCK_STREAM and SOCK_SEQPACKET sockets\r
2388 over TCPv4.\r
2389**/\r
2390CONST ESL_PROTOCOL_API cEslTcp4Api = {\r
2391 "TCPv4",\r
2392 IPPROTO_TCP,\r
2393 OFFSET_OF ( ESL_PORT, Context.Tcp4.ConfigData ),\r
2394 OFFSET_OF ( ESL_LAYER, pTcp4List ),\r
2395 OFFSET_OF ( struct sockaddr_in, sin_zero ),\r
2396 sizeof ( struct sockaddr_in ),\r
2397 AF_INET,\r
2398 sizeof (((ESL_PACKET *)0 )->Op.Tcp4Rx ),\r
2399 OFFSET_OF ( ESL_PACKET, Op.Tcp4Rx.Buffer ) - OFFSET_OF ( ESL_PACKET, Op ),\r
2400 OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Rx.Packet.RxData ),\r
2401 TRUE,\r
2402 EADDRINUSE,\r
2403 EslTcp4Accept,\r
2404 EslTcp4ConnectPoll,\r
2405 EslTcp4ConnectStart,\r
2406 EslTcp4SocketIsConfigured,\r
2407 EslTcp4LocalAddressGet,\r
2408 EslTcp4LocalAddressSet,\r
2409 EslTcp4Listen,\r
2410 NULL, // OptionGet\r
2411 NULL, // OptionSet\r
2412 EslTcp4PacketFree,\r
2413 EslTcp4PortAllocate,\r
2414 EslTcp4PortClose,\r
2415 EslTcp4PortCloseOp,\r
2416 FALSE,\r
2417 EslTcp4Receive,\r
2418 EslTcp4RemoteAddressGet,\r
2419 EslTcp4RemoteAddressSet,\r
2420 EslTcp4RxComplete,\r
2421 EslTcp4RxStart,\r
2422 EslTcp4TxBuffer,\r
2423 EslTcp4TxComplete,\r
2dc09dd5 2424 EslTcp4TxOobComplete,\r
a93b0f45 2425 (PFN_API_VERIFY_LOCAL_IP_ADDRESS)EslTcp4VerifyLocalIpAddress\r
a88c3163 2426};\r