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