/* $OpenBSD: print-802_11.c,v 1.4 2006/06/01 22:09:09 reyk Exp $ */ /* * Copyright (c) 2005 Reyk Floeter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* usr.sbin/tcpdump/print-802_11.c,v 1.3 2005/03/09 11:43:17 deraadt Exp */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hostapd.h" const char *ieee80211_mgt_subtype_name[] = { "association request", "association response", "reassociation request", "reassociation response", "probe request", "probe response", "reserved#6", "reserved#7", "beacon", "atim", "disassociation", "authentication", "deauthentication", "reserved#13", "reserved#14", "reserved#15" }; const u_int8_t *snapend; int vflag = 1, eflag = 1; int ieee80211_hdr(struct ieee80211_frame *); void ieee80211_print_element(u_int8_t *, u_int); void ieee80211_print_essid(u_int8_t *, u_int); int ieee80211_elements(struct ieee80211_frame *); int ieee80211_frame(struct ieee80211_frame *); int ieee80211_print(struct ieee80211_frame *); u_int ieee80211_any2ieee(u_int, u_int); void ieee802_11_if_print(u_int8_t *, u_int); void ieee802_11_radio_if_print(u_int8_t *, u_int); #define TCARR(a) TCHECK2(*a, sizeof(a)) int ieee80211_hdr(struct ieee80211_frame *wh) { struct ieee80211_frame_addr4 *w4; switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { case IEEE80211_FC1_DIR_NODS: TCARR(wh->i_addr2); PRINTF("%s", etheraddr_string(wh->i_addr2)); TCARR(wh->i_addr1); PRINTF(" > %s", etheraddr_string(wh->i_addr1)); TCARR(wh->i_addr3); PRINTF(", bssid %s", etheraddr_string(wh->i_addr3)); break; case IEEE80211_FC1_DIR_TODS: TCARR(wh->i_addr2); PRINTF("%s", etheraddr_string(wh->i_addr2)); TCARR(wh->i_addr3); PRINTF(" > %s", etheraddr_string(wh->i_addr3)); TCARR(wh->i_addr1); PRINTF(", bssid %s, > DS", etheraddr_string(wh->i_addr1)); break; case IEEE80211_FC1_DIR_FROMDS: TCARR(wh->i_addr3); PRINTF("%s", etheraddr_string(wh->i_addr3)); TCARR(wh->i_addr1); PRINTF(" > %s", etheraddr_string(wh->i_addr1)); TCARR(wh->i_addr2); PRINTF(", bssid %s, DS >", etheraddr_string(wh->i_addr2)); break; case IEEE80211_FC1_DIR_DSTODS: w4 = (struct ieee80211_frame_addr4 *) wh; TCARR(w4->i_addr4); PRINTF("%s", etheraddr_string(w4->i_addr4)); TCARR(w4->i_addr3); PRINTF(" > %s", etheraddr_string(w4->i_addr3)); TCARR(w4->i_addr2); PRINTF(", bssid %s", etheraddr_string(w4->i_addr2)); TCARR(w4->i_addr1); PRINTF(" > %s, DS > DS", etheraddr_string(w4->i_addr1)); break; } if (vflag) { TCARR(wh->i_seq); PRINTF(" (seq %u)", letoh16(*(u_int16_t *)&wh->i_seq[0])); } return (0); trunc: /* Truncated elements in frame */ return (1); } /* Caller checks len */ void ieee80211_print_element(u_int8_t *data, u_int len) { u_int8_t *p; u_int i; PRINTF(" 0x"); for (i = 0, p = data; i < len; i++, p++) PRINTF("%02x", *p); } /* Caller checks len */ void ieee80211_print_essid(u_int8_t *essid, u_int len) { u_int8_t *p; u_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++) PRINTF("%c", *p); PRINTF(")"); } else ieee80211_print_element(essid, len); } 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); } int ieee80211_frame(struct ieee80211_frame *wh) { u_int8_t subtype, type, *frm; TCARR(wh->i_fc); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; frm = (u_int8_t *)&wh[1]; switch (type) { case IEEE80211_FC0_TYPE_DATA: PRINTF(": data"); break; case IEEE80211_FC0_TYPE_MGT: PRINTF(": %s", ieee80211_mgt_subtype_name[ subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]); switch (subtype) { case IEEE80211_FC0_SUBTYPE_BEACON: case IEEE80211_FC0_SUBTYPE_PROBE_RESP: if (ieee80211_elements(wh) != 0) goto trunc; break; case IEEE80211_FC0_SUBTYPE_AUTH: TCHECK2(*frm, 2); /* Auth Algorithm */ switch (IEEE80211_AUTH_ALGORITHM(frm)) { case IEEE80211_AUTH_ALG_OPEN: TCHECK2(*frm, 4); /* Auth Transaction */ switch (IEEE80211_AUTH_TRANSACTION(frm)) { case IEEE80211_AUTH_OPEN_REQUEST: PRINTF(" request"); break; case IEEE80211_AUTH_OPEN_RESPONSE: PRINTF(" response"); break; } break; case IEEE80211_AUTH_ALG_SHARED: TCHECK2(*frm, 4); /* Auth Transaction */ switch (IEEE80211_AUTH_TRANSACTION(frm)) { case IEEE80211_AUTH_SHARED_REQUEST: PRINTF(" request"); break; case IEEE80211_AUTH_SHARED_CHALLENGE: PRINTF(" challenge"); break; case IEEE80211_AUTH_SHARED_RESPONSE: PRINTF(" response"); break; case IEEE80211_AUTH_SHARED_PASS: PRINTF(" pass"); break; } break; case IEEE80211_AUTH_ALG_LEAP: PRINTF(" (leap)"); break; } break; } break; default: PRINTF(": type#%d", type); break; } if (wh->i_fc[1] & IEEE80211_FC1_WEP) PRINTF(", WEP"); return (0); trunc: /* Truncated 802.11 frame */ return (1); } u_int ieee80211_any2ieee(u_int freq, u_int flags) { if (flags & IEEE80211_CHAN_2GHZ) { if (freq == 2484) return 14; if (freq < 2484) return (freq - 2407) / 5; else return 15 + ((freq - 2512) / 20); } else if (flags & IEEE80211_CHAN_5GHZ) { return (freq - 5000) / 5; } else { /* Assume channel is already an IEEE number */ return (freq); } } int ieee80211_print(struct ieee80211_frame *wh) { if (eflag) if (ieee80211_hdr(wh)) return (1); return (ieee80211_frame(wh)); } void ieee802_11_if_print(u_int8_t *buf, u_int len) { struct ieee80211_frame *wh = (struct ieee80211_frame*)buf; snapend = buf + len; if (ieee80211_print(wh) != 0) PRINTF("[|802.11]"); PRINTF(NULL); } void ieee802_11_radio_if_print(u_int8_t *buf, u_int len) { struct ieee80211_radiotap_header *rh = (struct ieee80211_radiotap_header*)buf; struct ieee80211_frame *wh; u_int8_t *t; u_int32_t present; u_int rh_len; snapend = buf + len; TCHECK(*rh); rh_len = letoh16(rh->it_len); if (rh->it_version != 0) { PRINTF("[?radiotap + 802.11 v:%u]", rh->it_version); goto out; } wh = (struct ieee80211_frame *)(buf + rh_len); if (len <= rh_len || ieee80211_print(wh)) PRINTF("[|802.11]"); t = (u_int8_t*)buf + sizeof(struct ieee80211_radiotap_header); if ((present = letoh32(rh->it_present)) == 0) goto out; PRINTF(", it_version); #define RADIOTAP(_x) \ (present & (1 << IEEE80211_RADIOTAP_##_x)) if (RADIOTAP(TSFT)) { u_int64_t tsf; u_int32_t tsf_v[2]; TCHECK2(*t, 8); tsf = letoh64(*(u_int64_t *)t); tsf_v[0] = (u_int32_t)(tsf >> 32); tsf_v[1] = (u_int32_t)(tsf & 0x00000000ffffffff); if (vflag > 1) PRINTF(", tsf 0x%08x%08x", tsf_v[0], tsf_v[1]); t += 8; } if (RADIOTAP(FLAGS)) { u_int8_t flags = *(u_int8_t*)t; TCHECK2(*t, 1); if (flags & IEEE80211_RADIOTAP_F_CFP) PRINTF(", CFP"); if (flags & IEEE80211_RADIOTAP_F_SHORTPRE) PRINTF(", SHORTPRE"); if (flags & IEEE80211_RADIOTAP_F_WEP) PRINTF(", WEP"); if (flags & IEEE80211_RADIOTAP_F_FRAG) PRINTF(", FRAG"); t += 1; } if (RADIOTAP(RATE)) { TCHECK2(*t, 1); if (vflag) PRINTF(", %uMbit/s", (*(u_int8_t*)t) / 2); t += 1; } if (RADIOTAP(CHANNEL)) { u_int16_t freq, flags; TCHECK2(*t, 2); freq = letoh16(*(u_int16_t*)t); t += 2; TCHECK2(*t, 2); flags = letoh16(*(u_int16_t*)t); t += 2; PRINTF(", chan %u", ieee80211_any2ieee(freq, flags)); if (flags & IEEE80211_CHAN_DYN && flags & IEEE80211_CHAN_2GHZ) PRINTF(", 11g"); else if (flags & IEEE80211_CHAN_CCK && flags & IEEE80211_CHAN_2GHZ) PRINTF(", 11b"); else if (flags & IEEE80211_CHAN_OFDM && flags & IEEE80211_CHAN_2GHZ) PRINTF(", 11G"); else if (flags & IEEE80211_CHAN_OFDM && flags & IEEE80211_CHAN_5GHZ) PRINTF(", 11a"); if (flags & IEEE80211_CHAN_TURBO) PRINTF(", TURBO"); if (flags & IEEE80211_CHAN_XR) PRINTF(", XR"); } if (RADIOTAP(FHSS)) { TCHECK2(*t, 2); PRINTF(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1); t += 2; } if (RADIOTAP(DBM_ANTSIGNAL)) { TCHECK(*t); PRINTF(", sig %ddBm", *(int8_t*)t); t += 1; } if (RADIOTAP(DBM_ANTNOISE)) { TCHECK(*t); PRINTF(", noise %ddBm", *(int8_t*)t); t += 1; } if (RADIOTAP(LOCK_QUALITY)) { TCHECK2(*t, 2); if (vflag) PRINTF(", quality %u", letoh16(*(u_int16_t*)t)); t += 2; } if (RADIOTAP(TX_ATTENUATION)) { TCHECK2(*t, 2); if (vflag) PRINTF(", txatt %u", letoh16(*(u_int16_t*)t)); t += 2; } if (RADIOTAP(DB_TX_ATTENUATION)) { TCHECK2(*t, 2); if (vflag) PRINTF(", txatt %udB", letoh16(*(u_int16_t*)t)); t += 2; } if (RADIOTAP(DBM_TX_POWER)) { TCHECK(*t); PRINTF(", txpower %ddBm", *(int8_t*)t); t += 1; } if (RADIOTAP(ANTENNA)) { TCHECK(*t); if (vflag) PRINTF(", antenna %u", *(u_int8_t*)t); t += 1; } if (RADIOTAP(DB_ANTSIGNAL)) { TCHECK(*t); PRINTF(", signal %udB", *(u_int8_t*)t); t += 1; } if (RADIOTAP(DB_ANTNOISE)) { TCHECK(*t); PRINTF(", noise %udB", *(u_int8_t*)t); t += 1; } if (RADIOTAP(FCS)) { TCHECK2(*t, 4); if (vflag) PRINTF(", fcs %08x", letoh32(*(u_int32_t*)t)); t += 4; } #undef RADIOTAP PRINTF(">"); goto out; trunc: /* Truncated frame */ PRINTF("[|radiotap + 802.11]"); out: PRINTF(NULL); } void hostapd_print_ieee80211(u_int dlt, u_int verbose, u_int8_t *buf, u_int len) { if (verbose) vflag = 1; else vflag = 0; if (dlt == DLT_IEEE802_11) ieee802_11_if_print(buf, len); else ieee802_11_radio_if_print(buf, len); }