1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * FILE: lib/dhcpcapi/dhcpcapi.c 5 * PURPOSE: Client API for DHCP 6 * COPYRIGHT: Copyright 2005 Art Yerkes <ayerkes@speakeasy.net> 7 */ 8 9 #include <rosdhcp.h> 10 #include <winsvc.h> 11 12 #define NDEBUG 13 #include <debug.h> 14 15 static WCHAR ServiceName[] = L"DHCP"; 16 17 SERVICE_STATUS_HANDLE ServiceStatusHandle = 0; 18 SERVICE_STATUS ServiceStatus; 19 HANDLE hStopEvent = NULL; 20 HANDLE hAdapterStateChangedEvent = NULL; 21 22 static HANDLE PipeHandle = INVALID_HANDLE_VALUE; 23 extern SOCKET DhcpSocket; 24 25 DWORD APIENTRY 26 DhcpCApiInitialize(LPDWORD Version) 27 { 28 DWORD PipeMode; 29 30 /* Wait for the pipe to be available */ 31 if (!WaitNamedPipeW(DHCP_PIPE_NAME, NMPWAIT_USE_DEFAULT_WAIT)) 32 { 33 /* No good, we failed */ 34 return GetLastError(); 35 } 36 37 /* It's available, let's try to open it */ 38 PipeHandle = CreateFileW(DHCP_PIPE_NAME, 39 GENERIC_READ | GENERIC_WRITE, 40 FILE_SHARE_READ | FILE_SHARE_WRITE, 41 NULL, 42 OPEN_EXISTING, 43 0, 44 NULL); 45 46 /* Check if we succeeded in opening the pipe */ 47 if (PipeHandle == INVALID_HANDLE_VALUE) 48 { 49 /* We didn't */ 50 return GetLastError(); 51 } 52 53 /* Change the pipe into message mode */ 54 PipeMode = PIPE_READMODE_MESSAGE; 55 if (!SetNamedPipeHandleState(PipeHandle, &PipeMode, NULL, NULL)) 56 { 57 /* Mode change failed */ 58 CloseHandle(PipeHandle); 59 PipeHandle = INVALID_HANDLE_VALUE; 60 return GetLastError(); 61 } 62 else 63 { 64 /* We're good to go */ 65 *Version = 2; 66 return NO_ERROR; 67 } 68 } 69 70 VOID APIENTRY 71 DhcpCApiCleanup(VOID) 72 { 73 CloseHandle(PipeHandle); 74 PipeHandle = INVALID_HANDLE_VALUE; 75 } 76 77 DWORD APIENTRY 78 DhcpQueryHWInfo(DWORD AdapterIndex, 79 PDWORD MediaType, 80 PDWORD Mtu, 81 PDWORD Speed) 82 { 83 COMM_DHCP_REQ Req; 84 COMM_DHCP_REPLY Reply; 85 DWORD BytesRead; 86 BOOL Result; 87 88 ASSERT(PipeHandle != INVALID_HANDLE_VALUE); 89 90 Req.Type = DhcpReqQueryHWInfo; 91 Req.AdapterIndex = AdapterIndex; 92 93 Result = TransactNamedPipe(PipeHandle, 94 &Req, sizeof(Req), 95 &Reply, sizeof(Reply), 96 &BytesRead, NULL); 97 if (!Result) 98 { 99 /* Pipe transaction failed */ 100 return 0; 101 } 102 103 if (Reply.Reply == 0) 104 return 0; 105 106 *MediaType = Reply.QueryHWInfo.MediaType; 107 *Mtu = Reply.QueryHWInfo.Mtu; 108 *Speed = Reply.QueryHWInfo.Speed; 109 return 1; 110 } 111 112 DWORD APIENTRY 113 DhcpLeaseIpAddress(DWORD AdapterIndex) 114 { 115 COMM_DHCP_REQ Req; 116 COMM_DHCP_REPLY Reply; 117 DWORD BytesRead; 118 BOOL Result; 119 120 ASSERT(PipeHandle != INVALID_HANDLE_VALUE); 121 122 Req.Type = DhcpReqLeaseIpAddress; 123 Req.AdapterIndex = AdapterIndex; 124 125 Result = TransactNamedPipe(PipeHandle, 126 &Req, sizeof(Req), 127 &Reply, sizeof(Reply), 128 &BytesRead, NULL); 129 if (!Result) 130 { 131 /* Pipe transaction failed */ 132 return 0; 133 } 134 135 return Reply.Reply; 136 } 137 138 DWORD APIENTRY 139 DhcpReleaseIpAddressLease(DWORD AdapterIndex) 140 { 141 COMM_DHCP_REQ Req; 142 COMM_DHCP_REPLY Reply; 143 DWORD BytesRead; 144 BOOL Result; 145 146 ASSERT(PipeHandle != INVALID_HANDLE_VALUE); 147 148 Req.Type = DhcpReqReleaseIpAddress; 149 Req.AdapterIndex = AdapterIndex; 150 151 Result = TransactNamedPipe(PipeHandle, 152 &Req, sizeof(Req), 153 &Reply, sizeof(Reply), 154 &BytesRead, NULL); 155 if (!Result) 156 { 157 /* Pipe transaction failed */ 158 return 0; 159 } 160 161 return Reply.Reply; 162 } 163 164 DWORD APIENTRY 165 DhcpRenewIpAddressLease(DWORD AdapterIndex) 166 { 167 COMM_DHCP_REQ Req; 168 COMM_DHCP_REPLY Reply; 169 DWORD BytesRead; 170 BOOL Result; 171 172 ASSERT(PipeHandle != INVALID_HANDLE_VALUE); 173 174 Req.Type = DhcpReqRenewIpAddress; 175 Req.AdapterIndex = AdapterIndex; 176 177 Result = TransactNamedPipe(PipeHandle, 178 &Req, sizeof(Req), 179 &Reply, sizeof(Reply), 180 &BytesRead, NULL); 181 if (!Result) 182 { 183 /* Pipe transaction failed */ 184 return 0; 185 } 186 187 return Reply.Reply; 188 } 189 190 DWORD APIENTRY 191 DhcpStaticRefreshParams(DWORD AdapterIndex, 192 DWORD Address, 193 DWORD Netmask) 194 { 195 COMM_DHCP_REQ Req; 196 COMM_DHCP_REPLY Reply; 197 DWORD BytesRead; 198 BOOL Result; 199 200 ASSERT(PipeHandle != INVALID_HANDLE_VALUE); 201 202 Req.Type = DhcpReqStaticRefreshParams; 203 Req.AdapterIndex = AdapterIndex; 204 Req.Body.StaticRefreshParams.IPAddress = Address; 205 Req.Body.StaticRefreshParams.Netmask = Netmask; 206 207 Result = TransactNamedPipe(PipeHandle, 208 &Req, sizeof(Req), 209 &Reply, sizeof(Reply), 210 &BytesRead, NULL); 211 if (!Result) 212 { 213 /* Pipe transaction failed */ 214 return 0; 215 } 216 217 return Reply.Reply; 218 } 219 220 /*! 221 * Set new TCP/IP parameters and notify DHCP client service of this 222 * 223 * \param[in] ServerName 224 * NULL for local machine 225 * 226 * \param[in] AdapterName 227 * IPHLPAPI name of adapter to change 228 * 229 * \param[in] NewIpAddress 230 * TRUE if IP address changes 231 * 232 * \param[in] IpAddress 233 * New IP address (network byte order) 234 * 235 * \param[in] SubnetMask 236 * New subnet mask (network byte order) 237 * 238 * \param[in] DhcpAction 239 * 0 - don't modify 240 * 1 - enable DHCP 241 * 2 - disable DHCP 242 * 243 * \return non-zero on success 244 * 245 * \remarks Undocumented by Microsoft 246 */ 247 DWORD APIENTRY 248 DhcpNotifyConfigChange(LPWSTR ServerName, 249 LPWSTR AdapterName, 250 BOOL NewIpAddress, 251 DWORD IpIndex, 252 DWORD IpAddress, 253 DWORD SubnetMask, 254 INT DhcpAction) 255 { 256 DPRINT1("DHCPCSVC: DhcpNotifyConfigChange not implemented yet\n"); 257 return 0; 258 } 259 260 DWORD APIENTRY 261 DhcpRequestParams(DWORD Flags, 262 PVOID Reserved, 263 LPWSTR AdapterName, 264 LPDHCPCAPI_CLASSID ClassId, 265 DHCPCAPI_PARAMS_ARRAY SendParams, 266 DHCPCAPI_PARAMS_ARRAY RecdParams, 267 LPBYTE Buffer, 268 LPDWORD pSize, 269 LPWSTR RequestIdStr) 270 { 271 UNIMPLEMENTED; 272 return 0; 273 } 274 275 /*! 276 * Get DHCP info for an adapter 277 * 278 * \param[in] AdapterIndex 279 * Index of the adapter (iphlpapi-style) for which info is 280 * requested 281 * 282 * \param[out] DhcpEnabled 283 * Returns whether DHCP is enabled for the adapter 284 * 285 * \param[out] DhcpServer 286 * Returns DHCP server IP address (255.255.255.255 if no 287 * server reached yet), in network byte order 288 * 289 * \param[out] LeaseObtained 290 * Returns time at which the lease was obtained 291 * 292 * \param[out] LeaseExpires 293 * Returns time at which the lease will expire 294 * 295 * \return non-zero on success 296 * 297 * \remarks This is a ReactOS-only routine 298 */ 299 DWORD APIENTRY 300 DhcpRosGetAdapterInfo(DWORD AdapterIndex, 301 PBOOL DhcpEnabled, 302 PDWORD DhcpServer, 303 time_t* LeaseObtained, 304 time_t* LeaseExpires) 305 { 306 COMM_DHCP_REQ Req; 307 COMM_DHCP_REPLY Reply; 308 DWORD BytesRead; 309 BOOL Result; 310 311 ASSERT(PipeHandle != INVALID_HANDLE_VALUE); 312 313 Req.Type = DhcpReqGetAdapterInfo; 314 Req.AdapterIndex = AdapterIndex; 315 316 Result = TransactNamedPipe(PipeHandle, 317 &Req, sizeof(Req), 318 &Reply, sizeof(Reply), 319 &BytesRead, NULL); 320 321 if (Result && Reply.Reply != 0) 322 *DhcpEnabled = Reply.GetAdapterInfo.DhcpEnabled; 323 else 324 *DhcpEnabled = FALSE; 325 326 if (*DhcpEnabled) 327 { 328 *DhcpServer = Reply.GetAdapterInfo.DhcpServer; 329 *LeaseObtained = Reply.GetAdapterInfo.LeaseObtained; 330 *LeaseExpires = Reply.GetAdapterInfo.LeaseExpires; 331 } 332 else 333 { 334 *DhcpServer = INADDR_NONE; 335 *LeaseObtained = 0; 336 *LeaseExpires = 0; 337 } 338 339 return Reply.Reply; 340 } 341 342 343 static VOID 344 UpdateServiceStatus(DWORD dwState) 345 { 346 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 347 ServiceStatus.dwCurrentState = dwState; 348 349 if (dwState == SERVICE_RUNNING) 350 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP; 351 else 352 ServiceStatus.dwControlsAccepted = 0; 353 354 ServiceStatus.dwWin32ExitCode = 0; 355 ServiceStatus.dwServiceSpecificExitCode = 0; 356 ServiceStatus.dwCheckPoint = 0; 357 358 if (dwState == SERVICE_START_PENDING || 359 dwState == SERVICE_STOP_PENDING) 360 ServiceStatus.dwWaitHint = 1000; 361 else 362 ServiceStatus.dwWaitHint = 0; 363 364 SetServiceStatus(ServiceStatusHandle, 365 &ServiceStatus); 366 } 367 368 static DWORD WINAPI 369 ServiceControlHandler(DWORD dwControl, 370 DWORD dwEventType, 371 LPVOID lpEventData, 372 LPVOID lpContext) 373 { 374 switch (dwControl) 375 { 376 case SERVICE_CONTROL_STOP: 377 case SERVICE_CONTROL_SHUTDOWN: 378 UpdateServiceStatus(SERVICE_STOP_PENDING); 379 if (hStopEvent != NULL) 380 SetEvent(hStopEvent); 381 return ERROR_SUCCESS; 382 383 case SERVICE_CONTROL_INTERROGATE: 384 SetServiceStatus(ServiceStatusHandle, 385 &ServiceStatus); 386 return ERROR_SUCCESS; 387 388 default: 389 return ERROR_CALL_NOT_IMPLEMENTED; 390 } 391 } 392 393 VOID WINAPI 394 ServiceMain(DWORD argc, LPWSTR* argv) 395 { 396 HANDLE hPipeThread = INVALID_HANDLE_VALUE; 397 HANDLE hDiscoveryThread = INVALID_HANDLE_VALUE; 398 DWORD ret; 399 400 ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName, 401 ServiceControlHandler, 402 NULL); 403 if (!ServiceStatusHandle) 404 { 405 DPRINT1("DHCPCSVC: Unable to register service control handler (%lx)\n", GetLastError()); 406 return; 407 } 408 409 UpdateServiceStatus(SERVICE_START_PENDING); 410 411 /* Create the stop event */ 412 hStopEvent = CreateEventW(NULL, TRUE, FALSE, NULL); 413 if (hStopEvent == NULL) 414 { 415 UpdateServiceStatus(SERVICE_STOPPED); 416 return; 417 } 418 419 hAdapterStateChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 420 if (hAdapterStateChangedEvent == NULL) 421 { 422 CloseHandle(hStopEvent); 423 UpdateServiceStatus(SERVICE_STOPPED); 424 return; 425 } 426 427 UpdateServiceStatus(SERVICE_START_PENDING); 428 429 if (!init_client()) 430 { 431 DbgPrint("DHCPCSVC: init_client() failed!\n"); 432 CloseHandle(hAdapterStateChangedEvent); 433 CloseHandle(hStopEvent); 434 UpdateServiceStatus(SERVICE_STOPPED); 435 return; 436 } 437 438 UpdateServiceStatus(SERVICE_START_PENDING); 439 440 hPipeThread = PipeInit(hStopEvent); 441 if (hPipeThread == INVALID_HANDLE_VALUE) 442 { 443 DbgPrint("DHCPCSVC: PipeInit() failed!\n"); 444 stop_client(); 445 CloseHandle(hAdapterStateChangedEvent); 446 CloseHandle(hStopEvent); 447 UpdateServiceStatus(SERVICE_STOPPED); 448 return; 449 } 450 451 hDiscoveryThread = StartAdapterDiscovery(hStopEvent); 452 if (hDiscoveryThread == INVALID_HANDLE_VALUE) 453 { 454 DbgPrint("DHCPCSVC: StartAdapterDiscovery() failed!\n"); 455 stop_client(); 456 CloseHandle(hAdapterStateChangedEvent); 457 CloseHandle(hStopEvent); 458 UpdateServiceStatus(SERVICE_STOPPED); 459 return; 460 } 461 462 DH_DbgPrint(MID_TRACE,("DHCP Service Started\n")); 463 464 UpdateServiceStatus(SERVICE_RUNNING); 465 466 DH_DbgPrint(MID_TRACE,("Going into dispatch()\n")); 467 DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is starting up\n")); 468 469 dispatch(hStopEvent); 470 471 DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is shutting down\n")); 472 473 stop_client(); 474 475 DPRINT("Wait for pipe thread to close! %p\n", hPipeThread); 476 if (hPipeThread != INVALID_HANDLE_VALUE) 477 { 478 DPRINT("Waiting for pipe thread\n"); 479 ret = WaitForSingleObject(hPipeThread, 5000); 480 DPRINT("Done %lx\n", ret); 481 } 482 483 DPRINT("Wait for discovery thread to close! %p\n", hDiscoveryThread); 484 if (hDiscoveryThread != INVALID_HANDLE_VALUE) 485 { 486 DPRINT("Waiting for discovery thread\n"); 487 ret = WaitForSingleObject(hDiscoveryThread, 5000); 488 DPRINT("Done %lx\n", ret); 489 } 490 491 DPRINT("Closing events!\n"); 492 CloseHandle(hAdapterStateChangedEvent); 493 CloseHandle(hStopEvent); 494 495 if (DhcpSocket != INVALID_SOCKET) 496 closesocket(DhcpSocket); 497 498 CloseHandle(hDiscoveryThread); 499 CloseHandle(hPipeThread); 500 501 DPRINT("Done!\n"); 502 503 UpdateServiceStatus(SERVICE_STOPPED); 504 } 505 506 BOOL WINAPI 507 DllMain(HINSTANCE hinstDLL, 508 DWORD fdwReason, 509 LPVOID lpvReserved) 510 { 511 switch (fdwReason) 512 { 513 case DLL_PROCESS_ATTACH: 514 DisableThreadLibraryCalls(hinstDLL); 515 break; 516 517 case DLL_PROCESS_DETACH: 518 break; 519 } 520 521 return TRUE; 522 } 523 524 /* EOF */ 525