Johannes Berg | 59bbb6f | 2009-08-07 17:22:35 +0200 | [diff] [blame] | 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 | |
Alexander Simon | 54858ee5b | 2011-11-30 16:56:32 +0100 | [diff] [blame] | 9 | #include <linux/export.h> |
Johannes Berg | 59bbb6f | 2009-08-07 17:22:35 +0200 | [diff] [blame] | 10 | #include <net/cfg80211.h> |
| 11 | #include "core.h" |
Hila Gonen | e35e4d2 | 2012-06-27 17:19:42 +0300 | [diff] [blame] | 12 | #include "rdev-ops.h" |
Johannes Berg | 59bbb6f | 2009-08-07 17:22:35 +0200 | [diff] [blame] | 13 | |
Johannes Berg | 683b6d3 | 2012-11-08 21:25:48 +0100 | [diff] [blame^] | 14 | bool cfg80211_reg_can_beacon(struct wiphy *wiphy, |
| 15 | struct cfg80211_chan_def *chandef) |
Luis R. Rodriguez | 9236d83 | 2010-11-12 16:31:23 -0800 | [diff] [blame] | 16 | { |
| 17 | struct ieee80211_channel *sec_chan; |
| 18 | int diff; |
| 19 | |
Johannes Berg | 683b6d3 | 2012-11-08 21:25:48 +0100 | [diff] [blame^] | 20 | trace_cfg80211_reg_can_beacon(wiphy, chandef); |
Beni Lev | 4ee3e06 | 2012-08-27 12:49:39 +0300 | [diff] [blame] | 21 | |
Johannes Berg | 683b6d3 | 2012-11-08 21:25:48 +0100 | [diff] [blame^] | 22 | switch (chandef->_type) { |
Luis R. Rodriguez | 9236d83 | 2010-11-12 16:31:23 -0800 | [diff] [blame] | 23 | case NL80211_CHAN_HT40PLUS: |
| 24 | diff = 20; |
Mark Mentovai | 09a02fd | 2010-11-17 16:34:37 -0500 | [diff] [blame] | 25 | break; |
Luis R. Rodriguez | 9236d83 | 2010-11-12 16:31:23 -0800 | [diff] [blame] | 26 | case NL80211_CHAN_HT40MINUS: |
| 27 | diff = -20; |
Mark Mentovai | 09a02fd | 2010-11-17 16:34:37 -0500 | [diff] [blame] | 28 | break; |
Luis R. Rodriguez | 9236d83 | 2010-11-12 16:31:23 -0800 | [diff] [blame] | 29 | default: |
Beni Lev | 4ee3e06 | 2012-08-27 12:49:39 +0300 | [diff] [blame] | 30 | trace_cfg80211_return_bool(true); |
Johannes Berg | d58e7e3 | 2012-05-16 23:50:17 +0200 | [diff] [blame] | 31 | return true; |
Luis R. Rodriguez | 9236d83 | 2010-11-12 16:31:23 -0800 | [diff] [blame] | 32 | } |
| 33 | |
Johannes Berg | 683b6d3 | 2012-11-08 21:25:48 +0100 | [diff] [blame^] | 34 | sec_chan = ieee80211_get_channel(wiphy, |
| 35 | chandef->chan->center_freq + diff); |
Beni Lev | 4ee3e06 | 2012-08-27 12:49:39 +0300 | [diff] [blame] | 36 | if (!sec_chan) { |
| 37 | trace_cfg80211_return_bool(false); |
Luis R. Rodriguez | 9236d83 | 2010-11-12 16:31:23 -0800 | [diff] [blame] | 38 | return false; |
Beni Lev | 4ee3e06 | 2012-08-27 12:49:39 +0300 | [diff] [blame] | 39 | } |
Luis R. Rodriguez | 9236d83 | 2010-11-12 16:31:23 -0800 | [diff] [blame] | 40 | |
| 41 | /* we'll need a DFS capability later */ |
| 42 | if (sec_chan->flags & (IEEE80211_CHAN_DISABLED | |
| 43 | IEEE80211_CHAN_PASSIVE_SCAN | |
| 44 | IEEE80211_CHAN_NO_IBSS | |
Beni Lev | 4ee3e06 | 2012-08-27 12:49:39 +0300 | [diff] [blame] | 45 | IEEE80211_CHAN_RADAR)) { |
| 46 | trace_cfg80211_return_bool(false); |
Luis R. Rodriguez | 9236d83 | 2010-11-12 16:31:23 -0800 | [diff] [blame] | 47 | return false; |
Beni Lev | 4ee3e06 | 2012-08-27 12:49:39 +0300 | [diff] [blame] | 48 | } |
| 49 | trace_cfg80211_return_bool(true); |
Luis R. Rodriguez | 9236d83 | 2010-11-12 16:31:23 -0800 | [diff] [blame] | 50 | return true; |
| 51 | } |
Johannes Berg | 683b6d3 | 2012-11-08 21:25:48 +0100 | [diff] [blame^] | 52 | EXPORT_SYMBOL(cfg80211_reg_can_beacon); |
Luis R. Rodriguez | 9236d83 | 2010-11-12 16:31:23 -0800 | [diff] [blame] | 53 | |
Johannes Berg | e8c9bd5 | 2012-06-06 08:18:22 +0200 | [diff] [blame] | 54 | int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, |
Johannes Berg | 683b6d3 | 2012-11-08 21:25:48 +0100 | [diff] [blame^] | 55 | struct cfg80211_chan_def *chandef) |
Johannes Berg | 59bbb6f | 2009-08-07 17:22:35 +0200 | [diff] [blame] | 56 | { |
Johannes Berg | e8c9bd5 | 2012-06-06 08:18:22 +0200 | [diff] [blame] | 57 | if (!rdev->ops->set_monitor_channel) |
Johannes Berg | 59bbb6f | 2009-08-07 17:22:35 +0200 | [diff] [blame] | 58 | return -EOPNOTSUPP; |
Michal Kazior | 4f03c1e | 2012-06-29 12:47:03 +0200 | [diff] [blame] | 59 | if (!cfg80211_has_monitors_only(rdev)) |
| 60 | return -EBUSY; |
Johannes Berg | 59bbb6f | 2009-08-07 17:22:35 +0200 | [diff] [blame] | 61 | |
Johannes Berg | 683b6d3 | 2012-11-08 21:25:48 +0100 | [diff] [blame^] | 62 | return rdev_set_monitor_channel(rdev, chandef); |
Johannes Berg | 59bbb6f | 2009-08-07 17:22:35 +0200 | [diff] [blame] | 63 | } |
Michal Kazior | 26ab9a0 | 2012-06-29 12:47:00 +0200 | [diff] [blame] | 64 | |
| 65 | void |
Johannes Berg | 8e95ea4 | 2012-07-10 19:39:02 +0200 | [diff] [blame] | 66 | cfg80211_get_chan_state(struct wireless_dev *wdev, |
Michal Kazior | 26ab9a0 | 2012-06-29 12:47:00 +0200 | [diff] [blame] | 67 | struct ieee80211_channel **chan, |
| 68 | enum cfg80211_chan_mode *chanmode) |
| 69 | { |
| 70 | *chan = NULL; |
| 71 | *chanmode = CHAN_MODE_UNDEFINED; |
| 72 | |
Michal Kazior | 26ab9a0 | 2012-06-29 12:47:00 +0200 | [diff] [blame] | 73 | ASSERT_WDEV_LOCK(wdev); |
| 74 | |
Johannes Berg | 98104fde | 2012-06-16 00:19:54 +0200 | [diff] [blame] | 75 | if (wdev->netdev && !netif_running(wdev->netdev)) |
Michal Kazior | 26ab9a0 | 2012-06-29 12:47:00 +0200 | [diff] [blame] | 76 | return; |
| 77 | |
| 78 | switch (wdev->iftype) { |
| 79 | case NL80211_IFTYPE_ADHOC: |
| 80 | if (wdev->current_bss) { |
| 81 | *chan = wdev->current_bss->pub.channel; |
| 82 | *chanmode = wdev->ibss_fixed |
| 83 | ? CHAN_MODE_SHARED |
| 84 | : CHAN_MODE_EXCLUSIVE; |
| 85 | return; |
| 86 | } |
| 87 | case NL80211_IFTYPE_STATION: |
| 88 | case NL80211_IFTYPE_P2P_CLIENT: |
| 89 | if (wdev->current_bss) { |
| 90 | *chan = wdev->current_bss->pub.channel; |
| 91 | *chanmode = CHAN_MODE_SHARED; |
| 92 | return; |
| 93 | } |
| 94 | break; |
| 95 | case NL80211_IFTYPE_AP: |
| 96 | case NL80211_IFTYPE_P2P_GO: |
Felix Fietkau | f53594a | 2012-07-12 16:10:02 +0200 | [diff] [blame] | 97 | if (wdev->beacon_interval) { |
| 98 | *chan = wdev->channel; |
| 99 | *chanmode = CHAN_MODE_SHARED; |
| 100 | } |
| 101 | return; |
Michal Kazior | 26ab9a0 | 2012-06-29 12:47:00 +0200 | [diff] [blame] | 102 | case NL80211_IFTYPE_MESH_POINT: |
Felix Fietkau | f53594a | 2012-07-12 16:10:02 +0200 | [diff] [blame] | 103 | if (wdev->mesh_id_len) { |
| 104 | *chan = wdev->channel; |
| 105 | *chanmode = CHAN_MODE_SHARED; |
| 106 | } |
Michal Kazior | 26ab9a0 | 2012-06-29 12:47:00 +0200 | [diff] [blame] | 107 | return; |
| 108 | case NL80211_IFTYPE_MONITOR: |
| 109 | case NL80211_IFTYPE_AP_VLAN: |
| 110 | case NL80211_IFTYPE_WDS: |
| 111 | /* these interface types don't really have a channel */ |
| 112 | return; |
Johannes Berg | 98104fde | 2012-06-16 00:19:54 +0200 | [diff] [blame] | 113 | case NL80211_IFTYPE_P2P_DEVICE: |
| 114 | if (wdev->wiphy->features & |
| 115 | NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL) |
| 116 | *chanmode = CHAN_MODE_EXCLUSIVE; |
| 117 | return; |
Michal Kazior | 26ab9a0 | 2012-06-29 12:47:00 +0200 | [diff] [blame] | 118 | case NL80211_IFTYPE_UNSPECIFIED: |
| 119 | case NUM_NL80211_IFTYPES: |
| 120 | WARN_ON(1); |
| 121 | } |
| 122 | |
| 123 | return; |
| 124 | } |