1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2010 Roy Marples <roy@marples.name> 4 * All rights reserved 5 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 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. 14 * 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 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/ioctl.h> 29 #include <sys/param.h> 30 #include <sys/socket.h> 31 #include <sys/stat.h> 32 #include <sys/sysctl.h> 33 #include <sys/types.h> 34 35 #include <arpa/inet.h> 36 #include <net/if.h> 37 #include <net/if_dl.h> 38 #include <net/route.h> 39 #include <netinet/in.h> 40 #ifdef __DragonFly__ 41 # include <netproto/802_11/ieee80211_ioctl.h> 42 #elif __APPLE__ 43 /* FIXME: Add apple includes so we can work out SSID */ 44 #else 45 # include <net80211/ieee80211_ioctl.h> 46 #endif 47 48 #include <errno.h> 49 #include <fnmatch.h> 50 #include <stddef.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 56 #include <rump/rump.h> 57 #include <rump/rump_syscalls.h> 58 59 #include "common.h" 60 #include "configure.h" 61 #include "dhcp.h" 62 #include "if-options.h" 63 #include "net.h" 64 65 #define ROUNDUP(a) \ 66 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 67 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 68 69 /* FIXME: Why do we need to check for sa_family 255 */ 70 #define COPYOUT(sin, sa) \ 71 sin.s_addr = ((sa) != NULL) ? \ 72 (((struct sockaddr_in *)(void *)sa)->sin_addr).s_addr : 0 73 74 static int r_fd = -1; 75 76 int 77 if_init(_unused struct interface *iface) 78 { 79 /* BSD promotes secondary address by default */ 80 return 0; 81 } 82 83 int 84 if_conf(_unused struct interface *iface) 85 { 86 /* No extra checks needed on BSD */ 87 return 0; 88 } 89 90 int 91 init_sockets(void) 92 { 93 94 if ((socket_afnet = rump_sys_socket(AF_INET, SOCK_DGRAM, 0)) == -1) 95 return -1; 96 if ((r_fd = rump_sys_socket(PF_ROUTE, SOCK_RAW, 0)) == -1) 97 return -1; 98 return 0; 99 } 100 101 int 102 getifssid(const char *ifname, char *ssid) 103 { 104 int retval = -1; 105 #if defined(SIOCG80211NWID) 106 struct ifreq ifr; 107 struct ieee80211_nwid nwid; 108 #elif defined(IEEE80211_IOC_SSID) 109 struct ieee80211req ireq; 110 char nwid[IEEE80211_NWID_LEN + 1]; 111 #endif 112 113 #if defined(SIOCG80211NWID) /* NetBSD */ 114 memset(&ifr, 0, sizeof(ifr)); 115 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 116 memset(&nwid, 0, sizeof(nwid)); 117 ifr.ifr_data = (void *)&nwid; 118 if (rump_sys_ioctl(socket_afnet, SIOCG80211NWID, &ifr) == 0) { 119 retval = nwid.i_len; 120 memcpy(ssid, nwid.i_nwid, nwid.i_len); 121 ssid[nwid.i_len] = '\0'; 122 } 123 #elif defined(IEEE80211_IOC_SSID) /* FreeBSD */ 124 memset(&ireq, 0, sizeof(ireq)); 125 strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name)); 126 ireq.i_type = IEEE80211_IOC_SSID; 127 ireq.i_val = -1; 128 ireq.i_data = &nwid; 129 if (rump_sys_ioctl(socket_afnet, SIOCG80211, &ireq) == 0) { 130 retval = ireq.i_len; 131 memcpy(ssid, nwid, ireq.i_len); 132 ssid[ireq.i_len] = '\0'; 133 } 134 #endif 135 return retval; 136 } 137 138 int 139 if_address(const struct interface *iface, const struct in_addr *address, 140 const struct in_addr *netmask, const struct in_addr *broadcast, 141 int action) 142 { 143 int retval; 144 struct ifaliasreq ifa; 145 union { 146 struct sockaddr *sa; 147 struct sockaddr_in *sin; 148 } _s; 149 150 memset(&ifa, 0, sizeof(ifa)); 151 strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name)); 152 153 #define ADDADDR(_var, _addr) { \ 154 _s.sa = &_var; \ 155 _s.sin->sin_family = AF_INET; \ 156 _s.sin->sin_len = sizeof(*_s.sin); \ 157 memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr)); \ 158 } 159 160 ADDADDR(ifa.ifra_addr, address); 161 ADDADDR(ifa.ifra_mask, netmask); 162 if (action >= 0 && broadcast) { 163 ADDADDR(ifa.ifra_broadaddr, broadcast); 164 } 165 #undef ADDADDR 166 167 if (action < 0) 168 retval = rump_sys_ioctl(socket_afnet, SIOCDIFADDR, &ifa); 169 else 170 retval = rump_sys_ioctl(socket_afnet, SIOCAIFADDR, &ifa); 171 return retval; 172 } 173 174 /* ARGSUSED4 */ 175 int 176 if_route(const struct interface *iface, const struct in_addr *dest, 177 const struct in_addr *net, const struct in_addr *gate, 178 _unused int metric, int action) 179 { 180 union sockunion { 181 struct sockaddr sa; 182 struct sockaddr_in sin; 183 #ifdef INET6 184 struct sockaddr_in6 sin6; 185 #endif 186 struct sockaddr_dl sdl; 187 struct sockaddr_storage ss; 188 } su; 189 struct rtm 190 { 191 struct rt_msghdr hdr; 192 char buffer[sizeof(su) * 4]; 193 } rtm; 194 char *bp = rtm.buffer, *p; 195 size_t l; 196 int retval = 0; 197 198 #define ADDSU(_su) { \ 199 l = ROUNDUP(_su.sa.sa_len); \ 200 memcpy(bp, &(_su), l); \ 201 bp += l; \ 202 } 203 #define ADDADDR(_a) { \ 204 memset (&su, 0, sizeof(su)); \ 205 su.sin.sin_family = AF_INET; \ 206 su.sin.sin_len = sizeof(su.sin); \ 207 memcpy (&su.sin.sin_addr, _a, sizeof(su.sin.sin_addr)); \ 208 ADDSU(su); \ 209 } 210 211 memset(&rtm, 0, sizeof(rtm)); 212 rtm.hdr.rtm_version = RTM_VERSION; 213 rtm.hdr.rtm_seq = 1; 214 if (action == 0) 215 rtm.hdr.rtm_type = RTM_CHANGE; 216 else if (action > 0) 217 rtm.hdr.rtm_type = RTM_ADD; 218 else 219 rtm.hdr.rtm_type = RTM_DELETE; 220 rtm.hdr.rtm_flags = RTF_UP; 221 /* None interface subnet routes are static. */ 222 if (gate->s_addr != INADDR_ANY || 223 net->s_addr != iface->net.s_addr || 224 dest->s_addr != (iface->addr.s_addr & iface->net.s_addr)) 225 rtm.hdr.rtm_flags |= RTF_STATIC; 226 rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; 227 if (dest->s_addr == gate->s_addr && net->s_addr == INADDR_BROADCAST) 228 rtm.hdr.rtm_flags |= RTF_HOST; 229 else { 230 rtm.hdr.rtm_addrs |= RTA_NETMASK; 231 if (rtm.hdr.rtm_flags & RTF_STATIC) 232 rtm.hdr.rtm_flags |= RTF_GATEWAY; 233 if (action >= 0) 234 rtm.hdr.rtm_addrs |= RTA_IFA; 235 } 236 237 ADDADDR(dest); 238 if (rtm.hdr.rtm_flags & RTF_HOST || 239 !(rtm.hdr.rtm_flags & RTF_STATIC)) 240 { 241 /* Make us a link layer socket for the host gateway */ 242 memset(&su, 0, sizeof(su)); 243 su.sdl.sdl_len = sizeof(struct sockaddr_dl); 244 link_addr(iface->name, &su.sdl); 245 ADDSU(su); 246 } else 247 ADDADDR(gate); 248 249 if (rtm.hdr.rtm_addrs & RTA_NETMASK) { 250 /* Ensure that netmask is set correctly */ 251 memset(&su, 0, sizeof(su)); 252 su.sin.sin_family = AF_INET; 253 su.sin.sin_len = sizeof(su.sin); 254 memcpy(&su.sin.sin_addr, &net->s_addr, sizeof(su.sin.sin_addr)); 255 p = su.sa.sa_len + (char *)&su; 256 for (su.sa.sa_len = 0; p > (char *)&su;) 257 if (*--p != 0) { 258 su.sa.sa_len = 1 + p - (char *)&su; 259 break; 260 } 261 ADDSU(su); 262 } 263 264 if (rtm.hdr.rtm_addrs & RTA_IFA) 265 ADDADDR(&iface->addr); 266 267 rtm.hdr.rtm_msglen = l = bp - (char *)&rtm; 268 if (rump_sys_write(r_fd, &rtm, l) == -1) 269 retval = -1; 270 return retval; 271 } 272