linux/net/x25/x25_timer.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 New timer architecture.
  19 *                                      Centralised disconnection processing.
  20 */
  21
  22#include <linux/errno.h>
  23#include <linux/jiffies.h>
  24#include <linux/timer.h>
  25#include <net/sock.h>
  26#include <net/tcp_states.h>
  27#include <net/x25.h>
  28
  29static void x25_heartbeat_expiry(unsigned long);
  30static void x25_timer_expiry(unsigned long);
  31
  32void x25_init_timers(struct sock *sk)
  33{
  34        struct x25_sock *x25 = x25_sk(sk);
  35
  36        setup_timer(&x25->timer, x25_timer_expiry, (unsigned long)sk);
  37
  38        /* initialized by sock_init_data */
  39        sk->sk_timer.data     = (unsigned long)sk;
  40        sk->sk_timer.function = &x25_heartbeat_expiry;
  41}
  42
  43void x25_start_heartbeat(struct sock *sk)
  44{
  45        mod_timer(&sk->sk_timer, jiffies + 5 * HZ);
  46}
  47
  48void x25_stop_heartbeat(struct sock *sk)
  49{
  50        del_timer(&sk->sk_timer);
  51}
  52
  53void x25_start_t2timer(struct sock *sk)
  54{
  55        struct x25_sock *x25 = x25_sk(sk);
  56
  57        mod_timer(&x25->timer, jiffies + x25->t2);
  58}
  59
  60void x25_start_t21timer(struct sock *sk)
  61{
  62        struct x25_sock *x25 = x25_sk(sk);
  63
  64        mod_timer(&x25->timer, jiffies + x25->t21);
  65}
  66
  67void x25_start_t22timer(struct sock *sk)
  68{
  69        struct x25_sock *x25 = x25_sk(sk);
  70
  71        mod_timer(&x25->timer, jiffies + x25->t22);
  72}
  73
  74void x25_start_t23timer(struct sock *sk)
  75{
  76        struct x25_sock *x25 = x25_sk(sk);
  77
  78        mod_timer(&x25->timer, jiffies + x25->t23);
  79}
  80
  81void x25_stop_timer(struct sock *sk)
  82{
  83        del_timer(&x25_sk(sk)->timer);
  84}
  85
  86unsigned long x25_display_timer(struct sock *sk)
  87{
  88        struct x25_sock *x25 = x25_sk(sk);
  89
  90        if (!timer_pending(&x25->timer))
  91                return 0;
  92
  93        return x25->timer.expires - jiffies;
  94}
  95
  96static void x25_heartbeat_expiry(unsigned long param)
  97{
  98        struct sock *sk = (struct sock *)param;
  99
 100        bh_lock_sock(sk);
 101        if (sock_owned_by_user(sk)) /* can currently only occur in state 3 */
 102                goto restart_heartbeat;
 103
 104        switch (x25_sk(sk)->state) {
 105
 106                case X25_STATE_0:
 107                        /*
 108                         * Magic here: If we listen() and a new link dies
 109                         * before it is accepted() it isn't 'dead' so doesn't
 110                         * get removed.
 111                         */
 112                        if (sock_flag(sk, SOCK_DESTROY) ||
 113                            (sk->sk_state == TCP_LISTEN &&
 114                             sock_flag(sk, SOCK_DEAD))) {
 115                                bh_unlock_sock(sk);
 116                                x25_destroy_socket_from_timer(sk);
 117                                return;
 118                        }
 119                        break;
 120
 121                case X25_STATE_3:
 122                        /*
 123                         * Check for the state of the receive buffer.
 124                         */
 125                        x25_check_rbuf(sk);
 126                        break;
 127        }
 128restart_heartbeat:
 129        x25_start_heartbeat(sk);
 130        bh_unlock_sock(sk);
 131}
 132
 133/*
 134 *      Timer has expired, it may have been T2, T21, T22, or T23. We can tell
 135 *      by the state machine state.
 136 */
 137static inline void x25_do_timer_expiry(struct sock * sk)
 138{
 139        struct x25_sock *x25 = x25_sk(sk);
 140
 141        switch (x25->state) {
 142
 143                case X25_STATE_3:       /* T2 */
 144                        if (x25->condition & X25_COND_ACK_PENDING) {
 145                                x25->condition &= ~X25_COND_ACK_PENDING;
 146                                x25_enquiry_response(sk);
 147                        }
 148                        break;
 149
 150                case X25_STATE_1:       /* T21 */
 151                case X25_STATE_4:       /* T22 */
 152                        x25_write_internal(sk, X25_CLEAR_REQUEST);
 153                        x25->state = X25_STATE_2;
 154                        x25_start_t23timer(sk);
 155                        break;
 156
 157                case X25_STATE_2:       /* T23 */
 158                        x25_disconnect(sk, ETIMEDOUT, 0, 0);
 159                        break;
 160        }
 161}
 162
 163static void x25_timer_expiry(unsigned long param)
 164{
 165        struct sock *sk = (struct sock *)param;
 166
 167        bh_lock_sock(sk);
 168        if (sock_owned_by_user(sk)) { /* can currently only occur in state 3 */
 169                if (x25_sk(sk)->state == X25_STATE_3)
 170                        x25_start_t2timer(sk);
 171        } else
 172                x25_do_timer_expiry(sk);
 173        bh_unlock_sock(sk);
 174}
 175