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

📄 nr_route.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
}/* *	A device has been removed. Remove its routes and neighbours. */void nr_rt_device_down(struct net_device *dev){	struct nr_neigh *s;	struct hlist_node *node, *nodet, *node2, *node2t;	struct nr_node  *t;	int i;	spin_lock_bh(&nr_neigh_list_lock);	nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) {		if (s->dev == dev) {			spin_lock_bh(&nr_node_list_lock);			nr_node_for_each_safe(t, node2, node2t, &nr_node_list) {				nr_node_lock(t);				for (i = 0; i < t->count; i++) {					if (t->routes[i].neighbour == s) {						t->count--;						switch (i) {						case 0:							t->routes[0] = t->routes[1];						case 1:							t->routes[1] = t->routes[2];						case 2:							break;						}					}				}				if (t->count <= 0)					nr_remove_node_locked(t);				nr_node_unlock(t);			}			spin_unlock_bh(&nr_node_list_lock);			nr_remove_neigh_locked(s);		}	}	spin_unlock_bh(&nr_neigh_list_lock);}/* *	Check that the device given is a valid AX.25 interface that is "up". *	Or a valid ethernet interface with an AX.25 callsign binding. */static struct net_device *nr_ax25_dev_get(char *devname){	struct net_device *dev;	if ((dev = dev_get_by_name(&init_net, devname)) == NULL)		return NULL;	if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)		return dev;	dev_put(dev);	return NULL;}/* *	Find the first active NET/ROM device, usually "nr0". */struct net_device *nr_dev_first(void){	struct net_device *dev, *first = NULL;	read_lock(&dev_base_lock);	for_each_netdev(&init_net, dev) {		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)			if (first == NULL || strncmp(dev->name, first->name, 3) < 0)				first = dev;	}	if (first)		dev_hold(first);	read_unlock(&dev_base_lock);	return first;}/* *	Find the NET/ROM device for the given callsign. */struct net_device *nr_dev_get(ax25_address *addr){	struct net_device *dev;	read_lock(&dev_base_lock);	for_each_netdev(&init_net, dev) {		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) {			dev_hold(dev);			goto out;		}	}	dev = NULL;out:	read_unlock(&dev_base_lock);	return dev;}static ax25_digi *nr_call_to_digi(int ndigis, ax25_address *digipeaters){	static ax25_digi ax25_digi;	int i;	if (ndigis == 0)		return NULL;	for (i = 0; i < ndigis; i++) {		ax25_digi.calls[i]    = digipeaters[i];		ax25_digi.repeated[i] = 0;	}	ax25_digi.ndigi      = ndigis;	ax25_digi.lastrepeat = -1;	return &ax25_digi;}/* *	Handle the ioctls that control the routing functions. */int nr_rt_ioctl(unsigned int cmd, void __user *arg){	struct nr_route_struct nr_route;	struct net_device *dev;	int ret;	switch (cmd) {	case SIOCADDRT:		if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))			return -EFAULT;		if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)			return -EINVAL;		if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) {			dev_put(dev);			return -EINVAL;		}		switch (nr_route.type) {		case NETROM_NODE:			ret = nr_add_node(&nr_route.callsign,				nr_route.mnemonic,				&nr_route.neighbour,				nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),				dev, nr_route.quality,				nr_route.obs_count);			break;		case NETROM_NEIGH:			ret = nr_add_neigh(&nr_route.callsign,				nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),				dev, nr_route.quality);			break;		default:			ret = -EINVAL;		}		dev_put(dev);		return ret;	case SIOCDELRT:		if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))			return -EFAULT;		if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)			return -EINVAL;		switch (nr_route.type) {		case NETROM_NODE:			ret = nr_del_node(&nr_route.callsign,				&nr_route.neighbour, dev);			break;		case NETROM_NEIGH:			ret = nr_del_neigh(&nr_route.callsign,				dev, nr_route.quality);			break;		default:			ret = -EINVAL;		}		dev_put(dev);		return ret;	case SIOCNRDECOBS:		return nr_dec_obs();	default:		return -EINVAL;	}	return 0;}/* * 	A level 2 link has timed out, therefore it appears to be a poor link, *	then don't use that neighbour until it is reset. */void nr_link_failed(ax25_cb *ax25, int reason){	struct nr_neigh *s, *nr_neigh = NULL;	struct hlist_node *node;	struct nr_node  *nr_node = NULL;	spin_lock_bh(&nr_neigh_list_lock);	nr_neigh_for_each(s, node, &nr_neigh_list) {		if (s->ax25 == ax25) {			nr_neigh_hold(s);			nr_neigh = s;			break;		}	}	spin_unlock_bh(&nr_neigh_list_lock);	if (nr_neigh == NULL)		return;	nr_neigh->ax25 = NULL;	ax25_cb_put(ax25);	if (++nr_neigh->failed < sysctl_netrom_link_fails_count) {		nr_neigh_put(nr_neigh);		return;	}	spin_lock_bh(&nr_node_list_lock);	nr_node_for_each(nr_node, node, &nr_node_list) {		nr_node_lock(nr_node);		if (nr_node->which < nr_node->count &&		    nr_node->routes[nr_node->which].neighbour == nr_neigh)			nr_node->which++;		nr_node_unlock(nr_node);	}	spin_unlock_bh(&nr_node_list_lock);	nr_neigh_put(nr_neigh);}/* *	Route a frame to an appropriate AX.25 connection. A NULL ax25_cb *	indicates an internally generated frame. */int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25){	ax25_address *nr_src, *nr_dest;	struct nr_neigh *nr_neigh;	struct nr_node  *nr_node;	struct net_device *dev;	unsigned char *dptr;	ax25_cb *ax25s;	int ret;	struct sk_buff *skbn;	nr_src  = (ax25_address *)(skb->data + 0);	nr_dest = (ax25_address *)(skb->data + 7);	if (ax25 != NULL) {		ret = nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,				  ax25->ax25_dev->dev, 0,				  sysctl_netrom_obsolescence_count_initialiser);		if (ret)			return ret;	}	if ((dev = nr_dev_get(nr_dest)) != NULL) {	/* Its for me */		if (ax25 == NULL)			/* Its from me */			ret = nr_loopback_queue(skb);		else			ret = nr_rx_frame(skb, dev);		dev_put(dev);		return ret;	}	if (!sysctl_netrom_routing_control && ax25 != NULL)		return 0;	/* Its Time-To-Live has expired */	if (skb->data[14] == 1) {		return 0;	}	nr_node = nr_node_get(nr_dest);	if (nr_node == NULL)		return 0;	nr_node_lock(nr_node);	if (nr_node->which >= nr_node->count) {		nr_node_unlock(nr_node);		nr_node_put(nr_node);		return 0;	}	nr_neigh = nr_node->routes[nr_node->which].neighbour;	if ((dev = nr_dev_first()) == NULL) {		nr_node_unlock(nr_node);		nr_node_put(nr_node);		return 0;	}	/* We are going to change the netrom headers so we should get our	   own skb, we also did not know until now how much header space	   we had to reserve... - RXQ */	if ((skbn=skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC)) == NULL) {		nr_node_unlock(nr_node);		nr_node_put(nr_node);		dev_put(dev);		return 0;	}	kfree_skb(skb);	skb=skbn;	skb->data[14]--;	dptr  = skb_push(skb, 1);	*dptr = AX25_P_NETROM;	ax25s = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);	if (nr_neigh->ax25 && ax25s) {		/* We were already holding this ax25_cb */		ax25_cb_put(ax25s);	}	nr_neigh->ax25 = ax25s;	dev_put(dev);	ret = (nr_neigh->ax25 != NULL);	nr_node_unlock(nr_node);	nr_node_put(nr_node);	return ret;}#ifdef CONFIG_PROC_FSstatic void *nr_node_start(struct seq_file *seq, loff_t *pos){	struct nr_node *nr_node;	struct hlist_node *node;	int i = 1;	spin_lock_bh(&nr_node_list_lock);	if (*pos == 0)		return SEQ_START_TOKEN;	nr_node_for_each(nr_node, node, &nr_node_list) {		if (i == *pos)			return nr_node;		++i;	}	return NULL;}static void *nr_node_next(struct seq_file *seq, void *v, loff_t *pos){	struct hlist_node *node;	++*pos;	node = (v == SEQ_START_TOKEN)		? nr_node_list.first		: ((struct nr_node *)v)->node_node.next;	return hlist_entry(node, struct nr_node, node_node);}static void nr_node_stop(struct seq_file *seq, void *v){	spin_unlock_bh(&nr_node_list_lock);}static int nr_node_show(struct seq_file *seq, void *v){	char buf[11];	int i;	if (v == SEQ_START_TOKEN)		seq_puts(seq,			 "callsign  mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");	else {		struct nr_node *nr_node = v;		nr_node_lock(nr_node);		seq_printf(seq, "%-9s %-7s  %d %d",			ax2asc(buf, &nr_node->callsign),			(nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,			nr_node->which + 1,			nr_node->count);		for (i = 0; i < nr_node->count; i++) {			seq_printf(seq, "  %3d   %d %05d",				nr_node->routes[i].quality,				nr_node->routes[i].obs_count,				nr_node->routes[i].neighbour->number);		}		nr_node_unlock(nr_node);		seq_puts(seq, "\n");	}	return 0;}static const struct seq_operations nr_node_seqops = {	.start = nr_node_start,	.next = nr_node_next,	.stop = nr_node_stop,	.show = nr_node_show,};static int nr_node_info_open(struct inode *inode, struct file *file){	return seq_open(file, &nr_node_seqops);}const struct file_operations nr_nodes_fops = {	.owner = THIS_MODULE,	.open = nr_node_info_open,	.read = seq_read,	.llseek = seq_lseek,	.release = seq_release,};static void *nr_neigh_start(struct seq_file *seq, loff_t *pos){	struct nr_neigh *nr_neigh;	struct hlist_node *node;	int i = 1;	spin_lock_bh(&nr_neigh_list_lock);	if (*pos == 0)		return SEQ_START_TOKEN;	nr_neigh_for_each(nr_neigh, node, &nr_neigh_list) {		if (i == *pos)			return nr_neigh;	}	return NULL;}static void *nr_neigh_next(struct seq_file *seq, void *v, loff_t *pos){	struct hlist_node *node;	++*pos;	node = (v == SEQ_START_TOKEN)		? nr_neigh_list.first		: ((struct nr_neigh *)v)->neigh_node.next;	return hlist_entry(node, struct nr_neigh, neigh_node);}static void nr_neigh_stop(struct seq_file *seq, void *v){	spin_unlock_bh(&nr_neigh_list_lock);}static int nr_neigh_show(struct seq_file *seq, void *v){	char buf[11];	int i;	if (v == SEQ_START_TOKEN)		seq_puts(seq, "addr  callsign  dev  qual lock count failed digipeaters\n");	else {		struct nr_neigh *nr_neigh = v;		seq_printf(seq, "%05d %-9s %-4s  %3d    %d   %3d    %3d",			nr_neigh->number,			ax2asc(buf, &nr_neigh->callsign),			nr_neigh->dev ? nr_neigh->dev->name : "???",			nr_neigh->quality,			nr_neigh->locked,			nr_neigh->count,			nr_neigh->failed);		if (nr_neigh->digipeat != NULL) {			for (i = 0; i < nr_neigh->digipeat->ndigi; i++)				seq_printf(seq, " %s",					   ax2asc(buf, &nr_neigh->digipeat->calls[i]));		}		seq_puts(seq, "\n");	}	return 0;}static const struct seq_operations nr_neigh_seqops = {	.start = nr_neigh_start,	.next = nr_neigh_next,	.stop = nr_neigh_stop,	.show = nr_neigh_show,};static int nr_neigh_info_open(struct inode *inode, struct file *file){	return seq_open(file, &nr_neigh_seqops);}const struct file_operations nr_neigh_fops = {	.owner = THIS_MODULE,	.open = nr_neigh_info_open,	.read = seq_read,	.llseek = seq_lseek,	.release = seq_release,};#endif/* *	Free all memory associated with the nodes and routes lists. */void __exit nr_rt_free(void){	struct nr_neigh *s = NULL;	struct nr_node  *t = NULL;	struct hlist_node *node, *nodet;	spin_lock_bh(&nr_neigh_list_lock);	spin_lock_bh(&nr_node_list_lock);	nr_node_for_each_safe(t, node, nodet, &nr_node_list) {		nr_node_lock(t);		nr_remove_node_locked(t);		nr_node_unlock(t);	}	nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) {		while(s->count) {			s->count--;			nr_neigh_put(s);		}		nr_remove_neigh_locked(s);	}	spin_unlock_bh(&nr_node_list_lock);	spin_unlock_bh(&nr_neigh_list_lock);}

⌨️ 快捷键说明

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