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 struct protocol
*protocols
= NULL
;
51 struct timeout
*timeouts
= NULL
;
52 static struct timeout
*free_timeouts
= NULL
;
53 static int interfaces_invalidated
= FALSE
;
54 void (*bootp_packet_handler
)(struct interface_info
*,
55 struct dhcp_packet
*, int, unsigned int,
56 struct iaddr
, struct hardware
*);
58 static int interface_status(struct interface_info
*ifinfo
);
61 * Use getifaddrs() to get a list of all the attached interfaces. For
62 * each interface that's of type INET and not the loopback interface,
63 * register that interface with the network I/O software, figure out
64 * what subnet it's on, and add it to the list of interfaces.
68 discover_interfaces(struct interface_info
*iface
)
70 struct ifaddrs
*ifap
, *ifa
;
71 struct sockaddr_in foo
;
74 if (getifaddrs(&ifap
) != 0)
75 error("getifaddrs failed");
77 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
78 if ((ifa
->ifa_flags
& IFF_LOOPBACK
) ||
79 (ifa
->ifa_flags
& IFF_POINTOPOINT
) ||
80 (!(ifa
->ifa_flags
& IFF_UP
)))
84 if (strcmp(iface
->name
, ifa
->ifa_name
))
88 * If we have the capability, extract link information
89 * and record it in a linked list.
91 if (ifa
->ifa_addr
->sa_family
== AF_LINK
) {
92 struct sockaddr_dl
*foo
=
93 (struct sockaddr_dl
*)ifa
->ifa_addr
;
95 iface
->index
= foo
->sdl_index
;
96 iface
->hw_address
.hlen
= foo
->sdl_alen
;
97 iface
->hw_address
.htype
= HTYPE_ETHER
; /* XXX */
98 memcpy(iface
->hw_address
.haddr
,
99 LLADDR(foo
), foo
->sdl_alen
);
100 } else if (ifa
->ifa_addr
->sa_family
== AF_INET
) {
103 memcpy(&foo
, ifa
->ifa_addr
, sizeof(foo
));
104 if (foo
.sin_addr
.s_addr
== htonl(INADDR_LOOPBACK
))
107 int len
= IFNAMSIZ
+ ifa
->ifa_addr
->sa_len
;
108 if ((tif
= malloc(len
)) == NULL
)
109 error("no space to remember ifp");
110 strlcpy(tif
->ifr_name
, ifa
->ifa_name
, IFNAMSIZ
);
111 memcpy(&tif
->ifr_addr
, ifa
->ifa_addr
,
112 ifa
->ifa_addr
->sa_len
);
114 iface
->primary_address
= foo
.sin_addr
;
117 memcpy(addr
.iabuf
, &foo
.sin_addr
.s_addr
, addr
.len
);
122 error("%s: not found", iface
->name
);
124 /* Register the interface... */
125 if_register_receive(iface
);
126 if_register_send(iface
);
127 add_protocol(iface
->name
, iface
->rfdesc
, got_one
, iface
);
132 discover_interfaces(struct interface_info
*iface
)
136 char TmpName
[IFNAMSIZ
];
138 PIP_ADAPTER_INFO pAdapterInfo
;
139 PIP_ADAPTER_INFO pAdapter
= NULL
;
141 pAdapterInfo
= malloc(sizeof(IP_ADAPTER_INFO
));
142 dim
= sizeof(IP_ADAPTER_INFO
);
144 if (GetAdaptersInfo( pAdapterInfo
, &dim
) != ERROR_SUCCESS
) {
146 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc (dim
);
149 if ((Status
= GetAdaptersInfo( pAdapterInfo
, &dim
)) != NO_ERROR
) {
150 note("Error %x", Status
);
155 for (pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
) {
156 /* we only do ethernet */
157 note("found: %s %x\n", pAdapter
->AdapterName
, pAdapter
->Address
);
158 if (pAdapter
->Type
!= MIB_IF_TYPE_ETHERNET
) {
161 note ("found ethernet\n");
163 iface
->hw_address
.hlen
= pAdapter
->AddressLength
;
164 iface
->hw_address
.htype
= HTYPE_ETHER
;
165 memcpy (&iface
->hw_address
.haddr
[0],
166 pAdapter
->Address
, iface
->hw_address
.hlen
);
168 if (pAdapter
->IpAddressList
.IpAddress
.String
)
169 iface
->primary_address
.S_un
.S_addr
= inet_addr(pAdapter
->IpAddressList
.IpAddress
.String
);
173 if_register_receive(iface
);
174 if_register_send(iface
);
175 add_protocol(iface
->name
, iface
->rfdesc
, got_one
, iface
);
182 reinitialize_interfaces(void)
184 interfaces_invalidated
= 1;
188 * Wait for packets to come in using poll(). When a packet comes in,
189 * call receive_packet to receive the packet and possibly strip hardware
190 * addressing information from it, and then call through the
191 * bootp_packet_handler hook to try to do something with it.
196 int count
, i
, to_msec
, nfds
= 0;
200 struct timeval timeval
;
202 for (l
= protocols
; l
; l
= l
->next
)
207 // fds = malloc(nfds * sizeof(struct pollfd));
209 // error("Can't allocate poll structures.");
212 DH_DbgPrint(MID_TRACE
,("Cycling dispatch()\n"));
214 * Call any expired timeouts, and then if there's still
215 * a timeout registered, time out the select call then.
219 DH_DbgPrint(MID_TRACE
,("Some timeouts are available\n"));
223 if (timeouts
->when
<= cur_time
) {
224 DH_DbgPrint(MID_TRACE
,("Calling timeout %x %p %x\n",
229 timeouts
= timeouts
->next
;
230 (*(t
->func
))(t
->what
);
231 t
->next
= free_timeouts
;
237 * Figure timeout in milliseconds, and check for
238 * potential overflow, so we can cram into an
239 * int for poll, while not polling with a
240 * negative timeout and blocking indefinitely.
242 howlong
= timeouts
->when
- cur_time
;
243 if (howlong
> INT_MAX
/ 1000)
244 howlong
= INT_MAX
/ 1000;
245 to_msec
= howlong
* 1000;
249 /* Set up the descriptors to be polled. */
250 for (i
= 0, l
= protocols
; l
; l
= l
->next
) {
251 struct interface_info
*ip
= l
->local
;
253 if (ip
&& (l
->handler
!= got_one
|| !ip
->dead
)) {
254 DH_DbgPrint(MID_TRACE
,("l->fd %d\n", l
->fd
));
257 // fds[i].fd = l->fd;
258 // fds[i].events = POLLIN;
259 // fds[i].revents = 0;
265 error("No live interfaces to poll on - exiting.");
267 /* Wait for a packet or a timeout... XXX */
268 timeval
.tv_sec
= to_msec
/ 1000;
269 timeval
.tv_usec
= (to_msec
% 1000) * 1000;
270 DH_DbgPrint(MID_TRACE
,("select(%d,%d.%03d) =>\n",
271 nfds
,timeval
.tv_sec
,timeval
.tv_usec
/1000));
272 count
= select(nfds
, &fds
, NULL
, NULL
, &timeval
);
273 DH_DbgPrint(MID_TRACE
,(" => %d\n", count
));
275 /* Not likely to be transitory... */
276 if (count
== SOCKET_ERROR
) {
277 if (errno
== EAGAIN
|| errno
== EINTR
) {
284 /* Get the current time... */
288 for (l
= protocols
; l
; l
= l
->next
) {
289 struct interface_info
*ip
;
291 if (!FD_ISSET(l
->fd
, &fds
)) {
292 //.revents & (POLLIN | POLLHUP))) {
293 // fds[i].revents = 0;
294 if (ip
&& (l
->handler
!= got_one
||
296 DH_DbgPrint(MID_TRACE
,("Handling %x\n", l
));
298 if (interfaces_invalidated
)
303 interfaces_invalidated
= 0;
305 DH_DbgPrint(MID_TRACE
,("Done\n"));
310 got_one(struct protocol
*l
)
312 struct sockaddr_in from
;
313 struct hardware hfrom
;
318 * Packet input buffer. Must be as large as largest
321 unsigned char packbuf
[4095];
322 struct dhcp_packet packet
;
324 struct interface_info
*ip
= l
->local
;
326 if ((result
= receive_packet(ip
, u
.packbuf
, sizeof(u
), &from
,
328 warning("receive_packet failed on %s: %s", ip
->name
,
331 if ((!interface_status(ip
)) ||
332 (ip
->noifmedia
&& ip
->errors
> 20)) {
333 /* our interface has gone away. */
334 warning("Interface %s no longer appears valid.",
337 interfaces_invalidated
= 1;
347 if (bootp_packet_handler
) {
349 memcpy(ifrom
.iabuf
, &from
.sin_addr
, ifrom
.len
);
351 (*bootp_packet_handler
)(ip
, &u
.packet
, result
,
352 from
.sin_port
, ifrom
, &hfrom
);
358 interface_status(struct interface_info
*ifinfo
)
360 char *ifname
= ifinfo
->name
;
361 int ifsock
= ifinfo
->rfdesc
;
363 struct ifmediareq ifmr
;
365 /* get interface flags */
366 memset(&ifr
, 0, sizeof(ifr
));
367 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
368 if (ioctl(ifsock
, SIOCGIFFLAGS
, &ifr
) < 0) {
369 syslog(LOG_ERR
, "ioctl(SIOCGIFFLAGS) on %s: %m", ifname
);
374 * if one of UP and RUNNING flags is dropped,
375 * the interface is not active.
377 if ((ifr
.ifr_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
))
380 /* Next, check carrier on the interface, if possible */
381 if (ifinfo
->noifmedia
)
383 memset(&ifmr
, 0, sizeof(ifmr
));
384 strlcpy(ifmr
.ifm_name
, ifname
, sizeof(ifmr
.ifm_name
));
385 if (ioctl(ifsock
, SIOCGIFMEDIA
, (caddr_t
)&ifmr
) < 0) {
386 if (errno
!= EINVAL
) {
387 syslog(LOG_DEBUG
, "ioctl(SIOCGIFMEDIA) on %s: %m",
390 ifinfo
->noifmedia
= 1;
394 * EINVAL (or ENOTTY) simply means that the interface
395 * does not support the SIOCGIFMEDIA ioctl. We regard it alive.
397 ifinfo
->noifmedia
= 1;
400 if (ifmr
.ifm_status
& IFM_AVALID
) {
401 switch (ifmr
.ifm_active
& IFM_NMASK
) {
403 if (ifmr
.ifm_status
& IFM_ACTIVE
)
419 interface_status(struct interface_info
*ifinfo
)
426 add_timeout(time_t when
, void (*where
)(void *), void *what
)
428 struct timeout
*t
, *q
;
430 DH_DbgPrint(MID_TRACE
,("Adding timeout %x %p %x\n", when
, where
, what
));
431 /* See if this timeout supersedes an existing timeout. */
433 for (q
= timeouts
; q
; q
= q
->next
) {
434 if (q
->func
== where
&& q
->what
== what
) {
444 /* If we didn't supersede a timeout, allocate a timeout
449 free_timeouts
= q
->next
;
453 q
= malloc(sizeof(struct timeout
));
455 error("Can't allocate timeout structure!");
463 /* Now sort this timeout into the timeout list. */
465 /* Beginning of list? */
466 if (!timeouts
|| timeouts
->when
> q
->when
) {
472 /* Middle of list? */
473 for (t
= timeouts
; t
->next
; t
= t
->next
) {
474 if (t
->next
->when
> q
->when
) {
487 cancel_timeout(void (*where
)(void *), void *what
)
489 struct timeout
*t
, *q
;
491 /* Look for this timeout on the list, and unlink it if we find it. */
493 for (q
= timeouts
; q
; q
= q
->next
) {
494 if (q
->func
== where
&& q
->what
== what
) {
504 /* If we found the timeout, put it on the free list. */
506 q
->next
= free_timeouts
;
511 /* Add a protocol to the list of protocols... */
513 add_protocol(char *name
, int fd
, void (*handler
)(struct protocol
*),
518 p
= malloc(sizeof(*p
));
520 error("can't allocate protocol struct for %s", name
);
523 p
->handler
= handler
;
530 remove_protocol(struct protocol
*proto
)
532 struct protocol
*p
, *next
, *prev
;
535 for (p
= protocols
; p
; p
= next
) {
539 prev
->next
= p
->next
;
548 interface_link_status(char *ifname
)
551 struct ifmediareq ifmr
;
554 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
555 error("Can't create socket");
557 memset(&ifmr
, 0, sizeof(ifmr
));
558 strlcpy(ifmr
.ifm_name
, ifname
, sizeof(ifmr
.ifm_name
));
559 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifmr
) == -1) {
560 /* EINVAL -> link state unknown. treat as active */
562 syslog(LOG_DEBUG
, "ioctl(SIOCGIFMEDIA) on %s: %m",
569 if (ifmr
.ifm_status
& IFM_AVALID
) {
570 if ((ifmr
.ifm_active
& IFM_NMASK
) == IFM_ETHER
) {
571 if (ifmr
.ifm_status
& IFM_ACTIVE
)