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  */
  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                 if (oldest->digipeat != NULL)
 105                         kfree_s(oldest->digipeat, sizeof(ax25_digi));
 106                 ax25_rt = oldest;
 107         } else {
 108                 if ((ax25_rt = (struct ax25_route *)kmalloc(sizeof(struct ax25_route), GFP_ATOMIC)) == NULL)
 109                         return;         /* No space */
 110         }
 111 
 112         ax25_rt->callsign = *src;
 113         ax25_rt->dev      = dev;
 114         ax25_rt->digipeat = NULL;
 115         ax25_rt->stamp    = xtime;
 116         ax25_rt->n        = 1;
 117         ax25_rt->ip_mode  = ' ';
 118 
 119         if (digi != NULL) {
 120                 if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
 121                         kfree_s(ax25_rt, sizeof(struct ax25_route));
 122                         return;
 123                 }
 124                 *ax25_rt->digipeat = *digi;
 125         }
 126 
 127         if (ax25_rt != oldest) {
 128                 save_flags(flags);
 129                 cli();
 130 
 131                 ax25_rt->next = ax25_route;
 132                 ax25_route    = ax25_rt;
 133 
 134                 restore_flags(flags);
 135         }
 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         char *callsign;
 273         int i;
 274   
 275         cli();
 276 
 277         len += sprintf(buffer, "callsign  dev  count time      mode digipeaters\n");
 278 
 279         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 280                 if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
 281                         callsign = "default";
 282                 else
 283                         callsign = ax2asc(&ax25_rt->callsign);
 284                 len += sprintf(buffer + len, "%-9s %-4s %5d %9d",
 285                         callsign,
 286                         ax25_rt->dev ? ax25_rt->dev->name : "???",
 287                         ax25_rt->n,
 288                         ax25_rt->stamp.tv_sec);
 289 
 290                 switch (ax25_rt->ip_mode) {
 291                         case 'V':
 292                         case 'v':
 293                                 len += sprintf(buffer + len, "   vc");
 294                                 break;
 295                         case 'D':
 296                         case 'd':
 297                                 len += sprintf(buffer + len, "   dg");
 298                                 break;
 299                         default:
 300                                 len += sprintf(buffer + len, "    *");
 301                                 break;
 302                 }
 303 
 304                 if (ax25_rt->digipeat != NULL)
 305                         for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
 306                                 len += sprintf(buffer + len, " %s", ax2asc(&ax25_rt->digipeat->calls[i]));
 307                 
 308                 len += sprintf(buffer + len, "\n");
 309                                 
 310                 pos = begin + len;
 311 
 312                 if (pos < offset) {
 313                         len   = 0;
 314                         begin = pos;
 315                 }
 316                 
 317                 if (pos > offset + length)
 318                         break;
 319         }
 320 
 321         sti();
 322 
 323         *start = buffer + (offset - begin);
 324         len   -= (offset - begin);
 325 
 326         if (len > length) len = length;
 327 
 328         return len;
 329 } 
 330 
 331 int ax25_cs_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 332 {
 333         ax25_uid_assoc *pt;
 334         int len     = 0;
 335         off_t pos   = 0;
 336         off_t begin = 0;
 337 
 338         cli();
 339 
 340         len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy);
 341 
 342         for (pt = ax25_uid_list; pt != NULL; pt = pt->next) {
 343                 len += sprintf(buffer + len, "%6d %s\n", pt->uid, ax2asc(&pt->call));
 344 
 345                 pos = begin + len;
 346 
 347                 if (pos < offset) {
 348                         len = 0;
 349                         begin = pos;
 350                 }
 351 
 352                 if (pos > offset + length)
 353                         break;
 354         }
 355 
 356         sti();
 357 
 358         *start = buffer + (offset - begin);
 359         len   -= offset - begin;
 360 
 361         if (len > length) len = length;
 362 
 363         return len;
 364 }
 365 
 366 /*
 367  *      Find which interface to use.
 368  */
 369 int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 370 {
 371         struct ax25_route *ax25_spe_rt = NULL;
 372         struct ax25_route *ax25_def_rt = NULL;
 373         struct ax25_route *ax25_rt;
 374         ax25_address *call;
 375 
 376         /*
 377          *      Bind to the physical interface we heard them on, or the default
 378          *      route if non is found;
 379          */
 380         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 381                 if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
 382                         ax25_spe_rt = ax25_rt;
 383                 if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
 384                         ax25_def_rt = ax25_rt;
 385         }
 386 
 387         if (ax25_spe_rt != NULL)
 388                 ax25_rt = ax25_spe_rt;
 389         else if (ax25_def_rt != NULL)
 390                 ax25_rt = ax25_def_rt;
 391         else
 392                 return -EHOSTUNREACH;
 393 
 394         if ((call = ax25_findbyuid(current->euid)) == NULL) {
 395                 if (ax25_uid_policy && !suser())
 396                         return -EPERM;
 397                 call = (ax25_address *)ax25->device->dev_addr;
 398         }
 399 
 400         ax25->source_addr = *call;
 401 
 402         if (ax25_rt->digipeat != NULL) {
 403                 if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
 404                         return -ENOMEM;
 405                 *ax25->digipeat = *ax25_rt->digipeat;
 406         }
 407 
 408         if (ax25->sk != NULL)
 409                 ax25->sk->zapped = 0;
 410 
 411         return 0;
 412 }
 413 
 414 /*
 415  *      dl1bke 960117: build digipeater path
 416  */
 417 void ax25_rt_build_path(ax25_cb *ax25, ax25_address *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 418 {
 419         struct ax25_route *ax25_rt;
 420 
 421         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 422                 if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->digipeat != NULL) {
 423                         if (ax25_rt->dev == NULL)
 424                                 continue;
 425                         
 426                         if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
 427                                 return;
 428 
 429                         ax25->device = ax25_rt->dev;
 430                         *ax25->digipeat = *ax25_rt->digipeat;
 431 
 432                         return;
 433                 }
 434         }
 435 
 436         ax25->digipeat = NULL;
 437 }
 438 
 439 void ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 440 {
 441         struct ax25_route *ax25_rt;
 442         ax25_address src, dest;
 443         unsigned char *bp;
 444         int len;
 445 
 446         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 447                 if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev) {
 448                         if (ax25_rt->digipeat == NULL)
 449                                 return;
 450 
 451                         len = ax25_rt->digipeat->ndigi * AX25_ADDR_LEN;
 452                         
 453                         if (skb_headroom(skb) < len) {
 454                                 printk("ax25_dg_build_path: not enough headroom for in skb\n");
 455                                 return;
 456                         }
 457 
 458                         memcpy(&dest, skb->data + 1, AX25_ADDR_LEN);
 459                         memcpy(&src,  skb->data + 8, AX25_ADDR_LEN);
 460 
 461                         bp = skb_push(skb, len);
 462 
 463                         *bp++ = 0x00;           /* KISS Data */
 464 
 465                         build_ax25_addr(bp, &src, &dest, ax25_rt->digipeat, C_COMMAND, MODULUS);
 466 
 467                         return;
 468                 }
 469         }
 470 }
 471 
 472 /*
 473  *      Register the mode of an incoming IP frame. It is assumed that an entry
 474  *      already exists in the routing table.
 475  */
 476 void ax25_ip_mode_set(ax25_address *callsign, struct device *dev, char ip_mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 477 {
 478         struct ax25_route *ax25_rt;
 479 
 480         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 481                 if (ax25cmp(&ax25_rt->callsign, callsign) == 0 && ax25_rt->dev == dev) {
 482                         ax25_rt->ip_mode = ip_mode;
 483                         return;
 484                 }
 485         }
 486 }
 487 
 488 /*
 489  *      Return the IP mode of a given callsign/device pair.
 490  */
 491 char ax25_ip_mode_get(ax25_address *callsign, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 492 {
 493         struct ax25_route *ax25_rt;
 494 
 495         for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next)
 496                 if (ax25cmp(&ax25_rt->callsign, callsign) == 0 && ax25_rt->dev == dev)
 497                         return ax25_rt->ip_mode;
 498 
 499         return ' ';
 500 }
 501 
 502 static struct ax25_dev *ax25_dev_get_dev(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 503 {
 504         struct ax25_dev *s;
 505 
 506         for (s = ax25_device; s != NULL; s = s->next)
 507                 if (s->dev == dev)
 508                         return s;
 509         
 510         return NULL;
 511 }
 512 
 513 /*
 514  *      Wow, a bit of data hiding. Is this C++ or what ?
 515  */
 516 unsigned short ax25_dev_get_value(struct device *dev, int valueno)
     /* [previous][next][first][last][top][bottom][index][help] */
 517 {
 518         struct ax25_dev *ax25_dev;
 519 
 520         if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL) {
 521                 printk("ax25_dev_get_flag called with invalid device\n");
 522                 return 1;
 523         }
 524 
 525         return ax25_dev->values[valueno];
 526 }
 527 
 528 /*
 529  *      This is called when an interface is brought up. These are
 530  *      reasonable defaults.
 531  */
 532 void ax25_dev_device_up(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 533 {
 534         unsigned long flags;
 535         struct ax25_dev *ax25_dev;
 536         
 537         if ((ax25_dev = (struct ax25_dev *)kmalloc(sizeof(struct ax25_dev), GFP_ATOMIC)) == NULL)
 538                 return;         /* No space */
 539 
 540         ax25_dev->dev        = dev;
 541 
 542         ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE;
 543         ax25_dev->values[AX25_VALUES_AXDEFMODE] = AX25_DEF_AXDEFMODE;
 544         ax25_dev->values[AX25_VALUES_NETROM]    = AX25_DEF_NETROM;
 545         ax25_dev->values[AX25_VALUES_TEXT]      = AX25_DEF_TEXT;
 546         ax25_dev->values[AX25_VALUES_BACKOFF]   = AX25_DEF_BACKOFF;
 547         ax25_dev->values[AX25_VALUES_CONMODE]   = AX25_DEF_CONMODE;
 548         ax25_dev->values[AX25_VALUES_WINDOW]    = AX25_DEF_WINDOW;
 549         ax25_dev->values[AX25_VALUES_EWINDOW]   = AX25_DEF_EWINDOW;
 550         ax25_dev->values[AX25_VALUES_T1]        = AX25_DEF_T1 * PR_SLOWHZ;
 551         ax25_dev->values[AX25_VALUES_T2]        = AX25_DEF_T2 * PR_SLOWHZ;
 552         ax25_dev->values[AX25_VALUES_T3]        = AX25_DEF_T3 * PR_SLOWHZ;
 553         ax25_dev->values[AX25_VALUES_N2]        = AX25_DEF_N2;
 554         ax25_dev->values[AX25_VALUES_DIGI]      = AX25_DEF_DIGI;
 555 
 556         save_flags(flags);
 557         cli();
 558 
 559         ax25_dev->next = ax25_device;
 560         ax25_device    = ax25_dev;
 561 
 562         restore_flags(flags);
 563 }
 564 
 565 void ax25_dev_device_down(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 566 {
 567         struct ax25_dev *s, *t, *ax25_dev = ax25_device;
 568         
 569         while (ax25_dev != NULL) {
 570                 s        = ax25_dev;
 571                 ax25_dev = ax25_dev->next;
 572 
 573                 if (s->dev == dev) {
 574                         if (ax25_device == s) {
 575                                 ax25_device = s->next;
 576                                 kfree_s((void *)s, (sizeof *s));
 577                         } else {
 578                                 for (t = ax25_device; t != NULL; t = t->next) {
 579                                         if (t->next == s) {
 580                                                 t->next = s->next;
 581                                                 kfree_s((void *)s, sizeof(*s));
 582                                                 break;
 583                                         }
 584                                 }                               
 585                         }
 586                 }
 587         }
 588 }
 589 
 590 int ax25_dev_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 591 {
 592         struct ax25_parms_struct ax25_parms;
 593         struct device *dev;
 594         struct ax25_dev *ax25_dev;
 595         int err;
 596 
 597         switch (cmd) {
 598                 case SIOCAX25SETPARMS:
 599                         if (!suser())
 600                                 return -EPERM;
 601                         if ((err = verify_area(VERIFY_READ, arg, sizeof(ax25_parms))) != 0)
 602                                 return err;
 603                         memcpy_fromfs(&ax25_parms, arg, sizeof(ax25_parms));
 604                         if ((dev = ax25rtr_get_dev(&ax25_parms.port_addr)) == NULL)
 605                                 return -EINVAL;
 606                         if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL)
 607                                 return -EINVAL;
 608                         if (ax25_parms.values[AX25_VALUES_IPDEFMODE] != 'D' &&
 609                             ax25_parms.values[AX25_VALUES_IPDEFMODE] != 'V')
 610                                 return -EINVAL;
 611                         if (ax25_parms.values[AX25_VALUES_AXDEFMODE] != MODULUS &&
 612                             ax25_parms.values[AX25_VALUES_AXDEFMODE] != EMODULUS)
 613                                 return -EINVAL;
 614                         if (ax25_parms.values[AX25_VALUES_NETROM] != 0 &&
 615                             ax25_parms.values[AX25_VALUES_NETROM] != 1)
 616                                 return -EINVAL;
 617                         if (ax25_parms.values[AX25_VALUES_TEXT] != 0 &&
 618                             ax25_parms.values[AX25_VALUES_TEXT] != 1)
 619                                 return -EINVAL;
 620                         if (ax25_parms.values[AX25_VALUES_BACKOFF] != 'E' &&
 621                             ax25_parms.values[AX25_VALUES_BACKOFF] != 'L')
 622                                 return -EINVAL;
 623                         if (ax25_parms.values[AX25_VALUES_CONMODE] != 0 &&
 624                             ax25_parms.values[AX25_VALUES_CONMODE] != 1)
 625                                 return -EINVAL;
 626                         if (ax25_parms.values[AX25_VALUES_WINDOW] < 1 ||
 627                             ax25_parms.values[AX25_VALUES_WINDOW] > 7)
 628                                 return -EINVAL;
 629                         if (ax25_parms.values[AX25_VALUES_EWINDOW] < 1 ||
 630                             ax25_parms.values[AX25_VALUES_EWINDOW] > 63)
 631                                 return -EINVAL;
 632                         if (ax25_parms.values[AX25_VALUES_T1] < 1)
 633                                 return -EINVAL;
 634                         if (ax25_parms.values[AX25_VALUES_T2] < 1)
 635                                 return -EINVAL;
 636                         if (ax25_parms.values[AX25_VALUES_T3] < 1)
 637                                 return -EINVAL;
 638                         if (ax25_parms.values[AX25_VALUES_N2] < 1 ||
 639                             ax25_parms.values[AX25_VALUES_N2] > 31)
 640                                 return -EINVAL;
 641                         if ((ax25_parms.values[AX25_VALUES_DIGI] &
 642                             ~(AX25_DIGI_INBAND | AX25_DIGI_XBAND)) != 0)
 643                                 return -EINVAL;
 644                         memcpy(ax25_dev->values, ax25_parms.values, AX25_MAX_VALUES * sizeof(short));
 645                         ax25_dev->values[AX25_VALUES_T1] *= PR_SLOWHZ;
 646                         ax25_dev->values[AX25_VALUES_T1] /= 2;
 647                         ax25_dev->values[AX25_VALUES_T2] *= PR_SLOWHZ;
 648                         ax25_dev->values[AX25_VALUES_T3] *= PR_SLOWHZ;
 649                         break;
 650 
 651                 case SIOCAX25GETPARMS:
 652                         if ((err = verify_area(VERIFY_WRITE, arg, sizeof(struct ax25_parms_struct))) != 0)
 653                                 return err;
 654                         memcpy_fromfs(&ax25_parms, arg, sizeof(ax25_parms));
 655                         if ((dev = ax25rtr_get_dev(&ax25_parms.port_addr)) == NULL)
 656                                 return -EINVAL;
 657                         if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL)
 658                                 return -EINVAL;
 659                         memcpy(ax25_parms.values, ax25_dev->values, AX25_MAX_VALUES * sizeof(short));
 660                         ax25_parms.values[AX25_VALUES_T1] *= 2;
 661                         ax25_parms.values[AX25_VALUES_T1] /= PR_SLOWHZ;
 662                         ax25_parms.values[AX25_VALUES_T2] /= PR_SLOWHZ;
 663                         ax25_parms.values[AX25_VALUES_T3] /= PR_SLOWHZ;
 664                         memcpy_tofs(arg, &ax25_parms, sizeof(ax25_parms));
 665                         break;
 666         }
 667 
 668         return 0;
 669 }
 670 
 671 #ifdef CONFIG_BPQETHER
 672 static struct ax25_bpqdev {
 673         struct ax25_bpqdev *next;
 674         struct device *dev;
 675         ax25_address callsign;
 676 } *ax25_bpqdev = NULL;
 677 
 678 int ax25_bpq_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 679 {
 680         struct ax25_bpqdev *bpqdev;
 681         int len     = 0;
 682         off_t pos   = 0;
 683         off_t begin = 0;
 684   
 685         cli();
 686 
 687         len += sprintf(buffer, "dev  callsign\n");
 688 
 689         for (bpqdev = ax25_bpqdev; bpqdev != NULL; bpqdev = bpqdev->next) {
 690                 len += sprintf(buffer + len, "%-4s %-9s\n",
 691                         bpqdev->dev ? bpqdev->dev->name : "???",
 692                         ax2asc(&bpqdev->callsign));
 693 
 694                 pos = begin + len;
 695 
 696                 if (pos < offset) {
 697                         len   = 0;
 698                         begin = pos;
 699                 }
 700                 
 701                 if (pos > offset + length)
 702                         break;
 703         }
 704 
 705         sti();
 706 
 707         *start = buffer + (offset - begin);
 708         len   -= (offset - begin);
 709 
 710         if (len > length) len = length;
 711 
 712         return len;
 713 } 
 714 
 715 ax25_address *ax25_bpq_get_addr(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 716 {
 717         struct ax25_bpqdev *bpqdev;
 718         
 719         for (bpqdev = ax25_bpqdev; bpqdev != NULL; bpqdev = bpqdev->next)
 720                 if (bpqdev->dev == dev)
 721                         return &bpqdev->callsign;
 722 
 723         return NULL;
 724 }
 725 
 726 int ax25_bpq_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 727 {
 728         unsigned long flags;
 729         struct ax25_bpqdev *bpqdev;
 730         struct ax25_bpqaddr_struct bpqaddr;
 731         struct device *dev;
 732         int err;
 733 
 734         switch (cmd) {
 735                 case SIOCAX25BPQADDR:
 736                         if ((err = verify_area(VERIFY_READ, arg, sizeof(bpqaddr))) != 0)
 737                                 return err;
 738                         memcpy_fromfs(&bpqaddr, arg, sizeof(bpqaddr));
 739                         if ((dev = dev_get(bpqaddr.dev)) == NULL)
 740                                 return -EINVAL;
 741                         if (dev->type != ARPHRD_ETHER)
 742                                 return -EINVAL;
 743                         for (bpqdev = ax25_bpqdev; bpqdev != NULL; bpqdev = bpqdev->next) {
 744                                 if (bpqdev->dev == dev) {
 745                                         bpqdev->callsign = bpqaddr.addr;
 746                                         return 0;
 747                                 }
 748                         }
 749                         if ((bpqdev = (struct ax25_bpqdev *)kmalloc(sizeof(struct ax25_bpqdev), GFP_ATOMIC)) == NULL)
 750                                 return -ENOMEM;
 751                         bpqdev->dev      = dev;
 752                         bpqdev->callsign = bpqaddr.addr;
 753                         save_flags(flags);
 754                         cli();
 755                         bpqdev->next = ax25_bpqdev;
 756                         ax25_bpqdev  = bpqdev;
 757                         restore_flags(flags);
 758                         break;
 759         }
 760 
 761         return 0;
 762 }
 763 
 764 #endif
 765 
 766 #endif

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