Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/wpi/if_wpi.c
Show First 20 Lines • Show All 1,896 Lines • ▼ Show 20 Lines | plcp2rate(const uint8_t plcp) | ||||
case 10: return 2; | case 10: return 2; | ||||
case 20: return 4; | case 20: return 4; | ||||
case 55: return 11; | case 55: return 11; | ||||
case 110: return 22; | case 110: return 22; | ||||
default: return 0; | default: return 0; | ||||
} | } | ||||
} | } | ||||
/* Quickly determine if a given rate is CCK or OFDM. */ | |||||
#define WPI_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) | |||||
static void | static void | ||||
wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, | wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, | ||||
struct wpi_rx_data *data) | struct wpi_rx_data *data) | ||||
{ | { | ||||
struct ieee80211com *ic = &sc->sc_ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct wpi_rx_ring *ring = &sc->rxq; | struct wpi_rx_ring *ring = &sc->rxq; | ||||
struct wpi_rx_stat *stat; | struct wpi_rx_stat *stat; | ||||
struct wpi_rx_head *head; | struct wpi_rx_head *head; | ||||
▲ Show 20 Lines • Show All 863 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Construct the data packet for a transmit buffer. | * Construct the data packet for a transmit buffer. | ||||
*/ | */ | ||||
static int | static int | ||||
wpi_tx_data(struct wpi_softc *sc, struct mbuf *m, struct ieee80211_node *ni) | wpi_tx_data(struct wpi_softc *sc, struct mbuf *m, struct ieee80211_node *ni) | ||||
{ | { | ||||
const struct ieee80211_txparam *tp = ni->ni_txparms; | const struct ieee80211_rate_t *rate; | ||||
const struct ieee80211_txparam_vht *tp = ni->ni_txparms; | |||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct ieee80211com *ic = ni->ni_ic; | struct ieee80211com *ic = ni->ni_ic; | ||||
struct wpi_node *wn = WPI_NODE(ni); | struct wpi_node *wn = WPI_NODE(ni); | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_key *k = NULL; | struct ieee80211_key *k = NULL; | ||||
struct wpi_buf tx_data; | struct wpi_buf tx_data; | ||||
struct wpi_cmd_data *tx = (struct wpi_cmd_data *)&tx_data.data; | struct wpi_cmd_data *tx = (struct wpi_cmd_data *)&tx_data.data; | ||||
uint32_t flags; | uint32_t flags; | ||||
uint16_t ac, qos; | uint16_t ac, qos, rate_idx; | ||||
uint8_t tid, type, rate; | uint8_t tid, type; | ||||
int swcrypt, ismcast, totlen; | int swcrypt, ismcast, totlen; | ||||
wh = mtod(m, struct ieee80211_frame *); | wh = mtod(m, struct ieee80211_frame *); | ||||
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; | type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; | ||||
ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); | ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); | ||||
swcrypt = 1; | swcrypt = 1; | ||||
/* Select EDCA Access Category and TX ring for this frame. */ | /* Select EDCA Access Category and TX ring for this frame. */ | ||||
if (IEEE80211_QOS_HAS_SEQ(wh)) { | if (IEEE80211_QOS_HAS_SEQ(wh)) { | ||||
qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; | qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; | ||||
tid = qos & IEEE80211_QOS_TID; | tid = qos & IEEE80211_QOS_TID; | ||||
} else { | } else { | ||||
qos = 0; | qos = 0; | ||||
tid = 0; | tid = 0; | ||||
} | } | ||||
ac = M_WME_GETAC(m); | ac = M_WME_GETAC(m); | ||||
/* Choose a TX rate index. */ | /* Choose a TX rate index. */ | ||||
if (type == IEEE80211_FC0_TYPE_MGT || | if (type == IEEE80211_FC0_TYPE_MGT || | ||||
type == IEEE80211_FC0_TYPE_CTL || | type == IEEE80211_FC0_TYPE_CTL || | ||||
(m->m_flags & M_EAPOL) != 0) | (m->m_flags & M_EAPOL) != 0) | ||||
rate = tp->mgmtrate; | rate_idx = tp->mgmtrate; | ||||
else if (ismcast) | else if (ismcast) | ||||
rate = tp->mcastrate; | rate_idx = tp->mcastrate; | ||||
else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) | else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) | ||||
rate = tp->ucastrate; | rate_idx = tp->ucastrate; | ||||
else { | else { | ||||
/* XXX pass pktlen */ | /* XXX pass pktlen */ | ||||
(void) ieee80211_ratectl_rate(ni, NULL, 0); | (void) ieee80211_ratectl_rate(ni, NULL, 0); | ||||
rate = ni->ni_txrate; | rate_idx = ni->ni_txrate; | ||||
} | } | ||||
rate = ieee80211_get_rate(rate_idx); | |||||
KASSERT(rate->type == IEEE80211_T_CCK || | |||||
rate->type == IEEE80211_T_OFDM, ("unsupported rate type %u\n", | |||||
rate->type)); | |||||
/* Encrypt the frame if need be. */ | /* Encrypt the frame if need be. */ | ||||
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { | if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { | ||||
/* Retrieve key for TX. */ | /* Retrieve key for TX. */ | ||||
k = ieee80211_crypto_encap(ni, m); | k = ieee80211_crypto_encap(ni, m); | ||||
if (k == NULL) | if (k == NULL) | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
swcrypt = k->wk_flags & IEEE80211_KEY_SWCRYPT; | swcrypt = k->wk_flags & IEEE80211_KEY_SWCRYPT; | ||||
/* 802.11 header may have moved. */ | /* 802.11 header may have moved. */ | ||||
wh = mtod(m, struct ieee80211_frame *); | wh = mtod(m, struct ieee80211_frame *); | ||||
} | } | ||||
totlen = m->m_pkthdr.len; | totlen = m->m_pkthdr.len; | ||||
if (ieee80211_radiotap_active_vap(vap)) { | if (ieee80211_radiotap_active_vap(vap)) { | ||||
struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; | struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; | ||||
tap->wt_flags = 0; | tap->wt_flags = 0; | ||||
tap->wt_rate = rate; | tap->wt_rate = rate->value; | ||||
if (k != NULL) | if (k != NULL) | ||||
tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; | tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; | ||||
if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) | if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) | ||||
tap->wt_flags |= IEEE80211_RADIOTAP_F_FRAG; | tap->wt_flags |= IEEE80211_RADIOTAP_F_FRAG; | ||||
ieee80211_radiotap_tx(vap, m); | ieee80211_radiotap_tx(vap, m); | ||||
} | } | ||||
Show All 11 Lines | if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) | ||||
flags |= WPI_TX_MORE_FRAG; | flags |= WPI_TX_MORE_FRAG; | ||||
/* Check if frame must be protected using RTS/CTS or CTS-to-self. */ | /* Check if frame must be protected using RTS/CTS or CTS-to-self. */ | ||||
if (!ismcast) { | if (!ismcast) { | ||||
/* NB: Group frames are sent using CCK in 802.11b/g. */ | /* NB: Group frames are sent using CCK in 802.11b/g. */ | ||||
if (totlen + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) { | if (totlen + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) { | ||||
flags |= WPI_TX_NEED_RTS; | flags |= WPI_TX_NEED_RTS; | ||||
} else if ((ic->ic_flags & IEEE80211_F_USEPROT) && | } else if ((ic->ic_flags & IEEE80211_F_USEPROT) && | ||||
WPI_RATE_IS_OFDM(rate)) { | rate->type == IEEE80211_T_OFDM) { | ||||
if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) | if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) | ||||
flags |= WPI_TX_NEED_CTS; | flags |= WPI_TX_NEED_CTS; | ||||
else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) | else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) | ||||
flags |= WPI_TX_NEED_RTS; | flags |= WPI_TX_NEED_RTS; | ||||
} | } | ||||
if (flags & (WPI_TX_NEED_RTS | WPI_TX_NEED_CTS)) | if (flags & (WPI_TX_NEED_RTS | WPI_TX_NEED_CTS)) | ||||
flags |= WPI_TX_FULL_TXOP; | flags |= WPI_TX_FULL_TXOP; | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) { | ||||
tx->lnext = htole16(next->m_pkthdr.len); | tx->lnext = htole16(next->m_pkthdr.len); | ||||
tx->fnext = htole32(tx->security | | tx->fnext = htole32(tx->security | | ||||
(flags & WPI_TX_NEED_ACK) | | (flags & WPI_TX_NEED_ACK) | | ||||
WPI_NEXT_STA_ID(tx->id)); | WPI_NEXT_STA_ID(tx->id)); | ||||
} | } | ||||
tx->len = htole16(totlen); | tx->len = htole16(totlen); | ||||
tx->flags = htole32(flags); | tx->flags = htole32(flags); | ||||
tx->plcp = rate2plcp(rate); | tx->plcp = rate2plcp(rate->value); | ||||
tx->tid = tid; | tx->tid = tid; | ||||
tx->lifetime = htole32(WPI_LIFETIME_INFINITE); | tx->lifetime = htole32(WPI_LIFETIME_INFINITE); | ||||
tx->ofdm_mask = 0xff; | tx->ofdm_mask = 0xff; | ||||
tx->cck_mask = 0x0f; | tx->cck_mask = 0x0f; | ||||
tx->rts_ntries = 7; | tx->rts_ntries = 7; | ||||
tx->data_ntries = tp->maxretry; | tx->data_ntries = tp->maxretry; | ||||
tx_data.ni = ni; | tx_data.ni = ni; | ||||
tx_data.m = m; | tx_data.m = m; | ||||
tx_data.size = sizeof(struct wpi_cmd_data); | tx_data.size = sizeof(struct wpi_cmd_data); | ||||
tx_data.code = WPI_CMD_TX_DATA; | tx_data.code = WPI_CMD_TX_DATA; | ||||
tx_data.ac = ac; | tx_data.ac = ac; | ||||
return wpi_cmd2(sc, &tx_data); | return wpi_cmd2(sc, &tx_data); | ||||
} | } | ||||
static int | static int | ||||
wpi_tx_data_raw(struct wpi_softc *sc, struct mbuf *m, | wpi_tx_data_raw(struct wpi_softc *sc, struct mbuf *m, | ||||
struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) | struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) | ||||
{ | { | ||||
const struct ieee80211_rate_t *rate; | |||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct ieee80211_key *k = NULL; | struct ieee80211_key *k = NULL; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct wpi_buf tx_data; | struct wpi_buf tx_data; | ||||
struct wpi_cmd_data *tx = (struct wpi_cmd_data *)&tx_data.data; | struct wpi_cmd_data *tx = (struct wpi_cmd_data *)&tx_data.data; | ||||
uint32_t flags; | uint32_t flags; | ||||
uint8_t ac, type, rate; | uint8_t ac, type; | ||||
int swcrypt, totlen; | int swcrypt, totlen; | ||||
wh = mtod(m, struct ieee80211_frame *); | wh = mtod(m, struct ieee80211_frame *); | ||||
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; | type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; | ||||
swcrypt = 1; | swcrypt = 1; | ||||
ac = params->ibp_pri & 3; | ac = params->ibp_pri & 3; | ||||
/* Choose a TX rate index. */ | /* Choose a TX rate. */ | ||||
rate = params->ibp_rate0; | rate = ieee80211_get_rate(params->ibp_rate0); | ||||
flags = 0; | flags = 0; | ||||
if (!IEEE80211_QOS_HAS_SEQ(wh)) | if (!IEEE80211_QOS_HAS_SEQ(wh)) | ||||
flags |= WPI_TX_AUTO_SEQ; | flags |= WPI_TX_AUTO_SEQ; | ||||
if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) | if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) | ||||
flags |= WPI_TX_NEED_ACK; | flags |= WPI_TX_NEED_ACK; | ||||
if (params->ibp_flags & IEEE80211_BPF_RTS) | if (params->ibp_flags & IEEE80211_BPF_RTS) | ||||
flags |= WPI_TX_NEED_RTS; | flags |= WPI_TX_NEED_RTS; | ||||
Show All 15 Lines | if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { | ||||
wh = mtod(m, struct ieee80211_frame *); | wh = mtod(m, struct ieee80211_frame *); | ||||
} | } | ||||
totlen = m->m_pkthdr.len; | totlen = m->m_pkthdr.len; | ||||
if (ieee80211_radiotap_active_vap(vap)) { | if (ieee80211_radiotap_active_vap(vap)) { | ||||
struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; | struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; | ||||
tap->wt_flags = 0; | tap->wt_flags = 0; | ||||
tap->wt_rate = rate; | tap->wt_rate = rate->value; | ||||
if (params->ibp_flags & IEEE80211_BPF_CRYPTO) | if (params->ibp_flags & IEEE80211_BPF_CRYPTO) | ||||
tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; | tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; | ||||
ieee80211_radiotap_tx(vap, m); | ieee80211_radiotap_tx(vap, m); | ||||
} | } | ||||
memset(tx, 0, sizeof (struct wpi_cmd_data)); | memset(tx, 0, sizeof (struct wpi_cmd_data)); | ||||
if (type == IEEE80211_FC0_TYPE_MGT) { | if (type == IEEE80211_FC0_TYPE_MGT) { | ||||
Show All 19 Lines | default: | ||||
break; | break; | ||||
} | } | ||||
memcpy(tx->key, k->wk_key, k->wk_keylen); | memcpy(tx->key, k->wk_key, k->wk_keylen); | ||||
} | } | ||||
tx->len = htole16(totlen); | tx->len = htole16(totlen); | ||||
tx->flags = htole32(flags); | tx->flags = htole32(flags); | ||||
tx->plcp = rate2plcp(rate); | tx->plcp = rate2plcp(rate->value); | ||||
tx->id = WPI_ID_BROADCAST; | tx->id = WPI_ID_BROADCAST; | ||||
tx->lifetime = htole32(WPI_LIFETIME_INFINITE); | tx->lifetime = htole32(WPI_LIFETIME_INFINITE); | ||||
tx->rts_ntries = params->ibp_try1; | tx->rts_ntries = params->ibp_try1; | ||||
tx->data_ntries = params->ibp_try0; | tx->data_ntries = params->ibp_try0; | ||||
tx_data.ni = ni; | tx_data.ni = ni; | ||||
tx_data.m = m; | tx_data.m = m; | ||||
tx_data.size = sizeof(struct wpi_cmd_data); | tx_data.size = sizeof(struct wpi_cmd_data); | ||||
▲ Show 20 Lines • Show All 1,034 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Send a scan request to the firmware. | * Send a scan request to the firmware. | ||||
*/ | */ | ||||
static int | static int | ||||
wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) | wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) | ||||
{ | { | ||||
const struct ieee80211_rateset *rs; | |||||
struct ieee80211com *ic = &sc->sc_ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211_scan_state *ss = ic->ic_scan; | struct ieee80211_scan_state *ss = ic->ic_scan; | ||||
struct ieee80211vap *vap = ss->ss_vap; | struct ieee80211vap *vap = ss->ss_vap; | ||||
struct wpi_scan_hdr *hdr; | struct wpi_scan_hdr *hdr; | ||||
struct wpi_cmd_data *tx; | struct wpi_cmd_data *tx; | ||||
struct wpi_scan_essid *essids; | struct wpi_scan_essid *essids; | ||||
struct wpi_scan_chan *chan; | struct wpi_scan_chan *chan; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_rateset *rs; | |||||
uint16_t bintval, buflen, dwell_active, dwell_passive; | uint16_t bintval, buflen, dwell_active, dwell_passive; | ||||
uint8_t *buf, *frm, i, nssid; | uint8_t *buf, *frm, i, nssid; | ||||
int bgscan, error; | int bgscan, error; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
/* | /* | ||||
* We are absolutely not allowed to send a scan command when another | * We are absolutely not allowed to send a scan command when another | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) | ||||
tx = (struct wpi_cmd_data *)(hdr + 1); | tx = (struct wpi_cmd_data *)(hdr + 1); | ||||
tx->flags = htole32(WPI_TX_AUTO_SEQ); | tx->flags = htole32(WPI_TX_AUTO_SEQ); | ||||
tx->id = WPI_ID_BROADCAST; | tx->id = WPI_ID_BROADCAST; | ||||
tx->lifetime = htole32(WPI_LIFETIME_INFINITE); | tx->lifetime = htole32(WPI_LIFETIME_INFINITE); | ||||
if (IEEE80211_IS_CHAN_5GHZ(c)) { | if (IEEE80211_IS_CHAN_5GHZ(c)) { | ||||
/* Send probe requests at 6Mbps. */ | /* Send probe requests at 6Mbps. */ | ||||
tx->plcp = wpi_ridx_to_plcp[WPI_RIDX_OFDM6]; | tx->plcp = wpi_ridx_to_plcp[WPI_RIDX_OFDM6]; | ||||
rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; | rs = ic->ic_sup_rates[IEEE80211_MODE_11A]; | ||||
} else { | } else { | ||||
hdr->flags = htole32(WPI_RXON_24GHZ | WPI_RXON_AUTO); | hdr->flags = htole32(WPI_RXON_24GHZ | WPI_RXON_AUTO); | ||||
/* Send probe requests at 1Mbps. */ | /* Send probe requests at 1Mbps. */ | ||||
tx->plcp = wpi_ridx_to_plcp[WPI_RIDX_CCK1]; | tx->plcp = wpi_ridx_to_plcp[WPI_RIDX_CCK1]; | ||||
rs = &ic->ic_sup_rates[IEEE80211_MODE_11G]; | rs = ic->ic_sup_rates[IEEE80211_MODE_11G]; | ||||
} | } | ||||
essids = (struct wpi_scan_essid *)(tx + 1); | essids = (struct wpi_scan_essid *)(tx + 1); | ||||
nssid = MIN(ss->ss_nssid, WPI_SCAN_MAX_ESSIDS); | nssid = MIN(ss->ss_nssid, WPI_SCAN_MAX_ESSIDS); | ||||
for (i = 0; i < nssid; i++) { | for (i = 0; i < nssid; i++) { | ||||
essids[i].id = IEEE80211_ELEMID_SSID; | essids[i].id = IEEE80211_ELEMID_SSID; | ||||
essids[i].len = MIN(ss->ss_ssid[i].len, IEEE80211_NWID_LEN); | essids[i].len = MIN(ss->ss_ssid[i].len, IEEE80211_NWID_LEN); | ||||
memcpy(essids[i].data, ss->ss_ssid[i].ssid, essids[i].len); | memcpy(essids[i].data, ss->ss_ssid[i].ssid, essids[i].len); | ||||
▲ Show 20 Lines • Show All 1,473 Lines • Show Last 20 Lines |