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