]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dispatcher.c
9039905be655fc573bd46774d186e307c64bd5d8
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / Tcp4Dispatcher.c
1 /** @file
2
3 Copyright (c) 2005 - 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Tcp4Dispatcher.c
15
16 Abstract:
17
18
19 **/
20
21 #include "Tcp4Main.h"
22
23 #define TCP_COMP_VAL(Min, Max, Default, Val) \
24 ((((Val) <= (Max)) && ((Val) >= (Min))) ? (Val) : (Default))
25
26 STATIC
27 EFI_STATUS
28 Tcp4Route (
29 IN TCP_CB *Tcb,
30 IN TCP4_ROUTE_INFO *RouteInfo
31 )
32 /*++
33
34 Routine Description:
35
36 Add or remove a route entry in the IP route table associated
37 with this TCP instance.
38
39 Arguments:
40
41 Tcb - Pointer to the TCP_CB of this TCP instance.
42 RouteInfo - Pointer to the route info to be processed.
43
44 Returns:
45
46 EFI_SUCCESS - The operation completed successfully.
47 EFI_NOT_STARTED - The driver instance has not been started.
48 EFI_NO_MAPPING - When using the default address, configuration(DHCP,
49 BOOTP, RARP, etc.) is not finished yet.
50 EFI_OUT_OF_RESOURCES - Could not add the entry to the routing table.
51 EFI_NOT_FOUND - This route is not in the routing table
52 (when RouteInfo->DeleteRoute is TRUE).
53 EFI_ACCESS_DENIED - The route is already defined in the routing table
54 (when RouteInfo->DeleteRoute is FALSE).
55
56 --*/
57 {
58 EFI_IP4_PROTOCOL *Ip;
59
60 Ip = Tcb->IpInfo->Ip;
61
62 ASSERT (Ip);
63
64 return Ip->Routes (
65 Ip,
66 RouteInfo->DeleteRoute,
67 RouteInfo->SubnetAddress,
68 RouteInfo->SubnetMask,
69 RouteInfo->GatewayAddress
70 );
71
72 }
73
74
75 /**
76 Get the operational settings of this TCP instance.
77
78 @param Tcb Pointer to the TCP_CB of this TCP instance.
79 @param Mode Pointer to the buffer to store the operational
80 settings.
81
82 @retval EFI_SUCCESS The mode data is read.
83 @retval EFI_NOT_STARTED No configuration data is available because this
84 instance hasn't been started.
85
86 **/
87 STATIC
88 EFI_STATUS
89 Tcp4GetMode (
90 IN TCP_CB *Tcb,
91 IN TCP4_MODE_DATA *Mode
92 )
93 {
94 SOCKET *Sock;
95 EFI_TCP4_CONFIG_DATA *ConfigData;
96 EFI_TCP4_ACCESS_POINT *AccessPoint;
97 EFI_TCP4_OPTION *Option;
98 EFI_IP4_PROTOCOL *Ip;
99
100 Sock = Tcb->Sk;
101
102 if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp4ConfigData != NULL)) {
103 return EFI_NOT_STARTED;
104 }
105
106 if (Mode->Tcp4State) {
107 *(Mode->Tcp4State) = Tcb->State;
108 }
109
110 if (Mode->Tcp4ConfigData) {
111
112 ConfigData = Mode->Tcp4ConfigData;
113 AccessPoint = &(ConfigData->AccessPoint);
114 Option = ConfigData->ControlOption;
115
116 ConfigData->TypeOfService = Tcb->TOS;
117 ConfigData->TimeToLive = Tcb->TTL;
118
119 AccessPoint->UseDefaultAddress = Tcb->UseDefaultAddr;
120
121 EFI_IP4 (AccessPoint->StationAddress) = Tcb->LocalEnd.Ip;
122 AccessPoint->SubnetMask = Tcb->SubnetMask;
123 AccessPoint->StationPort = NTOHS (Tcb->LocalEnd.Port);
124
125 EFI_IP4 (AccessPoint->RemoteAddress) = Tcb->RemoteEnd.Ip;
126 AccessPoint->RemotePort = NTOHS (Tcb->RemoteEnd.Port);
127 AccessPoint->ActiveFlag = (BOOLEAN) (Tcb->State != TCP_LISTEN);
128
129 if (Option != NULL) {
130 Option->ReceiveBufferSize = GET_RCV_BUFFSIZE (Tcb->Sk);
131 Option->SendBufferSize = GET_SND_BUFFSIZE (Tcb->Sk);
132 Option->MaxSynBackLog = GET_BACKLOG (Tcb->Sk);
133
134 Option->ConnectionTimeout = Tcb->ConnectTimeout / TCP_TICK_HZ;
135 Option->DataRetries = Tcb->MaxRexmit;
136 Option->FinTimeout = Tcb->FinWait2Timeout / TCP_TICK_HZ;
137 Option->TimeWaitTimeout = Tcb->TimeWaitTimeout / TCP_TICK_HZ;
138 Option->KeepAliveProbes = Tcb->MaxKeepAlive;
139 Option->KeepAliveTime = Tcb->KeepAliveIdle / TCP_TICK_HZ;
140 Option->KeepAliveInterval = Tcb->KeepAlivePeriod / TCP_TICK_HZ;
141
142 Option->EnableNagle = !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);
143 Option->EnableTimeStamp = !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS);
144 Option->EnableWindowScaling = !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS);
145
146 Option->EnableSelectiveAck = FALSE;
147 Option->EnablePathMtuDiscovery = FALSE;
148 }
149 }
150
151 Ip = Tcb->IpInfo->Ip;
152 ASSERT (Ip);
153
154 return Ip->GetModeData (Ip, Mode->Ip4ModeData, Mode->MnpConfigData, Mode->SnpModeData);
155 }
156
157
158 /**
159 If AP->StationPort isn't zero, check whether the access point
160 is registered, else generate a random station port for this
161 access point.
162
163 @param AP Pointer to the access point.
164
165 @retval EFI_SUCCESS The check is passed or the port is assigned.
166 @retval EFI_INVALID_PARAMETER The non-zero station port is already used.
167 @retval EFI_OUT_OF_RESOURCES No port can be allocated.
168
169 **/
170 STATIC
171 EFI_STATUS
172 Tcp4Bind (
173 IN EFI_TCP4_ACCESS_POINT *AP
174 )
175 {
176 BOOLEAN Cycle;
177
178 if (0 != AP->StationPort) {
179 //
180 // check if a same endpoint is bound
181 //
182 if (TcpFindTcbByPeer (&AP->StationAddress, AP->StationPort)) {
183
184 return EFI_INVALID_PARAMETER;
185 }
186 } else {
187 //
188 // generate a random port
189 //
190 Cycle = FALSE;
191
192 if (TCP4_PORT_USER_RESERVED == mTcp4RandomPort) {
193 mTcp4RandomPort = TCP4_PORT_KNOWN;
194 }
195
196 mTcp4RandomPort++;
197
198 while (TcpFindTcbByPeer (&AP->StationAddress, mTcp4RandomPort)) {
199
200 mTcp4RandomPort++;
201
202 if (mTcp4RandomPort <= TCP4_PORT_KNOWN) {
203
204 if (Cycle) {
205 TCP4_DEBUG_ERROR (("Tcp4Bind: no port can be allocated "
206 "for this pcb\n"));
207
208 return EFI_OUT_OF_RESOURCES;
209 }
210
211 mTcp4RandomPort = TCP4_PORT_KNOWN + 1;
212
213 Cycle = TRUE;
214 }
215
216 }
217
218 AP->StationPort = mTcp4RandomPort;
219 }
220
221 return EFI_SUCCESS;
222 }
223
224
225 /**
226 Flush the Tcb add its associated protocols..
227
228 @param Tcb Pointer to the TCP_CB to be flushed.
229
230 @retval EFI_SUCCESS The operation is completed successfully.
231
232 **/
233 STATIC
234 VOID
235 Tcp4FlushPcb (
236 IN TCP_CB *Tcb
237 )
238 {
239 SOCKET *Sock;
240 TCP4_PROTO_DATA *TcpProto;
241
242 IpIoConfigIp (Tcb->IpInfo, NULL);
243
244 Sock = Tcb->Sk;
245 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
246
247 if (SOCK_IS_CONFIGURED (Sock)) {
248 NetListRemoveEntry (&Tcb->List);
249
250 TcpSetVariableData (TcpProto->TcpService);
251 }
252
253 NetbufFreeList (&Tcb->SndQue);
254 NetbufFreeList (&Tcb->RcvQue);
255 }
256
257 STATIC
258 EFI_STATUS
259 Tcp4AttachPcb (
260 IN SOCKET *Sk
261 )
262 {
263 TCP_CB *Tcb;
264 TCP4_PROTO_DATA *ProtoData;
265 IP_IO *IpIo;
266
267 Tcb = NetAllocateZeroPool (sizeof (TCP_CB));
268
269 if (Tcb == NULL) {
270
271 TCP4_DEBUG_ERROR (("Tcp4ConfigurePcb: failed to allocate a TCB\n"));
272
273 return EFI_OUT_OF_RESOURCES;
274 }
275
276 ProtoData = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
277 IpIo = ProtoData->TcpService->IpIo;
278
279 //
280 // Create an IpInfo for this Tcb.
281 //
282 Tcb->IpInfo = IpIoAddIp (IpIo);
283 if (Tcb->IpInfo == NULL) {
284
285 NetFreePool (Tcb);
286 return EFI_OUT_OF_RESOURCES;
287 }
288
289 NetListInit (&Tcb->List);
290 NetListInit (&Tcb->SndQue);
291 NetListInit (&Tcb->RcvQue);
292
293 Tcb->State = TCP_CLOSED;
294 Tcb->Sk = Sk;
295 ProtoData->TcpPcb = Tcb;
296
297 return EFI_SUCCESS;
298 }
299
300 STATIC
301 VOID
302 Tcp4DetachPcb (
303 IN SOCKET *Sk
304 )
305 {
306 TCP4_PROTO_DATA *ProtoData;
307 TCP_CB *Tcb;
308
309 ProtoData = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
310 Tcb = ProtoData->TcpPcb;
311
312 ASSERT (Tcb != NULL);
313
314 Tcp4FlushPcb (Tcb);
315
316 IpIoRemoveIp (ProtoData->TcpService->IpIo, Tcb->IpInfo);
317
318 NetFreePool (Tcb);
319
320 ProtoData->TcpPcb = NULL;
321 }
322
323
324 /**
325 Configure the Tcb using CfgData.
326
327 @param Sk Pointer to the socket of this TCP instance.
328 @param SkTcb Pointer to the TCP_CB of this TCP instance.
329 @param CfgData Pointer to the TCP configuration data.
330
331 @retval EFI_SUCCESS The operation is completed successfully.
332 @retval EFI_INVALID_PARAMETER A same access point has been configured in
333 another TCP instance.
334 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
335
336 **/
337 STATIC
338 EFI_STATUS
339 Tcp4ConfigurePcb (
340 IN SOCKET *Sk,
341 IN EFI_TCP4_CONFIG_DATA *CfgData
342 )
343 {
344 IP_IO *IpIo;
345 EFI_IP4_CONFIG_DATA IpCfgData;
346 EFI_STATUS Status;
347 EFI_TCP4_OPTION *Option;
348 TCP4_PROTO_DATA *TcpProto;
349 TCP_CB *Tcb;
350
351 ASSERT (CfgData && Sk && Sk->SockHandle);
352
353 TcpProto = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
354 Tcb = TcpProto->TcpPcb;
355 IpIo = TcpProto->TcpService->IpIo;
356
357 ASSERT (Tcb != NULL);
358
359 //
360 // Add Ip for send pkt to the peer
361 //
362 IpCfgData = mIpIoDefaultIpConfigData;
363 IpCfgData.DefaultProtocol = EFI_IP_PROTO_TCP;
364 IpCfgData.UseDefaultAddress = CfgData->AccessPoint.UseDefaultAddress;
365 IpCfgData.StationAddress = CfgData->AccessPoint.StationAddress;
366 IpCfgData.SubnetMask = CfgData->AccessPoint.SubnetMask;
367 IpCfgData.ReceiveTimeout = (UINT32) (-1);
368
369 //
370 // Configure the IP instance this Tcb consumes.
371 //
372 Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData);
373 if (EFI_ERROR (Status)) {
374 goto OnExit;
375 }
376
377 //
378 // Get the default address info if the instance is configured to use default address.
379 //
380 if (CfgData->AccessPoint.UseDefaultAddress) {
381 CfgData->AccessPoint.StationAddress = IpCfgData.StationAddress;
382 CfgData->AccessPoint.SubnetMask = IpCfgData.SubnetMask;
383 }
384
385 //
386 // check if we can bind this endpoint in CfgData
387 //
388 Status = Tcp4Bind (&(CfgData->AccessPoint));
389
390 if (EFI_ERROR (Status)) {
391 TCP4_DEBUG_ERROR (("Tcp4ConfigurePcb: Bind endpoint failed "
392 "with %r\n", Status));
393
394 goto OnExit;
395 }
396
397 //
398 // Initalize the operating information in this Tcb
399 //
400 ASSERT (Tcb->State == TCP_CLOSED &&
401 NetListIsEmpty (&Tcb->SndQue) &&
402 NetListIsEmpty (&Tcb->RcvQue));
403
404 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
405 Tcb->State = TCP_CLOSED;
406
407 Tcb->SndMss = 536;
408 Tcb->RcvMss = TcpGetRcvMss (Sk);
409
410 Tcb->SRtt = 0;
411 Tcb->Rto = 3 * TCP_TICK_HZ;
412
413 Tcb->CWnd = Tcb->SndMss;
414 Tcb->Ssthresh = 0xffffffff;
415
416 Tcb->CongestState = TCP_CONGEST_OPEN;
417
418 Tcb->KeepAliveIdle = TCP_KEEPALIVE_IDLE_MIN;
419 Tcb->KeepAlivePeriod = TCP_KEEPALIVE_PERIOD;
420 Tcb->MaxKeepAlive = TCP_MAX_KEEPALIVE;
421 Tcb->MaxRexmit = TCP_MAX_LOSS;
422 Tcb->FinWait2Timeout = TCP_FIN_WAIT2_TIME;
423 Tcb->TimeWaitTimeout = TCP_TIME_WAIT_TIME;
424 Tcb->ConnectTimeout = TCP_CONNECT_TIME;
425
426 //
427 // initialize Tcb in the light of CfgData
428 //
429 Tcb->TTL = CfgData->TimeToLive;
430 Tcb->TOS = CfgData->TypeOfService;
431
432 Tcb->LocalEnd.Ip = EFI_IP4 (CfgData->AccessPoint.StationAddress);
433 Tcb->LocalEnd.Port = HTONS (CfgData->AccessPoint.StationPort);
434 Tcb->SubnetMask = CfgData->AccessPoint.SubnetMask;
435
436 Tcb->RemoteEnd.Ip = EFI_IP4 (CfgData->AccessPoint.RemoteAddress);
437 Tcb->RemoteEnd.Port = HTONS (CfgData->AccessPoint.RemotePort);
438
439 Option = CfgData->ControlOption;
440
441 if (Option != NULL) {
442 SET_RCV_BUFFSIZE (
443 Sk,
444 TCP_COMP_VAL (TCP_RCV_BUF_SIZE_MIN,
445 TCP_RCV_BUF_SIZE,
446 TCP_RCV_BUF_SIZE,
447 Option->ReceiveBufferSize)
448 );
449 SET_SND_BUFFSIZE (
450 Sk,
451 TCP_COMP_VAL (TCP_SND_BUF_SIZE_MIN,
452 TCP_SND_BUF_SIZE,
453 TCP_SND_BUF_SIZE,
454 Option->SendBufferSize)
455 );
456
457 SET_BACKLOG (
458 Sk,
459 TCP_COMP_VAL (TCP_BACKLOG_MIN,
460 TCP_BACKLOG,
461 TCP_BACKLOG,
462 Option->MaxSynBackLog)
463 );
464
465 Tcb->MaxRexmit = (UINT16) TCP_COMP_VAL (
466 TCP_MAX_LOSS_MIN,
467 TCP_MAX_LOSS,
468 TCP_MAX_LOSS,
469 Option->DataRetries
470 );
471 Tcb->FinWait2Timeout = TCP_COMP_VAL (
472 TCP_FIN_WAIT2_TIME,
473 TCP_FIN_WAIT2_TIME_MAX,
474 TCP_FIN_WAIT2_TIME,
475 Option->FinTimeout * TCP_TICK_HZ
476 );
477
478 if (Option->TimeWaitTimeout != 0) {
479 Tcb->TimeWaitTimeout = TCP_COMP_VAL (
480 TCP_TIME_WAIT_TIME,
481 TCP_TIME_WAIT_TIME_MAX,
482 TCP_TIME_WAIT_TIME,
483 Option->TimeWaitTimeout * TCP_TICK_HZ
484 );
485 } else {
486 Tcb->TimeWaitTimeout = 0;
487 }
488
489 if (Option->KeepAliveProbes != 0) {
490 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
491
492 Tcb->MaxKeepAlive = (UINT8) TCP_COMP_VAL (
493 TCP_MAX_KEEPALIVE_MIN,
494 TCP_MAX_KEEPALIVE,
495 TCP_MAX_KEEPALIVE,
496 Option->KeepAliveProbes
497 );
498 Tcb->KeepAliveIdle = TCP_COMP_VAL (
499 TCP_KEEPALIVE_IDLE_MIN,
500 TCP_KEEPALIVE_IDLE_MAX,
501 TCP_KEEPALIVE_IDLE_MIN,
502 Option->KeepAliveTime * TCP_TICK_HZ
503 );
504 Tcb->KeepAlivePeriod = TCP_COMP_VAL (
505 TCP_KEEPALIVE_PERIOD_MIN,
506 TCP_KEEPALIVE_PERIOD,
507 TCP_KEEPALIVE_PERIOD,
508 Option->KeepAliveInterval * TCP_TICK_HZ
509 );
510 }
511
512 Tcb->ConnectTimeout = TCP_COMP_VAL (
513 TCP_CONNECT_TIME_MIN,
514 TCP_CONNECT_TIME,
515 TCP_CONNECT_TIME,
516 Option->ConnectionTimeout * TCP_TICK_HZ
517 );
518
519 if (Option->EnableNagle == FALSE) {
520 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);
521 }
522
523 if (Option->EnableTimeStamp == FALSE) {
524 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_TS);
525 }
526
527 if (Option->EnableWindowScaling == FALSE) {
528 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_WS);
529 }
530 }
531
532 //
533 // update state of Tcb and socket
534 //
535 if (CfgData->AccessPoint.ActiveFlag == FALSE) {
536
537 TcpSetState (Tcb, TCP_LISTEN);
538 SockSetState (Sk, SO_LISTENING);
539
540 Sk->ConfigureState = SO_CONFIGURED_PASSIVE;
541 } else {
542
543 Sk->ConfigureState = SO_CONFIGURED_ACTIVE;
544 }
545
546 TcpInsertTcb (Tcb);
547
548 OnExit:
549
550 return Status;
551 }
552
553
554 /**
555 The procotol handler provided to the socket layer, used to
556 dispatch the socket level requests by calling the corresponding
557 TCP layer functions.
558
559 @param Sock Pointer to the socket of this TCP instance.
560 @param Request The code of this operation request.
561 @param Data Pointer to the operation specific data passed in
562 together with the operation request.
563
564 @retval EFI_SUCCESS The socket request is completed successfully.
565 @retval other The error status returned by the corresponding TCP
566 layer function.
567
568 **/
569 EFI_STATUS
570 Tcp4Dispatcher (
571 IN SOCKET *Sock,
572 IN SOCK_REQUEST Request,
573 IN VOID *Data OPTIONAL
574 )
575 {
576 TCP_CB *Tcb;
577 TCP4_PROTO_DATA *ProtoData;
578 EFI_IP4_PROTOCOL *Ip;
579
580 ProtoData = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
581 Tcb = ProtoData->TcpPcb;
582
583 switch (Request) {
584 case SOCK_POLL:
585 Ip = ProtoData->TcpService->IpIo->Ip;
586 Ip->Poll (Ip);
587 break;
588
589 case SOCK_CONSUMED:
590 //
591 // After user received data from socket buffer, socket will
592 // notify TCP using this message to give it a chance to send out
593 // window update information
594 //
595 ASSERT (Tcb);
596 TcpOnAppConsume (Tcb);
597 break;
598
599 case SOCK_SND:
600
601 ASSERT (Tcb);
602 TcpOnAppSend (Tcb);
603 break;
604
605 case SOCK_CLOSE:
606
607 TcpOnAppClose (Tcb);
608
609 break;
610
611 case SOCK_ABORT:
612
613 TcpOnAppAbort (Tcb);
614
615 break;
616
617 case SOCK_SNDPUSH:
618 Tcb->SndPsh = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk);
619 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);
620
621 break;
622
623 case SOCK_SNDURG:
624 Tcb->SndUp = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk) - 1;
625 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
626
627 break;
628
629 case SOCK_CONNECT:
630
631 TcpOnAppConnect (Tcb);
632
633 break;
634
635 case SOCK_ATTACH:
636
637 return Tcp4AttachPcb (Sock);
638
639 break;
640
641 case SOCK_FLUSH:
642
643 Tcp4FlushPcb (Tcb);
644
645 break;
646
647 case SOCK_DETACH:
648
649 Tcp4DetachPcb (Sock);
650
651 break;
652
653 case SOCK_CONFIGURE:
654
655 return Tcp4ConfigurePcb (
656 Sock,
657 (EFI_TCP4_CONFIG_DATA *) Data
658 );
659
660 break;
661
662 case SOCK_MODE:
663
664 ASSERT (Data && Tcb);
665
666 return Tcp4GetMode (Tcb, (TCP4_MODE_DATA *) Data);
667
668 break;
669
670 case SOCK_ROUTE:
671
672 ASSERT (Data && Tcb);
673
674 return Tcp4Route (Tcb, (TCP4_ROUTE_INFO *) Data);
675
676 }
677
678 return EFI_SUCCESS;
679
680 }