]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/EfiSocketLib/Tcp6.c
Change to match the tree required on the storage device.
[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
474 EFI_STATUS Status;\r
475\r
476 DBG_ENTER ( );\r
477 \r
478 //\r
479 // Determine if any more local adapters are available\r
480 //\r
481 pPort = pSocket->pPortList;\r
482 if ( NULL != pPort ) {\r
483 //\r
484 // Configure the port\r
485 //\r
486 pTcp6 = &pPort->Context.Tcp6;\r
487 pTcp6->ConfigData.AccessPoint.ActiveFlag = TRUE;\r
488 pTcp6->ConfigData.TrafficClass = 0;\r
489 pTcp6->ConfigData.HopLimit = 255;\r
490 pTcp6Protocol = pPort->pProtocol.TCPv6;\r
491 Status = pTcp6Protocol->Configure ( pTcp6Protocol,\r
492 &pTcp6->ConfigData );\r
493 if ( EFI_ERROR ( Status )) {\r
494 DEBUG (( DEBUG_CONNECT,\r
495 "ERROR - Failed to configure the Tcp6 port, Status: %r\r\n",\r
496 Status ));\r
497 switch ( Status ) {\r
498 case EFI_ACCESS_DENIED:\r
499 pSocket->errno = EACCES;\r
500 break;\r
501 \r
502 default:\r
503 case EFI_DEVICE_ERROR:\r
504 pSocket->errno = EIO;\r
505 break;\r
506 \r
507 case EFI_INVALID_PARAMETER:\r
508 pSocket->errno = EADDRNOTAVAIL;\r
509 break;\r
510 \r
511 case EFI_NO_MAPPING:\r
512 pSocket->errno = EAFNOSUPPORT;\r
513 break;\r
514 \r
515 case EFI_OUT_OF_RESOURCES:\r
516 pSocket->errno = ENOBUFS;\r
517 break;\r
518 \r
519 case EFI_UNSUPPORTED:\r
520 pSocket->errno = EOPNOTSUPP;\r
521 break;\r
522 }\r
523 }\r
524 else {\r
525 DEBUG (( DEBUG_CONNECT,\r
526 "0x%08x: Port configured\r\n",\r
527 pPort ));\r
528 pPort->bConfigured = TRUE;\r
529\r
530 //\r
531 // Attempt the connection to the remote system\r
532 //\r
533 Status = pTcp6Protocol->Connect ( pTcp6Protocol,\r
534 &pTcp6->ConnectToken );\r
535 if ( !EFI_ERROR ( Status )) {\r
536 //\r
537 // Connection in progress\r
538 //\r
539 pSocket->errno = EINPROGRESS;\r
540 Status = EFI_NOT_READY;\r
541 DEBUG (( DEBUG_CONNECT,\r
542 "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
543 pPort,\r
544 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
545 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[1],\r
546 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[2],\r
547 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[3],\r
548 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[4],\r
549 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[5],\r
550 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[6],\r
551 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[7],\r
552 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[8],\r
553 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[9],\r
554 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[10],\r
555 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[11],\r
556 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[12],\r
557 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[13],\r
558 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[14],\r
559 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[15],\r
560 pTcp6->ConfigData.AccessPoint.RemotePort ));\r
561 }\r
562 else {\r
563 //\r
564 // Connection error\r
565 //\r
566 DEBUG (( DEBUG_CONNECT,\r
567 "ERROR - Port 0x%08x not connected, Status: %r\r\n",\r
568 pPort,\r
569 Status ));\r
570 //\r
571 // Determine the errno value\r
572 //\r
573 switch ( Status ) {\r
574 default:\r
575 pSocket->errno = EIO;\r
576 break;\r
577\r
578 case EFI_OUT_OF_RESOURCES:\r
579 pSocket->errno = ENOBUFS;\r
580 break;\r
581\r
582 case EFI_TIMEOUT:\r
583 pSocket->errno = ETIMEDOUT;\r
584 break;\r
585\r
586 case EFI_NETWORK_UNREACHABLE:\r
587 pSocket->errno = ENETDOWN;\r
588 break;\r
589\r
590 case EFI_HOST_UNREACHABLE:\r
591 pSocket->errno = EHOSTUNREACH;\r
592 break;\r
593\r
594 case EFI_PORT_UNREACHABLE:\r
595 case EFI_PROTOCOL_UNREACHABLE:\r
596 case EFI_CONNECTION_REFUSED:\r
597 pSocket->errno = ECONNREFUSED;\r
598 break;\r
599\r
600 case EFI_CONNECTION_RESET:\r
601 pSocket->errno = ECONNRESET;\r
602 break;\r
603 }\r
604 }\r
605 }\r
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
804 \r
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
824\r
825 //\r
826 // All done\r
827 //\r
828 DEBUG (( DEBUG_LISTEN,\r
829 "0x%08x: pSocket - Listen pending on socket\r\n",\r
830 pSocket ));\r
831 break;\r
832 }\r
833\r
834 //\r
835 // Return the operation status\r
836 //\r
837 DBG_EXIT_STATUS ( Status );\r
838 return Status;\r
839}\r
840\r
841\r
842/**\r
843 Process the connection attempt\r
844\r
845 A system has initiated a connection attempt with a socket in the\r
846 listen state. Attempt to complete the connection.\r
847\r
848 The TCPv6 layer calls this routine when a connection is made to\r
849 the socket in the listen state. See the\r
850 \ref ConnectionManagement section.\r
851\r
852 @param [in] Event The listen completion event\r
853\r
854 @param [in] pPort Address of an ::ESL_PORT structure.\r
855\r
856**/\r
857VOID\r
858EslTcp6ListenComplete (\r
859 IN EFI_EVENT Event,\r
860 IN ESL_PORT * pPort\r
861 )\r
862{\r
863 EFI_HANDLE ChildHandle;\r
864 struct sockaddr_in6 LocalAddress;\r
865 EFI_TCP6_CONFIG_DATA * pConfigData;\r
866 ESL_LAYER * pLayer;\r
867 ESL_PORT * pNewPort;\r
868 ESL_SOCKET * pNewSocket;\r
869 ESL_SOCKET * pSocket;\r
870 ESL_TCP6_CONTEXT * pTcp6;\r
871 EFI_TCP6_PROTOCOL * pTcp6Protocol;\r
872 EFI_STATUS Status;\r
873 EFI_HANDLE TcpPortHandle;\r
874 EFI_STATUS TempStatus;\r
875\r
876 DBG_ENTER ( );\r
877 VERIFY_AT_TPL ( TPL_SOCKETS );\r
878\r
879 //\r
880 // Assume success\r
881 //\r
882 Status = EFI_SUCCESS;\r
883\r
884 //\r
885 // Determine if this connection fits into the connection FIFO\r
886 //\r
887 pSocket = pPort->pSocket;\r
888 TcpPortHandle = pPort->Context.Tcp6.ListenToken.NewChildHandle;\r
889 if (( SOCKET_STATE_LISTENING == pSocket->State )\r
890 && ( pSocket->MaxFifoDepth > pSocket->FifoDepth )) {\r
891 //\r
892 // Allocate a socket for this connection\r
893 //\r
894 ChildHandle = NULL;\r
895 pLayer = &mEslLayer;\r
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
1093 \r
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
1213\r
1214 //\r
1215 // Display the local address\r
1216 //\r
1217 DEBUG (( DEBUG_BIND,\r
1218 "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
1219 pPort,\r
1220 pAccessPoint->StationAddress.Addr[0],\r
1221 pAccessPoint->StationAddress.Addr[1],\r
1222 pAccessPoint->StationAddress.Addr[2],\r
1223 pAccessPoint->StationAddress.Addr[3],\r
1224 pAccessPoint->StationAddress.Addr[4],\r
1225 pAccessPoint->StationAddress.Addr[5],\r
1226 pAccessPoint->StationAddress.Addr[6],\r
1227 pAccessPoint->StationAddress.Addr[7],\r
1228 pAccessPoint->StationAddress.Addr[8],\r
1229 pAccessPoint->StationAddress.Addr[9],\r
1230 pAccessPoint->StationAddress.Addr[10],\r
1231 pAccessPoint->StationAddress.Addr[11],\r
1232 pAccessPoint->StationAddress.Addr[12],\r
1233 pAccessPoint->StationAddress.Addr[13],\r
1234 pAccessPoint->StationAddress.Addr[14],\r
1235 pAccessPoint->StationAddress.Addr[15],\r
1236 pAccessPoint->StationPort ));\r
1237 }\r
1238 }\r
1239\r
1240 //\r
1241 // Return the operation status\r
1242 //\r
1243 DBG_EXIT_STATUS ( Status );\r
1244 return Status;\r
1245}\r
1246\r
1247\r
1248/**\r
1249 Free a receive packet\r
1250\r
1251 This routine performs the network specific operations necessary\r
1252 to free a receive packet.\r
1253\r
1254 This routine is called by ::EslSocketPortCloseTxDone to free a\r
1255 receive packet.\r
1256\r
1257 @param [in] pPacket Address of an ::ESL_PACKET structure.\r
1258 @param [in, out] pRxBytes Address of the count of RX bytes\r
1259\r
1260**/\r
1261VOID\r
1262EslTcp6PacketFree (\r
1263 IN ESL_PACKET * pPacket,\r
1264 IN OUT size_t * pRxBytes\r
1265 )\r
1266{\r
1267 DBG_ENTER ( );\r
1268\r
1269 //\r
1270 // Account for the receive bytes\r
1271 //\r
1272 *pRxBytes -= pPacket->Op.Tcp6Rx.RxData.DataLength;\r
1273 DBG_EXIT ( );\r
1274}\r
1275\r
1276\r
1277/**\r
1278 Initialize the network specific portions of an ::ESL_PORT structure.\r
1279\r
1280 This routine initializes the network specific portions of an\r
1281 ::ESL_PORT structure for use by the socket.\r
1282\r
1283 This support routine is called by ::EslSocketPortAllocate\r
1284 to connect the socket with the underlying network adapter\r
1285 running the TCPv6 protocol.\r
1286\r
1287 @param [in] pPort Address of an ESL_PORT structure\r
1288 @param [in] DebugFlags Flags for debug messages\r
1289\r
1290 @retval EFI_SUCCESS - Socket successfully created\r
1291\r
1292 **/\r
1293EFI_STATUS\r
1294EslTcp6PortAllocate (\r
1295 IN ESL_PORT * pPort,\r
1296 IN UINTN DebugFlags\r
1297 )\r
1298{\r
1299 EFI_TCP6_ACCESS_POINT * pAccessPoint;\r
1300 ESL_SOCKET * pSocket;\r
1301 ESL_TCP6_CONTEXT * pTcp6;\r
1302 EFI_STATUS Status;\r
1303\r
1304 DBG_ENTER ( );\r
1305\r
1306 //\r
1307 // Use for/break instead of goto\r
1308 for ( ; ; ) {\r
1309 //\r
1310 // Allocate the close event\r
1311 //\r
1312 pSocket = pPort->pSocket;\r
1313 pTcp6 = &pPort->Context.Tcp6;\r
1314 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
1315 TPL_SOCKETS,\r
1316 (EFI_EVENT_NOTIFY)EslSocketPortCloseComplete,\r
1317 pPort,\r
1318 &pTcp6->CloseToken.CompletionToken.Event);\r
1319 if ( EFI_ERROR ( Status )) {\r
1320 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1321 "ERROR - Failed to create the close event, Status: %r\r\n",\r
1322 Status ));\r
1323 pSocket->errno = ENOMEM;\r
1324 break;\r
1325 }\r
1326 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
1327 "0x%08x: Created close event\r\n",\r
1328 pTcp6->CloseToken.CompletionToken.Event ));\r
1329\r
1330 //\r
1331 // Allocate the connection event\r
1332 //\r
1333 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
1334 TPL_SOCKETS,\r
1335 (EFI_EVENT_NOTIFY)EslTcp6ConnectComplete,\r
1336 pPort,\r
1337 &pTcp6->ConnectToken.CompletionToken.Event);\r
1338 if ( EFI_ERROR ( Status )) {\r
1339 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1340 "ERROR - Failed to create the connect event, Status: %r\r\n",\r
1341 Status ));\r
1342 pSocket->errno = ENOMEM;\r
1343 break;\r
1344 }\r
1345 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
1346 "0x%08x: Created connect event\r\n",\r
1347 pTcp6->ConnectToken.CompletionToken.Event ));\r
1348\r
1349 //\r
1350 // Initialize the port\r
1351 //\r
1352 pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Tcp6Tx.TxData );\r
1353 pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Tcp6Tx.CompletionToken.Event );\r
1354 pSocket->TxTokenOffset = OFFSET_OF ( EFI_TCP6_IO_TOKEN, Packet.TxData );\r
1355\r
1356 //\r
1357 // Save the cancel, receive and transmit addresses\r
1358 // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED\r
1359 //\r
1360 pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.TCPv6->Configure;\r
1361 pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.TCPv6->Poll;\r
1362 pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv6->Receive;\r
1363 pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv6->Transmit;\r
1364\r
1365 //\r
1366 // Set the configuration flags\r
1367 //\r
1368 pAccessPoint = &pPort->Context.Tcp6.ConfigData.AccessPoint;\r
1369 pAccessPoint->ActiveFlag = FALSE;\r
1370 pTcp6->ConfigData.TrafficClass = 0;\r
1371 pTcp6->ConfigData.HopLimit = 255;\r
1372 break;\r
1373 }\r
1374\r
1375 //\r
1376 // Return the operation status\r
1377 //\r
1378 DBG_EXIT_STATUS ( Status );\r
1379 return Status;\r
1380}\r
1381\r
1382\r
1383/**\r
1384 Close a Tcp6 port.\r
1385\r
1386 This routine releases the network specific resources allocated by\r
1387 ::EslTcp6PortAllocate.\r
1388\r
1389 This routine is called by ::EslSocketPortClose.\r
1390 See the \ref PortCloseStateMachine section.\r
1391 \r
1392 @param [in] pPort Address of an ::ESL_PORT structure.\r
1393\r
1394 @retval EFI_SUCCESS The port is closed\r
1395 @retval other Port close error\r
1396\r
1397**/\r
1398EFI_STATUS\r
1399EslTcp6PortClose (\r
1400 IN ESL_PORT * pPort\r
1401 )\r
1402{\r
1403 UINTN DebugFlags;\r
1404 ESL_TCP6_CONTEXT * pTcp6;\r
1405 EFI_STATUS Status;\r
1406 \r
1407 DBG_ENTER ( );\r
1408\r
1409 //\r
1410 // Locate the port in the socket list\r
1411 //\r
1412 Status = EFI_SUCCESS;\r
1413 DebugFlags = pPort->DebugFlags;\r
1414 pTcp6 = &pPort->Context.Tcp6;\r
1415\r
1416 //\r
1417 // Done with the connect event\r
1418 //\r
1419 if ( NULL != pTcp6->ConnectToken.CompletionToken.Event ) {\r
1420 Status = gBS->CloseEvent ( pTcp6->ConnectToken.CompletionToken.Event );\r
1421 if ( !EFI_ERROR ( Status )) {\r
1422 DEBUG (( DebugFlags | DEBUG_POOL,\r
1423 "0x%08x: Closed connect event\r\n",\r
1424 pTcp6->ConnectToken.CompletionToken.Event ));\r
1425 }\r
1426 else {\r
1427 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1428 "ERROR - Failed to close the connect event, Status: %r\r\n",\r
1429 Status ));\r
1430 ASSERT ( EFI_SUCCESS == Status );\r
1431 }\r
1432 }\r
1433\r
1434 //\r
1435 // Done with the close event\r
1436 //\r
1437 if ( NULL != pTcp6->CloseToken.CompletionToken.Event ) {\r
1438 Status = gBS->CloseEvent ( pTcp6->CloseToken.CompletionToken.Event );\r
1439 if ( !EFI_ERROR ( Status )) {\r
1440 DEBUG (( DebugFlags | DEBUG_POOL,\r
1441 "0x%08x: Closed close event\r\n",\r
1442 pTcp6->CloseToken.CompletionToken.Event ));\r
1443 }\r
1444 else {\r
1445 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1446 "ERROR - Failed to close the close event, Status: %r\r\n",\r
1447 Status ));\r
1448 ASSERT ( EFI_SUCCESS == Status );\r
1449 }\r
1450 }\r
1451\r
1452 //\r
1453 // Done with the listen completion event\r
1454 //\r
1455 if ( NULL != pTcp6->ListenToken.CompletionToken.Event ) {\r
1456 Status = gBS->CloseEvent ( pTcp6->ListenToken.CompletionToken.Event );\r
1457 if ( !EFI_ERROR ( Status )) {\r
1458 DEBUG (( DebugFlags | DEBUG_POOL,\r
1459 "0x%08x: Closed listen completion event\r\n",\r
1460 pTcp6->ListenToken.CompletionToken.Event ));\r
1461 }\r
1462 else {\r
1463 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1464 "ERROR - Failed to close the listen completion event, Status: %r\r\n",\r
1465 Status ));\r
1466 ASSERT ( EFI_SUCCESS == Status );\r
1467 }\r
1468 }\r
1469\r
1470 //\r
1471 // Return the operation status\r
1472 //\r
1473 DBG_EXIT_STATUS ( Status );\r
1474 return Status;\r
1475}\r
1476\r
1477\r
1478/**\r
1479 Perform the network specific close operation on the port.\r
1480\r
1481 This routine performs a cancel operations on the TCPv6 port to\r
1482 shutdown the receive operations on the port.\r
1483\r
1484 This routine is called by the ::EslSocketPortCloseTxDone\r
1485 routine after the port completes all of the transmission.\r
1486\r
1487 @param [in] pPort Address of an ::ESL_PORT structure.\r
1488\r
1489 @retval EFI_SUCCESS The port is closed, not normally returned\r
1490 @retval EFI_NOT_READY The port is still closing\r
1491 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
1492 most likely the routine was called already.\r
1493\r
1494**/\r
1495EFI_STATUS\r
1496EslTcp6PortCloseOp (\r
1497 IN ESL_PORT * pPort\r
1498 )\r
1499{\r
1500 ESL_TCP6_CONTEXT * pTcp6;\r
1501 EFI_TCP6_PROTOCOL * pTcp6Protocol;\r
1502 EFI_STATUS Status;\r
1503\r
1504 DBG_ENTER ( );\r
1505\r
1506 //\r
1507 // Close the configured port\r
1508 //\r
1509 Status = EFI_SUCCESS;\r
1510 pTcp6 = &pPort->Context.Tcp6;\r
1511 pTcp6Protocol = pPort->pProtocol.TCPv6;\r
1512 pTcp6->CloseToken.AbortOnClose = pPort->bCloseNow;\r
1513 Status = pTcp6Protocol->Close ( pTcp6Protocol,\r
1514 &pTcp6->CloseToken );\r
1515 if ( !EFI_ERROR ( Status )) {\r
1516 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
1517 "0x%08x: Port close started\r\n",\r
1518 pPort ));\r
1519 }\r
1520 else {\r
1521 DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
1522 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",\r
1523 pPort,\r
1524 Status ));\r
1525 }\r
1526\r
1527 //\r
1528 // Return the operation status\r
1529 //\r
1530 DBG_EXIT_STATUS ( Status );\r
1531 return Status;\r
1532}\r
1533\r
1534\r
1535/**\r
1536 Receive data from a network connection.\r
1537\r
1538 This routine attempts to return buffered data to the caller. The\r
1539 data is removed from the urgent queue if the message flag MSG_OOB\r
1540 is specified, otherwise data is removed from the normal queue.\r
1541 See the \ref ReceiveEngine section.\r
1542\r
1543 This routine is called by ::EslSocketReceive to handle the network\r
1544 specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET\r
1545 sockets.\r
1546\r
1547 @param [in] pPort Address of an ::ESL_PORT structure.\r
1548\r
1549 @param [in] pPacket Address of an ::ESL_PACKET structure.\r
1550 \r
1551 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed\r
1552 \r
1553 @param [in] BufferLength Length of the the buffer\r
1554 \r
1555 @param [in] pBuffer Address of a buffer to receive the data.\r
1556 \r
1557 @param [in] pDataLength Number of received data bytes in the buffer.\r
1558\r
1559 @param [out] pAddress Network address to receive the remote system address\r
1560\r
1561 @param [out] pSkipBytes Address to receive the number of bytes skipped\r
1562\r
1563 @return Returns the address of the next free byte in the buffer.\r
1564\r
1565 **/\r
1566UINT8 *\r
1567EslTcp6Receive (\r
1568 IN ESL_PORT * pPort,\r
1569 IN ESL_PACKET * pPacket,\r
1570 IN BOOLEAN * pbConsumePacket,\r
1571 IN size_t BufferLength,\r
1572 IN UINT8 * pBuffer,\r
1573 OUT size_t * pDataLength,\r
1574 OUT struct sockaddr * pAddress,\r
1575 OUT size_t * pSkipBytes\r
1576 )\r
1577{\r
1578 size_t DataLength;\r
1579 struct sockaddr_in6 * pRemoteAddress;\r
1580 ESL_TCP6_CONTEXT * pTcp6;\r
1581\r
1582 DBG_ENTER ( );\r
1583\r
1584 //\r
1585 // Return the remote system address if requested\r
1586 //\r
1587 if ( NULL != pAddress ) {\r
1588 //\r
1589 // Build the remote address\r
1590 //\r
1591 pTcp6 = &pPort->Context.Tcp6;\r
1592 DEBUG (( DEBUG_RX,\r
1593 "Getting packet remote address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
1594 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
1595 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[1],\r
1596 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[2],\r
1597 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[3],\r
1598 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[4],\r
1599 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[5],\r
1600 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[6],\r
1601 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[7],\r
1602 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[8],\r
1603 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[9],\r
1604 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[10],\r
1605 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[11],\r
1606 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[12],\r
1607 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[13],\r
1608 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[14],\r
1609 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[15],\r
1610 pTcp6->ConfigData.AccessPoint.RemotePort ));\r
1611 pRemoteAddress = (struct sockaddr_in6 *)pAddress;\r
1612 CopyMem ( &pRemoteAddress->sin6_addr,\r
1613 &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
1614 sizeof ( pRemoteAddress->sin6_addr ));\r
1615 pRemoteAddress->sin6_port = SwapBytes16 ( pTcp6->ConfigData.AccessPoint.RemotePort );\r
1616 }\r
1617\r
1618 //\r
1619 // Determine the amount of received data\r
1620 //\r
1621 DataLength = pPacket->ValidBytes;\r
1622 if ( BufferLength < DataLength ) {\r
1623 DataLength = BufferLength;\r
1624 }\r
1625\r
1626 //\r
1627 // Move the data into the buffer\r
1628 //\r
1629 DEBUG (( DEBUG_RX,\r
1630 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",\r
1631 pPort,\r
1632 pPacket,\r
1633 pBuffer,\r
1634 DataLength ));\r
1635 CopyMem ( pBuffer, pPacket->pBuffer, DataLength );\r
1636\r
1637 //\r
1638 // Determine if the data is being read\r
1639 //\r
1640 if ( *pbConsumePacket ) {\r
1641 //\r
1642 // Account for the bytes consumed\r
1643 //\r
1644 pPacket->pBuffer += DataLength;\r
1645 pPacket->ValidBytes -= DataLength;\r
1646 DEBUG (( DEBUG_RX,\r
1647 "0x%08x: Port account for 0x%08x bytes\r\n",\r
1648 pPort,\r
1649 DataLength ));\r
1650\r
1651 //\r
1652 // Determine if the entire packet was consumed\r
1653 //\r
1654 if (( 0 == pPacket->ValidBytes )\r
1655 || ( SOCK_STREAM != pPort->pSocket->Type )) {\r
1656 //\r
1657 // All done with this packet\r
1658 // Account for any discarded data\r
1659 //\r
1660 *pSkipBytes = pPacket->ValidBytes;\r
1661 }\r
1662 else\r
1663 {\r
1664 //\r
1665 // More data to consume later\r
1666 //\r
1667 *pbConsumePacket = FALSE;\r
1668 }\r
1669 }\r
1670\r
1671 //\r
1672 // Return the data length and the buffer address\r
1673 //\r
1674 *pDataLength = DataLength;\r
1675 DBG_EXIT_HEX ( pBuffer );\r
1676 return pBuffer;\r
1677}\r
1678\r
1679\r
1680/**\r
1681 Get the remote socket address.\r
1682\r
1683 This routine returns the address of the remote connection point\r
1684 associated with the SOCK_STREAM or SOCK_SEQPACKET socket.\r
1685\r
1686 This routine is called by ::EslSocketGetPeerAddress to detemine\r
1687 the TCPv6 address and por number associated with the network adapter.\r
1688\r
1689 @param [in] pPort Address of an ::ESL_PORT structure.\r
1690\r
1691 @param [out] pAddress Network address to receive the remote system address\r
1692\r
1693**/\r
1694VOID\r
1695EslTcp6RemoteAddressGet (\r
1696 IN ESL_PORT * pPort,\r
1697 OUT struct sockaddr * pAddress\r
1698 )\r
1699{\r
1700 struct sockaddr_in6 * pRemoteAddress;\r
1701 ESL_TCP6_CONTEXT * pTcp6;\r
1702\r
1703 DBG_ENTER ( );\r
1704\r
1705 //\r
1706 // Return the remote address\r
1707 //\r
1708 pTcp6 = &pPort->Context.Tcp6;\r
1709 pRemoteAddress = (struct sockaddr_in6 *)pAddress;\r
1710 pRemoteAddress->sin6_family = AF_INET6;\r
1711 pRemoteAddress->sin6_port = SwapBytes16 ( pTcp6->ConfigData.AccessPoint.RemotePort );\r
1712 CopyMem ( &pRemoteAddress->sin6_addr,\r
1713 &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
1714 sizeof ( pRemoteAddress->sin6_addr ));\r
1715\r
1716 DBG_EXIT ( );\r
1717}\r
1718\r
1719\r
1720/**\r
1721 Set the remote address\r
1722\r
1723 This routine sets the remote address in the port.\r
1724\r
1725 This routine is called by ::EslSocketConnect to specify the\r
1726 remote network address.\r
1727\r
1728 @param [in] pPort Address of an ::ESL_PORT structure.\r
1729\r
1730 @param [in] pSockAddr Network address of the remote system.\r
1731\r
1732 @param [in] SockAddrLength Length in bytes of the network address.\r
1733\r
1734 @retval EFI_SUCCESS The operation was successful\r
1735\r
1736 **/\r
1737EFI_STATUS\r
1738EslTcp6RemoteAddressSet (\r
1739 IN ESL_PORT * pPort,\r
1740 IN CONST struct sockaddr * pSockAddr,\r
1741 IN socklen_t SockAddrLength\r
1742 )\r
1743{\r
1744 CONST struct sockaddr_in6 * pRemoteAddress;\r
1745 ESL_TCP6_CONTEXT * pTcp6;\r
1746 EFI_STATUS Status;\r
1747\r
1748 DBG_ENTER ( );\r
1749\r
1750 //\r
1751 // Set the remote address\r
1752 //\r
1753 pTcp6 = &pPort->Context.Tcp6;\r
1754 pRemoteAddress = (struct sockaddr_in6 *)pSockAddr;\r
1755 CopyMem ( &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr [ 0 ],\r
1756 &pRemoteAddress->sin6_addr.__u6_addr.__u6_addr8 [ 0 ],\r
1757 sizeof ( pRemoteAddress->sin6_addr.__u6_addr.__u6_addr8 ));\r
1758 pTcp6->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pRemoteAddress->sin6_port );\r
1759 Status = EFI_SUCCESS;\r
1760\r
1761//\r
1762// TODO: Fix the following check\r
1763//\r
1764/*\r
1765 if ( INADDR_BROADCAST == pRemoteAddress->sin6_addr.s_addr ) {\r
1766 DEBUG (( DEBUG_CONNECT,\r
1767 "ERROR - Invalid remote address\r\n" ));\r
1768 Status = EFI_INVALID_PARAMETER;\r
1769 pPort->pSocket->errno = EAFNOSUPPORT;\r
1770 }\r
1771*/\r
1772\r
1773 //\r
1774 // Return the operation status\r
1775 //\r
1776 DBG_EXIT_STATUS ( Status );\r
1777 return Status;\r
1778}\r
1779\r
1780\r
1781/**\r
1782 Process the receive completion\r
1783\r
1784 This routine queues the data in FIFO order in either the urgent\r
1785 or normal data queues depending upon the type of data received.\r
1786 See the \ref ReceiveEngine section.\r
1787\r
1788 This routine is called by the TCPv6 driver when some data is\r
1789 received.\r
1790\r
1791 Buffer the data that was just received.\r
1792\r
1793 @param [in] Event The receive completion event\r
1794\r
1795 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
1796\r
1797**/\r
1798VOID\r
1799EslTcp6RxComplete (\r
1800 IN EFI_EVENT Event,\r
1801 IN ESL_IO_MGMT * pIo\r
1802 )\r
1803{\r
1804 BOOLEAN bUrgent;\r
1805 size_t LengthInBytes;\r
1806 ESL_PACKET * pPacket;\r
1807 EFI_STATUS Status;\r
1808\r
1809 DBG_ENTER ( );\r
1810\r
1811 //\r
1812 // Get the operation status.\r
1813 //\r
1814 Status = pIo->Token.Tcp6Rx.CompletionToken.Status;\r
1815\r
1816 //\r
1817 // +--------------------+ +---------------------------+\r
1818 // | ESL_IO_MGMT | | ESL_PACKET |\r
1819 // | | | |\r
1820 // | +---------------+ +-----------------------+ |\r
1821 // | | Token | | EFI_Tcp6_RECEIVE_DATA | |\r
1822 // | | RxData --> | | |\r
1823 // | | | +-----------------------+---+\r
1824 // | | Event | | Data Buffer |\r
1825 // +----+---------------+ | |\r
1826 // | |\r
1827 // +---------------------------+\r
1828 //\r
1829 //\r
1830 // Duplicate the buffer address and length for use by the\r
1831 // buffer handling code in EslTcp6Receive. These fields are\r
1832 // used when a partial read is done of the data from the\r
1833 // packet.\r
1834 //\r
1835 pPacket = pIo->pPacket;\r
1836 pPacket->pBuffer = pPacket->Op.Tcp6Rx.RxData.FragmentTable[0].FragmentBuffer;\r
1837 LengthInBytes = pPacket->Op.Tcp6Rx.RxData.DataLength;\r
1838 pPacket->ValidBytes = LengthInBytes;\r
1839\r
1840 //\r
1841 // Get the data type so that it may be linked to the\r
1842 // correct receive buffer list on the ESL_SOCKET structure\r
1843 //\r
1844 bUrgent = pPacket->Op.Tcp6Rx.RxData.UrgentFlag;\r
1845\r
1846 //\r
1847 // Complete this request\r
1848 //\r
1849 EslSocketRxComplete ( pIo, Status, LengthInBytes, bUrgent );\r
1850 DBG_EXIT ( );\r
1851}\r
1852\r
1853\r
1854/**\r
1855 Start a receive operation\r
1856\r
1857 This routine posts a receive buffer to the TCPv6 driver.\r
1858 See the \ref ReceiveEngine section.\r
1859\r
1860 This support routine is called by EslSocketRxStart.\r
1861\r
1862 @param [in] pPort Address of an ::ESL_PORT structure.\r
1863 @param [in] pIo Address of an ::ESL_IO_MGMT structure.\r
1864\r
1865 **/\r
1866VOID\r
1867EslTcp6RxStart (\r
1868 IN ESL_PORT * pPort,\r
1869 IN ESL_IO_MGMT * pIo\r
1870 )\r
1871{\r
1872 ESL_PACKET * pPacket;\r
1873\r
1874 DBG_ENTER ( );\r
1875\r
1876 //\r
1877 // Initialize the buffer for receive\r
1878 //\r
1879 pPacket = pIo->pPacket;\r
1880 pIo->Token.Tcp6Rx.Packet.RxData = &pPacket->Op.Tcp6Rx.RxData;\r
1881 pPacket->Op.Tcp6Rx.RxData.DataLength = sizeof ( pPacket->Op.Tcp6Rx.Buffer );\r
1882 pPacket->Op.Tcp6Rx.RxData.FragmentCount = 1;\r
1883 pPacket->Op.Tcp6Rx.RxData.FragmentTable[0].FragmentLength = pPacket->Op.Tcp6Rx.RxData.DataLength;\r
1884 pPacket->Op.Tcp6Rx.RxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp6Rx.Buffer[0];\r
1885\r
1886 DBG_EXIT ( );\r
1887}\r
1888\r
1889\r
1890/**\r
1891 Determine if the socket is configured.\r
1892\r
1893 This routine uses the flag ESL_SOCKET::bConfigured to determine\r
1894 if the network layer's configuration routine has been called.\r
1895\r
1896 This routine is called by EslSocketIsConfigured to verify\r
1897 that the socket has been configured.\r
1898\r
1899 @param [in] pSocket Address of an ::ESL_SOCKET structure.\r
1900\r
1901 @retval EFI_SUCCESS - The port is connected\r
1902 @retval EFI_NOT_STARTED - The port is not connected\r
1903\r
1904 **/\r
1905 EFI_STATUS\r
1906 EslTcp6SocketIsConfigured (\r
1907 IN ESL_SOCKET * pSocket\r
1908 )\r
1909{\r
1910 EFI_STATUS Status;\r
1911\r
1912 DBG_ENTER ( );\r
1913\r
1914 //\r
1915 // Determine the socket configuration status\r
1916 //\r
1917 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;\r
1918\r
1919 //\r
1920 // Return the port connected state.\r
1921 //\r
1922 DBG_EXIT_STATUS ( Status );\r
1923 return Status;\r
1924}\r
1925\r
1926\r
1927/**\r
1928 Buffer data for transmission over a network connection.\r
1929\r
1930 This routine buffers data for the transmit engine in one of two\r
1931 queues, one for urgent (out-of-band) data and the other for normal\r
1932 data. The urgent data is provided to TCP as soon as it is available,\r
1933 allowing the TCP layer to schedule transmission of the urgent data\r
1934 between packets of normal data.\r
1935\r
1936 This routine is called by ::EslSocketTransmit to buffer\r
1937 data for transmission. When the \ref TransmitEngine has resources,\r
1938 this routine will start the transmission of the next buffer on\r
1939 the network connection.\r
1940\r
1941 Transmission errors are returned during the next transmission or\r
1942 during the close operation. Only buffering errors are returned\r
1943 during the current transmission attempt.\r
1944\r
1945 @param [in] pSocket Address of an ::ESL_SOCKET structure\r
1946 \r
1947 @param [in] Flags Message control flags\r
1948 \r
1949 @param [in] BufferLength Length of the the buffer\r
1950 \r
1951 @param [in] pBuffer Address of a buffer to receive the data.\r
1952 \r
1953 @param [in] pDataLength Number of received data bytes in the buffer.\r
1954\r
1955 @param [in] pAddress Network address of the remote system address\r
1956\r
1957 @param [in] AddressLength Length of the remote network address structure\r
1958\r
1959 @retval EFI_SUCCESS - Socket data successfully buffered\r
1960\r
1961 **/\r
1962EFI_STATUS\r
1963EslTcp6TxBuffer (\r
1964 IN ESL_SOCKET * pSocket,\r
1965 IN int Flags,\r
1966 IN size_t BufferLength,\r
1967 IN CONST UINT8 * pBuffer,\r
1968 OUT size_t * pDataLength,\r
1969 IN const struct sockaddr * pAddress,\r
1970 IN socklen_t AddressLength\r
1971 )\r
1972{\r
1973 BOOLEAN bUrgent;\r
1974 BOOLEAN bUrgentQueue;\r
1975 ESL_PACKET * pPacket;\r
1976 ESL_IO_MGMT ** ppActive;\r
1977 ESL_IO_MGMT ** ppFree;\r
1978 ESL_PORT * pPort;\r
1979 ESL_PACKET ** ppQueueHead;\r
1980 ESL_PACKET ** ppQueueTail;\r
1981 ESL_PACKET * pPreviousPacket;\r
1982 ESL_TCP6_CONTEXT * pTcp6;\r
1983 size_t * pTxBytes;\r
1984 EFI_TCP6_TRANSMIT_DATA * pTxData;\r
1985 EFI_STATUS Status;\r
1986 EFI_TPL TplPrevious;\r
1987\r
1988 DBG_ENTER ( );\r
1989\r
1990 //\r
1991 // Assume failure\r
1992 //\r
1993 Status = EFI_UNSUPPORTED;\r
1994 pSocket->errno = ENOTCONN;\r
1995 *pDataLength = 0;\r
1996\r
1997 //\r
1998 // Verify that the socket is connected\r
1999 //\r
2000 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
2001 //\r
2002 // Locate the port\r
2003 //\r
2004 pPort = pSocket->pPortList;\r
2005 if ( NULL != pPort ) {\r
2006 //\r
2007 // Determine the queue head\r
2008 //\r
2009 pTcp6 = &pPort->Context.Tcp6;\r
2010 bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));\r
2011 bUrgentQueue = bUrgent\r
2012 && ( !pSocket->bOobInLine )\r
2013 && pSocket->pApi->bOobSupported;\r
2014 if ( bUrgentQueue ) {\r
2015 ppQueueHead = &pSocket->pTxOobPacketListHead;\r
2016 ppQueueTail = &pSocket->pTxOobPacketListTail;\r
2017 ppActive = &pPort->pTxOobActive;\r
2018 ppFree = &pPort->pTxOobFree;\r
2019 pTxBytes = &pSocket->TxOobBytes;\r
2020 }\r
2021 else {\r
2022 ppQueueHead = &pSocket->pTxPacketListHead;\r
2023 ppQueueTail = &pSocket->pTxPacketListTail;\r
2024 ppActive = &pPort->pTxActive;\r
2025 ppFree = &pPort->pTxFree;\r
2026 pTxBytes = &pSocket->TxBytes;\r
2027 }\r
2028\r
2029 //\r
2030 // Verify that there is enough room to buffer another\r
2031 // transmit operation\r
2032 //\r
2033 if ( pSocket->MaxTxBuf > *pTxBytes ) {\r
2034 if ( pPort->bTxFlowControl ) {\r
2035 DEBUG (( DEBUG_TX,\r
2036 "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",\r
2037 pPort,\r
2038 pSocket->MaxTxBuf,\r
2039 *pTxBytes ));\r
2040 pPort->bTxFlowControl = FALSE;\r
2041 }\r
2042\r
2043 //\r
2044 // Attempt to allocate the packet\r
2045 //\r
2046 Status = EslSocketPacketAllocate ( &pPacket,\r
2047 sizeof ( pPacket->Op.Tcp6Tx )\r
2048 - sizeof ( pPacket->Op.Tcp6Tx.Buffer )\r
2049 + BufferLength,\r
2050 0,\r
2051 DEBUG_TX );\r
2052 if ( !EFI_ERROR ( Status )) {\r
2053 //\r
2054 // Initialize the transmit operation\r
2055 //\r
2056 pTxData = &pPacket->Op.Tcp6Tx.TxData;\r
2057 pTxData->Push = TRUE || bUrgent;\r
2058 pTxData->Urgent = bUrgent;\r
2059 pTxData->DataLength = (UINT32) BufferLength;\r
2060 pTxData->FragmentCount = 1;\r
2061 pTxData->FragmentTable[0].FragmentLength = (UINT32) BufferLength;\r
2062 pTxData->FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp6Tx.Buffer[0];\r
2063\r
2064 //\r
2065 // Copy the data into the buffer\r
2066 //\r
2067 CopyMem ( &pPacket->Op.Tcp6Tx.Buffer[0],\r
2068 pBuffer,\r
2069 BufferLength );\r
2070\r
2071 //\r
2072 // Synchronize with the socket layer\r
2073 //\r
2074 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2075\r
2076 //\r
2077 // Stop transmission after an error\r
2078 //\r
2079 if ( !EFI_ERROR ( pSocket->TxError )) {\r
2080 //\r
2081 // Display the request\r
2082 //\r
2083 DEBUG (( DEBUG_TX,\r
2084 "Send %d %s bytes from 0x%08x\r\n",\r
2085 BufferLength,\r
2086 bUrgent ? L"urgent" : L"normal",\r
2087 pBuffer ));\r
2088\r
2089 //\r
2090 // Queue the data for transmission\r
2091 //\r
2092 pPacket->pNext = NULL;\r
2093 pPreviousPacket = *ppQueueTail;\r
2094 if ( NULL == pPreviousPacket ) {\r
2095 *ppQueueHead = pPacket;\r
2096 }\r
2097 else {\r
2098 pPreviousPacket->pNext = pPacket;\r
2099 }\r
2100 *ppQueueTail = pPacket;\r
2101 DEBUG (( DEBUG_TX,\r
2102 "0x%08x: Packet on %s transmit list\r\n",\r
2103 pPacket,\r
2104 bUrgentQueue ? L"urgent" : L"normal" ));\r
2105\r
2106 //\r
2107 // Account for the buffered data\r
2108 //\r
2109 *pTxBytes += BufferLength;\r
2110 *pDataLength = BufferLength;\r
2111\r
2112 //\r
2113 // Start the transmit engine if it is idle\r
2114 //\r
2115 if ( NULL != *ppFree ) {\r
2116 EslSocketTxStart ( pPort,\r
2117 ppQueueHead,\r
2118 ppQueueTail,\r
2119 ppActive,\r
2120 ppFree );\r
2121 }\r
2122 }\r
2123 else {\r
2124 //\r
2125 // Previous transmit error\r
2126 // Stop transmission\r
2127 //\r
2128 Status = pSocket->TxError;\r
2129 pSocket->errno = EIO;\r
2130\r
2131 //\r
2132 // Free the packet\r
2133 //\r
2134 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
2135 }\r
2136\r
2137 //\r
2138 // Release the socket layer synchronization\r
2139 //\r
2140 RESTORE_TPL ( TplPrevious );\r
2141 }\r
2142 else {\r
2143 //\r
2144 // Packet allocation failed\r
2145 //\r
2146 pSocket->errno = ENOMEM;\r
2147 }\r
2148 }\r
2149 else {\r
2150 if ( !pPort->bTxFlowControl ) {\r
2151 DEBUG (( DEBUG_TX,\r
2152 "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",\r
2153 pPort,\r
2154 pSocket->MaxTxBuf,\r
2155 *pTxBytes ));\r
2156 pPort->bTxFlowControl = TRUE;\r
2157 }\r
2158 //\r
2159 // Not enough buffer space available\r
2160 //\r
2161 pSocket->errno = EAGAIN;\r
2162 Status = EFI_NOT_READY;\r
2163 }\r
2164 }\r
2165 }\r
2166\r
2167 //\r
2168 // Return the operation status\r
2169 //\r
2170 DBG_EXIT_STATUS ( Status );\r
2171 return Status;\r
2172}\r
2173\r
2174\r
2175/**\r
2176 Process the normal data transmit completion\r
2177\r
2178 This routine use ::EslSocketTxComplete to perform the transmit\r
2179 completion processing for normal data.\r
2180\r
2181 This routine is called by the TCPv6 network layer when a\r
2182 normal data transmit request completes.\r
2183\r
2184 @param [in] Event The normal transmit completion event\r
2185\r
2186 @param [in] pIo The ESL_IO_MGMT structure address\r
2187\r
2188**/\r
2189VOID\r
2190EslTcp6TxComplete (\r
2191 IN EFI_EVENT Event,\r
2192 IN ESL_IO_MGMT * pIo\r
2193 )\r
2194{\r
2195 UINT32 LengthInBytes;\r
2196 ESL_PACKET * pPacket;\r
2197 ESL_PORT * pPort;\r
2198 ESL_SOCKET * pSocket;\r
2199 EFI_STATUS Status;\r
2200 \r
2201 DBG_ENTER ( );\r
2202\r
2203 //\r
2204 // Locate the active transmit packet\r
2205 //\r
2206 pPacket = pIo->pPacket;\r
2207 pPort = pIo->pPort;\r
2208 pSocket = pPort->pSocket;\r
2209\r
2210 //\r
2211 // Get the transmit length and status\r
2212 //\r
2213 LengthInBytes = pPacket->Op.Tcp6Tx.TxData.DataLength;\r
2214 pSocket->TxBytes -= LengthInBytes;\r
2215 Status = pIo->Token.Tcp6Tx.CompletionToken.Status;\r
2216\r
2217 //\r
2218 // Complete the transmit operation\r
2219 //\r
2220 EslSocketTxComplete ( pIo,\r
2221 LengthInBytes,\r
2222 Status,\r
2223 "Normal ",\r
2224 &pSocket->pTxPacketListHead,\r
2225 &pSocket->pTxPacketListTail,\r
2226 &pPort->pTxActive,\r
2227 &pPort->pTxFree );\r
2228 DBG_EXIT ( );\r
2229}\r
2230\r
2231\r
2232/**\r
2233 Process the urgent data transmit completion\r
2234\r
2235 This routine use ::EslSocketTxComplete to perform the transmit\r
2236 completion processing for urgent data.\r
2237\r
2238 This routine is called by the TCPv6 network layer when a\r
2239 urgent data transmit request completes.\r
2240\r
2241 @param [in] Event The urgent transmit completion event\r
2242\r
2243 @param [in] pIo The ESL_IO_MGMT structure address\r
2244\r
2245**/\r
2246VOID\r
2247EslTcp6TxOobComplete (\r
2248 IN EFI_EVENT Event,\r
2249 IN ESL_IO_MGMT * pIo\r
2250 )\r
2251{\r
2252 UINT32 LengthInBytes;\r
2253 ESL_PACKET * pPacket;\r
2254 ESL_PORT * pPort;\r
2255 ESL_SOCKET * pSocket;\r
2256 EFI_STATUS Status;\r
2257\r
2258 DBG_ENTER ( );\r
2259\r
2260 //\r
2261 // Locate the active transmit packet\r
2262 //\r
2263 pPacket = pIo->pPacket;\r
2264 pPort = pIo->pPort;\r
2265 pSocket = pPort->pSocket;\r
2266\r
2267 //\r
2268 // Get the transmit length and status\r
2269 //\r
2270 LengthInBytes = pPacket->Op.Tcp6Tx.TxData.DataLength;\r
2271 pSocket->TxOobBytes -= LengthInBytes;\r
2272 Status = pIo->Token.Tcp6Tx.CompletionToken.Status;\r
2273\r
2274 //\r
2275 // Complete the transmit operation\r
2276 //\r
2277 EslSocketTxComplete ( pIo,\r
2278 LengthInBytes,\r
2279 Status,\r
2280 "Urgent ",\r
2281 &pSocket->pTxOobPacketListHead,\r
2282 &pSocket->pTxOobPacketListTail,\r
2283 &pPort->pTxOobActive,\r
2284 &pPort->pTxOobFree );\r
2285 DBG_EXIT ( );\r
2286}\r
2287\r
2288\r
2289/**\r
2290 Interface between the socket layer and the network specific\r
2291 code that supports SOCK_STREAM and SOCK_SEQPACKET sockets\r
2292 over TCPv6.\r
2293**/\r
2294CONST ESL_PROTOCOL_API cEslTcp6Api = {\r
2295 "TCPv6",\r
2296 IPPROTO_TCP,\r
2297 OFFSET_OF ( ESL_PORT, Context.Tcp6.ConfigData ),\r
2298 OFFSET_OF ( ESL_LAYER, pTcp6List ),\r
2299 sizeof ( struct sockaddr_in6 ),\r
2300 sizeof ( struct sockaddr_in6 ),\r
2301 AF_INET6,\r
2302 sizeof (((ESL_PACKET *)0 )->Op.Tcp6Rx ),\r
2303 OFFSET_OF ( ESL_PACKET, Op.Tcp6Rx.Buffer ) - OFFSET_OF ( ESL_PACKET, Op ),\r
2304 OFFSET_OF ( ESL_IO_MGMT, Token.Tcp6Rx.Packet.RxData ),\r
2305 TRUE,\r
2306 EADDRINUSE,\r
2307 EslTcp6Accept,\r
2308 EslTcp6ConnectPoll,\r
2309 EslTcp6ConnectStart,\r
2310 EslTcp6SocketIsConfigured,\r
2311 EslTcp6LocalAddressGet,\r
2312 EslTcp6LocalAddressSet,\r
2313 EslTcp6Listen,\r
2314 NULL, // OptionGet\r
2315 NULL, // OptionSet\r
2316 EslTcp6PacketFree,\r
2317 EslTcp6PortAllocate,\r
2318 EslTcp6PortClose,\r
2319 EslTcp6PortCloseOp,\r
2320 FALSE,\r
2321 EslTcp6Receive,\r
2322 EslTcp6RemoteAddressGet,\r
2323 EslTcp6RemoteAddressSet,\r
2324 EslTcp6RxComplete,\r
2325 EslTcp6RxStart,\r
2326 EslTcp6TxBuffer,\r
2327 EslTcp6TxComplete,\r
2328 EslTcp6TxOobComplete\r
2329};\r