xref: /OK3568_Linux_fs/kernel/drivers/net/wan/lapbether.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *	"LAPB via ethernet" driver release 001
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *	This code REQUIRES 2.1.15 or higher/ NET3.038
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  *	This is a "pseudo" network driver to allow LAPB over Ethernet.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  *	This driver can use any ethernet destination address, and can be
10*4882a593Smuzhiyun  *	limited to accept frames from one dedicated ethernet card only.
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  *	History
13*4882a593Smuzhiyun  *	LAPBETH 001	Jonathan Naylor		Cloned from bpqether.c
14*4882a593Smuzhiyun  *	2000-10-29	Henner Eisen	lapb_data_indication() return status.
15*4882a593Smuzhiyun  *	2000-11-14	Henner Eisen	dev_hold/put, NETDEV_GOING_DOWN support
16*4882a593Smuzhiyun  */
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <linux/errno.h>
21*4882a593Smuzhiyun #include <linux/types.h>
22*4882a593Smuzhiyun #include <linux/socket.h>
23*4882a593Smuzhiyun #include <linux/in.h>
24*4882a593Smuzhiyun #include <linux/slab.h>
25*4882a593Smuzhiyun #include <linux/kernel.h>
26*4882a593Smuzhiyun #include <linux/string.h>
27*4882a593Smuzhiyun #include <linux/net.h>
28*4882a593Smuzhiyun #include <linux/inet.h>
29*4882a593Smuzhiyun #include <linux/netdevice.h>
30*4882a593Smuzhiyun #include <linux/if_arp.h>
31*4882a593Smuzhiyun #include <linux/skbuff.h>
32*4882a593Smuzhiyun #include <net/sock.h>
33*4882a593Smuzhiyun #include <linux/uaccess.h>
34*4882a593Smuzhiyun #include <linux/mm.h>
35*4882a593Smuzhiyun #include <linux/interrupt.h>
36*4882a593Smuzhiyun #include <linux/notifier.h>
37*4882a593Smuzhiyun #include <linux/stat.h>
38*4882a593Smuzhiyun #include <linux/module.h>
39*4882a593Smuzhiyun #include <linux/lapb.h>
40*4882a593Smuzhiyun #include <linux/init.h>
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #include <net/x25device.h>
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun static const u8 bcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun /* If this number is made larger, check that the temporary string buffer
47*4882a593Smuzhiyun  * in lapbeth_new_device is large enough to store the probe device name.*/
48*4882a593Smuzhiyun #define MAXLAPBDEV 100
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun struct lapbethdev {
51*4882a593Smuzhiyun 	struct list_head	node;
52*4882a593Smuzhiyun 	struct net_device	*ethdev;	/* link to ethernet device */
53*4882a593Smuzhiyun 	struct net_device	*axdev;		/* lapbeth device (lapb#) */
54*4882a593Smuzhiyun 	bool			up;
55*4882a593Smuzhiyun 	spinlock_t		up_lock;	/* Protects "up" */
56*4882a593Smuzhiyun };
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun static LIST_HEAD(lapbeth_devices);
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun /* ------------------------------------------------------------------------ */
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun /*
63*4882a593Smuzhiyun  *	Get the LAPB device for the ethernet device
64*4882a593Smuzhiyun  */
lapbeth_get_x25_dev(struct net_device * dev)65*4882a593Smuzhiyun static struct lapbethdev *lapbeth_get_x25_dev(struct net_device *dev)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	struct lapbethdev *lapbeth;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	list_for_each_entry_rcu(lapbeth, &lapbeth_devices, node, lockdep_rtnl_is_held()) {
70*4882a593Smuzhiyun 		if (lapbeth->ethdev == dev)
71*4882a593Smuzhiyun 			return lapbeth;
72*4882a593Smuzhiyun 	}
73*4882a593Smuzhiyun 	return NULL;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
dev_is_ethdev(struct net_device * dev)76*4882a593Smuzhiyun static __inline__ int dev_is_ethdev(struct net_device *dev)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	return dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5);
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun /* ------------------------------------------------------------------------ */
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun /*
84*4882a593Smuzhiyun  *	Receive a LAPB frame via an ethernet interface.
85*4882a593Smuzhiyun  */
lapbeth_rcv(struct sk_buff * skb,struct net_device * dev,struct packet_type * ptype,struct net_device * orig_dev)86*4882a593Smuzhiyun static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	int len, err;
89*4882a593Smuzhiyun 	struct lapbethdev *lapbeth;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	if (dev_net(dev) != &init_net)
92*4882a593Smuzhiyun 		goto drop;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
95*4882a593Smuzhiyun 		return NET_RX_DROP;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	if (!pskb_may_pull(skb, 2))
98*4882a593Smuzhiyun 		goto drop;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	rcu_read_lock();
101*4882a593Smuzhiyun 	lapbeth = lapbeth_get_x25_dev(dev);
102*4882a593Smuzhiyun 	if (!lapbeth)
103*4882a593Smuzhiyun 		goto drop_unlock_rcu;
104*4882a593Smuzhiyun 	spin_lock_bh(&lapbeth->up_lock);
105*4882a593Smuzhiyun 	if (!lapbeth->up)
106*4882a593Smuzhiyun 		goto drop_unlock;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	len = skb->data[0] + skb->data[1] * 256;
109*4882a593Smuzhiyun 	dev->stats.rx_packets++;
110*4882a593Smuzhiyun 	dev->stats.rx_bytes += len;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	skb_pull(skb, 2);	/* Remove the length bytes */
113*4882a593Smuzhiyun 	skb_trim(skb, len);	/* Set the length of the data */
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	if ((err = lapb_data_received(lapbeth->axdev, skb)) != LAPB_OK) {
116*4882a593Smuzhiyun 		printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err);
117*4882a593Smuzhiyun 		goto drop_unlock;
118*4882a593Smuzhiyun 	}
119*4882a593Smuzhiyun out:
120*4882a593Smuzhiyun 	spin_unlock_bh(&lapbeth->up_lock);
121*4882a593Smuzhiyun 	rcu_read_unlock();
122*4882a593Smuzhiyun 	return 0;
123*4882a593Smuzhiyun drop_unlock:
124*4882a593Smuzhiyun 	kfree_skb(skb);
125*4882a593Smuzhiyun 	goto out;
126*4882a593Smuzhiyun drop_unlock_rcu:
127*4882a593Smuzhiyun 	rcu_read_unlock();
128*4882a593Smuzhiyun drop:
129*4882a593Smuzhiyun 	kfree_skb(skb);
130*4882a593Smuzhiyun 	return 0;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
lapbeth_data_indication(struct net_device * dev,struct sk_buff * skb)133*4882a593Smuzhiyun static int lapbeth_data_indication(struct net_device *dev, struct sk_buff *skb)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	unsigned char *ptr;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	if (skb_cow(skb, 1)) {
138*4882a593Smuzhiyun 		kfree_skb(skb);
139*4882a593Smuzhiyun 		return NET_RX_DROP;
140*4882a593Smuzhiyun 	}
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	skb_push(skb, 1);
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	ptr  = skb->data;
145*4882a593Smuzhiyun 	*ptr = X25_IFACE_DATA;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	skb->protocol = x25_type_trans(skb, dev);
148*4882a593Smuzhiyun 	return netif_rx(skb);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun /*
152*4882a593Smuzhiyun  *	Send a LAPB frame via an ethernet interface
153*4882a593Smuzhiyun  */
lapbeth_xmit(struct sk_buff * skb,struct net_device * dev)154*4882a593Smuzhiyun static netdev_tx_t lapbeth_xmit(struct sk_buff *skb,
155*4882a593Smuzhiyun 				      struct net_device *dev)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	struct lapbethdev *lapbeth = netdev_priv(dev);
158*4882a593Smuzhiyun 	int err;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	spin_lock_bh(&lapbeth->up_lock);
161*4882a593Smuzhiyun 	if (!lapbeth->up)
162*4882a593Smuzhiyun 		goto drop;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	/* There should be a pseudo header of 1 byte added by upper layers.
165*4882a593Smuzhiyun 	 * Check to make sure it is there before reading it.
166*4882a593Smuzhiyun 	 */
167*4882a593Smuzhiyun 	if (skb->len < 1)
168*4882a593Smuzhiyun 		goto drop;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	switch (skb->data[0]) {
171*4882a593Smuzhiyun 	case X25_IFACE_DATA:
172*4882a593Smuzhiyun 		break;
173*4882a593Smuzhiyun 	case X25_IFACE_CONNECT:
174*4882a593Smuzhiyun 		if ((err = lapb_connect_request(dev)) != LAPB_OK)
175*4882a593Smuzhiyun 			pr_err("lapb_connect_request error: %d\n", err);
176*4882a593Smuzhiyun 		goto drop;
177*4882a593Smuzhiyun 	case X25_IFACE_DISCONNECT:
178*4882a593Smuzhiyun 		if ((err = lapb_disconnect_request(dev)) != LAPB_OK)
179*4882a593Smuzhiyun 			pr_err("lapb_disconnect_request err: %d\n", err);
180*4882a593Smuzhiyun 		fallthrough;
181*4882a593Smuzhiyun 	default:
182*4882a593Smuzhiyun 		goto drop;
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	skb_pull(skb, 1);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	if ((err = lapb_data_request(dev, skb)) != LAPB_OK) {
188*4882a593Smuzhiyun 		pr_err("lapb_data_request error - %d\n", err);
189*4882a593Smuzhiyun 		goto drop;
190*4882a593Smuzhiyun 	}
191*4882a593Smuzhiyun out:
192*4882a593Smuzhiyun 	spin_unlock_bh(&lapbeth->up_lock);
193*4882a593Smuzhiyun 	return NETDEV_TX_OK;
194*4882a593Smuzhiyun drop:
195*4882a593Smuzhiyun 	kfree_skb(skb);
196*4882a593Smuzhiyun 	goto out;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
lapbeth_data_transmit(struct net_device * ndev,struct sk_buff * skb)199*4882a593Smuzhiyun static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	struct lapbethdev *lapbeth = netdev_priv(ndev);
202*4882a593Smuzhiyun 	unsigned char *ptr;
203*4882a593Smuzhiyun 	struct net_device *dev;
204*4882a593Smuzhiyun 	int size = skb->len;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	ptr = skb_push(skb, 2);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	*ptr++ = size % 256;
209*4882a593Smuzhiyun 	*ptr++ = size / 256;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	ndev->stats.tx_packets++;
212*4882a593Smuzhiyun 	ndev->stats.tx_bytes += size;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	skb->dev = dev = lapbeth->ethdev;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	skb->protocol = htons(ETH_P_DEC);
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	skb_reset_network_header(skb);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	dev_hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	dev_queue_xmit(skb);
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun 
lapbeth_connected(struct net_device * dev,int reason)225*4882a593Smuzhiyun static void lapbeth_connected(struct net_device *dev, int reason)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	unsigned char *ptr;
228*4882a593Smuzhiyun 	struct sk_buff *skb = dev_alloc_skb(1);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	if (!skb) {
231*4882a593Smuzhiyun 		pr_err("out of memory\n");
232*4882a593Smuzhiyun 		return;
233*4882a593Smuzhiyun 	}
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	ptr  = skb_put(skb, 1);
236*4882a593Smuzhiyun 	*ptr = X25_IFACE_CONNECT;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	skb->protocol = x25_type_trans(skb, dev);
239*4882a593Smuzhiyun 	netif_rx(skb);
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
lapbeth_disconnected(struct net_device * dev,int reason)242*4882a593Smuzhiyun static void lapbeth_disconnected(struct net_device *dev, int reason)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun 	unsigned char *ptr;
245*4882a593Smuzhiyun 	struct sk_buff *skb = dev_alloc_skb(1);
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	if (!skb) {
248*4882a593Smuzhiyun 		pr_err("out of memory\n");
249*4882a593Smuzhiyun 		return;
250*4882a593Smuzhiyun 	}
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	ptr  = skb_put(skb, 1);
253*4882a593Smuzhiyun 	*ptr = X25_IFACE_DISCONNECT;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	skb->protocol = x25_type_trans(skb, dev);
256*4882a593Smuzhiyun 	netif_rx(skb);
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun /*
260*4882a593Smuzhiyun  *	Set AX.25 callsign
261*4882a593Smuzhiyun  */
lapbeth_set_mac_address(struct net_device * dev,void * addr)262*4882a593Smuzhiyun static int lapbeth_set_mac_address(struct net_device *dev, void *addr)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	struct sockaddr *sa = addr;
265*4882a593Smuzhiyun 	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
266*4882a593Smuzhiyun 	return 0;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun static const struct lapb_register_struct lapbeth_callbacks = {
271*4882a593Smuzhiyun 	.connect_confirmation    = lapbeth_connected,
272*4882a593Smuzhiyun 	.connect_indication      = lapbeth_connected,
273*4882a593Smuzhiyun 	.disconnect_confirmation = lapbeth_disconnected,
274*4882a593Smuzhiyun 	.disconnect_indication   = lapbeth_disconnected,
275*4882a593Smuzhiyun 	.data_indication         = lapbeth_data_indication,
276*4882a593Smuzhiyun 	.data_transmit           = lapbeth_data_transmit,
277*4882a593Smuzhiyun };
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun /*
280*4882a593Smuzhiyun  * open/close a device
281*4882a593Smuzhiyun  */
lapbeth_open(struct net_device * dev)282*4882a593Smuzhiyun static int lapbeth_open(struct net_device *dev)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	struct lapbethdev *lapbeth = netdev_priv(dev);
285*4882a593Smuzhiyun 	int err;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	if ((err = lapb_register(dev, &lapbeth_callbacks)) != LAPB_OK) {
288*4882a593Smuzhiyun 		pr_err("lapb_register error: %d\n", err);
289*4882a593Smuzhiyun 		return -ENODEV;
290*4882a593Smuzhiyun 	}
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	spin_lock_bh(&lapbeth->up_lock);
293*4882a593Smuzhiyun 	lapbeth->up = true;
294*4882a593Smuzhiyun 	spin_unlock_bh(&lapbeth->up_lock);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	return 0;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun 
lapbeth_close(struct net_device * dev)299*4882a593Smuzhiyun static int lapbeth_close(struct net_device *dev)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun 	struct lapbethdev *lapbeth = netdev_priv(dev);
302*4882a593Smuzhiyun 	int err;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	spin_lock_bh(&lapbeth->up_lock);
305*4882a593Smuzhiyun 	lapbeth->up = false;
306*4882a593Smuzhiyun 	spin_unlock_bh(&lapbeth->up_lock);
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	if ((err = lapb_unregister(dev)) != LAPB_OK)
309*4882a593Smuzhiyun 		pr_err("lapb_unregister error: %d\n", err);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	return 0;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun /* ------------------------------------------------------------------------ */
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun static const struct net_device_ops lapbeth_netdev_ops = {
317*4882a593Smuzhiyun 	.ndo_open	     = lapbeth_open,
318*4882a593Smuzhiyun 	.ndo_stop	     = lapbeth_close,
319*4882a593Smuzhiyun 	.ndo_start_xmit	     = lapbeth_xmit,
320*4882a593Smuzhiyun 	.ndo_set_mac_address = lapbeth_set_mac_address,
321*4882a593Smuzhiyun };
322*4882a593Smuzhiyun 
lapbeth_setup(struct net_device * dev)323*4882a593Smuzhiyun static void lapbeth_setup(struct net_device *dev)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	dev->netdev_ops	     = &lapbeth_netdev_ops;
326*4882a593Smuzhiyun 	dev->needs_free_netdev = true;
327*4882a593Smuzhiyun 	dev->type            = ARPHRD_X25;
328*4882a593Smuzhiyun 	dev->hard_header_len = 0;
329*4882a593Smuzhiyun 	dev->mtu             = 1000;
330*4882a593Smuzhiyun 	dev->addr_len        = 0;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun /*
334*4882a593Smuzhiyun  *	Setup a new device.
335*4882a593Smuzhiyun  */
lapbeth_new_device(struct net_device * dev)336*4882a593Smuzhiyun static int lapbeth_new_device(struct net_device *dev)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun 	struct net_device *ndev;
339*4882a593Smuzhiyun 	struct lapbethdev *lapbeth;
340*4882a593Smuzhiyun 	int rc = -ENOMEM;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	ASSERT_RTNL();
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	ndev = alloc_netdev(sizeof(*lapbeth), "lapb%d", NET_NAME_UNKNOWN,
345*4882a593Smuzhiyun 			    lapbeth_setup);
346*4882a593Smuzhiyun 	if (!ndev)
347*4882a593Smuzhiyun 		goto out;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	/* When transmitting data:
350*4882a593Smuzhiyun 	 * first this driver removes a pseudo header of 1 byte,
351*4882a593Smuzhiyun 	 * then the lapb module prepends an LAPB header of at most 3 bytes,
352*4882a593Smuzhiyun 	 * then this driver prepends a length field of 2 bytes,
353*4882a593Smuzhiyun 	 * then the underlying Ethernet device prepends its own header.
354*4882a593Smuzhiyun 	 */
355*4882a593Smuzhiyun 	ndev->needed_headroom = -1 + 3 + 2 + dev->hard_header_len
356*4882a593Smuzhiyun 					   + dev->needed_headroom;
357*4882a593Smuzhiyun 	ndev->needed_tailroom = dev->needed_tailroom;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	lapbeth = netdev_priv(ndev);
360*4882a593Smuzhiyun 	lapbeth->axdev = ndev;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	dev_hold(dev);
363*4882a593Smuzhiyun 	lapbeth->ethdev = dev;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	lapbeth->up = false;
366*4882a593Smuzhiyun 	spin_lock_init(&lapbeth->up_lock);
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	rc = -EIO;
369*4882a593Smuzhiyun 	if (register_netdevice(ndev))
370*4882a593Smuzhiyun 		goto fail;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	list_add_rcu(&lapbeth->node, &lapbeth_devices);
373*4882a593Smuzhiyun 	rc = 0;
374*4882a593Smuzhiyun out:
375*4882a593Smuzhiyun 	return rc;
376*4882a593Smuzhiyun fail:
377*4882a593Smuzhiyun 	dev_put(dev);
378*4882a593Smuzhiyun 	free_netdev(ndev);
379*4882a593Smuzhiyun 	goto out;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun /*
383*4882a593Smuzhiyun  *	Free a lapb network device.
384*4882a593Smuzhiyun  */
lapbeth_free_device(struct lapbethdev * lapbeth)385*4882a593Smuzhiyun static void lapbeth_free_device(struct lapbethdev *lapbeth)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun 	dev_put(lapbeth->ethdev);
388*4882a593Smuzhiyun 	list_del_rcu(&lapbeth->node);
389*4882a593Smuzhiyun 	unregister_netdevice(lapbeth->axdev);
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun /*
393*4882a593Smuzhiyun  *	Handle device status changes.
394*4882a593Smuzhiyun  *
395*4882a593Smuzhiyun  * Called from notifier with RTNL held.
396*4882a593Smuzhiyun  */
lapbeth_device_event(struct notifier_block * this,unsigned long event,void * ptr)397*4882a593Smuzhiyun static int lapbeth_device_event(struct notifier_block *this,
398*4882a593Smuzhiyun 				unsigned long event, void *ptr)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun 	struct lapbethdev *lapbeth;
401*4882a593Smuzhiyun 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	if (dev_net(dev) != &init_net)
404*4882a593Smuzhiyun 		return NOTIFY_DONE;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	if (!dev_is_ethdev(dev) && !lapbeth_get_x25_dev(dev))
407*4882a593Smuzhiyun 		return NOTIFY_DONE;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	switch (event) {
410*4882a593Smuzhiyun 	case NETDEV_UP:
411*4882a593Smuzhiyun 		/* New ethernet device -> new LAPB interface	 */
412*4882a593Smuzhiyun 		if (lapbeth_get_x25_dev(dev) == NULL)
413*4882a593Smuzhiyun 			lapbeth_new_device(dev);
414*4882a593Smuzhiyun 		break;
415*4882a593Smuzhiyun 	case NETDEV_DOWN:
416*4882a593Smuzhiyun 		/* ethernet device closed -> close LAPB interface */
417*4882a593Smuzhiyun 		lapbeth = lapbeth_get_x25_dev(dev);
418*4882a593Smuzhiyun 		if (lapbeth)
419*4882a593Smuzhiyun 			dev_close(lapbeth->axdev);
420*4882a593Smuzhiyun 		break;
421*4882a593Smuzhiyun 	case NETDEV_UNREGISTER:
422*4882a593Smuzhiyun 		/* ethernet device disappears -> remove LAPB interface */
423*4882a593Smuzhiyun 		lapbeth = lapbeth_get_x25_dev(dev);
424*4882a593Smuzhiyun 		if (lapbeth)
425*4882a593Smuzhiyun 			lapbeth_free_device(lapbeth);
426*4882a593Smuzhiyun 		break;
427*4882a593Smuzhiyun 	}
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	return NOTIFY_DONE;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun /* ------------------------------------------------------------------------ */
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun static struct packet_type lapbeth_packet_type __read_mostly = {
435*4882a593Smuzhiyun 	.type = cpu_to_be16(ETH_P_DEC),
436*4882a593Smuzhiyun 	.func = lapbeth_rcv,
437*4882a593Smuzhiyun };
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun static struct notifier_block lapbeth_dev_notifier = {
440*4882a593Smuzhiyun 	.notifier_call = lapbeth_device_event,
441*4882a593Smuzhiyun };
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun static const char banner[] __initconst =
444*4882a593Smuzhiyun 	KERN_INFO "LAPB Ethernet driver version 0.02\n";
445*4882a593Smuzhiyun 
lapbeth_init_driver(void)446*4882a593Smuzhiyun static int __init lapbeth_init_driver(void)
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun 	dev_add_pack(&lapbeth_packet_type);
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	register_netdevice_notifier(&lapbeth_dev_notifier);
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	printk(banner);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	return 0;
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun module_init(lapbeth_init_driver);
457*4882a593Smuzhiyun 
lapbeth_cleanup_driver(void)458*4882a593Smuzhiyun static void __exit lapbeth_cleanup_driver(void)
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun 	struct lapbethdev *lapbeth;
461*4882a593Smuzhiyun 	struct list_head *entry, *tmp;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	dev_remove_pack(&lapbeth_packet_type);
464*4882a593Smuzhiyun 	unregister_netdevice_notifier(&lapbeth_dev_notifier);
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	rtnl_lock();
467*4882a593Smuzhiyun 	list_for_each_safe(entry, tmp, &lapbeth_devices) {
468*4882a593Smuzhiyun 		lapbeth = list_entry(entry, struct lapbethdev, node);
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 		dev_put(lapbeth->ethdev);
471*4882a593Smuzhiyun 		unregister_netdevice(lapbeth->axdev);
472*4882a593Smuzhiyun 	}
473*4882a593Smuzhiyun 	rtnl_unlock();
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun module_exit(lapbeth_cleanup_driver);
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
478*4882a593Smuzhiyun MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver");
479*4882a593Smuzhiyun MODULE_LICENSE("GPL");
480