12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds *
41da177e4SLinus Torvalds * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
51da177e4SLinus Torvalds * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
61da177e4SLinus Torvalds */
71da177e4SLinus Torvalds #include <linux/errno.h>
81da177e4SLinus Torvalds #include <linux/types.h>
91da177e4SLinus Torvalds #include <linux/socket.h>
101da177e4SLinus Torvalds #include <linux/in.h>
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/jiffies.h>
131da177e4SLinus Torvalds #include <linux/timer.h>
141da177e4SLinus Torvalds #include <linux/string.h>
151da177e4SLinus Torvalds #include <linux/sockios.h>
161da177e4SLinus Torvalds #include <linux/net.h>
171da177e4SLinus Torvalds #include <net/ax25.h>
181da177e4SLinus Torvalds #include <linux/inet.h>
191da177e4SLinus Torvalds #include <linux/netdevice.h>
201da177e4SLinus Torvalds #include <linux/skbuff.h>
211da177e4SLinus Torvalds #include <net/sock.h>
22c752f073SArnaldo Carvalho de Melo #include <net/tcp_states.h>
231da177e4SLinus Torvalds #include <linux/fcntl.h>
241da177e4SLinus Torvalds #include <linux/mm.h>
251da177e4SLinus Torvalds #include <linux/interrupt.h>
261da177e4SLinus Torvalds #include <net/rose.h>
271da177e4SLinus Torvalds
2899767f27SKees Cook static void rose_heartbeat_expiry(struct timer_list *t);
294966babdSKees Cook static void rose_timer_expiry(struct timer_list *);
304966babdSKees Cook static void rose_idletimer_expiry(struct timer_list *);
311da177e4SLinus Torvalds
rose_start_heartbeat(struct sock * sk)321da177e4SLinus Torvalds void rose_start_heartbeat(struct sock *sk)
331da177e4SLinus Torvalds {
349cc02edeSDuoming Zhou sk_stop_timer(sk, &sk->sk_timer);
351da177e4SLinus Torvalds
36841b86f3SKees Cook sk->sk_timer.function = rose_heartbeat_expiry;
371da177e4SLinus Torvalds sk->sk_timer.expires = jiffies + 5 * HZ;
381da177e4SLinus Torvalds
399cc02edeSDuoming Zhou sk_reset_timer(sk, &sk->sk_timer, sk->sk_timer.expires);
401da177e4SLinus Torvalds }
411da177e4SLinus Torvalds
rose_start_t1timer(struct sock * sk)421da177e4SLinus Torvalds void rose_start_t1timer(struct sock *sk)
431da177e4SLinus Torvalds {
441da177e4SLinus Torvalds struct rose_sock *rose = rose_sk(sk);
451da177e4SLinus Torvalds
469cc02edeSDuoming Zhou sk_stop_timer(sk, &rose->timer);
471da177e4SLinus Torvalds
48841b86f3SKees Cook rose->timer.function = rose_timer_expiry;
491da177e4SLinus Torvalds rose->timer.expires = jiffies + rose->t1;
501da177e4SLinus Torvalds
519cc02edeSDuoming Zhou sk_reset_timer(sk, &rose->timer, rose->timer.expires);
521da177e4SLinus Torvalds }
531da177e4SLinus Torvalds
rose_start_t2timer(struct sock * sk)541da177e4SLinus Torvalds void rose_start_t2timer(struct sock *sk)
551da177e4SLinus Torvalds {
561da177e4SLinus Torvalds struct rose_sock *rose = rose_sk(sk);
571da177e4SLinus Torvalds
589cc02edeSDuoming Zhou sk_stop_timer(sk, &rose->timer);
591da177e4SLinus Torvalds
60841b86f3SKees Cook rose->timer.function = rose_timer_expiry;
611da177e4SLinus Torvalds rose->timer.expires = jiffies + rose->t2;
621da177e4SLinus Torvalds
639cc02edeSDuoming Zhou sk_reset_timer(sk, &rose->timer, rose->timer.expires);
641da177e4SLinus Torvalds }
651da177e4SLinus Torvalds
rose_start_t3timer(struct sock * sk)661da177e4SLinus Torvalds void rose_start_t3timer(struct sock *sk)
671da177e4SLinus Torvalds {
681da177e4SLinus Torvalds struct rose_sock *rose = rose_sk(sk);
691da177e4SLinus Torvalds
709cc02edeSDuoming Zhou sk_stop_timer(sk, &rose->timer);
711da177e4SLinus Torvalds
72841b86f3SKees Cook rose->timer.function = rose_timer_expiry;
731da177e4SLinus Torvalds rose->timer.expires = jiffies + rose->t3;
741da177e4SLinus Torvalds
759cc02edeSDuoming Zhou sk_reset_timer(sk, &rose->timer, rose->timer.expires);
761da177e4SLinus Torvalds }
771da177e4SLinus Torvalds
rose_start_hbtimer(struct sock * sk)781da177e4SLinus Torvalds void rose_start_hbtimer(struct sock *sk)
791da177e4SLinus Torvalds {
801da177e4SLinus Torvalds struct rose_sock *rose = rose_sk(sk);
811da177e4SLinus Torvalds
829cc02edeSDuoming Zhou sk_stop_timer(sk, &rose->timer);
831da177e4SLinus Torvalds
84841b86f3SKees Cook rose->timer.function = rose_timer_expiry;
851da177e4SLinus Torvalds rose->timer.expires = jiffies + rose->hb;
861da177e4SLinus Torvalds
879cc02edeSDuoming Zhou sk_reset_timer(sk, &rose->timer, rose->timer.expires);
881da177e4SLinus Torvalds }
891da177e4SLinus Torvalds
rose_start_idletimer(struct sock * sk)901da177e4SLinus Torvalds void rose_start_idletimer(struct sock *sk)
911da177e4SLinus Torvalds {
921da177e4SLinus Torvalds struct rose_sock *rose = rose_sk(sk);
931da177e4SLinus Torvalds
949cc02edeSDuoming Zhou sk_stop_timer(sk, &rose->idletimer);
951da177e4SLinus Torvalds
961da177e4SLinus Torvalds if (rose->idle > 0) {
97841b86f3SKees Cook rose->idletimer.function = rose_idletimer_expiry;
981da177e4SLinus Torvalds rose->idletimer.expires = jiffies + rose->idle;
991da177e4SLinus Torvalds
1009cc02edeSDuoming Zhou sk_reset_timer(sk, &rose->idletimer, rose->idletimer.expires);
1011da177e4SLinus Torvalds }
1021da177e4SLinus Torvalds }
1031da177e4SLinus Torvalds
rose_stop_heartbeat(struct sock * sk)1041da177e4SLinus Torvalds void rose_stop_heartbeat(struct sock *sk)
1051da177e4SLinus Torvalds {
1069cc02edeSDuoming Zhou sk_stop_timer(sk, &sk->sk_timer);
1071da177e4SLinus Torvalds }
1081da177e4SLinus Torvalds
rose_stop_timer(struct sock * sk)1091da177e4SLinus Torvalds void rose_stop_timer(struct sock *sk)
1101da177e4SLinus Torvalds {
1119cc02edeSDuoming Zhou sk_stop_timer(sk, &rose_sk(sk)->timer);
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds
rose_stop_idletimer(struct sock * sk)1141da177e4SLinus Torvalds void rose_stop_idletimer(struct sock *sk)
1151da177e4SLinus Torvalds {
1169cc02edeSDuoming Zhou sk_stop_timer(sk, &rose_sk(sk)->idletimer);
1171da177e4SLinus Torvalds }
1181da177e4SLinus Torvalds
rose_heartbeat_expiry(struct timer_list * t)11999767f27SKees Cook static void rose_heartbeat_expiry(struct timer_list *t)
1201da177e4SLinus Torvalds {
12199767f27SKees Cook struct sock *sk = from_timer(sk, t, sk_timer);
1221da177e4SLinus Torvalds struct rose_sock *rose = rose_sk(sk);
1231da177e4SLinus Torvalds
1241da177e4SLinus Torvalds bh_lock_sock(sk);
125*51c128baSEric Dumazet if (sock_owned_by_user(sk)) {
126*51c128baSEric Dumazet sk_reset_timer(sk, &sk->sk_timer, jiffies + HZ/20);
127*51c128baSEric Dumazet goto out;
128*51c128baSEric Dumazet }
1291da177e4SLinus Torvalds switch (rose->state) {
1301da177e4SLinus Torvalds case ROSE_STATE_0:
1311da177e4SLinus Torvalds /* Magic here: If we listen() and a new link dies before it
1321da177e4SLinus Torvalds is accepted() it isn't 'dead' so doesn't get removed. */
1331da177e4SLinus Torvalds if (sock_flag(sk, SOCK_DESTROY) ||
1341da177e4SLinus Torvalds (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
135a3d7a9d7SAndrew Morton bh_unlock_sock(sk);
1361da177e4SLinus Torvalds rose_destroy_socket(sk);
1379cc02edeSDuoming Zhou sock_put(sk);
1381da177e4SLinus Torvalds return;
1391da177e4SLinus Torvalds }
1401da177e4SLinus Torvalds break;
1411da177e4SLinus Torvalds
1421da177e4SLinus Torvalds case ROSE_STATE_3:
1431da177e4SLinus Torvalds /*
1441da177e4SLinus Torvalds * Check for the state of the receive buffer.
1451da177e4SLinus Torvalds */
1461da177e4SLinus Torvalds if (atomic_read(&sk->sk_rmem_alloc) < (sk->sk_rcvbuf / 2) &&
1471da177e4SLinus Torvalds (rose->condition & ROSE_COND_OWN_RX_BUSY)) {
1481da177e4SLinus Torvalds rose->condition &= ~ROSE_COND_OWN_RX_BUSY;
1491da177e4SLinus Torvalds rose->condition &= ~ROSE_COND_ACK_PENDING;
1501da177e4SLinus Torvalds rose->vl = rose->vr;
1511da177e4SLinus Torvalds rose_write_internal(sk, ROSE_RR);
1521da177e4SLinus Torvalds rose_stop_timer(sk); /* HB */
1531da177e4SLinus Torvalds break;
1541da177e4SLinus Torvalds }
1551da177e4SLinus Torvalds break;
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds
1581da177e4SLinus Torvalds rose_start_heartbeat(sk);
159*51c128baSEric Dumazet out:
1601da177e4SLinus Torvalds bh_unlock_sock(sk);
1619cc02edeSDuoming Zhou sock_put(sk);
1621da177e4SLinus Torvalds }
1631da177e4SLinus Torvalds
rose_timer_expiry(struct timer_list * t)1644966babdSKees Cook static void rose_timer_expiry(struct timer_list *t)
1651da177e4SLinus Torvalds {
1664966babdSKees Cook struct rose_sock *rose = from_timer(rose, t, timer);
1674966babdSKees Cook struct sock *sk = &rose->sock;
1681da177e4SLinus Torvalds
1691da177e4SLinus Torvalds bh_lock_sock(sk);
170*51c128baSEric Dumazet if (sock_owned_by_user(sk)) {
171*51c128baSEric Dumazet sk_reset_timer(sk, &rose->timer, jiffies + HZ/20);
172*51c128baSEric Dumazet goto out;
173*51c128baSEric Dumazet }
1741da177e4SLinus Torvalds switch (rose->state) {
1751da177e4SLinus Torvalds case ROSE_STATE_1: /* T1 */
1761da177e4SLinus Torvalds case ROSE_STATE_4: /* T2 */
1771da177e4SLinus Torvalds rose_write_internal(sk, ROSE_CLEAR_REQUEST);
1781da177e4SLinus Torvalds rose->state = ROSE_STATE_2;
1791da177e4SLinus Torvalds rose_start_t3timer(sk);
1801da177e4SLinus Torvalds break;
1811da177e4SLinus Torvalds
1821da177e4SLinus Torvalds case ROSE_STATE_2: /* T3 */
1831da177e4SLinus Torvalds rose->neighbour->use--;
1841da177e4SLinus Torvalds rose_disconnect(sk, ETIMEDOUT, -1, -1);
1851da177e4SLinus Torvalds break;
1861da177e4SLinus Torvalds
1871da177e4SLinus Torvalds case ROSE_STATE_3: /* HB */
1881da177e4SLinus Torvalds if (rose->condition & ROSE_COND_ACK_PENDING) {
1891da177e4SLinus Torvalds rose->condition &= ~ROSE_COND_ACK_PENDING;
1901da177e4SLinus Torvalds rose_enquiry_response(sk);
1911da177e4SLinus Torvalds }
1921da177e4SLinus Torvalds break;
1931da177e4SLinus Torvalds }
194*51c128baSEric Dumazet out:
1951da177e4SLinus Torvalds bh_unlock_sock(sk);
1969cc02edeSDuoming Zhou sock_put(sk);
1971da177e4SLinus Torvalds }
1981da177e4SLinus Torvalds
rose_idletimer_expiry(struct timer_list * t)1994966babdSKees Cook static void rose_idletimer_expiry(struct timer_list *t)
2001da177e4SLinus Torvalds {
2014966babdSKees Cook struct rose_sock *rose = from_timer(rose, t, idletimer);
2024966babdSKees Cook struct sock *sk = &rose->sock;
2031da177e4SLinus Torvalds
2041da177e4SLinus Torvalds bh_lock_sock(sk);
205*51c128baSEric Dumazet if (sock_owned_by_user(sk)) {
206*51c128baSEric Dumazet sk_reset_timer(sk, &rose->idletimer, jiffies + HZ/20);
207*51c128baSEric Dumazet goto out;
208*51c128baSEric Dumazet }
2091da177e4SLinus Torvalds rose_clear_queues(sk);
2101da177e4SLinus Torvalds
2111da177e4SLinus Torvalds rose_write_internal(sk, ROSE_CLEAR_REQUEST);
2121da177e4SLinus Torvalds rose_sk(sk)->state = ROSE_STATE_2;
2131da177e4SLinus Torvalds
2141da177e4SLinus Torvalds rose_start_t3timer(sk);
2151da177e4SLinus Torvalds
2161da177e4SLinus Torvalds sk->sk_state = TCP_CLOSE;
2171da177e4SLinus Torvalds sk->sk_err = 0;
2181da177e4SLinus Torvalds sk->sk_shutdown |= SEND_SHUTDOWN;
2191da177e4SLinus Torvalds
2201da177e4SLinus Torvalds if (!sock_flag(sk, SOCK_DEAD)) {
2211da177e4SLinus Torvalds sk->sk_state_change(sk);
2221da177e4SLinus Torvalds sock_set_flag(sk, SOCK_DEAD);
2231da177e4SLinus Torvalds }
224*51c128baSEric Dumazet out:
2251da177e4SLinus Torvalds bh_unlock_sock(sk);
2269cc02edeSDuoming Zhou sock_put(sk);
2271da177e4SLinus Torvalds }
228