📄 addrconf.c
字号:
ifp->prefix_len, ifp->scope, ifp->flags, ifp->idev->dev->name); pos=begin+len; if(pos<offset) { len=0; begin=pos; } if(pos>offset+length) { read_unlock_bh(&addrconf_hash_lock); goto done; } } read_unlock_bh(&addrconf_hash_lock); }done: *start=buffer+(offset-begin); len-=(offset-begin); if(len>length) len=length; if(len<0) len=0; return len;}#endif /* CONFIG_PROC_FS *//* * Periodic address status verification */void addrconf_verify(unsigned long foo){ struct inet6_ifaddr *ifp; unsigned long now = jiffies; int i; 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; if (ifp->flags & IFA_F_PERMANENT) continue; age = (now - ifp->tstamp) / HZ; if (age > ifp->valid_lft) { in6_ifa_hold(ifp); write_unlock(&addrconf_hash_lock); ipv6_del_addr(ifp); goto restart; } else if (age > ifp->prefered_lft) { int deprecate = 0; spin_lock(&ifp->lock); if (!(ifp->flags&IFA_F_DEPRECATED)) { deprecate = 1; ifp->flags |= IFA_F_DEPRECATED; } 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; } } } write_unlock(&addrconf_hash_lock); } mod_timer(&addr_chk_timer, jiffies + ADDR_CHECK_FREQUENCY);}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)); 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 != 0xFFFFFFFF) { long tval = (jiffies - ifa->tstamp)/HZ; ci.ifa_prefered -= tval; if (ci.ifa_valid != 0xFFFFFFFF) ci.ifa_valid -= tval; } 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_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb){ int idx, ip_idx; int s_idx, s_ip_idx; struct inet6_ifaddr *ifa; s_idx = cb->args[0]; s_ip_idx = ip_idx = cb->args[1]; for (idx=0; idx < IN6_ADDR_HSIZE; idx++) { if (idx < s_idx) continue; if (idx > s_idx) s_ip_idx = 0; read_lock_bh(&addrconf_hash_lock); for (ifa=inet6_addr_lst[idx], ip_idx = 0; ifa; ifa = ifa->lst_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; if (inet6_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWADDR) <= 0) { read_unlock_bh(&addrconf_hash_lock); goto done; } } read_unlock_bh(&addrconf_hash_lock); }done: cb->args[0] = idx; cb->args[1] = ip_idx; return skb->len;}static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa){ struct sk_buff *skb; int size = NLMSG_SPACE(sizeof(struct ifaddrmsg)+128); skb = alloc_skb(size, GFP_ATOMIC); if (!skb) { netlink_set_err(rtnl, 0, RTMGRP_IPV6_IFADDR, ENOBUFS); return; } if (inet6_fill_ifaddr(skb, ifa, 0, 0, event) < 0) { kfree_skb(skb); netlink_set_err(rtnl, 0, RTMGRP_IPV6_IFADDR, EINVAL); return; } NETLINK_CB(skb).dst_groups = RTMGRP_IPV6_IFADDR; netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_IFADDR, GFP_ATOMIC);}static struct rtnetlink_link inet6_rtnetlink_table[RTM_MAX-RTM_BASE+1] ={ { NULL, NULL, }, { NULL, NULL, }, { NULL, NULL, }, { NULL, NULL, }, { inet6_rtm_newaddr, NULL, }, { inet6_rtm_deladdr, NULL, }, { NULL, inet6_dump_ifaddr, }, { NULL, NULL, }, { inet6_rtm_newroute, NULL, }, { inet6_rtm_delroute, NULL, }, { inet6_rtm_getroute, inet6_dump_fib, }, { NULL, NULL, },};static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp){ inet6_ifa_notify(event ? : RTM_NEWADDR, ifp); switch (event) { case RTM_NEWADDR: ip6_rt_addr_add(&ifp->addr, ifp->idev->dev); break; case RTM_DELADDR: addrconf_leave_solict(ifp->idev->dev, &ifp->addr); if (!ipv6_chk_addr(&ifp->addr, ifp->idev->dev)) ip6_rt_addr_del(&ifp->addr, ifp->idev->dev); break; }}#ifdef CONFIG_SYSCTLstaticint addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp){ int *valp = ctl->data; int val = *valp; int ret; ret = proc_dointvec(ctl, write, filp, buffer, lenp); if (write && *valp != val && valp != &ipv6_devconf_dflt.forwarding) { struct inet6_dev *idev = NULL; if (valp != &ipv6_devconf.forwarding) { struct net_device *dev = dev_get_by_index(ctl->ctl_name); if (dev) { idev = in6_dev_get(dev); dev_put(dev); } if (idev == NULL) return ret; } else ipv6_devconf_dflt.forwarding = ipv6_devconf.forwarding; addrconf_forward_change(idev); if (*valp) rt6_purge_dflt_routers(0); if (idev) in6_dev_put(idev); } return ret;}static struct addrconf_sysctl_table{ struct ctl_table_header *sysctl_header; ctl_table addrconf_vars[11]; ctl_table addrconf_dev[2]; ctl_table addrconf_conf_dir[2]; ctl_table addrconf_proto_dir[2]; ctl_table addrconf_root_dir[2];} addrconf_sysctl = { NULL, {{NET_IPV6_FORWARDING, "forwarding", &ipv6_devconf.forwarding, sizeof(int), 0644, NULL, &addrconf_sysctl_forward}, {NET_IPV6_HOP_LIMIT, "hop_limit", &ipv6_devconf.hop_limit, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV6_MTU, "mtu", &ipv6_devconf.mtu6, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV6_ACCEPT_RA, "accept_ra", &ipv6_devconf.accept_ra, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV6_ACCEPT_REDIRECTS, "accept_redirects", &ipv6_devconf.accept_redirects, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV6_AUTOCONF, "autoconf", &ipv6_devconf.autoconf, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV6_DAD_TRANSMITS, "dad_transmits", &ipv6_devconf.dad_transmits, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV6_RTR_SOLICITS, "router_solicitations", &ipv6_devconf.rtr_solicits, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV6_RTR_SOLICIT_INTERVAL, "router_solicitation_interval", &ipv6_devconf.rtr_solicit_interval, sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, {NET_IPV6_RTR_SOLICIT_DELAY, "router_solicitation_delay", &ipv6_devconf.rtr_solicit_delay, sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, {0}}, {{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, addrconf_sysctl.addrconf_vars},{0}}, {{NET_IPV6_CONF, "conf", NULL, 0, 0555, addrconf_sysctl.addrconf_dev},{0}}, {{NET_IPV6, "ipv6", NULL, 0, 0555, addrconf_sysctl.addrconf_conf_dir},{0}}, {{CTL_NET, "net", NULL, 0, 0555, addrconf_sysctl.addrconf_proto_dir},{0}}};static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf *p){ int i; struct net_device *dev = idev ? idev->dev : NULL; struct addrconf_sysctl_table *t; t = kmalloc(sizeof(*t), GFP_KERNEL); if (t == NULL) return; memcpy(t, &addrconf_sysctl, sizeof(*t)); for (i=0; i<sizeof(t->addrconf_vars)/sizeof(t->addrconf_vars[0])-1; i++) { t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf; t->addrconf_vars[i].de = NULL; } if (dev) { t->addrconf_dev[0].procname = dev->name; t->addrconf_dev[0].ctl_name = dev->ifindex; } else { t->addrconf_dev[0].procname = "default"; t->addrconf_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT; } t->addrconf_dev[0].child = t->addrconf_vars; t->addrconf_dev[0].de = NULL; t->addrconf_conf_dir[0].child = t->addrconf_dev; t->addrconf_conf_dir[0].de = NULL; t->addrconf_proto_dir[0].child = t->addrconf_conf_dir; t->addrconf_proto_dir[0].de = NULL; t->addrconf_root_dir[0].child = t->addrconf_proto_dir; t->addrconf_root_dir[0].de = NULL; t->sysctl_header = register_sysctl_table(t->addrconf_root_dir, 0); if (t->sysctl_header == NULL) kfree(t); else p->sysctl = t;}static void addrconf_sysctl_unregister(struct ipv6_devconf *p){ if (p->sysctl) { struct addrconf_sysctl_table *t = p->sysctl; p->sysctl = NULL; unregister_sysctl_table(t->sysctl_header); kfree(t); }}#endif/* * Device notifier */int register_inet6addr_notifier(struct notifier_block *nb){ return notifier_chain_register(&inet6addr_chain, nb);}int unregister_inet6addr_notifier(struct notifier_block *nb){ return notifier_chain_unregister(&inet6addr_chain,nb);}/* * Init / cleanup code */void __init addrconf_init(void){#ifdef MODULE struct net_device *dev; /* This takes sense only during module load. */ rtnl_lock(); for (dev = dev_base; dev; dev = dev->next) { if (!(dev->flags&IFF_UP)) continue; switch (dev->type) { case ARPHRD_LOOPBACK: init_loopback(dev); break; case ARPHRD_ETHER: case ARPHRD_FDDI: case ARPHRD_IEEE802_TR: addrconf_dev_config(dev); break; default:; /* Ignore all other */ } } rtnl_unlock();#endif#ifdef CONFIG_PROC_FS proc_net_create("if_inet6", 0, iface_proc_info);#endif addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY; add_timer(&addr_chk_timer); rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;#ifdef CONFIG_SYSCTL addrconf_sysctl.sysctl_header = register_sysctl_table(addrconf_sysctl.addrconf_root_dir, 0); addrconf_sysctl_register(NULL, &ipv6_devconf_dflt);#endif}#ifdef MODULEvoid addrconf_cleanup(void){ struct net_device *dev; struct inet6_dev *idev; struct inet6_ifaddr *ifa; int i; rtnetlink_links[PF_INET6] = NULL;#ifdef CONFIG_SYSCTL addrconf_sysctl_unregister(&ipv6_devconf_dflt); addrconf_sysctl_unregister(&ipv6_devconf);#endif rtnl_lock(); /* * clean dev list. */ for (dev=dev_base; dev; dev=dev->next) { if ((idev = __in6_dev_get(dev)) == NULL) continue; addrconf_ifdown(dev, 1); } /* * Check hash table. */ write_lock_bh(&addrconf_hash_lock); for (i=0; i < IN6_ADDR_HSIZE; i++) { for (ifa=inet6_addr_lst[i]; ifa; ) { struct inet6_ifaddr *bifa; bifa = ifa; ifa = ifa->lst_next; printk(KERN_DEBUG "bug: IPv6 address leakage detected: ifa=%p\n", bifa); /* Do not free it; something is wrong. Now we can investigate it with debugger. */ } } write_unlock_bh(&addrconf_hash_lock); del_timer(&addr_chk_timer); rtnl_unlock();#ifdef CONFIG_PROC_FS proc_net_remove("if_inet6");#endif}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -