Newer
Older
* Marko Kiiskila <mkiiskila@yahoo.com>
*/
#include <linux/kernel.h>
#include <linux/bitops.h>
/* We are ethernet device */
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <net/sock.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
#include <net/arp.h>
#include <net/dst.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/seq_file.h>
/* TokenRing if needed */
#ifdef CONFIG_TR
#include <linux/trdevice.h>
#endif
/* And atm device */
#include <linux/atmdev.h>
#include <linux/atmlec.h>
/* Proxy LEC knows about bridging */
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
#include <linux/if_bridge.h>
#include "../bridge/br_private.h"
static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
#endif
/* Modular too */
#include <linux/module.h>
#include <linux/init.h>
#include "lec.h"
#include "lec_arpc.h"
#include "resources.h"
#define DUMP_PACKETS 0 /*
* 0 = None,
* 1 = 30 first bytes
* 2 = Whole packet
*/
#define LEC_UNRES_QUE_LEN 8 /*
* number of tx packets to queue for a
* single destination while waiting for SVC
*/
static int lec_open(struct net_device *dev);
static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int lec_close(struct net_device *dev);
static struct net_device_stats *lec_get_stats(struct net_device *dev);
static void lec_init(struct net_device *dev);
static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
unsigned char *mac_addr);
struct lec_arp_table *to_remove);
static void lane2_associate_ind(struct net_device *dev, u8 *mac_address,
u8 *tlvs, u32 sizeoftlvs);
static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
u8 **tlvs, u32 *sizeoftlvs);
static int lane2_associate_req(struct net_device *dev, u8 *lan_dst,
u8 *tlvs, u32 sizeoftlvs);
static int lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
unsigned long permanent);
static void lec_arp_check_empties(struct lec_priv *priv,
struct atm_vcc *vcc, struct sk_buff *skb);
static void lec_arp_destroy(struct lec_priv *priv);
static void lec_arp_init(struct lec_priv *priv);
static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
unsigned char *mac_to_find,
int is_rdesc,
struct lec_arp_table **ret_entry);
static void lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
unsigned char *atm_addr, unsigned long remoteflag,
unsigned int targetless_le_arp);
static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id);
static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc);
static void lec_set_flush_tran_id(struct lec_priv *priv,
unsigned char *atm_addr,
unsigned long tran_id);
static void lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
struct atm_vcc *vcc,
void (*old_push) (struct atm_vcc *vcc,
struct sk_buff *skb));
static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc);
/* must be done under lec_arp_lock */
static inline void lec_arp_hold(struct lec_arp_table *entry)
{
atomic_inc(&entry->usage);
}
static inline void lec_arp_put(struct lec_arp_table *entry)
{
if (atomic_dec_and_test(&entry->usage))
kfree(entry);
}
lane2_resolve, /* resolve, spec 3.1.3 */
lane2_associate_req, /* associate_req, spec 3.1.4 */
NULL /* associate indicator, spec 3.1.5 */
static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
/* Device structures */
static struct net_device *dev_lec[MAX_LEC_ITF];
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
char *buff;
struct lec_priv *priv;
/*
* Check if this is a BPDU. If so, ask zeppelin to send
* LE_TOPOLOGY_REQUEST with the same value of Topology Change bit
* as the Config BPDU has
*/
eth = (struct ethhdr *)skb->data;
buff = skb->data + skb->dev->hard_header_len;
if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {
struct sk_buff *skb2;
struct atmlec_msg *mesg;
skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
if (skb2 == NULL)
return;
skb2->len = sizeof(struct atmlec_msg);
mesg = (struct atmlec_msg *)skb2->data;
mesg->type = l_topology_change;
buff += 4;
mesg->content.normal.flag = *buff & 0x01; /* 0x01 is topology change */
priv = (struct lec_priv *)dev->priv;
atm_force_charge(priv->lecd, skb2->truesize);
skb_queue_tail(&sk->sk_receive_queue, skb2);
sk->sk_data_ready(sk, skb2->len);
}
}
#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
/*
* Modelled after tr_type_trans
* All multicast and ARE or STE frames go to BUS.
* Non source routed frames go by destination address.
* Last hop source routed frames go by destination address.
* Not last hop source routed frames go by _next_ route descriptor.
* Returns pointer to destination MAC address or fills in rdesc
* and returns NULL.
*/
#ifdef CONFIG_TR
static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
{
struct trh_hdr *trh;
trh = (struct trh_hdr *)packet;
if (trh->daddr[0] & (uint8_t) 0x80)
return bus_mac; /* multicast */
if (trh->saddr[0] & TR_RII) {
riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
if ((ntohs(trh->rcf) >> 13) != 0)
return bus_mac; /* ARE or STE */
} else
return trh->daddr; /* not source routed */
if (riflen < 6)
return trh->daddr; /* last hop, source routed */
/* riflen is 6 or more, packet has more than one route descriptor */
num_rdsc = (riflen / 2) - 1;
memset(rdesc, 0, ETH_ALEN);
/* offset 4 comes from LAN destination field in LE control frames */
if (trh->rcf & htons((uint16_t) TR_RCF_DIR_BIT))
memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(__be16));
rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0));
}
return NULL;
}
#endif /* CONFIG_TR */
/*
* Open/initialize the netdevice. This is called (in the current kernel)
* sometime after booting when the 'ifconfig' program is run.
*
* This routine should set everything up anew at each open, even
* registers that "should" only need to be set once at boot, so that
* there is non-reboot way to recover if something goes wrong.
*/
static int lec_open(struct net_device *dev)
struct lec_priv *priv = (struct lec_priv *)dev->priv;
memset(&priv->stats, 0, sizeof(struct net_device_stats));
return 0;
}
static __inline__ void
lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv)
{
ATM_SKB(skb)->vcc = vcc;
ATM_SKB(skb)->atm_options = vcc->atm_options;
atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
if (vcc->send(vcc, skb) < 0) {
priv->stats.tx_dropped++;
return;
}
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
}
static void lec_tx_timeout(struct net_device *dev)
{
printk(KERN_INFO "%s: tx timeout\n", dev->name);
dev->trans_start = jiffies;
netif_wake_queue(dev);
}
static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct sk_buff *skb2;
struct lec_priv *priv = (struct lec_priv *)dev->priv;
struct lecdatahdr_8023 *lec_h;
struct atm_vcc *vcc;
unsigned char rdesc[ETH_ALEN]; /* Token Ring route descriptor */
char buf[300];
int i = 0;
pr_debug("lec_start_xmit called\n");
if (!priv->lecd) {
printk("%s:No lecd attached\n", dev->name);
priv->stats.tx_errors++;
netif_stop_queue(dev);
return -EUNATCH;
}
pr_debug("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
(long)skb->head, (long)skb->data, (long)skb_tail_pointer(skb),
(long)skb_end_pointer(skb));
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
if (memcmp(skb->data, bridge_ula_lec, sizeof(bridge_ula_lec)) == 0)
lec_handle_bridge(skb, dev);
/* Make sure we have room for lec_id */
if (skb_headroom(skb) < 2) {
pr_debug("lec_start_xmit: reallocating skb\n");
skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
kfree_skb(skb);
if (skb2 == NULL)
return 0;
skb = skb2;
}
skb_push(skb, 2);
/* Put le header to place, works for TokenRing too */
lec_h = (struct lecdatahdr_8023 *)skb->data;
lec_h->le_header = htons(priv->lecid);
/*
* Ugly. Use this to realign Token Ring packets for
* e.g. PCA-200E driver.
*/
if (priv->is_trdev) {
skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
kfree_skb(skb);
if (skb2 == NULL)
return 0;
skb = skb2;
}
printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name,
skb->len, priv->lecid);
for (i = 0; i < skb->len && i < 99; i++) {
sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
}
for (i = 0; i < skb->len && i < 30; i++) {
sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
}
if (i == skb->len)
printk("%s\n", buf);
else
printk("%s...\n", buf);
/* Minimum ethernet-frame size */
if (priv->is_trdev)
min_frame_size = LEC_MINIMUM_8025_SIZE;
min_frame_size = LEC_MINIMUM_8023_SIZE;
if (skb->len < min_frame_size) {
if ((skb->len + skb_tailroom(skb)) < min_frame_size) {
skb2 = skb_copy_expand(skb, 0,
min_frame_size - skb->truesize,
GFP_ATOMIC);
dev_kfree_skb(skb);
if (skb2 == NULL) {
priv->stats.tx_dropped++;
return 0;
}
skb = skb2;
}
}
/* Send to right vcc */
is_rdesc = 0;
dst = lec_h->h_dest;
if (priv->is_trdev) {
dst = get_tr_dst(skb->data + 2, rdesc);
if (dst == NULL) {
dst = rdesc;
is_rdesc = 1;
}
}
entry = NULL;
vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
pr_debug("%s:vcc:%p vcc_flags:%lx, entry:%p\n", dev->name,
vcc, vcc ? vcc->flags : 0, entry);
if (!vcc || !test_bit(ATM_VF_READY, &vcc->flags)) {
if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
pr_debug("%s:lec_start_xmit: queuing packet, ",
pr_debug("MAC address " MAC_FMT "\n",
lec_h->h_dest[0], lec_h->h_dest[1],
lec_h->h_dest[2], lec_h->h_dest[3],
lec_h->h_dest[4], lec_h->h_dest[5]);
skb_queue_tail(&entry->tx_wait, skb);
} else {
("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ",
dev->name);
pr_debug("MAC address " MAC_FMT "\n",
lec_h->h_dest[0], lec_h->h_dest[1],
lec_h->h_dest[2], lec_h->h_dest[3],
lec_h->h_dest[4], lec_h->h_dest[5]);
priv->stats.tx_dropped++;
dev_kfree_skb(skb);
}
goto out;
}
#if DUMP_PACKETS > 0
printk("%s:sending to vpi:%d vci:%d\n", dev->name, vcc->vpi, vcc->vci);
while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
pr_debug("lec.c: emptying tx queue, ");
pr_debug("MAC address " MAC_FMT "\n",
lec_h->h_dest[0], lec_h->h_dest[1],
lec_h->h_dest[2], lec_h->h_dest[3],
lec_h->h_dest[4], lec_h->h_dest[5]);
lec_send(vcc, skb, priv);
if (!atm_may_send(vcc, 0)) {
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
vpriv->xoff = 1;
netif_stop_queue(dev);
/*
* vcc->pop() might have occurred in between, making
* the vcc usuable again. Since xmit is serialized,
* this is the only situation we have to re-test.
*/
if (atm_may_send(vcc, 0))
netif_wake_queue(dev);
}
out:
if (entry)
lec_arp_put(entry);
static int lec_close(struct net_device *dev)
netif_stop_queue(dev);
return 0;
}
/*
* Get the current statistics.
* This may be called with the card open or closed.
*/
static struct net_device_stats *lec_get_stats(struct net_device *dev)
return &((struct lec_priv *)dev->priv)->stats;
static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
struct net_device *dev = (struct net_device *)vcc->proto_data;
struct lec_priv *priv = (struct lec_priv *)dev->priv;
struct atmlec_msg *mesg;
struct lec_arp_table *entry;
int i;
char *tmp; /* FIXME */
atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
mesg = (struct atmlec_msg *)skb->data;
tmp = skb->data;
tmp += sizeof(struct atmlec_msg);
pr_debug("%s: msg from zeppelin:%d\n", dev->name, mesg->type);
switch (mesg->type) {
case l_set_mac_addr:
for (i = 0; i < 6; i++) {
dev->dev_addr[i] = mesg->content.normal.mac_addr[i];
}
break;
case l_del_mac_addr:
for (i = 0; i < 6; i++) {
dev->dev_addr[i] = 0;
}
break;
case l_addr_delete:
lec_addr_delete(priv, mesg->content.normal.atm_addr,
mesg->content.normal.flag);
break;
case l_topology_change:
priv->topology_change = mesg->content.normal.flag;
break;
case l_flush_complete:
lec_flush_complete(priv, mesg->content.normal.flag);
break;
case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */
entry = lec_arp_find(priv, mesg->content.normal.mac_addr);
lec_arp_remove(priv, entry);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
if (mesg->content.normal.no_source_le_narp)
break;
/* FALL THROUGH */
case l_arp_update:
lec_arp_update(priv, mesg->content.normal.mac_addr,
mesg->content.normal.atm_addr,
mesg->content.normal.flag,
mesg->content.normal.targetless_le_arp);
pr_debug("lec: in l_arp_update\n");
if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */
pr_debug("lec: LANE2 3.1.5, got tlvs, size %d\n",
mesg->sizeoftlvs);
lane2_associate_ind(dev, mesg->content.normal.mac_addr,
tmp, mesg->sizeoftlvs);
}
break;
case l_config:
priv->maximum_unknown_frame_count =
mesg->content.config.maximum_unknown_frame_count;
priv->max_unknown_frame_time =
(mesg->content.config.max_unknown_frame_time * HZ);
priv->max_retry_count = mesg->content.config.max_retry_count;
priv->aging_time = (mesg->content.config.aging_time * HZ);
priv->forward_delay_time =
(mesg->content.config.forward_delay_time * HZ);
priv->arp_response_time =
(mesg->content.config.arp_response_time * HZ);
priv->flush_timeout = (mesg->content.config.flush_timeout * HZ);
priv->path_switching_delay =
(mesg->content.config.path_switching_delay * HZ);
priv->lane_version = mesg->content.config.lane_version; /* LANE2 */
priv->lane2_ops = NULL;
if (priv->lane_version > 1)
priv->lane2_ops = &lane2_ops;
if (dev->change_mtu(dev, mesg->content.config.mtu))
printk("%s: change_mtu to %d failed\n", dev->name,
mesg->content.config.mtu);
break;
case l_flush_tran_id:
lec_set_flush_tran_id(priv, mesg->content.normal.atm_addr,
mesg->content.normal.flag);
break;
case l_set_lecid:
priv->lecid =
(unsigned short)(0xffff & mesg->content.normal.flag);
break;
case l_should_bridge:
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
{
struct net_bridge_fdb_entry *f;
("%s: bridge zeppelin asks about " MAC_FMT "\n",
mesg->content.proxy.mac_addr[0],
mesg->content.proxy.mac_addr[1],
mesg->content.proxy.mac_addr[2],
mesg->content.proxy.mac_addr[3],
mesg->content.proxy.mac_addr[4],
mesg->content.proxy.mac_addr[5]);
if (br_fdb_get_hook == NULL || dev->br_port == NULL)
break;
f = br_fdb_get_hook(dev->br_port->br,
mesg->content.proxy.mac_addr);
if (f != NULL && f->dst->dev != dev
&& f->dst->state == BR_STATE_FORWARDING) {
/* hit from bridge table, send LE_ARP_RESPONSE */
struct sk_buff *skb2;
struct sock *sk;
("%s: entry found, responding to zeppelin\n",
dev->name);
skb2 =
alloc_skb(sizeof(struct atmlec_msg),
GFP_ATOMIC);
if (skb2 == NULL) {
br_fdb_put_hook(f);
break;
}
skb2->len = sizeof(struct atmlec_msg);
skb_copy_to_linear_data(skb2, mesg,
sizeof(*mesg));
atm_force_charge(priv->lecd, skb2->truesize);
sk = sk_atm(priv->lecd);
skb_queue_tail(&sk->sk_receive_queue, skb2);
sk->sk_data_ready(sk, skb2->len);
}
if (f != NULL)
br_fdb_put_hook(f);
}
#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
break;
default:
printk("%s: Unknown message type %d\n", dev->name, mesg->type);
dev_kfree_skb(skb);
return -EINVAL;
}
dev_kfree_skb(skb);
return 0;
static void lec_atm_close(struct atm_vcc *vcc)
struct sk_buff *skb;
struct net_device *dev = (struct net_device *)vcc->proto_data;
struct lec_priv *priv = (struct lec_priv *)dev->priv;
priv->lecd = NULL;
/* Do something needful? */
netif_stop_queue(dev);
lec_arp_destroy(priv);
if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
printk("%s lec_atm_close: closing with messages pending\n",
dev->name);
while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue)) != NULL) {
atm_return(vcc, skb->truesize);
module_put(THIS_MODULE);
.close = lec_atm_close,
.send = lec_atm_send
.ops = &lecdev_ops,
.type = "lec",
.number = 999, /* dummy device number */
.lock = __SPIN_LOCK_UNLOCKED(lecatm_dev.lock)
};
/*
* LANE2: new argument struct sk_buff *data contains
* the LE_ARP based TLVs introduced in the LANE2 spec
*/
static int
send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
unsigned char *mac_addr, unsigned char *atm_addr,
struct sk_buff *data)
{
struct sock *sk;
struct sk_buff *skb;
struct atmlec_msg *mesg;
if (!priv || !priv->lecd) {
return -1;
}
skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
if (!skb)
return -1;
skb->len = sizeof(struct atmlec_msg);
mesg = (struct atmlec_msg *)skb->data;
memset(mesg, 0, sizeof(struct atmlec_msg));
if (data != NULL)
mesg->sizeoftlvs = data->len;
if (mac_addr)
memcpy(&mesg->content.normal.mac_addr, mac_addr, ETH_ALEN);
else
mesg->content.normal.targetless_le_arp = 1;
if (atm_addr)
memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
atm_force_charge(priv->lecd, skb->truesize);
sk = sk_atm(priv->lecd);
skb_queue_tail(&sk->sk_receive_queue, skb);
sk->sk_data_ready(sk, skb->len);
pr_debug("lec: about to send %d bytes of data\n", data->len);
atm_force_charge(priv->lecd, data->truesize);
skb_queue_tail(&sk->sk_receive_queue, data);
sk->sk_data_ready(sk, skb->len);
}
}
/* shamelessly stolen from drivers/net/net_init.c */
static int lec_change_mtu(struct net_device *dev, int new_mtu)
{
if ((new_mtu < 68) || (new_mtu > 18190))
return -EINVAL;
dev->mtu = new_mtu;
return 0;
}
static void lec_set_multicast_list(struct net_device *dev)
{
/*
* by default, all multicast frames arrive over the bus.
* eventually support selective multicast service
*/
return;
static void lec_init(struct net_device *dev)
dev->change_mtu = lec_change_mtu;
dev->open = lec_open;
dev->stop = lec_close;
dev->hard_start_xmit = lec_start_xmit;
dev->get_stats = lec_get_stats;
dev->set_multicast_list = lec_set_multicast_list;
dev->do_ioctl = NULL;
printk("%s: Initialized!\n", dev->name);
return;
0xff,
0x00,
0x01,
0x01
};
#define LEC_DATA_DIRECT_8023 2
#define LEC_DATA_DIRECT_8025 3
static int lec_is_data_direct(struct atm_vcc *vcc)
return ((vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8023) ||
(vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8025));
static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
struct net_device *dev = (struct net_device *)vcc->proto_data;
struct lec_priv *priv = (struct lec_priv *)dev->priv;
int i = 0;
char buf[300];
printk("%s: lec_push vcc vpi:%d vci:%d\n", dev->name,
vcc->vpi, vcc->vci);
pr_debug("%s: null skb\n", dev->name);
lec_vcc_close(priv, vcc);
return;
}
printk("%s: rcv datalen:%ld lecid:%4.4x\n", dev->name,
skb->len, priv->lecid);
for (i = 0; i < skb->len && i < 99; i++) {
sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
}
for (i = 0; i < skb->len && i < 30; i++) {
sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
}
if (i == skb->len)
printk("%s\n", buf);
else
printk("%s...\n", buf);
if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) { /* Control frame, to daemon */
pr_debug("%s: To daemon\n", dev->name);
skb_queue_tail(&sk->sk_receive_queue, skb);
sk->sk_data_ready(sk, skb->len);
} else { /* Data frame, queue to protocol handlers */
struct lec_arp_table *entry;
unsigned char *src, *dst;
atm_return(vcc, skb->truesize);
!priv->lecd || !(dev->flags & IFF_UP)) {
/*
* Probably looping back, or if lecd is missing,
* lecd has gone down
*/
pr_debug("Ignoring frame...\n");
dev_kfree_skb(skb);
return;
}
if (priv->is_trdev)
dst = ((struct lecdatahdr_8025 *)skb->data)->h_dest;
else
dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest;
/*
* If this is a Data Direct VCC, and the VCC does not match
* the LE_ARP cache entry, delete the LE_ARP cache entry.
*/
spin_lock_irqsave(&priv->lec_arp_lock, flags);
if (lec_is_data_direct(vcc)) {
#ifdef CONFIG_TR
if (priv->is_trdev)
src =
((struct lecdatahdr_8025 *)skb->data)->
h_source;
src =
((struct lecdatahdr_8023 *)skb->data)->
h_source;
entry = lec_arp_find(priv, src);
if (entry && entry->vcc != vcc) {
lec_arp_remove(priv, entry);
lec_arp_put(entry);
}
}
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
if (!(dst[0] & 0x01) && /* Never filter Multi/Broadcast */
!priv->is_proxy && /* Proxy wants all the packets */
dev_kfree_skb(skb);
return;
}
if (!hlist_empty(&priv->lec_arp_empty_ones)) {
lec_arp_check_empties(priv, vcc, skb);
}
skb_pull(skb, 2); /* skip lec_id */
if (priv->is_trdev)
skb->protocol = tr_type_trans(skb, dev);
else
skb->protocol = eth_type_trans(skb, dev);
priv->stats.rx_packets++;
priv->stats.rx_bytes += skb->len;
memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
netif_rx(skb);
}
static void lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
{
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
struct net_device *dev = skb->dev;
if (vpriv == NULL) {
printk("lec_pop(): vpriv = NULL!?!?!?\n");
return;
}
vpriv->old_pop(vcc, skb);
if (vpriv->xoff && atm_may_send(vcc, 0)) {
vpriv->xoff = 0;
if (netif_running(dev) && netif_queue_stopped(dev))
netif_wake_queue(dev);
}
}
static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
int bytes_left;
struct atmlec_ioc ioc_data;
/* Lecd must be up in this case */
bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
if (bytes_left != 0) {
printk
("lec: lec_vcc_attach, copy from user failed for %d bytes\n",
bytes_left);
}
if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF ||
!dev_lec[ioc_data.dev_num])
return -EINVAL;
if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL)))
return -ENOMEM;
vpriv->xoff = 0;
vpriv->old_pop = vcc->pop;
vcc->user_back = vpriv;
vcc->pop = lec_pop;
lec_vcc_added(dev_lec[ioc_data.dev_num]->priv,
&ioc_data, vcc, vcc->push);
vcc->proto_data = dev_lec[ioc_data.dev_num];
vcc->push = lec_push;
return 0;
static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
if (arg < 0 || arg >= MAX_LEC_ITF || !dev_lec[arg])
return -EINVAL;
vcc->proto_data = dev_lec[arg];
return (lec_mcast_make((struct lec_priv *)dev_lec[arg]->priv, vcc));
static int lecd_attach(struct atm_vcc *vcc, int arg)
{
int i;
struct lec_priv *priv;
if (arg < 0)
i = 0;
else
i = arg;
if (arg >= MAX_LEC_ITF)
return -EINVAL;
#else /* Reserve the top NUM_TR_DEVS for TR */
if (arg >= (MAX_LEC_ITF - NUM_TR_DEVS))
return -EINVAL;
if (!dev_lec[i]) {
int is_trdev, size;
is_trdev = 0;
if (i >= (MAX_LEC_ITF - NUM_TR_DEVS))
is_trdev = 1;
size = sizeof(struct lec_priv);
if (is_trdev)
dev_lec[i] = alloc_trdev(size);
else
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
dev_lec[i] = alloc_etherdev(size);
if (!dev_lec[i])
return -ENOMEM;
snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
if (register_netdev(dev_lec[i])) {
free_netdev(dev_lec[i]);
return -EINVAL;
}
priv = dev_lec[i]->priv;
priv->is_trdev = is_trdev;
lec_init(dev_lec[i]);
} else {
priv = dev_lec[i]->priv;
if (priv->lecd)
return -EADDRINUSE;
}
lec_arp_init(priv);
priv->itfnum = i; /* LANE2 addition */
priv->lecd = vcc;
vcc->dev = &lecatm_dev;
vcc_insert_socket(sk_atm(vcc));
vcc->proto_data = dev_lec[i];
set_bit(ATM_VF_META, &vcc->flags);
set_bit(ATM_VF_READY, &vcc->flags);
/* Set default values to these variables */
priv->maximum_unknown_frame_count = 1;
priv->max_unknown_frame_time = (1 * HZ);
priv->vcc_timeout_period = (1200 * HZ);
priv->max_retry_count = 1;
priv->aging_time = (300 * HZ);
priv->forward_delay_time = (15 * HZ);
priv->topology_change = 0;
priv->arp_response_time = (1 * HZ);
priv->flush_timeout = (4 * HZ);
priv->path_switching_delay = (6 * HZ);
if (dev_lec[i]->flags & IFF_UP) {
netif_start_queue(dev_lec[i]);
}
__module_get(THIS_MODULE);
return i;
static char *lec_arp_get_status_string(unsigned char status)
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
{
static char *lec_arp_status_string[] = {
"ESI_UNKNOWN ",
"ESI_ARP_PENDING ",
"ESI_VC_PENDING ",
"<Undefined> ",
"ESI_FLUSH_PENDING ",
"ESI_FORWARD_DIRECT"
};
if (status > ESI_FORWARD_DIRECT)
status = 3; /* ESI_UNDEFINED */
return lec_arp_status_string[status];
}
static void lec_info(struct seq_file *seq, struct lec_arp_table *entry)
{
int i;
for (i = 0; i < ETH_ALEN; i++)
seq_printf(seq, "%2.2x", entry->mac_addr[i] & 0xff);
seq_printf(seq, " ");
for (i = 0; i < ATM_ESA_LEN; i++)
seq_printf(seq, "%2.2x", entry->atm_addr[i] & 0xff);
seq_printf(seq, " %s %4.4x", lec_arp_get_status_string(entry->status),
entry->flags & 0xffff);
if (entry->vcc)
seq_printf(seq, "%3d %3d ", entry->vcc->vpi, entry->vcc->vci);
else
seq_printf(seq, " ");