chan.c 3.0 KB

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