o fix wpa w/ wme: don't strip the QoS header on recv as tkip requires
it; instead pass the space occupied by the header down into the crypto modules (except in the demic case which needs it only when doing int in s/w) o while here fix defrag to strip the header from 2nd and later frames o teach decap code how to handle 4-address frames
This commit is contained in:
parent
2c67c57c8b
commit
2cc12aded0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=147252
@ -522,7 +522,7 @@ ieee80211_crypto_encap(struct ieee80211com *ic,
|
||||
*/
|
||||
struct ieee80211_key *
|
||||
ieee80211_crypto_decap(struct ieee80211com *ic,
|
||||
struct ieee80211_node *ni, struct mbuf *m)
|
||||
struct ieee80211_node *ni, struct mbuf *m, int hdrlen)
|
||||
{
|
||||
#define IEEE80211_WEP_HDRLEN (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
|
||||
#define IEEE80211_WEP_MINLEN \
|
||||
@ -533,7 +533,6 @@ ieee80211_crypto_decap(struct ieee80211com *ic,
|
||||
const struct ieee80211_cipher *cip;
|
||||
const u_int8_t *ivp;
|
||||
u_int8_t keyid;
|
||||
int hdrlen;
|
||||
|
||||
/* NB: this minimum size data frame could be bigger */
|
||||
if (m->m_pkthdr.len < IEEE80211_WEP_MINLEN) {
|
||||
@ -551,7 +550,6 @@ ieee80211_crypto_decap(struct ieee80211com *ic,
|
||||
* the key id in the header is meaningless (typically 0).
|
||||
*/
|
||||
wh = mtod(m, struct ieee80211_frame *);
|
||||
hdrlen = ieee80211_hdrsize(wh);
|
||||
ivp = mtod(m, const u_int8_t *) + hdrlen; /* XXX contig */
|
||||
keyid = ivp[IEEE80211_WEP_IVLEN];
|
||||
if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
|
||||
@ -573,7 +571,7 @@ ieee80211_crypto_decap(struct ieee80211com *ic,
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (cip->ic_decap(k, m) ? k : NULL);
|
||||
return (cip->ic_decap(k, m, hdrlen) ? k : NULL);
|
||||
#undef IEEE80211_WEP_MINLEN
|
||||
#undef IEEE80211_WEP_HDRLEN
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ struct ieee80211_cipher {
|
||||
int (*ic_setkey)(struct ieee80211_key *);
|
||||
int (*ic_encap)(struct ieee80211_key *, struct mbuf *,
|
||||
u_int8_t keyid);
|
||||
int (*ic_decap)(struct ieee80211_key *, struct mbuf *);
|
||||
int (*ic_decap)(struct ieee80211_key *, struct mbuf *, int);
|
||||
int (*ic_enmic)(struct ieee80211_key *, struct mbuf *, int);
|
||||
int (*ic_demic)(struct ieee80211_key *, struct mbuf *, int);
|
||||
};
|
||||
@ -173,7 +173,7 @@ int ieee80211_crypto_available(u_int cipher);
|
||||
struct ieee80211_key *ieee80211_crypto_encap(struct ieee80211com *,
|
||||
struct ieee80211_node *, struct mbuf *);
|
||||
struct ieee80211_key *ieee80211_crypto_decap(struct ieee80211com *,
|
||||
struct ieee80211_node *, struct mbuf *);
|
||||
struct ieee80211_node *, struct mbuf *, int);
|
||||
|
||||
/*
|
||||
* Check and remove any MIC.
|
||||
|
@ -67,7 +67,7 @@ static void *ccmp_attach(struct ieee80211com *, struct ieee80211_key *);
|
||||
static void ccmp_detach(struct ieee80211_key *);
|
||||
static int ccmp_setkey(struct ieee80211_key *);
|
||||
static int ccmp_encap(struct ieee80211_key *k, struct mbuf *, u_int8_t keyid);
|
||||
static int ccmp_decap(struct ieee80211_key *, struct mbuf *);
|
||||
static int ccmp_decap(struct ieee80211_key *, struct mbuf *, int);
|
||||
static int ccmp_enmic(struct ieee80211_key *, struct mbuf *, int);
|
||||
static int ccmp_demic(struct ieee80211_key *, struct mbuf *, int);
|
||||
|
||||
@ -197,20 +197,18 @@ READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5)
|
||||
* is also verified.
|
||||
*/
|
||||
static int
|
||||
ccmp_decap(struct ieee80211_key *k, struct mbuf *m)
|
||||
ccmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
|
||||
{
|
||||
struct ccmp_ctx *ctx = k->wk_private;
|
||||
struct ieee80211_frame *wh;
|
||||
uint8_t *ivp;
|
||||
uint64_t pn;
|
||||
int hdrlen;
|
||||
|
||||
/*
|
||||
* Header should have extended IV and sequence number;
|
||||
* verify the former and validate the latter.
|
||||
*/
|
||||
wh = mtod(m, struct ieee80211_frame *);
|
||||
hdrlen = ieee80211_hdrsize(wh);
|
||||
ivp = mtod(m, uint8_t *) + hdrlen;
|
||||
if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
|
||||
/*
|
||||
|
@ -52,7 +52,7 @@ static void *none_attach(struct ieee80211com *, struct ieee80211_key *);
|
||||
static void none_detach(struct ieee80211_key *);
|
||||
static int none_setkey(struct ieee80211_key *);
|
||||
static int none_encap(struct ieee80211_key *, struct mbuf *, u_int8_t);
|
||||
static int none_decap(struct ieee80211_key *, struct mbuf *);
|
||||
static int none_decap(struct ieee80211_key *, struct mbuf *, int);
|
||||
static int none_enmic(struct ieee80211_key *, struct mbuf *, int);
|
||||
static int none_demic(struct ieee80211_key *, struct mbuf *, int);
|
||||
|
||||
@ -110,7 +110,7 @@ none_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid)
|
||||
}
|
||||
|
||||
static int
|
||||
none_decap(struct ieee80211_key *k, struct mbuf *m)
|
||||
none_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
|
||||
{
|
||||
struct ieee80211com *ic = k->wk_private;
|
||||
#ifdef IEEE80211_DEBUG
|
||||
|
@ -60,7 +60,7 @@ static void tkip_detach(struct ieee80211_key *);
|
||||
static int tkip_setkey(struct ieee80211_key *);
|
||||
static int tkip_encap(struct ieee80211_key *, struct mbuf *m, u_int8_t keyid);
|
||||
static int tkip_enmic(struct ieee80211_key *, struct mbuf *, int);
|
||||
static int tkip_decap(struct ieee80211_key *, struct mbuf *);
|
||||
static int tkip_decap(struct ieee80211_key *, struct mbuf *, int);
|
||||
static int tkip_demic(struct ieee80211_key *, struct mbuf *, int);
|
||||
|
||||
static const struct ieee80211_cipher tkip = {
|
||||
@ -244,20 +244,18 @@ READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5)
|
||||
* the specified key.
|
||||
*/
|
||||
static int
|
||||
tkip_decap(struct ieee80211_key *k, struct mbuf *m)
|
||||
tkip_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
|
||||
{
|
||||
struct tkip_ctx *ctx = k->wk_private;
|
||||
struct ieee80211com *ic = ctx->tc_ic;
|
||||
struct ieee80211_frame *wh;
|
||||
uint8_t *ivp;
|
||||
int hdrlen;
|
||||
|
||||
/*
|
||||
* Header should have extended IV and sequence number;
|
||||
* verify the former and validate the latter.
|
||||
*/
|
||||
wh = mtod(m, struct ieee80211_frame *);
|
||||
hdrlen = ieee80211_hdrsize(wh);
|
||||
ivp = mtod(m, uint8_t *) + hdrlen;
|
||||
if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
|
||||
/*
|
||||
@ -327,11 +325,12 @@ tkip_demic(struct ieee80211_key *k, struct mbuf *m, int force)
|
||||
|
||||
if (force || (k->wk_flags & IEEE80211_KEY_SWMIC)) {
|
||||
struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
|
||||
int hdrlen = ieee80211_hdrsize(wh);
|
||||
struct ieee80211com *ic = ctx->tc_ic;
|
||||
int hdrlen = ieee80211_hdrspace(ic, wh);
|
||||
u8 mic[IEEE80211_WEP_MICLEN];
|
||||
u8 mic0[IEEE80211_WEP_MICLEN];
|
||||
|
||||
ctx->tc_ic->ic_stats.is_crypto_tkipdemic++;
|
||||
ic->ic_stats.is_crypto_tkipdemic++;
|
||||
|
||||
michael_mic(ctx, k->wk_rxmic,
|
||||
m, hdrlen, m->m_pkthdr.len - (hdrlen + tkip.ic_miclen),
|
||||
@ -340,8 +339,7 @@ tkip_demic(struct ieee80211_key *k, struct mbuf *m, int force)
|
||||
tkip.ic_miclen, mic0);
|
||||
if (memcmp(mic, mic0, tkip.ic_miclen)) {
|
||||
/* NB: 802.11 layer handles statistic and debug msg */
|
||||
ieee80211_notify_michael_failure(ctx->tc_ic, wh,
|
||||
k->wk_keyix);
|
||||
ieee80211_notify_michael_failure(ic, wh, k->wk_keyix);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ static void *wep_attach(struct ieee80211com *, struct ieee80211_key *);
|
||||
static void wep_detach(struct ieee80211_key *);
|
||||
static int wep_setkey(struct ieee80211_key *);
|
||||
static int wep_encap(struct ieee80211_key *, struct mbuf *, u_int8_t keyid);
|
||||
static int wep_decap(struct ieee80211_key *, struct mbuf *);
|
||||
static int wep_decap(struct ieee80211_key *, struct mbuf *, int hdrlen);
|
||||
static int wep_enmic(struct ieee80211_key *, struct mbuf *, int);
|
||||
static int wep_demic(struct ieee80211_key *, struct mbuf *, int);
|
||||
|
||||
@ -205,14 +205,12 @@ wep_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
|
||||
* the specified key.
|
||||
*/
|
||||
static int
|
||||
wep_decap(struct ieee80211_key *k, struct mbuf *m)
|
||||
wep_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
|
||||
{
|
||||
struct wep_ctx *ctx = k->wk_private;
|
||||
struct ieee80211_frame *wh;
|
||||
int hdrlen;
|
||||
|
||||
wh = mtod(m, struct ieee80211_frame *);
|
||||
hdrlen = ieee80211_hdrsize(wh);
|
||||
|
||||
/*
|
||||
* Check if the device handled the decrypt in hardware.
|
||||
|
@ -108,8 +108,8 @@ static void ieee80211_discard_mac(struct ieee80211com *,
|
||||
#endif /* IEEE80211_DEBUG */
|
||||
|
||||
static struct mbuf *ieee80211_defrag(struct ieee80211com *,
|
||||
struct ieee80211_node *, struct mbuf *);
|
||||
static struct mbuf *ieee80211_decap(struct ieee80211com *, struct mbuf *);
|
||||
struct ieee80211_node *, struct mbuf *, int);
|
||||
static struct mbuf *ieee80211_decap(struct ieee80211com *, struct mbuf *, int);
|
||||
static void ieee80211_send_error(struct ieee80211com *, struct ieee80211_node *,
|
||||
const u_int8_t *mac, int subtype, int arg);
|
||||
static void ieee80211_node_pwrsave(struct ieee80211_node *, int enable);
|
||||
@ -136,7 +136,7 @@ ieee80211_input(struct ieee80211com *ic, struct mbuf *m,
|
||||
struct ieee80211_frame *wh;
|
||||
struct ieee80211_key *key;
|
||||
struct ether_header *eh;
|
||||
int len, hdrsize, off;
|
||||
int len, hdrspace;
|
||||
u_int8_t dir, type, subtype;
|
||||
u_int8_t *bssid;
|
||||
u_int16_t rxseq;
|
||||
@ -286,33 +286,15 @@ ieee80211_input(struct ieee80211com *ic, struct mbuf *m,
|
||||
|
||||
switch (type) {
|
||||
case IEEE80211_FC0_TYPE_DATA:
|
||||
hdrsize = ieee80211_hdrsize(wh);
|
||||
if (ic->ic_flags & IEEE80211_F_DATAPAD)
|
||||
hdrsize = roundup(hdrsize, sizeof(u_int32_t));
|
||||
if (m->m_len < hdrsize &&
|
||||
(m = m_pullup(m, hdrsize)) == NULL) {
|
||||
hdrspace = ieee80211_hdrspace(ic, wh);
|
||||
if (m->m_len < hdrspace &&
|
||||
(m = m_pullup(m, hdrspace)) == NULL) {
|
||||
IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
|
||||
ni->ni_macaddr, NULL,
|
||||
"data too short: expecting %u", hdrsize);
|
||||
"data too short: expecting %u", hdrspace);
|
||||
ic->ic_stats.is_rx_tooshort++;
|
||||
goto out; /* XXX */
|
||||
}
|
||||
if (subtype & IEEE80211_FC0_SUBTYPE_QOS) {
|
||||
/* XXX discard if node w/o IEEE80211_NODE_QOS? */
|
||||
/*
|
||||
* Strip QoS control and any padding so only a
|
||||
* stock 802.11 header is at the front.
|
||||
*/
|
||||
/* XXX 4-address QoS frame */
|
||||
off = hdrsize - sizeof(struct ieee80211_frame);
|
||||
ovbcopy(mtod(m, u_int8_t *), mtod(m, u_int8_t *) + off,
|
||||
hdrsize - off);
|
||||
m_adj(m, off);
|
||||
wh = mtod(m, struct ieee80211_frame *);
|
||||
wh->i_fc[0] &= ~IEEE80211_FC0_SUBTYPE_QOS;
|
||||
} else {
|
||||
/* XXX copy up for 4-address frames w/ padding */
|
||||
}
|
||||
switch (ic->ic_opmode) {
|
||||
case IEEE80211_M_STA:
|
||||
if (dir != IEEE80211_FC1_DIR_FROMDS) {
|
||||
@ -399,7 +381,7 @@ ieee80211_input(struct ieee80211com *ic, struct mbuf *m,
|
||||
IEEE80211_NODE_STAT(ni, rx_noprivacy);
|
||||
goto out;
|
||||
}
|
||||
key = ieee80211_crypto_decap(ic, ni, m);
|
||||
key = ieee80211_crypto_decap(ic, ni, m, hdrspace);
|
||||
if (key == NULL) {
|
||||
/* NB: stats+msgs handled in crypto_decap */
|
||||
IEEE80211_NODE_STAT(ni, rx_wepfail);
|
||||
@ -415,7 +397,7 @@ ieee80211_input(struct ieee80211com *ic, struct mbuf *m,
|
||||
* Next up, any fragmentation.
|
||||
*/
|
||||
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
|
||||
m = ieee80211_defrag(ic, ni, m);
|
||||
m = ieee80211_defrag(ic, ni, m, hdrspace);
|
||||
if (m == NULL) {
|
||||
/* Fragment dropped or frame not complete yet */
|
||||
goto out;
|
||||
@ -440,7 +422,7 @@ ieee80211_input(struct ieee80211com *ic, struct mbuf *m,
|
||||
/*
|
||||
* Finally, strip the 802.11 header.
|
||||
*/
|
||||
m = ieee80211_decap(ic, m);
|
||||
m = ieee80211_decap(ic, m, hdrspace);
|
||||
if (m == NULL) {
|
||||
/* don't count Null data frames as errors */
|
||||
if (subtype == IEEE80211_FC0_SUBTYPE_NODATA)
|
||||
@ -579,7 +561,8 @@ ieee80211_input(struct ieee80211com *ic, struct mbuf *m,
|
||||
ic->ic_stats.is_rx_noprivacy++;
|
||||
goto out;
|
||||
}
|
||||
key = ieee80211_crypto_decap(ic, ni, m);
|
||||
hdrspace = ieee80211_hdrspace(ic, wh);
|
||||
key = ieee80211_crypto_decap(ic, ni, m, hdrspace);
|
||||
if (key == NULL) {
|
||||
/* NB: stats+msgs handled in crypto_decap */
|
||||
goto out;
|
||||
@ -627,7 +610,7 @@ ieee80211_input(struct ieee80211com *ic, struct mbuf *m,
|
||||
*/
|
||||
static struct mbuf *
|
||||
ieee80211_defrag(struct ieee80211com *ic, struct ieee80211_node *ni,
|
||||
struct mbuf *m)
|
||||
struct mbuf *m, int hdrspace)
|
||||
{
|
||||
struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
|
||||
struct ieee80211_frame *lwh;
|
||||
@ -696,6 +679,7 @@ ieee80211_defrag(struct ieee80211com *ic, struct ieee80211_node *ni,
|
||||
}
|
||||
mfrag = m;
|
||||
} else { /* concatenate */
|
||||
m_adj(m, hdrspace); /* strip header */
|
||||
m_cat(mfrag, m);
|
||||
/* NB: m_cat doesn't update the packet header */
|
||||
mfrag->m_pkthdr.len += m->m_pkthdr.len;
|
||||
@ -712,26 +696,26 @@ ieee80211_defrag(struct ieee80211com *ic, struct ieee80211_node *ni,
|
||||
}
|
||||
|
||||
static struct mbuf *
|
||||
ieee80211_decap(struct ieee80211com *ic, struct mbuf *m)
|
||||
ieee80211_decap(struct ieee80211com *ic, struct mbuf *m, int hdrlen)
|
||||
{
|
||||
struct ieee80211_frame wh; /* NB: QoS stripped above */
|
||||
struct ieee80211_qosframe_addr4 wh; /* Max size address frames */
|
||||
struct ether_header *eh;
|
||||
struct llc *llc;
|
||||
|
||||
if (m->m_len < sizeof(wh) + sizeof(*llc) &&
|
||||
(m = m_pullup(m, sizeof(wh) + sizeof(*llc))) == NULL) {
|
||||
if (m->m_len < hdrlen + sizeof(*llc) &&
|
||||
(m = m_pullup(m, hdrlen + sizeof(*llc))) == NULL) {
|
||||
/* XXX stat, msg */
|
||||
return NULL;
|
||||
}
|
||||
memcpy(&wh, mtod(m, caddr_t), sizeof(wh));
|
||||
llc = (struct llc *)(mtod(m, caddr_t) + sizeof(wh));
|
||||
memcpy(&wh, mtod(m, caddr_t), hdrlen);
|
||||
llc = (struct llc *)(mtod(m, caddr_t) + hdrlen);
|
||||
if (llc->llc_dsap == LLC_SNAP_LSAP && llc->llc_ssap == LLC_SNAP_LSAP &&
|
||||
llc->llc_control == LLC_UI && llc->llc_snap.org_code[0] == 0 &&
|
||||
llc->llc_snap.org_code[1] == 0 && llc->llc_snap.org_code[2] == 0) {
|
||||
m_adj(m, sizeof(wh) + sizeof(struct llc) - sizeof(*eh));
|
||||
m_adj(m, hdrlen + sizeof(struct llc) - sizeof(*eh));
|
||||
llc = NULL;
|
||||
} else {
|
||||
m_adj(m, sizeof(wh) - sizeof(*eh));
|
||||
m_adj(m, hdrlen - sizeof(*eh));
|
||||
}
|
||||
eh = mtod(m, struct ether_header *);
|
||||
switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) {
|
||||
@ -748,11 +732,9 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *m)
|
||||
IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr3);
|
||||
break;
|
||||
case IEEE80211_FC1_DIR_DSTODS:
|
||||
/* not yet supported */
|
||||
IEEE80211_DISCARD(ic, IEEE80211_MSG_ANY,
|
||||
&wh, "data", "%s", "DS to DS not supported");
|
||||
m_freem(m);
|
||||
return NULL;
|
||||
IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr3);
|
||||
IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr4);
|
||||
break;
|
||||
}
|
||||
#ifdef ALIGNED_POINTER
|
||||
if (!ALIGNED_POINTER(mtod(m, caddr_t) + sizeof(*eh), u_int32_t)) {
|
||||
|
Loading…
Reference in New Issue
Block a user