aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2013-04-18 09:49:00 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-04-22 09:48:00 -0400
commit5de17984898c5758fc6ebe08eccea9f4b6548914 (patch)
tree17aab780c025cfac0bd5a8b010b8ea9c138ff780 /net/wireless
parenta36473621c871df14bbf2106ab0721b475aac8e0 (diff)
cfg80211: introduce critical protocol indication from user-space
Some protocols need a more reliable connection to complete successful in reasonable time. This patch adds a user-space API to indicate the wireless driver that a critical protocol is about to commence and when it is done, using nl80211 primitives NL80211_CMD_CRIT_PROTOCOL_START and NL80211_CRIT_PROTOCOL_STOP. There can be only on critical protocol session started per registered cfg80211 device. The driver can support this by implementing the cfg80211 callbacks .crit_proto_start() and .crit_proto_stop(). Examples of protocols that can benefit from this are DHCP, EAPOL, APIPA. Exactly how the link can/should be made more reliable is up to the driver. Things to consider are avoid scanning, no multi-channel operations, and alter coexistence schemes. Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.h3
-rw-r--r--net/wireless/mlme.c5
-rw-r--r--net/wireless/nl80211.c117
-rw-r--r--net/wireless/rdev-ops.h24
-rw-r--r--net/wireless/trace.h35
5 files changed, 183 insertions, 1 deletions
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 124e5e773fbc..fd35dae547c4 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -88,6 +88,9 @@ struct cfg80211_registered_device {
88 88
89 struct delayed_work dfs_update_channels_wk; 89 struct delayed_work dfs_update_channels_wk;
90 90
91 /* netlink port which started critical protocol (0 means not started) */
92 u32 crit_proto_nlportid;
93
91 /* must be last because of the way we do wiphy_priv(), 94 /* must be last because of the way we do wiphy_priv(),
92 * and it should at least be aligned to NETDEV_ALIGN */ 95 * and it should at least be aligned to NETDEV_ALIGN */
93 struct wiphy wiphy __aligned(NETDEV_ALIGN); 96 struct wiphy wiphy __aligned(NETDEV_ALIGN);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 390198bf4b36..0c7b7dd855f6 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -648,6 +648,11 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
648 648
649 spin_unlock_bh(&wdev->mgmt_registrations_lock); 649 spin_unlock_bh(&wdev->mgmt_registrations_lock);
650 650
651 if (nlportid && rdev->crit_proto_nlportid == nlportid) {
652 rdev->crit_proto_nlportid = 0;
653 rdev_crit_proto_stop(rdev, wdev);
654 }
655
651 if (nlportid == wdev->ap_unexpected_nlportid) 656 if (nlportid == wdev->ap_unexpected_nlportid)
652 wdev->ap_unexpected_nlportid = 0; 657 wdev->ap_unexpected_nlportid = 0;
653} 658}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 3abcbbada6d4..afa283841e8c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1424,6 +1424,10 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
1424 } 1424 }
1425 CMD(start_p2p_device, START_P2P_DEVICE); 1425 CMD(start_p2p_device, START_P2P_DEVICE);
1426 CMD(set_mcast_rate, SET_MCAST_RATE); 1426 CMD(set_mcast_rate, SET_MCAST_RATE);
1427 if (split) {
1428 CMD(crit_proto_start, CRIT_PROTOCOL_START);
1429 CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
1430 }
1427 1431
1428#ifdef CONFIG_NL80211_TESTMODE 1432#ifdef CONFIG_NL80211_TESTMODE
1429 CMD(testmode_cmd, TESTMODE); 1433 CMD(testmode_cmd, TESTMODE);
@@ -8216,6 +8220,64 @@ static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
8216 return rdev_update_ft_ies(rdev, dev, &ft_params); 8220 return rdev_update_ft_ies(rdev, dev, &ft_params);
8217} 8221}
8218 8222
8223static int nl80211_crit_protocol_start(struct sk_buff *skb,
8224 struct genl_info *info)
8225{
8226 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8227 struct wireless_dev *wdev = info->user_ptr[1];
8228 enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC;
8229 u16 duration;
8230 int ret;
8231
8232 if (!rdev->ops->crit_proto_start)
8233 return -EOPNOTSUPP;
8234
8235 if (WARN_ON(!rdev->ops->crit_proto_stop))
8236 return -EINVAL;
8237
8238 if (rdev->crit_proto_nlportid)
8239 return -EBUSY;
8240
8241 /* determine protocol if provided */
8242 if (info->attrs[NL80211_ATTR_CRIT_PROT_ID])
8243 proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]);
8244
8245 if (proto >= NUM_NL80211_CRIT_PROTO)
8246 return -EINVAL;
8247
8248 /* timeout must be provided */
8249 if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION])
8250 return -EINVAL;
8251
8252 duration =
8253 nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]);
8254
8255 if (duration > NL80211_CRIT_PROTO_MAX_DURATION)
8256 return -ERANGE;
8257
8258 ret = rdev_crit_proto_start(rdev, wdev, proto, duration);
8259 if (!ret)
8260 rdev->crit_proto_nlportid = info->snd_portid;
8261
8262 return ret;
8263}
8264
8265static int nl80211_crit_protocol_stop(struct sk_buff *skb,
8266 struct genl_info *info)
8267{
8268 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8269 struct wireless_dev *wdev = info->user_ptr[1];
8270
8271 if (!rdev->ops->crit_proto_stop)
8272 return -EOPNOTSUPP;
8273
8274 if (rdev->crit_proto_nlportid) {
8275 rdev->crit_proto_nlportid = 0;
8276 rdev_crit_proto_stop(rdev, wdev);
8277 }
8278 return 0;
8279}
8280
8219#define NL80211_FLAG_NEED_WIPHY 0x01 8281#define NL80211_FLAG_NEED_WIPHY 0x01
8220#define NL80211_FLAG_NEED_NETDEV 0x02 8282#define NL80211_FLAG_NEED_NETDEV 0x02
8221#define NL80211_FLAG_NEED_RTNL 0x04 8283#define NL80211_FLAG_NEED_RTNL 0x04
@@ -8905,6 +8967,22 @@ static struct genl_ops nl80211_ops[] = {
8905 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | 8967 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
8906 NL80211_FLAG_NEED_RTNL, 8968 NL80211_FLAG_NEED_RTNL,
8907 }, 8969 },
8970 {
8971 .cmd = NL80211_CMD_CRIT_PROTOCOL_START,
8972 .doit = nl80211_crit_protocol_start,
8973 .policy = nl80211_policy,
8974 .flags = GENL_ADMIN_PERM,
8975 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
8976 NL80211_FLAG_NEED_RTNL,
8977 },
8978 {
8979 .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
8980 .doit = nl80211_crit_protocol_stop,
8981 .policy = nl80211_policy,
8982 .flags = GENL_ADMIN_PERM,
8983 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
8984 NL80211_FLAG_NEED_RTNL,
8985 }
8908}; 8986};
8909 8987
8910static struct genl_multicast_group nl80211_mlme_mcgrp = { 8988static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -10650,6 +10728,45 @@ void cfg80211_ft_event(struct net_device *netdev,
10650} 10728}
10651EXPORT_SYMBOL(cfg80211_ft_event); 10729EXPORT_SYMBOL(cfg80211_ft_event);
10652 10730
10731void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
10732{
10733 struct cfg80211_registered_device *rdev;
10734 struct sk_buff *msg;
10735 void *hdr;
10736 u32 nlportid;
10737
10738 rdev = wiphy_to_dev(wdev->wiphy);
10739 if (!rdev->crit_proto_nlportid)
10740 return;
10741
10742 nlportid = rdev->crit_proto_nlportid;
10743 rdev->crit_proto_nlportid = 0;
10744
10745 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
10746 if (!msg)
10747 return;
10748
10749 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP);
10750 if (!hdr)
10751 goto nla_put_failure;
10752
10753 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
10754 nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
10755 goto nla_put_failure;
10756
10757 genlmsg_end(msg, hdr);
10758
10759 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
10760 return;
10761
10762 nla_put_failure:
10763 if (hdr)
10764 genlmsg_cancel(msg, hdr);
10765 nlmsg_free(msg);
10766
10767}
10768EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
10769
10653/* initialisation/exit functions */ 10770/* initialisation/exit functions */
10654 10771
10655int nl80211_init(void) 10772int nl80211_init(void)
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index d77e1c1d3a0e..9f15f0ac824d 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -875,7 +875,7 @@ static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev,
875 trace_rdev_stop_p2p_device(&rdev->wiphy, wdev); 875 trace_rdev_stop_p2p_device(&rdev->wiphy, wdev);
876 rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); 876 rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
877 trace_rdev_return_void(&rdev->wiphy); 877 trace_rdev_return_void(&rdev->wiphy);
878} 878}
879 879
880static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, 880static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev,
881 struct net_device *dev, 881 struct net_device *dev,
@@ -901,4 +901,26 @@ static inline int rdev_update_ft_ies(struct cfg80211_registered_device *rdev,
901 return ret; 901 return ret;
902} 902}
903 903
904static inline int rdev_crit_proto_start(struct cfg80211_registered_device *rdev,
905 struct wireless_dev *wdev,
906 enum nl80211_crit_proto_id protocol,
907 u16 duration)
908{
909 int ret;
910
911 trace_rdev_crit_proto_start(&rdev->wiphy, wdev, protocol, duration);
912 ret = rdev->ops->crit_proto_start(&rdev->wiphy, wdev,
913 protocol, duration);
914 trace_rdev_return_int(&rdev->wiphy, ret);
915 return ret;
916}
917
918static inline void rdev_crit_proto_stop(struct cfg80211_registered_device *rdev,
919 struct wireless_dev *wdev)
920{
921 trace_rdev_crit_proto_stop(&rdev->wiphy, wdev);
922 rdev->ops->crit_proto_stop(&rdev->wiphy, wdev);
923 trace_rdev_return_void(&rdev->wiphy);
924}
925
904#endif /* __CFG80211_RDEV_OPS */ 926#endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 3c2033b8f596..ecd4fcec3c94 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1806,6 +1806,41 @@ TRACE_EVENT(rdev_update_ft_ies,
1806 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->md) 1806 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->md)
1807); 1807);
1808 1808
1809TRACE_EVENT(rdev_crit_proto_start,
1810 TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
1811 enum nl80211_crit_proto_id protocol, u16 duration),
1812 TP_ARGS(wiphy, wdev, protocol, duration),
1813 TP_STRUCT__entry(
1814 WIPHY_ENTRY
1815 WDEV_ENTRY
1816 __field(u16, proto)
1817 __field(u16, duration)
1818 ),
1819 TP_fast_assign(
1820 WIPHY_ASSIGN;
1821 WDEV_ASSIGN;
1822 __entry->proto = protocol;
1823 __entry->duration = duration;
1824 ),
1825 TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", proto=%x, duration=%u",
1826 WIPHY_PR_ARG, WDEV_PR_ARG, __entry->proto, __entry->duration)
1827);
1828
1829TRACE_EVENT(rdev_crit_proto_stop,
1830 TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
1831 TP_ARGS(wiphy, wdev),
1832 TP_STRUCT__entry(
1833 WIPHY_ENTRY
1834 WDEV_ENTRY
1835 ),
1836 TP_fast_assign(
1837 WIPHY_ASSIGN;
1838 WDEV_ASSIGN;
1839 ),
1840 TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT,
1841 WIPHY_PR_ARG, WDEV_PR_ARG)
1842);
1843
1809/************************************************************* 1844/*************************************************************
1810 * cfg80211 exported functions traces * 1845 * cfg80211 exported functions traces *
1811 *************************************************************/ 1846 *************************************************************/