Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 13 Aug 2013 09:08:10 +0200
From:      "Cedric GROSS" <cg@cgross.info>
To:        "'Adrian Chadd'" <adrian@freebsd.org>
Cc:        freebsd-wireless@freebsd.org
Subject:   RE: [iwn]Review Split 6
Message-ID:  <000c01ce97f3$e0178d10$a046a730$@info>
In-Reply-To: <00cc01ce978e$dada4190$908ec4b0$@info>
References:  <001d01ce9694$142db8b0$3c892a10$@info> <CAJ-VmomM3FcdiuVWdiZ68i--ikGgNFvySiPURyOe_4CR_eYYXA@mail.gmail.com> <00cc01ce978e$dada4190$908ec4b0$@info>

index | next in thread | previous in thread | raw e-mail

[-- Attachment #1 --]
> >
> > I guess '_u1' here is 'PAN VAP'. We'll eventually rename this stuff
> > and maybe shift it into a separate source file so all the PAN stuff
> > clearly lives elsewhere.
> 
> Ok I'll do that.
> 

Here is new version of split 6 with new files and new function renamed.

Cedric

[-- Attachment #2 --]
Index: sys/dev/iwn/if_iwn.c
===================================================================
--- sys/dev/iwn/if_iwn.c	(revision 254271)
+++ sys/dev/iwn/if_iwn.c	(working copy)
@@ -77,6 +77,7 @@
 #include <dev/iwn/if_iwnreg.h>
 #include <dev/iwn/if_iwnvar.h>
 #include <dev/iwn/if_iwn_devid.h>
+#include <dev/iwn/if_iwn_pan.h>
 
 struct iwn_ident {
 	uint16_t	vendor;
@@ -180,7 +181,6 @@
 static void	iwn_read_eeprom_enhinfo(struct iwn_softc *);
 static struct ieee80211_node *iwn_node_alloc(struct ieee80211vap *,
 		    const uint8_t mac[IEEE80211_ADDR_LEN]);
-static void	iwn_newassoc(struct ieee80211_node *, int);
 static int	iwn_media_change(struct ifnet *);
 static int	iwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static void	iwn_calib_timeout(void *);
@@ -225,7 +225,6 @@
 static void	iwn_start_locked(struct ifnet *);
 static void	iwn_watchdog(void *);
 static int	iwn_ioctl(struct ifnet *, u_long, caddr_t);
-static int	iwn_cmd(struct iwn_softc *, int, const void *, int, int);
 static int	iwn4965_add_node(struct iwn_softc *, struct iwn_node_info *,
 		    int);
 static int	iwn5000_add_node(struct iwn_softc *, struct iwn_node_info *,
@@ -329,37 +328,7 @@
 #ifdef	IWN_DEBUG
 static char	*iwn_get_csr_string(int);
 static void	iwn_debug_register(struct iwn_softc *);
-#endif
-
-#ifdef	IWN_DEBUG
-enum {
-	IWN_DEBUG_XMIT		= 0x00000001,	/* basic xmit operation */
-	IWN_DEBUG_RECV		= 0x00000002,	/* basic recv operation */
-	IWN_DEBUG_STATE		= 0x00000004,	/* 802.11 state transitions */
-	IWN_DEBUG_TXPOW		= 0x00000008,	/* tx power processing */
-	IWN_DEBUG_RESET		= 0x00000010,	/* reset processing */
-	IWN_DEBUG_OPS		= 0x00000020,	/* iwn_ops processing */
-	IWN_DEBUG_BEACON 	= 0x00000040,	/* beacon handling */
-	IWN_DEBUG_WATCHDOG 	= 0x00000080,	/* watchdog timeout */
-	IWN_DEBUG_INTR		= 0x00000100,	/* ISR */
-	IWN_DEBUG_CALIBRATE	= 0x00000200,	/* periodic calibration */
-	IWN_DEBUG_NODE		= 0x00000400,	/* node management */
-	IWN_DEBUG_LED		= 0x00000800,	/* led management */
-	IWN_DEBUG_CMD		= 0x00001000,	/* cmd submission */
-	IWN_DEBUG_TXRATE	= 0x00002000,	/* TX rate debugging */
-	IWN_DEBUG_PWRSAVE	= 0x00004000,	/* Power save operations */
-	IWN_DEBUG_REGISTER	= 0x20000000,	/* print chipset register */
-	IWN_DEBUG_TRACE		= 0x40000000,	/* Print begin and start driver function */
-	IWN_DEBUG_FATAL		= 0x80000000,	/* fatal errors */
-	IWN_DEBUG_ANY		= 0xffffffff
-};
-
-#define DPRINTF(sc, m, fmt, ...) do {			\
-	if (sc->sc_debug & (m))				\
-		printf(fmt, __VA_ARGS__);		\
-} while (0)
-
-static const char *
+const char *
 iwn_intr_str(uint8_t cmd)
 {
 	switch (cmd) {
@@ -401,8 +370,6 @@
 	}
 	return "UNKNOWN INTR NOTIF/CMD";
 }
-#else
-#define DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0)
 #endif
 
 static device_method_t iwn_methods[] = {
@@ -919,6 +886,13 @@
 
 	IEEE80211_ADDR_COPY(mac1, mac);
 
+	if(unit == 1) {
+		if(!(sc->sc_flags & IWN_FLAG_PAN_SUPPORT))
+			return NULL;
+		mac1[5] += 1;
+		sc->ctx	= IWN_RXON_PAN_CTX;
+	}
+
 	ivp = (struct iwn_vap *) malloc(sizeof(struct iwn_vap),
 	    M_80211_VAP, M_NOWAIT | M_ZERO);
 	if (ivp == NULL)
@@ -925,13 +899,27 @@
 		return NULL;
 	vap = &ivp->iv_vap;
 	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac1);
-	ivp->ctx = IWN_RXON_BSS_CTX;
-	IEEE80211_ADDR_COPY(ivp->macaddr, mac1);
+
+	if(unit == 1) {
+		ivp->ctx = IWN_RXON_PAN_CTX;
+		ivp->iv_newstate = vap->iv_newstate;
+		vap->iv_newstate = iwn_newstate_pan;
+		IEEE80211_ADDR_COPY(ivp->macaddr, mac1);
+		memset(&sc->rx_on[IWN_RXON_PAN_CTX], 0, sizeof (struct iwn_rxon));
+		memcpy(&sc->rx_on[IWN_RXON_PAN_CTX], &sc->rx_on[IWN_RXON_BSS_CTX], sc->rxonsz);
+		IEEE80211_ADDR_COPY(sc->rx_on[IWN_RXON_PAN_CTX].myaddr, mac1);
+		sc->rx_on[IWN_RXON_PAN_CTX].mode = IWN_MODE_2STA;
+		sc->ivap[IWN_RXON_PAN_CTX] = vap;
+	}
+	else {
+		ivp->ctx = IWN_RXON_BSS_CTX;
+		IEEE80211_ADDR_COPY(ivp->macaddr, mac1);
+		ivp->iv_newstate = vap->iv_newstate;
+		vap->iv_newstate = iwn_newstate;
+		sc->ivap[IWN_RXON_BSS_CTX] = vap;
+	}
+
 	vap->iv_bmissthreshold = 10;		/* override default */
-	/* Override with driver methods. */
-	ivp->iv_newstate = vap->iv_newstate;
-	vap->iv_newstate = iwn_newstate;
-	sc->ivap[IWN_RXON_BSS_CTX] = vap;
 
 	ieee80211_ratectl_init(vap);
 	/* Complete setup. */
@@ -944,7 +932,11 @@
 iwn_vap_delete(struct ieee80211vap *vap)
 {
 	struct iwn_vap *ivp = IWN_VAP(vap);
+	struct iwn_softc *sc = vap->iv_ic->ic_ifp->if_softc;
 
+	if(ivp->ctx == IWN_RXON_PAN_CTX)
+		sc->ctx = 0;
+
 	ieee80211_ratectl_deinit(vap);
 	ieee80211_vap_detach(vap);
 	free(ivp, M_80211_VAP);
@@ -2317,7 +2309,7 @@
 #undef	RV
 }
 
-static void
+void
 iwn_newassoc(struct ieee80211_node *ni, int isnew)
 {
 	/* Doesn't do anything at the moment */
@@ -2794,6 +2786,7 @@
 	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
 	struct iwn_calib_state *calib = &sc->calib;
 	struct iwn_stats *stats = (struct iwn_stats *)(desc + 1);
+	struct ieee80211vap *vap1;
 	int temp;
 
 	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
@@ -2805,6 +2798,13 @@
 	    __func__);
 		return;
 	}
+	if(sc->ctx == IWN_RXON_PAN_CTX) {
+		vap1 = sc->ivap[IWN_RXON_PAN_CTX];
+		/* Ignore statistics received during a scan. */
+		if (vap1->iv_state != IEEE80211_S_RUN ||
+		    (ic->ic_flags & IEEE80211_F_SCAN))
+			return;
+	}
 
 	bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
 
@@ -2993,12 +2993,19 @@
 static void
 iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc *desc)
 {
-	struct iwn_tx_ring *ring = &sc->txq[4];
+	struct iwn_tx_ring *ring;
 	struct iwn_tx_data *data;
+	int cmd_queue_num;
 
-	if ((desc->qid & 0xf) != 4)
+	if(sc->sc_flags & IWN_FLAG_PAN_SUPPORT)
+		cmd_queue_num = IWN_PAN_CMD_QUEUE;
+	else
+		cmd_queue_num = IWN_CMD_QUEUE_NUM;
+
+	if ((desc->qid & IWN_RX_DESC_QID_MSK) != cmd_queue_num)
 		return;	/* Not a command ack. */
 
+	ring = &sc->txq[cmd_queue_num];
 	data = &ring->data[desc->idx];
 
 	/* If the command was mapped in an mbuf, free it. */
@@ -3154,7 +3161,7 @@
 		    desc->type, iwn_intr_str(desc->type),
 		    le16toh(desc->len));
 
-		if (!(desc->qid & 0x80))	/* Reply to a command. */
+		if (!(desc->qid & IWN_UNSOLICITED_RX_NOTIF))	/* Reply to a command. */
 			iwn_cmd_done(sc, desc);
 
 		switch (desc->type) {
@@ -3187,7 +3194,10 @@
 		{
 			struct iwn_beacon_missed *miss =
 			    (struct iwn_beacon_missed *)(desc + 1);
-			int misses;
+			struct ieee80211vap *vap0 = sc->ivap[IWN_RXON_BSS_CTX];
+			struct ieee80211vap *vap1 = sc->ivap[IWN_RXON_PAN_CTX];
+			int misses,iv_bmissthreshold;
+			int DoReinit =0 ;
 
 			bus_dmamap_sync(sc->rxq.data_dmat, data->map,
 			    BUS_DMASYNC_POSTREAD);
@@ -3194,17 +3204,31 @@
 			misses = le32toh(miss->consecutive);
 
 			DPRINTF(sc, IWN_DEBUG_STATE,
-			    "%s: beacons missed %d/%d\n", __func__,
-			    misses, le32toh(miss->total));
+			    "%s: beacons missed %d/%d rcv %d expect %d\n", __func__,
+			    misses, le32toh(miss->total), le32toh(miss->received),
+			    le32toh(miss->expected));
+
+			iv_bmissthreshold = vap0->iv_bmissthreshold;
+
+			if(sc->ctx == IWN_RXON_PAN_CTX) {
+				iv_bmissthreshold = vap1->iv_bmissthreshold;
+				if (vap0->iv_state == IEEE80211_S_RUN &&
+				    vap1->iv_state == IEEE80211_S_RUN &&
+				    (ic->ic_flags & IEEE80211_F_SCAN) == 0)
+					DoReinit = 1;
+			}
+			else if (vap0->iv_state == IEEE80211_S_RUN &&
+				 (ic->ic_flags & IEEE80211_F_SCAN) == 0)
+					DoReinit = 1;
+
 			/*
 			 * If more than 5 consecutive beacons are missed,
 			 * reinitialize the sensitivity state machine.
 			 */
-			if (vap->iv_state == IEEE80211_S_RUN &&
-			    (ic->ic_flags & IEEE80211_F_SCAN) == 0) {
+			if (DoReinit==1) {
 				if (misses > 5)
 					(void)iwn_init_sensitivity(sc);
-				if (misses >= vap->iv_bmissthreshold) {
+				if (misses >= iv_bmissthreshold) {
 					IWN_UNLOCK(sc);
 					ieee80211_beacon_miss(ic);
 					IWN_LOCK(sc);
@@ -3568,6 +3592,7 @@
 	const struct ieee80211_txparam *tp;
 	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211com *ic = ni->ni_ic;
+	struct iwn_vap *ivp = IWN_VAP(vap);
 	struct iwn_node *wn = (void *)ni;
 	struct iwn_tx_ring *ring;
 	struct iwn_tx_desc *desc;
@@ -3600,21 +3625,23 @@
 		qos = 0;
 		tid = 0;
 	}
-	ac = M_WME_GETAC(m);
-	if (m->m_flags & M_AMPDU_MPDU) {
+
+	if(ivp->ctx == IWN_RXON_PAN_CTX)
+		ac = iwn_pan_ac_to_queue[M_WME_GETAC(m)];
+	else
+		ac = iwn_bss_ac_to_queue[M_WME_GETAC(m)];
+
+	if (IEEE80211_QOS_HAS_SEQ(wh) &&
+	    IEEE80211_AMPDU_RUNNING(&ni->ni_tx_ampdu[ac])) {
 		struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac];
 
-		if (!IEEE80211_AMPDU_RUNNING(tap)) {
-			m_freem(m);
-			return EINVAL;
-		}
-
-		ac = *(int *)tap->txa_private;
+		ring = &sc->txq[*(int *)tap->txa_private];
 		*(uint16_t *)wh->i_seq =
 		    htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT);
 		ni->ni_txseqs[tid]++;
-	}
-	ring = &sc->txq[ac];
+	} else
+		ring = &sc->txq[ac];
+
 	desc = &ring->desc[ring->cur];
 	data = &ring->data[ring->cur];
 
@@ -3707,9 +3734,12 @@
 	}
 
 	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
-	    type != IEEE80211_FC0_TYPE_DATA)
-		tx->id = sc->broadcast_id;
-	else
+	    type != IEEE80211_FC0_TYPE_DATA) {
+		if(ivp->ctx == IWN_RXON_PAN_CTX)
+			tx->id = IWN_PAN_ID_BCAST;
+		else
+			tx->id = sc->broadcast_id;
+	} else
 		tx->id = wn->id;
 
 	if (type == IEEE80211_FC0_TYPE_MGT) {
@@ -3739,7 +3769,7 @@
 	tx->data_ntries = 15;
 	tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
 	tx->rate = iwn_rate_to_plcp(sc, ni, rate);
-	if (tx->id == sc->broadcast_id) {
+	if ((tx->id == IWN_PAN_ID_BCAST) || (tx->id == sc->broadcast_id)) {
 		/* Group or management frame. */
 		tx->linkq = 0;
 		/* XXX Alternate between antenna A and B? */
@@ -3856,7 +3886,7 @@
 	u_int hdrlen;
 	int ac, totlen, error, pad, nsegs = 0, i, rate;
 	uint8_t ridx, type, txant;
-
+	struct iwn_vap *ivp = IWN_VAP(vap);
 	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
 
 	IWN_LOCK_ASSERT(sc);
@@ -3946,7 +3976,10 @@
 
 	tx->len = htole16(totlen);
 	tx->tid = 0;
-	tx->id = sc->broadcast_id;
+	if(ivp->ctx == IWN_RXON_PAN_CTX)
+		tx->id = IWN_PAN_ID_BCAST;
+	else
+		tx->id = sc->broadcast_id;
 	tx->rts_ntries = params->ibp_try1;
 	tx->data_ntries = params->ibp_try0;
 	tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
@@ -4204,16 +4237,16 @@
 /*
  * Send a command to the firmware.
  */
-static int
+int
 iwn_cmd(struct iwn_softc *sc, int code, const void *buf, int size, int async)
 {
-	struct iwn_tx_ring *ring = &sc->txq[4];
+	struct iwn_tx_ring *ring ;
 	struct iwn_tx_desc *desc;
 	struct iwn_tx_data *data;
 	struct iwn_tx_cmd *cmd;
 	struct mbuf *m;
 	bus_addr_t paddr;
-	int totlen, error;
+	int totlen, error,cmd_queue_num;
 
 	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
 
@@ -4220,6 +4253,12 @@
 	if (async == 0)
 		IWN_LOCK_ASSERT(sc);
 
+	if(sc->sc_flags & IWN_FLAG_PAN_SUPPORT)
+		cmd_queue_num = IWN_PAN_CMD_QUEUE;
+	else
+		cmd_queue_num = IWN_CMD_QUEUE_NUM;
+
+	ring = &sc->txq[cmd_queue_num];
 	desc = &ring->desc[ring->cur];
 	data = &ring->data[ring->cur];
 	totlen = 4 + size;
@@ -5546,6 +5585,8 @@
 	struct ieee80211com *ic = ifp->if_l2com;
 	struct ieee80211_scan_state *ss = ic->ic_scan;	/*XXX*/
 	struct ieee80211_node *ni = ss->ss_vap->iv_bss;
+	struct ieee80211vap *vap = ni->ni_vap;
+	struct iwn_vap *ivp = IWN_VAP(vap);
 	struct iwn_scan_hdr *hdr;
 	struct iwn_cmd_data *tx;
 	struct iwn_scan_essid *essid;
@@ -5560,7 +5601,11 @@
 
 	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
 
-	sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX];
+	if(ivp->ctx == IWN_RXON_BSS_CTX)
+		sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX];
+	else if(ivp->ctx == IWN_RXON_PAN_CTX)
+		sc->rxon = &sc->rx_on[IWN_RXON_PAN_CTX];
+
 	buf = malloc(IWN_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO);
 	if (buf == NULL) {
 		device_printf(sc->sc_dev,
@@ -5592,7 +5637,11 @@
 
 	tx = (struct iwn_cmd_data *)(hdr + 1);
 	tx->flags = htole32(IWN_TX_AUTO_SEQ);
-	tx->id = sc->broadcast_id;
+	if(ivp->ctx == IWN_RXON_PAN_CTX)
+		tx->id = IWN_PAN_ID_BCAST;
+	else
+		tx->id = sc->broadcast_id;
+
 	tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
 
 	if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) {
@@ -5629,7 +5678,7 @@
 	    IEEE80211_FC0_SUBTYPE_PROBE_REQ;
 	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
 	IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr);
-	IEEE80211_ADDR_COPY(wh->i_addr2, IF_LLADDR(ifp));
+	IEEE80211_ADDR_COPY(wh->i_addr2, ivp->macaddr);
 	IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr);
 	*(uint16_t *)&wh->i_dur[0] = 0;	/* filled by HW */
 	*(uint16_t *)&wh->i_seq[0] = 0;	/* filled by HW */
@@ -5781,6 +5830,15 @@
 	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
 
 	sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX];
+
+	if(sc->ctx == IWN_RXON_PAN_CTX) {
+		if ((error = iwn_set_pan_params(sc)) != 0) {
+			device_printf(sc->sc_dev,
+			   "%s: iwn_set_pan_params error %d\n", __func__, error);
+			return error;
+		}
+	}
+
 	if (ic->ic_opmode == IEEE80211_M_MONITOR) {
 		/* Link LED blinks while monitoring. */
 		iwn_set_led(sc, IWN_LED_LINK, 5, 5);
@@ -6420,7 +6478,11 @@
 	IWN_SETBITS(sc, IWN_FH_TX_CHICKEN, IWN_FH_TX_CHICKEN_SCHED_RETRY);
 
 	/* Enable chain mode for all queues, except command queue. */
-	iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, 0xfffef);
+	if(sc->sc_flags & IWN_FLAG_PAN_SUPPORT)
+		iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, 0xffdff);
+	else
+		iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, 0xfffef);
+
 	iwn_prph_write(sc, IWN5000_SCHED_AGGR_SEL, 0);
 
 	for (qid = 0; qid < IWN5000_NTXQUEUES; qid++) {
@@ -6440,11 +6502,20 @@
 	/* Identify TX FIFO rings (0-7). */
 	iwn_prph_write(sc, IWN5000_SCHED_TXFACT, 0xff);
 
-	/* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */
-	for (qid = 0; qid < 7; qid++) {
-		static uint8_t qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
-		iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
-		    IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]);
+	if(sc->sc_flags & IWN_FLAG_PAN_SUPPORT) {
+		/* Mark TX rings as active. */
+		for (qid = 0; qid < 11; qid++) {
+			static uint8_t qid2fifo[] = { 3, 2, 1, 0, 0, 4, 2, 5, 4, 7, 5 };
+			iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
+			    IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]);
+		}
+	} else {
+		/* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */
+		for (qid = 0; qid < 7; qid++) {
+			static uint8_t qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
+			iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
+				IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]);
+		}
 	}
 	iwn_nic_unlock(sc);
 
