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