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

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

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