xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/bcmwifi_radiotap.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * RadioTap utility routines for WL
3*4882a593Smuzhiyun  * This file housing the functions use by
4*4882a593Smuzhiyun  * wl driver.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 2020, Broadcom.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *      Unless you and Broadcom execute a separate written software license
9*4882a593Smuzhiyun  * agreement governing use of this software, this software is licensed to you
10*4882a593Smuzhiyun  * under the terms of the GNU General Public License version 2 (the "GPL"),
11*4882a593Smuzhiyun  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
12*4882a593Smuzhiyun  * following added to such license:
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  *      As a special exception, the copyright holders of this software give you
15*4882a593Smuzhiyun  * permission to link this software with independent modules, and to copy and
16*4882a593Smuzhiyun  * distribute the resulting executable under terms of your choice, provided that
17*4882a593Smuzhiyun  * you also meet, for each linked independent module, the terms and conditions of
18*4882a593Smuzhiyun  * the license of that module.  An independent module is a module which is not
19*4882a593Smuzhiyun  * derived from this software.  The special exception does not apply to any
20*4882a593Smuzhiyun  * modifications of the software.
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * <<Broadcom-WL-IPTag/Dual:>>
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include <bcmutils.h>
27*4882a593Smuzhiyun #include <bcmendian.h>
28*4882a593Smuzhiyun #include <bcmwifi_channels.h>
29*4882a593Smuzhiyun #include <hndd11.h>
30*4882a593Smuzhiyun #include <bcmwifi_radiotap.h>
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun const struct rtap_field rtap_parse_info[] = {
33*4882a593Smuzhiyun 	{8, 8}, /* 0:  IEEE80211_RADIOTAP_TSFT */
34*4882a593Smuzhiyun 	{1, 1}, /* 1:  IEEE80211_RADIOTAP_FLAGS */
35*4882a593Smuzhiyun 	{1, 1}, /* 2:  IEEE80211_RADIOTAP_RATE */
36*4882a593Smuzhiyun 	{4, 2}, /* 3:  IEEE80211_RADIOTAP_CHANNEL */
37*4882a593Smuzhiyun 	{2, 2}, /* 4:  IEEE80211_RADIOTAP_FHSS */
38*4882a593Smuzhiyun 	{1, 1}, /* 5:  IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
39*4882a593Smuzhiyun 	{1, 1}, /* 6:  IEEE80211_RADIOTAP_DBM_ANTNOISE */
40*4882a593Smuzhiyun 	{2, 2}, /* 7:  IEEE80211_RADIOTAP_LOCK_QUALITY */
41*4882a593Smuzhiyun 	{2, 2}, /* 8:  IEEE80211_RADIOTAP_TX_ATTENUATION */
42*4882a593Smuzhiyun 	{2, 2}, /* 9:  IEEE80211_RADIOTAP_DB_TX_ATTENUATION */
43*4882a593Smuzhiyun 	{1, 1}, /* 10: IEEE80211_RADIOTAP_DBM_TX_POWER */
44*4882a593Smuzhiyun 	{1, 1}, /* 11: IEEE80211_RADIOTAP_ANTENNA */
45*4882a593Smuzhiyun 	{1, 1}, /* 12: IEEE80211_RADIOTAP_DB_ANTSIGNAL */
46*4882a593Smuzhiyun 	{1, 1}, /* 13: IEEE80211_RADIOTAP_DB_ANTNOISE */
47*4882a593Smuzhiyun 	{0, 0}, /* 14: netbsd */
48*4882a593Smuzhiyun 	{2, 2}, /* 15: IEEE80211_RADIOTAP_TXFLAGS */
49*4882a593Smuzhiyun 	{0, 0}, /* 16: missing */
50*4882a593Smuzhiyun 	{1, 1}, /* 17: IEEE80211_RADIOTAP_RETRIES */
51*4882a593Smuzhiyun 	{8, 4}, /* 18: IEEE80211_RADIOTAP_XCHANNEL */
52*4882a593Smuzhiyun 	{3, 1}, /* 19: IEEE80211_RADIOTAP_MCS */
53*4882a593Smuzhiyun 	{8, 4}, /* 20: IEEE80211_RADIOTAP_AMPDU_STATUS */
54*4882a593Smuzhiyun 	{12, 2}, /* 21: IEEE80211_RADIOTAP_VHT */
55*4882a593Smuzhiyun 	{0, 0}, /* 22: */
56*4882a593Smuzhiyun 	{0, 0}, /* 23: */
57*4882a593Smuzhiyun 	{0, 0}, /* 24: */
58*4882a593Smuzhiyun 	{0, 0}, /* 25: */
59*4882a593Smuzhiyun 	{0, 0}, /* 26: */
60*4882a593Smuzhiyun 	{0, 0}, /* 27: */
61*4882a593Smuzhiyun 	{0, 0}, /* 28: */
62*4882a593Smuzhiyun 	{0, 0}, /* 29: IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE */
63*4882a593Smuzhiyun 	{6, 2}, /* 30: IEEE80211_RADIOTAP_VENDOR_NAMESPACE */
64*4882a593Smuzhiyun 	{0, 0}  /* 31: IEEE80211_RADIOTAP_EXT */
65*4882a593Smuzhiyun };
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun static int bitmap = 0;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun void
70*4882a593Smuzhiyun radiotap_add_vendor_ns(ieee80211_radiotap_header_t *hdr);
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun void
73*4882a593Smuzhiyun radiotap_encode_multi_rssi(monitor_pkt_rxsts_t* rxsts, ieee80211_radiotap_header_t *hdr);
74*4882a593Smuzhiyun void
75*4882a593Smuzhiyun radiotap_encode_bw_signaling(uint16 mask, struct wl_rxsts* rxsts, ieee80211_radiotap_header_t *hdr);
76*4882a593Smuzhiyun #ifdef MONITOR_DNGL_CONV
77*4882a593Smuzhiyun void radiotap_encode_alignpad(ieee80211_radiotap_header_t *hdr, uint16 pad_req);
78*4882a593Smuzhiyun #endif
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun static const uint8 brcm_oui[] =  {0x00, 0x10, 0x18};
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun static void
wl_rtapParseReset(radiotap_parse_t * rtap)83*4882a593Smuzhiyun wl_rtapParseReset(radiotap_parse_t *rtap)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun 	rtap->idx = 0;		/* reset parse index */
86*4882a593Smuzhiyun 	rtap->offset = 0;	/* reset current field pointer */
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun static void*
wl_rtapParseFindField(radiotap_parse_t * rtap,uint search_idx)90*4882a593Smuzhiyun wl_rtapParseFindField(radiotap_parse_t *rtap, uint search_idx)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	uint idx;	/* first bit index to parse */
93*4882a593Smuzhiyun 	uint32 btmap;	/* presence bitmap */
94*4882a593Smuzhiyun 	uint offset, field_offset;
95*4882a593Smuzhiyun 	uint align, len;
96*4882a593Smuzhiyun 	void *ptr = NULL;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	if (search_idx > IEEE80211_RADIOTAP_EXT)
99*4882a593Smuzhiyun 		return ptr;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	if (search_idx < rtap->idx)
102*4882a593Smuzhiyun 		wl_rtapParseReset(rtap);
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	btmap = rtap->hdr->it_present;
105*4882a593Smuzhiyun 	idx = rtap->idx;
106*4882a593Smuzhiyun 	offset = rtap->offset;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	/* loop through each field index until we get to the target idx */
109*4882a593Smuzhiyun 	while (idx <= search_idx) {
110*4882a593Smuzhiyun 		/* if field 'idx' is present, update the offset and check for a match */
111*4882a593Smuzhiyun 		if ((1 << idx) & btmap) {
112*4882a593Smuzhiyun 			/* if we hit a field for which we have no parse info
113*4882a593Smuzhiyun 			 * we need to just bail out
114*4882a593Smuzhiyun 			 */
115*4882a593Smuzhiyun 			if (rtap_parse_info[idx].align == 0)
116*4882a593Smuzhiyun 				break;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 			/* step past any alignment padding */
119*4882a593Smuzhiyun 			align = rtap_parse_info[idx].align;
120*4882a593Smuzhiyun 			len = rtap_parse_info[idx].len;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 			/* ROUNDUP */
123*4882a593Smuzhiyun 			field_offset = ((offset + (align - 1)) / align) * align;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 			/* if this field is not in the boulds of the header
126*4882a593Smuzhiyun 			 * just bail out
127*4882a593Smuzhiyun 			 */
128*4882a593Smuzhiyun 			if (field_offset + len > rtap->fields_len)
129*4882a593Smuzhiyun 				break;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 			/* did we find the field? */
132*4882a593Smuzhiyun 			if (idx == search_idx)
133*4882a593Smuzhiyun 				ptr = (uint8*)rtap->fields + field_offset;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 			/* step past this field */
136*4882a593Smuzhiyun 			offset = field_offset + len;
137*4882a593Smuzhiyun 		}
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 		idx++;
140*4882a593Smuzhiyun 	}
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	rtap->idx = idx;
143*4882a593Smuzhiyun 	rtap->offset = offset;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	return ptr;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun ratespec_t
wl_calcRspecFromRTap(uint8 * rtap_header)149*4882a593Smuzhiyun wl_calcRspecFromRTap(uint8 *rtap_header)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	ratespec_t rspec = 0;
152*4882a593Smuzhiyun 	radiotap_parse_t rtap;
153*4882a593Smuzhiyun 	uint8 rate = 0;
154*4882a593Smuzhiyun 	uint8 flags = 0;
155*4882a593Smuzhiyun 	int flags_present = FALSE;
156*4882a593Smuzhiyun 	uint8 mcs = 0;
157*4882a593Smuzhiyun 	uint8 mcs_flags = 0;
158*4882a593Smuzhiyun 	uint8 mcs_known = 0;
159*4882a593Smuzhiyun 	int mcs_present = FALSE;
160*4882a593Smuzhiyun 	void *p;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	wl_rtapParseInit(&rtap, rtap_header);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	p = wl_rtapParseFindField(&rtap, IEEE80211_RADIOTAP_FLAGS);
165*4882a593Smuzhiyun 	if (p != NULL) {
166*4882a593Smuzhiyun 		flags_present = TRUE;
167*4882a593Smuzhiyun 		flags = ((uint8*)p)[0];
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	p = wl_rtapParseFindField(&rtap, IEEE80211_RADIOTAP_RATE);
171*4882a593Smuzhiyun 	if (p != NULL)
172*4882a593Smuzhiyun 		rate = ((uint8*)p)[0];
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	p = wl_rtapParseFindField(&rtap, IEEE80211_RADIOTAP_MCS);
175*4882a593Smuzhiyun 	if (p != NULL) {
176*4882a593Smuzhiyun 		mcs_present = TRUE;
177*4882a593Smuzhiyun 		mcs_known = ((uint8*)p)[0];
178*4882a593Smuzhiyun 		mcs_flags = ((uint8*)p)[1];
179*4882a593Smuzhiyun 		mcs = ((uint8*)p)[2];
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	if (rate != 0) {
183*4882a593Smuzhiyun 		/* validate the DSSS rates 1,2,5.5,11 */
184*4882a593Smuzhiyun 		if (rate == 2 || rate == 4 || rate == 11 || rate == 22) {
185*4882a593Smuzhiyun 			rspec = LEGACY_RSPEC(rate) | WL_RSPEC_OVERRIDE_RATE;
186*4882a593Smuzhiyun 			if (flags_present && (flags & IEEE80211_RADIOTAP_F_SHORTPRE)) {
187*4882a593Smuzhiyun 				rspec |= WL_RSPEC_OVERRIDE_MODE | WL_RSPEC_SHORT_PREAMBLE;
188*4882a593Smuzhiyun 			}
189*4882a593Smuzhiyun 		}
190*4882a593Smuzhiyun 	} else if (mcs_present) {
191*4882a593Smuzhiyun 		/* validate the MCS value */
192*4882a593Smuzhiyun 		if (mcs <= 23 || mcs == 32) {
193*4882a593Smuzhiyun 			uint32 override = 0;
194*4882a593Smuzhiyun 			if (mcs_known &
195*4882a593Smuzhiyun 			    (IEEE80211_RADIOTAP_MCS_HAVE_GI |
196*4882a593Smuzhiyun 			     IEEE80211_RADIOTAP_MCS_HAVE_FMT |
197*4882a593Smuzhiyun 			     IEEE80211_RADIOTAP_MCS_HAVE_FEC)) {
198*4882a593Smuzhiyun 				override = WL_RSPEC_OVERRIDE_MODE;
199*4882a593Smuzhiyun 			}
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 			rspec = HT_RSPEC(mcs) | WL_RSPEC_OVERRIDE_RATE;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 			if ((mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_GI) &&
204*4882a593Smuzhiyun 			    (mcs_flags & IEEE80211_RADIOTAP_MCS_SGI))
205*4882a593Smuzhiyun 				rspec |= WL_RSPEC_SGI;
206*4882a593Smuzhiyun 			if ((mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_FMT) &&
207*4882a593Smuzhiyun 			    (mcs_flags & IEEE80211_RADIOTAP_MCS_FMT_GF))
208*4882a593Smuzhiyun 				rspec |= WL_RSPEC_SHORT_PREAMBLE;
209*4882a593Smuzhiyun 			if ((mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_FEC) &&
210*4882a593Smuzhiyun 			    (mcs_flags & IEEE80211_RADIOTAP_MCS_FEC_LDPC))
211*4882a593Smuzhiyun 				rspec |= WL_RSPEC_LDPC;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 			rspec |= override;
214*4882a593Smuzhiyun 		}
215*4882a593Smuzhiyun 	}
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	return rspec;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun bool
wl_rtapFlags(uint8 * rtap_header,uint8 * flags)221*4882a593Smuzhiyun wl_rtapFlags(uint8 *rtap_header, uint8* flags)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	radiotap_parse_t rtap;
224*4882a593Smuzhiyun 	void *p;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	wl_rtapParseInit(&rtap, rtap_header);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	p = wl_rtapParseFindField(&rtap, IEEE80211_RADIOTAP_FLAGS);
229*4882a593Smuzhiyun 	if (p != NULL) {
230*4882a593Smuzhiyun 		*flags = ((uint8*)p)[0];
231*4882a593Smuzhiyun 	}
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	return (p != NULL);
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun void
wl_rtapParseInit(radiotap_parse_t * rtap,uint8 * rtap_header)237*4882a593Smuzhiyun wl_rtapParseInit(radiotap_parse_t *rtap, uint8 *rtap_header)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	uint rlen;
240*4882a593Smuzhiyun 	uint32 *present_word;
241*4882a593Smuzhiyun 	struct ieee80211_radiotap_header *hdr = (struct ieee80211_radiotap_header*)rtap_header;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	bzero(rtap, sizeof(radiotap_parse_t));
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	rlen = hdr->it_len; /* total space in rtap_header */
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	/* If a precence word has the IEEE80211_RADIOTAP_EXT bit set it indicates
248*4882a593Smuzhiyun 	 * that there is another precence word.
249*4882a593Smuzhiyun 	 * Step over the presence words until we find the end of the list
250*4882a593Smuzhiyun 	 */
251*4882a593Smuzhiyun 	present_word = &hdr->it_present;
252*4882a593Smuzhiyun 	/* remaining length in header past it_present */
253*4882a593Smuzhiyun 	rlen -= sizeof(struct ieee80211_radiotap_header);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	while ((*present_word & (1<<IEEE80211_RADIOTAP_EXT)) && rlen >= 4) {
256*4882a593Smuzhiyun 		present_word++;
257*4882a593Smuzhiyun 		rlen -= 4;	/* account for 4 bytes of present_word */
258*4882a593Smuzhiyun 	}
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	rtap->hdr = hdr;
261*4882a593Smuzhiyun 	rtap->fields = (uint8*)(present_word + 1);
262*4882a593Smuzhiyun 	rtap->fields_len = rlen;
263*4882a593Smuzhiyun 	wl_rtapParseReset(rtap);
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun uint
wl_radiotap_rx(struct dot11_header * mac_header,wl_rxsts_t * rxsts,bsd_header_rx_t * bsd_header)267*4882a593Smuzhiyun wl_radiotap_rx(struct dot11_header *mac_header,	wl_rxsts_t *rxsts, bsd_header_rx_t *bsd_header)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	int channel_frequency;
270*4882a593Smuzhiyun 	uint32 channel_flags;
271*4882a593Smuzhiyun 	uint8 flags;
272*4882a593Smuzhiyun 	uint8 *cp;
273*4882a593Smuzhiyun 	uint pad_len;
274*4882a593Smuzhiyun 	uint32 field_map;
275*4882a593Smuzhiyun 	uint16 fc;
276*4882a593Smuzhiyun 	uint bsd_header_len;
277*4882a593Smuzhiyun 	uint16 ampdu_flags = 0;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	fc = LTOH16(mac_header->fc);
280*4882a593Smuzhiyun 	pad_len = 3;
281*4882a593Smuzhiyun 	field_map = WL_RADIOTAP_PRESENT_BASIC;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	if (CHSPEC_IS2G(rxsts->chanspec)) {
284*4882a593Smuzhiyun 		channel_flags = IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN;
285*4882a593Smuzhiyun 		channel_frequency = wf_channel2mhz(wf_chspec_ctlchan(rxsts->chanspec),
286*4882a593Smuzhiyun 			WF_CHAN_FACTOR_2_4_G);
287*4882a593Smuzhiyun 	} else if (CHSPEC_IS5G(rxsts->chanspec)) {
288*4882a593Smuzhiyun 		channel_flags = IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM;
289*4882a593Smuzhiyun 		channel_frequency = wf_channel2mhz(wf_chspec_ctlchan(rxsts->chanspec),
290*4882a593Smuzhiyun 			WF_CHAN_FACTOR_5_G);
291*4882a593Smuzhiyun 	} else {
292*4882a593Smuzhiyun 		channel_flags = IEEE80211_CHAN_OFDM;
293*4882a593Smuzhiyun 		channel_frequency = wf_channel2mhz(wf_chspec_ctlchan(rxsts->chanspec),
294*4882a593Smuzhiyun 			WF_CHAN_FACTOR_6_G);
295*4882a593Smuzhiyun 	}
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	if ((rxsts->nfrmtype & WL_RXS_NFRM_AMPDU_FIRST) ||
298*4882a593Smuzhiyun 		(rxsts->nfrmtype & WL_RXS_NFRM_AMPDU_SUB)) {
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 		ampdu_flags = IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN;
301*4882a593Smuzhiyun 	}
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	flags = IEEE80211_RADIOTAP_F_FCS;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	if (rxsts->preamble == WL_RXS_PREAMBLE_SHORT)
306*4882a593Smuzhiyun 		flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	if ((fc &  FC_WEP) == FC_WEP)
309*4882a593Smuzhiyun 		flags |= IEEE80211_RADIOTAP_F_WEP;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	if ((fc & FC_MOREFRAG) == FC_MOREFRAG)
312*4882a593Smuzhiyun 		flags |= IEEE80211_RADIOTAP_F_FRAG;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	if (rxsts->pkterror & WL_RXS_CRC_ERROR)
315*4882a593Smuzhiyun 		flags |= IEEE80211_RADIOTAP_F_BADFCS;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	if (rxsts->encoding == WL_RXS_ENCODING_HT)
318*4882a593Smuzhiyun 		field_map = WL_RADIOTAP_PRESENT_HT;
319*4882a593Smuzhiyun 	else if (rxsts->encoding == WL_RXS_ENCODING_VHT)
320*4882a593Smuzhiyun 		field_map = WL_RADIOTAP_PRESENT_VHT;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	bsd_header_len = sizeof(struct wl_radiotap_sna); /* start with sna size */
323*4882a593Smuzhiyun 	/* Test for signal/noise values and update length and field bitmap */
324*4882a593Smuzhiyun 	if (rxsts->signal == 0) {
325*4882a593Smuzhiyun 		field_map &= ~(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
326*4882a593Smuzhiyun 		pad_len = (pad_len - 1);
327*4882a593Smuzhiyun 		bsd_header_len--;
328*4882a593Smuzhiyun 	}
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	if (rxsts->noise == 0) {
331*4882a593Smuzhiyun 		field_map &= ~(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE);
332*4882a593Smuzhiyun 		pad_len = (pad_len - 1);
333*4882a593Smuzhiyun 		bsd_header_len--;
334*4882a593Smuzhiyun 	}
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	if (rxsts->encoding == WL_RXS_ENCODING_HT ||
337*4882a593Smuzhiyun 	    rxsts->encoding == WL_RXS_ENCODING_VHT) {
338*4882a593Smuzhiyun 		struct wl_radiotap_hdr *rtht = &bsd_header->hdr;
339*4882a593Smuzhiyun 		struct wl_radiotap_ht_tail *tail;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 		/*
342*4882a593Smuzhiyun 		 * Header length is complicated due to dynamic
343*4882a593Smuzhiyun 		 * presence of signal and noise fields
344*4882a593Smuzhiyun 		 * and padding for xchannel following
345*4882a593Smuzhiyun 		 * signal/noise/ant.
346*4882a593Smuzhiyun 		 * Start with length of wl_radiotap_ht plus
347*4882a593Smuzhiyun 		 * signal/noise/ant
348*4882a593Smuzhiyun 		 */
349*4882a593Smuzhiyun 		bsd_header_len += sizeof(struct wl_radiotap_hdr) + pad_len;
350*4882a593Smuzhiyun 		bsd_header_len += sizeof(struct wl_radiotap_xchan);
351*4882a593Smuzhiyun 		if (rxsts->nfrmtype == WL_RXS_NFRM_AMPDU_FIRST ||
352*4882a593Smuzhiyun 			rxsts->nfrmtype == WL_RXS_NFRM_AMPDU_SUB) {
353*4882a593Smuzhiyun 			bsd_header_len += sizeof(struct wl_radiotap_ampdu);
354*4882a593Smuzhiyun 		}
355*4882a593Smuzhiyun 		/* add the length of the tail end of the structure */
356*4882a593Smuzhiyun 		if (rxsts->encoding == WL_RXS_ENCODING_HT)
357*4882a593Smuzhiyun 			bsd_header_len += sizeof(struct wl_htmcs);
358*4882a593Smuzhiyun 		else if (rxsts->encoding == WL_RXS_ENCODING_VHT)
359*4882a593Smuzhiyun 			bsd_header_len += sizeof(struct wl_vhtmcs);
360*4882a593Smuzhiyun 		bzero((uint8 *)rtht, sizeof(*rtht));
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 		rtht->ieee_radiotap.it_version = 0;
363*4882a593Smuzhiyun 		rtht->ieee_radiotap.it_pad = 0;
364*4882a593Smuzhiyun 		rtht->ieee_radiotap.it_len = (uint16)HTOL16(bsd_header_len);
365*4882a593Smuzhiyun 		rtht->ieee_radiotap.it_present = HTOL32(field_map);
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 		rtht->tsft = HTOL64((uint64)rxsts->mactime);
368*4882a593Smuzhiyun 		rtht->flags = flags;
369*4882a593Smuzhiyun 		rtht->channel_freq = (uint16)HTOL16(channel_frequency);
370*4882a593Smuzhiyun 		rtht->channel_flags = (uint16)HTOL16(channel_flags);
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 		cp = bsd_header->pad;
373*4882a593Smuzhiyun 		/* add in signal/noise/ant */
374*4882a593Smuzhiyun 		if (rxsts->signal != 0) {
375*4882a593Smuzhiyun 			*cp++ = (int8)rxsts->signal;
376*4882a593Smuzhiyun 			pad_len--;
377*4882a593Smuzhiyun 		}
378*4882a593Smuzhiyun 		if (rxsts->noise != 0) {
379*4882a593Smuzhiyun 			*cp++ = (int8)rxsts->noise;
380*4882a593Smuzhiyun 			pad_len--;
381*4882a593Smuzhiyun 		}
382*4882a593Smuzhiyun 		*cp++ = (int8)rxsts->antenna;
383*4882a593Smuzhiyun 		pad_len--;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 		tail = (struct wl_radiotap_ht_tail *)(bsd_header->ht);
386*4882a593Smuzhiyun 		/* Fill in XCHANNEL */
387*4882a593Smuzhiyun 		if (CHSPEC_IS40(rxsts->chanspec)) {
388*4882a593Smuzhiyun 			if (CHSPEC_SB_UPPER(rxsts->chanspec))
389*4882a593Smuzhiyun 				channel_flags |= IEEE80211_CHAN_HT40D;
390*4882a593Smuzhiyun 			else
391*4882a593Smuzhiyun 				channel_flags |= IEEE80211_CHAN_HT40U;
392*4882a593Smuzhiyun 		} else
393*4882a593Smuzhiyun 			channel_flags |= IEEE80211_CHAN_HT20;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 		tail->xc.xchannel_flags = HTOL32(channel_flags);
396*4882a593Smuzhiyun 		tail->xc.xchannel_freq = (uint16)HTOL16(channel_frequency);
397*4882a593Smuzhiyun 		tail->xc.xchannel_channel = wf_chspec_ctlchan(rxsts->chanspec);
398*4882a593Smuzhiyun 		tail->xc.xchannel_maxpower = (17*2);
399*4882a593Smuzhiyun 		/* fill in A-mpdu Status */
400*4882a593Smuzhiyun 		tail->ampdu.ref_num = mac_header->seq;
401*4882a593Smuzhiyun 		tail->ampdu.flags = ampdu_flags;
402*4882a593Smuzhiyun 		tail->ampdu.delimiter_crc = 0;
403*4882a593Smuzhiyun 		tail->ampdu.reserved = 0;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 		if (rxsts->encoding == WL_RXS_ENCODING_HT) {
406*4882a593Smuzhiyun 			tail->u.ht.mcs_index = rxsts->mcs;
407*4882a593Smuzhiyun 			tail->u.ht.mcs_known = (IEEE80211_RADIOTAP_MCS_HAVE_BW |
408*4882a593Smuzhiyun 			                        IEEE80211_RADIOTAP_MCS_HAVE_MCS |
409*4882a593Smuzhiyun 			                        IEEE80211_RADIOTAP_MCS_HAVE_GI |
410*4882a593Smuzhiyun 			                        IEEE80211_RADIOTAP_MCS_HAVE_FEC |
411*4882a593Smuzhiyun 			                        IEEE80211_RADIOTAP_MCS_HAVE_FMT);
412*4882a593Smuzhiyun 			tail->u.ht.mcs_flags = 0;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 			switch (rxsts->htflags & WL_RXS_HTF_BW_MASK) {
415*4882a593Smuzhiyun 			case WL_RXS_HTF_20L:
416*4882a593Smuzhiyun 				tail->u.ht.mcs_flags |= IEEE80211_RADIOTAP_MCS_BW_20L;
417*4882a593Smuzhiyun 				break;
418*4882a593Smuzhiyun 			case WL_RXS_HTF_20U:
419*4882a593Smuzhiyun 				tail->u.ht.mcs_flags |= IEEE80211_RADIOTAP_MCS_BW_20U;
420*4882a593Smuzhiyun 				break;
421*4882a593Smuzhiyun 			case WL_RXS_HTF_40:
422*4882a593Smuzhiyun 				tail->u.ht.mcs_flags |= IEEE80211_RADIOTAP_MCS_BW_40;
423*4882a593Smuzhiyun 				break;
424*4882a593Smuzhiyun 			default:
425*4882a593Smuzhiyun 				tail->u.ht.mcs_flags |= IEEE80211_RADIOTAP_MCS_BW_20;
426*4882a593Smuzhiyun 				break;
427*4882a593Smuzhiyun 			}
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 			if (rxsts->htflags & WL_RXS_HTF_SGI)
430*4882a593Smuzhiyun 				tail->u.ht.mcs_flags |= IEEE80211_RADIOTAP_MCS_SGI;
431*4882a593Smuzhiyun 			if (rxsts->preamble & WL_RXS_PREAMBLE_HT_GF)
432*4882a593Smuzhiyun 				tail->u.ht.mcs_flags |= IEEE80211_RADIOTAP_MCS_FMT_GF;
433*4882a593Smuzhiyun 			if (rxsts->htflags & WL_RXS_HTF_LDPC)
434*4882a593Smuzhiyun 				tail->u.ht.mcs_flags |= IEEE80211_RADIOTAP_MCS_FEC_LDPC;
435*4882a593Smuzhiyun 		} else if (rxsts->encoding == WL_RXS_ENCODING_VHT) {
436*4882a593Smuzhiyun 			tail->u.vht.vht_known = (IEEE80211_RADIOTAP_VHT_HAVE_STBC |
437*4882a593Smuzhiyun 			                         IEEE80211_RADIOTAP_VHT_HAVE_TXOP_PS |
438*4882a593Smuzhiyun 			                         IEEE80211_RADIOTAP_VHT_HAVE_GI |
439*4882a593Smuzhiyun 			                         IEEE80211_RADIOTAP_VHT_HAVE_SGI_NSYM_DA |
440*4882a593Smuzhiyun 			                         IEEE80211_RADIOTAP_VHT_HAVE_LDPC_EXTRA |
441*4882a593Smuzhiyun 			                         IEEE80211_RADIOTAP_VHT_HAVE_BF |
442*4882a593Smuzhiyun 			                         IEEE80211_RADIOTAP_VHT_HAVE_BW |
443*4882a593Smuzhiyun 			                         IEEE80211_RADIOTAP_VHT_HAVE_GID |
444*4882a593Smuzhiyun 			                         IEEE80211_RADIOTAP_VHT_HAVE_PAID);
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 			tail->u.vht.vht_flags = (uint8)HTOL16(rxsts->vhtflags);
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 			switch (rxsts->bw) {
449*4882a593Smuzhiyun 			case WL_RXS_VHT_BW_20:
450*4882a593Smuzhiyun 				tail->u.vht.vht_bw = IEEE80211_RADIOTAP_VHT_BW_20;
451*4882a593Smuzhiyun 				break;
452*4882a593Smuzhiyun 			case WL_RXS_VHT_BW_40:
453*4882a593Smuzhiyun 				tail->u.vht.vht_bw = IEEE80211_RADIOTAP_VHT_BW_40;
454*4882a593Smuzhiyun 				break;
455*4882a593Smuzhiyun 			case WL_RXS_VHT_BW_20L:
456*4882a593Smuzhiyun 				tail->u.vht.vht_bw = IEEE80211_RADIOTAP_VHT_BW_20L;
457*4882a593Smuzhiyun 				break;
458*4882a593Smuzhiyun 			case WL_RXS_VHT_BW_20U:
459*4882a593Smuzhiyun 				tail->u.vht.vht_bw = IEEE80211_RADIOTAP_VHT_BW_20U;
460*4882a593Smuzhiyun 				break;
461*4882a593Smuzhiyun 			case WL_RXS_VHT_BW_80:
462*4882a593Smuzhiyun 				tail->u.vht.vht_bw = IEEE80211_RADIOTAP_VHT_BW_80;
463*4882a593Smuzhiyun 				break;
464*4882a593Smuzhiyun 			case WL_RXS_VHT_BW_40L:
465*4882a593Smuzhiyun 				tail->u.vht.vht_bw = IEEE80211_RADIOTAP_VHT_BW_40L;
466*4882a593Smuzhiyun 				break;
467*4882a593Smuzhiyun 			case WL_RXS_VHT_BW_40U:
468*4882a593Smuzhiyun 				tail->u.vht.vht_bw = IEEE80211_RADIOTAP_VHT_BW_40U;
469*4882a593Smuzhiyun 				break;
470*4882a593Smuzhiyun 			case WL_RXS_VHT_BW_20LL:
471*4882a593Smuzhiyun 				tail->u.vht.vht_bw = IEEE80211_RADIOTAP_VHT_BW_20LL;
472*4882a593Smuzhiyun 				break;
473*4882a593Smuzhiyun 			case WL_RXS_VHT_BW_20LU:
474*4882a593Smuzhiyun 				tail->u.vht.vht_bw = IEEE80211_RADIOTAP_VHT_BW_20LU;
475*4882a593Smuzhiyun 				break;
476*4882a593Smuzhiyun 			case WL_RXS_VHT_BW_20UL:
477*4882a593Smuzhiyun 				tail->u.vht.vht_bw = IEEE80211_RADIOTAP_VHT_BW_20UL;
478*4882a593Smuzhiyun 				break;
479*4882a593Smuzhiyun 			case WL_RXS_VHT_BW_20UU:
480*4882a593Smuzhiyun 				tail->u.vht.vht_bw = IEEE80211_RADIOTAP_VHT_BW_20UU;
481*4882a593Smuzhiyun 				break;
482*4882a593Smuzhiyun 			default:
483*4882a593Smuzhiyun 				tail->u.vht.vht_bw = IEEE80211_RADIOTAP_VHT_BW_20;
484*4882a593Smuzhiyun 				break;
485*4882a593Smuzhiyun 			}
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 			tail->u.vht.vht_mcs_nss[0] = (rxsts->mcs << 4) |
488*4882a593Smuzhiyun 				(rxsts->nss & IEEE80211_RADIOTAP_VHT_NSS);
489*4882a593Smuzhiyun 			tail->u.vht.vht_mcs_nss[1] = 0;
490*4882a593Smuzhiyun 			tail->u.vht.vht_mcs_nss[2] = 0;
491*4882a593Smuzhiyun 			tail->u.vht.vht_mcs_nss[3] = 0;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 			tail->u.vht.vht_coding = rxsts->coding;
494*4882a593Smuzhiyun 			tail->u.vht.vht_group_id = rxsts->gid;
495*4882a593Smuzhiyun 			tail->u.vht.vht_partial_aid = HTOL16(rxsts->aid);
496*4882a593Smuzhiyun 		}
497*4882a593Smuzhiyun 	} else {
498*4882a593Smuzhiyun 		struct wl_radiotap_hdr *rtl = &bsd_header->hdr;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 		/*
501*4882a593Smuzhiyun 		 * Header length is complicated due to dynamic presence of signal and noise fields
502*4882a593Smuzhiyun 		 * Start with length of wl_radiotap_legacy plus signal/noise/ant
503*4882a593Smuzhiyun 		 */
504*4882a593Smuzhiyun 		bsd_header_len = sizeof(struct wl_radiotap_hdr) + pad_len;
505*4882a593Smuzhiyun 		bzero((uint8 *)rtl, sizeof(*rtl));
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 		rtl->ieee_radiotap.it_version = 0;
508*4882a593Smuzhiyun 		rtl->ieee_radiotap.it_pad = 0;
509*4882a593Smuzhiyun 		rtl->ieee_radiotap.it_len = (uint16)HTOL16(bsd_header_len);
510*4882a593Smuzhiyun 		rtl->ieee_radiotap.it_present = HTOL32(field_map);
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 		rtl->tsft = HTOL64((uint64)rxsts->mactime);
513*4882a593Smuzhiyun 		rtl->flags = flags;
514*4882a593Smuzhiyun 		rtl->u.rate = (uint8)rxsts->datarate;
515*4882a593Smuzhiyun 		rtl->channel_freq = (uint16)HTOL16(channel_frequency);
516*4882a593Smuzhiyun 		rtl->channel_flags = (uint16)HTOL16(channel_flags);
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 		/* add in signal/noise/ant */
519*4882a593Smuzhiyun 		cp = bsd_header->pad;
520*4882a593Smuzhiyun 		if (rxsts->signal != 0)
521*4882a593Smuzhiyun 			*cp++ = (int8)rxsts->signal;
522*4882a593Smuzhiyun 		if (rxsts->noise != 0)
523*4882a593Smuzhiyun 			*cp++ = (int8)rxsts->noise;
524*4882a593Smuzhiyun 		*cp++ = (int8)rxsts->antenna;
525*4882a593Smuzhiyun 	}
526*4882a593Smuzhiyun 	return bsd_header_len;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun static int
wl_radiotap_rx_channel_frequency(wl_rxsts_t * rxsts)530*4882a593Smuzhiyun wl_radiotap_rx_channel_frequency(wl_rxsts_t *rxsts)
531*4882a593Smuzhiyun {
532*4882a593Smuzhiyun 	if (CHSPEC_IS2G(rxsts->chanspec)) {
533*4882a593Smuzhiyun 		return wf_channel2mhz(wf_chspec_ctlchan(rxsts->chanspec),
534*4882a593Smuzhiyun 			WF_CHAN_FACTOR_2_4_G);
535*4882a593Smuzhiyun 	} else if (CHSPEC_IS5G(rxsts->chanspec)) {
536*4882a593Smuzhiyun 		return wf_channel2mhz(wf_chspec_ctlchan(rxsts->chanspec),
537*4882a593Smuzhiyun 			WF_CHAN_FACTOR_5_G);
538*4882a593Smuzhiyun 	} else {
539*4882a593Smuzhiyun 		return wf_channel2mhz(wf_chspec_ctlchan(rxsts->chanspec),
540*4882a593Smuzhiyun 			WF_CHAN_FACTOR_6_G);
541*4882a593Smuzhiyun 	}
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun static uint16
wl_radiotap_rx_channel_flags(wl_rxsts_t * rxsts)545*4882a593Smuzhiyun wl_radiotap_rx_channel_flags(wl_rxsts_t *rxsts)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun 	if (CHSPEC_IS2G(rxsts->chanspec)) {
548*4882a593Smuzhiyun 		return (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN);
549*4882a593Smuzhiyun 	} else if (CHSPEC_IS5G(rxsts->chanspec)) {
550*4882a593Smuzhiyun 		return (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM);
551*4882a593Smuzhiyun 	} else {
552*4882a593Smuzhiyun 		return (IEEE80211_CHAN_OFDM);
553*4882a593Smuzhiyun 	}
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun static uint8
wl_radiotap_rx_flags(struct dot11_header * mac_header,wl_rxsts_t * rxsts)557*4882a593Smuzhiyun wl_radiotap_rx_flags(struct dot11_header *mac_header, wl_rxsts_t *rxsts)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun 	uint8 flags;
560*4882a593Smuzhiyun 	uint16 fc;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	fc = ltoh16(mac_header->fc);
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	flags = IEEE80211_RADIOTAP_F_FCS;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	if (rxsts->preamble == WL_RXS_PREAMBLE_SHORT)
567*4882a593Smuzhiyun 		flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	if (fc & FC_WEP)
570*4882a593Smuzhiyun 		flags |= IEEE80211_RADIOTAP_F_WEP;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	if (fc & FC_MOREFRAG)
573*4882a593Smuzhiyun 		flags |= IEEE80211_RADIOTAP_F_FRAG;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	return flags;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun uint
wl_radiotap_rx_legacy(struct dot11_header * mac_header,wl_rxsts_t * rxsts,ieee80211_radiotap_header_t * rtap_hdr)579*4882a593Smuzhiyun wl_radiotap_rx_legacy(struct dot11_header *mac_header,
580*4882a593Smuzhiyun 	wl_rxsts_t *rxsts, ieee80211_radiotap_header_t *rtap_hdr)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun 	int channel_frequency;
583*4882a593Smuzhiyun 	uint16 channel_flags;
584*4882a593Smuzhiyun 	uint8 flags;
585*4882a593Smuzhiyun 	uint16 rtap_len = LTOH16(rtap_hdr->it_len);
586*4882a593Smuzhiyun 	wl_radiotap_legacy_t *rtl = (wl_radiotap_legacy_t *)((uint8*)rtap_hdr + rtap_len);
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	rtap_len += sizeof(wl_radiotap_legacy_t);
589*4882a593Smuzhiyun 	rtap_hdr->it_len = HTOL16(rtap_len);
590*4882a593Smuzhiyun 	rtap_hdr->it_present |= HTOL32(WL_RADIOTAP_PRESENT_LEGACY);
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	channel_frequency = (uint16)wl_radiotap_rx_channel_frequency(rxsts);
593*4882a593Smuzhiyun 	channel_flags = wl_radiotap_rx_channel_flags(rxsts);
594*4882a593Smuzhiyun 	flags = wl_radiotap_rx_flags(mac_header, rxsts);
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	rtl->basic.tsft_l = HTOL32(rxsts->mactime);
597*4882a593Smuzhiyun 	rtl->basic.tsft_h = 0;
598*4882a593Smuzhiyun 	rtl->basic.flags = flags;
599*4882a593Smuzhiyun 	rtl->basic.rate = (uint8)rxsts->datarate;
600*4882a593Smuzhiyun 	rtl->basic.channel_freq = (uint16)HTOL16(channel_frequency);
601*4882a593Smuzhiyun 	rtl->basic.channel_flags = HTOL16(channel_flags);
602*4882a593Smuzhiyun 	rtl->basic.signal = (int8)rxsts->signal;
603*4882a593Smuzhiyun 	rtl->basic.noise = (int8)rxsts->noise;
604*4882a593Smuzhiyun 	rtl->basic.antenna = (int8)rxsts->antenna;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	return 0;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun uint
wl_radiotap_rx_ht(struct dot11_header * mac_header,wl_rxsts_t * rxsts,ieee80211_radiotap_header_t * rtap_hdr)610*4882a593Smuzhiyun wl_radiotap_rx_ht(struct dot11_header *mac_header,
611*4882a593Smuzhiyun                   wl_rxsts_t *rxsts, ieee80211_radiotap_header_t *rtap_hdr)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun 	int channel_frequency;
614*4882a593Smuzhiyun 	uint16 channel_flags;
615*4882a593Smuzhiyun 	uint32 xchannel_flags;
616*4882a593Smuzhiyun 	uint8 flags;
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	uint16 rtap_len = LTOH16(rtap_hdr->it_len);
619*4882a593Smuzhiyun 	wl_radiotap_ht_t *rtht = (wl_radiotap_ht_t *)((uint8*)rtap_hdr + rtap_len);
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	rtap_len += sizeof(wl_radiotap_ht_t);
622*4882a593Smuzhiyun 	rtap_hdr->it_len = HTOL16(rtap_len);
623*4882a593Smuzhiyun 	rtap_hdr->it_present |= HTOL32(WL_RADIOTAP_PRESENT_HT);
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	channel_frequency = (uint16)wl_radiotap_rx_channel_frequency(rxsts);
626*4882a593Smuzhiyun 	channel_flags = wl_radiotap_rx_channel_flags(rxsts);
627*4882a593Smuzhiyun 	flags = wl_radiotap_rx_flags(mac_header, rxsts);
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	rtht->basic.tsft_l = HTOL32(rxsts->mactime);
630*4882a593Smuzhiyun 	rtht->basic.tsft_h = 0;
631*4882a593Smuzhiyun 	rtht->basic.flags = flags;
632*4882a593Smuzhiyun 	rtht->basic.channel_freq = (uint16)HTOL16(channel_frequency);
633*4882a593Smuzhiyun 	rtht->basic.channel_flags = HTOL16(channel_flags);
634*4882a593Smuzhiyun 	rtht->basic.signal = (int8)rxsts->signal;
635*4882a593Smuzhiyun 	rtht->basic.noise = (int8)rxsts->noise;
636*4882a593Smuzhiyun 	rtht->basic.antenna = (uint8)rxsts->antenna;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	/* xchannel */
639*4882a593Smuzhiyun 	xchannel_flags = (uint32)channel_flags;
640*4882a593Smuzhiyun 	if (CHSPEC_IS40(rxsts->chanspec)) {
641*4882a593Smuzhiyun 		if (CHSPEC_SB_UPPER(rxsts->chanspec))
642*4882a593Smuzhiyun 			xchannel_flags |= IEEE80211_CHAN_HT40D;
643*4882a593Smuzhiyun 		else {
644*4882a593Smuzhiyun 			xchannel_flags |= IEEE80211_CHAN_HT40U;
645*4882a593Smuzhiyun 		}
646*4882a593Smuzhiyun 	} else {
647*4882a593Smuzhiyun 		xchannel_flags |= IEEE80211_CHAN_HT20;
648*4882a593Smuzhiyun 	}
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	rtht->xchannel_flags = HTOL32(xchannel_flags);
651*4882a593Smuzhiyun 	rtht->xchannel_freq = (uint16)HTOL16(channel_frequency);
652*4882a593Smuzhiyun 	rtht->xchannel_channel = wf_chspec_ctlchan(rxsts->chanspec);
653*4882a593Smuzhiyun 	rtht->xchannel_maxpower = (17*2);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	/* add standard MCS */
656*4882a593Smuzhiyun 	rtht->mcs_known = (IEEE80211_RADIOTAP_MCS_HAVE_BW |
657*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_MCS_HAVE_MCS |
658*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_MCS_HAVE_GI |
659*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_MCS_HAVE_FEC |
660*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_MCS_HAVE_FMT);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	rtht->mcs_flags = 0;
663*4882a593Smuzhiyun 	switch (rxsts->htflags & WL_RXS_HTF_BW_MASK) {
664*4882a593Smuzhiyun 		case WL_RXS_HTF_20L:
665*4882a593Smuzhiyun 			rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_BW_20L;
666*4882a593Smuzhiyun 			break;
667*4882a593Smuzhiyun 		case WL_RXS_HTF_20U:
668*4882a593Smuzhiyun 			rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_BW_20U;
669*4882a593Smuzhiyun 			break;
670*4882a593Smuzhiyun 		case WL_RXS_HTF_40:
671*4882a593Smuzhiyun 			rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_BW_40;
672*4882a593Smuzhiyun 			break;
673*4882a593Smuzhiyun 		default:
674*4882a593Smuzhiyun 			rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_BW_20;
675*4882a593Smuzhiyun 	}
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	if (rxsts->htflags & WL_RXS_HTF_SGI) {
678*4882a593Smuzhiyun 		rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_SGI;
679*4882a593Smuzhiyun 	}
680*4882a593Smuzhiyun 	if (rxsts->preamble & WL_RXS_PREAMBLE_HT_GF) {
681*4882a593Smuzhiyun 		rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_FMT_GF;
682*4882a593Smuzhiyun 	}
683*4882a593Smuzhiyun 	if (rxsts->htflags & WL_RXS_HTF_LDPC) {
684*4882a593Smuzhiyun 		rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_FEC_LDPC;
685*4882a593Smuzhiyun 	}
686*4882a593Smuzhiyun 	rtht->mcs_index = rxsts->mcs;
687*4882a593Smuzhiyun 	rtht->ampdu_flags = 0;
688*4882a593Smuzhiyun 	rtht->ampdu_delim_crc = 0;
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	rtht->ampdu_ref_num = rxsts->ampdu_counter;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	if (!(rxsts->nfrmtype & WL_RXS_NFRM_AMPDU_FIRST) &&
693*4882a593Smuzhiyun 		!(rxsts->nfrmtype & WL_RXS_NFRM_AMPDU_SUB)) {
694*4882a593Smuzhiyun 		rtht->ampdu_flags |= IEEE80211_RADIOTAP_AMPDU_IS_LAST;
695*4882a593Smuzhiyun 	} else {
696*4882a593Smuzhiyun 		rtht->ampdu_flags |= IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN;
697*4882a593Smuzhiyun 	}
698*4882a593Smuzhiyun 	return 0;
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun uint
wl_radiotap_rx_vht(struct dot11_header * mac_header,wl_rxsts_t * rxsts,ieee80211_radiotap_header_t * rtap_hdr)702*4882a593Smuzhiyun wl_radiotap_rx_vht(struct dot11_header *mac_header,
703*4882a593Smuzhiyun                    wl_rxsts_t *rxsts, ieee80211_radiotap_header_t *rtap_hdr)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun 	int channel_frequency;
706*4882a593Smuzhiyun 	uint16 channel_flags;
707*4882a593Smuzhiyun 	uint8 flags;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	uint16 rtap_len = LTOH16(rtap_hdr->it_len);
710*4882a593Smuzhiyun 	wl_radiotap_vht_t *rtvht = (wl_radiotap_vht_t *)((uint8*)rtap_hdr + rtap_len);
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	rtap_len += sizeof(wl_radiotap_vht_t);
713*4882a593Smuzhiyun 	rtap_hdr->it_len = HTOL16(rtap_len);
714*4882a593Smuzhiyun 	rtap_hdr->it_present |= HTOL32(WL_RADIOTAP_PRESENT_VHT);
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	channel_frequency = (uint16)wl_radiotap_rx_channel_frequency(rxsts);
717*4882a593Smuzhiyun 	channel_flags = wl_radiotap_rx_channel_flags(rxsts);
718*4882a593Smuzhiyun 	flags = wl_radiotap_rx_flags(mac_header, rxsts);
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	rtvht->basic.tsft_l = HTOL32(rxsts->mactime);
721*4882a593Smuzhiyun 	rtvht->basic.tsft_h = 0;
722*4882a593Smuzhiyun 	rtvht->basic.flags = flags;
723*4882a593Smuzhiyun 	rtvht->basic.channel_freq = (uint16)HTOL16(channel_frequency);
724*4882a593Smuzhiyun 	rtvht->basic.channel_flags = HTOL16(channel_flags);
725*4882a593Smuzhiyun 	rtvht->basic.signal = (int8)rxsts->signal;
726*4882a593Smuzhiyun 	rtvht->basic.noise = (int8)rxsts->noise;
727*4882a593Smuzhiyun 	rtvht->basic.antenna = (uint8)rxsts->antenna;
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 	rtvht->vht_known = (IEEE80211_RADIOTAP_VHT_HAVE_STBC |
730*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_HAVE_TXOP_PS |
731*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_HAVE_GI |
732*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_HAVE_SGI_NSYM_DA |
733*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_HAVE_LDPC_EXTRA |
734*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_HAVE_BF |
735*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_HAVE_BW |
736*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_HAVE_GID |
737*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_HAVE_PAID);
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHTF_STBC ==
740*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_STBC);
741*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHTF_TXOP_PS ==
742*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_TXOP_PS);
743*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHTF_SGI ==
744*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_SGI);
745*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHTF_SGI_NSYM_DA ==
746*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_SGI_NSYM_DA);
747*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHTF_LDPC_EXTRA ==
748*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_LDPC_EXTRA);
749*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHTF_BF ==
750*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_BF);
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	rtvht->vht_flags = (uint8)HTOL16(rxsts->vhtflags);
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHT_BW_20 ==
755*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_BW_20);
756*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHT_BW_40 ==
757*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_BW_40);
758*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHT_BW_20L ==
759*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_BW_20L);
760*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHT_BW_20U ==
761*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_BW_20U);
762*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHT_BW_80 ==
763*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_BW_80);
764*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHT_BW_40L ==
765*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_BW_40L);
766*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHT_BW_40U ==
767*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_BW_40U);
768*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHT_BW_20LL ==
769*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_BW_20LL);
770*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHT_BW_20LU ==
771*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_BW_20LU);
772*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHT_BW_20UL ==
773*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_BW_20UL);
774*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHT_BW_20UU ==
775*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_BW_20UU);
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	rtvht->vht_bw = rxsts->bw;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	rtvht->vht_mcs_nss[0] = (rxsts->mcs << 4) |
780*4882a593Smuzhiyun 		(rxsts->nss & IEEE80211_RADIOTAP_VHT_NSS);
781*4882a593Smuzhiyun 	rtvht->vht_mcs_nss[1] = 0;
782*4882a593Smuzhiyun 	rtvht->vht_mcs_nss[2] = 0;
783*4882a593Smuzhiyun 	rtvht->vht_mcs_nss[3] = 0;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	STATIC_ASSERT(WL_RXS_VHTF_CODING_LDCP ==
786*4882a593Smuzhiyun 		IEEE80211_RADIOTAP_VHT_CODING_LDPC);
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 	rtvht->vht_coding = rxsts->coding;
789*4882a593Smuzhiyun 	rtvht->vht_group_id = rxsts->gid;
790*4882a593Smuzhiyun 	rtvht->vht_partial_aid = HTOL16(rxsts->aid);
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	rtvht->ampdu_flags = 0;
793*4882a593Smuzhiyun 	rtvht->ampdu_delim_crc = 0;
794*4882a593Smuzhiyun 	rtvht->ampdu_ref_num = HTOL32(rxsts->ampdu_counter);
795*4882a593Smuzhiyun 	if (!(rxsts->nfrmtype & WL_RXS_NFRM_AMPDU_FIRST) &&
796*4882a593Smuzhiyun 		!(rxsts->nfrmtype & WL_RXS_NFRM_AMPDU_SUB)) {
797*4882a593Smuzhiyun 		rtvht->ampdu_flags |= HTOL16(IEEE80211_RADIOTAP_AMPDU_IS_LAST);
798*4882a593Smuzhiyun 	} else {
799*4882a593Smuzhiyun 		rtvht->ampdu_flags |= HTOL16(IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN);
800*4882a593Smuzhiyun 	}
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	return 0;
803*4882a593Smuzhiyun }
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun /* Rx status to radiotap conversion of HE type */
806*4882a593Smuzhiyun uint
wl_radiotap_rx_he(struct dot11_header * mac_header,wl_rxsts_t * rxsts,ieee80211_radiotap_header_t * rtap_hdr)807*4882a593Smuzhiyun wl_radiotap_rx_he(struct dot11_header *mac_header, wl_rxsts_t *rxsts,
808*4882a593Smuzhiyun 		ieee80211_radiotap_header_t *rtap_hdr)
809*4882a593Smuzhiyun {
810*4882a593Smuzhiyun 	int channel_frequency;
811*4882a593Smuzhiyun 	uint16 channel_flags;
812*4882a593Smuzhiyun 	uint8 flags;
813*4882a593Smuzhiyun 	uint16 rtap_len = LTOH16(rtap_hdr->it_len);
814*4882a593Smuzhiyun 	wl_radiotap_he_t *rthe = (wl_radiotap_he_t *)((uint8*)rtap_hdr + rtap_len);
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 	rtap_len += sizeof(wl_radiotap_he_t);
817*4882a593Smuzhiyun 	rtap_hdr->it_len = HTOL16(rtap_len);
818*4882a593Smuzhiyun 	rtap_hdr->it_present |= HTOL32(WL_RADIOTAP_PRESENT_HE);
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	channel_frequency = (uint16)wl_radiotap_rx_channel_frequency(rxsts);
821*4882a593Smuzhiyun 	channel_flags = wl_radiotap_rx_channel_flags(rxsts);
822*4882a593Smuzhiyun 	flags = wl_radiotap_rx_flags(mac_header, rxsts);
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun 	rthe->basic.tsft_l = HTOL32(rxsts->mactime);
825*4882a593Smuzhiyun 	rthe->basic.tsft_h = 0;
826*4882a593Smuzhiyun 	rthe->basic.flags = flags;
827*4882a593Smuzhiyun 	rthe->basic.channel_freq = (uint16)HTOL16(channel_frequency);
828*4882a593Smuzhiyun 	rthe->basic.channel_flags = HTOL16(channel_flags);
829*4882a593Smuzhiyun 	rthe->basic.signal = (int8)rxsts->signal;
830*4882a593Smuzhiyun 	rthe->basic.noise = (int8)rxsts->noise;
831*4882a593Smuzhiyun 	rthe->basic.antenna = (uint8)rxsts->antenna;
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	rthe->ampdu_flags = 0;
834*4882a593Smuzhiyun 	rthe->ampdu_delim_crc = 0;
835*4882a593Smuzhiyun 	rthe->ampdu_ref_num = HTOL32(rxsts->ampdu_counter);
836*4882a593Smuzhiyun 	if (!(rxsts->nfrmtype & WL_RXS_NFRM_AMPDU_FIRST) &&
837*4882a593Smuzhiyun 		!(rxsts->nfrmtype & WL_RXS_NFRM_AMPDU_SUB)) {
838*4882a593Smuzhiyun 		rthe->ampdu_flags |= HTOL16(IEEE80211_RADIOTAP_AMPDU_IS_LAST);
839*4882a593Smuzhiyun 	} else {
840*4882a593Smuzhiyun 		rthe->ampdu_flags |= HTOL16(IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN);
841*4882a593Smuzhiyun 	}
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	rthe->data1 = HTOL16(rxsts->data1);
844*4882a593Smuzhiyun 	rthe->data2 = HTOL16(rxsts->data2);
845*4882a593Smuzhiyun 	rthe->data3 = HTOL16(rxsts->data3);
846*4882a593Smuzhiyun 	rthe->data4 = HTOL16(rxsts->data4);
847*4882a593Smuzhiyun 	rthe->data5 = HTOL16(rxsts->data5);
848*4882a593Smuzhiyun 	rthe->data6 = HTOL16(rxsts->data6);
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	return 0;
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun /* Rx status to radiotap conversion of EHT type */
854*4882a593Smuzhiyun uint
wl_radiotap_rx_eht(struct dot11_header * mac_header,wl_rxsts_t * rxsts,ieee80211_radiotap_header_t * rtap_hdr)855*4882a593Smuzhiyun wl_radiotap_rx_eht(struct dot11_header *mac_header, wl_rxsts_t *rxsts,
856*4882a593Smuzhiyun 	ieee80211_radiotap_header_t *rtap_hdr)
857*4882a593Smuzhiyun {
858*4882a593Smuzhiyun 	ASSERT(!"wl_radiotap_rx_eht: not implemented!");
859*4882a593Smuzhiyun 	return 0;
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun uint16
wl_rxsts_to_rtap(monitor_pkt_rxsts_t * pkt_rxsts,void * payload,uint16 len,void * pout,uint16 pad_req)863*4882a593Smuzhiyun wl_rxsts_to_rtap(monitor_pkt_rxsts_t *pkt_rxsts, void *payload,
864*4882a593Smuzhiyun                  uint16 len, void* pout, uint16 pad_req)
865*4882a593Smuzhiyun {
866*4882a593Smuzhiyun 	uint16 rtap_len = 0;
867*4882a593Smuzhiyun 	struct dot11_header* mac_header;
868*4882a593Smuzhiyun 	uint8* p = payload;
869*4882a593Smuzhiyun 	ieee80211_radiotap_header_t* rtap_hdr = (ieee80211_radiotap_header_t*)pout;
870*4882a593Smuzhiyun 	wl_rxsts_t* rxsts;
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun 	ASSERT(p && pkt_rxsts);
873*4882a593Smuzhiyun 	rxsts = pkt_rxsts->rxsts;
874*4882a593Smuzhiyun 	rtap_hdr->it_version = 0;
875*4882a593Smuzhiyun 	rtap_hdr->it_pad = 0;
876*4882a593Smuzhiyun 	rtap_hdr->it_len = HTOL16(sizeof(*rtap_hdr));
877*4882a593Smuzhiyun 	rtap_hdr->it_present = 0;
878*4882a593Smuzhiyun 	bitmap = 0;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun #ifdef MONITOR_DNGL_CONV
881*4882a593Smuzhiyun 	if (pad_req) {
882*4882a593Smuzhiyun 		radiotap_add_vendor_ns(rtap_hdr);
883*4882a593Smuzhiyun 	}
884*4882a593Smuzhiyun #endif
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun #ifdef BCM_MON_QDBM_RSSI
887*4882a593Smuzhiyun 	/* if per-core RSSI is present, add vendor element */
888*4882a593Smuzhiyun 	if (pkt_rxsts->corenum != 0) {
889*4882a593Smuzhiyun 		radiotap_add_vendor_ns(rtap_hdr);
890*4882a593Smuzhiyun 	}
891*4882a593Smuzhiyun #endif
892*4882a593Smuzhiyun 	mac_header = (struct dot11_header *)(p);
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun 	if (rxsts->encoding == WL_RXS_ENCODING_EHT) {
895*4882a593Smuzhiyun 		wl_radiotap_rx_eht(mac_header, rxsts, rtap_hdr);
896*4882a593Smuzhiyun 	} else if (rxsts->encoding == WL_RXS_ENCODING_HE) {
897*4882a593Smuzhiyun 		wl_radiotap_rx_he(mac_header, rxsts, rtap_hdr);
898*4882a593Smuzhiyun 	} else if (rxsts->encoding == WL_RXS_ENCODING_VHT) {
899*4882a593Smuzhiyun 		wl_radiotap_rx_vht(mac_header, rxsts, rtap_hdr);
900*4882a593Smuzhiyun 	} else if (rxsts->encoding == WL_RXS_ENCODING_HT) {
901*4882a593Smuzhiyun 		wl_radiotap_rx_ht(mac_header, rxsts, rtap_hdr);
902*4882a593Smuzhiyun 	} else {
903*4882a593Smuzhiyun 		uint16 mask = ltoh16(mac_header->fc) & FC_KIND_MASK;
904*4882a593Smuzhiyun 		if (mask == FC_RTS || mask == FC_CTS) {
905*4882a593Smuzhiyun 			radiotap_add_vendor_ns(rtap_hdr);
906*4882a593Smuzhiyun 		}
907*4882a593Smuzhiyun 		wl_radiotap_rx_legacy(mac_header, rxsts, rtap_hdr);
908*4882a593Smuzhiyun 		if (mask == FC_RTS || mask == FC_CTS) {
909*4882a593Smuzhiyun 			radiotap_encode_bw_signaling(mask, rxsts, rtap_hdr);
910*4882a593Smuzhiyun 		}
911*4882a593Smuzhiyun 	}
912*4882a593Smuzhiyun #ifdef BCM_MON_QDBM_RSSI
913*4882a593Smuzhiyun 	/* if per-core RSSI is present, add vendor element */
914*4882a593Smuzhiyun 	if (pkt_rxsts->corenum != 0) {
915*4882a593Smuzhiyun 		radiotap_encode_multi_rssi(pkt_rxsts, rtap_hdr);
916*4882a593Smuzhiyun 	}
917*4882a593Smuzhiyun #endif
918*4882a593Smuzhiyun #ifdef MONITOR_DNGL_CONV
919*4882a593Smuzhiyun 	if (pad_req) {
920*4882a593Smuzhiyun 		radiotap_encode_alignpad(rtap_hdr, pad_req);
921*4882a593Smuzhiyun 	}
922*4882a593Smuzhiyun #endif
923*4882a593Smuzhiyun 	rtap_len = LTOH16(rtap_hdr->it_len);
924*4882a593Smuzhiyun 	len += rtap_len;
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun #ifndef MONITOR_DNGL_CONV
927*4882a593Smuzhiyun 	if (len > MAX_MON_PKT_SIZE) {
928*4882a593Smuzhiyun 		return 0;
929*4882a593Smuzhiyun 	}
930*4882a593Smuzhiyun 	/* copy payload */
931*4882a593Smuzhiyun 	if (!(rxsts->nfrmtype & WL_RXS_NFRM_AMSDU_FIRST) &&
932*4882a593Smuzhiyun 			!(rxsts->nfrmtype & WL_RXS_NFRM_AMSDU_SUB)) {
933*4882a593Smuzhiyun 		memcpy((uint8*)pout + rtap_len, (uint8*)p, len - rtap_len);
934*4882a593Smuzhiyun 	}
935*4882a593Smuzhiyun #endif
936*4882a593Smuzhiyun #ifdef MONITOR_DNGL_CONV
937*4882a593Smuzhiyun 	return rtap_len;
938*4882a593Smuzhiyun #else
939*4882a593Smuzhiyun 	return len;
940*4882a593Smuzhiyun #endif
941*4882a593Smuzhiyun }
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun #ifdef BCM_MON_QDBM_RSSI
944*4882a593Smuzhiyun void
radiotap_encode_multi_rssi(monitor_pkt_rxsts_t * rxsts,ieee80211_radiotap_header_t * hdr)945*4882a593Smuzhiyun radiotap_encode_multi_rssi(monitor_pkt_rxsts_t* rxsts, ieee80211_radiotap_header_t *hdr)
946*4882a593Smuzhiyun {
947*4882a593Smuzhiyun 	uint16 cur_len = LTOH16(hdr->it_len);
948*4882a593Smuzhiyun 	uint16 len = ROUNDUP(1 + rxsts->corenum * sizeof(monitor_pkt_rssi_t), 4);
949*4882a593Smuzhiyun 	int i = 0;
950*4882a593Smuzhiyun 	uint8 *vend_p = (uint8 *)hdr + cur_len;
951*4882a593Smuzhiyun 	radiotap_vendor_ns_t *vendor_ns = (radiotap_vendor_ns_t*)vend_p;
952*4882a593Smuzhiyun 	memcpy(vendor_ns->vend_oui, brcm_oui, sizeof(vendor_ns->vend_oui));
953*4882a593Smuzhiyun 	vendor_ns->sns = 1;
954*4882a593Smuzhiyun 	vendor_ns->skip_len = HTOL16(len);
955*4882a593Smuzhiyun 	vend_p += sizeof(*vendor_ns);
956*4882a593Smuzhiyun 	vend_p[0] = rxsts->corenum;
957*4882a593Smuzhiyun 	for (i = 0; i < rxsts->corenum; i++) {
958*4882a593Smuzhiyun 	  vend_p[2*i + 1] = rxsts->rxpwr[i].dBm;
959*4882a593Smuzhiyun 	  vend_p[2*i + 2] = rxsts->rxpwr[i].decidBm;
960*4882a593Smuzhiyun 	}
961*4882a593Smuzhiyun 	hdr->it_len = HTOL16(cur_len + sizeof(radiotap_vendor_ns_t) + len);
962*4882a593Smuzhiyun }
963*4882a593Smuzhiyun #endif /* BCM_CORE_RSSI */
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun #ifdef MONITOR_DNGL_CONV
966*4882a593Smuzhiyun #define AILIGN_4BYTES	(4u)
967*4882a593Smuzhiyun void
radiotap_encode_alignpad(ieee80211_radiotap_header_t * hdr,uint16 pad_req)968*4882a593Smuzhiyun radiotap_encode_alignpad(ieee80211_radiotap_header_t *hdr, uint16 pad_req)
969*4882a593Smuzhiyun {
970*4882a593Smuzhiyun 	uint16 cur_len = LTOH16(hdr->it_len);
971*4882a593Smuzhiyun 	uint8 *vend_p = (uint8 *)hdr + cur_len;
972*4882a593Smuzhiyun 	radiotap_vendor_ns_t *vendor_ns = (radiotap_vendor_ns_t*)vend_p;
973*4882a593Smuzhiyun 	uint16 len;
974*4882a593Smuzhiyun 	uint16 align_pad = 0;
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	memcpy(vendor_ns->vend_oui, brcm_oui, sizeof(vendor_ns->vend_oui));
977*4882a593Smuzhiyun 	vendor_ns->sns = WL_RADIOTAP_BRCM_PAD_SNS;
978*4882a593Smuzhiyun 	len = cur_len + sizeof(radiotap_vendor_ns_t);
979*4882a593Smuzhiyun 	if (len % AILIGN_4BYTES	!= 0) {
980*4882a593Smuzhiyun 		align_pad = (AILIGN_4BYTES - (len % AILIGN_4BYTES));
981*4882a593Smuzhiyun 	}
982*4882a593Smuzhiyun 	hdr->it_len = HTOL16(len + pad_req + align_pad);
983*4882a593Smuzhiyun 	vendor_ns->skip_len = HTOL16(pad_req + align_pad);
984*4882a593Smuzhiyun }
985*4882a593Smuzhiyun #endif /* MONITOR_DNGL_CONV */
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun void
radiotap_encode_bw_signaling(uint16 mask,struct wl_rxsts * rxsts,ieee80211_radiotap_header_t * hdr)988*4882a593Smuzhiyun radiotap_encode_bw_signaling(uint16 mask,
989*4882a593Smuzhiyun                              struct wl_rxsts* rxsts, ieee80211_radiotap_header_t *hdr)
990*4882a593Smuzhiyun {
991*4882a593Smuzhiyun 	uint16 cur_len = LTOH16(hdr->it_len);
992*4882a593Smuzhiyun 	uint8 *vend_p = (uint8 *)hdr + cur_len;
993*4882a593Smuzhiyun 	radiotap_vendor_ns_t *vendor_ns = (radiotap_vendor_ns_t  *)vend_p;
994*4882a593Smuzhiyun 	wl_radiotap_nonht_vht_t* nonht_vht;
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 	memcpy(vendor_ns->vend_oui, brcm_oui, sizeof(vendor_ns->vend_oui));
997*4882a593Smuzhiyun 	vendor_ns->sns = 0;
998*4882a593Smuzhiyun 	vendor_ns->skip_len = sizeof(wl_radiotap_nonht_vht_t);
999*4882a593Smuzhiyun 	nonht_vht = (wl_radiotap_nonht_vht_t *)(vend_p + sizeof(*vendor_ns));
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	/* VHT b/w signalling */
1002*4882a593Smuzhiyun 	bzero((uint8 *)nonht_vht, sizeof(wl_radiotap_nonht_vht_t));
1003*4882a593Smuzhiyun 	nonht_vht->len = WL_RADIOTAP_NONHT_VHT_LEN;
1004*4882a593Smuzhiyun 	nonht_vht->flags |= WL_RADIOTAP_F_NONHT_VHT_BW;
1005*4882a593Smuzhiyun 	nonht_vht->bw = (uint8)rxsts->bw_nonht;
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	if (mask == FC_RTS) {
1008*4882a593Smuzhiyun 		if (rxsts->vhtflags & WL_RXS_VHTF_DYN_BW_NONHT) {
1009*4882a593Smuzhiyun 			nonht_vht->flags |= WL_RADIOTAP_F_NONHT_VHT_DYN_BW;
1010*4882a593Smuzhiyun 		}
1011*4882a593Smuzhiyun 	}
1012*4882a593Smuzhiyun 	hdr->it_len = HTOL16(cur_len + sizeof(radiotap_vendor_ns_t) +
1013*4882a593Smuzhiyun 	                     sizeof(wl_radiotap_nonht_vht_t));
1014*4882a593Smuzhiyun }
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun void
radiotap_add_vendor_ns(ieee80211_radiotap_header_t * hdr)1017*4882a593Smuzhiyun radiotap_add_vendor_ns(ieee80211_radiotap_header_t *hdr)
1018*4882a593Smuzhiyun {
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun 	uint32 * it_present = &hdr->it_present;
1021*4882a593Smuzhiyun 	uint16 len = LTOH16(hdr->it_len);
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun 	/* if the last bitmap has a vendor ns, add a new one */
1024*4882a593Smuzhiyun 	if (it_present[bitmap] & (1 << IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) {
1025*4882a593Smuzhiyun 		it_present[bitmap] |= 1 << IEEE80211_RADIOTAP_EXT;
1026*4882a593Smuzhiyun 		bitmap++;
1027*4882a593Smuzhiyun 		/* align to 8 bytes */
1028*4882a593Smuzhiyun 		if (bitmap%2) {
1029*4882a593Smuzhiyun 			hdr->it_len = HTOL16(len + 8);
1030*4882a593Smuzhiyun 		}
1031*4882a593Smuzhiyun 		it_present[bitmap] = 1 << IEEE80211_RADIOTAP_VENDOR_NAMESPACE;
1032*4882a593Smuzhiyun 	} else {
1033*4882a593Smuzhiyun 		it_present[bitmap] |= 1 << IEEE80211_RADIOTAP_VENDOR_NAMESPACE;
1034*4882a593Smuzhiyun 	}
1035*4882a593Smuzhiyun }
1036