cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ax25_route.c (11036B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *
      4 * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
      5 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
      6 * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
      7 * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
      8 * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
      9 * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
     10 */
     11
     12#include <linux/capability.h>
     13#include <linux/errno.h>
     14#include <linux/types.h>
     15#include <linux/socket.h>
     16#include <linux/timer.h>
     17#include <linux/in.h>
     18#include <linux/kernel.h>
     19#include <linux/sched.h>
     20#include <linux/string.h>
     21#include <linux/sockios.h>
     22#include <linux/net.h>
     23#include <linux/slab.h>
     24#include <net/ax25.h>
     25#include <linux/inet.h>
     26#include <linux/netdevice.h>
     27#include <linux/if_arp.h>
     28#include <linux/skbuff.h>
     29#include <linux/spinlock.h>
     30#include <net/sock.h>
     31#include <linux/uaccess.h>
     32#include <linux/fcntl.h>
     33#include <linux/mm.h>
     34#include <linux/interrupt.h>
     35#include <linux/init.h>
     36#include <linux/seq_file.h>
     37#include <linux/export.h>
     38
     39static ax25_route *ax25_route_list;
     40DEFINE_RWLOCK(ax25_route_lock);
     41
     42void ax25_rt_device_down(struct net_device *dev)
     43{
     44	ax25_route *s, *t, *ax25_rt;
     45
     46	write_lock_bh(&ax25_route_lock);
     47	ax25_rt = ax25_route_list;
     48	while (ax25_rt != NULL) {
     49		s       = ax25_rt;
     50		ax25_rt = ax25_rt->next;
     51
     52		if (s->dev == dev) {
     53			if (ax25_route_list == s) {
     54				ax25_route_list = s->next;
     55				kfree(s->digipeat);
     56				kfree(s);
     57			} else {
     58				for (t = ax25_route_list; t != NULL; t = t->next) {
     59					if (t->next == s) {
     60						t->next = s->next;
     61						kfree(s->digipeat);
     62						kfree(s);
     63						break;
     64					}
     65				}
     66			}
     67		}
     68	}
     69	write_unlock_bh(&ax25_route_lock);
     70}
     71
     72static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
     73{
     74	ax25_route *ax25_rt;
     75	ax25_dev *ax25_dev;
     76	int i;
     77
     78	if (route->digi_count > AX25_MAX_DIGIS)
     79		return -EINVAL;
     80
     81	ax25_dev = ax25_addr_ax25dev(&route->port_addr);
     82	if (!ax25_dev)
     83		return -EINVAL;
     84
     85	write_lock_bh(&ax25_route_lock);
     86
     87	ax25_rt = ax25_route_list;
     88	while (ax25_rt != NULL) {
     89		if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 &&
     90			    ax25_rt->dev == ax25_dev->dev) {
     91			kfree(ax25_rt->digipeat);
     92			ax25_rt->digipeat = NULL;
     93			if (route->digi_count != 0) {
     94				if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
     95					write_unlock_bh(&ax25_route_lock);
     96					ax25_dev_put(ax25_dev);
     97					return -ENOMEM;
     98				}
     99				ax25_rt->digipeat->lastrepeat = -1;
    100				ax25_rt->digipeat->ndigi      = route->digi_count;
    101				for (i = 0; i < route->digi_count; i++) {
    102					ax25_rt->digipeat->repeated[i] = 0;
    103					ax25_rt->digipeat->calls[i]    = route->digi_addr[i];
    104				}
    105			}
    106			write_unlock_bh(&ax25_route_lock);
    107			ax25_dev_put(ax25_dev);
    108			return 0;
    109		}
    110		ax25_rt = ax25_rt->next;
    111	}
    112
    113	if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
    114		write_unlock_bh(&ax25_route_lock);
    115		ax25_dev_put(ax25_dev);
    116		return -ENOMEM;
    117	}
    118
    119	ax25_rt->callsign     = route->dest_addr;
    120	ax25_rt->dev          = ax25_dev->dev;
    121	ax25_rt->digipeat     = NULL;
    122	ax25_rt->ip_mode      = ' ';
    123	if (route->digi_count != 0) {
    124		if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
    125			write_unlock_bh(&ax25_route_lock);
    126			kfree(ax25_rt);
    127			ax25_dev_put(ax25_dev);
    128			return -ENOMEM;
    129		}
    130		ax25_rt->digipeat->lastrepeat = -1;
    131		ax25_rt->digipeat->ndigi      = route->digi_count;
    132		for (i = 0; i < route->digi_count; i++) {
    133			ax25_rt->digipeat->repeated[i] = 0;
    134			ax25_rt->digipeat->calls[i]    = route->digi_addr[i];
    135		}
    136	}
    137	ax25_rt->next   = ax25_route_list;
    138	ax25_route_list = ax25_rt;
    139	write_unlock_bh(&ax25_route_lock);
    140	ax25_dev_put(ax25_dev);
    141
    142	return 0;
    143}
    144
    145void __ax25_put_route(ax25_route *ax25_rt)
    146{
    147	kfree(ax25_rt->digipeat);
    148	kfree(ax25_rt);
    149}
    150
    151static int ax25_rt_del(struct ax25_routes_struct *route)
    152{
    153	ax25_route *s, *t, *ax25_rt;
    154	ax25_dev *ax25_dev;
    155
    156	if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
    157		return -EINVAL;
    158
    159	write_lock_bh(&ax25_route_lock);
    160
    161	ax25_rt = ax25_route_list;
    162	while (ax25_rt != NULL) {
    163		s       = ax25_rt;
    164		ax25_rt = ax25_rt->next;
    165		if (s->dev == ax25_dev->dev &&
    166		    ax25cmp(&route->dest_addr, &s->callsign) == 0) {
    167			if (ax25_route_list == s) {
    168				ax25_route_list = s->next;
    169				__ax25_put_route(s);
    170			} else {
    171				for (t = ax25_route_list; t != NULL; t = t->next) {
    172					if (t->next == s) {
    173						t->next = s->next;
    174						__ax25_put_route(s);
    175						break;
    176					}
    177				}
    178			}
    179		}
    180	}
    181	write_unlock_bh(&ax25_route_lock);
    182	ax25_dev_put(ax25_dev);
    183
    184	return 0;
    185}
    186
    187static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
    188{
    189	ax25_route *ax25_rt;
    190	ax25_dev *ax25_dev;
    191	int err = 0;
    192
    193	if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL)
    194		return -EINVAL;
    195
    196	write_lock_bh(&ax25_route_lock);
    197
    198	ax25_rt = ax25_route_list;
    199	while (ax25_rt != NULL) {
    200		if (ax25_rt->dev == ax25_dev->dev &&
    201		    ax25cmp(&rt_option->dest_addr, &ax25_rt->callsign) == 0) {
    202			switch (rt_option->cmd) {
    203			case AX25_SET_RT_IPMODE:
    204				switch (rt_option->arg) {
    205				case ' ':
    206				case 'D':
    207				case 'V':
    208					ax25_rt->ip_mode = rt_option->arg;
    209					break;
    210				default:
    211					err = -EINVAL;
    212					goto out;
    213				}
    214				break;
    215			default:
    216				err = -EINVAL;
    217				goto out;
    218			}
    219		}
    220		ax25_rt = ax25_rt->next;
    221	}
    222
    223out:
    224	write_unlock_bh(&ax25_route_lock);
    225	ax25_dev_put(ax25_dev);
    226	return err;
    227}
    228
    229int ax25_rt_ioctl(unsigned int cmd, void __user *arg)
    230{
    231	struct ax25_route_opt_struct rt_option;
    232	struct ax25_routes_struct route;
    233
    234	switch (cmd) {
    235	case SIOCADDRT:
    236		if (copy_from_user(&route, arg, sizeof(route)))
    237			return -EFAULT;
    238		return ax25_rt_add(&route);
    239
    240	case SIOCDELRT:
    241		if (copy_from_user(&route, arg, sizeof(route)))
    242			return -EFAULT;
    243		return ax25_rt_del(&route);
    244
    245	case SIOCAX25OPTRT:
    246		if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
    247			return -EFAULT;
    248		return ax25_rt_opt(&rt_option);
    249
    250	default:
    251		return -EINVAL;
    252	}
    253}
    254
    255#ifdef CONFIG_PROC_FS
    256
    257static void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos)
    258	__acquires(ax25_route_lock)
    259{
    260	struct ax25_route *ax25_rt;
    261	int i = 1;
    262
    263	read_lock(&ax25_route_lock);
    264	if (*pos == 0)
    265		return SEQ_START_TOKEN;
    266
    267	for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
    268		if (i == *pos)
    269			return ax25_rt;
    270		++i;
    271	}
    272
    273	return NULL;
    274}
    275
    276static void *ax25_rt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
    277{
    278	++*pos;
    279	return (v == SEQ_START_TOKEN) ? ax25_route_list :
    280		((struct ax25_route *) v)->next;
    281}
    282
    283static void ax25_rt_seq_stop(struct seq_file *seq, void *v)
    284	__releases(ax25_route_lock)
    285{
    286	read_unlock(&ax25_route_lock);
    287}
    288
    289static int ax25_rt_seq_show(struct seq_file *seq, void *v)
    290{
    291	char buf[11];
    292
    293	if (v == SEQ_START_TOKEN)
    294		seq_puts(seq, "callsign  dev  mode digipeaters\n");
    295	else {
    296		struct ax25_route *ax25_rt = v;
    297		const char *callsign;
    298		int i;
    299
    300		if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
    301			callsign = "default";
    302		else
    303			callsign = ax2asc(buf, &ax25_rt->callsign);
    304
    305		seq_printf(seq, "%-9s %-4s",
    306			callsign,
    307			ax25_rt->dev ? ax25_rt->dev->name : "???");
    308
    309		switch (ax25_rt->ip_mode) {
    310		case 'V':
    311			seq_puts(seq, "   vc");
    312			break;
    313		case 'D':
    314			seq_puts(seq, "   dg");
    315			break;
    316		default:
    317			seq_puts(seq, "    *");
    318			break;
    319		}
    320
    321		if (ax25_rt->digipeat != NULL)
    322			for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
    323				seq_printf(seq, " %s",
    324				     ax2asc(buf, &ax25_rt->digipeat->calls[i]));
    325
    326		seq_puts(seq, "\n");
    327	}
    328	return 0;
    329}
    330
    331const struct seq_operations ax25_rt_seqops = {
    332	.start = ax25_rt_seq_start,
    333	.next = ax25_rt_seq_next,
    334	.stop = ax25_rt_seq_stop,
    335	.show = ax25_rt_seq_show,
    336};
    337#endif
    338
    339/*
    340 *	Find AX.25 route
    341 *
    342 *	Only routes with a reference count of zero can be destroyed.
    343 *	Must be called with ax25_route_lock read locked.
    344 */
    345ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
    346{
    347	ax25_route *ax25_spe_rt = NULL;
    348	ax25_route *ax25_def_rt = NULL;
    349	ax25_route *ax25_rt;
    350
    351	/*
    352	 *	Bind to the physical interface we heard them on, or the default
    353	 *	route if none is found;
    354	 */
    355	for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
    356		if (dev == NULL) {
    357			if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
    358				ax25_spe_rt = ax25_rt;
    359			if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
    360				ax25_def_rt = ax25_rt;
    361		} else {
    362			if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev)
    363				ax25_spe_rt = ax25_rt;
    364			if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev == dev)
    365				ax25_def_rt = ax25_rt;
    366		}
    367	}
    368
    369	ax25_rt = ax25_def_rt;
    370	if (ax25_spe_rt != NULL)
    371		ax25_rt = ax25_spe_rt;
    372
    373	return ax25_rt;
    374}
    375
    376/*
    377 *	Adjust path: If you specify a default route and want to connect
    378 *      a target on the digipeater path but w/o having a special route
    379 *	set before, the path has to be truncated from your target on.
    380 */
    381static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
    382{
    383	int k;
    384
    385	for (k = 0; k < digipeat->ndigi; k++) {
    386		if (ax25cmp(addr, &digipeat->calls[k]) == 0)
    387			break;
    388	}
    389
    390	digipeat->ndigi = k;
    391}
    392
    393
    394/*
    395 *	Find which interface to use.
    396 */
    397int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
    398{
    399	ax25_uid_assoc *user;
    400	ax25_route *ax25_rt;
    401	int err = 0;
    402
    403	ax25_route_lock_use();
    404	ax25_rt = ax25_get_route(addr, NULL);
    405	if (!ax25_rt) {
    406		ax25_route_lock_unuse();
    407		return -EHOSTUNREACH;
    408	}
    409	if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) {
    410		err = -EHOSTUNREACH;
    411		goto put;
    412	}
    413
    414	user = ax25_findbyuid(current_euid());
    415	if (user) {
    416		ax25->source_addr = user->call;
    417		ax25_uid_put(user);
    418	} else {
    419		if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
    420			err = -EPERM;
    421			goto put;
    422		}
    423		ax25->source_addr = *(ax25_address *)ax25->ax25_dev->dev->dev_addr;
    424	}
    425
    426	if (ax25_rt->digipeat != NULL) {
    427		ax25->digipeat = kmemdup(ax25_rt->digipeat, sizeof(ax25_digi),
    428					 GFP_ATOMIC);
    429		if (ax25->digipeat == NULL) {
    430			err = -ENOMEM;
    431			goto put;
    432		}
    433		ax25_adjust_path(addr, ax25->digipeat);
    434	}
    435
    436	if (ax25->sk != NULL) {
    437		local_bh_disable();
    438		bh_lock_sock(ax25->sk);
    439		sock_reset_flag(ax25->sk, SOCK_ZAPPED);
    440		bh_unlock_sock(ax25->sk);
    441		local_bh_enable();
    442	}
    443
    444put:
    445	ax25_route_lock_unuse();
    446	return err;
    447}
    448
    449struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
    450	ax25_address *dest, ax25_digi *digi)
    451{
    452	unsigned char *bp;
    453	int len;
    454
    455	len = digi->ndigi * AX25_ADDR_LEN;
    456
    457	if (unlikely(skb_headroom(skb) < len)) {
    458		skb = skb_expand_head(skb, len);
    459		if (!skb) {
    460			printk(KERN_CRIT "AX.25: ax25_dg_build_path - out of memory\n");
    461			return NULL;
    462		}
    463	}
    464
    465	bp = skb_push(skb, len);
    466
    467	ax25_addr_build(bp, src, dest, digi, AX25_COMMAND, AX25_MODULUS);
    468
    469	return skb;
    470}
    471
    472/*
    473 *	Free all memory associated with routing structures.
    474 */
    475void __exit ax25_rt_free(void)
    476{
    477	ax25_route *s, *ax25_rt = ax25_route_list;
    478
    479	write_lock_bh(&ax25_route_lock);
    480	while (ax25_rt != NULL) {
    481		s       = ax25_rt;
    482		ax25_rt = ax25_rt->next;
    483
    484		kfree(s->digipeat);
    485		kfree(s);
    486	}
    487	write_unlock_bh(&ax25_route_lock);
    488}