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 DWORD APIENTRY 259 DhcpRequestParams(DWORD Flags, 260 PVOID Reserved, 261 LPWSTR AdapterName, 262 LPDHCPCAPI_CLASSID ClassId, 263 DHCPCAPI_PARAMS_ARRAY SendParams, 264 DHCPCAPI_PARAMS_ARRAY RecdParams, 265 LPBYTE Buffer, 266 LPDWORD pSize, 267 LPWSTR RequestIdStr) 268 { 269 UNIMPLEMENTED; 270 return 0; 271 } 272 273 /*! 274 * Get DHCP info for an adapter 275 * 276 * \param[in] AdapterIndex 277 * Index of the adapter (iphlpapi-style) for which info is 278 * requested 279 * 280 * \param[out] DhcpEnabled 281 * Returns whether DHCP is enabled for the adapter 282 * 283 * \param[out] DhcpServer 284 * Returns DHCP server IP address (255.255.255.255 if no 285 * server reached yet), in network byte order 286 * 287 * \param[out] LeaseObtained 288 * Returns time at which the lease was obtained 289 * 290 * \param[out] LeaseExpires 291 * Returns time at which the lease will expire 292 * 293 * \return non-zero on success 294 * 295 * \remarks This is a ReactOS-only routine 296 */ 297 DWORD APIENTRY 298 DhcpRosGetAdapterInfo(DWORD AdapterIndex, 299 PBOOL DhcpEnabled, 300 PDWORD DhcpServer, 301 time_t* LeaseObtained, 302 time_t* LeaseExpires) 303 { 304 COMM_DHCP_REQ Req; 305 COMM_DHCP_REPLY Reply; 306 DWORD BytesRead; 307 BOOL Result; 308 309 ASSERT(PipeHandle != INVALID_HANDLE_VALUE); 310 311 Req.Type = DhcpReqGetAdapterInfo; 312 Req.AdapterIndex = AdapterIndex; 313 314 Result = TransactNamedPipe(PipeHandle, 315 &Req, sizeof(Req), 316 &Reply, sizeof(Reply), 317 &BytesRead, NULL); 318 319 if (Result && Reply.Reply != 0) 320 *DhcpEnabled = Reply.GetAdapterInfo.DhcpEnabled; 321 else 322 *DhcpEnabled = FALSE; 323 324 if (*DhcpEnabled) 325 { 326 *DhcpServer = Reply.GetAdapterInfo.DhcpServer; 327 *LeaseObtained = Reply.GetAdapterInfo.LeaseObtained; 328 *LeaseExpires = Reply.GetAdapterInfo.LeaseExpires; 329 } 330 else 331 { 332 *DhcpServer = INADDR_NONE; 333 *LeaseObtained = 0; 334 *LeaseExpires = 0; 335 } 336 337 return Reply.Reply; 338 } 339 340 341 static VOID 342 UpdateServiceStatus(DWORD dwState) 343 { 344 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 345 ServiceStatus.dwCurrentState = dwState; 346 347 if (dwState == SERVICE_RUNNING) 348 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP; 349 else 350 ServiceStatus.dwControlsAccepted = 0; 351 352 ServiceStatus.dwWin32ExitCode = 0; 353 ServiceStatus.dwServiceSpecificExitCode = 0; 354 ServiceStatus.dwCheckPoint = 0; 355 356 if (dwState == SERVICE_START_PENDING || 357 dwState == SERVICE_STOP_PENDING) 358 ServiceStatus.dwWaitHint = 1000; 359 else 360 ServiceStatus.dwWaitHint = 0; 361 362 SetServiceStatus(ServiceStatusHandle, 363 &ServiceStatus); 364 } 365 366 static DWORD WINAPI 367 ServiceControlHandler(DWORD dwControl, 368 DWORD dwEventType, 369 LPVOID lpEventData, 370 LPVOID lpContext) 371 { 372 switch (dwControl) 373 { 374 case SERVICE_CONTROL_STOP: 375 case SERVICE_CONTROL_SHUTDOWN: 376 UpdateServiceStatus(SERVICE_STOP_PENDING); 377 if (hStopEvent != NULL) 378 SetEvent(hStopEvent); 379 return ERROR_SUCCESS; 380 381 case SERVICE_CONTROL_INTERROGATE: 382 SetServiceStatus(ServiceStatusHandle, 383 &ServiceStatus); 384 return ERROR_SUCCESS; 385 386 default: 387 return ERROR_CALL_NOT_IMPLEMENTED; 388 } 389 } 390 391 VOID WINAPI 392 ServiceMain(DWORD argc, LPWSTR* argv) 393 { 394 ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName, 395 ServiceControlHandler, 396 NULL); 397 if (!ServiceStatusHandle) 398 { 399 DPRINT1("DHCPCSVC: Unable to register service control handler (%lx)\n", GetLastError()); 400 return; 401 } 402 403 UpdateServiceStatus(SERVICE_START_PENDING); 404 405 /* Create the stop event */ 406 hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL); 407 if (hStopEvent == NULL) 408 { 409 UpdateServiceStatus(SERVICE_STOPPED); 410 return; 411 } 412 413 UpdateServiceStatus(SERVICE_START_PENDING); 414 415 if (!init_client()) 416 { 417 DPRINT1("DHCPCSVC: init_client() failed!\n"); 418 UpdateServiceStatus(SERVICE_STOPPED); 419 return; 420 } 421 422 DH_DbgPrint(MID_TRACE,("DHCP Service Started\n")); 423 424 UpdateServiceStatus(SERVICE_RUNNING); 425 426 DH_DbgPrint(MID_TRACE,("Going into dispatch()\n")); 427 DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is starting up\n")); 428 429 dispatch(hStopEvent); 430 431 DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is shutting down\n")); 432 stop_client(); 433 434 UpdateServiceStatus(SERVICE_STOPPED); 435 } 436 437 BOOL WINAPI 438 DllMain(HINSTANCE hinstDLL, 439 DWORD fdwReason, 440 LPVOID lpvReserved) 441 { 442 switch (fdwReason) 443 { 444 case DLL_PROCESS_ATTACH: 445 DisableThreadLibraryCalls(hinstDLL); 446 break; 447 448 case DLL_PROCESS_DETACH: 449 break; 450 } 451 452 return TRUE; 453 } 454 455 /* EOF */ 456