]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dispatcher.c
1. Enable Network stack to pass SCT, currently MNP, ARP, IP4, TCP4 and DHCP4 have...
[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) = (EFI_TCP4_CONNECTION_STATE) 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 NetCopyMem (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
122 AccessPoint->SubnetMask = Tcb->SubnetMask;
123 AccessPoint->StationPort = NTOHS (Tcb->LocalEnd.Port);
124
125 NetCopyMem (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
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 = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE));
143 Option->EnableTimeStamp = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS));
144 Option->EnableWindowScaling = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS))
145 ;
146
147 Option->EnableSelectiveAck = FALSE;
148 Option->EnablePathMtuDiscovery = FALSE;
149 }
150 }
151
152 Ip = Tcb->IpInfo->Ip;
153 ASSERT (Ip);
154
155 return Ip->GetModeData (Ip, Mode->Ip4ModeData, Mode->MnpConfigData, Mode->SnpModeData);
156 }
157
158
159 /**
160 If AP->StationPort isn't zero, check whether the access point
161 is registered, else generate a random station port for this
162 access point.
163
164 @param AP Pointer to the access point.
165
166 @retval EFI_SUCCESS The check is passed or the port is assigned.
167 @retval EFI_INVALID_PARAMETER The non-zero station port is already used.
168 @retval EFI_OUT_OF_RESOURCES No port can be allocated.
169
170 **/
171 STATIC
172 EFI_STATUS
173 Tcp4Bind (
174 IN EFI_TCP4_ACCESS_POINT *AP
175 )
176 {
177 BOOLEAN Cycle;
178
179 if (0 != AP->StationPort) {
180 //
181 // check if a same endpoint is bound
182 //
183 if (TcpFindTcbByPeer (&AP->StationAddress, AP->StationPort)) {
184
185 return EFI_INVALID_PARAMETER;
186 }
187 } else {
188 //
189 // generate a random port
190 //
191 Cycle = FALSE;
192
193 if (TCP4_PORT_USER_RESERVED == mTcp4RandomPort) {
194 mTcp4RandomPort = TCP4_PORT_KNOWN;
195 }
196
197 mTcp4RandomPort++;
198
199 while (TcpFindTcbByPeer (&AP->StationAddress, mTcp4RandomPort)) {
200
201 mTcp4RandomPort++;
202
203 if (mTcp4RandomPort <= TCP4_PORT_KNOWN) {
204
205 if (Cycle) {
206 TCP4_DEBUG_ERROR (("Tcp4Bind: no port can be allocated "
207 "for this pcb\n"));
208
209 return EFI_OUT_OF_RESOURCES;
210 }
211
212 mTcp4RandomPort = TCP4_PORT_KNOWN + 1;
213
214 Cycle = TRUE;
215 }
216
217 }
218
219 AP->StationPort = mTcp4RandomPort;
220 }
221
222 return EFI_SUCCESS;
223 }
224
225
226 /**
227 Flush the Tcb add its associated protocols..
228
229 @param Tcb Pointer to the TCP_CB to be flushed.
230
231 @retval EFI_SUCCESS The operation is completed successfully.
232
233 **/
234 STATIC
235 VOID
236 Tcp4FlushPcb (
237 IN TCP_CB *Tcb
238 )
239 {
240 SOCKET *Sock;
241 TCP4_PROTO_DATA *TcpProto;
242
243 IpIoConfigIp (Tcb->IpInfo, NULL);
244
245 Sock = Tcb->Sk;
246 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
247
248 if (SOCK_IS_CONFIGURED (Sock)) {
249 NetListRemoveEntry (&Tcb->List);
250
251 TcpSetVariableData (TcpProto->TcpService);
252 }
253
254 NetbufFreeList (&Tcb->SndQue);
255 NetbufFreeList (&Tcb->RcvQue);
256 }
257
258 STATIC
259 EFI_STATUS
260 Tcp4AttachPcb (
261 IN SOCKET *Sk
262 )
263 {
264 TCP_CB *Tcb;
265 TCP4_PROTO_DATA *ProtoData;
266 IP_IO *IpIo;
267
268 Tcb = NetAllocateZeroPool (sizeof (TCP_CB));
269
270 if (Tcb == NULL) {
271
272 TCP4_DEBUG_ERROR (("Tcp4ConfigurePcb: failed to allocate a TCB\n"));
273
274 return EFI_OUT_OF_RESOURCES;
275 }
276
277 ProtoData = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
278 IpIo = ProtoData->TcpService->IpIo;
279
280 //
281 // Create an IpInfo for this Tcb.
282 //
283 Tcb->IpInfo = IpIoAddIp (IpIo);
284 if (Tcb->IpInfo == NULL) {
285
286 NetFreePool (Tcb);
287 return EFI_OUT_OF_RESOURCES;
288 }
289
290 NetListInit (&Tcb->List);
291 NetListInit (&Tcb->SndQue);
292 NetListInit (&Tcb->RcvQue);
293
294 Tcb->State = TCP_CLOSED;
295 Tcb->Sk = Sk;
296 ProtoData->TcpPcb = Tcb;
297
298 return EFI_SUCCESS;
299 }
300
301 STATIC
302 VOID
303 Tcp4DetachPcb (
304 IN SOCKET *Sk
305 )
306 {
307 TCP4_PROTO_DATA *ProtoData;
308 TCP_CB *Tcb;
309
310 ProtoData = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
311 Tcb = ProtoData->TcpPcb;
312
313 ASSERT (Tcb != NULL);
314
315 Tcp4FlushPcb (Tcb);
316
317 IpIoRemoveIp (ProtoData->TcpService->IpIo, Tcb->IpInfo);
318
319 NetFreePool (Tcb);
320
321 ProtoData->TcpPcb = NULL;
322 }
323
324
325 /**
326 Configure the Tcb using CfgData.
327
328 @param Sk Pointer to the socket of this TCP instance.
329 @param SkTcb Pointer to the TCP_CB of this TCP instance.
330 @param CfgData Pointer to the TCP configuration data.
331
332 @retval EFI_SUCCESS The operation is completed successfully.
333 @retval EFI_INVALID_PARAMETER A same access point has been configured in
334 another TCP instance.
335 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
336
337 **/
338 STATIC
339 EFI_STATUS
340 Tcp4ConfigurePcb (
341 IN SOCKET *Sk,
342 IN EFI_TCP4_CONFIG_DATA *CfgData
343 )
344 {
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
356 ASSERT (Tcb != NULL);
357
358 //
359 // Add Ip for send pkt to the peer
360 //
361 CopyMem (&IpCfgData, &mIpIoDefaultIpConfigData, sizeof (IpCfgData));
362 IpCfgData.DefaultProtocol = EFI_IP_PROTO_TCP;
363 IpCfgData.UseDefaultAddress = CfgData->AccessPoint.UseDefaultAddress;
364 IpCfgData.StationAddress = CfgData->AccessPoint.StationAddress;
365 IpCfgData.SubnetMask = CfgData->AccessPoint.SubnetMask;
366 IpCfgData.ReceiveTimeout = (UINT32) (-1);
367
368 //
369 // Configure the IP instance this Tcb consumes.
370 //
371 Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData);
372 if (EFI_ERROR (Status)) {
373 goto OnExit;
374 }
375
376 //
377 // Get the default address info if the instance is configured to use default address.
378 //
379 if (CfgData->AccessPoint.UseDefaultAddress) {
380 CfgData->AccessPoint.StationAddress = IpCfgData.StationAddress;
381 CfgData->AccessPoint.SubnetMask = IpCfgData.SubnetMask;
382 }
383
384 //
385 // check if we can bind this endpoint in CfgData
386 //
387 Status = Tcp4Bind (&(CfgData->AccessPoint));
388
389 if (EFI_ERROR (Status)) {
390 TCP4_DEBUG_ERROR (("Tcp4ConfigurePcb: Bind endpoint failed "
391 "with %r\n", Status));
392
393 goto OnExit;
394 }
395
396 //
397 // Initalize the operating information in this Tcb
398 //
399 ASSERT (Tcb->State == TCP_CLOSED &&
400 NetListIsEmpty (&Tcb->SndQue) &&
401 NetListIsEmpty (&Tcb->RcvQue));
402
403 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
404 Tcb->State = TCP_CLOSED;
405
406 Tcb->SndMss = 536;
407 Tcb->RcvMss = TcpGetRcvMss (Sk);
408
409 Tcb->SRtt = 0;
410 Tcb->Rto = 3 * TCP_TICK_HZ;
411
412 Tcb->CWnd = Tcb->SndMss;
413 Tcb->Ssthresh = 0xffffffff;
414
415 Tcb->CongestState = TCP_CONGEST_OPEN;
416
417 Tcb->KeepAliveIdle = TCP_KEEPALIVE_IDLE_MIN;
418 Tcb->KeepAlivePeriod = TCP_KEEPALIVE_PERIOD;
419 Tcb->MaxKeepAlive = TCP_MAX_KEEPALIVE;
420 Tcb->MaxRexmit = TCP_MAX_LOSS;
421 Tcb->FinWait2Timeout = TCP_FIN_WAIT2_TIME;
422 Tcb->TimeWaitTimeout = TCP_TIME_WAIT_TIME;
423 Tcb->ConnectTimeout = TCP_CONNECT_TIME;
424
425 //
426 // initialize Tcb in the light of CfgData
427 //
428 Tcb->TTL = CfgData->TimeToLive;
429 Tcb->TOS = CfgData->TypeOfService;
430
431 NetCopyMem (&Tcb->LocalEnd.Ip, &CfgData->AccessPoint.StationAddress, sizeof (IP4_ADDR));
432 Tcb->LocalEnd.Port = HTONS (CfgData->AccessPoint.StationPort);
433 Tcb->SubnetMask = CfgData->AccessPoint.SubnetMask;
434
435 NetCopyMem (&Tcb->RemoteEnd.Ip, &CfgData->AccessPoint.RemoteAddress, sizeof (IP4_ADDR));
436 Tcb->RemoteEnd.Port = HTONS (CfgData->AccessPoint.RemotePort);
437
438 Option = CfgData->ControlOption;
439
440 if (Option != NULL) {
441 SET_RCV_BUFFSIZE (
442 Sk,
443 (UINT32) (TCP_COMP_VAL (
444 TCP_RCV_BUF_SIZE_MIN,
445 TCP_RCV_BUF_SIZE,
446 TCP_RCV_BUF_SIZE,
447 Option->ReceiveBufferSize
448 )
449 )
450 );
451 SET_SND_BUFFSIZE (
452 Sk,
453 (UINT32) (TCP_COMP_VAL (
454 TCP_SND_BUF_SIZE_MIN,
455 TCP_SND_BUF_SIZE,
456 TCP_SND_BUF_SIZE,
457 Option->SendBufferSize
458 )
459 )
460 );
461
462 SET_BACKLOG (
463 Sk,
464 (UINT32) (TCP_COMP_VAL (
465 TCP_BACKLOG_MIN,
466 TCP_BACKLOG,
467 TCP_BACKLOG,
468 Option->MaxSynBackLog
469 )
470 )
471 );
472
473 Tcb->MaxRexmit = (UINT16) TCP_COMP_VAL (
474 TCP_MAX_LOSS_MIN,
475 TCP_MAX_LOSS,
476 TCP_MAX_LOSS,
477 Option->DataRetries
478 );
479 Tcb->FinWait2Timeout = TCP_COMP_VAL (
480 TCP_FIN_WAIT2_TIME,
481 TCP_FIN_WAIT2_TIME_MAX,
482 TCP_FIN_WAIT2_TIME,
483 (UINT32) (Option->FinTimeout * TCP_TICK_HZ)
484 );
485
486 if (Option->TimeWaitTimeout != 0) {
487 Tcb->TimeWaitTimeout = TCP_COMP_VAL (
488 TCP_TIME_WAIT_TIME,
489 TCP_TIME_WAIT_TIME_MAX,
490 TCP_TIME_WAIT_TIME,
491 (UINT32) (Option->TimeWaitTimeout * TCP_TICK_HZ)
492 );
493 } else {
494 Tcb->TimeWaitTimeout = 0;
495 }
496
497 if (Option->KeepAliveProbes != 0) {
498 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
499
500 Tcb->MaxKeepAlive = (UINT8) TCP_COMP_VAL (
501 TCP_MAX_KEEPALIVE_MIN,
502 TCP_MAX_KEEPALIVE,
503 TCP_MAX_KEEPALIVE,
504 Option->KeepAliveProbes
505 );
506 Tcb->KeepAliveIdle = TCP_COMP_VAL (
507 TCP_KEEPALIVE_IDLE_MIN,
508 TCP_KEEPALIVE_IDLE_MAX,
509 TCP_KEEPALIVE_IDLE_MIN,
510 (UINT32) (Option->KeepAliveTime * TCP_TICK_HZ)
511 );
512 Tcb->KeepAlivePeriod = TCP_COMP_VAL (
513 TCP_KEEPALIVE_PERIOD_MIN,
514 TCP_KEEPALIVE_PERIOD,
515 TCP_KEEPALIVE_PERIOD,
516 (UINT32) (Option->KeepAliveInterval * TCP_TICK_HZ)
517 );
518 }
519
520 Tcb->ConnectTimeout = TCP_COMP_VAL (
521 TCP_CONNECT_TIME_MIN,
522 TCP_CONNECT_TIME,
523 TCP_CONNECT_TIME,
524 (UINT32) (Option->ConnectionTimeout * TCP_TICK_HZ)
525 );
526
527 if (Option->EnableNagle == FALSE) {
528 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);
529 }
530
531 if (Option->EnableTimeStamp == FALSE) {
532 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_TS);
533 }
534
535 if (Option->EnableWindowScaling == FALSE) {
536 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_WS);
537 }
538 }
539
540 //
541 // update state of Tcb and socket
542 //
543 if (CfgData->AccessPoint.ActiveFlag == FALSE) {
544
545 TcpSetState (Tcb, TCP_LISTEN);
546 SockSetState (Sk, SO_LISTENING);
547
548 Sk->ConfigureState = SO_CONFIGURED_PASSIVE;
549 } else {
550
551 Sk->ConfigureState = SO_CONFIGURED_ACTIVE;
552 }
553
554 TcpInsertTcb (Tcb);
555
556 OnExit:
557
558 return Status;
559 }
560
561
562 /**
563 The procotol handler provided to the socket layer, used to
564 dispatch the socket level requests by calling the corresponding
565 TCP layer functions.
566
567 @param Sock Pointer to the socket of this TCP instance.
568 @param Request The code of this operation request.
569 @param Data Pointer to the operation specific data passed in
570 together with the operation request.
571
572 @retval EFI_SUCCESS The socket request is completed successfully.
573 @retval other The error status returned by the corresponding TCP
574 layer function.
575
576 **/
577 EFI_STATUS
578 Tcp4Dispatcher (
579 IN SOCKET *Sock,
580 IN SOCK_REQUEST Request,
581 IN VOID *Data OPTIONAL
582 )
583 {
584 TCP_CB *Tcb;
585 TCP4_PROTO_DATA *ProtoData;
586 EFI_IP4_PROTOCOL *Ip;
587
588 ProtoData = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
589 Tcb = ProtoData->TcpPcb;
590
591 switch (Request) {
592 case SOCK_POLL:
593 Ip = ProtoData->TcpService->IpIo->Ip;
594 Ip->Poll (Ip);
595 break;
596
597 case SOCK_CONSUMED:
598 //
599 // After user received data from socket buffer, socket will
600 // notify TCP using this message to give it a chance to send out
601 // window update information
602 //
603 ASSERT (Tcb);
604 TcpOnAppConsume (Tcb);
605 break;
606
607 case SOCK_SND:
608
609 ASSERT (Tcb);
610 TcpOnAppSend (Tcb);
611 break;
612
613 case SOCK_CLOSE:
614
615 TcpOnAppClose (Tcb);
616
617 break;
618
619 case SOCK_ABORT:
620
621 TcpOnAppAbort (Tcb);
622
623 break;
624
625 case SOCK_SNDPUSH:
626 Tcb->SndPsh = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk);
627 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);
628
629 break;
630
631 case SOCK_SNDURG:
632 Tcb->SndUp = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk) - 1;
633 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
634
635 break;
636
637 case SOCK_CONNECT:
638
639 TcpOnAppConnect (Tcb);
640
641 break;
642
643 case SOCK_ATTACH:
644
645 return Tcp4AttachPcb (Sock);
646
647 break;
648
649 case SOCK_FLUSH:
650
651 Tcp4FlushPcb (Tcb);
652
653 break;
654
655 case SOCK_DETACH:
656
657 Tcp4DetachPcb (Sock);
658
659 break;
660
661 case SOCK_CONFIGURE:
662
663 return Tcp4ConfigurePcb (
664 Sock,
665 (EFI_TCP4_CONFIG_DATA *) Data
666 );
667
668 break;
669
670 case SOCK_MODE:
671
672 ASSERT (Data && Tcb);
673
674 return Tcp4GetMode (Tcb, (TCP4_MODE_DATA *) Data);
675
676 break;
677
678 case SOCK_ROUTE:
679
680 ASSERT (Data && Tcb);
681
682 return Tcp4Route (Tcb, (TCP4_ROUTE_INFO *) Data);
683
684 }
685
686 return EFI_SUCCESS;
687
688 }