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/config.h>
19 #if defined(CONFIG_LAPB) || defined(CONFIG_LAPB_MODULE)
20 #include <linux/module.h>
21 #include <linux/errno.h>
22 #include <linux/types.h>
23 #include <linux/socket.h>
24 #include <linux/in.h>
25 #include <linux/kernel.h>
26 #include <linux/sched.h>
27 #include <linux/timer.h>
28 #include <linux/string.h>
29 #include <linux/sockios.h>
30 #include <linux/net.h>
31 #include <linux/inet.h>
32 #include <linux/if_arp.h>
33 #include <linux/skbuff.h>
34 #include <net/sock.h>
35 #include <asm/uaccess.h>
36 #include <asm/system.h>
37 #include <linux/fcntl.h>
38 #include <linux/mm.h>
39 #include <linux/interrupt.h>
40 #include <linux/stat.h>
41 #include <linux/init.h>
42 #include <net/lapb.h>
43
44 static lapb_cb *volatile lapb_list = NULL;
45
46 /*
47 * Free an allocated lapb control block. This is done to centralise
48 * the MOD count code.
49 */
50 static void lapb_free_cb(lapb_cb *lapb)
51 {
52 kfree(lapb);
53
54 MOD_DEC_USE_COUNT;
55 }
56
57 /*
58 * Socket removal during an interrupt is now safe.
59 */
60 static void lapb_remove_cb(lapb_cb *lapb)
61 {
62 lapb_cb *s;
63 unsigned long flags;
64
65 save_flags(flags); cli();
66
67 if ((s = lapb_list) == lapb) {
68 lapb_list = s->next;
69 restore_flags(flags);
70 return;
71 }
72
73 while (s != NULL && s->next != NULL) {
74 if (s->next == lapb) {
75 s->next = lapb->next;
76 restore_flags(flags);
77 return;
78 }
79
80 s = s->next;
81 }
82
83 restore_flags(flags);
84 }
85
86 /*
87 * Add a socket to the bound sockets list.
88 */
89 static void lapb_insert_cb(lapb_cb *lapb)
90 {
91 unsigned long flags;
92
93 save_flags(flags); cli();
94
95 lapb->next = lapb_list;
96 lapb_list = lapb;
97
98 restore_flags(flags);
99 }
100
101 /*
102 * Convert the integer token used by the device driver into a pointer
103 * to a LAPB control structure.
104 */
105 static lapb_cb *lapb_tokentostruct(void *token)
106 {
107 lapb_cb *lapb;
108
109 for (lapb = lapb_list; lapb != NULL; lapb = lapb->next)
110 if (lapb->token == token)
111 return lapb;
112
113 return NULL;
114 }
115
116 /*
117 * Create an empty LAPB control block.
118 */
119 static lapb_cb *lapb_create_cb(void)
120 {
121 lapb_cb *lapb;
122
123 if ((lapb = kmalloc(sizeof(*lapb), GFP_ATOMIC)) == NULL)
124 return NULL;
125
126 MOD_INC_USE_COUNT;
127
128 memset(lapb, 0x00, sizeof(*lapb));
129
130 skb_queue_head_init(&lapb->write_queue);
131 skb_queue_head_init(&lapb->ack_queue);
132
133 init_timer(&lapb->t1timer);
134 init_timer(&lapb->t2timer);
135
136 lapb->t1 = LAPB_DEFAULT_T1;
137 lapb->t2 = LAPB_DEFAULT_T2;
138 lapb->n2 = LAPB_DEFAULT_N2;
139 lapb->mode = LAPB_DEFAULT_MODE;
140 lapb->window = LAPB_DEFAULT_WINDOW;
141 lapb->state = LAPB_STATE_0;
142
143 return lapb;
144 }
145
146 int lapb_register(void *token, struct lapb_register_struct *callbacks)
147 {
148 lapb_cb *lapb;
149
150 if (lapb_tokentostruct(token) != NULL)
151 return LAPB_BADTOKEN;
152
153 if ((lapb = lapb_create_cb()) == NULL)
154 return LAPB_NOMEM;
155
156 lapb->token = token;
157 lapb->callbacks = *callbacks;
158
159 lapb_insert_cb(lapb);
160
161 lapb_start_t1timer(lapb);
162
163 return LAPB_OK;
164 }
165
166 int lapb_unregister(void *token)
167 {
168 lapb_cb *lapb;
169
170 if ((lapb = lapb_tokentostruct(token)) == NULL)
171 return LAPB_BADTOKEN;
172
173 lapb_stop_t1timer(lapb);
174 lapb_stop_t2timer(lapb);
175
176 lapb_clear_queues(lapb);
177
178 lapb_remove_cb(lapb);
179
180 lapb_free_cb(lapb);
181
182 return LAPB_OK;
183 }
184
185 int lapb_getparms(void *token, struct lapb_parms_struct *parms)
186 {
187 lapb_cb *lapb;
188
189 if ((lapb = lapb_tokentostruct(token)) == NULL)
190 return LAPB_BADTOKEN;
191
192 parms->t1 = lapb->t1 / HZ;
193 parms->t2 = lapb->t2 / HZ;
194 parms->n2 = lapb->n2;
195 parms->n2count = lapb->n2count;
196 parms->state = lapb->state;
197 parms->window = lapb->window;
198 parms->mode = lapb->mode;
199
200 if (!timer_pending(&lapb->t1timer))
201 parms->t1timer = 0;
202 else
203 parms->t1timer = (lapb->t1timer.expires - jiffies) / HZ;
204
205 if (!timer_pending(&lapb->t2timer))
206 parms->t2timer = 0;
207 else
208 parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ;
209
210 return LAPB_OK;
211 }
212
213 int lapb_setparms(void *token, struct lapb_parms_struct *parms)
214 {
215 lapb_cb *lapb;
216
217 if ((lapb = lapb_tokentostruct(token)) == NULL)
218 return LAPB_BADTOKEN;
219
220 if (parms->t1 < 1)
221 return LAPB_INVALUE;
222
223 if (parms->t2 < 1)
224 return LAPB_INVALUE;
225
226 if (parms->n2 < 1)
227 return LAPB_INVALUE;
228
229 if (lapb->state == LAPB_STATE_0) {
230 if (parms->mode & LAPB_EXTENDED) {
231 if (parms->window < 1 || parms->window > 127)
232 return LAPB_INVALUE;
233 } else {
234 if (parms->window < 1 || parms->window > 7)
235 return LAPB_INVALUE;
236 }
237
238 lapb->mode = parms->mode;
239 lapb->window = parms->window;
240 }
241
242 lapb->t1 = parms->t1 * HZ;
243 lapb->t2 = parms->t2 * HZ;
244 lapb->n2 = parms->n2;
245
246 return LAPB_OK;
247 }
248
249 int lapb_connect_request(void *token)
250 {
251 lapb_cb *lapb;
252
253 if ((lapb = lapb_tokentostruct(token)) == NULL)
254 return LAPB_BADTOKEN;
255
256 switch (lapb->state) {
257 case LAPB_STATE_1:
258 return LAPB_OK;
259 case LAPB_STATE_3:
260 case LAPB_STATE_4:
261 return LAPB_CONNECTED;
262 }
263
264 lapb_establish_data_link(lapb);
265
266 #if LAPB_DEBUG > 0
267 printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->token);
268 #endif
269
270 lapb->state = LAPB_STATE_1;
271
272 return LAPB_OK;
273 }
274
275 int lapb_disconnect_request(void *token)
276 {
277 lapb_cb *lapb;
278
279 if ((lapb = lapb_tokentostruct(token)) == NULL)
280 return LAPB_BADTOKEN;
281
282 switch (lapb->state) {
283 case LAPB_STATE_0:
284 return LAPB_NOTCONNECTED;
285
286 case LAPB_STATE_1:
287 #if LAPB_DEBUG > 1
288 printk(KERN_DEBUG "lapb: (%p) S1 TX DISC(1)\n", lapb->token);
289 #endif
290 #if LAPB_DEBUG > 0
291 printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token);
292 #endif
293 lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
294 lapb->state = LAPB_STATE_0;
295 lapb_start_t1timer(lapb);
296 return LAPB_NOTCONNECTED;
297
298 case LAPB_STATE_2:
299 return LAPB_OK;
300 }
301
302 lapb_clear_queues(lapb);
303 lapb->n2count = 0;
304 lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
305 lapb_start_t1timer(lapb);
306 lapb_stop_t2timer(lapb);
307 lapb->state = LAPB_STATE_2;
308
309 #if LAPB_DEBUG > 1
310 printk(KERN_DEBUG "lapb: (%p) S3 DISC(1)\n", lapb->token);
311 #endif
312 #if LAPB_DEBUG > 0
313 printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->token);
314 #endif
315
316 return LAPB_OK;
317 }
318
319 int lapb_data_request(void *token, struct sk_buff *skb)
320 {
321 lapb_cb *lapb;
322
323 if ((lapb = lapb_tokentostruct(token)) == NULL)
324 return LAPB_BADTOKEN;
325
326 if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4)
327 return LAPB_NOTCONNECTED;
328
329 skb_queue_tail(&lapb->write_queue, skb);
330
331 lapb_kick(lapb);
332
333 return LAPB_OK;
334 }
335
336 int lapb_data_received(void *token, struct sk_buff *skb)
337 {
338 lapb_cb *lapb;
339
340 if ((lapb = lapb_tokentostruct(token)) == NULL)
341 return LAPB_BADTOKEN;
342
343 lapb_data_input(lapb, skb);
344
345 return LAPB_OK;
346 }
347
348 void lapb_connect_confirmation(lapb_cb *lapb, int reason)
349 {
350 if (lapb->callbacks.connect_confirmation != NULL)
351 (lapb->callbacks.connect_confirmation)(lapb->token, reason);
352 }
353
354 void lapb_connect_indication(lapb_cb *lapb, int reason)
355 {
356 if (lapb->callbacks.connect_indication != NULL)
357 (lapb->callbacks.connect_indication)(lapb->token, reason);
358 }
359
360 void lapb_disconnect_confirmation(lapb_cb *lapb, int reason)
361 {
362 if (lapb->callbacks.disconnect_confirmation != NULL)
363 (lapb->callbacks.disconnect_confirmation)(lapb->token, reason);
364 }
365
366 void lapb_disconnect_indication(lapb_cb *lapb, int reason)
367 {
368 if (lapb->callbacks.disconnect_indication != NULL)
369 (lapb->callbacks.disconnect_indication)(lapb->token, reason);
370 }
371
372 int lapb_data_indication(lapb_cb *lapb, struct sk_buff *skb)
373 {
374 if (lapb->callbacks.data_indication != NULL) {
375 return (lapb->callbacks.data_indication)(lapb->token, skb);
376 }
377 kfree_skb(skb);
378 return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */
379 }
380
381 int lapb_data_transmit(lapb_cb *lapb, struct sk_buff *skb)
382 {
383 int used = 0;
384
385 if (lapb->callbacks.data_transmit != NULL) {
386 (lapb->callbacks.data_transmit)(lapb->token, skb);
387 used = 1;
388 }
389
390 return used;
391 }
392
393 EXPORT_SYMBOL(lapb_register);
394 EXPORT_SYMBOL(lapb_unregister);
395 EXPORT_SYMBOL(lapb_getparms);
396 EXPORT_SYMBOL(lapb_setparms);
397 EXPORT_SYMBOL(lapb_connect_request);
398 EXPORT_SYMBOL(lapb_disconnect_request);
399 EXPORT_SYMBOL(lapb_data_request);
400 EXPORT_SYMBOL(lapb_data_received);
401
402 static int __init lapb_init(void)
403 {
404 printk(KERN_INFO "NET4: LAPB for Linux. Version 0.01 for NET4.0\n");
405 return 0;
406 }
407
408 #ifdef MODULE
409 MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
410 MODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol");
411 #endif
412
413
414 module_init(lapb_init);
415
416 #endif
417
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.