ad18dfa49760df319ecb277e2be2bd40c53fdcdb
[reactos.git] / reactos / dll / win32 / dhcpcsvc / dhcp / adapter.c
1 #include "rosdhcp.h"
2
3 static SOCKET DhcpSocket = INVALID_SOCKET;
4 static LIST_ENTRY AdapterList;
5 static WSADATA wsd;
6
7 PCHAR *GetSubkeyNames( PCHAR MainKeyName, PCHAR Append ) {
8 int i = 0;
9 DWORD Error;
10 HKEY MainKey;
11 PCHAR *Out, OutKeyName;
12 DWORD CharTotal = 0, AppendLen = 1 + strlen(Append);
13 DWORD MaxSubKeyLen = 0, MaxSubKeys = 0;
14
15 Error = RegOpenKey( HKEY_LOCAL_MACHINE, MainKeyName, &MainKey );
16
17 if( Error ) return NULL;
18
19 Error = RegQueryInfoKey
20 ( MainKey,
21 NULL, NULL, NULL,
22 &MaxSubKeys, &MaxSubKeyLen,
23 NULL, NULL, NULL, NULL, NULL, NULL );
24
25 DH_DbgPrint(MID_TRACE,("MaxSubKeys: %d, MaxSubKeyLen %d\n",
26 MaxSubKeys, MaxSubKeyLen));
27
28 CharTotal = (sizeof(PCHAR) + MaxSubKeyLen + AppendLen) * (MaxSubKeys + 1);
29
30 DH_DbgPrint(MID_TRACE,("AppendLen: %d, CharTotal: %d\n",
31 AppendLen, CharTotal));
32
33 Out = (CHAR**) malloc( CharTotal );
34 OutKeyName = ((PCHAR)&Out[MaxSubKeys+1]);
35
36 if( !Out ) { RegCloseKey( MainKey ); return NULL; }
37
38 i = 0;
39 do {
40 Out[i] = OutKeyName;
41 Error = RegEnumKey( MainKey, i, OutKeyName, MaxSubKeyLen );
42 if( !Error ) {
43 strcat( OutKeyName, Append );
44 DH_DbgPrint(MID_TRACE,("[%d]: %s\n", i, OutKeyName));
45 OutKeyName += strlen(OutKeyName) + 1;
46 i++;
47 } else Out[i] = 0;
48 } while( Error == ERROR_SUCCESS );
49
50 RegCloseKey( MainKey );
51
52 return Out;
53 }
54
55 PCHAR RegReadString( HKEY Root, PCHAR Subkey, PCHAR Value ) {
56 PCHAR SubOut = NULL;
57 DWORD SubOutLen = 0, Error = 0;
58 HKEY ValueKey = NULL;
59
60 DH_DbgPrint(MID_TRACE,("Looking in %x:%s:%s\n", Root, Subkey, Value ));
61
62 if( Subkey && strlen(Subkey) ) {
63 if( RegOpenKey( Root, Subkey, &ValueKey ) != ERROR_SUCCESS )
64 goto regerror;
65 } else ValueKey = Root;
66
67 DH_DbgPrint(MID_TRACE,("Got Key %x\n", ValueKey));
68
69 if( (Error = RegQueryValueEx( ValueKey, Value, NULL, NULL,
70 (LPBYTE)SubOut, &SubOutLen )) != ERROR_SUCCESS )
71 goto regerror;
72
73 DH_DbgPrint(MID_TRACE,("Value %s has size %d\n", Value, SubOutLen));
74
75 if( !(SubOut = (CHAR*) malloc(SubOutLen)) )
76 goto regerror;
77
78 if( (Error = RegQueryValueEx( ValueKey, Value, NULL, NULL,
79 (LPBYTE)SubOut, &SubOutLen )) != ERROR_SUCCESS )
80 goto regerror;
81
82 DH_DbgPrint(MID_TRACE,("Value %s is %s\n", Value, SubOut));
83
84 goto cleanup;
85
86 regerror:
87 if( SubOut ) { free( SubOut ); SubOut = NULL; }
88 cleanup:
89 if( ValueKey && ValueKey != Root ) {
90 DH_DbgPrint(MID_TRACE,("Closing key %x\n", ValueKey));
91 RegCloseKey( ValueKey );
92 }
93
94 DH_DbgPrint(MID_TRACE,("Returning %x with error %d\n", SubOut, Error));
95
96 return SubOut;
97 }
98
99 HKEY FindAdapterKey( PDHCP_ADAPTER Adapter ) {
100 int i = 0;
101 PCHAR EnumKeyName =
102 "SYSTEM\\CurrentControlSet\\Control\\Class\\"
103 "{4D36E972-E325-11CE-BFC1-08002BE10318}";
104 PCHAR TargetKeyNameStart =
105 "SYSTEM\\CurrentControlSet\\Services\\";
106 PCHAR TargetKeyNameEnd = "\\Parameters\\Tcpip";
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;
113
114 if( !EnumKeysLinkage || !EnumKeysTop ) goto cleanup;
115
116 Error = RegOpenKey( HKEY_LOCAL_MACHINE, EnumKeyName, &EnumKey );
117
118 if( Error ) goto cleanup;
119
120 for( i = 0; EnumKeysLinkage[i]; i++ ) {
121 RootDevice = RegReadString
122 ( EnumKey, EnumKeysLinkage[i], "RootDevice" );
123
124 if( RootDevice &&
125 !strcmp( RootDevice, Adapter->DhclientInfo.name ) ) {
126 TargetKeyName =
127 (CHAR*) malloc( strlen( TargetKeyNameStart ) +
128 strlen( RootDevice ) + strlen( TargetKeyNameEnd ) + 1);
129 if( !TargetKeyName ) goto cleanup;
130 sprintf( TargetKeyName, "%s%s%s",
131 TargetKeyNameStart, RootDevice, TargetKeyNameEnd );
132 Error = RegCreateKeyExA( HKEY_LOCAL_MACHINE, TargetKeyName, 0, NULL, 0, KEY_READ, NULL, &OutKey, NULL );
133 break;
134 } else {
135 free( RootDevice ); RootDevice = 0;
136 }
137 }
138
139 cleanup:
140 if( RootDevice ) free( RootDevice );
141 if( EnumKeysLinkage ) free( EnumKeysLinkage );
142 if( EnumKeysTop ) free( EnumKeysTop );
143 if( TargetKeyName ) free( TargetKeyName );
144
145 return OutKey;
146 }
147
148 BOOL PrepareAdapterForService( PDHCP_ADAPTER Adapter ) {
149 HKEY AdapterKey;
150 DWORD Error = ERROR_SUCCESS, DhcpEnabled;
151
152 Adapter->DhclientState.config = &Adapter->DhclientConfig;
153 strncpy(Adapter->DhclientInfo.name, (char*)Adapter->IfMib.bDescr,
154 sizeof(Adapter->DhclientInfo.name));
155
156 AdapterKey = FindAdapterKey( Adapter );
157 if( AdapterKey )
158 {
159 Error = RegQueryValueEx(AdapterKey, "DhcpEnabled", NULL, NULL, (LPBYTE)&DhcpEnabled, NULL);
160
161 if (Error != ERROR_SUCCESS)
162 DhcpEnabled = 1;
163
164 CloseHandle(AdapterKey);
165 }
166 else
167 {
168 /* DHCP enabled by default */
169 DhcpEnabled = 1;
170 }
171
172 if( !DhcpEnabled ) {
173 /* Non-automatic case */
174 DbgPrint("DHCPCSVC: Adapter Name: [%s] (static)\n", Adapter->DhclientInfo.name);
175
176 Adapter->DhclientState.state = S_STATIC;
177 } else {
178 /* Automatic case */
179 DbgPrint("DHCPCSVC: Adapter Name: [%s] (dynamic)\n", Adapter->DhclientInfo.name);
180
181 Adapter->DhclientInfo.client->state = S_INIT;
182 }
183
184 return TRUE;
185 }
186
187 void AdapterInit() {
188 WSAStartup(0x0101,&wsd);
189
190 InitializeListHead( &AdapterList );
191 }
192
193 int
194 InterfaceConnected(MIB_IFROW IfEntry)
195 {
196 if (IfEntry.dwOperStatus == IF_OPER_STATUS_CONNECTED ||
197 IfEntry.dwOperStatus == IF_OPER_STATUS_OPERATIONAL)
198 return 1;
199
200 DH_DbgPrint(MID_TRACE,("Interface %d is down\n", IfEntry.dwIndex));
201 return 0;
202 }
203
204 /*
205 * XXX Figure out the way to bind a specific adapter to a socket.
206 */
207 DWORD WINAPI AdapterDiscoveryThread(LPVOID Context) {
208 PMIB_IFTABLE Table = (PMIB_IFTABLE) malloc(sizeof(MIB_IFTABLE));
209 DWORD Error, Size = sizeof(MIB_IFTABLE);
210 PDHCP_ADAPTER Adapter = NULL;
211 HANDLE AdapterStateChangedEvent = (HANDLE)Context;
212 struct interface_info *ifi = NULL;
213 int i, AdapterCount = 0;
214
215 /* FIXME: Kill this thread when the service is stopped */
216
217 do {
218 DH_DbgPrint(MID_TRACE,("Getting Adapter List...\n"));
219
220 while( (Error = GetIfTable(Table, &Size, 0 )) ==
221 ERROR_INSUFFICIENT_BUFFER ) {
222 DH_DbgPrint(MID_TRACE,("Error %d, New Buffer Size: %d\n", Error, Size));
223 free( Table );
224 Table = (PMIB_IFTABLE) malloc( Size );
225 }
226
227 if( Error != NO_ERROR )
228 {
229 /* HACK: We are waiting until TCP/IP starts */
230 Sleep(2000);
231 continue;
232 }
233
234 DH_DbgPrint(MID_TRACE,("Got Adapter List (%d entries)\n", Table->dwNumEntries));
235
236 for( i = Table->dwNumEntries - 1; i >= 0; i-- ) {
237 DH_DbgPrint(MID_TRACE,("Getting adapter %d attributes\n",
238 Table->table[i].dwIndex));
239
240 ApiLock();
241
242 if ((Adapter = AdapterFindByHardwareAddress(Table->table[i].bPhysAddr, Table->table[i].dwPhysAddrLen)))
243 {
244 /* This is an existing adapter */
245 if (InterfaceConnected(Table->table[i])) {
246 /* We're still active so we stay in the list */
247 ifi = &Adapter->DhclientInfo;
248 } else {
249 /* We've lost our link so out we go */
250 RemoveEntryList(&Adapter->ListEntry);
251 free(Adapter);
252 }
253
254 ApiUnlock();
255
256 continue;
257 }
258
259 ApiUnlock();
260
261 Adapter = (DHCP_ADAPTER*) calloc( sizeof( DHCP_ADAPTER ) + Table->table[i].dwMtu, 1 );
262
263 if( Adapter && Table->table[i].dwType == MIB_IF_TYPE_ETHERNET && InterfaceConnected(Table->table[i])) {
264 memcpy( &Adapter->IfMib, &Table->table[i],
265 sizeof(Adapter->IfMib) );
266 Adapter->DhclientInfo.client = &Adapter->DhclientState;
267 Adapter->DhclientInfo.rbuf = Adapter->recv_buf;
268 Adapter->DhclientInfo.rbuf_max = Table->table[i].dwMtu;
269 Adapter->DhclientInfo.rbuf_len =
270 Adapter->DhclientInfo.rbuf_offset = 0;
271 memcpy(Adapter->DhclientInfo.hw_address.haddr,
272 Adapter->IfMib.bPhysAddr,
273 Adapter->IfMib.dwPhysAddrLen);
274 Adapter->DhclientInfo.hw_address.hlen = Adapter->IfMib.dwPhysAddrLen;
275
276 /* I'm not sure where else to set this, but
277 some DHCP servers won't take a zero.
278 We checked the hardware type earlier in
279 the if statement. */
280 Adapter->DhclientInfo.hw_address.htype = HTYPE_ETHER;
281
282 if( DhcpSocket == INVALID_SOCKET ) {
283 DhcpSocket =
284 Adapter->DhclientInfo.rfdesc =
285 Adapter->DhclientInfo.wfdesc =
286 socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
287
288 if (DhcpSocket != INVALID_SOCKET) {
289 Adapter->ListenAddr.sin_family = AF_INET;
290 Adapter->ListenAddr.sin_port = htons(LOCAL_PORT);
291 Adapter->BindStatus =
292 (bind( Adapter->DhclientInfo.rfdesc,
293 (struct sockaddr *)&Adapter->ListenAddr,
294 sizeof(Adapter->ListenAddr) ) == 0) ?
295 0 : WSAGetLastError();
296 } else {
297 error("socket() failed: %d\n", WSAGetLastError());
298 }
299 } else {
300 Adapter->DhclientInfo.rfdesc =
301 Adapter->DhclientInfo.wfdesc = DhcpSocket;
302 }
303
304 Adapter->DhclientConfig.timeout = DHCP_PANIC_TIMEOUT;
305 Adapter->DhclientConfig.initial_interval = DHCP_DISCOVER_INTERVAL;
306 Adapter->DhclientConfig.retry_interval = DHCP_DISCOVER_INTERVAL;
307 Adapter->DhclientConfig.select_interval = 1;
308 Adapter->DhclientConfig.reboot_timeout = DHCP_REBOOT_TIMEOUT;
309 Adapter->DhclientConfig.backoff_cutoff = DHCP_BACKOFF_MAX;
310 Adapter->DhclientState.interval =
311 Adapter->DhclientConfig.retry_interval;
312
313 if( PrepareAdapterForService( Adapter ) ) {
314 Adapter->DhclientInfo.next = ifi;
315 ifi = &Adapter->DhclientInfo;
316
317 read_client_conf(&Adapter->DhclientInfo);
318
319 if (Adapter->DhclientInfo.client->state == S_INIT)
320 {
321 add_protocol(Adapter->DhclientInfo.name,
322 Adapter->DhclientInfo.rfdesc,
323 got_one, &Adapter->DhclientInfo);
324
325 state_init(&Adapter->DhclientInfo);
326 }
327
328 ApiLock();
329 InsertTailList( &AdapterList, &Adapter->ListEntry );
330 AdapterCount++;
331 SetEvent(AdapterStateChangedEvent);
332 ApiUnlock();
333 } else { free( Adapter ); Adapter = 0; }
334 } else { free( Adapter ); Adapter = 0; }
335
336 if( !Adapter )
337 DH_DbgPrint(MID_TRACE,("Adapter %d was rejected\n",
338 Table->table[i].dwIndex));
339 }
340 Error = NotifyAddrChange(NULL, NULL);
341 #if 0
342 if (Error != NO_ERROR)
343 break;
344 #else
345 if (AdapterCount)
346 break;
347 else
348 Sleep(3000);
349 #endif
350 } while (TRUE);
351
352 DbgPrint("DHCPCSVC: Adapter discovery thread is terminating! (Error: %d)\n", Error);
353
354 if( Table ) free( Table );
355 return Error;
356 }
357
358 HANDLE StartAdapterDiscovery(VOID) {
359 HANDLE /* ThreadHandle, */ EventHandle;
360
361 EventHandle = CreateEvent(NULL,
362 FALSE,
363 FALSE,
364 NULL);
365
366 #if 0
367 ThreadHandle = CreateThread(NULL,
368 0,
369 AdapterDiscoveryThread,
370 (LPVOID)EventHandle,
371 0,
372 NULL);
373
374 if (ThreadHandle == NULL)
375 return NULL;
376
377 CloseHandle(ThreadHandle);
378 #else
379 AdapterDiscoveryThread((LPVOID)EventHandle);
380 #endif
381
382 return EventHandle;
383 }
384
385 void AdapterStop() {
386 PLIST_ENTRY ListEntry;
387 PDHCP_ADAPTER Adapter;
388 ApiLock();
389 while( !IsListEmpty( &AdapterList ) ) {
390 ListEntry = (PLIST_ENTRY)RemoveHeadList( &AdapterList );
391 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
392 free( Adapter );
393 }
394 ApiUnlock();
395 WSACleanup();
396 }
397
398 PDHCP_ADAPTER AdapterFindIndex( unsigned int indx ) {
399 PDHCP_ADAPTER Adapter;
400 PLIST_ENTRY ListEntry;
401
402 for( ListEntry = AdapterList.Flink;
403 ListEntry != &AdapterList;
404 ListEntry = ListEntry->Flink ) {
405 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
406 if( Adapter->IfMib.dwIndex == indx ) return Adapter;
407 }
408
409 return NULL;
410 }
411
412 PDHCP_ADAPTER AdapterFindName( const WCHAR *name ) {
413 PDHCP_ADAPTER Adapter;
414 PLIST_ENTRY ListEntry;
415
416 for( ListEntry = AdapterList.Flink;
417 ListEntry != &AdapterList;
418 ListEntry = ListEntry->Flink ) {
419 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
420 if( !wcsicmp( Adapter->IfMib.wszName, name ) ) return Adapter;
421 }
422
423 return NULL;
424 }
425
426 PDHCP_ADAPTER AdapterFindInfo( struct interface_info *ip ) {
427 PDHCP_ADAPTER Adapter;
428 PLIST_ENTRY ListEntry;
429
430 for( ListEntry = AdapterList.Flink;
431 ListEntry != &AdapterList;
432 ListEntry = ListEntry->Flink ) {
433 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
434 if( ip == &Adapter->DhclientInfo ) return Adapter;
435 }
436
437 return NULL;
438 }
439
440 PDHCP_ADAPTER AdapterFindByHardwareAddress( u_int8_t haddr[16], u_int8_t hlen ) {
441 PDHCP_ADAPTER Adapter;
442 PLIST_ENTRY ListEntry;
443
444 for(ListEntry = AdapterList.Flink;
445 ListEntry != &AdapterList;
446 ListEntry = ListEntry->Flink) {
447 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
448 if (Adapter->DhclientInfo.hw_address.hlen == hlen &&
449 !memcmp(Adapter->DhclientInfo.hw_address.haddr,
450 haddr,
451 hlen)) return Adapter;
452 }
453
454 return NULL;
455 }
456
457 PDHCP_ADAPTER AdapterGetFirst() {
458 if( IsListEmpty( &AdapterList ) ) return NULL; else {
459 return CONTAINING_RECORD
460 ( AdapterList.Flink, DHCP_ADAPTER, ListEntry );
461 }
462 }
463
464 PDHCP_ADAPTER AdapterGetNext( PDHCP_ADAPTER This )
465 {
466 if( This->ListEntry.Flink == &AdapterList ) return NULL;
467 return CONTAINING_RECORD
468 ( This->ListEntry.Flink, DHCP_ADAPTER, ListEntry );
469 }
470
471 void if_register_send(struct interface_info *ip) {
472
473 }
474
475 void if_register_receive(struct interface_info *ip) {
476 }