diff options
Diffstat (limited to 'net')
34 files changed, 1138 insertions, 480 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c2a2dcbfdf01..ccbe2413142a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -2668,8 +2668,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
2668 | tf->u.setup_req.capability = | 2668 | tf->u.setup_req.capability = |
2669 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2669 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2670 | 2670 | ||
2671 | ieee80211_add_srates_ie(&sdata->vif, skb, false); | 2671 | ieee80211_add_srates_ie(sdata, skb, false); |
2672 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); | 2672 | ieee80211_add_ext_srates_ie(sdata, skb, false); |
2673 | ieee80211_tdls_add_ext_capab(skb); | 2673 | ieee80211_tdls_add_ext_capab(skb); |
2674 | break; | 2674 | break; |
2675 | case WLAN_TDLS_SETUP_RESPONSE: | 2675 | case WLAN_TDLS_SETUP_RESPONSE: |
@@ -2682,8 +2682,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
2682 | tf->u.setup_resp.capability = | 2682 | tf->u.setup_resp.capability = |
2683 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2683 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2684 | 2684 | ||
2685 | ieee80211_add_srates_ie(&sdata->vif, skb, false); | 2685 | ieee80211_add_srates_ie(sdata, skb, false); |
2686 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); | 2686 | ieee80211_add_ext_srates_ie(sdata, skb, false); |
2687 | ieee80211_tdls_add_ext_capab(skb); | 2687 | ieee80211_tdls_add_ext_capab(skb); |
2688 | break; | 2688 | break; |
2689 | case WLAN_TDLS_SETUP_CONFIRM: | 2689 | case WLAN_TDLS_SETUP_CONFIRM: |
@@ -2743,8 +2743,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
2743 | mgmt->u.action.u.tdls_discover_resp.capability = | 2743 | mgmt->u.action.u.tdls_discover_resp.capability = |
2744 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2744 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2745 | 2745 | ||
2746 | ieee80211_add_srates_ie(&sdata->vif, skb, false); | 2746 | ieee80211_add_srates_ie(sdata, skb, false); |
2747 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); | 2747 | ieee80211_add_ext_srates_ie(sdata, skb, false); |
2748 | ieee80211_tdls_add_ext_capab(skb); | 2748 | ieee80211_tdls_add_ext_capab(skb); |
2749 | break; | 2749 | break; |
2750 | default: | 2750 | default: |
@@ -2980,14 +2980,14 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
2980 | return 0; | 2980 | return 0; |
2981 | } | 2981 | } |
2982 | 2982 | ||
2983 | static struct ieee80211_channel * | 2983 | static void ieee80211_set_monitor_enabled(struct wiphy *wiphy, bool enabled) |
2984 | ieee80211_wiphy_get_channel(struct wiphy *wiphy, | ||
2985 | enum nl80211_channel_type *type) | ||
2986 | { | 2984 | { |
2987 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2985 | struct ieee80211_local *local = wiphy_priv(wiphy); |
2988 | 2986 | ||
2989 | *type = local->_oper_channel_type; | 2987 | if (enabled) |
2990 | return local->oper_channel; | 2988 | WARN_ON(ieee80211_add_virtual_monitor(local)); |
2989 | else | ||
2990 | ieee80211_del_virtual_monitor(local); | ||
2991 | } | 2991 | } |
2992 | 2992 | ||
2993 | #ifdef CONFIG_PM | 2993 | #ifdef CONFIG_PM |
@@ -3063,8 +3063,8 @@ struct cfg80211_ops mac80211_config_ops = { | |||
3063 | .tdls_oper = ieee80211_tdls_oper, | 3063 | .tdls_oper = ieee80211_tdls_oper, |
3064 | .tdls_mgmt = ieee80211_tdls_mgmt, | 3064 | .tdls_mgmt = ieee80211_tdls_mgmt, |
3065 | .probe_client = ieee80211_probe_client, | 3065 | .probe_client = ieee80211_probe_client, |
3066 | .get_channel = ieee80211_wiphy_get_channel, | ||
3067 | .set_noack_map = ieee80211_set_noack_map, | 3066 | .set_noack_map = ieee80211_set_noack_map, |
3067 | .set_monitor_enabled = ieee80211_set_monitor_enabled, | ||
3068 | #ifdef CONFIG_PM | 3068 | #ifdef CONFIG_PM |
3069 | .set_wakeup = ieee80211_set_wakeup, | 3069 | .set_wakeup = ieee80211_set_wakeup, |
3070 | #endif | 3070 | #endif |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 7932767bb482..090d08ff22c4 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -283,6 +283,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
283 | 283 | ||
284 | lockdep_assert_held(&sdata->local->key_mtx); | 284 | lockdep_assert_held(&sdata->local->key_mtx); |
285 | 285 | ||
286 | if (sdata->debugfs.default_unicast_key) { | ||
287 | debugfs_remove(sdata->debugfs.default_unicast_key); | ||
288 | sdata->debugfs.default_unicast_key = NULL; | ||
289 | } | ||
290 | |||
286 | if (sdata->default_unicast_key) { | 291 | if (sdata->default_unicast_key) { |
287 | key = key_mtx_dereference(sdata->local, | 292 | key = key_mtx_dereference(sdata->local, |
288 | sdata->default_unicast_key); | 293 | sdata->default_unicast_key); |
@@ -290,9 +295,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
290 | sdata->debugfs.default_unicast_key = | 295 | sdata->debugfs.default_unicast_key = |
291 | debugfs_create_symlink("default_unicast_key", | 296 | debugfs_create_symlink("default_unicast_key", |
292 | sdata->debugfs.dir, buf); | 297 | sdata->debugfs.dir, buf); |
293 | } else { | 298 | } |
294 | debugfs_remove(sdata->debugfs.default_unicast_key); | 299 | |
295 | sdata->debugfs.default_unicast_key = NULL; | 300 | if (sdata->debugfs.default_multicast_key) { |
301 | debugfs_remove(sdata->debugfs.default_multicast_key); | ||
302 | sdata->debugfs.default_multicast_key = NULL; | ||
296 | } | 303 | } |
297 | 304 | ||
298 | if (sdata->default_multicast_key) { | 305 | if (sdata->default_multicast_key) { |
@@ -302,9 +309,6 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
302 | sdata->debugfs.default_multicast_key = | 309 | sdata->debugfs.default_multicast_key = |
303 | debugfs_create_symlink("default_multicast_key", | 310 | debugfs_create_symlink("default_multicast_key", |
304 | sdata->debugfs.dir, buf); | 311 | sdata->debugfs.dir, buf); |
305 | } else { | ||
306 | debugfs_remove(sdata->debugfs.default_multicast_key); | ||
307 | sdata->debugfs.default_multicast_key = NULL; | ||
308 | } | 312 | } |
309 | } | 313 | } |
310 | 314 | ||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 44e8c1242781..df9203199102 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -27,14 +27,6 @@ static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb) | |||
27 | local->ops->tx(&local->hw, skb); | 27 | local->ops->tx(&local->hw, skb); |
28 | } | 28 | } |
29 | 29 | ||
30 | static inline void drv_tx_frags(struct ieee80211_local *local, | ||
31 | struct ieee80211_vif *vif, | ||
32 | struct ieee80211_sta *sta, | ||
33 | struct sk_buff_head *skbs) | ||
34 | { | ||
35 | local->ops->tx_frags(&local->hw, vif, sta, skbs); | ||
36 | } | ||
37 | |||
38 | static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata, | 30 | static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata, |
39 | u32 sset, u8 *data) | 31 | u32 sset, u8 *data) |
40 | { | 32 | { |
@@ -860,4 +852,18 @@ static inline int drv_get_rssi(struct ieee80211_local *local, | |||
860 | 852 | ||
861 | return ret; | 853 | return ret; |
862 | } | 854 | } |
855 | |||
856 | static inline void drv_mgd_prepare_tx(struct ieee80211_local *local, | ||
857 | struct ieee80211_sub_if_data *sdata) | ||
858 | { | ||
859 | might_sleep(); | ||
860 | |||
861 | check_sdata_in_driver(sdata); | ||
862 | WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION); | ||
863 | |||
864 | trace_drv_mgd_prepare_tx(local, sdata); | ||
865 | if (local->ops->mgd_prepare_tx) | ||
866 | local->ops->mgd_prepare_tx(&local->hw, &sdata->vif); | ||
867 | trace_drv_return_void(local); | ||
868 | } | ||
863 | #endif /* __MAC80211_DRIVER_OPS */ | 869 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f834a005e1c5..e0423f8c0ce1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -1284,7 +1284,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
1284 | enum nl80211_iftype type); | 1284 | enum nl80211_iftype type); |
1285 | void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); | 1285 | void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); |
1286 | void ieee80211_remove_interfaces(struct ieee80211_local *local); | 1286 | void ieee80211_remove_interfaces(struct ieee80211_local *local); |
1287 | u32 __ieee80211_recalc_idle(struct ieee80211_local *local); | ||
1288 | void ieee80211_recalc_idle(struct ieee80211_local *local); | 1287 | void ieee80211_recalc_idle(struct ieee80211_local *local); |
1289 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | 1288 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, |
1290 | const int offset); | 1289 | const int offset); |
@@ -1481,6 +1480,16 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
1481 | struct ieee80211_channel *channel, | 1480 | struct ieee80211_channel *channel, |
1482 | enum nl80211_channel_type channel_type, | 1481 | enum nl80211_channel_type channel_type, |
1483 | u16 prot_mode); | 1482 | u16 prot_mode); |
1483 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | ||
1484 | u32 cap); | ||
1485 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | ||
1486 | struct sk_buff *skb, bool need_basic); | ||
1487 | int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | ||
1488 | struct sk_buff *skb, bool need_basic); | ||
1489 | |||
1490 | /* virtual monitor */ | ||
1491 | int ieee80211_add_virtual_monitor(struct ieee80211_local *local); | ||
1492 | void ieee80211_del_virtual_monitor(struct ieee80211_local *local); | ||
1484 | 1493 | ||
1485 | /* channel management */ | 1494 | /* channel management */ |
1486 | enum ieee80211_chan_mode { | 1495 | enum ieee80211_chan_mode { |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 58c2ab3d483a..fbef7a1ada7a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -43,6 +43,127 @@ | |||
43 | */ | 43 | */ |
44 | 44 | ||
45 | 45 | ||
46 | static u32 ieee80211_idle_off(struct ieee80211_local *local, | ||
47 | const char *reason) | ||
48 | { | ||
49 | if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) | ||
50 | return 0; | ||
51 | |||
52 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; | ||
53 | return IEEE80211_CONF_CHANGE_IDLE; | ||
54 | } | ||
55 | |||
56 | static u32 ieee80211_idle_on(struct ieee80211_local *local) | ||
57 | { | ||
58 | if (local->hw.conf.flags & IEEE80211_CONF_IDLE) | ||
59 | return 0; | ||
60 | |||
61 | drv_flush(local, false); | ||
62 | |||
63 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; | ||
64 | return IEEE80211_CONF_CHANGE_IDLE; | ||
65 | } | ||
66 | |||
67 | static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | ||
68 | { | ||
69 | struct ieee80211_sub_if_data *sdata; | ||
70 | int count = 0; | ||
71 | bool working = false, scanning = false; | ||
72 | unsigned int led_trig_start = 0, led_trig_stop = 0; | ||
73 | struct ieee80211_roc_work *roc; | ||
74 | |||
75 | #ifdef CONFIG_PROVE_LOCKING | ||
76 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && | ||
77 | !lockdep_is_held(&local->iflist_mtx)); | ||
78 | #endif | ||
79 | lockdep_assert_held(&local->mtx); | ||
80 | |||
81 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
82 | if (!ieee80211_sdata_running(sdata)) { | ||
83 | sdata->vif.bss_conf.idle = true; | ||
84 | continue; | ||
85 | } | ||
86 | |||
87 | sdata->old_idle = sdata->vif.bss_conf.idle; | ||
88 | |||
89 | /* do not count disabled managed interfaces */ | ||
90 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
91 | !sdata->u.mgd.associated && | ||
92 | !sdata->u.mgd.auth_data && | ||
93 | !sdata->u.mgd.assoc_data) { | ||
94 | sdata->vif.bss_conf.idle = true; | ||
95 | continue; | ||
96 | } | ||
97 | /* do not count unused IBSS interfaces */ | ||
98 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | ||
99 | !sdata->u.ibss.ssid_len) { | ||
100 | sdata->vif.bss_conf.idle = true; | ||
101 | continue; | ||
102 | } | ||
103 | /* count everything else */ | ||
104 | sdata->vif.bss_conf.idle = false; | ||
105 | count++; | ||
106 | } | ||
107 | |||
108 | if (!local->ops->remain_on_channel) { | ||
109 | list_for_each_entry(roc, &local->roc_list, list) { | ||
110 | working = true; | ||
111 | roc->sdata->vif.bss_conf.idle = false; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | if (local->scan_sdata && | ||
116 | !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { | ||
117 | scanning = true; | ||
118 | local->scan_sdata->vif.bss_conf.idle = false; | ||
119 | } | ||
120 | |||
121 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
122 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||
123 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
124 | continue; | ||
125 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||
126 | continue; | ||
127 | if (!ieee80211_sdata_running(sdata)) | ||
128 | continue; | ||
129 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
130 | } | ||
131 | |||
132 | if (working || scanning) | ||
133 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
134 | else | ||
135 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
136 | |||
137 | if (count) | ||
138 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
139 | else | ||
140 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
141 | |||
142 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); | ||
143 | |||
144 | if (working) | ||
145 | return ieee80211_idle_off(local, "working"); | ||
146 | if (scanning) | ||
147 | return ieee80211_idle_off(local, "scanning"); | ||
148 | if (!count) | ||
149 | return ieee80211_idle_on(local); | ||
150 | else | ||
151 | return ieee80211_idle_off(local, "in use"); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | void ieee80211_recalc_idle(struct ieee80211_local *local) | ||
157 | { | ||
158 | u32 chg; | ||
159 | |||
160 | mutex_lock(&local->iflist_mtx); | ||
161 | chg = __ieee80211_recalc_idle(local); | ||
162 | mutex_unlock(&local->iflist_mtx); | ||
163 | if (chg) | ||
164 | ieee80211_hw_config(local, chg); | ||
165 | } | ||
166 | |||
46 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | 167 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) |
47 | { | 168 | { |
48 | int meshhdrlen; | 169 | int meshhdrlen; |
@@ -209,7 +330,7 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) | |||
209 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; | 330 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; |
210 | } | 331 | } |
211 | 332 | ||
212 | static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | 333 | int ieee80211_add_virtual_monitor(struct ieee80211_local *local) |
213 | { | 334 | { |
214 | struct ieee80211_sub_if_data *sdata; | 335 | struct ieee80211_sub_if_data *sdata; |
215 | int ret; | 336 | int ret; |
@@ -250,7 +371,7 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
250 | return 0; | 371 | return 0; |
251 | } | 372 | } |
252 | 373 | ||
253 | static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) | 374 | void ieee80211_del_virtual_monitor(struct ieee80211_local *local) |
254 | { | 375 | { |
255 | struct ieee80211_sub_if_data *sdata; | 376 | struct ieee80211_sub_if_data *sdata; |
256 | 377 | ||
@@ -366,12 +487,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
366 | break; | 487 | break; |
367 | } | 488 | } |
368 | 489 | ||
369 | if (local->monitors == 0 && local->open_count == 0) { | ||
370 | res = ieee80211_add_virtual_monitor(local); | ||
371 | if (res) | ||
372 | goto err_stop; | ||
373 | } | ||
374 | |||
375 | /* must be before the call to ieee80211_configure_filter */ | 490 | /* must be before the call to ieee80211_configure_filter */ |
376 | local->monitors++; | 491 | local->monitors++; |
377 | if (local->monitors == 1) { | 492 | if (local->monitors == 1) { |
@@ -386,8 +501,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
386 | break; | 501 | break; |
387 | default: | 502 | default: |
388 | if (coming_up) { | 503 | if (coming_up) { |
389 | ieee80211_del_virtual_monitor(local); | ||
390 | |||
391 | res = drv_add_interface(local, sdata); | 504 | res = drv_add_interface(local, sdata); |
392 | if (res) | 505 | if (res) |
393 | goto err_stop; | 506 | goto err_stop; |
@@ -622,7 +735,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
622 | if (local->monitors == 0) { | 735 | if (local->monitors == 0) { |
623 | local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; | 736 | local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; |
624 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; | 737 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; |
625 | ieee80211_del_virtual_monitor(local); | ||
626 | } | 738 | } |
627 | 739 | ||
628 | ieee80211_adjust_monitor_flags(sdata, -1); | 740 | ieee80211_adjust_monitor_flags(sdata, -1); |
@@ -696,9 +808,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
696 | } | 808 | } |
697 | } | 809 | } |
698 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 810 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
699 | |||
700 | if (local->monitors == local->open_count && local->monitors > 0) | ||
701 | ieee80211_add_virtual_monitor(local); | ||
702 | } | 811 | } |
703 | 812 | ||
704 | static int ieee80211_stop(struct net_device *dev) | 813 | static int ieee80211_stop(struct net_device *dev) |
@@ -1403,127 +1512,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) | |||
1403 | list_del(&unreg_list); | 1512 | list_del(&unreg_list); |
1404 | } | 1513 | } |
1405 | 1514 | ||
1406 | static u32 ieee80211_idle_off(struct ieee80211_local *local, | ||
1407 | const char *reason) | ||
1408 | { | ||
1409 | if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) | ||
1410 | return 0; | ||
1411 | |||
1412 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; | ||
1413 | return IEEE80211_CONF_CHANGE_IDLE; | ||
1414 | } | ||
1415 | |||
1416 | static u32 ieee80211_idle_on(struct ieee80211_local *local) | ||
1417 | { | ||
1418 | if (local->hw.conf.flags & IEEE80211_CONF_IDLE) | ||
1419 | return 0; | ||
1420 | |||
1421 | drv_flush(local, false); | ||
1422 | |||
1423 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; | ||
1424 | return IEEE80211_CONF_CHANGE_IDLE; | ||
1425 | } | ||
1426 | |||
1427 | u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | ||
1428 | { | ||
1429 | struct ieee80211_sub_if_data *sdata; | ||
1430 | int count = 0; | ||
1431 | bool working = false, scanning = false; | ||
1432 | unsigned int led_trig_start = 0, led_trig_stop = 0; | ||
1433 | struct ieee80211_roc_work *roc; | ||
1434 | |||
1435 | #ifdef CONFIG_PROVE_LOCKING | ||
1436 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && | ||
1437 | !lockdep_is_held(&local->iflist_mtx)); | ||
1438 | #endif | ||
1439 | lockdep_assert_held(&local->mtx); | ||
1440 | |||
1441 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1442 | if (!ieee80211_sdata_running(sdata)) { | ||
1443 | sdata->vif.bss_conf.idle = true; | ||
1444 | continue; | ||
1445 | } | ||
1446 | |||
1447 | sdata->old_idle = sdata->vif.bss_conf.idle; | ||
1448 | |||
1449 | /* do not count disabled managed interfaces */ | ||
1450 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
1451 | !sdata->u.mgd.associated && | ||
1452 | !sdata->u.mgd.auth_data && | ||
1453 | !sdata->u.mgd.assoc_data) { | ||
1454 | sdata->vif.bss_conf.idle = true; | ||
1455 | continue; | ||
1456 | } | ||
1457 | /* do not count unused IBSS interfaces */ | ||
1458 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | ||
1459 | !sdata->u.ibss.ssid_len) { | ||
1460 | sdata->vif.bss_conf.idle = true; | ||
1461 | continue; | ||
1462 | } | ||
1463 | /* count everything else */ | ||
1464 | sdata->vif.bss_conf.idle = false; | ||
1465 | count++; | ||
1466 | } | ||
1467 | |||
1468 | if (!local->ops->remain_on_channel) { | ||
1469 | list_for_each_entry(roc, &local->roc_list, list) { | ||
1470 | working = true; | ||
1471 | roc->sdata->vif.bss_conf.idle = false; | ||
1472 | } | ||
1473 | } | ||
1474 | |||
1475 | if (local->scan_sdata && | ||
1476 | !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { | ||
1477 | scanning = true; | ||
1478 | local->scan_sdata->vif.bss_conf.idle = false; | ||
1479 | } | ||
1480 | |||
1481 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1482 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||
1483 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
1484 | continue; | ||
1485 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||
1486 | continue; | ||
1487 | if (!ieee80211_sdata_running(sdata)) | ||
1488 | continue; | ||
1489 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
1490 | } | ||
1491 | |||
1492 | if (working || scanning) | ||
1493 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
1494 | else | ||
1495 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
1496 | |||
1497 | if (count) | ||
1498 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
1499 | else | ||
1500 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
1501 | |||
1502 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); | ||
1503 | |||
1504 | if (working) | ||
1505 | return ieee80211_idle_off(local, "working"); | ||
1506 | if (scanning) | ||
1507 | return ieee80211_idle_off(local, "scanning"); | ||
1508 | if (!count) | ||
1509 | return ieee80211_idle_on(local); | ||
1510 | else | ||
1511 | return ieee80211_idle_off(local, "in use"); | ||
1512 | |||
1513 | return 0; | ||
1514 | } | ||
1515 | |||
1516 | void ieee80211_recalc_idle(struct ieee80211_local *local) | ||
1517 | { | ||
1518 | u32 chg; | ||
1519 | |||
1520 | mutex_lock(&local->iflist_mtx); | ||
1521 | chg = __ieee80211_recalc_idle(local); | ||
1522 | mutex_unlock(&local->iflist_mtx); | ||
1523 | if (chg) | ||
1524 | ieee80211_hw_config(local, chg); | ||
1525 | } | ||
1526 | |||
1527 | static int netdev_notify(struct notifier_block *nb, | 1515 | static int netdev_notify(struct notifier_block *nb, |
1528 | unsigned long state, | 1516 | unsigned long state, |
1529 | void *ndev) | 1517 | void *ndev) |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0b040fb73673..c794101f8987 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -587,7 +587,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
587 | 587 | ||
588 | local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); | 588 | local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); |
589 | 589 | ||
590 | BUG_ON(!ops->tx && !ops->tx_frags); | 590 | BUG_ON(!ops->tx); |
591 | BUG_ON(!ops->start); | 591 | BUG_ON(!ops->start); |
592 | BUG_ON(!ops->stop); | 592 | BUG_ON(!ops->stop); |
593 | BUG_ON(!ops->config); | 593 | BUG_ON(!ops->config); |
@@ -688,7 +688,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
688 | int result, i; | 688 | int result, i; |
689 | enum ieee80211_band band; | 689 | enum ieee80211_band band; |
690 | int channels, max_bitrates; | 690 | int channels, max_bitrates; |
691 | bool supp_ht; | 691 | bool supp_ht, supp_vht; |
692 | netdev_features_t feature_whitelist; | 692 | netdev_features_t feature_whitelist; |
693 | static const u32 cipher_suites[] = { | 693 | static const u32 cipher_suites[] = { |
694 | /* keep WEP first, it may be removed below */ | 694 | /* keep WEP first, it may be removed below */ |
@@ -706,12 +706,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
706 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) | 706 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) |
707 | return -EINVAL; | 707 | return -EINVAL; |
708 | 708 | ||
709 | if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) | ||
710 | #ifdef CONFIG_PM | 709 | #ifdef CONFIG_PM |
711 | && (!local->ops->suspend || !local->ops->resume) | 710 | if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) && |
712 | #endif | 711 | (!local->ops->suspend || !local->ops->resume)) |
713 | ) | ||
714 | return -EINVAL; | 712 | return -EINVAL; |
713 | #endif | ||
715 | 714 | ||
716 | if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) | 715 | if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) |
717 | return -EINVAL; | 716 | return -EINVAL; |
@@ -733,6 +732,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
733 | channels = 0; | 732 | channels = 0; |
734 | max_bitrates = 0; | 733 | max_bitrates = 0; |
735 | supp_ht = false; | 734 | supp_ht = false; |
735 | supp_vht = false; | ||
736 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 736 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
737 | struct ieee80211_supported_band *sband; | 737 | struct ieee80211_supported_band *sband; |
738 | 738 | ||
@@ -750,6 +750,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
750 | if (max_bitrates < sband->n_bitrates) | 750 | if (max_bitrates < sband->n_bitrates) |
751 | max_bitrates = sband->n_bitrates; | 751 | max_bitrates = sband->n_bitrates; |
752 | supp_ht = supp_ht || sband->ht_cap.ht_supported; | 752 | supp_ht = supp_ht || sband->ht_cap.ht_supported; |
753 | supp_vht = supp_vht || sband->vht_cap.vht_supported; | ||
753 | } | 754 | } |
754 | 755 | ||
755 | local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + | 756 | local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + |
@@ -825,6 +826,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
825 | if (supp_ht) | 826 | if (supp_ht) |
826 | local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); | 827 | local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); |
827 | 828 | ||
829 | if (supp_vht) | ||
830 | local->scan_ies_len += | ||
831 | 2 + sizeof(struct ieee80211_vht_capabilities); | ||
832 | |||
828 | if (!local->ops->hw_scan) { | 833 | if (!local->ops->hw_scan) { |
829 | /* For hw_scan, driver needs to set these up. */ | 834 | /* For hw_scan, driver needs to set these up. */ |
830 | local->hw.wiphy->max_scan_ssids = 4; | 835 | local->hw.wiphy->max_scan_ssids = 4; |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 9ad74dd87a7b..af671b984df3 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -258,8 +258,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
258 | pos = skb_put(skb, 2); | 258 | pos = skb_put(skb, 2); |
259 | memcpy(pos + 2, &plid, 2); | 259 | memcpy(pos + 2, &plid, 2); |
260 | } | 260 | } |
261 | if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || | 261 | if (ieee80211_add_srates_ie(sdata, skb, true) || |
262 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || | 262 | ieee80211_add_ext_srates_ie(sdata, skb, true) || |
263 | mesh_add_rsn_ie(skb, sdata) || | 263 | mesh_add_rsn_ie(skb, sdata) || |
264 | mesh_add_meshid_ie(skb, sdata) || | 264 | mesh_add_meshid_ie(skb, sdata) || |
265 | mesh_add_meshconf_ie(skb, sdata)) | 265 | mesh_add_meshconf_ie(skb, sdata)) |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index aa69a331f374..f49f14f8ba82 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -541,6 +541,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
541 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | 541 | memcpy(pos, assoc_data->ie + offset, noffset - offset); |
542 | } | 542 | } |
543 | 543 | ||
544 | drv_mgd_prepare_tx(local, sdata); | ||
545 | |||
544 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 546 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
545 | ieee80211_tx_skb(sdata, skb); | 547 | ieee80211_tx_skb(sdata, skb); |
546 | } | 548 | } |
@@ -580,6 +582,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
580 | if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) | 582 | if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) |
581 | IEEE80211_SKB_CB(skb)->flags |= | 583 | IEEE80211_SKB_CB(skb)->flags |= |
582 | IEEE80211_TX_INTFL_DONT_ENCRYPT; | 584 | IEEE80211_TX_INTFL_DONT_ENCRYPT; |
585 | |||
586 | drv_mgd_prepare_tx(local, sdata); | ||
587 | |||
583 | ieee80211_tx_skb(sdata, skb); | 588 | ieee80211_tx_skb(sdata, skb); |
584 | } | 589 | } |
585 | } | 590 | } |
@@ -902,9 +907,6 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) | |||
902 | if (!mgd->associated) | 907 | if (!mgd->associated) |
903 | return false; | 908 | return false; |
904 | 909 | ||
905 | if (!mgd->associated->beacon_ies) | ||
906 | return false; | ||
907 | |||
908 | if (mgd->flags & (IEEE80211_STA_BEACON_POLL | | 910 | if (mgd->flags & (IEEE80211_STA_BEACON_POLL | |
909 | IEEE80211_STA_CONNECTION_POLL)) | 911 | IEEE80211_STA_CONNECTION_POLL)) |
910 | return false; | 912 | return false; |
@@ -1362,6 +1364,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1362 | } | 1364 | } |
1363 | mutex_unlock(&local->sta_mtx); | 1365 | mutex_unlock(&local->sta_mtx); |
1364 | 1366 | ||
1367 | /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ | ||
1368 | if (tx) | ||
1369 | drv_flush(local, false); | ||
1370 | |||
1365 | /* deauthenticate/disassociate now */ | 1371 | /* deauthenticate/disassociate now */ |
1366 | if (tx || frame_buf) | 1372 | if (tx || frame_buf) |
1367 | ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, | 1373 | ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, |
@@ -1610,6 +1616,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1610 | { | 1616 | { |
1611 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 1617 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
1612 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1618 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1619 | struct cfg80211_bss *cbss; | ||
1613 | struct sk_buff *skb; | 1620 | struct sk_buff *skb; |
1614 | const u8 *ssid; | 1621 | const u8 *ssid; |
1615 | int ssid_len; | 1622 | int ssid_len; |
@@ -1619,16 +1626,22 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1619 | 1626 | ||
1620 | ASSERT_MGD_MTX(ifmgd); | 1627 | ASSERT_MGD_MTX(ifmgd); |
1621 | 1628 | ||
1622 | if (!ifmgd->associated) | 1629 | if (ifmgd->associated) |
1630 | cbss = ifmgd->associated; | ||
1631 | else if (ifmgd->auth_data) | ||
1632 | cbss = ifmgd->auth_data->bss; | ||
1633 | else if (ifmgd->assoc_data) | ||
1634 | cbss = ifmgd->assoc_data->bss; | ||
1635 | else | ||
1623 | return NULL; | 1636 | return NULL; |
1624 | 1637 | ||
1625 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1638 | ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID); |
1626 | if (WARN_ON_ONCE(ssid == NULL)) | 1639 | if (WARN_ON_ONCE(ssid == NULL)) |
1627 | ssid_len = 0; | 1640 | ssid_len = 0; |
1628 | else | 1641 | else |
1629 | ssid_len = ssid[1]; | 1642 | ssid_len = ssid[1]; |
1630 | 1643 | ||
1631 | skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, | 1644 | skb = ieee80211_build_probe_req(sdata, cbss->bssid, |
1632 | (u32) -1, ssid + 2, ssid_len, | 1645 | (u32) -1, ssid + 2, ssid_len, |
1633 | NULL, 0, true); | 1646 | NULL, 0, true); |
1634 | 1647 | ||
@@ -1747,6 +1760,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
1747 | if (!elems.challenge) | 1760 | if (!elems.challenge) |
1748 | return; | 1761 | return; |
1749 | auth_data->expected_transaction = 4; | 1762 | auth_data->expected_transaction = 4; |
1763 | drv_mgd_prepare_tx(sdata->local, sdata); | ||
1750 | ieee80211_send_auth(sdata, 3, auth_data->algorithm, | 1764 | ieee80211_send_auth(sdata, 3, auth_data->algorithm, |
1751 | elems.challenge - 2, elems.challenge_len + 2, | 1765 | elems.challenge - 2, elems.challenge_len + 2, |
1752 | auth_data->bss->bssid, auth_data->bss->bssid, | 1766 | auth_data->bss->bssid, auth_data->bss->bssid, |
@@ -2630,6 +2644,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
2630 | return -ETIMEDOUT; | 2644 | return -ETIMEDOUT; |
2631 | } | 2645 | } |
2632 | 2646 | ||
2647 | drv_mgd_prepare_tx(local, sdata); | ||
2648 | |||
2633 | if (auth_data->bss->proberesp_ies) { | 2649 | if (auth_data->bss->proberesp_ies) { |
2634 | sdata_info(sdata, "send auth to %pM (try %d/%d)\n", | 2650 | sdata_info(sdata, "send auth to %pM (try %d/%d)\n", |
2635 | auth_data->bss->bssid, auth_data->tries, | 2651 | auth_data->bss->bssid, auth_data->tries, |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 2e60f4acd027..e1e9d10ec2e7 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -1244,6 +1244,13 @@ TRACE_EVENT(drv_get_rssi, | |||
1244 | ) | 1244 | ) |
1245 | ); | 1245 | ); |
1246 | 1246 | ||
1247 | DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx, | ||
1248 | TP_PROTO(struct ieee80211_local *local, | ||
1249 | struct ieee80211_sub_if_data *sdata), | ||
1250 | |||
1251 | TP_ARGS(local, sdata) | ||
1252 | ); | ||
1253 | |||
1247 | /* | 1254 | /* |
1248 | * Tracing for API calls that drivers call. | 1255 | * Tracing for API calls that drivers call. |
1249 | */ | 1256 | */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ec8f53467374..c9d2175d15c1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -140,6 +140,8 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, | |||
140 | if (r->flags & IEEE80211_RATE_MANDATORY_A) | 140 | if (r->flags & IEEE80211_RATE_MANDATORY_A) |
141 | mrate = r->bitrate; | 141 | mrate = r->bitrate; |
142 | break; | 142 | break; |
143 | case IEEE80211_BAND_60GHZ: | ||
144 | /* TODO, for now fall through */ | ||
143 | case IEEE80211_NUM_BANDS: | 145 | case IEEE80211_NUM_BANDS: |
144 | WARN_ON(1); | 146 | WARN_ON(1); |
145 | break; | 147 | break; |
@@ -957,8 +959,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
957 | info->control.rates[1].idx = -1; | 959 | info->control.rates[1].idx = -1; |
958 | info->control.rates[2].idx = -1; | 960 | info->control.rates[2].idx = -1; |
959 | info->control.rates[3].idx = -1; | 961 | info->control.rates[3].idx = -1; |
960 | info->control.rates[4].idx = -1; | 962 | BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 4); |
961 | BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); | ||
962 | info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; | 963 | info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; |
963 | } else { | 964 | } else { |
964 | hdr->frame_control &= ~morefrags; | 965 | hdr->frame_control &= ~morefrags; |
@@ -1293,11 +1294,8 @@ static bool __ieee80211_tx(struct ieee80211_local *local, | |||
1293 | break; | 1294 | break; |
1294 | } | 1295 | } |
1295 | 1296 | ||
1296 | if (local->ops->tx_frags) | 1297 | result = ieee80211_tx_frags(local, vif, pubsta, skbs, |
1297 | drv_tx_frags(local, vif, pubsta, skbs); | 1298 | txpending); |
1298 | else | ||
1299 | result = ieee80211_tx_frags(local, vif, pubsta, skbs, | ||
1300 | txpending); | ||
1301 | 1299 | ||
1302 | ieee80211_tpt_led_trig_tx(local, fc, led_len); | 1300 | ieee80211_tpt_led_trig_tx(local, fc, led_len); |
1303 | ieee80211_led_tx(local, 1); | 1301 | ieee80211_led_tx(local, 1); |
@@ -2420,9 +2418,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2420 | *pos++ = WLAN_EID_SSID; | 2418 | *pos++ = WLAN_EID_SSID; |
2421 | *pos++ = 0x0; | 2419 | *pos++ = 0x0; |
2422 | 2420 | ||
2423 | if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || | 2421 | if (ieee80211_add_srates_ie(sdata, skb, true) || |
2424 | mesh_add_ds_params_ie(skb, sdata) || | 2422 | mesh_add_ds_params_ie(skb, sdata) || |
2425 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || | 2423 | ieee80211_add_ext_srates_ie(sdata, skb, true) || |
2426 | mesh_add_rsn_ie(skb, sdata) || | 2424 | mesh_add_rsn_ie(skb, sdata) || |
2427 | mesh_add_ht_cap_ie(skb, sdata) || | 2425 | mesh_add_ht_cap_ie(skb, sdata) || |
2428 | mesh_add_ht_oper_ie(skb, sdata) || | 2426 | mesh_add_ht_oper_ie(skb, sdata) || |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 242ecde381f6..64493a7bef1a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -268,6 +268,10 @@ EXPORT_SYMBOL(ieee80211_ctstoself_duration); | |||
268 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) | 268 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) |
269 | { | 269 | { |
270 | struct ieee80211_sub_if_data *sdata; | 270 | struct ieee80211_sub_if_data *sdata; |
271 | int n_acs = IEEE80211_NUM_ACS; | ||
272 | |||
273 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
274 | n_acs = 1; | ||
271 | 275 | ||
272 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 276 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
273 | int ac; | 277 | int ac; |
@@ -279,7 +283,7 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) | |||
279 | local->queue_stop_reasons[sdata->vif.cab_queue] != 0) | 283 | local->queue_stop_reasons[sdata->vif.cab_queue] != 0) |
280 | continue; | 284 | continue; |
281 | 285 | ||
282 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 286 | for (ac = 0; ac < n_acs; ac++) { |
283 | int ac_queue = sdata->vif.hw_queue[ac]; | 287 | int ac_queue = sdata->vif.hw_queue[ac]; |
284 | 288 | ||
285 | if (ac_queue == queue || | 289 | if (ac_queue == queue || |
@@ -341,6 +345,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
341 | { | 345 | { |
342 | struct ieee80211_local *local = hw_to_local(hw); | 346 | struct ieee80211_local *local = hw_to_local(hw); |
343 | struct ieee80211_sub_if_data *sdata; | 347 | struct ieee80211_sub_if_data *sdata; |
348 | int n_acs = IEEE80211_NUM_ACS; | ||
344 | 349 | ||
345 | trace_stop_queue(local, queue, reason); | 350 | trace_stop_queue(local, queue, reason); |
346 | 351 | ||
@@ -352,11 +357,14 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
352 | 357 | ||
353 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 358 | __set_bit(reason, &local->queue_stop_reasons[queue]); |
354 | 359 | ||
360 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
361 | n_acs = 1; | ||
362 | |||
355 | rcu_read_lock(); | 363 | rcu_read_lock(); |
356 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 364 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
357 | int ac; | 365 | int ac; |
358 | 366 | ||
359 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 367 | for (ac = 0; ac < n_acs; ac++) { |
360 | if (sdata->vif.hw_queue[ac] == queue || | 368 | if (sdata->vif.hw_queue[ac] == queue || |
361 | sdata->vif.cab_queue == queue) | 369 | sdata->vif.cab_queue == queue) |
362 | netif_stop_subqueue(sdata->dev, ac); | 370 | netif_stop_subqueue(sdata->dev, ac); |
@@ -1072,6 +1080,10 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1072 | pos += noffset - offset; | 1080 | pos += noffset - offset; |
1073 | } | 1081 | } |
1074 | 1082 | ||
1083 | if (sband->vht_cap.vht_supported) | ||
1084 | pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, | ||
1085 | sband->vht_cap.cap); | ||
1086 | |||
1075 | return pos - buffer; | 1087 | return pos - buffer; |
1076 | } | 1088 | } |
1077 | 1089 | ||
@@ -1411,10 +1423,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1411 | if (ieee80211_sdata_running(sdata)) | 1423 | if (ieee80211_sdata_running(sdata)) |
1412 | ieee80211_enable_keys(sdata); | 1424 | ieee80211_enable_keys(sdata); |
1413 | 1425 | ||
1426 | wake_up: | ||
1414 | local->in_reconfig = false; | 1427 | local->in_reconfig = false; |
1415 | barrier(); | 1428 | barrier(); |
1416 | 1429 | ||
1417 | wake_up: | ||
1418 | /* | 1430 | /* |
1419 | * Clear the WLAN_STA_BLOCK_BA flag so new aggregation | 1431 | * Clear the WLAN_STA_BLOCK_BA flag so new aggregation |
1420 | * sessions can be established after a resume. | 1432 | * sessions can be established after a resume. |
@@ -1699,6 +1711,27 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
1699 | return pos; | 1711 | return pos; |
1700 | } | 1712 | } |
1701 | 1713 | ||
1714 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | ||
1715 | u32 cap) | ||
1716 | { | ||
1717 | __le32 tmp; | ||
1718 | |||
1719 | *pos++ = WLAN_EID_VHT_CAPABILITY; | ||
1720 | *pos++ = sizeof(struct ieee80211_vht_capabilities); | ||
1721 | memset(pos, 0, sizeof(struct ieee80211_vht_capabilities)); | ||
1722 | |||
1723 | /* capability flags */ | ||
1724 | tmp = cpu_to_le32(cap); | ||
1725 | memcpy(pos, &tmp, sizeof(u32)); | ||
1726 | pos += sizeof(u32); | ||
1727 | |||
1728 | /* VHT MCS set */ | ||
1729 | memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs)); | ||
1730 | pos += sizeof(vht_cap->vht_mcs); | ||
1731 | |||
1732 | return pos; | ||
1733 | } | ||
1734 | |||
1702 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1735 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
1703 | struct ieee80211_channel *channel, | 1736 | struct ieee80211_channel *channel, |
1704 | enum nl80211_channel_type channel_type, | 1737 | enum nl80211_channel_type channel_type, |
@@ -1764,15 +1797,14 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) | |||
1764 | return channel_type; | 1797 | return channel_type; |
1765 | } | 1798 | } |
1766 | 1799 | ||
1767 | int ieee80211_add_srates_ie(struct ieee80211_vif *vif, | 1800 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, |
1768 | struct sk_buff *skb, bool need_basic) | 1801 | struct sk_buff *skb, bool need_basic) |
1769 | { | 1802 | { |
1770 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1771 | struct ieee80211_local *local = sdata->local; | 1803 | struct ieee80211_local *local = sdata->local; |
1772 | struct ieee80211_supported_band *sband; | 1804 | struct ieee80211_supported_band *sband; |
1773 | int rate; | 1805 | int rate; |
1774 | u8 i, rates, *pos; | 1806 | u8 i, rates, *pos; |
1775 | u32 basic_rates = vif->bss_conf.basic_rates; | 1807 | u32 basic_rates = sdata->vif.bss_conf.basic_rates; |
1776 | 1808 | ||
1777 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1809 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1778 | rates = sband->n_bitrates; | 1810 | rates = sband->n_bitrates; |
@@ -1796,15 +1828,14 @@ int ieee80211_add_srates_ie(struct ieee80211_vif *vif, | |||
1796 | return 0; | 1828 | return 0; |
1797 | } | 1829 | } |
1798 | 1830 | ||
1799 | int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, | 1831 | int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, |
1800 | struct sk_buff *skb, bool need_basic) | 1832 | struct sk_buff *skb, bool need_basic) |
1801 | { | 1833 | { |
1802 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1803 | struct ieee80211_local *local = sdata->local; | 1834 | struct ieee80211_local *local = sdata->local; |
1804 | struct ieee80211_supported_band *sband; | 1835 | struct ieee80211_supported_band *sband; |
1805 | int rate; | 1836 | int rate; |
1806 | u8 i, exrates, *pos; | 1837 | u8 i, exrates, *pos; |
1807 | u32 basic_rates = vif->bss_conf.basic_rates; | 1838 | u32 basic_rates = sdata->vif.bss_conf.basic_rates; |
1808 | 1839 | ||
1809 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1840 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1810 | exrates = sband->n_bitrates; | 1841 | exrates = sband->n_bitrates; |
diff --git a/net/nfc/core.c b/net/nfc/core.c index 4177bb5104b9..ff749794bc5b 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/nfc.h> | 30 | #include <linux/nfc.h> |
31 | 31 | ||
32 | #include <net/genetlink.h> | ||
33 | |||
32 | #include "nfc.h" | 34 | #include "nfc.h" |
33 | 35 | ||
34 | #define VERSION "0.1" | 36 | #define VERSION "0.1" |
@@ -560,6 +562,8 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb); | |||
560 | * The device driver must call this function when one or many nfc targets | 562 | * The device driver must call this function when one or many nfc targets |
561 | * are found. After calling this function, the device driver must stop | 563 | * are found. After calling this function, the device driver must stop |
562 | * polling for targets. | 564 | * polling for targets. |
565 | * NOTE: This function can be called with targets=NULL and n_targets=0 to | ||
566 | * notify a driver error, meaning that the polling operation cannot complete. | ||
563 | * IMPORTANT: this function must not be called from an atomic context. | 567 | * IMPORTANT: this function must not be called from an atomic context. |
564 | * In addition, it must also not be called from a context that would prevent | 568 | * In addition, it must also not be called from a context that would prevent |
565 | * the NFC Core to call other nfc ops entry point concurrently. | 569 | * the NFC Core to call other nfc ops entry point concurrently. |
@@ -571,23 +575,33 @@ int nfc_targets_found(struct nfc_dev *dev, | |||
571 | 575 | ||
572 | pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets); | 576 | pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets); |
573 | 577 | ||
574 | dev->polling = false; | ||
575 | |||
576 | for (i = 0; i < n_targets; i++) | 578 | for (i = 0; i < n_targets; i++) |
577 | targets[i].idx = dev->target_next_idx++; | 579 | targets[i].idx = dev->target_next_idx++; |
578 | 580 | ||
579 | device_lock(&dev->dev); | 581 | device_lock(&dev->dev); |
580 | 582 | ||
583 | if (dev->polling == false) { | ||
584 | device_unlock(&dev->dev); | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | dev->polling = false; | ||
589 | |||
581 | dev->targets_generation++; | 590 | dev->targets_generation++; |
582 | 591 | ||
583 | kfree(dev->targets); | 592 | kfree(dev->targets); |
584 | dev->targets = kmemdup(targets, n_targets * sizeof(struct nfc_target), | 593 | dev->targets = NULL; |
585 | GFP_ATOMIC); | ||
586 | 594 | ||
587 | if (!dev->targets) { | 595 | if (targets) { |
588 | dev->n_targets = 0; | 596 | dev->targets = kmemdup(targets, |
589 | device_unlock(&dev->dev); | 597 | n_targets * sizeof(struct nfc_target), |
590 | return -ENOMEM; | 598 | GFP_ATOMIC); |
599 | |||
600 | if (!dev->targets) { | ||
601 | dev->n_targets = 0; | ||
602 | device_unlock(&dev->dev); | ||
603 | return -ENOMEM; | ||
604 | } | ||
591 | } | 605 | } |
592 | 606 | ||
593 | dev->n_targets = n_targets; | 607 | dev->n_targets = n_targets; |
@@ -651,6 +665,12 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) | |||
651 | } | 665 | } |
652 | EXPORT_SYMBOL(nfc_target_lost); | 666 | EXPORT_SYMBOL(nfc_target_lost); |
653 | 667 | ||
668 | inline void nfc_driver_failure(struct nfc_dev *dev, int err) | ||
669 | { | ||
670 | nfc_targets_found(dev, NULL, 0); | ||
671 | } | ||
672 | EXPORT_SYMBOL(nfc_driver_failure); | ||
673 | |||
654 | static void nfc_release(struct device *d) | 674 | static void nfc_release(struct device *d) |
655 | { | 675 | { |
656 | struct nfc_dev *dev = to_nfc_dev(d); | 676 | struct nfc_dev *dev = to_nfc_dev(d); |
@@ -906,3 +926,5 @@ MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>"); | |||
906 | MODULE_DESCRIPTION("NFC Core ver " VERSION); | 926 | MODULE_DESCRIPTION("NFC Core ver " VERSION); |
907 | MODULE_VERSION(VERSION); | 927 | MODULE_VERSION(VERSION); |
908 | MODULE_LICENSE("GPL"); | 928 | MODULE_LICENSE("GPL"); |
929 | MODULE_ALIAS_NETPROTO(PF_NFC); | ||
930 | MODULE_ALIAS_GENL_FAMILY(NFC_GENL_NAME); | ||
diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 8729abf5f18b..46362ef979db 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c | |||
@@ -28,26 +28,14 @@ | |||
28 | 28 | ||
29 | #include "hci.h" | 29 | #include "hci.h" |
30 | 30 | ||
31 | static int nfc_hci_result_to_errno(u8 result) | 31 | static void nfc_hci_execute_cb(struct nfc_hci_dev *hdev, int err, |
32 | { | ||
33 | switch (result) { | ||
34 | case NFC_HCI_ANY_OK: | ||
35 | return 0; | ||
36 | case NFC_HCI_ANY_E_TIMEOUT: | ||
37 | return -ETIMEDOUT; | ||
38 | default: | ||
39 | return -1; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | static void nfc_hci_execute_cb(struct nfc_hci_dev *hdev, u8 result, | ||
44 | struct sk_buff *skb, void *cb_data) | 32 | struct sk_buff *skb, void *cb_data) |
45 | { | 33 | { |
46 | struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)cb_data; | 34 | struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)cb_data; |
47 | 35 | ||
48 | pr_debug("HCI Cmd completed with HCI result=%d\n", result); | 36 | pr_debug("HCI Cmd completed with result=%d\n", err); |
49 | 37 | ||
50 | hcp_ew->exec_result = nfc_hci_result_to_errno(result); | 38 | hcp_ew->exec_result = err; |
51 | if (hcp_ew->exec_result == 0) | 39 | if (hcp_ew->exec_result == 0) |
52 | hcp_ew->result_skb = skb; | 40 | hcp_ew->result_skb = skb; |
53 | else | 41 | else |
@@ -311,9 +299,9 @@ int nfc_hci_disconnect_all_gates(struct nfc_hci_dev *hdev) | |||
311 | } | 299 | } |
312 | EXPORT_SYMBOL(nfc_hci_disconnect_all_gates); | 300 | EXPORT_SYMBOL(nfc_hci_disconnect_all_gates); |
313 | 301 | ||
314 | int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate) | 302 | int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, |
303 | u8 pipe) | ||
315 | { | 304 | { |
316 | u8 pipe = NFC_HCI_INVALID_PIPE; | ||
317 | bool pipe_created = false; | 305 | bool pipe_created = false; |
318 | int r; | 306 | int r; |
319 | 307 | ||
@@ -322,6 +310,9 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate) | |||
322 | if (hdev->gate2pipe[dest_gate] != NFC_HCI_INVALID_PIPE) | 310 | if (hdev->gate2pipe[dest_gate] != NFC_HCI_INVALID_PIPE) |
323 | return -EADDRINUSE; | 311 | return -EADDRINUSE; |
324 | 312 | ||
313 | if (pipe != NFC_HCI_INVALID_PIPE) | ||
314 | goto pipe_is_open; | ||
315 | |||
325 | switch (dest_gate) { | 316 | switch (dest_gate) { |
326 | case NFC_HCI_LINK_MGMT_GATE: | 317 | case NFC_HCI_LINK_MGMT_GATE: |
327 | pipe = NFC_HCI_LINK_MGMT_PIPE; | 318 | pipe = NFC_HCI_LINK_MGMT_PIPE; |
@@ -347,6 +338,7 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate) | |||
347 | return r; | 338 | return r; |
348 | } | 339 | } |
349 | 340 | ||
341 | pipe_is_open: | ||
350 | hdev->gate2pipe[dest_gate] = pipe; | 342 | hdev->gate2pipe[dest_gate] = pipe; |
351 | 343 | ||
352 | return 0; | 344 | return 0; |
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index a8b0b71e8f86..36717cebfbb6 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c | |||
@@ -32,6 +32,18 @@ | |||
32 | /* Largest headroom needed for outgoing HCI commands */ | 32 | /* Largest headroom needed for outgoing HCI commands */ |
33 | #define HCI_CMDS_HEADROOM 1 | 33 | #define HCI_CMDS_HEADROOM 1 |
34 | 34 | ||
35 | static int nfc_hci_result_to_errno(u8 result) | ||
36 | { | ||
37 | switch (result) { | ||
38 | case NFC_HCI_ANY_OK: | ||
39 | return 0; | ||
40 | case NFC_HCI_ANY_E_TIMEOUT: | ||
41 | return -ETIME; | ||
42 | default: | ||
43 | return -1; | ||
44 | } | ||
45 | } | ||
46 | |||
35 | static void nfc_hci_msg_tx_work(struct work_struct *work) | 47 | static void nfc_hci_msg_tx_work(struct work_struct *work) |
36 | { | 48 | { |
37 | struct nfc_hci_dev *hdev = container_of(work, struct nfc_hci_dev, | 49 | struct nfc_hci_dev *hdev = container_of(work, struct nfc_hci_dev, |
@@ -46,7 +58,7 @@ static void nfc_hci_msg_tx_work(struct work_struct *work) | |||
46 | if (timer_pending(&hdev->cmd_timer) == 0) { | 58 | if (timer_pending(&hdev->cmd_timer) == 0) { |
47 | if (hdev->cmd_pending_msg->cb) | 59 | if (hdev->cmd_pending_msg->cb) |
48 | hdev->cmd_pending_msg->cb(hdev, | 60 | hdev->cmd_pending_msg->cb(hdev, |
49 | NFC_HCI_ANY_E_TIMEOUT, | 61 | -ETIME, |
50 | NULL, | 62 | NULL, |
51 | hdev-> | 63 | hdev-> |
52 | cmd_pending_msg-> | 64 | cmd_pending_msg-> |
@@ -71,8 +83,7 @@ next_msg: | |||
71 | kfree_skb(skb); | 83 | kfree_skb(skb); |
72 | skb_queue_purge(&msg->msg_frags); | 84 | skb_queue_purge(&msg->msg_frags); |
73 | if (msg->cb) | 85 | if (msg->cb) |
74 | msg->cb(hdev, NFC_HCI_ANY_E_NOK, NULL, | 86 | msg->cb(hdev, r, NULL, msg->cb_context); |
75 | msg->cb_context); | ||
76 | kfree(msg); | 87 | kfree(msg); |
77 | break; | 88 | break; |
78 | } | 89 | } |
@@ -116,20 +127,13 @@ static void nfc_hci_msg_rx_work(struct work_struct *work) | |||
116 | } | 127 | } |
117 | } | 128 | } |
118 | 129 | ||
119 | void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, | 130 | static void __nfc_hci_cmd_completion(struct nfc_hci_dev *hdev, int err, |
120 | struct sk_buff *skb) | 131 | struct sk_buff *skb) |
121 | { | 132 | { |
122 | mutex_lock(&hdev->msg_tx_mutex); | ||
123 | |||
124 | if (hdev->cmd_pending_msg == NULL) { | ||
125 | kfree_skb(skb); | ||
126 | goto exit; | ||
127 | } | ||
128 | |||
129 | del_timer_sync(&hdev->cmd_timer); | 133 | del_timer_sync(&hdev->cmd_timer); |
130 | 134 | ||
131 | if (hdev->cmd_pending_msg->cb) | 135 | if (hdev->cmd_pending_msg->cb) |
132 | hdev->cmd_pending_msg->cb(hdev, result, skb, | 136 | hdev->cmd_pending_msg->cb(hdev, err, skb, |
133 | hdev->cmd_pending_msg->cb_context); | 137 | hdev->cmd_pending_msg->cb_context); |
134 | else | 138 | else |
135 | kfree_skb(skb); | 139 | kfree_skb(skb); |
@@ -138,6 +142,19 @@ void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, | |||
138 | hdev->cmd_pending_msg = NULL; | 142 | hdev->cmd_pending_msg = NULL; |
139 | 143 | ||
140 | queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); | 144 | queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); |
145 | } | ||
146 | |||
147 | void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, | ||
148 | struct sk_buff *skb) | ||
149 | { | ||
150 | mutex_lock(&hdev->msg_tx_mutex); | ||
151 | |||
152 | if (hdev->cmd_pending_msg == NULL) { | ||
153 | kfree_skb(skb); | ||
154 | goto exit; | ||
155 | } | ||
156 | |||
157 | __nfc_hci_cmd_completion(hdev, nfc_hci_result_to_errno(result), skb); | ||
141 | 158 | ||
142 | exit: | 159 | exit: |
143 | mutex_unlock(&hdev->msg_tx_mutex); | 160 | mutex_unlock(&hdev->msg_tx_mutex); |
@@ -213,7 +230,7 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) | |||
213 | } | 230 | } |
214 | break; | 231 | break; |
215 | case NFC_HCI_RF_READER_B_GATE: | 232 | case NFC_HCI_RF_READER_B_GATE: |
216 | targets->supported_protocols = NFC_PROTO_ISO14443_MASK; | 233 | targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK; |
217 | break; | 234 | break; |
218 | default: | 235 | default: |
219 | if (hdev->ops->target_from_gate) | 236 | if (hdev->ops->target_from_gate) |
@@ -298,15 +315,15 @@ static void nfc_hci_cmd_timeout(unsigned long data) | |||
298 | } | 315 | } |
299 | 316 | ||
300 | static int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count, | 317 | static int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count, |
301 | u8 gates[]) | 318 | struct nfc_hci_gate *gates) |
302 | { | 319 | { |
303 | int r; | 320 | int r; |
304 | u8 *p = gates; | ||
305 | while (gate_count--) { | 321 | while (gate_count--) { |
306 | r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, *p); | 322 | r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, |
323 | gates->gate, gates->pipe); | ||
307 | if (r < 0) | 324 | if (r < 0) |
308 | return r; | 325 | return r; |
309 | p++; | 326 | gates++; |
310 | } | 327 | } |
311 | 328 | ||
312 | return 0; | 329 | return 0; |
@@ -316,14 +333,13 @@ static int hci_dev_session_init(struct nfc_hci_dev *hdev) | |||
316 | { | 333 | { |
317 | struct sk_buff *skb = NULL; | 334 | struct sk_buff *skb = NULL; |
318 | int r; | 335 | int r; |
319 | u8 hci_gates[] = { /* NFC_HCI_ADMIN_GATE MUST be first */ | 336 | |
320 | NFC_HCI_ADMIN_GATE, NFC_HCI_LOOPBACK_GATE, | 337 | if (hdev->init_data.gates[0].gate != NFC_HCI_ADMIN_GATE) |
321 | NFC_HCI_ID_MGMT_GATE, NFC_HCI_LINK_MGMT_GATE, | 338 | return -EPROTO; |
322 | NFC_HCI_RF_READER_B_GATE, NFC_HCI_RF_READER_A_GATE | ||
323 | }; | ||
324 | 339 | ||
325 | r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, | 340 | r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, |
326 | NFC_HCI_ADMIN_GATE); | 341 | hdev->init_data.gates[0].gate, |
342 | hdev->init_data.gates[0].pipe); | ||
327 | if (r < 0) | 343 | if (r < 0) |
328 | goto exit; | 344 | goto exit; |
329 | 345 | ||
@@ -351,10 +367,6 @@ static int hci_dev_session_init(struct nfc_hci_dev *hdev) | |||
351 | if (r < 0) | 367 | if (r < 0) |
352 | goto exit; | 368 | goto exit; |
353 | 369 | ||
354 | r = hci_dev_connect_gates(hdev, sizeof(hci_gates), hci_gates); | ||
355 | if (r < 0) | ||
356 | goto disconnect_all; | ||
357 | |||
358 | r = hci_dev_connect_gates(hdev, hdev->init_data.gate_count, | 370 | r = hci_dev_connect_gates(hdev, hdev->init_data.gate_count, |
359 | hdev->init_data.gates); | 371 | hdev->init_data.gates); |
360 | if (r < 0) | 372 | if (r < 0) |
@@ -717,6 +729,27 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev) | |||
717 | } | 729 | } |
718 | EXPORT_SYMBOL(nfc_hci_get_clientdata); | 730 | EXPORT_SYMBOL(nfc_hci_get_clientdata); |
719 | 731 | ||
732 | static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) | ||
733 | { | ||
734 | mutex_lock(&hdev->msg_tx_mutex); | ||
735 | |||
736 | if (hdev->cmd_pending_msg == NULL) { | ||
737 | nfc_driver_failure(hdev->ndev, err); | ||
738 | goto exit; | ||
739 | } | ||
740 | |||
741 | __nfc_hci_cmd_completion(hdev, err, NULL); | ||
742 | |||
743 | exit: | ||
744 | mutex_unlock(&hdev->msg_tx_mutex); | ||
745 | } | ||
746 | |||
747 | void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) | ||
748 | { | ||
749 | nfc_hci_failure(hdev, err); | ||
750 | } | ||
751 | EXPORT_SYMBOL(nfc_hci_driver_failure); | ||
752 | |||
720 | void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) | 753 | void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) |
721 | { | 754 | { |
722 | struct hcp_packet *packet; | 755 | struct hcp_packet *packet; |
@@ -727,16 +760,6 @@ void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) | |||
727 | struct sk_buff *frag_skb; | 760 | struct sk_buff *frag_skb; |
728 | int msg_len; | 761 | int msg_len; |
729 | 762 | ||
730 | if (skb == NULL) { | ||
731 | /* TODO ELa: lower layer had permanent failure, need to | ||
732 | * propagate that up | ||
733 | */ | ||
734 | |||
735 | skb_queue_purge(&hdev->rx_hcp_frags); | ||
736 | |||
737 | return; | ||
738 | } | ||
739 | |||
740 | packet = (struct hcp_packet *)skb->data; | 763 | packet = (struct hcp_packet *)skb->data; |
741 | if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { | 764 | if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { |
742 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | 765 | skb_queue_tail(&hdev->rx_hcp_frags, skb); |
@@ -757,9 +780,8 @@ void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) | |||
757 | hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + | 780 | hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + |
758 | msg_len, GFP_KERNEL); | 781 | msg_len, GFP_KERNEL); |
759 | if (hcp_skb == NULL) { | 782 | if (hcp_skb == NULL) { |
760 | /* TODO ELa: cannot deliver HCP message. How to | 783 | nfc_hci_failure(hdev, -ENOMEM); |
761 | * propagate error up? | 784 | return; |
762 | */ | ||
763 | } | 785 | } |
764 | 786 | ||
765 | *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; | 787 | *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; |
diff --git a/net/nfc/hci/hci.h b/net/nfc/hci/hci.h index 45f2fe4fd486..fa9a21e92239 100644 --- a/net/nfc/hci/hci.h +++ b/net/nfc/hci/hci.h | |||
@@ -37,10 +37,11 @@ struct hcp_packet { | |||
37 | 37 | ||
38 | /* | 38 | /* |
39 | * HCI command execution completion callback. | 39 | * HCI command execution completion callback. |
40 | * result will be one of the HCI response codes. | 40 | * result will be a standard linux error (may be converted from HCI response) |
41 | * skb contains the response data and must be disposed. | 41 | * skb contains the response data and must be disposed, or may be NULL if |
42 | * an error occured | ||
42 | */ | 43 | */ |
43 | typedef void (*hci_cmd_cb_t) (struct nfc_hci_dev *hdev, u8 result, | 44 | typedef void (*hci_cmd_cb_t) (struct nfc_hci_dev *hdev, int result, |
44 | struct sk_buff *skb, void *cb_data); | 45 | struct sk_buff *skb, void *cb_data); |
45 | 46 | ||
46 | struct hcp_exec_waiter { | 47 | struct hcp_exec_waiter { |
@@ -131,9 +132,4 @@ void nfc_hci_hcp_message_rx(struct nfc_hci_dev *hdev, u8 pipe, u8 type, | |||
131 | #define NFC_HCI_ANY_E_REG_ACCESS_DENIED 0x0a | 132 | #define NFC_HCI_ANY_E_REG_ACCESS_DENIED 0x0a |
132 | #define NFC_HCI_ANY_E_PIPE_ACCESS_DENIED 0x0b | 133 | #define NFC_HCI_ANY_E_PIPE_ACCESS_DENIED 0x0b |
133 | 134 | ||
134 | /* Pipes */ | ||
135 | #define NFC_HCI_INVALID_PIPE 0x80 | ||
136 | #define NFC_HCI_LINK_MGMT_PIPE 0x00 | ||
137 | #define NFC_HCI_ADMIN_PIPE 0x01 | ||
138 | |||
139 | #endif /* __LOCAL_HCI_H */ | 135 | #endif /* __LOCAL_HCI_H */ |
diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c index 6b836e6242b7..6f840c18c892 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/shdlc.c | |||
@@ -340,15 +340,6 @@ static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) | |||
340 | shdlc->state = SHDLC_CONNECTED; | 340 | shdlc->state = SHDLC_CONNECTED; |
341 | } else { | 341 | } else { |
342 | shdlc->state = SHDLC_DISCONNECTED; | 342 | shdlc->state = SHDLC_DISCONNECTED; |
343 | |||
344 | /* | ||
345 | * TODO: Could it be possible that there are pending | ||
346 | * executing commands that are waiting for connect to complete | ||
347 | * before they can be carried? As connect is a blocking | ||
348 | * operation, it would require that the userspace process can | ||
349 | * send commands on the same device from a second thread before | ||
350 | * the device is up. I don't think that is possible, is it? | ||
351 | */ | ||
352 | } | 343 | } |
353 | 344 | ||
354 | shdlc->connect_result = r; | 345 | shdlc->connect_result = r; |
@@ -413,12 +404,12 @@ static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | |||
413 | r = nfc_shdlc_connect_send_ua(shdlc); | 404 | r = nfc_shdlc_connect_send_ua(shdlc); |
414 | nfc_shdlc_connect_complete(shdlc, r); | 405 | nfc_shdlc_connect_complete(shdlc, r); |
415 | } | 406 | } |
416 | } else if (shdlc->state > SHDLC_NEGOCIATING) { | 407 | } else if (shdlc->state == SHDLC_CONNECTED) { |
417 | /* | 408 | /* |
418 | * TODO: Chip wants to reset link | 409 | * Chip wants to reset link. This is unexpected and |
419 | * send ua, empty skb lists, reset counters | 410 | * unsupported. |
420 | * propagate info to HCI layer | ||
421 | */ | 411 | */ |
412 | shdlc->hard_fault = -ECONNRESET; | ||
422 | } | 413 | } |
423 | break; | 414 | break; |
424 | case U_FRAME_UA: | 415 | case U_FRAME_UA: |
@@ -523,10 +514,6 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | |||
523 | 514 | ||
524 | r = shdlc->ops->xmit(shdlc, skb); | 515 | r = shdlc->ops->xmit(shdlc, skb); |
525 | if (r < 0) { | 516 | if (r < 0) { |
526 | /* | ||
527 | * TODO: Cannot send, shdlc machine is dead, we | ||
528 | * must propagate the information up to HCI. | ||
529 | */ | ||
530 | shdlc->hard_fault = r; | 517 | shdlc->hard_fault = r; |
531 | break; | 518 | break; |
532 | } | 519 | } |
@@ -590,6 +577,11 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
590 | skb_queue_purge(&shdlc->ack_pending_q); | 577 | skb_queue_purge(&shdlc->ack_pending_q); |
591 | break; | 578 | break; |
592 | case SHDLC_CONNECTING: | 579 | case SHDLC_CONNECTING: |
580 | if (shdlc->hard_fault) { | ||
581 | nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); | ||
582 | break; | ||
583 | } | ||
584 | |||
593 | if (shdlc->connect_tries++ < 5) | 585 | if (shdlc->connect_tries++ < 5) |
594 | r = nfc_shdlc_connect_initiate(shdlc); | 586 | r = nfc_shdlc_connect_initiate(shdlc); |
595 | else | 587 | else |
@@ -610,6 +602,11 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
610 | } | 602 | } |
611 | 603 | ||
612 | nfc_shdlc_handle_rcv_queue(shdlc); | 604 | nfc_shdlc_handle_rcv_queue(shdlc); |
605 | |||
606 | if (shdlc->hard_fault) { | ||
607 | nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); | ||
608 | break; | ||
609 | } | ||
613 | break; | 610 | break; |
614 | case SHDLC_CONNECTED: | 611 | case SHDLC_CONNECTED: |
615 | nfc_shdlc_handle_rcv_queue(shdlc); | 612 | nfc_shdlc_handle_rcv_queue(shdlc); |
@@ -637,10 +634,7 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
637 | } | 634 | } |
638 | 635 | ||
639 | if (shdlc->hard_fault) { | 636 | if (shdlc->hard_fault) { |
640 | /* | 637 | nfc_hci_driver_failure(shdlc->hdev, shdlc->hard_fault); |
641 | * TODO: Handle hard_fault that occured during | ||
642 | * this invocation of the shdlc worker | ||
643 | */ | ||
644 | } | 638 | } |
645 | break; | 639 | break; |
646 | default: | 640 | default: |
@@ -923,8 +917,6 @@ void nfc_shdlc_free(struct nfc_shdlc *shdlc) | |||
923 | { | 917 | { |
924 | pr_debug("\n"); | 918 | pr_debug("\n"); |
925 | 919 | ||
926 | /* TODO: Check that this cannot be called while still in use */ | ||
927 | |||
928 | nfc_hci_unregister_device(shdlc->hdev); | 920 | nfc_hci_unregister_device(shdlc->hdev); |
929 | nfc_hci_free_device(shdlc->hdev); | 921 | nfc_hci_free_device(shdlc->hdev); |
930 | 922 | ||
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 5d503eeb15a1..82f0f7588b46 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c | |||
@@ -45,7 +45,7 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk) | |||
45 | write_unlock(&l->lock); | 45 | write_unlock(&l->lock); |
46 | } | 46 | } |
47 | 47 | ||
48 | static void nfc_llcp_socket_release(struct nfc_llcp_local *local) | 48 | static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) |
49 | { | 49 | { |
50 | struct sock *sk; | 50 | struct sock *sk; |
51 | struct hlist_node *node, *tmp; | 51 | struct hlist_node *node, *tmp; |
@@ -78,6 +78,11 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) | |||
78 | 78 | ||
79 | sock_orphan(accept_sk); | 79 | sock_orphan(accept_sk); |
80 | } | 80 | } |
81 | |||
82 | if (listen == true) { | ||
83 | release_sock(sk); | ||
84 | continue; | ||
85 | } | ||
81 | } | 86 | } |
82 | 87 | ||
83 | sk->sk_state = LLCP_CLOSED; | 88 | sk->sk_state = LLCP_CLOSED; |
@@ -106,7 +111,7 @@ static void local_release(struct kref *ref) | |||
106 | local = container_of(ref, struct nfc_llcp_local, ref); | 111 | local = container_of(ref, struct nfc_llcp_local, ref); |
107 | 112 | ||
108 | list_del(&local->list); | 113 | list_del(&local->list); |
109 | nfc_llcp_socket_release(local); | 114 | nfc_llcp_socket_release(local, false); |
110 | del_timer_sync(&local->link_timer); | 115 | del_timer_sync(&local->link_timer); |
111 | skb_queue_purge(&local->tx_queue); | 116 | skb_queue_purge(&local->tx_queue); |
112 | destroy_workqueue(local->tx_wq); | 117 | destroy_workqueue(local->tx_wq); |
@@ -118,23 +123,48 @@ static void local_release(struct kref *ref) | |||
118 | 123 | ||
119 | int nfc_llcp_local_put(struct nfc_llcp_local *local) | 124 | int nfc_llcp_local_put(struct nfc_llcp_local *local) |
120 | { | 125 | { |
121 | WARN_ON(local == NULL); | ||
122 | |||
123 | if (local == NULL) | 126 | if (local == NULL) |
124 | return 0; | 127 | return 0; |
125 | 128 | ||
126 | return kref_put(&local->ref, local_release); | 129 | return kref_put(&local->ref, local_release); |
127 | } | 130 | } |
128 | 131 | ||
129 | static void nfc_llcp_clear_sdp(struct nfc_llcp_local *local) | 132 | static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, |
133 | u8 ssap, u8 dsap) | ||
130 | { | 134 | { |
131 | mutex_lock(&local->sdp_lock); | 135 | struct sock *sk; |
136 | struct hlist_node *node; | ||
137 | struct nfc_llcp_sock *llcp_sock; | ||
132 | 138 | ||
133 | local->local_wks = 0; | 139 | pr_debug("ssap dsap %d %d\n", ssap, dsap); |
134 | local->local_sdp = 0; | ||
135 | local->local_sap = 0; | ||
136 | 140 | ||
137 | mutex_unlock(&local->sdp_lock); | 141 | if (ssap == 0 && dsap == 0) |
142 | return NULL; | ||
143 | |||
144 | read_lock(&local->sockets.lock); | ||
145 | |||
146 | llcp_sock = NULL; | ||
147 | |||
148 | sk_for_each(sk, node, &local->sockets.head) { | ||
149 | llcp_sock = nfc_llcp_sock(sk); | ||
150 | |||
151 | if (llcp_sock->ssap == ssap && llcp_sock->dsap == dsap) | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | read_unlock(&local->sockets.lock); | ||
156 | |||
157 | if (llcp_sock == NULL) | ||
158 | return NULL; | ||
159 | |||
160 | sock_hold(&llcp_sock->sk); | ||
161 | |||
162 | return llcp_sock; | ||
163 | } | ||
164 | |||
165 | static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock) | ||
166 | { | ||
167 | sock_put(&sock->sk); | ||
138 | } | 168 | } |
139 | 169 | ||
140 | static void nfc_llcp_timeout_work(struct work_struct *work) | 170 | static void nfc_llcp_timeout_work(struct work_struct *work) |
@@ -197,6 +227,51 @@ static int nfc_llcp_wks_sap(char *service_name, size_t service_name_len) | |||
197 | return -EINVAL; | 227 | return -EINVAL; |
198 | } | 228 | } |
199 | 229 | ||
230 | static | ||
231 | struct nfc_llcp_sock *nfc_llcp_sock_from_sn(struct nfc_llcp_local *local, | ||
232 | u8 *sn, size_t sn_len) | ||
233 | { | ||
234 | struct sock *sk; | ||
235 | struct hlist_node *node; | ||
236 | struct nfc_llcp_sock *llcp_sock, *tmp_sock; | ||
237 | |||
238 | pr_debug("sn %zd %p\n", sn_len, sn); | ||
239 | |||
240 | if (sn == NULL || sn_len == 0) | ||
241 | return NULL; | ||
242 | |||
243 | read_lock(&local->sockets.lock); | ||
244 | |||
245 | llcp_sock = NULL; | ||
246 | |||
247 | sk_for_each(sk, node, &local->sockets.head) { | ||
248 | tmp_sock = nfc_llcp_sock(sk); | ||
249 | |||
250 | pr_debug("llcp sock %p\n", tmp_sock); | ||
251 | |||
252 | if (tmp_sock->sk.sk_state != LLCP_LISTEN) | ||
253 | continue; | ||
254 | |||
255 | if (tmp_sock->service_name == NULL || | ||
256 | tmp_sock->service_name_len == 0) | ||
257 | continue; | ||
258 | |||
259 | if (tmp_sock->service_name_len != sn_len) | ||
260 | continue; | ||
261 | |||
262 | if (memcmp(sn, tmp_sock->service_name, sn_len) == 0) { | ||
263 | llcp_sock = tmp_sock; | ||
264 | break; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | read_unlock(&local->sockets.lock); | ||
269 | |||
270 | pr_debug("Found llcp sock %p\n", llcp_sock); | ||
271 | |||
272 | return llcp_sock; | ||
273 | } | ||
274 | |||
200 | u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, | 275 | u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, |
201 | struct nfc_llcp_sock *sock) | 276 | struct nfc_llcp_sock *sock) |
202 | { | 277 | { |
@@ -223,41 +298,26 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, | |||
223 | } | 298 | } |
224 | 299 | ||
225 | /* | 300 | /* |
226 | * This is not a well known service, | 301 | * Check if there already is a non WKS socket bound |
227 | * we should try to find a local SDP free spot | 302 | * to this service name. |
228 | */ | 303 | */ |
229 | ssap = find_first_zero_bit(&local->local_sdp, LLCP_SDP_NUM_SAP); | 304 | if (nfc_llcp_sock_from_sn(local, sock->service_name, |
230 | if (ssap == LLCP_SDP_NUM_SAP) { | 305 | sock->service_name_len) != NULL) { |
231 | mutex_unlock(&local->sdp_lock); | 306 | mutex_unlock(&local->sdp_lock); |
232 | 307 | ||
233 | return LLCP_SAP_MAX; | 308 | return LLCP_SAP_MAX; |
234 | } | 309 | } |
235 | 310 | ||
236 | pr_debug("SDP ssap %d\n", LLCP_WKS_NUM_SAP + ssap); | ||
237 | |||
238 | set_bit(ssap, &local->local_sdp); | ||
239 | mutex_unlock(&local->sdp_lock); | 311 | mutex_unlock(&local->sdp_lock); |
240 | 312 | ||
241 | return LLCP_WKS_NUM_SAP + ssap; | 313 | return LLCP_SDP_UNBOUND; |
242 | |||
243 | } else if (sock->ssap != 0) { | ||
244 | if (sock->ssap < LLCP_WKS_NUM_SAP) { | ||
245 | if (!test_bit(sock->ssap, &local->local_wks)) { | ||
246 | set_bit(sock->ssap, &local->local_wks); | ||
247 | mutex_unlock(&local->sdp_lock); | ||
248 | |||
249 | return sock->ssap; | ||
250 | } | ||
251 | 314 | ||
252 | } else if (sock->ssap < LLCP_SDP_NUM_SAP) { | 315 | } else if (sock->ssap != 0 && sock->ssap < LLCP_WKS_NUM_SAP) { |
253 | if (!test_bit(sock->ssap - LLCP_WKS_NUM_SAP, | 316 | if (!test_bit(sock->ssap, &local->local_wks)) { |
254 | &local->local_sdp)) { | 317 | set_bit(sock->ssap, &local->local_wks); |
255 | set_bit(sock->ssap - LLCP_WKS_NUM_SAP, | 318 | mutex_unlock(&local->sdp_lock); |
256 | &local->local_sdp); | ||
257 | mutex_unlock(&local->sdp_lock); | ||
258 | 319 | ||
259 | return sock->ssap; | 320 | return sock->ssap; |
260 | } | ||
261 | } | 321 | } |
262 | } | 322 | } |
263 | 323 | ||
@@ -294,8 +354,34 @@ void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap) | |||
294 | local_ssap = ssap; | 354 | local_ssap = ssap; |
295 | sdp = &local->local_wks; | 355 | sdp = &local->local_wks; |
296 | } else if (ssap < LLCP_LOCAL_NUM_SAP) { | 356 | } else if (ssap < LLCP_LOCAL_NUM_SAP) { |
357 | atomic_t *client_cnt; | ||
358 | |||
297 | local_ssap = ssap - LLCP_WKS_NUM_SAP; | 359 | local_ssap = ssap - LLCP_WKS_NUM_SAP; |
298 | sdp = &local->local_sdp; | 360 | sdp = &local->local_sdp; |
361 | client_cnt = &local->local_sdp_cnt[local_ssap]; | ||
362 | |||
363 | pr_debug("%d clients\n", atomic_read(client_cnt)); | ||
364 | |||
365 | mutex_lock(&local->sdp_lock); | ||
366 | |||
367 | if (atomic_dec_and_test(client_cnt)) { | ||
368 | struct nfc_llcp_sock *l_sock; | ||
369 | |||
370 | pr_debug("No more clients for SAP %d\n", ssap); | ||
371 | |||
372 | clear_bit(local_ssap, sdp); | ||
373 | |||
374 | /* Find the listening sock and set it back to UNBOUND */ | ||
375 | l_sock = nfc_llcp_sock_get(local, ssap, LLCP_SAP_SDP); | ||
376 | if (l_sock) { | ||
377 | l_sock->ssap = LLCP_SDP_UNBOUND; | ||
378 | nfc_llcp_sock_put(l_sock); | ||
379 | } | ||
380 | } | ||
381 | |||
382 | mutex_unlock(&local->sdp_lock); | ||
383 | |||
384 | return; | ||
299 | } else if (ssap < LLCP_MAX_SAP) { | 385 | } else if (ssap < LLCP_MAX_SAP) { |
300 | local_ssap = ssap - LLCP_LOCAL_NUM_SAP; | 386 | local_ssap = ssap - LLCP_LOCAL_NUM_SAP; |
301 | sdp = &local->local_sap; | 387 | sdp = &local->local_sap; |
@@ -310,19 +396,26 @@ void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap) | |||
310 | mutex_unlock(&local->sdp_lock); | 396 | mutex_unlock(&local->sdp_lock); |
311 | } | 397 | } |
312 | 398 | ||
313 | u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) | 399 | static u8 nfc_llcp_reserve_sdp_ssap(struct nfc_llcp_local *local) |
314 | { | 400 | { |
315 | struct nfc_llcp_local *local; | 401 | u8 ssap; |
316 | 402 | ||
317 | local = nfc_llcp_find_local(dev); | 403 | mutex_lock(&local->sdp_lock); |
318 | if (local == NULL) { | 404 | |
319 | *general_bytes_len = 0; | 405 | ssap = find_first_zero_bit(&local->local_sdp, LLCP_SDP_NUM_SAP); |
320 | return NULL; | 406 | if (ssap == LLCP_SDP_NUM_SAP) { |
407 | mutex_unlock(&local->sdp_lock); | ||
408 | |||
409 | return LLCP_SAP_MAX; | ||
321 | } | 410 | } |
322 | 411 | ||
323 | *general_bytes_len = local->gb_len; | 412 | pr_debug("SDP ssap %d\n", LLCP_WKS_NUM_SAP + ssap); |
324 | 413 | ||
325 | return local->gb; | 414 | set_bit(ssap, &local->local_sdp); |
415 | |||
416 | mutex_unlock(&local->sdp_lock); | ||
417 | |||
418 | return LLCP_WKS_NUM_SAP + ssap; | ||
326 | } | 419 | } |
327 | 420 | ||
328 | static int nfc_llcp_build_gb(struct nfc_llcp_local *local) | 421 | static int nfc_llcp_build_gb(struct nfc_llcp_local *local) |
@@ -386,6 +479,23 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) | |||
386 | return 0; | 479 | return 0; |
387 | } | 480 | } |
388 | 481 | ||
482 | u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) | ||
483 | { | ||
484 | struct nfc_llcp_local *local; | ||
485 | |||
486 | local = nfc_llcp_find_local(dev); | ||
487 | if (local == NULL) { | ||
488 | *general_bytes_len = 0; | ||
489 | return NULL; | ||
490 | } | ||
491 | |||
492 | nfc_llcp_build_gb(local); | ||
493 | |||
494 | *general_bytes_len = local->gb_len; | ||
495 | |||
496 | return local->gb; | ||
497 | } | ||
498 | |||
389 | int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) | 499 | int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) |
390 | { | 500 | { |
391 | struct nfc_llcp_local *local = nfc_llcp_find_local(dev); | 501 | struct nfc_llcp_local *local = nfc_llcp_find_local(dev); |
@@ -509,74 +619,12 @@ out: | |||
509 | return llcp_sock; | 619 | return llcp_sock; |
510 | } | 620 | } |
511 | 621 | ||
512 | static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, | ||
513 | u8 ssap, u8 dsap) | ||
514 | { | ||
515 | struct sock *sk; | ||
516 | struct hlist_node *node; | ||
517 | struct nfc_llcp_sock *llcp_sock; | ||
518 | |||
519 | pr_debug("ssap dsap %d %d\n", ssap, dsap); | ||
520 | |||
521 | if (ssap == 0 && dsap == 0) | ||
522 | return NULL; | ||
523 | |||
524 | read_lock(&local->sockets.lock); | ||
525 | |||
526 | llcp_sock = NULL; | ||
527 | |||
528 | sk_for_each(sk, node, &local->sockets.head) { | ||
529 | llcp_sock = nfc_llcp_sock(sk); | ||
530 | |||
531 | if (llcp_sock->ssap == ssap && | ||
532 | llcp_sock->dsap == dsap) | ||
533 | break; | ||
534 | } | ||
535 | |||
536 | read_unlock(&local->sockets.lock); | ||
537 | |||
538 | if (llcp_sock == NULL) | ||
539 | return NULL; | ||
540 | |||
541 | sock_hold(&llcp_sock->sk); | ||
542 | |||
543 | return llcp_sock; | ||
544 | } | ||
545 | |||
546 | static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local, | 622 | static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local, |
547 | u8 *sn, size_t sn_len) | 623 | u8 *sn, size_t sn_len) |
548 | { | 624 | { |
549 | struct sock *sk; | ||
550 | struct hlist_node *node; | ||
551 | struct nfc_llcp_sock *llcp_sock; | 625 | struct nfc_llcp_sock *llcp_sock; |
552 | 626 | ||
553 | pr_debug("sn %zd\n", sn_len); | 627 | llcp_sock = nfc_llcp_sock_from_sn(local, sn, sn_len); |
554 | |||
555 | if (sn == NULL || sn_len == 0) | ||
556 | return NULL; | ||
557 | |||
558 | read_lock(&local->sockets.lock); | ||
559 | |||
560 | llcp_sock = NULL; | ||
561 | |||
562 | sk_for_each(sk, node, &local->sockets.head) { | ||
563 | llcp_sock = nfc_llcp_sock(sk); | ||
564 | |||
565 | if (llcp_sock->sk.sk_state != LLCP_LISTEN) | ||
566 | continue; | ||
567 | |||
568 | if (llcp_sock->service_name == NULL || | ||
569 | llcp_sock->service_name_len == 0) | ||
570 | continue; | ||
571 | |||
572 | if (llcp_sock->service_name_len != sn_len) | ||
573 | continue; | ||
574 | |||
575 | if (memcmp(sn, llcp_sock->service_name, sn_len) == 0) | ||
576 | break; | ||
577 | } | ||
578 | |||
579 | read_unlock(&local->sockets.lock); | ||
580 | 628 | ||
581 | if (llcp_sock == NULL) | 629 | if (llcp_sock == NULL) |
582 | return NULL; | 630 | return NULL; |
@@ -586,11 +634,6 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local, | |||
586 | return llcp_sock; | 634 | return llcp_sock; |
587 | } | 635 | } |
588 | 636 | ||
589 | static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock) | ||
590 | { | ||
591 | sock_put(&sock->sk); | ||
592 | } | ||
593 | |||
594 | static u8 *nfc_llcp_connect_sn(struct sk_buff *skb, size_t *sn_len) | 637 | static u8 *nfc_llcp_connect_sn(struct sk_buff *skb, size_t *sn_len) |
595 | { | 638 | { |
596 | u8 *tlv = &skb->data[2], type, length; | 639 | u8 *tlv = &skb->data[2], type, length; |
@@ -662,6 +705,21 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, | |||
662 | goto fail; | 705 | goto fail; |
663 | } | 706 | } |
664 | 707 | ||
708 | if (sock->ssap == LLCP_SDP_UNBOUND) { | ||
709 | u8 ssap = nfc_llcp_reserve_sdp_ssap(local); | ||
710 | |||
711 | pr_debug("First client, reserving %d\n", ssap); | ||
712 | |||
713 | if (ssap == LLCP_SAP_MAX) { | ||
714 | reason = LLCP_DM_REJ; | ||
715 | release_sock(&sock->sk); | ||
716 | sock_put(&sock->sk); | ||
717 | goto fail; | ||
718 | } | ||
719 | |||
720 | sock->ssap = ssap; | ||
721 | } | ||
722 | |||
665 | new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type, GFP_ATOMIC); | 723 | new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type, GFP_ATOMIC); |
666 | if (new_sk == NULL) { | 724 | if (new_sk == NULL) { |
667 | reason = LLCP_DM_REJ; | 725 | reason = LLCP_DM_REJ; |
@@ -675,9 +733,21 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, | |||
675 | new_sock->local = nfc_llcp_local_get(local); | 733 | new_sock->local = nfc_llcp_local_get(local); |
676 | new_sock->miu = local->remote_miu; | 734 | new_sock->miu = local->remote_miu; |
677 | new_sock->nfc_protocol = sock->nfc_protocol; | 735 | new_sock->nfc_protocol = sock->nfc_protocol; |
678 | new_sock->ssap = sock->ssap; | ||
679 | new_sock->dsap = ssap; | 736 | new_sock->dsap = ssap; |
737 | new_sock->target_idx = local->target_idx; | ||
680 | new_sock->parent = parent; | 738 | new_sock->parent = parent; |
739 | new_sock->ssap = sock->ssap; | ||
740 | if (sock->ssap < LLCP_LOCAL_NUM_SAP && sock->ssap >= LLCP_WKS_NUM_SAP) { | ||
741 | atomic_t *client_count; | ||
742 | |||
743 | pr_debug("reserved_ssap %d for %p\n", sock->ssap, new_sock); | ||
744 | |||
745 | client_count = | ||
746 | &local->local_sdp_cnt[sock->ssap - LLCP_WKS_NUM_SAP]; | ||
747 | |||
748 | atomic_inc(client_count); | ||
749 | new_sock->reserved_ssap = sock->ssap; | ||
750 | } | ||
681 | 751 | ||
682 | nfc_llcp_parse_connection_tlv(new_sock, &skb->data[LLCP_HEADER_SIZE], | 752 | nfc_llcp_parse_connection_tlv(new_sock, &skb->data[LLCP_HEADER_SIZE], |
683 | skb->len - LLCP_HEADER_SIZE); | 753 | skb->len - LLCP_HEADER_SIZE); |
@@ -886,6 +956,45 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb) | |||
886 | nfc_llcp_sock_put(llcp_sock); | 956 | nfc_llcp_sock_put(llcp_sock); |
887 | } | 957 | } |
888 | 958 | ||
959 | static void nfc_llcp_recv_dm(struct nfc_llcp_local *local, struct sk_buff *skb) | ||
960 | { | ||
961 | struct nfc_llcp_sock *llcp_sock; | ||
962 | struct sock *sk; | ||
963 | u8 dsap, ssap, reason; | ||
964 | |||
965 | dsap = nfc_llcp_dsap(skb); | ||
966 | ssap = nfc_llcp_ssap(skb); | ||
967 | reason = skb->data[2]; | ||
968 | |||
969 | pr_debug("%d %d reason %d\n", ssap, dsap, reason); | ||
970 | |||
971 | switch (reason) { | ||
972 | case LLCP_DM_NOBOUND: | ||
973 | case LLCP_DM_REJ: | ||
974 | llcp_sock = nfc_llcp_connecting_sock_get(local, dsap); | ||
975 | break; | ||
976 | |||
977 | default: | ||
978 | llcp_sock = nfc_llcp_sock_get(local, dsap, ssap); | ||
979 | break; | ||
980 | } | ||
981 | |||
982 | if (llcp_sock == NULL) { | ||
983 | pr_err("Invalid DM\n"); | ||
984 | return; | ||
985 | } | ||
986 | |||
987 | sk = &llcp_sock->sk; | ||
988 | |||
989 | sk->sk_err = ENXIO; | ||
990 | sk->sk_state = LLCP_CLOSED; | ||
991 | sk->sk_state_change(sk); | ||
992 | |||
993 | nfc_llcp_sock_put(llcp_sock); | ||
994 | |||
995 | return; | ||
996 | } | ||
997 | |||
889 | static void nfc_llcp_rx_work(struct work_struct *work) | 998 | static void nfc_llcp_rx_work(struct work_struct *work) |
890 | { | 999 | { |
891 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, | 1000 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, |
@@ -929,6 +1038,11 @@ static void nfc_llcp_rx_work(struct work_struct *work) | |||
929 | nfc_llcp_recv_cc(local, skb); | 1038 | nfc_llcp_recv_cc(local, skb); |
930 | break; | 1039 | break; |
931 | 1040 | ||
1041 | case LLCP_PDU_DM: | ||
1042 | pr_debug("DM\n"); | ||
1043 | nfc_llcp_recv_dm(local, skb); | ||
1044 | break; | ||
1045 | |||
932 | case LLCP_PDU_I: | 1046 | case LLCP_PDU_I: |
933 | case LLCP_PDU_RR: | 1047 | case LLCP_PDU_RR: |
934 | case LLCP_PDU_RNR: | 1048 | case LLCP_PDU_RNR: |
@@ -985,10 +1099,8 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev) | |||
985 | if (local == NULL) | 1099 | if (local == NULL) |
986 | return; | 1100 | return; |
987 | 1101 | ||
988 | nfc_llcp_clear_sdp(local); | ||
989 | |||
990 | /* Close and purge all existing sockets */ | 1102 | /* Close and purge all existing sockets */ |
991 | nfc_llcp_socket_release(local); | 1103 | nfc_llcp_socket_release(local, true); |
992 | } | 1104 | } |
993 | 1105 | ||
994 | void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, | 1106 | void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, |
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 7286c86982ff..83b8bba5a280 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h | |||
@@ -37,6 +37,7 @@ enum llcp_state { | |||
37 | #define LLCP_LOCAL_NUM_SAP 32 | 37 | #define LLCP_LOCAL_NUM_SAP 32 |
38 | #define LLCP_LOCAL_SAP_OFFSET (LLCP_WKS_NUM_SAP + LLCP_SDP_NUM_SAP) | 38 | #define LLCP_LOCAL_SAP_OFFSET (LLCP_WKS_NUM_SAP + LLCP_SDP_NUM_SAP) |
39 | #define LLCP_MAX_SAP (LLCP_WKS_NUM_SAP + LLCP_SDP_NUM_SAP + LLCP_LOCAL_NUM_SAP) | 39 | #define LLCP_MAX_SAP (LLCP_WKS_NUM_SAP + LLCP_SDP_NUM_SAP + LLCP_LOCAL_NUM_SAP) |
40 | #define LLCP_SDP_UNBOUND (LLCP_MAX_SAP + 1) | ||
40 | 41 | ||
41 | struct nfc_llcp_sock; | 42 | struct nfc_llcp_sock; |
42 | 43 | ||
@@ -69,6 +70,7 @@ struct nfc_llcp_local { | |||
69 | unsigned long local_wks; /* Well known services */ | 70 | unsigned long local_wks; /* Well known services */ |
70 | unsigned long local_sdp; /* Local services */ | 71 | unsigned long local_sdp; /* Local services */ |
71 | unsigned long local_sap; /* Local SAPs, not available for discovery */ | 72 | unsigned long local_sap; /* Local SAPs, not available for discovery */ |
73 | atomic_t local_sdp_cnt[LLCP_SDP_NUM_SAP]; | ||
72 | 74 | ||
73 | /* local */ | 75 | /* local */ |
74 | u8 gb[NFC_MAX_GT_LEN]; | 76 | u8 gb[NFC_MAX_GT_LEN]; |
@@ -113,6 +115,9 @@ struct nfc_llcp_sock { | |||
113 | /* Is the remote peer ready to receive */ | 115 | /* Is the remote peer ready to receive */ |
114 | u8 remote_ready; | 116 | u8 remote_ready; |
115 | 117 | ||
118 | /* Reserved source SAP */ | ||
119 | u8 reserved_ssap; | ||
120 | |||
116 | struct sk_buff_head tx_queue; | 121 | struct sk_buff_head tx_queue; |
117 | struct sk_buff_head tx_pending_queue; | 122 | struct sk_buff_head tx_pending_queue; |
118 | struct sk_buff_head tx_backlog_queue; | 123 | struct sk_buff_head tx_backlog_queue; |
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 05ca5a680071..ddeb9aa398f0 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c | |||
@@ -78,11 +78,11 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | |||
78 | struct sockaddr_nfc_llcp llcp_addr; | 78 | struct sockaddr_nfc_llcp llcp_addr; |
79 | int len, ret = 0; | 79 | int len, ret = 0; |
80 | 80 | ||
81 | pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family); | ||
82 | |||
83 | if (!addr || addr->sa_family != AF_NFC) | 81 | if (!addr || addr->sa_family != AF_NFC) |
84 | return -EINVAL; | 82 | return -EINVAL; |
85 | 83 | ||
84 | pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family); | ||
85 | |||
86 | memset(&llcp_addr, 0, sizeof(llcp_addr)); | 86 | memset(&llcp_addr, 0, sizeof(llcp_addr)); |
87 | len = min_t(unsigned int, sizeof(llcp_addr), alen); | 87 | len = min_t(unsigned int, sizeof(llcp_addr), alen); |
88 | memcpy(&llcp_addr, addr, len); | 88 | memcpy(&llcp_addr, addr, len); |
@@ -121,8 +121,12 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | |||
121 | GFP_KERNEL); | 121 | GFP_KERNEL); |
122 | 122 | ||
123 | llcp_sock->ssap = nfc_llcp_get_sdp_ssap(local, llcp_sock); | 123 | llcp_sock->ssap = nfc_llcp_get_sdp_ssap(local, llcp_sock); |
124 | if (llcp_sock->ssap == LLCP_MAX_SAP) | 124 | if (llcp_sock->ssap == LLCP_SAP_MAX) { |
125 | ret = -EADDRINUSE; | ||
125 | goto put_dev; | 126 | goto put_dev; |
127 | } | ||
128 | |||
129 | llcp_sock->reserved_ssap = llcp_sock->ssap; | ||
126 | 130 | ||
127 | nfc_llcp_sock_link(&local->sockets, sk); | 131 | nfc_llcp_sock_link(&local->sockets, sk); |
128 | 132 | ||
@@ -283,22 +287,28 @@ error: | |||
283 | return ret; | 287 | return ret; |
284 | } | 288 | } |
285 | 289 | ||
286 | static int llcp_sock_getname(struct socket *sock, struct sockaddr *addr, | 290 | static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr, |
287 | int *len, int peer) | 291 | int *len, int peer) |
288 | { | 292 | { |
289 | struct sockaddr_nfc_llcp *llcp_addr = (struct sockaddr_nfc_llcp *)addr; | ||
290 | struct sock *sk = sock->sk; | 293 | struct sock *sk = sock->sk; |
291 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | 294 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); |
295 | DECLARE_SOCKADDR(struct sockaddr_nfc_llcp *, llcp_addr, uaddr); | ||
292 | 296 | ||
293 | pr_debug("%p\n", sk); | 297 | if (llcp_sock == NULL || llcp_sock->dev == NULL) |
298 | return -EBADFD; | ||
299 | |||
300 | pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, | ||
301 | llcp_sock->dsap, llcp_sock->ssap); | ||
294 | 302 | ||
295 | if (llcp_sock == NULL || llcp_sock->dev == NULL) | 303 | if (llcp_sock == NULL || llcp_sock->dev == NULL) |
296 | return -EBADFD; | 304 | return -EBADFD; |
297 | 305 | ||
298 | addr->sa_family = AF_NFC; | 306 | uaddr->sa_family = AF_NFC; |
307 | |||
299 | *len = sizeof(struct sockaddr_nfc_llcp); | 308 | *len = sizeof(struct sockaddr_nfc_llcp); |
300 | 309 | ||
301 | llcp_addr->dev_idx = llcp_sock->dev->idx; | 310 | llcp_addr->dev_idx = llcp_sock->dev->idx; |
311 | llcp_addr->target_idx = llcp_sock->target_idx; | ||
302 | llcp_addr->dsap = llcp_sock->dsap; | 312 | llcp_addr->dsap = llcp_sock->dsap; |
303 | llcp_addr->ssap = llcp_sock->ssap; | 313 | llcp_addr->ssap = llcp_sock->ssap; |
304 | llcp_addr->service_name_len = llcp_sock->service_name_len; | 314 | llcp_addr->service_name_len = llcp_sock->service_name_len; |
@@ -406,7 +416,8 @@ static int llcp_sock_release(struct socket *sock) | |||
406 | } | 416 | } |
407 | } | 417 | } |
408 | 418 | ||
409 | nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap); | 419 | if (llcp_sock->reserved_ssap < LLCP_SAP_MAX) |
420 | nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap); | ||
410 | 421 | ||
411 | release_sock(sk); | 422 | release_sock(sk); |
412 | 423 | ||
@@ -486,6 +497,9 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, | |||
486 | ret = -ENOMEM; | 497 | ret = -ENOMEM; |
487 | goto put_dev; | 498 | goto put_dev; |
488 | } | 499 | } |
500 | |||
501 | llcp_sock->reserved_ssap = llcp_sock->ssap; | ||
502 | |||
489 | if (addr->service_name_len == 0) | 503 | if (addr->service_name_len == 0) |
490 | llcp_sock->dsap = addr->dsap; | 504 | llcp_sock->dsap = addr->dsap; |
491 | else | 505 | else |
@@ -687,6 +701,7 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp) | |||
687 | llcp_sock->send_n = llcp_sock->send_ack_n = 0; | 701 | llcp_sock->send_n = llcp_sock->send_ack_n = 0; |
688 | llcp_sock->recv_n = llcp_sock->recv_ack_n = 0; | 702 | llcp_sock->recv_n = llcp_sock->recv_ack_n = 0; |
689 | llcp_sock->remote_ready = 1; | 703 | llcp_sock->remote_ready = 1; |
704 | llcp_sock->reserved_ssap = LLCP_SAP_MAX; | ||
690 | skb_queue_head_init(&llcp_sock->tx_queue); | 705 | skb_queue_head_init(&llcp_sock->tx_queue); |
691 | skb_queue_head_init(&llcp_sock->tx_pending_queue); | 706 | skb_queue_head_init(&llcp_sock->tx_pending_queue); |
692 | skb_queue_head_init(&llcp_sock->tx_backlog_queue); | 707 | skb_queue_head_init(&llcp_sock->tx_backlog_queue); |
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 766a02b1dfa1..5bb4da680427 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c | |||
@@ -194,7 +194,7 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) | |||
194 | } | 194 | } |
195 | 195 | ||
196 | if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && | 196 | if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && |
197 | (protocols & NFC_PROTO_ISO14443_MASK)) { | 197 | (protocols & NFC_PROTO_ISO14443_B_MASK)) { |
198 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = | 198 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = |
199 | NCI_NFC_B_PASSIVE_POLL_MODE; | 199 | NCI_NFC_B_PASSIVE_POLL_MODE; |
200 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; | 200 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; |
@@ -486,7 +486,8 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, | |||
486 | param.rf_protocol = NCI_RF_PROTOCOL_T2T; | 486 | param.rf_protocol = NCI_RF_PROTOCOL_T2T; |
487 | else if (protocol == NFC_PROTO_FELICA) | 487 | else if (protocol == NFC_PROTO_FELICA) |
488 | param.rf_protocol = NCI_RF_PROTOCOL_T3T; | 488 | param.rf_protocol = NCI_RF_PROTOCOL_T3T; |
489 | else if (protocol == NFC_PROTO_ISO14443) | 489 | else if (protocol == NFC_PROTO_ISO14443 || |
490 | protocol == NFC_PROTO_ISO14443_B) | ||
490 | param.rf_protocol = NCI_RF_PROTOCOL_ISO_DEP; | 491 | param.rf_protocol = NCI_RF_PROTOCOL_ISO_DEP; |
491 | else | 492 | else |
492 | param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP; | 493 | param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP; |
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index 2ab196a9f228..af7a93b04393 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c | |||
@@ -170,7 +170,10 @@ static int nci_add_new_protocol(struct nci_dev *ndev, | |||
170 | if (rf_protocol == NCI_RF_PROTOCOL_T2T) | 170 | if (rf_protocol == NCI_RF_PROTOCOL_T2T) |
171 | protocol = NFC_PROTO_MIFARE_MASK; | 171 | protocol = NFC_PROTO_MIFARE_MASK; |
172 | else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) | 172 | else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) |
173 | protocol = NFC_PROTO_ISO14443_MASK; | 173 | if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) |
174 | protocol = NFC_PROTO_ISO14443_MASK; | ||
175 | else | ||
176 | protocol = NFC_PROTO_ISO14443_B_MASK; | ||
174 | else if (rf_protocol == NCI_RF_PROTOCOL_T3T) | 177 | else if (rf_protocol == NCI_RF_PROTOCOL_T3T) |
175 | protocol = NFC_PROTO_FELICA_MASK; | 178 | protocol = NFC_PROTO_FELICA_MASK; |
176 | else | 179 | else |
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index f4f07f9b61c0..4c51714ee741 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c | |||
@@ -634,6 +634,15 @@ static int nfc_genl_stop_poll(struct sk_buff *skb, struct genl_info *info) | |||
634 | if (!dev) | 634 | if (!dev) |
635 | return -ENODEV; | 635 | return -ENODEV; |
636 | 636 | ||
637 | device_lock(&dev->dev); | ||
638 | |||
639 | if (!dev->polling) { | ||
640 | device_unlock(&dev->dev); | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | |||
644 | device_unlock(&dev->dev); | ||
645 | |||
637 | mutex_lock(&dev->genl_data.genl_data_mutex); | 646 | mutex_lock(&dev->genl_data.genl_data_mutex); |
638 | 647 | ||
639 | if (dev->genl_data.poll_req_pid != info->snd_pid) { | 648 | if (dev->genl_data.poll_req_pid != info->snd_pid) { |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 55a28ab21db9..0f7e0d621ab0 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o | |||
10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o | 10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o |
11 | 11 | ||
12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o | 12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o |
13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o | 13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o |
14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | 14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o |
15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o | 15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o |
16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o | 16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o |
diff --git a/net/wireless/ap.c b/net/wireless/ap.c new file mode 100644 index 000000000000..fcc60d8dbefa --- /dev/null +++ b/net/wireless/ap.c | |||
@@ -0,0 +1,46 @@ | |||
1 | #include <linux/ieee80211.h> | ||
2 | #include <linux/export.h> | ||
3 | #include <net/cfg80211.h> | ||
4 | #include "nl80211.h" | ||
5 | #include "core.h" | ||
6 | |||
7 | |||
8 | static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
9 | struct net_device *dev) | ||
10 | { | ||
11 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
12 | int err; | ||
13 | |||
14 | ASSERT_WDEV_LOCK(wdev); | ||
15 | |||
16 | if (!rdev->ops->stop_ap) | ||
17 | return -EOPNOTSUPP; | ||
18 | |||
19 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
20 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
21 | return -EOPNOTSUPP; | ||
22 | |||
23 | if (!wdev->beacon_interval) | ||
24 | return -ENOENT; | ||
25 | |||
26 | err = rdev->ops->stop_ap(&rdev->wiphy, dev); | ||
27 | if (!err) { | ||
28 | wdev->beacon_interval = 0; | ||
29 | wdev->channel = NULL; | ||
30 | } | ||
31 | |||
32 | return err; | ||
33 | } | ||
34 | |||
35 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
36 | struct net_device *dev) | ||
37 | { | ||
38 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
39 | int err; | ||
40 | |||
41 | wdev_lock(wdev); | ||
42 | err = __cfg80211_stop_ap(rdev, dev); | ||
43 | wdev_unlock(wdev); | ||
44 | |||
45 | return err; | ||
46 | } | ||
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index c1999e45a07c..434c56b92c3c 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -82,13 +82,73 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, | |||
82 | int freq, enum nl80211_channel_type chantype) | 82 | int freq, enum nl80211_channel_type chantype) |
83 | { | 83 | { |
84 | struct ieee80211_channel *chan; | 84 | struct ieee80211_channel *chan; |
85 | int err; | ||
85 | 86 | ||
86 | if (!rdev->ops->set_monitor_channel) | 87 | if (!rdev->ops->set_monitor_channel) |
87 | return -EOPNOTSUPP; | 88 | return -EOPNOTSUPP; |
89 | if (!cfg80211_has_monitors_only(rdev)) | ||
90 | return -EBUSY; | ||
88 | 91 | ||
89 | chan = rdev_freq_to_chan(rdev, freq, chantype); | 92 | chan = rdev_freq_to_chan(rdev, freq, chantype); |
90 | if (!chan) | 93 | if (!chan) |
91 | return -EINVAL; | 94 | return -EINVAL; |
92 | 95 | ||
93 | return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); | 96 | err = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); |
97 | if (!err) { | ||
98 | rdev->monitor_channel = chan; | ||
99 | rdev->monitor_channel_type = chantype; | ||
100 | } | ||
101 | |||
102 | return err; | ||
103 | } | ||
104 | |||
105 | void | ||
106 | cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, | ||
107 | struct wireless_dev *wdev, | ||
108 | struct ieee80211_channel **chan, | ||
109 | enum cfg80211_chan_mode *chanmode) | ||
110 | { | ||
111 | *chan = NULL; | ||
112 | *chanmode = CHAN_MODE_UNDEFINED; | ||
113 | |||
114 | ASSERT_RDEV_LOCK(rdev); | ||
115 | ASSERT_WDEV_LOCK(wdev); | ||
116 | |||
117 | if (!netif_running(wdev->netdev)) | ||
118 | return; | ||
119 | |||
120 | switch (wdev->iftype) { | ||
121 | case NL80211_IFTYPE_ADHOC: | ||
122 | if (wdev->current_bss) { | ||
123 | *chan = wdev->current_bss->pub.channel; | ||
124 | *chanmode = wdev->ibss_fixed | ||
125 | ? CHAN_MODE_SHARED | ||
126 | : CHAN_MODE_EXCLUSIVE; | ||
127 | return; | ||
128 | } | ||
129 | case NL80211_IFTYPE_STATION: | ||
130 | case NL80211_IFTYPE_P2P_CLIENT: | ||
131 | if (wdev->current_bss) { | ||
132 | *chan = wdev->current_bss->pub.channel; | ||
133 | *chanmode = CHAN_MODE_SHARED; | ||
134 | return; | ||
135 | } | ||
136 | break; | ||
137 | case NL80211_IFTYPE_AP: | ||
138 | case NL80211_IFTYPE_P2P_GO: | ||
139 | case NL80211_IFTYPE_MESH_POINT: | ||
140 | *chan = wdev->channel; | ||
141 | *chanmode = CHAN_MODE_SHARED; | ||
142 | return; | ||
143 | case NL80211_IFTYPE_MONITOR: | ||
144 | case NL80211_IFTYPE_AP_VLAN: | ||
145 | case NL80211_IFTYPE_WDS: | ||
146 | /* these interface types don't really have a channel */ | ||
147 | return; | ||
148 | case NL80211_IFTYPE_UNSPECIFIED: | ||
149 | case NUM_NL80211_IFTYPES: | ||
150 | WARN_ON(1); | ||
151 | } | ||
152 | |||
153 | return; | ||
94 | } | 154 | } |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 907f62c80e28..eb60410ae588 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -373,6 +373,14 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) | |||
373 | if (WARN_ON(!c->num_different_channels)) | 373 | if (WARN_ON(!c->num_different_channels)) |
374 | return -EINVAL; | 374 | return -EINVAL; |
375 | 375 | ||
376 | /* | ||
377 | * Put a sane limit on maximum number of different | ||
378 | * channels to simplify channel accounting code. | ||
379 | */ | ||
380 | if (WARN_ON(c->num_different_channels > | ||
381 | CFG80211_MAX_NUM_DIFFERENT_CHANNELS)) | ||
382 | return -EINVAL; | ||
383 | |||
376 | if (WARN_ON(!c->n_limits)) | 384 | if (WARN_ON(!c->n_limits)) |
377 | return -EINVAL; | 385 | return -EINVAL; |
378 | 386 | ||
@@ -421,9 +429,11 @@ int wiphy_register(struct wiphy *wiphy) | |||
421 | int i; | 429 | int i; |
422 | u16 ifmodes = wiphy->interface_modes; | 430 | u16 ifmodes = wiphy->interface_modes; |
423 | 431 | ||
432 | #ifdef CONFIG_PM | ||
424 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | 433 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && |
425 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) | 434 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) |
426 | return -EINVAL; | 435 | return -EINVAL; |
436 | #endif | ||
427 | 437 | ||
428 | if (WARN_ON(wiphy->ap_sme_capa && | 438 | if (WARN_ON(wiphy->ap_sme_capa && |
429 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) | 439 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) |
@@ -458,8 +468,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
458 | continue; | 468 | continue; |
459 | 469 | ||
460 | sband->band = band; | 470 | sband->band = band; |
461 | 471 | if (WARN_ON(!sband->n_channels)) | |
462 | if (WARN_ON(!sband->n_channels || !sband->n_bitrates)) | 472 | return -EINVAL; |
473 | /* | ||
474 | * on 60gHz band, there are no legacy rates, so | ||
475 | * n_bitrates is 0 | ||
476 | */ | ||
477 | if (WARN_ON(band != IEEE80211_BAND_60GHZ && | ||
478 | !sband->n_bitrates)) | ||
463 | return -EINVAL; | 479 | return -EINVAL; |
464 | 480 | ||
465 | /* | 481 | /* |
@@ -500,12 +516,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
500 | return -EINVAL; | 516 | return -EINVAL; |
501 | } | 517 | } |
502 | 518 | ||
519 | #ifdef CONFIG_PM | ||
503 | if (rdev->wiphy.wowlan.n_patterns) { | 520 | if (rdev->wiphy.wowlan.n_patterns) { |
504 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || | 521 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || |
505 | rdev->wiphy.wowlan.pattern_min_len > | 522 | rdev->wiphy.wowlan.pattern_min_len > |
506 | rdev->wiphy.wowlan.pattern_max_len)) | 523 | rdev->wiphy.wowlan.pattern_max_len)) |
507 | return -EINVAL; | 524 | return -EINVAL; |
508 | } | 525 | } |
526 | #endif | ||
509 | 527 | ||
510 | /* check and set up bitrates */ | 528 | /* check and set up bitrates */ |
511 | ieee80211_set_bitrate_flags(wiphy); | 529 | ieee80211_set_bitrate_flags(wiphy); |
@@ -713,6 +731,61 @@ static struct device_type wiphy_type = { | |||
713 | .name = "wlan", | 731 | .name = "wlan", |
714 | }; | 732 | }; |
715 | 733 | ||
734 | static struct ieee80211_channel * | ||
735 | cfg80211_get_any_chan(struct cfg80211_registered_device *rdev) | ||
736 | { | ||
737 | struct ieee80211_supported_band *sband; | ||
738 | int i; | ||
739 | |||
740 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
741 | sband = rdev->wiphy.bands[i]; | ||
742 | if (sband && sband->n_channels > 0) | ||
743 | return &sband->channels[0]; | ||
744 | } | ||
745 | |||
746 | return NULL; | ||
747 | } | ||
748 | |||
749 | static void cfg80211_init_mon_chan(struct cfg80211_registered_device *rdev) | ||
750 | { | ||
751 | struct ieee80211_channel *chan; | ||
752 | |||
753 | chan = cfg80211_get_any_chan(rdev); | ||
754 | if (WARN_ON(!chan)) | ||
755 | return; | ||
756 | |||
757 | mutex_lock(&rdev->devlist_mtx); | ||
758 | WARN_ON(cfg80211_set_monitor_channel(rdev, chan->center_freq, | ||
759 | NL80211_CHAN_NO_HT)); | ||
760 | mutex_unlock(&rdev->devlist_mtx); | ||
761 | } | ||
762 | |||
763 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | ||
764 | enum nl80211_iftype iftype, int num) | ||
765 | { | ||
766 | bool has_monitors_only_old = cfg80211_has_monitors_only(rdev); | ||
767 | bool has_monitors_only_new; | ||
768 | |||
769 | ASSERT_RTNL(); | ||
770 | |||
771 | rdev->num_running_ifaces += num; | ||
772 | if (iftype == NL80211_IFTYPE_MONITOR) | ||
773 | rdev->num_running_monitor_ifaces += num; | ||
774 | |||
775 | has_monitors_only_new = cfg80211_has_monitors_only(rdev); | ||
776 | if (has_monitors_only_new != has_monitors_only_old) { | ||
777 | rdev->ops->set_monitor_enabled(&rdev->wiphy, | ||
778 | has_monitors_only_new); | ||
779 | |||
780 | if (!has_monitors_only_new) { | ||
781 | rdev->monitor_channel = NULL; | ||
782 | rdev->monitor_channel_type = NL80211_CHAN_NO_HT; | ||
783 | } else { | ||
784 | cfg80211_init_mon_chan(rdev); | ||
785 | } | ||
786 | } | ||
787 | } | ||
788 | |||
716 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | 789 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, |
717 | unsigned long state, | 790 | unsigned long state, |
718 | void *ndev) | 791 | void *ndev) |
@@ -806,12 +879,16 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
806 | case NL80211_IFTYPE_MESH_POINT: | 879 | case NL80211_IFTYPE_MESH_POINT: |
807 | cfg80211_leave_mesh(rdev, dev); | 880 | cfg80211_leave_mesh(rdev, dev); |
808 | break; | 881 | break; |
882 | case NL80211_IFTYPE_AP: | ||
883 | cfg80211_stop_ap(rdev, dev); | ||
884 | break; | ||
809 | default: | 885 | default: |
810 | break; | 886 | break; |
811 | } | 887 | } |
812 | wdev->beacon_interval = 0; | 888 | wdev->beacon_interval = 0; |
813 | break; | 889 | break; |
814 | case NETDEV_DOWN: | 890 | case NETDEV_DOWN: |
891 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); | ||
815 | dev_hold(dev); | 892 | dev_hold(dev); |
816 | queue_work(cfg80211_wq, &wdev->cleanup_work); | 893 | queue_work(cfg80211_wq, &wdev->cleanup_work); |
817 | break; | 894 | break; |
@@ -917,9 +994,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
917 | return notifier_from_errno(-EOPNOTSUPP); | 994 | return notifier_from_errno(-EOPNOTSUPP); |
918 | if (rfkill_blocked(rdev->rfkill)) | 995 | if (rfkill_blocked(rdev->rfkill)) |
919 | return notifier_from_errno(-ERFKILL); | 996 | return notifier_from_errno(-ERFKILL); |
997 | mutex_lock(&rdev->devlist_mtx); | ||
920 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); | 998 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); |
999 | mutex_unlock(&rdev->devlist_mtx); | ||
921 | if (ret) | 1000 | if (ret) |
922 | return notifier_from_errno(ret); | 1001 | return notifier_from_errno(ret); |
1002 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); | ||
923 | break; | 1003 | break; |
924 | } | 1004 | } |
925 | 1005 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index 609a579255ac..377dc394f48c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/debugfs.h> | 13 | #include <linux/debugfs.h> |
14 | #include <linux/rfkill.h> | 14 | #include <linux/rfkill.h> |
15 | #include <linux/workqueue.h> | 15 | #include <linux/workqueue.h> |
16 | #include <linux/rtnetlink.h> | ||
16 | #include <net/genetlink.h> | 17 | #include <net/genetlink.h> |
17 | #include <net/cfg80211.h> | 18 | #include <net/cfg80211.h> |
18 | #include "reg.h" | 19 | #include "reg.h" |
@@ -56,6 +57,13 @@ struct cfg80211_registered_device { | |||
56 | 57 | ||
57 | u32 ap_beacons_nlpid; | 58 | u32 ap_beacons_nlpid; |
58 | 59 | ||
60 | /* protected by RTNL only */ | ||
61 | int num_running_ifaces; | ||
62 | int num_running_monitor_ifaces; | ||
63 | |||
64 | struct ieee80211_channel *monitor_channel; | ||
65 | enum nl80211_channel_type monitor_channel_type; | ||
66 | |||
59 | /* BSSes/scanning */ | 67 | /* BSSes/scanning */ |
60 | spinlock_t bss_lock; | 68 | spinlock_t bss_lock; |
61 | struct list_head bss_list; | 69 | struct list_head bss_list; |
@@ -197,6 +205,14 @@ static inline void wdev_unlock(struct wireless_dev *wdev) | |||
197 | #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) | 205 | #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) |
198 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) | 206 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) |
199 | 207 | ||
208 | static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev) | ||
209 | { | ||
210 | ASSERT_RTNL(); | ||
211 | |||
212 | return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces && | ||
213 | rdev->num_running_ifaces > 0; | ||
214 | } | ||
215 | |||
200 | enum cfg80211_event_type { | 216 | enum cfg80211_event_type { |
201 | EVENT_CONNECT_RESULT, | 217 | EVENT_CONNECT_RESULT, |
202 | EVENT_ROAMED, | 218 | EVENT_ROAMED, |
@@ -241,6 +257,12 @@ struct cfg80211_cached_keys { | |||
241 | int def, defmgmt; | 257 | int def, defmgmt; |
242 | }; | 258 | }; |
243 | 259 | ||
260 | enum cfg80211_chan_mode { | ||
261 | CHAN_MODE_UNDEFINED, | ||
262 | CHAN_MODE_SHARED, | ||
263 | CHAN_MODE_EXCLUSIVE, | ||
264 | }; | ||
265 | |||
244 | 266 | ||
245 | /* free object */ | 267 | /* free object */ |
246 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); | 268 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); |
@@ -289,6 +311,10 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
289 | struct wireless_dev *wdev, int freq, | 311 | struct wireless_dev *wdev, int freq, |
290 | enum nl80211_channel_type channel_type); | 312 | enum nl80211_channel_type channel_type); |
291 | 313 | ||
314 | /* AP */ | ||
315 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
316 | struct net_device *dev); | ||
317 | |||
292 | /* MLME */ | 318 | /* MLME */ |
293 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 319 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
294 | struct net_device *dev, | 320 | struct net_device *dev, |
@@ -404,9 +430,20 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
404 | u32 *flags, struct vif_params *params); | 430 | u32 *flags, struct vif_params *params); |
405 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); | 431 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); |
406 | 432 | ||
407 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | 433 | int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, |
408 | struct wireless_dev *wdev, | 434 | struct wireless_dev *wdev, |
409 | enum nl80211_iftype iftype); | 435 | enum nl80211_iftype iftype, |
436 | struct ieee80211_channel *chan, | ||
437 | enum cfg80211_chan_mode chanmode); | ||
438 | |||
439 | static inline int | ||
440 | cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | ||
441 | struct wireless_dev *wdev, | ||
442 | enum nl80211_iftype iftype) | ||
443 | { | ||
444 | return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL, | ||
445 | CHAN_MODE_UNDEFINED); | ||
446 | } | ||
410 | 447 | ||
411 | static inline int | 448 | static inline int |
412 | cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, | 449 | cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, |
@@ -415,6 +452,22 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, | |||
415 | return cfg80211_can_change_interface(rdev, NULL, iftype); | 452 | return cfg80211_can_change_interface(rdev, NULL, iftype); |
416 | } | 453 | } |
417 | 454 | ||
455 | static inline int | ||
456 | cfg80211_can_use_chan(struct cfg80211_registered_device *rdev, | ||
457 | struct wireless_dev *wdev, | ||
458 | struct ieee80211_channel *chan, | ||
459 | enum cfg80211_chan_mode chanmode) | ||
460 | { | ||
461 | return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | ||
462 | chan, chanmode); | ||
463 | } | ||
464 | |||
465 | void | ||
466 | cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, | ||
467 | struct wireless_dev *wdev, | ||
468 | struct ieee80211_channel **chan, | ||
469 | enum cfg80211_chan_mode *chanmode); | ||
470 | |||
418 | struct ieee80211_channel * | 471 | struct ieee80211_channel * |
419 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | 472 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, |
420 | int freq, enum nl80211_channel_type channel_type); | 473 | int freq, enum nl80211_channel_type channel_type); |
@@ -428,6 +481,11 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | |||
428 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 481 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
429 | u32 beacon_int); | 482 | u32 beacon_int); |
430 | 483 | ||
484 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | ||
485 | enum nl80211_iftype iftype, int num); | ||
486 | |||
487 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 | ||
488 | |||
431 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS | 489 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS |
432 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) | 490 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) |
433 | #else | 491 | #else |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 89baa3328411..ca5672f6ee2f 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -113,10 +113,21 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
113 | kfree(wdev->connect_keys); | 113 | kfree(wdev->connect_keys); |
114 | wdev->connect_keys = connkeys; | 114 | wdev->connect_keys = connkeys; |
115 | 115 | ||
116 | wdev->ibss_fixed = params->channel_fixed; | ||
116 | #ifdef CONFIG_CFG80211_WEXT | 117 | #ifdef CONFIG_CFG80211_WEXT |
117 | wdev->wext.ibss.channel = params->channel; | 118 | wdev->wext.ibss.channel = params->channel; |
118 | #endif | 119 | #endif |
119 | wdev->sme_state = CFG80211_SME_CONNECTING; | 120 | wdev->sme_state = CFG80211_SME_CONNECTING; |
121 | |||
122 | err = cfg80211_can_use_chan(rdev, wdev, params->channel, | ||
123 | params->channel_fixed | ||
124 | ? CHAN_MODE_SHARED | ||
125 | : CHAN_MODE_EXCLUSIVE); | ||
126 | if (err) { | ||
127 | wdev->connect_keys = NULL; | ||
128 | return err; | ||
129 | } | ||
130 | |||
120 | err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); | 131 | err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); |
121 | if (err) { | 132 | if (err) { |
122 | wdev->connect_keys = NULL; | 133 | wdev->connect_keys = NULL; |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 3b73b07486cf..c384e77ff77a 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -155,10 +155,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
155 | setup->channel_type)) | 155 | setup->channel_type)) |
156 | return -EINVAL; | 156 | return -EINVAL; |
157 | 157 | ||
158 | err = cfg80211_can_use_chan(rdev, wdev, setup->channel, | ||
159 | CHAN_MODE_SHARED); | ||
160 | if (err) | ||
161 | return err; | ||
162 | |||
158 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); | 163 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); |
159 | if (!err) { | 164 | if (!err) { |
160 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); | 165 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); |
161 | wdev->mesh_id_len = setup->mesh_id_len; | 166 | wdev->mesh_id_len = setup->mesh_id_len; |
167 | wdev->channel = setup->channel; | ||
162 | } | 168 | } |
163 | 169 | ||
164 | return err; | 170 | return err; |
@@ -172,9 +178,11 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
172 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 178 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
173 | int err; | 179 | int err; |
174 | 180 | ||
181 | mutex_lock(&rdev->devlist_mtx); | ||
175 | wdev_lock(wdev); | 182 | wdev_lock(wdev); |
176 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); | 183 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); |
177 | wdev_unlock(wdev); | 184 | wdev_unlock(wdev); |
185 | mutex_unlock(&rdev->devlist_mtx); | ||
178 | 186 | ||
179 | return err; | 187 | return err; |
180 | } | 188 | } |
@@ -184,6 +192,7 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
184 | enum nl80211_channel_type channel_type) | 192 | enum nl80211_channel_type channel_type) |
185 | { | 193 | { |
186 | struct ieee80211_channel *channel; | 194 | struct ieee80211_channel *channel; |
195 | int err; | ||
187 | 196 | ||
188 | channel = rdev_freq_to_chan(rdev, freq, channel_type); | 197 | channel = rdev_freq_to_chan(rdev, freq, channel_type); |
189 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, | 198 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, |
@@ -205,9 +214,19 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
205 | 214 | ||
206 | if (!netif_running(wdev->netdev)) | 215 | if (!netif_running(wdev->netdev)) |
207 | return -ENETDOWN; | 216 | return -ENETDOWN; |
208 | return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, | 217 | |
209 | wdev->netdev, | 218 | err = cfg80211_can_use_chan(rdev, wdev, channel, |
210 | channel); | 219 | CHAN_MODE_SHARED); |
220 | if (err) | ||
221 | return err; | ||
222 | |||
223 | err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, | ||
224 | wdev->netdev, | ||
225 | channel); | ||
226 | if (!err) | ||
227 | wdev->channel = channel; | ||
228 | |||
229 | return err; | ||
211 | } | 230 | } |
212 | 231 | ||
213 | if (wdev->mesh_id_len) | 232 | if (wdev->mesh_id_len) |
@@ -249,8 +268,11 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | |||
249 | return -ENOTCONN; | 268 | return -ENOTCONN; |
250 | 269 | ||
251 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); | 270 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); |
252 | if (!err) | 271 | if (!err) { |
253 | wdev->mesh_id_len = 0; | 272 | wdev->mesh_id_len = 0; |
273 | wdev->channel = NULL; | ||
274 | } | ||
275 | |||
254 | return err; | 276 | return err; |
255 | } | 277 | } |
256 | 278 | ||
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index da4406f11929..d4fece3bb18a 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -302,8 +302,14 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
302 | if (!req.bss) | 302 | if (!req.bss) |
303 | return -ENOENT; | 303 | return -ENOENT; |
304 | 304 | ||
305 | err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, | ||
306 | CHAN_MODE_SHARED); | ||
307 | if (err) | ||
308 | goto out; | ||
309 | |||
305 | err = rdev->ops->auth(&rdev->wiphy, dev, &req); | 310 | err = rdev->ops->auth(&rdev->wiphy, dev, &req); |
306 | 311 | ||
312 | out: | ||
307 | cfg80211_put_bss(req.bss); | 313 | cfg80211_put_bss(req.bss); |
308 | return err; | 314 | return err; |
309 | } | 315 | } |
@@ -317,11 +323,13 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
317 | { | 323 | { |
318 | int err; | 324 | int err; |
319 | 325 | ||
326 | mutex_lock(&rdev->devlist_mtx); | ||
320 | wdev_lock(dev->ieee80211_ptr); | 327 | wdev_lock(dev->ieee80211_ptr); |
321 | err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, | 328 | err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, |
322 | ssid, ssid_len, ie, ie_len, | 329 | ssid, ssid_len, ie, ie_len, |
323 | key, key_len, key_idx); | 330 | key, key_len, key_idx); |
324 | wdev_unlock(dev->ieee80211_ptr); | 331 | wdev_unlock(dev->ieee80211_ptr); |
332 | mutex_unlock(&rdev->devlist_mtx); | ||
325 | 333 | ||
326 | return err; | 334 | return err; |
327 | } | 335 | } |
@@ -397,8 +405,14 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
397 | return -ENOENT; | 405 | return -ENOENT; |
398 | } | 406 | } |
399 | 407 | ||
408 | err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, | ||
409 | CHAN_MODE_SHARED); | ||
410 | if (err) | ||
411 | goto out; | ||
412 | |||
400 | err = rdev->ops->assoc(&rdev->wiphy, dev, &req); | 413 | err = rdev->ops->assoc(&rdev->wiphy, dev, &req); |
401 | 414 | ||
415 | out: | ||
402 | if (err) { | 416 | if (err) { |
403 | if (was_connected) | 417 | if (was_connected) |
404 | wdev->sme_state = CFG80211_SME_CONNECTED; | 418 | wdev->sme_state = CFG80211_SME_CONNECTED; |
@@ -421,11 +435,13 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
421 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 435 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
422 | int err; | 436 | int err; |
423 | 437 | ||
438 | mutex_lock(&rdev->devlist_mtx); | ||
424 | wdev_lock(wdev); | 439 | wdev_lock(wdev); |
425 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 440 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
426 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, | 441 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, |
427 | assoc_flags, ht_capa, ht_capa_mask); | 442 | assoc_flags, ht_capa, ht_capa_mask); |
428 | wdev_unlock(wdev); | 443 | wdev_unlock(wdev); |
444 | mutex_unlock(&rdev->devlist_mtx); | ||
429 | 445 | ||
430 | return err; | 446 | return err; |
431 | } | 447 | } |
@@ -947,6 +963,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, | |||
947 | if (WARN_ON(!chan)) | 963 | if (WARN_ON(!chan)) |
948 | goto out; | 964 | goto out; |
949 | 965 | ||
966 | wdev->channel = chan; | ||
950 | nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); | 967 | nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); |
951 | out: | 968 | out: |
952 | wdev_unlock(wdev); | 969 | wdev_unlock(wdev); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3b508eaf2d07..0249cea53852 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -921,6 +921,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
921 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) | 921 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) |
922 | goto nla_put_failure; | 922 | goto nla_put_failure; |
923 | 923 | ||
924 | /* add VHT info */ | ||
925 | if (dev->wiphy.bands[band]->vht_cap.vht_supported && | ||
926 | (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, | ||
927 | sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs), | ||
928 | &dev->wiphy.bands[band]->vht_cap.vht_mcs) || | ||
929 | nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, | ||
930 | dev->wiphy.bands[band]->vht_cap.cap))) | ||
931 | goto nla_put_failure; | ||
932 | |||
924 | /* add frequencies */ | 933 | /* add frequencies */ |
925 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); | 934 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); |
926 | if (!nl_freqs) | 935 | if (!nl_freqs) |
@@ -1112,6 +1121,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1112 | nla_nest_end(msg, nl_ifs); | 1121 | nla_nest_end(msg, nl_ifs); |
1113 | } | 1122 | } |
1114 | 1123 | ||
1124 | #ifdef CONFIG_PM | ||
1115 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { | 1125 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { |
1116 | struct nlattr *nl_wowlan; | 1126 | struct nlattr *nl_wowlan; |
1117 | 1127 | ||
@@ -1152,6 +1162,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1152 | 1162 | ||
1153 | nla_nest_end(msg, nl_wowlan); | 1163 | nla_nest_end(msg, nl_wowlan); |
1154 | } | 1164 | } |
1165 | #endif | ||
1155 | 1166 | ||
1156 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 1167 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, |
1157 | dev->wiphy.software_iftypes)) | 1168 | dev->wiphy.software_iftypes)) |
@@ -1678,16 +1689,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1678 | (cfg80211_rdev_list_generation << 2))) | 1689 | (cfg80211_rdev_list_generation << 2))) |
1679 | goto nla_put_failure; | 1690 | goto nla_put_failure; |
1680 | 1691 | ||
1681 | if (rdev->ops->get_channel) { | 1692 | if (rdev->monitor_channel) { |
1682 | struct ieee80211_channel *chan; | 1693 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, |
1683 | enum nl80211_channel_type channel_type; | 1694 | rdev->monitor_channel->center_freq) || |
1684 | 1695 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | |
1685 | chan = rdev->ops->get_channel(&rdev->wiphy, &channel_type); | 1696 | rdev->monitor_channel_type)) |
1686 | if (chan && | ||
1687 | (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | ||
1688 | chan->center_freq) || | ||
1689 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | ||
1690 | channel_type))) | ||
1691 | goto nla_put_failure; | 1697 | goto nla_put_failure; |
1692 | } | 1698 | } |
1693 | 1699 | ||
@@ -2472,11 +2478,20 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2472 | params.channel_type)) | 2478 | params.channel_type)) |
2473 | return -EINVAL; | 2479 | return -EINVAL; |
2474 | 2480 | ||
2481 | mutex_lock(&rdev->devlist_mtx); | ||
2482 | err = cfg80211_can_use_chan(rdev, wdev, params.channel, | ||
2483 | CHAN_MODE_SHARED); | ||
2484 | mutex_unlock(&rdev->devlist_mtx); | ||
2485 | |||
2486 | if (err) | ||
2487 | return err; | ||
2488 | |||
2475 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); | 2489 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); |
2476 | if (!err) { | 2490 | if (!err) { |
2477 | wdev->preset_chan = params.channel; | 2491 | wdev->preset_chan = params.channel; |
2478 | wdev->preset_chantype = params.channel_type; | 2492 | wdev->preset_chantype = params.channel_type; |
2479 | wdev->beacon_interval = params.beacon_interval; | 2493 | wdev->beacon_interval = params.beacon_interval; |
2494 | wdev->channel = params.channel; | ||
2480 | } | 2495 | } |
2481 | return err; | 2496 | return err; |
2482 | } | 2497 | } |
@@ -2510,23 +2525,8 @@ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) | |||
2510 | { | 2525 | { |
2511 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2526 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2512 | struct net_device *dev = info->user_ptr[1]; | 2527 | struct net_device *dev = info->user_ptr[1]; |
2513 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2514 | int err; | ||
2515 | 2528 | ||
2516 | if (!rdev->ops->stop_ap) | 2529 | return cfg80211_stop_ap(rdev, dev); |
2517 | return -EOPNOTSUPP; | ||
2518 | |||
2519 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
2520 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
2521 | return -EOPNOTSUPP; | ||
2522 | |||
2523 | if (!wdev->beacon_interval) | ||
2524 | return -ENOENT; | ||
2525 | |||
2526 | err = rdev->ops->stop_ap(&rdev->wiphy, dev); | ||
2527 | if (!err) | ||
2528 | wdev->beacon_interval = 0; | ||
2529 | return err; | ||
2530 | } | 2530 | } |
2531 | 2531 | ||
2532 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 2532 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
@@ -2618,7 +2618,8 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2618 | int attr) | 2618 | int attr) |
2619 | { | 2619 | { |
2620 | struct nlattr *rate; | 2620 | struct nlattr *rate; |
2621 | u16 bitrate; | 2621 | u32 bitrate; |
2622 | u16 bitrate_compat; | ||
2622 | 2623 | ||
2623 | rate = nla_nest_start(msg, attr); | 2624 | rate = nla_nest_start(msg, attr); |
2624 | if (!rate) | 2625 | if (!rate) |
@@ -2626,8 +2627,12 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2626 | 2627 | ||
2627 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ | 2628 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ |
2628 | bitrate = cfg80211_calculate_bitrate(info); | 2629 | bitrate = cfg80211_calculate_bitrate(info); |
2630 | /* report 16-bit bitrate only if we can */ | ||
2631 | bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; | ||
2629 | if ((bitrate > 0 && | 2632 | if ((bitrate > 0 && |
2630 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate)) || | 2633 | nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) || |
2634 | (bitrate_compat > 0 && | ||
2635 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) || | ||
2631 | ((info->flags & RATE_INFO_FLAGS_MCS) && | 2636 | ((info->flags & RATE_INFO_FLAGS_MCS) && |
2632 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || | 2637 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || |
2633 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && | 2638 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && |
@@ -6276,6 +6281,7 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | |||
6276 | return cfg80211_leave_mesh(rdev, dev); | 6281 | return cfg80211_leave_mesh(rdev, dev); |
6277 | } | 6282 | } |
6278 | 6283 | ||
6284 | #ifdef CONFIG_PM | ||
6279 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 6285 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
6280 | { | 6286 | { |
6281 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6287 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -6504,6 +6510,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6504 | kfree(new_triggers.patterns); | 6510 | kfree(new_triggers.patterns); |
6505 | return err; | 6511 | return err; |
6506 | } | 6512 | } |
6513 | #endif | ||
6507 | 6514 | ||
6508 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) | 6515 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) |
6509 | { | 6516 | { |
@@ -7158,6 +7165,7 @@ static struct genl_ops nl80211_ops[] = { | |||
7158 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7165 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
7159 | NL80211_FLAG_NEED_RTNL, | 7166 | NL80211_FLAG_NEED_RTNL, |
7160 | }, | 7167 | }, |
7168 | #ifdef CONFIG_PM | ||
7161 | { | 7169 | { |
7162 | .cmd = NL80211_CMD_GET_WOWLAN, | 7170 | .cmd = NL80211_CMD_GET_WOWLAN, |
7163 | .doit = nl80211_get_wowlan, | 7171 | .doit = nl80211_get_wowlan, |
@@ -7174,6 +7182,7 @@ static struct genl_ops nl80211_ops[] = { | |||
7174 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 7182 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
7175 | NL80211_FLAG_NEED_RTNL, | 7183 | NL80211_FLAG_NEED_RTNL, |
7176 | }, | 7184 | }, |
7185 | #endif | ||
7177 | { | 7186 | { |
7178 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, | 7187 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, |
7179 | .doit = nl80211_set_rekey_data, | 7188 | .doit = nl80211_set_rekey_data, |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index baf5704740ee..b2b32229b607 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -129,7 +129,7 @@ static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); | |||
129 | 129 | ||
130 | /* We keep a static world regulatory domain in case of the absence of CRDA */ | 130 | /* We keep a static world regulatory domain in case of the absence of CRDA */ |
131 | static const struct ieee80211_regdomain world_regdom = { | 131 | static const struct ieee80211_regdomain world_regdom = { |
132 | .n_reg_rules = 5, | 132 | .n_reg_rules = 6, |
133 | .alpha2 = "00", | 133 | .alpha2 = "00", |
134 | .reg_rules = { | 134 | .reg_rules = { |
135 | /* IEEE 802.11b/g, channels 1..11 */ | 135 | /* IEEE 802.11b/g, channels 1..11 */ |
@@ -156,6 +156,9 @@ static const struct ieee80211_regdomain world_regdom = { | |||
156 | REG_RULE(5745-10, 5825+10, 40, 6, 20, | 156 | REG_RULE(5745-10, 5825+10, 40, 6, 20, |
157 | NL80211_RRF_PASSIVE_SCAN | | 157 | NL80211_RRF_PASSIVE_SCAN | |
158 | NL80211_RRF_NO_IBSS), | 158 | NL80211_RRF_NO_IBSS), |
159 | |||
160 | /* IEEE 802.11ad (60gHz), channels 1..3 */ | ||
161 | REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), | ||
159 | } | 162 | } |
160 | }; | 163 | }; |
161 | 164 | ||
diff --git a/net/wireless/util.c b/net/wireless/util.c index 316cfd00914f..e31f1dba79ec 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -35,19 +35,29 @@ int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band) | |||
35 | { | 35 | { |
36 | /* see 802.11 17.3.8.3.2 and Annex J | 36 | /* see 802.11 17.3.8.3.2 and Annex J |
37 | * there are overlapping channel numbers in 5GHz and 2GHz bands */ | 37 | * there are overlapping channel numbers in 5GHz and 2GHz bands */ |
38 | if (band == IEEE80211_BAND_5GHZ) { | 38 | if (chan <= 0) |
39 | if (chan >= 182 && chan <= 196) | 39 | return 0; /* not supported */ |
40 | return 4000 + chan * 5; | 40 | switch (band) { |
41 | else | 41 | case IEEE80211_BAND_2GHZ: |
42 | return 5000 + chan * 5; | ||
43 | } else { /* IEEE80211_BAND_2GHZ */ | ||
44 | if (chan == 14) | 42 | if (chan == 14) |
45 | return 2484; | 43 | return 2484; |
46 | else if (chan < 14) | 44 | else if (chan < 14) |
47 | return 2407 + chan * 5; | 45 | return 2407 + chan * 5; |
46 | break; | ||
47 | case IEEE80211_BAND_5GHZ: | ||
48 | if (chan >= 182 && chan <= 196) | ||
49 | return 4000 + chan * 5; | ||
48 | else | 50 | else |
49 | return 0; /* not supported */ | 51 | return 5000 + chan * 5; |
52 | break; | ||
53 | case IEEE80211_BAND_60GHZ: | ||
54 | if (chan < 5) | ||
55 | return 56160 + chan * 2160; | ||
56 | break; | ||
57 | default: | ||
58 | ; | ||
50 | } | 59 | } |
60 | return 0; /* not supported */ | ||
51 | } | 61 | } |
52 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); | 62 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); |
53 | 63 | ||
@@ -60,8 +70,12 @@ int ieee80211_frequency_to_channel(int freq) | |||
60 | return (freq - 2407) / 5; | 70 | return (freq - 2407) / 5; |
61 | else if (freq >= 4910 && freq <= 4980) | 71 | else if (freq >= 4910 && freq <= 4980) |
62 | return (freq - 4000) / 5; | 72 | return (freq - 4000) / 5; |
63 | else | 73 | else if (freq <= 45000) /* DMG band lower limit */ |
64 | return (freq - 5000) / 5; | 74 | return (freq - 5000) / 5; |
75 | else if (freq >= 58320 && freq <= 64800) | ||
76 | return (freq - 56160) / 2160; | ||
77 | else | ||
78 | return 0; | ||
65 | } | 79 | } |
66 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); | 80 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); |
67 | 81 | ||
@@ -137,6 +151,11 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, | |||
137 | } | 151 | } |
138 | WARN_ON(want != 0 && want != 3 && want != 6); | 152 | WARN_ON(want != 0 && want != 3 && want != 6); |
139 | break; | 153 | break; |
154 | case IEEE80211_BAND_60GHZ: | ||
155 | /* check for mandatory HT MCS 1..4 */ | ||
156 | WARN_ON(!sband->ht_cap.ht_supported); | ||
157 | WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e); | ||
158 | break; | ||
140 | case IEEE80211_NUM_BANDS: | 159 | case IEEE80211_NUM_BANDS: |
141 | WARN_ON(1); | 160 | WARN_ON(1); |
142 | break; | 161 | break; |
@@ -805,8 +824,10 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
805 | return -EBUSY; | 824 | return -EBUSY; |
806 | 825 | ||
807 | if (ntype != otype && netif_running(dev)) { | 826 | if (ntype != otype && netif_running(dev)) { |
827 | mutex_lock(&rdev->devlist_mtx); | ||
808 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, | 828 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, |
809 | ntype); | 829 | ntype); |
830 | mutex_unlock(&rdev->devlist_mtx); | ||
810 | if (err) | 831 | if (err) |
811 | return err; | 832 | return err; |
812 | 833 | ||
@@ -814,6 +835,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
814 | dev->ieee80211_ptr->mesh_id_up_len = 0; | 835 | dev->ieee80211_ptr->mesh_id_up_len = 0; |
815 | 836 | ||
816 | switch (otype) { | 837 | switch (otype) { |
838 | case NL80211_IFTYPE_AP: | ||
839 | cfg80211_stop_ap(rdev, dev); | ||
840 | break; | ||
817 | case NL80211_IFTYPE_ADHOC: | 841 | case NL80211_IFTYPE_ADHOC: |
818 | cfg80211_leave_ibss(rdev, dev, false); | 842 | cfg80211_leave_ibss(rdev, dev, false); |
819 | break; | 843 | break; |
@@ -868,15 +892,69 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
868 | } | 892 | } |
869 | } | 893 | } |
870 | 894 | ||
895 | if (!err && ntype != otype && netif_running(dev)) { | ||
896 | cfg80211_update_iface_num(rdev, ntype, 1); | ||
897 | cfg80211_update_iface_num(rdev, otype, -1); | ||
898 | } | ||
899 | |||
871 | return err; | 900 | return err; |
872 | } | 901 | } |
873 | 902 | ||
874 | u16 cfg80211_calculate_bitrate(struct rate_info *rate) | 903 | static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) |
904 | { | ||
905 | static const u32 __mcs2bitrate[] = { | ||
906 | /* control PHY */ | ||
907 | [0] = 275, | ||
908 | /* SC PHY */ | ||
909 | [1] = 3850, | ||
910 | [2] = 7700, | ||
911 | [3] = 9625, | ||
912 | [4] = 11550, | ||
913 | [5] = 12512, /* 1251.25 mbps */ | ||
914 | [6] = 15400, | ||
915 | [7] = 19250, | ||
916 | [8] = 23100, | ||
917 | [9] = 25025, | ||
918 | [10] = 30800, | ||
919 | [11] = 38500, | ||
920 | [12] = 46200, | ||
921 | /* OFDM PHY */ | ||
922 | [13] = 6930, | ||
923 | [14] = 8662, /* 866.25 mbps */ | ||
924 | [15] = 13860, | ||
925 | [16] = 17325, | ||
926 | [17] = 20790, | ||
927 | [18] = 27720, | ||
928 | [19] = 34650, | ||
929 | [20] = 41580, | ||
930 | [21] = 45045, | ||
931 | [22] = 51975, | ||
932 | [23] = 62370, | ||
933 | [24] = 67568, /* 6756.75 mbps */ | ||
934 | /* LP-SC PHY */ | ||
935 | [25] = 6260, | ||
936 | [26] = 8340, | ||
937 | [27] = 11120, | ||
938 | [28] = 12510, | ||
939 | [29] = 16680, | ||
940 | [30] = 22240, | ||
941 | [31] = 25030, | ||
942 | }; | ||
943 | |||
944 | if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate))) | ||
945 | return 0; | ||
946 | |||
947 | return __mcs2bitrate[rate->mcs]; | ||
948 | } | ||
949 | |||
950 | u32 cfg80211_calculate_bitrate(struct rate_info *rate) | ||
875 | { | 951 | { |
876 | int modulation, streams, bitrate; | 952 | int modulation, streams, bitrate; |
877 | 953 | ||
878 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) | 954 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) |
879 | return rate->legacy; | 955 | return rate->legacy; |
956 | if (rate->flags & RATE_INFO_FLAGS_60G) | ||
957 | return cfg80211_calculate_bitrate_60g(rate); | ||
880 | 958 | ||
881 | /* the formula below does only work for MCS values smaller than 32 */ | 959 | /* the formula below does only work for MCS values smaller than 32 */ |
882 | if (WARN_ON_ONCE(rate->mcs >= 32)) | 960 | if (WARN_ON_ONCE(rate->mcs >= 32)) |
@@ -930,27 +1008,48 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
930 | return res; | 1008 | return res; |
931 | } | 1009 | } |
932 | 1010 | ||
933 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | 1011 | int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, |
934 | struct wireless_dev *wdev, | 1012 | struct wireless_dev *wdev, |
935 | enum nl80211_iftype iftype) | 1013 | enum nl80211_iftype iftype, |
1014 | struct ieee80211_channel *chan, | ||
1015 | enum cfg80211_chan_mode chanmode) | ||
936 | { | 1016 | { |
937 | struct wireless_dev *wdev_iter; | 1017 | struct wireless_dev *wdev_iter; |
938 | u32 used_iftypes = BIT(iftype); | 1018 | u32 used_iftypes = BIT(iftype); |
939 | int num[NUM_NL80211_IFTYPES]; | 1019 | int num[NUM_NL80211_IFTYPES]; |
1020 | struct ieee80211_channel | ||
1021 | *used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS]; | ||
1022 | struct ieee80211_channel *ch; | ||
1023 | enum cfg80211_chan_mode chmode; | ||
1024 | int num_different_channels = 0; | ||
940 | int total = 1; | 1025 | int total = 1; |
941 | int i, j; | 1026 | int i, j; |
942 | 1027 | ||
943 | ASSERT_RTNL(); | 1028 | ASSERT_RTNL(); |
1029 | lockdep_assert_held(&rdev->devlist_mtx); | ||
944 | 1030 | ||
945 | /* Always allow software iftypes */ | 1031 | /* Always allow software iftypes */ |
946 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | 1032 | if (rdev->wiphy.software_iftypes & BIT(iftype)) |
947 | return 0; | 1033 | return 0; |
948 | 1034 | ||
949 | memset(num, 0, sizeof(num)); | 1035 | memset(num, 0, sizeof(num)); |
1036 | memset(used_channels, 0, sizeof(used_channels)); | ||
950 | 1037 | ||
951 | num[iftype] = 1; | 1038 | num[iftype] = 1; |
952 | 1039 | ||
953 | mutex_lock(&rdev->devlist_mtx); | 1040 | switch (chanmode) { |
1041 | case CHAN_MODE_UNDEFINED: | ||
1042 | break; | ||
1043 | case CHAN_MODE_SHARED: | ||
1044 | WARN_ON(!chan); | ||
1045 | used_channels[0] = chan; | ||
1046 | num_different_channels++; | ||
1047 | break; | ||
1048 | case CHAN_MODE_EXCLUSIVE: | ||
1049 | num_different_channels++; | ||
1050 | break; | ||
1051 | } | ||
1052 | |||
954 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { | 1053 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { |
955 | if (wdev_iter == wdev) | 1054 | if (wdev_iter == wdev) |
956 | continue; | 1055 | continue; |
@@ -960,11 +1059,33 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
960 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) | 1059 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) |
961 | continue; | 1060 | continue; |
962 | 1061 | ||
1062 | cfg80211_get_chan_state(rdev, wdev_iter, &ch, &chmode); | ||
1063 | |||
1064 | switch (chmode) { | ||
1065 | case CHAN_MODE_UNDEFINED: | ||
1066 | break; | ||
1067 | case CHAN_MODE_SHARED: | ||
1068 | for (i = 0; i < CFG80211_MAX_NUM_DIFFERENT_CHANNELS; i++) | ||
1069 | if (!used_channels[i] || used_channels[i] == ch) | ||
1070 | break; | ||
1071 | |||
1072 | if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS) | ||
1073 | return -EBUSY; | ||
1074 | |||
1075 | if (used_channels[i] == NULL) { | ||
1076 | used_channels[i] = ch; | ||
1077 | num_different_channels++; | ||
1078 | } | ||
1079 | break; | ||
1080 | case CHAN_MODE_EXCLUSIVE: | ||
1081 | num_different_channels++; | ||
1082 | break; | ||
1083 | } | ||
1084 | |||
963 | num[wdev_iter->iftype]++; | 1085 | num[wdev_iter->iftype]++; |
964 | total++; | 1086 | total++; |
965 | used_iftypes |= BIT(wdev_iter->iftype); | 1087 | used_iftypes |= BIT(wdev_iter->iftype); |
966 | } | 1088 | } |
967 | mutex_unlock(&rdev->devlist_mtx); | ||
968 | 1089 | ||
969 | if (total == 1) | 1090 | if (total == 1) |
970 | return 0; | 1091 | return 0; |
@@ -976,12 +1097,15 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
976 | 1097 | ||
977 | c = &rdev->wiphy.iface_combinations[i]; | 1098 | c = &rdev->wiphy.iface_combinations[i]; |
978 | 1099 | ||
1100 | if (total > c->max_interfaces) | ||
1101 | continue; | ||
1102 | if (num_different_channels > c->num_different_channels) | ||
1103 | continue; | ||
1104 | |||
979 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, | 1105 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, |
980 | GFP_KERNEL); | 1106 | GFP_KERNEL); |
981 | if (!limits) | 1107 | if (!limits) |
982 | return -ENOMEM; | 1108 | return -ENOMEM; |
983 | if (total > c->max_interfaces) | ||
984 | goto cont; | ||
985 | 1109 | ||
986 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { | 1110 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { |
987 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | 1111 | if (rdev->wiphy.software_iftypes & BIT(iftype)) |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index bc879833b21f..7df42f541873 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -827,8 +827,6 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, | |||
827 | { | 827 | { |
828 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 828 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
829 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 829 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
830 | struct ieee80211_channel *chan; | ||
831 | enum nl80211_channel_type channel_type; | ||
832 | 830 | ||
833 | switch (wdev->iftype) { | 831 | switch (wdev->iftype) { |
834 | case NL80211_IFTYPE_STATION: | 832 | case NL80211_IFTYPE_STATION: |
@@ -836,13 +834,10 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, | |||
836 | case NL80211_IFTYPE_ADHOC: | 834 | case NL80211_IFTYPE_ADHOC: |
837 | return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); | 835 | return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); |
838 | case NL80211_IFTYPE_MONITOR: | 836 | case NL80211_IFTYPE_MONITOR: |
839 | if (!rdev->ops->get_channel) | 837 | if (!rdev->monitor_channel) |
840 | return -EINVAL; | 838 | return -EINVAL; |
841 | 839 | ||
842 | chan = rdev->ops->get_channel(wdev->wiphy, &channel_type); | 840 | freq->m = rdev->monitor_channel->center_freq; |
843 | if (!chan) | ||
844 | return -EINVAL; | ||
845 | freq->m = chan->center_freq; | ||
846 | freq->e = 6; | 841 | freq->e = 6; |
847 | return 0; | 842 | return 0; |
848 | default: | 843 | default: |