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