root/net/ax25/ax25_route.c

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

DEFINITIONS

This source file includes following definitions.
  1. ax25_rt_rx_frame
  2. ax25_rt_device_down
  3. ax25_rt_ioctl
  4. ax25_rt_get_info
  5. ax25_cs_get_info
  6. ax25_rt_autobind
  7. ax25_rt_build_path
  8. ax25_dg_build_path
  9. ax25_ip_mode_set
  10. ax25_ip_mode_get
  11. ax25_dev_get_dev
  12. ax25_dev_get_value
  13. ax25_dev_device_up
  14. ax25_dev_device_down
  15. ax25_dev_ioctl
  16. ax25_bpq_get_info
  17. ax25_bpq_get_addr
  18. 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  */
  38  
  39 #include <linux/config.h>
  40 #ifdef CONFIG_AX25
  41 #include <linux/errno.h>
  42 #include <linux/types.h>
  43 #include <linux/socket.h>
  44 #include <linux/in.h>
  45 #include <linux/kernel.h>
  46 #include <linux/sched.h>
  47 #include <linux/timer.h>
  48 #include <linux/string.h>
  49 #include <linux/sockios.h>
  50 #include <linux/net.h>
  51 #include <net/ax25.h>
  52 #include <linux/inet.h>
  53 #include <linux/netdevice.h>
  54 #include <linux/if_arp.h>
  55 #include <linux/skbuff.h>
  56 #include <net/sock.h>
  57 #include <asm/segment.h>
  58 #include <asm/system.h>
  59 #include <linux/fcntl.h>
  60 #include <linux/mm.h>
  61 #include <linux/interrupt.h>
  62 
  63 #define AX25_ROUTE_MAX  40
  64 
  65 static struct ax25_route {
  66         struct ax25_route *next;
  67         ax25_address callsign;
  68         struct device *dev;
  69         ax25_digi *digipeat;
  70         struct timeval stamp;
  71         int n;
  72         char ip_mode;
  73 } *ax25_route = NULL;
  74 
  75 static struct ax25_dev {
  76         struct ax25_dev *next;
  77         struct device *dev;
  78         unsigned short values[AX25_MAX_VALUES];
  79 } *ax25_device = NULL;
  80 
  81 /*
  82  * FIXME: heard and routing table should be two lists. The routing table
  83  *        should be updated by connects only. (WAMPES way of doing it)
  84  *
  85  *        routing table should accept a new route to the same destination
  86  *        if the old one was added manually. Nevertheless we should still
  87  *        be able to add permanent routes. (dl1bke)
  88  */
  89 
  90 void ax25_rt_rx_frame(ax25_address *src, struct device *dev, ax25_digi *digi)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92         unsigned long flags;
  93         extern struct timeval xtime;
  94         struct ax25_route *ax25_rt;
  95         struct ax25_route *oldest;
  96         int count;
  97 
  98         count  = 0;
  99         oldest = NULL;
 100 
 101         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 102                 if (count == 0 || oldest->stamp.tv_sec == 0 || (ax25_rt->stamp.tv_sec != 0 && ax25_rt->stamp.tv_sec < oldest->stamp.tv_sec))
 103                         oldest = ax25_rt;
 104                 
 105                 if (ax25cmp(&ax25_rt->callsign, src) == 0 && ax25_rt->dev == dev) {
 106                         if (ax25_rt->stamp.tv_sec != 0)
 107                                 ax25_rt->stamp = xtime;
 108                         ax25_rt->n++;
 109                         return;                 
 110                 }
 111 
 112                 count++;
 113         }
 114 
 115         if (count > AX25_ROUTE_MAX) {
 116                 if (oldest->stamp.tv_sec == 0)
 117                         return;
 118                 if (oldest->digipeat != NULL)
 119                         kfree_s(oldest->digipeat, sizeof(ax25_digi));
 120                 ax25_rt = oldest;
 121         } else {
 122                 if ((ax25_rt = (struct ax25_route *)kmalloc(sizeof(struct ax25_route), GFP_ATOMIC)) == NULL)
 123                         return;         /* No space */
 124         }
 125 
 126         ax25_rt->callsign = *src;
 127         ax25_rt->dev      = dev;
 128         ax25_rt->digipeat = NULL;
 129         ax25_rt->stamp    = xtime;
 130         ax25_rt->n        = 1;
 131         ax25_rt->ip_mode  = ' ';
 132 
 133         if (digi != NULL) {
 134                 if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
 135                         kfree_s(ax25_rt, sizeof(struct ax25_route));
 136                         return;
 137                 }
 138                 *ax25_rt->digipeat = *digi;
 139         }
 140 
 141         if (ax25_rt != oldest) {
 142                 save_flags(flags);
 143                 cli();
 144 
 145                 ax25_rt->next = ax25_route;
 146                 ax25_route    = ax25_rt;
 147 
 148                 restore_flags(flags);
 149         }
 150 }
 151 
 152 void ax25_rt_device_down(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 153 {
 154         struct ax25_route *s, *t, *ax25_rt = ax25_route;
 155         
 156         while (ax25_rt != NULL) {
 157                 s       = ax25_rt;
 158                 ax25_rt = ax25_rt->next;
 159 
 160                 if (s->dev == dev) {
 161                         if (ax25_route == s) {
 162                                 ax25_route = s->next;
 163                                 if (s->digipeat != NULL)
 164                                         kfree_s((void *)s->digipeat, sizeof(ax25_digi));
 165                                 kfree_s((void *)s, (sizeof *s));
 166                         } else {
 167                                 for (t = ax25_route; t != NULL; t = t->next) {
 168                                         if (t->next == s) {
 169                                                 t->next = s->next;
 170                                                 if (s->digipeat != NULL)
 171                                                         kfree_s((void *)s->digipeat, sizeof(ax25_digi));
 172                                                 kfree_s((void *)s, sizeof(*s));
 173                                                 break;
 174                                         }
 175                                 }                               
 176                         }
 177                 }
 178         }
 179 }
 180 
 181 int ax25_rt_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 182 {
 183         unsigned long flags;
 184         struct ax25_route *s, *t, *ax25_rt;
 185         struct ax25_routes_struct route;
 186         struct device *dev;
 187         int i, err;
 188 
 189         switch (cmd) {
 190                 case SIOCADDRT:
 191                         if ((err = verify_area(VERIFY_READ, arg, sizeof(route))) != 0)
 192                                 return err;             
 193                         memcpy_fromfs(&route, arg, sizeof(route));
 194                         if ((dev = ax25rtr_get_dev(&route.port_addr)) == NULL)
 195                                 return -EINVAL;
 196                         if (route.digi_count > AX25_MAX_DIGIS)
 197                                 return -EINVAL;
 198                         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 199                                 if (ax25cmp(&ax25_rt->callsign, &route.dest_addr) == 0 && ax25_rt->dev == dev) {
 200                                         if (ax25_rt->digipeat != NULL) {
 201                                                 kfree_s(ax25_rt->digipeat, sizeof(ax25_digi));
 202                                                 ax25_rt->digipeat = NULL;
 203                                         }
 204                                         if (route.digi_count != 0) {
 205                                                 if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
 206                                                         return -ENOMEM;
 207                                                 ax25_rt->digipeat->lastrepeat = 0;
 208                                                 ax25_rt->digipeat->ndigi      = route.digi_count;
 209                                                 for (i = 0; i < route.digi_count; i++) {
 210                                                         ax25_rt->digipeat->repeated[i] = 0;
 211                                                         ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
 212                                                 }
 213                                         }
 214                                         ax25_rt->stamp.tv_sec = 0;
 215                                         return 0;
 216                                 }
 217                         }
 218                         if ((ax25_rt = (struct ax25_route *)kmalloc(sizeof(struct ax25_route), GFP_ATOMIC)) == NULL)
 219                                 return -ENOMEM;
 220                         ax25_rt->callsign     = route.dest_addr;
 221                         ax25_rt->dev          = dev;
 222                         ax25_rt->digipeat     = NULL;
 223                         ax25_rt->stamp.tv_sec = 0;
 224                         ax25_rt->n            = 0;
 225                         ax25_rt->ip_mode      = ' ';
 226                         if (route.digi_count != 0) {
 227                                 if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
 228                                         kfree_s(ax25_rt, sizeof(struct ax25_route));
 229                                         return -ENOMEM;
 230                                 }
 231                                 ax25_rt->digipeat->lastrepeat = 0;
 232                                 ax25_rt->digipeat->ndigi      = route.digi_count;
 233                                 for (i = 0; i < route.digi_count; i++) {
 234                                         ax25_rt->digipeat->repeated[i] = 0;
 235                                         ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
 236                                 }
 237                         }
 238                         save_flags(flags);
 239                         cli();
 240                         ax25_rt->next = ax25_route;
 241                         ax25_route    = ax25_rt;
 242                         restore_flags(flags);
 243                         break;
 244 
 245                 case SIOCDELRT:
 246                         if ((err = verify_area(VERIFY_READ, arg, sizeof(route))) != 0)
 247                                 return err;
 248                         memcpy_fromfs(&route, arg, sizeof(route));
 249                         if ((dev = ax25rtr_get_dev(&route.port_addr)) == NULL)
 250                                 return -EINVAL;
 251                         ax25_rt = ax25_route;
 252                         while (ax25_rt != NULL) {
 253                                 s       = ax25_rt;
 254                                 ax25_rt = ax25_rt->next;
 255                                 if (s->dev == dev && ax25cmp(&route.dest_addr, &s->callsign) == 0) {
 256                                         if (ax25_route == s) {
 257                                                 ax25_route = s->next;
 258                                                 if (s->digipeat != NULL)
 259                                                         kfree_s((void *)s->digipeat, sizeof(ax25_digi));
 260                                                 kfree_s((void *)s, (sizeof *s));
 261                                         } else {
 262                                                 for (t = ax25_route; t != NULL; t = t->next) {
 263                                                         if (t->next == s) {
 264                                                                 t->next = s->next;
 265                                                                 if (s->digipeat != NULL)
 266                                                                         kfree_s((void *)s->digipeat, sizeof(ax25_digi));
 267                                                                 kfree_s((void *)s, sizeof(*s));
 268                                                                 break;
 269                                                         }
 270                                                 }                               
 271                                         }
 272                                 }
 273                         }
 274                         break;
 275         }
 276 
 277         return 0;
 278 }
 279 
 280 int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282         struct ax25_route *ax25_rt;
 283         int len     = 0;
 284         off_t pos   = 0;
 285         off_t begin = 0;
 286         char *callsign;
 287         int i;
 288   
 289         cli();
 290 
 291         len += sprintf(buffer, "callsign  dev  count time      mode digipeaters\n");
 292 
 293         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 294                 if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
 295                         callsign = "default";
 296                 else
 297                         callsign = ax2asc(&ax25_rt->callsign);
 298                 len += sprintf(buffer + len, "%-9s %-4s %5d %9d",
 299                         callsign,
 300                         ax25_rt->dev ? ax25_rt->dev->name : "???",
 301                         ax25_rt->n,
 302                         ax25_rt->stamp.tv_sec);
 303 
 304                 switch (ax25_rt->ip_mode) {
 305                         case 'V':
 306                         case 'v':
 307                                 len += sprintf(buffer + len, "   vc");
 308                                 break;
 309                         case 'D':
 310                         case 'd':
 311                                 len += sprintf(buffer + len, "   dg");
 312                                 break;
 313                         default:
 314                                 len += sprintf(buffer + len, "    *");
 315                                 break;
 316                 }
 317 
 318                 if (ax25_rt->digipeat != NULL)
 319                         for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
 320                                 len += sprintf(buffer + len, " %s", ax2asc(&ax25_rt->digipeat->calls[i]));
 321                 
 322                 len += sprintf(buffer + len, "\n");
 323                                 
 324                 pos = begin + len;
 325 
 326                 if (pos < offset) {
 327                         len   = 0;
 328                         begin = pos;
 329                 }
 330                 
 331                 if (pos > offset + length)
 332                         break;
 333         }
 334 
 335         sti();
 336 
 337         *start = buffer + (offset - begin);
 338         len   -= (offset - begin);
 339 
 340         if (len > length) len = length;
 341 
 342         return len;
 343 } 
 344 
 345 int ax25_cs_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 346 {
 347         ax25_uid_assoc *pt;
 348         int len     = 0;
 349         off_t pos   = 0;
 350         off_t begin = 0;
 351 
 352         cli();
 353 
 354         len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy);
 355 
 356         for (pt = ax25_uid_list; pt != NULL; pt = pt->next) {
 357                 len += sprintf(buffer + len, "%6d %s\n", pt->uid, ax2asc(&pt->call));
 358 
 359                 pos = begin + len;
 360 
 361                 if (pos < offset) {
 362                         len = 0;
 363                         begin = pos;
 364                 }
 365 
 366                 if (pos > offset + length)
 367                         break;
 368         }
 369 
 370         sti();
 371 
 372         *start = buffer + (offset - begin);
 373         len   -= offset - begin;
 374 
 375         if (len > length) len = length;
 376 
 377         return len;
 378 }
 379 
 380 /*
 381  *      Find which interface to use.
 382  */
 383 int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 384 {
 385         struct ax25_route *ax25_spe_rt = NULL;
 386         struct ax25_route *ax25_def_rt = NULL;
 387         struct ax25_route *ax25_rt;
 388         ax25_address *call;
 389 
 390         /*
 391          *      Bind to the physical interface we heard them on, or the default
 392          *      route if non is found;
 393          */
 394         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 395                 if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
 396                         ax25_spe_rt = ax25_rt;
 397                 if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
 398                         ax25_def_rt = ax25_rt;
 399         }
 400 
 401         if (ax25_spe_rt != NULL)
 402                 ax25_rt = ax25_spe_rt;
 403         else if (ax25_def_rt != NULL)
 404                 ax25_rt = ax25_def_rt;
 405         else
 406                 return -EHOSTUNREACH;
 407 
 408         if ((call = ax25_findbyuid(current->euid)) == NULL) {
 409                 if (ax25_uid_policy && !suser())
 410                         return -EPERM;
 411                 if (ax25->device == NULL)
 412                         return -ENODEV;
 413                 call = (ax25_address *)ax25->device->dev_addr;
 414         }
 415 
 416         ax25->source_addr = *call;
 417 
 418         if (ax25_rt->digipeat != NULL) {
 419                 if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
 420                         return -ENOMEM;
 421                 *ax25->digipeat = *ax25_rt->digipeat;
 422         }
 423 
 424         if (ax25->sk != NULL)
 425                 ax25->sk->zapped = 0;
 426 
 427         return 0;
 428 }
 429 
 430 /*
 431  *      dl1bke 960117: build digipeater path
 432  *      dl1bke 960301: use the default route if it exists
 433  */
 434 void ax25_rt_build_path(ax25_cb *ax25, ax25_address *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 435 {
 436         struct ax25_route *ax25_rt;
 437         
 438         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 439                 if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
 440                         break;
 441                 
 442                 if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
 443                         break;
 444         }
 445         
 446         if (ax25_rt == NULL || ax25_rt->digipeat == NULL)
 447                 return;
 448 
 449         if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
 450                 return;
 451 
 452         ax25->device = ax25_rt->dev;
 453         *ax25->digipeat = *ax25_rt->digipeat;
 454 }
 455 
 456 void ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 457 {
 458         struct ax25_route *ax25_rt;
 459         ax25_address src, dest;
 460         unsigned char *bp;
 461         int len;
 462         
 463         /*
 464          * dl1bke 960301: use the default route if available
 465          *
 466          */
 467         
 468         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 469                 if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
 470                         break;
 471                 if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
 472                         break;
 473         }
 474         
 475         
 476         if (ax25_rt == NULL ||ax25_rt->digipeat == NULL)
 477                 return;
 478 
 479         len = ax25_rt->digipeat->ndigi * AX25_ADDR_LEN;
 480                 
 481         if (skb_headroom(skb) < len) {
 482                 printk("ax25_dg_build_path: not enough headroom for in skb\n");
 483                 return;
 484         }
 485 
 486         memcpy(&dest, skb->data + 1, AX25_ADDR_LEN);
 487         memcpy(&src,  skb->data + 8, AX25_ADDR_LEN);
 488 
 489         bp = skb_push(skb, len);
 490         *bp++ = 0x00;           /* KISS Data */
 491 
 492         build_ax25_addr(bp, &src, &dest, ax25_rt->digipeat, C_COMMAND, MODULUS);
 493 }
 494 
 495 /*
 496  *      Register the mode of an incoming IP frame. It is assumed that an entry
 497  *      already exists in the routing table.
 498  */
 499 void ax25_ip_mode_set(ax25_address *callsign, struct device *dev, char ip_mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 500 {
 501         struct ax25_route *ax25_rt;
 502 
 503         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 504                 if (ax25cmp(&ax25_rt->callsign, callsign) == 0 && ax25_rt->dev == dev) {
 505                         ax25_rt->ip_mode = ip_mode;
 506                         return;
 507                 }
 508         }
 509 }
 510 
 511 /*
 512  *      Return the IP mode of a given callsign/device pair.
 513  */
 514 char ax25_ip_mode_get(ax25_address *callsign, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 515 {
 516         struct ax25_route *ax25_rt;
 517 
 518         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next)
 519                 if (ax25cmp(&ax25_rt->callsign, callsign) == 0 && ax25_rt->dev == dev)
 520                         return ax25_rt->ip_mode;
 521 
 522         return ' ';
 523 }
 524 
 525 static struct ax25_dev *ax25_dev_get_dev(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 526 {
 527         struct ax25_dev *s;
 528 
 529         for (s = ax25_device; s != NULL; s = s->next)
 530                 if (s->dev == dev)
 531                         return s;
 532         
 533         return NULL;
 534 }
 535 
 536 /*
 537  *      Wow, a bit of data hiding. Is this C++ or what ?
 538  */
 539 unsigned short ax25_dev_get_value(struct device *dev, int valueno)
     /* [previous][next][first][last][top][bottom][index][help] */
 540 {
 541         struct ax25_dev *ax25_dev;
 542 
 543         if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL) {
 544                 printk("ax25_dev_get_flag called with invalid device\n");
 545                 return 1;
 546         }
 547 
 548         return ax25_dev->values[valueno];
 549 }
 550 
 551 /*
 552  *      This is called when an interface is brought up. These are
 553  *      reasonable defaults.
 554  */
 555 void ax25_dev_device_up(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 556 {
 557         unsigned long flags;
 558         struct ax25_dev *ax25_dev;
 559         
 560         if ((ax25_dev = (struct ax25_dev *)kmalloc(sizeof(struct ax25_dev), GFP_ATOMIC)) == NULL)
 561                 return;         /* No space */
 562 
 563         ax25_dev->dev        = dev;
 564 
 565         ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE;
 566         ax25_dev->values[AX25_VALUES_AXDEFMODE] = AX25_DEF_AXDEFMODE;
 567         ax25_dev->values[AX25_VALUES_NETROM]    = AX25_DEF_NETROM;
 568         ax25_dev->values[AX25_VALUES_TEXT]      = AX25_DEF_TEXT;
 569         ax25_dev->values[AX25_VALUES_BACKOFF]   = AX25_DEF_BACKOFF;
 570         ax25_dev->values[AX25_VALUES_CONMODE]   = AX25_DEF_CONMODE;
 571         ax25_dev->values[AX25_VALUES_WINDOW]    = AX25_DEF_WINDOW;
 572         ax25_dev->values[AX25_VALUES_EWINDOW]   = AX25_DEF_EWINDOW;
 573         ax25_dev->values[AX25_VALUES_T1]        = AX25_DEF_T1 * PR_SLOWHZ;
 574         ax25_dev->values[AX25_VALUES_T2]        = AX25_DEF_T2 * PR_SLOWHZ;
 575         ax25_dev->values[AX25_VALUES_T3]        = AX25_DEF_T3 * PR_SLOWHZ;
 576         ax25_dev->values[AX25_VALUES_IDLE]      = AX25_DEF_IDLE * PR_SLOWHZ * 60;
 577         ax25_dev->values[AX25_VALUES_N2]        = AX25_DEF_N2;
 578         ax25_dev->values[AX25_VALUES_DIGI]      = AX25_DEF_DIGI;
 579         ax25_dev->values[AX25_VALUES_PACLEN]    = AX25_DEF_PACLEN;
 580 
 581         save_flags(flags);
 582         cli();
 583 
 584         ax25_dev->next = ax25_device;
 585         ax25_device    = ax25_dev;
 586 
 587         restore_flags(flags);
 588 }
 589 
 590 void ax25_dev_device_down(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 591 {
 592         struct ax25_dev *s, *t, *ax25_dev = ax25_device;
 593         
 594         while (ax25_dev != NULL) {
 595                 s        = ax25_dev;
 596                 ax25_dev = ax25_dev->next;
 597 
 598                 if (s->dev == dev) {
 599                         if (ax25_device == s) {
 600                                 ax25_device = s->next;
 601                                 kfree_s((void *)s, (sizeof *s));
 602                         } else {
 603                                 for (t = ax25_device; t != NULL; t = t->next) {
 604                                         if (t->next == s) {
 605                                                 t->next = s->next;
 606                                                 kfree_s((void *)s, sizeof(*s));
 607                                                 break;
 608                                         }
 609                                 }                               
 610                         }
 611                 }
 612         }
 613 }
 614 
 615 int ax25_dev_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 616 {
 617         struct ax25_parms_struct ax25_parms;
 618         struct device *dev;
 619         struct ax25_dev *ax25_dev;
 620         int err;
 621 
 622         switch (cmd) {
 623                 case SIOCAX25SETPARMS:
 624                         if (!suser())
 625                                 return -EPERM;
 626                         if ((err = verify_area(VERIFY_READ, arg, sizeof(ax25_parms))) != 0)
 627                                 return err;
 628                         memcpy_fromfs(&ax25_parms, arg, sizeof(ax25_parms));
 629                         if ((dev = ax25rtr_get_dev(&ax25_parms.port_addr)) == NULL)
 630                                 return -EINVAL;
 631                         if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL)
 632                                 return -EINVAL;
 633                         if (ax25_parms.values[AX25_VALUES_IPDEFMODE] != 'D' &&
 634                             ax25_parms.values[AX25_VALUES_IPDEFMODE] != 'V')
 635                                 return -EINVAL;
 636                         if (ax25_parms.values[AX25_VALUES_AXDEFMODE] != MODULUS &&
 637                             ax25_parms.values[AX25_VALUES_AXDEFMODE] != EMODULUS)
 638                                 return -EINVAL;
 639                         if (ax25_parms.values[AX25_VALUES_NETROM] != 0 &&
 640                             ax25_parms.values[AX25_VALUES_NETROM] != 1)
 641                                 return -EINVAL;
 642                         if (ax25_parms.values[AX25_VALUES_TEXT] != 0 &&
 643                             ax25_parms.values[AX25_VALUES_TEXT] != 1)
 644                                 return -EINVAL;
 645                         if (ax25_parms.values[AX25_VALUES_BACKOFF] != 'E' &&
 646                             ax25_parms.values[AX25_VALUES_BACKOFF] != 'L')
 647                                 return -EINVAL;
 648                         if (ax25_parms.values[AX25_VALUES_CONMODE] != 0 &&
 649                             ax25_parms.values[AX25_VALUES_CONMODE] != 1)
 650                                 return -EINVAL;
 651                         if (ax25_parms.values[AX25_VALUES_WINDOW] < 1 ||
 652                             ax25_parms.values[AX25_VALUES_WINDOW] > 7)
 653                                 return -EINVAL;
 654                         if (ax25_parms.values[AX25_VALUES_EWINDOW] < 1 ||
 655                             ax25_parms.values[AX25_VALUES_EWINDOW] > 63)
 656                                 return -EINVAL;
 657                         if (ax25_parms.values[AX25_VALUES_T1] < 1)
 658                                 return -EINVAL;
 659                         if (ax25_parms.values[AX25_VALUES_T2] < 1)
 660                                 return -EINVAL;
 661                         if (ax25_parms.values[AX25_VALUES_T3] < 1)
 662                                 return -EINVAL;
 663                         if (ax25_parms.values[AX25_VALUES_IDLE] > 100)
 664                                 return -EINVAL;
 665                         if (ax25_parms.values[AX25_VALUES_N2] < 1 ||
 666                             ax25_parms.values[AX25_VALUES_N2] > 31)
 667                                 return -EINVAL;
 668                         if (ax25_parms.values[AX25_VALUES_PACLEN] < 16)
 669                                 return -EINVAL;
 670                         if ((ax25_parms.values[AX25_VALUES_DIGI] &
 671                             ~(AX25_DIGI_INBAND | AX25_DIGI_XBAND)) != 0)
 672                                 return -EINVAL;
 673                         memcpy(ax25_dev->values, ax25_parms.values, AX25_MAX_VALUES * sizeof(short));
 674                         ax25_dev->values[AX25_VALUES_T1] *= PR_SLOWHZ;
 675                         ax25_dev->values[AX25_VALUES_T1] /= 2;
 676                         ax25_dev->values[AX25_VALUES_T2] *= PR_SLOWHZ;
 677                         ax25_dev->values[AX25_VALUES_T3] *= PR_SLOWHZ;
 678                         ax25_dev->values[AX25_VALUES_IDLE] *= PR_SLOWHZ * 60;
 679                         break;
 680 
 681                 case SIOCAX25GETPARMS:
 682                         if ((err = verify_area(VERIFY_WRITE, arg, sizeof(struct ax25_parms_struct))) != 0)
 683                                 return err;
 684                         memcpy_fromfs(&ax25_parms, arg, sizeof(ax25_parms));
 685                         if ((dev = ax25rtr_get_dev(&ax25_parms.port_addr)) == NULL)
 686                                 return -EINVAL;
 687                         if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL)
 688                                 return -EINVAL;
 689                         memcpy(ax25_parms.values, ax25_dev->values, AX25_MAX_VALUES * sizeof(short));
 690                         ax25_parms.values[AX25_VALUES_T1] *= 2;
 691                         ax25_parms.values[AX25_VALUES_T1] /= PR_SLOWHZ;
 692                         ax25_parms.values[AX25_VALUES_T2] /= PR_SLOWHZ;
 693                         ax25_parms.values[AX25_VALUES_T3] /= PR_SLOWHZ;
 694                         ax25_parms.values[AX25_VALUES_IDLE] /= PR_SLOWHZ * 60;
 695                         memcpy_tofs(arg, &ax25_parms, sizeof(ax25_parms));
 696                         break;
 697         }
 698 
 699         return 0;
 700 }
 701 
 702 #ifdef CONFIG_BPQETHER
 703 static struct ax25_bpqdev {
 704         struct ax25_bpqdev *next;
 705         struct device *dev;
 706         ax25_address callsign;
 707 } *ax25_bpqdev = NULL;
 708 
 709 int ax25_bpq_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 710 {
 711         struct ax25_bpqdev *bpqdev;
 712         int len     = 0;
 713         off_t pos   = 0;
 714         off_t begin = 0;
 715   
 716         cli();
 717 
 718         len += sprintf(buffer, "dev  callsign\n");
 719 
 720         for (bpqdev = ax25_bpqdev; bpqdev != NULL; bpqdev = bpqdev->next) {
 721                 len += sprintf(buffer + len, "%-4s %-9s\n",
 722                         bpqdev->dev ? bpqdev->dev->name : "???",
 723                         ax2asc(&bpqdev->callsign));
 724 
 725                 pos = begin + len;
 726 
 727                 if (pos < offset) {
 728                         len   = 0;
 729                         begin = pos;
 730                 }
 731                 
 732                 if (pos > offset + length)
 733                         break;
 734         }
 735 
 736         sti();
 737 
 738         *start = buffer + (offset - begin);
 739         len   -= (offset - begin);
 740 
 741         if (len > length) len = length;
 742 
 743         return len;
 744 } 
 745 
 746 ax25_address *ax25_bpq_get_addr(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 747 {
 748         struct ax25_bpqdev *bpqdev;
 749         
 750         for (bpqdev = ax25_bpqdev; bpqdev != NULL; bpqdev = bpqdev->next)
 751                 if (bpqdev->dev == dev)
 752                         return &bpqdev->callsign;
 753 
 754         return NULL;
 755 }
 756 
 757 int ax25_bpq_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 758 {
 759         unsigned long flags;
 760         struct ax25_bpqdev *bpqdev;
 761         struct ax25_bpqaddr_struct bpqaddr;
 762         struct device *dev;
 763         int err;
 764 
 765         switch (cmd) {
 766                 case SIOCAX25BPQADDR:
 767                         if ((err = verify_area(VERIFY_READ, arg, sizeof(bpqaddr))) != 0)
 768                                 return err;
 769                         memcpy_fromfs(&bpqaddr, arg, sizeof(bpqaddr));
 770                         if ((dev = dev_get(bpqaddr.dev)) == NULL)
 771                                 return -EINVAL;
 772                         if (dev->type != ARPHRD_ETHER)
 773                                 return -EINVAL;
 774                         for (bpqdev = ax25_bpqdev; bpqdev != NULL; bpqdev = bpqdev->next) {
 775                                 if (bpqdev->dev == dev) {
 776                                         bpqdev->callsign = bpqaddr.addr;
 777                                         return 0;
 778                                 }
 779                         }
 780                         if ((bpqdev = (struct ax25_bpqdev *)kmalloc(sizeof(struct ax25_bpqdev), GFP_ATOMIC)) == NULL)
 781                                 return -ENOMEM;
 782                         bpqdev->dev      = dev;
 783                         bpqdev->callsign = bpqaddr.addr;
 784                         save_flags(flags);
 785                         cli();
 786                         bpqdev->next = ax25_bpqdev;
 787                         ax25_bpqdev  = bpqdev;
 788                         restore_flags(flags);
 789                         break;
 790         }
 791 
 792         return 0;
 793 }
 794 
 795 #endif
 796 
 797 #endif

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