diff options
-rw-r--r-- | include/linux/nl80211.h | 34 | ||||
-rw-r--r-- | include/net/cfg80211.h | 34 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 105 |
3 files changed, 173 insertions, 0 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index d2f276de9abe..45db17f81aa3 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -160,6 +160,11 @@ | |||
160 | * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, | 160 | * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, |
161 | * partial scan results may be available | 161 | * partial scan results may be available |
162 | * | 162 | * |
163 | * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation | ||
164 | * or noise level | ||
165 | * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to | ||
166 | * NL80211_CMD_GET_SURVEY and on the "scan" multicast group) | ||
167 | * | ||
163 | * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain | 168 | * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain |
164 | * has been changed and provides details of the request information | 169 | * has been changed and provides details of the request information |
165 | * that caused the change such as who initiated the regulatory request | 170 | * that caused the change such as who initiated the regulatory request |
@@ -341,6 +346,9 @@ enum nl80211_commands { | |||
341 | 346 | ||
342 | NL80211_CMD_SET_WIPHY_NETNS, | 347 | NL80211_CMD_SET_WIPHY_NETNS, |
343 | 348 | ||
349 | NL80211_CMD_GET_SURVEY, | ||
350 | NL80211_CMD_NEW_SURVEY_RESULTS, | ||
351 | |||
344 | /* add new commands above here */ | 352 | /* add new commands above here */ |
345 | 353 | ||
346 | /* used to define NL80211_CMD_MAX below */ | 354 | /* used to define NL80211_CMD_MAX below */ |
@@ -586,6 +594,10 @@ enum nl80211_commands { | |||
586 | * | 594 | * |
587 | * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface | 595 | * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface |
588 | * | 596 | * |
597 | * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of | ||
598 | * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute | ||
599 | * containing info as possible, see &enum survey_info. | ||
600 | * | ||
589 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 601 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
590 | * @__NL80211_ATTR_AFTER_LAST: internal use | 602 | * @__NL80211_ATTR_AFTER_LAST: internal use |
591 | */ | 603 | */ |
@@ -718,6 +730,8 @@ enum nl80211_attrs { | |||
718 | 730 | ||
719 | NL80211_ATTR_4ADDR, | 731 | NL80211_ATTR_4ADDR, |
720 | 732 | ||
733 | NL80211_ATTR_SURVEY_INFO, | ||
734 | |||
721 | /* add attributes here, update the policy in nl80211.c */ | 735 | /* add attributes here, update the policy in nl80211.c */ |
722 | 736 | ||
723 | __NL80211_ATTR_AFTER_LAST, | 737 | __NL80211_ATTR_AFTER_LAST, |
@@ -1121,6 +1135,26 @@ enum nl80211_reg_rule_flags { | |||
1121 | }; | 1135 | }; |
1122 | 1136 | ||
1123 | /** | 1137 | /** |
1138 | * enum nl80211_survey_info - survey information | ||
1139 | * | ||
1140 | * These attribute types are used with %NL80211_ATTR_SURVEY_INFO | ||
1141 | * when getting information about a survey. | ||
1142 | * | ||
1143 | * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved | ||
1144 | * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel | ||
1145 | * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) | ||
1146 | */ | ||
1147 | enum nl80211_survey_info { | ||
1148 | __NL80211_SURVEY_INFO_INVALID, | ||
1149 | NL80211_SURVEY_INFO_FREQUENCY, | ||
1150 | NL80211_SURVEY_INFO_NOISE, | ||
1151 | |||
1152 | /* keep last */ | ||
1153 | __NL80211_SURVEY_INFO_AFTER_LAST, | ||
1154 | NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1 | ||
1155 | }; | ||
1156 | |||
1157 | /** | ||
1124 | * enum nl80211_mntr_flags - monitor configuration flags | 1158 | * enum nl80211_mntr_flags - monitor configuration flags |
1125 | * | 1159 | * |
1126 | * Monitor configuration flags. | 1160 | * Monitor configuration flags. |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0e4c51fc63e5..21710fc17eaf 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -235,6 +235,35 @@ struct key_params { | |||
235 | }; | 235 | }; |
236 | 236 | ||
237 | /** | 237 | /** |
238 | * enum survey_info_flags - survey information flags | ||
239 | * | ||
240 | * Used by the driver to indicate which info in &struct survey_info | ||
241 | * it has filled in during the get_survey(). | ||
242 | */ | ||
243 | enum survey_info_flags { | ||
244 | SURVEY_INFO_NOISE_DBM = 1<<0, | ||
245 | }; | ||
246 | |||
247 | /** | ||
248 | * struct survey_info - channel survey response | ||
249 | * | ||
250 | * Used by dump_survey() to report back per-channel survey information. | ||
251 | * | ||
252 | * @channel: the channel this survey record reports, mandatory | ||
253 | * @filled: bitflag of flags from &enum survey_info_flags | ||
254 | * @noise: channel noise in dBm. This and all following fields are | ||
255 | * optional | ||
256 | * | ||
257 | * This structure can later be expanded with things like | ||
258 | * channel duty cycle etc. | ||
259 | */ | ||
260 | struct survey_info { | ||
261 | struct ieee80211_channel *channel; | ||
262 | u32 filled; | ||
263 | s8 noise; | ||
264 | }; | ||
265 | |||
266 | /** | ||
238 | * struct beacon_parameters - beacon parameters | 267 | * struct beacon_parameters - beacon parameters |
239 | * | 268 | * |
240 | * Used to configure the beacon for an interface. | 269 | * Used to configure the beacon for an interface. |
@@ -944,6 +973,8 @@ struct cfg80211_bitrate_mask { | |||
944 | * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting | 973 | * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting |
945 | * functions to adjust rfkill hw state | 974 | * functions to adjust rfkill hw state |
946 | * | 975 | * |
976 | * @dump_survey: get site survey information. | ||
977 | * | ||
947 | * @testmode_cmd: run a test mode command | 978 | * @testmode_cmd: run a test mode command |
948 | */ | 979 | */ |
949 | struct cfg80211_ops { | 980 | struct cfg80211_ops { |
@@ -1063,6 +1094,9 @@ struct cfg80211_ops { | |||
1063 | const u8 *peer, | 1094 | const u8 *peer, |
1064 | const struct cfg80211_bitrate_mask *mask); | 1095 | const struct cfg80211_bitrate_mask *mask); |
1065 | 1096 | ||
1097 | int (*dump_survey)(struct wiphy *wiphy, struct net_device *netdev, | ||
1098 | int idx, struct survey_info *info); | ||
1099 | |||
1066 | /* some temporary stuff to finish wext */ | 1100 | /* some temporary stuff to finish wext */ |
1067 | int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, | 1101 | int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, |
1068 | bool enabled, int timeout); | 1102 | bool enabled, int timeout); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4dc139cdba5c..5c8b3bfada4b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -3245,6 +3245,106 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3245 | return err; | 3245 | return err; |
3246 | } | 3246 | } |
3247 | 3247 | ||
3248 | static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | ||
3249 | int flags, struct net_device *dev, | ||
3250 | struct survey_info *survey) | ||
3251 | { | ||
3252 | void *hdr; | ||
3253 | struct nlattr *infoattr; | ||
3254 | |||
3255 | /* Survey without a channel doesn't make sense */ | ||
3256 | if (!survey->channel) | ||
3257 | return -EINVAL; | ||
3258 | |||
3259 | hdr = nl80211hdr_put(msg, pid, seq, flags, | ||
3260 | NL80211_CMD_NEW_SURVEY_RESULTS); | ||
3261 | if (!hdr) | ||
3262 | return -ENOMEM; | ||
3263 | |||
3264 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | ||
3265 | |||
3266 | infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO); | ||
3267 | if (!infoattr) | ||
3268 | goto nla_put_failure; | ||
3269 | |||
3270 | NLA_PUT_U32(msg, NL80211_SURVEY_INFO_FREQUENCY, | ||
3271 | survey->channel->center_freq); | ||
3272 | if (survey->filled & SURVEY_INFO_NOISE_DBM) | ||
3273 | NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, | ||
3274 | survey->noise); | ||
3275 | |||
3276 | nla_nest_end(msg, infoattr); | ||
3277 | |||
3278 | return genlmsg_end(msg, hdr); | ||
3279 | |||
3280 | nla_put_failure: | ||
3281 | genlmsg_cancel(msg, hdr); | ||
3282 | return -EMSGSIZE; | ||
3283 | } | ||
3284 | |||
3285 | static int nl80211_dump_survey(struct sk_buff *skb, | ||
3286 | struct netlink_callback *cb) | ||
3287 | { | ||
3288 | struct survey_info survey; | ||
3289 | struct cfg80211_registered_device *dev; | ||
3290 | struct net_device *netdev; | ||
3291 | int ifidx = cb->args[0]; | ||
3292 | int survey_idx = cb->args[1]; | ||
3293 | int res; | ||
3294 | |||
3295 | if (!ifidx) | ||
3296 | ifidx = nl80211_get_ifidx(cb); | ||
3297 | if (ifidx < 0) | ||
3298 | return ifidx; | ||
3299 | cb->args[0] = ifidx; | ||
3300 | |||
3301 | rtnl_lock(); | ||
3302 | |||
3303 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
3304 | if (!netdev) { | ||
3305 | res = -ENODEV; | ||
3306 | goto out_rtnl; | ||
3307 | } | ||
3308 | |||
3309 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
3310 | if (IS_ERR(dev)) { | ||
3311 | res = PTR_ERR(dev); | ||
3312 | goto out_rtnl; | ||
3313 | } | ||
3314 | |||
3315 | if (!dev->ops->dump_survey) { | ||
3316 | res = -EOPNOTSUPP; | ||
3317 | goto out_err; | ||
3318 | } | ||
3319 | |||
3320 | while (1) { | ||
3321 | res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, | ||
3322 | &survey); | ||
3323 | if (res == -ENOENT) | ||
3324 | break; | ||
3325 | if (res) | ||
3326 | goto out_err; | ||
3327 | |||
3328 | if (nl80211_send_survey(skb, | ||
3329 | NETLINK_CB(cb->skb).pid, | ||
3330 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
3331 | netdev, | ||
3332 | &survey) < 0) | ||
3333 | goto out; | ||
3334 | survey_idx++; | ||
3335 | } | ||
3336 | |||
3337 | out: | ||
3338 | cb->args[1] = survey_idx; | ||
3339 | res = skb->len; | ||
3340 | out_err: | ||
3341 | cfg80211_unlock_rdev(dev); | ||
3342 | out_rtnl: | ||
3343 | rtnl_unlock(); | ||
3344 | |||
3345 | return res; | ||
3346 | } | ||
3347 | |||
3248 | static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) | 3348 | static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) |
3249 | { | 3349 | { |
3250 | return auth_type <= NL80211_AUTHTYPE_MAX; | 3350 | return auth_type <= NL80211_AUTHTYPE_MAX; |
@@ -4322,6 +4422,11 @@ static struct genl_ops nl80211_ops[] = { | |||
4322 | .policy = nl80211_policy, | 4422 | .policy = nl80211_policy, |
4323 | .flags = GENL_ADMIN_PERM, | 4423 | .flags = GENL_ADMIN_PERM, |
4324 | }, | 4424 | }, |
4425 | { | ||
4426 | .cmd = NL80211_CMD_GET_SURVEY, | ||
4427 | .policy = nl80211_policy, | ||
4428 | .dumpit = nl80211_dump_survey, | ||
4429 | }, | ||
4325 | }; | 4430 | }; |
4326 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 4431 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
4327 | .name = "mlme", | 4432 | .name = "mlme", |