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

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