xref: /reactos/base/services/dhcpcsvc/dhcp/dispatch.c (revision 84344399)
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
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
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
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
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
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
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 *
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
424 interface_link_status(char *ifname)
425 {
426     return (1);
427 }
428