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
166 166
167#define IEEE80211_MAX_MESH_ID_LEN 32167#define IEEE80211_MAX_MESH_ID_LEN 32
168 168
169#define IEEE80211_FIRST_TSPEC_TSID 8
169#define IEEE80211_NUM_TIDS 16170#define IEEE80211_NUM_TIDS 16
170 171
172/* number of user priorities 802.11 uses */
173#define IEEE80211_NUM_UPS 8
174
171#define IEEE80211_QOS_CTL_LEN 2175#define IEEE80211_QOS_CTL_LEN 2
172/* 1d tag mask */176/* 1d tag mask */
173#define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007177#define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007
include/net/cfg80211.h+22−1
@@ -2318,6 +2318,17 @@ struct cfg80211_qos_map { · 2317 unmodified lines
2318 * @set_ap_chanwidth: Set the AP (including P2P GO) mode channel width for the2318 * @set_ap_chanwidth: Set the AP (including P2P GO) mode channel width for the
2319 * given interface This is used e.g. for dynamic HT 20/40 MHz channel width2319 * given interface This is used e.g. for dynamic HT 20/40 MHz channel width
2320 * changes during the lifetime of the BSS.2320 * 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
2321 */2332 */
2322struct cfg80211_ops {2333struct cfg80211_ops {
2323 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);2334 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2558,6 +2569,12 @@ struct cfg80211_ops { · 234 unmodified lines
2558 2569
2559 int (*set_ap_chanwidth)(struct wiphy *wiphy, struct net_device *dev,2570 int (*set_ap_chanwidth)(struct wiphy *wiphy, struct net_device *dev,
2560 struct cfg80211_chan_def *chandef);2571 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);
2561};2578};
2562 2579
2563/*2580/*
@@ -2604,9 +2621,13 @@ struct cfg80211_ops { · 40 unmodified lines
2604 * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels.2621 * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels.
2605 * @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in2622 * @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in
2606 * beaconing mode (AP, IBSS, Mesh, ...).2623 * 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.
2607 */2628 */
2608enum wiphy_flags {2629enum wiphy_flags {
2609 /* use hole at 0 */2630 WIPHY_FLAG_SUPPORTS_WMM_ADMISSION = BIT(0),
2610 /* use hole at 1 */2631 /* use hole at 1 */
2611 /* use hole at 2 */2632 /* use hole at 2 */
2612 WIPHY_FLAG_NETNS_OK = BIT(3),2633 WIPHY_FLAG_NETNS_OK = BIT(3),
include/uapi/linux/nl80211.h+28−0
@@ -722,6 +722,22 @@ · 721 unmodified lines
722 * QoS mapping is relevant for IP packets, it is only valid during an722 * QoS mapping is relevant for IP packets, it is only valid during an
723 * association. This is cleared on disassociation and AP restart.723 * association. This is cleared on disassociation and AP restart.
724 *724 *
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 *
725 * @NL80211_CMD_MAX: highest used command number741 * @NL80211_CMD_MAX: highest used command number
726 * @__NL80211_CMD_AFTER_LAST: internal use742 * @__NL80211_CMD_AFTER_LAST: internal use
727 */743 */
@@ -893,6 +909,9 @@ enum nl80211_commands { · 165 unmodified lines
893 909
894 NL80211_CMD_SET_QOS_MAP,910 NL80211_CMD_SET_QOS_MAP,
895 911
912 NL80211_CMD_ADD_TX_TS,
913 NL80211_CMD_DEL_TX_TS,
914
896 /* add new commands above here */915 /* add new commands above here */
897 916
898 /* used to define NL80211_CMD_MAX below */917 /* used to define NL80211_CMD_MAX below */
@@ -1611,6 +1630,11 @@ enum nl80211_commands { · 712 unmodified lines
1611 * drivers to indicate dynack capability. Dynack is automatically disabled1630 * drivers to indicate dynack capability. Dynack is automatically disabled
1612 * setting valid value for coverage class.1631 * setting valid value for coverage class.
1613 *1632 *
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 *
1614 * @NL80211_ATTR_MAX: highest attribute number currently defined1638 * @NL80211_ATTR_MAX: highest attribute number currently defined
1615 * @__NL80211_ATTR_AFTER_LAST: internal use1639 * @__NL80211_ATTR_AFTER_LAST: internal use
1616 */1640 */
@@ -1957,6 +1981,10 @@ enum nl80211_attrs { · 340 unmodified lines
1957 1981
1958 NL80211_ATTR_WIPHY_DYN_ACK,1982 NL80211_ATTR_WIPHY_DYN_ACK,
1959 1983
1984 NL80211_ATTR_TSID,
1985 NL80211_ATTR_USER_PRIO,
1986 NL80211_ATTR_ADMITTED_TIME,
1987
1960 /* add attributes here, update the policy in nl80211.c */1988 /* add attributes here, update the policy in nl80211.c */
1961 1989
1962 __NL80211_ATTR_AFTER_LAST,1990 __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
391 [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },391 [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
392 [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },392 [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
393 [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },393 [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 },
394};397};
395 398
396/* policy for the key attributes */399/* policy for the key attributes */
@@ -1510,6 +1513,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, · 1113 unmodified lines
1510 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)1513 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
1511 CMD(channel_switch, CHANNEL_SWITCH);1514 CMD(channel_switch, CHANNEL_SWITCH);
1512 CMD(set_qos_map, SET_QOS_MAP);1515 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);
1513 }1519 }
1514 /* add into the if now */1520 /* add into the if now */
1515#undef CMD1521#undef CMD
@@ -9390,6 +9396,93 @@ static int nl80211_set_qos_map(struct sk_buff *skb, · 7874 unmodified lines
9390 return ret;9396 return ret;
9391}9397}
9392 9398
9399static 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
9464static 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
9393#define NL80211_FLAG_NEED_WIPHY 0x019486#define NL80211_FLAG_NEED_WIPHY 0x01
9394#define NL80211_FLAG_NEED_NETDEV 0x029487#define NL80211_FLAG_NEED_NETDEV 0x02
9395#define NL80211_FLAG_NEED_RTNL 0x049488#define NL80211_FLAG_NEED_RTNL 0x04
@@ -10147,6 +10240,22 @@ static const struct genl_ops nl80211_ops[] = { · 751 unmodified lines
10147 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |10240 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
10148 NL80211_FLAG_NEED_RTNL,10241 NL80211_FLAG_NEED_RTNL,
10149 },10242 },
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 },
10150};10259};
10151 10260
10152/* notification functions */10261/* 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
915 return ret;915 return ret;
916}916}
917 917
918static inline int
919rdev_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
935static inline int
936rdev_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
918#endif /* __CFG80211_RDEV_OPS */949#endif /* __CFG80211_RDEV_OPS */
net/wireless/trace.h+45−0
@@ -1896,6 +1896,51 @@ TRACE_EVENT(rdev_set_ap_chanwidth, · 1895 unmodified lines
1896 WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG)1896 WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG)
1897);1897);
1898 1898
1899TRACE_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
1924TRACE_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
1899/*************************************************************1944/*************************************************************
1900 * cfg80211 exported functions traces *1945 * cfg80211 exported functions traces *
1901 *************************************************************/1946 *************************************************************/