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

📄 rose_route.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	ROSE release 003 * *	This code REQUIRES 2.1.15 or higher/ NET3.038 * *	This module: *		This module is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. * *	History *	ROSE 001	Jonathan(G4KLX)	Cloned from nr_route.c. *			Terry(VK2KTJ)	Added support for variable length *					address masks. *	ROSE 002	Jonathan(G4KLX)	Uprated through routing of packets. *					Routing loop detection. *	ROSE 003	Jonathan(G4KLX)	New timer architecture. *					Added use count to neighbours. */#include <linux/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/in.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/sockios.h>#include <linux/net.h>#include <net/ax25.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <net/arp.h>#include <linux/if_arp.h>#include <linux/skbuff.h>#include <net/sock.h>#include <asm/segment.h>#include <asm/system.h>#include <asm/uaccess.h>#include <linux/fcntl.h>#include <linux/termios.h>	/* For TIOCINQ/OUTQ */#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/notifier.h>#include <linux/netfilter.h>#include <linux/init.h>#include <net/rose.h>static unsigned int rose_neigh_no = 1;static struct rose_node  *rose_node_list;static struct rose_neigh *rose_neigh_list;static struct rose_route *rose_route_list;struct rose_neigh *rose_loopback_neigh;static void rose_remove_neigh(struct rose_neigh *);/* *	Add a new route to a node, and in the process add the node and the *	neighbour if it is new. */static int rose_add_node(struct rose_route_struct *rose_route, struct net_device *dev){	struct rose_node  *rose_node, *rose_tmpn, *rose_tmpp;	struct rose_neigh *rose_neigh;	unsigned long flags;	int i;	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)		if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0))			break;	if (rose_node != NULL && rose_node->loopback)		return -EINVAL;	for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)		if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)			break;	if (rose_neigh == NULL) {		if ((rose_neigh = kmalloc(sizeof(*rose_neigh), GFP_ATOMIC)) == NULL)			return -ENOMEM;		rose_neigh->callsign  = rose_route->neighbour;		rose_neigh->digipeat  = NULL;		rose_neigh->ax25      = NULL;		rose_neigh->dev       = dev;		rose_neigh->count     = 0;		rose_neigh->use       = 0;		rose_neigh->dce_mode  = 0;		rose_neigh->loopback  = 0;		rose_neigh->number    = rose_neigh_no++;		rose_neigh->restarted = 0;		skb_queue_head_init(&rose_neigh->queue);		init_timer(&rose_neigh->ftimer);		init_timer(&rose_neigh->t0timer);		if (rose_route->ndigis != 0) {			if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {				kfree(rose_neigh);				return -ENOMEM;			}			rose_neigh->digipeat->ndigi      = rose_route->ndigis;			rose_neigh->digipeat->lastrepeat = -1;			for (i = 0; i < rose_route->ndigis; i++) {				rose_neigh->digipeat->calls[i]    = rose_route->digipeaters[i];				rose_neigh->digipeat->repeated[i] = 0;			}		}		save_flags(flags); cli();		rose_neigh->next = rose_neigh_list;		rose_neigh_list  = rose_neigh;		restore_flags(flags);	}	/*	 * This is a new node to be inserted into the list. Find where it needs	 * to be inserted into the list, and insert it. We want to be sure	 * to order the list in descending order of mask size to ensure that	 * later when we are searching this list the first match will be the	 * best match.	 */	if (rose_node == NULL) {		rose_tmpn = rose_node_list;		rose_tmpp = NULL;		while (rose_tmpn != NULL) {			if (rose_tmpn->mask > rose_route->mask) {				rose_tmpp = rose_tmpn;				rose_tmpn = rose_tmpn->next;			} else {				break;			}		}		/* create new node */		if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)			return -ENOMEM;		rose_node->address      = rose_route->address;		rose_node->mask         = rose_route->mask;		rose_node->count        = 1;		rose_node->loopback     = 0;		rose_node->neighbour[0] = rose_neigh;		save_flags(flags); cli();		if (rose_tmpn == NULL) {			if (rose_tmpp == NULL) {	/* Empty list */				rose_node_list  = rose_node;				rose_node->next = NULL;			} else {				rose_tmpp->next = rose_node;				rose_node->next = NULL;			}		} else {			if (rose_tmpp == NULL) {	/* 1st node */				rose_node->next = rose_node_list;				rose_node_list  = rose_node;			} else {				rose_tmpp->next = rose_node;				rose_node->next = rose_tmpn;			}		}		restore_flags(flags);		rose_neigh->count++;		return 0;	}	/* We have space, slot it in */	if (rose_node->count < 3) {		rose_node->neighbour[rose_node->count] = rose_neigh;		rose_node->count++;		rose_neigh->count++;	}	return 0;}static void rose_remove_node(struct rose_node *rose_node){	struct rose_node *s;	unsigned long flags;		save_flags(flags);	cli();	if ((s = rose_node_list) == rose_node) {		rose_node_list = rose_node->next;		restore_flags(flags);		kfree(rose_node);		return;	}	while (s != NULL && s->next != NULL) {		if (s->next == rose_node) {			s->next = rose_node->next;			restore_flags(flags);			kfree(rose_node);			return;		}		s = s->next;	}	restore_flags(flags);}static void rose_remove_neigh(struct rose_neigh *rose_neigh){	struct rose_neigh *s;	unsigned long flags;	struct sk_buff *skb;	rose_stop_ftimer(rose_neigh);	rose_stop_t0timer(rose_neigh);	while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)		kfree_skb(skb);	save_flags(flags); cli();	if ((s = rose_neigh_list) == rose_neigh) {		rose_neigh_list = rose_neigh->next;		restore_flags(flags);		if (rose_neigh->digipeat != NULL)			kfree(rose_neigh->digipeat);		kfree(rose_neigh);		return;	}	while (s != NULL && s->next != NULL) {		if (s->next == rose_neigh) {			s->next = rose_neigh->next;			restore_flags(flags);			if (rose_neigh->digipeat != NULL)				kfree(rose_neigh->digipeat);			kfree(rose_neigh);			return;		}		s = s->next;	}	restore_flags(flags);}static void rose_remove_route(struct rose_route *rose_route){	struct rose_route *s;	unsigned long flags;	if (rose_route->neigh1 != NULL)		rose_route->neigh1->use--;	if (rose_route->neigh2 != NULL)		rose_route->neigh2->use--;	save_flags(flags); cli();	if ((s = rose_route_list) == rose_route) {		rose_route_list = rose_route->next;		restore_flags(flags);		kfree(rose_route);		return;	}	while (s != NULL && s->next != NULL) {		if (s->next == rose_route) {			s->next = rose_route->next;			restore_flags(flags);			kfree(rose_route);			return;		}		s = s->next;	}	restore_flags(flags);}/* *	"Delete" a node. Strictly speaking remove a route to a node. The node *	is only deleted if no routes are left to it. */static int rose_del_node(struct rose_route_struct *rose_route, struct net_device *dev){	struct rose_node  *rose_node;	struct rose_neigh *rose_neigh;	int i;	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)		if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0))			break;	if (rose_node == NULL) return -EINVAL;	if (rose_node->loopback) return -EINVAL;	for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)		if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)			break;	if (rose_neigh == NULL) return -EINVAL;	for (i = 0; i < rose_node->count; i++) {		if (rose_node->neighbour[i] == rose_neigh) {			rose_neigh->count--;			if (rose_neigh->count == 0 && rose_neigh->use == 0)				rose_remove_neigh(rose_neigh);			rose_node->count--;			if (rose_node->count == 0) {				rose_remove_node(rose_node);			} else {				switch (i) {					case 0:						rose_node->neighbour[0] = rose_node->neighbour[1];					case 1:						rose_node->neighbour[1] = rose_node->neighbour[2];					case 2:						break;				}			}			return 0;		}	}	return -EINVAL;}/* *	Add the loopback neighbour. */int rose_add_loopback_neigh(void){	unsigned long flags;	if ((rose_loopback_neigh = kmalloc(sizeof(struct rose_neigh), GFP_ATOMIC)) == NULL)		return -ENOMEM;	rose_loopback_neigh->callsign  = null_ax25_address;	rose_loopback_neigh->digipeat  = NULL;	rose_loopback_neigh->ax25      = NULL;	rose_loopback_neigh->dev       = NULL;	rose_loopback_neigh->count     = 0;	rose_loopback_neigh->use       = 0;	rose_loopback_neigh->dce_mode  = 1;	rose_loopback_neigh->loopback  = 1;	rose_loopback_neigh->number    = rose_neigh_no++;	rose_loopback_neigh->restarted = 1;	skb_queue_head_init(&rose_loopback_neigh->queue);	init_timer(&rose_loopback_neigh->ftimer);	init_timer(&rose_loopback_neigh->t0timer);	save_flags(flags); cli();	rose_loopback_neigh->next = rose_neigh_list;	rose_neigh_list           = rose_loopback_neigh;	restore_flags(flags);	return 0;}/* *	Add a loopback node. */int rose_add_loopback_node(rose_address *address){	struct rose_node *rose_node;	unsigned long flags;	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)		if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback)			break;	if (rose_node != NULL) return 0;		if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)		return -ENOMEM;	rose_node->address      = *address;	rose_node->mask         = 10;	rose_node->count        = 1;	rose_node->loopback     = 1;	rose_node->neighbour[0] = rose_loopback_neigh;	/* Insert at the head of list. Address is always mask=10 */	save_flags(flags); cli();	rose_node->next = rose_node_list;	rose_node_list  = rose_node;	restore_flags(flags);	rose_loopback_neigh->count++;	return 0;}/* *	Delete a loopback node. */void rose_del_loopback_node(rose_address *address){	struct rose_node *rose_node;	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)		if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback)			break;	if (rose_node == NULL) return;	rose_remove_node(rose_node);	rose_loopback_neigh->count--;}/* *	A device has been removed. Remove its routes and neighbours. */void rose_rt_device_down(struct net_device *dev){	struct rose_neigh *s, *rose_neigh = rose_neigh_list;	struct rose_node  *t, *rose_node;	int i;	while (rose_neigh != NULL) {		s          = rose_neigh;		rose_neigh = rose_neigh->next;		if (s->dev == dev) {			rose_node = rose_node_list;			while (rose_node != NULL) {				t         = rose_node;				rose_node = rose_node->next;				for (i = 0; i < t->count; i++) {					if (t->neighbour[i] == s) {						t->count--;						switch (i) {							case 0:								t->neighbour[0] = t->neighbour[1];							case 1:								t->neighbour[1] = t->neighbour[2];							case 2:								break;						}					}				}				if (t->count <= 0)					rose_remove_node(t);			}			rose_remove_neigh(s);		}	}}/* *	A device has been removed. Remove its links. */void rose_route_device_down(struct net_device *dev){	struct rose_route *s, *rose_route = rose_route_list;	while (rose_route != NULL) {		s          = rose_route;		rose_route = rose_route->next;		if (s->neigh1->dev == dev || s->neigh2->dev == dev)			rose_remove_route(s);	}}/* *	Clear all nodes and neighbours out, except for neighbours with *	active connections going through them. *  Do not clear loopback neighbour and nodes. */static int rose_clear_routes(void){	struct rose_neigh *s, *rose_neigh = rose_neigh_list;	struct rose_node  *t, *rose_node  = rose_node_list;	while (rose_node != NULL) {		t         = rose_node;		rose_node = rose_node->next;		if (!t->loopback)			rose_remove_node(t);	}	while (rose_neigh != NULL) {		s          = rose_neigh;		rose_neigh = rose_neigh->next;		if (s->use == 0 && !s->loopback) {			s->count = 0;			rose_remove_neigh(s);		}	}	return 0;}/* *	Check that the device given is a valid AX.25 interface that is "up". */struct net_device *rose_ax25_dev_get(char *devname){	struct net_device *dev;	if ((dev = dev_get_by_name(devname)) == NULL)		return NULL;	if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)		return dev;	dev_put(dev);	return NULL;}/* *	Find the first active ROSE device, usually "rose0". */struct net_device *rose_dev_first(void){	struct net_device *dev, *first = NULL;	read_lock(&dev_base_lock);	for (dev = dev_base; dev != NULL; dev = dev->next) {		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE)			if (first == NULL || strncmp(dev->name, first->name, 3) < 0)				first = dev;	}	read_unlock(&dev_base_lock);	return first;}/* *	Find the ROSE device for the given address. */struct net_device *rose_dev_get(rose_address *addr){	struct net_device *dev;	read_lock(&dev_base_lock);	for (dev = dev_base; dev != NULL; dev = dev->next) {		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) {			dev_hold(dev);			goto out;		}	}out:	read_unlock(&dev_base_lock);	return dev;}static int rose_dev_exists(rose_address *addr){	struct net_device *dev;

⌨️ 快捷键说明

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