summaryrefslogtreecommitdiffstats
path: root/sys/dev/iwi
diff options
context:
space:
mode:
authordamien <damien@FreeBSD.org>2005-09-19 18:59:04 +0000
committerdamien <damien@FreeBSD.org>2005-09-19 18:59:04 +0000
commit92d485220134cae42bad5e6d43661f3d923907df (patch)
tree66d0ab4186e70a2b4dd52ee881b3cf545553171b /sys/dev/iwi
parent59a2d9694438c06ffd2a5a0730bbb1396eee15bf (diff)
downloadFreeBSD-src-92d485220134cae42bad5e6d43661f3d923907df.zip
FreeBSD-src-92d485220134cae42bad5e6d43661f3d923907df.tar.gz
Use phk's kernel unit number allocator to associate unique ids to neighbors
in an IBSS. Store ids directly into ieee80211_node's instead of managing our own private association table. Idea and code by Sam Leffler. Submitted by: sam MFC after: 5 days
Diffstat (limited to 'sys/dev/iwi')
-rw-r--r--sys/dev/iwi/if_iwi.c107
-rw-r--r--sys/dev/iwi/if_iwireg.h2
-rw-r--r--sys/dev/iwi/if_iwivar.h12
3 files changed, 76 insertions, 45 deletions
diff --git a/sys/dev/iwi/if_iwi.c b/sys/dev/iwi/if_iwi.c
index 95e75aa..40e716d 100644
--- a/sys/dev/iwi/if_iwi.c
+++ b/sys/dev/iwi/if_iwi.c
@@ -116,12 +116,13 @@ static int iwi_alloc_rx_ring(struct iwi_softc *, struct iwi_rx_ring *,
int);
static void iwi_reset_rx_ring(struct iwi_softc *, struct iwi_rx_ring *);
static void iwi_free_rx_ring(struct iwi_softc *, struct iwi_rx_ring *);
+static struct ieee80211_node *iwi_node_alloc(struct ieee80211_node_table *);
+static void iwi_node_free(struct ieee80211_node *);
static int iwi_media_change(struct ifnet *);
static void iwi_media_status(struct ifnet *, struct ifmediareq *);
static int iwi_newstate(struct ieee80211com *, enum ieee80211_state, int);
static int iwi_wme_update(struct ieee80211com *);
static uint16_t iwi_read_prom_word(struct iwi_softc *, uint8_t);
-static int iwi_find_txnode(struct iwi_softc *, const uint8_t *);
static void iwi_fix_channel(struct ieee80211com *, struct mbuf *);
static void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *, int,
struct iwi_frame *);
@@ -130,6 +131,7 @@ static void iwi_rx_intr(struct iwi_softc *);
static void iwi_tx_intr(struct iwi_softc *, struct iwi_tx_ring *);
static void iwi_intr(void *);
static int iwi_cmd(struct iwi_softc *, uint8_t, void *, uint8_t, int);
+static void iwi_write_ibssnode(struct iwi_softc *, const struct iwi_node *);
static int iwi_tx_start(struct ifnet *, struct mbuf *,
struct ieee80211_node *, int);
static void iwi_start(struct ifnet *);
@@ -237,6 +239,8 @@ iwi_attach(device_t dev)
mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
MTX_DEF | MTX_RECURSE);
+ sc->sc_unr = new_unrhdr(0, IWI_MAX_IBSSNODE, &sc->sc_mtx);
+
if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
device_printf(dev, "chip is in D%d power mode "
"-- setting to D0\n", pci_get_powerstate(dev));
@@ -388,6 +392,10 @@ iwi_attach(device_t dev)
}
ieee80211_ifattach(ic);
+ /* override default methods */
+ ic->ic_node_alloc = iwi_node_alloc;
+ sc->sc_node_free = ic->ic_node_free;
+ ic->ic_node_free = iwi_node_free;
/* override state transition machine */
sc->sc_newstate = ic->ic_newstate;
ic->ic_newstate = iwi_newstate;
@@ -487,6 +495,9 @@ iwi_detach(device_t dev)
if (ifp != NULL)
if_free(ifp);
+ if (sc->sc_unr != NULL)
+ delete_unrhdr(sc->sc_unr);
+
mtx_destroy(&sc->sc_mtx);
return 0;
@@ -829,6 +840,33 @@ iwi_resume(device_t dev)
return 0;
}
+static struct ieee80211_node *
+iwi_node_alloc(struct ieee80211_node_table *nt)
+{
+ struct iwi_node *in;
+
+ in = malloc(sizeof (struct iwi_node), M_80211_NODE, M_NOWAIT | M_ZERO);
+ if (in == NULL)
+ return NULL;
+
+ in->in_station = -1;
+
+ return &in->in_node;
+}
+
+static void
+iwi_node_free(struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct iwi_softc *sc = ic->ic_ifp->if_softc;
+ struct iwi_node *in = (struct iwi_node *)ni;
+
+ if (in->in_station != -1)
+ free_unr(sc->sc_unr, in->in_station);
+
+ sc->sc_node_free(ni);
+}
+
static int
iwi_media_change(struct ifnet *ifp)
{
@@ -852,8 +890,8 @@ iwi_media_change(struct ifnet *ifp)
}
/*
- * The firmware automaticly adapt the transmit speed. We report the current
- * transmit speed here.
+ * The firmware automatically adapts the transmit speed. We report its current
+ * value here.
*/
static void
iwi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
@@ -925,7 +963,6 @@ iwi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
if (sc->flags & IWI_FLAG_SCANNING)
break;
- sc->nsta = 0; /* flush IBSS nodes */
ieee80211_node_table_reset(&ic->ic_scan);
ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN;
sc->flags |= IWI_FLAG_SCANNING;
@@ -1081,37 +1118,6 @@ iwi_read_prom_word(struct iwi_softc *sc, uint8_t addr)
}
/*
- * This is only used for IBSS mode where the firmware expect an index to an
- * internal node table instead of a destination address.
- */
-static int
-iwi_find_txnode(struct iwi_softc *sc, const uint8_t *macaddr)
-{
- struct iwi_node node;
- int i;
-
- for (i = 0; i < sc->nsta; i++)
- if (IEEE80211_ADDR_EQ(sc->sta[i], macaddr))
- return i; /* already existing node */
-
- if (i == IWI_MAX_NODE)
- return -1; /* no place left in neighbor table */
-
- /* save this new node in our softc table */
- IEEE80211_ADDR_COPY(sc->sta[i], macaddr);
- sc->nsta = i;
-
- /* write node information into NIC memory */
- memset(&node, 0, sizeof node);
- IEEE80211_ADDR_COPY(node.bssid, macaddr);
-
- CSR_WRITE_REGION_1(sc, IWI_CSR_NODE_BASE + i * sizeof node,
- (uint8_t *)&node, sizeof node);
-
- return i;
-}
-
-/*
* XXX: Hack to set the current channel to the value advertised in beacons or
* probe responses. Only used during AP detection.
*/
@@ -1470,12 +1476,27 @@ iwi_cmd(struct iwi_softc *sc, uint8_t type, void *data, uint8_t len, int async)
return async ? 0 : msleep(sc, &sc->sc_mtx, 0, "iwicmd", hz);
}
+static void
+iwi_write_ibssnode(struct iwi_softc *sc, const struct iwi_node *in)
+{
+ struct iwi_ibssnode node;
+
+ /* write node information into NIC memory */
+ memset(&node, 0, sizeof node);
+ IEEE80211_ADDR_COPY(node.bssid, in->in_node.ni_macaddr);
+
+ CSR_WRITE_REGION_1(sc,
+ IWI_CSR_NODE_BASE + in->in_station * sizeof node,
+ (uint8_t *)&node, sizeof node);
+}
+
static int
iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni,
int ac)
{
struct iwi_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
+ struct iwi_node *in = (struct iwi_node *)ni;
struct ieee80211_frame *wh;
struct ieee80211_key *k;
const struct chanAccParams *cap;
@@ -1484,7 +1505,7 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni,
struct iwi_tx_desc *desc;
struct mbuf *mnew;
bus_dma_segment_t segs[IWI_MAX_NSEG];
- int error, nsegs, hdrlen, i, station = 0, noack = 0;
+ int error, nsegs, hdrlen, i, noack = 0;
wh = mtod(m0, struct ieee80211_frame *);
@@ -1495,14 +1516,19 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni,
} else
hdrlen = sizeof (struct ieee80211_frame);
- if (ic->ic_opmode == IEEE80211_M_IBSS) {
- station = iwi_find_txnode(sc, wh->i_addr1);
- if (station == -1) {
+ /*
+ * This is only used in IBSS mode where the firmware expect an index
+ * in a h/w table instead of a destination address.
+ */
+ if (ic->ic_opmode == IEEE80211_M_IBSS && in->in_station == -1) {
+ in->in_station = alloc_unr(sc->sc_unr);
+ if (in->in_station == -1) { /* h/w table is full */
m_freem(m0);
ieee80211_free_node(ni);
ifp->if_oerrors++;
return 0;
}
+ iwi_write_ibssnode(sc, in);
}
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
@@ -1566,7 +1592,8 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni,
desc->hdr.type = IWI_HDR_TYPE_DATA;
desc->hdr.flags = IWI_HDR_FLAG_IRQ;
- desc->station = station;
+ desc->station =
+ (ic->ic_opmode == IEEE80211_M_IBSS) ? in->in_station : 0;
desc->cmd = IWI_DATA_CMD_TX;
desc->len = htole16(m0->m_pkthdr.len);
desc->flags = 0;
diff --git a/sys/dev/iwi/if_iwireg.h b/sys/dev/iwi/if_iwireg.h
index fa42bc2..e77d437 100644
--- a/sys/dev/iwi/if_iwireg.h
+++ b/sys/dev/iwi/if_iwireg.h
@@ -271,7 +271,7 @@ struct iwi_cmd_desc {
} __packed;
/* node information (IBSS) */
-struct iwi_node {
+struct iwi_ibssnode {
uint8_t bssid[IEEE80211_ADDR_LEN];
uint8_t reserved[2];
} __packed;
diff --git a/sys/dev/iwi/if_iwivar.h b/sys/dev/iwi/if_iwivar.h
index 1927bfa..82d5e93 100644
--- a/sys/dev/iwi/if_iwivar.h
+++ b/sys/dev/iwi/if_iwivar.h
@@ -110,14 +110,22 @@ struct iwi_rx_ring {
int cur;
};
+struct iwi_node {
+ struct ieee80211_node in_node;
+ int in_station;
+#define IWI_MAX_IBSSNODE 32
+};
+
struct iwi_softc {
struct ifnet *sc_ifp;
struct ieee80211com sc_ic;
int (*sc_newstate)(struct ieee80211com *,
enum ieee80211_state, int);
+ void (*sc_node_free)(struct ieee80211_node *);
device_t sc_dev;
struct mtx sc_mtx;
+ struct unrhdr *sc_unr;
struct iwi_firmware fw;
uint32_t flags;
@@ -130,10 +138,6 @@ struct iwi_softc {
struct iwi_tx_ring txq[WME_NUM_AC];
struct iwi_rx_ring rxq;
-#define IWI_MAX_NODE 32
- uint8_t sta[IWI_MAX_NODE][IEEE80211_ADDR_LEN];
- uint8_t nsta;
-
struct resource *irq;
struct resource *mem;
bus_space_tag_t sc_st;
OpenPOWER on IntegriCloud