]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/SockInterface.c
MdeModulePkg: Fix issue the iSCSI client can not send reset packet correctly.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / SockInterface.c
CommitLineData
8a67d61d 1/** @file\r
dab714aa 2 Interface function of the Socket.\r
8a67d61d 3\r
4bb89650 4Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 5This program and the accompanying materials\r
8a67d61d 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
dfc1f033 8http://opensource.org/licenses/bsd-license.php<BR>\r
8a67d61d 9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
8a67d61d 13**/\r
14\r
15\r
16#include "SockImpl.h"\r
17\r
18\r
19/**\r
20 Check whether the Event is in the List.\r
21\r
22 @param List Pointer to the token list to be searched.\r
23 @param Event The event to be checked.\r
24\r
120db52c 25 @retval TRUE The specific Event exists in the List. \r
77f00155 26 @retval FALSE The specific Event is not in the List.\r
8a67d61d 27\r
28**/\r
8a67d61d 29BOOLEAN\r
30SockTokenExistedInList (\r
e48e37fc 31 IN LIST_ENTRY *List,\r
8a67d61d 32 IN EFI_EVENT Event\r
33 )\r
34{\r
e48e37fc 35 LIST_ENTRY *ListEntry;\r
8a67d61d 36 SOCK_TOKEN *SockToken;\r
37\r
38 NET_LIST_FOR_EACH (ListEntry, List) {\r
39 SockToken = NET_LIST_USER_STRUCT (\r
40 ListEntry,\r
41 SOCK_TOKEN,\r
42 TokenList\r
43 );\r
44\r
45 if (Event == SockToken->Token->Event) {\r
46 return TRUE;\r
47 }\r
48 }\r
49\r
50 return FALSE;\r
51}\r
52\r
53\r
54/**\r
55 Call SockTokenExistedInList() to check whether the Event is\r
56 in the related socket's lists.\r
57\r
58 @param Sock Pointer to the instance's socket.\r
59 @param Event The event to be checked.\r
60\r
77f00155 61 @retval TRUE The Event exists in related socket's lists. \r
62 @retval FALSE The Event is not in related socket's lists.\r
8a67d61d 63\r
64**/\r
65BOOLEAN\r
66SockTokenExisted (\r
67 IN SOCKET *Sock,\r
68 IN EFI_EVENT Event\r
69 )\r
70{\r
71\r
72 if (SockTokenExistedInList (&Sock->SndTokenList, Event) ||\r
73 SockTokenExistedInList (&Sock->ProcessingSndTokenList, Event) ||\r
74 SockTokenExistedInList (&Sock->RcvTokenList, Event) ||\r
120db52c 75 SockTokenExistedInList (&Sock->ListenTokenList, Event)) {\r
8a67d61d 76\r
77 return TRUE;\r
78 }\r
79\r
80 if ((Sock->ConnectionToken != NULL) &&\r
81 (Sock->ConnectionToken->Event == Event)) {\r
82\r
83 return TRUE;\r
84 }\r
85\r
86 if ((Sock->CloseToken != NULL) && (Sock->CloseToken->Event == Event)) {\r
87 return TRUE;\r
88 }\r
89\r
90 return FALSE;\r
91}\r
92\r
93\r
94/**\r
95 Buffer a token into the specific list of socket Sock.\r
96\r
97 @param Sock Pointer to the instance's socket.\r
98 @param List Pointer to the list to store the token.\r
99 @param Token Pointer to the token to be buffered.\r
100 @param DataLen The data length of the buffer contained in Token.\r
101\r
102 @return Pointer to the token that wraps Token. If NULL, error condition occurred.\r
103\r
104**/\r
105SOCK_TOKEN *\r
106SockBufferToken (\r
107 IN SOCKET *Sock,\r
e48e37fc 108 IN LIST_ENTRY *List,\r
8a67d61d 109 IN VOID *Token,\r
110 IN UINT32 DataLen\r
111 )\r
112{\r
113 SOCK_TOKEN *SockToken;\r
114\r
e48e37fc 115 SockToken = AllocatePool (sizeof (SOCK_TOKEN));\r
8a67d61d 116 if (NULL == SockToken) {\r
117\r
e48e37fc 118 DEBUG ((EFI_D_ERROR, "SockBufferIOToken: No Memory "\r
8a67d61d 119 "to allocate SockToken\n"));\r
120\r
121 return NULL;\r
122 }\r
123\r
124 SockToken->Sock = Sock;\r
125 SockToken->Token = (SOCK_COMPLETION_TOKEN *) Token;\r
126 SockToken->RemainDataLen = DataLen;\r
e48e37fc 127 InsertTailList (List, &SockToken->TokenList);\r
8a67d61d 128\r
129 return SockToken;\r
130}\r
131\r
132\r
133/**\r
75dce340 134 Destroy the socket Sock and its associated protocol control block.\r
8a67d61d 135\r
136 @param Sock The socket to be destroyed.\r
137\r
138 @retval EFI_SUCCESS The socket Sock is destroyed successfully.\r
139 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
140\r
141**/\r
142EFI_STATUS\r
143SockDestroyChild (\r
77f00155 144 IN SOCKET *Sock\r
8a67d61d 145 )\r
146{\r
4bb89650
ZL
147 EFI_STATUS Status;\r
148 TCP4_PROTO_DATA *ProtoData;\r
149 TCP_CB *Tcb;\r
150 VOID *SockProtocol;\r
8a67d61d 151\r
120db52c 152 ASSERT ((Sock != NULL) && (Sock->ProtoHandler != NULL));\r
8a67d61d 153\r
216f7970 154 if (Sock->InDestroy) {\r
8a67d61d 155 return EFI_SUCCESS;\r
156 }\r
157\r
216f7970 158 Sock->InDestroy = TRUE;\r
8a67d61d 159\r
4bb89650
ZL
160 ProtoData = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
161 Tcb = ProtoData->TcpPcb;\r
162\r
163 ASSERT (Tcb != NULL);\r
164\r
4bb89650
ZL
165 //\r
166 // Close the IP protocol.\r
167 //\r
168 gBS->CloseProtocol (\r
169 Tcb->IpInfo->ChildHandle,\r
170 &gEfiIp4ProtocolGuid,\r
171 ProtoData->TcpService->IpIo->Image,\r
172 Sock->SockHandle\r
173 );\r
174\r
175 if (Sock->DestroyCallback != NULL) {\r
176 Sock->DestroyCallback (Sock, Sock->Context);\r
177 }\r
178\r
179 //\r
180 // Retrieve the protocol installed on this sock\r
181 //\r
182 Status = gBS->OpenProtocol (\r
183 Sock->SockHandle,\r
184 &gEfiTcp4ProtocolGuid,\r
185 &SockProtocol,\r
186 Sock->DriverBinding,\r
187 Sock->SockHandle,\r
188 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
189 );\r
190\r
191 if (EFI_ERROR (Status)) {\r
192\r
193 DEBUG ((EFI_D_ERROR, "SockDestroyChild: Open protocol installed "\r
194 "on socket failed with %r\n", Status));\r
195 }\r
196\r
197 //\r
198 // Uninstall the protocol installed on this sock\r
199 // in the light of Sock->SockType\r
200 //\r
201 gBS->UninstallMultipleProtocolInterfaces (\r
202 Sock->SockHandle,\r
203 &gEfiTcp4ProtocolGuid,\r
204 SockProtocol,\r
205 NULL\r
206 );\r
207\r
e3793f98
ZL
208 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
209 if (EFI_ERROR (Status)) {\r
210\r
211 DEBUG ((EFI_D_ERROR, "SockDestroyChild: Get the lock to "\r
212 "access socket failed with %r\n", Status));\r
213\r
214 return EFI_ACCESS_DENIED;\r
215 }\r
216\r
8a67d61d 217 //\r
218 // force protocol layer to detach the PCB\r
219 //\r
220 Status = Sock->ProtoHandler (Sock, SOCK_DETACH, NULL);\r
221\r
222 if (EFI_ERROR (Status)) {\r
223\r
e48e37fc 224 DEBUG ((EFI_D_ERROR, "SockDestroyChild: Protocol detach socket"\r
8a67d61d 225 " failed with %r\n", Status));\r
226\r
216f7970 227 Sock->InDestroy = FALSE;\r
8a67d61d 228 } else if (SOCK_IS_CONFIGURED (Sock)) {\r
229\r
230 SockConnFlush (Sock);\r
231 SockSetState (Sock, SO_CLOSED);\r
232\r
233 Sock->ConfigureState = SO_UNCONFIGURED;\r
234 }\r
235\r
e48e37fc 236 EfiReleaseLock (&(Sock->Lock));\r
8a67d61d 237\r
238 if (EFI_ERROR (Status)) {\r
239 return Status;\r
240 }\r
241\r
242 SockDestroy (Sock);\r
243 return EFI_SUCCESS;\r
244}\r
245\r
246\r
247/**\r
248 Create a socket and its associated protocol control block\r
249 with the intial data SockInitData and protocol specific\r
250 data ProtoData.\r
251\r
252 @param SockInitData Inital data to setting the socket.\r
85511ddf 253 \r
8a67d61d 254 @return Pointer to the newly created socket. If NULL, error condition occured.\r
255\r
256**/\r
257SOCKET *\r
258SockCreateChild (\r
4f6e31e4 259 IN SOCK_INIT_DATA *SockInitData\r
8a67d61d 260 )\r
261{\r
262 SOCKET *Sock;\r
4bb89650 263 VOID *SockProtocol;\r
8a67d61d 264 EFI_STATUS Status;\r
265\r
8a67d61d 266 //\r
267 // create a new socket\r
268 //\r
269 Sock = SockCreate (SockInitData);\r
270 if (NULL == Sock) {\r
271\r
e48e37fc 272 DEBUG ((EFI_D_ERROR, "SockCreateChild: No resource to "\r
8a67d61d 273 "create a new socket\n"));\r
274\r
275 return NULL;\r
276 }\r
277\r
e48e37fc 278 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
8a67d61d 279 if (EFI_ERROR (Status)) {\r
280\r
e48e37fc 281 DEBUG ((EFI_D_ERROR, "SockCreateChild: Get the lock to "\r
8a67d61d 282 "access socket failed with %r\n", Status));\r
283\r
4bb89650 284 goto ERROR;\r
8a67d61d 285 }\r
286 //\r
287 // inform the protocol layer to attach the socket\r
288 // with a new protocol control block\r
289 //\r
290 Status = Sock->ProtoHandler (Sock, SOCK_ATTACH, NULL);\r
54ea3ede 291 EfiReleaseLock (&(Sock->Lock));\r
8a67d61d 292 if (EFI_ERROR (Status)) {\r
293\r
e48e37fc 294 DEBUG ((EFI_D_ERROR, "SockCreateChild: Protocol failed to"\r
8a67d61d 295 " attach a socket with %r\n", Status));\r
296\r
4bb89650 297 goto ERROR;\r
8a67d61d 298 }\r
299\r
8a67d61d 300 return Sock;\r
4bb89650
ZL
301\r
302ERROR:\r
303\r
304 if (Sock->DestroyCallback != NULL) {\r
305 Sock->DestroyCallback (Sock, Sock->Context);\r
306 }\r
307\r
308 gBS->OpenProtocol (\r
309 Sock->SockHandle,\r
310 &gEfiTcp4ProtocolGuid,\r
311 &SockProtocol,\r
312 Sock->DriverBinding,\r
313 Sock->SockHandle,\r
314 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
315 );\r
316 //\r
317 // Uninstall the protocol installed on this sock\r
318 //\r
319 gBS->UninstallMultipleProtocolInterfaces (\r
320 Sock->SockHandle,\r
321 &gEfiTcp4ProtocolGuid,\r
322 SockProtocol,\r
323 NULL\r
324 );\r
325 SockDestroy (Sock);\r
326 return NULL;\r
8a67d61d 327}\r
328\r
329\r
330/**\r
120db52c 331 Configure the specific socket Sock using configuration data ConfigData.\r
8a67d61d 332\r
333 @param Sock Pointer to the socket to be configured.\r
334 @param ConfigData Pointer to the configuration data.\r
335\r
336 @retval EFI_SUCCESS The socket is configured successfully.\r
337 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket or the\r
338 socket is already configured.\r
339\r
340**/\r
341EFI_STATUS\r
342SockConfigure (\r
343 IN SOCKET *Sock,\r
344 IN VOID *ConfigData\r
345 )\r
346{\r
347 EFI_STATUS Status;\r
348\r
e48e37fc 349 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
8a67d61d 350 if (EFI_ERROR (Status)) {\r
351\r
e48e37fc 352 DEBUG ((EFI_D_ERROR, "SockConfigure: Get the access for "\r
8a67d61d 353 "socket failed with %r", Status));\r
354\r
355 return EFI_ACCESS_DENIED;\r
356 }\r
357\r
358 if (SOCK_IS_CONFIGURED (Sock)) {\r
359 Status = EFI_ACCESS_DENIED;\r
360 goto OnExit;\r
361 }\r
362\r
363 ASSERT (Sock->State == SO_CLOSED);\r
364\r
365 Status = Sock->ProtoHandler (Sock, SOCK_CONFIGURE, ConfigData);\r
366\r
367OnExit:\r
e48e37fc 368 EfiReleaseLock (&(Sock->Lock));\r
8a67d61d 369\r
370 return Status;\r
371}\r
372\r
373\r
374/**\r
375 Initiate a connection establishment process.\r
376\r
377 @param Sock Pointer to the socket to initiate the initate the\r
378 connection.\r
379 @param Token Pointer to the token used for the connection\r
380 operation.\r
381\r
382 @retval EFI_SUCCESS The connection is initialized successfully.\r
383 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
384 socket is closed, or the socket is not configured to\r
385 be an active one, or the token is already in one of\r
386 this socket's lists.\r
387 @retval EFI_NO_MAPPING The IP address configuration operation is not\r
388 finished.\r
389 @retval EFI_NOT_STARTED The socket is not configured.\r
390\r
391**/\r
392EFI_STATUS\r
393SockConnect (\r
394 IN SOCKET *Sock,\r
395 IN VOID *Token\r
396 )\r
397{\r
398 EFI_STATUS Status;\r
399 EFI_EVENT Event;\r
400\r
e48e37fc 401 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
8a67d61d 402 if (EFI_ERROR (Status)) {\r
403\r
e48e37fc 404 DEBUG ((EFI_D_ERROR, "SockConnect: Get the access for "\r
8a67d61d 405 "socket failed with %r", Status));\r
406\r
407 return EFI_ACCESS_DENIED;\r
408 }\r
409\r
410 if (SOCK_IS_NO_MAPPING (Sock)) {\r
411 Status = EFI_NO_MAPPING;\r
412 goto OnExit;\r
413 }\r
414\r
415 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
416\r
417 Status = EFI_NOT_STARTED;\r
418 goto OnExit;\r
419 }\r
420\r
421 if (!SOCK_IS_CLOSED (Sock) || !SOCK_IS_CONFIGURED_ACTIVE (Sock)) {\r
422\r
423 Status = EFI_ACCESS_DENIED;\r
424 goto OnExit;\r
425 }\r
426\r
427 Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
428\r
429 if (SockTokenExisted (Sock, Event)) {\r
430\r
431 Status = EFI_ACCESS_DENIED;\r
432 goto OnExit;\r
433 }\r
434\r
435 Sock->ConnectionToken = (SOCK_COMPLETION_TOKEN *) Token;\r
436 SockSetState (Sock, SO_CONNECTING);\r
437 Status = Sock->ProtoHandler (Sock, SOCK_CONNECT, NULL);\r
438\r
439OnExit:\r
e48e37fc 440 EfiReleaseLock (&(Sock->Lock));\r
8a67d61d 441 return Status;\r
442}\r
443\r
444\r
445/**\r
446 Issue a listen token to get an existed connected network instance\r
447 or wait for a connection if there is none.\r
448\r
449 @param Sock Pointer to the socket to accept connections.\r
450 @param Token The token to accept a connection.\r
451\r
452 @retval EFI_SUCCESS Either a connection is accpeted or the Token is\r
453 buffered for further acception.\r
454 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
455 socket is closed, or the socket is not configured to\r
456 be a passive one, or the token is already in one of\r
457 this socket's lists.\r
458 @retval EFI_NO_MAPPING The IP address configuration operation is not\r
459 finished.\r
460 @retval EFI_NOT_STARTED The socket is not configured.\r
461 @retval EFI_OUT_OF_RESOURCE Failed to buffer the Token due to memory limit.\r
462\r
463**/\r
464EFI_STATUS\r
465SockAccept (\r
466 IN SOCKET *Sock,\r
467 IN VOID *Token\r
468 )\r
469{\r
470 EFI_TCP4_LISTEN_TOKEN *ListenToken;\r
e48e37fc 471 LIST_ENTRY *ListEntry;\r
8a67d61d 472 EFI_STATUS Status;\r
473 SOCKET *Socket;\r
474 EFI_EVENT Event;\r
475\r
f6b7393c 476 ASSERT (SockStream == Sock->Type);\r
8a67d61d 477\r
e48e37fc 478 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
8a67d61d 479 if (EFI_ERROR (Status)) {\r
480\r
e48e37fc 481 DEBUG ((EFI_D_ERROR, "SockAccept: Get the access for socket"\r
8a67d61d 482 " failed with %r", Status));\r
483\r
484 return EFI_ACCESS_DENIED;\r
485 }\r
486\r
487 if (SOCK_IS_NO_MAPPING (Sock)) {\r
488 Status = EFI_NO_MAPPING;\r
489 goto Exit;\r
490 }\r
491\r
492 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
493\r
494 Status = EFI_NOT_STARTED;\r
495 goto Exit;\r
496 }\r
497\r
498 if (!SOCK_IS_LISTENING (Sock)) {\r
499\r
500 Status = EFI_ACCESS_DENIED;\r
501 goto Exit;\r
502 }\r
503\r
504 Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
505\r
506 if (SockTokenExisted (Sock, Event)) {\r
507\r
508 Status = EFI_ACCESS_DENIED;\r
509 goto Exit;\r
510 }\r
511\r
512 ListenToken = (EFI_TCP4_LISTEN_TOKEN *) Token;\r
513\r
514 //\r
515 // Check if a connection has already in this Sock->ConnectionList\r
516 //\r
517 NET_LIST_FOR_EACH (ListEntry, &Sock->ConnectionList) {\r
518\r
519 Socket = NET_LIST_USER_STRUCT (ListEntry, SOCKET, ConnectionList);\r
520\r
521 if (SOCK_IS_CONNECTED (Socket)) {\r
522 ListenToken->NewChildHandle = Socket->SockHandle;\r
523 SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);\r
524\r
e48e37fc 525 RemoveEntryList (ListEntry);\r
8a67d61d 526\r
120db52c 527 ASSERT (Socket->Parent != NULL);\r
8a67d61d 528\r
529 Socket->Parent->ConnCnt--;\r
530\r
e48e37fc 531 DEBUG (\r
dea6914d 532 (EFI_D_NET,\r
e48e37fc 533 "SockAccept: Accept a socket, now conncount is %d",\r
534 Socket->Parent->ConnCnt)\r
8a67d61d 535 );\r
536 Socket->Parent = NULL;\r
537\r
538 goto Exit;\r
539 }\r
540 }\r
541\r
542 //\r
543 // Buffer this token for latter incoming connection request\r
544 //\r
545 if (NULL == SockBufferToken (Sock, &(Sock->ListenTokenList), Token, 0)) {\r
546\r
547 Status = EFI_OUT_OF_RESOURCES;\r
548 }\r
549\r
550Exit:\r
e48e37fc 551 EfiReleaseLock (&(Sock->Lock));\r
8a67d61d 552\r
553 return Status;\r
554}\r
555\r
556\r
557/**\r
558 Issue a token with data to the socket to send out.\r
559\r
560 @param Sock Pointer to the socket to process the token with\r
561 data.\r
562 @param Token The token with data that needs to send out.\r
563\r
564 @retval EFI_SUCCESS The token is processed successfully.\r
565 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
566 socket is closed, or the socket is not in a\r
567 synchronized state , or the token is already in one\r
568 of this socket's lists.\r
569 @retval EFI_NO_MAPPING The IP address configuration operation is not\r
570 finished.\r
571 @retval EFI_NOT_STARTED The socket is not configured.\r
572 @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limit.\r
573\r
574**/\r
575EFI_STATUS\r
576SockSend (\r
577 IN SOCKET *Sock,\r
578 IN VOID *Token\r
579 )\r
580{\r
581 SOCK_IO_TOKEN *SndToken;\r
582 EFI_EVENT Event;\r
583 UINT32 FreeSpace;\r
584 EFI_TCP4_TRANSMIT_DATA *TxData;\r
585 EFI_STATUS Status;\r
586 SOCK_TOKEN *SockToken;\r
587 UINT32 DataLen;\r
588\r
f6b7393c 589 ASSERT (SockStream == Sock->Type);\r
8a67d61d 590\r
e48e37fc 591 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
8a67d61d 592 if (EFI_ERROR (Status)) {\r
593\r
e48e37fc 594 DEBUG ((EFI_D_ERROR, "SockSend: Get the access for socket"\r
8a67d61d 595 " failed with %r", Status));\r
596\r
597 return EFI_ACCESS_DENIED;\r
598 }\r
599\r
600 if (SOCK_IS_NO_MAPPING (Sock)) {\r
601 Status = EFI_NO_MAPPING;\r
602 goto Exit;\r
603 }\r
604\r
605 SndToken = (SOCK_IO_TOKEN *) Token;\r
606 TxData = (EFI_TCP4_TRANSMIT_DATA *) SndToken->Packet.TxData;\r
607\r
608 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
609 Status = EFI_NOT_STARTED;\r
610 goto Exit;\r
611 }\r
612\r
613 if (!(SOCK_IS_CONNECTING (Sock) || SOCK_IS_CONNECTED (Sock))) {\r
614\r
615 Status = EFI_ACCESS_DENIED;\r
616 goto Exit;\r
617 }\r
618\r
619 //\r
620 // check if a token is already in the token buffer\r
621 //\r
622 Event = SndToken->Token.Event;\r
623\r
624 if (SockTokenExisted (Sock, Event)) {\r
625 Status = EFI_ACCESS_DENIED;\r
626 goto Exit;\r
627 }\r
628\r
4eb65aff 629 DataLen = (UINT32) TxData->DataLength;\r
8a67d61d 630\r
631 //\r
632 // process this sending token now or buffer it only?\r
633 //\r
634 FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);\r
635\r
636 if ((FreeSpace < Sock->SndBuffer.LowWater) || !SOCK_IS_CONNECTED (Sock)) {\r
637\r
638 SockToken = SockBufferToken (\r
639 Sock,\r
640 &Sock->SndTokenList,\r
641 SndToken,\r
642 DataLen\r
643 );\r
644\r
645 if (NULL == SockToken) {\r
646 Status = EFI_OUT_OF_RESOURCES;\r
647 }\r
648 } else {\r
649\r
650 SockToken = SockBufferToken (\r
651 Sock,\r
652 &Sock->ProcessingSndTokenList,\r
653 SndToken,\r
654 DataLen\r
655 );\r
656\r
657 if (NULL == SockToken) {\r
e48e37fc 658 DEBUG ((EFI_D_ERROR, "SockSend: Failed to buffer IO token into"\r
8a67d61d 659 " socket processing SndToken List\n", Status));\r
660\r
661 Status = EFI_OUT_OF_RESOURCES;\r
662 goto Exit;\r
663 }\r
664\r
665 Status = SockProcessTcpSndData (Sock, TxData);\r
666\r
667 if (EFI_ERROR (Status)) {\r
e48e37fc 668 DEBUG ((EFI_D_ERROR, "SockSend: Failed to process "\r
8a67d61d 669 "Snd Data\n", Status));\r
670\r
e48e37fc 671 RemoveEntryList (&(SockToken->TokenList));\r
766c7483 672 FreePool (SockToken);\r
8a67d61d 673 }\r
674 }\r
675\r
676Exit:\r
e48e37fc 677 EfiReleaseLock (&(Sock->Lock));\r
8a67d61d 678 return Status;\r
679}\r
680\r
681\r
682/**\r
683 Issue a token to get data from the socket.\r
684\r
685 @param Sock Pointer to the socket to get data from.\r
686 @param Token The token to store the received data from the\r
687 socket.\r
688\r
689 @retval EFI_SUCCESS The token is processed successfully.\r
690 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
691 socket is closed, or the socket is not in a\r
692 synchronized state , or the token is already in one\r
693 of this socket's lists.\r
694 @retval EFI_NO_MAPPING The IP address configuration operation is not\r
695 finished.\r
696 @retval EFI_NOT_STARTED The socket is not configured.\r
697 @retval EFI_CONNECTION_FIN The connection is closed and there is no more data.\r
698 @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limit.\r
699\r
700**/\r
701EFI_STATUS\r
702SockRcv (\r
703 IN SOCKET *Sock,\r
704 IN VOID *Token\r
705 )\r
706{\r
707 SOCK_IO_TOKEN *RcvToken;\r
708 UINT32 RcvdBytes;\r
709 EFI_STATUS Status;\r
710 EFI_EVENT Event;\r
711\r
f6b7393c 712 ASSERT (SockStream == Sock->Type);\r
8a67d61d 713\r
e48e37fc 714 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
8a67d61d 715 if (EFI_ERROR (Status)) {\r
716\r
e48e37fc 717 DEBUG ((EFI_D_ERROR, "SockRcv: Get the access for socket"\r
8a67d61d 718 " failed with %r", Status));\r
719\r
720 return EFI_ACCESS_DENIED;\r
721 }\r
722\r
723 if (SOCK_IS_NO_MAPPING (Sock)) {\r
724\r
725 Status = EFI_NO_MAPPING;\r
726 goto Exit;\r
727 }\r
728\r
729 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
730\r
731 Status = EFI_NOT_STARTED;\r
732 goto Exit;\r
733 }\r
734\r
735 if (!(SOCK_IS_CONNECTED (Sock) || SOCK_IS_CONNECTING (Sock))) {\r
736\r
737 Status = EFI_ACCESS_DENIED;\r
738 goto Exit;\r
739 }\r
740\r
741 RcvToken = (SOCK_IO_TOKEN *) Token;\r
742\r
743 //\r
744 // check if a token is already in the token buffer of this socket\r
745 //\r
746 Event = RcvToken->Token.Event;\r
747 if (SockTokenExisted (Sock, Event)) {\r
748 Status = EFI_ACCESS_DENIED;\r
749 goto Exit;\r
750 }\r
751\r
752 RcvToken = (SOCK_IO_TOKEN *) Token;\r
753 RcvdBytes = GET_RCV_DATASIZE (Sock);\r
754\r
755 //\r
756 // check whether an error has happened before\r
757 //\r
758 if (EFI_ABORTED != Sock->SockError) {\r
759\r
760 SIGNAL_TOKEN (&(RcvToken->Token), Sock->SockError);\r
761 Sock->SockError = EFI_ABORTED;\r
762 goto Exit;\r
763 }\r
764\r
765 //\r
766 // check whether can not receive and there is no any\r
767 // data buffered in Sock->RcvBuffer\r
768 //\r
769 if (SOCK_IS_NO_MORE_DATA (Sock) && (0 == RcvdBytes)) {\r
770\r
771 Status = EFI_CONNECTION_FIN;\r
772 goto Exit;\r
773 }\r
774\r
775 if (RcvdBytes != 0) {\r
5679a62a 776 SockProcessRcvToken (Sock, RcvToken);\r
8a67d61d 777\r
778 Status = Sock->ProtoHandler (Sock, SOCK_CONSUMED, NULL);\r
779 } else {\r
780\r
781 if (NULL == SockBufferToken (Sock, &Sock->RcvTokenList, RcvToken, 0)) {\r
782 Status = EFI_OUT_OF_RESOURCES;\r
783 }\r
784 }\r
785\r
786Exit:\r
e48e37fc 787 EfiReleaseLock (&(Sock->Lock));\r
8a67d61d 788 return Status;\r
789}\r
790\r
791\r
792/**\r
793 Reset the socket and its associated protocol control block.\r
794\r
795 @param Sock Pointer to the socket to be flushed.\r
796\r
797 @retval EFI_SUCCESS The socket is flushed successfully.\r
798 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
799\r
800**/\r
801EFI_STATUS\r
802SockFlush (\r
803 IN SOCKET *Sock\r
804 )\r
805{\r
806 EFI_STATUS Status;\r
807\r
f6b7393c 808 ASSERT (SockStream == Sock->Type);\r
8a67d61d 809\r
e48e37fc 810 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
8a67d61d 811 if (EFI_ERROR (Status)) {\r
812\r
e48e37fc 813 DEBUG ((EFI_D_ERROR, "SockFlush: Get the access for socket"\r
8a67d61d 814 " failed with %r", Status));\r
815\r
816 return EFI_ACCESS_DENIED;\r
817 }\r
818\r
819 if (!SOCK_IS_CONFIGURED (Sock)) {\r
820 goto Exit;\r
821 }\r
822\r
823 Status = Sock->ProtoHandler (Sock, SOCK_FLUSH, NULL);\r
824 if (EFI_ERROR (Status)) {\r
825\r
e48e37fc 826 DEBUG ((EFI_D_ERROR, "SockFlush: Protocol failed handling"\r
8a67d61d 827 " SOCK_FLUSH with %r", Status));\r
828\r
829 goto Exit;\r
830 }\r
831\r
832 SOCK_ERROR (Sock, EFI_ABORTED);\r
833 SockConnFlush (Sock);\r
834 SockSetState (Sock, SO_CLOSED);\r
835\r
836 Sock->ConfigureState = SO_UNCONFIGURED;\r
837\r
838Exit:\r
e48e37fc 839 EfiReleaseLock (&(Sock->Lock));\r
8a67d61d 840 return Status;\r
841}\r
842\r
843\r
844/**\r
845 Close or abort the socket associated connection.\r
846\r
847 @param Sock Pointer to the socket of the connection to close or\r
848 abort.\r
849 @param Token The token for close operation.\r
850 @param OnAbort TRUE for aborting the connection, FALSE to close it.\r
851\r
852 @retval EFI_SUCCESS The close or abort operation is initialized\r
853 successfully.\r
854 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
855 socket is closed, or the socket is not in a\r
856 synchronized state , or the token is already in one\r
857 of this socket's lists.\r
858 @retval EFI_NO_MAPPING The IP address configuration operation is not\r
859 finished.\r
860 @retval EFI_NOT_STARTED The socket is not configured.\r
861\r
862**/\r
863EFI_STATUS\r
864SockClose (\r
865 IN SOCKET *Sock,\r
866 IN VOID *Token,\r
867 IN BOOLEAN OnAbort\r
868 )\r
869{\r
870 EFI_STATUS Status;\r
871 EFI_EVENT Event;\r
872\r
f6b7393c 873 ASSERT (SockStream == Sock->Type);\r
8a67d61d 874\r
e48e37fc 875 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
8a67d61d 876 if (EFI_ERROR (Status)) {\r
e48e37fc 877 DEBUG ((EFI_D_ERROR, "SockClose: Get the access for socket"\r
8a67d61d 878 " failed with %r", Status));\r
879\r
880 return EFI_ACCESS_DENIED;\r
881 }\r
882\r
883 if (SOCK_IS_NO_MAPPING (Sock)) {\r
884 Status = EFI_NO_MAPPING;\r
885 goto Exit;\r
886 }\r
887\r
888 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
889 Status = EFI_NOT_STARTED;\r
890 goto Exit;\r
891 }\r
892\r
893 if (SOCK_IS_DISCONNECTING (Sock)) {\r
894 Status = EFI_ACCESS_DENIED;\r
895 goto Exit;\r
896 }\r
897\r
898 Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
899\r
900 if (SockTokenExisted (Sock, Event)) {\r
901 Status = EFI_ACCESS_DENIED;\r
902 goto Exit;\r
903 }\r
904\r
905 Sock->CloseToken = Token;\r
906 SockSetState (Sock, SO_DISCONNECTING);\r
907\r
908 if (OnAbort) {\r
909 Status = Sock->ProtoHandler (Sock, SOCK_ABORT, NULL);\r
910 } else {\r
911 Status = Sock->ProtoHandler (Sock, SOCK_CLOSE, NULL);\r
912 }\r
913\r
914Exit:\r
e48e37fc 915 EfiReleaseLock (&(Sock->Lock));\r
8a67d61d 916 return Status;\r
917}\r
918\r
919\r
920/**\r
921 Get the mode data of the low layer protocol.\r
922\r
923 @param Sock Pointer to the socket to get mode data from.\r
924 @param Mode Pointer to the data to store the low layer mode\r
925 information.\r
926\r
927 @retval EFI_SUCCESS The mode data is got successfully.\r
928 @retval EFI_NOT_STARTED The socket is not configured.\r
929\r
930**/\r
931EFI_STATUS\r
932SockGetMode (\r
276dcc1b 933 IN SOCKET *Sock,\r
934 IN OUT VOID *Mode\r
8a67d61d 935 )\r
936{\r
937 return Sock->ProtoHandler (Sock, SOCK_MODE, Mode);\r
938}\r
939\r
940\r
941/**\r
942 Configure the low level protocol to join a multicast group for\r
943 this socket's connection.\r
944\r
945 @param Sock Pointer to the socket of the connection to join the\r
946 specific multicast group.\r
947 @param GroupInfo Pointer to the multicast group info.\r
948\r
949 @retval EFI_SUCCESS The configuration is done successfully.\r
950 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
951 @retval EFI_NOT_STARTED The socket is not configured.\r
952\r
953**/\r
954EFI_STATUS\r
955SockGroup (\r
956 IN SOCKET *Sock,\r
957 IN VOID *GroupInfo\r
958 )\r
959{\r
960 EFI_STATUS Status;\r
961\r
e48e37fc 962 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
8a67d61d 963\r
964 if (EFI_ERROR (Status)) {\r
965\r
e48e37fc 966 DEBUG ((EFI_D_ERROR, "SockGroup: Get the access for socket"\r
8a67d61d 967 " failed with %r", Status));\r
968\r
969 return EFI_ACCESS_DENIED;\r
970 }\r
971\r
972 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
973 Status = EFI_NOT_STARTED;\r
974 goto Exit;\r
975 }\r
976\r
977 Status = Sock->ProtoHandler (Sock, SOCK_GROUP, GroupInfo);\r
978\r
979Exit:\r
e48e37fc 980 EfiReleaseLock (&(Sock->Lock));\r
8a67d61d 981 return Status;\r
982}\r
983\r
984\r
985/**\r
986 Add or remove route information in IP route table associated\r
987 with this socket.\r
988\r
989 @param Sock Pointer to the socket associated with the IP route\r
990 table to operate on.\r
991 @param RouteInfo Pointer to the route information to be processed.\r
992\r
993 @retval EFI_SUCCESS The route table is updated successfully.\r
994 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
995 @retval EFI_NO_MAPPING The IP address configuration operation is not\r
996 finished.\r
997 @retval EFI_NOT_STARTED The socket is not configured.\r
998\r
999**/\r
1000EFI_STATUS\r
1001SockRoute (\r
1002 IN SOCKET *Sock,\r
1003 IN VOID *RouteInfo\r
1004 )\r
1005{\r
1006 EFI_STATUS Status;\r
1007\r
e48e37fc 1008 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
8a67d61d 1009 if (EFI_ERROR (Status)) {\r
e48e37fc 1010 DEBUG ((EFI_D_ERROR, "SockRoute: Get the access for socket"\r
8a67d61d 1011 " failed with %r", Status));\r
1012\r
1013 return EFI_ACCESS_DENIED;\r
1014 }\r
1015\r
1016 if (SOCK_IS_NO_MAPPING (Sock)) {\r
1017 Status = EFI_NO_MAPPING;\r
1018 goto Exit;\r
1019 }\r
1020\r
1021 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
1022 Status = EFI_NOT_STARTED;\r
1023 goto Exit;\r
1024 }\r
1025\r
1026 Status = Sock->ProtoHandler (Sock, SOCK_ROUTE, RouteInfo);\r
1027\r
1028Exit:\r
e48e37fc 1029 EfiReleaseLock (&(Sock->Lock));\r
8a67d61d 1030 return Status;\r
1031}\r