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 } 577