xref: /reactos/base/services/dhcpcsvc/dhcp/adapter.c (revision e4930be4)
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 
GetSubkeyNames(PCHAR MainKeyName,PCHAR Append)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 
RegReadString(HKEY Root,PCHAR Subkey,PCHAR Value)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 
FindAdapterKey(PDHCP_ADAPTER Adapter)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 
PrepareAdapterForService(PDHCP_ADAPTER Adapter)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 
AdapterInit()192 void AdapterInit() {
193     WSAStartup(0x0101,&wsd);
194 
195     InitializeListHead( &AdapterList );
196 }
197 
198 int
InterfaceConnected(const MIB_IFROW * IfEntry)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
IsReconnectHackNeeded(PDHCP_ADAPTER Adapter,const MIB_IFROW * IfEntry)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  */
AdapterDiscoveryThread(LPVOID Context)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 
StartAdapterDiscovery(HANDLE hStopEvent)481 HANDLE StartAdapterDiscovery(HANDLE hStopEvent) {
482     return CreateThread(NULL, 0, AdapterDiscoveryThread, (LPVOID)hStopEvent, 0, NULL);
483 }
484 
AdapterStop()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 
AdapterFindIndex(unsigned int indx)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 
AdapterFindName(const WCHAR * name)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 
AdapterFindInfo(struct interface_info * ip)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 
AdapterFindByHardwareAddress(u_int8_t haddr[16],u_int8_t hlen)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 
AdapterGetFirst()557 PDHCP_ADAPTER AdapterGetFirst() {
558     if( IsListEmpty( &AdapterList ) ) return NULL; else {
559         return CONTAINING_RECORD
560             ( AdapterList.Flink, DHCP_ADAPTER, ListEntry );
561     }
562 }
563 
AdapterGetNext(PDHCP_ADAPTER This)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 
if_register_send(struct interface_info * ip)571 void if_register_send(struct interface_info *ip) {
572 
573 }
574 
if_register_receive(struct interface_info * ip)575 void if_register_receive(struct interface_info *ip) {
576 }
577