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