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

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