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

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