blob: d4bc8ace5597604a0b6e0279efdaa64289690307 [file] [log] [blame]
Vishal Bhoj82c80712015-12-15 21:13:33 +05301/** @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**/
35EFI_STATUS
36Tcp4Route (
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**/
69EFI_STATUS
70Tcp4GetMode (
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**/
152EFI_STATUS
153Tcp6GetMode (
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**/
231EFI_STATUS
232TcpBind (
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**/
302VOID
303TcpFlushPcb (
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**/
346EFI_STATUS
347TcpAttachPcb (
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**/
419VOID
420TcpDetachPcb (
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**/
470EFI_STATUS
471TcpConfigurePcb (
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
770OnExit:
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**/
791EFI_STATUS
792TcpDispatcher (
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}