aboutsummaryrefslogtreecommitdiffstats
path: root/net/lapb
diff options
context:
space:
mode:
Diffstat (limited to 'net/lapb')
-rw-r--r--net/lapb/Makefile7
-rw-r--r--net/lapb/lapb_iface.c449
-rw-r--r--net/lapb/lapb_in.c724
-rw-r--r--net/lapb/lapb_out.c224
-rw-r--r--net/lapb/lapb_subr.c313
-rw-r--r--net/lapb/lapb_timer.c189
6 files changed, 1906 insertions, 0 deletions
diff --git a/net/lapb/Makefile b/net/lapb/Makefile
new file mode 100644
index 000000000000..53f7c90db163
--- /dev/null
+++ b/net/lapb/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the Linux LAPB layer.
3#
4
5obj-$(CONFIG_LAPB) += lapb.o
6
7lapb-objs := lapb_in.o lapb_out.o lapb_subr.o lapb_timer.o lapb_iface.o
diff --git a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c
new file mode 100644
index 000000000000..aea6616cea3d
--- /dev/null
+++ b/net/lapb/lapb_iface.c
@@ -0,0 +1,449 @@
1/*
2 * LAPB release 002
3 *
4 * This code REQUIRES 2.1.15 or higher/ NET3.038
5 *
6 * This module:
7 * This module is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * History
13 * LAPB 001 Jonathan Naylor Started Coding
14 * LAPB 002 Jonathan Naylor New timer architecture.
15 * 2000-10-29 Henner Eisen lapb_data_indication() return status.
16 */
17
18#include <linux/module.h>
19#include <linux/errno.h>
20#include <linux/types.h>
21#include <linux/socket.h>
22#include <linux/in.h>
23#include <linux/kernel.h>
24#include <linux/jiffies.h>
25#include <linux/timer.h>
26#include <linux/string.h>
27#include <linux/sockios.h>
28#include <linux/net.h>
29#include <linux/inet.h>
30#include <linux/if_arp.h>
31#include <linux/skbuff.h>
32#include <net/sock.h>
33#include <asm/uaccess.h>
34#include <asm/system.h>
35#include <linux/fcntl.h>
36#include <linux/mm.h>
37#include <linux/interrupt.h>
38#include <linux/stat.h>
39#include <linux/init.h>
40#include <net/lapb.h>
41
42static struct list_head lapb_list = LIST_HEAD_INIT(lapb_list);
43static DEFINE_RWLOCK(lapb_list_lock);
44
45/*
46 * Free an allocated lapb control block.
47 */
48static void lapb_free_cb(struct lapb_cb *lapb)
49{
50 kfree(lapb);
51}
52
53static __inline__ void lapb_hold(struct lapb_cb *lapb)
54{
55 atomic_inc(&lapb->refcnt);
56}
57
58static __inline__ void lapb_put(struct lapb_cb *lapb)
59{
60 if (atomic_dec_and_test(&lapb->refcnt))
61 lapb_free_cb(lapb);
62}
63
64/*
65 * Socket removal during an interrupt is now safe.
66 */
67static void __lapb_remove_cb(struct lapb_cb *lapb)
68{
69 if (lapb->node.next) {
70 list_del(&lapb->node);
71 lapb_put(lapb);
72 }
73}
74
75/*
76 * Add a socket to the bound sockets list.
77 */
78static void __lapb_insert_cb(struct lapb_cb *lapb)
79{
80 list_add(&lapb->node, &lapb_list);
81 lapb_hold(lapb);
82}
83
84static struct lapb_cb *__lapb_devtostruct(struct net_device *dev)
85{
86 struct list_head *entry;
87 struct lapb_cb *lapb, *use = NULL;
88
89 list_for_each(entry, &lapb_list) {
90 lapb = list_entry(entry, struct lapb_cb, node);
91 if (lapb->dev == dev) {
92 use = lapb;
93 break;
94 }
95 }
96
97 if (use)
98 lapb_hold(use);
99
100 return use;
101}
102
103static struct lapb_cb *lapb_devtostruct(struct net_device *dev)
104{
105 struct lapb_cb *rc;
106
107 read_lock_bh(&lapb_list_lock);
108 rc = __lapb_devtostruct(dev);
109 read_unlock_bh(&lapb_list_lock);
110
111 return rc;
112}
113/*
114 * Create an empty LAPB control block.
115 */
116static struct lapb_cb *lapb_create_cb(void)
117{
118 struct lapb_cb *lapb = kmalloc(sizeof(*lapb), GFP_ATOMIC);
119
120
121 if (!lapb)
122 goto out;
123
124 memset(lapb, 0x00, sizeof(*lapb));
125
126 skb_queue_head_init(&lapb->write_queue);
127 skb_queue_head_init(&lapb->ack_queue);
128
129 init_timer(&lapb->t1timer);
130 init_timer(&lapb->t2timer);
131
132 lapb->t1 = LAPB_DEFAULT_T1;
133 lapb->t2 = LAPB_DEFAULT_T2;
134 lapb->n2 = LAPB_DEFAULT_N2;
135 lapb->mode = LAPB_DEFAULT_MODE;
136 lapb->window = LAPB_DEFAULT_WINDOW;
137 lapb->state = LAPB_STATE_0;
138 atomic_set(&lapb->refcnt, 1);
139out:
140 return lapb;
141}
142
143int lapb_register(struct net_device *dev, struct lapb_register_struct *callbacks)
144{
145 struct lapb_cb *lapb;
146 int rc = LAPB_BADTOKEN;
147
148 write_lock_bh(&lapb_list_lock);
149
150 lapb = __lapb_devtostruct(dev);
151 if (lapb) {
152 lapb_put(lapb);
153 goto out;
154 }
155
156 lapb = lapb_create_cb();
157 rc = LAPB_NOMEM;
158 if (!lapb)
159 goto out;
160
161 lapb->dev = dev;
162 lapb->callbacks = *callbacks;
163
164 __lapb_insert_cb(lapb);
165
166 lapb_start_t1timer(lapb);
167
168 rc = LAPB_OK;
169out:
170 write_unlock_bh(&lapb_list_lock);
171 return rc;
172}
173
174int lapb_unregister(struct net_device *dev)
175{
176 struct lapb_cb *lapb;
177 int rc = LAPB_BADTOKEN;
178
179 write_lock_bh(&lapb_list_lock);
180 lapb = __lapb_devtostruct(dev);
181 if (!lapb)
182 goto out;
183
184 lapb_stop_t1timer(lapb);
185 lapb_stop_t2timer(lapb);
186
187 lapb_clear_queues(lapb);
188
189 __lapb_remove_cb(lapb);
190
191 lapb_put(lapb);
192 rc = LAPB_OK;
193out:
194 write_unlock_bh(&lapb_list_lock);
195 return rc;
196}
197
198int lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms)
199{
200 int rc = LAPB_BADTOKEN;
201 struct lapb_cb *lapb = lapb_devtostruct(dev);
202
203 if (!lapb)
204 goto out;
205
206 parms->t1 = lapb->t1 / HZ;
207 parms->t2 = lapb->t2 / HZ;
208 parms->n2 = lapb->n2;
209 parms->n2count = lapb->n2count;
210 parms->state = lapb->state;
211 parms->window = lapb->window;
212 parms->mode = lapb->mode;
213
214 if (!timer_pending(&lapb->t1timer))
215 parms->t1timer = 0;
216 else
217 parms->t1timer = (lapb->t1timer.expires - jiffies) / HZ;
218
219 if (!timer_pending(&lapb->t2timer))
220 parms->t2timer = 0;
221 else
222 parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ;
223
224 lapb_put(lapb);
225 rc = LAPB_OK;
226out:
227 return rc;
228}
229
230int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms)
231{
232 int rc = LAPB_BADTOKEN;
233 struct lapb_cb *lapb = lapb_devtostruct(dev);
234
235 if (!lapb)
236 goto out;
237
238 rc = LAPB_INVALUE;
239 if (parms->t1 < 1 || parms->t2 < 1 || parms->n2 < 1)
240 goto out_put;
241
242 if (lapb->state == LAPB_STATE_0) {
243 if (((parms->mode & LAPB_EXTENDED) &&
244 (parms->window < 1 || parms->window > 127)) ||
245 (parms->window < 1 || parms->window > 7))
246 goto out_put;
247
248 lapb->mode = parms->mode;
249 lapb->window = parms->window;
250 }
251
252 lapb->t1 = parms->t1 * HZ;
253 lapb->t2 = parms->t2 * HZ;
254 lapb->n2 = parms->n2;
255
256 rc = LAPB_OK;
257out_put:
258 lapb_put(lapb);
259out:
260 return rc;
261}
262
263int lapb_connect_request(struct net_device *dev)
264{
265 struct lapb_cb *lapb = lapb_devtostruct(dev);
266 int rc = LAPB_BADTOKEN;
267
268 if (!lapb)
269 goto out;
270
271 rc = LAPB_OK;
272 if (lapb->state == LAPB_STATE_1)
273 goto out_put;
274
275 rc = LAPB_CONNECTED;
276 if (lapb->state == LAPB_STATE_3 || lapb->state == LAPB_STATE_4)
277 goto out_put;
278
279 lapb_establish_data_link(lapb);
280
281#if LAPB_DEBUG > 0
282 printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->dev);
283#endif
284 lapb->state = LAPB_STATE_1;
285
286 rc = LAPB_OK;
287out_put:
288 lapb_put(lapb);
289out:
290 return rc;
291}
292
293int lapb_disconnect_request(struct net_device *dev)
294{
295 struct lapb_cb *lapb = lapb_devtostruct(dev);
296 int rc = LAPB_BADTOKEN;
297
298 if (!lapb)
299 goto out;
300
301 switch (lapb->state) {
302 case LAPB_STATE_0:
303 rc = LAPB_NOTCONNECTED;
304 goto out_put;
305
306 case LAPB_STATE_1:
307#if LAPB_DEBUG > 1
308 printk(KERN_DEBUG "lapb: (%p) S1 TX DISC(1)\n", lapb->dev);
309#endif
310#if LAPB_DEBUG > 0
311 printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->dev);
312#endif
313 lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
314 lapb->state = LAPB_STATE_0;
315 lapb_start_t1timer(lapb);
316 rc = LAPB_NOTCONNECTED;
317 goto out_put;
318
319 case LAPB_STATE_2:
320 rc = LAPB_OK;
321 goto out_put;
322 }
323
324 lapb_clear_queues(lapb);
325 lapb->n2count = 0;
326 lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
327 lapb_start_t1timer(lapb);
328 lapb_stop_t2timer(lapb);
329 lapb->state = LAPB_STATE_2;
330
331#if LAPB_DEBUG > 1
332 printk(KERN_DEBUG "lapb: (%p) S3 DISC(1)\n", lapb->dev);
333#endif
334#if LAPB_DEBUG > 0
335 printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->dev);
336#endif
337
338 rc = LAPB_OK;
339out_put:
340 lapb_put(lapb);
341out:
342 return rc;
343}
344
345int lapb_data_request(struct net_device *dev, struct sk_buff *skb)
346{
347 struct lapb_cb *lapb = lapb_devtostruct(dev);
348 int rc = LAPB_BADTOKEN;
349
350 if (!lapb)
351 goto out;
352
353 rc = LAPB_NOTCONNECTED;
354 if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4)
355 goto out_put;
356
357 skb_queue_tail(&lapb->write_queue, skb);
358 lapb_kick(lapb);
359 rc = LAPB_OK;
360out_put:
361 lapb_put(lapb);
362out:
363 return rc;
364}
365
366int lapb_data_received(struct net_device *dev, struct sk_buff *skb)
367{
368 struct lapb_cb *lapb = lapb_devtostruct(dev);
369 int rc = LAPB_BADTOKEN;
370
371 if (lapb) {
372 lapb_data_input(lapb, skb);
373 lapb_put(lapb);
374 rc = LAPB_OK;
375 }
376
377 return rc;
378}
379
380void lapb_connect_confirmation(struct lapb_cb *lapb, int reason)
381{
382 if (lapb->callbacks.connect_confirmation)
383 lapb->callbacks.connect_confirmation(lapb->dev, reason);
384}
385
386void lapb_connect_indication(struct lapb_cb *lapb, int reason)
387{
388 if (lapb->callbacks.connect_indication)
389 lapb->callbacks.connect_indication(lapb->dev, reason);
390}
391
392void lapb_disconnect_confirmation(struct lapb_cb *lapb, int reason)
393{
394 if (lapb->callbacks.disconnect_confirmation)
395 lapb->callbacks.disconnect_confirmation(lapb->dev, reason);
396}
397
398void lapb_disconnect_indication(struct lapb_cb *lapb, int reason)
399{
400 if (lapb->callbacks.disconnect_indication)
401 lapb->callbacks.disconnect_indication(lapb->dev, reason);
402}
403
404int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb)
405{
406 if (lapb->callbacks.data_indication)
407 return lapb->callbacks.data_indication(lapb->dev, skb);
408
409 kfree_skb(skb);
410 return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */
411}
412
413int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb)
414{
415 int used = 0;
416
417 if (lapb->callbacks.data_transmit) {
418 lapb->callbacks.data_transmit(lapb->dev, skb);
419 used = 1;
420 }
421
422 return used;
423}
424
425EXPORT_SYMBOL(lapb_register);
426EXPORT_SYMBOL(lapb_unregister);
427EXPORT_SYMBOL(lapb_getparms);
428EXPORT_SYMBOL(lapb_setparms);
429EXPORT_SYMBOL(lapb_connect_request);
430EXPORT_SYMBOL(lapb_disconnect_request);
431EXPORT_SYMBOL(lapb_data_request);
432EXPORT_SYMBOL(lapb_data_received);
433
434static int __init lapb_init(void)
435{
436 return 0;
437}
438
439static void __exit lapb_exit(void)
440{
441 WARN_ON(!list_empty(&lapb_list));
442}
443
444MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
445MODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol");
446MODULE_LICENSE("GPL");
447
448module_init(lapb_init);
449module_exit(lapb_exit);
diff --git a/net/lapb/lapb_in.c b/net/lapb/lapb_in.c
new file mode 100644
index 000000000000..b0f8713f66ca
--- /dev/null
+++ b/net/lapb/lapb_in.c
@@ -0,0 +1,724 @@
1/*
2 * LAPB release 002
3 *
4 * This code REQUIRES 2.1.15 or higher/ NET3.038
5 *
6 * This module:
7 * This module is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * History
13 * LAPB 001 Jonathan Naulor Started Coding
14 * LAPB 002 Jonathan Naylor New timer architecture.
15 * 2000-10-29 Henner Eisen lapb_data_indication() return status.
16 */
17
18#include <linux/errno.h>
19#include <linux/types.h>
20#include <linux/socket.h>
21#include <linux/in.h>
22#include <linux/kernel.h>
23#include <linux/sched.h>
24#include <linux/timer.h>
25#include <linux/string.h>
26#include <linux/sockios.h>
27#include <linux/net.h>
28#include <linux/inet.h>
29#include <linux/netdevice.h>
30#include <linux/skbuff.h>
31#include <net/sock.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#include <net/lapb.h>
38
39/*
40 * State machine for state 0, Disconnected State.
41 * The handling of the timer(s) is in file lapb_timer.c.
42 */
43static void lapb_state0_machine(struct lapb_cb *lapb, struct sk_buff *skb,
44 struct lapb_frame *frame)
45{
46 switch (frame->type) {
47 case LAPB_SABM:
48#if LAPB_DEBUG > 1
49 printk(KERN_DEBUG "lapb: (%p) S0 RX SABM(%d)\n",
50 lapb->dev, frame->pf);
51#endif
52 if (lapb->mode & LAPB_EXTENDED) {
53#if LAPB_DEBUG > 1
54 printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n",
55 lapb->dev, frame->pf);
56#endif
57 lapb_send_control(lapb, LAPB_DM, frame->pf,
58 LAPB_RESPONSE);
59 } else {
60#if LAPB_DEBUG > 1
61 printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n",
62 lapb->dev, frame->pf);
63#endif
64#if LAPB_DEBUG > 0
65 printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n",
66 lapb->dev);
67#endif
68 lapb_send_control(lapb, LAPB_UA, frame->pf,
69 LAPB_RESPONSE);
70 lapb_stop_t1timer(lapb);
71 lapb_stop_t2timer(lapb);
72 lapb->state = LAPB_STATE_3;
73 lapb->condition = 0x00;
74 lapb->n2count = 0;
75 lapb->vs = 0;
76 lapb->vr = 0;
77 lapb->va = 0;
78 lapb_connect_indication(lapb, LAPB_OK);
79 }
80 break;
81
82 case LAPB_SABME:
83#if LAPB_DEBUG > 1
84 printk(KERN_DEBUG "lapb: (%p) S0 RX SABME(%d)\n",
85 lapb->dev, frame->pf);
86#endif
87 if (lapb->mode & LAPB_EXTENDED) {
88#if LAPB_DEBUG > 1
89 printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n",
90 lapb->dev, frame->pf);
91#endif
92#if LAPB_DEBUG > 0
93 printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n",
94 lapb->dev);
95#endif
96 lapb_send_control(lapb, LAPB_UA, frame->pf,
97 LAPB_RESPONSE);
98 lapb_stop_t1timer(lapb);
99 lapb_stop_t2timer(lapb);
100 lapb->state = LAPB_STATE_3;
101 lapb->condition = 0x00;
102 lapb->n2count = 0;
103 lapb->vs = 0;
104 lapb->vr = 0;
105 lapb->va = 0;
106 lapb_connect_indication(lapb, LAPB_OK);
107 } else {
108#if LAPB_DEBUG > 1
109 printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n",
110 lapb->dev, frame->pf);
111#endif
112 lapb_send_control(lapb, LAPB_DM, frame->pf,
113 LAPB_RESPONSE);
114 }
115 break;
116
117 case LAPB_DISC:
118#if LAPB_DEBUG > 1
119 printk(KERN_DEBUG "lapb: (%p) S0 RX DISC(%d)\n",
120 lapb->dev, frame->pf);
121 printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n",
122 lapb->dev, frame->pf);
123#endif
124 lapb_send_control(lapb, LAPB_UA, frame->pf,
125 LAPB_RESPONSE);
126 break;
127
128 default:
129 break;
130 }
131
132 kfree_skb(skb);
133}
134
135/*
136 * State machine for state 1, Awaiting Connection State.
137 * The handling of the timer(s) is in file lapb_timer.c.
138 */
139static void lapb_state1_machine(struct lapb_cb *lapb, struct sk_buff *skb,
140 struct lapb_frame *frame)
141{
142 switch (frame->type) {
143 case LAPB_SABM:
144#if LAPB_DEBUG > 1
145 printk(KERN_DEBUG "lapb: (%p) S1 RX SABM(%d)\n",
146 lapb->dev, frame->pf);
147#endif
148 if (lapb->mode & LAPB_EXTENDED) {
149#if LAPB_DEBUG > 1
150 printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n",
151 lapb->dev, frame->pf);
152#endif
153 lapb_send_control(lapb, LAPB_DM, frame->pf,
154 LAPB_RESPONSE);
155 } else {
156#if LAPB_DEBUG > 1
157 printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n",
158 lapb->dev, frame->pf);
159#endif
160 lapb_send_control(lapb, LAPB_UA, frame->pf,
161 LAPB_RESPONSE);
162 }
163 break;
164
165 case LAPB_SABME:
166#if LAPB_DEBUG > 1
167 printk(KERN_DEBUG "lapb: (%p) S1 RX SABME(%d)\n",
168 lapb->dev, frame->pf);
169#endif
170 if (lapb->mode & LAPB_EXTENDED) {
171#if LAPB_DEBUG > 1
172 printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n",
173 lapb->dev, frame->pf);
174#endif
175 lapb_send_control(lapb, LAPB_UA, frame->pf,
176 LAPB_RESPONSE);
177 } else {
178#if LAPB_DEBUG > 1
179 printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n",
180 lapb->dev, frame->pf);
181#endif
182 lapb_send_control(lapb, LAPB_DM, frame->pf,
183 LAPB_RESPONSE);
184 }
185 break;
186
187 case LAPB_DISC:
188#if LAPB_DEBUG > 1
189 printk(KERN_DEBUG "lapb: (%p) S1 RX DISC(%d)\n",
190 lapb->dev, frame->pf);
191 printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n",
192 lapb->dev, frame->pf);
193#endif
194 lapb_send_control(lapb, LAPB_DM, frame->pf,
195 LAPB_RESPONSE);
196 break;
197
198 case LAPB_UA:
199#if LAPB_DEBUG > 1
200 printk(KERN_DEBUG "lapb: (%p) S1 RX UA(%d)\n",
201 lapb->dev, frame->pf);
202#endif
203 if (frame->pf) {
204#if LAPB_DEBUG > 0
205 printk(KERN_DEBUG "lapb: (%p) S1 -> S3\n",
206 lapb->dev);
207#endif
208 lapb_stop_t1timer(lapb);
209 lapb_stop_t2timer(lapb);
210 lapb->state = LAPB_STATE_3;
211 lapb->condition = 0x00;
212 lapb->n2count = 0;
213 lapb->vs = 0;
214 lapb->vr = 0;
215 lapb->va = 0;
216 lapb_connect_confirmation(lapb, LAPB_OK);
217 }
218 break;
219
220 case LAPB_DM:
221#if LAPB_DEBUG > 1
222 printk(KERN_DEBUG "lapb: (%p) S1 RX DM(%d)\n",
223 lapb->dev, frame->pf);
224#endif
225 if (frame->pf) {
226#if LAPB_DEBUG > 0
227 printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n",
228 lapb->dev);
229#endif
230 lapb_clear_queues(lapb);
231 lapb->state = LAPB_STATE_0;
232 lapb_start_t1timer(lapb);
233 lapb_stop_t2timer(lapb);
234 lapb_disconnect_indication(lapb, LAPB_REFUSED);
235 }
236 break;
237 }
238
239 kfree_skb(skb);
240}
241
242/*
243 * State machine for state 2, Awaiting Release State.
244 * The handling of the timer(s) is in file lapb_timer.c
245 */
246static void lapb_state2_machine(struct lapb_cb *lapb, struct sk_buff *skb,
247 struct lapb_frame *frame)
248{
249 switch (frame->type) {
250 case LAPB_SABM:
251 case LAPB_SABME:
252#if LAPB_DEBUG > 1
253 printk(KERN_DEBUG "lapb: (%p) S2 RX {SABM,SABME}(%d)\n",
254 lapb->dev, frame->pf);
255 printk(KERN_DEBUG "lapb: (%p) S2 TX DM(%d)\n",
256 lapb->dev, frame->pf);
257#endif
258 lapb_send_control(lapb, LAPB_DM, frame->pf,
259 LAPB_RESPONSE);
260 break;
261
262 case LAPB_DISC:
263#if LAPB_DEBUG > 1
264 printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n",
265 lapb->dev, frame->pf);
266 printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n",
267 lapb->dev, frame->pf);
268#endif
269 lapb_send_control(lapb, LAPB_UA, frame->pf,
270 LAPB_RESPONSE);
271 break;
272
273 case LAPB_UA:
274#if LAPB_DEBUG > 1
275 printk(KERN_DEBUG "lapb: (%p) S2 RX UA(%d)\n",
276 lapb->dev, frame->pf);
277#endif
278 if (frame->pf) {
279#if LAPB_DEBUG > 0
280 printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n",
281 lapb->dev);
282#endif
283 lapb->state = LAPB_STATE_0;
284 lapb_start_t1timer(lapb);
285 lapb_stop_t2timer(lapb);
286 lapb_disconnect_confirmation(lapb, LAPB_OK);
287 }
288 break;
289
290 case LAPB_DM:
291#if LAPB_DEBUG > 1
292 printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n",
293 lapb->dev, frame->pf);
294#endif
295 if (frame->pf) {
296#if LAPB_DEBUG > 0
297 printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n",
298 lapb->dev);
299#endif
300 lapb->state = LAPB_STATE_0;
301 lapb_start_t1timer(lapb);
302 lapb_stop_t2timer(lapb);
303 lapb_disconnect_confirmation(lapb,
304 LAPB_NOTCONNECTED);
305 }
306 break;
307
308 case LAPB_I:
309 case LAPB_REJ:
310 case LAPB_RNR:
311 case LAPB_RR:
312#if LAPB_DEBUG > 1
313 printk(KERN_DEBUG "lapb: (%p) S2 RX {I,REJ,RNR,RR}"
314 "(%d)\n", lapb->dev, frame->pf);
315 printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n",
316 lapb->dev, frame->pf);
317#endif
318 if (frame->pf)
319 lapb_send_control(lapb, LAPB_DM, frame->pf,
320 LAPB_RESPONSE);
321 break;
322 }
323
324 kfree_skb(skb);
325}
326
327/*
328 * State machine for state 3, Connected State.
329 * The handling of the timer(s) is in file lapb_timer.c
330 */
331static void lapb_state3_machine(struct lapb_cb *lapb, struct sk_buff *skb,
332 struct lapb_frame *frame)
333{
334 int queued = 0;
335 int modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS :
336 LAPB_SMODULUS;
337
338 switch (frame->type) {
339 case LAPB_SABM:
340#if LAPB_DEBUG > 1
341 printk(KERN_DEBUG "lapb: (%p) S3 RX SABM(%d)\n",
342 lapb->dev, frame->pf);
343#endif
344 if (lapb->mode & LAPB_EXTENDED) {
345#if LAPB_DEBUG > 1
346 printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n",
347 lapb->dev, frame->pf);
348#endif
349 lapb_send_control(lapb, LAPB_DM, frame->pf,
350 LAPB_RESPONSE);
351 } else {
352#if LAPB_DEBUG > 1
353 printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n",
354 lapb->dev, frame->pf);
355#endif
356 lapb_send_control(lapb, LAPB_UA, frame->pf,
357 LAPB_RESPONSE);
358 lapb_stop_t1timer(lapb);
359 lapb_stop_t2timer(lapb);
360 lapb->condition = 0x00;
361 lapb->n2count = 0;
362 lapb->vs = 0;
363 lapb->vr = 0;
364 lapb->va = 0;
365 lapb_requeue_frames(lapb);
366 }
367 break;
368
369 case LAPB_SABME:
370#if LAPB_DEBUG > 1
371 printk(KERN_DEBUG "lapb: (%p) S3 RX SABME(%d)\n",
372 lapb->dev, frame->pf);
373#endif
374 if (lapb->mode & LAPB_EXTENDED) {
375#if LAPB_DEBUG > 1
376 printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n",
377 lapb->dev, frame->pf);
378#endif
379 lapb_send_control(lapb, LAPB_UA, frame->pf,
380 LAPB_RESPONSE);
381 lapb_stop_t1timer(lapb);
382 lapb_stop_t2timer(lapb);
383 lapb->condition = 0x00;
384 lapb->n2count = 0;
385 lapb->vs = 0;
386 lapb->vr = 0;
387 lapb->va = 0;
388 lapb_requeue_frames(lapb);
389 } else {
390#if LAPB_DEBUG > 1
391 printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n",
392 lapb->dev, frame->pf);
393#endif
394 lapb_send_control(lapb, LAPB_DM, frame->pf,
395 LAPB_RESPONSE);
396 }
397 break;
398
399 case LAPB_DISC:
400#if LAPB_DEBUG > 1
401 printk(KERN_DEBUG "lapb: (%p) S3 RX DISC(%d)\n",
402 lapb->dev, frame->pf);
403#endif
404#if LAPB_DEBUG > 0
405 printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n",
406 lapb->dev);
407#endif
408 lapb_clear_queues(lapb);
409 lapb_send_control(lapb, LAPB_UA, frame->pf,
410 LAPB_RESPONSE);
411 lapb_start_t1timer(lapb);
412 lapb_stop_t2timer(lapb);
413 lapb->state = LAPB_STATE_0;
414 lapb_disconnect_indication(lapb, LAPB_OK);
415 break;
416
417 case LAPB_DM:
418#if LAPB_DEBUG > 1
419 printk(KERN_DEBUG "lapb: (%p) S3 RX DM(%d)\n",
420 lapb->dev, frame->pf);
421#endif
422#if LAPB_DEBUG > 0
423 printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n",
424 lapb->dev);
425#endif
426 lapb_clear_queues(lapb);
427 lapb->state = LAPB_STATE_0;
428 lapb_start_t1timer(lapb);
429 lapb_stop_t2timer(lapb);
430 lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED);
431 break;
432
433 case LAPB_RNR:
434#if LAPB_DEBUG > 1
435 printk(KERN_DEBUG "lapb: (%p) S3 RX RNR(%d) R%d\n",
436 lapb->dev, frame->pf, frame->nr);
437#endif
438 lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION;
439 lapb_check_need_response(lapb, frame->cr, frame->pf);
440 if (lapb_validate_nr(lapb, frame->nr)) {
441 lapb_check_iframes_acked(lapb, frame->nr);
442 } else {
443 lapb->frmr_data = *frame;
444 lapb->frmr_type = LAPB_FRMR_Z;
445 lapb_transmit_frmr(lapb);
446#if LAPB_DEBUG > 0
447 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
448 lapb->dev);
449#endif
450 lapb_start_t1timer(lapb);
451 lapb_stop_t2timer(lapb);
452 lapb->state = LAPB_STATE_4;
453 lapb->n2count = 0;
454 }
455 break;
456
457 case LAPB_RR:
458#if LAPB_DEBUG > 1
459 printk(KERN_DEBUG "lapb: (%p) S3 RX RR(%d) R%d\n",
460 lapb->dev, frame->pf, frame->nr);
461#endif
462 lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
463 lapb_check_need_response(lapb, frame->cr, frame->pf);
464 if (lapb_validate_nr(lapb, frame->nr)) {
465 lapb_check_iframes_acked(lapb, frame->nr);
466 } else {
467 lapb->frmr_data = *frame;
468 lapb->frmr_type = LAPB_FRMR_Z;
469 lapb_transmit_frmr(lapb);
470#if LAPB_DEBUG > 0
471 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
472 lapb->dev);
473#endif
474 lapb_start_t1timer(lapb);
475 lapb_stop_t2timer(lapb);
476 lapb->state = LAPB_STATE_4;
477 lapb->n2count = 0;
478 }
479 break;
480
481 case LAPB_REJ:
482#if LAPB_DEBUG > 1
483 printk(KERN_DEBUG "lapb: (%p) S3 RX REJ(%d) R%d\n",
484 lapb->dev, frame->pf, frame->nr);
485#endif
486 lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
487 lapb_check_need_response(lapb, frame->cr, frame->pf);
488 if (lapb_validate_nr(lapb, frame->nr)) {
489 lapb_frames_acked(lapb, frame->nr);
490 lapb_stop_t1timer(lapb);
491 lapb->n2count = 0;
492 lapb_requeue_frames(lapb);
493 } else {
494 lapb->frmr_data = *frame;
495 lapb->frmr_type = LAPB_FRMR_Z;
496 lapb_transmit_frmr(lapb);
497#if LAPB_DEBUG > 0
498 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
499 lapb->dev);
500#endif
501 lapb_start_t1timer(lapb);
502 lapb_stop_t2timer(lapb);
503 lapb->state = LAPB_STATE_4;
504 lapb->n2count = 0;
505 }
506 break;
507
508 case LAPB_I:
509#if LAPB_DEBUG > 1
510 printk(KERN_DEBUG "lapb: (%p) S3 RX I(%d) S%d R%d\n",
511 lapb->dev, frame->pf, frame->ns, frame->nr);
512#endif
513 if (!lapb_validate_nr(lapb, frame->nr)) {
514 lapb->frmr_data = *frame;
515 lapb->frmr_type = LAPB_FRMR_Z;
516 lapb_transmit_frmr(lapb);
517#if LAPB_DEBUG > 0
518 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
519 lapb->dev);
520#endif
521 lapb_start_t1timer(lapb);
522 lapb_stop_t2timer(lapb);
523 lapb->state = LAPB_STATE_4;
524 lapb->n2count = 0;
525 break;
526 }
527 if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION)
528 lapb_frames_acked(lapb, frame->nr);
529 else
530 lapb_check_iframes_acked(lapb, frame->nr);
531
532 if (frame->ns == lapb->vr) {
533 int cn;
534 cn = lapb_data_indication(lapb, skb);
535 queued = 1;
536 /*
537 * If upper layer has dropped the frame, we
538 * basically ignore any further protocol
539 * processing. This will cause the peer
540 * to re-transmit the frame later like
541 * a frame lost on the wire.
542 */
543 if (cn == NET_RX_DROP) {
544 printk(KERN_DEBUG
545 "LAPB: rx congestion\n");
546 break;
547 }
548 lapb->vr = (lapb->vr + 1) % modulus;
549 lapb->condition &= ~LAPB_REJECT_CONDITION;
550 if (frame->pf)
551 lapb_enquiry_response(lapb);
552 else {
553 if (!(lapb->condition &
554 LAPB_ACK_PENDING_CONDITION)) {
555 lapb->condition |= LAPB_ACK_PENDING_CONDITION;
556 lapb_start_t2timer(lapb);
557 }
558 }
559 } else {
560 if (lapb->condition & LAPB_REJECT_CONDITION) {
561 if (frame->pf)
562 lapb_enquiry_response(lapb);
563 } else {
564#if LAPB_DEBUG > 1
565 printk(KERN_DEBUG
566 "lapb: (%p) S3 TX REJ(%d) R%d\n",
567 lapb->dev, frame->pf, lapb->vr);
568#endif
569 lapb->condition |= LAPB_REJECT_CONDITION;
570 lapb_send_control(lapb, LAPB_REJ,
571 frame->pf,
572 LAPB_RESPONSE);
573 lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
574 }
575 }
576 break;
577
578 case LAPB_FRMR:
579#if LAPB_DEBUG > 1
580 printk(KERN_DEBUG "lapb: (%p) S3 RX FRMR(%d) %02X "
581 "%02X %02X %02X %02X\n", lapb->dev, frame->pf,
582 skb->data[0], skb->data[1], skb->data[2],
583 skb->data[3], skb->data[4]);
584#endif
585 lapb_establish_data_link(lapb);
586#if LAPB_DEBUG > 0
587 printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n",
588 lapb->dev);
589#endif
590 lapb_requeue_frames(lapb);
591 lapb->state = LAPB_STATE_1;
592 break;
593
594 case LAPB_ILLEGAL:
595#if LAPB_DEBUG > 1
596 printk(KERN_DEBUG "lapb: (%p) S3 RX ILLEGAL(%d)\n",
597 lapb->dev, frame->pf);
598#endif
599 lapb->frmr_data = *frame;
600 lapb->frmr_type = LAPB_FRMR_W;
601 lapb_transmit_frmr(lapb);
602#if LAPB_DEBUG > 0
603 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->dev);
604#endif
605 lapb_start_t1timer(lapb);
606 lapb_stop_t2timer(lapb);
607 lapb->state = LAPB_STATE_4;
608 lapb->n2count = 0;
609 break;
610 }
611
612 if (!queued)
613 kfree_skb(skb);
614}
615
616/*
617 * State machine for state 4, Frame Reject State.
618 * The handling of the timer(s) is in file lapb_timer.c.
619 */
620static void lapb_state4_machine(struct lapb_cb *lapb, struct sk_buff *skb,
621 struct lapb_frame *frame)
622{
623 switch (frame->type) {
624 case LAPB_SABM:
625#if LAPB_DEBUG > 1
626 printk(KERN_DEBUG "lapb: (%p) S4 RX SABM(%d)\n",
627 lapb->dev, frame->pf);
628#endif
629 if (lapb->mode & LAPB_EXTENDED) {
630#if LAPB_DEBUG > 1
631 printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n",
632 lapb->dev, frame->pf);
633#endif
634 lapb_send_control(lapb, LAPB_DM, frame->pf,
635 LAPB_RESPONSE);
636 } else {
637#if LAPB_DEBUG > 1
638 printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n",
639 lapb->dev, frame->pf);
640#endif
641#if LAPB_DEBUG > 0
642 printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n",
643 lapb->dev);
644#endif
645 lapb_send_control(lapb, LAPB_UA, frame->pf,
646 LAPB_RESPONSE);
647 lapb_stop_t1timer(lapb);
648 lapb_stop_t2timer(lapb);
649 lapb->state = LAPB_STATE_3;
650 lapb->condition = 0x00;
651 lapb->n2count = 0;
652 lapb->vs = 0;
653 lapb->vr = 0;
654 lapb->va = 0;
655 lapb_connect_indication(lapb, LAPB_OK);
656 }
657 break;
658
659 case LAPB_SABME:
660#if LAPB_DEBUG > 1
661 printk(KERN_DEBUG "lapb: (%p) S4 RX SABME(%d)\n",
662 lapb->dev, frame->pf);
663#endif
664 if (lapb->mode & LAPB_EXTENDED) {
665#if LAPB_DEBUG > 1
666 printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n",
667 lapb->dev, frame->pf);
668#endif
669#if LAPB_DEBUG > 0
670 printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n",
671 lapb->dev);
672#endif
673 lapb_send_control(lapb, LAPB_UA, frame->pf,
674 LAPB_RESPONSE);
675 lapb_stop_t1timer(lapb);
676 lapb_stop_t2timer(lapb);
677 lapb->state = LAPB_STATE_3;
678 lapb->condition = 0x00;
679 lapb->n2count = 0;
680 lapb->vs = 0;
681 lapb->vr = 0;
682 lapb->va = 0;
683 lapb_connect_indication(lapb, LAPB_OK);
684 } else {
685#if LAPB_DEBUG > 1
686 printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n",
687 lapb->dev, frame->pf);
688#endif
689 lapb_send_control(lapb, LAPB_DM, frame->pf,
690 LAPB_RESPONSE);
691 }
692 break;
693 }
694
695 kfree_skb(skb);
696}
697
698/*
699 * Process an incoming LAPB frame
700 */
701void lapb_data_input(struct lapb_cb *lapb, struct sk_buff *skb)
702{
703 struct lapb_frame frame;
704
705 if (lapb_decode(lapb, skb, &frame) < 0) {
706 kfree_skb(skb);
707 return;
708 }
709
710 switch (lapb->state) {
711 case LAPB_STATE_0:
712 lapb_state0_machine(lapb, skb, &frame); break;
713 case LAPB_STATE_1:
714 lapb_state1_machine(lapb, skb, &frame); break;
715 case LAPB_STATE_2:
716 lapb_state2_machine(lapb, skb, &frame); break;
717 case LAPB_STATE_3:
718 lapb_state3_machine(lapb, skb, &frame); break;
719 case LAPB_STATE_4:
720 lapb_state4_machine(lapb, skb, &frame); break;
721 }
722
723 lapb_kick(lapb);
724}
diff --git a/net/lapb/lapb_out.c b/net/lapb/lapb_out.c
new file mode 100644
index 000000000000..49a761bd9314
--- /dev/null
+++ b/net/lapb/lapb_out.c
@@ -0,0 +1,224 @@
1/*
2 * LAPB release 002
3 *
4 * This code REQUIRES 2.1.15 or higher/ NET3.038
5 *
6 * This module:
7 * This module is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * History
13 * LAPB 001 Jonathan Naylor Started Coding
14 * LAPB 002 Jonathan Naylor New timer architecture.
15 */
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/sched.h>
23#include <linux/timer.h>
24#include <linux/string.h>
25#include <linux/sockios.h>
26#include <linux/net.h>
27#include <linux/inet.h>
28#include <linux/skbuff.h>
29#include <net/sock.h>
30#include <asm/uaccess.h>
31#include <asm/system.h>
32#include <linux/fcntl.h>
33#include <linux/mm.h>
34#include <linux/interrupt.h>
35#include <net/lapb.h>
36
37/*
38 * This procedure is passed a buffer descriptor for an iframe. It builds
39 * the rest of the control part of the frame and then writes it out.
40 */
41static void lapb_send_iframe(struct lapb_cb *lapb, struct sk_buff *skb, int poll_bit)
42{
43 unsigned char *frame;
44
45 if (!skb)
46 return;
47
48 if (lapb->mode & LAPB_EXTENDED) {
49 frame = skb_push(skb, 2);
50
51 frame[0] = LAPB_I;
52 frame[0] |= lapb->vs << 1;
53 frame[1] = poll_bit ? LAPB_EPF : 0;
54 frame[1] |= lapb->vr << 1;
55 } else {
56 frame = skb_push(skb, 1);
57
58 *frame = LAPB_I;
59 *frame |= poll_bit ? LAPB_SPF : 0;
60 *frame |= lapb->vr << 5;
61 *frame |= lapb->vs << 1;
62 }
63
64#if LAPB_DEBUG > 1
65 printk(KERN_DEBUG "lapb: (%p) S%d TX I(%d) S%d R%d\n",
66 lapb->dev, lapb->state, poll_bit, lapb->vs, lapb->vr);
67#endif
68
69 lapb_transmit_buffer(lapb, skb, LAPB_COMMAND);
70}
71
72void lapb_kick(struct lapb_cb *lapb)
73{
74 struct sk_buff *skb, *skbn;
75 unsigned short modulus, start, end;
76
77 modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
78 start = !skb_peek(&lapb->ack_queue) ? lapb->va : lapb->vs;
79 end = (lapb->va + lapb->window) % modulus;
80
81 if (!(lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) &&
82 start != end && skb_peek(&lapb->write_queue)) {
83 lapb->vs = start;
84
85 /*
86 * Dequeue the frame and copy it.
87 */
88 skb = skb_dequeue(&lapb->write_queue);
89
90 do {
91 if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
92 skb_queue_head(&lapb->write_queue, skb);
93 break;
94 }
95
96 if (skb->sk)
97 skb_set_owner_w(skbn, skb->sk);
98
99 /*
100 * Transmit the frame copy.
101 */
102 lapb_send_iframe(lapb, skbn, LAPB_POLLOFF);
103
104 lapb->vs = (lapb->vs + 1) % modulus;
105
106 /*
107 * Requeue the original data frame.
108 */
109 skb_queue_tail(&lapb->ack_queue, skb);
110
111 } while (lapb->vs != end && (skb = skb_dequeue(&lapb->write_queue)) != NULL);
112
113 lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
114
115 if (!lapb_t1timer_running(lapb))
116 lapb_start_t1timer(lapb);
117 }
118}
119
120void lapb_transmit_buffer(struct lapb_cb *lapb, struct sk_buff *skb, int type)
121{
122 unsigned char *ptr;
123
124 ptr = skb_push(skb, 1);
125
126 if (lapb->mode & LAPB_MLP) {
127 if (lapb->mode & LAPB_DCE) {
128 if (type == LAPB_COMMAND)
129 *ptr = LAPB_ADDR_C;
130 if (type == LAPB_RESPONSE)
131 *ptr = LAPB_ADDR_D;
132 } else {
133 if (type == LAPB_COMMAND)
134 *ptr = LAPB_ADDR_D;
135 if (type == LAPB_RESPONSE)
136 *ptr = LAPB_ADDR_C;
137 }
138 } else {
139 if (lapb->mode & LAPB_DCE) {
140 if (type == LAPB_COMMAND)
141 *ptr = LAPB_ADDR_A;
142 if (type == LAPB_RESPONSE)
143 *ptr = LAPB_ADDR_B;
144 } else {
145 if (type == LAPB_COMMAND)
146 *ptr = LAPB_ADDR_B;
147 if (type == LAPB_RESPONSE)
148 *ptr = LAPB_ADDR_A;
149 }
150 }
151
152#if LAPB_DEBUG > 2
153 printk(KERN_DEBUG "lapb: (%p) S%d TX %02X %02X %02X\n",
154 lapb->dev, lapb->state,
155 skb->data[0], skb->data[1], skb->data[2]);
156#endif
157
158 if (!lapb_data_transmit(lapb, skb))
159 kfree_skb(skb);
160}
161
162void lapb_establish_data_link(struct lapb_cb *lapb)
163{
164 lapb->condition = 0x00;
165 lapb->n2count = 0;
166
167 if (lapb->mode & LAPB_EXTENDED) {
168#if LAPB_DEBUG > 1
169 printk(KERN_DEBUG "lapb: (%p) S%d TX SABME(1)\n",
170 lapb->dev, lapb->state);
171#endif
172 lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND);
173 } else {
174#if LAPB_DEBUG > 1
175 printk(KERN_DEBUG "lapb: (%p) S%d TX SABM(1)\n",
176 lapb->dev, lapb->state);
177#endif
178 lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND);
179 }
180
181 lapb_start_t1timer(lapb);
182 lapb_stop_t2timer(lapb);
183}
184
185void lapb_enquiry_response(struct lapb_cb *lapb)
186{
187#if LAPB_DEBUG > 1
188 printk(KERN_DEBUG "lapb: (%p) S%d TX RR(1) R%d\n",
189 lapb->dev, lapb->state, lapb->vr);
190#endif
191
192 lapb_send_control(lapb, LAPB_RR, LAPB_POLLON, LAPB_RESPONSE);
193
194 lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
195}
196
197void lapb_timeout_response(struct lapb_cb *lapb)
198{
199#if LAPB_DEBUG > 1
200 printk(KERN_DEBUG "lapb: (%p) S%d TX RR(0) R%d\n",
201 lapb->dev, lapb->state, lapb->vr);
202#endif
203 lapb_send_control(lapb, LAPB_RR, LAPB_POLLOFF, LAPB_RESPONSE);
204
205 lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
206}
207
208void lapb_check_iframes_acked(struct lapb_cb *lapb, unsigned short nr)
209{
210 if (lapb->vs == nr) {
211 lapb_frames_acked(lapb, nr);
212 lapb_stop_t1timer(lapb);
213 lapb->n2count = 0;
214 } else if (lapb->va != nr) {
215 lapb_frames_acked(lapb, nr);
216 lapb_start_t1timer(lapb);
217 }
218}
219
220void lapb_check_need_response(struct lapb_cb *lapb, int type, int pf)
221{
222 if (type == LAPB_COMMAND && pf)
223 lapb_enquiry_response(lapb);
224}
diff --git a/net/lapb/lapb_subr.c b/net/lapb/lapb_subr.c
new file mode 100644
index 000000000000..5de05a0bc0ff
--- /dev/null
+++ b/net/lapb/lapb_subr.c
@@ -0,0 +1,313 @@
1/*
2 * LAPB release 002
3 *
4 * This code REQUIRES 2.1.15 or higher/ NET3.038
5 *
6 * This module:
7 * This module is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * History
13 * LAPB 001 Jonathan Naylor Started Coding
14 */
15
16#include <linux/errno.h>
17#include <linux/types.h>
18#include <linux/socket.h>
19#include <linux/in.h>
20#include <linux/kernel.h>
21#include <linux/sched.h>
22#include <linux/timer.h>
23#include <linux/string.h>
24#include <linux/sockios.h>
25#include <linux/net.h>
26#include <linux/inet.h>
27#include <linux/skbuff.h>
28#include <net/sock.h>
29#include <asm/uaccess.h>
30#include <asm/system.h>
31#include <linux/fcntl.h>
32#include <linux/mm.h>
33#include <linux/interrupt.h>
34#include <net/lapb.h>
35
36/*
37 * This routine purges all the queues of frames.
38 */
39void lapb_clear_queues(struct lapb_cb *lapb)
40{
41 skb_queue_purge(&lapb->write_queue);
42 skb_queue_purge(&lapb->ack_queue);
43}
44
45/*
46 * This routine purges the input queue of those frames that have been
47 * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
48 * SDL diagram.
49 */
50void lapb_frames_acked(struct lapb_cb *lapb, unsigned short nr)
51{
52 struct sk_buff *skb;
53 int modulus;
54
55 modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
56
57 /*
58 * Remove all the ack-ed frames from the ack queue.
59 */
60 if (lapb->va != nr)
61 while (skb_peek(&lapb->ack_queue) && lapb->va != nr) {
62 skb = skb_dequeue(&lapb->ack_queue);
63 kfree_skb(skb);
64 lapb->va = (lapb->va + 1) % modulus;
65 }
66}
67
68void lapb_requeue_frames(struct lapb_cb *lapb)
69{
70 struct sk_buff *skb, *skb_prev = NULL;
71
72 /*
73 * Requeue all the un-ack-ed frames on the output queue to be picked
74 * up by lapb_kick called from the timer. This arrangement handles the
75 * possibility of an empty output queue.
76 */
77 while ((skb = skb_dequeue(&lapb->ack_queue)) != NULL) {
78 if (!skb_prev)
79 skb_queue_head(&lapb->write_queue, skb);
80 else
81 skb_append(skb_prev, skb);
82 skb_prev = skb;
83 }
84}
85
86/*
87 * Validate that the value of nr is between va and vs. Return true or
88 * false for testing.
89 */
90int lapb_validate_nr(struct lapb_cb *lapb, unsigned short nr)
91{
92 unsigned short vc = lapb->va;
93 int modulus;
94
95 modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
96
97 while (vc != lapb->vs) {
98 if (nr == vc)
99 return 1;
100 vc = (vc + 1) % modulus;
101 }
102
103 return nr == lapb->vs;
104}
105
106/*
107 * This routine is the centralised routine for parsing the control
108 * information for the different frame formats.
109 */
110int lapb_decode(struct lapb_cb *lapb, struct sk_buff *skb,
111 struct lapb_frame *frame)
112{
113 frame->type = LAPB_ILLEGAL;
114
115#if LAPB_DEBUG > 2
116 printk(KERN_DEBUG "lapb: (%p) S%d RX %02X %02X %02X\n",
117 lapb->dev, lapb->state,
118 skb->data[0], skb->data[1], skb->data[2]);
119#endif
120
121 /* We always need to look at 2 bytes, sometimes we need
122 * to look at 3 and those cases are handled below.
123 */
124 if (!pskb_may_pull(skb, 2))
125 return -1;
126
127 if (lapb->mode & LAPB_MLP) {
128 if (lapb->mode & LAPB_DCE) {
129 if (skb->data[0] == LAPB_ADDR_D)
130 frame->cr = LAPB_COMMAND;
131 if (skb->data[0] == LAPB_ADDR_C)
132 frame->cr = LAPB_RESPONSE;
133 } else {
134 if (skb->data[0] == LAPB_ADDR_C)
135 frame->cr = LAPB_COMMAND;
136 if (skb->data[0] == LAPB_ADDR_D)
137 frame->cr = LAPB_RESPONSE;
138 }
139 } else {
140 if (lapb->mode & LAPB_DCE) {
141 if (skb->data[0] == LAPB_ADDR_B)
142 frame->cr = LAPB_COMMAND;
143 if (skb->data[0] == LAPB_ADDR_A)
144 frame->cr = LAPB_RESPONSE;
145 } else {
146 if (skb->data[0] == LAPB_ADDR_A)
147 frame->cr = LAPB_COMMAND;
148 if (skb->data[0] == LAPB_ADDR_B)
149 frame->cr = LAPB_RESPONSE;
150 }
151 }
152
153 skb_pull(skb, 1);
154
155 if (lapb->mode & LAPB_EXTENDED) {
156 if (!(skb->data[0] & LAPB_S)) {
157 if (!pskb_may_pull(skb, 2))
158 return -1;
159 /*
160 * I frame - carries NR/NS/PF
161 */
162 frame->type = LAPB_I;
163 frame->ns = (skb->data[0] >> 1) & 0x7F;
164 frame->nr = (skb->data[1] >> 1) & 0x7F;
165 frame->pf = skb->data[1] & LAPB_EPF;
166 frame->control[0] = skb->data[0];
167 frame->control[1] = skb->data[1];
168 skb_pull(skb, 2);
169 } else if ((skb->data[0] & LAPB_U) == 1) {
170 if (!pskb_may_pull(skb, 2))
171 return -1;
172 /*
173 * S frame - take out PF/NR
174 */
175 frame->type = skb->data[0] & 0x0F;
176 frame->nr = (skb->data[1] >> 1) & 0x7F;
177 frame->pf = skb->data[1] & LAPB_EPF;
178 frame->control[0] = skb->data[0];
179 frame->control[1] = skb->data[1];
180 skb_pull(skb, 2);
181 } else if ((skb->data[0] & LAPB_U) == 3) {
182 /*
183 * U frame - take out PF
184 */
185 frame->type = skb->data[0] & ~LAPB_SPF;
186 frame->pf = skb->data[0] & LAPB_SPF;
187 frame->control[0] = skb->data[0];
188 frame->control[1] = 0x00;
189 skb_pull(skb, 1);
190 }
191 } else {
192 if (!(skb->data[0] & LAPB_S)) {
193 /*
194 * I frame - carries NR/NS/PF
195 */
196 frame->type = LAPB_I;
197 frame->ns = (skb->data[0] >> 1) & 0x07;
198 frame->nr = (skb->data[0] >> 5) & 0x07;
199 frame->pf = skb->data[0] & LAPB_SPF;
200 } else if ((skb->data[0] & LAPB_U) == 1) {
201 /*
202 * S frame - take out PF/NR
203 */
204 frame->type = skb->data[0] & 0x0F;
205 frame->nr = (skb->data[0] >> 5) & 0x07;
206 frame->pf = skb->data[0] & LAPB_SPF;
207 } else if ((skb->data[0] & LAPB_U) == 3) {
208 /*
209 * U frame - take out PF
210 */
211 frame->type = skb->data[0] & ~LAPB_SPF;
212 frame->pf = skb->data[0] & LAPB_SPF;
213 }
214
215 frame->control[0] = skb->data[0];
216
217 skb_pull(skb, 1);
218 }
219
220 return 0;
221}
222
223/*
224 * This routine is called when the HDLC layer internally generates a
225 * command or response for the remote machine ( eg. RR, UA etc. ).
226 * Only supervisory or unnumbered frames are processed, FRMRs are handled
227 * by lapb_transmit_frmr below.
228 */
229void lapb_send_control(struct lapb_cb *lapb, int frametype,
230 int poll_bit, int type)
231{
232 struct sk_buff *skb;
233 unsigned char *dptr;
234
235 if ((skb = alloc_skb(LAPB_HEADER_LEN + 3, GFP_ATOMIC)) == NULL)
236 return;
237
238 skb_reserve(skb, LAPB_HEADER_LEN + 1);
239
240 if (lapb->mode & LAPB_EXTENDED) {
241 if ((frametype & LAPB_U) == LAPB_U) {
242 dptr = skb_put(skb, 1);
243 *dptr = frametype;
244 *dptr |= poll_bit ? LAPB_SPF : 0;
245 } else {
246 dptr = skb_put(skb, 2);
247 dptr[0] = frametype;
248 dptr[1] = (lapb->vr << 1);
249 dptr[1] |= poll_bit ? LAPB_EPF : 0;
250 }
251 } else {
252 dptr = skb_put(skb, 1);
253 *dptr = frametype;
254 *dptr |= poll_bit ? LAPB_SPF : 0;
255 if ((frametype & LAPB_U) == LAPB_S) /* S frames carry NR */
256 *dptr |= (lapb->vr << 5);
257 }
258
259 lapb_transmit_buffer(lapb, skb, type);
260}
261
262/*
263 * This routine generates FRMRs based on information previously stored in
264 * the LAPB control block.
265 */
266void lapb_transmit_frmr(struct lapb_cb *lapb)
267{
268 struct sk_buff *skb;
269 unsigned char *dptr;
270
271 if ((skb = alloc_skb(LAPB_HEADER_LEN + 7, GFP_ATOMIC)) == NULL)
272 return;
273
274 skb_reserve(skb, LAPB_HEADER_LEN + 1);
275
276 if (lapb->mode & LAPB_EXTENDED) {
277 dptr = skb_put(skb, 6);
278 *dptr++ = LAPB_FRMR;
279 *dptr++ = lapb->frmr_data.control[0];
280 *dptr++ = lapb->frmr_data.control[1];
281 *dptr++ = (lapb->vs << 1) & 0xFE;
282 *dptr = (lapb->vr << 1) & 0xFE;
283 if (lapb->frmr_data.cr == LAPB_RESPONSE)
284 *dptr |= 0x01;
285 dptr++;
286 *dptr++ = lapb->frmr_type;
287
288#if LAPB_DEBUG > 1
289 printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X %02X %02X\n",
290 lapb->dev, lapb->state,
291 skb->data[1], skb->data[2], skb->data[3],
292 skb->data[4], skb->data[5]);
293#endif
294 } else {
295 dptr = skb_put(skb, 4);
296 *dptr++ = LAPB_FRMR;
297 *dptr++ = lapb->frmr_data.control[0];
298 *dptr = (lapb->vs << 1) & 0x0E;
299 *dptr |= (lapb->vr << 5) & 0xE0;
300 if (lapb->frmr_data.cr == LAPB_RESPONSE)
301 *dptr |= 0x10;
302 dptr++;
303 *dptr++ = lapb->frmr_type;
304
305#if LAPB_DEBUG > 1
306 printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X\n",
307 lapb->dev, lapb->state, skb->data[1],
308 skb->data[2], skb->data[3]);
309#endif
310 }
311
312 lapb_transmit_buffer(lapb, skb, LAPB_RESPONSE);
313}
diff --git a/net/lapb/lapb_timer.c b/net/lapb/lapb_timer.c
new file mode 100644
index 000000000000..2c8f0f809220
--- /dev/null
+++ b/net/lapb/lapb_timer.c
@@ -0,0 +1,189 @@
1/*
2 * LAPB release 002
3 *
4 * This code REQUIRES 2.1.15 or higher/ NET3.038
5 *
6 * This module:
7 * This module is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * History
13 * LAPB 001 Jonathan Naylor Started Coding
14 * LAPB 002 Jonathan Naylor New timer architecture.
15 */
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/jiffies.h>
23#include <linux/timer.h>
24#include <linux/string.h>
25#include <linux/sockios.h>
26#include <linux/net.h>
27#include <linux/inet.h>
28#include <linux/skbuff.h>
29#include <net/sock.h>
30#include <asm/uaccess.h>
31#include <asm/system.h>
32#include <linux/fcntl.h>
33#include <linux/mm.h>
34#include <linux/interrupt.h>
35#include <net/lapb.h>
36
37static void lapb_t1timer_expiry(unsigned long);
38static void lapb_t2timer_expiry(unsigned long);
39
40void lapb_start_t1timer(struct lapb_cb *lapb)
41{
42 del_timer(&lapb->t1timer);
43
44 lapb->t1timer.data = (unsigned long)lapb;
45 lapb->t1timer.function = &lapb_t1timer_expiry;
46 lapb->t1timer.expires = jiffies + lapb->t1;
47
48 add_timer(&lapb->t1timer);
49}
50
51void lapb_start_t2timer(struct lapb_cb *lapb)
52{
53 del_timer(&lapb->t2timer);
54
55 lapb->t2timer.data = (unsigned long)lapb;
56 lapb->t2timer.function = &lapb_t2timer_expiry;
57 lapb->t2timer.expires = jiffies + lapb->t2;
58
59 add_timer(&lapb->t2timer);
60}
61
62void lapb_stop_t1timer(struct lapb_cb *lapb)
63{
64 del_timer(&lapb->t1timer);
65}
66
67void lapb_stop_t2timer(struct lapb_cb *lapb)
68{
69 del_timer(&lapb->t2timer);
70}
71
72int lapb_t1timer_running(struct lapb_cb *lapb)
73{
74 return timer_pending(&lapb->t1timer);
75}
76
77static void lapb_t2timer_expiry(unsigned long param)
78{
79 struct lapb_cb *lapb = (struct lapb_cb *)param;
80
81 if (lapb->condition & LAPB_ACK_PENDING_CONDITION) {
82 lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
83 lapb_timeout_response(lapb);
84 }
85}
86
87static void lapb_t1timer_expiry(unsigned long param)
88{
89 struct lapb_cb *lapb = (struct lapb_cb *)param;
90
91 switch (lapb->state) {
92
93 /*
94 * If we are a DCE, keep going DM .. DM .. DM
95 */
96 case LAPB_STATE_0:
97 if (lapb->mode & LAPB_DCE)
98 lapb_send_control(lapb, LAPB_DM, LAPB_POLLOFF, LAPB_RESPONSE);
99 break;
100
101 /*
102 * Awaiting connection state, send SABM(E), up to N2 times.
103 */
104 case LAPB_STATE_1:
105 if (lapb->n2count == lapb->n2) {
106 lapb_clear_queues(lapb);
107 lapb->state = LAPB_STATE_0;
108 lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
109#if LAPB_DEBUG > 0
110 printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->dev);
111#endif
112 return;
113 } else {
114 lapb->n2count++;
115 if (lapb->mode & LAPB_EXTENDED) {
116#if LAPB_DEBUG > 1
117 printk(KERN_DEBUG "lapb: (%p) S1 TX SABME(1)\n", lapb->dev);
118#endif
119 lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND);
120 } else {
121#if LAPB_DEBUG > 1
122 printk(KERN_DEBUG "lapb: (%p) S1 TX SABM(1)\n", lapb->dev);
123#endif
124 lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND);
125 }
126 }
127 break;
128
129 /*
130 * Awaiting disconnection state, send DISC, up to N2 times.
131 */
132 case LAPB_STATE_2:
133 if (lapb->n2count == lapb->n2) {
134 lapb_clear_queues(lapb);
135 lapb->state = LAPB_STATE_0;
136 lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT);
137#if LAPB_DEBUG > 0
138 printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->dev);
139#endif
140 return;
141 } else {
142 lapb->n2count++;
143#if LAPB_DEBUG > 1
144 printk(KERN_DEBUG "lapb: (%p) S2 TX DISC(1)\n", lapb->dev);
145#endif
146 lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
147 }
148 break;
149
150 /*
151 * Data transfer state, restransmit I frames, up to N2 times.
152 */
153 case LAPB_STATE_3:
154 if (lapb->n2count == lapb->n2) {
155 lapb_clear_queues(lapb);
156 lapb->state = LAPB_STATE_0;
157 lapb_stop_t2timer(lapb);
158 lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
159#if LAPB_DEBUG > 0
160 printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->dev);
161#endif
162 return;
163 } else {
164 lapb->n2count++;
165 lapb_requeue_frames(lapb);
166 }
167 break;
168
169 /*
170 * Frame reject state, restransmit FRMR frames, up to N2 times.
171 */
172 case LAPB_STATE_4:
173 if (lapb->n2count == lapb->n2) {
174 lapb_clear_queues(lapb);
175 lapb->state = LAPB_STATE_0;
176 lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
177#if LAPB_DEBUG > 0
178 printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->dev);
179#endif
180 return;
181 } else {
182 lapb->n2count++;
183 lapb_transmit_frmr(lapb);
184 }
185 break;
186 }
187
188 lapb_start_t1timer(lapb);
189}