summaryrefslogtreecommitdiffstats
path: root/sys/dev/iwi
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/iwi')
-rw-r--r--sys/dev/iwi/if_iwi.c75
-rw-r--r--sys/dev/iwi/if_iwi_ioctl.h25
-rw-r--r--sys/dev/iwi/if_iwireg.h63
-rw-r--r--sys/dev/iwi/if_iwivar.h3
4 files changed, 155 insertions, 11 deletions
diff --git a/sys/dev/iwi/if_iwi.c b/sys/dev/iwi/if_iwi.c
index e6ee051..b6de4b6 100644
--- a/sys/dev/iwi/if_iwi.c
+++ b/sys/dev/iwi/if_iwi.c
@@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$");
#include <net/bpf.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <net/if_dl.h>
@@ -83,6 +84,7 @@ __FBSDID("$FreeBSD$");
#include <dev/iwi/if_iwireg.h>
#include <dev/iwi/if_iwivar.h>
+#include <dev/iwi/if_iwi_ioctl.h>
#define IWI_DEBUG
#ifdef IWI_DEBUG
@@ -936,10 +938,13 @@ iwi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
struct ieee80211vap *vap = ifp->if_softc;
struct ieee80211com *ic = vap->iv_ic;
struct iwi_softc *sc = ic->ic_ifp->if_softc;
+ struct ieee80211_node *ni;
/* read current transmission rate from adapter */
- vap->iv_bss->ni_txrate =
+ ni = ieee80211_ref_node(vap->iv_bss);
+ ni->ni_txrate =
iwi_cvtrate(CSR_READ_4(sc, IWI_CSR_CURRENT_TX_RATE));
+ ieee80211_free_node(ni);
ieee80211_media_status(ifp, imr);
}
@@ -1230,7 +1235,7 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i,
*/
mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
if (mnew == NULL) {
- ifp->if_ierrors++;
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
return;
}
@@ -1251,7 +1256,7 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i,
panic("%s: could not load old rx mbuf",
device_get_name(sc->sc_dev));
}
- ifp->if_ierrors++;
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
return;
}
@@ -1358,16 +1363,44 @@ iwi_checkforqos(struct ieee80211vap *vap,
frm += frm[1] + 2;
}
- ni = vap->iv_bss;
+ ni = ieee80211_ref_node(vap->iv_bss);
ni->ni_capinfo = capinfo;
ni->ni_associd = associd & 0x3fff;
if (wme != NULL)
ni->ni_flags |= IEEE80211_NODE_QOS;
else
ni->ni_flags &= ~IEEE80211_NODE_QOS;
+ ieee80211_free_node(ni);
#undef SUBTYPE
}
+static void
+iwi_notif_link_quality(struct iwi_softc *sc, struct iwi_notif *notif)
+{
+ struct iwi_notif_link_quality *lq;
+ int len;
+
+ len = le16toh(notif->len);
+
+ DPRINTFN(5, ("Notification (%u) - len=%d, sizeof=%zu\n",
+ notif->type,
+ len,
+ sizeof(struct iwi_notif_link_quality)
+ ));
+
+ /* enforce length */
+ if (len != sizeof(struct iwi_notif_link_quality)) {
+ DPRINTFN(5, ("Notification: (%u) too short (%d)\n",
+ notif->type,
+ len));
+ return;
+ }
+
+ lq = (struct iwi_notif_link_quality *)(notif + 1);
+ memcpy(&sc->sc_linkqual, lq, sizeof(sc->sc_linkqual));
+ sc->sc_linkqual_valid = 1;
+}
+
/*
* Task queue callbacks for iwi_notification_intr used to avoid LOR's.
*/
@@ -1537,9 +1570,12 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
case IWI_NOTIF_TYPE_CALIBRATION:
case IWI_NOTIF_TYPE_NOISE:
- case IWI_NOTIF_TYPE_LINK_QUALITY:
+ /* XXX handle? */
DPRINTFN(5, ("Notification (%u)\n", notif->type));
break;
+ case IWI_NOTIF_TYPE_LINK_QUALITY:
+ iwi_notif_link_quality(sc, notif);
+ break;
default:
DPRINTF(("unknown notification type %u flags 0x%x len %u\n",
@@ -1615,7 +1651,7 @@ iwi_tx_intr(struct iwi_softc *sc, struct iwi_tx_ring *txq)
DPRINTFN(15, ("tx done idx=%u\n", txq->next));
- ifp->if_opackets++;
+ if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
txq->queued--;
txq->next = (txq->next + 1) % IWI_TX_RING_COUNT;
@@ -1816,7 +1852,7 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni,
/* h/w table is full */
m_freem(m0);
ieee80211_free_node(ni);
- ifp->if_oerrors++;
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
return 0;
}
iwi_write_ibssnode(sc,
@@ -1971,7 +2007,7 @@ iwi_start_locked(struct ifnet *ifp)
ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
if (iwi_tx_start(ifp, m, ni, ac) != 0) {
ieee80211_free_node(ni);
- ifp->if_oerrors++;
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
break;
}
@@ -2002,7 +2038,7 @@ iwi_watchdog(void *arg)
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
if_printf(ifp, "device timeout\n");
- ifp->if_oerrors++;
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
ieee80211_runtask(ic, &sc->sc_restarttask);
}
}
@@ -2058,11 +2094,25 @@ iwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
+ case SIOCGIWISTATS:
+ IWI_LOCK(sc);
+ /* XXX validate permissions/memory/etc? */
+ error = copyout(&sc->sc_linkqual, ifr->ifr_data,
+ sizeof(struct iwi_notif_link_quality));
+ IWI_UNLOCK(sc);
+ break;
+ case SIOCZIWISTATS:
+ IWI_LOCK(sc);
+ memset(&sc->sc_linkqual, 0,
+ sizeof(struct iwi_notif_link_quality));
+ IWI_UNLOCK(sc);
+ error = 0;
+ break;
default:
error = EINVAL;
break;
}
- return error;
+ return error;
}
static void
@@ -2803,7 +2853,7 @@ iwi_auth_and_assoc(struct iwi_softc *sc, struct ieee80211vap *vap)
{
struct ieee80211com *ic = vap->iv_ic;
struct ifnet *ifp = vap->iv_ifp;
- struct ieee80211_node *ni = vap->iv_bss;
+ struct ieee80211_node *ni;
struct iwi_configuration config;
struct iwi_associate *assoc = &sc->assoc;
struct iwi_rateset rs;
@@ -2813,6 +2863,8 @@ iwi_auth_and_assoc(struct iwi_softc *sc, struct ieee80211vap *vap)
IWI_LOCK_ASSERT(sc);
+ ni = ieee80211_ref_node(vap->iv_bss);
+
if (sc->flags & IWI_FLAG_ASSOCIATED) {
DPRINTF(("Already associated\n"));
return (-1);
@@ -2971,6 +3023,7 @@ iwi_auth_and_assoc(struct iwi_softc *sc, struct ieee80211vap *vap)
le16toh(assoc->intval)));
error = iwi_cmd(sc, IWI_CMD_ASSOCIATE, assoc, sizeof *assoc);
done:
+ ieee80211_free_node(ni);
if (error)
IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
diff --git a/sys/dev/iwi/if_iwi_ioctl.h b/sys/dev/iwi/if_iwi_ioctl.h
new file mode 100644
index 0000000..0f4f447
--- /dev/null
+++ b/sys/dev/iwi/if_iwi_ioctl.h
@@ -0,0 +1,25 @@
+/*-
+ * Copyright (c) 2014 Adrian Chadd <adrian@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef __IF_IWI_IOCTL_H__
+#define __IF_IWI_IOCTL_H__
+
+/* XXX how should I pick appropriate ioctl numbers? */
+#define SIOCGIWISTATS _IOWR('i', 147, struct ifreq)
+#define SIOCZIWISTATS _IOWR('i', 148, struct ifreq)
+
+#endif /* __IF_IWI_IOCTL_H__ */
diff --git a/sys/dev/iwi/if_iwireg.h b/sys/dev/iwi/if_iwireg.h
index fb56fa5..bc05ad2 100644
--- a/sys/dev/iwi/if_iwireg.h
+++ b/sys/dev/iwi/if_iwireg.h
@@ -221,6 +221,7 @@ struct iwi_notif_association {
/* structure for notification IWI_NOTIF_TYPE_SCAN_CHANNEL */
struct iwi_notif_scan_channel {
uint8_t nchan;
+ /* XXX this is iwi_cmd_stats, and a u8 reserved field */
uint8_t reserved[47];
} __packed;
@@ -239,6 +240,68 @@ struct iwi_notif_beacon_state {
uint32_t number;
} __packed;
+/* structure(s) for notification IWI_NOTIF_TYPE_LINK_QUALITY */
+
+#define RX_FREE_BUFFERS 32
+#define RX_LOW_WATERMARK 8
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
+
+// Used for passing to driver number of successes and failures per rate
+struct iwi_rate_histogram {
+ union {
+ uint32_t a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+ uint32_t b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+ uint32_t g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+ } success;
+ union {
+ uint32_t a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+ uint32_t b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+ uint32_t g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+ } failed;
+} __packed;
+
+/* statistics command response */
+struct iwi_cmd_stats {
+ uint8_t cmd_id;
+ uint8_t seq_num;
+ uint16_t good_sfd;
+ uint16_t bad_plcp;
+ uint16_t wrong_bssid;
+ uint16_t valid_mpdu;
+ uint16_t bad_mac_header;
+ uint16_t reserved_frame_types;
+ uint16_t rx_ina;
+ uint16_t bad_crc32;
+ uint16_t invalid_cts;
+ uint16_t invalid_acks;
+ uint16_t long_distance_ina_fina;
+ uint16_t dsp_silence_unreachable;
+ uint16_t accumulated_rssi;
+ uint16_t rx_ovfl_frame_tossed;
+ uint16_t rssi_silence_threshold;
+ uint16_t rx_ovfl_frame_supplied;
+ uint16_t last_rx_frame_signal;
+ uint16_t last_rx_frame_noise;
+ uint16_t rx_autodetec_no_ofdm;
+ uint16_t rx_autodetec_no_barker;
+ uint16_t reserved;
+} __packed;
+
+#define SILENCE_OVER_THRESH (1)
+#define SILENCE_UNDER_THRESH (2)
+
+struct iwi_notif_link_quality {
+ struct iwi_cmd_stats stats;
+ uint8_t rate;
+ uint8_t modulation;
+ struct iwi_rate_histogram histogram;
+ uint8_t silence_notification_type; /* SILENCE_OVER/UNDER_THRESH */
+ uint16_t silence_count;
+} __packed;
+
/* received frame header */
struct iwi_frame {
uint32_t reserved1[2];
diff --git a/sys/dev/iwi/if_iwivar.h b/sys/dev/iwi/if_iwivar.h
index 42ca92e..b38bbd9 100644
--- a/sys/dev/iwi/if_iwivar.h
+++ b/sys/dev/iwi/if_iwivar.h
@@ -215,6 +215,9 @@ struct iwi_softc {
struct iwi_rx_radiotap_header sc_rxtap;
struct iwi_tx_radiotap_header sc_txtap;
+
+ struct iwi_notif_link_quality sc_linkqual;
+ int sc_linkqual_valid;
};
#define IWI_STATE_BEGIN(_sc, _state) do { \
OpenPOWER on IntegriCloud