xref: /illumos-gate/usr/src/uts/common/io/arn/arn_recv.c (revision 2dea4eed7ad1c66ae4770263aa2911815a8b86eb)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 2008 Atheros Communications Inc.
8  *
9  * Permission to use, copy, modify, and/or distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 #include <sys/byteorder.h>
23 
24 #include "arn_core.h"
25 
26 void
27 arn_setdefantenna(struct arn_softc *sc, uint32_t antenna)
28 {
29 	/* XXX block beacon interrupts */
30 	ath9k_hw_setantenna(sc->sc_ah, antenna);
31 	sc->sc_defant = (uint8_t)antenna; /* LINT */
32 	sc->sc_rxotherant = 0;
33 }
34 
35 /*
36  *  Extend 15-bit time stamp from rx descriptor to
37  *  a full 64-bit TSF using the current h/w TSF.
38  */
39 
40 static uint64_t
41 arn_extend_tsf(struct arn_softc *sc, uint32_t rstamp)
42 {
43 	uint64_t tsf;
44 
45 	tsf = ath9k_hw_gettsf64(sc->sc_ah);
46 	if ((tsf & 0x7fff) < rstamp)
47 		tsf -= 0x8000;
48 	return ((tsf & ~0x7fff) | rstamp);
49 }
50 
51 static void
52 arn_opmode_init(struct arn_softc *sc)
53 {
54 	struct ath_hal *ah = sc->sc_ah;
55 	uint32_t rfilt;
56 	uint32_t mfilt[2];
57 	ieee80211com_t *ic = (ieee80211com_t *)sc;
58 
59 	/* configure rx filter */
60 	rfilt = arn_calcrxfilter(sc);
61 	ath9k_hw_setrxfilter(ah, rfilt);
62 
63 	/* configure bssid mask */
64 	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
65 		(void) ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
66 
67 	/* configure operational mode */
68 	ath9k_hw_setopmode(ah);
69 
70 	/* Handle any link-level address change. */
71 	(void) ath9k_hw_setmac(ah, sc->sc_myaddr);
72 
73 	/* calculate and install multicast filter */
74 	mfilt[0] = ~((uint32_t)0); /* LINT */
75 	mfilt[1] = ~((uint32_t)0); /* LINT */
76 
77 	ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
78 
79 	ARN_DBG((ARN_DBG_RECV, "arn: arn_opmode_init(): "
80 	    "mode = %d RX filter 0x%x, MC filter %08x:%08x\n",
81 	    ic->ic_opmode, rfilt, mfilt[0], mfilt[1]));
82 }
83 
84 /*
85  * Calculate the receive filter according to the
86  * operating mode and state:
87  *
88  * o always accept unicast, broadcast, and multicast traffic
89  * o maintain current state of phy error reception (the hal
90  *   may enable phy error frames for noise immunity work)
91  * o probe request frames are accepted only when operating in
92  *   hostap, adhoc, or monitor modes
93  * o enable promiscuous mode according to the interface state
94  * o accept beacons:
95  * - when operating in adhoc mode so the 802.11 layer creates
96  * node table entries for peers,
97  * - when operating in station mode for collecting rssi data when
98  * the station is otherwise quiet, or
99  * - when operating as a repeater so we see repeater-sta beacons
100  * - when scanning
101  */
102 
103 uint32_t
104 arn_calcrxfilter(struct arn_softc *sc)
105 {
106 #define	RX_FILTER_PRESERVE	(ATH9K_RX_FILTER_PHYERR |	\
107 	ATH9K_RX_FILTER_PHYRADAR)
108 
109 	uint32_t rfilt;
110 
111 	rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE) |
112 	    ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST |
113 	    ATH9K_RX_FILTER_MCAST;
114 
115 	/* If not a STA, enable processing of Probe Requests */
116 	if (sc->sc_ah->ah_opmode != ATH9K_M_STA)
117 		rfilt |= ATH9K_RX_FILTER_PROBEREQ;
118 
119 	/* Can't set HOSTAP into promiscous mode */
120 	if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) &&
121 	    (sc->sc_promisc)) ||
122 	    (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) {
123 		rfilt |= ATH9K_RX_FILTER_PROM;
124 		/* ??? To prevent from sending ACK */
125 		rfilt &= ~ATH9K_RX_FILTER_UCAST;
126 	}
127 
128 	if (sc->sc_ah->ah_opmode == ATH9K_M_STA ||
129 	    sc->sc_ah->ah_opmode == ATH9K_M_IBSS)
130 		rfilt |= ATH9K_RX_FILTER_BEACON;
131 
132 	/*
133 	 * If in HOSTAP mode, want to enable reception of PSPOLL
134 	 * frames & beacon frames
135 	 */
136 	if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP)
137 		rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL);
138 
139 	return (rfilt);
140 
141 #undef RX_FILTER_PRESERVE
142 }
143 
144 int
145 arn_startrecv(struct arn_softc *sc)
146 {
147 	struct ath_hal *ah = sc->sc_ah;
148 	struct ath_buf *bf;
149 
150 	/* clean up rx link firstly */
151 	sc->sc_rxlink = NULL;
152 
153 	/* rx descriptor link set up */
154 	bf = list_head(&sc->sc_rxbuf_list);
155 	while (bf != NULL) {
156 		arn_rx_buf_link(sc, bf);
157 		bf = list_next(&sc->sc_rxbuf_list, bf);
158 	}
159 
160 	bf = list_head(&sc->sc_rxbuf_list);
161 
162 	ath9k_hw_putrxbuf(ah, bf->bf_daddr);
163 	ath9k_hw_rxena(ah);
164 
165 	arn_opmode_init(sc);
166 	ath9k_hw_startpcureceive(ah);
167 
168 	return (0);
169 }
170 
171 boolean_t
172 arn_stoprecv(struct arn_softc *sc)
173 {
174 	struct ath_hal *ah = sc->sc_ah;
175 	boolean_t stopped;
176 
177 	ath9k_hw_stoppcurecv(ah);
178 	ath9k_hw_setrxfilter(ah, 0);
179 	stopped = ath9k_hw_stopdmarecv(ah);
180 
181 	/* 3ms is long enough for 1 frame ??? */
182 	drv_usecwait(3000);
183 
184 	sc->sc_rxlink = NULL;
185 
186 	return (stopped);
187 }
188 
189 /*
190  * Intercept management frames to collect beacon rssi data
191  * and to do ibss merges.
192  */
193 
194 void
195 arn_recv_mgmt(struct ieee80211com *ic, mblk_t *mp, struct ieee80211_node *in,
196     int subtype, int rssi, uint32_t rstamp)
197 {
198 	struct arn_softc *sc = (struct arn_softc *)ic;
199 
200 	/*
201 	 * Call up first so subsequent work can use information
202 	 * potentially stored in the node (e.g. for ibss merge).
203 	 */
204 	sc->sc_recv_mgmt(ic, mp, in, subtype, rssi, rstamp);
205 
206 	ARN_LOCK(sc);
207 	switch (subtype) {
208 	case IEEE80211_FC0_SUBTYPE_BEACON:
209 		/* update rssi statistics */
210 		if (sc->sc_bsync && in == ic->ic_bss &&
211 		    ic->ic_state == IEEE80211_S_RUN) {
212 			/*
213 			 * Resync beacon timers using the tsf of the beacon
214 			 * frame we just received.
215 			 */
216 			arn_beacon_config(sc);
217 		}
218 		/* FALLTHRU */
219 	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
220 		if (ic->ic_opmode == IEEE80211_M_IBSS &&
221 		    ic->ic_state == IEEE80211_S_RUN &&
222 		    (in->in_capinfo & IEEE80211_CAPINFO_IBSS)) {
223 			uint64_t tsf = arn_extend_tsf(sc, rstamp);
224 			/*
225 			 * Handle ibss merge as needed; check the tsf on the
226 			 * frame before attempting the merge.  The 802.11 spec
227 			 * says the station should change it's bssid to match
228 			 * the oldest station with the same ssid, where oldest
229 			 * is determined by the tsf.  Note that hardware
230 			 * reconfiguration happens through callback to
231 			 * ath_newstate as the state machine will go from
232 			 * RUN -> RUN when this happens.
233 			 */
234 			if (LE_64(in->in_tstamp.tsf) >= tsf) {
235 				ARN_DBG((ARN_DBG_BEACON, "arn: arn_recv_mgmt:"
236 				    "ibss merge, rstamp %u tsf %lu "
237 				    "tstamp %lu\n", rstamp, tsf,
238 				    in->in_tstamp.tsf));
239 				ARN_UNLOCK(sc);
240 				ARN_DBG((ARN_DBG_BEACON, "arn_recv_mgmt():"
241 				    "ibss_merge: rstamp=%d in_tstamp=%02x %02x"
242 				    " %02x %02x %02x %02x %02x %02x\n",
243 				    rstamp, in->in_tstamp.data[0],
244 				    in->in_tstamp.data[1],
245 				    in->in_tstamp.data[2],
246 				    in->in_tstamp.data[3],
247 				    in->in_tstamp.data[4],
248 				    in->in_tstamp.data[5],
249 				    in->in_tstamp.data[6],
250 				    in->in_tstamp.data[7]));
251 				(void) ieee80211_ibss_merge(in);
252 				return;
253 			}
254 		}
255 		break;
256 	}
257 	ARN_UNLOCK(sc);
258 }
259 
260 static void
261 arn_printrxbuf(struct ath_buf *bf, int32_t done)
262 {
263 	struct ath_desc *ds = bf->bf_desc;
264 	const struct ath_rx_status *rs = &ds->ds_rxstat;
265 
266 	ARN_DBG((ARN_DBG_RECV, "arn: R (%p %p) %08x %08x %08x "
267 	    "%08x %08x %08x %c\n",
268 	    ds, bf->bf_daddr,
269 	    ds->ds_link, ds->ds_data,
270 	    ds->ds_ctl0, ds->ds_ctl1,
271 	    ds->ds_hw[0], ds->ds_hw[1],
272 	    !done ? ' ' : (rs->rs_status == 0) ? '*' : '!'));
273 }
274 
275 static void
276 arn_rx_handler(struct arn_softc *sc)
277 {
278 #define	PA2DESC(_sc, _pa) \
279 		((struct ath_desc *)((caddr_t)(_sc)->sc_desc + \
280 		((_pa) - (_sc)->sc_desc_dma.cookie.dmac_address)))
281 
282 	ieee80211com_t *ic = (ieee80211com_t *)sc;
283 	struct ath_buf *bf;
284 	struct ath_hal *ah = sc->sc_ah;
285 	struct ath_desc *ds;
286 	struct ath_rx_status *rs;
287 	mblk_t *rx_mp;
288 	struct ieee80211_frame *wh;
289 	int32_t len, ngood, loop = 1;
290 	uint8_t phyerr;
291 	int status;
292 	struct ieee80211_node *in;
293 	uint32_t cur_signal;
294 	uint32_t subtype;
295 
296 	ngood = 0;
297 	do {
298 		mutex_enter(&sc->sc_rxbuflock);
299 		bf = list_head(&sc->sc_rxbuf_list);
300 		if (bf == NULL) {
301 			ARN_DBG((ARN_DBG_RECV, "arn: arn_rx_handler(): "
302 			    "no buffer\n"));
303 			mutex_exit(&sc->sc_rxbuflock);
304 			break;
305 		}
306 		ASSERT(bf->bf_dma.cookie.dmac_address != NULL);
307 		ds = bf->bf_desc;
308 		if (ds->ds_link == bf->bf_daddr) {
309 			/*
310 			 * Never process the self-linked entry at the end,
311 			 * this may be met at heavy load.
312 			 */
313 			mutex_exit(&sc->sc_rxbuflock);
314 			break;
315 		}
316 
317 		/*
318 		 * Must provide the virtual address of the current
319 		 * descriptor, the physical address, and the virtual
320 		 * address of the next descriptor in the h/w chain.
321 		 * This allows the HAL to look ahead to see if the
322 		 * hardware is done with a descriptor by checking the
323 		 * done bit in the following descriptor and the address
324 		 * of the current descriptor the DMA engine is working
325 		 * on.  All this is necessary because of our use of
326 		 * a self-linked list to avoid rx overruns.
327 		 */
328 		status = ath9k_hw_rxprocdesc(ah, ds,
329 		    bf->bf_daddr,
330 		    PA2DESC(sc, ds->ds_link), 0);
331 		if (status == EINPROGRESS) {
332 			mutex_exit(&sc->sc_rxbuflock);
333 			break;
334 		}
335 		list_remove(&sc->sc_rxbuf_list, bf);
336 		mutex_exit(&sc->sc_rxbuflock);
337 
338 		rs = &ds->ds_rxstat;
339 		if (rs->rs_status != 0) {
340 			if (rs->rs_status & ATH9K_RXERR_CRC) {
341 				sc->sc_stats.ast_rx_crcerr++;
342 			}
343 			if (rs->rs_status & ATH9K_RXERR_FIFO) {
344 				sc->sc_stats.ast_rx_fifoerr++;
345 			}
346 			if (rs->rs_status & ATH9K_RXERR_DECRYPT) {
347 				sc->sc_stats.ast_rx_badcrypt++;
348 			}
349 			if (rs->rs_status & ATH9K_RXERR_PHY) {
350 				sc->sc_stats.ast_rx_phyerr++;
351 				phyerr = rs->rs_phyerr & 0x1f;
352 				sc->sc_stats.ast_rx_phy[phyerr]++;
353 			}
354 			goto rx_next;
355 		}
356 		len = rs->rs_datalen;
357 
358 		/* less than sizeof(struct ieee80211_frame) */
359 		if (len < 20) {
360 			sc->sc_stats.ast_rx_tooshort++;
361 			goto rx_next;
362 		}
363 
364 		if ((rx_mp = allocb(sc->sc_dmabuf_size, BPRI_MED)) == NULL) {
365 			arn_problem("arn: arn_rx_handler(): "
366 			    "allocing mblk buffer failed.\n");
367 			return;
368 		}
369 
370 		ARN_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORCPU);
371 		bcopy(bf->bf_dma.mem_va, rx_mp->b_rptr, len);
372 
373 		rx_mp->b_wptr += len;
374 		wh = (struct ieee80211_frame *)rx_mp->b_rptr;
375 
376 		if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
377 		    IEEE80211_FC0_TYPE_CTL) {
378 			/*
379 			 * Ignore control frame received in promisc mode.
380 			 */
381 			freemsg(rx_mp);
382 			goto rx_next;
383 		}
384 
385 		/* Remove the CRC at the end of IEEE80211 frame */
386 		rx_mp->b_wptr -= IEEE80211_CRC_LEN;
387 
388 		/*
389 		 * Locate the node for sender, track state, and then
390 		 * pass the (referenced) node up to the 802.11 layer
391 		 * for its use.
392 		 */
393 		in = ieee80211_find_rxnode(ic, wh);
394 
395 		if (ds->ds_rxstat.rs_rssi < 0)
396 			ds->ds_rxstat.rs_rssi = 0;
397 
398 		if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
399 		    IEEE80211_FC0_TYPE_MGT) {
400 			subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
401 			/* Update Beacon RSSI, this is used by ANI. */
402 			if (subtype == IEEE80211_FC0_SUBTYPE_BEACON)
403 				sc->sc_halstats.ns_avgbrssi =
404 				    ds->ds_rxstat.rs_rssi;
405 		}
406 
407 #ifdef DEBUG
408 		arn_printrxbuf(bf, status == 0);
409 #endif
410 
411 		/*
412 		 * signal 13-15 DLADM_WLAN_STRENGTH_EXCELLENT
413 		 * signal 10-12 DLADM_WLAN_STRENGTH_VERY_GOOD
414 		 * signal 6-9   DLADM_WLAN_STRENGTH_GOOD
415 		 * signal 3-5   DLADM_WLAN_STRENGTH_WEAK
416 		 * signal 0-2   DLADM_WLAN_STRENGTH_VERY_WEAK
417 		 */
418 		if (rs->rs_rssi == 0)
419 			cur_signal = 0;
420 		else if (rs->rs_rssi >= 45)
421 			cur_signal = MAX_RSSI;
422 		else
423 			cur_signal = rs->rs_rssi * MAX_RSSI / 45 + 1;
424 
425 		/*
426 		 * Send the frame to net80211 for processing
427 		 */
428 		if (cur_signal <= 2 && ic->ic_state == IEEE80211_S_RUN)
429 			(void) ieee80211_input(ic, rx_mp, in,
430 			    (rs->rs_rssi + 10), rs->rs_tstamp);
431 		else
432 			(void) ieee80211_input(ic, rx_mp, in,
433 			    rs->rs_rssi, rs->rs_tstamp);
434 
435 		/* release node */
436 		ieee80211_free_node(in);
437 
438 		/*
439 		 * Arrange to update the last rx timestamp only for
440 		 * frames from our ap when operating in station mode.
441 		 * This assumes the rx key is always setup when associated.
442 		 */
443 		if (ic->ic_opmode == IEEE80211_M_STA &&
444 		    rs->rs_keyix != ATH9K_RXKEYIX_INVALID) {
445 			ngood++;
446 		}
447 
448 		/*
449 		 * change the default rx antenna if rx diversity chooses the
450 		 * other antenna 3 times in a row.
451 		 */
452 		if (sc->sc_defant != ds->ds_rxstat.rs_antenna) {
453 			if (++sc->sc_rxotherant >= 3) {
454 				ath9k_hw_setantenna(sc->sc_ah,
455 				    ds->ds_rxstat.rs_antenna);
456 				sc->sc_defant = ds->ds_rxstat.rs_antenna;
457 				sc->sc_rxotherant = 0;
458 			}
459 		} else {
460 			sc->sc_rxotherant = 0;
461 		}
462 
463 rx_next:
464 		mutex_enter(&sc->sc_rxbuflock);
465 		list_insert_tail(&sc->sc_rxbuf_list, bf);
466 		mutex_exit(&sc->sc_rxbuflock);
467 		arn_rx_buf_link(sc, bf);
468 	} while (loop);
469 
470 	if (ngood)
471 		sc->sc_lastrx = ath9k_hw_gettsf64(ah);
472 
473 #undef PA2DESC
474 }
475 
476 uint_t
477 arn_softint_handler(caddr_t data)
478 {
479 	struct arn_softc *sc = (struct arn_softc *)data;
480 
481 	ARN_LOCK(sc);
482 
483 	if (sc->sc_rx_pend) {
484 		/* Soft interrupt for this driver */
485 		sc->sc_rx_pend = 0;
486 		ARN_UNLOCK(sc);
487 		arn_rx_handler(sc);
488 		return (DDI_INTR_CLAIMED);
489 	}
490 
491 	ARN_UNLOCK(sc);
492 
493 	return (DDI_INTR_UNCLAIMED);
494 }
495