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