📄 addrconf.c
字号:
struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; struct in6_addr unspec; struct in6_addr mcaddr; spin_lock_bh(&ifp->lock); if (ifp->probes == 0) { /* * DAD was successful */ ifp->flags &= ~IFA_F_TENTATIVE; spin_unlock_bh(&ifp->lock); addrconf_dad_completed(ifp); in6_ifa_put(ifp); return; } ifp->probes--; addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); spin_unlock_bh(&ifp->lock); /* send a neighbour solicitation for our addr */ memset(&unspec, 0, sizeof(unspec)); addrconf_addr_solict_mult(&ifp->addr, &mcaddr); ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &unspec); in6_ifa_put(ifp);}static void addrconf_dad_completed(struct inet6_ifaddr *ifp){ struct net_device * dev = ifp->idev->dev; /* * Configure the address for reception. Now it is valid. */ ipv6_ifa_notify(RTM_NEWADDR, ifp); /* If added prefix is link local and forwarding is off, start sending router solicitations. */ if (ifp->idev->cnf.forwarding == 0 && ifp->idev->cnf.rtr_solicits > 0 && (dev->flags&IFF_LOOPBACK) == 0 && (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { struct in6_addr all_routers; ipv6_addr_all_routers(&all_routers); /* * If a host as already performed a random delay * [...] as part of DAD [...] there is no need * to delay again before sending the first RS */ ndisc_send_rs(ifp->idev->dev, &ifp->addr, &all_routers); spin_lock_bh(&ifp->lock); ifp->probes = 1; ifp->idev->if_flags |= IF_RS_SENT; addrconf_mod_timer(ifp, AC_RS, ifp->idev->cnf.rtr_solicit_interval); spin_unlock_bh(&ifp->lock); }}#ifdef CONFIG_PROC_FSstruct if6_iter_state { int bucket;};static struct inet6_ifaddr *if6_get_first(struct seq_file *seq){ struct inet6_ifaddr *ifa = NULL; struct if6_iter_state *state = seq->private; for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { ifa = inet6_addr_lst[state->bucket]; if (ifa) break; } return ifa;}static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifaddr *ifa){ struct if6_iter_state *state = seq->private; ifa = ifa->lst_next;try_again: if (!ifa && ++state->bucket < IN6_ADDR_HSIZE) { ifa = inet6_addr_lst[state->bucket]; goto try_again; } return ifa;}static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos){ struct inet6_ifaddr *ifa = if6_get_first(seq); if (ifa) while(pos && (ifa = if6_get_next(seq, ifa)) != NULL) --pos; return pos ? NULL : ifa;}static void *if6_seq_start(struct seq_file *seq, loff_t *pos){ read_lock_bh(&addrconf_hash_lock); return if6_get_idx(seq, *pos);}static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos){ struct inet6_ifaddr *ifa; ifa = if6_get_next(seq, v); ++*pos; return ifa;}static void if6_seq_stop(struct seq_file *seq, void *v){ read_unlock_bh(&addrconf_hash_lock);}static int if6_seq_show(struct seq_file *seq, void *v){ struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v; seq_printf(seq, "%04x%04x%04x%04x%04x%04x%04x%04x %02x %02x %02x %02x %8s\n", NIP6(ifp->addr), ifp->idev->dev->ifindex, ifp->prefix_len, ifp->scope, ifp->flags, ifp->idev->dev->name); return 0;}static struct seq_operations if6_seq_ops = { .start = if6_seq_start, .next = if6_seq_next, .show = if6_seq_show, .stop = if6_seq_stop,};static int if6_seq_open(struct inode *inode, struct file *file){ struct seq_file *seq; int rc = -ENOMEM; struct if6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); if (!s) goto out; memset(s, 0, sizeof(*s)); rc = seq_open(file, &if6_seq_ops); if (rc) goto out_kfree; seq = file->private_data; seq->private = s;out: return rc;out_kfree: kfree(s); goto out;}static struct file_operations if6_fops = { .owner = THIS_MODULE, .open = if6_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private,};int __init if6_proc_init(void){ if (!proc_net_fops_create("if_inet6", S_IRUGO, &if6_fops)) return -ENOMEM; return 0;}void if6_proc_exit(void){ proc_net_remove("if_inet6");}#endif /* CONFIG_PROC_FS *//* * Periodic address status verification */static void addrconf_verify(unsigned long foo){ struct inet6_ifaddr *ifp; unsigned long now, next; int i; spin_lock_bh(&addrconf_verify_lock); now = jiffies; next = now + ADDR_CHECK_FREQUENCY; del_timer(&addr_chk_timer); for (i=0; i < IN6_ADDR_HSIZE; i++) {restart: write_lock(&addrconf_hash_lock); for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) { unsigned long age;#ifdef CONFIG_IPV6_PRIVACY unsigned long regen_advance;#endif if (ifp->flags & IFA_F_PERMANENT) continue; spin_lock(&ifp->lock); age = (now - ifp->tstamp) / HZ;#ifdef CONFIG_IPV6_PRIVACY regen_advance = ifp->idev->cnf.regen_max_retry * ifp->idev->cnf.dad_transmits * ifp->idev->nd_parms->retrans_time / HZ;#endif if (age >= ifp->valid_lft) { spin_unlock(&ifp->lock); in6_ifa_hold(ifp); write_unlock(&addrconf_hash_lock); ipv6_del_addr(ifp); goto restart; } else if (age >= ifp->prefered_lft) { /* jiffies - ifp->tsamp > age >= ifp->prefered_lft */ int deprecate = 0; if (!(ifp->flags&IFA_F_DEPRECATED)) { deprecate = 1; ifp->flags |= IFA_F_DEPRECATED; } if (time_before(ifp->tstamp + ifp->valid_lft * HZ, next)) next = ifp->tstamp + ifp->valid_lft * HZ; spin_unlock(&ifp->lock); if (deprecate) { in6_ifa_hold(ifp); write_unlock(&addrconf_hash_lock); ipv6_ifa_notify(0, ifp); in6_ifa_put(ifp); goto restart; }#ifdef CONFIG_IPV6_PRIVACY } else if ((ifp->flags&IFA_F_TEMPORARY) && !(ifp->flags&IFA_F_TENTATIVE)) { if (age >= ifp->prefered_lft - regen_advance) { struct inet6_ifaddr *ifpub = ifp->ifpub; if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next)) next = ifp->tstamp + ifp->prefered_lft * HZ; if (!ifp->regen_count && ifpub) { ifp->regen_count++; in6_ifa_hold(ifp); in6_ifa_hold(ifpub); spin_unlock(&ifp->lock); write_unlock(&addrconf_hash_lock); ipv6_create_tempaddr(ifpub, ifp); in6_ifa_put(ifpub); in6_ifa_put(ifp); goto restart; } } else if (time_before(ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ, next)) next = ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ; spin_unlock(&ifp->lock);#endif } else { /* ifp->prefered_lft <= ifp->valid_lft */ if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next)) next = ifp->tstamp + ifp->prefered_lft * HZ; spin_unlock(&ifp->lock); } } write_unlock(&addrconf_hash_lock); } addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next; add_timer(&addr_chk_timer); spin_unlock_bh(&addrconf_verify_lock);}static intinet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){ struct rtattr **rta = arg; struct ifaddrmsg *ifm = NLMSG_DATA(nlh); struct in6_addr *pfx; pfx = NULL; if (rta[IFA_ADDRESS-1]) { if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx)) return -EINVAL; pfx = RTA_DATA(rta[IFA_ADDRESS-1]); } if (rta[IFA_LOCAL-1]) { if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))) return -EINVAL; pfx = RTA_DATA(rta[IFA_LOCAL-1]); } if (pfx == NULL) return -EINVAL; return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen);}static intinet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){ struct rtattr **rta = arg; struct ifaddrmsg *ifm = NLMSG_DATA(nlh); struct in6_addr *pfx; pfx = NULL; if (rta[IFA_ADDRESS-1]) { if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx)) return -EINVAL; pfx = RTA_DATA(rta[IFA_ADDRESS-1]); } if (rta[IFA_LOCAL-1]) { if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))) return -EINVAL; pfx = RTA_DATA(rta[IFA_LOCAL-1]); } if (pfx == NULL) return -EINVAL; return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen);}static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, u32 pid, u32 seq, int event){ struct ifaddrmsg *ifm; struct nlmsghdr *nlh; struct ifa_cacheinfo ci; unsigned char *b = skb->tail; nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm)); if (pid) nlh->nlmsg_flags |= NLM_F_MULTI; ifm = NLMSG_DATA(nlh); ifm->ifa_family = AF_INET6; ifm->ifa_prefixlen = ifa->prefix_len; ifm->ifa_flags = ifa->flags; ifm->ifa_scope = RT_SCOPE_UNIVERSE; if (ifa->scope&IFA_HOST) ifm->ifa_scope = RT_SCOPE_HOST; else if (ifa->scope&IFA_LINK) ifm->ifa_scope = RT_SCOPE_LINK; else if (ifa->scope&IFA_SITE) ifm->ifa_scope = RT_SCOPE_SITE; ifm->ifa_index = ifa->idev->dev->ifindex; RTA_PUT(skb, IFA_ADDRESS, 16, &ifa->addr); if (!(ifa->flags&IFA_F_PERMANENT)) { ci.ifa_prefered = ifa->prefered_lft; ci.ifa_valid = ifa->valid_lft; if (ci.ifa_prefered != INFINITY_LIFE_TIME) { long tval = (jiffies - ifa->tstamp)/HZ; ci.ifa_prefered -= tval; if (ci.ifa_valid != INFINITY_LIFE_TIME) ci.ifa_valid -= tval; } } else { ci.ifa_prefered = INFINITY_LIFE_TIME; ci.ifa_valid = INFINITY_LIFE_TIME; } ci.cstamp = (__u32)(TIME_DELTA(ifa->cstamp, INITIAL_JIFFIES) / HZ * 100 + TIME_DELTA(ifa->cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); ci.tstamp = (__u32)(TIME_DELTA(ifa->tstamp, INITIAL_JIFFIES) / HZ * 100 + TIME_DELTA(ifa->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci); nlh->nlmsg_len = skb->tail - b; return skb->len;nlmsg_failure:rtattr_failure: skb_trim(skb, b - skb->data); return -1;}static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, u32 pid, u32 seq, int event){ struct ifaddrmsg *ifm; struct nlmsghdr *nlh; struct ifa_cacheinfo ci; unsigned char *b = skb->tail; nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm)); if (pid) nlh->nlmsg_flags |= NLM_F_MULTI; ifm = NLMSG_DATA(nlh); ifm->ifa_family = AF_INET6; ifm->ifa_prefixlen = 128; ifm->ifa_flags = IFA_F_PERMANENT; ifm->ifa_scope = RT_SCOPE_UNIVERSE; if (ipv6_addr_scope(&ifmca->mca_addr)&IFA_SITE) ifm->ifa_scope = RT_SCOPE_SITE; ifm->ifa_index = ifmca->idev->dev->ifindex; RTA_PUT(skb, IFA_MULTICAST, 16, &ifmca->mca_addr); ci.cstamp = (__u32)(TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) / HZ * 100 + TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); ci.tstamp = (__u32)(TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) / HZ * 100 + TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); ci.ifa_prefered = INFINITY_LIFE_TIME; ci.ifa_valid = INFINITY_LIFE_TIME; RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci); nlh->nlmsg_len = skb->tail - b; return skb->len;nlmsg_failure:rtattr_failure: skb_trim(skb, b - skb->data); return -1;}static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, u32 pid, u32 seq, int event){ struct ifaddrmsg *ifm; struct nlmsghdr *nlh; struct ifa_cacheinfo ci; unsigned char *b = skb->tail; nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm)); if (pid) nlh->nlmsg_flags |= NLM_F_MULTI; ifm = NLMSG_DATA(nlh); ifm->ifa_family = AF_INET6; ifm->ifa_prefixlen = 128; ifm->ifa_flags = IFA_F_PERMANENT; ifm->ifa_scope = RT_SCOPE_UNIVERSE; if (ipv6_addr_scope(&ifaca->aca_addr)&IFA_SITE) ifm->ifa_scope = RT_SCOPE_SITE; ifm->ifa_index = ifaca->aca_idev->dev->ifindex; RTA_PUT(skb, IFA_ANYCAST, 16, &ifaca->aca_addr); ci.cstamp = (__u32)(TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) / HZ * 100 + TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); ci.tstamp = (__u32)(TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) / HZ * 100 + TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); ci.ifa_prefered = INFINITY_LIFE_TIME; ci.ifa_valid = INFINITY_LIFE_TIME; RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci); nlh->nlmsg_len = skb->tail - b; return skb->len;nlmsg_failure:rtattr_failure: skb_trim(skb, b - skb->data); return -1;}enum addr_type_t{ UNICAST_ADDR, MULTICAST_ADDR, ANYCAST_ADDR,};static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, enum addr_type_t type){ int idx, ip_idx; int s_idx, s_ip_idx; int err = 1; struct net_device *dev; struct inet6_dev *idev = NULL; struct inet6_ifaddr *ifa; struct ifmcaddr6 *ifmca; struct ifacaddr6 *ifaca; s_idx = cb->args[0]; s_ip_idx = ip_idx = cb->args[1]; read_lock(&dev_base_lock); for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) { if (idx < s_idx) continue; if (idx > s_idx) s_ip_idx = 0; ip_idx = 0; if ((idev = in6_dev_get(dev)) == NULL) continue; read_lock_bh(&idev->lock); switch (type) { case UNICAST_ADDR: /* unicast address */ for (ifa = idev->addr_list; ifa; ifa = ifa->if_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; if ((err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWADDR)) <= 0) goto done; } /* temp addr */#ifdef CONFIG_IPV6_PRIVACY for (ifa = idev->tempaddr_list; ifa; ifa = ifa->tmp_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; if ((err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWADDR)) <= 0) goto done; }#endif break; case MULTICAST_ADDR: /* multicast address */ for (ifmca = idev->mc_list; ifmca; ifmca = ifmca->next, ip_idx++) { if (ip_idx < s_ip_idx) continue; if ((err = inet6_fill_ifmcaddr(skb, ifmca, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_GETMULTICAST)) <= 0) goto done; } break; case ANYCAST_ADDR: /* anycast address */ for (ifaca = idev->ac_list; ifaca;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -