Date: Sun, 11 Aug 2013 15:09:54 +0200 From: "Cedric GROSS" <cg@cgross.info> To: <freebsd-wireless@freebsd.org> Subject: [iwn]Review Split 6 Message-ID: <001d01ce9694$142db8b0$3c892a10$@info>
index | next in thread | raw e-mail
[-- Attachment #1 --]
Hello,
Here is patch split 6.
It's follow split 5 as it implement PAN context.
This patch is purely based on work done by Sean Bruno.
Cedric
[-- Attachment #2 --]
Index: sys/dev/iwn/if_iwn.c
===================================================================
--- sys/dev/iwn/if_iwn.c (revision 254210)
+++ sys/dev/iwn/if_iwn.c (working copy)
@@ -330,7 +330,16 @@
static char *iwn_get_csr_string(int);
static void iwn_debug_register(struct iwn_softc *);
#endif
+static int iwn_newstate_u1(struct ieee80211vap *, enum ieee80211_state, int);
+static int iwn_auth_u1(struct iwn_softc *, struct ieee80211vap *);
+static int iwn_run_u1(struct iwn_softc *, struct ieee80211vap *);
+static int iwn_set_timing_u1(struct iwn_softc *);
+static int iwn_config_u1(struct iwn_softc *);
+static int iwn_set_pan_params(struct iwn_softc *);
+static int iwn_updateedca_u1(struct ieee80211com *);
+static int iwn_add_broadcast_node_u1(struct iwn_softc *, int);
+
#ifdef IWN_DEBUG
enum {
IWN_DEBUG_XMIT = 0x00000001, /* basic xmit operation */
@@ -919,6 +928,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 +941,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_u1;
+ 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 +974,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);
@@ -2794,6 +2828,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 +2840,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 +3035,20 @@
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 +3204,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 +3237,10 @@
{
struct iwn_beacon_missed *miss =
(struct iwn_beacon_missed *)(desc + 1);
- int misses;
+ int misses,iv_bmissthreshold;
+ int DoReinit =0 ;
+ struct ieee80211vap *vap0 = sc->ivap[IWN_RXON_BSS_CTX];
+ struct ieee80211vap *vap1 = sc->ivap[IWN_RXON_PAN_CTX];
bus_dmamap_sync(sc->rxq.data_dmat, data->map,
BUS_DMASYNC_POSTREAD);
@@ -3194,17 +3247,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 +3635,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 +3668,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 +3777,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 +3812,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 +3929,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 +4019,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);
@@ -4207,13 +4283,13 @@
static 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 +4296,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 +5628,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 +5644,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 +5680,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 +5721,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 +5873,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 +6521,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 +6545,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);
@@ -7621,3 +7735,510 @@
DPRINTF(sc, IWN_DEBUG_REGISTER,"%s","\n");
}
#endif
+static int
+iwn_newstate_u1(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_u1(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_u1(sc)) != 0) {
+ device_printf(sc->sc_dev,
+ "%s: iwn_set_timing_u1 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_u1(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_u1(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_u1(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_run_u1(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_node_info node;
+ uint32_t htflags = 0;
+ int error;
+ struct iwn_vap *ivp = IWN_VAP(vap);
+
+ 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_u1(sc)) != 0) {
+ device_printf(sc->sc_dev,
+ "%s: could not set timing, error %d\n", __func__, error);
+ }
+
+ if ((error = iwn_updateedca_u1(ic)) != 0) {
+ device_printf(sc->sc_dev,
+ "%s: iwn_updateedca_u1, 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_set_timing_u1(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_u1(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_config_u1(struct iwn_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ uint16_t rxchain;
+ int error;
+ struct ieee80211vap *vap = sc->ivap[IWN_RXON_PAN_CTX];
+ 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));
+ 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;
+}
+
+static 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_u1(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_u1(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_iwnreg.h
===================================================================
--- sys/dev/iwn/if_iwnreg.h (revision 254210)
+++ sys/dev/iwn/if_iwnreg.h (working copy)
@@ -1689,6 +1689,16 @@
} __packed;
/*
+ * 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
+
+/*
* Offsets of channels descriptions in EEPROM.
*/
static const uint32_t iwn4965_regulatory_bands[IWN_NBANDS] = {
home |
help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?001d01ce9694$142db8b0$3c892a10$>
