]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Impl.c
1 /** @file
2
3 Copyright (c) 2005 - 2007, 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
13 Module Name:
14
15 Ip4Impl.c
16
17 Abstract:
18
19
20 **/
21
22 #include "Ip4Impl.h"
23
24
25 /**
26 Get the IP child's current operational data. This can
27 all be used to get the underlying MNP and SNP data.
28
29 @param This The IP4 protocol instance
30 @param Ip4ModeData The IP4 operation data
31 @param MnpConfigData The MNP configure data
32 @param SnpModeData The SNP operation data
33
34 @retval EFI_INVALID_PARAMETER The parameter is invalid because This == NULL
35 @retval EFI_SUCCESS The operational parameter is returned.
36 @retval Others Failed to retrieve the IP4 route table.
37
38 **/
39 EFI_STATUS
40 EFIAPI
41 EfiIp4GetModeData (
42 IN CONST EFI_IP4_PROTOCOL *This,
43 OUT EFI_IP4_MODE_DATA *Ip4ModeData, OPTIONAL
44 OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData, OPTIONAL
45 OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
46 )
47 {
48 IP4_PROTOCOL *IpInstance;
49 IP4_SERVICE *IpSb;
50 EFI_IP4_CONFIG_DATA *Config;
51 EFI_STATUS Status;
52 EFI_TPL OldTpl;
53 IP4_ADDR Ip;
54
55 if (This == NULL) {
56 return EFI_INVALID_PARAMETER;
57 }
58
59 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
60 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
61 IpSb = IpInstance->Service;
62
63 if (Ip4ModeData != NULL) {
64 //
65 // IsStarted is "whether the EfiIp4Configure has been called".
66 // IsConfigured is "whether the station address has been configured"
67 //
68 Ip4ModeData->IsStarted = (BOOLEAN)(IpInstance->State == IP4_STATE_CONFIGED);
69 CopyMem (&Ip4ModeData->ConfigData, &IpInstance->ConfigData, sizeof (Ip4ModeData->ConfigData));
70 Ip4ModeData->IsConfigured = FALSE;
71
72 Ip4ModeData->GroupCount = IpInstance->GroupCount;
73 Ip4ModeData->GroupTable = (EFI_IPv4_ADDRESS *) IpInstance->Groups;
74
75 Ip4ModeData->IcmpTypeCount = 23;
76 Ip4ModeData->IcmpTypeList = mIp4SupportedIcmp;
77
78 Ip4ModeData->RouteTable = NULL;
79 Ip4ModeData->RouteCount = 0;
80
81 //
82 // return the current station address for this IP child. So,
83 // the user can get the default address through this. Some
84 // application wants to know it station address even it is
85 // using the default one, such as a ftp server.
86 //
87 if (Ip4ModeData->IsStarted) {
88 Config = &Ip4ModeData->ConfigData;
89
90 Ip = HTONL (IpInstance->Interface->Ip);
91 CopyMem (&Config->StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
92
93 Ip = HTONL (IpInstance->Interface->SubnetMask);
94 CopyMem (&Config->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));
95
96 Ip4ModeData->IsConfigured = IpInstance->Interface->Configured;
97
98 //
99 // Build a EFI route table for user from the internal route table.
100 //
101 Status = Ip4BuildEfiRouteTable (IpInstance);
102
103 if (EFI_ERROR (Status)) {
104 gBS->RestoreTPL (OldTpl);
105 return Status;
106 }
107
108 Ip4ModeData->RouteTable = IpInstance->EfiRouteTable;
109 Ip4ModeData->RouteCount = IpInstance->EfiRouteCount;
110 }
111 }
112
113 if (MnpConfigData != NULL) {
114 CopyMem (MnpConfigData, &IpSb->MnpConfigData, sizeof (*MnpConfigData));
115 }
116
117 if (SnpModeData != NULL) {
118 CopyMem (SnpModeData, &IpSb->SnpMode, sizeof (*SnpModeData));
119 }
120
121 gBS->RestoreTPL (OldTpl);
122 return EFI_SUCCESS;
123 }
124
125
126 /**
127 Config the MNP parameter used by IP. The IP driver use one MNP
128 child to transmit/receive frames. By default, it configures MNP
129 to receive unicast/multicast/broadcast. And it will enable/disable
130 the promiscous receive according to whether there is IP child
131 enable that or not. If Force isn't false, it will iterate through
132 all the IP children to check whether the promiscuous receive
133 setting has been changed. If it hasn't been changed, it won't
134 reconfigure the MNP. If Force is true, the MNP is configured no
135 matter whether that is changed or not.
136
137 @param IpSb The IP4 service instance that is to be changed.
138 @param Force Force the configuration or not.
139
140 @retval EFI_SUCCESS The MNP is successfully configured/reconfigured.
141 @retval Others Configuration failed.
142
143 **/
144 EFI_STATUS
145 Ip4ServiceConfigMnp (
146 IN IP4_SERVICE *IpSb,
147 IN BOOLEAN Force
148 )
149 {
150 LIST_ENTRY *Entry;
151 LIST_ENTRY *ProtoEntry;
152 IP4_INTERFACE *IpIf;
153 IP4_PROTOCOL *IpInstance;
154 BOOLEAN Reconfig;
155 BOOLEAN PromiscReceive;
156 EFI_STATUS Status;
157
158 Reconfig = FALSE;
159 PromiscReceive = FALSE;
160
161 if (!Force) {
162 //
163 // Iterate through the IP children to check whether promiscuous
164 // receive setting has been changed. Update the interface's receive
165 // filter also.
166 //
167 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
168
169 IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
170 IpIf->PromiscRecv = FALSE;
171
172 NET_LIST_FOR_EACH (ProtoEntry, &IpIf->IpInstances) {
173 IpInstance = NET_LIST_USER_STRUCT (ProtoEntry, IP4_PROTOCOL, AddrLink);
174
175 if (IpInstance->ConfigData.AcceptPromiscuous) {
176 IpIf->PromiscRecv = TRUE;
177 PromiscReceive = TRUE;
178 }
179 }
180 }
181
182 //
183 // If promiscuous receive isn't changed, it isn't necessary to reconfigure.
184 //
185 if (PromiscReceive == IpSb->MnpConfigData.EnablePromiscuousReceive) {
186 return EFI_SUCCESS;
187 }
188
189 Reconfig = TRUE;
190 IpSb->MnpConfigData.EnablePromiscuousReceive = PromiscReceive;
191 }
192
193 Status = IpSb->Mnp->Configure (IpSb->Mnp, &IpSb->MnpConfigData);
194
195 //
196 // recover the original configuration if failed to set the configure.
197 //
198 if (EFI_ERROR (Status) && Reconfig) {
199 IpSb->MnpConfigData.EnablePromiscuousReceive = (BOOLEAN) !PromiscReceive;
200 }
201
202 return Status;
203 }
204
205
206 /**
207 The event handle for IP4 auto configuration. If IP is asked
208 to reconfigure the default address. The original default
209 interface and route table are removed as the default. If there
210 is active IP children using the default address, the interface
211 will remain valid until all the children have freed their
212 references. If IP is signalled when auto configuration is done,
213 it will configure the default interface and default route table
214 with the configuration information retrieved by IP4_CONFIGURE.
215
216 @param Context The IP4 service binding instance.
217
218 @return None
219
220 **/
221 VOID
222 EFIAPI
223 Ip4AutoConfigCallBackDpc (
224 IN VOID *Context
225 )
226 {
227 EFI_IP4_CONFIG_PROTOCOL *Ip4Config;
228 EFI_IP4_IPCONFIG_DATA *Data;
229 EFI_IP4_ROUTE_TABLE *RouteEntry;
230 IP4_SERVICE *IpSb;
231 IP4_ROUTE_TABLE *RouteTable;
232 IP4_INTERFACE *IpIf;
233 EFI_STATUS Status;
234 UINTN Len;
235 UINT32 Index;
236
237 IpSb = (IP4_SERVICE *) Context;
238 NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
239
240 Ip4Config = IpSb->Ip4Config;
241
242 //
243 // IP is asked to do the reconfiguration. If the default interface
244 // has been configured, release the default interface and route
245 // table, then create a new one. If there are some IP children
246 // using it, the interface won't be physically freed until all the
247 // children have released their reference to it. Also remember to
248 // restart the receive on the default address. IP4 driver only receive
249 // frames on the default address, and when the default interface is
250 // freed, Ip4AcceptFrame won't be informed.
251 //
252 if (IpSb->ActiveEvent == IpSb->ReconfigEvent) {
253
254 if (IpSb->DefaultInterface->Configured) {
255 IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
256
257 if (IpIf == NULL) {
258 return;
259 }
260
261 RouteTable = Ip4CreateRouteTable ();
262
263 if (RouteTable == NULL) {
264 Ip4FreeInterface (IpIf, NULL);
265 return;
266 }
267
268 Ip4CancelReceive (IpSb->DefaultInterface);
269 Ip4FreeInterface (IpSb->DefaultInterface, NULL);
270 Ip4FreeRouteTable (IpSb->DefaultRouteTable);
271
272 IpSb->DefaultInterface = IpIf;
273 InsertHeadList (&IpSb->Interfaces, &IpIf->Link);
274
275 IpSb->DefaultRouteTable = RouteTable;
276 Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);
277 }
278
279 Ip4Config->Stop (Ip4Config);
280 Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);
281 return ;
282 }
283
284 //
285 // Get the configure data in two steps: get the length then the data.
286 //
287 Len = 0;
288
289 if (Ip4Config->GetData (Ip4Config, &Len, NULL) != EFI_BUFFER_TOO_SMALL) {
290 return ;
291 }
292
293 Data = AllocatePool (Len);
294
295 if (Data == NULL) {
296 return ;
297 }
298
299 Status = Ip4Config->GetData (Ip4Config, &Len, Data);
300
301 if (EFI_ERROR (Status)) {
302 goto ON_EXIT;
303 }
304
305 IpIf = IpSb->DefaultInterface;
306
307 //
308 // If the default address has been configured don't change it.
309 // This is unlikely to happen if EFI_IP4_CONFIG protocol has
310 // informed us to reconfigure each time it wants to change the
311 // configuration parameters.
312 //
313 if (IpIf->Configured) {
314 goto ON_EXIT;
315 }
316
317 //
318 // Set the default interface's address, then add a directed
319 // route for it, that is, the route whose nexthop is zero.
320 //
321 Status = Ip4SetAddress (
322 IpIf,
323 EFI_NTOHL (Data->StationAddress),
324 EFI_NTOHL (Data->SubnetMask)
325 );
326
327 if (EFI_ERROR (Status)) {
328 goto ON_EXIT;
329 }
330
331 Ip4AddRoute (
332 IpSb->DefaultRouteTable,
333 EFI_NTOHL (Data->StationAddress),
334 EFI_NTOHL (Data->SubnetMask),
335 IP4_ALLZERO_ADDRESS
336 );
337
338 //
339 // Add routes returned by EFI_IP4_CONFIG protocol.
340 //
341 for (Index = 0; Index < Data->RouteTableSize; Index++) {
342 RouteEntry = &Data->RouteTable[Index];
343
344 Ip4AddRoute (
345 IpSb->DefaultRouteTable,
346 EFI_NTOHL (RouteEntry->SubnetAddress),
347 EFI_NTOHL (RouteEntry->SubnetMask),
348 EFI_NTOHL (RouteEntry->GatewayAddress)
349 );
350 }
351
352 IpSb->State = IP4_SERVICE_CONFIGED;
353
354 Ip4SetVariableData (IpSb);
355
356 ON_EXIT:
357 gBS->FreePool (Data);
358 }
359
360 VOID
361 EFIAPI
362 Ip4AutoConfigCallBack (
363 IN EFI_EVENT Event,
364 IN VOID *Context
365 )
366 /*++
367
368 Routine Description:
369
370 Request Ip4AutoConfigCallBackDpc as a DPC at TPL_CALLBACK
371
372 Arguments:
373
374 Event - The event that is signalled.
375 Context - The IP4 service binding instance.
376
377 Returns:
378
379 None
380
381 --*/
382 {
383 IP4_SERVICE *IpSb;
384
385 IpSb = (IP4_SERVICE *) Context;
386 IpSb->ActiveEvent = Event;
387
388 //
389 // Request Ip4AutoConfigCallBackDpc as a DPC at TPL_CALLBACK
390 //
391 NetLibQueueDpc (TPL_CALLBACK, Ip4AutoConfigCallBackDpc, Context);
392 }
393
394
395 /**
396 Start the auto configuration for this IP service instance.
397 It will locates the EFI_IP4_CONFIG_PROTOCOL, then start the
398 auto configuration.
399
400 @param IpSb The IP4 service instance to configure
401
402 @retval EFI_SUCCESS The auto configuration is successfull started
403 @retval Others Failed to start auto configuration.
404
405 **/
406 EFI_STATUS
407 Ip4StartAutoConfig (
408 IN IP4_SERVICE *IpSb
409 )
410 {
411 EFI_IP4_CONFIG_PROTOCOL *Ip4Config;
412 EFI_STATUS Status;
413
414 if (IpSb->State > IP4_SERVICE_UNSTARTED) {
415 return EFI_SUCCESS;
416 }
417
418 //
419 // Create the DoneEvent and ReconfigEvent to call EFI_IP4_CONFIG
420 //
421 Status = gBS->CreateEvent (
422 EVT_NOTIFY_SIGNAL,
423 TPL_CALLBACK,
424 Ip4AutoConfigCallBack,
425 IpSb,
426 &IpSb->DoneEvent
427 );
428
429 if (EFI_ERROR (Status)) {
430 return Status;
431 }
432
433 Status = gBS->CreateEvent (
434 EVT_NOTIFY_SIGNAL,
435 TPL_NOTIFY,
436 Ip4AutoConfigCallBack,
437 IpSb,
438 &IpSb->ReconfigEvent
439 );
440
441 if (EFI_ERROR (Status)) {
442 goto CLOSE_DONE_EVENT;
443 }
444
445 //
446 // Open the EFI_IP4_CONFIG protocol then start auto configure
447 //
448 Status = gBS->OpenProtocol (
449 IpSb->Controller,
450 &gEfiIp4ConfigProtocolGuid,
451 (VOID **) &Ip4Config,
452 IpSb->Image,
453 IpSb->Controller,
454 EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
455 );
456
457 if (EFI_ERROR (Status)) {
458 Status = EFI_UNSUPPORTED;
459 goto CLOSE_RECONFIG_EVENT;
460 }
461
462 Status = Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);
463
464 if (EFI_ERROR (Status)) {
465 gBS->CloseProtocol (
466 IpSb->Controller,
467 &gEfiIp4ConfigProtocolGuid,
468 IpSb->Image,
469 IpSb->Controller
470 );
471
472 goto CLOSE_RECONFIG_EVENT;
473 }
474
475 IpSb->Ip4Config = Ip4Config;
476 IpSb->State = IP4_SERVICE_STARTED;
477 return Status;
478
479 CLOSE_RECONFIG_EVENT:
480 gBS->CloseEvent (IpSb->ReconfigEvent);
481 IpSb->ReconfigEvent = NULL;
482
483 CLOSE_DONE_EVENT:
484 gBS->CloseEvent (IpSb->DoneEvent);
485 IpSb->DoneEvent = NULL;
486
487 return Status;
488 }
489
490
491 /**
492 Intiialize the IP4_PROTOCOL structure to the unconfigured states.
493
494 @param IpSb The IP4 service instance.
495 @param IpInstance The IP4 child instance.
496
497 @return None
498
499 **/
500 VOID
501 Ip4InitProtocol (
502 IN IP4_SERVICE *IpSb,
503 IN IP4_PROTOCOL *IpInstance
504 )
505 {
506 ASSERT ((IpSb != NULL) && (IpInstance != NULL));
507
508 ZeroMem (IpInstance, sizeof (IP4_PROTOCOL));
509
510 IpInstance->Signature = IP4_PROTOCOL_SIGNATURE;
511 CopyMem (&IpInstance->Ip4Proto, &mEfiIp4ProtocolTemplete, sizeof (IpInstance->Ip4Proto));
512 IpInstance->State = IP4_STATE_UNCONFIGED;
513 IpInstance->Service = IpSb;
514
515 InitializeListHead (&IpInstance->Link);
516 NetMapInit (&IpInstance->RxTokens);
517 NetMapInit (&IpInstance->TxTokens);
518 InitializeListHead (&IpInstance->Received);
519 InitializeListHead (&IpInstance->Delivered);
520 InitializeListHead (&IpInstance->AddrLink);
521
522 EfiInitializeLock (&IpInstance->RecycleLock, TPL_NOTIFY);
523 }
524
525
526 /**
527 Configure the IP4 child. If the child is already configured,
528 change the configuration parameter. Otherwise configure it
529 for the first time. The caller should validate the configuration
530 before deliver them to it. It also don't do configure NULL.
531
532 @param IpInstance The IP4 child to configure.
533 @param Config The configure data.
534
535 @retval EFI_SUCCESS The IP4 child is successfully configured.
536 @retval EFI_DEVICE_ERROR Failed to free the pending transive or to
537 configure underlying MNP or other errors.
538 @retval EFI_NO_MAPPING The IP4 child is configured to use default
539 address, but the default address hasn't been
540 configured. The IP4 child doesn't need to be
541 reconfigured when default address is configured.
542
543 **/
544 EFI_STATUS
545 Ip4ConfigProtocol (
546 IN IP4_PROTOCOL *IpInstance,
547 IN EFI_IP4_CONFIG_DATA *Config
548 )
549 {
550 IP4_SERVICE *IpSb;
551 IP4_INTERFACE *IpIf;
552 EFI_STATUS Status;
553 IP4_ADDR Ip;
554 IP4_ADDR Netmask;
555
556 IpSb = IpInstance->Service;
557
558 //
559 // User is changing packet filters. It must be stopped
560 // before the station address can be changed.
561 //
562 if (IpInstance->State == IP4_STATE_CONFIGED) {
563 //
564 // Cancel all the pending transmit/receive from upper layer
565 //
566 Status = Ip4Cancel (IpInstance, NULL);
567
568 if (EFI_ERROR (Status)) {
569 return EFI_DEVICE_ERROR;
570 }
571
572 CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
573 return EFI_SUCCESS;
574 }
575
576 //
577 // Configure a fresh IP4 protocol instance. Create a route table.
578 // Each IP child has its own route table, which may point to the
579 // default table if it is using default address.
580 //
581 Status = EFI_OUT_OF_RESOURCES;
582 IpInstance->RouteTable = Ip4CreateRouteTable ();
583
584 if (IpInstance->RouteTable == NULL) {
585 return Status;
586 }
587
588 //
589 // Set up the interface.
590 //
591 CopyMem (&Ip, &Config->StationAddress, sizeof (IP4_ADDR));
592 CopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));
593
594 Ip = NTOHL (Ip);
595 Netmask = NTOHL (Netmask);
596
597 if (!Config->UseDefaultAddress) {
598 //
599 // Find whether there is already an interface with the same
600 // station address. All the instances with the same station
601 // address shares one interface.
602 //
603 IpIf = Ip4FindStationAddress (IpSb, Ip, Netmask);
604
605 if (IpIf != NULL) {
606 NET_GET_REF (IpIf);
607
608 } else {
609 IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
610
611 if (IpIf == NULL) {
612 goto ON_ERROR;
613 }
614
615 Status = Ip4SetAddress (IpIf, Ip, Netmask);
616
617 if (EFI_ERROR (Status)) {
618 Status = EFI_DEVICE_ERROR;
619 Ip4FreeInterface (IpIf, IpInstance);
620 goto ON_ERROR;
621 }
622
623 InsertTailList (&IpSb->Interfaces, &IpIf->Link);
624 }
625
626 //
627 // Add a route to this connected network in the route table
628 //
629 Ip4AddRoute (IpInstance->RouteTable, Ip, Netmask, IP4_ALLZERO_ADDRESS);
630
631 } else {
632 //
633 // Use the default address. If the default configuration hasn't
634 // been started, start it.
635 //
636 if (IpSb->State == IP4_SERVICE_UNSTARTED) {
637 Status = Ip4StartAutoConfig (IpSb);
638
639 if (EFI_ERROR (Status)) {
640 goto ON_ERROR;
641 }
642 }
643
644 IpIf = IpSb->DefaultInterface;
645 NET_GET_REF (IpSb->DefaultInterface);
646
647 //
648 // If default address is used, so is the default route table.
649 // Any route set by the instance has the precedence over the
650 // routes in the default route table. Link the default table
651 // after the instance's table. Routing will search the local
652 // table first.
653 //
654 NET_GET_REF (IpSb->DefaultRouteTable);
655 IpInstance->RouteTable->Next = IpSb->DefaultRouteTable;
656 }
657
658 IpInstance->Interface = IpIf;
659 InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);
660
661 CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
662 IpInstance->State = IP4_STATE_CONFIGED;
663
664 //
665 // Although EFI_NO_MAPPING is an error code, the IP child has been
666 // successfully configured and doesn't need reconfiguration when
667 // default address is acquired.
668 //
669 if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
670 return EFI_NO_MAPPING;
671 }
672
673 return EFI_SUCCESS;
674
675 ON_ERROR:
676 Ip4FreeRouteTable (IpInstance->RouteTable);
677 IpInstance->RouteTable = NULL;
678 return Status;
679 }
680
681
682 /**
683 Clean up the IP4 child, release all the resources used by it.
684
685 @param IpInstance The IP4 child to clean up.
686
687 @retval EFI_SUCCESS The IP4 child is cleaned up
688 @retval EFI_DEVICE_ERROR Some resources failed to be released
689
690 **/
691 EFI_STATUS
692 Ip4CleanProtocol (
693 IN IP4_PROTOCOL *IpInstance
694 )
695 {
696 if (EFI_ERROR (Ip4Cancel (IpInstance, NULL))) {
697 return EFI_DEVICE_ERROR;
698 }
699
700 if (EFI_ERROR (Ip4Groups (IpInstance, FALSE, NULL))) {
701 return EFI_DEVICE_ERROR;
702 }
703
704 //
705 // Some packets haven't been recycled. It is because either the
706 // user forgets to recycle the packets, or because the callback
707 // hasn't been called. Just leave it alone.
708 //
709 if (!IsListEmpty (&IpInstance->Delivered)) {
710 ;
711 }
712
713 if (IpInstance->Interface != NULL) {
714 RemoveEntryList (&IpInstance->AddrLink);
715 Ip4FreeInterface (IpInstance->Interface, IpInstance);
716 IpInstance->Interface = NULL;
717 }
718
719 if (IpInstance->RouteTable != NULL) {
720 if (IpInstance->RouteTable->Next != NULL) {
721 Ip4FreeRouteTable (IpInstance->RouteTable->Next);
722 }
723
724 Ip4FreeRouteTable (IpInstance->RouteTable);
725 IpInstance->RouteTable = NULL;
726 }
727
728 if (IpInstance->EfiRouteTable != NULL) {
729 gBS->FreePool (IpInstance->EfiRouteTable);
730 IpInstance->EfiRouteTable = NULL;
731 IpInstance->EfiRouteCount = 0;
732 }
733
734 if (IpInstance->Groups != NULL) {
735 gBS->FreePool (IpInstance->Groups);
736 IpInstance->Groups = NULL;
737 IpInstance->GroupCount = 0;
738 }
739
740 NetMapClean (&IpInstance->TxTokens);
741
742 NetMapClean (&IpInstance->RxTokens);
743
744 return EFI_SUCCESS;
745 }
746
747
748 /**
749 Validate that Ip/Netmask pair is OK to be used as station
750 address. Only continuous netmasks are supported. and check
751 that StationAddress is a unicast address on the newtwork.
752
753 @param Ip The IP address to validate
754 @param Netmask The netmaks of the IP
755
756 @retval TRUE The Ip/Netmask pair is valid
757 @retval FALSE The
758
759 **/
760 BOOLEAN
761 Ip4StationAddressValid (
762 IN IP4_ADDR Ip,
763 IN IP4_ADDR Netmask
764 )
765 {
766 IP4_ADDR NetBrdcastMask;
767 INTN Len;
768 INTN Type;
769
770 //
771 // Only support the station address with 0.0.0.0/0 to enable DHCP client.
772 //
773 if (Netmask == IP4_ALLZERO_ADDRESS) {
774 return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);
775 }
776
777 //
778 // Only support the continuous net masks
779 //
780 if ((Len = NetGetMaskLength (Netmask)) == IP4_MASK_NUM) {
781 return FALSE;
782 }
783
784 //
785 // Station address can't be class D or class E address
786 //
787 if ((Type = NetGetIpClass (Ip)) > IP4_ADDR_CLASSC) {
788 return FALSE;
789 }
790
791 //
792 // Station address can't be subnet broadcast/net broadcast address
793 //
794 if ((Ip == (Ip & Netmask)) || (Ip == (Ip | ~Netmask))) {
795 return FALSE;
796 }
797
798 NetBrdcastMask = gIp4AllMasks[MIN (Len, Type << 3)];
799
800 if (Ip == (Ip | ~NetBrdcastMask)) {
801 return FALSE;
802 }
803
804 return TRUE;
805 }
806
807
808 /**
809 Configure the EFI_IP4_PROTOCOL instance. If IpConfigData is NULL,
810 the instance is cleaned up. If the instance hasn't been configure
811 before, it will be initialized. Otherwise, the filter setting of
812 the instance is updated.
813
814 @param This The IP4 child to configure
815 @param IpConfigData The configuration to apply. If NULL, clean it up.
816
817 @retval EFI_INVALID_PARAMETER The parameter is invalid
818 @retval EFI_NO_MAPPING The default address hasn't been configured and the
819 instance wants to use it.
820 @retval EFI_SUCCESS The instance is configured.
821
822 **/
823 EFI_STATUS
824 EFIAPI
825 EfiIp4Configure (
826 IN EFI_IP4_PROTOCOL *This,
827 IN EFI_IP4_CONFIG_DATA *IpConfigData OPTIONAL
828 )
829 {
830 IP4_PROTOCOL *IpInstance;
831 EFI_IP4_CONFIG_DATA *Current;
832 EFI_TPL OldTpl;
833 EFI_STATUS Status;
834 BOOLEAN AddrOk;
835 IP4_ADDR IpAddress;
836 IP4_ADDR SubnetMask;
837
838 //
839 // First, validate the parameters
840 //
841 if (This == NULL) {
842 return EFI_INVALID_PARAMETER;
843 }
844
845 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
846 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
847
848 //
849 // Validate the configuration first.
850 //
851 if (IpConfigData != NULL) {
852 //
853 // This implementation doesn't support RawData
854 //
855 if (IpConfigData->RawData) {
856 Status = EFI_UNSUPPORTED;
857 goto ON_EXIT;
858 }
859
860
861 CopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));
862 CopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));
863
864 IpAddress = NTOHL (IpAddress);
865 SubnetMask = NTOHL (SubnetMask);
866
867 //
868 // Check whether the station address is a valid unicast address
869 //
870 if (!IpConfigData->UseDefaultAddress) {
871 AddrOk = Ip4StationAddressValid (IpAddress, SubnetMask);
872
873 if (!AddrOk) {
874 Status = EFI_INVALID_PARAMETER;
875 goto ON_EXIT;
876 }
877 }
878
879 //
880 // User can only update packet filters when already configured.
881 // If it wants to change the station address, it must configure(NULL)
882 // the instance first.
883 //
884 if (IpInstance->State == IP4_STATE_CONFIGED) {
885 Current = &IpInstance->ConfigData;
886
887 if (Current->UseDefaultAddress != IpConfigData->UseDefaultAddress) {
888 Status = EFI_ALREADY_STARTED;
889 goto ON_EXIT;
890 }
891
892 if (!Current->UseDefaultAddress &&
893 (!EFI_IP4_EQUAL (&Current->StationAddress, &IpConfigData->StationAddress) ||
894 !EFI_IP4_EQUAL (&Current->SubnetMask, &IpConfigData->SubnetMask))) {
895 Status = EFI_ALREADY_STARTED;
896 goto ON_EXIT;
897 }
898
899 if (Current->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
900 return EFI_NO_MAPPING;
901 }
902 }
903 }
904
905 //
906 // Configure the instance or clean it up.
907 //
908 if (IpConfigData != NULL) {
909 Status = Ip4ConfigProtocol (IpInstance, IpConfigData);
910 } else {
911 Status = Ip4CleanProtocol (IpInstance);
912
913 //
914 // Don't change the state if it is DESTORY, consider the following
915 // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,
916 // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,
917 // the unload fails miserably.
918 //
919 if (IpInstance->State == IP4_STATE_CONFIGED) {
920 IpInstance->State = IP4_STATE_UNCONFIGED;
921 }
922 }
923
924 //
925 // Update the MNP's configure data. Ip4ServiceConfigMnp will check
926 // whether it is necessary to reconfigure the MNP.
927 //
928 Ip4ServiceConfigMnp (IpInstance->Service, FALSE);
929
930 //
931 // Update the variable data.
932 //
933 Ip4SetVariableData (IpInstance->Service);
934
935 ON_EXIT:
936 gBS->RestoreTPL (OldTpl);
937 return Status;
938
939 }
940
941
942 /**
943 Change the IP4 child's multicast setting. The caller
944 should make sure that the parameters is valid.
945
946 @param IpInstance The IP4 child to change the setting.
947 @param JoinFlag TRUE to join the group, otherwise leave it
948 @param GroupAddress The target group address
949
950 @retval EFI_ALREADY_STARTED Want to join the group, but already a member of it
951 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
952 @retval EFI_DEVICE_ERROR Failed to set the group configuraton
953 @retval EFI_SUCCESS Successfully updated the group setting.
954 @retval EFI_NOT_FOUND Try to leave the group which it isn't a member.
955
956 **/
957 EFI_STATUS
958 Ip4Groups (
959 IN IP4_PROTOCOL *IpInstance,
960 IN BOOLEAN JoinFlag,
961 IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
962 )
963 {
964 IP4_ADDR *Members;
965 IP4_ADDR Group;
966 UINT32 Index;
967
968 //
969 // Add it to the instance's Groups, and join the group by IGMP.
970 // IpInstance->Groups is in network byte order. IGMP operates in
971 // host byte order
972 //
973 if (JoinFlag) {
974 CopyMem (&Group, GroupAddress, sizeof (IP4_ADDR));
975
976 for (Index = 0; Index < IpInstance->GroupCount; Index++) {
977 if (IpInstance->Groups[Index] == Group) {
978 return EFI_ALREADY_STARTED;
979 }
980 }
981
982 Members = Ip4CombineGroups (IpInstance->Groups, IpInstance->GroupCount, Group);
983
984 if (Members == NULL) {
985 return EFI_OUT_OF_RESOURCES;
986 }
987
988 if (EFI_ERROR (Ip4JoinGroup (IpInstance, NTOHL (Group)))) {
989 gBS->FreePool (Members);
990 return EFI_DEVICE_ERROR;
991 }
992
993 if (IpInstance->Groups != NULL) {
994 gBS->FreePool (IpInstance->Groups);
995 }
996
997 IpInstance->Groups = Members;
998 IpInstance->GroupCount++;
999
1000 return EFI_SUCCESS;
1001 }
1002
1003 //
1004 // Leave the group. Leave all the groups if GroupAddress is NULL.
1005 // Must iterate from the end to the beginning because the GroupCount
1006 // is decreamented each time an address is removed..
1007 //
1008 for (Index = IpInstance->GroupCount; Index > 0 ; Index--) {
1009 Group = IpInstance->Groups[Index - 1];
1010
1011 if ((GroupAddress == NULL) || EFI_IP4_EQUAL (&Group, GroupAddress)) {
1012 if (EFI_ERROR (Ip4LeaveGroup (IpInstance, NTOHL (Group)))) {
1013 return EFI_DEVICE_ERROR;
1014 }
1015
1016 Ip4RemoveGroupAddr (IpInstance->Groups, IpInstance->GroupCount, Group);
1017 IpInstance->GroupCount--;
1018
1019 if (IpInstance->GroupCount == 0) {
1020 ASSERT (Index == 1);
1021
1022 gBS->FreePool (IpInstance->Groups);
1023 IpInstance->Groups = NULL;
1024 }
1025
1026 if (GroupAddress != NULL) {
1027 return EFI_SUCCESS;
1028 }
1029 }
1030 }
1031
1032 return ((GroupAddress != NULL) ? EFI_NOT_FOUND : EFI_SUCCESS);
1033 }
1034
1035
1036 /**
1037 Change the IP4 child's multicast setting. If JoinFlag is true,
1038 the child wants to join the group. Otherwise it wants to leave
1039 the group. If JoinFlag is false, and GroupAddress is NULL,
1040 it will leave all the groups which is a member.
1041
1042 @param This The IP4 child to change the setting.
1043 @param JoinFlag TRUE to join the group, otherwise leave it.
1044 @param GroupAddress The target group address
1045
1046 @retval EFI_INVALID_PARAMETER The parameters are invalid
1047 @retval EFI_SUCCESS The group setting has been changed.
1048 @retval Otherwise It failed to change the setting.
1049
1050 **/
1051 EFI_STATUS
1052 EFIAPI
1053 EfiIp4Groups (
1054 IN EFI_IP4_PROTOCOL *This,
1055 IN BOOLEAN JoinFlag,
1056 IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
1057 )
1058 {
1059 IP4_PROTOCOL *IpInstance;
1060 EFI_STATUS Status;
1061 EFI_TPL OldTpl;
1062 IP4_ADDR McastIp;
1063
1064 if ((This == NULL) || (JoinFlag && (GroupAddress == NULL))) {
1065 return EFI_INVALID_PARAMETER;
1066 }
1067
1068 if (GroupAddress != NULL) {
1069 CopyMem (&McastIp, GroupAddress, sizeof (IP4_ADDR));
1070
1071 if (!IP4_IS_MULTICAST (NTOHL (McastIp))) {
1072 return EFI_INVALID_PARAMETER;
1073 }
1074 }
1075
1076 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1077 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1078
1079 if (IpInstance->State != IP4_STATE_CONFIGED) {
1080 Status = EFI_NOT_STARTED;
1081 goto ON_EXIT;
1082 }
1083
1084 if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
1085 Status = EFI_NO_MAPPING;
1086 goto ON_EXIT;
1087 }
1088
1089 Status = Ip4Groups (IpInstance, JoinFlag, GroupAddress);
1090
1091 ON_EXIT:
1092 gBS->RestoreTPL (OldTpl);
1093 return Status;
1094 }
1095
1096
1097 /**
1098 Modify the IP child's route table. Each instance has its own
1099 route table.
1100
1101 @param This The IP4 child to modify the route
1102 @param DeleteRoute TRUE to delete the route, otherwise add it
1103 @param SubnetAddress The destination network
1104 @param SubnetMask The destination network's mask
1105 @param GatewayAddress The next hop address.
1106
1107 @retval EFI_INVALID_PARAMETER The parameter is invalid.
1108 @retval EFI_SUCCESS The route table is successfully modified.
1109 @retval Others Failed to modify the route table
1110
1111 **/
1112 EFI_STATUS
1113 EFIAPI
1114 EfiIp4Routes (
1115 IN EFI_IP4_PROTOCOL *This,
1116 IN BOOLEAN DeleteRoute,
1117 IN EFI_IPv4_ADDRESS *SubnetAddress,
1118 IN EFI_IPv4_ADDRESS *SubnetMask,
1119 IN EFI_IPv4_ADDRESS *GatewayAddress
1120 )
1121 {
1122 IP4_PROTOCOL *IpInstance;
1123 IP4_INTERFACE *IpIf;
1124 IP4_ADDR Dest;
1125 IP4_ADDR Netmask;
1126 IP4_ADDR Nexthop;
1127 EFI_STATUS Status;
1128 EFI_TPL OldTpl;
1129
1130 //
1131 // First, validate the parameters
1132 //
1133 if ((This == NULL) || (SubnetAddress == NULL) ||
1134 (SubnetMask == NULL) || (GatewayAddress == NULL)) {
1135 return EFI_INVALID_PARAMETER;
1136 }
1137
1138 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1139 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1140
1141 if (IpInstance->State != IP4_STATE_CONFIGED) {
1142 Status = EFI_NOT_STARTED;
1143 goto ON_EXIT;
1144 }
1145
1146 if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
1147 Status = EFI_NO_MAPPING;
1148 goto ON_EXIT;
1149 }
1150
1151 CopyMem (&Dest, SubnetAddress, sizeof (IP4_ADDR));
1152 CopyMem (&Netmask, SubnetMask, sizeof (IP4_ADDR));
1153 CopyMem (&Nexthop, GatewayAddress, sizeof (IP4_ADDR));
1154
1155 Dest = NTOHL (Dest);
1156 Netmask = NTOHL (Netmask);
1157 Nexthop = NTOHL (Nexthop);
1158
1159 IpIf = IpInstance->Interface;
1160
1161 if (!IP4_IS_VALID_NETMASK (Netmask)) {
1162 Status = EFI_INVALID_PARAMETER;
1163 goto ON_EXIT;
1164 }
1165
1166 //
1167 // the gateway address must be a unicast on the connected network if not zero.
1168 //
1169 if ((Nexthop != IP4_ALLZERO_ADDRESS) &&
1170 (!IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask) ||
1171 IP4_IS_BROADCAST (Ip4GetNetCast (Nexthop, IpIf)))) {
1172
1173 Status = EFI_INVALID_PARAMETER;
1174 goto ON_EXIT;
1175 }
1176
1177 if (DeleteRoute) {
1178 Status = Ip4DelRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
1179 } else {
1180 Status = Ip4AddRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
1181 }
1182
1183 ON_EXIT:
1184 gBS->RestoreTPL (OldTpl);
1185 return Status;
1186 }
1187
1188
1189 /**
1190 Check whether the user's token or event has already
1191 been enqueue on IP4's list.
1192
1193 @param Map The container of either user's transmit or receive
1194 token.
1195 @param Item Current item to check against
1196 @param Context The Token to check againist.
1197
1198 @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
1199 @retval EFI_SUCCESS The current item isn't the same token/event as the
1200 context.
1201
1202 **/
1203 EFI_STATUS
1204 Ip4TokenExist (
1205 IN NET_MAP *Map,
1206 IN NET_MAP_ITEM *Item,
1207 IN VOID *Context
1208 )
1209 {
1210 EFI_IP4_COMPLETION_TOKEN *Token;
1211 EFI_IP4_COMPLETION_TOKEN *TokenInItem;
1212
1213 Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
1214 TokenInItem = (EFI_IP4_COMPLETION_TOKEN *) Item->Key;
1215
1216 if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
1217 return EFI_ACCESS_DENIED;
1218 }
1219
1220 return EFI_SUCCESS;
1221 }
1222
1223
1224 /**
1225 Validate the user's token against current station address.
1226
1227 @param Token User's token to validate
1228 @param IpIf The IP4 child's interface.
1229
1230 @retval EFI_INVALID_PARAMETER Some parameters are invalid
1231 @retval EFI_BAD_BUFFER_SIZE The user's option/data is too long.
1232 @retval EFI_SUCCESS The token is OK
1233
1234 **/
1235 EFI_STATUS
1236 Ip4TxTokenValid (
1237 IN EFI_IP4_COMPLETION_TOKEN *Token,
1238 IN IP4_INTERFACE *IpIf
1239 )
1240 {
1241 EFI_IP4_TRANSMIT_DATA *TxData;
1242 EFI_IP4_OVERRIDE_DATA *Override;
1243 IP4_ADDR Src;
1244 IP4_ADDR Gateway;
1245 UINT32 Offset;
1246 UINT32 Index;
1247 UINT32 HeadLen;
1248
1249 if ((Token == NULL) || (Token->Event == NULL) || (Token->Packet.TxData == NULL)) {
1250 return EFI_INVALID_PARAMETER;
1251 }
1252
1253 TxData = Token->Packet.TxData;
1254
1255 //
1256 // Check the IP options: no more than 40 bytes and format is OK
1257 //
1258 if (TxData->OptionsLength != 0) {
1259 if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {
1260 return EFI_INVALID_PARAMETER;
1261 }
1262
1263 if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {
1264 return EFI_INVALID_PARAMETER;
1265 }
1266 }
1267
1268 //
1269 // Check the fragment table: no empty fragment, and length isn't bogus
1270 //
1271 if ((TxData->TotalDataLength == 0) || (TxData->FragmentCount == 0)) {
1272 return EFI_INVALID_PARAMETER;
1273 }
1274
1275 Offset = TxData->TotalDataLength;
1276
1277 for (Index = 0; Index < TxData->FragmentCount; Index++) {
1278 if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||
1279 (TxData->FragmentTable[Index].FragmentLength == 0)) {
1280
1281 return EFI_INVALID_PARAMETER;
1282 }
1283
1284 Offset -= TxData->FragmentTable[Index].FragmentLength;
1285 }
1286
1287 if (Offset != 0) {
1288 return EFI_INVALID_PARAMETER;
1289 }
1290
1291 //
1292 // Check the source and gateway: they must be a valid unicast.
1293 // Gateway must also be on the connected network.
1294 //
1295 if (TxData->OverrideData) {
1296 Override = TxData->OverrideData;
1297
1298 CopyMem (&Src, &Override->SourceAddress, sizeof (IP4_ADDR));
1299 CopyMem (&Gateway, &Override->GatewayAddress, sizeof (IP4_ADDR));
1300
1301 Src = NTOHL (Src);
1302 Gateway = NTOHL (Gateway);
1303
1304 if ((NetGetIpClass (Src) > IP4_ADDR_CLASSC) ||
1305 (Src == IP4_ALLONE_ADDRESS) ||
1306 IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {
1307
1308 return EFI_INVALID_PARAMETER;
1309 }
1310
1311 //
1312 // If gateway isn't zero, it must be a unicast address, and
1313 // on the connected network.
1314 //
1315 if ((Gateway != IP4_ALLZERO_ADDRESS) &&
1316 ((NetGetIpClass (Gateway) > IP4_ADDR_CLASSC) ||
1317 !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask) ||
1318 IP4_IS_BROADCAST (Ip4GetNetCast (Gateway, IpIf)))) {
1319
1320 return EFI_INVALID_PARAMETER;
1321 }
1322 }
1323
1324 //
1325 // Check the packet length: Head length and packet length all has a limit
1326 //
1327 HeadLen = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);
1328
1329 if ((HeadLen > IP4_MAX_HEADLEN) ||
1330 (TxData->TotalDataLength + HeadLen > IP4_MAX_PACKET_SIZE)) {
1331
1332 return EFI_BAD_BUFFER_SIZE;
1333 }
1334
1335 return EFI_SUCCESS;
1336 }
1337
1338
1339 /**
1340 The callback function for the net buffer which wraps the user's
1341 transmit token. Although it seems this function is pretty simple,
1342 there are some subtle things.
1343 When user requests the IP to transmit a packet by passing it a
1344 token, the token is wrapped in an IP4_TXTOKEN_WRAP and the data
1345 is wrapped in an net buffer. the net buffer's Free function is
1346 set to Ip4FreeTxToken. The Token and token wrap are added to the
1347 IP child's TxToken map. Then the buffer is passed to Ip4Output for
1348 transmission. If something error happened before that, the buffer
1349 is freed, which in turn will free the token wrap. The wrap may
1350 have been added to the TxToken map or not, and the user's event
1351 shouldn't be fired because we are still in the EfiIp4Transmit. If
1352 the buffer has been sent by Ip4Output, it should be removed from
1353 the TxToken map and user's event signaled. The token wrap and buffer
1354 are bound together. Check the comments in Ip4Output for information
1355 about IP fragmentation.
1356
1357 @param Context The token's wrap
1358
1359 @return None
1360
1361 **/
1362 VOID
1363 Ip4FreeTxToken (
1364 IN VOID *Context
1365 )
1366 {
1367 IP4_TXTOKEN_WRAP *Wrap;
1368 NET_MAP_ITEM *Item;
1369
1370 Wrap = (IP4_TXTOKEN_WRAP *) Context;
1371
1372 //
1373 // Find the token in the instance's map. EfiIp4Transmit put the
1374 // token to the map. If that failed, NetMapFindKey will return NULL.
1375 //
1376 Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);
1377
1378 if (Item != NULL) {
1379 NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);
1380 }
1381
1382 if (Wrap->Sent) {
1383 gBS->SignalEvent (Wrap->Token->Event);
1384
1385 //
1386 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
1387 //
1388 NetLibDispatchDpc ();
1389 }
1390
1391 gBS->FreePool (Wrap);
1392 }
1393
1394
1395 /**
1396 The callback function to Ip4Output to update the transmit status.
1397
1398 @param Ip4Instance The Ip4Instance that request the transmit.
1399 @param Packet The user's transmit request
1400 @param IoStatus The result of the transmission
1401 @param Flag Not used during transmission
1402 @param Context The token's wrap.
1403
1404 @return None
1405
1406 **/
1407 VOID
1408 Ip4OnPacketSent (
1409 IP4_PROTOCOL *Ip4Instance,
1410 NET_BUF *Packet,
1411 EFI_STATUS IoStatus,
1412 UINT32 Flag,
1413 VOID *Context
1414 )
1415 {
1416 IP4_TXTOKEN_WRAP *Wrap;
1417
1418 //
1419 // This is the transmission request from upper layer,
1420 // not the IP4 driver itself.
1421 //
1422 ASSERT (Ip4Instance != NULL);
1423
1424 //
1425 // The first fragment of the packet has been sent. Update
1426 // the token's status. That is, if fragmented, the transmit's
1427 // status is the first fragment's status. The Wrap will be
1428 // release when all the fragments are release. Check the comments
1429 // in Ip4FreeTxToken and Ip4Output for information.
1430 //
1431 Wrap = (IP4_TXTOKEN_WRAP *) Context;
1432 Wrap->Token->Status = IoStatus;
1433
1434 NetbufFree (Wrap->Packet);
1435 }
1436
1437
1438 /**
1439 Transmit the user's data asynchronously. When transmission
1440 completed,the Token's status is updated and its event signalled.
1441
1442 @param This The IP4 child instance
1443 @param Token The user's transmit token, which contains user's
1444 data, the result and an event to signal when
1445 completed.
1446
1447 @retval EFI_INVALID_PARAMETER The parameter is invalid.
1448 @retval EFI_NOT_STARTED The IP4 child hasn't been started.
1449 @retval EFI_SUCCESS The user's data has been successfully enqueued
1450 for transmission.
1451
1452 **/
1453 EFI_STATUS
1454 EFIAPI
1455 EfiIp4Transmit (
1456 IN EFI_IP4_PROTOCOL *This,
1457 IN EFI_IP4_COMPLETION_TOKEN *Token
1458 )
1459 {
1460 IP4_SERVICE *IpSb;
1461 IP4_PROTOCOL *IpInstance;
1462 IP4_INTERFACE *IpIf;
1463 IP4_TXTOKEN_WRAP *Wrap;
1464 EFI_IP4_TRANSMIT_DATA *TxData;
1465 EFI_IP4_CONFIG_DATA *Config;
1466 EFI_IP4_OVERRIDE_DATA *Override;
1467 IP4_HEAD Head;
1468 IP4_ADDR GateWay;
1469 EFI_STATUS Status;
1470 EFI_TPL OldTpl;
1471 BOOLEAN DontFragment;
1472 UINT32 HeadLen;
1473
1474 if (This == NULL) {
1475 return EFI_INVALID_PARAMETER;
1476 }
1477
1478 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1479
1480 if (IpInstance->State != IP4_STATE_CONFIGED) {
1481 return EFI_NOT_STARTED;
1482 }
1483
1484 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1485
1486 IpSb = IpInstance->Service;
1487 IpIf = IpInstance->Interface;
1488 Config = &IpInstance->ConfigData;
1489
1490 if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
1491 Status = EFI_NO_MAPPING;
1492 goto ON_EXIT;
1493 }
1494
1495 //
1496 // make sure that token is properly formated
1497 //
1498 Status = Ip4TxTokenValid (Token, IpIf);
1499
1500 if (EFI_ERROR (Status)) {
1501 goto ON_EXIT;
1502 }
1503
1504 //
1505 // Check whether the token or signal already existed.
1506 //
1507 if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip4TokenExist, Token))) {
1508 Status = EFI_ACCESS_DENIED;
1509 goto ON_EXIT;
1510 }
1511
1512 //
1513 // Build the IP header, need to fill in the Tos, TotalLen, Id,
1514 // fragment, Ttl, protocol, Src, and Dst.
1515 //
1516 TxData = Token->Packet.TxData;
1517
1518 CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));
1519 Head.Dst = NTOHL (Head.Dst);
1520
1521 if (TxData->OverrideData) {
1522 Override = TxData->OverrideData;
1523 Head.Protocol = Override->Protocol;
1524 Head.Tos = Override->TypeOfService;
1525 Head.Ttl = Override->TimeToLive;
1526 DontFragment = Override->DoNotFragment;
1527
1528 CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));
1529 CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));
1530
1531 Head.Src = NTOHL (Head.Src);
1532 GateWay = NTOHL (GateWay);
1533 } else {
1534 Head.Src = IpIf->Ip;
1535 GateWay = IP4_ALLZERO_ADDRESS;
1536 Head.Protocol = Config->DefaultProtocol;
1537 Head.Tos = Config->TypeOfService;
1538 Head.Ttl = Config->TimeToLive;
1539 DontFragment = Config->DoNotFragment;
1540 }
1541
1542 Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);
1543 HeadLen = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);
1544
1545 //
1546 // If don't fragment and fragment needed, return error
1547 //
1548 if (DontFragment && (TxData->TotalDataLength + HeadLen > IpSb->SnpMode.MaxPacketSize)) {
1549 Status = EFI_BAD_BUFFER_SIZE;
1550 goto ON_EXIT;
1551 }
1552
1553 //
1554 // OK, it survives all the validation check. Wrap the token in
1555 // a IP4_TXTOKEN_WRAP and the data in a netbuf
1556 //
1557 Status = EFI_OUT_OF_RESOURCES;
1558 Wrap = AllocatePool (sizeof (IP4_TXTOKEN_WRAP));
1559 if (Wrap == NULL) {
1560 goto ON_EXIT;
1561 }
1562
1563 Wrap->IpInstance = IpInstance;
1564 Wrap->Token = Token;
1565 Wrap->Sent = FALSE;
1566 Wrap->Life = IP4_US_TO_SEC (Config->TransmitTimeout);
1567 Wrap->Packet = NetbufFromExt (
1568 (NET_FRAGMENT *) TxData->FragmentTable,
1569 TxData->FragmentCount,
1570 IP4_MAX_HEADLEN,
1571 0,
1572 Ip4FreeTxToken,
1573 Wrap
1574 );
1575
1576 if (Wrap->Packet == NULL) {
1577 gBS->FreePool (Wrap);
1578 goto ON_EXIT;
1579 }
1580
1581 Token->Status = EFI_NOT_READY;
1582
1583 if (EFI_ERROR (NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap))) {
1584 //
1585 // NetbufFree will call Ip4FreeTxToken, which in turn will
1586 // free the IP4_TXTOKEN_WRAP. Now, the token wrap hasn't been
1587 // enqueued.
1588 //
1589 NetbufFree (Wrap->Packet);
1590 goto ON_EXIT;
1591 }
1592
1593 //
1594 // Mark the packet sent before output it. Mark it not sent again if the
1595 // returned status is not EFI_SUCCESS;
1596 //
1597 Wrap->Sent = TRUE;
1598
1599 Status = Ip4Output (
1600 IpSb,
1601 IpInstance,
1602 Wrap->Packet,
1603 &Head,
1604 TxData->OptionsBuffer,
1605 TxData->OptionsLength,
1606 GateWay,
1607 Ip4OnPacketSent,
1608 Wrap
1609 );
1610
1611 if (EFI_ERROR (Status)) {
1612 Wrap->Sent = FALSE;
1613 NetbufFree (Wrap->Packet);
1614 }
1615
1616 ON_EXIT:
1617 gBS->RestoreTPL (OldTpl);
1618 return Status;
1619 }
1620
1621
1622 /**
1623 Receive a packet for the upper layer. If there are packets
1624 pending on the child's receive queue, the receive request
1625 will be fulfilled immediately. Otherwise, the request is
1626 enqueued. When receive request is completed, the status in
1627 the Token is updated and its event is signalled.
1628
1629 @param This The IP4 child to receive packet.
1630 @param Token The user's receive token
1631
1632 @retval EFI_INVALID_PARAMETER The token is invalid.
1633 @retval EFI_NOT_STARTED The IP4 child hasn't been started
1634 @retval EFI_ACCESS_DENIED The token or event is already queued.
1635 @retval EFI_SUCCESS The receive request has been issued.
1636
1637 **/
1638 EFI_STATUS
1639 EFIAPI
1640 EfiIp4Receive (
1641 IN EFI_IP4_PROTOCOL *This,
1642 IN EFI_IP4_COMPLETION_TOKEN *Token
1643 )
1644 {
1645 IP4_PROTOCOL *IpInstance;
1646 EFI_STATUS Status;
1647 EFI_TPL OldTpl;
1648
1649 //
1650 // First validate the parameters
1651 //
1652 if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
1653 return EFI_INVALID_PARAMETER;
1654 }
1655
1656 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1657
1658 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1659
1660 if (IpInstance->State != IP4_STATE_CONFIGED) {
1661 Status = EFI_NOT_STARTED;
1662 goto ON_EXIT;
1663 }
1664
1665 //
1666 // Check whether the toke is already on the receive queue.
1667 //
1668 Status = NetMapIterate (&IpInstance->RxTokens, Ip4TokenExist, Token);
1669
1670 if (EFI_ERROR (Status)) {
1671 Status = EFI_ACCESS_DENIED;
1672 goto ON_EXIT;
1673 }
1674
1675 //
1676 // Queue the token then check whether there is pending received packet.
1677 //
1678 Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);
1679
1680 if (EFI_ERROR (Status)) {
1681 goto ON_EXIT;
1682 }
1683
1684 Status = Ip4InstanceDeliverPacket (IpInstance);
1685
1686 //
1687 // Dispatch the DPC queued by the NotifyFunction of this instane's receive
1688 // event.
1689 //
1690 NetLibDispatchDpc ();
1691
1692 ON_EXIT:
1693 gBS->RestoreTPL (OldTpl);
1694 return Status;
1695 }
1696
1697
1698 /**
1699 Cancel the transmitted but not recycled packet. If a matching
1700 token is found, it will call Ip4CancelPacket to cancel the
1701 packet. Ip4CancelPacket will cancel all the fragments of the
1702 packet. When all the fragments are freed, the IP4_TXTOKEN_WRAP
1703 will be deleted from the Map, and user's event signalled.
1704 Because Ip4CancelPacket and other functions are all called in
1705 line, so, after Ip4CancelPacket returns, the Item has been freed.
1706
1707 @param Map The IP4 child's transmit queue
1708 @param Item The current transmitted packet to test.
1709 @param Context The user's token to cancel.
1710
1711 @retval EFI_SUCCESS Continue to check the next Item.
1712 @retval EFI_ABORTED The user's Token (Token != NULL) is cancelled.
1713
1714 **/
1715 EFI_STATUS
1716 Ip4CancelTxTokens (
1717 IN NET_MAP *Map,
1718 IN NET_MAP_ITEM *Item,
1719 IN VOID *Context
1720 )
1721 {
1722 EFI_IP4_COMPLETION_TOKEN *Token;
1723 IP4_TXTOKEN_WRAP *Wrap;
1724
1725 Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
1726
1727 //
1728 // Return EFI_SUCCESS to check the next item in the map if
1729 // this one doesn't match.
1730 //
1731 if ((Token != NULL) && (Token != Item->Key)) {
1732 return EFI_SUCCESS;
1733 }
1734
1735 Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
1736 ASSERT (Wrap != NULL);
1737
1738 //
1739 // Don't access the Item, Wrap and Token's members after this point.
1740 // Item and wrap has been freed. And we no longer own the Token.
1741 //
1742 Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
1743
1744 //
1745 // If only one item is to be cancel, return EFI_ABORTED to stop
1746 // iterating the map any more.
1747 //
1748 if (Token != NULL) {
1749 return EFI_ABORTED;
1750 }
1751
1752 return EFI_SUCCESS;
1753 }
1754
1755
1756 /**
1757 Cancel the receive request. This is quiet simple, because
1758 it is only enqueued in our local receive map.
1759
1760 @param Map The IP4 child's receive queue
1761 @param Item Current receive request to cancel.
1762 @param Context The user's token to cancel
1763
1764 @retval EFI_SUCCESS Continue to check the next receive request on the
1765 queue.
1766 @retval EFI_ABORTED The user's token (token != NULL) has been
1767 cancelled.
1768
1769 **/
1770 EFI_STATUS
1771 Ip4CancelRxTokens (
1772 IN NET_MAP *Map,
1773 IN NET_MAP_ITEM *Item,
1774 IN VOID *Context
1775 )
1776 {
1777 EFI_IP4_COMPLETION_TOKEN *Token;
1778 EFI_IP4_COMPLETION_TOKEN *This;
1779
1780 Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
1781 This = Item->Key;
1782
1783 if ((Token != NULL) && (Token != This)) {
1784 return EFI_SUCCESS;
1785 }
1786
1787 NetMapRemoveItem (Map, Item, NULL);
1788
1789 This->Status = EFI_ABORTED;
1790 This->Packet.RxData = NULL;
1791 gBS->SignalEvent (This->Event);
1792
1793 if (Token != NULL) {
1794 return EFI_ABORTED;
1795 }
1796
1797 return EFI_SUCCESS;
1798 }
1799
1800
1801 /**
1802 Cancel the user's receive/transmit request.
1803
1804 @param IpInstance The IP4 child
1805 @param Token The token to cancel. If NULL, all token will be
1806 cancelled.
1807
1808 @retval EFI_SUCCESS The token is cancelled
1809 @retval EFI_NOT_FOUND The token isn't found on either the
1810 transmit/receive queue
1811 @retval EFI_DEVICE_ERROR Not all token is cancelled when Token is NULL.
1812
1813 **/
1814 EFI_STATUS
1815 Ip4Cancel (
1816 IN IP4_PROTOCOL *IpInstance,
1817 IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
1818 )
1819 {
1820 EFI_STATUS Status;
1821
1822 //
1823 // First check the transmitted packet. Ip4CancelTxTokens returns
1824 // EFI_ABORTED to mean that the token has been cancelled when
1825 // token != NULL. So, return EFI_SUCCESS for this condition.
1826 //
1827 Status = NetMapIterate (&IpInstance->TxTokens, Ip4CancelTxTokens, Token);
1828
1829 if (EFI_ERROR (Status)) {
1830 if ((Token != NULL) && (Status == EFI_ABORTED)) {
1831 return EFI_SUCCESS;
1832 }
1833
1834 return Status;
1835 }
1836
1837 //
1838 // Check the receive queue. Ip4CancelRxTokens also returns EFI_ABORT
1839 // for Token!=NULL and it is cancelled.
1840 //
1841 Status = NetMapIterate (&IpInstance->RxTokens, Ip4CancelRxTokens, Token);
1842 //
1843 // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's
1844 // events.
1845 //
1846 NetLibDispatchDpc ();
1847 if (EFI_ERROR (Status)) {
1848 if ((Token != NULL) && (Status == EFI_ABORTED)) {
1849 return EFI_SUCCESS;
1850 }
1851
1852 return Status;
1853 }
1854
1855 //
1856 // OK, if the Token is found when Token != NULL, the NetMapIterate
1857 // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.
1858 //
1859 if (Token != NULL) {
1860 return EFI_NOT_FOUND;
1861 }
1862
1863 //
1864 // If Token == NULL, cancel all the tokens. return error if no
1865 // all of them are cancelled.
1866 //
1867 if (!NetMapIsEmpty (&IpInstance->TxTokens) ||
1868 !NetMapIsEmpty (&IpInstance->RxTokens)) {
1869
1870 return EFI_DEVICE_ERROR;
1871 }
1872
1873 return EFI_SUCCESS;
1874 }
1875
1876
1877 /**
1878 Cancel the queued receive/transmit requests. If Token is NULL,
1879 all the queued requests will be cancelled. It just validate
1880 the parameter then pass them to Ip4Cancel.
1881
1882 @param This The IP4 child to cancel the request
1883 @param Token The token to cancel, if NULL, cancel all.
1884
1885 @retval EFI_INVALID_PARAMETER This is NULL
1886 @retval EFI_NOT_STARTED The IP4 child hasn't been configured.
1887 @retval EFI_NO_MAPPING The IP4 child is configured to use the default,
1888 but the default address hasn't been acquired.
1889 @retval EFI_SUCCESS The Token is cancelled.
1890
1891 **/
1892 EFI_STATUS
1893 EFIAPI
1894 EfiIp4Cancel (
1895 IN EFI_IP4_PROTOCOL *This,
1896 IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
1897 )
1898 {
1899 IP4_PROTOCOL *IpInstance;
1900 EFI_STATUS Status;
1901 EFI_TPL OldTpl;
1902
1903 if (This == NULL) {
1904 return EFI_INVALID_PARAMETER;
1905 }
1906
1907 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1908
1909 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1910
1911 if (IpInstance->State != IP4_STATE_CONFIGED) {
1912 Status = EFI_NOT_STARTED;
1913 goto ON_EXIT;
1914 }
1915
1916 if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
1917 Status = EFI_NO_MAPPING;
1918 goto ON_EXIT;
1919 }
1920
1921 Status = Ip4Cancel (IpInstance, Token);
1922
1923 ON_EXIT:
1924 gBS->RestoreTPL (OldTpl);
1925 return Status;
1926 }
1927
1928
1929 /**
1930 Poll the network stack. The EFI network stack is poll based. There
1931 is no interrupt support for the network interface card.
1932
1933 @param This The IP4 child to poll through
1934
1935 @retval EFI_INVALID_PARAMETER The parameter is invalid
1936 @retval EFI_NOT_STARTED The IP4 child hasn't been configured.
1937
1938 **/
1939 EFI_STATUS
1940 EFIAPI
1941 EfiIp4Poll (
1942 IN EFI_IP4_PROTOCOL *This
1943 )
1944 {
1945 IP4_PROTOCOL *IpInstance;
1946 EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
1947
1948 if (This == NULL) {
1949 return EFI_INVALID_PARAMETER;
1950 }
1951
1952 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1953
1954 if (IpInstance->State == IP4_STATE_UNCONFIGED) {
1955 return EFI_NOT_STARTED;
1956 }
1957
1958 Mnp = IpInstance->Service->Mnp;
1959
1960 //
1961 // Don't lock the Poll function to enable the deliver of
1962 // the packet polled up.
1963 //
1964 return Mnp->Poll (Mnp);
1965 }
1966
1967 EFI_IP4_PROTOCOL
1968 mEfiIp4ProtocolTemplete = {
1969 EfiIp4GetModeData,
1970 EfiIp4Configure,
1971 EfiIp4Groups,
1972 EfiIp4Routes,
1973 EfiIp4Transmit,
1974 EfiIp4Receive,
1975 EfiIp4Cancel,
1976 EfiIp4Poll
1977 };
1978
1979
1980 /**
1981 Decrease the life of the transmitted packets. If it is
1982 decreased to zero, cancel the packet. This function is
1983 called by Ip4packetTimerTicking which time out both the
1984 received-but-not-delivered and transmitted-but-not-recycle
1985 packets.
1986
1987 @param Map The IP4 child's transmit map.
1988 @param Item Current transmitted packet
1989 @param Context Not used.
1990
1991 @retval EFI_SUCCESS Always returns EFI_SUCCESS
1992
1993 **/
1994 EFI_STATUS
1995 Ip4SentPacketTicking (
1996 IN NET_MAP *Map,
1997 IN NET_MAP_ITEM *Item,
1998 IN VOID *Context
1999 )
2000 {
2001 IP4_TXTOKEN_WRAP *Wrap;
2002
2003 Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
2004 ASSERT (Wrap != NULL);
2005
2006 if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {
2007 Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
2008 }
2009
2010 return EFI_SUCCESS;
2011 }
2012
2013
2014 /**
2015 The heart beat timer of IP4 service instance. It times out
2016 all of its IP4 children's received-but-not-delivered and
2017 transmitted-but-not-recycle packets, and provides time input
2018 for its IGMP protocol.
2019
2020 @param Event The IP4 service instance's heart beat timer.
2021 @param Context The IP4 service instance.
2022
2023 @return None
2024
2025 **/
2026 VOID
2027 EFIAPI
2028 Ip4TimerTicking (
2029 IN EFI_EVENT Event,
2030 IN VOID *Context
2031 )
2032 {
2033 IP4_SERVICE *IpSb;
2034
2035 IpSb = (IP4_SERVICE *) Context;
2036 NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
2037
2038 Ip4PacketTimerTicking (IpSb);
2039 Ip4IgmpTicking (IpSb);
2040 }