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