📄 wlc.c
字号:
/* send and receive */static bool wlc_txstatus(wlc_info_t *wlc, uint bound);static void wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs);static bool wlc_tx_fifo_suspended(wlc_info_t *wlc, uint tx_fifo);static void wlc_tx_suspend(wlc_info_t *wlc);static bool wlc_tx_suspended(wlc_info_t *wlc);static void wlc_tx_resume(wlc_info_t *wlc);static void wlc_tx_fifo_suspend(wlc_info_t *wlc, uint tx_fifo);static void wlc_tx_fifo_resume(wlc_info_t *wlc, uint tx_fifo);static void wlc_flushqueues(wlc_info_t *wlc);static void* wlc_allocfrag(osl_t *osh, void *sdu, uint offset, uint headroom, uint frag_length, uint tailroom);static void wlc_dofrag(wlc_info_t *wlc, void *p, uint frag, uint nfrags, uint next_payload_len, osl_t *osh, wlc_bsscfg_t *cfg, struct scb *scb, bool is8021x, uint fifo, wsec_key_t *key, uint8 prio);static bool sstlookup(wlc_info_t *wlc, uint16 proto);static uint16 wlc_compute_airtime(wlc_info_t *wlc, bool is_ofdm, uint phy_rate, uint length);static void wlc_compute_cck_plcp(ratespec_t rate, uint length, uint8 *plcp);static void wlc_compute_ofdm_plcp(ratespec_t rate, uint length, uint8 *plcp);static uint16 wlc_d11hdrs(wlc_info_t *wlc, void *p, struct scb *scb, int short_preamble, uint frag, uint nfrags, uint queue, uint next_frag_len, wsec_key_t *key, ratespec_t rate_override);static uint16 wlc_compute_rtscts_dur(wlc_info_t *wlc, bool cts_only, ratespec_t rts_rate, ratespec_t frame_rate, int short_preamble, uint frame_len);static uint16 wlc_compute_frame_dur(wlc_info_t *wlc, ratespec_t rate, int short_preamble, uint next_frag_len);static bool wlc_recv(wlc_info_t *wlc, uint fifo, uint bound);static uint16 wlc_recvfilter(wlc_info_t *wlc, struct dot11_header *h, d11rxhdr_t *rxh, struct scb **pscb);static bool wlc_mcastfilter(wlc_info_t *wlc, struct dot11_header *h);static void wlc_recvctl(wlc_info_t *wlc, osl_t *osh, d11rxhdr_t *rxh, void *p);static void wlc_process_beacon(wlc_info_t *wlc, d11rxhdr_t *rxh, uint8 *plcp, struct dot11_management_header *hdr, int frame_len);static void wlc_frameaction_specmgmt(uint action_id, wlc_info_t *wlc, struct dot11_management_header *hdr, d11rxhdr_t *rxh, uint8 *plcp, uint8 *body, int body_len);static void wlc_recv_tpc_request(wlc_info_t *wlc, d11rxhdr_t *rxh, void *plcp, struct dot11_management_header *hdr, uint8 *body, int body_len);static void wlc_recv_measure_request(wlc_info_t *wlc, struct dot11_management_header *hdr, uint8 *body, int body_len);static void wlc_recv_measure_report(wlc_info_t *wlc, struct dot11_management_header *hdr, uint8 *body, int body_len);static void wlc_recv_csa_action(wlc_info_t *wlc, struct dot11_management_header *hdr, uint8 *body, int body_len);static void wlc_send_tpc_report(wlc_info_t *wlc, struct ether_addr *da, struct ether_addr *bssid, uint8 token, int8 txpwr, int8 link_margin);static void wlc_send_measure_report(wlc_info_t *wlc, struct ether_addr *da, struct ether_addr *bssid, uint8 token, uint8 *report, uint report_len);static void wlc_frameaction_wme(uint action_id, wlc_info_t *wlc, struct dot11_management_header *hdr, uint8 *body, int body_len);static void wlc_appendfrag(wlc_info_t *wlc, void *fragbuf, uint *fragresid, uchar *body, uint body_len, void* osh);static void wlc_set_mac(wlc_info_t *wlc, struct ether_addr *addr);static void wlc_set_bssid(wlc_info_t *wlc);static void wlc_clear_bssid(wlc_info_t *wlc);static uint wlc_calc_frame_len(wlc_info_t *wlc, ratespec_t rate, int short_preamble, uint dur);static uint wlc_calc_ack_time(wlc_info_t *wlc, ratespec_t rate, int short_preamble);static uint wlc_calc_cts_time(wlc_info_t *wlc, ratespec_t rate, int short_preamble);static bool wlc_valid_rate(wlc_info_t *wlc, ratespec_t rate, int band, bool verbose);static void wlc_mod_prb_rsp_rate_table(wlc_info_t *wlc, uint frame_len);static uint16 wlc_compute_bcntsfoff(wlc_info_t *wlc, bool is_ofdm, uint phy_rate, uint short_preamble, bool phydelay);static bool wlc_nonerp_find(wlc_info_t *wlc, void *body, uint body_len, uint8 **erp, int *len);static bool wlc_erp_find(wlc_info_t *wlc, void *body, uint body_len, uint8 **erp, int *len);static void wlc_bcn_prb_template(wlc_info_t *wlc, uint type, ratespec_t bcn_rate, wlc_bsscfg_t *cfg, uint16 *buf, int *len);static uint8* wlc_copy_info_elt(uint8 *cp, const void* data);static void wlc_bcn_prb_body(wlc_info_t *wlc, uint type, wlc_bsscfg_t *cfg, uint8 *bcn, int *len);static void wlc_process_brcm_ie(wlc_info_t *wlc, struct scb *scb, brcm_ie_t *brcm_ie);static void *wlc_sendauth(wlc_info_t *wlc, struct ether_addr *ea, struct ether_addr *bssid, struct scb *scb, int auth_alg, int auth_seq, int auth_status, wsec_key_t *scb_key, uint8 *challenge_text, int short_preamble);static void *wlc_senddisassoc(wlc_info_t *wlc, const struct ether_addr *da, const struct ether_addr *bssid, struct scb *scb, uint16 reason_code);static uint32 wlc_mhfdef(wlc_info_t *wlc);static void wlc_write_mhf(wlc_info_t *wlc, uint32 val);static bool wlc_mac_request_entry(wlc_info_t* wlc, int req);static void wlc_reprate_init(wlc_info_t *wlc);static uint wlc_get_reprate(wlc_info_t *wlc);static int wlc_parse_rates(wlc_info_t *wlc, uchar *tlvs, uint tlvs_len, wlc_bss_info_t *bi, struct rateset *rates);static void wlc_update_probe_resp(wlc_info_t *wlc, wlc_bsscfg_t *cfg, bool suspend);static void wlc_update_all_probe_resp(wlc_info_t *wlc, bool suspend);extern uint16 wlc_read_ihr(wlc_info_t *wlc, uint offset);extern void wlc_write_ihr(wlc_info_t *wlc, uint offset, uint16 v);/* channel */static bool wlc_radar_channel(wlc_info_t *wlc, uint channel);/* interrupt, up/down, band */static uint32 wlc_setband_inact(wlc_info_t *wlc, uint bandunit);static void wlc_bsinit(wlc_info_t *wlc);static uint32 wlc_wlintrsoff(wlc_info_t *wlc);static void wlc_wlintrsrestore(wlc_info_t *wlc, uint32 macintmask);static bool wlc_radio_read_hwdisabled(wlc_info_t* wlc);static bool wlc_radio_monitor_start(wlc_info_t *wlc);static bool wlc_radio_monitor_stop(wlc_info_t *wlc);static void wlc_radio_timer(void *arg);static void wlc_radio_disable(wlc_info_t *wlc);static void wlc_radio_enable(wlc_info_t *wlc);static void wlc_radio_upd(wlc_info_t* wlc);static void wlc_down_led_upd(wlc_info_t *wlc);static void wlc_led_gcclear(wlc_info_t *wlc);static void wlc_timer_led(void *arg);static void wlc_timer_led_blink(void *arg);static void wlc_coreinit(wlc_info_t *wlc);static void wlc_gpio_init(wlc_info_t *wlc);/* scan, association, BSS */static void wlc_scan(wlc_info_t *wlc, int bss_type, const struct ether_addr* bssid, const uchar ssid[], int ssid_len, int scan_type, int nprobes, int active_time, int passive_time, int home_time, const uint16* channel_list, int channel_num, bool save_prb, cb_fn_t fn, void* arg);static void wlc_scan_abort(wlc_info_t *wlc);static void wlc_scantimer(void *arg);static void wlc_scan_radar_clear(wlc_info_t *wlc);static void wlc_scan_channels(wlc_info_t *wlc, uint8 *channel_list, int *pchannel_num, int channel_max, uint channel_start, int channel_type);static void wlc_scan_parse(wlc_info_t *wlc, d11rxhdr_t *rxh, uint8 *plcp, struct dot11_management_header *hdr, uint8 *body, int body_len);static wlc_bss_info_t *wlc_BSSlookup(wlc_info_t *wlc, uchar *bssid, uint channel, uchar ssid[], uint ssid_len);static int wlc_parse_bcn_prb(wlc_info_t *wlc, d11rxhdr_t *rxh, struct dot11_management_header *hdr, void *body, uint body_len, wlc_bss_info_t *bi);static int wlc_bss2wl_bss(wlc_bss_info_t *bi, wl_bss_info_t *to_bi, int to_bi_len);static void wlc_BSSinit(wlc_info_t *wlc, wlc_bss_info_t *bi, wlc_bsscfg_t *cfg, int start);static int wlc_wpa_cap(wlc_info_t *wlc, wlc_bsscfg_t *cfg, uint8 *cap, int len);static int wlc_set_rate_override(wlc_info_t *wlc, int band, int32 phy_rate, bool mcast);static void wlc_11h_do_chanswitch(wlc_info_t *wlc, uint8 newchan);static void wlc_war16165(wlc_info_t *wlc, bool tx);/* ** STA-only routines ** *//* STA association/roam scan */static void wlc_setssid_disassoc_complete(wlc_info_t *wlc, uint txstatus, void *ignore);static void wlc_roam_start(wlc_info_t *wlc, uint reason);static void wlc_assoc_scan_start(wlc_info_t *wlc, struct ether_addr *bssid);static void wlc_assoc_scan_complete(void *arg);/* STA association/roam join */static void wlc_cook_join_targets(wlc_info_t *wlc, bool roam, int cur_rssi);static void wlc_join_start_ibss(wlc_info_t *wlc, const uchar ssid[], int ssid_len);static void wlc_join_attempt(wlc_info_t *wlc);static bool wlc_join_basicrate_supported(wlc_info_t *wlc, rateset_t *rs, int band);static void wlc_join_BSS(wlc_info_t *wlc, wlc_bss_info_t* bi);static void wlc_join_adopt_bss(wlc_info_t *wlc);static void wlc_tsf_adopt_bcn(wlc_info_t *wlc, struct dot11_bcn_prb *bcn);static void wlc_join_complete(wlc_info_t *wlc, struct dot11_bcn_prb *bcn, int bcn_len);static void wlc_merge_bcn_prb(wlc_info_t *wlc, struct dot11_bcn_prb *p1, int p1_len, struct dot11_bcn_prb *p2, int p2_len, struct dot11_bcn_prb **merged, int *merged_len);static int wlc_merged_ie_len(wlc_info_t *wlc, uint8 *tlvs1, int tlvs1_len, uint8 *tlvs2, int tlvs2_len);static bool wlc_find_ie_match(bcm_tlv_t *ie, bcm_tlv_t *ies, int len);static void wlc_merge_ies(uint8 *tlvs1, int tlvs1_len, uint8 *tlvs2, int tlvs2_len, uint8* merge);static void wlc_assoc_timeout(void *arg);static void wlc_ibss_suspend(wlc_info_t *wlc);static void wlc_ibss_resume(wlc_info_t *wlc);static void *wlc_sendassocreq(wlc_info_t *wlc, wlc_bss_info_t *bi, struct scb *scb, bool reassoc);static void wlc_authresp_client(wlc_info_t *wlc, d11rxhdr_t *rxh, struct dot11_management_header *hdr, void *body, uint len);/* power save and tbtt sync */static void wlc_tbtt_adopt(wlc_info_t *wlc, struct dot11_bcn_prb *bcn);static void wlc_tbtt_align(wlc_info_t *wlc, struct dot11_bcn_prb *bcn, bool adopt, bool is_ofdm, uint phy_rate, uint short_preamble);static int wlc_bcn_tsf_later(wlc_info_t* wlc, d11rxhdr_t *rxh, void* bcn_plcp);static void wlc_ps_null_complete(wlc_info_t *wlc, uint txstatus, void *arg);static void wlc_auth_complete(wlc_info_t *wlc, uint txstatus, void *arg);static void wlc_assocreq_complete(wlc_info_t *wlc, uint txstatus, void *arg);static bool wlc_sendpspoll(wlc_info_t *wlc);static void wlc_rateprobe_complete(wlc_info_t *wlc, uint txstatus, void *ea_arg);static void wlc_rateprobe_scan(wlc_info_t *wlc);static void wlc_tkip_countermeasures(wlc_info_t *wlc, uint txstatus, void *dummy);static void wlc_11h_channel_switch(wlc_info_t *wlc, dot11_channel_switch_t *tag);static void wlc_11h_quiet(wlc_info_t *wlc, dot11_quiet_t *tag, struct dot11_bcn_prb *bcn);static void wlc_start_quiet0(wlc_info_t *wlc);static void wlc_start_quiet1(wlc_info_t *wlc);static void wlc_start_quiet2(wlc_info_t *wlc);static void wlc_start_quiet3(wlc_info_t *wlc);static void wlc_quiet_timer(void *arg);static void wlc_freqtrack(wlc_info_t *wlc);static void wlc_freqtrack_reset(wlc_info_t *wlc);static void wlc_freqtrack_verify(wlc_info_t *wlc);static void wlc_parse_11h(wlc_info_t *wlc, uint8 *params, int len, struct dot11_bcn_prb *bcn);static void *wlc_frame_get_ps_ctl(wlc_info_t *wlc, const struct ether_addr *bssid);static void wlc_wme_setup_resp(wlc_info_t *wlc, struct dot11_management_header *hdr, uint8 *body, int body_len);/* the unit for HW fifo size is 256byte(one block), total size is HW dependent * ucode has default fifo partition, sw can overwrite if necessary */static uint8 hwfifo_blk4[] = { 15, 15, 15, 15, 15, 2 /* 3584, 3584, 3584, 3584, 3584, 512 */};static uint8 hwfifo_blk5_8[] = { 9, 13, 10, 8, 13, 1 /* 2304, 3328, 2560, 2048, 3328, 256 */};static uint8 hwfifo_blk9_11[] = { 10, 14, 11, 9, 14, 2 /* 2560, 3584, 2816, 2304, 3584, 512 */};static void wlc_d11fifo_alloc(wlc_info_t *wlc);/* Some helper functions for wlc_phy.c */boolwlc_scaninprog(wlc_info_t *wlc) { return SCAN_IN_PROGRESS(wlc);}boolwlc_rminprog(wlc_info_t *wlc) { return FALSE;}boolwlc_ofdm_restrict(wlc_info_t *wlc) { return (wlc_check_locale_flags(wlc->band->bandtype, WLC_NO_OFDM));}intwlc_cur_bandtype(wlc_info_t *wlc) { return (wlc->band->bandtype);}void *wlc_cur_phy(wlc_info_t *wlc) { return ((void *)wlc->band->pi);}static INLINE uintwlc_frag(wlc_info_t *wlc, struct scb *scb, uint fifo, uint plen, uint *flen){ uint payload, thresh, nfrags; plen -= ETHER_HDR_LEN; ASSERT(fifo < NFIFO); thresh = wlc->fragthresh[fifo]; /* optimize for non-fragmented case */ if (plen < (thresh - (DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_FCS_LEN + ETHER_ADDR_LEN))) { *flen = plen; return (1); } /* account for 802.11 MAC header */ thresh -= DOT11_A3_HDR_LEN + DOT11_FCS_LEN; /* WME: account for QoS Control Field */ if (SCB_WME(scb)) thresh -= DOT11_QOS_LEN; /* * Spec says broadcast and multicast frames are not fragmented. * LLC/SNAP considered part of packet payload. * Fragment length must be even per 9.4 . */ if ((plen > thresh) && !SCB_ISMULTI(scb)) { *flen = payload = thresh & ~1; nfrags = (plen + payload - 1) / payload; } else { *flen = plen; nfrags = 1; } ASSERT(nfrags <= DOT11_MAXNUMFRAGS); return (nfrags);}voidwlc_clkctl_clk(wlc_info_t *wlc, uint mode){ /* wake the mac */ if (wlc->pub.up) { wlc->wakeforclkctl = TRUE; wlc_set_ps_ctrl(wlc); } /* set the clk mode and check if that mode forces the fast clk */ if ((wlc->forcefastclk = sb_clkctl_clk(wlc->pub.sbh, mode))) wlc_mhf(wlc, MHF_FORCEFASTCLK, MHF_FORCEFASTCLK, TRUE); else wlc_mhf(wlc, MHF_FORCEFASTCLK, 0, TRUE); /* ok to clear the wakeup now */ if (wlc->pub.up) { wlc->wakeforclkctl = FALSE; wlc_set_ps_ctrl(wlc); }}voidBCMINITFN(wlc_reset)(wlc_info_t *wlc){ int i; WL_TRACE(("wl%d: wlc_reset\n", wlc->pub.unit)); WLCNTINCR(wlc->pub._cnt.reset); /* slurp up hw mac counters before core reset */ if ((WLC_UPDATE_STATS(wlc)) && (sb_iscoreup(wlc->pub.sbh))) { wlc_statsupd(wlc); } /* clear any pending pkt callbacks */ bzero((char*)&wlc->pkt_callback, sizeof(wlc->pkt_callback)); WLCNTSET(wlc->pub._cnt.pkt_callback_reg_fail, 0); wlc->check_for_unaligned_tbtt = FALSE; /* reset the core */ if (!DEVICEREMOVED(wlc)) wlc_corereset(wlc); /* purge the pio queues or dma rings */ wlc_flushqueues(wlc); for (i = 0; i < NFIFO; i++) wlc->core->txpktpend[i] = 0; wlc->txretried = 0; wlc->core->tsf_timerlow = 0; /* reset our delta macstat counters */ bzero((char*)&wlc->core->macstat_delta, sizeof(macstat32_t));}voidBCMINITFN(wlc_init)(wlc_info_t *wlc){ d11regs_t *regs; uint32 macintmask; WL_TRACE(("wl%d: wlc_init\n", wlc->pub.unit)); regs = wlc->regs; /* disable interrupts */ macintmask = wl_intrsoff(wlc->wl); /* do one-time phy inits and calibration */ wlc_phy_cal_init(wlc->band->pi); /* core-specific initialization */ wlc_coreinit(wlc); /* band-specific inits */ wlc_bsinit(wlc); wlc->band->init = TRUE; /* Enable EDCF mode (while the MAC is suspended) */ if (D11REV_GE(wlc->pub.corerev, 4) && WME_ENAB(wlc)) { wlc_mhf(wlc, MHF_EDCF, MHF_EDCF, TRUE); OR_REG(&wlc->regs->ifs_ctl, IFS_USEEDCF); wlc_wme_setparams(wlc, FALSE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -