xref: /openbmc/linux/net/atm/br2684.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
3fb64c735SChas Williams  * Ethernet netdevice using ATM AAL5 as underlying carrier
4fb64c735SChas Williams  * (RFC1483 obsoleted by RFC2684) for Linux
5fb64c735SChas Williams  *
6fb64c735SChas Williams  * Authors: Marcell GAL, 2000, XDSL Ltd, Hungary
7fb64c735SChas Williams  *          Eric Kinzie, 2006-2007, US Naval Research Laboratory
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
1099824461SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
1199824461SJoe Perches 
121da177e4SLinus Torvalds #include <linux/module.h>
131da177e4SLinus Torvalds #include <linux/init.h>
141da177e4SLinus Torvalds #include <linux/kernel.h>
151da177e4SLinus Torvalds #include <linux/list.h>
161da177e4SLinus Torvalds #include <linux/netdevice.h>
171da177e4SLinus Torvalds #include <linux/skbuff.h>
181da177e4SLinus Torvalds #include <linux/etherdevice.h>
191da177e4SLinus Torvalds #include <linux/rtnetlink.h>
201da177e4SLinus Torvalds #include <linux/ip.h>
21641d729eSJoe Perches #include <linux/uaccess.h>
225a0e3ad6STejun Heo #include <linux/slab.h>
231da177e4SLinus Torvalds #include <net/arp.h>
241da177e4SLinus Torvalds #include <linux/atm.h>
251da177e4SLinus Torvalds #include <linux/atmdev.h>
264fc268d2SRandy Dunlap #include <linux/capability.h>
271da177e4SLinus Torvalds #include <linux/seq_file.h>
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #include <linux/atmbr2684.h>
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds #include "common.h"
321da177e4SLinus Torvalds 
skb_debug(const struct sk_buff * skb)331da177e4SLinus Torvalds static void skb_debug(const struct sk_buff *skb)
341da177e4SLinus Torvalds {
35641d729eSJoe Perches #ifdef SKB_DEBUG
361da177e4SLinus Torvalds #define NUM2PRINT 50
37641d729eSJoe Perches 	print_hex_dump(KERN_DEBUG, "br2684: skb: ", DUMP_OFFSET,
38641d729eSJoe Perches 		       16, 1, skb->data, min(NUM2PRINT, skb->len), true);
391da177e4SLinus Torvalds #endif
40641d729eSJoe Perches }
411da177e4SLinus Torvalds 
42097b19a9SEric Kinzie #define BR2684_ETHERTYPE_LEN	2
43097b19a9SEric Kinzie #define BR2684_PAD_LEN		2
44097b19a9SEric Kinzie 
45097b19a9SEric Kinzie #define LLC		0xaa, 0xaa, 0x03
46097b19a9SEric Kinzie #define SNAP_BRIDGED	0x00, 0x80, 0xc2
47097b19a9SEric Kinzie #define SNAP_ROUTED	0x00, 0x00, 0x00
48097b19a9SEric Kinzie #define PID_ETHERNET	0x00, 0x07
49097b19a9SEric Kinzie #define ETHERTYPE_IPV4	0x08, 0x00
50097b19a9SEric Kinzie #define ETHERTYPE_IPV6	0x86, 0xdd
51097b19a9SEric Kinzie #define PAD_BRIDGED	0x00, 0x00
52097b19a9SEric Kinzie 
5361c33e01SMitchell Blank Jr static const unsigned char ethertype_ipv4[] = { ETHERTYPE_IPV4 };
5461c33e01SMitchell Blank Jr static const unsigned char ethertype_ipv6[] = { ETHERTYPE_IPV6 };
5561c33e01SMitchell Blank Jr static const unsigned char llc_oui_pid_pad[] =
56097b19a9SEric Kinzie 			{ LLC, SNAP_BRIDGED, PID_ETHERNET, PAD_BRIDGED };
57befc93feSPascal Hambourg static const unsigned char pad[] = { PAD_BRIDGED };
5861c33e01SMitchell Blank Jr static const unsigned char llc_oui_ipv4[] = { LLC, SNAP_ROUTED, ETHERTYPE_IPV4 };
5961c33e01SMitchell Blank Jr static const unsigned char llc_oui_ipv6[] = { LLC, SNAP_ROUTED, ETHERTYPE_IPV6 };
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds enum br2684_encaps {
621da177e4SLinus Torvalds 	e_vc = BR2684_ENCAPS_VC,
631da177e4SLinus Torvalds 	e_llc = BR2684_ENCAPS_LLC,
641da177e4SLinus Torvalds };
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds struct br2684_vcc {
671da177e4SLinus Torvalds 	struct atm_vcc *atmvcc;
681da177e4SLinus Torvalds 	struct net_device *device;
691da177e4SLinus Torvalds 	/* keep old push, pop functions for chaining */
701da177e4SLinus Torvalds 	void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb);
71137742cfSKarl Hiramoto 	void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb);
72b8958853SDavid Woodhouse 	void (*old_release_cb)(struct atm_vcc *vcc);
73d71ffeb1SDavid Woodhouse 	struct module *old_owner;
741da177e4SLinus Torvalds 	enum br2684_encaps encaps;
751da177e4SLinus Torvalds 	struct list_head brvccs;
761da177e4SLinus Torvalds #ifdef CONFIG_ATM_BR2684_IPFILTER
771da177e4SLinus Torvalds 	struct br2684_filter filter;
781da177e4SLinus Torvalds #endif /* CONFIG_ATM_BR2684_IPFILTER */
7995c96174SEric Dumazet 	unsigned int copies_needed, copies_failed;
80ae088d66SDavid Woodhouse 	atomic_t qspace;
811da177e4SLinus Torvalds };
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds struct br2684_dev {
841da177e4SLinus Torvalds 	struct net_device *net_dev;
851da177e4SLinus Torvalds 	struct list_head br2684_devs;
861da177e4SLinus Torvalds 	int number;
871da177e4SLinus Torvalds 	struct list_head brvccs;	/* one device <=> one vcc (before xmas) */
881da177e4SLinus Torvalds 	int mac_was_set;
89097b19a9SEric Kinzie 	enum br2684_payload payload;
901da177e4SLinus Torvalds };
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds /*
931da177e4SLinus Torvalds  * This lock should be held for writing any time the list of devices or
941da177e4SLinus Torvalds  * their attached vcc's could be altered.  It should be held for reading
951da177e4SLinus Torvalds  * any time these are being queried.  Note that we sometimes need to
964fb473feSgushengxian  * do read-locking under interrupting context, so write locking must block
974fb473feSgushengxian  * the current CPU's interrupts.
981da177e4SLinus Torvalds  */
991da177e4SLinus Torvalds static DEFINE_RWLOCK(devs_lock);
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds static LIST_HEAD(br2684_devs);
1021da177e4SLinus Torvalds 
BRPRIV(const struct net_device * net_dev)1031da177e4SLinus Torvalds static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev)
1041da177e4SLinus Torvalds {
10537d66800SJoe Perches 	return netdev_priv(net_dev);
1061da177e4SLinus Torvalds }
1071da177e4SLinus Torvalds 
list_entry_brdev(const struct list_head * le)1081da177e4SLinus Torvalds static inline struct net_device *list_entry_brdev(const struct list_head *le)
1091da177e4SLinus Torvalds {
1101da177e4SLinus Torvalds 	return list_entry(le, struct br2684_dev, br2684_devs)->net_dev;
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds 
BR2684_VCC(const struct atm_vcc * atmvcc)1131da177e4SLinus Torvalds static inline struct br2684_vcc *BR2684_VCC(const struct atm_vcc *atmvcc)
1141da177e4SLinus Torvalds {
1151da177e4SLinus Torvalds 	return (struct br2684_vcc *)(atmvcc->user_back);
1161da177e4SLinus Torvalds }
1171da177e4SLinus Torvalds 
list_entry_brvcc(const struct list_head * le)1181da177e4SLinus Torvalds static inline struct br2684_vcc *list_entry_brvcc(const struct list_head *le)
1191da177e4SLinus Torvalds {
1201da177e4SLinus Torvalds 	return list_entry(le, struct br2684_vcc, brvccs);
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds /* Caller should hold read_lock(&devs_lock) */
br2684_find_dev(const struct br2684_if_spec * s)1241da177e4SLinus Torvalds static struct net_device *br2684_find_dev(const struct br2684_if_spec *s)
1251da177e4SLinus Torvalds {
1261da177e4SLinus Torvalds 	struct list_head *lh;
1271da177e4SLinus Torvalds 	struct net_device *net_dev;
1281da177e4SLinus Torvalds 	switch (s->method) {
1291da177e4SLinus Torvalds 	case BR2684_FIND_BYNUM:
1301da177e4SLinus Torvalds 		list_for_each(lh, &br2684_devs) {
1311da177e4SLinus Torvalds 			net_dev = list_entry_brdev(lh);
1321da177e4SLinus Torvalds 			if (BRPRIV(net_dev)->number == s->spec.devnum)
1331da177e4SLinus Torvalds 				return net_dev;
1341da177e4SLinus Torvalds 		}
1351da177e4SLinus Torvalds 		break;
1361da177e4SLinus Torvalds 	case BR2684_FIND_BYIFNAME:
1371da177e4SLinus Torvalds 		list_for_each(lh, &br2684_devs) {
1381da177e4SLinus Torvalds 			net_dev = list_entry_brdev(lh);
1391da177e4SLinus Torvalds 			if (!strncmp(net_dev->name, s->spec.ifname, IFNAMSIZ))
1401da177e4SLinus Torvalds 				return net_dev;
1411da177e4SLinus Torvalds 		}
1421da177e4SLinus Torvalds 		break;
1431da177e4SLinus Torvalds 	}
1441da177e4SLinus Torvalds 	return NULL;
1451da177e4SLinus Torvalds }
1461da177e4SLinus Torvalds 
atm_dev_event(struct notifier_block * this,unsigned long event,void * arg)14700506612SKarl Hiramoto static int atm_dev_event(struct notifier_block *this, unsigned long event,
14800506612SKarl Hiramoto 		 void *arg)
14900506612SKarl Hiramoto {
15000506612SKarl Hiramoto 	struct atm_dev *atm_dev = arg;
15100506612SKarl Hiramoto 	struct list_head *lh;
15200506612SKarl Hiramoto 	struct net_device *net_dev;
15300506612SKarl Hiramoto 	struct br2684_vcc *brvcc;
15400506612SKarl Hiramoto 	struct atm_vcc *atm_vcc;
15500506612SKarl Hiramoto 	unsigned long flags;
15600506612SKarl Hiramoto 
15700506612SKarl Hiramoto 	pr_debug("event=%ld dev=%p\n", event, atm_dev);
15800506612SKarl Hiramoto 
15900506612SKarl Hiramoto 	read_lock_irqsave(&devs_lock, flags);
16000506612SKarl Hiramoto 	list_for_each(lh, &br2684_devs) {
16100506612SKarl Hiramoto 		net_dev = list_entry_brdev(lh);
16200506612SKarl Hiramoto 
16300506612SKarl Hiramoto 		list_for_each_entry(brvcc, &BRPRIV(net_dev)->brvccs, brvccs) {
16400506612SKarl Hiramoto 			atm_vcc = brvcc->atmvcc;
16500506612SKarl Hiramoto 			if (atm_vcc && brvcc->atmvcc->dev == atm_dev) {
16600506612SKarl Hiramoto 
16700506612SKarl Hiramoto 				if (atm_vcc->dev->signal == ATM_PHY_SIG_LOST)
16800506612SKarl Hiramoto 					netif_carrier_off(net_dev);
16900506612SKarl Hiramoto 				else
17000506612SKarl Hiramoto 					netif_carrier_on(net_dev);
17100506612SKarl Hiramoto 
17200506612SKarl Hiramoto 			}
17300506612SKarl Hiramoto 		}
17400506612SKarl Hiramoto 	}
17500506612SKarl Hiramoto 	read_unlock_irqrestore(&devs_lock, flags);
17600506612SKarl Hiramoto 
17700506612SKarl Hiramoto 	return NOTIFY_DONE;
17800506612SKarl Hiramoto }
17900506612SKarl Hiramoto 
18000506612SKarl Hiramoto static struct notifier_block atm_dev_notifier = {
18100506612SKarl Hiramoto 	.notifier_call = atm_dev_event,
18200506612SKarl Hiramoto };
18300506612SKarl Hiramoto 
184137742cfSKarl Hiramoto /* chained vcc->pop function.  Check if we should wake the netif_queue */
br2684_pop(struct atm_vcc * vcc,struct sk_buff * skb)185137742cfSKarl Hiramoto static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb)
186137742cfSKarl Hiramoto {
187137742cfSKarl Hiramoto 	struct br2684_vcc *brvcc = BR2684_VCC(vcc);
188137742cfSKarl Hiramoto 
189ae088d66SDavid Woodhouse 	pr_debug("(vcc %p ; net_dev %p )\n", vcc, brvcc->device);
190137742cfSKarl Hiramoto 	brvcc->old_pop(vcc, skb);
191137742cfSKarl Hiramoto 
192ae088d66SDavid Woodhouse 	/* If the queue space just went up from zero, wake */
193ae088d66SDavid Woodhouse 	if (atomic_inc_return(&brvcc->qspace) == 1)
194ae088d66SDavid Woodhouse 		netif_wake_queue(brvcc->device);
195137742cfSKarl Hiramoto }
196ae088d66SDavid Woodhouse 
1971da177e4SLinus Torvalds /*
1981da177e4SLinus Torvalds  * Send a packet out a particular vcc.  Not to useful right now, but paves
1991da177e4SLinus Torvalds  * the way for multiple vcc's per itf.  Returns true if we can send,
2001da177e4SLinus Torvalds  * otherwise false
2011da177e4SLinus Torvalds  */
br2684_xmit_vcc(struct sk_buff * skb,struct net_device * dev,struct br2684_vcc * brvcc)202410e9d8fSStephen Hemminger static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,
2031da177e4SLinus Torvalds 			   struct br2684_vcc *brvcc)
2041da177e4SLinus Torvalds {
205410e9d8fSStephen Hemminger 	struct br2684_dev *brdev = BRPRIV(dev);
2061da177e4SLinus Torvalds 	struct atm_vcc *atmvcc;
2079e667b29SPascal Hambourg 	int minheadroom = (brvcc->encaps == e_llc) ?
2089e667b29SPascal Hambourg 		((brdev->payload == p_bridged) ?
2099e667b29SPascal Hambourg 			sizeof(llc_oui_pid_pad) : sizeof(llc_oui_ipv4)) :
2109e667b29SPascal Hambourg 		((brdev->payload == p_bridged) ? BR2684_PAD_LEN : 0);
211097b19a9SEric Kinzie 
2121da177e4SLinus Torvalds 	if (skb_headroom(skb) < minheadroom) {
2131da177e4SLinus Torvalds 		struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom);
2141da177e4SLinus Torvalds 		brvcc->copies_needed++;
2151da177e4SLinus Torvalds 		dev_kfree_skb(skb);
2161da177e4SLinus Torvalds 		if (skb2 == NULL) {
2171da177e4SLinus Torvalds 			brvcc->copies_failed++;
2181da177e4SLinus Torvalds 			return 0;
2191da177e4SLinus Torvalds 		}
2201da177e4SLinus Torvalds 		skb = skb2;
2211da177e4SLinus Torvalds 	}
222097b19a9SEric Kinzie 
223097b19a9SEric Kinzie 	if (brvcc->encaps == e_llc) {
224097b19a9SEric Kinzie 		if (brdev->payload == p_bridged) {
225097b19a9SEric Kinzie 			skb_push(skb, sizeof(llc_oui_pid_pad));
226fb64c735SChas Williams 			skb_copy_to_linear_data(skb, llc_oui_pid_pad,
227fb64c735SChas Williams 						sizeof(llc_oui_pid_pad));
228097b19a9SEric Kinzie 		} else if (brdev->payload == p_routed) {
229097b19a9SEric Kinzie 			unsigned short prot = ntohs(skb->protocol);
230097b19a9SEric Kinzie 
231097b19a9SEric Kinzie 			skb_push(skb, sizeof(llc_oui_ipv4));
232097b19a9SEric Kinzie 			switch (prot) {
233097b19a9SEric Kinzie 			case ETH_P_IP:
234fb64c735SChas Williams 				skb_copy_to_linear_data(skb, llc_oui_ipv4,
235fb64c735SChas Williams 							sizeof(llc_oui_ipv4));
236097b19a9SEric Kinzie 				break;
237097b19a9SEric Kinzie 			case ETH_P_IPV6:
238fb64c735SChas Williams 				skb_copy_to_linear_data(skb, llc_oui_ipv6,
239fb64c735SChas Williams 							sizeof(llc_oui_ipv6));
240097b19a9SEric Kinzie 				break;
241097b19a9SEric Kinzie 			default:
242097b19a9SEric Kinzie 				dev_kfree_skb(skb);
243097b19a9SEric Kinzie 				return 0;
244097b19a9SEric Kinzie 			}
245097b19a9SEric Kinzie 		}
2467e903c2aSEric Kinzie 	} else { /* e_vc */
2477e903c2aSEric Kinzie 		if (brdev->payload == p_bridged) {
248097b19a9SEric Kinzie 			skb_push(skb, 2);
2491da177e4SLinus Torvalds 			memset(skb->data, 0, 2);
2507e903c2aSEric Kinzie 		}
251097b19a9SEric Kinzie 	}
2521da177e4SLinus Torvalds 	skb_debug(skb);
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 	ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
25552240062SStephen Hemminger 	pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);
2569bbe60a6SDavid Woodhouse 	atm_account_tx(atmvcc, skb);
257410e9d8fSStephen Hemminger 	dev->stats.tx_packets++;
258410e9d8fSStephen Hemminger 	dev->stats.tx_bytes += skb->len;
259137742cfSKarl Hiramoto 
260ae088d66SDavid Woodhouse 	if (atomic_dec_return(&brvcc->qspace) < 1) {
261ae088d66SDavid Woodhouse 		/* No more please! */
262137742cfSKarl Hiramoto 		netif_stop_queue(brvcc->device);
263ae088d66SDavid Woodhouse 		/* We might have raced with br2684_pop() */
264ae088d66SDavid Woodhouse 		if (unlikely(atomic_read(&brvcc->qspace) > 0))
265ae088d66SDavid Woodhouse 			netif_wake_queue(brvcc->device);
266137742cfSKarl Hiramoto 	}
267137742cfSKarl Hiramoto 
268ae088d66SDavid Woodhouse 	/* If this fails immediately, the skb will be freed and br2684_pop()
269ae088d66SDavid Woodhouse 	   will wake the queue if appropriate. Just return an error so that
270ae088d66SDavid Woodhouse 	   the stats are updated correctly */
271ae088d66SDavid Woodhouse 	return !atmvcc->send(atmvcc, skb);
2721da177e4SLinus Torvalds }
2731da177e4SLinus Torvalds 
br2684_release_cb(struct atm_vcc * atmvcc)274b8958853SDavid Woodhouse static void br2684_release_cb(struct atm_vcc *atmvcc)
275b8958853SDavid Woodhouse {
276b8958853SDavid Woodhouse 	struct br2684_vcc *brvcc = BR2684_VCC(atmvcc);
277b8958853SDavid Woodhouse 
278b8958853SDavid Woodhouse 	if (atomic_read(&brvcc->qspace) > 0)
279b8958853SDavid Woodhouse 		netif_wake_queue(brvcc->device);
280b8958853SDavid Woodhouse 
281b8958853SDavid Woodhouse 	if (brvcc->old_release_cb)
282b8958853SDavid Woodhouse 		brvcc->old_release_cb(atmvcc);
283b8958853SDavid Woodhouse }
284b8958853SDavid Woodhouse 
pick_outgoing_vcc(const struct sk_buff * skb,const struct br2684_dev * brdev)28561c33e01SMitchell Blank Jr static inline struct br2684_vcc *pick_outgoing_vcc(const struct sk_buff *skb,
28661c33e01SMitchell Blank Jr 						   const struct br2684_dev *brdev)
2871da177e4SLinus Torvalds {
288fb64c735SChas Williams 	return list_empty(&brdev->brvccs) ? NULL : list_entry_brvcc(brdev->brvccs.next);	/* 1 vcc/dev right now */
2891da177e4SLinus Torvalds }
2901da177e4SLinus Torvalds 
br2684_start_xmit(struct sk_buff * skb,struct net_device * dev)2913c805a22SStephen Hemminger static netdev_tx_t br2684_start_xmit(struct sk_buff *skb,
2923c805a22SStephen Hemminger 				     struct net_device *dev)
2931da177e4SLinus Torvalds {
2941da177e4SLinus Torvalds 	struct br2684_dev *brdev = BRPRIV(dev);
2951da177e4SLinus Torvalds 	struct br2684_vcc *brvcc;
296b8958853SDavid Woodhouse 	struct atm_vcc *atmvcc;
297b8958853SDavid Woodhouse 	netdev_tx_t ret = NETDEV_TX_OK;
2981da177e4SLinus Torvalds 
29999824461SJoe Perches 	pr_debug("skb_dst(skb)=%p\n", skb_dst(skb));
3001da177e4SLinus Torvalds 	read_lock(&devs_lock);
3011da177e4SLinus Torvalds 	brvcc = pick_outgoing_vcc(skb, brdev);
3021da177e4SLinus Torvalds 	if (brvcc == NULL) {
30352240062SStephen Hemminger 		pr_debug("no vcc attached to dev %s\n", dev->name);
304410e9d8fSStephen Hemminger 		dev->stats.tx_errors++;
305410e9d8fSStephen Hemminger 		dev->stats.tx_carrier_errors++;
3061da177e4SLinus Torvalds 		/* netif_stop_queue(dev); */
3071da177e4SLinus Torvalds 		dev_kfree_skb(skb);
308b8958853SDavid Woodhouse 		goto out_devs;
3091da177e4SLinus Torvalds 	}
310b8958853SDavid Woodhouse 	atmvcc = brvcc->atmvcc;
311b8958853SDavid Woodhouse 
312b8958853SDavid Woodhouse 	bh_lock_sock(sk_atm(atmvcc));
313b8958853SDavid Woodhouse 
314b8958853SDavid Woodhouse 	if (test_bit(ATM_VF_RELEASED, &atmvcc->flags) ||
315b8958853SDavid Woodhouse 	    test_bit(ATM_VF_CLOSE, &atmvcc->flags) ||
316b8958853SDavid Woodhouse 	    !test_bit(ATM_VF_READY, &atmvcc->flags)) {
317b8958853SDavid Woodhouse 		dev->stats.tx_dropped++;
318b8958853SDavid Woodhouse 		dev_kfree_skb(skb);
319b8958853SDavid Woodhouse 		goto out;
320b8958853SDavid Woodhouse 	}
321b8958853SDavid Woodhouse 
322b8958853SDavid Woodhouse 	if (sock_owned_by_user(sk_atm(atmvcc))) {
323b8958853SDavid Woodhouse 		netif_stop_queue(brvcc->device);
324b8958853SDavid Woodhouse 		ret = NETDEV_TX_BUSY;
325b8958853SDavid Woodhouse 		goto out;
326b8958853SDavid Woodhouse 	}
327b8958853SDavid Woodhouse 
328410e9d8fSStephen Hemminger 	if (!br2684_xmit_vcc(skb, dev, brvcc)) {
3291da177e4SLinus Torvalds 		/*
3301da177e4SLinus Torvalds 		 * We should probably use netif_*_queue() here, but that
3311da177e4SLinus Torvalds 		 * involves added complication.  We need to walk before
332fb64c735SChas Williams 		 * we can run.
333fb64c735SChas Williams 		 *
334fb64c735SChas Williams 		 * Don't free here! this pointer might be no longer valid!
3351da177e4SLinus Torvalds 		 */
336410e9d8fSStephen Hemminger 		dev->stats.tx_errors++;
337410e9d8fSStephen Hemminger 		dev->stats.tx_fifo_errors++;
3381da177e4SLinus Torvalds 	}
339b8958853SDavid Woodhouse  out:
340b8958853SDavid Woodhouse 	bh_unlock_sock(sk_atm(atmvcc));
341b8958853SDavid Woodhouse  out_devs:
3421da177e4SLinus Torvalds 	read_unlock(&devs_lock);
343b8958853SDavid Woodhouse 	return ret;
3441da177e4SLinus Torvalds }
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds /*
3471da177e4SLinus Torvalds  * We remember when the MAC gets set, so we don't override it later with
3481da177e4SLinus Torvalds  * the ESI of the ATM card of the first VC
3491da177e4SLinus Torvalds  */
br2684_mac_addr(struct net_device * dev,void * p)3501da177e4SLinus Torvalds static int br2684_mac_addr(struct net_device *dev, void *p)
3511da177e4SLinus Torvalds {
3520ba25ff4SStephen Hemminger 	int err = eth_mac_addr(dev, p);
3531da177e4SLinus Torvalds 	if (!err)
3541da177e4SLinus Torvalds 		BRPRIV(dev)->mac_was_set = 1;
3551da177e4SLinus Torvalds 	return err;
3561da177e4SLinus Torvalds }
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds #ifdef CONFIG_ATM_BR2684_IPFILTER
3591da177e4SLinus Torvalds /* this IOCTL is experimental. */
br2684_setfilt(struct atm_vcc * atmvcc,void __user * arg)3601da177e4SLinus Torvalds static int br2684_setfilt(struct atm_vcc *atmvcc, void __user * arg)
3611da177e4SLinus Torvalds {
3621da177e4SLinus Torvalds 	struct br2684_vcc *brvcc;
3631da177e4SLinus Torvalds 	struct br2684_filter_set fs;
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 	if (copy_from_user(&fs, arg, sizeof fs))
3661da177e4SLinus Torvalds 		return -EFAULT;
3671da177e4SLinus Torvalds 	if (fs.ifspec.method != BR2684_FIND_BYNOTHING) {
3681da177e4SLinus Torvalds 		/*
3691da177e4SLinus Torvalds 		 * This is really a per-vcc thing, but we can also search
370fb64c735SChas Williams 		 * by device.
3711da177e4SLinus Torvalds 		 */
3721da177e4SLinus Torvalds 		struct br2684_dev *brdev;
3731da177e4SLinus Torvalds 		read_lock(&devs_lock);
3741da177e4SLinus Torvalds 		brdev = BRPRIV(br2684_find_dev(&fs.ifspec));
375641d729eSJoe Perches 		if (brdev == NULL || list_empty(&brdev->brvccs) ||
376641d729eSJoe Perches 		    brdev->brvccs.next != brdev->brvccs.prev)	/* >1 VCC */
3771da177e4SLinus Torvalds 			brvcc = NULL;
3781da177e4SLinus Torvalds 		else
3791da177e4SLinus Torvalds 			brvcc = list_entry_brvcc(brdev->brvccs.next);
3801da177e4SLinus Torvalds 		read_unlock(&devs_lock);
3811da177e4SLinus Torvalds 		if (brvcc == NULL)
3821da177e4SLinus Torvalds 			return -ESRCH;
3831da177e4SLinus Torvalds 	} else
3841da177e4SLinus Torvalds 		brvcc = BR2684_VCC(atmvcc);
3851da177e4SLinus Torvalds 	memcpy(&brvcc->filter, &fs.filter, sizeof(brvcc->filter));
3861da177e4SLinus Torvalds 	return 0;
3871da177e4SLinus Torvalds }
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds /* Returns 1 if packet should be dropped */
3901da177e4SLinus Torvalds static inline int
packet_fails_filter(__be16 type,struct br2684_vcc * brvcc,struct sk_buff * skb)39130d492daSAl Viro packet_fails_filter(__be16 type, struct br2684_vcc *brvcc, struct sk_buff *skb)
3921da177e4SLinus Torvalds {
3931da177e4SLinus Torvalds 	if (brvcc->filter.netmask == 0)
3941da177e4SLinus Torvalds 		return 0;	/* no filter in place */
395acde4855SYOSHIFUJI Hideaki 	if (type == htons(ETH_P_IP) &&
3961da177e4SLinus Torvalds 	    (((struct iphdr *)(skb->data))->daddr & brvcc->filter.
3971da177e4SLinus Torvalds 	     netmask) == brvcc->filter.prefix)
3981da177e4SLinus Torvalds 		return 0;
399acde4855SYOSHIFUJI Hideaki 	if (type == htons(ETH_P_ARP))
4001da177e4SLinus Torvalds 		return 0;
401fb64c735SChas Williams 	/*
402fb64c735SChas Williams 	 * TODO: we should probably filter ARPs too.. don't want to have
4031da177e4SLinus Torvalds 	 * them returning values that don't make sense, or is that ok?
4041da177e4SLinus Torvalds 	 */
4051da177e4SLinus Torvalds 	return 1;		/* drop */
4061da177e4SLinus Torvalds }
4071da177e4SLinus Torvalds #endif /* CONFIG_ATM_BR2684_IPFILTER */
4081da177e4SLinus Torvalds 
br2684_close_vcc(struct br2684_vcc * brvcc)4091da177e4SLinus Torvalds static void br2684_close_vcc(struct br2684_vcc *brvcc)
4101da177e4SLinus Torvalds {
41152240062SStephen Hemminger 	pr_debug("removing VCC %p from dev %p\n", brvcc, brvcc->device);
4121da177e4SLinus Torvalds 	write_lock_irq(&devs_lock);
4131da177e4SLinus Torvalds 	list_del(&brvcc->brvccs);
4141da177e4SLinus Torvalds 	write_unlock_irq(&devs_lock);
4151da177e4SLinus Torvalds 	brvcc->atmvcc->user_back = NULL;	/* what about vcc->recvq ??? */
416b8958853SDavid Woodhouse 	brvcc->atmvcc->release_cb = brvcc->old_release_cb;
4171da177e4SLinus Torvalds 	brvcc->old_push(brvcc->atmvcc, NULL);	/* pass on the bad news */
418d71ffeb1SDavid Woodhouse 	module_put(brvcc->old_owner);
4191da177e4SLinus Torvalds 	kfree(brvcc);
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds /* when AAL5 PDU comes in: */
br2684_push(struct atm_vcc * atmvcc,struct sk_buff * skb)4231da177e4SLinus Torvalds static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
4241da177e4SLinus Torvalds {
4251da177e4SLinus Torvalds 	struct br2684_vcc *brvcc = BR2684_VCC(atmvcc);
4261da177e4SLinus Torvalds 	struct net_device *net_dev = brvcc->device;
4271da177e4SLinus Torvalds 	struct br2684_dev *brdev = BRPRIV(net_dev);
4281da177e4SLinus Torvalds 
42999824461SJoe Perches 	pr_debug("\n");
4301da177e4SLinus Torvalds 
4311da177e4SLinus Torvalds 	if (unlikely(skb == NULL)) {
4321da177e4SLinus Torvalds 		/* skb==NULL means VCC is being destroyed */
4331da177e4SLinus Torvalds 		br2684_close_vcc(brvcc);
4341da177e4SLinus Torvalds 		if (list_empty(&brdev->brvccs)) {
4351e0ba006SPavel Emelyanov 			write_lock_irq(&devs_lock);
4361da177e4SLinus Torvalds 			list_del(&brdev->br2684_devs);
4371e0ba006SPavel Emelyanov 			write_unlock_irq(&devs_lock);
4381da177e4SLinus Torvalds 			unregister_netdev(net_dev);
4395f6b1ea4SDavid S. Miller 			free_netdev(net_dev);
4401da177e4SLinus Torvalds 		}
4411da177e4SLinus Torvalds 		return;
4421da177e4SLinus Torvalds 	}
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 	skb_debug(skb);
4451da177e4SLinus Torvalds 	atm_return(atmvcc, skb->truesize);
44652240062SStephen Hemminger 	pr_debug("skb from brdev %p\n", brdev);
4471da177e4SLinus Torvalds 	if (brvcc->encaps == e_llc) {
448097b19a9SEric Kinzie 
449097b19a9SEric Kinzie 		if (skb->len > 7 && skb->data[7] == 0x01)
450097b19a9SEric Kinzie 			__skb_trim(skb, skb->len - 4);
451097b19a9SEric Kinzie 
452097b19a9SEric Kinzie 		/* accept packets that have "ipv[46]" in the snap header */
453641d729eSJoe Perches 		if ((skb->len >= (sizeof(llc_oui_ipv4))) &&
454641d729eSJoe Perches 		    (memcmp(skb->data, llc_oui_ipv4,
455fb64c735SChas Williams 			    sizeof(llc_oui_ipv4) - BR2684_ETHERTYPE_LEN) == 0)) {
456641d729eSJoe Perches 			if (memcmp(skb->data + 6, ethertype_ipv6,
457fb64c735SChas Williams 				   sizeof(ethertype_ipv6)) == 0)
45860678040SArnaldo Carvalho de Melo 				skb->protocol = htons(ETH_P_IPV6);
459641d729eSJoe Perches 			else if (memcmp(skb->data + 6, ethertype_ipv4,
460fb64c735SChas Williams 					sizeof(ethertype_ipv4)) == 0)
46160678040SArnaldo Carvalho de Melo 				skb->protocol = htons(ETH_P_IP);
4627e903c2aSEric Kinzie 			else
4637e903c2aSEric Kinzie 				goto error;
464097b19a9SEric Kinzie 			skb_pull(skb, sizeof(llc_oui_ipv4));
465097b19a9SEric Kinzie 			skb_reset_network_header(skb);
466097b19a9SEric Kinzie 			skb->pkt_type = PACKET_HOST;
467fb64c735SChas Williams 		/*
468fb64c735SChas Williams 		 * Let us waste some time for checking the encapsulation.
469fb64c735SChas Williams 		 * Note, that only 7 char is checked so frames with a valid FCS
470fb64c735SChas Williams 		 * are also accepted (but FCS is not checked of course).
471fb64c735SChas Williams 		 */
472097b19a9SEric Kinzie 		} else if ((skb->len >= sizeof(llc_oui_pid_pad)) &&
473097b19a9SEric Kinzie 			   (memcmp(skb->data, llc_oui_pid_pad, 7) == 0)) {
474097b19a9SEric Kinzie 			skb_pull(skb, sizeof(llc_oui_pid_pad));
475097b19a9SEric Kinzie 			skb->protocol = eth_type_trans(skb, net_dev);
4767e903c2aSEric Kinzie 		} else
4777e903c2aSEric Kinzie 			goto error;
4781da177e4SLinus Torvalds 
4797e903c2aSEric Kinzie 	} else { /* e_vc */
4807e903c2aSEric Kinzie 		if (brdev->payload == p_routed) {
4817e903c2aSEric Kinzie 			struct iphdr *iph;
4827e903c2aSEric Kinzie 
4837e903c2aSEric Kinzie 			skb_reset_network_header(skb);
4847e903c2aSEric Kinzie 			iph = ip_hdr(skb);
4857e903c2aSEric Kinzie 			if (iph->version == 4)
48660678040SArnaldo Carvalho de Melo 				skb->protocol = htons(ETH_P_IP);
4877e903c2aSEric Kinzie 			else if (iph->version == 6)
48860678040SArnaldo Carvalho de Melo 				skb->protocol = htons(ETH_P_IPV6);
4897e903c2aSEric Kinzie 			else
4907e903c2aSEric Kinzie 				goto error;
4917e903c2aSEric Kinzie 			skb->pkt_type = PACKET_HOST;
4927e903c2aSEric Kinzie 		} else { /* p_bridged */
4931da177e4SLinus Torvalds 			/* first 2 chars should be 0 */
494befc93feSPascal Hambourg 			if (memcmp(skb->data, pad, BR2684_PAD_LEN) != 0)
4957e903c2aSEric Kinzie 				goto error;
4967e903c2aSEric Kinzie 			skb_pull(skb, BR2684_PAD_LEN);
497097b19a9SEric Kinzie 			skb->protocol = eth_type_trans(skb, net_dev);
4981da177e4SLinus Torvalds 		}
4997e903c2aSEric Kinzie 	}
5001da177e4SLinus Torvalds 
5011da177e4SLinus Torvalds #ifdef CONFIG_ATM_BR2684_IPFILTER
5027e903c2aSEric Kinzie 	if (unlikely(packet_fails_filter(skb->protocol, brvcc, skb)))
5037e903c2aSEric Kinzie 		goto dropped;
5041da177e4SLinus Torvalds #endif /* CONFIG_ATM_BR2684_IPFILTER */
5051da177e4SLinus Torvalds 	skb->dev = net_dev;
5061da177e4SLinus Torvalds 	ATM_SKB(skb)->vcc = atmvcc;	/* needed ? */
50752240062SStephen Hemminger 	pr_debug("received packet's protocol: %x\n", ntohs(skb->protocol));
5081da177e4SLinus Torvalds 	skb_debug(skb);
5097e903c2aSEric Kinzie 	/* sigh, interface is down? */
5107e903c2aSEric Kinzie 	if (unlikely(!(net_dev->flags & IFF_UP)))
5117e903c2aSEric Kinzie 		goto dropped;
512410e9d8fSStephen Hemminger 	net_dev->stats.rx_packets++;
513410e9d8fSStephen Hemminger 	net_dev->stats.rx_bytes += skb->len;
5141da177e4SLinus Torvalds 	memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
5151da177e4SLinus Torvalds 	netif_rx(skb);
5167e903c2aSEric Kinzie 	return;
5177e903c2aSEric Kinzie 
5187e903c2aSEric Kinzie dropped:
519410e9d8fSStephen Hemminger 	net_dev->stats.rx_dropped++;
5207e903c2aSEric Kinzie 	goto free_skb;
5217e903c2aSEric Kinzie error:
522410e9d8fSStephen Hemminger 	net_dev->stats.rx_errors++;
5237e903c2aSEric Kinzie free_skb:
5247e903c2aSEric Kinzie 	dev_kfree_skb(skb);
5251da177e4SLinus Torvalds }
5261da177e4SLinus Torvalds 
527fb64c735SChas Williams /*
528fb64c735SChas Williams  * Assign a vcc to a dev
529fb64c735SChas Williams  * Note: we do not have explicit unassign, but look at _push()
530fb64c735SChas Williams  */
br2684_regvcc(struct atm_vcc * atmvcc,void __user * arg)5311da177e4SLinus Torvalds static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
5321da177e4SLinus Torvalds {
5331da177e4SLinus Torvalds 	struct br2684_vcc *brvcc;
5341da177e4SLinus Torvalds 	struct br2684_dev *brdev;
5351da177e4SLinus Torvalds 	struct net_device *net_dev;
5361da177e4SLinus Torvalds 	struct atm_backend_br2684 be;
5374e55f578SJorge Boncompte [DTI2] 	int err;
5381da177e4SLinus Torvalds 
5391da177e4SLinus Torvalds 	if (copy_from_user(&be, arg, sizeof be))
5401da177e4SLinus Torvalds 		return -EFAULT;
5410da974f4SPanagiotis Issaris 	brvcc = kzalloc(sizeof(struct br2684_vcc), GFP_KERNEL);
5421da177e4SLinus Torvalds 	if (!brvcc)
5431da177e4SLinus Torvalds 		return -ENOMEM;
544ae088d66SDavid Woodhouse 	/*
545ae088d66SDavid Woodhouse 	 * Allow two packets in the ATM queue. One actually being sent, and one
546ae088d66SDavid Woodhouse 	 * for the ATM 'TX done' handler to send. It shouldn't take long to get
547ae088d66SDavid Woodhouse 	 * the next one from the netdev queue, when we need it. More than that
548ae088d66SDavid Woodhouse 	 * would be bufferbloat.
549ae088d66SDavid Woodhouse 	 */
550ae088d66SDavid Woodhouse 	atomic_set(&brvcc->qspace, 2);
5511da177e4SLinus Torvalds 	write_lock_irq(&devs_lock);
5521da177e4SLinus Torvalds 	net_dev = br2684_find_dev(&be.ifspec);
5531da177e4SLinus Torvalds 	if (net_dev == NULL) {
55425985edcSLucas De Marchi 		pr_err("tried to attach to non-existent device\n");
5551da177e4SLinus Torvalds 		err = -ENXIO;
5561da177e4SLinus Torvalds 		goto error;
5571da177e4SLinus Torvalds 	}
5581da177e4SLinus Torvalds 	brdev = BRPRIV(net_dev);
5591da177e4SLinus Torvalds 	if (atmvcc->push == NULL) {
5601da177e4SLinus Torvalds 		err = -EBADFD;
5611da177e4SLinus Torvalds 		goto error;
5621da177e4SLinus Torvalds 	}
5631da177e4SLinus Torvalds 	if (!list_empty(&brdev->brvccs)) {
5641da177e4SLinus Torvalds 		/* Only 1 VCC/dev right now */
5651da177e4SLinus Torvalds 		err = -EEXIST;
5661da177e4SLinus Torvalds 		goto error;
5671da177e4SLinus Torvalds 	}
568641d729eSJoe Perches 	if (be.fcs_in != BR2684_FCSIN_NO ||
569641d729eSJoe Perches 	    be.fcs_out != BR2684_FCSOUT_NO ||
570641d729eSJoe Perches 	    be.fcs_auto || be.has_vpiid || be.send_padding ||
571641d729eSJoe Perches 	    (be.encaps != BR2684_ENCAPS_VC &&
572641d729eSJoe Perches 	     be.encaps != BR2684_ENCAPS_LLC) ||
573641d729eSJoe Perches 	    be.min_size != 0) {
5741da177e4SLinus Torvalds 		err = -EINVAL;
5751da177e4SLinus Torvalds 		goto error;
5761da177e4SLinus Torvalds 	}
57799824461SJoe Perches 	pr_debug("vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps, brvcc);
5781da177e4SLinus Torvalds 	if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) {
5791da177e4SLinus Torvalds 		unsigned char *esi = atmvcc->dev->esi;
580*d6b3daf2SJakub Kicinski 		const u8 one = 1;
581*d6b3daf2SJakub Kicinski 
5821da177e4SLinus Torvalds 		if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5])
583ea52a0b5SJakub Kicinski 			dev_addr_set(net_dev, esi);
5841da177e4SLinus Torvalds 		else
585*d6b3daf2SJakub Kicinski 			dev_addr_mod(net_dev, 2, &one, 1);
5861da177e4SLinus Torvalds 	}
5871da177e4SLinus Torvalds 	list_add(&brvcc->brvccs, &brdev->brvccs);
5881da177e4SLinus Torvalds 	write_unlock_irq(&devs_lock);
5891da177e4SLinus Torvalds 	brvcc->device = net_dev;
5901da177e4SLinus Torvalds 	brvcc->atmvcc = atmvcc;
5911da177e4SLinus Torvalds 	atmvcc->user_back = brvcc;
5921da177e4SLinus Torvalds 	brvcc->encaps = (enum br2684_encaps)be.encaps;
5931da177e4SLinus Torvalds 	brvcc->old_push = atmvcc->push;
594137742cfSKarl Hiramoto 	brvcc->old_pop = atmvcc->pop;
595b8958853SDavid Woodhouse 	brvcc->old_release_cb = atmvcc->release_cb;
596d71ffeb1SDavid Woodhouse 	brvcc->old_owner = atmvcc->owner;
5971da177e4SLinus Torvalds 	barrier();
5981da177e4SLinus Torvalds 	atmvcc->push = br2684_push;
599137742cfSKarl Hiramoto 	atmvcc->pop = br2684_pop;
600b8958853SDavid Woodhouse 	atmvcc->release_cb = br2684_release_cb;
601d71ffeb1SDavid Woodhouse 	atmvcc->owner = THIS_MODULE;
602c40a27f4SDavid S. Miller 
60300506612SKarl Hiramoto 	/* initialize netdev carrier state */
60400506612SKarl Hiramoto 	if (atmvcc->dev->signal == ATM_PHY_SIG_LOST)
60500506612SKarl Hiramoto 		netif_carrier_off(net_dev);
60600506612SKarl Hiramoto 	else
60700506612SKarl Hiramoto 		netif_carrier_on(net_dev);
60800506612SKarl Hiramoto 
6091da177e4SLinus Torvalds 	__module_get(THIS_MODULE);
6104e55f578SJorge Boncompte [DTI2] 
6114e55f578SJorge Boncompte [DTI2] 	/* re-process everything received between connection setup and
6124e55f578SJorge Boncompte [DTI2] 	   backend setup */
6134e55f578SJorge Boncompte [DTI2] 	vcc_process_recv_queue(atmvcc);
6141da177e4SLinus Torvalds 	return 0;
615641d729eSJoe Perches 
6161da177e4SLinus Torvalds error:
6171da177e4SLinus Torvalds 	write_unlock_irq(&devs_lock);
6181da177e4SLinus Torvalds 	kfree(brvcc);
6191da177e4SLinus Torvalds 	return err;
6201da177e4SLinus Torvalds }
6211da177e4SLinus Torvalds 
6220ba25ff4SStephen Hemminger static const struct net_device_ops br2684_netdev_ops = {
6230ba25ff4SStephen Hemminger 	.ndo_start_xmit 	= br2684_start_xmit,
6240ba25ff4SStephen Hemminger 	.ndo_set_mac_address	= br2684_mac_addr,
6250ba25ff4SStephen Hemminger 	.ndo_validate_addr	= eth_validate_addr,
6260ba25ff4SStephen Hemminger };
6270ba25ff4SStephen Hemminger 
6282e302ebfSchas williams - CONTRACTOR static const struct net_device_ops br2684_netdev_ops_routed = {
6292e302ebfSchas williams - CONTRACTOR 	.ndo_start_xmit 	= br2684_start_xmit,
6302e302ebfSchas williams - CONTRACTOR 	.ndo_set_mac_address	= br2684_mac_addr,
6312e302ebfSchas williams - CONTRACTOR };
6322e302ebfSchas williams - CONTRACTOR 
br2684_setup(struct net_device * netdev)6331da177e4SLinus Torvalds static void br2684_setup(struct net_device *netdev)
6341da177e4SLinus Torvalds {
6351da177e4SLinus Torvalds 	struct br2684_dev *brdev = BRPRIV(netdev);
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds 	ether_setup(netdev);
6389e667b29SPascal Hambourg 	netdev->hard_header_len += sizeof(llc_oui_pid_pad); /* worst case */
639902e5ea1SRabin Vincent 	brdev->net_dev = netdev;
6401da177e4SLinus Torvalds 
6410ba25ff4SStephen Hemminger 	netdev->netdev_ops = &br2684_netdev_ops;
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds 	INIT_LIST_HEAD(&brdev->brvccs);
6441da177e4SLinus Torvalds }
6451da177e4SLinus Torvalds 
br2684_setup_routed(struct net_device * netdev)646097b19a9SEric Kinzie static void br2684_setup_routed(struct net_device *netdev)
647097b19a9SEric Kinzie {
648097b19a9SEric Kinzie 	struct br2684_dev *brdev = BRPRIV(netdev);
6492e302ebfSchas williams - CONTRACTOR 
650097b19a9SEric Kinzie 	brdev->net_dev = netdev;
6519e667b29SPascal Hambourg 	netdev->hard_header_len = sizeof(llc_oui_ipv4); /* worst case */
6522e302ebfSchas williams - CONTRACTOR 	netdev->netdev_ops = &br2684_netdev_ops_routed;
653097b19a9SEric Kinzie 	netdev->addr_len = 0;
6548b1efc0fSJarod Wilson 	netdev->mtu = ETH_DATA_LEN;
6558b1efc0fSJarod Wilson 	netdev->min_mtu = 0;
6568b1efc0fSJarod Wilson 	netdev->max_mtu = ETH_MAX_MTU;
657097b19a9SEric Kinzie 	netdev->type = ARPHRD_PPP;
658097b19a9SEric Kinzie 	netdev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
659097b19a9SEric Kinzie 	netdev->tx_queue_len = 100;
660097b19a9SEric Kinzie 	INIT_LIST_HEAD(&brdev->brvccs);
661097b19a9SEric Kinzie }
662097b19a9SEric Kinzie 
br2684_create(void __user * arg)6631da177e4SLinus Torvalds static int br2684_create(void __user *arg)
6641da177e4SLinus Torvalds {
6651da177e4SLinus Torvalds 	int err;
6661da177e4SLinus Torvalds 	struct net_device *netdev;
6671da177e4SLinus Torvalds 	struct br2684_dev *brdev;
6681da177e4SLinus Torvalds 	struct atm_newif_br2684 ni;
669097b19a9SEric Kinzie 	enum br2684_payload payload;
6701da177e4SLinus Torvalds 
67199824461SJoe Perches 	pr_debug("\n");
6721da177e4SLinus Torvalds 
673641d729eSJoe Perches 	if (copy_from_user(&ni, arg, sizeof ni))
6741da177e4SLinus Torvalds 		return -EFAULT;
675097b19a9SEric Kinzie 
676097b19a9SEric Kinzie 	if (ni.media & BR2684_FLAG_ROUTED)
677097b19a9SEric Kinzie 		payload = p_routed;
678097b19a9SEric Kinzie 	else
679097b19a9SEric Kinzie 		payload = p_bridged;
680097b19a9SEric Kinzie 	ni.media &= 0xffff;	/* strip flags */
681097b19a9SEric Kinzie 
682641d729eSJoe Perches 	if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500)
6831da177e4SLinus Torvalds 		return -EINVAL;
6841da177e4SLinus Torvalds 
6851da177e4SLinus Torvalds 	netdev = alloc_netdev(sizeof(struct br2684_dev),
6861da177e4SLinus Torvalds 			      ni.ifname[0] ? ni.ifname : "nas%d",
687c835a677STom Gundersen 			      NET_NAME_UNKNOWN,
688c835a677STom Gundersen 			      (payload == p_routed) ? br2684_setup_routed : br2684_setup);
6891da177e4SLinus Torvalds 	if (!netdev)
6901da177e4SLinus Torvalds 		return -ENOMEM;
6911da177e4SLinus Torvalds 
6921da177e4SLinus Torvalds 	brdev = BRPRIV(netdev);
6931da177e4SLinus Torvalds 
69452240062SStephen Hemminger 	pr_debug("registered netdev %s\n", netdev->name);
6951da177e4SLinus Torvalds 	/* open, stop, do_ioctl ? */
6961da177e4SLinus Torvalds 	err = register_netdev(netdev);
6971da177e4SLinus Torvalds 	if (err < 0) {
69899824461SJoe Perches 		pr_err("register_netdev failed\n");
6991da177e4SLinus Torvalds 		free_netdev(netdev);
7001da177e4SLinus Torvalds 		return err;
7011da177e4SLinus Torvalds 	}
7021da177e4SLinus Torvalds 
7031da177e4SLinus Torvalds 	write_lock_irq(&devs_lock);
70400506612SKarl Hiramoto 
705097b19a9SEric Kinzie 	brdev->payload = payload;
70600506612SKarl Hiramoto 
70700506612SKarl Hiramoto 	if (list_empty(&br2684_devs)) {
70800506612SKarl Hiramoto 		/* 1st br2684 device */
70900506612SKarl Hiramoto 		brdev->number = 1;
71000506612SKarl Hiramoto 	} else
71100506612SKarl Hiramoto 		brdev->number = BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1;
71200506612SKarl Hiramoto 
7131da177e4SLinus Torvalds 	list_add_tail(&brdev->br2684_devs, &br2684_devs);
7141da177e4SLinus Torvalds 	write_unlock_irq(&devs_lock);
7151da177e4SLinus Torvalds 	return 0;
7161da177e4SLinus Torvalds }
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds /*
7191da177e4SLinus Torvalds  * This handles ioctls actually performed on our vcc - we must return
7201da177e4SLinus Torvalds  * -ENOIOCTLCMD for any unrecognized ioctl
7211da177e4SLinus Torvalds  */
br2684_ioctl(struct socket * sock,unsigned int cmd,unsigned long arg)7221da177e4SLinus Torvalds static int br2684_ioctl(struct socket *sock, unsigned int cmd,
7231da177e4SLinus Torvalds 			unsigned long arg)
7241da177e4SLinus Torvalds {
7251da177e4SLinus Torvalds 	struct atm_vcc *atmvcc = ATM_SD(sock);
7261da177e4SLinus Torvalds 	void __user *argp = (void __user *)arg;
727fb64c735SChas Williams 	atm_backend_t b;
7281da177e4SLinus Torvalds 
7291da177e4SLinus Torvalds 	int err;
7301da177e4SLinus Torvalds 	switch (cmd) {
7311da177e4SLinus Torvalds 	case ATM_SETBACKEND:
732fb64c735SChas Williams 	case ATM_NEWBACKENDIF:
7331da177e4SLinus Torvalds 		err = get_user(b, (atm_backend_t __user *) argp);
7341da177e4SLinus Torvalds 		if (err)
7351da177e4SLinus Torvalds 			return -EFAULT;
7361da177e4SLinus Torvalds 		if (b != ATM_BACKEND_BR2684)
7371da177e4SLinus Torvalds 			return -ENOIOCTLCMD;
7381da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
7391da177e4SLinus Torvalds 			return -EPERM;
7409eba2526SKrzysztof Mazur 		if (cmd == ATM_SETBACKEND) {
7419eba2526SKrzysztof Mazur 			if (sock->state != SS_CONNECTED)
7429eba2526SKrzysztof Mazur 				return -EINVAL;
7431da177e4SLinus Torvalds 			return br2684_regvcc(atmvcc, argp);
7449eba2526SKrzysztof Mazur 		} else {
7451da177e4SLinus Torvalds 			return br2684_create(argp);
7469eba2526SKrzysztof Mazur 		}
7471da177e4SLinus Torvalds #ifdef CONFIG_ATM_BR2684_IPFILTER
7481da177e4SLinus Torvalds 	case BR2684_SETFILT:
7491da177e4SLinus Torvalds 		if (atmvcc->push != br2684_push)
7501da177e4SLinus Torvalds 			return -ENOIOCTLCMD;
7511da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
7521da177e4SLinus Torvalds 			return -EPERM;
7531da177e4SLinus Torvalds 		err = br2684_setfilt(atmvcc, argp);
754fb64c735SChas Williams 
7551da177e4SLinus Torvalds 		return err;
7561da177e4SLinus Torvalds #endif /* CONFIG_ATM_BR2684_IPFILTER */
7571da177e4SLinus Torvalds 	}
7581da177e4SLinus Torvalds 	return -ENOIOCTLCMD;
7591da177e4SLinus Torvalds }
7601da177e4SLinus Torvalds 
7611da177e4SLinus Torvalds static struct atm_ioctl br2684_ioctl_ops = {
7621da177e4SLinus Torvalds 	.owner = THIS_MODULE,
7631da177e4SLinus Torvalds 	.ioctl = br2684_ioctl,
7641da177e4SLinus Torvalds };
7651da177e4SLinus Torvalds 
7661da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
br2684_seq_start(struct seq_file * seq,loff_t * pos)7671da177e4SLinus Torvalds static void *br2684_seq_start(struct seq_file *seq, loff_t * pos)
7685c17d5f1SEric Dumazet 	__acquires(devs_lock)
7691da177e4SLinus Torvalds {
7701da177e4SLinus Torvalds 	read_lock(&devs_lock);
7719af97186SPavel Emelianov 	return seq_list_start(&br2684_devs, *pos);
7721da177e4SLinus Torvalds }
7731da177e4SLinus Torvalds 
br2684_seq_next(struct seq_file * seq,void * v,loff_t * pos)7741da177e4SLinus Torvalds static void *br2684_seq_next(struct seq_file *seq, void *v, loff_t * pos)
7751da177e4SLinus Torvalds {
7769af97186SPavel Emelianov 	return seq_list_next(v, &br2684_devs, pos);
7771da177e4SLinus Torvalds }
7781da177e4SLinus Torvalds 
br2684_seq_stop(struct seq_file * seq,void * v)7791da177e4SLinus Torvalds static void br2684_seq_stop(struct seq_file *seq, void *v)
7805c17d5f1SEric Dumazet 	__releases(devs_lock)
7811da177e4SLinus Torvalds {
7821da177e4SLinus Torvalds 	read_unlock(&devs_lock);
7831da177e4SLinus Torvalds }
7841da177e4SLinus Torvalds 
br2684_seq_show(struct seq_file * seq,void * v)7851da177e4SLinus Torvalds static int br2684_seq_show(struct seq_file *seq, void *v)
7861da177e4SLinus Torvalds {
7879af97186SPavel Emelianov 	const struct br2684_dev *brdev = list_entry(v, struct br2684_dev,
7889af97186SPavel Emelianov 						    br2684_devs);
7891da177e4SLinus Torvalds 	const struct net_device *net_dev = brdev->net_dev;
7901da177e4SLinus Torvalds 	const struct br2684_vcc *brvcc;
7911da177e4SLinus Torvalds 
792e174961cSJohannes Berg 	seq_printf(seq, "dev %.16s: num=%d, mac=%pM (%s)\n",
7930795af57SJoe Perches 		   net_dev->name,
7941da177e4SLinus Torvalds 		   brdev->number,
795e174961cSJohannes Berg 		   net_dev->dev_addr,
7961da177e4SLinus Torvalds 		   brdev->mac_was_set ? "set" : "auto");
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds 	list_for_each_entry(brvcc, &brdev->brvccs, brvccs) {
799097b19a9SEric Kinzie 		seq_printf(seq, "  vcc %d.%d.%d: encaps=%s payload=%s"
8001da177e4SLinus Torvalds 			   ", failed copies %u/%u"
8011da177e4SLinus Torvalds 			   "\n", brvcc->atmvcc->dev->number,
8021da177e4SLinus Torvalds 			   brvcc->atmvcc->vpi, brvcc->atmvcc->vci,
803097b19a9SEric Kinzie 			   (brvcc->encaps == e_llc) ? "LLC" : "VC",
804097b19a9SEric Kinzie 			   (brdev->payload == p_bridged) ? "bridged" : "routed",
805fb64c735SChas Williams 			   brvcc->copies_failed, brvcc->copies_needed);
8061da177e4SLinus Torvalds #ifdef CONFIG_ATM_BR2684_IPFILTER
8071da177e4SLinus Torvalds 		if (brvcc->filter.netmask != 0)
80885b1d8bbSJoe Perches 			seq_printf(seq, "    filter=%pI4/%pI4\n",
80985b1d8bbSJoe Perches 				   &brvcc->filter.prefix,
81085b1d8bbSJoe Perches 				   &brvcc->filter.netmask);
8111da177e4SLinus Torvalds #endif /* CONFIG_ATM_BR2684_IPFILTER */
8121da177e4SLinus Torvalds 	}
8131da177e4SLinus Torvalds 	return 0;
8141da177e4SLinus Torvalds }
8151da177e4SLinus Torvalds 
81656b3d975SPhilippe De Muyter static const struct seq_operations br2684_seq_ops = {
8171da177e4SLinus Torvalds 	.start = br2684_seq_start,
8181da177e4SLinus Torvalds 	.next = br2684_seq_next,
8191da177e4SLinus Torvalds 	.stop = br2684_seq_stop,
8201da177e4SLinus Torvalds 	.show = br2684_seq_show,
8211da177e4SLinus Torvalds };
8221da177e4SLinus Torvalds 
8231da177e4SLinus Torvalds extern struct proc_dir_entry *atm_proc_root;	/* from proc.c */
824fb64c735SChas Williams #endif /* CONFIG_PROC_FS */
8251da177e4SLinus Torvalds 
br2684_init(void)8261da177e4SLinus Torvalds static int __init br2684_init(void)
8271da177e4SLinus Torvalds {
8281da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
8291da177e4SLinus Torvalds 	struct proc_dir_entry *p;
830fddda2b7SChristoph Hellwig 	p = proc_create_seq("br2684", 0, atm_proc_root, &br2684_seq_ops);
83116e297b3SWang Chen 	if (p == NULL)
8321da177e4SLinus Torvalds 		return -ENOMEM;
8331da177e4SLinus Torvalds #endif
8341da177e4SLinus Torvalds 	register_atm_ioctl(&br2684_ioctl_ops);
835a3d6713fSKarl Hiramoto 	register_atmdevice_notifier(&atm_dev_notifier);
8361da177e4SLinus Torvalds 	return 0;
8371da177e4SLinus Torvalds }
8381da177e4SLinus Torvalds 
br2684_exit(void)8391da177e4SLinus Torvalds static void __exit br2684_exit(void)
8401da177e4SLinus Torvalds {
8411da177e4SLinus Torvalds 	struct net_device *net_dev;
8421da177e4SLinus Torvalds 	struct br2684_dev *brdev;
8431da177e4SLinus Torvalds 	struct br2684_vcc *brvcc;
8441da177e4SLinus Torvalds 	deregister_atm_ioctl(&br2684_ioctl_ops);
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
8471da177e4SLinus Torvalds 	remove_proc_entry("br2684", atm_proc_root);
8481da177e4SLinus Torvalds #endif
8491da177e4SLinus Torvalds 
85000506612SKarl Hiramoto 
85100506612SKarl Hiramoto 	unregister_atmdevice_notifier(&atm_dev_notifier);
85200506612SKarl Hiramoto 
8531da177e4SLinus Torvalds 	while (!list_empty(&br2684_devs)) {
8541da177e4SLinus Torvalds 		net_dev = list_entry_brdev(br2684_devs.next);
8551da177e4SLinus Torvalds 		brdev = BRPRIV(net_dev);
8561da177e4SLinus Torvalds 		while (!list_empty(&brdev->brvccs)) {
8571da177e4SLinus Torvalds 			brvcc = list_entry_brvcc(brdev->brvccs.next);
8581da177e4SLinus Torvalds 			br2684_close_vcc(brvcc);
8591da177e4SLinus Torvalds 		}
8601da177e4SLinus Torvalds 
8611da177e4SLinus Torvalds 		list_del(&brdev->br2684_devs);
8621da177e4SLinus Torvalds 		unregister_netdev(net_dev);
8635f6b1ea4SDavid S. Miller 		free_netdev(net_dev);
8641da177e4SLinus Torvalds 	}
8651da177e4SLinus Torvalds }
8661da177e4SLinus Torvalds 
8671da177e4SLinus Torvalds module_init(br2684_init);
8681da177e4SLinus Torvalds module_exit(br2684_exit);
8691da177e4SLinus Torvalds 
8701da177e4SLinus Torvalds MODULE_AUTHOR("Marcell GAL");
8711da177e4SLinus Torvalds MODULE_DESCRIPTION("RFC2684 bridged protocols over ATM/AAL5");
8721da177e4SLinus Torvalds MODULE_LICENSE("GPL");
873