xref: /openbmc/linux/net/netrom/nr_in.c (revision 8c61e3be)
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 (READ_ONCE(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 		fallthrough;
126 	case NR_DISCACK:
127 		nr_disconnect(sk, 0);
128 		break;
129 
130 	case NR_RESET:
131 		if (READ_ONCE(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 
157 	switch (frametype) {
158 	case NR_CONNREQ:
159 		nr_write_internal(sk, NR_CONNACK);
160 		break;
161 
162 	case NR_DISCREQ:
163 		nr_write_internal(sk, NR_DISCACK);
164 		nr_disconnect(sk, 0);
165 		break;
166 
167 	case NR_CONNACK | NR_CHOKE_FLAG:
168 	case NR_DISCACK:
169 		nr_disconnect(sk, ECONNRESET);
170 		break;
171 
172 	case NR_INFOACK:
173 	case NR_INFOACK | NR_CHOKE_FLAG:
174 	case NR_INFOACK | NR_NAK_FLAG:
175 	case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
176 		if (frametype & NR_CHOKE_FLAG) {
177 			nrom->condition |= NR_COND_PEER_RX_BUSY;
178 			nr_start_t4timer(sk);
179 		} else {
180 			nrom->condition &= ~NR_COND_PEER_RX_BUSY;
181 			nr_stop_t4timer(sk);
182 		}
183 		if (!nr_validate_nr(sk, nr)) {
184 			break;
185 		}
186 		if (frametype & NR_NAK_FLAG) {
187 			nr_frames_acked(sk, nr);
188 			nr_send_nak_frame(sk);
189 		} else {
190 			if (nrom->condition & NR_COND_PEER_RX_BUSY) {
191 				nr_frames_acked(sk, nr);
192 			} else {
193 				nr_check_iframes_acked(sk, nr);
194 			}
195 		}
196 		break;
197 
198 	case NR_INFO:
199 	case NR_INFO | NR_NAK_FLAG:
200 	case NR_INFO | NR_CHOKE_FLAG:
201 	case NR_INFO | NR_MORE_FLAG:
202 	case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG:
203 	case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG:
204 	case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG:
205 	case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG:
206 		if (frametype & NR_CHOKE_FLAG) {
207 			nrom->condition |= NR_COND_PEER_RX_BUSY;
208 			nr_start_t4timer(sk);
209 		} else {
210 			nrom->condition &= ~NR_COND_PEER_RX_BUSY;
211 			nr_stop_t4timer(sk);
212 		}
213 		if (nr_validate_nr(sk, nr)) {
214 			if (frametype & NR_NAK_FLAG) {
215 				nr_frames_acked(sk, nr);
216 				nr_send_nak_frame(sk);
217 			} else {
218 				if (nrom->condition & NR_COND_PEER_RX_BUSY) {
219 					nr_frames_acked(sk, nr);
220 				} else {
221 					nr_check_iframes_acked(sk, nr);
222 				}
223 			}
224 		}
225 		queued = 1;
226 		skb_queue_head(&nrom->reseq_queue, skb);
227 		if (nrom->condition & NR_COND_OWN_RX_BUSY)
228 			break;
229 		skb_queue_head_init(&temp_queue);
230 		do {
231 			save_vr = nrom->vr;
232 			while ((skbn = skb_dequeue(&nrom->reseq_queue)) != NULL) {
233 				ns = skbn->data[17];
234 				if (ns == nrom->vr) {
235 					if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
236 						nrom->vr = (nrom->vr + 1) % NR_MODULUS;
237 					} else {
238 						nrom->condition |= NR_COND_OWN_RX_BUSY;
239 						skb_queue_tail(&temp_queue, skbn);
240 					}
241 				} else if (nr_in_rx_window(sk, ns)) {
242 					skb_queue_tail(&temp_queue, skbn);
243 				} else {
244 					kfree_skb(skbn);
245 				}
246 			}
247 			while ((skbn = skb_dequeue(&temp_queue)) != NULL) {
248 				skb_queue_tail(&nrom->reseq_queue, skbn);
249 			}
250 		} while (save_vr != nrom->vr);
251 		/*
252 		 * Window is full, ack it immediately.
253 		 */
254 		if (((nrom->vl + nrom->window) % NR_MODULUS) == nrom->vr) {
255 			nr_enquiry_response(sk);
256 		} else {
257 			if (!(nrom->condition & NR_COND_ACK_PENDING)) {
258 				nrom->condition |= NR_COND_ACK_PENDING;
259 				nr_start_t2timer(sk);
260 			}
261 		}
262 		break;
263 
264 	case NR_RESET:
265 		if (READ_ONCE(sysctl_netrom_reset_circuit))
266 			nr_disconnect(sk, ECONNRESET);
267 		break;
268 
269 	default:
270 		break;
271 	}
272 	return queued;
273 }
274 
275 /* Higher level upcall for a LAPB frame - called with sk locked */
276 int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
277 {
278 	struct nr_sock *nr = nr_sk(sk);
279 	int queued = 0, frametype;
280 
281 	if (nr->state == NR_STATE_0)
282 		return 0;
283 
284 	frametype = skb->data[19];
285 
286 	switch (nr->state) {
287 	case NR_STATE_1:
288 		queued = nr_state1_machine(sk, skb, frametype);
289 		break;
290 	case NR_STATE_2:
291 		queued = nr_state2_machine(sk, skb, frametype);
292 		break;
293 	case NR_STATE_3:
294 		queued = nr_state3_machine(sk, skb, frametype);
295 		break;
296 	}
297 
298 	nr_kick(sk);
299 
300 	return queued;
301 }
302