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 if (EventHandle == NULL) 480 return NULL; 481 482 ThreadHandle = CreateThread(NULL, 483 0, 484 AdapterDiscoveryThread, 485 (LPVOID)EventHandle, 486 0, 487 NULL); 488 489 if (ThreadHandle == NULL) 490 { 491 CloseHandle(EventHandle); 492 return NULL; 493 } 494 495 CloseHandle(ThreadHandle); 496 497 return EventHandle; 498 } 499 500 void AdapterStop() { 501 PLIST_ENTRY ListEntry; 502 PDHCP_ADAPTER Adapter; 503 ApiLock(); 504 while( !IsListEmpty( &AdapterList ) ) { 505 ListEntry = (PLIST_ENTRY)RemoveHeadList( &AdapterList ); 506 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry ); 507 free( Adapter ); 508 } 509 ApiUnlock(); 510 WSACleanup(); 511 } 512 513 PDHCP_ADAPTER AdapterFindIndex( unsigned int indx ) { 514 PDHCP_ADAPTER Adapter; 515 PLIST_ENTRY ListEntry; 516 517 for( ListEntry = AdapterList.Flink; 518 ListEntry != &AdapterList; 519 ListEntry = ListEntry->Flink ) { 520 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry ); 521 if( Adapter->IfMib.dwIndex == indx ) return Adapter; 522 } 523 524 return NULL; 525 } 526 527 PDHCP_ADAPTER AdapterFindName( const WCHAR *name ) { 528 PDHCP_ADAPTER Adapter; 529 PLIST_ENTRY ListEntry; 530 531 for( ListEntry = AdapterList.Flink; 532 ListEntry != &AdapterList; 533 ListEntry = ListEntry->Flink ) { 534 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry ); 535 if( !wcsicmp( Adapter->IfMib.wszName, name ) ) return Adapter; 536 } 537 538 return NULL; 539 } 540 541 PDHCP_ADAPTER AdapterFindInfo( struct interface_info *ip ) { 542 PDHCP_ADAPTER Adapter; 543 PLIST_ENTRY ListEntry; 544 545 for( ListEntry = AdapterList.Flink; 546 ListEntry != &AdapterList; 547 ListEntry = ListEntry->Flink ) { 548 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry ); 549 if( ip == &Adapter->DhclientInfo ) return Adapter; 550 } 551 552 return NULL; 553 } 554 555 PDHCP_ADAPTER AdapterFindByHardwareAddress( u_int8_t haddr[16], u_int8_t hlen ) { 556 PDHCP_ADAPTER Adapter; 557 PLIST_ENTRY ListEntry; 558 559 for(ListEntry = AdapterList.Flink; 560 ListEntry != &AdapterList; 561 ListEntry = ListEntry->Flink) { 562 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry ); 563 if (Adapter->DhclientInfo.hw_address.hlen == hlen && 564 !memcmp(Adapter->DhclientInfo.hw_address.haddr, 565 haddr, 566 hlen)) return Adapter; 567 } 568 569 return NULL; 570 } 571 572 PDHCP_ADAPTER AdapterGetFirst() { 573 if( IsListEmpty( &AdapterList ) ) return NULL; else { 574 return CONTAINING_RECORD 575 ( AdapterList.Flink, DHCP_ADAPTER, ListEntry ); 576 } 577 } 578 579 PDHCP_ADAPTER AdapterGetNext( PDHCP_ADAPTER This ) 580 { 581 if( This->ListEntry.Flink == &AdapterList ) return NULL; 582 return CONTAINING_RECORD 583 ( This->ListEntry.Flink, DHCP_ADAPTER, ListEntry ); 584 } 585 586 void if_register_send(struct interface_info *ip) { 587 588 } 589 590 void if_register_receive(struct interface_info *ip) { 591 } 592