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