Root/
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 (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) |
8 | * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) |
9 | * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) |
10 | * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de) |
11 | * |
12 | * Most of this code is based on the SDL diagrams published in the 7th ARRL |
13 | * Computer Networking Conference papers. The diagrams have mistakes in them, |
14 | * but are mostly correct. Before you modify the code could you read the SDL |
15 | * diagrams as the code is not obvious and probably very easy to break. |
16 | */ |
17 | #include <linux/errno.h> |
18 | #include <linux/types.h> |
19 | #include <linux/socket.h> |
20 | #include <linux/in.h> |
21 | #include <linux/kernel.h> |
22 | #include <linux/timer.h> |
23 | #include <linux/string.h> |
24 | #include <linux/sockios.h> |
25 | #include <linux/net.h> |
26 | #include <net/ax25.h> |
27 | #include <linux/inet.h> |
28 | #include <linux/netdevice.h> |
29 | #include <linux/skbuff.h> |
30 | #include <net/sock.h> |
31 | #include <net/tcp_states.h> |
32 | #include <asm/uaccess.h> |
33 | #include <asm/system.h> |
34 | #include <linux/fcntl.h> |
35 | #include <linux/mm.h> |
36 | #include <linux/interrupt.h> |
37 | |
38 | /* |
39 | * State machine for state 1, Awaiting Connection State. |
40 | * The handling of the timer(s) is in file ax25_std_timer.c. |
41 | * Handling of state 0 and connection release is in ax25.c. |
42 | */ |
43 | static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) |
44 | { |
45 | switch (frametype) { |
46 | case AX25_SABM: |
47 | ax25->modulus = AX25_MODULUS; |
48 | ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; |
49 | ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); |
50 | break; |
51 | |
52 | case AX25_SABME: |
53 | ax25->modulus = AX25_EMODULUS; |
54 | ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; |
55 | ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); |
56 | break; |
57 | |
58 | case AX25_DISC: |
59 | ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); |
60 | break; |
61 | |
62 | case AX25_UA: |
63 | if (pf) { |
64 | ax25_calculate_rtt(ax25); |
65 | ax25_stop_t1timer(ax25); |
66 | ax25_start_t3timer(ax25); |
67 | ax25_start_idletimer(ax25); |
68 | ax25->vs = 0; |
69 | ax25->va = 0; |
70 | ax25->vr = 0; |
71 | ax25->state = AX25_STATE_3; |
72 | ax25->n2count = 0; |
73 | if (ax25->sk != NULL) { |
74 | bh_lock_sock(ax25->sk); |
75 | ax25->sk->sk_state = TCP_ESTABLISHED; |
76 | /* For WAIT_SABM connections we will produce an accept ready socket here */ |
77 | if (!sock_flag(ax25->sk, SOCK_DEAD)) |
78 | ax25->sk->sk_state_change(ax25->sk); |
79 | bh_unlock_sock(ax25->sk); |
80 | } |
81 | } |
82 | break; |
83 | |
84 | case AX25_DM: |
85 | if (pf) { |
86 | if (ax25->modulus == AX25_MODULUS) { |
87 | ax25_disconnect(ax25, ECONNREFUSED); |
88 | } else { |
89 | ax25->modulus = AX25_MODULUS; |
90 | ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; |
91 | } |
92 | } |
93 | break; |
94 | |
95 | default: |
96 | break; |
97 | } |
98 | |
99 | return 0; |
100 | } |
101 | |
102 | /* |
103 | * State machine for state 2, Awaiting Release State. |
104 | * The handling of the timer(s) is in file ax25_std_timer.c |
105 | * Handling of state 0 and connection release is in ax25.c. |
106 | */ |
107 | static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) |
108 | { |
109 | switch (frametype) { |
110 | case AX25_SABM: |
111 | case AX25_SABME: |
112 | ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); |
113 | break; |
114 | |
115 | case AX25_DISC: |
116 | ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); |
117 | ax25_disconnect(ax25, 0); |
118 | break; |
119 | |
120 | case AX25_DM: |
121 | case AX25_UA: |
122 | if (pf) |
123 | ax25_disconnect(ax25, 0); |
124 | break; |
125 | |
126 | case AX25_I: |
127 | case AX25_REJ: |
128 | case AX25_RNR: |
129 | case AX25_RR: |
130 | if (pf) ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); |
131 | break; |
132 | |
133 | default: |
134 | break; |
135 | } |
136 | |
137 | return 0; |
138 | } |
139 | |
140 | /* |
141 | * State machine for state 3, Connected State. |
142 | * The handling of the timer(s) is in file ax25_std_timer.c |
143 | * Handling of state 0 and connection release is in ax25.c. |
144 | */ |
145 | static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type) |
146 | { |
147 | int queued = 0; |
148 | |
149 | switch (frametype) { |
150 | case AX25_SABM: |
151 | case AX25_SABME: |
152 | if (frametype == AX25_SABM) { |
153 | ax25->modulus = AX25_MODULUS; |
154 | ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; |
155 | } else { |
156 | ax25->modulus = AX25_EMODULUS; |
157 | ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; |
158 | } |
159 | ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); |
160 | ax25_stop_t1timer(ax25); |
161 | ax25_stop_t2timer(ax25); |
162 | ax25_start_t3timer(ax25); |
163 | ax25_start_idletimer(ax25); |
164 | ax25->condition = 0x00; |
165 | ax25->vs = 0; |
166 | ax25->va = 0; |
167 | ax25->vr = 0; |
168 | ax25_requeue_frames(ax25); |
169 | break; |
170 | |
171 | case AX25_DISC: |
172 | ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); |
173 | ax25_disconnect(ax25, 0); |
174 | break; |
175 | |
176 | case AX25_DM: |
177 | ax25_disconnect(ax25, ECONNRESET); |
178 | break; |
179 | |
180 | case AX25_RR: |
181 | case AX25_RNR: |
182 | if (frametype == AX25_RR) |
183 | ax25->condition &= ~AX25_COND_PEER_RX_BUSY; |
184 | else |
185 | ax25->condition |= AX25_COND_PEER_RX_BUSY; |
186 | if (type == AX25_COMMAND && pf) |
187 | ax25_std_enquiry_response(ax25); |
188 | if (ax25_validate_nr(ax25, nr)) { |
189 | ax25_check_iframes_acked(ax25, nr); |
190 | } else { |
191 | ax25_std_nr_error_recovery(ax25); |
192 | ax25->state = AX25_STATE_1; |
193 | } |
194 | break; |
195 | |
196 | case AX25_REJ: |
197 | ax25->condition &= ~AX25_COND_PEER_RX_BUSY; |
198 | if (type == AX25_COMMAND && pf) |
199 | ax25_std_enquiry_response(ax25); |
200 | if (ax25_validate_nr(ax25, nr)) { |
201 | ax25_frames_acked(ax25, nr); |
202 | ax25_calculate_rtt(ax25); |
203 | ax25_stop_t1timer(ax25); |
204 | ax25_start_t3timer(ax25); |
205 | ax25_requeue_frames(ax25); |
206 | } else { |
207 | ax25_std_nr_error_recovery(ax25); |
208 | ax25->state = AX25_STATE_1; |
209 | } |
210 | break; |
211 | |
212 | case AX25_I: |
213 | if (!ax25_validate_nr(ax25, nr)) { |
214 | ax25_std_nr_error_recovery(ax25); |
215 | ax25->state = AX25_STATE_1; |
216 | break; |
217 | } |
218 | if (ax25->condition & AX25_COND_PEER_RX_BUSY) { |
219 | ax25_frames_acked(ax25, nr); |
220 | } else { |
221 | ax25_check_iframes_acked(ax25, nr); |
222 | } |
223 | if (ax25->condition & AX25_COND_OWN_RX_BUSY) { |
224 | if (pf) ax25_std_enquiry_response(ax25); |
225 | break; |
226 | } |
227 | if (ns == ax25->vr) { |
228 | ax25->vr = (ax25->vr + 1) % ax25->modulus; |
229 | queued = ax25_rx_iframe(ax25, skb); |
230 | if (ax25->condition & AX25_COND_OWN_RX_BUSY) |
231 | ax25->vr = ns; /* ax25->vr - 1 */ |
232 | ax25->condition &= ~AX25_COND_REJECT; |
233 | if (pf) { |
234 | ax25_std_enquiry_response(ax25); |
235 | } else { |
236 | if (!(ax25->condition & AX25_COND_ACK_PENDING)) { |
237 | ax25->condition |= AX25_COND_ACK_PENDING; |
238 | ax25_start_t2timer(ax25); |
239 | } |
240 | } |
241 | } else { |
242 | if (ax25->condition & AX25_COND_REJECT) { |
243 | if (pf) ax25_std_enquiry_response(ax25); |
244 | } else { |
245 | ax25->condition |= AX25_COND_REJECT; |
246 | ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE); |
247 | ax25->condition &= ~AX25_COND_ACK_PENDING; |
248 | } |
249 | } |
250 | break; |
251 | |
252 | case AX25_FRMR: |
253 | case AX25_ILLEGAL: |
254 | ax25_std_establish_data_link(ax25); |
255 | ax25->state = AX25_STATE_1; |
256 | break; |
257 | |
258 | default: |
259 | break; |
260 | } |
261 | |
262 | return queued; |
263 | } |
264 | |
265 | /* |
266 | * State machine for state 4, Timer Recovery State. |
267 | * The handling of the timer(s) is in file ax25_std_timer.c |
268 | * Handling of state 0 and connection release is in ax25.c. |
269 | */ |
270 | static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type) |
271 | { |
272 | int queued = 0; |
273 | |
274 | switch (frametype) { |
275 | case AX25_SABM: |
276 | case AX25_SABME: |
277 | if (frametype == AX25_SABM) { |
278 | ax25->modulus = AX25_MODULUS; |
279 | ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; |
280 | } else { |
281 | ax25->modulus = AX25_EMODULUS; |
282 | ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; |
283 | } |
284 | ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); |
285 | ax25_stop_t1timer(ax25); |
286 | ax25_stop_t2timer(ax25); |
287 | ax25_start_t3timer(ax25); |
288 | ax25_start_idletimer(ax25); |
289 | ax25->condition = 0x00; |
290 | ax25->vs = 0; |
291 | ax25->va = 0; |
292 | ax25->vr = 0; |
293 | ax25->state = AX25_STATE_3; |
294 | ax25->n2count = 0; |
295 | ax25_requeue_frames(ax25); |
296 | break; |
297 | |
298 | case AX25_DISC: |
299 | ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); |
300 | ax25_disconnect(ax25, 0); |
301 | break; |
302 | |
303 | case AX25_DM: |
304 | ax25_disconnect(ax25, ECONNRESET); |
305 | break; |
306 | |
307 | case AX25_RR: |
308 | case AX25_RNR: |
309 | if (frametype == AX25_RR) |
310 | ax25->condition &= ~AX25_COND_PEER_RX_BUSY; |
311 | else |
312 | ax25->condition |= AX25_COND_PEER_RX_BUSY; |
313 | if (type == AX25_RESPONSE && pf) { |
314 | ax25_stop_t1timer(ax25); |
315 | ax25->n2count = 0; |
316 | if (ax25_validate_nr(ax25, nr)) { |
317 | ax25_frames_acked(ax25, nr); |
318 | if (ax25->vs == ax25->va) { |
319 | ax25_start_t3timer(ax25); |
320 | ax25->state = AX25_STATE_3; |
321 | } else { |
322 | ax25_requeue_frames(ax25); |
323 | } |
324 | } else { |
325 | ax25_std_nr_error_recovery(ax25); |
326 | ax25->state = AX25_STATE_1; |
327 | } |
328 | break; |
329 | } |
330 | if (type == AX25_COMMAND && pf) |
331 | ax25_std_enquiry_response(ax25); |
332 | if (ax25_validate_nr(ax25, nr)) { |
333 | ax25_frames_acked(ax25, nr); |
334 | } else { |
335 | ax25_std_nr_error_recovery(ax25); |
336 | ax25->state = AX25_STATE_1; |
337 | } |
338 | break; |
339 | |
340 | case AX25_REJ: |
341 | ax25->condition &= ~AX25_COND_PEER_RX_BUSY; |
342 | if (pf && type == AX25_RESPONSE) { |
343 | ax25_stop_t1timer(ax25); |
344 | ax25->n2count = 0; |
345 | if (ax25_validate_nr(ax25, nr)) { |
346 | ax25_frames_acked(ax25, nr); |
347 | if (ax25->vs == ax25->va) { |
348 | ax25_start_t3timer(ax25); |
349 | ax25->state = AX25_STATE_3; |
350 | } else { |
351 | ax25_requeue_frames(ax25); |
352 | } |
353 | } else { |
354 | ax25_std_nr_error_recovery(ax25); |
355 | ax25->state = AX25_STATE_1; |
356 | } |
357 | break; |
358 | } |
359 | if (type == AX25_COMMAND && pf) |
360 | ax25_std_enquiry_response(ax25); |
361 | if (ax25_validate_nr(ax25, nr)) { |
362 | ax25_frames_acked(ax25, nr); |
363 | ax25_requeue_frames(ax25); |
364 | } else { |
365 | ax25_std_nr_error_recovery(ax25); |
366 | ax25->state = AX25_STATE_1; |
367 | } |
368 | break; |
369 | |
370 | case AX25_I: |
371 | if (!ax25_validate_nr(ax25, nr)) { |
372 | ax25_std_nr_error_recovery(ax25); |
373 | ax25->state = AX25_STATE_1; |
374 | break; |
375 | } |
376 | ax25_frames_acked(ax25, nr); |
377 | if (ax25->condition & AX25_COND_OWN_RX_BUSY) { |
378 | if (pf) |
379 | ax25_std_enquiry_response(ax25); |
380 | break; |
381 | } |
382 | if (ns == ax25->vr) { |
383 | ax25->vr = (ax25->vr + 1) % ax25->modulus; |
384 | queued = ax25_rx_iframe(ax25, skb); |
385 | if (ax25->condition & AX25_COND_OWN_RX_BUSY) |
386 | ax25->vr = ns; /* ax25->vr - 1 */ |
387 | ax25->condition &= ~AX25_COND_REJECT; |
388 | if (pf) { |
389 | ax25_std_enquiry_response(ax25); |
390 | } else { |
391 | if (!(ax25->condition & AX25_COND_ACK_PENDING)) { |
392 | ax25->condition |= AX25_COND_ACK_PENDING; |
393 | ax25_start_t2timer(ax25); |
394 | } |
395 | } |
396 | } else { |
397 | if (ax25->condition & AX25_COND_REJECT) { |
398 | if (pf) ax25_std_enquiry_response(ax25); |
399 | } else { |
400 | ax25->condition |= AX25_COND_REJECT; |
401 | ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE); |
402 | ax25->condition &= ~AX25_COND_ACK_PENDING; |
403 | } |
404 | } |
405 | break; |
406 | |
407 | case AX25_FRMR: |
408 | case AX25_ILLEGAL: |
409 | ax25_std_establish_data_link(ax25); |
410 | ax25->state = AX25_STATE_1; |
411 | break; |
412 | |
413 | default: |
414 | break; |
415 | } |
416 | |
417 | return queued; |
418 | } |
419 | |
420 | /* |
421 | * Higher level upcall for a LAPB frame |
422 | */ |
423 | int ax25_std_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type) |
424 | { |
425 | int queued = 0, frametype, ns, nr, pf; |
426 | |
427 | frametype = ax25_decode(ax25, skb, &ns, &nr, &pf); |
428 | |
429 | switch (ax25->state) { |
430 | case AX25_STATE_1: |
431 | queued = ax25_std_state1_machine(ax25, skb, frametype, pf, type); |
432 | break; |
433 | case AX25_STATE_2: |
434 | queued = ax25_std_state2_machine(ax25, skb, frametype, pf, type); |
435 | break; |
436 | case AX25_STATE_3: |
437 | queued = ax25_std_state3_machine(ax25, skb, frametype, ns, nr, pf, type); |
438 | break; |
439 | case AX25_STATE_4: |
440 | queued = ax25_std_state4_machine(ax25, skb, frametype, ns, nr, pf, type); |
441 | break; |
442 | } |
443 | |
444 | ax25_kick(ax25); |
445 | |
446 | return queued; |
447 | } |
448 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9