Index: sys/dev/iwn/if_iwn_pan.c
===================================================================
--- sys/dev/iwn/if_iwn_pan.c	(revision 0)
+++ sys/dev/iwn/if_iwn_pan.c	(working copy)
@@ -0,0 +1,566 @@
+/*-
+ * Copyright (c) 2013 Cedric GROSS <cg@cgross.info>
+ * Copyright (c) 2011 Intel Corporation
+ * Copyright (c) 2007-2009
+ *	Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2008
+ *	Benjamin Close <benjsc@FreeBSD.org>
+ * Copyright (c) 2008 Sam Leffler, Errno Consulting
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Driver for Intel WiFi Link 4965 and 1000/2000/5000/6000 Series 802.11
+ * network adapters.
+ */
+
+#include "opt_wlan.h"
+#include "opt_iwn.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+
+#include <dev/iwn/if_iwnreg.h>
+#include <dev/iwn/if_iwnvar.h>
+
+#include <dev/iwn/if_iwn_pan.h>
+
+static int	iwn_auth_pan(struct iwn_softc *, struct ieee80211vap *);
+static int	iwn_set_timing_pan(struct iwn_softc *);
+static int	iwn_run_pan(struct iwn_softc *, struct ieee80211vap *);
+static int	iwn_config_pan(struct iwn_softc *);
+static int	iwn_updateedca_pan(struct ieee80211com *);
+static int	iwn_add_broadcast_node_pan(struct iwn_softc *, int);
+
+int
+iwn_newstate_pan(struct ieee80211vap *vap, enum ieee80211_state nstate,
+    int arg)
+{
+	struct iwn_vap *ivp = IWN_VAP(vap);
+	struct ieee80211com *ic = vap->iv_ic;
+	struct iwn_softc *sc = ic->ic_ifp->if_softc;
+
+	int error = 0;
+
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
+
+	DPRINTF(sc, IWN_DEBUG_STATE, "%s: %s -> %s\n", __func__,
+	    ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate]);
+
+	IEEE80211_UNLOCK(ic);
+	IWN_LOCK(sc);
+	callout_stop(&sc->calib_to);
+
+	sc->rxon = &sc->rx_on[IWN_RXON_PAN_CTX];
+
+	switch (nstate) {
+	case IEEE80211_S_ASSOC:
+		if (vap->iv_state != IEEE80211_S_RUN)
+			break;
+		/* FALLTHROUGH */
+	case IEEE80211_S_AUTH:
+		if (vap->iv_state == IEEE80211_S_AUTH)
+			break;
+
+		/*
+		 * !AUTH -> AUTH transition requires state reset to handle
+		 * reassociations correctly.
+		 */
+		sc->rxon->associd = 0;
+		sc->rxon->filter &= ~htole32(IWN_FILTER_BSS);
+		sc->calib.state = IWN_CALIB_STATE_INIT;
+
+		if ((error = iwn_auth_pan(sc, vap)) != 0) {
+			device_printf(sc->sc_dev,
+			    "%s: could not move to auth state\n", __func__);
+		}
+		break;
+
+	case IEEE80211_S_SCAN:
+
+		if ((error = iwn_set_timing_pan(sc)) != 0) {
+			device_printf(sc->sc_dev,
+			    "%s: iwn_set_timing_pan error %d\n", __func__, error);
+			return error;
+		}
+
+		break;
+
+	case IEEE80211_S_RUN:
+
+		/*
+		 * RUN -> RUN transition; Just restart the timers.
+		 */
+		if (vap->iv_state == IEEE80211_S_RUN) {
+			sc->calib_cnt = 0;
+			break;
+		}
+
+		/*
+		 * !RUN -> RUN requires setting the association id
+		 * which is done with a firmware cmd.  We also defer
+		 * starting the timers until that work is done.
+		 */
+		if ((error = iwn_run_pan(sc, vap)) != 0) {
+			device_printf(sc->sc_dev,
+			    "%s: could not move to run state\n", __func__);
+		}
+		break;
+
+	case IEEE80211_S_INIT:
+		sc->calib.state = IWN_CALIB_STATE_INIT;
+		break;
+
+	default:
+		break;
+	}
+	IWN_UNLOCK(sc);
+	IEEE80211_LOCK(ic);
+	if (error != 0) {
+		DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end in error\n", __func__);
+		return error;
+	}
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__);
+	return ivp->iv_newstate(vap, nstate, arg);
+}
+
+static int
+iwn_auth_pan(struct iwn_softc *sc, struct ieee80211vap *vap)
+{
+	struct iwn_ops *ops = &sc->ops;
+	struct ifnet *ifp = sc->sc_ifp;
+	struct ieee80211com *ic = ifp->if_l2com;
+	struct ieee80211_node *ni = vap->iv_bss;
+	int error;
+	struct iwn_vap *ivp = IWN_VAP(vap);
+
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
+
+	sc->rxon = &sc->rx_on[IWN_RXON_PAN_CTX];
+	IEEE80211_ADDR_COPY(sc->rxon->myaddr, ivp->macaddr);
+	IEEE80211_ADDR_COPY(sc->rxon->wlap, IF_LLADDR(ifp));
+	/* Update adapter configuration. */
+	IEEE80211_ADDR_COPY(sc->rxon->bssid, ni->ni_bssid);
+	sc->rxon->chan = ieee80211_chan2ieee(ic, ni->ni_chan);
+	sc->rxon->flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF);
+	if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
+		sc->rxon->flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ);
+	if (ic->ic_flags & IEEE80211_F_SHSLOT)
+		sc->rxon->flags |= htole32(IWN_RXON_SHSLOT);
+	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
+		sc->rxon->flags |= htole32(IWN_RXON_SHPREAMBLE);
+	if (IEEE80211_IS_CHAN_A(ni->ni_chan)) {
+		sc->rxon->cck_mask  = 0;
+		sc->rxon->ofdm_mask = 0x15;
+	} else if (IEEE80211_IS_CHAN_B(ni->ni_chan)) {
+		sc->rxon->cck_mask  = 0x03;
+		sc->rxon->ofdm_mask = 0;
+	} else {
+		/* Assume 802.11b/g. */
+		sc->rxon->cck_mask  = 0x0f;
+		sc->rxon->ofdm_mask = 0x15;
+	}
+	DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x cck %x ofdm %x\n",
+	    sc->rxon->chan, sc->rxon->flags, sc->rxon->cck_mask,
+	    sc->rxon->ofdm_mask);
+	sc->rxon->mode = IWN_MODE_2STA;
+	error = iwn_cmd(sc, IWN_CMD_WIPAN_RXON, sc->rxon, sc->rxonsz, 0);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "%s: RXON command failed, error %d\n",
+		    __func__, error);
+		return error;
+	}
+
+	/* Configuration has changed, set TX power accordingly. */
+	if ((error = ops->set_txpower(sc, ni->ni_chan, 1)) != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: could not set TX power, error %d\n", __func__, error);
+		return error;
+	}
+	/*
+	 * Reconfiguring RXON clears the firmware nodes table so we must
+	 * add the broadcast node again.
+	 */
+	if ((error = iwn_add_broadcast_node_pan(sc, 0)) != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: could not add broadcast node, error %d\n", __func__,
+		    error);
+		return error;
+	}
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__);
+
+	return 0;
+}
+
+static int
+iwn_set_timing_pan(struct iwn_softc *sc)
+{
+	struct iwn_cmd_timing cmd;
+	int error = 0;
+	struct ieee80211vap *vap;
+	struct iwn_vap *ivp;
+
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
+
+	vap = sc->ivap[IWN_RXON_PAN_CTX];
+	ivp = IWN_VAP(vap);
+
+	if ((error = iwn_config_pan(sc)) != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: iwn_config1 error %d\n", __func__, error);
+		return error;
+	}
+
+	if ((error = iwn_set_pan_params(sc)) != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: iwn_set_pan_params error %d\n", __func__, error);
+		return error;
+	}
+
+	memset(&cmd, 0, sizeof cmd);
+	cmd.lintval = htole16(10);
+	cmd.bintval = htole16(IWN_BEACON_INTERVAL_DEFAULT);
+	ivp->beacon_int = cmd.bintval;
+	cmd.binitval = htole32(0x032000);
+	cmd.dtim_period = 1;
+
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__);
+
+	return iwn_cmd(sc, IWN_CMD_WIPAN_RXON_TIMING, &cmd, sizeof cmd, 0);
+}
+static int
+iwn_run_pan(struct iwn_softc *sc, struct ieee80211vap *vap)
+{
+	struct iwn_ops *ops = &sc->ops;
+	struct ifnet *ifp = sc->sc_ifp;
+	struct ieee80211com *ic = ifp->if_l2com;
+	struct ieee80211_node *ni = vap->iv_bss;
+	struct iwn_vap *ivp = IWN_VAP(vap);
+	struct iwn_node_info node;
+	uint32_t htflags = 0;
+	int error;
+
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
+
+	if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+		/* Link LED blinks while monitoring. */
+		return 0;
+	}
+
+	if ((error = iwn_set_timing_pan(sc)) != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: could not set timing, error %d\n", __func__, error);
+	}
+
+	if ((error = iwn_updateedca_pan(ic)) != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: iwn_updateedca_pan, error %d\n", __func__, error);
+		return error;
+	}
+
+	sc->rxon = &sc->rx_on[IWN_RXON_PAN_CTX];
+	IEEE80211_ADDR_COPY(sc->rxon->myaddr, ivp->macaddr);
+	IEEE80211_ADDR_COPY(sc->rxon->wlap, IF_LLADDR(ifp));
+	/* Update adapter configuration. */
+	IEEE80211_ADDR_COPY(sc->rxon->bssid, ni->ni_bssid);
+	sc->rxon->associd = htole16(IEEE80211_AID(ni->ni_associd));
+	sc->rxon->chan = ieee80211_chan2ieee(ic, ni->ni_chan);
+	sc->rxon->flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF);
+	if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
+		sc->rxon->flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ);
+	if (ic->ic_flags & IEEE80211_F_SHSLOT)
+		sc->rxon->flags |= htole32(IWN_RXON_SHSLOT);
+	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
+		sc->rxon->flags |= htole32(IWN_RXON_SHPREAMBLE);
+	if (IEEE80211_IS_CHAN_A(ni->ni_chan)) {
+		sc->rxon->cck_mask  = 0;
+		sc->rxon->ofdm_mask = 0x15;
+	} else if (IEEE80211_IS_CHAN_B(ni->ni_chan)) {
+		sc->rxon->cck_mask  = 0x03;
+		sc->rxon->ofdm_mask = 0;
+	} else {
+		/* Assume 802.11b/g. */
+		sc->rxon->cck_mask  = 0x0f;
+		sc->rxon->ofdm_mask = 0x15;
+	}
+	if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {
+		htflags |= IWN_RXON_HT_PROTMODE(ic->ic_curhtprotmode);
+		if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
+			switch (ic->ic_curhtprotmode) {
+			case IEEE80211_HTINFO_OPMODE_HT20PR:
+				htflags |= IWN_RXON_HT_MODEPURE40;
+				break;
+			default:
+				htflags |= IWN_RXON_HT_MODEMIXED;
+				break;
+			}
+		}
+		if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
+			htflags |= IWN_RXON_HT_HT40MINUS;
+	}
+	sc->rxon->flags |= htole32(htflags);
+	sc->rxon->filter |= htole32(IWN_FILTER_BSS);
+	DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x\n",
+	    sc->rxon->chan, sc->rxon->flags);
+	sc->rxon->mode = IWN_MODE_2STA;
+	error = iwn_cmd(sc, IWN_CMD_WIPAN_RXON, sc->rxon, sc->rxonsz, 0);
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: could not update configuration, error %d\n", __func__,
+		    error);
+		return error;
+	}
+
+	/* Configuration has changed, set TX power accordingly. */
+	if ((error = ops->set_txpower(sc, ni->ni_chan, 1)) != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: could not set TX power, error %d\n", __func__, error);
+		return error;
+	}
+
+	/* Fake a join to initialize the TX rate. */
+	((struct iwn_node *)ni)->id = IWN_STA_ID;
+	iwn_newassoc(ni, 1);
+
+	/* Add BSS node. */
+	memset(&node, 0, sizeof node);
+	node.htflags |= htole32(IWN_STA_FLAG_PAN_STATION);
+	IEEE80211_ADDR_COPY(node.macaddr, ni->ni_macaddr);
+	node.id = IWN_STA_ID;
+	if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {
+		switch (ni->ni_htcap & IEEE80211_HTCAP_SMPS) {
+		case IEEE80211_HTCAP_SMPS_ENA:
+			node.htflags |= htole32(IWN_SMPS_MIMO_DIS);
+			break;
+		case IEEE80211_HTCAP_SMPS_DYNAMIC:
+			node.htflags |= htole32(IWN_SMPS_MIMO_PROT);
+			break;
+		}
+		node.htflags |= htole32(IWN_AMDPU_SIZE_FACTOR(3) |
+		    IWN_AMDPU_DENSITY(5));	/* 4us */
+		if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
+			node.htflags |= htole32(IWN_NODE_HT40);
+	}
+	DPRINTF(sc, IWN_DEBUG_STATE, "%s: adding BSS node1\n", __func__);
+	error = ops->add_node(sc, &node, 0);
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: could not add BSS node1, error %d\n", __func__, error);
+		return error;
+	}
+
+	/* Setting the initial rate for node */
+	ni->ni_txrate = ni->ni_rates.rs_rates[0];
+
+	/* XXX: init rate scaling */
+
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__);
+
+#ifdef IWN_DTIM_INDICATES_UNICAST_PENDING_AT_AP
+	return iwn_set_pslevel(sc, IWN_POWERSAVE_DTIM_VOIP_COMPATIBLE,
+	    sc->desired_pwrsave_level, 0);
+#else
+	return 0;
+#endif
+
+}
+
+static int
+iwn_config_pan(struct iwn_softc *sc)
+{
+	struct ifnet *ifp = sc->sc_ifp;
+	struct ieee80211com *ic = ifp->if_l2com;
+	struct ieee80211vap *vap = sc->ivap[IWN_RXON_PAN_CTX];
+	struct iwn_vap *ivp = IWN_VAP(vap);
+	uint16_t rxchain;
+	int error;
+
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
+
+	sc->rxon = &sc->rx_on[IWN_RXON_PAN_CTX];
+	IEEE80211_ADDR_COPY(sc->rxon->myaddr, ivp->macaddr);
+	IEEE80211_ADDR_COPY(sc->rxon->wlap, IF_LLADDR(ifp));
+	sc->rxon->chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
+	sc->rxon->flags = htole32(IWN_RXON_TSF);
+	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
+		sc->rxon->flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ);
+	sc->rxon->mode = IWN_MODE_P2P;
+	sc->rxon->filter = htole32(IWN_FILTER_MULTICAST);
+	sc->rxon->cck_mask  = 0x0f;	/* not yet negotiated */
+	sc->rxon->ofdm_mask = 0xff;	/* not yet negotiated */
+	sc->rxon->ht_single_mask = 0xff;
+	sc->rxon->ht_dual_mask = 0xff;
+	sc->rxon->ht_triple_mask = 0xff;
+	rxchain =
+	    IWN_RXCHAIN_VALID(sc->rxchainmask) |
+	    IWN_RXCHAIN_MIMO_COUNT(2) |
+	    IWN_RXCHAIN_IDLE_COUNT(2);
+	sc->rxon->rxchain = htole16(rxchain);
+	sc->rxon->associd = 0;
+	sc->rxon->filter &= ~htole32(IWN_FILTER_BSS);
+
+	error = iwn_cmd(sc, IWN_CMD_WIPAN_RXON, sc->rxon, sc->rxonsz, 0);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "%s: IWN_CMD_WIPAN_RXON command failed\n",
+		    __func__);
+		return error;
+	}
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__);
+
+	return 0;
+}
+
+int
+iwn_set_pan_params(struct iwn_softc *sc)
+{
+	struct iwn_pan_params_cmd cmd;
+	int slot0 = 300, slot1 = 0;
+	int bcnint;
+	int error = 0;
+
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
+
+	/*
+	 * If the PAN context is inactive, then we don't need
+	 * to update the PAN parameters
+	 */
+	if (sc->ctx != IWN_RXON_PAN_CTX) {
+		DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end with no need to do that\n",
+		    __func__);
+		return 0;
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	/* only 2 slots are currently allowed */
+	cmd.num_slots = 2;
+
+	cmd.slots[0].type = IWN_RXON_BSS_CTX;	/* BSS */
+	cmd.slots[1].type = IWN_RXON_PAN_CTX;	/* PAN */
+
+	cmd.flags |= htole16(IWN_PAN_PARAMS_FLG_SLOTTED_MODE);
+	bcnint = IWN_BEACON_INTERVAL_DEFAULT;
+	slot0 = (bcnint >> 1);
+	slot1 = (bcnint - slot0);
+
+	if(sc->uc_scan_progress == 1) {
+		slot0 = bcnint * 3 - IWN_SLOT_TIME_MIN;
+		slot1 = IWN_SLOT_TIME_MIN;
+	}
+	cmd.slots[0].time = htole16(slot0);
+	cmd.slots[1].time = htole16(slot1);
+
+	error = iwn_cmd(sc, IWN_CMD_WIPAN_PARAMS, &cmd, sizeof(cmd), 0);
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: IWN_CMD_WIPAN_PARAMS command failed, error %d\n",
+		    __func__, error);
+		return error;
+	}
+
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__);
+
+	return 0;
+}
+
+static int
+iwn_updateedca_pan(struct ieee80211com *ic)
+{
+#define IWN_EXP2(x)	((1 << (x)) - 1)	/* CWmin = 2^ECWmin - 1 */
+	struct iwn_softc *sc = ic->ic_ifp->if_softc;
+	struct iwn_edca_params cmd;
+	int aci;
+
+	memset(&cmd, 0, sizeof cmd);
+	cmd.flags = htole32(IWN_EDCA_UPDATE);
+	for (aci = 0; aci < WME_NUM_AC; aci++) {
+		const struct wmeParams *ac =
+		    &ic->ic_wme.wme_chanParams.cap_wmeParams[aci];
+		cmd.ac[aci].aifsn = ac->wmep_aifsn;
+		cmd.ac[aci].cwmin = htole16(IWN_EXP2(ac->wmep_logcwmin));
+		cmd.ac[aci].cwmax = htole16(IWN_EXP2(ac->wmep_logcwmax));
+		cmd.ac[aci].txoplimit =
+		    htole16(IEEE80211_TXOP_TO_US(ac->wmep_txopLimit));
+	}
+	return iwn_cmd(sc, IWN_CMD_WIPAN_QOS_PARAM, &cmd, sizeof cmd, 1);
+#undef IWN_EXP2
+}
+
+/*
+ * Broadcast node is used to send group-addressed and management frames.
+ */
+static int
+iwn_add_broadcast_node_pan(struct iwn_softc *sc, int async)
+{
+	struct iwn_ops *ops = &sc->ops;
+	struct ifnet *ifp = sc->sc_ifp;
+	struct ieee80211com *ic = ifp->if_l2com;
+	struct iwn_node_info node;
+	struct iwn_cmd_link_quality linkq;
+	uint8_t txant;
+	int i, error;
+
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
+
+	sc->rxon = &sc->rx_on[IWN_RXON_PAN_CTX];
+
+	memset(&node, 0, sizeof node);
+	IEEE80211_ADDR_COPY(node.macaddr, ifp->if_broadcastaddr);
+
+	node.id = IWN_PAN_ID_BCAST;
+	node.htflags |= htole32(IWN_STA_FLAG_PAN_STATION);
+	DPRINTF(sc, IWN_DEBUG_RESET, "%s: adding broadcast node1\n", __func__);
+	if ((error = ops->add_node(sc, &node, async)) != 0)
+		return error;
+
+	/* Use the first valid TX antenna. */
+	txant = IWN_LSB(sc->txchainmask);
+
+	memset(&linkq, 0, sizeof linkq);
+	linkq.id = IWN_PAN_ID_BCAST;
+	linkq.antmsk_1stream = txant;
+	linkq.antmsk_2stream = IWN_ANT_AB;
+	linkq.ampdu_max = 64;
+	linkq.ampdu_threshold = 3;
+	linkq.ampdu_limit = htole16(4000);	/* 4ms */
+
+	/* Use lowest mandatory bit-rate. */
+	if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
+		linkq.retry[0] = htole32(0xd);
+	else
+		linkq.retry[0] = htole32(10 | IWN_RFLAG_CCK);
+	linkq.retry[0] |= htole32(IWN_RFLAG_ANT(txant));
+	/* Use same bit-rate for all TX retries. */
+	for (i = 1; i < IWN_MAX_TX_RETRIES; i++) {
+		linkq.retry[i] = linkq.retry[0];
+	}
+	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__);
+
+	return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, async);
+}
+
Index: sys/dev/iwn/if_iwn_pan.h
===================================================================
--- sys/dev/iwn/if_iwn_pan.h	(revision 0)
+++ sys/dev/iwn/if_iwn_pan.h	(working copy)
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2013 Cedric GROSS <cg@cgross.info>
+ *
+ * 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_IWN_PAN_H__
+#define	__IF_IWN_PAN_H__
+/*
+ * ADD / MODIFY STATION Command (Op Code 18) -  byte 76-18 -bit13
+ * STA_FLAG_PAN_STATION bit:
+ * This bit is set (1) for a station in PAN mode
+ */
+#define IWN_STA_FLAG_PAN_STATION		(1 << 13)
+
+#define IWN_BEACON_INTERVAL_DEFAULT		200
+#define IWN_SLOT_TIME_MIN		20
+
+extern	int iwn_newstate_pan(struct ieee80211vap *, enum ieee80211_state, int);
+extern	int iwn_set_pan_params(struct iwn_softc *);
+
+#endif
Index: sys/dev/iwn/if_iwnreg.h
===================================================================
--- sys/dev/iwn/if_iwnreg.h	(revision 254271)
+++ sys/dev/iwn/if_iwnreg.h	(working copy)
@@ -2052,3 +2052,36 @@
 #define IWN_BARRIER_READ_WRITE(sc)					\
 	bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz,	\
 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
