Commit c3a93e09 authored by Chas Williams's avatar Chas Williams Committed by David S. Miller

[ATM]: lane and mpoa module refcounting and locking cleanup.

parent 29146e24
...@@ -32,21 +32,61 @@ ...@@ -32,21 +32,61 @@
#include <linux/atmlec.h> #include <linux/atmlec.h>
#include "lec.h" #include "lec.h"
#include "lec_arpc.h" #include "lec_arpc.h"
struct atm_lane_ops atm_lane_ops; struct atm_lane_ops *atm_lane_ops;
#endif static DECLARE_MUTEX(atm_lane_ops_mutex);
#ifdef CONFIG_ATM_LANE_MODULE
void atm_lane_ops_set(struct atm_lane_ops *hook)
{
down(&atm_lane_ops_mutex);
atm_lane_ops = hook;
up(&atm_lane_ops_mutex);
}
int try_atm_lane_ops(void)
{
down(&atm_lane_ops_mutex);
if (atm_lane_ops && try_module_get(atm_lane_ops->owner)) {
up(&atm_lane_ops_mutex);
return 1;
}
up(&atm_lane_ops_mutex);
return 0;
}
#if defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_ATM_MPOA_MODULE)
EXPORT_SYMBOL(atm_lane_ops); EXPORT_SYMBOL(atm_lane_ops);
EXPORT_SYMBOL(try_atm_lane_ops);
EXPORT_SYMBOL(atm_lane_ops_set);
#endif
#endif #endif
#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
#include <linux/atmmpc.h> #include <linux/atmmpc.h>
#include "mpc.h" #include "mpc.h"
struct atm_mpoa_ops atm_mpoa_ops; struct atm_mpoa_ops *atm_mpoa_ops;
#endif static DECLARE_MUTEX(atm_mpoa_ops_mutex);
void atm_mpoa_ops_set(struct atm_mpoa_ops *hook)
{
down(&atm_mpoa_ops_mutex);
atm_mpoa_ops = hook;
up(&atm_mpoa_ops_mutex);
}
int try_atm_mpoa_ops(void)
{
down(&atm_mpoa_ops_mutex);
if (atm_mpoa_ops && try_module_get(atm_mpoa_ops->owner)) {
up(&atm_mpoa_ops_mutex);
return 1;
}
up(&atm_mpoa_ops_mutex);
return 0;
}
#ifdef CONFIG_ATM_MPOA_MODULE #ifdef CONFIG_ATM_MPOA_MODULE
EXPORT_SYMBOL(atm_mpoa_ops); EXPORT_SYMBOL(atm_mpoa_ops);
#ifndef CONFIG_ATM_LANE_MODULE EXPORT_SYMBOL(try_atm_mpoa_ops);
EXPORT_SYMBOL(atm_lane_ops); EXPORT_SYMBOL(atm_mpoa_ops_set);
#endif #endif
#endif #endif
...@@ -728,27 +768,40 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) ...@@ -728,27 +768,40 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
ret_val = -EPERM; ret_val = -EPERM;
goto done; goto done;
} }
if (atm_lane_ops.lecd_attach == NULL) #if defined(CONFIG_ATM_LANE_MODULE)
atm_lane_init(); if (!atm_lane_ops)
if (atm_lane_ops.lecd_attach == NULL) { /* try again */ request_module("lec");
ret_val = -ENOSYS; #endif
goto done; if (try_atm_lane_ops()) {
} error = atm_lane_ops->lecd_attach(vcc, (int) arg);
error = atm_lane_ops.lecd_attach(vcc, (int)arg); module_put(atm_lane_ops->owner);
if (error >= 0) sock->state = SS_CONNECTED; if (error >= 0)
sock->state = SS_CONNECTED;
ret_val = error; ret_val = error;
} else
ret_val = -ENOSYS;
goto done; goto done;
case ATMLEC_MCAST: case ATMLEC_MCAST:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; ret_val = -EPERM;
else goto done;
ret_val = atm_lane_ops.mcast_attach(vcc, (int)arg); }
if (try_atm_lane_ops()) {
ret_val = atm_lane_ops->mcast_attach(vcc, (int) arg);
module_put(atm_lane_ops->owner);
} else
ret_val = -ENOSYS;
goto done; goto done;
case ATMLEC_DATA: case ATMLEC_DATA:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; ret_val = -EPERM;
else goto done;
ret_val = atm_lane_ops.vcc_attach(vcc, (void*)arg); }
if (try_atm_lane_ops()) {
ret_val = atm_lane_ops->vcc_attach(vcc, (void *) arg);
module_put(atm_lane_ops->owner);
} else
ret_val = -ENOSYS;
goto done; goto done;
#endif #endif
#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
...@@ -757,21 +810,29 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) ...@@ -757,21 +810,29 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
ret_val = -EPERM; ret_val = -EPERM;
goto done; goto done;
} }
if (atm_mpoa_ops.mpoad_attach == NULL) #if defined(CONFIG_ATM_MPOA_MODULE)
atm_mpoa_init(); if (!atm_mpoa_ops)
if (atm_mpoa_ops.mpoad_attach == NULL) { /* try again */ request_module("mpoa");
ret_val = -ENOSYS; #endif
goto done; if (try_atm_mpoa_ops()) {
} error = atm_mpoa_ops->mpoad_attach(vcc, (int) arg);
error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg); module_put(atm_mpoa_ops->owner);
if (error >= 0) sock->state = SS_CONNECTED; if (error >= 0)
sock->state = SS_CONNECTED;
ret_val = error; ret_val = error;
} else
ret_val = -ENOSYS;
goto done; goto done;
case ATMMPC_DATA: case ATMMPC_DATA:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; ret_val = -EPERM;
else goto done;
ret_val = atm_mpoa_ops.vcc_attach(vcc, arg); }
if (try_atm_mpoa_ops()) {
ret_val = atm_mpoa_ops->vcc_attach(vcc, arg);
module_put(atm_mpoa_ops->owner);
} else
ret_val = -ENOSYS;
goto done; goto done;
#endif #endif
#if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
...@@ -1155,40 +1216,6 @@ int atm_getsockopt(struct socket *sock,int level,int optname, ...@@ -1155,40 +1216,6 @@ int atm_getsockopt(struct socket *sock,int level,int optname,
} }
/*
* lane_mpoa_init.c: A couple of helper functions
* to make modular LANE and MPOA client easier to implement
*/
/*
* This is how it goes:
*
* if xxxx is not compiled as module, call atm_xxxx_init_ops()
* from here
* else call atm_mpoa_init_ops() from init_module() within
* the kernel when xxxx module is loaded
*
* In either case function pointers in struct atm_xxxx_ops
* are initialized to their correct values. Either they
* point to functions in the module or in the kernel
*/
extern struct atm_mpoa_ops atm_mpoa_ops; /* in common.c */
extern struct atm_lane_ops atm_lane_ops; /* in common.c */
#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
void atm_mpoa_init(void)
{
#ifndef CONFIG_ATM_MPOA_MODULE /* not module */
atm_mpoa_init_ops(&atm_mpoa_ops);
#else
request_module("mpoa");
#endif
return;
}
#endif
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
...@@ -1199,18 +1226,8 @@ EXPORT_SYMBOL(br_fdb_get_hook); ...@@ -1199,18 +1226,8 @@ EXPORT_SYMBOL(br_fdb_get_hook);
EXPORT_SYMBOL(br_fdb_put_hook); EXPORT_SYMBOL(br_fdb_put_hook);
#endif /* defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE) */ #endif /* defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE) */
#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
#endif /* defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) */
void atm_lane_init(void)
{
#ifndef CONFIG_ATM_LANE_MODULE /* not module */
atm_lane_init_ops(&atm_lane_ops);
#else
request_module("lec");
#endif
return;
}
#endif
static int __init atm_init(void) static int __init atm_init(void)
{ {
......
...@@ -56,8 +56,6 @@ extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent); ...@@ -56,8 +56,6 @@ extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
#define DPRINTK(format,args...) #define DPRINTK(format,args...)
#endif #endif
static spinlock_t lec_arp_spinlock = SPIN_LOCK_UNLOCKED;
#define DUMP_PACKETS 0 /* 0 = None, #define DUMP_PACKETS 0 /* 0 = None,
* 1 = 30 first bytes * 1 = 30 first bytes
* 2 = Whole packet * 2 = Whole packet
...@@ -71,9 +69,9 @@ static int lec_send_packet(struct sk_buff *skb, struct net_device *dev); ...@@ -71,9 +69,9 @@ static int lec_send_packet(struct sk_buff *skb, struct net_device *dev);
static int lec_close(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 struct net_device_stats *lec_get_stats(struct net_device *dev);
static void lec_init(struct net_device *dev); static void lec_init(struct net_device *dev);
static __inline__ struct lec_arp_table* lec_arp_find(struct lec_priv *priv, static inline struct lec_arp_table* lec_arp_find(struct lec_priv *priv,
unsigned char *mac_addr); unsigned char *mac_addr);
static __inline__ int lec_arp_remove(struct lec_arp_table **lec_arp_tables, static inline int lec_arp_remove(struct lec_priv *priv,
struct lec_arp_table *to_remove); struct lec_arp_table *to_remove);
/* LANE2 functions */ /* 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,
...@@ -95,8 +93,18 @@ static unsigned char bus_mac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; ...@@ -95,8 +93,18 @@ static unsigned char bus_mac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
static struct net_device *dev_lec[MAX_LEC_ITF]; static struct net_device *dev_lec[MAX_LEC_ITF];
/* This will be called from proc.c via function pointer */ /* This will be called from proc.c via function pointer */
struct net_device **get_dev_lec (void) { struct net_device *get_dev_lec(int itf)
return &dev_lec[0]; {
struct net_device *dev;
if (itf >= MAX_LEC_ITF)
return NULL;
rtnl_lock();
dev = dev_lec[itf];
if (dev)
dev_hold(dev);
rtnl_unlock();
return dev;
} }
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
...@@ -426,7 +434,7 @@ lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -426,7 +434,7 @@ lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
break; break;
case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */ case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */
entry = lec_arp_find(priv, mesg->content.normal.mac_addr); entry = lec_arp_find(priv, mesg->content.normal.mac_addr);
lec_arp_remove(priv->lec_arp_tables, entry); lec_arp_remove(priv, entry);
if (mesg->content.normal.no_source_le_narp) if (mesg->content.normal.no_source_le_narp)
break; break;
...@@ -542,7 +550,7 @@ lec_atm_close(struct atm_vcc *vcc) ...@@ -542,7 +550,7 @@ lec_atm_close(struct atm_vcc *vcc)
} }
printk("%s: Shut down!\n", dev->name); printk("%s: Shut down!\n", dev->name);
MOD_DEC_USE_COUNT; module_put(THIS_MODULE);
} }
static struct atmdev_ops lecdev_ops = { static struct atmdev_ops lecdev_ops = {
...@@ -823,41 +831,32 @@ lecd_attach(struct atm_vcc *vcc, int arg) ...@@ -823,41 +831,32 @@ lecd_attach(struct atm_vcc *vcc, int arg)
if (dev_lec[i]->flags & IFF_UP) { if (dev_lec[i]->flags & IFF_UP) {
netif_start_queue(dev_lec[i]); netif_start_queue(dev_lec[i]);
} }
MOD_INC_USE_COUNT; __module_get(THIS_MODULE);
return i; return i;
} }
void atm_lane_init_ops(struct atm_lane_ops *ops) static struct atm_lane_ops __atm_lane_ops =
{ {
ops->lecd_attach = lecd_attach; .lecd_attach = lecd_attach,
ops->mcast_attach = lec_mcast_attach; .mcast_attach = lec_mcast_attach,
ops->vcc_attach = lec_vcc_attach; .vcc_attach = lec_vcc_attach,
ops->get_lecs = get_dev_lec; .get_lec = get_dev_lec,
.owner = THIS_MODULE
printk("lec.c: " __DATE__ " " __TIME__ " initialized\n"); };
return;
}
static int __init lane_module_init(void) static int __init lane_module_init(void)
{ {
extern struct atm_lane_ops atm_lane_ops; atm_lane_ops_set(&__atm_lane_ops);
printk("lec.c: " __DATE__ " " __TIME__ " initialized\n");
atm_lane_init_ops(&atm_lane_ops);
return 0; return 0;
} }
static void __exit lane_module_cleanup(void) static void __exit lane_module_cleanup(void)
{ {
int i; int i;
extern struct atm_lane_ops atm_lane_ops;
struct lec_priv *priv; struct lec_priv *priv;
atm_lane_ops.lecd_attach = NULL; atm_lane_ops_set(NULL);
atm_lane_ops.mcast_attach = NULL;
atm_lane_ops.vcc_attach = NULL;
atm_lane_ops.get_lecs = NULL;
for (i = 0; i < MAX_LEC_ITF; i++) { for (i = 0; i < MAX_LEC_ITF; i++) {
if (dev_lec[i] != NULL) { if (dev_lec[i] != NULL) {
...@@ -1067,6 +1066,7 @@ lec_arp_init(struct lec_priv *priv) ...@@ -1067,6 +1066,7 @@ lec_arp_init(struct lec_priv *priv)
for (i=0;i<LEC_ARP_TABLE_SIZE;i++) { for (i=0;i<LEC_ARP_TABLE_SIZE;i++) {
priv->lec_arp_tables[i] = NULL; priv->lec_arp_tables[i] = NULL;
} }
spin_lock_init(&priv->lec_arp_lock);
init_timer(&priv->lec_arp_timer); init_timer(&priv->lec_arp_timer);
priv->lec_arp_timer.expires = jiffies+LEC_ARP_REFRESH_INTERVAL; priv->lec_arp_timer.expires = jiffies+LEC_ARP_REFRESH_INTERVAL;
priv->lec_arp_timer.data = (unsigned long)priv; priv->lec_arp_timer.data = (unsigned long)priv;
...@@ -1103,21 +1103,20 @@ lec_arp_clear_vccs(struct lec_arp_table *entry) ...@@ -1103,21 +1103,20 @@ lec_arp_clear_vccs(struct lec_arp_table *entry)
* Insert entry to lec_arp_table * Insert entry to lec_arp_table
* LANE2: Add to the end of the list to satisfy 8.1.13 * LANE2: Add to the end of the list to satisfy 8.1.13
*/ */
static __inline__ void static inline void
lec_arp_add(struct lec_arp_table **lec_arp_tables, lec_arp_add(struct lec_priv *priv, struct lec_arp_table *to_add)
struct lec_arp_table *to_add)
{ {
unsigned long flags; unsigned long flags;
unsigned short place; unsigned short place;
struct lec_arp_table *tmp; struct lec_arp_table *tmp;
spin_lock_irqsave(&lec_arp_spinlock, flags); spin_lock_irqsave(&priv->lec_arp_lock, flags);
place = HASH(to_add->mac_addr[ETH_ALEN-1]); place = HASH(to_add->mac_addr[ETH_ALEN-1]);
tmp = lec_arp_tables[place]; tmp = priv->lec_arp_tables[place];
to_add->next = NULL; to_add->next = NULL;
if (tmp == NULL) if (tmp == NULL)
lec_arp_tables[place] = to_add; priv->lec_arp_tables[place] = to_add;
else { /* add to the end */ else { /* add to the end */
while (tmp->next) while (tmp->next)
...@@ -1125,7 +1124,7 @@ lec_arp_add(struct lec_arp_table **lec_arp_tables, ...@@ -1125,7 +1124,7 @@ lec_arp_add(struct lec_arp_table **lec_arp_tables,
tmp->next = to_add; tmp->next = to_add;
} }
spin_unlock_irqrestore(&lec_arp_spinlock, flags); spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", 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[0], 0xff&to_add->mac_addr[1],
...@@ -1136,8 +1135,8 @@ lec_arp_add(struct lec_arp_table **lec_arp_tables, ...@@ -1136,8 +1135,8 @@ lec_arp_add(struct lec_arp_table **lec_arp_tables,
/* /*
* Remove entry from lec_arp_table * Remove entry from lec_arp_table
*/ */
static __inline__ int static inline int
lec_arp_remove(struct lec_arp_table **lec_arp_tables, lec_arp_remove(struct lec_priv *priv,
struct lec_arp_table *to_remove) struct lec_arp_table *to_remove)
{ {
unsigned long flags; unsigned long flags;
...@@ -1145,22 +1144,22 @@ lec_arp_remove(struct lec_arp_table **lec_arp_tables, ...@@ -1145,22 +1144,22 @@ lec_arp_remove(struct lec_arp_table **lec_arp_tables,
struct lec_arp_table *tmp; struct lec_arp_table *tmp;
int remove_vcc=1; int remove_vcc=1;
spin_lock_irqsave(&lec_arp_spinlock, flags); spin_lock_irqsave(&priv->lec_arp_lock, flags);
if (!to_remove) { if (!to_remove) {
spin_unlock_irqrestore(&lec_arp_spinlock, flags); spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
return -1; return -1;
} }
place = HASH(to_remove->mac_addr[ETH_ALEN-1]); place = HASH(to_remove->mac_addr[ETH_ALEN-1]);
tmp = lec_arp_tables[place]; tmp = priv->lec_arp_tables[place];
if (tmp == to_remove) { if (tmp == to_remove) {
lec_arp_tables[place] = tmp->next; priv->lec_arp_tables[place] = tmp->next;
} else { } else {
while(tmp && tmp->next != to_remove) { while(tmp && tmp->next != to_remove) {
tmp = tmp->next; tmp = tmp->next;
} }
if (!tmp) {/* Entry was not found */ if (!tmp) {/* Entry was not found */
spin_unlock_irqrestore(&lec_arp_spinlock, flags); spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
return -1; return -1;
} }
} }
...@@ -1174,7 +1173,7 @@ lec_arp_remove(struct lec_arp_table **lec_arp_tables, ...@@ -1174,7 +1173,7 @@ lec_arp_remove(struct lec_arp_table **lec_arp_tables,
* ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT
*/ */
for(place=0;place<LEC_ARP_TABLE_SIZE;place++) { for(place=0;place<LEC_ARP_TABLE_SIZE;place++) {
for(tmp=lec_arp_tables[place];tmp!=NULL;tmp=tmp->next){ for(tmp = priv->lec_arp_tables[place]; tmp != NULL; tmp = tmp->next) {
if (memcmp(tmp->atm_addr, to_remove->atm_addr, if (memcmp(tmp->atm_addr, to_remove->atm_addr,
ATM_ESA_LEN)==0) { ATM_ESA_LEN)==0) {
remove_vcc=0; remove_vcc=0;
...@@ -1187,7 +1186,7 @@ lec_arp_remove(struct lec_arp_table **lec_arp_tables, ...@@ -1187,7 +1186,7 @@ lec_arp_remove(struct lec_arp_table **lec_arp_tables,
} }
skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */ skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */
spin_unlock_irqrestore(&lec_arp_spinlock, flags); spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", 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[0], 0xff&to_remove->mac_addr[1],
...@@ -1383,7 +1382,7 @@ lec_arp_destroy(struct lec_priv *priv) ...@@ -1383,7 +1382,7 @@ lec_arp_destroy(struct lec_priv *priv)
for (i=0;i<LEC_ARP_TABLE_SIZE;i++) { for (i=0;i<LEC_ARP_TABLE_SIZE;i++) {
for(entry =priv->lec_arp_tables[i];entry != NULL; entry=next) { for(entry =priv->lec_arp_tables[i];entry != NULL; entry=next) {
next = entry->next; next = entry->next;
lec_arp_remove(priv->lec_arp_tables, entry); lec_arp_remove(priv, entry);
kfree(entry); kfree(entry);
} }
} }
...@@ -1423,7 +1422,7 @@ lec_arp_destroy(struct lec_priv *priv) ...@@ -1423,7 +1422,7 @@ lec_arp_destroy(struct lec_priv *priv)
/* /*
* Find entry by mac_address * Find entry by mac_address
*/ */
static __inline__ struct lec_arp_table* static inline struct lec_arp_table*
lec_arp_find(struct lec_priv *priv, lec_arp_find(struct lec_priv *priv,
unsigned char *mac_addr) unsigned char *mac_addr)
{ {
...@@ -1561,8 +1560,6 @@ static void ...@@ -1561,8 +1560,6 @@ static void
lec_arp_check_expire(unsigned long data) lec_arp_check_expire(unsigned long data)
{ {
struct lec_priv *priv = (struct lec_priv *)data; struct lec_priv *priv = (struct lec_priv *)data;
struct lec_arp_table **lec_arp_tables =
(struct lec_arp_table **)priv->lec_arp_tables;
struct lec_arp_table *entry, *next; struct lec_arp_table *entry, *next;
unsigned long now; unsigned long now;
unsigned long time_to_check; unsigned long time_to_check;
...@@ -1578,7 +1575,7 @@ lec_arp_check_expire(unsigned long data) ...@@ -1578,7 +1575,7 @@ lec_arp_check_expire(unsigned long data)
lec_arp_get(priv); lec_arp_get(priv);
now = jiffies; now = jiffies;
for(i=0;i<LEC_ARP_TABLE_SIZE;i++) { for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
for(entry = lec_arp_tables[i];entry != NULL;) { for(entry = priv->lec_arp_tables[i]; entry != NULL; ) {
if ((entry->flags) & LEC_REMOTE_FLAG && if ((entry->flags) & LEC_REMOTE_FLAG &&
priv->topology_change) priv->topology_change)
time_to_check=priv->forward_delay_time; time_to_check=priv->forward_delay_time;
...@@ -1594,7 +1591,7 @@ lec_arp_check_expire(unsigned long data) ...@@ -1594,7 +1591,7 @@ lec_arp_check_expire(unsigned long data)
/* Remove entry */ /* Remove entry */
DPRINTK("LEC:Entry timed out\n"); DPRINTK("LEC:Entry timed out\n");
next = entry->next; next = entry->next;
lec_arp_remove(lec_arp_tables, entry); lec_arp_remove(priv, entry);
kfree(entry); kfree(entry);
entry = next; entry = next;
} else { } else {
...@@ -1687,7 +1684,7 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, int is_rdesc, ...@@ -1687,7 +1684,7 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, int is_rdesc,
if (!entry) { if (!entry) {
return priv->mcast_vcc; return priv->mcast_vcc;
} }
lec_arp_add(priv->lec_arp_tables, entry); lec_arp_add(priv, entry);
/* We want arp-request(s) to be sent */ /* We want arp-request(s) to be sent */
entry->packets_flooded =1; entry->packets_flooded =1;
entry->status = ESI_ARP_PENDING; entry->status = ESI_ARP_PENDING;
...@@ -1720,7 +1717,7 @@ lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, ...@@ -1720,7 +1717,7 @@ lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN) if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)
&& (permanent || && (permanent ||
!(entry->flags & LEC_PERMANENT_FLAG))) { !(entry->flags & LEC_PERMANENT_FLAG))) {
lec_arp_remove(priv->lec_arp_tables, entry); lec_arp_remove(priv, entry);
kfree(entry); kfree(entry);
} }
lec_arp_put(priv); lec_arp_put(priv);
...@@ -1786,7 +1783,7 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, ...@@ -1786,7 +1783,7 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
entry->status = ESI_FORWARD_DIRECT; entry->status = ESI_FORWARD_DIRECT;
memcpy(entry->mac_addr, mac_addr, ETH_ALEN); memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
entry->last_used = jiffies; entry->last_used = jiffies;
lec_arp_add(priv->lec_arp_tables, entry); lec_arp_add(priv, entry);
} }
if (remoteflag) if (remoteflag)
entry->flags|=LEC_REMOTE_FLAG; entry->flags|=LEC_REMOTE_FLAG;
...@@ -1806,7 +1803,7 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, ...@@ -1806,7 +1803,7 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
return; return;
} }
entry->status = ESI_UNKNOWN; entry->status = ESI_UNKNOWN;
lec_arp_add(priv->lec_arp_tables, entry); lec_arp_add(priv, entry);
/* Temporary, changes before end of function */ /* Temporary, changes before end of function */
} }
memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN); memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
...@@ -2057,7 +2054,7 @@ lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc) ...@@ -2057,7 +2054,7 @@ lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
to_add->old_push = vcc->push; to_add->old_push = vcc->push;
vcc->push = lec_push; vcc->push = lec_push;
priv->mcast_vcc = vcc; priv->mcast_vcc = vcc;
lec_arp_add(priv->lec_arp_tables, to_add); lec_arp_add(priv, to_add);
lec_arp_put(priv); lec_arp_put(priv);
return 0; return 0;
} }
...@@ -2075,7 +2072,7 @@ lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc) ...@@ -2075,7 +2072,7 @@ lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
for(entry = priv->lec_arp_tables[i];entry; entry=next) { for(entry = priv->lec_arp_tables[i];entry; entry=next) {
next = entry->next; next = entry->next;
if (vcc == entry->vcc) { if (vcc == entry->vcc) {
lec_arp_remove(priv->lec_arp_tables,entry); lec_arp_remove(priv, entry);
kfree(entry); kfree(entry);
if (priv->mcast_vcc == vcc) { if (priv->mcast_vcc == vcc) {
priv->mcast_vcc = NULL; priv->mcast_vcc = NULL;
...@@ -2155,23 +2152,23 @@ lec_arp_check_empties(struct lec_priv *priv, ...@@ -2155,23 +2152,23 @@ lec_arp_check_empties(struct lec_priv *priv,
lec_arp_get(priv); lec_arp_get(priv);
entry = priv->lec_arp_empty_ones; entry = priv->lec_arp_empty_ones;
if (vcc == entry->vcc) { if (vcc == entry->vcc) {
spin_lock_irqsave(&lec_arp_spinlock, flags); spin_lock_irqsave(&priv->lec_arp_lock, flags);
del_timer(&entry->timer); del_timer(&entry->timer);
memcpy(entry->mac_addr, src, ETH_ALEN); memcpy(entry->mac_addr, src, ETH_ALEN);
entry->status = ESI_FORWARD_DIRECT; entry->status = ESI_FORWARD_DIRECT;
entry->last_used = jiffies; entry->last_used = jiffies;
priv->lec_arp_empty_ones = entry->next; priv->lec_arp_empty_ones = entry->next;
spin_unlock_irqrestore(&lec_arp_spinlock, flags); spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
/* We might have got an entry */ /* We might have got an entry */
if ((prev=lec_arp_find(priv,src))) { if ((prev=lec_arp_find(priv,src))) {
lec_arp_remove(priv->lec_arp_tables, prev); lec_arp_remove(priv, prev);
kfree(prev); kfree(prev);
} }
lec_arp_add(priv->lec_arp_tables, entry); lec_arp_add(priv, entry);
lec_arp_put(priv); lec_arp_put(priv);
return; return;
} }
spin_lock_irqsave(&lec_arp_spinlock, flags); spin_lock_irqsave(&priv->lec_arp_lock, flags);
prev = entry; prev = entry;
entry = entry->next; entry = entry->next;
while (entry && entry->vcc != vcc) { while (entry && entry->vcc != vcc) {
...@@ -2181,7 +2178,7 @@ lec_arp_check_empties(struct lec_priv *priv, ...@@ -2181,7 +2178,7 @@ lec_arp_check_empties(struct lec_priv *priv,
if (!entry) { if (!entry) {
DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n"); DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n");
lec_arp_put(priv); lec_arp_put(priv);
spin_unlock_irqrestore(&lec_arp_spinlock, flags); spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
return; return;
} }
del_timer(&entry->timer); del_timer(&entry->timer);
...@@ -2189,12 +2186,12 @@ lec_arp_check_empties(struct lec_priv *priv, ...@@ -2189,12 +2186,12 @@ lec_arp_check_empties(struct lec_priv *priv,
entry->status = ESI_FORWARD_DIRECT; entry->status = ESI_FORWARD_DIRECT;
entry->last_used = jiffies; entry->last_used = jiffies;
prev->next = entry->next; prev->next = entry->next;
spin_unlock_irqrestore(&lec_arp_spinlock, flags); spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
if ((prev = lec_arp_find(priv, src))) { if ((prev = lec_arp_find(priv, src))) {
lec_arp_remove(priv->lec_arp_tables,prev); lec_arp_remove(priv, prev);
kfree(prev); kfree(prev);
} }
lec_arp_add(priv->lec_arp_tables,entry); lec_arp_add(priv, entry);
lec_arp_put(priv); lec_arp_put(priv);
} }
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -64,7 +64,8 @@ struct atm_lane_ops { ...@@ -64,7 +64,8 @@ struct atm_lane_ops {
int (*lecd_attach)(struct atm_vcc *vcc, int arg); int (*lecd_attach)(struct atm_vcc *vcc, int arg);
int (*mcast_attach)(struct atm_vcc *vcc, int arg); int (*mcast_attach)(struct atm_vcc *vcc, int arg);
int (*vcc_attach)(struct atm_vcc *vcc, void *arg); int (*vcc_attach)(struct atm_vcc *vcc, void *arg);
struct net_device **(*get_lecs)(void); struct net_device * (*get_lec)(int itf);
struct module *owner;
}; };
/* /*
...@@ -102,6 +103,7 @@ struct lec_priv { ...@@ -102,6 +103,7 @@ struct lec_priv {
collects all those VCCs. LANEv1 client has only one item in this collects all those VCCs. LANEv1 client has only one item in this
list. These entries are not aged out. */ list. These entries are not aged out. */
atomic_t lec_arp_users; atomic_t lec_arp_users;
spinlock_t lec_arp_lock;
struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */ struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
struct atm_vcc *lecd; struct atm_vcc *lecd;
struct timer_list lec_arp_timer; struct timer_list lec_arp_timer;
...@@ -148,14 +150,16 @@ struct lec_priv { ...@@ -148,14 +150,16 @@ struct lec_priv {
int lecd_attach(struct atm_vcc *vcc, int arg); int lecd_attach(struct atm_vcc *vcc, int arg);
int lec_vcc_attach(struct atm_vcc *vcc, void *arg); int lec_vcc_attach(struct atm_vcc *vcc, void *arg);
int lec_mcast_attach(struct atm_vcc *vcc, int arg); int lec_mcast_attach(struct atm_vcc *vcc, int arg);
struct net_device **get_dev_lec(void); struct net_device *get_dev_lec(int itf);
int make_lec(struct atm_vcc *vcc); int make_lec(struct atm_vcc *vcc);
int send_to_lecd(struct lec_priv *priv, int send_to_lecd(struct lec_priv *priv,
atmlec_msg_type type, unsigned char *mac_addr, atmlec_msg_type type, unsigned char *mac_addr,
unsigned char *atm_addr, struct sk_buff *data); unsigned char *atm_addr, struct sk_buff *data);
void lec_push(struct atm_vcc *vcc, struct sk_buff *skb); void lec_push(struct atm_vcc *vcc, struct sk_buff *skb);
void atm_lane_init(void); extern struct atm_lane_ops *atm_lane_ops;
void atm_lane_init_ops(struct atm_lane_ops *ops); void atm_lane_ops_set(struct atm_lane_ops *hook);
int try_atm_lane_ops(void);
#endif /* _LEC_H_ */ #endif /* _LEC_H_ */
...@@ -251,12 +251,13 @@ void atm_mpoa_disp_qos(char *page, int *len) ...@@ -251,12 +251,13 @@ void atm_mpoa_disp_qos(char *page, int *len)
static struct net_device *find_lec_by_itfnum(int itf) static struct net_device *find_lec_by_itfnum(int itf)
{ {
extern struct atm_lane_ops atm_lane_ops; /* in common.c */ struct net_device *dev;
if (!try_atm_lane_ops())
if (atm_lane_ops.get_lecs == NULL)
return NULL; return NULL;
return atm_lane_ops.get_lecs()[itf]; /* FIXME: something better */ dev = atm_lane_ops->get_lec(itf);
module_put(atm_lane_ops->owner);
return dev;
} }
static struct mpoa_client *alloc_mpc(void) static struct mpoa_client *alloc_mpc(void)
...@@ -779,9 +780,10 @@ int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg) ...@@ -779,9 +780,10 @@ int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
if (mpc->dev) { /* check if the lec is LANE2 capable */ if (mpc->dev) { /* check if the lec is LANE2 capable */
priv = (struct lec_priv *)mpc->dev->priv; priv = (struct lec_priv *)mpc->dev->priv;
if (priv->lane_version < 2) if (priv->lane_version < 2) {
dev_put(mpc->dev);
mpc->dev = NULL; mpc->dev = NULL;
else } else
priv->lane2_ops->associate_indicator = lane2_assoc_ind; priv->lane2_ops->associate_indicator = lane2_assoc_ind;
} }
...@@ -802,7 +804,7 @@ int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg) ...@@ -802,7 +804,7 @@ int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc); send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc);
} }
MOD_INC_USE_COUNT; __module_get(THIS_MODULE);
return arg; return arg;
} }
...@@ -839,6 +841,7 @@ static void mpoad_close(struct atm_vcc *vcc) ...@@ -839,6 +841,7 @@ static void mpoad_close(struct atm_vcc *vcc)
struct lec_priv *priv = (struct lec_priv *)mpc->dev->priv; struct lec_priv *priv = (struct lec_priv *)mpc->dev->priv;
priv->lane2_ops->associate_indicator = NULL; priv->lane2_ops->associate_indicator = NULL;
stop_mpc(mpc); stop_mpc(mpc);
dev_put(mpc->dev);
} }
mpc->in_ops->destroy_cache(mpc); mpc->in_ops->destroy_cache(mpc);
...@@ -851,7 +854,7 @@ static void mpoad_close(struct atm_vcc *vcc) ...@@ -851,7 +854,7 @@ static void mpoad_close(struct atm_vcc *vcc)
printk("mpoa: (%s) going down\n", printk("mpoa: (%s) going down\n",
(mpc->dev) ? mpc->dev->name : "<unknown>"); (mpc->dev) ? mpc->dev->name : "<unknown>");
MOD_DEC_USE_COUNT; module_put(THIS_MODULE);
return; return;
} }
...@@ -975,6 +978,7 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo ...@@ -975,6 +978,7 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo
} }
mpc->dev_num = priv->itfnum; mpc->dev_num = priv->itfnum;
mpc->dev = dev; mpc->dev = dev;
dev_hold(dev);
dprintk("mpoa: (%s) was initialized\n", dev->name); dprintk("mpoa: (%s) was initialized\n", dev->name);
break; break;
case NETDEV_UNREGISTER: case NETDEV_UNREGISTER:
...@@ -984,6 +988,7 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo ...@@ -984,6 +988,7 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo
break; break;
dprintk("mpoa: device (%s) was deallocated\n", dev->name); dprintk("mpoa: device (%s) was deallocated\n", dev->name);
stop_mpc(mpc); stop_mpc(mpc);
dev_put(mpc->dev);
mpc->dev = NULL; mpc->dev = NULL;
break; break;
case NETDEV_UP: case NETDEV_UP:
...@@ -1393,13 +1398,18 @@ static void mpc_cache_check( unsigned long checking_time ) ...@@ -1393,13 +1398,18 @@ static void mpc_cache_check( unsigned long checking_time )
return; return;
} }
void atm_mpoa_init_ops(struct atm_mpoa_ops *ops) static struct atm_mpoa_ops __atm_mpoa_ops = {
.mpoad_attach = atm_mpoa_mpoad_attach,
.vcc_attach = atm_mpoa_vcc_attach,
.owner = THIS_MODULE
};
static __init int atm_mpoa_init(void)
{ {
ops->mpoad_attach = atm_mpoa_mpoad_attach; atm_mpoa_ops_set(&__atm_mpoa_ops);
ops->vcc_attach = atm_mpoa_vcc_attach;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
if(mpc_proc_init() != 0) if (mpc_proc_init() != 0)
printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n"); printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n");
else else
printk(KERN_INFO "mpoa: /proc/mpoa initialized\n"); printk(KERN_INFO "mpoa: /proc/mpoa initialized\n");
...@@ -1407,22 +1417,11 @@ void atm_mpoa_init_ops(struct atm_mpoa_ops *ops) ...@@ -1407,22 +1417,11 @@ void atm_mpoa_init_ops(struct atm_mpoa_ops *ops)
printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n"); printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n");
return;
}
#ifdef MODULE
int init_module(void)
{
extern struct atm_mpoa_ops atm_mpoa_ops;
atm_mpoa_init_ops(&atm_mpoa_ops);
return 0; return 0;
} }
void cleanup_module(void) void __exit atm_mpoa_cleanup(void)
{ {
extern struct atm_mpoa_ops atm_mpoa_ops;
struct mpoa_client *mpc, *tmp; struct mpoa_client *mpc, *tmp;
struct atm_mpoa_qos *qos, *nextqos; struct atm_mpoa_qos *qos, *nextqos;
struct lec_priv *priv; struct lec_priv *priv;
...@@ -1433,8 +1432,7 @@ void cleanup_module(void) ...@@ -1433,8 +1432,7 @@ void cleanup_module(void)
del_timer(&mpc_timer); del_timer(&mpc_timer);
unregister_netdevice_notifier(&mpoa_notifier); unregister_netdevice_notifier(&mpoa_notifier);
atm_mpoa_ops.mpoad_attach = NULL; atm_mpoa_ops_set(NULL);
atm_mpoa_ops.vcc_attach = NULL;
mpc = mpcs; mpc = mpcs;
mpcs = NULL; mpcs = NULL;
...@@ -1469,5 +1467,8 @@ void cleanup_module(void) ...@@ -1469,5 +1467,8 @@ void cleanup_module(void)
return; return;
} }
#endif /* MODULE */
module_init(atm_mpoa_init);
module_exit(atm_mpoa_cleanup);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -48,11 +48,13 @@ struct atm_mpoa_qos { ...@@ -48,11 +48,13 @@ struct atm_mpoa_qos {
struct atm_mpoa_ops { struct atm_mpoa_ops {
int (*mpoad_attach)(struct atm_vcc *vcc, int arg); /* attach mpoa daemon */ int (*mpoad_attach)(struct atm_vcc *vcc, int arg); /* attach mpoa daemon */
int (*vcc_attach)(struct atm_vcc *vcc, long arg); /* attach shortcut vcc */ int (*vcc_attach)(struct atm_vcc *vcc, long arg); /* attach shortcut vcc */
struct module *owner;
}; };
/* Boot/module initialization function */ /* Boot/module initialization function */
void atm_mpoa_init(void); extern struct atm_mpoa_ops *atm_mpoa_ops;
void atm_mpoa_init_ops(struct atm_mpoa_ops *ops); int try_atm_mpoa_ops(void);
void atm_mpoa_ops_set(struct atm_mpoa_ops *hook);
/* MPOA QoS operations */ /* MPOA QoS operations */
struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos); struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos);
......
...@@ -47,7 +47,6 @@ ...@@ -47,7 +47,6 @@
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
#include "lec.h" #include "lec.h"
#include "lec_arpc.h" #include "lec_arpc.h"
extern struct atm_lane_ops atm_lane_ops; /* in common.c */
#endif #endif
static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count, static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count,
...@@ -481,57 +480,72 @@ static int atm_arp_info(loff_t pos,char *buf) ...@@ -481,57 +480,72 @@ static int atm_arp_info(loff_t pos,char *buf)
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
static int atm_lec_info(loff_t pos,char *buf) static int atm_lec_info(loff_t pos,char *buf)
{ {
unsigned long flags;
struct lec_priv *priv; struct lec_priv *priv;
struct lec_arp_table *entry; struct lec_arp_table *entry;
int i, count, d, e; int i, count, d, e;
struct net_device **dev_lec; struct net_device *dev;
if (!pos) { if (!pos) {
return sprintf(buf,"Itf MAC ATM destination" return sprintf(buf,"Itf MAC ATM destination"
" Status Flags " " Status Flags "
"VPI/VCI Recv VPI/VCI\n"); "VPI/VCI Recv VPI/VCI\n");
} }
if (atm_lane_ops.get_lecs == NULL) if (!try_atm_lane_ops())
return 0; /* the lane module is not there yet */ return 0; /* the lane module is not there yet */
else
dev_lec = atm_lane_ops.get_lecs();
count = pos; count = pos;
for(d=0;d<MAX_LEC_ITF;d++) { for(d = 0; d < MAX_LEC_ITF; d++) {
if (!dev_lec[d] || !(priv = dev = atm_lane_ops->get_lec(d);
(struct lec_priv *) dev_lec[d]->priv)) continue; if (!dev || !(priv = (struct lec_priv *) dev->priv))
for(i=0;i<LEC_ARP_TABLE_SIZE;i++) { continue;
entry = priv->lec_arp_tables[i]; spin_lock_irqsave(&priv->lec_arp_lock, flags);
for(;entry;entry=entry->next) { for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
if (--count) continue; for(entry = priv->lec_arp_tables[i]; entry; entry = entry->next) {
e=sprintf(buf,"%s ", if (--count)
dev_lec[d]->name); continue;
lec_info(entry,buf+e); e = sprintf(buf,"%s ", dev->name);
lec_info(entry, buf+e);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
dev_put(dev);
module_put(atm_lane_ops->owner);
return strlen(buf); return strlen(buf);
} }
} }
for(entry=priv->lec_arp_empty_ones; entry; for(entry = priv->lec_arp_empty_ones; entry; entry = entry->next) {
entry=entry->next) { if (--count)
if (--count) continue; continue;
e=sprintf(buf,"%s ",dev_lec[d]->name); e = sprintf(buf,"%s ", dev->name);
lec_info(entry, buf+e); lec_info(entry, buf+e);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
dev_put(dev);
module_put(atm_lane_ops->owner);
return strlen(buf); return strlen(buf);
} }
for(entry=priv->lec_no_forward; entry; for(entry = priv->lec_no_forward; entry; entry=entry->next) {
entry=entry->next) { if (--count)
if (--count) continue; continue;
e=sprintf(buf,"%s ",dev_lec[d]->name); e = sprintf(buf,"%s ", dev->name);
lec_info(entry, buf+e); lec_info(entry, buf+e);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
dev_put(dev);
module_put(atm_lane_ops->owner);
return strlen(buf); return strlen(buf);
} }
for(entry=priv->mcast_fwds; entry; for(entry = priv->mcast_fwds; entry; entry = entry->next) {
entry=entry->next) { if (--count)
if (--count) continue; continue;
e=sprintf(buf,"%s ",dev_lec[d]->name); e = sprintf(buf,"%s ", dev->name);
lec_info(entry, buf+e); lec_info(entry, buf+e);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
dev_put(dev);
module_put(atm_lane_ops->owner);
return strlen(buf); return strlen(buf);
} }
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
dev_put(dev);
} }
module_put(atm_lane_ops->owner);
return 0; return 0;
} }
#endif #endif
......
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