Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 290249
b: refs/heads/master
c: 80abaf9
h: refs/heads/master
i:
  290247: 431419f
v: v3
  • Loading branch information
Vasanthakumar Thiagarajan authored and Kalle Valo committed Jan 9, 2012
1 parent 25124c2 commit d2da3ae
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f914edd38920369d8926261f9ab72da6756c3e0c
refs/heads/master: 80abaf9b4c920cab044e185ed4327f801c1ff99d
8 changes: 8 additions & 0 deletions trunk/drivers/net/wireless/ath/ath6kl/cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -2818,12 +2818,15 @@ static int ath6kl_init_if_data(struct ath6kl_vif *vif)
set_bit(WMM_ENABLED, &vif->flags);
spin_lock_init(&vif->if_lock);

INIT_LIST_HEAD(&vif->mc_filter);

return 0;
}

void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
{
struct ath6kl *ar = vif->ar;
struct ath6kl_mc_filter *mc_filter, *tmp;

aggr_module_destroy(vif->aggr_cntxt);

Expand All @@ -2832,6 +2835,11 @@ void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
if (vif->nw_type == ADHOC_NETWORK)
ar->ibss_if_active = false;

list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
list_del(&mc_filter->list);
kfree(mc_filter);
}

unregister_netdevice(vif->ndev);

ar->num_vif--;
Expand Down
9 changes: 9 additions & 0 deletions trunk/drivers/net/wireless/ath/ath6kl/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,13 @@ enum ath6kl_hif_type {
ATH6KL_HIF_TYPE_USB,
};

/* Max number of filters that hw supports */
#define ATH6K_MAX_MC_FILTERS_PER_LIST 7
struct ath6kl_mc_filter {
struct list_head list;
char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE];
};

/*
* Driver's maximum limit, note that some firmwares support only one vif
* and the runtime (current) limit must be checked from ar->vif_max.
Expand Down Expand Up @@ -473,6 +480,8 @@ struct ath6kl_vif {
u8 assoc_bss_dtim_period;
struct net_device_stats net_stats;
struct target_stats target_stats;

struct list_head mc_filter;
};

#define WOW_LIST_ID 0
Expand Down
110 changes: 110 additions & 0 deletions trunk/drivers/net/wireless/ath/ath6kl/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1052,12 +1052,122 @@ static int ath6kl_set_features(struct net_device *dev, u32 features)
return err;
}

static void ath6kl_set_multicast_list(struct net_device *ndev)
{
struct ath6kl_vif *vif = netdev_priv(ndev);
bool mc_all_on = false, mc_all_off = false;
int mc_count = netdev_mc_count(ndev);
struct netdev_hw_addr *ha;
bool found;
struct ath6kl_mc_filter *mc_filter, *tmp;
struct list_head mc_filter_new;
int ret;

if (!test_bit(WMI_READY, &vif->ar->flag) ||
!test_bit(WLAN_ENABLED, &vif->flags))
return;

mc_all_on = !!(ndev->flags & IFF_PROMISC) ||
!!(ndev->flags & IFF_ALLMULTI) ||
!!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST);

mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0;

if (mc_all_on || mc_all_off) {
/* Enable/disable all multicast */
ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n",
mc_all_on ? "enabling" : "disabling");
ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
mc_all_on);
if (ret)
ath6kl_warn("Failed to %s multicast receive\n",
mc_all_on ? "enable" : "disable");
return;
}

list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
found = false;
netdev_for_each_mc_addr(ha, ndev) {
if (memcmp(ha->addr, mc_filter->hw_addr,
ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) {
found = true;
break;
}
}

if (!found) {
/*
* Delete the filter which was previously set
* but not in the new request.
*/
ath6kl_dbg(ATH6KL_DBG_TRC,
"Removing %pM from multicast filter\n",
mc_filter->hw_addr);
ret = ath6kl_wmi_add_del_mcast_filter_cmd(vif->ar->wmi,
vif->fw_vif_idx, mc_filter->hw_addr,
false);
if (ret) {
ath6kl_warn("Failed to remove multicast filter:%pM\n",
mc_filter->hw_addr);
return;
}

list_del(&mc_filter->list);
kfree(mc_filter);
}
}

INIT_LIST_HEAD(&mc_filter_new);

netdev_for_each_mc_addr(ha, ndev) {
found = false;
list_for_each_entry(mc_filter, &vif->mc_filter, list) {
if (memcmp(ha->addr, mc_filter->hw_addr,
ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) {
found = true;
break;
}
}

if (!found) {
mc_filter = kzalloc(sizeof(struct ath6kl_mc_filter),
GFP_ATOMIC);
if (!mc_filter) {
WARN_ON(1);
goto out;
}

memcpy(mc_filter->hw_addr, ha->addr,
ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE);
/* Set the multicast filter */
ath6kl_dbg(ATH6KL_DBG_TRC,
"Adding %pM to multicast filter list\n",
mc_filter->hw_addr);
ret = ath6kl_wmi_add_del_mcast_filter_cmd(vif->ar->wmi,
vif->fw_vif_idx, mc_filter->hw_addr,
true);
if (ret) {
ath6kl_warn("Failed to add multicast filter :%pM\n",
mc_filter->hw_addr);
kfree(mc_filter);
goto out;
}

list_add_tail(&mc_filter->list, &mc_filter_new);
}
}

out:
list_splice_tail(&mc_filter_new, &vif->mc_filter);
}

static struct net_device_ops ath6kl_netdev_ops = {
.ndo_open = ath6kl_open,
.ndo_stop = ath6kl_close,
.ndo_start_xmit = ath6kl_data_tx,
.ndo_get_stats = ath6kl_get_stats,
.ndo_set_features = ath6kl_set_features,
.ndo_set_rx_mode = ath6kl_set_multicast_list,
};

void init_netdev(struct net_device *dev)
Expand Down

0 comments on commit d2da3ae

Please sign in to comment.