1*5113495bSYour Name /*
2*5113495bSYour Name * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
3*5113495bSYour Name * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name *
5*5113495bSYour Name * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name * above copyright notice and this permission notice appear in all
8*5113495bSYour Name * copies.
9*5113495bSYour Name *
10*5113495bSYour Name * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name */
19*5113495bSYour Name
20*5113495bSYour Name /**
21*5113495bSYour Name * DOC: wlan_hdd_wowl.c
22*5113495bSYour Name *
23*5113495bSYour Name * wake up on WLAN API file
24*5113495bSYour Name */
25*5113495bSYour Name
26*5113495bSYour Name /* Include Files */
27*5113495bSYour Name
28*5113495bSYour Name #include "qdf_str.h"
29*5113495bSYour Name #include <wlan_hdd_includes.h>
30*5113495bSYour Name #include <wlan_hdd_wowl.h>
31*5113495bSYour Name #include <wlan_pmo_wow_public_struct.h>
32*5113495bSYour Name #include "wlan_hdd_object_manager.h"
33*5113495bSYour Name
34*5113495bSYour Name /* Preprocessor Definitions and Constants */
35*5113495bSYour Name #define WOWL_INTER_PTRN_TOKENIZER ';'
36*5113495bSYour Name #define WOWL_INTRA_PTRN_TOKENIZER ':'
37*5113495bSYour Name
38*5113495bSYour Name /* Type Declarations */
39*5113495bSYour Name
40*5113495bSYour Name static char *g_hdd_wowl_ptrns[WOWL_MAX_PTRNS_ALLOWED];
41*5113495bSYour Name static bool g_hdd_wowl_ptrns_debugfs[WOWL_MAX_PTRNS_ALLOWED] = { 0 };
42*5113495bSYour Name
43*5113495bSYour Name static uint8_t g_hdd_wowl_ptrns_count;
44*5113495bSYour Name
find_ptrn_len(const char * ptrn)45*5113495bSYour Name static inline int find_ptrn_len(const char *ptrn)
46*5113495bSYour Name {
47*5113495bSYour Name int len = 0;
48*5113495bSYour Name
49*5113495bSYour Name while (*ptrn != '\0' && *ptrn != WOWL_INTER_PTRN_TOKENIZER) {
50*5113495bSYour Name len++;
51*5113495bSYour Name ptrn++;
52*5113495bSYour Name }
53*5113495bSYour Name return len;
54*5113495bSYour Name }
55*5113495bSYour Name
56*5113495bSYour Name /**
57*5113495bSYour Name * dump_hdd_wowl_ptrn() - log wow patterns
58*5113495bSYour Name * @ptrn: pointer to wow pattern
59*5113495bSYour Name *
60*5113495bSYour Name * Return: none
61*5113495bSYour Name */
dump_hdd_wowl_ptrn(struct pmo_wow_add_pattern * ptrn)62*5113495bSYour Name static void dump_hdd_wowl_ptrn(struct pmo_wow_add_pattern *ptrn)
63*5113495bSYour Name {
64*5113495bSYour Name hdd_debug("Dumping WOW pattern");
65*5113495bSYour Name hdd_nofl_debug("Pattern Id = 0x%x", ptrn->pattern_id);
66*5113495bSYour Name hdd_nofl_debug("Pattern Byte Offset = 0x%x", ptrn->pattern_byte_offset);
67*5113495bSYour Name hdd_nofl_debug("Pattern_size = 0x%x", ptrn->pattern_size);
68*5113495bSYour Name hdd_nofl_debug("Pattern_mask_size = 0x%x", ptrn->pattern_mask_size);
69*5113495bSYour Name hdd_nofl_debug("Pattern: ");
70*5113495bSYour Name qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG,
71*5113495bSYour Name ptrn->pattern, ptrn->pattern_size);
72*5113495bSYour Name hdd_nofl_debug("pattern_mask: ");
73*5113495bSYour Name qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG,
74*5113495bSYour Name ptrn->pattern_mask, ptrn->pattern_mask_size);
75*5113495bSYour Name }
76*5113495bSYour Name
77*5113495bSYour Name static QDF_STATUS
hdd_get_num_wow_filters(struct hdd_context * hdd_ctx,uint8_t * num_filters)78*5113495bSYour Name hdd_get_num_wow_filters(struct hdd_context *hdd_ctx, uint8_t *num_filters)
79*5113495bSYour Name {
80*5113495bSYour Name QDF_STATUS status;
81*5113495bSYour Name struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc;
82*5113495bSYour Name
83*5113495bSYour Name status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_HDD_ID_OBJ_MGR);
84*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status))
85*5113495bSYour Name return status;
86*5113495bSYour Name
87*5113495bSYour Name if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE)
88*5113495bSYour Name *num_filters = 0;
89*5113495bSYour Name else
90*5113495bSYour Name *num_filters = ucfg_pmo_get_num_wow_filters(hdd_ctx->psoc);
91*5113495bSYour Name
92*5113495bSYour Name wlan_objmgr_psoc_release_ref(psoc, WLAN_HDD_ID_OBJ_MGR);
93*5113495bSYour Name
94*5113495bSYour Name return QDF_STATUS_SUCCESS;
95*5113495bSYour Name }
96*5113495bSYour Name
97*5113495bSYour Name /**
98*5113495bSYour Name * hdd_add_wowl_ptrn() - Function which will add the WoWL pattern to be
99*5113495bSYour Name * used when PBM filtering is enabled
100*5113495bSYour Name * @adapter: pointer to the adapter
101*5113495bSYour Name * @ptrn: pointer to the pattern string to be added
102*5113495bSYour Name *
103*5113495bSYour Name * Return: false if any errors encountered, true otherwise
104*5113495bSYour Name */
hdd_add_wowl_ptrn(struct hdd_adapter * adapter,const char * ptrn)105*5113495bSYour Name bool hdd_add_wowl_ptrn(struct hdd_adapter *adapter, const char *ptrn)
106*5113495bSYour Name {
107*5113495bSYour Name struct pmo_wow_add_pattern wow_pattern;
108*5113495bSYour Name int i, empty_slot, len, offset;
109*5113495bSYour Name QDF_STATUS status;
110*5113495bSYour Name const char *temp;
111*5113495bSYour Name struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
112*5113495bSYour Name uint8_t num_filters;
113*5113495bSYour Name bool invalid_ptrn = false;
114*5113495bSYour Name struct wlan_objmgr_vdev *vdev;
115*5113495bSYour Name
116*5113495bSYour Name status = hdd_get_num_wow_filters(hdd_ctx, &num_filters);
117*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status))
118*5113495bSYour Name return false;
119*5113495bSYour Name
120*5113495bSYour Name /* There has to have at least 1 byte for each field (pattern
121*5113495bSYour Name * size, mask size, pattern, mask) e.g. PP:QQ:RR:SS ==> 11
122*5113495bSYour Name * chars
123*5113495bSYour Name */
124*5113495bSYour Name len = find_ptrn_len(ptrn);
125*5113495bSYour Name while (len >= 11) {
126*5113495bSYour Name empty_slot = -1;
127*5113495bSYour Name
128*5113495bSYour Name /* check if pattern is already configured */
129*5113495bSYour Name for (i = num_filters - 1; i >= 0; i--) {
130*5113495bSYour Name if (!g_hdd_wowl_ptrns[i]) {
131*5113495bSYour Name empty_slot = i;
132*5113495bSYour Name continue;
133*5113495bSYour Name }
134*5113495bSYour Name
135*5113495bSYour Name if (strlen(g_hdd_wowl_ptrns[i]) == len) {
136*5113495bSYour Name if (!memcmp(ptrn, g_hdd_wowl_ptrns[i], len)) {
137*5113495bSYour Name hdd_err("WoWL pattern '%s' already configured",
138*5113495bSYour Name g_hdd_wowl_ptrns[i]);
139*5113495bSYour Name ptrn += len;
140*5113495bSYour Name goto next_ptrn;
141*5113495bSYour Name }
142*5113495bSYour Name }
143*5113495bSYour Name }
144*5113495bSYour Name
145*5113495bSYour Name /* Maximum number of patterns have been configured already */
146*5113495bSYour Name if (empty_slot == -1) {
147*5113495bSYour Name hdd_err("Max WoW patterns (%u) reached", num_filters);
148*5113495bSYour Name return false;
149*5113495bSYour Name }
150*5113495bSYour Name
151*5113495bSYour Name /* Validate the pattern */
152*5113495bSYour Name if (ptrn[2] != WOWL_INTRA_PTRN_TOKENIZER ||
153*5113495bSYour Name ptrn[5] != WOWL_INTRA_PTRN_TOKENIZER) {
154*5113495bSYour Name hdd_err("Malformed pattern string. Skip!");
155*5113495bSYour Name invalid_ptrn = true;
156*5113495bSYour Name ptrn += len;
157*5113495bSYour Name goto next_ptrn;
158*5113495bSYour Name }
159*5113495bSYour Name
160*5113495bSYour Name /* Extract the pattern size */
161*5113495bSYour Name wow_pattern.pattern_size =
162*5113495bSYour Name (hex_to_bin(ptrn[0]) * 0x10) + hex_to_bin(ptrn[1]);
163*5113495bSYour Name
164*5113495bSYour Name /* Extract the pattern mask size */
165*5113495bSYour Name wow_pattern.pattern_mask_size =
166*5113495bSYour Name (hex_to_bin(ptrn[3]) * 0x10) + hex_to_bin(ptrn[4]);
167*5113495bSYour Name
168*5113495bSYour Name if (wow_pattern.pattern_size > PMO_WOWL_BCAST_PATTERN_MAX_SIZE
169*5113495bSYour Name || wow_pattern.pattern_mask_size >
170*5113495bSYour Name WOWL_PTRN_MASK_MAX_SIZE) {
171*5113495bSYour Name hdd_err("Invalid length specified. Skip!");
172*5113495bSYour Name invalid_ptrn = true;
173*5113495bSYour Name ptrn += len;
174*5113495bSYour Name goto next_ptrn;
175*5113495bSYour Name }
176*5113495bSYour Name
177*5113495bSYour Name /* compute the offset of tokenizer after the pattern */
178*5113495bSYour Name offset = 5 + 2 * wow_pattern.pattern_size + 1;
179*5113495bSYour Name if ((offset >= len) ||
180*5113495bSYour Name (ptrn[offset] != WOWL_INTRA_PTRN_TOKENIZER)) {
181*5113495bSYour Name hdd_err("Malformed pattern string..skip!");
182*5113495bSYour Name invalid_ptrn = true;
183*5113495bSYour Name ptrn += len;
184*5113495bSYour Name goto next_ptrn;
185*5113495bSYour Name }
186*5113495bSYour Name
187*5113495bSYour Name /* compute the end of pattern string */
188*5113495bSYour Name offset = offset + 2 * wow_pattern.pattern_mask_size;
189*5113495bSYour Name if (offset + 1 != len) {
190*5113495bSYour Name /* offset begins with 0 */
191*5113495bSYour Name hdd_err("Malformed pattern string...skip!");
192*5113495bSYour Name invalid_ptrn = true;
193*5113495bSYour Name ptrn += len;
194*5113495bSYour Name goto next_ptrn;
195*5113495bSYour Name }
196*5113495bSYour Name
197*5113495bSYour Name temp = ptrn;
198*5113495bSYour Name
199*5113495bSYour Name /* Now advance to where pattern begins */
200*5113495bSYour Name ptrn += 6;
201*5113495bSYour Name
202*5113495bSYour Name /* Extract the pattern */
203*5113495bSYour Name for (i = 0; i < wow_pattern.pattern_size; i++) {
204*5113495bSYour Name wow_pattern.pattern[i] =
205*5113495bSYour Name (hex_to_bin(ptrn[0]) * 0x10) +
206*5113495bSYour Name hex_to_bin(ptrn[1]);
207*5113495bSYour Name ptrn += 2; /* skip to next byte */
208*5113495bSYour Name }
209*5113495bSYour Name
210*5113495bSYour Name /* Skip over the ':' separator after the pattern */
211*5113495bSYour Name ptrn++;
212*5113495bSYour Name
213*5113495bSYour Name /* Extract the pattern Mask */
214*5113495bSYour Name for (i = 0; i < wow_pattern.pattern_mask_size; i++) {
215*5113495bSYour Name wow_pattern.pattern_mask[i] =
216*5113495bSYour Name (hex_to_bin(ptrn[0]) * 0x10) +
217*5113495bSYour Name hex_to_bin(ptrn[1]);
218*5113495bSYour Name ptrn += 2; /* skip to next byte */
219*5113495bSYour Name }
220*5113495bSYour Name
221*5113495bSYour Name /* All is good. Store the pattern locally */
222*5113495bSYour Name g_hdd_wowl_ptrns[empty_slot] = qdf_mem_malloc(len + 1);
223*5113495bSYour Name if (!g_hdd_wowl_ptrns[empty_slot])
224*5113495bSYour Name return false;
225*5113495bSYour Name
226*5113495bSYour Name memcpy(g_hdd_wowl_ptrns[empty_slot], temp, len);
227*5113495bSYour Name g_hdd_wowl_ptrns[empty_slot][len] = '\0';
228*5113495bSYour Name wow_pattern.pattern_id = empty_slot;
229*5113495bSYour Name wow_pattern.pattern_byte_offset = 0;
230*5113495bSYour Name
231*5113495bSYour Name vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
232*5113495bSYour Name WLAN_OSIF_POWER_ID);
233*5113495bSYour Name if (!vdev) {
234*5113495bSYour Name hdd_err("vdev is null");
235*5113495bSYour Name qdf_mem_free(g_hdd_wowl_ptrns[empty_slot]);
236*5113495bSYour Name g_hdd_wowl_ptrns[empty_slot] = NULL;
237*5113495bSYour Name return false;
238*5113495bSYour Name }
239*5113495bSYour Name /* Register the pattern downstream */
240*5113495bSYour Name status = ucfg_pmo_add_wow_user_pattern(vdev, &wow_pattern);
241*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status)) {
242*5113495bSYour Name /* Add failed, so invalidate the local storage */
243*5113495bSYour Name hdd_err("sme_wowl_add_bcast_pattern failed with error code (%d)",
244*5113495bSYour Name status);
245*5113495bSYour Name qdf_mem_free(g_hdd_wowl_ptrns[empty_slot]);
246*5113495bSYour Name g_hdd_wowl_ptrns[empty_slot] = NULL;
247*5113495bSYour Name }
248*5113495bSYour Name hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
249*5113495bSYour Name dump_hdd_wowl_ptrn(&wow_pattern);
250*5113495bSYour Name
251*5113495bSYour Name next_ptrn:
252*5113495bSYour Name if (*ptrn == WOWL_INTER_PTRN_TOKENIZER) {
253*5113495bSYour Name /* move past the tokenizer */
254*5113495bSYour Name ptrn += 1;
255*5113495bSYour Name len = find_ptrn_len(ptrn);
256*5113495bSYour Name continue;
257*5113495bSYour Name } else {
258*5113495bSYour Name break;
259*5113495bSYour Name }
260*5113495bSYour Name }
261*5113495bSYour Name
262*5113495bSYour Name if (invalid_ptrn)
263*5113495bSYour Name return false;
264*5113495bSYour Name
265*5113495bSYour Name return true;
266*5113495bSYour Name }
267*5113495bSYour Name
268*5113495bSYour Name /**
269*5113495bSYour Name * hdd_del_wowl_ptrn() - Function which will remove a WoWL pattern
270*5113495bSYour Name * @adapter: pointer to the adapter
271*5113495bSYour Name * @ptrn: pointer to the pattern string to be removed
272*5113495bSYour Name *
273*5113495bSYour Name * Return: false if any errors encountered, true otherwise
274*5113495bSYour Name */
hdd_del_wowl_ptrn(struct hdd_adapter * adapter,const char * ptrn)275*5113495bSYour Name bool hdd_del_wowl_ptrn(struct hdd_adapter *adapter, const char *ptrn)
276*5113495bSYour Name {
277*5113495bSYour Name uint8_t id;
278*5113495bSYour Name bool patternFound = false;
279*5113495bSYour Name QDF_STATUS status;
280*5113495bSYour Name struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
281*5113495bSYour Name uint8_t num_filters;
282*5113495bSYour Name struct wlan_objmgr_vdev *vdev;
283*5113495bSYour Name
284*5113495bSYour Name status = hdd_get_num_wow_filters(hdd_ctx, &num_filters);
285*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status))
286*5113495bSYour Name return false;
287*5113495bSYour Name
288*5113495bSYour Name /* lookup pattern */
289*5113495bSYour Name for (id = 0; id < num_filters; id++) {
290*5113495bSYour Name if (!g_hdd_wowl_ptrns[id])
291*5113495bSYour Name continue;
292*5113495bSYour Name
293*5113495bSYour Name if (qdf_str_eq(ptrn, g_hdd_wowl_ptrns[id])) {
294*5113495bSYour Name patternFound = true;
295*5113495bSYour Name break;
296*5113495bSYour Name }
297*5113495bSYour Name }
298*5113495bSYour Name
299*5113495bSYour Name /* If pattern present, remove it from downstream */
300*5113495bSYour Name if (!patternFound)
301*5113495bSYour Name return false;
302*5113495bSYour Name
303*5113495bSYour Name vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
304*5113495bSYour Name WLAN_OSIF_POWER_ID);
305*5113495bSYour Name if (!vdev)
306*5113495bSYour Name return false;
307*5113495bSYour Name
308*5113495bSYour Name status = ucfg_pmo_del_wow_user_pattern(vdev, id);
309*5113495bSYour Name hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
310*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status))
311*5113495bSYour Name return false;
312*5113495bSYour Name
313*5113495bSYour Name /* Remove from local storage as well */
314*5113495bSYour Name hdd_err("Deleted pattern with id %d [%s]", id, g_hdd_wowl_ptrns[id]);
315*5113495bSYour Name
316*5113495bSYour Name qdf_mem_free(g_hdd_wowl_ptrns[id]);
317*5113495bSYour Name g_hdd_wowl_ptrns[id] = NULL;
318*5113495bSYour Name
319*5113495bSYour Name return true;
320*5113495bSYour Name }
321*5113495bSYour Name
322*5113495bSYour Name /**
323*5113495bSYour Name * hdd_add_wowl_ptrn_debugfs() - Function which will add a WoW pattern
324*5113495bSYour Name * sent from debugfs interface
325*5113495bSYour Name * @adapter: pointer to the adapter
326*5113495bSYour Name * @pattern_idx: index of the pattern to be added
327*5113495bSYour Name * @pattern_offset: offset of the pattern in the frame payload
328*5113495bSYour Name * @pattern_buf: pointer to the pattern hex string to be added
329*5113495bSYour Name * @pattern_mask: pointer to the pattern mask hex string
330*5113495bSYour Name *
331*5113495bSYour Name * Return: false if any errors encountered, true otherwise
332*5113495bSYour Name */
hdd_add_wowl_ptrn_debugfs(struct hdd_adapter * adapter,uint8_t pattern_idx,uint8_t pattern_offset,char * pattern_buf,char * pattern_mask)333*5113495bSYour Name bool hdd_add_wowl_ptrn_debugfs(struct hdd_adapter *adapter, uint8_t pattern_idx,
334*5113495bSYour Name uint8_t pattern_offset, char *pattern_buf,
335*5113495bSYour Name char *pattern_mask)
336*5113495bSYour Name {
337*5113495bSYour Name struct pmo_wow_add_pattern wow_pattern;
338*5113495bSYour Name QDF_STATUS qdf_ret_status;
339*5113495bSYour Name uint16_t pattern_len, mask_len, i;
340*5113495bSYour Name struct wlan_objmgr_vdev *vdev;
341*5113495bSYour Name
342*5113495bSYour Name if (pattern_idx > (WOWL_MAX_PTRNS_ALLOWED - 1)) {
343*5113495bSYour Name hdd_err("WoW pattern index %d is out of range (0 ~ %d)",
344*5113495bSYour Name pattern_idx, WOWL_MAX_PTRNS_ALLOWED - 1);
345*5113495bSYour Name
346*5113495bSYour Name return false;
347*5113495bSYour Name }
348*5113495bSYour Name
349*5113495bSYour Name pattern_len = strlen(pattern_buf);
350*5113495bSYour Name
351*5113495bSYour Name /* Since the pattern is a hex string, 2 characters represent 1 byte. */
352*5113495bSYour Name if (pattern_len % 2) {
353*5113495bSYour Name hdd_err("Malformed WoW pattern!");
354*5113495bSYour Name
355*5113495bSYour Name return false;
356*5113495bSYour Name }
357*5113495bSYour Name
358*5113495bSYour Name pattern_len >>= 1;
359*5113495bSYour Name if (!pattern_len || pattern_len > WOWL_PTRN_MAX_SIZE) {
360*5113495bSYour Name hdd_err("WoW pattern length %d is out of range (1 ~ %d).",
361*5113495bSYour Name pattern_len, WOWL_PTRN_MAX_SIZE);
362*5113495bSYour Name
363*5113495bSYour Name return false;
364*5113495bSYour Name }
365*5113495bSYour Name
366*5113495bSYour Name wow_pattern.pattern_id = pattern_idx;
367*5113495bSYour Name wow_pattern.pattern_byte_offset = pattern_offset;
368*5113495bSYour Name wow_pattern.pattern_size = pattern_len;
369*5113495bSYour Name
370*5113495bSYour Name if (wow_pattern.pattern_size > PMO_WOWL_BCAST_PATTERN_MAX_SIZE) {
371*5113495bSYour Name hdd_err("WoW pattern size (%d) greater than max (%d)",
372*5113495bSYour Name wow_pattern.pattern_size,
373*5113495bSYour Name PMO_WOWL_BCAST_PATTERN_MAX_SIZE);
374*5113495bSYour Name return false;
375*5113495bSYour Name }
376*5113495bSYour Name /* Extract the pattern */
377*5113495bSYour Name for (i = 0; i < wow_pattern.pattern_size; i++) {
378*5113495bSYour Name wow_pattern.pattern[i] =
379*5113495bSYour Name (hex_to_bin(pattern_buf[0]) << 4) +
380*5113495bSYour Name hex_to_bin(pattern_buf[1]);
381*5113495bSYour Name
382*5113495bSYour Name /* Skip to next byte */
383*5113495bSYour Name pattern_buf += 2;
384*5113495bSYour Name }
385*5113495bSYour Name
386*5113495bSYour Name /* Get pattern mask size by pattern length */
387*5113495bSYour Name wow_pattern.pattern_mask_size = pattern_len >> 3;
388*5113495bSYour Name if (pattern_len % 8)
389*5113495bSYour Name wow_pattern.pattern_mask_size += 1;
390*5113495bSYour Name
391*5113495bSYour Name mask_len = strlen(pattern_mask);
392*5113495bSYour Name if ((mask_len % 2)
393*5113495bSYour Name || (wow_pattern.pattern_mask_size != (mask_len >> 1))) {
394*5113495bSYour Name hdd_err("Malformed WoW pattern mask!");
395*5113495bSYour Name
396*5113495bSYour Name return false;
397*5113495bSYour Name }
398*5113495bSYour Name if (wow_pattern.pattern_mask_size > WOWL_PTRN_MASK_MAX_SIZE) {
399*5113495bSYour Name hdd_err("WoW pattern mask size (%d) greater than max (%d)",
400*5113495bSYour Name wow_pattern.pattern_mask_size,
401*5113495bSYour Name WOWL_PTRN_MASK_MAX_SIZE);
402*5113495bSYour Name return false;
403*5113495bSYour Name }
404*5113495bSYour Name /* Extract the pattern mask */
405*5113495bSYour Name for (i = 0; i < wow_pattern.pattern_mask_size; i++) {
406*5113495bSYour Name wow_pattern.pattern_mask[i] =
407*5113495bSYour Name (hex_to_bin(pattern_mask[0]) << 4) +
408*5113495bSYour Name hex_to_bin(pattern_mask[1]);
409*5113495bSYour Name
410*5113495bSYour Name /* Skip to next byte */
411*5113495bSYour Name pattern_mask += 2;
412*5113495bSYour Name }
413*5113495bSYour Name
414*5113495bSYour Name vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
415*5113495bSYour Name WLAN_OSIF_POWER_ID);
416*5113495bSYour Name if (!vdev)
417*5113495bSYour Name return false;
418*5113495bSYour Name
419*5113495bSYour Name /* Register the pattern downstream */
420*5113495bSYour Name qdf_ret_status = ucfg_pmo_add_wow_user_pattern(vdev, &wow_pattern);
421*5113495bSYour Name hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
422*5113495bSYour Name if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) {
423*5113495bSYour Name hdd_err("pmo_wow_user_pattern failed with error code (%d).",
424*5113495bSYour Name qdf_ret_status);
425*5113495bSYour Name
426*5113495bSYour Name return false;
427*5113495bSYour Name }
428*5113495bSYour Name
429*5113495bSYour Name /* All is good. */
430*5113495bSYour Name if (!g_hdd_wowl_ptrns_debugfs[pattern_idx]) {
431*5113495bSYour Name g_hdd_wowl_ptrns_debugfs[pattern_idx] = 1;
432*5113495bSYour Name g_hdd_wowl_ptrns_count++;
433*5113495bSYour Name }
434*5113495bSYour Name
435*5113495bSYour Name dump_hdd_wowl_ptrn(&wow_pattern);
436*5113495bSYour Name
437*5113495bSYour Name return true;
438*5113495bSYour Name }
439*5113495bSYour Name
440*5113495bSYour Name /**
441*5113495bSYour Name * hdd_del_wowl_ptrn_debugfs() - Function which will remove a WoW pattern
442*5113495bSYour Name * sent from debugfs interface
443*5113495bSYour Name * @adapter: pointer to the adapter
444*5113495bSYour Name * @pattern_idx: index of the pattern to be removed
445*5113495bSYour Name *
446*5113495bSYour Name * Return: false if any errors encountered, true otherwise
447*5113495bSYour Name */
hdd_del_wowl_ptrn_debugfs(struct hdd_adapter * adapter,uint8_t pattern_idx)448*5113495bSYour Name bool hdd_del_wowl_ptrn_debugfs(struct hdd_adapter *adapter,
449*5113495bSYour Name uint8_t pattern_idx)
450*5113495bSYour Name {
451*5113495bSYour Name struct wlan_objmgr_vdev *vdev;
452*5113495bSYour Name QDF_STATUS qdf_ret_status;
453*5113495bSYour Name
454*5113495bSYour Name if (pattern_idx > (WOWL_MAX_PTRNS_ALLOWED - 1)) {
455*5113495bSYour Name hdd_err("WoW pattern index %d is not in the range (0 ~ %d).",
456*5113495bSYour Name pattern_idx, WOWL_MAX_PTRNS_ALLOWED - 1);
457*5113495bSYour Name
458*5113495bSYour Name return false;
459*5113495bSYour Name }
460*5113495bSYour Name
461*5113495bSYour Name if (!g_hdd_wowl_ptrns_debugfs[pattern_idx]) {
462*5113495bSYour Name hdd_err("WoW pattern %d is not in the table.",
463*5113495bSYour Name pattern_idx);
464*5113495bSYour Name
465*5113495bSYour Name return false;
466*5113495bSYour Name }
467*5113495bSYour Name
468*5113495bSYour Name vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
469*5113495bSYour Name WLAN_OSIF_POWER_ID);
470*5113495bSYour Name if (!vdev)
471*5113495bSYour Name return false;
472*5113495bSYour Name
473*5113495bSYour Name qdf_ret_status = ucfg_pmo_del_wow_user_pattern(vdev, pattern_idx);
474*5113495bSYour Name hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
475*5113495bSYour Name if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) {
476*5113495bSYour Name hdd_err("sme_wowl_del_bcast_pattern failed with error code (%d).",
477*5113495bSYour Name qdf_ret_status);
478*5113495bSYour Name
479*5113495bSYour Name return false;
480*5113495bSYour Name }
481*5113495bSYour Name
482*5113495bSYour Name g_hdd_wowl_ptrns_debugfs[pattern_idx] = 0;
483*5113495bSYour Name g_hdd_wowl_ptrns_count--;
484*5113495bSYour Name
485*5113495bSYour Name return true;
486*5113495bSYour Name }
487*5113495bSYour Name
hdd_free_user_wowl_ptrns(void)488*5113495bSYour Name void hdd_free_user_wowl_ptrns(void)
489*5113495bSYour Name {
490*5113495bSYour Name int i;
491*5113495bSYour Name
492*5113495bSYour Name for (i = 0; i < WOWL_MAX_PTRNS_ALLOWED; ++i) {
493*5113495bSYour Name if (g_hdd_wowl_ptrns[i]) {
494*5113495bSYour Name qdf_mem_free(g_hdd_wowl_ptrns[i]);
495*5113495bSYour Name g_hdd_wowl_ptrns[i] = NULL;
496*5113495bSYour Name }
497*5113495bSYour Name }
498*5113495bSYour Name }
499