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

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