📄 addrconf.c
字号:
write_unlock_bh(&addrconf_hash_lock); write_lock_bh(&idev->lock); /* Add to inet6_dev unicast addr list. */ ifa->if_next = idev->addr_list; idev->addr_list = ifa;#ifdef CONFIG_IPV6_PRIVACY ifa->regen_count = 0; if (ifa->flags&IFA_F_TEMPORARY) { ifa->tmp_next = idev->tempaddr_list; idev->tempaddr_list = ifa; in6_ifa_hold(ifa); } else { ifa->tmp_next = NULL; }#endif ifa->rt = rt; in6_ifa_hold(ifa); write_unlock_bh(&idev->lock); read_unlock(&addrconf_lock);out: spin_unlock_bh(&lock); if (unlikely(err == 0)) notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); else { kfree(ifa); ifa = ERR_PTR(err); } return ifa;}/* This function wants to get referenced ifp and releases it before return */static void ipv6_del_addr(struct inet6_ifaddr *ifp){ struct inet6_ifaddr *ifa, **ifap; struct inet6_dev *idev = ifp->idev; int hash; hash = ipv6_addr_hash(&ifp->addr); ifp->dead = 1; write_lock_bh(&addrconf_hash_lock); for (ifap = &inet6_addr_lst[hash]; (ifa=*ifap) != NULL; ifap = &ifa->lst_next) { if (ifa == ifp) { *ifap = ifa->lst_next; __in6_ifa_put(ifp); ifa->lst_next = NULL; break; } } write_unlock_bh(&addrconf_hash_lock); write_lock_bh(&idev->lock);#ifdef CONFIG_IPV6_PRIVACY if (ifp->flags&IFA_F_TEMPORARY) { for (ifap = &idev->tempaddr_list; (ifa=*ifap) != NULL; ifap = &ifa->tmp_next) { if (ifa == ifp) { *ifap = ifa->tmp_next; if (ifp->ifpub) { in6_ifa_put(ifp->ifpub); ifp->ifpub = NULL; } __in6_ifa_put(ifp); ifa->tmp_next = NULL; break; } } }#endif for (ifap = &idev->addr_list; (ifa=*ifap) != NULL; ifap = &ifa->if_next) { if (ifa == ifp) { *ifap = ifa->if_next; __in6_ifa_put(ifp); ifa->if_next = NULL; break; } } write_unlock_bh(&idev->lock); ipv6_ifa_notify(RTM_DELADDR, ifp); notifier_call_chain(&inet6addr_chain,NETDEV_DOWN,ifp); addrconf_del_timer(ifp); in6_ifa_put(ifp);}#ifdef CONFIG_IPV6_PRIVACYstatic int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *ift){ struct inet6_dev *idev; struct in6_addr addr, *tmpaddr; unsigned long tmp_prefered_lft, tmp_valid_lft; int tmp_plen; int ret = 0; int max_addresses; if (ift) { spin_lock_bh(&ift->lock); memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8); spin_unlock_bh(&ift->lock); tmpaddr = &addr; } else { tmpaddr = NULL; }retry: spin_lock_bh(&ifp->lock); in6_ifa_hold(ifp); idev = ifp->idev; in6_dev_hold(idev); memcpy(addr.s6_addr, ifp->addr.s6_addr, 8); write_lock(&idev->lock); if (idev->cnf.use_tempaddr <= 0) { write_unlock(&idev->lock); spin_unlock_bh(&ifp->lock); printk(KERN_INFO "ipv6_create_tempaddr(): use_tempaddr is disabled.\n"); in6_dev_put(idev); in6_ifa_put(ifp); ret = -1; goto out; } if (ifp->regen_count++ >= idev->cnf.regen_max_retry) { idev->cnf.use_tempaddr = -1; /*XXX*/ write_unlock(&idev->lock); spin_unlock_bh(&ifp->lock); printk(KERN_WARNING "ipv6_create_tempaddr(): regeneration time exceeded. disabled temporary address support.\n"); in6_dev_put(idev); in6_ifa_put(ifp); ret = -1; goto out; } if (__ipv6_try_regen_rndid(idev, tmpaddr) < 0) { write_unlock(&idev->lock); spin_unlock_bh(&ifp->lock); printk(KERN_WARNING "ipv6_create_tempaddr(): regeneration of randomized interface id failed.\n"); in6_dev_put(idev); in6_ifa_put(ifp); ret = -1; goto out; } memcpy(&addr.s6_addr[8], idev->rndid, 8); tmp_valid_lft = min_t(__u32, ifp->valid_lft, idev->cnf.temp_valid_lft); tmp_prefered_lft = min_t(__u32, ifp->prefered_lft, idev->cnf.temp_prefered_lft - desync_factor / HZ); tmp_plen = ifp->prefix_len; max_addresses = idev->cnf.max_addresses; write_unlock(&idev->lock); spin_unlock_bh(&ifp->lock); ift = !max_addresses || ipv6_count_addresses(idev) < max_addresses ? ipv6_add_addr(idev, &addr, tmp_plen, ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL; if (!ift || IS_ERR(ift)) { in6_dev_put(idev); in6_ifa_put(ifp); printk(KERN_INFO "ipv6_create_tempaddr(): retry temporary address regeneration.\n"); tmpaddr = &addr; goto retry; } spin_lock_bh(&ift->lock); ift->ifpub = ifp; ift->valid_lft = tmp_valid_lft; ift->prefered_lft = tmp_prefered_lft; ift->cstamp = ifp->cstamp; ift->tstamp = ifp->tstamp; spin_unlock_bh(&ift->lock); addrconf_dad_start(ift, 0); in6_ifa_put(ift); in6_dev_put(idev);out: return ret;}#endif/* * Choose an appropriate source address * should do: * i) get an address with an appropriate scope * ii) see if there is a specific route for the destination and use * an address of the attached interface * iii) don't use deprecated addresses */static int inline ipv6_saddr_pref(const struct inet6_ifaddr *ifp, u8 invpref){ int pref; pref = ifp->flags&IFA_F_DEPRECATED ? 0 : 2;#ifdef CONFIG_IPV6_PRIVACY pref |= (ifp->flags^invpref)&IFA_F_TEMPORARY ? 0 : 1;#endif return pref;}#ifdef CONFIG_IPV6_PRIVACY#define IPV6_GET_SADDR_MAXSCORE(score) ((score) == 3)#else#define IPV6_GET_SADDR_MAXSCORE(score) (score)#endifint ipv6_dev_get_saddr(struct net_device *dev, struct in6_addr *daddr, struct in6_addr *saddr, int onlink){ struct inet6_ifaddr *ifp = NULL; struct inet6_ifaddr *match = NULL; struct inet6_dev *idev; int scope; int err; int hiscore = -1, score; if (!onlink) scope = ipv6_addr_scope(daddr); else scope = IFA_LINK; /* * known dev * search dev and walk through dev addresses */ if (dev) { if (dev->flags & IFF_LOOPBACK) scope = IFA_HOST; read_lock(&addrconf_lock); idev = __in6_dev_get(dev); if (idev) { read_lock_bh(&idev->lock); for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { if (ifp->scope == scope) { if (ifp->flags&IFA_F_TENTATIVE) continue;#ifdef CONFIG_IPV6_PRIVACY score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);#else score = ipv6_saddr_pref(ifp, 0);#endif if (score <= hiscore) continue; if (match) in6_ifa_put(match); match = ifp; hiscore = score; in6_ifa_hold(ifp); if (IPV6_GET_SADDR_MAXSCORE(score)) { read_unlock_bh(&idev->lock); read_unlock(&addrconf_lock); goto out; } } } read_unlock_bh(&idev->lock); } read_unlock(&addrconf_lock); } if (scope == IFA_LINK) goto out; /* * dev == NULL or search failed for specified dev */ read_lock(&dev_base_lock); read_lock(&addrconf_lock); for (dev = dev_base; dev; dev=dev->next) { idev = __in6_dev_get(dev); if (idev) { read_lock_bh(&idev->lock); for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { if (ifp->scope == scope) { if (ifp->flags&IFA_F_TENTATIVE) continue;#ifdef CONFIG_IPV6_PRIVACY score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);#else score = ipv6_saddr_pref(ifp, 0);#endif if (score <= hiscore) continue; if (match) in6_ifa_put(match); match = ifp; hiscore = score; in6_ifa_hold(ifp); if (IPV6_GET_SADDR_MAXSCORE(score)) { read_unlock_bh(&idev->lock); goto out_unlock_base; } } } read_unlock_bh(&idev->lock); } }out_unlock_base: read_unlock(&addrconf_lock); read_unlock(&dev_base_lock);out: err = -EADDRNOTAVAIL; if (match) { ipv6_addr_copy(saddr, &match->addr); err = 0; in6_ifa_put(match); } return err;}int ipv6_get_saddr(struct dst_entry *dst, struct in6_addr *daddr, struct in6_addr *saddr){ struct rt6_info *rt; struct net_device *dev = NULL; int onlink; rt = (struct rt6_info *) dst; if (rt) dev = rt->rt6i_dev; onlink = (rt && (rt->rt6i_flags & RTF_ALLONLINK)); return ipv6_dev_get_saddr(dev, daddr, saddr, onlink);}int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr){ struct inet6_dev *idev; int err = -EADDRNOTAVAIL; read_lock(&addrconf_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&IFA_F_TENTATIVE)) { ipv6_addr_copy(addr, &ifp->addr); err = 0; break; } } read_unlock_bh(&idev->lock); } read_unlock(&addrconf_lock); 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_cmp(&ifp->addr, addr) == 0 && !(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;}staticint ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev){ 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_cmp(&ifp->addr, addr) == 0) { if (dev == NULL || ifp->idev->dev == dev) break; } } read_unlock_bh(&addrconf_hash_lock); 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_cmp(&ifp->addr, addr) == 0) { 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 = tcp_v6_rcv_saddr(sk2); u32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr; u32 sk2_rcv_saddr = tcp_v4_rcv_saddr(sk2); int sk_ipv6only = ipv6_only_sock(sk); int sk2_ipv6only = tcp_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_cmp(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 */void addrconf_dad_failure(struct inet6_ifaddr *ifp){ if (net_ratelimit()) printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); 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);}/* 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);}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);}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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -