1 /* $KAME: if.c,v 1.27 2003/10/05 00:09:36 itojun Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/socket.h> 36 #include <sys/sysctl.h> 37 #include <sys/ioctl.h> 38 #include <sys/queue.h> 39 40 #include <net/if.h> 41 #include <net/if_var.h> 42 #include <net/if_types.h> 43 #include <net/route.h> 44 #include <net/if_dl.h> 45 #include <net/if_media.h> 46 #include <net/ethernet.h> 47 #include <netinet/in.h> 48 #include <netinet/icmp6.h> 49 50 #include <netinet6/in6_var.h> 51 #include <netinet6/nd6.h> 52 53 #include <stdio.h> 54 #include <unistd.h> 55 #include <stdlib.h> 56 #include <syslog.h> 57 #include <string.h> 58 #include <fcntl.h> 59 #include <errno.h> 60 #include <limits.h> 61 #include <ifaddrs.h> 62 #include "rtsold.h" 63 64 static int ifsock; 65 66 static int get_llflag(const char *); 67 static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 68 69 int 70 ifinit(void) 71 { 72 ifsock = rssock; 73 74 return(0); 75 } 76 77 int 78 interface_up(char *name) 79 { 80 struct ifreq ifr; 81 struct in6_ndireq nd; 82 int llflag; 83 int s; 84 85 memset(&ifr, 0, sizeof(ifr)); 86 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 87 memset(&nd, 0, sizeof(nd)); 88 strlcpy(nd.ifname, name, sizeof(nd.ifname)); 89 90 if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { 91 warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFFLAGS): %s", 92 strerror(errno)); 93 return (-1); 94 } 95 if (!(ifr.ifr_flags & IFF_UP)) { 96 ifr.ifr_flags |= IFF_UP; 97 if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) 98 warnmsg(LOG_ERR, __func__, 99 "ioctl(SIOCSIFFLAGS): %s", strerror(errno)); 100 return (-1); 101 } 102 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 103 warnmsg(LOG_WARNING, __func__, "socket(AF_INET6, SOCK_DGRAM): %s", 104 strerror(errno)); 105 return (-1); 106 } 107 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 108 warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFINFO_IN6): %s", 109 strerror(errno)); 110 close(s); 111 return (-1); 112 } 113 114 warnmsg(LOG_DEBUG, __func__, "checking if %s is ready...", name); 115 116 if (nd.ndi.flags & ND6_IFF_IFDISABLED) { 117 if (Fflag) { 118 nd.ndi.flags &= ~ND6_IFF_IFDISABLED; 119 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) { 120 warnmsg(LOG_WARNING, __func__, 121 "ioctl(SIOCSIFINFO_IN6): %s", 122 strerror(errno)); 123 close(s); 124 return (-1); 125 } 126 } else { 127 warnmsg(LOG_WARNING, __func__, 128 "%s is disabled.", name); 129 close(s); 130 return (-1); 131 } 132 } 133 if (!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV)) { 134 if (Fflag) { 135 nd.ndi.flags |= ND6_IFF_ACCEPT_RTADV; 136 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) { 137 warnmsg(LOG_WARNING, __func__, 138 "ioctl(SIOCSIFINFO_IN6): %s", 139 strerror(errno)); 140 close(s); 141 return (-1); 142 } 143 } else { 144 warnmsg(LOG_WARNING, __func__, 145 "%s does not accept Router Advertisement.", name); 146 close(s); 147 return (-1); 148 } 149 } 150 close(s); 151 152 llflag = get_llflag(name); 153 if (llflag < 0) { 154 warnmsg(LOG_WARNING, __func__, 155 "get_llflag() failed, anyway I'll try"); 156 return (0); 157 } 158 159 if (!(llflag & IN6_IFF_NOTREADY)) { 160 warnmsg(LOG_DEBUG, __func__, "%s is ready", name); 161 return (0); 162 } else { 163 if (llflag & IN6_IFF_TENTATIVE) { 164 warnmsg(LOG_DEBUG, __func__, "%s is tentative", 165 name); 166 return (IFS_TENTATIVE); 167 } 168 if (llflag & IN6_IFF_DUPLICATED) 169 warnmsg(LOG_DEBUG, __func__, "%s is duplicated", 170 name); 171 return (-1); 172 } 173 } 174 175 int 176 interface_status(struct ifinfo *ifinfo) 177 { 178 char *ifname = ifinfo->ifname; 179 struct ifreq ifr; 180 struct ifmediareq ifmr; 181 182 /* get interface flags */ 183 memset(&ifr, 0, sizeof(ifr)); 184 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 185 if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { 186 warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFFLAGS) on %s: %s", 187 ifname, strerror(errno)); 188 return (-1); 189 } 190 /* 191 * if one of UP and RUNNING flags is dropped, 192 * the interface is not active. 193 */ 194 if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 195 goto inactive; 196 /* Next, check carrier on the interface, if possible */ 197 if (!ifinfo->mediareqok) 198 goto active; 199 memset(&ifmr, 0, sizeof(ifmr)); 200 strncpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 201 202 if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 203 if (errno != EINVAL) { 204 warnmsg(LOG_DEBUG, __func__, 205 "ioctl(SIOCGIFMEDIA) on %s: %s", 206 ifname, strerror(errno)); 207 return(-1); 208 } 209 /* 210 * EINVAL simply means that the interface does not support 211 * the SIOCGIFMEDIA ioctl. We regard it alive. 212 */ 213 ifinfo->mediareqok = 0; 214 goto active; 215 } 216 217 if (ifmr.ifm_status & IFM_AVALID) { 218 switch (ifmr.ifm_active & IFM_NMASK) { 219 case IFM_ETHER: 220 case IFM_IEEE80211: 221 if (ifmr.ifm_status & IFM_ACTIVE) 222 goto active; 223 else 224 goto inactive; 225 break; 226 default: 227 goto inactive; 228 } 229 } 230 231 inactive: 232 return (0); 233 234 active: 235 return (1); 236 } 237 238 #define ROUNDUP(a, size) \ 239 (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) 240 241 #define NEXT_SA(ap) (ap) = (struct sockaddr *) \ 242 ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ 243 sizeof(u_long)) : sizeof(u_long))) 244 #define ROUNDUP8(a) (1 + (((a) - 1) | 7)) 245 246 int 247 lladdropt_length(struct sockaddr_dl *sdl) 248 { 249 switch (sdl->sdl_type) { 250 case IFT_ETHER: 251 #ifdef IFT_IEEE80211 252 case IFT_IEEE80211: 253 #endif 254 return (ROUNDUP8(ETHER_ADDR_LEN + 2)); 255 default: 256 return (0); 257 } 258 } 259 260 void 261 lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 262 { 263 char *addr; 264 265 ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 266 267 switch (sdl->sdl_type) { 268 case IFT_ETHER: 269 #ifdef IFT_IEEE80211 270 case IFT_IEEE80211: 271 #endif 272 ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 273 addr = (char *)(ndopt + 1); 274 memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 275 break; 276 default: 277 warnmsg(LOG_ERR, __func__, 278 "unsupported link type(%d)", sdl->sdl_type); 279 exit(1); 280 } 281 282 return; 283 } 284 285 struct sockaddr_dl * 286 if_nametosdl(char *name) 287 { 288 int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; 289 char *buf, *next, *lim; 290 size_t len; 291 struct if_msghdr *ifm; 292 struct sockaddr *sa, *rti_info[RTAX_MAX]; 293 struct sockaddr_dl *sdl = NULL, *ret_sdl; 294 295 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 296 return(NULL); 297 if ((buf = malloc(len)) == NULL) 298 return(NULL); 299 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { 300 free(buf); 301 return (NULL); 302 } 303 304 lim = buf + len; 305 for (next = buf; next < lim; next += ifm->ifm_msglen) { 306 ifm = (struct if_msghdr *)(void *)next; 307 if (ifm->ifm_type == RTM_IFINFO) { 308 sa = (struct sockaddr *)(ifm + 1); 309 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 310 if ((sa = rti_info[RTAX_IFP]) != NULL) { 311 if (sa->sa_family == AF_LINK) { 312 sdl = (struct sockaddr_dl *)(void *)sa; 313 if (strlen(name) != sdl->sdl_nlen) 314 continue; /* not same len */ 315 if (strncmp(&sdl->sdl_data[0], 316 name, 317 sdl->sdl_nlen) == 0) { 318 break; 319 } 320 } 321 } 322 } 323 } 324 if (next == lim) { 325 /* search failed */ 326 free(buf); 327 return (NULL); 328 } 329 330 if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) { 331 free(buf); 332 return (NULL); 333 } 334 memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); 335 336 free(buf); 337 return (ret_sdl); 338 } 339 340 int 341 getinet6sysctl(int code) 342 { 343 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 344 int value; 345 size_t size; 346 347 mib[3] = code; 348 size = sizeof(value); 349 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0) 350 return (-1); 351 else 352 return (value); 353 } 354 355 int 356 setinet6sysctl(int code, int newval) 357 { 358 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 359 int value; 360 size_t size; 361 362 mib[3] = code; 363 size = sizeof(value); 364 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, 365 &newval, sizeof(newval)) < 0) 366 return (-1); 367 else 368 return (value); 369 } 370 371 /*------------------------------------------------------------*/ 372 373 /* get ia6_flags for link-local addr on if. returns -1 on error. */ 374 static int 375 get_llflag(const char *name) 376 { 377 struct ifaddrs *ifap, *ifa; 378 struct in6_ifreq ifr6; 379 struct sockaddr_in6 *sin6; 380 int s; 381 382 if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) { 383 warnmsg(LOG_ERR, __func__, "socket(SOCK_DGRAM): %s", 384 strerror(errno)); 385 exit(1); 386 } 387 if (getifaddrs(&ifap) != 0) { 388 warnmsg(LOG_ERR, __func__, "getifaddrs: %s", 389 strerror(errno)); 390 exit(1); 391 } 392 393 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 394 if (strlen(ifa->ifa_name) != strlen(name) || 395 strncmp(ifa->ifa_name, name, strlen(name)) != 0) 396 continue; 397 if (ifa->ifa_addr->sa_family != AF_INET6) 398 continue; 399 sin6 = (struct sockaddr_in6 *)(void *)ifa->ifa_addr; 400 if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 401 continue; 402 403 memset(&ifr6, 0, sizeof(ifr6)); 404 strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name)); 405 memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len); 406 if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { 407 warnmsg(LOG_ERR, __func__, 408 "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno)); 409 exit(1); 410 } 411 412 freeifaddrs(ifap); 413 close(s); 414 return (ifr6.ifr_ifru.ifru_flags6); 415 } 416 417 freeifaddrs(ifap); 418 close(s); 419 return (-1); 420 } 421 422 423 static void 424 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 425 { 426 int i; 427 428 for (i = 0; i < RTAX_MAX; i++) { 429 if (addrs & (1 << i)) { 430 rti_info[i] = sa; 431 NEXT_SA(sa); 432 } else 433 rti_info[i] = NULL; 434 } 435 } 436