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

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