📄 wlc.c
字号:
/* * Common (OS-independent) portion of * Broadcom 802.11abg Networking Device Driver * * Copyright 2005-2006, Broadcom Corporation * All Rights Reserved. * * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. * * $Id$ */#include <wlc_cfg.h>#include <typedefs.h>#include <bcmdefs.h>#include <osl.h>#include <sbutils.h>#include <bcmendian.h>#include <bcmutils.h>#include <proto/802.1d.h>#include <proto/802.11.h>#include <proto/802.11e.h>#include <proto/wpa.h>#include <proto/vlan.h>#include <sbconfig.h>#include <pcicfg.h>#include <bcmsrom.h>#include <wlioctl.h>#include <epivers.h>#include <proto/eapol.h>#include <bcmwpa.h>#include <sbhndpio.h>#include <sbhnddma.h>#include <hnddma.h>#include <d11.h>#include <wlc_rate.h>#include <wlc_pub.h>#include <wlc_rate_sel.h>#include <wlc_key.h>#include <wlc_bsscfg.h>#include <wlc_channel.h>#include <wlc_bsscfg.h>#include <wlc_pio.h>#include <wlc.h>#include <wlc_scb.h>#include <wlc_phy.h>#include <wlc_led.h>#include <wlc_frmutil.h>#include <wlc_security.h>#include <wl_export.h>#include "d11ucode.h"/* * buffer length needed for wlc_format_ssid * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL. */#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)/* antenna swap threshold */#define ANTCNT 10 /* vanilla M_MAX_ANTCNT value */#define SCAN_IN_PROGRESS(wlc) ((wlc)->scan.channel_idx != -1)#define WLC_ACTION_ASSOC 1 /* Association request for MAC */#define WLC_ACTION_ROAM 2 /* Roaming request for MAC */#define WLC_ACTION_SCAN 3 /* Scan request for MAC */#define WLC_ACTION_QUIET 4 /* Quiet request for MAC */#define WLC_ACTION_RM 5 /* Radio Measure request for MAC */#define TIMER_INTERVAL_WATCHDOG 1000 /* watchdog timer, in unit of ms */#define TIMER_INTERVAL_RADIOCHK 800 /* radio monitor timer, in unit of ms */#define BEACON_INTERVAL_DEFAULT 100 /* beacon interval, in unit of ms */#define DTIM_INTERVAL_DEFAULT 3 /* DTIM interval, in unit of beacon interval */#define SYNTHPU_DLY_APHY_US 3700 /* a phy synthpu_dly time in us */#define PRETBTT_APHY_US 120 /* a phy pretbtt time in us */#define SYNTHPU_DLY_BPHY_US 1050 /* b/g phy synthpu_dly time in us, default */#define PRETBTT_BPHY_US 250 /* b/g phy pretbtt time in us *//* * driver maintains internal 'tick'(wlc->pub.now) which increments in 1s OS timer(soft * watchdog) it is not a wall clock and won't increment when driver is in 'down" state * this low resolution driver tick can be used for maintenance tasks such as phy * calibration and scb update */#define SW_TIMER_IBSS_GMODE_RATEPROBE 60 /* periodic IBSS gmode rate probing */#define SW_TIMER_MAC_STAT_UPD 30 /* periodic MAC stats update */#define LED_TIME 200 /* 200ms wlc_led_timer() period *//* Find basic rate for a given rate : pren simply returns the same rspec */#define WLC_BASIC_RATE(wlc, rspec) ((wlc)->band->basic_rate[rspec & RSPC_RATE_MASK])/* Do we support this rate? */#define VALID_RATE(wlc, rspec) wlc_valid_rate(wlc, rspec, WLC_BAND_AUTO, FALSE)#define VALID_RATE_DBG(wlc, rspec) wlc_valid_rate(wlc, rspec, WLC_BAND_AUTO, TRUE)#define PLCP_PHYRATE(plcp, is_ofdm) (is_ofdm ? (((ofdm_phy_hdr_t *)plcp)->rlpt[0] & 0xf) : \ (((cck_phy_hdr_t *)plcp)->signal))/* To inform the ucode of the last mcast frame posted so that it can clear moredata bit */#define BCMCFID(wlc, fid) wlc_write_shm((wlc), M_BCMC_FID, (fid))#define WLC_IS_CURRENT_BSSID(wlc, bssid) \ (!bcmp((char*)(bssid), (char*)&((wlc)->BSSID), ETHER_ADDR_LEN))#define WLC_IS_TARGET_BSSID(wlc, bssid) \ (!bcmp((char*)(bssid), (char*)&((wlc)->target_bss.BSSID), ETHER_ADDR_LEN))#define WLC_IS_CURRENT_SSID(wlc, ssid, len) \ (((len) == (wlc)->pub.current_bss.SSID_len) && \ !bcmp((char*)(ssid), (char*)&((wlc)->pub.current_bss.SSID), (len)))#define WLC_IS_TARGET_SSID(wlc, ssid, len) \ (((len) == (wlc)->target_bss.SSID_len) && \ !bcmp((char*)(ssid), (char*)&((wlc)->target_bss.SSID), (len)))#define WLC_BSS_CONNECTED(wlc) \ ((wlc)->pub.associated && (!(wlc)->pub.BSS || !ETHER_ISNULLADDR(&(wlc)->BSSID)))#define IS_SINGLEBAND_5G(device) \ ((device == BCM4306_D11A_ID) || \ (device == BCM4311_D11A_ID) || \ (device == BCM4318_D11A_ID))#define START_CORE_INDEX(device, ncores) \ ((unsigned)((IS_SINGLEBAND_5G(device)) && ((ncores) == 2) ? 1 : 0))#define END_CORE_INDEX(device, ncores, nbands) \ ((unsigned)((((ncores) == 2) && (((nbands) == 2) || (IS_SINGLEBAND_5G(device)))) ? 2 : 1))#define FOR_ACTIVE_D11_CORES(loopindex, device, ncores, nbands) \ for (loopindex = START_CORE_INDEX(device, ncores); \ loopindex < END_CORE_INDEX(device, ncores, nbands); \ loopindex++)#define DMAREG(wlc, direction, fifonum) (D11REV_LT(wlc->pub.corerev, 11) ? \ ((direction == DMA_TX) ? (void*)&(wlc->regs->fifo.f32regs.dmaregs[fifonum].xmt) : \ (void*)&(wlc->regs->fifo.f32regs.dmaregs[fifonum].rcv)) : \ ((direction == DMA_TX) ? (void*)&(wlc->regs->fifo.f64regs[fifonum].dmaxmt) : \ (void*)&(wlc->regs->fifo.f64regs[fifonum].dmarcv)))#define DATA_BLOCK_SCAN (1 << 0)#define DATA_BLOCK_QUIET (1 << 1)#define DATA_BLOCK_JOIN (1 << 2)#define DATA_BLOCK_PS (1 << 3)#define WL_DUMP_BUF_SIZE (32 * 1024)#define FRAMETYPE(r, frame) ((IS_CCK(r) ? FT_CCK : FT_OFDM))/* join pref width in bits */#define WLC_JOIN_PREF_BITS_RSSI 8 /* # of bits for TLV in Join Pref for RSSI *//* join pref formats */#define WLC_JOIN_PREF_OFF_COUNT 1 /* Offset for Count for Join Pref TLV */#define WLC_JOIN_PREF_OFF_BAND 1 /* Offset for Band for Join Pref TLV */#define WLC_JOIN_PREF_LEN_FIXED 2 /* Fixed length for Join PREF TLV *//* handy macros */#define WLCWLUNIT(wlc) ((wlc)->pub.unit)#define WLCTYPEBMP(type) (1 << (type))#define WLCMAXCNT(type) (1 << (type))#define WLCMAXVAL(bits) ((1 << (bits)) - 1)#define WLCBITMASK(bits) ((1 << (bits)) - 1)#define WLC_BCMC_PSMODE(wlc) (TRUE)#define WLC_WAR16165(wlc) (wlc->war16165)#define RFDISABLE_DEFAULT 10000000 /* rfdisable delay timer 500 ms, runs of ALP clock *//* debug/trace */uint wl_msg_level = 0;/* IOVar table *//* Parameter IDs, for use only internally to wlc -- in the wlc_iovars * table and by the wlc_doiovar() function. No ordering is imposed: * the table is keyed by name, and the function uses a switch. */enum { IOV_RTSTHRESH = 1, IOV_5G_RATE, IOV_2G_RATE, IOV_FRAGTHRESH, IOV_WSEC, IOV_PWSEC, IOV_GWSEC, IOV_WSEC_KEY, IOV_WPA_AUTH, IOV_D11_AUTH, IOV_WPAIE, /* set/get the wpaie to/from the driver */ IOV_WSEC_RESTRICT, IOV_TKIP_CMS, /* TKIP counter measures */ IOV_URXEAPOL_RESTRICT, IOV_LAST /* In case of a need to check max ID number */};static uint8 WPA_info_element[] = { DOT11_MNG_WPA_ID, 0x18, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xf2, 0xff, 0x01, 0x00, 0x00, 0x50, 0xf2, 0xff, 0x01, 0x00, 0x00, 0x50, 0xf2, 0xff, 0x00, 0x00};#ifdef BCMWPA2static uint8 WPA2_info_element[] = { DOT11_MNG_RSN_ID, 0x14, 0x01, 0x00, 0x00, 0x0F, 0xAC, 0xff, 0x01, 0x00, 0x00, 0x0F, 0xAC, 0xff, 0x01, 0x00, 0x00, 0x0F, 0xAC, 0xff, 0x00, 0x00};#endif /* BCMWPA2 */const wlc_iovar_t wlc_iovars[] = { {"rtsthresh", IOV_RTSTHRESH, (IOVF_WHL), IOVT_UINT16, 0 }, {"a_rate", IOV_5G_RATE, (0), IOVT_UINT32, 0 }, {"bg_rate", IOV_2G_RATE, (0), IOVT_UINT32, 0 }, {"fragthresh", IOV_FRAGTHRESH, (0), IOVT_UINT16, 0 }, {"wsec", IOV_WSEC, (0), IOVT_UINT32, 0 }, {"pwsec", IOV_PWSEC, (0), IOVT_UINT32, 0 }, {"gwsec", IOV_GWSEC, (0), IOVT_UINT32, 0 }, {"wsec_key", IOV_WSEC_KEY, (0), IOVT_BUFFER, sizeof(wl_wsec_key_t) }, {"wpa_auth", IOV_WPA_AUTH, (0), IOVT_INT32, 0 }, {"auth", IOV_D11_AUTH, 0, IOVT_INT32, 0 }, {"wpaie", IOV_WPAIE, 0, IOVT_BUFFER, 16, }, {"wsec_restrict", IOV_WSEC_RESTRICT, (0), IOVT_BOOL, 0 }, {"tkip_countermeasures", IOV_TKIP_CMS, (0), IOVT_BOOL, 0 }, {"rx_unecrypted_restrict", IOV_URXEAPOL_RESTRICT, (0), IOVT_BOOL, 0 }, {NULL, 0, 0, 0, 0 }};uint8 wme_prio2fifo[NUMPRIO] = { TX_AC_BE_FIFO, /* 0 BE AC_BE Best Effort */ TX_AC_BK_FIFO, /* 1 BK AC_BK Background */ TX_AC_BK_FIFO, /* 2 -- AC_BK Background */ TX_AC_BE_FIFO, /* 3 EE AC_BE Best Effort */ TX_AC_VI_FIFO, /* 4 CL AC_VI Video */ TX_AC_VI_FIFO, /* 5 VI AC_VI Video */ TX_AC_VO_FIFO, /* 6 VO AC_VO Voice */ TX_AC_VO_FIFO /* 7 NC AC_VO Voice */};/* precedences numbers for wlc queues. These are twice as may levels as * 802.1D priorities. * Odd numbers are used for HI priority traffic at same precedence levels * These constants are used ONLY by wlc_prio2prec_map. Do not use them elsewhere. */#define _WLC_PREC_NONE 0 /* None = - */#define _WLC_PREC_BK 2 /* BK - Background */#define _WLC_PREC_BE 4 /* BE - Best-effort */#define _WLC_PREC_EE 6 /* EE - Excellent-effort */#define _WLC_PREC_CL 8 /* CL - Controlled Load */#define _WLC_PREC_VI 10 /* Vi - Video */#define _WLC_PREC_VO 12 /* Vo - Voice */#define _WLC_PREC_NC 14 /* NC - Network Control *//* 802.1D Priority to precedence queue mapping */const uint8 wlc_prio2prec_map[] = { _WLC_PREC_BE, /* 0 BE - Best-effort */ _WLC_PREC_BK, /* 1 BK - Background */ _WLC_PREC_NONE, /* 2 None = - */ _WLC_PREC_EE, /* 3 EE - Excellent-effort */ _WLC_PREC_CL, /* 4 CL - Controlled Load */ _WLC_PREC_VI, /* 5 Vi - Video */ _WLC_PREC_VO, /* 6 Vo - Voice */ _WLC_PREC_NC, /* 7 NC - Network Control */};/* Define a bitmap of precedences comprised by each AC */#define WLC_PREC_BMP_AC_BE (NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_BE)) | \ NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_BE)) | \ NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_EE)) | \ NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_EE)))#define WLC_PREC_BMP_AC_BK (NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_BK)) | \ NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_BK)) | \ NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_NONE)) | \ NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_NONE)))#define WLC_PREC_BMP_AC_VI (NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_CL)) | \ NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_CL)) | \ NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_VI)) | \ NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_VI)))#define WLC_PREC_BMP_AC_VO (NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_VO)) | \ NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_VO)) | \ NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_NC)) | \ NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_NC)))/* AC bitmap to precedence bitmap mapping (constructed in wlc_attach) */uint wlc_acbitmap2precbitmap[16];/* Sanity check for tx_prec_map and fifo synchup * Either there are some packets pending for the fifo, else if fifo is empty then * all the corresponding precmap bits should be set */#define WLC_TX_FIFO_CHECK(wlc, fifo) ((wlc)->core->txpktpend[(fifo)] || \ ((wlc)->core->txpktpend[(fifo)] == 0 && \ ((wlc)->tx_prec_map & (wlc)->fifo2prec_map[(fifo)]) == \ (wlc)->fifo2prec_map[(fifo)]) || \ (PIO_ENAB((wlc)) && (wlc->tx_suspended || \ !wlc_pio_txavailable((wlc)->core->pio[fifo], 1, 1))))/* TX FIFO number to WME/802.1E Access Category */const uint8 wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE, AC_BE };/* Shared memory location index for various AC params */static uint8 wme_shmemacindex[] = { 1, /* AC_BE index */ 0, /* AC_BK index */ 2, /* AC_VI index */ 3 /* AC_VO index */};/* conditions under which we want to keep the core awake */#define STAY_AWAKE(wlc) (wlc->wake || SCAN_IN_PROGRESS(wlc) || \ wlc->PMpending || wlc->assoc_state || wlc->check_for_unaligned_tbtt || \ wlc->PSpoll || wlc->apsd_sta_usp || wlc->forcefastclk || \ wlc->wakeforclkctl || wlc->pub.wakeforphyreg || wlc->wakefortxfifo || \ wlc->wakeformacsuspend || wlc->txpend16165war || wlc->PMawakebcn)#define WLC_CHAN_ID(x) (((x) & RXS_CHAN_ID_MASK) >> RXS_CHAN_ID_SHIFT)#define WLC_CHAN_PHYTYPE(x) (((x) & RXS_CHAN_PHYTYPE_MASK) >> RXS_CHAN_PHYTYPE_SHIFT)/* currently the best mechanism for determining SIFS is the band in use */#define SIFS(band) ((band)->bandtype == WLC_BAND_5G ? APHY_SIFS_TIME : BPHY_SIFS_TIME);/* value for # replay counters currently supported */#define WLC_REPLAY_CNTRS_VALUE WPA_CAP_16_REPLAY_CNTRS/* priority to replay counter (Rx IV) entry index mapping. *//** It is one-to-one mapping when there are 16 replay counters.* Otherwise it is many-to-one mapping when there are only 4* counters which are one-to-one mapped to 4 ACs.*/#if WLC_REPLAY_CNTRS_VALUE == WPA_CAP_16_REPLAY_CNTRS#define PRIO2IVIDX(prio) (prio)#elif WLC_REPLAY_CNTRS_VALUE == WPA_CAP_4_REPLAY_CNTRS#define PRIO2IVIDX(prio) WME_PRIO2AC(prio)#else#error "Neither WPA_CAP_4_REPLAY_CNTRS nor WPA_CAP_16_REPLAY_CNTRS is used"#endif /* WLC_REPLAY_CNTRS_VALUE == WPA_CAP_16_REPLAY_CNTRS *//* local prototypes */static void wlc_monitor(wlc_info_t *wlc, d11rxhdr_t *rxh, void *p);static void wlc_write_inits(wlc_info_t *wlc, const d11init_t *inits);static void wlc_wme_setparams(wlc_info_t *wlc, bool suspend);static bool wlc_is_wme_ie(wlc_info_t *wlc, uint8 *ie, uint8 **tlvs, uint *tlvs_len);static void wlc_write_ucode(wlc_info_t *wlc, const uint32 ucode[], const uint nbytes);static void wlc_write_pcm(wlc_info_t *wlc, const uint32 pcm[], const uint nbytes);static void wlc_set_txant(wlc_info_t *wlc, int txant);static void wlc_fifoerrors(wlc_info_t *wlc);static bool wlc_validboardtype(wlc_info_t *wlc);static bool wlc_isgoodchip(wlc_info_t* wlc);static void wlc_txq_enq(void *ctx, struct scb *scb, void *sdu, uint prec);static void wlc_pkt_callback(wlc_info_t *wlc, void *pkt, uint16 tx_status);static void wlc_tx_prec_map_init(wlc_info_t *wlc);static void wlc_switch_shortslot(wlc_info_t *wlc, bool shortslot);static void wlc_update_slot_timing(wlc_info_t *wlc, bool shortslot);static void wlc_watchdog(void *arg);static bool wlc_update_gbss_modes(wlc_info_t *wlc);static int wlc_set_rateset(wlc_info_t *wlc, struct rateset *rs_arg);static int wlc_iovar_rangecheck(wlc_info_t *wlc, uint32 val, const wlc_iovar_t *vi);int wlc_doiovar(void *hdl, const wlc_iovar_t *vi, uint32 actionid, const char *name, void *params, uint p_len, void *arg, int len, int val_size, struct wlc_if *wlcif);static const wlc_iovar_t* wlc_iovar_lookup(const wlc_iovar_t *table, const char *name);static void wlc_ap_upd(wlc_info_t* wlc);static char* wlc_dump_bsscfg(wlc_info_t *wlc, wlc_bsscfg_t *cfg, int bsscfg_idx, char *buf);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -