[DHCPCSVC]
[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 MaxSubKeyLen++;
26 DH_DbgPrint(MID_TRACE,("MaxSubKeys: %d, MaxSubKeyLen %d\n",
27 MaxSubKeys, MaxSubKeyLen));
28
29 CharTotal = (sizeof(PCHAR) + MaxSubKeyLen + AppendLen) * (MaxSubKeys + 1);
30
31 DH_DbgPrint(MID_TRACE,("AppendLen: %d, CharTotal: %d\n",
32 AppendLen, CharTotal));
33
34 Out = (CHAR**) malloc( CharTotal );
35 OutKeyName = ((PCHAR)&Out[MaxSubKeys+1]);
36
37 if( !Out ) { RegCloseKey( MainKey ); return NULL; }
38
39 i = 0;
40 do {
41 Out[i] = OutKeyName;
42 Error = RegEnumKey( MainKey, i, OutKeyName, MaxSubKeyLen );
43 if( !Error ) {
44 strcat( OutKeyName, Append );
45 DH_DbgPrint(MID_TRACE,("[%d]: %s\n", i, OutKeyName));
46 OutKeyName += strlen(OutKeyName) + 1;
47 i++;
48 } else Out[i] = 0;
49 } while( Error == ERROR_SUCCESS );
50
51 RegCloseKey( MainKey );
52
53 return Out;
54 }
55
56 PCHAR RegReadString( HKEY Root, PCHAR Subkey, PCHAR Value ) {
57 PCHAR SubOut = NULL;
58 DWORD SubOutLen = 0, Error = 0;
59 HKEY ValueKey = NULL;
60
61 DH_DbgPrint(MID_TRACE,("Looking in %x:%s:%s\n", Root, Subkey, Value ));
62
63 if( Subkey && strlen(Subkey) ) {
64 if( RegOpenKey( Root, Subkey, &ValueKey ) != ERROR_SUCCESS )
65 goto regerror;
66 } else ValueKey = Root;
67
68 DH_DbgPrint(MID_TRACE,("Got Key %x\n", ValueKey));
69
70 if( (Error = RegQueryValueEx( ValueKey, Value, NULL, NULL,
71 (LPBYTE)SubOut, &SubOutLen )) != ERROR_SUCCESS )
72 goto regerror;
73
74 DH_DbgPrint(MID_TRACE,("Value %s has size %d\n", Value, SubOutLen));
75
76 if( !(SubOut = (CHAR*) malloc(SubOutLen)) )
77 goto regerror;
78
79 if( (Error = RegQueryValueEx( ValueKey, Value, NULL, NULL,
80 (LPBYTE)SubOut, &SubOutLen )) != ERROR_SUCCESS )
81 goto regerror;
82
83 DH_DbgPrint(MID_TRACE,("Value %s is %s\n", Value, SubOut));
84
85 goto cleanup;
86
87 regerror:
88 if( SubOut ) { free( SubOut ); SubOut = NULL; }
89 cleanup:
90 if( ValueKey && ValueKey != Root ) {
91 DH_DbgPrint(MID_TRACE,("Closing key %x\n", ValueKey));
92 RegCloseKey( ValueKey );
93 }
94
95 DH_DbgPrint(MID_TRACE,("Returning %x with error %d\n", SubOut, Error));
96
97 return SubOut;
98 }
99
100 HKEY FindAdapterKey( PDHCP_ADAPTER Adapter ) {
101 int i = 0;
102 PCHAR EnumKeyName =
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;
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 ) + 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 );
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, Length = sizeof(DWORD);
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, "EnableDHCP", NULL, NULL, (LPBYTE)&DhcpEnabled, &Length);
160
161 if (Error != ERROR_SUCCESS || Length != sizeof(DWORD))
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(const 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 BOOL
205 IsReconnectHackNeeded(PDHCP_ADAPTER Adapter, const MIB_IFROW* IfEntry)
206 {
207 struct protocol *proto;
208 PIP_ADAPTER_INFO AdapterInfo, Orig;
209 DWORD Size, Ret;
210 char *ZeroAddress = "0.0.0.0";
211
212 proto = find_protocol_by_adapter(&Adapter->DhclientInfo);
213
214 if (Adapter->DhclientInfo.client->state == S_BOUND && !proto)
215 return FALSE;
216
217 if (Adapter->DhclientInfo.client->state != S_BOUND &&
218 Adapter->DhclientInfo.client->state != S_STATIC)
219 return FALSE;
220
221 ApiUnlock();
222
223 Orig = AdapterInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(IP_ADAPTER_INFO));
224 Size = sizeof(IP_ADAPTER_INFO);
225 if (!AdapterInfo)
226 {
227 ApiLock();
228 return FALSE;
229 }
230
231 Ret = GetAdaptersInfo(AdapterInfo, &Size);
232 if (Ret == ERROR_BUFFER_OVERFLOW)
233 {
234 HeapFree(GetProcessHeap(), 0, AdapterInfo);
235 AdapterInfo = HeapAlloc(GetProcessHeap(), 0, Size);
236 if (!AdapterInfo)
237 {
238 ApiLock();
239 return FALSE;
240 }
241
242 if (GetAdaptersInfo(AdapterInfo, &Size) != NO_ERROR)
243 {
244 ApiLock();
245 return FALSE;
246 }
247
248 Orig = AdapterInfo;
249 for (; AdapterInfo != NULL; AdapterInfo = AdapterInfo->Next)
250 {
251 if (AdapterInfo->Index == IfEntry->dwIndex)
252 break;
253 }
254
255 if (AdapterInfo == NULL)
256 {
257 HeapFree(GetProcessHeap(), 0, Orig);
258 ApiLock();
259 return FALSE;
260 }
261 }
262 else if (Ret != NO_ERROR)
263 {
264 HeapFree(GetProcessHeap(), 0, Orig);
265 ApiLock();
266 return FALSE;
267 }
268
269 if (!strcmp(AdapterInfo->IpAddressList.IpAddress.String, ZeroAddress))
270 {
271 HeapFree(GetProcessHeap(), 0, Orig);
272 ApiLock();
273 return TRUE;
274 }
275 else
276 {
277 HeapFree(GetProcessHeap(), 0, Orig);
278 ApiLock();
279 return FALSE;
280 }
281 }
282
283 /*
284 * XXX Figure out the way to bind a specific adapter to a socket.
285 */
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;
294
295 /* FIXME: Kill this thread when the service is stopped */
296
297 do {
298 DH_DbgPrint(MID_TRACE,("Getting Adapter List...\n"));
299
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));
303 free( Table );
304 Table = (PMIB_IFTABLE) malloc( Size );
305 }
306
307 if( Error != NO_ERROR )
308 {
309 /* HACK: We are waiting until TCP/IP starts */
310 Sleep(2000);
311 continue;
312 }
313
314 DH_DbgPrint(MID_TRACE,("Got Adapter List (%d entries)\n", Table->dwNumEntries));
315
316 for( i = Table->dwNumEntries - 1; i >= 0; i-- ) {
317 DH_DbgPrint(MID_TRACE,("Getting adapter %d attributes\n",
318 Table->table[i].dwIndex));
319
320 ApiLock();
321
322 if ((Adapter = AdapterFindByHardwareAddress(Table->table[i].bPhysAddr, Table->table[i].dwPhysAddrLen)))
323 {
324 proto = find_protocol_by_adapter(&Adapter->DhclientInfo);
325
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;
330
331 /* This is a hack because IP helper API sucks */
332 if (IsReconnectHackNeeded(Adapter, &Table->table[i]))
333 {
334 /* This handles a disconnect/reconnect */
335
336 if (proto)
337 remove_protocol(proto);
338 Adapter->DhclientInfo.client->state = S_INIT;
339
340 /* These are already invalid since the media state change */
341 Adapter->RouterMib.dwForwardNextHop = 0;
342 Adapter->NteContext = 0;
343
344 add_protocol(Adapter->DhclientInfo.name,
345 Adapter->DhclientInfo.rfdesc,
346 got_one, &Adapter->DhclientInfo);
347 state_init(&Adapter->DhclientInfo);
348
349 SetEvent(AdapterStateChangedEvent);
350 }
351
352 } else {
353 if (proto)
354 remove_protocol(proto);
355
356 /* We've lost our link so out we go */
357 RemoveEntryList(&Adapter->ListEntry);
358 free(Adapter);
359 }
360
361 ApiUnlock();
362
363 continue;
364 }
365
366 ApiUnlock();
367
368 Adapter = (DHCP_ADAPTER*) calloc( sizeof( DHCP_ADAPTER ) + Table->table[i].dwMtu, 1 );
369
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;
382
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
386 the if statement. */
387 Adapter->DhclientInfo.hw_address.htype = HTYPE_ETHER;
388
389 if( DhcpSocket == INVALID_SOCKET ) {
390 DhcpSocket =
391 Adapter->DhclientInfo.rfdesc =
392 Adapter->DhclientInfo.wfdesc =
393 socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
394
395 if (DhcpSocket != INVALID_SOCKET) {
396
397 /* Allow broadcast on this socket */
398 Broadcast = 1;
399 setsockopt(DhcpSocket,
400 SOL_SOCKET,
401 SO_BROADCAST,
402 (const char *)&Broadcast,
403 sizeof(Broadcast));
404
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();
412 } else {
413 error("socket() failed: %d\n", WSAGetLastError());
414 }
415 } else {
416 Adapter->DhclientInfo.rfdesc =
417 Adapter->DhclientInfo.wfdesc = DhcpSocket;
418 }
419
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;
428
429 if( PrepareAdapterForService( Adapter ) ) {
430 Adapter->DhclientInfo.next = ifi;
431 ifi = &Adapter->DhclientInfo;
432
433 read_client_conf(&Adapter->DhclientInfo);
434
435 if (Adapter->DhclientInfo.client->state == S_INIT)
436 {
437 add_protocol(Adapter->DhclientInfo.name,
438 Adapter->DhclientInfo.rfdesc,
439 got_one, &Adapter->DhclientInfo);
440
441 state_init(&Adapter->DhclientInfo);
442 }
443
444 ApiLock();
445 InsertTailList( &AdapterList, &Adapter->ListEntry );
446 AdapterCount++;
447 SetEvent(AdapterStateChangedEvent);
448 ApiUnlock();
449 } else { free( Adapter ); Adapter = 0; }
450 } else { free( Adapter ); Adapter = 0; }
451
452 if( !Adapter )
453 DH_DbgPrint(MID_TRACE,("Adapter %d was rejected\n",
454 Table->table[i].dwIndex));
455 }
456 #if 0
457 Error = NotifyAddrChange(NULL, NULL);
458 if (Error != NO_ERROR)
459 break;
460 #else
461 Sleep(3000);
462 #endif
463 } while (TRUE);
464
465 DbgPrint("DHCPCSVC: Adapter discovery thread is terminating! (Error: %d)\n", Error);
466
467 if( Table ) free( Table );
468 return Error;
469 }
470
471 HANDLE StartAdapterDiscovery(VOID) {
472 HANDLE ThreadHandle, EventHandle;
473
474 EventHandle = CreateEvent(NULL,
475 FALSE,
476 FALSE,
477 NULL);
478
479 ThreadHandle = CreateThread(NULL,
480 0,
481 AdapterDiscoveryThread,
482 (LPVOID)EventHandle,
483 0,
484 NULL);
485
486 if (ThreadHandle == NULL)
487 return NULL;
488
489 CloseHandle(ThreadHandle);
490
491 return EventHandle;
492 }
493
494 void AdapterStop() {
495 PLIST_ENTRY ListEntry;
496 PDHCP_ADAPTER Adapter;
497 ApiLock();
498 while( !IsListEmpty( &AdapterList ) ) {
499 ListEntry = (PLIST_ENTRY)RemoveHeadList( &AdapterList );
500 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
501 free( Adapter );
502 }
503 ApiUnlock();
504 WSACleanup();
505 }
506
507 PDHCP_ADAPTER AdapterFindIndex( unsigned int indx ) {
508 PDHCP_ADAPTER Adapter;
509 PLIST_ENTRY ListEntry;
510
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;
516 }
517
518 return NULL;
519 }
520
521 PDHCP_ADAPTER AdapterFindName( const WCHAR *name ) {
522 PDHCP_ADAPTER Adapter;
523 PLIST_ENTRY ListEntry;
524
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;
530 }
531
532 return NULL;
533 }
534
535 PDHCP_ADAPTER AdapterFindInfo( struct interface_info *ip ) {
536 PDHCP_ADAPTER Adapter;
537 PLIST_ENTRY ListEntry;
538
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;
544 }
545
546 return NULL;
547 }
548
549 PDHCP_ADAPTER AdapterFindByHardwareAddress( u_int8_t haddr[16], u_int8_t hlen ) {
550 PDHCP_ADAPTER Adapter;
551 PLIST_ENTRY ListEntry;
552
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,
559 haddr,
560 hlen)) return Adapter;
561 }
562
563 return NULL;
564 }
565
566 PDHCP_ADAPTER AdapterGetFirst() {
567 if( IsListEmpty( &AdapterList ) ) return NULL; else {
568 return CONTAINING_RECORD
569 ( AdapterList.Flink, DHCP_ADAPTER, ListEntry );
570 }
571 }
572
573 PDHCP_ADAPTER AdapterGetNext( PDHCP_ADAPTER This )
574 {
575 if( This->ListEntry.Flink == &AdapterList ) return NULL;
576 return CONTAINING_RECORD
577 ( This->ListEntry.Flink, DHCP_ADAPTER, ListEntry );
578 }
579
580 void if_register_send(struct interface_info *ip) {
581
582 }
583
584 void if_register_receive(struct interface_info *ip) {
585 }