@@ -329,6 +329,9 @@ struct ieee80211_if_managed {
struct work_struct monitor_work;
struct work_struct chswitch_work;
struct work_struct beacon_connection_loss_work;
+#ifdef CONFIG_INET
+ struct work_struct arp_config_work;
+#endif
unsigned long probe_timeout;
int probe_send_count;
@@ -477,6 +477,9 @@ static int ieee80211_stop(struct net_device *dev)
cancel_work_sync(&sdata->u.mgd.chswitch_work);
cancel_work_sync(&sdata->u.mgd.monitor_work);
cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work);
+#ifdef CONFIG_INET
+ cancel_work_sync(&sdata->u.mgd.arp_config_work);
+#endif
/*
* When we get here, the interface is marked down.
@@ -379,7 +379,8 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
ifmgd = &sdata->u.mgd;
mutex_lock(&ifmgd->mtx);
if (ifmgd->associated)
- ieee80211_set_arp_filter(sdata);
+ ieee80211_queue_work(&sdata->local->hw,
+ &sdata->u.mgd.arp_config_work);
mutex_unlock(&ifmgd->mtx);
return NOTIFY_DONE;
@@ -853,6 +853,11 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
ieee80211_bss_info_change_notify(sdata, bss_info_changed);
+#ifdef CONFIG_INET
+ /* Configure hardware ARP filter with current IPv4 config */
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.arp_config_work);
+#endif
+
mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1);
ieee80211_recalc_smps(local, sdata);
@@ -1767,6 +1772,26 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
kfree_skb(skb);
}
+#ifdef CONFIG_INET
+void ieee80211_arp_config_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data,
+ u.mgd.arp_config_work);
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+ if (!ieee80211_sdata_running(sdata))
+ return;
+
+ rtnl_lock();
+ mutex_lock(&ifmgd->mtx);
+ if (ifmgd->associated)
+ ieee80211_set_arp_filter(sdata);
+ mutex_unlock(&ifmgd->mtx);
+ rtnl_unlock();
+}
+#endif
+
static void ieee80211_sta_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
@@ -1959,6 +1984,9 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
INIT_WORK(&ifmgd->beacon_connection_loss_work,
ieee80211_beacon_connection_loss_work);
+#ifdef CONFIG_INET
+ INIT_WORK(&ifmgd->arp_config_work, ieee80211_arp_config_work);
+#endif
setup_timer(&ifmgd->timer, ieee80211_sta_timer,
(unsigned long) sdata);
setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
@@ -2116,19 +2144,8 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
cfg80211_send_assoc_timeout(wk->sdata->dev,
wk->filter_ta);
return WORK_DONE_DESTROY;
-#ifdef CONFIG_INET
- } else {
- mutex_unlock(&wk->sdata->u.mgd.mtx);
-
- /*
- * configure ARP filter IP addresses to the driver,
- * intentionally outside the mgd mutex.
- */
- rtnl_lock();
- ieee80211_set_arp_filter(wk->sdata);
- rtnl_unlock();
-#endif
}
+ mutex_unlock(&wk->sdata->u.mgd.mtx);
}
cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);