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