1/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
2
3/*-
4 * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
5 * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
6 * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21#include <sys/cdefs.h>
22__FBSDID("$FreeBSD$");
23
24#include "opt_wlan.h"
25
26#include <sys/param.h>
27#include <sys/lock.h>
28#include <sys/mutex.h>
29#include <sys/mbuf.h>
30#include <sys/kernel.h>
31#include <sys/socket.h>
32#include <sys/systm.h>
33#include <sys/malloc.h>
34#include <sys/queue.h>
35#include <sys/taskqueue.h>
36#include <sys/bus.h>
37#include <sys/endian.h>
38
39#include <net/if.h>
40#include <net/if_var.h>
41#include <net/ethernet.h>
42#include <net/if_dl.h>
43#include <net/if_media.h>
44
45#include <net80211/ieee80211_var.h>
46#include <net80211/ieee80211_radiotap.h>
47
48#include <dev/rtwn/if_rtwnreg.h>
49#include <dev/rtwn/if_rtwnvar.h>
50
51#include <dev/rtwn/if_rtwn_debug.h>
52#include <dev/rtwn/if_rtwn_ridx.h>
53#include <dev/rtwn/if_rtwn_rx.h>
54
55#include <dev/rtwn/rtl8192c/r92c_reg.h>
56
57void
58rtwn_get_rates(struct rtwn_softc *sc, const struct ieee80211_rateset *rs,
59    const struct ieee80211_htrateset *rs_ht, uint32_t *rates_p,
60    int *maxrate_p, int basic_rates)
61{
62	uint32_t rates;
63	uint8_t ridx;
64	int i, maxrate;
65
66	/* Get rates mask. */
67	rates = 0;
68	maxrate = 0;
69
70	/* This is for 11bg */
71	for (i = 0; i < rs->rs_nrates; i++) {
72		/* Convert 802.11 rate to HW rate index. */
73		ridx = rate2ridx(IEEE80211_RV(rs->rs_rates[i]));
74		if (ridx == RTWN_RIDX_UNKNOWN)	/* Unknown rate, skip. */
75			continue;
76		if (((rs->rs_rates[i] & IEEE80211_RATE_BASIC) != 0) ||
77		    !basic_rates) {
78			rates |= 1 << ridx;
79			if (ridx > maxrate)
80				maxrate = ridx;
81		}
82	}
83
84	/* If we're doing 11n, enable 11n rates */
85	if (rs_ht != NULL && !basic_rates) {
86		for (i = 0; i < rs_ht->rs_nrates; i++) {
87			if ((rs_ht->rs_rates[i] & 0x7f) > 0xf)
88				continue;
89			/* 11n rates start at index 12 */
90			ridx = RTWN_RIDX_HT_MCS((rs_ht->rs_rates[i]) & 0xf);
91			rates |= (1 << ridx);
92
93			/* Guard against the rate table being oddly ordered */
94			if (ridx > maxrate)
95				maxrate = ridx;
96		}
97	}
98
99	RTWN_DPRINTF(sc, RTWN_DEBUG_RA,
100	    "%s: rates 0x%08X, maxrate %d\n", __func__, rates, maxrate);
101
102	if (rates_p != NULL)
103		*rates_p = rates;
104	if (maxrate_p != NULL)
105		*maxrate_p = maxrate;
106}
107
108void
109rtwn_set_basicrates(struct rtwn_softc *sc, uint32_t rates)
110{
111
112	RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X\n", __func__, rates);
113
114	rtwn_setbits_4(sc, R92C_RRSR, R92C_RRSR_RATE_BITMAP_M, rates);
115}
116
117static void
118rtwn_update_avgrssi(struct rtwn_softc *sc, struct rtwn_node *un, int8_t rssi,
119    int is_cck)
120{
121	int pwdb;
122
123	/* Convert antenna signal to percentage. */
124	if (rssi <= -100 || rssi >= 20)
125		pwdb = 0;
126	else if (rssi >= 0)
127		pwdb = 100;
128	else
129		pwdb = 100 + rssi;
130	if (is_cck) {
131		/* CCK gain is smaller than OFDM/MCS gain. */
132		pwdb += 6;
133		if (pwdb > 100)
134			pwdb = 100;
135		if (pwdb <= 14)
136			pwdb -= 4;
137		else if (pwdb <= 26)
138			pwdb -= 8;
139		else if (pwdb <= 34)
140			pwdb -= 6;
141		else if (pwdb <= 42)
142			pwdb -= 2;
143	}
144
145	if (un->avg_pwdb == -1)	/* Init. */
146		un->avg_pwdb = pwdb;
147	else if (un->avg_pwdb < pwdb)
148		un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20) + 1;
149	else
150		un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20);
151
152	RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI,
153	    "MACID %d, PWDB %d, EMA %d\n", un->id, pwdb, un->avg_pwdb);
154}
155
156static int8_t
157rtwn_get_rssi(struct rtwn_softc *sc, void *physt, int is_cck)
158{
159	int8_t rssi;
160
161	if (is_cck)
162		rssi = rtwn_get_rssi_cck(sc, physt);
163	else	/* OFDM/HT. */
164		rssi = rtwn_get_rssi_ofdm(sc, physt);
165
166	return (rssi);
167}
168
169static uint32_t
170rtwn_get_tsf_low(struct rtwn_softc *sc, int id)
171{
172	return (rtwn_read_4(sc, R92C_TSFTR(id)));
173}
174
175static uint32_t
176rtwn_get_tsf_high(struct rtwn_softc *sc, int id)
177{
178	return (rtwn_read_4(sc, R92C_TSFTR(id) + 4));
179}
180
181static void
182rtwn_get_tsf(struct rtwn_softc *sc, uint64_t *buf, int id)
183{
184	/* NB: we cannot read it at once. */
185	*buf = rtwn_get_tsf_high(sc, id);
186	*buf <<= 32;
187	*buf += rtwn_get_tsf_low(sc, id);
188}
189
190static uint64_t
191rtwn_extend_rx_tsf(struct rtwn_softc *sc,
192    const struct rtwn_rx_stat_common *stat)
193{
194	uint64_t tsft;
195	uint32_t rxdw3, tsfl, tsfl_curr;
196	int id;
197
198	rxdw3 = le32toh(stat->rxdw3);
199	tsfl = le32toh(stat->tsf_low);
200	id = MS(rxdw3, RTWN_RXDW3_BSSID01_FIT);
201
202	switch (id) {
203	case 1:
204	case 2:
205		id >>= 1;
206		tsfl_curr = rtwn_get_tsf_low(sc, id);
207		break;
208	default:
209	{
210		uint32_t tsfl0, tsfl1;
211
212		tsfl0 = rtwn_get_tsf_low(sc, 0);
213		tsfl1 = rtwn_get_tsf_low(sc, 1);
214
215		if (abs(tsfl0 - tsfl) < abs(tsfl1 - tsfl)) {
216			id = 0;
217			tsfl_curr = tsfl0;
218		} else {
219			id = 1;
220			tsfl_curr = tsfl1;
221		}
222		break;
223	}
224	}
225
226	tsft = rtwn_get_tsf_high(sc, id);
227	if (tsfl > tsfl_curr && tsfl > 0xffff0000)
228		tsft--;
229	tsft <<= 32;
230	tsft += tsfl;
231
232	return (tsft);
233}
234
235struct ieee80211_node *
236rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc)
237{
238	struct ieee80211com *ic = &sc->sc_ic;
239	struct ieee80211_node *ni;
240	struct ieee80211_frame_min *wh;
241	struct ieee80211_rx_stats rxs;
242	struct rtwn_node *un;
243	struct rtwn_rx_stat_common *stat;
244	void *physt;
245	uint32_t rxdw0;
246	int8_t rssi;
247	int cipher, infosz, is_cck, pktlen, shift;
248
249	stat = desc;
250	rxdw0 = le32toh(stat->rxdw0);
251
252	cipher = MS(rxdw0, RTWN_RXDW0_CIPHER);
253	infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8;
254	pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
255	shift = MS(rxdw0, RTWN_RXDW0_SHIFT);
256
257	wh = (struct ieee80211_frame_min *)(mtodo(m, shift + infosz));
258	if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
259	    cipher != R92C_CAM_ALGO_NONE)
260		m->m_flags |= M_WEP;
261
262	if (pktlen >= sizeof(*wh)) {
263		ni = ieee80211_find_rxnode(ic, wh);
264		if (ni != NULL && (ni->ni_flags & IEEE80211_NODE_HT))
265			m->m_flags |= M_AMPDU;
266	} else
267		ni = NULL;
268	un = RTWN_NODE(ni);
269
270	if (infosz != 0 && (rxdw0 & RTWN_RXDW0_PHYST))
271		physt = (void *)mtodo(m, shift);
272	else
273		physt = (un != NULL) ? &un->last_physt : &sc->last_physt;
274
275	bzero(&rxs, sizeof(rxs));
276	rtwn_get_rx_stats(sc, &rxs, desc, physt);
277	if (rxs.c_pktflags & IEEE80211_RX_F_AMPDU) {
278		/* Next MPDU will come without PHY info. */
279		memcpy(&sc->last_physt, physt, sizeof(sc->last_physt));
280		if (un != NULL)
281			memcpy(&un->last_physt, physt, sizeof(sc->last_physt));
282	}
283
284	/* Add some common bits. */
285	/* NB: should not happen. */
286	if (rxdw0 & RTWN_RXDW0_CRCERR)
287		rxs.c_pktflags |= IEEE80211_RX_F_FAIL_FCSCRC;
288
289	rxs.r_flags |= IEEE80211_R_TSF_START;	/* XXX undocumented */
290	rxs.r_flags |= IEEE80211_R_TSF64;
291	rxs.c_rx_tsf = rtwn_extend_rx_tsf(sc, stat);
292
293	/* Get RSSI from PHY status descriptor. */
294	is_cck = (rxs.c_pktflags & IEEE80211_RX_F_CCK) != 0;
295	rssi = rtwn_get_rssi(sc, physt, is_cck);
296
297	/* XXX TODO: we really need a rate-to-string method */
298	RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "%s: rssi %d, rate %d\n",
299	    __func__, rssi, rxs.c_rate);
300	if (un != NULL && infosz != 0 && (rxdw0 & RTWN_RXDW0_PHYST)) {
301		/* Update our average RSSI. */
302		rtwn_update_avgrssi(sc, un, rssi, is_cck);
303	}
304
305	rxs.r_flags |= IEEE80211_R_NF | IEEE80211_R_RSSI;
306	rxs.c_nf = RTWN_NOISE_FLOOR;
307	rxs.c_rssi = rssi - rxs.c_nf;
308	(void) ieee80211_add_rx_params(m, &rxs);
309
310	if (ieee80211_radiotap_active(ic)) {
311		struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap;
312
313		tap->wr_flags = rtwn_rx_radiotap_flags(sc, desc);
314		tap->wr_tsft = htole64(rxs.c_rx_tsf);
315		tap->wr_rate = rxs.c_rate;
316		tap->wr_dbm_antsignal = rssi;
317		tap->wr_dbm_antnoise = rxs.c_nf;
318	}
319
320	/* Drop PHY descriptor. */
321	m_adj(m, infosz + shift);
322
323	return (ni);
324}
325
326void
327rtwn_adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
328    const struct ieee80211_rx_stats *rxs,
329    int rssi, int nf)
330{
331	struct ieee80211vap *vap = ni->ni_vap;
332	struct rtwn_softc *sc = vap->iv_ic->ic_softc;
333	struct rtwn_vap *uvp = RTWN_VAP(vap);
334	uint64_t ni_tstamp, curr_tstamp;
335
336	uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
337
338	if (vap->iv_state == IEEE80211_S_RUN &&
339	    (subtype == IEEE80211_FC0_SUBTYPE_BEACON ||
340	    subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) {
341		ni_tstamp = le64toh(ni->ni_tstamp.tsf);
342		RTWN_LOCK(sc);
343		rtwn_get_tsf(sc, &curr_tstamp, uvp->id);
344		RTWN_UNLOCK(sc);
345
346		if (ni_tstamp >= curr_tstamp)
347			(void) ieee80211_ibss_merge(ni);
348	}
349}
350
351static uint8_t
352rtwn_get_multi_pos(const uint8_t maddr[])
353{
354	uint64_t mask = 0x00004d101df481b4;
355	uint8_t pos = 0x27;	/* initial value */
356	int i, j;
357
358	for (i = 0; i < IEEE80211_ADDR_LEN; i++)
359		for (j = (i == 0) ? 1 : 0; j < 8; j++)
360			if ((maddr[i] >> j) & 1)
361				pos ^= (mask >> (i * 8 + j - 1));
362
363	pos &= 0x3f;
364
365	return (pos);
366}
367
368static u_int
369rtwm_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
370{
371	uint32_t *mfilt = arg;
372	uint8_t pos;
373
374	pos = rtwn_get_multi_pos(LLADDR(sdl));
375	mfilt[pos / 32] |= (1 << (pos % 32));
376
377	return (1);
378}
379
380void
381rtwn_set_multi(struct rtwn_softc *sc)
382{
383	struct ieee80211com *ic = &sc->sc_ic;
384	uint32_t mfilt[2];
385
386	RTWN_ASSERT_LOCKED(sc);
387
388	/* general structure was copied from ath(4). */
389	if (ic->ic_allmulti == 0) {
390		struct ieee80211vap *vap;
391
392		/*
393		 * Merge multicast addresses to form the hardware filter.
394		 */
395		mfilt[0] = mfilt[1] = 0;
396		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
397			if_foreach_llmaddr(vap->iv_ifp, rtwm_hash_maddr, mfilt);
398	} else
399		mfilt[0] = mfilt[1] = ~0;
400
401	rtwn_write_4(sc, R92C_MAR + 0, mfilt[0]);
402	rtwn_write_4(sc, R92C_MAR + 4, mfilt[1]);
403
404	RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: MC filter %08x:%08x\n",
405	    __func__, mfilt[0], mfilt[1]);
406}
407
408static void
409rtwn_rxfilter_update_mgt(struct rtwn_softc *sc)
410{
411	uint16_t filter;
412
413	filter = 0x7f7f;
414	if (sc->bcn_vaps == 0) {	/* STA and/or MONITOR mode vaps */
415		filter &= ~(
416		    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) |
417		    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) |
418		    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ));
419	}
420	if (sc->ap_vaps == sc->nvaps - sc->mon_vaps) {	/* AP vaps only */
421		filter &= ~(
422		    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) |
423		    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP));
424	}
425	rtwn_write_2(sc, R92C_RXFLTMAP0, filter);
426}
427
428void
429rtwn_rxfilter_update(struct rtwn_softc *sc)
430{
431
432	RTWN_ASSERT_LOCKED(sc);
433
434	/* Filter for management frames. */
435	rtwn_rxfilter_update_mgt(sc);
436
437	/* Update Rx filter. */
438	rtwn_set_promisc(sc);
439}
440
441void
442rtwn_rxfilter_init(struct rtwn_softc *sc)
443{
444
445	RTWN_ASSERT_LOCKED(sc);
446
447	/* Setup multicast filter. */
448	rtwn_set_multi(sc);
449
450	/* Reject all control frames. */
451	rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000);
452
453	/* Reject all data frames. */
454	rtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000);
455
456	/* Append generic Rx filter bits. */
457	sc->rcr |= R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM |
458	    R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS |
459	    R92C_RCR_APP_ICV | R92C_RCR_APP_MIC;
460
461	/* Update dynamic Rx filter parts. */
462	rtwn_rxfilter_update(sc);
463}
464
465void
466rtwn_rxfilter_set(struct rtwn_softc *sc)
467{
468	if (!(sc->sc_flags & RTWN_RCR_LOCKED))
469		rtwn_write_4(sc, R92C_RCR, sc->rcr);
470}
471
472void
473rtwn_set_rx_bssid_all(struct rtwn_softc *sc, int enable)
474{
475
476	if (enable)
477		sc->rcr &= ~R92C_RCR_CBSSID_BCN;
478	else
479		sc->rcr |= R92C_RCR_CBSSID_BCN;
480	rtwn_rxfilter_set(sc);
481}
482
483void
484rtwn_set_promisc(struct rtwn_softc *sc)
485{
486	struct ieee80211com *ic = &sc->sc_ic;
487	uint32_t mask_all, mask_min;
488
489	RTWN_ASSERT_LOCKED(sc);
490
491	mask_all = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP;
492	mask_min = R92C_RCR_APM;
493
494	if (sc->bcn_vaps == 0)
495		mask_min |= R92C_RCR_CBSSID_BCN;
496	if (sc->ap_vaps == 0)
497		mask_min |= R92C_RCR_CBSSID_DATA;
498
499	if (ic->ic_promisc == 0 && sc->mon_vaps == 0) {
500		if (sc->bcn_vaps != 0)
501			mask_all |= R92C_RCR_CBSSID_BCN;
502		if (sc->ap_vaps != 0)	/* for Null data frames */
503			mask_all |= R92C_RCR_CBSSID_DATA;
504
505		sc->rcr &= ~mask_all;
506		sc->rcr |= mask_min;
507	} else {
508		sc->rcr &= ~mask_min;
509		sc->rcr |= mask_all;
510	}
511	rtwn_rxfilter_set(sc);
512}
513