diff options
author | Denis Kenzior <denkenz@gmail.com> | 2018-03-26 13:52:41 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2018-03-29 07:44:04 -0400 |
commit | 6a671a50f8199b3e1fe49fa8afff0fc8335da79c (patch) | |
tree | 2c363b4dadd770bd6cac7d6e37a0ec4d688c873f | |
parent | 4d191c75365a0067a9d5b8c8746b1bd9310c5a70 (diff) |
nl80211: Add CMD_CONTROL_PORT_FRAME API
This commit also adds cfg80211_rx_control_port function. This is used
to generate a CMD_CONTROL_PORT_FRAME event out to userspace. The
conn_owner_nlportid is used as the unicast destination. This means that
userspace must specify NL80211_ATTR_SOCKET_OWNER flag if control port
over nl80211 routing is requested in NL80211_CMD_CONNECT,
NL80211_CMD_ASSOCIATE, NL80211_CMD_START_AP or IBSS/mesh join.
Signed-off-by: Denis Kenzior <denkenz@gmail.com>
[johannes: fix return value of cfg80211_rx_control_port()]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/net/cfg80211.h | 22 | ||||
-rw-r--r-- | include/uapi/linux/nl80211.h | 13 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 58 | ||||
-rw-r--r-- | net/wireless/trace.h | 21 |
4 files changed, 114 insertions, 0 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index bfe174896fcf..df145f76adad 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -5722,6 +5722,28 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, | |||
5722 | 5722 | ||
5723 | 5723 | ||
5724 | /** | 5724 | /** |
5725 | * cfg80211_rx_control_port - notification about a received control port frame | ||
5726 | * @dev: The device the frame matched to | ||
5727 | * @buf: control port frame | ||
5728 | * @len: length of the frame data | ||
5729 | * @addr: The peer from which the frame was received | ||
5730 | * @proto: frame protocol, typically PAE or Pre-authentication | ||
5731 | * @unencrypted: Whether the frame was received unencrypted | ||
5732 | * | ||
5733 | * This function is used to inform userspace about a received control port | ||
5734 | * frame. It should only be used if userspace indicated it wants to receive | ||
5735 | * control port frames over nl80211. | ||
5736 | * | ||
5737 | * The frame is the data portion of the 802.3 or 802.11 data frame with all | ||
5738 | * network layer headers removed (e.g. the raw EAPoL frame). | ||
5739 | * | ||
5740 | * Return: %true if the frame was passed to userspace | ||
5741 | */ | ||
5742 | bool cfg80211_rx_control_port(struct net_device *dev, | ||
5743 | const u8 *buf, size_t len, | ||
5744 | const u8 *addr, u16 proto, bool unencrypted); | ||
5745 | |||
5746 | /** | ||
5725 | * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event | 5747 | * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event |
5726 | * @dev: network device | 5748 | * @dev: network device |
5727 | * @rssi_event: the triggered RSSI event | 5749 | * @rssi_event: the triggered RSSI event |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 9ea3d6039eca..6a3cc7a635b5 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -990,6 +990,17 @@ | |||
990 | * &NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed | 990 | * &NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed |
991 | * &NL80211_CMD_DISCONNECT should be indicated instead. | 991 | * &NL80211_CMD_DISCONNECT should be indicated instead. |
992 | * | 992 | * |
993 | * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request | ||
994 | * and RX notification. This command is used both as a request to transmit | ||
995 | * a control port frame and as a notification that a control port frame | ||
996 | * has been received. %NL80211_ATTR_FRAME is used to specify the | ||
997 | * frame contents. The frame is the raw EAPoL data, without ethernet or | ||
998 | * 802.11 headers. | ||
999 | * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, | ||
1000 | * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added | ||
1001 | * indicating the protocol type of the received frame; whether the frame | ||
1002 | * was received unencrypted and the MAC address of the peer respectively. | ||
1003 | * | ||
993 | * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded. | 1004 | * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded. |
994 | * | 1005 | * |
995 | * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host | 1006 | * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host |
@@ -1228,6 +1239,8 @@ enum nl80211_commands { | |||
1228 | 1239 | ||
1229 | NL80211_CMD_STA_OPMODE_CHANGED, | 1240 | NL80211_CMD_STA_OPMODE_CHANGED, |
1230 | 1241 | ||
1242 | NL80211_CMD_CONTROL_PORT_FRAME, | ||
1243 | |||
1231 | /* add new commands above here */ | 1244 | /* add new commands above here */ |
1232 | 1245 | ||
1233 | /* used to define NL80211_CMD_MAX below */ | 1246 | /* used to define NL80211_CMD_MAX below */ |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cfaf2aeb9783..0870447fbd55 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -14553,6 +14553,64 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, | |||
14553 | } | 14553 | } |
14554 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); | 14554 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); |
14555 | 14555 | ||
14556 | static int __nl80211_rx_control_port(struct net_device *dev, | ||
14557 | const u8 *buf, size_t len, | ||
14558 | const u8 *addr, u16 proto, | ||
14559 | bool unencrypted, gfp_t gfp) | ||
14560 | { | ||
14561 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
14562 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
14563 | struct sk_buff *msg; | ||
14564 | void *hdr; | ||
14565 | u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid); | ||
14566 | |||
14567 | if (!nlportid) | ||
14568 | return -ENOENT; | ||
14569 | |||
14570 | msg = nlmsg_new(100 + len, gfp); | ||
14571 | if (!msg) | ||
14572 | return -ENOMEM; | ||
14573 | |||
14574 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONTROL_PORT_FRAME); | ||
14575 | if (!hdr) { | ||
14576 | nlmsg_free(msg); | ||
14577 | return -ENOBUFS; | ||
14578 | } | ||
14579 | |||
14580 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
14581 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || | ||
14582 | nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), | ||
14583 | NL80211_ATTR_PAD) || | ||
14584 | nla_put(msg, NL80211_ATTR_FRAME, len, buf) || | ||
14585 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) || | ||
14586 | nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) || | ||
14587 | (unencrypted && nla_put_flag(msg, | ||
14588 | NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) | ||
14589 | goto nla_put_failure; | ||
14590 | |||
14591 | genlmsg_end(msg, hdr); | ||
14592 | |||
14593 | return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid); | ||
14594 | |||
14595 | nla_put_failure: | ||
14596 | nlmsg_free(msg); | ||
14597 | return -ENOBUFS; | ||
14598 | } | ||
14599 | |||
14600 | bool cfg80211_rx_control_port(struct net_device *dev, | ||
14601 | const u8 *buf, size_t len, | ||
14602 | const u8 *addr, u16 proto, bool unencrypted) | ||
14603 | { | ||
14604 | int ret; | ||
14605 | |||
14606 | trace_cfg80211_rx_control_port(dev, buf, len, addr, proto, unencrypted); | ||
14607 | ret = __nl80211_rx_control_port(dev, buf, len, addr, proto, | ||
14608 | unencrypted, GFP_ATOMIC); | ||
14609 | trace_cfg80211_return_bool(ret == 0); | ||
14610 | return ret == 0; | ||
14611 | } | ||
14612 | EXPORT_SYMBOL(cfg80211_rx_control_port); | ||
14613 | |||
14556 | static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev, | 14614 | static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev, |
14557 | const char *mac, gfp_t gfp) | 14615 | const char *mac, gfp_t gfp) |
14558 | { | 14616 | { |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 5152938b358d..42fd338f879e 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -2600,6 +2600,27 @@ TRACE_EVENT(cfg80211_mgmt_tx_status, | |||
2600 | WDEV_PR_ARG, __entry->cookie, BOOL_TO_STR(__entry->ack)) | 2600 | WDEV_PR_ARG, __entry->cookie, BOOL_TO_STR(__entry->ack)) |
2601 | ); | 2601 | ); |
2602 | 2602 | ||
2603 | TRACE_EVENT(cfg80211_rx_control_port, | ||
2604 | TP_PROTO(struct net_device *netdev, const u8 *buf, size_t len, | ||
2605 | const u8 *addr, u16 proto, bool unencrypted), | ||
2606 | TP_ARGS(netdev, buf, len, addr, proto, unencrypted), | ||
2607 | TP_STRUCT__entry( | ||
2608 | NETDEV_ENTRY | ||
2609 | MAC_ENTRY(addr) | ||
2610 | __field(u16, proto) | ||
2611 | __field(bool, unencrypted) | ||
2612 | ), | ||
2613 | TP_fast_assign( | ||
2614 | NETDEV_ASSIGN; | ||
2615 | MAC_ASSIGN(addr, addr); | ||
2616 | __entry->proto = proto; | ||
2617 | __entry->unencrypted = unencrypted; | ||
2618 | ), | ||
2619 | TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT " proto: 0x%x, unencrypted: %s", | ||
2620 | NETDEV_PR_ARG, MAC_PR_ARG(addr), | ||
2621 | __entry->proto, BOOL_TO_STR(__entry->unencrypted)) | ||
2622 | ); | ||
2623 | |||
2603 | TRACE_EVENT(cfg80211_cqm_rssi_notify, | 2624 | TRACE_EVENT(cfg80211_cqm_rssi_notify, |
2604 | TP_PROTO(struct net_device *netdev, | 2625 | TP_PROTO(struct net_device *netdev, |
2605 | enum nl80211_cqm_rssi_threshold_event rssi_event, | 2626 | enum nl80211_cqm_rssi_threshold_event rssi_event, |