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