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