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>
15 static WCHAR ServiceName
[] = L
"DHCP";
17 SERVICE_STATUS_HANDLE ServiceStatusHandle
= 0;
18 SERVICE_STATUS ServiceStatus
;
19 HANDLE hStopEvent
= NULL
;
20 HANDLE hAdapterStateChangedEvent
= NULL
;
22 static HANDLE PipeHandle
= INVALID_HANDLE_VALUE
;
23 extern SOCKET DhcpSocket
;
26 DhcpCApiInitialize(LPDWORD Version
)
30 /* Wait for the pipe to be available */
31 if (!WaitNamedPipeW(DHCP_PIPE_NAME
, NMPWAIT_USE_DEFAULT_WAIT
))
33 /* No good, we failed */
34 return GetLastError();
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
,
46 /* Check if we succeeded in opening the pipe */
47 if (PipeHandle
== INVALID_HANDLE_VALUE
)
50 return GetLastError();
53 /* Change the pipe into message mode */
54 PipeMode
= PIPE_READMODE_MESSAGE
;
55 if (!SetNamedPipeHandleState(PipeHandle
, &PipeMode
, NULL
, NULL
))
57 /* Mode change failed */
58 CloseHandle(PipeHandle
);
59 PipeHandle
= INVALID_HANDLE_VALUE
;
60 return GetLastError();
64 /* We're good to go */
73 CloseHandle(PipeHandle
);
74 PipeHandle
= INVALID_HANDLE_VALUE
;
78 DhcpQueryHWInfo(DWORD AdapterIndex
,
84 COMM_DHCP_REPLY Reply
;
88 ASSERT(PipeHandle
!= INVALID_HANDLE_VALUE
);
90 Req
.Type
= DhcpReqQueryHWInfo
;
91 Req
.AdapterIndex
= AdapterIndex
;
93 Result
= TransactNamedPipe(PipeHandle
,
95 &Reply
, sizeof(Reply
),
99 /* Pipe transaction failed */
103 if (Reply
.Reply
== 0)
106 *MediaType
= Reply
.QueryHWInfo
.MediaType
;
107 *Mtu
= Reply
.QueryHWInfo
.Mtu
;
108 *Speed
= Reply
.QueryHWInfo
.Speed
;
113 DhcpLeaseIpAddress(DWORD AdapterIndex
)
116 COMM_DHCP_REPLY Reply
;
120 ASSERT(PipeHandle
!= INVALID_HANDLE_VALUE
);
122 Req
.Type
= DhcpReqLeaseIpAddress
;
123 Req
.AdapterIndex
= AdapterIndex
;
125 Result
= TransactNamedPipe(PipeHandle
,
127 &Reply
, sizeof(Reply
),
131 /* Pipe transaction failed */
139 DhcpReleaseIpAddressLease(DWORD AdapterIndex
)
142 COMM_DHCP_REPLY Reply
;
146 ASSERT(PipeHandle
!= INVALID_HANDLE_VALUE
);
148 Req
.Type
= DhcpReqReleaseIpAddress
;
149 Req
.AdapterIndex
= AdapterIndex
;
151 Result
= TransactNamedPipe(PipeHandle
,
153 &Reply
, sizeof(Reply
),
157 /* Pipe transaction failed */
165 DhcpRenewIpAddressLease(DWORD AdapterIndex
)
168 COMM_DHCP_REPLY Reply
;
172 ASSERT(PipeHandle
!= INVALID_HANDLE_VALUE
);
174 Req
.Type
= DhcpReqRenewIpAddress
;
175 Req
.AdapterIndex
= AdapterIndex
;
177 Result
= TransactNamedPipe(PipeHandle
,
179 &Reply
, sizeof(Reply
),
183 /* Pipe transaction failed */
191 DhcpStaticRefreshParams(DWORD AdapterIndex
,
196 COMM_DHCP_REPLY Reply
;
200 ASSERT(PipeHandle
!= INVALID_HANDLE_VALUE
);
202 Req
.Type
= DhcpReqStaticRefreshParams
;
203 Req
.AdapterIndex
= AdapterIndex
;
204 Req
.Body
.StaticRefreshParams
.IPAddress
= Address
;
205 Req
.Body
.StaticRefreshParams
.Netmask
= Netmask
;
207 Result
= TransactNamedPipe(PipeHandle
,
209 &Reply
, sizeof(Reply
),
213 /* Pipe transaction failed */
221 * Set new TCP/IP parameters and notify DHCP client service of this
223 * \param[in] ServerName
224 * NULL for local machine
226 * \param[in] AdapterName
227 * IPHLPAPI name of adapter to change
229 * \param[in] NewIpAddress
230 * TRUE if IP address changes
232 * \param[in] IpAddress
233 * New IP address (network byte order)
235 * \param[in] SubnetMask
236 * New subnet mask (network byte order)
238 * \param[in] DhcpAction
243 * \return non-zero on success
245 * \remarks Undocumented by Microsoft
248 DhcpNotifyConfigChange(LPWSTR ServerName
,
256 DPRINT1("DHCPCSVC: DhcpNotifyConfigChange not implemented yet\n");
261 DhcpRequestParams(DWORD Flags
,
264 LPDHCPCAPI_CLASSID ClassId
,
265 DHCPCAPI_PARAMS_ARRAY SendParams
,
266 DHCPCAPI_PARAMS_ARRAY RecdParams
,
276 * Get DHCP info for an adapter
278 * \param[in] AdapterIndex
279 * Index of the adapter (iphlpapi-style) for which info is
282 * \param[out] DhcpEnabled
283 * Returns whether DHCP is enabled for the adapter
285 * \param[out] DhcpServer
286 * Returns DHCP server IP address (255.255.255.255 if no
287 * server reached yet), in network byte order
289 * \param[out] LeaseObtained
290 * Returns time at which the lease was obtained
292 * \param[out] LeaseExpires
293 * Returns time at which the lease will expire
295 * \return non-zero on success
297 * \remarks This is a ReactOS-only routine
300 DhcpRosGetAdapterInfo(DWORD AdapterIndex
,
303 time_t* LeaseObtained
,
304 time_t* LeaseExpires
)
307 COMM_DHCP_REPLY Reply
;
311 ASSERT(PipeHandle
!= INVALID_HANDLE_VALUE
);
313 Req
.Type
= DhcpReqGetAdapterInfo
;
314 Req
.AdapterIndex
= AdapterIndex
;
316 Result
= TransactNamedPipe(PipeHandle
,
318 &Reply
, sizeof(Reply
),
321 if (Result
&& Reply
.Reply
!= 0)
322 *DhcpEnabled
= Reply
.GetAdapterInfo
.DhcpEnabled
;
324 *DhcpEnabled
= FALSE
;
328 *DhcpServer
= Reply
.GetAdapterInfo
.DhcpServer
;
329 *LeaseObtained
= Reply
.GetAdapterInfo
.LeaseObtained
;
330 *LeaseExpires
= Reply
.GetAdapterInfo
.LeaseExpires
;
334 *DhcpServer
= INADDR_NONE
;
344 UpdateServiceStatus(DWORD dwState
)
346 ServiceStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
347 ServiceStatus
.dwCurrentState
= dwState
;
349 if (dwState
== SERVICE_RUNNING
)
350 ServiceStatus
.dwControlsAccepted
= SERVICE_ACCEPT_SHUTDOWN
| SERVICE_ACCEPT_STOP
;
352 ServiceStatus
.dwControlsAccepted
= 0;
354 ServiceStatus
.dwWin32ExitCode
= 0;
355 ServiceStatus
.dwServiceSpecificExitCode
= 0;
356 ServiceStatus
.dwCheckPoint
= 0;
358 if (dwState
== SERVICE_START_PENDING
||
359 dwState
== SERVICE_STOP_PENDING
)
360 ServiceStatus
.dwWaitHint
= 1000;
362 ServiceStatus
.dwWaitHint
= 0;
364 SetServiceStatus(ServiceStatusHandle
,
369 ServiceControlHandler(DWORD dwControl
,
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
;
383 case SERVICE_CONTROL_INTERROGATE
:
384 SetServiceStatus(ServiceStatusHandle
,
386 return ERROR_SUCCESS
;
389 return ERROR_CALL_NOT_IMPLEMENTED
;
394 ServiceMain(DWORD argc
, LPWSTR
* argv
)
396 HANDLE hPipeThread
= INVALID_HANDLE_VALUE
;
397 HANDLE hDiscoveryThread
= INVALID_HANDLE_VALUE
;
400 ServiceStatusHandle
= RegisterServiceCtrlHandlerExW(ServiceName
,
401 ServiceControlHandler
,
403 if (!ServiceStatusHandle
)
405 DPRINT1("DHCPCSVC: Unable to register service control handler (%lx)\n", GetLastError());
409 UpdateServiceStatus(SERVICE_START_PENDING
);
411 /* Create the stop event */
412 hStopEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
413 if (hStopEvent
== NULL
)
415 UpdateServiceStatus(SERVICE_STOPPED
);
419 hAdapterStateChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
420 if (hAdapterStateChangedEvent
== NULL
)
422 CloseHandle(hStopEvent
);
423 UpdateServiceStatus(SERVICE_STOPPED
);
427 UpdateServiceStatus(SERVICE_START_PENDING
);
431 DbgPrint("DHCPCSVC: init_client() failed!\n");
432 CloseHandle(hAdapterStateChangedEvent
);
433 CloseHandle(hStopEvent
);
434 UpdateServiceStatus(SERVICE_STOPPED
);
438 UpdateServiceStatus(SERVICE_START_PENDING
);
440 hPipeThread
= PipeInit(hStopEvent
);
441 if (hPipeThread
== INVALID_HANDLE_VALUE
)
443 DbgPrint("DHCPCSVC: PipeInit() failed!\n");
445 CloseHandle(hAdapterStateChangedEvent
);
446 CloseHandle(hStopEvent
);
447 UpdateServiceStatus(SERVICE_STOPPED
);
451 hDiscoveryThread
= StartAdapterDiscovery(hStopEvent
);
452 if (hDiscoveryThread
== INVALID_HANDLE_VALUE
)
454 DbgPrint("DHCPCSVC: StartAdapterDiscovery() failed!\n");
456 CloseHandle(hAdapterStateChangedEvent
);
457 CloseHandle(hStopEvent
);
458 UpdateServiceStatus(SERVICE_STOPPED
);
462 DH_DbgPrint(MID_TRACE
,("DHCP Service Started\n"));
464 UpdateServiceStatus(SERVICE_RUNNING
);
466 DH_DbgPrint(MID_TRACE
,("Going into dispatch()\n"));
467 DH_DbgPrint(MID_TRACE
,("DHCPCSVC: DHCP service is starting up\n"));
469 dispatch(hStopEvent
);
471 DH_DbgPrint(MID_TRACE
,("DHCPCSVC: DHCP service is shutting down\n"));
475 DPRINT("Wait for pipe thread to close! %p\n", hPipeThread
);
476 if (hPipeThread
!= INVALID_HANDLE_VALUE
)
478 DPRINT("Waiting for pipe thread\n");
479 ret
= WaitForSingleObject(hPipeThread
, 5000);
480 DPRINT("Done %lx\n", ret
);
483 DPRINT("Wait for discovery thread to close! %p\n", hDiscoveryThread
);
484 if (hDiscoveryThread
!= INVALID_HANDLE_VALUE
)
486 DPRINT("Waiting for discovery thread\n");
487 ret
= WaitForSingleObject(hDiscoveryThread
, 5000);
488 DPRINT("Done %lx\n", ret
);
491 DPRINT("Closing events!\n");
492 CloseHandle(hAdapterStateChangedEvent
);
493 CloseHandle(hStopEvent
);
495 if (DhcpSocket
!= INVALID_SOCKET
)
496 closesocket(DhcpSocket
);
498 CloseHandle(hDiscoveryThread
);
499 CloseHandle(hPipeThread
);
503 UpdateServiceStatus(SERVICE_STOPPED
);
507 DllMain(HINSTANCE hinstDLL
,
513 case DLL_PROCESS_ATTACH
:
514 DisableThreadLibraryCalls(hinstDLL
);
517 case DLL_PROCESS_DETACH
: