11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/socket.h>
125a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sockios.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/net.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/ax25.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/inet.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/sock.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsax25_dev *ax25_dev_list;
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsDEFINE_SPINLOCK(ax25_dev_lock);
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsax25_dev *ax25_addr_ax25dev(ax25_address *addr)
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev *ax25_dev, *res = NULL;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_bh(&ax25_dev_lock);
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) {
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			res = ax25_dev;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_bh(&ax25_dev_lock);
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	This is called when an interface is brought up. These are
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	reasonable defaults.
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ax25_dev_device_up(struct net_device *dev)
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev *ax25_dev;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571b30dd359ebec22d035e8b145751319f63772ca1Ralf Baechle	if ((ax25_dev = kzalloc(sizeof(*ax25_dev), GFP_ATOMIC)) == NULL) {
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "AX.25: ax25_dev_device_up - out of memory\n");
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->ax25_ptr     = ax25_dev;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->dev     = dev;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_hold(dev);
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->forward = NULL;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_AXDEFMODE] = AX25_DEF_AXDEFMODE;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_BACKOFF]   = AX25_DEF_BACKOFF;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_CONMODE]   = AX25_DEF_CONMODE;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_WINDOW]    = AX25_DEF_WINDOW;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_EWINDOW]   = AX25_DEF_EWINDOW;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_T1]        = AX25_DEF_T1;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_T2]        = AX25_DEF_T2;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_T3]        = AX25_DEF_T3;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_IDLE]	= AX25_DEF_IDLE;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_N2]        = AX25_DEF_N2;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_PACLEN]	= AX25_DEF_PACLEN;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_PROTOCOL]  = AX25_DEF_PROTOCOL;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER)
83e848b583e03306f5f9b3a66a793c37e3649e04caJarek Poplawski	ax25_ds_setup_timer(ax25_dev);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_bh(&ax25_dev_lock);
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev->next = ax25_dev_list;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev_list  = ax25_dev;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_bh(&ax25_dev_lock);
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
910ca7a4c87d27dd2fde0783dec94a821d6d035696Eric W. Biederman	ax25_register_dev_sysctl(ax25_dev);
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ax25_dev_device_down(struct net_device *dev)
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev *s, *ax25_dev;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1010ca7a4c87d27dd2fde0783dec94a821d6d035696Eric W. Biederman	ax25_unregister_dev_sysctl(ax25_dev);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_bh(&ax25_dev_lock);
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_AX25_DAMA_SLAVE
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_ds_del_timer(ax25_dev);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	Remove any packet forwarding that points to this device.
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (s = ax25_dev_list; s != NULL; s = s->next)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (s->forward == dev)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			s->forward = NULL;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((s = ax25_dev_list) == ax25_dev) {
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ax25_dev_list = s->next;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_bh(&ax25_dev_lock);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_put(dev);
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(ax25_dev);
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (s != NULL && s->next != NULL) {
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (s->next == ax25_dev) {
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			s->next = ax25_dev->next;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock_bh(&ax25_dev_lock);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_put(dev);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(ax25_dev);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		s = s->next;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_bh(&ax25_dev_lock);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->ax25_ptr = NULL;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev *ax25_dev, *fwd_dev;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ax25_dev = ax25_addr_ax25dev(&fwd->port_from)) == NULL)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SIOCAX25ADDFWD:
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ax25_dev->forward != NULL)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ax25_dev->forward = fwd_dev->dev;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SIOCAX25DELFWD:
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ax25_dev->forward == NULL)
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ax25_dev->forward = NULL;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct net_device *ax25_fwd_dev(struct net_device *dev)
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev *ax25_dev;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return dev;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ax25_dev->forward == NULL)
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return dev;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ax25_dev->forward;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Free all memory associated with device structures.
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __exit ax25_dev_free(void)
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev *s, *ax25_dev;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_bh(&ax25_dev_lock);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev = ax25_dev_list;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (ax25_dev != NULL) {
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		s        = ax25_dev;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_put(ax25_dev->dev);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ax25_dev = ax25_dev->next;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(s);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev_list = NULL;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_bh(&ax25_dev_lock);
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
199