History

cfg80211: add WMM traffic stream API

Add nl80211 and driver API to validate, add and delete traffic streams with appropriate settings. The API calls for userspace doing the action frame handshake with the peer, and then allows only to set up the parameters in the driver. To avoid setting up a session only to tear it down again, the validate API is provided, but the real usage later can still fail so userspace must be prepared for that.

Johannes Berg committed 12 years ago

Commit 960d01a1 parent 9d58f256 files · +239 −1Browse files

Unified · Split

6 files
  1. include/linux/ieee80211.h +4 −0
  2. include/net/cfg80211.h +22 −1
  3. include/uapi/linux/nl80211.h +28 −0
  4. net/wireless/nl80211.c +109 −0
  5. net/wireless/rdev-ops.h +31 −0
  6. net/wireless/trace.h +45 −0
include/linux/ieee80211.h+4−0
@@ -166,8 +166,12 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) · 165 unmodified lines
166166
167167 #define IEEE80211_MAX_MESH_ID_LEN 32
168168
169+#define IEEE80211_FIRST_TSPEC_TSID 8
169170 #define IEEE80211_NUM_TIDS 16
170171
172+/* number of user priorities 802.11 uses */
173+#define IEEE80211_NUM_UPS 8
174+
171175 #define IEEE80211_QOS_CTL_LEN 2
172176 /* 1d tag mask */
173177 #define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007
include/net/cfg80211.h+22−1
@@ -2318,6 +2318,17 @@ struct cfg80211_qos_map { · 2317 unmodified lines
23182318 * @set_ap_chanwidth: Set the AP (including P2P GO) mode channel width for the
23192319 * given interface This is used e.g. for dynamic HT 20/40 MHz channel width
23202320 * changes during the lifetime of the BSS.
2321+ *
2322+ * @add_tx_ts: validate (if admitted_time is 0) or add a TX TS to the device
2323+ * with the given parameters; action frame exchange has been handled by
2324+ * userspace so this just has to modify the TX path to take the TS into
2325+ * account.
2326+ * If the admitted time is 0 just validate the parameters to make sure
2327+ * the session can be created at all; it is valid to just always return
2328+ * success for that but that may result in inefficient behaviour (handshake
2329+ * with the peer followed by immediate teardown when the addition is later
2330+ * rejected)
2331+ * @del_tx_ts: remove an existing TX TS
23212332 */
23222333 struct cfg80211_ops {
23232334 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2558,6 +2569,12 @@ struct cfg80211_ops { · 234 unmodified lines
25582569
25592570 int (*set_ap_chanwidth)(struct wiphy *wiphy, struct net_device *dev,
25602571 struct cfg80211_chan_def *chandef);
2572+
2573+ int (*add_tx_ts)(struct wiphy *wiphy, struct net_device *dev,
2574+ u8 tsid, const u8 *peer, u8 user_prio,
2575+ u16 admitted_time);
2576+ int (*del_tx_ts)(struct wiphy *wiphy, struct net_device *dev,
2577+ u8 tsid, const u8 *peer);
25612578 };
25622579
25632580 /*
@@ -2604,9 +2621,13 @@ struct cfg80211_ops { · 40 unmodified lines
26042621 * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels.
26052622 * @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in
26062623 * beaconing mode (AP, IBSS, Mesh, ...).
2624+ * @WIPHY_FLAG_SUPPORTS_WMM_ADMISSION: the device supports setting up WMM
2625+ * TSPEC sessions (TID aka TSID 0-7) with the NL80211_CMD_ADD_TX_TS
2626+ * command. Standard IEEE 802.11 TSPEC setup is not yet supported, it
2627+ * needs to be able to handle Block-Ack agreements and other things.
26072628 */
26082629 enum wiphy_flags {
2609− /* use hole at 0 */
2630+ WIPHY_FLAG_SUPPORTS_WMM_ADMISSION = BIT(0),
26102631 /* use hole at 1 */
26112632 /* use hole at 2 */
26122633 WIPHY_FLAG_NETNS_OK = BIT(3),
include/uapi/linux/nl80211.h+28−0
@@ -722,6 +722,22 @@ · 721 unmodified lines
722722 * QoS mapping is relevant for IP packets, it is only valid during an
723723 * association. This is cleared on disassociation and AP restart.
724724 *
725+ * @NL80211_CMD_ADD_TX_TS: Ask the kernel to add a traffic stream for the given
726+ * %NL80211_ATTR_TSID and %NL80211_ATTR_MAC with %NL80211_ATTR_USER_PRIO
727+ * and %NL80211_ATTR_ADMITTED_TIME parameters.
728+ * Note that the action frame handshake with the AP shall be handled by
729+ * userspace via the normal management RX/TX framework, this only sets
730+ * up the TX TS in the driver/device.
731+ * If the admitted time attribute is not added then the request just checks
732+ * if a subsequent setup could be successful, the intent is to use this to
733+ * avoid setting up a session with the AP when local restrictions would
734+ * make that impossible. However, the subsequent "real" setup may still
735+ * fail even if the check was successful.
736+ * @NL80211_CMD_DEL_TX_TS: Remove an existing TS with the %NL80211_ATTR_TSID
737+ * and %NL80211_ATTR_MAC parameters. It isn't necessary to call this
738+ * before removing a station entry entirely, or before disassociating
739+ * or similar, cleanup will happen in the driver/device in this case.
740+ *
725741 * @NL80211_CMD_MAX: highest used command number
726742 * @__NL80211_CMD_AFTER_LAST: internal use
727743 */
@@ -893,6 +909,9 @@ enum nl80211_commands { · 165 unmodified lines
893909
894910 NL80211_CMD_SET_QOS_MAP,
895911
912+ NL80211_CMD_ADD_TX_TS,
913+ NL80211_CMD_DEL_TX_TS,
914+
896915 /* add new commands above here */
897916
898917 /* used to define NL80211_CMD_MAX below */
@@ -1611,6 +1630,11 @@ enum nl80211_commands { · 712 unmodified lines
16111630 * drivers to indicate dynack capability. Dynack is automatically disabled
16121631 * setting valid value for coverage class.
16131632 *
1633+ * @NL80211_ATTR_TSID: a TSID value (u8 attribute)
1634+ * @NL80211_ATTR_USER_PRIO: user priority value (u8 attribute)
1635+ * @NL80211_ATTR_ADMITTED_TIME: admitted time in units of 32 microseconds
1636+ * (per second) (u16 attribute)
1637+ *
16141638 * @NL80211_ATTR_MAX: highest attribute number currently defined
16151639 * @__NL80211_ATTR_AFTER_LAST: internal use
16161640 */
@@ -1957,6 +1981,10 @@ enum nl80211_attrs { · 340 unmodified lines
19571981
19581982 NL80211_ATTR_WIPHY_DYN_ACK,
19591983
1984+ NL80211_ATTR_TSID,
1985+ NL80211_ATTR_USER_PRIO,
1986+ NL80211_ATTR_ADMITTED_TIME,
1987+
19601988 /* add attributes here, update the policy in nl80211.c */
19611989
19621990 __NL80211_ATTR_AFTER_LAST,
net/wireless/nl80211.c+109−0
@@ -391,6 +391,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { · 390 unmodified lines
391391 [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
392392 [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
393393 [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
394+ [NL80211_ATTR_TSID] = { .type = NLA_U8 },
395+ [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 },
396+ [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
394397 };
395398
396399 /* policy for the key attributes */
@@ -1510,6 +1513,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, · 1113 unmodified lines
15101513 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
15111514 CMD(channel_switch, CHANNEL_SWITCH);
15121515 CMD(set_qos_map, SET_QOS_MAP);
1516+ if (rdev->wiphy.flags &
1517+ WIPHY_FLAG_SUPPORTS_WMM_ADMISSION)
1518+ CMD(add_tx_ts, ADD_TX_TS);
15131519 }
15141520 /* add into the if now */
15151521 #undef CMD
@@ -9390,6 +9396,93 @@ static int nl80211_set_qos_map(struct sk_buff *skb, · 7874 unmodified lines
93909396 return ret;
93919397 }
93929398
9399+static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
9400+{
9401+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
9402+ struct net_device *dev = info->user_ptr[1];
9403+ struct wireless_dev *wdev = dev->ieee80211_ptr;
9404+ const u8 *peer;
9405+ u8 tsid, up;
9406+ u16 admitted_time = 0;
9407+ int err;
9408+
9409+ if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION))
9410+ return -EOPNOTSUPP;
9411+
9412+ if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
9413+ !info->attrs[NL80211_ATTR_USER_PRIO])
9414+ return -EINVAL;
9415+
9416+ tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
9417+ if (tsid >= IEEE80211_NUM_TIDS)
9418+ return -EINVAL;
9419+
9420+ up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]);
9421+ if (up >= IEEE80211_NUM_UPS)
9422+ return -EINVAL;
9423+
9424+ /* WMM uses TIDs 0-7 even for TSPEC */
9425+ if (tsid < IEEE80211_FIRST_TSPEC_TSID) {
9426+ if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION))
9427+ return -EINVAL;
9428+ } else {
9429+ /* TODO: handle 802.11 TSPEC/admission control
9430+ * need more attributes for that (e.g. BA session requirement)
9431+ */
9432+ return -EINVAL;
9433+ }
9434+
9435+ peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9436+
9437+ if (info->attrs[NL80211_ATTR_ADMITTED_TIME]) {
9438+ admitted_time =
9439+ nla_get_u16(info->attrs[NL80211_ATTR_ADMITTED_TIME]);
9440+ if (!admitted_time)
9441+ return -EINVAL;
9442+ }
9443+
9444+ wdev_lock(wdev);
9445+ switch (wdev->iftype) {
9446+ case NL80211_IFTYPE_STATION:
9447+ case NL80211_IFTYPE_P2P_CLIENT:
9448+ if (wdev->current_bss)
9449+ break;
9450+ err = -ENOTCONN;
9451+ goto out;
9452+ default:
9453+ err = -EOPNOTSUPP;
9454+ goto out;
9455+ }
9456+
9457+ err = rdev_add_tx_ts(rdev, dev, tsid, peer, up, admitted_time);
9458+
9459+ out:
9460+ wdev_unlock(wdev);
9461+ return err;
9462+}
9463+
9464+static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info)
9465+{
9466+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
9467+ struct net_device *dev = info->user_ptr[1];
9468+ struct wireless_dev *wdev = dev->ieee80211_ptr;
9469+ const u8 *peer;
9470+ u8 tsid;
9471+ int err;
9472+
9473+ if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC])
9474+ return -EINVAL;
9475+
9476+ tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
9477+ peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9478+
9479+ wdev_lock(wdev);
9480+ err = rdev_del_tx_ts(rdev, dev, tsid, peer);
9481+ wdev_unlock(wdev);
9482+
9483+ return err;
9484+}
9485+
93939486 #define NL80211_FLAG_NEED_WIPHY 0x01
93949487 #define NL80211_FLAG_NEED_NETDEV 0x02
93959488 #define NL80211_FLAG_NEED_RTNL 0x04
@@ -10147,6 +10240,22 @@ static const struct genl_ops nl80211_ops[] = { · 751 unmodified lines
1014710240 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
1014810241 NL80211_FLAG_NEED_RTNL,
1014910242 },
10243+ {
10244+ .cmd = NL80211_CMD_ADD_TX_TS,
10245+ .doit = nl80211_add_tx_ts,
10246+ .policy = nl80211_policy,
10247+ .flags = GENL_ADMIN_PERM,
10248+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
10249+ NL80211_FLAG_NEED_RTNL,
10250+ },
10251+ {
10252+ .cmd = NL80211_CMD_DEL_TX_TS,
10253+ .doit = nl80211_del_tx_ts,
10254+ .policy = nl80211_policy,
10255+ .flags = GENL_ADMIN_PERM,
10256+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
10257+ NL80211_FLAG_NEED_RTNL,
10258+ },
1015010259 };
1015110260
1015210261 /* notification functions */
net/wireless/rdev-ops.h+31−0
@@ -915,4 +915,35 @@ rdev_set_ap_chanwidth(struct cfg80211_registered_device *rdev, · 914 unmodified lines
915915 return ret;
916916 }
917917
918+static inline int
919+rdev_add_tx_ts(struct cfg80211_registered_device *rdev,
920+ struct net_device *dev, u8 tsid, const u8 *peer,
921+ u8 user_prio, u16 admitted_time)
922+{
923+ int ret = -EOPNOTSUPP;
924+
925+ trace_rdev_add_tx_ts(&rdev->wiphy, dev, tsid, peer,
926+ user_prio, admitted_time);
927+ if (rdev->ops->add_tx_ts)
928+ ret = rdev->ops->add_tx_ts(&rdev->wiphy, dev, tsid, peer,
929+ user_prio, admitted_time);
930+ trace_rdev_return_int(&rdev->wiphy, ret);
931+
932+ return ret;
933+}
934+
935+static inline int
936+rdev_del_tx_ts(struct cfg80211_registered_device *rdev,
937+ struct net_device *dev, u8 tsid, const u8 *peer)
938+{
939+ int ret = -EOPNOTSUPP;
940+
941+ trace_rdev_del_tx_ts(&rdev->wiphy, dev, tsid, peer);
942+ if (rdev->ops->del_tx_ts)
943+ ret = rdev->ops->del_tx_ts(&rdev->wiphy, dev, tsid, peer);
944+ trace_rdev_return_int(&rdev->wiphy, ret);
945+
946+ return ret;
947+}
948+
918949 #endif /* __CFG80211_RDEV_OPS */
net/wireless/trace.h+45−0
@@ -1896,6 +1896,51 @@ TRACE_EVENT(rdev_set_ap_chanwidth, · 1895 unmodified lines
18961896 WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG)
18971897 );
18981898
1899+TRACE_EVENT(rdev_add_tx_ts,
1900+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
1901+ u8 tsid, const u8 *peer, u8 user_prio, u16 admitted_time),
1902+ TP_ARGS(wiphy, netdev, tsid, peer, user_prio, admitted_time),
1903+ TP_STRUCT__entry(
1904+ WIPHY_ENTRY
1905+ NETDEV_ENTRY
1906+ MAC_ENTRY(peer)
1907+ __field(u8, tsid)
1908+ __field(u8, user_prio)
1909+ __field(u16, admitted_time)
1910+ ),
1911+ TP_fast_assign(
1912+ WIPHY_ASSIGN;
1913+ NETDEV_ASSIGN;
1914+ MAC_ASSIGN(peer, peer);
1915+ __entry->tsid = tsid;
1916+ __entry->user_prio = user_prio;
1917+ __entry->admitted_time = admitted_time;
1918+ ),
1919+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", TSID %d, UP %d, time %d",
1920+ WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer),
1921+ __entry->tsid, __entry->user_prio, __entry->admitted_time)
1922+);
1923+
1924+TRACE_EVENT(rdev_del_tx_ts,
1925+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
1926+ u8 tsid, const u8 *peer),
1927+ TP_ARGS(wiphy, netdev, tsid, peer),
1928+ TP_STRUCT__entry(
1929+ WIPHY_ENTRY
1930+ NETDEV_ENTRY
1931+ MAC_ENTRY(peer)
1932+ __field(u8, tsid)
1933+ ),
1934+ TP_fast_assign(
1935+ WIPHY_ASSIGN;
1936+ NETDEV_ASSIGN;
1937+ MAC_ASSIGN(peer, peer);
1938+ __entry->tsid = tsid;
1939+ ),
1940+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", TSID %d",
1941+ WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tsid)
1942+);
1943+
18991944 /*************************************************************
19001945 * cfg80211 exported functions traces *
19011946 *************************************************************/