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