Changeset View
Changeset View
Standalone View
Standalone View
sys/net80211/ieee80211_output.c
Show First 20 Lines • Show All 608 Lines • ▼ Show 20 Lines | |||||
* connect bpf write calls to the 802.11 layer for injecting | * connect bpf write calls to the 802.11 layer for injecting | ||||
* raw 802.11 frames. | * raw 802.11 frames. | ||||
*/ | */ | ||||
int | int | ||||
ieee80211_output(struct ifnet *ifp, struct mbuf *m, | ieee80211_output(struct ifnet *ifp, struct mbuf *m, | ||||
const struct sockaddr *dst, struct route *ro) | const struct sockaddr *dst, struct route *ro) | ||||
{ | { | ||||
#define senderr(e) do { error = (e); goto bad;} while (0) | #define senderr(e) do { error = (e); goto bad;} while (0) | ||||
const struct ieee80211_bpf_params *params = NULL; | struct ieee80211_bpf_params params; | ||||
struct ieee80211_node *ni = NULL; | struct ieee80211_node *ni = NULL; | ||||
struct ieee80211vap *vap; | struct ieee80211vap *vap; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211com *ic = NULL; | struct ieee80211com *ic = NULL; | ||||
int error; | int error; | ||||
int ret; | int ret; | ||||
if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { | if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { | ||||
Show All 36 Lines | #endif | ||||
/* | /* | ||||
* NB: DLT_IEEE802_11_RADIO identifies the parameters are | * NB: DLT_IEEE802_11_RADIO identifies the parameters are | ||||
* present by setting the sa_len field of the sockaddr (yes, | * present by setting the sa_len field of the sockaddr (yes, | ||||
* this is a hack). | * this is a hack). | ||||
* NB: we assume sa_data is suitably aligned to cast. | * NB: we assume sa_data is suitably aligned to cast. | ||||
*/ | */ | ||||
if (dst->sa_len != 0) | if (dst->sa_len != 0) | ||||
params = (const struct ieee80211_bpf_params *)dst->sa_data; | memcpy(¶ms, dst->sa_data, sizeof(params)); | ||||
error = ieee80211_validate_frame(m, params); | error = ieee80211_validate_frame(m, ¶ms); | ||||
if (error != 0) | if (error != 0) | ||||
senderr(error); | senderr(error); | ||||
wh = mtod(m, struct ieee80211_frame *); | wh = mtod(m, struct ieee80211_frame *); | ||||
/* locate destination node */ | /* locate destination node */ | ||||
switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { | switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { | ||||
case IEEE80211_FC1_DIR_NODS: | case IEEE80211_FC1_DIR_NODS: | ||||
Show All 12 Lines | if (ni == NULL) { | ||||
* Permit packets w/ bpf params through regardless | * Permit packets w/ bpf params through regardless | ||||
* (see below about sa_len). | * (see below about sa_len). | ||||
*/ | */ | ||||
if (dst->sa_len == 0) | if (dst->sa_len == 0) | ||||
senderr(EHOSTUNREACH); | senderr(EHOSTUNREACH); | ||||
ni = ieee80211_ref_node(vap->iv_bss); | ni = ieee80211_ref_node(vap->iv_bss); | ||||
} | } | ||||
if (dst->sa_len && params.ibp_vers == IEEE80211_BPF_VERSION) { | |||||
#define TO_RATE_INDEX(r, mode) \ | |||||
IEEE80211_BPF_RATE(ieee80211_convert_from_legacy_rate((r), (mode))) | |||||
const struct ieee80211_channel *chan; | |||||
enum ieee80211_phymode mode; | |||||
chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? | |||||
ni->ni_chan : ic->ic_curchan; | |||||
mode = ieee80211_chan2mode(chan); | |||||
/* Convert legacy rates to rate indices. */ | |||||
params.ibp_rate0 = TO_RATE_INDEX(params.ibp_rate0, mode); | |||||
params.ibp_rate1 = TO_RATE_INDEX(params.ibp_rate1, mode); | |||||
params.ibp_rate2 = TO_RATE_INDEX(params.ibp_rate2, mode); | |||||
params.ibp_rate3 = TO_RATE_INDEX(params.ibp_rate3, mode); | |||||
params.ibp_ctsrate = TO_RATE_INDEX(params.ibp_ctsrate, mode); | |||||
params.ibp_vers = IEEE80211_BPF_VERSION_1; | |||||
#undef TO_RATE_INDEX | |||||
} | |||||
/* | /* | ||||
* Sanitize mbuf for net80211 flags leaked from above. | * Sanitize mbuf for net80211 flags leaked from above. | ||||
* | * | ||||
* NB: This must be done before ieee80211_classify as | * NB: This must be done before ieee80211_classify as | ||||
* it marks EAPOL in frames with M_EAPOL. | * it marks EAPOL in frames with M_EAPOL. | ||||
*/ | */ | ||||
m->m_flags &= ~M_80211_TX; | m->m_flags &= ~M_80211_TX; | ||||
m->m_flags |= M_ENCAP; /* mark encapsulated */ | m->m_flags |= M_ENCAP; /* mark encapsulated */ | ||||
Show All 12 Lines | #undef TO_RATE_INDEX | ||||
IEEE80211_NODE_STAT(ni, tx_data); | IEEE80211_NODE_STAT(ni, tx_data); | ||||
if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { | if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { | ||||
IEEE80211_NODE_STAT(ni, tx_mcast); | IEEE80211_NODE_STAT(ni, tx_mcast); | ||||
m->m_flags |= M_MCAST; | m->m_flags |= M_MCAST; | ||||
} else | } else | ||||
IEEE80211_NODE_STAT(ni, tx_ucast); | IEEE80211_NODE_STAT(ni, tx_ucast); | ||||
IEEE80211_TX_LOCK(ic); | IEEE80211_TX_LOCK(ic); | ||||
ret = ieee80211_raw_output(vap, ni, m, params); | ret = ieee80211_raw_output(vap, ni, m, dst->sa_len ? ¶ms : NULL); | ||||
IEEE80211_TX_UNLOCK(ic); | IEEE80211_TX_UNLOCK(ic); | ||||
return (ret); | return (ret); | ||||
bad: | bad: | ||||
if (m != NULL) | if (m != NULL) | ||||
m_freem(m); | m_freem(m); | ||||
if (ni != NULL) | if (ni != NULL) | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
▲ Show 20 Lines • Show All 1,167 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Add a supported rates element id to a frame. | * Add a supported rates element id to a frame. | ||||
*/ | */ | ||||
uint8_t * | uint8_t * | ||||
ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) | ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) | ||||
{ | { | ||||
int nrates; | const struct ieee80211_rate_t *rate; | ||||
uint8_t i, nrates, value; | |||||
*frm++ = IEEE80211_ELEMID_RATES; | *frm++ = IEEE80211_ELEMID_RATES; | ||||
nrates = rs->rs_nrates; | nrates = rs->rs_nrates; | ||||
if (nrates > IEEE80211_RATE_SIZE) | if (nrates > IEEE80211_RATE_SIZE) | ||||
nrates = IEEE80211_RATE_SIZE; | nrates = IEEE80211_RATE_SIZE; | ||||
*frm++ = nrates; | *frm++ = nrates; | ||||
memcpy(frm, rs->rs_rates, nrates); | for (i = 0; i < nrates; i++) { | ||||
return frm + nrates; | rate = ieee80211_get_rate(rs->rates[i].rs_index); | ||||
value = rate->value; | |||||
if (rs->rates[i].rs_basic) | |||||
value |= IEEE80211_RATE_BASIC; | |||||
*frm++ = value; | |||||
} | } | ||||
return frm; | |||||
} | |||||
/* | /* | ||||
* Add an extended supported rates element id to a frame. | * Add an extended supported rates element id to a frame. | ||||
*/ | */ | ||||
uint8_t * | uint8_t * | ||||
ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) | ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) | ||||
{ | { | ||||
const struct ieee80211_rate_t *rate; | |||||
uint8_t i, value; | |||||
/* | /* | ||||
* Add an extended supported rates element if operating in 11g mode. | * Add an extended supported rates element if operating in 11g mode. | ||||
*/ | */ | ||||
if (rs->rs_nrates > IEEE80211_RATE_SIZE) { | if (rs->rs_nrates > IEEE80211_RATE_SIZE) { | ||||
int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; | |||||
*frm++ = IEEE80211_ELEMID_XRATES; | *frm++ = IEEE80211_ELEMID_XRATES; | ||||
*frm++ = nrates; | *frm++ = rs->rs_nrates - IEEE80211_RATE_SIZE; | ||||
memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); | |||||
frm += nrates; | for (i = IEEE80211_RATE_SIZE; i < rs->rs_nrates; i++) { | ||||
rate = ieee80211_get_rate(rs->rates[i].rs_index); | |||||
value = rate->value; | |||||
if (rs->rates[i].rs_basic) | |||||
value |= IEEE80211_RATE_BASIC; | |||||
*frm++ = value; | |||||
} | } | ||||
} | |||||
return frm; | return frm; | ||||
} | } | ||||
/* | /* | ||||
* Add an ssid element to a frame. | * Add an ssid element to a frame. | ||||
*/ | */ | ||||
uint8_t * | uint8_t * | ||||
ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) | ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) | ||||
▲ Show 20 Lines • Show All 288 Lines • ▼ Show 20 Lines | ieee80211_send_probereq(struct ieee80211_node *ni, | ||||
const uint8_t sa[IEEE80211_ADDR_LEN], | const uint8_t sa[IEEE80211_ADDR_LEN], | ||||
const uint8_t da[IEEE80211_ADDR_LEN], | const uint8_t da[IEEE80211_ADDR_LEN], | ||||
const uint8_t bssid[IEEE80211_ADDR_LEN], | const uint8_t bssid[IEEE80211_ADDR_LEN], | ||||
const uint8_t *ssid, size_t ssidlen) | const uint8_t *ssid, size_t ssidlen) | ||||
{ | { | ||||
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 ieee80211_node *bss; | struct ieee80211_node *bss; | ||||
const struct ieee80211_txparam *tp; | const struct ieee80211_txparam_vht *tp; | ||||
struct ieee80211_bpf_params params; | struct ieee80211_bpf_params params; | ||||
const struct ieee80211_rateset *rs; | const struct ieee80211_rateset *rs; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
uint8_t *frm; | uint8_t *frm; | ||||
int ret; | int ret; | ||||
bss = ieee80211_ref_node(vap->iv_bss); | bss = ieee80211_ref_node(vap->iv_bss); | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, | ||||
"send probe req on channel %u bssid %s sa %6D da %6D ssid \"%.*s\"\n", | "send probe req on channel %u bssid %s sa %6D da %6D ssid \"%.*s\"\n", | ||||
ieee80211_chan2ieee(ic, ic->ic_curchan), | ieee80211_chan2ieee(ic, ic->ic_curchan), | ||||
ether_sprintf(bssid), | ether_sprintf(bssid), | ||||
sa, ":", | sa, ":", | ||||
da, ":", | da, ":", | ||||
ssidlen, ssid); | ssidlen, ssid); | ||||
memset(¶ms, 0, sizeof(params)); | memset(¶ms, 0, sizeof(params)); | ||||
params.ibp_vers = IEEE80211_BPF_VERSION_1; | |||||
params.ibp_pri = M_WME_GETAC(m); | params.ibp_pri = M_WME_GETAC(m); | ||||
tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; | tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; | ||||
params.ibp_rate0 = tp->mgmtrate; | params.ibp_rate0 = IEEE80211_BPF_RATE(tp->mgmtrate); | ||||
if (IEEE80211_IS_MULTICAST(da)) { | if (IEEE80211_IS_MULTICAST(da)) { | ||||
params.ibp_flags |= IEEE80211_BPF_NOACK; | params.ibp_flags |= IEEE80211_BPF_NOACK; | ||||
params.ibp_try0 = 1; | params.ibp_try0 = 1; | ||||
} else | } else | ||||
params.ibp_try0 = tp->maxretry; | params.ibp_try0 = tp->maxretry; | ||||
params.ibp_power = ni->ni_txpower; | params.ibp_power = ni->ni_txpower; | ||||
ret = ieee80211_raw_output(vap, ni, m, ¶ms); | ret = ieee80211_raw_output(vap, ni, m, ¶ms); | ||||
IEEE80211_TX_UNLOCK(ic); | IEEE80211_TX_UNLOCK(ic); | ||||
▲ Show 20 Lines • Show All 386 Lines • ▼ Show 20 Lines | #endif /* IEEE80211_SUPPORT_SUPERG */ | ||||
default: | default: | ||||
IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, | IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, | ||||
"invalid mgmt frame type %u", type); | "invalid mgmt frame type %u", type); | ||||
senderr(EINVAL, is_tx_unknownmgt); | senderr(EINVAL, is_tx_unknownmgt); | ||||
/* NOTREACHED */ | /* NOTREACHED */ | ||||
} | } | ||||
/* NB: force non-ProbeResp frames to the highest queue */ | /* NB: force non-ProbeResp frames to the highest queue */ | ||||
params.ibp_vers = IEEE80211_BPF_VERSION_1; | |||||
params.ibp_pri = WME_AC_VO; | params.ibp_pri = WME_AC_VO; | ||||
params.ibp_rate0 = bss->ni_txparms->mgmtrate; | params.ibp_rate0 = IEEE80211_BPF_RATE(bss->ni_txparms->mgmtrate); | ||||
/* NB: we know all frames are unicast */ | /* NB: we know all frames are unicast */ | ||||
params.ibp_try0 = bss->ni_txparms->maxretry; | params.ibp_try0 = bss->ni_txparms->maxretry; | ||||
params.ibp_power = bss->ni_txpower; | params.ibp_power = bss->ni_txpower; | ||||
return ieee80211_mgmt_output(ni, m, type, ¶ms); | return ieee80211_mgmt_output(ni, m, type, ¶ms); | ||||
bad: | bad: | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
return ret; | return ret; | ||||
#undef senderr | #undef senderr | ||||
▲ Show 20 Lines • Show All 292 Lines • ▼ Show 20 Lines | ieee80211_alloc_cts(struct ieee80211com *ic, | ||||
return m; | return m; | ||||
} | } | ||||
/* | /* | ||||
* Wrapper for CTS/RTS frame allocation. | * Wrapper for CTS/RTS frame allocation. | ||||
*/ | */ | ||||
struct mbuf * | struct mbuf * | ||||
ieee80211_alloc_prot(struct ieee80211_node *ni, const struct mbuf *m, | ieee80211_alloc_prot(struct ieee80211_node *ni, const struct mbuf *m, | ||||
uint8_t rate, int prot) | uint16_t rate_idx, int prot) | ||||
{ | { | ||||
struct ieee80211com *ic = ni->ni_ic; | struct ieee80211com *ic = ni->ni_ic; | ||||
const struct ieee80211_frame *wh; | const struct ieee80211_frame *wh; | ||||
struct mbuf *mprot; | struct mbuf *mprot; | ||||
uint16_t dur; | uint32_t chan_flags; | ||||
uint16_t dur, ack_dur; | |||||
int pktlen, isshort; | int pktlen, isshort; | ||||
KASSERT(prot == IEEE80211_PROT_RTSCTS || | KASSERT(prot == IEEE80211_PROT_RTSCTS || | ||||
prot == IEEE80211_PROT_CTSONLY, | prot == IEEE80211_PROT_CTSONLY, | ||||
("wrong protection type %d", prot)); | ("wrong protection type %d", prot)); | ||||
wh = mtod(m, const struct ieee80211_frame *); | wh = mtod(m, const struct ieee80211_frame *); | ||||
pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; | pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; | ||||
isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; | isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; | ||||
dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) | if (ni->ni_chan != NULL && ni->ni_chan != IEEE80211_CHAN_ANYC) | ||||
+ ieee80211_ack_duration(ic->ic_rt, rate, isshort); | chan_flags = ni->ni_chan->ic_flags; | ||||
else | |||||
chan_flags = 0; | |||||
ack_dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, rate_idx, | |||||
isshort); | |||||
dur = ieee80211_compute_duration(rate_idx, pktlen, chan_flags, isshort) | |||||
+ ack_dur; | |||||
if (prot == IEEE80211_PROT_RTSCTS) { | if (prot == IEEE80211_PROT_RTSCTS) { | ||||
/* NB: CTS is the same size as an ACK */ | /* NB: CTS is the same size as an ACK */ | ||||
dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); | dur += ack_dur; | ||||
mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); | mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); | ||||
} else | } else | ||||
mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); | mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); | ||||
return (mprot); | return (mprot); | ||||
} | } | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 800 Lines • Show Last 20 Lines |