1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
5*4882a593Smuzhiyun * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
6*4882a593Smuzhiyun * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
7*4882a593Smuzhiyun * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
8*4882a593Smuzhiyun * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
9*4882a593Smuzhiyun * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/capability.h>
13*4882a593Smuzhiyun #include <linux/errno.h>
14*4882a593Smuzhiyun #include <linux/types.h>
15*4882a593Smuzhiyun #include <linux/socket.h>
16*4882a593Smuzhiyun #include <linux/timer.h>
17*4882a593Smuzhiyun #include <linux/in.h>
18*4882a593Smuzhiyun #include <linux/kernel.h>
19*4882a593Smuzhiyun #include <linux/sched.h>
20*4882a593Smuzhiyun #include <linux/string.h>
21*4882a593Smuzhiyun #include <linux/sockios.h>
22*4882a593Smuzhiyun #include <linux/net.h>
23*4882a593Smuzhiyun #include <linux/slab.h>
24*4882a593Smuzhiyun #include <net/ax25.h>
25*4882a593Smuzhiyun #include <linux/inet.h>
26*4882a593Smuzhiyun #include <linux/netdevice.h>
27*4882a593Smuzhiyun #include <linux/if_arp.h>
28*4882a593Smuzhiyun #include <linux/skbuff.h>
29*4882a593Smuzhiyun #include <linux/spinlock.h>
30*4882a593Smuzhiyun #include <net/sock.h>
31*4882a593Smuzhiyun #include <linux/uaccess.h>
32*4882a593Smuzhiyun #include <linux/fcntl.h>
33*4882a593Smuzhiyun #include <linux/mm.h>
34*4882a593Smuzhiyun #include <linux/interrupt.h>
35*4882a593Smuzhiyun #include <linux/init.h>
36*4882a593Smuzhiyun #include <linux/seq_file.h>
37*4882a593Smuzhiyun #include <linux/export.h>
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun static ax25_route *ax25_route_list;
40*4882a593Smuzhiyun DEFINE_RWLOCK(ax25_route_lock);
41*4882a593Smuzhiyun
ax25_rt_device_down(struct net_device * dev)42*4882a593Smuzhiyun void ax25_rt_device_down(struct net_device *dev)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun ax25_route *s, *t, *ax25_rt;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun write_lock_bh(&ax25_route_lock);
47*4882a593Smuzhiyun ax25_rt = ax25_route_list;
48*4882a593Smuzhiyun while (ax25_rt != NULL) {
49*4882a593Smuzhiyun s = ax25_rt;
50*4882a593Smuzhiyun ax25_rt = ax25_rt->next;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun if (s->dev == dev) {
53*4882a593Smuzhiyun if (ax25_route_list == s) {
54*4882a593Smuzhiyun ax25_route_list = s->next;
55*4882a593Smuzhiyun kfree(s->digipeat);
56*4882a593Smuzhiyun kfree(s);
57*4882a593Smuzhiyun } else {
58*4882a593Smuzhiyun for (t = ax25_route_list; t != NULL; t = t->next) {
59*4882a593Smuzhiyun if (t->next == s) {
60*4882a593Smuzhiyun t->next = s->next;
61*4882a593Smuzhiyun kfree(s->digipeat);
62*4882a593Smuzhiyun kfree(s);
63*4882a593Smuzhiyun break;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun write_unlock_bh(&ax25_route_lock);
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
ax25_rt_add(struct ax25_routes_struct * route)72*4882a593Smuzhiyun static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun ax25_route *ax25_rt;
75*4882a593Smuzhiyun ax25_dev *ax25_dev;
76*4882a593Smuzhiyun int i;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun if (route->digi_count > AX25_MAX_DIGIS)
79*4882a593Smuzhiyun return -EINVAL;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun ax25_dev = ax25_addr_ax25dev(&route->port_addr);
82*4882a593Smuzhiyun if (!ax25_dev)
83*4882a593Smuzhiyun return -EINVAL;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun write_lock_bh(&ax25_route_lock);
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun ax25_rt = ax25_route_list;
88*4882a593Smuzhiyun while (ax25_rt != NULL) {
89*4882a593Smuzhiyun if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 &&
90*4882a593Smuzhiyun ax25_rt->dev == ax25_dev->dev) {
91*4882a593Smuzhiyun kfree(ax25_rt->digipeat);
92*4882a593Smuzhiyun ax25_rt->digipeat = NULL;
93*4882a593Smuzhiyun if (route->digi_count != 0) {
94*4882a593Smuzhiyun if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
95*4882a593Smuzhiyun write_unlock_bh(&ax25_route_lock);
96*4882a593Smuzhiyun ax25_dev_put(ax25_dev);
97*4882a593Smuzhiyun return -ENOMEM;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun ax25_rt->digipeat->lastrepeat = -1;
100*4882a593Smuzhiyun ax25_rt->digipeat->ndigi = route->digi_count;
101*4882a593Smuzhiyun for (i = 0; i < route->digi_count; i++) {
102*4882a593Smuzhiyun ax25_rt->digipeat->repeated[i] = 0;
103*4882a593Smuzhiyun ax25_rt->digipeat->calls[i] = route->digi_addr[i];
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun write_unlock_bh(&ax25_route_lock);
107*4882a593Smuzhiyun ax25_dev_put(ax25_dev);
108*4882a593Smuzhiyun return 0;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun ax25_rt = ax25_rt->next;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
114*4882a593Smuzhiyun write_unlock_bh(&ax25_route_lock);
115*4882a593Smuzhiyun ax25_dev_put(ax25_dev);
116*4882a593Smuzhiyun return -ENOMEM;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun refcount_set(&ax25_rt->refcount, 1);
120*4882a593Smuzhiyun ax25_rt->callsign = route->dest_addr;
121*4882a593Smuzhiyun ax25_rt->dev = ax25_dev->dev;
122*4882a593Smuzhiyun ax25_rt->digipeat = NULL;
123*4882a593Smuzhiyun ax25_rt->ip_mode = ' ';
124*4882a593Smuzhiyun if (route->digi_count != 0) {
125*4882a593Smuzhiyun if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
126*4882a593Smuzhiyun write_unlock_bh(&ax25_route_lock);
127*4882a593Smuzhiyun kfree(ax25_rt);
128*4882a593Smuzhiyun ax25_dev_put(ax25_dev);
129*4882a593Smuzhiyun return -ENOMEM;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun ax25_rt->digipeat->lastrepeat = -1;
132*4882a593Smuzhiyun ax25_rt->digipeat->ndigi = route->digi_count;
133*4882a593Smuzhiyun for (i = 0; i < route->digi_count; i++) {
134*4882a593Smuzhiyun ax25_rt->digipeat->repeated[i] = 0;
135*4882a593Smuzhiyun ax25_rt->digipeat->calls[i] = route->digi_addr[i];
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun ax25_rt->next = ax25_route_list;
139*4882a593Smuzhiyun ax25_route_list = ax25_rt;
140*4882a593Smuzhiyun write_unlock_bh(&ax25_route_lock);
141*4882a593Smuzhiyun ax25_dev_put(ax25_dev);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun return 0;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
__ax25_put_route(ax25_route * ax25_rt)146*4882a593Smuzhiyun void __ax25_put_route(ax25_route *ax25_rt)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun kfree(ax25_rt->digipeat);
149*4882a593Smuzhiyun kfree(ax25_rt);
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
ax25_rt_del(struct ax25_routes_struct * route)152*4882a593Smuzhiyun static int ax25_rt_del(struct ax25_routes_struct *route)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun ax25_route *s, *t, *ax25_rt;
155*4882a593Smuzhiyun ax25_dev *ax25_dev;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
158*4882a593Smuzhiyun return -EINVAL;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun write_lock_bh(&ax25_route_lock);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun ax25_rt = ax25_route_list;
163*4882a593Smuzhiyun while (ax25_rt != NULL) {
164*4882a593Smuzhiyun s = ax25_rt;
165*4882a593Smuzhiyun ax25_rt = ax25_rt->next;
166*4882a593Smuzhiyun if (s->dev == ax25_dev->dev &&
167*4882a593Smuzhiyun ax25cmp(&route->dest_addr, &s->callsign) == 0) {
168*4882a593Smuzhiyun if (ax25_route_list == s) {
169*4882a593Smuzhiyun ax25_route_list = s->next;
170*4882a593Smuzhiyun ax25_put_route(s);
171*4882a593Smuzhiyun } else {
172*4882a593Smuzhiyun for (t = ax25_route_list; t != NULL; t = t->next) {
173*4882a593Smuzhiyun if (t->next == s) {
174*4882a593Smuzhiyun t->next = s->next;
175*4882a593Smuzhiyun ax25_put_route(s);
176*4882a593Smuzhiyun break;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun write_unlock_bh(&ax25_route_lock);
183*4882a593Smuzhiyun ax25_dev_put(ax25_dev);
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun return 0;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
ax25_rt_opt(struct ax25_route_opt_struct * rt_option)188*4882a593Smuzhiyun static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun ax25_route *ax25_rt;
191*4882a593Smuzhiyun ax25_dev *ax25_dev;
192*4882a593Smuzhiyun int err = 0;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL)
195*4882a593Smuzhiyun return -EINVAL;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun write_lock_bh(&ax25_route_lock);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun ax25_rt = ax25_route_list;
200*4882a593Smuzhiyun while (ax25_rt != NULL) {
201*4882a593Smuzhiyun if (ax25_rt->dev == ax25_dev->dev &&
202*4882a593Smuzhiyun ax25cmp(&rt_option->dest_addr, &ax25_rt->callsign) == 0) {
203*4882a593Smuzhiyun switch (rt_option->cmd) {
204*4882a593Smuzhiyun case AX25_SET_RT_IPMODE:
205*4882a593Smuzhiyun switch (rt_option->arg) {
206*4882a593Smuzhiyun case ' ':
207*4882a593Smuzhiyun case 'D':
208*4882a593Smuzhiyun case 'V':
209*4882a593Smuzhiyun ax25_rt->ip_mode = rt_option->arg;
210*4882a593Smuzhiyun break;
211*4882a593Smuzhiyun default:
212*4882a593Smuzhiyun err = -EINVAL;
213*4882a593Smuzhiyun goto out;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun break;
216*4882a593Smuzhiyun default:
217*4882a593Smuzhiyun err = -EINVAL;
218*4882a593Smuzhiyun goto out;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun ax25_rt = ax25_rt->next;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun out:
225*4882a593Smuzhiyun write_unlock_bh(&ax25_route_lock);
226*4882a593Smuzhiyun ax25_dev_put(ax25_dev);
227*4882a593Smuzhiyun return err;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
ax25_rt_ioctl(unsigned int cmd,void __user * arg)230*4882a593Smuzhiyun int ax25_rt_ioctl(unsigned int cmd, void __user *arg)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun struct ax25_route_opt_struct rt_option;
233*4882a593Smuzhiyun struct ax25_routes_struct route;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun switch (cmd) {
236*4882a593Smuzhiyun case SIOCADDRT:
237*4882a593Smuzhiyun if (copy_from_user(&route, arg, sizeof(route)))
238*4882a593Smuzhiyun return -EFAULT;
239*4882a593Smuzhiyun return ax25_rt_add(&route);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun case SIOCDELRT:
242*4882a593Smuzhiyun if (copy_from_user(&route, arg, sizeof(route)))
243*4882a593Smuzhiyun return -EFAULT;
244*4882a593Smuzhiyun return ax25_rt_del(&route);
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun case SIOCAX25OPTRT:
247*4882a593Smuzhiyun if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
248*4882a593Smuzhiyun return -EFAULT;
249*4882a593Smuzhiyun return ax25_rt_opt(&rt_option);
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun default:
252*4882a593Smuzhiyun return -EINVAL;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun #ifdef CONFIG_PROC_FS
257*4882a593Smuzhiyun
ax25_rt_seq_start(struct seq_file * seq,loff_t * pos)258*4882a593Smuzhiyun static void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos)
259*4882a593Smuzhiyun __acquires(ax25_route_lock)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun struct ax25_route *ax25_rt;
262*4882a593Smuzhiyun int i = 1;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun read_lock(&ax25_route_lock);
265*4882a593Smuzhiyun if (*pos == 0)
266*4882a593Smuzhiyun return SEQ_START_TOKEN;
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
269*4882a593Smuzhiyun if (i == *pos)
270*4882a593Smuzhiyun return ax25_rt;
271*4882a593Smuzhiyun ++i;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun return NULL;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
ax25_rt_seq_next(struct seq_file * seq,void * v,loff_t * pos)277*4882a593Smuzhiyun static void *ax25_rt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun ++*pos;
280*4882a593Smuzhiyun return (v == SEQ_START_TOKEN) ? ax25_route_list :
281*4882a593Smuzhiyun ((struct ax25_route *) v)->next;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
ax25_rt_seq_stop(struct seq_file * seq,void * v)284*4882a593Smuzhiyun static void ax25_rt_seq_stop(struct seq_file *seq, void *v)
285*4882a593Smuzhiyun __releases(ax25_route_lock)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun read_unlock(&ax25_route_lock);
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
ax25_rt_seq_show(struct seq_file * seq,void * v)290*4882a593Smuzhiyun static int ax25_rt_seq_show(struct seq_file *seq, void *v)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun char buf[11];
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun if (v == SEQ_START_TOKEN)
295*4882a593Smuzhiyun seq_puts(seq, "callsign dev mode digipeaters\n");
296*4882a593Smuzhiyun else {
297*4882a593Smuzhiyun struct ax25_route *ax25_rt = v;
298*4882a593Smuzhiyun const char *callsign;
299*4882a593Smuzhiyun int i;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
302*4882a593Smuzhiyun callsign = "default";
303*4882a593Smuzhiyun else
304*4882a593Smuzhiyun callsign = ax2asc(buf, &ax25_rt->callsign);
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun seq_printf(seq, "%-9s %-4s",
307*4882a593Smuzhiyun callsign,
308*4882a593Smuzhiyun ax25_rt->dev ? ax25_rt->dev->name : "???");
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun switch (ax25_rt->ip_mode) {
311*4882a593Smuzhiyun case 'V':
312*4882a593Smuzhiyun seq_puts(seq, " vc");
313*4882a593Smuzhiyun break;
314*4882a593Smuzhiyun case 'D':
315*4882a593Smuzhiyun seq_puts(seq, " dg");
316*4882a593Smuzhiyun break;
317*4882a593Smuzhiyun default:
318*4882a593Smuzhiyun seq_puts(seq, " *");
319*4882a593Smuzhiyun break;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun if (ax25_rt->digipeat != NULL)
323*4882a593Smuzhiyun for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
324*4882a593Smuzhiyun seq_printf(seq, " %s",
325*4882a593Smuzhiyun ax2asc(buf, &ax25_rt->digipeat->calls[i]));
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun seq_puts(seq, "\n");
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun return 0;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun const struct seq_operations ax25_rt_seqops = {
333*4882a593Smuzhiyun .start = ax25_rt_seq_start,
334*4882a593Smuzhiyun .next = ax25_rt_seq_next,
335*4882a593Smuzhiyun .stop = ax25_rt_seq_stop,
336*4882a593Smuzhiyun .show = ax25_rt_seq_show,
337*4882a593Smuzhiyun };
338*4882a593Smuzhiyun #endif
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /*
341*4882a593Smuzhiyun * Find AX.25 route
342*4882a593Smuzhiyun *
343*4882a593Smuzhiyun * Only routes with a reference count of zero can be destroyed.
344*4882a593Smuzhiyun * Must be called with ax25_route_lock read locked.
345*4882a593Smuzhiyun */
ax25_get_route(ax25_address * addr,struct net_device * dev)346*4882a593Smuzhiyun ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun ax25_route *ax25_spe_rt = NULL;
349*4882a593Smuzhiyun ax25_route *ax25_def_rt = NULL;
350*4882a593Smuzhiyun ax25_route *ax25_rt;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun /*
353*4882a593Smuzhiyun * Bind to the physical interface we heard them on, or the default
354*4882a593Smuzhiyun * route if none is found;
355*4882a593Smuzhiyun */
356*4882a593Smuzhiyun for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
357*4882a593Smuzhiyun if (dev == NULL) {
358*4882a593Smuzhiyun if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
359*4882a593Smuzhiyun ax25_spe_rt = ax25_rt;
360*4882a593Smuzhiyun if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
361*4882a593Smuzhiyun ax25_def_rt = ax25_rt;
362*4882a593Smuzhiyun } else {
363*4882a593Smuzhiyun if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev)
364*4882a593Smuzhiyun ax25_spe_rt = ax25_rt;
365*4882a593Smuzhiyun if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev == dev)
366*4882a593Smuzhiyun ax25_def_rt = ax25_rt;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun ax25_rt = ax25_def_rt;
371*4882a593Smuzhiyun if (ax25_spe_rt != NULL)
372*4882a593Smuzhiyun ax25_rt = ax25_spe_rt;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun return ax25_rt;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun /*
378*4882a593Smuzhiyun * Adjust path: If you specify a default route and want to connect
379*4882a593Smuzhiyun * a target on the digipeater path but w/o having a special route
380*4882a593Smuzhiyun * set before, the path has to be truncated from your target on.
381*4882a593Smuzhiyun */
ax25_adjust_path(ax25_address * addr,ax25_digi * digipeat)382*4882a593Smuzhiyun static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun int k;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun for (k = 0; k < digipeat->ndigi; k++) {
387*4882a593Smuzhiyun if (ax25cmp(addr, &digipeat->calls[k]) == 0)
388*4882a593Smuzhiyun break;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun digipeat->ndigi = k;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun /*
396*4882a593Smuzhiyun * Find which interface to use.
397*4882a593Smuzhiyun */
ax25_rt_autobind(ax25_cb * ax25,ax25_address * addr)398*4882a593Smuzhiyun int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun ax25_uid_assoc *user;
401*4882a593Smuzhiyun ax25_route *ax25_rt;
402*4882a593Smuzhiyun int err = 0;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun ax25_route_lock_use();
405*4882a593Smuzhiyun ax25_rt = ax25_get_route(addr, NULL);
406*4882a593Smuzhiyun if (!ax25_rt) {
407*4882a593Smuzhiyun ax25_route_lock_unuse();
408*4882a593Smuzhiyun return -EHOSTUNREACH;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) {
411*4882a593Smuzhiyun err = -EHOSTUNREACH;
412*4882a593Smuzhiyun goto put;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun user = ax25_findbyuid(current_euid());
416*4882a593Smuzhiyun if (user) {
417*4882a593Smuzhiyun ax25->source_addr = user->call;
418*4882a593Smuzhiyun ax25_uid_put(user);
419*4882a593Smuzhiyun } else {
420*4882a593Smuzhiyun if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
421*4882a593Smuzhiyun err = -EPERM;
422*4882a593Smuzhiyun goto put;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun ax25->source_addr = *(ax25_address *)ax25->ax25_dev->dev->dev_addr;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun if (ax25_rt->digipeat != NULL) {
428*4882a593Smuzhiyun ax25->digipeat = kmemdup(ax25_rt->digipeat, sizeof(ax25_digi),
429*4882a593Smuzhiyun GFP_ATOMIC);
430*4882a593Smuzhiyun if (ax25->digipeat == NULL) {
431*4882a593Smuzhiyun err = -ENOMEM;
432*4882a593Smuzhiyun goto put;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun ax25_adjust_path(addr, ax25->digipeat);
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun if (ax25->sk != NULL) {
438*4882a593Smuzhiyun local_bh_disable();
439*4882a593Smuzhiyun bh_lock_sock(ax25->sk);
440*4882a593Smuzhiyun sock_reset_flag(ax25->sk, SOCK_ZAPPED);
441*4882a593Smuzhiyun bh_unlock_sock(ax25->sk);
442*4882a593Smuzhiyun local_bh_enable();
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun put:
446*4882a593Smuzhiyun ax25_route_lock_unuse();
447*4882a593Smuzhiyun return err;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
ax25_rt_build_path(struct sk_buff * skb,ax25_address * src,ax25_address * dest,ax25_digi * digi)450*4882a593Smuzhiyun struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
451*4882a593Smuzhiyun ax25_address *dest, ax25_digi *digi)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun struct sk_buff *skbn;
454*4882a593Smuzhiyun unsigned char *bp;
455*4882a593Smuzhiyun int len;
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun len = digi->ndigi * AX25_ADDR_LEN;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun if (skb_headroom(skb) < len) {
460*4882a593Smuzhiyun if ((skbn = skb_realloc_headroom(skb, len)) == NULL) {
461*4882a593Smuzhiyun printk(KERN_CRIT "AX.25: ax25_dg_build_path - out of memory\n");
462*4882a593Smuzhiyun return NULL;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun if (skb->sk != NULL)
466*4882a593Smuzhiyun skb_set_owner_w(skbn, skb->sk);
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun consume_skb(skb);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun skb = skbn;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun bp = skb_push(skb, len);
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun ax25_addr_build(bp, src, dest, digi, AX25_COMMAND, AX25_MODULUS);
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun return skb;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun /*
481*4882a593Smuzhiyun * Free all memory associated with routing structures.
482*4882a593Smuzhiyun */
ax25_rt_free(void)483*4882a593Smuzhiyun void __exit ax25_rt_free(void)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun ax25_route *s, *ax25_rt = ax25_route_list;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun write_lock_bh(&ax25_route_lock);
488*4882a593Smuzhiyun while (ax25_rt != NULL) {
489*4882a593Smuzhiyun s = ax25_rt;
490*4882a593Smuzhiyun ax25_rt = ax25_rt->next;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun kfree(s->digipeat);
493*4882a593Smuzhiyun kfree(s);
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun write_unlock_bh(&ax25_route_lock);
496*4882a593Smuzhiyun }
497