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
Tcp4Route(IN TCP_CB * Tcb,IN TCP4_ROUTE_INFO * RouteInfo)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
Tcp4GetMode(IN TCP_CB * Tcb,IN OUT TCP4_MODE_DATA * Mode)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
Tcp6GetMode(IN TCP_CB * Tcb,IN OUT TCP6_MODE_DATA * Mode)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
TcpBind(IN TCP_ACCESS_POINT * TcpAp,IN UINT8 IpVersion)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
TcpFlushPcb(IN OUT TCP_CB * Tcb)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 protocl.
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
TcpAttachPcb(IN SOCKET * Sk)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     return Status;
394   }
395 
396   InitializeListHead (&Tcb->List);
397   InitializeListHead (&Tcb->SndQue);
398   InitializeListHead (&Tcb->RcvQue);
399 
400   Tcb->State        = TCP_CLOSED;
401   Tcb->Sk           = Sk;
402   ProtoData->TcpPcb = Tcb;
403 
404   return EFI_SUCCESS;
405 }
406 
407 /**
408   Detach the Pcb of the socket.
409 
410   @param[in, out]  Sk           Pointer to the socket of this TCP instance.
411 
412 **/
413 VOID
TcpDetachPcb(IN OUT SOCKET * Sk)414 TcpDetachPcb (
415   IN OUT SOCKET    *Sk
416   )
417 {
418   TCP_PROTO_DATA   *ProtoData;
419   TCP_CB           *Tcb;
420 
421   ProtoData = (TCP_PROTO_DATA *) Sk->ProtoReserved;
422   Tcb       = ProtoData->TcpPcb;
423 
424   ASSERT (Tcb != NULL);
425 
426   TcpFlushPcb (Tcb);
427 
428   IpIoRemoveIp (ProtoData->TcpService->IpIo, Tcb->IpInfo);
429 
430   FreePool (Tcb);
431 
432   ProtoData->TcpPcb = NULL;
433 }
434 
435 /**
436   Configure the Pcb using CfgData.
437 
438   @param[in]  Sk                 Pointer to the socket of this TCP instance.
439   @param[in]  CfgData            Pointer to the TCP configuration data.
440 
441   @retval EFI_SUCCESS            The operation completed successfully.
442   @retval EFI_INVALID_PARAMETER  A same access point has been configured in
443                                  another TCP instance.
444   @retval EFI_OUT_OF_RESOURCES   Failed due to resource limits.
445 
446 **/
447 EFI_STATUS
TcpConfigurePcb(IN SOCKET * Sk,IN TCP_CONFIG_DATA * CfgData)448 TcpConfigurePcb (
449   IN SOCKET           *Sk,
450   IN TCP_CONFIG_DATA  *CfgData
451   )
452 {
453   IP_IO_IP_CONFIG_DATA IpCfgData;
454   EFI_STATUS           Status;
455   EFI_TCP4_OPTION      *Option;
456   TCP_PROTO_DATA       *TcpProto;
457   TCP_CB               *Tcb;
458   TCP_ACCESS_POINT     *TcpAp;
459 
460   ASSERT ((CfgData != NULL) && (Sk != NULL) && (Sk->SockHandle != NULL));
461 
462   TcpProto = (TCP_PROTO_DATA *) Sk->ProtoReserved;
463   Tcb      = TcpProto->TcpPcb;
464 
465   ASSERT (Tcb != NULL);
466 
467   if (Sk->IpVersion == IP_VERSION_4) {
468     //
469     // Add Ip for send pkt to the peer
470     //
471     CopyMem (&IpCfgData.Ip4CfgData, &mIp4IoDefaultIpConfigData, sizeof (EFI_IP4_CONFIG_DATA));
472     IpCfgData.Ip4CfgData.DefaultProtocol    = EFI_IP_PROTO_TCP;
473     IpCfgData.Ip4CfgData.TypeOfService      = CfgData->Tcp4CfgData.TypeOfService;
474     IpCfgData.Ip4CfgData.TimeToLive         = CfgData->Tcp4CfgData.TimeToLive;
475     IpCfgData.Ip4CfgData.UseDefaultAddress  = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress;
476     IP4_COPY_ADDRESS (
477       &IpCfgData.Ip4CfgData.SubnetMask,
478       &CfgData->Tcp4CfgData.AccessPoint.SubnetMask
479       );
480     IpCfgData.Ip4CfgData.ReceiveTimeout     = (UINT32) (-1);
481     IP4_COPY_ADDRESS (
482       &IpCfgData.Ip4CfgData.StationAddress,
483       &CfgData->Tcp4CfgData.AccessPoint.StationAddress
484       );
485 
486   } else {
487     ASSERT (Sk->IpVersion == IP_VERSION_6);
488 
489     CopyMem (&IpCfgData.Ip6CfgData, &mIp6IoDefaultIpConfigData, sizeof (EFI_IP6_CONFIG_DATA));
490     IpCfgData.Ip6CfgData.DefaultProtocol    = EFI_IP_PROTO_TCP;
491     IpCfgData.Ip6CfgData.TrafficClass       = CfgData->Tcp6CfgData.TrafficClass;
492     IpCfgData.Ip6CfgData.HopLimit           = CfgData->Tcp6CfgData.HopLimit;
493     IpCfgData.Ip6CfgData.ReceiveTimeout     = (UINT32) (-1);
494     IP6_COPY_ADDRESS (
495       &IpCfgData.Ip6CfgData.StationAddress,
496       &CfgData->Tcp6CfgData.AccessPoint.StationAddress
497       );
498     IP6_COPY_ADDRESS (
499       &IpCfgData.Ip6CfgData.DestinationAddress,
500       &CfgData->Tcp6CfgData.AccessPoint.RemoteAddress
501       );
502   }
503 
504   //
505   // Configure the IP instance this Tcb consumes.
506   //
507   Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData);
508   if (EFI_ERROR (Status)) {
509     goto OnExit;
510   }
511 
512   if (Sk->IpVersion == IP_VERSION_4) {
513     //
514     // Get the default address information if the instance is configured to use default address.
515     //
516     IP4_COPY_ADDRESS (
517       &CfgData->Tcp4CfgData.AccessPoint.StationAddress,
518       &IpCfgData.Ip4CfgData.StationAddress
519       );
520     IP4_COPY_ADDRESS (
521       &CfgData->Tcp4CfgData.AccessPoint.SubnetMask,
522       &IpCfgData.Ip4CfgData.SubnetMask
523       );
524 
525     TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp4CfgData.AccessPoint;
526   } else {
527     IP6_COPY_ADDRESS (
528       &CfgData->Tcp6CfgData.AccessPoint.StationAddress,
529       &IpCfgData.Ip6CfgData.StationAddress
530       );
531 
532     TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp6CfgData.AccessPoint;
533   }
534 
535   //
536   // check if we can bind this endpoint in CfgData
537   //
538   Status = TcpBind (TcpAp, Sk->IpVersion);
539 
540   if (EFI_ERROR (Status)) {
541     DEBUG (
542       (EFI_D_ERROR,
543       "TcpConfigurePcb: Bind endpoint failed with %r\n",
544       Status)
545       );
546 
547     goto OnExit;
548   }
549 
550   //
551   // Initalize the operating information in this Tcb
552   //
553   ASSERT (Tcb->State == TCP_CLOSED &&
554     IsListEmpty (&Tcb->SndQue) &&
555     IsListEmpty (&Tcb->RcvQue));
556 
557   TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
558   Tcb->State            = TCP_CLOSED;
559 
560   Tcb->SndMss           = 536;
561   Tcb->RcvMss           = TcpGetRcvMss (Sk);
562 
563   Tcb->SRtt             = 0;
564   Tcb->Rto              = 3 * TCP_TICK_HZ;
565 
566   Tcb->CWnd             = Tcb->SndMss;
567   Tcb->Ssthresh         = 0xffffffff;
568 
569   Tcb->CongestState     = TCP_CONGEST_OPEN;
570 
571   Tcb->KeepAliveIdle    = TCP_KEEPALIVE_IDLE_MIN;
572   Tcb->KeepAlivePeriod  = TCP_KEEPALIVE_PERIOD;
573   Tcb->MaxKeepAlive     = TCP_MAX_KEEPALIVE;
574   Tcb->MaxRexmit        = TCP_MAX_LOSS;
575   Tcb->FinWait2Timeout  = TCP_FIN_WAIT2_TIME;
576   Tcb->TimeWaitTimeout  = TCP_TIME_WAIT_TIME;
577   Tcb->ConnectTimeout   = TCP_CONNECT_TIME;
578 
579   if (Sk->IpVersion == IP_VERSION_4) {
580     //
581     // initialize Tcb in the light of CfgData
582     //
583     Tcb->Ttl            = CfgData->Tcp4CfgData.TimeToLive;
584     Tcb->Tos            = CfgData->Tcp4CfgData.TypeOfService;
585 
586     Tcb->UseDefaultAddr = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress;
587 
588     CopyMem (&Tcb->LocalEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.StationAddress, sizeof (IP4_ADDR));
589     Tcb->LocalEnd.Port  = HTONS (CfgData->Tcp4CfgData.AccessPoint.StationPort);
590     IP4_COPY_ADDRESS (&Tcb->SubnetMask, &CfgData->Tcp4CfgData.AccessPoint.SubnetMask);
591 
592     CopyMem (&Tcb->RemoteEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.RemoteAddress, sizeof (IP4_ADDR));
593     Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp4CfgData.AccessPoint.RemotePort);
594 
595     Option              = CfgData->Tcp4CfgData.ControlOption;
596   } else {
597     Tcb->Ttl            = CfgData->Tcp6CfgData.HopLimit;
598     Tcb->Tos            = CfgData->Tcp6CfgData.TrafficClass;
599 
600     IP6_COPY_ADDRESS (&Tcb->LocalEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.StationAddress);
601     Tcb->LocalEnd.Port  = HTONS (CfgData->Tcp6CfgData.AccessPoint.StationPort);
602 
603     IP6_COPY_ADDRESS (&Tcb->RemoteEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.RemoteAddress);
604     Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp6CfgData.AccessPoint.RemotePort);
605 
606     //
607     // Type EFI_TCP4_OPTION and EFI_TCP6_OPTION are the same.
608     //
609     Option              = (EFI_TCP4_OPTION *) CfgData->Tcp6CfgData.ControlOption;
610   }
611 
612   if (Option != NULL) {
613     SET_RCV_BUFFSIZE (
614       Sk,
615       (UINT32) (TCP_COMP_VAL (
616                   TCP_RCV_BUF_SIZE_MIN,
617                   TCP_RCV_BUF_SIZE,
618                   TCP_RCV_BUF_SIZE,
619                   Option->ReceiveBufferSize
620                   )
621                )
622       );
623     SET_SND_BUFFSIZE (
624       Sk,
625       (UINT32) (TCP_COMP_VAL (
626                   TCP_SND_BUF_SIZE_MIN,
627                   TCP_SND_BUF_SIZE,
628                   TCP_SND_BUF_SIZE,
629                   Option->SendBufferSize
630                   )
631                )
632       );
633 
634     SET_BACKLOG (
635       Sk,
636       (UINT32) (TCP_COMP_VAL (
637                   TCP_BACKLOG_MIN,
638                   TCP_BACKLOG,
639                   TCP_BACKLOG,
640                   Option->MaxSynBackLog
641                   )
642                )
643       );
644 
645     Tcb->MaxRexmit = (UINT16) TCP_COMP_VAL (
646                                 TCP_MAX_LOSS_MIN,
647                                 TCP_MAX_LOSS,
648                                 TCP_MAX_LOSS,
649                                 Option->DataRetries
650                                 );
651     Tcb->FinWait2Timeout = TCP_COMP_VAL (
652                               TCP_FIN_WAIT2_TIME,
653                               TCP_FIN_WAIT2_TIME_MAX,
654                               TCP_FIN_WAIT2_TIME,
655                               (UINT32) (Option->FinTimeout * TCP_TICK_HZ)
656                               );
657 
658     if (Option->TimeWaitTimeout != 0) {
659       Tcb->TimeWaitTimeout = TCP_COMP_VAL (
660                                TCP_TIME_WAIT_TIME,
661                                TCP_TIME_WAIT_TIME_MAX,
662                                TCP_TIME_WAIT_TIME,
663                                (UINT32) (Option->TimeWaitTimeout * TCP_TICK_HZ)
664                                );
665     } else {
666       Tcb->TimeWaitTimeout = 0;
667     }
668 
669     if (Option->KeepAliveProbes != 0) {
670       TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
671 
672       Tcb->MaxKeepAlive = (UINT8) TCP_COMP_VAL (
673                                     TCP_MAX_KEEPALIVE_MIN,
674                                     TCP_MAX_KEEPALIVE,
675                                     TCP_MAX_KEEPALIVE,
676                                     Option->KeepAliveProbes
677                                     );
678       Tcb->KeepAliveIdle = TCP_COMP_VAL (
679                              TCP_KEEPALIVE_IDLE_MIN,
680                              TCP_KEEPALIVE_IDLE_MAX,
681                              TCP_KEEPALIVE_IDLE_MIN,
682                              (UINT32) (Option->KeepAliveTime * TCP_TICK_HZ)
683                              );
684       Tcb->KeepAlivePeriod = TCP_COMP_VAL (
685                                TCP_KEEPALIVE_PERIOD_MIN,
686                                TCP_KEEPALIVE_PERIOD,
687                                TCP_KEEPALIVE_PERIOD,
688                                (UINT32) (Option->KeepAliveInterval * TCP_TICK_HZ)
689                                );
690     }
691 
692     Tcb->ConnectTimeout = TCP_COMP_VAL (
693                             TCP_CONNECT_TIME_MIN,
694                             TCP_CONNECT_TIME,
695                             TCP_CONNECT_TIME,
696                             (UINT32) (Option->ConnectionTimeout * TCP_TICK_HZ)
697                             );
698 
699     if (!Option->EnableNagle) {
700       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);
701     }
702 
703     if (!Option->EnableTimeStamp) {
704       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_TS);
705     }
706 
707     if (!Option->EnableWindowScaling) {
708       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_WS);
709     }
710   }
711 
712   //
713   // The socket is bound, the <SrcIp, SrcPort, DstIp, DstPort> is
714   // determined, construct the IP device path and install it.
715   //
716   Status = TcpInstallDevicePath (Sk);
717   if (EFI_ERROR (Status)) {
718     goto OnExit;
719   }
720 
721   //
722   // update state of Tcb and socket
723   //
724   if (((Sk->IpVersion == IP_VERSION_4) && !CfgData->Tcp4CfgData.AccessPoint.ActiveFlag) ||
725       ((Sk->IpVersion == IP_VERSION_6) && !CfgData->Tcp6CfgData.AccessPoint.ActiveFlag)
726       ) {
727 
728     TcpSetState (Tcb, TCP_LISTEN);
729     SockSetState (Sk, SO_LISTENING);
730 
731     Sk->ConfigureState = SO_CONFIGURED_PASSIVE;
732   } else {
733 
734     Sk->ConfigureState = SO_CONFIGURED_ACTIVE;
735   }
736 
737   if (Sk->IpVersion == IP_VERSION_6) {
738     Tcb->Tick          = TCP6_REFRESH_NEIGHBOR_TICK;
739 
740     if (NetIp6IsUnspecifiedAddr (&Tcb->RemoteEnd.Ip.v6)) {
741       Tcb->RemoteIpZero = TRUE;
742     }
743   }
744 
745   TcpInsertTcb (Tcb);
746 
747 OnExit:
748 
749   return Status;
750 }
751 
752 /**
753   The procotol handler provided to the socket layer, which is used to
754   dispatch the socket level requests by calling the corresponding
755   TCP layer functions.
756 
757   @param[in]  Sock               Pointer to the socket of this TCP instance.
758   @param[in]  Request            The code of this operation request.
759   @param[in]  Data               Pointer to the operation specific data passed in
760                                  together with the operation request. This is an
761                                  optional parameter that may be NULL.
762 
763   @retval EFI_SUCCESS            The socket request completed successfully.
764   @retval other                  The error status returned by the corresponding TCP
765                                  layer function.
766 
767 **/
768 EFI_STATUS
TcpDispatcher(IN SOCKET * Sock,IN UINT8 Request,IN VOID * Data OPTIONAL)769 TcpDispatcher (
770   IN SOCKET                  *Sock,
771   IN UINT8                   Request,
772   IN VOID                    *Data    OPTIONAL
773   )
774 {
775   TCP_CB          *Tcb;
776   TCP_PROTO_DATA  *ProtoData;
777 
778   ProtoData = (TCP_PROTO_DATA *) Sock->ProtoReserved;
779   Tcb       = ProtoData->TcpPcb;
780 
781   switch (Request) {
782   case SOCK_POLL:
783     if (Tcb->Sk->IpVersion == IP_VERSION_4) {
784       ProtoData->TcpService->IpIo->Ip.Ip4->Poll (ProtoData->TcpService->IpIo->Ip.Ip4);
785     } else {
786       ProtoData->TcpService->IpIo->Ip.Ip6->Poll (ProtoData->TcpService->IpIo->Ip.Ip6);
787     }
788 
789     break;
790 
791   case SOCK_CONSUMED:
792     //
793     // After user received data from socket buffer, socket will
794     // notify TCP using this message to give it a chance to send out
795     // window update information
796     //
797     ASSERT (Tcb != NULL);
798     TcpOnAppConsume (Tcb);
799     break;
800 
801   case SOCK_SND:
802 
803     ASSERT (Tcb != NULL);
804     TcpOnAppSend (Tcb);
805     break;
806 
807   case SOCK_CLOSE:
808 
809     TcpOnAppClose (Tcb);
810 
811     break;
812 
813   case SOCK_ABORT:
814 
815     TcpOnAppAbort (Tcb);
816 
817     break;
818 
819   case SOCK_SNDPUSH:
820     Tcb->SndPsh = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk);
821     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);
822 
823     break;
824 
825   case SOCK_SNDURG:
826     Tcb->SndUp = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk) - 1;
827     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
828 
829     break;
830 
831   case SOCK_CONNECT:
832 
833     TcpOnAppConnect (Tcb);
834 
835     break;
836 
837   case SOCK_ATTACH:
838 
839     return TcpAttachPcb (Sock);
840 
841     break;
842 
843   case SOCK_FLUSH:
844 
845     TcpFlushPcb (Tcb);
846 
847     break;
848 
849   case SOCK_DETACH:
850 
851     TcpDetachPcb (Sock);
852 
853     break;
854 
855   case SOCK_CONFIGURE:
856 
857     return TcpConfigurePcb (
858             Sock,
859             (TCP_CONFIG_DATA *) Data
860             );
861 
862     break;
863 
864   case SOCK_MODE:
865 
866     ASSERT ((Data != NULL) && (Tcb != NULL));
867 
868     if (Tcb->Sk->IpVersion == IP_VERSION_4) {
869 
870       return Tcp4GetMode (Tcb, (TCP4_MODE_DATA *) Data);
871     } else {
872 
873       return Tcp6GetMode (Tcb, (TCP6_MODE_DATA *) Data);
874     }
875 
876     break;
877 
878   case SOCK_ROUTE:
879 
880     ASSERT ((Data != NULL) && (Tcb != NULL) && (Tcb->Sk->IpVersion == IP_VERSION_4));
881 
882     return Tcp4Route (Tcb, (TCP4_ROUTE_INFO *) Data);
883 
884   default:
885 
886     return EFI_UNSUPPORTED;
887   }
888 
889   return EFI_SUCCESS;
890 }
891