@@ -2821,6 +2821,10 @@ struct cfg80211_nan_func {
* All other parameters must be ignored.
*
* @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
+ *
+ * @set_link_loss_profile: Set link loss profile for specific connection.
+ * @get_link_loss_profile: Get the current link loss profile of specific
+ * connection.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3109,6 +3113,14 @@ struct cfg80211_ops {
int (*set_multicast_to_unicast)(struct wiphy *wiphy,
struct net_device *dev,
const bool enabled);
+ int (*set_link_loss_profile)(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ enum nl80211_link_loss_profile profile,
+ const u8 *addr);
+ enum nl80211_link_loss_profile (*get_link_loss_profile)(
+ struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const u8 *addr);
};
/*
@@ -901,6 +901,11 @@
* does not result in a change for the current association. Currently,
* only the %NL80211_ATTR_IE data is used and updated with this command.
*
+ * @NL80211_CMD_SET_LINK_LOSS_PROFILE: Set link loss profile (behavior) for
+ * specific connection.
+ * @NL80211_CMD_GET_LINK_LOSS_PROFILE: Get current link loss profile of specific
+ * connection.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1100,6 +1105,9 @@ enum nl80211_commands {
NL80211_CMD_UPDATE_CONNECT_PARAMS,
+ NL80211_CMD_SET_LINK_LOSS_PROFILE,
+ NL80211_CMD_GET_LINK_LOSS_PROFILE,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -2013,6 +2021,10 @@ enum nl80211_commands {
* e.g., with %NL80211_CMD_CONNECT event.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
+ *
+ * @NL80211_ATTR_LINK_LOSS_PROFILE: attribute that indicate the link loss
+ * behavior using &enum nl80211_link_loss_profile values.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -2423,6 +2435,8 @@ enum nl80211_attrs {
NL80211_ATTR_TIMEOUT_REASON,
+ NL80211_ATTR_LINK_LOSS_PROFILE,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -5254,4 +5268,23 @@ enum nl80211_nan_match_attributes {
NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1
};
+/**
+ * enum nl80211_link_loss_profile.
+ *
+ * Used by set_link_loss_profile() and get_link_loss_profile()
+ * to set/get link loss behavior.
+ *
+ * @NL80211_LINK_LOSS_PROFILE_RELAXED: prefer maintaining link
+ * up even in poor link quality environment
+ * @NL80211_LINK_LOSS_PROFILE_DEFAULT: The default behavior for
+ * maintaining link up vs link quality.
+ * @NL80211_LINK_LOSS_PROFILE_AGGRESSIVE: prefer losing link
+ * up in poor link quality environment
+ */
+enum nl80211_link_loss_profile {
+ NL80211_LINK_LOSS_PROFILE_RELAXED,
+ NL80211_LINK_LOSS_PROFILE_DEFAULT,
+ NL80211_LINK_LOSS_PROFILE_AGGRESSIVE
+};
+
#endif /* __LINUX_NL80211_H */
@@ -410,6 +410,7 @@ enum nl80211_multicast_groups {
.len = sizeof(struct nl80211_bss_select_rssi_adjust)
},
[NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
+ [NL80211_ATTR_LINK_LOSS_PROFILE] = { .type = NLA_U8 },
};
/* policy for the key attributes */
@@ -12067,6 +12068,60 @@ static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
return rdev_set_multicast_to_unicast(rdev, dev, enabled);
}
+static int nl80211_set_link_loss_profile(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct wireless_dev *wdev = info->user_ptr[1];
+ enum nl80211_link_loss_profile profile;
+ const u8 *addr;
+ int ret;
+
+ if (!info->attrs[NL80211_ATTR_LINK_LOSS_PROFILE] ||
+ !info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ profile = nla_get_u8(info->attrs[NL80211_ATTR_LINK_LOSS_PROFILE]);
+ addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (profile != NL80211_LINK_LOSS_PROFILE_RELAXED &&
+ profile != NL80211_LINK_LOSS_PROFILE_DEFAULT &&
+ profile != NL80211_LINK_LOSS_PROFILE_AGGRESSIVE)
+ return -EINVAL;
+
+ if (!rdev->ops->set_link_loss_profile)
+ return -EOPNOTSUPP;
+
+ wdev_lock(wdev);
+ ret = rdev_set_link_loss_profile(rdev, wdev, profile, addr);
+ wdev_unlock(wdev);
+
+ return ret;
+}
+
+static int nl80211_get_link_loss_profile(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct wireless_dev *wdev = info->user_ptr[1];
+ const u8 *addr;
+ enum nl80211_link_loss_profile profile;
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (!rdev->ops->get_link_loss_profile)
+ return -EOPNOTSUPP;
+
+ wdev_lock(wdev);
+ profile = rdev_get_link_loss_profile(rdev, wdev, addr);
+ wdev_unlock(wdev);
+
+ return profile;
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -12942,6 +12997,21 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_SET_LINK_LOSS_PROFILE,
+ .doit = nl80211_set_link_loss_profile,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_GET_LINK_LOSS_PROFILE,
+ .doit = nl80211_get_link_loss_profile,
+ .policy = nl80211_policy,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_family nl80211_fam __ro_after_init = {
@@ -1165,4 +1165,32 @@ static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev,
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
+
+static inline int
+rdev_set_link_loss_profile(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ enum nl80211_link_loss_profile profile,
+ const u8 *addr)
+{
+ int ret;
+
+ trace_rdev_set_link_loss_profile(&rdev->wiphy, wdev, profile, addr);
+ ret = rdev->ops->set_link_loss_profile(&rdev->wiphy, wdev, profile,
+ addr);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
+static inline enum nl80211_link_loss_profile
+rdev_get_link_loss_profile(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ const u8 *addr)
+{
+ enum nl80211_link_loss_profile profile;
+
+ trace_rdev_get_link_loss_profile(&rdev->wiphy, wdev, addr);
+ profile = rdev->ops->get_link_loss_profile(&rdev->wiphy, wdev, addr);
+ trace_rdev_return_int(&rdev->wiphy, profile);
+ return profile;
+}
#endif /* __CFG80211_RDEV_OPS */
@@ -2252,6 +2252,45 @@
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(addr))
);
+TRACE_EVENT(rdev_set_link_loss_profile,
+ TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+ enum nl80211_link_loss_profile profile, const u8 *addr),
+ TP_ARGS(wiphy, wdev, profile, addr),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ WDEV_ENTRY
+ __field(enum nl80211_link_loss_profile, profile)
+ MAC_ENTRY(addr)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ WDEV_ASSIGN;
+ __entry->profile = profile;
+ MAC_ASSIGN(addr, addr);
+ ),
+ TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " MAC_PR_FMT ", PROFILE %d",
+ WIPHY_PR_ARG, WDEV_PR_ARG, MAC_PR_ARG(addr),
+ __entry->profile)
+);
+
+TRACE_EVENT(rdev_get_link_loss_profile,
+ TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const u8 *addr),
+ TP_ARGS(wiphy, wdev, addr),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ WDEV_ENTRY
+ MAC_ENTRY(addr)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ WDEV_ASSIGN;
+ MAC_ASSIGN(addr, addr);
+ ),
+ TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " MAC_PR_FMT, WIPHY_PR_ARG,
+ WDEV_PR_ARG, MAC_PR_ARG(addr))
+);
+
/*************************************************************
* cfg80211 exported functions traces *
*************************************************************/