/* get channel list via currently setting in wifi driver */ int get_channel_list_via_driver(int unit, char *buffer, int len) { struct ieee80211req_chaninfo chans; struct iwreq wrq; char tmp[128], prefix[] = "wlXXXXXXXXXX_", *ifname; int i; char *p; if (buffer == NULL || len <= 0) return -1; memset(buffer, 0, len); snprintf(prefix, sizeof(prefix), "wl%d_", unit); ifname = nvram_safe_get(strcat_r(prefix, "ifname", tmp)); memset(&wrq, 0, sizeof(wrq)); wrq.u.data.pointer = (void *)&chans; wrq.u.data.length = sizeof(chans); if (wl_ioctl(ifname, IEEE80211_IOCTL_GETCHANINFO, &wrq) < 0) return -1; for (i = 0, p=buffer; i < chans.ic_nchans ; i++) { if (i == 0) p += sprintf(p, "%u", ieee80211_mhz2ieee(chans.ic_chans[i].ic_freq)); else p += sprintf(p, ",%u", ieee80211_mhz2ieee(chans.ic_chans[i].ic_freq)); } return (p - buffer); }
static int iwm_mvm_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_cmd *cmd, int flags, int n_ssids, int basic_ssid) { struct ieee80211com *ic = sc->sc_ic; uint16_t passive_dwell = iwm_mvm_get_passive_dwell(sc, flags); uint16_t active_dwell = iwm_mvm_get_active_dwell(sc, flags, n_ssids); struct iwm_scan_channel *chan = (struct iwm_scan_channel *) (cmd->data + le16toh(cmd->tx_cmd.len)); int type = (1 << n_ssids) - 1; struct ieee80211_channel *c; int nchan, j; if (!basic_ssid) type |= (1 << n_ssids); for (nchan = j = 0; j < ic->ic_nchans; j++) { c = &ic->ic_channels[j]; /* For 2GHz, only populate 11b channels */ /* For 5GHz, only populate 11a channels */ /* * Catch other channels, in case we have 900MHz channels or * something in the chanlist. */ if ((flags & IEEE80211_CHAN_2GHZ) && (! IEEE80211_IS_CHAN_B(c))) { continue; } else if ((flags & IEEE80211_CHAN_5GHZ) && (! IEEE80211_IS_CHAN_A(c))) { continue; } else { IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM, "%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n", __func__, c->ic_freq, c->ic_ieee, c->ic_flags); } IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM, "Adding channel %d (%d Mhz) to the list\n", nchan, c->ic_freq); chan->channel = htole16(ieee80211_mhz2ieee(c->ic_freq, flags)); chan->type = htole32(type); if (c->ic_flags & IEEE80211_CHAN_PASSIVE) chan->type &= htole32(~IWM_SCAN_CHANNEL_TYPE_ACTIVE); chan->active_dwell = htole16(active_dwell); chan->passive_dwell = htole16(passive_dwell); chan->iteration_count = htole16(1); chan++; nchan++; } if (nchan == 0) device_printf(sc->sc_dev, "%s: NO CHANNEL!\n", __func__); return nchan; }
static void list_scan(prop_dictionary_t env) { u_int8_t buf[64*1024 - 1]; struct ieee80211req ireq; char ssid[IEEE80211_NWID_LEN+1]; const u_int8_t *cp; int len, ssidmax; const struct ieee80211req_scan_result *sr; memset(&ireq, 0, sizeof(ireq)); ireq.i_type = IEEE80211_IOC_SCAN_RESULTS; ireq.i_data = buf; ireq.i_len = sizeof(buf); if (direct_ioctl(env, SIOCG80211, &ireq) < 0) errx(EXIT_FAILURE, "unable to get scan results"); len = ireq.i_len; if (len < (int)sizeof(*sr)) return; ssidmax = calc_len(buf, len); printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n" , ssidmax, ssidmax, "SSID" , "BSSID" , "CHAN" , "RATE" , "S:N" , "INT" , "CAPS" ); cp = buf; while (len >= (int)sizeof(*sr)) { const uint8_t *vp; sr = (const struct ieee80211req_scan_result *) cp; vp = (const u_int8_t *)(sr+1); (void)copy_essid(ssid, sizeof(ssid), vp, sr->isr_ssid_len); printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s" , ssidmax, ssidmax, ssid , ether_ntoa((const struct ether_addr *) sr->isr_bssid) , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags) , getmaxrate(sr->isr_rates, sr->isr_nrates) , sr->isr_rssi, sr->isr_noise , sr->isr_intval , getcaps(sr->isr_capinfo) ); printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24); printf("\n"); cp += sr->isr_len, len -= sr->isr_len; } }
static void list_scan(const char *ifname) { uint8_t buf[24 * 1024]; char ssid[14]; uint8_t *cp; int len; len = get80211priv(ifname, IEEE80211_IOCTL_SCAN_RESULTS, buf, sizeof(buf)); if (len == -1) errx(1, "unable to get scan results"); if (len < sizeof(struct ieee80211req_scan_result)) return; printf("%-14.14s %-17.17s %4s %4s %-5s %3s %4s\n", "SSID", "BSSID", "CHAN", "RATE", "S:N", "INT", "CAPS"); cp = buf; do { struct ieee80211req_scan_result *sr; uint8_t *vp; sr = (struct ieee80211req_scan_result *) cp; vp = (u_int8_t *)(sr+1); printf("%-14.*s %s %3d %3dM %2d:%-2d %3d %-4.4s", copy_essid(ssid, sizeof(ssid), vp, sr->isr_ssid_len), ssid, ieee80211_ntoa(sr->isr_bssid), ieee80211_mhz2ieee(sr->isr_freq), getmaxrate(sr->isr_rates, sr->isr_nrates), (int8_t) sr->isr_rssi, sr->isr_noise, sr->isr_intval, getcaps(sr->isr_capinfo)); printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24); printf("\n"); cp += sr->isr_len, len -= sr->isr_len; } while (len >= sizeof(struct ieee80211req_scan_result)); }
static uint8_t iwm_mvm_lmac_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_channel_cfg_lmac *chan, int n_ssids) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_scan_state *ss = ic->ic_scan; struct ieee80211_channel *c; uint8_t nchan; int j; for (nchan = j = 0; j < ss->ss_last && nchan < sc->ucode_capa.n_scan_channels; j++) { c = ss->ss_chans[j]; /* * Catch other channels, in case we have 900MHz channels or * something in the chanlist. */ if (!IEEE80211_IS_CHAN_2GHZ(c) && !IEEE80211_IS_CHAN_5GHZ(c)) { IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM, "%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n", __func__, c->ic_freq, c->ic_ieee, c->ic_flags); continue; } IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM, "Adding channel %d (%d Mhz) to the list\n", nchan, c->ic_freq); chan->channel_num = htole16(ieee80211_mhz2ieee(c->ic_freq, 0)); chan->iter_count = htole16(1); chan->iter_interval = htole32(0); chan->flags = htole32(IWM_UNIFIED_SCAN_CHANNEL_PARTIAL); chan->flags |= htole32(IWM_SCAN_CHANNEL_NSSIDS(n_ssids)); /* XXX IEEE80211_SCAN_NOBCAST flag is never set. */ if (!IEEE80211_IS_CHAN_PASSIVE(c) && (!(ss->ss_flags & IEEE80211_SCAN_NOBCAST) || n_ssids != 0)) chan->flags |= htole32(IWM_SCAN_CHANNEL_TYPE_ACTIVE); chan++; nchan++; } return nchan; }
static void list_channels(const char *ifname, int allchans) { struct ieee80211req_chaninfo chans; struct ieee80211req_chaninfo achans; const struct ieee80211_channel *c; int i, half; if (get80211priv(ifname, IEEE80211_IOCTL_GETCHANINFO, &chans, sizeof(chans)) < 0) errx(1, "unable to get channel information"); if (!allchans) { uint8_t active[32]; if (get80211priv(ifname, IEEE80211_IOCTL_GETCHANLIST, &active, sizeof(active)) < 0) errx(1, "unable to get active channel list"); memset(&achans, 0, sizeof(achans)); for (i = 0; i < chans.ic_nchans; i++) { c = &chans.ic_chans[i]; if (isset(active, ieee80211_mhz2ieee(c->ic_freq)) || allchans) achans.ic_chans[achans.ic_nchans++] = *c; } } else achans = chans; half = achans.ic_nchans / 2; if (achans.ic_nchans % 2) half++; for (i = 0; i < achans.ic_nchans / 2; i++) { print_chaninfo(&achans.ic_chans[i]); print_chaninfo(&achans.ic_chans[half + i]); printf("\n"); } if (achans.ic_nchans % 2) { print_chaninfo(&achans.ic_chans[i]); printf("\n"); } }
/* * Fill in 802.11 available channel set, mark * all available channels as active, and pick * a default channel if not already specified. */ static void ieee80211_chan_init(struct ieee80211com *ic) { #define DEFAULTRATES(m, def) do { \ if (ic->ic_sup_rates[m].rs_nrates == 0) \ ic->ic_sup_rates[m] = def; \ } while (0) struct ieee80211_channel *c; int i; KASSERT(0 < ic->ic_nchans && ic->ic_nchans <= IEEE80211_CHAN_MAX, ("invalid number of channels specified: %u", ic->ic_nchans)); memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); memset(ic->ic_modecaps, 0, sizeof(ic->ic_modecaps)); setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO); for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; KASSERT(c->ic_flags != 0, ("channel with no flags")); /* * Help drivers that work only with frequencies by filling * in IEEE channel #'s if not already calculated. Note this * mimics similar work done in ieee80211_setregdomain when * changing regulatory state. */ if (c->ic_ieee == 0) c->ic_ieee = ieee80211_mhz2ieee(c->ic_freq,c->ic_flags); if (IEEE80211_IS_CHAN_HT40(c) && c->ic_extieee == 0) c->ic_extieee = ieee80211_mhz2ieee(c->ic_freq + (IEEE80211_IS_CHAN_HT40U(c) ? 20 : -20), c->ic_flags); /* default max tx power to max regulatory */ if (c->ic_maxpower == 0) c->ic_maxpower = 2*c->ic_maxregpower; setbit(ic->ic_chan_avail, c->ic_ieee); /* * Identify mode capabilities. */ if (IEEE80211_IS_CHAN_A(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11A); if (IEEE80211_IS_CHAN_B(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11B); if (IEEE80211_IS_CHAN_ANYG(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11G); if (IEEE80211_IS_CHAN_FHSS(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_FH); if (IEEE80211_IS_CHAN_108A(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_A); if (IEEE80211_IS_CHAN_108G(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_G); if (IEEE80211_IS_CHAN_ST(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_STURBO_A); if (IEEE80211_IS_CHAN_HALF(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_HALF); if (IEEE80211_IS_CHAN_QUARTER(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_QUARTER); if (IEEE80211_IS_CHAN_HTA(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11NA); if (IEEE80211_IS_CHAN_HTG(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11NG); } /* initialize candidate channels to all available */ memcpy(ic->ic_chan_active, ic->ic_chan_avail, sizeof(ic->ic_chan_avail)); /* sort channel table to allow lookup optimizations */ ieee80211_sort_channels(ic->ic_channels, ic->ic_nchans); /* invalidate any previous state */ ic->ic_bsschan = IEEE80211_CHAN_ANYC; ic->ic_prevchan = NULL; ic->ic_csa_newchan = NULL; /* arbitrarily pick the first channel */ ic->ic_curchan = &ic->ic_channels[0]; ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); /* fillin well-known rate sets if driver has not specified */ DEFAULTRATES(IEEE80211_MODE_11B, ieee80211_rateset_11b); DEFAULTRATES(IEEE80211_MODE_11G, ieee80211_rateset_11g); DEFAULTRATES(IEEE80211_MODE_11A, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_TURBO_A, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_TURBO_G, ieee80211_rateset_11g); DEFAULTRATES(IEEE80211_MODE_STURBO_A, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_HALF, ieee80211_rateset_half); DEFAULTRATES(IEEE80211_MODE_QUARTER, ieee80211_rateset_quarter); DEFAULTRATES(IEEE80211_MODE_11NA, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_11NG, ieee80211_rateset_11g); /* * Set auto mode to reset active channel state and any desired channel. */ (void) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); #undef DEFAULTRATES }
int site_survey_main(int argc, char *argv[]) { char *name = nvram_safe_get("wl0_ifname"); unsigned char mac[20]; int i = 0; char *dev = name; unlink(SITE_SURVEY_DB); int ap = 0, oldap = 0; unsigned char buf[24 * 1024]; char ssid[31]; unsigned char *cp; int len; system2("airoscan-ng wifi0"); len = do80211priv("ath0", IEEE80211_IOCTL_SCAN_RESULTS, buf, sizeof(buf)); if (len == -1) fprintf(stderr, "unable to get scan results"); if (len < sizeof(struct ieee80211req_scan_result)) return; cp = buf; do { struct ieee80211req_scan_result *sr; unsigned char *vp; char ssid[14]; sr = (struct ieee80211req_scan_result *)cp; vp = (u_int8_t *)(sr + 1); memset(ssid, 0, sizeof(ssid)); strncpy(site_survey_lists[i].SSID, vp, sr->isr_ssid_len); strcpy(site_survey_lists[i].BSSID, ieee80211_ntoa(sr->isr_bssid)); site_survey_lists[i].channel = ieee80211_mhz2ieee(sr->isr_freq); site_survey_lists[i].frequency = sr->isr_freq; int noise = 256; noise -= (int)sr->isr_noise; site_survey_lists[i].phy_noise = -noise; site_survey_lists[i].RSSI = (int)site_survey_lists[i].phy_noise + (int)sr->isr_rssi; site_survey_lists[i].capability = sr->isr_capinfo; site_survey_lists[i].rate_count = sr->isr_nrates; cp += sr->isr_len, len -= sr->isr_len; i++; } while (len >= sizeof(struct ieee80211req_scan_result)); write_site_survey(); open_site_survey(); for (i = 0; i < SITE_SURVEY_NUM && site_survey_lists[i].BSSID[0] && site_survey_lists[i].channel != 0; i++) { fprintf(stderr, "[%2d] SSID[%20s] BSSID[%s] channel[%2d] frequency[%4d] rssi[%d] noise[%d] beacon[%d] cap[%x] dtim[%d] rate[%d]\n", i, site_survey_lists[i].SSID, site_survey_lists[i].BSSID, site_survey_lists[i].channel, site_survey_lists[i].frequency, site_survey_lists[i].RSSI, site_survey_lists[i].phy_noise, site_survey_lists[i].beacon_period, site_survey_lists[i].capability, site_survey_lists[i].dtim_period, site_survey_lists[i].rate_count); } return 0; }
static void get_radiotap_info(struct priv_fbsd *pf, struct ieee80211_radiotap_header *rth, int *plen, struct rx_info *ri) { uint32_t present; uint8_t rflags = 0; int i; unsigned char *body = (unsigned char*) (rth+1); int dbm_power = 0, db_power = 0; /* reset control info */ if (ri) memset(ri, 0, sizeof(*ri)); /* get info */ present = le32toh(rth->it_present); for (i = IEEE80211_RADIOTAP_TSFT; i <= IEEE80211_RADIOTAP_EXT; i++) { if (!(present & (1 << i))) continue; switch (i) { case IEEE80211_RADIOTAP_TSFT: body += sizeof(uint64_t); break; case IEEE80211_RADIOTAP_FLAGS: rflags = *((uint8_t*)body); /* fall through */ case IEEE80211_RADIOTAP_RATE: body += sizeof(uint8_t); break; case IEEE80211_RADIOTAP_CHANNEL: if (ri) { uint16_t *p = (uint16_t*) body; int c = ieee80211_mhz2ieee(*p, *(p+1)); ri->ri_channel = c; } body += sizeof(uint16_t)*2; break; case IEEE80211_RADIOTAP_FHSS: body += sizeof(uint16_t); break; case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: dbm_power = *body++; break; case IEEE80211_RADIOTAP_DBM_ANTNOISE: dbm_power -= *body++; break; case IEEE80211_RADIOTAP_DB_ANTSIGNAL: db_power = *body++; break; case IEEE80211_RADIOTAP_DB_ANTNOISE: db_power -= *body++; break; default: i = IEEE80211_RADIOTAP_EXT+1; break; } } /* set power */ if (ri) { if (dbm_power) ri->ri_power = dbm_power; else ri->ri_power = db_power; } /* XXX cache; drivers won't change this per-packet */ /* check if FCS/CRC is included in packet */ if (pf->pf_nocrc || (rflags & IEEE80211_RADIOTAP_F_FCS)) { *plen -= IEEE80211_CRC_LEN; pf->pf_nocrc = 1; } }
/* * Context: softIRQ (tasklet) */ void ieee80211_input_monitor(struct ieee80211com *ic, struct sk_buff *skb, const struct ath_buf *bf, int tx, u_int64_t mactime, struct ath_softc *sc) { struct ieee80211vap *vap, *next; struct ath_desc *ds = bf->bf_desc; int noise = 0, antenna = 0, ieeerate = 0; u_int32_t rssi = 0; u_int8_t pkttype = 0; unsigned int mon_hdrspace = A_MAX(sizeof(struct ath_tx_radiotap_header), (A_MAX(sizeof(struct wlan_ng_prism2_header), ATHDESC_HEADER_SIZE))); if ((skb_headroom(skb) < mon_hdrspace) && pskb_expand_head(skb, mon_hdrspace, 0, GFP_ATOMIC)) { printk("No headroom for monitor header - %s:%d %s\n", __FILE__, __LINE__, __func__); return; } if (tx) { rssi = bf->bf_dsstatus.ds_txstat.ts_rssi; antenna = bf->bf_dsstatus.ds_txstat.ts_antenna; ieeerate = sc->sc_hwmap[bf->bf_dsstatus.ds_txstat.ts_rate].ieeerate; } else { rssi = bf->bf_dsstatus.ds_rxstat.rs_rssi; antenna = bf->bf_dsstatus.ds_rxstat.rs_antenna; ieeerate = sc->sc_hwmap[bf->bf_dsstatus.ds_rxstat.rs_rate].ieeerate; } noise = bf->bf_channoise; /* XXX locking */ for (vap = TAILQ_FIRST(&ic->ic_vaps); vap != NULL; vap = next) { struct sk_buff *skb1; struct net_device *dev = vap->iv_dev; struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data; u_int8_t dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; next = TAILQ_NEXT(vap, iv_next); /* If we have rx'd an error frame... */ if (!tx && bf->bf_dsstatus.ds_rxstat.rs_status != 0) { /* Discard PHY errors if necessary */ if (bf->bf_dsstatus.ds_rxstat.rs_status & HAL_RXERR_PHY) { if (vap->iv_monitor_phy_errors == 0) continue; } /* Discard CRC errors if necessary */ if (bf->bf_dsstatus.ds_rxstat.rs_status & HAL_RXERR_CRC) { if (vap->iv_monitor_crc_errors == 0) continue; } /* Accept PHY, CRC and decrypt errors. Discard the rest. */ if (bf->bf_dsstatus.ds_rxstat.rs_status &~ (HAL_RXERR_DECRYPT | HAL_RXERR_MIC | HAL_RXERR_PHY | HAL_RXERR_CRC)) continue; /* We can't use addr1 to determine direction at this point */ pkttype = PACKET_HOST; } else { /* * The frame passed its CRC, so we can rely * on the contents of the frame to set pkttype. */ if (tx) pkttype = PACKET_OUTGOING; else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { if (IEEE80211_ADDR_EQ(wh->i_addr1, dev->broadcast)) pkttype = PACKET_BROADCAST; else pkttype = PACKET_MULTICAST; } else pkttype = PACKET_HOST; } if (vap->iv_opmode != IEEE80211_M_MONITOR || vap->iv_state != IEEE80211_S_RUN) continue; if (vap->iv_monitor_nods_only && dir != IEEE80211_FC1_DIR_NODS) { /* don't rx fromds, tods, or dstods packets */ continue; } skb1 = skb_copy(skb, GFP_ATOMIC); if (skb1 == NULL) { /* XXX stat+msg */ continue; } ieee80211_skb_copy_noderef(skb, skb1); if (vap->iv_monitor_txf_len && tx) { /* truncate transmit feedback packets */ skb_trim(skb1, vap->iv_monitor_txf_len); skb_reset_network_header(skb1); } switch (vap->iv_dev->type) { case ARPHRD_IEEE80211: break; case ARPHRD_IEEE80211_PRISM: { struct wlan_ng_prism2_header *ph; if (skb_headroom(skb1) < sizeof(struct wlan_ng_prism2_header)) { ieee80211_dev_kfree_skb(&skb1); break; } ph = (struct wlan_ng_prism2_header *) skb_push(skb1, sizeof(struct wlan_ng_prism2_header)); memset(ph, 0, sizeof(struct wlan_ng_prism2_header)); ph->msgcode = DIDmsg_lnxind_wlansniffrm; ph->msglen = sizeof(struct wlan_ng_prism2_header); strncpy(ph->devname, dev->name, sizeof(ph->devname)); ph->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime; ph->hosttime.status = 0; ph->hosttime.len = 4; ph->hosttime.data = jiffies; /* Pass up tsf clock in mactime */ /* NB: the prism mactime field is 32bit, so we lose TSF precision here */ ph->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime; ph->mactime.status = 0; ph->mactime.len = 4; ph->mactime.data = mactime; ph->istx.did = DIDmsg_lnxind_wlansniffrm_istx; ph->istx.status = 0; ph->istx.len = 4; ph->istx.data = tx ? P80211ENUM_truth_true : P80211ENUM_truth_false; ph->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen; ph->frmlen.status = 0; ph->frmlen.len = 4; ph->frmlen.data = skb->len; ph->channel.did = DIDmsg_lnxind_wlansniffrm_channel; ph->channel.status = 0; ph->channel.len = 4; ph->channel.data = ieee80211_mhz2ieee(ic->ic_curchan->ic_freq, ic->ic_curchan->ic_flags); ph->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi; ph->rssi.status = 0; ph->rssi.len = 4; ph->rssi.data = rssi; ph->noise.did = DIDmsg_lnxind_wlansniffrm_noise; ph->noise.status = 0; ph->noise.len = 4; ph->noise.data = noise; ph->signal.did = DIDmsg_lnxind_wlansniffrm_signal; ph->signal.status = 0; ph->signal.len = 4; ph->signal.data = rssi + noise; ph->rate.did = DIDmsg_lnxind_wlansniffrm_rate; ph->rate.status = 0; ph->rate.len = 4; ph->rate.data = ieeerate; break; } case ARPHRD_IEEE80211_RADIOTAP: { if (tx) { struct ath_tx_radiotap_header *th; if (skb_headroom(skb1) < sizeof(struct ath_tx_radiotap_header)) { printk("%s:%d %s\n", __FILE__, __LINE__, __func__); ieee80211_dev_kfree_skb(&skb1); break; } th = (struct ath_tx_radiotap_header *) skb_push(skb1, sizeof(struct ath_tx_radiotap_header)); memset(th, 0, sizeof(struct ath_tx_radiotap_header)); th->wt_ihdr.it_version = 0; th->wt_ihdr.it_len = cpu_to_le16(sizeof(struct ath_tx_radiotap_header)); th->wt_ihdr.it_present = cpu_to_le32(ATH_TX_RADIOTAP_PRESENT); /* radiotap's TSF field is the full 64 bits, so we don't lose * any TSF precision when using radiotap */ th->wt_tsft = cpu_to_le64(mactime); th->wt_flags = 0; th->wt_rate = ieeerate; th->wt_antenna = antenna; th->wt_pad = 0; if (bf->bf_dsstatus.ds_txstat.ts_status & HAL_TXERR_XRETRY) th->wt_txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); th->wt_dataretries = bf->bf_dsstatus.ds_txstat.ts_shortretry + bf->bf_dsstatus.ds_txstat.ts_longretry; } else { struct ath_rx_radiotap_header *th; if (skb_headroom(skb1) < sizeof(struct ath_rx_radiotap_header)) { printk("%s:%d %s\n", __FILE__, __LINE__, __func__); ieee80211_dev_kfree_skb(&skb1); break; } th = (struct ath_rx_radiotap_header *) skb_push(skb1, sizeof(struct ath_rx_radiotap_header)); memset(th, 0, sizeof(struct ath_rx_radiotap_header)); th->wr_ihdr.it_version = 0; th->wr_ihdr.it_len = cpu_to_le16(sizeof(struct ath_rx_radiotap_header)); th->wr_ihdr.it_present = cpu_to_le32(ATH_RX_RADIOTAP_PRESENT); if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) th->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; if (bf->bf_dsstatus.ds_rxstat.rs_status & HAL_RXERR_CRC) th->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; if (skb->len >= IEEE80211_CRC_LEN) th->wr_flags |= IEEE80211_RADIOTAP_F_FCS; th->wr_rate = ieeerate; th->wr_chan_freq = cpu_to_le16(ic->ic_curchan->ic_freq); /* Define the channel flags for radiotap */ switch (sc->sc_curmode) { case IEEE80211_MODE_11A: th->wr_chan_flags = cpu_to_le16(IEEE80211_CHAN_A); break; case IEEE80211_MODE_TURBO_A: th->wr_chan_flags = cpu_to_le16(IEEE80211_CHAN_TA); break; case IEEE80211_MODE_11B: th->wr_chan_flags = cpu_to_le16(IEEE80211_CHAN_B); break; case IEEE80211_MODE_11G: th->wr_chan_flags = cpu_to_le16(IEEE80211_CHAN_G); break; case IEEE80211_MODE_TURBO_G: th->wr_chan_flags = cpu_to_le16(IEEE80211_CHAN_TG); break; default: th->wr_chan_flags = 0; /* unknown */ break; } th->wr_dbm_antnoise = (int8_t) noise; th->wr_dbm_antsignal = th->wr_dbm_antnoise + rssi; th->wr_antenna = antenna; th->wr_antsignal = rssi; th->wr_tsft = cpu_to_le64(mactime); } break; } case ARPHRD_IEEE80211_ATHDESC: { if (skb_headroom(skb1) < ATHDESC_HEADER_SIZE) { printk("%s:%d %s\n", __FILE__, __LINE__, __func__); ieee80211_dev_kfree_skb(&skb1); break; } memcpy(skb_push(skb1, ATHDESC_HEADER_SIZE), ds, ATHDESC_HEADER_SIZE); break; } default: break; } if (skb1 != NULL) { if (!tx && (skb1->len >= IEEE80211_CRC_LEN) && (vap->iv_dev->type != ARPHRD_IEEE80211_RADIOTAP)) { /* Remove FCS from end of RX frames when * delivering to non-Radiotap VAPs. */ skb_trim(skb1, skb1->len - IEEE80211_CRC_LEN); } skb1->dev = dev; /* NB: deliver to wlanX */ skb_reset_mac_header(skb1); skb1->ip_summed = CHECKSUM_NONE; skb1->pkt_type = pkttype; skb1->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */ if (netif_rx(skb1) == NET_RX_DROP) { /* If netif_rx dropped the packet because * device was too busy, reclaim the ref. in * the skb. */ if (SKB_CB(skb1)->ni != NULL) ieee80211_unref_node(&SKB_CB(skb1)->ni); vap->iv_devstats.rx_dropped++; } vap->iv_devstats.rx_packets++; vap->iv_devstats.rx_bytes += skb1->len; } } }
int iwm_mvm_config_umac_scan(struct iwm_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct iwm_scan_config *scan_config; int ret, j, nchan; size_t cmd_size; struct ieee80211_channel *c; struct iwm_host_cmd hcmd = { .id = iwm_cmd_id(IWM_SCAN_CFG_CMD, IWM_ALWAYS_LONG_GROUP, 0), .flags = IWM_CMD_SYNC, }; static const uint32_t rates = (IWM_SCAN_CONFIG_RATE_1M | IWM_SCAN_CONFIG_RATE_2M | IWM_SCAN_CONFIG_RATE_5M | IWM_SCAN_CONFIG_RATE_11M | IWM_SCAN_CONFIG_RATE_6M | IWM_SCAN_CONFIG_RATE_9M | IWM_SCAN_CONFIG_RATE_12M | IWM_SCAN_CONFIG_RATE_18M | IWM_SCAN_CONFIG_RATE_24M | IWM_SCAN_CONFIG_RATE_36M | IWM_SCAN_CONFIG_RATE_48M | IWM_SCAN_CONFIG_RATE_54M); cmd_size = sizeof(*scan_config) + sc->ucode_capa.n_scan_channels; scan_config = malloc(cmd_size, M_DEVBUF, M_NOWAIT | M_ZERO); if (scan_config == NULL) return ENOMEM; scan_config->tx_chains = htole32(iwm_mvm_get_valid_tx_ant(sc)); scan_config->rx_chains = htole32(iwm_mvm_get_valid_rx_ant(sc)); scan_config->legacy_rates = htole32(rates | IWM_SCAN_CONFIG_SUPPORTED_RATE(rates)); /* These timings correspond to iwlwifi's UNASSOC scan. */ scan_config->dwell_active = 10; scan_config->dwell_passive = 110; scan_config->dwell_fragmented = 44; scan_config->dwell_extended = 90; scan_config->out_of_channel_time = htole32(0); scan_config->suspend_time = htole32(0); IEEE80211_ADDR_COPY(scan_config->mac_addr, vap ? vap->iv_myaddr : ic->ic_macaddr); scan_config->bcast_sta_id = sc->sc_aux_sta.sta_id; scan_config->channel_flags = IWM_CHANNEL_FLAG_EBS | IWM_CHANNEL_FLAG_ACCURATE_EBS | IWM_CHANNEL_FLAG_EBS_ADD | IWM_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE; for (nchan = j = 0; j < ic->ic_nchans && nchan < sc->ucode_capa.n_scan_channels; j++) { c = &ic->ic_channels[j]; /* For 2GHz, only populate 11b channels */ /* For 5GHz, only populate 11a channels */ /* * Catch other channels, in case we have 900MHz channels or * something in the chanlist. */ if (iwm_mvm_scan_skip_channel(c)) continue; scan_config->channel_array[nchan++] = ieee80211_mhz2ieee(c->ic_freq, 0); } scan_config->flags = htole32(IWM_SCAN_CONFIG_FLAG_ACTIVATE | IWM_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS | IWM_SCAN_CONFIG_FLAG_SET_TX_CHAINS | IWM_SCAN_CONFIG_FLAG_SET_RX_CHAINS | IWM_SCAN_CONFIG_FLAG_SET_AUX_STA_ID | IWM_SCAN_CONFIG_FLAG_SET_ALL_TIMES | IWM_SCAN_CONFIG_FLAG_SET_LEGACY_RATES | IWM_SCAN_CONFIG_FLAG_SET_MAC_ADDR | IWM_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS| IWM_SCAN_CONFIG_N_CHANNELS(nchan) | IWM_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED); hcmd.data[0] = scan_config; hcmd.len[0] = cmd_size; IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Sending UMAC scan config\n"); ret = iwm_send_cmd(sc, &hcmd); if (!ret) IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "UMAC scan config was sent successfully\n"); free(scan_config, M_DEVBUF); return ret; } static boolean_t iwm_mvm_scan_use_ebs(struct iwm_softc *sc) { const struct iwm_ucode_capabilities *capa = &sc->ucode_capa; /* We can only use EBS if: * 1. the feature is supported; * 2. the last EBS was successful; * 3. if only single scan, the single scan EBS API is supported; * 4. it's not a p2p find operation. */ return ((capa->flags & IWM_UCODE_TLV_FLAGS_EBS_SUPPORT) && sc->last_ebs_successful); } int iwm_mvm_umac_scan(struct iwm_softc *sc) { struct iwm_host_cmd hcmd = { .id = iwm_cmd_id(IWM_SCAN_REQ_UMAC, IWM_ALWAYS_LONG_GROUP, 0), .len = { 0, }, .data = { NULL, }, .flags = IWM_CMD_SYNC, }; struct ieee80211_scan_state *ss = sc->sc_ic.ic_scan; struct iwm_scan_req_umac *req; struct iwm_scan_req_umac_tail *tail; size_t req_len; uint8_t i, nssid; int ret; req_len = sizeof(struct iwm_scan_req_umac) + (sizeof(struct iwm_scan_channel_cfg_umac) * sc->ucode_capa.n_scan_channels) + sizeof(struct iwm_scan_req_umac_tail); if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE) return ENOMEM; req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO); if (req == NULL) return ENOMEM; hcmd.len[0] = (uint16_t)req_len; hcmd.data[0] = (void *)req; IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Handling ieee80211 scan request\n"); /* These timings correspond to iwlwifi's UNASSOC scan. */ req->active_dwell = 10; req->passive_dwell = 110; req->fragmented_dwell = 44; req->extended_dwell = 90; req->max_out_time = 0; req->suspend_time = 0; req->scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH); req->ooc_priority = htole32(IWM_SCAN_PRIORITY_HIGH); nssid = MIN(ss->ss_nssid, IWM_PROBE_OPTION_MAX); req->n_channels = iwm_mvm_umac_scan_fill_channels(sc, (struct iwm_scan_channel_cfg_umac *)req->data, nssid); req->general_flags = htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL | IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE | IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL); tail = (void *)((char *)&req->data + sizeof(struct iwm_scan_channel_cfg_umac) * sc->ucode_capa.n_scan_channels); /* Check if we're doing an active directed scan. */ for (i = 0; i < nssid; i++) { tail->direct_scan[i].id = IEEE80211_ELEMID_SSID; tail->direct_scan[i].len = MIN(ss->ss_ssid[i].len, IEEE80211_NWID_LEN); memcpy(tail->direct_scan[i].ssid, ss->ss_ssid[i].ssid, tail->direct_scan[i].len); /* XXX debug */ } if (nssid != 0) { req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT); } else req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE); if (iwm_mvm_scan_use_ebs(sc)) req->channel_flags = IWM_SCAN_CHANNEL_FLAG_EBS | IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE | IWM_SCAN_CHANNEL_FLAG_CACHE_ADD; if (iwm_mvm_rrm_scan_needed(sc)) req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED); ret = iwm_mvm_fill_probe_req(sc, &tail->preq); if (ret) { free(req, M_DEVBUF); return ret; } /* Specify the scan plan: We'll do one iteration. */ tail->schedule[0].interval = 0; tail->schedule[0].iter_count = 1; ret = iwm_send_cmd(sc, &hcmd); if (!ret) IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Scan request was sent successfully\n"); free(req, M_DEVBUF); return ret; } int iwm_mvm_lmac_scan(struct iwm_softc *sc) { struct iwm_host_cmd hcmd = { .id = IWM_SCAN_OFFLOAD_REQUEST_CMD, .len = { 0, }, .data = { NULL, }, .flags = IWM_CMD_SYNC, }; struct ieee80211_scan_state *ss = sc->sc_ic.ic_scan; struct iwm_scan_req_lmac *req; size_t req_len; uint8_t i, nssid; int ret; IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Handling ieee80211 scan request\n"); req_len = sizeof(struct iwm_scan_req_lmac) + (sizeof(struct iwm_scan_channel_cfg_lmac) * sc->ucode_capa.n_scan_channels) + sizeof(struct iwm_scan_probe_req); if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE) return ENOMEM; req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO); if (req == NULL) return ENOMEM; hcmd.len[0] = (uint16_t)req_len; hcmd.data[0] = (void *)req; /* These timings correspond to iwlwifi's UNASSOC scan. */ req->active_dwell = 10; req->passive_dwell = 110; req->fragmented_dwell = 44; req->extended_dwell = 90; req->max_out_time = 0; req->suspend_time = 0; req->scan_prio = htole32(IWM_SCAN_PRIORITY_HIGH); req->rx_chain_select = iwm_mvm_scan_rx_chain(sc); req->iter_num = htole32(1); req->delay = 0; req->scan_flags = htole32(IWM_MVM_LMAC_SCAN_FLAG_PASS_ALL | IWM_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE | IWM_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL); if (iwm_mvm_rrm_scan_needed(sc)) req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED); req->flags = iwm_mvm_scan_rxon_flags(sc->sc_ic.ic_scan->ss_chans[0]); req->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP | IWM_MAC_FILTER_IN_BEACON); /* Tx flags 2 GHz. */ req->tx_cmd[0].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL | IWM_TX_CMD_FLG_BT_DIS); req->tx_cmd[0].rate_n_flags = iwm_mvm_scan_rate_n_flags(sc, IEEE80211_CHAN_2GHZ, 1/*XXX*/); req->tx_cmd[0].sta_id = sc->sc_aux_sta.sta_id; /* Tx flags 5 GHz. */ req->tx_cmd[1].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL | IWM_TX_CMD_FLG_BT_DIS); req->tx_cmd[1].rate_n_flags = iwm_mvm_scan_rate_n_flags(sc, IEEE80211_CHAN_5GHZ, 1/*XXX*/); req->tx_cmd[1].sta_id = sc->sc_aux_sta.sta_id; /* Check if we're doing an active directed scan. */ nssid = MIN(ss->ss_nssid, IWM_PROBE_OPTION_MAX); for (i = 0; i < nssid; i++) { req->direct_scan[i].id = IEEE80211_ELEMID_SSID; req->direct_scan[i].len = MIN(ss->ss_ssid[i].len, IEEE80211_NWID_LEN); memcpy(req->direct_scan[i].ssid, ss->ss_ssid[i].ssid, req->direct_scan[i].len); /* XXX debug */ } if (nssid != 0) { req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION); } else req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAG_PASSIVE); req->n_channels = iwm_mvm_lmac_scan_fill_channels(sc, (struct iwm_scan_channel_cfg_lmac *)req->data, nssid); ret = iwm_mvm_fill_probe_req(sc, (struct iwm_scan_probe_req *)(req->data + (sizeof(struct iwm_scan_channel_cfg_lmac) * sc->ucode_capa.n_scan_channels))); if (ret) { free(req, M_DEVBUF); return ret; } /* Specify the scan plan: We'll do one iteration. */ req->schedule[0].iterations = 1; req->schedule[0].full_scan_mul = 1; if (iwm_mvm_scan_use_ebs(sc)) { req->channel_opt[0].flags = htole16(IWM_SCAN_CHANNEL_FLAG_EBS | IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE | IWM_SCAN_CHANNEL_FLAG_CACHE_ADD); req->channel_opt[0].non_ebs_ratio = htole16(IWM_DENSE_EBS_SCAN_RATIO); req->channel_opt[1].flags = htole16(IWM_SCAN_CHANNEL_FLAG_EBS | IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE | IWM_SCAN_CHANNEL_FLAG_CACHE_ADD); req->channel_opt[1].non_ebs_ratio = htole16(IWM_SPARSE_EBS_SCAN_RATIO); } ret = iwm_send_cmd(sc, &hcmd); if (!ret) { IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Scan request was sent successfully\n"); } free(req, M_DEVBUF); return ret; }
static void list_stations(const char *ifname) { uint8_t buf[24*1024]; struct iwreq iwr; uint8_t *cp; int s, len; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) err(1, "socket(SOCK_DGRAM)"); (void) memset(&iwr, 0, sizeof(iwr)); (void) strncpy(iwr.ifr_name, ifname, sizeof(iwr.ifr_name)); iwr.u.data.pointer = (void *) buf; iwr.u.data.length = sizeof(buf); if (ioctl(s, IEEE80211_IOCTL_STA_INFO, &iwr) < 0) errx(1, "unable to get station information"); len = iwr.u.data.length; if (len < sizeof(struct ieee80211req_sta_info)) return; close(s); printf("%-17.17s %4s %4s %4s %4s %4s %4s %6s %6s %4s %5s %3s %8s %8s\n", "ADDR", "AID", "CHAN", "RATE", "RSSI", "DBM", "IDLE", "TXSEQ", "RXSEQ", "CAPS", "ACAPS", "ERP", "STATE", "MODE"); cp = buf; do { struct ieee80211req_sta_info *si; uint8_t *vp; si = (struct ieee80211req_sta_info *) cp; vp = (u_int8_t *)(si+1); printf("%s %4u %4d %3dM %4d %4d %4d %6d %6d %-4.4s %-5.5s %3x %8x %8s", ieee80211_ntoa(si->isi_macaddr), IEEE80211_AID(si->isi_associd), ieee80211_mhz2ieee(si->isi_freq), (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL) / 2, si->isi_rssi, rssi2dbm(si->isi_rssi), si->isi_inact, si->isi_txseqs[0], si->isi_rxseqs[0], getcaps(si->isi_capinfo), getathcaps(si->isi_athflags), si->isi_erp, si->isi_state, getstamode(si->isi_opmode)); printies(vp, si->isi_ie_len, 24); printf("\n"); if (si->isi_uapsd) { printf(" UAPSD QoSInfo: 0x%02x, ", si->isi_uapsd); printf("(VO,VI,BE,BK) = (%d,%d,%d,%d), MaxSpLimit = %s\n", WME_UAPSD_AC_ENABLED(WME_AC_VO, si->isi_uapsd) ? 1 : 0, WME_UAPSD_AC_ENABLED(WME_AC_VI, si->isi_uapsd) ? 1 : 0, WME_UAPSD_AC_ENABLED(WME_AC_BE, si->isi_uapsd) ? 1 : 0, WME_UAPSD_AC_ENABLED(WME_AC_BK, si->isi_uapsd) ? 1 : 0, WME_UAPSD_MAXSP(si->isi_uapsd) == 1 ? "2" : WME_UAPSD_MAXSP(si->isi_uapsd) == 2 ? "4" : WME_UAPSD_MAXSP(si->isi_uapsd) == 3 ? "6" : "NoLimit"); } cp += si->isi_len; len -= si->isi_len; } while (len >= sizeof(struct ieee80211req_sta_info)); }
/* * Take the MHz channel value and set the Channel value * * ASSUMES: Writes enabled to analog bus * * Actual Expression, * * For 2GHz channel, * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17) * (freq_ref = 40MHz) * * For 5GHz channel, * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10) * (freq_ref = 40MHz/(24>>amode_ref_sel)) * * For 5GHz channels which are 5MHz spaced, * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17) * (freq_ref = 40MHz) */ static HAL_BOOL ar9300_set_channel(struct ath_hal *ah, struct ieee80211_channel *chan) { u_int16_t b_mode, frac_mode = 0, a_mode_ref_sel = 0; u_int32_t freq, channel_sel, reg32; u_int8_t clk_25mhz = AH9300(ah)->clk_25mhz; CHAN_CENTERS centers; int load_synth_channel; #ifdef AH_DEBUG_ALQ HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); #endif /* * Put this behind AH_DEBUG_ALQ for now until the Hornet * channel_sel code below is made to work. */ #ifdef AH_DEBUG_ALQ OS_MARK(ah, AH_MARK_SETCHANNEL, ichan->channel); #endif ar9300_get_channel_centers(ah, chan, ¢ers); freq = centers.synth_center; if (freq < 4800) { /* 2 GHz, fractional mode */ b_mode = 1; /* 2 GHz */ if (AR_SREV_HORNET(ah)) { #if 0 u_int32_t ichan = ieee80211_mhz2ieee(ah, chan->ic_freq, chan->ic_flags); HALASSERT(ichan > 0 && ichan <= 14); if (clk_25mhz) { channel_sel = ar9300_chansel_xtal_25M[ichan - 1]; } else { channel_sel = ar9300_chansel_xtal_40M[ichan - 1]; } #endif uint32_t i; /* * Pay close attention to this bit! * * We need to map the actual desired synth frequency to * one of the channel select array entries. * * For HT20, it'll align with the channel we select. * * For HT40 though it won't - the centre frequency * will not be the frequency of chan->ic_freq or ichan->freq; * it needs to be whatever frequency maps to 'freq'. */ i = ath_hal_mhz2ieee_2ghz(ah, freq); HALASSERT(i > 0 && i <= 14); if (clk_25mhz) { channel_sel = ar9300_chansel_xtal_25M[i - 1]; } else { channel_sel = ar9300_chansel_xtal_40M[i - 1]; } } else if (AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { u_int32_t channel_frac; /* * freq_ref = (40 / (refdiva >> a_mode_ref_sel)); * (where refdiva = 1 and amoderefsel = 0) * ndiv = ((chan_mhz * 4) / 3) / freq_ref; * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 */ channel_sel = (freq * 4) / 120; channel_frac = (((freq * 4) % 120) * 0x20000) / 120; channel_sel = (channel_sel << 17) | (channel_frac); } else if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) { u_int32_t channel_frac; if (clk_25mhz) { /* * freq_ref = (50 / (refdiva >> a_mode_ref_sel)); * (where refdiva = 1 and amoderefsel = 0) * ndiv = ((chan_mhz * 4) / 3) / freq_ref; * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 */ if (AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) { /* Doubler is off for Scorpion */ channel_sel = (freq * 4) / 75; channel_frac = (((freq * 4) % 75) * 0x20000) / 75; } else { channel_sel = (freq * 2) / 75; channel_frac = (((freq * 2) % 75) * 0x20000) / 75; } } else { /* * freq_ref = (50 / (refdiva >> a_mode_ref_sel)); * (where refdiva = 1 and amoderefsel = 0) * ndiv = ((chan_mhz * 4) / 3) / freq_ref; * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 */ if (AR_SREV_SCORPION(ah)) { /* Doubler is off for Scorpion */ channel_sel = (freq * 4) / 120; channel_frac = (((freq * 4) % 120) * 0x20000) / 120; } else { channel_sel = (freq * 2) / 120; channel_frac = (((freq * 2) % 120) * 0x20000) / 120; } } channel_sel = (channel_sel << 17) | (channel_frac); } else { channel_sel = CHANSEL_2G(freq); } } else { b_mode = 0; /* 5 GHz */ if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && clk_25mhz){ u_int32_t channel_frac; /* * freq_ref = (50 / (refdiva >> amoderefsel)); * (refdiva = 1, amoderefsel = 0) * ndiv = ((chan_mhz * 2) / 3) / freq_ref; * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 */ channel_sel = freq / 75 ; channel_frac = ((freq % 75) * 0x20000) / 75; channel_sel = (channel_sel << 17) | (channel_frac); } else { channel_sel = CHANSEL_5G(freq); /* Doubler is ON, so, divide channel_sel by 2. */ channel_sel >>= 1; } } /* Enable fractional mode for all channels */ frac_mode = 1; a_mode_ref_sel = 0; load_synth_channel = 0; reg32 = (b_mode << 29); OS_REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32); /* Enable Long shift Select for Synthesizer */ OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_SYNTH4, AR_PHY_SYNTH4_LONG_SHIFT_SELECT, 1); /* program synth. setting */ reg32 = (channel_sel << 2) | (a_mode_ref_sel << 28) | (frac_mode << 30) | (load_synth_channel << 31); if (IEEE80211_IS_CHAN_QUARTER(chan)) { reg32 += CHANSEL_5G_DOT5MHZ; } OS_REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32); /* Toggle Load Synth channel bit */ load_synth_channel = 1; reg32 |= load_synth_channel << 31; OS_REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32); AH_PRIVATE(ah)->ah_curchan = chan; return AH_TRUE; }