Example #1
0
/*
 *	Find AX.25 route
 */
static ax25_route *ax25_find_route(ax25_address *addr, struct device *dev)
{
	ax25_route *ax25_spe_rt = NULL;
	ax25_route *ax25_def_rt = NULL;
	ax25_route *ax25_rt;

	/*
	 *	Bind to the physical interface we heard them on, or the default
	 *	route if none is found;
	 */
	for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
		if (dev == NULL) {
			if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
				ax25_spe_rt = ax25_rt;
			if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
				ax25_def_rt = ax25_rt;
		} else {
			if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev)
				ax25_spe_rt = ax25_rt;
			if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev == dev)
				ax25_def_rt = ax25_rt;
		}
	}

	if (ax25_spe_rt != NULL)
		return ax25_spe_rt;

	return ax25_def_rt;
}
void ax25_listen_release(ax25_address *callsign, struct net_device *dev)
{
	struct listen_struct *s, *listen;

	spin_lock_bh(&listen_lock);
	listen = listen_list;
	if (listen == NULL) {
		spin_unlock_bh(&listen_lock);
		return;
	}

	if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) {
		listen_list = listen->next;
		spin_unlock_bh(&listen_lock);
		kfree(listen);
		return;
	}

	while (listen != NULL && listen->next != NULL) {
		if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) {
			s = listen->next;
			listen->next = listen->next->next;
			spin_unlock_bh(&listen_lock);
			kfree(s);
			return;
		}

		listen = listen->next;
	}
	spin_unlock_bh(&listen_lock);
}
Example #3
0
void ax25_listen_release(ax25_address *callsign, struct device *dev)
{
	struct listen_struct *s, *listen = listen_list;
	unsigned long flags;

	if (listen == NULL)
		return;

	save_flags(flags);
	cli();

	if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) {
		listen_list = listen->next;
		restore_flags(flags);
		kfree_s(listen, sizeof(struct listen_struct));
		return;
	}

	while (listen != NULL && listen->next != NULL) {
		if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) {
			s = listen->next;
			listen->next = listen->next->next;
			restore_flags(flags);
			kfree_s(s, sizeof(struct listen_struct));
			return;
		}

		listen = listen->next;
	}

	restore_flags(flags);
}
Example #4
0
static int ax25_rt_del(struct ax25_routes_struct *route)
{
	ax25_route *s, *t, *ax25_rt;
	ax25_dev *ax25_dev;

	if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
		return -EINVAL;

	write_lock_bh(&ax25_route_lock);

	ax25_rt = ax25_route_list;
	while (ax25_rt != NULL) {
		s       = ax25_rt;
		ax25_rt = ax25_rt->next;
		if (s->dev == ax25_dev->dev &&
		    ax25cmp(&route->dest_addr, &s->callsign) == 0) {
			if (ax25_route_list == s) {
				ax25_route_list = s->next;
				ax25_put_route(s);
			} else {
				for (t = ax25_route_list; t != NULL; t = t->next) {
					if (t->next == s) {
						t->next = s->next;
						ax25_put_route(s);
						break;
					}
				}
			}
		}
	}
	write_unlock_bh(&ax25_route_lock);

	return 0;
}
Example #5
0
int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
{
	ax25_route *ax25_rt;
	int len     = 0;
	off_t pos   = 0;
	off_t begin = 0;
	char *callsign;
	int i;
  
	cli();

	len += sprintf(buffer, "callsign  dev  mode digipeaters\n");

	for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
		if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
			callsign = "default";
		else
			callsign = ax2asc(&ax25_rt->callsign);
		len += sprintf(buffer + len, "%-9s %-4s",
			callsign,
			ax25_rt->dev ? ax25_rt->dev->name : "???");

		switch (ax25_rt->ip_mode) {
			case 'V':
				len += sprintf(buffer + len, "   vc");
				break;
			case 'D':
				len += sprintf(buffer + len, "   dg");
				break;
			default:
				len += sprintf(buffer + len, "    *");
				break;
		}

		if (ax25_rt->digipeat != NULL)
			for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
				len += sprintf(buffer + len, " %s", ax2asc(&ax25_rt->digipeat->calls[i]));

		len += sprintf(buffer + len, "\n");

		pos = begin + len;

		if (pos < offset) {
			len   = 0;
			begin = pos;
		}

		if (pos > offset + length)
			break;
	}

	sti();

	*start = buffer + (offset - begin);
	len   -= (offset - begin);

	if (len > length) len = length;

	return len;
} 
Example #6
0
/*
 *	"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 nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct net_device *dev)
{
	struct nr_node  *nr_node;
	struct nr_neigh *nr_neigh;
	int i;

	for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
		if (ax25cmp(callsign, &nr_node->callsign) == 0)
			break;

	if (nr_node == NULL) return -EINVAL;

	for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
		if (ax25cmp(neighbour, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
			break;

	if (nr_neigh == NULL) return -EINVAL;

	for (i = 0; i < nr_node->count; i++) {
		if (nr_node->routes[i].neighbour == nr_neigh) {
			nr_neigh->count--;

			if (nr_neigh->count == 0 && !nr_neigh->locked)
				nr_remove_neigh(nr_neigh);

			nr_node->count--;

			if (nr_node->count == 0) {
				nr_remove_node(nr_node);
			} else {
				switch (i) {
					case 0:
						nr_node->routes[0] = nr_node->routes[1];
					case 1:
						nr_node->routes[1] = nr_node->routes[2];
					case 2:
						break;
				}
			}

			return 0;
		}
	}

	return -EINVAL;
}
Example #7
0
ax25_dev *ax25_addr_ax25dev(ax25_address *addr)
{
	ax25_dev *ax25_dev;

	for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
		if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0)
			return ax25_dev;

	return NULL;
}
Example #8
0
int ax25_listen_mine(ax25_address *callsign, struct device *dev)
{
	struct listen_struct *listen;

	for (listen = listen_list; listen != NULL; listen = listen->next)
		if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL))
			return 1;

	return 0;
}
Example #9
0
/*
 *	"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 device *dev)
{
	struct rose_node  *rose_node;
	struct rose_neigh *rose_neigh;
	struct rose_route_struct dummy_route;
	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;

	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) {
				/* Add a dummy node to keep the neighbourg still visible */
				dummy_route = *rose_route;
				dummy_route.mask = 10;
				memset(&dummy_route.address, 0, sizeof(rose_address));
				rose_add_node(&dummy_route, dev);
			}
			/* 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;
}
Example #10
0
/*
 *	Adjust path: If you specify a default route and want to connect
 *      a target on the digipeater path but w/o having a special route
 *	set before, the path has to be truncated from your target on.
 */
