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/in.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/spinlock.h> 1362306a36Sopenharmony_ci#include <linux/timer.h> 1462306a36Sopenharmony_ci#include <linux/string.h> 1562306a36Sopenharmony_ci#include <linux/sockios.h> 1662306a36Sopenharmony_ci#include <linux/net.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <net/ax25.h> 1962306a36Sopenharmony_ci#include <linux/inet.h> 2062306a36Sopenharmony_ci#include <linux/netdevice.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 2862306a36Sopenharmony_cistatic struct ax25_protocol *protocol_list; 2962306a36Sopenharmony_cistatic DEFINE_RWLOCK(protocol_list_lock); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic HLIST_HEAD(ax25_linkfail_list); 3262306a36Sopenharmony_cistatic DEFINE_SPINLOCK(linkfail_lock); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic struct listen_struct { 3562306a36Sopenharmony_ci struct listen_struct *next; 3662306a36Sopenharmony_ci ax25_address callsign; 3762306a36Sopenharmony_ci struct net_device *dev; 3862306a36Sopenharmony_ci} *listen_list = NULL; 3962306a36Sopenharmony_cistatic DEFINE_SPINLOCK(listen_lock); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * Do not register the internal protocols AX25_P_TEXT, AX25_P_SEGMENT, 4362306a36Sopenharmony_ci * AX25_P_IP or AX25_P_ARP ... 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_civoid ax25_register_pid(struct ax25_protocol *ap) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci write_lock_bh(&protocol_list_lock); 4862306a36Sopenharmony_ci ap->next = protocol_list; 4962306a36Sopenharmony_ci protocol_list = ap; 5062306a36Sopenharmony_ci write_unlock_bh(&protocol_list_lock); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ax25_register_pid); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_civoid ax25_protocol_release(unsigned int pid) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct ax25_protocol *protocol; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci write_lock_bh(&protocol_list_lock); 6062306a36Sopenharmony_ci protocol = protocol_list; 6162306a36Sopenharmony_ci if (protocol == NULL) 6262306a36Sopenharmony_ci goto out; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (protocol->pid == pid) { 6562306a36Sopenharmony_ci protocol_list = protocol->next; 6662306a36Sopenharmony_ci goto out; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci while (protocol != NULL && protocol->next != NULL) { 7062306a36Sopenharmony_ci if (protocol->next->pid == pid) { 7162306a36Sopenharmony_ci protocol->next = protocol->next->next; 7262306a36Sopenharmony_ci goto out; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci protocol = protocol->next; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ciout: 7862306a36Sopenharmony_ci write_unlock_bh(&protocol_list_lock); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ciEXPORT_SYMBOL(ax25_protocol_release); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_civoid ax25_linkfail_register(struct ax25_linkfail *lf) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci spin_lock_bh(&linkfail_lock); 8662306a36Sopenharmony_ci hlist_add_head(&lf->lf_node, &ax25_linkfail_list); 8762306a36Sopenharmony_ci spin_unlock_bh(&linkfail_lock); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ciEXPORT_SYMBOL(ax25_linkfail_register); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_civoid ax25_linkfail_release(struct ax25_linkfail *lf) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci spin_lock_bh(&linkfail_lock); 9562306a36Sopenharmony_ci hlist_del_init(&lf->lf_node); 9662306a36Sopenharmony_ci spin_unlock_bh(&linkfail_lock); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ciEXPORT_SYMBOL(ax25_linkfail_release); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciint ax25_listen_register(const ax25_address *callsign, struct net_device *dev) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct listen_struct *listen; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (ax25_listen_mine(callsign, dev)) 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if ((listen = kmalloc(sizeof(*listen), GFP_ATOMIC)) == NULL) 10962306a36Sopenharmony_ci return -ENOMEM; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci listen->callsign = *callsign; 11262306a36Sopenharmony_ci listen->dev = dev; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci spin_lock_bh(&listen_lock); 11562306a36Sopenharmony_ci listen->next = listen_list; 11662306a36Sopenharmony_ci listen_list = listen; 11762306a36Sopenharmony_ci spin_unlock_bh(&listen_lock); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciEXPORT_SYMBOL(ax25_listen_register); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_civoid ax25_listen_release(const ax25_address *callsign, struct net_device *dev) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct listen_struct *s, *listen; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci spin_lock_bh(&listen_lock); 12962306a36Sopenharmony_ci listen = listen_list; 13062306a36Sopenharmony_ci if (listen == NULL) { 13162306a36Sopenharmony_ci spin_unlock_bh(&listen_lock); 13262306a36Sopenharmony_ci return; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) { 13662306a36Sopenharmony_ci listen_list = listen->next; 13762306a36Sopenharmony_ci spin_unlock_bh(&listen_lock); 13862306a36Sopenharmony_ci kfree(listen); 13962306a36Sopenharmony_ci return; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci while (listen != NULL && listen->next != NULL) { 14362306a36Sopenharmony_ci if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) { 14462306a36Sopenharmony_ci s = listen->next; 14562306a36Sopenharmony_ci listen->next = listen->next->next; 14662306a36Sopenharmony_ci spin_unlock_bh(&listen_lock); 14762306a36Sopenharmony_ci kfree(s); 14862306a36Sopenharmony_ci return; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci listen = listen->next; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci spin_unlock_bh(&listen_lock); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ciEXPORT_SYMBOL(ax25_listen_release); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ciint (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci int (*res)(struct sk_buff *, ax25_cb *) = NULL; 16162306a36Sopenharmony_ci struct ax25_protocol *protocol; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci read_lock(&protocol_list_lock); 16462306a36Sopenharmony_ci for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) 16562306a36Sopenharmony_ci if (protocol->pid == pid) { 16662306a36Sopenharmony_ci res = protocol->func; 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci read_unlock(&protocol_list_lock); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return res; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ciint ax25_listen_mine(const ax25_address *callsign, struct net_device *dev) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct listen_struct *listen; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci spin_lock_bh(&listen_lock); 17962306a36Sopenharmony_ci for (listen = listen_list; listen != NULL; listen = listen->next) 18062306a36Sopenharmony_ci if (ax25cmp(&listen->callsign, callsign) == 0 && 18162306a36Sopenharmony_ci (listen->dev == dev || listen->dev == NULL)) { 18262306a36Sopenharmony_ci spin_unlock_bh(&listen_lock); 18362306a36Sopenharmony_ci return 1; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci spin_unlock_bh(&listen_lock); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_civoid ax25_link_failed(ax25_cb *ax25, int reason) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct ax25_linkfail *lf; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci spin_lock_bh(&linkfail_lock); 19562306a36Sopenharmony_ci hlist_for_each_entry(lf, &ax25_linkfail_list, lf_node) 19662306a36Sopenharmony_ci lf->func(ax25, reason); 19762306a36Sopenharmony_ci spin_unlock_bh(&linkfail_lock); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ciint ax25_protocol_is_registered(unsigned int pid) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct ax25_protocol *protocol; 20362306a36Sopenharmony_ci int res = 0; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci read_lock_bh(&protocol_list_lock); 20662306a36Sopenharmony_ci for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) 20762306a36Sopenharmony_ci if (protocol->pid == pid) { 20862306a36Sopenharmony_ci res = 1; 20962306a36Sopenharmony_ci break; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci read_unlock_bh(&protocol_list_lock); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return res; 21462306a36Sopenharmony_ci} 215