Partial merge of condrv_restructure branch r65657.
[reactos.git] / reactos / dll / win32 / dhcpcsvc / dhcp / adapter.c
1 #include <rosdhcp.h>
2
3 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\\Tcpip\\Parameters\\Interfaces\\";
106 PCHAR TargetKeyName = NULL;
107 PCHAR *EnumKeysLinkage = GetSubkeyNames( EnumKeyName, "\\Linkage" );
108 PCHAR *EnumKeysTop = GetSubkeyNames( EnumKeyName, "" );
109 PCHAR RootDevice = NULL;
110 HKEY EnumKey, OutKey = NULL;
111 DWORD Error = ERROR_SUCCESS;
112
113 if( !EnumKeysLinkage || !EnumKeysTop ) goto cleanup;
114
115 Error = RegOpenKey( HKEY_LOCAL_MACHINE, EnumKeyName, &EnumKey );
116
117 if( Error ) goto cleanup;
118
119 for( i = 0; EnumKeysLinkage[i]; i++ ) {
120 RootDevice = RegReadString
121 ( EnumKey, EnumKeysLinkage[i], "RootDevice" );
122
123 if( RootDevice &&
124 !strcmp( RootDevice, Adapter->DhclientInfo.name ) ) {
125 TargetKeyName =
126 (CHAR*) malloc( strlen( TargetKeyNameStart ) +
127 strlen( RootDevice ) + 1);
128 if( !TargetKeyName ) goto cleanup;
129 sprintf( TargetKeyName, "%s%s",
130 TargetKeyNameStart, RootDevice );
131 Error = RegCreateKeyExA( HKEY_LOCAL_MACHINE, TargetKeyName, 0, NULL, 0, KEY_READ, NULL, &OutKey, NULL );
132 break;
133 } else {
134 free( RootDevice ); RootDevice = 0;
135 }
136 }
137
138 cleanup:
139 if( RootDevice ) free( RootDevice );
140 if( EnumKeysLinkage ) free( EnumKeysLinkage );
141 if( EnumKeysTop ) free( EnumKeysTop );
142 if( TargetKeyName ) free( TargetKeyName );
143
144 return OutKey;
145 }
146
147 BOOL PrepareAdapterForService( PDHCP_ADAPTER Adapter ) {
148 HKEY AdapterKey;
149 DWORD Error = ERROR_SUCCESS, DhcpEnabled, Length = sizeof(DWORD);
150
151 Adapter->DhclientState.config = &Adapter->DhclientConfig;
152 strncpy(Adapter->DhclientInfo.name, (char*)Adapter->IfMib.bDescr,
153 sizeof(Adapter->DhclientInfo.name));
154
155 AdapterKey = FindAdapterKey( Adapter );
156 if( AdapterKey )
157 {
158 Error = RegQueryValueEx(AdapterKey, "EnableDHCP", NULL, NULL, (LPBYTE)&DhcpEnabled, &Length);
159
160 if (Error != ERROR_SUCCESS || Length != sizeof(DWORD))
161 DhcpEnabled = 1;
162
163 CloseHandle(AdapterKey);
164 }
165 else
166 {
167 /* DHCP enabled by default */
168 DhcpEnabled = 1;
169 }
170
171 if( !DhcpEnabled ) {
172 /* Non-automatic case */
173 DbgPrint("DHCPCSVC: Adapter Name: [%s] (static)\n", Adapter->DhclientInfo.name);
174
175 Adapter->DhclientState.state = S_STATIC;
176 } else {
177 /* Automatic case */
178 DbgPrint("DHCPCSVC: Adapter Name: [%s] (dynamic)\n", Adapter->DhclientInfo.name);
179
180 Adapter->DhclientInfo.client->state = S_INIT;
181 }
182
183 return TRUE;
184 }
185
186 void AdapterInit() {
187 WSAStartup(0x0101,&wsd);
188
189 InitializeListHead( &AdapterList );
190 }
191
192 int
193 InterfaceConnected(const MIB_IFROW* IfEntry)
194 {
195 if (IfEntry->dwOperStatus == IF_OPER_STATUS_CONNECTED ||
196 IfEntry->dwOperStatus == IF_OPER_STATUS_OPERATIONAL)
197 return 1;
198
199 DH_DbgPrint(MID_TRACE,("Interface %d is down\n", IfEntry->dwIndex));
200 return 0;
201 }
202
203 BOOL
204 IsReconnectHackNeeded(PDHCP_ADAPTER Adapter, const MIB_IFROW* IfEntry)
205 {
206 struct protocol *proto;
207 PIP_ADAPTER_INFO AdapterInfo, Orig;
208 DWORD Size, Ret;
209 char *ZeroAddress = "0.0.0.0";
210
211 proto = find_protocol_by_adapter(&Adapter->DhclientInfo);
212
213 if (Adapter->DhclientInfo.client->state == S_BOUND && !proto)
214 return FALSE;
215
216 if (Adapter->DhclientInfo.client->state != S_BOUND &&
217 Adapter->DhclientInfo.client->state != S_STATIC)
218 return FALSE;
219
220 ApiUnlock();
221
222 Orig = AdapterInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(IP_ADAPTER_INFO));
223 Size = sizeof(IP_ADAPTER_INFO);
224 if (!AdapterInfo)
225 {
226 ApiLock();
227 return FALSE;
228 }
229
230 Ret = GetAdaptersInfo(AdapterInfo, &Size);
231 if (Ret == ERROR_BUFFER_OVERFLOW)
232 {
233 HeapFree(GetProcessHeap(), 0, AdapterInfo);
234 AdapterInfo = HeapAlloc(GetProcessHeap(), 0, Size);
235 if (!AdapterInfo)
236 {
237 ApiLock();
238 return FALSE;
239 }
240
241 if (GetAdaptersInfo(AdapterInfo, &Size) != NO_ERROR)
242 {
243 ApiLock();
244 return FALSE;
245 }
246
247 Orig = AdapterInfo;
248 for (; AdapterInfo != NULL; AdapterInfo = AdapterInfo->Next)
249 {
250 if (AdapterInfo->Index == IfEntry->dwIndex)
251 break;
252 }
253
254 if (AdapterInfo == NULL)
255 {
256 HeapFree(GetProcessHeap(), 0, Orig);
257 ApiLock();
258 return FALSE;
259 }
260 }
261 else if (Ret != NO_ERROR)
262 {
263 HeapFree(GetProcessHeap(), 0, Orig);
264 ApiLock();
265 return FALSE;
266 }
267
268 if (!strcmp(AdapterInfo->IpAddressList.IpAddress.String, ZeroAddress))
269 {
270 HeapFree(GetProcessHeap(), 0, Orig);
271 ApiLock();
272 return TRUE;
273 }
274 else
275 {
276 HeapFree(GetProcessHeap(), 0, Orig);
277 ApiLock();
278 return FALSE;
279 }
280 }
281
282 /*
283 * XXX Figure out the way to bind a specific adapter to a socket.
284 */
285 DWORD WINAPI AdapterDiscoveryThread(LPVOID Context) {
286 PMIB_IFTABLE Table = (PMIB_IFTABLE) malloc(sizeof(MIB_IFTABLE));
287 DWORD Error, Size = sizeof(MIB_IFTABLE);
288 PDHCP_ADAPTER Adapter = NULL;
289 HANDLE AdapterStateChangedEvent = (HANDLE)Context;
290 struct interface_info *ifi = NULL;
291 struct protocol *proto;
292 int i, AdapterCount = 0, Broadcast;
293
294 /* FIXME: Kill this thread when the service is stopped */
295
296 do {
297 DH_DbgPrint(MID_TRACE,("Getting Adapter List...\n"));
298
299 while( (Error = GetIfTable(Table, &Size, 0 )) ==
300 ERROR_INSUFFICIENT_BUFFER ) {
301 DH_DbgPrint(MID_TRACE,("Error %d, New Buffer Size: %d\n", Error, Size));
302 free( Table );
303 Table = (PMIB_IFTABLE) malloc( Size );
304 }
305
306 if( Error != NO_ERROR )
307 {
308 /* HACK: We are waiting until TCP/IP starts */
309 Sleep(2000);
310 continue;
311 }
312
313 DH_DbgPrint(MID_TRACE,("Got Adapter List (%d entries)\n", Table->dwNumEntries));
314
315 for( i = Table->dwNumEntries - 1; i >= 0; i-- ) {
316 DH_DbgPrint(MID_TRACE,("Getting adapter %d attributes\n",
317 Table->table[i].dwIndex));
318
319 ApiLock();
320
321 if ((Adapter = AdapterFindByHardwareAddress(Table->table[i].bPhysAddr, Table->table[i].dwPhysAddrLen)))
322 {
323 proto = find_protocol_by_adapter(&Adapter->DhclientInfo);
324
325 /* This is an existing adapter */
326 if (InterfaceConnected(&Table->table[i])) {
327 /* We're still active so we stay in the list */
328 ifi = &Adapter->DhclientInfo;
329
330 /* This is a hack because IP helper API sucks */
331 if (IsReconnectHackNeeded(Adapter, &Table->table[i]))
332 {
333 /* This handles a disconnect/reconnect */
334
335 if (proto)
336 remove_protocol(proto);
337 Adapter->DhclientInfo.client->state = S_INIT;
338
339 /* These are already invalid since the media state change */
340 Adapter->RouterMib.dwForwardNextHop = 0;
341 Adapter->NteContext = 0;
342
343 add_protocol(Adapter->DhclientInfo.name,
344 Adapter->DhclientInfo.rfdesc,
345 got_one, &Adapter->DhclientInfo);
346 state_init(&Adapter->DhclientInfo);
347
348 SetEvent(AdapterStateChangedEvent);
349 }
350
351 } else {
352 if (proto)
353 remove_protocol(proto);
354
355 /* We've lost our link so out we go */
356 RemoveEntryList(&Adapter->ListEntry);
357 free(Adapter);
358 }
359
360 ApiUnlock();
361
362 continue;
363 }
364
365 ApiUnlock();
366
367 Adapter = (DHCP_ADAPTER*) calloc( sizeof( DHCP_ADAPTER ) + Table->table[i].dwMtu, 1 );
368
369 if( Adapter && Table->table[i].dwType == MIB_IF_TYPE_ETHERNET && InterfaceConnected(&Table->table[i])) {
370 memcpy( &Adapter->IfMib, &Table->table[i],
371 sizeof(Adapter->IfMib) );
372 Adapter->DhclientInfo.client = &Adapter->DhclientState;
373 Adapter->DhclientInfo.rbuf = Adapter->recv_buf;
374 Adapter->DhclientInfo.rbuf_max = Table->table[i].dwMtu;
375 Adapter->DhclientInfo.rbuf_len =
376 Adapter->DhclientInfo.rbuf_offset = 0;
377 memcpy(Adapter->DhclientInfo.hw_address.haddr,
378 Adapter->IfMib.bPhysAddr,
379 Adapter->IfMib.dwPhysAddrLen);
380 Adapter->DhclientInfo.hw_address.hlen = Adapter->IfMib.dwPhysAddrLen;
381
382 /* I'm not sure where else to set this, but
383 some DHCP servers won't take a zero.
384 We checked the hardware type earlier in
385 the if statement. */
386 Adapter->DhclientInfo.hw_address.htype = HTYPE_ETHER;
387
388 if( DhcpSocket == INVALID_SOCKET ) {
389 DhcpSocket =
390 Adapter->DhclientInfo.rfdesc =
391 Adapter->DhclientInfo.wfdesc =
392 socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
393
394 if (DhcpSocket != INVALID_SOCKET) {
395
396 /* Allow broadcast on this socket */
397 Broadcast = 1;
398 setsockopt(DhcpSocket,
399 SOL_SOCKET,
400 SO_BROADCAST,
401 (const char *)&Broadcast,
402 sizeof(Broadcast));
403
404 Adapter->ListenAddr.sin_family = AF_INET;
405 Adapter->ListenAddr.sin_port = htons(LOCAL_PORT);
406 Adapter->BindStatus =
407 (bind( Adapter->DhclientInfo.rfdesc,
408 (struct sockaddr *)&Adapter->ListenAddr,
409 sizeof(Adapter->ListenAddr) ) == 0) ?
410 0 : WSAGetLastError();
411 } else {
412 error("socket() failed: %d\n", WSAGetLastError());
413 }
414 } else {
415 Adapter->DhclientInfo.rfdesc =
416 Adapter->DhclientInfo.wfdesc = DhcpSocket;
417 }
418
419 Adapter->DhclientConfig.timeout = DHCP_PANIC_TIMEOUT;
420 Adapter->DhclientConfig.initial_interval = DHCP_DISCOVER_INTERVAL;
421 Adapter->DhclientConfig.retry_interval = DHCP_DISCOVER_INTERVAL;
422 Adapter->DhclientConfig.select_interval = 1;
423 Adapter->DhclientConfig.reboot_timeout = DHCP_REBOOT_TIMEOUT;
424 Adapter->DhclientConfig.backoff_cutoff = DHCP_BACKOFF_MAX;
425 Adapter->DhclientState.interval =
426 Adapter->DhclientConfig.retry_interval;
427
428 if( PrepareAdapterForService( Adapter ) ) {
429 Adapter->DhclientInfo.next = ifi;
430 ifi = &Adapter->DhclientInfo;
431
432 read_client_conf(&Adapter->DhclientInfo);
433
434 if (Adapter->DhclientInfo.client->state == S_INIT)
435 {
436 add_protocol(Adapter->DhclientInfo.name,
437 Adapter->DhclientInfo.rfdesc,
438 got_one, &Adapter->DhclientInfo);
439
440 state_init(&Adapter->DhclientInfo);
441 }
442
443 ApiLock();
444 InsertTailList( &AdapterList, &Adapter->ListEntry );
445 AdapterCount++;
446 SetEvent(AdapterStateChangedEvent);
447 ApiUnlock();
448 } else { free( Adapter ); Adapter = 0; }
449 } else { free( Adapter ); Adapter = 0; }
450
451 if( !Adapter )
452 DH_DbgPrint(MID_TRACE,("Adapter %d was rejected\n",
453 Table->table[i].dwIndex));
454 }
455 #if 0
456 Error = NotifyAddrChange(NULL, NULL);
457 if (Error != NO_ERROR)
458 break;
459 #else
460 Sleep(3000);
461 #endif
462 } while (TRUE);
463
464 DbgPrint("DHCPCSVC: Adapter discovery thread is terminating! (Error: %d)\n", Error);
465
466 if( Table ) free( Table );
467 return Error;
468 }
469
470 HANDLE StartAdapterDiscovery(VOID) {
471 HANDLE ThreadHandle, EventHandle;
472
473 EventHandle = CreateEvent(NULL,
474 FALSE,
475 FALSE,
476 NULL);
477
478 ThreadHandle = CreateThread(NULL,
479 0,
480 AdapterDiscoveryThread,
481 (LPVOID)EventHandle,
482 0,
483 NULL);
484
485 if (ThreadHandle == NULL)
486 return NULL;
487
488 CloseHandle(ThreadHandle);
489
490 return EventHandle;
491 }
492
493 void AdapterStop() {
494 PLIST_ENTRY ListEntry;
495 PDHCP_ADAPTER Adapter;
496 ApiLock();
497 while( !IsListEmpty( &AdapterList ) ) {
498 ListEntry = (PLIST_ENTRY)RemoveHeadList( &AdapterList );
499 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
500 free( Adapter );
501 }
502 ApiUnlock();
503 WSACleanup();
504 }
505
506 PDHCP_ADAPTER AdapterFindIndex( unsigned int indx ) {
507 PDHCP_ADAPTER Adapter;
508 PLIST_ENTRY ListEntry;
509
510 for( ListEntry = AdapterList.Flink;
511 ListEntry != &AdapterList;
512 ListEntry = ListEntry->Flink ) {
513 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
514 if( Adapter->IfMib.dwIndex == indx ) return Adapter;
515 }
516
517 return NULL;
518 }
519
520 PDHCP_ADAPTER AdapterFindName( const WCHAR *name ) {
521 PDHCP_ADAPTER Adapter;
522 PLIST_ENTRY ListEntry;
523
524 for( ListEntry = AdapterList.Flink;
525 ListEntry != &AdapterList;
526 ListEntry = ListEntry->Flink ) {
527 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
528 if( !wcsicmp( Adapter->IfMib.wszName, name ) ) return Adapter;
529 }
530
531 return NULL;
532 }
533
534 PDHCP_ADAPTER AdapterFindInfo( struct interface_info *ip ) {
535 PDHCP_ADAPTER Adapter;
536 PLIST_ENTRY ListEntry;
537
538 for( ListEntry = AdapterList.Flink;
539 ListEntry != &AdapterList;
540 ListEntry = ListEntry->Flink ) {
541 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
542 if( ip == &Adapter->DhclientInfo ) return Adapter;
543 }
544
545 return NULL;
546 }
547
548 PDHCP_ADAPTER AdapterFindByHardwareAddress( u_int8_t haddr[16], u_int8_t hlen ) {
549 PDHCP_ADAPTER Adapter;
550 PLIST_ENTRY ListEntry;
551
552 for(ListEntry = AdapterList.Flink;
553 ListEntry != &AdapterList;
554 ListEntry = ListEntry->Flink) {
555 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
556 if (Adapter->DhclientInfo.hw_address.hlen == hlen &&
557 !memcmp(Adapter->DhclientInfo.hw_address.haddr,
558 haddr,
559 hlen)) return Adapter;
560 }
561
562 return NULL;
563 }
564
565 PDHCP_ADAPTER AdapterGetFirst() {
566 if( IsListEmpty( &AdapterList ) ) return NULL; else {
567 return CONTAINING_RECORD
568 ( AdapterList.Flink, DHCP_ADAPTER, ListEntry );
569 }
570 }
571
572 PDHCP_ADAPTER AdapterGetNext( PDHCP_ADAPTER This )
573 {
574 if( This->ListEntry.Flink == &AdapterList ) return NULL;
575 return CONTAINING_RECORD
576 ( This->ListEntry.Flink, DHCP_ADAPTER, ListEntry );
577 }
578
579 void if_register_send(struct interface_info *ip) {
580
581 }
582
583 void if_register_receive(struct interface_info *ip) {
584 }