075e080026abe5f8d4ddd22a4d949263586c4989
[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\\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 = NULL;
149 PCHAR IPAddress = NULL, Netmask = NULL, DefaultGateway = NULL;
150 NTSTATUS Status = STATUS_SUCCESS;
151 DWORD Error = ERROR_SUCCESS;
152
153 Adapter->DhclientState.config = &Adapter->DhclientConfig;
154 strncpy(Adapter->DhclientInfo.name, (char*)Adapter->IfMib.bDescr,
155 sizeof(Adapter->DhclientInfo.name));
156
157 AdapterKey = FindAdapterKey( Adapter );
158 if( AdapterKey )
159 IPAddress = RegReadString( AdapterKey, NULL, "IPAddress" );
160
161 if( IPAddress && strcmp( IPAddress, "0.0.0.0" ) ) {
162 /* Non-automatic case */
163 DH_DbgPrint
164 (MID_TRACE,("Adapter Name: [%s] (Bind Status %x) (static %s)\n",
165 Adapter->DhclientInfo.name,
166 Adapter->BindStatus,
167 IPAddress));
168
169 Adapter->DhclientState.state = S_STATIC;
170
171 Netmask = RegReadString( AdapterKey, NULL, "Subnetmask" );
172
173 Status = AddIPAddress( inet_addr( IPAddress ),
174 inet_addr( Netmask ? Netmask : "255.255.255.0" ),
175 Adapter->IfMib.dwIndex,
176 &Adapter->NteContext,
177 &Adapter->NteInstance );
178
179 DefaultGateway = RegReadString( AdapterKey, NULL, "DefaultGateway" );
180
181 if( DefaultGateway ) {
182 Adapter->RouterMib.dwForwardDest = 0;
183 Adapter->RouterMib.dwForwardMask = 0;
184 Adapter->RouterMib.dwForwardMetric1 = 1;
185 Adapter->RouterMib.dwForwardIfIndex = Adapter->IfMib.dwIndex;
186 Adapter->RouterMib.dwForwardNextHop = inet_addr(DefaultGateway);
187 Error = CreateIpForwardEntry( &Adapter->RouterMib );
188 if( Error )
189 warning("Failed to set default gateway %s: %ld\n",
190 DefaultGateway, Error);
191 }
192
193 if( DefaultGateway ) free( DefaultGateway );
194 if( Netmask ) free( Netmask );
195 } else {
196 /* Automatic case */
197 DH_DbgPrint
198 (MID_TRACE,("Adapter Name: [%s] (Bind Status %x) (dynamic)\n",
199 Adapter->DhclientInfo.name,
200 Adapter->BindStatus));
201
202 Adapter->DhclientInfo.client->state = S_INIT;
203 }
204
205 if( IPAddress ) free( IPAddress );
206
207 return TRUE;
208 }
209
210 void AdapterInit() {
211 WSAStartup(0x0101,&wsd);
212
213 InitializeListHead( &AdapterList );
214 }
215
216 int
217 InterfaceConnected(MIB_IFROW IfEntry)
218 {
219 if (IfEntry.dwOperStatus == IF_OPER_STATUS_CONNECTED ||
220 IfEntry.dwOperStatus == IF_OPER_STATUS_OPERATIONAL)
221 return 1;
222
223 DH_DbgPrint(MID_TRACE,("Interface %d is down\n", IfEntry.dwIndex));
224 return 0;
225 }
226
227 /*
228 * XXX Figure out the way to bind a specific adapter to a socket.
229 */
230 DWORD WINAPI AdapterDiscoveryThread(LPVOID Context) {
231 PMIB_IFTABLE Table = (PMIB_IFTABLE) malloc(sizeof(MIB_IFTABLE));
232 DWORD Error, Size = sizeof(MIB_IFTABLE);
233 PDHCP_ADAPTER Adapter = NULL;
234 HANDLE AdapterStateChangedEvent = (HANDLE)Context;
235 struct interface_info *ifi = NULL;
236 int i, AdapterCount = 0;
237
238 /* FIXME: Kill this thread when the service is stopped */
239
240 do {
241 DH_DbgPrint(MID_TRACE,("Getting Adapter List...\n"));
242
243 while( (Error = GetIfTable(Table, &Size, 0 )) ==
244 ERROR_INSUFFICIENT_BUFFER ) {
245 DH_DbgPrint(MID_TRACE,("Error %d, New Buffer Size: %d\n", Error, Size));
246 free( Table );
247 Table = (PMIB_IFTABLE) malloc( Size );
248 }
249
250 if( Error != NO_ERROR )
251 {
252 /* HACK: We are waiting until TCP/IP starts */
253 Sleep(2000);
254 continue;
255 }
256
257 DH_DbgPrint(MID_TRACE,("Got Adapter List (%d entries)\n", Table->dwNumEntries));
258
259 for( i = Table->dwNumEntries - 1; i >= 0; i-- ) {
260 DH_DbgPrint(MID_TRACE,("Getting adapter %d attributes\n",
261 Table->table[i].dwIndex));
262
263 ApiLock();
264
265 if ((Adapter = AdapterFindByHardwareAddress(Table->table[i].bPhysAddr, Table->table[i].dwPhysAddrLen)))
266 {
267 /* This is an existing adapter */
268 if (InterfaceConnected(Table->table[i])) {
269 /* We're still active so we stay in the list */
270 ifi = &Adapter->DhclientInfo;
271 } else {
272 /* We've lost our link so out we go */
273 RemoveEntryList(&Adapter->ListEntry);
274 free(Adapter);
275 }
276
277 ApiUnlock();
278
279 continue;
280 }
281
282 ApiUnlock();
283
284 Adapter = (DHCP_ADAPTER*) calloc( sizeof( DHCP_ADAPTER ) + Table->table[i].dwMtu, 1 );
285
286 if( Adapter && Table->table[i].dwType == MIB_IF_TYPE_ETHERNET && InterfaceConnected(Table->table[i])) {
287 memcpy( &Adapter->IfMib, &Table->table[i],
288 sizeof(Adapter->IfMib) );
289 Adapter->DhclientInfo.client = &Adapter->DhclientState;
290 Adapter->DhclientInfo.rbuf = Adapter->recv_buf;
291 Adapter->DhclientInfo.rbuf_max = Table->table[i].dwMtu;
292 Adapter->DhclientInfo.rbuf_len =
293 Adapter->DhclientInfo.rbuf_offset = 0;
294 memcpy(Adapter->DhclientInfo.hw_address.haddr,
295 Adapter->IfMib.bPhysAddr,
296 Adapter->IfMib.dwPhysAddrLen);
297 Adapter->DhclientInfo.hw_address.hlen = Adapter->IfMib.dwPhysAddrLen;
298
299 /* I'm not sure where else to set this, but
300 some DHCP servers won't take a zero.
301 We checked the hardware type earlier in
302 the if statement. */
303 Adapter->DhclientInfo.hw_address.htype = HTYPE_ETHER;
304
305 if( DhcpSocket == INVALID_SOCKET ) {
306 DhcpSocket =
307 Adapter->DhclientInfo.rfdesc =
308 Adapter->DhclientInfo.wfdesc =
309 socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
310
311 if (DhcpSocket != INVALID_SOCKET) {
312 Adapter->ListenAddr.sin_family = AF_INET;
313 Adapter->ListenAddr.sin_port = htons(LOCAL_PORT);
314 Adapter->BindStatus =
315 (bind( Adapter->DhclientInfo.rfdesc,
316 (struct sockaddr *)&Adapter->ListenAddr,
317 sizeof(Adapter->ListenAddr) ) == 0) ?
318 0 : WSAGetLastError();
319 } else {
320 error("socket() failed: %d\n", WSAGetLastError());
321 }
322 } else {
323 Adapter->DhclientInfo.rfdesc =
324 Adapter->DhclientInfo.wfdesc = DhcpSocket;
325 }
326
327 Adapter->DhclientConfig.timeout = DHCP_PANIC_TIMEOUT;
328 Adapter->DhclientConfig.initial_interval = DHCP_DISCOVER_INTERVAL;
329 Adapter->DhclientConfig.retry_interval = DHCP_DISCOVER_INTERVAL;
330 Adapter->DhclientConfig.select_interval = 1;
331 Adapter->DhclientConfig.reboot_timeout = DHCP_REBOOT_TIMEOUT;
332 Adapter->DhclientConfig.backoff_cutoff = DHCP_BACKOFF_MAX;
333 Adapter->DhclientState.interval =
334 Adapter->DhclientConfig.retry_interval;
335
336 if( PrepareAdapterForService( Adapter ) ) {
337 Adapter->DhclientInfo.next = ifi;
338 ifi = &Adapter->DhclientInfo;
339
340 read_client_conf(&Adapter->DhclientInfo);
341
342 if (Adapter->DhclientInfo.client->state == S_INIT)
343 {
344 add_protocol(Adapter->DhclientInfo.name,
345 Adapter->DhclientInfo.rfdesc,
346 got_one, &Adapter->DhclientInfo);
347
348 state_init(&Adapter->DhclientInfo);
349 }
350
351 ApiLock();
352 InsertTailList( &AdapterList, &Adapter->ListEntry );
353 DbgPrint("DHCPCSVC: Discovered new adapter [%s]\n", Adapter->DhclientInfo.name);
354 AdapterCount++;
355 SetEvent(AdapterStateChangedEvent);
356 ApiUnlock();
357 } else { free( Adapter ); Adapter = 0; }
358 } else { free( Adapter ); Adapter = 0; }
359
360 if( !Adapter )
361 DH_DbgPrint(MID_TRACE,("Adapter %d was rejected\n",
362 Table->table[i].dwIndex));
363 }
364 Error = NotifyAddrChange(NULL, NULL);
365 #if 0
366 if (Error != NO_ERROR)
367 break;
368 #else
369 if (AdapterCount)
370 break;
371 else
372 Sleep(3000);
373 #endif
374 } while (TRUE);
375
376 DbgPrint("DHCPCSVC: Adapter discovery thread is terminating! (Error: %d)\n", Error);
377
378 if( Table ) free( Table );
379 return Error;
380 }
381
382 HANDLE StartAdapterDiscovery(VOID) {
383 HANDLE /* ThreadHandle, */ EventHandle;
384
385 EventHandle = CreateEvent(NULL,
386 FALSE,
387 FALSE,
388 NULL);
389
390 #if 0
391 ThreadHandle = CreateThread(NULL,
392 0,
393 AdapterDiscoveryThread,
394 (LPVOID)EventHandle,
395 0,
396 NULL);
397
398 if (ThreadHandle == NULL)
399 return NULL;
400
401 CloseHandle(ThreadHandle);
402 #else
403 AdapterDiscoveryThread((LPVOID)EventHandle);
404 #endif
405
406 return EventHandle;
407 }
408
409 void AdapterStop() {
410 PLIST_ENTRY ListEntry;
411 PDHCP_ADAPTER Adapter;
412 ApiLock();
413 while( !IsListEmpty( &AdapterList ) ) {
414 ListEntry = (PLIST_ENTRY)RemoveHeadList( &AdapterList );
415 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
416 free( Adapter );
417 }
418 ApiUnlock();
419 WSACleanup();
420 }
421
422 PDHCP_ADAPTER AdapterFindIndex( unsigned int indx ) {
423 PDHCP_ADAPTER Adapter;
424 PLIST_ENTRY ListEntry;
425
426 for( ListEntry = AdapterList.Flink;
427 ListEntry != &AdapterList;
428 ListEntry = ListEntry->Flink ) {
429 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
430 if( Adapter->IfMib.dwIndex == indx ) return Adapter;
431 }
432
433 return NULL;
434 }
435
436 PDHCP_ADAPTER AdapterFindName( const WCHAR *name ) {
437 PDHCP_ADAPTER Adapter;
438 PLIST_ENTRY ListEntry;
439
440 for( ListEntry = AdapterList.Flink;
441 ListEntry != &AdapterList;
442 ListEntry = ListEntry->Flink ) {
443 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
444 if( !wcsicmp( Adapter->IfMib.wszName, name ) ) return Adapter;
445 }
446
447 return NULL;
448 }
449
450 PDHCP_ADAPTER AdapterFindInfo( struct interface_info *ip ) {
451 PDHCP_ADAPTER Adapter;
452 PLIST_ENTRY ListEntry;
453
454 for( ListEntry = AdapterList.Flink;
455 ListEntry != &AdapterList;
456 ListEntry = ListEntry->Flink ) {
457 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
458 if( ip == &Adapter->DhclientInfo ) return Adapter;
459 }
460
461 return NULL;
462 }
463
464 PDHCP_ADAPTER AdapterFindByHardwareAddress( u_int8_t haddr[16], u_int8_t hlen ) {
465 PDHCP_ADAPTER Adapter;
466 PLIST_ENTRY ListEntry;
467
468 for(ListEntry = AdapterList.Flink;
469 ListEntry != &AdapterList;
470 ListEntry = ListEntry->Flink) {
471 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
472 if (Adapter->DhclientInfo.hw_address.hlen == hlen &&
473 !memcmp(Adapter->DhclientInfo.hw_address.haddr,
474 haddr,
475 hlen)) return Adapter;
476 }
477
478 return NULL;
479 }
480
481 PDHCP_ADAPTER AdapterGetFirst() {
482 if( IsListEmpty( &AdapterList ) ) return NULL; else {
483 return CONTAINING_RECORD
484 ( AdapterList.Flink, DHCP_ADAPTER, ListEntry );
485 }
486 }
487
488 PDHCP_ADAPTER AdapterGetNext( PDHCP_ADAPTER This )
489 {
490 if( This->ListEntry.Flink == &AdapterList ) return NULL;
491 return CONTAINING_RECORD
492 ( This->ListEntry.Flink, DHCP_ADAPTER, ListEntry );
493 }
494
495 void if_register_send(struct interface_info *ip) {
496
497 }
498
499 void if_register_receive(struct interface_info *ip) {
500 }