* Note that the pattern matching is done as though frames were not
* 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
* first (including SNAP header unpacking) and then matched.
+ * @NL80211_WOWLAN_PKTPAT_OFFSET: packet offset, pattern is matched after
+ * these fixed number of bytes of received packet
* @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
* @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
*/
__NL80211_WOWLAN_PKTPAT_INVALID,
NL80211_WOWLAN_PKTPAT_MASK,
NL80211_WOWLAN_PKTPAT_PATTERN,
+ NL80211_WOWLAN_PKTPAT_OFFSET,
NUM_NL80211_WOWLAN_PKTPAT,
MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
* @max_patterns: maximum number of patterns supported
* @min_pattern_len: minimum length of each pattern
* @max_pattern_len: maximum length of each pattern
+ * @max_pkt_offset: maximum Rx packet offset
*
* This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
* that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
__u32 max_patterns;
__u32 min_pattern_len;
__u32 max_pattern_len;
+ __u32 max_pkt_offset;
} __attribute__((packed));
/**
* @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns
* which are passed in an array of nested attributes, each nested attribute
* defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern.
- * Each pattern defines a wakeup packet. The matching is done on the MSDU,
- * i.e. as though the packet was an 802.3 packet, so the pattern matching
- * is done after the packet is converted to the MSDU.
+ * Each pattern defines a wakeup packet. Packet offset is associated with
+ * each pattern which is used while matching the pattern. The matching is
+ * done on the MSDU, i.e. as though the packet was an 802.3 packet, so the
+ * pattern matching is done after the packet is converted to the MSDU.
*
* In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
* carrying a &struct nl80211_wowlan_pattern_support.
dev->wiphy.wowlan.pattern_min_len,
.max_pattern_len =
dev->wiphy.wowlan.pattern_max_len,
+ .max_pkt_offset =
+ dev->wiphy.wowlan.max_pkt_offset,
};
if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
sizeof(pat), &pat))
}
#ifdef CONFIG_PM
+static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
+ struct cfg80211_registered_device *rdev)
+{
+ struct nlattr *nl_pats, *nl_pat;
+ int i, pat_len;
+
+ if (!rdev->wowlan->n_patterns)
+ return 0;
+
+ nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN);
+ if (!nl_pats)
+ return -ENOBUFS;
+
+ for (i = 0; i < rdev->wowlan->n_patterns; i++) {
+ nl_pat = nla_nest_start(msg, i + 1);
+ if (!nl_pat)
+ return -ENOBUFS;
+ pat_len = rdev->wowlan->patterns[i].pattern_len;
+ if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK,
+ DIV_ROUND_UP(pat_len, 8),
+ rdev->wowlan->patterns[i].mask) ||
+ nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN,
+ pat_len, rdev->wowlan->patterns[i].pattern) ||
+ nla_put_u32(msg, NL80211_WOWLAN_PKTPAT_OFFSET,
+ rdev->wowlan->patterns[i].pkt_offset))
+ return -ENOBUFS;
+ nla_nest_end(msg, nl_pat);
+ }
+ nla_nest_end(msg, nl_pats);
+
+ return 0;
+}
+
static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
(rdev->wowlan->rfkill_release &&
nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
goto nla_put_failure;
- if (rdev->wowlan->n_patterns) {
- struct nlattr *nl_pats, *nl_pat;
- int i, pat_len;
-
- nl_pats = nla_nest_start(msg,
- NL80211_WOWLAN_TRIG_PKT_PATTERN);
- if (!nl_pats)
- goto nla_put_failure;
-
- for (i = 0; i < rdev->wowlan->n_patterns; i++) {
- nl_pat = nla_nest_start(msg, i + 1);
- if (!nl_pat)
- goto nla_put_failure;
- pat_len = rdev->wowlan->patterns[i].pattern_len;
- if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK,
- DIV_ROUND_UP(pat_len, 8),
- rdev->wowlan->patterns[i].mask) ||
- nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN,
- pat_len,
- rdev->wowlan->patterns[i].pattern))
- goto nla_put_failure;
- nla_nest_end(msg, nl_pat);
- }
- nla_nest_end(msg, nl_pats);
- }
-
+ if (nl80211_send_wowlan_patterns(msg, rdev))
+ goto nla_put_failure;
nla_nest_end(msg, nl_wowlan);
}
if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
struct nlattr *pat;
int n_patterns = 0;
- int rem, pat_len, mask_len;
+ int rem, pat_len, mask_len, pkt_offset;
struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT];
nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
pat_len < wowlan->pattern_min_len)
goto error;
+ if (!pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET])
+ pkt_offset = 0;
+ else
+ pkt_offset = nla_get_u32(
+ pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]);
+ if (pkt_offset > wowlan->max_pkt_offset)
+ goto error;
+ new_triggers.patterns[i].pkt_offset = pkt_offset;
+
new_triggers.patterns[i].mask =
kmalloc(mask_len + pat_len, GFP_KERNEL);
if (!new_triggers.patterns[i].mask) {