linux/net/ax25/ax25_route.c
<<
>>
Prefs
   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
  39static ax25_route *ax25_route_list;
  40DEFINE_RWLOCK(ax25_route_lock);
  41
  42void 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
  72static 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 ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
  79                return -EINVAL;
  80        if (route->digi_count > AX25_MAX_DIGIS)
  81                return -EINVAL;
  82
  83        write_lock_bh(&ax25_route_lock);
  84
  85        ax25_rt = ax25_route_list;
  86        while (ax25_rt != NULL) {
  87                if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 &&
  88                            ax25_rt->dev == ax25_dev->dev) {
  89                        kfree(ax25_rt->digipeat);
  90                        ax25_rt->digipeat = NULL;
  91                        if (route->digi_count != 0) {
  92                                if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
  93                                        write_unlock_bh(&ax25_route_lock);
  94                                        return -ENOMEM;
  95                                }
  96                                ax25_rt->digipeat->lastrepeat = -1;
  97                                ax25_rt->digipeat->ndigi      = route->digi_count;
  98                                for (i = 0; i < route->digi_count; i++) {
  99                                        ax25_rt->digipeat->repeated[i] = 0;
 100                                        ax25_rt->digipeat->calls[i]    = route->digi_addr[i];
 101                                }
 102                        }
 103                        write_unlock_bh(&ax25_route_lock);
 104                        return 0;
 105                }
 106                ax25_rt = ax25_rt->next;
 107        }
 108
 109        if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
 110                write_unlock_bh(&ax25_route_lock);
 111                return -ENOMEM;
 112        }
 113
 114        refcount_set(&ax25_rt->refcount, 1);
 115        ax25_rt->callsign     = route->dest_addr;
 116        ax25_rt->dev          = ax25_dev->dev;
 117        ax25_rt->digipeat     = NULL;
 118        ax25_rt->ip_mode      = ' ';
 119        if (route->digi_count != 0) {
 120                if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
 121                        write_unlock_bh(&ax25_route_lock);
 122                        kfree(ax25_rt);
 123                        return -ENOMEM;
 124                }
 125                ax25_rt->digipeat->lastrepeat = -1;
 126                ax25_rt->digipeat->ndigi      = route->digi_count;
 127                for (i = 0; i < route->digi_count; i++) {
 128                        ax25_rt->digipeat->repeated[i] = 0;
 129                        ax25_rt->digipeat->calls[i]    = route->digi_addr[i];
 130                }
 131        }
 132        ax25_rt->next   = ax25_route_list;
 133        ax25_route_list = ax25_rt;
 134        write_unlock_bh(&ax25_route_lock);
 135
 136        return 0;
 137}
 138
 139void __ax25_put_route(ax25_route *ax25_rt)
 140{
 141        kfree(ax25_rt->digipeat);
 142        kfree(ax25_rt);
 143}
 144
 145static int ax25_rt_del(struct ax25_routes_struct *route)
 146{
 147        ax25_route *s, *t, *ax25_rt;
 148        ax25_dev *ax25_dev;
 149
 150        if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
 151                return -EINVAL;
 152
 153        write_lock_bh(&ax25_route_lock);
 154
 155        ax25_rt = ax25_route_list;
 156        while (ax25_rt != NULL) {
 157                s       = ax25_rt;
 158                ax25_rt = ax25_rt->next;
 159                if (s->dev == ax25_dev->dev &&
 160                    ax25cmp(&route->dest_addr, &s->callsign) == 0) {
 161                        if (ax25_route_list == s) {
 162                                ax25_route_list = s->next;
 163                                ax25_put_route(s);
 164                        } else {
 165                                for (t = ax25_route_list; t != NULL; t = t->next) {
 166                                        if (t->next == s) {
 167                                                t->next = s->next;
 168                                                ax25_put_route(s);
 169                                                break;
 170                                        }
 171                                }
 172                        }
 173                }
 174        }
 175        write_unlock_bh(&ax25_route_lock);
 176
 177        return 0;
 178}
 179
 180static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
 181{
 182        ax25_route *ax25_rt;
 183        ax25_dev *ax25_dev;
 184        int err = 0;
 185
 186        if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL)
 187                return -EINVAL;
 188
 189        write_lock_bh(&ax25_route_lock);
 190
 191        ax25_rt = ax25_route_list;
 192        while (ax25_rt != NULL) {
 193                if (ax25_rt->dev == ax25_dev->dev &&
 194                    ax25cmp(&rt_option->dest_addr, &ax25_rt->callsign) == 0) {
 195                        switch (rt_option->cmd) {
 196                        case AX25_SET_RT_IPMODE:
 197                                switch (rt_option->arg) {
 198                                case ' ':
 199                                case 'D':
 200                                case 'V':
 201                                        ax25_rt->ip_mode = rt_option->arg;
 202                                        break;
 203                                default:
 204                                        err = -EINVAL;
 205                                        goto out;
 206                                }
 207                                break;
 208                        default:
 209                                err = -EINVAL;
 210                                goto out;
 211                        }
 212                }
 213                ax25_rt = ax25_rt->next;
 214        }
 215
 216out:
 217        write_unlock_bh(&ax25_route_lock);
 218        return err;
 219}
 220
 221int ax25_rt_ioctl(unsigned int cmd, void __user *arg)
 222{
 223        struct ax25_route_opt_struct rt_option;
 224        struct ax25_routes_struct route;
 225
 226        switch (cmd) {
 227        case SIOCADDRT:
 228                if (copy_from_user(&route, arg, sizeof(route)))
 229                        return -EFAULT;
 230                return ax25_rt_add(&route);
 231
 232        case SIOCDELRT:
 233                if (copy_from_user(&route, arg, sizeof(route)))
 234                        return -EFAULT;
 235                return ax25_rt_del(&route);
 236
 237        case SIOCAX25OPTRT:
 238                if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
 239                        return -EFAULT;
 240                return ax25_rt_opt(&rt_option);
 241
 242        default:
 243                return -EINVAL;
 244        }
 245}
 246
 247#ifdef CONFIG_PROC_FS
 248
 249static void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos)
 250        __acquires(ax25_route_lock)
 251{
 252        struct ax25_route *ax25_rt;
 253        int i = 1;
 254
 255        read_lock(&ax25_route_lock);
 256        if (*pos == 0)
 257                return SEQ_START_TOKEN;
 258
 259        for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 260                if (i == *pos)
 261                        return ax25_rt;
 262                ++i;
 263        }
 264
 265        return NULL;
 266}
 267
 268static void *ax25_rt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 269{
 270        ++*pos;
 271        return (v == SEQ_START_TOKEN) ? ax25_route_list :
 272                ((struct ax25_route *) v)->next;
 273}
 274
 275static void ax25_rt_seq_stop(struct seq_file *seq, void *v)
 276        __releases(ax25_route_lock)
 277{
 278        read_unlock(&ax25_route_lock);
 279}
 280
 281static int ax25_rt_seq_show(struct seq_file *seq, void *v)
 282{
 283        char buf[11];
 284
 285        if (v == SEQ_START_TOKEN)
 286                seq_puts(seq, "callsign  dev  mode digipeaters\n");
 287        else {
 288                struct ax25_route *ax25_rt = v;
 289                const char *callsign;
 290                int i;
 291
 292                if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
 293                        callsign = "default";
 294                else
 295                        callsign = ax2asc(buf, &ax25_rt->callsign);
 296
 297                seq_printf(seq, "%-9s %-4s",
 298                        callsign,
 299                        ax25_rt->dev ? ax25_rt->dev->name : "???");
 300
 301                switch (ax25_rt->ip_mode) {
 302                case 'V':
 303                        seq_puts(seq, "   vc");
 304                        break;
 305                case 'D':
 306                        seq_puts(seq, "   dg");
 307                        break;
 308                default:
 309                        seq_puts(seq, "    *");
 310                        break;
 311                }
 312
 313                if (ax25_rt->digipeat != NULL)
 314                        for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
 315                                seq_printf(seq, " %s",
 316                                     ax2asc(buf, &ax25_rt->digipeat->calls[i]));
 317
 318                seq_puts(seq, "\n");
 319        }
 320        return 0;
 321}
 322
 323const struct seq_operations ax25_rt_seqops = {
 324        .start = ax25_rt_seq_start,
 325        .next = ax25_rt_seq_next,
 326        .stop = ax25_rt_seq_stop,
 327        .show = ax25_rt_seq_show,
 328};
 329#endif
 330
 331/*
 332 *      Find AX.25 route
 333 *
 334 *      Only routes with a reference count of zero can be destroyed.
 335 *      Must be called with ax25_route_lock read locked.
 336 */
 337ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
 338{
 339        ax25_route *ax25_spe_rt = NULL;
 340        ax25_route *ax25_def_rt = NULL;
 341        ax25_route *ax25_rt;
 342
 343        /*
 344         *      Bind to the physical interface we heard them on, or the default
 345         *      route if none is found;
 346         */
 347        for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 348                if (dev == NULL) {
 349                        if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
 350                                ax25_spe_rt = ax25_rt;
 351                        if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
 352                                ax25_def_rt = ax25_rt;
 353                } else {
 354                        if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev)
 355                                ax25_spe_rt = ax25_rt;
 356                        if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev == dev)
 357                                ax25_def_rt = ax25_rt;
 358                }
 359        }
 360
 361        ax25_rt = ax25_def_rt;
 362        if (ax25_spe_rt != NULL)
 363                ax25_rt = ax25_spe_rt;
 364
 365        return ax25_rt;
 366}
 367
 368/*
 369 *      Adjust path: If you specify a default route and want to connect
 370 *      a target on the digipeater path but w/o having a special route
 371 *      set before, the path has to be truncated from your target on.
 372 */
 373static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
 374{
 375        int k;
 376
 377        for (k = 0; k < digipeat->ndigi; k++) {
 378                if (ax25cmp(addr, &digipeat->calls[k]) == 0)
 379                        break;
 380        }
 381
 382        digipeat->ndigi = k;
 383}
 384
 385
 386/*
 387 *      Find which interface to use.
 388 */
 389int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
 390{
 391        ax25_uid_assoc *user;
 392        ax25_route *ax25_rt;
 393        int err = 0;
 394
 395        ax25_route_lock_use();
 396        ax25_rt = ax25_get_route(addr, NULL);
 397        if (!ax25_rt) {
 398                ax25_route_lock_unuse();
 399                return -EHOSTUNREACH;
 400        }
 401        if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) {
 402                err = -EHOSTUNREACH;
 403                goto put;
 404        }
 405
 406        user = ax25_findbyuid(current_euid());
 407        if (user) {
 408                ax25->source_addr = user->call;
 409                ax25_uid_put(user);
 410        } else {
 411                if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
 412                        err = -EPERM;
 413                        goto put;
 414                }
 415                ax25->source_addr = *(ax25_address *)ax25->ax25_dev->dev->dev_addr;
 416        }
 417
 418        if (ax25_rt->digipeat != NULL) {
 419                ax25->digipeat = kmemdup(ax25_rt->digipeat, sizeof(ax25_digi),
 420                                         GFP_ATOMIC);
 421                if (ax25->digipeat == NULL) {
 422                        err = -ENOMEM;
 423                        goto put;
 424                }
 425                ax25_adjust_path(addr, ax25->digipeat);
 426        }
 427
 428        if (ax25->sk != NULL) {
 429                local_bh_disable();
 430                bh_lock_sock(ax25->sk);
 431                sock_reset_flag(ax25->sk, SOCK_ZAPPED);
 432                bh_unlock_sock(ax25->sk);
 433                local_bh_enable();
 434        }
 435
 436put:
 437        ax25_route_lock_unuse();
 438        return err;
 439}
 440
 441struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
 442        ax25_address *dest, ax25_digi *digi)
 443{
 444        unsigned char *bp;
 445        int len;
 446
 447        len = digi->ndigi * AX25_ADDR_LEN;
 448
 449        if (unlikely(skb_headroom(skb) < len)) {
 450                skb = skb_expand_head(skb, len);
 451                if (!skb) {
 452                        printk(KERN_CRIT "AX.25: ax25_dg_build_path - out of memory\n");
 453                        return NULL;
 454                }
 455        }
 456
 457        bp = skb_push(skb, len);
 458
 459        ax25_addr_build(bp, src, dest, digi, AX25_COMMAND, AX25_MODULUS);
 460
 461        return skb;
 462}
 463
 464/*
 465 *      Free all memory associated with routing structures.
 466 */
 467void __exit ax25_rt_free(void)
 468{
 469        ax25_route *s, *ax25_rt = ax25_route_list;
 470
 471        write_lock_bh(&ax25_route_lock);
 472        while (ax25_rt != NULL) {
 473                s       = ax25_rt;
 474                ax25_rt = ax25_rt->next;
 475
 476                kfree(s->digipeat);
 477                kfree(s);
 478        }
 479        write_unlock_bh(&ax25_route_lock);
 480}
 481