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