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