/* return rest of packet length (may be 0) or -1 on error */ static int parse_80211_header(unsigned char** buf, int len, struct packet_info* p) { struct wlan_frame* wh; int hdrlen; uint8_t* ra = NULL; uint8_t* ta = NULL; uint8_t* bssid = NULL; uint16_t fc, cap_i; if (len < 10) /* minimum frame size (CTS/ACK) */ return -1; p->wlan_mode = WLAN_MODE_UNKNOWN; wh = (struct wlan_frame*)*buf; fc = le16toh(wh->fc); p->wlan_type = (fc & WLAN_FRAME_FC_MASK); DEBUG("wlan_type %x - type %x - stype %x\n", fc, fc & WLAN_FRAME_FC_TYPE_MASK, fc & WLAN_FRAME_FC_STYPE_MASK); DEBUG("%s\n", get_packet_type_name(fc)); if (WLAN_FRAME_IS_DATA(fc)) { hdrlen = 24; if (WLAN_FRAME_IS_QOS(fc)) { hdrlen += 2; if (fc & WLAN_FRAME_FC_ORDER) hdrlen += 4; } /* AP, STA or IBSS */ if ((fc & WLAN_FRAME_FC_FROM_DS) == 0 && (fc & WLAN_FRAME_FC_TO_DS) == 0) { p->wlan_mode = WLAN_MODE_IBSS; bssid = wh->addr3; } else if ((fc & WLAN_FRAME_FC_FROM_DS) && (fc & WLAN_FRAME_FC_TO_DS)) { p->wlan_mode = WLAN_MODE_4ADDR; hdrlen += 6; if (WLAN_FRAME_IS_QOS(fc)) { uint16_t qos = le16toh(wh->u.addr4_qos_ht.qos); DEBUG("4ADDR A-MSDU %x\n", qos & WLAN_FRAME_QOS_AMSDU_PRESENT); if (qos & WLAN_FRAME_QOS_AMSDU_PRESENT) bssid = wh->addr3; // in the MSDU case BSSID is unknown } } else if (fc & WLAN_FRAME_FC_FROM_DS) { p->wlan_mode = WLAN_MODE_AP; bssid = wh->addr2; } else if (fc & WLAN_FRAME_FC_TO_DS) { p->wlan_mode = WLAN_MODE_STA; bssid = wh->addr1; } if (len < hdrlen) return -1; p->wlan_nav = le16toh(wh->duration); DEBUG("DATA NAV %d\n", p->wlan_nav); p->wlan_seqno = le16toh(wh->seq); DEBUG("DATA SEQ %d\n", p->wlan_seqno); DEBUG("A1 %s\n", ether_sprintf(wh->addr1)); DEBUG("A2 %s\n", ether_sprintf(wh->addr2)); DEBUG("A3 %s\n", ether_sprintf(wh->addr3)); if (p->wlan_mode == WLAN_MODE_4ADDR) { DEBUG("A4 %s\n", ether_sprintf(wh->u.addr4)); } DEBUG("ToDS %d FromDS %d\n", (fc & WLAN_FRAME_FC_FROM_DS) != 0, (fc & WLAN_FRAME_FC_TO_DS) != 0); ra = wh->addr1; ta = wh->addr2; /* WEP */ if (fc & WLAN_FRAME_FC_PROTECTED) p->wlan_wep = 1; if (fc & WLAN_FRAME_FC_RETRY) p->wlan_retry = 1; } else if (WLAN_FRAME_IS_CTRL(fc)) { if (p->wlan_type == WLAN_FRAME_CTS || p->wlan_type == WLAN_FRAME_ACK) hdrlen = 10; else hdrlen = 16; if (len < hdrlen) return -1; } else if (WLAN_FRAME_IS_MGMT(fc)) { hdrlen = 24; if (fc & WLAN_FRAME_FC_ORDER) hdrlen += 4; if (len < hdrlen) return -1; ra = wh->addr1; ta = wh->addr2; bssid = wh->addr3; p->wlan_seqno = le16toh(wh->seq); DEBUG("MGMT SEQ %d\n", p->wlan_seqno); if (fc & WLAN_FRAME_FC_RETRY) p->wlan_retry = 1; } else { DEBUG("!!!UNKNOWN FRAME!!!"); return -1; } p->wlan_len = len; switch (p->wlan_type) { case WLAN_FRAME_NULL: break; case WLAN_FRAME_QDATA: p->wlan_qos_class = le16toh(wh->u.qos) & WLAN_FRAME_QOS_TID_MASK; DEBUG("***QDATA %x\n", p->wlan_qos_class); break; case WLAN_FRAME_RTS: p->wlan_nav = le16toh(wh->duration); DEBUG("RTS NAV %d\n", p->wlan_nav); ra = wh->addr1; ta = wh->addr2; break; case WLAN_FRAME_CTS: p->wlan_nav = le16toh(wh->duration); DEBUG("CTS NAV %d\n", p->wlan_nav); ra = wh->addr1; break; case WLAN_FRAME_ACK: p->wlan_nav = le16toh(wh->duration); DEBUG("ACK NAV %d\n", p->wlan_nav); ra = wh->addr1; break; case WLAN_FRAME_PSPOLL: ra = wh->addr1; bssid = wh->addr1; ta = wh->addr2; break; case WLAN_FRAME_CF_END: case WLAN_FRAME_CF_END_ACK: ra = wh->addr1; ta = wh->addr2; bssid = wh->addr2; break; case WLAN_FRAME_BLKACK: case WLAN_FRAME_BLKACK_REQ: p->wlan_nav = le16toh(wh->duration); ra = wh->addr1; ta = wh->addr2; break; case WLAN_FRAME_BEACON: case WLAN_FRAME_PROBE_RESP: ; struct wlan_frame_beacon* bc = (struct wlan_frame_beacon*)(*buf + hdrlen); p->wlan_tsf = le64toh(bc->tsf); p->wlan_bintval = le16toh(bc->bintval); //DEBUG("TSF %u\n BINTVAL %u", p->wlan_tsf, p->wlan_bintval); wlan_parse_information_elements(bc->ie, len - hdrlen - sizeof(struct wlan_frame_beacon) - 4 /* FCS */, p); DEBUG("ESSID %s \n", p->wlan_essid ); DEBUG("CHAN %d \n", p->wlan_channel ); cap_i = le16toh(bc->capab); if (cap_i & WLAN_CAPAB_IBSS) p->wlan_mode = WLAN_MODE_IBSS; else if (cap_i & WLAN_CAPAB_ESS) p->wlan_mode = WLAN_MODE_AP; if (cap_i & WLAN_CAPAB_PRIVACY) p->wlan_wep = 1; break; case WLAN_FRAME_PROBE_REQ: wlan_parse_information_elements((*buf + hdrlen), len - hdrlen - 4 /* FCS */, p); p->wlan_mode = WLAN_MODE_PROBE; break; case WLAN_FRAME_ASSOC_REQ: case WLAN_FRAME_ASSOC_RESP: case WLAN_FRAME_REASSOC_REQ: case WLAN_FRAME_REASSOC_RESP: case WLAN_FRAME_DISASSOC: break; case WLAN_FRAME_AUTH: if (fc & WLAN_FRAME_FC_PROTECTED) p->wlan_wep = 1; /* no break */ case WLAN_FRAME_DEAUTH: break; case WLAN_FRAME_ACTION: break; } if (ta != NULL) { memcpy(p->wlan_src, ta, MAC_LEN); DEBUG("TA %s\n", ether_sprintf(ta)); } if (ra != NULL) { memcpy(p->wlan_dst, ra, MAC_LEN); DEBUG("RA %s\n", ether_sprintf(ra)); } if (bssid != NULL) { memcpy(p->wlan_bssid, bssid, MAC_LEN); DEBUG("BSSID %s\n", ether_sprintf(bssid)); } /* only data frames contain more info, otherwise stop parsing */ if (WLAN_FRAME_IS_DATA(p->wlan_type) && p->wlan_wep != 1) { *buf = *buf + hdrlen; return len - hdrlen; } return 0; }
/* from mac80211/util.c, modified */ int ieee80211_frame_duration(int phymode, size_t len, int rate, int short_preamble, int shortslot, int type, char qos_class, int retries) { int dur; bool erp; int sifs, slottime; static int last_was_cts; erp = ieee80211_is_erp_rate(phymode, rate); /* calculate duration (in microseconds, rounded up to next higher * integer if it includes a fractional microsecond) to send frame of * len bytes (does not include FCS) at the given rate. Duration will * also include SIFS. * * rate is in 100 kbps, so divident is multiplied by 10 in the * DIV_ROUND_UP() operations. */ DEBUG("DUR mode %d, len %d, rate %d, shortpre %d shortslot %d type %x UP %d\n", phymode, (int)len, rate, short_preamble, shortslot, type, qos_class); if (phymode == PHY_FLAG_A || erp) { DEBUG("OFDM\n"); /* * OFDM: * * N_DBPS = DATARATE x 4 * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) * (16 = SIGNAL time, 6 = tail bits) * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext * * T_SYM = 4 usec * 802.11a - 17.5.2: aSIFSTime = 16 usec * 802.11g - 19.8.4: aSIFSTime = 10 usec + * signal ext = 6 usec */ sifs = 16; /* SIFS + signal ext */ slottime = 9; dur = 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, 4 * rate); /* T_SYM x N_SYM */ } else { DEBUG("CCK\n"); /* * 802.11b or 802.11g with 802.11b compatibility: * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. * * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 * aSIFSTime = 10 usec * aPreambleLength = 144 usec or 72 usec with short preamble * aPLCPHeaderLength = 48 usec or 24 usec with short preamble */ sifs = 10; /* aSIFSTime = 10 usec */ slottime = shortslot ? 9 : 20; dur = short_preamble ? (72 + 24) : (144 + 48); dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); } if (type == WLAN_FRAME_CTS || type == WLAN_FRAME_ACK) { //TODO: also fragments DEBUG("DUR SIFS\n"); dur += sifs; } else if (type == WLAN_FRAME_BEACON) { /* TODO: which AIFS and CW should be used for beacons? */ dur += sifs + (2 * slottime); /* AIFS */ dur += (slottime * 1) / 2; /* contention */ } else if (WLAN_FRAME_IS_DATA(type) && last_was_cts) { DEBUG("DUR LAST CTS\n"); dur += sifs; } else if (type == WLAN_FRAME_QDATA) { unsigned char ac = ieee802_1d_to_ac[(unsigned char)qos_class]; dur += sifs + (ac_to_aifs[ac] * slottime); /* AIFS */ dur += get_cw_time(ac_to_cwmin[ac], ac_to_cwmax[ac], retries, slottime); DEBUG("DUR AIFS %d CWMIN %d AC %d, UP %d\n", ac_to_aifs[ac], ac_to_cwmin[ac], ac, qos_class); } else { DEBUG("DUR DIFS\n"); dur += sifs + (2 * slottime); /* DIFS */ dur += get_cw_time(4, 10, retries, slottime); } if (type == WLAN_FRAME_CTS) { DEBUG("SET CTS\n"); last_was_cts = 1; } else last_was_cts = 0; /* TODO: Add EIFS (SIFS + ACKTXTIME) to frames with CRC errors, if we can get them */ DEBUG("DUR %d\n", dur); return dur; }