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