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