reactos/base/services/dhcp/adapter.c
Timo Kreuzer 6afbc8f483 Hopefully create a branch and not destroy the svn repository.
svn path=/branches/reactos-yarotows/; revision=45219
2010-01-23 23:25:04 +00:00

446 lines
15 KiB
C

#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) {
}