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  *
  20  *      TO DO
  21  *      Sort out the which pointer when shuffling entries in the routes
  22  *      section. Also reset the which pointer when a route becomes "good"
  23  *      again, ie when a NODES broadcast is processed via calls to
  24  *      nr_add_node().
  25  */
  26  
  27 #include <linux/config.h>
  28 #ifdef CONFIG_NETROM
  29 #include <linux/errno.h>
  30 #include <linux/types.h>
  31 #include <linux/socket.h>
  32 #include <linux/in.h>
  33 #include <linux/kernel.h>
  34 #include <linux/sched.h>
  35 #include <linux/timer.h>
  36 #include <linux/string.h>
  37 #include <linux/sockios.h>
  38 #include <linux/net.h>
  39 #include <net/ax25.h>
  40 #include <linux/inet.h>
  41 #include <linux/netdevice.h>
  42 #include <net/arp.h>
  43 #include <linux/if_arp.h>
  44 #include <linux/skbuff.h>
  45 #include <net/sock.h>
  46 #include <asm/segment.h>
  47 #include <asm/system.h>
  48 #include <linux/fcntl.h>
  49 #include <linux/termios.h>      /* For TIOCINQ/OUTQ */
  50 #include <linux/mm.h>
  51 #include <linux/interrupt.h>
  52 #include <linux/notifier.h>
  53 #include <net/netrom.h>
  54 
  55 static int nr_neigh_no = 1;
  56 static int nr_route_on = 1;
  57 
  58 static struct nr_node  *nr_node_list  = NULL;
  59 static struct nr_neigh *nr_neigh_list = NULL;
  60 
  61 /*
  62  *      Add a new route to a node, and in the process add the node and the
  63  *      neighbour if it is new.
  64  */
  65 static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax25,
     /* [previous][next][first][last][top][bottom][index][help] */
  66         ax25_digi *ax25_digi, struct device *dev, int quality, int obs_count)
  67 {
  68         struct nr_node  *nr_node;
  69         struct nr_neigh *nr_neigh;
  70         struct nr_route nr_route;
  71         unsigned long flags;
  72         int i, found;
  73         
  74         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
  75                 if (ax25cmp(nr, &nr_node->callsign) == 0)
  76                         break;
  77 
  78         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
  79                 if (ax25cmp(ax25, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
  80                         break;
  81 
  82         if (quality == 0 && nr_neigh != NULL && nr_node != NULL)
  83                 return 0;
  84 
  85         if (nr_neigh == NULL) {
  86                 if ((nr_neigh = (struct nr_neigh *)kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
  87                         return -ENOMEM;
  88 
  89                 memcpy(&nr_neigh->callsign, ax25, sizeof(ax25_address));
  90 
  91                 nr_neigh->digipeat= NULL;
  92                 nr_neigh->dev     = dev;
  93                 nr_neigh->quality = nr_default.quality;
  94                 nr_neigh->locked  = 0;
  95                 nr_neigh->count   = 0;
  96                 nr_neigh->number  = nr_neigh_no++;
  97 
  98                 if (ax25_digi != NULL) {
  99                         if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
 100                                 kfree_s(nr_neigh, sizeof(*nr_neigh));
 101                                 return -ENOMEM;
 102                         }
 103                         memcpy(nr_neigh->digipeat, ax25_digi, sizeof(*ax25_digi));
 104                 }
 105                         
 106                 save_flags(flags);
 107                 cli();
 108 
 109                 nr_neigh->next = nr_neigh_list;
 110                 nr_neigh_list  = nr_neigh;
 111 
 112                 restore_flags(flags);
 113         }
 114 
 115         if (nr_node == NULL) {
 116                 if ((nr_node = (struct nr_node *)kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL)
 117                         return -ENOMEM;
 118 
 119                 memcpy(&nr_node->callsign, nr, sizeof(ax25_address));
 120                 memcpy(&nr_node->mnemonic, mnemonic, sizeof(nr_node->mnemonic));
 121 
 122                 nr_node->which = 0;
 123                 nr_node->count = 1;
 124 
 125                 nr_node->routes[0].quality   = quality;
 126                 nr_node->routes[0].obs_count = obs_count;
 127                 nr_node->routes[0].neighbour = nr_neigh->number;
 128                         
 129                 save_flags(flags);
 130                 cli();
 131 
 132                 nr_node->next = nr_node_list;
 133                 nr_node_list  = nr_node;
 134 
 135                 restore_flags(flags);
 136                 
 137                 nr_neigh->count++;
 138 
 139                 return 0;
 140         }
 141 
 142         for (found = 0, i = 0; i < nr_node->count; i++) {
 143                 if (nr_node->routes[i].neighbour == nr_neigh->number) {
 144                         nr_node->routes[i].quality   = quality;
 145                         nr_node->routes[i].obs_count = obs_count;
 146                         found = 1;
 147                         break;
 148                 }
 149         }
 150 
 151         if (!found) {
 152                 /* We have space at the bottom, slot it in */
 153                 if (nr_node->count < 3) {
 154                         nr_node->routes[2] = nr_node->routes[1];
 155                         nr_node->routes[1] = nr_node->routes[0];
 156 
 157                         nr_node->routes[0].quality   = quality;
 158                         nr_node->routes[0].obs_count = obs_count;
 159                         nr_node->routes[0].neighbour = nr_neigh->number;
 160                                 
 161                         nr_node->count++;
 162                         nr_neigh->count++;
 163                 } else {
 164                         /* It must be better than the worst */
 165                         if (quality > nr_node->routes[2].quality) {
 166                                 nr_node->routes[2].quality   = quality;
 167                                 nr_node->routes[2].obs_count = obs_count;
 168                                 nr_node->routes[2].neighbour = nr_neigh->number;
 169 
 170                                 nr_neigh->count++;
 171                         }
 172                 }
 173         }
 174 
 175         /* Now re-sort the routes in quality order */
 176         switch (nr_node->count) {
 177                 case 3:
 178                         if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
 179                                 switch (nr_node->which) {
 180                                         case 0:  nr_node->which = 1; break;
 181                                         case 1:  nr_node->which = 0; break;
 182                                         default: break;
 183                                 }
 184                                 nr_route           = nr_node->routes[0];
 185                                 nr_node->routes[0] = nr_node->routes[1];
 186                                 nr_node->routes[1] = nr_route;
 187                         }
 188                         if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
 189                                 switch (nr_node->which) {
 190                                         case 1:  nr_node->which = 2; break;
 191                                         case 2:  nr_node->which = 1; break;
 192                                         default: break;
 193                                 }
 194                                 nr_route           = nr_node->routes[1];
 195                                 nr_node->routes[1] = nr_node->routes[2];
 196                                 nr_node->routes[2] = nr_route;
 197                         }
 198                 case 2:
 199                         if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
 200                                 switch (nr_node->which) {
 201                                         case 0:  nr_node->which = 1; break;
 202                                         case 1:  nr_node->which = 0; break;
 203                                         default: break;
 204                                 }
 205                                 nr_route           = nr_node->routes[0];
 206                                 nr_node->routes[0] = nr_node->routes[1];
 207                                 nr_node->routes[1] = nr_route;
 208                         }
 209                 case 1:
 210                         break;
 211         }
 212 
 213         for (i = 0; i < nr_node->count; i++) {
 214                 if (nr_node->routes[i].neighbour == nr_neigh->number) {
 215                         if (i < nr_node->which)
 216                                 nr_node->which = i;
 217                         break;
 218                 }
 219         }
 220 
 221         return 0;
 222 }
 223 
 224 static void nr_remove_node(struct nr_node *nr_node)
     /* [previous][next][first][last][top][bottom][index][help] */
 225 {
 226         struct nr_node *s;
 227         unsigned long flags;
 228         
 229         save_flags(flags);
 230         cli();
 231 
 232         if ((s = nr_node_list) == nr_node) {
 233                 nr_node_list = nr_node->next;
 234                 restore_flags(flags);
 235                 kfree_s(nr_node, sizeof(struct nr_node));
 236                 return;
 237         }
 238 
 239         while (s != NULL && s->next != NULL) {
 240                 if (s->next == nr_node) {
 241                         s->next = nr_node->next;
 242                         restore_flags(flags);
 243                         kfree_s(nr_node, sizeof(struct nr_node));
 244                         return;
 245                 }
 246 
 247                 s = s->next;
 248         }
 249 
 250         restore_flags(flags);
 251 }
 252 
 253 static void nr_remove_neigh(struct nr_neigh *nr_neigh)
     /* [previous][next][first][last][top][bottom][index][help] */
 254 {
 255         struct nr_neigh *s;
 256         unsigned long flags;
 257         
 258         save_flags(flags);
 259         cli();
 260 
 261         if ((s = nr_neigh_list) == nr_neigh) {
 262                 nr_neigh_list = nr_neigh->next;
 263                 restore_flags(flags);
 264                 if (nr_neigh->digipeat != NULL)
 265                         kfree_s(nr_neigh->digipeat, sizeof(ax25_digi));
 266                 kfree_s(nr_neigh, sizeof(struct nr_neigh));
 267                 return;
 268         }
 269 
 270         while (s != NULL && s->next != NULL) {
 271                 if (s->next == nr_neigh) {
 272                         s->next = nr_neigh->next;
 273                         restore_flags(flags);
 274                         if (nr_neigh->digipeat != NULL)
 275                                 kfree_s(nr_neigh->digipeat, sizeof(ax25_digi));
 276                         kfree_s(nr_neigh, sizeof(struct nr_neigh));
 277                         return;
 278                 }
 279 
 280                 s = s->next;
 281         }
 282 
 283         restore_flags(flags);
 284 }
 285 
 286 /*
 287  *      "Delete" a node. Strictly speaking remove a route to a node. The node
 288  *      is only deleted if no routes are left to it.
 289  */
 290 static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292         struct nr_node  *nr_node;
 293         struct nr_neigh *nr_neigh;
 294         int i;
 295         
 296         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
 297                 if (ax25cmp(callsign, &nr_node->callsign) == 0)
 298                         break;
 299 
 300         if (nr_node == NULL) return -EINVAL;
 301 
 302         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
 303                 if (ax25cmp(neighbour, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
 304                         break;
 305 
 306         if (nr_neigh == NULL) return -EINVAL;
 307         
 308         for (i = 0; i < nr_node->count; i++) {
 309                 if (nr_node->routes[i].neighbour == nr_neigh->number) {
 310                         nr_neigh->count--;
 311 
 312                         if (nr_neigh->count == 0 && !nr_neigh->locked)
 313                                 nr_remove_neigh(nr_neigh);
 314                                 
 315                         nr_node->count--;
 316                         
 317                         if (nr_node->count == 0) {
 318                                 nr_remove_node(nr_node);
 319                         } else {
 320                                 switch (i) {
 321                                         case 0:
 322                                                 nr_node->routes[0] = nr_node->routes[1];
 323                                         case 1:
 324                                                 nr_node->routes[1] = nr_node->routes[2];
 325                                         case 2:
 326                                                 break;
 327                                 }
 328                         }
 329 
 330                         return 0;
 331                 }
 332         }
 333 
 334         return -EINVAL;
 335 }
 336 
 337 /*
 338  *      Lock a neighbour with a quality.
 339  */
 340 static int nr_add_neigh(ax25_address *callsign, struct device *dev, unsigned int quality)
     /* [previous][next][first][last][top][bottom][index][help] */
 341 {
 342         struct nr_neigh *nr_neigh;
 343         unsigned long flags;
 344 
 345         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
 346                 if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) {
 347                         nr_neigh->quality = quality;
 348                         nr_neigh->locked  = 1;
 349                         return 0;
 350                 }
 351         }
 352 
 353         if ((nr_neigh = (struct nr_neigh *)kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
 354                 return -ENOMEM;
 355 
 356         memcpy(&nr_neigh->callsign, callsign, sizeof(ax25_address));
 357 
 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         ax25_address callsign;
 517 
 518         if ((dev = dev_get(devname)) == NULL)
 519                 return NULL;
 520 
 521         if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
 522                 return dev;
 523 
 524         if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ETHER)
 525                 if (arp_query((unsigned char *)&callsign, dev->pa_addr, ARPHRD_AX25))
 526                         return dev;
 527         
 528         return NULL;
 529 }
 530 
 531 /*
 532  *      Find the first active NET/ROM device, usually "nr0".
 533  */
 534 struct device *nr_dev_first(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 535 {
 536         struct device *dev, *first = NULL;
 537 
 538         for (dev = dev_base; dev != NULL; dev = dev->next)
 539                 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
 540                         if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
 541                                 first = dev;
 542 
 543         return first;
 544 }
 545 
 546 /*
 547  *      Find the NET/ROM device for the given callsign.
 548  */
 549 struct device *nr_dev_get(ax25_address *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 550 {
 551         struct device *dev;
 552 
 553         for (dev = dev_base; dev != NULL; dev = dev->next)
 554                 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0)
 555                         return dev;
 556         
 557         return NULL;
 558 }
 559 
 560 /*
 561  *      Handle the ioctls that control the routing functions.
 562  */
 563 int nr_rt_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 564 {
 565         struct nr_route_struct nr_route;
 566         struct device *dev;
 567         int err;
 568         long opt = 0;
 569 
 570         switch (cmd) {
 571 
 572                 case SIOCADDRT:
 573                         if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
 574                                 return err;
 575                         memcpy_fromfs(&nr_route, arg, sizeof(struct nr_route_struct));
 576                         if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
 577                                 return -EINVAL;
 578                         switch (nr_route.type) {
 579                                 case NETROM_NODE:
 580                                         return nr_add_node(&nr_route.callsign,
 581                                                 nr_route.mnemonic,
 582                                                 &nr_route.neighbour,
 583                                                 NULL, dev, nr_route.quality,
 584                                                 nr_route.obs_count);
 585                                 case NETROM_NEIGH:
 586                                         return nr_add_neigh(&nr_route.callsign,
 587                                                 dev, nr_route.quality);
 588                                 default:
 589                                         return -EINVAL;
 590                         }
 591 
 592                 case SIOCDELRT:
 593                         if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
 594                                 return err;
 595                         memcpy_fromfs(&nr_route, arg, sizeof(struct nr_route_struct));
 596                         if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
 597                                 return -EINVAL;
 598                         switch (nr_route.type) {
 599                                 case NETROM_NODE:
 600                                         return nr_del_node(&nr_route.callsign,
 601                                                 &nr_route.neighbour, dev);
 602                                 case NETROM_NEIGH:
 603                                         return nr_del_neigh(&nr_route.callsign,
 604                                                 dev, nr_route.quality);
 605                                 default:
 606                                         return -EINVAL;
 607                         }
 608 
 609                 case SIOCNRDECOBS:
 610                         return nr_dec_obs();
 611                         
 612                 case SIOCNRRTCTL:
 613                         if ((err = verify_area(VERIFY_READ, arg, sizeof(int))) != 0)
 614                                 return err;
 615                         opt = get_fs_long((void *)arg);
 616                         nr_route_on = opt ? 1 : 0;
 617                         return 0;
 618         }
 619 
 620         return 0;
 621 }
 622 
 623 /*
 624  *      A level 2 link has timed out, therefore it appears to be a poor link,
 625  *      then don't use that neighbour until it is reset.
 626  */
 627 void nr_link_failed(ax25_address *callsign, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 628 {
 629         struct nr_neigh *nr_neigh;
 630         struct nr_node  *nr_node;
 631 
 632         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
 633                 if (ax25cmp(&nr_neigh->callsign, callsign) == 0 && nr_neigh->dev == dev)
 634                         break;
 635                         
 636         if (nr_neigh == NULL) return;
 637         
 638         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
 639                 if (nr_node->which >= nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh->number)
 640                         nr_node->which++;
 641 }
 642 
 643 /*
 644  *      Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
 645  *      indicates an internally generated frame.
 646  */
 647 int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 648 {
 649         ax25_address *nr_src, *nr_dest;
 650         struct nr_neigh *nr_neigh;
 651         struct nr_node  *nr_node;
 652         struct device *dev;
 653         unsigned char *dptr;
 654 
 655         nr_src  = (ax25_address *)(skb->data + 0);
 656         nr_dest = (ax25_address *)(skb->data + 7);
 657 
 658         if (ax25 != NULL)
 659                 nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat, ax25->device, 0, nr_default.obs_count);
 660 
 661         if ((dev = nr_dev_get(nr_dest)) != NULL)        /* Its for me */
 662                 return nr_rx_frame(skb, dev);
 663 
 664         if (!nr_route_on && ax25 != NULL)
 665                 return 0;
 666 
 667         /* Its Time-To-Live has expired */
 668         if (--skb->data[14] == 0)
 669                 return 0;
 670 
 671         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
 672                 if (ax25cmp(nr_dest, &nr_node->callsign) == 0)
 673                         break;
 674 
 675         if (nr_node == NULL || nr_node->which >= nr_node->count)
 676                 return 0;
 677 
 678         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
 679                 if (nr_neigh->number == nr_node->routes[nr_node->which].neighbour)
 680                         break;
 681                         
 682         if (nr_neigh == NULL)
 683                 return 0;
 684 
 685         if ((dev = nr_dev_first()) == NULL)
 686                 return 0;
 687 
 688         dptr  = skb_push(skb, 1);
 689         *dptr = AX25_P_NETROM;
 690 
 691         ax25_send_frame(skb, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
 692 
 693         return 1;
 694 }
 695 
 696 int nr_nodes_get_info(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
 697                       int length, int dummy)
 698 {
 699         struct nr_node *nr_node;
 700         int len     = 0;
 701         off_t pos   = 0;
 702         off_t begin = 0;
 703         int i;
 704   
 705         cli();
 706 
 707         len += sprintf(buffer, "callsign  mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
 708 
 709         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) {
 710                 len += sprintf(buffer + len, "%-9s %-7s  %d %d",
 711                         ax2asc(&nr_node->callsign),
 712                         nr_node->mnemonic,
 713                         nr_node->which + 1,
 714                         nr_node->count);                        
 715 
 716                 for (i = 0; i < nr_node->count; i++) {
 717                         len += sprintf(buffer + len, "  %3d   %d %05d",
 718                                 nr_node->routes[i].quality,
 719                                 nr_node->routes[i].obs_count,
 720                                 nr_node->routes[i].neighbour);
 721                 }
 722 
 723                 len += sprintf(buffer + len, "\n");
 724 
 725                 pos = begin + len;
 726 
 727                 if (pos < offset) {
 728                         len   = 0;
 729                         begin = pos;
 730                 }
 731                 
 732                 if (pos > offset + length)
 733                         break;
 734         }
 735 
 736         sti();
 737 
 738         *start = buffer + (offset - begin);
 739         len   -= (offset - begin);
 740 
 741         if (len > length) len = length;
 742 
 743         return(len);
 744 } 
 745 
 746 int nr_neigh_get_info(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
 747                       int length, int dummy)
 748 {
 749         struct nr_neigh *nr_neigh;
 750         int len     = 0;
 751         off_t pos   = 0;
 752         off_t begin = 0;
 753   
 754         cli();
 755 
 756         len += sprintf(buffer, "addr  callsign  dev  qual lock count\n");
 757 
 758         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
 759                 len += sprintf(buffer + len, "%05d %-9s %-4s  %3d    %d   %3d\n",
 760                         nr_neigh->number,
 761                         ax2asc(&nr_neigh->callsign),
 762                         nr_neigh->dev ? nr_neigh->dev->name : "???",
 763                         nr_neigh->quality,
 764                         nr_neigh->locked,
 765                         nr_neigh->count);
 766 
 767                 pos = begin + len;
 768 
 769                 if (pos < offset) {
 770                         len   = 0;
 771                         begin = pos;
 772                 }
 773                 
 774                 if (pos > offset + length)
 775                         break;
 776         }
 777 
 778         sti();
 779 
 780         *start = buffer + (offset - begin);
 781         len   -= (offset - begin);
 782 
 783         if (len > length) len = length;
 784 
 785         return(len);
 786 } 
 787 
 788 #endif

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