linux/net/ax25/ax25_iface.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *
   4 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
   5 */
   6#include <linux/errno.h>
   7#include <linux/types.h>
   8#include <linux/socket.h>
   9#include <linux/in.h>
  10#include <linux/kernel.h>
  11#include <linux/module.h>
  12#include <linux/spinlock.h>
  13#include <linux/timer.h>
  14#include <linux/string.h>
  15#include <linux/sockios.h>
  16#include <linux/net.h>
  17#include <linux/slab.h>
  18#include <net/ax25.h>
  19#include <linux/inet.h>
  20#include <linux/netdevice.h>
  21#include <linux/skbuff.h>
  22#include <net/sock.h>
  23#include <linux/uaccess.h>
  24#include <linux/fcntl.h>
  25#include <linux/mm.h>
  26#include <linux/interrupt.h>
  27
  28static struct ax25_protocol *protocol_list;
  29static DEFINE_RWLOCK(protocol_list_lock);
  30
  31static HLIST_HEAD(ax25_linkfail_list);
  32static DEFINE_SPINLOCK(linkfail_lock);
  33
  34static struct listen_struct {
  35        struct listen_struct *next;
  36        ax25_address  callsign;
  37        struct net_device *dev;
  38} *listen_list = NULL;
  39static DEFINE_SPINLOCK(listen_lock);
  40
  41/*
  42 * Do not register the internal protocols AX25_P_TEXT, AX25_P_SEGMENT,
  43 * AX25_P_IP or AX25_P_ARP ...
  44 */
  45void ax25_register_pid(struct ax25_protocol *ap)
  46{
  47        write_lock_bh(&protocol_list_lock);
  48        ap->next = protocol_list;
  49        protocol_list = ap;
  50        write_unlock_bh(&protocol_list_lock);
  51}
  52
  53EXPORT_SYMBOL_GPL(ax25_register_pid);
  54
  55void ax25_protocol_release(unsigned int pid)
  56{
  57        struct ax25_protocol *protocol;
  58
  59        write_lock_bh(&protocol_list_lock);
  60        protocol = protocol_list;
  61        if (protocol == NULL)
  62                goto out;
  63
  64        if (protocol->pid == pid) {
  65                protocol_list = protocol->next;
  66                goto out;
  67        }
  68
  69        while (protocol != NULL && protocol->next != NULL) {
  70                if (protocol->next->pid == pid) {
  71                        protocol->next = protocol->next->next;
  72                        goto out;
  73                }
  74
  75                protocol = protocol->next;
  76        }
  77out:
  78        write_unlock_bh(&protocol_list_lock);
  79}
  80
  81EXPORT_SYMBOL(ax25_protocol_release);
  82
  83void ax25_linkfail_register(struct ax25_linkfail *lf)
  84{
  85        spin_lock_bh(&linkfail_lock);
  86        hlist_add_head(&lf->lf_node, &ax25_linkfail_list);
  87        spin_unlock_bh(&linkfail_lock);
  88}
  89
  90EXPORT_SYMBOL(ax25_linkfail_register);
  91
  92void ax25_linkfail_release(struct ax25_linkfail *lf)
  93{
  94        spin_lock_bh(&linkfail_lock);
  95        hlist_del_init(&lf->lf_node);
  96        spin_unlock_bh(&linkfail_lock);
  97}
  98
  99EXPORT_SYMBOL(ax25_linkfail_release);
 100
 101int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
 102{
 103        struct listen_struct *listen;
 104
 105        if (ax25_listen_mine(callsign, dev))
 106                return 0;
 107
 108        if ((listen = kmalloc(sizeof(*listen), GFP_ATOMIC)) == NULL)
 109                return -ENOMEM;
 110
 111        listen->callsign = *callsign;
 112        listen->dev      = dev;
 113
 114        spin_lock_bh(&listen_lock);
 115        listen->next = listen_list;
 116        listen_list  = listen;
 117        spin_unlock_bh(&listen_lock);
 118
 119        return 0;
 120}
 121
 122EXPORT_SYMBOL(ax25_listen_register);
 123
 124void ax25_listen_release(ax25_address *callsign, struct net_device *dev)
 125{
 126        struct listen_struct *s, *listen;
 127
 128        spin_lock_bh(&listen_lock);
 129        listen = listen_list;
 130        if (listen == NULL) {
 131                spin_unlock_bh(&listen_lock);
 132                return;
 133        }
 134
 135        if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) {
 136                listen_list = listen->next;
 137                spin_unlock_bh(&listen_lock);
 138                kfree(listen);
 139                return;
 140        }
 141
 142        while (listen != NULL && listen->next != NULL) {
 143                if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) {
 144                        s = listen->next;
 145                        listen->next = listen->next->next;
 146                        spin_unlock_bh(&listen_lock);
 147                        kfree(s);
 148                        return;
 149                }
 150
 151                listen = listen->next;
 152        }
 153        spin_unlock_bh(&listen_lock);
 154}
 155
 156EXPORT_SYMBOL(ax25_listen_release);
 157
 158int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *)
 159{
 160        int (*res)(struct sk_buff *, ax25_cb *) = NULL;
 161        struct ax25_protocol *protocol;
 162
 163        read_lock(&protocol_list_lock);
 164        for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
 165                if (protocol->pid == pid) {
 166                        res = protocol->func;
 167                        break;
 168                }
 169        read_unlock(&protocol_list_lock);
 170
 171        return res;
 172}
 173
 174int ax25_listen_mine(ax25_address *callsign, struct net_device *dev)
 175{
 176        struct listen_struct *listen;
 177
 178        spin_lock_bh(&listen_lock);
 179        for (listen = listen_list; listen != NULL; listen = listen->next)
 180                if (ax25cmp(&listen->callsign, callsign) == 0 &&
 181                    (listen->dev == dev || listen->dev == NULL)) {
 182                        spin_unlock_bh(&listen_lock);
 183                        return 1;
 184        }
 185        spin_unlock_bh(&listen_lock);
 186
 187        return 0;
 188}
 189
 190void ax25_link_failed(ax25_cb *ax25, int reason)
 191{
 192        struct ax25_linkfail *lf;
 193
 194        spin_lock_bh(&linkfail_lock);
 195        hlist_for_each_entry(lf, &ax25_linkfail_list, lf_node)
 196                lf->func(ax25, reason);
 197        spin_unlock_bh(&linkfail_lock);
 198}
 199
 200int ax25_protocol_is_registered(unsigned int pid)
 201{
 202        struct ax25_protocol *protocol;
 203        int res = 0;
 204
 205        read_lock_bh(&protocol_list_lock);
 206        for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
 207                if (protocol->pid == pid) {
 208                        res = 1;
 209                        break;
 210                }
 211        read_unlock_bh(&protocol_list_lock);
 212
 213        return res;
 214}
 215