📄 wlc.c
字号:
/* use the override if it is set */ if (wlc->shortslot_override != WLC_SHORTSLOT_AUTO) shortslot = (wlc->shortslot_override == WLC_SHORTSLOT_ON); if (wlc->shortslot == shortslot) return; wlc->shortslot = shortslot; /* update the capability based on current shortslot mode */ wlc->pub.current_bss.capability &= ~DOT11_CAP_SHORTSLOT; if (wlc->shortslot) wlc->pub.current_bss.capability |= DOT11_CAP_SHORTSLOT; wlc_suspend_mac_and_wait(wlc); wlc_update_slot_timing(wlc, shortslot); wlc_enable_mac(wlc);}/* * Update the slot timing for standard 11b/g (20us slots) * or shortslot 11g (9us slots) * The PSM needs to be suspended for this call. */static voidwlc_update_slot_timing(wlc_info_t *wlc, bool shortslot){ d11regs_t *regs; regs = wlc->regs; if (shortslot) { /* 11g short slot: 11a timing */ W_REG(®s->ifs_slot, 0x0207); /* APHY_SLOT_TIME */ wlc_write_shm(wlc, M_DOT11_SLOT, APHY_SLOT_TIME); } else { /* 11g long slot: 11b timing */ W_REG(®s->ifs_slot, 0x0212); /* BPHY_SLOT_TIME */ wlc_write_shm(wlc, M_DOT11_SLOT, BPHY_SLOT_TIME); }}voidwlc_set_cwmin(wlc_info_t *wlc, uint16 newmin){ wlc->band->CWmin = newmin; W_REG(&wlc->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMIN); W_REG(&wlc->regs->objdata, newmin);}voidwlc_set_cwmax(wlc_info_t *wlc, uint16 newmax){ wlc->band->CWmax = newmax; W_REG(&wlc->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMAX); W_REG(&wlc->regs->objdata, newmax);}voidwlc_update_txpwr_shmem(wlc_pub_t *pub){ wlc_info_t *wlc = (wlc_info_t *)pub; uint8 r; bool war = FALSE; WL_TRACE(("wl%d: %s\n", pub->unit, __FUNCTION__)); if (wlc->core->clk) { if (wlc->pub.associated) r = wlc->pub.current_bss.rateset.rates[0]; else r = wlc->default_bss.rateset.rates[0]; if (ISGPHY(wlc->band->pi) && ((r != 0x82) && (r != 0x84) && (r != 0x8b) && (r != 0x96))) war = TRUE; wlc_phy_update_txpwr_shmem(wlc->band->pi, war); }}static voidwlc_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){ bool scan_in_progress; bool scan_timer_set; int i; ASSERT(ssid_len >= 0); ASSERT(ssid_len <= DOT11_MAX_SSID_LEN); ASSERT(bss_type == DOT11_BSSTYPE_INFRASTRUCTURE || bss_type == DOT11_BSSTYPE_INDEPENDENT || bss_type == DOT11_BSSTYPE_ANY); WL_INFORM(("wl%d: %s: for SSID \"%s\"\n", wlc->pub.unit, __FUNCTION__, (wlc_format_ssid(ssidbuf, ssid, ssid_len), ssidbuf))); scan_in_progress = SCAN_IN_PROGRESS(wlc); scan_timer_set = (scan_in_progress && 0 == (wlc->scan.state & (SCAN_STATE_WSUSPEND | SCAN_STATE_PSPEND))); /* clear or set optional params to default */ wlc->scan.state &= SCAN_STATE_SUPPRESS; /* keep persistent scan suppress flag */ wlc->scan.nprobes = wlc->scan.defaults.nprobes; if (wlc->pub.associated) { wlc->scan.active_time = wlc->scan.defaults.assoc_time; wlc->scan.home_time = wlc->scan.defaults.home_time; } else { wlc->scan.active_time = wlc->scan.defaults.unassoc_time; wlc->scan.home_time = 0; } wlc->scan.passive_time = wlc->scan.defaults.passive_time; if (wlc->scan.defaults.passive) wlc->scan.state |= SCAN_STATE_PASSIVE; wlc_scan_default_channels(wlc, wlc->scan.channel_list, &wlc->scan.channel_num); /* set required and optional params */ /* If IBSS Lock Out feature is turned on, set the scan type to BSS only */ wlc->scan.bss_type = (wlc->ibss_allowed == FALSE)?DOT11_BSSTYPE_INFRASTRUCTURE:bss_type; bcopy((char*)bssid, (char*)&wlc->scan.bssid, ETHER_ADDR_LEN); wlc->scan.ssid_len = ssid_len; bzero(wlc->scan.ssid, DOT11_MAX_SSID_LEN); if (ssid_len > 0) bcopy(ssid, wlc->scan.ssid, ssid_len); if (scan_type == DOT11_SCANTYPE_ACTIVE) { wlc->scan.state &= ~SCAN_STATE_PASSIVE; } else if (scan_type == DOT11_SCANTYPE_PASSIVE) { wlc->scan.state |= SCAN_STATE_PASSIVE; } /* passive scan always has nprobes to 1 */ if (wlc->scan.state & SCAN_STATE_PASSIVE) { wlc->scan.nprobes = 1; } if (active_time > 0) wlc->scan.active_time = (uint16)active_time; if (passive_time > 0) wlc->scan.passive_time = (uint16)passive_time; if (home_time >= 0 && wlc->pub.associated) wlc->scan.home_time = (uint16)home_time; if (nprobes > 0 && (wlc->scan.state & SCAN_STATE_PASSIVE) == 0) wlc->scan.nprobes = (uint8)nprobes; if (save_prb) wlc->scan.state |= SCAN_STATE_SAVE_PRB; wlc->scan.cb = fn; wlc->scan.cb_arg = arg; WL_INFORM(("wl%d: %s: wlc_scan params: nprobes %d dwell active/passive %dms/%dms home %dms" " flags %d\n", wlc->pub.unit, __FUNCTION__, wlc->scan.nprobes, wlc->scan.active_time, wlc->scan.passive_time, wlc->scan.home_time, wlc->scan.state)); /* channel list validation */ if (channel_num > MAXCHANNEL) { WL_ERROR(("wl%d: %s: wlc_scan bad param channel_num %d greater than max %d\n", wlc->pub.unit, __FUNCTION__, channel_num, MAXCHANNEL)); channel_num = 0; } if (channel_num > 0 && channel_list == NULL) { WL_ERROR(("wl%d: %s: wlc_scan bad param channel_list was NULL with channel_num =" " %d\n", wlc->pub.unit, __FUNCTION__, channel_num)); channel_num = 0; } for (i = 0; i < channel_num; i++) { if (!VALID_CHANNEL_DB(wlc, channel_list[i] & WL_CHANSPEC_CHAN_MASK)) { channel_num = 0; } } if (channel_num > 0) { for (i = 0; i < channel_num; i++) wlc->scan.channel_list[i] = channel_list[i] & WL_CHANSPEC_CHAN_MASK; wlc->scan.channel_num = channel_num; } if ((wlc->scan.state & SCAN_STATE_SUPPRESS) || (!wlc->scan.channel_num)) { WL_INFORM(("wl%d: %s: scan.state %d scan.channel_num %d\n", wlc->pub.unit, __FUNCTION__, wlc->scan.state, wlc->scan.channel_num)); if (scan_in_progress) wlc_scan_abort(wlc); /* no scan now, but free any earlier leftovers */ wlc_bss_list_free(wlc, &wlc->scan_results); if (fn) (fn)(arg); return; } if (scan_in_progress && wlc->assoc_state == AS_IDLE) wlc_mac_event(wlc, WLC_E_SCAN_COMPLETE, NULL, WLC_E_STATUS_ABORT, 0, 0, 0, 0); /* start the scan with the results cleared */ wlc->scan.away_count = 0; wlc->scan.away_limit = MAX(1, WLC_SCAN_AWAY_LIMIT / wlc->scan.active_time); wlc->scan.channel_idx = 0; wlc->scan.pass = WLC_SCAN_START; /* ...and free any leftover responses from before */ wlc_bss_list_free(wlc, &wlc->scan_results); /* keep core awake to receive solicited probe responses, SCAN_IN_PROGRESS is TRUE */ ASSERT(STAY_AWAKE(wlc)); wlc_set_ps_ctrl(wlc); if (wlc->pub.associated) { /* return to the current BSS channel if associated */ wlc->scan.channel_return = wlc->pub.current_bss.channel; } else if (!scan_in_progress) { /* not associated and no scan in progress, so just return to the current channel */ if (VALID_CHANNEL_DB(wlc, wlc->band->pi->radio_channel)) { wlc->scan.channel_return = (uint8)wlc->band->pi->radio_channel; } else { wlc->scan.channel_return = wlc_next_channel(wlc, (uint8)wlc->band->pi->radio_channel, CHAN_TYPE_ANY, 1); } } /* else, we are interrupting a scan, but not associated, so use the original return channel */ if (!scan_timer_set) { /* call wlc_scantimer to get the scan state machine going */ /* DUALBAND - Don't call wlc_scantimer() directly from DPC... */ wl_add_timer(wlc->wl, wlc->scan.timer, 0, 0); } /* if a scan is in progress, allow the next callback to restart the scan state machine */}static voidwlc_scan_abort(wlc_info_t *wlc){ if (!SCAN_IN_PROGRESS(wlc)) return; /* abort the current scan, and return to home channel */ WL_INFORM(("wl%d: %s: aborting scan in progress\n", wlc->pub.unit, __FUNCTION__)); if (wlc->assoc_state == AS_IDLE) wlc_mac_event(wlc, WLC_E_SCAN_COMPLETE, NULL, WLC_E_STATUS_ABORT, 0, 0, 0, 0); wlc_bss_list_free(wlc, &wlc->scan_results); /* Move to abort state for wlc_scantimer to clean up */ wlc->scan.pass = WLC_SCAN_ABORT; /* Change the radio channel to the return channel */ if (wlc->band->pi->radio_channel != wlc->scan.channel_return) { wlc_suspend_mac_and_wait(wlc); wlc_set_channel(wlc, wlc->scan.channel_return); wlc_enable_mac(wlc); } /* un-block PSPoll operations and restore PS state */ if (wlc->PMblocked) { wlc->PMblocked = FALSE; /* come out of PS mode if appropriate */ if (wlc->PM != PM_MAX || wlc->WME_PM_blocked) wlc_set_pmstate(wlc, FALSE); } /* Clear the tssi values since we may have collected * info from other channels during the scan */ wlc_clear_tssi(wlc->band->pi); /* un-suspend the data fifos now that we are back on the home channel */ wlc_tx_resume(wlc); wlc->block_datafifo &= ~DATA_BLOCK_SCAN; /* enable CFP update */ wlc_mhf(wlc, MHF_SKIP_CFP_UPDATE, 0, TRUE); /* check for states that indicate the scan timer is not scheduled */ if (wlc->scan.state & (SCAN_STATE_WSUSPEND | SCAN_STATE_PSPEND)) { /* wlc_scantimer would have been scheduled by either a tx fifo * suspend or PS indication, both of which we are canceling. * Call wlc_scantimer directly to abort. */ wlc->scan.state &= ~(SCAN_STATE_WSUSPEND | SCAN_STATE_PSPEND); wlc_scantimer(wlc); }}static voidwlc_scantimer(void *arg){ wlc_info_t *wlc = (wlc_info_t*)arg; uint channel; int next_channel; int8 passes; if (!wlc->pub.up) return; if (DEVICEREMOVED(wlc)) { WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub.unit, __FUNCTION__)); wl_down(wlc->wl); return; } if (wlc->scan.pass == WLC_SCAN_ABORT) { WL_ASSOC(("SCAN: wlc_scantimer: aborted scan for SSID \"%s\"\n", ssidbuf)); wlc->scan.channel_idx = -1; wlc_set_ps_ctrl(wlc); return; } /* check if we are still waiting on an event to continue */ if (wlc->scan.state & SCAN_STATE_SUSPEND_REQ) { wlc->scan.state &= ~SCAN_STATE_SUSPEND_REQ; if (!wlc_tx_suspended(wlc)) { wlc_tx_suspend(wlc); wlc->scan.state |= SCAN_STATE_WSUSPEND; return; } } /* still waiting for tx data fifo suspended indication */ if (wlc->scan.state & SCAN_STATE_WSUSPEND) return; wlc->scan.pass++; channel = wlc->scan.channel_list[wlc->scan.channel_idx]; passes = QUIET_CHANNEL(wlc, channel) ? 1 : wlc->scan.nprobes; if (wlc->scan.pass > passes) { if (wlc->scan.pass == passes + 1) { /* scan passes complete for the current channel */ WL_INFORM(("wl%d: %s: %sscanned channel %d, %d total responses for SSID" " \"%s\"\n", wlc->pub.unit, __FUNCTION__, ((QUIET_CHANNEL(wlc, channel) && !(wlc->scan.state & SCAN_STATE_RADAR_CLEAR)) ? "passively ":""), channel, wlc->scan_results.count, ssidbuf)); /* reset the radar clear flag since we will be leaving the channel */ wlc->scan.state &= ~SCAN_STATE_RADAR_CLEAR; } if (wlc->scan.channel_idx < wlc->scan.channel_num - 1) next_channel = wlc->scan.channel_list[wlc->scan.channel_idx + 1]; else next_channel = -1; /* keep track of the number of channels scanned since the last * time we returned to the home channel */ if (wlc->band->pi->radio_channel != wlc->scan.channel_return) wlc->scan.away_count++; else wlc->scan.away_count = 0; /* If the home_time is non-zero, * and there are more channels to scan, * and we reached the away channel limit or the channel * we just scanned or are about to scan is a passive scan channel, * return to the home channel before scanning the next channel */ if (wlc->scan.pass == (passes + 1) && wlc->scan.home_time > 0 && next_channel != -1 && (wlc->scan.away_count >= wlc->scan.away_limit || QUIET_CHANNEL(wlc, channel) || QUIET_CHANNEL(wlc, next_channel))) { /* Change the radio channel to associated BSS */ wlc_suspend_mac_and_wait(wlc); wlc_set_channel(wlc, wlc->scan.channel_return); if (!wlc->pub.BSS) wlc_ibss_resume(wlc); /* Restore promisc behavior for beacons and probes */ wlc->bcnmisc_scan = FALSE; wlc_mac_bcn_promisc(wlc); wlc_enable_mac(wlc); /* Clear the tssi values */ wlc_clear_tssi(wlc->band->pi); /* un-block PSPoll operations and restore PS state */ if (wlc->PMblocked) { wlc->PMblocked = FALSE; /* come out of PS mode if appropriate */ if (wlc->PM != PM_MAX || wlc->WME_PM_blocked) wlc_set_pmstate(wlc, FALSE); } /* un-suspend the DATA fifo now that we are back on the home channel */ wlc_tx_resume(wlc); /* re-enable txq processing now that we are back on the home channel */ wlc->block_datafifo &= ~DATA_BLOCK_SCAN; /* enable CFP update */ wlc_mhf(wlc, MHF_SKIP_CFP_UPDATE, 0, TRUE); /* Allow normal traffic before next channel scan */ wl_add_timer(wlc->wl, wlc->scan.timer, wlc->scan.home_time, 0); /* wlc_scantimer called back when wlc->scan.timer fires */ return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -