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