DF-3325 / dfpredispatch.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | /* * DF-3325 / DF-3342 / DF-3416 harness (shared shape, one binary per * finding compiled with -DHOSTAP / -DSTA / -DADHOC) -- pre-dispatch * rx-sequence block reads i_seq (offset 22) and i_qos (offset 24) of * TODS/DSTODS frames although only frame_ack (10 bytes) is guaranteed. * * VERBATIM kernel code (hostap.c:580-590 == sta.c:641-649 == * adhoc.c:410-419 modulo the addr2 precondition): * * if (IEEE80211_HAS_SEQ(type, subtype)) { * uint8_t tid = ieee80211_gettid(wh); * if (IEEE80211_QOS_HAS_SEQ(wh) && * TID_TO_WME_AC(tid) >= WME_AC_VI) * ic->ic_wme.wme_hipri_traffic++; * if (! ieee80211_check_rxseq(ni, wh, bssid)) * goto out; * } * * The >= 24-byte length check only guards the NODS bssid path * (hostap.c:557-566); a TODS QoS data frame of 10 bytes passes: * dir = TODS -> bssid = wh->i_addr1 (bytes 4..10, in range) * IEEE80211_HAS_SEQ(DATA) = true * ieee80211_gettid -> IEEE80211_QOS_HAS_SEQ(wh) (reads i_fc[0]) -> * ((qosframe*)wh)->i_qos[0] = byte 24 of a 10-byte frame. * ieee80211_check_rxseq() then reads wh->i_seq (bytes 22-23). */ #include "guard.h" /* frame layout */ struct ieee80211_frame { uint8_t i_fc[2], i_dur[2]; uint8_t i_addr1[6], i_addr2[6], i_addr3[6]; uint16_t i_seq; } __packed; struct ieee80211_qosframe { struct ieee80211_frame wh; uint16_t i_qos[2]; } __packed; /* verbatim macros (ieee80211.h / _ieee80211.h) */ #define IEEE80211_FC0_TYPE_MASK 0x0c #define IEEE80211_FC0_SUBTYPE_QOS 0x80 #define IEEE80211_FC0_TYPE_DATA 0x08 #define IEEE80211_FC1_DIR_MASK 0x03 #define IEEE80211_FC1_DIR_TODS 0x01 #define IEEE80211_FC1_DIR_NODS 0x00 #define IEEE80211_FC0_TYPE_CTL 0x04 #define IEEE80211_QOS_TID 0x0f #define IEEE80211_HAS_SEQ(t, s) \ (((t) == IEEE80211_FC0_TYPE_DATA || \ !((s) & 0x40) /* !CF-Ack,CF-Poll */) && \ (t) != IEEE80211_FC0_TYPE_CTL) #define IEEE80211_QOS_HAS_SEQ(wh) \ (((wh)->i_fc[0] & \ (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == \ (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) /* verbatim ieee80211_proto.h:337-350 */ static uint8_t ieee80211_gettid(const struct ieee80211_frame *wh) { uint8_t tid; if (IEEE80211_QOS_HAS_SEQ(wh)) { tid = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; tid &= IEEE80211_QOS_TID; } else tid = 7; /* IEEE80211_NONQOS_TID */ return tid; } static int hipri; /* the pre-dispatch block, verbatim shape */ static int predispatch(struct ieee80211_frame *wh, uint8_t *bssid) { int type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; int subtype = wh->i_fc[0] & 0xf0; int dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; /* only the NODS path is length-checked in the kernel */ if (dir != IEEE80211_FC1_DIR_NODS) bssid = wh->i_addr1; /* bytes 4..10 -- in range */ else return 0; /* (NODS path is guarded) */ if (IEEE80211_HAS_SEQ(type, subtype)) { uint8_t tid = ieee80211_gettid(wh); /* reads byte 24 */ if (IEEE80211_QOS_HAS_SEQ(wh) && (tid & 7) >= 5) hipri++; /* ieee80211_check_rxseq(ni, wh, bssid) reads wh->i_seq */ volatile uint16_t seq __unused = wh->i_seq; /* bytes 22..23 */ } return 0; } static struct ieee80211_frame *wh; static struct ieee80211_frame *wh; int df_frame_len; int main(int argc, char **argv) { int oob = (argc > 1 && argv[1][0] == 'o'); #if defined(HOSTAP) printf("DF-3325 (hostap_input pre-dispatch, hostap.c:580-590)\n"); #elif defined(STA) printf("DF-3342 (sta_input pre-dispatch, sta.c:641-649)\n"); #else printf("DF-3416 (adhoc_input pre-dispatch, adhoc.c:410-419)\n"); #endif wh = (struct ieee80211_frame *)guard_buf(oob ? 10 : 30); df_frame_len = oob ? 10 : 30; wh->i_fc[0] = IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS; wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; memset((void *)wh->i_addr1, 0xff, 6); printf(" frame: %d bytes, TODS, QoS data; i_qos at offset 24, i_seq at 22\n", oob ? 10 : 30); printf(" pre-dispatch block: gettid reads i_qos[0]; check_rxseq reads i_seq\n"); fflush(stdout); #if defined(FIXED) && defined(HOSTAP) /* DF-3325 fix: require a full header for any sequenced frame */ if (((struct { char b[30]; } *)0, 0)) {} #endif #if defined(FIXED) && (defined(STA) || defined(ADHOC) || defined(HOSTAP)) { /* pre-dispatch length gate: sequenced/QoS frames need the * full qosframe header present (>= 26 bytes TODS QoS) */ extern int df_frame_len; if (df_frame_len < 26) { printf("FIXED: frame too short for seq/QoS pre-dispatch" " (%d bytes), rejected\n", df_frame_len); return 0; } } #endif predispatch(wh, NULL); printf(" ran (frame long enough)\n"); return 0; } |