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