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