root/net/ax25/ax25_subr.c

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

DEFINITIONS

This source file includes following definitions.
  1. ax25_clear_queues
  2. ax25_frames_acked
  3. ax25_requeue_frames
  4. ax25_validate_nr
  5. ax25_decode
  6. ax25_send_control
  7. ax25_return_dm
  8. ax25_calculate_t1
  9. ax25_calculate_rtt
  10. ax25_parse_addr
  11. build_ax25_addr
  12. size_ax25_addr
  13. ax25_digi_invert
  14. ax25_kiss_cmd
  15. ax25_dama_on
  16. ax25_dama_off

   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.3.61 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  *      Most of this code is based on the SDL diagrams published in the 7th
  16  *      ARRL Computer Networking Conference papers. The diagrams have mistakes
  17  *      in them, but are mostly correct. Before you modify the code could you
  18  *      read the SDL diagrams as the code is not obvious and probably very
  19  *      easy to break;
  20  *
  21  *      History
  22  *      AX.25 029       Alan(GW4PTS)    Switched to KA9Q constant names. Removed
  23  *                                      old BSD code.
  24  *      AX.25 030       Jonathan(G4KLX) Added support for extended AX.25.
  25  *                                      Added fragmentation support.
  26  *                      Darryl(G7LED)   Added function ax25_requeue_frames() to split
  27  *                                      it up from ax25_frames_acked().
  28  *      AX.25 031       Joerg(DL1BKE)   DAMA needs KISS Fullduplex ON/OFF.
  29  *                                      Thus we have ax25_kiss_cmd() now... ;-)
  30  *                      Dave Brown(N2RJT)
  31  *                                      Killed a silly bug in the DAMA code.
  32  *                      Joerg(DL1BKE)   found the real bug in ax25.h --- sorry.
  33  */
  34 
  35 #include <linux/config.h>
  36 #ifdef CONFIG_AX25
  37 #include <linux/errno.h>
  38 #include <linux/types.h>
  39 #include <linux/socket.h>
  40 #include <linux/in.h>
  41 #include <linux/kernel.h>
  42 #include <linux/sched.h>
  43 #include <linux/timer.h>
  44 #include <linux/string.h>
  45 #include <linux/sockios.h>
  46 #include <linux/net.h>
  47 #include <net/ax25.h>
  48 #include <linux/inet.h>
  49 #include <linux/netdevice.h>
  50 #include <linux/skbuff.h>
  51 #include <net/sock.h>
  52 #include <asm/segment.h>
  53 #include <asm/system.h>
  54 #include <linux/fcntl.h>
  55 #include <linux/mm.h>
  56 #include <linux/interrupt.h>
  57 
  58 /*
  59  *      This routine purges all the queues of frames.
  60  */
  61 void ax25_clear_queues(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
  62 {
  63         struct sk_buff *skb;
  64 
  65         while ((skb = skb_dequeue(&ax25->write_queue)) != NULL) {
  66                 skb->free = 1;
  67                 kfree_skb(skb, FREE_WRITE);
  68         }
  69 
  70         while ((skb = skb_dequeue(&ax25->ack_queue)) != NULL) {
  71                 skb->free = 1;
  72                 kfree_skb(skb, FREE_WRITE);
  73         }
  74 
  75         while ((skb = skb_dequeue(&ax25->reseq_queue)) != NULL) {
  76                 kfree_skb(skb, FREE_READ);
  77         }
  78 
  79         while ((skb = skb_dequeue(&ax25->frag_queue)) != NULL) {
  80                 kfree_skb(skb, FREE_READ);
  81         }
  82 }
  83 
  84 /*
  85  * This routine purges the input queue of those frames that have been
  86  * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
  87  * SDL diagram.
  88  */
  89 void ax25_frames_acked(ax25_cb *ax25, unsigned short nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91         struct sk_buff *skb;
  92 
  93         /*
  94          * Remove all the ack-ed frames from the ack queue.
  95          */
  96         if (ax25->va != nr) {
  97                 while (skb_peek(&ax25->ack_queue) != NULL && ax25->va != nr) {
  98                         skb = skb_dequeue(&ax25->ack_queue);
  99                         skb->free = 1;
 100                         kfree_skb(skb, FREE_WRITE);
 101                         ax25->va = (ax25->va + 1) % ax25->modulus;
 102                         if (ax25->dama_slave)           /* dl1bke 960120 */
 103                                 ax25->n2count = 0;
 104                 }
 105         }
 106 }
 107 
 108 /* Maybe this should be your ax25_invoke_retransmission(), which appears
 109  * to be used but not do anything.  ax25_invoke_retransmission() used to
 110  * be in AX 0.29, but has now gone in 0.30.
 111  */
 112 void ax25_requeue_frames(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 113 {
 114         struct sk_buff *skb, *skb_prev = NULL;
 115 
 116         /*
 117          * Requeue all the un-ack-ed frames on the output queue to be picked
 118          * up by ax25_kick called from the timer. This arrangement handles the
 119          * possibility of an empty output queue.
 120          */
 121         while ((skb = skb_dequeue(&ax25->ack_queue)) != NULL) {
 122                 if (skb_prev == NULL)
 123                         skb_queue_head(&ax25->write_queue, skb);
 124                 else
 125                         skb_append(skb_prev, skb);
 126                 skb_prev = skb;
 127         }
 128 }
 129 
 130 /*
 131  *      Validate that the value of nr is between va and vs. Return true or
 132  *      false for testing.
 133  */
 134 int ax25_validate_nr(ax25_cb *ax25, unsigned short nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 135 {
 136         unsigned short vc = ax25->va;
 137 
 138         while (vc != ax25->vs) {
 139                 if (nr == vc) return 1;
 140                 vc = (vc + 1) % ax25->modulus;
 141         }
 142         
 143         if (nr == ax25->vs) return 1;
 144 
 145         return 0;
 146 }
 147 
 148 /*
 149  *      This routine is the centralised routine for parsing the control
 150  *      information for the different frame formats.
 151  */
 152 int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf)
     /* [previous][next][first][last][top][bottom][index][help] */
 153 {
 154         unsigned char *frame;
 155         int frametype = ILLEGAL;
 156 
 157         frame = skb->data;
 158         *ns = *nr = *pf = 0;
 159 
 160         if (ax25->modulus == MODULUS) {
 161                 if ((frame[0] & S) == 0) {
 162                         frametype = I;                  /* I frame - carries NR/NS/PF */
 163                         *ns = (frame[0] >> 1) & 0x07;
 164                         *nr = (frame[0] >> 5) & 0x07;
 165                         *pf = frame[0] & PF;
 166                 } else if ((frame[0] & U) == 1) {       /* S frame - take out PF/NR */
 167                         frametype = frame[0] & 0x0F;
 168                         *nr = (frame[0] >> 5) & 0x07;
 169                         *pf = frame[0] & PF;
 170                 } else if ((frame[0] & U) == 3) {       /* U frame - take out PF */
 171                         frametype = frame[0] & ~PF;
 172                         *pf = frame[0] & PF;
 173                 }
 174                 skb_pull(skb, 1);
 175         } else {
 176                 if ((frame[0] & S) == 0) {
 177                         frametype = I;                  /* I frame - carries NR/NS/PF */
 178                         *ns = (frame[0] >> 1) & 0x7F;
 179                         *nr = (frame[1] >> 1) & 0x7F;
 180                         *pf = frame[1] & EPF;
 181                         skb_pull(skb, 2);
 182                 } else if ((frame[0] & U) == 1) {       /* S frame - take out PF/NR */
 183                         frametype = frame[0] & 0x0F;
 184                         *nr = (frame[1] >> 1) & 0x7F;
 185                         *pf = frame[1] & EPF;
 186                         skb_pull(skb, 2);
 187                 } else if ((frame[0] & U) == 3) {       /* U frame - take out PF */
 188                         frametype = frame[0] & ~PF;
 189                         *pf = frame[0] & PF;
 190                         skb_pull(skb, 1);
 191                 }
 192         }
 193 
 194         return frametype;
 195 }
 196 
 197 /* 
 198  *      This routine is called when the HDLC layer internally  generates a
 199  *      command or  response  for  the remote machine ( eg. RR, UA etc. ). 
 200  *      Only supervisory or unnumbered frames are processed.
 201  */
 202 void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204         struct sk_buff *skb;
 205         unsigned char  *dptr;
 206         struct device *dev;
 207         
 208         if ((dev = ax25->device) == NULL)
 209                 return; /* Route died */
 210 
 211         if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat) + 2, GFP_ATOMIC)) == NULL)
 212                 return;
 213 
 214         skb_reserve(skb, AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat));
 215 
 216         if (ax25->sk != NULL) {
 217                 skb->sk = ax25->sk;
 218                 atomic_add(skb->truesize, &ax25->sk->wmem_alloc);
 219         }
 220 
 221         /* Assume a response - address structure for DTE */
 222         if (ax25->modulus == MODULUS) {
 223                 dptr = skb_put(skb, 1);
 224                 *dptr = frametype;
 225                 *dptr |= (poll_bit) ? PF : 0;
 226                 if ((frametype & U) == S)               /* S frames carry NR */
 227                         *dptr |= (ax25->vr << 5);
 228         } else {
 229                 if ((frametype & U) == U) {
 230                         dptr = skb_put(skb, 1);
 231                         *dptr = frametype;
 232                         *dptr |= (poll_bit) ? PF : 0;
 233                 } else {
 234                         dptr = skb_put(skb, 2);
 235                         dptr[0] = frametype;
 236                         dptr[1] = (ax25->vr << 1);
 237                         dptr[1] |= (poll_bit) ? EPF : 0;
 238                 }
 239         }
 240 
 241         skb->free = 1;
 242 
 243         ax25_transmit_buffer(ax25, skb, type);
 244 }
 245 
 246 /*
 247  *      Send a 'DM' to an unknown connection attempt, or an invalid caller.
 248  *
 249  *      Note: src here is the sender, thus its the target of the DM
 250  */
 251 void ax25_return_dm(struct device *dev, ax25_address *src, ax25_address *dest, ax25_digi *digi)
     /* [previous][next][first][last][top][bottom][index][help] */
 252 {
 253         struct sk_buff *skb;
 254         char *dptr;
 255         ax25_digi retdigi;
 256 
 257         if (dev == NULL)
 258                 return;
 259 
 260         if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + size_ax25_addr(digi) + 1, GFP_ATOMIC)) == NULL)
 261                 return; /* Next SABM will get DM'd */
 262 
 263         skb_reserve(skb, AX25_BPQ_HEADER_LEN + size_ax25_addr(digi));
 264 
 265         ax25_digi_invert(digi, &retdigi);
 266 
 267         dptr = skb_put(skb, 1);
 268         skb->sk = NULL;
 269 
 270         *dptr = DM | PF;
 271 
 272         /*
 273          *      Do the address ourselves
 274          */
 275 
 276         dptr  = skb_push(skb, size_ax25_addr(digi));
 277         dptr += build_ax25_addr(dptr, dest, src, &retdigi, C_RESPONSE, MODULUS);
 278 
 279         skb->arp  = 1;
 280         skb->free = 1;
 281 
 282         ax25_queue_xmit(skb, dev, SOPRI_NORMAL);
 283 }
 284 
 285 /*
 286  *      Exponential backoff for AX.25
 287  */
 288 unsigned short ax25_calculate_t1(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 289 {
 290         int n, t = 2;
 291 
 292         if (ax25->backoff) {
 293                 for (n = 0; n < ax25->n2count; n++)
 294                         t *= 2;
 295 
 296                 if (t > 8) t = 8;
 297         }
 298 
 299         return t * ax25->rtt;
 300 }
 301 
 302 /*
 303  *      Calculate the Round Trip Time
 304  */
 305 void ax25_calculate_rtt(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 306 {
 307         if (ax25->t1timer > 0 && ax25->n2count == 0)
 308                 ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25->t1timer) / 10;
 309 
 310 #ifdef  AX25_T1CLAMPLO
 311         /* Don't go below one tenth of a second */
 312         if (ax25->rtt < (AX25_T1CLAMPLO))
 313                 ax25->rtt = (AX25_T1CLAMPLO);
 314 #else   /* Failsafe - some people might have sub 1/10th RTTs :-) **/
 315         if (ax25->rtt == 0)
 316                 ax25->rtt = PR_SLOWHZ;
 317 #endif
 318 #ifdef  AX25_T1CLAMPHI
 319         /* OR above clamped seconds **/
 320         if (ax25->rtt > (AX25_T1CLAMPHI))
 321                 ax25->rtt = (AX25_T1CLAMPHI);
 322 #endif
 323 }
 324 
 325 /*
 326  *      Digipeated address processing
 327  */
 328  
 329 
 330 /*
 331  *      Given an AX.25 address pull of to, from, digi list, command/response and the start of data
 332  *
 333  */
 334 unsigned char *ax25_parse_addr(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, int *dama)
     /* [previous][next][first][last][top][bottom][index][help] */
 335 {
 336         int d = 0;
 337         
 338         if (len < 14) return NULL;
 339                 
 340         if (flags != NULL) {
 341                 *flags = 0;
 342         
 343                 if (buf[6] & LAPB_C) {
 344                         *flags = C_COMMAND;
 345                 }
 346                 if (buf[13] & LAPB_C) {
 347                         *flags = C_RESPONSE;
 348                 }
 349         }
 350                 
 351         if (dama != NULL) 
 352                 *dama = ~buf[13] & DAMA_FLAG;
 353                 
 354         /* Copy to, from */
 355         if (dest != NULL) 
 356                 memcpy(dest, buf + 0, AX25_ADDR_LEN);
 357         if (src != NULL)  
 358                 memcpy(src,  buf + 7, AX25_ADDR_LEN);
 359         buf += 2 * AX25_ADDR_LEN;
 360         len -= 2 * AX25_ADDR_LEN;
 361         digi->lastrepeat = -1;
 362         digi->ndigi      = 0;
 363         
 364         while (!(buf[-1] & LAPB_E)) {
 365                 if (d >= AX25_MAX_DIGIS)  return NULL;  /* Max of 6 digis */
 366                 if (len < 7) return NULL;       /* Short packet */
 367 
 368                 if (digi != NULL) {
 369                         memcpy(&digi->calls[d], buf, AX25_ADDR_LEN);
 370                         digi->ndigi = d + 1;
 371                         if (buf[6] & AX25_REPEATED) {
 372                                 digi->repeated[d] = 1;
 373                                 digi->lastrepeat  = d;
 374                         } else {
 375                                 digi->repeated[d] = 0;
 376                         }
 377                 }
 378 
 379                 buf += AX25_ADDR_LEN;
 380                 len -= AX25_ADDR_LEN;
 381                 d++;
 382         }
 383 
 384         return buf;
 385 }
 386 
 387 /*
 388  *      Assemble an AX.25 header from the bits
 389  */
 390 int build_ax25_addr(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag, int modulus)
     /* [previous][next][first][last][top][bottom][index][help] */
 391 {
 392         int len = 0;
 393         int ct  = 0;
 394 
 395         memcpy(buf, dest, AX25_ADDR_LEN);
 396         buf[6] &= ~(LAPB_E | LAPB_C);
 397         buf[6] |= SSSID_SPARE;
 398 
 399         if (flag == C_COMMAND) buf[6] |= LAPB_C;
 400 
 401         buf += AX25_ADDR_LEN;
 402         len += AX25_ADDR_LEN;
 403 
 404         memcpy(buf, src, AX25_ADDR_LEN);
 405         buf[6] &= ~(LAPB_E | LAPB_C);
 406         buf[6] &= ~SSSID_SPARE;
 407 
 408         if (modulus == MODULUS) {
 409                 buf[6] |= SSSID_SPARE;
 410         } else {
 411                 buf[6] |= ESSID_SPARE;
 412         }
 413 
 414         if (flag == C_RESPONSE) buf[6] |= LAPB_C;
 415 
 416         /*
 417          *      Fast path the normal digiless path
 418          */
 419         if (d == NULL || d->ndigi == 0) {
 420                 buf[6] |= LAPB_E;
 421                 return 2 * AX25_ADDR_LEN;
 422         }       
 423         
 424         buf += AX25_ADDR_LEN;
 425         len += AX25_ADDR_LEN;
 426         
 427         while (ct < d->ndigi) {
 428                 memcpy(buf, &d->calls[ct], AX25_ADDR_LEN);
 429                 if (d->repeated[ct])
 430                         buf[6] |= AX25_REPEATED;
 431                 else
 432                         buf[6] &= ~AX25_REPEATED;
 433                 buf[6] &= ~LAPB_E;
 434                 buf[6] |= SSSID_SPARE;
 435 
 436                 buf += AX25_ADDR_LEN;
 437                 len += AX25_ADDR_LEN;
 438                 ct++;
 439         }
 440 
 441         buf[-1] |= LAPB_E;
 442         
 443         return len;
 444 }
 445 
 446 int size_ax25_addr(ax25_digi *dp)
     /* [previous][next][first][last][top][bottom][index][help] */
 447 {
 448         if (dp == NULL)
 449                 return 2 * AX25_ADDR_LEN;
 450 
 451         return AX25_ADDR_LEN * (2 + dp->ndigi);
 452 }
 453         
 454 /* 
 455  *      Reverse Digipeat List. May not pass both parameters as same struct
 456  */     
 457 void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
     /* [previous][next][first][last][top][bottom][index][help] */
 458 {
 459         int ct = 0;
 460         
 461         /* Invert the digipeaters */
 462         
 463         while (ct < in->ndigi) {
 464                 out->calls[ct]    = in->calls[in->ndigi - ct - 1];
 465                 out->repeated[ct] = 0;
 466                 ct++;
 467         }
 468         
 469         /* Copy ndigis */
 470         out->ndigi = in->ndigi;
 471 
 472         /* Finish off */
 473         out->lastrepeat = 0;
 474 }
 475 
 476 /*
 477  *      :::FIXME:::
 478  *      This is ****NOT**** the right approach. Not all drivers do kiss. We
 479  *      need a driver level request to switch duplex mode, that does either
 480  *      SCC changing, PI config or KISS as required.
 481  *
 482  *      Not to mention this request isnt currently reliable.
 483  */
 484  
 485 void ax25_kiss_cmd(ax25_cb *ax25, unsigned char cmd, unsigned char param)
     /* [previous][next][first][last][top][bottom][index][help] */
 486 {
 487         struct sk_buff *skb;
 488         unsigned char *p;
 489 
 490         if (ax25->device == NULL)
 491                 return;
 492 
 493         if ((skb = alloc_skb(2, GFP_ATOMIC)) == NULL)
 494                 return;
 495 
 496         skb->free = 1;
 497         skb->arp = 1;
 498 
 499         if (ax25->sk != NULL) {
 500                 skb->sk = ax25->sk;
 501                 atomic_add(skb->truesize, &ax25->sk->wmem_alloc);
 502         }
 503 
 504         skb->protocol = htons(ETH_P_AX25);
 505 
 506         p = skb_put(skb, 2);
 507 
 508         *p++=cmd;
 509         *p  =param;
 510 
 511         dev_queue_xmit(skb, ax25->device, SOPRI_NORMAL);
 512 }
 513 
 514 void ax25_dama_on(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 515 {
 516         if (ax25_dev_is_dama_slave(ax25->device) == 0) {
 517                 if (ax25->sk != NULL && ax25->sk->debug)
 518                         printk("ax25_dama_on: DAMA on\n");
 519                 ax25_kiss_cmd(ax25, 5, 1);
 520         }
 521 }
 522 
 523 void ax25_dama_off(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 524 {
 525         if (ax25->dama_slave == 0)
 526                 return;
 527 
 528         ax25->dama_slave = 0;
 529         if (ax25_dev_is_dama_slave(ax25->device) == 0) {
 530                 if (ax25->sk != NULL && ax25->sk->debug)
 531                         printk("ax25_dama_off: DAMA off\n");
 532                 ax25_kiss_cmd(ax25, 5, 0);
 533         }
 534 }
 535 
 536 #endif

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