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

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