1*ee5d8f4dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * X.25 Packet Layer release 002
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * This is ALPHA test software. This code may break your machine,
61da177e4SLinus Torvalds * randomly fail to work with new releases, misbehave and/or generally
71da177e4SLinus Torvalds * screw up. It might even work.
81da177e4SLinus Torvalds *
91da177e4SLinus Torvalds * This code REQUIRES 2.1.15 or higher
101da177e4SLinus Torvalds *
111da177e4SLinus Torvalds * History
121da177e4SLinus Torvalds * X.25 001 Jonathan Naylor Started coding.
131da177e4SLinus Torvalds * X.25 002 Jonathan Naylor New timer architecture.
141da177e4SLinus Torvalds * Centralised disconnection processing.
151da177e4SLinus Torvalds */
161da177e4SLinus Torvalds
171da177e4SLinus Torvalds #include <linux/errno.h>
181da177e4SLinus Torvalds #include <linux/jiffies.h>
191da177e4SLinus Torvalds #include <linux/timer.h>
201da177e4SLinus Torvalds #include <net/sock.h>
21c752f073SArnaldo Carvalho de Melo #include <net/tcp_states.h>
221da177e4SLinus Torvalds #include <net/x25.h>
231da177e4SLinus Torvalds
2499767f27SKees Cook static void x25_heartbeat_expiry(struct timer_list *t);
2599767f27SKees Cook static void x25_timer_expiry(struct timer_list *t);
261da177e4SLinus Torvalds
x25_init_timers(struct sock * sk)271da177e4SLinus Torvalds void x25_init_timers(struct sock *sk)
281da177e4SLinus Torvalds {
291da177e4SLinus Torvalds struct x25_sock *x25 = x25_sk(sk);
301da177e4SLinus Torvalds
3199767f27SKees Cook timer_setup(&x25->timer, x25_timer_expiry, 0);
321da177e4SLinus Torvalds
331da177e4SLinus Torvalds /* initialized by sock_init_data */
34841b86f3SKees Cook sk->sk_timer.function = x25_heartbeat_expiry;
351da177e4SLinus Torvalds }
361da177e4SLinus Torvalds
x25_start_heartbeat(struct sock * sk)371da177e4SLinus Torvalds void x25_start_heartbeat(struct sock *sk)
381da177e4SLinus Torvalds {
391da177e4SLinus Torvalds mod_timer(&sk->sk_timer, jiffies + 5 * HZ);
401da177e4SLinus Torvalds }
411da177e4SLinus Torvalds
x25_stop_heartbeat(struct sock * sk)421da177e4SLinus Torvalds void x25_stop_heartbeat(struct sock *sk)
431da177e4SLinus Torvalds {
441da177e4SLinus Torvalds del_timer(&sk->sk_timer);
451da177e4SLinus Torvalds }
461da177e4SLinus Torvalds
x25_start_t2timer(struct sock * sk)471da177e4SLinus Torvalds void x25_start_t2timer(struct sock *sk)
481da177e4SLinus Torvalds {
491da177e4SLinus Torvalds struct x25_sock *x25 = x25_sk(sk);
501da177e4SLinus Torvalds
511da177e4SLinus Torvalds mod_timer(&x25->timer, jiffies + x25->t2);
521da177e4SLinus Torvalds }
531da177e4SLinus Torvalds
x25_start_t21timer(struct sock * sk)541da177e4SLinus Torvalds void x25_start_t21timer(struct sock *sk)
551da177e4SLinus Torvalds {
561da177e4SLinus Torvalds struct x25_sock *x25 = x25_sk(sk);
571da177e4SLinus Torvalds
581da177e4SLinus Torvalds mod_timer(&x25->timer, jiffies + x25->t21);
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds
x25_start_t22timer(struct sock * sk)611da177e4SLinus Torvalds void x25_start_t22timer(struct sock *sk)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds struct x25_sock *x25 = x25_sk(sk);
641da177e4SLinus Torvalds
651da177e4SLinus Torvalds mod_timer(&x25->timer, jiffies + x25->t22);
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds
x25_start_t23timer(struct sock * sk)681da177e4SLinus Torvalds void x25_start_t23timer(struct sock *sk)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds struct x25_sock *x25 = x25_sk(sk);
711da177e4SLinus Torvalds
721da177e4SLinus Torvalds mod_timer(&x25->timer, jiffies + x25->t23);
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds
x25_stop_timer(struct sock * sk)751da177e4SLinus Torvalds void x25_stop_timer(struct sock *sk)
761da177e4SLinus Torvalds {
771da177e4SLinus Torvalds del_timer(&x25_sk(sk)->timer);
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds
x25_display_timer(struct sock * sk)801da177e4SLinus Torvalds unsigned long x25_display_timer(struct sock *sk)
811da177e4SLinus Torvalds {
821da177e4SLinus Torvalds struct x25_sock *x25 = x25_sk(sk);
831da177e4SLinus Torvalds
841da177e4SLinus Torvalds if (!timer_pending(&x25->timer))
851da177e4SLinus Torvalds return 0;
861da177e4SLinus Torvalds
871da177e4SLinus Torvalds return x25->timer.expires - jiffies;
881da177e4SLinus Torvalds }
891da177e4SLinus Torvalds
x25_heartbeat_expiry(struct timer_list * t)9099767f27SKees Cook static void x25_heartbeat_expiry(struct timer_list *t)
911da177e4SLinus Torvalds {
9299767f27SKees Cook struct sock *sk = from_timer(sk, t, sk_timer);
931da177e4SLinus Torvalds
941da177e4SLinus Torvalds bh_lock_sock(sk);
951da177e4SLinus Torvalds if (sock_owned_by_user(sk)) /* can currently only occur in state 3 */
961da177e4SLinus Torvalds goto restart_heartbeat;
971da177e4SLinus Torvalds
981da177e4SLinus Torvalds switch (x25_sk(sk)->state) {
991da177e4SLinus Torvalds
1001da177e4SLinus Torvalds case X25_STATE_0:
1011da177e4SLinus Torvalds /*
1021da177e4SLinus Torvalds * Magic here: If we listen() and a new link dies
1031da177e4SLinus Torvalds * before it is accepted() it isn't 'dead' so doesn't
1041da177e4SLinus Torvalds * get removed.
1051da177e4SLinus Torvalds */
1061da177e4SLinus Torvalds if (sock_flag(sk, SOCK_DESTROY) ||
1071da177e4SLinus Torvalds (sk->sk_state == TCP_LISTEN &&
1081da177e4SLinus Torvalds sock_flag(sk, SOCK_DEAD))) {
10943dff98bSShaun Pereira bh_unlock_sock(sk);
11014ebaf81SDavid S. Miller x25_destroy_socket_from_timer(sk);
11143dff98bSShaun Pereira return;
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds break;
1141da177e4SLinus Torvalds
1151da177e4SLinus Torvalds case X25_STATE_3:
1161da177e4SLinus Torvalds /*
1171da177e4SLinus Torvalds * Check for the state of the receive buffer.
1181da177e4SLinus Torvalds */
1191da177e4SLinus Torvalds x25_check_rbuf(sk);
1201da177e4SLinus Torvalds break;
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds restart_heartbeat:
1231da177e4SLinus Torvalds x25_start_heartbeat(sk);
1241da177e4SLinus Torvalds bh_unlock_sock(sk);
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds
1271da177e4SLinus Torvalds /*
1281da177e4SLinus Torvalds * Timer has expired, it may have been T2, T21, T22, or T23. We can tell
1291da177e4SLinus Torvalds * by the state machine state.
1301da177e4SLinus Torvalds */
x25_do_timer_expiry(struct sock * sk)1311da177e4SLinus Torvalds static inline void x25_do_timer_expiry(struct sock * sk)
1321da177e4SLinus Torvalds {
1331da177e4SLinus Torvalds struct x25_sock *x25 = x25_sk(sk);
1341da177e4SLinus Torvalds
1351da177e4SLinus Torvalds switch (x25->state) {
1361da177e4SLinus Torvalds
1371da177e4SLinus Torvalds case X25_STATE_3: /* T2 */
1381da177e4SLinus Torvalds if (x25->condition & X25_COND_ACK_PENDING) {
1391da177e4SLinus Torvalds x25->condition &= ~X25_COND_ACK_PENDING;
1401da177e4SLinus Torvalds x25_enquiry_response(sk);
1411da177e4SLinus Torvalds }
1421da177e4SLinus Torvalds break;
1431da177e4SLinus Torvalds
1441da177e4SLinus Torvalds case X25_STATE_1: /* T21 */
1451da177e4SLinus Torvalds case X25_STATE_4: /* T22 */
1461da177e4SLinus Torvalds x25_write_internal(sk, X25_CLEAR_REQUEST);
1471da177e4SLinus Torvalds x25->state = X25_STATE_2;
1481da177e4SLinus Torvalds x25_start_t23timer(sk);
1491da177e4SLinus Torvalds break;
1501da177e4SLinus Torvalds
1511da177e4SLinus Torvalds case X25_STATE_2: /* T23 */
1521da177e4SLinus Torvalds x25_disconnect(sk, ETIMEDOUT, 0, 0);
1531da177e4SLinus Torvalds break;
1541da177e4SLinus Torvalds }
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds
x25_timer_expiry(struct timer_list * t)15799767f27SKees Cook static void x25_timer_expiry(struct timer_list *t)
1581da177e4SLinus Torvalds {
15999767f27SKees Cook struct x25_sock *x25 = from_timer(x25, t, timer);
16099767f27SKees Cook struct sock *sk = &x25->sk;
1611da177e4SLinus Torvalds
1621da177e4SLinus Torvalds bh_lock_sock(sk);
1631da177e4SLinus Torvalds if (sock_owned_by_user(sk)) { /* can currently only occur in state 3 */
1641da177e4SLinus Torvalds if (x25_sk(sk)->state == X25_STATE_3)
1651da177e4SLinus Torvalds x25_start_t2timer(sk);
1661da177e4SLinus Torvalds } else
1671da177e4SLinus Torvalds x25_do_timer_expiry(sk);
1681da177e4SLinus Torvalds bh_unlock_sock(sk);
1691da177e4SLinus Torvalds }
170