/****************************************************************************** * * Copyright(c) 2007 - 2017 Realtek Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * *****************************************************************************/ #define _RTW_RADIOTAP_C_ #ifdef CONFIG_WIFI_MONITOR #include #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) #include #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) #define __bf_shf(x) (__builtin_ffsll(x) - 1) /** * FIELD_PREP() - prepare a bitfield element * @_mask: shifted mask defining the field's length and position * @_val: value to put in the field * * FIELD_PREP() masks and shifts up the value. The result should * be combined with other fields of the bitfield using logical OR. */ #define FIELD_PREP(_mask, _val) \ ({ \ ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ }) #endif #define __encode_bits(w, v, field) FIELD_PREP((u##w)(field), v) #define __u16_encode_bits(v, field) __encode_bits(16, v, field) #define __le16_encode_bits(v, field) cpu_to_le16(__encode_bits(16, v, field)) #define __be16_encode_bits(v, field) cpu_to_be16(__encode_bits(16, v, field)) #define __u32_encode_bits(v, field) __encode_bits(32, v, field) #define __le32_encode_bits(v, field) cpu_to_le32(__encode_bits(32, v, field)) #define __be32_encode_bits(v, field) cpu_to_be32(__encode_bits(32, v, field)) #define __u64_encode_bits(v, field) __encode_bits(64, v, field) #define __le64_encode_bits(v, field) cpu_to_le64(__encode_bits(64, v, field)) #define __be64_encode_bits(v, field) cpu_to_be64(__encode_bits(64, v, field)) #define CHAN2FREQ(a) ((a < 14) ? (2407+5*a) : (5000+5*a)) #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0)) #define IEEE80211_RADIOTAP_ZERO_LEN_PSDU 26 #define IEEE80211_RADIOTAP_LSIG 27 #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) #define IEEE80211_RADIOTAP_TIMESTAMP 22 /* For IEEE80211_RADIOTAP_TIMESTAMP */ #define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MASK 0x000F #define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MS 0x0000 #define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US 0x0001 #define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_NS 0x0003 #define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_MASK 0x00F0 #define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_BEGIN_MDPU 0x0000 #define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_MPDU 0x0010 #define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_PPDU 0x0020 #define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ 0x0030 #define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_UNKNOWN 0x00F0 #define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_64BIT 0x00 #define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT 0x01 #define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY 0x02 #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)) /* for IEEE80211_RADIOTAP_CHANNEL */ #define IEEE80211_CHAN_GSM 0x1000 /* GSM (900 MHz) */ #define IEEE80211_CHAN_STURBO 0x2000 /* Static Turbo */ #define IEEE80211_CHAN_HALF 0x4000 /* Half channel (10 MHz wide) */ #define IEEE80211_CHAN_QUARTER 0x8000 /* Quarter channel (5 MHz wide) */ #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) #define IEEE80211_RADIOTAP_HE 23 struct ieee80211_radiotap_he { u16 data1, data2, data3, data4, data5, data6; }; enum ieee80211_radiotap_he_bits { IEEE80211_RADIOTAP_HE_DATA1_FORMAT_MASK = 3, IEEE80211_RADIOTAP_HE_DATA1_FORMAT_SU = 0, IEEE80211_RADIOTAP_HE_DATA1_FORMAT_EXT_SU = 1, IEEE80211_RADIOTAP_HE_DATA1_FORMAT_MU = 2, IEEE80211_RADIOTAP_HE_DATA1_FORMAT_TRIG = 3, IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN = 0x0004, IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN = 0x0008, IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN = 0x0010, IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN = 0x0020, IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN = 0x0040, IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN = 0x0080, IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN = 0x0100, IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN = 0x0200, IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN = 0x0400, IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE2_KNOWN = 0x0800, IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE3_KNOWN = 0x1000, IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE4_KNOWN = 0x2000, IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN = 0x4000, IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN = 0x8000, IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN = 0x0001, IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN = 0x0002, IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN = 0x0004, IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN = 0x0008, IEEE80211_RADIOTAP_HE_DATA2_TXBF_KNOWN = 0x0010, IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN = 0x0020, IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN = 0x0040, IEEE80211_RADIOTAP_HE_DATA2_MIDAMBLE_KNOWN = 0x0080, IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET = 0x3f00, IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN = 0x4000, IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC = 0x8000, IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR = 0x003f, IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE = 0x0040, IEEE80211_RADIOTAP_HE_DATA3_UL_DL = 0x0080, IEEE80211_RADIOTAP_HE_DATA3_DATA_MCS = 0x0f00, IEEE80211_RADIOTAP_HE_DATA3_DATA_DCM = 0x1000, IEEE80211_RADIOTAP_HE_DATA3_CODING = 0x2000, IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG = 0x4000, IEEE80211_RADIOTAP_HE_DATA3_STBC = 0x8000, IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE = 0x000f, IEEE80211_RADIOTAP_HE_DATA4_MU_STA_ID = 0x7ff0, IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE1 = 0x000f, IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE2 = 0x00f0, IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE3 = 0x0f00, IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE4 = 0xf000, IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC = 0x000f, IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ = 0, IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ = 1, IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ = 2, IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ = 3, IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_26T = 4, IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_52T = 5, IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_106T = 6, IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_242T = 7, IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_484T = 8, IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_996T = 9, IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_2x996T = 10, IEEE80211_RADIOTAP_HE_DATA5_GI = 0x0030, IEEE80211_RADIOTAP_HE_DATA5_GI_0_8 = 0, IEEE80211_RADIOTAP_HE_DATA5_GI_1_6 = 1, IEEE80211_RADIOTAP_HE_DATA5_GI_3_2 = 2, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE = 0x00c0, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN = 0, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X = 1, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X = 2, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X = 3, IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS = 0x0700, IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD = 0x3000, IEEE80211_RADIOTAP_HE_DATA5_TXBF = 0x4000, IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG = 0x8000, IEEE80211_RADIOTAP_HE_DATA6_NSTS = 0x000f, IEEE80211_RADIOTAP_HE_DATA6_DOPPLER = 0x0010, IEEE80211_RADIOTAP_HE_DATA6_TXOP = 0x7f00, IEEE80211_RADIOTAP_HE_DATA6_MIDAMBLE_PDCTY = 0x8000, }; #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) #define IEEE80211_RADIOTAP_VHT 21 /* For IEEE80211_RADIOTAP_VHT */ #define IEEE80211_RADIOTAP_VHT_KNOWN_STBC 0x0001 #define IEEE80211_RADIOTAP_VHT_KNOWN_TXOP_PS_NA 0x0002 #define IEEE80211_RADIOTAP_VHT_KNOWN_GI 0x0004 #define IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS 0x0008 #define IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM 0x0010 #define IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED 0x0020 #define IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH 0x0040 #define IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID 0x0080 #define IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID 0x0100 #define IEEE80211_RADIOTAP_VHT_FLAG_STBC 0x01 #define IEEE80211_RADIOTAP_VHT_FLAG_TXOP_PS_NA 0x02 #define IEEE80211_RADIOTAP_VHT_FLAG_SGI 0x04 #define IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9 0x08 #define IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM 0x10 #define IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED 0x20 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) #define IEEE80211_RADIOTAP_CODING_LDPC_USER0 0x01 #define IEEE80211_RADIOTAP_CODING_LDPC_USER1 0x02 #define IEEE80211_RADIOTAP_CODING_LDPC_USER2 0x04 #define IEEE80211_RADIOTAP_CODING_LDPC_USER3 0x08 #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) #define IEEE80211_RADIOTAP_AMPDU_STATUS 20 /* For IEEE80211_RADIOTAP_AMPDU_STATUS */ #define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001 #define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002 #define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004 #define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008 #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010 #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)) #define IEEE80211_RADIOTAP_AMPDU_EOF 0x0040 #define IEEE80211_RADIOTAP_AMPDU_EOF_KNOWN 0x0080 #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) #define IEEE80211_RADIOTAP_MCS 19 /* For IEEE80211_RADIOTAP_MCS */ #define IEEE80211_RADIOTAP_MCS_HAVE_BW 0x01 #define IEEE80211_RADIOTAP_MCS_HAVE_MCS 0x02 #define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04 #define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08 #define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10 #define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03 #define IEEE80211_RADIOTAP_MCS_BW_20 0 #define IEEE80211_RADIOTAP_MCS_BW_40 1 #define IEEE80211_RADIOTAP_MCS_BW_20L 2 #define IEEE80211_RADIOTAP_MCS_BW_20U 3 #define IEEE80211_RADIOTAP_MCS_SGI 0x04 #define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08 #define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)) #define IEEE80211_RADIOTAP_MCS_HAVE_STBC 0x20 #define IEEE80211_RADIOTAP_MCS_STBC_MASK 0x60 #define IEEE80211_RADIOTAP_MCS_STBC_1 1 #define IEEE80211_RADIOTAP_MCS_STBC_2 2 #define IEEE80211_RADIOTAP_MCS_STBC_3 3 #define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5 #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)) #define IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE 29 #define IEEE80211_RADIOTAP_VENDOR_NAMESPACE 30 #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)) #define IEEE80211_RADIOTAP_F_BADFCS 0x40 #endif static inline void _rtw_radiotap_fill_flags(struct rx_pkt_attrib *a, u8 *flags) { struct moinfo *moif = (struct moinfo *)&a->moif; if (0) *flags |= IEEE80211_RADIOTAP_F_CFP; if (0) *flags |= IEEE80211_RADIOTAP_F_SHORTPRE; if ((a->encrypt == 1) || (a->encrypt == 5)) *flags |= IEEE80211_RADIOTAP_F_WEP; if (a->mfrag) *flags |= IEEE80211_RADIOTAP_F_FRAG; if (1) *flags |= IEEE80211_RADIOTAP_F_FCS; if (0) *flags |= IEEE80211_RADIOTAP_F_DATAPAD; if (a->crc_err) *flags |= IEEE80211_RADIOTAP_F_BADFCS; /* Currently unspecified but used for short guard interval (HT) */ if (moif->u.snif_info.sgi || a->sgi) *flags |= 0x80; } sint rtw_fill_radiotap_hdr(_adapter *padapter, struct rx_pkt_attrib *a, struct rtw_recv_pkt *rx_req, u8 *buf) { #define RTAP_HDR_MAX 64 sint ret = _SUCCESS; struct moinfo *moif = (struct moinfo *)&a->moif; u8 rx_cnt = 0; int i = 0; u8 tmp_8bit = 0; u16 tmp_16bit = 0; u32 tmp_32bit = 0; u64 tmp_64bit = 0; struct sk_buff *pskb = NULL; struct ieee80211_radiotap_header *rtap_hdr = NULL; u8 *ptr = NULL; /* radiotap length (include header 8) 11G length: 36 (0x0040002f) 11N length: 11AC length: 60 (0x0070002b) */ u8 hdr_buf[RTAP_HDR_MAX] = { 0 }; u16 rt_len = 8; /* create header */ rtap_hdr = (struct ieee80211_radiotap_header *)&hdr_buf[0]; rtap_hdr->it_version = PKTHDR_RADIOTAP_VERSION; /* each antenna information */ rx_cnt = GET_HAL_RFPATH_NUM(padapter->dvobj); #if 0 if (rx_cnt > 1) { rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE) | BIT(IEEE80211_RADIOTAP_EXT); for (i = 1; i < rx_cnt; i++) { tmp_32bit = (BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | BIT(IEEE80211_RADIOTAP_LOCK_QUALITY) | BIT(IEEE80211_RADIOTAP_ANTENNA) | BIT(IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE) | BIT(IEEE80211_RADIOTAP_EXT)); _rtw_memcpy(&hdr_buf[rt_len], &tmp_32bit, 4); rt_len += 4; } tmp_32bit = (BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | BIT(IEEE80211_RADIOTAP_LOCK_QUALITY) | BIT(IEEE80211_RADIOTAP_ANTENNA)); _rtw_memcpy(&hdr_buf[rt_len], &tmp_32bit, 4); rt_len += 4; } #endif /* tsft, Required Alignment: 8 bytes */ if (0) { //(a->free_cnt) { /* TSFT + free_cnt */ rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_TSFT); if (!IS_ALIGNED(rt_len, 8)) rt_len = ((rt_len + 7) & 0xFFF8); /* Alignment */ tmp_64bit = cpu_to_le64(rx_req->mdata.freerun_cnt); _rtw_memcpy(&hdr_buf[rt_len], &tmp_64bit, 8); rt_len += 8; } /* flags */ rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_FLAGS); _rtw_radiotap_fill_flags(a, &hdr_buf[rt_len]); rt_len += 1; /* rate */ if (rx_req->mdata.rx_rate <= RTW_DATA_RATE_OFDM54) { rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_RATE); hdr_buf[rt_len] = hwrate_to_mrate(rx_req->mdata.rx_rate); rt_len += 1; } /* channel & flags, Required Alignment: 2 bytes */ if (1) { rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_CHANNEL); rt_len += (rt_len % 2); /* Alignment */ tmp_16bit = CHAN2FREQ(rtw_get_oper_ch(padapter)); _rtw_memcpy(&hdr_buf[rt_len], &tmp_16bit, 2); rt_len += 2; /* channel flags */ tmp_16bit = 0; if (WIFI_ROLE_IS_ON_24G(padapter)) tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_2GHZ); else tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_5GHZ); if (rx_req->mdata.rx_rate <= RTW_DATA_RATE_CCK11) { /* CCK */ tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_CCK); } else { /* OFDM */ tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_OFDM); } if (rtw_get_oper_bw(padapter) == CHANNEL_WIDTH_10) { /* 10Mhz Channel Width */ tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_HALF); } if (rtw_get_oper_bw(padapter) == CHANNEL_WIDTH_5) { /* 5Mhz Channel Width */ tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_QUARTER); } _rtw_memcpy(&hdr_buf[rt_len], &tmp_16bit, 2); rt_len += 2; } /* dBm Antenna Signal */ rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); hdr_buf[rt_len] = a->phy_info.recv_signal_power; rt_len += 1; #if 0 /* dBm Antenna Noise */ rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_DBM_ANTNOISE); hdr_buf[rt_len] = 0; rt_len += 1; #endif #if 0 /* Signal Quality, Required Alignment: 2 bytes */ rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_LOCK_QUALITY); if (!IS_ALIGNED(rt_len, 2)) rt_len++; hdr_buf[rt_len] = a->phy_info.signal_quality; rt_len += 2; #endif #if 0 /* Antenna */ rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_ANTENNA); hdr_buf[rt_len] = 0; /* pHalData->rf_type; */ rt_len += 1; #endif #if 0 /* RX flags, Required Alignment: 2 bytes */ rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_RX_FLAGS); tmp_16bit = 0; _rtw_memcpy(&hdr_buf[rt_len], &tmp_16bit, 2); rt_len += 2; #endif /* MCS information, Required Alignment: 1 bytes */ if (rx_req->mdata.rx_rate >= RTW_DATA_RATE_MCS0 && rx_req->mdata.rx_rate <= RTW_DATA_RATE_MCS31) { rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_MCS); /* Structure u8 known, u8 flags, u8 mcs */ /* known.bandwidth */ hdr_buf[rt_len] |= IEEE80211_RADIOTAP_MCS_HAVE_BW; if (moif->u.snif_info.ofdm_bw) hdr_buf[rt_len + 1] |= IEEE80211_RADIOTAP_MCS_BW_40; if (rx_req->mdata.bw == CHANNEL_WIDTH_40) hdr_buf[rt_len + 1] |= IEEE80211_RADIOTAP_MCS_BW_40; else hdr_buf[rt_len + 1] |= IEEE80211_RADIOTAP_MCS_BW_20; /* known.guard interval */ hdr_buf[rt_len] |= IEEE80211_RADIOTAP_MCS_HAVE_GI; if (moif->u.snif_info.sgi) { hdr_buf[rt_len + 1] |= IEEE80211_RADIOTAP_MCS_SGI; } else { hdr_buf[rt_len + 1] |= ((a->sgi & 0x01) << 2); } /* FEC Type */ hdr_buf[rt_len] |= IEEE80211_RADIOTAP_MCS_HAVE_FEC; if (moif->u.snif_info.ldpc) { hdr_buf[rt_len + 1] |= ((moif->u.snif_info.ldpc & 0x01) << 4); } else { hdr_buf[rt_len + 1] |= ((a->ldpc & 0x01) << 4); } /* STBC */ hdr_buf[rt_len] |= IEEE80211_RADIOTAP_MCS_HAVE_STBC; if (moif->u.snif_info.stbc) { hdr_buf[rt_len + 1] |= ((moif->u.snif_info.stbc & 0x03) << 5); } else { hdr_buf[rt_len + 1] |= ((a->stbc & 0x03) << 5); } /* known.MCS index */ hdr_buf[rt_len] |= IEEE80211_RADIOTAP_MCS_HAVE_MCS; /* u8 mcs */ hdr_buf[rt_len + 2] = rx_req->mdata.rx_rate - RTW_DATA_RATE_MCS0; rt_len += 3; } /* AMPDU, Required Alignment: 4 bytes */ if (rx_req->mdata.ampdu) { static u32 ref_num = 0x10000000; static u8 ppdu_cnt = 0; /* Structure u32 reference number, u16 flags, u8 delimiter CRC value, u8 reserved */ rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_AMPDU_STATUS); if (!IS_ALIGNED(rt_len, 4)) rt_len = ((rt_len + 3) & 0xFFFC); /* Alignment */ /* u32 reference number */ if (rx_req->mdata.ppdu_cnt != ppdu_cnt) { ppdu_cnt = rx_req->mdata.ppdu_cnt; ref_num += 1; } tmp_32bit = cpu_to_le32(ref_num); _rtw_memcpy(&hdr_buf[rt_len], &tmp_32bit, 4); rt_len += 4; /* u16 flags */ tmp_16bit = 0; if (0) { tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN); tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN); } if (0) { tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_AMPDU_IS_LAST); tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN); } if (0) { tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR); tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN); } if (rx_req->mdata.ampdu_end_pkt) { tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_AMPDU_EOF_KNOWN); tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_AMPDU_EOF); } _rtw_memcpy(&hdr_buf[rt_len], &tmp_16bit, 2); rt_len += 2; /* u8 delimiter CRC value, u8 reserved */ rt_len += 2; } /* VHT, Required Alignment: 2 bytes */ if (rx_req->mdata.rx_rate >= RTW_DATA_RATE_VHT_NSS1_MCS0 && rx_req->mdata.rx_rate <= RTW_DATA_RATE_VHT_NSS4_MCS9) { rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_VHT); rt_len += (rt_len % 2); /* Alignment */ /* Structure u16 known, u8 flags, u8 bandwidth, u8 mcs_nss[4], u8 coding, u8 group_id, u16 partial_aid */ tmp_16bit = 0; /* STBC */ tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_STBC); if (moif->u.snif_info.stbc) { hdr_buf[rt_len + 2] |= IEEE80211_RADIOTAP_VHT_FLAG_STBC; } else { hdr_buf[rt_len + 2] |= (a->stbc & 0x01); } /* TXOP_PS_NOT_ALLOWED */ tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_TXOP_PS_NA); if (moif->u.snif_info.vht_txop_not_allow) { hdr_buf[rt_len + 2] |= IEEE80211_RADIOTAP_VHT_FLAG_TXOP_PS_NA; } /* Guard interval */ tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_GI); if (moif->u.snif_info.sgi) { hdr_buf[rt_len + 2] |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; } else { hdr_buf[rt_len + 2] |= ((a->sgi & 0x01) << 2); } /* Short GI NSYM */ tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS); if (moif->u.snif_info.vht_nsym_dis) { hdr_buf[rt_len + 2] |= IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9; } /* LDPC extra OFDM symbol */ tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM); if (moif->u.snif_info.vht_ldpc_extra) { hdr_buf[rt_len + 2] |= IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM; } else { hdr_buf[rt_len + 2] |= ((a->ldpc & 0x01) << 4); } /* Short GI NSYM */ tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED); if (moif->u.snif_info.vht_beamformed) { hdr_buf[rt_len + 2] |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED; } /* know.Bandwidth */ tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH); /* Group ID */ tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID); /* Partial AID */ tmp_16bit |= cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID); _rtw_memcpy(&hdr_buf[rt_len], &tmp_16bit, 2); rt_len += 3; /* u8 bandwidth */ if (moif->u.snif_info.ofdm_bw) tmp_8bit = moif->u.snif_info.ofdm_bw; else tmp_8bit = rx_req->mdata.bw; switch (tmp_8bit) { case CHANNEL_WIDTH_20: hdr_buf[rt_len] |= 0; break; case CHANNEL_WIDTH_40: hdr_buf[rt_len] |= 1; break; case CHANNEL_WIDTH_80: hdr_buf[rt_len] |= 4; break; case CHANNEL_WIDTH_160: hdr_buf[rt_len] |= 11; break; default: hdr_buf[rt_len] |= 0; } rt_len += 1; /* u8 mcs_nss[4] */ if ((RTW_DATA_RATE_VHT_NSS1_MCS0 <= rx_req->mdata.rx_rate) && (rx_req->mdata.rx_rate <= RTW_DATA_RATE_VHT_NSS4_MCS9)) { /* User 0 */ /* MCS */ hdr_buf[rt_len] = cpu_to_le16 (((rx_req->mdata.rx_rate - RTW_DATA_RATE_VHT_NSS1_MCS0) % 10) << 4); /* NSS */ hdr_buf[rt_len] |= cpu_to_le16((((rx_req->mdata.rx_rate - RTW_DATA_RATE_VHT_NSS1_MCS0) / 10) + 1)); } rt_len += 4; /* u8 coding, phystat? */ hdr_buf[rt_len] = 0; rt_len += 1; /* u8 group_id */ hdr_buf[rt_len] = moif->u.snif_info.vht_group_id; rt_len += 1; /* u16 partial_aid */ tmp_16bit = cpu_to_le16(moif->u.snif_info.vht_nsts_aid); _rtw_memcpy(&hdr_buf[rt_len], &tmp_16bit, 2); rt_len += 2; } /* HE, Required Alignment: 2 bytes */ if (rx_req->mdata.rx_rate >= RTW_DATA_RATE_HE_NSS1_MCS0 && rx_req->mdata.rx_rate <= RTW_DATA_RATE_HE_NSS4_MCS11) { struct ieee80211_radiotap_he he_hdr; u8 ltf, he_gi, ss; _rtw_memset(&he_hdr, 0, sizeof(struct ieee80211_radiotap_he)); rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_HE); rt_len += (rt_len % 2); /* Alignment */ /* Structure u16 data1, data2, data3, data4, data5, data6 */ /* HE PPDU Format: 0=HE_SU, 1=HE_EXT_SU, 2=HE_MU, 3=HE_TRIG */ he_hdr.data1 |= 0x0000; he_hdr.data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN); he_hdr.data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); he_hdr.data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN); he_hdr.data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); he_hdr.data3 |= __le16_encode_bits((rx_req->mdata.rx_rate & 0xf), IEEE80211_RADIOTAP_HE_DATA3_DATA_MCS); he_hdr.data5 |= cpu_to_le16((rx_req->mdata.bw)); switch (rx_req->mdata.rx_gi_ltf) { case 0x0: he_gi = IEEE80211_RADIOTAP_HE_DATA5_GI_3_2; ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; break; case 0x1: he_gi = IEEE80211_RADIOTAP_HE_DATA5_GI_0_8; ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; break; case 0x2: he_gi = IEEE80211_RADIOTAP_HE_DATA5_GI_1_6; ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X; break; case 0x3: he_gi = IEEE80211_RADIOTAP_HE_DATA5_GI_0_8; ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X; break; case 0x4: he_gi = IEEE80211_RADIOTAP_HE_DATA5_GI_1_6; ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X; break; case 0x5: he_gi = IEEE80211_RADIOTAP_HE_DATA5_GI_0_8; ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X; break; default: he_gi = IEEE80211_RADIOTAP_HE_DATA5_GI_0_8; ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X; break; } he_hdr.data5 |= __le16_encode_bits(he_gi, IEEE80211_RADIOTAP_HE_DATA5_GI); he_hdr.data5 |= __le16_encode_bits(ltf, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); ss = cpu_to_le16(((0x70 & rx_req->mdata.rx_rate) >> 4) + 1); he_hdr.data6 |= __le16_encode_bits(ss, IEEE80211_RADIOTAP_HE_DATA6_NSTS); _rtw_memcpy(&hdr_buf[rt_len], &he_hdr, sizeof(struct ieee80211_radiotap_he)); rt_len += sizeof(struct ieee80211_radiotap_he); } /* frame timestamp, Required Alignment: 8 bytes */ if (0) { //(a->free_cnt) { rtap_hdr->it_present |= BIT(IEEE80211_RADIOTAP_TIMESTAMP); if (!IS_ALIGNED(rt_len, 8)) rt_len = ((rt_len + 7) & 0xFFF8); /* Alignment */ /* u64 timestamp */ tmp_64bit = cpu_to_le64(rx_req->mdata.freerun_cnt); _rtw_memcpy(&hdr_buf[rt_len], &tmp_64bit, 8); rt_len += 8; /* u16 accuracy */ tmp_16bit = cpu_to_le16(22); _rtw_memcpy(&hdr_buf[rt_len], &tmp_16bit, 2); rt_len += 2; /* u8 unit/position */ hdr_buf[rt_len] |= IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; rt_len += 1; /* u8 flags */ hdr_buf[rt_len] |= IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT; hdr_buf[rt_len] |= IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY; rt_len += 1; } /* each antenna information */ #if 0 if (rx_cnt > 1) { for (i = 0; i <= rx_cnt; i++) { /* dBm Antenna Signal */ hdr_buf[rt_len] = a->phy_info.rx_mimo_signal_strength[i]; rt_len += 1; /* Signal Quality */ if (!IS_ALIGNED(rt_len, 2)) rt_len++; hdr_buf[rt_len] = cpu_to_le16(a->phy_info.rx_mimo_signal_quality[i]); rt_len += 2; /* Antenna */ hdr_buf[rt_len] = i; /* pHalData->rf_type; */ rt_len += 1; } } #endif /* push to skb */ pskb = (struct sk_buff *)buf; if (skb_headroom(pskb) < rt_len) { RTW_INFO("%s:%d %s headroom is too small.\n", __FILE__, __LINE__, __func__); ret = _FAIL; return ret; } ptr = skb_push(pskb, rt_len); if (ptr) { rtap_hdr->it_len = cpu_to_le16(rt_len); rtap_hdr->it_present = cpu_to_le32(rtap_hdr->it_present); memcpy(ptr, rtap_hdr, rt_len); } else ret = _FAIL; return ret; } void rx_query_moinfo(struct rx_pkt_attrib *a, u8 *desc) { switch (a->drvinfo_sz) { case 40: _rtw_memcpy(a->moif, &desc[32], 8); break; case 48: _rtw_memcpy(a->moif, &desc[32], 12); break; case 32: /* passthrough */ default: break; } } #endif /* CONFIG_WIFI_MONITOR */