merged changes from 8.2 FreeBSD release for most wlan drivers and net80211.

updated several firmwares for iprowifi4965 and iprowifi3945. Tested on iprowifi4965 only.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41240 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval
2011-04-11 22:48:42 +00:00
parent 19c52a6cec
commit 8dc03de632
54 changed files with 1498 additions and 768 deletions
@@ -773,8 +773,8 @@ an_attach(struct an_softc *sc, int unit, int flags)
ifp->if_watchdog = an_watchdog;
ifp->if_init = an_init;
ifp->if_baudrate = 10000000;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
IFQ_SET_READY(&ifp->if_snd);
bzero(sc->an_config.an_nodename, sizeof(sc->an_config.an_nodename));
@@ -64,8 +64,8 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_regdomain.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_phy.h>
#include <net80211/ieee80211_ratectl.h>
#include <net/bpf.h>
@@ -112,9 +112,6 @@ static void bwi_set_channel(struct ieee80211com *);
static void bwi_scan_end(struct ieee80211com *);
static int bwi_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void bwi_updateslot(struct ifnet *);
static struct ieee80211_node *bwi_node_alloc(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN]);
static void bwi_newassoc(struct ieee80211_node *, int);
static int bwi_media_change(struct ifnet *);
static void bwi_calibrate(void *);
@@ -465,8 +462,8 @@ bwi_attach(struct bwi_softc *sc)
ifp->if_ioctl = bwi_ioctl;
ifp->if_start = bwi_start;
ifp->if_watchdog = bwi_watchdog;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
IFQ_SET_READY(&ifp->if_snd);
/*
@@ -525,7 +522,6 @@ bwi_attach(struct bwi_softc *sc)
ic->ic_vap_delete = bwi_vap_delete;
ic->ic_raw_xmit = bwi_raw_xmit;
ic->ic_updateslot = bwi_updateslot;
ic->ic_node_alloc = bwi_node_alloc;
ic->ic_scan_start = bwi_scan_start;
ic->ic_scan_end = bwi_scan_end;
ic->ic_set_channel = bwi_set_channel;
@@ -620,10 +616,7 @@ bwi_vap_create(struct ieee80211com *ic,
#if 0
vap->iv_update_beacon = bwi_beacon_update;
#endif
ieee80211_amrr_init(&bvp->bv_amrr, vap,
IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD,
500 /*ms*/);
ieee80211_ratectl_init(vap);
/* complete setup */
ieee80211_vap_attach(vap, bwi_media_change, ieee80211_media_status);
@@ -636,7 +629,7 @@ bwi_vap_delete(struct ieee80211vap *vap)
{
struct bwi_vap *bvp = BWI_VAP(vap);
ieee80211_amrr_cleanup(&bvp->bv_amrr);
ieee80211_ratectl_deinit(vap);
ieee80211_vap_detach(vap);
free(bvp, M_80211_VAP);
}
@@ -1782,7 +1775,6 @@ bwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
enum ieee80211_state ostate = vap->iv_state;
struct bwi_softc *sc = ifp->if_softc;
struct bwi_mac *mac;
struct ieee80211_node *ni = vap->iv_bss;
int error;
BWI_LOCK(sc);
@@ -1830,10 +1822,6 @@ bwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
#else
sc->sc_txpwrcb_type = BWI_TXPWR_CALIB;
#endif
if (vap->iv_opmode == IEEE80211_M_STA) {
/* fake a join to init the tx rate */
bwi_newassoc(ni, 1);
}
callout_reset(&sc->sc_calib_ch, hz, bwi_calibrate, sc);
}
@@ -1843,25 +1831,6 @@ back:
return error;
}
/* ARGUSED */
static struct ieee80211_node *
bwi_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
{
struct bwi_node *bn;
bn = malloc(sizeof(struct bwi_node), M_80211_NODE, M_NOWAIT | M_ZERO);
return bn != NULL ? &bn->ni : NULL;
}
static void
bwi_newassoc(struct ieee80211_node *ni, int isnew)
{
struct ieee80211vap *vap = ni->ni_vap;
ieee80211_amrr_node_init(&BWI_VAP(vap)->bv_amrr,
&BWI_NODE(ni)->amn, ni);
}
static int
bwi_media_change(struct ifnet *ifp)
{
@@ -3013,7 +2982,7 @@ bwi_encap(struct bwi_softc *sc, int idx, struct mbuf *m,
} else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
rate = rate_fb = tp->ucastrate;
} else {
rix = ieee80211_amrr_choose(ni, &BWI_NODE(ni)->amn);
rix = ieee80211_ratectl_rate(ni, NULL, pkt_len);
rate = ni->ni_txrate;
if (rix > 0) {
@@ -3370,6 +3339,7 @@ _bwi_txeof(struct bwi_softc *sc, uint16_t tx_id, int acked, int data_txcnt)
struct bwi_txbuf *tb;
int ring_idx, buf_idx;
struct ieee80211_node *ni;
struct ieee80211vap *vap;
if (tx_id == 0) {
if_printf(ifp, "%s: zero tx id\n", __func__);
@@ -3395,9 +3365,9 @@ _bwi_txeof(struct bwi_softc *sc, uint16_t tx_id, int acked, int data_txcnt)
ni = tb->tb_ni;
if (tb->tb_ni != NULL) {
struct bwi_node *bn = (struct bwi_node *) tb->tb_ni;
const struct bwi_txbuf_hdr *hdr =
mtod(tb->tb_mbuf, const struct bwi_txbuf_hdr *);
vap = ni->ni_vap;
/* NB: update rate control only for unicast frames */
if (hdr->txh_mac_ctrl & htole32(BWI_TXH_MAC_C_ACK)) {
@@ -3408,8 +3378,9 @@ _bwi_txeof(struct bwi_softc *sc, uint16_t tx_id, int acked, int data_txcnt)
* well so to avoid over-aggressive downshifting we
* treat any number of retries as "1".
*/
ieee80211_amrr_tx_complete(&bn->amn, acked,
data_txcnt > 1);
ieee80211_ratectl_tx_complete(vap, ni,
(data_txcnt > 1) ? IEEE80211_RATECTL_TX_SUCCESS :
IEEE80211_RATECTL_TX_FAILURE, &acked, NULL);
}
/*
@@ -92,7 +92,7 @@ static const struct bwi_dev {
{ PCI_VENDOR_BROADCOM, 0x4318,"Broadcom BCM4318 802.11b/g Wireless Lan" },
{ PCI_VENDOR_BROADCOM, 0x4319,"Broadcom BCM4318 802.11a/b/g Wireless Lan" },
{ PCI_VENDOR_BROADCOM, 0x431a,"Broadcom BCM4318 802.11a Wireless Lan" },
{ 0, 0, NULL}
{ 0, 0, NULL }
};
static int
@@ -533,15 +533,8 @@ struct bwi_rx_radiotap_hdr {
/* TODO: sq */
};
struct bwi_node {
struct ieee80211_node ni; /* must be the first */
struct ieee80211_amrr_node amn;
};
#define BWI_NODE(ni) ((struct bwi_node *)(ni))
struct bwi_vap {
struct ieee80211vap bv_vap;
struct ieee80211_amrr bv_amrr;
int (*bv_newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
};
@@ -180,6 +180,7 @@ static void iwi_release_fw_dma(struct iwi_softc *sc);
static int iwi_config(struct iwi_softc *);
static int iwi_get_firmware(struct iwi_softc *, enum ieee80211_opmode);
static void iwi_put_firmware(struct iwi_softc *);
static void iwi_monitor_scan(void *, int);
static int iwi_scanchan(struct iwi_softc *, unsigned long, int);
static void iwi_scan_start(struct ieee80211com *);
static void iwi_scan_end(struct ieee80211com *);
@@ -292,6 +293,7 @@ iwi_attach(device_t dev)
TASK_INIT(&sc->sc_restarttask, 0, iwi_restart, sc);
TASK_INIT(&sc->sc_disassoctask, 0, iwi_disassoc, sc);
TASK_INIT(&sc->sc_wmetask, 0, iwi_update_wme, sc);
TASK_INIT(&sc->sc_monitortask, 0, iwi_monitor_scan, sc);
callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0);
callout_init_mtx(&sc->sc_rftimer, &sc->sc_mtx, 0);
@@ -363,8 +365,8 @@ iwi_attach(device_t dev)
ifp->if_init = iwi_init;
ifp->if_ioctl = iwi_ioctl;
ifp->if_start = iwi_start;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
IFQ_SET_READY(&ifp->if_snd);
ic->ic_ifp = ifp;
@@ -460,6 +462,7 @@ iwi_detach(device_t dev)
ieee80211_draintask(ic, &sc->sc_radiofftask);
ieee80211_draintask(ic, &sc->sc_restarttask);
ieee80211_draintask(ic, &sc->sc_disassoctask);
ieee80211_draintask(ic, &sc->sc_monitortask);
iwi_stop(sc);
@@ -988,7 +991,8 @@ iwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
* This is all totally bogus and needs to be redone.
*/
iwi_auth_and_assoc(sc, vap);
}
} else if (vap->iv_opmode == IEEE80211_M_MONITOR)
ieee80211_runtask(ic, &sc->sc_monitortask);
break;
case IEEE80211_S_ASSOC:
/*
@@ -1364,7 +1368,7 @@ iwi_checkforqos(struct ieee80211vap *vap,
ni = vap->iv_bss;
ni->ni_capinfo = capinfo;
ni->ni_associd = associd;
ni->ni_associd = associd & 0x3fff;
if (wme != NULL)
ni->ni_flags |= IEEE80211_NODE_QOS;
else
@@ -1407,6 +1411,18 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
IWI_STATE_END(sc, IWI_FW_SCANNING);
/*
* Monitor mode works by doing a passive scan to set
* the channel and enable rx. Because we don't want
* to abort a scan lest the firmware crash we scan
* for a short period of time and automatically restart
* the scan when notified the sweep has completed.
*/
if (vap->iv_opmode == IEEE80211_M_MONITOR) {
ieee80211_runtask(ic, &sc->sc_monitortask);
break;
}
if (scan->status == IWI_SCAN_COMPLETED) {
/* NB: don't need to defer, net80211 does it for us */
ieee80211_scan_next(vap);
@@ -1467,7 +1483,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
iwi_checkforqos(vap,
(const struct ieee80211_frame *)(assoc+1),
le16toh(notif->len) - sizeof(*assoc));
le16toh(notif->len) - sizeof(*assoc) - 1);
ieee80211_new_state(vap, IEEE80211_S_RUN, -1);
break;
case IWI_ASSOC_INIT:
@@ -2561,6 +2577,11 @@ iwi_config(struct iwi_softc *sc)
config.answer_pbreq = (ic->ic_opmode == IEEE80211_M_IBSS) ? 1 : 0;
config.disable_unicast_decryption = 1;
config.disable_multicast_decryption = 1;
if (ic->ic_opmode == IEEE80211_M_MONITOR) {
config.allow_invalid_frames = 1;
config.allow_beacon_and_probe_resp = 1;
config.allow_mgt = 1;
}
DPRINTF(("Configuring adapter\n"));
error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config);
if (error != 0)
@@ -2646,6 +2667,17 @@ scan_band(const struct ieee80211_channel *c)
return IEEE80211_IS_CHAN_5GHZ(c) ? IWI_CHAN_5GHZ : IWI_CHAN_2GHZ;
}
static void
iwi_monitor_scan(void *arg, int npending)
{
struct iwi_softc *sc = arg;
IWI_LOCK_DECL;
IWI_LOCK(sc);
(void) iwi_scanchan(sc, 2000, 0);
IWI_UNLOCK(sc);
}
/*
* Start a scan on the current channel or all channels.
*/
@@ -193,6 +193,7 @@ struct iwi_softc {
struct task sc_restarttask; /* restart adapter processing */
struct task sc_disassoctask;
struct task sc_wmetask; /* set wme parameters */
struct task sc_monitortask;
unsigned int sc_softled : 1, /* enable LED gpio status */
sc_ledstate: 1, /* LED on/off state */
@@ -23,7 +23,7 @@ KernelAddon iprowifi3945 :
libfreebsd_network.a
;
HAIKU_WIFI_FIRMWARE_PACKAGE on iprowifi3945 = iwlwifi-3945-ucode-2.14.1.5 ;
HAIKU_WIFI_FIRMWARE_ARCHIVE on iprowifi3945 = iwlwifi-3945-ucode-2.14.1.5.tgz ;
HAIKU_WIFI_FIRMWARE_PACKAGE on iprowifi3945 = iwlwifi-3945-ucode-15.32.2.9 ;
HAIKU_WIFI_FIRMWARE_ARCHIVE on iprowifi3945 = iwlwifi-3945-ucode-15.32.2.9.tgz ;
HAIKU_WIFI_FIRMWARE_DO_EXTRACT on iprowifi3945 = true ;
@@ -93,6 +93,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_regdomain.h>
#include <net80211/ieee80211_ratectl.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -126,7 +127,7 @@ enum {
WPI_DEBUG_ANY = 0xffffffff
};
static int wpi_debug = 1;
static int wpi_debug = 0;
SYSCTL_INT(_debug, OID_AUTO, wpi, CTLFLAG_RW, &wpi_debug, 0, "wpi debug level");
TUNABLE_INT("debug.wpi", &wpi_debug);
@@ -173,8 +174,6 @@ static int wpi_alloc_tx_ring(struct wpi_softc *, struct wpi_tx_ring *,
int, int);
static void wpi_reset_tx_ring(struct wpi_softc *, struct wpi_tx_ring *);
static void wpi_free_tx_ring(struct wpi_softc *, struct wpi_tx_ring *);
static struct ieee80211_node *wpi_node_alloc(struct ieee80211vap *,
const uint8_t mac[IEEE80211_ADDR_LEN]);
static int wpi_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void wpi_mem_lock(struct wpi_softc *);
static void wpi_mem_unlock(struct wpi_softc *);
@@ -235,7 +234,6 @@ static void wpi_init_locked(struct wpi_softc *, int);
static void wpi_stop(struct wpi_softc *);
static void wpi_stop_locked(struct wpi_softc *);
static void wpi_newassoc(struct ieee80211_node *, int);
static int wpi_set_txpower(struct wpi_softc *, struct ieee80211_channel *,
int);
static void wpi_calib_timeout(void *);
@@ -665,14 +663,12 @@ wpi_attach(device_t dev)
ifp->if_init = wpi_init;
ifp->if_ioctl = wpi_ioctl;
ifp->if_start = wpi_start;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
IFQ_SET_READY(&ifp->if_snd);
ieee80211_ifattach(ic, macaddr);
/* override default methods */
ic->ic_node_alloc = wpi_node_alloc;
ic->ic_newassoc = wpi_newassoc;
ic->ic_raw_xmit = wpi_raw_xmit;
ic->ic_wme.wme_update = wpi_wme_update;
ic->ic_scan_start = wpi_scan_start;
@@ -716,13 +712,14 @@ wpi_detach(device_t dev)
{
struct wpi_softc *sc = device_get_softc(dev);
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = ifp->if_l2com;
struct ieee80211com *ic;
int ac;
ieee80211_draintask(ic, &sc->sc_restarttask);
ieee80211_draintask(ic, &sc->sc_radiotask);
if (ifp != NULL) {
ic = ifp->if_l2com;
ieee80211_draintask(ic, &sc->sc_restarttask);
ieee80211_draintask(ic, &sc->sc_radiotask);
wpi_stop(sc);
callout_drain(&sc->watchdog_to);
callout_drain(&sc->calib_to);
@@ -786,11 +783,7 @@ wpi_vap_create(struct ieee80211com *ic,
wvp->newstate = vap->iv_newstate;
vap->iv_newstate = wpi_newstate;
ieee80211_amrr_init(&wvp->amrr, vap,
IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD,
500 /*ms*/);
ieee80211_ratectl_init(vap);
/* complete setup */
ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status);
ic->ic_opmode = opmode;
@@ -802,7 +795,7 @@ wpi_vap_delete(struct ieee80211vap *vap)
{
struct wpi_vap *wvp = WPI_VAP(vap);
ieee80211_amrr_cleanup(&wvp->amrr);
ieee80211_ratectl_deinit(vap);
ieee80211_vap_detach(vap);
free(wvp, M_80211_VAP);
}
@@ -1062,9 +1055,18 @@ wpi_free_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring)
wpi_dma_contig_free(&ring->desc_dma);
for (i = 0; i < WPI_RX_RING_COUNT; i++)
if (ring->data[i].m != NULL)
m_freem(ring->data[i].m);
for (i = 0; i < WPI_RX_RING_COUNT; i++) {
struct wpi_rx_data *data = &ring->data[i];
if (data->m != NULL) {
bus_dmamap_sync(ring->data_dmat, data->map,
BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(ring->data_dmat, data->map);
m_freem(data->m);
}
if (data->map != NULL)
bus_dmamap_destroy(ring->data_dmat, data->map);
}
}
static int
@@ -1240,18 +1242,6 @@ wpi_resume(device_t dev)
return 0;
}
/* ARGSUSED */
static struct ieee80211_node *
wpi_node_alloc(struct ieee80211vap *vap __unused,
const uint8_t mac[IEEE80211_ADDR_LEN] __unused)
{
struct wpi_node *wn;
wn = malloc(sizeof (struct wpi_node), M_80211_NODE, M_NOWAIT | M_ZERO);
return &wn->ni;
}
/**
* Called by net80211 when ever there is a change to 80211 state machine
*/
@@ -1270,8 +1260,25 @@ wpi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
IEEE80211_UNLOCK(ic);
WPI_LOCK(sc);
if (nstate == IEEE80211_S_AUTH) {
/* The node must be registered in the firmware before auth */
if (nstate == IEEE80211_S_SCAN && vap->iv_state != IEEE80211_S_INIT) {
/*
* On !INIT -> SCAN transitions, we need to clear any possible
* knowledge about associations.
*/
error = wpi_config(sc);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: device config failed, error %d\n",
__func__, error);
}
}
if (nstate == IEEE80211_S_AUTH ||
(nstate == IEEE80211_S_ASSOC && vap->iv_state == IEEE80211_S_RUN)) {
/*
* The node must be registered in the firmware before auth.
* Also the associd must be cleared on RUN -> ASSOC
* transitions.
*/
error = wpi_auth(sc, vap);
if (error != 0) {
device_printf(sc->sc_dev,
@@ -1466,6 +1473,7 @@ wpi_rx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc,
return;
}
bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD);
head = (struct wpi_rx_head *)((caddr_t)(stat + 1) + stat->len);
tail = (struct wpi_rx_tail *)((caddr_t)(head + 1) + le16toh(head->len));
@@ -1496,6 +1504,8 @@ wpi_rx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc,
ifp->if_ierrors++;
return;
}
bus_dmamap_unload(ring->data_dmat, data->map);
error = bus_dmamap_load(ring->data_dmat, data->map,
mtod(mnew, caddr_t), MJUMPAGESIZE,
wpi_dma_map_addr, &paddr, BUS_DMA_NOWAIT);
@@ -1571,7 +1581,9 @@ wpi_tx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc)
struct wpi_tx_ring *ring = &sc->txq[desc->qid & 0x3];
struct wpi_tx_data *txdata = &ring->data[desc->idx];
struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1);
struct wpi_node *wn = (struct wpi_node *)txdata->ni;
struct ieee80211_node *ni = txdata->ni;
struct ieee80211vap *vap = ni->ni_vap;
int retrycnt = 0;
DPRINTFN(WPI_DEBUG_TX, ("tx done: qid=%d idx=%d retries=%d nkill=%d "
"rate=%x duration=%d status=%x\n", desc->qid, desc->idx,
@@ -1584,11 +1596,12 @@ wpi_tx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc)
* the lowest available bit-rate.
* XXX frames w/o ACK shouldn't be used either
*/
wn->amn.amn_txcnt++;
if (stat->ntries > 0) {
DPRINTFN(WPI_DEBUG_TX, ("%d retries\n", stat->ntries));
wn->amn.amn_retrycnt++;
retrycnt = 1;
}
ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_SUCCESS,
&retrycnt, NULL);
/* XXX oerrors should only count errors !maxtries */
if ((le32toh(stat->status) & 0xff) != 1)
@@ -1647,9 +1660,15 @@ wpi_notif_intr(struct wpi_softc *sc)
struct wpi_rx_data *data;
uint32_t hw;
bus_dmamap_sync(sc->shared_dma.tag, sc->shared_dma.map,
BUS_DMASYNC_POSTREAD);
hw = le32toh(sc->shared->next);
while (sc->rxq.cur != hw) {
data = &sc->rxq.data[sc->rxq.cur];
bus_dmamap_sync(sc->rxq.data_dmat, data->map,
BUS_DMASYNC_POSTREAD);
desc = (void *)data->m->m_ext.ext_buf;
DPRINTFN(WPI_DEBUG_NOTIFY,
@@ -1928,7 +1947,7 @@ wpi_tx_data(struct wpi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni,
} else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
rate = tp->ucastrate;
} else {
(void) ieee80211_amrr_choose(ni, &WPI_NODE(ni)->amn);
(void) ieee80211_ratectl_rate(ni, NULL, 0);
rate = ni->ni_txrate;
}
tx->rate = wpi_plcp_signal(rate);
@@ -2436,6 +2455,9 @@ wpi_auth(struct wpi_softc *sc, struct ieee80211vap *vap)
if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) {
sc->config.flags |= htole32(WPI_CONFIG_AUTO |
WPI_CONFIG_24GHZ);
} else {
sc->config.flags &= ~htole32(WPI_CONFIG_AUTO |
WPI_CONFIG_24GHZ);
}
if (IEEE80211_IS_CHAN_A(ni->ni_chan)) {
sc->config.cck_mask = 0;
@@ -3011,14 +3033,12 @@ wpi_rfkill_resume(struct wpi_softc *sc)
if (ntries == 1000) {
device_printf(sc->sc_dev,
"timeout waiting for thermal calibration\n");
WPI_UNLOCK(sc);
return;
}
DPRINTFN(WPI_DEBUG_TEMP,("temperature %d\n", sc->temp));
if (wpi_config(sc) != 0) {
device_printf(sc->sc_dev, "device config failed\n");
WPI_UNLOCK(sc);
return;
}
@@ -3220,15 +3240,6 @@ wpi_stop(struct wpi_softc *sc)
WPI_UNLOCK(sc);
}
static void
wpi_newassoc(struct ieee80211_node *ni, int isnew)
{
struct ieee80211vap *vap = ni->ni_vap;
struct wpi_vap *wvp = WPI_VAP(vap);
ieee80211_amrr_node_init(&wvp->amrr, &WPI_NODE(ni)->amn, ni);
}
static void
wpi_calib_timeout(void *arg)
{
@@ -3562,7 +3573,9 @@ wpi_set_channel(struct ieee80211com *ic)
* are already taken care of by their respective firmware commands.
*/
if (ic->ic_opmode == IEEE80211_M_MONITOR) {
WPI_LOCK(sc);
error = wpi_config(sc);
WPI_UNLOCK(sc);
if (error != 0)
device_printf(sc->sc_dev,
"error %d settting channel\n", error);
@@ -3715,4 +3728,3 @@ static const char *wpi_cmd_str(int cmd)
MODULE_DEPEND(wpi, pci, 1, 1, 1);
MODULE_DEPEND(wpi, wlan, 1, 1, 1);
MODULE_DEPEND(wpi, firmware, 1, 1, 1);
MODULE_DEPEND(wpi, wlan_amrr, 1, 1, 1);
@@ -106,12 +106,6 @@ struct wpi_amrr {
int recovery;
};
struct wpi_node {
struct ieee80211_node ni; /* must be the first */
struct ieee80211_amrr_node amn;
};
#define WPI_NODE(ni) ((struct wpi_node *)(ni))
struct wpi_power_sample {
uint8_t index;
int8_t power;
@@ -127,7 +121,6 @@ struct wpi_power_group {
struct wpi_vap {
struct ieee80211vap vap;
struct ieee80211_amrr amrr;
int (*newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
@@ -23,7 +23,7 @@ NO_HAIKU_FBSD_MII_DRIVER();
NO_HAIKU_REENABLE_INTERRUPTS();
HAIKU_DRIVER_REQUIREMENTS(FBSD_TASKQUEUES | FBSD_WLAN);
HAIKU_FIRMWARE_VERSION(2144);
HAIKU_FIRMWARE_NAME_MAP(1) = {{"wpifw", "iwlwifi-3945-1.ucode"}};
HAIKU_FIRMWARE_NAME_MAP(1) = {{"wpifw", "iwlwifi-3945-2.ucode"}};
int
@@ -25,12 +25,14 @@ KernelAddon iprowifi4965 :
;
HAIKU_WIFI_FIRMWARE_PACKAGES on iprowifi4965 =
iwlwifi-1000-ucode-128.50.3.1 iwlwifi-4965-ucode-228.61.2.24
iwlwifi-5000-ucode-8.24.2.12 iwlwifi-5150-ucode-8.24.2.2
iwlwifi-6000-ucode-9.221.4.1 iwlwifi-6050-ucode-9.201.4.1 ;
iwlwifi-1000-ucode-39.31.5.1 iwlwifi-4965-ucode-228.61.2.24
iwlwifi-5000-ucode-8.83.5.1 iwlwifi-5150-ucode-8.24.2.2
iwlwifi-6000-ucode-9.221.4.1 iwlwifi-6000g2a-ucode-17.168.5.2
iwlwifi-6050-ucode-41.28.5.1 ;
HAIKU_WIFI_FIRMWARE_ARCHIVES on iprowifi4965 =
iwlwifi-1000-ucode-128.50.3.1.tgz iwlwifi-4965-ucode-228.61.2.24.tgz
iwlwifi-5000-ucode-8.24.2.12.tgz iwlwifi-5150-ucode-8.24.2.2.tgz
iwlwifi-6000-ucode-9.221.4.1.tgz iwlwifi-6050-ucode-9.201.4.1.tgz ;
iwlwifi-1000-ucode-39.31.5.1.tgz iwlwifi-4965-ucode-228.61.2.24.tgz
iwlwifi-5000-ucode-8.83.5.1.tgz iwlwifi-5150-ucode-8.24.2.2.tgz
iwlwifi-6000-ucode-9.221.4.1.tgz iwlwifi-6000g2a-ucode-17.168.5.2.tgz
iwlwifi-6050-ucode-41.28.5.1.tgz ;
HAIKU_WIFI_FIRMWARE_DO_EXTRACT on iprowifi4965 = true ;
@@ -122,7 +122,6 @@ static void iwn_read_eeprom_channels(struct iwn_softc *, int,
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_rx_phy(struct iwn_softc *, struct iwn_rx_desc *,
@@ -135,8 +134,6 @@ static void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
static void iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *);
#endif
static void iwn5000_rx_calib_results(struct iwn_softc *,
struct iwn_rx_desc *, struct iwn_rx_data *);
static void iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *);
static void iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
@@ -220,8 +217,14 @@ static void iwn5000_ampdu_tx_start(struct iwn_softc *,
struct ieee80211_node *, uint8_t, uint16_t);
static void iwn5000_ampdu_tx_stop(struct iwn_softc *, uint8_t, uint16_t);
#endif
static int iwn5000_query_calibration(struct iwn_softc *);
static int iwn5000_send_calibration(struct iwn_softc *);
static int iwn5000_send_calib_results(struct iwn_softc *);
static int iwn5000_save_calib_result(struct iwn_softc *,
struct iwn_phy_calib *, int, int);
static void iwn5000_free_calib_results(struct iwn_softc *);
static int iwn5000_chrystal_calib(struct iwn_softc *);
static int iwn5000_send_calib_query(struct iwn_softc *, uint32_t);
static int iwn5000_rx_calib_result(struct iwn_softc *,
struct iwn_rx_desc *, struct iwn_rx_data *);
static int iwn5000_send_wimax_coex(struct iwn_softc *);
static int iwn4965_post_alive(struct iwn_softc *);
static int iwn5000_post_alive(struct iwn_softc *);
@@ -231,6 +234,10 @@ static int iwn4965_load_firmware(struct iwn_softc *);
static int iwn5000_load_firmware_section(struct iwn_softc *, uint32_t,
const uint8_t *, int);
static int iwn5000_load_firmware(struct iwn_softc *);
static int iwn_read_firmware_leg(struct iwn_softc *,
struct iwn_fw_info *);
static int iwn_read_firmware_tlv(struct iwn_softc *,
struct iwn_fw_info *, uint16_t);
static int iwn_read_firmware(struct iwn_softc *);
static int iwn_clock_wait(struct iwn_softc *);
static int iwn_apm_init(struct iwn_softc *);
@@ -310,7 +317,6 @@ static const struct iwn_ident iwn_ident_table [] = {
{ 0x8086, 0x423D, "Intel(R) PRO/Wireless 5150" },
{ 0x8086, 0x4235, "Intel(R) PRO/Wireless 5300" },
{ 0x8086, 0x4236, "Intel(R) PRO/Wireless 5300" },
{ 0x8086, 0x4236, "Intel(R) PRO/Wireless 5350" },
{ 0x8086, 0x423A, "Intel(R) PRO/Wireless 5350" },
{ 0x8086, 0x423B, "Intel(R) PRO/Wireless 5350" },
{ 0x8086, 0x0083, "Intel(R) PRO/Wireless 1000" },
@@ -321,8 +327,17 @@ static const struct iwn_ident iwn_ident_table [] = {
{ 0x8086, 0x4239, "Intel(R) PRO/Wireless 6000" },
{ 0x8086, 0x422B, "Intel(R) PRO/Wireless 6000" },
{ 0x8086, 0x422C, "Intel(R) PRO/Wireless 6000" },
{ 0x8086, 0x0086, "Intel(R) PRO/Wireless 6050" },
{ 0x8086, 0x0087, "Intel(R) PRO/Wireless 6050" },
{ 0x8086, 0x0087, "Intel(R) PRO/Wireless 6250" },
{ 0x8086, 0x0089, "Intel(R) PRO/Wireless 6250" },
{ 0x8086, 0x0082, "Intel(R) PRO/Wireless 6205a" },
{ 0x8086, 0x0085, "Intel(R) PRO/Wireless 6205a" },
#ifdef notyet
{ 0x8086, 0x008a, "Intel(R) PRO/Wireless 6205b" },
{ 0x8086, 0x008b, "Intel(R) PRO/Wireless 6205b" },
{ 0x8086, 0x008f, "Intel(R) PRO/Wireless 6205b" },
{ 0x8086, 0x0090, "Intel(R) PRO/Wireless 6205b" },
{ 0x8086, 0x0091, "Intel(R) PRO/Wireless 6205b" },
#endif
{ 0, 0, NULL }
};
@@ -627,8 +642,8 @@ iwn_attach(device_t dev)
ifp->if_init = iwn_init;
ifp->if_ioctl = iwn_ioctl;
ifp->if_start = iwn_start;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
IFQ_SET_READY(&ifp->if_snd);
ieee80211_ifattach(ic, macaddr);
@@ -636,7 +651,6 @@ iwn_attach(device_t dev)
ic->ic_vap_delete = iwn_vap_delete;
ic->ic_raw_xmit = iwn_raw_xmit;
ic->ic_node_alloc = iwn_node_alloc;
ic->ic_newassoc = iwn_newassoc;
ic->ic_wme.wme_update = iwn_wme_update;
ic->ic_update_mcast = iwn_update_mcast;
ic->ic_scan_start = iwn_scan_start;
@@ -692,6 +706,9 @@ iwn_hal_attach(struct iwn_softc *sc)
sc->fwname = "iwn5000fw";
sc->txchainmask = IWN_ANT_B;
sc->rxchainmask = IWN_ANT_AB;
sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO |
IWN_CALIB_TX_IQ | IWN_CALIB_TX_IQ_PERIODIC |
IWN_CALIB_BASE_BAND;
break;
case IWN_HW_REV_TYPE_5150:
sc->sc_hal = &iwn5000_hal;
@@ -699,6 +716,8 @@ iwn_hal_attach(struct iwn_softc *sc)
sc->fwname = "iwn5150fw";
sc->txchainmask = IWN_ANT_A;
sc->rxchainmask = IWN_ANT_AB;
sc->calib_init = IWN_CALIB_DC | IWN_CALIB_LO |
IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND;
break;
case IWN_HW_REV_TYPE_5300:
case IWN_HW_REV_TYPE_5350:
@@ -707,6 +726,9 @@ iwn_hal_attach(struct iwn_softc *sc)
sc->fwname = "iwn5000fw";
sc->txchainmask = IWN_ANT_ABC;
sc->rxchainmask = IWN_ANT_ABC;
sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO |
IWN_CALIB_TX_IQ | IWN_CALIB_TX_IQ_PERIODIC |
IWN_CALIB_BASE_BAND;
break;
case IWN_HW_REV_TYPE_1000:
sc->sc_hal = &iwn5000_hal;
@@ -714,6 +736,9 @@ iwn_hal_attach(struct iwn_softc *sc)
sc->fwname = "iwn1000fw";
sc->txchainmask = IWN_ANT_A;
sc->rxchainmask = IWN_ANT_AB;
sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO |
IWN_CALIB_TX_IQ | IWN_CALIB_TX_IQ_PERIODIC |
IWN_CALIB_BASE_BAND;
break;
case IWN_HW_REV_TYPE_6000:
sc->sc_hal = &iwn5000_hal;
@@ -729,15 +754,31 @@ iwn_hal_attach(struct iwn_softc *sc)
default:
sc->txchainmask = IWN_ANT_ABC;
sc->rxchainmask = IWN_ANT_ABC;
sc->calib_runtime = IWN_CALIB_DC;
break;
}
sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO |
IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND;
break;
case IWN_HW_REV_TYPE_6050:
sc->sc_hal = &iwn5000_hal;
sc->limits = &iwn6000_sensitivity_limits;
sc->fwname = "iwn6000fw";
sc->fwname = "iwn6050fw";
sc->txchainmask = IWN_ANT_AB;
sc->rxchainmask = IWN_ANT_AB;
sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO |
IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND;
sc->calib_runtime = IWN_CALIB_DC;
break;
case IWN_HW_REV_TYPE_6005:
sc->sc_hal = &iwn5000_hal;
sc->limits = &iwn6000_sensitivity_limits;
sc->fwname = "iwn6005fw";
sc->txchainmask = IWN_ANT_AB;
sc->rxchainmask = IWN_ANT_AB;
sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO |
IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND;
sc->calib_runtime = IWN_CALIB_DC;
break;
default:
device_printf(sc->sc_dev, "adapter type %d not supported\n",
@@ -826,6 +867,8 @@ iwn_cleanup(device_t dev)
ieee80211_ifdetach(ic);
}
iwn5000_free_calib_results(sc);
/* Free DMA resources. */
iwn_free_rx_ring(sc, &sc->rxq);
if (sc->sc_hal != NULL)
@@ -1670,7 +1713,7 @@ iwn5000_read_eeprom(struct iwn_softc *sc)
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
"%s: calib version=%u pa type=%u voltage=%u\n",
__func__, hdr.version, hdr.pa_type, le16toh(hdr.volt));
sc->calib_ver = hdr.version;
sc->calib_ver = hdr.version;
if (sc->hw_type == IWN_HW_REV_TYPE_5150) {
/* Compute temperature offset. */
@@ -1681,12 +1724,6 @@ iwn5000_read_eeprom(struct iwn_softc *sc)
sc->temp_off = temp - (volt / -5);
DPRINTF(sc, IWN_DEBUG_CALIBRATE, "temp=%d volt=%d offset=%dK\n",
temp, volt, sc->temp_off);
} else {
/* Read crystal calibration. */
iwn_read_prom_data(sc, base + IWN5000_EEPROM_CRYSTAL,
&sc->eeprom_crystal, sizeof (uint32_t));
DPRINTF(sc, IWN_DEBUG_CALIBRATE, "crystal calibration 0x%08x\n",
le32toh(sc->eeprom_crystal));
}
}
@@ -1894,15 +1931,6 @@ iwn_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
return malloc(sizeof (struct iwn_node), M_80211_NODE,M_NOWAIT | M_ZERO);
}
static void
iwn_newassoc(struct ieee80211_node *ni, int isnew)
{
/* XXX move */
#if 0
ieee80211_ratectl_node_init(ni);
#endif
}
static int
iwn_media_change(struct ifnet *ifp)
{
@@ -1927,27 +1955,45 @@ iwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
IWN_LOCK(sc);
callout_stop(&sc->sc_timer_to);
if (nstate == IEEE80211_S_AUTH && vap->iv_state != IEEE80211_S_AUTH) {
/* !AUTH -> AUTH requires adapter config */
/* Reset state to handle reassociations correctly. */
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);
iwn_calib_reset(sc);
error = iwn_auth(sc, vap);
}
if (nstate == IEEE80211_S_RUN && vap->iv_state != IEEE80211_S_RUN) {
break;
case IEEE80211_S_RUN:
/*
* RUN -> RUN transition; Just restart the timers.
*/
if (vap->iv_state == IEEE80211_S_RUN &&
vap->iv_opmode != IEEE80211_M_MONITOR) {
iwn_calib_reset(sc);
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.
*/
error = iwn_run(sc, vap);
}
if (nstate == IEEE80211_S_RUN) {
/*
* RUN -> RUN transition; just restart the timers.
*/
iwn_calib_reset(sc);
break;
default:
break;
}
IWN_UNLOCK(sc);
IEEE80211_LOCK(ic);
@@ -2164,64 +2210,6 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
}
#endif
/*
* Process a CALIBRATION_RESULT notification sent by the initialization
* firmware on response to a CMD_CALIB_CONFIG command (5000 only.)
*/
static void
iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc,
struct iwn_rx_data *data)
{
struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1);
int len, idx = -1;
/* Runtime firmware should not send such a notification. */
if (sc->sc_flags & IWN_FLAG_CALIB_DONE)
return;
bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
len = (le32toh(desc->len) & 0x3fff) - 4;
switch (calib->code) {
case IWN5000_PHY_CALIB_DC:
if (sc->hw_type == IWN_HW_REV_TYPE_5150 ||
sc->hw_type == IWN_HW_REV_TYPE_6050)
idx = 0;
break;
case IWN5000_PHY_CALIB_LO:
idx = 1;
break;
case IWN5000_PHY_CALIB_TX_IQ:
idx = 2;
break;
case IWN5000_PHY_CALIB_TX_IQ_PERIODIC:
if (sc->hw_type < IWN_HW_REV_TYPE_6000 &&
sc->hw_type != IWN_HW_REV_TYPE_5150)
idx = 3;
break;
case IWN5000_PHY_CALIB_BASE_BAND:
idx = 4;
break;
}
if (idx == -1) /* Ignore other results. */
return;
/* Save calibration result. */
if (sc->calibcmd[idx].buf != NULL)
free(sc->calibcmd[idx].buf, M_DEVBUF);
sc->calibcmd[idx].buf = malloc(len, M_DEVBUF, M_NOWAIT);
if (sc->calibcmd[idx].buf == NULL) {
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
"not enough memory for calibration result %d\n",
calib->code);
return;
}
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
"saving calibration result code=%d len=%d\n", calib->code, len);
sc->calibcmd[idx].len = len;
memcpy(sc->calibcmd[idx].buf, calib, len);
}
/*
* Process an RX_STATISTICS or BEACON_STATISTICS firmware notification.
* The latter is sent by the firmware after each received beacon.
@@ -2579,7 +2567,7 @@ iwn_notif_intr(struct iwn_softc *sc)
break;
}
case IWN5000_CALIBRATION_RESULT:
iwn5000_rx_calib_results(sc, desc, data);
iwn5000_rx_calib_result(sc, desc, data);
break;
case IWN5000_CALIBRATION_DONE:
@@ -3022,7 +3010,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
txant = IWN_LSB(sc->txchainmask);
tx->rflags |= IWN_RFLAG_ANT(txant);
} else {
tx->linkq = 0;
tx->linkq = IWN_RIDX_OFDM54 - ridx;
flags |= IWN_TX_LINKQ; /* enable MRR */
}
@@ -4134,10 +4122,14 @@ iwn_collect_noise(struct iwn_softc *sc,
val = MAX(calib->rssi[2], val);
/* Determine which antennas are connected. */
sc->chainmask = 0;
sc->chainmask = sc->rxchainmask;
for (i = 0; i < 3; i++)
if (val - calib->rssi[i] <= 15 * 20)
sc->chainmask |= 1 << i;
if (val - calib->rssi[i] > 15 * 20)
sc->chainmask &= ~(1 << i);
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
"%s: RX chains mask: theoretical=0x%x, actual=0x%x\n",
__func__, sc->rxchainmask, sc->chainmask);
/* If none of the TX antennas are connected, keep at least one. */
if ((sc->chainmask & sc->txchainmask) == 0)
sc->chainmask |= IWN_LSB(sc->txchainmask);
@@ -4864,11 +4856,9 @@ iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap)
struct iwn_node_info node;
int error;
sc->calib.state = IWN_CALIB_STATE_INIT;
if (ic->ic_opmode == IEEE80211_M_MONITOR) {
/* Link LED blinks while monitoring. */
iwn_set_led(sc, IWN_LED_LINK, 5, 5);
iwn_set_led(sc, IWN_LED_LINK, 20, 20);
return 0;
}
error = iwn_set_timing(sc, ni);
@@ -5213,22 +5203,143 @@ iwn5000_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn)
#endif
/*
* Query calibration tables from the initialization firmware. We do this
* only once at first boot. Called from a process context.
* Send calibration results to the runtime firmware. These results were
* obtained on first boot from the initialization firmware, or by reading
* the EEPROM for crystal calibration.
*/
static int
iwn5000_query_calibration(struct iwn_softc *sc)
iwn5000_send_calib_results(struct iwn_softc *sc)
{
struct iwn_calib_info *calib_result;
int idx, error;
for (idx = 0; idx < IWN_CALIB_NUM; idx++) {
calib_result = &sc->calib_results[idx];
/* No support for this type of calibration. */
if ((sc->calib_init & (1 << idx)) == 0)
continue;
/* No calibration result available. */
if (calib_result->buf == NULL)
continue;
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
"%s: send calibration result idx=%d, len=%d\n",
__func__, idx, calib_result->len);
error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, calib_result->buf,
calib_result->len, 0);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: could not send calibration result "
"idx=%d, error=%d\n",
__func__, idx, error);
return error;
}
}
return 0;
}
/*
* Save calibration result at the given index. The index determines
* in which order the results are sent to the runtime firmware.
*/
static int
iwn5000_save_calib_result(struct iwn_softc *sc, struct iwn_phy_calib *calib,
int len, int idx)
{
struct iwn_calib_info *calib_result = &sc->calib_results[idx];
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
"%s: saving calibration result code=%d, idx=%d, len=%d\n",
__func__, calib->code, idx, len);
if (calib_result->buf != NULL)
free(calib_result->buf, M_DEVBUF);
calib_result->buf = malloc(len, M_DEVBUF, M_NOWAIT);
if (calib_result->buf == NULL) {
device_printf(sc->sc_dev,
"%s: not enough memory for calibration result "
"code=%d, len=%d\n", __func__, calib->code, len);
return ENOMEM;
}
calib_result->len = len;
memcpy(calib_result->buf, calib, len);
return 0;
}
static void
iwn5000_free_calib_results(struct iwn_softc *sc)
{
struct iwn_calib_info *calib_result;
int idx;
for (idx = 0; idx < IWN_CALIB_NUM; idx++) {
calib_result = &sc->calib_results[idx];
if (calib_result->buf != NULL)
free(calib_result->buf, M_DEVBUF);
calib_result->buf = NULL;
calib_result->len = 0;
}
}
/*
* Obtain the crystal calibration result from the EEPROM.
*/
static int
iwn5000_chrystal_calib(struct iwn_softc *sc)
{
struct iwn5000_phy_calib_crystal cmd;
uint32_t base, crystal;
uint16_t val;
/* Read crystal calibration. */
iwn_read_prom_data(sc, IWN5000_EEPROM_CAL, &val, 2);
base = le16toh(val);
iwn_read_prom_data(sc, base + IWN5000_EEPROM_CRYSTAL, &crystal,
sizeof(uint32_t));
DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: crystal calibration=0x%08x\n",
__func__, le32toh(crystal));
memset(&cmd, 0, sizeof cmd);
cmd.code = IWN5000_PHY_CALIB_CRYSTAL;
cmd.ngroups = 1;
cmd.isvalid = 1;
cmd.cap_pin[0] = le32toh(crystal) & 0xff;
cmd.cap_pin[1] = (le32toh(crystal) >> 16) & 0xff;
return iwn5000_save_calib_result(sc, (struct iwn_phy_calib *)&cmd,
sizeof cmd, IWN_CALIB_IDX_XTAL);
}
/*
* Query calibration results from the initialization firmware. We do this
* only once at first boot.
*/
static int
iwn5000_send_calib_query(struct iwn_softc *sc, uint32_t cfg)
{
#define CALIB_INIT_CFG 0xffffffff;
struct iwn5000_calib_config cmd;
int error;
memset(&cmd, 0, sizeof cmd);
cmd.ucode.once.enable = 0xffffffff;
cmd.ucode.once.start = 0xffffffff;
cmd.ucode.once.send = 0xffffffff;
cmd.ucode.flags = 0xffffffff;
DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: sending calibration query\n",
__func__);
cmd.ucode.once.enable = CALIB_INIT_CFG;
if (cfg == 0) {
cmd.ucode.once.start = CALIB_INIT_CFG;
cmd.ucode.once.send = CALIB_INIT_CFG;
cmd.ucode.flags = CALIB_INIT_CFG;
} else
cmd.ucode.once.start = cfg;
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
"%s: query calibration results, cfg %x\n", __func__, cfg);
error = iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof cmd, 0);
if (error != 0)
return error;
@@ -5236,34 +5347,56 @@ iwn5000_query_calibration(struct iwn_softc *sc)
/* Wait at most two seconds for calibration to complete. */
if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE))
error = msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", 2 * hz);
return error;
#undef CALIB_INIT_CFG
}
/*
* Send calibration results to the runtime firmware. These results were
* obtained on first boot from the initialization firmware.
* Process a CALIBRATION_RESULT notification sent by the initialization
* firmware on response to a CMD_CALIB_CONFIG command.
*/
static int
iwn5000_send_calibration(struct iwn_softc *sc)
iwn5000_rx_calib_result(struct iwn_softc *sc, struct iwn_rx_desc *desc,
struct iwn_rx_data *data)
{
int idx, error;
#define FRAME_SIZE_MASK 0x3fff
struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1);
int len, idx;
for (idx = 0; idx < 5; idx++) {
if (sc->calibcmd[idx].buf == NULL)
continue; /* No results available. */
bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
len = (le32toh(desc->len) & FRAME_SIZE_MASK);
/* Remove length field itself. */
len -= 4;
/*
* Determine the order in which the results will be send to the
* runtime firmware.
*/
switch (calib->code) {
case IWN5000_PHY_CALIB_DC:
idx = IWN_CALIB_IDX_DC;
break;
case IWN5000_PHY_CALIB_LO:
idx = IWN_CALIB_IDX_LO;
break;
case IWN5000_PHY_CALIB_TX_IQ:
idx = IWN_CALIB_IDX_TX_IQ;
break;
case IWN5000_PHY_CALIB_TX_IQ_PERIODIC:
idx = IWN_CALIB_IDX_TX_IQ_PERIODIC;
break;
case IWN5000_PHY_CALIB_BASE_BAND:
idx = IWN_CALIB_IDX_BASE_BAND;
break;
default:
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
"send calibration result idx=%d len=%d\n",
idx, sc->calibcmd[idx].len);
error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, sc->calibcmd[idx].buf,
sc->calibcmd[idx].len, 0);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: could not send calibration result, error %d\n",
__func__, error);
return error;
}
"%s: unknown calibration code=%d\n", __func__, calib->code);
return EINVAL;
}
return 0;
return iwn5000_save_calib_result(sc, calib, len, idx);
#undef FRAME_SIZE_MASK
}
static int
@@ -5411,36 +5544,40 @@ iwn5000_post_alive(struct iwn_softc *sc)
__func__, error);
return error;
}
if (sc->hw_type != IWN_HW_REV_TYPE_5150) {
struct iwn5000_phy_calib_crystal cmd;
/* Perform crystal calibration. */
memset(&cmd, 0, sizeof cmd);
cmd.code = IWN5000_PHY_CALIB_CRYSTAL;
cmd.ngroups = 1;
cmd.isvalid = 1;
cmd.cap_pin[0] = le32toh(sc->eeprom_crystal) & 0xff;
cmd.cap_pin[1] = (le32toh(sc->eeprom_crystal) >> 16) & 0xff;
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
"sending crystal calibration %d, %d\n",
cmd.cap_pin[0], cmd.cap_pin[1]);
error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: crystal calibration failed, error %d\n",
__func__, error);
return error;
}
}
if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE)) {
/* Query calibration from the initialization firmware. */
error = iwn5000_query_calibration(sc);
/*
* Start calibration by setting and sending the chrystal
* calibration first, this must be done before we are able
* to query the other calibration results.
*/
error = iwn5000_chrystal_calib(sc);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: could not query calibration, error %d\n",
"%s: could not set chrystal calibration, "
"error=%d\n", __func__, error);
return error;
}
error = iwn5000_send_calib_results(sc);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: could not send chrystal calibration, "
"error=%d\n", __func__, error);
return error;
}
/*
* Query other calibration results from the initialization
* firmware.
*/
error = iwn5000_send_calib_query(sc, 0);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: could not query calibration, error=%d\n",
__func__, error);
return error;
}
/*
* We have the calibration results now, reboot with the
* runtime firmware (call ourselves recursively!)
@@ -5448,8 +5585,24 @@ iwn5000_post_alive(struct iwn_softc *sc)
iwn_hw_stop(sc);
error = iwn_hw_init(sc);
} else {
/* Send calibration results to runtime firmware. */
error = iwn5000_send_calibration(sc);
/*
* Send calibration results obtained from the initialization
* firmware to the runtime firmware.
*/
error = iwn5000_send_calib_results(sc);
/*
* Tell the runtime firmware to do certain calibration types.
*/
if (sc->calib_runtime != 0) {
error = iwn5000_send_calib_query(sc, sc->calib_runtime);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: could not send query calibration, "
"error=%d, cfg=%x\n", __func__, error,
sc->calib_runtime);
}
}
}
return error;
}
@@ -5642,17 +5795,159 @@ iwn5000_load_firmware(struct iwn_softc *sc)
return 0;
}
/*
* Extract text and data sections from a legacy firmware image.
*/
static int
iwn_read_firmware_leg(struct iwn_softc *sc, struct iwn_fw_info *fw)
{
const uint32_t *ptr;
size_t hdrlen = 24;
uint32_t rev;
ptr = (const uint32_t *)sc->fw_fp->data;
rev = le32toh(*ptr++);
/* Check firmware API version. */
if (IWN_FW_API(rev) <= 1) {
device_printf(sc->sc_dev,
"%s: bad firmware, need API version >=2\n", __func__);
return EINVAL;
}
if (IWN_FW_API(rev) >= 3) {
/* Skip build number (version 2 header). */
hdrlen += 4;
ptr++;
}
if (fw->size < hdrlen) {
device_printf(sc->sc_dev,
"%s: firmware file too short: %zu bytes\n",
__func__, fw->size);
return EINVAL;
}
fw->main.textsz = le32toh(*ptr++);
fw->main.datasz = le32toh(*ptr++);
fw->init.textsz = le32toh(*ptr++);
fw->init.datasz = le32toh(*ptr++);
fw->boot.textsz = le32toh(*ptr++);
/* Check that all firmware sections fit. */
if (fw->size < hdrlen + fw->main.textsz + fw->main.datasz +
fw->init.textsz + fw->init.datasz + fw->boot.textsz) {
device_printf(sc->sc_dev,
"%s: firmware file too short: %zu bytes\n",
__func__, fw->size);
return EINVAL;
}
/* Get pointers to firmware sections. */
fw->main.text = (const uint8_t *)ptr;
fw->main.data = fw->main.text + fw->main.textsz;
fw->init.text = fw->main.data + fw->main.datasz;
fw->init.data = fw->init.text + fw->init.textsz;
fw->boot.text = fw->init.data + fw->init.datasz;
return 0;
}
/*
* Extract text and data sections from a TLV firmware image.
*/
int
iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw,
uint16_t alt)
{
const struct iwn_fw_tlv_hdr *hdr;
const struct iwn_fw_tlv *tlv;
const uint8_t *ptr, *end;
uint64_t altmask;
uint32_t len;
if (fw->size < sizeof (*hdr)) {
device_printf(sc->sc_dev,
"%s: firmware file too short: %zu bytes\n",
__func__, fw->size);
return EINVAL;
}
hdr = (const struct iwn_fw_tlv_hdr *)fw->data;
if (hdr->signature != htole32(IWN_FW_SIGNATURE)) {
device_printf(sc->sc_dev,
"%s: bad firmware file signature 0x%08x\n",
__func__, le32toh(hdr->signature));
return EINVAL;
}
/*
* Select the closest supported alternative that is less than
* or equal to the specified one.
*/
altmask = le64toh(hdr->altmask);
while (alt > 0 && !(altmask & (1ULL << alt)))
alt--; /* Downgrade. */
ptr = (const uint8_t *)(hdr + 1);
end = (const uint8_t *)(fw->data + fw->size);
/* Parse type-length-value fields. */
while (ptr + sizeof (*tlv) <= end) {
tlv = (const struct iwn_fw_tlv *)ptr;
len = le32toh(tlv->len);
ptr += sizeof (*tlv);
if (ptr + len > end) {
device_printf(sc->sc_dev,
"%s: firmware file too short: %zu bytes\n",
__func__, fw->size);
return EINVAL;
}
/* Skip other alternatives. */
if (tlv->alt != 0 && tlv->alt != htole16(alt))
goto next;
switch (le16toh(tlv->type)) {
case IWN_FW_TLV_MAIN_TEXT:
fw->main.text = ptr;
fw->main.textsz = len;
break;
case IWN_FW_TLV_MAIN_DATA:
fw->main.data = ptr;
fw->main.datasz = len;
break;
case IWN_FW_TLV_INIT_TEXT:
fw->init.text = ptr;
fw->init.textsz = len;
break;
case IWN_FW_TLV_INIT_DATA:
fw->init.data = ptr;
fw->init.datasz = len;
break;
case IWN_FW_TLV_BOOT_TEXT:
fw->boot.text = ptr;
fw->boot.textsz = len;
break;
default:
DPRINTF(sc, IWN_DEBUG_RESET,
"%s: TLV type %d not handled\n",
__func__, le16toh(tlv->type));
break;
}
next: /* TLV fields are 32-bit aligned. */
ptr += (len + 3) & ~3;
}
return 0;
}
static int
iwn_read_firmware(struct iwn_softc *sc)
{
const struct iwn_hal *hal = sc->sc_hal;
struct iwn_fw_info *fw = &sc->fw;
const uint32_t *ptr;
uint32_t rev;
size_t size;
int error;
IWN_UNLOCK(sc);
memset(fw, 0, sizeof (*fw));
/* Read firmware image from filesystem. */
sc->fw_fp = firmware_get(sc->fwname);
if (sc->fw_fp == NULL) {
@@ -5664,63 +5959,39 @@ iwn_read_firmware(struct iwn_softc *sc)
}
IWN_LOCK(sc);
size = sc->fw_fp->datasize;
if (size < 28) {
fw->size = sc->fw_fp->datasize;
fw->data = (const uint8_t *)sc->fw_fp->data;
if (fw->size < sizeof (uint32_t)) {
device_printf(sc->sc_dev,
"%s: truncated firmware header: %zu bytes\n",
__func__, size);
"%s: firmware file too short: %zu bytes\n",
__func__, fw->size);
return EINVAL;
}
/* Process firmware header. */
ptr = (const uint32_t *)sc->fw_fp->data;
rev = le32toh(*ptr++);
/* Check firmware API version. */
if (IWN_FW_API(rev) <= 1) {
/* Retrieve text and data sections. */
if (*(const uint32_t *)fw->data != 0) /* Legacy image. */
error = iwn_read_firmware_leg(sc, fw);
else
error = iwn_read_firmware_tlv(sc, fw, 1);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: bad firmware, need API version >=2\n", __func__);
return EINVAL;
"%s: could not read firmware sections\n", __func__);
return error;
}
if (IWN_FW_API(rev) >= 3) {
/* Skip build number (version 2 header). */
size -= 4;
ptr++;
}
fw->main.textsz = le32toh(*ptr++);
fw->main.datasz = le32toh(*ptr++);
fw->init.textsz = le32toh(*ptr++);
fw->init.datasz = le32toh(*ptr++);
fw->boot.textsz = le32toh(*ptr++);
size -= 24;
/* Sanity-check firmware header. */
/* Make sure text and data sections fit in hardware memory. */
if (fw->main.textsz > hal->fw_text_maxsz ||
fw->main.datasz > hal->fw_data_maxsz ||
fw->init.textsz > hal->fw_text_maxsz ||
fw->init.datasz > hal->fw_data_maxsz ||
fw->boot.textsz > IWN_FW_BOOT_TEXT_MAXSZ ||
(fw->boot.textsz & 3) != 0) {
device_printf(sc->sc_dev, "%s: invalid firmware header\n",
__func__);
return EINVAL;
}
/* Check that all firmware sections fit. */
if (fw->main.textsz + fw->main.datasz + fw->init.textsz +
fw->init.datasz + fw->boot.textsz > size) {
device_printf(sc->sc_dev,
"%s: firmware file too short: %zu bytes\n",
__func__, size);
"%s: firmware sections too large\n", __func__);
return EINVAL;
}
/* Get pointers to firmware sections. */
fw->main.text = (const uint8_t *)ptr;
fw->main.data = fw->main.text + fw->main.textsz;
fw->init.text = fw->main.data + fw->main.datasz;
fw->init.data = fw->init.text + fw->init.textsz;
fw->boot.text = fw->init.data + fw->init.datasz;
/* We can proceed with loading the firmware. */
return 0;
}
@@ -5769,8 +6040,7 @@ iwn_apm_init(struct iwn_softc *sc)
IWN_CLRBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA);
if (sc->hw_type != IWN_HW_REV_TYPE_4965 &&
sc->hw_type != IWN_HW_REV_TYPE_6000 &&
sc->hw_type != IWN_HW_REV_TYPE_6050)
sc->hw_type <= IWN_HW_REV_TYPE_1000)
IWN_SETBITS(sc, IWN_ANA_PLL, IWN_ANA_PLL_INIT);
/* Wait for clock stabilization before accessing prph. */
@@ -5885,9 +6155,9 @@ iwn5000_nic_config(struct iwn_softc *sc)
/* Use internal power amplifier only. */
IWN_WRITE(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_2X2_IPA);
}
if (sc->hw_type == IWN_HW_REV_TYPE_6050 && sc->calib_ver >= 6) {
/* Indicate that ROM calibration version is >=6. */
IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6);
if (sc->hw_type == IWN_HW_REV_TYPE_6050 && sc->calib_ver >= 6) {
/* Indicate that ROM calibration version is >=6. */
IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6);
}
return 0;
}
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
/* $OpenBSD: if_iwnreg.h,v 1.37 2010/02/17 18:23:00 damien Exp $ */
/* $OpenBSD: if_iwnreg.h,v 1.40 2010/05/05 19:41:57 damien Exp $ */
/*-
* Copyright (c) 2007, 2008
@@ -204,6 +204,7 @@
#define IWN_HW_REV_TYPE_1000 6
#define IWN_HW_REV_TYPE_6000 7
#define IWN_HW_REV_TYPE_6050 8
#define IWN_HW_REV_TYPE_6005 11
/* Possible flags for register IWN_GIO_CHICKEN. */
#define IWN_GIO_CHICKEN_L1A_NO_L0S_RX (1 << 23)
@@ -1259,6 +1260,34 @@ struct iwn_fw_dump {
uint32_t time[2];
} __packed;
/* TLV firmware header. */
struct iwn_fw_tlv_hdr {
uint32_t zero; /* Always 0, to differentiate from legacy. */
uint32_t signature;
#define IWN_FW_SIGNATURE 0x0a4c5749 /* "IWL\n" */
uint8_t descr[64];
uint32_t rev;
#define IWN_FW_API(x) (((x) >> 8) & 0xff)
uint32_t build;
uint64_t altmask;
} __packed;
/* TLV header. */
struct iwn_fw_tlv {
uint16_t type;
#define IWN_FW_TLV_MAIN_TEXT 1
#define IWN_FW_TLV_MAIN_DATA 2
#define IWN_FW_TLV_INIT_TEXT 3
#define IWN_FW_TLV_INIT_DATA 4
#define IWN_FW_TLV_BOOT_TEXT 5
#define IWN_FW_TLV_PBREQ_MAXLEN 6
uint16_t alt;
uint32_t len;
} __packed;
#define IWN4965_FW_TEXT_MAXSZ ( 96 * 1024)
#define IWN4965_FW_DATA_MAXSZ ( 40 * 1024)
#define IWN5000_FW_TEXT_MAXSZ (256 * 1024)
@@ -1267,8 +1296,6 @@ struct iwn_fw_dump {
#define IWN4965_FWSZ (IWN4965_FW_TEXT_MAXSZ + IWN4965_FW_DATA_MAXSZ)
#define IWN5000_FWSZ IWN5000_FW_TEXT_MAXSZ
#define IWN_FW_API(x) (((x) >> 8) & 0xff)
/*
* Offsets into EEPROM.
*/
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
/* $OpenBSD: if_iwnvar.h,v 1.17 2010/02/17 18:23:00 damien Exp $ */
/* $OpenBSD: if_iwnvar.h,v 1.18 2010/04/30 16:06:46 damien Exp $ */
/*-
* Copyright (c) 2007, 2008
@@ -150,7 +150,8 @@ struct iwn_fw_part {
};
struct iwn_fw_info {
u_char *data;
const uint8_t *data;
size_t size;
struct iwn_fw_part init;
struct iwn_fw_part main;
struct iwn_fw_part boot;
@@ -262,9 +263,24 @@ struct iwn_softc {
int calib_cnt;
struct iwn_calib_state calib;
u_int calib_init;
u_int calib_runtime;
#define IWN_CALIB_XTAL (1 << IWN_CALIB_IDX_XTAL)
#define IWN_CALIB_DC (1 << IWN_CALIB_IDX_DC)
#define IWN_CALIB_LO (1 << IWN_CALIB_IDX_LO)
#define IWN_CALIB_TX_IQ (1 << IWN_CALIB_IDX_TX_IQ)
#define IWN_CALIB_TX_IQ_PERIODIC (1 << IWN_CALIB_IDX_TX_IQ_PERIODIC)
#define IWN_CALIB_BASE_BAND (1 << IWN_CALIB_IDX_BASE_BAND)
#define IWN_CALIB_NUM 6
struct iwn_calib_info calib_results[IWN_CALIB_NUM];
#define IWN_CALIB_IDX_XTAL 0
#define IWN_CALIB_IDX_DC 1
#define IWN_CALIB_IDX_LO 2
#define IWN_CALIB_IDX_TX_IQ 3
#define IWN_CALIB_IDX_TX_IQ_PERIODIC 4
#define IWN_CALIB_IDX_BASE_BAND 5
struct iwn_fw_info fw;
struct iwn_calib_info calibcmd[5];
uint32_t errptr;
struct iwn_rx_stat last_rx_stat;
@@ -283,7 +299,6 @@ struct iwn_softc {
uint16_t rfcfg;
uint8_t calib_ver;
char eeprom_domain[4];
uint32_t eeprom_crystal;
int16_t eeprom_voltage;
int8_t maxpwr2GHz;
int8_t maxpwr5GHz;
@@ -312,7 +327,7 @@ struct iwn_softc {
#define IWN_LOCK_INIT(_sc) \
mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \
MTX_NETWORK_LOCK, MTX_DEF)
MTX_NETWORK_LOCK, MTX_DEF)
#define IWN_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define IWN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
#define IWN_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
@@ -24,12 +24,14 @@ NO_HAIKU_FBSD_MII_DRIVER();
NO_HAIKU_REENABLE_INTERRUPTS();
HAIKU_DRIVER_REQUIREMENTS(FBSD_TASKQUEUES | FBSD_WLAN);
HAIKU_FIRMWARE_VERSION(44417);
HAIKU_FIRMWARE_NAME_MAP(5) = {
{"iwn1000fw", "iwlwifi-1000-3.ucode"},
HAIKU_FIRMWARE_NAME_MAP(7) = {
{"iwn1000fw", "iwlwifi-1000-5.ucode"},
{"iwn4965fw", "iwlwifi-4965-2.ucode"},
{"iwn5000fw", "iwlwifi-5000-2.ucode"},
{"iwn5000fw", "iwlwifi-5000-5.ucode"},
{"iwn5150fw", "iwlwifi-5150-2.ucode"},
{"iwn6000fw", "iwlwifi-6000-4.ucode"}
{"iwn6000fw", "iwlwifi-6000-4.ucode"},
{"iwn6005fw", "iwlwifi-6000g2a-5.ucode"},
{"iwn6050fw", "iwlwifi-6050-5.ucode"}
};
@@ -275,8 +275,8 @@ malo_attach(uint16_t devid, struct malo_softc *sc)
ifp->if_watchdog = malo_watchdog;
ifp->if_ioctl = malo_ioctl;
ifp->if_init = malo_init;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
IFQ_SET_READY(&ifp->if_snd);
ic->ic_ifp = ifp;
@@ -2099,7 +2099,7 @@ malo_rx_proc(void *arg, int npending)
* payload prior to constructing the header.
*/
m = bf->bf_m;
data = mtod(m, uint8_t *);;
data = mtod(m, uint8_t *);
hdrlen = ieee80211_anyhdrsize(data + sizeof(uint16_t));
off = sizeof(uint16_t) + sizeof(struct ieee80211_frame_addr4);
@@ -371,4 +371,4 @@ static devclass_t malo_devclass;
DRIVER_MODULE(malo, pci, malo_pci_driver, malo_devclass, 0, 0);
MODULE_VERSION(malo, 1);
MODULE_DEPEND(malo, wlan, 1, 1, 1); /* 802.11 media layer */
MODULE_DEPEND(malo, malofw_fw, 1, 1, 1);
MODULE_DEPEND(malo, firmware, 1, 1, 1);
@@ -404,8 +404,8 @@ mwl_attach(uint16_t devid, struct mwl_softc *sc)
ifp->if_watchdog = mwl_watchdog;
ifp->if_ioctl = mwl_ioctl;
ifp->if_init = mwl_init;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
IFQ_SET_READY(&ifp->if_snd);
ic->ic_ifp = ifp;
@@ -204,7 +204,7 @@ mwl_pci_attach(device_t dev)
BUS_SPACE_MAXADDR, /* maxsize */
MWL_TXDESC, /* nsegments */
BUS_SPACE_MAXADDR, /* maxsegsize */
BUS_DMA_ALLOCNOW, /* flags */
0, /* flags */
NULL, /* lockfunc */
NULL, /* lockarg */
&sc->sc_dmat)) {
@@ -313,4 +313,4 @@ static devclass_t mwl_devclass;
DRIVER_MODULE(mwl, pci, mwl_pci_driver, mwl_devclass, 0, 0);
MODULE_VERSION(mwl, 1);
MODULE_DEPEND(mwl, wlan, 1, 1, 1); /* 802.11 media layer */
MODULE_DEPEND(mwl, mwlfw_fw, 1, 1, 1); /* firmware */
MODULE_DEPEND(mwl, firmware, 1, 1, 1);
@@ -54,7 +54,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_regdomain.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_ratectl.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -103,9 +103,6 @@ static void rt2560_reset_rx_ring(struct rt2560_softc *,
struct rt2560_rx_ring *);
static void rt2560_free_rx_ring(struct rt2560_softc *,
struct rt2560_rx_ring *);
static struct ieee80211_node *rt2560_node_alloc(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN]);
static void rt2560_newassoc(struct ieee80211_node *, int);
static int rt2560_newstate(struct ieee80211vap *,
enum ieee80211_state, int);
static uint16_t rt2560_eeprom_read(struct rt2560_softc *, uint8_t);
@@ -269,8 +266,8 @@ rt2560_attach(device_t dev, int id)
ifp->if_init = rt2560_init;
ifp->if_ioctl = rt2560_ioctl;
ifp->if_start = rt2560_start;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
IFQ_SET_READY(&ifp->if_snd);
ic->ic_ifp = ifp;
@@ -303,11 +300,9 @@ rt2560_attach(device_t dev, int id)
ieee80211_init_channels(ic, NULL, &bands);
ieee80211_ifattach(ic, macaddr);
ic->ic_newassoc = rt2560_newassoc;
ic->ic_raw_xmit = rt2560_raw_xmit;
ic->ic_updateslot = rt2560_update_slot;
ic->ic_update_promisc = rt2560_update_promisc;
ic->ic_node_alloc = rt2560_node_alloc;
ic->ic_scan_start = rt2560_scan_start;
ic->ic_scan_end = rt2560_scan_end;
ic->ic_set_channel = rt2560_set_channel;
@@ -430,11 +425,7 @@ rt2560_vap_create(struct ieee80211com *ic,
vap->iv_newstate = rt2560_newstate;
vap->iv_update_beacon = rt2560_beacon_update;
ieee80211_amrr_init(&rvp->amrr, vap,
IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD,
500 /* ms */);
ieee80211_ratectl_init(vap);
/* complete setup */
ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status);
if (TAILQ_FIRST(&ic->ic_vaps) == vap)
@@ -447,7 +438,7 @@ rt2560_vap_delete(struct ieee80211vap *vap)
{
struct rt2560_vap *rvp = RT2560_VAP(vap);
ieee80211_amrr_cleanup(&rvp->amrr);
ieee80211_ratectl_deinit(vap);
ieee80211_vap_detach(vap);
free(rvp, M_80211_VAP);
}
@@ -764,27 +755,6 @@ rt2560_free_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring)
bus_dma_tag_destroy(ring->data_dmat);
}
static struct ieee80211_node *
rt2560_node_alloc(struct ieee80211vap *vap,
const uint8_t mac[IEEE80211_ADDR_LEN])
{
struct rt2560_node *rn;
rn = malloc(sizeof (struct rt2560_node), M_80211_NODE,
M_NOWAIT | M_ZERO);
return (rn != NULL) ? &rn->ni : NULL;
}
static void
rt2560_newassoc(struct ieee80211_node *ni, int isnew)
{
struct ieee80211vap *vap = ni->ni_vap;
ieee80211_amrr_node_init(&RT2560_VAP(vap)->amrr,
&RT2560_NODE(ni)->amrr, ni);
}
static int
rt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
{
@@ -955,10 +925,11 @@ rt2560_tx_intr(struct rt2560_softc *sc)
struct ifnet *ifp = sc->sc_ifp;
struct rt2560_tx_desc *desc;
struct rt2560_tx_data *data;
struct rt2560_node *rn;
struct mbuf *m;
uint32_t flags;
int retrycnt;
struct ieee80211vap *vap;
struct ieee80211_node *ni;
bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map,
BUS_DMASYNC_POSTREAD);
@@ -973,15 +944,19 @@ rt2560_tx_intr(struct rt2560_softc *sc)
!(flags & RT2560_TX_VALID))
break;
rn = (struct rt2560_node *)data->ni;
m = data->m;
ni = data->ni;
vap = ni->ni_vap;
switch (flags & RT2560_TX_RESULT_MASK) {
case RT2560_TX_SUCCESS:
retrycnt = 0;
DPRINTFN(sc, 10, "%s\n", "data frame sent successfully");
if (data->rix != IEEE80211_FIXED_RATE_NONE)
ieee80211_amrr_tx_complete(&rn->amrr,
IEEE80211_AMRR_SUCCESS, 0);
ieee80211_ratectl_tx_complete(vap, ni,
IEEE80211_RATECTL_TX_SUCCESS,
&retrycnt, NULL);
ifp->if_opackets++;
break;
@@ -991,8 +966,9 @@ rt2560_tx_intr(struct rt2560_softc *sc)
DPRINTFN(sc, 9, "data frame sent after %u retries\n",
retrycnt);
if (data->rix != IEEE80211_FIXED_RATE_NONE)
ieee80211_amrr_tx_complete(&rn->amrr,
IEEE80211_AMRR_SUCCESS, retrycnt);
ieee80211_ratectl_tx_complete(vap, ni,
IEEE80211_RATECTL_TX_SUCCESS,
&retrycnt, NULL);
ifp->if_opackets++;
break;
@@ -1002,8 +978,9 @@ rt2560_tx_intr(struct rt2560_softc *sc)
DPRINTFN(sc, 9, "data frame failed after %d retries\n",
retrycnt);
if (data->rix != IEEE80211_FIXED_RATE_NONE)
ieee80211_amrr_tx_complete(&rn->amrr,
IEEE80211_AMRR_FAILURE, retrycnt);
ieee80211_ratectl_tx_complete(vap, ni,
IEEE80211_RATECTL_TX_FAILURE,
&retrycnt, NULL);
ifp->if_oerrors++;
break;
@@ -1823,7 +1800,7 @@ rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0,
} else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
rate = tp->ucastrate;
} else {
(void) ieee80211_amrr_choose(ni, &RT2560_NODE(ni)->amrr);
(void) ieee80211_ratectl_rate(ni, NULL, 0);
rate = ni->ni_txrate;
}
@@ -2682,8 +2659,7 @@ rt2560_init_locked(struct rt2560_softc *sc)
RAL_WRITE(sc, RT2560_CSR1, RT2560_HOST_READY);
if (rt2560_bbp_init(sc) != 0) {
rt2560_stop(sc);
RAL_UNLOCK(sc);
rt2560_stop_locked(sc);
return;
}
@@ -95,16 +95,9 @@ struct rt2560_rx_ring {
int cur_decrypt;
};
struct rt2560_node {
struct ieee80211_node ni;
struct ieee80211_amrr_node amrr;
};
#define RT2560_NODE(ni) ((struct rt2560_node *)(ni))
struct rt2560_vap {
struct ieee80211vap ral_vap;
struct ieee80211_beacon_offsets ral_bo;
struct ieee80211_amrr amrr;
int (*ral_newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
@@ -55,7 +55,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_regdomain.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_ratectl.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -100,9 +100,6 @@ static void rt2661_reset_rx_ring(struct rt2661_softc *,
struct rt2661_rx_ring *);
static void rt2661_free_rx_ring(struct rt2661_softc *,
struct rt2661_rx_ring *);
static struct ieee80211_node *rt2661_node_alloc(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN]);
static void rt2661_newassoc(struct ieee80211_node *, int);
static int rt2661_newstate(struct ieee80211vap *,
enum ieee80211_state, int);
static uint16_t rt2661_eeprom_read(struct rt2661_softc *, uint8_t);
@@ -271,8 +268,8 @@ rt2661_attach(device_t dev, int id)
ifp->if_init = rt2661_init;
ifp->if_ioctl = rt2661_ioctl;
ifp->if_start = rt2661_start;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
IFQ_SET_READY(&ifp->if_snd);
ic->ic_ifp = ifp;
@@ -306,8 +303,6 @@ rt2661_attach(device_t dev, int id)
ieee80211_init_channels(ic, NULL, &bands);
ieee80211_ifattach(ic, macaddr);
ic->ic_newassoc = rt2661_newassoc;
ic->ic_node_alloc = rt2661_node_alloc;
#if 0
ic->ic_wme.wme_update = rt2661_wme_update;
#endif
@@ -428,11 +423,7 @@ rt2661_vap_create(struct ieee80211com *ic,
vap->iv_update_beacon = rt2661_beacon_update;
#endif
ieee80211_amrr_init(&rvp->amrr, vap,
IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD,
500 /* ms */);
ieee80211_ratectl_init(vap);
/* complete setup */
ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status);
if (TAILQ_FIRST(&ic->ic_vaps) == vap)
@@ -445,7 +436,7 @@ rt2661_vap_delete(struct ieee80211vap *vap)
{
struct rt2661_vap *rvp = RT2661_VAP(vap);
ieee80211_amrr_cleanup(&rvp->amrr);
ieee80211_ratectl_deinit(vap);
ieee80211_vap_detach(vap);
free(rvp, M_80211_VAP);
}
@@ -771,27 +762,6 @@ rt2661_free_rx_ring(struct rt2661_softc *sc, struct rt2661_rx_ring *ring)
bus_dma_tag_destroy(ring->data_dmat);
}
static struct ieee80211_node *
rt2661_node_alloc(struct ieee80211vap *vap,
const uint8_t mac[IEEE80211_ADDR_LEN])
{
struct rt2661_node *rn;
rn = malloc(sizeof (struct rt2661_node), M_80211_NODE,
M_NOWAIT | M_ZERO);
return (rn != NULL) ? &rn->ni : NULL;
}
static void
rt2661_newassoc(struct ieee80211_node *ni, int isnew)
{
struct ieee80211vap *vap = ni->ni_vap;
ieee80211_amrr_node_init(&RT2661_VAP(vap)->amrr,
&RT2661_NODE(ni)->amrr, ni);
}
static int
rt2661_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
{
@@ -899,9 +869,9 @@ rt2661_tx_intr(struct rt2661_softc *sc)
struct ifnet *ifp = sc->sc_ifp;
struct rt2661_tx_ring *txq;
struct rt2661_tx_data *data;
struct rt2661_node *rn;
uint32_t val;
int qid, retrycnt;
struct ieee80211vap *vap;
for (;;) {
struct ieee80211_node *ni;
@@ -925,8 +895,8 @@ rt2661_tx_intr(struct rt2661_softc *sc)
/* if no frame has been sent, ignore */
if (ni == NULL)
continue;
rn = RT2661_NODE(ni);
else
vap = ni->ni_vap;
switch (RT2661_TX_RESULT(val)) {
case RT2661_TX_SUCCESS:
@@ -935,8 +905,9 @@ rt2661_tx_intr(struct rt2661_softc *sc)
DPRINTFN(sc, 10, "data frame sent successfully after "
"%d retries\n", retrycnt);
if (data->rix != IEEE80211_FIXED_RATE_NONE)
ieee80211_amrr_tx_complete(&rn->amrr,
IEEE80211_AMRR_SUCCESS, retrycnt);
ieee80211_ratectl_tx_complete(vap, ni,
IEEE80211_RATECTL_TX_SUCCESS,
&retrycnt, NULL);
ifp->if_opackets++;
break;
@@ -946,8 +917,9 @@ rt2661_tx_intr(struct rt2661_softc *sc)
DPRINTFN(sc, 9, "%s\n",
"sending data frame failed (too much retries)");
if (data->rix != IEEE80211_FIXED_RATE_NONE)
ieee80211_amrr_tx_complete(&rn->amrr,
IEEE80211_AMRR_FAILURE, retrycnt);
ieee80211_ratectl_tx_complete(vap, ni,
IEEE80211_RATECTL_TX_FAILURE,
&retrycnt, NULL);
ifp->if_oerrors++;
break;
@@ -1513,7 +1485,7 @@ rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m0,
} else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
rate = tp->ucastrate;
} else {
(void) ieee80211_amrr_choose(ni, &RT2661_NODE(ni)->amrr);
(void) ieee80211_ratectl_rate(ni, NULL, 0);
rate = ni->ni_txrate;
}
rate &= IEEE80211_RATE_VAL;
@@ -88,15 +88,8 @@ struct rt2661_rx_ring {
int next;
};
struct rt2661_node {
struct ieee80211_node ni;
struct ieee80211_amrr_node amrr;
};
#define RT2661_NODE(ni) ((struct rt2661_node *)(ni))
struct rt2661_vap {
struct ieee80211vap ral_vap;
struct ieee80211_amrr amrr;
int (*ral_newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
@@ -333,8 +333,8 @@ wi_attach(device_t dev)
ifp->if_ioctl = wi_ioctl;
ifp->if_start = wi_start;
ifp->if_init = wi_init;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
IFQ_SET_READY(&ifp->if_snd);
ic->ic_ifp = ifp;
@@ -634,6 +634,7 @@ void if_attach(struct ifnet *);
int if_delmulti(struct ifnet *, struct sockaddr *);
void if_detach(struct ifnet *);
void if_purgeaddrs(struct ifnet *);
void if_delallmulti(struct ifnet *);
void if_purgemaddrs(struct ifnet *);
void if_down(struct ifnet *);
void if_free(struct ifnet *);
+142 -46
View File
@@ -27,6 +27,9 @@
#include <compat/net/ethernet.h>
int ifqmaxlen = IFQ_MAXLEN;
#define IFNET_HOLD (void *)(uintptr_t)(-1)
@@ -386,6 +389,28 @@ if_findmulti(struct ifnet *ifp, struct sockaddr *_address)
}
/*
* if_freemulti: free ifmultiaddr structure and possibly attached related
* addresses. The caller is responsible for implementing reference
* counting, notifying the driver, handling routing messages, and releasing
* any dependent link layer state.
*/
static void
if_freemulti(struct ifmultiaddr *ifma)
{
KASSERT(ifma->ifma_refcount == 0, ("if_freemulti: refcount %d",
ifma->ifma_refcount));
KASSERT(ifma->ifma_protospec == NULL,
("if_freemulti: protospec not NULL"));
if (ifma->ifma_lladdr != NULL)
free(ifma->ifma_lladdr);
free(ifma->ifma_addr);
free(ifma);
}
static struct ifmultiaddr *
_if_addmulti(struct ifnet *ifp, struct sockaddr *address)
{
@@ -441,6 +466,96 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *address,
}
static int
if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching)
{
struct ifmultiaddr *ll_ifma;
if (ifp != NULL && ifma->ifma_ifp != NULL) {
KASSERT(ifma->ifma_ifp == ifp,
("%s: inconsistent ifp %p", __func__, ifp));
IF_ADDR_LOCK_ASSERT(ifp);
}
ifp = ifma->ifma_ifp;
/*
* If the ifnet is detaching, null out references to ifnet,
* so that upper protocol layers will notice, and not attempt
* to obtain locks for an ifnet which no longer exists. The
* routing socket announcement must happen before the ifnet
* instance is detached from the system.
*/
if (detaching) {
#ifdef DIAGNOSTIC
printf("%s: detaching ifnet instance %p\n", __func__, ifp);
#endif
/*
* ifp may already be nulled out if we are being reentered
* to delete the ll_ifma.
*/
if (ifp != NULL) {
#ifndef __HAIKU__
rt_newmaddrmsg(RTM_DELMADDR, ifma);
#endif
ifma->ifma_ifp = NULL;
}
}
if (--ifma->ifma_refcount > 0)
return 0;
#ifndef __HAIKU__
/*
* If this ifma is a network-layer ifma, a link-layer ifma may
* have been associated with it. Release it first if so.
*/
ll_ifma = ifma->ifma_llifma;
if (ll_ifma != NULL) {
KASSERT(ifma->ifma_lladdr != NULL,
("%s: llifma w/o lladdr", __func__));
if (detaching)
ll_ifma->ifma_ifp = NULL; /* XXX */
if (--ll_ifma->ifma_refcount == 0) {
if (ifp != NULL) {
TAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma,
ifma_link);
}
if_freemulti(ll_ifma);
}
}
#endif
if (ifp != NULL)
TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
if_freemulti(ifma);
/*
* The last reference to this instance of struct ifmultiaddr
* was released; the hardware should be notified of this change.
*/
return 1;
}
/*
* Delete all multicast group membership for an interface.
* Should be used to quickly flush all multicast filters.
*/
void
if_delallmulti(struct ifnet *ifp)
{
struct ifmultiaddr *ifma;
struct ifmultiaddr *next;
IF_ADDR_LOCK(ifp);
TAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next)
if_delmulti_locked(ifp, ifma, 0);
IF_ADDR_UNLOCK(ifp);
}
static void
if_delete_multiaddr(struct ifnet *ifp, struct ifmultiaddr *ifma)
{
@@ -450,60 +565,41 @@ if_delete_multiaddr(struct ifnet *ifp, struct ifmultiaddr *ifma)
int
if_delmulti(struct ifnet *ifp, struct sockaddr *address)
if_delmulti(struct ifnet *ifp, struct sockaddr *sa)
{
struct ifmultiaddr *addr;
int deleted = 0;
struct ifmultiaddr *ifma;
int lastref;
#ifdef INVARIANTS
struct ifnet *oifp;
IFNET_RLOCK_NOSLEEP();
TAILQ_FOREACH(oifp, &V_ifnet, if_link)
if (ifp == oifp)
break;
if (ifp != oifp)
ifp = NULL;
IFNET_RUNLOCK_NOSLEEP();
KASSERT(ifp != NULL, ("%s: ifnet went away", __func__));
#endif
if (ifp == NULL)
return (ENOENT);
IF_ADDR_LOCK(ifp);
addr = if_findmulti(ifp, address);
if (addr != NULL) {
addr->ifma_refcount--;
if (addr->ifma_refcount == 0) {
if_delete_multiaddr(ifp, addr);
deleted = 1;
}
}
lastref = 0;
ifma = if_findmulti(ifp, sa);
if (ifma != NULL)
lastref = if_delmulti_locked(ifp, ifma, 0);
IF_ADDR_UNLOCK(ifp);
if (deleted && ifp->if_ioctl != NULL)
ifp->if_ioctl(ifp, SIOCDELMULTI, NULL);
if (ifma == NULL)
return (ENOENT);
return 0;
}
static void
if_freemulti(struct ifmultiaddr *ifma)
{
if (ifma->ifma_lladdr != NULL)
free(ifma->ifma_lladdr);
free(ifma->ifma_addr);
free(ifma);
}
static int
if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma,
int detaching)
{
ifp = ifma->ifma_ifp;
if (detaching) {
if (ifp != NULL) {
ifma->ifma_ifp = NULL;
}
if (lastref && ifp->if_ioctl != NULL) {
(void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, 0);
}
if (--ifma->ifma_refcount > 0)
return 0;
if (ifp != NULL)
TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
if_freemulti(ifma);
return 1;
return (0);
}
@@ -42,7 +42,10 @@ KernelStaticLibrary libfreebsd_wlan.a :
ieee80211_power.c
ieee80211_proto.c
ieee80211_radiotap.c
ieee80211_ratectl.c
ieee80211_ratectl_none.c
ieee80211_regdomain.c
ieee80211_rssadapt.c
ieee80211_scan_sta.c
ieee80211_scan.c
ieee80211_sta.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#ifdef IEEE80211_SUPPORT_SUPERG
#include <net80211/ieee80211_superg.h>
#endif
#include <net80211/ieee80211_ratectl.h>
#include <net/bpf.h>
@@ -393,11 +394,10 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap,
ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
ifp->if_start = ieee80211_start;
ifp->if_ioctl = ieee80211_ioctl;
ifp->if_watchdog = NULL; /* NB: no watchdog routine */
ifp->if_init = ieee80211_init;
/* NB: input+output filled in by ether_ifattach */
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
IFQ_SET_READY(&ifp->if_snd);
vap->iv_ifp = ifp;
@@ -443,6 +443,9 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap,
/* auto-enable s/w beacon miss support */
if (flags & IEEE80211_CLONE_NOBEACONS)
vap->iv_flags_ext |= IEEE80211_FEXT_SWBMISS;
/* auto-generated or user supplied MAC address */
if (flags & (IEEE80211_CLONE_BSSID|IEEE80211_CLONE_MACADDR))
vap->iv_flags_ext |= IEEE80211_FEXT_UNIQMAC;
/*
* Enable various functionality by default if we're
* capable; the driver can override us if it knows better.
@@ -486,6 +489,7 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap,
ieee80211_scan_vattach(vap);
ieee80211_regdomain_vattach(vap);
ieee80211_radiotap_vattach(vap);
ieee80211_ratectl_set(vap, IEEE80211_RATECTL_NONE);
return 0;
}
@@ -105,7 +105,7 @@ ieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f)
meshlm_send_action[act] = f;
return 0;
case IEEE80211_ACTION_CAT_MESHPATH:
if (act > N(hwmp_send_action))
if (act >= N(hwmp_send_action))
break;
hwmp_send_action[act] = f;
return 0;
@@ -293,7 +293,7 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
struct ieee80211_frame *wh;
struct ieee80211_key *key;
struct ether_header *eh;
int hdrspace, need_tap;
int hdrspace, need_tap = 1; /* mbuf need to be tapped. */
uint8_t dir, type, subtype, qos;
uint8_t *bssid;
uint16_t rxseq;
@@ -318,7 +318,6 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
KASSERT(ni != NULL, ("null node"));
ni->ni_inact = ni->ni_inact_reload;
need_tap = 1; /* mbuf need to be tapped. */
type = -1; /* undefined */
if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {
@@ -1,6 +1,7 @@
/* $OpenBSD: ieee80211_amrr.c,v 1.1 2006/06/17 19:07:19 damien Exp $ */
/*-
* Copyright (c) 2010 Rui Paulo <rpaulo@FreeBSD.org>
* Copyright (c) 2006
* Damien Bergamini <damien.bergamini@free.fr>
*
@@ -46,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_ratectl.h>
#define is_success(amn) \
((amn)->amn_retrycnt < (amn)->amn_txcnt / 10)
@@ -54,15 +56,45 @@ __FBSDID("$FreeBSD$");
#define is_enough(amn) \
((amn)->amn_txcnt > 10)
static void amrr_sysctlattach(struct ieee80211_amrr *amrr,
struct sysctl_ctx_list *ctx, struct sysctl_oid *tree);
static void amrr_setinterval(const struct ieee80211vap *, int);
static void amrr_init(struct ieee80211vap *);
static void amrr_deinit(struct ieee80211vap *);
static void amrr_node_init(struct ieee80211_node *);
static void amrr_node_deinit(struct ieee80211_node *);
static int amrr_update(struct ieee80211_amrr *,
struct ieee80211_amrr_node *, struct ieee80211_node *);
static int amrr_rate(struct ieee80211_node *, void *, uint32_t);
static void amrr_tx_complete(const struct ieee80211vap *,
const struct ieee80211_node *, int,
void *, void *);
static void amrr_tx_update(const struct ieee80211vap *vap,
const struct ieee80211_node *, void *, void *, void *);
static void amrr_sysctlattach(struct ieee80211vap *,
struct sysctl_ctx_list *, struct sysctl_oid *);
/* number of references from net80211 layer */
static int nrefs = 0;
void
ieee80211_amrr_setinterval(struct ieee80211_amrr *amrr, int msecs)
static const struct ieee80211_ratectl amrr = {
.ir_name = "amrr",
.ir_attach = NULL,
.ir_detach = NULL,
.ir_init = amrr_init,
.ir_deinit = amrr_deinit,
.ir_node_init = amrr_node_init,
.ir_node_deinit = amrr_node_deinit,
.ir_rate = amrr_rate,
.ir_tx_complete = amrr_tx_complete,
.ir_tx_update = amrr_tx_update,
.ir_setinterval = amrr_setinterval,
};
IEEE80211_RATECTL_MODULE(amrr, 1);
IEEE80211_RATECTL_ALG(amrr, IEEE80211_RATECTL_AMRR, amrr);
static void
amrr_setinterval(const struct ieee80211vap *vap, int msecs)
{
struct ieee80211_amrr *amrr = vap->iv_rs;
int t;
if (msecs < 100)
@@ -71,29 +103,49 @@ ieee80211_amrr_setinterval(struct ieee80211_amrr *amrr, int msecs)
amrr->amrr_interval = (t < 1) ? 1 : t;
}
void
ieee80211_amrr_init(struct ieee80211_amrr *amrr,
struct ieee80211vap *vap, int amin, int amax, int interval)
static void
amrr_init(struct ieee80211vap *vap)
{
/* XXX bounds check? */
amrr->amrr_min_success_threshold = amin;
amrr->amrr_max_success_threshold = amax;
ieee80211_amrr_setinterval(amrr, interval);
struct ieee80211_amrr *amrr;
amrr_sysctlattach(amrr, vap->iv_sysctl, vap->iv_oid);
KASSERT(vap->iv_rs == NULL, ("%s called multiple times", __func__));
amrr = vap->iv_rs = malloc(sizeof(struct ieee80211_amrr),
M_80211_RATECTL, M_NOWAIT|M_ZERO);
if (amrr == NULL) {
if_printf(vap->iv_ifp, "couldn't alloc ratectl structure\n");
return;
}
amrr->amrr_min_success_threshold = IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD;
amrr->amrr_max_success_threshold = IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD;
amrr_setinterval(vap, 500 /* ms */);
amrr_sysctlattach(vap, vap->iv_sysctl, vap->iv_oid);
}
void
ieee80211_amrr_cleanup(struct ieee80211_amrr *amrr)
static void
amrr_deinit(struct ieee80211vap *vap)
{
free(vap->iv_rs, M_80211_RATECTL);
}
void
ieee80211_amrr_node_init(struct ieee80211_amrr *amrr,
struct ieee80211_amrr_node *amn, struct ieee80211_node *ni)
static void
amrr_node_init(struct ieee80211_node *ni)
{
const struct ieee80211_rateset *rs = &ni->ni_rates;
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_amrr *amrr = vap->iv_rs;
struct ieee80211_amrr_node *amn;
if (ni->ni_rctls == NULL) {
ni->ni_rctls = amn = malloc(sizeof(struct ieee80211_amrr_node),
M_80211_RATECTL, M_NOWAIT|M_ZERO);
if (amn == NULL) {
if_printf(vap->iv_ifp, "couldn't alloc per-node ratectl "
"structure\n");
return;
}
} else
amn = ni->ni_rctls;
amn->amn_amrr = amrr;
amn->amn_success = 0;
amn->amn_recovery = 0;
@@ -112,6 +164,12 @@ ieee80211_amrr_node_init(struct ieee80211_amrr *amrr,
"AMRR initial rate %d", ni->ni_txrate);
}
static void
amrr_node_deinit(struct ieee80211_node *ni)
{
free(ni->ni_rctls, M_80211_RATECTL);
}
static int
amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn,
struct ieee80211_node *ni)
@@ -168,10 +226,10 @@ amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn,
* Update our internal state if it's been long enough.
* If the rate changes we also update ni_txrate to match.
*/
int
ieee80211_amrr_choose(struct ieee80211_node *ni,
struct ieee80211_amrr_node *amn)
static int
amrr_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused)
{
struct ieee80211_amrr_node *amn = ni->ni_rctls;
struct ieee80211_amrr *amrr = amn->amn_amrr;
int rix;
@@ -189,27 +247,65 @@ ieee80211_amrr_choose(struct ieee80211_node *ni,
return rix;
}
/*
* Update statistics with tx complete status. Ok is non-zero
* if the packet is known to be ACK'd. Retries has the number
* retransmissions (i.e. xmit attempts - 1).
*/
static void
amrr_tx_complete(const struct ieee80211vap *vap,
const struct ieee80211_node *ni, int ok,
void *arg1, void *arg2 __unused)
{
struct ieee80211_amrr_node *amn = ni->ni_rctls;
int retries = *(int *)arg1;
amn->amn_txcnt++;
if (ok)
amn->amn_success++;
amn->amn_retrycnt += retries;
}
/*
* Set tx count/retry statistics explicitly. Intended for
* drivers that poll the device for statistics maintained
* in the device.
*/
static void
amrr_tx_update(const struct ieee80211vap *vap, const struct ieee80211_node *ni,
void *arg1, void *arg2, void *arg3)
{
struct ieee80211_amrr_node *amn = ni->ni_rctls;
int txcnt = *(int *)arg1, success = *(int *)arg2, retrycnt = *(int *)arg3;
amn->amn_txcnt = txcnt;
amn->amn_success = success;
amn->amn_retrycnt = retrycnt;
}
static int
amrr_sysctl_interval(SYSCTL_HANDLER_ARGS)
{
struct ieee80211_amrr *amrr = arg1;
struct ieee80211vap *vap = arg1;
struct ieee80211_amrr *amrr = vap->iv_rs;
int msecs = ticks_to_msecs(amrr->amrr_interval);
int error;
error = sysctl_handle_int(oidp, &msecs, 0, req);
if (error || !req->newptr)
return error;
ieee80211_amrr_setinterval(amrr, msecs);
amrr_setinterval(vap, msecs);
return 0;
}
static void
amrr_sysctlattach(struct ieee80211_amrr *amrr,
amrr_sysctlattach(struct ieee80211vap *vap,
struct sysctl_ctx_list *ctx, struct sysctl_oid *tree)
{
struct ieee80211_amrr *amrr = vap->iv_rs;
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"amrr_rate_interval", CTLTYPE_INT | CTLFLAG_RW, amrr,
"amrr_rate_interval", CTLTYPE_INT | CTLFLAG_RW, vap,
0, amrr_sysctl_interval, "I", "amrr operation interval (ms)");
/* XXX bounds check values */
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
@@ -219,4 +315,3 @@ amrr_sysctlattach(struct ieee80211_amrr *amrr,
"amrr_min_sucess_threshold", CTLFLAG_RW,
&amrr->amrr_min_success_threshold, 0, "");
}
@@ -58,44 +58,4 @@ struct ieee80211_amrr_node {
u_int amn_retrycnt;
};
void ieee80211_amrr_init(struct ieee80211_amrr *, struct ieee80211vap *,
int, int, int);
void ieee80211_amrr_cleanup(struct ieee80211_amrr *);
void ieee80211_amrr_setinterval(struct ieee80211_amrr *, int);
void ieee80211_amrr_node_init(struct ieee80211_amrr *,
struct ieee80211_amrr_node *, struct ieee80211_node *);
int ieee80211_amrr_choose(struct ieee80211_node *,
struct ieee80211_amrr_node *);
#define IEEE80211_AMRR_SUCCESS 1
#define IEEE80211_AMRR_FAILURE 0
/*
* Update statistics with tx complete status. Ok is non-zero
* if the packet is known to be ACK'd. Retries has the number
* retransmissions (i.e. xmit attempts - 1).
*/
static __inline void
ieee80211_amrr_tx_complete(struct ieee80211_amrr_node *amn,
int ok, int retries)
{
amn->amn_txcnt++;
if (ok)
amn->amn_success++;
amn->amn_retrycnt += retries;
}
/*
* Set tx count/retry statistics explicitly. Intended for
* drivers that poll the device for statistics maintained
* in the device.
*/
static __inline void
ieee80211_amrr_tx_update(struct ieee80211_amrr_node *amn,
int txcnt, int success, int retrycnt)
{
amn->amn_txcnt = txcnt;
amn->amn_success = success;
amn->amn_retrycnt = retrycnt;
}
#endif /* _FBSD_COMPAT_NET80211_IEEE80211_AMRR_H_ */
@@ -144,6 +144,7 @@ tkip_setkey(struct ieee80211_key *k)
return 0;
}
k->wk_keytsc = 1; /* TSC starts at 1 */
ctx->rx_phase1_done = 0;
return 1;
}
@@ -161,6 +161,16 @@ typedef struct mtx ieee80211_ageq_lock_t;
#define IEEE80211_AGEQ_LOCK(_aq) mtx_lock(&(_aq)->aq_lock)
#define IEEE80211_AGEQ_UNLOCK(_aq) mtx_unlock(&(_aq)->aq_lock)
/*
* Scan table definitions.
*/
typedef struct mtx ieee80211_scan_table_lock_t;
#define IEEE80211_SCAN_TABLE_LOCK_INIT(_st, _name) \
mtx_init(&(_st)->st_lock, _name, "802.11 scan table", MTX_DEF)
#define IEEE80211_SCAN_TABLE_LOCK_DESTROY(_st) mtx_destroy(&(_st)->st_lock)
#define IEEE80211_SCAN_TABLE_LOCK(_st) mtx_lock(&(_st)->st_lock)
#define IEEE80211_SCAN_TABLE_UNLOCK(_st) mtx_unlock(&(_st)->st_lock)
/*
* Node reference counting definitions.
*
@@ -311,6 +321,23 @@ void ieee80211_scan_sta_init(void);
void ieee80211_scan_sta_uninit(void);
/*
* Rate control modules provide tx rate control support.
*/
#define IEEE80211_RATECTL_MODULE(alg, version) \
_IEEE80211_POLICY_MODULE(ratectl, alg, version); \
#define IEEE80211_RATECTL_ALG(name, alg, v) \
static void \
alg##_modevent(int type) \
{ \
if (type == MOD_LOAD) \
ieee80211_ratectl_register(alg, &v); \
else \
ieee80211_ratectl_unregister(alg); \
} \
TEXT_SET(ratectl##_set, alg##_modevent)
struct ieee80211req;
typedef int ieee80211_ioctl_getfunc(struct ieee80211vap *,
struct ieee80211req *);
@@ -480,7 +480,7 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
struct ieee80211_frame *wh;
struct ieee80211_key *key;
struct ether_header *eh;
int hdrspace, need_tap;
int hdrspace, need_tap = 1; /* mbuf need to be tapped. */
uint8_t dir, type, subtype, qos;
uint8_t *bssid;
uint16_t rxseq;
@@ -505,7 +505,6 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
KASSERT(ni != NULL, ("null node"));
ni->ni_inact = ni->ni_inact_reload;
need_tap = 1; /* mbuf need to be tapped. */
type = -1; /* undefined */
if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {
@@ -884,6 +883,14 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
wh = mtod(m, struct ieee80211_frame *);
wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
}
/*
* Pass the packet to radiotap before calling iv_recv_mgmt().
* Otherwise iv_recv_mgmt() might pass another packet to
* radiotap, resulting in out of order packet captures.
*/
if (ieee80211_radiotap_active_vap(vap))
ieee80211_radiotap_rx(vap, m);
need_tap = 0;
vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
goto out;
@@ -1252,7 +1259,7 @@ ieee80211_parse_wpa(struct ieee80211vap *vap, const uint8_t *frm,
return IEEE80211_REASON_IE_INVALID;
}
frm += 6, len -= 4; /* NB: len is payload only */
/* NB: iswapoui already validated the OUI and type */
/* NB: iswpaoui already validated the OUI and type */
w = LE_READ_2(frm);
if (w != WPA_VERSION) {
IEEE80211_DISCARD_IE(vap,
@@ -148,7 +148,7 @@ typedef uint32_t ieee80211_hwmp_seq;
struct ieee80211_hwmp_route {
ieee80211_hwmp_seq hr_seq; /* last HWMP seq seen from dst*/
ieee80211_hwmp_seq hr_preqid; /* last PREQ ID seen from dst */
ieee80211_hwmp_seq hr_targetseq; /* seq. no. on our latest PREQ*/
ieee80211_hwmp_seq hr_origseq; /* seq. no. on our latest PREQ*/
int hr_preqretries;
};
struct ieee80211_hwmp_state {
@@ -548,7 +548,7 @@ hwmp_add_meshperr(uint8_t *frm, const struct ieee80211_meshperr_ie *perr)
*frm++ = perr->perr_ttl;
*frm++ = perr->perr_ndests;
for (i = 0; i < perr->perr_ndests; i++) {
*frm += perr->perr_dests[i].dest_flags;
*frm++ = perr->perr_dests[i].dest_flags;
IEEE80211_ADDR_COPY(frm, perr->perr_dests[i].dest_addr);
frm += 6;
ADDWORD(frm, perr->perr_dests[i].dest_seq);
@@ -653,6 +653,7 @@ hwmp_rootmode_rann_cb(void *arg)
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
"%s", "send broadcast RANN");
rann.rann_flags = 0;
if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
rann.rann_flags |= IEEE80211_MESHRANN_FLAGS_PR;
rann.rann_hopcount = 0;
@@ -706,6 +707,10 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
rtorig = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
if (rtorig == NULL)
rtorig = ieee80211_mesh_rt_add(vap, preq->preq_origaddr);
if (rtorig == NULL) {
/* XXX stat */
return;
}
hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route);
/*
* Sequence number validation.
@@ -733,12 +738,12 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
prep.prep_flags = 0;
prep.prep_hopcount = 0;
prep.prep_ttl = ms->ms_ttl;
IEEE80211_ADDR_COPY(prep.prep_targetaddr, preq->preq_origaddr);
prep.prep_targetseq = preq->preq_origseq;
IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr);
prep.prep_targetseq = ++hs->hs_seq;
prep.prep_lifetime = preq->preq_lifetime;
prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
IEEE80211_ADDR_COPY(prep.prep_origaddr, vap->iv_myaddr);
prep.prep_origseq = ++hs->hs_seq;
IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr);
prep.prep_origseq = preq->preq_origseq;
hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep);
/*
* Build the reverse path, if we don't have it already.
@@ -784,13 +789,13 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
prep.prep_flags = 0;
prep.prep_hopcount = 0;
prep.prep_ttl = ms->ms_ttl;
IEEE80211_ADDR_COPY(prep.prep_origaddr, vap->iv_myaddr);
IEEE80211_ADDR_COPY(prep.prep_origaddr, rootmac);
prep.prep_origseq = preq->preq_origseq;
prep.prep_targetseq = ++hs->hs_seq;
prep.prep_lifetime = preq->preq_lifetime;
prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
IEEE80211_ADDR_COPY(prep.prep_targetaddr, rootmac);
prep.prep_targetseq = PREQ_TSEQ(0);
IEEE80211_ADDR_COPY(prep.prep_targetaddr,
vap->iv_myaddr);
prep.prep_targetseq = ++hs->hs_seq;
hwmp_send_prep(vap->iv_bss, vap->iv_myaddr,
broadcastaddr, &prep);
}
@@ -848,13 +853,13 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
prep.prep_hopcount = rt->rt_nhops + 1;
prep.prep_ttl = ms->ms_ttl;
IEEE80211_ADDR_COPY(&prep.prep_targetaddr,
preq->preq_origaddr);
PREQ_TADDR(0));
prep.prep_targetseq = hrorig->hr_seq;
prep.prep_lifetime = preq->preq_lifetime;
prep.prep_metric = rt->rt_metric +
ms->ms_pmetric->mpm_metric(ni);
IEEE80211_ADDR_COPY(&prep.prep_origaddr,
PREQ_TADDR(0));
preq->preq_origaddr);
prep.prep_origseq = hrorig->hr_seq;
hwmp_send_prep(ni, vap->iv_myaddr,
broadcastaddr, &prep);
@@ -951,19 +956,19 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
return;
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"received PREP from %s", ether_sprintf(prep->prep_origaddr));
"received PREP from %s", ether_sprintf(prep->prep_targetaddr));
rt = ieee80211_mesh_rt_find(vap, prep->prep_origaddr);
rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
if (rt == NULL) {
/*
* If we have no entry this could be a reply to a root PREQ.
*/
if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) {
rt = ieee80211_mesh_rt_add(vap, prep->prep_origaddr);
rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
if (rt == NULL) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
ni, "unable to add PREP path to %s",
ether_sprintf(prep->prep_origaddr));
ether_sprintf(prep->prep_targetaddr));
vap->iv_stats.is_mesh_rtaddfailed++;
return;
}
@@ -974,7 +979,7 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"add root path to %s nhops %d metric %d (PREP)",
ether_sprintf(prep->prep_origaddr),
ether_sprintf(prep->prep_targetaddr),
rt->rt_nhops, rt->rt_metric);
return;
}
@@ -984,30 +989,30 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
* Sequence number validation.
*/
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
if (HWMP_SEQ_LEQ(prep->prep_origseq, hr->hr_seq)) {
if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq)) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"discard PREP from %s, old seq no %u <= %u",
ether_sprintf(prep->prep_origaddr),
prep->prep_origseq, hr->hr_seq);
ether_sprintf(prep->prep_targetaddr),
prep->prep_targetseq, hr->hr_seq);
return;
}
hr->hr_seq = prep->prep_origseq;
hr->hr_seq = prep->prep_targetseq;
/*
* If it's NOT for us, propagate the PREP.
*/
if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_targetaddr) &&
if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
prep->prep_ttl > 1 && prep->prep_hopcount < hs->hs_maxhops) {
struct ieee80211_meshprep_ie pprep; /* propagated PREP */
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"propagate PREP from %s",
ether_sprintf(prep->prep_origaddr));
ether_sprintf(prep->prep_targetaddr));
memcpy(&pprep, prep, sizeof(pprep));
pprep.prep_hopcount += 1;
pprep.prep_ttl -= 1;
pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
IEEE80211_ADDR_COPY(pprep.prep_origaddr, vap->iv_myaddr);
IEEE80211_ADDR_COPY(pprep.prep_targetaddr, vap->iv_myaddr);
hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep);
}
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
@@ -1015,9 +1020,9 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
/* NB: never clobber a proxy entry */;
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"discard PREP for %s, route is marked PROXY",
ether_sprintf(prep->prep_origaddr));
ether_sprintf(prep->prep_targetaddr));
vap->iv_stats.is_hwmp_proxy++;
} else if (prep->prep_targetseq == hr->hr_targetseq) {
} else if (prep->prep_origseq == hr->hr_origseq) {
/*
* Check if we already have a path to this node.
* If we do, check if this path reply contains a
@@ -1041,14 +1046,14 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
} else {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"ignore PREP for %s, hopcount %d:%d metric %d:%d",
ether_sprintf(prep->prep_origaddr),
ether_sprintf(prep->prep_targetaddr),
rt->rt_nhops, prep->prep_hopcount,
rt->rt_metric, prep->prep_metric);
}
} else {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"discard PREP for %s, wrong seqno %u != %u",
ether_sprintf(prep->prep_origaddr), prep->prep_targetseq,
ether_sprintf(prep->prep_targetaddr), prep->prep_origseq,
hr->hr_seq);
vap->iv_stats.is_hwmp_wrongseq++;
}
@@ -1114,6 +1119,7 @@ hwmp_peerdown(struct ieee80211_node *ni)
"%s", "delete route entry");
perr.perr_ttl = ms->ms_ttl;
perr.perr_ndests = 1;
PERR_DFLAGS(0) = 0;
if (hr->hr_seq == 0)
PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN;
PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC;
@@ -1223,7 +1229,8 @@ hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
struct ieee80211_meshrann_ie prann;
if (ni == vap->iv_bss ||
ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr))
return;
rt = ieee80211_mesh_rt_find(vap, rann->rann_addr);
@@ -1236,15 +1243,18 @@ hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
return;
}
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq) && rann->rann_ttl > 1 &&
rann->rann_hopcount < hs->hs_maxhops &&
(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
memcpy(&prann, rann, sizeof(prann));
prann.rann_hopcount += 1;
prann.rann_ttl -= 1;
prann.rann_metric += ms->ms_pmetric->mpm_metric(ni);
hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, broadcastaddr,
&prann);
if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq)) {
hr->hr_seq = rann->rann_seq;
if (rann->rann_ttl > 1 &&
rann->rann_hopcount < hs->hs_maxhops &&
(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
memcpy(&prann, rann, sizeof(prann));
prann.rann_hopcount += 1;
prann.rann_ttl -= 1;
prann.rann_metric += ms->ms_pmetric->mpm_metric(ni);
hwmp_send_rann(vap->iv_bss, vap->iv_myaddr,
broadcastaddr, &prann);
}
}
}
@@ -1305,8 +1315,8 @@ hwmp_discover(struct ieee80211vap *vap,
hr = IEEE80211_MESH_ROUTE_PRIV(rt,
struct ieee80211_hwmp_route);
if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
if (hr->hr_targetseq == 0)
hr->hr_targetseq = ++hs->hs_seq;
if (hr->hr_origseq == 0)
hr->hr_origseq = ++hs->hs_seq;
rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
rt->rt_lifetime =
ticks_to_msecs(ieee80211_hwmp_pathtimeout);
@@ -1324,7 +1334,7 @@ hwmp_discover(struct ieee80211vap *vap,
preq.preq_ttl = ms->ms_ttl;
preq.preq_id = ++hs->hs_preqid;
IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
preq.preq_origseq = hr->hr_targetseq;
preq.preq_origseq = hr->hr_origseq;
preq.preq_lifetime = rt->rt_lifetime;
preq.preq_metric = rt->rt_metric;
preq.preq_tcount = 1;
@@ -734,7 +734,8 @@ ieee80211_ssid_mismatch(struct ieee80211vap *vap, const char *tag,
* Return the bssid of a frame.
*/
static const uint8_t *
ieee80211_getbssid(struct ieee80211vap *vap, const struct ieee80211_frame *wh)
ieee80211_getbssid(const struct ieee80211vap *vap,
const struct ieee80211_frame *wh)
{
if (vap->iv_opmode == IEEE80211_M_STA)
return wh->i_addr2;
@@ -748,7 +749,7 @@ ieee80211_getbssid(struct ieee80211vap *vap, const struct ieee80211_frame *wh)
#include <machine/stdarg.h>
void
ieee80211_note(struct ieee80211vap *vap, const char *fmt, ...)
ieee80211_note(const struct ieee80211vap *vap, const char *fmt, ...)
{
char buf[128]; /* XXX */
va_list ap;
@@ -761,7 +762,7 @@ ieee80211_note(struct ieee80211vap *vap, const char *fmt, ...)
}
void
ieee80211_note_frame(struct ieee80211vap *vap,
ieee80211_note_frame(const struct ieee80211vap *vap,
const struct ieee80211_frame *wh,
const char *fmt, ...)
{
@@ -776,7 +777,7 @@ ieee80211_note_frame(struct ieee80211vap *vap,
}
void
ieee80211_note_mac(struct ieee80211vap *vap,
ieee80211_note_mac(const struct ieee80211vap *vap,
const uint8_t mac[IEEE80211_ADDR_LEN],
const char *fmt, ...)
{
@@ -790,7 +791,7 @@ ieee80211_note_mac(struct ieee80211vap *vap,
}
void
ieee80211_discard_frame(struct ieee80211vap *vap,
ieee80211_discard_frame(const struct ieee80211vap *vap,
const struct ieee80211_frame *wh,
const char *type, const char *fmt, ...)
{
@@ -811,7 +812,7 @@ ieee80211_discard_frame(struct ieee80211vap *vap,
}
void
ieee80211_discard_ie(struct ieee80211vap *vap,
ieee80211_discard_ie(const struct ieee80211vap *vap,
const struct ieee80211_frame *wh,
const char *type, const char *fmt, ...)
{
@@ -830,7 +831,7 @@ ieee80211_discard_ie(struct ieee80211vap *vap,
}
void
ieee80211_discard_mac(struct ieee80211vap *vap,
ieee80211_discard_mac(const struct ieee80211vap *vap,
const uint8_t mac[IEEE80211_ADDR_LEN],
const char *type, const char *fmt, ...)
{
@@ -1598,8 +1598,10 @@ ieee80211_ioctl_setchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq)
if (list == NULL)
return ENOMEM;
error = copyin(ireq->i_data, list, ireq->i_len);
if (error)
if (error) {
free(list, M_TEMP);
return error;
}
nchan = 0;
chanlist = list + ireq->i_len; /* NB: zero'd already */
maxchan = ireq->i_len * NBBY;
@@ -1615,8 +1617,10 @@ ieee80211_ioctl_setchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq)
nchan++;
}
}
if (nchan == 0)
if (nchan == 0) {
free(list, M_TEMP);
return EINVAL;
}
if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && /* XXX */
isclr(chanlist, ic->ic_bsschan->ic_ieee))
ic->ic_bsschan = IEEE80211_CHAN_ANYC;
@@ -3207,15 +3211,18 @@ ieee80211_ioctl_updatemulti(struct ieee80211com *ic)
void *ioctl;
IEEE80211_LOCK(ic);
if_purgemaddrs(parent);
if_delallmulti(parent);
ioctl = parent->if_ioctl; /* XXX WAR if_allmulti */
parent->if_ioctl = NULL;
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
struct ifnet *ifp = vap->iv_ifp;
struct ifmultiaddr *ifma;
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
(void) if_addmulti(parent, ifma->ifma_addr, NULL);
}
}
parent->if_ioctl = ioctl;
ieee80211_runtask(ic, &ic->ic_mcast_task);
@@ -388,8 +388,6 @@ mesh_select_proto_path(struct ieee80211vap *vap, const char *name)
for (i = 0; i < N(mesh_proto_paths); i++) {
if (strcasecmp(mesh_proto_paths[i].mpp_descr, name) == 0) {
ms->ms_ppath = &mesh_proto_paths[i];
if (vap->iv_state == IEEE80211_S_RUN)
vap->iv_newstate(vap, IEEE80211_S_INIT, 0);
return 0;
}
}
@@ -405,8 +403,6 @@ mesh_select_proto_metric(struct ieee80211vap *vap, const char *name)
for (i = 0; i < N(mesh_proto_metrics); i++) {
if (strcasecmp(mesh_proto_metrics[i].mpm_descr, name) == 0) {
ms->ms_pmetric = &mesh_proto_metrics[i];
if (vap->iv_state == IEEE80211_S_RUN)
vap->iv_newstate(vap, IEEE80211_S_INIT, 0);
return 0;
}
}
@@ -739,10 +735,12 @@ mesh_linkchange(struct ieee80211_node *ni, enum ieee80211_mesh_mlstate state)
ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) {
KASSERT(ms->ms_neighbors < 65535, ("neighbor count overflow"));
ms->ms_neighbors++;
ieee80211_beacon_notify(vap, IEEE80211_BEACON_MESHCONF);
} else if (ni->ni_mlstate == IEEE80211_NODE_MESH_ESTABLISHED &&
state != IEEE80211_NODE_MESH_ESTABLISHED) {
KASSERT(ms->ms_neighbors > 0, ("neighbor count 0"));
ms->ms_neighbors--;
ieee80211_beacon_notify(vap, IEEE80211_BEACON_MESHCONF);
}
ni->ni_mlstate = state;
switch (state) {
@@ -2552,6 +2550,18 @@ ieee80211_mesh_init_neighbor(struct ieee80211_node *ni,
ieee80211_parse_meshid(ni, sp->meshid);
}
void
ieee80211_mesh_update_beacon(struct ieee80211vap *vap,
struct ieee80211_beacon_offsets *bo)
{
KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, ("not a MBSS vap"));
if (isset(bo->bo_flags, IEEE80211_BEACON_MESHCONF)) {
(void)ieee80211_add_meshconf(bo->bo_meshconf, vap);
clrbit(bo->bo_flags, IEEE80211_BEACON_MESHCONF);
}
}
static int
mesh_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
{
@@ -469,6 +469,8 @@ struct ieee80211_scanparams;
void ieee80211_mesh_init_neighbor(struct ieee80211_node *,
const struct ieee80211_frame *,
const struct ieee80211_scanparams *);
void ieee80211_mesh_update_beacon(struct ieee80211vap *,
struct ieee80211_beacon_offsets *);
/*
* Return non-zero if proxy operation is enabled.
@@ -218,7 +218,8 @@ struct ieee80211_node {
struct ieee80211_nodestats ni_stats; /* per-node statistics */
struct ieee80211vap *ni_wdsvap; /* associated WDS vap */
uint64_t ni_spare[4];
void *ni_rctls; /* private ratectl state */
uint64_t ni_spare[3];
};
#define IEEE80211_NODE_ATH (IEEE80211_NODE_FF | IEEE80211_NODE_TURBOP)
@@ -2570,6 +2570,7 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
#ifdef IEEE80211_SUPPORT_MESH
if (vap->iv_opmode == IEEE80211_M_MBSS) {
frm = ieee80211_add_meshid(frm, vap);
bo->bo_meshconf = frm;
frm = ieee80211_add_meshconf(frm, vap);
}
#endif
@@ -2675,13 +2676,7 @@ ieee80211_beacon_alloc(struct ieee80211_node *ni,
*(uint16_t *)wh->i_dur = 0;
IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr);
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
#ifdef IEEE80211_SUPPORT_MESH
if (vap->iv_opmode == IEEE80211_M_MBSS) {
static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
IEEE80211_ADDR_COPY(wh->i_addr3, zerobssid);
} else
#endif
IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
*(uint16_t *)wh->i_seq = 0;
return m;
@@ -2786,6 +2781,11 @@ ieee80211_beacon_update(struct ieee80211_node *ni,
ieee80211_tdma_update_beacon(vap, bo);
}
#endif
#ifdef IEEE80211_SUPPORT_MESH
if (vap->iv_opmode == IEEE80211_M_MBSS)
ieee80211_mesh_update_beacon(vap, bo);
#endif
if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
vap->iv_opmode == IEEE80211_M_MBSS) { /* NB: no IBSS support*/
struct ieee80211_tim_ie *tie =
@@ -2839,6 +2839,9 @@ ieee80211_beacon_update(struct ieee80211_node *ni,
#endif
#ifdef IEEE80211_TDMA_SUPPORT
bo->bo_tdma += adjust;
#endif
#ifdef IEEE80211_MESH_SUPPORT
bo->bo_meshconf += adjust;
#endif
bo->bo_appie += adjust;
bo->bo_wme += adjust;
@@ -2890,6 +2893,9 @@ ieee80211_beacon_update(struct ieee80211_node *ni,
#endif
#ifdef IEEE80211_TDMA_SUPPORT
bo->bo_tdma += sizeof(*csa);
#endif
#ifdef IEEE80211_MESH_SUPPORT
bo->bo_meshconf += sizeof(*csa);
#endif
bo->bo_appie += sizeof(*csa);
bo->bo_csa_trailer_len += sizeof(*csa);
@@ -1432,8 +1432,6 @@ ieee80211_swbmiss(void *arg)
} else if (vap->iv_swbmiss_count == 0) {
if (vap->iv_bmiss != NULL)
ieee80211_runtask(ic, &vap->iv_swbmiss_task);
if (vap->iv_bmiss_count == 0) /* don't re-arm timer */
return;
} else
vap->iv_swbmiss_count = 0;
callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period,
@@ -317,9 +317,10 @@ struct ieee80211_beacon_offsets {
uint8_t *bo_ath; /* start of ATH parameters */
uint8_t *bo_appie; /* start of AppIE element */
uint16_t bo_appie_len; /* AppIE length in bytes */
uint16_t bo_csa_trailer_len;;
uint16_t bo_csa_trailer_len;
uint8_t *bo_csa; /* start of CSA element */
uint8_t *bo_spare[4];
uint8_t *bo_meshconf; /* start of MESHCONF element */
uint8_t *bo_spare[3];
};
struct mbuf *ieee80211_beacon_alloc(struct ieee80211_node *,
struct ieee80211_beacon_offsets *);
@@ -347,6 +348,7 @@ enum {
IEEE80211_BEACON_CSA = 7, /* Channel Switch Announcement */
IEEE80211_BEACON_TDMA = 9, /* TDMA Info */
IEEE80211_BEACON_ATH = 10, /* ATH parameters */
IEEE80211_BEACON_MESHCONF = 11, /* Mesh Configuration */
};
int ieee80211_beacon_update(struct ieee80211_node *,
struct ieee80211_beacon_offsets *, struct mbuf *, int mcast);
@@ -0,0 +1,92 @@
/*-
* Copyright (c) 2010 Rui Paulo <rpaulo@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_ratectl.h>
static const struct ieee80211_ratectl *ratectls[IEEE80211_RATECTL_MAX];
static const char *ratectl_modnames[IEEE80211_RATECTL_MAX] = {
[IEEE80211_RATECTL_AMRR] = "wlan_amrr",
[IEEE80211_RATECTL_RSSADAPT] = "wlan_rssadapt",
[IEEE80211_RATECTL_ONOE] = "wlan_onoe",
[IEEE80211_RATECTL_SAMPLE] = "wlan_sample",
[IEEE80211_RATECTL_NONE] = "wlan_none",
};
MALLOC_DEFINE(M_80211_RATECTL, "80211ratectl", "802.11 rate control");
void
ieee80211_ratectl_register(int type, const struct ieee80211_ratectl *ratectl)
{
if (type >= IEEE80211_RATECTL_MAX)
return;
ratectls[type] = ratectl;
}
void
ieee80211_ratectl_unregister(int type)
{
if (type >= IEEE80211_RATECTL_MAX)
return;
ratectls[type] = NULL;
}
void
ieee80211_ratectl_init(struct ieee80211vap *vap)
{
if (vap->iv_rate == ratectls[IEEE80211_RATECTL_NONE])
ieee80211_ratectl_set(vap, IEEE80211_RATECTL_AMRR);
vap->iv_rate->ir_init(vap);
}
void
ieee80211_ratectl_set(struct ieee80211vap *vap, int type)
{
if (type >= IEEE80211_RATECTL_MAX)
return;
if (ratectls[type] == NULL) {
ieee80211_load_module(ratectl_modnames[type]);
if (ratectls[type] == NULL) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_RATECTL,
"%s: unable to load algo %u, module %s\n",
__func__, type, ratectl_modnames[type]);
vap->iv_rate = ratectls[IEEE80211_RATECTL_NONE];
return;
}
}
vap->iv_rate = ratectls[type];
}
@@ -26,10 +26,11 @@
*/
enum ieee80211_ratealgs {
IEEE80211_RATECTL_AMRR = 0,
IEEE80211_RATECTL_AMRR = 0,
IEEE80211_RATECTL_RSSADAPT = 1,
IEEE80211_RATECTL_ONOE = 2,
IEEE80211_RATECTL_SAMPLE = 3,
IEEE80211_RATECTL_NONE = 4,
IEEE80211_RATECTL_MAX
};
@@ -56,15 +57,10 @@ struct ieee80211_ratectl {
void ieee80211_ratectl_register(int, const struct ieee80211_ratectl *);
void ieee80211_ratectl_unregister(int);
void ieee80211_ratectl_init(struct ieee80211vap *);
void ieee80211_ratectl_set(struct ieee80211vap *, int);
MALLOC_DECLARE(M_80211_RATECTL);
#ifndef __HAIKU__
static void __inline
ieee80211_ratectl_init(struct ieee80211vap *vap)
{
vap->iv_rate->ir_init(vap);
}
static void __inline
ieee80211_ratectl_deinit(struct ieee80211vap *vap)
@@ -76,8 +72,9 @@ static void __inline
ieee80211_ratectl_node_init(struct ieee80211_node *ni)
{
const struct ieee80211vap *vap = ni->ni_vap;
kernel_debugger("ieee80211_ratectl_node_init\n");
vap->iv_rate->ir_node_init(ni);
kernel_debugger("ieee80211_ratectl_node_init exit\n");
}
static void __inline
@@ -85,8 +82,6 @@ ieee80211_ratectl_node_deinit(struct ieee80211_node *ni)
{
const struct ieee80211vap *vap = ni->ni_vap;
if (ni->ni_rctls == NULL) /* ratectl not setup */
return;
vap->iv_rate->ir_node_deinit(ni);
}
@@ -95,8 +90,6 @@ ieee80211_ratectl_rate(struct ieee80211_node *ni, void *arg, uint32_t iarg)
{
const struct ieee80211vap *vap = ni->ni_vap;
if (ni->ni_rctls == NULL) /* ratectl not setup */
return 0;
return vap->iv_rate->ir_rate(ni, arg, iarg);
}
@@ -104,8 +97,6 @@ static void __inline
ieee80211_ratectl_tx_complete(const struct ieee80211vap *vap,
const struct ieee80211_node *ni, int status, void *arg1, void *arg2)
{
if (ni->ni_rctls == NULL) /* ratectl not setup */
return;
vap->iv_rate->ir_tx_complete(vap, ni, status, arg1, arg2);
}
@@ -115,8 +106,6 @@ ieee80211_ratectl_tx_update(const struct ieee80211vap *vap,
{
if (vap->iv_rate->ir_tx_update == NULL)
return;
if (ni->ni_rctls == NULL) /* ratectl not setup */
return;
vap->iv_rate->ir_tx_update(vap, ni, arg1, arg2, arg3);
}
@@ -127,4 +116,3 @@ ieee80211_ratectl_setinterval(const struct ieee80211vap *vap, int msecs)
return;
vap->iv_rate->ir_setinterval(vap, msecs);
}
#endif
@@ -0,0 +1,114 @@
/*-
* Copyright (c) 2010 Bernhard Schmidt <bschmidt@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_wlan.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_media.h>
#ifdef INET
#include <netinet/in.h>
#include <netinet/if_ether.h>
#endif
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_ratectl.h>
static void
none_init(struct ieee80211vap *vap)
{
}
static void
none_deinit(struct ieee80211vap *vap)
{
free(vap->iv_rs, M_80211_RATECTL);
}
static void
none_node_init(struct ieee80211_node *ni)
{
ni->ni_txrate = ni->ni_rates.rs_rates[0] & IEEE80211_RATE_VAL;
}
static void
none_node_deinit(struct ieee80211_node *ni)
{
}
static int
none_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused)
{
int rix = 0;
ni->ni_txrate = ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL;
return rix;
}
static void
none_tx_complete(const struct ieee80211vap *vap,
const struct ieee80211_node *ni, int ok,
void *arg1, void *arg2 __unused)
{
}
static void
none_tx_update(const struct ieee80211vap *vap, const struct ieee80211_node *ni,
void *arg1, void *arg2, void *arg3)
{
}
static void
none_setinterval(const struct ieee80211vap *vap, int msecs)
{
}
/* number of references from net80211 layer */
static int nrefs = 0;
static const struct ieee80211_ratectl none = {
.ir_name = "none",
.ir_attach = NULL,
.ir_detach = NULL,
.ir_init = none_init,
.ir_deinit = none_deinit,
.ir_node_init = none_node_init,
.ir_node_deinit = none_node_deinit,
.ir_rate = none_rate,
.ir_tx_complete = none_tx_complete,
.ir_tx_update = none_tx_update,
.ir_setinterval = none_setinterval,
};
IEEE80211_RATECTL_MODULE(ratectl_none, 1);
IEEE80211_RATECTL_ALG(none, IEEE80211_RATECTL_NONE, none);
@@ -1,6 +1,7 @@
/* $FreeBSD$ */
/* $NetBSD: ieee80211_rssadapt.c,v 1.9 2005/02/26 22:45:09 perry Exp $ */
/*-
* Copyright (c) 2010 Rui Paulo <rpaulo@FreeBSD.org>
* Copyright (c) 2003, 2004 David Young. All rights reserved.
*
* Redistribution and use in source and binary forms, with or
@@ -42,6 +43,7 @@
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_rssadapt.h>
#include <net80211/ieee80211_ratectl.h>
struct rssadapt_expavgctl {
/* RSS threshold decay. */
@@ -56,12 +58,12 @@ struct rssadapt_expavgctl {
};
static struct rssadapt_expavgctl master_expavgctl = {
rc_decay_denom : 16,
rc_decay_old : 15,
rc_thresh_denom : 8,
rc_thresh_old : 4,
rc_avgrssi_denom : 8,
rc_avgrssi_old : 4
.rc_decay_denom = 16,
.rc_decay_old = 15,
.rc_thresh_denom = 8,
.rc_thresh_old = 4,
.rc_avgrssi_denom = 8,
.rc_avgrssi_old = 4
};
#ifdef interpolate
@@ -71,15 +73,45 @@ static struct rssadapt_expavgctl master_expavgctl = {
(parm##_denom - parm##_old) * (new)) / \
parm##_denom)
static void rssadapt_sysctlattach(struct ieee80211_rssadapt *rs,
struct sysctl_ctx_list *ctx, struct sysctl_oid *tree);
static void rssadapt_setinterval(const struct ieee80211vap *, int);
static void rssadapt_init(struct ieee80211vap *);
static void rssadapt_deinit(struct ieee80211vap *);
static void rssadapt_updatestats(struct ieee80211_rssadapt_node *);
static void rssadapt_node_init(struct ieee80211_node *);
static void rssadapt_node_deinit(struct ieee80211_node *);
static int rssadapt_rate(struct ieee80211_node *, void *, uint32_t);
static void rssadapt_lower_rate(struct ieee80211_rssadapt_node *, int, int);
static void rssadapt_raise_rate(struct ieee80211_rssadapt_node *,
int, int);
static void rssadapt_tx_complete(const struct ieee80211vap *,
const struct ieee80211_node *, int,
void *, void *);
static void rssadapt_sysctlattach(struct ieee80211vap *,
struct sysctl_ctx_list *, struct sysctl_oid *);
/* number of references from net80211 layer */
static int nrefs = 0;
void
ieee80211_rssadapt_setinterval(struct ieee80211_rssadapt *rs, int msecs)
static const struct ieee80211_ratectl rssadapt = {
.ir_name = "rssadapt",
.ir_attach = NULL,
.ir_detach = NULL,
.ir_init = rssadapt_init,
.ir_deinit = rssadapt_deinit,
.ir_node_init = rssadapt_node_init,
.ir_node_deinit = rssadapt_node_deinit,
.ir_rate = rssadapt_rate,
.ir_tx_complete = rssadapt_tx_complete,
.ir_tx_update = NULL,
.ir_setinterval = rssadapt_setinterval,
};
IEEE80211_RATECTL_MODULE(rssadapt, 1);
IEEE80211_RATECTL_ALG(rssadapt, IEEE80211_RATECTL_RSSADAPT, rssadapt);
static void
rssadapt_setinterval(const struct ieee80211vap *vap, int msecs)
{
struct ieee80211_rssadapt *rs = vap->iv_rs;
int t;
if (msecs < 100)
@@ -88,18 +120,29 @@ ieee80211_rssadapt_setinterval(struct ieee80211_rssadapt *rs, int msecs)
rs->interval = (t < 1) ? 1 : t;
}
void
ieee80211_rssadapt_init(struct ieee80211_rssadapt *rs, struct ieee80211vap *vap, int interval)
static void
rssadapt_init(struct ieee80211vap *vap)
{
rs->vap = vap;
ieee80211_rssadapt_setinterval(rs, interval);
struct ieee80211_rssadapt *rs;
rssadapt_sysctlattach(rs, vap->iv_sysctl, vap->iv_oid);
KASSERT(vap->iv_rs == NULL, ("%s: iv_rs already initialized",
__func__));
vap->iv_rs = rs = malloc(sizeof(struct ieee80211_rssadapt),
M_80211_RATECTL, M_NOWAIT|M_ZERO);
if (rs == NULL) {
if_printf(vap->iv_ifp, "couldn't alloc ratectl structure\n");
return;
}
rs->vap = vap;
rssadapt_setinterval(vap, 500 /* msecs */);
rssadapt_sysctlattach(vap, vap->iv_sysctl, vap->iv_oid);
}
void
ieee80211_rssadapt_cleanup(struct ieee80211_rssadapt *rs)
static void
rssadapt_deinit(struct ieee80211vap *vap)
{
free(vap->iv_rs, M_80211_RATECTL);
}
static void
@@ -118,12 +161,25 @@ rssadapt_updatestats(struct ieee80211_rssadapt_node *ra)
ra->ra_raise_interval = msecs_to_ticks(interval);
}
void
ieee80211_rssadapt_node_init(struct ieee80211_rssadapt *rsa,
struct ieee80211_rssadapt_node *ra, struct ieee80211_node *ni)
static void
rssadapt_node_init(struct ieee80211_node *ni)
{
struct ieee80211_rssadapt_node *ra;
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_rssadapt *rsa = vap->iv_rs;
const struct ieee80211_rateset *rs = &ni->ni_rates;
if (ni->ni_rctls == NULL) {
ni->ni_rctls = ra =
malloc(sizeof(struct ieee80211_rssadapt_node),
M_80211_RATECTL, M_NOWAIT|M_ZERO);
if (ra == NULL) {
if_printf(vap->iv_ifp, "couldn't alloc per-node ratectl "
"structure\n");
return;
}
} else
ra = ni->ni_rctls;
ra->ra_rs = rsa;
ra->ra_rates = *rs;
rssadapt_updatestats(ra);
@@ -140,6 +196,13 @@ ieee80211_rssadapt_node_init(struct ieee80211_rssadapt *rsa,
"RSSADAPT initial rate %d", ni->ni_txrate);
}
static void
rssadapt_node_deinit(struct ieee80211_node *ni)
{
free(ni->ni_rctls, M_80211_RATECTL);
}
static __inline int
bucket(int pktlen)
{
@@ -155,10 +218,11 @@ bucket(int pktlen)
return thridx;
}
int
ieee80211_rssadapt_choose(struct ieee80211_node *ni,
struct ieee80211_rssadapt_node *ra, u_int pktlen)
static int
rssadapt_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg)
{
struct ieee80211_rssadapt_node *ra = ni->ni_rctls;
u_int pktlen = iarg;
const struct ieee80211_rateset *rs = &ra->ra_rates;
uint16_t (*thrs)[IEEE80211_RATE_SIZE];
int rix, rssi;
@@ -193,9 +257,8 @@ ieee80211_rssadapt_choose(struct ieee80211_node *ni,
* raise the RSS threshold for transmitting packets of similar length at
* the same data rate.
*/
void
ieee80211_rssadapt_lower_rate(struct ieee80211_rssadapt_node *ra,
int pktlen, int rssi)
static void
rssadapt_lower_rate(struct ieee80211_rssadapt_node *ra, int pktlen, int rssi)
{
uint16_t last_thr;
uint16_t (*thrs)[IEEE80211_RATE_SIZE];
@@ -214,9 +277,8 @@ ieee80211_rssadapt_lower_rate(struct ieee80211_rssadapt_node *ra,
last_thr, (*thrs)[rix], rssi);
}
void
ieee80211_rssadapt_raise_rate(struct ieee80211_rssadapt_node *ra,
int pktlen, int rssi)
static void
rssadapt_raise_rate(struct ieee80211_rssadapt_node *ra, int pktlen, int rssi)
{
uint16_t (*thrs)[IEEE80211_RATE_SIZE];
uint16_t newthr, oldthr;
@@ -243,31 +305,45 @@ ieee80211_rssadapt_raise_rate(struct ieee80211_rssadapt_node *ra,
}
}
static void
rssadapt_tx_complete(const struct ieee80211vap *vap,
const struct ieee80211_node *ni, int success, void *arg1, void *arg2)
{
struct ieee80211_rssadapt_node *ra = ni->ni_rctls;
int pktlen = *(int *)arg1, rssi = *(int *)arg2;
if (success) {
ra->ra_nok++;
if ((ra->ra_rix + 1) < ra->ra_rates.rs_nrates &&
(ticks - ra->ra_last_raise) >= ra->ra_raise_interval)
rssadapt_raise_rate(ra, pktlen, rssi);
} else {
ra->ra_nfail++;
rssadapt_lower_rate(ra, pktlen, rssi);
}
}
static int
rssadapt_sysctl_interval(SYSCTL_HANDLER_ARGS)
{
struct ieee80211_rssadapt *rs = arg1;
struct ieee80211vap *vap = arg1;
struct ieee80211_rssadapt *rs = vap->iv_rs;
int msecs = ticks_to_msecs(rs->interval);
int error;
error = sysctl_handle_int(oidp, &msecs, 0, req);
if (error || !req->newptr)
return error;
ieee80211_rssadapt_setinterval(rs, msecs);
rssadapt_setinterval(vap, msecs);
return 0;
}
static void
rssadapt_sysctlattach(struct ieee80211_rssadapt *rs,
rssadapt_sysctlattach(struct ieee80211vap *vap,
struct sysctl_ctx_list *ctx, struct sysctl_oid *tree)
{
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"rssadapt_rate_interval", CTLTYPE_INT | CTLFLAG_RW, rs,
"rssadapt_rate_interval", CTLTYPE_INT | CTLFLAG_RW, vap,
0, rssadapt_sysctl_interval, "I", "rssadapt operation interval (ms)");
}
/*
* Module glue.
*/
IEEE80211_RATE_MODULE(rssadapt, 1);
@@ -43,7 +43,7 @@
#define IEEE80211_RSSADAPT_BKTPOWER 3 /* 2**_BKTPOWER */
struct ieee80211_rssadapt {
struct ieee80211vap *vap;
const struct ieee80211vap *vap;
int interval; /* update interval (ticks) */
};
@@ -66,36 +66,6 @@ struct ieee80211_rssadapt_node {
[IEEE80211_RATE_SIZE];
};
void ieee80211_rssadapt_init(struct ieee80211_rssadapt *,
struct ieee80211vap *, int);
void ieee80211_rssadapt_cleanup(struct ieee80211_rssadapt *);
void ieee80211_rssadapt_setinterval(struct ieee80211_rssadapt *, int);
void ieee80211_rssadapt_node_init(struct ieee80211_rssadapt *,
struct ieee80211_rssadapt_node *, struct ieee80211_node *);
int ieee80211_rssadapt_choose(struct ieee80211_node *,
struct ieee80211_rssadapt_node *, u_int);
/* NB: these are public only for the inline below */
void ieee80211_rssadapt_raise_rate(struct ieee80211_rssadapt_node *,
int pktlen, int rssi);
void ieee80211_rssadapt_lower_rate(struct ieee80211_rssadapt_node *,
int pktlen, int rssi);
#define IEEE80211_RSSADAPT_SUCCESS 1
#define IEEE80211_RSSADAPT_FAILURE 0
static __inline void
ieee80211_rssadapt_tx_complete(struct ieee80211_rssadapt_node *ra,
int success, int pktlen, int rssi)
{
if (success) {
ra->ra_nok++;
if ((ra->ra_rix + 1) < ra->ra_rates.rs_nrates &&
(ticks - ra->ra_last_raise) >= ra->ra_raise_interval)
ieee80211_rssadapt_raise_rate(ra, pktlen, rssi);
} else {
ra->ra_nfail++;
ieee80211_rssadapt_lower_rate(ra, pktlen, rssi);
}
}
#endif /* _FBSD_COMPAT_NET80211_IEEE80211_RSSADAPT_H_ */
@@ -97,7 +97,7 @@ struct sta_entry {
CTASSERT(MAX_IEEE_CHAN >= 256);
struct sta_table {
struct mtx st_lock; /* on scan table */
ieee80211_scan_table_lock_t st_lock; /* on scan table */
TAILQ_HEAD(, sta_entry) st_entry; /* all entries */
LIST_HEAD(, sta_entry) st_hash[STA_HASHSIZE];
struct mtx st_scanlock; /* on st_scaniter */
@@ -161,7 +161,7 @@ sta_attach(struct ieee80211_scan_state *ss)
M_80211_SCAN, M_NOWAIT | M_ZERO);
if (st == NULL)
return 0;
mtx_init(&st->st_lock, "scantable", "802.11 scan table", MTX_DEF);
IEEE80211_SCAN_TABLE_LOCK_INIT(st, "scantable");
mtx_init(&st->st_scanlock, "scangen", "802.11 scangen", MTX_DEF);
TAILQ_INIT(&st->st_entry);
ss->ss_priv = st;
@@ -179,7 +179,7 @@ sta_detach(struct ieee80211_scan_state *ss)
if (st != NULL) {
sta_flush_table(st);
mtx_destroy(&st->st_lock);
IEEE80211_SCAN_TABLE_LOCK_DESTROY(st);
mtx_destroy(&st->st_scanlock);
free(st, M_80211_SCAN);
KASSERT(nrefs > 0, ("imbalanced attach/detach"));
@@ -196,9 +196,9 @@ sta_flush(struct ieee80211_scan_state *ss)
{
struct sta_table *st = ss->ss_priv;
mtx_lock(&st->st_lock);
IEEE80211_SCAN_TABLE_LOCK(st);
sta_flush_table(st);
mtx_unlock(&st->st_lock);
IEEE80211_SCAN_TABLE_UNLOCK(st);
ss->ss_last = 0;
return 0;
}
@@ -244,14 +244,14 @@ sta_add(struct ieee80211_scan_state *ss,
hash = STA_HASH(macaddr);
mtx_lock(&st->st_lock);
IEEE80211_SCAN_TABLE_LOCK(st);
LIST_FOREACH(se, &st->st_hash[hash], se_hash)
if (IEEE80211_ADDR_EQ(se->base.se_macaddr, macaddr))
goto found;
se = (struct sta_entry *) malloc(sizeof(struct sta_entry),
M_80211_SCAN, M_NOWAIT | M_ZERO);
if (se == NULL) {
mtx_unlock(&st->st_lock);
IEEE80211_SCAN_TABLE_UNLOCK(st);
return 0;
}
se->se_scangen = st->st_scaniter-1;
@@ -370,7 +370,7 @@ found:
if (rssi > st->st_maxrssi[sp->bchan])
st->st_maxrssi[sp->bchan] = rssi;
mtx_unlock(&st->st_lock);
IEEE80211_SCAN_TABLE_UNLOCK(st);
/*
* If looking for a quick choice and nothing's
@@ -1013,7 +1013,7 @@ match_bss(struct ieee80211vap *vap,
*/
if (se->se_capinfo & (IEEE80211_CAPINFO_IBSS|IEEE80211_CAPINFO_ESS))
fail |= MATCH_CAPINFO;
else if (se->se_meshid == NULL)
else if (se->se_meshid[0] != IEEE80211_ELEMID_MESHID)
fail |= MATCH_MESH_NOID;
else if (ms->ms_idlen != 0 &&
match_id(se->se_meshid, ms->ms_id, ms->ms_idlen))
@@ -1132,7 +1132,7 @@ sta_update_notseen(struct sta_table *st)
{
struct sta_entry *se;
mtx_lock(&st->st_lock);
IEEE80211_SCAN_TABLE_LOCK(st);
TAILQ_FOREACH(se, &st->st_entry, se_list) {
/*
* If seen the reset and don't bump the count;
@@ -1146,7 +1146,7 @@ sta_update_notseen(struct sta_table *st)
else
se->se_notseen++;
}
mtx_unlock(&st->st_lock);
IEEE80211_SCAN_TABLE_UNLOCK(st);
}
static void
@@ -1154,11 +1154,11 @@ sta_dec_fails(struct sta_table *st)
{
struct sta_entry *se;
mtx_lock(&st->st_lock);
IEEE80211_SCAN_TABLE_LOCK(st);
TAILQ_FOREACH(se, &st->st_entry, se_list)
if (se->se_fails)
se->se_fails--;
mtx_unlock(&st->st_lock);
IEEE80211_SCAN_TABLE_UNLOCK(st);
}
static struct sta_entry *
@@ -1169,7 +1169,7 @@ select_bss(struct ieee80211_scan_state *ss, struct ieee80211vap *vap, int debug)
IEEE80211_DPRINTF(vap, debug, " %s\n",
"macaddr bssid chan rssi rate flag wep essid");
mtx_lock(&st->st_lock);
IEEE80211_SCAN_TABLE_LOCK(st);
TAILQ_FOREACH(se, &st->st_entry, se_list) {
ieee80211_ies_expand(&se->base.se_ies);
if (match_bss(vap, ss, se, debug) == 0) {
@@ -1179,7 +1179,7 @@ select_bss(struct ieee80211_scan_state *ss, struct ieee80211vap *vap, int debug)
selbs = se;
}
}
mtx_unlock(&st->st_lock);
IEEE80211_SCAN_TABLE_UNLOCK(st);
return selbs;
}
@@ -1258,11 +1258,11 @@ sta_lookup(struct sta_table *st, const uint8_t macaddr[IEEE80211_ADDR_LEN])
struct sta_entry *se;
int hash = STA_HASH(macaddr);
mtx_lock(&st->st_lock);
IEEE80211_SCAN_TABLE_LOCK(st);
LIST_FOREACH(se, &st->st_hash[hash], se_hash)
if (IEEE80211_ADDR_EQ(se->base.se_macaddr, macaddr))
break;
mtx_unlock(&st->st_lock);
IEEE80211_SCAN_TABLE_UNLOCK(st);
return se; /* NB: unlocked */
}
@@ -1361,7 +1361,7 @@ sta_age(struct ieee80211_scan_state *ss)
KASSERT(vap->iv_opmode == IEEE80211_M_STA,
("wrong mode %u", vap->iv_opmode));
if (vap->iv_roaming == IEEE80211_ROAMING_AUTO &&
(vap->iv_ic->ic_flags & IEEE80211_F_BGSCAN) &&
(vap->iv_flags & IEEE80211_F_BGSCAN) &&
vap->iv_state >= IEEE80211_S_RUN)
/* XXX vap is implicit */
sta_roam_check(ss, vap);
@@ -1382,18 +1382,18 @@ sta_iterate(struct ieee80211_scan_state *ss,
mtx_lock(&st->st_scanlock);
gen = st->st_scaniter++;
restart:
mtx_lock(&st->st_lock);
IEEE80211_SCAN_TABLE_LOCK(st);
TAILQ_FOREACH(se, &st->st_entry, se_list) {
if (se->se_scangen != gen) {
se->se_scangen = gen;
/* update public state */
se->base.se_age = ticks - se->se_lastupdate;
mtx_unlock(&st->st_lock);
IEEE80211_SCAN_TABLE_UNLOCK(st);
(*f)(arg, &se->base);
goto restart;
}
}
mtx_unlock(&st->st_lock);
IEEE80211_SCAN_TABLE_UNLOCK(st);
mtx_unlock(&st->st_scanlock);
}
@@ -1509,7 +1509,7 @@ adhoc_pick_channel(struct ieee80211_scan_state *ss, int flags)
bestchan = NULL;
bestrssi = -1;
mtx_lock(&st->st_lock);
IEEE80211_SCAN_TABLE_LOCK(st);
for (i = 0; i < ss->ss_last; i++) {
c = ss->ss_chans[i];
/* never consider a channel with radar */
@@ -1531,7 +1531,7 @@ adhoc_pick_channel(struct ieee80211_scan_state *ss, int flags)
if (bestchan == NULL || maxrssi < bestrssi)
bestchan = c;
}
mtx_unlock(&st->st_lock);
IEEE80211_SCAN_TABLE_UNLOCK(st);
return bestchan;
}
@@ -1637,7 +1637,7 @@ adhoc_age(struct ieee80211_scan_state *ss)
struct sta_table *st = ss->ss_priv;
struct sta_entry *se, *next;
mtx_lock(&st->st_lock);
IEEE80211_SCAN_TABLE_LOCK(st);
TAILQ_FOREACH_SAFE(se, &st->st_entry, se_list, next) {
if (se->se_notseen > STA_PURGE_SCANS) {
TAILQ_REMOVE(&st->st_entry, se, se_list);
@@ -1646,7 +1646,7 @@ adhoc_age(struct ieee80211_scan_state *ss)
free(se, M_80211_SCAN);
}
}
mtx_unlock(&st->st_lock);
IEEE80211_SCAN_TABLE_UNLOCK(st);
}
static const struct ieee80211_scanner adhoc_default = {
@@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$");
#ifdef IEEE80211_SUPPORT_SUPERG
#include <net80211/ieee80211_superg.h>
#endif
#include <net80211/ieee80211_ratectl.h>
#define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2)
@@ -141,6 +142,8 @@ sta_beacon_miss(struct ieee80211vap *vap)
vap->iv_bss->ni_essid, vap->iv_bss->ni_esslen);
return;
}
callout_stop(&vap->iv_swbmiss);
vap->iv_bmiss_count = 0;
vap->iv_stats.is_beacon_miss++;
if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) {
@@ -517,7 +520,7 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
struct ieee80211_frame *wh;
struct ieee80211_key *key;
struct ether_header *eh;
int hdrspace, need_tap;
int hdrspace, need_tap = 1; /* mbuf need to be tapped. */
uint8_t dir, type, subtype, qos;
uint8_t *bssid;
uint16_t rxseq;
@@ -542,7 +545,6 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
KASSERT(ni != NULL, ("null node"));
ni->ni_inact = ni->ni_inact_reload;
need_tap = 1; /* mbuf need to be tapped. */
type = -1; /* undefined */
if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {
@@ -583,7 +585,7 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
}
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
ni->ni_noise = nf;
if (HAS_SEQ(type)) {
if (HAS_SEQ(type) && !IEEE80211_IS_MULTICAST(wh->i_addr1)) {
uint8_t tid = ieee80211_gettid(wh);
if (IEEE80211_QOS_HAS_SEQ(wh) &&
TID_TO_WME_AC(tid) >= WME_AC_VI)
@@ -759,7 +761,7 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
/* copy to listener after decrypt */
if (ieee80211_radiotap_active_vap(vap))
ieee80211_radiotap_tx(vap, m);
ieee80211_radiotap_rx(vap, m);
need_tap = 0;
/*
@@ -1595,6 +1597,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
ieee80211_setup_basic_htrates(ni, htinfo);
ieee80211_node_setuptxparms(ni);
ieee80211_ratectl_node_init(ni);
} else {
#ifdef IEEE80211_SUPPORT_SUPERG
if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_ATH))
@@ -295,6 +295,8 @@ tdma_beacon_miss(struct ieee80211vap *vap)
"beacon miss, mode %u state %s\n",
vap->iv_opmode, ieee80211_state_name[vap->iv_state]);
callout_stop(&vap->iv_swbmiss);
if (ts->tdma_peer != NULL) { /* XXX? can this be null? */
ieee80211_notify_node_leave(vap->iv_bss);
ts->tdma_peer = NULL;
@@ -33,11 +33,11 @@
* Definitions for IEEE 802.11 drivers.
*/
/* NB: portability glue must go first */
#ifdef __NetBSD__
#if defined(__NetBSD__)
#include <net80211/ieee80211_netbsd.h>
#elif __FreeBSD__
#elif defined(__FreeBSD__)
#include <net80211/ieee80211_freebsd.h>
#elif __linux__
#elif defined(__linux__)
#include <net80211/ieee80211_linux.h>
#elif __HAIKU__
#include <net80211/ieee80211_haiku.h>
@@ -436,6 +436,9 @@ struct ieee80211vap {
const struct ieee80211_aclator *iv_acl; /* acl glue */
void *iv_as; /* private aclator state */
const struct ieee80211_ratectl *iv_rate;
void *iv_rs; /* private ratectl state */
struct ieee80211_tdma_state *iv_tdma; /* tdma state */
struct ieee80211_mesh_state *iv_mesh; /* MBSS state */
struct ieee80211_hwmp_state *iv_hwmp; /* HWMP state */
@@ -471,7 +474,7 @@ struct ieee80211vap {
/* 802.3 output method for raw frame xmit */
int (*iv_output)(struct ifnet *, struct mbuf *,
struct sockaddr *, struct route *);
uint64_t iv_spare[8];
uint64_t iv_spare[6];
};
#define IEEE80211_ADDR_EQ(a1,a2) (memcmp(a1,a2,IEEE80211_ADDR_LEN) == 0)
@@ -547,11 +550,12 @@ struct ieee80211vap {
/* NB: immutable: should be set only when creating a vap */
#define IEEE80211_FEXT_WDSLEGACY 0x00010000 /* CONF: legacy WDS operation */
#define IEEE80211_FEXT_PROBECHAN 0x00020000 /* CONF: probe passive channel*/
#define IEEE80211_FEXT_UNIQMAC 0x00040000 /* CONF: user or computed mac */
#define IEEE80211_FEXT_BITS \
"\20\2INACT\3SCANWAIT\4BGSCAN\5WPS\6TSN\7SCANREQ\10RESUME" \
"\0114ADDR\12NONEPR_PR\13SWBMISS\14DFS\15DOTD\16STATEWAIT\17REINIT" \
"\20BPF\21WDSLEGACY\22PROBECHAN"
"\20BPF\21WDSLEGACY\22PROBECHAN\23UNIQMAC"
/* ic_flags_ht/iv_flags_ht */
#define IEEE80211_FHT_NONHT_PR 0x00000001 /* STATUS: non-HT sta present */
@@ -850,10 +854,10 @@ ieee80211_htchanflags(const struct ieee80211_channel *c)
if (ieee80211_msg(_vap, _m)) \
ieee80211_note_frame(_vap, _wh, _fmt, __VA_ARGS__); \
} while (0)
void ieee80211_note(struct ieee80211vap *, const char *, ...);
void ieee80211_note_mac(struct ieee80211vap *,
void ieee80211_note(const struct ieee80211vap *, const char *, ...);
void ieee80211_note_mac(const struct ieee80211vap *,
const uint8_t mac[IEEE80211_ADDR_LEN], const char *, ...);
void ieee80211_note_frame(struct ieee80211vap *,
void ieee80211_note_frame(const struct ieee80211vap *,
const struct ieee80211_frame *, const char *, ...);
#define ieee80211_msg_debug(_vap) \
((_vap)->iv_debug & IEEE80211_MSG_DEBUG)
@@ -891,11 +895,11 @@ void ieee80211_note_frame(struct ieee80211vap *,
ieee80211_discard_mac(_vap, _mac, _type, _fmt, __VA_ARGS__);\
} while (0)
void ieee80211_discard_frame(struct ieee80211vap *,
void ieee80211_discard_frame(const struct ieee80211vap *,
const struct ieee80211_frame *, const char *type, const char *fmt, ...);
void ieee80211_discard_ie(struct ieee80211vap *,
void ieee80211_discard_ie(const struct ieee80211vap *,
const struct ieee80211_frame *, const char *type, const char *fmt, ...);
void ieee80211_discard_mac(struct ieee80211vap *,
void ieee80211_discard_mac(const struct ieee80211vap *,
const uint8_t mac[IEEE80211_ADDR_LEN], const char *type,
const char *fmt, ...);
#else
@@ -414,7 +414,7 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
struct ieee80211_frame *wh;
struct ieee80211_key *key;
struct ether_header *eh;
int hdrspace, need_tap;
int hdrspace, need_tap = 1; /* mbuf need to be tapped. */
uint8_t dir, type, subtype, qos;
uint16_t rxseq;
@@ -437,7 +437,6 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
KASSERT(ni != NULL, ("null node"));
need_tap = 1; /* mbuf need to be tapped. */
type = -1; /* undefined */
if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {