1 /** @file
2   The implementation of a dispatch routine for processing TCP requests.
3 
4   (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5   Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
6 
7   This program and the accompanying materials
8   are licensed and made available under the terms and conditions of the BSD License
9   which accompanies this distribution.  The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php.
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "TcpMain.h"
18 
19 /**
20   Add or remove a route entry in the IP route table associated with this TCP instance.
21 
22   @param[in]  Tcb               Pointer to the TCP_CB of this TCP instance.
23   @param[in]  RouteInfo         Pointer to the route information to be processed.
24 
25   @retval EFI_SUCCESS           The operation completed successfully.
26   @retval EFI_NOT_STARTED       The driver instance has not been started.
27   @retval EFI_NO_MAPPING        When using the default address, configuration(DHCP,
28                                 BOOTP, RARP, etc.) is not finished yet.
29   @retval EFI_OUT_OF_RESOURCES  Could not add the entry to the routing table.
30   @retval EFI_NOT_FOUND         This route is not in the routing table
31                                 (when RouteInfo->DeleteRoute is TRUE).
32   @retval EFI_ACCESS_DENIED     The route is already defined in the routing table
33                                 (when RouteInfo->DeleteRoute is FALSE).
34 **/
35 EFI_STATUS
Tcp4Route(IN TCP_CB * Tcb,IN TCP4_ROUTE_INFO * RouteInfo)36 Tcp4Route (
37   IN TCP_CB           *Tcb,
38   IN TCP4_ROUTE_INFO  *RouteInfo
39   )
40 {
41   IP_IO_IP_PROTOCOL   Ip;
42 
43   Ip = Tcb->IpInfo->Ip;
44 
45   ASSERT (Ip.Ip4!= NULL);
46 
47   return Ip.Ip4->Routes (
48                    Ip.Ip4,
49                    RouteInfo->DeleteRoute,
50                    RouteInfo->SubnetAddress,
51                    RouteInfo->SubnetMask,
52                    RouteInfo->GatewayAddress
53                    );
54 
55 }
56 
57 /**
58   Get the operational settings of this TCPv4 instance.
59 
60   @param[in]       Tcb           Pointer to the TCP_CB of this TCP instance.
61   @param[in, out]  Mode          Pointer to the buffer to store the operational
62                                  settings.
63 
64   @retval EFI_SUCCESS            The mode data was read.
65   @retval EFI_NOT_STARTED        No configuration data is available because this
66                                  instance hasn't been started.
67 
68 **/
69 EFI_STATUS
Tcp4GetMode(IN TCP_CB * Tcb,IN OUT TCP4_MODE_DATA * Mode)70 Tcp4GetMode (
71   IN     TCP_CB         *Tcb,
72   IN OUT TCP4_MODE_DATA *Mode
73   )
74 {
75   SOCKET                *Sock;
76   EFI_TCP4_CONFIG_DATA  *ConfigData;
77   EFI_TCP4_ACCESS_POINT *AccessPoint;
78   EFI_TCP4_OPTION       *Option;
79   EFI_IP4_PROTOCOL      *Ip;
80 
81   Sock = Tcb->Sk;
82 
83   if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp4ConfigData != NULL)) {
84     return EFI_NOT_STARTED;
85   }
86 
87   if (Mode->Tcp4State != NULL) {
88     *(Mode->Tcp4State) = (EFI_TCP4_CONNECTION_STATE) Tcb->State;
89   }
90 
91   if (Mode->Tcp4ConfigData != NULL) {
92 
93     ConfigData                       = Mode->Tcp4ConfigData;
94     AccessPoint                      = &(ConfigData->AccessPoint);
95     Option                           = ConfigData->ControlOption;
96 
97     ConfigData->TypeOfService        = Tcb->Tos;
98     ConfigData->TimeToLive           = Tcb->Ttl;
99 
100     AccessPoint->UseDefaultAddress   = Tcb->UseDefaultAddr;
101 
102     IP4_COPY_ADDRESS (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip);
103 
104     IP4_COPY_ADDRESS (&AccessPoint->SubnetMask, &Tcb->SubnetMask);
105     AccessPoint->StationPort         = NTOHS (Tcb->LocalEnd.Port);
106 
107     IP4_COPY_ADDRESS (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip);
108 
109     AccessPoint->RemotePort          = NTOHS (Tcb->RemoteEnd.Port);
110     AccessPoint->ActiveFlag          = (BOOLEAN) (Tcb->State != TCP_LISTEN);
111 
112     if (Option != NULL) {
113       Option->ReceiveBufferSize      = GET_RCV_BUFFSIZE (Tcb->Sk);
114       Option->SendBufferSize         = GET_SND_BUFFSIZE (Tcb->Sk);
115       Option->MaxSynBackLog          = GET_BACKLOG (Tcb->Sk);
116 
117       Option->ConnectionTimeout      = Tcb->ConnectTimeout / TCP_TICK_HZ;
118       Option->DataRetries            = Tcb->MaxRexmit;
119       Option->FinTimeout             = Tcb->FinWait2Timeout / TCP_TICK_HZ;
120       Option->TimeWaitTimeout        = Tcb->TimeWaitTimeout / TCP_TICK_HZ;
121       Option->KeepAliveProbes        = Tcb->MaxKeepAlive;
122       Option->KeepAliveTime          = Tcb->KeepAliveIdle / TCP_TICK_HZ;
123       Option->KeepAliveInterval      = Tcb->KeepAlivePeriod / TCP_TICK_HZ;
124 
125       Option->EnableNagle            = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE));
126       Option->EnableTimeStamp        = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS));
127       Option->EnableWindowScaling    = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS));
128 
129       Option->EnableSelectiveAck     = FALSE;
130       Option->EnablePathMtuDiscovery = FALSE;
131     }
132   }
133 
134   Ip = Tcb->IpInfo->Ip.Ip4;
135   ASSERT (Ip != NULL);
136 
137   return Ip->GetModeData (Ip, Mode->Ip4ModeData, Mode->MnpConfigData, Mode->SnpModeData);
138 }
139 
140 /**
141   Get the operational settings of this TCPv6 instance.
142 
143   @param[in]       Tcb           Pointer to the TCP_CB of this TCP instance.
144   @param[in, out]  Mode          Pointer to the buffer to store the operational
145                                  settings.
146 
147   @retval EFI_SUCCESS            The mode data was read.
148   @retval EFI_NOT_STARTED        No configuration data is available because this
149                                  instance hasn't been started.
150 
151 **/
152 EFI_STATUS
Tcp6GetMode(IN TCP_CB * Tcb,IN OUT TCP6_MODE_DATA * Mode)153 Tcp6GetMode (
154   IN     TCP_CB         *Tcb,
155   IN OUT TCP6_MODE_DATA *Mode
156   )
157 {
158   SOCKET                *Sock;
159   EFI_TCP6_CONFIG_DATA  *ConfigData;
160   EFI_TCP6_ACCESS_POINT *AccessPoint;
161   EFI_TCP6_OPTION       *Option;
162   EFI_IP6_PROTOCOL      *Ip;
163 
164   Sock = Tcb->Sk;
165 
166   if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp6ConfigData != NULL)) {
167     return EFI_NOT_STARTED;
168   }
169 
170   if (Mode->Tcp6State != NULL) {
171     *(Mode->Tcp6State) = (EFI_TCP6_CONNECTION_STATE) (Tcb->State);
172   }
173 
174   if (Mode->Tcp6ConfigData != NULL) {
175 
176     ConfigData                       = Mode->Tcp6ConfigData;
177     AccessPoint                      = &(ConfigData->AccessPoint);
178     Option                           = ConfigData->ControlOption;
179 
180     ConfigData->TrafficClass         = Tcb->Tos;
181     ConfigData->HopLimit             = Tcb->Ttl;
182 
183     AccessPoint->StationPort         = NTOHS (Tcb->LocalEnd.Port);
184     AccessPoint->RemotePort          = NTOHS (Tcb->RemoteEnd.Port);
185     AccessPoint->ActiveFlag          = (BOOLEAN) (Tcb->State != TCP_LISTEN);
186 
187     IP6_COPY_ADDRESS (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip);
188     IP6_COPY_ADDRESS (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip);
189 
190     if (Option != NULL) {
191       Option->ReceiveBufferSize      = GET_RCV_BUFFSIZE (Tcb->Sk);
192       Option->SendBufferSize         = GET_SND_BUFFSIZE (Tcb->Sk);
193       Option->MaxSynBackLog          = GET_BACKLOG (Tcb->Sk);
194 
195       Option->ConnectionTimeout      = Tcb->ConnectTimeout / TCP_TICK_HZ;
196       Option->DataRetries            = Tcb->MaxRexmit;
197       Option->FinTimeout             = Tcb->FinWait2Timeout / TCP_TICK_HZ;
198       Option->TimeWaitTimeout        = Tcb->TimeWaitTimeout / TCP_TICK_HZ;
199       Option->KeepAliveProbes        = Tcb->MaxKeepAlive;
200       Option->KeepAliveTime          = Tcb->KeepAliveIdle / TCP_TICK_HZ;
201       Option->KeepAliveInterval      = Tcb->KeepAlivePeriod / TCP_TICK_HZ;
202 
203       Option->EnableNagle            = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE));
204       Option->EnableTimeStamp        = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS));
205       Option->EnableWindowScaling    = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS));
206 
207       Option->EnableSelectiveAck     = FALSE;
208       Option->EnablePathMtuDiscovery = FALSE;
209     }
210   }
211 
212   Ip = Tcb->IpInfo->Ip.Ip6;
213   ASSERT (Ip != NULL);
214 
215   return Ip->GetModeData (Ip, Mode->Ip6ModeData, Mode->MnpConfigData, Mode->SnpModeData);
216 }
217 
218 /**
219   If TcpAp->StationPort isn't zero, check whether the access point
220   is registered, else generate a random station port for this
221   access point.
222 
223   @param[in]  TcpAp              Pointer to the access point.
224   @param[in]  IpVersion          IP_VERSION_4 or IP_VERSION_6
225 
226   @retval EFI_SUCCESS            The check passed or the port is assigned.
227   @retval EFI_INVALID_PARAMETER  The non-zero station port is already used.
228   @retval EFI_OUT_OF_RESOURCES   No port can be allocated.
229 
230 **/
231 EFI_STATUS
TcpBind(IN TCP_ACCESS_POINT * TcpAp,IN UINT8 IpVersion)232 TcpBind (
233   IN TCP_ACCESS_POINT  *TcpAp,
234   IN UINT8             IpVersion
235   )
236 {
237   BOOLEAN         Cycle;
238   EFI_IP_ADDRESS  Local;
239   UINT16          *Port;
240   UINT16          *RandomPort;
241 
242   if (IpVersion == IP_VERSION_4) {
243     IP4_COPY_ADDRESS (&Local, &TcpAp->Tcp4Ap.StationAddress);
244     Port       = &TcpAp->Tcp4Ap.StationPort;
245     RandomPort = &mTcp4RandomPort;
246   } else {
247     IP6_COPY_ADDRESS (&Local, &TcpAp->Tcp6Ap.StationAddress);
248     Port       = &TcpAp->Tcp6Ap.StationPort;
249     RandomPort = &mTcp6RandomPort;
250   }
251 
252   if (0 != *Port) {
253     //
254     // Check if a same endpoing is bound.
255     //
256     if (TcpFindTcbByPeer (&Local, *Port, IpVersion)) {
257 
258       return EFI_INVALID_PARAMETER;
259     }
260   } else {
261     //
262     // generate a random port
263     //
264     Cycle = FALSE;
265 
266     if (TCP_PORT_USER_RESERVED == *RandomPort) {
267       *RandomPort = TCP_PORT_KNOWN;
268     }
269 
270     (*RandomPort)++;
271 
272     while (TcpFindTcbByPeer (&Local, *RandomPort, IpVersion)) {
273       (*RandomPort)++;
274 
275       if (*RandomPort <= TCP_PORT_KNOWN) {
276         if (Cycle) {
277           DEBUG (
278             (EFI_D_ERROR,
279             "TcpBind: no port can be allocated for this pcb\n")
280             );
281           return EFI_OUT_OF_RESOURCES;
282         }
283 
284         *RandomPort = TCP_PORT_KNOWN + 1;
285 
286         Cycle       = TRUE;
287       }
288     }
289 
290     *Port = *RandomPort;
291   }
292 
293   return EFI_SUCCESS;
294 }
295 
296 /**
297   Flush the Tcb add its associated protocols.
298 
299   @param[in, out]  Tcb      Pointer to the TCP_CB to be flushed.
300 
301 **/
302 VOID
TcpFlushPcb(IN OUT TCP_CB * Tcb)303 TcpFlushPcb (
304   IN OUT TCP_CB *Tcb
305   )
306 {
307   SOCKET                    *Sock;
308 
309   IpIoConfigIp (Tcb->IpInfo, NULL);
310 
311   Sock     = Tcb->Sk;
312 
313   if (SOCK_IS_CONFIGURED (Sock)) {
314     RemoveEntryList (&Tcb->List);
315 
316     if (Sock->DevicePath != NULL) {
317       //
318       // Uninstall the device path protocl.
319       //
320       gBS->UninstallProtocolInterface (
321              Sock->SockHandle,
322              &gEfiDevicePathProtocolGuid,
323              Sock->DevicePath
324              );
325 
326       FreePool (Sock->DevicePath);
327       Sock->DevicePath = NULL;
328     }
329   }
330 
331   NetbufFreeList (&Tcb->SndQue);
332   NetbufFreeList (&Tcb->RcvQue);
333   Tcb->State = TCP_CLOSED;
334   Tcb->RemoteIpZero = FALSE;
335 }
336 
337 /**
338   Attach a Pcb to the socket.
339 
340   @param[in]  Sk                 Pointer to the socket of this TCP instance.
341 
342   @retval EFI_SUCCESS            The operation completed successfully.
343   @retval EFI_OUT_OF_RESOURCES   Failed due to resource limits.
344 
345 **/
346 EFI_STATUS
TcpAttachPcb(IN SOCKET * Sk)347 TcpAttachPcb (
348   IN SOCKET  *Sk
349   )
350 {
351   TCP_CB          *Tcb;
352   TCP_PROTO_DATA  *ProtoData;
353   IP_IO           *IpIo;
354   EFI_STATUS      Status;
355   VOID            *Ip;
356   EFI_GUID        *IpProtocolGuid;
357 
358   if (Sk->IpVersion == IP_VERSION_4) {
359     IpProtocolGuid = &gEfiIp4ProtocolGuid;
360   } else {
361     IpProtocolGuid = &gEfiIp6ProtocolGuid;
362   }
363 
364   Tcb = AllocateZeroPool (sizeof (TCP_CB));
365 
366   if (Tcb == NULL) {
367 
368     DEBUG ((EFI_D_ERROR, "TcpConfigurePcb: failed to allocate a TCB\n"));
369 
370     return EFI_OUT_OF_RESOURCES;
371   }
372 
373   ProtoData = (TCP_PROTO_DATA *) Sk->ProtoReserved;
374   IpIo      = ProtoData->TcpService->IpIo;
375 
376   //
377   // Create an IpInfo for this Tcb.
378   //
379   Tcb->IpInfo = IpIoAddIp (IpIo);
380   if (Tcb->IpInfo == NULL) {
381 
382     FreePool (Tcb);
383     return EFI_OUT_OF_RESOURCES;
384   }
385 
386   //
387   // Open the new created IP instance BY_CHILD.
388   //
389   Status = gBS->OpenProtocol (
390                   Tcb->IpInfo->ChildHandle,
391                   IpProtocolGuid,
392                   &Ip,
393                   IpIo->Image,
394                   Sk->SockHandle,
395                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
396                   );
397   if (EFI_ERROR (Status)) {
398     IpIoRemoveIp (IpIo, Tcb->IpInfo);
399     return Status;
400   }
401 
402   InitializeListHead (&Tcb->List);
403   InitializeListHead (&Tcb->SndQue);
404   InitializeListHead (&Tcb->RcvQue);
405 
406   Tcb->State        = TCP_CLOSED;
407   Tcb->Sk           = Sk;
408   ProtoData->TcpPcb = Tcb;
409 
410   return EFI_SUCCESS;
411 }
412 
413 /**
414   Detach the Pcb of the socket.
415 
416   @param[in, out]  Sk           Pointer to the socket of this TCP instance.
417 
418 **/
419 VOID
TcpDetachPcb(IN OUT SOCKET * Sk)420 TcpDetachPcb (
421   IN OUT SOCKET    *Sk
422   )
423 {
424   TCP_PROTO_DATA   *ProtoData;
425   TCP_CB           *Tcb;
426   EFI_GUID         *IpProtocolGuid;
427 
428   if (Sk->IpVersion == IP_VERSION_4) {
429     IpProtocolGuid = &gEfiIp4ProtocolGuid;
430   } else {
431     IpProtocolGuid = &gEfiIp6ProtocolGuid;
432   }
433 
434   ProtoData = (TCP_PROTO_DATA *) Sk->ProtoReserved;
435   Tcb       = ProtoData->TcpPcb;
436 
437   ASSERT (Tcb != NULL);
438 
439   TcpFlushPcb (Tcb);
440 
441   //
442   // Close the IP protocol.
443   //
444   gBS->CloseProtocol (
445          Tcb->IpInfo->ChildHandle,
446          IpProtocolGuid,
447          ProtoData->TcpService->IpIo->Image,
448          Sk->SockHandle
449          );
450 
451   IpIoRemoveIp (ProtoData->TcpService->IpIo, Tcb->IpInfo);
452 
453   FreePool (Tcb);
454 
455   ProtoData->TcpPcb = NULL;
456 }
457 
458 /**
459   Configure the Pcb using CfgData.
460 
461   @param[in]  Sk                 Pointer to the socket of this TCP instance.
462   @param[in]  CfgData            Pointer to the TCP configuration data.
463 
464   @retval EFI_SUCCESS            The operation completed successfully.
465   @retval EFI_INVALID_PARAMETER  A same access point has been configured in
466                                  another TCP instance.
467   @retval EFI_OUT_OF_RESOURCES   Failed due to resource limits.
468 
469 **/
470 EFI_STATUS
TcpConfigurePcb(IN SOCKET * Sk,IN TCP_CONFIG_DATA * CfgData)471 TcpConfigurePcb (
472   IN SOCKET           *Sk,
473   IN TCP_CONFIG_DATA  *CfgData
474   )
475 {
476   IP_IO_IP_CONFIG_DATA IpCfgData;
477   EFI_STATUS           Status;
478   EFI_TCP4_OPTION      *Option;
479   TCP_PROTO_DATA       *TcpProto;
480   TCP_CB               *Tcb;
481   TCP_ACCESS_POINT     *TcpAp;
482 
483   ASSERT ((CfgData != NULL) && (Sk != NULL) && (Sk->SockHandle != NULL));
484 
485   TcpProto = (TCP_PROTO_DATA *) Sk->ProtoReserved;
486   Tcb      = TcpProto->TcpPcb;
487 
488   ASSERT (Tcb != NULL);
489 
490   if (Sk->IpVersion == IP_VERSION_4) {
491     //
492     // Add Ip for send pkt to the peer
493     //
494     CopyMem (&IpCfgData.Ip4CfgData, &mIp4IoDefaultIpConfigData, sizeof (EFI_IP4_CONFIG_DATA));
495     IpCfgData.Ip4CfgData.DefaultProtocol    = EFI_IP_PROTO_TCP;
496     IpCfgData.Ip4CfgData.TypeOfService      = CfgData->Tcp4CfgData.TypeOfService;
497     IpCfgData.Ip4CfgData.TimeToLive         = CfgData->Tcp4CfgData.TimeToLive;
498     IpCfgData.Ip4CfgData.UseDefaultAddress  = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress;
499     IP4_COPY_ADDRESS (
500       &IpCfgData.Ip4CfgData.SubnetMask,
501       &CfgData->Tcp4CfgData.AccessPoint.SubnetMask
502       );
503     IpCfgData.Ip4CfgData.ReceiveTimeout     = (UINT32) (-1);
504     IP4_COPY_ADDRESS (
505       &IpCfgData.Ip4CfgData.StationAddress,
506       &CfgData->Tcp4CfgData.AccessPoint.StationAddress
507       );
508 
509   } else {
510     ASSERT (Sk->IpVersion == IP_VERSION_6);
511 
512     CopyMem (&IpCfgData.Ip6CfgData, &mIp6IoDefaultIpConfigData, sizeof (EFI_IP6_CONFIG_DATA));
513     IpCfgData.Ip6CfgData.DefaultProtocol    = EFI_IP_PROTO_TCP;
514     IpCfgData.Ip6CfgData.TrafficClass       = CfgData->Tcp6CfgData.TrafficClass;
515     IpCfgData.Ip6CfgData.HopLimit           = CfgData->Tcp6CfgData.HopLimit;
516     IpCfgData.Ip6CfgData.ReceiveTimeout     = (UINT32) (-1);
517     IP6_COPY_ADDRESS (
518       &IpCfgData.Ip6CfgData.StationAddress,
519       &CfgData->Tcp6CfgData.AccessPoint.StationAddress
520       );
521     IP6_COPY_ADDRESS (
522       &IpCfgData.Ip6CfgData.DestinationAddress,
523       &CfgData->Tcp6CfgData.AccessPoint.RemoteAddress
524       );
525   }
526 
527   //
528   // Configure the IP instance this Tcb consumes.
529   //
530   Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData);
531   if (EFI_ERROR (Status)) {
532     goto OnExit;
533   }
534 
535   if (Sk->IpVersion == IP_VERSION_4) {
536     //
537     // Get the default address information if the instance is configured to use default address.
538     //
539     IP4_COPY_ADDRESS (
540       &CfgData->Tcp4CfgData.AccessPoint.StationAddress,
541       &IpCfgData.Ip4CfgData.StationAddress
542       );
543     IP4_COPY_ADDRESS (
544       &CfgData->Tcp4CfgData.AccessPoint.SubnetMask,
545       &IpCfgData.Ip4CfgData.SubnetMask
546       );
547 
548     TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp4CfgData.AccessPoint;
549   } else {
550     IP6_COPY_ADDRESS (
551       &CfgData->Tcp6CfgData.AccessPoint.StationAddress,
552       &IpCfgData.Ip6CfgData.StationAddress
553       );
554 
555     TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp6CfgData.AccessPoint;
556   }
557 
558   //
559   // check if we can bind this endpoint in CfgData
560   //
561   Status = TcpBind (TcpAp, Sk->IpVersion);
562 
563   if (EFI_ERROR (Status)) {
564     DEBUG (
565       (EFI_D_ERROR,
566       "TcpConfigurePcb: Bind endpoint failed with %r\n",
567       Status)
568       );
569 
570     goto OnExit;
571   }
572 
573   //
574   // Initalize the operating information in this Tcb
575   //
576   ASSERT (Tcb->State == TCP_CLOSED &&
577     IsListEmpty (&Tcb->SndQue) &&
578     IsListEmpty (&Tcb->RcvQue));
579 
580   TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
581   Tcb->State            = TCP_CLOSED;
582 
583   Tcb->SndMss           = 536;
584   Tcb->RcvMss           = TcpGetRcvMss (Sk);
585 
586   Tcb->SRtt             = 0;
587   Tcb->Rto              = 3 * TCP_TICK_HZ;
588 
589   Tcb->CWnd             = Tcb->SndMss;
590   Tcb->Ssthresh         = 0xffffffff;
591 
592   Tcb->CongestState     = TCP_CONGEST_OPEN;
593 
594   Tcb->KeepAliveIdle    = TCP_KEEPALIVE_IDLE_MIN;
595   Tcb->KeepAlivePeriod  = TCP_KEEPALIVE_PERIOD;
596   Tcb->MaxKeepAlive     = TCP_MAX_KEEPALIVE;
597   Tcb->MaxRexmit        = TCP_MAX_LOSS;
598   Tcb->FinWait2Timeout  = TCP_FIN_WAIT2_TIME;
599   Tcb->TimeWaitTimeout  = TCP_TIME_WAIT_TIME;
600   Tcb->ConnectTimeout   = TCP_CONNECT_TIME;
601 
602   if (Sk->IpVersion == IP_VERSION_4) {
603     //
604     // initialize Tcb in the light of CfgData
605     //
606     Tcb->Ttl            = CfgData->Tcp4CfgData.TimeToLive;
607     Tcb->Tos            = CfgData->Tcp4CfgData.TypeOfService;
608 
609     Tcb->UseDefaultAddr = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress;
610 
611     CopyMem (&Tcb->LocalEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.StationAddress, sizeof (IP4_ADDR));
612     Tcb->LocalEnd.Port  = HTONS (CfgData->Tcp4CfgData.AccessPoint.StationPort);
613     IP4_COPY_ADDRESS (&Tcb->SubnetMask, &CfgData->Tcp4CfgData.AccessPoint.SubnetMask);
614 
615     CopyMem (&Tcb->RemoteEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.RemoteAddress, sizeof (IP4_ADDR));
616     Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp4CfgData.AccessPoint.RemotePort);
617 
618     Option              = CfgData->Tcp4CfgData.ControlOption;
619   } else {
620     Tcb->Ttl            = CfgData->Tcp6CfgData.HopLimit;
621     Tcb->Tos            = CfgData->Tcp6CfgData.TrafficClass;
622 
623     IP6_COPY_ADDRESS (&Tcb->LocalEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.StationAddress);
624     Tcb->LocalEnd.Port  = HTONS (CfgData->Tcp6CfgData.AccessPoint.StationPort);
625 
626     IP6_COPY_ADDRESS (&Tcb->RemoteEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.RemoteAddress);
627     Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp6CfgData.AccessPoint.RemotePort);
628 
629     //
630     // Type EFI_TCP4_OPTION and EFI_TCP6_OPTION are the same.
631     //
632     Option              = (EFI_TCP4_OPTION *) CfgData->Tcp6CfgData.ControlOption;
633   }
634 
635   if (Option != NULL) {
636     SET_RCV_BUFFSIZE (
637       Sk,
638       (UINT32) (TCP_COMP_VAL (
639                   TCP_RCV_BUF_SIZE_MIN,
640                   TCP_RCV_BUF_SIZE,
641                   TCP_RCV_BUF_SIZE,
642                   Option->ReceiveBufferSize
643                   )
644                )
645       );
646     SET_SND_BUFFSIZE (
647       Sk,
648       (UINT32) (TCP_COMP_VAL (
649                   TCP_SND_BUF_SIZE_MIN,
650                   TCP_SND_BUF_SIZE,
651                   TCP_SND_BUF_SIZE,
652                   Option->SendBufferSize
653                   )
654                )
655       );
656 
657     SET_BACKLOG (
658       Sk,
659       (UINT32) (TCP_COMP_VAL (
660                   TCP_BACKLOG_MIN,
661                   TCP_BACKLOG,
662                   TCP_BACKLOG,
663                   Option->MaxSynBackLog
664                   )
665                )
666       );
667 
668     Tcb->MaxRexmit = (UINT16) TCP_COMP_VAL (
669                                 TCP_MAX_LOSS_MIN,
670                                 TCP_MAX_LOSS,
671                                 TCP_MAX_LOSS,
672                                 Option->DataRetries
673                                 );
674     Tcb->FinWait2Timeout = TCP_COMP_VAL (
675                               TCP_FIN_WAIT2_TIME,
676                               TCP_FIN_WAIT2_TIME_MAX,
677                               TCP_FIN_WAIT2_TIME,
678                               (UINT32) (Option->FinTimeout * TCP_TICK_HZ)
679                               );
680 
681     if (Option->TimeWaitTimeout != 0) {
682       Tcb->TimeWaitTimeout = TCP_COMP_VAL (
683                                TCP_TIME_WAIT_TIME,
684                                TCP_TIME_WAIT_TIME_MAX,
685                                TCP_TIME_WAIT_TIME,
686                                (UINT32) (Option->TimeWaitTimeout * TCP_TICK_HZ)
687                                );
688     } else {
689       Tcb->TimeWaitTimeout = 0;
690     }
691 
692     if (Option->KeepAliveProbes != 0) {
693       TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
694 
695       Tcb->MaxKeepAlive = (UINT8) TCP_COMP_VAL (
696                                     TCP_MAX_KEEPALIVE_MIN,
697                                     TCP_MAX_KEEPALIVE,
698                                     TCP_MAX_KEEPALIVE,
699                                     Option->KeepAliveProbes
700                                     );
701       Tcb->KeepAliveIdle = TCP_COMP_VAL (
702                              TCP_KEEPALIVE_IDLE_MIN,
703                              TCP_KEEPALIVE_IDLE_MAX,
704                              TCP_KEEPALIVE_IDLE_MIN,
705                              (UINT32) (Option->KeepAliveTime * TCP_TICK_HZ)
706                              );
707       Tcb->KeepAlivePeriod = TCP_COMP_VAL (
708                                TCP_KEEPALIVE_PERIOD_MIN,
709                                TCP_KEEPALIVE_PERIOD,
710                                TCP_KEEPALIVE_PERIOD,
711                                (UINT32) (Option->KeepAliveInterval * TCP_TICK_HZ)
712                                );
713     }
714 
715     Tcb->ConnectTimeout = TCP_COMP_VAL (
716                             TCP_CONNECT_TIME_MIN,
717                             TCP_CONNECT_TIME,
718                             TCP_CONNECT_TIME,
719                             (UINT32) (Option->ConnectionTimeout * TCP_TICK_HZ)
720                             );
721 
722     if (!Option->EnableNagle) {
723       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);
724     }
725 
726     if (!Option->EnableTimeStamp) {
727       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_TS);
728     }
729 
730     if (!Option->EnableWindowScaling) {
731       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_WS);
732     }
733   }
734 
735   //
736   // The socket is bound, the <SrcIp, SrcPort, DstIp, DstPort> is
737   // determined, construct the IP device path and install it.
738   //
739   Status = TcpInstallDevicePath (Sk);
740   if (EFI_ERROR (Status)) {
741     goto OnExit;
742   }
743 
744   //
745   // update state of Tcb and socket
746   //
747   if (((Sk->IpVersion == IP_VERSION_4) && !CfgData->Tcp4CfgData.AccessPoint.ActiveFlag) ||
748       ((Sk->IpVersion == IP_VERSION_6) && !CfgData->Tcp6CfgData.AccessPoint.ActiveFlag)
749       ) {
750 
751     TcpSetState (Tcb, TCP_LISTEN);
752     SockSetState (Sk, SO_LISTENING);
753 
754     Sk->ConfigureState = SO_CONFIGURED_PASSIVE;
755   } else {
756 
757     Sk->ConfigureState = SO_CONFIGURED_ACTIVE;
758   }
759 
760   if (Sk->IpVersion == IP_VERSION_6) {
761     Tcb->Tick          = TCP6_REFRESH_NEIGHBOR_TICK;
762 
763     if (NetIp6IsUnspecifiedAddr (&Tcb->RemoteEnd.Ip.v6)) {
764       Tcb->RemoteIpZero = TRUE;
765     }
766   }
767 
768   TcpInsertTcb (Tcb);
769 
770 OnExit:
771 
772   return Status;
773 }
774 
775 /**
776   The procotol handler provided to the socket layer, which is used to
777   dispatch the socket level requests by calling the corresponding
778   TCP layer functions.
779 
780   @param[in]  Sock               Pointer to the socket of this TCP instance.
781   @param[in]  Request            The code of this operation request.
782   @param[in]  Data               Pointer to the operation specific data passed in
783                                  together with the operation request. This is an
784                                  optional parameter that may be NULL.
785 
786   @retval EFI_SUCCESS            The socket request completed successfully.
787   @retval other                  The error status returned by the corresponding TCP
788                                  layer function.
789 
790 **/
791 EFI_STATUS
TcpDispatcher(IN SOCKET * Sock,IN UINT8 Request,IN VOID * Data OPTIONAL)792 TcpDispatcher (
793   IN SOCKET                  *Sock,
794   IN UINT8                   Request,
795   IN VOID                    *Data    OPTIONAL
796   )
797 {
798   TCP_CB          *Tcb;
799   TCP_PROTO_DATA  *ProtoData;
800 
801   ProtoData = (TCP_PROTO_DATA *) Sock->ProtoReserved;
802   Tcb       = ProtoData->TcpPcb;
803 
804   switch (Request) {
805   case SOCK_POLL:
806     if (Tcb->Sk->IpVersion == IP_VERSION_4) {
807       ProtoData->TcpService->IpIo->Ip.Ip4->Poll (ProtoData->TcpService->IpIo->Ip.Ip4);
808     } else {
809       ProtoData->TcpService->IpIo->Ip.Ip6->Poll (ProtoData->TcpService->IpIo->Ip.Ip6);
810     }
811 
812     break;
813 
814   case SOCK_CONSUMED:
815     //
816     // After user received data from socket buffer, socket will
817     // notify TCP using this message to give it a chance to send out
818     // window update information
819     //
820     ASSERT (Tcb != NULL);
821     TcpOnAppConsume (Tcb);
822     break;
823 
824   case SOCK_SND:
825 
826     ASSERT (Tcb != NULL);
827     TcpOnAppSend (Tcb);
828     break;
829 
830   case SOCK_CLOSE:
831 
832     TcpOnAppClose (Tcb);
833 
834     break;
835 
836   case SOCK_ABORT:
837 
838     TcpOnAppAbort (Tcb);
839 
840     break;
841 
842   case SOCK_SNDPUSH:
843     Tcb->SndPsh = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk);
844     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);
845 
846     break;
847 
848   case SOCK_SNDURG:
849     Tcb->SndUp = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk) - 1;
850     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
851 
852     break;
853 
854   case SOCK_CONNECT:
855 
856     TcpOnAppConnect (Tcb);
857 
858     break;
859 
860   case SOCK_ATTACH:
861 
862     return TcpAttachPcb (Sock);
863 
864     break;
865 
866   case SOCK_FLUSH:
867 
868     TcpFlushPcb (Tcb);
869 
870     break;
871 
872   case SOCK_DETACH:
873 
874     TcpDetachPcb (Sock);
875 
876     break;
877 
878   case SOCK_CONFIGURE:
879 
880     return TcpConfigurePcb (
881             Sock,
882             (TCP_CONFIG_DATA *) Data
883             );
884 
885     break;
886 
887   case SOCK_MODE:
888 
889     ASSERT ((Data != NULL) && (Tcb != NULL));
890 
891     if (Tcb->Sk->IpVersion == IP_VERSION_4) {
892 
893       return Tcp4GetMode (Tcb, (TCP4_MODE_DATA *) Data);
894     } else {
895 
896       return Tcp6GetMode (Tcb, (TCP6_MODE_DATA *) Data);
897     }
898 
899     break;
900 
901   case SOCK_ROUTE:
902 
903     ASSERT ((Data != NULL) && (Tcb != NULL) && (Tcb->Sk->IpVersion == IP_VERSION_4));
904 
905     return Tcp4Route (Tcb, (TCP4_ROUTE_INFO *) Data);
906 
907   default:
908 
909     return EFI_UNSUPPORTED;
910   }
911 
912   return EFI_SUCCESS;
913 }
914