~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ax25/ax25_route.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  *
  4  * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
  5  * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  6  * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
  7  * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
  8  * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
  9  * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
 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  *      Adjust path: If you specify a default route and want to connect
378  *      a target on the digipeater path but w/o having a special route
379  *      set before, the path has to be truncated from your target on.
380  */
381 static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
382 {
383         int k;
384 
385         for (k = 0; k < digipeat->ndigi; k++) {
386                 if (ax25cmp(addr, &digipeat->calls[k]) == 0)
387                         break;
388         }
389 
390         digipeat->ndigi = k;
391 }
392 
393 
394 /*
395  *      Find which interface to use.
396  */
397 int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
398 {
399         ax25_uid_assoc *user;
400         ax25_route *ax25_rt;
401         int err = 0;
402 
403         ax25_route_lock_use();
404         ax25_rt = ax25_get_route(addr, NULL);
405         if (!ax25_rt) {
406                 ax25_route_lock_unuse();
407                 return -EHOSTUNREACH;
408         }
409         if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) {
410                 err = -EHOSTUNREACH;
411                 goto put;
412         }
413 
414         user = ax25_findbyuid(current_euid());
415         if (user) {
416                 ax25->source_addr = user->call;
417                 ax25_uid_put(user);
418         } else {
419                 if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
420                         err = -EPERM;
421                         goto put;
422                 }
423                 ax25->source_addr = *(ax25_address *)ax25->ax25_dev->dev->dev_addr;
424         }
425 
426         if (ax25_rt->digipeat != NULL) {
427                 ax25->digipeat = kmemdup(ax25_rt->digipeat, sizeof(ax25_digi),
428                                          GFP_ATOMIC);
429                 if (ax25->digipeat == NULL) {
430                         err = -ENOMEM;
431                         goto put;
432                 }
433                 ax25_adjust_path(addr, ax25->digipeat);
434         }
435 
436         if (ax25->sk != NULL) {
437                 local_bh_disable();
438                 bh_lock_sock(ax25->sk);
439                 sock_reset_flag(ax25->sk, SOCK_ZAPPED);
440                 bh_unlock_sock(ax25->sk);
441                 local_bh_enable();
442         }
443 
444 put:
445         ax25_route_lock_unuse();
446         return err;
447 }
448 
449 struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
450         ax25_address *dest, ax25_digi *digi)
451 {
452         unsigned char *bp;
453         int len;
454 
455         len = digi->ndigi * AX25_ADDR_LEN;
456 
457         if (unlikely(skb_headroom(skb) < len)) {
458                 skb = skb_expand_head(skb, len);
459                 if (!skb) {
460                         printk(KERN_CRIT "AX.25: ax25_dg_build_path - out of memory\n");
461                         return NULL;
462                 }
463         }
464 
465         bp = skb_push(skb, len);
466 
467         ax25_addr_build(bp, src, dest, digi, AX25_COMMAND, AX25_MODULUS);
468 
469         return skb;
470 }
471 
472 /*
473  *      Free all memory associated with routing structures.
474  */
475 void __exit ax25_rt_free(void)
476 {
477         ax25_route *s, *ax25_rt = ax25_route_list;
478 
479         write_lock_bh(&ax25_route_lock);
480         while (ax25_rt != NULL) {
481                 s       = ax25_rt;
482                 ax25_rt = ax25_rt->next;
483 
484                 kfree(s->digipeat);
485                 kfree(s);
486         }
487         write_unlock_bh(&ax25_route_lock);
488 }
489 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php