Hi, Michael

It's indeed a problem that NET_RANDOM (NetRandomInitSeed ()) may return same 
value if the time service is not accuracy enough on some platform. And as you 
said it's used to give unique but not necessarily to be real random number, so 
I think we could just add some salt into the seed. I think the platform 
monotonic counter may be a good choose, we can call 
gBS->GetNextMonotonicCount() and add the low 32 bits of MC to the seed. This 
could make the returned seed unique even GetTime() return all zero in the worst 
case. What do you think about it?

For your recommendation #3, the IaId is configured by Ip6Dxe and PXE driver, 
and there are no interface to exchange the index between them. DHCP6 driver 
just use the IaId configured by caller and it couldn't modify it. And for 4, 
one of the design intention of PXE boot is "platform doesn't need any 
pre-configuration", so it's also not acceptable.

Best Regards,
Siyuan

-----Original Message-----
From: Michael Chang [mailto:mch...@suse.com] 
Sent: Thursday, July 23, 2015 3:33 PM
To: edk2-devel@lists.sourceforge.net
Subject: [edk2] DHCPv6 IAID and NetRandomInitSeed problem in OVMF

Hi,

I have problem in IPv6 PXE booting under OVMF that the process terminated 
immediately right after selecting the UEFI IPv6 boot entry. I have to change 
the IPv6 config policy from automatic to manual to get things working again for 
me.

I looked a bit into this problem, it was terminated by the error in IaId check

 in NetworkPkg/Dhcp6Dxe/Dhcp6Impl.c::EfiDhcp6Configure function  
    
    //
    // Make sure the (IaId, IaType) is unique over all the instances.
    //
    NET_LIST_FOR_EACH (Entry, &Service->Child) {
      Other = NET_LIST_USER_STRUCT (Entry, DHCP6_INSTANCE, Link);
      if (Other->IaCb.Ia != NULL &&
          Other->IaCb.Ia->Descriptor.Type == Dhcp6CfgData->IaDescriptor.Type &&
          Other->IaCb.Ia->Descriptor.IaId == Dhcp6CfgData->IaDescriptor.IaId
          ) {
        return EFI_INVALID_PARAMETER;
      }
    }

Which would be saying clearly it was not "unique" among all the running
DHCPv6 instances. At that time there should be only two:

1. The IPv6 config instance, while the policy is set to automatic would 
exchange information with server with the IaId initialized at

  NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c::Ip6ConfigInitInstance

    Instance->IaId = NET_RANDOM (NetRandomInitSeed ());

    for (Index = 0; Index < IpSb->SnpMode.HwAddressSize; Index++) {
      Instance->IaId |= (IpSb->SnpMode.CurrentAddress.Addr[Index] << ((Index << 
3) & 31));
    }

2. The IPv6 PXE Base code driver would start another DHCPv6 session with the 
IaId initialized at

  NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c::PxeBcCreateIp6Children 

  //
  // Generate a random IAID for the Dhcp6 assigned address.
  //
  Private->IaId = NET_RANDOM (NetRandomInitSeed ());
  if (Private->Snp != NULL) {
    for (Index = 0; Index < Private->Snp->Mode->HwAddressSize; Index++) {
      Private->IaId |= (Private->Snp->Mode->CurrentAddress.Addr[Index] << 
((Index << 3) & 31));
    }
  }

Unfortunately both IaId collides, and quite surprisingly it's NET_RANDOM 
(NetRandomInitSeed ()), or NetRandomInitSeed () generates the same number for 
them.

UINT32
EFIAPI
NetRandomInitSeed (
  VOID
  )
{
  EFI_TIME                  Time;
  UINT32                    Seed;

  gRT->GetTime (&Time, NULL);
  Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second);
  Seed ^= Time.Nanosecond;
  Seed ^= Time.Year << 7;

  return Seed;
}

The returned Time.Nanosecond is always zero as the timer resolution is l Hz for 
PC-AT CMOS RTC, that seems to be default real time clock driver used by OVMF. 
At least from .dsc file it says so ..

  PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf

The NetRandomInitSeed is not random enough in this case, and the NET_RANDOM 
marco is even more confusing as it's not a random number generator either (so 
what is good for always feeding random "seed" to a deterministic mathematic 
fucntion ??)  

I don't have good idea how to fix the problem, but here are of my thoughs.

1. Use real timer clock driver which could provide higher resolution for time 
service. Qemu is able to provide HPET timer but I don't know how to configure 
OVMF to use it.

2. Use GetPerformanceCounter(), but that would increase image size by linking 
TimerLib.

3. The IaId has to be "unique" thus not necessarily to be random, probably it 
should be derived by some properties like MAC address and an assgined index 
(staring from zero) for the interface to be confiured.

4. Use manual as default IPv6 policy, but that just hide the problem.

Hope that my information and findings helps. :)

Thanks,
Michael

------------------------------------------------------------------------------
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

------------------------------------------------------------------------------
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to