1 /* $OpenBSD: dispatch.c,v 1.31 2004/09/21 04:07:03 david Exp $ */
4 * Copyright 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 1995, 1996, 1997, 1998, 1999
6 * The Internet Software Consortium. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
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''.
44 //#include <sys/ioctl.h>
46 //#include <net/if_media.h>
47 //#include <ifaddrs.h>
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
*);
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.
70 time_t howlong
, cur_time
;
74 Events
[0] = StartAdapterDiscovery();
77 AdapterStateChangedEvent
= Events
[0];
79 Events
[1] = WSA_INVALID_EVENT
;
85 * Call any expired timeouts, and then if there's still
86 * a timeout registered, time out the select call then.
94 if (timeouts
->when
<= cur_time
) {
96 timeouts
= timeouts
->next
;
97 (*(t
->func
))(t
->what
);
98 t
->next
= free_timeouts
;
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.
109 howlong
= timeouts
->when
- cur_time
;
110 if (howlong
> INT_MAX
/ 1000)
111 howlong
= INT_MAX
/ 1000;
112 to_msec
= howlong
* 1000;
119 if (Events
[1] == WSA_INVALID_EVENT
&& DhcpSocket
!= INVALID_SOCKET
)
121 Events
[1] = WSACreateEvent();
122 if (Events
[1] != WSA_INVALID_EVENT
)
124 count
= WSAEventSelect(DhcpSocket
, Events
[1], FD_READ
| FD_CLOSE
);
125 if (count
!= NO_ERROR
)
127 WSACloseEvent(Events
[1]);
128 Events
[1] = WSA_INVALID_EVENT
;
136 else if (Events
[1] != WSA_INVALID_EVENT
&& DhcpSocket
== INVALID_SOCKET
)
138 WSACloseEvent(Events
[1]);
139 Events
[1] = WSA_INVALID_EVENT
;
145 count
= WaitForMultipleObjects(EventCount
,
150 if (count
== WAIT_OBJECT_0
)
152 /* Adapter state change */
155 else if (count
== WAIT_OBJECT_0
+ 1)
157 /* Packet received */
159 /* WSA events are manual reset events */
160 WSAResetEvent(Events
[1]);
168 for (l
= protocols
; l
; l
= l
->next
) {
169 struct interface_info
*ip
;
171 if (ip
&& (l
->handler
!= got_one
||
173 DH_DbgPrint(MID_TRACE
,("Handling %x\n", l
));
179 AdapterStateChangedEvent
= NULL
;
180 CloseHandle(Events
[0]);
181 WSACloseEvent(Events
[1]);
187 got_one(struct protocol
*l
)
189 struct sockaddr_in from
;
190 struct hardware hfrom
;
195 * Packet input buffer. Must be as large as largest
198 unsigned char packbuf
[4095];
199 struct dhcp_packet packet
;
201 struct interface_info
*ip
= l
->local
;
202 PDHCP_ADAPTER adapter
;
204 if ((result
= receive_packet(ip
, u
.packbuf
, sizeof(u
), &from
,
206 warning("receive_packet failed on %s: %d", ip
->name
,
209 if (ip
->errors
> 20) {
210 /* our interface has gone away. */
211 warning("Interface %s no longer appears valid.",
216 adapter
= AdapterFindInfo(ip
);
218 RemoveEntryList(&adapter
->ListEntry
);
227 if (bootp_packet_handler
) {
229 memcpy(ifrom
.iabuf
, &from
.sin_addr
, ifrom
.len
);
232 adapter
= AdapterFindByHardwareAddress(u
.packet
.chaddr
,
236 warning("Discarding packet with a non-matching target physical address\n");
240 (*bootp_packet_handler
)(&adapter
->DhclientInfo
, &u
.packet
, result
,
241 from
.sin_port
, ifrom
, &hfrom
);
246 add_timeout(time_t when
, void (*where
)(void *), void *what
)
248 struct timeout
*t
, *q
;
250 DH_DbgPrint(MID_TRACE
,("Adding timeout %x %p %x\n", when
, where
, what
));
251 /* See if this timeout supersedes an existing timeout. */
253 for (q
= timeouts
; q
; q
= q
->next
) {
254 if (q
->func
== where
&& q
->what
== what
) {
264 /* If we didn't supersede a timeout, allocate a timeout
269 free_timeouts
= q
->next
;
273 q
= malloc(sizeof(struct timeout
));
275 error("Can't allocate timeout structure!");
285 /* Now sort this timeout into the timeout list. */
287 /* Beginning of list? */
288 if (!timeouts
|| timeouts
->when
> q
->when
) {
294 /* Middle of list? */
295 for (t
= timeouts
; t
->next
; t
= t
->next
) {
296 if (t
->next
->when
> q
->when
) {
309 cancel_timeout(void (*where
)(void *), void *what
)
311 struct timeout
*t
, *q
;
313 /* Look for this timeout on the list, and unlink it if we find it. */
315 for (q
= timeouts
; q
; q
= q
->next
) {
316 if (q
->func
== where
&& q
->what
== what
) {
326 /* If we found the timeout, put it on the free list. */
328 q
->next
= free_timeouts
;
333 /* Add a protocol to the list of protocols... */
335 add_protocol(char *name
, int fd
, void (*handler
)(struct protocol
*),
340 p
= malloc(sizeof(*p
));
342 error("can't allocate protocol struct for %s", name
);
345 p
->handler
= handler
;
352 remove_protocol(struct protocol
*proto
)
354 struct protocol
*p
, *next
, *prev
;
355 struct interface_info
*ip
= proto
->local
;
356 struct timeout
*t
, *q
, *u
;
362 /* Remove all timeouts for this protocol */
365 /* Unlink the timeout from previous */
371 /* Advance to the next timeout */
374 /* Add it to the free list */
375 q
->next
= free_timeouts
;
380 /* Advance to the next timeout */
383 /* Update the previous pointer */
392 for (p
= protocols
; p
; p
= next
) {
396 prev
->next
= p
->next
;
405 find_protocol_by_adapter(struct interface_info
*info
)
409 for( p
= protocols
; p
; p
= p
->next
) {
410 if( p
->local
== (void *)info
) return p
;
417 interface_link_status(char *ifname
)