static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
{
	int k;

	for (k = 0; k < digipeat->ndigi; k++) {
		if (ax25cmp(addr, &digipeat->calls[k]) == 0)
			break;
	}

	digipeat->ndigi = k;
}
Example #11
0
/*
 *	Interface to ax25_send_frame. Changes my level 2 callsign depending
 *	on whether we have a global ROSE callsign or use the default port
 *	callsign.
 */
static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
{
	ax25_address *rose_call;

	if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
		rose_call = (ax25_address *)neigh->dev->dev_addr;
	else
		rose_call = &rose_callsign;

	neigh->ax25 = ax25_send_frame(skb, 260, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);

	return (neigh->ax25 != NULL);
}
Example #12
0
ax25_dev *ax25_addr_ax25dev(ax25_address *addr)
{
	ax25_dev *ax25_dev, *res = NULL;

	spin_lock_bh(&ax25_dev_lock);
	for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
		if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) {
			res = ax25_dev;
		}
	spin_unlock_bh(&ax25_dev_lock);

	return res;
}
Example #13
0
/*
 *	Interface to ax25_link_up. Changes my level 2 callsign depending
 *	on whether we have a global ROSE callsign or use the default port
 *	callsign.
 */
static int rose_link_up(struct rose_neigh *neigh)
{
	ax25_address *rose_call;

	if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
		rose_call = (ax25_address *)neigh->dev->dev_addr;
	else
		rose_call = &rose_callsign;

	neigh->ax25 = ax25_find_cb(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);

	return (neigh->ax25 != NULL);
}
Example #14
0
int ax25_listen_mine(ax25_address *callsign, struct net_device *dev)
{
	struct listen_struct *listen;

	spin_lock_bh(&listen_lock);
	for (listen = listen_list; listen != NULL; listen = listen->next)
		if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) {
			spin_unlock_bh(&listen_lock);
			return 1;
	}
	spin_unlock_bh(&listen_lock);

	return 0;
}
Example #15
0
/*
 *	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;


	nr_src  = (ax25_address *)(skb->data + 0);
	nr_dest = (ax25_address *)(skb->data + 7);

	if (ax25 != NULL)
		nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
			    ax25->ax25_dev->dev, 0, sysctl_netrom_obsolescence_count_initialiser);

	if ((dev = nr_dev_get(nr_dest)) != NULL) {	/* Its for me */
		if (ax25 == NULL)			/* Its from me */
			return nr_loopback_queue(skb);
		else
			return nr_rx_frame(skb, dev);
	}

	if (!sysctl_netrom_routing_control && ax25 != NULL)
		return 0;

	/* Its Time-To-Live has expired */
	if (--skb->data[14] == 0)
		return 0;

	for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
		if (ax25cmp(nr_dest, &nr_node->callsign) == 0)
			break;

	if (nr_node == NULL || nr_node->which >= nr_node->count)
		return 0;

	nr_neigh = nr_node->routes[nr_node->which].neighbour;

	if ((dev = nr_dev_first()) == NULL)
		return 0;

	dptr  = skb_push(skb, 1);
	*dptr = AX25_P_NETROM;

	nr_neigh->ax25 = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);

	return (nr_neigh->ax25 != NULL);
}
Example #16
0
/*
 *	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 (dev = dev_base; dev != NULL; dev = dev->next) {
		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) {
			dev_hold(dev);
			goto out;
		}
	}
out:
	read_unlock(&dev_base_lock);
	return dev;
}
ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
{
	ax25_route *ax25_spe_rt = NULL;
	ax25_route *ax25_def_rt = NULL;
	ax25_route *ax25_rt;

	read_lock(&ax25_route_lock);
	/*
                                                                   
                           
  */
	for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
		if (dev == NULL) {
			if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
				ax25_spe_rt = ax25_rt;
			if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
				ax25_def_rt = ax25_rt;
		} else {
			if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev)
				ax25_spe_rt = ax25_rt;
			if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev == dev)
				ax25_def_rt = ax25_rt;
		}
	}

	ax25_rt = ax25_def_rt;
	if (ax25_spe_rt != NULL)
		ax25_rt = ax25_spe_rt;

	if (ax25_rt != NULL)
		ax25_hold_route(ax25_rt);

	read_unlock(&ax25_route_lock);

	return ax25_rt;
}
Example #18
0
/*
 *	"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;
}
Example #19
0
/*
 *	"Delete" a neighbour. The neighbour is only removed if the number
 *	of nodes that may use it is zero.
 */
