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

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