/* Caller checks len */ void ieee80211_print_essid(u_int8_t *essid, u_int len) { u_int8_t *p; int i; if (len > IEEE80211_NWID_LEN) len = IEEE80211_NWID_LEN; /* determine printable or not */ for (i = 0, p = essid; i < len; i++, p++) { if (*p < ' ' || *p > 0x7e) break; } if (i == len) { printf(" ("); for (i = 0, p = essid; i < len; i++, p++) putchar(*p); putchar(')'); } else ieee80211_print_element(essid, len); }
/* Caller checks len */ void ieee80211_print_htcaps(u_int8_t *data, u_int len) { uint16_t htcaps, rxrate; int smps, rxstbc; uint8_t ampdu, txmcs; int i; uint8_t *rxmcs; if (len < 2) { ieee80211_print_element(data, len); return; } htcaps = (data[0]) | (data[1] << 8); printf("=<"); /* channel width */ if (htcaps & IEEE80211_HTCAP_CBW20_40) printf("20/40MHz"); else printf("20MHz"); /* LDPC coding */ if (htcaps & IEEE80211_HTCAP_LDPC) printf(",LDPC"); /* spatial multiplexing power save mode */ smps = (htcaps & IEEE80211_HTCAP_SMPS_MASK) >> IEEE80211_HTCAP_SMPS_SHIFT; if (smps == 0) printf(",SMPS static"); else if (smps == 1) printf(",SMPS dynamic"); /* 11n greenfield mode */ if (htcaps & IEEE80211_HTCAP_GF) printf(",greenfield"); /* short guard interval */ if (htcaps & IEEE80211_HTCAP_SGI20) printf(",SGI@20MHz"); if (htcaps & IEEE80211_HTCAP_SGI40) printf(",SGI@40MHz"); /* space-time block coding */ if (htcaps & IEEE80211_HTCAP_TXSTBC) printf(",TXSTBC"); rxstbc = (htcaps & IEEE80211_HTCAP_RXSTBC_MASK) >> IEEE80211_HTCAP_RXSTBC_SHIFT; if (rxstbc > 0 && rxstbc < 4) printf(",RXSTBC %d stream", rxstbc); /* delayed block-ack */ if (htcaps & IEEE80211_HTCAP_DELAYEDBA) printf(",delayed BA"); /* max A-MSDU length */ if (htcaps & IEEE80211_HTCAP_AMSDU7935) printf(",A-MSDU 7935"); else printf(",A-MSDU 3839"); /* DSSS/CCK in 40MHz mode */ if (htcaps & IEEE80211_HTCAP_DSSSCCK40) printf(",DSSS/CCK@40MHz"); /* 40MHz intolerant */ if (htcaps & IEEE80211_HTCAP_40INTOLERANT) printf(",40MHz intolerant"); /* L-SIG TXOP protection */ if (htcaps & IEEE80211_HTCAP_LSIGTXOPPROT) printf(",L-SIG TXOP prot"); if (len < 3) { printf(">"); return; } /* A-MPDU parameters. */ ampdu = data[2]; /* A-MPDU length exponent */ if ((ampdu & IEEE80211_AMPDU_PARAM_LE) >= 0 && (ampdu & IEEE80211_AMPDU_PARAM_LE) <= 3) printf(",A-MPDU max %d", (1 << (13 + (ampdu & IEEE80211_AMPDU_PARAM_LE))) - 1); /* A-MPDU start spacing */ if (ampdu & IEEE80211_AMPDU_PARAM_SS) { float ss; switch ((ampdu & IEEE80211_AMPDU_PARAM_SS) >> 2) { case 1: ss = 0.25; break; case 2: ss = 0.5; break; case 3: ss = 1; break; case 4: ss = 2; break; case 5: ss = 4; break; case 6: ss = 8; break; case 7: ss = 16; break; default: ss = 0; break; } if (ss != 0) printf(",A-MPDU spacing %.2fus", ss); }
int ieee80211_elements(struct ieee80211_frame *wh) { u_int8_t *frm; u_int8_t *tstamp, *bintval, *capinfo; int i; frm = (u_int8_t *)&wh[1]; tstamp = frm; TCHECK2(*tstamp, 8); frm += 8; bintval = frm; TCHECK2(*bintval, 2); frm += 2; if (vflag) PRINTF(", interval %u", letoh16(*(u_int16_t *)bintval)); capinfo = frm; TCHECK2(*capinfo, 2); frm += 2; #if 0 if (vflag) printb(", caps", letoh16(*(u_int16_t *)capinfo), IEEE80211_CAPINFO_BITS); #endif while (TTEST2(*frm, 2)) { u_int len = frm[1]; u_int8_t *data = frm + 2; if (!TTEST2(*data, len)) break; #define ELEM_CHECK(l) if (len != l) break switch (*frm) { case IEEE80211_ELEMID_SSID: PRINTF(", ssid"); ieee80211_print_essid(data, len); break; case IEEE80211_ELEMID_RATES: if (!vflag) break; PRINTF(", rates"); for (i = len; i > 0; i--, data++) PRINTF(" %uM", (data[0] & IEEE80211_RATE_VAL) / 2); break; case IEEE80211_ELEMID_FHPARMS: ELEM_CHECK(5); PRINTF(", fh (dwell %u, chan %u, index %u)", (data[1] << 8) | data[0], (data[2] - 1) * 80 + data[3], /* FH_CHAN */ data[4]); break; case IEEE80211_ELEMID_DSPARMS: ELEM_CHECK(1); if (!vflag) break; PRINTF(", ds"); PRINTF(" (chan %u)", data[0]); break; case IEEE80211_ELEMID_CFPARMS: if (!vflag) break; PRINTF(", cf"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_TIM: if (!vflag) break; PRINTF(", tim"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_IBSSPARMS: if (!vflag) break; PRINTF(", ibss"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_COUNTRY: if (!vflag) break; PRINTF(", country"); for (i = len; i > 0; i--, data++) PRINTF(" %u", data[0]); break; case IEEE80211_ELEMID_CHALLENGE: if (!vflag) break; PRINTF(", challenge"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_ERP: if (!vflag) break; PRINTF(", erp"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_RSN: if (!vflag) break; PRINTF(", rsn"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_XRATES: if (!vflag) break; PRINTF(", xrates"); for (i = len; i > 0; i--, data++) PRINTF(" %uM", (data[0] & IEEE80211_RATE_VAL) / 2); break; case IEEE80211_ELEMID_TPC: if (!vflag) break; PRINTF(", tpc"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_CCKM: if (!vflag) break; PRINTF(", cckm"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_VENDOR: if (!vflag) break; PRINTF(", vendor"); ieee80211_print_element(data, len); break; default: if (!vflag) break; PRINTF(", %u:%u", (u_int) *frm, len); ieee80211_print_element(data, len); break; } frm += len + 2; if (frm >= snapend) break; } #undef ELEM_CHECK return (0); trunc: /* Truncated elements in frame */ return (1); }