@@ -2830,6 +2830,20 @@ enum nl80211_commands {
* @NL80211_ATTR_MLO_LINK_DISABLED: Flag attribute indicating that the link is
* disabled.
*
+ * @NL80211_ATTR_CARRIER_UP_COUNT: This u32 attribute is included in some
+ * events that indicate a successful connection (notably association),
+ * indicating the value of the netdev's carrier_up_count at the time
+ * of sending this event. Userspace can use this to fix a race: when
+ * the carrier is turned on, the actual handling thereof is done in
+ * an asynchronous manner in the kernel. Thus, if userspace attempts
+ * to send a frame immediately after receiving the event indicating
+ * successful connection over nl80211, that may not go through if the
+ * asynchronous processing in the kernel hasn't yet happened. To fix
+ * it then userspace should be listening to rtnetlink events, and if
+ * it didn't see the value of the carrier_up_count yet, it can wait
+ * for a further rtnetlink event with a value equal to or bigger than
+ * the value reported here, and only then transmit data.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3368,6 +3382,8 @@ enum nl80211_attrs {
NL80211_ATTR_MLO_LINK_DISABLED,
+ NL80211_ATTR_CARRIER_UP_COUNT,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -818,6 +818,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_HW_TIMESTAMP_ENABLED] = { .type = NLA_FLAG },
[NL80211_ATTR_EMA_RNR_ELEMS] = { .type = NLA_NESTED },
[NL80211_ATTR_MLO_LINK_DISABLED] = { .type = NLA_FLAG },
+ [NL80211_ATTR_CARRIER_UP_COUNT] = { .type = NLA_REJECT },
};
/* policy for the key attributes */
@@ -17738,11 +17739,13 @@ void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
struct nl80211_mlme_event {
enum nl80211_commands cmd;
+ const u8 *mac_addr;
const u8 *buf;
size_t buf_len;
int uapsd_queues;
const u8 *req_ies;
size_t req_ies_len;
+ u32 carrier_up_count;
bool reconnect;
};
@@ -17766,12 +17769,17 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
- nla_put(msg, NL80211_ATTR_FRAME, event->buf_len, event->buf) ||
+ (event->buf &&
+ nla_put(msg, NL80211_ATTR_FRAME, event->buf_len, event->buf)) ||
(event->req_ies &&
nla_put(msg, NL80211_ATTR_REQ_IE, event->req_ies_len,
event->req_ies)))
goto nla_put_failure;
+ if (event->mac_addr &&
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, event->mac_addr))
+ goto nla_put_failure;
+
if (event->reconnect &&
nla_put_flag(msg, NL80211_ATTR_RECONNECT_REQUESTED))
goto nla_put_failure;
@@ -17789,6 +17797,11 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
nla_nest_end(msg, nla_wmm);
}
+ if (event->carrier_up_count &&
+ nla_put_u32(msg, NL80211_ATTR_CARRIER_UP_COUNT,
+ event->carrier_up_count))
+ goto nla_put_failure;
+
genlmsg_end(msg, hdr);
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
@@ -17824,6 +17837,7 @@ void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
.uapsd_queues = data->uapsd_queues,
.req_ies = data->req_ies,
.req_ies_len = data->req_ies_len,
+ .carrier_up_count = atomic_read(&netdev->carrier_up_count),
};
nl80211_send_mlme_event(rdev, netdev, &event, GFP_KERNEL);
@@ -18307,32 +18321,13 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *bssid,
gfp_t gfp)
{
- struct sk_buff *msg;
- void *hdr;
+ struct nl80211_mlme_event event = {
+ .cmd = NL80211_CMD_JOIN_IBSS,
+ .mac_addr = bssid,
+ .carrier_up_count = atomic_read(&netdev->carrier_up_count),
+ };
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
- if (!msg)
- return;
-
- hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
- if (!hdr) {
- nlmsg_free(msg);
- return;
- }
-
- if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
- nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
- nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
- goto nla_put_failure;
-
- genlmsg_end(msg, hdr);
-
- genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
- NL80211_MCGRP_MLME, gfp);
- return;
-
- nla_put_failure:
- nlmsg_free(msg);
+ nl80211_send_mlme_event(rdev, netdev, &event, gfp);
}
void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,