From d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 02:45:28 +0000 Subject: [PATCH] add boot partition size --- kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmutils.c | 4133 ++++++++++++++++++++++++++++++++++------------------------- 1 files changed, 2,403 insertions(+), 1,730 deletions(-) diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmutils.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmutils.c index 2a8aa0a..906b92a 100644 --- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmutils.c +++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmutils.c @@ -1,15 +1,16 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /* * Driver O/S-independent utility routines * - * Copyright (C) 1999-2019, Broadcom Corporation - * + * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation + * + * Copyright (C) 1999-2017, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -17,7 +18,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -25,7 +26,7 @@ * * <<Broadcom-WL-IPTag/Open:>> * - * $Id: bcmutils.c 692666 2018-07-30 08:58:07Z $ + * $Id: bcmutils.c 702105 2017-05-30 19:10:39Z $ */ #include <bcm_cfg.h> @@ -33,7 +34,6 @@ #include <bcmdefs.h> #include <stdarg.h> #ifdef BCMDRIVER - #include <osl.h> #include <bcmutils.h> @@ -41,99 +41,39 @@ #include <stdio.h> #include <string.h> +#include <bcm_math.h> #include <bcmutils.h> #if defined(BCMEXTSUP) #include <bcm_osl.h> -#endif +#endif // endif #ifndef ASSERT #define ASSERT(exp) -#endif +#endif // endif #endif /* !BCMDRIVER */ +#ifdef WL_UNITTEST +#ifdef ASSERT +#undef ASSERT +#endif /* ASSERT */ +#define ASSERT(exp) +#endif /* WL_UNITTEST */ + +#include <bcmstdlib_s.h> #include <bcmendian.h> #include <bcmdevs.h> -#include <proto/ethernet.h> -#include <proto/vlan.h> -#include <proto/bcmip.h> -#include <proto/802.1d.h> -#include <proto/802.11.h> - - -void *_bcmutils_dummy_fn = NULL; - - - +#include <ethernet.h> +#include <vlan.h> +#include <bcmip.h> +#include <802.1d.h> +#include <802.11.h> +#include <bcmip.h> +#include <bcmipv6.h> +#include <bcmtcp.h> #ifdef BCMDRIVER - - - -/* copy a pkt buffer chain into a buffer */ -uint -pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) -{ - uint n, ret = 0; - - if (len < 0) - len = 4096; /* "infinite" */ - - /* skip 'offset' bytes */ - for (; p && offset; p = PKTNEXT(osh, p)) { - if (offset < (uint)PKTLEN(osh, p)) - break; - offset -= PKTLEN(osh, p); - } - - if (!p) - return 0; - - /* copy the data */ - for (; p && len; p = PKTNEXT(osh, p)) { - n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); - bcopy(PKTDATA(osh, p) + offset, buf, n); - buf += n; - len -= n; - ret += n; - offset = 0; - } - - return ret; -} - -/* copy a buffer into a pkt buffer chain */ -uint -pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) -{ - uint n, ret = 0; - - - /* skip 'offset' bytes */ - for (; p && offset; p = PKTNEXT(osh, p)) { - if (offset < (uint)PKTLEN(osh, p)) - break; - offset -= PKTLEN(osh, p); - } - - if (!p) - return 0; - - /* copy the data */ - for (; p && len; p = PKTNEXT(osh, p)) { - n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); - bcopy(buf, PKTDATA(osh, p) + offset, n); - buf += n; - len -= n; - ret += n; - offset = 0; - } - - return ret; -} - - /* return total length of buffer chain */ uint BCMFASTPATH @@ -145,14 +85,14 @@ total = 0; for (; p; p = PKTNEXT(osh, p)) { len = PKTLEN(osh, p); - total += len; + total += (uint)len; #ifdef BCMLFRAG if (BCMLFRAG_ENAB()) { if (PKTISFRAG(osh, p)) { total += PKTFRAGTOTLEN(osh, p); } } -#endif +#endif // endif } return (total); @@ -182,41 +122,71 @@ cnt += PKTFRAGTOTNUM(osh, p); } } -#endif +#endif // endif } return cnt; } - -/* count segments of a chained packet */ -uint BCMFASTPATH -pktsegcnt_war(osl_t *osh, void *p) +/* copy a pkt buffer chain into a buffer */ +uint +pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) { - uint cnt; - uint8 *pktdata; - uint len, remain, align64; + uint n, ret = 0; - for (cnt = 0; p; p = PKTNEXT(osh, p)) { - cnt++; - len = PKTLEN(osh, p); - if (len > 128) { - pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */ - /* Check for page boundary straddle (2048B) */ - if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff)) - cnt++; + if (len < 0) + len = 4096; /* "infinite" */ - align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */ - align64 = (64 - align64) & 0x3f; - len -= align64; /* bytes from aligned 64B to end */ - /* if aligned to 128B, check for MOD 128 between 1 to 4B */ - remain = len % 128; - if (remain > 0 && remain <= 4) - cnt++; /* add extra seg */ - } + /* skip 'offset' bytes */ + for (; p && offset; p = PKTNEXT(osh, p)) { + if (offset < (uint)PKTLEN(osh, p)) + break; + offset -= (uint)PKTLEN(osh, p); } - return cnt; + if (!p) + return 0; + + /* copy the data */ + for (; p && len; p = PKTNEXT(osh, p)) { + n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); + bcopy(PKTDATA(osh, p) + offset, buf, n); + buf += n; + len -= n; + ret += n; + offset = 0; + } + + return ret; +} + +/* copy a buffer into a pkt buffer chain */ +uint +pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) +{ + uint n, ret = 0; + + /* skip 'offset' bytes */ + for (; p && offset; p = PKTNEXT(osh, p)) { + if (offset < (uint)PKTLEN(osh, p)) + break; + offset -= (uint)PKTLEN(osh, p); + } + + if (!p) + return 0; + + /* copy the data */ + for (; p && len; p = PKTNEXT(osh, p)) { + n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); + bcopy(buf, PKTDATA(osh, p) + offset, n); + buf += n; + len -= n; + ret += n; + offset = 0; + } + + return ret; } uint8 * BCMFASTPATH @@ -232,13 +202,12 @@ for (; p; p = PKTNEXT(osh, p)) { pdata = (uint8 *) PKTDATA(osh, p); pkt_off = offset - len; - len += PKTLEN(osh, p); + len += (uint)PKTLEN(osh, p); if (len > offset) break; } return (uint8*) (pdata+pkt_off); } - /* given a offset in pdata, find the pkt seg hdr */ void * @@ -251,14 +220,1479 @@ return NULL; for (; p; p = PKTNEXT(osh, p)) { - len += PKTLEN(osh, p); + len += (uint)PKTLEN(osh, p); if (len > offset) break; } return p; } +void +bcm_mdelay(uint ms) +{ + uint i; + + for (i = 0; i < ms; i++) { + OSL_DELAY(1000); + } +} + +#if defined(DHD_DEBUG) +/* pretty hex print a pkt buffer chain */ +void +prpkt(const char *msg, osl_t *osh, void *p0) +{ + void *p; + + if (msg && (msg[0] != '\0')) + printf("%s:\n", msg); + + for (p = p0; p; p = PKTNEXT(osh, p)) + prhex(NULL, PKTDATA(osh, p), (uint)PKTLEN(osh, p)); +} +#endif // endif + +/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. + * Also updates the inplace vlan tag if requested. + * For debugging, it returns an indication of what it did. + */ +uint BCMFASTPATH +pktsetprio(void *pkt, bool update_vtag) +{ + struct ether_header *eh; + struct ethervlan_header *evh; + uint8 *pktdata; + uint priority = 0; + uint rc = 0; + + pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); + ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); + + eh = (struct ether_header *) pktdata; + + if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { + uint16 vlan_tag; + uint vlan_prio, dscp_prio = 0; + + evh = (struct ethervlan_header *)eh; + + vlan_tag = ntoh16(evh->vlan_tag); + vlan_prio = (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; + + if ((evh->ether_type == hton16(ETHER_TYPE_IP)) || + (evh->ether_type == hton16(ETHER_TYPE_IPV6))) { + uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); + uint8 tos_tc = (uint8)IP_TOS46(ip_body); + dscp_prio = tos_tc >> IPV4_TOS_PREC_SHIFT; + } + + /* DSCP priority gets precedence over 802.1P (vlan tag) */ + if (dscp_prio != 0) { + priority = dscp_prio; + rc |= PKTPRIO_VDSCP; + } else { + priority = vlan_prio; + rc |= PKTPRIO_VLAN; + } + /* + * If the DSCP priority is not the same as the VLAN priority, + * then overwrite the priority field in the vlan tag, with the + * DSCP priority value. This is required for Linux APs because + * the VLAN driver on Linux, overwrites the skb->priority field + * with the priority value in the vlan tag + */ + if (update_vtag && (priority != vlan_prio)) { + vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); + vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; + evh->vlan_tag = hton16(vlan_tag); + rc |= PKTPRIO_UPD; + } +#if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING) + } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) { + priority = PRIO_8021D_NC; + rc = PKTPRIO_DSCP; +#endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */ + } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) || + (eh->ether_type == hton16(ETHER_TYPE_IPV6))) { + uint8 *ip_body = pktdata + sizeof(struct ether_header); + uint8 tos_tc = (uint8)IP_TOS46(ip_body); + uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT; + switch (dscp) { + case DSCP_EF: + case DSCP_VA: + priority = PRIO_8021D_VO; + break; + case DSCP_AF31: + case DSCP_AF32: + case DSCP_AF33: + case DSCP_CS3: + priority = PRIO_8021D_CL; + break; + case DSCP_AF21: + case DSCP_AF22: + case DSCP_AF23: + priority = PRIO_8021D_EE; + break; + case DSCP_AF11: + case DSCP_AF12: + case DSCP_AF13: + case DSCP_CS2: + priority = PRIO_8021D_BE; + break; + case DSCP_CS6: + case DSCP_CS7: + priority = PRIO_8021D_NC; + break; + default: + priority = tos_tc >> IPV4_TOS_PREC_SHIFT; + break; + } + + rc |= PKTPRIO_DSCP; + } + + ASSERT(priority <= MAXPRIO); + PKTSETPRIO(pkt, (int)priority); + return (rc | priority); +} + +/* lookup user priority for specified DSCP */ +static uint8 +dscp2up(uint8 *up_table, uint8 dscp) +{ + uint8 user_priority = 255; + + /* lookup up from table if parameters valid */ + if (up_table != NULL && dscp < UP_TABLE_MAX) { + user_priority = up_table[dscp]; + } + + /* 255 is unused value so return up from dscp */ + if (user_priority == 255) { + user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT); + } + + return user_priority; +} + +/* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */ +uint BCMFASTPATH +pktsetprio_qms(void *pkt, uint8* up_table, bool update_vtag) +{ + if (up_table) { + uint8 *pktdata; + uint pktlen; + uint8 dscp; + uint user_priority = 0; + uint rc = 0; + + pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); + pktlen = (uint)PKTLEN(OSH_NULL, pkt); + + if (pktgetdscp(pktdata, pktlen, &dscp)) { + rc = PKTPRIO_DSCP; + user_priority = dscp2up(up_table, dscp); + PKTSETPRIO(pkt, (int)user_priority); + } + + return (rc | user_priority); + } else { + return pktsetprio(pkt, update_vtag); + } +} + +/* Returns TRUE and DSCP if IP header found, FALSE otherwise. + */ +bool BCMFASTPATH +pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp) +{ + struct ether_header *eh; + struct ethervlan_header *evh; + uint8 *ip_body; + bool rc = FALSE; + + /* minimum length is ether header and IP header */ + if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN) + return FALSE; + + eh = (struct ether_header *) pktdata; + + if (eh->ether_type == HTON16(ETHER_TYPE_IP)) { + ip_body = pktdata + sizeof(struct ether_header); + *dscp = (uint8)IP_DSCP46(ip_body); + rc = TRUE; + } + else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) { + evh = (struct ethervlan_header *)eh; + + /* minimum length is ethervlan header and IP header */ + if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN && + evh->ether_type == HTON16(ETHER_TYPE_IP)) { + ip_body = pktdata + sizeof(struct ethervlan_header); + *dscp = (uint8)IP_DSCP46(ip_body); + rc = TRUE; + } + } + + return rc; +} + +/* usr_prio range from low to high with usr_prio value */ +static bool +up_table_set(uint8 *up_table, uint8 usr_prio, uint8 low, uint8 high) +{ + int i; + + if (usr_prio > 7 || low > high || low >= UP_TABLE_MAX || high >= UP_TABLE_MAX) { + return FALSE; + } + + for (i = low; i <= high; i++) { + up_table[i] = usr_prio; + } + + return TRUE; +} + +/* set user priority table */ +int BCMFASTPATH +wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie) +{ + uint8 len; + + if (up_table == NULL || qos_map_ie == NULL) { + return BCME_ERROR; + } + + /* clear table to check table was set or not */ + memset(up_table, 0xff, UP_TABLE_MAX); + + /* length of QoS Map IE must be 16+n*2, n is number of exceptions */ + if (qos_map_ie != NULL && qos_map_ie->id == DOT11_MNG_QOS_MAP_ID && + (len = qos_map_ie->len) >= QOS_MAP_FIXED_LENGTH && + (len % 2) == 0) { + uint8 *except_ptr = (uint8 *)qos_map_ie->data; + uint8 except_len = len - QOS_MAP_FIXED_LENGTH; + uint8 *range_ptr = except_ptr + except_len; + uint8 i; + + /* fill in ranges */ + for (i = 0; i < QOS_MAP_FIXED_LENGTH; i += 2) { + uint8 low = range_ptr[i]; + uint8 high = range_ptr[i + 1]; + if (low == 255 && high == 255) { + continue; + } + + if (!up_table_set(up_table, i / 2, low, high)) { + /* clear the table on failure */ + memset(up_table, 0xff, UP_TABLE_MAX); + return BCME_ERROR; + } + } + + /* update exceptions */ + for (i = 0; i < except_len; i += 2) { + uint8 dscp = except_ptr[i]; + uint8 usr_prio = except_ptr[i+1]; + + /* exceptions with invalid dscp/usr_prio are ignored */ + up_table_set(up_table, usr_prio, dscp, dscp); + } + } + + return BCME_OK; +} + +/* The 0.5KB string table is not removed by compiler even though it's unused */ + +static char bcm_undeferrstr[32]; +static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; + +/* Convert the error codes into related error strings */ +const char * +BCMRAMFN(bcmerrorstr)(int bcmerror) +{ + /* check if someone added a bcmerror code but forgot to add errorstring */ + ASSERT((uint)ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); + + if (bcmerror > 0 || bcmerror < BCME_LAST) { + snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); + return bcm_undeferrstr; + } + + ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN); + + return bcmerrorstrtable[-bcmerror]; +} + +/* iovar table lookup */ +/* could mandate sorted tables and do a binary search */ +const bcm_iovar_t* +bcm_iovar_lookup(const bcm_iovar_t *table, const char *name) +{ + const bcm_iovar_t *vi; + const char *lookup_name; + + /* skip any ':' delimited option prefixes */ + lookup_name = strrchr(name, ':'); + if (lookup_name != NULL) + lookup_name++; + else + lookup_name = name; + + ASSERT(table != NULL); + + for (vi = table; vi->name; vi++) { + if (!strcmp(vi->name, lookup_name)) + return vi; + } + /* ran to end of table */ + + return NULL; /* var name not found */ +} + +int +bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) +{ + int bcmerror = 0; + BCM_REFERENCE(arg); + + /* length check on io buf */ + switch (vi->type) { + case IOVT_BOOL: + case IOVT_INT8: + case IOVT_INT16: + case IOVT_INT32: + case IOVT_UINT8: + case IOVT_UINT16: + case IOVT_UINT32: + /* all integers are int32 sized args at the ioctl interface */ + if (len < (int)sizeof(int)) { + bcmerror = BCME_BUFTOOSHORT; + } + break; + + case IOVT_BUFFER: + /* buffer must meet minimum length requirement */ + if (len < vi->minlen) { + bcmerror = BCME_BUFTOOSHORT; + } + break; + + case IOVT_VOID: + if (!set) { + /* Cannot return nil... */ + bcmerror = BCME_UNSUPPORTED; + } + break; + + default: + /* unknown type for length check in iovar info */ + ASSERT(0); + bcmerror = BCME_UNSUPPORTED; + } + + return bcmerror; +} + +#if !defined(_CFEZ_) +/* + * Hierarchical Multiword bitmap based small id allocator. + * + * Multilevel hierarchy bitmap. (maximum 2 levels) + * First hierarchy uses a multiword bitmap to identify 32bit words in the + * second hierarchy that have at least a single bit set. Each bit in a word of + * the second hierarchy represents a unique ID that may be allocated. + * + * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed. + * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word + * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs. + * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non + * non-zero bitmap word carrying at least one free ID. + * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations. + * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID + * + * Design Notes: + * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many + * bits are computed each time on allocation and deallocation, requiring 4 + * array indexed access and 3 arithmetic operations. When not defined, a runtime + * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed. + * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation. + * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may + * be used by defining BCM_MWBMAP_USE_CNTSETBITS. + * + * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array + * size is fixed. No intention to support larger than 4K indice allocation. ID + * allocators for ranges smaller than 4K will have a wastage of only 12Bytes + * with savings in not having to use an indirect access, had it been dynamically + * allocated. + */ +#define BCM_MWBMAP_ITEMS_MAX (64 * 1024) /* May increase to 64K */ + +#define BCM_MWBMAP_BITS_WORD (NBITS(uint32)) +#define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD) +#define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD) +#define BCM_MWBMAP_SHIFT_OP (5) +#define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1)) +#define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP) +#define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP) + +/* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */ +#define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl)) +#define BCM_MWBMAP_HDL(ptr) ((void *)(ptr)) + +#if defined(BCM_MWBMAP_DEBUG) +#define BCM_MWBMAP_AUDIT(mwb) \ + do { \ + ASSERT((mwb != NULL) && \ + (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \ + bcm_mwbmap_audit(mwb); \ + } while (0) +#define MWBMAP_ASSERT(exp) ASSERT(exp) +#define MWBMAP_DBG(x) printf x +#else /* !BCM_MWBMAP_DEBUG */ +#define BCM_MWBMAP_AUDIT(mwb) do {} while (0) +#define MWBMAP_ASSERT(exp) do {} while (0) +#define MWBMAP_DBG(x) +#endif /* !BCM_MWBMAP_DEBUG */ + +typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */ + uint16 wmaps; /* Total number of words in free wd bitmap */ + uint16 imaps; /* Total number of words in free id bitmap */ + int32 ifree; /* Count of free indices. Used only in audits */ + uint16 total; /* Total indices managed by multiword bitmap */ + + void * magic; /* Audit handle parameter from user */ + + uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */ +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */ +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + + uint32 id_bitmap[0]; /* Second level bitmap */ +} bcm_mwbmap_t; + +/* Incarnate a hierarchical multiword bitmap based small index allocator. */ +struct bcm_mwbmap * +bcm_mwbmap_init(osl_t *osh, uint32 items_max) +{ + struct bcm_mwbmap * mwbmap_p; + uint32 wordix, size, words, extra; + + /* Implementation Constraint: Uses 32bit word bitmap */ + MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U); + MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U); + MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX)); + MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U); + + ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX); + + /* Determine the number of words needed in the multiword bitmap */ + extra = BCM_MWBMAP_MODOP(items_max); + words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U); + + /* Allocate runtime state of multiword bitmap */ + /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */ + size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words); + mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size); + if (mwbmap_p == (bcm_mwbmap_t *)NULL) { + ASSERT(0); + goto error1; + } + memset(mwbmap_p, 0, size); + + /* Initialize runtime multiword bitmap state */ + mwbmap_p->imaps = (uint16)words; + mwbmap_p->ifree = (int32)items_max; + mwbmap_p->total = (uint16)items_max; + + /* Setup magic, for use in audit of handle */ + mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p); + + /* Setup the second level bitmap of free indices */ + /* Mark all indices as available */ + for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) { + mwbmap_p->id_bitmap[wordix] = (uint32)(~0U); +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD; +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + } + + /* Ensure that extra indices are tagged as un-available */ + if (extra) { /* fixup the free ids in last bitmap and wd_count */ + uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1]; + *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */ +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + } + + /* Setup the first level bitmap hierarchy */ + extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps); + words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U); + + mwbmap_p->wmaps = (uint16)words; + + for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++) + mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U); + if (extra) { + uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1]; + *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ + } + + return mwbmap_p; + +error1: + return BCM_MWBMAP_INVALID_HDL; +} + +/* Release resources used by multiword bitmap based small index allocator. */ +void +bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap) + + (sizeof(uint32) * mwbmap_p->imaps)); + return; +} + +/* Allocate a unique small index using a multiword bitmap index allocator. */ +uint32 BCMFASTPATH +bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 wordix, bitmap; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + /* Start with the first hierarchy */ + for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) { + + bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */ + + if (bitmap != 0U) { + + uint32 count, bitix, *bitmap_p; + + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + + /* clear all except trailing 1 */ + bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); + MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == + bcm_count_leading_zeros(bitmap)); + bitix = (BCM_MWBMAP_BITS_WORD - 1) + - (uint32)bcm_count_leading_zeros(bitmap); /* use asm clz */ + wordix = BCM_MWBMAP_MULOP(wordix) + bitix; + + /* Clear bit if wd count is 0, without conditional branch */ +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1; +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + mwbmap_p->wd_count[wordix]--; + count = (uint32)mwbmap_p->wd_count[wordix]; + MWBMAP_ASSERT(count == + (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1)); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + MWBMAP_ASSERT(count >= 0); + + /* clear wd_bitmap bit if id_map count is 0 */ + bitmap = ((uint32)(count == 0)) << BCM_MWBMAP_MODOP(bitix); + + MWBMAP_DBG(( + "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count)); + + *bitmap_p ^= bitmap; + + /* Use bitix in the second hierarchy */ + bitmap_p = &mwbmap_p->id_bitmap[wordix]; + + bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */ + MWBMAP_ASSERT(bitmap != 0U); + + /* clear all except trailing 1 */ + bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); + MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == + bcm_count_leading_zeros(bitmap)); + bitix = BCM_MWBMAP_MULOP(wordix) + + (BCM_MWBMAP_BITS_WORD - 1) + - (uint32)bcm_count_leading_zeros(bitmap); /* use asm clz */ + + mwbmap_p->ifree--; /* decrement system wide free count */ + MWBMAP_ASSERT(mwbmap_p->ifree >= 0); + + MWBMAP_DBG(( + "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, + mwbmap_p->ifree)); + + *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */ + + return bitix; + } + } + + ASSERT(mwbmap_p->ifree == 0); + + return BCM_MWBMAP_INVALID_IDX; +} + +/* Force an index at a specified position to be in use */ +void +bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 count, wordix, bitmap, *bitmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(bitix < mwbmap_p->total); + + /* Start with second hierarchy */ + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix)); + bitmap_p = &mwbmap_p->id_bitmap[wordix]; + + ASSERT((*bitmap_p & bitmap) == bitmap); + + mwbmap_p->ifree--; /* update free count */ + ASSERT(mwbmap_p->ifree >= 0); + + MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, + mwbmap_p->ifree)); + + *bitmap_p ^= bitmap; /* mark as in use */ + + /* Update first hierarchy */ + bitix = wordix; + + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + mwbmap_p->wd_count[bitix]--; + count = (uint32)mwbmap_p->wd_count[bitix]; + MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + MWBMAP_ASSERT(count >= 0); + + bitmap = (uint32)(count == 0) << BCM_MWBMAP_MODOP(bitix); + + MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d", + BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap, + (*bitmap_p) ^ bitmap, count)); + + *bitmap_p ^= bitmap; /* mark as in use */ + + return; +} + +/* Free a previously allocated index back into the multiword bitmap allocator */ +void BCMFASTPATH +bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 wordix, bitmap, *bitmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(bitix < mwbmap_p->total); + + /* Start with second level hierarchy */ + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); + bitmap_p = &mwbmap_p->id_bitmap[wordix]; + + ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */ + + mwbmap_p->ifree++; /* update free count */ + ASSERT(mwbmap_p->ifree <= mwbmap_p->total); + + MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, + mwbmap_p->ifree)); + + *bitmap_p |= bitmap; /* mark as available */ + + /* Now update first level hierarchy */ + + bitix = wordix; + + wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */ + bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + mwbmap_p->wd_count[bitix]++; +#endif // endif + +#if defined(BCM_MWBMAP_DEBUG) + { + uint32 count; +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + count = mwbmap_p->wd_count[bitix]; + MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + + MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD); + + MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count)); + } +#endif /* BCM_MWBMAP_DEBUG */ + + *bitmap_p |= bitmap; + + return; +} + +/* Fetch the toal number of free indices in the multiword bitmap allocator */ +uint32 +bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(mwbmap_p->ifree >= 0); + + return (uint32)mwbmap_p->ifree; +} + +/* Determine whether an index is inuse or free */ +bool +bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 wordix, bitmap; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(bitix < mwbmap_p->total); + + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); + + return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U); +} + +/* Debug dump a multiword bitmap allocator */ +void +bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl) +{ + uint32 ix, count; + bcm_mwbmap_t * mwbmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", + OSL_OBFUSCATE_BUF((void *)mwbmap_p), + mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total); + for (ix = 0U; ix < mwbmap_p->wmaps; ix++) { + printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]); + bcm_bitprint32(mwbmap_p->wd_bitmap[ix]); + printf("\n"); + } + for (ix = 0U; ix < mwbmap_p->imaps; ix++) { +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + count = (uint32)mwbmap_p->wd_count[ix]; + MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count); + bcm_bitprint32(mwbmap_p->id_bitmap[ix]); + printf("\n"); + } + + return; +} + +/* Audit a hierarchical multiword bitmap */ +void +bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p; + + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) { + + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + + for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) { + if ((*bitmap_p) & (1 << bitix)) { + idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix; +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + count = (uint32)mwbmap_p->wd_count[idmap_ix]; + ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + ASSERT(count != 0U); + free_cnt += count; + } + } + } + + ASSERT((int)free_cnt == mwbmap_p->ifree); +} +/* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */ + +/* Simple 16bit Id allocator using a stack implementation. */ +typedef struct id16_map { + uint32 failures; /* count of failures */ + void *dbg; /* debug placeholder */ + uint16 total; /* total number of ids managed by allocator */ + uint16 start; /* start value of 16bit ids to be managed */ + int stack_idx; /* index into stack of available ids */ + uint16 stack[0]; /* stack of 16 bit ids */ +} id16_map_t; + +#define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \ + (sizeof(uint16) * (items))) + +#if defined(BCM_DBG) + +/* Uncomment BCM_DBG_ID16 to debug double free */ +/* #define BCM_DBG_ID16 */ + +typedef struct id16_map_dbg { + uint16 total; + bool avail[0]; +} id16_map_dbg_t; +#define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \ + (sizeof(bool) * (items))) +#define ID16_MAP_MSG(x) print x +#else +#define ID16_MAP_MSG(x) +#endif /* BCM_DBG */ + +void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */ +id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16) +{ + uint16 idx, val16; + id16_map_t * id16_map; + + ASSERT(total_ids > 0); + + /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map + * with random values. + */ + ASSERT((start_val16 == ID16_UNDEFINED) || + (start_val16 + total_ids) < ID16_INVALID); + + id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids)); + if (id16_map == NULL) { + return NULL; + } + + id16_map->total = total_ids; + id16_map->start = start_val16; + id16_map->failures = 0; + id16_map->dbg = NULL; + + /* + * Populate stack with 16bit id values, commencing with start_val16. + * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map. + */ + id16_map->stack_idx = -1; + + if (id16_map->start != ID16_UNDEFINED) { + val16 = start_val16; + + for (idx = 0; idx < total_ids; idx++, val16++) { + id16_map->stack_idx = idx; + id16_map->stack[id16_map->stack_idx] = val16; + } + } + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + if (id16_map->start != ID16_UNDEFINED) { + id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids)); + + if (id16_map->dbg) { + id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; + + id16_map_dbg->total = total_ids; + for (idx = 0; idx < total_ids; idx++) { + id16_map_dbg->avail[idx] = TRUE; + } + } + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ + + return (void *)id16_map; +} + +void * /* Destruct an id16 allocator instance */ +id16_map_fini(osl_t *osh, void * id16_map_hndl) +{ + uint16 total_ids; + id16_map_t * id16_map; + + if (id16_map_hndl == NULL) + return NULL; + + id16_map = (id16_map_t *)id16_map_hndl; + + total_ids = id16_map->total; + ASSERT(total_ids > 0); + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + if (id16_map->dbg) { + MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids)); + id16_map->dbg = NULL; + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ + + id16_map->total = 0; + MFREE(osh, id16_map, ID16_MAP_SZ(total_ids)); + + return NULL; +} + +void +id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16) +{ + uint16 idx, val16; + id16_map_t * id16_map; + + ASSERT(total_ids > 0); + /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map + * with random values. + */ + ASSERT((start_val16 == ID16_UNDEFINED) || + (start_val16 + total_ids) < ID16_INVALID); + + id16_map = (id16_map_t *)id16_map_hndl; + if (id16_map == NULL) { + return; + } + + id16_map->total = total_ids; + id16_map->start = start_val16; + id16_map->failures = 0; + + /* Populate stack with 16bit id values, commencing with start_val16 */ + id16_map->stack_idx = -1; + + if (id16_map->start != ID16_UNDEFINED) { + val16 = start_val16; + + for (idx = 0; idx < total_ids; idx++, val16++) { + id16_map->stack_idx = idx; + id16_map->stack[id16_map->stack_idx] = val16; + } + } + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + if (id16_map->start != ID16_UNDEFINED) { + if (id16_map->dbg) { + id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; + + id16_map_dbg->total = total_ids; + for (idx = 0; idx < total_ids; idx++) { + id16_map_dbg->avail[idx] = TRUE; + } + } + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ +} + +uint16 BCMFASTPATH /* Allocate a unique 16bit id */ +id16_map_alloc(void * id16_map_hndl) +{ + uint16 val16; + id16_map_t * id16_map; + + ASSERT(id16_map_hndl != NULL); + if (!id16_map_hndl) { + return ID16_INVALID; + } + id16_map = (id16_map_t *)id16_map_hndl; + + ASSERT(id16_map->total > 0); + + if (id16_map->stack_idx < 0) { + id16_map->failures++; + return ID16_INVALID; + } + + val16 = id16_map->stack[id16_map->stack_idx]; + id16_map->stack_idx--; + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + ASSERT((id16_map->start == ID16_UNDEFINED) || + (val16 < (id16_map->start + id16_map->total))); + + if (id16_map->dbg) { /* Validate val16 */ + id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; + + ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE); + id16_map_dbg->avail[val16 - id16_map->start] = FALSE; + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ + + return val16; +} + +void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */ +id16_map_free(void * id16_map_hndl, uint16 val16) +{ + id16_map_t * id16_map; + + ASSERT(id16_map_hndl != NULL); + + id16_map = (id16_map_t *)id16_map_hndl; + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + ASSERT((id16_map->start == ID16_UNDEFINED) || + (val16 < (id16_map->start + id16_map->total))); + + if (id16_map->dbg) { /* Validate val16 */ + id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; + + ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE); + id16_map_dbg->avail[val16 - id16_map->start] = TRUE; + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ + + id16_map->stack_idx++; + id16_map->stack[id16_map->stack_idx] = val16; +} + +uint32 /* Returns number of failures to allocate an unique id16 */ +id16_map_failures(void * id16_map_hndl) +{ + ASSERT(id16_map_hndl != NULL); + return ((id16_map_t *)id16_map_hndl)->failures; +} + +bool +id16_map_audit(void * id16_map_hndl) +{ + int idx; + int insane = 0; + id16_map_t * id16_map; + + ASSERT(id16_map_hndl != NULL); + if (!id16_map_hndl) { + goto done; + } + id16_map = (id16_map_t *)id16_map_hndl; + + ASSERT(id16_map->stack_idx >= -1); + ASSERT(id16_map->stack_idx < (int)id16_map->total); + + if (id16_map->start == ID16_UNDEFINED) + goto done; + + for (idx = 0; idx <= id16_map->stack_idx; idx++) { + ASSERT(id16_map->stack[idx] >= id16_map->start); + ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total)); + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + if (id16_map->dbg) { + uint16 val16 = id16_map->stack[idx]; + if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) { + insane |= 1; + ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n", + OSL_OBFUSATE_BUF(id16_map_hndl), idx, val16)); + } + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ + } + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + if (id16_map->dbg) { + uint16 avail = 0; /* Audit available ids counts */ + for (idx = 0; idx < id16_map_dbg->total; idx++) { + if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE) + avail++; + } + if (avail && (avail != (id16_map->stack_idx + 1))) { + insane |= 1; + ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n", + OSL_OBFUSCATE_BUF(id16_map_hndl), + avail, id16_map->stack_idx)); + } + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ + +done: + /* invoke any other system audits */ + return (!!insane); +} +/* END: Simple id16 allocator */ + +void +dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size) +{ + uint32 memsize; + memsize = sizeof(dll_pool_t) + (elems_max * elem_size); + if (pool) + MFREE(osh, pool, memsize); +} +dll_pool_t * +dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size) +{ + uint32 memsize, i; + dll_pool_t * dll_pool_p; + dll_t * elem_p; + + ASSERT(elem_size > sizeof(dll_t)); + + memsize = sizeof(dll_pool_t) + (elems_max * elem_size); + + if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, memsize)) == NULL) { + printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n", + elems_max, elem_size); + ASSERT(0); + return dll_pool_p; + } + + dll_init(&dll_pool_p->free_list); + dll_pool_p->elems_max = elems_max; + dll_pool_p->elem_size = elem_size; + + elem_p = dll_pool_p->elements; + for (i = 0; i < elems_max; i++) { + dll_append(&dll_pool_p->free_list, elem_p); + elem_p = (dll_t *)((uintptr)elem_p + elem_size); + } + + dll_pool_p->free_count = elems_max; + + return dll_pool_p; +} + +void * +dll_pool_alloc(dll_pool_t * dll_pool_p) +{ + dll_t * elem_p; + + if (dll_pool_p->free_count == 0) { + ASSERT(dll_empty(&dll_pool_p->free_list)); + return NULL; + } + + elem_p = dll_head_p(&dll_pool_p->free_list); + dll_delete(elem_p); + dll_pool_p->free_count -= 1; + + return (void *)elem_p; +} + +void +dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p) +{ + dll_t * node_p = (dll_t *)elem_p; + dll_prepend(&dll_pool_p->free_list, node_p); + dll_pool_p->free_count += 1; +} + +void +dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p) +{ + dll_t * node_p = (dll_t *)elem_p; + dll_append(&dll_pool_p->free_list, node_p); + dll_pool_p->free_count += 1; +} + +#endif // endif + #endif /* BCMDRIVER */ + +#if defined(BCMDRIVER) || defined(WL_UNITTEST) + +/* triggers bcm_bprintf to print to kernel log */ +bool bcm_bprintf_bypass = FALSE; + +/* Initialization of bcmstrbuf structure */ +void +bcm_binit(struct bcmstrbuf *b, char *buf, uint size) +{ + b->origsize = b->size = size; + b->origbuf = b->buf = buf; + if (size > 0) { + buf[0] = '\0'; + } +} + +/* Buffer sprintf wrapper to guard against buffer overflow */ +int +bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + + r = vsnprintf(b->buf, b->size, fmt, ap); + if (bcm_bprintf_bypass == TRUE) { + printf("%s", b->buf); + goto exit; + } + + /* Non Ansi C99 compliant returns -1, + * Ansi compliant return r >= b->size, + * bcmstdlib returns 0, handle all + */ + /* r == 0 is also the case when strlen(fmt) is zero. + * typically the case when "" is passed as argument. + */ + if ((r == -1) || (r >= (int)b->size)) { + b->size = 0; + } else { + b->size -= (uint)r; + b->buf += r; + } + +exit: + va_end(ap); + + return r; +} + +void +bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, int len) +{ + int i; + + if (msg != NULL && msg[0] != '\0') + bcm_bprintf(b, "%s", msg); + for (i = 0; i < len; i ++) + bcm_bprintf(b, "%02X", buf[i]); + if (newline) + bcm_bprintf(b, "\n"); +} + +void +bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) +{ + int i; + + for (i = 0; i < num_bytes; i++) { + num[i] += amount; + if (num[i] >= amount) + break; + amount = 1; + } +} + +int +bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes) +{ + int i; + + for (i = nbytes - 1; i >= 0; i--) { + if (arg1[i] != arg2[i]) + return (arg1[i] - arg2[i]); + } + return 0; +} + +void +bcm_print_bytes(const char *name, const uchar *data, int len) +{ + int i; + int per_line = 0; + + printf("%s: %d \n", name ? name : "", len); + for (i = 0; i < len; i++) { + printf("%02x ", *data++); + per_line++; + if (per_line == 16) { + per_line = 0; + printf("\n"); + } + } + printf("\n"); +} + +/* Look for vendor-specific IE with specified OUI and optional type */ +bcm_tlv_t * +bcm_find_vendor_ie(const void *tlvs, uint tlvs_len, const char *voui, uint8 *type, uint type_len) +{ + const bcm_tlv_t *ie; + uint8 ie_len; + + ie = (const bcm_tlv_t*)tlvs; + + /* make sure we are looking at a valid IE */ + if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) { + return NULL; + } + + /* Walk through the IEs looking for an OUI match */ + do { + ie_len = ie->len; + if ((ie->id == DOT11_MNG_VS_ID) && + (ie_len >= (DOT11_OUI_LEN + type_len)) && + !bcmp(ie->data, voui, DOT11_OUI_LEN)) + { + /* compare optional type */ + if (type_len == 0 || + !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) { + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + return (bcm_tlv_t *)(ie); /* a match */ + GCC_DIAGNOSTIC_POP(); + } + } + } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL); + + return NULL; +} + +#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ + defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) +#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) + +int +bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) +{ + uint i, c; + char *p = buf; + char *endp = buf + SSID_FMT_BUF_LEN; + + if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; + + for (i = 0; i < ssid_len; i++) { + c = (uint)ssid[i]; + if (c == '\\') { + *p++ = '\\'; + *p++ = '\\'; + } else if (bcm_isprint((uchar)c)) { + *p++ = (char)c; + } else { + p += snprintf(p, (size_t)(endp - p), "\\x%02X", c); + } + } + *p = '\0'; + ASSERT(p < endp); + + return (int)(p - buf); +} +#endif // endif + +#endif /* BCMDRIVER || WL_UNITTEST */ + +char * +bcm_ether_ntoa(const struct ether_addr *ea, char *buf) +{ + static const char hex[] = + { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + const uint8 *octet = ea->octet; + char *p = buf; + int i; + + for (i = 0; i < 6; i++, octet++) { + *p++ = hex[(*octet >> 4) & 0xf]; + *p++ = hex[*octet & 0xf]; + *p++ = ':'; + } + + *(p-1) = '\0'; + + return (buf); +} + +/* Find the position of first bit set + * in the given number. + */ +int +bcm_find_fsb(uint32 num) +{ + uint8 pos = 0; + if (!num) + return pos; + while (!(num & 1)) { + num >>= 1; + pos++; + } + return (pos+1); +} + +char * +bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) +{ + snprintf(buf, 16, "%d.%d.%d.%d", + ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); + return (buf); +} + +char * +bcm_ipv6_ntoa(void *ipv6, char *buf) +{ + /* Implementing RFC 5952 Sections 4 + 5 */ + /* Not thoroughly tested */ + uint16 tmp[8]; + uint16 *a = &tmp[0]; + char *p = buf; + int i, i_max = -1, cnt = 0, cnt_max = 1; + uint8 *a4 = NULL; + memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN); + + for (i = 0; i < IPV6_ADDR_LEN/2; i++) { + if (a[i]) { + if (cnt > cnt_max) { + cnt_max = cnt; + i_max = i - cnt; + } + cnt = 0; + } else + cnt++; + } + if (cnt > cnt_max) { + cnt_max = cnt; + i_max = i - cnt; + } + if (i_max == 0 && + /* IPv4-translated: ::ffff:0:a.b.c.d */ + ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) || + /* IPv4-mapped: ::ffff:a.b.c.d */ + (cnt_max == 5 && a[5] == 0xffff))) + a4 = (uint8*) (a + 6); + + for (i = 0; i < IPV6_ADDR_LEN/2; i++) { + if ((uint8*) (a + i) == a4) { + snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]); + break; + } else if (i == i_max) { + *p++ = ':'; + i += cnt_max - 1; + p[0] = ':'; + p[1] = '\0'; + } else { + if (i) + *p++ = ':'; + p += snprintf(p, 8, "%x", ntoh16(a[i])); + } + } + + return buf; +} #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) const unsigned char bcm_ctype[] = { @@ -298,10 +1732,10 @@ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */ }; -ulong -bcm_strtoul(const char *cp, char **endp, uint base) +uint64 +bcm_strtoull(const char *cp, char **endp, uint base) { - ulong result, last_result = 0, value; + uint64 result, last_result = 0, value; bool minus; minus = FALSE; @@ -334,11 +1768,19 @@ result = 0; while (bcm_isxdigit(*cp) && - (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { + (value = (uint64)(bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10)) < base) { result = result*base + value; /* Detected overflow */ - if (result < last_result && !minus) + if (result < last_result && !minus) { + if (endp) { + /* Go to the end of current number */ + while (bcm_isxdigit(*cp)) { + cp++; + } + *endp = DISCARD_QUAL(cp, char); + } return (ulong)-1; + } last_result = result; cp++; } @@ -350,6 +1792,12 @@ *endp = DISCARD_QUAL(cp, char); return (result); +} + +ulong +bcm_strtoul(const char *cp, char **endp, uint base) +{ + return (ulong) bcm_strtoull(cp, endp, base); } int @@ -372,7 +1820,7 @@ len = (int)strlen(haystack) - nlen + 1; for (i = 0; i < len; i++) - if (memcmp(needle, &haystack[i], nlen) == 0) + if (memcmp(needle, &haystack[i], (size_t)nlen) == 0) return DISCARD_QUAL(&haystack[i], char); return (NULL); } @@ -414,7 +1862,6 @@ return (dest); } - /**************************************************************************** * Function: bcmstrtok @@ -477,7 +1924,7 @@ for (; *str; str++) { if (map[*str >> 5] & (1 << (*str & 31))) { if (tokdelim != NULL) { - *tokdelim = *str; + *tokdelim = (char)*str; } *str++ = '\0'; @@ -496,10 +1943,8 @@ } } - #define xToLower(C) \ ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C) - /**************************************************************************** * Function: bcmstricmp @@ -531,7 +1976,6 @@ if (!*s1 && *s2) return -1; return 0; } - /**************************************************************************** * Function: bcmstrnicmp @@ -576,7 +2020,7 @@ char *ep; for (;;) { - ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16); + ea->octet[i++] = (uint8) bcm_strtoul(p, &ep, 16); p = ep; if (!*p++ || i == 6) break; @@ -600,7 +2044,6 @@ return (i == IPV4_ADDR_LEN); } #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ - #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER) /* registry routine buffer preparation utility functions: @@ -630,460 +2073,6 @@ return copyct; } #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */ - -char * -bcm_ether_ntoa(const struct ether_addr *ea, char *buf) -{ - static const char hex[] = - { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; - const uint8 *octet = ea->octet; - char *p = buf; - int i; - - for (i = 0; i < 6; i++, octet++) { - *p++ = hex[(*octet >> 4) & 0xf]; - *p++ = hex[*octet & 0xf]; - *p++ = ':'; - } - - *(p-1) = '\0'; - - return (buf); -} - -char * -bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) -{ - snprintf(buf, 16, "%d.%d.%d.%d", - ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); - return (buf); -} - -char * -bcm_ipv6_ntoa(void *ipv6, char *buf) -{ - /* Implementing RFC 5952 Sections 4 + 5 */ - /* Not thoroughly tested */ - uint16 tmp[8]; - uint16 *a = &tmp[0]; - char *p = buf; - int i, i_max = -1, cnt = 0, cnt_max = 1; - uint8 *a4 = NULL; - memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN); - - for (i = 0; i < IPV6_ADDR_LEN/2; i++) { - if (a[i]) { - if (cnt > cnt_max) { - cnt_max = cnt; - i_max = i - cnt; - } - cnt = 0; - } else - cnt++; - } - if (cnt > cnt_max) { - cnt_max = cnt; - i_max = i - cnt; - } - if (i_max == 0 && - /* IPv4-translated: ::ffff:0:a.b.c.d */ - ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) || - /* IPv4-mapped: ::ffff:a.b.c.d */ - (cnt_max == 5 && a[5] == 0xffff))) - a4 = (uint8*) (a + 6); - - for (i = 0; i < IPV6_ADDR_LEN/2; i++) { - if ((uint8*) (a + i) == a4) { - snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]); - break; - } else if (i == i_max) { - *p++ = ':'; - i += cnt_max - 1; - p[0] = ':'; - p[1] = '\0'; - } else { - if (i) - *p++ = ':'; - p += snprintf(p, 8, "%x", ntoh16(a[i])); - } - } - - return buf; -} -#ifdef BCMDRIVER - -void -bcm_mdelay(uint ms) -{ - uint i; - - for (i = 0; i < ms; i++) { - OSL_DELAY(1000); - } -} - - - - - -#if defined(DHD_DEBUG) -/* pretty hex print a pkt buffer chain */ -void -prpkt(const char *msg, osl_t *osh, void *p0) -{ - void *p; - - if (msg && (msg[0] != '\0')) - printf("%s:\n", msg); - - for (p = p0; p; p = PKTNEXT(osh, p)) - prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p)); -} -#endif - -/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. - * Also updates the inplace vlan tag if requested. - * For debugging, it returns an indication of what it did. - */ -uint BCMFASTPATH -pktsetprio(void *pkt, bool update_vtag) -{ - struct ether_header *eh; - struct ethervlan_header *evh; - uint8 *pktdata; - int priority = 0; - int rc = 0; - - pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); - ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); - - eh = (struct ether_header *) pktdata; - - if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { - uint16 vlan_tag; - int vlan_prio, dscp_prio = 0; - - evh = (struct ethervlan_header *)eh; - - vlan_tag = ntoh16(evh->vlan_tag); - vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; - - if ((evh->ether_type == hton16(ETHER_TYPE_IP)) || - (evh->ether_type == hton16(ETHER_TYPE_IPV6))) { - uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); - uint8 tos_tc = IP_TOS46(ip_body); - dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); - } - - /* DSCP priority gets precedence over 802.1P (vlan tag) */ - if (dscp_prio != 0) { - priority = dscp_prio; - rc |= PKTPRIO_VDSCP; - } else { - priority = vlan_prio; - rc |= PKTPRIO_VLAN; - } - /* - * If the DSCP priority is not the same as the VLAN priority, - * then overwrite the priority field in the vlan tag, with the - * DSCP priority value. This is required for Linux APs because - * the VLAN driver on Linux, overwrites the skb->priority field - * with the priority value in the vlan tag - */ - if (update_vtag && (priority != vlan_prio)) { - vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); - vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; - evh->vlan_tag = hton16(vlan_tag); - rc |= PKTPRIO_UPD; - } -#ifdef DHD_LOSSLESS_ROAMING - } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) { - priority = PRIO_8021D_NC; - rc = PKTPRIO_DSCP; -#endif /* DHD_LOSSLESS_ROAMING */ - } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) || - (eh->ether_type == hton16(ETHER_TYPE_IPV6))) { - uint8 *ip_body = pktdata + sizeof(struct ether_header); - uint8 tos_tc = IP_TOS46(ip_body); - uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT; - switch (dscp) { - case DSCP_EF: - priority = PRIO_8021D_VO; - break; - case DSCP_AF31: - case DSCP_AF32: - case DSCP_AF33: - priority = PRIO_8021D_CL; - break; - case DSCP_AF21: - case DSCP_AF22: - case DSCP_AF23: - case DSCP_AF11: - case DSCP_AF12: - case DSCP_AF13: - priority = PRIO_8021D_EE; - break; - default: - priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); - break; - } - - rc |= PKTPRIO_DSCP; - } - - ASSERT(priority >= 0 && priority <= MAXPRIO); - PKTSETPRIO(pkt, priority); - return (rc | priority); -} - -/* lookup user priority for specified DSCP */ -static uint8 -dscp2up(uint8 *up_table, uint8 dscp) -{ - uint8 user_priority = 255; - - /* lookup up from table if parameters valid */ - if (up_table != NULL && dscp < UP_TABLE_MAX) { - user_priority = up_table[dscp]; - } - - /* 255 is unused value so return up from dscp */ - if (user_priority == 255) { - user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT); - } - - return user_priority; -} - -/* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */ -uint BCMFASTPATH -pktsetprio_qms(void *pkt, uint8* up_table, bool update_vtag) -{ - if (up_table) { - uint8 *pktdata; - uint pktlen; - uint8 dscp; - uint user_priority = 0; - uint rc = 0; - - pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); - pktlen = PKTLEN(OSH_NULL, pkt); - - if (pktgetdscp(pktdata, pktlen, &dscp)) { - rc = PKTPRIO_DSCP; - user_priority = dscp2up(up_table, dscp); - PKTSETPRIO(pkt, user_priority); - } - - return (rc | user_priority); - } else { - return pktsetprio(pkt, update_vtag); - } -} - -/* Returns TRUE and DSCP if IP header found, FALSE otherwise. - */ -bool BCMFASTPATH -pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp) -{ - struct ether_header *eh; - struct ethervlan_header *evh; - uint8 *ip_body; - bool rc = FALSE; - - /* minimum length is ether header and IP header */ - if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN) - return FALSE; - - eh = (struct ether_header *) pktdata; - - if (eh->ether_type == HTON16(ETHER_TYPE_IP)) { - ip_body = pktdata + sizeof(struct ether_header); - *dscp = IP_DSCP46(ip_body); - rc = TRUE; - } - else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) { - evh = (struct ethervlan_header *)eh; - - /* minimum length is ethervlan header and IP header */ - if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN && - evh->ether_type == HTON16(ETHER_TYPE_IP)) { - ip_body = pktdata + sizeof(struct ethervlan_header); - *dscp = IP_DSCP46(ip_body); - rc = TRUE; - } - } - - return rc; -} - -/* usr_prio range from low to high with usr_prio value */ -static bool -up_table_set(uint8 *up_table, uint8 usr_prio, uint8 low, uint8 high) -{ - int i; - - if (usr_prio > 7 || low > high || low >= UP_TABLE_MAX || high >= UP_TABLE_MAX) { - return FALSE; - } - - for (i = low; i <= high; i++) { - up_table[i] = usr_prio; - } - - return TRUE; -} - -/* set user priority table */ -int BCMFASTPATH -wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie) -{ - uint8 len; - - if (up_table == NULL || qos_map_ie == NULL) { - return BCME_ERROR; - } - - /* clear table to check table was set or not */ - memset(up_table, 0xff, UP_TABLE_MAX); - - /* length of QoS Map IE must be 16+n*2, n is number of exceptions */ - if (qos_map_ie != NULL && qos_map_ie->id == DOT11_MNG_QOS_MAP_ID && - (len = qos_map_ie->len) >= QOS_MAP_FIXED_LENGTH && - (len % 2) == 0) { - uint8 *except_ptr = (uint8 *)qos_map_ie->data; - uint8 except_len = len - QOS_MAP_FIXED_LENGTH; - uint8 *range_ptr = except_ptr + except_len; - int i; - - /* fill in ranges */ - for (i = 0; i < QOS_MAP_FIXED_LENGTH; i += 2) { - uint8 low = range_ptr[i]; - uint8 high = range_ptr[i + 1]; - if (low == 255 && high == 255) { - continue; - } - - if (!up_table_set(up_table, i / 2, low, high)) { - /* clear the table on failure */ - memset(up_table, 0xff, UP_TABLE_MAX); - return BCME_ERROR; - } - } - - /* update exceptions */ - for (i = 0; i < except_len; i += 2) { - uint8 dscp = except_ptr[i]; - uint8 usr_prio = except_ptr[i+1]; - - /* exceptions with invalid dscp/usr_prio are ignored */ - up_table_set(up_table, usr_prio, dscp, dscp); - } - } - - return BCME_OK; -} - -/* The 0.5KB string table is not removed by compiler even though it's unused */ - -static char bcm_undeferrstr[32]; -static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; - -/* Convert the error codes into related error strings */ -const char * -bcmerrorstr(int bcmerror) -{ - /* check if someone added a bcmerror code but forgot to add errorstring */ - ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); - - if (bcmerror > 0 || bcmerror < BCME_LAST) { - snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); - return bcm_undeferrstr; - } - - ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN); - - return bcmerrorstrtable[-bcmerror]; -} - - - -/* iovar table lookup */ -/* could mandate sorted tables and do a binary search */ -const bcm_iovar_t* -bcm_iovar_lookup(const bcm_iovar_t *table, const char *name) -{ - const bcm_iovar_t *vi; - const char *lookup_name; - - /* skip any ':' delimited option prefixes */ - lookup_name = strrchr(name, ':'); - if (lookup_name != NULL) - lookup_name++; - else - lookup_name = name; - - ASSERT(table != NULL); - - for (vi = table; vi->name; vi++) { - if (!strcmp(vi->name, lookup_name)) - return vi; - } - /* ran to end of table */ - - return NULL; /* var name not found */ -} - -int -bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) -{ - int bcmerror = 0; - - /* length check on io buf */ - switch (vi->type) { - case IOVT_BOOL: - case IOVT_INT8: - case IOVT_INT16: - case IOVT_INT32: - case IOVT_UINT8: - case IOVT_UINT16: - case IOVT_UINT32: - /* all integers are int32 sized args at the ioctl interface */ - if (len < (int)sizeof(int)) { - bcmerror = BCME_BUFTOOSHORT; - } - break; - - case IOVT_BUFFER: - /* buffer must meet minimum length requirement */ - if (len < vi->minlen) { - bcmerror = BCME_BUFTOOSHORT; - } - break; - - case IOVT_VOID: - if (!set) { - /* Cannot return nil... */ - bcmerror = BCME_UNSUPPORTED; - } else if (len) { - /* Set is an action w/o parameters */ - bcmerror = BCME_BUFTOOLONG; - } - break; - - default: - /* unknown type for length check in iovar info */ - ASSERT(0); - bcmerror = BCME_UNSUPPORTED; - } - - return bcmerror; -} - -#endif /* BCMDRIVER */ #ifdef BCM_OBJECT_TRACE @@ -1522,22 +2511,70 @@ ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) && ((data != NULL) || (datalen == 0))) { - /* write type, len fields */ + /* write type, len fields */ dst_tlv->id = (uint8)type; - dst_tlv->len = (uint8)datalen; + dst_tlv->len = (uint8)datalen; /* if data is present, copy to the output buffer and update * pointer to output buffer */ if (datalen > 0) { - memcpy(dst_tlv->data, data, datalen); + memcpy(dst_tlv->data, data, (size_t)datalen); } /* update the output destination poitner to point past * the TLV written */ new_dst = dst + BCM_TLV_HDR_SIZE + datalen; + } + + return (new_dst); +} + +uint8 * +bcm_write_tlv_ext(uint8 type, uint8 ext, const void *data, uint8 datalen, uint8 *dst) +{ + uint8 *new_dst = dst; + bcm_tlv_ext_t *dst_tlv = (bcm_tlv_ext_t *)dst; + + /* dst buffer should always be valid */ + ASSERT(dst); + + /* data len must be within valid range */ + ASSERT(datalen <= BCM_TLV_EXT_MAX_DATA_SIZE); + + /* source data buffer pointer should be valid, unless datalen is 0 + * meaning no data with this TLV + */ + ASSERT((data != NULL) || (datalen == 0)); + + /* only do work if the inputs are valid + * - must have a dst to write to AND + * - datalen must be within range AND + * - the source data pointer must be non-NULL if datalen is non-zero + * (this last condition detects datalen > 0 with a NULL data pointer) + */ + if ((dst != NULL) && + (datalen <= BCM_TLV_EXT_MAX_DATA_SIZE) && + ((data != NULL) || (datalen == 0))) { + + /* write type, len fields */ + dst_tlv->id = (uint8)type; + dst_tlv->ext = ext; + dst_tlv->len = 1 + (uint8)datalen; + + /* if data is present, copy to the output buffer and update + * pointer to output buffer + */ + if (datalen > 0) { + memcpy(dst_tlv->data, data, datalen); + } + + /* update the output destination poitner to point past + * the TLV written + */ + new_dst = dst + BCM_TLV_EXT_HDR_SIZE + datalen; } return (new_dst); @@ -1553,7 +2590,7 @@ /* if len + tlv hdr len is more than destlen, don't do anything * just return the buffer untouched */ - if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) { + if ((int)(datalen + (int)BCM_TLV_HDR_SIZE) <= dst_maxlen) { new_dst = bcm_write_tlv(type, data, datalen, dst); } @@ -1580,7 +2617,6 @@ return (new_dst); } - uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen) { uint8 *new_dst = dst; @@ -1595,7 +2631,6 @@ return (new_dst); } - #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) /******************************************************************************* @@ -1660,7 +2695,7 @@ uint8 hndcrc8( - uint8 *pdata, /* pointer to array of data to process */ + const uint8 *pdata, /* pointer to array of data to process */ uint nbytes, /* number of input data bytes to process */ uint8 crc /* either CRC8_INIT_VALUE or previous return value */ ) @@ -1733,7 +2768,7 @@ uint16 hndcrc16( - uint8 *pdata, /* pointer to array of data to process */ + const uint8 *pdata, /* pointer to array of data to process */ uint nbytes, /* number of input data bytes to process */ uint16 crc /* either CRC16_INIT_VALUE or previous return value */ ) @@ -1815,9 +2850,9 @@ * accumulating over multiple pieces. */ uint32 -hndcrc32(uint8 *pdata, uint nbytes, uint32 crc) +hndcrc32(const uint8 *pdata, uint nbytes, uint32 crc) { - uint8 *pend; + const uint8 *pend; pend = pdata + nbytes; while (pdata < pend) CRC_INNER_LOOP(32, crc, *pdata++); @@ -1826,8 +2861,8 @@ } #ifdef notdef -#define CLEN 1499 /* CRC Length */ -#define CBUFSIZ (CLEN+4) +#define CLEN 1499 /* CRC Length */ +#define CBUFSIZ (CLEN+4) #define CNBUFS 5 /* # of bufs */ void @@ -1870,9 +2905,9 @@ * by the TLV parameter's length if it is valid. */ bcm_tlv_t * -bcm_next_tlv(bcm_tlv_t *elt, int *buflen) +bcm_next_tlv(const bcm_tlv_t *elt, uint *buflen) { - int len; + uint len; /* validate current elt */ if (!bcm_valid_tlv(elt, *buflen)) { @@ -1881,7 +2916,7 @@ /* advance to next elt */ len = elt->len; - elt = (bcm_tlv_t*)(elt->data + len); + elt = (const bcm_tlv_t*)(elt->data + len); *buflen -= (TLV_HDR_LEN + len); /* validate next elt */ @@ -1889,7 +2924,112 @@ return NULL; } - return elt; + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + return (bcm_tlv_t *)(elt); + GCC_DIAGNOSTIC_POP(); +} + +/** + * Advance a const tlv buffer pointer and length up to the given tlv element pointer + * 'elt'. The function checks that elt is a valid tlv; the elt pointer and data + * are all in the range of the buffer/length. + * + * @param elt pointer to a valid bcm_tlv_t in the buffer + * @param buffer pointer to a tlv buffer + * @param buflen length of the buffer in bytes + * + * On return, if elt is not a tlv in the buffer bounds, the *buffer parameter + * will be set to NULL and *buflen parameter will be set to zero. Otherwise, + * *buffer will point to elt, and *buflen will have been adjusted by the the + * difference between *buffer and elt. + */ +void +bcm_tlv_buffer_advance_to(const bcm_tlv_t *elt, const uint8 **buffer, uint *buflen) +{ + uint new_buflen; + const uint8 *new_buffer; + + new_buffer = (const uint8*)elt; + + /* make sure the input buffer pointer is non-null, that (buffer + buflen) does not wrap, + * and that the elt pointer is in the range of [buffer, buffer + buflen] + */ + if ((*buffer != NULL) && + ((uintptr)*buffer < ((uintptr)*buffer + *buflen)) && + (new_buffer >= *buffer) && + (new_buffer < (*buffer + *buflen))) { + /* delta between buffer and new_buffer is <= *buflen, so truncating cast to uint + * from ptrdiff is ok + */ + uint delta = (uint)(new_buffer - *buffer); + + /* New buffer length is old len minus the delta from the buffer start to elt. + * The check just above guarantees that the subtractions does not underflow. + */ + new_buflen = *buflen - delta; + + /* validate current elt */ + if (bcm_valid_tlv(elt, new_buflen)) { + /* All good, so update the input/output parameters */ + *buffer = new_buffer; + *buflen = new_buflen; + return; + } + } + + /* something did not check out, clear out the buffer info */ + *buffer = NULL; + *buflen = 0; + + return; +} + +/** + * Advance a const tlv buffer pointer and length past the given tlv element pointer + * 'elt'. The function checks that elt is a valid tlv; the elt pointer and data + * are all in the range of the buffer/length. The function also checks that the + * remaining buffer starts with a valid tlv. + * + * @param elt pointer to a valid bcm_tlv_t in the buffer + * @param buffer pointer to a tlv buffer + * @param buflen length of the buffer in bytes + * + * On return, if elt is not a tlv in the buffer bounds, or the remaining buffer + * following the elt does not begin with a tlv in the buffer bounds, the *buffer + * parameter will be set to NULL and *buflen parameter will be set to zero. + * Otherwise, *buffer will point to the first byte past elt, and *buflen will + * have the remaining buffer length. + */ +void +bcm_tlv_buffer_advance_past(const bcm_tlv_t *elt, const uint8 **buffer, uint *buflen) +{ + /* Start by advancing the buffer up to the given elt */ + bcm_tlv_buffer_advance_to(elt, buffer, buflen); + + /* if that did not work, bail out */ + if (*buflen == 0) { + return; + } + +#if defined(__COVERITY__) + /* The elt has been verified by bcm_tlv_buffer_advance_to() to be a valid element, + * so its elt->len is in the bounds of the buffer. The following check prevents + * Coverity from flagging the (elt->data + elt->len) statement below as using a + * tainted elt->len to index into array 'elt->data'. + */ + if (elt->len > *buflen) { + return; + } +#endif /* __COVERITY__ */ + + /* We know we are advanced up to a good tlv. + * Now just advance to the following tlv. + */ + elt = (const bcm_tlv_t*)(elt->data + elt->len); + + bcm_tlv_buffer_advance_to(elt, buffer, buflen); + + return; } /* @@ -1898,25 +3038,68 @@ * matches tag */ bcm_tlv_t * -bcm_parse_tlvs(void *buf, int buflen, uint key) +bcm_parse_tlvs(const void *buf, uint buflen, uint key) +{ + const bcm_tlv_t *elt; + int totlen; + + if ((elt = (const bcm_tlv_t*)buf) == NULL) { + return NULL; + } + totlen = (int)buflen; + + /* find tagged parameter */ + while (totlen >= TLV_HDR_LEN) { + uint len = elt->len; + + /* validate remaining totlen */ + if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + return (bcm_tlv_t *)(elt); + GCC_DIAGNOSTIC_POP(); + } + + elt = (const bcm_tlv_t*)((const uint8*)elt + (len + TLV_HDR_LEN)); + totlen -= (len + TLV_HDR_LEN); + } + + return NULL; +} + +bcm_tlv_t * +bcm_parse_tlvs_dot11(const void *buf, int buflen, uint key, bool id_ext) { bcm_tlv_t *elt; int totlen; - if ((elt = (bcm_tlv_t*)buf) == NULL) { - return NULL; - } + /* + ideally, we don't want to do that, but returning a const pointer + from these parse function spreads casting everywhere in the code + */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + elt = (bcm_tlv_t*)buf; + GCC_DIAGNOSTIC_POP(); + totlen = buflen; /* find tagged parameter */ while (totlen >= TLV_HDR_LEN) { int len = elt->len; - /* validate remaining totlen */ - if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { + do { + /* validate remaining totlen */ + if (totlen < (int)(len + TLV_HDR_LEN)) + break; - return (elt); - } + if (id_ext) { + if (!DOT11_MNG_IE_ID_EXT_MATCH(elt, key)) + break; + } else if (elt->id != key) { + break; + } + + return (bcm_tlv_t *)(elt); /* a match */ + } while (0); elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); totlen -= (len + TLV_HDR_LEN); @@ -1932,9 +3115,10 @@ * return NULL if not found or length field < min_varlen */ bcm_tlv_t * -bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen) +bcm_parse_tlvs_min_bodylen(const void *buf, int buflen, uint key, int min_bodylen) { - bcm_tlv_t * ret = bcm_parse_tlvs(buf, buflen, key); + bcm_tlv_t * ret; + ret = bcm_parse_tlvs(buf, (uint)buflen, key); if (ret == NULL || ret->len < min_bodylen) { return NULL; } @@ -1947,13 +3131,13 @@ * matches tag. Stop parsing when we see an element whose ID is greater * than the target key. */ -bcm_tlv_t * -bcm_parse_ordered_tlvs(void *buf, int buflen, uint key) +const bcm_tlv_t * +bcm_parse_ordered_tlvs(const void *buf, int buflen, uint key) { - bcm_tlv_t *elt; + const bcm_tlv_t *elt; int totlen; - elt = (bcm_tlv_t*)buf; + elt = (const bcm_tlv_t*)buf; totlen = buflen; /* find tagged parameter */ @@ -1971,7 +3155,7 @@ return (elt); } - elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); + elt = (const bcm_tlv_t*)((const uint8*)elt + (len + TLV_HDR_LEN)); totlen -= (len + TLV_HDR_LEN); } return NULL; @@ -1996,8 +3180,8 @@ bit = bd->bitfield[i].bit; if ((flags & mask) == bit) { if (len > (int)strlen(name)) { - slen = strlen(name); - strncpy(buf, name, slen+1); + slen = (int)strlen(name); + strncpy(buf, name, (size_t)slen+1); } break; } @@ -2031,7 +3215,7 @@ } else if ((flags & bit) == 0) continue; flags &= ~bit; - nlen = strlen(name); + nlen = (int)strlen(name); slen += nlen; /* count btwn flag space */ if (flags != 0) @@ -2040,7 +3224,7 @@ if (len <= slen) break; /* copy NULL char but don't count it */ - strncpy(p, name, nlen + 1); + strncpy(p, name, (size_t)nlen + 1); p += nlen; /* copy btwn flag space and NULL char */ if (flags != 0) @@ -2054,7 +3238,58 @@ return (int)(p - buf); } -#endif + +/* print out whcih bits in octet array 'addr' are set. bcm_bit_desc_t:bit is a bit offset. */ +int +bcm_format_octets(const bcm_bit_desc_t *bd, uint bdsz, + const uint8 *addr, uint size, char *buf, int len) +{ + uint i; + char *p = buf; + int slen = 0, nlen = 0; + uint32 bit; + const char* name; + bool more = FALSE; + + BCM_REFERENCE(size); + + if (len < 2 || !buf) + return 0; + + buf[0] = '\0'; + + for (i = 0; i < bdsz; i++) { + bit = bd[i].bit; + name = bd[i].name; + CLANG_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + if (isset(addr, bit)) { + CLANG_DIAGNOSTIC_POP(); + nlen = (int)strlen(name); + slen += nlen; + /* need SPACE - for simplicity */ + slen += 1; + /* need NULL as well */ + if (len < slen + 1) { + more = TRUE; + break; + } + memcpy(p, name, (size_t)nlen); + p += nlen; + p[0] = ' '; + p += 1; + p[0] = '\0'; + } + } + + if (more) { + p[0] = '>'; + p += 1; + p[0] = '\0'; + } + + return (int)(p - buf); +} +#endif // endif /* print bytes formatted as hex to a string. return the resulting string length */ int @@ -2073,7 +3308,7 @@ /* pretty hex print a contiguous buffer */ void -prhex(const char *msg, uchar *buf, uint nbytes) +prhex(const char *msg, const uchar *buf, uint nbytes) { char line[128], *p; int len = sizeof(line); @@ -2086,12 +3321,12 @@ p = line; for (i = 0; i < nbytes; i++) { if (i % 16 == 0) { - nchar = snprintf(p, len, " %04x: ", i); /* line prefix */ + nchar = snprintf(p, (size_t)len, " %04x: ", i); /* line prefix */ p += nchar; len -= nchar; } if (len > 0) { - nchar = snprintf(p, len, "%02x ", buf[i]); + nchar = snprintf(p, (size_t)len, "%02x ", buf[i]); p += nchar; len -= nchar; } @@ -2116,11 +3351,22 @@ "AES_CCM", "AES_OCB_MSDU", "AES_OCB_MPDU", +#ifdef BCMCCX + "CKIP", + "CKIP_MMH", + "WEP_MMH", + "NALG", +#else "NALG", "UNDEF", "UNDEF", "UNDEF", +#endif /* BCMCCX */ +#ifdef BCMWAPI_WAI "WAPI", +#else + "UNDEF", +#endif // endif "PMK", "BIP", "AES_GCM", @@ -2138,14 +3384,24 @@ return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR"; } - char * bcm_chipname(uint chipid, char *buf, uint len) { const char *fmt; fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; + /* + * The following call to snprintf generates a compiler warning + * due to -Wformat-nonliteral. However, the format string is coming + * from internal callers rather than external data input, and is a + * useful debugging tool serving a variety of diagnostics. Rather + * than expand code size by replicating multiple functions with different + * argument lists, or disabling the warning globally, let's consider + * if we can just disable the warning for this one instance. + */ + CLANG_DIAGNOSTIC_PUSH_SUPPRESS_FORMAT() snprintf(buf, len, fmt, chipid); + CLANG_DIAGNOSTIC_POP() return buf; } @@ -2203,21 +3459,33 @@ while (bufsize > 1) { if (cur_ptr->nameandfmt == NULL) break; + + /* + * The following call to snprintf generates a compiler warning + * due to -Wformat-nonliteral. However, the format string is coming + * from internal callers rather than external data input, and is a + * useful debugging tool serving a variety of diagnostics. Rather + * than expand code size by replicating multiple functions with different + * argument lists, or disabling the warning globally, let's consider + * if we can just disable the warning for this one instance. + */ + CLANG_DIAGNOSTIC_PUSH_SUPPRESS_FORMAT() len = snprintf(buf, bufsize, cur_ptr->nameandfmt, - read_rtn(arg0, arg1, cur_ptr->offset)); + read_rtn(arg0, arg1, cur_ptr->offset)); + CLANG_DIAGNOSTIC_POP() /* check for snprintf overflow or error */ if (len < 0 || (uint32)len >= bufsize) - len = bufsize - 1; + len = (int)(bufsize - 1); buf += len; - bufsize -= len; - filled_len += len; + bufsize -= (uint32)len; + filled_len += (uint32)len; cur_ptr++; } return filled_len; } uint -bcm_mkiovar(const char *name, char *data, uint datalen, char *buf, uint buflen) +bcm_mkiovar(const char *name, const char *data, uint datalen, char *buf, uint buflen) { uint len; @@ -2258,7 +3526,7 @@ #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */ static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = { -/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */ +/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */ /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000, /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849, /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119, @@ -2288,7 +3556,7 @@ /* return the mW value scaled down to the correct factor of 10, * adding in factor/2 to get proper rounding. */ - return ((nqdBm_to_mW_map[idx] + factor/2) / factor); + return (uint16)((nqdBm_to_mW_map[idx] + factor/2) / factor); } uint8 @@ -2322,7 +3590,6 @@ return (qdbm); } - uint bcm_bitcount(uint8 *bitmap, uint length) { @@ -2337,175 +3604,6 @@ } return bitcount; } - -#if defined(BCMDRIVER) || defined(WL_UNITTEST) - -/* triggers bcm_bprintf to print to kernel log */ -bool bcm_bprintf_bypass = FALSE; - -/* Initialization of bcmstrbuf structure */ -void -bcm_binit(struct bcmstrbuf *b, char *buf, uint size) -{ - b->origsize = b->size = size; - b->origbuf = b->buf = buf; -} - -/* Buffer sprintf wrapper to guard against buffer overflow */ -int -bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) -{ - va_list ap; - int r; - - va_start(ap, fmt); - - r = vsnprintf(b->buf, b->size, fmt, ap); - if (bcm_bprintf_bypass == TRUE) { - printf("%s\n", b->buf); - goto exit; - } - - /* Non Ansi C99 compliant returns -1, - * Ansi compliant return r >= b->size, - * bcmstdlib returns 0, handle all - */ - /* r == 0 is also the case when strlen(fmt) is zero. - * typically the case when "" is passed as argument. - */ - if ((r == -1) || (r >= (int)b->size)) { - b->size = 0; - } else { - b->size -= r; - b->buf += r; - } - -exit: - va_end(ap); - - return r; -} - -void -bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, int len) -{ - int i; - - if (msg != NULL && msg[0] != '\0') - bcm_bprintf(b, "%s", msg); - for (i = 0; i < len; i ++) - bcm_bprintf(b, "%02X", buf[i]); - if (newline) - bcm_bprintf(b, "\n"); -} - -void -bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) -{ - int i; - - for (i = 0; i < num_bytes; i++) { - num[i] += amount; - if (num[i] >= amount) - break; - amount = 1; - } -} - -int -bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes) -{ - int i; - - for (i = nbytes - 1; i >= 0; i--) { - if (arg1[i] != arg2[i]) - return (arg1[i] - arg2[i]); - } - return 0; -} - -void -bcm_print_bytes(const char *name, const uchar *data, int len) -{ - int i; - int per_line = 0; - - printf("%s: %d \n", name ? name : "", len); - for (i = 0; i < len; i++) { - printf("%02x ", *data++); - per_line++; - if (per_line == 16) { - per_line = 0; - printf("\n"); - } - } - printf("\n"); -} - -/* Look for vendor-specific IE with specified OUI and optional type */ -bcm_tlv_t * -bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len) -{ - bcm_tlv_t *ie; - uint8 ie_len; - - ie = (bcm_tlv_t*)tlvs; - - /* make sure we are looking at a valid IE */ - if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) { - return NULL; - } - - /* Walk through the IEs looking for an OUI match */ - do { - ie_len = ie->len; - if ((ie->id == DOT11_MNG_PROPR_ID) && - (ie_len >= (DOT11_OUI_LEN + type_len)) && - !bcmp(ie->data, voui, DOT11_OUI_LEN)) - { - /* compare optional type */ - if (type_len == 0 || - !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) { - return (ie); /* a match */ - } - } - } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL); - - return NULL; -} - -#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ - defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) -#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) - -int -bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) -{ - uint i, c; - char *p = buf; - char *endp = buf + SSID_FMT_BUF_LEN; - - if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; - - for (i = 0; i < ssid_len; i++) { - c = (uint)ssid[i]; - if (c == '\\') { - *p++ = '\\'; - *p++ = '\\'; - } else if (bcm_isprint((uchar)c)) { - *p++ = (char)c; - } else { - p += snprintf(p, (endp - p), "\\x%02X", c); - } - } - *p = '\0'; - ASSERT(p < endp); - - return (int)(p - buf); -} -#endif - -#endif /* BCMDRIVER || WL_UNITTEST */ /* * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL. @@ -2560,64 +3658,6 @@ *dp++ = 0; return buf_len; -} - -/* calculate a * b + c */ -void -bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c) -{ -#define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;} - uint32 r1, r0; - uint32 a1, a0, b1, b0, t, cc = 0; - - a1 = a >> 16; - a0 = a & 0xffff; - b1 = b >> 16; - b0 = b & 0xffff; - - r0 = a0 * b0; - FORMALIZE(r0); - - t = (a1 * b0) << 16; - FORMALIZE(t); - - r0 += t; - FORMALIZE(r0); - - t = (a0 * b1) << 16; - FORMALIZE(t); - - r0 += t; - FORMALIZE(r0); - - FORMALIZE(c); - - r0 += c; - FORMALIZE(r0); - - r0 |= (cc % 2) ? 0x80000000 : 0; - r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2); - - *r_high = r1; - *r_low = r0; -} - -/* calculate a / b */ -void -bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b) -{ - uint32 a1 = a_high, a0 = a_low, r0 = 0; - - if (b < 2) - return; - - while (a1 != 0) { - r0 += (0xffffffff / b) * a1; - bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0); - } - - r0 += a0 / b; - *r = r0; } #ifndef setbit /* As in the header file */ @@ -2686,7 +3726,12 @@ { int i; for (i = NBITS(uint32) - 1; i >= 0; i--) { - printf(isbitset(u32arg, i) ? "1" : "0"); + if (isbitset(u32arg, i)) { + printf("1"); + } else { + printf("0"); + } + if ((i % NBBY) == 0) printf(" "); } printf("\n"); @@ -2697,13 +3742,13 @@ bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum) { while (len > 1) { - sum += (buf[0] << 8) | buf[1]; + sum += (uint32)((buf[0] << 8) | buf[1]); buf += 2; len -= 2; } if (len > 0) { - sum += (*buf) << 8; + sum += (uint32)((*buf) << 8); } while (sum >> 16) { @@ -2712,797 +3757,11 @@ return ((uint16)~sum); } -#if defined(BCMDRIVER) && !defined(_CFEZ_) -/* - * Hierarchical Multiword bitmap based small id allocator. - * - * Multilevel hierarchy bitmap. (maximum 2 levels) - * First hierarchy uses a multiword bitmap to identify 32bit words in the - * second hierarchy that have at least a single bit set. Each bit in a word of - * the second hierarchy represents a unique ID that may be allocated. - * - * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed. - * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word - * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs. - * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non - * non-zero bitmap word carrying at least one free ID. - * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations. - * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID - * - * Design Notes: - * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many - * bits are computed each time on allocation and deallocation, requiring 4 - * array indexed access and 3 arithmetic operations. When not defined, a runtime - * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed. - * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation. - * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may - * be used by defining BCM_MWBMAP_USE_CNTSETBITS. - * - * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array - * size is fixed. No intention to support larger than 4K indice allocation. ID - * allocators for ranges smaller than 4K will have a wastage of only 12Bytes - * with savings in not having to use an indirect access, had it been dynamically - * allocated. - */ -#define BCM_MWBMAP_ITEMS_MAX (64 * 1024) /* May increase to 64K */ -#define BCM_MWBMAP_BITS_WORD (NBITS(uint32)) -#define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD) -#define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD) -#define BCM_MWBMAP_SHIFT_OP (5) -#define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1)) -#define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP) -#define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP) - -/* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */ -#define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl)) -#define BCM_MWBMAP_HDL(ptr) ((void *)(ptr)) - -#if defined(BCM_MWBMAP_DEBUG) -#define BCM_MWBMAP_AUDIT(mwb) \ - do { \ - ASSERT((mwb != NULL) && \ - (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \ - bcm_mwbmap_audit(mwb); \ - } while (0) -#define MWBMAP_ASSERT(exp) ASSERT(exp) -#define MWBMAP_DBG(x) printf x -#else /* !BCM_MWBMAP_DEBUG */ -#define BCM_MWBMAP_AUDIT(mwb) do {} while (0) -#define MWBMAP_ASSERT(exp) do {} while (0) -#define MWBMAP_DBG(x) -#endif /* !BCM_MWBMAP_DEBUG */ - - -typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */ - uint16 wmaps; /* Total number of words in free wd bitmap */ - uint16 imaps; /* Total number of words in free id bitmap */ - int32 ifree; /* Count of free indices. Used only in audits */ - uint16 total; /* Total indices managed by multiword bitmap */ - - void * magic; /* Audit handle parameter from user */ - - uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */ -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */ -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - - uint32 id_bitmap[0]; /* Second level bitmap */ -} bcm_mwbmap_t; - -/* Incarnate a hierarchical multiword bitmap based small index allocator. */ -struct bcm_mwbmap * -bcm_mwbmap_init(osl_t *osh, uint32 items_max) +int +BCMRAMFN(valid_bcmerror)(int e) { - struct bcm_mwbmap * mwbmap_p; - uint32 wordix, size, words, extra; - - /* Implementation Constraint: Uses 32bit word bitmap */ - MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U); - MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U); - MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX)); - MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U); - - ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX); - - /* Determine the number of words needed in the multiword bitmap */ - extra = BCM_MWBMAP_MODOP(items_max); - words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U); - - /* Allocate runtime state of multiword bitmap */ - /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */ - size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words); - mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size); - if (mwbmap_p == (bcm_mwbmap_t *)NULL) { - ASSERT(0); - goto error1; - } - memset(mwbmap_p, 0, size); - - /* Initialize runtime multiword bitmap state */ - mwbmap_p->imaps = (uint16)words; - mwbmap_p->ifree = (int32)items_max; - mwbmap_p->total = (uint16)items_max; - - /* Setup magic, for use in audit of handle */ - mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p); - - /* Setup the second level bitmap of free indices */ - /* Mark all indices as available */ - for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) { - mwbmap_p->id_bitmap[wordix] = (uint32)(~0U); -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD; -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - } - - /* Ensure that extra indices are tagged as un-available */ - if (extra) { /* fixup the free ids in last bitmap and wd_count */ - uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1]; - *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */ -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - } - - /* Setup the first level bitmap hierarchy */ - extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps); - words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U); - - mwbmap_p->wmaps = (uint16)words; - - for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++) - mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U); - if (extra) { - uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1]; - *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ - } - - return mwbmap_p; - -error1: - return BCM_MWBMAP_INVALID_HDL; -} - -/* Release resources used by multiword bitmap based small index allocator. */ -void -bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap) - + (sizeof(uint32) * mwbmap_p->imaps)); - return; -} - -/* Allocate a unique small index using a multiword bitmap index allocator. */ -uint32 BCMFASTPATH -bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 wordix, bitmap; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - /* Start with the first hierarchy */ - for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) { - - bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */ - - if (bitmap != 0U) { - - uint32 count, bitix, *bitmap_p; - - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - - /* clear all except trailing 1 */ - bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); - MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == - bcm_count_leading_zeros(bitmap)); - bitix = (BCM_MWBMAP_BITS_WORD - 1) - - bcm_count_leading_zeros(bitmap); /* use asm clz */ - wordix = BCM_MWBMAP_MULOP(wordix) + bitix; - - /* Clear bit if wd count is 0, without conditional branch */ -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1; -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - mwbmap_p->wd_count[wordix]--; - count = mwbmap_p->wd_count[wordix]; - MWBMAP_ASSERT(count == - (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1)); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - MWBMAP_ASSERT(count >= 0); - - /* clear wd_bitmap bit if id_map count is 0 */ - bitmap = (count == 0) << bitix; - - MWBMAP_DBG(( - "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count)); - - *bitmap_p ^= bitmap; - - /* Use bitix in the second hierarchy */ - bitmap_p = &mwbmap_p->id_bitmap[wordix]; - - bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */ - MWBMAP_ASSERT(bitmap != 0U); - - /* clear all except trailing 1 */ - bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); - MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == - bcm_count_leading_zeros(bitmap)); - bitix = BCM_MWBMAP_MULOP(wordix) - + (BCM_MWBMAP_BITS_WORD - 1) - - bcm_count_leading_zeros(bitmap); /* use asm clz */ - - mwbmap_p->ifree--; /* decrement system wide free count */ - MWBMAP_ASSERT(mwbmap_p->ifree >= 0); - - MWBMAP_DBG(( - "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, - mwbmap_p->ifree)); - - *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */ - - return bitix; - } - } - - ASSERT(mwbmap_p->ifree == 0); - - return BCM_MWBMAP_INVALID_IDX; -} - -/* Force an index at a specified position to be in use */ -void -bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 count, wordix, bitmap, *bitmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(bitix < mwbmap_p->total); - - /* Start with second hierarchy */ - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix)); - bitmap_p = &mwbmap_p->id_bitmap[wordix]; - - ASSERT((*bitmap_p & bitmap) == bitmap); - - mwbmap_p->ifree--; /* update free count */ - ASSERT(mwbmap_p->ifree >= 0); - - MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, - mwbmap_p->ifree)); - - *bitmap_p ^= bitmap; /* mark as in use */ - - /* Update first hierarchy */ - bitix = wordix; - - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - mwbmap_p->wd_count[bitix]--; - count = mwbmap_p->wd_count[bitix]; - MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - MWBMAP_ASSERT(count >= 0); - - bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix); - - MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d", - BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap, - (*bitmap_p) ^ bitmap, count)); - - *bitmap_p ^= bitmap; /* mark as in use */ - - return; -} - -/* Free a previously allocated index back into the multiword bitmap allocator */ -void BCMFASTPATH -bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 wordix, bitmap, *bitmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(bitix < mwbmap_p->total); - - /* Start with second level hierarchy */ - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); - bitmap_p = &mwbmap_p->id_bitmap[wordix]; - - ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */ - - mwbmap_p->ifree++; /* update free count */ - ASSERT(mwbmap_p->ifree <= mwbmap_p->total); - - MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, - mwbmap_p->ifree)); - - *bitmap_p |= bitmap; /* mark as available */ - - /* Now update first level hierarchy */ - - bitix = wordix; - - wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */ - bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - mwbmap_p->wd_count[bitix]++; -#endif - -#if defined(BCM_MWBMAP_DEBUG) - { - uint32 count; -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - count = mwbmap_p->wd_count[bitix]; - MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - - MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD); - - MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count)); - } -#endif /* BCM_MWBMAP_DEBUG */ - - *bitmap_p |= bitmap; - - return; -} - -/* Fetch the toal number of free indices in the multiword bitmap allocator */ -uint32 -bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(mwbmap_p->ifree >= 0); - - return mwbmap_p->ifree; -} - -/* Determine whether an index is inuse or free */ -bool -bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 wordix, bitmap; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(bitix < mwbmap_p->total); - - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); - - return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U); -} - -/* Debug dump a multiword bitmap allocator */ -void -bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl) -{ - uint32 ix, count; - bcm_mwbmap_t * mwbmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p, - mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total); - for (ix = 0U; ix < mwbmap_p->wmaps; ix++) { - printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]); - bcm_bitprint32(mwbmap_p->wd_bitmap[ix]); - printf("\n"); - } - for (ix = 0U; ix < mwbmap_p->imaps; ix++) { -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - count = mwbmap_p->wd_count[ix]; - MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count); - bcm_bitprint32(mwbmap_p->id_bitmap[ix]); - printf("\n"); - } - - return; -} - -/* Audit a hierarchical multiword bitmap */ -void -bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p; - - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) { - - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - - for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) { - if ((*bitmap_p) & (1 << bitix)) { - idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix; -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - count = mwbmap_p->wd_count[idmap_ix]; - ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - ASSERT(count != 0U); - free_cnt += count; - } - } - } - - ASSERT((int)free_cnt == mwbmap_p->ifree); -} -/* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */ - -/* Simple 16bit Id allocator using a stack implementation. */ -typedef struct id16_map { - uint32 failures; /* count of failures */ - void *dbg; /* debug placeholder */ - uint16 total; /* total number of ids managed by allocator */ - uint16 start; /* start value of 16bit ids to be managed */ - int stack_idx; /* index into stack of available ids */ - uint16 stack[0]; /* stack of 16 bit ids */ -} id16_map_t; - -#define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \ - (sizeof(uint16) * (items))) - -#if defined(BCM_DBG) - -/* Uncomment BCM_DBG_ID16 to debug double free */ -/* #define BCM_DBG_ID16 */ - -typedef struct id16_map_dbg { - uint16 total; - bool avail[0]; -} id16_map_dbg_t; -#define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \ - (sizeof(bool) * (items))) -#define ID16_MAP_MSG(x) print x -#else -#define ID16_MAP_MSG(x) -#endif /* BCM_DBG */ - -void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */ -id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16) -{ - uint16 idx, val16; - id16_map_t * id16_map; - - ASSERT(total_ids > 0); - - /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map - * with random values. - */ - ASSERT((start_val16 == ID16_UNDEFINED) || - (start_val16 + total_ids) < ID16_INVALID); - - id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids)); - if (id16_map == NULL) { - return NULL; - } - - id16_map->total = total_ids; - id16_map->start = start_val16; - id16_map->failures = 0; - id16_map->dbg = NULL; - - /* - * Populate stack with 16bit id values, commencing with start_val16. - * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map. - */ - id16_map->stack_idx = -1; - - if (id16_map->start != ID16_UNDEFINED) { - val16 = start_val16; - - for (idx = 0; idx < total_ids; idx++, val16++) { - id16_map->stack_idx = idx; - id16_map->stack[id16_map->stack_idx] = val16; - } - } - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->start != ID16_UNDEFINED) { - id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids)); - - if (id16_map->dbg) { - id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; - - id16_map_dbg->total = total_ids; - for (idx = 0; idx < total_ids; idx++) { - id16_map_dbg->avail[idx] = TRUE; - } - } - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - - return (void *)id16_map; -} - -void * /* Destruct an id16 allocator instance */ -id16_map_fini(osl_t *osh, void * id16_map_hndl) -{ - uint16 total_ids; - id16_map_t * id16_map; - - if (id16_map_hndl == NULL) - return NULL; - - id16_map = (id16_map_t *)id16_map_hndl; - - total_ids = id16_map->total; - ASSERT(total_ids > 0); - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->dbg) { - MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids)); - id16_map->dbg = NULL; - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - - id16_map->total = 0; - MFREE(osh, id16_map, ID16_MAP_SZ(total_ids)); - - return NULL; -} - -void -id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16) -{ - uint16 idx, val16; - id16_map_t * id16_map; - - ASSERT(total_ids > 0); - /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map - * with random values. - */ - ASSERT((start_val16 == ID16_UNDEFINED) || - (start_val16 + total_ids) < ID16_INVALID); - - id16_map = (id16_map_t *)id16_map_hndl; - if (id16_map == NULL) { - return; - } - - id16_map->total = total_ids; - id16_map->start = start_val16; - id16_map->failures = 0; - - /* Populate stack with 16bit id values, commencing with start_val16 */ - id16_map->stack_idx = -1; - - if (id16_map->start != ID16_UNDEFINED) { - val16 = start_val16; - - for (idx = 0; idx < total_ids; idx++, val16++) { - id16_map->stack_idx = idx; - id16_map->stack[id16_map->stack_idx] = val16; - } - } - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->start != ID16_UNDEFINED) { - if (id16_map->dbg) { - id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; - - id16_map_dbg->total = total_ids; - for (idx = 0; idx < total_ids; idx++) { - id16_map_dbg->avail[idx] = TRUE; - } - } - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ -} - -uint16 BCMFASTPATH /* Allocate a unique 16bit id */ -id16_map_alloc(void * id16_map_hndl) -{ - uint16 val16; - id16_map_t * id16_map; - - ASSERT(id16_map_hndl != NULL); - - id16_map = (id16_map_t *)id16_map_hndl; - - ASSERT(id16_map->total > 0); - - if (id16_map->stack_idx < 0) { - id16_map->failures++; - return ID16_INVALID; - } - - val16 = id16_map->stack[id16_map->stack_idx]; - id16_map->stack_idx--; - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - ASSERT((id16_map->start == ID16_UNDEFINED) || - (val16 < (id16_map->start + id16_map->total))); - - if (id16_map->dbg) { /* Validate val16 */ - id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; - - ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE); - id16_map_dbg->avail[val16 - id16_map->start] = FALSE; - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - - return val16; -} - - -void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */ -id16_map_free(void * id16_map_hndl, uint16 val16) -{ - id16_map_t * id16_map; - - ASSERT(id16_map_hndl != NULL); - - id16_map = (id16_map_t *)id16_map_hndl; - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - ASSERT((id16_map->start == ID16_UNDEFINED) || - (val16 < (id16_map->start + id16_map->total))); - - if (id16_map->dbg) { /* Validate val16 */ - id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; - - ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE); - id16_map_dbg->avail[val16 - id16_map->start] = TRUE; - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - - id16_map->stack_idx++; - id16_map->stack[id16_map->stack_idx] = val16; -} - -uint32 /* Returns number of failures to allocate an unique id16 */ -id16_map_failures(void * id16_map_hndl) -{ - ASSERT(id16_map_hndl != NULL); - return ((id16_map_t *)id16_map_hndl)->failures; -} - -bool -id16_map_audit(void * id16_map_hndl) -{ - int idx; - int insane = 0; - id16_map_t * id16_map; - - ASSERT(id16_map_hndl != NULL); - - id16_map = (id16_map_t *)id16_map_hndl; - - ASSERT(id16_map->stack_idx >= -1); - ASSERT(id16_map->stack_idx < (int)id16_map->total); - - if (id16_map->start == ID16_UNDEFINED) - goto done; - - for (idx = 0; idx <= id16_map->stack_idx; idx++) { - ASSERT(id16_map->stack[idx] >= id16_map->start); - ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total)); - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->dbg) { - uint16 val16 = id16_map->stack[idx]; - if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) { - insane |= 1; - ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n", - id16_map_hndl, idx, val16)); - } - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - } - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->dbg) { - uint16 avail = 0; /* Audit available ids counts */ - for (idx = 0; idx < id16_map_dbg->total; idx++) { - if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE) - avail++; - } - if (avail && (avail != (id16_map->stack_idx + 1))) { - insane |= 1; - ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n", - id16_map_hndl, avail, id16_map->stack_idx)); - } - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - -done: - /* invoke any other system audits */ - return (!!insane); -} -/* END: Simple id16 allocator */ - - -#endif - -/* calculate a >> b; and returns only lower 32 bits */ -void -bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b) -{ - uint32 a1 = a_high, a0 = a_low, r0 = 0; - - if (b == 0) { - r0 = a_low; - *r = r0; - return; - } - - if (b < 32) { - a0 = a0 >> b; - a1 = a1 & ((1 << b) - 1); - a1 = a1 << (32 - b); - r0 = a0 | a1; - *r = r0; - return; - } else { - r0 = a1 >> (b - 32); - *r = r0; - return; - } - -} - -/* calculate a + b where a is a 64 bit number and b is a 32 bit number */ -void -bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset) -{ - uint32 r1_lo = *r_lo; - (*r_lo) += offset; - if (*r_lo < r1_lo) - (*r_hi) ++; -} - -/* calculate a - b where a is a 64 bit number and b is a 32 bit number */ -void -bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset) -{ - uint32 r1_lo = *r_lo; - (*r_lo) -= offset; - if (*r_lo > r1_lo) - (*r_hi) --; + return ((e <= 0) && (e >= BCME_LAST)); } #ifdef DEBUG_COUNTER @@ -3534,85 +3793,6 @@ #define counter_printlog(a) do {} while (0) #endif /* OSL_SYSUPTIME_SUPPORT == TRUE */ #endif /* DEBUG_COUNTER */ - -#if defined(BCMDRIVER) && !defined(_CFEZ_) -void -dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size) -{ - uint32 mem_size; - mem_size = sizeof(dll_pool_t) + (elems_max * elem_size); - if (pool) - MFREE(osh, pool, mem_size); -} -dll_pool_t * -dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size) -{ - uint32 mem_size, i; - dll_pool_t * dll_pool_p; - dll_t * elem_p; - - ASSERT(elem_size > sizeof(dll_t)); - - mem_size = sizeof(dll_pool_t) + (elems_max * elem_size); - - if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, mem_size)) == NULL) { - printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n", - elems_max, elem_size); - ASSERT(0); - return dll_pool_p; - } - - dll_init(&dll_pool_p->free_list); - dll_pool_p->elems_max = elems_max; - dll_pool_p->elem_size = elem_size; - - elem_p = dll_pool_p->elements; - for (i = 0; i < elems_max; i++) { - dll_append(&dll_pool_p->free_list, elem_p); - elem_p = (dll_t *)((uintptr)elem_p + elem_size); - } - - dll_pool_p->free_count = elems_max; - - return dll_pool_p; -} - - -void * -dll_pool_alloc(dll_pool_t * dll_pool_p) -{ - dll_t * elem_p; - - if (dll_pool_p->free_count == 0) { - ASSERT(dll_empty(&dll_pool_p->free_list)); - return NULL; - } - - elem_p = dll_head_p(&dll_pool_p->free_list); - dll_delete(elem_p); - dll_pool_p->free_count -= 1; - - return (void *)elem_p; -} - -void -dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p) -{ - dll_t * node_p = (dll_t *)elem_p; - dll_prepend(&dll_pool_p->free_list, node_p); - dll_pool_p->free_count += 1; -} - - -void -dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p) -{ - dll_t * node_p = (dll_t *)elem_p; - dll_append(&dll_pool_p->free_list, node_p); - dll_pool_p->free_count += 1; -} - -#endif /* calculate partial checksum */ static uint32 @@ -3674,5 +3854,498 @@ ptr += OFFSETOF(struct ipv4_hdr, hdr_chksum) + 2; /* return calculated chksum */ - return ip_cksum(sum, ptr, ip_len - OFFSETOF(struct ipv4_hdr, src_ip)); + return ip_cksum(sum, ptr, (uint32)((uint)ip_len - OFFSETOF(struct ipv4_hdr, src_ip))); +} + +/* calculate TCP header checksum using partial sum */ +static uint16 +tcp_hdr_chksum(uint32 sum, uint8 *tcp_hdr, uint16 tcp_len) +{ + uint8 *ptr = tcp_hdr; + + ASSERT(tcp_hdr != NULL); + ASSERT(tcp_len >= TCP_MIN_HEADER_LEN); + + /* partial TCP cksum skipping the chksum field */ + sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct bcmtcp_hdr, chksum)); + ptr += OFFSETOF(struct bcmtcp_hdr, chksum) + 2; + + /* return calculated chksum */ + return ip_cksum(sum, ptr, tcp_len - OFFSETOF(struct bcmtcp_hdr, urg_ptr)); +} + +struct tcp_pseudo_hdr { + uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */ + uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */ + uint8 zero; + uint8 prot; + uint16 tcp_size; +}; + +/* calculate IPv4 TCP header checksum + * - input ip and tcp points to IP and TCP header in network order + * - output cksum is in network order + */ +uint16 +ipv4_tcp_hdr_cksum(uint8 *ip, uint8 *tcp, uint16 tcp_len) +{ + struct ipv4_hdr *ip_hdr = (struct ipv4_hdr *)ip; + struct tcp_pseudo_hdr tcp_ps; + uint32 sum = 0; + + ASSERT(ip != NULL); + ASSERT(tcp != NULL); + ASSERT(tcp_len >= TCP_MIN_HEADER_LEN); + + if (!ip || !tcp || !(tcp_len >= TCP_MIN_HEADER_LEN)) + return 0; + /* pseudo header cksum */ + memset(&tcp_ps, 0, sizeof(tcp_ps)); + memcpy(&tcp_ps.dst_ip, ip_hdr->dst_ip, IPV4_ADDR_LEN); + memcpy(&tcp_ps.src_ip, ip_hdr->src_ip, IPV4_ADDR_LEN); + tcp_ps.zero = 0; + tcp_ps.prot = ip_hdr->prot; + tcp_ps.tcp_size = hton16(tcp_len); + sum = ip_cksum_partial(sum, (uint8 *)&tcp_ps, sizeof(tcp_ps)); + + /* return calculated TCP header chksum */ + return tcp_hdr_chksum(sum, tcp, tcp_len); +} + +struct ipv6_pseudo_hdr { + uint8 saddr[IPV6_ADDR_LEN]; + uint8 daddr[IPV6_ADDR_LEN]; + uint16 payload_len; + uint8 zero; + uint8 next_hdr; +}; + +/* calculate IPv6 TCP header checksum + * - input ipv6 and tcp points to IPv6 and TCP header in network order + * - output cksum is in network order + */ +uint16 +ipv6_tcp_hdr_cksum(uint8 *ipv6, uint8 *tcp, uint16 tcp_len) +{ + struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)ipv6; + struct ipv6_pseudo_hdr ipv6_pseudo; + uint32 sum = 0; + + ASSERT(ipv6 != NULL); + ASSERT(tcp != NULL); + ASSERT(tcp_len >= TCP_MIN_HEADER_LEN); + + if (!ipv6 || !tcp || !(tcp_len >= TCP_MIN_HEADER_LEN)) + return 0; + /* pseudo header cksum */ + memset((char *)&ipv6_pseudo, 0, sizeof(ipv6_pseudo)); + memcpy((char *)ipv6_pseudo.saddr, (char *)ipv6_hdr->saddr.addr, + sizeof(ipv6_pseudo.saddr)); + memcpy((char *)ipv6_pseudo.daddr, (char *)ipv6_hdr->daddr.addr, + sizeof(ipv6_pseudo.daddr)); + ipv6_pseudo.payload_len = ipv6_hdr->payload_len; + ipv6_pseudo.next_hdr = ipv6_hdr->nexthdr; + sum = ip_cksum_partial(sum, (uint8 *)&ipv6_pseudo, sizeof(ipv6_pseudo)); + + /* return calculated TCP header chksum */ + return tcp_hdr_chksum(sum, tcp, tcp_len); +} + +void *_bcmutils_dummy_fn = NULL; + +/* GROUP 1 --- start + * These function under GROUP 1 are general purpose functions to do complex number + * calculations and square root calculation. + */ + +uint32 sqrt_int(uint32 value) +{ + uint32 root = 0, shift = 0; + + /* Compute integer nearest to square root of input integer value */ + for (shift = 0; shift < 32; shift += 2) { + if (((0x40000000 >> shift) + root) <= value) { + value -= ((0x40000000 >> shift) + root); + root = (root >> 1) | (0x40000000 >> shift); + } + else { + root = root >> 1; + } + } + + /* round to the nearest integer */ + if (root < value) ++root; + + return root; +} +/* GROUP 1 --- end */ + +/* read/write field in a consecutive bits in an octet array. + * 'addr' is the octet array's start byte address + * 'size' is the octet array's byte size + * 'stbit' is the value's start bit offset + * 'nbits' is the value's bit size + * This set of utilities are for convenience. Don't use them + * in time critical/data path as there's a great overhead in them. + */ +void +setbits(uint8 *addr, uint size, uint stbit, uint nbits, uint32 val) +{ + uint fbyte = stbit >> 3; /* first byte */ + uint lbyte = (stbit + nbits - 1) >> 3; /* last byte */ + uint fbit = stbit & 7; /* first bit in the first byte */ + uint rbits = (nbits > 8 - fbit ? + nbits - (8 - fbit) : + 0) & 7; /* remaining bits of the last byte when not 0 */ + uint8 mask; + uint byte; + + BCM_REFERENCE(size); + + ASSERT(fbyte < size); + ASSERT(lbyte < size); + ASSERT(nbits <= (sizeof(val) << 3)); + + /* all bits are in the same byte */ + if (fbyte == lbyte) { + mask = (uint8)(((1 << nbits) - 1) << fbit); + addr[fbyte] &= ~mask; + addr[fbyte] |= (uint8)(val << fbit); + return; + } + + /* first partial byte */ + if (fbit > 0) { + mask = (uint8)(0xff << fbit); + addr[fbyte] &= ~mask; + addr[fbyte] |= (uint8)(val << fbit); + val >>= (8 - fbit); + nbits -= (8 - fbit); + fbyte ++; /* first full byte */ + } + + /* last partial byte */ + if (rbits > 0) { + mask = (uint8)((1 << rbits) - 1); + addr[lbyte] &= ~mask; + addr[lbyte] |= (uint8)(val >> (nbits - rbits)); + lbyte --; /* last full byte */ + } + + /* remaining full byte(s) */ + for (byte = fbyte; byte <= lbyte; byte ++) { + addr[byte] = (uint8)val; + val >>= 8; + } +} + +uint32 +getbits(const uint8 *addr, uint size, uint stbit, uint nbits) +{ + uint fbyte = stbit >> 3; /* first byte */ + uint lbyte = (stbit + nbits - 1) >> 3; /* last byte */ + uint fbit = stbit & 7; /* first bit in the first byte */ + uint rbits = (nbits > 8 - fbit ? + nbits - (8 - fbit) : + 0) & 7; /* remaining bits of the last byte when not 0 */ + uint32 val = 0; + uint bits = 0; /* bits in first partial byte */ + uint8 mask; + uint byte; + + BCM_REFERENCE(size); + + ASSERT(fbyte < size); + ASSERT(lbyte < size); + ASSERT(nbits <= (sizeof(val) << 3)); + + /* all bits are in the same byte */ + if (fbyte == lbyte) { + mask = (uint8)(((1 << nbits) - 1) << fbit); + val = (addr[fbyte] & mask) >> fbit; + return val; + } + + /* first partial byte */ + if (fbit > 0) { + bits = 8 - fbit; + mask = (uint8)(0xFFu << fbit); + val |= (addr[fbyte] & mask) >> fbit; + fbyte ++; /* first full byte */ + } + + /* last partial byte */ + if (rbits > 0) { + mask = (uint8)((1 << rbits) - 1); + val |= (uint32)((addr[lbyte] & mask) << (nbits - rbits)); + lbyte --; /* last full byte */ + } + + /* remaining full byte(s) */ + for (byte = fbyte; byte <= lbyte; byte ++) { + val |= (uint32)((addr[byte] << (((byte - fbyte) << 3) + bits))); + } + + return val; +} + +#ifdef BCMDRIVER + +/** allocate variable sized data with 'size' bytes. note: vld should NOT be null. + */ +int +bcm_vdata_alloc(osl_t *osh, var_len_data_t *vld, uint32 size) +{ + int ret = BCME_ERROR; + uint8 *dat = NULL; + + if (vld == NULL) { + ASSERT(0); + goto done; + } + + /* trying to allocate twice? */ + if (vld->vdata != NULL) { + ASSERT(0); + goto done; + } + + /* trying to allocate 0 size? */ + if (size == 0) { + ASSERT(0); + ret = BCME_BADARG; + goto done; + } + + dat = MALLOCZ(osh, size); + if (dat == NULL) { + ret = BCME_NOMEM; + goto done; + } + vld->vlen = size; + vld->vdata = dat; + ret = BCME_OK; +done: + return ret; +} + +/** free memory associated with variable sized data. note: vld should NOT be null. + */ +int +bcm_vdata_free(osl_t *osh, var_len_data_t *vld) +{ + int ret = BCME_ERROR; + + if (vld == NULL) { + ASSERT(0); + goto done; + } + + if (vld->vdata) { + MFREE(osh, vld->vdata, vld->vlen); + vld->vdata = NULL; + vld->vlen = 0; + ret = BCME_OK; + } +done: + return ret; +} + +#endif /* BCMDRIVER */ + +/* Count the number of elements not matching a given value in a null terminated array */ +int +array_value_mismatch_count(uint8 value, uint8 *array, int array_size) +{ + int i; + int count = 0; + + for (i = 0; i < array_size; i++) { + /* exit if a null terminator is found */ + if (array[i] == 0) { + break; + } + if (array[i] != value) { + count++; + } + } + return count; +} + +/* Count the number of non-zero elements in an uint8 array */ +int +array_nonzero_count(uint8 *array, int array_size) +{ + return array_value_mismatch_count(0, array, array_size); +} + +/* Count the number of non-zero elements in an int16 array */ +int +array_nonzero_count_int16(int16 *array, int array_size) +{ + int i; + int count = 0; + + for (i = 0; i < array_size; i++) { + if (array[i] != 0) { + count++; + } + } + return count; +} + +/* Count the number of zero elements in an uint8 array */ +int +array_zero_count(uint8 *array, int array_size) +{ + int i; + int count = 0; + + for (i = 0; i < array_size; i++) { + if (array[i] == 0) { + count++; + } + } + return count; +} + +/* Validate an array that can be 1 of 2 data types. + * One of array1 or array2 should be non-NULL. The other should be NULL. + */ +static int +verify_ordered_array(uint8 *array1, int16 *array2, int array_size, + int range_lo, int range_hi, bool err_if_no_zero_term, bool is_ordered) +{ + int ret; + int i; + int val = 0; + int prev_val = 0; + + ret = err_if_no_zero_term ? BCME_NOTFOUND : BCME_OK; + + /* Check that: + * - values are in strict descending order. + * - values are within the valid range. + */ + for (i = 0; i < array_size; i++) { + if (array1) { + val = (int)array1[i]; + } else if (array2) { + val = (int)array2[i]; + } else { + /* both array parameters are NULL */ + return BCME_NOTFOUND; + } + if (val == 0) { + /* array is zero-terminated */ + ret = BCME_OK; + break; + } + + if (is_ordered && i > 0 && val >= prev_val) { + /* array is not in descending order */ + ret = BCME_BADOPTION; + break; + } + prev_val = val; + + if (val < range_lo || val > range_hi) { + /* array value out of range */ + ret = BCME_RANGE; + break; + } + } + + return ret; +} + +/* Validate an ordered uint8 configuration array */ +int +verify_ordered_array_uint8(uint8 *array, int array_size, + uint8 range_lo, uint8 range_hi) +{ + return verify_ordered_array(array, NULL, array_size, (int)range_lo, (int)range_hi, + TRUE, TRUE); +} + +/* Validate an ordered int16 non-zero-terminated configuration array */ +int +verify_ordered_array_int16(int16 *array, int array_size, + int16 range_lo, int16 range_hi) +{ + return verify_ordered_array(NULL, array, array_size, (int)range_lo, (int)range_hi, + FALSE, TRUE); +} + +/* Validate all values in an array are in range */ +int +verify_array_values(uint8 *array, int array_size, + int range_lo, int range_hi, bool zero_terminated) +{ + int ret = BCME_OK; + int i; + int val = 0; + + /* Check that: + * - values are in strict descending order. + * - values are within the valid range. + */ + for (i = 0; i < array_size; i++) { + val = (int)array[i]; + if (val == 0 && zero_terminated) { + ret = BCME_OK; + break; + } + if (val < range_lo || val > range_hi) { + /* array value out of range */ + ret = BCME_RANGE; + break; + } + } + return ret; +} + +/* Adds/replaces NVRAM variable with given value + * varbuf[in,out] - Buffer with NVRAM variables (sequence of zero-terminated 'name=value' records, + * terminated with additional zero) + * buflen[in] - Length of buffer (may, even should, have some unused space) + * variable[in] - Variable to add/replace in 'name=value' form + * datalen[out,opt] - Optional output parameter - resulting length of data in buffer + * Returns TRUE on success, FALSE if buffer too short or variable specified incorrectly + */ +bool +replace_nvram_variable(char *varbuf, unsigned int buflen, const char *variable, + unsigned int *datalen) +{ + char *p; + int variable_heading_len, record_len, variable_record_len = (int)strlen(variable) + 1; + char *buf_end = varbuf + buflen; + p = strchr(variable, '='); + if (!p) { + return FALSE; + } + /* Length of given variable name, followed by '=' */ + variable_heading_len = (int)((const char *)(p + 1) - variable); + /* Scanning NVRAM, record by record up to trailing 0 */ + for (p = varbuf; *p; p += strlen(p) + 1) { + /* If given variable found - remove it */ + if (!strncmp(p, variable, (size_t)variable_heading_len)) { + record_len = (int)strlen(p) + 1; + memmove_s(p, buf_end - p, p + record_len, + (size_t)(buf_end - (p + record_len))); + } + } + /* If buffer does not have space for given variable - return FALSE */ + if ((p + variable_record_len + 1) > buf_end) { + return FALSE; + } + /* Copy given variable to end of buffer */ + memmove_s(p, buf_end - p, variable, (size_t)variable_record_len); + /* Adding trailing 0 */ + p[variable_record_len] = 0; + /* Setting optional output parameter - length of data in buffer */ + if (datalen) { + *datalen = (unsigned int)(p + variable_record_len + 1 - varbuf); + } + return TRUE; } -- Gitblit v1.6.2