blob: 979bc4b828a007f60a8992d8171e9d0a6a2bfb6b [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
5 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006#include <linux/errno.h>
7#include <linux/types.h>
8#include <linux/socket.h>
9#include <linux/in.h>
10#include <linux/kernel.h>
Ralf Baechle70868ea2006-05-03 23:25:17 -070011#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/spinlock.h>
13#include <linux/timer.h>
14#include <linux/string.h>
15#include <linux/sockios.h>
16#include <linux/net.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090017#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <net/ax25.h>
19#include <linux/inet.h>
20#include <linux/netdevice.h>
21#include <linux/skbuff.h>
22#include <net/sock.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080023#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/fcntl.h>
25#include <linux/mm.h>
26#include <linux/interrupt.h>
27
Ralf Baechle8d5cf592006-12-14 15:50:01 -080028static struct ax25_protocol *protocol_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -070029static DEFINE_RWLOCK(protocol_list_lock);
30
Ralf Baechlea4282712006-12-14 15:51:23 -080031static HLIST_HEAD(ax25_linkfail_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -070032static 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
Ralf Baechle8d5cf592006-12-14 15:50:01 -080041/*
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)
Linus Torvalds1da177e2005-04-16 15:20:36 -070046{
Ralf Baechle95ff9f42006-07-10 16:21:29 -070047 write_lock_bh(&protocol_list_lock);
Ralf Baechle8d5cf592006-12-14 15:50:01 -080048 ap->next = protocol_list;
49 protocol_list = ap;
Ralf Baechle95ff9f42006-07-10 16:21:29 -070050 write_unlock_bh(&protocol_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070051}
52
Ralf Baechle8d5cf592006-12-14 15:50:01 -080053EXPORT_SYMBOL_GPL(ax25_register_pid);
Ralf Baechle70868ea2006-05-03 23:25:17 -070054
Linus Torvalds1da177e2005-04-16 15:20:36 -070055void ax25_protocol_release(unsigned int pid)
56{
David S. Millerd8f969e2011-04-17 00:46:45 -070057 struct ax25_protocol *protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Ralf Baechle95ff9f42006-07-10 16:21:29 -070059 write_lock_bh(&protocol_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 protocol = protocol_list;
Ilpo Järvinen910d30b2009-02-06 23:47:14 -080061 if (protocol == NULL)
62 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64 if (protocol->pid == pid) {
65 protocol_list = protocol->next;
Ilpo Järvinen910d30b2009-02-06 23:47:14 -080066 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 }
68
69 while (protocol != NULL && protocol->next != NULL) {
70 if (protocol->next->pid == pid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 protocol->next = protocol->next->next;
Ilpo Järvinen910d30b2009-02-06 23:47:14 -080072 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 }
74
75 protocol = protocol->next;
76 }
Ilpo Järvinen910d30b2009-02-06 23:47:14 -080077out:
Ralf Baechle95ff9f42006-07-10 16:21:29 -070078 write_unlock_bh(&protocol_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079}
80
Ralf Baechle70868ea2006-05-03 23:25:17 -070081EXPORT_SYMBOL(ax25_protocol_release);
82
Ralf Baechlea4282712006-12-14 15:51:23 -080083void ax25_linkfail_register(struct ax25_linkfail *lf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070084{
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 spin_lock_bh(&linkfail_lock);
Ralf Baechlea4282712006-12-14 15:51:23 -080086 hlist_add_head(&lf->lf_node, &ax25_linkfail_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 spin_unlock_bh(&linkfail_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088}
89
Ralf Baechle70868ea2006-05-03 23:25:17 -070090EXPORT_SYMBOL(ax25_linkfail_register);
91
Ralf Baechlea4282712006-12-14 15:51:23 -080092void ax25_linkfail_release(struct ax25_linkfail *lf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 spin_lock_bh(&linkfail_lock);
Ralf Baechlea4282712006-12-14 15:51:23 -080095 hlist_del_init(&lf->lf_node);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 spin_unlock_bh(&linkfail_lock);
97}
98
Ralf Baechle70868ea2006-05-03 23:25:17 -070099EXPORT_SYMBOL(ax25_linkfail_release);
100
Jakub Kicinskic045ad22021-10-12 08:58:35 -0700101int ax25_listen_register(const ax25_address *callsign, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102{
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)
Ralf Baechle81dcd162006-12-14 15:50:34 -0800109 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
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
Ralf Baechle81dcd162006-12-14 15:50:34 -0800119 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120}
121
Ralf Baechle70868ea2006-05-03 23:25:17 -0700122EXPORT_SYMBOL(ax25_listen_register);
123
Jakub Kicinskic045ad22021-10-12 08:58:35 -0700124void ax25_listen_release(const ax25_address *callsign, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125{
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
Ralf Baechle70868ea2006-05-03 23:25:17 -0700156EXPORT_SYMBOL(ax25_listen_release);
157
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *)
159{
160 int (*res)(struct sk_buff *, ax25_cb *) = NULL;
Ralf Baechle8d5cf592006-12-14 15:50:01 -0800161 struct ax25_protocol *protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
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
Jakub Kicinskic045ad22021-10-12 08:58:35 -0700174int ax25_listen_mine(const ax25_address *callsign, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175{
176 struct listen_struct *listen;
177
178 spin_lock_bh(&listen_lock);
179 for (listen = listen_list; listen != NULL; listen = listen->next)
Ralf Baechle81dcd162006-12-14 15:50:34 -0800180 if (ax25cmp(&listen->callsign, callsign) == 0 &&
181 (listen->dev == dev || listen->dev == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 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{
Ralf Baechlea4282712006-12-14 15:51:23 -0800192 struct ax25_linkfail *lf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
194 spin_lock_bh(&linkfail_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -0800195 hlist_for_each_entry(lf, &ax25_linkfail_list, lf_node)
Ralf Baechlea4282712006-12-14 15:51:23 -0800196 lf->func(ax25, reason);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 spin_unlock_bh(&linkfail_lock);
198}
199
200int ax25_protocol_is_registered(unsigned int pid)
201{
Ralf Baechle8d5cf592006-12-14 15:50:01 -0800202 struct ax25_protocol *protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 int res = 0;
204
Ralf Baechle95ff9f42006-07-10 16:21:29 -0700205 read_lock_bh(&protocol_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
207 if (protocol->pid == pid) {
208 res = 1;
209 break;
210 }
Ralf Baechle95ff9f42006-07-10 16:21:29 -0700211 read_unlock_bh(&protocol_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213 return res;
214}