diff options
Diffstat (limited to 'usr.sbin/hostapd/print-802_11.c')
-rw-r--r-- | usr.sbin/hostapd/print-802_11.c | 647 |
1 files changed, 647 insertions, 0 deletions
diff --git a/usr.sbin/hostapd/print-802_11.c b/usr.sbin/hostapd/print-802_11.c new file mode 100644 index 00000000000..c1e7781d516 --- /dev/null +++ b/usr.sbin/hostapd/print-802_11.c @@ -0,0 +1,647 @@ +/* $OpenBSD: print-802_11.c,v 1.1 2005/06/17 19:13:35 reyk Exp $ */ + +/* + * Copyright (c) 2005 Reyk Floeter <reyk@vantronix.net> + * + * 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 <sys/param.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_arp.h> +#include <net/if_llc.h> +#include <net/bpf.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <arpa/inet.h> + +#include <net80211/ieee80211.h> +#include <net80211/ieee80211_radiotap.h> + +#include <pcap.h> +#include <stdio.h> +#include <string.h> + +#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 *, u_int); +int ieee80211_frame(struct ieee80211_frame *, u_int); +int ieee80211_print(struct ieee80211_frame *, u_int); +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_int flen) +{ + u_int8_t *buf, *frm; + u_int8_t *tstamp, *bintval, *capinfo; + int i; + + buf = (u_int8_t *)wh; + 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_int len) +{ + 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, len) != 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, u_int len) +{ + if (eflag) + if (ieee80211_hdr(wh)) + return (1); + + return (ieee80211_frame(wh, len)); +} + +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, len) != 0) + PRINTF("[|802.11]"); + + PRINTF("\n"); +} + +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]\n", rh->it_version); + goto out; + } + + wh = (struct ieee80211_frame *)(buf + rh_len); + if (len <= rh_len || ieee80211_print(wh, len - rh_len)) + PRINTF("[|802.11]"); + + t = (u_int8_t*)buf + sizeof(struct ieee80211_radiotap_header); + + if ((present = letoh32(rh->it_present)) == 0) + goto out; + + PRINTF(", <radiotap v%u", rh->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("\n"); +} + +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); +} |