⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 neighbour.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 + -