aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2010-05-27 08:32:13 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-03 14:10:45 -0400
commit2b2c009ecf71f4c66ff8420b63dddbc9737e04e3 (patch)
tree62f93194843ecf92d871d34963450c03d165af08 /net/mac80211
parent095dfdb0c479661f437b24b85e31f0d0b841eab6 (diff)
mac80211: Add support for hardware ARP query filtering
Some hardware allow extended filtering of ARP frames not intended for the host. To perform such filtering, the hardware needs to know the current IP address(es) of the host, bound to its interface. Add support for ARP filtering to mac80211 by adding a new op to the driver interface, allowing to configure the current IP addresses. This op is called upon association with the currently configured address(es), and when associated whenever the IP address(es) change. This patch adds configuration of IPv4 addresses only, as IPv6 addresses don't need ARP filtering. Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Reviewed-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/driver-ops.h17
-rw-r--r--net/mac80211/driver-trace.h25
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/main.c63
-rw-r--r--net/mac80211/mlme.c11
5 files changed, 116 insertions, 2 deletions
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 4f2271316650..978850ee3a5f 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -83,6 +83,23 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
83 trace_drv_bss_info_changed(local, sdata, info, changed); 83 trace_drv_bss_info_changed(local, sdata, info, changed);
84} 84}
85 85
86struct in_ifaddr;
87static inline int drv_configure_arp_filter(struct ieee80211_local *local,
88 struct ieee80211_vif *vif,
89 struct in_ifaddr *ifa_list)
90{
91 int ret = 0;
92
93 might_sleep();
94
95 if (local->ops->configure_arp_filter)
96 ret = local->ops->configure_arp_filter(&local->hw, vif,
97 ifa_list);
98
99 trace_drv_configure_arp_filter(local, vif_to_sdata(vif), ifa_list, ret);
100 return ret;
101}
102
86static inline u64 drv_prepare_multicast(struct ieee80211_local *local, 103static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
87 struct netdev_hw_addr_list *mc_list) 104 struct netdev_hw_addr_list *mc_list)
88{ 105{
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 6a9b2342a9c2..577460da2ea1 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -219,6 +219,31 @@ TRACE_EVENT(drv_bss_info_changed,
219 ) 219 )
220); 220);
221 221
222TRACE_EVENT(drv_configure_arp_filter,
223 TP_PROTO(struct ieee80211_local *local,
224 struct ieee80211_sub_if_data *sdata,
225 struct in_ifaddr *ifa_list, int ret),
226
227 TP_ARGS(local, sdata, ifa_list, ret),
228
229 TP_STRUCT__entry(
230 LOCAL_ENTRY
231 VIF_ENTRY
232 __field(int, ret)
233 ),
234
235 TP_fast_assign(
236 LOCAL_ASSIGN;
237 VIF_ASSIGN;
238 __entry->ret = ret;
239 ),
240
241 TP_printk(
242 VIF_PR_FMT LOCAL_PR_FMT " ret:%d",
243 VIF_PR_ARG, LOCAL_PR_ARG, __entry->ret
244 )
245);
246
222TRACE_EVENT(drv_prepare_multicast, 247TRACE_EVENT(drv_prepare_multicast,
223 TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret), 248 TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret),
224 249
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d4677efd3a36..47d67537f170 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -851,6 +851,7 @@ struct ieee80211_local {
851 struct work_struct dynamic_ps_disable_work; 851 struct work_struct dynamic_ps_disable_work;
852 struct timer_list dynamic_ps_timer; 852 struct timer_list dynamic_ps_timer;
853 struct notifier_block network_latency_notifier; 853 struct notifier_block network_latency_notifier;
854 struct notifier_block ifa_notifier;
854 855
855 int user_power_level; /* in dBm */ 856 int user_power_level; /* in dBm */
856 int power_constr_level; /* in dBm */ 857 int power_constr_level; /* in dBm */
@@ -997,6 +998,7 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
997void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); 998void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
998int ieee80211_max_network_latency(struct notifier_block *nb, 999int ieee80211_max_network_latency(struct notifier_block *nb,
999 unsigned long data, void *dummy); 1000 unsigned long data, void *dummy);
1001int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata);
1000void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, 1002void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1001 struct ieee80211_channel_sw_ie *sw_elem, 1003 struct ieee80211_channel_sw_ie *sw_elem,
1002 struct ieee80211_bss *bss, 1004 struct ieee80211_bss *bss,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index c8548e61f860..4051b232c6e6 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -329,6 +329,58 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
329 mutex_unlock(&local->iflist_mtx); 329 mutex_unlock(&local->iflist_mtx);
330} 330}
331 331
332int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata)
333{
334 struct in_device *idev;
335 int ret = 0;
336
337 BUG_ON(!sdata);
338 ASSERT_RTNL();
339
340 idev = sdata->dev->ip_ptr;
341 if (!idev)
342 return 0;
343
344 ret = drv_configure_arp_filter(sdata->local, &sdata->vif,
345 idev->ifa_list);
346 return ret;
347}
348
349static int ieee80211_ifa_changed(struct notifier_block *nb,
350 unsigned long data, void *arg)
351{
352 struct in_ifaddr *ifa = arg;
353 struct ieee80211_local *local =
354 container_of(nb, struct ieee80211_local,
355 ifa_notifier);
356 struct net_device *ndev = ifa->ifa_dev->dev;
357 struct wireless_dev *wdev = ndev->ieee80211_ptr;
358 struct ieee80211_sub_if_data *sdata;
359 struct ieee80211_if_managed *ifmgd;
360
361 /* Make sure it's our interface that got changed */
362 if (!wdev)
363 return NOTIFY_DONE;
364
365 if (wdev->wiphy != local->hw.wiphy)
366 return NOTIFY_DONE;
367
368 /* We are concerned about IP addresses only when associated */
369 sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
370
371 /* ARP filtering is only supported in managed mode */
372 if (sdata->vif.type != NL80211_IFTYPE_STATION)
373 return NOTIFY_DONE;
374
375 ifmgd = &sdata->u.mgd;
376 mutex_lock(&ifmgd->mtx);
377 if (ifmgd->associated)
378 ieee80211_set_arp_filter(sdata);
379 mutex_unlock(&ifmgd->mtx);
380
381 return NOTIFY_DONE;
382}
383
332struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, 384struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
333 const struct ieee80211_ops *ops) 385 const struct ieee80211_ops *ops)
334{ 386{
@@ -612,14 +664,22 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
612 ieee80211_max_network_latency; 664 ieee80211_max_network_latency;
613 result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, 665 result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY,
614 &local->network_latency_notifier); 666 &local->network_latency_notifier);
615
616 if (result) { 667 if (result) {
617 rtnl_lock(); 668 rtnl_lock();
618 goto fail_pm_qos; 669 goto fail_pm_qos;
619 } 670 }
620 671
672 local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
673 result = register_inetaddr_notifier(&local->ifa_notifier);
674 if (result)
675 goto fail_ifa;
676
621 return 0; 677 return 0;
622 678
679 fail_ifa:
680 pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
681 &local->network_latency_notifier);
682 rtnl_lock();
623 fail_pm_qos: 683 fail_pm_qos:
624 ieee80211_led_exit(local); 684 ieee80211_led_exit(local);
625 ieee80211_remove_interfaces(local); 685 ieee80211_remove_interfaces(local);
@@ -647,6 +707,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
647 707
648 pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, 708 pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
649 &local->network_latency_notifier); 709 &local->network_latency_notifier);
710 unregister_inetaddr_notifier(&local->ifa_notifier);
650 711
651 rtnl_lock(); 712 rtnl_lock();
652 713
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 29c3a75a7ad0..7e720133358c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2078,8 +2078,17 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
2078 cfg80211_send_assoc_timeout(wk->sdata->dev, 2078 cfg80211_send_assoc_timeout(wk->sdata->dev,
2079 wk->filter_ta); 2079 wk->filter_ta);
2080 return WORK_DONE_DESTROY; 2080 return WORK_DONE_DESTROY;
2081 } else {
2082 mutex_unlock(&wk->sdata->u.mgd.mtx);
2083
2084 /*
2085 * configure ARP filter IP addresses to the driver,
2086 * intentionally outside the mgd mutex.
2087 */
2088 rtnl_lock();
2089 ieee80211_set_arp_filter(wk->sdata);
2090 rtnl_unlock();
2081 } 2091 }
2082 mutex_unlock(&wk->sdata->u.mgd.mtx);
2083 } 2092 }
2084 2093
2085 cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); 2094 cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);