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