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 #define NDEBUG
45 #include <reactos/debug.h>
46
47 //#include <sys/ioctl.h>
48
49 //#include <net/if_media.h>
50 //#include <ifaddrs.h>
51 //#include <poll.h>
52
53 extern SOCKET DhcpSocket;
54 extern HANDLE hAdapterStateChangedEvent;
55
56 struct protocol *protocols = NULL;
57 struct timeout *timeouts = NULL;
58 static struct timeout *free_timeouts = NULL;
59 void (*bootp_packet_handler)(struct interface_info *,
60 struct dhcp_packet *, int, unsigned int,
61 struct iaddr, struct hardware *);
62
63 /*
64 * Wait for packets to come in using poll(). When a packet comes in,
65 * call receive_packet to receive the packet and possibly strip hardware
66 * addressing information from it, and then call through the
67 * bootp_packet_handler hook to try to do something with it.
68 */
69 void
dispatch(HANDLE hStopEvent)70 dispatch(HANDLE hStopEvent)
71 {
72 int count, to_msec;
73 struct protocol *l;
74 time_t howlong, cur_time;
75 HANDLE Events[3];
76 int EventCount = 2;
77
78 Events[0] = hAdapterStateChangedEvent;
79 Events[1] = hStopEvent;
80 Events[2] = WSA_INVALID_EVENT;
81
82 ApiLock();
83
84 do {
85 /*
86 * Call any expired timeouts, and then if there's still
87 * a timeout registered, time out the select call then.
88 */
89 time(&cur_time);
90
91 if (timeouts)
92 {
93 struct timeout *t;
94
95 if (timeouts->when <= cur_time) {
96 t = timeouts;
97 timeouts = timeouts->next;
98 (*(t->func))(t->what);
99 t->next = free_timeouts;
100 free_timeouts = t;
101 continue;
102 }
103
104 /*
105 * Figure timeout in milliseconds, and check for
106 * potential overflow, so we can cram into an
107 * int for poll, while not polling with a
108 * negative timeout and blocking indefinitely.
109 */
110 howlong = timeouts->when - cur_time;
111 if (howlong > INT_MAX / 1000)
112 howlong = INT_MAX / 1000;
113 to_msec = howlong * 1000;
114 }
115 else
116 {
117 to_msec = INFINITE;
118 }
119
120 if (Events[2] == WSA_INVALID_EVENT && DhcpSocket != INVALID_SOCKET)
121 {
122 Events[2] = WSACreateEvent();
123 if (Events[2] != WSA_INVALID_EVENT)
124 {
125 count = WSAEventSelect(DhcpSocket, Events[2], FD_READ | FD_CLOSE);
126 if (count != NO_ERROR)
127 {
128 WSACloseEvent(Events[2]);
129 Events[2] = WSA_INVALID_EVENT;
130 }
131 else
132 {
133 EventCount = 3;
134 }
135 }
136 }
137 else if (Events[2] != WSA_INVALID_EVENT && DhcpSocket == INVALID_SOCKET)
138 {
139 WSACloseEvent(Events[2]);
140 Events[2] = WSA_INVALID_EVENT;
141
142 EventCount = 2;
143 }
144
145 ApiUnlock();
146 count = WaitForMultipleObjects(EventCount,
147 Events,
148 FALSE,
149 to_msec);
150 ApiLock();
151 if (count == WAIT_OBJECT_0)
152 {
153 /* Adapter state change */
154 continue;
155 }
156 else if (count == WAIT_OBJECT_0 + 1)
157 {
158 /* Stop event signalled */
159 DPRINT("Dispatch thread stop event!\n");
160 break;
161 }
162 else if (count == WAIT_OBJECT_0 + 2)
163 {
164 /* Packet received */
165
166 /* WSA events are manual reset events */
167 WSAResetEvent(Events[2]);
168 }
169 else
170 {
171 /* Timeout */
172 continue;
173 }
174
175 for (l = protocols; l; l = l->next) {
176 struct interface_info *ip;
177 ip = l->local;
178 if (ip && (l->handler != got_one ||
179 !ip->dead)) {
180 DH_DbgPrint(MID_TRACE,("Handling %x\n", l));
181 (*(l->handler))(l);
182 }
183 }
184 } while (1);
185
186 WSACloseEvent(Events[2]);
187
188 ApiUnlock();
189
190 DPRINT("Dispatch thread stopped!\n");
191 }
192
193 void
got_one(struct protocol * l)194 got_one(struct protocol *l)
195 {
196 struct sockaddr_in from;
197 struct hardware hfrom;
198 struct iaddr ifrom;
199 ssize_t result;
200 union {
201 /*
202 * Packet input buffer. Must be as large as largest
203 * possible MTU.
204 */
205 unsigned char packbuf[4095];
206 struct dhcp_packet packet;
207 } u;
208 struct interface_info *ip = l->local;
209 PDHCP_ADAPTER adapter;
210
211 if ((result = receive_packet(ip, u.packbuf, sizeof(u), &from,
212 &hfrom)) == -1) {
213 warning("receive_packet failed on %s: %d", ip->name,
214 WSAGetLastError());
215 ip->errors++;
216 if (ip->errors > 20) {
217 /* our interface has gone away. */
218 warning("Interface %s no longer appears valid.",
219 ip->name);
220 ip->dead = 1;
221 closesocket(l->fd);
222 remove_protocol(l);
223 adapter = AdapterFindInfo(ip);
224 if (adapter) {
225 RemoveEntryList(&adapter->ListEntry);
226 free(adapter);
227 }
228 }
229 return;
230 }
231 if (result == 0)
232 return;
233
234 if (bootp_packet_handler) {
235 ifrom.len = 4;
236 memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len);
237
238
239 adapter = AdapterFindByHardwareAddress(u.packet.chaddr,
240 u.packet.hlen);
241
242 if (!adapter) {
243 warning("Discarding packet with a non-matching target physical address\n");
244 return;
245 }
246
247 (*bootp_packet_handler)(&adapter->DhclientInfo, &u.packet, result,
248 from.sin_port, ifrom, &hfrom);
249 }
250 }
251
252 void
add_timeout(time_t when,void (* where)(void *),void * what)253 add_timeout(time_t when, void (*where)(void *), void *what)
254 {
255 struct timeout *t, *q;
256
257 DH_DbgPrint(MID_TRACE,("Adding timeout %x %p %x\n", when, where, what));
258 /* See if this timeout supersedes an existing timeout. */
259 t = NULL;
260 for (q = timeouts; q; q = q->next) {
261 if (q->func == where && q->what == what) {
262 if (t)
263 t->next = q->next;
264 else
265 timeouts = q->next;
266 break;
267 }
268 t = q;
269 }
270
271 /* If we didn't supersede a timeout, allocate a timeout
272 structure now. */
273 if (!q) {
274 if (free_timeouts) {
275 q = free_timeouts;
276 free_timeouts = q->next;
277 q->func = where;
278 q->what = what;
279 } else {
280 q = malloc(sizeof(struct timeout));
281 if (!q) {
282 error("Can't allocate timeout structure!");
283 return;
284 }
285 q->func = where;
286 q->what = what;
287 }
288 }
289
290 q->when = when;
291
292 /* Now sort this timeout into the timeout list. */
293
294 /* Beginning of list? */
295 if (!timeouts || timeouts->when > q->when) {
296 q->next = timeouts;
297 timeouts = q;
298 return;
299 }
300
301 /* Middle of list? */
302 for (t = timeouts; t->next; t = t->next) {
303 if (t->next->when > q->when) {
304 q->next = t->next;
305 t->next = q;
306 return;
307 }
308 }
309
310 /* End of list. */
311 t->next = q;
312 q->next = NULL;
313 }
314
315 void
cancel_timeout(void (* where)(void *),void * what)316 cancel_timeout(void (*where)(void *), void *what)
317 {
318 struct timeout *t, *q;
319
320 /* Look for this timeout on the list, and unlink it if we find it. */
321 t = NULL;
322 for (q = timeouts; q; q = q->next) {
323 if (q->func == where && q->what == what) {
324 if (t)
325 t->next = q->next;
326 else
327 timeouts = q->next;
328 break;
329 }
330 t = q;
331 }
332
333 /* If we found the timeout, put it on the free list. */
334 if (q) {
335 q->next = free_timeouts;
336 free_timeouts = q;
337 }
338 }
339
340 /* Add a protocol to the list of protocols... */
341 void
add_protocol(char * name,int fd,void (* handler)(struct protocol *),void * local)342 add_protocol(char *name, int fd, void (*handler)(struct protocol *),
343 void *local)
344 {
345 struct protocol *p;
346
347 p = malloc(sizeof(*p));
348 if (!p)
349 error("can't allocate protocol struct for %s", name);
350
351 p->fd = fd;
352 p->handler = handler;
353 p->local = local;
354 p->next = protocols;
355 protocols = p;
356 }
357
358 void
remove_protocol(struct protocol * proto)359 remove_protocol(struct protocol *proto)
360 {
361 struct protocol *p, *next, *prev;
362 struct interface_info *ip = proto->local;
363 struct timeout *t, *q, *u;
364
365 t = NULL;
366 q = timeouts;
367 while (q != NULL)
368 {
369 /* Remove all timeouts for this protocol */
370 if (q->what == ip)
371 {
372 /* Unlink the timeout from previous */
373 if (t)
374 t->next = q->next;
375 else
376 timeouts = q->next;
377
378 /* Advance to the next timeout */
379 u = q->next;
380
381 /* Add it to the free list */
382 q->next = free_timeouts;
383 free_timeouts = q;
384 }
385 else
386 {
387 /* Advance to the next timeout */
388 u = q->next;
389
390 /* Update the previous pointer */
391 t = q;
392 }
393
394 /* Advance */
395 q = u;
396 }
397
398 prev = NULL;
399 for (p = protocols; p; p = next) {
400 next = p->next;
401 if (p == proto) {
402 if (prev)
403 prev->next = p->next;
404 else
405 protocols = p->next;
406 free(p);
407 }
408 }
409 }
410
411 struct protocol *
find_protocol_by_adapter(struct interface_info * info)412 find_protocol_by_adapter(struct interface_info *info)
413 {
414 struct protocol *p;
415
416 for( p = protocols; p; p = p->next ) {
417 if( p->local == (void *)info ) return p;
418 }
419
420 return NULL;
421 }
422
423 int
interface_link_status(char * ifname)424 interface_link_status(char *ifname)
425 {
426 return (1);
427 }
428