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 / SockImpl.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   SockImpl.c\r
15 \r
16 Abstract:\r
17 \r
18 \r
19 **/\r
20 \r
21 #include "SockImpl.h"\r
22 \r
23 STATIC\r
24 UINT32\r
25 SockTcpDataToRcv (\r
26   IN  SOCK_BUFFER   *SockBuffer,\r
27   OUT BOOLEAN       *IsOOB,\r
28   IN  UINT32        BufLen\r
29   );\r
30 \r
31 STATIC\r
32 VOID\r
33 SockProcessSndToken (\r
34   IN SOCKET *Sock\r
35   );\r
36 \r
37 VOID\r
38 SockFreeFoo (\r
39   IN EFI_EVENT Event\r
40   )\r
41 {\r
42   return ;\r
43 }\r
44 \r
45 \r
46 /**\r
47   Get the length of the data that can be retrieved from the socket\r
48   receive buffer.\r
49 \r
50   @param  SockBuffer            Pointer to the socket receive buffer.\r
51   @param  IsUrg                 Pointer to a BOOLEAN variable. If TRUE the data is\r
52                                 OOB.\r
53   @param  BufLen                The maximum length of the data buffer to store the\r
54                                 received data in socket layer.\r
55 \r
56   @return The length of the data can be retreived.\r
57 \r
58 **/\r
59 STATIC\r
60 UINT32\r
61 SockTcpDataToRcv (\r
62   IN  SOCK_BUFFER    *SockBuffer,\r
63   OUT BOOLEAN        *IsUrg,\r
64   IN  UINT32         BufLen\r
65   )\r
66 {\r
67   NET_BUF       *RcvBufEntry;\r
68   UINT32        DataLen;\r
69   TCP_RSV_DATA  *TcpRsvData;\r
70   BOOLEAN       Urg;\r
71 \r
72   ASSERT (SockBuffer && IsUrg && (BufLen > 0));\r
73 \r
74   RcvBufEntry = SockBufFirst (SockBuffer);\r
75   ASSERT (RcvBufEntry);\r
76 \r
77   TcpRsvData  = (TCP_RSV_DATA *) RcvBufEntry->ProtoData;\r
78 \r
79   *IsUrg      = (BOOLEAN) ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);\r
80 \r
81   if (*IsUrg && TcpRsvData->UrgLen < RcvBufEntry->TotalSize) {\r
82 \r
83     DataLen = MIN (TcpRsvData->UrgLen, BufLen);\r
84 \r
85     if (DataLen < TcpRsvData->UrgLen) {\r
86       TcpRsvData->UrgLen = TcpRsvData->UrgLen - DataLen;\r
87     } else {\r
88       TcpRsvData->UrgLen = 0;\r
89     }\r
90 \r
91     return DataLen;\r
92 \r
93   }\r
94 \r
95   DataLen     = RcvBufEntry->TotalSize;\r
96 \r
97   RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);\r
98 \r
99   while ((BufLen > DataLen) && (RcvBufEntry != NULL)) {\r
100 \r
101     TcpRsvData  = (TCP_RSV_DATA *) RcvBufEntry->ProtoData;\r
102 \r
103     Urg         = (BOOLEAN) ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);\r
104 \r
105     if (*IsUrg != Urg) {\r
106       break;\r
107     }\r
108 \r
109     if (*IsUrg && TcpRsvData->UrgLen < RcvBufEntry->TotalSize) {\r
110 \r
111       if (TcpRsvData->UrgLen + DataLen < BufLen) {\r
112         TcpRsvData->UrgLen = 0;\r
113       } else {\r
114         TcpRsvData->UrgLen = TcpRsvData->UrgLen - (BufLen - DataLen);\r
115       }\r
116 \r
117       return MIN (TcpRsvData->UrgLen + DataLen, BufLen);\r
118 \r
119     }\r
120 \r
121     DataLen += RcvBufEntry->TotalSize;\r
122 \r
123     RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);\r
124   }\r
125 \r
126   DataLen = MIN (BufLen, DataLen);\r
127   return DataLen;\r
128 }\r
129 \r
130 \r
131 /**\r
132   Copy data from socket buffer to application provided receive buffer.\r
133 \r
134   @param  Sock                  Pointer to the socket.\r
135   @param  TcpRxData             Pointer to the application provided receive buffer.\r
136   @param  RcvdBytes             The maximum length of the data can be copied.\r
137   @param  IsOOB                 If TURE the data is OOB, else the data is normal.\r
138 \r
139   @return None.\r
140 \r
141 **/\r
142 VOID\r
143 SockSetTcpRxData (\r
144   IN SOCKET     *Sock,\r
145   IN VOID       *TcpRxData,\r
146   IN UINT32     RcvdBytes,\r
147   IN BOOLEAN    IsOOB\r
148   )\r
149 {\r
150   UINT32                  Index;\r
151   UINT32                  CopyBytes;\r
152   UINT32                  OffSet;\r
153   EFI_TCP4_RECEIVE_DATA   *RxData;\r
154   EFI_TCP4_FRAGMENT_DATA  *Fragment;\r
155 \r
156   RxData  = (EFI_TCP4_RECEIVE_DATA *) TcpRxData;\r
157 \r
158   OffSet  = 0;\r
159 \r
160   ASSERT (RxData->DataLength >= RcvdBytes);\r
161 \r
162   RxData->DataLength  = RcvdBytes;\r
163   RxData->UrgentFlag  = IsOOB;\r
164 \r
165   for (Index = 0; (Index < RxData->FragmentCount) && (RcvdBytes > 0); Index++) {\r
166 \r
167     Fragment  = &RxData->FragmentTable[Index];\r
168     CopyBytes = MIN ((UINT32) (Fragment->FragmentLength), RcvdBytes);\r
169 \r
170     NetbufQueCopy (\r
171       Sock->RcvBuffer.DataQueue,\r
172       OffSet,\r
173       CopyBytes,\r
174       Fragment->FragmentBuffer\r
175       );\r
176 \r
177     Fragment->FragmentLength = CopyBytes;\r
178     RcvdBytes -= CopyBytes;\r
179     OffSet += CopyBytes;\r
180   }\r
181 }\r
182 \r
183 \r
184 /**\r
185   Get received data from the socket layer to the receive token.\r
186 \r
187   @param  Sock                  Pointer to the socket.\r
188   @param  RcvToken              Pointer to the application provided receive token.\r
189 \r
190   @return The length of data received in this token.\r
191 \r
192 **/\r
193 UINT32\r
194 SockProcessRcvToken (\r
195   IN SOCKET        *Sock,\r
196   IN SOCK_IO_TOKEN *RcvToken\r
197   )\r
198 {\r
199   UINT32                 TokenRcvdBytes;\r
200   EFI_TCP4_RECEIVE_DATA  *RxData;\r
201   BOOLEAN                IsUrg;\r
202 \r
203   ASSERT (Sock);\r
204 \r
205   ASSERT (SOCK_STREAM == Sock->Type);\r
206 \r
207   RxData = RcvToken->Packet.RxData;\r
208 \r
209   TokenRcvdBytes = SockTcpDataToRcv (\r
210                       &Sock->RcvBuffer,\r
211                       &IsUrg,\r
212                       (UINT32) RxData->DataLength\r
213                       );\r
214 \r
215   //\r
216   // Copy data from RcvBuffer of socket to user\r
217   // provided RxData and set the fields in TCP RxData\r
218   //\r
219   SockSetTcpRxData (Sock, RxData, TokenRcvdBytes, IsUrg);\r
220 \r
221   SOCK_TRIM_RCV_BUFF (Sock, TokenRcvdBytes);\r
222   SIGNAL_TOKEN (&(RcvToken->Token), EFI_SUCCESS);\r
223 \r
224   return TokenRcvdBytes;\r
225 }\r
226 \r
227 \r
228 /**\r
229   Process the TCP send data, buffer the tcp txdata and append\r
230   the buffer to socket send buffer,then try to send it.\r
231 \r
232   @param  Sock                  Pointer to the socket.\r
233   @param  TcpTxData             Pointer to the tcp txdata.\r
234 \r
235   @retval EFI_SUCCESS           The operation is completed successfully.\r
236   @retval EFI_OUT_OF_RESOURCES  Failed due to resource limit.\r
237 \r
238 **/\r
239 EFI_STATUS\r
240 SockProcessTcpSndData (\r
241   IN SOCKET   *Sock,\r
242   IN VOID     *TcpTxData\r
243   )\r
244 {\r
245   NET_BUF                 *SndData;\r
246   EFI_STATUS              Status;\r
247   EFI_TCP4_TRANSMIT_DATA  *TxData;\r
248 \r
249   TxData = (EFI_TCP4_TRANSMIT_DATA *) TcpTxData;\r
250 \r
251   //\r
252   // transform this TxData into a NET_BUFFER\r
253   // and insert it into Sock->SndBuffer\r
254   //\r
255   SndData = NetbufFromExt (\r
256               (NET_FRAGMENT *) TxData->FragmentTable,\r
257               (UINT32) TxData->FragmentCount,\r
258               0,\r
259               0,\r
260               SockFreeFoo,\r
261               NULL\r
262               );\r
263 \r
264   if (NULL == SndData) {\r
265     SOCK_DEBUG_ERROR (("SockKProcessSndData: Failed to"\r
266       " call NetBufferFromExt\n"));\r
267 \r
268     return EFI_OUT_OF_RESOURCES;\r
269   }\r
270 \r
271   NetbufQueAppend (Sock->SndBuffer.DataQueue, SndData);\r
272 \r
273   //\r
274   // notify the low layer protocol to handle this send token\r
275   //\r
276   if (TxData->Urgent) {\r
277     Status = Sock->ProtoHandler (Sock, SOCK_SNDURG, NULL);\r
278 \r
279     if (EFI_ERROR (Status)) {\r
280       return Status;\r
281     }\r
282   }\r
283 \r
284   if (TxData->Push) {\r
285     Status = Sock->ProtoHandler (Sock, SOCK_SNDPUSH, NULL);\r
286 \r
287     if (EFI_ERROR (Status)) {\r
288       return Status;\r
289     }\r
290   }\r
291 \r
292   //\r
293   // low layer protocol should really handle the sending\r
294   // process when catching SOCK_SND request\r
295   //\r
296   Status = Sock->ProtoHandler (Sock, SOCK_SND, NULL);\r
297 \r
298   if (EFI_ERROR (Status)) {\r
299     return Status;\r
300   }\r
301 \r
302   return EFI_SUCCESS;\r
303 }\r
304 \r
305 \r
306 /**\r
307   Flush the tokens in the specific token list.\r
308 \r
309   @param  Sock                  Pointer to the socket.\r
310   @param  PendingTokenList      Pointer to the token list to be flushed.\r
311 \r
312   @return None.\r
313 \r
314 **/\r
315 STATIC\r
316 VOID\r
317 SockFlushPendingToken (\r
318   IN SOCKET         *Sock,\r
319   IN NET_LIST_ENTRY *PendingTokenList\r
320   )\r
321 {\r
322   SOCK_TOKEN            *SockToken;\r
323   SOCK_COMPLETION_TOKEN *Token;\r
324 \r
325   ASSERT (Sock && PendingTokenList);\r
326 \r
327   while (!NetListIsEmpty (PendingTokenList)) {\r
328     SockToken = NET_LIST_HEAD (\r
329                   PendingTokenList,\r
330                   SOCK_TOKEN,\r
331                   TokenList\r
332                   );\r
333 \r
334     Token = SockToken->Token;\r
335     SIGNAL_TOKEN (Token, Sock->SockError);\r
336 \r
337     NetListRemoveEntry (&(SockToken->TokenList));\r
338     NetFreePool (SockToken);\r
339   }\r
340 }\r
341 \r
342 \r
343 /**\r
344   Wake up the connection token while the connection is\r
345   successfully established, then try to process any\r
346   pending send token.\r
347 \r
348   @param  Sock                  Pointer to the socket.\r
349 \r
350   @return None.\r
351 \r
352 **/\r
353 STATIC\r
354 VOID\r
355 SockWakeConnToken (\r
356   IN SOCKET *Sock\r
357   )\r
358 {\r
359   ASSERT (Sock->ConnectionToken != NULL);\r
360 \r
361   SIGNAL_TOKEN (Sock->ConnectionToken, EFI_SUCCESS);\r
362   Sock->ConnectionToken = NULL;\r
363 \r
364   //\r
365   // check to see if some pending send token existed?\r
366   //\r
367   SockProcessSndToken (Sock);\r
368   return ;\r
369 }\r
370 \r
371 \r
372 /**\r
373   Wake up the listen token while the connection is\r
374   established successfully.\r
375 \r
376   @param  Sock                  Pointer to the socket.\r
377 \r
378   @return None.\r
379 \r
380 **/\r
381 STATIC\r
382 VOID\r
383 SockWakeListenToken (\r
384   IN SOCKET *Sock\r
385   )\r
386 {\r
387   SOCKET                *Parent;\r
388   SOCK_TOKEN            *SockToken;\r
389   EFI_TCP4_LISTEN_TOKEN *ListenToken;\r
390 \r
391   Parent = Sock->Parent;\r
392 \r
393   ASSERT (Parent && SOCK_IS_LISTENING (Parent) && SOCK_IS_CONNECTED (Sock));\r
394 \r
395   if (!NetListIsEmpty (&Parent->ListenTokenList)) {\r
396     SockToken = NET_LIST_HEAD (\r
397                   &Parent->ListenTokenList,\r
398                   SOCK_TOKEN,\r
399                   TokenList\r
400                   );\r
401 \r
402     ListenToken = (EFI_TCP4_LISTEN_TOKEN *) SockToken->Token;\r
403     ListenToken->NewChildHandle = Sock->SockHandle;\r
404 \r
405     SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);\r
406 \r
407     NetListRemoveEntry (&SockToken->TokenList);\r
408     NetFreePool (SockToken);\r
409 \r
410     NetListRemoveEntry (&Sock->ConnectionList);\r
411 \r
412     Parent->ConnCnt--;\r
413     SOCK_DEBUG_WARN (("SockWakeListenToken: accept a socket,"\r
414       "now conncnt is %d", Parent->ConnCnt));\r
415 \r
416     Sock->Parent = NULL;\r
417   }\r
418 }\r
419 \r
420 \r
421 /**\r
422   Wake up the receive token while some data is received.\r
423 \r
424   @param  Sock                  Pointer to the socket.\r
425 \r
426   @return None.\r
427 \r
428 **/\r
429 STATIC\r
430 VOID\r
431 SockWakeRcvToken (\r
432   IN SOCKET *Sock\r
433   )\r
434 {\r
435   UINT32        RcvdBytes;\r
436   UINT32        TokenRcvdBytes;\r
437   SOCK_TOKEN    *SockToken;\r
438   SOCK_IO_TOKEN *RcvToken;\r
439 \r
440   ASSERT (Sock->RcvBuffer.DataQueue);\r
441 \r
442   RcvdBytes = (Sock->RcvBuffer.DataQueue)->BufSize;\r
443 \r
444   ASSERT (RcvdBytes > 0);\r
445 \r
446   while (RcvdBytes > 0 && !NetListIsEmpty (&Sock->RcvTokenList)) {\r
447 \r
448     SockToken = NET_LIST_HEAD (\r
449                   &Sock->RcvTokenList,\r
450                   SOCK_TOKEN,\r
451                   TokenList\r
452                   );\r
453 \r
454     RcvToken        = (SOCK_IO_TOKEN *) SockToken->Token;\r
455     TokenRcvdBytes  = SockProcessRcvToken (Sock, RcvToken);\r
456 \r
457     if (0 == TokenRcvdBytes) {\r
458       return ;\r
459     }\r
460 \r
461     NetListRemoveEntry (&(SockToken->TokenList));\r
462     NetFreePool (SockToken);\r
463     RcvdBytes -= TokenRcvdBytes;\r
464   }\r
465 }\r
466 \r
467 \r
468 /**\r
469   Process the send token.\r
470 \r
471   @param  Sock                  Pointer to the socket.\r
472 \r
473   @return None.\r
474 \r
475 **/\r
476 STATIC\r
477 VOID\r
478 SockProcessSndToken (\r
479   IN SOCKET *Sock\r
480   )\r
481 {\r
482   UINT32                  FreeSpace;\r
483   SOCK_TOKEN              *SockToken;\r
484   UINT32                  DataLen;\r
485   SOCK_IO_TOKEN           *SndToken;\r
486   EFI_TCP4_TRANSMIT_DATA  *TxData;\r
487   EFI_STATUS              Status;\r
488 \r
489   ASSERT (Sock && (SOCK_STREAM == Sock->Type));\r
490 \r
491   FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);\r
492 \r
493   //\r
494   // to determine if process a send token using\r
495   // socket layer flow control policy\r
496   //\r
497   while ((FreeSpace >= Sock->SndBuffer.LowWater) &&\r
498          !NetListIsEmpty (&Sock->SndTokenList)) {\r
499 \r
500     SockToken = NET_LIST_HEAD (\r
501                   &(Sock->SndTokenList),\r
502                   SOCK_TOKEN,\r
503                   TokenList\r
504                   );\r
505 \r
506     //\r
507     // process this token\r
508     //\r
509     NetListRemoveEntry (&(SockToken->TokenList));\r
510     NetListInsertTail (\r
511       &(Sock->ProcessingSndTokenList),\r
512       &(SockToken->TokenList)\r
513       );\r
514 \r
515     //\r
516     // Proceess it in the light of  SockType\r
517     //\r
518     SndToken  = (SOCK_IO_TOKEN *) SockToken->Token;\r
519     TxData    = SndToken->Packet.TxData;\r
520 \r
521     DataLen = (UINT32) TxData->DataLength;\r
522     Status  = SockProcessTcpSndData (Sock, TxData);\r
523 \r
524     if (EFI_ERROR (Status)) {\r
525       goto OnError;\r
526     }\r
527 \r
528     if (DataLen >= FreeSpace) {\r
529       FreeSpace = 0;\r
530 \r
531     } else {\r
532       FreeSpace -= DataLen;\r
533 \r
534     }\r
535   }\r
536 \r
537   return ;\r
538 \r
539 OnError:\r
540 \r
541   NetListRemoveEntry (&SockToken->TokenList);\r
542   SIGNAL_TOKEN (SockToken->Token, Status);\r
543   NetFreePool (SockToken);\r
544 }\r
545 \r
546 \r
547 /**\r
548   Create a socket with initial data SockInitData.\r
549 \r
550   @param  SockInitData          Pointer to the initial data of the socket.\r
551 \r
552   @return Pointer to the newly created socket.\r
553 \r
554 **/\r
555 SOCKET *\r
556 SockCreate (\r
557   IN SOCK_INIT_DATA *SockInitData\r
558   )\r
559 {\r
560   SOCKET      *Sock;\r
561   SOCKET      *Parent;\r
562   EFI_STATUS  Status;\r
563 \r
564   ASSERT (SockInitData && SockInitData->ProtoHandler);\r
565   ASSERT (SockInitData->Type == SOCK_STREAM);\r
566   ASSERT (SockInitData->ProtoData && (SockInitData->DataSize <= PROTO_RESERVED_LEN));\r
567 \r
568   Parent = SockInitData->Parent;\r
569 \r
570   if (Parent && (Parent->ConnCnt == Parent->BackLog)) {\r
571     SOCK_DEBUG_ERROR (\r
572       ("SockCreate: Socket parent has "\r
573       "reached its connection limit with %d ConnCnt and %d BackLog\n",\r
574       Parent->ConnCnt,\r
575       Parent->BackLog)\r
576       );\r
577 \r
578     return NULL;\r
579   }\r
580 \r
581   Sock = NetAllocateZeroPool (sizeof (SOCKET));\r
582   if (NULL == Sock) {\r
583 \r
584     SOCK_DEBUG_ERROR (("SockCreate: No resource to create a new socket\n"));\r
585     return NULL;\r
586   }\r
587 \r
588   NetListInit (&Sock->Link);\r
589   NetListInit (&Sock->ConnectionList);\r
590   NetListInit (&Sock->ListenTokenList);\r
591   NetListInit (&Sock->RcvTokenList);\r
592   NetListInit (&Sock->SndTokenList);\r
593   NetListInit (&Sock->ProcessingSndTokenList);\r
594 \r
595   NET_LOCK_INIT (&(Sock->Lock));\r
596 \r
597   Sock->SndBuffer.DataQueue = NetbufQueAlloc ();\r
598   if (NULL == Sock->SndBuffer.DataQueue) {\r
599     SOCK_DEBUG_ERROR (("SockCreate: No resource to allocate"\r
600       " SndBuffer for new socket\n"));\r
601 \r
602     goto OnError;\r
603   }\r
604 \r
605   Sock->RcvBuffer.DataQueue = NetbufQueAlloc ();\r
606   if (NULL == Sock->RcvBuffer.DataQueue) {\r
607     SOCK_DEBUG_ERROR (("SockCreate: No resource to allocate "\r
608       "RcvBuffer for new socket\n"));\r
609 \r
610     goto OnError;\r
611   }\r
612 \r
613   Sock->Signature           = SOCK_SIGNATURE;\r
614 \r
615   Sock->Parent              = Parent;\r
616   Sock->BackLog             = SockInitData->BackLog;\r
617   Sock->ProtoHandler        = SockInitData->ProtoHandler;\r
618   Sock->SndBuffer.HighWater = SockInitData->SndBufferSize;\r
619   Sock->RcvBuffer.HighWater = SockInitData->RcvBufferSize;\r
620   Sock->Type                = SockInitData->Type;\r
621   Sock->DriverBinding       = SockInitData->DriverBinding;\r
622   Sock->State               = SockInitData->State;\r
623   Sock->CreateCallback      = SockInitData->CreateCallback;\r
624   Sock->DestroyCallback     = SockInitData->DestroyCallback;\r
625   Sock->Context             = SockInitData->Context;\r
626 \r
627   Sock->SockError           = EFI_ABORTED;\r
628   Sock->SndBuffer.LowWater  = SOCK_BUFF_LOW_WATER;\r
629   Sock->RcvBuffer.LowWater  = SOCK_BUFF_LOW_WATER;\r
630 \r
631   //\r
632   // Install protocol on Sock->SockHandle\r
633   //\r
634   NetCopyMem (\r
635     &(Sock->NetProtocol.TcpProtocol),\r
636     SockInitData->Protocol,\r
637     sizeof (EFI_TCP4_PROTOCOL)\r
638     );\r
639 \r
640   //\r
641   // copy the protodata into socket\r
642   //\r
643   NetCopyMem (Sock->ProtoReserved, SockInitData->ProtoData, SockInitData->DataSize);\r
644 \r
645   Status = gBS->InstallMultipleProtocolInterfaces (\r
646                   &Sock->SockHandle,\r
647                   &gEfiTcp4ProtocolGuid,\r
648                   &(Sock->NetProtocol.TcpProtocol),\r
649                   NULL\r
650                   );\r
651 \r
652   if (EFI_ERROR (Status)) {\r
653     SOCK_DEBUG_ERROR (("SockCreate: Install TCP protocol in "\r
654       "socket failed with %r\n", Status));\r
655 \r
656     goto OnError;\r
657   }\r
658 \r
659   if (Parent != NULL) {\r
660     ASSERT (Parent->BackLog > 0);\r
661     ASSERT (SOCK_IS_LISTENING (Parent));\r
662 \r
663     //\r
664     // need to add it into Parent->ConnectionList\r
665     // if the Parent->ConnCnt < Parent->BackLog\r
666     //\r
667     Parent->ConnCnt++;\r
668 \r
669     SOCK_DEBUG_WARN (("SockCreate: Create a new socket and"\r
670       "add to parent, now conncnt is %d\n", Parent->ConnCnt));\r
671 \r
672     NetListInsertTail (&Parent->ConnectionList, &Sock->ConnectionList);\r
673   }\r
674 \r
675   if (Sock->CreateCallback != NULL) {\r
676     Status = Sock->CreateCallback (Sock, Sock->Context);\r
677     if (EFI_ERROR (Status)) {\r
678       goto OnError;\r
679     }\r
680   }\r
681 \r
682   return Sock;\r
683 \r
684 OnError:\r
685 \r
686   if (Sock->SockHandle != NULL) {\r
687     gBS->UninstallMultipleProtocolInterfaces (\r
688            Sock->SockHandle,\r
689            &gEfiTcp4ProtocolGuid,\r
690            &(Sock->NetProtocol.TcpProtocol),\r
691            NULL\r
692            );\r
693   }\r
694 \r
695   if (NULL != Sock->SndBuffer.DataQueue) {\r
696     NetbufQueFree (Sock->SndBuffer.DataQueue);\r
697   }\r
698 \r
699   if (NULL != Sock->RcvBuffer.DataQueue) {\r
700     NetbufQueFree (Sock->RcvBuffer.DataQueue);\r
701   }\r
702 \r
703   NetFreePool (Sock);\r
704 \r
705   return NULL;\r
706 }\r
707 \r
708 \r
709 /**\r
710   Destroy a socket.\r
711 \r
712   @param  Sock                  Pointer to the socket.\r
713 \r
714   @return None.\r
715 \r
716 **/\r
717 VOID\r
718 SockDestroy (\r
719   IN SOCKET *Sock\r
720   )\r
721 {\r
722   VOID        *SockProtocol;\r
723   EFI_GUID    *ProtocolGuid;\r
724   EFI_STATUS  Status;\r
725 \r
726   ASSERT (SOCK_STREAM == Sock->Type);\r
727 \r
728   if (Sock->DestroyCallback != NULL) {\r
729     Sock->DestroyCallback (Sock, Sock->Context);\r
730   }\r
731 \r
732   //\r
733   // Flush the completion token buffered\r
734   // by sock and rcv, snd buffer\r
735   //\r
736   if (!SOCK_IS_UNCONFIGURED (Sock)) {\r
737 \r
738     SockConnFlush (Sock);\r
739     SockSetState (Sock, SO_CLOSED);\r
740     Sock->ConfigureState = SO_UNCONFIGURED;\r
741 \r
742   }\r
743   //\r
744   // Destory the RcvBuffer Queue and SendBuffer Queue\r
745   //\r
746   NetbufQueFree (Sock->RcvBuffer.DataQueue);\r
747   NetbufQueFree (Sock->SndBuffer.DataQueue);\r
748 \r
749   //\r
750   // Remove it from parent connection list if needed\r
751   //\r
752   if (Sock->Parent) {\r
753 \r
754     NetListRemoveEntry (&(Sock->ConnectionList));\r
755     (Sock->Parent->ConnCnt)--;\r
756 \r
757     SOCK_DEBUG_WARN (("SockDestory: Delete a unaccepted socket from parent"\r
758       "now conncnt is %d\n", Sock->Parent->ConnCnt));\r
759 \r
760     Sock->Parent = NULL;\r
761   }\r
762 \r
763   //\r
764   // Set the protocol guid and driver binding handle\r
765   // in the light of Sock->SockType\r
766   //\r
767   ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
768 \r
769   //\r
770   // Retrieve the protocol installed on this sock\r
771   //\r
772   Status = gBS->OpenProtocol (\r
773                   Sock->SockHandle,\r
774                   ProtocolGuid,\r
775                   &SockProtocol,\r
776                   Sock->DriverBinding,\r
777                   Sock->SockHandle,\r
778                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
779                   );\r
780 \r
781   if (EFI_ERROR (Status)) {\r
782 \r
783     SOCK_DEBUG_ERROR (("SockDestroy: Open protocol installed "\r
784       "on socket failed with %r\n", Status));\r
785 \r
786     goto FreeSock;\r
787   }\r
788 \r
789   //\r
790   // Uninstall the protocol installed on this sock\r
791   // in the light of Sock->SockType\r
792   //\r
793   gBS->UninstallMultipleProtocolInterfaces (\r
794         Sock->SockHandle,\r
795         ProtocolGuid,\r
796         SockProtocol,\r
797         NULL\r
798         );\r
799 \r
800 FreeSock:\r
801   NetFreePool (Sock);\r
802   return ;\r
803 }\r
804 \r
805 \r
806 /**\r
807   Flush the socket.\r
808 \r
809   @param  Sock                  Pointer to the socket.\r
810 \r
811   @return None.\r
812 \r
813 **/\r
814 VOID\r
815 SockConnFlush (\r
816   IN SOCKET *Sock\r
817   )\r
818 {\r
819   SOCKET  *Child;\r
820 \r
821   ASSERT (Sock);\r
822 \r
823   //\r
824   // Clear the flag in this socket\r
825   //\r
826   Sock->Flag = 0;\r
827 \r
828   //\r
829   // Flush the SndBuffer and RcvBuffer of Sock\r
830   //\r
831   NetbufQueFlush (Sock->SndBuffer.DataQueue);\r
832   NetbufQueFlush (Sock->RcvBuffer.DataQueue);\r
833 \r
834   //\r
835   // Signal the pending token\r
836   //\r
837   if (Sock->ConnectionToken != NULL) {\r
838     SIGNAL_TOKEN (Sock->ConnectionToken, Sock->SockError);\r
839     Sock->ConnectionToken = NULL;\r
840   }\r
841 \r
842   if (Sock->CloseToken != NULL) {\r
843     SIGNAL_TOKEN (Sock->CloseToken, Sock->SockError);\r
844     Sock->CloseToken = NULL;\r
845   }\r
846 \r
847   SockFlushPendingToken (Sock, &(Sock->ListenTokenList));\r
848   SockFlushPendingToken (Sock, &(Sock->RcvTokenList));\r
849   SockFlushPendingToken (Sock, &(Sock->SndTokenList));\r
850   SockFlushPendingToken (Sock, &(Sock->ProcessingSndTokenList));\r
851 \r
852   //\r
853   // Destroy the pending connection, if it is a listening socket\r
854   //\r
855   if (SOCK_IS_LISTENING (Sock)) {\r
856     while (!NetListIsEmpty (&Sock->ConnectionList)) {\r
857       Child = NET_LIST_HEAD (\r
858                 &Sock->ConnectionList,\r
859                 SOCKET,\r
860                 ConnectionList\r
861                 );\r
862 \r
863       SockDestroyChild (Child);\r
864     }\r
865 \r
866     Sock->ConnCnt = 0;\r
867   }\r
868 \r
869   return ;\r
870 }\r
871 \r
872 \r
873 /**\r
874   Set the state of the socket.\r
875 \r
876   @param  Sock                  Pointer to the socket.\r
877   @param  State                 The new state to be set.\r
878 \r
879   @return None.\r
880 \r
881 **/\r
882 VOID\r
883 SockSetState (\r
884   IN SOCKET     *Sock,\r
885   IN SOCK_STATE State\r
886   )\r
887 {\r
888   Sock->State = State;\r
889 }\r
890 \r
891 \r
892 /**\r
893   Clone a new socket including its associated protocol control block.\r
894 \r
895   @param  Sock                  Pointer to the socket to be cloned.\r
896 \r
897   @retval *                     Pointer to the newly cloned socket. If NULL, error\r
898                                 condition occurred.\r
899 \r
900 **/\r
901 SOCKET *\r
902 SockClone (\r
903   IN SOCKET *Sock\r
904   )\r
905 {\r
906   SOCKET          *ClonedSock;\r
907   SOCK_INIT_DATA  InitData;\r
908 \r
909   InitData.BackLog        = Sock->BackLog;\r
910   InitData.Parent         = Sock;\r
911   InitData.State          = Sock->State;\r
912   InitData.ProtoHandler   = Sock->ProtoHandler;\r
913   InitData.Type           = Sock->Type;\r
914   InitData.RcvBufferSize  = Sock->RcvBuffer.HighWater;\r
915   InitData.SndBufferSize  = Sock->SndBuffer.HighWater;\r
916   InitData.DriverBinding  = Sock->DriverBinding;\r
917   InitData.Protocol       = &(Sock->NetProtocol);\r
918   InitData.CreateCallback  = Sock->CreateCallback;\r
919   InitData.DestroyCallback = Sock->DestroyCallback;\r
920   InitData.Context         = Sock->Context;\r
921   InitData.ProtoData       = Sock->ProtoReserved;\r
922   InitData.DataSize        = sizeof (Sock->ProtoReserved);\r
923 \r
924   ClonedSock              = SockCreate (&InitData);\r
925 \r
926   if (NULL == ClonedSock) {\r
927     SOCK_DEBUG_ERROR (("SockClone: no resource to create a cloned sock\n"));\r
928     return NULL;\r
929   }\r
930 \r
931   SockSetState (ClonedSock, SO_CONNECTING);\r
932   ClonedSock->ConfigureState = Sock->ConfigureState;\r
933 \r
934   return ClonedSock;\r
935 }\r
936 \r
937 \r
938 /**\r
939   Called by the low layer protocol to indicate the socket\r
940   a connection is established. This function just changes\r
941   the socket's state to SO_CONNECTED and signals the token\r
942   used for connection establishment.\r
943 \r
944   @param  Sock                  Pointer to the socket associated with the\r
945                                 established connection.\r
946 \r
947   @return None.\r
948 \r
949 **/\r
950 VOID\r
951 SockConnEstablished (\r
952   IN SOCKET *Sock\r
953   )\r
954 {\r
955 \r
956   ASSERT (SO_CONNECTING == Sock->State);\r
957 \r
958   SockSetState (Sock, SO_CONNECTED);\r
959 \r
960   if (NULL == Sock->Parent) {\r
961     SockWakeConnToken (Sock);\r
962   } else {\r
963     SockWakeListenToken (Sock);\r
964   }\r
965 \r
966   return ;\r
967 }\r
968 \r
969 \r
970 /**\r
971   Called by the low layer protocol to indicate the connection\r
972   is closed. This function flushes the socket, sets the state\r
973   to SO_CLOSED and signals the close token.\r
974 \r
975   @param  Sock                  Pointer to the socket associated with the closed\r
976                                 connection.\r
977 \r
978   @return None.\r
979 \r
980 **/\r
981 VOID\r
982 SockConnClosed (\r
983   IN SOCKET *Sock\r
984   )\r
985 {\r
986   if (Sock->CloseToken) {\r
987     SIGNAL_TOKEN (Sock->CloseToken, EFI_SUCCESS);\r
988     Sock->CloseToken = NULL;\r
989   }\r
990 \r
991   SockConnFlush (Sock);\r
992   SockSetState (Sock, SO_CLOSED);\r
993 \r
994   if (Sock->Parent != NULL) {\r
995     SockDestroyChild (Sock);\r
996   }\r
997 \r
998 }\r
999 \r
1000 \r
1001 /**\r
1002   Called by low layer protocol to indicate that some\r
1003   data is sent or processed. This function trims the\r
1004   sent data in the socket send buffer, signals the\r
1005   data token if proper\r
1006 \r
1007   @param  Sock                  Pointer to the socket.\r
1008   @param  Count                 The length of the data processed or sent, in bytes.\r
1009 \r
1010   @return None.\r
1011 \r
1012 **/\r
1013 VOID\r
1014 SockDataSent (\r
1015   IN SOCKET     *Sock,\r
1016   IN UINT32     Count\r
1017   )\r
1018 {\r
1019   SOCK_TOKEN            *SockToken;\r
1020   SOCK_COMPLETION_TOKEN *SndToken;\r
1021 \r
1022   ASSERT (!NetListIsEmpty (&Sock->ProcessingSndTokenList));\r
1023   ASSERT (Count <= (Sock->SndBuffer.DataQueue)->BufSize);\r
1024 \r
1025   NetbufQueTrim (Sock->SndBuffer.DataQueue, Count);\r
1026 \r
1027   //\r
1028   // To check if we can signal some snd token in this socket\r
1029   //\r
1030   while (Count > 0) {\r
1031     SockToken = NET_LIST_HEAD (\r
1032                   &(Sock->ProcessingSndTokenList),\r
1033                   SOCK_TOKEN,\r
1034                   TokenList\r
1035                   );\r
1036 \r
1037     SndToken = SockToken->Token;\r
1038 \r
1039     if (SockToken->RemainDataLen <= Count) {\r
1040 \r
1041       NetListRemoveEntry (&(SockToken->TokenList));\r
1042       SIGNAL_TOKEN (SndToken, EFI_SUCCESS);\r
1043       Count -= SockToken->RemainDataLen;\r
1044       NetFreePool (SockToken);\r
1045     } else {\r
1046 \r
1047       SockToken->RemainDataLen -= Count;\r
1048       Count = 0;\r
1049     }\r
1050   }\r
1051 \r
1052   //\r
1053   // to judge if we can process some send token in\r
1054   // Sock->SndTokenList, if so process those send token\r
1055   //\r
1056   SockProcessSndToken (Sock);\r
1057   return ;\r
1058 }\r
1059 \r
1060 \r
1061 /**\r
1062   Called by the low layer protocol to copy some data in socket send\r
1063   buffer starting from the specific offset to a buffer provided by\r
1064   the caller.\r
1065 \r
1066   @param  Sock                  Pointer to the socket.\r
1067   @param  Offset                The start point of the data to be copied.\r
1068   @param  Len                   The length of the data to be copied.\r
1069   @param  Dest                  Pointer to the destination to copy the data.\r
1070 \r
1071   @return The data size copied.\r
1072 \r
1073 **/\r
1074 UINT32\r
1075 SockGetDataToSend (\r
1076   IN SOCKET      *Sock,\r
1077   IN UINT32      Offset,\r
1078   IN UINT32      Len,\r
1079   IN UINT8       *Dest\r
1080   )\r
1081 {\r
1082   ASSERT (Sock && SOCK_STREAM == Sock->Type);\r
1083 \r
1084   return NetbufQueCopy (\r
1085           Sock->SndBuffer.DataQueue,\r
1086           Offset,\r
1087           Len,\r
1088           Dest\r
1089           );\r
1090 }\r
1091 \r
1092 \r
1093 /**\r
1094   Called by the low layer protocol to deliver received data\r
1095   to socket layer. This function will append the data to the\r
1096   socket receive buffer, set ther urgent data length and then\r
1097   check if any receive token can be signaled.\r
1098 \r
1099   @param  Sock                  Pointer to the socket.\r
1100   @param  NetBuffer             Pointer to the buffer that contains the received\r
1101                                 data.\r
1102   @param  UrgLen                The length of the urgent data in the received data.\r
1103 \r
1104   @return None.\r
1105 \r
1106 **/\r
1107 VOID\r
1108 SockDataRcvd (\r
1109   IN SOCKET    *Sock,\r
1110   IN NET_BUF   *NetBuffer,\r
1111   IN UINT32    UrgLen\r
1112   )\r
1113 {\r
1114   ASSERT (Sock && Sock->RcvBuffer.DataQueue &&\r
1115     UrgLen <= NetBuffer->TotalSize);\r
1116 \r
1117   NET_GET_REF (NetBuffer);\r
1118 \r
1119   ((TCP_RSV_DATA *) (NetBuffer->ProtoData))->UrgLen = UrgLen;\r
1120 \r
1121   NetbufQueAppend (Sock->RcvBuffer.DataQueue, NetBuffer);\r
1122 \r
1123   SockWakeRcvToken (Sock);\r
1124   return ;\r
1125 }\r
1126 \r
1127 \r
1128 /**\r
1129   Get the length of the free space of the specific socket buffer.\r
1130 \r
1131   @param  Sock                  Pointer to the socket.\r
1132   @param  Which                 Flag to indicate which socket buffer to check,\r
1133                                 either send buffer or receive buffer.\r
1134 \r
1135   @return The length of the free space, in bytes.\r
1136 \r
1137 **/\r
1138 UINT32\r
1139 SockGetFreeSpace (\r
1140   IN SOCKET  *Sock,\r
1141   IN UINT32  Which\r
1142   )\r
1143 {\r
1144   UINT32      BufferCC;\r
1145   SOCK_BUFFER *SockBuffer;\r
1146 \r
1147   ASSERT (Sock && ((SOCK_SND_BUF == Which) || (SOCK_RCV_BUF == Which)));\r
1148 \r
1149   if (SOCK_SND_BUF == Which) {\r
1150     SockBuffer = &(Sock->SndBuffer);\r
1151   } else {\r
1152     SockBuffer = &(Sock->RcvBuffer);\r
1153   }\r
1154 \r
1155   BufferCC = (SockBuffer->DataQueue)->BufSize;\r
1156 \r
1157   if (BufferCC >= SockBuffer->HighWater) {\r
1158 \r
1159     return 0;\r
1160   }\r
1161 \r
1162   return SockBuffer->HighWater - BufferCC;\r
1163 }\r
1164 \r
1165 \r
1166 /**\r
1167   Signal the receive token with the specific error or\r
1168   set socket error code after error is received.\r
1169 \r
1170   @param  Sock                  Pointer to the socket.\r
1171   @param  Error                 The error code received.\r
1172 \r
1173   @return None.\r
1174 \r
1175 **/\r
1176 VOID\r
1177 SockRcvdErr (\r
1178   IN SOCKET       *Sock,\r
1179   IN EFI_STATUS   Error\r
1180   )\r
1181 {\r
1182   SOCK_TOKEN  *SockToken;\r
1183 \r
1184   if (!NetListIsEmpty (&Sock->RcvTokenList)) {\r
1185 \r
1186     SockToken = NET_LIST_HEAD (\r
1187                   &Sock->RcvTokenList,\r
1188                   SOCK_TOKEN,\r
1189                   TokenList\r
1190                   );\r
1191 \r
1192     NetListRemoveEntry (&SockToken->TokenList);\r
1193 \r
1194     SIGNAL_TOKEN (SockToken->Token, Error);\r
1195 \r
1196     NetFreePool (SockToken);\r
1197   } else {\r
1198 \r
1199     SOCK_ERROR (Sock, Error);\r
1200   }\r
1201 }\r
1202 \r
1203 \r
1204 /**\r
1205   Called by the low layer protocol to indicate that there\r
1206   will be no more data from the communication peer. This\r
1207   function set the socket's state to SO_NO_MORE_DATA and\r
1208   signal all queued IO tokens with the error status\r
1209   EFI_CONNECTION_FIN.\r
1210 \r
1211   @param  Sock                  Pointer to the socket.\r
1212 \r
1213   @return None.\r
1214 \r
1215 **/\r
1216 VOID\r
1217 SockNoMoreData (\r
1218   IN SOCKET *Sock\r
1219   )\r
1220 {\r
1221   EFI_STATUS  Err;\r
1222 \r
1223   SOCK_NO_MORE_DATA (Sock);\r
1224 \r
1225   if (!NetListIsEmpty (&Sock->RcvTokenList)) {\r
1226 \r
1227     ASSERT (0 == GET_RCV_DATASIZE (Sock));\r
1228 \r
1229     Err = Sock->SockError;\r
1230 \r
1231     SOCK_ERROR (Sock, EFI_CONNECTION_FIN);\r
1232 \r
1233     SockFlushPendingToken (Sock, &Sock->RcvTokenList);\r
1234 \r
1235     SOCK_ERROR (Sock, Err);\r
1236 \r
1237   }\r
1238 \r
1239 }\r
1240 \r
1241 \r
1242 /**\r
1243   Get the first buffer block in the specific socket buffer.\r
1244 \r
1245   @param  Sockbuf               Pointer to the socket buffer.\r
1246 \r
1247   @return Pointer to the first buffer in the queue. NULL if the queue is empty.\r
1248 \r
1249 **/\r
1250 NET_BUF *\r
1251 SockBufFirst (\r
1252   IN SOCK_BUFFER *Sockbuf\r
1253   )\r
1254 {\r
1255   NET_LIST_ENTRY  *NetbufList;\r
1256 \r
1257   NetbufList = &(Sockbuf->DataQueue->BufList);\r
1258 \r
1259   if (NetListIsEmpty (NetbufList)) {\r
1260     return NULL;\r
1261   }\r
1262 \r
1263   return NET_LIST_HEAD (NetbufList, NET_BUF, List);\r
1264 }\r
1265 \r
1266 \r
1267 /**\r
1268   Get the next buffer block in the specific socket buffer.\r
1269 \r
1270   @param  Sockbuf               Pointer to the socket buffer.\r
1271   @param  SockEntry             Pointer to the buffer block prior to the required\r
1272                                 one.\r
1273 \r
1274   @return Pointer to the buffer block next to SockEntry. NULL if SockEntry is the tail or head entry.\r
1275 \r
1276 **/\r
1277 NET_BUF *\r
1278 SockBufNext (\r
1279   IN SOCK_BUFFER *Sockbuf,\r
1280   IN NET_BUF     *SockEntry\r
1281   )\r
1282 {\r
1283   NET_LIST_ENTRY  *NetbufList;\r
1284 \r
1285   NetbufList = &(Sockbuf->DataQueue->BufList);\r
1286 \r
1287   if ((SockEntry->List.ForwardLink == NetbufList) ||\r
1288       (SockEntry->List.BackLink == &SockEntry->List) ||\r
1289       (SockEntry->List.ForwardLink == &SockEntry->List)\r
1290       ) {\r
1291 \r
1292     return NULL;\r
1293   }\r
1294 \r
1295   return NET_LIST_USER_STRUCT (SockEntry->List.ForwardLink, NET_BUF, List);\r
1296 }\r