/* * Initialize the passed vif with all appropriate default values. * "t" is true if a tunnel, or false if a phyint. */ void zero_vif(struct uvif *v, int t) { v->uv_flags = 0; v->uv_metric = DEFAULT_METRIC; v->uv_admetric = 0; v->uv_threshold = DEFAULT_THRESHOLD; v->uv_rate_limit = t ? DEFAULT_TUN_RATE_LIMIT : DEFAULT_PHY_RATE_LIMIT; v->uv_lcl_addr = 0; v->uv_rmt_addr = 0; v->uv_dst_addr = t ? 0 : dvmrp_group; v->uv_subnet = 0; v->uv_subnetmask = 0; v->uv_subnetbcast = 0; v->uv_name[0] = '\0'; v->uv_groups = NULL; v->uv_neighbors = NULL; NBRM_CLRALL(v->uv_nbrmap); v->uv_querier = NULL; v->uv_igmpv1_warn = 0; v->uv_prune_lifetime = 0; v->uv_leaf_timer = 0; v->uv_acl = NULL; v->uv_addrs = NULL; v->uv_filter = NULL; v->uv_blasterbuf = NULL; v->uv_blastercur = NULL; v->uv_blasterend = NULL; v->uv_blasterlen = 0; v->uv_blastertimer = 0; v->uv_nbrup = 0; v->uv_icmp_warn = 0; v->uv_nroutes = 0; }
/* * Query the kernel to find network interfaces that are multicast-capable * and install them in the uvifs array. */ void config_vifs_from_kernel() { register struct uvif *v=NULL; register vifi_t vifi; struct sockaddr_in6 addr; struct in6_addr mask, prefix; short flags; #ifdef HAVE_GETIFADDRS struct ifaddrs *ifap=NULL, *ifa=NULL;//init by ziqiang #else int n; int num_ifreq = 64; struct ifconf ifc; struct ifreq *ifrp=NULL, *ifend=NULL;//init by ziqiang #endif total_interfaces = 0; /* The total number of physical interfaces */ #ifdef HAVE_GETIFADDRS if (getifaddrs(&ifap)) { syslog(LOG_ERR, "getiaddrs() error ifap = %p\n",ifap); return ;//by ziqiang } /* * Loop through all of the interfaces. */ for (ifa = ifap; ifa; ifa = ifa->ifa_next) { /* * Ignore any interface for an address family other than IPv6. */ if (ifa->ifa_addr->sa_family != AF_INET6) { total_interfaces++; /* Eventually may have IPv6 address later */ continue; } memcpy(&addr, ifa->ifa_addr, sizeof(struct sockaddr_in6)); flags = ifa->ifa_flags; if ((flags & (IFF_LOOPBACK | IFF_MULTICAST)) != IFF_MULTICAST) continue; /* * Get netmask of the address. */ //memcpy(&mask, &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr, // sizeof(mask)); inet_pton(AF_INET6, "ffff:ffff:ffff:ffff::", &mask); if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr)) { addr.sin6_scope_id = if_nametoindex(ifa->ifa_name); #ifdef __KAME__ /* * Hack for KAME kernel. Set sin6_scope_id field of a * link local address and clear the index embedded in * the address. */ /* clear interface index */ addr.sin6_addr.s6_addr[2] = 0; addr.sin6_addr.s6_addr[3] = 0; #endif } /* * If the address is connected to the same subnet as one already * installed in the uvifs array, just add the address to the list * of addresses of the uvif. */ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { if (strcmp(v->uv_name, ifa->ifa_name) == 0) { add_phaddr(v, &addr, &mask); break; } } if (vifi != numvifs) continue; /* * If there is room in the uvifs array, install this interface. */ if (numvifs == MAXMIFS) { syslog(LOG_WARNING, "too many ifs, ignoring %s", ifa->ifa_name); continue; } /* * Everyone below is a potential vif interface. * We don't care if it has wrong configuration or not configured * at all. */ total_interfaces++; v = &uvifs[numvifs]; v->uv_flags = 0; v->uv_metric = DEFAULT_METRIC; v->uv_admetric = 0; v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT; v->uv_dst_addr = allpim6routers_group; v->uv_prefix.sin6_addr = prefix; v->uv_subnetmask = mask; strncpy(v->uv_name, ifa->ifa_name, IFNAMSIZ); v->uv_ifindex = if_nametoindex(v->uv_name); v->uv_groups = (struct listaddr *)NULL; v->uv_dvmrp_neighbors = (struct listaddr *)NULL; NBRM_CLRALL(v->uv_nbrmap); v->uv_querier = (struct listaddr *)NULL; v->uv_prune_lifetime = 0; v->uv_acl = (struct vif_acl *)NULL; v->uv_leaf_timer = 0; v->uv_addrs = (struct phaddr *)NULL; v->uv_filter = (struct vif_filter *)NULL; v->uv_pim_hello_timer = 0; v->uv_gq_timer = 0; v->uv_pim_neighbors = (struct pim_nbr_entry *)NULL; v->uv_local_pref = default_source_preference; v->uv_local_metric = default_source_metric; add_phaddr(v, &addr, &mask); if (flags & IFF_POINTOPOINT) v->uv_flags |= (VIFF_REXMIT_PRUNES | VIFF_POINT_TO_POINT); syslog(LOG_INFO, "installing %s as if #%u - rate=%d", v->uv_name, numvifs, v->uv_rate_limit); ++numvifs; /* * If the interface is not yet up, set the vifs_down flag to * remind us to check again later. */ if (!(flags & IFF_UP)) { v->uv_flags |= VIFF_DOWN; vifs_down = TRUE; } } freeifaddrs(ifap); #else /* !HAVE_GETIFADDRS */ ifc.ifc_len = num_ifreq * sizeof(struct ifreq); ifc.ifc_buf = calloc(ifc.ifc_len, sizeof(char)); while (ifc.ifc_buf) { caddr_t newbuf; if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0) syslog(LOG_ERR, "ioctl SIOCGIFCONF"); /* * If the buffer was large enough to hold all the addresses * then break out, otherwise increase the buffer size and * try again. * * The only way to know that we definitely had enough space * is to know that there was enough space for at least one * more struct ifreq. ??? */ if ((num_ifreq * sizeof(struct ifreq)) >= ifc.ifc_len + sizeof(struct ifreq)) break; num_ifreq *= 2; ifc.ifc_len = num_ifreq * sizeof(struct ifreq); newbuf = realloc(ifc.ifc_buf, ifc.ifc_len); if (newbuf == NULL) free(ifc.ifc_buf); ifc.ifc_buf = newbuf; } if (ifc.ifc_buf == NULL) syslog(LOG_ERR, "config_vifs_from_kernel: ran out of memory"); ifrp = (struct ifreq *)ifc.ifc_buf; ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len); /* * Loop through all of the interfaces. */ for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) { struct ifreq ifr; struct in6_ifreq ifr6; #ifdef HAVE_SA_LEN n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); if (n < sizeof(*ifrp)) n = sizeof(*ifrp); #else n = sizeof(*ifrp); #endif /* HAVE_SA_LEN */ /* * Ignore any interface for an address family other than IPv6. */ if (ifrp->ifr_addr.sa_family != AF_INET6) { total_interfaces++; /* Eventually may have IPv6 address later */ continue; } memcpy(&addr, &ifrp->ifr_addr, sizeof(struct sockaddr_in6)); /* * Need a template to preserve address info that is * used below to locate the next entry. (Otherwise, * SIOCGIFFLAGS stomps over it because the requests * are returned in a union.) */ memcpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name)); memcpy(ifr6.ifr_name, ifrp->ifr_name, sizeof(ifr6.ifr_name)); /* * Ignore loopback interfaces and interfaces that do not * support multicast. */ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0) syslog(LOG_ERR, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name); flags = ifr.ifr_flags; if ((flags & (IFF_LOOPBACK | IFF_MULTICAST)) != IFF_MULTICAST) continue; /* * Get netmask of the address. */ ifr6.ifr_addr = *(struct sockaddr_in6 *)&ifrp->ifr_addr; if (ioctl(udp_socket, SIOCGIFNETMASK_IN6, (char *)&ifr6) < 0) syslog(LOG_ERR, "ioctl SIOCGIFNETMASK_IN6 for %s", ifr6.ifr_name); memcpy(&mask, &ifr6.ifr_addr.sin6_addr, sizeof(mask)); if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr)) { addr.sin6_scope_id = if_nametoindex(ifrp->ifr_name); #ifdef __KAME__ /* * Hack for KAME kernel. Set sin6_scope_id field of a * link local address and clear the index embedded in * the address. */ /* clear interface index */ addr.sin6_addr.s6_addr[2] = 0; addr.sin6_addr.s6_addr[3] = 0; #endif } /* * If the address is connected to the same subnet as one already * installed in the uvifs array, just add the address to the list * of addresses of the uvif. */ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { if (strcmp(v->uv_name, ifr.ifr_name) == 0) { add_phaddr(v, &addr, &mask); break; } } if (vifi != numvifs) continue; /* * If there is room in the uvifs array, install this interface. */ if (numvifs == MAXMIFS) { syslog(LOG_WARNING, "too many ifs, ignoring %s", ifr.ifr_name); continue; } /* * Everyone below is a potential vif interface. * We don't care if it has wrong configuration or not configured * at all. */ total_interfaces++; v = &uvifs[numvifs]; v->uv_flags = 0; v->uv_metric = DEFAULT_METRIC; v->uv_admetric = 0; v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT; v->uv_dst_addr = allpim6routers_group; v->uv_prefix.sin6_addr = prefix; v->uv_subnetmask = mask; strncpy(v->uv_name, ifr.ifr_name, IFNAMSIZ); v->uv_ifindex = if_nametoindex(v->uv_name); v->uv_groups = (struct listaddr *)NULL; v->uv_dvmrp_neighbors = (struct listaddr *)NULL; NBRM_CLRALL(v->uv_nbrmap); v->uv_querier = (struct listaddr *)NULL; v->uv_prune_lifetime = 0; v->uv_acl = (struct vif_acl *)NULL; v->uv_leaf_timer = 0; v->uv_addrs = (struct phaddr *)NULL; v->uv_filter = (struct vif_filter *)NULL; v->uv_pim_hello_timer = 0; v->uv_gq_timer = 0; v->uv_pim_neighbors = (struct pim_nbr_entry *)NULL; v->uv_local_pref = default_source_preference; v->uv_local_metric = default_source_metric; add_phaddr(v, &addr, &mask); if (flags & IFF_POINTOPOINT) v->uv_flags |= (VIFF_REXMIT_PRUNES | VIFF_POINT_TO_POINT); syslog(LOG_INFO, "installing %s as if #%u - rate=%d", v->uv_name, numvifs, v->uv_rate_limit); ++numvifs; /* * If the interface is not yet up, set the vifs_down flag to * remind us to check again later. */ if (!(flags & IFF_UP)) { v->uv_flags |= VIFF_DOWN; vifs_down = TRUE; } } #endif /* HAVE_GETIFADDRS */ }