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