📄 neighbour.c
字号:
if (tbl->proxy_queue.qlen > p->proxy_qlen) { kfree_skb(skb); return; } skb->stamp.tv_sec = 0; skb->stamp.tv_usec = now + sched_next; spin_lock(&tbl->proxy_queue.lock); if (del_timer(&tbl->proxy_timer)) { long tval = tbl->proxy_timer.expires - now; if (tval < sched_next) sched_next = tval; } dst_release(skb->dst); skb->dst = NULL; dev_hold(skb->dev); __skb_queue_tail(&tbl->proxy_queue, skb); mod_timer(&tbl->proxy_timer, now + sched_next); spin_unlock(&tbl->proxy_queue.lock);}struct neigh_parms *neigh_parms_alloc(struct net_device *dev, struct neigh_table *tbl){ struct neigh_parms *p; p = kmalloc(sizeof(*p), GFP_KERNEL); if (p) { memcpy(p, &tbl->parms, sizeof(*p)); p->tbl = tbl; p->reachable_time = neigh_rand_reach_time(p->base_reachable_time); if (dev && dev->neigh_setup) { if (dev->neigh_setup(dev, p)) { kfree(p); return NULL; } } write_lock_bh(&tbl->lock); p->next = tbl->parms.next; tbl->parms.next = p; write_unlock_bh(&tbl->lock); } return p;}void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms){ struct neigh_parms **p; if (parms == NULL || parms == &tbl->parms) return; write_lock_bh(&tbl->lock); for (p = &tbl->parms.next; *p; p = &(*p)->next) { if (*p == parms) { *p = parms->next; write_unlock_bh(&tbl->lock);#ifdef CONFIG_SYSCTL neigh_sysctl_unregister(parms);#endif kfree(parms); return; } } write_unlock_bh(&tbl->lock); NEIGH_PRINTK1("neigh_parms_release: not found\n");}void neigh_table_init(struct neigh_table *tbl){ unsigned long now = jiffies; tbl->parms.reachable_time = neigh_rand_reach_time(tbl->parms.base_reachable_time); if (tbl->kmem_cachep == NULL) tbl->kmem_cachep = kmem_cache_create(tbl->id, (tbl->entry_size+15)&~15, 0, SLAB_HWCACHE_ALIGN, NULL, NULL);#ifdef CONFIG_SMP tasklet_init(&tbl->gc_task, SMP_TIMER_NAME(neigh_periodic_timer), (unsigned long)tbl);#endif init_timer(&tbl->gc_timer); tbl->lock = RW_LOCK_UNLOCKED; tbl->gc_timer.data = (unsigned long)tbl; tbl->gc_timer.function = neigh_periodic_timer; tbl->gc_timer.expires = now + tbl->gc_interval + tbl->parms.reachable_time; add_timer(&tbl->gc_timer); init_timer(&tbl->proxy_timer); tbl->proxy_timer.data = (unsigned long)tbl; tbl->proxy_timer.function = neigh_proxy_process; skb_queue_head_init(&tbl->proxy_queue); tbl->last_flush = now; tbl->last_rand = now + tbl->parms.reachable_time*20; write_lock(&neigh_tbl_lock); tbl->next = neigh_tables; neigh_tables = tbl; write_unlock(&neigh_tbl_lock);}int neigh_table_clear(struct neigh_table *tbl){ struct neigh_table **tp; /* It is not clean... Fix it to unload IPv6 module safely */ del_timer_sync(&tbl->gc_timer); tasklet_kill(&tbl->gc_task); del_timer_sync(&tbl->proxy_timer); pneigh_queue_purge(&tbl->proxy_queue); neigh_ifdown(tbl, NULL); if (tbl->entries) printk(KERN_CRIT "neighbour leakage\n"); write_lock(&neigh_tbl_lock); for (tp = &neigh_tables; *tp; tp = &(*tp)->next) { if (*tp == tbl) { *tp = tbl->next; break; } } write_unlock(&neigh_tbl_lock);#ifdef CONFIG_SYSCTL neigh_sysctl_unregister(&tbl->parms);#endif return 0;}int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){ struct ndmsg *ndm = NLMSG_DATA(nlh); struct rtattr **nda = arg; struct neigh_table *tbl; struct net_device *dev = NULL; int err = 0; if (ndm->ndm_ifindex) { if ((dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL) return -ENODEV; } read_lock(&neigh_tbl_lock); for (tbl=neigh_tables; tbl; tbl = tbl->next) { struct neighbour *n; if (tbl->family != ndm->ndm_family) continue; read_unlock(&neigh_tbl_lock); err = -EINVAL; if (nda[NDA_DST-1] == NULL || nda[NDA_DST-1]->rta_len != RTA_LENGTH(tbl->key_len)) goto out; if (ndm->ndm_flags&NTF_PROXY) { err = pneigh_delete(tbl, RTA_DATA(nda[NDA_DST-1]), dev); goto out; } if (dev == NULL) return -EINVAL; n = neigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev); if (n) { err = neigh_update(n, NULL, NUD_FAILED, 1, 0); neigh_release(n); }out: if (dev) dev_put(dev); return err; } read_unlock(&neigh_tbl_lock); if (dev) dev_put(dev); return -EADDRNOTAVAIL;}int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){ struct ndmsg *ndm = NLMSG_DATA(nlh); struct rtattr **nda = arg; struct neigh_table *tbl; struct net_device *dev = NULL; if (ndm->ndm_ifindex) { if ((dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL) return -ENODEV; } read_lock(&neigh_tbl_lock); for (tbl=neigh_tables; tbl; tbl = tbl->next) { int err = 0; struct neighbour *n; if (tbl->family != ndm->ndm_family) continue; read_unlock(&neigh_tbl_lock); err = -EINVAL; if (nda[NDA_DST-1] == NULL || nda[NDA_DST-1]->rta_len != RTA_LENGTH(tbl->key_len)) goto out; if (ndm->ndm_flags&NTF_PROXY) { err = -ENOBUFS; if (pneigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev, 1)) err = 0; goto out; } if (dev == NULL) return -EINVAL; err = -EINVAL; if (nda[NDA_LLADDR-1] != NULL && nda[NDA_LLADDR-1]->rta_len != RTA_LENGTH(dev->addr_len)) goto out; err = 0; n = neigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev); if (n) { if (nlh->nlmsg_flags&NLM_F_EXCL) err = -EEXIST; } else if (!(nlh->nlmsg_flags&NLM_F_CREATE)) err = -ENOENT; else { n = __neigh_lookup_errno(tbl, RTA_DATA(nda[NDA_DST-1]), dev); if (IS_ERR(n)) { err = PTR_ERR(n); n = NULL; } } if (err == 0) { err = neigh_update(n, nda[NDA_LLADDR-1] ? RTA_DATA(nda[NDA_LLADDR-1]) : NULL, ndm->ndm_state, nlh->nlmsg_flags&NLM_F_REPLACE, 0); } if (n) neigh_release(n);out: if (dev) dev_put(dev); return err; } read_unlock(&neigh_tbl_lock); if (dev) dev_put(dev); return -EADDRNOTAVAIL;}static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n, u32 pid, u32 seq, int event){ unsigned long now = jiffies; struct ndmsg *ndm; struct nlmsghdr *nlh; unsigned char *b = skb->tail; struct nda_cacheinfo ci; int locked = 0; nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ndm)); ndm = NLMSG_DATA(nlh); ndm->ndm_family = n->ops->family; ndm->ndm_flags = n->flags; ndm->ndm_type = n->type; ndm->ndm_ifindex = n->dev->ifindex; RTA_PUT(skb, NDA_DST, n->tbl->key_len, n->primary_key); read_lock_bh(&n->lock); locked=1; ndm->ndm_state = n->nud_state; if (n->nud_state&NUD_VALID) RTA_PUT(skb, NDA_LLADDR, n->dev->addr_len, n->ha); ci.ndm_used = now - n->used; ci.ndm_confirmed = now - n->confirmed; ci.ndm_updated = now - n->updated; ci.ndm_refcnt = atomic_read(&n->refcnt) - 1; read_unlock_bh(&n->lock); locked=0; RTA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci); nlh->nlmsg_len = skb->tail - b; return skb->len;nlmsg_failure:rtattr_failure: if (locked) read_unlock_bh(&n->lock); skb_trim(skb, b - skb->data); return -1;}static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, struct netlink_callback *cb){ struct neighbour *n; int h, s_h; int idx, s_idx; s_h = cb->args[1]; s_idx = idx = cb->args[2]; for (h=0; h <= NEIGH_HASHMASK; h++) { if (h < s_h) continue; if (h > s_h) s_idx = 0; read_lock_bh(&tbl->lock); for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next, idx++) { if (idx < s_idx) continue; if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWNEIGH) <= 0) { read_unlock_bh(&tbl->lock); cb->args[1] = h; cb->args[2] = idx; return -1; } } read_unlock_bh(&tbl->lock); } cb->args[1] = h; cb->args[2] = idx; return skb->len;}int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb){ int t; int s_t; struct neigh_table *tbl; int family = ((struct rtgenmsg*)NLMSG_DATA(cb->nlh))->rtgen_family; s_t = cb->args[0]; read_lock(&neigh_tbl_lock); for (tbl=neigh_tables, t=0; tbl; tbl = tbl->next, t++) { if (t < s_t) continue; if (family && tbl->family != family) continue; if (t > s_t) memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); if (neigh_dump_table(tbl, skb, cb) < 0) break; } read_unlock(&neigh_tbl_lock); cb->args[0] = t; return skb->len;}#ifdef CONFIG_ARPDvoid neigh_app_ns(struct neighbour *n){ struct sk_buff *skb; struct nlmsghdr *nlh; int size = NLMSG_SPACE(sizeof(struct ndmsg)+256); skb = alloc_skb(size, GFP_ATOMIC); if (!skb) return; if (neigh_fill_info(skb, n, 0, 0, RTM_GETNEIGH) < 0) { kfree_skb(skb); return; } nlh = (struct nlmsghdr*)skb->data; nlh->nlmsg_flags = NLM_F_REQUEST; NETLINK_CB(skb).dst_groups = RTMGRP_NEIGH; netlink_broadcast(rtnl, skb, 0, RTMGRP_NEIGH, GFP_ATOMIC);}static void neigh_app_notify(struct neighbour *n){ struct sk_buff *skb; struct nlmsghdr *nlh; int size = NLMSG_SPACE(sizeof(struct ndmsg)+256); skb = alloc_skb(size, GFP_ATOMIC); if (!skb) return; if (neigh_fill_info(skb, n, 0, 0, RTM_NEWNEIGH) < 0) { kfree_skb(skb); return; } nlh = (struct nlmsghdr*)skb->data; NETLINK_CB(skb).dst_groups = RTMGRP_NEIGH; netlink_broadcast(rtnl, skb, 0, RTMGRP_NEIGH, GFP_ATOMIC);}#endif /* CONFIG_ARPD */#ifdef CONFIG_SYSCTLstruct neigh_sysctl_table{ struct ctl_table_header *sysctl_header; ctl_table neigh_vars[17]; ctl_table neigh_dev[2]; ctl_table neigh_neigh_dir[2]; ctl_table neigh_proto_dir[2]; ctl_table neigh_root_dir[2];} neigh_sysctl_template = { NULL, {{NET_NEIGH_MCAST_SOLICIT, "mcast_solicit", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_NEIGH_UCAST_SOLICIT, "ucast_solicit", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_NEIGH_APP_SOLICIT, "app_solicit", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_NEIGH_RETRANS_TIME, "retrans_time", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_NEIGH_REACHABLE_TIME, "base_reachable_time", NULL, sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, {NET_NEIGH_DELAY_PROBE_TIME, "delay_first_probe_time", NULL, sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, {NET_NEIGH_GC_STALE_TIME, "gc_stale_time", NULL, sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, {NET_NEIGH_UNRES_QLEN, "unres_qlen", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_NEIGH_PROXY_QLEN, "proxy_qlen", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_NEIGH_ANYCAST_DELAY, "anycast_delay", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_NEIGH_PROXY_DELAY, "proxy_delay", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_NEIGH_LOCKTIME, "locktime", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_NEIGH_GC_INTERVAL, "gc_interval", NULL, sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, {NET_NEIGH_GC_THRESH1, "gc_thresh1", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_NEIGH_GC_THRESH2, "gc_thresh2", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_NEIGH_GC_THRESH3, "gc_thresh3", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {0}}, {{NET_PROTO_CONF_DEFAULT, "default", NULL, 0, 0555, NULL},{0}}, {{0, "neigh", NULL, 0, 0555, NULL},{0}}, {{0, NULL, NULL, 0, 0555, NULL},{0}}, {{CTL_NET, "net", NULL, 0, 0555, NULL},{0}}};int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, int p_id, int pdev_id, char *p_name){ struct neigh_sysctl_table *t; t = kmalloc(sizeof(*t), GFP_KERNEL); if (t == NULL) return -ENOBUFS; memcpy(t, &neigh_sysctl_template, sizeof(*t)); t->neigh_vars[0].data = &p->mcast_probes; t->neigh_vars[1].data = &p->ucast_probes; t->neigh_vars[2].data = &p->app_probes; t->neigh_vars[3].data = &p->retrans_time; t->neigh_vars[4].data = &p->base_reachable_time; t->neigh_vars[5].data = &p->delay_probe_time; t->neigh_vars[6].data = &p->gc_staletime; t->neigh_vars[7].data = &p->queue_len; t->neigh_vars[8].data = &p->proxy_qlen; t->neigh_vars[9].data = &p->anycast_delay; t->neigh_vars[10].data = &p->proxy_delay; t->neigh_vars[11].data = &p->locktime; if (dev) { t->neigh_dev[0].procname = dev->name; t->neigh_dev[0].ctl_name = dev->ifindex; memset(&t->neigh_vars[12], 0, sizeof(ctl_table)); } else { t->neigh_vars[12].data = (int*)(p+1); t->neigh_vars[13].data = (int*)(p+1) + 1; t->neigh_vars[14].data = (int*)(p+1) + 2; t->neigh_vars[15].data = (int*)(p+1) + 3; } t->neigh_neigh_dir[0].ctl_name = pdev_id; t->neigh_proto_dir[0].procname = p_name; t->neigh_proto_dir[0].ctl_name = p_id; t->neigh_dev[0].child = t->neigh_vars; t->neigh_neigh_dir[0].child = t->neigh_dev; t->neigh_proto_dir[0].child = t->neigh_neigh_dir; t->neigh_root_dir[0].child = t->neigh_proto_dir; t->sysctl_header = register_sysctl_table(t->neigh_root_dir, 0); if (t->sysctl_header == NULL) { kfree(t); return -ENOBUFS; } p->sysctl_table = t; return 0;}void neigh_sysctl_unregister(struct neigh_parms *p){ if (p->sysctl_table) { struct neigh_sysctl_table *t = p->sysctl_table; p->sysctl_table = NULL; unregister_sysctl_table(t->sysctl_header); kfree(t); }}#endif /* CONFIG_SYSCTL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -