/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2008 Atheros Communications Inc.
*
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/byteorder.h>
#include "arn_core.h"
/*
* Setup and link descriptors.
*
* 11N: we can no longer afford to self link the last descriptor.
* MAC acknowledges BA status as long as it copies frames to host
* buffer (or rx fifo). This can incorrectly acknowledge packets
* to a sender if last desc is self-linked.
*/
void
{
/* virtual addr of the beginning of the buffer. */
/*
* setup rx descriptors. The bf_dma.alength here tells the H/W
* how much data it can DMA to us and that we are prepared
* to process
*/
0);
else
}
void
{
/* XXX block beacon interrupts */
sc->sc_rxotherant = 0;
}
/*
* Extend 15-bit time stamp from rx descriptor to
* a full 64-bit TSF using the current h/w TSF.
*/
static uint64_t
{
tsf -= 0x8000;
}
static int
{
/*
* Frame spans multiple descriptors; this cannot happen yet
* as we don't support jumbograms. If not in monitor mode,
* discard the frame. Enable this if you want to see
* error frames in Monitor mode.
*/
goto rx_next;
goto rx_next; /* should ignore? */
}
}
goto rx_next;
}
}
/*
* Reject error frames with the exception of
* decryption and MIC failures. For monitor mode,
* we also ignore the CRC error.
*/
goto rx_next;
} else {
~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
goto rx_next;
}
}
}
return (1);
return (0);
}
static void
{
/* configure rx filter */
/* configure bssid mask */
/* configure operational mode */
/* Handle any link-level address change. */
/* calculate and install multicast filter */
"mode = %d RX filter 0x%x, MC filter %08x:%08x\n",
}
/*
* Calculate the receive filter according to the
* operating mode and state:
*
* o always accept unicast, broadcast, and multicast traffic
* o maintain current state of phy error reception (the hal
* may enable phy error frames for noise immunity work)
* o probe request frames are accepted only when operating in
* hostap, adhoc, or monitor modes
* o enable promiscuous mode according to the interface state
* o accept beacons:
* - when operating in adhoc mode so the 802.11 layer creates
* node table entries for peers,
* - when operating in station mode for collecting rssi data when
* the station is otherwise quiet, or
* - when operating as a repeater so we see repeater-sta beacons
* - when scanning
*/
{
/* If not a STA, enable processing of Probe Requests */
/* Can't set HOSTAP into promiscous mode */
(sc->sc_promisc)) ||
/* ??? To prevent from sending ACK */
}
/*
* If in HOSTAP mode, want to enable reception of PSPOLL
* frames & beacon frames
*/
return (rfilt);
}
/*
* When block ACK agreement has been set up between station and AP,
* Net80211 module will call this function to inform hardware about
* informations of this BA agreement.
* When AP wants to delete BA agreement that was originated by it,
* Net80211 modele will call this function to clean up relevant
* information in hardware.
*/
void
{
"Unknown AMPDU action or NULL node index\n"));
return;
}
return;
else
}
int
{
/* rx descriptor link set up */
goto start_recv;
/* clean up rx link firstly */
}
/* We could have deleted elements so the list may be empty now */
goto start_recv;
return (0);
}
{
ath9k_hw_setrxfilter(ah, 0);
/* 3ms is long enough for 1 frame ??? */
drv_usecwait(3000);
return (stopped);
}
/*
* Intercept management frames to collect beacon rssi data
* and to do ibss merges.
*/
void
{
/*
* Call up first so subsequent work can use information
* potentially stored in the node (e.g. for ibss merge).
*/
switch (subtype) {
/* update rssi statistics */
/*
* Resync beacon timers using the tsf of the beacon
* frame we just received.
*/
}
/* FALLTHRU */
/*
* Handle ibss merge as needed; check the tsf on the
* frame before attempting the merge. The 802.11 spec
* says the station should change it's bssid to match
* the oldest station with the same ssid, where oldest
* is determined by the tsf. Note that hardware
* reconfiguration happens through callback to
* ath_newstate as the state machine will go from
* RUN -> RUN when this happens.
*/
"ibss merge, rstamp %u tsf %lu "
ARN_UNLOCK(sc);
"ibss_merge: rstamp=%d in_tstamp=%02x %02x"
" %02x %02x %02x %02x %02x %02x\n",
(void) ieee80211_ibss_merge(in);
return;
}
}
break;
}
ARN_UNLOCK(sc);
}
static void
{
"%08x %08x %08x %c\n",
}
static void
{
int status;
#ifdef ARN_DBG_AMSDU
#endif
do {
"no buffer\n"));
break;
}
/*
* Must provide the virtual address of the current
* descriptor, the physical address, and the virtual
* address of the next descriptor in the h/w chain.
* This allows the HAL to look ahead to see if the
* hardware is done with a descriptor by checking the
* done bit in the following descriptor and the address
* of the current descriptor the DMA engine is working
* on. All this is necessary because of our use of
* a self-linked list to avoid rx overruns.
*/
if (status == EINPROGRESS) {
"List is in last! \n"));
break;
}
/*
* On some hardware the descriptor status words could
* get corrupted, including the done bit. Because of
* this, check if the next descriptor's done bit is
* set or not.
*
* If the next descriptor's done bit is set, the current
* descriptor has been corrupted. Force s/w to discard
* this descriptor and continue...
*/
if (status == EINPROGRESS) {
break;
}
}
/* less than sizeof(struct ieee80211_frame) */
if (len < 20) {
goto requeue;
}
/* The status portion of the descriptor could get corrupted. */
arn_problem("Requeued because of wrong rs_datalen\n");
goto requeue;
}
goto requeue;
arn_problem("arn: arn_rx_handler(): "
"allocing mblk buffer failed.\n");
return;
}
/*
* Ignore control frame received in promisc mode.
*/
goto requeue;
}
/* Remove the CRC at the end of IEEE80211 frame */
#ifdef DEBUG
#endif
#ifdef ARN_DBG_AMSDU
if (IEEE80211_IS_DATA_QOS(wh)) {
qos = ((struct ieee80211_qosframe_addr4 *)
else
qos =
if (qos & IEEE80211_QOS_AMSDU)
}
#endif /* ARN_DBG_AMSDU */
/*
* Locate the node for sender, track state, and then
* pass the (referenced) node up to the 802.11 layer
* for its use.
*/
/*
* Theory for reporting quality:
*
* At a hardware RSSI of 45 you will be able to use
* MCS 7 reliably.
* At a hardware RSSI of 45 you will be able to use
* MCS 15 reliably.
* At a hardware RSSI of 35 you should be able use
* 54 Mbps reliably.
*
* MCS 7 is the highets MCS index usable by a 1-stream device.
* MCS 15 is the highest MCS index usable by a 2-stream device.
*
* All ath9k devices are either 1-stream or 2-stream.
*
* How many bars you see is derived from the qual reporting.
*
* A more elaborate scheme can be used here but it requires
* tables of SNR/throughput for each possible mode used. For
* the MCS table you can refer to the wireless wiki:
*
* ieee80211/802.11n
*/
/* LINTED: E_CONSTANT_CONDITION */
}
if (last_rssi != ATH_RSSI_DUMMY_MARKER)
if (subtype == IEEE80211_FC0_SUBTYPE_BEACON)
}
/*
* signal (13-15) DLADM_WLAN_STRENGTH_EXCELLENT
* signal (10-12) DLADM_WLAN_STRENGTH_VERY_GOOD
* signal (6-9) DLADM_WLAN_STRENGTH_GOOD
* signal (3-5) DLADM_WLAN_STRENGTH_WEAK
* signal (0-2) DLADM_WLAN_STRENGTH_VERY_WEAK
*/
cur_signal = 0;
else
/*
* Send the frame to net80211 for processing
*/
}
else
/* release node */
/*
* Arrange to update the last rx timestamp only for
* frames from our ap when operating in station mode.
* This assumes the rx key is always setup when associated.
*/
ngood++;
}
/*
* change the default rx antenna if rx diversity chooses the
* other antenna 3 times in a row.
*/
sc->sc_rxotherant = 0;
}
} else {
sc->sc_rxotherant = 0;
}
} while (loop);
if (ngood)
}
{
if (sc->sc_rx_pend) {
/* Soft interrupt for this driver */
sc->sc_rx_pend = 0;
ARN_UNLOCK(sc);
return (DDI_INTR_CLAIMED);
}
ARN_UNLOCK(sc);
return (DDI_INTR_UNCLAIMED);
}