aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c3
-rw-r--r--net/mac80211/driver-ops.h14
-rw-r--r--net/mac80211/driver-trace.h25
-rw-r--r--net/mac80211/ieee80211_i.h14
-rw-r--r--net/mac80211/iface.c157
5 files changed, 176 insertions, 37 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index f82b18e996b2..5de1ca3f17b9 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -52,9 +52,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
52 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 52 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
53 int ret; 53 int ret;
54 54
55 if (ieee80211_sdata_running(sdata))
56 return -EBUSY;
57
58 ret = ieee80211_if_change_type(sdata, type); 55 ret = ieee80211_if_change_type(sdata, type);
59 if (ret) 56 if (ret)
60 return ret; 57 return ret;
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 14123dce544b..6064b7b09e01 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -54,6 +54,20 @@ static inline int drv_add_interface(struct ieee80211_local *local,
54 return ret; 54 return ret;
55} 55}
56 56
57static inline int drv_change_interface(struct ieee80211_local *local,
58 struct ieee80211_sub_if_data *sdata,
59 enum nl80211_iftype type)
60{
61 int ret;
62
63 might_sleep();
64
65 trace_drv_change_interface(local, sdata, type);
66 ret = local->ops->change_interface(&local->hw, &sdata->vif, type);
67 trace_drv_return_int(local, ret);
68 return ret;
69}
70
57static inline void drv_remove_interface(struct ieee80211_local *local, 71static inline void drv_remove_interface(struct ieee80211_local *local,
58 struct ieee80211_vif *vif) 72 struct ieee80211_vif *vif)
59{ 73{
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index b5a95582d816..f6f3d89e43fa 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -136,6 +136,31 @@ TRACE_EVENT(drv_add_interface,
136 ) 136 )
137); 137);
138 138
139TRACE_EVENT(drv_change_interface,
140 TP_PROTO(struct ieee80211_local *local,
141 struct ieee80211_sub_if_data *sdata,
142 enum nl80211_iftype type),
143
144 TP_ARGS(local, sdata, type),
145
146 TP_STRUCT__entry(
147 LOCAL_ENTRY
148 VIF_ENTRY
149 __field(u32, new_type)
150 ),
151
152 TP_fast_assign(
153 LOCAL_ASSIGN;
154 VIF_ASSIGN;
155 __entry->new_type = type;
156 ),
157
158 TP_printk(
159 LOCAL_PR_FMT VIF_PR_FMT " new type:%d",
160 LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_type
161 )
162);
163
139TRACE_EVENT(drv_remove_interface, 164TRACE_EVENT(drv_remove_interface,
140 TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata), 165 TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata),
141 166
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f64837788681..d529bd5eab47 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -472,6 +472,16 @@ enum ieee80211_sub_if_data_flags {
472 IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), 472 IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3),
473}; 473};
474 474
475/**
476 * enum ieee80211_sdata_state_bits - virtual interface state bits
477 * @SDATA_STATE_RUNNING: virtual interface is up & running; this
478 * mirrors netif_running() but is separate for interface type
479 * change handling while the interface is up
480 */
481enum ieee80211_sdata_state_bits {
482 SDATA_STATE_RUNNING,
483};
484
475struct ieee80211_sub_if_data { 485struct ieee80211_sub_if_data {
476 struct list_head list; 486 struct list_head list;
477 487
@@ -485,6 +495,8 @@ struct ieee80211_sub_if_data {
485 495
486 unsigned int flags; 496 unsigned int flags;
487 497
498 unsigned long state;
499
488 int drop_unencrypted; 500 int drop_unencrypted;
489 501
490 char name[IFNAMSIZ]; 502 char name[IFNAMSIZ];
@@ -1087,7 +1099,7 @@ void ieee80211_recalc_idle(struct ieee80211_local *local);
1087 1099
1088static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) 1100static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
1089{ 1101{
1090 return netif_running(sdata->dev); 1102 return test_bit(SDATA_STATE_RUNNING, &sdata->state);
1091} 1103}
1092 1104
1093/* tx handling */ 1105/* tx handling */
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index cba3d806d722..c1cc200ac81f 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -148,7 +148,12 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
148 return 0; 148 return 0;
149} 149}
150 150
151static int ieee80211_open(struct net_device *dev) 151/*
152 * NOTE: Be very careful when changing this function, it must NOT return
153 * an error on interface type changes that have been pre-checked, so most
154 * checks should be in ieee80211_check_concurrent_iface.
155 */
156static int ieee80211_do_open(struct net_device *dev, bool coming_up)
152{ 157{
153 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 158 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
154 struct ieee80211_local *local = sdata->local; 159 struct ieee80211_local *local = sdata->local;
@@ -157,15 +162,6 @@ static int ieee80211_open(struct net_device *dev)
157 int res; 162 int res;
158 u32 hw_reconf_flags = 0; 163 u32 hw_reconf_flags = 0;
159 164
160 /* fail early if user set an invalid address */
161 if (!is_zero_ether_addr(dev->dev_addr) &&
162 !is_valid_ether_addr(dev->dev_addr))
163 return -EADDRNOTAVAIL;
164
165 res = ieee80211_check_concurrent_iface(sdata, sdata->vif.type);
166 if (res)
167 return res;
168
169 switch (sdata->vif.type) { 165 switch (sdata->vif.type) {
170 case NL80211_IFTYPE_WDS: 166 case NL80211_IFTYPE_WDS:
171 if (!is_valid_ether_addr(sdata->u.wds.remote_addr)) 167 if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
@@ -258,9 +254,11 @@ static int ieee80211_open(struct net_device *dev)
258 netif_carrier_on(dev); 254 netif_carrier_on(dev);
259 break; 255 break;
260 default: 256 default:
261 res = drv_add_interface(local, &sdata->vif); 257 if (coming_up) {
262 if (res) 258 res = drv_add_interface(local, &sdata->vif);
263 goto err_stop; 259 if (res)
260 goto err_stop;
261 }
264 262
265 if (ieee80211_vif_is_mesh(&sdata->vif)) { 263 if (ieee80211_vif_is_mesh(&sdata->vif)) {
266 local->fif_other_bss++; 264 local->fif_other_bss++;
@@ -316,7 +314,9 @@ static int ieee80211_open(struct net_device *dev)
316 hw_reconf_flags |= __ieee80211_recalc_idle(local); 314 hw_reconf_flags |= __ieee80211_recalc_idle(local);
317 mutex_unlock(&local->mtx); 315 mutex_unlock(&local->mtx);
318 316
319 local->open_count++; 317 if (coming_up)
318 local->open_count++;
319
320 if (hw_reconf_flags) { 320 if (hw_reconf_flags) {
321 ieee80211_hw_config(local, hw_reconf_flags); 321 ieee80211_hw_config(local, hw_reconf_flags);
322 /* 322 /*
@@ -331,6 +331,8 @@ static int ieee80211_open(struct net_device *dev)
331 331
332 netif_tx_start_all_queues(dev); 332 netif_tx_start_all_queues(dev);
333 333
334 set_bit(SDATA_STATE_RUNNING, &sdata->state);
335
334 return 0; 336 return 0;
335 err_del_interface: 337 err_del_interface:
336 drv_remove_interface(local, &sdata->vif); 338 drv_remove_interface(local, &sdata->vif);
@@ -344,19 +346,38 @@ static int ieee80211_open(struct net_device *dev)
344 return res; 346 return res;
345} 347}
346 348
347static int ieee80211_stop(struct net_device *dev) 349static int ieee80211_open(struct net_device *dev)
348{ 350{
349 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 351 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
352 int err;
353
354 /* fail early if user set an invalid address */
355 if (!is_zero_ether_addr(dev->dev_addr) &&
356 !is_valid_ether_addr(dev->dev_addr))
357 return -EADDRNOTAVAIL;
358
359 err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type);
360 if (err)
361 return err;
362
363 return ieee80211_do_open(dev, true);
364}
365
366static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
367 bool going_down)
368{
350 struct ieee80211_local *local = sdata->local; 369 struct ieee80211_local *local = sdata->local;
351 unsigned long flags; 370 unsigned long flags;
352 struct sk_buff *skb, *tmp; 371 struct sk_buff *skb, *tmp;
353 u32 hw_reconf_flags = 0; 372 u32 hw_reconf_flags = 0;
354 int i; 373 int i;
355 374
375 clear_bit(SDATA_STATE_RUNNING, &sdata->state);
376
356 /* 377 /*
357 * Stop TX on this interface first. 378 * Stop TX on this interface first.
358 */ 379 */
359 netif_tx_stop_all_queues(dev); 380 netif_tx_stop_all_queues(sdata->dev);
360 381
361 /* 382 /*
362 * Purge work for this interface. 383 * Purge work for this interface.
@@ -394,11 +415,12 @@ static int ieee80211_stop(struct net_device *dev)
394 if (sdata->vif.type == NL80211_IFTYPE_AP) 415 if (sdata->vif.type == NL80211_IFTYPE_AP)
395 local->fif_pspoll--; 416 local->fif_pspoll--;
396 417
397 netif_addr_lock_bh(dev); 418 netif_addr_lock_bh(sdata->dev);
398 spin_lock_bh(&local->filter_lock); 419 spin_lock_bh(&local->filter_lock);
399 __hw_addr_unsync(&local->mc_list, &dev->mc, dev->addr_len); 420 __hw_addr_unsync(&local->mc_list, &sdata->dev->mc,
421 sdata->dev->addr_len);
400 spin_unlock_bh(&local->filter_lock); 422 spin_unlock_bh(&local->filter_lock);
401 netif_addr_unlock_bh(dev); 423 netif_addr_unlock_bh(sdata->dev);
402 424
403 ieee80211_configure_filter(local); 425 ieee80211_configure_filter(local);
404 426
@@ -432,7 +454,8 @@ static int ieee80211_stop(struct net_device *dev)
432 WARN_ON(!list_empty(&sdata->u.ap.vlans)); 454 WARN_ON(!list_empty(&sdata->u.ap.vlans));
433 } 455 }
434 456
435 local->open_count--; 457 if (going_down)
458 local->open_count--;
436 459
437 switch (sdata->vif.type) { 460 switch (sdata->vif.type) {
438 case NL80211_IFTYPE_AP_VLAN: 461 case NL80211_IFTYPE_AP_VLAN:
@@ -504,7 +527,8 @@ static int ieee80211_stop(struct net_device *dev)
504 */ 527 */
505 ieee80211_free_keys(sdata); 528 ieee80211_free_keys(sdata);
506 529
507 drv_remove_interface(local, &sdata->vif); 530 if (going_down)
531 drv_remove_interface(local, &sdata->vif);
508 } 532 }
509 533
510 sdata->bss = NULL; 534 sdata->bss = NULL;
@@ -540,6 +564,13 @@ static int ieee80211_stop(struct net_device *dev)
540 } 564 }
541 } 565 }
542 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 566 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
567}
568
569static int ieee80211_stop(struct net_device *dev)
570{
571 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
572
573 ieee80211_do_stop(sdata, true);
543 574
544 return 0; 575 return 0;
545} 576}
@@ -857,9 +888,72 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
857 ieee80211_debugfs_add_netdev(sdata); 888 ieee80211_debugfs_add_netdev(sdata);
858} 889}
859 890
891static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
892 enum nl80211_iftype type)
893{
894 struct ieee80211_local *local = sdata->local;
895 int ret, err;
896
897 ASSERT_RTNL();
898
899 if (!local->ops->change_interface)
900 return -EBUSY;
901
902 switch (sdata->vif.type) {
903 case NL80211_IFTYPE_AP:
904 case NL80211_IFTYPE_STATION:
905 case NL80211_IFTYPE_ADHOC:
906 /*
907 * Could maybe also all others here?
908 * Just not sure how that interacts
909 * with the RX/config path e.g. for
910 * mesh.
911 */
912 break;
913 default:
914 return -EBUSY;
915 }
916
917 switch (type) {
918 case NL80211_IFTYPE_AP:
919 case NL80211_IFTYPE_STATION:
920 case NL80211_IFTYPE_ADHOC:
921 /*
922 * Could probably support everything
923 * but WDS here (WDS do_open can fail
924 * under memory pressure, which this
925 * code isn't prepared to handle).
926 */
927 break;
928 default:
929 return -EBUSY;
930 }
931
932 ret = ieee80211_check_concurrent_iface(sdata, type);
933 if (ret)
934 return ret;
935
936 ieee80211_do_stop(sdata, false);
937
938 ieee80211_teardown_sdata(sdata->dev);
939
940 ret = drv_change_interface(local, sdata, type);
941 if (ret)
942 type = sdata->vif.type;
943
944 ieee80211_setup_sdata(sdata, type);
945
946 err = ieee80211_do_open(sdata->dev, false);
947 WARN(err, "type change: do_open returned %d", err);
948
949 return ret;
950}
951
860int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, 952int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
861 enum nl80211_iftype type) 953 enum nl80211_iftype type)
862{ 954{
955 int ret;
956
863 ASSERT_RTNL(); 957 ASSERT_RTNL();
864 958
865 if (type == sdata->vif.type) 959 if (type == sdata->vif.type)
@@ -870,18 +964,15 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
870 type == NL80211_IFTYPE_ADHOC) 964 type == NL80211_IFTYPE_ADHOC)
871 return -EOPNOTSUPP; 965 return -EOPNOTSUPP;
872 966
873 /* 967 if (ieee80211_sdata_running(sdata)) {
874 * We could, here, on changes between IBSS/STA/MESH modes, 968 ret = ieee80211_runtime_change_iftype(sdata, type);
875 * invoke an MLME function instead that disassociates etc. 969 if (ret)
876 * and goes into the requested mode. 970 return ret;
877 */ 971 } else {
878 972 /* Purge and reset type-dependent state. */
879 if (ieee80211_sdata_running(sdata)) 973 ieee80211_teardown_sdata(sdata->dev);
880 return -EBUSY; 974 ieee80211_setup_sdata(sdata, type);
881 975 }
882 /* Purge and reset type-dependent state. */
883 ieee80211_teardown_sdata(sdata->dev);
884 ieee80211_setup_sdata(sdata, type);
885 976
886 /* reset some values that shouldn't be kept across type changes */ 977 /* reset some values that shouldn't be kept across type changes */
887 sdata->vif.bss_conf.basic_rates = 978 sdata->vif.bss_conf.basic_rates =