chan.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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. switch (sdata->vif.type) {
  18. case NL80211_IFTYPE_MONITOR:
  19. continue;
  20. case NL80211_IFTYPE_STATION:
  21. if (!sdata->u.mgd.associated)
  22. continue;
  23. break;
  24. case NL80211_IFTYPE_ADHOC:
  25. if (!sdata->u.ibss.ssid_len)
  26. continue;
  27. if (!sdata->u.ibss.fixed_channel)
  28. return CHAN_MODE_HOPPING;
  29. break;
  30. case NL80211_IFTYPE_AP_VLAN:
  31. /* will also have _AP interface */
  32. continue;
  33. case NL80211_IFTYPE_AP:
  34. if (!sdata->u.ap.beacon)
  35. continue;
  36. break;
  37. default:
  38. break;
  39. }
  40. return CHAN_MODE_FIXED;
  41. }
  42. return CHAN_MODE_UNDEFINED;
  43. }
  44. enum ieee80211_chan_mode
  45. ieee80211_get_channel_mode(struct ieee80211_local *local,
  46. struct ieee80211_sub_if_data *ignore)
  47. {
  48. enum ieee80211_chan_mode mode;
  49. mutex_lock(&local->iflist_mtx);
  50. mode = __ieee80211_get_channel_mode(local, ignore);
  51. mutex_unlock(&local->iflist_mtx);
  52. return mode;
  53. }
  54. bool ieee80211_set_channel_type(struct ieee80211_local *local,
  55. struct ieee80211_sub_if_data *sdata,
  56. enum nl80211_channel_type chantype)
  57. {
  58. struct ieee80211_sub_if_data *tmp;
  59. enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT;
  60. bool result;
  61. mutex_lock(&local->iflist_mtx);
  62. list_for_each_entry(tmp, &local->interfaces, list) {
  63. if (tmp == sdata)
  64. continue;
  65. if (!ieee80211_sdata_running(tmp))
  66. continue;
  67. switch (tmp->vif.bss_conf.channel_type) {
  68. case NL80211_CHAN_NO_HT:
  69. case NL80211_CHAN_HT20:
  70. if (superchan > tmp->vif.bss_conf.channel_type)
  71. break;
  72. superchan = tmp->vif.bss_conf.channel_type;
  73. break;
  74. case NL80211_CHAN_HT40PLUS:
  75. WARN_ON(superchan == NL80211_CHAN_HT40MINUS);
  76. superchan = NL80211_CHAN_HT40PLUS;
  77. break;
  78. case NL80211_CHAN_HT40MINUS:
  79. WARN_ON(superchan == NL80211_CHAN_HT40PLUS);
  80. superchan = NL80211_CHAN_HT40MINUS;
  81. break;
  82. }
  83. }
  84. switch (superchan) {
  85. case NL80211_CHAN_NO_HT:
  86. case NL80211_CHAN_HT20:
  87. /*
  88. * allow any change that doesn't go to no-HT
  89. * (if it already is no-HT no change is needed)
  90. */
  91. if (chantype == NL80211_CHAN_NO_HT)
  92. break;
  93. superchan = chantype;
  94. break;
  95. case NL80211_CHAN_HT40PLUS:
  96. case NL80211_CHAN_HT40MINUS:
  97. /* allow smaller bandwidth and same */
  98. if (chantype == NL80211_CHAN_NO_HT)
  99. break;
  100. if (chantype == NL80211_CHAN_HT20)
  101. break;
  102. if (superchan == chantype)
  103. break;
  104. result = false;
  105. goto out;
  106. }
  107. local->_oper_channel_type = superchan;
  108. if (sdata)
  109. sdata->vif.bss_conf.channel_type = chantype;
  110. result = true;
  111. out:
  112. mutex_unlock(&local->iflist_mtx);
  113. return result;
  114. }