1 /** @file
2 Interface function of the Socket.
3
4 Copyright (c) 2009 - 2012, 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
SockTokenExistedInList(IN LIST_ENTRY * List,IN EFI_EVENT Event)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
SockTokenExisted(IN SOCKET * Sock,IN EFI_EVENT Event)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 *
SockBufferToken(IN SOCKET * Sock,IN LIST_ENTRY * List,IN VOID * Token,IN UINT32 DataLen)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
SockDestroyChild(IN OUT SOCKET * Sock)141 SockDestroyChild (
142 IN OUT SOCKET *Sock
143 )
144 {
145 EFI_STATUS Status;
146
147 ASSERT ((Sock != NULL) && (Sock->ProtoHandler != NULL));
148
149 if (Sock->InDestroy) {
150 return EFI_SUCCESS;
151 }
152
153 Sock->InDestroy = TRUE;
154
155 Status = EfiAcquireLockOrFail (&(Sock->Lock));
156 if (EFI_ERROR (Status)) {
157
158 DEBUG (
159 (EFI_D_ERROR,
160 "SockDestroyChild: Get the lock to access socket failed with %r\n",
161 Status)
162 );
163
164 return EFI_ACCESS_DENIED;
165 }
166
167 //
168 // force protocol layer to detach the PCB
169 //
170 Status = Sock->ProtoHandler (Sock, SOCK_DETACH, NULL);
171
172 if (EFI_ERROR (Status)) {
173
174 DEBUG (
175 (EFI_D_ERROR,
176 "SockDestroyChild: Protocol detach socket failed with %r\n",
177 Status)
178 );
179
180 Sock->InDestroy = FALSE;
181 } else if (SOCK_IS_CONFIGURED (Sock)) {
182
183 SockConnFlush (Sock);
184 SockSetState (Sock, SO_CLOSED);
185
186 Sock->ConfigureState = SO_UNCONFIGURED;
187 }
188
189 EfiReleaseLock (&(Sock->Lock));
190
191 if (EFI_ERROR (Status)) {
192 return Status;
193 }
194
195 SockDestroy (Sock);
196 return EFI_SUCCESS;
197 }
198
199 /**
200 Create a socket and its associated protocol control block
201 with the intial data SockInitData and protocol specific
202 data ProtoData.
203
204 @param[in] SockInitData Inital data to setting the socket.
205
206 @return Pointer to the newly created socket. If NULL, an error condition occured.
207
208 **/
209 SOCKET *
SockCreateChild(IN SOCK_INIT_DATA * SockInitData)210 SockCreateChild (
211 IN SOCK_INIT_DATA *SockInitData
212 )
213 {
214 SOCKET *Sock;
215 EFI_STATUS Status;
216
217 //
218 // create a new socket
219 //
220 Sock = SockCreate (SockInitData);
221 if (NULL == Sock) {
222
223 DEBUG (
224 (EFI_D_ERROR,
225 "SockCreateChild: No resource to create a new socket\n")
226 );
227
228 return NULL;
229 }
230
231 Status = EfiAcquireLockOrFail (&(Sock->Lock));
232 if (EFI_ERROR (Status)) {
233
234 DEBUG (
235 (EFI_D_ERROR,
236 "SockCreateChild: Get the lock to access socket failed with %r\n",
237 Status)
238 );
239
240 SockDestroy (Sock);
241 return NULL;
242 }
243 //
244 // inform the protocol layer to attach the socket
245 // with a new protocol control block
246 //
247 Status = Sock->ProtoHandler (Sock, SOCK_ATTACH, NULL);
248 EfiReleaseLock (&(Sock->Lock));
249 if (EFI_ERROR (Status)) {
250
251 DEBUG (
252 (EFI_D_ERROR,
253 "SockCreateChild: Protocol failed to attach a socket with %r\n",
254 Status)
255 );
256
257 SockDestroy (Sock);
258 Sock = NULL;
259 }
260
261 return Sock;
262 }
263
264 /**
265 Configure the specific socket Sock using configuration data ConfigData.
266
267 @param[in] Sock Pointer to the socket to be configured.
268 @param[in] ConfigData Pointer to the configuration data.
269
270 @retval EFI_SUCCESS The socket 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
SockConfigure(IN SOCKET * Sock,IN VOID * ConfigData)276 SockConfigure (
277 IN SOCKET *Sock,
278 IN VOID *ConfigData
279 )
280 {
281 EFI_STATUS Status;
282
283 Status = EfiAcquireLockOrFail (&(Sock->Lock));
284 if (EFI_ERROR (Status)) {
285
286 DEBUG (
287 (EFI_D_ERROR,
288 "SockConfigure: Get the access for socket failed with %r",
289 Status)
290 );
291
292 return EFI_ACCESS_DENIED;
293 }
294
295 if (SOCK_IS_CONFIGURED (Sock)) {
296 Status = EFI_ACCESS_DENIED;
297 goto OnExit;
298 }
299
300 ASSERT (Sock->State == SO_CLOSED);
301
302 Status = Sock->ProtoHandler (Sock, SOCK_CONFIGURE, ConfigData);
303
304 OnExit:
305 EfiReleaseLock (&(Sock->Lock));
306
307 return Status;
308 }
309
310 /**
311 Initiate a connection establishment process.
312
313 @param[in] Sock Pointer to the socket to initiate the initate the
314 connection.
315 @param[in] Token Pointer to the token used for the connection
316 operation.
317
318 @retval EFI_SUCCESS The connection initialized successfully.
319 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the
320 socket is closed, or the socket is not configured to
321 be an active one, or the token is already in one of
322 this socket's lists.
323 @retval EFI_NO_MAPPING The IP address configuration operation is not
324 finished.
325 @retval EFI_NOT_STARTED The socket is not configured.
326
327 **/
328 EFI_STATUS
SockConnect(IN SOCKET * Sock,IN VOID * Token)329 SockConnect (
330 IN SOCKET *Sock,
331 IN VOID *Token
332 )
333 {
334 EFI_STATUS Status;
335 EFI_EVENT Event;
336
337 Status = EfiAcquireLockOrFail (&(Sock->Lock));
338 if (EFI_ERROR (Status)) {
339
340 DEBUG (
341 (EFI_D_ERROR,
342 "SockConnect: Get the access for socket failed with %r",
343 Status)
344 );
345
346 return EFI_ACCESS_DENIED;
347 }
348
349 if (SOCK_IS_NO_MAPPING (Sock)) {
350 Status = EFI_NO_MAPPING;
351 goto OnExit;
352 }
353
354 if (SOCK_IS_UNCONFIGURED (Sock)) {
355
356 Status = EFI_NOT_STARTED;
357 goto OnExit;
358 }
359
360 if (!SOCK_IS_CLOSED (Sock) || !SOCK_IS_CONFIGURED_ACTIVE (Sock)) {
361
362 Status = EFI_ACCESS_DENIED;
363 goto OnExit;
364 }
365
366 Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;
367
368 if (SockTokenExisted (Sock, Event)) {
369
370 Status = EFI_ACCESS_DENIED;
371 goto OnExit;
372 }
373
374 Sock->ConnectionToken = (SOCK_COMPLETION_TOKEN *) Token;
375 SockSetState (Sock, SO_CONNECTING);
376 Status = Sock->ProtoHandler (Sock, SOCK_CONNECT, NULL);
377
378 OnExit:
379 EfiReleaseLock (&(Sock->Lock));
380 return Status;
381 }
382
383 /**
384 Issue a listen token to get an existed connected network instance
385 or wait for a connection if there is none.
386
387 @param[in] Sock Pointer to the socket to accept connections.
388 @param[in] Token The token to accept a connection.
389
390 @retval EFI_SUCCESS Either a connection is accpeted or the Token is
391 buffered for further acception.
392 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the
393 socket is closed, or the socket is not configured to
394 be a passive one, or the token is already in one of
395 this socket's lists.
396 @retval EFI_NO_MAPPING The IP address configuration operation is not
397 finished.
398 @retval EFI_NOT_STARTED The socket is not configured.
399 @retval EFI_OUT_OF_RESOURCE Failed to buffer the Token due to memory limits.
400
401 **/
402 EFI_STATUS
SockAccept(IN SOCKET * Sock,IN VOID * Token)403 SockAccept (
404 IN SOCKET *Sock,
405 IN VOID *Token
406 )
407 {
408 EFI_TCP4_LISTEN_TOKEN *ListenToken;
409 LIST_ENTRY *ListEntry;
410 EFI_STATUS Status;
411 SOCKET *Socket;
412 EFI_EVENT Event;
413
414 ASSERT (SockStream == Sock->Type);
415
416 Status = EfiAcquireLockOrFail (&(Sock->Lock));
417 if (EFI_ERROR (Status)) {
418
419 DEBUG (
420 (EFI_D_ERROR,
421 "SockAccept: Get the access for socket failed with %r",
422 Status)
423 );
424
425 return EFI_ACCESS_DENIED;
426 }
427
428 if (SOCK_IS_NO_MAPPING (Sock)) {
429 Status = EFI_NO_MAPPING;
430 goto Exit;
431 }
432
433 if (SOCK_IS_UNCONFIGURED (Sock)) {
434
435 Status = EFI_NOT_STARTED;
436 goto Exit;
437 }
438
439 if (!SOCK_IS_LISTENING (Sock)) {
440
441 Status = EFI_ACCESS_DENIED;
442 goto Exit;
443 }
444
445 Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;
446
447 if (SockTokenExisted (Sock, Event)) {
448
449 Status = EFI_ACCESS_DENIED;
450 goto Exit;
451 }
452
453 ListenToken = (EFI_TCP4_LISTEN_TOKEN *) Token;
454
455 //
456 // Check if a connection has already in this Sock->ConnectionList
457 //
458 NET_LIST_FOR_EACH (ListEntry, &Sock->ConnectionList) {
459
460 Socket = NET_LIST_USER_STRUCT (ListEntry, SOCKET, ConnectionList);
461
462 if (SOCK_IS_CONNECTED (Socket)) {
463 ListenToken->NewChildHandle = Socket->SockHandle;
464 SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);
465
466 RemoveEntryList (ListEntry);
467
468 ASSERT (Socket->Parent != NULL);
469
470 Socket->Parent->ConnCnt--;
471
472 DEBUG (
473 (EFI_D_INFO,
474 "SockAccept: Accept a socket, now conncount is %d",
475 Socket->Parent->ConnCnt)
476 );
477 Socket->Parent = NULL;
478
479 goto Exit;
480 }
481 }
482
483 //
484 // Buffer this token for latter incoming connection request
485 //
486 if (NULL == SockBufferToken (Sock, &(Sock->ListenTokenList), Token, 0)) {
487
488 Status = EFI_OUT_OF_RESOURCES;
489 }
490
491 Exit:
492 EfiReleaseLock (&(Sock->Lock));
493
494 return Status;
495 }
496
497 /**
498 Issue a token with data to the socket to send out.
499
500 @param[in] Sock Pointer to the socket to process the token with
501 data.
502 @param[in] Token The token with data that needs to send out.
503
504 @retval EFI_SUCCESS The token processed successfully.
505 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the
506 socket is closed, or the socket is not in a
507 synchronized state , or the token is already in one
508 of this socket's lists.
509 @retval EFI_NO_MAPPING The IP address configuration operation is not
510 finished.
511 @retval EFI_NOT_STARTED The socket is not configured.
512 @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limits.
513
514 **/
515 EFI_STATUS
SockSend(IN SOCKET * Sock,IN VOID * Token)516 SockSend (
517 IN SOCKET *Sock,
518 IN VOID *Token
519 )
520 {
521 SOCK_IO_TOKEN *SndToken;
522 EFI_EVENT Event;
523 UINT32 FreeSpace;
524 EFI_TCP4_TRANSMIT_DATA *TxData;
525 EFI_STATUS Status;
526 SOCK_TOKEN *SockToken;
527 UINT32 DataLen;
528
529 ASSERT (SockStream == Sock->Type);
530
531 Status = EfiAcquireLockOrFail (&(Sock->Lock));
532 if (EFI_ERROR (Status)) {
533
534 DEBUG (
535 (EFI_D_ERROR,
536 "SockSend: Get the access for socket failed with %r",
537 Status)
538 );
539
540 return EFI_ACCESS_DENIED;
541 }
542
543 if (SOCK_IS_NO_MAPPING (Sock)) {
544 Status = EFI_NO_MAPPING;
545 goto Exit;
546 }
547
548 SndToken = (SOCK_IO_TOKEN *) Token;
549 TxData = (EFI_TCP4_TRANSMIT_DATA *) SndToken->Packet.TxData;
550
551 if (SOCK_IS_UNCONFIGURED (Sock)) {
552 Status = EFI_NOT_STARTED;
553 goto Exit;
554 }
555
556 if (!(SOCK_IS_CONNECTING (Sock) || SOCK_IS_CONNECTED (Sock))) {
557
558 Status = EFI_ACCESS_DENIED;
559 goto Exit;
560 }
561
562 //
563 // check if a token is already in the token buffer
564 //
565 Event = SndToken->Token.Event;
566
567 if (SockTokenExisted (Sock, Event)) {
568 Status = EFI_ACCESS_DENIED;
569 goto Exit;
570 }
571
572 DataLen = TxData->DataLength;
573
574 //
575 // process this sending token now or buffer it only?
576 //
577 FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);
578
579 if ((FreeSpace < Sock->SndBuffer.LowWater) || !SOCK_IS_CONNECTED (Sock)) {
580
581 SockToken = SockBufferToken (
582 Sock,
583 &Sock->SndTokenList,
584 SndToken,
585 DataLen
586 );
587
588 if (NULL == SockToken) {
589 Status = EFI_OUT_OF_RESOURCES;
590 }
591 } else {
592
593 SockToken = SockBufferToken (
594 Sock,
595 &Sock->ProcessingSndTokenList,
596 SndToken,
597 DataLen
598 );
599
600 if (NULL == SockToken) {
601 DEBUG (
602 (EFI_D_ERROR,
603 "SockSend: Failed to buffer IO token into socket processing SndToken List\n",
604 Status)
605 );
606
607 Status = EFI_OUT_OF_RESOURCES;
608 goto Exit;
609 }
610
611 Status = SockProcessTcpSndData (Sock, TxData);
612
613 if (EFI_ERROR (Status)) {
614 DEBUG (
615 (EFI_D_ERROR,
616 "SockSend: Failed to process Snd Data\n",
617 Status)
618 );
619
620 RemoveEntryList (&(SockToken->TokenList));
621 FreePool (SockToken);
622 }
623 }
624
625 Exit:
626 EfiReleaseLock (&(Sock->Lock));
627 return Status;
628 }
629
630 /**
631 Issue a token to get data from the socket.
632
633 @param[in] Sock Pointer to the socket to get data from.
634 @param[in] Token The token to store the received data from the
635 socket.
636
637 @retval EFI_SUCCESS The token processed successfully.
638 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the
639 socket is closed, or the socket is not in a
640 synchronized state , or the token is already in one
641 of this socket's lists.
642 @retval EFI_NO_MAPPING The IP address configuration operation is not
643 finished.
644 @retval EFI_NOT_STARTED The socket is not configured.
645 @retval EFI_CONNECTION_FIN The connection is closed and there is no more data.
646 @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limit.
647
648 **/
649 EFI_STATUS
SockRcv(IN SOCKET * Sock,IN VOID * Token)650 SockRcv (
651 IN SOCKET *Sock,
652 IN VOID *Token
653 )
654 {
655 SOCK_IO_TOKEN *RcvToken;
656 UINT32 RcvdBytes;
657 EFI_STATUS Status;
658 EFI_EVENT Event;
659
660 ASSERT (SockStream == Sock->Type);
661
662 Status = EfiAcquireLockOrFail (&(Sock->Lock));
663 if (EFI_ERROR (Status)) {
664
665 DEBUG (
666 (EFI_D_ERROR,
667 "SockRcv: Get the access for socket failed with %r",
668 Status)
669 );
670
671 return EFI_ACCESS_DENIED;
672 }
673
674 if (SOCK_IS_NO_MAPPING (Sock)) {
675
676 Status = EFI_NO_MAPPING;
677 goto Exit;
678 }
679
680 if (SOCK_IS_UNCONFIGURED (Sock)) {
681
682 Status = EFI_NOT_STARTED;
683 goto Exit;
684 }
685
686 if (!(SOCK_IS_CONNECTED (Sock) || SOCK_IS_CONNECTING (Sock))) {
687
688 Status = EFI_ACCESS_DENIED;
689 goto Exit;
690 }
691
692 RcvToken = (SOCK_IO_TOKEN *) Token;
693
694 //
695 // check if a token is already in the token buffer of this socket
696 //
697 Event = RcvToken->Token.Event;
698 if (SockTokenExisted (Sock, Event)) {
699 Status = EFI_ACCESS_DENIED;
700 goto Exit;
701 }
702
703 RcvToken = (SOCK_IO_TOKEN *) Token;
704 RcvdBytes = GET_RCV_DATASIZE (Sock);
705
706 //
707 // check whether an error has happened before
708 //
709 if (EFI_ABORTED != Sock->SockError) {
710
711 SIGNAL_TOKEN (&(RcvToken->Token), Sock->SockError);
712 Sock->SockError = EFI_ABORTED;
713 goto Exit;
714 }
715
716 //
717 // check whether can not receive and there is no any
718 // data buffered in Sock->RcvBuffer
719 //
720 if (SOCK_IS_NO_MORE_DATA (Sock) && (0 == RcvdBytes)) {
721
722 Status = EFI_CONNECTION_FIN;
723 goto Exit;
724 }
725
726 if (RcvdBytes != 0) {
727 Status = SockProcessRcvToken (Sock, RcvToken);
728
729 if (EFI_ERROR (Status)) {
730 goto Exit;
731 }
732
733 Status = Sock->ProtoHandler (Sock, SOCK_CONSUMED, NULL);
734 } else {
735
736 if (NULL == SockBufferToken (Sock, &Sock->RcvTokenList, RcvToken, 0)) {
737 Status = EFI_OUT_OF_RESOURCES;
738 }
739 }
740
741 Exit:
742 EfiReleaseLock (&(Sock->Lock));
743 return Status;
744 }
745
746 /**
747 Reset the socket and its associated protocol control block.
748
749 @param[in, out] Sock Pointer to the socket to be flushed.
750
751 @retval EFI_SUCCESS The socket is flushed successfully.
752 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.
753
754 **/
755 EFI_STATUS
SockFlush(IN OUT SOCKET * Sock)756 SockFlush (
757 IN OUT SOCKET *Sock
758 )
759 {
760 EFI_STATUS Status;
761
762 ASSERT (SockStream == Sock->Type);
763
764 Status = EfiAcquireLockOrFail (&(Sock->Lock));
765 if (EFI_ERROR (Status)) {
766
767 DEBUG (
768 (EFI_D_ERROR,
769 "SockFlush: Get the access for socket failed with %r",
770 Status)
771 );
772
773 return EFI_ACCESS_DENIED;
774 }
775
776 if (!SOCK_IS_CONFIGURED (Sock)) {
777
778 Status = EFI_ACCESS_DENIED;
779 goto Exit;
780 }
781
782 Status = Sock->ProtoHandler (Sock, SOCK_FLUSH, NULL);
783 if (EFI_ERROR (Status)) {
784
785 DEBUG (
786 (EFI_D_ERROR,
787 "SockFlush: Protocol failed handling SOCK_FLUSH with %r",
788 Status)
789 );
790
791 goto Exit;
792 }
793
794 SOCK_ERROR (Sock, EFI_ABORTED);
795 SockConnFlush (Sock);
796 SockSetState (Sock, SO_CLOSED);
797
798 Sock->ConfigureState = SO_UNCONFIGURED;
799
800 Exit:
801 EfiReleaseLock (&(Sock->Lock));
802 return Status;
803 }
804
805 /**
806 Close or abort the socket associated connection.
807
808 @param[in, out] Sock Pointer to the socket of the connection to close
809 or abort.
810 @param[in] Token The token for a close operation.
811 @param[in] OnAbort TRUE for aborting the connection; FALSE to close it.
812
813 @retval EFI_SUCCESS The close or abort operation initialized
814 successfully.
815 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the
816 socket is closed, or the socket is not in a
817 synchronized state , or the token is already in one
818 of this socket's lists.
819 @retval EFI_NO_MAPPING The IP address configuration operation is not
820 finished.
821 @retval EFI_NOT_STARTED The socket is not configured.
822
823 **/
824 EFI_STATUS
SockClose(IN OUT SOCKET * Sock,IN VOID * Token,IN BOOLEAN OnAbort)825 SockClose (
826 IN OUT SOCKET *Sock,
827 IN VOID *Token,
828 IN BOOLEAN OnAbort
829 )
830 {
831 EFI_STATUS Status;
832 EFI_EVENT Event;
833
834 ASSERT (SockStream == Sock->Type);
835
836 Status = EfiAcquireLockOrFail (&(Sock->Lock));
837 if (EFI_ERROR (Status)) {
838 DEBUG (
839 (EFI_D_ERROR,
840 "SockClose: Get the access for socket failed with %r",
841 Status)
842 );
843
844 return EFI_ACCESS_DENIED;
845 }
846
847 if (SOCK_IS_NO_MAPPING (Sock)) {
848 Status = EFI_NO_MAPPING;
849 goto Exit;
850 }
851
852 if (SOCK_IS_UNCONFIGURED (Sock)) {
853 Status = EFI_NOT_STARTED;
854 goto Exit;
855 }
856
857 if (SOCK_IS_DISCONNECTING (Sock)) {
858 Status = EFI_ACCESS_DENIED;
859 goto Exit;
860 }
861
862 Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;
863
864 if (SockTokenExisted (Sock, Event)) {
865 Status = EFI_ACCESS_DENIED;
866 goto Exit;
867 }
868
869 Sock->CloseToken = Token;
870 SockSetState (Sock, SO_DISCONNECTING);
871
872 if (OnAbort) {
873 Status = Sock->ProtoHandler (Sock, SOCK_ABORT, NULL);
874 } else {
875 Status = Sock->ProtoHandler (Sock, SOCK_CLOSE, NULL);
876 }
877
878 Exit:
879 EfiReleaseLock (&(Sock->Lock));
880 return Status;
881 }
882
883 /**
884 Get the mode data of the low layer protocol.
885
886 @param[in] Sock Pointer to the socket to get mode data from.
887 @param[in, out] Mode Pointer to the data to store the low layer mode
888 information.
889
890 @retval EFI_SUCCESS The mode data was obtained successfully.
891 @retval EFI_NOT_STARTED The socket is not configured.
892
893 **/
894 EFI_STATUS
SockGetMode(IN SOCKET * Sock,IN OUT VOID * Mode)895 SockGetMode (
896 IN SOCKET *Sock,
897 IN OUT VOID *Mode
898 )
899 {
900 return Sock->ProtoHandler (Sock, SOCK_MODE, Mode);
901 }
902
903 /**
904 Configure the low level protocol to join a multicast group for
905 this socket's connection.
906
907 @param[in] Sock Pointer to the socket of the connection to join the
908 specific multicast group.
909 @param[in] GroupInfo Pointer to the multicast group info.
910
911 @retval EFI_SUCCESS The configuration completed successfully.
912 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.
913 @retval EFI_NOT_STARTED The socket is not configured.
914
915 **/
916 EFI_STATUS
SockGroup(IN SOCKET * Sock,IN VOID * GroupInfo)917 SockGroup (
918 IN SOCKET *Sock,
919 IN VOID *GroupInfo
920 )
921 {
922 EFI_STATUS Status;
923
924 Status = EfiAcquireLockOrFail (&(Sock->Lock));
925
926 if (EFI_ERROR (Status)) {
927
928 DEBUG (
929 (EFI_D_ERROR,
930 "SockGroup: Get the access for socket failed with %r",
931 Status)
932 );
933
934 return EFI_ACCESS_DENIED;
935 }
936
937 if (SOCK_IS_UNCONFIGURED (Sock)) {
938 Status = EFI_NOT_STARTED;
939 goto Exit;
940 }
941
942 Status = Sock->ProtoHandler (Sock, SOCK_GROUP, GroupInfo);
943
944 Exit:
945 EfiReleaseLock (&(Sock->Lock));
946 return Status;
947 }
948
949 /**
950 Add or remove route information in IP route table associated
951 with this socket.
952
953 @param[in] Sock Pointer to the socket associated with the IP route
954 table to operate on.
955 @param[in] RouteInfo Pointer to the route information to be processed.
956
957 @retval EFI_SUCCESS The route table updated successfully.
958 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.
959 @retval EFI_NO_MAPPING The IP address configuration operation is not
960 finished.
961 @retval EFI_NOT_STARTED The socket is not configured.
962
963 **/
964 EFI_STATUS
SockRoute(IN SOCKET * Sock,IN VOID * RouteInfo)965 SockRoute (
966 IN SOCKET *Sock,
967 IN VOID *RouteInfo
968 )
969 {
970 EFI_STATUS Status;
971
972 Status = EfiAcquireLockOrFail (&(Sock->Lock));
973 if (EFI_ERROR (Status)) {
974 DEBUG (
975 (EFI_D_ERROR,
976 "SockRoute: Get the access for socket failed with %r",
977 Status)
978 );
979
980 return EFI_ACCESS_DENIED;
981 }
982
983 if (SOCK_IS_NO_MAPPING (Sock)) {
984 Status = EFI_NO_MAPPING;
985 goto Exit;
986 }
987
988 if (SOCK_IS_UNCONFIGURED (Sock)) {
989 Status = EFI_NOT_STARTED;
990 goto Exit;
991 }
992
993 Status = Sock->ProtoHandler (Sock, SOCK_ROUTE, RouteInfo);
994
995 Exit:
996 EfiReleaseLock (&(Sock->Lock));
997 return Status;
998 }
999
1000