]>
Commit | Line | Data |
---|---|---|
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 | |
38 | EFI_STATUS\r | |
39 | EslTcpAccept4 (\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 | |
126 | EFI_STATUS\r | |
127 | EslTcpBind4 (\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 | |
265 | EFI_STATUS\r | |
266 | EslTcpConnectAttempt4 (\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 | |
390 | VOID\r | |
391 | EslTcpConnectComplete4 (\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 | |
531 | EFI_STATUS\r | |
532 | EslTcpConnectPoll4 (\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 | |
631 | EFI_STATUS\r | |
632 | EslTcpConnectStart4 (\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 | |
721 | EFI_STATUS\r | |
722 | EFIAPI\r | |
723 | EslTcpInitialize4 (\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 | |
770 | EFI_STATUS\r | |
771 | EslTcpGetLocalAddress4 (\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 | |
846 | EFI_STATUS\r | |
847 | EslTcpGetRemoteAddress4 (\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 | |
925 | EFI_STATUS\r | |
926 | EslTcpListen4 (\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 | |
1140 | VOID\r | |
1141 | EslTcpListenComplete4 (\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 | |
1359 | EFI_STATUS\r | |
1360 | EslTcpPortAllocate4 (\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 | |
1613 | EFI_STATUS\r | |
1614 | EslTcpPortClose4 (\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 | |
1911 | VOID\r | |
1912 | EslTcpPortCloseComplete4 (\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 | |
1953 | EFI_STATUS\r | |
1954 | EslTcpPortCloseStart4 (\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 | |
2015 | EFI_STATUS\r | |
2016 | EslTcpPortCloseRxDone4 (\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 | |
2098 | EFI_STATUS\r | |
2099 | EslTcpPortCloseTxDone4 (\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 | |
2224 | EFI_STATUS\r | |
2225 | EslTcpReceive4 (\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 | |
2517 | EFI_STATUS\r | |
2518 | EslTcpRxCancel4 (\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 | |
2579 | VOID\r | |
2580 | EslTcpRxComplete4 (\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 | |
2719 | VOID\r | |
2720 | EslTcpRxStart4 (\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 | |
2829 | VOID\r | |
2830 | EFIAPI\r | |
2831 | EslTcpShutdown4 (\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 | |
2955 | EFI_STATUS\r | |
2956 | EslTcpTxBuffer4 (\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 | |
3152 | VOID\r | |
3153 | EslTcpTxComplete4 (\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 | |
3257 | VOID\r | |
3258 | EslTcpTxOobComplete4 (\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 | |
3366 | VOID\r | |
3367 | EslTcpTxStart4 (\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 |