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) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) |
8 | * |
9 | * Most of this code is based on the SDL diagrams published in the 7th ARRL |
10 | * Computer Networking Conference papers. The diagrams have mistakes in them, |
11 | * but are mostly correct. Before you modify the code could you read the SDL |
12 | * diagrams as the code is not obvious and probably very easy to break. |
13 | */ |
14 | #include <linux/errno.h> |
15 | #include <linux/types.h> |
16 | #include <linux/socket.h> |
17 | #include <linux/in.h> |
18 | #include <linux/kernel.h> |
19 | #include <linux/timer.h> |
20 | #include <linux/string.h> |
21 | #include <linux/sockios.h> |
22 | #include <linux/net.h> |
23 | #include <net/ax25.h> |
24 | #include <linux/inet.h> |
25 | #include <linux/netdevice.h> |
26 | #include <linux/skbuff.h> |
27 | #include <net/sock.h> |
28 | #include <net/tcp_states.h> |
29 | #include <asm/system.h> |
30 | #include <linux/fcntl.h> |
31 | #include <linux/mm.h> |
32 | #include <linux/interrupt.h> |
33 | #include <net/rose.h> |
34 | |
35 | /* |
36 | * State machine for state 1, Awaiting Call Accepted State. |
37 | * The handling of the timer(s) is in file rose_timer.c. |
38 | * Handling of state 0 and connection release is in af_rose.c. |
39 | */ |
40 | static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) |
41 | { |
42 | struct rose_sock *rose = rose_sk(sk); |
43 | |
44 | switch (frametype) { |
45 | case ROSE_CALL_ACCEPTED: |
46 | rose_stop_timer(sk); |
47 | rose_start_idletimer(sk); |
48 | rose->condition = 0x00; |
49 | rose->vs = 0; |
50 | rose->va = 0; |
51 | rose->vr = 0; |
52 | rose->vl = 0; |
53 | rose->state = ROSE_STATE_3; |
54 | sk->sk_state = TCP_ESTABLISHED; |
55 | if (!sock_flag(sk, SOCK_DEAD)) |
56 | sk->sk_state_change(sk); |
57 | break; |
58 | |
59 | case ROSE_CLEAR_REQUEST: |
60 | rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); |
61 | rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); |
62 | rose->neighbour->use--; |
63 | break; |
64 | |
65 | default: |
66 | break; |
67 | } |
68 | |
69 | return 0; |
70 | } |
71 | |
72 | /* |
73 | * State machine for state 2, Awaiting Clear Confirmation State. |
74 | * The handling of the timer(s) is in file rose_timer.c |
75 | * Handling of state 0 and connection release is in af_rose.c. |
76 | */ |
77 | static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype) |
78 | { |
79 | struct rose_sock *rose = rose_sk(sk); |
80 | |
81 | switch (frametype) { |
82 | case ROSE_CLEAR_REQUEST: |
83 | rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); |
84 | rose_disconnect(sk, 0, skb->data[3], skb->data[4]); |
85 | rose->neighbour->use--; |
86 | break; |
87 | |
88 | case ROSE_CLEAR_CONFIRMATION: |
89 | rose_disconnect(sk, 0, -1, -1); |
90 | rose->neighbour->use--; |
91 | break; |
92 | |
93 | default: |
94 | break; |
95 | } |
96 | |
97 | return 0; |
98 | } |
99 | |
100 | /* |
101 | * State machine for state 3, Connected State. |
102 | * The handling of the timer(s) is in file rose_timer.c |
103 | * Handling of state 0 and connection release is in af_rose.c. |
104 | */ |
105 | static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m) |
106 | { |
107 | struct rose_sock *rose = rose_sk(sk); |
108 | int queued = 0; |
109 | |
110 | switch (frametype) { |
111 | case ROSE_RESET_REQUEST: |
112 | rose_stop_timer(sk); |
113 | rose_start_idletimer(sk); |
114 | rose_write_internal(sk, ROSE_RESET_CONFIRMATION); |
115 | rose->condition = 0x00; |
116 | rose->vs = 0; |
117 | rose->vr = 0; |
118 | rose->va = 0; |
119 | rose->vl = 0; |
120 | rose_requeue_frames(sk); |
121 | break; |
122 | |
123 | case ROSE_CLEAR_REQUEST: |
124 | rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); |
125 | rose_disconnect(sk, 0, skb->data[3], skb->data[4]); |
126 | rose->neighbour->use--; |
127 | break; |
128 | |
129 | case ROSE_RR: |
130 | case ROSE_RNR: |
131 | if (!rose_validate_nr(sk, nr)) { |
132 | rose_write_internal(sk, ROSE_RESET_REQUEST); |
133 | rose->condition = 0x00; |
134 | rose->vs = 0; |
135 | rose->vr = 0; |
136 | rose->va = 0; |
137 | rose->vl = 0; |
138 | rose->state = ROSE_STATE_4; |
139 | rose_start_t2timer(sk); |
140 | rose_stop_idletimer(sk); |
141 | } else { |
142 | rose_frames_acked(sk, nr); |
143 | if (frametype == ROSE_RNR) { |
144 | rose->condition |= ROSE_COND_PEER_RX_BUSY; |
145 | } else { |
146 | rose->condition &= ~ROSE_COND_PEER_RX_BUSY; |
147 | } |
148 | } |
149 | break; |
150 | |
151 | case ROSE_DATA: /* XXX */ |
152 | rose->condition &= ~ROSE_COND_PEER_RX_BUSY; |
153 | if (!rose_validate_nr(sk, nr)) { |
154 | rose_write_internal(sk, ROSE_RESET_REQUEST); |
155 | rose->condition = 0x00; |
156 | rose->vs = 0; |
157 | rose->vr = 0; |
158 | rose->va = 0; |
159 | rose->vl = 0; |
160 | rose->state = ROSE_STATE_4; |
161 | rose_start_t2timer(sk); |
162 | rose_stop_idletimer(sk); |
163 | break; |
164 | } |
165 | rose_frames_acked(sk, nr); |
166 | if (ns == rose->vr) { |
167 | rose_start_idletimer(sk); |
168 | if (sock_queue_rcv_skb(sk, skb) == 0) { |
169 | rose->vr = (rose->vr + 1) % ROSE_MODULUS; |
170 | queued = 1; |
171 | } else { |
172 | /* Should never happen ! */ |
173 | rose_write_internal(sk, ROSE_RESET_REQUEST); |
174 | rose->condition = 0x00; |
175 | rose->vs = 0; |
176 | rose->vr = 0; |
177 | rose->va = 0; |
178 | rose->vl = 0; |
179 | rose->state = ROSE_STATE_4; |
180 | rose_start_t2timer(sk); |
181 | rose_stop_idletimer(sk); |
182 | break; |
183 | } |
184 | if (atomic_read(&sk->sk_rmem_alloc) > |
185 | (sk->sk_rcvbuf >> 1)) |
186 | rose->condition |= ROSE_COND_OWN_RX_BUSY; |
187 | } |
188 | /* |
189 | * If the window is full, ack the frame, else start the |
190 | * acknowledge hold back timer. |
191 | */ |
192 | if (((rose->vl + sysctl_rose_window_size) % ROSE_MODULUS) == rose->vr) { |
193 | rose->condition &= ~ROSE_COND_ACK_PENDING; |
194 | rose_stop_timer(sk); |
195 | rose_enquiry_response(sk); |
196 | } else { |
197 | rose->condition |= ROSE_COND_ACK_PENDING; |
198 | rose_start_hbtimer(sk); |
199 | } |
200 | break; |
201 | |
202 | default: |
203 | printk(KERN_WARNING "ROSE: unknown %02X in state 3\n", frametype); |
204 | break; |
205 | } |
206 | |
207 | return queued; |
208 | } |
209 | |
210 | /* |
211 | * State machine for state 4, Awaiting Reset Confirmation State. |
212 | * The handling of the timer(s) is in file rose_timer.c |
213 | * Handling of state 0 and connection release is in af_rose.c. |
214 | */ |
215 | static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype) |
216 | { |
217 | struct rose_sock *rose = rose_sk(sk); |
218 | |
219 | switch (frametype) { |
220 | case ROSE_RESET_REQUEST: |
221 | rose_write_internal(sk, ROSE_RESET_CONFIRMATION); |
222 | case ROSE_RESET_CONFIRMATION: |
223 | rose_stop_timer(sk); |
224 | rose_start_idletimer(sk); |
225 | rose->condition = 0x00; |
226 | rose->va = 0; |
227 | rose->vr = 0; |
228 | rose->vs = 0; |
229 | rose->vl = 0; |
230 | rose->state = ROSE_STATE_3; |
231 | rose_requeue_frames(sk); |
232 | break; |
233 | |
234 | case ROSE_CLEAR_REQUEST: |
235 | rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); |
236 | rose_disconnect(sk, 0, skb->data[3], skb->data[4]); |
237 | rose->neighbour->use--; |
238 | break; |
239 | |
240 | default: |
241 | break; |
242 | } |
243 | |
244 | return 0; |
245 | } |
246 | |
247 | /* |
248 | * State machine for state 5, Awaiting Call Acceptance State. |
249 | * The handling of the timer(s) is in file rose_timer.c |
250 | * Handling of state 0 and connection release is in af_rose.c. |
251 | */ |
252 | static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype) |
253 | { |
254 | if (frametype == ROSE_CLEAR_REQUEST) { |
255 | rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); |
256 | rose_disconnect(sk, 0, skb->data[3], skb->data[4]); |
257 | rose_sk(sk)->neighbour->use--; |
258 | } |
259 | |
260 | return 0; |
261 | } |
262 | |
263 | /* Higher level upcall for a LAPB frame */ |
264 | int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb) |
265 | { |
266 | struct rose_sock *rose = rose_sk(sk); |
267 | int queued = 0, frametype, ns, nr, q, d, m; |
268 | |
269 | if (rose->state == ROSE_STATE_0) |
270 | return 0; |
271 | |
272 | frametype = rose_decode(skb, &ns, &nr, &q, &d, &m); |
273 | |
274 | switch (rose->state) { |
275 | case ROSE_STATE_1: |
276 | queued = rose_state1_machine(sk, skb, frametype); |
277 | break; |
278 | case ROSE_STATE_2: |
279 | queued = rose_state2_machine(sk, skb, frametype); |
280 | break; |
281 | case ROSE_STATE_3: |
282 | queued = rose_state3_machine(sk, skb, frametype, ns, nr, q, d, m); |
283 | break; |
284 | case ROSE_STATE_4: |
285 | queued = rose_state4_machine(sk, skb, frametype); |
286 | break; |
287 | case ROSE_STATE_5: |
288 | queued = rose_state5_machine(sk, skb, frametype); |
289 | break; |
290 | } |
291 | |
292 | rose_kick(sk); |
293 | |
294 | return queued; |
295 | } |
296 |
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