1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * 4 * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) 5 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 6 * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) 7 * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) 8 */ 9 #include <linux/errno.h> 10 #include <linux/types.h> 11 #include <linux/socket.h> 12 #include <linux/in.h> 13 #include <linux/kernel.h> 14 #include <linux/timer.h> 15 #include <linux/string.h> 16 #include <linux/sockios.h> 17 #include <linux/net.h> 18 #include <net/ax25.h> 19 #include <linux/inet.h> 20 #include <linux/netdevice.h> 21 #include <linux/skbuff.h> 22 #include <net/sock.h> 23 #include <net/tcp_states.h> 24 #include <linux/uaccess.h> 25 #include <linux/fcntl.h> 26 #include <linux/mm.h> 27 #include <linux/interrupt.h> 28 29 void ax25_std_heartbeat_expiry(ax25_cb *ax25) 30 { 31 struct sock *sk = ax25->sk; 32 33 if (sk) 34 bh_lock_sock(sk); 35 36 switch (ax25->state) { 37 case AX25_STATE_0: 38 case AX25_STATE_2: 39 /* Magic here: If we listen() and a new link dies before it 40 is accepted() it isn't 'dead' so doesn't get removed. */ 41 if (!sk || sock_flag(sk, SOCK_DESTROY) || 42 (sk->sk_state == TCP_LISTEN && 43 sock_flag(sk, SOCK_DEAD))) { 44 if (sk) { 45 sock_hold(sk); 46 ax25_destroy_socket(ax25); 47 bh_unlock_sock(sk); 48 /* Ungrab socket and destroy it */ 49 sock_put(sk); 50 } else 51 ax25_destroy_socket(ax25); 52 return; 53 } 54 break; 55 56 case AX25_STATE_3: 57 case AX25_STATE_4: 58 /* 59 * Check the state of the receive buffer. 60 */ 61 if (sk != NULL) { 62 if (atomic_read(&sk->sk_rmem_alloc) < 63 (sk->sk_rcvbuf >> 1) && 64 (ax25->condition & AX25_COND_OWN_RX_BUSY)) { 65 ax25->condition &= ~AX25_COND_OWN_RX_BUSY; 66 ax25->condition &= ~AX25_COND_ACK_PENDING; 67 ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE); 68 break; 69 } 70 } 71 } 72 73 if (sk) 74 bh_unlock_sock(sk); 75 76 ax25_start_heartbeat(ax25); 77 } 78 79 void ax25_std_t2timer_expiry(ax25_cb *ax25) 80 { 81 if (ax25->condition & AX25_COND_ACK_PENDING) { 82 ax25->condition &= ~AX25_COND_ACK_PENDING; 83 ax25_std_timeout_response(ax25); 84 } 85 } 86 87 void ax25_std_t3timer_expiry(ax25_cb *ax25) 88 { 89 ax25->n2count = 0; 90 ax25_std_transmit_enquiry(ax25); 91 ax25->state = AX25_STATE_4; 92 } 93 94 void ax25_std_idletimer_expiry(ax25_cb *ax25) 95 { 96 ax25_clear_queues(ax25); 97 98 ax25->n2count = 0; 99 ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); 100 ax25->state = AX25_STATE_2; 101 102 ax25_calculate_t1(ax25); 103 ax25_start_t1timer(ax25); 104 ax25_stop_t2timer(ax25); 105 ax25_stop_t3timer(ax25); 106 107 if (ax25->sk != NULL) { 108 bh_lock_sock(ax25->sk); 109 ax25->sk->sk_state = TCP_CLOSE; 110 ax25->sk->sk_err = 0; 111 ax25->sk->sk_shutdown |= SEND_SHUTDOWN; 112 if (!sock_flag(ax25->sk, SOCK_DEAD)) { 113 ax25->sk->sk_state_change(ax25->sk); 114 sock_set_flag(ax25->sk, SOCK_DEAD); 115 } 116 bh_unlock_sock(ax25->sk); 117 } 118 } 119 120 void ax25_std_t1timer_expiry(ax25_cb *ax25) 121 { 122 switch (ax25->state) { 123 case AX25_STATE_1: 124 if (ax25->n2count == ax25->n2) { 125 if (ax25->modulus == AX25_MODULUS) { 126 ax25_disconnect(ax25, ETIMEDOUT); 127 return; 128 } else { 129 ax25->modulus = AX25_MODULUS; 130 ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; 131 ax25->n2count = 0; 132 ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); 133 } 134 } else { 135 ax25->n2count++; 136 if (ax25->modulus == AX25_MODULUS) 137 ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); 138 else 139 ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND); 140 } 141 break; 142 143 case AX25_STATE_2: 144 if (ax25->n2count == ax25->n2) { 145 ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); 146 if (!sock_flag(ax25->sk, SOCK_DESTROY)) 147 ax25_disconnect(ax25, ETIMEDOUT); 148 return; 149 } else { 150 ax25->n2count++; 151 ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); 152 } 153 break; 154 155 case AX25_STATE_3: 156 ax25->n2count = 1; 157 ax25_std_transmit_enquiry(ax25); 158 ax25->state = AX25_STATE_4; 159 break; 160 161 case AX25_STATE_4: 162 if (ax25->n2count == ax25->n2) { 163 ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); 164 ax25_disconnect(ax25, ETIMEDOUT); 165 return; 166 } else { 167 ax25->n2count++; 168 ax25_std_transmit_enquiry(ax25); 169 } 170 break; 171 } 172 173 ax25_calculate_t1(ax25); 174 ax25_start_t1timer(ax25); 175 } 176
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.