static int nr_del_neigh(ax25_address *callsign, struct net_device *dev, unsigned int quality)
{
	struct nr_neigh *nr_neigh;

	for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
		if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
			break;

	if (nr_neigh == NULL) return -EINVAL;

	nr_neigh->quality = quality;
	nr_neigh->locked  = 0;

	if (nr_neigh->count == 0)
		nr_remove_neigh(nr_neigh);

	return 0;
}
Example #20
0
/*
 *	Lock a neighbour with a quality.
 */
static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality)
{
	struct nr_neigh *nr_neigh;
	unsigned long flags;

	for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
		if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) {
			nr_neigh->quality = quality;
			nr_neigh->locked  = 1;
			return 0;
		}
	}

	if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
		return -ENOMEM;

	nr_neigh->callsign = *callsign;
	nr_neigh->digipeat = NULL;
	nr_neigh->ax25     = NULL;
	nr_neigh->dev      = dev;
	nr_neigh->quality  = quality;
	nr_neigh->locked   = 1;
	nr_neigh->count    = 0;
	nr_neigh->number   = nr_neigh_no++;
	nr_neigh->failed   = 0;

	if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
		if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
			kfree(nr_neigh);
			return -ENOMEM;
		}
		memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
	}

	save_flags(flags);
	cli();

	nr_neigh->next = nr_neigh_list;
	nr_neigh_list  = nr_neigh;

	restore_flags(flags);

	return 0;	
}
Example #21
0
static int ax25_rt_seq_show(struct seq_file *seq, void *v)
{
	char buf[11];

	if (v == SEQ_START_TOKEN)
		seq_puts(seq, "callsign  dev  mode digipeaters\n");
	else {
		struct ax25_route *ax25_rt = v;
		const char *callsign;
		int i;

		if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
			callsign = "default";
		else
			callsign = ax2asc(buf, &ax25_rt->callsign);

		seq_printf(seq, "%-9s %-4s",
			callsign,
			ax25_rt->dev ? ax25_rt->dev->name : "???");

		switch (ax25_rt->ip_mode) {
		case 'V':
			seq_puts(seq, "   vc");
			break;
		case 'D':
			seq_puts(seq, "   dg");
			break;
		default:
			seq_puts(seq, "    *");
			break;
		}

		if (ax25_rt->digipeat != NULL)
			for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
				seq_printf(seq, " %s",
				     ax2asc(buf, &ax25_rt->digipeat->calls[i]));

		seq_puts(seq, "\n");
	}
	return 0;
}
Example #22
0
static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
{
	ax25_route *ax25_rt;
	ax25_dev *ax25_dev;
	int err = 0;

	if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL)
		return -EINVAL;

	write_lock_bh(&ax25_route_lock);

	ax25_rt = ax25_route_list;
	while (ax25_rt != NULL) {
		if (ax25_rt->dev == ax25_dev->dev &&
		    ax25cmp(&rt_option->dest_addr, &ax25_rt->callsign) == 0) {
			switch (rt_option->cmd) {
			case AX25_SET_RT_IPMODE:
				switch (rt_option->arg) {
				case ' ':
				case 'D':
				case 'V':
					ax25_rt->ip_mode = rt_option->arg;
					break;
				default:
					err = -EINVAL;
					goto out;
				}
				break;
			default:
				err = -EINVAL;
				goto out;
			}
		}
		ax25_rt = ax25_rt->next;
	}

out:
	write_unlock_bh(&ax25_route_lock);
	return err;
}
Example #23
0
/*
 *	Add a new route to a node, and in the process add the node and the
 *	neighbour if it is new.
 */
