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