aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/iface.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-08-27 06:35:58 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-08-27 13:53:31 -0400
commit34d4bc4d41d282a66dafe1b01a7d46bad468cefb (patch)
treeac0936b00f1ebd037be32fd0e5f304f26366e6c0 /net/mac80211/iface.c
parent87490f6db38999fee7f6d3dbecc5b94730c7e010 (diff)
mac80211: support runtime interface type changes
Add support to mac80211 for changing the interface type even when the interface is UP, if the driver supports it. To achieve this * add a new driver callback for switching, * split some of the interface up/down code out into new functions (do_open/do_stop), and * maintain an own __SDATA_RUNNING bit that will not be set during interface type, so that any other code doesn't use the interface. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r--net/mac80211/iface.c157
1 files changed, 124 insertions, 33 deletions
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 =