Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/ax25/ax25_route.c
26288 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
*
4
* Copyright (C) Alan Cox GW4PTS ([email protected])
5
* Copyright (C) Jonathan Naylor G4KLX ([email protected])
6
* Copyright (C) Steven Whitehouse GW7RRM ([email protected])
7
* Copyright (C) Joerg Reuter DL1BKE ([email protected])
8
* Copyright (C) Hans-Joachim Hetscher DD8NE ([email protected])
9
* Copyright (C) Frederic Rible F1OAT ([email protected])
10
*/
11
12
#include <linux/capability.h>
13
#include <linux/errno.h>
14
#include <linux/types.h>
15
#include <linux/socket.h>
16
#include <linux/timer.h>
17
#include <linux/in.h>
18
#include <linux/kernel.h>
19
#include <linux/sched.h>
20
#include <linux/string.h>
21
#include <linux/sockios.h>
22
#include <linux/net.h>
23
#include <linux/slab.h>
24
#include <net/ax25.h>
25
#include <linux/inet.h>
26
#include <linux/netdevice.h>
27
#include <linux/if_arp.h>
28
#include <linux/skbuff.h>
29
#include <linux/spinlock.h>
30
#include <net/sock.h>
31
#include <linux/uaccess.h>
32
#include <linux/fcntl.h>
33
#include <linux/mm.h>
34
#include <linux/interrupt.h>
35
#include <linux/init.h>
36
#include <linux/seq_file.h>
37
#include <linux/export.h>
38
39
static ax25_route *ax25_route_list;
40
DEFINE_RWLOCK(ax25_route_lock);
41
42
void ax25_rt_device_down(struct net_device *dev)
43
{
44
ax25_route *s, *t, *ax25_rt;
45
46
write_lock_bh(&ax25_route_lock);
47
ax25_rt = ax25_route_list;
48
while (ax25_rt != NULL) {
49
s = ax25_rt;
50
ax25_rt = ax25_rt->next;
51
52
if (s->dev == dev) {
53
if (ax25_route_list == s) {
54
ax25_route_list = s->next;
55
kfree(s->digipeat);
56
kfree(s);
57
} else {
58
for (t = ax25_route_list; t != NULL; t = t->next) {
59
if (t->next == s) {
60
t->next = s->next;
61
kfree(s->digipeat);
62
kfree(s);
63
break;
64
}
65
}
66
}
67
}
68
}
69
write_unlock_bh(&ax25_route_lock);
70
}
71
72
static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
73
{
74
ax25_route *ax25_rt;
75
ax25_dev *ax25_dev;
76
int i;
77
78
if (route->digi_count > AX25_MAX_DIGIS)
79
return -EINVAL;
80
81
ax25_dev = ax25_addr_ax25dev(&route->port_addr);
82
if (!ax25_dev)
83
return -EINVAL;
84
85
write_lock_bh(&ax25_route_lock);
86
87
ax25_rt = ax25_route_list;
88
while (ax25_rt != NULL) {
89
if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 &&
90
ax25_rt->dev == ax25_dev->dev) {
91
kfree(ax25_rt->digipeat);
92
ax25_rt->digipeat = NULL;
93
if (route->digi_count != 0) {
94
if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
95
write_unlock_bh(&ax25_route_lock);
96
ax25_dev_put(ax25_dev);
97
return -ENOMEM;
98
}
99
ax25_rt->digipeat->lastrepeat = -1;
100
ax25_rt->digipeat->ndigi = route->digi_count;
101
for (i = 0; i < route->digi_count; i++) {
102
ax25_rt->digipeat->repeated[i] = 0;
103
ax25_rt->digipeat->calls[i] = route->digi_addr[i];
104
}
105
}
106
write_unlock_bh(&ax25_route_lock);
107
ax25_dev_put(ax25_dev);
108
return 0;
109
}
110
ax25_rt = ax25_rt->next;
111
}
112
113
if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
114
write_unlock_bh(&ax25_route_lock);
115
ax25_dev_put(ax25_dev);
116
return -ENOMEM;
117
}
118
119
ax25_rt->callsign = route->dest_addr;
120
ax25_rt->dev = ax25_dev->dev;
121
ax25_rt->digipeat = NULL;
122
ax25_rt->ip_mode = ' ';
123
if (route->digi_count != 0) {
124
if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
125
write_unlock_bh(&ax25_route_lock);
126
kfree(ax25_rt);
127
ax25_dev_put(ax25_dev);
128
return -ENOMEM;
129
}
130
ax25_rt->digipeat->lastrepeat = -1;
131
ax25_rt->digipeat->ndigi = route->digi_count;
132
for (i = 0; i < route->digi_count; i++) {
133
ax25_rt->digipeat->repeated[i] = 0;
134
ax25_rt->digipeat->calls[i] = route->digi_addr[i];
135
}
136
}
137
ax25_rt->next = ax25_route_list;
138
ax25_route_list = ax25_rt;
139
write_unlock_bh(&ax25_route_lock);
140
ax25_dev_put(ax25_dev);
141
142
return 0;
143
}
144
145
void __ax25_put_route(ax25_route *ax25_rt)
146
{
147
kfree(ax25_rt->digipeat);
148
kfree(ax25_rt);
149
}
150
151
static int ax25_rt_del(struct ax25_routes_struct *route)
152
{
153
ax25_route *s, *t, *ax25_rt;
154
ax25_dev *ax25_dev;
155
156
if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
157
return -EINVAL;
158
159
write_lock_bh(&ax25_route_lock);
160
161
ax25_rt = ax25_route_list;
162
while (ax25_rt != NULL) {
163
s = ax25_rt;
164
ax25_rt = ax25_rt->next;
165
if (s->dev == ax25_dev->dev &&
166
ax25cmp(&route->dest_addr, &s->callsign) == 0) {
167
if (ax25_route_list == s) {
168
ax25_route_list = s->next;
169
__ax25_put_route(s);
170
} else {
171
for (t = ax25_route_list; t != NULL; t = t->next) {
172
if (t->next == s) {
173
t->next = s->next;
174
__ax25_put_route(s);
175
break;
176
}
177
}
178
}
179
}
180
}
181
write_unlock_bh(&ax25_route_lock);
182
ax25_dev_put(ax25_dev);
183
184
return 0;
185
}
186
187
static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
188
{
189
ax25_route *ax25_rt;
190
ax25_dev *ax25_dev;
191
int err = 0;
192
193
if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL)
194
return -EINVAL;
195
196
write_lock_bh(&ax25_route_lock);
197
198
ax25_rt = ax25_route_list;
199
while (ax25_rt != NULL) {
200
if (ax25_rt->dev == ax25_dev->dev &&
201
ax25cmp(&rt_option->dest_addr, &ax25_rt->callsign) == 0) {
202
switch (rt_option->cmd) {
203
case AX25_SET_RT_IPMODE:
204
switch (rt_option->arg) {
205
case ' ':
206
case 'D':
207
case 'V':
208
ax25_rt->ip_mode = rt_option->arg;
209
break;
210
default:
211
err = -EINVAL;
212
goto out;
213
}
214
break;
215
default:
216
err = -EINVAL;
217
goto out;
218
}
219
}
220
ax25_rt = ax25_rt->next;
221
}
222
223
out:
224
write_unlock_bh(&ax25_route_lock);
225
ax25_dev_put(ax25_dev);
226
return err;
227
}
228
229
int ax25_rt_ioctl(unsigned int cmd, void __user *arg)
230
{
231
struct ax25_route_opt_struct rt_option;
232
struct ax25_routes_struct route;
233
234
switch (cmd) {
235
case SIOCADDRT:
236
if (copy_from_user(&route, arg, sizeof(route)))
237
return -EFAULT;
238
return ax25_rt_add(&route);
239
240
case SIOCDELRT:
241
if (copy_from_user(&route, arg, sizeof(route)))
242
return -EFAULT;
243
return ax25_rt_del(&route);
244
245
case SIOCAX25OPTRT:
246
if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
247
return -EFAULT;
248
return ax25_rt_opt(&rt_option);
249
250
default:
251
return -EINVAL;
252
}
253
}
254
255
#ifdef CONFIG_PROC_FS
256
257
static void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos)
258
__acquires(ax25_route_lock)
259
{
260
struct ax25_route *ax25_rt;
261
int i = 1;
262
263
read_lock(&ax25_route_lock);
264
if (*pos == 0)
265
return SEQ_START_TOKEN;
266
267
for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
268
if (i == *pos)
269
return ax25_rt;
270
++i;
271
}
272
273
return NULL;
274
}
275
276
static void *ax25_rt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
277
{
278
++*pos;
279
return (v == SEQ_START_TOKEN) ? ax25_route_list :
280
((struct ax25_route *) v)->next;
281
}
282
283
static void ax25_rt_seq_stop(struct seq_file *seq, void *v)
284
__releases(ax25_route_lock)
285
{
286
read_unlock(&ax25_route_lock);
287
}
288
289
static int ax25_rt_seq_show(struct seq_file *seq, void *v)
290
{
291
char buf[11];
292
293
if (v == SEQ_START_TOKEN)
294
seq_puts(seq, "callsign dev mode digipeaters\n");
295
else {
296
struct ax25_route *ax25_rt = v;
297
const char *callsign;
298
int i;
299
300
if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
301
callsign = "default";
302
else
303
callsign = ax2asc(buf, &ax25_rt->callsign);
304
305
seq_printf(seq, "%-9s %-4s",
306
callsign,
307
ax25_rt->dev ? ax25_rt->dev->name : "???");
308
309
switch (ax25_rt->ip_mode) {
310
case 'V':
311
seq_puts(seq, " vc");
312
break;
313
case 'D':
314
seq_puts(seq, " dg");
315
break;
316
default:
317
seq_puts(seq, " *");
318
break;
319
}
320
321
if (ax25_rt->digipeat != NULL)
322
for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
323
seq_printf(seq, " %s",
324
ax2asc(buf, &ax25_rt->digipeat->calls[i]));
325
326
seq_puts(seq, "\n");
327
}
328
return 0;
329
}
330
331
const struct seq_operations ax25_rt_seqops = {
332
.start = ax25_rt_seq_start,
333
.next = ax25_rt_seq_next,
334
.stop = ax25_rt_seq_stop,
335
.show = ax25_rt_seq_show,
336
};
337
#endif
338
339
/*
340
* Find AX.25 route
341
*
342
* Only routes with a reference count of zero can be destroyed.
343
* Must be called with ax25_route_lock read locked.
344
*/
345
ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
346
{
347
ax25_route *ax25_spe_rt = NULL;
348
ax25_route *ax25_def_rt = NULL;
349
ax25_route *ax25_rt;
350
351
/*
352
* Bind to the physical interface we heard them on, or the default
353
* route if none is found;
354
*/
355
for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
356
if (dev == NULL) {
357
if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
358
ax25_spe_rt = ax25_rt;
359
if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
360
ax25_def_rt = ax25_rt;
361
} else {
362
if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev)
363
ax25_spe_rt = ax25_rt;
364
if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev == dev)
365
ax25_def_rt = ax25_rt;
366
}
367
}
368
369
ax25_rt = ax25_def_rt;
370
if (ax25_spe_rt != NULL)
371
ax25_rt = ax25_spe_rt;
372
373
return ax25_rt;
374
}
375
376
377
struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
378
ax25_address *dest, ax25_digi *digi)
379
{
380
unsigned char *bp;
381
int len;
382
383
len = digi->ndigi * AX25_ADDR_LEN;
384
385
if (unlikely(skb_headroom(skb) < len)) {
386
skb = skb_expand_head(skb, len);
387
if (!skb) {
388
printk(KERN_CRIT "AX.25: ax25_dg_build_path - out of memory\n");
389
return NULL;
390
}
391
}
392
393
bp = skb_push(skb, len);
394
395
ax25_addr_build(bp, src, dest, digi, AX25_COMMAND, AX25_MODULUS);
396
397
return skb;
398
}
399
400
/*
401
* Free all memory associated with routing structures.
402
*/
403
void __exit ax25_rt_free(void)
404
{
405
ax25_route *s, *ax25_rt = ax25_route_list;
406
407
write_lock_bh(&ax25_route_lock);
408
while (ax25_rt != NULL) {
409
s = ax25_rt;
410
ax25_rt = ax25_rt->next;
411
412
kfree(s->digipeat);
413
kfree(s);
414
}
415
write_unlock_bh(&ax25_route_lock);
416
}
417
418