xref: /openbmc/linux/net/atm/lec.c (revision d44f77466cfdc6f1d1e3870e176afedab7f46a42)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * lec.c: Lan Emulation driver
31da177e4SLinus Torvalds  *
4*d44f7746SChas Williams  * Marko Kiiskila <mkiiskila@yahoo.com>
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds #include <linux/kernel.h>
81da177e4SLinus Torvalds #include <linux/bitops.h>
94fc268d2SRandy Dunlap #include <linux/capability.h>
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds /* We are ethernet device */
121da177e4SLinus Torvalds #include <linux/if_ether.h>
131da177e4SLinus Torvalds #include <linux/netdevice.h>
141da177e4SLinus Torvalds #include <linux/etherdevice.h>
151da177e4SLinus Torvalds #include <net/sock.h>
161da177e4SLinus Torvalds #include <linux/skbuff.h>
171da177e4SLinus Torvalds #include <linux/ip.h>
181da177e4SLinus Torvalds #include <asm/byteorder.h>
191da177e4SLinus Torvalds #include <asm/uaccess.h>
201da177e4SLinus Torvalds #include <net/arp.h>
211da177e4SLinus Torvalds #include <net/dst.h>
221da177e4SLinus Torvalds #include <linux/proc_fs.h>
231da177e4SLinus Torvalds #include <linux/spinlock.h>
241da177e4SLinus Torvalds #include <linux/proc_fs.h>
251da177e4SLinus Torvalds #include <linux/seq_file.h>
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds /* TokenRing if needed */
281da177e4SLinus Torvalds #ifdef CONFIG_TR
291da177e4SLinus Torvalds #include <linux/trdevice.h>
301da177e4SLinus Torvalds #endif
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds /* And atm device */
331da177e4SLinus Torvalds #include <linux/atmdev.h>
341da177e4SLinus Torvalds #include <linux/atmlec.h>
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds /* Proxy LEC knows about bridging */
371da177e4SLinus Torvalds #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
381da177e4SLinus Torvalds #include <linux/if_bridge.h>
391da177e4SLinus Torvalds #include "../bridge/br_private.h"
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
421da177e4SLinus Torvalds #endif
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds /* Modular too */
451da177e4SLinus Torvalds #include <linux/module.h>
461da177e4SLinus Torvalds #include <linux/init.h>
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds #include "lec.h"
491da177e4SLinus Torvalds #include "lec_arpc.h"
501da177e4SLinus Torvalds #include "resources.h"
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds #if 0
531da177e4SLinus Torvalds #define DPRINTK printk
541da177e4SLinus Torvalds #else
551da177e4SLinus Torvalds #define DPRINTK(format,args...)
561da177e4SLinus Torvalds #endif
571da177e4SLinus Torvalds 
58*d44f7746SChas Williams #define DUMP_PACKETS 0		/*
59*d44f7746SChas Williams 				 * 0 = None,
601da177e4SLinus Torvalds 				 * 1 = 30 first bytes
611da177e4SLinus Torvalds 				 * 2 = Whole packet
621da177e4SLinus Torvalds 				 */
631da177e4SLinus Torvalds 
64*d44f7746SChas Williams #define LEC_UNRES_QUE_LEN 8	/*
65*d44f7746SChas Williams 				 * number of tx packets to queue for a
66*d44f7746SChas Williams 				 * single destination while waiting for SVC
67*d44f7746SChas Williams 				 */
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds static int lec_open(struct net_device *dev);
701da177e4SLinus Torvalds static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev);
711da177e4SLinus Torvalds static int lec_close(struct net_device *dev);
721da177e4SLinus Torvalds static struct net_device_stats *lec_get_stats(struct net_device *dev);
731da177e4SLinus Torvalds static void lec_init(struct net_device *dev);
741da177e4SLinus Torvalds static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
751da177e4SLinus Torvalds 					  unsigned char *mac_addr);
761da177e4SLinus Torvalds static int lec_arp_remove(struct lec_priv *priv,
771da177e4SLinus Torvalds 			  struct lec_arp_table *to_remove);
781da177e4SLinus Torvalds /* LANE2 functions */
791da177e4SLinus Torvalds static void lane2_associate_ind(struct net_device *dev, u8 *mac_address,
801da177e4SLinus Torvalds 				u8 *tlvs, u32 sizeoftlvs);
811da177e4SLinus Torvalds static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
821da177e4SLinus Torvalds 			 u8 **tlvs, u32 *sizeoftlvs);
831da177e4SLinus Torvalds static int lane2_associate_req(struct net_device *dev, u8 *lan_dst,
841da177e4SLinus Torvalds 			       u8 *tlvs, u32 sizeoftlvs);
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds static int lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
871da177e4SLinus Torvalds 			   unsigned long permanent);
881da177e4SLinus Torvalds static void lec_arp_check_empties(struct lec_priv *priv,
891da177e4SLinus Torvalds 				  struct atm_vcc *vcc, struct sk_buff *skb);
901da177e4SLinus Torvalds static void lec_arp_destroy(struct lec_priv *priv);
911da177e4SLinus Torvalds static void lec_arp_init(struct lec_priv *priv);
921da177e4SLinus Torvalds static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
931da177e4SLinus Torvalds 				       unsigned char *mac_to_find,
941da177e4SLinus Torvalds 				       int is_rdesc,
951da177e4SLinus Torvalds 				       struct lec_arp_table **ret_entry);
961da177e4SLinus Torvalds static void lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
971da177e4SLinus Torvalds 			   unsigned char *atm_addr, unsigned long remoteflag,
981da177e4SLinus Torvalds 			   unsigned int targetless_le_arp);
991da177e4SLinus Torvalds static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id);
1001da177e4SLinus Torvalds static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc);
1011da177e4SLinus Torvalds static void lec_set_flush_tran_id(struct lec_priv *priv,
1021da177e4SLinus Torvalds 				  unsigned char *atm_addr,
1031da177e4SLinus Torvalds 				  unsigned long tran_id);
1041da177e4SLinus Torvalds static void lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
1051da177e4SLinus Torvalds 			  struct atm_vcc *vcc,
106*d44f7746SChas Williams 			  void (*old_push) (struct atm_vcc *vcc,
107*d44f7746SChas Williams 					    struct sk_buff *skb));
1081da177e4SLinus Torvalds static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc);
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds static struct lane2_ops lane2_ops = {
1111da177e4SLinus Torvalds 	lane2_resolve,		/* resolve,             spec 3.1.3 */
1121da177e4SLinus Torvalds 	lane2_associate_req,	/* associate_req,       spec 3.1.4 */
1131da177e4SLinus Torvalds 	NULL			/* associate indicator, spec 3.1.5 */
1141da177e4SLinus Torvalds };
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds /* Device structures */
1191da177e4SLinus Torvalds static struct net_device *dev_lec[MAX_LEC_ITF];
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
1221da177e4SLinus Torvalds static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
1231da177e4SLinus Torvalds {
1241da177e4SLinus Torvalds 	struct ethhdr *eth;
1251da177e4SLinus Torvalds 	char *buff;
1261da177e4SLinus Torvalds 	struct lec_priv *priv;
1271da177e4SLinus Torvalds 
128*d44f7746SChas Williams 	/*
129*d44f7746SChas Williams 	 * Check if this is a BPDU. If so, ask zeppelin to send
1301da177e4SLinus Torvalds 	 * LE_TOPOLOGY_REQUEST with the same value of Topology Change bit
131*d44f7746SChas Williams 	 * as the Config BPDU has
132*d44f7746SChas Williams 	 */
1331da177e4SLinus Torvalds 	eth = (struct ethhdr *)skb->data;
1341da177e4SLinus Torvalds 	buff = skb->data + skb->dev->hard_header_len;
1351da177e4SLinus Torvalds 	if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {
1361da177e4SLinus Torvalds 		struct sock *sk;
1371da177e4SLinus Torvalds 		struct sk_buff *skb2;
1381da177e4SLinus Torvalds 		struct atmlec_msg *mesg;
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds 		skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
141*d44f7746SChas Williams 		if (skb2 == NULL)
142*d44f7746SChas Williams 			return;
1431da177e4SLinus Torvalds 		skb2->len = sizeof(struct atmlec_msg);
1441da177e4SLinus Torvalds 		mesg = (struct atmlec_msg *)skb2->data;
1451da177e4SLinus Torvalds 		mesg->type = l_topology_change;
1461da177e4SLinus Torvalds 		buff += 4;
1471da177e4SLinus Torvalds 		mesg->content.normal.flag = *buff & 0x01;	/* 0x01 is topology change */
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds 		priv = (struct lec_priv *)dev->priv;
1501da177e4SLinus Torvalds 		atm_force_charge(priv->lecd, skb2->truesize);
1511da177e4SLinus Torvalds 		sk = sk_atm(priv->lecd);
1521da177e4SLinus Torvalds 		skb_queue_tail(&sk->sk_receive_queue, skb2);
1531da177e4SLinus Torvalds 		sk->sk_data_ready(sk, skb2->len);
1541da177e4SLinus Torvalds 	}
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	return;
1571da177e4SLinus Torvalds }
1581da177e4SLinus Torvalds #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds /*
1611da177e4SLinus Torvalds  * Modelled after tr_type_trans
1621da177e4SLinus Torvalds  * All multicast and ARE or STE frames go to BUS.
1631da177e4SLinus Torvalds  * Non source routed frames go by destination address.
1641da177e4SLinus Torvalds  * Last hop source routed frames go by destination address.
1651da177e4SLinus Torvalds  * Not last hop source routed frames go by _next_ route descriptor.
1661da177e4SLinus Torvalds  * Returns pointer to destination MAC address or fills in rdesc
1671da177e4SLinus Torvalds  * and returns NULL.
1681da177e4SLinus Torvalds  */
1691da177e4SLinus Torvalds #ifdef CONFIG_TR
1701da177e4SLinus Torvalds static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
1711da177e4SLinus Torvalds {
1721da177e4SLinus Torvalds 	struct trh_hdr *trh;
1731da177e4SLinus Torvalds 	int riflen, num_rdsc;
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	trh = (struct trh_hdr *)packet;
1761da177e4SLinus Torvalds 	if (trh->daddr[0] & (uint8_t) 0x80)
1771da177e4SLinus Torvalds 		return bus_mac;	/* multicast */
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds 	if (trh->saddr[0] & TR_RII) {
1801da177e4SLinus Torvalds 		riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
1811da177e4SLinus Torvalds 		if ((ntohs(trh->rcf) >> 13) != 0)
1821da177e4SLinus Torvalds 			return bus_mac;	/* ARE or STE */
183*d44f7746SChas Williams 	} else
1841da177e4SLinus Torvalds 		return trh->daddr;	/* not source routed */
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds 	if (riflen < 6)
1871da177e4SLinus Torvalds 		return trh->daddr;	/* last hop, source routed */
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 	/* riflen is 6 or more, packet has more than one route descriptor */
1901da177e4SLinus Torvalds 	num_rdsc = (riflen / 2) - 1;
1911da177e4SLinus Torvalds 	memset(rdesc, 0, ETH_ALEN);
1921da177e4SLinus Torvalds 	/* offset 4 comes from LAN destination field in LE control frames */
1931da177e4SLinus Torvalds 	if (trh->rcf & htons((uint16_t) TR_RCF_DIR_BIT))
1941da177e4SLinus Torvalds 		memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(uint16_t));
1951da177e4SLinus Torvalds 	else {
1961da177e4SLinus Torvalds 		memcpy(&rdesc[4], &trh->rseg[1], sizeof(uint16_t));
1971da177e4SLinus Torvalds 		rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0));
1981da177e4SLinus Torvalds 	}
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	return NULL;
2011da177e4SLinus Torvalds }
2021da177e4SLinus Torvalds #endif /* CONFIG_TR */
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds /*
2051da177e4SLinus Torvalds  * Open/initialize the netdevice. This is called (in the current kernel)
2061da177e4SLinus Torvalds  * sometime after booting when the 'ifconfig' program is run.
2071da177e4SLinus Torvalds  *
2081da177e4SLinus Torvalds  * This routine should set everything up anew at each open, even
2091da177e4SLinus Torvalds  * registers that "should" only need to be set once at boot, so that
2101da177e4SLinus Torvalds  * there is non-reboot way to recover if something goes wrong.
2111da177e4SLinus Torvalds  */
2121da177e4SLinus Torvalds 
213*d44f7746SChas Williams static int lec_open(struct net_device *dev)
2141da177e4SLinus Torvalds {
2151da177e4SLinus Torvalds 	struct lec_priv *priv = (struct lec_priv *)dev->priv;
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds 	netif_start_queue(dev);
2181da177e4SLinus Torvalds 	memset(&priv->stats, 0, sizeof(struct net_device_stats));
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds 	return 0;
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds static __inline__ void
2241da177e4SLinus Torvalds lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv)
2251da177e4SLinus Torvalds {
2261da177e4SLinus Torvalds 	ATM_SKB(skb)->vcc = vcc;
2271da177e4SLinus Torvalds 	ATM_SKB(skb)->atm_options = vcc->atm_options;
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds 	atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
2301da177e4SLinus Torvalds 	if (vcc->send(vcc, skb) < 0) {
2311da177e4SLinus Torvalds 		priv->stats.tx_dropped++;
2321da177e4SLinus Torvalds 		return;
2331da177e4SLinus Torvalds 	}
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds 	priv->stats.tx_packets++;
2361da177e4SLinus Torvalds 	priv->stats.tx_bytes += skb->len;
2371da177e4SLinus Torvalds }
2381da177e4SLinus Torvalds 
239*d44f7746SChas Williams static void lec_tx_timeout(struct net_device *dev)
2401da177e4SLinus Torvalds {
2411da177e4SLinus Torvalds 	printk(KERN_INFO "%s: tx timeout\n", dev->name);
2421da177e4SLinus Torvalds 	dev->trans_start = jiffies;
2431da177e4SLinus Torvalds 	netif_wake_queue(dev);
2441da177e4SLinus Torvalds }
2451da177e4SLinus Torvalds 
246*d44f7746SChas Williams static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
2471da177e4SLinus Torvalds {
2481da177e4SLinus Torvalds 	struct sk_buff *skb2;
2491da177e4SLinus Torvalds 	struct lec_priv *priv = (struct lec_priv *)dev->priv;
2501da177e4SLinus Torvalds 	struct lecdatahdr_8023 *lec_h;
2511da177e4SLinus Torvalds 	struct atm_vcc *vcc;
2521da177e4SLinus Torvalds 	struct lec_arp_table *entry;
2531da177e4SLinus Torvalds 	unsigned char *dst;
2541da177e4SLinus Torvalds 	int min_frame_size;
2551da177e4SLinus Torvalds #ifdef CONFIG_TR
2561da177e4SLinus Torvalds 	unsigned char rdesc[ETH_ALEN];	/* Token Ring route descriptor */
2571da177e4SLinus Torvalds #endif
2581da177e4SLinus Torvalds 	int is_rdesc;
2591da177e4SLinus Torvalds #if DUMP_PACKETS > 0
2601da177e4SLinus Torvalds 	char buf[300];
2611da177e4SLinus Torvalds 	int i = 0;
2621da177e4SLinus Torvalds #endif /* DUMP_PACKETS >0 */
2631da177e4SLinus Torvalds 
2641da177e4SLinus Torvalds 	DPRINTK("lec_start_xmit called\n");
2651da177e4SLinus Torvalds 	if (!priv->lecd) {
2661da177e4SLinus Torvalds 		printk("%s:No lecd attached\n", dev->name);
2671da177e4SLinus Torvalds 		priv->stats.tx_errors++;
2681da177e4SLinus Torvalds 		netif_stop_queue(dev);
2691da177e4SLinus Torvalds 		return -EUNATCH;
2701da177e4SLinus Torvalds 	}
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 	DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
2731da177e4SLinus Torvalds 		(long)skb->head, (long)skb->data, (long)skb->tail,
2741da177e4SLinus Torvalds 		(long)skb->end);
2751da177e4SLinus Torvalds #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
2761da177e4SLinus Torvalds 	if (memcmp(skb->data, bridge_ula_lec, sizeof(bridge_ula_lec)) == 0)
2771da177e4SLinus Torvalds 		lec_handle_bridge(skb, dev);
2781da177e4SLinus Torvalds #endif
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds 	/* Make sure we have room for lec_id */
2811da177e4SLinus Torvalds 	if (skb_headroom(skb) < 2) {
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 		DPRINTK("lec_start_xmit: reallocating skb\n");
2841da177e4SLinus Torvalds 		skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
2851da177e4SLinus Torvalds 		kfree_skb(skb);
286*d44f7746SChas Williams 		if (skb2 == NULL)
287*d44f7746SChas Williams 			return 0;
2881da177e4SLinus Torvalds 		skb = skb2;
2891da177e4SLinus Torvalds 	}
2901da177e4SLinus Torvalds 	skb_push(skb, 2);
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds 	/* Put le header to place, works for TokenRing too */
2931da177e4SLinus Torvalds 	lec_h = (struct lecdatahdr_8023 *)skb->data;
2941da177e4SLinus Torvalds 	lec_h->le_header = htons(priv->lecid);
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds #ifdef CONFIG_TR
297*d44f7746SChas Williams 	/*
298*d44f7746SChas Williams 	 * Ugly. Use this to realign Token Ring packets for
299*d44f7746SChas Williams 	 * e.g. PCA-200E driver.
300*d44f7746SChas Williams 	 */
3011da177e4SLinus Torvalds 	if (priv->is_trdev) {
3021da177e4SLinus Torvalds 		skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
3031da177e4SLinus Torvalds 		kfree_skb(skb);
304*d44f7746SChas Williams 		if (skb2 == NULL)
305*d44f7746SChas Williams 			return 0;
3061da177e4SLinus Torvalds 		skb = skb2;
3071da177e4SLinus Torvalds 	}
3081da177e4SLinus Torvalds #endif
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds #if DUMP_PACKETS > 0
3111da177e4SLinus Torvalds 	printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name,
3121da177e4SLinus Torvalds 	       skb->len, priv->lecid);
3131da177e4SLinus Torvalds #if DUMP_PACKETS >= 2
3141da177e4SLinus Torvalds 	for (i = 0; i < skb->len && i < 99; i++) {
3151da177e4SLinus Torvalds 		sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
3161da177e4SLinus Torvalds 	}
3171da177e4SLinus Torvalds #elif DUMP_PACKETS >= 1
3181da177e4SLinus Torvalds 	for (i = 0; i < skb->len && i < 30; i++) {
3191da177e4SLinus Torvalds 		sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
3201da177e4SLinus Torvalds 	}
3211da177e4SLinus Torvalds #endif /* DUMP_PACKETS >= 1 */
3221da177e4SLinus Torvalds 	if (i == skb->len)
3231da177e4SLinus Torvalds 		printk("%s\n", buf);
3241da177e4SLinus Torvalds 	else
3251da177e4SLinus Torvalds 		printk("%s...\n", buf);
3261da177e4SLinus Torvalds #endif /* DUMP_PACKETS > 0 */
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds 	/* Minimum ethernet-frame size */
3291da177e4SLinus Torvalds #ifdef CONFIG_TR
3301da177e4SLinus Torvalds 	if (priv->is_trdev)
3311da177e4SLinus Torvalds 		min_frame_size = LEC_MINIMUM_8025_SIZE;
3321da177e4SLinus Torvalds 	else
3331da177e4SLinus Torvalds #endif
3341da177e4SLinus Torvalds 		min_frame_size = LEC_MINIMUM_8023_SIZE;
3351da177e4SLinus Torvalds 	if (skb->len < min_frame_size) {
3361da177e4SLinus Torvalds 		if ((skb->len + skb_tailroom(skb)) < min_frame_size) {
3371da177e4SLinus Torvalds 			skb2 = skb_copy_expand(skb, 0,
338*d44f7746SChas Williams 					       min_frame_size - skb->truesize,
339*d44f7746SChas Williams 					       GFP_ATOMIC);
3401da177e4SLinus Torvalds 			dev_kfree_skb(skb);
3411da177e4SLinus Torvalds 			if (skb2 == NULL) {
3421da177e4SLinus Torvalds 				priv->stats.tx_dropped++;
3431da177e4SLinus Torvalds 				return 0;
3441da177e4SLinus Torvalds 			}
3451da177e4SLinus Torvalds 			skb = skb2;
3461da177e4SLinus Torvalds 		}
3471da177e4SLinus Torvalds 		skb_put(skb, min_frame_size - skb->len);
3481da177e4SLinus Torvalds 	}
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds 	/* Send to right vcc */
3511da177e4SLinus Torvalds 	is_rdesc = 0;
3521da177e4SLinus Torvalds 	dst = lec_h->h_dest;
3531da177e4SLinus Torvalds #ifdef CONFIG_TR
3541da177e4SLinus Torvalds 	if (priv->is_trdev) {
3551da177e4SLinus Torvalds 		dst = get_tr_dst(skb->data + 2, rdesc);
3561da177e4SLinus Torvalds 		if (dst == NULL) {
3571da177e4SLinus Torvalds 			dst = rdesc;
3581da177e4SLinus Torvalds 			is_rdesc = 1;
3591da177e4SLinus Torvalds 		}
3601da177e4SLinus Torvalds 	}
3611da177e4SLinus Torvalds #endif
3621da177e4SLinus Torvalds 	entry = NULL;
3631da177e4SLinus Torvalds 	vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
3641da177e4SLinus Torvalds 	DPRINTK("%s:vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
3651da177e4SLinus Torvalds 		vcc, vcc ? vcc->flags : 0, entry);
3661da177e4SLinus Torvalds 	if (!vcc || !test_bit(ATM_VF_READY, &vcc->flags)) {
3671da177e4SLinus Torvalds 		if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
368*d44f7746SChas Williams 			DPRINTK("%s:lec_start_xmit: queuing packet, ",
369*d44f7746SChas Williams 				dev->name);
3701da177e4SLinus Torvalds 			DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
371*d44f7746SChas Williams 				lec_h->h_dest[0], lec_h->h_dest[1],
372*d44f7746SChas Williams 				lec_h->h_dest[2], lec_h->h_dest[3],
373*d44f7746SChas Williams 				lec_h->h_dest[4], lec_h->h_dest[5]);
3741da177e4SLinus Torvalds 			skb_queue_tail(&entry->tx_wait, skb);
3751da177e4SLinus Torvalds 		} else {
376*d44f7746SChas Williams 			DPRINTK
377*d44f7746SChas Williams 			    ("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ",
378*d44f7746SChas Williams 			     dev->name);
3791da177e4SLinus Torvalds 			DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
380*d44f7746SChas Williams 				lec_h->h_dest[0], lec_h->h_dest[1],
381*d44f7746SChas Williams 				lec_h->h_dest[2], lec_h->h_dest[3],
382*d44f7746SChas Williams 				lec_h->h_dest[4], lec_h->h_dest[5]);
3831da177e4SLinus Torvalds 			priv->stats.tx_dropped++;
3841da177e4SLinus Torvalds 			dev_kfree_skb(skb);
3851da177e4SLinus Torvalds 		}
3861da177e4SLinus Torvalds 		return 0;
3871da177e4SLinus Torvalds 	}
3881da177e4SLinus Torvalds #if DUMP_PACKETS > 0
389*d44f7746SChas Williams 	printk("%s:sending to vpi:%d vci:%d\n", dev->name, vcc->vpi, vcc->vci);
3901da177e4SLinus Torvalds #endif /* DUMP_PACKETS > 0 */
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds 	while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
3931da177e4SLinus Torvalds 		DPRINTK("lec.c: emptying tx queue, ");
3941da177e4SLinus Torvalds 		DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
3951da177e4SLinus Torvalds 			lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
3961da177e4SLinus Torvalds 			lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
3971da177e4SLinus Torvalds 		lec_send(vcc, skb2, priv);
3981da177e4SLinus Torvalds 	}
3991da177e4SLinus Torvalds 
4001da177e4SLinus Torvalds 	lec_send(vcc, skb, priv);
4011da177e4SLinus Torvalds 
4021da177e4SLinus Torvalds 	if (!atm_may_send(vcc, 0)) {
4031da177e4SLinus Torvalds 		struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
4041da177e4SLinus Torvalds 
4051da177e4SLinus Torvalds 		vpriv->xoff = 1;
4061da177e4SLinus Torvalds 		netif_stop_queue(dev);
4071da177e4SLinus Torvalds 
4081da177e4SLinus Torvalds 		/*
4091da177e4SLinus Torvalds 		 * vcc->pop() might have occurred in between, making
4101da177e4SLinus Torvalds 		 * the vcc usuable again.  Since xmit is serialized,
4111da177e4SLinus Torvalds 		 * this is the only situation we have to re-test.
4121da177e4SLinus Torvalds 		 */
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds 		if (atm_may_send(vcc, 0))
4151da177e4SLinus Torvalds 			netif_wake_queue(dev);
4161da177e4SLinus Torvalds 	}
4171da177e4SLinus Torvalds 
4181da177e4SLinus Torvalds 	dev->trans_start = jiffies;
4191da177e4SLinus Torvalds 	return 0;
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds /* The inverse routine to net_open(). */
423*d44f7746SChas Williams static int lec_close(struct net_device *dev)
4241da177e4SLinus Torvalds {
4251da177e4SLinus Torvalds 	netif_stop_queue(dev);
4261da177e4SLinus Torvalds 	return 0;
4271da177e4SLinus Torvalds }
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds /*
4301da177e4SLinus Torvalds  * Get the current statistics.
4311da177e4SLinus Torvalds  * This may be called with the card open or closed.
4321da177e4SLinus Torvalds  */
433*d44f7746SChas Williams static struct net_device_stats *lec_get_stats(struct net_device *dev)
4341da177e4SLinus Torvalds {
4351da177e4SLinus Torvalds 	return &((struct lec_priv *)dev->priv)->stats;
4361da177e4SLinus Torvalds }
4371da177e4SLinus Torvalds 
438*d44f7746SChas Williams static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
4391da177e4SLinus Torvalds {
4401da177e4SLinus Torvalds 	unsigned long flags;
4411da177e4SLinus Torvalds 	struct net_device *dev = (struct net_device *)vcc->proto_data;
4421da177e4SLinus Torvalds 	struct lec_priv *priv = (struct lec_priv *)dev->priv;
4431da177e4SLinus Torvalds 	struct atmlec_msg *mesg;
4441da177e4SLinus Torvalds 	struct lec_arp_table *entry;
4451da177e4SLinus Torvalds 	int i;
4461da177e4SLinus Torvalds 	char *tmp;		/* FIXME */
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds 	atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
4491da177e4SLinus Torvalds 	mesg = (struct atmlec_msg *)skb->data;
4501da177e4SLinus Torvalds 	tmp = skb->data;
4511da177e4SLinus Torvalds 	tmp += sizeof(struct atmlec_msg);
4521da177e4SLinus Torvalds 	DPRINTK("%s: msg from zeppelin:%d\n", dev->name, mesg->type);
4531da177e4SLinus Torvalds 	switch (mesg->type) {
4541da177e4SLinus Torvalds 	case l_set_mac_addr:
4551da177e4SLinus Torvalds 		for (i = 0; i < 6; i++) {
4561da177e4SLinus Torvalds 			dev->dev_addr[i] = mesg->content.normal.mac_addr[i];
4571da177e4SLinus Torvalds 		}
4581da177e4SLinus Torvalds 		break;
4591da177e4SLinus Torvalds 	case l_del_mac_addr:
4601da177e4SLinus Torvalds 		for (i = 0; i < 6; i++) {
4611da177e4SLinus Torvalds 			dev->dev_addr[i] = 0;
4621da177e4SLinus Torvalds 		}
4631da177e4SLinus Torvalds 		break;
4641da177e4SLinus Torvalds 	case l_addr_delete:
4651da177e4SLinus Torvalds 		lec_addr_delete(priv, mesg->content.normal.atm_addr,
4661da177e4SLinus Torvalds 				mesg->content.normal.flag);
4671da177e4SLinus Torvalds 		break;
4681da177e4SLinus Torvalds 	case l_topology_change:
4691da177e4SLinus Torvalds 		priv->topology_change = mesg->content.normal.flag;
4701da177e4SLinus Torvalds 		break;
4711da177e4SLinus Torvalds 	case l_flush_complete:
4721da177e4SLinus Torvalds 		lec_flush_complete(priv, mesg->content.normal.flag);
4731da177e4SLinus Torvalds 		break;
4741da177e4SLinus Torvalds 	case l_narp_req:	/* LANE2: see 7.1.35 in the lane2 spec */
4751da177e4SLinus Torvalds 		spin_lock_irqsave(&priv->lec_arp_lock, flags);
4761da177e4SLinus Torvalds 		entry = lec_arp_find(priv, mesg->content.normal.mac_addr);
4771da177e4SLinus Torvalds 		lec_arp_remove(priv, entry);
4781da177e4SLinus Torvalds 		spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds 		if (mesg->content.normal.no_source_le_narp)
4811da177e4SLinus Torvalds 			break;
4821da177e4SLinus Torvalds 		/* FALL THROUGH */
4831da177e4SLinus Torvalds 	case l_arp_update:
4841da177e4SLinus Torvalds 		lec_arp_update(priv, mesg->content.normal.mac_addr,
4851da177e4SLinus Torvalds 			       mesg->content.normal.atm_addr,
4861da177e4SLinus Torvalds 			       mesg->content.normal.flag,
4871da177e4SLinus Torvalds 			       mesg->content.normal.targetless_le_arp);
4881da177e4SLinus Torvalds 		DPRINTK("lec: in l_arp_update\n");
4891da177e4SLinus Torvalds 		if (mesg->sizeoftlvs != 0) {	/* LANE2 3.1.5 */
490*d44f7746SChas Williams 			DPRINTK("lec: LANE2 3.1.5, got tlvs, size %d\n",
491*d44f7746SChas Williams 				mesg->sizeoftlvs);
492*d44f7746SChas Williams 			lane2_associate_ind(dev, mesg->content.normal.mac_addr,
4931da177e4SLinus Torvalds 					    tmp, mesg->sizeoftlvs);
4941da177e4SLinus Torvalds 		}
4951da177e4SLinus Torvalds 		break;
4961da177e4SLinus Torvalds 	case l_config:
4971da177e4SLinus Torvalds 		priv->maximum_unknown_frame_count =
4981da177e4SLinus Torvalds 		    mesg->content.config.maximum_unknown_frame_count;
4991da177e4SLinus Torvalds 		priv->max_unknown_frame_time =
5001da177e4SLinus Torvalds 		    (mesg->content.config.max_unknown_frame_time * HZ);
501*d44f7746SChas Williams 		priv->max_retry_count = mesg->content.config.max_retry_count;
5021da177e4SLinus Torvalds 		priv->aging_time = (mesg->content.config.aging_time * HZ);
5031da177e4SLinus Torvalds 		priv->forward_delay_time =
5041da177e4SLinus Torvalds 		    (mesg->content.config.forward_delay_time * HZ);
5051da177e4SLinus Torvalds 		priv->arp_response_time =
5061da177e4SLinus Torvalds 		    (mesg->content.config.arp_response_time * HZ);
5071da177e4SLinus Torvalds 		priv->flush_timeout = (mesg->content.config.flush_timeout * HZ);
5081da177e4SLinus Torvalds 		priv->path_switching_delay =
5091da177e4SLinus Torvalds 		    (mesg->content.config.path_switching_delay * HZ);
5101da177e4SLinus Torvalds 		priv->lane_version = mesg->content.config.lane_version;	/* LANE2 */
5111da177e4SLinus Torvalds 		priv->lane2_ops = NULL;
5121da177e4SLinus Torvalds 		if (priv->lane_version > 1)
5131da177e4SLinus Torvalds 			priv->lane2_ops = &lane2_ops;
5141da177e4SLinus Torvalds 		if (dev->change_mtu(dev, mesg->content.config.mtu))
5151da177e4SLinus Torvalds 			printk("%s: change_mtu to %d failed\n", dev->name,
5161da177e4SLinus Torvalds 			       mesg->content.config.mtu);
5171da177e4SLinus Torvalds 		priv->is_proxy = mesg->content.config.is_proxy;
5181da177e4SLinus Torvalds 		break;
5191da177e4SLinus Torvalds 	case l_flush_tran_id:
5201da177e4SLinus Torvalds 		lec_set_flush_tran_id(priv, mesg->content.normal.atm_addr,
5211da177e4SLinus Torvalds 				      mesg->content.normal.flag);
5221da177e4SLinus Torvalds 		break;
5231da177e4SLinus Torvalds 	case l_set_lecid:
524*d44f7746SChas Williams 		priv->lecid =
525*d44f7746SChas Williams 		    (unsigned short)(0xffff & mesg->content.normal.flag);
5261da177e4SLinus Torvalds 		break;
527*d44f7746SChas Williams 	case l_should_bridge:
5281da177e4SLinus Torvalds #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
529*d44f7746SChas Williams 		{
5301da177e4SLinus Torvalds 			struct net_bridge_fdb_entry *f;
5311da177e4SLinus Torvalds 
532*d44f7746SChas Williams 			DPRINTK
533*d44f7746SChas Williams 			    ("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
534*d44f7746SChas Williams 			     dev->name, mesg->content.proxy.mac_addr[0],
535*d44f7746SChas Williams 			     mesg->content.proxy.mac_addr[1],
536*d44f7746SChas Williams 			     mesg->content.proxy.mac_addr[2],
537*d44f7746SChas Williams 			     mesg->content.proxy.mac_addr[3],
538*d44f7746SChas Williams 			     mesg->content.proxy.mac_addr[4],
539*d44f7746SChas Williams 			     mesg->content.proxy.mac_addr[5]);
5401da177e4SLinus Torvalds 
5411da177e4SLinus Torvalds 			if (br_fdb_get_hook == NULL || dev->br_port == NULL)
5421da177e4SLinus Torvalds 				break;
5431da177e4SLinus Torvalds 
544*d44f7746SChas Williams 			f = br_fdb_get_hook(dev->br_port->br,
545*d44f7746SChas Williams 					    mesg->content.proxy.mac_addr);
546*d44f7746SChas Williams 			if (f != NULL && f->dst->dev != dev
547*d44f7746SChas Williams 			    && f->dst->state == BR_STATE_FORWARDING) {
5481da177e4SLinus Torvalds 				/* hit from bridge table, send LE_ARP_RESPONSE */
5491da177e4SLinus Torvalds 				struct sk_buff *skb2;
5501da177e4SLinus Torvalds 				struct sock *sk;
5511da177e4SLinus Torvalds 
552*d44f7746SChas Williams 				DPRINTK
553*d44f7746SChas Williams 				    ("%s: entry found, responding to zeppelin\n",
554*d44f7746SChas Williams 				     dev->name);
555*d44f7746SChas Williams 				skb2 =
556*d44f7746SChas Williams 				    alloc_skb(sizeof(struct atmlec_msg),
557*d44f7746SChas Williams 					      GFP_ATOMIC);
5581da177e4SLinus Torvalds 				if (skb2 == NULL) {
5591da177e4SLinus Torvalds 					br_fdb_put_hook(f);
5601da177e4SLinus Torvalds 					break;
5611da177e4SLinus Torvalds 				}
5621da177e4SLinus Torvalds 				skb2->len = sizeof(struct atmlec_msg);
563*d44f7746SChas Williams 				memcpy(skb2->data, mesg,
564*d44f7746SChas Williams 				       sizeof(struct atmlec_msg));
5651da177e4SLinus Torvalds 				atm_force_charge(priv->lecd, skb2->truesize);
5661da177e4SLinus Torvalds 				sk = sk_atm(priv->lecd);
5671da177e4SLinus Torvalds 				skb_queue_tail(&sk->sk_receive_queue, skb2);
5681da177e4SLinus Torvalds 				sk->sk_data_ready(sk, skb2->len);
5691da177e4SLinus Torvalds 			}
570*d44f7746SChas Williams 			if (f != NULL)
571*d44f7746SChas Williams 				br_fdb_put_hook(f);
5721da177e4SLinus Torvalds 		}
573*d44f7746SChas Williams #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
5741da177e4SLinus Torvalds 		break;
5751da177e4SLinus Torvalds 	default:
5761da177e4SLinus Torvalds 		printk("%s: Unknown message type %d\n", dev->name, mesg->type);
5771da177e4SLinus Torvalds 		dev_kfree_skb(skb);
5781da177e4SLinus Torvalds 		return -EINVAL;
5791da177e4SLinus Torvalds 	}
5801da177e4SLinus Torvalds 	dev_kfree_skb(skb);
5811da177e4SLinus Torvalds 	return 0;
5821da177e4SLinus Torvalds }
5831da177e4SLinus Torvalds 
584*d44f7746SChas Williams static void lec_atm_close(struct atm_vcc *vcc)
5851da177e4SLinus Torvalds {
5861da177e4SLinus Torvalds 	struct sk_buff *skb;
5871da177e4SLinus Torvalds 	struct net_device *dev = (struct net_device *)vcc->proto_data;
5881da177e4SLinus Torvalds 	struct lec_priv *priv = (struct lec_priv *)dev->priv;
5891da177e4SLinus Torvalds 
5901da177e4SLinus Torvalds 	priv->lecd = NULL;
5911da177e4SLinus Torvalds 	/* Do something needful? */
5921da177e4SLinus Torvalds 
5931da177e4SLinus Torvalds 	netif_stop_queue(dev);
5941da177e4SLinus Torvalds 	lec_arp_destroy(priv);
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds 	if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
5971da177e4SLinus Torvalds 		printk("%s lec_atm_close: closing with messages pending\n",
5981da177e4SLinus Torvalds 		       dev->name);
5991da177e4SLinus Torvalds 	while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue)) != NULL) {
6001da177e4SLinus Torvalds 		atm_return(vcc, skb->truesize);
6011da177e4SLinus Torvalds 		dev_kfree_skb(skb);
6021da177e4SLinus Torvalds 	}
6031da177e4SLinus Torvalds 
6041da177e4SLinus Torvalds 	printk("%s: Shut down!\n", dev->name);
6051da177e4SLinus Torvalds 	module_put(THIS_MODULE);
6061da177e4SLinus Torvalds }
6071da177e4SLinus Torvalds 
6081da177e4SLinus Torvalds static struct atmdev_ops lecdev_ops = {
6091da177e4SLinus Torvalds 	.close = lec_atm_close,
6101da177e4SLinus Torvalds 	.send = lec_atm_send
6111da177e4SLinus Torvalds };
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds static struct atm_dev lecatm_dev = {
6141da177e4SLinus Torvalds 	.ops = &lecdev_ops,
6151da177e4SLinus Torvalds 	.type = "lec",
6161da177e4SLinus Torvalds 	.number = 999,		/* dummy device number */
6171da177e4SLinus Torvalds 	.lock = SPIN_LOCK_UNLOCKED
6181da177e4SLinus Torvalds };
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds /*
6211da177e4SLinus Torvalds  * LANE2: new argument struct sk_buff *data contains
6221da177e4SLinus Torvalds  * the LE_ARP based TLVs introduced in the LANE2 spec
6231da177e4SLinus Torvalds  */
6241da177e4SLinus Torvalds static int
6251da177e4SLinus Torvalds send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
6261da177e4SLinus Torvalds 	     unsigned char *mac_addr, unsigned char *atm_addr,
6271da177e4SLinus Torvalds 	     struct sk_buff *data)
6281da177e4SLinus Torvalds {
6291da177e4SLinus Torvalds 	struct sock *sk;
6301da177e4SLinus Torvalds 	struct sk_buff *skb;
6311da177e4SLinus Torvalds 	struct atmlec_msg *mesg;
6321da177e4SLinus Torvalds 
6331da177e4SLinus Torvalds 	if (!priv || !priv->lecd) {
6341da177e4SLinus Torvalds 		return -1;
6351da177e4SLinus Torvalds 	}
6361da177e4SLinus Torvalds 	skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
6371da177e4SLinus Torvalds 	if (!skb)
6381da177e4SLinus Torvalds 		return -1;
6391da177e4SLinus Torvalds 	skb->len = sizeof(struct atmlec_msg);
6401da177e4SLinus Torvalds 	mesg = (struct atmlec_msg *)skb->data;
6411da177e4SLinus Torvalds 	memset(mesg, 0, sizeof(struct atmlec_msg));
6421da177e4SLinus Torvalds 	mesg->type = type;
6431da177e4SLinus Torvalds 	if (data != NULL)
6441da177e4SLinus Torvalds 		mesg->sizeoftlvs = data->len;
6451da177e4SLinus Torvalds 	if (mac_addr)
6461da177e4SLinus Torvalds 		memcpy(&mesg->content.normal.mac_addr, mac_addr, ETH_ALEN);
6471da177e4SLinus Torvalds 	else
6481da177e4SLinus Torvalds 		mesg->content.normal.targetless_le_arp = 1;
6491da177e4SLinus Torvalds 	if (atm_addr)
6501da177e4SLinus Torvalds 		memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
6511da177e4SLinus Torvalds 
6521da177e4SLinus Torvalds 	atm_force_charge(priv->lecd, skb->truesize);
6531da177e4SLinus Torvalds 	sk = sk_atm(priv->lecd);
6541da177e4SLinus Torvalds 	skb_queue_tail(&sk->sk_receive_queue, skb);
6551da177e4SLinus Torvalds 	sk->sk_data_ready(sk, skb->len);
6561da177e4SLinus Torvalds 
6571da177e4SLinus Torvalds 	if (data != NULL) {
6581da177e4SLinus Torvalds 		DPRINTK("lec: about to send %d bytes of data\n", data->len);
6591da177e4SLinus Torvalds 		atm_force_charge(priv->lecd, data->truesize);
6601da177e4SLinus Torvalds 		skb_queue_tail(&sk->sk_receive_queue, data);
6611da177e4SLinus Torvalds 		sk->sk_data_ready(sk, skb->len);
6621da177e4SLinus Torvalds 	}
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds 	return 0;
6651da177e4SLinus Torvalds }
6661da177e4SLinus Torvalds 
6671da177e4SLinus Torvalds /* shamelessly stolen from drivers/net/net_init.c */
6681da177e4SLinus Torvalds static int lec_change_mtu(struct net_device *dev, int new_mtu)
6691da177e4SLinus Torvalds {
6701da177e4SLinus Torvalds 	if ((new_mtu < 68) || (new_mtu > 18190))
6711da177e4SLinus Torvalds 		return -EINVAL;
6721da177e4SLinus Torvalds 	dev->mtu = new_mtu;
6731da177e4SLinus Torvalds 	return 0;
6741da177e4SLinus Torvalds }
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds static void lec_set_multicast_list(struct net_device *dev)
6771da177e4SLinus Torvalds {
678*d44f7746SChas Williams 	/*
679*d44f7746SChas Williams 	 * by default, all multicast frames arrive over the bus.
6801da177e4SLinus Torvalds 	 * eventually support selective multicast service
6811da177e4SLinus Torvalds 	 */
6821da177e4SLinus Torvalds 	return;
6831da177e4SLinus Torvalds }
6841da177e4SLinus Torvalds 
685*d44f7746SChas Williams static void lec_init(struct net_device *dev)
6861da177e4SLinus Torvalds {
6871da177e4SLinus Torvalds 	dev->change_mtu = lec_change_mtu;
6881da177e4SLinus Torvalds 	dev->open = lec_open;
6891da177e4SLinus Torvalds 	dev->stop = lec_close;
6901da177e4SLinus Torvalds 	dev->hard_start_xmit = lec_start_xmit;
6911da177e4SLinus Torvalds 	dev->tx_timeout = lec_tx_timeout;
6921da177e4SLinus Torvalds 
6931da177e4SLinus Torvalds 	dev->get_stats = lec_get_stats;
6941da177e4SLinus Torvalds 	dev->set_multicast_list = lec_set_multicast_list;
6951da177e4SLinus Torvalds 	dev->do_ioctl = NULL;
6961da177e4SLinus Torvalds 	printk("%s: Initialized!\n", dev->name);
6971da177e4SLinus Torvalds 	return;
6981da177e4SLinus Torvalds }
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds static unsigned char lec_ctrl_magic[] = {
7011da177e4SLinus Torvalds 	0xff,
7021da177e4SLinus Torvalds 	0x00,
7031da177e4SLinus Torvalds 	0x01,
704*d44f7746SChas Williams 	0x01
705*d44f7746SChas Williams };
7061da177e4SLinus Torvalds 
7074a7097fcSScott Talbert #define LEC_DATA_DIRECT_8023  2
7084a7097fcSScott Talbert #define LEC_DATA_DIRECT_8025  3
7094a7097fcSScott Talbert 
7104a7097fcSScott Talbert static int lec_is_data_direct(struct atm_vcc *vcc)
7114a7097fcSScott Talbert {
7124a7097fcSScott Talbert 	return ((vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8023) ||
7134a7097fcSScott Talbert 		(vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8025));
7144a7097fcSScott Talbert }
7154a7097fcSScott Talbert 
716*d44f7746SChas Williams static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
7171da177e4SLinus Torvalds {
7184a7097fcSScott Talbert 	unsigned long flags;
7191da177e4SLinus Torvalds 	struct net_device *dev = (struct net_device *)vcc->proto_data;
7201da177e4SLinus Torvalds 	struct lec_priv *priv = (struct lec_priv *)dev->priv;
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds #if DUMP_PACKETS >0
7231da177e4SLinus Torvalds 	int i = 0;
7241da177e4SLinus Torvalds 	char buf[300];
7251da177e4SLinus Torvalds 
7261da177e4SLinus Torvalds 	printk("%s: lec_push vcc vpi:%d vci:%d\n", dev->name,
7271da177e4SLinus Torvalds 	       vcc->vpi, vcc->vci);
7281da177e4SLinus Torvalds #endif
7291da177e4SLinus Torvalds 	if (!skb) {
7301da177e4SLinus Torvalds 		DPRINTK("%s: null skb\n", dev->name);
7311da177e4SLinus Torvalds 		lec_vcc_close(priv, vcc);
7321da177e4SLinus Torvalds 		return;
7331da177e4SLinus Torvalds 	}
7341da177e4SLinus Torvalds #if DUMP_PACKETS > 0
7351da177e4SLinus Torvalds 	printk("%s: rcv datalen:%ld lecid:%4.4x\n", dev->name,
7361da177e4SLinus Torvalds 	       skb->len, priv->lecid);
7371da177e4SLinus Torvalds #if DUMP_PACKETS >= 2
7381da177e4SLinus Torvalds 	for (i = 0; i < skb->len && i < 99; i++) {
7391da177e4SLinus Torvalds 		sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
7401da177e4SLinus Torvalds 	}
7411da177e4SLinus Torvalds #elif DUMP_PACKETS >= 1
7421da177e4SLinus Torvalds 	for (i = 0; i < skb->len && i < 30; i++) {
7431da177e4SLinus Torvalds 		sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
7441da177e4SLinus Torvalds 	}
7451da177e4SLinus Torvalds #endif /* DUMP_PACKETS >= 1 */
7461da177e4SLinus Torvalds 	if (i == skb->len)
7471da177e4SLinus Torvalds 		printk("%s\n", buf);
7481da177e4SLinus Torvalds 	else
7491da177e4SLinus Torvalds 		printk("%s...\n", buf);
7501da177e4SLinus Torvalds #endif /* DUMP_PACKETS > 0 */
7511da177e4SLinus Torvalds 	if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) {	/* Control frame, to daemon */
7521da177e4SLinus Torvalds 		struct sock *sk = sk_atm(vcc);
7531da177e4SLinus Torvalds 
7541da177e4SLinus Torvalds 		DPRINTK("%s: To daemon\n", dev->name);
7551da177e4SLinus Torvalds 		skb_queue_tail(&sk->sk_receive_queue, skb);
7561da177e4SLinus Torvalds 		sk->sk_data_ready(sk, skb->len);
7571da177e4SLinus Torvalds 	} else {		/* Data frame, queue to protocol handlers */
7584a7097fcSScott Talbert 		struct lec_arp_table *entry;
7594a7097fcSScott Talbert 		unsigned char *src, *dst;
7601da177e4SLinus Torvalds 
7611da177e4SLinus Torvalds 		atm_return(vcc, skb->truesize);
7621da177e4SLinus Torvalds 		if (*(uint16_t *) skb->data == htons(priv->lecid) ||
763*d44f7746SChas Williams 		    !priv->lecd || !(dev->flags & IFF_UP)) {
764*d44f7746SChas Williams 			/*
765*d44f7746SChas Williams 			 * Probably looping back, or if lecd is missing,
766*d44f7746SChas Williams 			 * lecd has gone down
767*d44f7746SChas Williams 			 */
7681da177e4SLinus Torvalds 			DPRINTK("Ignoring frame...\n");
7691da177e4SLinus Torvalds 			dev_kfree_skb(skb);
7701da177e4SLinus Torvalds 			return;
7711da177e4SLinus Torvalds 		}
7721da177e4SLinus Torvalds #ifdef CONFIG_TR
7734a7097fcSScott Talbert 		if (priv->is_trdev)
7744a7097fcSScott Talbert 			dst = ((struct lecdatahdr_8025 *)skb->data)->h_dest;
7751da177e4SLinus Torvalds 		else
7761da177e4SLinus Torvalds #endif
7771da177e4SLinus Torvalds 			dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest;
7781da177e4SLinus Torvalds 
779*d44f7746SChas Williams 		/*
780*d44f7746SChas Williams 		 * If this is a Data Direct VCC, and the VCC does not match
7814a7097fcSScott Talbert 		 * the LE_ARP cache entry, delete the LE_ARP cache entry.
7824a7097fcSScott Talbert 		 */
7834a7097fcSScott Talbert 		spin_lock_irqsave(&priv->lec_arp_lock, flags);
7844a7097fcSScott Talbert 		if (lec_is_data_direct(vcc)) {
7854a7097fcSScott Talbert #ifdef CONFIG_TR
7864a7097fcSScott Talbert 			if (priv->is_trdev)
787*d44f7746SChas Williams 				src =
788*d44f7746SChas Williams 				    ((struct lecdatahdr_8025 *)skb->data)->
789*d44f7746SChas Williams 				    h_source;
7904a7097fcSScott Talbert 			else
7914a7097fcSScott Talbert #endif
792*d44f7746SChas Williams 				src =
793*d44f7746SChas Williams 				    ((struct lecdatahdr_8023 *)skb->data)->
794*d44f7746SChas Williams 				    h_source;
7954a7097fcSScott Talbert 			entry = lec_arp_find(priv, src);
7964a7097fcSScott Talbert 			if (entry && entry->vcc != vcc) {
7974a7097fcSScott Talbert 				lec_arp_remove(priv, entry);
7984a7097fcSScott Talbert 				kfree(entry);
7994a7097fcSScott Talbert 			}
8004a7097fcSScott Talbert 		}
8014a7097fcSScott Talbert 		spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
8024a7097fcSScott Talbert 
8031da177e4SLinus Torvalds 		if (!(dst[0] & 0x01) &&	/* Never filter Multi/Broadcast */
8041da177e4SLinus Torvalds 		    !priv->is_proxy &&	/* Proxy wants all the packets */
8051da177e4SLinus Torvalds 		    memcmp(dst, dev->dev_addr, dev->addr_len)) {
8061da177e4SLinus Torvalds 			dev_kfree_skb(skb);
8071da177e4SLinus Torvalds 			return;
8081da177e4SLinus Torvalds 		}
8091da177e4SLinus Torvalds 		if (priv->lec_arp_empty_ones) {
8101da177e4SLinus Torvalds 			lec_arp_check_empties(priv, vcc, skb);
8111da177e4SLinus Torvalds 		}
8121da177e4SLinus Torvalds 		skb->dev = dev;
8131da177e4SLinus Torvalds 		skb_pull(skb, 2);	/* skip lec_id */
8141da177e4SLinus Torvalds #ifdef CONFIG_TR
815*d44f7746SChas Williams 		if (priv->is_trdev)
816*d44f7746SChas Williams 			skb->protocol = tr_type_trans(skb, dev);
8171da177e4SLinus Torvalds 		else
8181da177e4SLinus Torvalds #endif
8191da177e4SLinus Torvalds 			skb->protocol = eth_type_trans(skb, dev);
8201da177e4SLinus Torvalds 		priv->stats.rx_packets++;
8211da177e4SLinus Torvalds 		priv->stats.rx_bytes += skb->len;
8221da177e4SLinus Torvalds 		memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
8231da177e4SLinus Torvalds 		netif_rx(skb);
8241da177e4SLinus Torvalds 	}
8251da177e4SLinus Torvalds }
8261da177e4SLinus Torvalds 
827*d44f7746SChas Williams static void lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
8281da177e4SLinus Torvalds {
8291da177e4SLinus Torvalds 	struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
8301da177e4SLinus Torvalds 	struct net_device *dev = skb->dev;
8311da177e4SLinus Torvalds 
8321da177e4SLinus Torvalds 	if (vpriv == NULL) {
8331da177e4SLinus Torvalds 		printk("lec_pop(): vpriv = NULL!?!?!?\n");
8341da177e4SLinus Torvalds 		return;
8351da177e4SLinus Torvalds 	}
8361da177e4SLinus Torvalds 
8371da177e4SLinus Torvalds 	vpriv->old_pop(vcc, skb);
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	if (vpriv->xoff && atm_may_send(vcc, 0)) {
8401da177e4SLinus Torvalds 		vpriv->xoff = 0;
8411da177e4SLinus Torvalds 		if (netif_running(dev) && netif_queue_stopped(dev))
8421da177e4SLinus Torvalds 			netif_wake_queue(dev);
8431da177e4SLinus Torvalds 	}
8441da177e4SLinus Torvalds }
8451da177e4SLinus Torvalds 
846*d44f7746SChas Williams static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
8471da177e4SLinus Torvalds {
8481da177e4SLinus Torvalds 	struct lec_vcc_priv *vpriv;
8491da177e4SLinus Torvalds 	int bytes_left;
8501da177e4SLinus Torvalds 	struct atmlec_ioc ioc_data;
8511da177e4SLinus Torvalds 
8521da177e4SLinus Torvalds 	/* Lecd must be up in this case */
8531da177e4SLinus Torvalds 	bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
8541da177e4SLinus Torvalds 	if (bytes_left != 0) {
855*d44f7746SChas Williams 		printk
856*d44f7746SChas Williams 		    ("lec: lec_vcc_attach, copy from user failed for %d bytes\n",
8571da177e4SLinus Torvalds 		     bytes_left);
8581da177e4SLinus Torvalds 	}
8591da177e4SLinus Torvalds 	if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF ||
8601da177e4SLinus Torvalds 	    !dev_lec[ioc_data.dev_num])
8611da177e4SLinus Torvalds 		return -EINVAL;
8621da177e4SLinus Torvalds 	if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL)))
8631da177e4SLinus Torvalds 		return -ENOMEM;
8641da177e4SLinus Torvalds 	vpriv->xoff = 0;
8651da177e4SLinus Torvalds 	vpriv->old_pop = vcc->pop;
8661da177e4SLinus Torvalds 	vcc->user_back = vpriv;
8671da177e4SLinus Torvalds 	vcc->pop = lec_pop;
8681da177e4SLinus Torvalds 	lec_vcc_added(dev_lec[ioc_data.dev_num]->priv,
8691da177e4SLinus Torvalds 		      &ioc_data, vcc, vcc->push);
8701da177e4SLinus Torvalds 	vcc->proto_data = dev_lec[ioc_data.dev_num];
8711da177e4SLinus Torvalds 	vcc->push = lec_push;
8721da177e4SLinus Torvalds 	return 0;
8731da177e4SLinus Torvalds }
8741da177e4SLinus Torvalds 
875*d44f7746SChas Williams static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
8761da177e4SLinus Torvalds {
8771da177e4SLinus Torvalds 	if (arg < 0 || arg >= MAX_LEC_ITF || !dev_lec[arg])
8781da177e4SLinus Torvalds 		return -EINVAL;
8791da177e4SLinus Torvalds 	vcc->proto_data = dev_lec[arg];
8801da177e4SLinus Torvalds 	return (lec_mcast_make((struct lec_priv *)dev_lec[arg]->priv, vcc));
8811da177e4SLinus Torvalds }
8821da177e4SLinus Torvalds 
8831da177e4SLinus Torvalds /* Initialize device. */
884*d44f7746SChas Williams static int lecd_attach(struct atm_vcc *vcc, int arg)
8851da177e4SLinus Torvalds {
8861da177e4SLinus Torvalds 	int i;
8871da177e4SLinus Torvalds 	struct lec_priv *priv;
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds 	if (arg < 0)
8901da177e4SLinus Torvalds 		i = 0;
8911da177e4SLinus Torvalds 	else
8921da177e4SLinus Torvalds 		i = arg;
8931da177e4SLinus Torvalds #ifdef CONFIG_TR
8941da177e4SLinus Torvalds 	if (arg >= MAX_LEC_ITF)
8951da177e4SLinus Torvalds 		return -EINVAL;
8961da177e4SLinus Torvalds #else				/* Reserve the top NUM_TR_DEVS for TR */
8971da177e4SLinus Torvalds 	if (arg >= (MAX_LEC_ITF - NUM_TR_DEVS))
8981da177e4SLinus Torvalds 		return -EINVAL;
8991da177e4SLinus Torvalds #endif
9001da177e4SLinus Torvalds 	if (!dev_lec[i]) {
9011da177e4SLinus Torvalds 		int is_trdev, size;
9021da177e4SLinus Torvalds 
9031da177e4SLinus Torvalds 		is_trdev = 0;
9041da177e4SLinus Torvalds 		if (i >= (MAX_LEC_ITF - NUM_TR_DEVS))
9051da177e4SLinus Torvalds 			is_trdev = 1;
9061da177e4SLinus Torvalds 
9071da177e4SLinus Torvalds 		size = sizeof(struct lec_priv);
9081da177e4SLinus Torvalds #ifdef CONFIG_TR
9091da177e4SLinus Torvalds 		if (is_trdev)
9101da177e4SLinus Torvalds 			dev_lec[i] = alloc_trdev(size);
9111da177e4SLinus Torvalds 		else
9121da177e4SLinus Torvalds #endif
9131da177e4SLinus Torvalds 			dev_lec[i] = alloc_etherdev(size);
9141da177e4SLinus Torvalds 		if (!dev_lec[i])
9151da177e4SLinus Torvalds 			return -ENOMEM;
9161da177e4SLinus Torvalds 		snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
9171da177e4SLinus Torvalds 		if (register_netdev(dev_lec[i])) {
9181da177e4SLinus Torvalds 			free_netdev(dev_lec[i]);
9191da177e4SLinus Torvalds 			return -EINVAL;
9201da177e4SLinus Torvalds 		}
9211da177e4SLinus Torvalds 
9221da177e4SLinus Torvalds 		priv = dev_lec[i]->priv;
9231da177e4SLinus Torvalds 		priv->is_trdev = is_trdev;
9241da177e4SLinus Torvalds 		lec_init(dev_lec[i]);
9251da177e4SLinus Torvalds 	} else {
9261da177e4SLinus Torvalds 		priv = dev_lec[i]->priv;
9271da177e4SLinus Torvalds 		if (priv->lecd)
9281da177e4SLinus Torvalds 			return -EADDRINUSE;
9291da177e4SLinus Torvalds 	}
9301da177e4SLinus Torvalds 	lec_arp_init(priv);
9311da177e4SLinus Torvalds 	priv->itfnum = i;	/* LANE2 addition */
9321da177e4SLinus Torvalds 	priv->lecd = vcc;
9331da177e4SLinus Torvalds 	vcc->dev = &lecatm_dev;
9341da177e4SLinus Torvalds 	vcc_insert_socket(sk_atm(vcc));
9351da177e4SLinus Torvalds 
9361da177e4SLinus Torvalds 	vcc->proto_data = dev_lec[i];
9371da177e4SLinus Torvalds 	set_bit(ATM_VF_META, &vcc->flags);
9381da177e4SLinus Torvalds 	set_bit(ATM_VF_READY, &vcc->flags);
9391da177e4SLinus Torvalds 
9401da177e4SLinus Torvalds 	/* Set default values to these variables */
9411da177e4SLinus Torvalds 	priv->maximum_unknown_frame_count = 1;
9421da177e4SLinus Torvalds 	priv->max_unknown_frame_time = (1 * HZ);
9431da177e4SLinus Torvalds 	priv->vcc_timeout_period = (1200 * HZ);
9441da177e4SLinus Torvalds 	priv->max_retry_count = 1;
9451da177e4SLinus Torvalds 	priv->aging_time = (300 * HZ);
9461da177e4SLinus Torvalds 	priv->forward_delay_time = (15 * HZ);
9471da177e4SLinus Torvalds 	priv->topology_change = 0;
9481da177e4SLinus Torvalds 	priv->arp_response_time = (1 * HZ);
9491da177e4SLinus Torvalds 	priv->flush_timeout = (4 * HZ);
9501da177e4SLinus Torvalds 	priv->path_switching_delay = (6 * HZ);
9511da177e4SLinus Torvalds 
9521da177e4SLinus Torvalds 	if (dev_lec[i]->flags & IFF_UP) {
9531da177e4SLinus Torvalds 		netif_start_queue(dev_lec[i]);
9541da177e4SLinus Torvalds 	}
9551da177e4SLinus Torvalds 	__module_get(THIS_MODULE);
9561da177e4SLinus Torvalds 	return i;
9571da177e4SLinus Torvalds }
9581da177e4SLinus Torvalds 
9591da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
9601da177e4SLinus Torvalds static char *lec_arp_get_status_string(unsigned char status)
9611da177e4SLinus Torvalds {
9621da177e4SLinus Torvalds 	static char *lec_arp_status_string[] = {
9631da177e4SLinus Torvalds 		"ESI_UNKNOWN       ",
9641da177e4SLinus Torvalds 		"ESI_ARP_PENDING   ",
9651da177e4SLinus Torvalds 		"ESI_VC_PENDING    ",
9661da177e4SLinus Torvalds 		"<Undefined>       ",
9671da177e4SLinus Torvalds 		"ESI_FLUSH_PENDING ",
9681da177e4SLinus Torvalds 		"ESI_FORWARD_DIRECT"
9691da177e4SLinus Torvalds 	};
9701da177e4SLinus Torvalds 
9711da177e4SLinus Torvalds 	if (status > ESI_FORWARD_DIRECT)
9721da177e4SLinus Torvalds 		status = 3;	/* ESI_UNDEFINED */
9731da177e4SLinus Torvalds 	return lec_arp_status_string[status];
9741da177e4SLinus Torvalds }
9751da177e4SLinus Torvalds 
9761da177e4SLinus Torvalds static void lec_info(struct seq_file *seq, struct lec_arp_table *entry)
9771da177e4SLinus Torvalds {
9781da177e4SLinus Torvalds 	int i;
9791da177e4SLinus Torvalds 
9801da177e4SLinus Torvalds 	for (i = 0; i < ETH_ALEN; i++)
9811da177e4SLinus Torvalds 		seq_printf(seq, "%2.2x", entry->mac_addr[i] & 0xff);
9821da177e4SLinus Torvalds 	seq_printf(seq, " ");
9831da177e4SLinus Torvalds 	for (i = 0; i < ATM_ESA_LEN; i++)
9841da177e4SLinus Torvalds 		seq_printf(seq, "%2.2x", entry->atm_addr[i] & 0xff);
9851da177e4SLinus Torvalds 	seq_printf(seq, " %s %4.4x", lec_arp_get_status_string(entry->status),
9861da177e4SLinus Torvalds 		   entry->flags & 0xffff);
9871da177e4SLinus Torvalds 	if (entry->vcc)
9881da177e4SLinus Torvalds 		seq_printf(seq, "%3d %3d ", entry->vcc->vpi, entry->vcc->vci);
9891da177e4SLinus Torvalds 	else
9901da177e4SLinus Torvalds 		seq_printf(seq, "        ");
9911da177e4SLinus Torvalds 	if (entry->recv_vcc) {
9921da177e4SLinus Torvalds 		seq_printf(seq, "     %3d %3d", entry->recv_vcc->vpi,
9931da177e4SLinus Torvalds 			   entry->recv_vcc->vci);
9941da177e4SLinus Torvalds 	}
9951da177e4SLinus Torvalds 	seq_putc(seq, '\n');
9961da177e4SLinus Torvalds }
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds struct lec_state {
9991da177e4SLinus Torvalds 	unsigned long flags;
10001da177e4SLinus Torvalds 	struct lec_priv *locked;
10011da177e4SLinus Torvalds 	struct lec_arp_table *entry;
10021da177e4SLinus Torvalds 	struct net_device *dev;
10031da177e4SLinus Torvalds 	int itf;
10041da177e4SLinus Torvalds 	int arp_table;
10051da177e4SLinus Torvalds 	int misc_table;
10061da177e4SLinus Torvalds };
10071da177e4SLinus Torvalds 
10081da177e4SLinus Torvalds static void *lec_tbl_walk(struct lec_state *state, struct lec_arp_table *tbl,
10091da177e4SLinus Torvalds 			  loff_t *l)
10101da177e4SLinus Torvalds {
10111da177e4SLinus Torvalds 	struct lec_arp_table *e = state->entry;
10121da177e4SLinus Torvalds 
10131da177e4SLinus Torvalds 	if (!e)
10141da177e4SLinus Torvalds 		e = tbl;
10151da177e4SLinus Torvalds 	if (e == (void *)1) {
10161da177e4SLinus Torvalds 		e = tbl;
10171da177e4SLinus Torvalds 		--*l;
10181da177e4SLinus Torvalds 	}
10191da177e4SLinus Torvalds 	for (; e; e = e->next) {
10201da177e4SLinus Torvalds 		if (--*l < 0)
10211da177e4SLinus Torvalds 			break;
10221da177e4SLinus Torvalds 	}
10231da177e4SLinus Torvalds 	state->entry = e;
10241da177e4SLinus Torvalds 	return (*l < 0) ? state : NULL;
10251da177e4SLinus Torvalds }
10261da177e4SLinus Torvalds 
10271da177e4SLinus Torvalds static void *lec_arp_walk(struct lec_state *state, loff_t *l,
10281da177e4SLinus Torvalds 			  struct lec_priv *priv)
10291da177e4SLinus Torvalds {
10301da177e4SLinus Torvalds 	void *v = NULL;
10311da177e4SLinus Torvalds 	int p;
10321da177e4SLinus Torvalds 
10331da177e4SLinus Torvalds 	for (p = state->arp_table; p < LEC_ARP_TABLE_SIZE; p++) {
10341da177e4SLinus Torvalds 		v = lec_tbl_walk(state, priv->lec_arp_tables[p], l);
10351da177e4SLinus Torvalds 		if (v)
10361da177e4SLinus Torvalds 			break;
10371da177e4SLinus Torvalds 	}
10381da177e4SLinus Torvalds 	state->arp_table = p;
10391da177e4SLinus Torvalds 	return v;
10401da177e4SLinus Torvalds }
10411da177e4SLinus Torvalds 
10421da177e4SLinus Torvalds static void *lec_misc_walk(struct lec_state *state, loff_t *l,
10431da177e4SLinus Torvalds 			   struct lec_priv *priv)
10441da177e4SLinus Torvalds {
10451da177e4SLinus Torvalds 	struct lec_arp_table *lec_misc_tables[] = {
10461da177e4SLinus Torvalds 		priv->lec_arp_empty_ones,
10471da177e4SLinus Torvalds 		priv->lec_no_forward,
10481da177e4SLinus Torvalds 		priv->mcast_fwds
10491da177e4SLinus Torvalds 	};
10501da177e4SLinus Torvalds 	void *v = NULL;
10511da177e4SLinus Torvalds 	int q;
10521da177e4SLinus Torvalds 
10531da177e4SLinus Torvalds 	for (q = state->misc_table; q < ARRAY_SIZE(lec_misc_tables); q++) {
10541da177e4SLinus Torvalds 		v = lec_tbl_walk(state, lec_misc_tables[q], l);
10551da177e4SLinus Torvalds 		if (v)
10561da177e4SLinus Torvalds 			break;
10571da177e4SLinus Torvalds 	}
10581da177e4SLinus Torvalds 	state->misc_table = q;
10591da177e4SLinus Torvalds 	return v;
10601da177e4SLinus Torvalds }
10611da177e4SLinus Torvalds 
10621da177e4SLinus Torvalds static void *lec_priv_walk(struct lec_state *state, loff_t *l,
10631da177e4SLinus Torvalds 			   struct lec_priv *priv)
10641da177e4SLinus Torvalds {
10651da177e4SLinus Torvalds 	if (!state->locked) {
10661da177e4SLinus Torvalds 		state->locked = priv;
10671da177e4SLinus Torvalds 		spin_lock_irqsave(&priv->lec_arp_lock, state->flags);
10681da177e4SLinus Torvalds 	}
1069*d44f7746SChas Williams 	if (!lec_arp_walk(state, l, priv) && !lec_misc_walk(state, l, priv)) {
10701da177e4SLinus Torvalds 		spin_unlock_irqrestore(&priv->lec_arp_lock, state->flags);
10711da177e4SLinus Torvalds 		state->locked = NULL;
10721da177e4SLinus Torvalds 		/* Partial state reset for the next time we get called */
10731da177e4SLinus Torvalds 		state->arp_table = state->misc_table = 0;
10741da177e4SLinus Torvalds 	}
10751da177e4SLinus Torvalds 	return state->locked;
10761da177e4SLinus Torvalds }
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds static void *lec_itf_walk(struct lec_state *state, loff_t *l)
10791da177e4SLinus Torvalds {
10801da177e4SLinus Torvalds 	struct net_device *dev;
10811da177e4SLinus Torvalds 	void *v;
10821da177e4SLinus Torvalds 
10831da177e4SLinus Torvalds 	dev = state->dev ? state->dev : dev_lec[state->itf];
10841da177e4SLinus Torvalds 	v = (dev && dev->priv) ? lec_priv_walk(state, l, dev->priv) : NULL;
10851da177e4SLinus Torvalds 	if (!v && dev) {
10861da177e4SLinus Torvalds 		dev_put(dev);
10871da177e4SLinus Torvalds 		/* Partial state reset for the next time we get called */
10881da177e4SLinus Torvalds 		dev = NULL;
10891da177e4SLinus Torvalds 	}
10901da177e4SLinus Torvalds 	state->dev = dev;
10911da177e4SLinus Torvalds 	return v;
10921da177e4SLinus Torvalds }
10931da177e4SLinus Torvalds 
10941da177e4SLinus Torvalds static void *lec_get_idx(struct lec_state *state, loff_t l)
10951da177e4SLinus Torvalds {
10961da177e4SLinus Torvalds 	void *v = NULL;
10971da177e4SLinus Torvalds 
10981da177e4SLinus Torvalds 	for (; state->itf < MAX_LEC_ITF; state->itf++) {
10991da177e4SLinus Torvalds 		v = lec_itf_walk(state, &l);
11001da177e4SLinus Torvalds 		if (v)
11011da177e4SLinus Torvalds 			break;
11021da177e4SLinus Torvalds 	}
11031da177e4SLinus Torvalds 	return v;
11041da177e4SLinus Torvalds }
11051da177e4SLinus Torvalds 
11061da177e4SLinus Torvalds static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
11071da177e4SLinus Torvalds {
11081da177e4SLinus Torvalds 	struct lec_state *state = seq->private;
11091da177e4SLinus Torvalds 
11101da177e4SLinus Torvalds 	state->itf = 0;
11111da177e4SLinus Torvalds 	state->dev = NULL;
11121da177e4SLinus Torvalds 	state->locked = NULL;
11131da177e4SLinus Torvalds 	state->arp_table = 0;
11141da177e4SLinus Torvalds 	state->misc_table = 0;
11151da177e4SLinus Torvalds 	state->entry = (void *)1;
11161da177e4SLinus Torvalds 
11171da177e4SLinus Torvalds 	return *pos ? lec_get_idx(state, *pos) : (void *)1;
11181da177e4SLinus Torvalds }
11191da177e4SLinus Torvalds 
11201da177e4SLinus Torvalds static void lec_seq_stop(struct seq_file *seq, void *v)
11211da177e4SLinus Torvalds {
11221da177e4SLinus Torvalds 	struct lec_state *state = seq->private;
11231da177e4SLinus Torvalds 
11241da177e4SLinus Torvalds 	if (state->dev) {
11251da177e4SLinus Torvalds 		spin_unlock_irqrestore(&state->locked->lec_arp_lock,
11261da177e4SLinus Torvalds 				       state->flags);
11271da177e4SLinus Torvalds 		dev_put(state->dev);
11281da177e4SLinus Torvalds 	}
11291da177e4SLinus Torvalds }
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos)
11321da177e4SLinus Torvalds {
11331da177e4SLinus Torvalds 	struct lec_state *state = seq->private;
11341da177e4SLinus Torvalds 
11351da177e4SLinus Torvalds 	v = lec_get_idx(state, 1);
11361da177e4SLinus Torvalds 	*pos += !!PTR_ERR(v);
11371da177e4SLinus Torvalds 	return v;
11381da177e4SLinus Torvalds }
11391da177e4SLinus Torvalds 
11401da177e4SLinus Torvalds static int lec_seq_show(struct seq_file *seq, void *v)
11411da177e4SLinus Torvalds {
11421da177e4SLinus Torvalds 	static char lec_banner[] = "Itf  MAC          ATM destination"
11431da177e4SLinus Torvalds 	    "                          Status            Flags "
11441da177e4SLinus Torvalds 	    "VPI/VCI Recv VPI/VCI\n";
11451da177e4SLinus Torvalds 
11461da177e4SLinus Torvalds 	if (v == (void *)1)
11471da177e4SLinus Torvalds 		seq_puts(seq, lec_banner);
11481da177e4SLinus Torvalds 	else {
11491da177e4SLinus Torvalds 		struct lec_state *state = seq->private;
11501da177e4SLinus Torvalds 		struct net_device *dev = state->dev;
11511da177e4SLinus Torvalds 
11521da177e4SLinus Torvalds 		seq_printf(seq, "%s ", dev->name);
11531da177e4SLinus Torvalds 		lec_info(seq, state->entry);
11541da177e4SLinus Torvalds 	}
11551da177e4SLinus Torvalds 	return 0;
11561da177e4SLinus Torvalds }
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds static struct seq_operations lec_seq_ops = {
11591da177e4SLinus Torvalds 	.start = lec_seq_start,
11601da177e4SLinus Torvalds 	.next = lec_seq_next,
11611da177e4SLinus Torvalds 	.stop = lec_seq_stop,
11621da177e4SLinus Torvalds 	.show = lec_seq_show,
11631da177e4SLinus Torvalds };
11641da177e4SLinus Torvalds 
11651da177e4SLinus Torvalds static int lec_seq_open(struct inode *inode, struct file *file)
11661da177e4SLinus Torvalds {
11671da177e4SLinus Torvalds 	struct lec_state *state;
11681da177e4SLinus Torvalds 	struct seq_file *seq;
11691da177e4SLinus Torvalds 	int rc = -EAGAIN;
11701da177e4SLinus Torvalds 
11711da177e4SLinus Torvalds 	state = kmalloc(sizeof(*state), GFP_KERNEL);
11721da177e4SLinus Torvalds 	if (!state) {
11731da177e4SLinus Torvalds 		rc = -ENOMEM;
11741da177e4SLinus Torvalds 		goto out;
11751da177e4SLinus Torvalds 	}
11761da177e4SLinus Torvalds 
11771da177e4SLinus Torvalds 	rc = seq_open(file, &lec_seq_ops);
11781da177e4SLinus Torvalds 	if (rc)
11791da177e4SLinus Torvalds 		goto out_kfree;
11801da177e4SLinus Torvalds 	seq = file->private_data;
11811da177e4SLinus Torvalds 	seq->private = state;
11821da177e4SLinus Torvalds out:
11831da177e4SLinus Torvalds 	return rc;
11841da177e4SLinus Torvalds 
11851da177e4SLinus Torvalds out_kfree:
11861da177e4SLinus Torvalds 	kfree(state);
11871da177e4SLinus Torvalds 	goto out;
11881da177e4SLinus Torvalds }
11891da177e4SLinus Torvalds 
11901da177e4SLinus Torvalds static int lec_seq_release(struct inode *inode, struct file *file)
11911da177e4SLinus Torvalds {
11921da177e4SLinus Torvalds 	return seq_release_private(inode, file);
11931da177e4SLinus Torvalds }
11941da177e4SLinus Torvalds 
11951da177e4SLinus Torvalds static struct file_operations lec_seq_fops = {
11961da177e4SLinus Torvalds 	.owner = THIS_MODULE,
11971da177e4SLinus Torvalds 	.open = lec_seq_open,
11981da177e4SLinus Torvalds 	.read = seq_read,
11991da177e4SLinus Torvalds 	.llseek = seq_lseek,
12001da177e4SLinus Torvalds 	.release = lec_seq_release,
12011da177e4SLinus Torvalds };
12021da177e4SLinus Torvalds #endif
12031da177e4SLinus Torvalds 
12041da177e4SLinus Torvalds static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
12051da177e4SLinus Torvalds {
12061da177e4SLinus Torvalds 	struct atm_vcc *vcc = ATM_SD(sock);
12071da177e4SLinus Torvalds 	int err = 0;
12081da177e4SLinus Torvalds 
12091da177e4SLinus Torvalds 	switch (cmd) {
12101da177e4SLinus Torvalds 	case ATMLEC_CTRL:
12111da177e4SLinus Torvalds 	case ATMLEC_MCAST:
12121da177e4SLinus Torvalds 	case ATMLEC_DATA:
12131da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
12141da177e4SLinus Torvalds 			return -EPERM;
12151da177e4SLinus Torvalds 		break;
12161da177e4SLinus Torvalds 	default:
12171da177e4SLinus Torvalds 		return -ENOIOCTLCMD;
12181da177e4SLinus Torvalds 	}
12191da177e4SLinus Torvalds 
12201da177e4SLinus Torvalds 	switch (cmd) {
12211da177e4SLinus Torvalds 	case ATMLEC_CTRL:
12221da177e4SLinus Torvalds 		err = lecd_attach(vcc, (int)arg);
12231da177e4SLinus Torvalds 		if (err >= 0)
12241da177e4SLinus Torvalds 			sock->state = SS_CONNECTED;
12251da177e4SLinus Torvalds 		break;
12261da177e4SLinus Torvalds 	case ATMLEC_MCAST:
12271da177e4SLinus Torvalds 		err = lec_mcast_attach(vcc, (int)arg);
12281da177e4SLinus Torvalds 		break;
12291da177e4SLinus Torvalds 	case ATMLEC_DATA:
12301da177e4SLinus Torvalds 		err = lec_vcc_attach(vcc, (void __user *)arg);
12311da177e4SLinus Torvalds 		break;
12321da177e4SLinus Torvalds 	}
12331da177e4SLinus Torvalds 
12341da177e4SLinus Torvalds 	return err;
12351da177e4SLinus Torvalds }
12361da177e4SLinus Torvalds 
12371da177e4SLinus Torvalds static struct atm_ioctl lane_ioctl_ops = {
12381da177e4SLinus Torvalds 	.owner = THIS_MODULE,
12391da177e4SLinus Torvalds 	.ioctl = lane_ioctl,
12401da177e4SLinus Torvalds };
12411da177e4SLinus Torvalds 
12421da177e4SLinus Torvalds static int __init lane_module_init(void)
12431da177e4SLinus Torvalds {
12441da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
12451da177e4SLinus Torvalds 	struct proc_dir_entry *p;
12461da177e4SLinus Torvalds 
12471da177e4SLinus Torvalds 	p = create_proc_entry("lec", S_IRUGO, atm_proc_root);
12481da177e4SLinus Torvalds 	if (p)
12491da177e4SLinus Torvalds 		p->proc_fops = &lec_seq_fops;
12501da177e4SLinus Torvalds #endif
12511da177e4SLinus Torvalds 
12521da177e4SLinus Torvalds 	register_atm_ioctl(&lane_ioctl_ops);
12531da177e4SLinus Torvalds 	printk("lec.c: " __DATE__ " " __TIME__ " initialized\n");
12541da177e4SLinus Torvalds 	return 0;
12551da177e4SLinus Torvalds }
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds static void __exit lane_module_cleanup(void)
12581da177e4SLinus Torvalds {
12591da177e4SLinus Torvalds 	int i;
12601da177e4SLinus Torvalds 	struct lec_priv *priv;
12611da177e4SLinus Torvalds 
12621da177e4SLinus Torvalds 	remove_proc_entry("lec", atm_proc_root);
12631da177e4SLinus Torvalds 
12641da177e4SLinus Torvalds 	deregister_atm_ioctl(&lane_ioctl_ops);
12651da177e4SLinus Torvalds 
12661da177e4SLinus Torvalds 	for (i = 0; i < MAX_LEC_ITF; i++) {
12671da177e4SLinus Torvalds 		if (dev_lec[i] != NULL) {
12681da177e4SLinus Torvalds 			priv = (struct lec_priv *)dev_lec[i]->priv;
12691da177e4SLinus Torvalds 			unregister_netdev(dev_lec[i]);
12701da177e4SLinus Torvalds 			free_netdev(dev_lec[i]);
12711da177e4SLinus Torvalds 			dev_lec[i] = NULL;
12721da177e4SLinus Torvalds 		}
12731da177e4SLinus Torvalds 	}
12741da177e4SLinus Torvalds 
12751da177e4SLinus Torvalds 	return;
12761da177e4SLinus Torvalds }
12771da177e4SLinus Torvalds 
12781da177e4SLinus Torvalds module_init(lane_module_init);
12791da177e4SLinus Torvalds module_exit(lane_module_cleanup);
12801da177e4SLinus Torvalds 
12811da177e4SLinus Torvalds /*
12821da177e4SLinus Torvalds  * LANE2: 3.1.3, LE_RESOLVE.request
12831da177e4SLinus Torvalds  * Non force allocates memory and fills in *tlvs, fills in *sizeoftlvs.
12841da177e4SLinus Torvalds  * If sizeoftlvs == NULL the default TLVs associated with with this
12851da177e4SLinus Torvalds  * lec will be used.
12861da177e4SLinus Torvalds  * If dst_mac == NULL, targetless LE_ARP will be sent
12871da177e4SLinus Torvalds  */
12881da177e4SLinus Torvalds static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
12891da177e4SLinus Torvalds 			 u8 **tlvs, u32 *sizeoftlvs)
12901da177e4SLinus Torvalds {
12911da177e4SLinus Torvalds 	unsigned long flags;
12921da177e4SLinus Torvalds 	struct lec_priv *priv = (struct lec_priv *)dev->priv;
12931da177e4SLinus Torvalds 	struct lec_arp_table *table;
12941da177e4SLinus Torvalds 	struct sk_buff *skb;
12951da177e4SLinus Torvalds 	int retval;
12961da177e4SLinus Torvalds 
12971da177e4SLinus Torvalds 	if (force == 0) {
12981da177e4SLinus Torvalds 		spin_lock_irqsave(&priv->lec_arp_lock, flags);
12991da177e4SLinus Torvalds 		table = lec_arp_find(priv, dst_mac);
13001da177e4SLinus Torvalds 		spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
13011da177e4SLinus Torvalds 		if (table == NULL)
13021da177e4SLinus Torvalds 			return -1;
13031da177e4SLinus Torvalds 
13041da177e4SLinus Torvalds 		*tlvs = kmalloc(table->sizeoftlvs, GFP_ATOMIC);
13051da177e4SLinus Torvalds 		if (*tlvs == NULL)
13061da177e4SLinus Torvalds 			return -1;
13071da177e4SLinus Torvalds 
13081da177e4SLinus Torvalds 		memcpy(*tlvs, table->tlvs, table->sizeoftlvs);
13091da177e4SLinus Torvalds 		*sizeoftlvs = table->sizeoftlvs;
13101da177e4SLinus Torvalds 
13111da177e4SLinus Torvalds 		return 0;
13121da177e4SLinus Torvalds 	}
13131da177e4SLinus Torvalds 
13141da177e4SLinus Torvalds 	if (sizeoftlvs == NULL)
13151da177e4SLinus Torvalds 		retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, NULL);
13161da177e4SLinus Torvalds 
13171da177e4SLinus Torvalds 	else {
13181da177e4SLinus Torvalds 		skb = alloc_skb(*sizeoftlvs, GFP_ATOMIC);
13191da177e4SLinus Torvalds 		if (skb == NULL)
13201da177e4SLinus Torvalds 			return -1;
13211da177e4SLinus Torvalds 		skb->len = *sizeoftlvs;
13221da177e4SLinus Torvalds 		memcpy(skb->data, *tlvs, *sizeoftlvs);
13231da177e4SLinus Torvalds 		retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, skb);
13241da177e4SLinus Torvalds 	}
13251da177e4SLinus Torvalds 	return retval;
13261da177e4SLinus Torvalds }
13271da177e4SLinus Torvalds 
13281da177e4SLinus Torvalds /*
13291da177e4SLinus Torvalds  * LANE2: 3.1.4, LE_ASSOCIATE.request
13301da177e4SLinus Torvalds  * Associate the *tlvs with the *lan_dst address.
13311da177e4SLinus Torvalds  * Will overwrite any previous association
13321da177e4SLinus Torvalds  * Returns 1 for success, 0 for failure (out of memory)
13331da177e4SLinus Torvalds  *
13341da177e4SLinus Torvalds  */
13351da177e4SLinus Torvalds static int lane2_associate_req(struct net_device *dev, u8 *lan_dst,
13361da177e4SLinus Torvalds 			       u8 *tlvs, u32 sizeoftlvs)
13371da177e4SLinus Torvalds {
13381da177e4SLinus Torvalds 	int retval;
13391da177e4SLinus Torvalds 	struct sk_buff *skb;
13401da177e4SLinus Torvalds 	struct lec_priv *priv = (struct lec_priv *)dev->priv;
13411da177e4SLinus Torvalds 
1342d3f4a687SKris Katterjohn 	if (compare_ether_addr(lan_dst, dev->dev_addr))
13431da177e4SLinus Torvalds 		return (0);	/* not our mac address */
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds 	kfree(priv->tlvs);	/* NULL if there was no previous association */
13461da177e4SLinus Torvalds 
13471da177e4SLinus Torvalds 	priv->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL);
13481da177e4SLinus Torvalds 	if (priv->tlvs == NULL)
13491da177e4SLinus Torvalds 		return (0);
13501da177e4SLinus Torvalds 	priv->sizeoftlvs = sizeoftlvs;
13511da177e4SLinus Torvalds 	memcpy(priv->tlvs, tlvs, sizeoftlvs);
13521da177e4SLinus Torvalds 
13531da177e4SLinus Torvalds 	skb = alloc_skb(sizeoftlvs, GFP_ATOMIC);
13541da177e4SLinus Torvalds 	if (skb == NULL)
13551da177e4SLinus Torvalds 		return 0;
13561da177e4SLinus Torvalds 	skb->len = sizeoftlvs;
13571da177e4SLinus Torvalds 	memcpy(skb->data, tlvs, sizeoftlvs);
13581da177e4SLinus Torvalds 	retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb);
13591da177e4SLinus Torvalds 	if (retval != 0)
13601da177e4SLinus Torvalds 		printk("lec.c: lane2_associate_req() failed\n");
1361*d44f7746SChas Williams 	/*
1362*d44f7746SChas Williams 	 * If the previous association has changed we must
13631da177e4SLinus Torvalds 	 * somehow notify other LANE entities about the change
13641da177e4SLinus Torvalds 	 */
13651da177e4SLinus Torvalds 	return (1);
13661da177e4SLinus Torvalds }
13671da177e4SLinus Torvalds 
13681da177e4SLinus Torvalds /*
13691da177e4SLinus Torvalds  * LANE2: 3.1.5, LE_ASSOCIATE.indication
13701da177e4SLinus Torvalds  *
13711da177e4SLinus Torvalds  */
13721da177e4SLinus Torvalds static void lane2_associate_ind(struct net_device *dev, u8 *mac_addr,
13731da177e4SLinus Torvalds 				u8 *tlvs, u32 sizeoftlvs)
13741da177e4SLinus Torvalds {
13751da177e4SLinus Torvalds #if 0
13761da177e4SLinus Torvalds 	int i = 0;
13771da177e4SLinus Torvalds #endif
13781da177e4SLinus Torvalds 	struct lec_priv *priv = (struct lec_priv *)dev->priv;
1379*d44f7746SChas Williams #if 0				/*
1380*d44f7746SChas Williams 				 * Why have the TLVs in LE_ARP entries
1381*d44f7746SChas Williams 				 * since we do not use them? When you
1382*d44f7746SChas Williams 				 * uncomment this code, make sure the
1383*d44f7746SChas Williams 				 * TLVs get freed when entry is killed
1384*d44f7746SChas Williams 				 */
13851da177e4SLinus Torvalds 	struct lec_arp_table *entry = lec_arp_find(priv, mac_addr);
13861da177e4SLinus Torvalds 
13871da177e4SLinus Torvalds 	if (entry == NULL)
13881da177e4SLinus Torvalds 		return;		/* should not happen */
13891da177e4SLinus Torvalds 
13901da177e4SLinus Torvalds 	kfree(entry->tlvs);
13911da177e4SLinus Torvalds 
13921da177e4SLinus Torvalds 	entry->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL);
13931da177e4SLinus Torvalds 	if (entry->tlvs == NULL)
13941da177e4SLinus Torvalds 		return;
13951da177e4SLinus Torvalds 
13961da177e4SLinus Torvalds 	entry->sizeoftlvs = sizeoftlvs;
13971da177e4SLinus Torvalds 	memcpy(entry->tlvs, tlvs, sizeoftlvs);
13981da177e4SLinus Torvalds #endif
13991da177e4SLinus Torvalds #if 0
14001da177e4SLinus Torvalds 	printk("lec.c: lane2_associate_ind()\n");
14011da177e4SLinus Torvalds 	printk("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs);
14021da177e4SLinus Torvalds 	while (i < sizeoftlvs)
14031da177e4SLinus Torvalds 		printk("%02x ", tlvs[i++]);
14041da177e4SLinus Torvalds 
14051da177e4SLinus Torvalds 	printk("\n");
14061da177e4SLinus Torvalds #endif
14071da177e4SLinus Torvalds 
14081da177e4SLinus Torvalds 	/* tell MPOA about the TLVs we saw */
14091da177e4SLinus Torvalds 	if (priv->lane2_ops && priv->lane2_ops->associate_indicator) {
14101da177e4SLinus Torvalds 		priv->lane2_ops->associate_indicator(dev, mac_addr,
14111da177e4SLinus Torvalds 						     tlvs, sizeoftlvs);
14121da177e4SLinus Torvalds 	}
14131da177e4SLinus Torvalds 	return;
14141da177e4SLinus Torvalds }
14151da177e4SLinus Torvalds 
14161da177e4SLinus Torvalds /*
14171da177e4SLinus Torvalds  * Here starts what used to lec_arpc.c
14181da177e4SLinus Torvalds  *
14191da177e4SLinus Torvalds  * lec_arpc.c was added here when making
14201da177e4SLinus Torvalds  * lane client modular. October 1997
14211da177e4SLinus Torvalds  *
14221da177e4SLinus Torvalds  */
14231da177e4SLinus Torvalds 
14241da177e4SLinus Torvalds #include <linux/types.h>
14251da177e4SLinus Torvalds #include <linux/sched.h>
14261da177e4SLinus Torvalds #include <linux/timer.h>
14271da177e4SLinus Torvalds #include <asm/param.h>
14281da177e4SLinus Torvalds #include <asm/atomic.h>
14291da177e4SLinus Torvalds #include <linux/inetdevice.h>
14301da177e4SLinus Torvalds #include <net/route.h>
14311da177e4SLinus Torvalds 
14321da177e4SLinus Torvalds 
14331da177e4SLinus Torvalds #if 0
14341da177e4SLinus Torvalds #define DPRINTK(format,args...)
14351da177e4SLinus Torvalds /*
14361da177e4SLinus Torvalds #define DPRINTK printk
14371da177e4SLinus Torvalds */
14381da177e4SLinus Torvalds #endif
14391da177e4SLinus Torvalds #define DEBUG_ARP_TABLE 0
14401da177e4SLinus Torvalds 
14411da177e4SLinus Torvalds #define LEC_ARP_REFRESH_INTERVAL (3*HZ)
14421da177e4SLinus Torvalds 
14431da177e4SLinus Torvalds static void lec_arp_check_expire(unsigned long data);
14441da177e4SLinus Torvalds static void lec_arp_expire_arp(unsigned long data);
14451da177e4SLinus Torvalds 
14461da177e4SLinus Torvalds /*
14471da177e4SLinus Torvalds  * Arp table funcs
14481da177e4SLinus Torvalds  */
14491da177e4SLinus Torvalds 
14501da177e4SLinus Torvalds #define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE -1))
14511da177e4SLinus Torvalds 
14521da177e4SLinus Torvalds /*
14531da177e4SLinus Torvalds  * Initialization of arp-cache
14541da177e4SLinus Torvalds  */
14551da177e4SLinus Torvalds static void
14561da177e4SLinus Torvalds lec_arp_init(struct lec_priv *priv)
14571da177e4SLinus Torvalds {
14581da177e4SLinus Torvalds         unsigned short i;
14591da177e4SLinus Torvalds 
14601da177e4SLinus Torvalds         for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
14611da177e4SLinus Torvalds                 priv->lec_arp_tables[i] = NULL;
14621da177e4SLinus Torvalds         }
14631da177e4SLinus Torvalds 	spin_lock_init(&priv->lec_arp_lock);
14641da177e4SLinus Torvalds         init_timer(&priv->lec_arp_timer);
14651da177e4SLinus Torvalds         priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL;
14661da177e4SLinus Torvalds         priv->lec_arp_timer.data = (unsigned long)priv;
14671da177e4SLinus Torvalds         priv->lec_arp_timer.function = lec_arp_check_expire;
14681da177e4SLinus Torvalds         add_timer(&priv->lec_arp_timer);
14691da177e4SLinus Torvalds }
14701da177e4SLinus Torvalds 
14711da177e4SLinus Torvalds static void
14721da177e4SLinus Torvalds lec_arp_clear_vccs(struct lec_arp_table *entry)
14731da177e4SLinus Torvalds {
14741da177e4SLinus Torvalds         if (entry->vcc) {
14751da177e4SLinus Torvalds 		struct atm_vcc *vcc = entry->vcc;
14761da177e4SLinus Torvalds 		struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
14771da177e4SLinus Torvalds 		struct net_device *dev = (struct net_device*) vcc->proto_data;
14781da177e4SLinus Torvalds 
14791da177e4SLinus Torvalds                 vcc->pop = vpriv->old_pop;
14801da177e4SLinus Torvalds 		if (vpriv->xoff)
14811da177e4SLinus Torvalds 			netif_wake_queue(dev);
14821da177e4SLinus Torvalds 		kfree(vpriv);
14831da177e4SLinus Torvalds 		vcc->user_back = NULL;
14841da177e4SLinus Torvalds                 vcc->push = entry->old_push;
14851da177e4SLinus Torvalds 		vcc_release_async(vcc, -EPIPE);
14861da177e4SLinus Torvalds                 vcc = NULL;
14871da177e4SLinus Torvalds         }
14881da177e4SLinus Torvalds         if (entry->recv_vcc) {
14891da177e4SLinus Torvalds                 entry->recv_vcc->push = entry->old_recv_push;
14901da177e4SLinus Torvalds 		vcc_release_async(entry->recv_vcc, -EPIPE);
14911da177e4SLinus Torvalds                 entry->recv_vcc = NULL;
14921da177e4SLinus Torvalds         }
14931da177e4SLinus Torvalds }
14941da177e4SLinus Torvalds 
14951da177e4SLinus Torvalds /*
14961da177e4SLinus Torvalds  * Insert entry to lec_arp_table
14971da177e4SLinus Torvalds  * LANE2: Add to the end of the list to satisfy 8.1.13
14981da177e4SLinus Torvalds  */
14991da177e4SLinus Torvalds static inline void
15001da177e4SLinus Torvalds lec_arp_add(struct lec_priv *priv, struct lec_arp_table *to_add)
15011da177e4SLinus Torvalds {
15021da177e4SLinus Torvalds         unsigned short place;
15031da177e4SLinus Torvalds         struct lec_arp_table *tmp;
15041da177e4SLinus Torvalds 
15051da177e4SLinus Torvalds         place = HASH(to_add->mac_addr[ETH_ALEN-1]);
15061da177e4SLinus Torvalds         tmp = priv->lec_arp_tables[place];
15071da177e4SLinus Torvalds         to_add->next = NULL;
15081da177e4SLinus Torvalds         if (tmp == NULL)
15091da177e4SLinus Torvalds                 priv->lec_arp_tables[place] = to_add;
15101da177e4SLinus Torvalds 
15111da177e4SLinus Torvalds         else {  /* add to the end */
15121da177e4SLinus Torvalds                 while (tmp->next)
15131da177e4SLinus Torvalds                         tmp = tmp->next;
15141da177e4SLinus Torvalds                 tmp->next = to_add;
15151da177e4SLinus Torvalds         }
15161da177e4SLinus Torvalds 
15171da177e4SLinus Torvalds         DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
15181da177e4SLinus Torvalds                 0xff&to_add->mac_addr[0], 0xff&to_add->mac_addr[1],
15191da177e4SLinus Torvalds                 0xff&to_add->mac_addr[2], 0xff&to_add->mac_addr[3],
15201da177e4SLinus Torvalds                 0xff&to_add->mac_addr[4], 0xff&to_add->mac_addr[5]);
15211da177e4SLinus Torvalds }
15221da177e4SLinus Torvalds 
15231da177e4SLinus Torvalds /*
15241da177e4SLinus Torvalds  * Remove entry from lec_arp_table
15251da177e4SLinus Torvalds  */
15261da177e4SLinus Torvalds static int
15271da177e4SLinus Torvalds lec_arp_remove(struct lec_priv *priv,
15281da177e4SLinus Torvalds                struct lec_arp_table *to_remove)
15291da177e4SLinus Torvalds {
15301da177e4SLinus Torvalds         unsigned short place;
15311da177e4SLinus Torvalds         struct lec_arp_table *tmp;
15321da177e4SLinus Torvalds         int remove_vcc=1;
15331da177e4SLinus Torvalds 
15341da177e4SLinus Torvalds         if (!to_remove) {
15351da177e4SLinus Torvalds                 return -1;
15361da177e4SLinus Torvalds         }
15371da177e4SLinus Torvalds         place = HASH(to_remove->mac_addr[ETH_ALEN-1]);
15381da177e4SLinus Torvalds         tmp = priv->lec_arp_tables[place];
15391da177e4SLinus Torvalds         if (tmp == to_remove) {
15401da177e4SLinus Torvalds                 priv->lec_arp_tables[place] = tmp->next;
15411da177e4SLinus Torvalds         } else {
15421da177e4SLinus Torvalds                 while(tmp && tmp->next != to_remove) {
15431da177e4SLinus Torvalds                         tmp = tmp->next;
15441da177e4SLinus Torvalds                 }
15451da177e4SLinus Torvalds                 if (!tmp) {/* Entry was not found */
15461da177e4SLinus Torvalds                         return -1;
15471da177e4SLinus Torvalds                 }
15481da177e4SLinus Torvalds         }
15491da177e4SLinus Torvalds         tmp->next = to_remove->next;
15501da177e4SLinus Torvalds         del_timer(&to_remove->timer);
15511da177e4SLinus Torvalds 
15521da177e4SLinus Torvalds         /* If this is the only MAC connected to this VCC, also tear down
15531da177e4SLinus Torvalds            the VCC */
15541da177e4SLinus Torvalds         if (to_remove->status >= ESI_FLUSH_PENDING) {
15551da177e4SLinus Torvalds                 /*
15561da177e4SLinus Torvalds                  * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT
15571da177e4SLinus Torvalds                  */
15581da177e4SLinus Torvalds                 for(place = 0; place < LEC_ARP_TABLE_SIZE; place++) {
15591da177e4SLinus Torvalds                         for(tmp = priv->lec_arp_tables[place]; tmp != NULL; tmp = tmp->next) {
15601da177e4SLinus Torvalds                                 if (memcmp(tmp->atm_addr, to_remove->atm_addr,
15611da177e4SLinus Torvalds                                            ATM_ESA_LEN)==0) {
15621da177e4SLinus Torvalds                                         remove_vcc=0;
15631da177e4SLinus Torvalds                                         break;
15641da177e4SLinus Torvalds                                 }
15651da177e4SLinus Torvalds                         }
15661da177e4SLinus Torvalds                 }
15671da177e4SLinus Torvalds                 if (remove_vcc)
15681da177e4SLinus Torvalds                         lec_arp_clear_vccs(to_remove);
15691da177e4SLinus Torvalds         }
15701da177e4SLinus Torvalds         skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */
15711da177e4SLinus Torvalds 
15721da177e4SLinus Torvalds         DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
15731da177e4SLinus Torvalds                 0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1],
15741da177e4SLinus Torvalds                 0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3],
15751da177e4SLinus Torvalds                 0xff&to_remove->mac_addr[4], 0xff&to_remove->mac_addr[5]);
15761da177e4SLinus Torvalds         return 0;
15771da177e4SLinus Torvalds }
15781da177e4SLinus Torvalds 
15791da177e4SLinus Torvalds #if DEBUG_ARP_TABLE
15801da177e4SLinus Torvalds static char*
15811da177e4SLinus Torvalds get_status_string(unsigned char st)
15821da177e4SLinus Torvalds {
15831da177e4SLinus Torvalds         switch(st) {
15841da177e4SLinus Torvalds         case ESI_UNKNOWN:
15851da177e4SLinus Torvalds                 return "ESI_UNKNOWN";
15861da177e4SLinus Torvalds         case ESI_ARP_PENDING:
15871da177e4SLinus Torvalds                 return "ESI_ARP_PENDING";
15881da177e4SLinus Torvalds         case ESI_VC_PENDING:
15891da177e4SLinus Torvalds                 return "ESI_VC_PENDING";
15901da177e4SLinus Torvalds         case ESI_FLUSH_PENDING:
15911da177e4SLinus Torvalds                 return "ESI_FLUSH_PENDING";
15921da177e4SLinus Torvalds         case ESI_FORWARD_DIRECT:
15931da177e4SLinus Torvalds                 return "ESI_FORWARD_DIRECT";
15941da177e4SLinus Torvalds         default:
15951da177e4SLinus Torvalds                 return "<UNKNOWN>";
15961da177e4SLinus Torvalds         }
15971da177e4SLinus Torvalds }
15981da177e4SLinus Torvalds #endif
15991da177e4SLinus Torvalds 
16001da177e4SLinus Torvalds static void
16011da177e4SLinus Torvalds dump_arp_table(struct lec_priv *priv)
16021da177e4SLinus Torvalds {
16031da177e4SLinus Torvalds #if DEBUG_ARP_TABLE
16041da177e4SLinus Torvalds         int i,j, offset;
16051da177e4SLinus Torvalds         struct lec_arp_table *rulla;
16061da177e4SLinus Torvalds         char buf[1024];
16071da177e4SLinus Torvalds         struct lec_arp_table **lec_arp_tables =
16081da177e4SLinus Torvalds                 (struct lec_arp_table **)priv->lec_arp_tables;
16091da177e4SLinus Torvalds         struct lec_arp_table *lec_arp_empty_ones =
16101da177e4SLinus Torvalds                 (struct lec_arp_table *)priv->lec_arp_empty_ones;
16111da177e4SLinus Torvalds         struct lec_arp_table *lec_no_forward =
16121da177e4SLinus Torvalds                 (struct lec_arp_table *)priv->lec_no_forward;
16131da177e4SLinus Torvalds         struct lec_arp_table *mcast_fwds = priv->mcast_fwds;
16141da177e4SLinus Torvalds 
16151da177e4SLinus Torvalds 
16161da177e4SLinus Torvalds         printk("Dump %p:\n",priv);
16171da177e4SLinus Torvalds         for (i=0;i<LEC_ARP_TABLE_SIZE;i++) {
16181da177e4SLinus Torvalds                 rulla = lec_arp_tables[i];
16191da177e4SLinus Torvalds                 offset = 0;
16201da177e4SLinus Torvalds                 offset += sprintf(buf,"%d: %p\n",i, rulla);
16211da177e4SLinus Torvalds                 while (rulla) {
16221da177e4SLinus Torvalds                         offset += sprintf(buf+offset,"Mac:");
16231da177e4SLinus Torvalds                         for(j=0;j<ETH_ALEN;j++) {
16241da177e4SLinus Torvalds                                 offset+=sprintf(buf+offset,
16251da177e4SLinus Torvalds                                                 "%2.2x ",
16261da177e4SLinus Torvalds                                                 rulla->mac_addr[j]&0xff);
16271da177e4SLinus Torvalds                         }
16281da177e4SLinus Torvalds                         offset +=sprintf(buf+offset,"Atm:");
16291da177e4SLinus Torvalds                         for(j=0;j<ATM_ESA_LEN;j++) {
16301da177e4SLinus Torvalds                                 offset+=sprintf(buf+offset,
16311da177e4SLinus Torvalds                                                 "%2.2x ",
16321da177e4SLinus Torvalds                                                 rulla->atm_addr[j]&0xff);
16331da177e4SLinus Torvalds                         }
16341da177e4SLinus Torvalds                         offset+=sprintf(buf+offset,
16351da177e4SLinus Torvalds                                         "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
16361da177e4SLinus Torvalds                                         rulla->vcc?rulla->vcc->vpi:0,
16371da177e4SLinus Torvalds                                         rulla->vcc?rulla->vcc->vci:0,
16381da177e4SLinus Torvalds                                         rulla->recv_vcc?rulla->recv_vcc->vpi:0,
16391da177e4SLinus Torvalds                                         rulla->recv_vcc?rulla->recv_vcc->vci:0,
16401da177e4SLinus Torvalds                                         rulla->last_used,
16411da177e4SLinus Torvalds                                         rulla->timestamp, rulla->no_tries);
16421da177e4SLinus Torvalds                         offset+=sprintf(buf+offset,
16431da177e4SLinus Torvalds                                         "Flags:%x, Packets_flooded:%x, Status: %s ",
16441da177e4SLinus Torvalds                                         rulla->flags, rulla->packets_flooded,
16451da177e4SLinus Torvalds                                         get_status_string(rulla->status));
16461da177e4SLinus Torvalds                         offset+=sprintf(buf+offset,"->%p\n",rulla->next);
16471da177e4SLinus Torvalds                         rulla = rulla->next;
16481da177e4SLinus Torvalds                 }
16491da177e4SLinus Torvalds                 printk("%s",buf);
16501da177e4SLinus Torvalds         }
16511da177e4SLinus Torvalds         rulla = lec_no_forward;
16521da177e4SLinus Torvalds         if (rulla)
16531da177e4SLinus Torvalds                 printk("No forward\n");
16541da177e4SLinus Torvalds         while(rulla) {
16551da177e4SLinus Torvalds                 offset=0;
16561da177e4SLinus Torvalds                 offset += sprintf(buf+offset,"Mac:");
16571da177e4SLinus Torvalds                 for(j=0;j<ETH_ALEN;j++) {
16581da177e4SLinus Torvalds                         offset+=sprintf(buf+offset,"%2.2x ",
16591da177e4SLinus Torvalds                                         rulla->mac_addr[j]&0xff);
16601da177e4SLinus Torvalds                 }
16611da177e4SLinus Torvalds                 offset +=sprintf(buf+offset,"Atm:");
16621da177e4SLinus Torvalds                 for(j=0;j<ATM_ESA_LEN;j++) {
16631da177e4SLinus Torvalds                         offset+=sprintf(buf+offset,"%2.2x ",
16641da177e4SLinus Torvalds                                         rulla->atm_addr[j]&0xff);
16651da177e4SLinus Torvalds                 }
16661da177e4SLinus Torvalds                 offset+=sprintf(buf+offset,
16671da177e4SLinus Torvalds                                 "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
16681da177e4SLinus Torvalds                                 rulla->vcc?rulla->vcc->vpi:0,
16691da177e4SLinus Torvalds                                 rulla->vcc?rulla->vcc->vci:0,
16701da177e4SLinus Torvalds                                 rulla->recv_vcc?rulla->recv_vcc->vpi:0,
16711da177e4SLinus Torvalds                                 rulla->recv_vcc?rulla->recv_vcc->vci:0,
16721da177e4SLinus Torvalds                                 rulla->last_used,
16731da177e4SLinus Torvalds                                 rulla->timestamp, rulla->no_tries);
16741da177e4SLinus Torvalds                 offset+=sprintf(buf+offset,
16751da177e4SLinus Torvalds                                 "Flags:%x, Packets_flooded:%x, Status: %s ",
16761da177e4SLinus Torvalds                                 rulla->flags, rulla->packets_flooded,
16771da177e4SLinus Torvalds                                 get_status_string(rulla->status));
16781da177e4SLinus Torvalds                 offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next);
16791da177e4SLinus Torvalds                 rulla = rulla->next;
16801da177e4SLinus Torvalds                 printk("%s",buf);
16811da177e4SLinus Torvalds         }
16821da177e4SLinus Torvalds         rulla = lec_arp_empty_ones;
16831da177e4SLinus Torvalds         if (rulla)
16841da177e4SLinus Torvalds                 printk("Empty ones\n");
16851da177e4SLinus Torvalds         while(rulla) {
16861da177e4SLinus Torvalds                 offset=0;
16871da177e4SLinus Torvalds                 offset += sprintf(buf+offset,"Mac:");
16881da177e4SLinus Torvalds                 for(j=0;j<ETH_ALEN;j++) {
16891da177e4SLinus Torvalds                         offset+=sprintf(buf+offset,"%2.2x ",
16901da177e4SLinus Torvalds                                         rulla->mac_addr[j]&0xff);
16911da177e4SLinus Torvalds                 }
16921da177e4SLinus Torvalds                 offset +=sprintf(buf+offset,"Atm:");
16931da177e4SLinus Torvalds                 for(j=0;j<ATM_ESA_LEN;j++) {
16941da177e4SLinus Torvalds                         offset+=sprintf(buf+offset,"%2.2x ",
16951da177e4SLinus Torvalds                                         rulla->atm_addr[j]&0xff);
16961da177e4SLinus Torvalds                 }
16971da177e4SLinus Torvalds                 offset+=sprintf(buf+offset,
16981da177e4SLinus Torvalds                                 "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
16991da177e4SLinus Torvalds                                 rulla->vcc?rulla->vcc->vpi:0,
17001da177e4SLinus Torvalds                                 rulla->vcc?rulla->vcc->vci:0,
17011da177e4SLinus Torvalds                                 rulla->recv_vcc?rulla->recv_vcc->vpi:0,
17021da177e4SLinus Torvalds                                 rulla->recv_vcc?rulla->recv_vcc->vci:0,
17031da177e4SLinus Torvalds                                 rulla->last_used,
17041da177e4SLinus Torvalds                                 rulla->timestamp, rulla->no_tries);
17051da177e4SLinus Torvalds                 offset+=sprintf(buf+offset,
17061da177e4SLinus Torvalds                                 "Flags:%x, Packets_flooded:%x, Status: %s ",
17071da177e4SLinus Torvalds                                 rulla->flags, rulla->packets_flooded,
17081da177e4SLinus Torvalds                                 get_status_string(rulla->status));
17091da177e4SLinus Torvalds                 offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next);
17101da177e4SLinus Torvalds                 rulla = rulla->next;
17111da177e4SLinus Torvalds                 printk("%s",buf);
17121da177e4SLinus Torvalds         }
17131da177e4SLinus Torvalds 
17141da177e4SLinus Torvalds         rulla = mcast_fwds;
17151da177e4SLinus Torvalds         if (rulla)
17161da177e4SLinus Torvalds                 printk("Multicast Forward VCCs\n");
17171da177e4SLinus Torvalds         while(rulla) {
17181da177e4SLinus Torvalds                 offset=0;
17191da177e4SLinus Torvalds                 offset += sprintf(buf+offset,"Mac:");
17201da177e4SLinus Torvalds                 for(j=0;j<ETH_ALEN;j++) {
17211da177e4SLinus Torvalds                         offset+=sprintf(buf+offset,"%2.2x ",
17221da177e4SLinus Torvalds                                         rulla->mac_addr[j]&0xff);
17231da177e4SLinus Torvalds                 }
17241da177e4SLinus Torvalds                 offset +=sprintf(buf+offset,"Atm:");
17251da177e4SLinus Torvalds                 for(j=0;j<ATM_ESA_LEN;j++) {
17261da177e4SLinus Torvalds                         offset+=sprintf(buf+offset,"%2.2x ",
17271da177e4SLinus Torvalds                                         rulla->atm_addr[j]&0xff);
17281da177e4SLinus Torvalds                 }
17291da177e4SLinus Torvalds                 offset+=sprintf(buf+offset,
17301da177e4SLinus Torvalds                                 "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
17311da177e4SLinus Torvalds                                 rulla->vcc?rulla->vcc->vpi:0,
17321da177e4SLinus Torvalds                                 rulla->vcc?rulla->vcc->vci:0,
17331da177e4SLinus Torvalds                                 rulla->recv_vcc?rulla->recv_vcc->vpi:0,
17341da177e4SLinus Torvalds                                 rulla->recv_vcc?rulla->recv_vcc->vci:0,
17351da177e4SLinus Torvalds                                 rulla->last_used,
17361da177e4SLinus Torvalds                                 rulla->timestamp, rulla->no_tries);
17371da177e4SLinus Torvalds                 offset+=sprintf(buf+offset,
17381da177e4SLinus Torvalds                                 "Flags:%x, Packets_flooded:%x, Status: %s ",
17391da177e4SLinus Torvalds                                 rulla->flags, rulla->packets_flooded,
17401da177e4SLinus Torvalds                                 get_status_string(rulla->status));
17411da177e4SLinus Torvalds                 offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next);
17421da177e4SLinus Torvalds                 rulla = rulla->next;
17431da177e4SLinus Torvalds                 printk("%s",buf);
17441da177e4SLinus Torvalds         }
17451da177e4SLinus Torvalds 
17461da177e4SLinus Torvalds #endif
17471da177e4SLinus Torvalds }
17481da177e4SLinus Torvalds 
17491da177e4SLinus Torvalds /*
17501da177e4SLinus Torvalds  * Destruction of arp-cache
17511da177e4SLinus Torvalds  */
17521da177e4SLinus Torvalds static void
17531da177e4SLinus Torvalds lec_arp_destroy(struct lec_priv *priv)
17541da177e4SLinus Torvalds {
17551da177e4SLinus Torvalds 	unsigned long flags;
17561da177e4SLinus Torvalds         struct lec_arp_table *entry, *next;
17571da177e4SLinus Torvalds         int i;
17581da177e4SLinus Torvalds 
17591da177e4SLinus Torvalds         del_timer_sync(&priv->lec_arp_timer);
17601da177e4SLinus Torvalds 
17611da177e4SLinus Torvalds         /*
17621da177e4SLinus Torvalds          * Remove all entries
17631da177e4SLinus Torvalds          */
17641da177e4SLinus Torvalds 
17651da177e4SLinus Torvalds 	spin_lock_irqsave(&priv->lec_arp_lock, flags);
17661da177e4SLinus Torvalds         for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
17671da177e4SLinus Torvalds                 for(entry = priv->lec_arp_tables[i]; entry != NULL; entry=next) {
17681da177e4SLinus Torvalds                         next = entry->next;
17691da177e4SLinus Torvalds                         lec_arp_remove(priv, entry);
17701da177e4SLinus Torvalds                         kfree(entry);
17711da177e4SLinus Torvalds                 }
17721da177e4SLinus Torvalds         }
17731da177e4SLinus Torvalds         entry = priv->lec_arp_empty_ones;
17741da177e4SLinus Torvalds         while(entry) {
17751da177e4SLinus Torvalds                 next = entry->next;
17761da177e4SLinus Torvalds                 del_timer_sync(&entry->timer);
17771da177e4SLinus Torvalds                 lec_arp_clear_vccs(entry);
17781da177e4SLinus Torvalds                 kfree(entry);
17791da177e4SLinus Torvalds                 entry = next;
17801da177e4SLinus Torvalds         }
17811da177e4SLinus Torvalds         priv->lec_arp_empty_ones = NULL;
17821da177e4SLinus Torvalds         entry = priv->lec_no_forward;
17831da177e4SLinus Torvalds         while(entry) {
17841da177e4SLinus Torvalds                 next = entry->next;
17851da177e4SLinus Torvalds                 del_timer_sync(&entry->timer);
17861da177e4SLinus Torvalds                 lec_arp_clear_vccs(entry);
17871da177e4SLinus Torvalds                 kfree(entry);
17881da177e4SLinus Torvalds                 entry = next;
17891da177e4SLinus Torvalds         }
17901da177e4SLinus Torvalds         priv->lec_no_forward = NULL;
17911da177e4SLinus Torvalds         entry = priv->mcast_fwds;
17921da177e4SLinus Torvalds         while(entry) {
17931da177e4SLinus Torvalds                 next = entry->next;
17941da177e4SLinus Torvalds                 /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
17951da177e4SLinus Torvalds                 lec_arp_clear_vccs(entry);
17961da177e4SLinus Torvalds                 kfree(entry);
17971da177e4SLinus Torvalds                 entry = next;
17981da177e4SLinus Torvalds         }
17991da177e4SLinus Torvalds         priv->mcast_fwds = NULL;
18001da177e4SLinus Torvalds         priv->mcast_vcc = NULL;
18011da177e4SLinus Torvalds         memset(priv->lec_arp_tables, 0,
18021da177e4SLinus Torvalds                sizeof(struct lec_arp_table *) * LEC_ARP_TABLE_SIZE);
18031da177e4SLinus Torvalds 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
18041da177e4SLinus Torvalds }
18051da177e4SLinus Torvalds 
18061da177e4SLinus Torvalds 
18071da177e4SLinus Torvalds /*
18081da177e4SLinus Torvalds  * Find entry by mac_address
18091da177e4SLinus Torvalds  */
18101da177e4SLinus Torvalds static struct lec_arp_table*
18111da177e4SLinus Torvalds lec_arp_find(struct lec_priv *priv,
18121da177e4SLinus Torvalds              unsigned char *mac_addr)
18131da177e4SLinus Torvalds {
18141da177e4SLinus Torvalds         unsigned short place;
18151da177e4SLinus Torvalds         struct lec_arp_table *to_return;
18161da177e4SLinus Torvalds 
18171da177e4SLinus Torvalds         DPRINTK("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
18181da177e4SLinus Torvalds                 mac_addr[0]&0xff, mac_addr[1]&0xff, mac_addr[2]&0xff,
18191da177e4SLinus Torvalds                 mac_addr[3]&0xff, mac_addr[4]&0xff, mac_addr[5]&0xff);
18201da177e4SLinus Torvalds         place = HASH(mac_addr[ETH_ALEN-1]);
18211da177e4SLinus Torvalds 
18221da177e4SLinus Torvalds         to_return = priv->lec_arp_tables[place];
18231da177e4SLinus Torvalds         while(to_return) {
1824d3f4a687SKris Katterjohn                 if (!compare_ether_addr(mac_addr, to_return->mac_addr)) {
18251da177e4SLinus Torvalds                         return to_return;
18261da177e4SLinus Torvalds                 }
18271da177e4SLinus Torvalds                 to_return = to_return->next;
18281da177e4SLinus Torvalds         }
18291da177e4SLinus Torvalds         return NULL;
18301da177e4SLinus Torvalds }
18311da177e4SLinus Torvalds 
18321da177e4SLinus Torvalds static struct lec_arp_table*
18331da177e4SLinus Torvalds make_entry(struct lec_priv *priv, unsigned char *mac_addr)
18341da177e4SLinus Torvalds {
18351da177e4SLinus Torvalds         struct lec_arp_table *to_return;
18361da177e4SLinus Torvalds 
18370da974f4SPanagiotis Issaris         to_return = kzalloc(sizeof(struct lec_arp_table), GFP_ATOMIC);
18381da177e4SLinus Torvalds         if (!to_return) {
18391da177e4SLinus Torvalds                 printk("LEC: Arp entry kmalloc failed\n");
18401da177e4SLinus Torvalds                 return NULL;
18411da177e4SLinus Torvalds         }
18421da177e4SLinus Torvalds         memcpy(to_return->mac_addr, mac_addr, ETH_ALEN);
18431da177e4SLinus Torvalds         init_timer(&to_return->timer);
18441da177e4SLinus Torvalds         to_return->timer.function = lec_arp_expire_arp;
18451da177e4SLinus Torvalds         to_return->timer.data = (unsigned long) to_return;
18461da177e4SLinus Torvalds         to_return->last_used = jiffies;
18471da177e4SLinus Torvalds         to_return->priv = priv;
18481da177e4SLinus Torvalds         skb_queue_head_init(&to_return->tx_wait);
18491da177e4SLinus Torvalds         return to_return;
18501da177e4SLinus Torvalds }
18511da177e4SLinus Torvalds 
18521da177e4SLinus Torvalds /*
18531da177e4SLinus Torvalds  *
18541da177e4SLinus Torvalds  * Arp sent timer expired
18551da177e4SLinus Torvalds  *
18561da177e4SLinus Torvalds  */
18571da177e4SLinus Torvalds static void
18581da177e4SLinus Torvalds lec_arp_expire_arp(unsigned long data)
18591da177e4SLinus Torvalds {
18601da177e4SLinus Torvalds         struct lec_arp_table *entry;
18611da177e4SLinus Torvalds 
18621da177e4SLinus Torvalds         entry = (struct lec_arp_table *)data;
18631da177e4SLinus Torvalds 
18641da177e4SLinus Torvalds         DPRINTK("lec_arp_expire_arp\n");
18651da177e4SLinus Torvalds         if (entry->status == ESI_ARP_PENDING) {
18661da177e4SLinus Torvalds                 if (entry->no_tries <= entry->priv->max_retry_count) {
18671da177e4SLinus Torvalds                         if (entry->is_rdesc)
18681da177e4SLinus Torvalds                                 send_to_lecd(entry->priv, l_rdesc_arp_xmt, entry->mac_addr, NULL, NULL);
18691da177e4SLinus Torvalds                         else
18701da177e4SLinus Torvalds                                 send_to_lecd(entry->priv, l_arp_xmt, entry->mac_addr, NULL, NULL);
18711da177e4SLinus Torvalds                         entry->no_tries++;
18721da177e4SLinus Torvalds                 }
18731da177e4SLinus Torvalds                 mod_timer(&entry->timer, jiffies + (1*HZ));
18741da177e4SLinus Torvalds         }
18751da177e4SLinus Torvalds }
18761da177e4SLinus Torvalds 
18771da177e4SLinus Torvalds /*
18781da177e4SLinus Torvalds  *
18791da177e4SLinus Torvalds  * Unknown/unused vcc expire, remove associated entry
18801da177e4SLinus Torvalds  *
18811da177e4SLinus Torvalds  */
18821da177e4SLinus Torvalds static void
18831da177e4SLinus Torvalds lec_arp_expire_vcc(unsigned long data)
18841da177e4SLinus Torvalds {
18851da177e4SLinus Torvalds 	unsigned long flags;
18861da177e4SLinus Torvalds         struct lec_arp_table *to_remove = (struct lec_arp_table*)data;
18871da177e4SLinus Torvalds         struct lec_priv *priv = (struct lec_priv *)to_remove->priv;
18881da177e4SLinus Torvalds         struct lec_arp_table *entry = NULL;
18891da177e4SLinus Torvalds 
18901da177e4SLinus Torvalds         del_timer(&to_remove->timer);
18911da177e4SLinus Torvalds 
18921da177e4SLinus Torvalds         DPRINTK("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n",
18931da177e4SLinus Torvalds                 to_remove, priv,
18941da177e4SLinus Torvalds                 to_remove->vcc?to_remove->recv_vcc->vpi:0,
18951da177e4SLinus Torvalds                 to_remove->vcc?to_remove->recv_vcc->vci:0);
18961da177e4SLinus Torvalds         DPRINTK("eo:%p nf:%p\n",priv->lec_arp_empty_ones,priv->lec_no_forward);
18971da177e4SLinus Torvalds 
18981da177e4SLinus Torvalds 	spin_lock_irqsave(&priv->lec_arp_lock, flags);
18991da177e4SLinus Torvalds         if (to_remove == priv->lec_arp_empty_ones)
19001da177e4SLinus Torvalds                 priv->lec_arp_empty_ones = to_remove->next;
19011da177e4SLinus Torvalds         else {
19021da177e4SLinus Torvalds                 entry = priv->lec_arp_empty_ones;
19031da177e4SLinus Torvalds                 while (entry && entry->next != to_remove)
19041da177e4SLinus Torvalds                         entry = entry->next;
19051da177e4SLinus Torvalds                 if (entry)
19061da177e4SLinus Torvalds                         entry->next = to_remove->next;
19071da177e4SLinus Torvalds         }
19081da177e4SLinus Torvalds         if (!entry) {
19091da177e4SLinus Torvalds                 if (to_remove == priv->lec_no_forward) {
19101da177e4SLinus Torvalds                         priv->lec_no_forward = to_remove->next;
19111da177e4SLinus Torvalds                 } else {
19121da177e4SLinus Torvalds                         entry = priv->lec_no_forward;
19131da177e4SLinus Torvalds                         while (entry && entry->next != to_remove)
19141da177e4SLinus Torvalds                                 entry = entry->next;
19151da177e4SLinus Torvalds                         if (entry)
19161da177e4SLinus Torvalds                                 entry->next = to_remove->next;
19171da177e4SLinus Torvalds                 }
19181da177e4SLinus Torvalds 	}
19191da177e4SLinus Torvalds 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
19201da177e4SLinus Torvalds 
19211da177e4SLinus Torvalds         lec_arp_clear_vccs(to_remove);
19221da177e4SLinus Torvalds         kfree(to_remove);
19231da177e4SLinus Torvalds }
19241da177e4SLinus Torvalds 
19251da177e4SLinus Torvalds /*
19261da177e4SLinus Torvalds  * Expire entries.
19271da177e4SLinus Torvalds  * 1. Re-set timer
19281da177e4SLinus Torvalds  * 2. For each entry, delete entries that have aged past the age limit.
19291da177e4SLinus Torvalds  * 3. For each entry, depending on the status of the entry, perform
19301da177e4SLinus Torvalds  *    the following maintenance.
19311da177e4SLinus Torvalds  *    a. If status is ESI_VC_PENDING or ESI_ARP_PENDING then if the
19321da177e4SLinus Torvalds  *       tick_count is above the max_unknown_frame_time, clear
19331da177e4SLinus Torvalds  *       the tick_count to zero and clear the packets_flooded counter
19341da177e4SLinus Torvalds  *       to zero. This supports the packet rate limit per address
19351da177e4SLinus Torvalds  *       while flooding unknowns.
19361da177e4SLinus Torvalds  *    b. If the status is ESI_FLUSH_PENDING and the tick_count is greater
19371da177e4SLinus Torvalds  *       than or equal to the path_switching_delay, change the status
19381da177e4SLinus Torvalds  *       to ESI_FORWARD_DIRECT. This causes the flush period to end
19391da177e4SLinus Torvalds  *       regardless of the progress of the flush protocol.
19401da177e4SLinus Torvalds  */
19411da177e4SLinus Torvalds static void
19421da177e4SLinus Torvalds lec_arp_check_expire(unsigned long data)
19431da177e4SLinus Torvalds {
19441da177e4SLinus Torvalds 	unsigned long flags;
19451da177e4SLinus Torvalds         struct lec_priv *priv = (struct lec_priv *)data;
19461da177e4SLinus Torvalds         struct lec_arp_table *entry, *next;
19471da177e4SLinus Torvalds         unsigned long now;
19481da177e4SLinus Torvalds         unsigned long time_to_check;
19491da177e4SLinus Torvalds         int i;
19501da177e4SLinus Torvalds 
19511da177e4SLinus Torvalds         DPRINTK("lec_arp_check_expire %p\n",priv);
19521da177e4SLinus Torvalds         DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones,
19531da177e4SLinus Torvalds                 priv->lec_no_forward);
19541da177e4SLinus Torvalds 	now = jiffies;
19551da177e4SLinus Torvalds 	spin_lock_irqsave(&priv->lec_arp_lock, flags);
19561da177e4SLinus Torvalds 	for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
19571da177e4SLinus Torvalds 		for(entry = priv->lec_arp_tables[i]; entry != NULL; ) {
19581da177e4SLinus Torvalds 			if ((entry->flags) & LEC_REMOTE_FLAG &&
19591da177e4SLinus Torvalds 			    priv->topology_change)
19601da177e4SLinus Torvalds 				time_to_check = priv->forward_delay_time;
19611da177e4SLinus Torvalds 			else
19621da177e4SLinus Torvalds 				time_to_check = priv->aging_time;
19631da177e4SLinus Torvalds 
19641da177e4SLinus Torvalds 			DPRINTK("About to expire: %lx - %lx > %lx\n",
19651da177e4SLinus Torvalds 				now,entry->last_used, time_to_check);
19661da177e4SLinus Torvalds 			if( time_after(now, entry->last_used+
19671da177e4SLinus Torvalds 			   time_to_check) &&
19681da177e4SLinus Torvalds 			    !(entry->flags & LEC_PERMANENT_FLAG) &&
19691da177e4SLinus Torvalds 			    !(entry->mac_addr[0] & 0x01) ) { /* LANE2: 7.1.20 */
19701da177e4SLinus Torvalds 				/* Remove entry */
19711da177e4SLinus Torvalds 				DPRINTK("LEC:Entry timed out\n");
19721da177e4SLinus Torvalds 				next = entry->next;
19731da177e4SLinus Torvalds 				lec_arp_remove(priv, entry);
19741da177e4SLinus Torvalds 				kfree(entry);
19751da177e4SLinus Torvalds 				entry = next;
19761da177e4SLinus Torvalds 			} else {
19771da177e4SLinus Torvalds 				/* Something else */
19781da177e4SLinus Torvalds 				if ((entry->status == ESI_VC_PENDING ||
19791da177e4SLinus Torvalds 				     entry->status == ESI_ARP_PENDING)
19801da177e4SLinus Torvalds 				    && time_after_eq(now,
19811da177e4SLinus Torvalds 				    entry->timestamp +
19821da177e4SLinus Torvalds 				    priv->max_unknown_frame_time)) {
19831da177e4SLinus Torvalds 					entry->timestamp = jiffies;
19841da177e4SLinus Torvalds 					entry->packets_flooded = 0;
19851da177e4SLinus Torvalds 					if (entry->status == ESI_VC_PENDING)
19861da177e4SLinus Torvalds 						send_to_lecd(priv, l_svc_setup, entry->mac_addr, entry->atm_addr, NULL);
19871da177e4SLinus Torvalds 				}
19881da177e4SLinus Torvalds 				if (entry->status == ESI_FLUSH_PENDING
19891da177e4SLinus Torvalds 				   &&
19901da177e4SLinus Torvalds 				   time_after_eq(now, entry->timestamp+
19911da177e4SLinus Torvalds 				   priv->path_switching_delay)) {
19921da177e4SLinus Torvalds 					struct sk_buff *skb;
19931da177e4SLinus Torvalds 
19941da177e4SLinus Torvalds 					while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
19951da177e4SLinus Torvalds 						lec_send(entry->vcc, skb, entry->priv);
19961da177e4SLinus Torvalds 					entry->last_used = jiffies;
19971da177e4SLinus Torvalds 					entry->status =
19981da177e4SLinus Torvalds 						ESI_FORWARD_DIRECT;
19991da177e4SLinus Torvalds 				}
20001da177e4SLinus Torvalds 				entry = entry->next;
20011da177e4SLinus Torvalds 			}
20021da177e4SLinus Torvalds 		}
20031da177e4SLinus Torvalds 	}
20041da177e4SLinus Torvalds 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
20051da177e4SLinus Torvalds 
20061da177e4SLinus Torvalds         mod_timer(&priv->lec_arp_timer, jiffies + LEC_ARP_REFRESH_INTERVAL);
20071da177e4SLinus Torvalds }
20081da177e4SLinus Torvalds /*
20091da177e4SLinus Torvalds  * Try to find vcc where mac_address is attached.
20101da177e4SLinus Torvalds  *
20111da177e4SLinus Torvalds  */
20121da177e4SLinus Torvalds static struct atm_vcc*
20131da177e4SLinus Torvalds lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find,
20141da177e4SLinus Torvalds 		int is_rdesc, struct lec_arp_table **ret_entry)
20151da177e4SLinus Torvalds {
20161da177e4SLinus Torvalds 	unsigned long flags;
20171da177e4SLinus Torvalds         struct lec_arp_table *entry;
20181da177e4SLinus Torvalds 	struct atm_vcc *found;
20191da177e4SLinus Torvalds 
20201da177e4SLinus Torvalds         if (mac_to_find[0] & 0x01) {
20211da177e4SLinus Torvalds                 switch (priv->lane_version) {
20221da177e4SLinus Torvalds                 case 1:
20231da177e4SLinus Torvalds                         return priv->mcast_vcc;
20241da177e4SLinus Torvalds                         break;
20251da177e4SLinus Torvalds                 case 2:  /* LANE2 wants arp for multicast addresses */
2026d3f4a687SKris Katterjohn                         if (!compare_ether_addr(mac_to_find, bus_mac))
20271da177e4SLinus Torvalds                                 return priv->mcast_vcc;
20281da177e4SLinus Torvalds                         break;
20291da177e4SLinus Torvalds                 default:
20301da177e4SLinus Torvalds                         break;
20311da177e4SLinus Torvalds                 }
20321da177e4SLinus Torvalds         }
20331da177e4SLinus Torvalds 
20341da177e4SLinus Torvalds 	spin_lock_irqsave(&priv->lec_arp_lock, flags);
20351da177e4SLinus Torvalds         entry = lec_arp_find(priv, mac_to_find);
20361da177e4SLinus Torvalds 
20371da177e4SLinus Torvalds         if (entry) {
20381da177e4SLinus Torvalds                 if (entry->status == ESI_FORWARD_DIRECT) {
20391da177e4SLinus Torvalds                         /* Connection Ok */
20401da177e4SLinus Torvalds                         entry->last_used = jiffies;
20411da177e4SLinus Torvalds                         *ret_entry = entry;
20421da177e4SLinus Torvalds                         found = entry->vcc;
20431da177e4SLinus Torvalds 			goto out;
20441da177e4SLinus Torvalds                 }
204575b895c1SScott Talbert 		/* If the LE_ARP cache entry is still pending, reset count to 0
204675b895c1SScott Talbert 		 * so another LE_ARP request can be made for this frame.
204775b895c1SScott Talbert 		 */
204875b895c1SScott Talbert 		if (entry->status == ESI_ARP_PENDING) {
204975b895c1SScott Talbert 			entry->no_tries = 0;
205075b895c1SScott Talbert 		}
20511da177e4SLinus Torvalds                 /* Data direct VC not yet set up, check to see if the unknown
20521da177e4SLinus Torvalds                    frame count is greater than the limit. If the limit has
20531da177e4SLinus Torvalds                    not been reached, allow the caller to send packet to
20541da177e4SLinus Torvalds                    BUS. */
20551da177e4SLinus Torvalds                 if (entry->status != ESI_FLUSH_PENDING &&
20561da177e4SLinus Torvalds                     entry->packets_flooded<priv->maximum_unknown_frame_count) {
20571da177e4SLinus Torvalds                         entry->packets_flooded++;
20581da177e4SLinus Torvalds                         DPRINTK("LEC_ARP: Flooding..\n");
20591da177e4SLinus Torvalds                         found = priv->mcast_vcc;
20601da177e4SLinus Torvalds 			goto out;
20611da177e4SLinus Torvalds                 }
20621da177e4SLinus Torvalds 		/* We got here because entry->status == ESI_FLUSH_PENDING
20631da177e4SLinus Torvalds 		 * or BUS flood limit was reached for an entry which is
20641da177e4SLinus Torvalds 		 * in ESI_ARP_PENDING or ESI_VC_PENDING state.
20651da177e4SLinus Torvalds 		 */
20661da177e4SLinus Torvalds                 *ret_entry = entry;
20671da177e4SLinus Torvalds                 DPRINTK("lec: entry->status %d entry->vcc %p\n", entry->status, entry->vcc);
20681da177e4SLinus Torvalds                 found = NULL;
20691da177e4SLinus Torvalds         } else {
20701da177e4SLinus Torvalds                 /* No matching entry was found */
20711da177e4SLinus Torvalds                 entry = make_entry(priv, mac_to_find);
20721da177e4SLinus Torvalds                 DPRINTK("LEC_ARP: Making entry\n");
20731da177e4SLinus Torvalds                 if (!entry) {
20741da177e4SLinus Torvalds                         found = priv->mcast_vcc;
20751da177e4SLinus Torvalds 			goto out;
20761da177e4SLinus Torvalds                 }
20771da177e4SLinus Torvalds                 lec_arp_add(priv, entry);
20781da177e4SLinus Torvalds                 /* We want arp-request(s) to be sent */
20791da177e4SLinus Torvalds                 entry->packets_flooded =1;
20801da177e4SLinus Torvalds                 entry->status = ESI_ARP_PENDING;
20811da177e4SLinus Torvalds                 entry->no_tries = 1;
20821da177e4SLinus Torvalds                 entry->last_used = entry->timestamp = jiffies;
20831da177e4SLinus Torvalds                 entry->is_rdesc = is_rdesc;
20841da177e4SLinus Torvalds                 if (entry->is_rdesc)
20851da177e4SLinus Torvalds                         send_to_lecd(priv, l_rdesc_arp_xmt, mac_to_find, NULL, NULL);
20861da177e4SLinus Torvalds                 else
20871da177e4SLinus Torvalds                         send_to_lecd(priv, l_arp_xmt, mac_to_find, NULL, NULL);
20881da177e4SLinus Torvalds                 entry->timer.expires = jiffies + (1*HZ);
20891da177e4SLinus Torvalds                 entry->timer.function = lec_arp_expire_arp;
20901da177e4SLinus Torvalds                 add_timer(&entry->timer);
20911da177e4SLinus Torvalds                 found = priv->mcast_vcc;
20921da177e4SLinus Torvalds         }
20931da177e4SLinus Torvalds 
20941da177e4SLinus Torvalds out:
20951da177e4SLinus Torvalds 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
20961da177e4SLinus Torvalds 	return found;
20971da177e4SLinus Torvalds }
20981da177e4SLinus Torvalds 
20991da177e4SLinus Torvalds static int
21001da177e4SLinus Torvalds lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
21011da177e4SLinus Torvalds                 unsigned long permanent)
21021da177e4SLinus Torvalds {
21031da177e4SLinus Torvalds 	unsigned long flags;
21041da177e4SLinus Torvalds         struct lec_arp_table *entry, *next;
21051da177e4SLinus Torvalds         int i;
21061da177e4SLinus Torvalds 
21071da177e4SLinus Torvalds         DPRINTK("lec_addr_delete\n");
21081da177e4SLinus Torvalds 	spin_lock_irqsave(&priv->lec_arp_lock, flags);
21091da177e4SLinus Torvalds         for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
21101da177e4SLinus Torvalds                 for(entry = priv->lec_arp_tables[i]; entry != NULL; entry = next) {
21111da177e4SLinus Torvalds                         next = entry->next;
21121da177e4SLinus Torvalds                         if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)
21131da177e4SLinus Torvalds                             && (permanent ||
21141da177e4SLinus Torvalds                                 !(entry->flags & LEC_PERMANENT_FLAG))) {
21151da177e4SLinus Torvalds 				lec_arp_remove(priv, entry);
21161da177e4SLinus Torvalds                                 kfree(entry);
21171da177e4SLinus Torvalds                         }
21181da177e4SLinus Torvalds 			spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
21191da177e4SLinus Torvalds                         return 0;
21201da177e4SLinus Torvalds                 }
21211da177e4SLinus Torvalds         }
21221da177e4SLinus Torvalds 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
21231da177e4SLinus Torvalds         return -1;
21241da177e4SLinus Torvalds }
21251da177e4SLinus Torvalds 
21261da177e4SLinus Torvalds /*
21271da177e4SLinus Torvalds  * Notifies:  Response to arp_request (atm_addr != NULL)
21281da177e4SLinus Torvalds  */
21291da177e4SLinus Torvalds static void
21301da177e4SLinus Torvalds lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
21311da177e4SLinus Torvalds                unsigned char *atm_addr, unsigned long remoteflag,
21321da177e4SLinus Torvalds                unsigned int targetless_le_arp)
21331da177e4SLinus Torvalds {
21341da177e4SLinus Torvalds 	unsigned long flags;
21351da177e4SLinus Torvalds         struct lec_arp_table *entry, *tmp;
21361da177e4SLinus Torvalds         int i;
21371da177e4SLinus Torvalds 
21381da177e4SLinus Torvalds         DPRINTK("lec:%s", (targetless_le_arp) ? "targetless ": " ");
21391da177e4SLinus Torvalds         DPRINTK("lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
21401da177e4SLinus Torvalds                 mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],
21411da177e4SLinus Torvalds                 mac_addr[4],mac_addr[5]);
21421da177e4SLinus Torvalds 
21431da177e4SLinus Torvalds 	spin_lock_irqsave(&priv->lec_arp_lock, flags);
21441da177e4SLinus Torvalds         entry = lec_arp_find(priv, mac_addr);
21451da177e4SLinus Torvalds         if (entry == NULL && targetless_le_arp)
21461da177e4SLinus Torvalds                 goto out;   /* LANE2: ignore targetless LE_ARPs for which
21471da177e4SLinus Torvalds                              * we have no entry in the cache. 7.1.30
21481da177e4SLinus Torvalds                              */
21491da177e4SLinus Torvalds         if (priv->lec_arp_empty_ones) {
21501da177e4SLinus Torvalds                 entry = priv->lec_arp_empty_ones;
21511da177e4SLinus Torvalds                 if (!memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN)) {
21521da177e4SLinus Torvalds                         priv->lec_arp_empty_ones = entry->next;
21531da177e4SLinus Torvalds                 } else {
21541da177e4SLinus Torvalds                         while(entry->next && memcmp(entry->next->atm_addr,
21551da177e4SLinus Torvalds                                                     atm_addr, ATM_ESA_LEN))
21561da177e4SLinus Torvalds                                 entry = entry->next;
21571da177e4SLinus Torvalds                         if (entry->next) {
21581da177e4SLinus Torvalds                                 tmp = entry;
21591da177e4SLinus Torvalds                                 entry = entry->next;
21601da177e4SLinus Torvalds                                 tmp->next = entry->next;
21611da177e4SLinus Torvalds                         } else
21621da177e4SLinus Torvalds                                 entry = NULL;
21631da177e4SLinus Torvalds 
21641da177e4SLinus Torvalds                 }
21651da177e4SLinus Torvalds                 if (entry) {
21661da177e4SLinus Torvalds                         del_timer(&entry->timer);
21671da177e4SLinus Torvalds                         tmp = lec_arp_find(priv, mac_addr);
21681da177e4SLinus Torvalds                         if (tmp) {
21691da177e4SLinus Torvalds                                 del_timer(&tmp->timer);
21701da177e4SLinus Torvalds                                 tmp->status = ESI_FORWARD_DIRECT;
21711da177e4SLinus Torvalds                                 memcpy(tmp->atm_addr, atm_addr, ATM_ESA_LEN);
21721da177e4SLinus Torvalds                                 tmp->vcc = entry->vcc;
21731da177e4SLinus Torvalds                                 tmp->old_push = entry->old_push;
21741da177e4SLinus Torvalds                                 tmp->last_used = jiffies;
21751da177e4SLinus Torvalds                                 del_timer(&entry->timer);
21761da177e4SLinus Torvalds                                 kfree(entry);
21771da177e4SLinus Torvalds                                 entry=tmp;
21781da177e4SLinus Torvalds                         } else {
21791da177e4SLinus Torvalds                                 entry->status = ESI_FORWARD_DIRECT;
21801da177e4SLinus Torvalds                                 memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
21811da177e4SLinus Torvalds                                 entry->last_used = jiffies;
21821da177e4SLinus Torvalds                                 lec_arp_add(priv, entry);
21831da177e4SLinus Torvalds                         }
21841da177e4SLinus Torvalds                         if (remoteflag)
21851da177e4SLinus Torvalds                                 entry->flags|=LEC_REMOTE_FLAG;
21861da177e4SLinus Torvalds                         else
21871da177e4SLinus Torvalds                                 entry->flags&=~LEC_REMOTE_FLAG;
21881da177e4SLinus Torvalds                         DPRINTK("After update\n");
21891da177e4SLinus Torvalds                         dump_arp_table(priv);
21901da177e4SLinus Torvalds                         goto out;
21911da177e4SLinus Torvalds                 }
21921da177e4SLinus Torvalds         }
21931da177e4SLinus Torvalds         entry = lec_arp_find(priv, mac_addr);
21941da177e4SLinus Torvalds         if (!entry) {
21951da177e4SLinus Torvalds                 entry = make_entry(priv, mac_addr);
21961da177e4SLinus Torvalds                 if (!entry)
21971da177e4SLinus Torvalds 			goto out;
21981da177e4SLinus Torvalds                 entry->status = ESI_UNKNOWN;
21991da177e4SLinus Torvalds                 lec_arp_add(priv, entry);
22001da177e4SLinus Torvalds                 /* Temporary, changes before end of function */
22011da177e4SLinus Torvalds         }
22021da177e4SLinus Torvalds         memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
22031da177e4SLinus Torvalds         del_timer(&entry->timer);
22041da177e4SLinus Torvalds         for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
22051da177e4SLinus Torvalds                 for(tmp = priv->lec_arp_tables[i]; tmp; tmp=tmp->next) {
22061da177e4SLinus Torvalds                         if (entry != tmp &&
22071da177e4SLinus Torvalds                             !memcmp(tmp->atm_addr, atm_addr,
22081da177e4SLinus Torvalds                                     ATM_ESA_LEN)) {
22091da177e4SLinus Torvalds                                 /* Vcc to this host exists */
22101da177e4SLinus Torvalds                                 if (tmp->status > ESI_VC_PENDING) {
22111da177e4SLinus Torvalds                                         /*
22121da177e4SLinus Torvalds                                          * ESI_FLUSH_PENDING,
22131da177e4SLinus Torvalds                                          * ESI_FORWARD_DIRECT
22141da177e4SLinus Torvalds                                          */
22151da177e4SLinus Torvalds                                         entry->vcc = tmp->vcc;
22161da177e4SLinus Torvalds                                         entry->old_push=tmp->old_push;
22171da177e4SLinus Torvalds                                 }
22181da177e4SLinus Torvalds                                 entry->status=tmp->status;
22191da177e4SLinus Torvalds                                 break;
22201da177e4SLinus Torvalds                         }
22211da177e4SLinus Torvalds                 }
22221da177e4SLinus Torvalds         }
22231da177e4SLinus Torvalds         if (remoteflag)
22241da177e4SLinus Torvalds                 entry->flags|=LEC_REMOTE_FLAG;
22251da177e4SLinus Torvalds         else
22261da177e4SLinus Torvalds                 entry->flags&=~LEC_REMOTE_FLAG;
22271da177e4SLinus Torvalds         if (entry->status == ESI_ARP_PENDING ||
22281da177e4SLinus Torvalds             entry->status == ESI_UNKNOWN) {
22291da177e4SLinus Torvalds                 entry->status = ESI_VC_PENDING;
22301da177e4SLinus Torvalds                 send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL);
22311da177e4SLinus Torvalds         }
22321da177e4SLinus Torvalds         DPRINTK("After update2\n");
22331da177e4SLinus Torvalds         dump_arp_table(priv);
22341da177e4SLinus Torvalds out:
22351da177e4SLinus Torvalds 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
22361da177e4SLinus Torvalds }
22371da177e4SLinus Torvalds 
22381da177e4SLinus Torvalds /*
22391da177e4SLinus Torvalds  * Notifies: Vcc setup ready
22401da177e4SLinus Torvalds  */
22411da177e4SLinus Torvalds static void
22421da177e4SLinus Torvalds lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
22431da177e4SLinus Torvalds               struct atm_vcc *vcc,
22441da177e4SLinus Torvalds               void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb))
22451da177e4SLinus Torvalds {
22461da177e4SLinus Torvalds 	unsigned long flags;
22471da177e4SLinus Torvalds         struct lec_arp_table *entry;
22481da177e4SLinus Torvalds         int i, found_entry=0;
22491da177e4SLinus Torvalds 
22501da177e4SLinus Torvalds 	spin_lock_irqsave(&priv->lec_arp_lock, flags);
22511da177e4SLinus Torvalds         if (ioc_data->receive == 2) {
22521da177e4SLinus Torvalds                 /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
22531da177e4SLinus Torvalds 
22541da177e4SLinus Torvalds                 DPRINTK("LEC_ARP: Attaching mcast forward\n");
22551da177e4SLinus Torvalds #if 0
22561da177e4SLinus Torvalds                 entry = lec_arp_find(priv, bus_mac);
22571da177e4SLinus Torvalds                 if (!entry) {
22581da177e4SLinus Torvalds                         printk("LEC_ARP: Multicast entry not found!\n");
22591da177e4SLinus Torvalds 			goto out;
22601da177e4SLinus Torvalds                 }
22611da177e4SLinus Torvalds                 memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
22621da177e4SLinus Torvalds                 entry->recv_vcc = vcc;
22631da177e4SLinus Torvalds                 entry->old_recv_push = old_push;
22641da177e4SLinus Torvalds #endif
22651da177e4SLinus Torvalds                 entry = make_entry(priv, bus_mac);
22661da177e4SLinus Torvalds                 if (entry == NULL)
22671da177e4SLinus Torvalds 			goto out;
22681da177e4SLinus Torvalds                 del_timer(&entry->timer);
22691da177e4SLinus Torvalds                 memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
22701da177e4SLinus Torvalds                 entry->recv_vcc = vcc;
22711da177e4SLinus Torvalds                 entry->old_recv_push = old_push;
22721da177e4SLinus Torvalds                 entry->next = priv->mcast_fwds;
22731da177e4SLinus Torvalds                 priv->mcast_fwds = entry;
22741da177e4SLinus Torvalds                 goto out;
22751da177e4SLinus Torvalds         } else if (ioc_data->receive == 1) {
22761da177e4SLinus Torvalds                 /* Vcc which we don't want to make default vcc, attach it
22771da177e4SLinus Torvalds                    anyway. */
22781da177e4SLinus Torvalds                 DPRINTK("LEC_ARP:Attaching data direct, not default :%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
22791da177e4SLinus Torvalds                         ioc_data->atm_addr[0],ioc_data->atm_addr[1],
22801da177e4SLinus Torvalds                         ioc_data->atm_addr[2],ioc_data->atm_addr[3],
22811da177e4SLinus Torvalds                         ioc_data->atm_addr[4],ioc_data->atm_addr[5],
22821da177e4SLinus Torvalds                         ioc_data->atm_addr[6],ioc_data->atm_addr[7],
22831da177e4SLinus Torvalds                         ioc_data->atm_addr[8],ioc_data->atm_addr[9],
22841da177e4SLinus Torvalds                         ioc_data->atm_addr[10],ioc_data->atm_addr[11],
22851da177e4SLinus Torvalds                         ioc_data->atm_addr[12],ioc_data->atm_addr[13],
22861da177e4SLinus Torvalds                         ioc_data->atm_addr[14],ioc_data->atm_addr[15],
22871da177e4SLinus Torvalds                         ioc_data->atm_addr[16],ioc_data->atm_addr[17],
22881da177e4SLinus Torvalds                         ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
22891da177e4SLinus Torvalds                 entry = make_entry(priv, bus_mac);
22901da177e4SLinus Torvalds                 if (entry == NULL)
22911da177e4SLinus Torvalds 			goto out;
22921da177e4SLinus Torvalds                 memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
22931da177e4SLinus Torvalds                 memset(entry->mac_addr, 0, ETH_ALEN);
22941da177e4SLinus Torvalds                 entry->recv_vcc = vcc;
22951da177e4SLinus Torvalds                 entry->old_recv_push = old_push;
22961da177e4SLinus Torvalds                 entry->status = ESI_UNKNOWN;
22971da177e4SLinus Torvalds                 entry->timer.expires = jiffies + priv->vcc_timeout_period;
22981da177e4SLinus Torvalds                 entry->timer.function = lec_arp_expire_vcc;
22991da177e4SLinus Torvalds                 add_timer(&entry->timer);
23001da177e4SLinus Torvalds                 entry->next = priv->lec_no_forward;
23011da177e4SLinus Torvalds                 priv->lec_no_forward = entry;
23021da177e4SLinus Torvalds 		dump_arp_table(priv);
23031da177e4SLinus Torvalds 		goto out;
23041da177e4SLinus Torvalds         }
23051da177e4SLinus Torvalds         DPRINTK("LEC_ARP:Attaching data direct, default:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
23061da177e4SLinus Torvalds                 ioc_data->atm_addr[0],ioc_data->atm_addr[1],
23071da177e4SLinus Torvalds                 ioc_data->atm_addr[2],ioc_data->atm_addr[3],
23081da177e4SLinus Torvalds                 ioc_data->atm_addr[4],ioc_data->atm_addr[5],
23091da177e4SLinus Torvalds                 ioc_data->atm_addr[6],ioc_data->atm_addr[7],
23101da177e4SLinus Torvalds                 ioc_data->atm_addr[8],ioc_data->atm_addr[9],
23111da177e4SLinus Torvalds                 ioc_data->atm_addr[10],ioc_data->atm_addr[11],
23121da177e4SLinus Torvalds                 ioc_data->atm_addr[12],ioc_data->atm_addr[13],
23131da177e4SLinus Torvalds                 ioc_data->atm_addr[14],ioc_data->atm_addr[15],
23141da177e4SLinus Torvalds                 ioc_data->atm_addr[16],ioc_data->atm_addr[17],
23151da177e4SLinus Torvalds                 ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
23161da177e4SLinus Torvalds         for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
23171da177e4SLinus Torvalds                 for (entry = priv->lec_arp_tables[i]; entry; entry=entry->next) {
23181da177e4SLinus Torvalds                         if (memcmp(ioc_data->atm_addr, entry->atm_addr,
23191da177e4SLinus Torvalds                                    ATM_ESA_LEN)==0) {
23201da177e4SLinus Torvalds                                 DPRINTK("LEC_ARP: Attaching data direct\n");
23211da177e4SLinus Torvalds                                 DPRINTK("Currently -> Vcc: %d, Rvcc:%d\n",
23221da177e4SLinus Torvalds                                         entry->vcc?entry->vcc->vci:0,
23231da177e4SLinus Torvalds                                         entry->recv_vcc?entry->recv_vcc->vci:0);
23241da177e4SLinus Torvalds                                 found_entry=1;
23251da177e4SLinus Torvalds                                 del_timer(&entry->timer);
23261da177e4SLinus Torvalds                                 entry->vcc = vcc;
23271da177e4SLinus Torvalds                                 entry->old_push = old_push;
23281da177e4SLinus Torvalds                                 if (entry->status == ESI_VC_PENDING) {
23291da177e4SLinus Torvalds                                         if(priv->maximum_unknown_frame_count
23301da177e4SLinus Torvalds                                            ==0)
23311da177e4SLinus Torvalds                                                 entry->status =
23321da177e4SLinus Torvalds                                                         ESI_FORWARD_DIRECT;
23331da177e4SLinus Torvalds                                         else {
23341da177e4SLinus Torvalds                                                 entry->timestamp = jiffies;
23351da177e4SLinus Torvalds                                                 entry->status =
23361da177e4SLinus Torvalds                                                         ESI_FLUSH_PENDING;
23371da177e4SLinus Torvalds #if 0
23381da177e4SLinus Torvalds                                                 send_to_lecd(priv,l_flush_xmt,
23391da177e4SLinus Torvalds                                                              NULL,
23401da177e4SLinus Torvalds                                                              entry->atm_addr,
23411da177e4SLinus Torvalds                                                              NULL);
23421da177e4SLinus Torvalds #endif
23431da177e4SLinus Torvalds                                         }
23441da177e4SLinus Torvalds                                 } else {
23451da177e4SLinus Torvalds                                         /* They were forming a connection
23461da177e4SLinus Torvalds                                            to us, and we to them. Our
23471da177e4SLinus Torvalds                                            ATM address is numerically lower
23481da177e4SLinus Torvalds                                            than theirs, so we make connection
23491da177e4SLinus Torvalds                                            we formed into default VCC (8.1.11).
23501da177e4SLinus Torvalds                                            Connection they made gets torn
23511da177e4SLinus Torvalds                                            down. This might confuse some
23521da177e4SLinus Torvalds                                            clients. Can be changed if
23531da177e4SLinus Torvalds                                            someone reports trouble... */
23541da177e4SLinus Torvalds                                         ;
23551da177e4SLinus Torvalds                                 }
23561da177e4SLinus Torvalds                         }
23571da177e4SLinus Torvalds                 }
23581da177e4SLinus Torvalds         }
23591da177e4SLinus Torvalds         if (found_entry) {
23601da177e4SLinus Torvalds                 DPRINTK("After vcc was added\n");
23611da177e4SLinus Torvalds                 dump_arp_table(priv);
23621da177e4SLinus Torvalds 		goto out;
23631da177e4SLinus Torvalds         }
23641da177e4SLinus Torvalds         /* Not found, snatch address from first data packet that arrives from
23651da177e4SLinus Torvalds            this vcc */
23661da177e4SLinus Torvalds         entry = make_entry(priv, bus_mac);
23671da177e4SLinus Torvalds         if (!entry)
23681da177e4SLinus Torvalds 		goto out;
23691da177e4SLinus Torvalds         entry->vcc = vcc;
23701da177e4SLinus Torvalds         entry->old_push = old_push;
23711da177e4SLinus Torvalds         memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
23721da177e4SLinus Torvalds         memset(entry->mac_addr, 0, ETH_ALEN);
23731da177e4SLinus Torvalds         entry->status = ESI_UNKNOWN;
23741da177e4SLinus Torvalds         entry->next = priv->lec_arp_empty_ones;
23751da177e4SLinus Torvalds         priv->lec_arp_empty_ones = entry;
23761da177e4SLinus Torvalds         entry->timer.expires = jiffies + priv->vcc_timeout_period;
23771da177e4SLinus Torvalds         entry->timer.function = lec_arp_expire_vcc;
23781da177e4SLinus Torvalds         add_timer(&entry->timer);
23791da177e4SLinus Torvalds         DPRINTK("After vcc was added\n");
23801da177e4SLinus Torvalds 	dump_arp_table(priv);
23811da177e4SLinus Torvalds out:
23821da177e4SLinus Torvalds 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
23831da177e4SLinus Torvalds }
23841da177e4SLinus Torvalds 
23851da177e4SLinus Torvalds static void
23861da177e4SLinus Torvalds lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
23871da177e4SLinus Torvalds {
23881da177e4SLinus Torvalds 	unsigned long flags;
23891da177e4SLinus Torvalds         struct lec_arp_table *entry;
23901da177e4SLinus Torvalds         int i;
23911da177e4SLinus Torvalds 
23921da177e4SLinus Torvalds         DPRINTK("LEC:lec_flush_complete %lx\n",tran_id);
23931da177e4SLinus Torvalds 	spin_lock_irqsave(&priv->lec_arp_lock, flags);
23941da177e4SLinus Torvalds         for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
23951da177e4SLinus Torvalds                 for (entry = priv->lec_arp_tables[i]; entry; entry=entry->next) {
23961da177e4SLinus Torvalds                         if (entry->flush_tran_id == tran_id &&
23971da177e4SLinus Torvalds                             entry->status == ESI_FLUSH_PENDING) {
23981da177e4SLinus Torvalds 			        struct sk_buff *skb;
23991da177e4SLinus Torvalds 
24001da177e4SLinus Torvalds  				while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
24011da177e4SLinus Torvalds 					lec_send(entry->vcc, skb, entry->priv);
24021da177e4SLinus Torvalds                                 entry->status = ESI_FORWARD_DIRECT;
24031da177e4SLinus Torvalds                                 DPRINTK("LEC_ARP: Flushed\n");
24041da177e4SLinus Torvalds                         }
24051da177e4SLinus Torvalds                 }
24061da177e4SLinus Torvalds         }
24071da177e4SLinus Torvalds 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
24081da177e4SLinus Torvalds         dump_arp_table(priv);
24091da177e4SLinus Torvalds }
24101da177e4SLinus Torvalds 
24111da177e4SLinus Torvalds static void
24121da177e4SLinus Torvalds lec_set_flush_tran_id(struct lec_priv *priv,
24131da177e4SLinus Torvalds                       unsigned char *atm_addr, unsigned long tran_id)
24141da177e4SLinus Torvalds {
24151da177e4SLinus Torvalds 	unsigned long flags;
24161da177e4SLinus Torvalds         struct lec_arp_table *entry;
24171da177e4SLinus Torvalds         int i;
24181da177e4SLinus Torvalds 
24191da177e4SLinus Torvalds 	spin_lock_irqsave(&priv->lec_arp_lock, flags);
24201da177e4SLinus Torvalds         for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
24211da177e4SLinus Torvalds                 for(entry = priv->lec_arp_tables[i]; entry; entry=entry->next)
24221da177e4SLinus Torvalds                         if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {
24231da177e4SLinus Torvalds                                 entry->flush_tran_id = tran_id;
24241da177e4SLinus Torvalds                                 DPRINTK("Set flush transaction id to %lx for %p\n",tran_id,entry);
24251da177e4SLinus Torvalds                         }
24261da177e4SLinus Torvalds 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
24271da177e4SLinus Torvalds }
24281da177e4SLinus Torvalds 
24291da177e4SLinus Torvalds static int
24301da177e4SLinus Torvalds lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
24311da177e4SLinus Torvalds {
24321da177e4SLinus Torvalds 	unsigned long flags;
24331da177e4SLinus Torvalds         unsigned char mac_addr[] = {
24341da177e4SLinus Torvalds                 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
24351da177e4SLinus Torvalds         struct lec_arp_table *to_add;
24361da177e4SLinus Torvalds 	struct lec_vcc_priv *vpriv;
24371da177e4SLinus Torvalds 	int err = 0;
24381da177e4SLinus Torvalds 
24391da177e4SLinus Torvalds 	if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL)))
24401da177e4SLinus Torvalds 		return -ENOMEM;
24411da177e4SLinus Torvalds 	vpriv->xoff = 0;
24421da177e4SLinus Torvalds 	vpriv->old_pop = vcc->pop;
24431da177e4SLinus Torvalds 	vcc->user_back = vpriv;
24441da177e4SLinus Torvalds         vcc->pop = lec_pop;
24451da177e4SLinus Torvalds 	spin_lock_irqsave(&priv->lec_arp_lock, flags);
24461da177e4SLinus Torvalds         to_add = make_entry(priv, mac_addr);
24471da177e4SLinus Torvalds         if (!to_add) {
24481da177e4SLinus Torvalds 		vcc->pop = vpriv->old_pop;
24491da177e4SLinus Torvalds 		kfree(vpriv);
24501da177e4SLinus Torvalds                 err = -ENOMEM;
24511da177e4SLinus Torvalds 		goto out;
24521da177e4SLinus Torvalds         }
24531da177e4SLinus Torvalds         memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN);
24541da177e4SLinus Torvalds         to_add->status = ESI_FORWARD_DIRECT;
24551da177e4SLinus Torvalds         to_add->flags |= LEC_PERMANENT_FLAG;
24561da177e4SLinus Torvalds         to_add->vcc = vcc;
24571da177e4SLinus Torvalds         to_add->old_push = vcc->push;
24581da177e4SLinus Torvalds         vcc->push = lec_push;
24591da177e4SLinus Torvalds         priv->mcast_vcc = vcc;
24601da177e4SLinus Torvalds         lec_arp_add(priv, to_add);
24611da177e4SLinus Torvalds out:
24621da177e4SLinus Torvalds 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
24631da177e4SLinus Torvalds         return err;
24641da177e4SLinus Torvalds }
24651da177e4SLinus Torvalds 
24661da177e4SLinus Torvalds static void
24671da177e4SLinus Torvalds lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
24681da177e4SLinus Torvalds {
24691da177e4SLinus Torvalds 	unsigned long flags;
24701da177e4SLinus Torvalds         struct lec_arp_table *entry, *next;
24711da177e4SLinus Torvalds         int i;
24721da177e4SLinus Torvalds 
24731da177e4SLinus Torvalds         DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n",vcc->vpi,vcc->vci);
24741da177e4SLinus Torvalds         dump_arp_table(priv);
24751da177e4SLinus Torvalds 	spin_lock_irqsave(&priv->lec_arp_lock, flags);
24761da177e4SLinus Torvalds         for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
24771da177e4SLinus Torvalds                 for(entry = priv->lec_arp_tables[i];entry; entry=next) {
24781da177e4SLinus Torvalds                         next = entry->next;
24791da177e4SLinus Torvalds                         if (vcc == entry->vcc) {
24801da177e4SLinus Torvalds                                 lec_arp_remove(priv, entry);
24811da177e4SLinus Torvalds                                 kfree(entry);
24821da177e4SLinus Torvalds                                 if (priv->mcast_vcc == vcc) {
24831da177e4SLinus Torvalds                                         priv->mcast_vcc = NULL;
24841da177e4SLinus Torvalds                                 }
24851da177e4SLinus Torvalds                         }
24861da177e4SLinus Torvalds                 }
24871da177e4SLinus Torvalds         }
24881da177e4SLinus Torvalds 
24891da177e4SLinus Torvalds         entry = priv->lec_arp_empty_ones;
24901da177e4SLinus Torvalds         priv->lec_arp_empty_ones = NULL;
24911da177e4SLinus Torvalds         while (entry != NULL) {
24921da177e4SLinus Torvalds                 next = entry->next;
24931da177e4SLinus Torvalds                 if (entry->vcc == vcc) { /* leave it out from the list */
24941da177e4SLinus Torvalds                         lec_arp_clear_vccs(entry);
24951da177e4SLinus Torvalds                         del_timer(&entry->timer);
24961da177e4SLinus Torvalds                         kfree(entry);
24971da177e4SLinus Torvalds                 }
24981da177e4SLinus Torvalds                 else {              /* put it back to the list */
24991da177e4SLinus Torvalds                         entry->next = priv->lec_arp_empty_ones;
25001da177e4SLinus Torvalds                         priv->lec_arp_empty_ones = entry;
25011da177e4SLinus Torvalds                 }
25021da177e4SLinus Torvalds                 entry = next;
25031da177e4SLinus Torvalds         }
25041da177e4SLinus Torvalds 
25051da177e4SLinus Torvalds         entry = priv->lec_no_forward;
25061da177e4SLinus Torvalds         priv->lec_no_forward = NULL;
25071da177e4SLinus Torvalds         while (entry != NULL) {
25081da177e4SLinus Torvalds                 next = entry->next;
25091da177e4SLinus Torvalds                 if (entry->recv_vcc == vcc) {
25101da177e4SLinus Torvalds                         lec_arp_clear_vccs(entry);
25111da177e4SLinus Torvalds                         del_timer(&entry->timer);
25121da177e4SLinus Torvalds                         kfree(entry);
25131da177e4SLinus Torvalds                 }
25141da177e4SLinus Torvalds                 else {
25151da177e4SLinus Torvalds                         entry->next = priv->lec_no_forward;
25161da177e4SLinus Torvalds                         priv->lec_no_forward = entry;
25171da177e4SLinus Torvalds                 }
25181da177e4SLinus Torvalds                 entry = next;
25191da177e4SLinus Torvalds         }
25201da177e4SLinus Torvalds 
25211da177e4SLinus Torvalds         entry = priv->mcast_fwds;
25221da177e4SLinus Torvalds         priv->mcast_fwds = NULL;
25231da177e4SLinus Torvalds         while (entry != NULL) {
25241da177e4SLinus Torvalds                 next = entry->next;
25251da177e4SLinus Torvalds                 if (entry->recv_vcc == vcc) {
25261da177e4SLinus Torvalds                         lec_arp_clear_vccs(entry);
25271da177e4SLinus Torvalds                         /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
25281da177e4SLinus Torvalds                         kfree(entry);
25291da177e4SLinus Torvalds                 }
25301da177e4SLinus Torvalds                 else {
25311da177e4SLinus Torvalds                         entry->next = priv->mcast_fwds;
25321da177e4SLinus Torvalds                         priv->mcast_fwds = entry;
25331da177e4SLinus Torvalds                 }
25341da177e4SLinus Torvalds                 entry = next;
25351da177e4SLinus Torvalds         }
25361da177e4SLinus Torvalds 
25371da177e4SLinus Torvalds 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
25381da177e4SLinus Torvalds 	dump_arp_table(priv);
25391da177e4SLinus Torvalds }
25401da177e4SLinus Torvalds 
25411da177e4SLinus Torvalds static void
25421da177e4SLinus Torvalds lec_arp_check_empties(struct lec_priv *priv,
25431da177e4SLinus Torvalds                       struct atm_vcc *vcc, struct sk_buff *skb)
25441da177e4SLinus Torvalds {
25451da177e4SLinus Torvalds         unsigned long flags;
25461da177e4SLinus Torvalds         struct lec_arp_table *entry, *prev;
25471da177e4SLinus Torvalds         struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
25481da177e4SLinus Torvalds         unsigned char *src;
25491da177e4SLinus Torvalds #ifdef CONFIG_TR
25501da177e4SLinus Torvalds         struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
25511da177e4SLinus Torvalds 
25521da177e4SLinus Torvalds         if (priv->is_trdev) src = tr_hdr->h_source;
25531da177e4SLinus Torvalds         else
25541da177e4SLinus Torvalds #endif
25551da177e4SLinus Torvalds         src = hdr->h_source;
25561da177e4SLinus Torvalds 
25571da177e4SLinus Torvalds 	spin_lock_irqsave(&priv->lec_arp_lock, flags);
25581da177e4SLinus Torvalds         entry = priv->lec_arp_empty_ones;
25591da177e4SLinus Torvalds         if (vcc == entry->vcc) {
25601da177e4SLinus Torvalds                 del_timer(&entry->timer);
25611da177e4SLinus Torvalds                 memcpy(entry->mac_addr, src, ETH_ALEN);
25621da177e4SLinus Torvalds                 entry->status = ESI_FORWARD_DIRECT;
25631da177e4SLinus Torvalds                 entry->last_used = jiffies;
25641da177e4SLinus Torvalds                 priv->lec_arp_empty_ones = entry->next;
25651da177e4SLinus Torvalds                 /* We might have got an entry */
25661da177e4SLinus Torvalds                 if ((prev = lec_arp_find(priv,src))) {
25671da177e4SLinus Torvalds                         lec_arp_remove(priv, prev);
25681da177e4SLinus Torvalds                         kfree(prev);
25691da177e4SLinus Torvalds                 }
25701da177e4SLinus Torvalds                 lec_arp_add(priv, entry);
25711da177e4SLinus Torvalds 		goto out;
25721da177e4SLinus Torvalds         }
25731da177e4SLinus Torvalds         prev = entry;
25741da177e4SLinus Torvalds         entry = entry->next;
25751da177e4SLinus Torvalds         while (entry && entry->vcc != vcc) {
25761da177e4SLinus Torvalds                 prev= entry;
25771da177e4SLinus Torvalds                 entry = entry->next;
25781da177e4SLinus Torvalds         }
25791da177e4SLinus Torvalds         if (!entry) {
25801da177e4SLinus Torvalds                 DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n");
25811da177e4SLinus Torvalds 		goto out;
25821da177e4SLinus Torvalds         }
25831da177e4SLinus Torvalds         del_timer(&entry->timer);
25841da177e4SLinus Torvalds         memcpy(entry->mac_addr, src, ETH_ALEN);
25851da177e4SLinus Torvalds         entry->status = ESI_FORWARD_DIRECT;
25861da177e4SLinus Torvalds         entry->last_used = jiffies;
25871da177e4SLinus Torvalds         prev->next = entry->next;
25881da177e4SLinus Torvalds         if ((prev = lec_arp_find(priv, src))) {
25891da177e4SLinus Torvalds                 lec_arp_remove(priv, prev);
25901da177e4SLinus Torvalds                 kfree(prev);
25911da177e4SLinus Torvalds         }
25921da177e4SLinus Torvalds         lec_arp_add(priv, entry);
25931da177e4SLinus Torvalds out:
25941da177e4SLinus Torvalds 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
25951da177e4SLinus Torvalds }
25961da177e4SLinus Torvalds MODULE_LICENSE("GPL");
2597