2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/ioctl.h>
29 #include <sys/param.h>
30 #include <sys/socket.h>
32 #include <sys/sysctl.h>
33 #include <sys/types.h>
35 #include <arpa/inet.h>
37 #include <net/if_dl.h>
38 #include <net/route.h>
39 #include <netinet/in.h>
41 # include <netproto/802_11/ieee80211_ioctl.h>
43 # include <net80211/ieee80211_ioctl.h>
57 #include "configure.h"
59 #include "if-options.h"
63 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
64 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
66 /* FIXME: Why do we need to check for sa_family 255 */
67 #define COPYOUT(sin, sa) \
68 sin.s_addr = ((sa) != NULL && ((sa)->sa_family == AF_INET || \
69 (sa)->sa_family == 255)) \
71 (((struct sockaddr_in *)(void *)sa)->sin_addr).s_addr : 0
78 if ((socket_afnet
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
80 set_cloexec(socket_afnet
);
81 if ((r_fd
= socket(PF_ROUTE
, SOCK_RAW
, 0)) == -1)
88 getifssid(const char *ifname
, char *ssid
)
91 #if defined(SIOCG80211NWID)
93 struct ieee80211_nwid nwid
;
94 #elif defined(IEEE80211_IOC_SSID)
95 struct ieee80211req ireq
;
96 char nwid
[IEEE80211_NWID_LEN
+ 1];
99 #if defined(SIOCG80211NWID) /* NetBSD */
100 memset(&ifr
, 0, sizeof(ifr
));
101 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
102 memset(&nwid
, 0, sizeof(nwid
));
103 ifr
.ifr_data
= (void *)&nwid
;
104 if (ioctl(socket_afnet
, SIOCG80211NWID
, &ifr
) == 0) {
106 memcpy(ssid
, nwid
.i_nwid
, nwid
.i_len
);
107 ssid
[nwid
.i_len
] = '\0';
109 #elif defined(IEEE80211_IOC_SSID) /* FreeBSD */
110 memset(&ireq
, 0, sizeof(ireq
));
111 strlcpy(ireq
.i_name
, ifname
, sizeof(ireq
.i_name
));
112 ireq
.i_type
= IEEE80211_IOC_SSID
;
115 if (ioctl(socket_afnet
, SIOCG80211
, &ireq
) == 0) {
117 memcpy(ssid
, nwid
, ireq
.i_len
);
118 ssid
[ireq
.i_len
] = '\0';
125 if_address(const struct interface
*iface
, const struct in_addr
*address
,
126 const struct in_addr
*netmask
, const struct in_addr
*broadcast
,
130 struct ifaliasreq ifa
;
133 struct sockaddr_in
*sin
;
136 memset(&ifa
, 0, sizeof(ifa
));
137 strlcpy(ifa
.ifra_name
, iface
->name
, sizeof(ifa
.ifra_name
));
139 #define ADDADDR(_var, _addr) { \
141 _s.sin->sin_family = AF_INET; \
142 _s.sin->sin_len = sizeof(*_s.sin); \
143 memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr)); \
146 ADDADDR(ifa
.ifra_addr
, address
);
147 ADDADDR(ifa
.ifra_mask
, netmask
);
148 if (action
>= 0 && broadcast
) {
149 ADDADDR(ifa
.ifra_broadaddr
, broadcast
);
154 retval
= ioctl(socket_afnet
, SIOCDIFADDR
, &ifa
);
156 retval
= ioctl(socket_afnet
, SIOCAIFADDR
, &ifa
);
162 if_route(const struct interface
*iface
, const struct in_addr
*dest
,
163 const struct in_addr
*net
, const struct in_addr
*gate
,
164 _unused
int metric
, int action
)
168 struct sockaddr_in sin
;
170 struct sockaddr_in6 sin6
;
172 struct sockaddr_dl sdl
;
173 struct sockaddr_storage ss
;
177 struct rt_msghdr hdr
;
178 char buffer
[sizeof(su
) * 4];
180 char *bp
= rtm
.buffer
, *p
;
184 #define ADDSU(_su) { \
185 l = ROUNDUP(_su.sa.sa_len); \
186 memcpy(bp, &(_su), l); \
189 #define ADDADDR(_a) { \
190 memset (&su, 0, sizeof(su)); \
191 su.sin.sin_family = AF_INET; \
192 su.sin.sin_len = sizeof(su.sin); \
193 memcpy (&su.sin.sin_addr, _a, sizeof(su.sin.sin_addr)); \
197 memset(&rtm
, 0, sizeof(rtm
));
198 rtm
.hdr
.rtm_version
= RTM_VERSION
;
201 rtm
.hdr
.rtm_type
= RTM_CHANGE
;
203 rtm
.hdr
.rtm_type
= RTM_ADD
;
205 rtm
.hdr
.rtm_type
= RTM_DELETE
;
206 rtm
.hdr
.rtm_flags
= RTF_UP
;
207 /* None interface subnet routes are static. */
208 if (gate
->s_addr
!= INADDR_ANY
||
209 net
->s_addr
!= iface
->net
.s_addr
||
210 dest
->s_addr
!= (iface
->addr
.s_addr
& iface
->net
.s_addr
))
211 rtm
.hdr
.rtm_flags
|= RTF_STATIC
;
212 rtm
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
213 if (dest
->s_addr
== gate
->s_addr
&& net
->s_addr
== INADDR_BROADCAST
)
214 rtm
.hdr
.rtm_flags
|= RTF_HOST
;
216 rtm
.hdr
.rtm_addrs
|= RTA_NETMASK
;
217 if (rtm
.hdr
.rtm_flags
& RTF_STATIC
)
218 rtm
.hdr
.rtm_flags
|= RTF_GATEWAY
;
220 rtm
.hdr
.rtm_addrs
|= RTA_IFA
;
224 if (rtm
.hdr
.rtm_flags
& RTF_HOST
||
225 !(rtm
.hdr
.rtm_flags
& RTF_STATIC
))
227 /* Make us a link layer socket for the host gateway */
228 memset(&su
, 0, sizeof(su
));
229 su
.sdl
.sdl_len
= sizeof(struct sockaddr_dl
);
230 link_addr(iface
->name
, &su
.sdl
);
235 if (rtm
.hdr
.rtm_addrs
& RTA_NETMASK
) {
236 /* Ensure that netmask is set correctly */
237 memset(&su
, 0, sizeof(su
));
238 su
.sin
.sin_family
= AF_INET
;
239 su
.sin
.sin_len
= sizeof(su
.sin
);
240 memcpy(&su
.sin
.sin_addr
, &net
->s_addr
, sizeof(su
.sin
.sin_addr
));
241 p
= su
.sa
.sa_len
+ (char *)&su
;
242 for (su
.sa
.sa_len
= 0; p
> (char *)&su
;)
244 su
.sa
.sa_len
= 1 + p
- (char *)&su
;
250 if (rtm
.hdr
.rtm_addrs
& RTA_IFA
)
251 ADDADDR(&iface
->addr
);
253 rtm
.hdr
.rtm_msglen
= l
= bp
- (char *)&rtm
;
254 if (write(r_fd
, &rtm
, l
) == -1)
260 open_link_socket(void)
264 fd
= socket(PF_ROUTE
, SOCK_RAW
, 0);
273 get_addrs(int type
, char *cp
, struct sockaddr
**sa
)
277 for (i
= 0; i
< RTAX_MAX
; i
++) {
278 if (type
& (1 << i
)) {
279 sa
[i
] = (struct sockaddr
*)cp
;
281 printf ("got %d %d %s\n", i
, sa
[i
]->sa_family
,
282 inet_ntoa(((struct sockaddr_in
*)sa
[i
])->
291 #define BUFFER_LEN 2048
295 char buffer
[2048], *p
, *e
, *cp
;
296 char ifname
[IF_NAMESIZE
];
298 struct rt_msghdr
*rtm
;
299 struct if_announcemsghdr
*ifan
;
300 struct if_msghdr
*ifm
;
301 struct ifa_msghdr
*ifam
;
303 struct sockaddr
*sa
, *rti_info
[RTAX_MAX
];
306 bytes
= read(fd
, buffer
, BUFFER_LEN
);
315 for (p
= buffer
; p
< e
; p
+= rtm
->rtm_msglen
) {
316 rtm
= (struct rt_msghdr
*)(void *)p
;
317 switch(rtm
->rtm_type
) {
319 ifan
= (struct if_announcemsghdr
*)(void *)p
;
320 switch(ifan
->ifan_what
) {
322 handle_interface(1, ifan
->ifan_name
);
325 handle_interface(-1, ifan
->ifan_name
);
330 ifm
= (struct if_msghdr
*)(void *)p
;
331 memset(ifname
, 0, sizeof(ifname
));
332 if (if_indextoname(ifm
->ifm_index
, ifname
))
333 handle_interface(0, ifname
);
336 if (!(rtm
->rtm_addrs
& RTA_DST
) ||
337 !(rtm
->rtm_addrs
& RTA_GATEWAY
) ||
338 !(rtm
->rtm_addrs
& RTA_NETMASK
))
340 if (rtm
->rtm_pid
== getpid())
342 cp
= (char *)(void *)(rtm
+ 1);
343 sa
= (struct sockaddr
*)(void *)cp
;
344 if (sa
->sa_family
!= AF_INET
)
346 get_addrs(rtm
->rtm_addrs
, cp
, rti_info
);
349 COPYOUT(rt
.dest
, rti_info
[RTAX_DST
]);
350 COPYOUT(rt
.net
, rti_info
[RTAX_NETMASK
]);
351 COPYOUT(rt
.gate
, rti_info
[RTAX_GATEWAY
]);
356 ifam
= (struct ifa_msghdr
*)(void *)p
;
357 cp
= (char *)(void *)(ifam
+ 1);
358 get_addrs(ifam
->ifam_addrs
, cp
, rti_info
);
359 COPYOUT(rt
.dest
, rti_info
[RTAX_IFA
]);
360 COPYOUT(rt
.net
, rti_info
[RTAX_NETMASK
]);
361 COPYOUT(rt
.gate
, rti_info
[RTAX_BRD
]);
362 if (if_indextoname(ifam
->ifam_index
, ifname
))
363 handle_ifa(rtm
->rtm_type
, ifname
,
364 &rt
.dest
, &rt
.net
, &rt
.gate
);