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