root/net/netrom/nr_route.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nr_add_node
  2. nr_remove_node
  3. nr_remove_neigh
  4. nr_del_node
  5. nr_add_neigh
  6. nr_del_neigh
  7. nr_dec_obs
  8. nr_rt_device_down
  9. nr_ax25_dev_get
  10. nr_dev_first
  11. nr_dev_get
  12. nr_rt_ioctl
  13. nr_link_failed
  14. nr_route_frame
  15. nr_nodes_get_info
  16. nr_neigh_get_info

   1 /*
   2  *      NET/ROM release 003
   3  *
   4  *      This is ALPHA test software. This code may break your machine, randomly fail to work with new 
   5  *      releases, misbehave and/or generally screw up. It might even work. 
   6  *
   7  *      This code REQUIRES 1.2.1 or higher/ NET3.029
   8  *
   9  *      This module:
  10  *              This module is free software; you can redistribute it and/or
  11  *              modify it under the terms of the GNU General Public License
  12  *              as published by the Free Software Foundation; either version
  13  *              2 of the License, or (at your option) any later version.
  14  *
  15  *      History
  16  *      NET/ROM 001     Jonathan(G4KLX) First attempt.
  17  *      NET/ROM 003     Jonathan(G4KLX) Use SIOCADDRT/SIOCDELRT ioctl values
  18  *                                      for NET/ROM routes.
  19  *                      Alan Cox(GW4PTS) Added the firewall hooks.
  20  *
  21  *      TO DO
  22  *      Sort out the which pointer when shuffling entries in the routes
  23  *      section. Also reset the which pointer when a route becomes "good"
  24  *      again, ie when a NODES broadcast is processed via calls to
  25  *      nr_add_node().
  26  */
  27  
  28 #include <linux/config.h>
  29 #ifdef CONFIG_NETROM
  30 #include <linux/errno.h>
  31 #include <linux/types.h>
  32 #include <linux/socket.h>
  33 #include <linux/in.h>
  34 #include <linux/kernel.h>
  35 #include <linux/sched.h>
  36 #include <linux/timer.h>
  37 #include <linux/string.h>
  38 #include <linux/sockios.h>
  39 #include <linux/net.h>
  40 #include <net/ax25.h>
  41 #include <linux/inet.h>
  42 #include <linux/netdevice.h>
  43 #include <net/arp.h>
  44 #include <linux/if_arp.h>
  45 #include <linux/skbuff.h>
  46 #include <net/sock.h>
  47 #include <asm/segment.h>
  48 #include <asm/system.h>
  49 #include <linux/fcntl.h>
  50 #include <linux/termios.h>      /* For TIOCINQ/OUTQ */
  51 #include <linux/mm.h>
  52 #include <linux/interrupt.h>
  53 #include <linux/notifier.h>
  54 #include <linux/firewall.h>
  55 #include <net/netrom.h>
  56 
  57 static int nr_neigh_no = 1;
  58 static int nr_route_on = 1;
  59 
  60 static struct nr_node  *nr_node_list  = NULL;
  61 static struct nr_neigh *nr_neigh_list = NULL;
  62 
  63 /*
  64  *      Add a new route to a node, and in the process add the node and the
  65  *      neighbour if it is new.
  66  */
  67 static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax25,
     /* [previous][next][first][last][top][bottom][index][help] */
  68         ax25_digi *ax25_digi, struct device *dev, int quality, int obs_count)
  69 {
  70         struct nr_node  *nr_node;
  71         struct nr_neigh *nr_neigh;
  72         struct nr_route nr_route;
  73         unsigned long flags;
  74         int i, found;
  75         
  76         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
  77                 if (ax25cmp(nr, &nr_node->callsign) == 0)
  78                         break;
  79 
  80         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
  81                 if (ax25cmp(ax25, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
  82                         break;
  83 
  84         if (quality == 0 && nr_neigh != NULL && nr_node != NULL)
  85                 return 0;
  86 
  87         if (nr_neigh == NULL) {
  88                 if ((nr_neigh = (struct nr_neigh *)kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
  89                         return -ENOMEM;
  90 
  91                 memcpy(&nr_neigh->callsign, ax25, sizeof(ax25_address));
  92 
  93                 nr_neigh->digipeat= NULL;
  94                 nr_neigh->dev     = dev;
  95                 nr_neigh->quality = nr_default.quality;
  96                 nr_neigh->locked  = 0;
  97                 nr_neigh->count   = 0;
  98                 nr_neigh->number  = nr_neigh_no++;
  99 
 100                 if (ax25_digi != NULL) {
 101                         if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
 102                                 kfree_s(nr_neigh, sizeof(*nr_neigh));
 103                                 return -ENOMEM;
 104                         }
 105                         memcpy(nr_neigh->digipeat, ax25_digi, sizeof(*ax25_digi));
 106                 }
 107                         
 108                 save_flags(flags);
 109                 cli();
 110 
 111                 nr_neigh->next = nr_neigh_list;
 112                 nr_neigh_list  = nr_neigh;
 113 
 114                 restore_flags(flags);
 115         }
 116 
 117         if (nr_node == NULL) {
 118                 if ((nr_node = (struct nr_node *)kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL)
 119                         return -ENOMEM;
 120 
 121                 memcpy(&nr_node->callsign, nr, sizeof(ax25_address));
 122                 memcpy(&nr_node->mnemonic, mnemonic, sizeof(nr_node->mnemonic));
 123 
 124                 nr_node->which = 0;
 125                 nr_node->count = 1;
 126 
 127                 nr_node->routes[0].quality   = quality;
 128                 nr_node->routes[0].obs_count = obs_count;
 129                 nr_node->routes[0].neighbour = nr_neigh->number;
 130                         
 131                 save_flags(flags);
 132                 cli();
 133 
 134                 nr_node->next = nr_node_list;
 135                 nr_node_list  = nr_node;
 136 
 137                 restore_flags(flags);
 138                 
 139                 nr_neigh->count++;
 140 
 141                 return 0;
 142         }
 143 
 144         for (found = 0, i = 0; i < nr_node->count; i++) {
 145                 if (nr_node->routes[i].neighbour == nr_neigh->number) {
 146                         nr_node->routes[i].quality   = quality;
 147                         nr_node->routes[i].obs_count = obs_count;
 148                         found = 1;
 149                         break;
 150                 }
 151         }
 152 
 153         if (!found) {
 154                 /* We have space at the bottom, slot it in */
 155                 if (nr_node->count < 3) {
 156                         nr_node->routes[2] = nr_node->routes[1];
 157                         nr_node->routes[1] = nr_node->routes[0];
 158 
 159                         nr_node->routes[0].quality   = quality;
 160                         nr_node->routes[0].obs_count = obs_count;
 161                         nr_node->routes[0].neighbour = nr_neigh->number;
 162                                 
 163                         nr_node->count++;
 164                         nr_neigh->count++;
 165                 } else {
 166                         /* It must be better than the worst */
 167                         if (quality > nr_node->routes[2].quality) {
 168                                 nr_node->routes[2].quality   = quality;
 169                                 nr_node->routes[2].obs_count = obs_count;
 170                                 nr_node->routes[2].neighbour = nr_neigh->number;
 171 
 172                                 nr_neigh->count++;
 173                         }
 174                 }
 175         }
 176 
 177         /* Now re-sort the routes in quality order */
 178         switch (nr_node->count) {
 179                 case 3:
 180                         if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
 181                                 switch (nr_node->which) {
 182                                         case 0:  nr_node->which = 1; break;
 183                                         case 1:  nr_node->which = 0; break;
 184                                         default: break;
 185                                 }
 186                                 nr_route           = nr_node->routes[0];
 187                                 nr_node->routes[0] = nr_node->routes[1];
 188                                 nr_node->routes[1] = nr_route;
 189                         }
 190                         if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
 191                                 switch (nr_node->which) {
 192                                         case 1:  nr_node->which = 2; break;
 193                                         case 2:  nr_node->which = 1; break;
 194                                         default: break;
 195                                 }
 196                                 nr_route           = nr_node->routes[1];
 197                                 nr_node->routes[1] = nr_node->routes[2];
 198                                 nr_node->routes[2] = nr_route;
 199                         }
 200                 case 2:
 201                         if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
 202                                 switch (nr_node->which) {
 203                                         case 0:  nr_node->which = 1; break;
 204                                         case 1:  nr_node->which = 0; break;
 205                                         default: break;
 206                                 }
 207                                 nr_route           = nr_node->routes[0];
 208                                 nr_node->routes[0] = nr_node->routes[1];
 209                                 nr_node->routes[1] = nr_route;
 210                         }
 211                 case 1:
 212                         break;
 213         }
 214 
 215         for (i = 0; i < nr_node->count; i++) {
 216                 if (nr_node->routes[i].neighbour == nr_neigh->number) {
 217                         if (i < nr_node->which)
 218                                 nr_node->which = i;
 219                         break;
 220                 }
 221         }
 222 
 223         return 0;
 224 }
 225 
 226 static void nr_remove_node(struct nr_node *nr_node)
     /* [previous][next][first][last][top][bottom][index][help] */
 227 {
 228         struct nr_node *s;
 229         unsigned long flags;
 230         
 231         save_flags(flags);
 232         cli();
 233 
 234         if ((s = nr_node_list) == nr_node) {
 235                 nr_node_list = nr_node->next;
 236                 restore_flags(flags);
 237                 kfree_s(nr_node, sizeof(struct nr_node));
 238                 return;
 239         }
 240 
 241         while (s != NULL && s->next != NULL) {
 242                 if (s->next == nr_node) {
 243                         s->next = nr_node->next;
 244                         restore_flags(flags);
 245                         kfree_s(nr_node, sizeof(struct nr_node));
 246                         return;
 247                 }
 248 
 249                 s = s->next;
 250         }
 251 
 252         restore_flags(flags);
 253 }
 254 
 255 static void nr_remove_neigh(struct nr_neigh *nr_neigh)
     /* [previous][next][first][last][top][bottom][index][help] */
 256 {
 257         struct nr_neigh *s;
 258         unsigned long flags;
 259         
 260         save_flags(flags);
 261         cli();
 262 
 263         if ((s = nr_neigh_list) == nr_neigh) {
 264                 nr_neigh_list = nr_neigh->next;
 265                 restore_flags(flags);
 266                 if (nr_neigh->digipeat != NULL)
 267                         kfree_s(nr_neigh->digipeat, sizeof(ax25_digi));
 268                 kfree_s(nr_neigh, sizeof(struct nr_neigh));
 269                 return;
 270         }
 271 
 272         while (s != NULL && s->next != NULL) {
 273                 if (s->next == nr_neigh) {
 274                         s->next = nr_neigh->next;
 275                         restore_flags(flags);
 276                         if (nr_neigh->digipeat != NULL)
 277                                 kfree_s(nr_neigh->digipeat, sizeof(ax25_digi));
 278                         kfree_s(nr_neigh, sizeof(struct nr_neigh));
 279                         return;
 280                 }
 281 
 282                 s = s->next;
 283         }
 284 
 285         restore_flags(flags);
 286 }
 287 
 288 /*
 289  *      "Delete" a node. Strictly speaking remove a route to a node. The node
 290  *      is only deleted if no routes are left to it.
 291  */
 292 static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 293 {
 294         struct nr_node  *nr_node;
 295         struct nr_neigh *nr_neigh;
 296         int i;
 297         
 298         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
 299                 if (ax25cmp(callsign, &nr_node->callsign) == 0)
 300                         break;
 301 
 302         if (nr_node == NULL) return -EINVAL;
 303 
 304         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
 305                 if (ax25cmp(neighbour, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
 306                         break;
 307 
 308         if (nr_neigh == NULL) return -EINVAL;
 309         
 310         for (i = 0; i < nr_node->count; i++) {
 311                 if (nr_node->routes[i].neighbour == nr_neigh->number) {
 312                         nr_neigh->count--;
 313 
 314                         if (nr_neigh->count == 0 && !nr_neigh->locked)
 315                                 nr_remove_neigh(nr_neigh);
 316                                 
 317                         nr_node->count--;
 318                         
 319                         if (nr_node->count == 0) {
 320                                 nr_remove_node(nr_node);
 321                         } else {
 322                                 switch (i) {
 323                                         case 0:
 324                                                 nr_node->routes[0] = nr_node->routes[1];
 325                                         case 1:
 326                                                 nr_node->routes[1] = nr_node->routes[2];
 327                                         case 2:
 328                                                 break;
 329                                 }
 330                         }
 331 
 332                         return 0;
 333                 }
 334         }
 335 
 336         return -EINVAL;
 337 }
 338 
 339 /*
 340  *      Lock a neighbour with a quality.
 341  */
 342 static int nr_add_neigh(ax25_address *callsign, struct device *dev, unsigned int quality)
     /* [previous][next][first][last][top][bottom][index][help] */
 343 {
 344         struct nr_neigh *nr_neigh;
 345         unsigned long flags;
 346 
 347         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
 348                 if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) {
 349                         nr_neigh->quality = quality;
 350                         nr_neigh->locked  = 1;
 351                         return 0;
 352                 }
 353         }
 354 
 355         if ((nr_neigh = (struct nr_neigh *)kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
 356                 return -ENOMEM;
 357 
 358         memcpy(&nr_neigh->callsign, callsign, sizeof(ax25_address));
 359 
 360         nr_neigh->digipeat= NULL;
 361         nr_neigh->dev     = dev;
 362         nr_neigh->quality = quality;
 363         nr_neigh->locked  = 1;
 364         nr_neigh->count   = 0;
 365         nr_neigh->number  = nr_neigh_no++;
 366 
 367         save_flags(flags);
 368         cli();
 369                         
 370         nr_neigh->next = nr_neigh_list;
 371         nr_neigh_list  = nr_neigh;
 372 
 373         restore_flags(flags);
 374 
 375         return 0;       
 376 }
 377 
 378 /*
 379  *      "Delete" a neighbour. The neighbour is only removed if the number
 380  *      of nodes that may use it is zero.
 381  */
 382 static int nr_del_neigh(ax25_address *callsign, struct device *dev, unsigned int quality)
     /* [previous][next][first][last][top][bottom][index][help] */
 383 {
 384         struct nr_neigh *nr_neigh;
 385 
 386         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
 387                 if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
 388                         break;
 389 
 390         if (nr_neigh == NULL) return -EINVAL;
 391 
 392         nr_neigh->quality = quality;
 393         nr_neigh->locked  = 0;
 394 
 395         if (nr_neigh->count == 0)
 396                 nr_remove_neigh(nr_neigh);
 397 
 398         return 0;
 399 }
 400 
 401 /*
 402  *      Decrement the obsolescence count by one. If a route is reduced to a
 403  *      count of zero, remove it. Also remove any unlocked neighbours with
 404  *      zero nodes routing via it.
 405  */
 406 static int nr_dec_obs(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 407 {
 408         struct nr_neigh *t, *nr_neigh;
 409         struct nr_node  *s, *nr_node;
 410         int i;
 411 
 412         nr_node = nr_node_list;
 413 
 414         while (nr_node != NULL) {
 415                 s       = nr_node;
 416                 nr_node = nr_node->next;
 417 
 418                 for (i = 0; i < s->count; i++) {
 419                         switch (s->routes[i].obs_count) {
 420 
 421                         case 0:         /* A locked entry */
 422                                 break;
 423 
 424                         case 1:         /* From 1 -> 0 */
 425                                 nr_neigh = nr_neigh_list;
 426 
 427                                 while (nr_neigh != NULL) {
 428                                         t        = nr_neigh;
 429                                         nr_neigh = nr_neigh->next;
 430 
 431                                         if (t->number == s->routes[i].neighbour) {
 432                                                 t->count--;
 433                                                 
 434                                                 if (t->count == 0 && !t->locked)
 435                                                         nr_remove_neigh(t);
 436 
 437                                                 break;
 438                                         }
 439                                 }
 440 
 441                                 s->count--;
 442 
 443                                 switch (i) {
 444                                         case 0:
 445                                                 s->routes[0] = s->routes[1];
 446                                         case 1:
 447                                                 s->routes[1] = s->routes[2];
 448                                         case 2:
 449                                                 break;
 450                                 }
 451                                 break;
 452 
 453                         default:
 454                                 s->routes[i].obs_count--;
 455                                 break;
 456 
 457                         }
 458                 }
 459 
 460                 if (s->count <= 0)
 461                         nr_remove_node(s);
 462         }
 463 
 464         return 0;
 465 }
 466 
 467 /*
 468  *      A device has been removed. Remove its routes and neighbours.
 469  */
 470 void nr_rt_device_down(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 471 {
 472         struct nr_neigh *s, *nr_neigh = nr_neigh_list;
 473         struct nr_node  *t, *nr_node;
 474         int i;
 475 
 476         while (nr_neigh != NULL) {
 477                 s        = nr_neigh;
 478                 nr_neigh = nr_neigh->next;
 479                 
 480                 if (s->dev == dev) {
 481                         nr_node = nr_node_list;
 482 
 483                         while (nr_node != NULL) {
 484                                 t       = nr_node;
 485                                 nr_node = nr_node->next;
 486                                 
 487                                 for (i = 0; i < t->count; i++) {
 488                                         if (t->routes[i].neighbour == s->number) {
 489                                                 t->count--;
 490 
 491                                                 switch (i) {
 492                                                         case 0:
 493                                                                 t->routes[0] = t->routes[1];
 494                                                         case 1:
 495                                                                 t->routes[1] = t->routes[2];
 496                                                         case 2:
 497                                                                 break;
 498                                                 }
 499                                         }
 500                                 }
 501                                 
 502                                 if (t->count <= 0)
 503                                         nr_remove_node(t);
 504                         }
 505                         
 506                         nr_remove_neigh(s);
 507                 }
 508         }
 509 }
 510 
 511 /*
 512  *      Check that the device given is a valid AX.25 interface that is "up".
 513  *      Or a valid ethernet interface with an AX.25 callsign binding.
 514  */
 515 static struct device *nr_ax25_dev_get(char *devname)
     /* [previous][next][first][last][top][bottom][index][help] */
 516 {
 517         struct device *dev;
 518         ax25_address callsign;
 519 
 520         if ((dev = dev_get(devname)) == NULL)
 521                 return NULL;
 522 
 523         if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
 524                 return dev;
 525 
 526         if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ETHER)
 527                 if (arp_query((unsigned char *)&callsign, dev->pa_addr, dev))
 528                         return dev;
 529         
 530         return NULL;
 531 }
 532 
 533 /*
 534  *      Find the first active NET/ROM device, usually "nr0".
 535  */
 536 struct device *nr_dev_first(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 537 {
 538         struct device *dev, *first = NULL;
 539 
 540         for (dev = dev_base; dev != NULL; dev = dev->next)
 541                 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
 542                         if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
 543                                 first = dev;
 544 
 545         return first;
 546 }
 547 
 548 /*
 549  *      Find the NET/ROM device for the given callsign.
 550  */
 551 struct device *nr_dev_get(ax25_address *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 552 {
 553         struct device *dev;
 554 
 555         for (dev = dev_base; dev != NULL; dev = dev->next)
 556                 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0)
 557                         return dev;
 558         
 559         return NULL;
 560 }
 561 
 562 /*
 563  *      Handle the ioctls that control the routing functions.
 564  */
 565 int nr_rt_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 566 {
 567         struct nr_route_struct nr_route;
 568         struct device *dev;
 569         int err;
 570         long opt = 0;
 571 
 572         switch (cmd) {
 573 
 574                 case SIOCADDRT:
 575                         if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
 576                                 return err;
 577                         memcpy_fromfs(&nr_route, arg, sizeof(struct nr_route_struct));
 578                         if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
 579                                 return -EINVAL;
 580                         switch (nr_route.type) {
 581                                 case NETROM_NODE:
 582                                         return nr_add_node(&nr_route.callsign,
 583                                                 nr_route.mnemonic,
 584                                                 &nr_route.neighbour,
 585                                                 NULL, dev, nr_route.quality,
 586                                                 nr_route.obs_count);
 587                                 case NETROM_NEIGH:
 588                                         return nr_add_neigh(&nr_route.callsign,
 589                                                 dev, nr_route.quality);
 590                                 default:
 591                                         return -EINVAL;
 592                         }
 593 
 594                 case SIOCDELRT:
 595                         if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
 596                                 return err;
 597                         memcpy_fromfs(&nr_route, arg, sizeof(struct nr_route_struct));
 598                         if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
 599                                 return -EINVAL;
 600                         switch (nr_route.type) {
 601                                 case NETROM_NODE:
 602                                         return nr_del_node(&nr_route.callsign,
 603                                                 &nr_route.neighbour, dev);
 604                                 case NETROM_NEIGH:
 605                                         return nr_del_neigh(&nr_route.callsign,
 606                                                 dev, nr_route.quality);
 607                                 default:
 608                                         return -EINVAL;
 609                         }
 610 
 611                 case SIOCNRDECOBS:
 612                         return nr_dec_obs();
 613                         
 614                 case SIOCNRRTCTL:
 615                         if ((err = verify_area(VERIFY_READ, arg, sizeof(int))) != 0)
 616                                 return err;
 617                         opt = get_fs_long((void *)arg);
 618                         nr_route_on = opt ? 1 : 0;
 619                         return 0;
 620         }
 621 
 622         return 0;
 623 }
 624 
 625 /*
 626  *      A level 2 link has timed out, therefore it appears to be a poor link,
 627  *      then don't use that neighbour until it is reset.
 628  */
 629 void nr_link_failed(ax25_address *callsign, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 630 {
 631         struct nr_neigh *nr_neigh;
 632         struct nr_node  *nr_node;
 633 
 634         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
 635                 if (ax25cmp(&nr_neigh->callsign, callsign) == 0 && nr_neigh->dev == dev)
 636                         break;
 637                         
 638         if (nr_neigh == NULL) return;
 639         
 640         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
 641                 if (nr_node->which >= nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh->number)
 642                         nr_node->which++;
 643 }
 644 
 645 /*
 646  *      Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
 647  *      indicates an internally generated frame.
 648  */
 649 
 650 int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 651 {
 652         ax25_address *nr_src, *nr_dest;
 653         struct nr_neigh *nr_neigh;
 654         struct nr_node  *nr_node;
 655         struct device *dev;
 656         unsigned char *dptr;
 657         
 658 #ifdef CONFIG_FIREWALL
 659 
 660         if(ax25 && call_in_firewall(PF_NETROM, skb, skb->data)!=FW_ACCEPT)
 661                 return 0;
 662         if(!ax25 && call_out_firewall(PF_NETROM, skb, skb->data)!=FW_ACCEPT)
 663                 return 0;
 664 #endif
 665         nr_src  = (ax25_address *)(skb->data + 0);
 666         nr_dest = (ax25_address *)(skb->data + 7);
 667 
 668         if (ax25 != NULL)
 669                 nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat, ax25->device, 0, nr_default.obs_count);
 670 
 671         if ((dev = nr_dev_get(nr_dest)) != NULL)        /* Its for me */
 672                 return nr_rx_frame(skb, dev);
 673 
 674         if (!nr_route_on && ax25 != NULL)
 675                 return 0;
 676 
 677         /* Its Time-To-Live has expired */
 678         if (--skb->data[14] == 0)
 679                 return 0;
 680 
 681         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
 682                 if (ax25cmp(nr_dest, &nr_node->callsign) == 0)
 683                         break;
 684 
 685         if (nr_node == NULL || nr_node->which >= nr_node->count)
 686                 return 0;
 687 
 688         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
 689                 if (nr_neigh->number == nr_node->routes[nr_node->which].neighbour)
 690                         break;
 691                         
 692         if (nr_neigh == NULL)
 693                 return 0;
 694 
 695         if ((dev = nr_dev_first()) == NULL)
 696                 return 0;
 697 
 698 #ifdef CONFIG_FIREWALL
 699         if(ax25 && call_fw_firewall(PF_NETROM, skb, skb->data)!=FW_ACCEPT)
 700                 return 0;
 701 #endif
 702 
 703         dptr  = skb_push(skb, 1);
 704         *dptr = AX25_P_NETROM;
 705 
 706         ax25_send_frame(skb, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
 707 
 708         return 1;
 709 }
 710 
 711 int nr_nodes_get_info(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
 712                       int length, int dummy)
 713 {
 714         struct nr_node *nr_node;
 715         int len     = 0;
 716         off_t pos   = 0;
 717         off_t begin = 0;
 718         int i;
 719   
 720         cli();
 721 
 722         len += sprintf(buffer, "callsign  mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
 723 
 724         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) {
 725                 len += sprintf(buffer + len, "%-9s %-7s  %d %d",
 726                         ax2asc(&nr_node->callsign),
 727                         nr_node->mnemonic,
 728                         nr_node->which + 1,
 729                         nr_node->count);                        
 730 
 731                 for (i = 0; i < nr_node->count; i++) {
 732                         len += sprintf(buffer + len, "  %3d   %d %05d",
 733                                 nr_node->routes[i].quality,
 734                                 nr_node->routes[i].obs_count,
 735                                 nr_node->routes[i].neighbour);
 736                 }
 737 
 738                 len += sprintf(buffer + len, "\n");
 739 
 740                 pos = begin + len;
 741 
 742                 if (pos < offset) {
 743                         len   = 0;
 744                         begin = pos;
 745                 }
 746                 
 747                 if (pos > offset + length)
 748                         break;
 749         }
 750 
 751         sti();
 752 
 753         *start = buffer + (offset - begin);
 754         len   -= (offset - begin);
 755 
 756         if (len > length) len = length;
 757 
 758         return(len);
 759 } 
 760 
 761 int nr_neigh_get_info(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
 762                       int length, int dummy)
 763 {
 764         struct nr_neigh *nr_neigh;
 765         int len     = 0;
 766         off_t pos   = 0;
 767         off_t begin = 0;
 768   
 769         cli();
 770 
 771         len += sprintf(buffer, "addr  callsign  dev  qual lock count\n");
 772 
 773         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
 774                 len += sprintf(buffer + len, "%05d %-9s %-4s  %3d    %d   %3d\n",
 775                         nr_neigh->number,
 776                         ax2asc(&nr_neigh->callsign),
 777                         nr_neigh->dev ? nr_neigh->dev->name : "???",
 778                         nr_neigh->quality,
 779                         nr_neigh->locked,
 780                         nr_neigh->count);
 781 
 782                 pos = begin + len;
 783 
 784                 if (pos < offset) {
 785                         len   = 0;
 786                         begin = pos;
 787                 }
 788                 
 789                 if (pos > offset + length)
 790                         break;
 791         }
 792 
 793         sti();
 794 
 795         *start = buffer + (offset - begin);
 796         len   -= (offset - begin);
 797 
 798         if (len > length) len = length;
 799 
 800         return(len);
 801 } 
 802 
 803 #endif

/* [previous][next][first][last][top][bottom][index][help] */