Newer
Older
del_timer(&entry->timer);
tmp = lec_arp_find(priv, mac_addr);
if (tmp) {
del_timer(&tmp->timer);
tmp->status = ESI_FORWARD_DIRECT;
memcpy(tmp->atm_addr, atm_addr, ATM_ESA_LEN);
tmp->vcc = entry->vcc;
tmp->old_push = entry->old_push;
tmp->last_used = jiffies;
del_timer(&entry->timer);
lec_arp_put(entry);
entry = tmp;
} else {
entry->status = ESI_FORWARD_DIRECT;
memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
entry->last_used = jiffies;
lec_arp_add(priv, entry);
}
if (remoteflag)
entry->flags |= LEC_REMOTE_FLAG;
else
entry->flags &= ~LEC_REMOTE_FLAG;
pr_debug("After update\n");
dump_arp_table(priv);
goto out;
}
}
}
entry = lec_arp_find(priv, mac_addr);
if (!entry) {
entry = make_entry(priv, mac_addr);
if (!entry)
goto out;
entry->status = ESI_UNKNOWN;
lec_arp_add(priv, entry);
/* Temporary, changes before end of function */
}
memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
del_timer(&entry->timer);
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
hlist_for_each_entry(tmp, node,
&priv->lec_arp_tables[i], next) {
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
if (entry != tmp &&
!memcmp(tmp->atm_addr, atm_addr, ATM_ESA_LEN)) {
/* Vcc to this host exists */
if (tmp->status > ESI_VC_PENDING) {
/*
* ESI_FLUSH_PENDING,
* ESI_FORWARD_DIRECT
*/
entry->vcc = tmp->vcc;
entry->old_push = tmp->old_push;
}
entry->status = tmp->status;
break;
}
}
}
if (remoteflag)
entry->flags |= LEC_REMOTE_FLAG;
else
entry->flags &= ~LEC_REMOTE_FLAG;
if (entry->status == ESI_ARP_PENDING || entry->status == ESI_UNKNOWN) {
entry->status = ESI_VC_PENDING;
send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL);
pr_debug("After update2\n");
dump_arp_table(priv);
out:
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
}
/*
lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data,
struct atm_vcc *vcc,
void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb))
struct lec_arp_table *entry;
int i, found_entry = 0;
/* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
if (ioc_data->receive == 2) {
pr_debug("LEC_ARP: Attaching mcast forward\n");
entry = lec_arp_find(priv, bus_mac);
if (!entry) {
pr_info("LEC_ARP: Multicast entry not found!\n");
}
memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
entry->recv_vcc = vcc;
entry->old_recv_push = old_push;
entry = make_entry(priv, bus_mac);
if (entry == NULL)
del_timer(&entry->timer);
memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
entry->recv_vcc = vcc;
entry->old_recv_push = old_push;
hlist_add_head(&entry->next, &priv->mcast_fwds);
goto out;
} else if (ioc_data->receive == 1) {
/*
* Vcc which we don't want to make default vcc,
* attach it anyway.
*/
pr_debug("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",
ioc_data->atm_addr[0], ioc_data->atm_addr[1],
ioc_data->atm_addr[2], ioc_data->atm_addr[3],
ioc_data->atm_addr[4], ioc_data->atm_addr[5],
ioc_data->atm_addr[6], ioc_data->atm_addr[7],
ioc_data->atm_addr[8], ioc_data->atm_addr[9],
ioc_data->atm_addr[10], ioc_data->atm_addr[11],
ioc_data->atm_addr[12], ioc_data->atm_addr[13],
ioc_data->atm_addr[14], ioc_data->atm_addr[15],
ioc_data->atm_addr[16], ioc_data->atm_addr[17],
ioc_data->atm_addr[18], ioc_data->atm_addr[19]);
entry = make_entry(priv, bus_mac);
if (entry == NULL)
memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
memset(entry->mac_addr, 0, ETH_ALEN);
entry->recv_vcc = vcc;
entry->old_recv_push = old_push;
entry->status = ESI_UNKNOWN;
entry->timer.expires = jiffies + priv->vcc_timeout_period;
entry->timer.function = lec_arp_expire_vcc;
hlist_add_head(&entry->next, &priv->lec_no_forward);
add_timer(&entry->timer);
pr_debug("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",
ioc_data->atm_addr[0], ioc_data->atm_addr[1],
ioc_data->atm_addr[2], ioc_data->atm_addr[3],
ioc_data->atm_addr[4], ioc_data->atm_addr[5],
ioc_data->atm_addr[6], ioc_data->atm_addr[7],
ioc_data->atm_addr[8], ioc_data->atm_addr[9],
ioc_data->atm_addr[10], ioc_data->atm_addr[11],
ioc_data->atm_addr[12], ioc_data->atm_addr[13],
ioc_data->atm_addr[14], ioc_data->atm_addr[15],
ioc_data->atm_addr[16], ioc_data->atm_addr[17],
ioc_data->atm_addr[18], ioc_data->atm_addr[19]);
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
hlist_for_each_entry(entry, node,
&priv->lec_arp_tables[i], next) {
if (memcmp
(ioc_data->atm_addr, entry->atm_addr,
ATM_ESA_LEN) == 0) {
pr_debug("LEC_ARP: Attaching data direct\n");
pr_debug("Currently -> Vcc: %d, Rvcc:%d\n",
entry->vcc ? entry->vcc->vci : 0,
entry->recv_vcc ? entry->recv_vcc->
vci : 0);
found_entry = 1;
del_timer(&entry->timer);
entry->vcc = vcc;
entry->old_push = old_push;
if (entry->status == ESI_VC_PENDING) {
if (priv->maximum_unknown_frame_count
== 0)
entry->status =
ESI_FORWARD_DIRECT;
else {
entry->timestamp = jiffies;
entry->status =
ESI_FLUSH_PENDING;
send_to_lecd(priv, l_flush_xmt,
NULL,
entry->atm_addr,
NULL);
}
} else {
/*
* They were forming a connection
* to us, and we to them. Our
* ATM address is numerically lower
* than theirs, so we make connection
* we formed into default VCC (8.1.11).
* Connection they made gets torn
* down. This might confuse some
* clients. Can be changed if
* someone reports trouble...
*/
;
}
}
}
}
if (found_entry) {
pr_debug("After vcc was added\n");
dump_arp_table(priv);
}
/*
* Not found, snatch address from first data packet that arrives
* from this vcc
*/
entry = make_entry(priv, bus_mac);
if (!entry)
entry->vcc = vcc;
entry->old_push = old_push;
memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
memset(entry->mac_addr, 0, ETH_ALEN);
entry->status = ESI_UNKNOWN;
hlist_add_head(&entry->next, &priv->lec_arp_empty_ones);
entry->timer.expires = jiffies + priv->vcc_timeout_period;
entry->timer.function = lec_arp_expire_vcc;
add_timer(&entry->timer);
pr_debug("After vcc was added\n");
dump_arp_table(priv);
out:
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
}
static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
struct lec_arp_table *entry;
int i;
restart:
spin_lock_irqsave(&priv->lec_arp_lock, flags);
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
hlist_for_each_entry(entry, node,
&priv->lec_arp_tables[i], next) {
if (entry->flush_tran_id == tran_id &&
entry->status == ESI_FLUSH_PENDING) {
struct sk_buff *skb;
struct atm_vcc *vcc = entry->vcc;
lec_arp_hold(entry);
spin_unlock_irqrestore(&priv->lec_arp_lock,
flags);
while ((skb = skb_dequeue(&entry->tx_wait)))
entry->last_used = jiffies;
entry->status = ESI_FORWARD_DIRECT;
lec_arp_put(entry);
pr_debug("LEC_ARP: Flushed\n");
goto restart;
}
}
}
dump_arp_table(priv);
}
static void
lec_set_flush_tran_id(struct lec_priv *priv,
const unsigned char *atm_addr, unsigned long tran_id)
struct lec_arp_table *entry;
int i;
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
hlist_for_each_entry(entry, node,
&priv->lec_arp_tables[i], next) {
if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {
entry->flush_tran_id = tran_id;
pr_debug("Set flush transaction id to %lx for %p\n",
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
}
static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
unsigned char mac_addr[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
struct lec_arp_table *to_add;
vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL);
if (!vpriv)
return -ENOMEM;
vpriv->xoff = 0;
vpriv->old_pop = vcc->pop;
vcc->user_back = vpriv;
vcc->pop = lec_pop;
to_add = make_entry(priv, mac_addr);
if (!to_add) {
err = -ENOMEM;
}
memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN);
to_add->status = ESI_FORWARD_DIRECT;
to_add->flags |= LEC_PERMANENT_FLAG;
to_add->vcc = vcc;
to_add->old_push = vcc->push;
vcc->push = lec_push;
priv->mcast_vcc = vcc;
lec_arp_add(priv, to_add);
out:
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
return err;
static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
struct hlist_node *node, *next;
struct lec_arp_table *entry;
pr_debug("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n", vcc->vpi, vcc->vci);
dump_arp_table(priv);
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
hlist_for_each_entry_safe(entry, node, next,
&priv->lec_arp_tables[i], next) {
if (vcc == entry->vcc) {
lec_arp_remove(priv, entry);
lec_arp_put(entry);
priv->mcast_vcc = NULL;
}
}
}
hlist_for_each_entry_safe(entry, node, next,
&priv->lec_arp_empty_ones, next) {
lec_arp_clear_vccs(entry);
del_timer(&entry->timer);
lec_arp_put(entry);
}
}
hlist_for_each_entry_safe(entry, node, next,
&priv->lec_no_forward, next) {
if (entry->recv_vcc == vcc) {
lec_arp_clear_vccs(entry);
del_timer(&entry->timer);
lec_arp_put(entry);
}
}
hlist_for_each_entry_safe(entry, node, next, &priv->mcast_fwds, next) {
if (entry->recv_vcc == vcc) {
lec_arp_clear_vccs(entry);
/* No timer, LANEv2 7.1.20 and 2.3.5.3 */
lec_arp_put(entry);
}
}
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
dump_arp_table(priv);
}
static void
lec_arp_check_empties(struct lec_priv *priv,
struct atm_vcc *vcc, struct sk_buff *skb)
unsigned long flags;
struct hlist_node *node, *next;
struct lec_arp_table *entry, *tmp;
struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
unsigned char *src;
struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
if (priv->is_trdev)
src = tr_hdr->h_source;
else
src = hdr->h_source;
hlist_for_each_entry_safe(entry, node, next,
&priv->lec_arp_empty_ones, next) {
if (vcc == entry->vcc) {
del_timer(&entry->timer);
memcpy(entry->mac_addr, src, ETH_ALEN);
entry->status = ESI_FORWARD_DIRECT;
entry->last_used = jiffies;
/* We might have got an entry */
tmp = lec_arp_find(priv, src);
if (tmp) {
lec_arp_put(tmp);
}
hlist_del(&entry->next);
lec_arp_add(priv, entry);
goto out;
}
}
pr_debug("LEC_ARP: Arp_check_empties: entry not found!\n");
out:
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
}