]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/wireless/nl80211.c
cfg80211: add WMM traffic stream API
[mirror_ubuntu-bionic-kernel.git] / net / wireless / nl80211.c
index e9fbd4f4ddb0fcff1e56db4c1394002bf73f82ec..ab7ee4893e40a3c386834c7ae5a5f371be22005b 100644 (file)
@@ -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_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
        [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 */
@@ -1510,6 +1513,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                        if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
                                CMD(channel_switch, CHANNEL_SWITCH);
                        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 */
 #undef CMD
@@ -9390,6 +9396,93 @@ static int nl80211_set_qos_map(struct sk_buff *skb,
        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_NETDEV       0x02
 #define NL80211_FLAG_NEED_RTNL         0x04
@@ -10147,6 +10240,22 @@ static const struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  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 */