chan.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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. default:
  39. break;
  40. }
  41. return CHAN_MODE_FIXED;
  42. }
  43. return CHAN_MODE_UNDEFINED;
  44. }
  45. enum ieee80211_chan_mode
  46. ieee80211_get_channel_mode(struct ieee80211_local *local,
  47. struct ieee80211_sub_if_data *ignore)
  48. {
  49. enum ieee80211_chan_mode mode;
  50. mutex_lock(&local->iflist_mtx);
  51. mode = __ieee80211_get_channel_mode(local, ignore);
  52. mutex_unlock(&local->iflist_mtx);
  53. return mode;
  54. }
  55. bool ieee80211_set_channel_type(struct ieee80211_local *local,
  56. struct ieee80211_sub_if_data *sdata,
  57. enum nl80211_channel_type chantype)
  58. {
  59. struct ieee80211_sub_if_data *tmp;
  60. enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT;
  61. bool result;
  62. mutex_lock(&local->iflist_mtx);
  63. list_for_each_entry(tmp, &local->interfaces, list) {
  64. if (tmp == sdata)
  65. continue;
  66. if (!ieee80211_sdata_running(tmp))
  67. continue;
  68. switch (tmp->vif.bss_conf.channel_type) {
  69. case NL80211_CHAN_NO_HT:
  70. case NL80211_CHAN_HT20:
  71. if (superchan > tmp->vif.bss_conf.channel_type)
  72. break;
  73. superchan = tmp->vif.bss_conf.channel_type;
  74. break;
  75. case NL80211_CHAN_HT40PLUS:
  76. WARN_ON(superchan == NL80211_CHAN_HT40MINUS);
  77. superchan = NL80211_CHAN_HT40PLUS;
  78. break;
  79. case NL80211_CHAN_HT40MINUS:
  80. WARN_ON(superchan == NL80211_CHAN_HT40PLUS);
  81. superchan = NL80211_CHAN_HT40MINUS;
  82. break;
  83. }
  84. }
  85. switch (superchan) {
  86. case NL80211_CHAN_NO_HT:
  87. case NL80211_CHAN_HT20:
  88. /*
  89. * allow any change that doesn't go to no-HT
  90. * (if it already is no-HT no change is needed)
  91. */
  92. if (chantype == NL80211_CHAN_NO_HT)
  93. break;
  94. superchan = chantype;
  95. break;
  96. case NL80211_CHAN_HT40PLUS:
  97. case NL80211_CHAN_HT40MINUS:
  98. /* allow smaller bandwidth and same */
  99. if (chantype == NL80211_CHAN_NO_HT)
  100. break;
  101. if (chantype == NL80211_CHAN_HT20)
  102. break;
  103. if (superchan == chantype)
  104. break;
  105. result = false;
  106. goto out;
  107. }
  108. local->_oper_channel_type = superchan;
  109. if (sdata)
  110. sdata->vif.bss_conf.channel_type = chantype;
  111. result = true;
  112. out:
  113. mutex_unlock(&local->iflist_mtx);
  114. return result;
  115. }
  116. /*
  117. * ieee80211_get_tx_channel_type returns the channel type we should
  118. * use for packet transmission, given the channel capability and
  119. * whatever regulatory flags we have been given.
  120. */
  121. enum nl80211_channel_type ieee80211_get_tx_channel_type(
  122. struct ieee80211_local *local,
  123. enum nl80211_channel_type channel_type)
  124. {
  125. switch (channel_type) {
  126. case NL80211_CHAN_HT40PLUS:
  127. if (local->hw.conf.channel->flags &
  128. IEEE80211_CHAN_NO_HT40PLUS)
  129. return NL80211_CHAN_HT20;
  130. break;
  131. case NL80211_CHAN_HT40MINUS:
  132. if (local->hw.conf.channel->flags &
  133. IEEE80211_CHAN_NO_HT40MINUS)
  134. return NL80211_CHAN_HT20;
  135. break;
  136. default:
  137. break;
  138. }
  139. return channel_type;
  140. }