aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwl8k.c
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2009-08-17 21:55:42 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-20 11:38:05 -0400
commite81cd2d664fe5b75a0db9bb24b43c0dfbde32319 (patch)
tree80998d7d45d112c1fef92111189b996386ba595d /drivers/net/wireless/mwl8k.c
parent5539bb51295f2c9300a6e467a29bb62bcfe9f4bc (diff)
mwl8k: fix mwl8k_configure_filter() parameter lifetime issue
mwl8k_configure_filter() passes pointers to total_flags and the multicast address list to a workqueue function, while there is no guarantee that those pointers will still be valid by the time the workqueue function runs. Solve this by passing total_flags by value, and by passing an already built multicast address setup command packet to the workqueue function so that we don't have to look at the multicast address list itself outside of mwl8k_configure_filter(). Also, since ->configure_filter() can sleep now, wait synchronously for the worker to finish. Signed-off-by: Lennert Buytenhek <buytenh@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r--drivers/net/wireless/mwl8k.c107
1 files changed, 39 insertions, 68 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index a40434b5572b..a961b698c691 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1613,38 +1613,39 @@ struct mwl8k_cmd_mac_multicast_adr {
1613 1613
1614#define MWL8K_ENABLE_RX_MULTICAST 0x000F 1614#define MWL8K_ENABLE_RX_MULTICAST 0x000F
1615 1615
1616static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, 1616static struct mwl8k_cmd_pkt *
1617 int mc_count, 1617__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
1618 struct dev_addr_list *mclist) 1618 int mc_count, struct dev_addr_list *mclist)
1619{ 1619{
1620 struct mwl8k_priv *priv = hw->priv;
1620 struct mwl8k_cmd_mac_multicast_adr *cmd; 1621 struct mwl8k_cmd_mac_multicast_adr *cmd;
1621 int index = 0; 1622 int size;
1622 int rc; 1623 int i;
1623 int size = sizeof(*cmd) + mc_count * ETH_ALEN; 1624
1625 if (mc_count > priv->num_mcaddrs)
1626 mc_count = priv->num_mcaddrs;
1627
1628 size = sizeof(*cmd) + mc_count * ETH_ALEN;
1624 1629
1625 cmd = kzalloc(size, GFP_KERNEL); 1630 cmd = kzalloc(size, GFP_ATOMIC);
1626 if (cmd == NULL) 1631 if (cmd == NULL)
1627 return -ENOMEM; 1632 return NULL;
1628 1633
1629 cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR); 1634 cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR);
1630 cmd->header.length = cpu_to_le16(size); 1635 cmd->header.length = cpu_to_le16(size);
1631 cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); 1636 cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST);
1632 cmd->numaddr = cpu_to_le16(mc_count); 1637 cmd->numaddr = cpu_to_le16(mc_count);
1633 1638
1634 while (index < mc_count && mclist) { 1639 for (i = 0; i < mc_count && mclist; i++) {
1635 if (mclist->da_addrlen != ETH_ALEN) { 1640 if (mclist->da_addrlen != ETH_ALEN) {
1636 rc = -EINVAL; 1641 kfree(cmd);
1637 goto mwl8k_cmd_mac_multicast_adr_exit; 1642 return NULL;
1638 } 1643 }
1639 memcpy(cmd->addr[index++], mclist->da_addr, ETH_ALEN); 1644 memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN);
1640 mclist = mclist->next; 1645 mclist = mclist->next;
1641 } 1646 }
1642 1647
1643 rc = mwl8k_post_cmd(hw, &cmd->header); 1648 return &cmd->header;
1644
1645mwl8k_cmd_mac_multicast_adr_exit:
1646 kfree(cmd);
1647 return rc;
1648} 1649}
1649 1650
1650/* 1651/*
@@ -3091,12 +3092,21 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
3091 printk(KERN_ERR "%s() timed out\n", __func__); 3092 printk(KERN_ERR "%s() timed out\n", __func__);
3092} 3093}
3093 3094
3095static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
3096 int mc_count, struct dev_addr_list *mclist)
3097{
3098 struct mwl8k_cmd_pkt *cmd;
3099
3100 cmd = __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
3101
3102 return (unsigned long)cmd;
3103}
3104
3094struct mwl8k_configure_filter_worker { 3105struct mwl8k_configure_filter_worker {
3095 struct mwl8k_work_struct header; 3106 struct mwl8k_work_struct header;
3096 unsigned int changed_flags; 3107 unsigned int changed_flags;
3097 unsigned int *total_flags; 3108 unsigned int total_flags;
3098 int mc_count; 3109 struct mwl8k_cmd_pkt *multicast_adr_cmd;
3099 struct dev_addr_list *mclist;
3100}; 3110};
3101 3111
3102#define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC 3112#define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC
@@ -3105,18 +3115,12 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt)
3105{ 3115{
3106 struct mwl8k_configure_filter_worker *worker = 3116 struct mwl8k_configure_filter_worker *worker =
3107 (struct mwl8k_configure_filter_worker *)wt; 3117 (struct mwl8k_configure_filter_worker *)wt;
3108
3109 struct ieee80211_hw *hw = worker->header.hw; 3118 struct ieee80211_hw *hw = worker->header.hw;
3110 unsigned int changed_flags = worker->changed_flags;
3111 unsigned int *total_flags = worker->total_flags;
3112 int mc_count = worker->mc_count;
3113 struct dev_addr_list *mclist = worker->mclist;
3114
3115 struct mwl8k_priv *priv = hw->priv; 3119 struct mwl8k_priv *priv = hw->priv;
3116 int rc = 0; 3120 int rc = 0;
3117 3121
3118 if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { 3122 if (worker->changed_flags & FIF_BCN_PRBRESP_PROMISC) {
3119 if (*total_flags & FIF_BCN_PRBRESP_PROMISC) 3123 if (worker->total_flags & FIF_BCN_PRBRESP_PROMISC)
3120 rc = mwl8k_cmd_set_pre_scan(hw); 3124 rc = mwl8k_cmd_set_pre_scan(hw);
3121 else { 3125 else {
3122 u8 *bssid; 3126 u8 *bssid;
@@ -3129,54 +3133,20 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt)
3129 } 3133 }
3130 } 3134 }
3131 3135
3132 if (rc) 3136 if (!rc && worker->multicast_adr_cmd != NULL)
3133 goto mwl8k_configure_filter_exit; 3137 rc = mwl8k_post_cmd(hw, worker->multicast_adr_cmd);
3134 if (mc_count) { 3138 kfree(worker->multicast_adr_cmd);
3135 if (mc_count > priv->num_mcaddrs)
3136 mc_count = priv->num_mcaddrs;
3137
3138 rc = mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
3139 if (rc)
3140 printk(KERN_ERR
3141 "%s()Error setting multicast addresses\n",
3142 __func__);
3143 }
3144 3139
3145mwl8k_configure_filter_exit:
3146 return rc; 3140 return rc;
3147} 3141}
3148 3142
3149static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
3150 int mc_count, struct dev_addr_list *mclist)
3151{
3152 struct mwl8k_configure_filter_worker *worker;
3153
3154 worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
3155
3156 if (!worker)
3157 return 0;
3158
3159 /*
3160 * XXX: This is _HORRIBLY_ broken!!
3161 *
3162 * No locking, the mclist pointer might be invalid as soon as this
3163 * function returns, something in the list might be invalidated
3164 * once we get to the worker, etc...
3165 */
3166 worker->mc_count = mc_count;
3167 worker->mclist = mclist;
3168
3169 return (u64)worker;
3170}
3171
3172static void mwl8k_configure_filter(struct ieee80211_hw *hw, 3143static void mwl8k_configure_filter(struct ieee80211_hw *hw,
3173 unsigned int changed_flags, 3144 unsigned int changed_flags,
3174 unsigned int *total_flags, 3145 unsigned int *total_flags,
3175 u64 multicast) 3146 u64 multicast)
3176{ 3147{
3177
3178 struct mwl8k_configure_filter_worker *worker = (void *)multicast;
3179 struct mwl8k_priv *priv = hw->priv; 3148 struct mwl8k_priv *priv = hw->priv;
3149 struct mwl8k_configure_filter_worker *worker;
3180 3150
3181 /* Clear unsupported feature flags */ 3151 /* Clear unsupported feature flags */
3182 *total_flags &= MWL8K_SUPPORTED_IF_FLAGS; 3152 *total_flags &= MWL8K_SUPPORTED_IF_FLAGS;
@@ -3184,12 +3154,13 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
3184 if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS)) 3154 if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS))
3185 return; 3155 return;
3186 3156
3157 worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
3187 if (worker == NULL) 3158 if (worker == NULL)
3188 return; 3159 return;
3189 3160
3190 worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY;
3191 worker->changed_flags = changed_flags; 3161 worker->changed_flags = changed_flags;
3192 worker->total_flags = total_flags; 3162 worker->total_flags = *total_flags;
3163 worker->multicast_adr_cmd = (void *)(unsigned long)multicast;
3193 3164
3194 mwl8k_queue_work(hw, &worker->header, priv->config_wq, 3165 mwl8k_queue_work(hw, &worker->header, priv->config_wq,
3195 mwl8k_configure_filter_wt); 3166 mwl8k_configure_filter_wt);