summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net80211/ieee80211_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/net80211/ieee80211_output.c')
-rw-r--r--freebsd/sys/net80211/ieee80211_output.c108
1 files changed, 99 insertions, 9 deletions
diff --git a/freebsd/sys/net80211/ieee80211_output.c b/freebsd/sys/net80211/ieee80211_output.c
index 06fca965..57ea67d3 100644
--- a/freebsd/sys/net80211/ieee80211_output.c
+++ b/freebsd/sys/net80211/ieee80211_output.c
@@ -165,6 +165,7 @@ ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m,
* uses any existing value for rcvif to identify the
* interface it (might have been) received on.
*/
+ MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0);
m->m_pkthdr.rcvif = (void *)ni;
mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1: 0;
@@ -530,6 +531,7 @@ ieee80211_raw_output(struct ieee80211vap *vap, struct ieee80211_node *ni,
* that the mbuf has the same node value that
* it would if it were going via the normal path.
*/
+ MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0);
m->m_pkthdr.rcvif = (void *)ni;
/*
@@ -606,6 +608,97 @@ ieee80211_validate_frame(struct mbuf *m,
return (0);
}
+static int
+ieee80211_validate_rate(struct ieee80211_node *ni, uint8_t rate)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+
+ if (IEEE80211_IS_HT_RATE(rate)) {
+ if ((ic->ic_htcaps & IEEE80211_HTC_HT) == 0)
+ return (EINVAL);
+
+ rate = IEEE80211_RV(rate);
+ if (rate <= 31) {
+ if (rate > ic->ic_txstream * 8 - 1)
+ return (EINVAL);
+
+ return (0);
+ }
+
+ if (rate == 32) {
+ if ((ic->ic_htcaps & IEEE80211_HTC_TXMCS32) == 0)
+ return (EINVAL);
+
+ return (0);
+ }
+
+ if ((ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) == 0)
+ return (EINVAL);
+
+ switch (ic->ic_txstream) {
+ case 0:
+ case 1:
+ return (EINVAL);
+ case 2:
+ if (rate > 38)
+ return (EINVAL);
+
+ return (0);
+ case 3:
+ if (rate > 52)
+ return (EINVAL);
+
+ return (0);
+ case 4:
+ default:
+ if (rate > 76)
+ return (EINVAL);
+
+ return (0);
+ }
+ }
+
+ if (!ieee80211_isratevalid(ic->ic_rt, rate))
+ return (EINVAL);
+
+ return (0);
+}
+
+static int
+ieee80211_sanitize_rates(struct ieee80211_node *ni, struct mbuf *m,
+ const struct ieee80211_bpf_params *params)
+{
+ int error;
+
+ if (!params)
+ return (0); /* nothing to do */
+
+ /* NB: most drivers assume that ibp_rate0 is set (!= 0). */
+ if (params->ibp_rate0 != 0) {
+ error = ieee80211_validate_rate(ni, params->ibp_rate0);
+ if (error != 0)
+ return (error);
+ } else {
+ /* XXX pre-setup some default (e.g., mgmt / mcast) rate */
+ /* XXX __DECONST? */
+ (void) m;
+ }
+
+ if (params->ibp_rate1 != 0 &&
+ (error = ieee80211_validate_rate(ni, params->ibp_rate1)) != 0)
+ return (error);
+
+ if (params->ibp_rate2 != 0 &&
+ (error = ieee80211_validate_rate(ni, params->ibp_rate2)) != 0)
+ return (error);
+
+ if (params->ibp_rate3 != 0 &&
+ (error = ieee80211_validate_rate(ni, params->ibp_rate3)) != 0)
+ return (error);
+
+ return (0);
+}
+
/*
* 802.11 output routine. This is (currently) used only to
* connect bpf write calls to the 802.11 layer for injecting
@@ -720,6 +813,10 @@ ieee80211_output(struct ifnet *ifp, struct mbuf *m,
} else
M_WME_SETAC(m, WME_AC_BE);
+ error = ieee80211_sanitize_rates(ni, m, params);
+ if (error != 0)
+ senderr(error);
+
IEEE80211_NODE_STAT(ni, tx_data);
if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
IEEE80211_NODE_STAT(ni, tx_mcast);
@@ -1700,7 +1797,6 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
* capability; this may also change when we pull
* aggregation up into net80211
*/
- seqno = ni->ni_txseqs[tid]++;
*(uint16_t *)wh->i_seq =
htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
M_SEQNO_SET(m, seqno);
@@ -1856,14 +1952,8 @@ ieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0,
whf = mtod(m, struct ieee80211_frame *);
memcpy(whf, wh, hdrsize);
#ifdef IEEE80211_SUPPORT_MESH
- if (vap->iv_opmode == IEEE80211_M_MBSS) {
- if (IEEE80211_IS_DSTODS(wh))
- ((struct ieee80211_qosframe_addr4 *)
- whf)->i_qos[1] &= ~IEEE80211_QOS_MC;
- else
- ((struct ieee80211_qosframe *)
- whf)->i_qos[1] &= ~IEEE80211_QOS_MC;
- }
+ if (vap->iv_opmode == IEEE80211_M_MBSS)
+ ieee80211_getqos(wh)[1] &= ~IEEE80211_QOS_MC;
#endif
*(uint16_t *)&whf->i_seq[0] |= htole16(
(fragno & IEEE80211_SEQ_FRAG_MASK) <<