Reactos
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
15static WCHAR ServiceName[] = L"DHCP";
16
17SERVICE_STATUS_HANDLE ServiceStatusHandle = 0;
18SERVICE_STATUS ServiceStatus;
19HANDLE hStopEvent = NULL;
20HANDLE hAdapterStateChangedEvent = NULL;
21
22extern SOCKET DhcpSocket;
23
24
25void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
26{
27 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
28}
29
30void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
31{
32 HeapFree(GetProcessHeap(), 0, ptr);
33}
34
35handle_t __RPC_USER
36PDHCP_SERVER_NAME_bind(
37 _In_ PDHCP_SERVER_NAME pszServerName)
38{
39 handle_t hBinding = NULL;
40 LPWSTR pszStringBinding;
41 RPC_STATUS status;
42
43 DPRINT("PDHCP_SERVER_NAME_bind() called\n");
44
45 status = RpcStringBindingComposeW(NULL,
46 L"ncacn_np",
47 pszServerName,
48 L"\\pipe\\dhcpcsvc",
49 NULL,
50 &pszStringBinding);
51 if (status)
52 {
53 DPRINT1("RpcStringBindingCompose returned 0x%x\n", status);
54 return NULL;
55 }
56
57 /* Set the binding handle that will be used to bind to the server. */
58 status = RpcBindingFromStringBindingW(pszStringBinding,
59 &hBinding);
60 if (status)
61 {
62 DPRINT1("RpcBindingFromStringBinding returned 0x%x\n", status);
63 }
64
65 status = RpcStringFreeW(&pszStringBinding);
66 if (status)
67 {
68 DPRINT1("RpcStringFree returned 0x%x\n", status);
69 }
70
71 return hBinding;
72}
73
74void __RPC_USER
75PDHCP_SERVER_NAME_unbind(
76 _In_ PDHCP_SERVER_NAME pszServerName,
77 _In_ handle_t hBinding)
78{
79 RPC_STATUS status;
80
81 DPRINT("PDHCP_SERVER_NAME_unbind() called\n");
82
83 status = RpcBindingFree(&hBinding);
84 if (status)
85 {
86 DPRINT1("RpcBindingFree returned 0x%x\n", status);
87 }
88}
89
90/*!
91 * Initializes the DHCP interface
92 *
93 * \param[out] Version
94 * Returns the DHCP Interface Version
95 *
96 * \return ERROR_SUCCESS on success
97 *
98 * \remarks DhcpCApiInitialized must be called before any other DHCP Function.
99 */
100DWORD
101APIENTRY
102DhcpCApiInitialize(
103 _Out_ LPDWORD Version)
104{
105 *Version = 2;
106 return ERROR_SUCCESS;
107}
108
109/*!
110 * Cleans up the DHCP interface
111 *
112 * \remarks Other DHCP Functions must not be called after DhcpCApiCleanup.
113 */
114VOID
115APIENTRY
116DhcpCApiCleanup(VOID)
117{
118}
119
120/*!
121 * Renews a DHCP Lease
122 *
123 * \param[in] AdapterName
124 * Name (GUID) of the Adapter
125 *
126 * \return ERROR_SUCCESS on success
127 *
128 * \remarks Undocumented by Microsoft
129 */
130DWORD
131APIENTRY
132DhcpAcquireParameters(
133 _In_ PWSTR AdapterName)
134{
135 DWORD ret;
136
137 DPRINT("DhcpAcquireParameters(%S)\n", AdapterName);
138
139 RpcTryExcept
140 {
141 ret = Client_AcquireParameters(NULL, AdapterName);
142 }
143 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
144 {
145 ret = I_RpcMapWin32Status(RpcExceptionCode());
146 }
147 RpcEndExcept;
148
149 return ret;
150}
151
152DWORD
153APIENTRY
154DhcpEnumClasses(
155 _In_ DWORD Unknown1,
156 _In_ PWSTR AdapterName,
157 _In_ DWORD Unknown3,
158 _In_ DWORD Unknown4)
159{
160 DPRINT1("DhcpEnumClasses(%lx %S %lx %lx)\n",
161 Unknown1, AdapterName, Unknown3, Unknown4);
162 return 0;
163}
164
165DWORD
166APIENTRY
167DhcpHandlePnPEvent(
168 _In_ DWORD Unknown1,
169 _In_ DWORD Unknown2,
170 _In_ PWSTR AdapterName,
171 _In_ DWORD Unknown4,
172 _In_ DWORD Unknown5)
173{
174 DPRINT1("DhcpHandlePnPEvent(%lx %lx %S %lx %lx)\n",
175 Unknown1, Unknown2, AdapterName, Unknown4, Unknown5);
176 return 0;
177}
178
179/*!
180 * Set new TCP/IP parameters and notify DHCP client service of this
181 *
182 * \param[in] ServerName
183 * NULL for local machine
184 *
185 * \param[in] AdapterName
186 * IPHLPAPI name of adapter to change
187 *
188 * \param[in] NewIpAddress
189 * TRUE if IP address changes
190
191 * \param[in] IpIndex
192 * ...
193 *
194 * \param[in] IpAddress
195 * New IP address (network byte order)
196 *
197 * \param[in] SubnetMask
198 * New subnet mask (network byte order)
199 *
200 * \param[in] DhcpAction
201 * 0 - don't modify
202 * 1 - enable DHCP
203 * 2 - disable DHCP
204 *
205 * \return ERROR_SUCCESS on success
206 *
207 * \remarks Undocumented by Microsoft
208 */
209DWORD
210APIENTRY
211DhcpNotifyConfigChange(
212 _In_ LPWSTR ServerName,
213 _In_ LPWSTR AdapterName,
214 _In_ BOOL NewIpAddress,
215 _In_ DWORD IpIndex,
216 _In_ DWORD IpAddress,
217 _In_ DWORD SubnetMask,
218 _In_ INT DhcpAction)
219{
220 DPRINT1("DHCPCSVC: DhcpNotifyConfigChange not implemented yet\n");
221 DPRINT1("DhcpNotifyConfigChange(%S %S %lu %lu %lu %lu %d)\n",
222 ServerName, AdapterName, NewIpAddress, IpIndex, IpAddress, SubnetMask, DhcpAction);
223
224 if (AdapterName == NULL)
225 return ERROR_INVALID_PARAMETER;
226
227 UNIMPLEMENTED;
228 return ERROR_SUCCESS;
229}
230
231DWORD APIENTRY
232DhcpQueryHWInfo(DWORD AdapterIndex,
233 PDWORD MediaType,
234 PDWORD Mtu,
235 PDWORD Speed)
236{
237 DWORD ret;
238
239 DPRINT("DhcpQueryHWInfo()\n");
240
241 RpcTryExcept
242 {
243 ret = Client_QueryHWInfo(NULL, AdapterIndex, MediaType, Mtu, Speed);
244 }
245 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
246 {
247 ret = I_RpcMapWin32Status(RpcExceptionCode());
248 }
249 RpcEndExcept;
250
251 return (ret == ERROR_SUCCESS) ? 1 : 0;
252}
253
254/*!
255 * Releases a DHCP Lease
256 *
257 * \param[in] AdapterName
258 * Name (GUID) of the Adapter
259 *
260 * \return ERROR_SUCCESS on success
261 *
262 * \remarks Undocumented by Microsoft
263 */
264DWORD
265APIENTRY
266DhcpReleaseParameters(
267 _In_ PWSTR AdapterName)
268{
269 DWORD ret;
270
271 DPRINT("DhcpReleaseParameters(%S)\n", AdapterName);
272
273 RpcTryExcept
274 {
275 ret = Client_ReleaseParameters(NULL, AdapterName);
276 }
277 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
278 {
279 ret = I_RpcMapWin32Status(RpcExceptionCode());
280 }
281 RpcEndExcept;
282
283 return ret;
284}
285
286/*!
287 * Removes all DNS Registrations which were added by the DHCP Client
288 *
289 * \return ERROR_SUCCESS on success
290 */
291DWORD
292WINAPI
293DhcpRemoveDNSRegistrations(VOID)
294{
295 DWORD ret;
296
297 DPRINT("DhcpRemoveDNSRegistrations()\n");
298
299 RpcTryExcept
300 {
301 ret = Client_RemoveDNSRegistrations(NULL);
302 }
303 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
304 {
305 ret = I_RpcMapWin32Status(RpcExceptionCode());
306 }
307 RpcEndExcept;
308
309 return ret;
310}
311
312DWORD
313APIENTRY
314DhcpStaticRefreshParams(DWORD AdapterIndex,
315 DWORD Address,
316 DWORD Netmask)
317{
318 DWORD ret;
319
320 DPRINT("DhcpStaticRefreshParams()\n");
321
322 RpcTryExcept
323 {
324 ret = Client_StaticRefreshParams(NULL, AdapterIndex, Address, Netmask);
325 }
326 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
327 {
328 ret = I_RpcMapWin32Status(RpcExceptionCode());
329 }
330 RpcEndExcept;
331
332 return (ret == ERROR_SUCCESS) ? 1 : 0;
333}
334
335
336DWORD APIENTRY
337DhcpRequestParams(DWORD Flags,
338 PVOID Reserved,
339 LPWSTR AdapterName,
340 LPDHCPCAPI_CLASSID ClassId,
341 DHCPCAPI_PARAMS_ARRAY SendParams,
342 DHCPCAPI_PARAMS_ARRAY RecdParams,
343 LPBYTE Buffer,
344 LPDWORD pSize,
345 LPWSTR RequestIdStr)
346{
347 UNIMPLEMENTED;
348 return 0;
349}
350
351static VOID
352UpdateServiceStatus(DWORD dwState)
353{
354 ServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
355 ServiceStatus.dwCurrentState = dwState;
356
357 if (dwState == SERVICE_RUNNING)
358 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
359 else
360 ServiceStatus.dwControlsAccepted = 0;
361
362 ServiceStatus.dwWin32ExitCode = 0;
363 ServiceStatus.dwServiceSpecificExitCode = 0;
364 ServiceStatus.dwCheckPoint = 0;
365
366 if (dwState == SERVICE_START_PENDING ||
367 dwState == SERVICE_STOP_PENDING)
368 ServiceStatus.dwWaitHint = 1000;
369 else
370 ServiceStatus.dwWaitHint = 0;
371
372 SetServiceStatus(ServiceStatusHandle,
373 &ServiceStatus);
374}
375
376static DWORD WINAPI
377ServiceControlHandler(DWORD dwControl,
378 DWORD dwEventType,
379 LPVOID lpEventData,
380 LPVOID lpContext)
381{
382 switch (dwControl)
383 {
384 case SERVICE_CONTROL_STOP:
385 case SERVICE_CONTROL_SHUTDOWN:
386 UpdateServiceStatus(SERVICE_STOP_PENDING);
387 if (hStopEvent != NULL)
388 SetEvent(hStopEvent);
389 return ERROR_SUCCESS;
390
391 case SERVICE_CONTROL_INTERROGATE:
392 SetServiceStatus(ServiceStatusHandle,
393 &ServiceStatus);
394 return ERROR_SUCCESS;
395
396 default:
397 return ERROR_CALL_NOT_IMPLEMENTED;
398 }
399}
400
401VOID WINAPI
402ServiceMain(DWORD argc, LPWSTR* argv)
403{
404 HANDLE hPipeThread = INVALID_HANDLE_VALUE;
405 HANDLE hDiscoveryThread = INVALID_HANDLE_VALUE;
406 DWORD ret;
407
408 ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
409 ServiceControlHandler,
410 NULL);
411 if (!ServiceStatusHandle)
412 {
413 DPRINT1("DHCPCSVC: Unable to register service control handler (%lx)\n", GetLastError());
414 return;
415 }
416
417 UpdateServiceStatus(SERVICE_START_PENDING);
418
419 /* Create the stop event */
420 hStopEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
421 if (hStopEvent == NULL)
422 {
423 UpdateServiceStatus(SERVICE_STOPPED);
424 return;
425 }
426
427 hAdapterStateChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
428 if (hAdapterStateChangedEvent == NULL)
429 {
430 CloseHandle(hStopEvent);
431 UpdateServiceStatus(SERVICE_STOPPED);
432 return;
433 }
434
435 UpdateServiceStatus(SERVICE_START_PENDING);
436
437 if (!init_client())
438 {
439 DbgPrint("DHCPCSVC: init_client() failed!\n");
440 CloseHandle(hAdapterStateChangedEvent);
441 CloseHandle(hStopEvent);
442 UpdateServiceStatus(SERVICE_STOPPED);
443 return;
444 }
445
446 UpdateServiceStatus(SERVICE_START_PENDING);
447
448 hPipeThread = InitRpc();
449 if (hPipeThread == INVALID_HANDLE_VALUE)
450 {
451 DbgPrint("DHCPCSVC: PipeInit() failed!\n");
452 stop_client();
453 CloseHandle(hAdapterStateChangedEvent);
454 CloseHandle(hStopEvent);
455 UpdateServiceStatus(SERVICE_STOPPED);
456 return;
457 }
458
459 hDiscoveryThread = StartAdapterDiscovery(hStopEvent);
460 if (hDiscoveryThread == INVALID_HANDLE_VALUE)
461 {
462 DbgPrint("DHCPCSVC: StartAdapterDiscovery() failed!\n");
463 ShutdownRpc();
464 stop_client();
465 CloseHandle(hAdapterStateChangedEvent);
466 CloseHandle(hStopEvent);
467 UpdateServiceStatus(SERVICE_STOPPED);
468 return;
469 }
470
471 DH_DbgPrint(MID_TRACE,("DHCP Service Started\n"));
472
473 UpdateServiceStatus(SERVICE_RUNNING);
474
475 DH_DbgPrint(MID_TRACE,("Going into dispatch()\n"));
476 DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is starting up\n"));
477
478 dispatch(hStopEvent);
479
480 DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is shutting down\n"));
481
482 ShutdownRpc();
483 stop_client();
484
485 DPRINT("Wait for pipe thread to close! %p\n", hPipeThread);
486 if (hPipeThread != INVALID_HANDLE_VALUE)
487 {
488 DPRINT("Waiting for pipe thread\n");
489 ret = WaitForSingleObject(hPipeThread, 5000);
490 DPRINT("Done %lx\n", ret);
491 }
492
493 DPRINT("Wait for discovery thread to close! %p\n", hDiscoveryThread);
494 if (hDiscoveryThread != INVALID_HANDLE_VALUE)
495 {
496 DPRINT("Waiting for discovery thread\n");
497 ret = WaitForSingleObject(hDiscoveryThread, 5000);
498 DPRINT("Done %lx\n", ret);
499 }
500
501 DPRINT("Closing events!\n");
502 CloseHandle(hAdapterStateChangedEvent);
503 CloseHandle(hStopEvent);
504
505 if (DhcpSocket != INVALID_SOCKET)
506 closesocket(DhcpSocket);
507
508 CloseHandle(hDiscoveryThread);
509 CloseHandle(hPipeThread);
510
511 DPRINT("Done!\n");
512
513 UpdateServiceStatus(SERVICE_STOPPED);
514}
515
516BOOL WINAPI
517DllMain(HINSTANCE hinstDLL,
518 DWORD fdwReason,
519 LPVOID lpvReserved)
520{
521 switch (fdwReason)
522 {
523 case DLL_PROCESS_ATTACH:
524 DisableThreadLibraryCalls(hinstDLL);
525 break;
526
527 case DLL_PROCESS_DETACH:
528 break;
529 }
530
531 return TRUE;
532}
533
534/* EOF */