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