aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h54
-rw-r--r--include/uapi/linux/nl80211.h90
-rw-r--r--net/wireless/core.c9
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/nl80211.c308
-rw-r--r--net/wireless/nl80211.h2
6 files changed, 463 insertions, 2 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 49409602fe3d..071ed2395c9a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1781,6 +1781,35 @@ struct cfg80211_wowlan {
1781}; 1781};
1782 1782
1783/** 1783/**
1784 * struct cfg80211_coalesce_rules - Coalesce rule parameters
1785 *
1786 * This structure defines coalesce rule for the device.
1787 * @delay: maximum coalescing delay in msecs.
1788 * @condition: condition for packet coalescence.
1789 * see &enum nl80211_coalesce_condition.
1790 * @patterns: array of packet patterns
1791 * @n_patterns: number of patterns
1792 */
1793struct cfg80211_coalesce_rules {
1794 int delay;
1795 enum nl80211_coalesce_condition condition;
1796 struct cfg80211_pkt_pattern *patterns;
1797 int n_patterns;
1798};
1799
1800/**
1801 * struct cfg80211_coalesce - Packet coalescing settings
1802 *
1803 * This structure defines coalescing settings.
1804 * @rules: array of coalesce rules
1805 * @n_rules: number of rules
1806 */
1807struct cfg80211_coalesce {
1808 struct cfg80211_coalesce_rules *rules;
1809 int n_rules;
1810};
1811
1812/**
1784 * struct cfg80211_wowlan_wakeup - wakeup report 1813 * struct cfg80211_wowlan_wakeup - wakeup report
1785 * @disconnect: woke up by getting disconnected 1814 * @disconnect: woke up by getting disconnected
1786 * @magic_pkt: woke up by receiving magic packet 1815 * @magic_pkt: woke up by receiving magic packet
@@ -2076,6 +2105,7 @@ struct cfg80211_update_ft_ies_params {
2076 * driver can take the most appropriate actions. 2105 * driver can take the most appropriate actions.
2077 * @crit_proto_stop: Indicates critical protocol no longer needs increased link 2106 * @crit_proto_stop: Indicates critical protocol no longer needs increased link
2078 * reliability. This operation can not fail. 2107 * reliability. This operation can not fail.
2108 * @set_coalesce: Set coalesce parameters.
2079 */ 2109 */
2080struct cfg80211_ops { 2110struct cfg80211_ops {
2081 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); 2111 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2311,6 +2341,8 @@ struct cfg80211_ops {
2311 u16 duration); 2341 u16 duration);
2312 void (*crit_proto_stop)(struct wiphy *wiphy, 2342 void (*crit_proto_stop)(struct wiphy *wiphy,
2313 struct wireless_dev *wdev); 2343 struct wireless_dev *wdev);
2344 int (*set_coalesce)(struct wiphy *wiphy,
2345 struct cfg80211_coalesce *coalesce);
2314}; 2346};
2315 2347
2316/* 2348/*
@@ -2537,6 +2569,25 @@ struct wiphy_wowlan_support {
2537}; 2569};
2538 2570
2539/** 2571/**
2572 * struct wiphy_coalesce_support - coalesce support data
2573 * @n_rules: maximum number of coalesce rules
2574 * @max_delay: maximum supported coalescing delay in msecs
2575 * @n_patterns: number of supported patterns in a rule
2576 * (see nl80211.h for the pattern definition)
2577 * @pattern_max_len: maximum length of each pattern
2578 * @pattern_min_len: minimum length of each pattern
2579 * @max_pkt_offset: maximum Rx packet offset
2580 */
2581struct wiphy_coalesce_support {
2582 int n_rules;
2583 int max_delay;
2584 int n_patterns;
2585 int pattern_max_len;
2586 int pattern_min_len;
2587 int max_pkt_offset;
2588};
2589
2590/**
2540 * struct wiphy - wireless hardware description 2591 * struct wiphy - wireless hardware description
2541 * @reg_notifier: the driver's regulatory notification callback, 2592 * @reg_notifier: the driver's regulatory notification callback,
2542 * note that if your driver uses wiphy_apply_custom_regulatory() 2593 * note that if your driver uses wiphy_apply_custom_regulatory()
@@ -2646,6 +2697,7 @@ struct wiphy_wowlan_support {
2646 * 802.11-2012 8.4.2.29 for the defined fields. 2697 * 802.11-2012 8.4.2.29 for the defined fields.
2647 * @extended_capabilities_mask: mask of the valid values 2698 * @extended_capabilities_mask: mask of the valid values
2648 * @extended_capabilities_len: length of the extended capabilities 2699 * @extended_capabilities_len: length of the extended capabilities
2700 * @coalesce: packet coalescing support information
2649 */ 2701 */
2650struct wiphy { 2702struct wiphy {
2651 /* assign these fields before you register the wiphy */ 2703 /* assign these fields before you register the wiphy */
@@ -2755,6 +2807,8 @@ struct wiphy {
2755 const struct iw_handler_def *wext; 2807 const struct iw_handler_def *wext;
2756#endif 2808#endif
2757 2809
2810 const struct wiphy_coalesce_support *coalesce;
2811
2758 char priv[0] __aligned(NETDEV_ALIGN); 2812 char priv[0] __aligned(NETDEV_ALIGN);
2759}; 2813};
2760 2814
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index de0ce809068a..5abc54d14d4d 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -126,6 +126,31 @@
126 */ 126 */
127 127
128/** 128/**
129 * DOC: packet coalesce support
130 *
131 * In most cases, host that receives IPv4 and IPv6 multicast/broadcast
132 * packets does not do anything with these packets. Therefore the
133 * reception of these unwanted packets causes unnecessary processing
134 * and power consumption.
135 *
136 * Packet coalesce feature helps to reduce number of received interrupts
137 * to host by buffering these packets in firmware/hardware for some
138 * predefined time. Received interrupt will be generated when one of the
139 * following events occur.
140 * a) Expiration of hardware timer whose expiration time is set to maximum
141 * coalescing delay of matching coalesce rule.
142 * b) Coalescing buffer in hardware reaches it's limit.
143 * c) Packet doesn't match any of the configured coalesce rules.
144 *
145 * User needs to configure following parameters for creating a coalesce
146 * rule.
147 * a) Maximum coalescing delay
148 * b) List of packet patterns which needs to be matched
149 * c) Condition for coalescence. pattern 'match' or 'no match'
150 * Multiple such rules can be created.
151 */
152
153/**
129 * enum nl80211_commands - supported nl80211 commands 154 * enum nl80211_commands - supported nl80211 commands
130 * 155 *
131 * @NL80211_CMD_UNSPEC: unspecified command to catch errors 156 * @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -648,6 +673,9 @@
648 * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can 673 * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can
649 * return back to normal. 674 * return back to normal.
650 * 675 *
676 * @NL80211_CMD_GET_COALESCE: Get currently supported coalesce rules.
677 * @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules.
678 *
651 * @NL80211_CMD_MAX: highest used command number 679 * @NL80211_CMD_MAX: highest used command number
652 * @__NL80211_CMD_AFTER_LAST: internal use 680 * @__NL80211_CMD_AFTER_LAST: internal use
653 */ 681 */
@@ -810,6 +838,9 @@ enum nl80211_commands {
810 NL80211_CMD_CRIT_PROTOCOL_START, 838 NL80211_CMD_CRIT_PROTOCOL_START,
811 NL80211_CMD_CRIT_PROTOCOL_STOP, 839 NL80211_CMD_CRIT_PROTOCOL_STOP,
812 840
841 NL80211_CMD_GET_COALESCE,
842 NL80211_CMD_SET_COALESCE,
843
813 /* add new commands above here */ 844 /* add new commands above here */
814 845
815 /* used to define NL80211_CMD_MAX below */ 846 /* used to define NL80211_CMD_MAX below */
@@ -1436,6 +1467,8 @@ enum nl80211_commands {
1436 * allowed to be used with the first @NL80211_CMD_SET_STATION command to 1467 * allowed to be used with the first @NL80211_CMD_SET_STATION command to
1437 * update a TDLS peer STA entry. 1468 * update a TDLS peer STA entry.
1438 * 1469 *
1470 * @NL80211_ATTR_COALESCE_RULE: Coalesce rule information.
1471 *
1439 * @NL80211_ATTR_MAX: highest attribute number currently defined 1472 * @NL80211_ATTR_MAX: highest attribute number currently defined
1440 * @__NL80211_ATTR_AFTER_LAST: internal use 1473 * @__NL80211_ATTR_AFTER_LAST: internal use
1441 */ 1474 */
@@ -1736,6 +1769,8 @@ enum nl80211_attrs {
1736 1769
1737 NL80211_ATTR_PEER_AID, 1770 NL80211_ATTR_PEER_AID,
1738 1771
1772 NL80211_ATTR_COALESCE_RULE,
1773
1739 /* add attributes here, update the policy in nl80211.c */ 1774 /* add attributes here, update the policy in nl80211.c */
1740 1775
1741 __NL80211_ATTR_AFTER_LAST, 1776 __NL80211_ATTR_AFTER_LAST,
@@ -3098,8 +3133,10 @@ enum nl80211_packet_pattern_attr {
3098 * @max_pkt_offset: maximum Rx packet offset 3133 * @max_pkt_offset: maximum Rx packet offset
3099 * 3134 *
3100 * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when 3135 * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
3101 * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the 3136 * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED or in
3102 * capability information given by the kernel to userspace. 3137 * %NL80211_ATTR_COALESCE_RULE_PKT_PATTERN when that is part of
3138 * %NL80211_ATTR_COALESCE_RULE in the capability information given
3139 * by the kernel to userspace.
3103 */ 3140 */
3104struct nl80211_pattern_support { 3141struct nl80211_pattern_support {
3105 __u32 max_patterns; 3142 __u32 max_patterns;
@@ -3318,6 +3355,55 @@ enum nl80211_wowlan_tcp_attrs {
3318}; 3355};
3319 3356
3320/** 3357/**
3358 * struct nl80211_coalesce_rule_support - coalesce rule support information
3359 * @max_rules: maximum number of rules supported
3360 * @pat: packet pattern support information
3361 * @max_delay: maximum supported coalescing delay in msecs
3362 *
3363 * This struct is carried in %NL80211_ATTR_COALESCE_RULE in the
3364 * capability information given by the kernel to userspace.
3365 */
3366struct nl80211_coalesce_rule_support {
3367 __u32 max_rules;
3368 struct nl80211_pattern_support pat;
3369 __u32 max_delay;
3370} __attribute__((packed));
3371
3372/**
3373 * enum nl80211_attr_coalesce_rule - coalesce rule attribute
3374 * @__NL80211_COALESCE_RULE_INVALID: invalid number for nested attribute
3375 * @NL80211_ATTR_COALESCE_RULE_DELAY: delay in msecs used for packet coalescing
3376 * @NL80211_ATTR_COALESCE_RULE_CONDITION: condition for packet coalescence,
3377 * see &enum nl80211_coalesce_condition.
3378 * @NL80211_ATTR_COALESCE_RULE_PKT_PATTERN: packet offset, pattern is matched
3379 * after these fixed number of bytes of received packet
3380 * @NUM_NL80211_ATTR_COALESCE_RULE: number of attributes
3381 * @NL80211_ATTR_COALESCE_RULE_MAX: max attribute number
3382 */
3383enum nl80211_attr_coalesce_rule {
3384 __NL80211_COALESCE_RULE_INVALID,
3385 NL80211_ATTR_COALESCE_RULE_DELAY,
3386 NL80211_ATTR_COALESCE_RULE_CONDITION,
3387 NL80211_ATTR_COALESCE_RULE_PKT_PATTERN,
3388
3389 /* keep last */
3390 NUM_NL80211_ATTR_COALESCE_RULE,
3391 NL80211_ATTR_COALESCE_RULE_MAX = NUM_NL80211_ATTR_COALESCE_RULE - 1
3392};
3393
3394/**
3395 * enum nl80211_coalesce_condition - coalesce rule conditions
3396 * @NL80211_COALESCE_CONDITION_MATCH: coalaesce Rx packets when patterns
3397 * in a rule are matched.
3398 * @NL80211_COALESCE_CONDITION_NO_MATCH: coalesce Rx packets when patterns
3399 * in a rule are not matched.
3400 */
3401enum nl80211_coalesce_condition {
3402 NL80211_COALESCE_CONDITION_MATCH,
3403 NL80211_COALESCE_CONDITION_NO_MATCH
3404};
3405
3406/**
3321 * enum nl80211_iface_limit_attrs - limit attributes 3407 * enum nl80211_iface_limit_attrs - limit attributes
3322 * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) 3408 * @NL80211_IFACE_LIMIT_UNSPEC: (reserved)
3323 * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that 3409 * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 4f9f216665e9..389a3f2ee464 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -462,6 +462,14 @@ int wiphy_register(struct wiphy *wiphy)
462 return -EINVAL; 462 return -EINVAL;
463#endif 463#endif
464 464
465 if (WARN_ON(wiphy->coalesce &&
466 (!wiphy->coalesce->n_rules ||
467 !wiphy->coalesce->n_patterns) &&
468 (!wiphy->coalesce->pattern_min_len ||
469 wiphy->coalesce->pattern_min_len >
470 wiphy->coalesce->pattern_max_len)))
471 return -EINVAL;
472
465 if (WARN_ON(wiphy->ap_sme_capa && 473 if (WARN_ON(wiphy->ap_sme_capa &&
466 !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) 474 !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
467 return -EINVAL; 475 return -EINVAL;
@@ -668,6 +676,7 @@ void wiphy_unregister(struct wiphy *wiphy)
668 rdev_set_wakeup(rdev, false); 676 rdev_set_wakeup(rdev, false);
669#endif 677#endif
670 cfg80211_rdev_free_wowlan(rdev); 678 cfg80211_rdev_free_wowlan(rdev);
679 cfg80211_rdev_free_coalesce(rdev);
671} 680}
672EXPORT_SYMBOL(wiphy_unregister); 681EXPORT_SYMBOL(wiphy_unregister);
673 682
diff --git a/net/wireless/core.h b/net/wireless/core.h
index a6b45bf00f33..9ad43c619c54 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -79,6 +79,8 @@ struct cfg80211_registered_device {
79 /* netlink port which started critical protocol (0 means not started) */ 79 /* netlink port which started critical protocol (0 means not started) */
80 u32 crit_proto_nlportid; 80 u32 crit_proto_nlportid;
81 81
82 struct cfg80211_coalesce *coalesce;
83
82 /* must be last because of the way we do wiphy_priv(), 84 /* must be last because of the way we do wiphy_priv(),
83 * and it should at least be aligned to NETDEV_ALIGN */ 85 * and it should at least be aligned to NETDEV_ALIGN */
84 struct wiphy wiphy __aligned(NETDEV_ALIGN); 86 struct wiphy wiphy __aligned(NETDEV_ALIGN);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0492478ab74e..6dca5a700174 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -403,6 +403,14 @@ nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
403 [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 }, 403 [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 },
404}; 404};
405 405
406/* policy for coalesce rule attributes */
407static const struct nla_policy
408nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
409 [NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 },
410 [NL80211_ATTR_COALESCE_RULE_CONDITION] = { .type = NLA_U32 },
411 [NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED },
412};
413
406/* policy for GTK rekey offload attributes */ 414/* policy for GTK rekey offload attributes */
407static const struct nla_policy 415static const struct nla_policy
408nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { 416nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
@@ -995,6 +1003,27 @@ static int nl80211_send_wowlan(struct sk_buff *msg,
995} 1003}
996#endif 1004#endif
997 1005
1006static int nl80211_send_coalesce(struct sk_buff *msg,
1007 struct cfg80211_registered_device *dev)
1008{
1009 struct nl80211_coalesce_rule_support rule;
1010
1011 if (!dev->wiphy.coalesce)
1012 return 0;
1013
1014 rule.max_rules = dev->wiphy.coalesce->n_rules;
1015 rule.max_delay = dev->wiphy.coalesce->max_delay;
1016 rule.pat.max_patterns = dev->wiphy.coalesce->n_patterns;
1017 rule.pat.min_pattern_len = dev->wiphy.coalesce->pattern_min_len;
1018 rule.pat.max_pattern_len = dev->wiphy.coalesce->pattern_max_len;
1019 rule.pat.max_pkt_offset = dev->wiphy.coalesce->max_pkt_offset;
1020
1021 if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
1022 return -ENOBUFS;
1023
1024 return 0;
1025}
1026
998static int nl80211_send_band_rateinfo(struct sk_buff *msg, 1027static int nl80211_send_band_rateinfo(struct sk_buff *msg,
999 struct ieee80211_supported_band *sband) 1028 struct ieee80211_supported_band *sband)
1000{ 1029{
@@ -1513,6 +1542,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
1513 dev->wiphy.vht_capa_mod_mask)) 1542 dev->wiphy.vht_capa_mod_mask))
1514 goto nla_put_failure; 1543 goto nla_put_failure;
1515 1544
1545 state->split_start++;
1546 break;
1547 case 10:
1548 if (nl80211_send_coalesce(msg, dev))
1549 goto nla_put_failure;
1550
1516 /* done */ 1551 /* done */
1517 state->split_start = 0; 1552 state->split_start = 0;
1518 break; 1553 break;
@@ -8043,6 +8078,264 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
8043} 8078}
8044#endif 8079#endif
8045 8080
8081static int nl80211_send_coalesce_rules(struct sk_buff *msg,
8082 struct cfg80211_registered_device *rdev)
8083{
8084 struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules;
8085 int i, j, pat_len;
8086 struct cfg80211_coalesce_rules *rule;
8087
8088 if (!rdev->coalesce->n_rules)
8089 return 0;
8090
8091 nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE);
8092 if (!nl_rules)
8093 return -ENOBUFS;
8094
8095 for (i = 0; i < rdev->coalesce->n_rules; i++) {
8096 nl_rule = nla_nest_start(msg, i + 1);
8097 if (!nl_rule)
8098 return -ENOBUFS;
8099
8100 rule = &rdev->coalesce->rules[i];
8101 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
8102 rule->delay))
8103 return -ENOBUFS;
8104
8105 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
8106 rule->condition))
8107 return -ENOBUFS;
8108
8109 nl_pats = nla_nest_start(msg,
8110 NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
8111 if (!nl_pats)
8112 return -ENOBUFS;
8113
8114 for (j = 0; j < rule->n_patterns; j++) {
8115 nl_pat = nla_nest_start(msg, j + 1);
8116 if (!nl_pat)
8117 return -ENOBUFS;
8118 pat_len = rule->patterns[j].pattern_len;
8119 if (nla_put(msg, NL80211_PKTPAT_MASK,
8120 DIV_ROUND_UP(pat_len, 8),
8121 rule->patterns[j].mask) ||
8122 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
8123 rule->patterns[j].pattern) ||
8124 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
8125 rule->patterns[j].pkt_offset))
8126 return -ENOBUFS;
8127 nla_nest_end(msg, nl_pat);
8128 }
8129 nla_nest_end(msg, nl_pats);
8130 nla_nest_end(msg, nl_rule);
8131 }
8132 nla_nest_end(msg, nl_rules);
8133
8134 return 0;
8135}
8136
8137static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info)
8138{
8139 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8140 struct sk_buff *msg;
8141 void *hdr;
8142
8143 if (!rdev->wiphy.coalesce)
8144 return -EOPNOTSUPP;
8145
8146 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8147 if (!msg)
8148 return -ENOMEM;
8149
8150 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
8151 NL80211_CMD_GET_COALESCE);
8152 if (!hdr)
8153 goto nla_put_failure;
8154
8155 if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev))
8156 goto nla_put_failure;
8157
8158 genlmsg_end(msg, hdr);
8159 return genlmsg_reply(msg, info);
8160
8161nla_put_failure:
8162 nlmsg_free(msg);
8163 return -ENOBUFS;
8164}
8165
8166void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev)
8167{
8168 struct cfg80211_coalesce *coalesce = rdev->coalesce;
8169 int i, j;
8170 struct cfg80211_coalesce_rules *rule;
8171
8172 if (!coalesce)
8173 return;
8174
8175 for (i = 0; i < coalesce->n_rules; i++) {
8176 rule = &coalesce->rules[i];
8177 for (j = 0; j < rule->n_patterns; j++)
8178 kfree(rule->patterns[j].mask);
8179 kfree(rule->patterns);
8180 }
8181 kfree(coalesce->rules);
8182 kfree(coalesce);
8183 rdev->coalesce = NULL;
8184}
8185
8186static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
8187 struct nlattr *rule,
8188 struct cfg80211_coalesce_rules *new_rule)
8189{
8190 int err, i;
8191 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
8192 struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat;
8193 int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
8194 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
8195
8196 err = nla_parse(tb, NL80211_ATTR_COALESCE_RULE_MAX, nla_data(rule),
8197 nla_len(rule), nl80211_coalesce_policy);
8198 if (err)
8199 return err;
8200
8201 if (tb[NL80211_ATTR_COALESCE_RULE_DELAY])
8202 new_rule->delay =
8203 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]);
8204 if (new_rule->delay > coalesce->max_delay)
8205 return -EINVAL;
8206
8207 if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION])
8208 new_rule->condition =
8209 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]);
8210 if (new_rule->condition != NL80211_COALESCE_CONDITION_MATCH &&
8211 new_rule->condition != NL80211_COALESCE_CONDITION_NO_MATCH)
8212 return -EINVAL;
8213
8214 if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN])
8215 return -EINVAL;
8216
8217 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
8218 rem)
8219 n_patterns++;
8220 if (n_patterns > coalesce->n_patterns)
8221 return -EINVAL;
8222
8223 new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]),
8224 GFP_KERNEL);
8225 if (!new_rule->patterns)
8226 return -ENOMEM;
8227
8228 new_rule->n_patterns = n_patterns;
8229 i = 0;
8230
8231 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
8232 rem) {
8233 nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
8234 nla_len(pat), NULL);
8235 if (!pat_tb[NL80211_PKTPAT_MASK] ||
8236 !pat_tb[NL80211_PKTPAT_PATTERN])
8237 return -EINVAL;
8238 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
8239 mask_len = DIV_ROUND_UP(pat_len, 8);
8240 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
8241 return -EINVAL;
8242 if (pat_len > coalesce->pattern_max_len ||
8243 pat_len < coalesce->pattern_min_len)
8244 return -EINVAL;
8245
8246 if (!pat_tb[NL80211_PKTPAT_OFFSET])
8247 pkt_offset = 0;
8248 else
8249 pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
8250 if (pkt_offset > coalesce->max_pkt_offset)
8251 return -EINVAL;
8252 new_rule->patterns[i].pkt_offset = pkt_offset;
8253
8254 new_rule->patterns[i].mask =
8255 kmalloc(mask_len + pat_len, GFP_KERNEL);
8256 if (!new_rule->patterns[i].mask)
8257 return -ENOMEM;
8258 new_rule->patterns[i].pattern =
8259 new_rule->patterns[i].mask + mask_len;
8260 memcpy(new_rule->patterns[i].mask,
8261 nla_data(pat_tb[NL80211_PKTPAT_MASK]), mask_len);
8262 new_rule->patterns[i].pattern_len = pat_len;
8263 memcpy(new_rule->patterns[i].pattern,
8264 nla_data(pat_tb[NL80211_PKTPAT_PATTERN]), pat_len);
8265 i++;
8266 }
8267
8268 return 0;
8269}
8270
8271static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info)
8272{
8273 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8274 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
8275 struct cfg80211_coalesce new_coalesce = {};
8276 struct cfg80211_coalesce *n_coalesce;
8277 int err, rem_rule, n_rules = 0, i, j;
8278 struct nlattr *rule;
8279 struct cfg80211_coalesce_rules *tmp_rule;
8280
8281 if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce)
8282 return -EOPNOTSUPP;
8283
8284 if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) {
8285 cfg80211_rdev_free_coalesce(rdev);
8286 rdev->ops->set_coalesce(&rdev->wiphy, NULL);
8287 return 0;
8288 }
8289
8290 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
8291 rem_rule)
8292 n_rules++;
8293 if (n_rules > coalesce->n_rules)
8294 return -EINVAL;
8295
8296 new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]),
8297 GFP_KERNEL);
8298 if (!new_coalesce.rules)
8299 return -ENOMEM;
8300
8301 new_coalesce.n_rules = n_rules;
8302 i = 0;
8303
8304 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
8305 rem_rule) {
8306 err = nl80211_parse_coalesce_rule(rdev, rule,
8307 &new_coalesce.rules[i]);
8308 if (err)
8309 goto error;
8310
8311 i++;
8312 }
8313
8314 err = rdev->ops->set_coalesce(&rdev->wiphy, &new_coalesce);
8315 if (err)
8316 goto error;
8317
8318 n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL);
8319 if (!n_coalesce) {
8320 err = -ENOMEM;
8321 goto error;
8322 }
8323 cfg80211_rdev_free_coalesce(rdev);
8324 rdev->coalesce = n_coalesce;
8325
8326 return 0;
8327error:
8328 for (i = 0; i < new_coalesce.n_rules; i++) {
8329 tmp_rule = &new_coalesce.rules[i];
8330 for (j = 0; j < tmp_rule->n_patterns; j++)
8331 kfree(tmp_rule->patterns[j].mask);
8332 kfree(tmp_rule->patterns);
8333 }
8334 kfree(new_coalesce.rules);
8335
8336 return err;
8337}
8338
8046static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) 8339static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
8047{ 8340{
8048 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 8341 struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -9050,6 +9343,21 @@ static struct genl_ops nl80211_ops[] = {
9050 .flags = GENL_ADMIN_PERM, 9343 .flags = GENL_ADMIN_PERM,
9051 .internal_flags = NL80211_FLAG_NEED_WDEV_UP | 9344 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
9052 NL80211_FLAG_NEED_RTNL, 9345 NL80211_FLAG_NEED_RTNL,
9346 },
9347 {
9348 .cmd = NL80211_CMD_GET_COALESCE,
9349 .doit = nl80211_get_coalesce,
9350 .policy = nl80211_policy,
9351 .internal_flags = NL80211_FLAG_NEED_WIPHY |
9352 NL80211_FLAG_NEED_RTNL,
9353 },
9354 {
9355 .cmd = NL80211_CMD_SET_COALESCE,
9356 .doit = nl80211_set_coalesce,
9357 .policy = nl80211_policy,
9358 .flags = GENL_ADMIN_PERM,
9359 .internal_flags = NL80211_FLAG_NEED_WIPHY |
9360 NL80211_FLAG_NEED_RTNL,
9053 } 9361 }
9054}; 9362};
9055 9363
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index a4073e808c13..44341bf53cfc 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -74,4 +74,6 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
74 enum nl80211_radar_event event, 74 enum nl80211_radar_event event,
75 struct net_device *netdev, gfp_t gfp); 75 struct net_device *netdev, gfp_t gfp);
76 76
77void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev);
78
77#endif /* __NET_WIRELESS_NL80211_H */ 79#endif /* __NET_WIRELESS_NL80211_H */