wifi: update ap6356 driver to bcmdhd.101.10.361.x [1/1]
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd.1.579.77.41.1.cn / bcmutils.c
1 /*
2 * Driver O/S-independent utility routines
3 *
4 * Copyright (C) 1999-2017, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
27 * $Id: bcmutils.c 699163 2017-05-12 05:18:23Z $
28 */
29
30 #include <bcm_cfg.h>
31 #include <typedefs.h>
32 #include <bcmdefs.h>
33 #include <stdarg.h>
34 #ifdef BCMDRIVER
35
36 #include <osl.h>
37 #include <bcmutils.h>
38
39 #else /* !BCMDRIVER */
40
41 #include <stdio.h>
42 #include <string.h>
43 #include <bcmutils.h>
44
45 #if defined(BCMEXTSUP)
46 #include <bcm_osl.h>
47 #endif
48
49 #ifndef ASSERT
50 #define ASSERT(exp)
51 #endif
52
53 #endif /* !BCMDRIVER */
54
55 #include <bcmendian.h>
56 #include <bcmdevs.h>
57 #include <ethernet.h>
58 #include <vlan.h>
59 #include <bcmip.h>
60 #include <802.1d.h>
61 #include <802.11.h>
62 #include <bcmip.h>
63 #include <bcmipv6.h>
64 #include <bcmtcp.h>
65
66 /* Look-up table to calculate head room present in a number */
67 static const uint8 msb_table[] = {
68 0, 1, 2, 2, 3, 3, 3, 3,
69 4, 4, 4, 4, 4, 4, 4, 4,
70 5, 5, 5, 5, 5, 5, 5, 5,
71 5, 5, 5, 5, 5, 5, 5, 5,
72 6, 6, 6, 6, 6, 6, 6, 6,
73 6, 6, 6, 6, 6, 6, 6, 6,
74 6, 6, 6, 6, 6, 6, 6, 6,
75 6, 6, 6, 6, 6, 6, 6, 6,
76 7, 7, 7, 7, 7, 7, 7, 7,
77 7, 7, 7, 7, 7, 7, 7, 7,
78 7, 7, 7, 7, 7, 7, 7, 7,
79 7, 7, 7, 7, 7, 7, 7, 7,
80 7, 7, 7, 7, 7, 7, 7, 7,
81 7, 7, 7, 7, 7, 7, 7, 7,
82 7, 7, 7, 7, 7, 7, 7, 7,
83 7, 7, 7, 7, 7, 7, 7, 7,
84 8, 8, 8, 8, 8, 8, 8, 8,
85 8, 8, 8, 8, 8, 8, 8, 8,
86 8, 8, 8, 8, 8, 8, 8, 8,
87 8, 8, 8, 8, 8, 8, 8, 8,
88 8, 8, 8, 8, 8, 8, 8, 8,
89 8, 8, 8, 8, 8, 8, 8, 8,
90 8, 8, 8, 8, 8, 8, 8, 8,
91 8, 8, 8, 8, 8, 8, 8, 8,
92 8, 8, 8, 8, 8, 8, 8, 8,
93 8, 8, 8, 8, 8, 8, 8, 8,
94 8, 8, 8, 8, 8, 8, 8, 8,
95 8, 8, 8, 8, 8, 8, 8, 8,
96 8, 8, 8, 8, 8, 8, 8, 8,
97 8, 8, 8, 8, 8, 8, 8, 8,
98 8, 8, 8, 8, 8, 8, 8, 8,
99 8, 8, 8, 8, 8, 8, 8, 8,
100 };
101
102 void *_bcmutils_dummy_fn = NULL;
103
104
105
106
107 #ifdef BCMDRIVER
108
109
110 /* copy a pkt buffer chain into a buffer */
111 uint
112 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
113 {
114 uint n, ret = 0;
115
116 if (len < 0)
117 len = 4096; /* "infinite" */
118
119 /* skip 'offset' bytes */
120 for (; p && offset; p = PKTNEXT(osh, p)) {
121 if (offset < (uint)PKTLEN(osh, p))
122 break;
123 offset -= PKTLEN(osh, p);
124 }
125
126 if (!p)
127 return 0;
128
129 /* copy the data */
130 for (; p && len; p = PKTNEXT(osh, p)) {
131 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
132 bcopy(PKTDATA(osh, p) + offset, buf, n);
133 buf += n;
134 len -= n;
135 ret += n;
136 offset = 0;
137 }
138
139 return ret;
140 }
141
142 /* copy a buffer into a pkt buffer chain */
143 uint
144 pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
145 {
146 uint n, ret = 0;
147
148
149 /* skip 'offset' bytes */
150 for (; p && offset; p = PKTNEXT(osh, p)) {
151 if (offset < (uint)PKTLEN(osh, p))
152 break;
153 offset -= PKTLEN(osh, p);
154 }
155
156 if (!p)
157 return 0;
158
159 /* copy the data */
160 for (; p && len; p = PKTNEXT(osh, p)) {
161 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
162 bcopy(buf, PKTDATA(osh, p) + offset, n);
163 buf += n;
164 len -= n;
165 ret += n;
166 offset = 0;
167 }
168
169 return ret;
170 }
171
172
173
174 /* return total length of buffer chain */
175 uint BCMFASTPATH
176 pkttotlen(osl_t *osh, void *p)
177 {
178 uint total;
179 int len;
180
181 total = 0;
182 for (; p; p = PKTNEXT(osh, p)) {
183 len = PKTLEN(osh, p);
184 total += len;
185 #ifdef BCMLFRAG
186 if (BCMLFRAG_ENAB()) {
187 if (PKTISFRAG(osh, p)) {
188 total += PKTFRAGTOTLEN(osh, p);
189 }
190 }
191 #endif
192 }
193
194 return (total);
195 }
196
197 /* return the last buffer of chained pkt */
198 void *
199 pktlast(osl_t *osh, void *p)
200 {
201 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
202 ;
203
204 return (p);
205 }
206
207 /* count segments of a chained packet */
208 uint BCMFASTPATH
209 pktsegcnt(osl_t *osh, void *p)
210 {
211 uint cnt;
212
213 for (cnt = 0; p; p = PKTNEXT(osh, p)) {
214 cnt++;
215 #ifdef BCMLFRAG
216 if (BCMLFRAG_ENAB()) {
217 if (PKTISFRAG(osh, p)) {
218 cnt += PKTFRAGTOTNUM(osh, p);
219 }
220 }
221 #endif
222 }
223
224 return cnt;
225 }
226
227
228 /* count segments of a chained packet */
229 uint BCMFASTPATH
230 pktsegcnt_war(osl_t *osh, void *p)
231 {
232 uint cnt;
233 uint8 *pktdata;
234 uint len, remain, align64;
235
236 for (cnt = 0; p; p = PKTNEXT(osh, p)) {
237 cnt++;
238 len = PKTLEN(osh, p);
239 if (len > 128) {
240 pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */
241 /* Check for page boundary straddle (2048B) */
242 if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff))
243 cnt++;
244
245 align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */
246 align64 = (64 - align64) & 0x3f;
247 len -= align64; /* bytes from aligned 64B to end */
248 /* if aligned to 128B, check for MOD 128 between 1 to 4B */
249 remain = len % 128;
250 if (remain > 0 && remain <= 4)
251 cnt++; /* add extra seg */
252 }
253 }
254
255 return cnt;
256 }
257
258 uint8 * BCMFASTPATH
259 pktdataoffset(osl_t *osh, void *p, uint offset)
260 {
261 uint total = pkttotlen(osh, p);
262 uint pkt_off = 0, len = 0;
263 uint8 *pdata = (uint8 *) PKTDATA(osh, p);
264
265 if (offset > total)
266 return NULL;
267
268 for (; p; p = PKTNEXT(osh, p)) {
269 pdata = (uint8 *) PKTDATA(osh, p);
270 pkt_off = offset - len;
271 len += PKTLEN(osh, p);
272 if (len > offset)
273 break;
274 }
275 return (uint8*) (pdata+pkt_off);
276 }
277
278
279 /* given a offset in pdata, find the pkt seg hdr */
280 void *
281 pktoffset(osl_t *osh, void *p, uint offset)
282 {
283 uint total = pkttotlen(osh, p);
284 uint len = 0;
285
286 if (offset > total)
287 return NULL;
288
289 for (; p; p = PKTNEXT(osh, p)) {
290 len += PKTLEN(osh, p);
291 if (len > offset)
292 break;
293 }
294 return p;
295 }
296
297 #endif /* BCMDRIVER */
298
299 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
300 const unsigned char bcm_ctype[] = {
301
302 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
303 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
304 _BCM_C, /* 8-15 */
305 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
306 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
307 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
308 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
309 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
310 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
311 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
312 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
313 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
314 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
315 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
316 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
317 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
318 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
319 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
320 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
321 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
322 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
323 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
324 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
325 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
326 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
327 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
328 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
329 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
330 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
331 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
332 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
333 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
334 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
335 };
336
337 ulong
338 bcm_strtoul(const char *cp, char **endp, uint base)
339 {
340 ulong result, last_result = 0, value;
341 bool minus;
342
343 minus = FALSE;
344
345 while (bcm_isspace(*cp))
346 cp++;
347
348 if (cp[0] == '+')
349 cp++;
350 else if (cp[0] == '-') {
351 minus = TRUE;
352 cp++;
353 }
354
355 if (base == 0) {
356 if (cp[0] == '0') {
357 if ((cp[1] == 'x') || (cp[1] == 'X')) {
358 base = 16;
359 cp = &cp[2];
360 } else {
361 base = 8;
362 cp = &cp[1];
363 }
364 } else
365 base = 10;
366 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
367 cp = &cp[2];
368 }
369
370 result = 0;
371
372 while (bcm_isxdigit(*cp) &&
373 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
374 result = result*base + value;
375 /* Detected overflow */
376 if (result < last_result && !minus) {
377 if (endp) {
378 /* Go to the end of current number */
379 while (bcm_isxdigit(*cp)) {
380 cp++;
381 }
382 *endp = DISCARD_QUAL(cp, char);
383 }
384 return (ulong)-1;
385 }
386 last_result = result;
387 cp++;
388 }
389
390 if (minus)
391 result = (ulong)(-(long)result);
392
393 if (endp)
394 *endp = DISCARD_QUAL(cp, char);
395
396 return (result);
397 }
398
399 int
400 bcm_atoi(const char *s)
401 {
402 return (int)bcm_strtoul(s, NULL, 10);
403 }
404
405 /* return pointer to location of substring 'needle' in 'haystack' */
406 char *
407 bcmstrstr(const char *haystack, const char *needle)
408 {
409 int len, nlen;
410 int i;
411
412 if ((haystack == NULL) || (needle == NULL))
413 return DISCARD_QUAL(haystack, char);
414
415 nlen = (int)strlen(needle);
416 len = (int)strlen(haystack) - nlen + 1;
417
418 for (i = 0; i < len; i++)
419 if (memcmp(needle, &haystack[i], nlen) == 0)
420 return DISCARD_QUAL(&haystack[i], char);
421 return (NULL);
422 }
423
424 char *
425 bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len)
426 {
427 for (; s_len >= substr_len; s++, s_len--)
428 if (strncmp(s, substr, substr_len) == 0)
429 return DISCARD_QUAL(s, char);
430
431 return NULL;
432 }
433
434 char *
435 bcmstrcat(char *dest, const char *src)
436 {
437 char *p;
438
439 p = dest + strlen(dest);
440
441 while ((*p++ = *src++) != '\0')
442 ;
443
444 return (dest);
445 }
446
447 char *
448 bcmstrncat(char *dest, const char *src, uint size)
449 {
450 char *endp;
451 char *p;
452
453 p = dest + strlen(dest);
454 endp = p + size;
455
456 while (p != endp && (*p++ = *src++) != '\0')
457 ;
458
459 return (dest);
460 }
461
462
463 /****************************************************************************
464 * Function: bcmstrtok
465 *
466 * Purpose:
467 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
468 * but allows strToken() to be used by different strings or callers at the same
469 * time. Each call modifies '*string' by substituting a NULL character for the
470 * first delimiter that is encountered, and updates 'string' to point to the char
471 * after the delimiter. Leading delimiters are skipped.
472 *
473 * Parameters:
474 * string (mod) Ptr to string ptr, updated by token.
475 * delimiters (in) Set of delimiter characters.
476 * tokdelim (out) Character that delimits the returned token. (May
477 * be set to NULL if token delimiter is not required).
478 *
479 * Returns: Pointer to the next token found. NULL when no more tokens are found.
480 *****************************************************************************
481 */
482 char *
483 bcmstrtok(char **string, const char *delimiters, char *tokdelim)
484 {
485 unsigned char *str;
486 unsigned long map[8];
487 int count;
488 char *nextoken;
489
490 if (tokdelim != NULL) {
491 /* Prime the token delimiter */
492 *tokdelim = '\0';
493 }
494
495 /* Clear control map */
496 for (count = 0; count < 8; count++) {
497 map[count] = 0;
498 }
499
500 /* Set bits in delimiter table */
501 do {
502 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
503 }
504 while (*delimiters++);
505
506 str = (unsigned char*)*string;
507
508 /* Find beginning of token (skip over leading delimiters). Note that
509 * there is no token iff this loop sets str to point to the terminal
510 * null (*str == '\0')
511 */
512 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
513 str++;
514 }
515
516 nextoken = (char*)str;
517
518 /* Find the end of the token. If it is not the end of the string,
519 * put a null there.
520 */
521 for (; *str; str++) {
522 if (map[*str >> 5] & (1 << (*str & 31))) {
523 if (tokdelim != NULL) {
524 *tokdelim = *str;
525 }
526
527 *str++ = '\0';
528 break;
529 }
530 }
531
532 *string = (char*)str;
533
534 /* Determine if a token has been found. */
535 if (nextoken == (char *) str) {
536 return NULL;
537 }
538 else {
539 return nextoken;
540 }
541 }
542
543
544 #define xToLower(C) \
545 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
546
547
548 /****************************************************************************
549 * Function: bcmstricmp
550 *
551 * Purpose: Compare to strings case insensitively.
552 *
553 * Parameters: s1 (in) First string to compare.
554 * s2 (in) Second string to compare.
555 *
556 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
557 * t1 > t2, when ignoring case sensitivity.
558 *****************************************************************************
559 */
560 int
561 bcmstricmp(const char *s1, const char *s2)
562 {
563 char dc, sc;
564
565 while (*s2 && *s1) {
566 dc = xToLower(*s1);
567 sc = xToLower(*s2);
568 if (dc < sc) return -1;
569 if (dc > sc) return 1;
570 s1++;
571 s2++;
572 }
573
574 if (*s1 && !*s2) return 1;
575 if (!*s1 && *s2) return -1;
576 return 0;
577 }
578
579
580 /****************************************************************************
581 * Function: bcmstrnicmp
582 *
583 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
584 * characters.
585 *
586 * Parameters: s1 (in) First string to compare.
587 * s2 (in) Second string to compare.
588 * cnt (in) Max characters to compare.
589 *
590 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
591 * t1 > t2, when ignoring case sensitivity.
592 *****************************************************************************
593 */
594 int
595 bcmstrnicmp(const char* s1, const char* s2, int cnt)
596 {
597 char dc, sc;
598
599 while (*s2 && *s1 && cnt) {
600 dc = xToLower(*s1);
601 sc = xToLower(*s2);
602 if (dc < sc) return -1;
603 if (dc > sc) return 1;
604 s1++;
605 s2++;
606 cnt--;
607 }
608
609 if (!cnt) return 0;
610 if (*s1 && !*s2) return 1;
611 if (!*s1 && *s2) return -1;
612 return 0;
613 }
614
615 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
616 int
617 bcm_ether_atoe(const char *p, struct ether_addr *ea)
618 {
619 int i = 0;
620 char *ep;
621
622 for (;;) {
623 ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16);
624 p = ep;
625 if (!*p++ || i == 6)
626 break;
627 }
628
629 return (i == 6);
630 }
631
632 int
633 bcm_atoipv4(const char *p, struct ipv4_addr *ip)
634 {
635
636 int i = 0;
637 char *c;
638 for (;;) {
639 ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0);
640 if (*c++ != '.' || i == IPV4_ADDR_LEN)
641 break;
642 p = c;
643 }
644 return (i == IPV4_ADDR_LEN);
645 }
646 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
647
648
649 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
650 /* registry routine buffer preparation utility functions:
651 * parameter order is like strncpy, but returns count
652 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
653 */
654 ulong
655 wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
656 {
657 ulong copyct = 1;
658 ushort i;
659
660 if (abuflen == 0)
661 return 0;
662
663 /* wbuflen is in bytes */
664 wbuflen /= sizeof(ushort);
665
666 for (i = 0; i < wbuflen; ++i) {
667 if (--abuflen == 0)
668 break;
669 *abuf++ = (char) *wbuf++;
670 ++copyct;
671 }
672 *abuf = '\0';
673
674 return copyct;
675 }
676 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
677
678 char *
679 bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
680 {
681 static const char hex[] =
682 {
683 '0', '1', '2', '3', '4', '5', '6', '7',
684 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
685 };
686 const uint8 *octet = ea->octet;
687 char *p = buf;
688 int i;
689
690 for (i = 0; i < 6; i++, octet++) {
691 *p++ = hex[(*octet >> 4) & 0xf];
692 *p++ = hex[*octet & 0xf];
693 *p++ = ':';
694 }
695
696 *(p-1) = '\0';
697
698 return (buf);
699 }
700
701 char *
702 bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
703 {
704 snprintf(buf, 16, "%d.%d.%d.%d",
705 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
706 return (buf);
707 }
708
709 char *
710 bcm_ipv6_ntoa(void *ipv6, char *buf)
711 {
712 /* Implementing RFC 5952 Sections 4 + 5 */
713 /* Not thoroughly tested */
714 uint16 tmp[8];
715 uint16 *a = &tmp[0];
716 char *p = buf;
717 int i, i_max = -1, cnt = 0, cnt_max = 1;
718 uint8 *a4 = NULL;
719 memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN);
720
721 for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
722 if (a[i]) {
723 if (cnt > cnt_max) {
724 cnt_max = cnt;
725 i_max = i - cnt;
726 }
727 cnt = 0;
728 } else
729 cnt++;
730 }
731 if (cnt > cnt_max) {
732 cnt_max = cnt;
733 i_max = i - cnt;
734 }
735 if (i_max == 0 &&
736 /* IPv4-translated: ::ffff:0:a.b.c.d */
737 ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) ||
738 /* IPv4-mapped: ::ffff:a.b.c.d */
739 (cnt_max == 5 && a[5] == 0xffff)))
740 a4 = (uint8*) (a + 6);
741
742 for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
743 if ((uint8*) (a + i) == a4) {
744 snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]);
745 break;
746 } else if (i == i_max) {
747 *p++ = ':';
748 i += cnt_max - 1;
749 p[0] = ':';
750 p[1] = '\0';
751 } else {
752 if (i)
753 *p++ = ':';
754 p += snprintf(p, 8, "%x", ntoh16(a[i]));
755 }
756 }
757
758 return buf;
759 }
760 #ifdef BCMDRIVER
761
762 void
763 bcm_mdelay(uint ms)
764 {
765 uint i;
766
767 for (i = 0; i < ms; i++) {
768 OSL_DELAY(1000);
769 }
770 }
771
772
773
774
775
776 #if defined(DHD_DEBUG)
777 /* pretty hex print a pkt buffer chain */
778 void
779 prpkt(const char *msg, osl_t *osh, void *p0)
780 {
781 void *p;
782
783 if (msg && (msg[0] != '\0'))
784 printf("%s:\n", msg);
785
786 for (p = p0; p; p = PKTNEXT(osh, p))
787 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
788 }
789 #endif
790
791 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
792 * Also updates the inplace vlan tag if requested.
793 * For debugging, it returns an indication of what it did.
794 */
795 uint BCMFASTPATH
796 pktsetprio(void *pkt, bool update_vtag)
797 {
798 struct ether_header *eh;
799 struct ethervlan_header *evh;
800 uint8 *pktdata;
801 int priority = 0;
802 int rc = 0;
803
804 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
805 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
806
807 eh = (struct ether_header *) pktdata;
808
809 if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
810 uint16 vlan_tag;
811 int vlan_prio, dscp_prio = 0;
812
813 evh = (struct ethervlan_header *)eh;
814
815 vlan_tag = ntoh16(evh->vlan_tag);
816 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
817
818 if ((evh->ether_type == hton16(ETHER_TYPE_IP)) ||
819 (evh->ether_type == hton16(ETHER_TYPE_IPV6))) {
820 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
821 uint8 tos_tc = IP_TOS46(ip_body);
822 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
823 }
824
825 /* DSCP priority gets precedence over 802.1P (vlan tag) */
826 if (dscp_prio != 0) {
827 priority = dscp_prio;
828 rc |= PKTPRIO_VDSCP;
829 } else {
830 priority = vlan_prio;
831 rc |= PKTPRIO_VLAN;
832 }
833 /*
834 * If the DSCP priority is not the same as the VLAN priority,
835 * then overwrite the priority field in the vlan tag, with the
836 * DSCP priority value. This is required for Linux APs because
837 * the VLAN driver on Linux, overwrites the skb->priority field
838 * with the priority value in the vlan tag
839 */
840 if (update_vtag && (priority != vlan_prio)) {
841 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
842 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
843 evh->vlan_tag = hton16(vlan_tag);
844 rc |= PKTPRIO_UPD;
845 }
846 #if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING)
847 } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
848 priority = PRIO_8021D_NC;
849 rc = PKTPRIO_DSCP;
850 #endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */
851 } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) ||
852 (eh->ether_type == hton16(ETHER_TYPE_IPV6))) {
853 uint8 *ip_body = pktdata + sizeof(struct ether_header);
854 uint8 tos_tc = IP_TOS46(ip_body);
855 uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT;
856 switch (dscp) {
857 case DSCP_EF:
858 priority = PRIO_8021D_VO;
859 break;
860 case DSCP_AF31:
861 case DSCP_AF32:
862 case DSCP_AF33:
863 priority = PRIO_8021D_CL;
864 break;
865 case DSCP_AF21:
866 case DSCP_AF22:
867 case DSCP_AF23:
868 case DSCP_AF11:
869 case DSCP_AF12:
870 case DSCP_AF13:
871 priority = PRIO_8021D_EE;
872 break;
873 default:
874 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
875 break;
876 }
877
878 rc |= PKTPRIO_DSCP;
879 }
880
881 ASSERT(priority >= 0 && priority <= MAXPRIO);
882 PKTSETPRIO(pkt, priority);
883 return (rc | priority);
884 }
885
886 /* lookup user priority for specified DSCP */
887 static uint8
888 dscp2up(uint8 *up_table, uint8 dscp)
889 {
890 uint8 user_priority = 255;
891
892 /* lookup up from table if parameters valid */
893 if (up_table != NULL && dscp < UP_TABLE_MAX) {
894 user_priority = up_table[dscp];
895 }
896
897 /* 255 is unused value so return up from dscp */
898 if (user_priority == 255) {
899 user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT);
900 }
901
902 return user_priority;
903 }
904
905 /* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */
906 uint BCMFASTPATH
907 pktsetprio_qms(void *pkt, uint8* up_table, bool update_vtag)
908 {
909 if (up_table) {
910 uint8 *pktdata;
911 uint pktlen;
912 uint8 dscp;
913 uint user_priority = 0;
914 uint rc = 0;
915
916 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
917 pktlen = PKTLEN(OSH_NULL, pkt);
918
919 if (pktgetdscp(pktdata, pktlen, &dscp)) {
920 rc = PKTPRIO_DSCP;
921 user_priority = dscp2up(up_table, dscp);
922 PKTSETPRIO(pkt, user_priority);
923 }
924
925 return (rc | user_priority);
926 } else {
927 return pktsetprio(pkt, update_vtag);
928 }
929 }
930
931 /* Returns TRUE and DSCP if IP header found, FALSE otherwise.
932 */
933 bool BCMFASTPATH
934 pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp)
935 {
936 struct ether_header *eh;
937 struct ethervlan_header *evh;
938 uint8 *ip_body;
939 bool rc = FALSE;
940
941 /* minimum length is ether header and IP header */
942 if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN)
943 return FALSE;
944
945 eh = (struct ether_header *) pktdata;
946
947 if (eh->ether_type == HTON16(ETHER_TYPE_IP)) {
948 ip_body = pktdata + sizeof(struct ether_header);
949 *dscp = IP_DSCP46(ip_body);
950 rc = TRUE;
951 }
952 else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) {
953 evh = (struct ethervlan_header *)eh;
954
955 /* minimum length is ethervlan header and IP header */
956 if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN &&
957 evh->ether_type == HTON16(ETHER_TYPE_IP)) {
958 ip_body = pktdata + sizeof(struct ethervlan_header);
959 *dscp = IP_DSCP46(ip_body);
960 rc = TRUE;
961 }
962 }
963
964 return rc;
965 }
966
967 /* Add to adjust the 802.1x priority */
968 void
969 pktset8021xprio(void *pkt, int prio)
970 {
971 struct ether_header *eh;
972 uint8 *pktdata;
973 if(prio == PKTPRIO(pkt))
974 return;
975 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
976 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
977 eh = (struct ether_header *) pktdata;
978 if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
979 ASSERT(prio >= 0 && prio <= MAXPRIO);
980 PKTSETPRIO(pkt, prio);
981 }
982 }
983
984 /* usr_prio range from low to high with usr_prio value */
985 static bool
986 up_table_set(uint8 *up_table, uint8 usr_prio, uint8 low, uint8 high)
987 {
988 int i;
989
990 if (usr_prio > 7 || low > high || low >= UP_TABLE_MAX || high >= UP_TABLE_MAX) {
991 return FALSE;
992 }
993
994 for (i = low; i <= high; i++) {
995 up_table[i] = usr_prio;
996 }
997
998 return TRUE;
999 }
1000
1001 /* set user priority table */
1002 int BCMFASTPATH
1003 wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie)
1004 {
1005 uint8 len;
1006
1007 if (up_table == NULL || qos_map_ie == NULL) {
1008 return BCME_ERROR;
1009 }
1010
1011 /* clear table to check table was set or not */
1012 memset(up_table, 0xff, UP_TABLE_MAX);
1013
1014 /* length of QoS Map IE must be 16+n*2, n is number of exceptions */
1015 if (qos_map_ie != NULL && qos_map_ie->id == DOT11_MNG_QOS_MAP_ID &&
1016 (len = qos_map_ie->len) >= QOS_MAP_FIXED_LENGTH &&
1017 (len % 2) == 0) {
1018 uint8 *except_ptr = (uint8 *)qos_map_ie->data;
1019 uint8 except_len = len - QOS_MAP_FIXED_LENGTH;
1020 uint8 *range_ptr = except_ptr + except_len;
1021 int i;
1022
1023 /* fill in ranges */
1024 for (i = 0; i < QOS_MAP_FIXED_LENGTH; i += 2) {
1025 uint8 low = range_ptr[i];
1026 uint8 high = range_ptr[i + 1];
1027 if (low == 255 && high == 255) {
1028 continue;
1029 }
1030
1031 if (!up_table_set(up_table, i / 2, low, high)) {
1032 /* clear the table on failure */
1033 memset(up_table, 0xff, UP_TABLE_MAX);
1034 return BCME_ERROR;
1035 }
1036 }
1037
1038 /* update exceptions */
1039 for (i = 0; i < except_len; i += 2) {
1040 uint8 dscp = except_ptr[i];
1041 uint8 usr_prio = except_ptr[i+1];
1042
1043 /* exceptions with invalid dscp/usr_prio are ignored */
1044 up_table_set(up_table, usr_prio, dscp, dscp);
1045 }
1046 }
1047
1048 return BCME_OK;
1049 }
1050
1051 /* The 0.5KB string table is not removed by compiler even though it's unused */
1052
1053 static char bcm_undeferrstr[32];
1054 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
1055
1056 /* Convert the error codes into related error strings */
1057 const char *
1058 bcmerrorstr(int bcmerror)
1059 {
1060 /* check if someone added a bcmerror code but forgot to add errorstring */
1061 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
1062
1063 if (bcmerror > 0 || bcmerror < BCME_LAST) {
1064 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
1065 return bcm_undeferrstr;
1066 }
1067
1068 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
1069
1070 return bcmerrorstrtable[-bcmerror];
1071 }
1072
1073
1074 /* iovar table lookup */
1075 /* could mandate sorted tables and do a binary search */
1076 const bcm_iovar_t*
1077 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
1078 {
1079 const bcm_iovar_t *vi;
1080 const char *lookup_name;
1081
1082 /* skip any ':' delimited option prefixes */
1083 lookup_name = strrchr(name, ':');
1084 if (lookup_name != NULL)
1085 lookup_name++;
1086 else
1087 lookup_name = name;
1088
1089 ASSERT(table != NULL);
1090
1091 for (vi = table; vi->name; vi++) {
1092 if (!strcmp(vi->name, lookup_name))
1093 return vi;
1094 }
1095 /* ran to end of table */
1096
1097 return NULL; /* var name not found */
1098 }
1099
1100 int
1101 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
1102 {
1103 int bcmerror = 0;
1104 BCM_REFERENCE(arg);
1105
1106 /* length check on io buf */
1107 switch (vi->type) {
1108 case IOVT_BOOL:
1109 case IOVT_INT8:
1110 case IOVT_INT16:
1111 case IOVT_INT32:
1112 case IOVT_UINT8:
1113 case IOVT_UINT16:
1114 case IOVT_UINT32:
1115 /* all integers are int32 sized args at the ioctl interface */
1116 if (len < (int)sizeof(int)) {
1117 bcmerror = BCME_BUFTOOSHORT;
1118 }
1119 break;
1120
1121 case IOVT_BUFFER:
1122 /* buffer must meet minimum length requirement */
1123 if (len < vi->minlen) {
1124 bcmerror = BCME_BUFTOOSHORT;
1125 }
1126 break;
1127
1128 case IOVT_VOID:
1129 if (!set) {
1130 /* Cannot return nil... */
1131 bcmerror = BCME_UNSUPPORTED;
1132 } else if (len) {
1133 /* Set is an action w/o parameters */
1134 bcmerror = BCME_BUFTOOLONG;
1135 }
1136 break;
1137
1138 default:
1139 /* unknown type for length check in iovar info */
1140 ASSERT(0);
1141 bcmerror = BCME_UNSUPPORTED;
1142 }
1143
1144 return bcmerror;
1145 }
1146
1147 #endif /* BCMDRIVER */
1148
1149 #ifdef BCM_OBJECT_TRACE
1150
1151 #define BCM_OBJECT_MERGE_SAME_OBJ 0
1152
1153 /* some place may add / remove the object to trace list for Linux: */
1154 /* add: osl_alloc_skb dev_alloc_skb skb_realloc_headroom dhd_start_xmit */
1155 /* remove: osl_pktfree dev_kfree_skb netif_rx */
1156
1157 #define BCM_OBJDBG_COUNT (1024 * 100)
1158 static spinlock_t dbgobj_lock;
1159 #define BCM_OBJDBG_LOCK_INIT() spin_lock_init(&dbgobj_lock)
1160 #define BCM_OBJDBG_LOCK_DESTROY()
1161 #define BCM_OBJDBG_LOCK spin_lock_irqsave
1162 #define BCM_OBJDBG_UNLOCK spin_unlock_irqrestore
1163
1164 #define BCM_OBJDBG_ADDTOHEAD 0
1165 #define BCM_OBJDBG_ADDTOTAIL 1
1166
1167 #define BCM_OBJDBG_CALLER_LEN 32
1168 struct bcm_dbgobj {
1169 struct bcm_dbgobj *prior;
1170 struct bcm_dbgobj *next;
1171 uint32 flag;
1172 void *obj;
1173 uint32 obj_sn;
1174 uint32 obj_state;
1175 uint32 line;
1176 char caller[BCM_OBJDBG_CALLER_LEN];
1177 };
1178
1179 static struct bcm_dbgobj *dbgobj_freehead = NULL;
1180 static struct bcm_dbgobj *dbgobj_freetail = NULL;
1181 static struct bcm_dbgobj *dbgobj_objhead = NULL;
1182 static struct bcm_dbgobj *dbgobj_objtail = NULL;
1183
1184 static uint32 dbgobj_sn = 0;
1185 static int dbgobj_count = 0;
1186 static struct bcm_dbgobj bcm_dbg_objs[BCM_OBJDBG_COUNT];
1187
1188 void
1189 bcm_object_trace_init(void)
1190 {
1191 int i = 0;
1192 BCM_OBJDBG_LOCK_INIT();
1193 memset(&bcm_dbg_objs, 0x00, sizeof(struct bcm_dbgobj) * BCM_OBJDBG_COUNT);
1194 dbgobj_freehead = &bcm_dbg_objs[0];
1195 dbgobj_freetail = &bcm_dbg_objs[BCM_OBJDBG_COUNT - 1];
1196
1197 for (i = 0; i < BCM_OBJDBG_COUNT; ++i) {
1198 bcm_dbg_objs[i].next = (i == (BCM_OBJDBG_COUNT - 1)) ?
1199 dbgobj_freehead : &bcm_dbg_objs[i + 1];
1200 bcm_dbg_objs[i].prior = (i == 0) ?
1201 dbgobj_freetail : &bcm_dbg_objs[i - 1];
1202 }
1203 }
1204
1205 void
1206 bcm_object_trace_deinit(void)
1207 {
1208 if (dbgobj_objhead || dbgobj_objtail) {
1209 printf("%s: not all objects are released\n", __FUNCTION__);
1210 ASSERT(0);
1211 }
1212 BCM_OBJDBG_LOCK_DESTROY();
1213 }
1214
1215 static void
1216 bcm_object_rm_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
1217 struct bcm_dbgobj *dbgobj)
1218 {
1219 if ((dbgobj == *head) && (dbgobj == *tail)) {
1220 *head = NULL;
1221 *tail = NULL;
1222 } else if (dbgobj == *head) {
1223 *head = (*head)->next;
1224 } else if (dbgobj == *tail) {
1225 *tail = (*tail)->prior;
1226 }
1227 dbgobj->next->prior = dbgobj->prior;
1228 dbgobj->prior->next = dbgobj->next;
1229 }
1230
1231 static void
1232 bcm_object_add_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
1233 struct bcm_dbgobj *dbgobj, int addtotail)
1234 {
1235 if (!(*head) && !(*tail)) {
1236 *head = dbgobj;
1237 *tail = dbgobj;
1238 dbgobj->next = dbgobj;
1239 dbgobj->prior = dbgobj;
1240 } else if ((*head) && (*tail)) {
1241 (*tail)->next = dbgobj;
1242 (*head)->prior = dbgobj;
1243 dbgobj->next = *head;
1244 dbgobj->prior = *tail;
1245 if (addtotail == BCM_OBJDBG_ADDTOTAIL)
1246 *tail = dbgobj;
1247 else
1248 *head = dbgobj;
1249 } else {
1250 ASSERT(0); /* can't be this case */
1251 }
1252 }
1253
1254 static INLINE void
1255 bcm_object_movetoend(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
1256 struct bcm_dbgobj *dbgobj, int movetotail)
1257 {
1258 if ((*head) && (*tail)) {
1259 if (movetotail == BCM_OBJDBG_ADDTOTAIL) {
1260 if (dbgobj != (*tail)) {
1261 bcm_object_rm_list(head, tail, dbgobj);
1262 bcm_object_add_list(head, tail, dbgobj, movetotail);
1263 }
1264 } else {
1265 if (dbgobj != (*head)) {
1266 bcm_object_rm_list(head, tail, dbgobj);
1267 bcm_object_add_list(head, tail, dbgobj, movetotail);
1268 }
1269 }
1270 } else {
1271 ASSERT(0); /* can't be this case */
1272 }
1273 }
1274
1275 void
1276 bcm_object_trace_opr(void *obj, uint32 opt, const char *caller, int line)
1277 {
1278 struct bcm_dbgobj *dbgobj;
1279 unsigned long flags;
1280
1281 BCM_REFERENCE(flags);
1282 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1283
1284 if (opt == BCM_OBJDBG_ADD_PKT ||
1285 opt == BCM_OBJDBG_ADD) {
1286 dbgobj = dbgobj_objtail;
1287 while (dbgobj) {
1288 if (dbgobj->obj == obj) {
1289 printf("%s: obj %p allocated from %s(%d),"
1290 " allocate again from %s(%d)\n",
1291 __FUNCTION__, dbgobj->obj,
1292 dbgobj->caller, dbgobj->line,
1293 caller, line);
1294 ASSERT(0);
1295 goto EXIT;
1296 }
1297 dbgobj = dbgobj->prior;
1298 if (dbgobj == dbgobj_objtail)
1299 break;
1300 }
1301
1302 #if BCM_OBJECT_MERGE_SAME_OBJ
1303 dbgobj = dbgobj_freetail;
1304 while (dbgobj) {
1305 if (dbgobj->obj == obj) {
1306 goto FREED_ENTRY_FOUND;
1307 }
1308 dbgobj = dbgobj->prior;
1309 if (dbgobj == dbgobj_freetail)
1310 break;
1311 }
1312 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
1313
1314 dbgobj = dbgobj_freehead;
1315 #if BCM_OBJECT_MERGE_SAME_OBJ
1316 FREED_ENTRY_FOUND:
1317 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
1318 if (!dbgobj) {
1319 printf("%s: already got %d objects ?????????????????????\n",
1320 __FUNCTION__, BCM_OBJDBG_COUNT);
1321 ASSERT(0);
1322 goto EXIT;
1323 }
1324
1325 bcm_object_rm_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj);
1326 dbgobj->obj = obj;
1327 strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN);
1328 dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0';
1329 dbgobj->line = line;
1330 dbgobj->flag = 0;
1331 if (opt == BCM_OBJDBG_ADD_PKT) {
1332 dbgobj->obj_sn = dbgobj_sn++;
1333 dbgobj->obj_state = 0;
1334 /* first 4 bytes is pkt sn */
1335 if (((unsigned long)PKTTAG(obj)) & 0x3)
1336 printf("pkt tag address not aligned by 4: %p\n", PKTTAG(obj));
1337 *(uint32*)PKTTAG(obj) = dbgobj->obj_sn;
1338 }
1339 bcm_object_add_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj,
1340 BCM_OBJDBG_ADDTOTAIL);
1341
1342 dbgobj_count++;
1343
1344 } else if (opt == BCM_OBJDBG_REMOVE) {
1345 dbgobj = dbgobj_objtail;
1346 while (dbgobj) {
1347 if (dbgobj->obj == obj) {
1348 if (dbgobj->flag) {
1349 printf("%s: rm flagged obj %p flag 0x%08x from %s(%d)\n",
1350 __FUNCTION__, obj, dbgobj->flag, caller, line);
1351 }
1352 bcm_object_rm_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj);
1353 memset(dbgobj->caller, 0x00, BCM_OBJDBG_CALLER_LEN);
1354 strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN);
1355 dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0';
1356 dbgobj->line = line;
1357 bcm_object_add_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj,
1358 BCM_OBJDBG_ADDTOTAIL);
1359 dbgobj_count--;
1360 goto EXIT;
1361 }
1362 dbgobj = dbgobj->prior;
1363 if (dbgobj == dbgobj_objtail)
1364 break;
1365 }
1366
1367 dbgobj = dbgobj_freetail;
1368 while (dbgobj && dbgobj->obj) {
1369 if (dbgobj->obj == obj) {
1370 printf("%s: obj %p already freed from from %s(%d),"
1371 " try free again from %s(%d)\n",
1372 __FUNCTION__, obj,
1373 dbgobj->caller, dbgobj->line,
1374 caller, line);
1375 //ASSERT(0); /* release same obj more than one time? */
1376 goto EXIT;
1377 }
1378 dbgobj = dbgobj->prior;
1379 if (dbgobj == dbgobj_freetail)
1380 break;
1381 }
1382
1383 printf("%s: ################### release none-existing obj %p from %s(%d)\n",
1384 __FUNCTION__, obj, caller, line);
1385 //ASSERT(0); /* release same obj more than one time? */
1386
1387 }
1388
1389 EXIT:
1390 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1391 return;
1392 }
1393
1394 void
1395 bcm_object_trace_upd(void *obj, void *obj_new)
1396 {
1397 struct bcm_dbgobj *dbgobj;
1398 unsigned long flags;
1399
1400 BCM_REFERENCE(flags);
1401 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1402
1403 dbgobj = dbgobj_objtail;
1404 while (dbgobj) {
1405 if (dbgobj->obj == obj) {
1406 dbgobj->obj = obj_new;
1407 if (dbgobj != dbgobj_objtail) {
1408 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
1409 dbgobj, BCM_OBJDBG_ADDTOTAIL);
1410 }
1411 goto EXIT;
1412 }
1413 dbgobj = dbgobj->prior;
1414 if (dbgobj == dbgobj_objtail)
1415 break;
1416 }
1417
1418 EXIT:
1419 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1420 return;
1421 }
1422
1423 void
1424 bcm_object_trace_chk(void *obj, uint32 chksn, uint32 sn,
1425 const char *caller, int line)
1426 {
1427 struct bcm_dbgobj *dbgobj;
1428 unsigned long flags;
1429
1430 BCM_REFERENCE(flags);
1431 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1432
1433 dbgobj = dbgobj_objtail;
1434 while (dbgobj) {
1435 if ((dbgobj->obj == obj) &&
1436 ((!chksn) || (dbgobj->obj_sn == sn))) {
1437 if (dbgobj != dbgobj_objtail) {
1438 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
1439 dbgobj, BCM_OBJDBG_ADDTOTAIL);
1440 }
1441 goto EXIT;
1442 }
1443 dbgobj = dbgobj->prior;
1444 if (dbgobj == dbgobj_objtail)
1445 break;
1446 }
1447
1448 dbgobj = dbgobj_freetail;
1449 while (dbgobj) {
1450 if ((dbgobj->obj == obj) &&
1451 ((!chksn) || (dbgobj->obj_sn == sn))) {
1452 printf("%s: (%s:%d) obj %p (sn %d state %d) was freed from %s(%d)\n",
1453 __FUNCTION__, caller, line,
1454 dbgobj->obj, dbgobj->obj_sn, dbgobj->obj_state,
1455 dbgobj->caller, dbgobj->line);
1456 goto EXIT;
1457 }
1458 else if (dbgobj->obj == NULL) {
1459 break;
1460 }
1461 dbgobj = dbgobj->prior;
1462 if (dbgobj == dbgobj_freetail)
1463 break;
1464 }
1465
1466 printf("%s: obj %p not found, check from %s(%d), chksn %s, sn %d\n",
1467 __FUNCTION__, obj, caller, line, chksn ? "yes" : "no", sn);
1468 dbgobj = dbgobj_objtail;
1469 while (dbgobj) {
1470 printf("%s: (%s:%d) obj %p sn %d was allocated from %s(%d)\n",
1471 __FUNCTION__, caller, line,
1472 dbgobj->obj, dbgobj->obj_sn, dbgobj->caller, dbgobj->line);
1473 dbgobj = dbgobj->prior;
1474 if (dbgobj == dbgobj_objtail)
1475 break;
1476 }
1477
1478 EXIT:
1479 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1480 return;
1481 }
1482
1483 void
1484 bcm_object_feature_set(void *obj, uint32 type, uint32 value)
1485 {
1486 struct bcm_dbgobj *dbgobj;
1487 unsigned long flags;
1488
1489 BCM_REFERENCE(flags);
1490 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1491
1492 dbgobj = dbgobj_objtail;
1493 while (dbgobj) {
1494 if (dbgobj->obj == obj) {
1495 if (type == BCM_OBJECT_FEATURE_FLAG) {
1496 if (value & BCM_OBJECT_FEATURE_CLEAR)
1497 dbgobj->flag &= ~(value);
1498 else
1499 dbgobj->flag |= (value);
1500 } else if (type == BCM_OBJECT_FEATURE_PKT_STATE) {
1501 dbgobj->obj_state = value;
1502 }
1503 if (dbgobj != dbgobj_objtail) {
1504 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
1505 dbgobj, BCM_OBJDBG_ADDTOTAIL);
1506 }
1507 goto EXIT;
1508 }
1509 dbgobj = dbgobj->prior;
1510 if (dbgobj == dbgobj_objtail)
1511 break;
1512 }
1513
1514 printf("%s: obj %p not found in active list\n", __FUNCTION__, obj);
1515 ASSERT(0);
1516
1517 EXIT:
1518 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1519 return;
1520 }
1521
1522 int
1523 bcm_object_feature_get(void *obj, uint32 type, uint32 value)
1524 {
1525 int rtn = 0;
1526 struct bcm_dbgobj *dbgobj;
1527 unsigned long flags;
1528
1529 BCM_REFERENCE(flags);
1530 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1531
1532 dbgobj = dbgobj_objtail;
1533 while (dbgobj) {
1534 if (dbgobj->obj == obj) {
1535 if (type == BCM_OBJECT_FEATURE_FLAG) {
1536 rtn = (dbgobj->flag & value) & (~BCM_OBJECT_FEATURE_CLEAR);
1537 }
1538 if (dbgobj != dbgobj_objtail) {
1539 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
1540 dbgobj, BCM_OBJDBG_ADDTOTAIL);
1541 }
1542 goto EXIT;
1543 }
1544 dbgobj = dbgobj->prior;
1545 if (dbgobj == dbgobj_objtail)
1546 break;
1547 }
1548
1549 printf("%s: obj %p not found in active list\n", __FUNCTION__, obj);
1550 ASSERT(0);
1551
1552 EXIT:
1553 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1554 return rtn;
1555 }
1556
1557 #endif /* BCM_OBJECT_TRACE */
1558
1559 uint8 *
1560 bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst)
1561 {
1562 uint8 *new_dst = dst;
1563 bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst;
1564
1565 /* dst buffer should always be valid */
1566 ASSERT(dst);
1567
1568 /* data len must be within valid range */
1569 ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE));
1570
1571 /* source data buffer pointer should be valid, unless datalen is 0
1572 * meaning no data with this TLV
1573 */
1574 ASSERT((data != NULL) || (datalen == 0));
1575
1576 /* only do work if the inputs are valid
1577 * - must have a dst to write to AND
1578 * - datalen must be within range AND
1579 * - the source data pointer must be non-NULL if datalen is non-zero
1580 * (this last condition detects datalen > 0 with a NULL data pointer)
1581 */
1582 if ((dst != NULL) &&
1583 ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) &&
1584 ((data != NULL) || (datalen == 0))) {
1585
1586 /* write type, len fields */
1587 dst_tlv->id = (uint8)type;
1588 dst_tlv->len = (uint8)datalen;
1589
1590 /* if data is present, copy to the output buffer and update
1591 * pointer to output buffer
1592 */
1593 if (datalen > 0) {
1594
1595 memcpy(dst_tlv->data, data, datalen);
1596 }
1597
1598 /* update the output destination poitner to point past
1599 * the TLV written
1600 */
1601 new_dst = dst + BCM_TLV_HDR_SIZE + datalen;
1602 }
1603
1604 return (new_dst);
1605 }
1606
1607 uint8 *
1608 bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen)
1609 {
1610 uint8 *new_dst = dst;
1611
1612 if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) {
1613
1614 /* if len + tlv hdr len is more than destlen, don't do anything
1615 * just return the buffer untouched
1616 */
1617 if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) {
1618
1619 new_dst = bcm_write_tlv(type, data, datalen, dst);
1620 }
1621 }
1622
1623 return (new_dst);
1624 }
1625
1626 uint8 *
1627 bcm_copy_tlv(const void *src, uint8 *dst)
1628 {
1629 uint8 *new_dst = dst;
1630 const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
1631 uint totlen;
1632
1633 ASSERT(dst && src);
1634 if (dst && src) {
1635
1636 totlen = BCM_TLV_HDR_SIZE + src_tlv->len;
1637 memcpy(dst, src_tlv, totlen);
1638 new_dst = dst + totlen;
1639 }
1640
1641 return (new_dst);
1642 }
1643
1644
1645 uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen)
1646 {
1647 uint8 *new_dst = dst;
1648 const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
1649
1650 ASSERT(src);
1651 if (src) {
1652 if (bcm_valid_tlv(src_tlv, dst_maxlen)) {
1653 new_dst = bcm_copy_tlv(src, dst);
1654 }
1655 }
1656
1657 return (new_dst);
1658 }
1659
1660
1661 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
1662 /*******************************************************************************
1663 * crc8
1664 *
1665 * Computes a crc8 over the input data using the polynomial:
1666 *
1667 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1668 *
1669 * The caller provides the initial value (either CRC8_INIT_VALUE
1670 * or the previous returned value) to allow for processing of
1671 * discontiguous blocks of data. When generating the CRC the
1672 * caller is responsible for complementing the final return value
1673 * and inserting it into the byte stream. When checking, a final
1674 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1675 *
1676 * Reference: Dallas Semiconductor Application Note 27
1677 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1678 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1679 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1680 *
1681 * ****************************************************************************
1682 */
1683
1684 static const uint8 crc8_table[256] = {
1685 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1686 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1687 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1688 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1689 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1690 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1691 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1692 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1693 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1694 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1695 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1696 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1697 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1698 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1699 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1700 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1701 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1702 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1703 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1704 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1705 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1706 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1707 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1708 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1709 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1710 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1711 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1712 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1713 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1714 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1715 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1716 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1717 };
1718
1719 #define CRC_INNER_LOOP(n, c, x) \
1720 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1721
1722 uint8
1723 hndcrc8(
1724 uint8 *pdata, /* pointer to array of data to process */
1725 uint nbytes, /* number of input data bytes to process */
1726 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1727 )
1728 {
1729 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1730 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1731 */
1732 while (nbytes-- > 0)
1733 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1734
1735 return crc;
1736 }
1737
1738 /*******************************************************************************
1739 * crc16
1740 *
1741 * Computes a crc16 over the input data using the polynomial:
1742 *
1743 * x^16 + x^12 +x^5 + 1
1744 *
1745 * The caller provides the initial value (either CRC16_INIT_VALUE
1746 * or the previous returned value) to allow for processing of
1747 * discontiguous blocks of data. When generating the CRC the
1748 * caller is responsible for complementing the final return value
1749 * and inserting it into the byte stream. When checking, a final
1750 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1751 *
1752 * Reference: Dallas Semiconductor Application Note 27
1753 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1754 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1755 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1756 *
1757 * ****************************************************************************
1758 */
1759
1760 static const uint16 crc16_table[256] = {
1761 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1762 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1763 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1764 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1765 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1766 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1767 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1768 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1769 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1770 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1771 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1772 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1773 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1774 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1775 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1776 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1777 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1778 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1779 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1780 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1781 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1782 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1783 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1784 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1785 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1786 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1787 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1788 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1789 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1790 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1791 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1792 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1793 };
1794
1795 uint16
1796 hndcrc16(
1797 uint8 *pdata, /* pointer to array of data to process */
1798 uint nbytes, /* number of input data bytes to process */
1799 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1800 )
1801 {
1802 while (nbytes-- > 0)
1803 CRC_INNER_LOOP(16, crc, *pdata++);
1804 return crc;
1805 }
1806
1807 static const uint32 crc32_table[256] = {
1808 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1809 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1810 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1811 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1812 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1813 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1814 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1815 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1816 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1817 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1818 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1819 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1820 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1821 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1822 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1823 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1824 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1825 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1826 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1827 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1828 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1829 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1830 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1831 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1832 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1833 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1834 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1835 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1836 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1837 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1838 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1839 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1840 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1841 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1842 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1843 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1844 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1845 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1846 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1847 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1848 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1849 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1850 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1851 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1852 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1853 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1854 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1855 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1856 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1857 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1858 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1859 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1860 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1861 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1862 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1863 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1864 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1865 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1866 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1867 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1868 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1869 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1870 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1871 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1872 };
1873
1874 /*
1875 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
1876 * accumulating over multiple pieces.
1877 */
1878 uint32
1879 hndcrc32(uint8 *pdata, uint nbytes, uint32 crc)
1880 {
1881 uint8 *pend;
1882 pend = pdata + nbytes;
1883 while (pdata < pend)
1884 CRC_INNER_LOOP(32, crc, *pdata++);
1885
1886 return crc;
1887 }
1888
1889 #ifdef notdef
1890 #define CLEN 1499 /* CRC Length */
1891 #define CBUFSIZ (CLEN+4)
1892 #define CNBUFS 5 /* # of bufs */
1893
1894 void
1895 testcrc32(void)
1896 {
1897 uint j, k, l;
1898 uint8 *buf;
1899 uint len[CNBUFS];
1900 uint32 crcr;
1901 uint32 crc32tv[CNBUFS] =
1902 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1903
1904 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1905
1906 /* step through all possible alignments */
1907 for (l = 0; l <= 4; l++) {
1908 for (j = 0; j < CNBUFS; j++) {
1909 len[j] = CLEN;
1910 for (k = 0; k < len[j]; k++)
1911 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1912 }
1913
1914 for (j = 0; j < CNBUFS; j++) {
1915 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1916 ASSERT(crcr == crc32tv[j]);
1917 }
1918 }
1919
1920 MFREE(buf, CBUFSIZ*CNBUFS);
1921 return;
1922 }
1923 #endif /* notdef */
1924
1925 /*
1926 * Advance from the current 1-byte tag/1-byte length/variable-length value
1927 * triple, to the next, returning a pointer to the next.
1928 * If the current or next TLV is invalid (does not fit in given buffer length),
1929 * NULL is returned.
1930 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1931 * by the TLV parameter's length if it is valid.
1932 */
1933 bcm_tlv_t *
1934 bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
1935 {
1936 int len;
1937
1938 /* validate current elt */
1939 if (!bcm_valid_tlv(elt, *buflen)) {
1940 return NULL;
1941 }
1942
1943 /* advance to next elt */
1944 len = elt->len;
1945 elt = (bcm_tlv_t*)(elt->data + len);
1946 *buflen -= (TLV_HDR_LEN + len);
1947
1948 /* validate next elt */
1949 if (!bcm_valid_tlv(elt, *buflen)) {
1950 return NULL;
1951 }
1952
1953 return elt;
1954 }
1955
1956 /*
1957 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1958 * triples, returning a pointer to the substring whose first element
1959 * matches tag
1960 */
1961 bcm_tlv_t *
1962 bcm_parse_tlvs(void *buf, int buflen, uint key)
1963 {
1964 bcm_tlv_t *elt;
1965 int totlen;
1966
1967 if ((elt = (bcm_tlv_t*)buf) == NULL) {
1968 return NULL;
1969 }
1970 totlen = buflen;
1971
1972 /* find tagged parameter */
1973 while (totlen >= TLV_HDR_LEN) {
1974 int len = elt->len;
1975
1976 /* validate remaining totlen */
1977 if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
1978
1979 return (elt);
1980 }
1981
1982 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
1983 totlen -= (len + TLV_HDR_LEN);
1984 }
1985
1986 return NULL;
1987 }
1988
1989 bcm_tlv_t *
1990 bcm_parse_tlvs_dot11(void *buf, int buflen, uint key, bool id_ext)
1991 {
1992 bcm_tlv_t *elt;
1993 int totlen;
1994
1995 elt = (bcm_tlv_t*)buf;
1996 totlen = buflen;
1997
1998 /* find tagged parameter */
1999 while (totlen >= TLV_HDR_LEN) {
2000 int len = elt->len;
2001
2002 do {
2003 /* validate remaining totlen */
2004 if (totlen < (int)(len + TLV_HDR_LEN))
2005 break;
2006
2007 if (id_ext) {
2008 if (!DOT11_MNG_IE_ID_EXT_MATCH(elt, key))
2009 break;
2010 } else if (elt->id != key) {
2011 break;
2012 }
2013
2014 return (elt);
2015 } while (0);
2016
2017 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
2018 totlen -= (len + TLV_HDR_LEN);
2019 }
2020
2021 return NULL;
2022 }
2023
2024 /*
2025 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2026 * triples, returning a pointer to the substring whose first element
2027 * matches tag
2028 * return NULL if not found or length field < min_varlen
2029 */
2030 bcm_tlv_t *
2031 bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen)
2032 {
2033 bcm_tlv_t * ret;
2034 ret = bcm_parse_tlvs(buf, buflen, key);
2035 if (ret == NULL || ret->len < min_bodylen) {
2036 return NULL;
2037 }
2038 return ret;
2039 }
2040
2041 /*
2042 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2043 * triples, returning a pointer to the substring whose first element
2044 * matches tag. Stop parsing when we see an element whose ID is greater
2045 * than the target key.
2046 */
2047 bcm_tlv_t *
2048 bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
2049 {
2050 bcm_tlv_t *elt;
2051 int totlen;
2052
2053 elt = (bcm_tlv_t*)buf;
2054 totlen = buflen;
2055
2056 /* find tagged parameter */
2057 while (totlen >= TLV_HDR_LEN) {
2058 uint id = elt->id;
2059 int len = elt->len;
2060
2061 /* Punt if we start seeing IDs > than target key */
2062 if (id > key) {
2063 return (NULL);
2064 }
2065
2066 /* validate remaining totlen */
2067 if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
2068 return (elt);
2069 }
2070
2071 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
2072 totlen -= (len + TLV_HDR_LEN);
2073 }
2074 return NULL;
2075 }
2076 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
2077
2078 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
2079 defined(DHD_DEBUG)
2080 int
2081 bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len)
2082 {
2083 int i, slen = 0;
2084 uint32 bit, mask;
2085 const char *name;
2086 mask = bd->mask;
2087 if (len < 2 || !buf)
2088 return 0;
2089
2090 buf[0] = '\0';
2091
2092 for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) {
2093 bit = bd->bitfield[i].bit;
2094 if ((flags & mask) == bit) {
2095 if (len > (int)strlen(name)) {
2096 slen = strlen(name);
2097 strncpy(buf, name, slen+1);
2098 }
2099 break;
2100 }
2101 }
2102 return slen;
2103 }
2104
2105 int
2106 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
2107 {
2108 int i;
2109 char* p = buf;
2110 char hexstr[16];
2111 int slen = 0, nlen = 0;
2112 uint32 bit;
2113 const char* name;
2114
2115 if (len < 2 || !buf)
2116 return 0;
2117
2118 buf[0] = '\0';
2119
2120 for (i = 0; flags != 0; i++) {
2121 bit = bd[i].bit;
2122 name = bd[i].name;
2123 if (bit == 0 && flags != 0) {
2124 /* print any unnamed bits */
2125 snprintf(hexstr, 16, "0x%X", flags);
2126 name = hexstr;
2127 flags = 0; /* exit loop */
2128 } else if ((flags & bit) == 0)
2129 continue;
2130 flags &= ~bit;
2131 nlen = strlen(name);
2132 slen += nlen;
2133 /* count btwn flag space */
2134 if (flags != 0)
2135 slen += 1;
2136 /* need NULL char as well */
2137 if (len <= slen)
2138 break;
2139 /* copy NULL char but don't count it */
2140 strncpy(p, name, nlen + 1);
2141 p += nlen;
2142 /* copy btwn flag space and NULL char */
2143 if (flags != 0)
2144 p += snprintf(p, 2, " ");
2145 }
2146
2147 /* indicate the str was too short */
2148 if (flags != 0) {
2149 p += snprintf(p, 2, ">");
2150 }
2151
2152 return (int)(p - buf);
2153 }
2154 #endif
2155
2156 /* print bytes formatted as hex to a string. return the resulting string length */
2157 int
2158 bcm_format_hex(char *str, const void *bytes, int len)
2159 {
2160 int i;
2161 char *p = str;
2162 const uint8 *src = (const uint8*)bytes;
2163
2164 for (i = 0; i < len; i++) {
2165 p += snprintf(p, 3, "%02X", *src);
2166 src++;
2167 }
2168 return (int)(p - str);
2169 }
2170
2171 /* pretty hex print a contiguous buffer */
2172 void
2173 prhex(const char *msg, volatile uchar *buf, uint nbytes)
2174 {
2175 char line[128], *p;
2176 int len = sizeof(line);
2177 int nchar;
2178 uint i;
2179
2180 if (msg && (msg[0] != '\0'))
2181 printf("%s:\n", msg);
2182
2183 p = line;
2184 for (i = 0; i < nbytes; i++) {
2185 if (i % 16 == 0) {
2186 nchar = snprintf(p, len, " %04x: ", i); /* line prefix */
2187 p += nchar;
2188 len -= nchar;
2189 }
2190 if (len > 0) {
2191 nchar = snprintf(p, len, "%02x ", buf[i]);
2192 p += nchar;
2193 len -= nchar;
2194 }
2195
2196 if (i % 16 == 15) {
2197 printf("%s\n", line); /* flush line */
2198 p = line;
2199 len = sizeof(line);
2200 }
2201 }
2202
2203 /* flush last partial line */
2204 if (p != line)
2205 printf("%s\n", line);
2206 }
2207
2208 static const char *crypto_algo_names[] = {
2209 "NONE",
2210 "WEP1",
2211 "TKIP",
2212 "WEP128",
2213 "AES_CCM",
2214 "AES_OCB_MSDU",
2215 "AES_OCB_MPDU",
2216 "NALG",
2217 "UNDEF",
2218 "UNDEF",
2219 "UNDEF",
2220 "UNDEF"
2221 "PMK",
2222 "BIP",
2223 "AES_GCM",
2224 "AES_CCM256",
2225 "AES_GCM256",
2226 "BIP_CMAC256",
2227 "BIP_GMAC",
2228 "BIP_GMAC256",
2229 "UNDEF"
2230 };
2231
2232 const char *
2233 bcm_crypto_algo_name(uint algo)
2234 {
2235 return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
2236 }
2237
2238
2239 char *
2240 bcm_chipname(uint chipid, char *buf, uint len)
2241 {
2242 const char *fmt;
2243
2244 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
2245 snprintf(buf, len, fmt, chipid);
2246 return buf;
2247 }
2248
2249 /* Produce a human-readable string for boardrev */
2250 char *
2251 bcm_brev_str(uint32 brev, char *buf)
2252 {
2253 if (brev < 0x100)
2254 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
2255 else
2256 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
2257
2258 return (buf);
2259 }
2260
2261 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
2262
2263 /* dump large strings to console */
2264 void
2265 printbig(char *buf)
2266 {
2267 uint len, max_len;
2268 char c;
2269
2270 len = (uint)strlen(buf);
2271
2272 max_len = BUFSIZE_TODUMP_ATONCE;
2273
2274 while (len > max_len) {
2275 c = buf[max_len];
2276 buf[max_len] = '\0';
2277 printf("%s", buf);
2278 buf[max_len] = c;
2279
2280 buf += max_len;
2281 len -= max_len;
2282 }
2283 /* print the remaining string */
2284 printf("%s\n", buf);
2285 return;
2286 }
2287
2288 /* routine to dump fields in a fileddesc structure */
2289 uint
2290 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
2291 char *buf, uint32 bufsize)
2292 {
2293 uint filled_len;
2294 int len;
2295 struct fielddesc *cur_ptr;
2296
2297 filled_len = 0;
2298 cur_ptr = fielddesc_array;
2299
2300 while (bufsize > 1) {
2301 if (cur_ptr->nameandfmt == NULL)
2302 break;
2303 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
2304 read_rtn(arg0, arg1, cur_ptr->offset));
2305 /* check for snprintf overflow or error */
2306 if (len < 0 || (uint32)len >= bufsize)
2307 len = bufsize - 1;
2308 buf += len;
2309 bufsize -= len;
2310 filled_len += len;
2311 cur_ptr++;
2312 }
2313 return filled_len;
2314 }
2315
2316 uint
2317 bcm_mkiovar(const char *name, const char *data, uint datalen, char *buf, uint buflen)
2318 {
2319 uint len;
2320
2321 len = (uint)strlen(name) + 1;
2322
2323 if ((len + datalen) > buflen)
2324 return 0;
2325
2326 strncpy(buf, name, buflen);
2327
2328 /* append data onto the end of the name string */
2329 if (data && datalen != 0) {
2330 memcpy(&buf[len], data, datalen);
2331 len += datalen;
2332 }
2333
2334 return len;
2335 }
2336
2337 /* Quarter dBm units to mW
2338 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
2339 * Table is offset so the last entry is largest mW value that fits in
2340 * a uint16.
2341 */
2342
2343 #define QDBM_OFFSET 153 /* Offset for first entry */
2344 #define QDBM_TABLE_LEN 40 /* Table size */
2345
2346 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
2347 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
2348 */
2349 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
2350
2351 /* Largest mW value that will round down to the last table entry,
2352 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
2353 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
2354 */
2355 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
2356
2357 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
2358 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
2359 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
2360 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
2361 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
2362 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
2363 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
2364 };
2365
2366 uint16
2367 bcm_qdbm_to_mw(uint8 qdbm)
2368 {
2369 uint factor = 1;
2370 int idx = qdbm - QDBM_OFFSET;
2371
2372 if (idx >= QDBM_TABLE_LEN) {
2373 /* clamp to max uint16 mW value */
2374 return 0xFFFF;
2375 }
2376
2377 /* scale the qdBm index up to the range of the table 0-40
2378 * where an offset of 40 qdBm equals a factor of 10 mW.
2379 */
2380 while (idx < 0) {
2381 idx += 40;
2382 factor *= 10;
2383 }
2384
2385 /* return the mW value scaled down to the correct factor of 10,
2386 * adding in factor/2 to get proper rounding.
2387 */
2388 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
2389 }
2390
2391 uint8
2392 bcm_mw_to_qdbm(uint16 mw)
2393 {
2394 uint8 qdbm;
2395 int offset;
2396 uint mw_uint = mw;
2397 uint boundary;
2398
2399 /* handle boundary case */
2400 if (mw_uint <= 1)
2401 return 0;
2402
2403 offset = QDBM_OFFSET;
2404
2405 /* move mw into the range of the table */
2406 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
2407 mw_uint *= 10;
2408 offset -= 40;
2409 }
2410
2411 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
2412 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
2413 nqdBm_to_mW_map[qdbm])/2;
2414 if (mw_uint < boundary) break;
2415 }
2416
2417 qdbm += (uint8)offset;
2418
2419 return (qdbm);
2420 }
2421
2422
2423 uint
2424 bcm_bitcount(uint8 *bitmap, uint length)
2425 {
2426 uint bitcount = 0, i;
2427 uint8 tmp;
2428 for (i = 0; i < length; i++) {
2429 tmp = bitmap[i];
2430 while (tmp) {
2431 bitcount++;
2432 tmp &= (tmp - 1);
2433 }
2434 }
2435 return bitcount;
2436 }
2437
2438 #if defined(BCMDRIVER) || defined(WL_UNITTEST)
2439
2440 /* triggers bcm_bprintf to print to kernel log */
2441 bool bcm_bprintf_bypass = FALSE;
2442
2443 /* Initialization of bcmstrbuf structure */
2444 void
2445 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
2446 {
2447 b->origsize = b->size = size;
2448 b->origbuf = b->buf = buf;
2449 }
2450
2451 /* Buffer sprintf wrapper to guard against buffer overflow */
2452 int
2453 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
2454 {
2455 va_list ap;
2456 int r;
2457
2458 va_start(ap, fmt);
2459
2460 r = vsnprintf(b->buf, b->size, fmt, ap);
2461 if (bcm_bprintf_bypass == TRUE) {
2462 printf("%s", b->buf);
2463 goto exit;
2464 }
2465
2466 /* Non Ansi C99 compliant returns -1,
2467 * Ansi compliant return r >= b->size,
2468 * bcmstdlib returns 0, handle all
2469 */
2470 /* r == 0 is also the case when strlen(fmt) is zero.
2471 * typically the case when "" is passed as argument.
2472 */
2473 if ((r == -1) || (r >= (int)b->size)) {
2474 b->size = 0;
2475 } else {
2476 b->size -= r;
2477 b->buf += r;
2478 }
2479
2480 exit:
2481 va_end(ap);
2482
2483 return r;
2484 }
2485
2486 void
2487 bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, int len)
2488 {
2489 int i;
2490
2491 if (msg != NULL && msg[0] != '\0')
2492 bcm_bprintf(b, "%s", msg);
2493 for (i = 0; i < len; i ++)
2494 bcm_bprintf(b, "%02X", buf[i]);
2495 if (newline)
2496 bcm_bprintf(b, "\n");
2497 }
2498
2499 void
2500 bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
2501 {
2502 int i;
2503
2504 for (i = 0; i < num_bytes; i++) {
2505 num[i] += amount;
2506 if (num[i] >= amount)
2507 break;
2508 amount = 1;
2509 }
2510 }
2511
2512 int
2513 bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
2514 {
2515 int i;
2516
2517 for (i = nbytes - 1; i >= 0; i--) {
2518 if (arg1[i] != arg2[i])
2519 return (arg1[i] - arg2[i]);
2520 }
2521 return 0;
2522 }
2523
2524 void
2525 bcm_print_bytes(const char *name, const uchar *data, int len)
2526 {
2527 int i;
2528 int per_line = 0;
2529
2530 printf("%s: %d \n", name ? name : "", len);
2531 for (i = 0; i < len; i++) {
2532 printf("%02x ", *data++);
2533 per_line++;
2534 if (per_line == 16) {
2535 per_line = 0;
2536 printf("\n");
2537 }
2538 }
2539 printf("\n");
2540 }
2541
2542 /* Look for vendor-specific IE with specified OUI and optional type */
2543 bcm_tlv_t *
2544 bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len)
2545 {
2546 bcm_tlv_t *ie;
2547 uint8 ie_len;
2548
2549 ie = (bcm_tlv_t*)tlvs;
2550
2551 /* make sure we are looking at a valid IE */
2552 if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) {
2553 return NULL;
2554 }
2555
2556 /* Walk through the IEs looking for an OUI match */
2557 do {
2558 ie_len = ie->len;
2559 if ((ie->id == DOT11_MNG_PROPR_ID) &&
2560 (ie_len >= (DOT11_OUI_LEN + type_len)) &&
2561 !bcmp(ie->data, voui, DOT11_OUI_LEN))
2562 {
2563 /* compare optional type */
2564 if (type_len == 0 ||
2565 !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) {
2566 return (ie); /* a match */
2567 }
2568 }
2569 } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL);
2570
2571 return NULL;
2572 }
2573
2574 #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
2575 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
2576 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
2577
2578 int
2579 bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
2580 {
2581 uint i, c;
2582 char *p = buf;
2583 char *endp = buf + SSID_FMT_BUF_LEN;
2584
2585 if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
2586
2587 for (i = 0; i < ssid_len; i++) {
2588 c = (uint)ssid[i];
2589 if (c == '\\') {
2590 *p++ = '\\';
2591 *p++ = '\\';
2592 } else if (bcm_isprint((uchar)c)) {
2593 *p++ = (char)c;
2594 } else {
2595 p += snprintf(p, (endp - p), "\\x%02X", c);
2596 }
2597 }
2598 *p = '\0';
2599 ASSERT(p < endp);
2600
2601 return (int)(p - buf);
2602 }
2603 #endif
2604
2605 #endif /* BCMDRIVER || WL_UNITTEST */
2606
2607 /*
2608 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
2609 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
2610 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
2611 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
2612 */
2613
2614 unsigned int
2615 process_nvram_vars(char *varbuf, unsigned int len)
2616 {
2617 char *dp;
2618 bool findNewline;
2619 int column;
2620 unsigned int buf_len, n;
2621 unsigned int pad = 0;
2622 char nv_ver[128];
2623
2624 dp = varbuf;
2625
2626 findNewline = FALSE;
2627 column = 0;
2628
2629 // terence 20130914: print out NVRAM version
2630 if (varbuf[0] == '#') {
2631 memset(nv_ver, 0x00, sizeof(nv_ver));
2632 for (n=1; n<len && n<(sizeof(nv_ver)-1); n++) {
2633 if (varbuf[n] == '\n')
2634 break;
2635 nv_ver[n-1] = varbuf[n];
2636 }
2637 printk("NVRAM version: %s\n", nv_ver);
2638 }
2639
2640 for (n = 0; n < len; n++) {
2641 if (varbuf[n] == '\r')
2642 continue;
2643 if (findNewline && varbuf[n] != '\n')
2644 continue;
2645 findNewline = FALSE;
2646 if (varbuf[n] == '#') {
2647 findNewline = TRUE;
2648 continue;
2649 }
2650 if (varbuf[n] == '\n') {
2651 if (column == 0)
2652 continue;
2653 *dp++ = 0;
2654 column = 0;
2655 continue;
2656 }
2657 *dp++ = varbuf[n];
2658 column++;
2659 }
2660 buf_len = (unsigned int)(dp - varbuf);
2661 if (buf_len % 4) {
2662 pad = 4 - buf_len % 4;
2663 if (pad && (buf_len + pad <= len)) {
2664 buf_len += pad;
2665 }
2666 }
2667
2668 while (dp < varbuf + n)
2669 *dp++ = 0;
2670
2671 return buf_len;
2672 }
2673
2674 /* calculate a * b + c */
2675 void
2676 bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c)
2677 {
2678 #define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
2679 uint32 r1, r0;
2680 uint32 a1, a0, b1, b0, t, cc = 0;
2681
2682 a1 = a >> 16;
2683 a0 = a & 0xffff;
2684 b1 = b >> 16;
2685 b0 = b & 0xffff;
2686
2687 r0 = a0 * b0;
2688 FORMALIZE(r0);
2689
2690 t = (a1 * b0) << 16;
2691 FORMALIZE(t);
2692
2693 r0 += t;
2694 FORMALIZE(r0);
2695
2696 t = (a0 * b1) << 16;
2697 FORMALIZE(t);
2698
2699 r0 += t;
2700 FORMALIZE(r0);
2701
2702 FORMALIZE(c);
2703
2704 r0 += c;
2705 FORMALIZE(r0);
2706
2707 r0 |= (cc % 2) ? 0x80000000 : 0;
2708 r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2);
2709
2710 *r_high = r1;
2711 *r_low = r0;
2712 }
2713
2714 /* calculate a / b */
2715 void
2716 bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
2717 {
2718 uint32 a1 = a_high, a0 = a_low, r0 = 0;
2719
2720 if (b < 2)
2721 return;
2722
2723 while (a1 != 0) {
2724 r0 += (0xffffffff / b) * a1;
2725 bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0);
2726 }
2727
2728 r0 += a0 / b;
2729 *r = r0;
2730 }
2731
2732 #ifndef setbit /* As in the header file */
2733 #ifdef BCMUTILS_BIT_MACROS_USE_FUNCS
2734 /* Set bit in byte array. */
2735 void
2736 setbit(void *array, uint bit)
2737 {
2738 ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY);
2739 }
2740
2741 /* Clear bit in byte array. */
2742 void
2743 clrbit(void *array, uint bit)
2744 {
2745 ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY));
2746 }
2747
2748 /* Test if bit is set in byte array. */
2749 bool
2750 isset(const void *array, uint bit)
2751 {
2752 return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY)));
2753 }
2754
2755 /* Test if bit is clear in byte array. */
2756 bool
2757 isclr(const void *array, uint bit)
2758 {
2759 return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0);
2760 }
2761 #endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */
2762 #endif /* setbit */
2763
2764 void
2765 set_bitrange(void *array, uint start, uint end, uint maxbit)
2766 {
2767 uint startbyte = start/NBBY;
2768 uint endbyte = end/NBBY;
2769 uint i, startbytelastbit, endbytestartbit;
2770
2771 if (end >= start) {
2772 if (endbyte - startbyte > 1)
2773 {
2774 startbytelastbit = (startbyte+1)*NBBY - 1;
2775 endbytestartbit = endbyte*NBBY;
2776 for (i = startbyte+1; i < endbyte; i++)
2777 ((uint8 *)array)[i] = 0xFF;
2778 for (i = start; i <= startbytelastbit; i++)
2779 setbit(array, i);
2780 for (i = endbytestartbit; i <= end; i++)
2781 setbit(array, i);
2782 } else {
2783 for (i = start; i <= end; i++)
2784 setbit(array, i);
2785 }
2786 }
2787 else {
2788 set_bitrange(array, start, maxbit, maxbit);
2789 set_bitrange(array, 0, end, maxbit);
2790 }
2791 }
2792
2793 void
2794 bcm_bitprint32(const uint32 u32arg)
2795 {
2796 int i;
2797 for (i = NBITS(uint32) - 1; i >= 0; i--) {
2798 if (isbitset(u32arg, i)) {
2799 printf("1");
2800 } else {
2801 printf("0");
2802 }
2803
2804 if ((i % NBBY) == 0) printf(" ");
2805 }
2806 printf("\n");
2807 }
2808
2809 /* calculate checksum for ip header, tcp / udp header / data */
2810 uint16
2811 bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum)
2812 {
2813 while (len > 1) {
2814 sum += (buf[0] << 8) | buf[1];
2815 buf += 2;
2816 len -= 2;
2817 }
2818
2819 if (len > 0) {
2820 sum += (*buf) << 8;
2821 }
2822
2823 while (sum >> 16) {
2824 sum = (sum & 0xffff) + (sum >> 16);
2825 }
2826
2827 return ((uint16)~sum);
2828 }
2829 #if defined(BCMDRIVER) && !defined(_CFEZ_)
2830 /*
2831 * Hierarchical Multiword bitmap based small id allocator.
2832 *
2833 * Multilevel hierarchy bitmap. (maximum 2 levels)
2834 * First hierarchy uses a multiword bitmap to identify 32bit words in the
2835 * second hierarchy that have at least a single bit set. Each bit in a word of
2836 * the second hierarchy represents a unique ID that may be allocated.
2837 *
2838 * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed.
2839 * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word
2840 * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs.
2841 * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non
2842 * non-zero bitmap word carrying at least one free ID.
2843 * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations.
2844 * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID
2845 *
2846 * Design Notes:
2847 * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many
2848 * bits are computed each time on allocation and deallocation, requiring 4
2849 * array indexed access and 3 arithmetic operations. When not defined, a runtime
2850 * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed.
2851 * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation.
2852 * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may
2853 * be used by defining BCM_MWBMAP_USE_CNTSETBITS.
2854 *
2855 * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array
2856 * size is fixed. No intention to support larger than 4K indice allocation. ID
2857 * allocators for ranges smaller than 4K will have a wastage of only 12Bytes
2858 * with savings in not having to use an indirect access, had it been dynamically
2859 * allocated.
2860 */
2861 #define BCM_MWBMAP_ITEMS_MAX (64 * 1024) /* May increase to 64K */
2862
2863 #define BCM_MWBMAP_BITS_WORD (NBITS(uint32))
2864 #define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD)
2865 #define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD)
2866 #define BCM_MWBMAP_SHIFT_OP (5)
2867 #define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1))
2868 #define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP)
2869 #define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP)
2870
2871 /* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */
2872 #define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl))
2873 #define BCM_MWBMAP_HDL(ptr) ((void *)(ptr))
2874
2875 #if defined(BCM_MWBMAP_DEBUG)
2876 #define BCM_MWBMAP_AUDIT(mwb) \
2877 do { \
2878 ASSERT((mwb != NULL) && \
2879 (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \
2880 bcm_mwbmap_audit(mwb); \
2881 } while (0)
2882 #define MWBMAP_ASSERT(exp) ASSERT(exp)
2883 #define MWBMAP_DBG(x) printf x
2884 #else /* !BCM_MWBMAP_DEBUG */
2885 #define BCM_MWBMAP_AUDIT(mwb) do {} while (0)
2886 #define MWBMAP_ASSERT(exp) do {} while (0)
2887 #define MWBMAP_DBG(x)
2888 #endif /* !BCM_MWBMAP_DEBUG */
2889
2890
2891 typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */
2892 uint16 wmaps; /* Total number of words in free wd bitmap */
2893 uint16 imaps; /* Total number of words in free id bitmap */
2894 int32 ifree; /* Count of free indices. Used only in audits */
2895 uint16 total; /* Total indices managed by multiword bitmap */
2896
2897 void * magic; /* Audit handle parameter from user */
2898
2899 uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */
2900 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2901 int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */
2902 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2903
2904 uint32 id_bitmap[0]; /* Second level bitmap */
2905 } bcm_mwbmap_t;
2906
2907 /* Incarnate a hierarchical multiword bitmap based small index allocator. */
2908 struct bcm_mwbmap *
2909 bcm_mwbmap_init(osl_t *osh, uint32 items_max)
2910 {
2911 struct bcm_mwbmap * mwbmap_p;
2912 uint32 wordix, size, words, extra;
2913
2914 /* Implementation Constraint: Uses 32bit word bitmap */
2915 MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U);
2916 MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U);
2917 MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX));
2918 MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U);
2919
2920 ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX);
2921
2922 /* Determine the number of words needed in the multiword bitmap */
2923 extra = BCM_MWBMAP_MODOP(items_max);
2924 words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U);
2925
2926 /* Allocate runtime state of multiword bitmap */
2927 /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */
2928 size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words);
2929 mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size);
2930 if (mwbmap_p == (bcm_mwbmap_t *)NULL) {
2931 ASSERT(0);
2932 goto error1;
2933 }
2934 memset(mwbmap_p, 0, size);
2935
2936 /* Initialize runtime multiword bitmap state */
2937 mwbmap_p->imaps = (uint16)words;
2938 mwbmap_p->ifree = (int32)items_max;
2939 mwbmap_p->total = (uint16)items_max;
2940
2941 /* Setup magic, for use in audit of handle */
2942 mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p);
2943
2944 /* Setup the second level bitmap of free indices */
2945 /* Mark all indices as available */
2946 for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) {
2947 mwbmap_p->id_bitmap[wordix] = (uint32)(~0U);
2948 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2949 mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD;
2950 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2951 }
2952
2953 /* Ensure that extra indices are tagged as un-available */
2954 if (extra) { /* fixup the free ids in last bitmap and wd_count */
2955 uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1];
2956 *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
2957 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2958 mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */
2959 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2960 }
2961
2962 /* Setup the first level bitmap hierarchy */
2963 extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps);
2964 words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U);
2965
2966 mwbmap_p->wmaps = (uint16)words;
2967
2968 for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++)
2969 mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U);
2970 if (extra) {
2971 uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1];
2972 *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
2973 }
2974
2975 return mwbmap_p;
2976
2977 error1:
2978 return BCM_MWBMAP_INVALID_HDL;
2979 }
2980
2981 /* Release resources used by multiword bitmap based small index allocator. */
2982 void
2983 bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl)
2984 {
2985 bcm_mwbmap_t * mwbmap_p;
2986
2987 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2988 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2989
2990 MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap)
2991 + (sizeof(uint32) * mwbmap_p->imaps));
2992 return;
2993 }
2994
2995 /* Allocate a unique small index using a multiword bitmap index allocator. */
2996 uint32 BCMFASTPATH
2997 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl)
2998 {
2999 bcm_mwbmap_t * mwbmap_p;
3000 uint32 wordix, bitmap;
3001
3002 BCM_MWBMAP_AUDIT(mwbmap_hdl);
3003 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3004
3005 /* Start with the first hierarchy */
3006 for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) {
3007
3008 bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */
3009
3010 if (bitmap != 0U) {
3011
3012 uint32 count, bitix, *bitmap_p;
3013
3014 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
3015
3016 /* clear all except trailing 1 */
3017 bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
3018 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
3019 bcm_count_leading_zeros(bitmap));
3020 bitix = (BCM_MWBMAP_BITS_WORD - 1)
3021 - bcm_count_leading_zeros(bitmap); /* use asm clz */
3022 wordix = BCM_MWBMAP_MULOP(wordix) + bitix;
3023
3024 /* Clear bit if wd count is 0, without conditional branch */
3025 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3026 count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1;
3027 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3028 mwbmap_p->wd_count[wordix]--;
3029 count = mwbmap_p->wd_count[wordix];
3030 MWBMAP_ASSERT(count ==
3031 (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1));
3032 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3033 MWBMAP_ASSERT(count >= 0);
3034
3035 /* clear wd_bitmap bit if id_map count is 0 */
3036 bitmap = (count == 0) << bitix;
3037
3038 MWBMAP_DBG((
3039 "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
3040 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count));
3041
3042 *bitmap_p ^= bitmap;
3043
3044 /* Use bitix in the second hierarchy */
3045 bitmap_p = &mwbmap_p->id_bitmap[wordix];
3046
3047 bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */
3048 MWBMAP_ASSERT(bitmap != 0U);
3049
3050 /* clear all except trailing 1 */
3051 bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
3052 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
3053 bcm_count_leading_zeros(bitmap));
3054 bitix = BCM_MWBMAP_MULOP(wordix)
3055 + (BCM_MWBMAP_BITS_WORD - 1)
3056 - bcm_count_leading_zeros(bitmap); /* use asm clz */
3057
3058 mwbmap_p->ifree--; /* decrement system wide free count */
3059 MWBMAP_ASSERT(mwbmap_p->ifree >= 0);
3060
3061 MWBMAP_DBG((
3062 "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d",
3063 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
3064 mwbmap_p->ifree));
3065
3066 *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */
3067
3068 return bitix;
3069 }
3070 }
3071
3072 ASSERT(mwbmap_p->ifree == 0);
3073
3074 return BCM_MWBMAP_INVALID_IDX;
3075 }
3076
3077 /* Force an index at a specified position to be in use */
3078 void
3079 bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
3080 {
3081 bcm_mwbmap_t * mwbmap_p;
3082 uint32 count, wordix, bitmap, *bitmap_p;
3083
3084 BCM_MWBMAP_AUDIT(mwbmap_hdl);
3085 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3086
3087 ASSERT(bitix < mwbmap_p->total);
3088
3089 /* Start with second hierarchy */
3090 wordix = BCM_MWBMAP_DIVOP(bitix);
3091 bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix));
3092 bitmap_p = &mwbmap_p->id_bitmap[wordix];
3093
3094 ASSERT((*bitmap_p & bitmap) == bitmap);
3095
3096 mwbmap_p->ifree--; /* update free count */
3097 ASSERT(mwbmap_p->ifree >= 0);
3098
3099 MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d",
3100 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
3101 mwbmap_p->ifree));
3102
3103 *bitmap_p ^= bitmap; /* mark as in use */
3104
3105 /* Update first hierarchy */
3106 bitix = wordix;
3107
3108 wordix = BCM_MWBMAP_DIVOP(bitix);
3109 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
3110
3111 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3112 count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
3113 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3114 mwbmap_p->wd_count[bitix]--;
3115 count = mwbmap_p->wd_count[bitix];
3116 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
3117 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3118 MWBMAP_ASSERT(count >= 0);
3119
3120 bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix);
3121
3122 MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
3123 BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap,
3124 (*bitmap_p) ^ bitmap, count));
3125
3126 *bitmap_p ^= bitmap; /* mark as in use */
3127
3128 return;
3129 }
3130
3131 /* Free a previously allocated index back into the multiword bitmap allocator */
3132 void BCMFASTPATH
3133 bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
3134 {
3135 bcm_mwbmap_t * mwbmap_p;
3136 uint32 wordix, bitmap, *bitmap_p;
3137
3138 BCM_MWBMAP_AUDIT(mwbmap_hdl);
3139 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3140
3141 ASSERT(bitix < mwbmap_p->total);
3142
3143 /* Start with second level hierarchy */
3144 wordix = BCM_MWBMAP_DIVOP(bitix);
3145 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
3146 bitmap_p = &mwbmap_p->id_bitmap[wordix];
3147
3148 ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */
3149
3150 mwbmap_p->ifree++; /* update free count */
3151 ASSERT(mwbmap_p->ifree <= mwbmap_p->total);
3152
3153 MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d",
3154 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap,
3155 mwbmap_p->ifree));
3156
3157 *bitmap_p |= bitmap; /* mark as available */
3158
3159 /* Now update first level hierarchy */
3160
3161 bitix = wordix;
3162
3163 wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */
3164 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
3165 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
3166
3167 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
3168 mwbmap_p->wd_count[bitix]++;
3169 #endif
3170
3171 #if defined(BCM_MWBMAP_DEBUG)
3172 {
3173 uint32 count;
3174 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3175 count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
3176 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3177 count = mwbmap_p->wd_count[bitix];
3178 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
3179 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3180
3181 MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD);
3182
3183 MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d",
3184 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count));
3185 }
3186 #endif /* BCM_MWBMAP_DEBUG */
3187
3188 *bitmap_p |= bitmap;
3189
3190 return;
3191 }
3192
3193 /* Fetch the toal number of free indices in the multiword bitmap allocator */
3194 uint32
3195 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)
3196 {
3197 bcm_mwbmap_t * mwbmap_p;
3198
3199 BCM_MWBMAP_AUDIT(mwbmap_hdl);
3200 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3201
3202 ASSERT(mwbmap_p->ifree >= 0);
3203
3204 return mwbmap_p->ifree;
3205 }
3206
3207 /* Determine whether an index is inuse or free */
3208 bool
3209 bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
3210 {
3211 bcm_mwbmap_t * mwbmap_p;
3212 uint32 wordix, bitmap;
3213
3214 BCM_MWBMAP_AUDIT(mwbmap_hdl);
3215 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3216
3217 ASSERT(bitix < mwbmap_p->total);
3218
3219 wordix = BCM_MWBMAP_DIVOP(bitix);
3220 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
3221
3222 return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U);
3223 }
3224
3225 /* Debug dump a multiword bitmap allocator */
3226 void
3227 bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)
3228 {
3229 uint32 ix, count;
3230 bcm_mwbmap_t * mwbmap_p;
3231
3232 BCM_MWBMAP_AUDIT(mwbmap_hdl);
3233 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3234
3235 printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p,
3236 mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total);
3237 for (ix = 0U; ix < mwbmap_p->wmaps; ix++) {
3238 printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]);
3239 bcm_bitprint32(mwbmap_p->wd_bitmap[ix]);
3240 printf("\n");
3241 }
3242 for (ix = 0U; ix < mwbmap_p->imaps; ix++) {
3243 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3244 count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]);
3245 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3246 count = mwbmap_p->wd_count[ix];
3247 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix]));
3248 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3249 printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count);
3250 bcm_bitprint32(mwbmap_p->id_bitmap[ix]);
3251 printf("\n");
3252 }
3253
3254 return;
3255 }
3256
3257 /* Audit a hierarchical multiword bitmap */
3258 void
3259 bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)
3260 {
3261 bcm_mwbmap_t * mwbmap_p;
3262 uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p;
3263
3264 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3265
3266 for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) {
3267
3268 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
3269
3270 for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) {
3271 if ((*bitmap_p) & (1 << bitix)) {
3272 idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix;
3273 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3274 count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]);
3275 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3276 count = mwbmap_p->wd_count[idmap_ix];
3277 ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]));
3278 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3279 ASSERT(count != 0U);
3280 free_cnt += count;
3281 }
3282 }
3283 }
3284
3285 ASSERT((int)free_cnt == mwbmap_p->ifree);
3286 }
3287 /* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
3288
3289 /* Simple 16bit Id allocator using a stack implementation. */
3290 typedef struct id16_map {
3291 uint32 failures; /* count of failures */
3292 void *dbg; /* debug placeholder */
3293 uint16 total; /* total number of ids managed by allocator */
3294 uint16 start; /* start value of 16bit ids to be managed */
3295 int stack_idx; /* index into stack of available ids */
3296 uint16 stack[0]; /* stack of 16 bit ids */
3297 } id16_map_t;
3298
3299 #define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \
3300 (sizeof(uint16) * (items)))
3301
3302 #if defined(BCM_DBG)
3303
3304 /* Uncomment BCM_DBG_ID16 to debug double free */
3305 /* #define BCM_DBG_ID16 */
3306
3307 typedef struct id16_map_dbg {
3308 uint16 total;
3309 bool avail[0];
3310 } id16_map_dbg_t;
3311 #define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \
3312 (sizeof(bool) * (items)))
3313 #define ID16_MAP_MSG(x) print x
3314 #else
3315 #define ID16_MAP_MSG(x)
3316 #endif /* BCM_DBG */
3317
3318 void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */
3319 id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16)
3320 {
3321 uint16 idx, val16;
3322 id16_map_t * id16_map;
3323
3324 ASSERT(total_ids > 0);
3325
3326 /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
3327 * with random values.
3328 */
3329 ASSERT((start_val16 == ID16_UNDEFINED) ||
3330 (start_val16 + total_ids) < ID16_INVALID);
3331
3332 id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids));
3333 if (id16_map == NULL) {
3334 return NULL;
3335 }
3336
3337 id16_map->total = total_ids;
3338 id16_map->start = start_val16;
3339 id16_map->failures = 0;
3340 id16_map->dbg = NULL;
3341
3342 /*
3343 * Populate stack with 16bit id values, commencing with start_val16.
3344 * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map.
3345 */
3346 id16_map->stack_idx = -1;
3347
3348 if (id16_map->start != ID16_UNDEFINED) {
3349 val16 = start_val16;
3350
3351 for (idx = 0; idx < total_ids; idx++, val16++) {
3352 id16_map->stack_idx = idx;
3353 id16_map->stack[id16_map->stack_idx] = val16;
3354 }
3355 }
3356
3357 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3358 if (id16_map->start != ID16_UNDEFINED) {
3359 id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids));
3360
3361 if (id16_map->dbg) {
3362 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
3363
3364 id16_map_dbg->total = total_ids;
3365 for (idx = 0; idx < total_ids; idx++) {
3366 id16_map_dbg->avail[idx] = TRUE;
3367 }
3368 }
3369 }
3370 #endif /* BCM_DBG && BCM_DBG_ID16 */
3371
3372 return (void *)id16_map;
3373 }
3374
3375 void * /* Destruct an id16 allocator instance */
3376 id16_map_fini(osl_t *osh, void * id16_map_hndl)
3377 {
3378 uint16 total_ids;
3379 id16_map_t * id16_map;
3380
3381 if (id16_map_hndl == NULL)
3382 return NULL;
3383
3384 id16_map = (id16_map_t *)id16_map_hndl;
3385
3386 total_ids = id16_map->total;
3387 ASSERT(total_ids > 0);
3388
3389 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3390 if (id16_map->dbg) {
3391 MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids));
3392 id16_map->dbg = NULL;
3393 }
3394 #endif /* BCM_DBG && BCM_DBG_ID16 */
3395
3396 id16_map->total = 0;
3397 MFREE(osh, id16_map, ID16_MAP_SZ(total_ids));
3398
3399 return NULL;
3400 }
3401
3402 void
3403 id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16)
3404 {
3405 uint16 idx, val16;
3406 id16_map_t * id16_map;
3407
3408 ASSERT(total_ids > 0);
3409 /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
3410 * with random values.
3411 */
3412 ASSERT((start_val16 == ID16_UNDEFINED) ||
3413 (start_val16 + total_ids) < ID16_INVALID);
3414
3415 id16_map = (id16_map_t *)id16_map_hndl;
3416 if (id16_map == NULL) {
3417 return;
3418 }
3419
3420 id16_map->total = total_ids;
3421 id16_map->start = start_val16;
3422 id16_map->failures = 0;
3423
3424 /* Populate stack with 16bit id values, commencing with start_val16 */
3425 id16_map->stack_idx = -1;
3426
3427 if (id16_map->start != ID16_UNDEFINED) {
3428 val16 = start_val16;
3429
3430 for (idx = 0; idx < total_ids; idx++, val16++) {
3431 id16_map->stack_idx = idx;
3432 id16_map->stack[id16_map->stack_idx] = val16;
3433 }
3434 }
3435
3436 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3437 if (id16_map->start != ID16_UNDEFINED) {
3438 if (id16_map->dbg) {
3439 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
3440
3441 id16_map_dbg->total = total_ids;
3442 for (idx = 0; idx < total_ids; idx++) {
3443 id16_map_dbg->avail[idx] = TRUE;
3444 }
3445 }
3446 }
3447 #endif /* BCM_DBG && BCM_DBG_ID16 */
3448 }
3449
3450 uint16 BCMFASTPATH /* Allocate a unique 16bit id */
3451 id16_map_alloc(void * id16_map_hndl)
3452 {
3453 uint16 val16;
3454 id16_map_t * id16_map;
3455
3456 ASSERT(id16_map_hndl != NULL);
3457
3458 id16_map = (id16_map_t *)id16_map_hndl;
3459
3460 ASSERT(id16_map->total > 0);
3461
3462 if (id16_map->stack_idx < 0) {
3463 id16_map->failures++;
3464 return ID16_INVALID;
3465 }
3466
3467 val16 = id16_map->stack[id16_map->stack_idx];
3468 id16_map->stack_idx--;
3469
3470 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3471 ASSERT((id16_map->start == ID16_UNDEFINED) ||
3472 (val16 < (id16_map->start + id16_map->total)));
3473
3474 if (id16_map->dbg) { /* Validate val16 */
3475 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
3476
3477 ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE);
3478 id16_map_dbg->avail[val16 - id16_map->start] = FALSE;
3479 }
3480 #endif /* BCM_DBG && BCM_DBG_ID16 */
3481
3482 return val16;
3483 }
3484
3485
3486 void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */
3487 id16_map_free(void * id16_map_hndl, uint16 val16)
3488 {
3489 id16_map_t * id16_map;
3490
3491 ASSERT(id16_map_hndl != NULL);
3492
3493 id16_map = (id16_map_t *)id16_map_hndl;
3494
3495 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3496 ASSERT((id16_map->start == ID16_UNDEFINED) ||
3497 (val16 < (id16_map->start + id16_map->total)));
3498
3499 if (id16_map->dbg) { /* Validate val16 */
3500 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
3501
3502 ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE);
3503 id16_map_dbg->avail[val16 - id16_map->start] = TRUE;
3504 }
3505 #endif /* BCM_DBG && BCM_DBG_ID16 */
3506
3507 id16_map->stack_idx++;
3508 id16_map->stack[id16_map->stack_idx] = val16;
3509 }
3510
3511 uint32 /* Returns number of failures to allocate an unique id16 */
3512 id16_map_failures(void * id16_map_hndl)
3513 {
3514 ASSERT(id16_map_hndl != NULL);
3515 return ((id16_map_t *)id16_map_hndl)->failures;
3516 }
3517
3518 bool
3519 id16_map_audit(void * id16_map_hndl)
3520 {
3521 int idx;
3522 int insane = 0;
3523 id16_map_t * id16_map;
3524
3525 ASSERT(id16_map_hndl != NULL);
3526
3527 id16_map = (id16_map_t *)id16_map_hndl;
3528
3529 ASSERT(id16_map->stack_idx >= -1);
3530 ASSERT(id16_map->stack_idx < (int)id16_map->total);
3531
3532 if (id16_map->start == ID16_UNDEFINED)
3533 goto done;
3534
3535 for (idx = 0; idx <= id16_map->stack_idx; idx++) {
3536 ASSERT(id16_map->stack[idx] >= id16_map->start);
3537 ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total));
3538
3539 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3540 if (id16_map->dbg) {
3541 uint16 val16 = id16_map->stack[idx];
3542 if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) {
3543 insane |= 1;
3544 ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n",
3545 id16_map_hndl, idx, val16));
3546 }
3547 }
3548 #endif /* BCM_DBG && BCM_DBG_ID16 */
3549 }
3550
3551 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3552 if (id16_map->dbg) {
3553 uint16 avail = 0; /* Audit available ids counts */
3554 for (idx = 0; idx < id16_map_dbg->total; idx++) {
3555 if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE)
3556 avail++;
3557 }
3558 if (avail && (avail != (id16_map->stack_idx + 1))) {
3559 insane |= 1;
3560 ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n",
3561 id16_map_hndl, avail, id16_map->stack_idx));
3562 }
3563 }
3564 #endif /* BCM_DBG && BCM_DBG_ID16 */
3565
3566 done:
3567 /* invoke any other system audits */
3568 return (!!insane);
3569 }
3570 /* END: Simple id16 allocator */
3571
3572
3573 #endif
3574
3575 /* calculate a >> b; and returns only lower 32 bits */
3576 void
3577 bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
3578 {
3579 uint32 a1 = a_high, a0 = a_low, r0 = 0;
3580
3581 if (b == 0) {
3582 r0 = a_low;
3583 *r = r0;
3584 return;
3585 }
3586
3587 if (b < 32) {
3588 a0 = a0 >> b;
3589 a1 = a1 & ((1 << b) - 1);
3590 a1 = a1 << (32 - b);
3591 r0 = a0 | a1;
3592 *r = r0;
3593 return;
3594 } else {
3595 r0 = a1 >> (b - 32);
3596 *r = r0;
3597 return;
3598 }
3599
3600 }
3601
3602 /* calculate a + b where a is a 64 bit number and b is a 32 bit number */
3603 void
3604 bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset)
3605 {
3606 uint32 r1_lo = *r_lo;
3607 (*r_lo) += offset;
3608 if (*r_lo < r1_lo)
3609 (*r_hi) ++;
3610 }
3611
3612 /* calculate a - b where a is a 64 bit number and b is a 32 bit number */
3613 void
3614 bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset)
3615 {
3616 uint32 r1_lo = *r_lo;
3617 (*r_lo) -= offset;
3618 if (*r_lo > r1_lo)
3619 (*r_hi) --;
3620 }
3621
3622 /* Does unsigned 64 bit fixed point multiplication */
3623 uint64
3624 fp_mult_64(uint64 val1, uint64 val2, uint8 nf1, uint8 nf2, uint8 nf_res)
3625 {
3626 uint64 mult_out_tmp, mult_out, rnd_val;
3627 uint8 shift_amt;
3628
3629 shift_amt = nf1 + nf2 - nf_res;
3630 /* 0.5 in 1.0.shift_amt */
3631 rnd_val = bcm_shl_64(1, (shift_amt - 1));
3632 rnd_val = (shift_amt == 0) ? 0 : rnd_val;
3633 mult_out_tmp = (uint64)((uint64)val1 * (uint64)val2) + (uint64)rnd_val;
3634 mult_out = bcm_shr_64(mult_out_tmp, shift_amt);
3635
3636 return mult_out;
3637 }
3638
3639
3640 /* Does unsigned 64 bit by 32 bit fixed point division */
3641 uint8
3642 fp_div_64(uint64 num, uint32 den, uint8 nf_num, uint8 nf_den, uint32 *div_out)
3643 {
3644 uint8 shift_amt1, shift_amt2, shift_amt, nf_res, hd_rm_nr, hd_rm_dr;
3645 uint32 num_hi, num_lo;
3646 uint64 num_scale;
3647
3648 /* Worst case shift possible */
3649 hd_rm_nr = fp_calc_head_room_64(num);
3650 hd_rm_dr = fp_calc_head_room_32(den);
3651
3652 /* (Nr / Dr) <= 2^32 */
3653 shift_amt1 = hd_rm_nr - hd_rm_dr - 1;
3654 /* Shift <= 32 + N2 - N1 */
3655 shift_amt2 = 31 + nf_den - nf_num;
3656 shift_amt = MINIMUM(shift_amt1, shift_amt2);
3657
3658 /* Scale numerator */
3659 num_scale = bcm_shl_64(num, shift_amt);
3660
3661 /* Do division */
3662 num_hi = (uint32)((uint64)num_scale >> 32) & MASK_32_BITS;
3663 num_lo = (uint32)(num_scale & MASK_32_BITS);
3664 bcm_uint64_divide(div_out, num_hi, num_lo, den);
3665
3666 /* Result format */
3667 nf_res = nf_num - nf_den + shift_amt;
3668 return nf_res;
3669 }
3670
3671 /* Finds the number of bits available for shifting in unsigned 64 bit number */
3672 uint8
3673 fp_calc_head_room_64(uint64 num)
3674 {
3675 uint8 n_room_bits = 0, msb_pos;
3676 uint32 num_hi, num_lo, x;
3677
3678 num_hi = (uint32)((uint64)num >> 32) & MASK_32_BITS;
3679 num_lo = (uint32)(num & MASK_32_BITS);
3680
3681 if (num_hi > 0) {
3682 x = num_hi;
3683 n_room_bits = 0;
3684 } else {
3685 x = num_lo;
3686 n_room_bits = 32;
3687 }
3688
3689 msb_pos = (x >> 16) ? ((x >> 24) ? (24 + msb_table[(x >> 24) & MASK_8_BITS])
3690 : (16 + msb_table[(x >> 16) & MASK_8_BITS]))
3691 : ((x >> 8) ? (8 + msb_table[(x >> 8) & MASK_8_BITS])
3692 : msb_table[x & MASK_8_BITS]);
3693
3694 return (n_room_bits + 32 - msb_pos);
3695 }
3696
3697 /* Finds the number of bits available for shifting in unsigned 32 bit number */
3698 uint8
3699 fp_calc_head_room_32(uint32 x)
3700 {
3701 uint8 msb_pos;
3702
3703 msb_pos = (x >> 16) ? ((x >> 24) ? (24 + msb_table[(x >> 24) & MASK_8_BITS])
3704 : (16 + msb_table[(x >> 16) & MASK_8_BITS]))
3705 : ((x >> 8) ? (8 + msb_table[(x >> 8) & MASK_8_BITS])
3706 : msb_table[x & MASK_8_BITS]);
3707
3708 return (32 - msb_pos);
3709 }
3710
3711 /* Does unsigned 64 bit fixed point floor */
3712 uint32
3713 fp_floor_64(uint64 num, uint8 floor_pos)
3714 {
3715 uint32 floor_out;
3716
3717 floor_out = (uint32)bcm_shr_64(num, floor_pos);
3718
3719 return floor_out;
3720 }
3721
3722 /* Does unsigned 32 bit fixed point floor */
3723 uint32
3724 fp_floor_32(uint32 num, uint8 floor_pos)
3725 {
3726 return num >> floor_pos;
3727 }
3728
3729 /* Does unsigned 64 bit fixed point rounding */
3730 uint32
3731 fp_round_64(uint64 num, uint8 rnd_pos)
3732 {
3733 uint64 rnd_val, rnd_out_tmp;
3734 uint32 rnd_out;
3735
3736 /* 0.5 in 1.0.rnd_pos */
3737 rnd_val = bcm_shl_64(1, (rnd_pos - 1));
3738 rnd_val = (rnd_pos == 0) ? 0 : rnd_val;
3739 rnd_out_tmp = num + rnd_val;
3740 rnd_out = (uint32)bcm_shr_64(rnd_out_tmp, rnd_pos);
3741
3742 return rnd_out;
3743 }
3744
3745 /* Does unsigned 32 bit fixed point rounding */
3746 uint32
3747 fp_round_32(uint32 num, uint8 rnd_pos)
3748 {
3749 uint32 rnd_val, rnd_out_tmp;
3750
3751 /* 0.5 in 1.0.rnd_pos */
3752 rnd_val = 1 << (rnd_pos - 1);
3753 rnd_val = (rnd_pos == 0) ? 0 : rnd_val;
3754 rnd_out_tmp = num + rnd_val;
3755 return (rnd_out_tmp >> rnd_pos);
3756 }
3757
3758 /* Does unsigned fixed point ceiling */
3759 uint32
3760 fp_ceil_64(uint64 num, uint8 ceil_pos)
3761 {
3762 uint64 ceil_val, ceil_out_tmp;
3763 uint32 ceil_out;
3764
3765 /* 0.999 in 1.0.rnd_pos */
3766 ceil_val = bcm_shl_64(1, ceil_pos) - 1;
3767 ceil_out_tmp = num + ceil_val;
3768 ceil_out = (uint32)bcm_shr_64(ceil_out_tmp, ceil_pos);
3769
3770 return ceil_out;
3771 }
3772
3773 /* Does left shift of unsigned 64 bit number */
3774 uint64
3775 bcm_shl_64(uint64 input, uint8 shift_amt)
3776 {
3777 uint32 in_hi, in_lo;
3778 uint32 masked_lo = 0;
3779 uint32 mask;
3780 uint64 shl_out;
3781
3782 if (shift_amt == 0) {
3783 return input;
3784 }
3785
3786 /* Get hi and lo part */
3787 in_hi = (uint32)((uint64)input >> 32) & MASK_32_BITS;
3788 in_lo = (uint32)(input & MASK_32_BITS);
3789
3790 if (shift_amt < 32) {
3791 /* Extract bit which belongs to hi part after shifting */
3792 mask = ((uint32)~0) << (32 - shift_amt);
3793 masked_lo = (in_lo & mask) >> (32 - shift_amt);
3794
3795 /* Shift hi and lo and prepare output */
3796 in_hi = (in_hi << shift_amt) | masked_lo;
3797 in_lo = in_lo << shift_amt;
3798 } else {
3799 /* Extract bit which belongs to hi part after shifting */
3800 shift_amt = shift_amt - 32;
3801
3802 /* Shift hi and lo and prepare output */
3803 in_hi = in_lo << shift_amt;
3804 in_lo = 0;
3805 }
3806
3807 shl_out = (((uint64)in_hi << 32) | in_lo);
3808 return shl_out;
3809 }
3810
3811 /* Does right shift of unsigned 64 bit number */
3812 uint64
3813 bcm_shr_64(uint64 input, uint8 shift_amt)
3814 {
3815 uint32 in_hi, in_lo;
3816 uint32 masked_hi = 0;
3817 uint32 mask;
3818 uint64 shr_out;
3819
3820 if (shift_amt == 0) {
3821 return input;
3822 }
3823
3824 /* Get hi and lo part */
3825 in_hi = (uint32)((uint64)input >> 32) & MASK_32_BITS;
3826 in_lo = (uint32)(input & MASK_32_BITS);
3827
3828 if (shift_amt < 32) {
3829 /* Extract bit which belongs to lo part after shifting */
3830 mask = (1 << shift_amt) - 1;
3831 masked_hi = in_hi & mask;
3832
3833 /* Shift hi and lo and prepare output */
3834 in_hi = (uint32)in_hi >> shift_amt;
3835 in_lo = ((uint32)in_lo >> shift_amt) | (masked_hi << (32 - shift_amt));
3836 } else {
3837 shift_amt = shift_amt - 32;
3838 in_lo = in_hi >> shift_amt;
3839 in_hi = 0;
3840 }
3841
3842 shr_out = (((uint64)in_hi << 32) | in_lo);
3843 return shr_out;
3844 }
3845
3846 #ifdef DEBUG_COUNTER
3847 #if (OSL_SYSUPTIME_SUPPORT == TRUE)
3848 void counter_printlog(counter_tbl_t *ctr_tbl)
3849 {
3850 uint32 now;
3851
3852 if (!ctr_tbl->enabled)
3853 return;
3854
3855 now = OSL_SYSUPTIME();
3856
3857 if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) {
3858 uint8 i = 0;
3859 printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print);
3860
3861 for (i = 0; i < ctr_tbl->needed_cnt; i++) {
3862 printf(" %u", ctr_tbl->cnt[i]);
3863 }
3864 printf("\n");
3865
3866 ctr_tbl->prev_log_print = now;
3867 bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint));
3868 }
3869 }
3870 #else
3871 /* OSL_SYSUPTIME is not supported so no way to get time */
3872 #define counter_printlog(a) do {} while (0)
3873 #endif /* OSL_SYSUPTIME_SUPPORT == TRUE */
3874 #endif /* DEBUG_COUNTER */
3875
3876 #if defined(BCMDRIVER) && !defined(_CFEZ_)
3877 void
3878 dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size)
3879 {
3880 uint32 mem_size;
3881 mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
3882 if (pool)
3883 MFREE(osh, pool, mem_size);
3884 }
3885 dll_pool_t *
3886 dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size)
3887 {
3888 uint32 mem_size, i;
3889 dll_pool_t * dll_pool_p;
3890 dll_t * elem_p;
3891
3892 ASSERT(elem_size > sizeof(dll_t));
3893
3894 mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
3895
3896 if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, mem_size)) == NULL) {
3897 printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n",
3898 elems_max, elem_size);
3899 ASSERT(0);
3900 return dll_pool_p;
3901 }
3902
3903 dll_init(&dll_pool_p->free_list);
3904 dll_pool_p->elems_max = elems_max;
3905 dll_pool_p->elem_size = elem_size;
3906
3907 elem_p = dll_pool_p->elements;
3908 for (i = 0; i < elems_max; i++) {
3909 dll_append(&dll_pool_p->free_list, elem_p);
3910 elem_p = (dll_t *)((uintptr)elem_p + elem_size);
3911 }
3912
3913 dll_pool_p->free_count = elems_max;
3914
3915 return dll_pool_p;
3916 }
3917
3918
3919 void *
3920 dll_pool_alloc(dll_pool_t * dll_pool_p)
3921 {
3922 dll_t * elem_p;
3923
3924 if (dll_pool_p->free_count == 0) {
3925 ASSERT(dll_empty(&dll_pool_p->free_list));
3926 return NULL;
3927 }
3928
3929 elem_p = dll_head_p(&dll_pool_p->free_list);
3930 dll_delete(elem_p);
3931 dll_pool_p->free_count -= 1;
3932
3933 return (void *)elem_p;
3934 }
3935
3936 void
3937 dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p)
3938 {
3939 dll_t * node_p = (dll_t *)elem_p;
3940 dll_prepend(&dll_pool_p->free_list, node_p);
3941 dll_pool_p->free_count += 1;
3942 }
3943
3944
3945 void
3946 dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p)
3947 {
3948 dll_t * node_p = (dll_t *)elem_p;
3949 dll_append(&dll_pool_p->free_list, node_p);
3950 dll_pool_p->free_count += 1;
3951 }
3952
3953 #endif
3954
3955 /* calculate partial checksum */
3956 static uint32
3957 ip_cksum_partial(uint32 sum, uint8 *val8, uint32 count)
3958 {
3959 uint32 i;
3960 uint16 *val16 = (uint16 *)val8;
3961
3962 ASSERT(val8 != NULL);
3963 /* partial chksum calculated on 16-bit values */
3964 ASSERT((count % 2) == 0);
3965
3966 count /= 2;
3967
3968 for (i = 0; i < count; i++) {
3969 sum += *val16++;
3970 }
3971 return sum;
3972 }
3973
3974 /* calculate IP checksum */
3975 static uint16
3976 ip_cksum(uint32 sum, uint8 *val8, uint32 count)
3977 {
3978 uint16 *val16 = (uint16 *)val8;
3979
3980 ASSERT(val8 != NULL);
3981
3982 while (count > 1) {
3983 sum += *val16++;
3984 count -= 2;
3985 }
3986 /* add left-over byte, if any */
3987 if (count > 0) {
3988 sum += (*(uint8 *)val16);
3989 }
3990
3991 /* fold 32-bit sum to 16 bits */
3992 sum = (sum >> 16) + (sum & 0xffff);
3993 sum += (sum >> 16);
3994 return ((uint16)~sum);
3995 }
3996
3997 /* calculate IPv4 header checksum
3998 * - input ip points to IP header in network order
3999 * - output cksum is in network order
4000 */
4001 uint16
4002 ipv4_hdr_cksum(uint8 *ip, int ip_len)
4003 {
4004 uint32 sum = 0;
4005 uint8 *ptr = ip;
4006
4007 ASSERT(ip != NULL);
4008 ASSERT(ip_len >= IPV4_MIN_HEADER_LEN);
4009
4010 /* partial cksum skipping the hdr_chksum field */
4011 sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct ipv4_hdr, hdr_chksum));
4012 ptr += OFFSETOF(struct ipv4_hdr, hdr_chksum) + 2;
4013
4014 /* return calculated chksum */
4015 return ip_cksum(sum, ptr, ip_len - OFFSETOF(struct ipv4_hdr, src_ip));
4016 }
4017
4018 /* calculate TCP header checksum using partial sum */
4019 static uint16
4020 tcp_hdr_chksum(uint32 sum, uint8 *tcp_hdr, uint16 tcp_len)
4021 {
4022 uint8 *ptr = tcp_hdr;
4023
4024 ASSERT(tcp_hdr != NULL);
4025 ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
4026
4027 /* partial TCP cksum skipping the chksum field */
4028 sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct bcmtcp_hdr, chksum));
4029 ptr += OFFSETOF(struct bcmtcp_hdr, chksum) + 2;
4030
4031 /* return calculated chksum */
4032 return ip_cksum(sum, ptr, tcp_len - OFFSETOF(struct bcmtcp_hdr, urg_ptr));
4033 }
4034
4035 struct tcp_pseudo_hdr {
4036 uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */
4037 uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */
4038 uint8 zero;
4039 uint8 prot;
4040 uint16 tcp_size;
4041 };
4042
4043 /* calculate IPv4 TCP header checksum
4044 * - input ip and tcp points to IP and TCP header in network order
4045 * - output cksum is in network order
4046 */
4047 uint16
4048 ipv4_tcp_hdr_cksum(uint8 *ip, uint8 *tcp, uint16 tcp_len)
4049 {
4050 struct ipv4_hdr *ip_hdr = (struct ipv4_hdr *)ip;
4051 struct tcp_pseudo_hdr tcp_ps;
4052 uint32 sum = 0;
4053
4054 ASSERT(ip != NULL);
4055 ASSERT(tcp != NULL);
4056 ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
4057
4058 /* pseudo header cksum */
4059 memset(&tcp_ps, 0, sizeof(tcp_ps));
4060 memcpy(&tcp_ps.dst_ip, ip_hdr->dst_ip, IPV4_ADDR_LEN);
4061 memcpy(&tcp_ps.src_ip, ip_hdr->src_ip, IPV4_ADDR_LEN);
4062 tcp_ps.zero = 0;
4063 tcp_ps.prot = ip_hdr->prot;
4064 tcp_ps.tcp_size = hton16(tcp_len);
4065 sum = ip_cksum_partial(sum, (uint8 *)&tcp_ps, sizeof(tcp_ps));
4066
4067 /* return calculated TCP header chksum */
4068 return tcp_hdr_chksum(sum, tcp, tcp_len);
4069 }
4070
4071 struct ipv6_pseudo_hdr {
4072 uint8 saddr[IPV6_ADDR_LEN];
4073 uint8 daddr[IPV6_ADDR_LEN];
4074 uint16 payload_len;
4075 uint8 zero;
4076 uint8 next_hdr;
4077 };
4078
4079 /* calculate IPv6 TCP header checksum
4080 * - input ipv6 and tcp points to IPv6 and TCP header in network order
4081 * - output cksum is in network order
4082 */
4083 uint16
4084 ipv6_tcp_hdr_cksum(uint8 *ipv6, uint8 *tcp, uint16 tcp_len)
4085 {
4086 struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)ipv6;
4087 struct ipv6_pseudo_hdr ipv6_pseudo;
4088 uint32 sum = 0;
4089
4090 ASSERT(ipv6 != NULL);
4091 ASSERT(tcp != NULL);
4092 ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
4093
4094 /* pseudo header cksum */
4095 memset((char *)&ipv6_pseudo, 0, sizeof(ipv6_pseudo));
4096 memcpy((char *)ipv6_pseudo.saddr, (char *)ipv6_hdr->saddr.addr,
4097 sizeof(ipv6_pseudo.saddr));
4098 memcpy((char *)ipv6_pseudo.daddr, (char *)ipv6_hdr->daddr.addr,
4099 sizeof(ipv6_pseudo.daddr));
4100 ipv6_pseudo.payload_len = ipv6_hdr->payload_len;
4101 ipv6_pseudo.next_hdr = ipv6_hdr->nexthdr;
4102 sum = ip_cksum_partial(sum, (uint8 *)&ipv6_pseudo, sizeof(ipv6_pseudo));
4103
4104 /* return calculated TCP header chksum */
4105 return tcp_hdr_chksum(sum, tcp, tcp_len);
4106 }