3 SOCKET DhcpSocket
= INVALID_SOCKET
;
4 static LIST_ENTRY AdapterList
;
7 PCHAR
*GetSubkeyNames( PCHAR MainKeyName
, PCHAR Append
) {
11 PCHAR
*Out
, OutKeyName
;
12 DWORD CharTotal
= 0, AppendLen
= 1 + strlen(Append
);
13 DWORD MaxSubKeyLen
= 0, MaxSubKeys
= 0;
15 Error
= RegOpenKey( HKEY_LOCAL_MACHINE
, MainKeyName
, &MainKey
);
17 if( Error
) return NULL
;
19 Error
= RegQueryInfoKey
22 &MaxSubKeys
, &MaxSubKeyLen
,
23 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
26 DH_DbgPrint(MID_TRACE
,("MaxSubKeys: %d, MaxSubKeyLen %d\n",
27 MaxSubKeys
, MaxSubKeyLen
));
29 CharTotal
= (sizeof(PCHAR
) + MaxSubKeyLen
+ AppendLen
) * (MaxSubKeys
+ 1);
31 DH_DbgPrint(MID_TRACE
,("AppendLen: %d, CharTotal: %d\n",
32 AppendLen
, CharTotal
));
34 Out
= (CHAR
**) malloc( CharTotal
);
35 OutKeyName
= ((PCHAR
)&Out
[MaxSubKeys
+1]);
37 if( !Out
) { RegCloseKey( MainKey
); return NULL
; }
42 Error
= RegEnumKey( MainKey
, i
, OutKeyName
, MaxSubKeyLen
);
44 strcat( OutKeyName
, Append
);
45 DH_DbgPrint(MID_TRACE
,("[%d]: %s\n", i
, OutKeyName
));
46 OutKeyName
+= strlen(OutKeyName
) + 1;
49 } while( Error
== ERROR_SUCCESS
);
51 RegCloseKey( MainKey
);
56 PCHAR
RegReadString( HKEY Root
, PCHAR Subkey
, PCHAR Value
) {
58 DWORD SubOutLen
= 0, Error
= 0;
61 DH_DbgPrint(MID_TRACE
,("Looking in %x:%s:%s\n", Root
, Subkey
, Value
));
63 if( Subkey
&& strlen(Subkey
) ) {
64 if( RegOpenKey( Root
, Subkey
, &ValueKey
) != ERROR_SUCCESS
)
66 } else ValueKey
= Root
;
68 DH_DbgPrint(MID_TRACE
,("Got Key %x\n", ValueKey
));
70 if( (Error
= RegQueryValueEx( ValueKey
, Value
, NULL
, NULL
,
71 (LPBYTE
)SubOut
, &SubOutLen
)) != ERROR_SUCCESS
)
74 DH_DbgPrint(MID_TRACE
,("Value %s has size %d\n", Value
, SubOutLen
));
76 if( !(SubOut
= (CHAR
*) malloc(SubOutLen
)) )
79 if( (Error
= RegQueryValueEx( ValueKey
, Value
, NULL
, NULL
,
80 (LPBYTE
)SubOut
, &SubOutLen
)) != ERROR_SUCCESS
)
83 DH_DbgPrint(MID_TRACE
,("Value %s is %s\n", Value
, SubOut
));
88 if( SubOut
) { free( SubOut
); SubOut
= NULL
; }
90 if( ValueKey
&& ValueKey
!= Root
) {
91 DH_DbgPrint(MID_TRACE
,("Closing key %x\n", ValueKey
));
92 RegCloseKey( ValueKey
);
95 DH_DbgPrint(MID_TRACE
,("Returning %x with error %d\n", SubOut
, Error
));
100 HKEY
FindAdapterKey( PDHCP_ADAPTER Adapter
) {
103 "SYSTEM\\CurrentControlSet\\Control\\Class\\"
104 "{4D36E972-E325-11CE-BFC1-08002BE10318}";
105 PCHAR TargetKeyNameStart
=
106 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
107 PCHAR TargetKeyName
= NULL
;
108 PCHAR
*EnumKeysLinkage
= GetSubkeyNames( EnumKeyName
, "\\Linkage" );
109 PCHAR
*EnumKeysTop
= GetSubkeyNames( EnumKeyName
, "" );
110 PCHAR RootDevice
= NULL
;
111 HKEY EnumKey
, OutKey
= NULL
;
112 DWORD Error
= ERROR_SUCCESS
;
114 if( !EnumKeysLinkage
|| !EnumKeysTop
) goto cleanup
;
116 Error
= RegOpenKey( HKEY_LOCAL_MACHINE
, EnumKeyName
, &EnumKey
);
118 if( Error
) goto cleanup
;
120 for( i
= 0; EnumKeysLinkage
[i
]; i
++ ) {
121 RootDevice
= RegReadString
122 ( EnumKey
, EnumKeysLinkage
[i
], "RootDevice" );
125 !strcmp( RootDevice
, Adapter
->DhclientInfo
.name
) ) {
127 (CHAR
*) malloc( strlen( TargetKeyNameStart
) +
128 strlen( RootDevice
) + 1);
129 if( !TargetKeyName
) goto cleanup
;
130 sprintf( TargetKeyName
, "%s%s",
131 TargetKeyNameStart
, RootDevice
);
132 Error
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, TargetKeyName
, 0, NULL
, 0, KEY_READ
, NULL
, &OutKey
, NULL
);
135 free( RootDevice
); RootDevice
= 0;
140 if( RootDevice
) free( RootDevice
);
141 if( EnumKeysLinkage
) free( EnumKeysLinkage
);
142 if( EnumKeysTop
) free( EnumKeysTop
);
143 if( TargetKeyName
) free( TargetKeyName
);
148 BOOL
PrepareAdapterForService( PDHCP_ADAPTER Adapter
) {
150 DWORD Error
= ERROR_SUCCESS
, DhcpEnabled
, Length
= sizeof(DWORD
);
152 Adapter
->DhclientState
.config
= &Adapter
->DhclientConfig
;
153 strncpy(Adapter
->DhclientInfo
.name
, (char*)Adapter
->IfMib
.bDescr
,
154 sizeof(Adapter
->DhclientInfo
.name
));
156 AdapterKey
= FindAdapterKey( Adapter
);
159 Error
= RegQueryValueEx(AdapterKey
, "EnableDHCP", NULL
, NULL
, (LPBYTE
)&DhcpEnabled
, &Length
);
161 if (Error
!= ERROR_SUCCESS
|| Length
!= sizeof(DWORD
))
164 CloseHandle(AdapterKey
);
168 /* DHCP enabled by default */
173 /* Non-automatic case */
174 DbgPrint("DHCPCSVC: Adapter Name: [%s] (static)\n", Adapter
->DhclientInfo
.name
);
176 Adapter
->DhclientState
.state
= S_STATIC
;
179 DbgPrint("DHCPCSVC: Adapter Name: [%s] (dynamic)\n", Adapter
->DhclientInfo
.name
);
181 Adapter
->DhclientInfo
.client
->state
= S_INIT
;
188 WSAStartup(0x0101,&wsd
);
190 InitializeListHead( &AdapterList
);
194 InterfaceConnected(const MIB_IFROW
* IfEntry
)
196 if (IfEntry
->dwOperStatus
== IF_OPER_STATUS_CONNECTED
||
197 IfEntry
->dwOperStatus
== IF_OPER_STATUS_OPERATIONAL
)
200 DH_DbgPrint(MID_TRACE
,("Interface %d is down\n", IfEntry
->dwIndex
));
205 IsReconnectHackNeeded(PDHCP_ADAPTER Adapter
, const MIB_IFROW
* IfEntry
)
207 struct protocol
*proto
;
208 PIP_ADAPTER_INFO AdapterInfo
, Orig
;
210 char *ZeroAddress
= "0.0.0.0";
212 proto
= find_protocol_by_adapter(&Adapter
->DhclientInfo
);
214 if (Adapter
->DhclientInfo
.client
->state
== S_BOUND
&& !proto
)
217 if (Adapter
->DhclientInfo
.client
->state
!= S_BOUND
&&
218 Adapter
->DhclientInfo
.client
->state
!= S_STATIC
)
223 Orig
= AdapterInfo
= HeapAlloc(GetProcessHeap(), 0, sizeof(IP_ADAPTER_INFO
));
224 Size
= sizeof(IP_ADAPTER_INFO
);
231 Ret
= GetAdaptersInfo(AdapterInfo
, &Size
);
232 if (Ret
== ERROR_BUFFER_OVERFLOW
)
234 HeapFree(GetProcessHeap(), 0, AdapterInfo
);
235 AdapterInfo
= HeapAlloc(GetProcessHeap(), 0, Size
);
242 if (GetAdaptersInfo(AdapterInfo
, &Size
) != NO_ERROR
)
249 for (; AdapterInfo
!= NULL
; AdapterInfo
= AdapterInfo
->Next
)
251 if (AdapterInfo
->Index
== IfEntry
->dwIndex
)
255 if (AdapterInfo
== NULL
)
257 HeapFree(GetProcessHeap(), 0, Orig
);
262 else if (Ret
!= NO_ERROR
)
264 HeapFree(GetProcessHeap(), 0, Orig
);
269 if (!strcmp(AdapterInfo
->IpAddressList
.IpAddress
.String
, ZeroAddress
))
271 HeapFree(GetProcessHeap(), 0, Orig
);
277 HeapFree(GetProcessHeap(), 0, Orig
);
284 * XXX Figure out the way to bind a specific adapter to a socket.
286 DWORD WINAPI
AdapterDiscoveryThread(LPVOID Context
) {
287 PMIB_IFTABLE Table
= (PMIB_IFTABLE
) malloc(sizeof(MIB_IFTABLE
));
288 DWORD Error
, Size
= sizeof(MIB_IFTABLE
);
289 PDHCP_ADAPTER Adapter
= NULL
;
290 HANDLE AdapterStateChangedEvent
= (HANDLE
)Context
;
291 struct interface_info
*ifi
= NULL
;
292 struct protocol
*proto
;
293 int i
, AdapterCount
= 0, Broadcast
;
295 /* FIXME: Kill this thread when the service is stopped */
298 DH_DbgPrint(MID_TRACE
,("Getting Adapter List...\n"));
300 while( (Error
= GetIfTable(Table
, &Size
, 0 )) ==
301 ERROR_INSUFFICIENT_BUFFER
) {
302 DH_DbgPrint(MID_TRACE
,("Error %d, New Buffer Size: %d\n", Error
, Size
));
304 Table
= (PMIB_IFTABLE
) malloc( Size
);
307 if( Error
!= NO_ERROR
)
309 /* HACK: We are waiting until TCP/IP starts */
314 DH_DbgPrint(MID_TRACE
,("Got Adapter List (%d entries)\n", Table
->dwNumEntries
));
316 for( i
= Table
->dwNumEntries
- 1; i
>= 0; i
-- ) {
317 DH_DbgPrint(MID_TRACE
,("Getting adapter %d attributes\n",
318 Table
->table
[i
].dwIndex
));
322 if ((Adapter
= AdapterFindByHardwareAddress(Table
->table
[i
].bPhysAddr
, Table
->table
[i
].dwPhysAddrLen
)))
324 proto
= find_protocol_by_adapter(&Adapter
->DhclientInfo
);
326 /* This is an existing adapter */
327 if (InterfaceConnected(&Table
->table
[i
])) {
328 /* We're still active so we stay in the list */
329 ifi
= &Adapter
->DhclientInfo
;
331 /* This is a hack because IP helper API sucks */
332 if (IsReconnectHackNeeded(Adapter
, &Table
->table
[i
]))
334 /* This handles a disconnect/reconnect */
337 remove_protocol(proto
);
338 Adapter
->DhclientInfo
.client
->state
= S_INIT
;
340 /* These are already invalid since the media state change */
341 Adapter
->RouterMib
.dwForwardNextHop
= 0;
342 Adapter
->NteContext
= 0;
344 add_protocol(Adapter
->DhclientInfo
.name
,
345 Adapter
->DhclientInfo
.rfdesc
,
346 got_one
, &Adapter
->DhclientInfo
);
347 state_init(&Adapter
->DhclientInfo
);
349 SetEvent(AdapterStateChangedEvent
);
354 remove_protocol(proto
);
356 /* We've lost our link so out we go */
357 RemoveEntryList(&Adapter
->ListEntry
);
368 Adapter
= (DHCP_ADAPTER
*) calloc( sizeof( DHCP_ADAPTER
) + Table
->table
[i
].dwMtu
, 1 );
370 if( Adapter
&& Table
->table
[i
].dwType
== MIB_IF_TYPE_ETHERNET
&& InterfaceConnected(&Table
->table
[i
])) {
371 memcpy( &Adapter
->IfMib
, &Table
->table
[i
],
372 sizeof(Adapter
->IfMib
) );
373 Adapter
->DhclientInfo
.client
= &Adapter
->DhclientState
;
374 Adapter
->DhclientInfo
.rbuf
= Adapter
->recv_buf
;
375 Adapter
->DhclientInfo
.rbuf_max
= Table
->table
[i
].dwMtu
;
376 Adapter
->DhclientInfo
.rbuf_len
=
377 Adapter
->DhclientInfo
.rbuf_offset
= 0;
378 memcpy(Adapter
->DhclientInfo
.hw_address
.haddr
,
379 Adapter
->IfMib
.bPhysAddr
,
380 Adapter
->IfMib
.dwPhysAddrLen
);
381 Adapter
->DhclientInfo
.hw_address
.hlen
= Adapter
->IfMib
.dwPhysAddrLen
;
383 /* I'm not sure where else to set this, but
384 some DHCP servers won't take a zero.
385 We checked the hardware type earlier in
387 Adapter
->DhclientInfo
.hw_address
.htype
= HTYPE_ETHER
;
389 if( DhcpSocket
== INVALID_SOCKET
) {
391 Adapter
->DhclientInfo
.rfdesc
=
392 Adapter
->DhclientInfo
.wfdesc
=
393 socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
395 if (DhcpSocket
!= INVALID_SOCKET
) {
397 /* Allow broadcast on this socket */
399 setsockopt(DhcpSocket
,
402 (const char *)&Broadcast
,
405 Adapter
->ListenAddr
.sin_family
= AF_INET
;
406 Adapter
->ListenAddr
.sin_port
= htons(LOCAL_PORT
);
407 Adapter
->BindStatus
=
408 (bind( Adapter
->DhclientInfo
.rfdesc
,
409 (struct sockaddr
*)&Adapter
->ListenAddr
,
410 sizeof(Adapter
->ListenAddr
) ) == 0) ?
411 0 : WSAGetLastError();
413 error("socket() failed: %d\n", WSAGetLastError());
416 Adapter
->DhclientInfo
.rfdesc
=
417 Adapter
->DhclientInfo
.wfdesc
= DhcpSocket
;
420 Adapter
->DhclientConfig
.timeout
= DHCP_PANIC_TIMEOUT
;
421 Adapter
->DhclientConfig
.initial_interval
= DHCP_DISCOVER_INTERVAL
;
422 Adapter
->DhclientConfig
.retry_interval
= DHCP_DISCOVER_INTERVAL
;
423 Adapter
->DhclientConfig
.select_interval
= 1;
424 Adapter
->DhclientConfig
.reboot_timeout
= DHCP_REBOOT_TIMEOUT
;
425 Adapter
->DhclientConfig
.backoff_cutoff
= DHCP_BACKOFF_MAX
;
426 Adapter
->DhclientState
.interval
=
427 Adapter
->DhclientConfig
.retry_interval
;
429 if( PrepareAdapterForService( Adapter
) ) {
430 Adapter
->DhclientInfo
.next
= ifi
;
431 ifi
= &Adapter
->DhclientInfo
;
433 read_client_conf(&Adapter
->DhclientInfo
);
435 if (Adapter
->DhclientInfo
.client
->state
== S_INIT
)
437 add_protocol(Adapter
->DhclientInfo
.name
,
438 Adapter
->DhclientInfo
.rfdesc
,
439 got_one
, &Adapter
->DhclientInfo
);
441 state_init(&Adapter
->DhclientInfo
);
445 InsertTailList( &AdapterList
, &Adapter
->ListEntry
);
447 SetEvent(AdapterStateChangedEvent
);
449 } else { free( Adapter
); Adapter
= 0; }
450 } else { free( Adapter
); Adapter
= 0; }
453 DH_DbgPrint(MID_TRACE
,("Adapter %d was rejected\n",
454 Table
->table
[i
].dwIndex
));
457 Error
= NotifyAddrChange(NULL
, NULL
);
458 if (Error
!= NO_ERROR
)
465 DbgPrint("DHCPCSVC: Adapter discovery thread is terminating! (Error: %d)\n", Error
);
467 if( Table
) free( Table
);
471 HANDLE
StartAdapterDiscovery(VOID
) {
472 HANDLE ThreadHandle
, EventHandle
;
474 EventHandle
= CreateEvent(NULL
,
479 ThreadHandle
= CreateThread(NULL
,
481 AdapterDiscoveryThread
,
486 if (ThreadHandle
== NULL
)
489 CloseHandle(ThreadHandle
);
495 PLIST_ENTRY ListEntry
;
496 PDHCP_ADAPTER Adapter
;
498 while( !IsListEmpty( &AdapterList
) ) {
499 ListEntry
= (PLIST_ENTRY
)RemoveHeadList( &AdapterList
);
500 Adapter
= CONTAINING_RECORD( ListEntry
, DHCP_ADAPTER
, ListEntry
);
507 PDHCP_ADAPTER
AdapterFindIndex( unsigned int indx
) {
508 PDHCP_ADAPTER Adapter
;
509 PLIST_ENTRY ListEntry
;
511 for( ListEntry
= AdapterList
.Flink
;
512 ListEntry
!= &AdapterList
;
513 ListEntry
= ListEntry
->Flink
) {
514 Adapter
= CONTAINING_RECORD( ListEntry
, DHCP_ADAPTER
, ListEntry
);
515 if( Adapter
->IfMib
.dwIndex
== indx
) return Adapter
;
521 PDHCP_ADAPTER
AdapterFindName( const WCHAR
*name
) {
522 PDHCP_ADAPTER Adapter
;
523 PLIST_ENTRY ListEntry
;
525 for( ListEntry
= AdapterList
.Flink
;
526 ListEntry
!= &AdapterList
;
527 ListEntry
= ListEntry
->Flink
) {
528 Adapter
= CONTAINING_RECORD( ListEntry
, DHCP_ADAPTER
, ListEntry
);
529 if( !wcsicmp( Adapter
->IfMib
.wszName
, name
) ) return Adapter
;
535 PDHCP_ADAPTER
AdapterFindInfo( struct interface_info
*ip
) {
536 PDHCP_ADAPTER Adapter
;
537 PLIST_ENTRY ListEntry
;
539 for( ListEntry
= AdapterList
.Flink
;
540 ListEntry
!= &AdapterList
;
541 ListEntry
= ListEntry
->Flink
) {
542 Adapter
= CONTAINING_RECORD( ListEntry
, DHCP_ADAPTER
, ListEntry
);
543 if( ip
== &Adapter
->DhclientInfo
) return Adapter
;
549 PDHCP_ADAPTER
AdapterFindByHardwareAddress( u_int8_t haddr
[16], u_int8_t hlen
) {
550 PDHCP_ADAPTER Adapter
;
551 PLIST_ENTRY ListEntry
;
553 for(ListEntry
= AdapterList
.Flink
;
554 ListEntry
!= &AdapterList
;
555 ListEntry
= ListEntry
->Flink
) {
556 Adapter
= CONTAINING_RECORD( ListEntry
, DHCP_ADAPTER
, ListEntry
);
557 if (Adapter
->DhclientInfo
.hw_address
.hlen
== hlen
&&
558 !memcmp(Adapter
->DhclientInfo
.hw_address
.haddr
,
560 hlen
)) return Adapter
;
566 PDHCP_ADAPTER
AdapterGetFirst() {
567 if( IsListEmpty( &AdapterList
) ) return NULL
; else {
568 return CONTAINING_RECORD
569 ( AdapterList
.Flink
, DHCP_ADAPTER
, ListEntry
);
573 PDHCP_ADAPTER
AdapterGetNext( PDHCP_ADAPTER This
)
575 if( This
->ListEntry
.Flink
== &AdapterList
) return NULL
;
576 return CONTAINING_RECORD
577 ( This
->ListEntry
.Flink
, DHCP_ADAPTER
, ListEntry
);
580 void if_register_send(struct interface_info
*ip
) {
584 void if_register_receive(struct interface_info
*ip
) {