#include "rosdhcp.h" static SOCKET DhcpSocket = INVALID_SOCKET; static LIST_ENTRY AdapterList; static WSADATA wsd; PCHAR *GetSubkeyNames( PCHAR MainKeyName, PCHAR Append ) { int i = 0; DWORD Error; HKEY MainKey; PCHAR *Out, OutKeyName; DWORD CharTotal = 0, AppendLen = 1 + strlen(Append); DWORD MaxSubKeyLen = 0, MaxSubKeys = 0; Error = RegOpenKey( HKEY_LOCAL_MACHINE, MainKeyName, &MainKey ); if( Error ) return NULL; Error = RegQueryInfoKey ( MainKey, NULL, NULL, NULL, &MaxSubKeys, &MaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL ); DH_DbgPrint(MID_TRACE,("MaxSubKeys: %d, MaxSubKeyLen %d\n", MaxSubKeys, MaxSubKeyLen)); CharTotal = (sizeof(PCHAR) + MaxSubKeyLen + AppendLen) * (MaxSubKeys + 1); DH_DbgPrint(MID_TRACE,("AppendLen: %d, CharTotal: %d\n", AppendLen, CharTotal)); Out = (CHAR**) malloc( CharTotal ); OutKeyName = ((PCHAR)&Out[MaxSubKeys+1]); if( !Out ) { RegCloseKey( MainKey ); return NULL; } i = 0; do { Out[i] = OutKeyName; Error = RegEnumKey( MainKey, i, OutKeyName, MaxSubKeyLen ); if( !Error ) { strcat( OutKeyName, Append ); DH_DbgPrint(MID_TRACE,("[%d]: %s\n", i, OutKeyName)); OutKeyName += strlen(OutKeyName) + 1; i++; } else Out[i] = 0; } while( Error == ERROR_SUCCESS ); RegCloseKey( MainKey ); return Out; } PCHAR RegReadString( HKEY Root, PCHAR Subkey, PCHAR Value ) { PCHAR SubOut = NULL; DWORD SubOutLen = 0, Error = 0; HKEY ValueKey = NULL; DH_DbgPrint(MID_TRACE,("Looking in %x:%s:%s\n", Root, Subkey, Value )); if( Subkey && strlen(Subkey) ) { if( RegOpenKey( Root, Subkey, &ValueKey ) != ERROR_SUCCESS ) goto regerror; } else ValueKey = Root; DH_DbgPrint(MID_TRACE,("Got Key %x\n", ValueKey)); if( (Error = RegQueryValueEx( ValueKey, Value, NULL, NULL, (LPBYTE)SubOut, &SubOutLen )) != ERROR_SUCCESS ) goto regerror; DH_DbgPrint(MID_TRACE,("Value %s has size %d\n", Value, SubOutLen)); if( !(SubOut = (CHAR*) malloc(SubOutLen)) ) goto regerror; if( (Error = RegQueryValueEx( ValueKey, Value, NULL, NULL, (LPBYTE)SubOut, &SubOutLen )) != ERROR_SUCCESS ) goto regerror; DH_DbgPrint(MID_TRACE,("Value %s is %s\n", Value, SubOut)); goto cleanup; regerror: if( SubOut ) { free( SubOut ); SubOut = NULL; } cleanup: if( ValueKey && ValueKey != Root ) { DH_DbgPrint(MID_TRACE,("Closing key %x\n", ValueKey)); RegCloseKey( ValueKey ); } DH_DbgPrint(MID_TRACE,("Returning %x with error %d\n", SubOut, Error)); return SubOut; } HKEY FindAdapterKey( PDHCP_ADAPTER Adapter ) { int i = 0; PCHAR EnumKeyName = "SYSTEM\\CurrentControlSet\\Control\\Class\\" "{4D36E972-E325-11CE-BFC1-08002BE10318}"; PCHAR TargetKeyNameStart = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"; PCHAR TargetKeyName = NULL; PCHAR *EnumKeysLinkage = GetSubkeyNames( EnumKeyName, "\\Linkage" ); PCHAR *EnumKeysTop = GetSubkeyNames( EnumKeyName, "" ); PCHAR RootDevice = NULL; HKEY EnumKey, OutKey = NULL; DWORD Error = ERROR_SUCCESS; if( !EnumKeysLinkage || !EnumKeysTop ) goto cleanup; Error = RegOpenKey( HKEY_LOCAL_MACHINE, EnumKeyName, &EnumKey ); if( Error ) goto cleanup; for( i = 0; EnumKeysLinkage[i]; i++ ) { RootDevice = RegReadString ( EnumKey, EnumKeysLinkage[i], "RootDevice" ); if( RootDevice && !strcmp( RootDevice, Adapter->DhclientInfo.name ) ) { TargetKeyName = (CHAR*) malloc( strlen( TargetKeyNameStart ) + strlen( RootDevice ) + 1); if( !TargetKeyName ) goto cleanup; sprintf( TargetKeyName, "%s%s", TargetKeyNameStart, RootDevice ); Error = RegCreateKeyExA( HKEY_LOCAL_MACHINE, TargetKeyName, 0, NULL, 0, KEY_READ, NULL, &OutKey, NULL ); break; } else { free( RootDevice ); RootDevice = 0; } } cleanup: if( RootDevice ) free( RootDevice ); if( EnumKeysLinkage ) free( EnumKeysLinkage ); if( EnumKeysTop ) free( EnumKeysTop ); if( TargetKeyName ) free( TargetKeyName ); return OutKey; } BOOL PrepareAdapterForService( PDHCP_ADAPTER Adapter ) { HKEY AdapterKey = NULL; PCHAR IPAddress = NULL, Netmask = NULL, DefaultGateway = NULL; NTSTATUS Status = STATUS_SUCCESS; DWORD Error = ERROR_SUCCESS; Adapter->DhclientState.config = &Adapter->DhclientConfig; strncpy(Adapter->DhclientInfo.name, (char*)Adapter->IfMib.bDescr, sizeof(Adapter->DhclientInfo.name)); AdapterKey = FindAdapterKey( Adapter ); if( AdapterKey ) IPAddress = RegReadString( AdapterKey, NULL, "IPAddress" ); if( IPAddress && strcmp( IPAddress, "0.0.0.0" ) ) { /* Non-automatic case */ DH_DbgPrint (MID_TRACE,("Adapter Name: [%s] (Bind Status %x) (static %s)\n", Adapter->DhclientInfo.name, Adapter->BindStatus, IPAddress)); Adapter->DhclientState.state = S_STATIC; Netmask = RegReadString( AdapterKey, NULL, "Subnetmask" ); Status = AddIPAddress( inet_addr( IPAddress ), inet_addr( Netmask ? Netmask : "255.255.255.0" ), Adapter->IfMib.dwIndex, &Adapter->NteContext, &Adapter->NteInstance ); DefaultGateway = RegReadString( AdapterKey, NULL, "DefaultGateway" ); if( DefaultGateway ) { Adapter->RouterMib.dwForwardDest = 0; Adapter->RouterMib.dwForwardMask = 0; Adapter->RouterMib.dwForwardMetric1 = 1; Adapter->RouterMib.dwForwardIfIndex = Adapter->IfMib.dwIndex; Adapter->RouterMib.dwForwardNextHop = inet_addr(DefaultGateway); Error = CreateIpForwardEntry( &Adapter->RouterMib ); if( Error ) warning("Failed to set default gateway %s: %ld\n", DefaultGateway, Error); } if( DefaultGateway ) free( DefaultGateway ); if( Netmask ) free( Netmask ); } else { /* Automatic case */ DH_DbgPrint (MID_TRACE,("Adapter Name: [%s] (Bind Status %x) (dynamic)\n", Adapter->DhclientInfo.name, Adapter->BindStatus)); Adapter->DhclientInfo.client->state = S_INIT; } if( IPAddress ) free( IPAddress ); return TRUE; } void AdapterInit() { WSAStartup(0x0101,&wsd); InitializeListHead( &AdapterList ); } int InterfaceConnected(MIB_IFROW IfEntry) { if (IfEntry.dwOperStatus == IF_OPER_STATUS_CONNECTED || IfEntry.dwOperStatus == IF_OPER_STATUS_OPERATIONAL) return 1; DH_DbgPrint(MID_TRACE,("Interface %d is down\n", IfEntry.dwIndex)); return 0; } /* * XXX Figure out the way to bind a specific adapter to a socket. */ BOOLEAN AdapterDiscover() { PMIB_IFTABLE Table = (PMIB_IFTABLE) malloc(sizeof(MIB_IFTABLE)); DWORD Error, Size = sizeof(MIB_IFTABLE); PDHCP_ADAPTER Adapter = NULL; struct interface_info *ifi = NULL; int i; BOOLEAN ret = TRUE; DH_DbgPrint(MID_TRACE,("Getting Adapter List...\n")); while( (Error = GetIfTable(Table, &Size, 0 )) == ERROR_INSUFFICIENT_BUFFER ) { DH_DbgPrint(MID_TRACE,("Error %d, New Buffer Size: %d\n", Error, Size)); free( Table ); Table = (PMIB_IFTABLE) malloc( Size ); } if( Error != NO_ERROR ) { ret = FALSE; goto term; } DH_DbgPrint(MID_TRACE,("Got Adapter List (%d entries)\n", Table->dwNumEntries)); for( i = Table->dwNumEntries - 1; i >= 0; i-- ) { DH_DbgPrint(MID_TRACE,("Getting adapter %d attributes\n", Table->table[i].dwIndex)); if ((Adapter = AdapterFindByHardwareAddress(Table->table[i].bPhysAddr, Table->table[i].dwPhysAddrLen))) { /* This is an existing adapter */ if (InterfaceConnected(Table->table[i])) { /* We're still active so we stay in the list */ ifi = &Adapter->DhclientInfo; } else { /* We've lost our link so out we go */ RemoveEntryList(&Adapter->ListEntry); free(Adapter); } continue; } Adapter = (DHCP_ADAPTER*) calloc( sizeof( DHCP_ADAPTER ) + Table->table[i].dwMtu, 1 ); if( Adapter && Table->table[i].dwType == MIB_IF_TYPE_ETHERNET && InterfaceConnected(Table->table[i])) { memcpy( &Adapter->IfMib, &Table->table[i], sizeof(Adapter->IfMib) ); Adapter->DhclientInfo.client = &Adapter->DhclientState; Adapter->DhclientInfo.rbuf = Adapter->recv_buf; Adapter->DhclientInfo.rbuf_max = Table->table[i].dwMtu; Adapter->DhclientInfo.rbuf_len = Adapter->DhclientInfo.rbuf_offset = 0; memcpy(Adapter->DhclientInfo.hw_address.haddr, Adapter->IfMib.bPhysAddr, Adapter->IfMib.dwPhysAddrLen); Adapter->DhclientInfo.hw_address.hlen = Adapter->IfMib.dwPhysAddrLen; /* I'm not sure where else to set this, but some DHCP servers won't take a zero. We checked the hardware type earlier in the if statement. */ Adapter->DhclientInfo.hw_address.htype = HTYPE_ETHER; if( DhcpSocket == INVALID_SOCKET ) { DhcpSocket = Adapter->DhclientInfo.rfdesc = Adapter->DhclientInfo.wfdesc = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); if (DhcpSocket != INVALID_SOCKET) { Adapter->ListenAddr.sin_family = AF_INET; Adapter->ListenAddr.sin_port = htons(LOCAL_PORT); Adapter->BindStatus = (bind( Adapter->DhclientInfo.rfdesc, (struct sockaddr *)&Adapter->ListenAddr, sizeof(Adapter->ListenAddr) ) == 0) ? 0 : WSAGetLastError(); } else { error("socket() failed: %d\n", WSAGetLastError()); } } else { Adapter->DhclientInfo.rfdesc = Adapter->DhclientInfo.wfdesc = DhcpSocket; } Adapter->DhclientConfig.timeout = DHCP_PANIC_TIMEOUT; Adapter->DhclientConfig.initial_interval = DHCP_DISCOVER_INTERVAL; Adapter->DhclientConfig.retry_interval = DHCP_DISCOVER_INTERVAL; Adapter->DhclientConfig.select_interval = 1; Adapter->DhclientConfig.reboot_timeout = DHCP_REBOOT_TIMEOUT; Adapter->DhclientConfig.backoff_cutoff = DHCP_BACKOFF_MAX; Adapter->DhclientState.interval = Adapter->DhclientConfig.retry_interval; if( PrepareAdapterForService( Adapter ) ) { Adapter->DhclientInfo.next = ifi; ifi = &Adapter->DhclientInfo; read_client_conf(&Adapter->DhclientInfo); if (Adapter->DhclientInfo.client->state == S_INIT) { add_protocol(Adapter->DhclientInfo.name, Adapter->DhclientInfo.rfdesc, got_one, &Adapter->DhclientInfo); state_init(&Adapter->DhclientInfo); } InsertTailList( &AdapterList, &Adapter->ListEntry ); } else { free( Adapter ); Adapter = 0; } } else { free( Adapter ); Adapter = 0; } if( !Adapter ) DH_DbgPrint(MID_TRACE,("Adapter %d was rejected\n", Table->table[i].dwIndex)); } DH_DbgPrint(MID_TRACE,("done with AdapterInit\n")); term: if( Table ) free( Table ); return ret; } void AdapterStop() { PLIST_ENTRY ListEntry; PDHCP_ADAPTER Adapter; while( !IsListEmpty( &AdapterList ) ) { ListEntry = (PLIST_ENTRY)RemoveHeadList( &AdapterList ); Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry ); free( Adapter ); } WSACleanup(); } PDHCP_ADAPTER AdapterFindIndex( unsigned int indx ) { PDHCP_ADAPTER Adapter; PLIST_ENTRY ListEntry; for( ListEntry = AdapterList.Flink; ListEntry != &AdapterList; ListEntry = ListEntry->Flink ) { Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry ); if( Adapter->IfMib.dwIndex == indx ) return Adapter; } return NULL; } PDHCP_ADAPTER AdapterFindName( const WCHAR *name ) { PDHCP_ADAPTER Adapter; PLIST_ENTRY ListEntry; for( ListEntry = AdapterList.Flink; ListEntry != &AdapterList; ListEntry = ListEntry->Flink ) { Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry ); if( !wcsicmp( Adapter->IfMib.wszName, name ) ) return Adapter; } return NULL; } PDHCP_ADAPTER AdapterFindInfo( struct interface_info *ip ) { PDHCP_ADAPTER Adapter; PLIST_ENTRY ListEntry; for( ListEntry = AdapterList.Flink; ListEntry != &AdapterList; ListEntry = ListEntry->Flink ) { Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry ); if( ip == &Adapter->DhclientInfo ) return Adapter; } return NULL; } PDHCP_ADAPTER AdapterFindByHardwareAddress( u_int8_t haddr[16], u_int8_t hlen ) { PDHCP_ADAPTER Adapter; PLIST_ENTRY ListEntry; for(ListEntry = AdapterList.Flink; ListEntry != &AdapterList; ListEntry = ListEntry->Flink) { Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry ); if (Adapter->DhclientInfo.hw_address.hlen == hlen && !memcmp(Adapter->DhclientInfo.hw_address.haddr, haddr, hlen)) return Adapter; } return NULL; } PDHCP_ADAPTER AdapterGetFirst() { if( IsListEmpty( &AdapterList ) ) return NULL; else { return CONTAINING_RECORD ( AdapterList.Flink, DHCP_ADAPTER, ListEntry ); } } PDHCP_ADAPTER AdapterGetNext( PDHCP_ADAPTER This ) { if( This->ListEntry.Flink == &AdapterList ) return NULL; return CONTAINING_RECORD ( This->ListEntry.Flink, DHCP_ADAPTER, ListEntry ); } void if_register_send(struct interface_info *ip) { } void if_register_receive(struct interface_info *ip) { }