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_ip_mode_set
  8. ax25_ip_mode_get
  9. ax25_dev_get_dev
  10. ax25_dev_get_value
  11. ax25_dev_device_up
  12. ax25_dev_device_down
  13. ax25_dev_ioctl

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

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