]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/SockImpl.c
MdeModulePkg: Fix service binding issue in TCP4 and Ip4 dxe.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / SockImpl.c
CommitLineData
8a67d61d 1/** @file\r
dab714aa 2 Implementation of the Socket.\r
8a67d61d 3\r
4bb89650 4Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 5This program and the accompanying materials\r
8a67d61d 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
dea6914d 36\r
120db52c 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
dea6914d 52\r
120db52c 53**/\r
8a67d61d 54VOID\r
e798cd87 55EFIAPI\r
8a67d61d 56SockFreeFoo (\r
57 IN EFI_EVENT Event\r
58 )\r
59{\r
60 return ;\r
61}\r
62\r
63\r
64/**\r
65 Get the length of the data that can be retrieved from the socket\r
66 receive buffer.\r
67\r
68 @param SockBuffer Pointer to the socket receive buffer.\r
69 @param IsUrg Pointer to a BOOLEAN variable. If TRUE the data is\r
70 OOB.\r
71 @param BufLen The maximum length of the data buffer to store the\r
72 received data in socket layer.\r
73\r
74 @return The length of the data can be retreived.\r
75\r
76**/\r
8a67d61d 77UINT32\r
78SockTcpDataToRcv (\r
120db52c 79 IN SOCK_BUFFER *SockBuffer,\r
80 OUT BOOLEAN *IsUrg,\r
81 IN UINT32 BufLen\r
8a67d61d 82 )\r
83{\r
84 NET_BUF *RcvBufEntry;\r
85 UINT32 DataLen;\r
86 TCP_RSV_DATA *TcpRsvData;\r
87 BOOLEAN Urg;\r
120db52c 88 ASSERT ((SockBuffer != NULL) && (IsUrg != NULL) && (BufLen > 0));\r
8a67d61d 89\r
90 RcvBufEntry = SockBufFirst (SockBuffer);\r
120db52c 91 ASSERT (RcvBufEntry != NULL);\r
8a67d61d 92\r
93 TcpRsvData = (TCP_RSV_DATA *) RcvBufEntry->ProtoData;\r
94\r
4eb65aff 95 *IsUrg = (BOOLEAN) ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);\r
8a67d61d 96\r
97 if (*IsUrg && TcpRsvData->UrgLen < RcvBufEntry->TotalSize) {\r
98\r
36ee91ca 99 DataLen = MIN (TcpRsvData->UrgLen, BufLen);\r
8a67d61d 100\r
101 if (DataLen < TcpRsvData->UrgLen) {\r
102 TcpRsvData->UrgLen = TcpRsvData->UrgLen - DataLen;\r
103 } else {\r
104 TcpRsvData->UrgLen = 0;\r
105 }\r
106\r
107 return DataLen;\r
108\r
109 }\r
110\r
111 DataLen = RcvBufEntry->TotalSize;\r
112\r
113 RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);\r
114\r
115 while ((BufLen > DataLen) && (RcvBufEntry != NULL)) {\r
116\r
117 TcpRsvData = (TCP_RSV_DATA *) RcvBufEntry->ProtoData;\r
118\r
4eb65aff 119 Urg = (BOOLEAN) ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);\r
8a67d61d 120\r
121 if (*IsUrg != Urg) {\r
122 break;\r
123 }\r
124\r
125 if (*IsUrg && TcpRsvData->UrgLen < RcvBufEntry->TotalSize) {\r
126\r
127 if (TcpRsvData->UrgLen + DataLen < BufLen) {\r
128 TcpRsvData->UrgLen = 0;\r
129 } else {\r
130 TcpRsvData->UrgLen = TcpRsvData->UrgLen - (BufLen - DataLen);\r
131 }\r
132\r
36ee91ca 133 return MIN (TcpRsvData->UrgLen + DataLen, BufLen);\r
8a67d61d 134\r
135 }\r
136\r
137 DataLen += RcvBufEntry->TotalSize;\r
138\r
139 RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);\r
140 }\r
141\r
36ee91ca 142 DataLen = MIN (BufLen, DataLen);\r
8a67d61d 143 return DataLen;\r
144}\r
145\r
146\r
147/**\r
148 Copy data from socket buffer to application provided receive buffer.\r
149\r
150 @param Sock Pointer to the socket.\r
151 @param TcpRxData Pointer to the application provided receive buffer.\r
152 @param RcvdBytes The maximum length of the data can be copied.\r
0a18956d 153 @param IsOOB If TRUE the data is OOB, FALSE the data is normal.\r
8a67d61d 154\r
8a67d61d 155**/\r
156VOID\r
157SockSetTcpRxData (\r
158 IN SOCKET *Sock,\r
159 IN VOID *TcpRxData,\r
160 IN UINT32 RcvdBytes,\r
161 IN BOOLEAN IsOOB\r
162 )\r
163{\r
164 UINT32 Index;\r
165 UINT32 CopyBytes;\r
166 UINT32 OffSet;\r
167 EFI_TCP4_RECEIVE_DATA *RxData;\r
168 EFI_TCP4_FRAGMENT_DATA *Fragment;\r
169\r
170 RxData = (EFI_TCP4_RECEIVE_DATA *) TcpRxData;\r
171\r
172 OffSet = 0;\r
173\r
174 ASSERT (RxData->DataLength >= RcvdBytes);\r
175\r
176 RxData->DataLength = RcvdBytes;\r
177 RxData->UrgentFlag = IsOOB;\r
178\r
179 for (Index = 0; (Index < RxData->FragmentCount) && (RcvdBytes > 0); Index++) {\r
180\r
181 Fragment = &RxData->FragmentTable[Index];\r
36ee91ca 182 CopyBytes = MIN ((UINT32) (Fragment->FragmentLength), RcvdBytes);\r
8a67d61d 183\r
184 NetbufQueCopy (\r
185 Sock->RcvBuffer.DataQueue,\r
186 OffSet,\r
187 CopyBytes,\r
188 Fragment->FragmentBuffer\r
189 );\r
190\r
191 Fragment->FragmentLength = CopyBytes;\r
192 RcvdBytes -= CopyBytes;\r
193 OffSet += CopyBytes;\r
194 }\r
195}\r
196\r
197\r
198/**\r
199 Get received data from the socket layer to the receive token.\r
200\r
201 @param Sock Pointer to the socket.\r
202 @param RcvToken Pointer to the application provided receive token.\r
203\r
204 @return The length of data received in this token.\r
205\r
206**/\r
207UINT32\r
208SockProcessRcvToken (\r
77f00155 209 IN SOCKET *Sock,\r
210 IN OUT SOCK_IO_TOKEN *RcvToken\r
8a67d61d 211 )\r
212{\r
213 UINT32 TokenRcvdBytes;\r
214 EFI_TCP4_RECEIVE_DATA *RxData;\r
215 BOOLEAN IsUrg;\r
216\r
120db52c 217 ASSERT (Sock != NULL);\r
8a67d61d 218\r
f6b7393c 219 ASSERT (SockStream == Sock->Type);\r
8a67d61d 220\r
221 RxData = RcvToken->Packet.RxData;\r
222\r
223 TokenRcvdBytes = SockTcpDataToRcv (\r
224 &Sock->RcvBuffer,\r
225 &IsUrg,\r
4eb65aff 226 (UINT32) RxData->DataLength\r
8a67d61d 227 );\r
228\r
229 //\r
230 // Copy data from RcvBuffer of socket to user\r
231 // provided RxData and set the fields in TCP RxData\r
232 //\r
233 SockSetTcpRxData (Sock, RxData, TokenRcvdBytes, IsUrg);\r
234\r
dfc1f033 235 NetbufQueTrim (Sock->RcvBuffer.DataQueue, 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
77f00155 247 @param TcpTxData Pointer to the application provided send buffer.\r
8a67d61d 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
dea6914d 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
766c7483 349 FreePool (SockToken);\r
8a67d61d 350 }\r
351}\r
352\r
353\r
354/**\r
dea6914d 355 Wake up the connection token while the connection is successfully established,\r
120db52c 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
77f00155 363 IN OUT SOCKET *Sock\r
8a67d61d 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
77f00155 387 IN OUT SOCKET *Sock\r
8a67d61d 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
766c7483 411 FreePool (SockToken);\r
8a67d61d 412\r
e48e37fc 413 RemoveEntryList (&Sock->ConnectionList);\r
8a67d61d 414\r
415 Parent->ConnCnt--;\r
dea6914d 416 DEBUG ((EFI_D_NET, "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
766c7483 461 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
77f00155 475 IN OUT SOCKET *Sock\r
8a67d61d 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
f6b7393c 485 ASSERT ((Sock != NULL) && (SockStream == 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
766c7483 539 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
276dcc1b 548 @return Pointer to the newly created socket, return NULL when exception occured.\r
8a67d61d 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
f6b7393c 561 ASSERT (SockInitData->Type == SockStream);\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
dea6914d 667 (EFI_D_NET,\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
766c7483 703 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
77f00155 717 IN OUT SOCKET *Sock\r
8a67d61d 718 )\r
719{\r
f6b7393c 720 ASSERT (SockStream == Sock->Type);\r
8a67d61d 721\r
722 //\r
723 // Flush the completion token buffered\r
724 // by sock and rcv, snd buffer\r
725 //\r
726 if (!SOCK_IS_UNCONFIGURED (Sock)) {\r
727\r
728 SockConnFlush (Sock);\r
729 SockSetState (Sock, SO_CLOSED);\r
730 Sock->ConfigureState = SO_UNCONFIGURED;\r
731\r
732 }\r
733 //\r
75dce340 734 // Destroy the RcvBuffer Queue and SendBuffer Queue\r
8a67d61d 735 //\r
736 NetbufQueFree (Sock->RcvBuffer.DataQueue);\r
737 NetbufQueFree (Sock->SndBuffer.DataQueue);\r
738\r
739 //\r
740 // Remove it from parent connection list if needed\r
741 //\r
85511ddf 742 if (Sock->Parent != NULL) {\r
8a67d61d 743\r
e48e37fc 744 RemoveEntryList (&(Sock->ConnectionList));\r
8a67d61d 745 (Sock->Parent->ConnCnt)--;\r
746\r
e48e37fc 747 DEBUG (\r
dea6914d 748 (EFI_D_NET,\r
75dce340 749 "SockDestroy: Delete a unaccepted socket from parent"\r
e48e37fc 750 "now conncnt is %d\n",\r
751 Sock->Parent->ConnCnt)\r
752 );\r
8a67d61d 753\r
754 Sock->Parent = NULL;\r
755 }\r
756\r
766c7483 757 FreePool (Sock);\r
8a67d61d 758 return ;\r
759}\r
760\r
761\r
762/**\r
77f00155 763 Flush the sndBuffer and rcvBuffer of socket.\r
8a67d61d 764\r
765 @param Sock Pointer to the socket.\r
766\r
8a67d61d 767**/\r
768VOID\r
769SockConnFlush (\r
77f00155 770 IN OUT SOCKET *Sock\r
8a67d61d 771 )\r
772{\r
773 SOCKET *Child;\r
774\r
120db52c 775 ASSERT (Sock != NULL);\r
8a67d61d 776\r
777 //\r
778 // Clear the flag in this socket\r
779 //\r
780 Sock->Flag = 0;\r
781\r
782 //\r
783 // Flush the SndBuffer and RcvBuffer of Sock\r
784 //\r
785 NetbufQueFlush (Sock->SndBuffer.DataQueue);\r
786 NetbufQueFlush (Sock->RcvBuffer.DataQueue);\r
787\r
788 //\r
789 // Signal the pending token\r
790 //\r
791 if (Sock->ConnectionToken != NULL) {\r
792 SIGNAL_TOKEN (Sock->ConnectionToken, Sock->SockError);\r
793 Sock->ConnectionToken = NULL;\r
794 }\r
795\r
796 if (Sock->CloseToken != NULL) {\r
797 SIGNAL_TOKEN (Sock->CloseToken, Sock->SockError);\r
798 Sock->CloseToken = NULL;\r
799 }\r
800\r
801 SockFlushPendingToken (Sock, &(Sock->ListenTokenList));\r
802 SockFlushPendingToken (Sock, &(Sock->RcvTokenList));\r
803 SockFlushPendingToken (Sock, &(Sock->SndTokenList));\r
804 SockFlushPendingToken (Sock, &(Sock->ProcessingSndTokenList));\r
805\r
806 //\r
807 // Destroy the pending connection, if it is a listening socket\r
808 //\r
809 if (SOCK_IS_LISTENING (Sock)) {\r
e48e37fc 810 while (!IsListEmpty (&Sock->ConnectionList)) {\r
8a67d61d 811 Child = NET_LIST_HEAD (\r
812 &Sock->ConnectionList,\r
813 SOCKET,\r
814 ConnectionList\r
815 );\r
816\r
817 SockDestroyChild (Child);\r
818 }\r
819\r
820 Sock->ConnCnt = 0;\r
821 }\r
822\r
823 return ;\r
824}\r
825\r
826\r
827/**\r
828 Set the state of the socket.\r
829\r
830 @param Sock Pointer to the socket.\r
f6b7393c 831 @param State The new socket state to be set.\r
8a67d61d 832\r
8a67d61d 833**/\r
834VOID\r
835SockSetState (\r
77f00155 836 IN OUT SOCKET *Sock,\r
f6b7393c 837 IN UINT8 State\r
8a67d61d 838 )\r
839{\r
840 Sock->State = State;\r
841}\r
842\r
843\r
844/**\r
845 Clone a new socket including its associated protocol control block.\r
846\r
847 @param Sock Pointer to the socket to be cloned.\r
848\r
120db52c 849 @return Pointer to the newly cloned socket. If NULL, error condition occurred.\r
8a67d61d 850\r
851**/\r
852SOCKET *\r
853SockClone (\r
854 IN SOCKET *Sock\r
855 )\r
856{\r
857 SOCKET *ClonedSock;\r
858 SOCK_INIT_DATA InitData;\r
859\r
120db52c 860 InitData.BackLog = Sock->BackLog;\r
861 InitData.Parent = Sock;\r
862 InitData.State = Sock->State;\r
863 InitData.ProtoHandler = Sock->ProtoHandler;\r
864 InitData.Type = Sock->Type;\r
865 InitData.RcvBufferSize = Sock->RcvBuffer.HighWater;\r
866 InitData.SndBufferSize = Sock->SndBuffer.HighWater;\r
867 InitData.DriverBinding = Sock->DriverBinding;\r
868 InitData.Protocol = &(Sock->NetProtocol);\r
4f6e31e4 869 InitData.CreateCallback = Sock->CreateCallback;\r
870 InitData.DestroyCallback = Sock->DestroyCallback;\r
871 InitData.Context = Sock->Context;\r
872 InitData.ProtoData = Sock->ProtoReserved;\r
873 InitData.DataSize = sizeof (Sock->ProtoReserved);\r
8a67d61d 874\r
120db52c 875 ClonedSock = SockCreate (&InitData);\r
8a67d61d 876\r
877 if (NULL == ClonedSock) {\r
e48e37fc 878 DEBUG ((EFI_D_ERROR, "SockClone: no resource to create a cloned sock\n"));\r
8a67d61d 879 return NULL;\r
880 }\r
881\r
8a67d61d 882 SockSetState (ClonedSock, SO_CONNECTING);\r
883 ClonedSock->ConfigureState = Sock->ConfigureState;\r
884\r
885 return ClonedSock;\r
886}\r
887\r
888\r
889/**\r
dea6914d
ZL
890 Called by the low layer protocol to indicate the socket a connection is\r
891 established.\r
892\r
893 This function just changes the socket's state to SO_CONNECTED\r
120db52c 894 and signals the token used for connection establishment.\r
8a67d61d 895\r
896 @param Sock Pointer to the socket associated with the\r
897 established connection.\r
8a67d61d 898**/\r
899VOID\r
900SockConnEstablished (\r
901 IN SOCKET *Sock\r
902 )\r
903{\r
904\r
905 ASSERT (SO_CONNECTING == Sock->State);\r
906\r
907 SockSetState (Sock, SO_CONNECTED);\r
908\r
909 if (NULL == Sock->Parent) {\r
910 SockWakeConnToken (Sock);\r
911 } else {\r
912 SockWakeListenToken (Sock);\r
913 }\r
914\r
915 return ;\r
916}\r
917\r
918\r
919/**\r
276dcc1b 920 Called by the low layer protocol to indicate the connection is closed.\r
dea6914d
ZL
921\r
922 This function flushes the socket, sets the state to SO_CLOSED and signals\r
276dcc1b 923 the close token.\r
8a67d61d 924\r
925 @param Sock Pointer to the socket associated with the closed\r
926 connection.\r
dea6914d 927\r
8a67d61d 928**/\r
929VOID\r
930SockConnClosed (\r
77f00155 931 IN OUT SOCKET *Sock\r
8a67d61d 932 )\r
933{\r
85511ddf 934 if (Sock->CloseToken != NULL) {\r
8a67d61d 935 SIGNAL_TOKEN (Sock->CloseToken, EFI_SUCCESS);\r
936 Sock->CloseToken = NULL;\r
937 }\r
938\r
939 SockConnFlush (Sock);\r
940 SockSetState (Sock, SO_CLOSED);\r
941\r
942 if (Sock->Parent != NULL) {\r
943 SockDestroyChild (Sock);\r
944 }\r
945\r
946}\r
947\r
948\r
949/**\r
276dcc1b 950 Called by low layer protocol to indicate that some data is sent or processed.\r
dea6914d
ZL
951\r
952 This function trims the sent data in the socket send buffer, signals the data\r
120db52c 953 token if proper.\r
8a67d61d 954\r
955 @param Sock Pointer to the socket.\r
956 @param Count The length of the data processed or sent, in bytes.\r
957\r
8a67d61d 958**/\r
959VOID\r
960SockDataSent (\r
961 IN SOCKET *Sock,\r
962 IN UINT32 Count\r
963 )\r
964{\r
965 SOCK_TOKEN *SockToken;\r
966 SOCK_COMPLETION_TOKEN *SndToken;\r
967\r
e48e37fc 968 ASSERT (!IsListEmpty (&Sock->ProcessingSndTokenList));\r
8a67d61d 969 ASSERT (Count <= (Sock->SndBuffer.DataQueue)->BufSize);\r
970\r
971 NetbufQueTrim (Sock->SndBuffer.DataQueue, Count);\r
972\r
973 //\r
974 // To check if we can signal some snd token in this socket\r
975 //\r
976 while (Count > 0) {\r
977 SockToken = NET_LIST_HEAD (\r
978 &(Sock->ProcessingSndTokenList),\r
979 SOCK_TOKEN,\r
980 TokenList\r
981 );\r
982\r
983 SndToken = SockToken->Token;\r
984\r
985 if (SockToken->RemainDataLen <= Count) {\r
986\r
e48e37fc 987 RemoveEntryList (&(SockToken->TokenList));\r
8a67d61d 988 SIGNAL_TOKEN (SndToken, EFI_SUCCESS);\r
989 Count -= SockToken->RemainDataLen;\r
766c7483 990 FreePool (SockToken);\r
8a67d61d 991 } else {\r
992\r
993 SockToken->RemainDataLen -= Count;\r
994 Count = 0;\r
995 }\r
996 }\r
997\r
998 //\r
999 // to judge if we can process some send token in\r
1000 // Sock->SndTokenList, if so process those send token\r
1001 //\r
1002 SockProcessSndToken (Sock);\r
1003 return ;\r
1004}\r
1005\r
1006\r
1007/**\r
1008 Called by the low layer protocol to copy some data in socket send\r
1009 buffer starting from the specific offset to a buffer provided by\r
1010 the caller.\r
1011\r
1012 @param Sock Pointer to the socket.\r
1013 @param Offset The start point of the data to be copied.\r
1014 @param Len The length of the data to be copied.\r
1015 @param Dest Pointer to the destination to copy the data.\r
1016\r
1017 @return The data size copied.\r
1018\r
1019**/\r
1020UINT32\r
1021SockGetDataToSend (\r
1022 IN SOCKET *Sock,\r
1023 IN UINT32 Offset,\r
1024 IN UINT32 Len,\r
1025 IN UINT8 *Dest\r
1026 )\r
1027{\r
f6b7393c 1028 ASSERT ((Sock != NULL) && SockStream == Sock->Type);\r
8a67d61d 1029\r
1030 return NetbufQueCopy (\r
1031 Sock->SndBuffer.DataQueue,\r
1032 Offset,\r
1033 Len,\r
1034 Dest\r
1035 );\r
1036}\r
1037\r
1038\r
1039/**\r
276dcc1b 1040 Called by the low layer protocol to deliver received data to socket layer.\r
dea6914d
ZL
1041\r
1042 This function will append the data to the socket receive buffer, set ther\r
120db52c 1043 urgent data length and then check if any receive token can be signaled.\r
8a67d61d 1044\r
1045 @param Sock Pointer to the socket.\r
1046 @param NetBuffer Pointer to the buffer that contains the received\r
1047 data.\r
1048 @param UrgLen The length of the urgent data in the received data.\r
1049\r
8a67d61d 1050**/\r
1051VOID\r
1052SockDataRcvd (\r
77f00155 1053 IN SOCKET *Sock,\r
1054 IN OUT NET_BUF *NetBuffer,\r
1055 IN UINT32 UrgLen\r
8a67d61d 1056 )\r
1057{\r
120db52c 1058 ASSERT ((Sock != NULL) && (Sock->RcvBuffer.DataQueue != NULL) &&\r
8a67d61d 1059 UrgLen <= NetBuffer->TotalSize);\r
1060\r
1061 NET_GET_REF (NetBuffer);\r
1062\r
1063 ((TCP_RSV_DATA *) (NetBuffer->ProtoData))->UrgLen = UrgLen;\r
1064\r
1065 NetbufQueAppend (Sock->RcvBuffer.DataQueue, NetBuffer);\r
1066\r
1067 SockWakeRcvToken (Sock);\r
1068 return ;\r
1069}\r
1070\r
1071\r
1072/**\r
1073 Get the length of the free space of the specific socket buffer.\r
1074\r
1075 @param Sock Pointer to the socket.\r
1076 @param Which Flag to indicate which socket buffer to check,\r
1077 either send buffer or receive buffer.\r
1078\r
1079 @return The length of the free space, in bytes.\r
1080\r
1081**/\r
1082UINT32\r
1083SockGetFreeSpace (\r
1084 IN SOCKET *Sock,\r
1085 IN UINT32 Which\r
1086 )\r
1087{\r
1088 UINT32 BufferCC;\r
1089 SOCK_BUFFER *SockBuffer;\r
1090\r
120db52c 1091 ASSERT ((Sock != NULL) && ((SOCK_SND_BUF == Which) || (SOCK_RCV_BUF == Which)));\r
8a67d61d 1092\r
1093 if (SOCK_SND_BUF == Which) {\r
1094 SockBuffer = &(Sock->SndBuffer);\r
1095 } else {\r
1096 SockBuffer = &(Sock->RcvBuffer);\r
1097 }\r
1098\r
1099 BufferCC = (SockBuffer->DataQueue)->BufSize;\r
1100\r
1101 if (BufferCC >= SockBuffer->HighWater) {\r
1102\r
1103 return 0;\r
1104 }\r
1105\r
1106 return SockBuffer->HighWater - BufferCC;\r
1107}\r
1108\r
1109\r
1110/**\r
1111 Signal the receive token with the specific error or\r
1112 set socket error code after error is received.\r
1113\r
1114 @param Sock Pointer to the socket.\r
1115 @param Error The error code received.\r
1116\r
8a67d61d 1117**/\r
1118VOID\r
1119SockRcvdErr (\r
77f00155 1120 IN OUT SOCKET *Sock,\r
1121 IN EFI_STATUS Error\r
8a67d61d 1122 )\r
1123{\r
1124 SOCK_TOKEN *SockToken;\r
1125\r
e48e37fc 1126 if (!IsListEmpty (&Sock->RcvTokenList)) {\r
8a67d61d 1127\r
1128 SockToken = NET_LIST_HEAD (\r
1129 &Sock->RcvTokenList,\r
1130 SOCK_TOKEN,\r
1131 TokenList\r
1132 );\r
1133\r
e48e37fc 1134 RemoveEntryList (&SockToken->TokenList);\r
8a67d61d 1135\r
1136 SIGNAL_TOKEN (SockToken->Token, Error);\r
1137\r
766c7483 1138 FreePool (SockToken);\r
8a67d61d 1139 } else {\r
1140\r
1141 SOCK_ERROR (Sock, Error);\r
1142 }\r
1143}\r
1144\r
1145\r
1146/**\r
dea6914d 1147 Called by the low layer protocol to indicate that there will be no more data\r
276dcc1b 1148 from the communication peer.\r
dea6914d
ZL
1149\r
1150 This function set the socket's state to SO_NO_MORE_DATA and signal all queued\r
276dcc1b 1151 IO tokens with the error status EFI_CONNECTION_FIN.\r
8a67d61d 1152\r
1153 @param Sock Pointer to the socket.\r
1154\r
8a67d61d 1155**/\r
1156VOID\r
1157SockNoMoreData (\r
77f00155 1158 IN OUT SOCKET *Sock\r
8a67d61d 1159 )\r
1160{\r
1161 EFI_STATUS Err;\r
1162\r
1163 SOCK_NO_MORE_DATA (Sock);\r
1164\r
e48e37fc 1165 if (!IsListEmpty (&Sock->RcvTokenList)) {\r
8a67d61d 1166\r
1167 ASSERT (0 == GET_RCV_DATASIZE (Sock));\r
1168\r
1169 Err = Sock->SockError;\r
1170\r
1171 SOCK_ERROR (Sock, EFI_CONNECTION_FIN);\r
1172\r
1173 SockFlushPendingToken (Sock, &Sock->RcvTokenList);\r
1174\r
1175 SOCK_ERROR (Sock, Err);\r
1176\r
1177 }\r
1178\r
1179}\r
1180\r
1181\r
1182/**\r
1183 Get the first buffer block in the specific socket buffer.\r
1184\r
1185 @param Sockbuf Pointer to the socket buffer.\r
1186\r
1187 @return Pointer to the first buffer in the queue. NULL if the queue is empty.\r
1188\r
1189**/\r
1190NET_BUF *\r
1191SockBufFirst (\r
1192 IN SOCK_BUFFER *Sockbuf\r
1193 )\r
1194{\r
e48e37fc 1195 LIST_ENTRY *NetbufList;\r
8a67d61d 1196\r
1197 NetbufList = &(Sockbuf->DataQueue->BufList);\r
1198\r
e48e37fc 1199 if (IsListEmpty (NetbufList)) {\r
8a67d61d 1200 return NULL;\r
1201 }\r
1202\r
1203 return NET_LIST_HEAD (NetbufList, NET_BUF, List);\r
1204}\r
1205\r
1206\r
1207/**\r
1208 Get the next buffer block in the specific socket buffer.\r
1209\r
1210 @param Sockbuf Pointer to the socket buffer.\r
1211 @param SockEntry Pointer to the buffer block prior to the required\r
1212 one.\r
1213\r
dea6914d 1214 @return Pointer to the buffer block next to SockEntry. NULL if SockEntry is\r
120db52c 1215 the tail or head entry.\r
8a67d61d 1216\r
1217**/\r
1218NET_BUF *\r
1219SockBufNext (\r
1220 IN SOCK_BUFFER *Sockbuf,\r
1221 IN NET_BUF *SockEntry\r
1222 )\r
1223{\r
e48e37fc 1224 LIST_ENTRY *NetbufList;\r
8a67d61d 1225\r
1226 NetbufList = &(Sockbuf->DataQueue->BufList);\r
1227\r
1228 if ((SockEntry->List.ForwardLink == NetbufList) ||\r
1229 (SockEntry->List.BackLink == &SockEntry->List) ||\r
120db52c 1230 (SockEntry->List.ForwardLink == &SockEntry->List)) {\r
8a67d61d 1231\r
1232 return NULL;\r
1233 }\r
1234\r
1235 return NET_LIST_USER_STRUCT (SockEntry->List.ForwardLink, NET_BUF, List);\r
1236}\r