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