linux/net/x25/x25_in.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 code.
  19 *                                        New timer architecture.
  20 *      2000-03-20      Daniela Squassoni Disabling/enabling of facilities
  21 *                                        negotiation.
  22 *      2000-11-10      Henner Eisen      Check and reset for out-of-sequence
  23 *                                        i-frames.
  24 */
  25
  26#include <linux/slab.h>
  27#include <linux/errno.h>
  28#include <linux/kernel.h>
  29#include <linux/string.h>
  30#include <linux/skbuff.h>
  31#include <net/sock.h>
  32#include <net/tcp_states.h>
  33#include <net/x25.h>
  34
  35static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
  36{
  37        struct sk_buff *skbo, *skbn = skb;
  38        struct x25_sock *x25 = x25_sk(sk);
  39
  40        if (more) {
  41                x25->fraglen += skb->len;
  42                skb_queue_tail(&x25->fragment_queue, skb);
  43                skb_set_owner_r(skb, sk);
  44                return 0;
  45        }
  46
  47        if (!more && x25->fraglen > 0) {        /* End of fragment */
  48                int len = x25->fraglen + skb->len;
  49
  50                if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
  51                        kfree_skb(skb);
  52                        return 1;
  53                }
  54
  55                skb_queue_tail(&x25->fragment_queue, skb);
  56
  57                skb_reset_transport_header(skbn);
  58
  59                skbo = skb_dequeue(&x25->fragment_queue);
  60                skb_copy_from_linear_data(skbo, skb_put(skbn, skbo->len),
  61                                          skbo->len);
  62                kfree_skb(skbo);
  63
  64                while ((skbo =
  65                        skb_dequeue(&x25->fragment_queue)) != NULL) {
  66                        skb_pull(skbo, (x25->neighbour->extended) ?
  67                                        X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
  68                        skb_copy_from_linear_data(skbo,
  69                                                  skb_put(skbn, skbo->len),
  70                                                  skbo->len);
  71                        kfree_skb(skbo);
  72                }
  73
  74                x25->fraglen = 0;
  75        }
  76
  77        skb_set_owner_r(skbn, sk);
  78        skb_queue_tail(&sk->sk_receive_queue, skbn);
  79        if (!sock_flag(sk, SOCK_DEAD))
  80                sk->sk_data_ready(sk, skbn->len);
  81
  82        return 0;
  83}
  84
  85/*
  86 * State machine for state 1, Awaiting Call Accepted State.
  87 * The handling of the timer(s) is in file x25_timer.c.
  88 * Handling of state 0 and connection release is in af_x25.c.
  89 */
  90static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
  91{
  92        struct x25_address source_addr, dest_addr;
  93        int len;
  94        struct x25_sock *x25 = x25_sk(sk);
  95
  96        switch (frametype) {
  97                case X25_CALL_ACCEPTED: {
  98
  99                        x25_stop_timer(sk);
 100                        x25->condition = 0x00;
 101                        x25->vs        = 0;
 102                        x25->va        = 0;
 103                        x25->vr        = 0;
 104                        x25->vl        = 0;
 105                        x25->state     = X25_STATE_3;
 106                        sk->sk_state   = TCP_ESTABLISHED;
 107                        /*
 108                         *      Parse the data in the frame.
 109                         */
 110                        skb_pull(skb, X25_STD_MIN_LEN);
 111
 112                        len = x25_parse_address_block(skb, &source_addr,
 113                                                &dest_addr);
 114                        if (len > 0)
 115                                skb_pull(skb, len);
 116                        else if (len < 0)
 117                                goto out_clear;
 118
 119                        len = x25_parse_facilities(skb, &x25->facilities,
 120                                                &x25->dte_facilities,
 121                                                &x25->vc_facil_mask);
 122                        if (len > 0)
 123                                skb_pull(skb, len);
 124                        else if (len < 0)
 125                                goto out_clear;
 126                        /*
 127                         *      Copy any Call User Data.
 128                         */
 129                        if (skb->len > 0) {
 130                                skb_copy_from_linear_data(skb,
 131                                              x25->calluserdata.cuddata,
 132                                              skb->len);
 133                                x25->calluserdata.cudlength = skb->len;
 134                        }
 135                        if (!sock_flag(sk, SOCK_DEAD))
 136                                sk->sk_state_change(sk);
 137                        break;
 138                }
 139                case X25_CLEAR_REQUEST:
 140                        x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
 141                        x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
 142                        break;
 143
 144                default:
 145                        break;
 146        }
 147
 148        return 0;
 149
 150out_clear:
 151        x25_write_internal(sk, X25_CLEAR_REQUEST);
 152        x25->state = X25_STATE_2;
 153        x25_start_t23timer(sk);
 154        return 0;
 155}
 156
 157/*
 158 * State machine for state 2, Awaiting Clear Confirmation State.
 159 * The handling of the timer(s) is in file x25_timer.c
 160 * Handling of state 0 and connection release is in af_x25.c.
 161 */
 162static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype)
 163{
 164        switch (frametype) {
 165
 166                case X25_CLEAR_REQUEST:
 167                        x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
 168                        x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
 169                        break;
 170
 171                case X25_CLEAR_CONFIRMATION:
 172                        x25_disconnect(sk, 0, 0, 0);
 173                        break;
 174
 175                default:
 176                        break;
 177        }
 178
 179        return 0;
 180}
 181
 182/*
 183 * State machine for state 3, Connected State.
 184 * The handling of the timer(s) is in file x25_timer.c
 185 * Handling of state 0 and connection release is in af_x25.c.
 186 */
 187static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m)
 188{
 189        int queued = 0;
 190        int modulus;
 191        struct x25_sock *x25 = x25_sk(sk);
 192
 193        modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
 194
 195        switch (frametype) {
 196
 197                case X25_RESET_REQUEST:
 198                        x25_write_internal(sk, X25_RESET_CONFIRMATION);
 199                        x25_stop_timer(sk);
 200                        x25->condition = 0x00;
 201                        x25->vs        = 0;
 202                        x25->vr        = 0;
 203                        x25->va        = 0;
 204                        x25->vl        = 0;
 205                        x25_requeue_frames(sk);
 206                        break;
 207
 208                case X25_CLEAR_REQUEST:
 209                        x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
 210                        x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
 211                        break;
 212
 213                case X25_RR:
 214                case X25_RNR:
 215                        if (!x25_validate_nr(sk, nr)) {
 216                                x25_clear_queues(sk);
 217                                x25_write_internal(sk, X25_RESET_REQUEST);
 218                                x25_start_t22timer(sk);
 219                                x25->condition = 0x00;
 220                                x25->vs        = 0;
 221                                x25->vr        = 0;
 222                                x25->va        = 0;
 223                                x25->vl        = 0;
 224                                x25->state     = X25_STATE_4;
 225                        } else {
 226                                x25_frames_acked(sk, nr);
 227                                if (frametype == X25_RNR) {
 228                                        x25->condition |= X25_COND_PEER_RX_BUSY;
 229                                } else {
 230                                        x25->condition &= ~X25_COND_PEER_RX_BUSY;
 231                                }
 232                        }
 233                        break;
 234
 235                case X25_DATA:  /* XXX */
 236                        x25->condition &= ~X25_COND_PEER_RX_BUSY;
 237                        if ((ns != x25->vr) || !x25_validate_nr(sk, nr)) {
 238                                x25_clear_queues(sk);
 239                                x25_write_internal(sk, X25_RESET_REQUEST);
 240                                x25_start_t22timer(sk);
 241                                x25->condition = 0x00;
 242                                x25->vs        = 0;
 243                                x25->vr        = 0;
 244                                x25->va        = 0;
 245                                x25->vl        = 0;
 246                                x25->state     = X25_STATE_4;
 247                                break;
 248                        }
 249                        x25_frames_acked(sk, nr);
 250                        if (ns == x25->vr) {
 251                                if (x25_queue_rx_frame(sk, skb, m) == 0) {
 252                                        x25->vr = (x25->vr + 1) % modulus;
 253                                        queued = 1;
 254                                } else {
 255                                        /* Should never happen */
 256                                        x25_clear_queues(sk);
 257                                        x25_write_internal(sk, X25_RESET_REQUEST);
 258                                        x25_start_t22timer(sk);
 259                                        x25->condition = 0x00;
 260                                        x25->vs        = 0;
 261                                        x25->vr        = 0;
 262                                        x25->va        = 0;
 263                                        x25->vl        = 0;
 264                                        x25->state     = X25_STATE_4;
 265                                        break;
 266                                }
 267                                if (atomic_read(&sk->sk_rmem_alloc) >
 268                                    (sk->sk_rcvbuf >> 1))
 269                                        x25->condition |= X25_COND_OWN_RX_BUSY;
 270                        }
 271                        /*
 272                         *      If the window is full Ack it immediately, else
 273                         *      start the holdback timer.
 274                         */
 275                        if (((x25->vl + x25->facilities.winsize_in) % modulus) == x25->vr) {
 276                                x25->condition &= ~X25_COND_ACK_PENDING;
 277                                x25_stop_timer(sk);
 278                                x25_enquiry_response(sk);
 279                        } else {
 280                                x25->condition |= X25_COND_ACK_PENDING;
 281                                x25_start_t2timer(sk);
 282                        }
 283                        break;
 284
 285                case X25_INTERRUPT_CONFIRMATION:
 286                        clear_bit(X25_INTERRUPT_FLAG, &x25->flags);
 287                        break;
 288
 289                case X25_INTERRUPT:
 290                        if (sock_flag(sk, SOCK_URGINLINE))
 291                                queued = !sock_queue_rcv_skb(sk, skb);
 292                        else {
 293                                skb_set_owner_r(skb, sk);
 294                                skb_queue_tail(&x25->interrupt_in_queue, skb);
 295                                queued = 1;
 296                        }
 297                        sk_send_sigurg(sk);
 298                        x25_write_internal(sk, X25_INTERRUPT_CONFIRMATION);
 299                        break;
 300
 301                default:
 302                        printk(KERN_WARNING "x25: unknown %02X in state 3\n", frametype);
 303                        break;
 304        }
 305
 306        return queued;
 307}
 308
 309/*
 310 * State machine for state 4, Awaiting Reset Confirmation State.
 311 * The handling of the timer(s) is in file x25_timer.c
 312 * Handling of state 0 and connection release is in af_x25.c.
 313 */
 314static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
 315{
 316        switch (frametype) {
 317
 318                case X25_RESET_REQUEST:
 319                        x25_write_internal(sk, X25_RESET_CONFIRMATION);
 320                case X25_RESET_CONFIRMATION: {
 321                        struct x25_sock *x25 = x25_sk(sk);
 322
 323                        x25_stop_timer(sk);
 324                        x25->condition = 0x00;
 325                        x25->va        = 0;
 326                        x25->vr        = 0;
 327                        x25->vs        = 0;
 328                        x25->vl        = 0;
 329                        x25->state     = X25_STATE_3;
 330                        x25_requeue_frames(sk);
 331                        break;
 332                }
 333                case X25_CLEAR_REQUEST:
 334                        x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
 335                        x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
 336                        break;
 337
 338                default:
 339                        break;
 340        }
 341
 342        return 0;
 343}
 344
 345/* Higher level upcall for a LAPB frame */
 346int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 347{
 348        struct x25_sock *x25 = x25_sk(sk);
 349        int queued = 0, frametype, ns, nr, q, d, m;
 350
 351        if (x25->state == X25_STATE_0)
 352                return 0;
 353
 354        frametype = x25_decode(sk, skb, &ns, &nr, &q, &d, &m);
 355
 356        switch (x25->state) {
 357                case X25_STATE_1:
 358                        queued = x25_state1_machine(sk, skb, frametype);
 359                        break;
 360                case X25_STATE_2:
 361                        queued = x25_state2_machine(sk, skb, frametype);
 362                        break;
 363                case X25_STATE_3:
 364                        queued = x25_state3_machine(sk, skb, frametype, ns, nr, q, d, m);
 365                        break;
 366                case X25_STATE_4:
 367                        queued = x25_state4_machine(sk, skb, frametype);
 368                        break;
 369        }
 370
 371        x25_kick(sk);
 372
 373        return queued;
 374}
 375
 376int x25_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 377{
 378        int queued = x25_process_rx_frame(sk, skb);
 379
 380        if (!queued)
 381                kfree_skb(skb);
 382
 383        return 0;
 384}
 385