static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax25,
	ax25_digi *ax25_digi, struct net_device *dev, int quality, int obs_count)
{
	struct nr_node  *nr_node;
	struct nr_neigh *nr_neigh;
	struct nr_route nr_route;
	unsigned long flags;
	int i, found;

	if (nr_dev_get(nr) != NULL)	/* Can't add routes to ourself */
		return -EINVAL;

	for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
		if (ax25cmp(nr, &nr_node->callsign) == 0)
			break;

	for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
		if (ax25cmp(ax25, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
			break;

	/*
	 * The L2 link to a neighbour has failed in the past
	 * and now a frame comes from this neighbour. We assume
	 * it was a temporary trouble with the link and reset the
	 * routes now (and not wait for a node broadcast).
	 */
	if (nr_neigh != NULL && nr_neigh->failed != 0 && quality == 0) {
		struct nr_node *node;

		for (node = nr_node_list; node != NULL; node = node->next)
			for (i = 0; i < node->count; i++)
				if (node->routes[i].neighbour == nr_neigh)
					if (i < node->which)
						node->which = i;
	}

	if (nr_neigh != NULL)
		nr_neigh->failed = 0;

	if (quality == 0 && nr_neigh != NULL && nr_node != NULL)
		return 0;

	if (nr_neigh == NULL) {
		if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
			return -ENOMEM;

		nr_neigh->callsign = *ax25;
		nr_neigh->digipeat = NULL;
		nr_neigh->ax25     = NULL;
		nr_neigh->dev      = dev;
		nr_neigh->quality  = sysctl_netrom_default_path_quality;
		nr_neigh->locked   = 0;
		nr_neigh->count    = 0;
		nr_neigh->number   = nr_neigh_no++;
		nr_neigh->failed   = 0;

		if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
			if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
				kfree(nr_neigh);
				return -ENOMEM;
			}
			memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
		}

		save_flags(flags);
		cli();

		nr_neigh->next = nr_neigh_list;
		nr_neigh_list  = nr_neigh;

		restore_flags(flags);
	}

	if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked)
		nr_neigh->quality = quality;

	if (nr_node == NULL) {
		if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL)
			return -ENOMEM;

		nr_node->callsign = *nr;
		strcpy(nr_node->mnemonic, mnemonic);

		nr_node->which = 0;
		nr_node->count = 1;

		nr_node->routes[0].quality   = quality;
		nr_node->routes[0].obs_count = obs_count;
		nr_node->routes[0].neighbour = nr_neigh;

		save_flags(flags);
		cli();

		nr_node->next = nr_node_list;
		nr_node_list  = nr_node;

		restore_flags(flags);

		nr_neigh->count++;

		return 0;
	}

	if (quality != 0)
		strcpy(nr_node->mnemonic, mnemonic);

	for (found = 0, i = 0; i < nr_node->count; i++) {
		if (nr_node->routes[i].neighbour == nr_neigh) {
			nr_node->routes[i].quality   = quality;
			nr_node->routes[i].obs_count = obs_count;
			found = 1;
			break;
		}
	}

	if (!found) {
		/* We have space at the bottom, slot it in */
		if (nr_node->count < 3) {
			nr_node->routes[2] = nr_node->routes[1];
			nr_node->routes[1] = nr_node->routes[0];

			nr_node->routes[0].quality   = quality;
			nr_node->routes[0].obs_count = obs_count;
			nr_node->routes[0].neighbour = nr_neigh;

			nr_node->which++;
			nr_node->count++;
			nr_neigh->count++;
		} else {
			/* It must be better than the worst */
			if (quality > nr_node->routes[2].quality) {
				nr_node->routes[2].neighbour->count--;

				if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
					nr_remove_neigh(nr_node->routes[2].neighbour);

				nr_node->routes[2].quality   = quality;
				nr_node->routes[2].obs_count = obs_count;
				nr_node->routes[2].neighbour = nr_neigh;

				nr_neigh->count++;
			}
		}
	}

	/* Now re-sort the routes in quality order */
	switch (nr_node->count) {
		case 3:
			if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
				switch (nr_node->which) {
					case 0:  nr_node->which = 1; break;
					case 1:  nr_node->which = 0; break;
					default: break;
				}
				nr_route           = nr_node->routes[0];
				nr_node->routes[0] = nr_node->routes[1];
				nr_node->routes[1] = nr_route;
			}
			if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
				switch (nr_node->which) {
					case 1:  nr_node->which = 2; break;
					case 2:  nr_node->which = 1; break;
					default: break;
				}
				nr_route           = nr_node->routes[1];
				nr_node->routes[1] = nr_node->routes[2];
				nr_node->routes[2] = nr_route;
			}
		case 2:
			if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
				switch (nr_node->which) {
					case 0:  nr_node->which = 1; break;
					case 1:  nr_node->which = 0; break;
					default: break;
				}
				nr_route           = nr_node->routes[0];
				nr_node->routes[0] = nr_node->routes[1];
				nr_node->routes[1] = nr_route;
			}
		case 1:
			break;
	}

	for (i = 0; i < nr_node->count; i++) {
		if (nr_node->routes[i].neighbour == nr_neigh) {
			if (i < nr_node->which)
				nr_node->which = i;
			break;
		}
	}

	return 0;
}
Example #24
0
/*
 *	Route a frame to an appropriate AX.25 connection.
 */
int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
{
    struct rose_neigh *rose_neigh, *new_neigh;
    struct rose_route *rose_route;
    struct rose_facilities_struct facilities;
    rose_address *src_addr, *dest_addr;
    struct sock *sk;
    unsigned short frametype;
    unsigned int lci, new_lci;
    unsigned char cause, diagnostic;
    struct net_device *dev;
    int len, res = 0;

#if 0
    if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT)
        return res;
