#define MWL8K_ENABLE_RX_MULTICAST 0x000F
-static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
- int mc_count,
- struct dev_addr_list *mclist)
+static struct mwl8k_cmd_pkt *
+__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
+ int mc_count, struct dev_addr_list *mclist)
{
+ struct mwl8k_priv *priv = hw->priv;
struct mwl8k_cmd_mac_multicast_adr *cmd;
- int index = 0;
- int rc;
- int size = sizeof(*cmd) + mc_count * ETH_ALEN;
+ int size;
+ int i;
+
+ if (mc_count > priv->num_mcaddrs)
+ mc_count = priv->num_mcaddrs;
+
+ size = sizeof(*cmd) + mc_count * ETH_ALEN;
- cmd = kzalloc(size, GFP_KERNEL);
+ cmd = kzalloc(size, GFP_ATOMIC);
if (cmd == NULL)
- return -ENOMEM;
+ return NULL;
cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR);
cmd->header.length = cpu_to_le16(size);
cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST);
cmd->numaddr = cpu_to_le16(mc_count);
- while (index < mc_count && mclist) {
+ for (i = 0; i < mc_count && mclist; i++) {
if (mclist->da_addrlen != ETH_ALEN) {
- rc = -EINVAL;
- goto mwl8k_cmd_mac_multicast_adr_exit;
+ kfree(cmd);
+ return NULL;
}
- memcpy(cmd->addr[index++], mclist->da_addr, ETH_ALEN);
+ memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN);
mclist = mclist->next;
}
- rc = mwl8k_post_cmd(hw, &cmd->header);
-
-mwl8k_cmd_mac_multicast_adr_exit:
- kfree(cmd);
- return rc;
+ return &cmd->header;
}
/*
printk(KERN_ERR "%s() timed out\n", __func__);
}
+static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
+ int mc_count, struct dev_addr_list *mclist)
+{
+ struct mwl8k_cmd_pkt *cmd;
+
+ cmd = __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
+
+ return (unsigned long)cmd;
+}
+
struct mwl8k_configure_filter_worker {
struct mwl8k_work_struct header;
unsigned int changed_flags;
- unsigned int *total_flags;
- int mc_count;
- struct dev_addr_list *mclist;
+ unsigned int total_flags;
+ struct mwl8k_cmd_pkt *multicast_adr_cmd;
};
#define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC
{
struct mwl8k_configure_filter_worker *worker =
(struct mwl8k_configure_filter_worker *)wt;
-
struct ieee80211_hw *hw = worker->header.hw;
- unsigned int changed_flags = worker->changed_flags;
- unsigned int *total_flags = worker->total_flags;
- int mc_count = worker->mc_count;
- struct dev_addr_list *mclist = worker->mclist;
-
struct mwl8k_priv *priv = hw->priv;
int rc = 0;
- if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
- if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ if (worker->changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+ if (worker->total_flags & FIF_BCN_PRBRESP_PROMISC)
rc = mwl8k_cmd_set_pre_scan(hw);
else {
u8 *bssid;
}
}
- if (rc)
- goto mwl8k_configure_filter_exit;
- if (mc_count) {
- if (mc_count > priv->num_mcaddrs)
- mc_count = priv->num_mcaddrs;
-
- rc = mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
- if (rc)
- printk(KERN_ERR
- "%s()Error setting multicast addresses\n",
- __func__);
- }
+ if (!rc && worker->multicast_adr_cmd != NULL)
+ rc = mwl8k_post_cmd(hw, worker->multicast_adr_cmd);
+ kfree(worker->multicast_adr_cmd);
-mwl8k_configure_filter_exit:
return rc;
}
-static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
- int mc_count, struct dev_addr_list *mclist)
-{
- struct mwl8k_configure_filter_worker *worker;
-
- worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
-
- if (!worker)
- return 0;
-
- /*
- * XXX: This is _HORRIBLY_ broken!!
- *
- * No locking, the mclist pointer might be invalid as soon as this
- * function returns, something in the list might be invalidated
- * once we get to the worker, etc...
- */
- worker->mc_count = mc_count;
- worker->mclist = mclist;
-
- return (u64)worker;
-}
-
static void mwl8k_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
u64 multicast)
{
-
- struct mwl8k_configure_filter_worker *worker = (void *)multicast;
struct mwl8k_priv *priv = hw->priv;
+ struct mwl8k_configure_filter_worker *worker;
/* Clear unsupported feature flags */
*total_flags &= MWL8K_SUPPORTED_IF_FLAGS;
if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS))
return;
+ worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
if (worker == NULL)
return;
- worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY;
worker->changed_flags = changed_flags;
- worker->total_flags = total_flags;
+ worker->total_flags = *total_flags;
+ worker->multicast_adr_cmd = (void *)(unsigned long)multicast;
mwl8k_queue_work(hw, &worker->header, priv->config_wq,
mwl8k_configure_filter_wt);