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