summaryrefslogtreecommitdiff
path: root/usr.sbin/hostapd/print-802_11.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/hostapd/print-802_11.c')
-rw-r--r--usr.sbin/hostapd/print-802_11.c647
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);
+}