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