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