PRIVATE_EXTERN int inet6_linklocal_stop(const char * ifname) { int ret = 0; int s = inet6_dgram_socket(); if (s < 0) { ret = errno; my_log(LOG_ERR, "inet6_linklocal_stop(%s): socket() failed, %s (%d)", ifname, strerror(ret), ret); goto done; } if (siocll_stop(s, ifname) < 0) { ret = errno; if (errno != ENXIO) { my_log(LOG_ERR, "siocll_stop(%s) failed, %s (%d)", ifname, strerror(errno), errno); } } close(s); done: return (ret); }
PRIVATE_EXTERN int inet6_linklocal_start(const char * ifname, boolean_t use_cga) { int ret = 0; int s = inet6_dgram_socket(); if (s < 0) { ret = errno; my_log(LOG_ERR, "inet6_linklocal_start(%s): socket() failed, %s (%d)", ifname, strerror(ret), ret); goto done; } nd_flags_set_with_socket(s, ifname, 0, ND6_IFF_IFDISABLED); if (ll_start(s, ifname, use_cga) < 0) { ret = errno; if (errno != ENXIO) { my_log(LOG_ERR, "siocll_start(%s) failed, %s (%d)", ifname, strerror(errno), errno); } } close(s); done: return (ret); }
PRIVATE_EXTERN int inet6_detach_interface(const char * ifname) { int ret = 0; int s = inet6_dgram_socket(); if (s < 0) { ret = errno; my_log(LOG_ERR, "inet6_detach_interface(%s): socket() failed, %s (%d)", ifname, strerror(ret), ret); goto done; } if (siocprotodetach_in6(s, ifname) < 0) { ret = errno; if (ret != ENXIO) { my_log(LOG_DEBUG, "siocprotodetach_in6(%s) failed, %s (%d)", ifname, strerror(errno), errno); } } close(s); done: return (ret); }
STATIC boolean_t nd_flags_set(const char * if_name, uint32_t set_flags, uint32_t clear_flags) { int s; boolean_t success = FALSE; s = inet6_dgram_socket(); if (s < 0) { my_log_fl(LOG_ERR, "socket failed, %s", strerror(errno)); } else { success = nd_flags_set_with_socket(s, if_name, set_flags, clear_flags); close(s); } return (success); }
PRIVATE_EXTERN boolean_t inet6_set_perform_nud(const char * if_name, boolean_t perform_nud) { boolean_t need_set = FALSE; struct in6_ndireq nd; int s; boolean_t success = FALSE; s = inet6_dgram_socket(); if (s < 0) { my_log_fl(LOG_ERR, "socket failed, %s", strerror(errno)); goto done; } bzero(&nd, sizeof(nd)); strncpy(nd.ifname, if_name, sizeof(nd.ifname)); if (ioctl(s, SIOCGIFINFO_IN6, &nd)) { my_log_fl(LOG_ERR, "SIOCGIFINFO_IN6(%s) failed, %s", if_name, strerror(errno)); goto done; } if (perform_nud) { if ((nd.ndi.flags & ND6_IFF_PERFORMNUD) == 0) { nd.ndi.flags |= ND6_IFF_PERFORMNUD; need_set = TRUE; } } else if ((nd.ndi.flags & ND6_IFF_PERFORMNUD) != 0) { nd.ndi.flags &= ~ND6_IFF_PERFORMNUD; need_set = TRUE; } if (need_set) { if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd)) { my_log_fl(LOG_ERR, "SIOCSIFINFO_FLAGS(%s) failed, %s", if_name, strerror(errno)); goto done; } } success = TRUE; done: if (s >= 0) { close(s); } return (success); }
STATIC int inet6_if_ioctl(const char * ifname, unsigned long request) { struct in6_ifreq ifr; int ret = 0; int s; s = inet6_dgram_socket(); if (s < 0) { ret = errno; goto done; } bzero(&ifr, sizeof(ifr)); strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(s, request, &ifr) < 0) { ret = errno; } done: if (s >=0) { close(s); } return (ret); }
PRIVATE_EXTERN int inet6_rtadv_enable(const char * if_name) { int ret = 0; int s = inet6_dgram_socket(); if (s < 0) { ret = errno; my_log(LOG_ERR, "inet6_rtadv_enable(%s): socket() failed, %s (%d)", if_name, strerror(ret), ret); goto done; } if (siocautoconf_start(s, if_name) < 0) { ret = errno; if (errno != ENXIO) { my_log(LOG_ERR, "siocautoconf_start(%s) failed, %s (%d)", if_name, strerror(errno), errno); } } close(s); done: return (ret); }
PRIVATE_EXTERN void inet6_addrlist_copy(inet6_addrlist_t * addr_list_p, int if_index) { int addr_index = 0; char * buf = NULL; char * buf_end; int buf_len; int count; int error; int i; char ifname[IFNAMSIZ + 1]; inet6_addrinfo_t * linklocal = NULL; inet6_addrinfo_t * list = NULL; char * scan; struct rt_msghdr * rtm; int s = -1; buf = get_if_info(if_index, AF_INET6, &buf_len); if (buf == NULL) { goto done; } buf_end = buf + buf_len; /* figure out how many IPv6 addresses there are */ count = 0; ifname[0] = '\0'; for (scan = buf; scan < buf_end; scan += rtm->rtm_msglen) { struct if_msghdr * ifm; /* ALIGN: buf aligned (from calling get_if_info), scan aligned, * cast ok. */ rtm = (struct rt_msghdr *)(void *)scan; if (rtm->rtm_version != RTM_VERSION) { continue; } switch (rtm->rtm_type) { case RTM_IFINFO: ifm = (struct if_msghdr *)rtm; if (ifm->ifm_addrs & RTA_IFP) { struct sockaddr_dl * dl_p; dl_p = (struct sockaddr_dl *)(ifm + 1); if (dl_p->sdl_nlen == 0 || dl_p->sdl_nlen >= sizeof(ifname)) { goto done; } bcopy(dl_p->sdl_data, ifname, dl_p->sdl_nlen); ifname[dl_p->sdl_nlen] = '\0'; } break; case RTM_NEWADDR: count++; break; default: break; } } if (ifname[0] == '\0') { goto done; } if (count == 0) { goto done; } if (count > INET6_ADDRLIST_N_STATIC) { list = (inet6_addrinfo_t *)malloc(sizeof(*list) * count); if (list == NULL) { goto done; } } else { list = addr_list_p->list_static; } for (scan = buf; scan < buf_end; scan += rtm->rtm_msglen) { boolean_t got_address = FALSE; struct ifa_msghdr * ifam; struct rt_addrinfo info; rtm = (struct rt_msghdr *)(void *)scan; if (rtm->rtm_version != RTM_VERSION) { continue; } if (rtm->rtm_type == RTM_NEWADDR) { ifam = (struct ifa_msghdr *)rtm; info.rti_addrs = ifam->ifam_addrs; error = rt_xaddrs((char *)(ifam + 1), ((char *)ifam) + ifam->ifam_msglen, &info); if (error) { fprintf(stderr, "couldn't extract rt_addrinfo %s (%d)\n", strerror(error), error); goto done; } for (i = 0; i < RTAX_MAX; i++) { struct sockaddr_in6 * sin6_p; /* ALIGN: info.rti_info aligned (sockaddr), cast ok. */ sin6_p = (struct sockaddr_in6 *)(void *)info.rti_info[i]; if (sin6_p == NULL || sin6_p->sin6_len < sizeof(struct sockaddr_in6)) { continue; } switch (i) { case RTAX_NETMASK: list[addr_index].prefix_length = count_prefix_bits(&sin6_p->sin6_addr, sizeof(sin6_p->sin6_addr)); break; case RTAX_IFA: list[addr_index].addr = sin6_p->sin6_addr; got_address = TRUE; break; default: break; } } if (got_address) { if (s < 0) { s = inet6_dgram_socket(); } if (s >= 0) { siocgifaflag_in6(s, ifname, &list[addr_index].addr, &list[addr_index].addr_flags); siocgifalifetime_in6(s, ifname, &list[addr_index].addr, &list[addr_index].valid_lifetime, &list[addr_index].preferred_lifetime); } /* Mask the v6 LL scope id */ if (IN6_IS_ADDR_LINKLOCAL(&list[addr_index].addr)) { list[addr_index].addr.s6_addr16[1] = 0; if (linklocal == NULL) { linklocal = &list[addr_index]; } } addr_index++; } } } if (addr_index == 0) { if (list != addr_list_p->list_static) { free(list); } list = NULL; } done: if (s >= 0) { close(s); } if (buf != NULL) { free(buf); } addr_list_p->list = list; addr_list_p->count = addr_index; addr_list_p->linklocal = linklocal; return; }