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