linux/net/ax25/ax25_subr.c
<<
>>
Prefs
   1/*
   2 * This program is free software; you can redistribute it and/or modify
   3 * it under the terms of the GNU General Public License as published by
   4 * the Free Software Foundation; either version 2 of the License, or
   5 * (at your option) any later version.
   6 *
   7 * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
   8 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
   9 * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
  10 * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
  11 */
  12#include <linux/errno.h>
  13#include <linux/types.h>
  14#include <linux/socket.h>
  15#include <linux/in.h>
  16#include <linux/kernel.h>
  17#include <linux/timer.h>
  18#include <linux/string.h>
  19#include <linux/sockios.h>
  20#include <linux/net.h>
  21#include <net/ax25.h>
  22#include <linux/inet.h>
  23#include <linux/netdevice.h>
  24#include <linux/skbuff.h>
  25#include <net/sock.h>
  26#include <net/tcp_states.h>
  27#include <asm/uaccess.h>
  28#include <asm/system.h>
  29#include <linux/fcntl.h>
  30#include <linux/mm.h>
  31#include <linux/interrupt.h>
  32
  33/*
  34 *      This routine purges all the queues of frames.
  35 */
  36void ax25_clear_queues(ax25_cb *ax25)
  37{
  38        skb_queue_purge(&ax25->write_queue);
  39        skb_queue_purge(&ax25->ack_queue);
  40        skb_queue_purge(&ax25->reseq_queue);
  41        skb_queue_purge(&ax25->frag_queue);
  42}
  43
  44/*
  45 * This routine purges the input queue of those frames that have been
  46 * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
  47 * SDL diagram.
  48 */
  49void ax25_frames_acked(ax25_cb *ax25, unsigned short nr)
  50{
  51        struct sk_buff *skb;
  52
  53        /*
  54         * Remove all the ack-ed frames from the ack queue.
  55         */
  56        if (ax25->va != nr) {
  57                while (skb_peek(&ax25->ack_queue) != NULL && ax25->va != nr) {
  58                        skb = skb_dequeue(&ax25->ack_queue);
  59                        kfree_skb(skb);
  60                        ax25->va = (ax25->va + 1) % ax25->modulus;
  61                }
  62        }
  63}
  64
  65void ax25_requeue_frames(ax25_cb *ax25)
  66{
  67        struct sk_buff *skb, *skb_prev = NULL;
  68
  69        /*
  70         * Requeue all the un-ack-ed frames on the output queue to be picked
  71         * up by ax25_kick called from the timer. This arrangement handles the
  72         * possibility of an empty output queue.
  73         */
  74        while ((skb = skb_dequeue(&ax25->ack_queue)) != NULL) {
  75                if (skb_prev == NULL)
  76                        skb_queue_head(&ax25->write_queue, skb);
  77                else
  78                        skb_append(skb_prev, skb, &ax25->write_queue);
  79                skb_prev = skb;
  80        }
  81}
  82
  83/*
  84 *      Validate that the value of nr is between va and vs. Return true or
  85 *      false for testing.
  86 */
  87int ax25_validate_nr(ax25_cb *ax25, unsigned short nr)
  88{
  89        unsigned short vc = ax25->va;
  90
  91        while (vc != ax25->vs) {
  92                if (nr == vc) return 1;
  93                vc = (vc + 1) % ax25->modulus;
  94        }
  95
  96        if (nr == ax25->vs) return 1;
  97
  98        return 0;
  99}
 100
 101/*
 102 *      This routine is the centralised routine for parsing the control
 103 *      information for the different frame formats.
 104 */
 105int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf)
 106{
 107        unsigned char *frame;
 108        int frametype = AX25_ILLEGAL;
 109
 110        frame = skb->data;
 111        *ns = *nr = *pf = 0;
 112
 113        if (ax25->modulus == AX25_MODULUS) {
 114                if ((frame[0] & AX25_S) == 0) {
 115                        frametype = AX25_I;                     /* I frame - carries NR/NS/PF */
 116                        *ns = (frame[0] >> 1) & 0x07;
 117                        *nr = (frame[0] >> 5) & 0x07;
 118                        *pf = frame[0] & AX25_PF;
 119                } else if ((frame[0] & AX25_U) == 1) {  /* S frame - take out PF/NR */
 120                        frametype = frame[0] & 0x0F;
 121                        *nr = (frame[0] >> 5) & 0x07;
 122                        *pf = frame[0] & AX25_PF;
 123                } else if ((frame[0] & AX25_U) == 3) {  /* U frame - take out PF */
 124                        frametype = frame[0] & ~AX25_PF;
 125                        *pf = frame[0] & AX25_PF;
 126                }
 127                skb_pull(skb, 1);
 128        } else {
 129                if ((frame[0] & AX25_S) == 0) {
 130                        frametype = AX25_I;                     /* I frame - carries NR/NS/PF */
 131                        *ns = (frame[0] >> 1) & 0x7F;
 132                        *nr = (frame[1] >> 1) & 0x7F;
 133                        *pf = frame[1] & AX25_EPF;
 134                        skb_pull(skb, 2);
 135                } else if ((frame[0] & AX25_U) == 1) {  /* S frame - take out PF/NR */
 136                        frametype = frame[0] & 0x0F;
 137                        *nr = (frame[1] >> 1) & 0x7F;
 138                        *pf = frame[1] & AX25_EPF;
 139                        skb_pull(skb, 2);
 140                } else if ((frame[0] & AX25_U) == 3) {  /* U frame - take out PF */
 141                        frametype = frame[0] & ~AX25_PF;
 142                        *pf = frame[0] & AX25_PF;
 143                        skb_pull(skb, 1);
 144                }
 145        }
 146
 147        return frametype;
 148}
 149
 150/*
 151 *      This routine is called when the HDLC layer internally  generates a
 152 *      command or  response  for  the remote machine ( eg. RR, UA etc. ).
 153 *      Only supervisory or unnumbered frames are processed.
 154 */
 155void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type)
 156{
 157        struct sk_buff *skb;
 158        unsigned char  *dptr;
 159
 160        if ((skb = alloc_skb(ax25->ax25_dev->dev->hard_header_len + 2, GFP_ATOMIC)) == NULL)
 161                return;
 162
 163        skb_reserve(skb, ax25->ax25_dev->dev->hard_header_len);
 164
 165        skb_reset_network_header(skb);
 166
 167        /* Assume a response - address structure for DTE */
 168        if (ax25->modulus == AX25_MODULUS) {
 169                dptr = skb_put(skb, 1);
 170                *dptr = frametype;
 171                *dptr |= (poll_bit) ? AX25_PF : 0;
 172                if ((frametype & AX25_U) == AX25_S)             /* S frames carry NR */
 173                        *dptr |= (ax25->vr << 5);
 174        } else {
 175                if ((frametype & AX25_U) == AX25_U) {
 176                        dptr = skb_put(skb, 1);
 177                        *dptr = frametype;
 178                        *dptr |= (poll_bit) ? AX25_PF : 0;
 179                } else {
 180                        dptr = skb_put(skb, 2);
 181                        dptr[0] = frametype;
 182                        dptr[1] = (ax25->vr << 1);
 183                        dptr[1] |= (poll_bit) ? AX25_EPF : 0;
 184                }
 185        }
 186
 187        ax25_transmit_buffer(ax25, skb, type);
 188}
 189
 190/*
 191 *      Send a 'DM' to an unknown connection attempt, or an invalid caller.
 192 *
 193 *      Note: src here is the sender, thus it's the target of the DM
 194 */
 195void ax25_return_dm(struct net_device *dev, ax25_address *src, ax25_address *dest, ax25_digi *digi)
 196{
 197        struct sk_buff *skb;
 198        char *dptr;
 199        ax25_digi retdigi;
 200
 201        if (dev == NULL)
 202                return;
 203
 204        if ((skb = alloc_skb(dev->hard_header_len + 1, GFP_ATOMIC)) == NULL)
 205                return; /* Next SABM will get DM'd */
 206
 207        skb_reserve(skb, dev->hard_header_len);
 208        skb_reset_network_header(skb);
 209
 210        ax25_digi_invert(digi, &retdigi);
 211
 212        dptr = skb_put(skb, 1);
 213
 214        *dptr = AX25_DM | AX25_PF;
 215
 216        /*
 217         *      Do the address ourselves
 218         */
 219        dptr  = skb_push(skb, ax25_addr_size(digi));
 220        dptr += ax25_addr_build(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS);
 221
 222        ax25_queue_xmit(skb, dev);
 223}
 224
 225/*
 226 *      Exponential backoff for AX.25
 227 */
 228void ax25_calculate_t1(ax25_cb *ax25)
 229{
 230        int n, t = 2;
 231
 232        switch (ax25->backoff) {
 233        case 0:
 234                break;
 235
 236        case 1:
 237                t += 2 * ax25->n2count;
 238                break;
 239
 240        case 2:
 241                for (n = 0; n < ax25->n2count; n++)
 242                        t *= 2;
 243                if (t > 8) t = 8;
 244                break;
 245        }
 246
 247        ax25->t1 = t * ax25->rtt;
 248}
 249
 250/*
 251 *      Calculate the Round Trip Time
 252 */
 253void ax25_calculate_rtt(ax25_cb *ax25)
 254{
 255        if (ax25->backoff == 0)
 256                return;
 257
 258        if (ax25_t1timer_running(ax25) && ax25->n2count == 0)
 259                ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25_display_timer(&ax25->t1timer)) / 10;
 260
 261        if (ax25->rtt < AX25_T1CLAMPLO)
 262                ax25->rtt = AX25_T1CLAMPLO;
 263
 264        if (ax25->rtt > AX25_T1CLAMPHI)
 265                ax25->rtt = AX25_T1CLAMPHI;
 266}
 267
 268void ax25_disconnect(ax25_cb *ax25, int reason)
 269{
 270        ax25_clear_queues(ax25);
 271
 272        ax25_stop_t1timer(ax25);
 273        ax25_stop_t2timer(ax25);
 274        ax25_stop_t3timer(ax25);
 275        ax25_stop_idletimer(ax25);
 276
 277        ax25->state = AX25_STATE_0;
 278
 279        ax25_link_failed(ax25, reason);
 280
 281        if (ax25->sk != NULL) {
 282                local_bh_disable();
 283                bh_lock_sock(ax25->sk);
 284                ax25->sk->sk_state     = TCP_CLOSE;
 285                ax25->sk->sk_err       = reason;
 286                ax25->sk->sk_shutdown |= SEND_SHUTDOWN;
 287                if (!sock_flag(ax25->sk, SOCK_DEAD)) {
 288                        ax25->sk->sk_state_change(ax25->sk);
 289                        sock_set_flag(ax25->sk, SOCK_DEAD);
 290                }
 291                bh_unlock_sock(ax25->sk);
 292                local_bh_enable();
 293        }
 294}
 295