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