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

📄 neighbour.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
					       neigh->ha, NULL, skb->len);			read_unlock_bh(&neigh->lock);		}		if (err >= 0)			rc = neigh->ops->queue_xmit(skb);		else			goto out_kfree_skb;	}out:	return rc;discard:	NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",		      dst, dst ? dst->neighbour : NULL);out_kfree_skb:	rc = -EINVAL;	kfree_skb(skb);	goto out;}/* As fast as possible without hh cache */int neigh_connected_output(struct sk_buff *skb){	int err;	struct dst_entry *dst = skb->dst;	struct neighbour *neigh = dst->neighbour;	struct net_device *dev = neigh->dev;	__skb_pull(skb, skb->nh.raw - skb->data);	read_lock_bh(&neigh->lock);	err = dev->hard_header(skb, dev, ntohs(skb->protocol),			       neigh->ha, NULL, skb->len);	read_unlock_bh(&neigh->lock);	if (err >= 0)		err = neigh->ops->queue_xmit(skb);	else {		err = -EINVAL;		kfree_skb(skb);	}	return err;}static void neigh_proxy_process(unsigned long arg){	struct neigh_table *tbl = (struct neigh_table *)arg;	long sched_next = 0;	unsigned long now = jiffies;	struct sk_buff *skb;	spin_lock(&tbl->proxy_queue.lock);	skb = tbl->proxy_queue.next;	while (skb != (struct sk_buff *)&tbl->proxy_queue) {		struct sk_buff *back = skb;		long tdif = back->stamp.tv_usec - now;		skb = skb->next;		if (tdif <= 0) {			struct net_device *dev = back->dev;			__skb_unlink(back, &tbl->proxy_queue);			if (tbl->proxy_redo && netif_running(dev))				tbl->proxy_redo(back);			else				kfree_skb(back);			dev_put(dev);		} else if (!sched_next || tdif < sched_next)			sched_next = tdif;	}	del_timer(&tbl->proxy_timer);	if (sched_next)		mod_timer(&tbl->proxy_timer, jiffies + sched_next);	spin_unlock(&tbl->proxy_queue.lock);}void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,		    struct sk_buff *skb){	unsigned long now = jiffies;	unsigned long sched_next = now + (net_random() % p->proxy_delay);	if (tbl->proxy_queue.qlen > p->proxy_qlen) {		kfree_skb(skb);		return;	}	skb->stamp.tv_sec  = LOCALLY_ENQUEUED;	skb->stamp.tv_usec = sched_next;	spin_lock(&tbl->proxy_queue.lock);	if (del_timer(&tbl->proxy_timer)) {		if (time_before(tbl->proxy_timer.expires, sched_next))			sched_next = tbl->proxy_timer.expires;	}	dst_release(skb->dst);	skb->dst = NULL;	dev_hold(skb->dev);	__skb_queue_tail(&tbl->proxy_queue, skb);	mod_timer(&tbl->proxy_timer, 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 = kmalloc(sizeof(*p), GFP_KERNEL);	if (p) {		memcpy(p, &tbl->parms, sizeof(*p));		p->tbl		  = tbl;		atomic_set(&p->refcnt, 1);		INIT_RCU_HEAD(&p->rcu_head);		p->reachable_time =				neigh_rand_reach_time(p->base_reachable_time);		if (dev && dev->neigh_setup && dev->neigh_setup(dev, p)) {			kfree(p);			return NULL;		}		p->sysctl_table = NULL;		write_lock_bh(&tbl->lock);		p->next		= tbl->parms.next;		tbl->parms.next = p;		write_unlock_bh(&tbl->lock);	}	return p;}static void neigh_rcu_free_parms(struct rcu_head *head){	struct neigh_parms *parms =		container_of(head, struct neigh_parms, rcu_head);	neigh_parms_put(parms);}void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms){	struct neigh_parms **p;	if (!parms || parms == &tbl->parms)		return;	write_lock_bh(&tbl->lock);	for (p = &tbl->parms.next; *p; p = &(*p)->next) {		if (*p == parms) {			*p = parms->next;			parms->dead = 1;			write_unlock_bh(&tbl->lock);			call_rcu(&parms->rcu_head, neigh_rcu_free_parms);			return;		}	}	write_unlock_bh(&tbl->lock);	NEIGH_PRINTK1("neigh_parms_release: not found\n");}void neigh_parms_destroy(struct neigh_parms *parms){	kfree(parms);}void neigh_table_init(struct neigh_table *tbl){	unsigned long now = jiffies;	unsigned long phsize;	atomic_set(&tbl->parms.refcnt, 1);	INIT_RCU_HEAD(&tbl->parms.rcu_head);	tbl->parms.reachable_time =			  neigh_rand_reach_time(tbl->parms.base_reachable_time);	if (!tbl->kmem_cachep)		tbl->kmem_cachep = kmem_cache_create(tbl->id,						     tbl->entry_size,						     0, SLAB_HWCACHE_ALIGN,						     NULL, NULL);	if (!tbl->kmem_cachep)		panic("cannot create neighbour cache");	tbl->stats = alloc_percpu(struct neigh_statistics);	if (!tbl->stats)		panic("cannot create neighbour cache statistics");	#ifdef CONFIG_PROC_FS	tbl->pde = create_proc_entry(tbl->id, 0, proc_net_stat);	if (!tbl->pde) 		panic("cannot create neighbour proc dir entry");	tbl->pde->proc_fops = &neigh_stat_seq_fops;	tbl->pde->data = tbl;#endif	tbl->hash_mask = 1;	tbl->hash_buckets = neigh_hash_alloc(tbl->hash_mask + 1);	phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);	tbl->phash_buckets = kmalloc(phsize, GFP_KERNEL);	if (!tbl->hash_buckets || !tbl->phash_buckets)		panic("cannot allocate neighbour cache hashes");	memset(tbl->phash_buckets, 0, phsize);	get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd));	tbl->lock	       = RW_LOCK_UNLOCKED;	init_timer(&tbl->gc_timer);	tbl->gc_timer.data     = (unsigned long)tbl;	tbl->gc_timer.function = neigh_periodic_timer;	tbl->gc_timer.expires  = now + 1;	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);	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);	neigh_hash_free(tbl->hash_buckets, tbl->hash_mask + 1);	tbl->hash_buckets = NULL;	kfree(tbl->phash_buckets);	tbl->phash_buckets = NULL;	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 = -ENODEV;	if (ndm->ndm_ifindex &&	    (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL)		goto out;	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] ||		    nda[NDA_DST - 1]->rta_len != RTA_LENGTH(tbl->key_len))			goto out_dev_put;		if (ndm->ndm_flags & NTF_PROXY) {			err = pneigh_delete(tbl,					    RTA_DATA(nda[NDA_DST - 1]), dev);			goto out_dev_put;		}		if (!dev)			goto out;		n = neigh_lookup(tbl, RTA_DATA(nda[NDA_DST - 1]), dev);		if (n) {			err = neigh_update(n, NULL, NUD_FAILED, 					   NEIGH_UPDATE_F_OVERRIDE|					   NEIGH_UPDATE_F_ADMIN);			neigh_release(n);		}		goto out_dev_put;	}	read_unlock(&neigh_tbl_lock);	err = -EADDRNOTAVAIL;out_dev_put:	if (dev)		dev_put(dev);out:	return err;}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;	int err = -ENODEV;	if (ndm->ndm_ifindex &&	    (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL)		goto out;	read_lock(&neigh_tbl_lock);	for (tbl = neigh_tables; tbl; tbl = tbl->next) {		int override = 1;		struct neighbour *n;		if (tbl->family != ndm->ndm_family)			continue;		read_unlock(&neigh_tbl_lock);		err = -EINVAL;		if (!nda[NDA_DST - 1] ||		    nda[NDA_DST - 1]->rta_len != RTA_LENGTH(tbl->key_len))			goto out_dev_put;		if (ndm->ndm_flags & NTF_PROXY) {			err = -ENOBUFS;			if (pneigh_lookup(tbl,					  RTA_DATA(nda[NDA_DST - 1]), dev, 1))				err = 0;			goto out_dev_put;		}		err = -EINVAL;		if (!dev)			goto out;		if (nda[NDA_LLADDR - 1] &&		    nda[NDA_LLADDR - 1]->rta_len != RTA_LENGTH(dev->addr_len))			goto out_dev_put;		err = 0;		n = neigh_lookup(tbl, RTA_DATA(nda[NDA_DST - 1]), dev);		if (n) {			if (nlh->nlmsg_flags & NLM_F_EXCL)				err = -EEXIST;			override = nlh->nlmsg_flags & NLM_F_REPLACE;		} 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) {			err = neigh_update(n, nda[NDA_LLADDR - 1] ?						RTA_DATA(nda[NDA_LLADDR - 1]) :						NULL,					   ndm->ndm_state,					   (override ? NEIGH_UPDATE_F_OVERRIDE : 0) |					   NEIGH_UPDATE_F_ADMIN);		}		if (n)			neigh_release(n);		goto out_dev_put;	}	read_unlock(&neigh_tbl_lock);	err = -EADDRNOTAVAIL;out_dev_put:	if (dev)		dev_put(dev);out:	return err;}static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n,			   u32 pid, u32 seq, int event){	unsigned long now = jiffies;	unsigned char *b = skb->tail;	struct nda_cacheinfo ci;	int locked = 0;	struct nlmsghdr *nlh = NLMSG_PUT(skb, pid, seq, event,					 sizeof(struct ndmsg));	struct ndmsg *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 rc, h, s_h = cb->args[1];	int idx, s_idx = idx = cb->args[2];	for (h = 0; h <= tbl->hash_mask; 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);				rc = -1;				goto out;			}		}		read_unlock_bh(&tbl->lock);	}	rc = skb->len;out:	cb->args[1] = h;	cb->args[2] = idx;	return rc;}int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb){	struct neigh_table *tbl;	int t, family, s_t;	read_lock(&neigh_tbl_lock);	family = ((struct rtgenmsg *)NLMSG_DATA(cb->nlh))->rtgen_family;	s_t = cb->args[0];	for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) {		if (t < s_t || (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;}void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie){	int chain;	read_lock_bh(&tbl->lock);	for (chain = 0; chain <= tbl->hash_mask; chain++) {		struct neighbour *n;		for (n = tbl->hash_buckets[chain]; n; n = n->next)			cb(n, cookie);	}	read_unlock_bh(&tbl->lock);}EXPORT_SYMBOL(neigh_for_each);/* The tbl->lock must be held as a writer and BH disabled. */void __neigh_for_each_release(struct neigh_table *tbl,			      int (*cb)(struct neighbour *)){	int chain;	for (chain = 0; chain <= tbl->hash_mask; chain++) {		struct neighbour *n, **np;		np = &tbl->hash_buckets[chain];		while ((n = *np) != NULL) {			int release;			write_lock(&n->lock);			release = cb(n);			if (release) {				*np = n->next;				n->dead = 1;			} else				np = &n->next;			write_unlock(&n->lock);			if (release)				neigh_release(n);		}	}}EXPORT_SYMBOL(__neigh_for_each_release);#ifdef CONFIG_PROC_FSstatic struct neighbour *neigh_get_first(struct seq_file *seq){	struct neigh_seq_state *state = seq->private;	struct neigh_table *tbl = state->tbl;	struct neighbour *n = NULL;	int bucket = state->bucket;	state->flags &= ~NEIGH_SEQ_IS_PNEIGH;	for (bucket = 0; bucket <= tbl->hash_mask; bucket++) {		n = tbl->hash_buckets[bucket];		while (n) {			if (state->neigh_sub_iter) {				loff_t fakep = 0;				void *v;				v = state->neigh_sub_iter(state, n, &fakep);				if (!v)					goto next;			}			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))				break;			if (n->nud_state & ~NUD_NOARP)				break;		next:			n = n->next;		}		if (n)			break;	}	state->bucket = bucket;	return n;}static struct neighbour *neigh_get_next(struct seq_file *seq,					struct neighbour *n,					loff_t *pos){	struct neigh_seq_state *state = seq->private;	struct neigh_table *tbl = state->tbl;	if (state->neigh_sub_iter) {		void *v = state->neigh_sub_iter(state, n, pos);		if (v)			return n;	}	n = n->next;	while (1) {		while (n) {			if (state->neigh_sub_iter) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -