📄 addrconf.c
字号:
} else { if (hiscore.attrs & IPV6_SADDR_SCORE_OIF) continue; } /* Rule 6: Prefer matching label */ if (hiscore.rule < 6) { if (ipv6_saddr_label(&ifa_result->addr, hiscore.addr_type) == daddr_label) hiscore.attrs |= IPV6_SADDR_SCORE_LABEL; hiscore.rule++; } if (ipv6_saddr_label(&ifa->addr, score.addr_type) == daddr_label) { score.attrs |= IPV6_SADDR_SCORE_LABEL; if (!(hiscore.attrs & IPV6_SADDR_SCORE_LABEL)) { score.rule = 6; goto record_it; } } else { if (hiscore.attrs & IPV6_SADDR_SCORE_LABEL) continue; }#ifdef CONFIG_IPV6_PRIVACY /* Rule 7: Prefer public address * Note: prefer temprary address if use_tempaddr >= 2 */ if (hiscore.rule < 7) { if ((!(ifa_result->flags & IFA_F_TEMPORARY)) ^ (ifa_result->idev->cnf.use_tempaddr >= 2)) hiscore.attrs |= IPV6_SADDR_SCORE_PRIVACY; hiscore.rule++; } if ((!(ifa->flags & IFA_F_TEMPORARY)) ^ (ifa->idev->cnf.use_tempaddr >= 2)) { score.attrs |= IPV6_SADDR_SCORE_PRIVACY; if (!(hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)) { score.rule = 7; goto record_it; } } else { if (hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY) continue; }#else if (hiscore.rule < 7) hiscore.rule++;#endif /* Rule 8: Use longest matching prefix */ if (hiscore.rule < 8) { hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr); hiscore.rule++; } score.matchlen = ipv6_addr_diff(&ifa->addr, daddr); if (score.matchlen > hiscore.matchlen) { score.rule = 8; goto record_it; }#if 0 else if (score.matchlen < hiscore.matchlen) continue;#endif /* Final Rule: choose first available one */ continue;record_it: if (ifa_result) in6_ifa_put(ifa_result); in6_ifa_hold(ifa); ifa_result = ifa; hiscore = score; } read_unlock_bh(&idev->lock); } rcu_read_unlock(); read_unlock(&dev_base_lock); if (!ifa_result) return -EADDRNOTAVAIL; ipv6_addr_copy(saddr, &ifa_result->addr); in6_ifa_put(ifa_result); return 0;}int ipv6_get_saddr(struct dst_entry *dst, struct in6_addr *daddr, struct in6_addr *saddr){ return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr);}EXPORT_SYMBOL(ipv6_get_saddr);int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, unsigned char banned_flags){ struct inet6_dev *idev; int err = -EADDRNOTAVAIL; rcu_read_lock(); if ((idev = __in6_dev_get(dev)) != NULL) { struct inet6_ifaddr *ifp; read_lock_bh(&idev->lock); for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) { ipv6_addr_copy(addr, &ifp->addr); err = 0; break; } } read_unlock_bh(&idev->lock); } rcu_read_unlock(); return err;}static int ipv6_count_addresses(struct inet6_dev *idev){ int cnt = 0; struct inet6_ifaddr *ifp; read_lock_bh(&idev->lock); for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) cnt++; read_unlock_bh(&idev->lock); return cnt;}int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev, int strict){ struct inet6_ifaddr * ifp; u8 hash = ipv6_addr_hash(addr); read_lock_bh(&addrconf_hash_lock); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { if (ipv6_addr_equal(&ifp->addr, addr) && !(ifp->flags&IFA_F_TENTATIVE)) { if (dev == NULL || ifp->idev->dev == dev || !(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) break; } } read_unlock_bh(&addrconf_hash_lock); return ifp != NULL;}EXPORT_SYMBOL(ipv6_chk_addr);staticint ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev){ struct inet6_ifaddr * ifp; u8 hash = ipv6_addr_hash(addr); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { if (ipv6_addr_equal(&ifp->addr, addr)) { if (dev == NULL || ifp->idev->dev == dev) break; } } return ifp != NULL;}struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, struct net_device *dev, int strict){ struct inet6_ifaddr * ifp; u8 hash = ipv6_addr_hash(addr); read_lock_bh(&addrconf_hash_lock); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { if (ipv6_addr_equal(&ifp->addr, addr)) { if (dev == NULL || ifp->idev->dev == dev || !(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) { in6_ifa_hold(ifp); break; } } } read_unlock_bh(&addrconf_hash_lock); return ifp;}int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2){ const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); __be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr; __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); int sk_ipv6only = ipv6_only_sock(sk); int sk2_ipv6only = inet_v6_ipv6only(sk2); int addr_type = ipv6_addr_type(sk_rcv_saddr6); int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; if (!sk2_rcv_saddr && !sk_ipv6only) return 1; if (addr_type2 == IPV6_ADDR_ANY && !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) return 1; if (addr_type == IPV6_ADDR_ANY && !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) return 1; if (sk2_rcv_saddr6 && ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) return 1; if (addr_type == IPV6_ADDR_MAPPED && !sk2_ipv6only && (!sk2_rcv_saddr || !sk_rcv_saddr || sk_rcv_saddr == sk2_rcv_saddr)) return 1; return 0;}/* Gets referenced address, destroys ifaddr */static void addrconf_dad_stop(struct inet6_ifaddr *ifp){ if (ifp->flags&IFA_F_PERMANENT) { spin_lock_bh(&ifp->lock); addrconf_del_timer(ifp); ifp->flags |= IFA_F_TENTATIVE; spin_unlock_bh(&ifp->lock); in6_ifa_put(ifp);#ifdef CONFIG_IPV6_PRIVACY } else if (ifp->flags&IFA_F_TEMPORARY) { struct inet6_ifaddr *ifpub; spin_lock_bh(&ifp->lock); ifpub = ifp->ifpub; if (ifpub) { in6_ifa_hold(ifpub); spin_unlock_bh(&ifp->lock); ipv6_create_tempaddr(ifpub, ifp); in6_ifa_put(ifpub); } else { spin_unlock_bh(&ifp->lock); } ipv6_del_addr(ifp);#endif } else ipv6_del_addr(ifp);}void addrconf_dad_failure(struct inet6_ifaddr *ifp){ if (net_ratelimit()) printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); addrconf_dad_stop(ifp);}/* Join to solicited addr multicast group. */void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr){ struct in6_addr maddr; if (dev->flags&(IFF_LOOPBACK|IFF_NOARP)) return; addrconf_addr_solict_mult(addr, &maddr); ipv6_dev_mc_inc(dev, &maddr);}void addrconf_leave_solict(struct inet6_dev *idev, struct in6_addr *addr){ struct in6_addr maddr; if (idev->dev->flags&(IFF_LOOPBACK|IFF_NOARP)) return; addrconf_addr_solict_mult(addr, &maddr); __ipv6_dev_mc_dec(idev, &maddr);}static void addrconf_join_anycast(struct inet6_ifaddr *ifp){ struct in6_addr addr; ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len); if (ipv6_addr_any(&addr)) return; ipv6_dev_ac_inc(ifp->idev->dev, &addr);}static void addrconf_leave_anycast(struct inet6_ifaddr *ifp){ struct in6_addr addr; ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len); if (ipv6_addr_any(&addr)) return; __ipv6_dev_ac_dec(ifp->idev, &addr);}static int addrconf_ifid_eui48(u8 *eui, struct net_device *dev){ if (dev->addr_len != ETH_ALEN) return -1; memcpy(eui, dev->dev_addr, 3); memcpy(eui + 5, dev->dev_addr + 3, 3); /* * The zSeries OSA network cards can be shared among various * OS instances, but the OSA cards have only one MAC address. * This leads to duplicate address conflicts in conjunction * with IPv6 if more than one instance uses the same card. * * The driver for these cards can deliver a unique 16-bit * identifier for each instance sharing the same card. It is * placed instead of 0xFFFE in the interface identifier. The * "u" bit of the interface identifier is not inverted in this * case. Hence the resulting interface identifier has local * scope according to RFC2373. */ if (dev->dev_id) { eui[3] = (dev->dev_id >> 8) & 0xFF; eui[4] = dev->dev_id & 0xFF; } else { eui[3] = 0xFF; eui[4] = 0xFE; eui[0] ^= 2; } return 0;}static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev){ /* XXX: inherit EUI-64 from other interface -- yoshfuji */ if (dev->addr_len != ARCNET_ALEN) return -1; memset(eui, 0, 7); eui[7] = *(u8*)dev->dev_addr; return 0;}static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev){ if (dev->addr_len != INFINIBAND_ALEN) return -1; memcpy(eui, dev->dev_addr + 12, 8); eui[0] |= 2; return 0;}static int ipv6_generate_eui64(u8 *eui, struct net_device *dev){ switch (dev->type) { case ARPHRD_ETHER: case ARPHRD_FDDI: case ARPHRD_IEEE802_TR: return addrconf_ifid_eui48(eui, dev); case ARPHRD_ARCNET: return addrconf_ifid_arcnet(eui, dev); case ARPHRD_INFINIBAND: return addrconf_ifid_infiniband(eui, dev); } return -1;}static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev){ int err = -1; struct inet6_ifaddr *ifp; read_lock_bh(&idev->lock); for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { memcpy(eui, ifp->addr.s6_addr+8, 8); err = 0; break; } } read_unlock_bh(&idev->lock); return err;}#ifdef CONFIG_IPV6_PRIVACY/* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */static int __ipv6_regen_rndid(struct inet6_dev *idev){regen: get_random_bytes(idev->rndid, sizeof(idev->rndid)); idev->rndid[0] &= ~0x02; /* * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>: * check if generated address is not inappropriate * * - Reserved subnet anycast (RFC 2526) * 11111101 11....11 1xxxxxxx * - ISATAP (draft-ietf-ngtrans-isatap-13.txt) 5.1 * 00-00-5E-FE-xx-xx-xx-xx * - value 0 * - XXX: already assigned to an address on the device */ if (idev->rndid[0] == 0xfd && (idev->rndid[1]&idev->rndid[2]&idev->rndid[3]&idev->rndid[4]&idev->rndid[5]&idev->rndid[6]) == 0xff && (idev->rndid[7]&0x80)) goto regen; if ((idev->rndid[0]|idev->rndid[1]) == 0) { if (idev->rndid[2] == 0x5e && idev->rndid[3] == 0xfe) goto regen; if ((idev->rndid[2]|idev->rndid[3]|idev->rndid[4]|idev->rndid[5]|idev->rndid[6]|idev->rndid[7]) == 0x00) goto regen; } return 0;}static void ipv6_regen_rndid(unsigned long data){ struct inet6_dev *idev = (struct inet6_dev *) data; unsigned long expires; rcu_read_lock_bh(); write_lock_bh(&idev->lock); if (idev->dead) goto out; if (__ipv6_regen_rndid(idev) < 0) goto out; expires = jiffies + idev->cnf.temp_prefered_lft * HZ - idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - desync_factor; if (time_before(expires, jiffies)) { printk(KERN_WARNING "ipv6_regen_rndid(): too short regeneration interval; timer disabled for %s.\n", idev->dev->name); goto out; } if (!mod_timer(&idev->regen_timer, expires)) in6_dev_hold(idev);out: write_unlock_bh(&idev->lock); rcu_read_unlock_bh(); in6_dev_put(idev);}static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) { int ret = 0; if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0) ret = __ipv6_regen_rndid(idev); return ret;}#endif/* * Add prefix route. */static voidaddrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, unsigned long expires, u32 flags){ struct fib6_config cfg = { .fc_table = RT6_TABLE_PREFIX, .fc_metric = IP6_RT_PRIO_ADDRCONF, .fc_ifindex = dev->ifindex, .fc_expires = expires, .fc_dst_len = plen, .fc_flags = RTF_UP | flags, }; ipv6_addr_copy(&cfg.fc_dst, pfx); /* Prevent useless cloning on PtP SIT. This thing is done here expecting that the whole class of non-broadcast devices need not cloning. */#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT)) cfg.fc_flags |= RTF_NONEXTHOP;#endif ip6_route_add(&cfg);}/* Create "default" multicast route to the interface */static void addrconf_add_mroute(struct net_device *dev){ struct fib6_config cfg = { .fc_table = RT6_TABLE_LOCAL, .fc_metric = IP6_RT_PRIO_ADDRCONF, .fc_ifindex = dev->ifindex, .fc_dst_len = 8, .fc_flags = RTF_UP, }; ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0); ip6_route_add(&cfg);}#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)static void sit_route_add(struct net_device *dev){ struct fib6_config cfg = { .fc_table = RT6_TABLE_MAIN, .fc_metric = IP6_RT_PRIO_ADDRCONF, .fc_ifindex = dev->ifindex, .fc_dst_len = 96, .fc_flags = RTF_UP | RTF_NONEXTHOP, }; /* prefix length - 96 bits "::d.d.d.d" */ ip6_route_add(&cfg);}#endifstatic void addrconf_add_lroute(struct net_device *dev){ struct in6_addr addr; ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); addrconf_prefix_route(&addr, 64, dev, 0, 0);}static struct inet6_dev *addrconf_add_dev(struct net_device *dev){ struct inet6_dev *idev; ASSERT_RTNL(); if ((idev = ipv6_find_idev(dev)) == NULL) return NULL; /* Add default multicast route */ addrconf_add_mroute(dev); /* Add link local route */ addrconf_add_lroute(dev); return idev;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -