blob: fa41a23aace400518530677b9f2cdf0f3359bf53 [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
2 * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*============================================================================
23 * @file wlan_hdd_wowl.c
24 *
25 * Copyright (c) 2009 QUALCOMM Incorporated.
26 * All Rights Reserved.
27 * Qualcomm Confidential and Proprietary
28 *
29 * ==========================================================================*/
30
31/*----------------------------------------------------------------------------
32 * Include Files
33 * -------------------------------------------------------------------------*/
34
35#include <wlan_hdd_includes.h>
36#include <wlan_hdd_wowl.h>
37
38/*----------------------------------------------------------------------------
39 * Preprocessor Definitions and Constants
40 * -------------------------------------------------------------------------*/
41
42#define WOWL_PTRN_MAX_SIZE 128
43#define WOWL_PTRN_MASK_MAX_SIZE 16
44#define WOWL_MAX_PTRNS_ALLOWED 8
45#define WOWL_INTER_PTRN_TOKENIZER ';'
46#define WOWL_INTRA_PTRN_TOKENIZER ':'
47
48/*----------------------------------------------------------------------------
49 * Type Declarations
50 * -------------------------------------------------------------------------*/
51
52static struct hdd_context_s *pAdapterHandle = NULL;
53
54char *g_hdd_wowl_ptrns[WOWL_MAX_PTRNS_ALLOWED]; //Patterns 0-7
55
56static int parse_hex(unsigned char c)
57{
58 if (c >= '0' && c <= '9')
59 return c-'0';
60 if (c >= 'a' && c <= 'f')
61 return c-'a'+10;
62 if (c >= 'A' && c <= 'F')
63 return c-'A'+10;
64
65 return 0;
66}
67
68static inline int find_ptrn_len(const char* ptrn)
69{
70 int len = 0;
71 while (*ptrn != '\0' && *ptrn != WOWL_INTER_PTRN_TOKENIZER)
72 {
73 len++; ptrn++;
74 }
75 return len;
76}
77
78static void hdd_wowl_callback( void *pContext, eHalStatus halStatus )
79{
80 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
81 "%s: Return code = (%ld)\n", __FUNCTION__, halStatus );
82}
83
84static void dump_hdd_wowl_ptrn(tSirWowlAddBcastPtrn *ptrn)
85{
86 int i;
87
88 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: ucPatetrnId = 0x%x", __func__,
89 ptrn->ucPatternId);
90 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: ucPatternByteOffset = 0x%x", __func__,
91 ptrn->ucPatternByteOffset);
92 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: ucPatternSize = 0x%x", __func__,
93 ptrn->ucPatternSize);
94 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: ucPatternMaskSize = 0x%x", __func__,
95 ptrn->ucPatternMaskSize);
96 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Pattern: ", __func__);
97 for(i = 0; i<ptrn->ucPatternSize; i++)
98 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO," %02X", ptrn->ucPattern[i]);
99 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: PatternMask: ", __func__);
100 for(i = 0; i<ptrn->ucPatternMaskSize; i++)
101 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"%02X", ptrn->ucPatternMask[i]);
102}
103
104
105/**============================================================================
106 @brief hdd_add_wowl_ptrn() - Function which will add the WoWL pattern to be
107 used when PBM filtering is enabled
108
109 @param ptrn : [in] pointer to the pattern string to be added
110
111 @return : FALSE if any errors encountered
112 : TRUE otherwise
113 ===========================================================================*/
114v_BOOL_t hdd_add_wowl_ptrn (const char * ptrn)
115{
116 tSirWowlAddBcastPtrn localPattern;
117 int i, first_empty_slot, len, offset;
118 eHalStatus halStatus;
119 const char *temp;
120
121 len = find_ptrn_len(ptrn);
122
123 /* There has to have atleast 1 byte for each field (pattern size, mask size,
124 * pattern, mask) e.g. PP:QQ:RR:SS ==> 11 chars */
125 while ( len >= 11 )
126 {
127 first_empty_slot = -1;
128
129 // Find an empty slot to store the pattern
130 for (i=0; i<WOWL_MAX_PTRNS_ALLOWED; i++)
131 {
132 if(g_hdd_wowl_ptrns[i] == NULL) {
133 first_empty_slot = i;
134 break;
135 }
136 }
137
138 // Maximum number of patterns have been configured already
139 if(first_empty_slot == -1)
140 {
141 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
142 "%s: Cannot add anymore patterns. No free slot!", __FUNCTION__);
143 return VOS_FALSE;
144 }
145
146 // Detect duplicate pattern
147 for (i=0; i<WOWL_MAX_PTRNS_ALLOWED; i++)
148 {
149 if(g_hdd_wowl_ptrns[i] == NULL) continue;
150
151 if(!memcmp(ptrn, g_hdd_wowl_ptrns[i], len))
152 {
153 // Pattern Already configured, skip to next pattern
154 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
155 "Trying to add duplicate WoWL pattern. Skip it!");
156 ptrn += len;
157 goto next_ptrn;
158 }
159 }
160
161 //Validate the pattern
162 if(ptrn[2] != WOWL_INTRA_PTRN_TOKENIZER ||
163 ptrn[5] != WOWL_INTRA_PTRN_TOKENIZER)
164 {
165 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
166 "%s: Malformed pattern string. Skip!\n", __FUNCTION__);
167 ptrn += len;
168 goto next_ptrn;
169 }
170
171 // Extract the pattern size
172 localPattern.ucPatternSize =
173 ( parse_hex( ptrn[0] ) * 0x10 ) + parse_hex( ptrn[1] );
174
175 // Extract the pattern mask size
176 localPattern.ucPatternMaskSize =
177 ( parse_hex( ptrn[3] ) * 0x10 ) + parse_hex( ptrn[4] );
178
179 if(localPattern.ucPatternSize > WOWL_PTRN_MAX_SIZE ||
180 localPattern.ucPatternMaskSize > WOWL_PTRN_MASK_MAX_SIZE)
181 {
182 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
183 "%s: Invalid length specified. Skip!\n", __FUNCTION__);
184 ptrn += len;
185 goto next_ptrn;
186 }
187
188 //compute the offset of tokenizer after the pattern
189 offset = 5 + 2*localPattern.ucPatternSize + 1;
190 if(offset >= len || ptrn[offset] != WOWL_INTRA_PTRN_TOKENIZER)
191 {
192 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
193 "%s: Malformed pattern string..skip!\n", __FUNCTION__);
194 ptrn += len;
195 goto next_ptrn;
196 }
197
198 //compute the end of pattern sring
199 offset = offset + 2*localPattern.ucPatternMaskSize;
200 if(offset+1 != len) //offset begins with 0
201 {
202 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
203 "%s: Malformed pattern string...skip!\n", __FUNCTION__);
204 ptrn += len;
205 goto next_ptrn;
206 }
207
208 temp = ptrn;
209
210 // Now advance to where pattern begins
211 ptrn += 6;
212
213 // Extract the pattern
214 for(i=0; i < localPattern.ucPatternSize; i++)
215 {
216 localPattern.ucPattern[i] =
217 (parse_hex( ptrn[0] ) * 0x10 ) + parse_hex( ptrn[1] );
218 ptrn += 2; //skip to next byte
219 }
220
221 ptrn++; // Skip over the ':' seperator after the pattern
222
223 // Extract the pattern Mask
224 for(i=0; i < localPattern.ucPatternMaskSize; i++)
225 {
226 localPattern.ucPatternMask[i] =
227 (parse_hex( ptrn[0] ) * 0x10 ) + parse_hex( ptrn[1] );
228 ptrn += 2; //skip to next byte
229 }
230
231 //All is good. Store the pattern locally
232 g_hdd_wowl_ptrns[first_empty_slot] = (char*) kmalloc(len+1, GFP_KERNEL);
233 if(g_hdd_wowl_ptrns[first_empty_slot] == NULL)
234 {
235 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
236 "%s: kmalloc failure", __FUNCTION__);
237 return VOS_FALSE;
238 }
239
240 memcpy(g_hdd_wowl_ptrns[first_empty_slot], temp, len);
241 g_hdd_wowl_ptrns[first_empty_slot][len] = '\0';
242 localPattern.ucPatternId = first_empty_slot;
243 localPattern.ucPatternByteOffset = 0;
244
245 // Register the pattern downstream
246 halStatus = sme_WowlAddBcastPattern( pAdapterHandle->hHal, &localPattern );
247 if ( !HAL_STATUS_SUCCESS( halStatus ) )
248 {
249 // Add failed, so invalidate the local storage
250 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
251 "sme_WowlAddBcastPattern failed with error code (%ld)", halStatus );
252 kfree(g_hdd_wowl_ptrns[first_empty_slot]);
253 g_hdd_wowl_ptrns[first_empty_slot] = NULL;
254 }
255
256 dump_hdd_wowl_ptrn(&localPattern);
257
258 next_ptrn:
259 if (*ptrn == WOWL_INTER_PTRN_TOKENIZER)
260 {
261 ptrn += 1; // move past the tokenizer
262 len = find_ptrn_len(ptrn);
263 continue;
264 }
265 else
266 break;
267 }
268
269 return VOS_TRUE;
270}
271
272/**============================================================================
273 @brief hdd_del_wowl_ptrn() - Function which will remove a WoWL pattern
274
275 @param ptrn : [in] pointer to the pattern string to be removed
276
277 @return : FALSE if any errors encountered
278 : TRUE otherwise
279 ===========================================================================*/
280v_BOOL_t hdd_del_wowl_ptrn (const char * ptrn)
281{
282 tSirWowlDelBcastPtrn delPattern;
283 unsigned char id;
284 v_BOOL_t patternFound = VOS_FALSE;
285 eHalStatus halStatus;
286
287 // Detect pattern
288 for (id=0; id<WOWL_MAX_PTRNS_ALLOWED && g_hdd_wowl_ptrns[id] != NULL; id++)
289 {
290 if(!strcmp(ptrn, g_hdd_wowl_ptrns[id]))
291 {
292 patternFound = VOS_TRUE;
293 break;
294 }
295 }
296
297 // If pattern present, remove it from downstream
298 if(patternFound)
299 {
300 delPattern.ucPatternId = id;
301 halStatus = sme_WowlDelBcastPattern( pAdapterHandle->hHal, &delPattern );
302 if ( HAL_STATUS_SUCCESS( halStatus ) )
303 {
304 // Remove from local storage as well
305 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
306 "Deleted pattern with id %d [%s]", id, g_hdd_wowl_ptrns[id]);
307
308 kfree(g_hdd_wowl_ptrns[id]);
309 g_hdd_wowl_ptrns[id] = NULL;
310 return VOS_TRUE;
311 }
312 }
313 return VOS_FALSE;
314}
315
316/**============================================================================
317 @brief hdd_enter_wowl() - Function which will enable WoWL. Atleast one
318 of MP and PBM must be enabled
319
320 @param enable_mp : [in] Whether to enable magic packet WoWL mode
321 @param enable_pbm : [in] Whether to enable pattern byte matching WoWL mode
322
323 @return : FALSE if any errors encountered
324 : TRUE otherwise
325 ===========================================================================*/
326v_BOOL_t hdd_enter_wowl (hdd_adapter_t *pAdapter, v_BOOL_t enable_mp, v_BOOL_t enable_pbm)
327{
328 tSirSmeWowlEnterParams wowParams;
329 eHalStatus halStatus;
330
331 wowParams.ucPatternFilteringEnable = enable_pbm;
332 wowParams.ucMagicPktEnable = enable_mp;
333 if(enable_mp)
334 {
335 vos_copy_macaddr( (v_MACADDR_t *)&(wowParams.magicPtrn),
336 &(pAdapter->macAddressCurrent) );
337 }
338
339 // Request to put Libra into WoWL
340 halStatus = sme_EnterWowl( pAdapterHandle->hHal, hdd_wowl_callback,
341 pAdapterHandle, &wowParams );
342
343 if ( !HAL_STATUS_SUCCESS( halStatus ) )
344 {
345 if ( eHAL_STATUS_PMC_PENDING != halStatus )
346 {
347 // We failed to enter WoWL
348 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
349 "sme_EnterWowl failed with error code (%ld)", halStatus );
350 return VOS_FALSE;
351 }
352 }
353 return VOS_TRUE;
354}
355
356/**============================================================================
357 @brief hdd_exit_wowl() - Function which will disable WoWL
358
359 @return : FALSE if any errors encountered
360 : TRUE otherwise
361 ===========================================================================*/
362v_BOOL_t hdd_exit_wowl (void)
363{
364 eHalStatus halStatus;
365
366 halStatus = sme_ExitWowl( pAdapterHandle->hHal );
367 if ( !HAL_STATUS_SUCCESS( halStatus ) )
368 {
369 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
370 "sme_ExitWowl failed with error code (%ld)", halStatus );
371 return VOS_FALSE;
372 }
373
374 return VOS_TRUE;
375}
376
377/**============================================================================
378 @brief hdd_init_wowl() - Init function which will initialize the WoWL module
379 and perform any required intial configuration
380
381 @return : FALSE if any errors encountered
382 : TRUE otherwise
383 ===========================================================================*/
384v_BOOL_t hdd_init_wowl (void *pAdapter)
385{
386 pAdapterHandle = (struct hdd_context_s*)pAdapter;
387
388 memset(g_hdd_wowl_ptrns, 0, sizeof(g_hdd_wowl_ptrns));
389
390 //Add any statically configured patterns
391 hdd_add_wowl_ptrn(pAdapterHandle->cfg_ini->wowlPattern);
392
393 return VOS_TRUE;
394}