|
@@ -391,6 +391,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
|
[NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
|
|
[NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
|
|
[NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
|
|
[NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
|
|
[NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
|
|
[NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
|
|
|
|
+ [NL80211_ATTR_TSID] = { .type = NLA_U8 },
|
|
|
|
+ [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 },
|
|
|
|
+ [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
|
|
};
|
|
};
|
|
|
|
|
|
/* policy for the key attributes */
|
|
/* policy for the key attributes */
|
|
@@ -1510,6 +1513,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|
if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
|
|
if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
|
|
CMD(channel_switch, CHANNEL_SWITCH);
|
|
CMD(channel_switch, CHANNEL_SWITCH);
|
|
CMD(set_qos_map, SET_QOS_MAP);
|
|
CMD(set_qos_map, SET_QOS_MAP);
|
|
|
|
+ if (rdev->wiphy.flags &
|
|
|
|
+ WIPHY_FLAG_SUPPORTS_WMM_ADMISSION)
|
|
|
|
+ CMD(add_tx_ts, ADD_TX_TS);
|
|
}
|
|
}
|
|
/* add into the if now */
|
|
/* add into the if now */
|
|
#undef CMD
|
|
#undef CMD
|
|
@@ -9390,6 +9396,93 @@ static int nl80211_set_qos_map(struct sk_buff *skb,
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
+{
|
|
|
|
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
|
|
+ struct net_device *dev = info->user_ptr[1];
|
|
|
|
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
+ const u8 *peer;
|
|
|
|
+ u8 tsid, up;
|
|
|
|
+ u16 admitted_time = 0;
|
|
|
|
+ int err;
|
|
|
|
+
|
|
|
|
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION))
|
|
|
|
+ return -EOPNOTSUPP;
|
|
|
|
+
|
|
|
|
+ if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
|
|
|
|
+ !info->attrs[NL80211_ATTR_USER_PRIO])
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
|
|
|
|
+ if (tsid >= IEEE80211_NUM_TIDS)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]);
|
|
|
|
+ if (up >= IEEE80211_NUM_UPS)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ /* WMM uses TIDs 0-7 even for TSPEC */
|
|
|
|
+ if (tsid < IEEE80211_FIRST_TSPEC_TSID) {
|
|
|
|
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ } else {
|
|
|
|
+ /* TODO: handle 802.11 TSPEC/admission control
|
|
|
|
+ * need more attributes for that (e.g. BA session requirement)
|
|
|
|
+ */
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
|
|
|
+
|
|
|
|
+ if (info->attrs[NL80211_ATTR_ADMITTED_TIME]) {
|
|
|
|
+ admitted_time =
|
|
|
|
+ nla_get_u16(info->attrs[NL80211_ATTR_ADMITTED_TIME]);
|
|
|
|
+ if (!admitted_time)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ wdev_lock(wdev);
|
|
|
|
+ switch (wdev->iftype) {
|
|
|
|
+ case NL80211_IFTYPE_STATION:
|
|
|
|
+ case NL80211_IFTYPE_P2P_CLIENT:
|
|
|
|
+ if (wdev->current_bss)
|
|
|
|
+ break;
|
|
|
|
+ err = -ENOTCONN;
|
|
|
|
+ goto out;
|
|
|
|
+ default:
|
|
|
|
+ err = -EOPNOTSUPP;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ err = rdev_add_tx_ts(rdev, dev, tsid, peer, up, admitted_time);
|
|
|
|
+
|
|
|
|
+ out:
|
|
|
|
+ wdev_unlock(wdev);
|
|
|
|
+ return err;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
+{
|
|
|
|
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
|
|
+ struct net_device *dev = info->user_ptr[1];
|
|
|
|
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
+ const u8 *peer;
|
|
|
|
+ u8 tsid;
|
|
|
|
+ int err;
|
|
|
|
+
|
|
|
|
+ if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC])
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
|
|
|
|
+ peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
|
|
|
+
|
|
|
|
+ wdev_lock(wdev);
|
|
|
|
+ err = rdev_del_tx_ts(rdev, dev, tsid, peer);
|
|
|
|
+ wdev_unlock(wdev);
|
|
|
|
+
|
|
|
|
+ return err;
|
|
|
|
+}
|
|
|
|
+
|
|
#define NL80211_FLAG_NEED_WIPHY 0x01
|
|
#define NL80211_FLAG_NEED_WIPHY 0x01
|
|
#define NL80211_FLAG_NEED_NETDEV 0x02
|
|
#define NL80211_FLAG_NEED_NETDEV 0x02
|
|
#define NL80211_FLAG_NEED_RTNL 0x04
|
|
#define NL80211_FLAG_NEED_RTNL 0x04
|
|
@@ -10147,6 +10240,22 @@ static const struct genl_ops nl80211_ops[] = {
|
|
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
|
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
|
NL80211_FLAG_NEED_RTNL,
|
|
NL80211_FLAG_NEED_RTNL,
|
|
},
|
|
},
|
|
|
|
+ {
|
|
|
|
+ .cmd = NL80211_CMD_ADD_TX_TS,
|
|
|
|
+ .doit = nl80211_add_tx_ts,
|
|
|
|
+ .policy = nl80211_policy,
|
|
|
|
+ .flags = GENL_ADMIN_PERM,
|
|
|
|
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
|
|
|
+ NL80211_FLAG_NEED_RTNL,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ .cmd = NL80211_CMD_DEL_TX_TS,
|
|
|
|
+ .doit = nl80211_del_tx_ts,
|
|
|
|
+ .policy = nl80211_policy,
|
|
|
|
+ .flags = GENL_ADMIN_PERM,
|
|
|
|
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
|
|
|
+ NL80211_FLAG_NEED_RTNL,
|
|
|
|
+ },
|
|
};
|
|
};
|
|
|
|
|
|
/* notification functions */
|
|
/* notification functions */
|