[DHCPCSVC] Implement alternate configuration

- Set the ip address, subnet mask and default gateway when an alternate configuration has been configured.
- Set registry values for the alternate configuration and APIPA.
This commit is contained in:
Eric Kohl
2026-04-12 14:35:48 +02:00
parent 278234259d
commit 98b9b434c6

View File

@@ -1213,53 +1213,187 @@ send_discover(void *ipp)
void
state_panic(void *ipp)
{
struct interface_info *ip = ipp;
uint16_t address_low;
int i;
CHAR szKeyNameBuffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
CHAR Server[] = "255.255.255.255";
CHAR SubnetMask[] = "255.255.0.0";
CHAR AddressBuffer[32];
struct interface_info *ip = ipp;
uint16_t address_low;
int i;
IPAddr IpAddress;
ULONG Buffer[20];
ULONG BufferSize;
DWORD ret;
HKEY hKey = NULL;
PDHCP_ADAPTER Adapter = AdapterFindInfo(ip);
NTSTATUS Status;
DWORD lease = 0;
time_t cur_time, never_time = 0x7FFFFFFF;
struct in_addr addr;
note("No DHCPOFFERS received.");
note("No DHCPOFFERS received.");
time(&cur_time);
strcat(szKeyNameBuffer, Adapter->DhclientInfo.name);
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, szKeyNameBuffer, 0, KEY_WRITE, &hKey) != ERROR_SUCCESS)
hKey = NULL;
if (Adapter && !Adapter->NteContext)
{
/* Generate an automatic private address */
DbgPrint("DHCPCSVC: Failed to receive a response from a DHCP server. An automatic private address will be assigned.\n");
/* FIXME: The address generation code sucks */
srand(0);
for (;;)
DH_DbgPrint(MID_TRACE,("DHCPCSVC: Failed to receive a response from a DHCP server\n"));
if ((Adapter->AlternateConfiguration != NULL) &&
(Adapter->AlternateConfiguration->IpAddress != 0))
{
address_low = rand();
for (i = 0; i < ip->hw_address.hlen; i++)
address_low += ip->hw_address.haddr[i];
/* Use the alternate configuration */
DH_DbgPrint(MID_TRACE,("DHCPCSVC: The alternate configuration will be used.\n"));
IpAddress = htonl(0xA9FE0000 | address_low); // 169.254.X.X
/* IPAddress & SubnetMask */
Status = AddIPAddress(htonl(Adapter->AlternateConfiguration->IpAddress),
htonl(Adapter->AlternateConfiguration->SubnetMask),
Adapter->IfMib.dwIndex,
&Adapter->NteContext,
&Adapter->NteInstance);
if (!NT_SUCCESS(Status))
DH_DbgPrint(MID_TRACE,("AddIPAddress: %lx\n", Status));
/* Send an ARP request to check if the IP address is already in use */
BufferSize = sizeof(Buffer);
ret = SendARP(IpAddress,
IpAddress,
Buffer,
&BufferSize);
DH_DbgPrint(MID_TRACE,("DHCPCSVC: SendARP returned %lu\n", ret));
if (ret != 0)
/* DefaultGateway */
if (Adapter->AlternateConfiguration->DefaultGateway != 0)
{
/* The IP address is not in use */
DH_DbgPrint(MID_TRACE,("DHCPCSVC: Using automatic private address\n"));
AddIPAddress(IpAddress,
htonl(0xFFFF0000), // 255.255.0.0
Adapter->IfMib.dwIndex,
&Adapter->NteContext,
&Adapter->NteInstance);
return;
Adapter->RouterMib.dwForwardDest = 0; /* Default route */
Adapter->RouterMib.dwForwardMask = 0;
Adapter->RouterMib.dwForwardMetric1 = 1;
Adapter->RouterMib.dwForwardIfIndex = Adapter->IfMib.dwIndex;
if (Adapter->RouterMib.dwForwardNextHop)
{
/* If we set a default route before, delete it before continuing */
DeleteIpForwardEntry(&Adapter->RouterMib);
}
Adapter->RouterMib.dwForwardNextHop = htonl(Adapter->AlternateConfiguration->DefaultGateway);
Status = CreateIpForwardEntry(&Adapter->RouterMib);
if (!NT_SUCCESS(Status))
DH_DbgPrint(MID_TRACE,("CreateIpForwardEntry: %lx\n", Status));
}
if (hKey)
{
addr.S_un.S_addr = htonl(Adapter->AlternateConfiguration->IpAddress);
RtlIpv4AddressToStringA(&addr, AddressBuffer);
RegSetValueExA(hKey, "DhcpIPAddress", 0, REG_SZ, (LPBYTE)AddressBuffer, strlen(AddressBuffer) + 1);
addr.S_un.S_addr = htonl(Adapter->AlternateConfiguration->SubnetMask);
RtlIpv4AddressToStringA(&addr, AddressBuffer);
RegSetValueExA(hKey, "DhcpSubnetMask", 0, REG_SZ, (LPBYTE)AddressBuffer, strlen(AddressBuffer) + 1);
if (Adapter->AlternateConfiguration->DefaultGateway != 0)
{
addr.S_un.S_addr = htonl(Adapter->AlternateConfiguration->DefaultGateway);
RtlIpv4AddressToStringA(&addr, AddressBuffer);
RegSetValueExA(hKey, "DhcpDefaultGateway", 0, REG_SZ, (LPBYTE)AddressBuffer, strlen(AddressBuffer) + 1);
}
else
{
RegDeleteValueA(hKey, "DhcpDefaultGateway");
}
RegSetValueExA(hKey, "DhcpServer", 0, REG_SZ, (LPBYTE)Server, strlen(Server) + 1);
RegDeleteValueA(hKey, "DhcpDomain");
if (Adapter->AlternateConfiguration->DnsServer1 != 0)
{
char *pPtr;
addr.S_un.S_addr = htonl(Adapter->AlternateConfiguration->DnsServer1);
pPtr = RtlIpv4AddressToStringA(&addr, AddressBuffer);
if (Adapter->AlternateConfiguration->DnsServer2 != 0)
{
*pPtr = ' ';
pPtr++;
addr.S_un.S_addr = htonl(Adapter->AlternateConfiguration->DnsServer2);
RtlIpv4AddressToStringA(&addr, pPtr);
}
RegSetValueExA(hKey, "DhcpNameServer", 0, REG_SZ, (LPBYTE)AddressBuffer, strlen(AddressBuffer) + 1);
}
else
{
RegDeleteValueA(hKey, "DhcpNameServer");
}
RegDeleteValueA(hKey, "IPAutoconfigurationAddress");
RegDeleteValueA(hKey, "IPAutoconfigurationMask");
RegSetValueExA(hKey, "Lease", 0, REG_DWORD, (LPBYTE)&lease, sizeof(DWORD));
RegSetValueExA(hKey, "LeaseObtainedTime", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD));
RegSetValueExA(hKey, "LeaseTerminatesTime", 0, REG_DWORD, (LPBYTE)&never_time, sizeof(DWORD));
RegSetValueExA(hKey, "T1", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD));
RegSetValueExA(hKey, "T2", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD));
}
}
else
{
/* Generate an automatic private address */
DH_DbgPrint(MID_TRACE,("DHCPCSVC: An automatic private address will be assigned.\n"));
/* FIXME: The address generation code sucks */
srand(0);
for (;;)
{
address_low = rand();
for (i = 0; i < ip->hw_address.hlen; i++)
address_low += ip->hw_address.haddr[i];
IpAddress = htonl(0xA9FE0000 | address_low); // 169.254.X.X
/* Send an ARP request to check if the IP address is already in use */
BufferSize = sizeof(Buffer);
ret = SendARP(IpAddress,
IpAddress,
Buffer,
&BufferSize);
DH_DbgPrint(MID_TRACE,("DHCPCSVC: SendARP returned %lu\n", ret));
if (ret != 0)
{
/* The IP address is not in use */
DH_DbgPrint(MID_TRACE,("DHCPCSVC: Using automatic private address\n"));
Status = AddIPAddress(IpAddress,
htonl(0xFFFF0000), // 255.255.0.0
Adapter->IfMib.dwIndex,
&Adapter->NteContext,
&Adapter->NteInstance);
if (!NT_SUCCESS(Status))
DH_DbgPrint(MID_TRACE,("AddIPAddress: %lx\n", Status));
if (hKey)
{
addr.S_un.S_addr = IpAddress;
RtlIpv4AddressToStringA(&addr, AddressBuffer);
RegSetValueExA(hKey, "DhcpIPAddress", 0, REG_SZ, (LPBYTE)AddressBuffer, strlen(AddressBuffer) + 1);
RegSetValueExA(hKey, "DhcpSubnetMask", 0, REG_SZ, (LPBYTE)SubnetMask, strlen(SubnetMask) + 1);
RegSetValueExA(hKey, "DhcpServer", 0, REG_SZ, (LPBYTE)Server, strlen(Server) + 1);
RegDeleteValueA(hKey, "DhcpDefaultGateway");
RegDeleteValueA(hKey, "DhcpDomain");
RegDeleteValueA(hKey, "DhcpNameServer");
RegSetValueExA(hKey, "IPAutoconfigurationAddress", 0, REG_SZ, (LPBYTE)AddressBuffer, strlen(AddressBuffer) + 1);
RegSetValueExA(hKey, "IPAutoconfigurationMask", 0, REG_SZ, (LPBYTE)SubnetMask, strlen(SubnetMask) + 1);
RegSetValueExA(hKey, "Lease", 0, REG_DWORD, (LPBYTE)&lease, sizeof(DWORD));
RegSetValueExA(hKey, "LeaseObtainedTime", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD));
RegSetValueExA(hKey, "LeaseTerminatesTime", 0, REG_DWORD, (LPBYTE)&never_time, sizeof(DWORD));
RegSetValueExA(hKey, "T1", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD));
RegSetValueExA(hKey, "T2", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD));
}
goto done;
}
}
}
}
done:
if (hKey)
RegCloseKey(hKey);
}
void