1291233Sadrian/*- 2291233Sadrian * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3291233Sadrian * All rights reserved. 4291233Sadrian * 5291233Sadrian * Redistribution and use in source and binary forms, with or without 6291233Sadrian * modification, are permitted provided that the following conditions 7291233Sadrian * are met: 8291233Sadrian * 1. Redistributions of source code must retain the above copyright 9291233Sadrian * notice, this list of conditions and the following disclaimer, 10291233Sadrian * without modification. 11291233Sadrian * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12291233Sadrian * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13291233Sadrian * redistribution must be conditioned upon including a substantially 14291233Sadrian * similar Disclaimer requirement for further binary redistribution. 15291233Sadrian * 16291233Sadrian * NO WARRANTY 17291233Sadrian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18291233Sadrian * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19291233Sadrian * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20291233Sadrian * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21291233Sadrian * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22291233Sadrian * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23291233Sadrian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24291233Sadrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25291233Sadrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26291233Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27291233Sadrian * THE POSSIBILITY OF SUCH DAMAGES. 28291233Sadrian */ 29291233Sadrian 30291233Sadrian#include <sys/cdefs.h> 31291233Sadrian__FBSDID("$FreeBSD: stable/11/sys/dev/ath/if_ath_ioctl.c 332303 2018-04-08 20:50:16Z emaste $"); 32291233Sadrian 33291233Sadrian/* 34291233Sadrian * Driver for the Atheros Wireless LAN controller. 35291233Sadrian * 36291233Sadrian * This software is derived from work of Atsushi Onoe; his contribution 37291233Sadrian * is greatly appreciated. 38291233Sadrian */ 39291233Sadrian 40291233Sadrian#include "opt_inet.h" 41291233Sadrian#include "opt_ath.h" 42291233Sadrian/* 43291233Sadrian * This is needed for register operations which are performed 44291233Sadrian * by the driver - eg, calls to ath_hal_gettsf32(). 45291233Sadrian * 46291233Sadrian * It's also required for any AH_DEBUG checks in here, eg the 47291233Sadrian * module dependencies. 48291233Sadrian */ 49291233Sadrian#include "opt_ah.h" 50291233Sadrian#include "opt_wlan.h" 51291233Sadrian 52291233Sadrian#include <sys/param.h> 53291233Sadrian#include <sys/systm.h> 54291233Sadrian#include <sys/sysctl.h> 55291233Sadrian#include <sys/mbuf.h> 56291233Sadrian#include <sys/malloc.h> 57291233Sadrian#include <sys/lock.h> 58291233Sadrian#include <sys/mutex.h> 59291233Sadrian#include <sys/kernel.h> 60291233Sadrian#include <sys/socket.h> 61291233Sadrian#include <sys/sockio.h> 62291233Sadrian#include <sys/errno.h> 63291233Sadrian#include <sys/callout.h> 64291233Sadrian#include <sys/bus.h> 65291233Sadrian#include <sys/endian.h> 66291233Sadrian#include <sys/kthread.h> 67291233Sadrian#include <sys/taskqueue.h> 68291233Sadrian#include <sys/priv.h> 69291233Sadrian#include <sys/module.h> 70291233Sadrian#include <sys/ktr.h> 71291233Sadrian#include <sys/smp.h> /* for mp_ncpus */ 72291233Sadrian 73291233Sadrian#include <machine/bus.h> 74291233Sadrian 75291233Sadrian#include <net/if.h> 76291233Sadrian#include <net/if_var.h> 77291233Sadrian#include <net/if_dl.h> 78291233Sadrian#include <net/if_media.h> 79291233Sadrian#include <net/if_types.h> 80291233Sadrian#include <net/if_arp.h> 81291233Sadrian#include <net/ethernet.h> 82291233Sadrian#include <net/if_llc.h> 83291233Sadrian 84291233Sadrian#include <net80211/ieee80211_var.h> 85291233Sadrian#include <net80211/ieee80211_regdomain.h> 86291233Sadrian#ifdef IEEE80211_SUPPORT_SUPERG 87291233Sadrian#include <net80211/ieee80211_superg.h> 88291233Sadrian#endif 89291233Sadrian#ifdef IEEE80211_SUPPORT_TDMA 90291233Sadrian#include <net80211/ieee80211_tdma.h> 91291233Sadrian#endif 92291233Sadrian 93291233Sadrian#include <net/bpf.h> 94291233Sadrian 95291233Sadrian#ifdef INET 96291233Sadrian#include <netinet/in.h> 97291233Sadrian#include <netinet/if_ether.h> 98291233Sadrian#endif 99291233Sadrian 100291233Sadrian#include <dev/ath/if_athvar.h> 101291233Sadrian#include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */ 102291233Sadrian#include <dev/ath/ath_hal/ah_diagcodes.h> 103291233Sadrian 104291233Sadrian#include <dev/ath/if_ath_debug.h> 105291233Sadrian#include <dev/ath/if_ath_misc.h> 106291233Sadrian#include <dev/ath/if_ath_btcoex.h> 107291233Sadrian#include <dev/ath/if_ath_spectral.h> 108291233Sadrian#include <dev/ath/if_ath_lna_div.h> 109291233Sadrian#include <dev/ath/if_athdfs.h> 110291233Sadrian 111291233Sadrian#ifdef IEEE80211_SUPPORT_TDMA 112291233Sadrian#include <dev/ath/if_ath_tdma.h> 113291233Sadrian#endif 114291233Sadrian 115291233Sadrian#include <dev/ath/if_ath_ioctl.h> 116291233Sadrian 117291233Sadrian/* 118291233Sadrian * ioctl() related pieces. 119291233Sadrian * 120291233Sadrian * Some subsystems (eg spectral, dfs) have their own ioctl method which 121291233Sadrian * we call. 122291233Sadrian */ 123291233Sadrian 124291233Sadrian/* 125291233Sadrian * Fetch the rate control statistics for the given node. 126291233Sadrian */ 127291233Sadrianstatic int 128291233Sadrianath_ioctl_ratestats(struct ath_softc *sc, struct ath_rateioctl *rs) 129291233Sadrian{ 130291233Sadrian struct ath_node *an; 131291233Sadrian struct ieee80211com *ic = &sc->sc_ic; 132291233Sadrian struct ieee80211_node *ni; 133291233Sadrian int error = 0; 134291233Sadrian 135291233Sadrian /* Perform a lookup on the given node */ 136291233Sadrian ni = ieee80211_find_node(&ic->ic_sta, rs->is_u.macaddr); 137291233Sadrian if (ni == NULL) { 138291233Sadrian error = EINVAL; 139291233Sadrian goto bad; 140291233Sadrian } 141291233Sadrian 142291233Sadrian /* Lock the ath_node */ 143291233Sadrian an = ATH_NODE(ni); 144291233Sadrian ATH_NODE_LOCK(an); 145291233Sadrian 146291233Sadrian /* Fetch the rate control stats for this node */ 147291233Sadrian error = ath_rate_fetch_node_stats(sc, an, rs); 148291233Sadrian 149291233Sadrian /* No matter what happens here, just drop through */ 150291233Sadrian 151291233Sadrian /* Unlock the ath_node */ 152291233Sadrian ATH_NODE_UNLOCK(an); 153291233Sadrian 154291233Sadrian /* Unref the node */ 155291233Sadrian ieee80211_node_decref(ni); 156291233Sadrian 157291233Sadrianbad: 158291233Sadrian return (error); 159291233Sadrian} 160291233Sadrian 161291233Sadrian#ifdef ATH_DIAGAPI 162291233Sadrian/* 163291233Sadrian * Diagnostic interface to the HAL. This is used by various 164291233Sadrian * tools to do things like retrieve register contents for 165291233Sadrian * debugging. The mechanism is intentionally opaque so that 166298939Spfg * it can change frequently w/o concern for compatibility. 167291233Sadrian */ 168291233Sadrianstatic int 169291233Sadrianath_ioctl_diag(struct ath_softc *sc, struct ath_diag *ad) 170291233Sadrian{ 171291233Sadrian struct ath_hal *ah = sc->sc_ah; 172291233Sadrian u_int id = ad->ad_id & ATH_DIAG_ID; 173291233Sadrian void *indata = NULL; 174291233Sadrian void *outdata = NULL; 175291233Sadrian u_int32_t insize = ad->ad_in_size; 176291233Sadrian u_int32_t outsize = ad->ad_out_size; 177291233Sadrian int error = 0; 178291233Sadrian 179291233Sadrian if (ad->ad_id & ATH_DIAG_IN) { 180291233Sadrian /* 181291233Sadrian * Copy in data. 182291233Sadrian */ 183291233Sadrian indata = malloc(insize, M_TEMP, M_NOWAIT); 184291233Sadrian if (indata == NULL) { 185291233Sadrian error = ENOMEM; 186291233Sadrian goto bad; 187291233Sadrian } 188291233Sadrian error = copyin(ad->ad_in_data, indata, insize); 189291233Sadrian if (error) 190291233Sadrian goto bad; 191291233Sadrian } 192291233Sadrian if (ad->ad_id & ATH_DIAG_DYN) { 193291233Sadrian /* 194291233Sadrian * Allocate a buffer for the results (otherwise the HAL 195291233Sadrian * returns a pointer to a buffer where we can read the 196291233Sadrian * results). Note that we depend on the HAL leaving this 197291233Sadrian * pointer for us to use below in reclaiming the buffer; 198291233Sadrian * may want to be more defensive. 199291233Sadrian */ 200332303Semaste outdata = malloc(outsize, M_TEMP, M_NOWAIT | M_ZERO); 201291233Sadrian if (outdata == NULL) { 202291233Sadrian error = ENOMEM; 203291233Sadrian goto bad; 204291233Sadrian } 205291233Sadrian } 206291233Sadrian 207291233Sadrian 208291233Sadrian ATH_LOCK(sc); 209291233Sadrian if (id != HAL_DIAG_REGS) 210291233Sadrian ath_power_set_power_state(sc, HAL_PM_AWAKE); 211291233Sadrian ATH_UNLOCK(sc); 212291233Sadrian 213291233Sadrian if (ath_hal_getdiagstate(ah, id, indata, insize, &outdata, &outsize)) { 214291233Sadrian if (outsize < ad->ad_out_size) 215291233Sadrian ad->ad_out_size = outsize; 216291233Sadrian if (outdata != NULL) 217291233Sadrian error = copyout(outdata, ad->ad_out_data, 218291233Sadrian ad->ad_out_size); 219291233Sadrian } else { 220291233Sadrian error = EINVAL; 221291233Sadrian } 222291233Sadrian 223291233Sadrian ATH_LOCK(sc); 224291233Sadrian if (id != HAL_DIAG_REGS) 225291233Sadrian ath_power_restore_power_state(sc); 226291233Sadrian ATH_UNLOCK(sc); 227291233Sadrian 228291233Sadrianbad: 229291233Sadrian if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) 230291233Sadrian free(indata, M_TEMP); 231291233Sadrian if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) 232291233Sadrian free(outdata, M_TEMP); 233291233Sadrian return error; 234291233Sadrian} 235291233Sadrian#endif /* ATH_DIAGAPI */ 236291233Sadrian 237291233Sadrianint 238291233Sadrianath_ioctl(struct ieee80211com *ic, u_long cmd, void *data) 239291233Sadrian{ 240291233Sadrian struct ifreq *ifr = data; 241291233Sadrian struct ath_softc *sc = ic->ic_softc; 242291233Sadrian 243291233Sadrian switch (cmd) { 244291233Sadrian case SIOCGATHSTATS: { 245291233Sadrian struct ieee80211vap *vap; 246291233Sadrian struct ifnet *ifp; 247291233Sadrian const HAL_RATE_TABLE *rt; 248291233Sadrian 249291233Sadrian /* NB: embed these numbers to get a consistent view */ 250291233Sadrian sc->sc_stats.ast_tx_packets = 0; 251291233Sadrian sc->sc_stats.ast_rx_packets = 0; 252291233Sadrian TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 253291233Sadrian ifp = vap->iv_ifp; 254291233Sadrian sc->sc_stats.ast_tx_packets += ifp->if_get_counter(ifp, 255291233Sadrian IFCOUNTER_OPACKETS); 256291233Sadrian sc->sc_stats.ast_rx_packets += ifp->if_get_counter(ifp, 257291233Sadrian IFCOUNTER_IPACKETS); 258291233Sadrian } 259291233Sadrian sc->sc_stats.ast_tx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgtxrssi); 260291233Sadrian sc->sc_stats.ast_rx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgrssi); 261291233Sadrian#ifdef IEEE80211_SUPPORT_TDMA 262291233Sadrian sc->sc_stats.ast_tdma_tsfadjp = TDMA_AVG(sc->sc_avgtsfdeltap); 263291233Sadrian sc->sc_stats.ast_tdma_tsfadjm = TDMA_AVG(sc->sc_avgtsfdeltam); 264291233Sadrian#endif 265291233Sadrian rt = sc->sc_currates; 266291233Sadrian sc->sc_stats.ast_tx_rate = 267291233Sadrian rt->info[sc->sc_txrix].dot11Rate &~ IEEE80211_RATE_BASIC; 268291233Sadrian if (rt->info[sc->sc_txrix].phy & IEEE80211_T_HT) 269291233Sadrian sc->sc_stats.ast_tx_rate |= IEEE80211_RATE_MCS; 270332288Sbrooks return copyout(&sc->sc_stats, ifr_data_get_ptr(ifr), 271332288Sbrooks sizeof (sc->sc_stats)); 272291233Sadrian } 273291233Sadrian case SIOCGATHAGSTATS: 274332288Sbrooks return copyout(&sc->sc_aggr_stats, ifr_data_get_ptr(ifr), 275332288Sbrooks sizeof (sc->sc_aggr_stats)); 276291233Sadrian case SIOCZATHSTATS: { 277291233Sadrian int error; 278291233Sadrian 279291233Sadrian error = priv_check(curthread, PRIV_DRIVER); 280291233Sadrian if (error == 0) { 281291233Sadrian memset(&sc->sc_stats, 0, sizeof(sc->sc_stats)); 282291233Sadrian memset(&sc->sc_aggr_stats, 0, 283291233Sadrian sizeof(sc->sc_aggr_stats)); 284291233Sadrian memset(&sc->sc_intr_stats, 0, 285291233Sadrian sizeof(sc->sc_intr_stats)); 286291233Sadrian } 287291233Sadrian return (error); 288291233Sadrian } 289291233Sadrian#ifdef ATH_DIAGAPI 290291233Sadrian case SIOCGATHDIAG: 291291233Sadrian return (ath_ioctl_diag(sc, data)); 292291233Sadrian case SIOCGATHPHYERR: 293291233Sadrian return (ath_ioctl_phyerr(sc, data)); 294291233Sadrian#endif 295291233Sadrian case SIOCGATHSPECTRAL: 296291233Sadrian return (ath_ioctl_spectral(sc, data)); 297291233Sadrian case SIOCGATHNODERATESTATS: 298291233Sadrian return (ath_ioctl_ratestats(sc, data)); 299291233Sadrian default: 300291233Sadrian /* 301291233Sadrian * This signals the net80211 layer that we didn't handle this 302291233Sadrian * ioctl. 303291233Sadrian */ 304291233Sadrian return (ENOTTY); 305291233Sadrian } 306291233Sadrian} 307291233Sadrian 308