From 92d485220134cae42bad5e6d43661f3d923907df Mon Sep 17 00:00:00 2001 From: damien Date: Mon, 19 Sep 2005 18:59:04 +0000 Subject: 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 --- sys/dev/iwi/if_iwi.c | 107 ++++++++++++++++++++++++++++++------------------ sys/dev/iwi/if_iwireg.h | 2 +- sys/dev/iwi/if_iwivar.h | 12 ++++-- 3 files changed, 76 insertions(+), 45 deletions(-) (limited to 'sys/dev/iwi') 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; -- cgit v1.1