chan.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /*
  2. * mac80211 - channel management
  3. */
  4. #include <linux/nl80211.h>
  5. #include "ieee80211_i.h"
  6. static enum ieee80211_chan_mode
  7. __ieee80211_get_channel_mode(struct ieee80211_local *local,
  8. struct ieee80211_sub_if_data *ignore)
  9. {
  10. struct ieee80211_sub_if_data *sdata;
  11. lockdep_assert_held(&local->iflist_mtx);
  12. list_for_each_entry(sdata, &local->interfaces, list) {
  13. if (sdata == ignore)
  14. continue;
  15. if (!ieee80211_sdata_running(sdata))
  16. continue;
  17. if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
  18. continue;
  19. if (sdata->vif.type == NL80211_IFTYPE_STATION &&
  20. !sdata->u.mgd.associated)
  21. continue;
  22. if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
  23. if (!sdata->u.ibss.ssid_len)
  24. continue;
  25. if (!sdata->u.ibss.fixed_channel)
  26. return CHAN_MODE_HOPPING;
  27. }
  28. if (sdata->vif.type == NL80211_IFTYPE_AP &&
  29. !sdata->u.ap.beacon)
  30. continue;
  31. return CHAN_MODE_FIXED;
  32. }
  33. return CHAN_MODE_UNDEFINED;
  34. }
  35. enum ieee80211_chan_mode
  36. ieee80211_get_channel_mode(struct ieee80211_local *local,
  37. struct ieee80211_sub_if_data *ignore)
  38. {
  39. enum ieee80211_chan_mode mode;
  40. mutex_lock(&local->iflist_mtx);
  41. mode = __ieee80211_get_channel_mode(local, ignore);
  42. mutex_unlock(&local->iflist_mtx);
  43. return mode;
  44. }
  45. bool ieee80211_set_channel_type(struct ieee80211_local *local,
  46. struct ieee80211_sub_if_data *sdata,
  47. enum nl80211_channel_type chantype)
  48. {
  49. struct ieee80211_sub_if_data *tmp;
  50. enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT;
  51. bool result;
  52. mutex_lock(&local->iflist_mtx);
  53. list_for_each_entry(tmp, &local->interfaces, list) {
  54. if (tmp == sdata)
  55. continue;
  56. if (!ieee80211_sdata_running(tmp))
  57. continue;
  58. switch (tmp->vif.bss_conf.channel_type) {
  59. case NL80211_CHAN_NO_HT:
  60. case NL80211_CHAN_HT20:
  61. if (superchan > tmp->vif.bss_conf.channel_type)
  62. break;
  63. superchan = tmp->vif.bss_conf.channel_type;
  64. break;
  65. case NL80211_CHAN_HT40PLUS:
  66. WARN_ON(superchan == NL80211_CHAN_HT40MINUS);
  67. superchan = NL80211_CHAN_HT40PLUS;
  68. break;
  69. case NL80211_CHAN_HT40MINUS:
  70. WARN_ON(superchan == NL80211_CHAN_HT40PLUS);
  71. superchan = NL80211_CHAN_HT40MINUS;
  72. break;
  73. }
  74. }
  75. switch (superchan) {
  76. case NL80211_CHAN_NO_HT:
  77. case NL80211_CHAN_HT20:
  78. /*
  79. * allow any change that doesn't go to no-HT
  80. * (if it already is no-HT no change is needed)
  81. */
  82. if (chantype == NL80211_CHAN_NO_HT)
  83. break;
  84. superchan = chantype;
  85. break;
  86. case NL80211_CHAN_HT40PLUS:
  87. case NL80211_CHAN_HT40MINUS:
  88. /* allow smaller bandwidth and same */
  89. if (chantype == NL80211_CHAN_NO_HT)
  90. break;
  91. if (chantype == NL80211_CHAN_HT20)
  92. break;
  93. if (superchan == chantype)
  94. break;
  95. result = false;
  96. goto out;
  97. }
  98. local->_oper_channel_type = superchan;
  99. if (sdata)
  100. sdata->vif.bss_conf.channel_type = chantype;
  101. result = true;
  102. out:
  103. mutex_unlock(&local->iflist_mtx);
  104. return result;
  105. }