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