1 /* $OpenBSD: src/sbin/dhclient/dispatch.c,v 1.59 2012/10/11 08:05:05 sthen 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''.
42 #include <sys/ioctl.h>
44 #include <net/if_media.h>
51 struct timeout timeout
;
54 * Use getifaddrs() to get a list of all the attached interfaces. Find
55 * our interface on the list and store the interesting information about it.
58 discover_interface(void)
60 struct ifaddrs
*ifap
, *ifa
;
62 int len
= IFNAMSIZ
+ sizeof(struct sockaddr_storage
);
64 if (getifaddrs(&ifap
) != 0)
65 error("getifaddrs failed");
67 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
68 if ((ifa
->ifa_flags
& IFF_LOOPBACK
) ||
69 (ifa
->ifa_flags
& IFF_POINTOPOINT
) ||
70 (!(ifa
->ifa_flags
& IFF_UP
)))
73 if (strcmp(ifi
->name
, ifa
->ifa_name
))
77 * If we have the capability, extract & save link information.
79 if (ifa
->ifa_addr
->sa_family
== AF_LINK
) {
80 struct sockaddr_dl
*foo
=
81 (struct sockaddr_dl
*)ifa
->ifa_addr
;
83 ifi
->index
= foo
->sdl_index
;
84 ifi
->hw_address
.hlen
= foo
->sdl_alen
;
85 ifi
->hw_address
.htype
= HTYPE_ETHER
; /* XXX */
86 memcpy(ifi
->hw_address
.haddr
,
87 LLADDR(foo
), foo
->sdl_alen
);
90 if ((tif
= malloc(len
)) == NULL
)
91 error("no space to remember ifp");
92 strlcpy(tif
->ifr_name
, ifa
->ifa_name
, IFNAMSIZ
);
98 error("%s: not found", ifi
->name
);
100 /* Register the interface... */
101 if_register_receive();
107 * Loop waiting for packets, timeouts or routing messages.
113 struct pollfd fds
[2];
114 time_t cur_time
, howlong
;
119 * Call expired timeout, and then if there's still
120 * a timeout registered, time out the select call then.
124 error("No interfaces available");
128 if (timeout
.when
<= cur_time
) {
135 * Figure timeout in milliseconds, and check for
136 * potential overflow, so we can cram into an
137 * int for poll, while not polling with a
138 * negative timeout and blocking indefinitely.
140 howlong
= timeout
.when
- cur_time
;
141 if (howlong
> INT_MAX
/ 1000)
142 howlong
= INT_MAX
/ 1000;
143 to_msec
= howlong
* 1000;
147 /* Set up the descriptors to be polled. */
148 if (!ifi
|| ifi
->rfdesc
== -1)
149 error("No live interface to poll on");
151 fds
[0].fd
= ifi
->rfdesc
;
152 fds
[1].fd
= routefd
; /* Could be -1, which will be ignored. */
153 fds
[0].events
= fds
[1].events
= POLLIN
;
155 /* Wait for a packet or a timeout... XXX */
156 count
= poll(fds
, 2, to_msec
);
158 /* Not likely to be transitory... */
160 if (errno
== EAGAIN
|| errno
== EINTR
) {
166 if ((fds
[0].revents
& (POLLIN
| POLLHUP
))) {
167 /* XXX profmakx: I am not sure whether updating the linkstate
168 here is the best idea, but it being not up to date leads
170 Alternatively we can just remove the link state check since
171 the link state is checked in got_one() later on
173 ifi
->linkstat
= interface_status(ifi
->name
);
175 if (ifi
&& ifi
->linkstat
&& ifi
->rfdesc
!= -1)
178 if ((fds
[1].revents
& (POLLIN
| POLLHUP
))) {
188 struct sockaddr_in from
;
189 struct hardware hfrom
;
193 if ((result
= receive_packet(&from
, &hfrom
)) == -1) {
194 warning("receive_packet failed on %s: %s", ifi
->name
,
197 if ((!interface_status(ifi
->name
)) ||
198 (ifi
->noifmedia
&& ifi
->errors
> 20)) {
199 /* our interface has gone away. */
200 error("Interface %s no longer appears valid.",
209 memcpy(ifrom
.iabuf
, &from
.sin_addr
, ifrom
.len
);
211 do_packet(result
, from
.sin_port
, ifrom
, &hfrom
);
215 * Normally its ok to force the interface link up, but don't do it
216 * if it is an 80211 interface.
219 interface_link_forceup(char *ifname
)
222 struct ifmediareq ifmr
;
225 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
226 error("Can't create socket");
228 memset(&ifr
, 0, sizeof(ifr
));
229 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
230 if (ioctl(sock
, SIOCGIFFLAGS
, (caddr_t
)&ifr
) == -1) {
234 memset(&ifmr
, 0, sizeof(ifmr
));
235 strlcpy(ifmr
.ifm_name
, ifname
, sizeof(ifmr
.ifm_name
));
236 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifmr
) != -1) {
237 if (IFM_TYPE(ifmr
.ifm_active
) == IFM_IEEE80211
) {
242 if ((ifr
.ifr_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
)) {
243 ifr
.ifr_flags
|= IFF_UP
;
244 if (ioctl(sock
, SIOCSIFFLAGS
, (caddr_t
)&ifr
) == -1) {
256 interface_status(char *ifname
)
259 struct ifmediareq ifmr
;
262 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
263 error("Can't create socket");
265 /* get interface flags */
266 memset(&ifr
, 0, sizeof(ifr
));
267 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
268 if (ioctl(sock
, SIOCGIFFLAGS
, &ifr
) == -1) {
269 error("ioctl(SIOCGIFFLAGS) on %s: %m", ifname
);
273 * if one of UP and RUNNING flags is dropped,
274 * the interface is not active.
276 if ((ifr
.ifr_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
))
279 /* Next, check carrier on the interface, if possible */
282 memset(&ifmr
, 0, sizeof(ifmr
));
283 strlcpy(ifmr
.ifm_name
, ifname
, sizeof(ifmr
.ifm_name
));
284 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifmr
) == -1) {
286 * EINVAL or ENOTTY simply means that the interface
287 * does not support the SIOCGIFMEDIA ioctl. We regard it alive.
290 if (errno
!= EINVAL
&& errno
!= ENOTTY
)
291 debug("ioctl(SIOCGIFMEDIA) on %s: %m", ifname
);
296 if (ifmr
.ifm_status
& IFM_AVALID
) {
297 if (ifmr
.ifm_status
& IFM_ACTIVE
)
303 /* Assume 'active' if IFM_AVALID is not set. */
314 set_timeout(time_t when
, void (*where
)(void))
317 timeout
.func
= where
;
321 set_timeout_interval(time_t secs
, void (*where
)(void))
323 timeout
.when
= time(NULL
) + secs
;
324 timeout
.func
= where
;
335 subnet_exists(struct client_lease
*l
)
337 struct ifaddrs
*ifap
, *ifa
;
338 in_addr_t mymask
, myaddr
, mynet
, hismask
, hisaddr
, hisnet
;
340 bcopy(l
->options
[DHO_SUBNET_MASK
].data
, &mymask
, 4);
341 bcopy(l
->address
.iabuf
, &myaddr
, 4);
342 mynet
= mymask
& myaddr
;
344 if (getifaddrs(&ifap
) != 0)
345 error("getifaddrs failed");
347 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
348 if (strcmp(ifi
->name
, ifa
->ifa_name
) == 0)
351 if (ifa
->ifa_addr
->sa_family
!= AF_INET
)
354 hismask
= ((struct sockaddr_in
*)ifa
->ifa_netmask
)->
356 hisaddr
= ((struct sockaddr_in
*)ifa
->ifa_addr
)->
358 hisnet
= hisaddr
& hismask
;
363 /* Would his packets go out *my* interface? */
364 if (mynet
== (hisaddr
& mymask
)) {
365 note("interface %s already has the offered subnet!",
370 /* Would my packets go out *his* interface? */
371 if (hisnet
== (myaddr
& hismask
)) {
372 note("interface %s already has the offered subnet!",