Merge PR #283 "[USBPORT] Transaction Translator (TT) support bringup"
[reactos.git] / base / services / dhcpcsvc / dhcpcsvc.c
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 */