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