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 Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 8 * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk) 9 */ 10#include <linux/errno.h> 11#include <linux/types.h> 12#include <linux/socket.h> 13#include <linux/in.h> 14#include <linux/kernel.h> 15#include <linux/timer.h> 16#include <linux/string.h> 17#include <linux/sockios.h> 18#include <linux/net.h> 19#include <linux/slab.h> 20#include <net/ax25.h> 21#include <linux/inet.h> 22#include <linux/netdevice.h> 23#include <linux/skbuff.h> 24#include <net/sock.h> 25#include <net/tcp_states.h> 26#include <linux/uaccess.h> 27#include <linux/fcntl.h> 28#include <linux/mm.h> 29#include <linux/interrupt.h> 30#include <net/netrom.h> 31 32static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) 33{ 34 struct sk_buff *skbo, *skbn = skb; 35 struct nr_sock *nr = nr_sk(sk); 36 37 skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN); 38 39 nr_start_idletimer(sk); 40 41 if (more) { 42 nr->fraglen += skb->len; 43 skb_queue_tail(&nr->frag_queue, skb); 44 return 0; 45 } 46 47 if (!more && nr->fraglen > 0) { /* End of fragment */ 48 nr->fraglen += skb->len; 49 skb_queue_tail(&nr->frag_queue, skb); 50 51 if ((skbn = alloc_skb(nr->fraglen, GFP_ATOMIC)) == NULL) 52 return 1; 53 54 skb_reset_transport_header(skbn); 55 56 while ((skbo = skb_dequeue(&nr->frag_queue)) != NULL) { 57 skb_copy_from_linear_data(skbo, 58 skb_put(skbn, skbo->len), 59 skbo->len); 60 kfree_skb(skbo); 61 } 62 63 nr->fraglen = 0; 64 } 65 66 return sock_queue_rcv_skb(sk, skbn); 67} 68 69/* 70 * State machine for state 1, Awaiting Connection State. 71 * The handling of the timer(s) is in file nr_timer.c. 72 * Handling of state 0 and connection release is in netrom.c. 73 */ 74static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, 75 int frametype) 76{ 77 switch (frametype) { 78 case NR_CONNACK: { 79 struct nr_sock *nr = nr_sk(sk); 80 81 nr_stop_t1timer(sk); 82 nr_start_idletimer(sk); 83 nr->your_index = skb->data[17]; 84 nr->your_id = skb->data[18]; 85 nr->vs = 0; 86 nr->va = 0; 87 nr->vr = 0; 88 nr->vl = 0; 89 nr->state = NR_STATE_3; 90 nr->n2count = 0; 91 nr->window = skb->data[20]; 92 sk->sk_state = TCP_ESTABLISHED; 93 if (!sock_flag(sk, SOCK_DEAD)) 94 sk->sk_state_change(sk); 95 break; 96 } 97 98 case NR_CONNACK | NR_CHOKE_FLAG: 99 nr_disconnect(sk, ECONNREFUSED); 100 break; 101 102 case NR_RESET: 103 if (sysctl_netrom_reset_circuit) 104 nr_disconnect(sk, ECONNRESET); 105 break; 106 107 default: 108 break; 109 } 110 return 0; 111} 112 113/* 114 * State machine for state 2, Awaiting Release State. 115 * The handling of the timer(s) is in file nr_timer.c 116 * Handling of state 0 and connection release is in netrom.c. 117 */ 118static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, 119 int frametype) 120{ 121 switch (frametype) { 122 case NR_CONNACK | NR_CHOKE_FLAG: 123 nr_disconnect(sk, ECONNRESET); 124 break; 125 126 case NR_DISCREQ: 127 nr_write_internal(sk, NR_DISCACK); 128 129 case NR_DISCACK: 130 nr_disconnect(sk, 0); 131 break; 132 133 case NR_RESET: 134 if (sysctl_netrom_reset_circuit) 135 nr_disconnect(sk, ECONNRESET); 136 break; 137 138 default: 139 break; 140 } 141 return 0; 142} 143 144/* 145 * State machine for state 3, Connected State. 146 * The handling of the timer(s) is in file nr_timer.c 147 * Handling of state 0 and connection release is in netrom.c. 148 */ 149static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype) 150{ 151 struct nr_sock *nrom = nr_sk(sk); 152 struct sk_buff_head temp_queue; 153 struct sk_buff *skbn; 154 unsigned short save_vr; 155 unsigned short nr, ns; 156 int queued = 0; 157 158 nr = skb->data[18]; 159 ns = skb->data[17]; 160 161 switch (frametype) { 162 case NR_CONNREQ: 163 nr_write_internal(sk, NR_CONNACK); 164 break; 165 166 case NR_DISCREQ: 167 nr_write_internal(sk, NR_DISCACK); 168 nr_disconnect(sk, 0); 169 break; 170 171 case NR_CONNACK | NR_CHOKE_FLAG: 172 case NR_DISCACK: 173 nr_disconnect(sk, ECONNRESET); 174 break; 175 176 case NR_INFOACK: 177 case NR_INFOACK | NR_CHOKE_FLAG: 178 case NR_INFOACK | NR_NAK_FLAG: 179 case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG: 180 if (frametype & NR_CHOKE_FLAG) { 181 nrom->condition |= NR_COND_PEER_RX_BUSY; 182 nr_start_t4timer(sk); 183 } else { 184 nrom->condition &= ~NR_COND_PEER_RX_BUSY; 185 nr_stop_t4timer(sk); 186 } 187 if (!nr_validate_nr(sk, nr)) { 188 break; 189 } 190 if (frametype & NR_NAK_FLAG) { 191 nr_frames_acked(sk, nr); 192 nr_send_nak_frame(sk); 193 } else { 194 if (nrom->condition & NR_COND_PEER_RX_BUSY) { 195 nr_frames_acked(sk, nr); 196 } else { 197 nr_check_iframes_acked(sk, nr); 198 } 199 } 200 break; 201 202 case NR_INFO: 203 case NR_INFO | NR_NAK_FLAG: 204 case NR_INFO | NR_CHOKE_FLAG: 205 case NR_INFO | NR_MORE_FLAG: 206 case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG: 207 case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG: 208 case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG: 209 case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG: 210 if (frametype & NR_CHOKE_FLAG) { 211 nrom->condition |= NR_COND_PEER_RX_BUSY; 212 nr_start_t4timer(sk); 213 } else { 214 nrom->condition &= ~NR_COND_PEER_RX_BUSY; 215 nr_stop_t4timer(sk); 216 } 217 if (nr_validate_nr(sk, nr)) { 218 if (frametype & NR_NAK_FLAG) { 219 nr_frames_acked(sk, nr); 220 nr_send_nak_frame(sk); 221 } else { 222 if (nrom->condition & NR_COND_PEER_RX_BUSY) { 223 nr_frames_acked(sk, nr); 224 } else { 225 nr_check_iframes_acked(sk, nr); 226 } 227 } 228 } 229 queued = 1; 230 skb_queue_head(&nrom->reseq_queue, skb); 231 if (nrom->condition & NR_COND_OWN_RX_BUSY) 232 break; 233 skb_queue_head_init(&temp_queue); 234 do { 235 save_vr = nrom->vr; 236 while ((skbn = skb_dequeue(&nrom->reseq_queue)) != NULL) { 237 ns = skbn->data[17]; 238 if (ns == nrom->vr) { 239 if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) { 240 nrom->vr = (nrom->vr + 1) % NR_MODULUS; 241 } else { 242 nrom->condition |= NR_COND_OWN_RX_BUSY; 243 skb_queue_tail(&temp_queue, skbn); 244 } 245 } else if (nr_in_rx_window(sk, ns)) { 246 skb_queue_tail(&temp_queue, skbn); 247 } else { 248 kfree_skb(skbn); 249 } 250 } 251 while ((skbn = skb_dequeue(&temp_queue)) != NULL) { 252 skb_queue_tail(&nrom->reseq_queue, skbn); 253 } 254 } while (save_vr != nrom->vr); 255 /* 256 * Window is full, ack it immediately. 257 */ 258 if (((nrom->vl + nrom->window) % NR_MODULUS) == nrom->vr) { 259 nr_enquiry_response(sk); 260 } else { 261 if (!(nrom->condition & NR_COND_ACK_PENDING)) { 262 nrom->condition |= NR_COND_ACK_PENDING; 263 nr_start_t2timer(sk); 264 } 265 } 266 break; 267 268 case NR_RESET: 269 if (sysctl_netrom_reset_circuit) 270 nr_disconnect(sk, ECONNRESET); 271 break; 272 273 default: 274 break; 275 } 276 return queued; 277} 278 279/* Higher level upcall for a LAPB frame - called with sk locked */ 280int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb) 281{ 282 struct nr_sock *nr = nr_sk(sk); 283 int queued = 0, frametype; 284 285 if (nr->state == NR_STATE_0) 286 return 0; 287 288 frametype = skb->data[19]; 289 290 switch (nr->state) { 291 case NR_STATE_1: 292 queued = nr_state1_machine(sk, skb, frametype); 293 break; 294 case NR_STATE_2: 295 queued = nr_state2_machine(sk, skb, frametype); 296 break; 297 case NR_STATE_3: 298 queued = nr_state3_machine(sk, skb, frametype); 299 break; 300 } 301 302 nr_kick(sk); 303 304 return queued; 305} 306