xref: /linux/net/lapb/lapb_iface.c (revision 16ace88405fba82b9c86aeac824d82072ff89c0f)
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  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19  
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/jiffies.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 <linux/slab.h>
35  #include <net/sock.h>
36  #include <linux/uaccess.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 LIST_HEAD(lapb_list);
45  static DEFINE_RWLOCK(lapb_list_lock);
46  
47  /*
48   *	Free an allocated lapb control block.
49   */
50  static void lapb_free_cb(struct lapb_cb *lapb)
51  {
52  	kfree(lapb);
53  }
54  
55  static __inline__ void lapb_hold(struct lapb_cb *lapb)
56  {
57  	refcount_inc(&lapb->refcnt);
58  }
59  
60  static __inline__ void lapb_put(struct lapb_cb *lapb)
61  {
62  	if (refcount_dec_and_test(&lapb->refcnt))
63  		lapb_free_cb(lapb);
64  }
65  
66  /*
67   *	Socket removal during an interrupt is now safe.
68   */
69  static void __lapb_remove_cb(struct lapb_cb *lapb)
70  {
71  	if (lapb->node.next) {
72  		list_del(&lapb->node);
73  		lapb_put(lapb);
74  	}
75  }
76  EXPORT_SYMBOL(lapb_register);
77  
78  /*
79   *	Add a socket to the bound sockets list.
80   */
81  static void __lapb_insert_cb(struct lapb_cb *lapb)
82  {
83  	list_add(&lapb->node, &lapb_list);
84  	lapb_hold(lapb);
85  }
86  
87  static struct lapb_cb *__lapb_devtostruct(struct net_device *dev)
88  {
89  	struct list_head *entry;
90  	struct lapb_cb *lapb, *use = NULL;
91  
92  	list_for_each(entry, &lapb_list) {
93  		lapb = list_entry(entry, struct lapb_cb, node);
94  		if (lapb->dev == dev) {
95  			use = lapb;
96  			break;
97  		}
98  	}
99  
100  	if (use)
101  		lapb_hold(use);
102  
103  	return use;
104  }
105  
106  static struct lapb_cb *lapb_devtostruct(struct net_device *dev)
107  {
108  	struct lapb_cb *rc;
109  
110  	read_lock_bh(&lapb_list_lock);
111  	rc = __lapb_devtostruct(dev);
112  	read_unlock_bh(&lapb_list_lock);
113  
114  	return rc;
115  }
116  /*
117   *	Create an empty LAPB control block.
118   */
119  static struct lapb_cb *lapb_create_cb(void)
120  {
121  	struct lapb_cb *lapb = kzalloc(sizeof(*lapb), GFP_ATOMIC);
122  
123  
124  	if (!lapb)
125  		goto out;
126  
127  	skb_queue_head_init(&lapb->write_queue);
128  	skb_queue_head_init(&lapb->ack_queue);
129  
130  	timer_setup(&lapb->t1timer, NULL, 0);
131  	timer_setup(&lapb->t2timer, NULL, 0);
132  
133  	lapb->t1      = LAPB_DEFAULT_T1;
134  	lapb->t2      = LAPB_DEFAULT_T2;
135  	lapb->n2      = LAPB_DEFAULT_N2;
136  	lapb->mode    = LAPB_DEFAULT_MODE;
137  	lapb->window  = LAPB_DEFAULT_WINDOW;
138  	lapb->state   = LAPB_STATE_0;
139  	refcount_set(&lapb->refcnt, 1);
140  out:
141  	return lapb;
142  }
143  
144  int lapb_register(struct net_device *dev,
145  		  const struct lapb_register_struct *callbacks)
146  {
147  	struct lapb_cb *lapb;
148  	int rc = LAPB_BADTOKEN;
149  
150  	write_lock_bh(&lapb_list_lock);
151  
152  	lapb = __lapb_devtostruct(dev);
153  	if (lapb) {
154  		lapb_put(lapb);
155  		goto out;
156  	}
157  
158  	lapb = lapb_create_cb();
159  	rc = LAPB_NOMEM;
160  	if (!lapb)
161  		goto out;
162  
163  	lapb->dev       = dev;
164  	lapb->callbacks = callbacks;
165  
166  	__lapb_insert_cb(lapb);
167  
168  	lapb_start_t1timer(lapb);
169  
170  	rc = LAPB_OK;
171  out:
172  	write_unlock_bh(&lapb_list_lock);
173  	return rc;
174  }
175  
176  int lapb_unregister(struct net_device *dev)
177  {
178  	struct lapb_cb *lapb;
179  	int rc = LAPB_BADTOKEN;
180  
181  	write_lock_bh(&lapb_list_lock);
182  	lapb = __lapb_devtostruct(dev);
183  	if (!lapb)
184  		goto out;
185  
186  	lapb_stop_t1timer(lapb);
187  	lapb_stop_t2timer(lapb);
188  
189  	lapb_clear_queues(lapb);
190  
191  	__lapb_remove_cb(lapb);
192  
193  	lapb_put(lapb);
194  	rc = LAPB_OK;
195  out:
196  	write_unlock_bh(&lapb_list_lock);
197  	return rc;
198  }
199  EXPORT_SYMBOL(lapb_unregister);
200  
201  int lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms)
202  {
203  	int rc = LAPB_BADTOKEN;
204  	struct lapb_cb *lapb = lapb_devtostruct(dev);
205  
206  	if (!lapb)
207  		goto out;
208  
209  	parms->t1      = lapb->t1 / HZ;
210  	parms->t2      = lapb->t2 / HZ;
211  	parms->n2      = lapb->n2;
212  	parms->n2count = lapb->n2count;
213  	parms->state   = lapb->state;
214  	parms->window  = lapb->window;
215  	parms->mode    = lapb->mode;
216  
217  	if (!timer_pending(&lapb->t1timer))
218  		parms->t1timer = 0;
219  	else
220  		parms->t1timer = (lapb->t1timer.expires - jiffies) / HZ;
221  
222  	if (!timer_pending(&lapb->t2timer))
223  		parms->t2timer = 0;
224  	else
225  		parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ;
226  
227  	lapb_put(lapb);
228  	rc = LAPB_OK;
229  out:
230  	return rc;
231  }
232  EXPORT_SYMBOL(lapb_getparms);
233  
234  int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms)
235  {
236  	int rc = LAPB_BADTOKEN;
237  	struct lapb_cb *lapb = lapb_devtostruct(dev);
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  			if (parms->window < 1 || parms->window > 127)
249  				goto out_put;
250  		} else {
251  			if (parms->window < 1 || parms->window > 7)
252  				goto out_put;
253  		}
254  		lapb->mode    = parms->mode;
255  		lapb->window  = parms->window;
256  	}
257  
258  	lapb->t1    = parms->t1 * HZ;
259  	lapb->t2    = parms->t2 * HZ;
260  	lapb->n2    = parms->n2;
261  
262  	rc = LAPB_OK;
263  out_put:
264  	lapb_put(lapb);
265  out:
266  	return rc;
267  }
268  EXPORT_SYMBOL(lapb_setparms);
269  
270  int lapb_connect_request(struct net_device *dev)
271  {
272  	struct lapb_cb *lapb = lapb_devtostruct(dev);
273  	int rc = LAPB_BADTOKEN;
274  
275  	if (!lapb)
276  		goto out;
277  
278  	rc = LAPB_OK;
279  	if (lapb->state == LAPB_STATE_1)
280  		goto out_put;
281  
282  	rc = LAPB_CONNECTED;
283  	if (lapb->state == LAPB_STATE_3 || lapb->state == LAPB_STATE_4)
284  		goto out_put;
285  
286  	lapb_establish_data_link(lapb);
287  
288  	lapb_dbg(0, "(%p) S0 -> S1\n", lapb->dev);
289  	lapb->state = LAPB_STATE_1;
290  
291  	rc = LAPB_OK;
292  out_put:
293  	lapb_put(lapb);
294  out:
295  	return rc;
296  }
297  EXPORT_SYMBOL(lapb_connect_request);
298  
299  int lapb_disconnect_request(struct net_device *dev)
300  {
301  	struct lapb_cb *lapb = lapb_devtostruct(dev);
302  	int rc = LAPB_BADTOKEN;
303  
304  	if (!lapb)
305  		goto out;
306  
307  	switch (lapb->state) {
308  	case LAPB_STATE_0:
309  		rc = LAPB_NOTCONNECTED;
310  		goto out_put;
311  
312  	case LAPB_STATE_1:
313  		lapb_dbg(1, "(%p) S1 TX DISC(1)\n", lapb->dev);
314  		lapb_dbg(0, "(%p) S1 -> S0\n", lapb->dev);
315  		lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
316  		lapb->state = LAPB_STATE_0;
317  		lapb_start_t1timer(lapb);
318  		rc = LAPB_NOTCONNECTED;
319  		goto out_put;
320  
321  	case LAPB_STATE_2:
322  		rc = LAPB_OK;
323  		goto out_put;
324  	}
325  
326  	lapb_clear_queues(lapb);
327  	lapb->n2count = 0;
328  	lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
329  	lapb_start_t1timer(lapb);
330  	lapb_stop_t2timer(lapb);
331  	lapb->state = LAPB_STATE_2;
332  
333  	lapb_dbg(1, "(%p) S3 DISC(1)\n", lapb->dev);
334  	lapb_dbg(0, "(%p) S3 -> S2\n", lapb->dev);
335  
336  	rc = LAPB_OK;
337  out_put:
338  	lapb_put(lapb);
339  out:
340  	return rc;
341  }
342  EXPORT_SYMBOL(lapb_disconnect_request);
343  
344  int lapb_data_request(struct net_device *dev, struct sk_buff *skb)
345  {
346  	struct lapb_cb *lapb = lapb_devtostruct(dev);
347  	int rc = LAPB_BADTOKEN;
348  
349  	if (!lapb)
350  		goto out;
351  
352  	rc = LAPB_NOTCONNECTED;
353  	if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4)
354  		goto out_put;
355  
356  	skb_queue_tail(&lapb->write_queue, skb);
357  	lapb_kick(lapb);
358  	rc = LAPB_OK;
359  out_put:
360  	lapb_put(lapb);
361  out:
362  	return rc;
363  }
364  EXPORT_SYMBOL(lapb_data_request);
365  
366  int 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  EXPORT_SYMBOL(lapb_data_received);
380  
381  void lapb_connect_confirmation(struct lapb_cb *lapb, int reason)
382  {
383  	if (lapb->callbacks->connect_confirmation)
384  		lapb->callbacks->connect_confirmation(lapb->dev, reason);
385  }
386  
387  void lapb_connect_indication(struct lapb_cb *lapb, int reason)
388  {
389  	if (lapb->callbacks->connect_indication)
390  		lapb->callbacks->connect_indication(lapb->dev, reason);
391  }
392  
393  void lapb_disconnect_confirmation(struct lapb_cb *lapb, int reason)
394  {
395  	if (lapb->callbacks->disconnect_confirmation)
396  		lapb->callbacks->disconnect_confirmation(lapb->dev, reason);
397  }
398  
399  void lapb_disconnect_indication(struct lapb_cb *lapb, int reason)
400  {
401  	if (lapb->callbacks->disconnect_indication)
402  		lapb->callbacks->disconnect_indication(lapb->dev, reason);
403  }
404  
405  int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb)
406  {
407  	if (lapb->callbacks->data_indication)
408  		return lapb->callbacks->data_indication(lapb->dev, skb);
409  
410  	kfree_skb(skb);
411  	return NET_RX_SUCCESS; /* For now; must be != NET_RX_DROP */
412  }
413  
414  int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb)
415  {
416  	int used = 0;
417  
418  	if (lapb->callbacks->data_transmit) {
419  		lapb->callbacks->data_transmit(lapb->dev, skb);
420  		used = 1;
421  	}
422  
423  	return used;
424  }
425  
426  static int __init lapb_init(void)
427  {
428  	return 0;
429  }
430  
431  static void __exit lapb_exit(void)
432  {
433  	WARN_ON(!list_empty(&lapb_list));
434  }
435  
436  MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
437  MODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol");
438  MODULE_LICENSE("GPL");
439  
440  module_init(lapb_init);
441  module_exit(lapb_exit);
442