📄 addrconf.c
字号:
}void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len){ struct prefix_info *pinfo; __u32 valid_lft; __u32 prefered_lft; int addr_type; unsigned long rt_expires; struct inet6_dev *in6_dev; pinfo = (struct prefix_info *) opt; if (len < sizeof(struct prefix_info)) { ADBG(("addrconf: prefix option too short\n")); return; } /* * Validation checks ([ADDRCONF], page 19) */ addr_type = ipv6_addr_type(&pinfo->prefix); if (addr_type & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL)) return; valid_lft = ntohl(pinfo->valid); prefered_lft = ntohl(pinfo->prefered); if (prefered_lft > valid_lft) { if (net_ratelimit()) printk(KERN_WARNING "addrconf: prefix option has invalid lifetime\n"); return; } in6_dev = in6_dev_get(dev); if (in6_dev == NULL) { if (net_ratelimit()) printk(KERN_DEBUG "addrconf: device %s not configured\n", dev->name); return; } /* * Two things going on here: * 1) Add routes for on-link prefixes * 2) Configure prefixes with the auto flag set */ /* Avoid arithmetic overflow. Really, we could save rt_expires in seconds, likely valid_lft, but it would require division in fib gc, that it not good. */ if (valid_lft >= 0x7FFFFFFF/HZ) rt_expires = 0x7FFFFFFF - (0x7FFFFFFF % HZ); else rt_expires = valid_lft * HZ; /* * We convert this (in jiffies) to clock_t later. * Avoid arithmetic overflow there as well. * Overflow can happen only if HZ < USER_HZ. */ if (HZ < USER_HZ && rt_expires > 0x7FFFFFFF / USER_HZ) rt_expires = 0x7FFFFFFF / USER_HZ; if (pinfo->onlink) { struct rt6_info *rt; rt = rt6_lookup(&pinfo->prefix, NULL, dev->ifindex, 1); if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { if (rt->rt6i_flags&RTF_EXPIRES) { if (valid_lft == 0) { ip6_del_rt(rt); rt = NULL; } else { rt->rt6i_expires = jiffies + rt_expires; } } } else if (valid_lft) { addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, dev, jiffies_to_clock_t(rt_expires), RTF_ADDRCONF|RTF_EXPIRES|RTF_PREFIX_RT); } if (rt) dst_release(&rt->u.dst); } /* Try to figure out our local address for this prefix */ if (pinfo->autoconf && in6_dev->cnf.autoconf) { struct inet6_ifaddr * ifp; struct in6_addr addr; int create = 0, update_lft = 0; if (pinfo->prefix_len == 64) { memcpy(&addr, &pinfo->prefix, 8); if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) { in6_dev_put(in6_dev); return; } goto ok; } if (net_ratelimit()) printk(KERN_DEBUG "IPv6 addrconf: prefix with wrong length %d\n", pinfo->prefix_len); in6_dev_put(in6_dev); return;ok: ifp = ipv6_get_ifaddr(&addr, dev, 1); if (ifp == NULL && valid_lft) { int max_addresses = in6_dev->cnf.max_addresses; u32 addr_flags = 0;#ifdef CONFIG_IPV6_OPTIMISTIC_DAD if (in6_dev->cnf.optimistic_dad && !ipv6_devconf.forwarding) addr_flags = IFA_F_OPTIMISTIC;#endif /* Do not allow to create too much of autoconfigured * addresses; this would be too easy way to crash kernel. */ if (!max_addresses || ipv6_count_addresses(in6_dev) < max_addresses) ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len, addr_type&IPV6_ADDR_SCOPE_MASK, addr_flags); if (!ifp || IS_ERR(ifp)) { in6_dev_put(in6_dev); return; } update_lft = create = 1; ifp->cstamp = jiffies; addrconf_dad_start(ifp, RTF_ADDRCONF|RTF_PREFIX_RT); } if (ifp) { int flags; unsigned long now;#ifdef CONFIG_IPV6_PRIVACY struct inet6_ifaddr *ift;#endif u32 stored_lft; /* update lifetime (RFC2462 5.5.3 e) */ spin_lock(&ifp->lock); now = jiffies; if (ifp->valid_lft > (now - ifp->tstamp) / HZ) stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ; else stored_lft = 0; if (!update_lft && stored_lft) { if (valid_lft > MIN_VALID_LIFETIME || valid_lft > stored_lft) update_lft = 1; else if (stored_lft <= MIN_VALID_LIFETIME) { /* valid_lft <= stored_lft is always true */ /* XXX: IPsec */ update_lft = 0; } else { valid_lft = MIN_VALID_LIFETIME; if (valid_lft < prefered_lft) prefered_lft = valid_lft; update_lft = 1; } } if (update_lft) { ifp->valid_lft = valid_lft; ifp->prefered_lft = prefered_lft; ifp->tstamp = now; flags = ifp->flags; ifp->flags &= ~IFA_F_DEPRECATED; spin_unlock(&ifp->lock); if (!(flags&IFA_F_TENTATIVE)) ipv6_ifa_notify(0, ifp); } else spin_unlock(&ifp->lock);#ifdef CONFIG_IPV6_PRIVACY read_lock_bh(&in6_dev->lock); /* update all temporary addresses in the list */ for (ift=in6_dev->tempaddr_list; ift; ift=ift->tmp_next) { /* * When adjusting the lifetimes of an existing * temporary address, only lower the lifetimes. * Implementations must not increase the * lifetimes of an existing temporary address * when processing a Prefix Information Option. */ spin_lock(&ift->lock); flags = ift->flags; if (ift->valid_lft > valid_lft && ift->valid_lft - valid_lft > (jiffies - ift->tstamp) / HZ) ift->valid_lft = valid_lft + (jiffies - ift->tstamp) / HZ; if (ift->prefered_lft > prefered_lft && ift->prefered_lft - prefered_lft > (jiffies - ift->tstamp) / HZ) ift->prefered_lft = prefered_lft + (jiffies - ift->tstamp) / HZ; spin_unlock(&ift->lock); if (!(flags&IFA_F_TENTATIVE)) ipv6_ifa_notify(0, ift); } if (create && in6_dev->cnf.use_tempaddr > 0) { /* * When a new public address is created as described in [ADDRCONF], * also create a new temporary address. */ read_unlock_bh(&in6_dev->lock); ipv6_create_tempaddr(ifp, NULL); } else { read_unlock_bh(&in6_dev->lock); }#endif in6_ifa_put(ifp); addrconf_verify(0); } } inet6_prefix_notify(RTM_NEWPREFIX, in6_dev, pinfo); in6_dev_put(in6_dev);}/* * Set destination address. * Special case for SIT interfaces where we create a new "virtual" * device. */int addrconf_set_dstaddr(void __user *arg){ struct in6_ifreq ireq; struct net_device *dev; int err = -EINVAL; rtnl_lock(); err = -EFAULT; if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) goto err_exit; dev = __dev_get_by_index(&init_net, ireq.ifr6_ifindex); err = -ENODEV; if (dev == NULL) goto err_exit;#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) if (dev->type == ARPHRD_SIT) { struct ifreq ifr; mm_segment_t oldfs; struct ip_tunnel_parm p; err = -EADDRNOTAVAIL; if (!(ipv6_addr_type(&ireq.ifr6_addr) & IPV6_ADDR_COMPATv4)) goto err_exit; memset(&p, 0, sizeof(p)); p.iph.daddr = ireq.ifr6_addr.s6_addr32[3]; p.iph.saddr = 0; p.iph.version = 4; p.iph.ihl = 5; p.iph.protocol = IPPROTO_IPV6; p.iph.ttl = 64; ifr.ifr_ifru.ifru_data = (void __user *)&p; oldfs = get_fs(); set_fs(KERNEL_DS); err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL); set_fs(oldfs); if (err == 0) { err = -ENOBUFS; if ((dev = __dev_get_by_name(&init_net, p.name)) == NULL) goto err_exit; err = dev_open(dev); } }#endiferr_exit: rtnl_unlock(); return err;}/* * Manual configuration of address on an interface */static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft){ struct inet6_ifaddr *ifp; struct inet6_dev *idev; struct net_device *dev; int scope; u32 flags = RTF_EXPIRES; ASSERT_RTNL(); /* check the lifetime */ if (!valid_lft || prefered_lft > valid_lft) return -EINVAL; if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL) return -ENODEV; if ((idev = addrconf_add_dev(dev)) == NULL) return -ENOBUFS; scope = ipv6_addr_scope(pfx); if (valid_lft == INFINITY_LIFE_TIME) { ifa_flags |= IFA_F_PERMANENT; flags = 0; } else if (valid_lft >= 0x7FFFFFFF/HZ) valid_lft = 0x7FFFFFFF/HZ; if (prefered_lft == 0) ifa_flags |= IFA_F_DEPRECATED; else if ((prefered_lft >= 0x7FFFFFFF/HZ) && (prefered_lft != INFINITY_LIFE_TIME)) prefered_lft = 0x7FFFFFFF/HZ; ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags); if (!IS_ERR(ifp)) { spin_lock_bh(&ifp->lock); ifp->valid_lft = valid_lft; ifp->prefered_lft = prefered_lft; ifp->tstamp = jiffies; spin_unlock_bh(&ifp->lock); addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, jiffies_to_clock_t(valid_lft * HZ), flags); /* * Note that section 3.1 of RFC 4429 indicates * that the Optimistic flag should not be set for * manually configured addresses */ addrconf_dad_start(ifp, 0); in6_ifa_put(ifp); addrconf_verify(0); return 0; } return PTR_ERR(ifp);}static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen){ struct inet6_ifaddr *ifp; struct inet6_dev *idev; struct net_device *dev; if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL) return -ENODEV; if ((idev = __in6_dev_get(dev)) == NULL) return -ENXIO; read_lock_bh(&idev->lock); for (ifp = idev->addr_list; ifp; ifp=ifp->if_next) { if (ifp->prefix_len == plen && ipv6_addr_equal(pfx, &ifp->addr)) { in6_ifa_hold(ifp); read_unlock_bh(&idev->lock); ipv6_del_addr(ifp); /* If the last address is deleted administratively, disable IPv6 on this interface. */ if (idev->addr_list == NULL) addrconf_ifdown(idev->dev, 1); return 0; } } read_unlock_bh(&idev->lock); return -EADDRNOTAVAIL;}int addrconf_add_ifaddr(void __user *arg){ struct in6_ifreq ireq; int err; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) return -EFAULT; rtnl_lock(); err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen, IFA_F_PERMANENT, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); rtnl_unlock(); return err;}int addrconf_del_ifaddr(void __user *arg){ struct in6_ifreq ireq; int err; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) return -EFAULT; rtnl_lock(); err = inet6_addr_del(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen); rtnl_unlock(); return err;}#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)static void sit_add_v4_addrs(struct inet6_dev *idev){ struct inet6_ifaddr * ifp; struct in6_addr addr; struct net_device *dev; int scope; ASSERT_RTNL(); memset(&addr, 0, sizeof(struct in6_addr)); memcpy(&addr.s6_addr32[3], idev->dev->dev_addr, 4); if (idev->dev->flags&IFF_POINTOPOINT) { addr.s6_addr32[0] = htonl(0xfe800000); scope = IFA_LINK; } else { scope = IPV6_ADDR_COMPATv4; } if (addr.s6_addr32[3]) { ifp = ipv6_add_addr(idev, &addr, 128, scope, IFA_F_PERMANENT); if (!IS_ERR(ifp)) { spin_lock_bh(&ifp->lock); ifp->flags &= ~IFA_F_TENTATIVE; spin_unlock_bh(&ifp->lock); ipv6_ifa_notify(RTM_NEWADDR, ifp); in6_ifa_put(ifp); } return; } for_each_netdev(&init_net, dev) { struct in_device * in_dev = __in_dev_get_rtnl(dev); if (in_dev && (dev->flags & IFF_UP)) { struct in_ifaddr * ifa; int flag = scope; for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { int plen; addr.s6_addr32[3] = ifa->ifa_local; if (ifa->ifa_scope == RT_SCOPE_LINK) continue; if (ifa->ifa_scope >= RT_SCOPE_HOST) { if (idev->dev->flags&IFF_POINTOPOINT) continue; flag |= IFA_HOST; } if (idev->dev->flags&IFF_POINTOPOINT) plen = 64; else plen = 96; ifp = ipv6_add_addr(idev, &addr, plen, flag, IFA_F_PERMANENT); if (!IS_ERR(ifp)) { spin_lock_bh(&ifp->lock); ifp->flags &= ~IFA_F_TENTATIVE; spin_unlock_bh(&ifp->lock); ipv6_ifa_notify(RTM_NEWADDR, ifp); in6_ifa_put(ifp); } } } }}#endifstatic void init_loopback(struct net_device *dev){ struct inet6_dev *idev; struct inet6_ifaddr * ifp; /* ::1 */ ASSERT_RTNL(); if ((idev = ipv6_find_idev(dev)) == NULL) { printk(KERN_DEBUG "init loopback: add_dev failed\n"); return; } ifp = ipv6_add_addr(idev, &in6addr_loopback, 128, IFA_HOST, IFA_F_PERMANENT); if (!IS_ERR(ifp)) { spin_lock_bh(&ifp->lock); ifp->flags &= ~IFA_F_TENTATIVE; spin_unlock_bh(&ifp->lock); ipv6_ifa_notify(RTM_NEWADDR, ifp); in6_ifa_put(ifp); }}static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr){ struct inet6_ifaddr * ifp; u32 addr_flags = IFA_F_PERMANENT;#ifdef CONFIG_IPV6_OPTIMISTIC_DAD if (idev->cnf.optimistic_dad && !ipv6_devconf.forwarding) addr_flags |= IFA_F_OPTIMISTIC;#endif ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags); if (!IS_ERR(ifp)) { addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); addrconf_dad_start(ifp, 0); in6_ifa_put(ifp); }}static void addrconf_dev_config(struct net_device *dev){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -