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