fc71309e7e9b1b3ae7d7c76a1cf36428d18ea537
[linux-flexiantxendom0-3.2.10.git] / net / lapb / lapb_iface.c
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
42 static struct list_head lapb_list = LIST_HEAD_INIT(lapb_list);
43 static rwlock_t lapb_list_lock = RW_LOCK_UNLOCKED;
44
45 /*
46  *      Free an allocated lapb control block. 
47  */
48 static void lapb_free_cb(struct lapb_cb *lapb)
49 {
50         kfree(lapb);
51 }
52
53 static __inline__ void lapb_hold(struct lapb_cb *lapb)
54 {
55         atomic_inc(&lapb->refcnt);
56 }
57
58 static __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  */
67 static 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  */
78 static void __lapb_insert_cb(struct lapb_cb *lapb)
79 {
80         list_add(&lapb->node, &lapb_list);
81         lapb_hold(lapb);
82 }
83
84 /*
85  *      Convert the integer token used by the device driver into a pointer
86  *      to a LAPB control structure.
87  */
88 static struct lapb_cb *__lapb_tokentostruct(void *token)
89 {
90         struct list_head *entry;
91         struct lapb_cb *lapb, *use = NULL;
92
93         list_for_each(entry, &lapb_list) {
94                 lapb = list_entry(entry, struct lapb_cb, node);
95                 if (lapb->token == token) {
96                         use = lapb;
97                         break;
98                 }
99         }
100
101         if (use)
102                 lapb_hold(use);
103
104         return use;
105 }
106
107 static struct lapb_cb *lapb_tokentostruct(void *token)
108 {
109         struct lapb_cb *rc;
110
111         read_lock_bh(&lapb_list_lock);
112         rc = __lapb_tokentostruct(token);
113         read_unlock_bh(&lapb_list_lock);
114
115         return rc;
116 }
117 /*
118  *      Create an empty LAPB control block.
119  */
120 static struct lapb_cb *lapb_create_cb(void)
121 {
122         struct lapb_cb *lapb = kmalloc(sizeof(*lapb), GFP_ATOMIC);
123
124
125         if (!lapb)
126                 goto out;
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         atomic_set(&lapb->refcnt, 1);
143 out:
144         return lapb;
145 }
146
147 int lapb_register(void *token, struct lapb_register_struct *callbacks)
148 {
149         struct lapb_cb *lapb;
150         int rc = LAPB_BADTOKEN;
151
152         write_lock_bh(&lapb_list_lock);
153
154         lapb = __lapb_tokentostruct(token);
155         if (lapb) {
156                 lapb_put(lapb);
157                 goto out;
158         }
159
160         lapb = lapb_create_cb();
161         rc = LAPB_NOMEM;
162         if (!lapb)
163                 goto out;
164
165         lapb->token     = token;
166         lapb->callbacks = *callbacks;
167
168         __lapb_insert_cb(lapb);
169
170         lapb_start_t1timer(lapb);
171
172         rc = LAPB_OK;
173 out:
174         write_unlock_bh(&lapb_list_lock);
175         return rc;
176 }
177
178 int lapb_unregister(void *token)
179 {
180         struct lapb_cb *lapb;
181         int rc = LAPB_BADTOKEN;
182
183         write_unlock_bh(&lapb_list_lock);
184         lapb = __lapb_tokentostruct(token);
185         if (!lapb)
186                 goto out;
187
188         lapb_stop_t1timer(lapb);
189         lapb_stop_t2timer(lapb);
190
191         lapb_clear_queues(lapb);
192
193         __lapb_remove_cb(lapb);
194
195         lapb_put(lapb);
196         rc = LAPB_OK;
197 out:
198         write_unlock_bh(&lapb_list_lock);
199         return rc;
200 }
201
202 int lapb_getparms(void *token, struct lapb_parms_struct *parms)
203 {
204         int rc = LAPB_BADTOKEN;
205         struct lapb_cb *lapb = lapb_tokentostruct(token);
206
207         if (!lapb)
208                 goto out;
209
210         parms->t1      = lapb->t1 / HZ;
211         parms->t2      = lapb->t2 / HZ;
212         parms->n2      = lapb->n2;
213         parms->n2count = lapb->n2count;
214         parms->state   = lapb->state;
215         parms->window  = lapb->window;
216         parms->mode    = lapb->mode;
217
218         if (!timer_pending(&lapb->t1timer))
219                 parms->t1timer = 0;
220         else
221                 parms->t1timer = (lapb->t1timer.expires - jiffies) / HZ;
222
223         if (!timer_pending(&lapb->t2timer))
224                 parms->t2timer = 0;
225         else
226                 parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ;
227
228         lapb_put(lapb);
229         rc = LAPB_OK;
230 out:
231         return rc;
232 }
233
234 int lapb_setparms(void *token, struct lapb_parms_struct *parms)
235 {
236         int rc = LAPB_BADTOKEN;
237         struct lapb_cb *lapb = lapb_tokentostruct(token);
238
239         if (!lapb)
240                 goto out;
241
242         rc = LAPB_INVALUE;
243         if (parms->t1 < 1 || parms->t2 < 1 || parms->n2 < 1)
244                 goto out_put;
245
246         if (lapb->state == LAPB_STATE_0) {
247                 if (((parms->mode & LAPB_EXTENDED) &&
248                      (parms->window < 1 || parms->window > 127)) ||
249                     (parms->window < 1 || parms->window > 7))
250                         goto out_put;
251
252                 lapb->mode    = parms->mode;
253                 lapb->window  = parms->window;
254         }
255
256         lapb->t1    = parms->t1 * HZ;
257         lapb->t2    = parms->t2 * HZ;
258         lapb->n2    = parms->n2;
259
260         rc = LAPB_OK;
261 out_put:
262         lapb_put(lapb);
263 out:
264         return rc;
265 }
266
267 int lapb_connect_request(void *token)
268 {
269         struct lapb_cb *lapb = lapb_tokentostruct(token);
270         int rc = LAPB_BADTOKEN;
271
272         if (!lapb)
273                 goto out;
274
275         rc = LAPB_OK;
276         if (lapb->state == LAPB_STATE_1)
277                 goto out_put;
278
279         rc = LAPB_CONNECTED;
280         if (lapb->state == LAPB_STATE_3 || lapb->state == LAPB_STATE_4)
281                 goto out_put;
282
283         lapb_establish_data_link(lapb);
284
285 #if LAPB_DEBUG > 0
286         printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->token);
287 #endif
288         lapb->state = LAPB_STATE_1;
289
290         rc = LAPB_OK;
291 out_put:
292         lapb_put(lapb);
293 out:
294         return rc;
295 }
296
297 int lapb_disconnect_request(void *token)
298 {
299         struct lapb_cb *lapb = lapb_tokentostruct(token);
300         int rc = LAPB_BADTOKEN;
301
302         if (!lapb)
303                 goto out;
304
305         switch (lapb->state) {
306                 case LAPB_STATE_0:
307                         rc = LAPB_NOTCONNECTED;
308                         goto out_put;
309
310                 case LAPB_STATE_1:
311 #if LAPB_DEBUG > 1
312                         printk(KERN_DEBUG "lapb: (%p) S1 TX DISC(1)\n", lapb->token);
313 #endif
314 #if LAPB_DEBUG > 0
315                         printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token);
316 #endif
317                         lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
318                         lapb->state = LAPB_STATE_0;
319                         lapb_start_t1timer(lapb);
320                         rc = LAPB_NOTCONNECTED;
321                         goto out_put;
322
323                 case LAPB_STATE_2:
324                         rc = LAPB_OK;
325                         goto out_put;
326         }
327
328         lapb_clear_queues(lapb);
329         lapb->n2count = 0;
330         lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
331         lapb_start_t1timer(lapb);
332         lapb_stop_t2timer(lapb);
333         lapb->state = LAPB_STATE_2;
334
335 #if LAPB_DEBUG > 1
336         printk(KERN_DEBUG "lapb: (%p) S3 DISC(1)\n", lapb->token);
337 #endif
338 #if LAPB_DEBUG > 0
339         printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->token);
340 #endif
341
342         rc = LAPB_OK;
343 out_put:
344         lapb_put(lapb);
345 out:
346         return rc;
347 }
348
349 int lapb_data_request(void *token, struct sk_buff *skb)
350 {
351         struct lapb_cb *lapb = lapb_tokentostruct(token);
352         int rc = LAPB_BADTOKEN;
353
354         if (!lapb)
355                 goto out;
356
357         rc = LAPB_NOTCONNECTED;
358         if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4)
359                 goto out_put;
360
361         skb_queue_tail(&lapb->write_queue, skb);
362         lapb_kick(lapb);
363         rc = LAPB_OK;
364 out_put:
365         lapb_put(lapb);
366 out:
367         return rc;
368 }
369
370 int lapb_data_received(void *token, struct sk_buff *skb)
371 {
372         struct lapb_cb *lapb = lapb_tokentostruct(token);
373         int rc = LAPB_BADTOKEN;
374
375         if (lapb) {
376                 lapb_data_input(lapb, skb);
377                 lapb_put(lapb);
378                 rc = LAPB_OK;
379         }
380
381         return rc;
382 }
383
384 void lapb_connect_confirmation(struct lapb_cb *lapb, int reason)
385 {
386         if (lapb->callbacks.connect_confirmation)
387                 lapb->callbacks.connect_confirmation(lapb->token, reason);
388 }
389
390 void lapb_connect_indication(struct lapb_cb *lapb, int reason)
391 {
392         if (lapb->callbacks.connect_indication)
393                 lapb->callbacks.connect_indication(lapb->token, reason);
394 }
395
396 void lapb_disconnect_confirmation(struct lapb_cb *lapb, int reason)
397 {
398         if (lapb->callbacks.disconnect_confirmation)
399                 lapb->callbacks.disconnect_confirmation(lapb->token, reason);
400 }
401
402 void lapb_disconnect_indication(struct lapb_cb *lapb, int reason)
403 {
404         if (lapb->callbacks.disconnect_indication)
405                 lapb->callbacks.disconnect_indication(lapb->token, reason);
406 }
407
408 int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb)
409 {
410         if (lapb->callbacks.data_indication)
411                 return lapb->callbacks.data_indication(lapb->token, skb);
412
413         kfree_skb(skb);
414         return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */ 
415 }
416
417 int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb)
418 {
419         int used = 0;
420
421         if (lapb->callbacks.data_transmit) {
422                 lapb->callbacks.data_transmit(lapb->token, skb);
423                 used = 1;
424         }
425
426         return used;
427 }
428
429 EXPORT_SYMBOL(lapb_register);
430 EXPORT_SYMBOL(lapb_unregister);
431 EXPORT_SYMBOL(lapb_getparms);
432 EXPORT_SYMBOL(lapb_setparms);
433 EXPORT_SYMBOL(lapb_connect_request);
434 EXPORT_SYMBOL(lapb_disconnect_request);
435 EXPORT_SYMBOL(lapb_data_request);
436 EXPORT_SYMBOL(lapb_data_received);
437
438 static int __init lapb_init(void)
439 {
440         return 0;
441 }
442
443 static void __exit lapb_exit(void)
444 {
445         WARN_ON(!list_empty(&lapb_list));
446 }
447
448 MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
449 MODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol");
450 MODULE_LICENSE("GPL");
451
452 module_init(lapb_init);
453 module_exit(lapb_exit);