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(list: &nr->frag_queue, newsk: skb); |
41 | return 0; |
42 | } |
43 | |
44 | if (!more && nr->fraglen > 0) { /* End of fragment */ |
45 | nr->fraglen += skb->len; |
46 | skb_queue_tail(list: &nr->frag_queue, newsk: skb); |
47 | |
48 | if ((skbn = alloc_skb(size: nr->fraglen, GFP_ATOMIC)) == NULL) |
49 | return 1; |
50 | |
51 | skb_reset_transport_header(skb: skbn); |
52 | |
53 | while ((skbo = skb_dequeue(list: &nr->frag_queue)) != NULL) { |
54 | skb_copy_from_linear_data(skb: skbo, |
55 | to: skb_put(skb: skbn, len: skbo->len), |
56 | len: skbo->len); |
57 | kfree_skb(skb: skbo); |
58 | } |
59 | |
60 | nr->fraglen = 0; |
61 | } |
62 | |
63 | return sock_queue_rcv_skb(sk, skb: 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, flag: 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 | fallthrough; |
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 | |
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(list: &nrom->reseq_queue, newsk: skb); |
227 | if (nrom->condition & NR_COND_OWN_RX_BUSY) |
228 | break; |
229 | skb_queue_head_init(list: &temp_queue); |
230 | do { |
231 | save_vr = nrom->vr; |
232 | while ((skbn = skb_dequeue(list: &nrom->reseq_queue)) != NULL) { |
233 | ns = skbn->data[17]; |
234 | if (ns == nrom->vr) { |
235 | if (nr_queue_rx_frame(sk, skb: skbn, more: 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(list: &temp_queue, newsk: skbn); |
240 | } |
241 | } else if (nr_in_rx_window(sk, ns)) { |
242 | skb_queue_tail(list: &temp_queue, newsk: skbn); |
243 | } else { |
244 | kfree_skb(skb: skbn); |
245 | } |
246 | } |
247 | while ((skbn = skb_dequeue(list: &temp_queue)) != NULL) { |
248 | skb_queue_tail(list: &nrom->reseq_queue, newsk: 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 (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 | |