Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *
0004  * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
0005  */
0006 #include <linux/errno.h>
0007 #include <linux/types.h>
0008 #include <linux/socket.h>
0009 #include <linux/in.h>
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/spinlock.h>
0013 #include <linux/timer.h>
0014 #include <linux/string.h>
0015 #include <linux/sockios.h>
0016 #include <linux/net.h>
0017 #include <linux/slab.h>
0018 #include <net/ax25.h>
0019 #include <linux/inet.h>
0020 #include <linux/netdevice.h>
0021 #include <linux/skbuff.h>
0022 #include <net/sock.h>
0023 #include <linux/uaccess.h>
0024 #include <linux/fcntl.h>
0025 #include <linux/mm.h>
0026 #include <linux/interrupt.h>
0027 
0028 static struct ax25_protocol *protocol_list;
0029 static DEFINE_RWLOCK(protocol_list_lock);
0030 
0031 static HLIST_HEAD(ax25_linkfail_list);
0032 static DEFINE_SPINLOCK(linkfail_lock);
0033 
0034 static struct listen_struct {
0035     struct listen_struct *next;
0036     ax25_address  callsign;
0037     struct net_device *dev;
0038 } *listen_list = NULL;
0039 static DEFINE_SPINLOCK(listen_lock);
0040 
0041 /*
0042  * Do not register the internal protocols AX25_P_TEXT, AX25_P_SEGMENT,
0043  * AX25_P_IP or AX25_P_ARP ...
0044  */
0045 void ax25_register_pid(struct ax25_protocol *ap)
0046 {
0047     write_lock_bh(&protocol_list_lock);
0048     ap->next = protocol_list;
0049     protocol_list = ap;
0050     write_unlock_bh(&protocol_list_lock);
0051 }
0052 
0053 EXPORT_SYMBOL_GPL(ax25_register_pid);
0054 
0055 void ax25_protocol_release(unsigned int pid)
0056 {
0057     struct ax25_protocol *protocol;
0058 
0059     write_lock_bh(&protocol_list_lock);
0060     protocol = protocol_list;
0061     if (protocol == NULL)
0062         goto out;
0063 
0064     if (protocol->pid == pid) {
0065         protocol_list = protocol->next;
0066         goto out;
0067     }
0068 
0069     while (protocol != NULL && protocol->next != NULL) {
0070         if (protocol->next->pid == pid) {
0071             protocol->next = protocol->next->next;
0072             goto out;
0073         }
0074 
0075         protocol = protocol->next;
0076     }
0077 out:
0078     write_unlock_bh(&protocol_list_lock);
0079 }
0080 
0081 EXPORT_SYMBOL(ax25_protocol_release);
0082 
0083 void ax25_linkfail_register(struct ax25_linkfail *lf)
0084 {
0085     spin_lock_bh(&linkfail_lock);
0086     hlist_add_head(&lf->lf_node, &ax25_linkfail_list);
0087     spin_unlock_bh(&linkfail_lock);
0088 }
0089 
0090 EXPORT_SYMBOL(ax25_linkfail_register);
0091 
0092 void ax25_linkfail_release(struct ax25_linkfail *lf)
0093 {
0094     spin_lock_bh(&linkfail_lock);
0095     hlist_del_init(&lf->lf_node);
0096     spin_unlock_bh(&linkfail_lock);
0097 }
0098 
0099 EXPORT_SYMBOL(ax25_linkfail_release);
0100 
0101 int ax25_listen_register(const ax25_address *callsign, struct net_device *dev)
0102 {
0103     struct listen_struct *listen;
0104 
0105     if (ax25_listen_mine(callsign, dev))
0106         return 0;
0107 
0108     if ((listen = kmalloc(sizeof(*listen), GFP_ATOMIC)) == NULL)
0109         return -ENOMEM;
0110 
0111     listen->callsign = *callsign;
0112     listen->dev      = dev;
0113 
0114     spin_lock_bh(&listen_lock);
0115     listen->next = listen_list;
0116     listen_list  = listen;
0117     spin_unlock_bh(&listen_lock);
0118 
0119     return 0;
0120 }
0121 
0122 EXPORT_SYMBOL(ax25_listen_register);
0123 
0124 void ax25_listen_release(const ax25_address *callsign, struct net_device *dev)
0125 {
0126     struct listen_struct *s, *listen;
0127 
0128     spin_lock_bh(&listen_lock);
0129     listen = listen_list;
0130     if (listen == NULL) {
0131         spin_unlock_bh(&listen_lock);
0132         return;
0133     }
0134 
0135     if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) {
0136         listen_list = listen->next;
0137         spin_unlock_bh(&listen_lock);
0138         kfree(listen);
0139         return;
0140     }
0141 
0142     while (listen != NULL && listen->next != NULL) {
0143         if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) {
0144             s = listen->next;
0145             listen->next = listen->next->next;
0146             spin_unlock_bh(&listen_lock);
0147             kfree(s);
0148             return;
0149         }
0150 
0151         listen = listen->next;
0152     }
0153     spin_unlock_bh(&listen_lock);
0154 }
0155 
0156 EXPORT_SYMBOL(ax25_listen_release);
0157 
0158 int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *)
0159 {
0160     int (*res)(struct sk_buff *, ax25_cb *) = NULL;
0161     struct ax25_protocol *protocol;
0162 
0163     read_lock(&protocol_list_lock);
0164     for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
0165         if (protocol->pid == pid) {
0166             res = protocol->func;
0167             break;
0168         }
0169     read_unlock(&protocol_list_lock);
0170 
0171     return res;
0172 }
0173 
0174 int ax25_listen_mine(const ax25_address *callsign, struct net_device *dev)
0175 {
0176     struct listen_struct *listen;
0177 
0178     spin_lock_bh(&listen_lock);
0179     for (listen = listen_list; listen != NULL; listen = listen->next)
0180         if (ax25cmp(&listen->callsign, callsign) == 0 &&
0181             (listen->dev == dev || listen->dev == NULL)) {
0182             spin_unlock_bh(&listen_lock);
0183             return 1;
0184     }
0185     spin_unlock_bh(&listen_lock);
0186 
0187     return 0;
0188 }
0189 
0190 void ax25_link_failed(ax25_cb *ax25, int reason)
0191 {
0192     struct ax25_linkfail *lf;
0193 
0194     spin_lock_bh(&linkfail_lock);
0195     hlist_for_each_entry(lf, &ax25_linkfail_list, lf_node)
0196         lf->func(ax25, reason);
0197     spin_unlock_bh(&linkfail_lock);
0198 }
0199 
0200 int ax25_protocol_is_registered(unsigned int pid)
0201 {
0202     struct ax25_protocol *protocol;
0203     int res = 0;
0204 
0205     read_lock_bh(&protocol_list_lock);
0206     for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
0207         if (protocol->pid == pid) {
0208             res = 1;
0209             break;
0210         }
0211     read_unlock_bh(&protocol_list_lock);
0212 
0213     return res;
0214 }