]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/SockImpl.c
Use Mde library and definition instead of some native definitions in NetLib, to simpl...
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / SockImpl.c
CommitLineData
8a67d61d 1/** @file\r
2\r
3Copyright (c) 2005 - 2006, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 SockImpl.c\r
15\r
16Abstract:\r
17\r
18\r
19**/\r
20\r
21#include "SockImpl.h"\r
22\r
23STATIC\r
24UINT32\r
25SockTcpDataToRcv (\r
26 IN SOCK_BUFFER *SockBuffer,\r
27 OUT BOOLEAN *IsOOB,\r
28 IN UINT32 BufLen\r
29 );\r
30\r
31STATIC\r
32VOID\r
33SockProcessSndToken (\r
34 IN SOCKET *Sock\r
35 );\r
36\r
37VOID\r
38SockFreeFoo (\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
59STATIC\r
60UINT32\r
61SockTcpDataToRcv (\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
4eb65aff 79 *IsUrg = (BOOLEAN) ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);\r
8a67d61d 80\r
81 if (*IsUrg && TcpRsvData->UrgLen < RcvBufEntry->TotalSize) {\r
82\r
36ee91ca 83 DataLen = MIN (TcpRsvData->UrgLen, BufLen);\r
8a67d61d 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
4eb65aff 103 Urg = (BOOLEAN) ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);\r
8a67d61d 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
36ee91ca 117 return MIN (TcpRsvData->UrgLen + DataLen, BufLen);\r
8a67d61d 118\r
119 }\r
120\r
121 DataLen += RcvBufEntry->TotalSize;\r
122\r
123 RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);\r
124 }\r
125\r
36ee91ca 126 DataLen = MIN (BufLen, DataLen);\r
8a67d61d 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
142VOID\r
143SockSetTcpRxData (\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
36ee91ca 168 CopyBytes = MIN ((UINT32) (Fragment->FragmentLength), RcvdBytes);\r
8a67d61d 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
193UINT32\r
194SockProcessRcvToken (\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
4eb65aff 212 (UINT32) RxData->DataLength\r
8a67d61d 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
239EFI_STATUS\r
240SockProcessTcpSndData (\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
4eb65aff 257 (UINT32) TxData->FragmentCount,\r
8a67d61d 258 0,\r
259 0,\r
260 SockFreeFoo,\r
261 NULL\r
262 );\r
263\r
264 if (NULL == SndData) {\r
e48e37fc 265 DEBUG ((EFI_D_ERROR, "SockKProcessSndData: Failed to"\r
8a67d61d 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
315STATIC\r
316VOID\r
317SockFlushPendingToken (\r
318 IN SOCKET *Sock,\r
e48e37fc 319 IN LIST_ENTRY *PendingTokenList\r
8a67d61d 320 )\r
321{\r
322 SOCK_TOKEN *SockToken;\r
323 SOCK_COMPLETION_TOKEN *Token;\r
324\r
325 ASSERT (Sock && PendingTokenList);\r
326\r
e48e37fc 327 while (!IsListEmpty (PendingTokenList)) {\r
8a67d61d 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
e48e37fc 337 RemoveEntryList (&(SockToken->TokenList));\r
338 gBS->FreePool (SockToken);\r
8a67d61d 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
353STATIC\r
354VOID\r
355SockWakeConnToken (\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
381STATIC\r
382VOID\r
383SockWakeListenToken (\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
e48e37fc 395 if (!IsListEmpty (&Parent->ListenTokenList)) {\r
8a67d61d 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
e48e37fc 407 RemoveEntryList (&SockToken->TokenList);\r
408 gBS->FreePool (SockToken);\r
8a67d61d 409\r
e48e37fc 410 RemoveEntryList (&Sock->ConnectionList);\r
8a67d61d 411\r
412 Parent->ConnCnt--;\r
e48e37fc 413 DEBUG ((EFI_D_WARN, "SockWakeListenToken: accept a socket, now conncnt is %d", Parent->ConnCnt));\r
8a67d61d 414\r
415 Sock->Parent = NULL;\r
416 }\r
417}\r
418\r
419\r
420/**\r
421 Wake up the receive token while some data is received.\r
422\r
423 @param Sock Pointer to the socket.\r
424\r
425 @return None.\r
426\r
427**/\r
428STATIC\r
429VOID\r
430SockWakeRcvToken (\r
431 IN SOCKET *Sock\r
432 )\r
433{\r
434 UINT32 RcvdBytes;\r
435 UINT32 TokenRcvdBytes;\r
436 SOCK_TOKEN *SockToken;\r
437 SOCK_IO_TOKEN *RcvToken;\r
438\r
439 ASSERT (Sock->RcvBuffer.DataQueue);\r
440\r
441 RcvdBytes = (Sock->RcvBuffer.DataQueue)->BufSize;\r
442\r
443 ASSERT (RcvdBytes > 0);\r
444\r
e48e37fc 445 while (RcvdBytes > 0 && !IsListEmpty (&Sock->RcvTokenList)) {\r
8a67d61d 446\r
447 SockToken = NET_LIST_HEAD (\r
448 &Sock->RcvTokenList,\r
449 SOCK_TOKEN,\r
450 TokenList\r
451 );\r
452\r
453 RcvToken = (SOCK_IO_TOKEN *) SockToken->Token;\r
454 TokenRcvdBytes = SockProcessRcvToken (Sock, RcvToken);\r
455\r
456 if (0 == TokenRcvdBytes) {\r
457 return ;\r
458 }\r
459\r
e48e37fc 460 RemoveEntryList (&(SockToken->TokenList));\r
461 gBS->FreePool (SockToken);\r
8a67d61d 462 RcvdBytes -= TokenRcvdBytes;\r
463 }\r
464}\r
465\r
466\r
467/**\r
468 Process the send token.\r
469\r
470 @param Sock Pointer to the socket.\r
471\r
472 @return None.\r
473\r
474**/\r
475STATIC\r
476VOID\r
477SockProcessSndToken (\r
478 IN SOCKET *Sock\r
479 )\r
480{\r
481 UINT32 FreeSpace;\r
482 SOCK_TOKEN *SockToken;\r
483 UINT32 DataLen;\r
484 SOCK_IO_TOKEN *SndToken;\r
485 EFI_TCP4_TRANSMIT_DATA *TxData;\r
486 EFI_STATUS Status;\r
487\r
488 ASSERT (Sock && (SOCK_STREAM == Sock->Type));\r
489\r
490 FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);\r
491\r
492 //\r
493 // to determine if process a send token using\r
494 // socket layer flow control policy\r
495 //\r
496 while ((FreeSpace >= Sock->SndBuffer.LowWater) &&\r
e48e37fc 497 !IsListEmpty (&Sock->SndTokenList)) {\r
8a67d61d 498\r
499 SockToken = NET_LIST_HEAD (\r
500 &(Sock->SndTokenList),\r
501 SOCK_TOKEN,\r
502 TokenList\r
503 );\r
504\r
505 //\r
506 // process this token\r
507 //\r
e48e37fc 508 RemoveEntryList (&(SockToken->TokenList));\r
509 InsertTailList (\r
8a67d61d 510 &(Sock->ProcessingSndTokenList),\r
511 &(SockToken->TokenList)\r
512 );\r
513\r
514 //\r
515 // Proceess it in the light of SockType\r
516 //\r
517 SndToken = (SOCK_IO_TOKEN *) SockToken->Token;\r
518 TxData = SndToken->Packet.TxData;\r
519\r
4eb65aff 520 DataLen = (UINT32) TxData->DataLength;\r
8a67d61d 521 Status = SockProcessTcpSndData (Sock, TxData);\r
522\r
523 if (EFI_ERROR (Status)) {\r
524 goto OnError;\r
525 }\r
526\r
527 if (DataLen >= FreeSpace) {\r
528 FreeSpace = 0;\r
529\r
530 } else {\r
531 FreeSpace -= DataLen;\r
532\r
533 }\r
534 }\r
535\r
536 return ;\r
537\r
538OnError:\r
539\r
e48e37fc 540 RemoveEntryList (&SockToken->TokenList);\r
8a67d61d 541 SIGNAL_TOKEN (SockToken->Token, Status);\r
e48e37fc 542 gBS->FreePool (SockToken);\r
8a67d61d 543}\r
544\r
545\r
546/**\r
547 Create a socket with initial data SockInitData.\r
548\r
549 @param SockInitData Pointer to the initial data of the socket.\r
550\r
551 @return Pointer to the newly created socket.\r
552\r
553**/\r
554SOCKET *\r
555SockCreate (\r
556 IN SOCK_INIT_DATA *SockInitData\r
557 )\r
558{\r
559 SOCKET *Sock;\r
560 SOCKET *Parent;\r
561 EFI_STATUS Status;\r
562\r
563 ASSERT (SockInitData && SockInitData->ProtoHandler);\r
564 ASSERT (SockInitData->Type == SOCK_STREAM);\r
4f6e31e4 565 ASSERT (SockInitData->ProtoData && (SockInitData->DataSize <= PROTO_RESERVED_LEN));\r
8a67d61d 566\r
567 Parent = SockInitData->Parent;\r
568\r
569 if (Parent && (Parent->ConnCnt == Parent->BackLog)) {\r
e48e37fc 570 DEBUG (\r
571 (EFI_D_ERROR,\r
572 "SockCreate: Socket parent has "\r
8a67d61d 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
e48e37fc 581 Sock = AllocateZeroPool (sizeof (SOCKET));\r
8a67d61d 582 if (NULL == Sock) {\r
583\r
e48e37fc 584 DEBUG ((EFI_D_ERROR, "SockCreate: No resource to create a new socket\n"));\r
8a67d61d 585 return NULL;\r
586 }\r
587\r
e48e37fc 588 InitializeListHead (&Sock->Link);\r
589 InitializeListHead (&Sock->ConnectionList);\r
590 InitializeListHead (&Sock->ListenTokenList);\r
591 InitializeListHead (&Sock->RcvTokenList);\r
592 InitializeListHead (&Sock->SndTokenList);\r
593 InitializeListHead (&Sock->ProcessingSndTokenList);\r
8a67d61d 594\r
e48e37fc 595 EfiInitializeLock (&(Sock->Lock), TPL_CALLBACK);\r
8a67d61d 596\r
597 Sock->SndBuffer.DataQueue = NetbufQueAlloc ();\r
598 if (NULL == Sock->SndBuffer.DataQueue) {\r
e48e37fc 599 DEBUG ((EFI_D_ERROR, "SockCreate: No resource to allocate"\r
8a67d61d 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
e48e37fc 607 DEBUG ((EFI_D_ERROR, "SockCreate: No resource to allocate "\r
8a67d61d 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
4f6e31e4 623 Sock->CreateCallback = SockInitData->CreateCallback;\r
624 Sock->DestroyCallback = SockInitData->DestroyCallback;\r
625 Sock->Context = SockInitData->Context;\r
8a67d61d 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
e48e37fc 634 CopyMem (\r
8a67d61d 635 &(Sock->NetProtocol.TcpProtocol),\r
636 SockInitData->Protocol,\r
637 sizeof (EFI_TCP4_PROTOCOL)\r
638 );\r
639\r
4f6e31e4 640 //\r
641 // copy the protodata into socket\r
642 //\r
e48e37fc 643 CopyMem (Sock->ProtoReserved, SockInitData->ProtoData, SockInitData->DataSize);\r
4f6e31e4 644\r
8a67d61d 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
e48e37fc 653 DEBUG ((EFI_D_ERROR, "SockCreate: Install TCP protocol in "\r
8a67d61d 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
e48e37fc 669 DEBUG (\r
670 (EFI_D_WARN,\r
671 "SockCreate: Create a new socket and add to parent, now conncnt is %d\n",\r
672 Parent->ConnCnt)\r
673 );\r
8a67d61d 674\r
e48e37fc 675 InsertTailList (&Parent->ConnectionList, &Sock->ConnectionList);\r
8a67d61d 676 }\r
677\r
4f6e31e4 678 if (Sock->CreateCallback != NULL) {\r
679 Status = Sock->CreateCallback (Sock, Sock->Context);\r
680 if (EFI_ERROR (Status)) {\r
681 goto OnError;\r
682 }\r
683 }\r
684\r
8a67d61d 685 return Sock;\r
686\r
687OnError:\r
8a67d61d 688\r
4f6e31e4 689 if (Sock->SockHandle != NULL) {\r
690 gBS->UninstallMultipleProtocolInterfaces (\r
691 Sock->SockHandle,\r
692 &gEfiTcp4ProtocolGuid,\r
693 &(Sock->NetProtocol.TcpProtocol),\r
694 NULL\r
695 );\r
696 }\r
8a67d61d 697\r
4f6e31e4 698 if (NULL != Sock->SndBuffer.DataQueue) {\r
699 NetbufQueFree (Sock->SndBuffer.DataQueue);\r
700 }\r
8a67d61d 701\r
4f6e31e4 702 if (NULL != Sock->RcvBuffer.DataQueue) {\r
703 NetbufQueFree (Sock->RcvBuffer.DataQueue);\r
8a67d61d 704 }\r
705\r
e48e37fc 706 gBS->FreePool (Sock);\r
4f6e31e4 707\r
8a67d61d 708 return NULL;\r
709}\r
710\r
711\r
712/**\r
713 Destroy a socket.\r
714\r
715 @param Sock Pointer to the socket.\r
716\r
717 @return None.\r
718\r
719**/\r
720VOID\r
721SockDestroy (\r
722 IN SOCKET *Sock\r
723 )\r
724{\r
725 VOID *SockProtocol;\r
726 EFI_GUID *ProtocolGuid;\r
727 EFI_STATUS Status;\r
728\r
729 ASSERT (SOCK_STREAM == Sock->Type);\r
730\r
4f6e31e4 731 if (Sock->DestroyCallback != NULL) {\r
732 Sock->DestroyCallback (Sock, Sock->Context);\r
733 }\r
734\r
8a67d61d 735 //\r
736 // Flush the completion token buffered\r
737 // by sock and rcv, snd buffer\r
738 //\r
739 if (!SOCK_IS_UNCONFIGURED (Sock)) {\r
740\r
741 SockConnFlush (Sock);\r
742 SockSetState (Sock, SO_CLOSED);\r
743 Sock->ConfigureState = SO_UNCONFIGURED;\r
744\r
745 }\r
746 //\r
747 // Destory the RcvBuffer Queue and SendBuffer Queue\r
748 //\r
749 NetbufQueFree (Sock->RcvBuffer.DataQueue);\r
750 NetbufQueFree (Sock->SndBuffer.DataQueue);\r
751\r
752 //\r
753 // Remove it from parent connection list if needed\r
754 //\r
755 if (Sock->Parent) {\r
756\r
e48e37fc 757 RemoveEntryList (&(Sock->ConnectionList));\r
8a67d61d 758 (Sock->Parent->ConnCnt)--;\r
759\r
e48e37fc 760 DEBUG (\r
761 (EFI_D_WARN,\r
762 "SockDestory: Delete a unaccepted socket from parent"\r
763 "now conncnt is %d\n",\r
764 Sock->Parent->ConnCnt)\r
765 );\r
8a67d61d 766\r
767 Sock->Parent = NULL;\r
768 }\r
769\r
770 //\r
771 // Set the protocol guid and driver binding handle\r
772 // in the light of Sock->SockType\r
773 //\r
774 ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
775\r
776 //\r
777 // Retrieve the protocol installed on this sock\r
778 //\r
779 Status = gBS->OpenProtocol (\r
780 Sock->SockHandle,\r
781 ProtocolGuid,\r
782 &SockProtocol,\r
783 Sock->DriverBinding,\r
784 Sock->SockHandle,\r
785 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
786 );\r
787\r
788 if (EFI_ERROR (Status)) {\r
789\r
e48e37fc 790 DEBUG ((EFI_D_ERROR, "SockDestroy: Open protocol installed "\r
8a67d61d 791 "on socket failed with %r\n", Status));\r
792\r
793 goto FreeSock;\r
794 }\r
795\r
796 //\r
797 // Uninstall the protocol installed on this sock\r
798 // in the light of Sock->SockType\r
799 //\r
800 gBS->UninstallMultipleProtocolInterfaces (\r
801 Sock->SockHandle,\r
802 ProtocolGuid,\r
803 SockProtocol,\r
804 NULL\r
805 );\r
806\r
807FreeSock:\r
e48e37fc 808 gBS->FreePool (Sock);\r
8a67d61d 809 return ;\r
810}\r
811\r
812\r
813/**\r
814 Flush the socket.\r
815\r
816 @param Sock Pointer to the socket.\r
817\r
818 @return None.\r
819\r
820**/\r
821VOID\r
822SockConnFlush (\r
823 IN SOCKET *Sock\r
824 )\r
825{\r
826 SOCKET *Child;\r
827\r
828 ASSERT (Sock);\r
829\r
830 //\r
831 // Clear the flag in this socket\r
832 //\r
833 Sock->Flag = 0;\r
834\r
835 //\r
836 // Flush the SndBuffer and RcvBuffer of Sock\r
837 //\r
838 NetbufQueFlush (Sock->SndBuffer.DataQueue);\r
839 NetbufQueFlush (Sock->RcvBuffer.DataQueue);\r
840\r
841 //\r
842 // Signal the pending token\r
843 //\r
844 if (Sock->ConnectionToken != NULL) {\r
845 SIGNAL_TOKEN (Sock->ConnectionToken, Sock->SockError);\r
846 Sock->ConnectionToken = NULL;\r
847 }\r
848\r
849 if (Sock->CloseToken != NULL) {\r
850 SIGNAL_TOKEN (Sock->CloseToken, Sock->SockError);\r
851 Sock->CloseToken = NULL;\r
852 }\r
853\r
854 SockFlushPendingToken (Sock, &(Sock->ListenTokenList));\r
855 SockFlushPendingToken (Sock, &(Sock->RcvTokenList));\r
856 SockFlushPendingToken (Sock, &(Sock->SndTokenList));\r
857 SockFlushPendingToken (Sock, &(Sock->ProcessingSndTokenList));\r
858\r
859 //\r
860 // Destroy the pending connection, if it is a listening socket\r
861 //\r
862 if (SOCK_IS_LISTENING (Sock)) {\r
e48e37fc 863 while (!IsListEmpty (&Sock->ConnectionList)) {\r
8a67d61d 864 Child = NET_LIST_HEAD (\r
865 &Sock->ConnectionList,\r
866 SOCKET,\r
867 ConnectionList\r
868 );\r
869\r
870 SockDestroyChild (Child);\r
871 }\r
872\r
873 Sock->ConnCnt = 0;\r
874 }\r
875\r
876 return ;\r
877}\r
878\r
879\r
880/**\r
881 Set the state of the socket.\r
882\r
883 @param Sock Pointer to the socket.\r
884 @param State The new state to be set.\r
885\r
886 @return None.\r
887\r
888**/\r
889VOID\r
890SockSetState (\r
891 IN SOCKET *Sock,\r
892 IN SOCK_STATE State\r
893 )\r
894{\r
895 Sock->State = State;\r
896}\r
897\r
898\r
899/**\r
900 Clone a new socket including its associated protocol control block.\r
901\r
902 @param Sock Pointer to the socket to be cloned.\r
903\r
904 @retval * Pointer to the newly cloned socket. If NULL, error\r
905 condition occurred.\r
906\r
907**/\r
908SOCKET *\r
909SockClone (\r
910 IN SOCKET *Sock\r
911 )\r
912{\r
913 SOCKET *ClonedSock;\r
914 SOCK_INIT_DATA InitData;\r
915\r
916 InitData.BackLog = Sock->BackLog;\r
917 InitData.Parent = Sock;\r
918 InitData.State = Sock->State;\r
919 InitData.ProtoHandler = Sock->ProtoHandler;\r
920 InitData.Type = Sock->Type;\r
921 InitData.RcvBufferSize = Sock->RcvBuffer.HighWater;\r
922 InitData.SndBufferSize = Sock->SndBuffer.HighWater;\r
923 InitData.DriverBinding = Sock->DriverBinding;\r
924 InitData.Protocol = &(Sock->NetProtocol);\r
4f6e31e4 925 InitData.CreateCallback = Sock->CreateCallback;\r
926 InitData.DestroyCallback = Sock->DestroyCallback;\r
927 InitData.Context = Sock->Context;\r
928 InitData.ProtoData = Sock->ProtoReserved;\r
929 InitData.DataSize = sizeof (Sock->ProtoReserved);\r
8a67d61d 930\r
931 ClonedSock = SockCreate (&InitData);\r
932\r
933 if (NULL == ClonedSock) {\r
e48e37fc 934 DEBUG ((EFI_D_ERROR, "SockClone: no resource to create a cloned sock\n"));\r
8a67d61d 935 return NULL;\r
936 }\r
937\r
8a67d61d 938 SockSetState (ClonedSock, SO_CONNECTING);\r
939 ClonedSock->ConfigureState = Sock->ConfigureState;\r
940\r
941 return ClonedSock;\r
942}\r
943\r
944\r
945/**\r
946 Called by the low layer protocol to indicate the socket\r
947 a connection is established. This function just changes\r
948 the socket's state to SO_CONNECTED and signals the token\r
949 used for connection establishment.\r
950\r
951 @param Sock Pointer to the socket associated with the\r
952 established connection.\r
953\r
954 @return None.\r
955\r
956**/\r
957VOID\r
958SockConnEstablished (\r
959 IN SOCKET *Sock\r
960 )\r
961{\r
962\r
963 ASSERT (SO_CONNECTING == Sock->State);\r
964\r
965 SockSetState (Sock, SO_CONNECTED);\r
966\r
967 if (NULL == Sock->Parent) {\r
968 SockWakeConnToken (Sock);\r
969 } else {\r
970 SockWakeListenToken (Sock);\r
971 }\r
972\r
973 return ;\r
974}\r
975\r
976\r
977/**\r
978 Called by the low layer protocol to indicate the connection\r
979 is closed. This function flushes the socket, sets the state\r
980 to SO_CLOSED and signals the close token.\r
981\r
982 @param Sock Pointer to the socket associated with the closed\r
983 connection.\r
984\r
985 @return None.\r
986\r
987**/\r
988VOID\r
989SockConnClosed (\r
990 IN SOCKET *Sock\r
991 )\r
992{\r
993 if (Sock->CloseToken) {\r
994 SIGNAL_TOKEN (Sock->CloseToken, EFI_SUCCESS);\r
995 Sock->CloseToken = NULL;\r
996 }\r
997\r
998 SockConnFlush (Sock);\r
999 SockSetState (Sock, SO_CLOSED);\r
1000\r
1001 if (Sock->Parent != NULL) {\r
1002 SockDestroyChild (Sock);\r
1003 }\r
1004\r
1005}\r
1006\r
1007\r
1008/**\r
1009 Called by low layer protocol to indicate that some\r
1010 data is sent or processed. This function trims the\r
1011 sent data in the socket send buffer, signals the\r
1012 data token if proper\r
1013\r
1014 @param Sock Pointer to the socket.\r
1015 @param Count The length of the data processed or sent, in bytes.\r
1016\r
1017 @return None.\r
1018\r
1019**/\r
1020VOID\r
1021SockDataSent (\r
1022 IN SOCKET *Sock,\r
1023 IN UINT32 Count\r
1024 )\r
1025{\r
1026 SOCK_TOKEN *SockToken;\r
1027 SOCK_COMPLETION_TOKEN *SndToken;\r
1028\r
e48e37fc 1029 ASSERT (!IsListEmpty (&Sock->ProcessingSndTokenList));\r
8a67d61d 1030 ASSERT (Count <= (Sock->SndBuffer.DataQueue)->BufSize);\r
1031\r
1032 NetbufQueTrim (Sock->SndBuffer.DataQueue, Count);\r
1033\r
1034 //\r
1035 // To check if we can signal some snd token in this socket\r
1036 //\r
1037 while (Count > 0) {\r
1038 SockToken = NET_LIST_HEAD (\r
1039 &(Sock->ProcessingSndTokenList),\r
1040 SOCK_TOKEN,\r
1041 TokenList\r
1042 );\r
1043\r
1044 SndToken = SockToken->Token;\r
1045\r
1046 if (SockToken->RemainDataLen <= Count) {\r
1047\r
e48e37fc 1048 RemoveEntryList (&(SockToken->TokenList));\r
8a67d61d 1049 SIGNAL_TOKEN (SndToken, EFI_SUCCESS);\r
1050 Count -= SockToken->RemainDataLen;\r
e48e37fc 1051 gBS->FreePool (SockToken);\r
8a67d61d 1052 } else {\r
1053\r
1054 SockToken->RemainDataLen -= Count;\r
1055 Count = 0;\r
1056 }\r
1057 }\r
1058\r
1059 //\r
1060 // to judge if we can process some send token in\r
1061 // Sock->SndTokenList, if so process those send token\r
1062 //\r
1063 SockProcessSndToken (Sock);\r
1064 return ;\r
1065}\r
1066\r
1067\r
1068/**\r
1069 Called by the low layer protocol to copy some data in socket send\r
1070 buffer starting from the specific offset to a buffer provided by\r
1071 the caller.\r
1072\r
1073 @param Sock Pointer to the socket.\r
1074 @param Offset The start point of the data to be copied.\r
1075 @param Len The length of the data to be copied.\r
1076 @param Dest Pointer to the destination to copy the data.\r
1077\r
1078 @return The data size copied.\r
1079\r
1080**/\r
1081UINT32\r
1082SockGetDataToSend (\r
1083 IN SOCKET *Sock,\r
1084 IN UINT32 Offset,\r
1085 IN UINT32 Len,\r
1086 IN UINT8 *Dest\r
1087 )\r
1088{\r
1089 ASSERT (Sock && SOCK_STREAM == Sock->Type);\r
1090\r
1091 return NetbufQueCopy (\r
1092 Sock->SndBuffer.DataQueue,\r
1093 Offset,\r
1094 Len,\r
1095 Dest\r
1096 );\r
1097}\r
1098\r
1099\r
1100/**\r
1101 Called by the low layer protocol to deliver received data\r
1102 to socket layer. This function will append the data to the\r
1103 socket receive buffer, set ther urgent data length and then\r
1104 check if any receive token can be signaled.\r
1105\r
1106 @param Sock Pointer to the socket.\r
1107 @param NetBuffer Pointer to the buffer that contains the received\r
1108 data.\r
1109 @param UrgLen The length of the urgent data in the received data.\r
1110\r
1111 @return None.\r
1112\r
1113**/\r
1114VOID\r
1115SockDataRcvd (\r
1116 IN SOCKET *Sock,\r
1117 IN NET_BUF *NetBuffer,\r
1118 IN UINT32 UrgLen\r
1119 )\r
1120{\r
1121 ASSERT (Sock && Sock->RcvBuffer.DataQueue &&\r
1122 UrgLen <= NetBuffer->TotalSize);\r
1123\r
1124 NET_GET_REF (NetBuffer);\r
1125\r
1126 ((TCP_RSV_DATA *) (NetBuffer->ProtoData))->UrgLen = UrgLen;\r
1127\r
1128 NetbufQueAppend (Sock->RcvBuffer.DataQueue, NetBuffer);\r
1129\r
1130 SockWakeRcvToken (Sock);\r
1131 return ;\r
1132}\r
1133\r
1134\r
1135/**\r
1136 Get the length of the free space of the specific socket buffer.\r
1137\r
1138 @param Sock Pointer to the socket.\r
1139 @param Which Flag to indicate which socket buffer to check,\r
1140 either send buffer or receive buffer.\r
1141\r
1142 @return The length of the free space, in bytes.\r
1143\r
1144**/\r
1145UINT32\r
1146SockGetFreeSpace (\r
1147 IN SOCKET *Sock,\r
1148 IN UINT32 Which\r
1149 )\r
1150{\r
1151 UINT32 BufferCC;\r
1152 SOCK_BUFFER *SockBuffer;\r
1153\r
1154 ASSERT (Sock && ((SOCK_SND_BUF == Which) || (SOCK_RCV_BUF == Which)));\r
1155\r
1156 if (SOCK_SND_BUF == Which) {\r
1157 SockBuffer = &(Sock->SndBuffer);\r
1158 } else {\r
1159 SockBuffer = &(Sock->RcvBuffer);\r
1160 }\r
1161\r
1162 BufferCC = (SockBuffer->DataQueue)->BufSize;\r
1163\r
1164 if (BufferCC >= SockBuffer->HighWater) {\r
1165\r
1166 return 0;\r
1167 }\r
1168\r
1169 return SockBuffer->HighWater - BufferCC;\r
1170}\r
1171\r
1172\r
1173/**\r
1174 Signal the receive token with the specific error or\r
1175 set socket error code after error is received.\r
1176\r
1177 @param Sock Pointer to the socket.\r
1178 @param Error The error code received.\r
1179\r
1180 @return None.\r
1181\r
1182**/\r
1183VOID\r
1184SockRcvdErr (\r
1185 IN SOCKET *Sock,\r
1186 IN EFI_STATUS Error\r
1187 )\r
1188{\r
1189 SOCK_TOKEN *SockToken;\r
1190\r
e48e37fc 1191 if (!IsListEmpty (&Sock->RcvTokenList)) {\r
8a67d61d 1192\r
1193 SockToken = NET_LIST_HEAD (\r
1194 &Sock->RcvTokenList,\r
1195 SOCK_TOKEN,\r
1196 TokenList\r
1197 );\r
1198\r
e48e37fc 1199 RemoveEntryList (&SockToken->TokenList);\r
8a67d61d 1200\r
1201 SIGNAL_TOKEN (SockToken->Token, Error);\r
1202\r
e48e37fc 1203 gBS->FreePool (SockToken);\r
8a67d61d 1204 } else {\r
1205\r
1206 SOCK_ERROR (Sock, Error);\r
1207 }\r
1208}\r
1209\r
1210\r
1211/**\r
1212 Called by the low layer protocol to indicate that there\r
1213 will be no more data from the communication peer. This\r
1214 function set the socket's state to SO_NO_MORE_DATA and\r
1215 signal all queued IO tokens with the error status\r
1216 EFI_CONNECTION_FIN.\r
1217\r
1218 @param Sock Pointer to the socket.\r
1219\r
1220 @return None.\r
1221\r
1222**/\r
1223VOID\r
1224SockNoMoreData (\r
1225 IN SOCKET *Sock\r
1226 )\r
1227{\r
1228 EFI_STATUS Err;\r
1229\r
1230 SOCK_NO_MORE_DATA (Sock);\r
1231\r
e48e37fc 1232 if (!IsListEmpty (&Sock->RcvTokenList)) {\r
8a67d61d 1233\r
1234 ASSERT (0 == GET_RCV_DATASIZE (Sock));\r
1235\r
1236 Err = Sock->SockError;\r
1237\r
1238 SOCK_ERROR (Sock, EFI_CONNECTION_FIN);\r
1239\r
1240 SockFlushPendingToken (Sock, &Sock->RcvTokenList);\r
1241\r
1242 SOCK_ERROR (Sock, Err);\r
1243\r
1244 }\r
1245\r
1246}\r
1247\r
1248\r
1249/**\r
1250 Get the first buffer block in the specific socket buffer.\r
1251\r
1252 @param Sockbuf Pointer to the socket buffer.\r
1253\r
1254 @return Pointer to the first buffer in the queue. NULL if the queue is empty.\r
1255\r
1256**/\r
1257NET_BUF *\r
1258SockBufFirst (\r
1259 IN SOCK_BUFFER *Sockbuf\r
1260 )\r
1261{\r
e48e37fc 1262 LIST_ENTRY *NetbufList;\r
8a67d61d 1263\r
1264 NetbufList = &(Sockbuf->DataQueue->BufList);\r
1265\r
e48e37fc 1266 if (IsListEmpty (NetbufList)) {\r
8a67d61d 1267 return NULL;\r
1268 }\r
1269\r
1270 return NET_LIST_HEAD (NetbufList, NET_BUF, List);\r
1271}\r
1272\r
1273\r
1274/**\r
1275 Get the next buffer block in the specific socket buffer.\r
1276\r
1277 @param Sockbuf Pointer to the socket buffer.\r
1278 @param SockEntry Pointer to the buffer block prior to the required\r
1279 one.\r
1280\r
1281 @return Pointer to the buffer block next to SockEntry. NULL if SockEntry is the tail or head entry.\r
1282\r
1283**/\r
1284NET_BUF *\r
1285SockBufNext (\r
1286 IN SOCK_BUFFER *Sockbuf,\r
1287 IN NET_BUF *SockEntry\r
1288 )\r
1289{\r
e48e37fc 1290 LIST_ENTRY *NetbufList;\r
8a67d61d 1291\r
1292 NetbufList = &(Sockbuf->DataQueue->BufList);\r
1293\r
1294 if ((SockEntry->List.ForwardLink == NetbufList) ||\r
1295 (SockEntry->List.BackLink == &SockEntry->List) ||\r
1296 (SockEntry->List.ForwardLink == &SockEntry->List)\r
1297 ) {\r
1298\r
1299 return NULL;\r
1300 }\r
1301\r
1302 return NET_LIST_USER_STRUCT (SockEntry->List.ForwardLink, NET_BUF, List);\r
1303}\r