]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - StdLib/EfiSocketLib/Tcp4.c
Better handle transmit errors
[mirror_edk2.git] / StdLib / EfiSocketLib / Tcp4.c
... / ...
CommitLineData
1/** @file\r
2 Implement the TCP4 driver support for the socket layer.\r
3\r
4 Copyright (c) 2011, Intel Corporation\r
5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "Socket.h"\r
16\r
17\r
18/**\r
19 Accept a network connection.\r
20\r
21 The SocketAccept routine waits for a network connection to the socket.\r
22 It is able to return the remote network address to the caller if\r
23 requested.\r
24\r
25 @param [in] pSocket Address of the socket structure.\r
26\r
27 @param [in] pSockAddr Address of a buffer to receive the remote\r
28 network address.\r
29\r
30 @param [in, out] pSockAddrLength Length in bytes of the address buffer.\r
31 On output specifies the length of the\r
32 remote network address.\r
33\r
34 @retval EFI_SUCCESS Remote address is available\r
35 @retval Others Remote address not available\r
36\r
37 **/\r
38EFI_STATUS\r
39EslTcpAccept4 (\r
40 IN DT_SOCKET * pSocket,\r
41 IN struct sockaddr * pSockAddr,\r
42 IN OUT socklen_t * pSockAddrLength\r
43 )\r
44{\r
45 DT_PORT * pPort;\r
46 struct sockaddr_in * pRemoteAddress;\r
47 DT_TCP4_CONTEXT * pTcp4;\r
48 UINT32 RemoteAddress;\r
49 EFI_STATUS Status;\r
50\r
51 DBG_ENTER ( );\r
52\r
53 //\r
54 // Validate the socket length\r
55 //\r
56 pRemoteAddress = (struct sockaddr_in *) pSockAddr;\r
57 if (( NULL == pSockAddrLength )\r
58 || ( sizeof ( *pRemoteAddress ) > *pSockAddrLength )) {\r
59 //\r
60 // Invalid socket address\r
61 //\r
62 Status = EFI_INVALID_PARAMETER;\r
63 pSocket->errno = EINVAL;\r
64 DEBUG (( DEBUG_ACCEPT,\r
65 "ERROR - Invalid address length\r\n" ));\r
66 }\r
67 else {\r
68 //\r
69 // Assume success\r
70 //\r
71 Status = EFI_SUCCESS;\r
72\r
73 //\r
74 // Locate the address context\r
75 //\r
76 pPort = pSocket->pPortList;\r
77 pTcp4 = &pPort->Context.Tcp4;\r
78\r
79 //\r
80 // Fill-in the remote address structure\r
81 //\r
82 ZeroMem ( pRemoteAddress, sizeof ( *pRemoteAddress ));\r
83 pRemoteAddress->sin_len = sizeof ( *pRemoteAddress );\r
84 pRemoteAddress->sin_family = AF_INET;\r
85 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );\r
86 RemoteAddress = pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3];\r
87 RemoteAddress <<= 8;\r
88 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2];\r
89 RemoteAddress <<= 8;\r
90 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1];\r
91 RemoteAddress <<= 8;\r
92 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0];\r
93 pRemoteAddress->sin_addr.s_addr = RemoteAddress;\r
94 }\r
95\r
96 //\r
97 // Return the operation status\r
98 //\r
99 DBG_EXIT_STATUS ( Status );\r
100 return Status;\r
101}\r
102\r
103\r
104/**\r
105 Bind a name to a socket.\r
106\r
107 The ::TcpBind4 routine connects a name to a TCP4 stack on the local machine.\r
108\r
109 @param [in] pSocket Address of the socket structure.\r
110\r
111 @param [in] pSockAddr Address of a sockaddr structure that contains the\r
112 connection point on the local machine. An IPv4 address\r
113 of INADDR_ANY specifies that the connection is made to\r
114 all of the network stacks on the platform. Specifying a\r
115 specific IPv4 address restricts the connection to the\r
116 network stack supporting that address. Specifying zero\r
117 for the port causes the network layer to assign a port\r
118 number from the dynamic range. Specifying a specific\r
119 port number causes the network layer to use that port.\r
120\r
121 @param [in] SockAddrLen Specifies the length in bytes of the sockaddr structure.\r
122\r
123 @retval EFI_SUCCESS - Socket successfully created\r
124\r
125 **/\r
126EFI_STATUS\r
127EslTcpBind4 (\r
128 IN DT_SOCKET * pSocket,\r
129 IN const struct sockaddr * pSockAddr,\r
130 IN socklen_t SockAddrLength\r
131 )\r
132{\r
133 EFI_HANDLE ChildHandle;\r
134 DT_LAYER * pLayer;\r
135 DT_PORT * pPort;\r
136 DT_SERVICE * pService;\r
137 CONST struct sockaddr_in * pIp4Address;\r
138 EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service;\r
139 EFI_STATUS Status;\r
140 EFI_STATUS TempStatus;\r
141\r
142 DBG_ENTER ( );\r
143\r
144 //\r
145 // Verify the socket layer synchronization\r
146 //\r
147 VERIFY_TPL ( TPL_SOCKETS );\r
148\r
149 //\r
150 // Assume success\r
151 //\r
152 pSocket->errno = 0;\r
153 Status = EFI_SUCCESS;\r
154\r
155 //\r
156 // Validate the address length\r
157 //\r
158 pIp4Address = (CONST struct sockaddr_in *) pSockAddr;\r
159 if ( SockAddrLength >= ( sizeof ( *pIp4Address )\r
160 - sizeof ( pIp4Address->sin_zero ))) {\r
161\r
162 //\r
163 // Walk the list of services\r
164 //\r
165 pLayer = &mEslLayer;\r
166 pService = pLayer->pTcp4List;\r
167 while ( NULL != pService ) {\r
168 //\r
169 // Create the TCP port\r
170 //\r
171 pTcp4Service = pService->pInterface;\r
172 ChildHandle = NULL;\r
173 Status = pTcp4Service->CreateChild ( pTcp4Service,\r
174 &ChildHandle );\r
175 if ( !EFI_ERROR ( Status )) {\r
176 DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
177 "0x%08x: Tcp4 port handle created\r\n",\r
178 ChildHandle ));\r
179\r
180 //\r
181 // Open the port\r
182 //\r
183 Status = EslTcpPortAllocate4 ( pSocket,\r
184 pService,\r
185 ChildHandle,\r
186 (UINT8 *) &pIp4Address->sin_addr.s_addr,\r
187 SwapBytes16 ( pIp4Address->sin_port ),\r
188 DEBUG_BIND,\r
189 &pPort );\r
190 }\r
191 else {\r
192 DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
193 "ERROR - Failed to open Tcp4 port handle, Status: %r\r\n",\r
194 Status ));\r
195 ChildHandle = NULL;\r
196 }\r
197\r
198 //\r
199 // Close the port if necessary\r
200 //\r
201 if (( EFI_ERROR ( Status )) && ( NULL != ChildHandle )) {\r
202 TempStatus = pTcp4Service->DestroyChild ( pTcp4Service,\r
203 ChildHandle );\r
204 if ( !EFI_ERROR ( TempStatus )) {\r
205 DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
206 "0x%08x: Tcp4 port handle destroyed\r\n",\r
207 ChildHandle ));\r
208 }\r
209 else {\r
210 DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,\r
211 "ERROR - Failed to destroy the Tcp4 port handle 0x%08x, Status: %r\r\n",\r
212 ChildHandle,\r
213 TempStatus ));\r
214 ASSERT ( EFI_SUCCESS == TempStatus );\r
215 }\r
216 }\r
217\r
218 //\r
219 // Set the next service\r
220 //\r
221 pService = pService->pNext;\r
222 }\r
223\r
224 //\r
225 // Verify that at least one network connection was found\r
226 //\r
227 if ( NULL == pSocket->pPortList ) {\r
228 DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,\r
229 "Socket address %d.%d.%d.%d (0x%08x) is not available!\r\n",\r
230 ( pIp4Address->sin_addr.s_addr >> 24 ) & 0xff,\r
231 ( pIp4Address->sin_addr.s_addr >> 16 ) & 0xff,\r
232 ( pIp4Address->sin_addr.s_addr >> 8 ) & 0xff,\r
233 pIp4Address->sin_addr.s_addr & 0xff,\r
234 pIp4Address->sin_addr.s_addr ));\r
235 pSocket->errno = EADDRNOTAVAIL;\r
236 Status = EFI_INVALID_PARAMETER;\r
237 }\r
238 }\r
239 else {\r
240 DEBUG (( DEBUG_BIND,\r
241 "ERROR - Invalid TCP4 address length: %d\r\n",\r
242 SockAddrLength ));\r
243 Status = EFI_INVALID_PARAMETER;\r
244 pSocket->errno = EINVAL;\r
245 }\r
246\r
247 //\r
248 // Return the operation status\r
249 //\r
250 DBG_EXIT_STATUS ( Status );\r
251 return Status;\r
252}\r
253\r
254\r
255/**\r
256 Attempt to connect to a remote TCP port\r
257\r
258 @param [in] pSocket Address of the socket structure.\r
259\r
260 @retval EFI_SUCCESS The connection was successfully established.\r
261 @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
262 @retval Others The connection attempt failed.\r
263\r
264 **/\r
265EFI_STATUS\r
266EslTcpConnectAttempt4 (\r
267 IN DT_SOCKET * pSocket\r
268 )\r
269{\r
270 DT_PORT * pPort;\r
271 DT_TCP4_CONTEXT * pTcp4;\r
272 EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
273 EFI_STATUS Status;\r
274\r
275 DBG_ENTER ( );\r
276 \r
277 //\r
278 // Determine if any more local adapters are available\r
279 //\r
280 pPort = pSocket->pPortList;\r
281 if ( NULL != pPort ) {\r
282 //\r
283 // Configure the port\r
284 //\r
285 pTcp4 = &pPort->Context.Tcp4;\r
286 pTcp4->ConfigData.AccessPoint.ActiveFlag = TRUE;\r
287 pTcp4->ConfigData.TimeToLive = 255;\r
288 pTcp4Protocol = pTcp4->pProtocol;\r
289 Status = pTcp4Protocol->Configure ( pTcp4Protocol,\r
290 &pTcp4->ConfigData );\r
291 if ( EFI_ERROR ( Status )) {\r
292 DEBUG (( DEBUG_CONNECT,\r
293 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",\r
294 Status ));\r
295 switch ( Status ) {\r
296 case EFI_ACCESS_DENIED:\r
297 pSocket->errno = EACCES;\r
298 break;\r
299 \r
300 default:\r
301 case EFI_DEVICE_ERROR:\r
302 pSocket->errno = EIO;\r
303 break;\r
304 \r
305 case EFI_INVALID_PARAMETER:\r
306 pSocket->errno = EADDRNOTAVAIL;\r
307 break;\r
308 \r
309 case EFI_NO_MAPPING:\r
310 pSocket->errno = EAFNOSUPPORT;\r
311 break;\r
312 \r
313 case EFI_OUT_OF_RESOURCES:\r
314 pSocket->errno = ENOBUFS;\r
315 break;\r
316 \r
317 case EFI_UNSUPPORTED:\r
318 pSocket->errno = EOPNOTSUPP;\r
319 break;\r
320 }\r
321 }\r
322 else {\r
323 DEBUG (( DEBUG_CONNECT,\r
324 "0x%08x: Port configured\r\n",\r
325 pPort ));\r
326 pTcp4->bConfigured = TRUE;\r
327\r
328 //\r
329 // Attempt the connection to the remote system\r
330 //\r
331 Status = pTcp4Protocol->Connect ( pTcp4Protocol,\r
332 &pTcp4->ConnectToken );\r
333 if ( !EFI_ERROR ( Status )) {\r
334 //\r
335 // Connection in progress\r
336 //\r
337 pSocket->errno = EINPROGRESS;\r
338 Status = EFI_NOT_READY;\r
339 DEBUG (( DEBUG_CONNECT,\r
340 "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",\r
341 pPort,\r
342 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
343 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],\r
344 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],\r
345 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],\r
346 pTcp4->ConfigData.AccessPoint.RemotePort ));\r
347 }\r
348 else {\r
349 //\r
350 // Connection error\r
351 //\r
352 pSocket->errno = EINVAL;\r
353 DEBUG (( DEBUG_CONNECT,\r
354 "ERROR - Port 0x%08x not connected, Status: %r\r\n",\r
355 pPort,\r
356 Status ));\r
357 }\r
358 }\r
359 }\r
360 else {\r
361 //\r
362 // No more local adapters available\r
363 //\r
364 pSocket->errno = ENETUNREACH;\r
365 Status = EFI_NO_RESPONSE;\r
366 }\r
367\r
368 //\r
369 // Return the operation status\r
370 //\r
371 DBG_EXIT_STATUS ( Status );\r
372 return Status;\r
373}\r
374\r
375\r
376/**\r
377 Process the remote connection attempt\r
378\r
379 A connection attempt to a remote system has just completed when\r
380 this routine is invoked. Release the port in the case of an\r
381 error and start a connection attempt on the next port. If the\r
382 connection attempt was successful, then release all of the other\r
383 ports.\r
384\r
385 @param Event The connect completion event\r
386\r
387 @param pPort The DT_PORT structure address\r
388\r
389**/\r
390VOID\r
391EslTcpConnectComplete4 (\r
392 IN EFI_EVENT Event,\r
393 IN DT_PORT * pPort\r
394 )\r
395{\r
396 BOOLEAN bRemoveFirstPort;\r
397 BOOLEAN bRemovePorts;\r
398 DT_PORT * pNextPort;\r
399 DT_SOCKET * pSocket;\r
400 DT_TCP4_CONTEXT * pTcp4;\r
401 EFI_STATUS Status;\r
402\r
403 DBG_ENTER ( );\r
404\r
405 //\r
406 // Locate the TCP context\r
407 //\r
408 pSocket = pPort->pSocket;\r
409 pTcp4 = &pPort->Context.Tcp4;\r
410\r
411 //\r
412 // Get the connection status\r
413 //\r
414 bRemoveFirstPort = FALSE;\r
415 bRemovePorts = FALSE;\r
416 Status = pTcp4->ConnectToken.CompletionToken.Status;\r
417 pSocket->ConnectStatus = Status;\r
418 if ( !EFI_ERROR ( Status )) {\r
419 //\r
420 // The connection was successful\r
421 //\r
422 DEBUG (( DEBUG_CONNECT,\r
423 "0x%08x: Port connected to %d.%d.%d.%d:%d\r\n",\r
424 pPort,\r
425 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [0],\r
426 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [1],\r
427 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [2],\r
428 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [3],\r
429 pTcp4->ConfigData.AccessPoint.RemotePort ));\r
430\r
431 //\r
432 // Remove the rest of the ports\r
433 //\r
434 bRemovePorts = TRUE;\r
435 }\r
436 else {\r
437 //\r
438 // The connection failed\r
439 //\r
440 DEBUG (( DEBUG_CONNECT,\r
441 "0x%08x: Port connection to %d.%d.%d.%d:%d failed, Status: %r\r\n",\r
442 pPort,\r
443 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [0],\r
444 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [1],\r
445 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [2],\r
446 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [3],\r
447 pTcp4->ConfigData.AccessPoint.RemotePort,\r
448 Status ));\r
449\r
450 //\r
451 // Close the current port\r
452 //\r
453 Status = EslTcpPortClose4 ( pPort );\r
454 if ( !EFI_ERROR ( Status )) {\r
455 DEBUG (( DEBUG_CONNECT,\r
456 "0x%08x: Port closed\r\n",\r
457 pPort ));\r
458 }\r
459 else {\r
460 DEBUG (( DEBUG_CONNECT,\r
461 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",\r
462 pPort,\r
463 Status ));\r
464 }\r
465\r
466 //\r
467 // Try to connect using the next port\r
468 //\r
469 Status = EslTcpConnectAttempt4 ( pSocket );\r
470 if ( EFI_NOT_READY != Status ) {\r
471 pSocket->ConnectStatus = Status;\r
472 bRemoveFirstPort = TRUE;\r
473 }\r
474 }\r
475\r
476 //\r
477 // Remove the ports if necessary\r
478 //\r
479 if ( bRemoveFirstPort || bRemovePorts ) {\r
480 //\r
481 // Remove the first port if necessary\r
482 //\r
483 pPort = pSocket->pPortList;\r
484 if (( !bRemoveFirstPort ) && ( NULL != pPort )) {\r
485 pPort = pPort->pLinkSocket;\r
486 }\r
487\r
488 //\r
489 // Remove the rest of the list\r
490 //\r
491 while ( NULL != pPort ) {\r
492 pNextPort = pPort->pLinkSocket;\r
493 EslTcpPortClose4 ( pPort );\r
494 if ( !EFI_ERROR ( Status )) {\r
495 DEBUG (( DEBUG_CONNECT,\r
496 "0x%08x: Port closed\r\n",\r
497 pPort ));\r
498 }\r
499 else {\r
500 DEBUG (( DEBUG_CONNECT,\r
501 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",\r
502 pPort,\r
503 Status ));\r
504 }\r
505 pPort = pNextPort;\r
506 }\r
507\r
508 //\r
509 // Notify the poll routine\r
510 //\r
511 pSocket->bConnected = TRUE;\r
512 }\r
513\r
514 DBG_EXIT ( );\r
515}\r
516\r
517\r
518/**\r
519 Poll for completion of the connection attempt.\r
520\r
521 The ::TcpConnectPoll4 routine determines when the connection\r
522 attempt transitions from being in process to being complete.\r
523\r
524 @param [in] pSocket Address of the socket structure.\r
525\r
526 @retval EFI_SUCCESS The connection was successfully established.\r
527 @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
528 @retval Others The connection attempt failed.\r
529\r
530 **/\r
531EFI_STATUS\r
532EslTcpConnectPoll4 (\r
533 IN DT_SOCKET * pSocket\r
534 )\r
535{\r
536 EFI_STATUS Status;\r
537\r
538 DBG_ENTER ( );\r
539\r
540 //\r
541 // Determine if the connection is complete\r
542 //\r
543 if ( !pSocket->bConnected ) {\r
544 //\r
545 // Not connected\r
546 //\r
547 pSocket->errno = EAGAIN;\r
548 Status = EFI_NOT_READY;\r
549 }\r
550 else {\r
551 //\r
552 // The connection processing is complete\r
553 //\r
554 pSocket->bConnected = FALSE;\r
555\r
556 //\r
557 // Translate the connection status\r
558 //\r
559 Status = pSocket->ConnectStatus;\r
560 switch ( Status ) {\r
561 default:\r
562 case EFI_DEVICE_ERROR:\r
563 pSocket->errno = EIO;\r
564 break;\r
565\r
566 case EFI_ABORTED:\r
567 pSocket->errno = ECONNREFUSED;\r
568 break;\r
569\r
570 case EFI_INVALID_PARAMETER:\r
571 pSocket->errno = EINVAL;\r
572 break;\r
573\r
574 case EFI_NO_MAPPING:\r
575 case EFI_NO_RESPONSE:\r
576 pSocket->errno = EHOSTUNREACH;\r
577 break;\r
578\r
579 case EFI_NO_MEDIA:\r
580 pSocket->errno = ENETDOWN;\r
581 break;\r
582\r
583 case EFI_OUT_OF_RESOURCES:\r
584 pSocket->errno = ENOMEM;\r
585 break;\r
586\r
587 case EFI_SUCCESS:\r
588 pSocket->errno = 0;\r
589 pSocket->bConfigured = TRUE;\r
590 break;\r
591\r
592 case EFI_TIMEOUT:\r
593 pSocket->errno = ETIMEDOUT;\r
594 break;\r
595\r
596 case EFI_UNSUPPORTED:\r
597 pSocket->errno = ENOTSUP;\r
598 break;\r
599\r
600 case 0x80000069:\r
601 pSocket->errno = ECONNRESET;\r
602 break;\r
603 }\r
604 }\r
605\r
606 //\r
607 // Return the initialization status\r
608 //\r
609 DBG_EXIT_STATUS ( Status );\r
610 return Status;\r
611}\r
612\r
613\r
614/**\r
615 Connect to a remote system via the network.\r
616\r
617 The ::TcpConnectStart4= routine starts the connection processing\r
618 for a TCP4 port.\r
619\r
620 @param [in] pSocket Address of the socket structure.\r
621\r
622 @param [in] pSockAddr Network address of the remote system.\r
623 \r
624 @param [in] SockAddrLength Length in bytes of the network address.\r
625 \r
626 @retval EFI_SUCCESS The connection was successfully established.\r
627 @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
628 @retval Others The connection attempt failed.\r
629\r
630 **/\r
631EFI_STATUS\r
632EslTcpConnectStart4 (\r
633 IN DT_SOCKET * pSocket,\r
634 IN const struct sockaddr * pSockAddr,\r
635 IN socklen_t SockAddrLength\r
636 )\r
637{\r
638 struct sockaddr_in LocalAddress;\r
639 DT_PORT * pPort;\r
640 DT_TCP4_CONTEXT * pTcp4;\r
641 CONST struct sockaddr_in * pIp4Address;\r
642 EFI_STATUS Status;\r
643\r
644 DBG_ENTER ( );\r
645\r
646 //\r
647 // Validate the address length\r
648 //\r
649 Status = EFI_SUCCESS;\r
650 pIp4Address = (CONST struct sockaddr_in *) pSockAddr;\r
651 if ( SockAddrLength >= ( sizeof ( *pIp4Address )\r
652 - sizeof ( pIp4Address->sin_zero ))) {\r
653 //\r
654 // Determine if BIND was already called\r
655 //\r
656 if ( NULL == pSocket->pPortList ) {\r
657 //\r
658 // Allow any local port\r
659 //\r
660 ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));\r
661 LocalAddress.sin_len = sizeof ( LocalAddress );\r
662 LocalAddress.sin_family = AF_INET;\r
663 Status = EslSocketBind ( &pSocket->SocketProtocol,\r
664 (struct sockaddr *)&LocalAddress,\r
665 LocalAddress.sin_len,\r
666 &pSocket->errno );\r
667 }\r
668 if ( NULL != pSocket->pPortList ) {\r
669 //\r
670 // Walk the list of ports\r
671 //\r
672 pPort = pSocket->pPortList;\r
673 while ( NULL != pPort ) {\r
674 //\r
675 // Set the remote address\r
676 //\r
677 pTcp4 = &pPort->Context.Tcp4;\r
678 *(UINT32 *)&pTcp4->ConfigData.AccessPoint.RemoteAddress = pIp4Address->sin_addr.s_addr;\r
679 pTcp4->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pIp4Address->sin_port );\r
680\r
681 //\r
682 // Set the next port\r
683 //\r
684 pPort = pPort->pLinkSocket;\r
685 }\r
686 \r
687 //\r
688 // Attempt a connection using the first adapter\r
689 //\r
690 Status = EslTcpConnectAttempt4 ( pSocket );\r
691 }\r
692 }\r
693 else {\r
694 DEBUG (( DEBUG_CONNECT,\r
695 "ERROR - Invalid TCP4 address length: %d\r\n",\r
696 SockAddrLength ));\r
697 Status = EFI_INVALID_PARAMETER;\r
698 pSocket->errno = EINVAL;\r
699 }\r
700\r
701 //\r
702 // Return the initialization status\r
703 //\r
704 DBG_EXIT_STATUS ( Status );\r
705 return Status;\r
706}\r
707\r
708\r
709/**\r
710 Initialize the TCP4 service.\r
711\r
712 This routine initializes the TCP4 service after its service binding\r
713 protocol was located on a controller.\r
714\r
715 @param [in] pService DT_SERVICE structure address\r
716\r
717 @retval EFI_SUCCESS The service was properly initialized\r
718 @retval other A failure occurred during the service initialization\r
719\r
720**/\r
721EFI_STATUS\r
722EFIAPI\r
723EslTcpInitialize4 (\r
724 IN DT_SERVICE * pService\r
725 )\r
726{\r
727 DT_LAYER * pLayer;\r
728 EFI_STATUS Status;\r
729\r
730 DBG_ENTER ( );\r
731\r
732 //\r
733 // Identify the service\r
734 //\r
735 pService->NetworkType = NETWORK_TYPE_TCP4;\r
736\r
737 //\r
738 // Connect this service to the service list\r
739 //\r
740 pLayer = &mEslLayer;\r
741 pService->pNext = pLayer->pTcp4List;\r
742 pLayer->pTcp4List = pService;\r
743\r
744 //\r
745 // Assume the list is empty\r
746 //\r
747 Status = EFI_SUCCESS;\r
748\r
749 //\r
750 // Return the initialization status\r
751 //\r
752 DBG_EXIT_STATUS ( Status );\r
753 return Status;\r
754}\r
755\r
756\r
757/**\r
758 Get the local socket address\r
759\r
760 @param [in] pSocket Address of the socket structure.\r
761\r
762 @param [out] pAddress Network address to receive the local system address\r
763\r
764 @param [in,out] pAddressLength Length of the local network address structure\r
765\r
766 @retval EFI_SUCCESS - Address available\r
767 @retval Other - Failed to get the address\r
768\r
769**/\r
770EFI_STATUS\r
771EslTcpGetLocalAddress4 (\r
772 IN DT_SOCKET * pSocket,\r
773 OUT struct sockaddr * pAddress,\r
774 IN OUT socklen_t * pAddressLength\r
775 )\r
776{\r
777 socklen_t LengthInBytes;\r
778 DT_PORT * pPort;\r
779 struct sockaddr_in * pLocalAddress;\r
780 DT_TCP4_CONTEXT * pTcp4;\r
781 EFI_STATUS Status;\r
782\r
783 DBG_ENTER ( );\r
784\r
785 //\r
786 // Verify the socket layer synchronization\r
787 //\r
788 VERIFY_TPL ( TPL_SOCKETS );\r
789\r
790 //\r
791 // Verify that there is just a single connection\r
792 //\r
793 pPort = pSocket->pPortList;\r
794 if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {\r
795 //\r
796 // Verify the address length\r
797 //\r
798 LengthInBytes = sizeof ( struct sockaddr_in );\r
799 if ( LengthInBytes <= * pAddressLength ) {\r
800 //\r
801 // Return the local address\r
802 //\r
803 pTcp4 = &pPort->Context.Tcp4;\r
804 pLocalAddress = (struct sockaddr_in *)pAddress;\r
805 ZeroMem ( pLocalAddress, LengthInBytes );\r
806 pLocalAddress->sin_family = AF_INET;\r
807 pLocalAddress->sin_len = (uint8_t)LengthInBytes;\r
808 pLocalAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.StationPort );\r
809 CopyMem ( &pLocalAddress->sin_addr,\r
810 &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],\r
811 sizeof ( pLocalAddress->sin_addr ));\r
812 pSocket->errno = 0;\r
813 Status = EFI_SUCCESS;\r
814 }\r
815 else {\r
816 pSocket->errno = EINVAL;\r
817 Status = EFI_INVALID_PARAMETER;\r
818 }\r
819 }\r
820 else {\r
821 pSocket->errno = ENOTCONN;\r
822 Status = EFI_NOT_STARTED;\r
823 }\r
824 \r
825 //\r
826 // Return the operation status\r
827 //\r
828 DBG_EXIT_STATUS ( Status );\r
829 return Status;\r
830}\r
831\r
832\r
833/**\r
834 Get the remote socket address\r
835\r
836 @param [in] pSocket Address of the socket structure.\r
837\r
838 @param [out] pAddress Network address to receive the remote system address\r
839\r
840 @param [in,out] pAddressLength Length of the remote network address structure\r
841\r
842 @retval EFI_SUCCESS - Address available\r
843 @retval Other - Failed to get the address\r
844\r
845**/\r
846EFI_STATUS\r
847EslTcpGetRemoteAddress4 (\r
848 IN DT_SOCKET * pSocket,\r
849 OUT struct sockaddr * pAddress,\r
850 IN OUT socklen_t * pAddressLength\r
851 )\r
852{\r
853 socklen_t LengthInBytes;\r
854 DT_PORT * pPort;\r
855 struct sockaddr_in * pRemoteAddress;\r
856 DT_TCP4_CONTEXT * pTcp4;\r
857 EFI_STATUS Status;\r
858\r
859 DBG_ENTER ( );\r
860\r
861 //\r
862 // Verify the socket layer synchronization\r
863 //\r
864 VERIFY_TPL ( TPL_SOCKETS );\r
865\r
866 //\r
867 // Verify that there is just a single connection\r
868 //\r
869 pPort = pSocket->pPortList;\r
870 if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {\r
871 //\r
872 // Verify the address length\r
873 //\r
874 LengthInBytes = sizeof ( struct sockaddr_in );\r
875 if ( LengthInBytes <= * pAddressLength ) {\r
876 //\r
877 // Return the local address\r
878 //\r
879 pTcp4 = &pPort->Context.Tcp4;\r
880 pRemoteAddress = (struct sockaddr_in *)pAddress;\r
881 ZeroMem ( pRemoteAddress, LengthInBytes );\r
882 pRemoteAddress->sin_family = AF_INET;\r
883 pRemoteAddress->sin_len = (uint8_t)LengthInBytes;\r
884 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );\r
885 CopyMem ( &pRemoteAddress->sin_addr,\r
886 &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
887 sizeof ( pRemoteAddress->sin_addr ));\r
888 pSocket->errno = 0;\r
889 Status = EFI_SUCCESS;\r
890 }\r
891 else {\r
892 pSocket->errno = EINVAL;\r
893 Status = EFI_INVALID_PARAMETER;\r
894 }\r
895 }\r
896 else {\r
897 pSocket->errno = ENOTCONN;\r
898 Status = EFI_NOT_STARTED;\r
899 }\r
900 \r
901 //\r
902 // Return the operation status\r
903 //\r
904 DBG_EXIT_STATUS ( Status );\r
905 return Status;\r
906}\r
907\r
908\r
909/**\r
910 Establish the known port to listen for network connections.\r
911\r
912 The ::Tcp4Listen routine places the port into a state that enables connection\r
913 attempts. Connections are placed into FIFO order in a queue to be serviced\r
914 by the application. The application calls the ::Tcp4Accept routine to remove\r
915 the next connection from the queue and get the associated socket. The\r
916 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>\r
917 documentation for the listen routine is available online for reference.\r
918\r
919 @param [in] pSocket Address of the socket structure.\r
920\r
921 @retval EFI_SUCCESS - Socket successfully created\r
922 @retval Other - Failed to enable the socket for listen\r
923\r
924**/\r
925EFI_STATUS\r
926EslTcpListen4 (\r
927 IN DT_SOCKET * pSocket\r
928 )\r
929{\r
930 DT_PORT * pNextPort;\r
931 DT_PORT * pPort;\r
932 DT_TCP4_CONTEXT * pTcp4;\r
933 EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
934 EFI_STATUS Status;\r
935\r
936 DBG_ENTER ( );\r
937\r
938 //\r
939 // Verify the socket layer synchronization\r
940 //\r
941 VERIFY_TPL ( TPL_SOCKETS );\r
942\r
943 //\r
944 // Use for/break instead of goto\r
945 //\r
946 for ( ; ; ) {\r
947 //\r
948 // Assume no ports are available\r
949 //\r
950 pSocket->errno = EOPNOTSUPP;\r
951 Status = EFI_NOT_READY;\r
952\r
953 //\r
954 // Walk the list of ports\r
955 //\r
956 pPort = pSocket->pPortList;\r
957 while ( NULL != pPort ) {\r
958 //\r
959 // Assume success\r
960 //\r
961 pSocket->errno = 0;\r
962\r
963 //\r
964 // Use for/break insteak of goto\r
965 //\r
966 for ( ; ; ) {\r
967 //\r
968 // Create the listen completion event\r
969 //\r
970 pTcp4 = &pPort->Context.Tcp4;\r
971 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
972 TPL_SOCKETS,\r
973 (EFI_EVENT_NOTIFY)EslTcpListenComplete4,\r
974 pPort,\r
975 &pTcp4->ListenToken.CompletionToken.Event );\r
976 if ( EFI_ERROR ( Status )) {\r
977 DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,\r
978 "ERROR - Failed to create the listen completion event, Status: %r\r\n",\r
979 Status ));\r
980 pSocket->errno = ENOMEM;\r
981 break;\r
982 }\r
983 DEBUG (( DEBUG_POOL,\r
984 "0x%08x: Created listen completion event\r\n",\r
985 pTcp4->ListenToken.CompletionToken.Event ));\r
986\r
987 //\r
988 // Configure the port\r
989 //\r
990 pTcp4Protocol = pTcp4->pProtocol;\r
991 Status = pTcp4Protocol->Configure ( pTcp4Protocol,\r
992 &pTcp4->ConfigData );\r
993 if ( EFI_ERROR ( Status )) {\r
994 DEBUG (( DEBUG_LISTEN,\r
995 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",\r
996 Status ));\r
997 switch ( Status ) {\r
998 case EFI_ACCESS_DENIED:\r
999 pSocket->errno = EACCES;\r
1000 break;\r
1001\r
1002 default:\r
1003 case EFI_DEVICE_ERROR:\r
1004 pSocket->errno = EIO;\r
1005 break;\r
1006\r
1007 case EFI_INVALID_PARAMETER:\r
1008 pSocket->errno = EADDRNOTAVAIL;\r
1009 break;\r
1010\r
1011 case EFI_NO_MAPPING:\r
1012 pSocket->errno = EAFNOSUPPORT;\r
1013 break;\r
1014\r
1015 case EFI_OUT_OF_RESOURCES:\r
1016 pSocket->errno = ENOBUFS;\r
1017 break;\r
1018\r
1019 case EFI_UNSUPPORTED:\r
1020 pSocket->errno = EOPNOTSUPP;\r
1021 break;\r
1022 }\r
1023 break;\r
1024 }\r
1025 DEBUG (( DEBUG_LISTEN,\r
1026 "0x%08x: Port configured\r\n",\r
1027 pPort ));\r
1028 pTcp4->bConfigured = TRUE;\r
1029\r
1030 //\r
1031 // Start the listen operation on the port\r
1032 //\r
1033 Status = pTcp4Protocol->Accept ( pTcp4Protocol,\r
1034 &pTcp4->ListenToken );\r
1035 if ( EFI_ERROR ( Status )) {\r
1036 DEBUG (( DEBUG_LISTEN,\r
1037 "ERROR - Failed Tcp4 accept, Status: %r\r\n",\r
1038 Status ));\r
1039 switch ( Status ) {\r
1040 case EFI_ACCESS_DENIED:\r
1041 pSocket->errno = EACCES;\r
1042 break;\r
1043\r
1044 default:\r
1045 case EFI_DEVICE_ERROR:\r
1046 pSocket->errno = EIO;\r
1047 break;\r
1048\r
1049 case EFI_INVALID_PARAMETER:\r
1050 pSocket->errno = EADDRNOTAVAIL;\r
1051 break;\r
1052\r
1053 case EFI_NOT_STARTED:\r
1054 pSocket->errno = ENETDOWN;\r
1055 break;\r
1056\r
1057 case EFI_OUT_OF_RESOURCES:\r
1058 pSocket->errno = ENOBUFS;\r
1059 break;\r
1060 }\r
1061 break;\r
1062 }\r
1063 DEBUG (( DEBUG_LISTEN,\r
1064 "0x%08x: Listen pending on Port\r\n",\r
1065 pPort ));\r
1066\r
1067 //\r
1068 // Listen is pending on this port\r
1069 //\r
1070 break;\r
1071 }\r
1072\r
1073 //\r
1074 // Get the next port\r
1075 //\r
1076 pNextPort = pPort->pLinkSocket;\r
1077\r
1078 //\r
1079 // Close the port upon error\r
1080 //\r
1081 if ( EFI_ERROR ( Status ))\r
1082 {\r
1083 EslTcpPortCloseStart4 ( pPort, TRUE, DEBUG_LISTEN );\r
1084 }\r
1085\r
1086 //\r
1087 // Set the next port\r
1088 //\r
1089 pPort = pNextPort;\r
1090 }\r
1091 \r
1092 //\r
1093 // Determine if any ports are in the listen state\r
1094 //\r
1095 if ( NULL == pSocket->pPortList ) {\r
1096 //\r
1097 // No ports in the listen state\r
1098 //\r
1099 pSocket->MaxFifoDepth = 0;\r
1100\r
1101 //\r
1102 // Return the last error detected\r
1103 //\r
1104 break;\r
1105 }\r
1106\r
1107 //\r
1108 // Mark the socket as configured\r
1109 //\r
1110 pSocket->bConfigured = TRUE;\r
1111\r
1112 //\r
1113 // All done\r
1114 //\r
1115 DEBUG (( DEBUG_LISTEN,\r
1116 "0x%08x: pSocket - Listen pending on socket\r\n",\r
1117 pSocket ));\r
1118 break;\r
1119 }\r
1120\r
1121 //\r
1122 // Return the operation status\r
1123 //\r
1124 DBG_EXIT_STATUS ( Status );\r
1125 return Status;\r
1126}\r
1127\r
1128\r
1129/**\r
1130 Process the connection attempt\r
1131\r
1132 A system has initiated a connection attempt with a socket in the\r
1133 listen state. Attempt to complete the connection.\r
1134\r
1135 @param Event The listen completion event\r
1136\r
1137 @param pPort The DT_PORT structure address\r
1138\r
1139**/\r
1140VOID\r
1141EslTcpListenComplete4 (\r
1142 IN EFI_EVENT Event,\r
1143 IN DT_PORT * pPort\r
1144 )\r
1145{\r
1146 EFI_HANDLE ChildHandle;\r
1147 EFI_TCP4_CONFIG_DATA * pConfigData;\r
1148 DT_LAYER * pLayer;\r
1149 DT_PORT * pNewPort;\r
1150 DT_SOCKET * pNewSocket;\r
1151 DT_SOCKET * pSocket;\r
1152 DT_TCP4_CONTEXT * pTcp4;\r
1153 EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
1154 EFI_STATUS Status;\r
1155 EFI_HANDLE TcpPortHandle;\r
1156 EFI_STATUS TempStatus;\r
1157\r
1158 DBG_ENTER ( );\r
1159\r
1160 //\r
1161 // Assume success\r
1162 //\r
1163 Status = EFI_SUCCESS;\r
1164\r
1165 //\r
1166 // Determine if this connection fits into the connection FIFO\r
1167 //\r
1168 pSocket = pPort->pSocket;\r
1169 TcpPortHandle = pPort->Context.Tcp4.ListenToken.NewChildHandle;\r
1170 if (( SOCKET_STATE_LISTENING == pSocket->State )\r
1171 && ( pSocket->MaxFifoDepth > pSocket->FifoDepth )) {\r
1172 //\r
1173 // Allocate a socket for this connection\r
1174 //\r
1175 ChildHandle = NULL;\r
1176 pLayer = &mEslLayer;\r
1177 Status = EslSocketAllocate ( &ChildHandle,\r
1178 DEBUG_CONNECTION,\r
1179 &pNewSocket );\r
1180 if ( !EFI_ERROR ( Status )) {\r
1181 //\r
1182 // Clone the socket parameters\r
1183 //\r
1184 pNewSocket->Domain = pSocket->Domain;\r
1185 pNewSocket->Protocol = pSocket->Protocol;\r
1186 pNewSocket->Type = pSocket->Type;\r
1187\r
1188 //\r
1189 // Allocate a port for this connection\r
1190 //\r
1191 pTcp4 = &pPort->Context.Tcp4;\r
1192 Status = EslTcpPortAllocate4 ( pNewSocket,\r
1193 pPort->pService,\r
1194 TcpPortHandle,\r
1195 &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],\r
1196 0,\r
1197 DEBUG_CONNECTION,\r
1198 &pNewPort );\r
1199 if ( !EFI_ERROR ( Status )) {\r
1200 //\r
1201 // Restart the listen operation on the port\r
1202 //\r
1203 pTcp4Protocol = pTcp4->pProtocol;\r
1204 Status = pTcp4Protocol->Accept ( pTcp4Protocol,\r
1205 &pTcp4->ListenToken );\r
1206\r
1207 //\r
1208 // Close the TCP port using SocketClose\r
1209 //\r
1210 TcpPortHandle = NULL;\r
1211 pTcp4 = &pNewPort->Context.Tcp4;\r
1212 pTcp4->bConfigured = TRUE;\r
1213\r
1214 //\r
1215 // Check for an accept call error\r
1216 //\r
1217 if ( !EFI_ERROR ( Status )) {\r
1218 //\r
1219 // Get the port configuration\r
1220 //\r
1221 pConfigData = &pTcp4->ConfigData;\r
1222 pConfigData->ControlOption = &pTcp4->Option;\r
1223 pTcp4Protocol = pTcp4->pProtocol;\r
1224 Status = pTcp4Protocol->GetModeData ( pTcp4Protocol,\r
1225 NULL,\r
1226 pConfigData,\r
1227 NULL,\r
1228 NULL,\r
1229 NULL );\r
1230 if ( !EFI_ERROR ( Status )) {\r
1231 //\r
1232 // Add the new socket to the connection FIFO\r
1233 //\r
1234 if ( NULL == pSocket->pFifoTail ) {\r
1235 //\r
1236 // First connection\r
1237 //\r
1238 pSocket->pFifoHead = pNewSocket;\r
1239 }\r
1240 else {\r
1241 //\r
1242 // Add to end of list.\r
1243 //\r
1244 pSocket->pFifoTail->pNextConnection = pNewSocket;\r
1245 }\r
1246 pSocket->pFifoTail = pNewSocket;\r
1247 pSocket->FifoDepth += 1;\r
1248\r
1249 //\r
1250 // Update the socket state\r
1251 //\r
1252 pNewSocket->State = SOCKET_STATE_IN_FIFO;\r
1253\r
1254 //\r
1255 // Log the connection\r
1256 //\r
1257 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,\r
1258 "0x%08x: Socket on port %d.%d.%d.%d:%d connected to %d.%d.%d.%d:%d\r\n",\r
1259 pNewSocket,\r
1260 pConfigData->AccessPoint.StationAddress.Addr[0],\r
1261 pConfigData->AccessPoint.StationAddress.Addr[1],\r
1262 pConfigData->AccessPoint.StationAddress.Addr[2],\r
1263 pConfigData->AccessPoint.StationAddress.Addr[3],\r
1264 pConfigData->AccessPoint.StationPort,\r
1265 pConfigData->AccessPoint.RemoteAddress.Addr[0],\r
1266 pConfigData->AccessPoint.RemoteAddress.Addr[1],\r
1267 pConfigData->AccessPoint.RemoteAddress.Addr[2],\r
1268 pConfigData->AccessPoint.RemoteAddress.Addr[3],\r
1269 pConfigData->AccessPoint.RemotePort ));\r
1270 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,\r
1271 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",\r
1272 pSocket,\r
1273 pNewSocket,\r
1274 pSocket->FifoDepth ));\r
1275\r
1276 //\r
1277 // Start the receive operation\r
1278 //\r
1279 EslTcpRxStart4 ( pNewPort );\r
1280 }\r
1281 else {\r
1282 DEBUG (( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO,\r
1283 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",\r
1284 pNewPort,\r
1285 Status ));\r
1286 }\r
1287 }\r
1288 else {\r
1289 //\r
1290 // The listen failed on this port\r
1291 //\r
1292 DEBUG (( DEBUG_LISTEN | DEBUG_INFO,\r
1293 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",\r
1294 pPort,\r
1295 Status ));\r
1296\r
1297 //\r
1298 // Close the listening port\r
1299 //\r
1300 EslTcpPortCloseStart4 ( pPort, TRUE, DEBUG_LISTEN );\r
1301 }\r
1302 }\r
1303\r
1304 //\r
1305 // Done with the socket if necessary\r
1306 //\r
1307 if ( EFI_ERROR ( Status )) {\r
1308 TempStatus = EslSocketCloseStart ( &pNewSocket->SocketProtocol,\r
1309 TRUE,\r
1310 &pSocket->errno );\r
1311 ASSERT ( EFI_SUCCESS == TempStatus );\r
1312 }\r
1313 }\r
1314 }\r
1315 else {\r
1316 DEBUG (( DEBUG_CONNECTION,\r
1317 "0x%08x: Socket FIFO full, connection refused\r\n",\r
1318 pSocket ));\r
1319\r
1320 //\r
1321 // The FIFO is full or the socket is in the wrong state\r
1322 //\r
1323 Status = EFI_BUFFER_TOO_SMALL;\r
1324 }\r
1325\r
1326 //\r
1327 // Close the connection if necessary\r
1328 //\r
1329 if (( EFI_ERROR ( Status ))\r
1330 && ( NULL == TcpPortHandle )) {\r
1331 //\r
1332 // TODO: Finish this code path\r
1333 // The new connection does not fit into the connection FIFO\r
1334 //\r
1335 // Process:\r
1336 // Call close\r
1337 // Release the resources\r
1338 \r
1339 }\r
1340\r
1341 DBG_EXIT ( );\r
1342}\r
1343\r
1344\r
1345/**\r
1346 Allocate and initialize a DT_PORT structure.\r
1347\r
1348 @param [in] pSocket Address of the socket structure.\r
1349 @param [in] pService Address of the DT_SERVICE structure.\r
1350 @param [in] ChildHandle TCP4 child handle\r
1351 @param [in] pIpAddress Buffer containing IP4 network address of the local host\r
1352 @param [in] PortNumber Tcp4 port number\r
1353 @param [in] DebugFlags Flags for debug messages\r
1354 @param [out] ppPort Buffer to receive new DT_PORT structure address\r
1355\r
1356 @retval EFI_SUCCESS - Socket successfully created\r
1357\r
1358 **/\r
1359EFI_STATUS\r
1360EslTcpPortAllocate4 (\r
1361 IN DT_SOCKET * pSocket,\r
1362 IN DT_SERVICE * pService,\r
1363 IN EFI_HANDLE ChildHandle,\r
1364 IN CONST UINT8 * pIpAddress,\r
1365 IN UINT16 PortNumber,\r
1366 IN UINTN DebugFlags,\r
1367 OUT DT_PORT ** ppPort\r
1368 )\r
1369{\r
1370 UINTN LengthInBytes;\r
1371 EFI_TCP4_ACCESS_POINT * pAccessPoint;\r
1372 DT_LAYER * pLayer;\r
1373 DT_PORT * pPort;\r
1374 DT_TCP4_CONTEXT * pTcp4;\r
1375 EFI_STATUS Status;\r
1376\r
1377 DBG_ENTER ( );\r
1378\r
1379 //\r
1380 // Use for/break instead of goto\r
1381 for ( ; ; ) {\r
1382 //\r
1383 // Allocate a port structure\r
1384 //\r
1385 pLayer = &mEslLayer;\r
1386 LengthInBytes = sizeof ( *pPort );\r
1387 Status = gBS->AllocatePool ( EfiRuntimeServicesData,\r
1388 LengthInBytes,\r
1389 (VOID **)&pPort );\r
1390 if ( EFI_ERROR ( Status )) {\r
1391 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
1392 "ERROR - Failed to allocate the port structure, Status: %r\r\n",\r
1393 Status ));\r
1394 pSocket->errno = ENOMEM;\r
1395 pPort = NULL;\r
1396 break;\r
1397 }\r
1398 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
1399 "0x%08x: Allocate pPort, %d bytes\r\n",\r
1400 pPort,\r
1401 LengthInBytes ));\r
1402\r
1403 //\r
1404 // Initialize the port\r
1405 //\r
1406 ZeroMem ( pPort, LengthInBytes );\r
1407 pPort->Signature = PORT_SIGNATURE;\r
1408 pPort->pService = pService;\r
1409 pPort->pSocket = pSocket;\r
1410 pPort->pfnCloseStart = EslTcpPortCloseStart4;\r
1411 pPort->DebugFlags = DebugFlags;\r
1412\r
1413 //\r
1414 // Allocate the receive event\r
1415 //\r
1416 pTcp4 = &pPort->Context.Tcp4;\r
1417 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
1418 TPL_SOCKETS,\r
1419 (EFI_EVENT_NOTIFY)EslTcpRxComplete4,\r
1420 pPort,\r
1421 &pTcp4->RxToken.CompletionToken.Event);\r
1422 if ( EFI_ERROR ( Status )) {\r
1423 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1424 "ERROR - Failed to create the receive event, Status: %r\r\n",\r
1425 Status ));\r
1426 pSocket->errno = ENOMEM;\r
1427 break;\r
1428 }\r
1429 DEBUG (( DEBUG_RX | DEBUG_POOL,\r
1430 "0x%08x: Created receive event\r\n",\r
1431 pTcp4->RxToken.CompletionToken.Event ));\r
1432\r
1433 //\r
1434 // Allocate the urgent transmit event\r
1435 //\r
1436 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
1437 TPL_SOCKETS,\r
1438 (EFI_EVENT_NOTIFY)EslTcpTxOobComplete4,\r
1439 pPort,\r
1440 &pTcp4->TxOobToken.CompletionToken.Event);\r
1441 if ( EFI_ERROR ( Status )) {\r
1442 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1443 "ERROR - Failed to create the urgent transmit event, Status: %r\r\n",\r
1444 Status ));\r
1445 pSocket->errno = ENOMEM;\r
1446 break;\r
1447 }\r
1448 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
1449 "0x%08x: Created urgent transmit event\r\n",\r
1450 pTcp4->TxOobToken.CompletionToken.Event ));\r
1451\r
1452 //\r
1453 // Allocate the normal transmit event\r
1454 //\r
1455 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
1456 TPL_SOCKETS,\r
1457 (EFI_EVENT_NOTIFY)EslTcpTxComplete4,\r
1458 pPort,\r
1459 &pTcp4->TxToken.CompletionToken.Event);\r
1460 if ( EFI_ERROR ( Status )) {\r
1461 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1462 "ERROR - Failed to create the normal transmit event, Status: %r\r\n",\r
1463 Status ));\r
1464 pSocket->errno = ENOMEM;\r
1465 break;\r
1466 }\r
1467 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
1468 "0x%08x: Created normal transmit event\r\n",\r
1469 pTcp4->TxToken.CompletionToken.Event ));\r
1470\r
1471 //\r
1472 // Allocate the close event\r
1473 //\r
1474 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
1475 TPL_SOCKETS,\r
1476 (EFI_EVENT_NOTIFY)EslTcpPortCloseComplete4,\r
1477 pPort,\r
1478 &pTcp4->CloseToken.CompletionToken.Event);\r
1479 if ( EFI_ERROR ( Status )) {\r
1480 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1481 "ERROR - Failed to create the close event, Status: %r\r\n",\r
1482 Status ));\r
1483 pSocket->errno = ENOMEM;\r
1484 break;\r
1485 }\r
1486 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
1487 "0x%08x: Created close event\r\n",\r
1488 pTcp4->CloseToken.CompletionToken.Event ));\r
1489\r
1490 //\r
1491 // Allocate the connection event\r
1492 //\r
1493 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
1494 TPL_SOCKETS,\r
1495 (EFI_EVENT_NOTIFY)EslTcpConnectComplete4,\r
1496 pPort,\r
1497 &pTcp4->ConnectToken.CompletionToken.Event);\r
1498 if ( EFI_ERROR ( Status )) {\r
1499 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1500 "ERROR - Failed to create the connect event, Status: %r\r\n",\r
1501 Status ));\r
1502 pSocket->errno = ENOMEM;\r
1503 break;\r
1504 }\r
1505 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
1506 "0x%08x: Created connect event\r\n",\r
1507 pTcp4->ConnectToken.CompletionToken.Event ));\r
1508\r
1509 //\r
1510 // Open the port protocol\r
1511 //\r
1512 Status = gBS->OpenProtocol (\r
1513 ChildHandle,\r
1514 &gEfiTcp4ProtocolGuid,\r
1515 (VOID **) &pTcp4->pProtocol,\r
1516 pLayer->ImageHandle,\r
1517 NULL,\r
1518 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );\r
1519 if ( EFI_ERROR ( Status )) {\r
1520 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1521 "ERROR - Failed to open gEfiTcp4ProtocolGuid on controller 0x%08x\r\n",\r
1522 pTcp4->Handle ));\r
1523 pSocket->errno = EEXIST;\r
1524 break;\r
1525 }\r
1526 DEBUG (( DebugFlags,\r
1527 "0x%08x: gEfiTcp4ProtocolGuid opened on controller 0x%08x\r\n",\r
1528 pTcp4->pProtocol,\r
1529 ChildHandle ));\r
1530\r
1531 //\r
1532 // Set the port address\r
1533 //\r
1534 pTcp4->Handle = ChildHandle;\r
1535 pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;\r
1536 pAccessPoint->StationPort = PortNumber;\r
1537 if (( 0 == pIpAddress[0])\r
1538 && ( 0 == pIpAddress[1])\r
1539 && ( 0 == pIpAddress[2])\r
1540 && ( 0 == pIpAddress[3])) {\r
1541 pAccessPoint->UseDefaultAddress = TRUE;\r
1542 }\r
1543 else {\r
1544 pAccessPoint->StationAddress.Addr[0] = pIpAddress[0];\r
1545 pAccessPoint->StationAddress.Addr[1] = pIpAddress[1];\r
1546 pAccessPoint->StationAddress.Addr[2] = pIpAddress[2];\r
1547 pAccessPoint->StationAddress.Addr[3] = pIpAddress[3];\r
1548 pAccessPoint->SubnetMask.Addr[0] = 0xff;\r
1549 pAccessPoint->SubnetMask.Addr[1] = 0xff;\r
1550 pAccessPoint->SubnetMask.Addr[2] = 0xff;\r
1551 pAccessPoint->SubnetMask.Addr[3] = 0xff;\r
1552 }\r
1553 pAccessPoint->ActiveFlag = FALSE;\r
1554 pTcp4->ConfigData.TimeToLive = 255;\r
1555\r
1556 //\r
1557 // Verify the socket layer synchronization\r
1558 //\r
1559 VERIFY_TPL ( TPL_SOCKETS );\r
1560\r
1561 //\r
1562 // Add this port to the socket\r
1563 //\r
1564 pPort->pLinkSocket = pSocket->pPortList;\r
1565 pSocket->pPortList = pPort;\r
1566 DEBUG (( DebugFlags,\r
1567 "0x%08x: Socket adding port: 0x%08x\r\n",\r
1568 pSocket,\r
1569 pPort ));\r
1570\r
1571 //\r
1572 // Add this port to the service\r
1573 //\r
1574 pPort->pLinkService = pService->pPortList;\r
1575 pService->pPortList = pPort;\r
1576\r
1577 //\r
1578 // Return the port\r
1579 //\r
1580 *ppPort = pPort;\r
1581 break;\r
1582 }\r
1583\r
1584 //\r
1585 // Clean up after the error if necessary\r
1586 //\r
1587 if (( EFI_ERROR ( Status )) && ( NULL != pPort )) {\r
1588 //\r
1589 // Close the port\r
1590 //\r
1591 EslTcpPortClose4 ( pPort );\r
1592 }\r
1593 //\r
1594 // Return the operation status\r
1595 //\r
1596 DBG_EXIT_STATUS ( Status );\r
1597 return Status;\r
1598}\r
1599\r
1600\r
1601/**\r
1602 Close a TCP4 port.\r
1603\r
1604 This routine releases the resources allocated by\r
1605 ::TcpPortAllocate4().\r
1606 \r
1607 @param [in] pPort Address of the port structure.\r
1608\r
1609 @retval EFI_SUCCESS The port is closed\r
1610 @retval other Port close error\r
1611\r
1612**/\r
1613EFI_STATUS\r
1614EslTcpPortClose4 (\r
1615 IN DT_PORT * pPort\r
1616 )\r
1617{\r
1618 UINTN DebugFlags;\r
1619 DT_LAYER * pLayer;\r
1620 DT_PACKET * pPacket;\r
1621 DT_PORT * pPreviousPort;\r
1622 DT_SERVICE * pService;\r
1623 DT_SOCKET * pSocket;\r
1624 EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service;\r
1625 DT_TCP4_CONTEXT * pTcp4;\r
1626 EFI_STATUS Status;\r
1627 \r
1628 DBG_ENTER ( );\r
1629\r
1630 //\r
1631 // Verify the socket layer synchronization\r
1632 //\r
1633 VERIFY_TPL ( TPL_SOCKETS );\r
1634\r
1635 //\r
1636 // Locate the port in the socket list\r
1637 //\r
1638 Status = EFI_SUCCESS;\r
1639 pLayer = &mEslLayer;\r
1640 DebugFlags = pPort->DebugFlags;\r
1641 pSocket = pPort->pSocket;\r
1642 pPreviousPort = pSocket->pPortList;\r
1643 if ( pPreviousPort == pPort ) {\r
1644 //\r
1645 // Remove this port from the head of the socket list\r
1646 //\r
1647 pSocket->pPortList = pPort->pLinkSocket;\r
1648 }\r
1649 else {\r
1650 //\r
1651 // Locate the port in the middle of the socket list\r
1652 //\r
1653 while (( NULL != pPreviousPort )\r
1654 && ( pPreviousPort->pLinkSocket != pPort )) {\r
1655 pPreviousPort = pPreviousPort->pLinkSocket;\r
1656 }\r
1657 if ( NULL != pPreviousPort ) {\r
1658 //\r
1659 // Remove the port from the middle of the socket list\r
1660 //\r
1661 pPreviousPort->pLinkSocket = pPort->pLinkSocket;\r
1662 }\r
1663 }\r
1664\r
1665 //\r
1666 // Locate the port in the service list\r
1667 //\r
1668 pService = pPort->pService;\r
1669 pPreviousPort = pService->pPortList;\r
1670 if ( pPreviousPort == pPort ) {\r
1671 //\r
1672 // Remove this port from the head of the service list\r
1673 //\r
1674 pService->pPortList = pPort->pLinkService;\r
1675 }\r
1676 else {\r
1677 //\r
1678 // Locate the port in the middle of the service list\r
1679 //\r
1680 while (( NULL != pPreviousPort )\r
1681 && ( pPreviousPort->pLinkService != pPort )) {\r
1682 pPreviousPort = pPreviousPort->pLinkService;\r
1683 }\r
1684 if ( NULL != pPreviousPort ) {\r
1685 //\r
1686 // Remove the port from the middle of the service list\r
1687 //\r
1688 pPreviousPort->pLinkService = pPort->pLinkService;\r
1689 }\r
1690 }\r
1691\r
1692 //\r
1693 // Empty the urgent receive queue\r
1694 //\r
1695 pTcp4 = &pPort->Context.Tcp4;\r
1696 while ( NULL != pSocket->pRxOobPacketListHead ) {\r
1697 pPacket = pSocket->pRxOobPacketListHead;\r
1698 pSocket->pRxOobPacketListHead = pPacket->pNext;\r
1699 pSocket->RxOobBytes -= pPacket->Op.Tcp4Rx.ValidBytes;\r
1700 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
1701 }\r
1702 pSocket->pRxOobPacketListTail = NULL;\r
1703 ASSERT ( 0 == pSocket->RxOobBytes );\r
1704\r
1705 //\r
1706 // Empty the receive queue\r
1707 //\r
1708 while ( NULL != pSocket->pRxPacketListHead ) {\r
1709 pPacket = pSocket->pRxPacketListHead;\r
1710 pSocket->pRxPacketListHead = pPacket->pNext;\r
1711 pSocket->RxBytes -= pPacket->Op.Tcp4Rx.ValidBytes;\r
1712 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
1713 }\r
1714 pSocket->pRxPacketListTail = NULL;\r
1715 ASSERT ( 0 == pSocket->RxBytes );\r
1716\r
1717 //\r
1718 // Empty the receive free queue\r
1719 //\r
1720 while ( NULL != pSocket->pRxFree ) {\r
1721 pPacket = pSocket->pRxFree;\r
1722 pSocket->pRxFree = pPacket->pNext;\r
1723 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
1724 }\r
1725\r
1726 //\r
1727 // Done with the connect event\r
1728 //\r
1729 if ( NULL != pTcp4->ConnectToken.CompletionToken.Event ) {\r
1730 Status = gBS->CloseEvent ( pTcp4->ConnectToken.CompletionToken.Event );\r
1731 if ( !EFI_ERROR ( Status )) {\r
1732 DEBUG (( DebugFlags | DEBUG_POOL,\r
1733 "0x%08x: Closed connect event\r\n",\r
1734 pTcp4->ConnectToken.CompletionToken.Event ));\r
1735 }\r
1736 else {\r
1737 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1738 "ERROR - Failed to close the connect event, Status: %r\r\n",\r
1739 Status ));\r
1740 ASSERT ( EFI_SUCCESS == Status );\r
1741 }\r
1742 }\r
1743\r
1744 //\r
1745 // Done with the close event\r
1746 //\r
1747 if ( NULL != pTcp4->CloseToken.CompletionToken.Event ) {\r
1748 Status = gBS->CloseEvent ( pTcp4->CloseToken.CompletionToken.Event );\r
1749 if ( !EFI_ERROR ( Status )) {\r
1750 DEBUG (( DebugFlags | DEBUG_POOL,\r
1751 "0x%08x: Closed close event\r\n",\r
1752 pTcp4->CloseToken.CompletionToken.Event ));\r
1753 }\r
1754 else {\r
1755 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1756 "ERROR - Failed to close the close event, Status: %r\r\n",\r
1757 Status ));\r
1758 ASSERT ( EFI_SUCCESS == Status );\r
1759 }\r
1760 }\r
1761\r
1762 //\r
1763 // Done with the listen completion event\r
1764 //\r
1765 if ( NULL != pTcp4->ListenToken.CompletionToken.Event ) {\r
1766 Status = gBS->CloseEvent ( pTcp4->ListenToken.CompletionToken.Event );\r
1767 if ( !EFI_ERROR ( Status )) {\r
1768 DEBUG (( DebugFlags | DEBUG_POOL,\r
1769 "0x%08x: Closed listen completion event\r\n",\r
1770 pTcp4->ListenToken.CompletionToken.Event ));\r
1771 }\r
1772 else {\r
1773 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1774 "ERROR - Failed to close the listen completion event, Status: %r\r\n",\r
1775 Status ));\r
1776 ASSERT ( EFI_SUCCESS == Status );\r
1777 }\r
1778 }\r
1779\r
1780 //\r
1781 // Done with the receive event\r
1782 //\r
1783 if ( NULL != pTcp4->RxToken.CompletionToken.Event ) {\r
1784 Status = gBS->CloseEvent ( pTcp4->RxToken.CompletionToken.Event );\r
1785 if ( !EFI_ERROR ( Status )) {\r
1786 DEBUG (( DebugFlags | DEBUG_POOL,\r
1787 "0x%08x: Closed receive event\r\n",\r
1788 pTcp4->RxToken.CompletionToken.Event ));\r
1789 }\r
1790 else {\r
1791 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1792 "ERROR - Failed to close the receive event, Status: %r\r\n",\r
1793 Status ));\r
1794 ASSERT ( EFI_SUCCESS == Status );\r
1795 }\r
1796 }\r
1797\r
1798 //\r
1799 // Done with the normal transmit event\r
1800 //\r
1801 if ( NULL != pTcp4->TxToken.CompletionToken.Event ) {\r
1802 Status = gBS->CloseEvent ( pTcp4->TxToken.CompletionToken.Event );\r
1803 if ( !EFI_ERROR ( Status )) {\r
1804 DEBUG (( DebugFlags | DEBUG_POOL,\r
1805 "0x%08x: Closed normal transmit event\r\n",\r
1806 pTcp4->TxToken.CompletionToken.Event ));\r
1807 }\r
1808 else {\r
1809 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1810 "ERROR - Failed to close the normal transmit event, Status: %r\r\n",\r
1811 Status ));\r
1812 ASSERT ( EFI_SUCCESS == Status );\r
1813 }\r
1814 }\r
1815\r
1816 //\r
1817 // Done with the urgent transmit event\r
1818 //\r
1819 if ( NULL != pTcp4->TxOobToken.CompletionToken.Event ) {\r
1820 Status = gBS->CloseEvent ( pTcp4->TxOobToken.CompletionToken.Event );\r
1821 if ( !EFI_ERROR ( Status )) {\r
1822 DEBUG (( DebugFlags | DEBUG_POOL,\r
1823 "0x%08x: Closed urgent transmit event\r\n",\r
1824 pTcp4->TxOobToken.CompletionToken.Event ));\r
1825 }\r
1826 else {\r
1827 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1828 "ERROR - Failed to close the urgent transmit event, Status: %r\r\n",\r
1829 Status ));\r
1830 ASSERT ( EFI_SUCCESS == Status );\r
1831 }\r
1832 }\r
1833\r
1834 //\r
1835 // Done with the TCP protocol\r
1836 //\r
1837 pTcp4Service = pService->pInterface;\r
1838 if ( NULL != pTcp4->pProtocol ) {\r
1839 Status = gBS->CloseProtocol ( pTcp4->Handle,\r
1840 &gEfiTcp4ProtocolGuid,\r
1841 pLayer->ImageHandle,\r
1842 NULL );\r
1843 if ( !EFI_ERROR ( Status )) {\r
1844 DEBUG (( DebugFlags,\r
1845 "0x%08x: gEfiTcp4ProtocolGuid closed on controller 0x%08x\r\n",\r
1846 pTcp4->pProtocol,\r
1847 pTcp4->Handle ));\r
1848 }\r
1849 else {\r
1850 DEBUG (( DEBUG_ERROR | DebugFlags,\r
1851 "ERROR - Failed to close gEfiTcp4ProtocolGuid opened on controller 0x%08x, Status: %r\r\n",\r
1852 pTcp4->Handle,\r
1853 Status ));\r
1854 ASSERT ( EFI_SUCCESS == Status );\r
1855 }\r
1856 }\r
1857\r
1858 //\r
1859 // Done with the TCP port\r
1860 //\r
1861 if ( NULL != pTcp4->Handle ) {\r
1862 Status = pTcp4Service->DestroyChild ( pTcp4Service,\r
1863 pTcp4->Handle );\r
1864 if ( !EFI_ERROR ( Status )) {\r
1865 DEBUG (( DebugFlags | DEBUG_POOL,\r
1866 "0x%08x: Tcp4 port handle destroyed\r\n",\r
1867 pTcp4->Handle ));\r
1868 }\r
1869 else {\r
1870 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,\r
1871 "ERROR - Failed to destroy the Tcp4 port handle, Status: %r\r\n",\r
1872 Status ));\r
1873 ASSERT ( EFI_SUCCESS == Status );\r
1874 }\r
1875 }\r
1876\r
1877 //\r
1878 // Release the port structure\r
1879 //\r
1880 Status = gBS->FreePool ( pPort );\r
1881 if ( !EFI_ERROR ( Status )) {\r
1882 DEBUG (( DebugFlags | DEBUG_POOL,\r
1883 "0x%08x: Free pPort, %d bytes\r\n",\r
1884 pPort,\r
1885 sizeof ( *pPort )));\r
1886 }\r
1887 else {\r
1888 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,\r
1889 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",\r
1890 pPort,\r
1891 Status ));\r
1892 ASSERT ( EFI_SUCCESS == Status );\r
1893 }\r
1894\r
1895 //\r
1896 // Return the operation status\r
1897 //\r
1898 DBG_EXIT_STATUS ( Status );\r
1899 return Status;\r
1900}\r
1901\r
1902\r
1903/**\r
1904 Process the port close completion\r
1905\r
1906 @param Event The close completion event\r
1907\r
1908 @param pPort The DT_PORT structure address\r
1909\r
1910**/\r
1911VOID\r
1912EslTcpPortCloseComplete4 (\r
1913 IN EFI_EVENT Event,\r
1914 IN DT_PORT * pPort\r
1915 )\r
1916{\r
1917 EFI_STATUS Status;\r
1918\r
1919 DBG_ENTER ( );\r
1920\r
1921 //\r
1922 // Update the port state\r
1923 //\r
1924 pPort->State = PORT_STATE_CLOSE_DONE;\r
1925\r
1926 //\r
1927 // Release the resources once the receive operation completes\r
1928 //\r
1929 Status = EslTcpPortCloseRxDone4 ( pPort );\r
1930 DBG_EXIT_STATUS ( Status );\r
1931}\r
1932\r
1933\r
1934/**\r
1935 Start the close operation on a TCP4 port, state 1.\r
1936\r
1937 Closing a port goes through the following states:\r
1938 1. Port close starting - Mark the port as closing and wait for transmission to complete\r
1939 2. Port TX close done - Transmissions complete, close the port and abort the receives\r
1940 3. Port RX close done - Receive operations complete, close the port\r
1941 4. Port closed - Release the port resources\r
1942 \r
1943 @param [in] pPort Address of the port structure.\r
1944 @param [in] bCloseNow Set TRUE to abort active transfers\r
1945 @param [in] DebugFlags Flags for debug messages\r
1946\r
1947 @retval EFI_SUCCESS The port is closed, not normally returned\r
1948 @retval EFI_NOT_READY The port has started the closing process\r
1949 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
1950 most likely the routine was called already.\r
1951\r
1952**/\r
1953EFI_STATUS\r
1954EslTcpPortCloseStart4 (\r
1955 IN DT_PORT * pPort,\r
1956 IN BOOLEAN bCloseNow,\r
1957 IN UINTN DebugFlags\r
1958 )\r
1959{\r
1960 DT_SOCKET * pSocket;\r
1961 EFI_STATUS Status;\r
1962\r
1963 DBG_ENTER ( );\r
1964\r
1965 //\r
1966 // Verify the socket layer synchronization\r
1967 //\r
1968 VERIFY_TPL ( TPL_SOCKETS );\r
1969\r
1970 //\r
1971 // Mark the port as closing\r
1972 //\r
1973 Status = EFI_ALREADY_STARTED;\r
1974 pSocket = pPort->pSocket;\r
1975 pSocket->errno = EALREADY;\r
1976 if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {\r
1977\r
1978 //\r
1979 // Update the port state\r
1980 //\r
1981 pPort->State = PORT_STATE_CLOSE_STARTED;\r
1982 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
1983 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",\r
1984 pPort ));\r
1985 pPort->bCloseNow = bCloseNow;\r
1986 pPort->DebugFlags = DebugFlags;\r
1987\r
1988 //\r
1989 // Determine if transmits are complete\r
1990 //\r
1991 Status = EslTcpPortCloseTxDone4 ( pPort );\r
1992 }\r
1993\r
1994 //\r
1995 // Return the operation status\r
1996 //\r
1997 DBG_EXIT_STATUS ( Status );\r
1998 return Status;\r
1999}\r
2000\r
2001\r
2002/**\r
2003 Port close state 3\r
2004\r
2005 Continue the close operation after the receive is complete.\r
2006\r
2007 @param [in] pPort Address of the port structure.\r
2008\r
2009 @retval EFI_SUCCESS The port is closed\r
2010 @retval EFI_NOT_READY The port is still closing\r
2011 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
2012 most likely the routine was called already.\r
2013\r
2014**/\r
2015EFI_STATUS\r
2016EslTcpPortCloseRxDone4 (\r
2017 IN DT_PORT * pPort\r
2018 )\r
2019{\r
2020 PORT_STATE PortState;\r
2021 DT_TCP4_CONTEXT * pTcp4;\r
2022 EFI_STATUS Status;\r
2023\r
2024 DBG_ENTER ( );\r
2025\r
2026 //\r
2027 // Verify the socket layer synchronization\r
2028 //\r
2029 VERIFY_TPL ( TPL_SOCKETS );\r
2030\r
2031 //\r
2032 // Verify that the port is closing\r
2033 //\r
2034 Status = EFI_ALREADY_STARTED;\r
2035 PortState = pPort->State;\r
2036 if (( PORT_STATE_CLOSE_TX_DONE == PortState )\r
2037 || ( PORT_STATE_CLOSE_DONE == PortState )) {\r
2038 //\r
2039 // Determine if the receive operation is pending\r
2040 //\r
2041 Status = EFI_NOT_READY;\r
2042 pTcp4 = &pPort->Context.Tcp4;\r
2043 if ( NULL == pTcp4->pReceivePending ) {\r
2044 //\r
2045 // The receive operation is complete\r
2046 // Update the port state\r
2047 //\r
2048 pPort->State = PORT_STATE_CLOSE_RX_DONE;\r
2049 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
2050 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",\r
2051 pPort ));\r
2052\r
2053 //\r
2054 // Determine if the close operation has completed\r
2055 //\r
2056 if ( PORT_STATE_CLOSE_DONE == PortState ) {\r
2057 //\r
2058 // The close operation has completed\r
2059 // Release the port resources\r
2060 //\r
2061 Status = EslTcpPortClose4 ( pPort );\r
2062 }\r
2063 else\r
2064 {\r
2065 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
2066 "0x%08x: Port Close: Close operation still pending!\r\n",\r
2067 pPort ));\r
2068 }\r
2069 }\r
2070 else {\r
2071 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
2072 "0x%08x: Port Close: Receive still pending!\r\n",\r
2073 pPort ));\r
2074 }\r
2075 }\r
2076\r
2077 //\r
2078 // Return the operation status\r
2079 //\r
2080 DBG_EXIT_STATUS ( Status );\r
2081 return Status;\r
2082}\r
2083\r
2084\r
2085/**\r
2086 Port close state 2\r
2087\r
2088 Continue the close operation after the transmission is complete.\r
2089\r
2090 @param [in] pPort Address of the port structure.\r
2091\r
2092 @retval EFI_SUCCESS The port is closed, not normally returned\r
2093 @retval EFI_NOT_READY The port is still closing\r
2094 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
2095 most likely the routine was called already.\r
2096\r
2097**/\r
2098EFI_STATUS\r
2099EslTcpPortCloseTxDone4 (\r
2100 IN DT_PORT * pPort\r
2101 )\r
2102{\r
2103 DT_SOCKET * pSocket;\r
2104 DT_TCP4_CONTEXT * pTcp4;\r
2105 EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
2106 EFI_STATUS Status;\r
2107\r
2108 DBG_ENTER ( );\r
2109\r
2110 //\r
2111 // Verify the socket layer synchronization\r
2112 //\r
2113 VERIFY_TPL ( TPL_SOCKETS );\r
2114\r
2115 //\r
2116 // All transmissions are complete or must be stopped\r
2117 // Mark the port as TX complete\r
2118 //\r
2119 Status = EFI_ALREADY_STARTED;\r
2120 if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {\r
2121 //\r
2122 // Verify that the transmissions are complete\r
2123 //\r
2124 pSocket = pPort->pSocket;\r
2125 if ( pPort->bCloseNow\r
2126 || ( EFI_SUCCESS != pSocket->TxError )\r
2127 || (( 0 == pSocket->TxOobBytes )\r
2128 && ( 0 == pSocket->TxBytes ))) {\r
2129 //\r
2130 // Start the close operation on the port\r
2131 //\r
2132 pTcp4 = &pPort->Context.Tcp4;\r
2133 pTcp4->CloseToken.AbortOnClose = FALSE;\r
2134 pTcp4Protocol = pTcp4->pProtocol;\r
2135 if ( !pTcp4->bConfigured ) {\r
2136 //\r
2137 // Skip the close operation since the port is not\r
2138 // configured\r
2139 //\r
2140 // Update the port state\r
2141 //\r
2142 pPort->State = PORT_STATE_CLOSE_DONE;\r
2143 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
2144 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",\r
2145 pPort ));\r
2146 Status = EFI_SUCCESS;\r
2147 }\r
2148 else {\r
2149 //\r
2150 // Close the configured port\r
2151 //\r
2152 Status = pTcp4Protocol->Close ( pTcp4Protocol,\r
2153 &pTcp4->CloseToken );\r
2154 if ( !EFI_ERROR ( Status )) {\r
2155 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
2156 "0x%08x: Port close started\r\n",\r
2157 pPort ));\r
2158\r
2159 //\r
2160 // Update the port state\r
2161 //\r
2162 pPort->State = PORT_STATE_CLOSE_TX_DONE;\r
2163 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
2164 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",\r
2165 pPort ));\r
2166 }\r
2167 else {\r
2168 DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
2169 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",\r
2170 pPort,\r
2171 Status ));\r
2172 ASSERT ( EFI_SUCCESS == Status );\r
2173 }\r
2174 }\r
2175\r
2176 //\r
2177 // Determine if the receive operation is pending\r
2178 //\r
2179 if ( !EFI_ERROR ( Status )) {\r
2180 Status = EslTcpPortCloseRxDone4 ( pPort );\r
2181 }\r
2182 }\r
2183 else {\r
2184 //\r
2185 // Transmissions are still active, exit\r
2186 //\r
2187 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
2188 "0x%08x: Port Close: Transmits are still pending!\r\n",\r
2189 pPort ));\r
2190 Status = EFI_NOT_READY;\r
2191 pSocket->errno = EAGAIN;\r
2192 }\r
2193 }\r
2194\r
2195 //\r
2196 // Return the operation status\r
2197 //\r
2198 DBG_EXIT_STATUS ( Status );\r
2199 return Status;\r
2200}\r
2201\r
2202\r
2203/**\r
2204 Receive data from a network connection.\r
2205\r
2206\r
2207 @param [in] pSocket Address of a DT_SOCKET structure\r
2208 \r
2209 @param [in] Flags Message control flags\r
2210 \r
2211 @param [in] BufferLength Length of the the buffer\r
2212 \r
2213 @param [in] pBuffer Address of a buffer to receive the data.\r
2214 \r
2215 @param [in] pDataLength Number of received data bytes in the buffer.\r
2216\r
2217 @param [out] pAddress Network address to receive the remote system address\r
2218\r
2219 @param [in,out] pAddressLength Length of the remote network address structure\r
2220\r
2221 @retval EFI_SUCCESS - Socket data successfully received\r
2222\r
2223 **/\r
2224EFI_STATUS\r
2225EslTcpReceive4 (\r
2226 IN DT_SOCKET * pSocket,\r
2227 IN INT32 Flags,\r
2228 IN size_t BufferLength,\r
2229 IN UINT8 * pBuffer,\r
2230 OUT size_t * pDataLength,\r
2231 OUT struct sockaddr * pAddress,\r
2232 IN OUT socklen_t * pAddressLength\r
2233 )\r
2234{\r
2235 socklen_t AddressLength;\r
2236 size_t BytesToCopy;\r
2237 in_addr_t IpAddress;\r
2238 size_t LengthInBytes;\r
2239 DT_PACKET * pPacket;\r
2240 DT_PORT * pPort;\r
2241 DT_PACKET ** ppQueueHead;\r
2242 DT_PACKET ** ppQueueTail;\r
2243 struct sockaddr_in * pRemoteAddress;\r
2244 size_t * pRxDataBytes;\r
2245 DT_TCP4_CONTEXT * pTcp4;\r
2246 struct sockaddr_in RemoteAddress;\r
2247 EFI_STATUS Status;\r
2248\r
2249 DBG_ENTER ( );\r
2250\r
2251 //\r
2252 // Assume failure\r
2253 //\r
2254 Status = EFI_UNSUPPORTED;\r
2255 pSocket->errno = ENOTCONN;\r
2256\r
2257 //\r
2258 // Verify that the socket is connected\r
2259 //\r
2260 if (( SOCKET_STATE_CONNECTED == pSocket->State )\r
2261 || ( PORT_STATE_RX_ERROR == pSocket->State )) {\r
2262 //\r
2263 // Locate the port\r
2264 //\r
2265 pPort = pSocket->pPortList;\r
2266 if ( NULL != pPort ) {\r
2267 //\r
2268 // Determine the queue head\r
2269 //\r
2270 pTcp4 = &pPort->Context.Tcp4;\r
2271 if ( 0 != ( Flags & MSG_OOB )) {\r
2272 ppQueueHead = &pSocket->pRxOobPacketListHead;\r
2273 ppQueueTail = &pSocket->pRxOobPacketListTail;\r
2274 pRxDataBytes = &pSocket->RxOobBytes;\r
2275 }\r
2276 else {\r
2277 ppQueueHead = &pSocket->pRxPacketListHead;\r
2278 ppQueueTail = &pSocket->pRxPacketListTail;\r
2279 pRxDataBytes = &pSocket->RxBytes;\r
2280 }\r
2281\r
2282 //\r
2283 // Determine if there is any data on the queue\r
2284 //\r
2285 pPacket = *ppQueueHead;\r
2286 if ( NULL != pPacket ) {\r
2287 //\r
2288 // Validate the return address parameters\r
2289 //\r
2290 if (( NULL == pAddress ) || ( NULL != pAddressLength )) {\r
2291 //\r
2292 // Return the remote system address if requested\r
2293 //\r
2294 if ( NULL != pAddress ) {\r
2295 //\r
2296 // Build the remote address\r
2297 //\r
2298 ZeroMem ( &RemoteAddress, sizeof ( RemoteAddress ));\r
2299 RemoteAddress.sin_len = sizeof ( RemoteAddress );\r
2300 RemoteAddress.sin_family = AF_INET;\r
2301 IpAddress = pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3];\r
2302 IpAddress <<= 8;\r
2303 IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2];\r
2304 IpAddress <<= 8;\r
2305 IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1];\r
2306 IpAddress <<= 8;\r
2307 IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0];\r
2308 RemoteAddress.sin_addr.s_addr = IpAddress;\r
2309 RemoteAddress.sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );\r
2310\r
2311 //\r
2312 // Copy the address\r
2313 //\r
2314 pRemoteAddress = (struct sockaddr_in *)pAddress;\r
2315 AddressLength = sizeof ( *pRemoteAddress );\r
2316 if ( AddressLength > *pAddressLength ) {\r
2317 AddressLength = *pAddressLength;\r
2318 }\r
2319 CopyMem ( pRemoteAddress,\r
2320 &RemoteAddress,\r
2321 AddressLength );\r
2322\r
2323 //\r
2324 // Update the address length\r
2325 //\r
2326 *pAddressLength = AddressLength;\r
2327 }\r
2328\r
2329 //\r
2330 // Copy the received data\r
2331 //\r
2332 LengthInBytes = 0;\r
2333 do {\r
2334 //\r
2335 // Determine the amount of received data\r
2336 //\r
2337 BytesToCopy = pPacket->Op.Tcp4Rx.ValidBytes;\r
2338 if (( BufferLength - LengthInBytes ) < BytesToCopy ) {\r
2339 BytesToCopy = BufferLength - LengthInBytes;\r
2340 }\r
2341 LengthInBytes += BytesToCopy;\r
2342\r
2343 //\r
2344 // Move the data into the buffer\r
2345 //\r
2346 DEBUG (( DEBUG_RX,\r
2347 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",\r
2348 pPort,\r
2349 pPacket,\r
2350 pBuffer,\r
2351 BytesToCopy ));\r
2352 CopyMem ( pBuffer, pPacket->Op.Tcp4Rx.pBuffer, BytesToCopy );\r
2353\r
2354 //\r
2355 // Determine if the data is being read\r
2356 //\r
2357 if ( 0 == ( Flags & MSG_PEEK )) {\r
2358 //\r
2359 // Account for the bytes consumed\r
2360 //\r
2361 pPacket->Op.Tcp4Rx.pBuffer += BytesToCopy;\r
2362 pPacket->Op.Tcp4Rx.ValidBytes -= BytesToCopy;\r
2363 *pRxDataBytes -= BytesToCopy;\r
2364 DEBUG (( DEBUG_RX,\r
2365 "0x%08x: Port account for 0x%08x bytes\r\n",\r
2366 pPort,\r
2367 BytesToCopy ));\r
2368\r
2369 //\r
2370 // Determine if the entire packet was consumed\r
2371 //\r
2372 if (( 0 == pPacket->Op.Tcp4Rx.ValidBytes )\r
2373 || ( SOCK_STREAM != pSocket->Type )) {\r
2374 //\r
2375 // All done with this packet\r
2376 // Account for any discarded data\r
2377 //\r
2378 *pRxDataBytes -= pPacket->Op.Tcp4Rx.ValidBytes;\r
2379 if ( 0 != pPacket->Op.Tcp4Rx.ValidBytes ) {\r
2380 DEBUG (( DEBUG_RX,\r
2381 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",\r
2382 pPort,\r
2383 pPacket->Op.Tcp4Rx.ValidBytes ));\r
2384 }\r
2385\r
2386 //\r
2387 // Remove this packet from the queue\r
2388 //\r
2389 *ppQueueHead = pPacket->pNext;\r
2390 if ( NULL == *ppQueueHead ) {\r
2391 *ppQueueTail = NULL;\r
2392 }\r
2393\r
2394 //\r
2395 // Move the packet to the free queue\r
2396 //\r
2397 pPacket->pNext = pSocket->pRxFree;\r
2398 pSocket->pRxFree = pPacket;\r
2399 DEBUG (( DEBUG_RX,\r
2400 "0x%08x: Port freeing packet 0x%08x\r\n",\r
2401 pPort,\r
2402 pPacket ));\r
2403\r
2404 //\r
2405 // Restart this receive operation if necessary\r
2406 //\r
2407 if (( NULL == pTcp4->pReceivePending )\r
2408 && ( MAX_RX_DATA > pSocket->RxBytes )) {\r
2409 EslTcpRxStart4 ( pPort );\r
2410 }\r
2411 }\r
2412 }\r
2413\r
2414 //\r
2415 // Get the next packet\r
2416 //\r
2417 pPacket = *ppQueueHead;\r
2418 } while (( SOCK_STREAM == pSocket->Type )\r
2419 && ( NULL != pPacket )\r
2420 && ( 0 == ( Flags & MSG_PEEK ))\r
2421 && ( BufferLength > LengthInBytes ));\r
2422\r
2423 //\r
2424 // Return the data length\r
2425 //\r
2426 *pDataLength = LengthInBytes;\r
2427\r
2428 //\r
2429 // Successful operation\r
2430 //\r
2431 Status = EFI_SUCCESS;\r
2432 pSocket->errno = 0;\r
2433 }\r
2434 else {\r
2435 //\r
2436 // Bad return address pointer and length\r
2437 //\r
2438 Status = EFI_INVALID_PARAMETER;\r
2439 pSocket->errno = EINVAL;\r
2440 }\r
2441 }\r
2442 else {\r
2443 //\r
2444 // The queue is empty\r
2445 // Determine if it is time to return the receive error\r
2446 //\r
2447 if ( EFI_ERROR ( pSocket->RxError )\r
2448 && ( NULL == pSocket->pRxPacketListHead )\r
2449 && ( NULL == pSocket->pRxOobPacketListHead )) {\r
2450 Status = pSocket->RxError;\r
2451 pSocket->RxError = EFI_SUCCESS;\r
2452 switch ( Status ) {\r
2453 default:\r
2454 pSocket->errno = EIO;\r
2455 break;\r
2456 \r
2457 case EFI_CONNECTION_FIN:\r
2458 //\r
2459 // Continue to return zero bytes received when the\r
2460 // peer has successfully closed the connection\r
2461 //\r
2462 pSocket->RxError = EFI_CONNECTION_FIN;\r
2463 *pDataLength = 0;\r
2464 pSocket->errno = 0;\r
2465 Status = EFI_SUCCESS;\r
2466 break;\r
2467\r
2468 case EFI_CONNECTION_REFUSED:\r
2469 pSocket->errno = ECONNREFUSED;\r
2470 break;\r
2471\r
2472 case EFI_CONNECTION_RESET:\r
2473 pSocket->errno = ECONNRESET;\r
2474 break;\r
2475\r
2476 case EFI_HOST_UNREACHABLE:\r
2477 pSocket->errno = EHOSTUNREACH;\r
2478 break;\r
2479 \r
2480 case EFI_NETWORK_UNREACHABLE:\r
2481 pSocket->errno = ENETUNREACH;\r
2482 break;\r
2483 \r
2484 case EFI_PORT_UNREACHABLE:\r
2485 pSocket->errno = EPROTONOSUPPORT;\r
2486 break;\r
2487 \r
2488 case EFI_PROTOCOL_UNREACHABLE:\r
2489 pSocket->errno = ENOPROTOOPT;\r
2490 break;\r
2491 }\r
2492 }\r
2493 else {\r
2494 Status = EFI_NOT_READY;\r
2495 pSocket->errno = EAGAIN;\r
2496 }\r
2497 }\r
2498 }\r
2499 }\r
2500\r
2501 //\r
2502 // Return the operation status\r
2503 //\r
2504 DBG_EXIT_STATUS ( Status );\r
2505 return Status;\r
2506}\r
2507\r
2508\r
2509/**\r
2510 Cancel the receive operations\r
2511\r
2512 @param [in] pSocket Address of a DT_SOCKET structure\r
2513 \r
2514 @retval EFI_SUCCESS - The cancel was successful\r
2515\r
2516 **/\r
2517EFI_STATUS\r
2518EslTcpRxCancel4 (\r
2519 IN DT_SOCKET * pSocket\r
2520 )\r
2521{\r
2522 DT_PACKET * pPacket;\r
2523 DT_PORT * pPort;\r
2524 DT_TCP4_CONTEXT * pTcp4;\r
2525 EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
2526 EFI_STATUS Status;\r
2527\r
2528 DBG_ENTER ( );\r
2529\r
2530 //\r
2531 // Assume failure\r
2532 //\r
2533 Status = EFI_NOT_FOUND;\r
2534\r
2535 //\r
2536 // Locate the port\r
2537 //\r
2538 pPort = pSocket->pPortList;\r
2539 if ( NULL != pPort ) {\r
2540 //\r
2541 // Determine if a receive is pending\r
2542 //\r
2543 pTcp4 = &pPort->Context.Tcp4;\r
2544 pPacket = pTcp4->pReceivePending;\r
2545 if ( NULL != pPacket ) {\r
2546 //\r
2547 // Attempt to cancel the receive operation\r
2548 //\r
2549 pTcp4Protocol = pTcp4->pProtocol;\r
2550 Status = pTcp4Protocol->Cancel ( pTcp4Protocol,\r
2551 &pTcp4->RxToken.CompletionToken );\r
2552 if ( EFI_NOT_FOUND == Status ) {\r
2553 //\r
2554 // The receive is complete\r
2555 //\r
2556 Status = EFI_SUCCESS;\r
2557 }\r
2558 }\r
2559 }\r
2560\r
2561 //\r
2562 // Return the operation status\r
2563 //\r
2564 DBG_EXIT_STATUS ( Status );\r
2565 return Status;\r
2566}\r
2567\r
2568\r
2569/**\r
2570 Process the receive completion\r
2571\r
2572 Buffer the data that was just received.\r
2573\r
2574 @param Event The receive completion event\r
2575\r
2576 @param pPort The DT_PORT structure address\r
2577\r
2578**/\r
2579VOID\r
2580EslTcpRxComplete4 (\r
2581 IN EFI_EVENT Event,\r
2582 IN DT_PORT * pPort\r
2583 )\r
2584{\r
2585 BOOLEAN bUrgent;\r
2586 size_t LengthInBytes;\r
2587 DT_PACKET * pPacket;\r
2588 DT_PACKET * pPrevious;\r
2589 DT_SOCKET * pSocket;\r
2590 DT_TCP4_CONTEXT * pTcp4;\r
2591 EFI_STATUS Status;\r
2592\r
2593 DBG_ENTER ( );\r
2594\r
2595 //\r
2596 // Mark this receive complete\r
2597 //\r
2598 pTcp4 = &pPort->Context.Tcp4;\r
2599 pPacket = pTcp4->pReceivePending;\r
2600 pTcp4->pReceivePending = NULL;\r
2601\r
2602 //\r
2603 // Determine if this receive was successful\r
2604 //\r
2605 pSocket = pPort->pSocket;\r
2606 Status = pTcp4->RxToken.CompletionToken.Status;\r
2607 if (( !EFI_ERROR ( Status )) && ( !pSocket->bRxDisable )) {\r
2608 //\r
2609 // Set the buffer size and address\r
2610 //\r
2611 pPacket->Op.Tcp4Rx.pBuffer = pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer;\r
2612 LengthInBytes = pPacket->Op.Tcp4Rx.RxData.DataLength;\r
2613 pPacket->Op.Tcp4Rx.ValidBytes = LengthInBytes;\r
2614 pPacket->pNext = NULL;\r
2615\r
2616 //\r
2617 // Queue this packet\r
2618 //\r
2619 bUrgent = pPacket->Op.Tcp4Rx.RxData.UrgentFlag;\r
2620 if ( bUrgent ) {\r
2621 //\r
2622 // Add packet to the urgent list\r
2623 //\r
2624 pPrevious = pSocket->pRxOobPacketListTail;\r
2625 if ( NULL == pPrevious ) {\r
2626 pSocket->pRxOobPacketListHead = pPacket;\r
2627 }\r
2628 else {\r
2629 pPrevious->pNext = pPacket;\r
2630 }\r
2631 pSocket->pRxOobPacketListTail = pPacket;\r
2632\r
2633 //\r
2634 // Account for the urgent data\r
2635 //\r
2636 pSocket->RxOobBytes += LengthInBytes;\r
2637 }\r
2638 else {\r
2639 //\r
2640 // Add packet to the normal list\r
2641 //\r
2642 pPrevious = pSocket->pRxPacketListTail;\r
2643 if ( NULL == pPrevious ) {\r
2644 pSocket->pRxPacketListHead = pPacket;\r
2645 }\r
2646 else {\r
2647 pPrevious->pNext = pPacket;\r
2648 }\r
2649 pSocket->pRxPacketListTail = pPacket;\r
2650\r
2651 //\r
2652 // Account for the normal data\r
2653 //\r
2654 pSocket->RxBytes += LengthInBytes;\r
2655 }\r
2656\r
2657 //\r
2658 // Log the received data\r
2659 //\r
2660 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
2661 "0x%08x: Packet queued on port 0x%08x with 0x%08x bytes of %s data\r\n",\r
2662 pPacket,\r
2663 pPort,\r
2664 LengthInBytes,\r
2665 bUrgent ? L"urgent" : L"normal" ));\r
2666\r
2667 //\r
2668 // Attempt to restart this receive operation\r
2669 //\r
2670 if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {\r
2671 EslTcpRxStart4 ( pPort );\r
2672 }\r
2673 else {\r
2674 DEBUG (( DEBUG_RX,\r
2675 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",\r
2676 pPort,\r
2677 pSocket->RxBytes ));\r
2678 }\r
2679 }\r
2680 else\r
2681 {\r
2682 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
2683 "ERROR - Receiving packet 0x%08x, on port 0x%08x, Status:%r\r\n",\r
2684 pPacket,\r
2685 pPort,\r
2686 Status ));\r
2687\r
2688 //\r
2689 // Receive error, free the packet save the error\r
2690 //\r
2691 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
2692 if ( !EFI_ERROR ( pSocket->RxError )) {\r
2693 pSocket->RxError = Status;\r
2694 }\r
2695\r
2696 //\r
2697 // Update the port state\r
2698 //\r
2699 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
2700 EslTcpPortCloseRxDone4 ( pPort );\r
2701 }\r
2702 else {\r
2703 if ( EFI_ERROR ( Status )) {\r
2704 pPort->State = PORT_STATE_RX_ERROR;\r
2705 }\r
2706 }\r
2707 }\r
2708\r
2709 DBG_EXIT ( );\r
2710}\r
2711\r
2712\r
2713/**\r
2714 Start a receive operation\r
2715\r
2716 @param [in] pPort Address of the DT_PORT structure.\r
2717\r
2718 **/\r
2719VOID\r
2720EslTcpRxStart4 (\r
2721 IN DT_PORT * pPort\r
2722 )\r
2723{\r
2724 size_t LengthInBytes;\r
2725 DT_PACKET * pPacket;\r
2726 DT_SOCKET * pSocket;\r
2727 DT_TCP4_CONTEXT * pTcp4;\r
2728 EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
2729 EFI_STATUS Status;\r
2730\r
2731 DBG_ENTER ( );\r
2732\r
2733 //\r
2734 // Determine if a receive is already pending\r
2735 //\r
2736 Status = EFI_SUCCESS;\r
2737 pPacket = NULL;\r
2738 pSocket = pPort->pSocket;\r
2739 pTcp4 = &pPort->Context.Tcp4;\r
2740 if ( !EFI_ERROR ( pPort->pSocket->RxError )) {\r
2741 if (( NULL == pTcp4->pReceivePending )\r
2742 && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {\r
2743 //\r
2744 // Determine if there are any free packets\r
2745 //\r
2746 pPacket = pSocket->pRxFree;\r
2747 LengthInBytes = sizeof ( pPacket->Op.Tcp4Rx.Buffer );\r
2748 if ( NULL != pPacket ) {\r
2749 //\r
2750 // Remove this packet from the free list\r
2751 //\r
2752 pSocket->pRxFree = pPacket->pNext;\r
2753 DEBUG (( DEBUG_RX,\r
2754 "0x%08x: Port removed packet 0x%08x from free list\r\n",\r
2755 pPort,\r
2756 pPacket ));\r
2757 }\r
2758 else {\r
2759 //\r
2760 // Allocate a packet structure\r
2761 //\r
2762 Status = EslSocketPacketAllocate ( &pPacket,\r
2763 sizeof ( pPacket->Op.Tcp4Rx ),\r
2764 DEBUG_RX );\r
2765 if ( EFI_ERROR ( Status )) {\r
2766 pPacket = NULL;\r
2767 DEBUG (( DEBUG_ERROR | DEBUG_RX,\r
2768 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",\r
2769 pPort,\r
2770 Status ));\r
2771 }\r
2772 }\r
2773\r
2774 //\r
2775 // Determine if a packet is available\r
2776 //\r
2777 if ( NULL != pPacket ) {\r
2778 //\r
2779 // Initialize the buffer for receive\r
2780 //\r
2781 pTcp4->RxToken.Packet.RxData = &pPacket->Op.Tcp4Rx.RxData;\r
2782 pPacket->Op.Tcp4Rx.RxData.DataLength = (UINT32) LengthInBytes;\r
2783 pPacket->Op.Tcp4Rx.RxData.FragmentCount = 1;\r
2784 pPacket->Op.Tcp4Rx.RxData.FragmentTable [0].FragmentLength = (UINT32) LengthInBytes;\r
2785 pPacket->Op.Tcp4Rx.RxData.FragmentTable [0].FragmentBuffer = &pPacket->Op.Tcp4Rx.Buffer [0];\r
2786 pTcp4->pReceivePending = pPacket;\r
2787\r
2788 //\r
2789 // Start the receive on the packet\r
2790 //\r
2791 pTcp4Protocol = pTcp4->pProtocol;\r
2792 Status = pTcp4Protocol->Receive ( pTcp4Protocol,\r
2793 &pTcp4->RxToken );\r
2794 if ( !EFI_ERROR ( Status )) {\r
2795 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
2796 "0x%08x: Packet receive pending on port 0x%08x\r\n",\r
2797 pPacket,\r
2798 pPort ));\r
2799 }\r
2800 else {\r
2801 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
2802 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",\r
2803 pPort,\r
2804 Status ));\r
2805 pTcp4->pReceivePending = NULL;\r
2806 if ( !EFI_ERROR ( pSocket->RxError )) {\r
2807 //\r
2808 // Save the error status\r
2809 //\r
2810 pSocket->RxError = Status;\r
2811 }\r
2812 }\r
2813 }\r
2814 }\r
2815 }\r
2816\r
2817 DBG_EXIT ( );\r
2818}\r
2819\r
2820\r
2821/**\r
2822 Shutdown the TCP4 service.\r
2823\r
2824 This routine undoes the work performed by ::TcpInitialize4.\r
2825\r
2826 @param [in] pService DT_SERVICE structure address\r
2827\r
2828**/\r
2829VOID\r
2830EFIAPI\r
2831EslTcpShutdown4 (\r
2832 IN DT_SERVICE * pService\r
2833 )\r
2834{\r
2835 DT_LAYER * pLayer;\r
2836 DT_PORT * pPort;\r
2837 DT_SERVICE * pPreviousService;\r
2838\r
2839 DBG_ENTER ( );\r
2840\r
2841 //\r
2842 // Verify the socket layer synchronization\r
2843 //\r
2844 VERIFY_TPL ( TPL_SOCKETS );\r
2845\r
2846 //\r
2847 // Walk the list of ports\r
2848 //\r
2849 do {\r
2850 pPort = pService->pPortList;\r
2851 if ( NULL != pPort ) {\r
2852 //\r
2853 // Remove the port from the port list\r
2854 //\r
2855 pService->pPortList = pPort->pLinkService;\r
2856\r
2857 //\r
2858 // Close the port\r
2859 // TODO: Fix this\r
2860 //\r
2861// pPort->pfnClosePort ( pPort, DEBUG_LISTEN | DEBUG_CONNECTION );\r
2862 }\r
2863 } while ( NULL != pPort );\r
2864\r
2865 //\r
2866 // Remove the service from the service list\r
2867 //\r
2868 pLayer = &mEslLayer;\r
2869 pPreviousService = pLayer->pTcp4List;\r
2870 if ( pService == pPreviousService ) {\r
2871 //\r
2872 // Remove the service from the beginning of the list\r
2873 //\r
2874 pLayer->pTcp4List = pService->pNext;\r
2875 }\r
2876 else {\r
2877 //\r
2878 // Remove the service from the middle of the list\r
2879 //\r
2880 while ( NULL != pPreviousService ) {\r
2881 if ( pService == pPreviousService->pNext ) {\r
2882 pPreviousService->pNext = pService->pNext;\r
2883 break;\r
2884 }\r
2885 }\r
2886 }\r
2887\r
2888 DBG_EXIT ( );\r
2889}\r
2890\r
2891\r
2892/**\r
2893 Determine if the socket is configured.\r
2894\r
2895\r
2896 @param [in] pSocket Address of a DT_SOCKET structure\r
2897 \r
2898 @retval EFI_SUCCESS - The port is connected\r
2899 @retval EFI_NOT_STARTED - The port is not connected\r
2900\r
2901 **/\r
2902 EFI_STATUS\r
2903 EslTcpSocketIsConfigured4 (\r
2904 IN DT_SOCKET * pSocket\r
2905 )\r
2906{\r
2907 EFI_STATUS Status;\r
2908\r
2909 DBG_ENTER ( );\r
2910\r
2911 //\r
2912 // Determine the socket configuration status\r
2913 //\r
2914 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;\r
2915\r
2916 //\r
2917 // Return the port connected state.\r
2918 //\r
2919 DBG_EXIT_STATUS ( Status );\r
2920 return Status;\r
2921}\r
2922\r
2923\r
2924/**\r
2925 Buffer data for transmission over a network connection.\r
2926\r
2927 This routine is called by the socket layer API to buffer\r
2928 data for transmission. When necessary, this routine will\r
2929 start the transmit engine that performs the data transmission\r
2930 on the network connection.\r
2931\r
2932 The transmit engine uses two queues, one for urgent (out-of-band)\r
2933 data and the other for normal data. The urgent data is provided\r
2934 to TCP as soon as it is available, allowing the TCP layer to\r
2935 schedule transmission of the urgent data between packets of normal\r
2936 data.\r
2937\r
2938 Transmission errors are returned during the next transmission or\r
2939 during the close operation. Only buffering errors are returned\r
2940 during the current transmission attempt.\r
2941\r
2942 @param [in] pSocket Address of a DT_SOCKET structure\r
2943 \r
2944 @param [in] Flags Message control flags\r
2945 \r
2946 @param [in] BufferLength Length of the the buffer\r
2947 \r
2948 @param [in] pBuffer Address of a buffer to receive the data.\r
2949 \r
2950 @param [in] pDataLength Number of received data bytes in the buffer.\r
2951\r
2952 @retval EFI_SUCCESS - Socket data successfully buffered\r
2953\r
2954 **/\r
2955EFI_STATUS\r
2956EslTcpTxBuffer4 (\r
2957 IN DT_SOCKET * pSocket,\r
2958 IN int Flags,\r
2959 IN size_t BufferLength,\r
2960 IN CONST UINT8 * pBuffer,\r
2961 OUT size_t * pDataLength\r
2962 )\r
2963{\r
2964 BOOLEAN bUrgent;\r
2965 DT_PACKET * pPacket;\r
2966 DT_PACKET * pPreviousPacket;\r
2967 DT_PACKET ** ppPacket;\r
2968 DT_PACKET ** ppQueueHead;\r
2969 DT_PACKET ** ppQueueTail;\r
2970 DT_PORT * pPort;\r
2971 DT_TCP4_CONTEXT * pTcp4;\r
2972 EFI_TCP4_IO_TOKEN * pToken;\r
2973 size_t * pTxBytes;\r
2974 EFI_TCP4_TRANSMIT_DATA * pTxData;\r
2975 EFI_STATUS Status;\r
2976 EFI_TPL TplPrevious;\r
2977\r
2978 DBG_ENTER ( );\r
2979\r
2980 //\r
2981 // Assume failure\r
2982 //\r
2983 Status = EFI_UNSUPPORTED;\r
2984 pSocket->errno = ENOTCONN;\r
2985 * pDataLength = 0;\r
2986\r
2987 //\r
2988 // Verify that the socket is connected\r
2989 //\r
2990 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
2991 //\r
2992 // Locate the port\r
2993 //\r
2994 pPort = pSocket->pPortList;\r
2995 if ( NULL != pPort ) {\r
2996 //\r
2997 // Determine the queue head\r
2998 //\r
2999 pTcp4 = &pPort->Context.Tcp4;\r
3000 bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));\r
3001 if ( bUrgent ) {\r
3002 ppQueueHead = &pSocket->pTxOobPacketListHead;\r
3003 ppQueueTail = &pSocket->pTxOobPacketListTail;\r
3004 ppPacket = &pTcp4->pTxOobPacket;\r
3005 pToken = &pTcp4->TxOobToken;\r
3006 pTxBytes = &pSocket->TxOobBytes;\r
3007 }\r
3008 else {\r
3009 ppQueueHead = &pSocket->pTxPacketListHead;\r
3010 ppQueueTail = &pSocket->pTxPacketListTail;\r
3011 ppPacket = &pTcp4->pTxPacket;\r
3012 pToken = &pTcp4->TxToken;\r
3013 pTxBytes = &pSocket->TxBytes;\r
3014 }\r
3015\r
3016 //\r
3017 // Verify that there is enough room to buffer another\r
3018 // transmit operation\r
3019 //\r
3020 if ( pSocket->MaxTxBuf > *pTxBytes ) {\r
3021 //\r
3022 // Attempt to allocate the packet\r
3023 //\r
3024 Status = EslSocketPacketAllocate ( &pPacket,\r
3025 sizeof ( pPacket->Op.Tcp4Tx )\r
3026 - sizeof ( pPacket->Op.Tcp4Tx.Buffer )\r
3027 + BufferLength,\r
3028 DEBUG_TX );\r
3029 if ( !EFI_ERROR ( Status )) {\r
3030 //\r
3031 // Initialize the transmit operation\r
3032 //\r
3033 pTxData = &pPacket->Op.Tcp4Tx.TxData;\r
3034 pTxData->Push = TRUE;\r
3035 pTxData->Urgent = bUrgent;\r
3036 pTxData->DataLength = (UINT32) BufferLength;\r
3037 pTxData->FragmentCount = 1;\r
3038 pTxData->FragmentTable[0].FragmentLength = (UINT32) BufferLength;\r
3039 pTxData->FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Tx.Buffer[0];\r
3040\r
3041 //\r
3042 // Copy the data into the buffer\r
3043 //\r
3044 CopyMem ( &pPacket->Op.Tcp4Tx.Buffer[0],\r
3045 pBuffer,\r
3046 BufferLength );\r
3047\r
3048 //\r
3049 // Synchronize with the socket layer\r
3050 //\r
3051 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
3052\r
3053 //\r
3054 // Stop transmission after an error\r
3055 //\r
3056 if ( !EFI_ERROR ( pSocket->TxError )) {\r
3057 //\r
3058 // Display the request\r
3059 //\r
3060 DEBUG (( DEBUG_TX,\r
3061 "Send %d %s bytes from 0x%08x\r\n",\r
3062 BufferLength,\r
3063 bUrgent ? L"urgent" : L"normal",\r
3064 pBuffer ));\r
3065\r
3066 //\r
3067 // Queue the data for transmission\r
3068 //\r
3069 pPacket->pNext = NULL;\r
3070 pPreviousPacket = *ppQueueTail;\r
3071 if ( NULL == pPreviousPacket ) {\r
3072 *ppQueueHead = pPacket;\r
3073 }\r
3074 else {\r
3075 pPreviousPacket->pNext = pPacket;\r
3076 }\r
3077 *ppQueueTail = pPacket;\r
3078 DEBUG (( DEBUG_TX,\r
3079 "0x%08x: Packet on %s transmit list\r\n",\r
3080 pPacket,\r
3081 bUrgent ? L"urgent" : L"normal" ));\r
3082\r
3083 //\r
3084 // Account for the buffered data\r
3085 //\r
3086 *pTxBytes += BufferLength;\r
3087 *pDataLength = BufferLength;\r
3088\r
3089 //\r
3090 // Start the transmit engine if it is idle\r
3091 //\r
3092 if ( NULL == *ppPacket ) {\r
3093 EslTcpTxStart4 ( pSocket->pPortList,\r
3094 pToken,\r
3095 ppQueueHead,\r
3096 ppQueueTail,\r
3097 ppPacket );\r
3098 }\r
3099 }\r
3100 else {\r
3101 //\r
3102 // Previous transmit error\r
3103 // Stop transmission\r
3104 //\r
3105 Status = pSocket->TxError;\r
3106 pSocket->errno = EIO;\r
3107\r
3108 //\r
3109 // Free the packet\r
3110 //\r
3111 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
3112 }\r
3113\r
3114 //\r
3115 // Release the socket layer synchronization\r
3116 //\r
3117 RESTORE_TPL ( TplPrevious );\r
3118 }\r
3119 else {\r
3120 //\r
3121 // Packet allocation failed\r
3122 //\r
3123 pSocket->errno = ENOMEM;\r
3124 }\r
3125 }\r
3126 else {\r
3127 //\r
3128 // Not enough buffer space available\r
3129 //\r
3130 pSocket->errno = EAGAIN;\r
3131 Status = EFI_NOT_READY;\r
3132 }\r
3133 }\r
3134 }\r
3135\r
3136 //\r
3137 // Return the operation status\r
3138 //\r
3139 DBG_EXIT_STATUS ( Status );\r
3140 return Status;\r
3141}\r
3142\r
3143\r
3144/**\r
3145 Process the normal data transmit completion\r
3146\r
3147 @param Event The normal transmit completion event\r
3148\r
3149 @param pPort The DT_PORT structure address\r
3150\r
3151**/\r
3152VOID\r
3153EslTcpTxComplete4 (\r
3154 IN EFI_EVENT Event,\r
3155 IN DT_PORT * pPort\r
3156 )\r
3157{\r
3158 UINT32 LengthInBytes;\r
3159 DT_PACKET * pCurrentPacket;\r
3160 DT_PACKET * pNextPacket;\r
3161 DT_PACKET * pPacket;\r
3162 DT_SOCKET * pSocket;\r
3163 DT_TCP4_CONTEXT * pTcp4;\r
3164 EFI_STATUS Status;\r
3165 \r
3166 DBG_ENTER ( );\r
3167 \r
3168 //\r
3169 // Locate the active transmit packet\r
3170 //\r
3171 pSocket = pPort->pSocket;\r
3172 pTcp4 = &pPort->Context.Tcp4;\r
3173 pPacket = pTcp4->pTxPacket;\r
3174 \r
3175 //\r
3176 // Mark this packet as complete\r
3177 //\r
3178 pTcp4->pTxPacket = NULL;\r
3179 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;\r
3180 pSocket->TxBytes -= LengthInBytes;\r
3181 \r
3182 //\r
3183 // Save any transmit error\r
3184 //\r
3185 Status = pTcp4->TxToken.CompletionToken.Status;\r
3186 if ( EFI_ERROR ( Status )) {\r
3187 if ( !EFI_ERROR ( pSocket->TxError )) {\r
3188 pSocket->TxError = Status;\r
3189 }\r
3190 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
3191 "ERROR - Transmit failure for packet 0x%08x, Status: %r\r\n",\r
3192 pPacket,\r
3193 Status ));\r
3194\r
3195 //\r
3196 // Empty the normal transmit list\r
3197 //\r
3198 pCurrentPacket = pPacket;\r
3199 pNextPacket = pSocket->pTxPacketListHead;\r
3200 while ( NULL != pNextPacket ) {\r
3201 pPacket = pNextPacket;\r
3202 pNextPacket = pPacket->pNext;\r
3203 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
3204 }\r
3205 pSocket->pTxPacketListHead = NULL;\r
3206 pSocket->pTxPacketListTail = NULL;\r
3207 pPacket = pCurrentPacket;\r
3208 }\r
3209 else\r
3210 {\r
3211 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
3212 "0x%08x: Packet transmitted %d bytes successfully\r\n",\r
3213 pPacket,\r
3214 LengthInBytes ));\r
3215\r
3216 //\r
3217 // Verify the transmit engine is still running\r
3218 //\r
3219 if ( !pPort->bCloseNow ) {\r
3220 //\r
3221 // Start the next packet transmission\r
3222 //\r
3223 EslTcpTxStart4 ( pPort,\r
3224 &pTcp4->TxToken,\r
3225 &pSocket->pTxPacketListHead,\r
3226 &pSocket->pTxPacketListTail,\r
3227 &pTcp4->pTxPacket );\r
3228 }\r
3229 }\r
3230\r
3231 //\r
3232 // Release this packet\r
3233 //\r
3234 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
3235\r
3236 //\r
3237 // Finish the close operation if necessary\r
3238 //\r
3239 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
3240 //\r
3241 // Indicate that the transmit is complete\r
3242 //\r
3243 EslTcpPortCloseTxDone4 ( pPort );\r
3244 }\r
3245 DBG_EXIT ( );\r
3246}\r
3247\r
3248\r
3249/**\r
3250 Process the urgent data transmit completion\r
3251\r
3252 @param Event The urgent transmit completion event\r
3253\r
3254 @param pPort The DT_PORT structure address\r
3255\r
3256**/\r
3257VOID\r
3258EslTcpTxOobComplete4 (\r
3259 IN EFI_EVENT Event,\r
3260 IN DT_PORT * pPort\r
3261 )\r
3262{\r
3263 UINT32 LengthInBytes;\r
3264 DT_PACKET * pCurrentPacket;\r
3265 DT_PACKET * pNextPacket;\r
3266 DT_PACKET * pPacket;\r
3267 DT_SOCKET * pSocket;\r
3268 DT_TCP4_CONTEXT * pTcp4;\r
3269 EFI_STATUS Status;\r
3270\r
3271 DBG_ENTER ( );\r
3272\r
3273 //\r
3274 // Locate the active transmit packet\r
3275 //\r
3276 pSocket = pPort->pSocket;\r
3277 pTcp4 = &pPort->Context.Tcp4;\r
3278 pPacket = pTcp4->pTxOobPacket;\r
3279\r
3280 //\r
3281 // Mark this packet as complete\r
3282 //\r
3283 pTcp4->pTxOobPacket = NULL;\r
3284 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;\r
3285 pSocket->TxOobBytes -= LengthInBytes;\r
3286\r
3287 //\r
3288 // Save any transmit error\r
3289 //\r
3290 Status = pTcp4->TxOobToken.CompletionToken.Status;\r
3291 if ( EFI_ERROR ( Status )) {\r
3292 if ( !EFI_ERROR ( Status )) {\r
3293 pSocket->TxError = Status;\r
3294 }\r
3295 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
3296 "ERROR - Transmit failure for urgent packet 0x%08x, Status: %r\r\n",\r
3297 pPacket,\r
3298 Status ));\r
3299\r
3300\r
3301 //\r
3302 // Empty the OOB transmit list\r
3303 //\r
3304 pCurrentPacket = pPacket;\r
3305 pNextPacket = pSocket->pTxOobPacketListHead;\r
3306 while ( NULL != pNextPacket ) {\r
3307 pPacket = pNextPacket;\r
3308 pNextPacket = pPacket->pNext;\r
3309 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
3310 }\r
3311 pSocket->pTxOobPacketListHead = NULL;\r
3312 pSocket->pTxOobPacketListTail = NULL;\r
3313 pPacket = pCurrentPacket;\r
3314 }\r
3315 else\r
3316 {\r
3317 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
3318 "0x%08x: Urgent packet transmitted %d bytes successfully\r\n",\r
3319 pPacket,\r
3320 LengthInBytes ));\r
3321\r
3322 //\r
3323 // Verify the transmit engine is still running\r
3324 //\r
3325 if ( !pPort->bCloseNow ) {\r
3326 //\r
3327 // Start the next packet transmission\r
3328 //\r
3329 EslTcpTxStart4 ( pPort,\r
3330 &pTcp4->TxOobToken,\r
3331 &pSocket->pTxOobPacketListHead,\r
3332 &pSocket->pTxOobPacketListTail,\r
3333 &pTcp4->pTxOobPacket );\r
3334 }\r
3335 }\r
3336\r
3337 //\r
3338 // Release this packet\r
3339 //\r
3340 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
3341\r
3342 //\r
3343 // Finish the close operation if necessary\r
3344 //\r
3345 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
3346 //\r
3347 // Indicate that the transmit is complete\r
3348 //\r
3349 EslTcpPortCloseTxDone4 ( pPort );\r
3350 }\r
3351 DBG_EXIT ( );\r
3352}\r
3353\r
3354\r
3355/**\r
3356 Transmit data using a network connection.\r
3357\r
3358\r
3359 @param [in] pPort Address of a DT_PORT structure\r
3360 @param [in] pToken Address of either the OOB or normal transmit token\r
3361 @param [in] ppQueueHead Transmit queue head address\r
3362 @param [in] ppQueueTail Transmit queue tail address\r
3363 @param [in] ppPacket Active transmit packet address\r
3364\r
3365 **/\r
3366VOID\r
3367EslTcpTxStart4 (\r
3368 IN DT_PORT * pPort,\r
3369 IN EFI_TCP4_IO_TOKEN * pToken,\r
3370 IN DT_PACKET ** ppQueueHead,\r
3371 IN DT_PACKET ** ppQueueTail,\r
3372 IN DT_PACKET ** ppPacket\r
3373 )\r
3374{\r
3375 DT_PACKET * pNextPacket;\r
3376 DT_PACKET * pPacket;\r
3377 DT_SOCKET * pSocket;\r
3378 EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
3379 EFI_STATUS Status;\r
3380\r
3381 DBG_ENTER ( );\r
3382\r
3383 //\r
3384 // Assume success\r
3385 //\r
3386 Status = EFI_SUCCESS;\r
3387\r
3388 //\r
3389 // Get the packet from the queue head\r
3390 //\r
3391 pPacket = *ppQueueHead;\r
3392 if ( NULL != pPacket ) {\r
3393 //\r
3394 // Remove the packet from the queue\r
3395 //\r
3396 pNextPacket = pPacket->pNext;\r
3397 *ppQueueHead = pNextPacket;\r
3398 if ( NULL == pNextPacket ) {\r
3399 *ppQueueTail = NULL;\r
3400 }\r
3401\r
3402 //\r
3403 // Set the packet as active\r
3404 //\r
3405 *ppPacket = pPacket;\r
3406\r
3407 //\r
3408 // Start the transmit operation\r
3409 //\r
3410 pTcp4Protocol = pPort->Context.Tcp4.pProtocol;\r
3411 pToken->Packet.TxData = &pPacket->Op.Tcp4Tx.TxData;\r
3412 Status = pTcp4Protocol->Transmit ( pTcp4Protocol, pToken );\r
3413 if ( EFI_ERROR ( Status )) {\r
3414 pSocket = pPort->pSocket;\r
3415 if ( EFI_SUCCESS == pSocket->TxError ) {\r
3416 pSocket->TxError = Status;\r
3417 }\r
3418 }\r
3419 }\r
3420\r
3421 DBG_EXIT ( );\r
3422}\r