static void x25_timer_expiry(unsigned long param) { struct sock *sk = (struct sock *)param; bh_lock_sock(sk); if (sock_owned_by_user(sk)) { /* can currently only occur in state 3 */ if (x25_sk(sk)->state == X25_STATE_3) x25_start_t2timer(sk); } else x25_do_timer_expiry(sk); bh_unlock_sock(sk); }
/* * State machine for state 3, Connected State. * The handling of the timer(s) is in file x25_timer.c * Handling of state 0 and connection release is in af_x25.c. */ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m) { int queued = 0; int modulus; struct x25_sock *x25 = x25_sk(sk); modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS; switch (frametype) { case X25_RESET_REQUEST: x25_write_internal(sk, X25_RESET_CONFIRMATION); x25_stop_timer(sk); x25->condition = 0x00; x25->vs = 0; x25->vr = 0; x25->va = 0; x25->vl = 0; x25_requeue_frames(sk); break; case X25_CLEAR_REQUEST: x25_write_internal(sk, X25_CLEAR_CONFIRMATION); x25_disconnect(sk, 0, skb->data[3], skb->data[4]); break; case X25_RR: case X25_RNR: if (!x25_validate_nr(sk, nr)) { x25_clear_queues(sk); x25_write_internal(sk, X25_RESET_REQUEST); x25_start_t22timer(sk); x25->condition = 0x00; x25->vs = 0; x25->vr = 0; x25->va = 0; x25->vl = 0; x25->state = X25_STATE_4; } else { x25_frames_acked(sk, nr); if (frametype == X25_RNR) { x25->condition |= X25_COND_PEER_RX_BUSY; } else { x25->condition &= ~X25_COND_PEER_RX_BUSY; } } break; case X25_DATA: /* XXX */ x25->condition &= ~X25_COND_PEER_RX_BUSY; if ((ns != x25->vr) || !x25_validate_nr(sk, nr)) { x25_clear_queues(sk); x25_write_internal(sk, X25_RESET_REQUEST); x25_start_t22timer(sk); x25->condition = 0x00; x25->vs = 0; x25->vr = 0; x25->va = 0; x25->vl = 0; x25->state = X25_STATE_4; break; } x25_frames_acked(sk, nr); if (ns == x25->vr) { if (x25_queue_rx_frame(sk, skb, m) == 0) { x25->vr = (x25->vr + 1) % modulus; queued = 1; } else { /* Should never happen */ x25_clear_queues(sk); x25_write_internal(sk, X25_RESET_REQUEST); x25_start_t22timer(sk); x25->condition = 0x00; x25->vs = 0; x25->vr = 0; x25->va = 0; x25->vl = 0; x25->state = X25_STATE_4; break; } if (atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf / 2)) x25->condition |= X25_COND_OWN_RX_BUSY; } /* * If the window is full Ack it immediately, else * start the holdback timer. */ if (((x25->vl + x25->facilities.winsize_in) % modulus) == x25->vr) { x25->condition &= ~X25_COND_ACK_PENDING; x25_stop_timer(sk); x25_enquiry_response(sk); } else { x25->condition |= X25_COND_ACK_PENDING; x25_start_t2timer(sk); } break; case X25_INTERRUPT_CONFIRMATION: x25->intflag = 0; break; case X25_INTERRUPT: if (sock_flag(sk, SOCK_URGINLINE)) queued = !sock_queue_rcv_skb(sk, skb); else { skb_set_owner_r(skb, sk); skb_queue_tail(&x25->interrupt_in_queue, skb); queued = 1; } sk_send_sigurg(sk); x25_write_internal(sk, X25_INTERRUPT_CONFIRMATION); break; default: printk(KERN_WARNING "x25: unknown %02X in state 3\n", frametype); break; } return queued; }