+
+#ifdef	IWN_DEBUG
+enum {
+	IWN_DEBUG_XMIT		= 0x00000001,	/* basic xmit operation */
+	IWN_DEBUG_RECV		= 0x00000002,	/* basic recv operation */
+	IWN_DEBUG_STATE		= 0x00000004,	/* 802.11 state transitions */
+	IWN_DEBUG_TXPOW		= 0x00000008,	/* tx power processing */
+	IWN_DEBUG_RESET		= 0x00000010,	/* reset processing */
+	IWN_DEBUG_OPS		= 0x00000020,	/* iwn_ops processing */
+	IWN_DEBUG_BEACON	= 0x00000040,	/* beacon handling */
+	IWN_DEBUG_WATCHDOG 	= 0x00000080,	/* watchdog timeout */
+	IWN_DEBUG_INTR		= 0x00000100,	/* ISR */
+	IWN_DEBUG_CALIBRATE	= 0x00000200,	/* periodic calibration */
+	IWN_DEBUG_NODE		= 0x00000400,	/* node management */
+	IWN_DEBUG_LED		= 0x00000800,	/* led management */
+	IWN_DEBUG_CMD		= 0x00001000,	/* cmd submission */
+	IWN_DEBUG_TXRATE	= 0x00002000,	/* TX rate debugging */
+	IWN_DEBUG_PWRSAVE	= 0x00004000,	/* Power save operations */
+	IWN_DEBUG_REGISTER	= 0x20000000,	/* print chipset register */
+	IWN_DEBUG_TRACE		= 0x40000000,	/* Print begin and start driver function */
+	IWN_DEBUG_FATAL		= 0x80000000,	/* fatal errors */
+	IWN_DEBUG_ANY		= 0xffffffff
+};
+
+#define DPRINTF(sc, m, fmt, ...) do {			\
+	if (sc->sc_debug & (m))				\
+		printf(fmt, __VA_ARGS__);		\
+} while (0)
+
+#else
+#define DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0)
+#endif
+
Index: sys/dev/iwn/if_iwnvar.h
===================================================================
--- sys/dev/iwn/if_iwnvar.h	(revision 254271)
+++ sys/dev/iwn/if_iwnvar.h	(working copy)
@@ -391,6 +391,12 @@
 	struct iwn_base_params *base_params;
 };
 
+extern	int iwn_cmd(struct iwn_softc *, int, const void *, int, int);
+extern	void iwn_newassoc(struct ieee80211_node *, int);
+#ifdef	IWN_DEBUG
+extern	const char *iwn_intr_str(uint8_t);
+#endif
+
 #define IWN_LOCK_INIT(_sc) \
 	mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \
 	    MTX_NETWORK_LOCK, MTX_DEF)
Index: sys/modules/iwn/Makefile
===================================================================
--- sys/modules/iwn/Makefile	(revision 254271)
+++ sys/modules/iwn/Makefile	(working copy)
@@ -3,6 +3,7 @@
 .PATH:  ${.CURDIR}/../../dev/iwn
 
 KMOD    = if_iwn
-SRCS    = if_iwn.c device_if.h bus_if.h pci_if.h opt_iwn.h opt_wlan.h
+SRCS    = if_iwn.c if_iwn_pan.c device_if.h bus_if.h pci_if.h
+SRCS	+= opt_iwn.h opt_wlan.h
 
 .include <bsd.kmod.mk>
help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?000c01ce97f3$e0178d10$a046a730$>