linux/net/wireless/chan.c
<<
>>
Prefs
   1/*
   2 * This file contains helper code to handle channel
   3 * settings and keeping track of what is possible at
   4 * any point in time.
   5 *
   6 * Copyright 2009       Johannes Berg <johannes@sipsolutions.net>
   7 */
   8
   9#include <linux/export.h>
  10#include <net/cfg80211.h>
  11#include "core.h"
  12
  13struct ieee80211_channel *
  14rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
  15                  int freq, enum nl80211_channel_type channel_type)
  16{
  17        struct ieee80211_channel *chan;
  18        struct ieee80211_sta_ht_cap *ht_cap;
  19
  20        chan = ieee80211_get_channel(&rdev->wiphy, freq);
  21
  22        /* Primary channel not allowed */
  23        if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
  24                return NULL;
  25
  26        if (channel_type == NL80211_CHAN_HT40MINUS &&
  27            chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
  28                return NULL;
  29        else if (channel_type == NL80211_CHAN_HT40PLUS &&
  30                 chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
  31                return NULL;
  32
  33        ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
  34
  35        if (channel_type != NL80211_CHAN_NO_HT) {
  36                if (!ht_cap->ht_supported)
  37                        return NULL;
  38
  39                if (channel_type != NL80211_CHAN_HT20 &&
  40                    (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
  41                    ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
  42                        return NULL;
  43        }
  44
  45        return chan;
  46}
  47
  48bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
  49                                  struct ieee80211_channel *chan,
  50                                  enum nl80211_channel_type channel_type)
  51{
  52        struct ieee80211_channel *sec_chan;
  53        int diff;
  54
  55        switch (channel_type) {
  56        case NL80211_CHAN_HT40PLUS:
  57                diff = 20;
  58                break;
  59        case NL80211_CHAN_HT40MINUS:
  60                diff = -20;
  61                break;
  62        default:
  63                return true;
  64        }
  65
  66        sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff);
  67        if (!sec_chan)
  68                return false;
  69
  70        /* we'll need a DFS capability later */
  71        if (sec_chan->flags & (IEEE80211_CHAN_DISABLED |
  72                               IEEE80211_CHAN_PASSIVE_SCAN |
  73                               IEEE80211_CHAN_NO_IBSS |
  74                               IEEE80211_CHAN_RADAR))
  75                return false;
  76
  77        return true;
  78}
  79EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
  80
  81int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
  82                                 int freq, enum nl80211_channel_type chantype)
  83{
  84        struct ieee80211_channel *chan;
  85
  86        if (!rdev->ops->set_monitor_channel)
  87                return -EOPNOTSUPP;
  88        if (!cfg80211_has_monitors_only(rdev))
  89                return -EBUSY;
  90
  91        chan = rdev_freq_to_chan(rdev, freq, chantype);
  92        if (!chan)
  93                return -EINVAL;
  94
  95        return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
  96}
  97
  98void
  99cfg80211_get_chan_state(struct wireless_dev *wdev,
 100                        struct ieee80211_channel **chan,
 101                        enum cfg80211_chan_mode *chanmode)
 102{
 103        *chan = NULL;
 104        *chanmode = CHAN_MODE_UNDEFINED;
 105
 106        ASSERT_WDEV_LOCK(wdev);
 107
 108        if (wdev->netdev && !netif_running(wdev->netdev))
 109                return;
 110
 111        switch (wdev->iftype) {
 112        case NL80211_IFTYPE_ADHOC:
 113                if (wdev->current_bss) {
 114                        *chan = wdev->current_bss->pub.channel;
 115                        *chanmode = wdev->ibss_fixed
 116                                  ? CHAN_MODE_SHARED
 117                                  : CHAN_MODE_EXCLUSIVE;
 118                        return;
 119                }
 120        case NL80211_IFTYPE_STATION:
 121        case NL80211_IFTYPE_P2P_CLIENT:
 122                if (wdev->current_bss) {
 123                        *chan = wdev->current_bss->pub.channel;
 124                        *chanmode = CHAN_MODE_SHARED;
 125                        return;
 126                }
 127                break;
 128        case NL80211_IFTYPE_AP:
 129        case NL80211_IFTYPE_P2P_GO:
 130                if (wdev->beacon_interval) {
 131                        *chan = wdev->channel;
 132                        *chanmode = CHAN_MODE_SHARED;
 133                }
 134                return;
 135        case NL80211_IFTYPE_MESH_POINT:
 136                if (wdev->mesh_id_len) {
 137                        *chan = wdev->channel;
 138                        *chanmode = CHAN_MODE_SHARED;
 139                }
 140                return;
 141        case NL80211_IFTYPE_MONITOR:
 142        case NL80211_IFTYPE_AP_VLAN:
 143        case NL80211_IFTYPE_WDS:
 144                /* these interface types don't really have a channel */
 145                return;
 146        case NL80211_IFTYPE_P2P_DEVICE:
 147                if (wdev->wiphy->features &
 148                                NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL)
 149                        *chanmode = CHAN_MODE_EXCLUSIVE;
 150                return;
 151        case NL80211_IFTYPE_UNSPECIFIED:
 152        case NUM_NL80211_IFTYPES:
 153                WARN_ON(1);
 154        }
 155
 156        return;
 157}
 158
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.