linux/net/netrom/nr_route.c History
<<
>>
Prefs
   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 Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
   8 * Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
   9 * Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
  10 */
  11#include <linux/errno.h>
  12#include <linux/types.h>
  13#include <linux/socket.h>
  14#include <linux/in.h>
  15#include <linux/kernel.h>
  16#include <linux/timer.h>
  17#include <linux/string.h>
  18#include <linux/sockios.h>
  19#include <linux/net.h>
  20#include <net/ax25.h>
  21#include <linux/inet.h>
  22#include <linux/netdevice.h>
  23#include <net/arp.h>
  24#include <linux/if_arp.h>
  25#include <linux/skbuff.h>
  26#include <net/sock.h>
  27#include <asm/uaccess.h>
  28#include <asm/system.h>
  29#include <linux/fcntl.h>
  30#include <linux/termios.h>      /* For TIOCINQ/OUTQ */
  31#include <linux/mm.h>
  32#include <linux/interrupt.h>
  33#include <linux/notifier.h>
  34#include <linux/netfilter.h>
  35#include <linux/init.h>
  36#include <linux/spinlock.h>
  37#include <net/netrom.h>
  38#include <linux/seq_file.h>
  39
  40static unsigned int nr_neigh_no = 1;
  41
  42static HLIST_HEAD(nr_node_list);
  43static DEFINE_SPINLOCK(nr_node_list_lock);
  44static HLIST_HEAD(nr_neigh_list);
  45static DEFINE_SPINLOCK(nr_neigh_list_lock);
  46
  47static struct nr_node *nr_node_get(ax25_address *callsign)
  48{
  49        struct nr_node *found = NULL;
  50        struct nr_node *nr_node;
  51        struct hlist_node *node;
  52
  53        spin_lock_bh(&nr_node_list_lock);
  54        nr_node_for_each(nr_node, node, &nr_node_list)
  55                if (ax25cmp(callsign, &nr_node->callsign) == 0) {
  56                        nr_node_hold(nr_node);
  57                        found = nr_node;
  58                        break;
  59                }
  60        spin_unlock_bh(&nr_node_list_lock);
  61        return found;
  62}
  63
  64static struct nr_neigh *nr_neigh_get_dev(ax25_address *callsign,
  65                                         struct net_device *dev)
  66{
  67        struct nr_neigh *found = NULL;
  68        struct nr_neigh *nr_neigh;
  69        struct hlist_node *node;
  70
  71        spin_lock_bh(&nr_neigh_list_lock);
  72        nr_neigh_for_each(nr_neigh, node, &nr_neigh_list)
  73                if (ax25cmp(callsign, &nr_neigh->callsign) == 0 &&
  74                    nr_neigh->dev == dev) {
  75                        nr_neigh_hold(nr_neigh);
  76                        found = nr_neigh;
  77                        break;
  78                }
  79        spin_unlock_bh(&nr_neigh_list_lock);
  80        return found;
  81}
  82
  83static void nr_remove_neigh(struct nr_neigh *);
  84
  85/*
  86 *      Add a new route to a node, and in the process add the node and the
  87 *      neighbour if it is new.
  88 */
  89static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
  90        ax25_address *ax25, ax25_digi *ax25_digi, struct net_device *dev,
  91        int quality, int obs_count)
  92{
  93        struct nr_node  *nr_node;
  94        struct nr_neigh *nr_neigh;
  95        struct nr_route nr_route;
  96        int i, found;
  97        struct net_device *odev;
  98
  99        if ((odev=nr_dev_get(nr)) != NULL) {    /* Can't add routes to ourself */
 100                dev_put(odev);
 101                return -EINVAL;
 102        }
 103
 104        nr_node = nr_node_get(nr);
 105
 106        nr_neigh = nr_neigh_get_dev(ax25, dev);
 107
 108        /*
 109         * The L2 link to a neighbour has failed in the past
 110         * and now a frame comes from this neighbour. We assume
 111         * it was a temporary trouble with the link and reset the
 112         * routes now (and not wait for a node broadcast).
 113         */
 114        if (nr_neigh != NULL && nr_neigh->failed != 0 && quality == 0) {
 115                struct nr_node *nr_nodet;
 116                struct hlist_node *node;
 117
 118                spin_lock_bh(&nr_node_list_lock);
 119                nr_node_for_each(nr_nodet, node, &nr_node_list) {
 120                        nr_node_lock(nr_nodet);
 121                        for (i = 0; i < nr_nodet->count; i++)
 122                                if (nr_nodet->routes[i].neighbour == nr_neigh)
 123                                        if (i < nr_nodet->which)
 124                                                nr_nodet->which = i;
 125                        nr_node_unlock(nr_nodet);
 126                }
 127                spin_unlock_bh(&nr_node_list_lock);
 128        }
 129
 130        if (nr_neigh != NULL)
 131                nr_neigh->failed = 0;
 132
 133        if (quality == 0 && nr_neigh != NULL && nr_node != NULL) {
 134                nr_neigh_put(nr_neigh);
 135                nr_node_put(nr_node);
 136                return 0;
 137        }
 138
 139        if (nr_neigh == NULL) {
 140                if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) {
 141                        if (nr_node)
 142                                nr_node_put(nr_node);
 143                        return -ENOMEM;
 144                }
 145
 146                nr_neigh->callsign = *ax25;
 147                nr_neigh->digipeat = NULL;
 148                nr_neigh->ax25     = NULL;
 149                nr_neigh->dev      = dev;
 150                nr_neigh->quality  = sysctl_netrom_default_path_quality;
 151                nr_neigh->locked   = 0;
 152                nr_neigh->count    = 0;
 153                nr_neigh->number   = nr_neigh_no++;
 154                nr_neigh->failed   = 0;
 155                atomic_set(&nr_neigh->refcount, 1);
 156
 157                if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
 158                        nr_neigh->digipeat = kmemdup(ax25_digi,
 159                                                     sizeof(*ax25_digi),
 160                                                     GFP_KERNEL);
 161                        if (nr_neigh->digipeat == NULL) {
 162                                kfree(nr_neigh);
 163                                if (nr_node)
 164                                        nr_node_put(nr_node);
 165                                return -ENOMEM;
 166                        }
 167                }
 168
 169                spin_lock_bh(&nr_neigh_list_lock);
 170                hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list);
 171                nr_neigh_hold(nr_neigh);
 172                spin_unlock_bh(&nr_neigh_list_lock);
 173        }
 174
 175        if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked)
 176                nr_neigh->quality = quality;
 177
 178        if (nr_node == NULL) {
 179                if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL) {
 180                        if (nr_neigh)
 181                                nr_neigh_put(nr_neigh);
 182                        return -ENOMEM;
 183                }
 184
 185                nr_node->callsign = *nr;
 186                strcpy(nr_node->mnemonic, mnemonic);
 187
 188                nr_node->which = 0;
 189                nr_node->count = 1;
 190                atomic_set(&nr_node->refcount, 1);
 191                spin_lock_init(&nr_node->node_lock);
 192
 193                nr_node->routes[0].quality   = quality;
 194                nr_node->routes[0].obs_count = obs_count;
 195                nr_node->routes[0].neighbour = nr_neigh;
 196
 197                nr_neigh_hold(nr_neigh);
 198                nr_neigh->count++;
 199
 200                spin_lock_bh(&nr_node_list_lock);
 201                hlist_add_head(&nr_node->node_node, &nr_node_list);
 202                /* refcount initialized at 1 */
 203                spin_unlock_bh(&nr_node_list_lock);
 204
 205                return 0;
 206        }
 207        nr_node_lock(nr_node);
 208
 209        if (quality != 0)
 210                strcpy(nr_node->mnemonic, mnemonic);
 211
 212        for (found = 0, i = 0; i < nr_node->count; i++) {
 213                if (nr_node->routes[i].neighbour == nr_neigh) {
 214                        nr_node->routes[i].quality   = quality;
 215                        nr_node->routes[i].obs_count = obs_count;
 216                        found = 1;
 217                        break;
 218                }
 219        }
 220
 221        if (!found) {
 222                /* We have space at the bottom, slot it in */
 223                if (nr_node->count < 3) {
 224                        nr_node->routes[2] = nr_node->routes[1];
 225                        nr_node->routes[1] = nr_node->routes[0];
 226
 227                        nr_node->routes[0].quality   = quality;
 228                        nr_node->routes[0].obs_count = obs_count;
 229                        nr_node->routes[0].neighbour = nr_neigh;
 230
 231                        nr_node->which++;
 232                        nr_node->count++;
 233                        nr_neigh_hold(nr_neigh);
 234                        nr_neigh->count++;
 235                } else {
 236                        /* It must be better than the worst */
 237                        if (quality > nr_node->routes[2].quality) {
 238                                nr_node->routes[2].neighbour->count--;
 239                                nr_neigh_put(nr_node->routes[2].neighbour);
 240
 241                                if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
 242                                        nr_remove_neigh(nr_node->routes[2].neighbour);
 243
 244                                nr_node->routes[2].quality   = quality;
 245                                nr_node->routes[2].obs_count = obs_count;
 246                                nr_node->routes[2].neighbour = nr_neigh;
 247
 248                                nr_neigh_hold(nr_neigh);
 249                                nr_neigh->count++;
 250                        }
 251                }
 252        }
 253
 254        /* Now re-sort the routes in quality order */
 255        switch (nr_node->count) {
 256        case 3:
 257                if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
 258                        switch (nr_node->which) {
 259                                case 0:  nr_node->which = 1; break;
 260                                case 1:  nr_node->which = 0; break;
 261                                default: break;
 262                        }
 263                        nr_route           = nr_node->routes[0];
 264                        nr_node->routes[0] = nr_node->routes[1];
 265                        nr_node->routes[1] = nr_route;
 266                }
 267                if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
 268                        switch (nr_node->which) {
 269                        case 1:  nr_node->which = 2;
 270                                break;
 271
 272                        case 2:  nr_node->which = 1;
 273                                break;
 274
 275                        default:
 276                                break;
 277                        }
 278                        nr_route           = nr_node->routes[1];
 279                        nr_node->routes[1] = nr_node->routes[2];
 280                        nr_node->routes[2] = nr_route;
 281                }
 282        case 2:
 283                if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
 284                        switch (nr_node->which) {
 285                        case 0:  nr_node->which = 1;
 286                                break;
 287
 288                        case 1:  nr_node->which = 0;
 289                                break;
 290
 291                        default: break;
 292                        }
 293                        nr_route           = nr_node->routes[0];
 294                        nr_node->routes[0] = nr_node->routes[1];
 295                        nr_node->routes[1] = nr_route;
 296                        }
 297        case 1:
 298                break;
 299        }
 300
 301        for (i = 0; i < nr_node->count; i++) {
 302                if (nr_node->routes[i].neighbour == nr_neigh) {
 303                        if (i < nr_node->which)
 304                                nr_node->which = i;
 305                        break;
 306                }
 307        }
 308
 309        nr_neigh_put(nr_neigh);
 310        nr_node_unlock(nr_node);
 311        nr_node_put(nr_node);
 312        return 0;
 313}
 314
 315static inline void __nr_remove_node(struct nr_node *nr_node)
 316{
 317        hlist_del_init(&nr_node->node_node);
 318        nr_node_put(nr_node);
 319}
 320
 321#define nr_remove_node_locked(__node) \
 322        __nr_remove_node(__node)
 323
 324static void nr_remove_node(struct nr_node *nr_node)
 325{
 326        spin_lock_bh(&nr_node_list_lock);
 327        __nr_remove_node(nr_node);
 328        spin_unlock_bh(&nr_node_list_lock);
 329}
 330
 331static inline void __nr_remove_neigh(struct nr_neigh *nr_neigh)
 332{
 333        hlist_del_init(&nr_neigh->neigh_node);
 334        nr_neigh_put(nr_neigh);
 335}
 336
 337#define nr_remove_neigh_locked(__neigh) \
 338        __nr_remove_neigh(__neigh)
 339
 340static void nr_remove_neigh(struct nr_neigh *nr_neigh)
 341{
 342        spin_lock_bh(&nr_neigh_list_lock);
 343        __nr_remove_neigh(nr_neigh);
 344        spin_unlock_bh(&nr_neigh_list_lock);
 345}
 346
 347/*
 348 *      "Delete" a node. Strictly speaking remove a route to a node. The node
 349 *      is only deleted if no routes are left to it.
 350 */
 351static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct net_device *dev)
 352{
 353        struct nr_node  *nr_node;
 354        struct nr_neigh *nr_neigh;
 355        int i;
 356
 357        nr_node = nr_node_get(callsign);
 358
 359        if (nr_node == NULL)
 360                return -EINVAL;
 361
 362        nr_neigh = nr_neigh_get_dev(neighbour, dev);
 363
 364        if (nr_neigh == NULL) {
 365                nr_node_put(nr_node);
 366                return -EINVAL;
 367        }
 368
 369        nr_node_lock(nr_node);
 370        for (i = 0; i < nr_node->count; i++) {
 371                if (nr_node->routes[i].neighbour == nr_neigh) {
 372                        nr_neigh->count--;
 373                        nr_neigh_put(nr_neigh);
 374
 375                        if (nr_neigh->count == 0 && !nr_neigh->locked)
 376                                nr_remove_neigh(nr_neigh);
 377                        nr_neigh_put(nr_neigh);
 378
 379                        nr_node->count--;
 380
 381                        if (nr_node->count == 0) {
 382                                nr_remove_node(nr_node);
 383                        } else {
 384                                switch (i) {
 385                                case 0:
 386                                        nr_node->routes[0] = nr_node->routes[1];
 387                                case 1:
 388                                        nr_node->routes[1] = nr_node->routes[2];
 389                                case 2:
 390                                        break;
 391                                }
 392                                nr_node_put(nr_node);
 393                        }
 394                        nr_node_unlock(nr_node);
 395
 396                        return 0;
 397                }
 398        }
 399        nr_neigh_put(nr_neigh);
 400        nr_node_unlock(nr_node);
 401        nr_node_put(nr_node);
 402
 403        return -EINVAL;
 404}
 405
 406/*
 407 *      Lock a neighbour with a quality.
 408 */
 409static int __must_check nr_add_neigh(ax25_address *callsign,
 410        ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality)
 411{
 412        struct nr_neigh *nr_neigh;
 413
 414        nr_neigh = nr_neigh_get_dev(callsign, dev);
 415        if (nr_neigh) {
 416                nr_neigh->quality = quality;
 417                nr_neigh->locked  = 1;
 418                nr_neigh_put(nr_neigh);
 419                return 0;
 420        }
 421
 422        if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
 423                return -ENOMEM;
 424
 425        nr_neigh->callsign = *callsign;
 426        nr_neigh->digipeat = NULL;
 427        nr_neigh->ax25     = NULL;
 428        nr_neigh->dev      = dev;
 429        nr_neigh->quality  = quality;
 430        nr_neigh->locked   = 1;
 431        nr_neigh->count    = 0;
 432        nr_neigh->number   = nr_neigh_no++;
 433        nr_neigh->failed   = 0;
 434        atomic_set(&nr_neigh->refcount, 1);
 435
 436        if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
 437                nr_neigh->digipeat = kmemdup(ax25_digi, sizeof(*ax25_digi),
 438                                             GFP_KERNEL);
 439                if (nr_neigh->digipeat == NULL) {
 440                        kfree(nr_neigh);
 441                        return -ENOMEM;
 442                }
 443        }
 444
 445        spin_lock_bh(&nr_neigh_list_lock);
 446        hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list);
 447        /* refcount is initialized at 1 */
 448        spin_unlock_bh(&nr_neigh_list_lock);
 449
 450        return 0;
 451}
 452
 453/*
 454 *      "Delete" a neighbour. The neighbour is only removed if the number
 455 *      of nodes that may use it is zero.
 456 */
 457static int nr_del_neigh(ax25_address *callsign, struct net_device *dev, unsigned int quality)
 458{
 459        struct nr_neigh *nr_neigh;
 460
 461        nr_neigh = nr_neigh_get_dev(callsign, dev);
 462
 463        if (nr_neigh == NULL) return -EINVAL;
 464
 465        nr_neigh->quality = quality;
 466        nr_neigh->locked  = 0;
 467
 468        if (nr_neigh->count == 0)
 469                nr_remove_neigh(nr_neigh);
 470        nr_neigh_put(nr_neigh);
 471
 472        return 0;
 473}
 474
 475/*
 476 *      Decrement the obsolescence count by one. If a route is reduced to a
 477 *      count of zero, remove it. Also remove any unlocked neighbours with
 478 *      zero nodes routing via it.
 479 */
 480static int nr_dec_obs(void)
 481{
 482        struct nr_neigh *nr_neigh;
 483        struct nr_node  *s;
 484        struct hlist_node *node, *nodet;
 485        int i;
 486
 487        spin_lock_bh(&nr_node_list_lock);
 488        nr_node_for_each_safe(s, node, nodet, &nr_node_list) {
 489                nr_node_lock(s);
 490                for (i = 0; i < s->count; i++) {
 491                        switch (s->routes[i].obs_count) {
 492                        case 0:         /* A locked entry */
 493                                break;
 494
 495                        case 1:         /* From 1 -> 0 */
 496                                nr_neigh = s->routes[i].neighbour;
 497
 498                                nr_neigh->count--;
 499                                nr_neigh_put(nr_neigh);
 500
 501                                if (nr_neigh->count == 0 && !nr_neigh->locked)
 502                                        nr_remove_neigh(nr_neigh);
 503
 504                                s->count--;
 505
 506                                switch (i) {
 507                                        case 0:
 508                                                s->routes[0] = s->routes[1];
 509                                        case 1:
 510                                                s->routes[1] = s->routes[2];
 511                                        case 2:
 512                                                break;
 513                                }
 514                                break;
 515
 516                        default:
 517                                s->routes[i].obs_count--;
 518                                break;
 519
 520                        }
 521                }
 522
 523                if (s->count <= 0)
 524                        nr_remove_node_locked(s);
 525                nr_node_unlock(s);
 526        }
 527        spin_unlock_bh(&nr_node_list_lock);
 528
 529        return 0;
 530}
 531
 532/*
 533 *      A device has been removed. Remove its routes and neighbours.
 534 */
 535void nr_rt_device_down(struct net_device *dev)
 536{
 537        struct nr_neigh *s;
 538        struct hlist_node *node, *nodet, *node2, *node2t;
 539        struct nr_node  *t;
 540        int i;
 541
 542        spin_lock_bh(&nr_neigh_list_lock);
 543        nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) {
 544                if (s->dev == dev) {
 545                        spin_lock_bh(&nr_node_list_lock);
 546                        nr_node_for_each_safe(t, node2, node2t, &nr_node_list) {
 547                                nr_node_lock(t);
 548                                for (i = 0; i < t->count; i++) {
 549                                        if (t->routes[i].neighbour == s) {
 550                                                t->count--;
 551
 552                                                switch (i) {
 553                                                case 0:
 554                                                        t->routes[0] = t->routes[1];
 555                                                case 1:
 556                                                        t->routes[1] = t->routes[2];
 557                                                case 2:
 558                                                        break;
 559                                                }
 560                                        }
 561                                }
 562
 563                                if (t->count <= 0)
 564                                        nr_remove_node_locked(t);
 565                                nr_node_unlock(t);
 566                        }
 567                        spin_unlock_bh(&nr_node_list_lock);
 568
 569                        nr_remove_neigh_locked(s);
 570                }
 571        }
 572        spin_unlock_bh(&nr_neigh_list_lock);
 573}
 574
 575/*
 576 *      Check that the device given is a valid AX.25 interface that is "up".
 577 *      Or a valid ethernet interface with an AX.25 callsign binding.
 578 */
 579static struct net_device *nr_ax25_dev_get(char *devname)
 580{
 581        struct net_device *dev;
 582
 583        if ((dev = dev_get_by_name(&init_net, devname)) == NULL)
 584                return NULL;
 585
 586        if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
 587                return dev;
 588
 589        dev_put(dev);
 590        return NULL;
 591}
 592
 593/*
 594 *      Find the first active NET/ROM device, usually "nr0".
 595 */
 596struct net_device *nr_dev_first(void)
 597{
 598        struct net_device *dev, *first = NULL;
 599
 600        read_lock(&dev_base_lock);
 601        for_each_netdev(&init_net, dev) {
 602                if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
 603                        if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
 604                                first = dev;
 605        }
 606        if (first)
 607                dev_hold(first);
 608        read_unlock(&dev_base_lock);
 609
 610        return first;
 611}
 612
 613/*
 614 *      Find the NET/ROM device for the given callsign.
 615 */
 616struct net_device *nr_dev_get(ax25_address *addr)
 617{
 618        struct net_device *dev;
 619
 620        read_lock(&dev_base_lock);
 621        for_each_netdev(&init_net, dev) {
 622                if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) {
 623                        dev_hold(dev);
 624                        goto out;
 625                }
 626        }
 627        dev = NULL;
 628out:
 629        read_unlock(&dev_base_lock);
 630        return dev;
 631}
 632
 633static ax25_digi *nr_call_to_digi(ax25_digi *digi, int ndigis,
 634        ax25_address *digipeaters)
 635{
 636        int i;
 637
 638        if (ndigis == 0)
 639                return NULL;
 640
 641        for (i = 0; i < ndigis; i++) {
 642                digi->calls[i]    = digipeaters[i];
 643                digi->repeated[i] = 0;
 644        }
 645
 646        digi->ndigi      = ndigis;
 647        digi->lastrepeat = -1;
 648
 649        return digi;
 650}
 651
 652/*
 653 *      Handle the ioctls that control the routing functions.
 654 */
 655int nr_rt_ioctl(unsigned int cmd, void __user *arg)
 656{
 657        struct nr_route_struct nr_route;
 658        struct net_device *dev;
 659        ax25_digi digi;
 660        int ret;
 661
 662        switch (cmd) {
 663        case SIOCADDRT:
 664                if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
 665                        return -EFAULT;
 666                if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
 667                        return -EINVAL;
 668                if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) {
 669                        dev_put(dev);
 670                        return -EINVAL;
 671                }
 672                switch (nr_route.type) {
 673                case NETROM_NODE:
 674                        ret = nr_add_node(&nr_route.callsign,
 675                                nr_route.mnemonic,
 676                                &nr_route.neighbour,
 677                                nr_call_to_digi(&digi, nr_route.ndigis,
 678                                                nr_route.digipeaters),
 679                                dev, nr_route.quality,
 680                                nr_route.obs_count);
 681                        break;
 682                case NETROM_NEIGH:
 683                        ret = nr_add_neigh(&nr_route.callsign,
 684                                nr_call_to_digi(&digi, nr_route.ndigis,
 685                                                nr_route.digipeaters),
 686                                dev, nr_route.quality);
 687                        break;
 688                default:
 689                        ret = -EINVAL;
 690                }
 691                dev_put(dev);
 692                return ret;
 693
 694        case SIOCDELRT:
 695                if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
 696                        return -EFAULT;
 697                if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
 698                        return -EINVAL;
 699                switch (nr_route.type) {
 700                case NETROM_NODE:
 701                        ret = nr_del_node(&nr_route.callsign,
 702                                &nr_route.neighbour, dev);
 703                        break;
 704                case NETROM_NEIGH:
 705                        ret = nr_del_neigh(&nr_route.callsign,
 706                                dev, nr_route.quality);
 707                        break;
 708                default:
 709                        ret = -EINVAL;
 710                }
 711                dev_put(dev);
 712                return ret;
 713
 714        case SIOCNRDECOBS:
 715                return nr_dec_obs();
 716
 717        default:
 718                return -EINVAL;
 719        }
 720
 721        return 0;
 722}
 723
 724/*
 725 *      A level 2 link has timed out, therefore it appears to be a poor link,
 726 *      then don't use that neighbour until it is reset.
 727 */
 728void nr_link_failed(ax25_cb *ax25, int reason)
 729{
 730        struct nr_neigh *s, *nr_neigh = NULL;
 731        struct hlist_node *node;
 732        struct nr_node  *nr_node = NULL;
 733
 734        spin_lock_bh(&nr_neigh_list_lock);
 735        nr_neigh_for_each(s, node, &nr_neigh_list) {
 736                if (s->ax25 == ax25) {
 737                        nr_neigh_hold(s);
 738                        nr_neigh = s;
 739                        break;
 740                }
 741        }
 742        spin_unlock_bh(&nr_neigh_list_lock);
 743
 744        if (nr_neigh == NULL)
 745                return;
 746
 747        nr_neigh->ax25 = NULL;
 748        ax25_cb_put(ax25);
 749
 750        if (++nr_neigh->failed < sysctl_netrom_link_fails_count) {
 751                nr_neigh_put(nr_neigh);
 752                return;
 753        }
 754        spin_lock_bh(&nr_node_list_lock);
 755        nr_node_for_each(nr_node, node, &nr_node_list) {
 756                nr_node_lock(nr_node);
 757                if (nr_node->which < nr_node->count &&
 758                    nr_node->routes[nr_node->which].neighbour == nr_neigh)
 759                        nr_node->which++;
 760                nr_node_unlock(nr_node);
 761        }
 762        spin_unlock_bh(&nr_node_list_lock);
 763        nr_neigh_put(nr_neigh);
 764}
 765
 766/*
 767 *      Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
 768 *      indicates an internally generated frame.
 769 */
 770int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
 771{
 772        ax25_address *nr_src, *nr_dest;
 773        struct nr_neigh *nr_neigh;
 774        struct nr_node  *nr_node;
 775        struct net_device *dev;
 776        unsigned char *dptr;
 777        ax25_cb *ax25s;
 778        int ret;
 779        struct sk_buff *skbn;
 780
 781
 782        nr_src  = (ax25_address *)(skb->data + 0);
 783        nr_dest = (ax25_address *)(skb->data + 7);
 784
 785        if (ax25 != NULL) {
 786                ret = nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
 787                                  ax25->ax25_dev->dev, 0,
 788                                  sysctl_netrom_obsolescence_count_initialiser);
 789                if (ret)
 790                        return ret;
 791        }
 792
 793        if ((dev = nr_dev_get(nr_dest)) != NULL) {      /* Its for me */
 794                if (ax25 == NULL)                       /* Its from me */
 795                        ret = nr_loopback_queue(skb);
 796                else
 797                        ret = nr_rx_frame(skb, dev);
 798                dev_put(dev);
 799                return ret;
 800        }
 801
 802        if (!sysctl_netrom_routing_control && ax25 != NULL)
 803                return 0;
 804
 805        /* Its Time-To-Live has expired */
 806        if (skb->data[14] == 1) {
 807                return 0;
 808        }
 809
 810        nr_node = nr_node_get(nr_dest);
 811        if (nr_node == NULL)
 812                return 0;
 813        nr_node_lock(nr_node);
 814
 815        if (nr_node->which >= nr_node->count) {
 816                nr_node_unlock(nr_node);
 817                nr_node_put(nr_node);
 818                return 0;
 819        }
 820
 821        nr_neigh = nr_node->routes[nr_node->which].neighbour;
 822
 823        if ((dev = nr_dev_first()) == NULL) {
 824                nr_node_unlock(nr_node);
 825                nr_node_put(nr_node);
 826                return 0;
 827        }
 828
 829        /* We are going to change the netrom headers so we should get our
 830           own skb, we also did not know until now how much header space
 831           we had to reserve... - RXQ */
 832        if ((skbn=skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC)) == NULL) {
 833                nr_node_unlock(nr_node);
 834                nr_node_put(nr_node);
 835                dev_put(dev);
 836                return 0;
 837        }
 838        kfree_skb(skb);
 839        skb=skbn;
 840        skb->data[14]--;
 841
 842        dptr  = skb_push(skb, 1);
 843        *dptr = AX25_P_NETROM;
 844
 845        ax25s = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
 846        if (nr_neigh->ax25 && ax25s) {
 847                /* We were already holding this ax25_cb */
 848                ax25_cb_put(ax25s);
 849        }
 850        nr_neigh->ax25 = ax25s;
 851
 852        dev_put(dev);
 853        ret = (nr_neigh->ax25 != NULL);
 854        nr_node_unlock(nr_node);
 855        nr_node_put(nr_node);
 856
 857        return ret;
 858}
 859
 860#ifdef CONFIG_PROC_FS
 861
 862static void *nr_node_start(struct seq_file *seq, loff_t *pos)
 863{
 864        struct nr_node *nr_node;
 865        struct hlist_node *node;
 866        int i = 1;
 867
 868        spin_lock_bh(&nr_node_list_lock);
 869        if (*pos == 0)
 870                return SEQ_START_TOKEN;
 871
 872        nr_node_for_each(nr_node, node, &nr_node_list) {
 873                if (i == *pos)
 874                        return nr_node;
 875                ++i;
 876        }
 877
 878        return NULL;
 879}
 880
 881static void *nr_node_next(struct seq_file *seq, void *v, loff_t *pos)
 882{
 883        struct hlist_node *node;
 884        ++*pos;
 885
 886        node = (v == SEQ_START_TOKEN)
 887                ? nr_node_list.first
 888                : ((struct nr_node *)v)->node_node.next;
 889
 890        return hlist_entry(node, struct nr_node, node_node);
 891}
 892
 893static void nr_node_stop(struct seq_file *seq, void *v)
 894{
 895        spin_unlock_bh(&nr_node_list_lock);
 896}
 897
 898static int nr_node_show(struct seq_file *seq, void *v)
 899{
 900        char buf[11];
 901        int i;
 902
 903        if (v == SEQ_START_TOKEN)
 904                seq_puts(seq,
 905                         "callsign  mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
 906        else {
 907                struct nr_node *nr_node = v;
 908                nr_node_lock(nr_node);
 909                seq_printf(seq, "%-9s %-7s  %d %d",
 910                        ax2asc(buf, &nr_node->callsign),
 911                        (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
 912                        nr_node->which + 1,
 913                        nr_node->count);
 914
 915                for (i = 0; i < nr_node->count; i++) {
 916                        seq_printf(seq, "  %3d   %d %05d",
 917                                nr_node->routes[i].quality,
 918                                nr_node->routes[i].obs_count,
 919                                nr_node->routes[i].neighbour->number);
 920                }
 921                nr_node_unlock(nr_node);
 922
 923                seq_puts(seq, "\n");
 924        }
 925        return 0;
 926}
 927
 928static const struct seq_operations nr_node_seqops = {
 929        .start = nr_node_start,
 930        .next = nr_node_next,
 931        .stop = nr_node_stop,
 932        .show = nr_node_show,
 933};
 934
 935static int nr_node_info_open(struct inode *inode, struct file *file)
 936{
 937        return seq_open(file, &nr_node_seqops);
 938}
 939
 940const struct file_operations nr_nodes_fops = {
 941        .owner = THIS_MODULE,
 942        .open = nr_node_info_open,
 943        .read = seq_read,
 944        .llseek = seq_lseek,
 945        .release = seq_release,
 946};
 947
 948static void *nr_neigh_start(struct seq_file *seq, loff_t *pos)
 949{
 950        struct nr_neigh *nr_neigh;
 951        struct hlist_node *node;
 952        int i = 1;
 953
 954        spin_lock_bh(&nr_neigh_list_lock);
 955        if (*pos == 0)
 956                return SEQ_START_TOKEN;
 957
 958        nr_neigh_for_each(nr_neigh, node, &nr_neigh_list) {
 959                if (i == *pos)
 960                        return nr_neigh;
 961        }
 962        return NULL;
 963}
 964
 965static void *nr_neigh_next(struct seq_file *seq, void *v, loff_t *pos)
 966{
 967        struct hlist_node *node;
 968        ++*pos;
 969
 970        node = (v == SEQ_START_TOKEN)
 971                ? nr_neigh_list.first
 972                : ((struct nr_neigh *)v)->neigh_node.next;
 973
 974        return hlist_entry(node, struct nr_neigh, neigh_node);
 975}
 976
 977static void nr_neigh_stop(struct seq_file *seq, void *v)
 978{
 979        spin_unlock_bh(&nr_neigh_list_lock);
 980}
 981
 982static int nr_neigh_show(struct seq_file *seq, void *v)
 983{
 984        char buf[11];
 985        int i;
 986
 987        if (v == SEQ_START_TOKEN)
 988                seq_puts(seq, "addr  callsign  dev  qual lock count failed digipeaters\n");
 989        else {
 990                struct nr_neigh *nr_neigh = v;
 991
 992                seq_printf(seq, "%05d %-9s %-4s  %3d    %d   %3d    %3d",
 993                        nr_neigh->number,
 994                        ax2asc(buf, &nr_neigh->callsign),
 995                        nr_neigh->dev ? nr_neigh->dev->name : "???",
 996                        nr_neigh->quality,
 997                        nr_neigh->locked,
 998                        nr_neigh->count,
 999                        nr_neigh->failed);
1000
1001                if (nr_neigh->digipeat != NULL) {
1002                        for (i = 0; i < nr_neigh->digipeat->ndigi; i++)
1003                                seq_printf(seq, " %s",
1004                                           ax2asc(buf, &nr_neigh->digipeat->calls[i]));
1005                }
1006
1007                seq_puts(seq, "\n");
1008        }
1009        return 0;
1010}
1011
1012static const struct seq_operations nr_neigh_seqops = {
1013        .start = nr_neigh_start,
1014        .next = nr_neigh_next,
1015        .stop = nr_neigh_stop,
1016        .show = nr_neigh_show,
1017};
1018
1019static int nr_neigh_info_open(struct inode *inode, struct file *file)
1020{
1021        return seq_open(file, &nr_neigh_seqops);
1022}
1023
1024const struct file_operations nr_neigh_fops = {
1025        .owner = THIS_MODULE,
1026        .open = nr_neigh_info_open,
1027        .read = seq_read,
1028        .llseek = seq_lseek,
1029        .release = seq_release,
1030};
1031
1032#endif
1033
1034/*
1035 *      Free all memory associated with the nodes and routes lists.
1036 */
1037void __exit nr_rt_free(void)
1038{
1039        struct nr_neigh *s = NULL;
1040        struct nr_node  *t = NULL;
1041        struct hlist_node *node, *nodet;
1042
1043        spin_lock_bh(&nr_neigh_list_lock);
1044        spin_lock_bh(&nr_node_list_lock);
1045        nr_node_for_each_safe(t, node, nodet, &nr_node_list) {
1046                nr_node_lock(t);
1047                nr_remove_node_locked(t);
1048                nr_node_unlock(t);
1049        }
1050        nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) {
1051                while(s->count) {
1052                        s->count--;
1053                        nr_neigh_put(s);
1054                }
1055                nr_remove_neigh_locked(s);
1056        }
1057        spin_unlock_bh(&nr_node_list_lock);
1058        spin_unlock_bh(&nr_neigh_list_lock);
1059}
1060
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.