root/net/ax25/ax25_subr.c

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

DEFINITIONS

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

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