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