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