diff options
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 107 |
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 | ||
1616 | static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, | 1616 | static 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 | |||
1645 | mwl8k_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 | ||
3095 | static 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 | |||
3094 | struct mwl8k_configure_filter_worker { | 3105 | struct 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 | ||
3145 | mwl8k_configure_filter_exit: | ||
3146 | return rc; | 3140 | return rc; |
3147 | } | 3141 | } |
3148 | 3142 | ||
3149 | static 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 | |||
3172 | static void mwl8k_configure_filter(struct ieee80211_hw *hw, | 3143 | static 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); |