aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmitkumar Karwar <akarwar@marvell.com>2013-06-28 14:51:26 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-07-16 02:58:00 -0400
commitbe29b99a9b51b0338eea3c66a58de53bbd01de24 (patch)
treeabd4b2831ca396dddda2ea8bb02a39b12ea2a1b4
parenta144f378a489b5900c028425cb0d0a7a3fc8c1c1 (diff)
cfg80211/nl80211: Add packet coalesce support
In most cases, host that receives IPv4 and IPv6 multicast/broadcast packets does not do anything with these packets. Therefore the reception of these unwanted packets causes unnecessary processing and power consumption. Packet coalesce feature helps to reduce number of received interrupts to host by buffering these packets in firmware/hardware for some predefined time. Received interrupt will be generated when one of the following events occur. a) Expiration of hardware timer whose expiration time is set to maximum coalescing delay of matching coalesce rule. b) Coalescing buffer in hardware reaches it's limit. c) Packet doesn't match any of the configured coalesce rules. This patch adds set/get configuration support for packet coalesce. User needs to configure following parameters for creating a coalesce rule. a) Maximum coalescing delay b) List of packet patterns which needs to be matched c) Condition for coalescence. pattern 'match' or 'no match' Multiple such rules can be created. This feature needs to be advertised during driver initialization. Drivers are supposed to do required firmware/hardware settings based on user configuration. Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> [fix kernel-doc, change free function, fix copy/paste error] Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-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 */