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