#include "ieee802_11_radio.h"
#define PRINT_SSID(p) \
- switch (p.ssid_status) { \
- case TRUNCATED: \
- return 0; \
- case PRESENT: \
+ if (p.ssid_present) { \
printf(" ("); \
fn_print(p.ssid.ssid, NULL); \
printf(")"); \
- break; \
- case NOT_PRESENT: \
- break; \
}
#define PRINT_RATE(_sep, _r, _suf) \
printf("%s%2.1f%s", _sep, (.5 * ((_r) & 0x7f)), _suf)
#define PRINT_RATES(p) \
- switch (p.rates_status) { \
- case TRUNCATED: \
- return 0; \
- case PRESENT: \
- do { \
- int z; \
- const char *sep = " ["; \
- for (z = 0; z < p.rates.length ; z++) { \
- PRINT_RATE(sep, p.rates.rate[z], \
- (p.rates.rate[z] & 0x80 ? "*" : "")); \
- sep = " "; \
- } \
- if (p.rates.length != 0) \
- printf(" Mbit]"); \
- } while (0); \
- break; \
- case NOT_PRESENT: \
- break; \
+ if (p.rates_present) { \
+ int z; \
+ const char *sep = " ["; \
+ for (z = 0; z < p.rates.length ; z++) { \
+ PRINT_RATE(sep, p.rates.rate[z], \
+ (p.rates.rate[z] & 0x80 ? "*" : "")); \
+ sep = " "; \
+ } \
+ if (p.rates.length != 0) \
+ printf(" Mbit]"); \
}
#define PRINT_DS_CHANNEL(p) \
- switch (p.ds_status) { \
- case TRUNCATED: \
- return 0; \
- case PRESENT: \
+ if (p.ds_present) \
printf(" CH: %u", p.ds.channel); \
- break; \
- case NOT_PRESENT: \
- break; \
- } \
printf("%s", \
CAPABILITY_PRIVACY(p.capability_info) ? ", PRIVACY" : "" );
return 1;
}
-static void
-parse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset)
+static int
+parse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset,
+ u_int length)
{
+ struct ssid_t ssid;
+ struct challenge_t challenge;
+ struct rates_t rates;
+ struct ds_t ds;
+ struct cf_t cf;
+ struct tim_t tim;
+
/*
* We haven't seen any elements yet.
*/
- pbody->challenge_status = NOT_PRESENT;
- pbody->ssid_status = NOT_PRESENT;
- pbody->rates_status = NOT_PRESENT;
- pbody->ds_status = NOT_PRESENT;
- pbody->cf_status = NOT_PRESENT;
- pbody->tim_status = NOT_PRESENT;
-
- for (;;) {
+ pbody->challenge_present = 0;
+ pbody->ssid_present = 0;
+ pbody->rates_present = 0;
+ pbody->ds_present = 0;
+ pbody->cf_present = 0;
+ pbody->tim_present = 0;
+
+ while (length != 0) {
if (!TTEST2(*(p + offset), 1))
- return;
+ return 0;
+ if (length < 1)
+ return 0;
switch (*(p + offset)) {
case E_SSID:
- /* Present, possibly truncated */
- pbody->ssid_status = TRUNCATED;
if (!TTEST2(*(p + offset), 2))
- return;
- memcpy(&pbody->ssid, p + offset, 2);
+ return 0;
+ if (length < 2)
+ return 0;
+ memcpy(&ssid, p + offset, 2);
offset += 2;
- if (pbody->ssid.length != 0) {
- if (pbody->ssid.length >
- sizeof(pbody->ssid.ssid) - 1)
- return;
- if (!TTEST2(*(p + offset), pbody->ssid.length))
- return;
- memcpy(&pbody->ssid.ssid, p + offset,
- pbody->ssid.length);
- offset += pbody->ssid.length;
+ length -= 2;
+ if (ssid.length != 0) {
+ if (ssid.length > sizeof(ssid.ssid) - 1)
+ return 0;
+ if (!TTEST2(*(p + offset), ssid.length))
+ return 0;
+ if (length < ssid.length)
+ return 0;
+ memcpy(&ssid.ssid, p + offset, ssid.length);
+ offset += ssid.length;
+ length -= ssid.length;
+ }
+ ssid.ssid[ssid.length] = '\0';
+ /*
+ * Present and not truncated.
+ *
+ * If we haven't already seen an SSID IE,
+ * copy this one, otherwise ignore this one,
+ * so we later report the first one we saw.
+ */
+ if (!pbody->ssid_present) {
+ pbody->ssid = ssid;
+ pbody->ssid_present = 1;
}
- pbody->ssid.ssid[pbody->ssid.length] = '\0';
- /* Present and not truncated */
- pbody->ssid_status = PRESENT;
break;
case E_CHALLENGE:
- /* Present, possibly truncated */
- pbody->challenge_status = TRUNCATED;
if (!TTEST2(*(p + offset), 2))
- return;
- memcpy(&pbody->challenge, p + offset, 2);
+ return 0;
+ if (length < 2)
+ return 0;
+ memcpy(&challenge, p + offset, 2);
offset += 2;
- if (pbody->challenge.length != 0) {
- if (pbody->challenge.length >
- sizeof(pbody->challenge.text) - 1)
- return;
- if (!TTEST2(*(p + offset), pbody->challenge.length))
- return;
- memcpy(&pbody->challenge.text, p + offset,
- pbody->challenge.length);
- offset += pbody->challenge.length;
+ length -= 2;
+ if (challenge.length != 0) {
+ if (challenge.length >
+ sizeof(challenge.text) - 1)
+ return 0;
+ if (!TTEST2(*(p + offset), challenge.length))
+ return 0;
+ if (length < challenge.length)
+ return 0;
+ memcpy(&challenge.text, p + offset,
+ challenge.length);
+ offset += challenge.length;
+ length -= challenge.length;
+ }
+ challenge.text[challenge.length] = '\0';
+ /*
+ * Present and not truncated.
+ *
+ * If we haven't already seen a challenge IE,
+ * copy this one, otherwise ignore this one,
+ * so we later report the first one we saw.
+ */
+ if (!pbody->challenge_present) {
+ pbody->challenge = challenge;
+ pbody->challenge_present = 1;
}
- pbody->challenge.text[pbody->challenge.length] = '\0';
- /* Present and not truncated */
- pbody->challenge_status = PRESENT;
break;
case E_RATES:
- /* Present, possibly truncated */
- pbody->rates_status = TRUNCATED;
if (!TTEST2(*(p + offset), 2))
- return;
- memcpy(&(pbody->rates), p + offset, 2);
+ return 0;
+ if (length < 2)
+ return 0;
+ memcpy(&rates, p + offset, 2);
offset += 2;
- if (pbody->rates.length != 0) {
- if (pbody->rates.length > sizeof pbody->rates.rate)
- return;
- if (!TTEST2(*(p + offset), pbody->rates.length))
- return;
- memcpy(&pbody->rates.rate, p + offset,
- pbody->rates.length);
- offset += pbody->rates.length;
+ length -= 2;
+ if (rates.length != 0) {
+ if (rates.length > sizeof rates.rate)
+ return 0;
+ if (!TTEST2(*(p + offset), rates.length))
+ return 0;
+ if (length < rates.length)
+ return 0;
+ memcpy(&rates.rate, p + offset, rates.length);
+ offset += rates.length;
+ length -= rates.length;
+ }
+ /*
+ * Present and not truncated.
+ *
+ * If we haven't already seen a rates IE,
+ * copy this one if it's not zero-length,
+ * otherwise ignore this one, so we later
+ * report the first one we saw.
+ *
+ * We ignore zero-length rates IEs as some
+ * devices seem to put a zero-length rates
+ * IE, followed by an SSID IE, followed by
+ * a non-zero-length rates IE into frames,
+ * even though IEEE Std 802.11-2007 doesn't
+ * seem to indicate that a zero-length rates
+ * IE is valid.
+ */
+ if (!pbody->rates_present && rates.length != 0) {
+ pbody->rates = rates;
+ pbody->rates_present = 1;
}
- /* Present and not truncated */
- pbody->rates_status = PRESENT;
break;
case E_DS:
- /* Present, possibly truncated */
- pbody->ds_status = TRUNCATED;
if (!TTEST2(*(p + offset), 3))
- return;
- memcpy(&pbody->ds, p + offset, 3);
+ return 0;
+ if (length < 3)
+ return 0;
+ memcpy(&ds, p + offset, 3);
offset += 3;
- /* Present and not truncated */
- pbody->ds_status = PRESENT;
+ length -= 3;
+ /*
+ * Present and not truncated.
+ *
+ * If we haven't already seen a DS IE,
+ * copy this one, otherwise ignore this one,
+ * so we later report the first one we saw.
+ */
+ if (!pbody->ds_present) {
+ pbody->ds = ds;
+ pbody->ds_present = 1;
+ }
break;
case E_CF:
- /* Present, possibly truncated */
- pbody->cf_status = TRUNCATED;
if (!TTEST2(*(p + offset), 8))
- return;
- memcpy(&pbody->cf, p + offset, 8);
+ return 0;
+ if (length < 8)
+ return 0;
+ memcpy(&cf, p + offset, 8);
offset += 8;
- /* Present and not truncated */
- pbody->cf_status = PRESENT;
+ length -= 8;
+ /*
+ * Present and not truncated.
+ *
+ * If we haven't already seen a CF IE,
+ * copy this one, otherwise ignore this one,
+ * so we later report the first one we saw.
+ */
+ if (!pbody->cf_present) {
+ pbody->cf = cf;
+ pbody->cf_present = 1;
+ }
break;
case E_TIM:
- /* Present, possibly truncated */
- pbody->tim_status = TRUNCATED;
if (!TTEST2(*(p + offset), 2))
- return;
- memcpy(&pbody->tim, p + offset, 2);
+ return 0;
+ if (length < 2)
+ return 0;
+ memcpy(&tim, p + offset, 2);
offset += 2;
+ length -= 2;
if (!TTEST2(*(p + offset), 3))
- return;
- memcpy(&pbody->tim.count, p + offset, 3);
+ return 0;
+ if (length < 3)
+ return 0;
+ memcpy(&tim.count, p + offset, 3);
offset += 3;
+ length -= 3;
- if (pbody->tim.length <= 3)
+ if (tim.length <= 3)
break;
- if (pbody->tim.length - 3 > (int)sizeof pbody->tim.bitmap)
- return;
- if (!TTEST2(*(p + offset), pbody->tim.length - 3))
- return;
- memcpy(pbody->tim.bitmap, p + (pbody->tim.length - 3),
- (pbody->tim.length - 3));
- offset += pbody->tim.length - 3;
- /* Present and not truncated */
- pbody->tim_status = PRESENT;
+ if (tim.length - 3 > (int)sizeof tim.bitmap)
+ return 0;
+ if (!TTEST2(*(p + offset), tim.length - 3))
+ return 0;
+ if (length < (u_int)(tim.length - 3))
+ return 0;
+ memcpy(tim.bitmap, p + (tim.length - 3),
+ (tim.length - 3));
+ offset += tim.length - 3;
+ length -= tim.length - 3;
+ /*
+ * Present and not truncated.
+ *
+ * If we haven't already seen a TIM IE,
+ * copy this one, otherwise ignore this one,
+ * so we later report the first one we saw.
+ */
+ if (!pbody->tim_present) {
+ pbody->tim = tim;
+ pbody->tim_present = 1;
+ }
break;
default:
#if 0
printf("(1) unhandled element_id (%d) ",
- *(p + offset) );
+ *(p + offset));
#endif
if (!TTEST2(*(p + offset), 2))
- return;
+ return 0;
+ if (length < 2)
+ return 0;
if (!TTEST2(*(p + offset + 2), *(p + offset + 1)))
- return;
+ return 0;
+ if (length < (u_int)(*(p + offset + 1) + 2))
+ return 0;
offset += *(p + offset + 1) + 2;
+ length -= *(p + offset + 1) + 2;
break;
}
}
+
+ /* No problems found. */
+ return 1;
}
/*********************************************************************************
*********************************************************************************/
static int
-handle_beacon(const u_char *p)
+handle_beacon(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
IEEE802_11_CAPINFO_LEN))
return 0;
+ if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
+ IEEE802_11_CAPINFO_LEN)
+ return 0;
memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
offset += IEEE802_11_TSTAMP_LEN;
+ length -= IEEE802_11_TSTAMP_LEN;
pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_BCNINT_LEN;
+ length -= IEEE802_11_BCNINT_LEN;
pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_CAPINFO_LEN;
+ length -= IEEE802_11_CAPINFO_LEN;
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
PRINT_SSID(pbody);
PRINT_RATES(pbody);
CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS");
PRINT_DS_CHANNEL(pbody);
- return 1;
+ return ret;
}
static int
-handle_assoc_request(const u_char *p)
+handle_assoc_request(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN))
return 0;
+ if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN)
+ return 0;
pbody.capability_info = EXTRACT_LE_16BITS(p);
offset += IEEE802_11_CAPINFO_LEN;
+ length -= IEEE802_11_CAPINFO_LEN;
pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_LISTENINT_LEN;
+ length -= IEEE802_11_LISTENINT_LEN;
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
PRINT_SSID(pbody);
PRINT_RATES(pbody);
- return 1;
+ return ret;
}
static int
-handle_assoc_response(const u_char *p)
+handle_assoc_response(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
IEEE802_11_AID_LEN))
return 0;
+ if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
+ IEEE802_11_AID_LEN)
+ return 0;
pbody.capability_info = EXTRACT_LE_16BITS(p);
offset += IEEE802_11_CAPINFO_LEN;
+ length -= IEEE802_11_CAPINFO_LEN;
pbody.status_code = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_STATUS_LEN;
+ length -= IEEE802_11_STATUS_LEN;
pbody.aid = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_AID_LEN;
+ length -= IEEE802_11_AID_LEN;
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
printf(" AID(%x) :%s: %s", ((u_int16_t)(pbody.aid << 2 )) >> 2 ,
CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "",
? status_text[pbody.status_code]
: "n/a"));
- return 1;
+ return ret;
}
static int
-handle_reassoc_request(const u_char *p)
+handle_reassoc_request(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
IEEE802_11_AP_LEN))
return 0;
+ if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
+ IEEE802_11_AP_LEN)
+ return 0;
pbody.capability_info = EXTRACT_LE_16BITS(p);
offset += IEEE802_11_CAPINFO_LEN;
+ length -= IEEE802_11_CAPINFO_LEN;
pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_LISTENINT_LEN;
+ length -= IEEE802_11_LISTENINT_LEN;
memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN);
offset += IEEE802_11_AP_LEN;
+ length -= IEEE802_11_AP_LEN;
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
PRINT_SSID(pbody);
printf(" AP : %s", etheraddr_string( pbody.ap ));
- return 1;
+ return ret;
}
static int
-handle_reassoc_response(const u_char *p)
+handle_reassoc_response(const u_char *p, u_int length)
{
/* Same as a Association Reponse */
- return handle_assoc_response(p);
+ return handle_assoc_response(p, length);
}
static int
-handle_probe_request(const u_char *p)
+handle_probe_request(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
PRINT_SSID(pbody);
PRINT_RATES(pbody);
- return 1;
+ return ret;
}
static int
-handle_probe_response(const u_char *p)
+handle_probe_response(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
IEEE802_11_CAPINFO_LEN))
return 0;
-
+ if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
+ IEEE802_11_CAPINFO_LEN)
+ return 0;
memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
offset += IEEE802_11_TSTAMP_LEN;
+ length -= IEEE802_11_TSTAMP_LEN;
pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_BCNINT_LEN;
+ length -= IEEE802_11_BCNINT_LEN;
pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_CAPINFO_LEN;
+ length -= IEEE802_11_CAPINFO_LEN;
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
PRINT_SSID(pbody);
PRINT_RATES(pbody);
PRINT_DS_CHANNEL(pbody);
- return 1;
+ return ret;
}
static int
}
static int
-handle_disassoc(const u_char *p)
+handle_disassoc(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
if (!TTEST2(*p, IEEE802_11_REASON_LEN))
return 0;
+ if (length < IEEE802_11_REASON_LEN)
+ return 0;
pbody.reason_code = EXTRACT_LE_16BITS(p);
printf(": %s",
}
static int
-handle_auth(const u_char *p)
+handle_auth(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
if (!TTEST2(*p, 6))
return 0;
+ if (length < 6)
+ return 0;
pbody.auth_alg = EXTRACT_LE_16BITS(p);
offset += 2;
+ length -= 2;
pbody.auth_trans_seq_num = EXTRACT_LE_16BITS(p + offset);
offset += 2;
+ length -= 2;
pbody.status_code = EXTRACT_LE_16BITS(p + offset);
offset += 2;
+ length -= 2;
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
if ((pbody.auth_alg == 1) &&
((pbody.auth_trans_seq_num == 2) ||
? ((pbody.status_code < NUM_STATUSES)
? status_text[pbody.status_code]
: "n/a") : ""));
- return 1;
+ return ret;
}
printf(" (%s)-%x: %s",
(pbody.auth_alg < NUM_AUTH_ALGS)
: "n/a")
: "");
- return 1;
+ return ret;
}
static int
-handle_deauth(const struct mgmt_header_t *pmh, const u_char *p)
+handle_deauth(const struct mgmt_header_t *pmh, const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
if (!TTEST2(*p, IEEE802_11_REASON_LEN))
return 0;
+ if (length < IEEE802_11_REASON_LEN)
+ return 0;
pbody.reason_code = EXTRACT_LE_16BITS(p);
offset += IEEE802_11_REASON_LEN;
+ length -= IEEE802_11_REASON_LEN;
reason = (pbody.reason_code < NUM_REASONS)
? reason_text[pbody.reason_code]
)
static int
-handle_action(const struct mgmt_header_t *pmh, const u_char *p)
+handle_action(const struct mgmt_header_t *pmh, const u_char *p, u_int length)
{
if (!TTEST2(*p, 2))
return 0;
+ if (length < 2)
+ return 0;
if (eflag) {
printf(": ");
} else {
static int
mgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh,
- const u_char *p)
+ const u_char *p, u_int length)
{
switch (FC_SUBTYPE(fc)) {
case ST_ASSOC_REQUEST:
printf("Assoc Request");
- return handle_assoc_request(p);
+ return handle_assoc_request(p, length);
case ST_ASSOC_RESPONSE:
printf("Assoc Response");
- return handle_assoc_response(p);
+ return handle_assoc_response(p, length);
case ST_REASSOC_REQUEST:
printf("ReAssoc Request");
- return handle_reassoc_request(p);
+ return handle_reassoc_request(p, length);
case ST_REASSOC_RESPONSE:
printf("ReAssoc Response");
- return handle_reassoc_response(p);
+ return handle_reassoc_response(p, length);
case ST_PROBE_REQUEST:
printf("Probe Request");
- return handle_probe_request(p);
+ return handle_probe_request(p, length);
case ST_PROBE_RESPONSE:
printf("Probe Response");
- return handle_probe_response(p);
+ return handle_probe_response(p, length);
case ST_BEACON:
printf("Beacon");
- return handle_beacon(p);
+ return handle_beacon(p, length);
case ST_ATIM:
printf("ATIM");
return handle_atim();
case ST_DISASSOC:
printf("Disassociation");
- return handle_disassoc(p);
+ return handle_disassoc(p, length);
case ST_AUTH:
printf("Authentication");
if (!TTEST2(*p, 3))
printf("Authentication (Shared-Key)-3 ");
return wep_print(p);
}
- return handle_auth(p);
+ return handle_auth(p, length);
case ST_DEAUTH:
printf("DeAuthentication");
- return handle_deauth(pmh, p);
+ return handle_deauth(pmh, p, length);
break;
case ST_ACTION:
printf("Action");
- return handle_action(pmh, p);
+ return handle_action(pmh, p, length);
break;
default:
printf("Unhandled Management subtype(%x)",
switch (FC_TYPE(fc)) {
case T_MGMT:
if (!mgmt_body_print(fc,
- (const struct mgmt_header_t *)(p - hdrlen), p)) {
+ (const struct mgmt_header_t *)(p - hdrlen), p, length)) {
printf("[|802.11]");
return hdrlen;
}