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