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.
Unified · Split
| @@ -5721,6 +5721,28 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, · 5720 unmodified lines | ||
| 5721 | 5721 | const u8 *buf, size_t len, bool ack, gfp_t gfp); |
| 5722 | 5722 | |
| 5723 | 5723 | |
| 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 | + | |
| 5724 | 5746 | /** |
| 5725 | 5747 | * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event |
| 5726 | 5748 | * @dev: network device |
| @@ -990,6 +990,17 @@ · 989 unmodified lines | ||
| 990 | 990 | * &NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed |
| 991 | 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 | 1004 | * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded. |
| 994 | 1005 | * |
| 995 | 1006 | * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host |
| @@ -1228,6 +1239,8 @@ enum nl80211_commands { · 232 unmodified lines | ||
| 1228 | 1239 | |
| 1229 | 1240 | NL80211_CMD_STA_OPMODE_CHANGED, |
| 1230 | 1241 | |
| 1242 | + NL80211_CMD_CONTROL_PORT_FRAME, | |
| 1243 | + | |
| 1231 | 1244 | /* add new commands above here */ |
| 1232 | 1245 | |
| 1233 | 1246 | /* used to define NL80211_CMD_MAX below */ |
| @@ -14553,6 +14553,64 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, · 14552 unmodified lines | ||
| 14553 | 14553 | } |
| 14554 | 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 | 14614 | static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev, |
| 14557 | 14615 | const char *mac, gfp_t gfp) |
| 14558 | 14616 | { |
| @@ -2600,6 +2600,27 @@ TRACE_EVENT(cfg80211_mgmt_tx_status, · 2599 unmodified lines | ||
| 2600 | 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 | 2624 | TRACE_EVENT(cfg80211_cqm_rssi_notify, |
| 2604 | 2625 | TP_PROTO(struct net_device *netdev, |
| 2605 | 2626 | enum nl80211_cqm_rssi_threshold_event rssi_event, |