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