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

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