blob: e834422de40ac693323e3bc0bffd3eca1f2fb312 [file] [log] [blame]
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001/*
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 Simon54858ee5b2011-11-30 16:56:32 +01009#include <linux/export.h>
Johannes Berg59bbb6f2009-08-07 17:22:35 +020010#include <net/cfg80211.h>
11#include "core.h"
Hila Gonene35e4d22012-06-27 17:19:42 +030012#include "rdev-ops.h"
Johannes Berg59bbb6f2009-08-07 17:22:35 +020013
Johannes Berg683b6d32012-11-08 21:25:48 +010014bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
15 struct cfg80211_chan_def *chandef)
Luis R. Rodriguez9236d832010-11-12 16:31:23 -080016{
17 struct ieee80211_channel *sec_chan;
18 int diff;
19
Johannes Berg683b6d32012-11-08 21:25:48 +010020 trace_cfg80211_reg_can_beacon(wiphy, chandef);
Beni Lev4ee3e062012-08-27 12:49:39 +030021
Johannes Berg683b6d32012-11-08 21:25:48 +010022 switch (chandef->_type) {
Luis R. Rodriguez9236d832010-11-12 16:31:23 -080023 case NL80211_CHAN_HT40PLUS:
24 diff = 20;
Mark Mentovai09a02fd2010-11-17 16:34:37 -050025 break;
Luis R. Rodriguez9236d832010-11-12 16:31:23 -080026 case NL80211_CHAN_HT40MINUS:
27 diff = -20;
Mark Mentovai09a02fd2010-11-17 16:34:37 -050028 break;
Luis R. Rodriguez9236d832010-11-12 16:31:23 -080029 default:
Beni Lev4ee3e062012-08-27 12:49:39 +030030 trace_cfg80211_return_bool(true);
Johannes Bergd58e7e32012-05-16 23:50:17 +020031 return true;
Luis R. Rodriguez9236d832010-11-12 16:31:23 -080032 }
33
Johannes Berg683b6d32012-11-08 21:25:48 +010034 sec_chan = ieee80211_get_channel(wiphy,
35 chandef->chan->center_freq + diff);
Beni Lev4ee3e062012-08-27 12:49:39 +030036 if (!sec_chan) {
37 trace_cfg80211_return_bool(false);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -080038 return false;
Beni Lev4ee3e062012-08-27 12:49:39 +030039 }
Luis R. Rodriguez9236d832010-11-12 16:31:23 -080040
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 Lev4ee3e062012-08-27 12:49:39 +030045 IEEE80211_CHAN_RADAR)) {
46 trace_cfg80211_return_bool(false);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -080047 return false;
Beni Lev4ee3e062012-08-27 12:49:39 +030048 }
49 trace_cfg80211_return_bool(true);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -080050 return true;
51}
Johannes Berg683b6d32012-11-08 21:25:48 +010052EXPORT_SYMBOL(cfg80211_reg_can_beacon);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -080053
Johannes Berge8c9bd52012-06-06 08:18:22 +020054int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
Johannes Berg683b6d32012-11-08 21:25:48 +010055 struct cfg80211_chan_def *chandef)
Johannes Berg59bbb6f2009-08-07 17:22:35 +020056{
Johannes Berge8c9bd52012-06-06 08:18:22 +020057 if (!rdev->ops->set_monitor_channel)
Johannes Berg59bbb6f2009-08-07 17:22:35 +020058 return -EOPNOTSUPP;
Michal Kazior4f03c1e2012-06-29 12:47:03 +020059 if (!cfg80211_has_monitors_only(rdev))
60 return -EBUSY;
Johannes Berg59bbb6f2009-08-07 17:22:35 +020061
Johannes Berg683b6d32012-11-08 21:25:48 +010062 return rdev_set_monitor_channel(rdev, chandef);
Johannes Berg59bbb6f2009-08-07 17:22:35 +020063}
Michal Kazior26ab9a02012-06-29 12:47:00 +020064
65void
Johannes Berg8e95ea42012-07-10 19:39:02 +020066cfg80211_get_chan_state(struct wireless_dev *wdev,
Michal Kazior26ab9a02012-06-29 12:47:00 +020067 struct ieee80211_channel **chan,
68 enum cfg80211_chan_mode *chanmode)
69{
70 *chan = NULL;
71 *chanmode = CHAN_MODE_UNDEFINED;
72
Michal Kazior26ab9a02012-06-29 12:47:00 +020073 ASSERT_WDEV_LOCK(wdev);
74
Johannes Berg98104fde2012-06-16 00:19:54 +020075 if (wdev->netdev && !netif_running(wdev->netdev))
Michal Kazior26ab9a02012-06-29 12:47:00 +020076 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 Fietkauf53594a2012-07-12 16:10:02 +020097 if (wdev->beacon_interval) {
98 *chan = wdev->channel;
99 *chanmode = CHAN_MODE_SHARED;
100 }
101 return;
Michal Kazior26ab9a02012-06-29 12:47:00 +0200102 case NL80211_IFTYPE_MESH_POINT:
Felix Fietkauf53594a2012-07-12 16:10:02 +0200103 if (wdev->mesh_id_len) {
104 *chan = wdev->channel;
105 *chanmode = CHAN_MODE_SHARED;
106 }
Michal Kazior26ab9a02012-06-29 12:47:00 +0200107 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 Berg98104fde2012-06-16 00:19:54 +0200113 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 Kazior26ab9a02012-06-29 12:47:00 +0200118 case NL80211_IFTYPE_UNSPECIFIED:
119 case NUM_NL80211_IFTYPES:
120 WARN_ON(1);
121 }
122
123 return;
124}