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 
 519         if ((dev = dev_get(devname)) == NULL)
 520                 return NULL;
 521 
 522         if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
 523                 return dev;
 524 
 525 #ifdef CONFIG_BPQETHER
 526         if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ETHER)
 527                 if (ax25_bpq_get_addr(dev) != NULL)
 528                         return dev;
 529 #endif
 530         
 531         return NULL;
 532 }
 533 
 534 /*
 535  *      Find the first active NET/ROM device, usually "nr0".
 536  */
 537 struct device *nr_dev_first(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 538 {
 539         struct device *dev, *first = NULL;
 540 
 541         for (dev = dev_base; dev != NULL; dev = dev->next)
 542                 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
 543                         if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
 544                                 first = dev;
 545 
 546         return first;
 547 }
 548 
 549 /*
 550  *      Find the NET/ROM device for the given callsign.
 551  */
 552 struct device *nr_dev_get(ax25_address *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 553 {
 554         struct device *dev;
 555 
 556         for (dev = dev_base; dev != NULL; dev = dev->next)
 557                 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0)
 558                         return dev;
 559         
 560         return NULL;
 561 }
 562 
 563 /*
 564  *      Handle the ioctls that control the routing functions.
 565  */
 566 int nr_rt_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 567 {
 568         struct nr_route_struct nr_route;
 569         struct device *dev;
 570         int err;
 571         long opt = 0;
 572 
 573         switch (cmd) {
 574 
 575                 case SIOCADDRT:
 576                         if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
 577                                 return err;
 578                         memcpy_fromfs(&nr_route, arg, sizeof(struct nr_route_struct));
 579                         if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
 580                                 return -EINVAL;
 581                         switch (nr_route.type) {
 582                                 case NETROM_NODE:
 583                                         return nr_add_node(&nr_route.callsign,
 584                                                 nr_route.mnemonic,
 585                                                 &nr_route.neighbour,
 586                                                 NULL, dev, nr_route.quality,
 587                                                 nr_route.obs_count);
 588                                 case NETROM_NEIGH:
 589                                         return nr_add_neigh(&nr_route.callsign,
 590                                                 dev, nr_route.quality);
 591                                 default:
 592                                         return -EINVAL;
 593                         }
 594 
 595                 case SIOCDELRT:
 596                         if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
 597                                 return err;
 598                         memcpy_fromfs(&nr_route, arg, sizeof(struct nr_route_struct));
 599                         if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
 600                                 return -EINVAL;
 601                         switch (nr_route.type) {
 602                                 case NETROM_NODE:
 603                                         return nr_del_node(&nr_route.callsign,
 604                                                 &nr_route.neighbour, dev);
 605                                 case NETROM_NEIGH:
 606                                         return nr_del_neigh(&nr_route.callsign,
 607                                                 dev, nr_route.quality);
 608                                 default:
 609                                         return -EINVAL;
 610                         }
 611 
 612                 case SIOCNRDECOBS:
 613                         return nr_dec_obs();
 614                         
 615                 case SIOCNRRTCTL:
 616                         if ((err = verify_area(VERIFY_READ, arg, sizeof(int))) != 0)
 617                                 return err;
 618                         opt = get_fs_long((void *)arg);
 619                         nr_route_on = opt ? 1 : 0;
 620                         return 0;
 621         }
 622 
 623         return 0;
 624 }
 625 
 626 /*
 627  *      A level 2 link has timed out, therefore it appears to be a poor link,
 628  *      then don't use that neighbour until it is reset.
 629  */
 630 void nr_link_failed(ax25_address *callsign, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 631 {
 632         struct nr_neigh *nr_neigh;
 633         struct nr_node  *nr_node;
 634 
 635         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
 636                 if (ax25cmp(&nr_neigh->callsign, callsign) == 0 && nr_neigh->dev == dev)
 637                         break;
 638                         
 639         if (nr_neigh == NULL) return;
 640         
 641         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
 642                 if (nr_node->which >= nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh->number)
 643                         nr_node->which++;
 644 }
 645 
 646 /*
 647  *      Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
 648  *      indicates an internally generated frame.
 649  */
 650 
 651 int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 652 {
 653         ax25_address *nr_src, *nr_dest;
 654         struct nr_neigh *nr_neigh;
 655         struct nr_node  *nr_node;
 656         struct device *dev;
 657         unsigned char *dptr;
 658         
 659 #ifdef CONFIG_FIREWALL
 660 
 661         if(ax25 && call_in_firewall(PF_NETROM, skb, skb->data)!=FW_ACCEPT)
 662                 return 0;
 663         if(!ax25 && call_out_firewall(PF_NETROM, skb, skb->data)!=FW_ACCEPT)
 664                 return 0;
 665 #endif
 666         nr_src  = (ax25_address *)(skb->data + 0);
 667         nr_dest = (ax25_address *)(skb->data + 7);
 668 
 669         if (ax25 != NULL)
 670                 nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat, ax25->device, 0, nr_default.obs_count);
 671 
 672         if ((dev = nr_dev_get(nr_dest)) != NULL)        /* Its for me */
 673                 return nr_rx_frame(skb, dev);
 674 
 675         if (!nr_route_on && ax25 != NULL)
 676                 return 0;
 677 
 678         /* Its Time-To-Live has expired */
 679         if (--skb->data[14] == 0)
 680                 return 0;
 681 
 682         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
 683                 if (ax25cmp(nr_dest, &nr_node->callsign) == 0)
 684                         break;
 685 
 686         if (nr_node == NULL || nr_node->which >= nr_node->count)
 687                 return 0;
 688 
 689         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
 690                 if (nr_neigh->number == nr_node->routes[nr_node->which].neighbour)
 691                         break;
 692                         
 693         if (nr_neigh == NULL)
 694                 return 0;
 695 
 696         if ((dev = nr_dev_first()) == NULL)
 697                 return 0;
 698 
 699 #ifdef CONFIG_FIREWALL
 700         if(ax25 && call_fw_firewall(PF_NETROM, skb, skb->data)!=FW_ACCEPT)
 701                 return 0;
 702 #endif
 703 
 704         dptr  = skb_push(skb, 1);
 705         *dptr = AX25_P_NETROM;
 706 
 707         ax25_send_frame(skb, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
 708 
 709         return 1;
 710 }
 711 
 712 int nr_nodes_get_info(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
 713                       int length, int dummy)
 714 {
 715         struct nr_node *nr_node;
 716         int len     = 0;
 717         off_t pos   = 0;
 718         off_t begin = 0;
 719         int i;
 720   
 721         cli();
 722 
 723         len += sprintf(buffer, "callsign  mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
 724 
 725         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) {
 726                 len += sprintf(buffer + len, "%-9s %-7s  %d %d",
 727                         ax2asc(&nr_node->callsign),
 728                         nr_node->mnemonic,
 729                         nr_node->which + 1,
 730                         nr_node->count);                        
 731 
 732                 for (i = 0; i < nr_node->count; i++) {
 733                         len += sprintf(buffer + len, "  %3d   %d %05d",
 734                                 nr_node->routes[i].quality,
 735                                 nr_node->routes[i].obs_count,
 736                                 nr_node->routes[i].neighbour);
 737                 }
 738 
 739                 len += sprintf(buffer + len, "\n");
 740 
 741                 pos = begin + len;
 742 
 743                 if (pos < offset) {
 744                         len   = 0;
 745                         begin = pos;
 746                 }
 747                 
 748                 if (pos > offset + length)
 749                         break;
 750         }
 751 
 752         sti();
 753 
 754         *start = buffer + (offset - begin);
 755         len   -= (offset - begin);
 756 
 757         if (len > length) len = length;
 758 
 759         return(len);
 760 } 
 761 
 762 int nr_neigh_get_info(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
 763                       int length, int dummy)
 764 {
 765         struct nr_neigh *nr_neigh;
 766         int len     = 0;
 767         off_t pos   = 0;
 768         off_t begin = 0;
 769   
 770         cli();
 771 
 772         len += sprintf(buffer, "addr  callsign  dev  qual lock count\n");
 773 
 774         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
 775                 len += sprintf(buffer + len, "%05d %-9s %-4s  %3d    %d   %3d\n",
 776                         nr_neigh->number,
 777                         ax2asc(&nr_neigh->callsign),
 778                         nr_neigh->dev ? nr_neigh->dev->name : "???",
 779                         nr_neigh->quality,
 780                         nr_neigh->locked,
 781                         nr_neigh->count);
 782 
 783                 pos = begin + len;
 784 
 785                 if (pos < offset) {
 786                         len   = 0;
 787                         begin = pos;
 788                 }
 789                 
 790                 if (pos > offset + length)
 791                         break;
 792         }
 793 
 794         sti();
 795 
 796         *start = buffer + (offset - begin);
 797         len   -= (offset - begin);
 798 
 799         if (len > length) len = length;
 800 
 801         return(len);
 802 } 
 803 
 804 #endif

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