linux/net/x25/x25_subr.c
<<
>>
Prefs
   1/*
   2 *      X.25 Packet Layer release 002
   3 *
   4 *      This is ALPHA test software. This code may break your machine,
   5 *      randomly fail to work with new releases, misbehave and/or generally
   6 *      screw up. It might even work.
   7 *
   8 *      This code REQUIRES 2.1.15 or higher
   9 *
  10 *      This module:
  11 *              This module is free software; you can redistribute it and/or
  12 *              modify it under the terms of the GNU General Public License
  13 *              as published by the Free Software Foundation; either version
  14 *              2 of the License, or (at your option) any later version.
  15 *
  16 *      History
  17 *      X.25 001        Jonathan Naylor   Started coding.
  18 *      X.25 002        Jonathan Naylor   Centralised disconnection processing.
  19 *      mar/20/00       Daniela Squassoni Disabling/enabling of facilities
  20 *                                        negotiation.
  21 *      jun/24/01       Arnaldo C. Melo   use skb_queue_purge, cleanups
  22 *      apr/04/15       Shaun Pereira           Fast select with no
  23 *                                              restriction on response.
  24 */
  25
  26#include <linux/slab.h>
  27#include <linux/kernel.h>
  28#include <linux/string.h>
  29#include <linux/skbuff.h>
  30#include <net/sock.h>
  31#include <net/tcp_states.h>
  32#include <net/x25.h>
  33
  34/*
  35 *      This routine purges all of the queues of frames.
  36 */
  37void x25_clear_queues(struct sock *sk)
  38{
  39        struct x25_sock *x25 = x25_sk(sk);
  40
  41        skb_queue_purge(&sk->sk_write_queue);
  42        skb_queue_purge(&x25->ack_queue);
  43        skb_queue_purge(&x25->interrupt_in_queue);
  44        skb_queue_purge(&x25->interrupt_out_queue);
  45        skb_queue_purge(&x25->fragment_queue);
  46}
  47
  48
  49/*
  50 * This routine purges the input queue of those frames that have been
  51 * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
  52 * SDL diagram.
  53*/
  54void x25_frames_acked(struct sock *sk, unsigned short nr)
  55{
  56        struct sk_buff *skb;
  57        struct x25_sock *x25 = x25_sk(sk);
  58        int modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS;
  59
  60        /*
  61         * Remove all the ack-ed frames from the ack queue.
  62         */
  63        if (x25->va != nr)
  64                while (skb_peek(&x25->ack_queue) && x25->va != nr) {
  65                        skb = skb_dequeue(&x25->ack_queue);
  66                        kfree_skb(skb);
  67                        x25->va = (x25->va + 1) % modulus;
  68                }
  69}
  70
  71void x25_requeue_frames(struct sock *sk)
  72{
  73        struct sk_buff *skb, *skb_prev = NULL;
  74
  75        /*
  76         * Requeue all the un-ack-ed frames on the output queue to be picked
  77         * up by x25_kick. This arrangement handles the possibility of an empty
  78         * output queue.
  79         */
  80        while ((skb = skb_dequeue(&x25_sk(sk)->ack_queue)) != NULL) {
  81                if (!skb_prev)
  82                        skb_queue_head(&sk->sk_write_queue, skb);
  83                else
  84                        skb_append(skb_prev, skb, &sk->sk_write_queue);
  85                skb_prev = skb;
  86        }
  87}
  88
  89/*
  90 *      Validate that the value of nr is between va and vs. Return true or
  91 *      false for testing.
  92 */
  93int x25_validate_nr(struct sock *sk, unsigned short nr)
  94{
  95        struct x25_sock *x25 = x25_sk(sk);
  96        unsigned short vc = x25->va;
  97        int modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS;
  98
  99        while (vc != x25->vs) {
 100                if (nr == vc)
 101                        return 1;
 102                vc = (vc + 1) % modulus;
 103        }
 104
 105        return nr == x25->vs ? 1 : 0;
 106}
 107
 108/*
 109 *  This routine is called when the packet layer internally generates a
 110 *  control frame.
 111 */
 112void x25_write_internal(struct sock *sk, int frametype)
 113{
 114        struct x25_sock *x25 = x25_sk(sk);
 115        struct sk_buff *skb;
 116        unsigned char  *dptr;
 117        unsigned char  facilities[X25_MAX_FAC_LEN];
 118        unsigned char  addresses[1 + X25_ADDR_LEN];
 119        unsigned char  lci1, lci2;
 120        /*
 121         *      Default safe frame size.
 122         */
 123        int len = X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
 124
 125        /*
 126         *      Adjust frame size.
 127         */
 128        switch (frametype) {
 129        case X25_CALL_REQUEST:
 130                len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN;
 131                break;
 132        case X25_CALL_ACCEPTED: /* fast sel with no restr on resp */
 133                if (x25->facilities.reverse & 0x80) {
 134                        len += 1 + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN;
 135                } else {
 136                        len += 1 + X25_MAX_FAC_LEN;
 137                }
 138                break;
 139        case X25_CLEAR_REQUEST:
 140        case X25_RESET_REQUEST:
 141                len += 2;
 142                break;
 143        case X25_RR:
 144        case X25_RNR:
 145        case X25_REJ:
 146        case X25_CLEAR_CONFIRMATION:
 147        case X25_INTERRUPT_CONFIRMATION:
 148        case X25_RESET_CONFIRMATION:
 149                break;
 150        default:
 151                printk(KERN_ERR "X.25: invalid frame type %02X\n", frametype);
 152                return;
 153        }
 154
 155        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
 156                return;
 157
 158        /*
 159         *      Space for Ethernet and 802.2 LLC headers.
 160         */
 161        skb_reserve(skb, X25_MAX_L2_LEN);
 162
 163        /*
 164         *      Make space for the GFI and LCI, and fill them in.
 165         */
 166        dptr = skb_put(skb, 2);
 167
 168        lci1 = (x25->lci >> 8) & 0x0F;
 169        lci2 = (x25->lci >> 0) & 0xFF;
 170
 171        if (x25->neighbour->extended) {
 172                *dptr++ = lci1 | X25_GFI_EXTSEQ;
 173                *dptr++ = lci2;
 174        } else {
 175                *dptr++ = lci1 | X25_GFI_STDSEQ;
 176                *dptr++ = lci2;
 177        }
 178
 179        /*
 180         *      Now fill in the frame type specific information.
 181         */
 182        switch (frametype) {
 183
 184                case X25_CALL_REQUEST:
 185                        dptr    = skb_put(skb, 1);
 186                        *dptr++ = X25_CALL_REQUEST;
 187                        len     = x25_addr_aton(addresses, &x25->dest_addr,
 188                                                &x25->source_addr);
 189                        dptr    = skb_put(skb, len);
 190                        memcpy(dptr, addresses, len);
 191                        len     = x25_create_facilities(facilities,
 192                                        &x25->facilities,
 193                                        &x25->dte_facilities,
 194                                        x25->neighbour->global_facil_mask);
 195                        dptr    = skb_put(skb, len);
 196                        memcpy(dptr, facilities, len);
 197                        dptr = skb_put(skb, x25->calluserdata.cudlength);
 198                        memcpy(dptr, x25->calluserdata.cuddata,
 199                               x25->calluserdata.cudlength);
 200                        x25->calluserdata.cudlength = 0;
 201                        break;
 202
 203                case X25_CALL_ACCEPTED:
 204                        dptr    = skb_put(skb, 2);
 205                        *dptr++ = X25_CALL_ACCEPTED;
 206                        *dptr++ = 0x00;         /* Address lengths */
 207                        len     = x25_create_facilities(facilities,
 208                                                        &x25->facilities,
 209                                                        &x25->dte_facilities,
 210                                                        x25->vc_facil_mask);
 211                        dptr    = skb_put(skb, len);
 212                        memcpy(dptr, facilities, len);
 213
 214                        /* fast select with no restriction on response
 215                                allows call user data. Userland must
 216                                ensure it is ours and not theirs */
 217                        if(x25->facilities.reverse & 0x80) {
 218                                dptr = skb_put(skb,
 219                                        x25->calluserdata.cudlength);
 220                                memcpy(dptr, x25->calluserdata.cuddata,
 221                                       x25->calluserdata.cudlength);
 222                        }
 223                        x25->calluserdata.cudlength = 0;
 224                        break;
 225
 226                case X25_CLEAR_REQUEST:
 227                        dptr    = skb_put(skb, 3);
 228                        *dptr++ = frametype;
 229                        *dptr++ = x25->causediag.cause;
 230                        *dptr++ = x25->causediag.diagnostic;
 231                        break;
 232
 233                case X25_RESET_REQUEST:
 234                        dptr    = skb_put(skb, 3);
 235                        *dptr++ = frametype;
 236                        *dptr++ = 0x00;         /* XXX */
 237                        *dptr++ = 0x00;         /* XXX */
 238                        break;
 239
 240                case X25_RR:
 241                case X25_RNR:
 242                case X25_REJ:
 243                        if (x25->neighbour->extended) {
 244                                dptr     = skb_put(skb, 2);
 245                                *dptr++  = frametype;
 246                                *dptr++  = (x25->vr << 1) & 0xFE;
 247                        } else {
 248                                dptr     = skb_put(skb, 1);
 249                                *dptr    = frametype;
 250                                *dptr++ |= (x25->vr << 5) & 0xE0;
 251                        }
 252                        break;
 253
 254                case X25_CLEAR_CONFIRMATION:
 255                case X25_INTERRUPT_CONFIRMATION:
 256                case X25_RESET_CONFIRMATION:
 257                        dptr  = skb_put(skb, 1);
 258                        *dptr = frametype;
 259                        break;
 260        }
 261
 262        x25_transmit_link(skb, x25->neighbour);
 263}
 264
 265/*
 266 *      Unpick the contents of the passed X.25 Packet Layer frame.
 267 */
 268int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
 269               int *d, int *m)
 270{
 271        struct x25_sock *x25 = x25_sk(sk);
 272        unsigned char *frame;
 273
 274        if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
 275                return X25_ILLEGAL;
 276        frame = skb->data;
 277
 278        *ns = *nr = *q = *d = *m = 0;
 279
 280        switch (frame[2]) {
 281        case X25_CALL_REQUEST:
 282        case X25_CALL_ACCEPTED:
 283        case X25_CLEAR_REQUEST:
 284        case X25_CLEAR_CONFIRMATION:
 285        case X25_INTERRUPT:
 286        case X25_INTERRUPT_CONFIRMATION:
 287        case X25_RESET_REQUEST:
 288        case X25_RESET_CONFIRMATION:
 289        case X25_RESTART_REQUEST:
 290        case X25_RESTART_CONFIRMATION:
 291        case X25_REGISTRATION_REQUEST:
 292        case X25_REGISTRATION_CONFIRMATION:
 293        case X25_DIAGNOSTIC:
 294                return frame[2];
 295        }
 296
 297        if (x25->neighbour->extended) {
 298                if (frame[2] == X25_RR  ||
 299                    frame[2] == X25_RNR ||
 300                    frame[2] == X25_REJ) {
 301                        if (!pskb_may_pull(skb, X25_EXT_MIN_LEN))
 302                                return X25_ILLEGAL;
 303                        frame = skb->data;
 304
 305                        *nr = (frame[3] >> 1) & 0x7F;
 306                        return frame[2];
 307                }
 308        } else {
 309                if ((frame[2] & 0x1F) == X25_RR  ||
 310                    (frame[2] & 0x1F) == X25_RNR ||
 311                    (frame[2] & 0x1F) == X25_REJ) {
 312                        *nr = (frame[2] >> 5) & 0x07;
 313                        return frame[2] & 0x1F;
 314                }
 315        }
 316
 317        if (x25->neighbour->extended) {
 318                if ((frame[2] & 0x01) == X25_DATA) {
 319                        if (!pskb_may_pull(skb, X25_EXT_MIN_LEN))
 320                                return X25_ILLEGAL;
 321                        frame = skb->data;
 322
 323                        *q  = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
 324                        *d  = (frame[0] & X25_D_BIT) == X25_D_BIT;
 325                        *m  = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT;
 326                        *nr = (frame[3] >> 1) & 0x7F;
 327                        *ns = (frame[2] >> 1) & 0x7F;
 328                        return X25_DATA;
 329                }
 330        } else {
 331                if ((frame[2] & 0x01) == X25_DATA) {
 332                        *q  = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
 333                        *d  = (frame[0] & X25_D_BIT) == X25_D_BIT;
 334                        *m  = (frame[2] & X25_STD_M_BIT) == X25_STD_M_BIT;
 335                        *nr = (frame[2] >> 5) & 0x07;
 336                        *ns = (frame[2] >> 1) & 0x07;
 337                        return X25_DATA;
 338                }
 339        }
 340
 341        printk(KERN_DEBUG "X.25: invalid PLP frame %02X %02X %02X\n",
 342               frame[0], frame[1], frame[2]);
 343
 344        return X25_ILLEGAL;
 345}
 346
 347void x25_disconnect(struct sock *sk, int reason, unsigned char cause,
 348                    unsigned char diagnostic)
 349{
 350        struct x25_sock *x25 = x25_sk(sk);
 351
 352        x25_clear_queues(sk);
 353        x25_stop_timer(sk);
 354
 355        x25->lci   = 0;
 356        x25->state = X25_STATE_0;
 357
 358        x25->causediag.cause      = cause;
 359        x25->causediag.diagnostic = diagnostic;
 360
 361        sk->sk_state     = TCP_CLOSE;
 362        sk->sk_err       = reason;
 363        sk->sk_shutdown |= SEND_SHUTDOWN;
 364
 365        if (!sock_flag(sk, SOCK_DEAD)) {
 366                sk->sk_state_change(sk);
 367                sock_set_flag(sk, SOCK_DEAD);
 368        }
 369}
 370
 371/*
 372 * Clear an own-rx-busy condition and tell the peer about this, provided
 373 * that there is a significant amount of free receive buffer space available.
 374 */
 375void x25_check_rbuf(struct sock *sk)
 376{
 377        struct x25_sock *x25 = x25_sk(sk);
 378
 379        if (atomic_read(&sk->sk_rmem_alloc) < (sk->sk_rcvbuf >> 1) &&
 380            (x25->condition & X25_COND_OWN_RX_BUSY)) {
 381                x25->condition &= ~X25_COND_OWN_RX_BUSY;
 382                x25->condition &= ~X25_COND_ACK_PENDING;
 383                x25->vl         = x25->vr;
 384                x25_write_internal(sk, X25_RR);
 385                x25_stop_timer(sk);
 386        }
 387}
 388
 389
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.