#endif

    frametype = skb->data[2];
    lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
    src_addr  = (rose_address *)(skb->data + 9);
    dest_addr = (rose_address *)(skb->data + 4);

    spin_lock_bh(&rose_node_list_lock);
    spin_lock_bh(&rose_neigh_list_lock);
    spin_lock_bh(&rose_route_list_lock);

    rose_neigh = rose_neigh_list;
    while (rose_neigh != NULL) {
        if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 &&
                ax25->ax25_dev->dev == rose_neigh->dev)
            break;
        rose_neigh = rose_neigh->next;
    }

    if (rose_neigh == NULL) {
        printk("rose_route : unknown neighbour or device %s\n",
               ax2asc(&ax25->dest_addr));
        goto out;
    }

    /*
     *	Obviously the link is working, halt the ftimer.
     */
    rose_stop_ftimer(rose_neigh);

    /*
     *	LCI of zero is always for us, and its always a restart
     * 	frame.
     */
    if (lci == 0) {
        rose_link_rx_restart(skb, rose_neigh, frametype);
        goto out;
    }

    /*
     *	Find an existing socket.
     */
    if ((sk = rose_find_socket(lci, rose_neigh)) != NULL) {
        if (frametype == ROSE_CALL_REQUEST) {
            struct rose_sock *rose = rose_sk(sk);

            /* Remove an existing unused socket */
            rose_clear_queues(sk);
            rose->cause	 = ROSE_NETWORK_CONGESTION;
            rose->diagnostic = 0;
            rose->neighbour->use--;
            rose->neighbour	 = NULL;
            rose->lci	 = 0;
            rose->state	 = ROSE_STATE_0;
            sk->sk_state	 = TCP_CLOSE;
            sk->sk_err	 = 0;
            sk->sk_shutdown	 |= SEND_SHUTDOWN;
            if (!sock_flag(sk, SOCK_DEAD)) {
                sk->sk_state_change(sk);
                sock_set_flag(sk, SOCK_DEAD);
            }
        }
        else {
            skb->h.raw = skb->data;
            res = rose_process_rx_frame(sk, skb);
            goto out;
        }
    }

    /*
     *	Is is a Call Request and is it for us ?
     */
    if (frametype == ROSE_CALL_REQUEST)
        if ((dev = rose_dev_get(dest_addr)) != NULL) {
            res = rose_rx_call_request(skb, dev, rose_neigh, lci);
            dev_put(dev);
            goto out;
        }

    if (!sysctl_rose_routing_control) {
        rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0);
        goto out;
    }

    /*
     *	Route it to the next in line if we have an entry for it.
     */
    rose_route = rose_route_list;
    while (rose_route != NULL) {
        if (rose_route->lci1 == lci &&
                rose_route->neigh1 == rose_neigh) {
            if (frametype == ROSE_CALL_REQUEST) {
                /* F6FBB - Remove an existing unused route */
                rose_remove_route(rose_route);
                break;
            } else if (rose_route->neigh2 != NULL) {
                skb->data[0] &= 0xF0;
                skb->data[0] |= (rose_route->lci2 >> 8) & 0x0F;
                skb->data[1]  = (rose_route->lci2 >> 0) & 0xFF;
                rose_transmit_link(skb, rose_route->neigh2);
                if (frametype == ROSE_CLEAR_CONFIRMATION)
                    rose_remove_route(rose_route);
                res = 1;
                goto out;
            } else {
                if (frametype == ROSE_CLEAR_CONFIRMATION)
                    rose_remove_route(rose_route);
                goto out;
            }
        }
Example #25
0
static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
{
	ax25_route *ax25_rt;
	ax25_dev *ax25_dev;
	int i;

	if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
		return -EINVAL;
	if (route->digi_count > AX25_MAX_DIGIS)
		return -EINVAL;

	write_lock_bh(&ax25_route_lock);

	ax25_rt = ax25_route_list;
	while (ax25_rt != NULL) {
		if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 &&
			    ax25_rt->dev == ax25_dev->dev) {
			kfree(ax25_rt->digipeat);
			ax25_rt->digipeat = NULL;
			if (route->digi_count != 0) {
				if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
					write_unlock_bh(&ax25_route_lock);
					return -ENOMEM;
				}
				ax25_rt->digipeat->lastrepeat = -1;
				ax25_rt->digipeat->ndigi      = route->digi_count;
				for (i = 0; i < route->digi_count; i++) {
					ax25_rt->digipeat->repeated[i] = 0;
					ax25_rt->digipeat->calls[i]    = route->digi_addr[i];
				}
			}
			write_unlock_bh(&ax25_route_lock);
			return 0;
		}
		ax25_rt = ax25_rt->next;
	}

	if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
		write_unlock_bh(&ax25_route_lock);
		return -ENOMEM;
	}

	refcount_set(&ax25_rt->refcount, 1);
	ax25_rt->callsign     = route->dest_addr;
	ax25_rt->dev          = ax25_dev->dev;
	ax25_rt->digipeat     = NULL;
	ax25_rt->ip_mode      = ' ';
	if (route->digi_count != 0) {
		if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
			write_unlock_bh(&ax25_route_lock);
			kfree(ax25_rt);
			return -ENOMEM;
		}
		ax25_rt->digipeat->lastrepeat = -1;
		ax25_rt->digipeat->ndigi      = route->digi_count;
		for (i = 0; i < route->digi_count; i++) {
			ax25_rt->digipeat->repeated[i] = 0;
			ax25_rt->digipeat->calls[i]    = route->digi_addr[i];
		}
	}
	ax25_rt->next   = ax25_route_list;
	ax25_route_list = ax25_rt;
	write_unlock_bh(&ax25_route_lock);

	return 0;
}
Example #26
0
int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
{
	ax25_uid_assoc *s, *ax25_uid;
	unsigned long flags;

	switch (cmd) {
		case SIOCAX25GETUID:
			for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
				if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
					return ax25_uid->uid;
			}
			return -ENOENT;

		case SIOCAX25ADDUID:
			if (!capable(CAP_NET_ADMIN))
				return -EPERM;
			if (ax25_findbyuid(sax->sax25_uid))
				return -EEXIST;
			if (sax->sax25_uid == 0)
				return -EINVAL;
			if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
				return -ENOMEM;
			ax25_uid->uid  = sax->sax25_uid;
			ax25_uid->call = sax->sax25_call;
			save_flags(flags); cli();
			ax25_uid->next = ax25_uid_list;
			ax25_uid_list  = ax25_uid;
			restore_flags(flags);
			return 0;

		case SIOCAX25DELUID:
			if (!capable(CAP_NET_ADMIN))
				return -EPERM;
			for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
				if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
					break;
			}
			if (ax25_uid == NULL)
				return -ENOENT;
			save_flags(flags); cli();
			if ((s = ax25_uid_list) == ax25_uid) {
				ax25_uid_list = s->next;
				restore_flags(flags);
				kfree(ax25_uid);
				return 0;
			}
			while (s != NULL && s->next != NULL) {
				if (s->next == ax25_uid) {
					s->next = ax25_uid->next;
					restore_flags(flags);
					kfree(ax25_uid);
					return 0;
				}
				s = s->next;
			}
			restore_flags(flags);
			return -ENOENT;

		default:
			return -EINVAL;
	}

	return -EINVAL;	/*NOTREACHED */
}
Example #27
0
/*
 *	"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, err = 0;

    spin_lock_bh(&rose_node_list_lock);
    spin_lock_bh(&rose_neigh_list_lock);

    rose_node = rose_node_list;
    while (rose_node != NULL) {
        if ((rose_node->mask == rose_route->mask) &&
                (rosecmpm(&rose_route->address, &rose_node->address,
                          rose_route->mask) == 0))
            break;
        rose_node = rose_node->next;
    }

    if (rose_node == NULL || rose_node->loopback) {
        err = -EINVAL;
        goto out;
    }

    rose_neigh = rose_neigh_list;
    while (rose_neigh != NULL) {
        if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0
                && rose_neigh->dev == dev)
            break;
        rose_neigh = rose_neigh->next;
    }

    if (rose_neigh == NULL) {
        err = -EINVAL;
        goto out;
    }

    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;
                }
            }
            goto out;
        }
    }
    err = -EINVAL;

out:
    spin_unlock_bh(&rose_neigh_list_lock);
    spin_unlock_bh(&rose_node_list_lock);

    return err;
}
Example #28
0
int ax25_rt_ioctl(unsigned int cmd, void *arg)
{
	unsigned long flags;
	ax25_route *s, *t, *ax25_rt;
	struct ax25_routes_struct route;
	struct ax25_route_opt_struct rt_option;
	ax25_dev *ax25_dev;
	int i;

	switch (cmd) {
		case SIOCADDRT:
			if (copy_from_user(&route, arg, sizeof(route)))
				return -EFAULT;
			if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
				return -EINVAL;
			if (route.digi_count > AX25_MAX_DIGIS)
				return -EINVAL;
			for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
				if (ax25cmp(&ax25_rt->callsign, &route.dest_addr) == 0 && ax25_rt->dev == ax25_dev->dev) {
					if (ax25_rt->digipeat != NULL) {
						kfree(ax25_rt->digipeat);
						ax25_rt->digipeat = NULL;
					}
					if (route.digi_count != 0) {
						if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
							return -ENOMEM;
						ax25_rt->digipeat->lastrepeat = -1;
						ax25_rt->digipeat->ndigi      = route.digi_count;
						for (i = 0; i < route.digi_count; i++) {
							ax25_rt->digipeat->repeated[i] = 0;
							ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
						}
					}
					return 0;
				}
			}
			if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL)
				return -ENOMEM;
			ax25_rt->callsign     = route.dest_addr;
			ax25_rt->dev          = ax25_dev->dev;
			ax25_rt->digipeat     = NULL;
			ax25_rt->ip_mode      = ' ';
			if (route.digi_count != 0) {
				if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
					kfree(ax25_rt);
					return -ENOMEM;
				}
				ax25_rt->digipeat->lastrepeat = -1;
				ax25_rt->digipeat->ndigi      = route.digi_count;
				for (i = 0; i < route.digi_count; i++) {
					ax25_rt->digipeat->repeated[i] = 0;
					ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
				}
			}
			save_flags(flags); cli();
			ax25_rt->next   = ax25_route_list;
			ax25_route_list = ax25_rt;
			restore_flags(flags);
			break;

		case SIOCDELRT:
			if (copy_from_user(&route, arg, sizeof(route)))
				return -EFAULT;
			if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
				return -EINVAL;
			ax25_rt = ax25_route_list;
			while (ax25_rt != NULL) {
				s       = ax25_rt;
				ax25_rt = ax25_rt->next;
				if (s->dev == ax25_dev->dev && ax25cmp(&route.dest_addr, &s->callsign) == 0) {
					if (ax25_route_list == s) {
						ax25_route_list = s->next;
						if (s->digipeat != NULL)
							kfree(s->digipeat);
						kfree(s);
					} else {
						for (t = ax25_route_list; t != NULL; t = t->next) {
							if (t->next == s) {
								t->next = s->next;
								if (s->digipeat != NULL)
									kfree(s->digipeat);
								kfree(s);
								break;
							}
						}				
					}
				}
			}
			break;

		case SIOCAX25OPTRT:
			if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
				return -EFAULT;
			if ((ax25_dev = ax25_addr_ax25dev(&rt_option.port_addr)) == NULL)
				return -EINVAL;
			for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
				if (ax25_rt->dev == ax25_dev->dev && ax25cmp(&rt_option.dest_addr, &ax25_rt->callsign) == 0) {
					switch (rt_option.cmd) {
						case AX25_SET_RT_IPMODE:
							switch (rt_option.arg) {
								case ' ':
								case 'D':
								case 'V':
									ax25_rt->ip_mode = rt_option.arg;
									break;
								default:
									return -EINVAL;
							}
							break;
						default:
							return -EINVAL;
					}
				}
			}
			break;

		default:
			return -EINVAL;
	}

	return 0;
}
Example #29
0
static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
	ax25_address *dev_addr, struct packet_type *ptype)
{
	ax25_address src, dest, *next_digi = NULL;
	int type = 0, mine = 0, dama;
	struct sock *make, *sk;
	ax25_digi dp, reverse_dp;
	ax25_cb *ax25;
	ax25_dev *ax25_dev;

	/*
	 *	Process the AX.25/LAPB frame.
	 */

	skb_reset_transport_header(skb);

	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
		kfree_skb(skb);
		return 0;
	}

	/*
	 *	Parse the address header.
	 */

	if (ax25_addr_parse(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL) {
		kfree_skb(skb);
		return 0;
	}

	/*
	 *	Ours perhaps ?
	 */
	if (dp.lastrepeat + 1 < dp.ndigi)		/* Not yet digipeated completely */
		next_digi = &dp.calls[dp.lastrepeat + 1];

	/*
	 *	Pull of the AX.25 headers leaving the CTRL/PID bytes
	 */
	skb_pull(skb, ax25_addr_size(&dp));

	/* For our port addresses ? */
	if (ax25cmp(&dest, dev_addr) == 0 && dp.lastrepeat + 1 == dp.ndigi)
		mine = 1;

	/* Also match on any registered callsign from L3/4 */
	if (!mine && ax25_listen_mine(&dest, dev) && dp.lastrepeat + 1 == dp.ndigi)
		mine = 1;

	/* UI frame - bypass LAPB processing */
	if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) {
		skb_set_transport_header(skb, 2); /* skip control and pid */

		ax25_send_to_raw(&dest, skb, skb->data[1]);

		if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) {
			kfree_skb(skb);
			return 0;
		}

		/* Now we are pointing at the pid byte */
		switch (skb->data[1]) {
		case AX25_P_IP:
			skb_pull(skb,2);		/* drop PID/CTRL */
			skb_reset_transport_header(skb);
			skb_reset_network_header(skb);
			skb->dev      = dev;
			skb->pkt_type = PACKET_HOST;
			skb->protocol = htons(ETH_P_IP);
			netif_rx(skb);
			break;

		case AX25_P_ARP:
			skb_pull(skb,2);
			skb_reset_transport_header(skb);
			skb_reset_network_header(skb);
			skb->dev      = dev;
			skb->pkt_type = PACKET_HOST;
			skb->protocol = htons(ETH_P_ARP);
			netif_rx(skb);
			break;
		case AX25_P_TEXT:
			/* Now find a suitable dgram socket */
			sk = ax25_get_socket(&dest, &src, SOCK_DGRAM);
			if (sk != NULL) {
				bh_lock_sock(sk);
				if (atomic_read(&sk->sk_rmem_alloc) >=
				    sk->sk_rcvbuf) {
					kfree_skb(skb);
				} else {
					/*
					 *	Remove the control and PID.
					 */
					skb_pull(skb, 2);
					if (sock_queue_rcv_skb(sk, skb) != 0)
						kfree_skb(skb);
				}
				bh_unlock_sock(sk);
				sock_put(sk);
			} else {
				kfree_skb(skb);
			}
			break;

		default:
			kfree_skb(skb);	/* Will scan SOCK_AX25 RAW sockets */
			break;
		}

		return 0;
	}

	/*
	 *	Is connected mode supported on this device ?
	 *	If not, should we DM the incoming frame (except DMs) or
	 *	silently ignore them. For now we stay quiet.
	 */
	if (ax25_dev->values[AX25_VALUES_CONMODE] == 0) {
		kfree_skb(skb);
		return 0;
	}

	/* LAPB */

	/* AX.25 state 1-4 */

	ax25_digi_invert(&dp, &reverse_dp);

	if ((ax25 = ax25_find_cb(&dest, &src, &reverse_dp, dev)) != NULL) {
		/*
		 *	Process the frame. If it is queued up internally it
		 *	returns one otherwise we free it immediately. This
		 *	routine itself wakes the user context layers so we do
		 *	no further work
		 */
		if (ax25_process_rx_frame(ax25, skb, type, dama) == 0)
			kfree_skb(skb);

		ax25_cb_put(ax25);
		return 0;
	}

	/* AX.25 state 0 (disconnected) */

	/* a) received not a SABM(E) */

	if ((*skb->data & ~AX25_PF) != AX25_SABM &&
	    (*skb->data & ~AX25_PF) != AX25_SABME) {
		/*
		 *	Never reply to a DM. Also ignore any connects for
		 *	addresses that are not our interfaces and not a socket.
		 */
		if ((*skb->data & ~AX25_PF) != AX25_DM && mine)
			ax25_return_dm(dev, &src, &dest, &dp);

		kfree_skb(skb);
		return 0;
	}

	/* b) received SABM(E) */

	if (dp.lastrepeat + 1 == dp.ndigi)
		sk = ax25_find_listener(&dest, 0, dev, SOCK_SEQPACKET);
	else
		sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET);

	if (sk != NULL) {
		bh_lock_sock(sk);
		if (sk_acceptq_is_full(sk) ||
		    (make = ax25_make_new(sk, ax25_dev)) == NULL) {
			if (mine)
				ax25_return_dm(dev, &src, &dest, &dp);
			kfree_skb(skb);
			bh_unlock_sock(sk);
			sock_put(sk);

			return 0;
		}

		ax25 = ax25_sk(make);
		skb_set_owner_r(skb, make);
		skb_queue_head(&sk->sk_receive_queue, skb);

		make->sk_state = TCP_ESTABLISHED;

		sk->sk_ack_backlog++;
		bh_unlock_sock(sk);
	} else {
		if (!mine) {
			kfree_skb(skb);
			return 0;
		}

		if ((ax25 = ax25_create_cb()) == NULL) {
			ax25_return_dm(dev, &src, &dest, &dp);
			kfree_skb(skb);
			return 0;
		}

		ax25_fillin_cb(ax25, ax25_dev);
	}

	ax25->source_addr = dest;
	ax25->dest_addr   = src;

	/*
	 *	Sort out any digipeated paths.
	 */
	if (dp.ndigi && !ax25->digipeat &&
	    (ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
		kfree_skb(skb);
		ax25_destroy_socket(ax25);
		if (sk)
			sock_put(sk);
		return 0;
	}

	if (dp.ndigi == 0) {
		kfree(ax25->digipeat);
		ax25->digipeat = NULL;
	} else {
		/* Reverse the source SABM's path */
		memcpy(ax25->digipeat, &reverse_dp, sizeof(ax25_digi));
	}

	if ((*skb->data & ~AX25_PF) == AX25_SABME) {
		ax25->modulus = AX25_EMODULUS;
		ax25->window  = ax25_dev->values[AX25_VALUES_EWINDOW];
	} else {
		ax25->modulus = AX25_MODULUS;
		ax25->window  = ax25_dev->values[AX25_VALUES_WINDOW];
	}

	ax25_send_control(ax25, AX25_UA, AX25_POLLON, AX25_RESPONSE);

#ifdef CONFIG_AX25_DAMA_SLAVE
	if (dama && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
		ax25_dama_on(ax25);
#endif

	ax25->state = AX25_STATE_3;

	ax25_cb_add(ax25);

	ax25_start_heartbeat(ax25);
	ax25_start_t3timer(ax25);
	ax25_start_idletimer(ax25);

	if (sk) {
		if (!sock_flag(sk, SOCK_DEAD))
			sk->sk_data_ready(sk, skb->len);
		sock_put(sk);
	} else
		kfree_skb(skb);

	return 0;
}
Example #30
0
/*
 *	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;
    int i, res = 0;

    spin_lock_bh(&rose_node_list_lock);
    spin_lock_bh(&rose_neigh_list_lock);

    rose_node = rose_node_list;
    while (rose_node != NULL) {
        if ((rose_node->mask == rose_route->mask) &&
                (rosecmpm(&rose_route->address, &rose_node->address,
                          rose_route->mask) == 0))
            break;
        rose_node = rose_node->next;
    }

    if (rose_node != NULL && rose_node->loopback) {
        res = -EINVAL;
        goto out;
    }

    rose_neigh = rose_neigh_list;
    while (rose_neigh != NULL) {
        if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0
                && rose_neigh->dev == dev)
            break;
        rose_neigh = rose_neigh->next;
    }

    if (rose_neigh == NULL) {
        rose_neigh = kmalloc(sizeof(*rose_neigh), GFP_ATOMIC);
        if (rose_neigh == NULL) {
            res = -ENOMEM;
            goto out;
        }

        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);
                res = -ENOMEM;
                goto out;
            }

            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;
            }
        }

        rose_neigh->next = rose_neigh_list;
        rose_neigh_list  = rose_neigh;
    }

    /*
     * 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 */
        rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC);
        if (rose_node == NULL) {
            res = -ENOMEM;
            goto out;
        }

        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;

        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;
            }
        }
        rose_neigh->count++;

        goto out;
    }

    /* 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++;
    }

out:
    spin_unlock_bh(&rose_neigh_list_lock);
    spin_unlock_bh(&rose_node_list_lock);

    return res;
}