162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/errno.h> 762306a36Sopenharmony_ci#include <linux/types.h> 862306a36Sopenharmony_ci#include <linux/socket.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/in.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/timer.h> 1362306a36Sopenharmony_ci#include <linux/string.h> 1462306a36Sopenharmony_ci#include <linux/sockios.h> 1562306a36Sopenharmony_ci#include <linux/net.h> 1662306a36Sopenharmony_ci#include <linux/spinlock.h> 1762306a36Sopenharmony_ci#include <net/ax25.h> 1862306a36Sopenharmony_ci#include <linux/inet.h> 1962306a36Sopenharmony_ci#include <linux/netdevice.h> 2062306a36Sopenharmony_ci#include <linux/if_arp.h> 2162306a36Sopenharmony_ci#include <linux/skbuff.h> 2262306a36Sopenharmony_ci#include <net/sock.h> 2362306a36Sopenharmony_ci#include <linux/uaccess.h> 2462306a36Sopenharmony_ci#include <linux/fcntl.h> 2562306a36Sopenharmony_ci#include <linux/mm.h> 2662306a36Sopenharmony_ci#include <linux/interrupt.h> 2762306a36Sopenharmony_ci#include <linux/init.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ciax25_dev *ax25_dev_list; 3062306a36Sopenharmony_ciDEFINE_SPINLOCK(ax25_dev_lock); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ciax25_dev *ax25_addr_ax25dev(ax25_address *addr) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci ax25_dev *ax25_dev, *res = NULL; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci spin_lock_bh(&ax25_dev_lock); 3762306a36Sopenharmony_ci for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) 3862306a36Sopenharmony_ci if (ax25cmp(addr, (const ax25_address *)ax25_dev->dev->dev_addr) == 0) { 3962306a36Sopenharmony_ci res = ax25_dev; 4062306a36Sopenharmony_ci ax25_dev_hold(ax25_dev); 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci spin_unlock_bh(&ax25_dev_lock); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return res; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * This is called when an interface is brought up. These are 4962306a36Sopenharmony_ci * reasonable defaults. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_civoid ax25_dev_device_up(struct net_device *dev) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci ax25_dev *ax25_dev; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci ax25_dev = kzalloc(sizeof(*ax25_dev), GFP_KERNEL); 5662306a36Sopenharmony_ci if (!ax25_dev) { 5762306a36Sopenharmony_ci printk(KERN_ERR "AX.25: ax25_dev_device_up - out of memory\n"); 5862306a36Sopenharmony_ci return; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci refcount_set(&ax25_dev->refcount, 1); 6262306a36Sopenharmony_ci dev->ax25_ptr = ax25_dev; 6362306a36Sopenharmony_ci ax25_dev->dev = dev; 6462306a36Sopenharmony_ci netdev_hold(dev, &ax25_dev->dev_tracker, GFP_KERNEL); 6562306a36Sopenharmony_ci ax25_dev->forward = NULL; 6662306a36Sopenharmony_ci ax25_dev->device_up = true; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE; 6962306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_AXDEFMODE] = AX25_DEF_AXDEFMODE; 7062306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_BACKOFF] = AX25_DEF_BACKOFF; 7162306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_CONMODE] = AX25_DEF_CONMODE; 7262306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_WINDOW] = AX25_DEF_WINDOW; 7362306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_EWINDOW] = AX25_DEF_EWINDOW; 7462306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_T1] = AX25_DEF_T1; 7562306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_T2] = AX25_DEF_T2; 7662306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_T3] = AX25_DEF_T3; 7762306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_IDLE] = AX25_DEF_IDLE; 7862306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_N2] = AX25_DEF_N2; 7962306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_PACLEN] = AX25_DEF_PACLEN; 8062306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_DEF_PROTOCOL; 8162306a36Sopenharmony_ci ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER) 8462306a36Sopenharmony_ci ax25_ds_setup_timer(ax25_dev); 8562306a36Sopenharmony_ci#endif 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci spin_lock_bh(&ax25_dev_lock); 8862306a36Sopenharmony_ci ax25_dev->next = ax25_dev_list; 8962306a36Sopenharmony_ci ax25_dev_list = ax25_dev; 9062306a36Sopenharmony_ci spin_unlock_bh(&ax25_dev_lock); 9162306a36Sopenharmony_ci ax25_dev_hold(ax25_dev); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci ax25_register_dev_sysctl(ax25_dev); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_civoid ax25_dev_device_down(struct net_device *dev) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci ax25_dev *s, *ax25_dev; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) 10162306a36Sopenharmony_ci return; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci ax25_unregister_dev_sysctl(ax25_dev); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci spin_lock_bh(&ax25_dev_lock); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#ifdef CONFIG_AX25_DAMA_SLAVE 10862306a36Sopenharmony_ci ax25_ds_del_timer(ax25_dev); 10962306a36Sopenharmony_ci#endif 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* 11262306a36Sopenharmony_ci * Remove any packet forwarding that points to this device. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ci for (s = ax25_dev_list; s != NULL; s = s->next) 11562306a36Sopenharmony_ci if (s->forward == dev) 11662306a36Sopenharmony_ci s->forward = NULL; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if ((s = ax25_dev_list) == ax25_dev) { 11962306a36Sopenharmony_ci ax25_dev_list = s->next; 12062306a36Sopenharmony_ci goto unlock_put; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci while (s != NULL && s->next != NULL) { 12462306a36Sopenharmony_ci if (s->next == ax25_dev) { 12562306a36Sopenharmony_ci s->next = ax25_dev->next; 12662306a36Sopenharmony_ci goto unlock_put; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci s = s->next; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci spin_unlock_bh(&ax25_dev_lock); 13262306a36Sopenharmony_ci dev->ax25_ptr = NULL; 13362306a36Sopenharmony_ci ax25_dev_put(ax25_dev); 13462306a36Sopenharmony_ci return; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ciunlock_put: 13762306a36Sopenharmony_ci spin_unlock_bh(&ax25_dev_lock); 13862306a36Sopenharmony_ci ax25_dev_put(ax25_dev); 13962306a36Sopenharmony_ci dev->ax25_ptr = NULL; 14062306a36Sopenharmony_ci netdev_put(dev, &ax25_dev->dev_tracker); 14162306a36Sopenharmony_ci ax25_dev_put(ax25_dev); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ciint ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci ax25_dev *ax25_dev, *fwd_dev; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if ((ax25_dev = ax25_addr_ax25dev(&fwd->port_from)) == NULL) 14962306a36Sopenharmony_ci return -EINVAL; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci switch (cmd) { 15262306a36Sopenharmony_ci case SIOCAX25ADDFWD: 15362306a36Sopenharmony_ci fwd_dev = ax25_addr_ax25dev(&fwd->port_to); 15462306a36Sopenharmony_ci if (!fwd_dev) { 15562306a36Sopenharmony_ci ax25_dev_put(ax25_dev); 15662306a36Sopenharmony_ci return -EINVAL; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci if (ax25_dev->forward) { 15962306a36Sopenharmony_ci ax25_dev_put(fwd_dev); 16062306a36Sopenharmony_ci ax25_dev_put(ax25_dev); 16162306a36Sopenharmony_ci return -EINVAL; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci ax25_dev->forward = fwd_dev->dev; 16462306a36Sopenharmony_ci ax25_dev_put(fwd_dev); 16562306a36Sopenharmony_ci ax25_dev_put(ax25_dev); 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci case SIOCAX25DELFWD: 16962306a36Sopenharmony_ci if (!ax25_dev->forward) { 17062306a36Sopenharmony_ci ax25_dev_put(ax25_dev); 17162306a36Sopenharmony_ci return -EINVAL; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci ax25_dev->forward = NULL; 17462306a36Sopenharmony_ci ax25_dev_put(ax25_dev); 17562306a36Sopenharmony_ci break; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci default: 17862306a36Sopenharmony_ci ax25_dev_put(ax25_dev); 17962306a36Sopenharmony_ci return -EINVAL; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return 0; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistruct net_device *ax25_fwd_dev(struct net_device *dev) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci ax25_dev *ax25_dev; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) 19062306a36Sopenharmony_ci return dev; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (ax25_dev->forward == NULL) 19362306a36Sopenharmony_ci return dev; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return ax25_dev->forward; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci/* 19962306a36Sopenharmony_ci * Free all memory associated with device structures. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_civoid __exit ax25_dev_free(void) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci ax25_dev *s, *ax25_dev; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci spin_lock_bh(&ax25_dev_lock); 20662306a36Sopenharmony_ci ax25_dev = ax25_dev_list; 20762306a36Sopenharmony_ci while (ax25_dev != NULL) { 20862306a36Sopenharmony_ci s = ax25_dev; 20962306a36Sopenharmony_ci netdev_put(ax25_dev->dev, &ax25_dev->dev_tracker); 21062306a36Sopenharmony_ci ax25_dev = ax25_dev->next; 21162306a36Sopenharmony_ci kfree(s); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci ax25_dev_list = NULL; 21462306a36Sopenharmony_ci spin_unlock_bh(&ax25_dev_lock); 21562306a36Sopenharmony_ci} 216