Commit bf603625 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
  [ATM]: [lec] use refcnt to protect lec_arp_entries outside lock
  [ATM]: [lec] add reference counting to lec_arp entries
  [ATM]: [lec] use work queue instead of timer for lec arp expiry
  [ATM]: [lec] old_close is no longer used
  [ATM]: [lec] convert lec_arp_table to hlist
  [ATM]: [lec] header indent, comment and whitespace cleanup
  [ATM]: [lec] indent, comment and whitespace cleanup [continued]
  [ATM]: [lec] indent, comment and whitespace cleanup
  [SCTP]: Do not timestamp every SCTP packet.
  [SCTP]: Use correct mask when disabling PMTUD.
  [SCTP]: Include sk_buff overhead while updating the peer's receive window.
  [SCTP]: Enable Nagle algorithm by default.
  [BNX2]: Disable MSI on 5706 if AMD 8132 bridge is present.
  [NetLabel]: audit fixups due to delayed feedback
parents fbe96f92 6656e3c4
......@@ -56,8 +56,8 @@
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "1.4.44"
#define DRV_MODULE_RELDATE "August 10, 2006"
#define DRV_MODULE_VERSION "1.4.45"
#define DRV_MODULE_RELDATE "September 29, 2006"
#define RUN_AT(x) (jiffies + (x))
......@@ -5805,6 +5805,34 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->cmd_ticks_int = bp->cmd_ticks;
}
/* Disable MSI on 5706 if AMD 8132 bridge is found.
*
* MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
* with byte enables disabled on the unused 32-bit word. This is legal
* but causes problems on the AMD 8132 which will eventually stop
* responding after a while.
*
* AMD believes this incompatibility is unique to the 5706, and
* prefers to locally disable MSI rather than globally disabling it
* using pci_msi_quirk.
*/
if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
struct pci_dev *amd_8132 = NULL;
while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_8132_BRIDGE,
amd_8132))) {
u8 rev;
pci_read_config_byte(amd_8132, PCI_REVISION_ID, &rev);
if (rev >= 0x10 && rev <= 0x13) {
disable_msi = 1;
pci_dev_put(amd_8132);
break;
}
}
}
bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
bp->req_line_speed = 0;
if (bp->phy_flags & PHY_SERDES_FLAG) {
......
/*
* ATM Lan Emulation Daemon driver interface
*
* ATM Lan Emulation Daemon vs. driver interface
*
* mkiiskila@yahoo.com
*
* Marko Kiiskila <mkiiskila@yahoo.com>
*/
#ifndef _ATMLEC_H_
......@@ -13,28 +11,35 @@
#include <linux/atmioc.h>
#include <linux/atm.h>
#include <linux/if_ether.h>
/* ATM lec daemon control socket */
#define ATMLEC_CTRL _IO('a',ATMIOC_LANE)
#define ATMLEC_DATA _IO('a',ATMIOC_LANE+1)
#define ATMLEC_MCAST _IO('a',ATMIOC_LANE+2)
#define ATMLEC_CTRL _IO('a', ATMIOC_LANE)
#define ATMLEC_DATA _IO('a', ATMIOC_LANE+1)
#define ATMLEC_MCAST _IO('a', ATMIOC_LANE+2)
/* Maximum number of LEC interfaces (tweakable) */
#define MAX_LEC_ITF 48
/* From the total of MAX_LEC_ITF, last NUM_TR_DEVS are reserved for Token Ring.
/*
* From the total of MAX_LEC_ITF, last NUM_TR_DEVS are reserved for Token Ring.
* E.g. if MAX_LEC_ITF = 48 and NUM_TR_DEVS = 8, then lec0-lec39 are for
* Ethernet ELANs and lec40-lec47 are for Token Ring ELANS.
*/
#define NUM_TR_DEVS 8
typedef enum {
l_set_mac_addr, l_del_mac_addr,
l_set_mac_addr,
l_del_mac_addr,
l_svc_setup,
l_addr_delete, l_topology_change,
l_flush_complete, l_arp_update,
l_addr_delete,
l_topology_change,
l_flush_complete,
l_arp_update,
l_narp_req, /* LANE2 mandates the use of this */
l_config, l_flush_tran_id,
l_set_lecid, l_arp_xmt,
l_config,
l_flush_tran_id,
l_set_lecid,
l_arp_xmt,
l_rdesc_arp_xmt,
l_associate_req,
l_should_bridge /* should we bridge this MAC? */
......@@ -63,9 +68,11 @@ struct atmlec_msg {
struct {
unsigned char mac_addr[ETH_ALEN];
unsigned char atm_addr[ATM_ESA_LEN];
unsigned int flag;/* Topology_change flag,
remoteflag, permanent flag,
lecid, transaction id */
unsigned int flag; /*
* Topology_change flag,
* remoteflag, permanent flag,
* lecid, transaction id
*/
unsigned int targetless_le_arp; /* LANE2 */
unsigned int no_source_le_narp; /* LANE2 */
} normal;
......@@ -75,9 +82,11 @@ struct atmlec_msg {
uint32_t tran_id; /* transaction id */
unsigned char mac_addr[ETH_ALEN]; /* dst mac addr */
unsigned char atm_addr[ATM_ESA_LEN]; /* reqestor ATM addr */
} proxy;
/* For mapping LE_ARP requests to responses. Filled by */
} content; /* zeppelin, returned by kernel. Used only when proxying */
} proxy; /*
* For mapping LE_ARP requests to responses. Filled by
* zeppelin, returned by kernel. Used only when proxying
*/
} content;
} __ATM_API_ALIGN;
struct atmlec_ioc {
......
......@@ -95,12 +95,11 @@
#define AUDIT_MAC_POLICY_LOAD 1403 /* Policy file load */
#define AUDIT_MAC_STATUS 1404 /* Changed enforcing,permissive,off */
#define AUDIT_MAC_CONFIG_CHANGE 1405 /* Changes to booleans */
#define AUDIT_MAC_UNLBL_ACCEPT 1406 /* NetLabel: allow unlabeled traffic */
#define AUDIT_MAC_UNLBL_DENY 1407 /* NetLabel: deny unlabeled traffic */
#define AUDIT_MAC_CIPSOV4_ADD 1408 /* NetLabel: add CIPSOv4 DOI entry */
#define AUDIT_MAC_CIPSOV4_DEL 1409 /* NetLabel: del CIPSOv4 DOI entry */
#define AUDIT_MAC_MAP_ADD 1410 /* NetLabel: add LSM domain mapping */
#define AUDIT_MAC_MAP_DEL 1411 /* NetLabel: del LSM domain mapping */
#define AUDIT_MAC_UNLBL_ALLOW 1406 /* NetLabel: allow unlabeled traffic */
#define AUDIT_MAC_CIPSOV4_ADD 1407 /* NetLabel: add CIPSOv4 DOI entry */
#define AUDIT_MAC_CIPSOV4_DEL 1408 /* NetLabel: del CIPSOv4 DOI entry */
#define AUDIT_MAC_MAP_ADD 1409 /* NetLabel: add LSM domain mapping */
#define AUDIT_MAC_MAP_DEL 1410 /* NetLabel: del LSM domain mapping */
#define AUDIT_FIRST_KERN_ANOM_MSG 1700
#define AUDIT_LAST_KERN_ANOM_MSG 1799
......
......@@ -507,6 +507,7 @@
#define PCI_DEVICE_ID_AMD_8151_0 0x7454
#define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450
#define PCI_DEVICE_ID_AMD_8131_APIC 0x7451
#define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458
#define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090
#define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091
#define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093
......
......@@ -129,7 +129,7 @@ extern int cipso_v4_rbm_strictvalid;
#ifdef CONFIG_NETLABEL
int cipso_v4_doi_add(struct cipso_v4_doi *doi_def);
int cipso_v4_doi_remove(u32 doi,
u32 audit_secid,
struct netlbl_audit *audit_info,
void (*callback) (struct rcu_head * head));
struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi);
int cipso_v4_doi_walk(u32 *skip_cnt,
......@@ -145,7 +145,7 @@ static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
}
static inline int cipso_v4_doi_remove(u32 doi,
u32 audit_secid,
struct netlbl_audit *audit_info,
void (*callback) (struct rcu_head * head))
{
return 0;
......
......@@ -92,11 +92,17 @@
*
*/
/* NetLabel audit information */
struct netlbl_audit {
u32 secid;
uid_t loginuid;
};
/* Domain mapping definition struct */
struct netlbl_dom_map;
/* Domain mapping operations */
int netlbl_domhsh_remove(const char *domain, u32 audit_secid);
int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
/* LSM security attributes */
struct netlbl_lsm_cache {
......
/*
* lec.c: Lan Emulation driver
* Marko Kiiskila mkiiskila@yahoo.com
*
* Marko Kiiskila <mkiiskila@yahoo.com>
*/
#include <linux/kernel.h>
......@@ -38,7 +38,7 @@
#include <linux/if_bridge.h>
#include "../bridge/br_private.h"
static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
#endif
/* Modular too */
......@@ -55,29 +55,32 @@ static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
#define DPRINTK(format,args...)
#endif
#define DUMP_PACKETS 0 /* 0 = None,
#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 */
#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,
static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
unsigned char *mac_addr);
static int lec_arp_remove(struct lec_priv *priv,
struct lec_arp_table *to_remove);
/* LANE2 functions */
static void lane2_associate_ind (struct net_device *dev, u8 *mac_address,
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,
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,
......@@ -86,7 +89,7 @@ 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,
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);
......@@ -100,16 +103,30 @@ static void lec_set_flush_tran_id(struct lec_priv *priv,
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));
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);
}
static struct lane2_ops lane2_ops = {
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};
static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
/* Device structures */
static struct net_device *dev_lec[MAX_LEC_ITF];
......@@ -121,9 +138,11 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
char *buff;
struct lec_priv *priv;
/* Check if this is a BPDU. If so, ask zeppelin to send
/*
* 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 */
* 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) {
......@@ -132,7 +151,8 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
struct atmlec_msg *mesg;
skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
if (skb2 == NULL) return;
if (skb2 == NULL)
return;
skb2->len = sizeof(struct atmlec_msg);
mesg = (struct atmlec_msg *)skb2->data;
mesg->type = l_topology_change;
......@@ -166,26 +186,25 @@ static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
int riflen, num_rdsc;
trh = (struct trh_hdr *)packet;
if (trh->daddr[0] & (uint8_t)0x80)
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
} 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;
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(uint16_t));
if (trh->rcf & htons((uint16_t) TR_RCF_DIR_BIT))
memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(uint16_t));
else {
memcpy(&rdesc[4], &trh->rseg[1], sizeof(uint16_t));
rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0));
......@@ -204,13 +223,12 @@ static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
* there is non-reboot way to recover if something goes wrong.
*/
static int
lec_open(struct net_device *dev)
static int lec_open(struct net_device *dev)
{
struct lec_priv *priv = (struct lec_priv *)dev->priv;
netif_start_queue(dev);
memset(&priv->stats,0,sizeof(struct net_device_stats));
memset(&priv->stats, 0, sizeof(struct net_device_stats));
return 0;
}
......@@ -231,16 +249,14 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv)
priv->stats.tx_bytes += skb->len;
}
static void
lec_tx_timeout(struct net_device *dev)
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)
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;
......@@ -255,12 +271,12 @@ lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
int is_rdesc;
#if DUMP_PACKETS > 0
char buf[300];
int i=0;
int i = 0;
#endif /* DUMP_PACKETS >0 */
DPRINTK("lec_start_xmit called\n");
if (!priv->lecd) {
printk("%s:No lecd attached\n",dev->name);
printk("%s:No lecd attached\n", dev->name);
priv->stats.tx_errors++;
netif_stop_queue(dev);
return -EUNATCH;
......@@ -280,22 +296,26 @@ lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
DPRINTK("lec_start_xmit: reallocating skb\n");
skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
kfree_skb(skb);
if (skb2 == NULL) return 0;
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 = (struct lecdatahdr_8023 *)skb->data;
lec_h->le_header = htons(priv->lecid);
#ifdef CONFIG_TR
/* Ugly. Use this to realign Token Ring packets for
* e.g. PCA-200E driver. */
/*
* 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;
if (skb2 == NULL)
return 0;
skb = skb2;
}
#endif
......@@ -304,18 +324,18 @@ lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name,
skb->len, priv->lecid);
#if DUMP_PACKETS >= 2
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 < 99; i++) {
sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
}
#elif DUMP_PACKETS >= 1
for(i=0;i<skb->len && i < 30;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]);
}
#endif /* DUMP_PACKETS >= 1 */
if (i==skb->len)
printk("%s\n",buf);
if (i == skb->len)
printk("%s\n", buf);
else
printk("%s...\n",buf);
printk("%s...\n", buf);
#endif /* DUMP_PACKETS > 0 */
/* Minimum ethernet-frame size */
......@@ -328,7 +348,8 @@ lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
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);
min_frame_size - skb->truesize,
GFP_ATOMIC);
dev_kfree_skb(skb);
if (skb2 == NULL) {
priv->stats.tx_dropped++;
......@@ -344,7 +365,7 @@ lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
dst = lec_h->h_dest;
#ifdef CONFIG_TR
if (priv->is_trdev) {
dst = get_tr_dst(skb->data+2, rdesc);
dst = get_tr_dst(skb->data + 2, rdesc);
if (dst == NULL) {
dst = rdesc;
is_rdesc = 1;
......@@ -354,28 +375,31 @@ lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
entry = NULL;
vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
DPRINTK("%s:vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
vcc, vcc?vcc->flags:0, entry);
if (!vcc || !test_bit(ATM_VF_READY,&vcc->flags)) {
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)) {
DPRINTK("%s:lec_start_xmit: queuing packet, ", dev->name);
DPRINTK("%s:lec_start_xmit: queuing packet, ",
dev->name);
DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\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_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 {
DPRINTK("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ", dev->name);
DPRINTK
("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ",
dev->name);
DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\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_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);
}
return 0;
goto out;
}
#if DUMP_PACKETS > 0
printk("%s:sending to vpi:%d vci:%d\n", dev->name,
vcc->vpi, vcc->vci);
printk("%s:sending to vpi:%d vci:%d\n", dev->name, vcc->vpi, vcc->vci);
#endif /* DUMP_PACKETS > 0 */
while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
......@@ -404,13 +428,15 @@ lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_wake_queue(dev);
}
out:
if (entry)
lec_arp_put(entry);
dev->trans_start = jiffies;
return 0;
}
/* The inverse routine to net_open(). */
static int
lec_close(struct net_device *dev)
static int lec_close(struct net_device *dev)
{
netif_stop_queue(dev);
return 0;
......@@ -420,18 +446,16 @@ lec_close(struct net_device *dev)
* 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)
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)
static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
unsigned long flags;
struct net_device *dev = (struct net_device*)vcc->proto_data;
struct lec_priv *priv = (struct lec_priv*)dev->priv;
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;
......@@ -442,14 +466,14 @@ lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
tmp = skb->data;
tmp += sizeof(struct atmlec_msg);
DPRINTK("%s: msg from zeppelin:%d\n", dev->name, mesg->type);
switch(mesg->type) {
switch (mesg->type) {
case l_set_mac_addr:
for (i=0;i<6;i++) {
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++) {
for (i = 0; i < 6; i++) {
dev->dev_addr[i] = 0;
}
break;
......@@ -479,9 +503,9 @@ lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
mesg->content.normal.targetless_le_arp);
DPRINTK("lec: in l_arp_update\n");
if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */
DPRINTK("lec: LANE2 3.1.5, got tlvs, size %d\n", mesg->sizeoftlvs);
lane2_associate_ind(dev,
mesg->content.normal.mac_addr,
DPRINTK("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;
......@@ -489,17 +513,16 @@ lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
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);
(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);
(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);
(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);
(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)
......@@ -514,45 +537,56 @@ lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
mesg->content.normal.flag);
break;
case l_set_lecid:
priv->lecid=(unsigned short)(0xffff&mesg->content.normal.flag);
priv->lecid =
(unsigned short)(0xffff & mesg->content.normal.flag);
break;
case l_should_bridge: {
case l_should_bridge:
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
{
struct net_bridge_fdb_entry *f;
DPRINTK("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
dev->name,
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]);
DPRINTK
("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
dev->name, 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) {
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;
DPRINTK("%s: entry found, responding to zeppelin\n", dev->name);
skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
DPRINTK
("%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);
memcpy(skb2->data, mesg, sizeof(struct atmlec_msg));
memcpy(skb2->data, mesg,
sizeof(struct atmlec_msg));
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) */
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);
......@@ -563,8 +597,7 @@ lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
return 0;
}
static void
lec_atm_close(struct atm_vcc *vcc)
static void lec_atm_close(struct atm_vcc *vcc)
{
struct sk_buff *skb;
struct net_device *dev = (struct net_device *)vcc->proto_data;
......@@ -658,14 +691,14 @@ static int lec_change_mtu(struct net_device *dev, int new_mtu)
static void lec_set_multicast_list(struct net_device *dev)
{
/* by default, all multicast frames arrive over the bus.
/*
* by default, all multicast frames arrive over the bus.
* eventually support selective multicast service
*/
return;
}
static void
lec_init(struct net_device *dev)
static void lec_init(struct net_device *dev)
{
dev->change_mtu = lec_change_mtu;
dev->open = lec_open;
......@@ -676,7 +709,7 @@ lec_init(struct net_device *dev)
dev->get_stats = lec_get_stats;
dev->set_multicast_list = lec_set_multicast_list;
dev->do_ioctl = NULL;
printk("%s: Initialized!\n",dev->name);
printk("%s: Initialized!\n", dev->name);
return;
}
......@@ -684,7 +717,8 @@ static unsigned char lec_ctrl_magic[] = {
0xff,
0x00,
0x01,
0x01 };
0x01
};
#define LEC_DATA_DIRECT_8023 2
#define LEC_DATA_DIRECT_8025 3
......@@ -695,22 +729,21 @@ static int lec_is_data_direct(struct atm_vcc *vcc)
(vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8025));
}
static void
lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
{
unsigned long flags;
struct net_device *dev = (struct net_device *)vcc->proto_data;
struct lec_priv *priv = (struct lec_priv *)dev->priv;
#if DUMP_PACKETS >0
int i=0;
int i = 0;
char buf[300];
printk("%s: lec_push vcc vpi:%d vci:%d\n", dev->name,
vcc->vpi, vcc->vci);
#endif
if (!skb) {
DPRINTK("%s: null skb\n",dev->name);
DPRINTK("%s: null skb\n", dev->name);
lec_vcc_close(priv, vcc);
return;
}
......@@ -718,78 +751,85 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
printk("%s: rcv datalen:%ld lecid:%4.4x\n", dev->name,
skb->len, priv->lecid);
#if DUMP_PACKETS >= 2
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 < 99; i++) {
sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
}
#elif DUMP_PACKETS >= 1
for(i=0;i<skb->len && i < 30;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]);
}
#endif /* DUMP_PACKETS >= 1 */
if (i==skb->len)
printk("%s\n",buf);
if (i == skb->len)
printk("%s\n", buf);
else
printk("%s...\n",buf);
printk("%s...\n", buf);
#endif /* DUMP_PACKETS > 0 */
if (memcmp(skb->data, lec_ctrl_magic, 4) ==0) { /* Control frame, to daemon*/
if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) { /* Control frame, to daemon */
struct sock *sk = sk_atm(vcc);
DPRINTK("%s: To daemon\n",dev->name);
DPRINTK("%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);
if (*(uint16_t *)skb->data == htons(priv->lecid) ||
!priv->lecd ||
!(dev->flags & IFF_UP)) {
/* Probably looping back, or if lecd is missing,
lecd has gone down */
atm_return(vcc, skb->truesize);
if (*(uint16_t *) skb->data == htons(priv->lecid) ||
!priv->lecd || !(dev->flags & IFF_UP)) {
/*
* Probably looping back, or if lecd is missing,
* lecd has gone down
*/
DPRINTK("Ignoring frame...\n");
dev_kfree_skb(skb);
return;
}
#ifdef CONFIG_TR
if (priv->is_trdev)
dst = ((struct lecdatahdr_8025 *) skb->data)->h_dest;
dst = ((struct lecdatahdr_8025 *)skb->data)->h_dest;
else
#endif
dst = ((struct lecdatahdr_8023 *) skb->data)->h_dest;
dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest;
/* If this is a Data Direct VCC, and the VCC does not match
/*
* 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_8025 *)skb->data)->
h_source;
else
#endif
src = ((struct lecdatahdr_8023 *) 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);
kfree(entry);
lec_arp_put(entry);
}
}
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
if (!(dst[0]&0x01) && /* Never filter Multi/Broadcast */
if (!(dst[0] & 0x01) && /* Never filter Multi/Broadcast */
!priv->is_proxy && /* Proxy wants all the packets */
memcmp(dst, dev->dev_addr, dev->addr_len)) {
dev_kfree_skb(skb);
return;
}
if (priv->lec_arp_empty_ones) {
if (!hlist_empty(&priv->lec_arp_empty_ones)) {
lec_arp_check_empties(priv, vcc, skb);
}
skb->dev = dev;
skb_pull(skb, 2); /* skip lec_id */
#ifdef CONFIG_TR
if (priv->is_trdev) skb->protocol = tr_type_trans(skb, dev);
if (priv->is_trdev)
skb->protocol = tr_type_trans(skb, dev);
else
#endif
skb->protocol = eth_type_trans(skb, dev);
......@@ -800,8 +840,7 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
}
}
static void
lec_pop(struct atm_vcc *vcc, struct sk_buff *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;
......@@ -820,8 +859,7 @@ lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
}
}
static int
lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
{
struct lec_vcc_priv *vpriv;
int bytes_left;
......@@ -830,7 +868,8 @@ lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
/* 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",
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 ||
......@@ -849,23 +888,21 @@ lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
return 0;
}
static int
lec_mcast_attach(struct atm_vcc *vcc, int arg)
static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
{
if (arg <0 || arg >= MAX_LEC_ITF || !dev_lec[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));
return (lec_mcast_make((struct lec_priv *)dev_lec[arg]->priv, vcc));
}
/* Initialize device. */
static int
lecd_attach(struct atm_vcc *vcc, int arg)
static int lecd_attach(struct atm_vcc *vcc, int arg)
{
int i;
struct lec_priv *priv;
if (arg<0)
if (arg < 0)
i = 0;
else
i = arg;
......@@ -873,7 +910,7 @@ lecd_attach(struct atm_vcc *vcc, int 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))
if (arg >= (MAX_LEC_ITF - NUM_TR_DEVS))
return -EINVAL;
#endif
if (!dev_lec[i]) {
......@@ -913,20 +950,20 @@ lecd_attach(struct atm_vcc *vcc, int arg)
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_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_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->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);
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]);
......@@ -936,7 +973,7 @@ lecd_attach(struct atm_vcc *vcc, int arg)
}
#ifdef CONFIG_PROC_FS
static char* lec_arp_get_status_string(unsigned char status)
static char *lec_arp_get_status_string(unsigned char status)
{
static char *lec_arp_status_string[] = {
"ESI_UNKNOWN ",
......@@ -974,33 +1011,35 @@ static void lec_info(struct seq_file *seq, struct lec_arp_table *entry)
seq_putc(seq, '\n');
}
struct lec_state {
unsigned long flags;
struct lec_priv *locked;
struct lec_arp_table *entry;
struct hlist_node *node;
struct net_device *dev;
int itf;
int arp_table;
int misc_table;
};
static void *lec_tbl_walk(struct lec_state *state, struct lec_arp_table *tbl,
static void *lec_tbl_walk(struct lec_state *state, struct hlist_head *tbl,
loff_t *l)
{
struct lec_arp_table *e = state->entry;
struct hlist_node *e = state->node;
struct lec_arp_table *tmp;
if (!e)
e = tbl;
e = tbl->first;
if (e == (void *)1) {
e = tbl;
e = tbl->first;
--*l;
}
for (; e; e = e->next) {
hlist_for_each_entry_from(tmp, e, next) {
if (--*l < 0)
break;
}
state->entry = e;
state->node = e;
return (*l < 0) ? state : NULL;
}
......@@ -1011,7 +1050,7 @@ static void *lec_arp_walk(struct lec_state *state, loff_t *l,
int p;
for (p = state->arp_table; p < LEC_ARP_TABLE_SIZE; p++) {
v = lec_tbl_walk(state, priv->lec_arp_tables[p], l);
v = lec_tbl_walk(state, &priv->lec_arp_tables[p], l);
if (v)
break;
}
......@@ -1022,10 +1061,10 @@ static void *lec_arp_walk(struct lec_state *state, loff_t *l,
static void *lec_misc_walk(struct lec_state *state, loff_t *l,
struct lec_priv *priv)
{
struct lec_arp_table *lec_misc_tables[] = {
priv->lec_arp_empty_ones,
priv->lec_no_forward,
priv->mcast_fwds
struct hlist_head *lec_misc_tables[] = {
&priv->lec_arp_empty_ones,
&priv->lec_no_forward,
&priv->mcast_fwds
};
void *v = NULL;
int q;
......@@ -1046,8 +1085,7 @@ static void *lec_priv_walk(struct lec_state *state, loff_t *l,
state->locked = priv;
spin_lock_irqsave(&priv->lec_arp_lock, state->flags);
}
if (!lec_arp_walk(state, l, priv) &&
!lec_misc_walk(state, l, priv)) {
if (!lec_arp_walk(state, l, priv) && !lec_misc_walk(state, l, priv)) {
spin_unlock_irqrestore(&priv->lec_arp_lock, state->flags);
state->locked = NULL;
/* Partial state reset for the next time we get called */
......@@ -1093,9 +1131,9 @@ static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
state->locked = NULL;
state->arp_table = 0;
state->misc_table = 0;
state->entry = (void *)1;
state->node = (void *)1;
return *pos ? lec_get_idx(state, *pos) : (void*)1;
return *pos ? lec_get_idx(state, *pos) : (void *)1;
}
static void lec_seq_stop(struct seq_file *seq, void *v)
......@@ -1129,9 +1167,10 @@ static int lec_seq_show(struct seq_file *seq, void *v)
else {
struct lec_state *state = seq->private;
struct net_device *dev = state->dev;
struct lec_arp_table *entry = hlist_entry(state->node, struct lec_arp_table, next);
seq_printf(seq, "%s ", dev->name);
lec_info(seq, state->entry);
lec_info(seq, entry);
}
return 0;
}
......@@ -1200,15 +1239,15 @@ static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
switch (cmd) {
case ATMLEC_CTRL:
err = lecd_attach(vcc, (int) arg);
err = lecd_attach(vcc, (int)arg);
if (err >= 0)
sock->state = SS_CONNECTED;
break;
case ATMLEC_MCAST:
err = lec_mcast_attach(vcc, (int) arg);
err = lec_mcast_attach(vcc, (int)arg);
break;
case ATMLEC_DATA:
err = lec_vcc_attach(vcc, (void __user *) arg);
err = lec_vcc_attach(vcc, (void __user *)arg);
break;
}
......@@ -1279,7 +1318,7 @@ static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
spin_lock_irqsave(&priv->lec_arp_lock, flags);
table = lec_arp_find(priv, dst_mac);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
if(table == NULL)
if (table == NULL)
return -1;
*tlvs = kmalloc(table->sizeoftlvs, GFP_ATOMIC);
......@@ -1306,7 +1345,6 @@ static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
return retval;
}
/*
* LANE2: 3.1.4, LE_ASSOCIATE.request
* Associate the *tlvs with the *lan_dst address.
......@@ -1314,12 +1352,12 @@ static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
* Returns 1 for success, 0 for failure (out of memory)
*
*/
static int lane2_associate_req (struct net_device *dev, u8 *lan_dst,
static int lane2_associate_req(struct net_device *dev, u8 *lan_dst,
u8 *tlvs, u32 sizeoftlvs)
{
int retval;
struct sk_buff *skb;
struct lec_priv *priv = (struct lec_priv*)dev->priv;
struct lec_priv *priv = (struct lec_priv *)dev->priv;
if (compare_ether_addr(lan_dst, dev->dev_addr))
return (0); /* not our mac address */
......@@ -1340,7 +1378,8 @@ static int lane2_associate_req (struct net_device *dev, u8 *lan_dst,
retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb);
if (retval != 0)
printk("lec.c: lane2_associate_req() failed\n");
/* If the previous association has changed we must
/*
* If the previous association has changed we must
* somehow notify other LANE entities about the change
*/
return (1);
......@@ -1350,15 +1389,19 @@ static int lane2_associate_req (struct net_device *dev, u8 *lan_dst,
* LANE2: 3.1.5, LE_ASSOCIATE.indication
*
*/
static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr,
static void lane2_associate_ind(struct net_device *dev, u8 *mac_addr,
u8 *tlvs, u32 sizeoftlvs)
{
#if 0
int i = 0;
#endif
struct lec_priv *priv = (struct lec_priv *)dev->priv;
#if 0 /* Why have the TLVs in LE_ARP entries since we do not use them? When you
uncomment this code, make sure the TLVs get freed when entry is killed */
#if 0 /*
* Why have the TLVs in LE_ARP entries
* since we do not use them? When you
* uncomment this code, make sure the
* TLVs get freed when entry is killed
*/
struct lec_arp_table *entry = lec_arp_find(priv, mac_addr);
if (entry == NULL)
......@@ -1395,7 +1438,6 @@ static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr,
*
* lec_arpc.c was added here when making
* lane client modular. October 1997
*
*/
#include <linux/types.h>
......@@ -1406,7 +1448,6 @@ static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr,
#include <linux/inetdevice.h>
#include <net/route.h>
#if 0
#define DPRINTK(format,args...)
/*
......@@ -1417,7 +1458,7 @@ static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr,
#define LEC_ARP_REFRESH_INTERVAL (3*HZ)
static void lec_arp_check_expire(unsigned long data);
static void lec_arp_check_expire(void *data);
static void lec_arp_expire_arp(unsigned long data);
/*
......@@ -1429,29 +1470,27 @@ static void lec_arp_expire_arp(unsigned long data);
/*
* Initialization of arp-cache
*/
static void
lec_arp_init(struct lec_priv *priv)
static void lec_arp_init(struct lec_priv *priv)
{
unsigned short i;
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
priv->lec_arp_tables[i] = NULL;
INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
}
INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
INIT_HLIST_HEAD(&priv->lec_no_forward);
INIT_HLIST_HEAD(&priv->mcast_fwds);
spin_lock_init(&priv->lec_arp_lock);
init_timer(&priv->lec_arp_timer);
priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL;
priv->lec_arp_timer.data = (unsigned long)priv;
priv->lec_arp_timer.function = lec_arp_check_expire;
add_timer(&priv->lec_arp_timer);
INIT_WORK(&priv->lec_arp_work, lec_arp_check_expire, priv);
schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
}
static void
lec_arp_clear_vccs(struct lec_arp_table *entry)
static void lec_arp_clear_vccs(struct lec_arp_table *entry)
{
if (entry->vcc) {
struct atm_vcc *vcc = entry->vcc;
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
struct net_device *dev = (struct net_device*) vcc->proto_data;
struct net_device *dev = (struct net_device *)vcc->proto_data;
vcc->pop = vpriv->old_pop;
if (vpriv->xoff)
......@@ -1460,7 +1499,7 @@ lec_arp_clear_vccs(struct lec_arp_table *entry)
vcc->user_back = NULL;
vcc->push = entry->old_push;
vcc_release_async(vcc, -EPIPE);
vcc = NULL;
entry->vcc = NULL;
}
if (entry->recv_vcc) {
entry->recv_vcc->push = entry->old_recv_push;
......@@ -1474,69 +1513,46 @@ lec_arp_clear_vccs(struct lec_arp_table *entry)
* LANE2: Add to the end of the list to satisfy 8.1.13
*/
static inline void
lec_arp_add(struct lec_priv *priv, struct lec_arp_table *to_add)
lec_arp_add(struct lec_priv *priv, struct lec_arp_table *entry)
{
unsigned short place;
struct lec_arp_table *tmp;
struct hlist_head *tmp;
place = HASH(to_add->mac_addr[ETH_ALEN-1]);
tmp = priv->lec_arp_tables[place];
to_add->next = NULL;
if (tmp == NULL)
priv->lec_arp_tables[place] = to_add;
else { /* add to the end */
while (tmp->next)
tmp = tmp->next;
tmp->next = to_add;
}
tmp = &priv->lec_arp_tables[HASH(entry->mac_addr[ETH_ALEN - 1])];
hlist_add_head(&entry->next, tmp);
DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
0xff&to_add->mac_addr[0], 0xff&to_add->mac_addr[1],
0xff&to_add->mac_addr[2], 0xff&to_add->mac_addr[3],
0xff&to_add->mac_addr[4], 0xff&to_add->mac_addr[5]);
0xff & entry->mac_addr[0], 0xff & entry->mac_addr[1],
0xff & entry->mac_addr[2], 0xff & entry->mac_addr[3],
0xff & entry->mac_addr[4], 0xff & entry->mac_addr[5]);
}
/*
* Remove entry from lec_arp_table
*/
static int
lec_arp_remove(struct lec_priv *priv,
struct lec_arp_table *to_remove)
lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove)
{
unsigned short place;
struct lec_arp_table *tmp;
int remove_vcc=1;
struct hlist_node *node;
struct lec_arp_table *entry;
int i, remove_vcc = 1;
if (!to_remove) {
return -1;
}
place = HASH(to_remove->mac_addr[ETH_ALEN-1]);
tmp = priv->lec_arp_tables[place];
if (tmp == to_remove) {
priv->lec_arp_tables[place] = tmp->next;
} else {
while(tmp && tmp->next != to_remove) {
tmp = tmp->next;
}
if (!tmp) {/* Entry was not found */
return -1;
}
}
tmp->next = to_remove->next;
hlist_del(&to_remove->next);
del_timer(&to_remove->timer);
/* If this is the only MAC connected to this VCC, also tear down
the VCC */
/* If this is the only MAC connected to this VCC, also tear down the VCC */
if (to_remove->status >= ESI_FLUSH_PENDING) {
/*
* ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT
*/
for(place = 0; place < LEC_ARP_TABLE_SIZE; place++) {
for(tmp = priv->lec_arp_tables[place]; tmp != NULL; tmp = tmp->next) {
if (memcmp(tmp->atm_addr, to_remove->atm_addr,
ATM_ESA_LEN)==0) {
remove_vcc=0;
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
if (memcmp(to_remove->atm_addr,
entry->atm_addr, ATM_ESA_LEN) == 0) {
remove_vcc = 0;
break;
}
}
......@@ -1547,17 +1563,16 @@ lec_arp_remove(struct lec_priv *priv,
skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */
DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1],
0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3],
0xff&to_remove->mac_addr[4], 0xff&to_remove->mac_addr[5]);
0xff & to_remove->mac_addr[0], 0xff & to_remove->mac_addr[1],
0xff & to_remove->mac_addr[2], 0xff & to_remove->mac_addr[3],
0xff & to_remove->mac_addr[4], 0xff & to_remove->mac_addr[5]);
return 0;
}
#if DEBUG_ARP_TABLE
static char*
get_status_string(unsigned char st)
static char *get_status_string(unsigned char st)
{
switch(st) {
switch (st) {
case ESI_UNKNOWN:
return "ESI_UNKNOWN";
case ESI_ARP_PENDING:
......@@ -1572,168 +1587,152 @@ get_status_string(unsigned char st)
return "<UNKNOWN>";
}
}
#endif
static void
dump_arp_table(struct lec_priv *priv)
static void dump_arp_table(struct lec_priv *priv)
{
#if DEBUG_ARP_TABLE
int i,j, offset;
struct hlist_node *node;
struct lec_arp_table *rulla;
char buf[1024];
struct lec_arp_table **lec_arp_tables =
(struct lec_arp_table **)priv->lec_arp_tables;
struct lec_arp_table *lec_arp_empty_ones =
(struct lec_arp_table *)priv->lec_arp_empty_ones;
struct lec_arp_table *lec_no_forward =
(struct lec_arp_table *)priv->lec_no_forward;
struct lec_arp_table *mcast_fwds = priv->mcast_fwds;
printk("Dump %p:\n",priv);
for (i=0;i<LEC_ARP_TABLE_SIZE;i++) {
rulla = lec_arp_tables[i];
char buf[256];
int i, j, offset;
printk("Dump %p:\n", priv);
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
hlist_for_each_entry(rulla, node, &priv->lec_arp_tables[i], next) {
offset = 0;
offset += sprintf(buf,"%d: %p\n",i, rulla);
while (rulla) {
offset += sprintf(buf+offset,"Mac:");
for(j=0;j<ETH_ALEN;j++) {
offset+=sprintf(buf+offset,
offset += sprintf(buf, "%d: %p\n", i, rulla);
offset += sprintf(buf + offset, "Mac:");
for (j = 0; j < ETH_ALEN; j++) {
offset += sprintf(buf + offset,
"%2.2x ",
rulla->mac_addr[j]&0xff);
rulla->mac_addr[j] & 0xff);
}
offset +=sprintf(buf+offset,"Atm:");
for(j=0;j<ATM_ESA_LEN;j++) {
offset+=sprintf(buf+offset,
offset += sprintf(buf + offset, "Atm:");
for (j = 0; j < ATM_ESA_LEN; j++) {
offset += sprintf(buf + offset,
"%2.2x ",
rulla->atm_addr[j]&0xff);
rulla->atm_addr[j] & 0xff);
}
offset+=sprintf(buf+offset,
offset += sprintf(buf + offset,
"Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
rulla->vcc?rulla->vcc->vpi:0,
rulla->vcc?rulla->vcc->vci:0,
rulla->recv_vcc?rulla->recv_vcc->vpi:0,
rulla->recv_vcc?rulla->recv_vcc->vci:0,
rulla->last_used,
rulla->vcc ? rulla->vcc->vpi : 0,
rulla->vcc ? rulla->vcc->vci : 0,
rulla->recv_vcc ? rulla->recv_vcc->
vpi : 0,
rulla->recv_vcc ? rulla->recv_vcc->
vci : 0, rulla->last_used,
rulla->timestamp, rulla->no_tries);
offset+=sprintf(buf+offset,
offset +=
sprintf(buf + offset,
"Flags:%x, Packets_flooded:%x, Status: %s ",
rulla->flags, rulla->packets_flooded,
get_status_string(rulla->status));
offset+=sprintf(buf+offset,"->%p\n",rulla->next);
rulla = rulla->next;
printk("%s\n", buf);
}
printk("%s",buf);
}
rulla = lec_no_forward;
if (rulla)
if (!hlist_empty(&priv->lec_no_forward))
printk("No forward\n");
while(rulla) {
offset=0;
offset += sprintf(buf+offset,"Mac:");
for(j=0;j<ETH_ALEN;j++) {
offset+=sprintf(buf+offset,"%2.2x ",
rulla->mac_addr[j]&0xff);
}
offset +=sprintf(buf+offset,"Atm:");
for(j=0;j<ATM_ESA_LEN;j++) {
offset+=sprintf(buf+offset,"%2.2x ",
rulla->atm_addr[j]&0xff);
}
offset+=sprintf(buf+offset,
hlist_for_each_entry(rulla, node, &priv->lec_no_forward, next) {
offset = 0;
offset += sprintf(buf + offset, "Mac:");
for (j = 0; j < ETH_ALEN; j++) {
offset += sprintf(buf + offset, "%2.2x ",
rulla->mac_addr[j] & 0xff);
}
offset += sprintf(buf + offset, "Atm:");
for (j = 0; j < ATM_ESA_LEN; j++) {
offset += sprintf(buf + offset, "%2.2x ",
rulla->atm_addr[j] & 0xff);
}
offset += sprintf(buf + offset,
"Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
rulla->vcc?rulla->vcc->vpi:0,
rulla->vcc?rulla->vcc->vci:0,
rulla->recv_vcc?rulla->recv_vcc->vpi:0,
rulla->recv_vcc?rulla->recv_vcc->vci:0,
rulla->vcc ? rulla->vcc->vpi : 0,
rulla->vcc ? rulla->vcc->vci : 0,
rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,
rulla->recv_vcc ? rulla->recv_vcc->vci : 0,
rulla->last_used,
rulla->timestamp, rulla->no_tries);
offset+=sprintf(buf+offset,
offset += sprintf(buf + offset,
"Flags:%x, Packets_flooded:%x, Status: %s ",
rulla->flags, rulla->packets_flooded,
get_status_string(rulla->status));
offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next);
rulla = rulla->next;
printk("%s",buf);
printk("%s\n", buf);
}
rulla = lec_arp_empty_ones;
if (rulla)
if (!hlist_empty(&priv->lec_arp_empty_ones))
printk("Empty ones\n");
while(rulla) {
offset=0;
offset += sprintf(buf+offset,"Mac:");
for(j=0;j<ETH_ALEN;j++) {
offset+=sprintf(buf+offset,"%2.2x ",
rulla->mac_addr[j]&0xff);
}
offset +=sprintf(buf+offset,"Atm:");
for(j=0;j<ATM_ESA_LEN;j++) {
offset+=sprintf(buf+offset,"%2.2x ",
rulla->atm_addr[j]&0xff);
}
offset+=sprintf(buf+offset,
hlist_for_each_entry(rulla, node, &priv->lec_arp_empty_ones, next) {
offset = 0;
offset += sprintf(buf + offset, "Mac:");
for (j = 0; j < ETH_ALEN; j++) {
offset += sprintf(buf + offset, "%2.2x ",
rulla->mac_addr[j] & 0xff);
}
offset += sprintf(buf + offset, "Atm:");
for (j = 0; j < ATM_ESA_LEN; j++) {
offset += sprintf(buf + offset, "%2.2x ",
rulla->atm_addr[j] & 0xff);
}
offset += sprintf(buf + offset,
"Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
rulla->vcc?rulla->vcc->vpi:0,
rulla->vcc?rulla->vcc->vci:0,
rulla->recv_vcc?rulla->recv_vcc->vpi:0,
rulla->recv_vcc?rulla->recv_vcc->vci:0,
rulla->vcc ? rulla->vcc->vpi : 0,
rulla->vcc ? rulla->vcc->vci : 0,
rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,
rulla->recv_vcc ? rulla->recv_vcc->vci : 0,
rulla->last_used,
rulla->timestamp, rulla->no_tries);
offset+=sprintf(buf+offset,
offset += sprintf(buf + offset,
"Flags:%x, Packets_flooded:%x, Status: %s ",
rulla->flags, rulla->packets_flooded,
get_status_string(rulla->status));
offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next);
rulla = rulla->next;
printk("%s",buf);
printk("%s", buf);
}
rulla = mcast_fwds;
if (rulla)
if (!hlist_empty(&priv->mcast_fwds))
printk("Multicast Forward VCCs\n");
while(rulla) {
offset=0;
offset += sprintf(buf+offset,"Mac:");
for(j=0;j<ETH_ALEN;j++) {
offset+=sprintf(buf+offset,"%2.2x ",
rulla->mac_addr[j]&0xff);
}
offset +=sprintf(buf+offset,"Atm:");
for(j=0;j<ATM_ESA_LEN;j++) {
offset+=sprintf(buf+offset,"%2.2x ",
rulla->atm_addr[j]&0xff);
}
offset+=sprintf(buf+offset,
hlist_for_each_entry(rulla, node, &priv->mcast_fwds, next) {
offset = 0;
offset += sprintf(buf + offset, "Mac:");
for (j = 0; j < ETH_ALEN; j++) {
offset += sprintf(buf + offset, "%2.2x ",
rulla->mac_addr[j] & 0xff);
}
offset += sprintf(buf + offset, "Atm:");
for (j = 0; j < ATM_ESA_LEN; j++) {
offset += sprintf(buf + offset, "%2.2x ",
rulla->atm_addr[j] & 0xff);
}
offset += sprintf(buf + offset,
"Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
rulla->vcc?rulla->vcc->vpi:0,
rulla->vcc?rulla->vcc->vci:0,
rulla->recv_vcc?rulla->recv_vcc->vpi:0,
rulla->recv_vcc?rulla->recv_vcc->vci:0,
rulla->vcc ? rulla->vcc->vpi : 0,
rulla->vcc ? rulla->vcc->vci : 0,
rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,
rulla->recv_vcc ? rulla->recv_vcc->vci : 0,
rulla->last_used,
rulla->timestamp, rulla->no_tries);
offset+=sprintf(buf+offset,
offset += sprintf(buf + offset,
"Flags:%x, Packets_flooded:%x, Status: %s ",
rulla->flags, rulla->packets_flooded,
get_status_string(rulla->status));
offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next);
rulla = rulla->next;
printk("%s",buf);
printk("%s\n", buf);
}
#endif
}
#else
#define dump_arp_table(priv) do { } while (0)
#endif
/*
* Destruction of arp-cache
*/
static void
lec_arp_destroy(struct lec_priv *priv)
static void lec_arp_destroy(struct lec_priv *priv)
{
unsigned long flags;
struct lec_arp_table *entry, *next;
struct hlist_node *node, *next;
struct lec_arp_table *entry;
int i;
del_timer_sync(&priv->lec_arp_timer);
cancel_rearming_delayed_work(&priv->lec_arp_work);
/*
* Remove all entries
......@@ -1741,73 +1740,65 @@ lec_arp_destroy(struct lec_priv *priv)
spin_lock_irqsave(&priv->lec_arp_lock, flags);
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
for(entry = priv->lec_arp_tables[i]; entry != NULL; entry=next) {
next = entry->next;
hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
lec_arp_remove(priv, entry);
kfree(entry);
lec_arp_put(entry);
}
INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
}
entry = priv->lec_arp_empty_ones;
while(entry) {
next = entry->next;
hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
del_timer_sync(&entry->timer);
lec_arp_clear_vccs(entry);
kfree(entry);
entry = next;
hlist_del(&entry->next);
lec_arp_put(entry);
}
priv->lec_arp_empty_ones = NULL;
entry = priv->lec_no_forward;
while(entry) {
next = entry->next;
INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
hlist_for_each_entry_safe(entry, node, next, &priv->lec_no_forward, next) {
del_timer_sync(&entry->timer);
lec_arp_clear_vccs(entry);
kfree(entry);
entry = next;
hlist_del(&entry->next);
lec_arp_put(entry);
}
priv->lec_no_forward = NULL;
entry = priv->mcast_fwds;
while(entry) {
next = entry->next;
INIT_HLIST_HEAD(&priv->lec_no_forward);
hlist_for_each_entry_safe(entry, node, next, &priv->mcast_fwds, next) {
/* No timer, LANEv2 7.1.20 and 2.3.5.3 */
lec_arp_clear_vccs(entry);
kfree(entry);
entry = next;
hlist_del(&entry->next);
lec_arp_put(entry);
}
priv->mcast_fwds = NULL;
INIT_HLIST_HEAD(&priv->mcast_fwds);
priv->mcast_vcc = NULL;
memset(priv->lec_arp_tables, 0,
sizeof(struct lec_arp_table *) * LEC_ARP_TABLE_SIZE);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
}
/*
* Find entry by mac_address
*/
static struct lec_arp_table*
lec_arp_find(struct lec_priv *priv,
static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
unsigned char *mac_addr)
{
unsigned short place;
struct lec_arp_table *to_return;
struct hlist_node *node;
struct hlist_head *head;
struct lec_arp_table *entry;
DPRINTK("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
mac_addr[0]&0xff, mac_addr[1]&0xff, mac_addr[2]&0xff,
mac_addr[3]&0xff, mac_addr[4]&0xff, mac_addr[5]&0xff);
place = HASH(mac_addr[ETH_ALEN-1]);
mac_addr[0] & 0xff, mac_addr[1] & 0xff, mac_addr[2] & 0xff,
mac_addr[3] & 0xff, mac_addr[4] & 0xff, mac_addr[5] & 0xff);
to_return = priv->lec_arp_tables[place];
while(to_return) {
if (!compare_ether_addr(mac_addr, to_return->mac_addr)) {
return to_return;
head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])];
hlist_for_each_entry(entry, node, head, next) {
if (!compare_ether_addr(mac_addr, entry->mac_addr)) {
return entry;
}
to_return = to_return->next;
}
return NULL;
}
static struct lec_arp_table*
make_entry(struct lec_priv *priv, unsigned char *mac_addr)
static struct lec_arp_table *make_entry(struct lec_priv *priv,
unsigned char *mac_addr)
{
struct lec_arp_table *to_return;
......@@ -1817,22 +1808,19 @@ make_entry(struct lec_priv *priv, unsigned char *mac_addr)
return NULL;
}
memcpy(to_return->mac_addr, mac_addr, ETH_ALEN);
INIT_HLIST_NODE(&to_return->next);
init_timer(&to_return->timer);
to_return->timer.function = lec_arp_expire_arp;
to_return->timer.data = (unsigned long) to_return;
to_return->timer.data = (unsigned long)to_return;
to_return->last_used = jiffies;
to_return->priv = priv;
skb_queue_head_init(&to_return->tx_wait);
atomic_set(&to_return->usage, 1);
return to_return;
}
/*
*
* Arp sent timer expired
*
*/
static void
lec_arp_expire_arp(unsigned long data)
/* Arp sent timer expired */
static void lec_arp_expire_arp(unsigned long data)
{
struct lec_arp_table *entry;
......@@ -1842,61 +1830,37 @@ lec_arp_expire_arp(unsigned long data)
if (entry->status == ESI_ARP_PENDING) {
if (entry->no_tries <= entry->priv->max_retry_count) {
if (entry->is_rdesc)
send_to_lecd(entry->priv, l_rdesc_arp_xmt, entry->mac_addr, NULL, NULL);
send_to_lecd(entry->priv, l_rdesc_arp_xmt,
entry->mac_addr, NULL, NULL);
else
send_to_lecd(entry->priv, l_arp_xmt, entry->mac_addr, NULL, NULL);
send_to_lecd(entry->priv, l_arp_xmt,
entry->mac_addr, NULL, NULL);
entry->no_tries++;
}
mod_timer(&entry->timer, jiffies + (1*HZ));
mod_timer(&entry->timer, jiffies + (1 * HZ));
}
}
/*
*
* Unknown/unused vcc expire, remove associated entry
*
*/
static void
lec_arp_expire_vcc(unsigned long data)
/* Unknown/unused vcc expire, remove associated entry */
static void lec_arp_expire_vcc(unsigned long data)
{
unsigned long flags;
struct lec_arp_table *to_remove = (struct lec_arp_table*)data;
struct lec_arp_table *to_remove = (struct lec_arp_table *)data;
struct lec_priv *priv = (struct lec_priv *)to_remove->priv;
struct lec_arp_table *entry = NULL;
del_timer(&to_remove->timer);
DPRINTK("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n",
to_remove, priv,
to_remove->vcc?to_remove->recv_vcc->vpi:0,
to_remove->vcc?to_remove->recv_vcc->vci:0);
DPRINTK("eo:%p nf:%p\n",priv->lec_arp_empty_ones,priv->lec_no_forward);
to_remove->vcc ? to_remove->recv_vcc->vpi : 0,
to_remove->vcc ? to_remove->recv_vcc->vci : 0);
spin_lock_irqsave(&priv->lec_arp_lock, flags);
if (to_remove == priv->lec_arp_empty_ones)
priv->lec_arp_empty_ones = to_remove->next;
else {
entry = priv->lec_arp_empty_ones;
while (entry && entry->next != to_remove)
entry = entry->next;
if (entry)
entry->next = to_remove->next;
}
if (!entry) {
if (to_remove == priv->lec_no_forward) {
priv->lec_no_forward = to_remove->next;
} else {
entry = priv->lec_no_forward;
while (entry && entry->next != to_remove)
entry = entry->next;
if (entry)
entry->next = to_remove->next;
}
}
hlist_del(&to_remove->next);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
lec_arp_clear_vccs(to_remove);
kfree(to_remove);
lec_arp_put(to_remove);
}
/*
......@@ -1915,23 +1879,22 @@ lec_arp_expire_vcc(unsigned long data)
* to ESI_FORWARD_DIRECT. This causes the flush period to end
* regardless of the progress of the flush protocol.
*/
static void
lec_arp_check_expire(unsigned long data)
static void lec_arp_check_expire(void *data)
{
unsigned long flags;
struct lec_priv *priv = (struct lec_priv *)data;
struct lec_arp_table *entry, *next;
struct lec_priv *priv = data;
struct hlist_node *node, *next;
struct lec_arp_table *entry;
unsigned long now;
unsigned long time_to_check;
int i;
DPRINTK("lec_arp_check_expire %p\n",priv);
DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones,
priv->lec_no_forward);
DPRINTK("lec_arp_check_expire %p\n", priv);
now = jiffies;
restart:
spin_lock_irqsave(&priv->lec_arp_lock, flags);
for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
for(entry = priv->lec_arp_tables[i]; entry != NULL; ) {
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
if ((entry->flags) & LEC_REMOTE_FLAG &&
priv->topology_change)
time_to_check = priv->forward_delay_time;
......@@ -1939,56 +1902,61 @@ lec_arp_check_expire(unsigned long data)
time_to_check = priv->aging_time;
DPRINTK("About to expire: %lx - %lx > %lx\n",
now,entry->last_used, time_to_check);
if( time_after(now, entry->last_used+
time_to_check) &&
!(entry->flags & LEC_PERMANENT_FLAG) &&
!(entry->mac_addr[0] & 0x01) ) { /* LANE2: 7.1.20 */
now, entry->last_used, time_to_check);
if (time_after(now, entry->last_used + time_to_check)
&& !(entry->flags & LEC_PERMANENT_FLAG)
&& !(entry->mac_addr[0] & 0x01)) { /* LANE2: 7.1.20 */
/* Remove entry */
DPRINTK("LEC:Entry timed out\n");
next = entry->next;
lec_arp_remove(priv, entry);
kfree(entry);
entry = next;
lec_arp_put(entry);
} else {
/* Something else */
if ((entry->status == ESI_VC_PENDING ||
entry->status == ESI_ARP_PENDING)
&& time_after_eq(now,
entry->timestamp +
priv->max_unknown_frame_time)) {
priv->
max_unknown_frame_time)) {
entry->timestamp = jiffies;
entry->packets_flooded = 0;
if (entry->status == ESI_VC_PENDING)
send_to_lecd(priv, l_svc_setup, entry->mac_addr, entry->atm_addr, NULL);
send_to_lecd(priv, l_svc_setup,
entry->mac_addr,
entry->atm_addr,
NULL);
}
if (entry->status == ESI_FLUSH_PENDING
&&
time_after_eq(now, entry->timestamp+
time_after_eq(now, entry->timestamp +
priv->path_switching_delay)) {
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)) != NULL)
lec_send(entry->vcc, skb, entry->priv);
lec_send(vcc, skb, entry->priv);
entry->last_used = jiffies;
entry->status =
ESI_FORWARD_DIRECT;
entry->status = ESI_FORWARD_DIRECT;
lec_arp_put(entry);
goto restart;
}
entry = entry->next;
}
}
}
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
mod_timer(&priv->lec_arp_timer, jiffies + LEC_ARP_REFRESH_INTERVAL);
schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
}
/*
* Try to find vcc where mac_address is attached.
*
*/
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 struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
unsigned char *mac_to_find, int is_rdesc,
struct lec_arp_table **ret_entry)
{
unsigned long flags;
struct lec_arp_table *entry;
......@@ -2015,33 +1983,41 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find,
if (entry->status == ESI_FORWARD_DIRECT) {
/* Connection Ok */
entry->last_used = jiffies;
lec_arp_hold(entry);
*ret_entry = entry;
found = entry->vcc;
goto out;
}
/* If the LE_ARP cache entry is still pending, reset count to 0
/*
* If the LE_ARP cache entry is still pending, reset count to 0
* so another LE_ARP request can be made for this frame.
*/
if (entry->status == ESI_ARP_PENDING) {
entry->no_tries = 0;
}
/* Data direct VC not yet set up, check to see if the unknown
frame count is greater than the limit. If the limit has
not been reached, allow the caller to send packet to
BUS. */
/*
* Data direct VC not yet set up, check to see if the unknown
* frame count is greater than the limit. If the limit has
* not been reached, allow the caller to send packet to
* BUS.
*/
if (entry->status != ESI_FLUSH_PENDING &&
entry->packets_flooded<priv->maximum_unknown_frame_count) {
entry->packets_flooded <
priv->maximum_unknown_frame_count) {
entry->packets_flooded++;
DPRINTK("LEC_ARP: Flooding..\n");
found = priv->mcast_vcc;
goto out;
}
/* We got here because entry->status == ESI_FLUSH_PENDING
/*
* We got here because entry->status == ESI_FLUSH_PENDING
* or BUS flood limit was reached for an entry which is
* in ESI_ARP_PENDING or ESI_VC_PENDING state.
*/
lec_arp_hold(entry);
*ret_entry = entry;
DPRINTK("lec: entry->status %d entry->vcc %p\n", entry->status, entry->vcc);
DPRINTK("lec: entry->status %d entry->vcc %p\n", entry->status,
entry->vcc);
found = NULL;
} else {
/* No matching entry was found */
......@@ -2053,16 +2029,17 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find,
}
lec_arp_add(priv, entry);
/* We want arp-request(s) to be sent */
entry->packets_flooded =1;
entry->packets_flooded = 1;
entry->status = ESI_ARP_PENDING;
entry->no_tries = 1;
entry->last_used = entry->timestamp = jiffies;
entry->is_rdesc = is_rdesc;
if (entry->is_rdesc)
send_to_lecd(priv, l_rdesc_arp_xmt, mac_to_find, NULL, NULL);
send_to_lecd(priv, l_rdesc_arp_xmt, mac_to_find, NULL,
NULL);
else
send_to_lecd(priv, l_arp_xmt, mac_to_find, NULL, NULL);
entry->timer.expires = jiffies + (1*HZ);
entry->timer.expires = jiffies + (1 * HZ);
entry->timer.function = lec_arp_expire_arp;
add_timer(&entry->timer);
found = priv->mcast_vcc;
......@@ -2078,19 +2055,19 @@ lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
unsigned long permanent)
{
unsigned long flags;
struct lec_arp_table *entry, *next;
struct hlist_node *node, *next;
struct lec_arp_table *entry;
int i;
DPRINTK("lec_addr_delete\n");
spin_lock_irqsave(&priv->lec_arp_lock, flags);
for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
for(entry = priv->lec_arp_tables[i]; entry != NULL; entry = next) {
next = entry->next;
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)
&& (permanent ||
!(entry->flags & LEC_PERMANENT_FLAG))) {
lec_arp_remove(priv, entry);
kfree(entry);
lec_arp_put(entry);
}
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
return 0;
......@@ -2109,37 +2086,26 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
unsigned int targetless_le_arp)
{
unsigned long flags;
struct hlist_node *node, *next;
struct lec_arp_table *entry, *tmp;
int i;
DPRINTK("lec:%s", (targetless_le_arp) ? "targetless ": " ");
DPRINTK("lec:%s", (targetless_le_arp) ? "targetless " : " ");
DPRINTK("lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],
mac_addr[4],mac_addr[5]);
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
mac_addr[4], mac_addr[5]);
spin_lock_irqsave(&priv->lec_arp_lock, flags);
entry = lec_arp_find(priv, mac_addr);
if (entry == NULL && targetless_le_arp)
goto out; /* LANE2: ignore targetless LE_ARPs for which
goto out; /*
* LANE2: ignore targetless LE_ARPs for which
* we have no entry in the cache. 7.1.30
*/
if (priv->lec_arp_empty_ones) {
entry = priv->lec_arp_empty_ones;
if (!memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN)) {
priv->lec_arp_empty_ones = entry->next;
} else {
while(entry->next && memcmp(entry->next->atm_addr,
atm_addr, ATM_ESA_LEN))
entry = entry->next;
if (entry->next) {
tmp = entry;
entry = entry->next;
tmp->next = entry->next;
} else
entry = NULL;
}
if (entry) {
if (!hlist_empty(&priv->lec_arp_empty_ones)) {
hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
if (memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN) == 0) {
hlist_del(&entry->next);
del_timer(&entry->timer);
tmp = lec_arp_find(priv, mac_addr);
if (tmp) {
......@@ -2150,8 +2116,8 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
tmp->old_push = entry->old_push;
tmp->last_used = jiffies;
del_timer(&entry->timer);
kfree(entry);
entry=tmp;
lec_arp_put(entry);
entry = tmp;
} else {
entry->status = ESI_FORWARD_DIRECT;
memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
......@@ -2159,14 +2125,16 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
lec_arp_add(priv, entry);
}
if (remoteflag)
entry->flags|=LEC_REMOTE_FLAG;
entry->flags |= LEC_REMOTE_FLAG;
else
entry->flags&=~LEC_REMOTE_FLAG;
entry->flags &= ~LEC_REMOTE_FLAG;
DPRINTK("After update\n");
dump_arp_table(priv);
goto out;
}
}
}
entry = lec_arp_find(priv, mac_addr);
if (!entry) {
entry = make_entry(priv, mac_addr);
......@@ -2178,11 +2146,10 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
}
memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
del_timer(&entry->timer);
for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
for(tmp = priv->lec_arp_tables[i]; tmp; tmp=tmp->next) {
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
hlist_for_each_entry(tmp, node, &priv->lec_arp_tables[i], next) {
if (entry != tmp &&
!memcmp(tmp->atm_addr, atm_addr,
ATM_ESA_LEN)) {
!memcmp(tmp->atm_addr, atm_addr, ATM_ESA_LEN)) {
/* Vcc to this host exists */
if (tmp->status > ESI_VC_PENDING) {
/*
......@@ -2190,19 +2157,18 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
* ESI_FORWARD_DIRECT
*/
entry->vcc = tmp->vcc;
entry->old_push=tmp->old_push;
entry->old_push = tmp->old_push;
}
entry->status=tmp->status;
entry->status = tmp->status;
break;
}
}
}
if (remoteflag)
entry->flags|=LEC_REMOTE_FLAG;
entry->flags |= LEC_REMOTE_FLAG;
else
entry->flags&=~LEC_REMOTE_FLAG;
if (entry->status == ESI_ARP_PENDING ||
entry->status == ESI_UNKNOWN) {
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);
}
......@@ -2218,11 +2184,12 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
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))
void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb))
{
unsigned long flags;
struct hlist_node *node;
struct lec_arp_table *entry;
int i, found_entry=0;
int i, found_entry = 0;
spin_lock_irqsave(&priv->lec_arp_lock, flags);
if (ioc_data->receive == 2) {
......@@ -2246,23 +2213,26 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
entry->recv_vcc = vcc;
entry->old_recv_push = old_push;
entry->next = priv->mcast_fwds;
priv->mcast_fwds = entry;
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. */
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",
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]);
/*
* Vcc which we don't want to make default vcc,
* attach it anyway.
*/
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",
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)
goto out;
......@@ -2273,38 +2243,41 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
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);
entry->next = priv->lec_no_forward;
priv->lec_no_forward = entry;
dump_arp_table(priv);
goto out;
}
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",
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]);
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",
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++) {
for (entry = priv->lec_arp_tables[i]; entry; entry=entry->next) {
if (memcmp(ioc_data->atm_addr, entry->atm_addr,
ATM_ESA_LEN)==0) {
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) {
DPRINTK("LEC_ARP: Attaching data direct\n");
DPRINTK("Currently -> Vcc: %d, Rvcc:%d\n",
entry->vcc?entry->vcc->vci:0,
entry->recv_vcc?entry->recv_vcc->vci:0);
found_entry=1;
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)
if (priv->maximum_unknown_frame_count
== 0)
entry->status =
ESI_FORWARD_DIRECT;
else {
......@@ -2312,22 +2285,24 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
entry->status =
ESI_FLUSH_PENDING;
#if 0
send_to_lecd(priv,l_flush_xmt,
send_to_lecd(priv, l_flush_xmt,
NULL,
entry->atm_addr,
NULL);
#endif
}
} 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... */
/*
* 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...
*/
;
}
}
......@@ -2338,8 +2313,10 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
dump_arp_table(priv);
goto out;
}
/* Not found, snatch address from first data packet that arrives from
this vcc */
/*
* Not found, snatch address from first data packet that arrives
* from this vcc
*/
entry = make_entry(priv, bus_mac);
if (!entry)
goto out;
......@@ -2348,8 +2325,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
memset(entry->mac_addr, 0, ETH_ALEN);
entry->status = ESI_UNKNOWN;
entry->next = priv->lec_arp_empty_ones;
priv->lec_arp_empty_ones = entry;
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);
......@@ -2359,25 +2335,32 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
}
static void
lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
{
unsigned long flags;
struct hlist_node *node;
struct lec_arp_table *entry;
int i;
DPRINTK("LEC:lec_flush_complete %lx\n",tran_id);
DPRINTK("LEC:lec_flush_complete %lx\n", tran_id);
restart:
spin_lock_irqsave(&priv->lec_arp_lock, flags);
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
for (entry = priv->lec_arp_tables[i]; entry; entry=entry->next) {
if (entry->flush_tran_id == tran_id &&
entry->status == ESI_FLUSH_PENDING) {
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)) != NULL)
lec_send(entry->vcc, skb, entry->priv);
lec_send(vcc, skb, entry->priv);
entry->last_used = jiffies;
entry->status = ESI_FORWARD_DIRECT;
lec_arp_put(entry);
DPRINTK("LEC_ARP: Flushed\n");
goto restart;
}
}
}
......@@ -2390,25 +2373,28 @@ lec_set_flush_tran_id(struct lec_priv *priv,
unsigned char *atm_addr, unsigned long tran_id)
{
unsigned long flags;
struct hlist_node *node;
struct lec_arp_table *entry;
int i;
spin_lock_irqsave(&priv->lec_arp_lock, flags);
for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
for(entry = priv->lec_arp_tables[i]; entry; entry=entry->next)
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;
DPRINTK("Set flush transaction id to %lx for %p\n",tran_id,entry);
DPRINTK("Set flush transaction id to %lx for %p\n",
tran_id, entry);
}
}
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
}
static int
lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
{
unsigned long flags;
unsigned char mac_addr[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
struct lec_arp_table *to_add;
struct lec_vcc_priv *vpriv;
int err = 0;
......@@ -2440,22 +2426,23 @@ lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
return err;
}
static void
lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
{
unsigned long flags;
struct lec_arp_table *entry, *next;
struct hlist_node *node, *next;
struct lec_arp_table *entry;
int i;
DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n",vcc->vpi,vcc->vci);
DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n", vcc->vpi, vcc->vci);
dump_arp_table(priv);
spin_lock_irqsave(&priv->lec_arp_lock, flags);
for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
for(entry = priv->lec_arp_tables[i];entry; entry=next) {
next = entry->next;
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);
kfree(entry);
lec_arp_put(entry);
if (priv->mcast_vcc == vcc) {
priv->mcast_vcc = NULL;
}
......@@ -2463,52 +2450,31 @@ lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
}
}
entry = priv->lec_arp_empty_ones;
priv->lec_arp_empty_ones = NULL;
while (entry != NULL) {
next = entry->next;
if (entry->vcc == vcc) { /* leave it out from the list */
hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
if (entry->vcc == vcc) {
lec_arp_clear_vccs(entry);
del_timer(&entry->timer);
kfree(entry);
}
else { /* put it back to the list */
entry->next = priv->lec_arp_empty_ones;
priv->lec_arp_empty_ones = entry;
hlist_del(&entry->next);
lec_arp_put(entry);
}
entry = next;
}
entry = priv->lec_no_forward;
priv->lec_no_forward = NULL;
while (entry != NULL) {
next = entry->next;
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);
kfree(entry);
}
else {
entry->next = priv->lec_no_forward;
priv->lec_no_forward = entry;
hlist_del(&entry->next);
lec_arp_put(entry);
}
entry = next;
}
entry = priv->mcast_fwds;
priv->mcast_fwds = NULL;
while (entry != NULL) {
next = entry->next;
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 */
kfree(entry);
}
else {
entry->next = priv->mcast_fwds;
priv->mcast_fwds = entry;
hlist_del(&entry->next);
lec_arp_put(entry);
}
entry = next;
}
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
......@@ -2520,54 +2486,39 @@ lec_arp_check_empties(struct lec_priv *priv,
struct atm_vcc *vcc, struct sk_buff *skb)
{
unsigned long flags;
struct lec_arp_table *entry, *prev;
struct hlist_node *node, *next;
struct lec_arp_table *entry, *tmp;
struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
unsigned char *src;
#ifdef CONFIG_TR
struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
if (priv->is_trdev) src = tr_hdr->h_source;
if (priv->is_trdev)
src = tr_hdr->h_source;
else
#endif
src = hdr->h_source;
spin_lock_irqsave(&priv->lec_arp_lock, flags);
entry = priv->lec_arp_empty_ones;
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;
priv->lec_arp_empty_ones = entry->next;
/* We might have got an entry */
if ((prev = lec_arp_find(priv,src))) {
lec_arp_remove(priv, prev);
kfree(prev);
if ((tmp = lec_arp_find(priv, src))) {
lec_arp_remove(priv, tmp);
lec_arp_put(tmp);
}
hlist_del(&entry->next);
lec_arp_add(priv, entry);
goto out;
}
prev = entry;
entry = entry->next;
while (entry && entry->vcc != vcc) {
prev= entry;
entry = entry->next;
}
if (!entry) {
DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n");
goto out;
}
del_timer(&entry->timer);
memcpy(entry->mac_addr, src, ETH_ALEN);
entry->status = ESI_FORWARD_DIRECT;
entry->last_used = jiffies;
prev->next = entry->next;
if ((prev = lec_arp_find(priv, src))) {
lec_arp_remove(priv, prev);
kfree(prev);
}
lec_arp_add(priv, entry);
out:
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
}
MODULE_LICENSE("GPL");
/*
*
* Lan Emulation client header file
*
* Marko Kiiskila mkiiskila@yahoo.com
*
* Marko Kiiskila <mkiiskila@yahoo.com>
*/
#ifndef _LEC_H_
#define _LEC_H_
#include <linux/config.h>
#include <linux/atmdev.h>
#include <linux/netdevice.h>
#include <linux/atmlec.h>
......@@ -44,17 +43,18 @@ struct lecdatahdr_8025 {
*
*/
struct lane2_ops {
int (*resolve)(struct net_device *dev, u8 *dst_mac, int force,
int (*resolve) (struct net_device *dev, u8 *dst_mac, int force,
u8 **tlvs, u32 *sizeoftlvs);
int (*associate_req)(struct net_device *dev, u8 *lan_dst,
int (*associate_req) (struct net_device *dev, u8 *lan_dst,
u8 *tlvs, u32 sizeoftlvs);
void (*associate_indicator)(struct net_device *dev, u8 *mac_addr,
void (*associate_indicator) (struct net_device *dev, u8 *mac_addr,
u8 *tlvs, u32 sizeoftlvs);
};
/*
* ATM LAN Emulation supports both LLC & Dix Ethernet EtherType
* frames.
*
* 1. Dix Ethernet EtherType frames encoded by placing EtherType
* field in h_type field. Data follows immediatelly after header.
* 2. LLC Data frames whose total length, including LLC field and data,
......@@ -72,53 +72,70 @@ struct lane2_ops {
struct lec_priv {
struct net_device_stats stats;
unsigned short lecid; /* Lecid of this client */
struct lec_arp_table *lec_arp_empty_ones;
struct hlist_head lec_arp_empty_ones;
/* Used for storing VCC's that don't have a MAC address attached yet */
struct lec_arp_table *lec_arp_tables[LEC_ARP_TABLE_SIZE];
struct hlist_head lec_arp_tables[LEC_ARP_TABLE_SIZE];
/* Actual LE ARP table */
struct lec_arp_table *lec_no_forward;
/* Used for storing VCC's (and forward packets from) which are to
age out by not using them to forward packets.
This is because to some LE clients there will be 2 VCCs. Only
one of them gets used. */
struct lec_arp_table *mcast_fwds;
/* With LANEv2 it is possible that BUS (or a special multicast server)
establishes multiple Multicast Forward VCCs to us. This list
collects all those VCCs. LANEv1 client has only one item in this
list. These entries are not aged out. */
struct hlist_head lec_no_forward;
/*
* Used for storing VCC's (and forward packets from) which are to
* age out by not using them to forward packets.
* This is because to some LE clients there will be 2 VCCs. Only
* one of them gets used.
*/
struct hlist_head mcast_fwds;
/*
* With LANEv2 it is possible that BUS (or a special multicast server)
* establishes multiple Multicast Forward VCCs to us. This list
* collects all those VCCs. LANEv1 client has only one item in this
* list. These entries are not aged out.
*/
spinlock_t lec_arp_lock;
struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
struct atm_vcc *lecd;
struct timer_list lec_arp_timer;
/* C10 */
struct work_struct lec_arp_work; /* C10 */
unsigned int maximum_unknown_frame_count;
/* Within the period of time defined by this variable, the client will send
no more than C10 frames to BUS for a given unicast destination. (C11) */
/*
* Within the period of time defined by this variable, the client will send
* no more than C10 frames to BUS for a given unicast destination. (C11)
*/
unsigned long max_unknown_frame_time;
/* If no traffic has been sent in this vcc for this period of time,
vcc will be torn down (C12)*/
/*
* If no traffic has been sent in this vcc for this period of time,
* vcc will be torn down (C12)
*/
unsigned long vcc_timeout_period;
/* An LE Client MUST not retry an LE_ARP_REQUEST for a
given frame's LAN Destination more than maximum retry count times,
after the first LEC_ARP_REQUEST (C13)*/
/*
* An LE Client MUST not retry an LE_ARP_REQUEST for a
* given frame's LAN Destination more than maximum retry count times,
* after the first LEC_ARP_REQUEST (C13)
*/
unsigned short max_retry_count;
/* Max time the client will maintain an entry in its arp cache in
absence of a verification of that relationship (C17)*/
/*
* Max time the client will maintain an entry in its arp cache in
* absence of a verification of that relationship (C17)
*/
unsigned long aging_time;
/* Max time the client will maintain an entry in cache when
topology change flag is true (C18) */
unsigned long forward_delay_time;
/* Topology change flag (C19)*/
/*
* Max time the client will maintain an entry in cache when
* topology change flag is true (C18)
*/
unsigned long forward_delay_time; /* Topology change flag (C19) */
int topology_change;
/* Max time the client expects an LE_ARP_REQUEST/LE_ARP_RESPONSE
cycle to take (C20)*/
/*
* Max time the client expects an LE_ARP_REQUEST/LE_ARP_RESPONSE
* cycle to take (C20)
*/
unsigned long arp_response_time;
/* Time limit ot wait to receive an LE_FLUSH_RESPONSE after the
LE_FLUSH_REQUEST has been sent before taking recover action. (C21)*/
/*
* Time limit ot wait to receive an LE_FLUSH_RESPONSE after the
* LE_FLUSH_REQUEST has been sent before taking recover action. (C21)
*/
unsigned long flush_timeout;
/* The time since sending a frame to the bus after which the
LE Client may assume that the frame has been either discarded or
delivered to the recipient (C22) */
/* The time since sending a frame to the bus after which the
* LE Client may assume that the frame has been either discarded or
* delivered to the recipient (C22)
*/
unsigned long path_switching_delay;
u8 *tlvs; /* LANE2: TLVs are new */
......@@ -131,11 +148,10 @@ struct lec_priv {
};
struct lec_vcc_priv {
void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb);
void (*old_pop) (struct atm_vcc *vcc, struct sk_buff *skb);
int xoff;
};
#define LEC_VCC_PRIV(vcc) ((struct lec_vcc_priv *)((vcc)->user_back))
#endif /* _LEC_H_ */
/*
* Lec arp cache
* Marko Kiiskila mkiiskila@yahoo.com
*
* Marko Kiiskila <mkiiskila@yahoo.com>
*/
#ifndef _LEC_ARP_H
#define _LEC_ARP_H
#ifndef _LEC_ARP_H_
#define _LEC_ARP_H_
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/if_ether.h>
#include <linux/atmlec.h>
struct lec_arp_table {
struct lec_arp_table *next; /* Linked entry list */
struct hlist_node next; /* Linked entry list */
unsigned char atm_addr[ATM_ESA_LEN]; /* Atm address */
unsigned char mac_addr[ETH_ALEN]; /* Mac address */
int is_rdesc; /* Mac address is a route descriptor */
struct atm_vcc *vcc; /* Vcc this entry is attached */
struct atm_vcc *recv_vcc; /* Vcc we receive data from */
void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb);
void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb);
/* Push that leads to daemon */
void (*old_recv_push)(struct atm_vcc *vcc, struct sk_buff *skb);
void (*old_recv_push) (struct atm_vcc *vcc, struct sk_buff *skb);
/* Push that leads to daemon */
void (*old_close)(struct atm_vcc *vcc);
/* We want to see when this
* vcc gets closed */
unsigned long last_used; /* For expiry */
unsigned long timestamp; /* Used for various timestamping
* things:
unsigned long timestamp; /* Used for various timestamping things:
* 1. FLUSH started
* (status=ESI_FLUSH_PENDING)
* 2. Counting to
......@@ -34,23 +33,28 @@ struct lec_arp_table {
* (status=ESI_ARP_PENDING||
* status=ESI_VC_PENDING)
*/
unsigned char no_tries; /* No of times arp retry has been
tried */
unsigned char no_tries; /* No of times arp retry has been tried */
unsigned char status; /* Status of this entry */
unsigned short flags; /* Flags for this entry */
unsigned short packets_flooded; /* Data packets flooded */
unsigned long flush_tran_id; /* Transaction id in flush protocol */
struct timer_list timer; /* Arping timer */
struct lec_priv *priv; /* Pointer back */
u8 *tlvs; /* LANE2: Each MAC address can have TLVs */
u32 sizeoftlvs; /* associated with it. sizeoftlvs tells the */
/* the length of the tlvs array */
u8 *tlvs;
u32 sizeoftlvs; /*
* LANE2: Each MAC address can have TLVs
* associated with it. sizeoftlvs tells the
* the length of the tlvs array
*/
struct sk_buff_head tx_wait; /* wait queue for outgoing packets */
atomic_t usage; /* usage count */
};
struct tlv { /* LANE2: Template tlv struct for accessing */
/* the tlvs in the lec_arp_table->tlvs array*/
/*
* LANE2: Template tlv struct for accessing
* the tlvs in the lec_arp_table->tlvs array
*/
struct tlv {
u32 type;
u8 length;
u8 value[255];
......@@ -89,4 +93,4 @@ struct tlv { /* LANE2: Template tlv struct for accessing */
#define LEC_REMOTE_FLAG 0x0001
#define LEC_PERMANENT_FLAG 0x0002
#endif
#endif /* _LEC_ARP_H_ */
......@@ -485,7 +485,7 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
*
*/
int cipso_v4_doi_remove(u32 doi,
u32 audit_secid,
struct netlbl_audit *audit_info,
void (*callback) (struct rcu_head * head))
{
struct cipso_v4_doi *doi_def;
......@@ -506,7 +506,7 @@ int cipso_v4_doi_remove(u32 doi,
list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
if (dom_iter->valid)
netlbl_domhsh_remove(dom_iter->domain,
audit_secid);
audit_info);
cipso_v4_cache_invalidate();
rcu_read_unlock();
......
......@@ -384,11 +384,15 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
u32 doi;
const char *type_str = "(unknown)";
struct audit_buffer *audit_buf;
struct netlbl_audit audit_info;
if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
!info->attrs[NLBL_CIPSOV4_A_MTYPE])
return -EINVAL;
doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
netlbl_netlink_auditinfo(skb, &audit_info);
type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
switch (type) {
case CIPSO_V4_MAP_STD:
......@@ -401,13 +405,14 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
break;
}
if (ret_val == 0) {
doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
NETLINK_CB(skb).sid);
audit_log_format(audit_buf, " doi=%u type=%s", doi, type_str);
&audit_info);
audit_log_format(audit_buf,
" cipso_doi=%u cipso_type=%s res=%u",
doi,
type_str,
ret_val == 0 ? 1 : 0);
audit_log_end(audit_buf);
}
return ret_val;
}
......@@ -668,20 +673,25 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
int ret_val = -EINVAL;
u32 doi = 0;
struct audit_buffer *audit_buf;
struct netlbl_audit audit_info;
if (!info->attrs[NLBL_CIPSOV4_A_DOI])
return -EINVAL;
if (info->attrs[NLBL_CIPSOV4_A_DOI]) {
doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
netlbl_netlink_auditinfo(skb, &audit_info);
ret_val = cipso_v4_doi_remove(doi,
NETLINK_CB(skb).sid,
&audit_info,
netlbl_cipsov4_doi_free);
}
if (ret_val == 0) {
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
NETLINK_CB(skb).sid);
audit_log_format(audit_buf, " doi=%u", doi);
&audit_info);
audit_log_format(audit_buf,
" cipso_doi=%u res=%u",
doi,
ret_val == 0 ? 1 : 0);
audit_log_end(audit_buf);
}
return ret_val;
}
......
......@@ -188,7 +188,7 @@ int netlbl_domhsh_init(u32 size)
/**
* netlbl_domhsh_add - Adds a entry to the domain hash table
* @entry: the entry to add
* @audit_secid: the LSM secid to use in the audit message
* @audit_info: NetLabel audit information
*
* Description:
* Adds a new entry to the domain hash table and handles any updates to the
......@@ -196,7 +196,8 @@ int netlbl_domhsh_init(u32 size)
* negative on failure.
*
*/
int netlbl_domhsh_add(struct netlbl_dom_map *entry, u32 audit_secid)
int netlbl_domhsh_add(struct netlbl_dom_map *entry,
struct netlbl_audit *audit_info)
{
int ret_val;
u32 bkt;
......@@ -241,26 +242,26 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, u32 audit_secid)
spin_unlock(&netlbl_domhsh_def_lock);
} else
ret_val = -EINVAL;
if (ret_val == 0) {
if (entry->domain != NULL)
audit_domain = entry->domain;
else
audit_domain = "(default)";
audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD,
audit_secid);
audit_log_format(audit_buf, " domain=%s", audit_domain);
audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
audit_log_format(audit_buf, " nlbl_domain=%s", audit_domain);
switch (entry->type) {
case NETLBL_NLTYPE_UNLABELED:
audit_log_format(audit_buf, " protocol=unlbl");
audit_log_format(audit_buf, " nlbl_protocol=unlbl");
break;
case NETLBL_NLTYPE_CIPSOV4:
audit_log_format(audit_buf,
" protocol=cipsov4 doi=%u",
" nlbl_protocol=cipsov4 cipso_doi=%u",
entry->type_def.cipsov4->doi);
break;
}
audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
audit_log_end(audit_buf);
}
rcu_read_unlock();
if (ret_val != 0) {
......@@ -279,7 +280,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, u32 audit_secid)
/**
* netlbl_domhsh_add_default - Adds the default entry to the domain hash table
* @entry: the entry to add
* @audit_secid: the LSM secid to use in the audit message
* @audit_info: NetLabel audit information
*
* Description:
* Adds a new default entry to the domain hash table and handles any updates
......@@ -287,15 +288,16 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, u32 audit_secid)
* negative on failure.
*
*/
int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, u32 audit_secid)
int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
struct netlbl_audit *audit_info)
{
return netlbl_domhsh_add(entry, audit_secid);
return netlbl_domhsh_add(entry, audit_info);
}
/**
* netlbl_domhsh_remove - Removes an entry from the domain hash table
* @domain: the domain to remove
* @audit_secid: the LSM secid to use in the audit message
* @audit_info: NetLabel audit information
*
* Description:
* Removes an entry from the domain hash table and handles any updates to the
......@@ -303,7 +305,7 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, u32 audit_secid)
* negative on failure.
*
*/
int netlbl_domhsh_remove(const char *domain, u32 audit_secid)
int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
{
int ret_val = -ENOENT;
struct netlbl_dom_map *entry;
......@@ -345,18 +347,20 @@ int netlbl_domhsh_remove(const char *domain, u32 audit_secid)
ret_val = -ENOENT;
spin_unlock(&netlbl_domhsh_def_lock);
}
if (ret_val == 0) {
if (entry->domain != NULL)
audit_domain = entry->domain;
else
audit_domain = "(default)";
audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL,
audit_secid);
audit_log_format(audit_buf, " domain=%s", audit_domain);
audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
audit_log_format(audit_buf,
" nlbl_domain=%s res=%u",
audit_domain,
ret_val == 0 ? 1 : 0);
audit_log_end(audit_buf);
if (ret_val == 0)
call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
}
remove_return:
rcu_read_unlock();
......@@ -365,7 +369,7 @@ int netlbl_domhsh_remove(const char *domain, u32 audit_secid)
/**
* netlbl_domhsh_remove_default - Removes the default entry from the table
* @audit_secid: the LSM secid to use in the audit message
* @audit_info: NetLabel audit information
*
* Description:
* Removes/resets the default entry for the domain hash table and handles any
......@@ -373,9 +377,9 @@ int netlbl_domhsh_remove(const char *domain, u32 audit_secid)
* success, non-zero on failure.
*
*/
int netlbl_domhsh_remove_default(u32 audit_secid)
int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info)
{
return netlbl_domhsh_remove(NULL, audit_secid);
return netlbl_domhsh_remove(NULL, audit_info);
}
/**
......
......@@ -57,9 +57,11 @@ struct netlbl_dom_map {
int netlbl_domhsh_init(u32 size);
/* Manipulate the domain hash table */
int netlbl_domhsh_add(struct netlbl_dom_map *entry, u32 audit_secid);
int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, u32 audit_secid);
int netlbl_domhsh_remove_default(u32 audit_secid);
int netlbl_domhsh_add(struct netlbl_dom_map *entry,
struct netlbl_audit *audit_info);
int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
struct netlbl_audit *audit_info);
int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
int netlbl_domhsh_walk(u32 *skip_bkt,
u32 *skip_chain,
......
......@@ -87,11 +87,14 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
struct netlbl_dom_map *entry = NULL;
size_t tmp_size;
u32 tmp_val;
struct netlbl_audit audit_info;
if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
!info->attrs[NLBL_MGMT_A_PROTOCOL])
goto add_failure;
netlbl_netlink_auditinfo(skb, &audit_info);
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (entry == NULL) {
ret_val = -ENOMEM;
......@@ -108,7 +111,7 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
switch (entry->type) {
case NETLBL_NLTYPE_UNLABELED:
ret_val = netlbl_domhsh_add(entry, NETLINK_CB(skb).sid);
ret_val = netlbl_domhsh_add(entry, &audit_info);
break;
case NETLBL_NLTYPE_CIPSOV4:
if (!info->attrs[NLBL_MGMT_A_CV4DOI])
......@@ -125,7 +128,7 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
rcu_read_unlock();
goto add_failure;
}
ret_val = netlbl_domhsh_add(entry, NETLINK_CB(skb).sid);
ret_val = netlbl_domhsh_add(entry, &audit_info);
rcu_read_unlock();
break;
default:
......@@ -156,12 +159,15 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
{
char *domain;
struct netlbl_audit audit_info;
if (!info->attrs[NLBL_MGMT_A_DOMAIN])
return -EINVAL;
netlbl_netlink_auditinfo(skb, &audit_info);
domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
return netlbl_domhsh_remove(domain, NETLINK_CB(skb).sid);
return netlbl_domhsh_remove(domain, &audit_info);
}
/**
......@@ -264,10 +270,13 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
int ret_val = -EINVAL;
struct netlbl_dom_map *entry = NULL;
u32 tmp_val;
struct netlbl_audit audit_info;
if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
goto adddef_failure;
netlbl_netlink_auditinfo(skb, &audit_info);
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (entry == NULL) {
ret_val = -ENOMEM;
......@@ -277,8 +286,7 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
switch (entry->type) {
case NETLBL_NLTYPE_UNLABELED:
ret_val = netlbl_domhsh_add_default(entry,
NETLINK_CB(skb).sid);
ret_val = netlbl_domhsh_add_default(entry, &audit_info);
break;
case NETLBL_NLTYPE_CIPSOV4:
if (!info->attrs[NLBL_MGMT_A_CV4DOI])
......@@ -295,8 +303,7 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
rcu_read_unlock();
goto adddef_failure;
}
ret_val = netlbl_domhsh_add_default(entry,
NETLINK_CB(skb).sid);
ret_val = netlbl_domhsh_add_default(entry, &audit_info);
rcu_read_unlock();
break;
default:
......@@ -324,7 +331,11 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
*/
static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
{
return netlbl_domhsh_remove_default(NETLINK_CB(skb).sid);
struct netlbl_audit audit_info;
netlbl_netlink_auditinfo(skb, &audit_info);
return netlbl_domhsh_remove_default(&audit_info);
}
/**
......
......@@ -70,18 +70,25 @@ static struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {
/**
* netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag
* @value: desired value
* @audit_secid: the LSM secid to use in the audit message
* @audit_info: NetLabel audit information
*
* Description:
* Set the value of the unlabeled accept flag to @value.
*
*/
static void netlbl_unlabel_acceptflg_set(u8 value, u32 audit_secid)
static void netlbl_unlabel_acceptflg_set(u8 value,
struct netlbl_audit *audit_info)
{
struct audit_buffer *audit_buf;
u8 old_val;
old_val = atomic_read(&netlabel_unlabel_accept_flg);
atomic_set(&netlabel_unlabel_accept_flg, value);
netlbl_audit_nomsg((value ?
AUDIT_MAC_UNLBL_ACCEPT : AUDIT_MAC_UNLBL_DENY),
audit_secid);
audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_ALLOW,
audit_info);
audit_log_format(audit_buf, " unlbl_accept=%u old=%u", value, old_val);
audit_log_end(audit_buf);
}
/*
......@@ -101,12 +108,13 @@ static void netlbl_unlabel_acceptflg_set(u8 value, u32 audit_secid)
static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info)
{
u8 value;
struct netlbl_audit audit_info;
if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) {
value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]);
if (value == 1 || value == 0) {
netlbl_unlabel_acceptflg_set(value,
NETLINK_CB(skb).sid);
netlbl_netlink_auditinfo(skb, &audit_info);
netlbl_unlabel_acceptflg_set(value, &audit_info);
return 0;
}
}
......@@ -250,19 +258,23 @@ int netlbl_unlabel_defconf(void)
{
int ret_val;
struct netlbl_dom_map *entry;
u32 secid;
struct netlbl_audit audit_info;
security_task_getsecid(current, &secid);
/* Only the kernel is allowed to call this function and the only time
* it is called is at bootup before the audit subsystem is reporting
* messages so don't worry to much about these values. */
security_task_getsecid(current, &audit_info.secid);
audit_info.loginuid = 0;
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (entry == NULL)
return -ENOMEM;
entry->type = NETLBL_NLTYPE_UNLABELED;
ret_val = netlbl_domhsh_add_default(entry, secid);
ret_val = netlbl_domhsh_add_default(entry, &audit_info);
if (ret_val != 0)
return ret_val;
netlbl_unlabel_acceptflg_set(1, secid);
netlbl_unlabel_acceptflg_set(1, &audit_info);
return 0;
}
......@@ -85,7 +85,7 @@ int netlbl_netlink_init(void)
/**
* netlbl_audit_start_common - Start an audit message
* @type: audit message type
* @secid: LSM context ID
* @audit_info: NetLabel audit information
*
* Description:
* Start an audit message using the type specified in @type and fill the audit
......@@ -93,14 +93,11 @@ int netlbl_netlink_init(void)
* a pointer to the audit buffer on success, NULL on failure.
*
*/
struct audit_buffer *netlbl_audit_start_common(int type, u32 secid)
struct audit_buffer *netlbl_audit_start_common(int type,
struct netlbl_audit *audit_info)
{
struct audit_context *audit_ctx = current->audit_context;
struct audit_buffer *audit_buf;
uid_t audit_loginuid;
const char *audit_tty;
char audit_comm[sizeof(current->comm)];
struct vm_area_struct *vma;
char *secctx;
u32 secctx_len;
......@@ -108,60 +105,13 @@ struct audit_buffer *netlbl_audit_start_common(int type, u32 secid)
if (audit_buf == NULL)
return NULL;
audit_loginuid = audit_get_loginuid(audit_ctx);
if (current->signal &&
current->signal->tty &&
current->signal->tty->name)
audit_tty = current->signal->tty->name;
else
audit_tty = "(none)";
get_task_comm(audit_comm, current);
audit_log_format(audit_buf, "netlabel: auid=%u", audit_info->loginuid);
audit_log_format(audit_buf,
"netlabel: auid=%u uid=%u tty=%s pid=%d",
audit_loginuid,
current->uid,
audit_tty,
current->pid);
audit_log_format(audit_buf, " comm=");
audit_log_untrustedstring(audit_buf, audit_comm);
if (current->mm) {
down_read(&current->mm->mmap_sem);
vma = current->mm->mmap;
while (vma) {
if ((vma->vm_flags & VM_EXECUTABLE) &&
vma->vm_file) {
audit_log_d_path(audit_buf,
" exe=",
vma->vm_file->f_dentry,
vma->vm_file->f_vfsmnt);
break;
}
vma = vma->vm_next;
}
up_read(&current->mm->mmap_sem);
}
if (secid != 0 &&
security_secid_to_secctx(secid, &secctx, &secctx_len) == 0)
if (audit_info->secid != 0 &&
security_secid_to_secctx(audit_info->secid,
&secctx,
&secctx_len) == 0)
audit_log_format(audit_buf, " subj=%s", secctx);
return audit_buf;
}
/**
* netlbl_audit_nomsg - Send an audit message without additional text
* @type: audit message type
* @secid: LSM context ID
*
* Description:
* Send an audit message with only the common NetLabel audit fields.
*
*/
void netlbl_audit_nomsg(int type, u32 secid)
{
struct audit_buffer *audit_buf;
audit_buf = netlbl_audit_start_common(type, secid);
audit_log_end(audit_buf);
}
......@@ -72,13 +72,25 @@ static inline void *netlbl_netlink_hdr_put(struct sk_buff *skb,
NETLBL_PROTO_VERSION);
}
/**
* netlbl_netlink_auditinfo - Fetch the audit information from a NETLINK msg
* @skb: the packet
* @audit_info: NetLabel audit information
*/
static inline void netlbl_netlink_auditinfo(struct sk_buff *skb,
struct netlbl_audit *audit_info)
{
audit_info->secid = NETLINK_CB(skb).sid;
audit_info->loginuid = NETLINK_CB(skb).loginuid;
}
/* NetLabel NETLINK I/O functions */
int netlbl_netlink_init(void);
/* NetLabel Audit Functions */
struct audit_buffer *netlbl_audit_start_common(int type, u32 secid);
void netlbl_audit_nomsg(int type, u32 secid);
struct audit_buffer *netlbl_audit_start_common(int type,
struct netlbl_audit *audit_info);
#endif
......@@ -218,12 +218,6 @@ int sctp_rcv(struct sk_buff *skb)
}
}
/* SCTP seems to always need a timestamp right now (FIXME) */
if (skb->tstamp.off_sec == 0) {
__net_timestamp(skb);
sock_enable_timestamp(sk);
}
if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family))
goto discard_release;
nf_reset(skb);
......@@ -388,7 +382,7 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
* pmtu discovery on this transport.
*/
t->pathmtu = SCTP_DEFAULT_MINSEGMENT;
t->param_flags = (t->param_flags & ~SPP_HB) |
t->param_flags = (t->param_flags & ~SPP_PMTUD) |
SPP_PMTUD_DISABLE;
} else {
t->pathmtu = pmtu;
......
......@@ -633,7 +633,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* data will fit or delay in hopes of bundling a full
* sized packet.
*/
if (len < asoc->pathmtu - packet->overhead) {
if (len < asoc->frag_point) {
retval = SCTP_XMIT_NAGLE_DELAY;
goto finish;
}
......@@ -645,7 +645,13 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
/* Keep track of how many bytes are in flight to the receiver. */
asoc->outqueue.outstanding_bytes += datasize;
/* Update our view of the receiver's rwnd. */
/* Update our view of the receiver's rwnd. Include sk_buff overhead
* while updating peer.rwnd so that it reduces the chances of a
* receiver running out of receive buffer space even when receive
* window is still open. This can happen when a sender is sending
* sending small messages.
*/
datasize += sizeof(struct sk_buff);
if (datasize < rwnd)
rwnd -= datasize;
else
......
......@@ -416,7 +416,8 @@ void sctp_retransmit_mark(struct sctp_outq *q,
* (Section 7.2.4)), add the data size of those
* chunks to the rwnd.
*/
q->asoc->peer.rwnd += sctp_data_size(chunk);
q->asoc->peer.rwnd += (sctp_data_size(chunk) +
sizeof(struct sk_buff));
q->outstanding_bytes -= sctp_data_size(chunk);
transport->flight_size -= sctp_data_size(chunk);
......
......@@ -1447,8 +1447,16 @@ struct sctp_association *sctp_unpack_cookie(
/* Check to see if the cookie is stale. If there is already
* an association, there is no need to check cookie's expiration
* for init collision case of lost COOKIE ACK.
* If skb has been timestamped, then use the stamp, otherwise
* use current time. This introduces a small possibility that
* that a cookie may be considered expired, but his would only slow
* down the new association establishment instead of every packet.
*/
if (sock_flag(ep->base.sk, SOCK_TIMESTAMP))
skb_get_timestamp(skb, &tv);
else
do_gettimeofday(&tv);
if (!asoc && tv_lt(bear_cookie->expiration, tv)) {
__u16 len;
/*
......
......@@ -3084,8 +3084,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
*/
sp->disable_fragments = 0;
/* Turn on/off any Nagle-like algorithm. */
sp->nodelay = 1;
/* Enable Nagle algorithm by default. */
sp->nodelay = 0;
/* Enable by default. */
sp->v4mapped = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment