- Merge 54895, 54896, 54899, 54912, 54913, 54915, and 54916 from wlan-bringup
[reactos.git] / reactos / dll / win32 / dhcpcsvc / dhcp / dispatch.c
1 /* $OpenBSD: dispatch.c,v 1.31 2004/09/21 04:07:03 david Exp $ */
2
3 /*
4 * Copyright 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 1995, 1996, 1997, 1998, 1999
6 * The Internet Software Consortium. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of The Internet Software Consortium nor the names
18 * of its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
22 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * This software has been written for the Internet Software Consortium
36 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
37 * Enterprises. To learn more about the Internet Software Consortium,
38 * see ``http://www.vix.com/isc''. To learn more about Vixie
39 * Enterprises, see ``http://www.vix.com''.
40 */
41
42 #include "rosdhcp.h"
43
44 //#include <sys/ioctl.h>
45
46 //#include <net/if_media.h>
47 //#include <ifaddrs.h>
48 //#include <poll.h>
49
50 extern SOCKET DhcpSocket;
51 HANDLE AdapterStateChangedEvent = NULL;
52 struct protocol *protocols = NULL;
53 struct timeout *timeouts = NULL;
54 static struct timeout *free_timeouts = NULL;
55 void (*bootp_packet_handler)(struct interface_info *,
56 struct dhcp_packet *, int, unsigned int,
57 struct iaddr, struct hardware *);
58
59 /*
60 * Wait for packets to come in using poll(). When a packet comes in,
61 * call receive_packet to receive the packet and possibly strip hardware
62 * addressing information from it, and then call through the
63 * bootp_packet_handler hook to try to do something with it.
64 */
65 void
66 dispatch(void)
67 {
68 int count, to_msec;
69 struct protocol *l;
70 time_t howlong, cur_time;
71 HANDLE Events[2];
72 int EventCount = 1;
73
74 Events[0] = StartAdapterDiscovery();
75 if (!Events[0])
76 return;
77 AdapterStateChangedEvent = Events[0];
78
79 Events[1] = WSA_INVALID_EVENT;
80
81 ApiLock();
82
83 do {
84 /*
85 * Call any expired timeouts, and then if there's still
86 * a timeout registered, time out the select call then.
87 */
88 time(&cur_time);
89
90 if (timeouts)
91 {
92 struct timeout *t;
93
94 if (timeouts->when <= cur_time) {
95 t = timeouts;
96 timeouts = timeouts->next;
97 (*(t->func))(t->what);
98 t->next = free_timeouts;
99 free_timeouts = t;
100 continue;
101 }
102
103 /*
104 * Figure timeout in milliseconds, and check for
105 * potential overflow, so we can cram into an
106 * int for poll, while not polling with a
107 * negative timeout and blocking indefinitely.
108 */
109 howlong = timeouts->when - cur_time;
110 if (howlong > INT_MAX / 1000)
111 howlong = INT_MAX / 1000;
112 to_msec = howlong * 1000;
113 }
114 else
115 {
116 to_msec = INFINITE;
117 }
118
119 if (Events[1] == WSA_INVALID_EVENT && DhcpSocket != INVALID_SOCKET)
120 {
121 Events[1] = WSACreateEvent();
122 if (Events[1] != WSA_INVALID_EVENT)
123 {
124 count = WSAEventSelect(DhcpSocket, Events[1], FD_READ | FD_CLOSE);
125 if (count != NO_ERROR)
126 {
127 WSACloseEvent(Events[1]);
128 Events[1] = WSA_INVALID_EVENT;
129 }
130 else
131 {
132 EventCount = 2;
133 }
134 }
135 }
136 else if (Events[1] != WSA_INVALID_EVENT && DhcpSocket == INVALID_SOCKET)
137 {
138 WSACloseEvent(Events[1]);
139 Events[1] = WSA_INVALID_EVENT;
140
141 EventCount = 1;
142 }
143
144 ApiUnlock();
145 count = WaitForMultipleObjects(EventCount,
146 Events,
147 FALSE,
148 to_msec);
149 ApiLock();
150 if (count == WAIT_OBJECT_0)
151 {
152 /* Adapter state change */
153 continue;
154 }
155 else if (count == WAIT_OBJECT_0 + 1)
156 {
157 /* Packet received */
158
159 /* WSA events are manual reset events */
160 WSAResetEvent(Events[1]);
161 }
162 else
163 {
164 /* Timeout */
165 continue;
166 }
167
168 for (l = protocols; l; l = l->next) {
169 struct interface_info *ip;
170 ip = l->local;
171 if (ip && (l->handler != got_one ||
172 !ip->dead)) {
173 DH_DbgPrint(MID_TRACE,("Handling %x\n", l));
174 (*(l->handler))(l);
175 }
176 }
177 } while (1);
178
179 AdapterStateChangedEvent = NULL;
180 CloseHandle(Events[0]);
181 WSACloseEvent(Events[1]);
182
183 ApiUnlock();
184 }
185
186 void
187 got_one(struct protocol *l)
188 {
189 struct sockaddr_in from;
190 struct hardware hfrom;
191 struct iaddr ifrom;
192 ssize_t result;
193 union {
194 /*
195 * Packet input buffer. Must be as large as largest
196 * possible MTU.
197 */
198 unsigned char packbuf[4095];
199 struct dhcp_packet packet;
200 } u;
201 struct interface_info *ip = l->local;
202 PDHCP_ADAPTER adapter;
203
204 if ((result = receive_packet(ip, u.packbuf, sizeof(u), &from,
205 &hfrom)) == -1) {
206 warning("receive_packet failed on %s: %d", ip->name,
207 WSAGetLastError());
208 ip->errors++;
209 if (ip->errors > 20) {
210 /* our interface has gone away. */
211 warning("Interface %s no longer appears valid.",
212 ip->name);
213 ip->dead = 1;
214 closesocket(l->fd);
215 remove_protocol(l);
216 adapter = AdapterFindInfo(ip);
217 if (adapter) {
218 RemoveEntryList(&adapter->ListEntry);
219 free(adapter);
220 }
221 }
222 return;
223 }
224 if (result == 0)
225 return;
226
227 if (bootp_packet_handler) {
228 ifrom.len = 4;
229 memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len);
230
231
232 adapter = AdapterFindByHardwareAddress(u.packet.chaddr,
233 u.packet.hlen);
234
235 if (!adapter) {
236 warning("Discarding packet with a non-matching target physical address\n");
237 return;
238 }
239
240 (*bootp_packet_handler)(&adapter->DhclientInfo, &u.packet, result,
241 from.sin_port, ifrom, &hfrom);
242 }
243 }
244
245 void
246 add_timeout(time_t when, void (*where)(void *), void *what)
247 {
248 struct timeout *t, *q;
249
250 DH_DbgPrint(MID_TRACE,("Adding timeout %x %p %x\n", when, where, what));
251 /* See if this timeout supersedes an existing timeout. */
252 t = NULL;
253 for (q = timeouts; q; q = q->next) {
254 if (q->func == where && q->what == what) {
255 if (t)
256 t->next = q->next;
257 else
258 timeouts = q->next;
259 break;
260 }
261 t = q;
262 }
263
264 /* If we didn't supersede a timeout, allocate a timeout
265 structure now. */
266 if (!q) {
267 if (free_timeouts) {
268 q = free_timeouts;
269 free_timeouts = q->next;
270 q->func = where;
271 q->what = what;
272 } else {
273 q = malloc(sizeof(struct timeout));
274 if (!q) {
275 error("Can't allocate timeout structure!");
276 return;
277 }
278 q->func = where;
279 q->what = what;
280 }
281 }
282
283 q->when = when;
284
285 /* Now sort this timeout into the timeout list. */
286
287 /* Beginning of list? */
288 if (!timeouts || timeouts->when > q->when) {
289 q->next = timeouts;
290 timeouts = q;
291 return;
292 }
293
294 /* Middle of list? */
295 for (t = timeouts; t->next; t = t->next) {
296 if (t->next->when > q->when) {
297 q->next = t->next;
298 t->next = q;
299 return;
300 }
301 }
302
303 /* End of list. */
304 t->next = q;
305 q->next = NULL;
306 }
307
308 void
309 cancel_timeout(void (*where)(void *), void *what)
310 {
311 struct timeout *t, *q;
312
313 /* Look for this timeout on the list, and unlink it if we find it. */
314 t = NULL;
315 for (q = timeouts; q; q = q->next) {
316 if (q->func == where && q->what == what) {
317 if (t)
318 t->next = q->next;
319 else
320 timeouts = q->next;
321 break;
322 }
323 t = q;
324 }
325
326 /* If we found the timeout, put it on the free list. */
327 if (q) {
328 q->next = free_timeouts;
329 free_timeouts = q;
330 }
331 }
332
333 /* Add a protocol to the list of protocols... */
334 void
335 add_protocol(char *name, int fd, void (*handler)(struct protocol *),
336 void *local)
337 {
338 struct protocol *p;
339
340 p = malloc(sizeof(*p));
341 if (!p)
342 error("can't allocate protocol struct for %s", name);
343
344 p->fd = fd;
345 p->handler = handler;
346 p->local = local;
347 p->next = protocols;
348 protocols = p;
349 }
350
351 void
352 remove_protocol(struct protocol *proto)
353 {
354 struct protocol *p, *next, *prev;
355 struct interface_info *ip = proto->local;
356 struct timeout *t, *q, *u;
357
358 t = NULL;
359 q = timeouts;
360 while (q != NULL)
361 {
362 /* Remove all timeouts for this protocol */
363 if (q->what == ip)
364 {
365 /* Unlink the timeout from previous */
366 if (t)
367 t->next = q->next;
368 else
369 timeouts = q->next;
370
371 /* Advance to the next timeout */
372 u = q->next;
373
374 /* Add it to the free list */
375 q->next = free_timeouts;
376 free_timeouts = q;
377 }
378 else
379 {
380 /* Advance to the next timeout */
381 u = q->next;
382
383 /* Update the previous pointer */
384 t = q;
385 }
386
387 /* Advance */
388 q = u;
389 }
390
391 prev = NULL;
392 for (p = protocols; p; p = next) {
393 next = p->next;
394 if (p == proto) {
395 if (prev)
396 prev->next = p->next;
397 else
398 protocols = p->next;
399 free(p);
400 }
401 }
402 }
403
404 struct protocol *
405 find_protocol_by_adapter(struct interface_info *info)
406 {
407 struct protocol *p;
408
409 for( p = protocols; p; p = p->next ) {
410 if( p->local == (void *)info ) return p;
411 }
412
413 return NULL;
414 }
415
416 int
417 interface_link_status(char *ifname)
418 {
419 return (1);
420 }