1/*
2 *	AX.25 release 037
3 *
4 *	This code REQUIRES 2.1.15 or higher/ NET3.038
5 *
6 *	This module:
7 *		This module is free software; you can redistribute it and/or
8 *		modify it under the terms of the GNU General Public License
9 *		as published by the Free Software Foundation; either version
10 *		2 of the License, or (at your option) any later version.
11 *
12 *	History
13 *	AX.25 036	Jonathan(G4KLX)	Split from ax25_timer.c.
14 */
15
16#include <linux/config.h>
17#include <linux/errno.h>
18#include <linux/types.h>
19#include <linux/socket.h>
20#include <linux/in.h>
21#include <linux/kernel.h>
22#include <linux/sched.h>
23#include <linux/timer.h>
24#include <linux/string.h>
25#include <linux/sockios.h>
26#include <linux/net.h>
27#include <net/ax25.h>
28#include <linux/inet.h>
29#include <linux/netdevice.h>
30#include <linux/skbuff.h>
31#include <net/sock.h>
32#include <asm/uaccess.h>
33#include <asm/system.h>
34#include <linux/fcntl.h>
35#include <linux/mm.h>
36#include <linux/interrupt.h>
37
38static struct protocol_struct {
39	struct protocol_struct *next;
40	unsigned int pid;
41	int (*func)(struct sk_buff *, ax25_cb *);
42} *protocol_list;
43
44static struct linkfail_struct {
45	struct linkfail_struct *next;
46	void (*func)(ax25_cb *, int);
47} *linkfail_list;
48
49static struct listen_struct {
50	struct listen_struct *next;
51	ax25_address  callsign;
52	struct net_device *dev;
53} *listen_list;
54
55int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_cb *))
56{
57	struct protocol_struct *protocol;
58	unsigned long flags;
59
60	if (pid == AX25_P_TEXT || pid == AX25_P_SEGMENT)
61		return 0;
62#ifdef CONFIG_INET
63	if (pid == AX25_P_IP || pid == AX25_P_ARP)
64		return 0;
65#endif
66	if ((protocol = kmalloc(sizeof(*protocol), GFP_ATOMIC)) == NULL)
67		return 0;
68
69	protocol->pid  = pid;
70	protocol->func = func;
71
72	save_flags(flags);
73	cli();
74
75	protocol->next = protocol_list;
76	protocol_list  = protocol;
77
78	restore_flags(flags);
79
80	return 1;
81}
82
83void ax25_protocol_release(unsigned int pid)
84{
85	struct protocol_struct *s, *protocol = protocol_list;
86	unsigned long flags;
87
88	if (protocol == NULL)
89		return;
90
91	save_flags(flags);
92	cli();
93
94	if (protocol->pid == pid) {
95		protocol_list = protocol->next;
96		restore_flags(flags);
97		kfree(protocol);
98		return;
99	}
100
101	while (protocol != NULL && protocol->next != NULL) {
102		if (protocol->next->pid == pid) {
103			s = protocol->next;
104			protocol->next = protocol->next->next;
105			restore_flags(flags);
106			kfree(s);
107			return;
108		}
109
110		protocol = protocol->next;
111	}
112
113	restore_flags(flags);
114}
115
116int ax25_linkfail_register(void (*func)(ax25_cb *, int))
117{
118	struct linkfail_struct *linkfail;
119	unsigned long flags;
120
121	if ((linkfail = kmalloc(sizeof(*linkfail), GFP_ATOMIC)) == NULL)
122		return 0;
123
124	linkfail->func = func;
125
126	save_flags(flags);
127	cli();
128
129	linkfail->next = linkfail_list;
130	linkfail_list  = linkfail;
131
132	restore_flags(flags);
133
134	return 1;
135}
136
137void ax25_linkfail_release(void (*func)(ax25_cb *, int))
138{
139	struct linkfail_struct *s, *linkfail = linkfail_list;
140	unsigned long flags;
141
142	if (linkfail == NULL)
143		return;
144
145	save_flags(flags);
146	cli();
147
148	if (linkfail->func == func) {
149		linkfail_list = linkfail->next;
150		restore_flags(flags);
151		kfree(linkfail);
152		return;
153	}
154
155	while (linkfail != NULL && linkfail->next != NULL) {
156		if (linkfail->next->func == func) {
157			s = linkfail->next;
158			linkfail->next = linkfail->next->next;
159			restore_flags(flags);
160			kfree(s);
161			return;
162		}
163
164		linkfail = linkfail->next;
165	}
166
167	restore_flags(flags);
168}
169
170int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
171{
172	struct listen_struct *listen;
173	unsigned long flags;
174
175	if (ax25_listen_mine(callsign, dev))
176		return 0;
177
178	if ((listen = kmalloc(sizeof(*listen), GFP_ATOMIC)) == NULL)
179		return 0;
180
181	listen->callsign = *callsign;
182	listen->dev      = dev;
183
184	save_flags(flags);
185	cli();
186
187	listen->next = listen_list;
188	listen_list  = listen;
189
190	restore_flags(flags);
191
192	return 1;
193}
194
195void ax25_listen_release(ax25_address *callsign, struct net_device *dev)
196{
197	struct listen_struct *s, *listen = listen_list;
198	unsigned long flags;
199
200	if (listen == NULL)
201		return;
202
203	save_flags(flags);
204	cli();
205
206	if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) {
207		listen_list = listen->next;
208		restore_flags(flags);
209		kfree(listen);
210		return;
211	}
212
213	while (listen != NULL && listen->next != NULL) {
214		if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) {
215			s = listen->next;
216			listen->next = listen->next->next;
217			restore_flags(flags);
218			kfree(s);
219			return;
220		}
221
222		listen = listen->next;
223	}
224
225	restore_flags(flags);
226}
227
228int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *)
229{
230	struct protocol_struct *protocol;
231
232	for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
233		if (protocol->pid == pid)
234			return protocol->func;
235
236	return NULL;
237}
238
239int ax25_listen_mine(ax25_address *callsign, struct net_device *dev)
240{
241	struct listen_struct *listen;
242
243	for (listen = listen_list; listen != NULL; listen = listen->next)
244		if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL))
245			return 1;
246
247	return 0;
248}
249
250void ax25_link_failed(ax25_cb *ax25, int reason)
251{
252	struct linkfail_struct *linkfail;
253
254	for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next)
255		(linkfail->func)(ax25, reason);
256}
257
258int ax25_protocol_is_registered(unsigned int pid)
259{
260	struct protocol_struct *protocol;
261
262	for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
263		if (protocol->pid == pid)
264			return 1;
265
266	return 0;
267}
268
269