root/net/ax25/ax25_route.c

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

DEFINITIONS

This source file includes following definitions.
  1. ax25_route_invert
  2. ax25_rt_rx_frame
  3. ax25_rt_device_down
  4. ax25_rt_ioctl
  5. ax25_rt_get_info
  6. ax25_cs_get_info
  7. ax25_find_route
  8. ax25_adjust_path
  9. ax25_rt_autobind
  10. ax25_rt_build_path
  11. ax25_dg_build_path
  12. ax25_ip_mode_set
  13. ax25_ip_mode_get
  14. ax25_dev_get_dev
  15. ax25_dev_get_value
  16. ax25_dev_device_up
  17. ax25_dev_device_down
  18. ax25_dev_ioctl
  19. ax25_bpq_get_info
  20. ax25_bpq_get_addr
  21. ax25_bpq_ioctl

   1 /*
   2  *      AX.25 release 031
   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  *      Other kernels modules in this kit are generally BSD derived. See the copyright headers.
  16  *
  17  *
  18  *      History
  19  *      AX.25 020       Jonathan(G4KLX) First go.
  20  *      AX.25 022       Jonathan(G4KLX) Added the actual meat to this - we now have a nice mheard list.
  21  *      AX.25 025       Alan(GW4PTS)    First cut at autobinding by route scan.
  22  *      AX.25 028b      Jonathan(G4KLX) Extracted AX25 control block from the
  23  *                                      sock structure. Device removal now
  24  *                                      removes the heard structure.
  25  *      AX.25 029       Steven(GW7RRM)  Added /proc information for uid/callsign mapping.
  26  *                      Jonathan(G4KLX) Handling of IP mode in the routing list and /proc entry.
  27  *      AX.25 030       Jonathan(G4KLX) Added digi-peaters to routing table, and
  28  *                                      ioctls to manipulate them. Added port
  29  *                                      configuration.
  30  *      AX.25 031       Jonathan(G4KLX) Added concept of default route.
  31  *                      Joerg(DL1BKE)   ax25_rt_build_path() find digipeater list and device by 
  32  *                                      destination call. Needed for IP routing via digipeater
  33  *                      Jonathan(G4KLX) Added routing for IP datagram packets.
  34  *                      Joerg(DL1BKE)   changed routing for IP datagram and VC to use a default
  35  *                                      route if available. Does not overwrite default routes
  36  *                                      on route-table overflow anymore.
  37  *                      Joerg(DL1BKE)   fixed AX.25 routing of IP datagram and VC, new ioctl()
  38  *                                      "SIOCAX25OPTRT" to set IP mode and a 'permanent' flag
  39  *                                      on routes.
  40  */
  41  
  42 #include <linux/config.h>
  43 #ifdef CONFIG_AX25
  44 #include <linux/errno.h>
  45 #include <linux/types.h>
  46 #include <linux/socket.h>
  47 #include <linux/in.h>
  48 #include <linux/kernel.h>
  49 #include <linux/sched.h>
  50 #include <linux/timer.h>
  51 #include <linux/string.h>
  52 #include <linux/sockios.h>
  53 #include <linux/net.h>
  54 #include <net/ax25.h>
  55 #include <linux/inet.h>
  56 #include <linux/netdevice.h>
  57 #include <linux/if_arp.h>
  58 #include <linux/skbuff.h>
  59 #include <net/sock.h>
  60 #include <asm/segment.h>
  61 #include <asm/system.h>
  62 #include <linux/fcntl.h>
  63 #include <linux/mm.h>
  64 #include <linux/interrupt.h>
  65 
  66 #define AX25_ROUTE_MAX  128
  67 
  68 static struct ax25_route {
  69         struct ax25_route *next;
  70         ax25_address callsign;
  71         struct device *dev;
  72         ax25_digi *digipeat;
  73         struct timeval stamp;
  74         int n;
  75         char ip_mode;
  76         char perm;
  77 } *ax25_route = NULL;
  78 
  79 static struct ax25_dev {
  80         struct ax25_dev *next;
  81         struct device *dev;
  82         unsigned short values[AX25_MAX_VALUES];
  83 } *ax25_device = NULL;
  84 
  85 static struct ax25_route * ax25_find_route(ax25_address *addr);
  86 
  87 /*
  88  * small macro to drop non-digipeated digipeaters and reverse path
  89  */
  90  
  91 static inline void ax25_route_invert(ax25_digi *in, ax25_digi *out)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93         int k;
  94         for (k = 0; k < in->ndigi; k++)
  95                 if (!in->repeated[k])
  96                         break;
  97         in->ndigi = k;
  98         ax25_digi_invert(in, out);
  99 
 100 }
 101 
 102 /*
 103  * dl1bke 960310: new behaviour:
 104  *
 105  * * try to find an existing route to 'src', if found:
 106  *   - if the route was added manually don't adjust the timestamp
 107  *   - if this route is 'permanent' just do some statistics and return
 108  *   - overwrite device and digipeater path
 109  * * no existing route found:
 110  *   - try to alloc a new entry
 111  *   - overwrite the oldest, not manually added entry if this fails.
 112  *
 113  * * updated on receiption of frames directed to us _only_
 114  *
 115  */
 116 
 117 void ax25_rt_rx_frame(ax25_address *src, struct device *dev, ax25_digi *digi)
     /* [previous][next][first][last][top][bottom][index][help] */
 118 {
 119         unsigned long flags;
 120         extern struct timeval xtime;
 121         struct ax25_route *ax25_rt;
 122         struct ax25_route *oldest;
 123         int count;
 124 
 125         count  = 0;
 126         oldest = NULL;
 127 
 128         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 129                 if (count == 0 || oldest->stamp.tv_sec == 0 || (ax25_rt->stamp.tv_sec != 0 && ax25_rt->stamp.tv_sec < oldest->stamp.tv_sec))
 130                         oldest = ax25_rt;
 131                 
 132                 if (ax25cmp(&ax25_rt->callsign, src) == 0) {
 133                         if (ax25_rt->stamp.tv_sec != 0)
 134                                 ax25_rt->stamp = xtime;
 135 
 136                         if (ax25_rt->perm == AX25_RT_PERMANENT) {
 137                                 ax25_rt->n++;
 138                                 return;
 139                         }
 140                         
 141                         ax25_rt->dev = dev;
 142                         if (digi == NULL) {
 143                                 /* drop old digipeater list */
 144                                 if (ax25_rt->digipeat != NULL) {
 145                                         kfree_s(ax25_rt->digipeat, sizeof(ax25_digi));
 146                                         ax25_rt->digipeat = NULL;
 147                                 }
 148                                 return;
 149                         }
 150                         
 151                         if (ax25_rt->digipeat == NULL && (ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
 152                                         return;
 153                         
 154                         ax25_route_invert(digi, ax25_rt->digipeat);
 155                         return;
 156                 }
 157 
 158                 count++;
 159         }
 160 
 161         if (count > AX25_ROUTE_MAX) {
 162                 if (oldest->stamp.tv_sec == 0)
 163                         return;
 164                 if (oldest->digipeat != NULL)
 165                         kfree_s(oldest->digipeat, sizeof(ax25_digi));
 166                 ax25_rt = oldest;
 167         } else {
 168                 if ((ax25_rt = (struct ax25_route *)kmalloc(sizeof(struct ax25_route), GFP_ATOMIC)) == NULL)
 169                         return;         /* No space */
 170         }
 171         
 172         ax25_rt->callsign = *src;
 173         ax25_rt->dev      = dev;
 174         ax25_rt->digipeat = NULL;
 175         ax25_rt->stamp    = xtime;
 176         ax25_rt->n        = 1;
 177         ax25_rt->ip_mode  = ' ';
 178         ax25_rt->perm     = AX25_RT_DYNAMIC;
 179 
 180         if (digi != NULL) {
 181                 if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
 182                         kfree_s(ax25_rt, sizeof(struct ax25_route));
 183                         return;
 184                 }
 185                 
 186                 ax25_route_invert(digi, ax25_rt->digipeat);
 187                 /* used to be: *ax25_rt->digipeat = *digi; */
 188         }
 189 
 190         if (ax25_rt != oldest) {
 191                 save_flags(flags);
 192                 cli();
 193 
 194                 ax25_rt->next = ax25_route;
 195                 ax25_route    = ax25_rt;
 196 
 197                 restore_flags(flags);
 198         }
 199 }
 200 
 201 void ax25_rt_device_down(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 202 {
 203         struct ax25_route *s, *t, *ax25_rt = ax25_route;
 204         
 205         while (ax25_rt != NULL) {
 206                 s       = ax25_rt;
 207                 ax25_rt = ax25_rt->next;
 208 
 209                 if (s->dev == dev) {
 210                         if (ax25_route == s) {
 211                                 ax25_route = s->next;
 212                                 if (s->digipeat != NULL)
 213                                         kfree_s((void *)s->digipeat, sizeof(ax25_digi));
 214                                 kfree_s((void *)s, (sizeof *s));
 215                         } else {
 216                                 for (t = ax25_route; t != NULL; t = t->next) {
 217                                         if (t->next == s) {
 218                                                 t->next = s->next;
 219                                                 if (s->digipeat != NULL)
 220                                                         kfree_s((void *)s->digipeat, sizeof(ax25_digi));
 221                                                 kfree_s((void *)s, sizeof(*s));
 222                                                 break;
 223                                         }
 224                                 }                               
 225                         }
 226                 }
 227         }
 228 }
 229 
 230 int ax25_rt_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 231 {
 232         unsigned long flags;
 233         struct ax25_route *s, *t, *ax25_rt;
 234         struct ax25_routes_struct route;
 235         struct ax25_route_opt_struct rt_option;
 236         struct device *dev;
 237         int i, err;
 238 
 239         switch (cmd) {
 240                 case SIOCADDRT:
 241                         if ((err = verify_area(VERIFY_READ, arg, sizeof(route))) != 0)
 242                                 return err;             
 243                         memcpy_fromfs(&route, arg, sizeof(route));
 244                         if ((dev = ax25rtr_get_dev(&route.port_addr)) == NULL)
 245                                 return -EINVAL;
 246                         if (route.digi_count > AX25_MAX_DIGIS)
 247                                 return -EINVAL;
 248                         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 249                                 if (ax25cmp(&ax25_rt->callsign, &route.dest_addr) == 0 && ax25_rt->dev == dev) {
 250                                         if (ax25_rt->digipeat != NULL) {
 251                                                 kfree_s(ax25_rt->digipeat, sizeof(ax25_digi));
 252                                                 ax25_rt->digipeat = NULL;
 253                                         }
 254                                         if (route.digi_count != 0) {
 255                                                 if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
 256                                                         return -ENOMEM;
 257                                                 ax25_rt->digipeat->lastrepeat = 0;
 258                                                 ax25_rt->digipeat->ndigi      = route.digi_count;
 259                                                 for (i = 0; i < route.digi_count; i++) {
 260                                                         ax25_rt->digipeat->repeated[i] = 0;
 261                                                         ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
 262                                                 }
 263                                         }
 264                                         ax25_rt->stamp.tv_sec = 0;
 265                                         return 0;
 266                                 }
 267                         }
 268                         if ((ax25_rt = (struct ax25_route *)kmalloc(sizeof(struct ax25_route), GFP_ATOMIC)) == NULL)
 269                                 return -ENOMEM;
 270                         ax25_rt->callsign     = route.dest_addr;
 271                         ax25_rt->dev          = dev;
 272                         ax25_rt->digipeat     = NULL;
 273                         ax25_rt->stamp.tv_sec = 0;
 274                         ax25_rt->n            = 0;
 275                         ax25_rt->ip_mode      = ' ';
 276                         ax25_rt->perm         = AX25_RT_DYNAMIC;
 277                         if (route.digi_count != 0) {
 278                                 if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
 279                                         kfree_s(ax25_rt, sizeof(struct ax25_route));
 280                                         return -ENOMEM;
 281                                 }
 282                                 ax25_rt->digipeat->lastrepeat = 0;
 283                                 ax25_rt->digipeat->ndigi      = route.digi_count;
 284                                 for (i = 0; i < route.digi_count; i++) {
 285                                         ax25_rt->digipeat->repeated[i] = 0;
 286                                         ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
 287                                 }
 288                         }
 289                         save_flags(flags);
 290                         cli();
 291                         ax25_rt->next = ax25_route;
 292                         ax25_route    = ax25_rt;
 293                         restore_flags(flags);
 294                         break;
 295 
 296                 case SIOCDELRT:
 297                         if ((err = verify_area(VERIFY_READ, arg, sizeof(route))) != 0)
 298                                 return err;
 299                         memcpy_fromfs(&route, arg, sizeof(route));
 300                         if ((dev = ax25rtr_get_dev(&route.port_addr)) == NULL)
 301                                 return -EINVAL;
 302                         ax25_rt = ax25_route;
 303                         while (ax25_rt != NULL) {
 304                                 s       = ax25_rt;
 305                                 ax25_rt = ax25_rt->next;
 306                                 if (s->dev == dev && ax25cmp(&route.dest_addr, &s->callsign) == 0) {
 307                                         if (ax25_route == s) {
 308                                                 ax25_route = s->next;
 309                                                 if (s->digipeat != NULL)
 310                                                         kfree_s((void *)s->digipeat, sizeof(ax25_digi));
 311                                                 kfree_s((void *)s, (sizeof *s));
 312                                         } else {
 313                                                 for (t = ax25_route; t != NULL; t = t->next) {
 314                                                         if (t->next == s) {
 315                                                                 t->next = s->next;
 316                                                                 if (s->digipeat != NULL)
 317                                                                         kfree_s((void *)s->digipeat, sizeof(ax25_digi));
 318                                                                 kfree_s((void *)s, sizeof(*s));
 319                                                                 break;
 320                                                         }
 321                                                 }                               
 322                                         }
 323                                 }
 324                         }
 325                         break;
 326                 case SIOCAX25OPTRT:
 327                         if ((err = verify_area(VERIFY_READ, arg, sizeof(rt_option))) != 0)
 328                                 return err;
 329                         memcpy_fromfs(&rt_option, arg, sizeof(rt_option));
 330                         if ((dev = ax25rtr_get_dev(&rt_option.port_addr)) == NULL)
 331                                 return -EINVAL;
 332                         ax25_rt = ax25_route;
 333                         while (ax25_rt != NULL) {
 334                                 if (ax25_rt->dev == dev && ax25cmp(&rt_option.dest_addr, &ax25_rt->callsign) == 0) {
 335                                         switch(rt_option.cmd) {
 336                                                 case AX25_SET_RT_PERMANENT:
 337                                                         ax25_rt->perm = (char) rt_option.arg;
 338                                                         ax25_rt->stamp.tv_sec = 0;
 339                                                         break;
 340                                                 case AX25_SET_RT_IPMODE:
 341                                                         switch (rt_option.arg) {
 342                                                                 case AX25_RT_IPMODE_DEFAULT:
 343                                                                         ax25_rt->ip_mode = ' ';
 344                                                                         break;
 345                                                                 case AX25_RT_IPMODE_DATAGRAM:
 346                                                                         ax25_rt->ip_mode = 'D';
 347                                                                         break;
 348                                                                 case AX25_RT_IPMODE_VC:
 349                                                                         ax25_rt->ip_mode = 'V';
 350                                                                         break;
 351                                                                 default:
 352                                                                         return -EINVAL;
 353                                                         }
 354                                                         break;
 355                                         }
 356                                 }
 357                                 ax25_rt = ax25_rt->next;
 358                         }
 359                         break;
 360         }
 361 
 362         return 0;
 363 }
 364 
 365 int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 366 {
 367         struct ax25_route *ax25_rt;
 368         int len     = 0;
 369         off_t pos   = 0;
 370         off_t begin = 0;
 371         char *callsign;
 372         int i;
 373   
 374         cli();
 375 
 376         len += sprintf(buffer, "callsign  dev  count time      mode F digipeaters\n");
 377 
 378         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 379                 if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
 380                         callsign = "default";
 381                 else
 382                         callsign = ax2asc(&ax25_rt->callsign);
 383                 len += sprintf(buffer + len, "%-9s %-4s %5d %9d",
 384                         callsign,
 385                         ax25_rt->dev ? ax25_rt->dev->name : "???",
 386                         ax25_rt->n,
 387                         ax25_rt->stamp.tv_sec);
 388 
 389                 switch (ax25_rt->ip_mode) {
 390                         case 'V':
 391                         case 'v':
 392                                 len += sprintf(buffer + len, "   vc");
 393                                 break;
 394                         case 'D':
 395                         case 'd':
 396                                 len += sprintf(buffer + len, "   dg");
 397                                 break;
 398                         default:
 399                                 len += sprintf(buffer + len, "    *");
 400                                 break;
 401                 }
 402                 
 403                 switch (ax25_rt->perm) {
 404                         case AX25_RT_DYNAMIC:
 405                                 if (ax25_rt->stamp.tv_sec == 0)
 406                                         len += sprintf(buffer + len, " M");
 407                                 else
 408                                         len += sprintf(buffer + len, "  ");
 409                                 break;
 410                         case AX25_RT_PERMANENT:
 411                                 len += sprintf(buffer + len, " P");
 412                                 break;
 413                         default:
 414                                 len += sprintf(buffer + len, " ?");
 415                 }
 416 
 417                 if (ax25_rt->digipeat != NULL)
 418                         for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
 419                                 len += sprintf(buffer + len, " %s", ax2asc(&ax25_rt->digipeat->calls[i]));
 420                 
 421                 len += sprintf(buffer + len, "\n");
 422                                 
 423                 pos = begin + len;
 424 
 425                 if (pos < offset) {
 426                         len   = 0;
 427                         begin = pos;
 428                 }
 429                 
 430                 if (pos > offset + length)
 431                         break;
 432         }
 433 
 434         sti();
 435 
 436         *start = buffer + (offset - begin);
 437         len   -= (offset - begin);
 438 
 439         if (len > length) len = length;
 440 
 441         return len;
 442 } 
 443 
 444 int ax25_cs_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 445 {
 446         ax25_uid_assoc *pt;
 447         int len     = 0;
 448         off_t pos   = 0;
 449         off_t begin = 0;
 450 
 451         cli();
 452 
 453         len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy);
 454 
 455         for (pt = ax25_uid_list; pt != NULL; pt = pt->next) {
 456                 len += sprintf(buffer + len, "%6d %s\n", pt->uid, ax2asc(&pt->call));
 457 
 458                 pos = begin + len;
 459 
 460                 if (pos < offset) {
 461                         len = 0;
 462                         begin = pos;
 463                 }
 464 
 465                 if (pos > offset + length)
 466                         break;
 467         }
 468 
 469         sti();
 470 
 471         *start = buffer + (offset - begin);
 472         len   -= offset - begin;
 473 
 474         if (len > length) len = length;
 475 
 476         return len;
 477 }
 478 
 479 /*
 480  *      Find AX.25 route
 481  */
 482  
 483 static struct ax25_route * ax25_find_route(ax25_address *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 484 {
 485         struct ax25_route *ax25_spe_rt = NULL;
 486         struct ax25_route *ax25_def_rt = NULL;
 487         struct ax25_route *ax25_rt;
 488         
 489         /*
 490          *      Bind to the physical interface we heard them on, or the default
 491          *      route if non is found;
 492          */
 493         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 494                 if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
 495                         ax25_spe_rt = ax25_rt;
 496                 if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
 497                         ax25_def_rt = ax25_rt;
 498         }
 499 
 500         if (ax25_spe_rt != NULL)
 501                 return ax25_spe_rt;
 502                 
 503         return ax25_def_rt;
 504 }
 505 
 506 /*
 507  *      Adjust path: If you specify a default route and want to connect
 508  *      a target on the digipeater path but w/o having a special route
 509  *      set before, the path has to be truncated from your target on.
 510  */
 511  
 512 static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
     /* [previous][next][first][last][top][bottom][index][help] */
 513 {
 514         int k;
 515         
 516         for (k = 0; k < digipeat->ndigi; k++) {
 517                 if (ax25cmp(addr, &digipeat->calls[k]) == 0)
 518                         break;
 519         }
 520         
 521         digipeat->ndigi = k;
 522 }
 523  
 524 
 525 /*
 526  *      Find which interface to use.
 527  */
 528 int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 529 {
 530         struct ax25_route *ax25_rt;
 531         ax25_address *call;
 532 
 533         if ((ax25_rt = ax25_find_route(addr)) == NULL)
 534                 return -EHOSTUNREACH;
 535                 
 536         if ((call = ax25_findbyuid(current->euid)) == NULL) {
 537                 if (ax25_uid_policy && !suser())
 538                         return -EPERM;
 539                 if (ax25->device == NULL)
 540                         return -ENODEV;
 541                 call = (ax25_address *)ax25->device->dev_addr;
 542         }
 543 
 544         ax25->source_addr = *call;
 545 
 546         if (ax25_rt->digipeat != NULL) {
 547                 if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
 548                         return -ENOMEM;
 549                 *ax25->digipeat = *ax25_rt->digipeat;
 550                 ax25_adjust_path(addr, ax25->digipeat);
 551         }
 552 
 553         if (ax25->sk != NULL)
 554                 ax25->sk->zapped = 0;
 555 
 556         return 0;
 557 }
 558 
 559 /*
 560  *      dl1bke 960117: build digipeater path
 561  *      dl1bke 960301: use the default route if it exists
 562  */
 563 void ax25_rt_build_path(ax25_cb *ax25, ax25_address *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 564 {
 565         struct ax25_route *ax25_rt;
 566         
 567         ax25_rt = ax25_find_route(addr);
 568         
 569         if (ax25_rt == NULL || ax25_rt->digipeat == NULL)
 570                 return;
 571 
 572         if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
 573                 return;
 574 
 575         ax25->device = ax25_rt->dev;
 576         *ax25->digipeat = *ax25_rt->digipeat;
 577         ax25_adjust_path(addr, ax25->digipeat);
 578 }
 579 
 580 void ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 581 {
 582         struct ax25_route *ax25_rt;
 583         ax25_digi digipeat;
 584         ax25_address src, dest;
 585         unsigned char *bp;
 586         int len;
 587         
 588 
 589         ax25_rt = ax25_find_route(addr);
 590         if (ax25_rt == NULL || ax25_rt->digipeat == NULL)
 591                 return;
 592                 
 593         digipeat = *ax25_rt->digipeat;
 594         
 595         ax25_adjust_path(addr, &digipeat);
 596 
 597         len = ax25_rt->digipeat->ndigi * AX25_ADDR_LEN;
 598                 
 599         if (skb_headroom(skb) < len) {
 600                 printk("ax25_dg_build_path: not enough headroom for in skb\n");
 601                 return;
 602         }
 603 
 604         memcpy(&dest, skb->data + 1, AX25_ADDR_LEN);
 605         memcpy(&src,  skb->data + 8, AX25_ADDR_LEN);
 606         
 607 
 608         bp = skb_push(skb, len);
 609         *bp++ = 0x00;           /* KISS Data */
 610 
 611         build_ax25_addr(bp, &src, &dest, ax25_rt->digipeat, C_COMMAND, MODULUS);
 612 }
 613 
 614 /*
 615  *      Register the mode of an incoming IP frame. It is assumed that an entry
 616  *      already exists in the routing table.
 617  */
 618 void ax25_ip_mode_set(ax25_address *callsign, struct device *dev, char ip_mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 619 {
 620         struct ax25_route *ax25_rt;
 621 
 622         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 623                 if (ax25cmp(&ax25_rt->callsign, callsign) == 0 && ax25_rt->dev == dev) {
 624                         ax25_rt->ip_mode = ip_mode;
 625                         return;
 626                 }
 627         }
 628 }
 629 
 630 /*
 631  *      Return the IP mode of a given callsign/device pair.
 632  */
 633 char ax25_ip_mode_get(ax25_address *callsign, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 634 {
 635         struct ax25_route *ax25_rt;
 636 
 637         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next)
 638                 if (ax25cmp(&ax25_rt->callsign, callsign) == 0 && ax25_rt->dev == dev)
 639                         return ax25_rt->ip_mode;
 640 
 641         return ' ';
 642 }
 643 
 644 static struct ax25_dev *ax25_dev_get_dev(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 645 {
 646         struct ax25_dev *s;
 647 
 648         for (s = ax25_device; s != NULL; s = s->next)
 649                 if (s->dev == dev)
 650                         return s;
 651         
 652         return NULL;
 653 }
 654 
 655 /*
 656  *      Wow, a bit of data hiding. Is this C++ or what ?
 657  */
 658 unsigned short ax25_dev_get_value(struct device *dev, int valueno)
     /* [previous][next][first][last][top][bottom][index][help] */
 659 {
 660         struct ax25_dev *ax25_dev;
 661 
 662         if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL) {
 663                 printk("ax25_dev_get_flag called with invalid device\n");
 664                 return 1;
 665         }
 666 
 667         return ax25_dev->values[valueno];
 668 }
 669 
 670 /*
 671  *      This is called when an interface is brought up. These are
 672  *      reasonable defaults.
 673  */
 674 void ax25_dev_device_up(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 675 {
 676         unsigned long flags;
 677         struct ax25_dev *ax25_dev;
 678         
 679         if ((ax25_dev = (struct ax25_dev *)kmalloc(sizeof(struct ax25_dev), GFP_ATOMIC)) == NULL)
 680                 return;         /* No space */
 681 
 682         ax25_dev->dev        = dev;
 683 
 684         ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE;
 685         ax25_dev->values[AX25_VALUES_AXDEFMODE] = AX25_DEF_AXDEFMODE;
 686         ax25_dev->values[AX25_VALUES_NETROM]    = AX25_DEF_NETROM;
 687         ax25_dev->values[AX25_VALUES_TEXT]      = AX25_DEF_TEXT;
 688         ax25_dev->values[AX25_VALUES_BACKOFF]   = AX25_DEF_BACKOFF;
 689         ax25_dev->values[AX25_VALUES_CONMODE]   = AX25_DEF_CONMODE;
 690         ax25_dev->values[AX25_VALUES_WINDOW]    = AX25_DEF_WINDOW;
 691         ax25_dev->values[AX25_VALUES_EWINDOW]   = AX25_DEF_EWINDOW;
 692         ax25_dev->values[AX25_VALUES_T1]        = AX25_DEF_T1 * PR_SLOWHZ;
 693         ax25_dev->values[AX25_VALUES_T2]        = AX25_DEF_T2 * PR_SLOWHZ;
 694         ax25_dev->values[AX25_VALUES_T3]        = AX25_DEF_T3 * PR_SLOWHZ;
 695         ax25_dev->values[AX25_VALUES_IDLE]      = AX25_DEF_IDLE * PR_SLOWHZ * 60;
 696         ax25_dev->values[AX25_VALUES_N2]        = AX25_DEF_N2;
 697         ax25_dev->values[AX25_VALUES_DIGI]      = AX25_DEF_DIGI;
 698         ax25_dev->values[AX25_VALUES_PACLEN]    = AX25_DEF_PACLEN;
 699 
 700         save_flags(flags);
 701         cli();
 702 
 703         ax25_dev->next = ax25_device;
 704         ax25_device    = ax25_dev;
 705 
 706         restore_flags(flags);
 707 }
 708 
 709 void ax25_dev_device_down(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 710 {
 711         struct ax25_dev *s, *t, *ax25_dev = ax25_device;
 712         
 713         while (ax25_dev != NULL) {
 714                 s        = ax25_dev;
 715                 ax25_dev = ax25_dev->next;
 716 
 717                 if (s->dev == dev) {
 718                         if (ax25_device == s) {
 719                                 ax25_device = s->next;
 720                                 kfree_s((void *)s, (sizeof *s));
 721                         } else {
 722                                 for (t = ax25_device; t != NULL; t = t->next) {
 723                                         if (t->next == s) {
 724                                                 t->next = s->next;
 725                                                 kfree_s((void *)s, sizeof(*s));
 726                                                 break;
 727                                         }
 728                                 }                               
 729                         }
 730                 }
 731         }
 732 }
 733 
 734 int ax25_dev_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 735 {
 736         struct ax25_parms_struct ax25_parms;
 737         struct device *dev;
 738         struct ax25_dev *ax25_dev;
 739         int err;
 740 
 741         switch (cmd) {
 742                 case SIOCAX25SETPARMS:
 743                         if (!suser())
 744                                 return -EPERM;
 745                         if ((err = verify_area(VERIFY_READ, arg, sizeof(ax25_parms))) != 0)
 746                                 return err;
 747                         memcpy_fromfs(&ax25_parms, arg, sizeof(ax25_parms));
 748                         if ((dev = ax25rtr_get_dev(&ax25_parms.port_addr)) == NULL)
 749                                 return -EINVAL;
 750                         if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL)
 751                                 return -EINVAL;
 752                         if (ax25_parms.values[AX25_VALUES_IPDEFMODE] != 'D' &&
 753                             ax25_parms.values[AX25_VALUES_IPDEFMODE] != 'V')
 754                                 return -EINVAL;
 755                         if (ax25_parms.values[AX25_VALUES_AXDEFMODE] != MODULUS &&
 756                             ax25_parms.values[AX25_VALUES_AXDEFMODE] != EMODULUS)
 757                                 return -EINVAL;
 758                         if (ax25_parms.values[AX25_VALUES_NETROM] != 0 &&
 759                             ax25_parms.values[AX25_VALUES_NETROM] != 1)
 760                                 return -EINVAL;
 761                         if (ax25_parms.values[AX25_VALUES_TEXT] != 0 &&
 762                             ax25_parms.values[AX25_VALUES_TEXT] != 1)
 763                                 return -EINVAL;
 764                         if (ax25_parms.values[AX25_VALUES_BACKOFF] != 'E' &&
 765                             ax25_parms.values[AX25_VALUES_BACKOFF] != 'L')
 766                                 return -EINVAL;
 767                         if (ax25_parms.values[AX25_VALUES_CONMODE] != 0 &&
 768                             ax25_parms.values[AX25_VALUES_CONMODE] != 1)
 769                                 return -EINVAL;
 770                         if (ax25_parms.values[AX25_VALUES_WINDOW] < 1 ||
 771                             ax25_parms.values[AX25_VALUES_WINDOW] > 7)
 772                                 return -EINVAL;
 773                         if (ax25_parms.values[AX25_VALUES_EWINDOW] < 1 ||
 774                             ax25_parms.values[AX25_VALUES_EWINDOW] > 63)
 775                                 return -EINVAL;
 776                         if (ax25_parms.values[AX25_VALUES_T1] < 1)
 777                                 return -EINVAL;
 778                         if (ax25_parms.values[AX25_VALUES_T2] < 1)
 779                                 return -EINVAL;
 780                         if (ax25_parms.values[AX25_VALUES_T3] < 1)
 781                                 return -EINVAL;
 782                         if (ax25_parms.values[AX25_VALUES_IDLE] > 100)
 783                                 return -EINVAL;
 784                         if (ax25_parms.values[AX25_VALUES_N2] < 1 ||
 785                             ax25_parms.values[AX25_VALUES_N2] > 31)
 786                                 return -EINVAL;
 787                         if (ax25_parms.values[AX25_VALUES_PACLEN] < 16)
 788                                 return -EINVAL;
 789                         if ((ax25_parms.values[AX25_VALUES_DIGI] &
 790                             ~(AX25_DIGI_INBAND | AX25_DIGI_XBAND)) != 0)
 791                                 return -EINVAL;
 792                         memcpy(ax25_dev->values, ax25_parms.values, AX25_MAX_VALUES * sizeof(short));
 793                         ax25_dev->values[AX25_VALUES_T1] *= PR_SLOWHZ;
 794                         ax25_dev->values[AX25_VALUES_T1] /= 2;
 795                         ax25_dev->values[AX25_VALUES_T2] *= PR_SLOWHZ;
 796                         ax25_dev->values[AX25_VALUES_T3] *= PR_SLOWHZ;
 797                         ax25_dev->values[AX25_VALUES_IDLE] *= PR_SLOWHZ * 60;
 798                         break;
 799 
 800                 case SIOCAX25GETPARMS:
 801                         if ((err = verify_area(VERIFY_WRITE, arg, sizeof(struct ax25_parms_struct))) != 0)
 802                                 return err;
 803                         memcpy_fromfs(&ax25_parms, arg, sizeof(ax25_parms));
 804                         if ((dev = ax25rtr_get_dev(&ax25_parms.port_addr)) == NULL)
 805                                 return -EINVAL;
 806                         if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL)
 807                                 return -EINVAL;
 808                         memcpy(ax25_parms.values, ax25_dev->values, AX25_MAX_VALUES * sizeof(short));
 809                         ax25_parms.values[AX25_VALUES_T1] *= 2;
 810                         ax25_parms.values[AX25_VALUES_T1] /= PR_SLOWHZ;
 811                         ax25_parms.values[AX25_VALUES_T2] /= PR_SLOWHZ;
 812                         ax25_parms.values[AX25_VALUES_T3] /= PR_SLOWHZ;
 813                         ax25_parms.values[AX25_VALUES_IDLE] /= PR_SLOWHZ * 60;
 814                         memcpy_tofs(arg, &ax25_parms, sizeof(ax25_parms));
 815                         break;
 816         }
 817 
 818         return 0;
 819 }
 820 
 821 #ifdef CONFIG_BPQETHER
 822 static struct ax25_bpqdev {
 823         struct ax25_bpqdev *next;
 824         struct device *dev;
 825         ax25_address callsign;
 826 } *ax25_bpqdev = NULL;
 827 
 828 int ax25_bpq_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 829 {
 830         struct ax25_bpqdev *bpqdev;
 831         int len     = 0;
 832         off_t pos   = 0;
 833         off_t begin = 0;
 834   
 835         cli();
 836 
 837         len += sprintf(buffer, "dev  callsign\n");
 838 
 839         for (bpqdev = ax25_bpqdev; bpqdev != NULL; bpqdev = bpqdev->next) {
 840                 len += sprintf(buffer + len, "%-4s %-9s\n",
 841                         bpqdev->dev ? bpqdev->dev->name : "???",
 842                         ax2asc(&bpqdev->callsign));
 843 
 844                 pos = begin + len;
 845 
 846                 if (pos < offset) {
 847                         len   = 0;
 848                         begin = pos;
 849                 }
 850                 
 851                 if (pos > offset + length)
 852                         break;
 853         }
 854 
 855         sti();
 856 
 857         *start = buffer + (offset - begin);
 858         len   -= (offset - begin);
 859 
 860         if (len > length) len = length;
 861 
 862         return len;
 863 } 
 864 
 865 ax25_address *ax25_bpq_get_addr(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 866 {
 867         struct ax25_bpqdev *bpqdev;
 868         
 869         for (bpqdev = ax25_bpqdev; bpqdev != NULL; bpqdev = bpqdev->next)
 870                 if (bpqdev->dev == dev)
 871                         return &bpqdev->callsign;
 872 
 873         return NULL;
 874 }
 875 
 876 int ax25_bpq_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 877 {
 878         unsigned long flags;
 879         struct ax25_bpqdev *bpqdev;
 880         struct ax25_bpqaddr_struct bpqaddr;
 881         struct device *dev;
 882         int err;
 883 
 884         switch (cmd) {
 885                 case SIOCAX25BPQADDR:
 886                         if ((err = verify_area(VERIFY_READ, arg, sizeof(bpqaddr))) != 0)
 887                                 return err;
 888                         memcpy_fromfs(&bpqaddr, arg, sizeof(bpqaddr));
 889                         if ((dev = dev_get(bpqaddr.dev)) == NULL)
 890                                 return -EINVAL;
 891                         if (dev->type != ARPHRD_ETHER)
 892                                 return -EINVAL;
 893                         for (bpqdev = ax25_bpqdev; bpqdev != NULL; bpqdev = bpqdev->next) {
 894                                 if (bpqdev->dev == dev) {
 895                                         bpqdev->callsign = bpqaddr.addr;
 896                                         return 0;
 897                                 }
 898                         }
 899                         if ((bpqdev = (struct ax25_bpqdev *)kmalloc(sizeof(struct ax25_bpqdev), GFP_ATOMIC)) == NULL)
 900                                 return -ENOMEM;
 901                         bpqdev->dev      = dev;
 902                         bpqdev->callsign = bpqaddr.addr;
 903                         save_flags(flags);
 904                         cli();
 905                         bpqdev->next = ax25_bpqdev;
 906                         ax25_bpqdev  = bpqdev;
 907                         restore_flags(flags);
 908                         break;
 909         }
 910 
 911         return 0;
 912 }
 913 
 914 #endif
 915 
 916 #endif

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