aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h46
-rw-r--r--include/net/cfg80211.h19
-rw-r--r--net/wireless/mlme.c13
-rw-r--r--net/wireless/nl80211.c131
-rw-r--r--net/wireless/nl80211.h6
5 files changed, 215 insertions, 0 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 28ba20fda3e2..89947597b9ce 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -323,6 +323,12 @@
323 * the TX command and %NL80211_ATTR_FRAME includes the contents of the 323 * the TX command and %NL80211_ATTR_FRAME includes the contents of the
324 * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged 324 * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
325 * the frame. 325 * the frame.
326 * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
327 * is used to configure connection quality monitoring notification trigger
328 * levels.
329 * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This
330 * command is used as an event to indicate the that a trigger level was
331 * reached.
326 * 332 *
327 * @NL80211_CMD_MAX: highest used command number 333 * @NL80211_CMD_MAX: highest used command number
328 * @__NL80211_CMD_AFTER_LAST: internal use 334 * @__NL80211_CMD_AFTER_LAST: internal use
@@ -419,6 +425,9 @@ enum nl80211_commands {
419 NL80211_CMD_SET_POWER_SAVE, 425 NL80211_CMD_SET_POWER_SAVE,
420 NL80211_CMD_GET_POWER_SAVE, 426 NL80211_CMD_GET_POWER_SAVE,
421 427
428 NL80211_CMD_SET_CQM,
429 NL80211_CMD_NOTIFY_CQM,
430
422 /* add new commands above here */ 431 /* add new commands above here */
423 432
424 /* used to define NL80211_CMD_MAX below */ 433 /* used to define NL80211_CMD_MAX below */
@@ -691,6 +700,9 @@ enum nl80211_commands {
691 * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was 700 * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
692 * acknowledged by the recipient. 701 * acknowledged by the recipient.
693 * 702 *
703 * @NL80211_ATTR_CQM: connection quality monitor configuration in a
704 * nested attribute with %NL80211_ATTR_CQM_* sub-attributes.
705 *
694 * @NL80211_ATTR_MAX: highest attribute number currently defined 706 * @NL80211_ATTR_MAX: highest attribute number currently defined
695 * @__NL80211_ATTR_AFTER_LAST: internal use 707 * @__NL80211_ATTR_AFTER_LAST: internal use
696 */ 708 */
@@ -842,6 +854,8 @@ enum nl80211_attrs {
842 854
843 NL80211_ATTR_PS_STATE, 855 NL80211_ATTR_PS_STATE,
844 856
857 NL80211_ATTR_CQM,
858
845 /* add attributes here, update the policy in nl80211.c */ 859 /* add attributes here, update the policy in nl80211.c */
846 860
847 __NL80211_ATTR_AFTER_LAST, 861 __NL80211_ATTR_AFTER_LAST,
@@ -1583,4 +1597,36 @@ enum nl80211_ps_state {
1583 NL80211_PS_ENABLED, 1597 NL80211_PS_ENABLED,
1584}; 1598};
1585 1599
1600/**
1601 * enum nl80211_attr_cqm - connection quality monitor attributes
1602 * @__NL80211_ATTR_CQM_INVALID: invalid
1603 * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm (zero to disable)
1604 * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm
1605 * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event
1606 * @__NL80211_ATTR_CQM_AFTER_LAST: internal
1607 * @NL80211_ATTR_CQM_MAX: highest key attribute
1608 */
1609enum nl80211_attr_cqm {
1610 __NL80211_ATTR_CQM_INVALID,
1611 NL80211_ATTR_CQM_RSSI_THOLD,
1612 NL80211_ATTR_CQM_RSSI_HYST,
1613 NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
1614
1615 /* keep last */
1616 __NL80211_ATTR_CQM_AFTER_LAST,
1617 NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1
1618};
1619
1620/**
1621 * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event
1622 * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW - The RSSI level is lower than the
1623 * configured threshold
1624 * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH - The RSSI is higher than the
1625 * configured threshold
1626 */
1627enum nl80211_cqm_rssi_threshold_event {
1628 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
1629 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
1630};
1631
1586#endif /* __LINUX_NL80211_H */ 1632#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 3d134a1fb96b..868cfd3b9724 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1007,6 +1007,7 @@ struct cfg80211_pmksa {
1007 * RSN IE. It allows for faster roaming between WPA2 BSSIDs. 1007 * RSN IE. It allows for faster roaming between WPA2 BSSIDs.
1008 * @del_pmksa: Delete a cached PMKID. 1008 * @del_pmksa: Delete a cached PMKID.
1009 * @flush_pmksa: Flush all cached PMKIDs. 1009 * @flush_pmksa: Flush all cached PMKIDs.
1010 * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold.
1010 * 1011 *
1011 */ 1012 */
1012struct cfg80211_ops { 1013struct cfg80211_ops {
@@ -1152,6 +1153,10 @@ struct cfg80211_ops {
1152 1153
1153 int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, 1154 int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
1154 bool enabled, int timeout); 1155 bool enabled, int timeout);
1156
1157 int (*set_cqm_rssi_config)(struct wiphy *wiphy,
1158 struct net_device *dev,
1159 s32 rssi_thold, u32 rssi_hyst);
1155}; 1160};
1156 1161
1157/* 1162/*
@@ -2337,4 +2342,18 @@ bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
2337void cfg80211_action_tx_status(struct net_device *dev, u64 cookie, 2342void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
2338 const u8 *buf, size_t len, bool ack, gfp_t gfp); 2343 const u8 *buf, size_t len, bool ack, gfp_t gfp);
2339 2344
2345
2346/**
2347 * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event
2348 * @dev: network device
2349 * @rssi_event: the triggered RSSI event
2350 * @gfp: context flags
2351 *
2352 * This function is called when a configured connection quality monitoring
2353 * rssi threshold reached event occurs.
2354 */
2355void cfg80211_cqm_rssi_notify(struct net_device *dev,
2356 enum nl80211_cqm_rssi_threshold_event rssi_event,
2357 gfp_t gfp);
2358
2340#endif /* __NET_CFG80211_H */ 2359#endif /* __NET_CFG80211_H */
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 62bc8855e123..0855f0d32349 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -894,3 +894,16 @@ void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
894 nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp); 894 nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
895} 895}
896EXPORT_SYMBOL(cfg80211_action_tx_status); 896EXPORT_SYMBOL(cfg80211_action_tx_status);
897
898void cfg80211_cqm_rssi_notify(struct net_device *dev,
899 enum nl80211_cqm_rssi_threshold_event rssi_event,
900 gfp_t gfp)
901{
902 struct wireless_dev *wdev = dev->ieee80211_ptr;
903 struct wiphy *wiphy = wdev->wiphy;
904 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
905
906 /* Indicate roaming trigger event to user space */
907 nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp);
908}
909EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e447db04cf76..a7fc3d83f5f6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -149,6 +149,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
149 .len = IEEE80211_MAX_DATA_LEN }, 149 .len = IEEE80211_MAX_DATA_LEN },
150 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, }, 150 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
151 [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 }, 151 [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
152 [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
152}; 153};
153 154
154/* policy for the attributes */ 155/* policy for the attributes */
@@ -4778,6 +4779,84 @@ unlock_rtnl:
4778 return err; 4779 return err;
4779} 4780}
4780 4781
4782static struct nla_policy
4783nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
4784 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
4785 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
4786 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
4787};
4788
4789static int nl80211_set_cqm_rssi(struct genl_info *info,
4790 s32 threshold, u32 hysteresis)
4791{
4792 struct cfg80211_registered_device *rdev;
4793 struct wireless_dev *wdev;
4794 struct net_device *dev;
4795 int err;
4796
4797 if (threshold > 0)
4798 return -EINVAL;
4799
4800 rtnl_lock();
4801
4802 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4803 if (err)
4804 goto unlock_rdev;
4805
4806 wdev = dev->ieee80211_ptr;
4807
4808 if (!rdev->ops->set_cqm_rssi_config) {
4809 err = -EOPNOTSUPP;
4810 goto unlock_rdev;
4811 }
4812
4813 if (wdev->iftype != NL80211_IFTYPE_STATION) {
4814 err = -EOPNOTSUPP;
4815 goto unlock_rdev;
4816 }
4817
4818 err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev,
4819 threshold, hysteresis);
4820
4821unlock_rdev:
4822 cfg80211_unlock_rdev(rdev);
4823 dev_put(dev);
4824 rtnl_unlock();
4825
4826 return err;
4827}
4828
4829static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
4830{
4831 struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
4832 struct nlattr *cqm;
4833 int err;
4834
4835 cqm = info->attrs[NL80211_ATTR_CQM];
4836 if (!cqm) {
4837 err = -EINVAL;
4838 goto out;
4839 }
4840
4841 err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm,
4842 nl80211_attr_cqm_policy);
4843 if (err)
4844 goto out;
4845
4846 if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
4847 attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
4848 s32 threshold;
4849 u32 hysteresis;
4850 threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
4851 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
4852 err = nl80211_set_cqm_rssi(info, threshold, hysteresis);
4853 } else
4854 err = -EINVAL;
4855
4856out:
4857 return err;
4858}
4859
4781static struct genl_ops nl80211_ops[] = { 4860static struct genl_ops nl80211_ops[] = {
4782 { 4861 {
4783 .cmd = NL80211_CMD_GET_WIPHY, 4862 .cmd = NL80211_CMD_GET_WIPHY,
@@ -5082,6 +5161,12 @@ static struct genl_ops nl80211_ops[] = {
5082 .policy = nl80211_policy, 5161 .policy = nl80211_policy,
5083 /* can be retrieved by unprivileged users */ 5162 /* can be retrieved by unprivileged users */
5084 }, 5163 },
5164 {
5165 .cmd = NL80211_CMD_SET_CQM,
5166 .doit = nl80211_set_cqm,
5167 .policy = nl80211_policy,
5168 .flags = GENL_ADMIN_PERM,
5169 },
5085}; 5170};
5086 5171
5087static struct genl_multicast_group nl80211_mlme_mcgrp = { 5172static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -5832,6 +5917,52 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
5832 nlmsg_free(msg); 5917 nlmsg_free(msg);
5833} 5918}
5834 5919
5920void
5921nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
5922 struct net_device *netdev,
5923 enum nl80211_cqm_rssi_threshold_event rssi_event,
5924 gfp_t gfp)
5925{
5926 struct sk_buff *msg;
5927 struct nlattr *pinfoattr;
5928 void *hdr;
5929
5930 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
5931 if (!msg)
5932 return;
5933
5934 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
5935 if (!hdr) {
5936 nlmsg_free(msg);
5937 return;
5938 }
5939
5940 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
5941 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
5942
5943 pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
5944 if (!pinfoattr)
5945 goto nla_put_failure;
5946
5947 NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
5948 rssi_event);
5949
5950 nla_nest_end(msg, pinfoattr);
5951
5952 if (genlmsg_end(msg, hdr) < 0) {
5953 nlmsg_free(msg);
5954 return;
5955 }
5956
5957 genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
5958 nl80211_mlme_mcgrp.id, gfp);
5959 return;
5960
5961 nla_put_failure:
5962 genlmsg_cancel(msg, hdr);
5963 nlmsg_free(msg);
5964}
5965
5835static int nl80211_netlink_notify(struct notifier_block * nb, 5966static int nl80211_netlink_notify(struct notifier_block * nb,
5836 unsigned long state, 5967 unsigned long state,
5837 void *_notify) 5968 void *_notify)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 4ca511102c6c..2ad7fbc7d9f1 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -82,4 +82,10 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
82 const u8 *buf, size_t len, bool ack, 82 const u8 *buf, size_t len, bool ack,
83 gfp_t gfp); 83 gfp_t gfp);
84 84
85void
86nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
87 struct net_device *netdev,
88 enum nl80211_cqm_rssi_threshold_event rssi_event,
89 gfp_t gfp);
90
85#endif /* __NET_WIRELESS_NL80211_H */ 91#endif /* __NET_WIRELESS_NL80211_H */