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

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