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