Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/wtap/if_wtap.c
Show All 35 Lines | |||||
#include "if_wtapvar.h" | #include "if_wtapvar.h" | ||||
#include <sys/uio.h> /* uio struct */ | #include <sys/uio.h> /* uio struct */ | ||||
#include <sys/jail.h> | #include <sys/jail.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <net80211/ieee80211_ratectl.h> | #include <net80211/ieee80211_ratectl.h> | ||||
#include "if_medium.h" | #include "if_medium.h" | ||||
#include "wtap_hal/hal.h" | |||||
/* | /* | ||||
* This _requires_ vimage to be useful. | * This _requires_ vimage to be useful. | ||||
*/ | */ | ||||
#ifndef VIMAGE | #ifndef VIMAGE | ||||
#error if_wtap requires VIMAGE. | #error if_wtap requires VIMAGE. | ||||
#endif /* VIMAGE */ | #endif /* VIMAGE */ | ||||
▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | |||||
* Intercept management frames to collect beacon rssi data | * Intercept management frames to collect beacon rssi data | ||||
* and to do ibss merges. | * and to do ibss merges. | ||||
*/ | */ | ||||
static void | static void | ||||
wtap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, | wtap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, | ||||
int subtype, const struct ieee80211_rx_stats *stats, int rssi, int nf) | int subtype, const struct ieee80211_rx_stats *stats, int rssi, int nf) | ||||
{ | { | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct wtap_softc *sc = vap->iv_ic->ic_softc; | |||||
#if 0 | #if 0 | ||||
DWTAP_PRINTF("[%d] %s\n", myath_id(ni), __func__); | DWTAP_PRINTF("[%d] %s\n", myath_id(ni), __func__); | ||||
#endif | #endif | ||||
/* | |||||
* Call up first so subsequent work can use information | |||||
* potentially stored in the node (e.g. for ibss merge). | |||||
*/ | |||||
WTAP_VAP(vap)->av_recv_mgmt(ni, m, subtype, stats, rssi, nf); | WTAP_VAP(vap)->av_recv_mgmt(ni, m, subtype, stats, rssi, nf); | ||||
switch (subtype) { | |||||
case IEEE80211_FC0_SUBTYPE_BEACON: | |||||
case IEEE80211_FC0_SUBTYPE_PROBE_RESP: | |||||
if (vap->iv_opmode == IEEE80211_M_IBSS && | |||||
vap->iv_state == IEEE80211_S_RUN && | |||||
ieee80211_ibss_merge_check(ni)) { | |||||
uint64_t tsf = wtap_hal_get_tsf(sc->hal); | |||||
/* | |||||
* Handle ibss merge as needed; check the tsf on the | |||||
* frame before attempting the merge. The 802.11 spec | |||||
* says the station should change it's bssid to match | |||||
* the oldest station with the same ssid, where oldest | |||||
* is determined by the tsf. Note that hardware | |||||
* reconfiguration happens through callback to | |||||
* ath_newstate as the state machine will go from | |||||
* RUN -> RUN when this happens. | |||||
*/ | |||||
if (le64toh(ni->ni_tstamp.tsf) >= tsf) | |||||
(void) ieee80211_ibss_merge(ni); | |||||
} | } | ||||
break; | |||||
} | |||||
} | |||||
static int | static int | ||||
wtap_reset_vap(struct ieee80211vap *vap, u_long cmd) | wtap_reset_vap(struct ieee80211vap *vap, u_long cmd) | ||||
{ | { | ||||
DWTAP_PRINTF("%s\n", __func__); | DWTAP_PRINTF("%s\n", __func__); | ||||
return 0; | return 0; | ||||
} | } | ||||
Show All 23 Lines | wtap_beacon_alloc(struct wtap_softc *sc, struct ieee80211_node *ni) | ||||
* we assume the mbuf routines will return us something | * we assume the mbuf routines will return us something | ||||
* with this alignment (perhaps should assert). | * with this alignment (perhaps should assert). | ||||
*/ | */ | ||||
avp->beacon = ieee80211_beacon_alloc(ni); | avp->beacon = ieee80211_beacon_alloc(ni); | ||||
if (avp->beacon == NULL) { | if (avp->beacon == NULL) { | ||||
printf("%s: cannot get mbuf\n", __func__); | printf("%s: cannot get mbuf\n", __func__); | ||||
return ENOMEM; | return ENOMEM; | ||||
} | } | ||||
callout_init(&avp->av_swba, 0); | |||||
avp->bf_node = ieee80211_ref_node(ni); | avp->bf_node = ieee80211_ref_node(ni); | ||||
return 0; | return 0; | ||||
} | } | ||||
static void | static void | ||||
wtap_beacon_config(struct wtap_softc *sc, struct ieee80211vap *vap) | wtap_beacon_config(struct wtap_softc *sc, struct ieee80211vap *vap) | ||||
{ | { | ||||
DWTAP_PRINTF("%s\n", __func__); | DWTAP_PRINTF("%s\n", __func__); | ||||
} | } | ||||
static void | static void | ||||
wtap_beacon_intrp(void *arg) | wtap_beacon_intrp(void *arg) | ||||
{ | { | ||||
struct wtap_vap *avp = arg; | struct wtap_vap *avp = arg; | ||||
struct ieee80211vap *vap = arg; | struct ieee80211vap *vap = arg; | ||||
struct wtap_softc *sc = vap->iv_ic->ic_softc; | |||||
struct ieee80211_frame *wh; | |||||
struct mbuf *m; | struct mbuf *m; | ||||
uint64_t tsf; | |||||
if (vap->iv_state < IEEE80211_S_RUN) { | if (vap->iv_state < IEEE80211_S_RUN) { | ||||
DWTAP_PRINTF("Skip beacon, not running, state %d", vap->iv_state); | DWTAP_PRINTF("Skip beacon, not running, state %d", vap->iv_state); | ||||
return ; | return ; | ||||
} | } | ||||
DWTAP_PRINTF("[%d] beacon intrp\n", avp->id); //burst mode | DWTAP_PRINTF("[%d] beacon intrp\n", avp->id); //burst mode | ||||
/* | /* | ||||
* Update dynamic beacon contents. If this returns | * Update dynamic beacon contents. If this returns | ||||
* non-zero then we need to remap the memory because | * non-zero then we need to remap the memory because | ||||
* the beacon frame changed size (probably because | * the beacon frame changed size (probably because | ||||
* of the TIM bitmap). | * of the TIM bitmap). | ||||
*/ | */ | ||||
m = m_dup(avp->beacon, M_NOWAIT); | m = m_dup(avp->beacon, M_NOWAIT); | ||||
if (ieee80211_beacon_update(avp->bf_node, m, 0)) { | if (ieee80211_beacon_update(avp->bf_node, m, 0)) { | ||||
printf("%s, need to remap the memory because the beacon frame" | printf("%s, need to remap the memory because the beacon frame" | ||||
" changed size.\n",__func__); | " changed size.\n",__func__); | ||||
} | } | ||||
/* Get TSF from HAL, and insert it into beacon frame */ | |||||
tsf = wtap_hal_get_tsf(sc->hal); | |||||
wh = mtod(m, struct ieee80211_frame *); | |||||
memcpy(&wh[1], &tsf, sizeof(tsf)); | |||||
if (ieee80211_radiotap_active_vap(vap)) | if (ieee80211_radiotap_active_vap(vap)) | ||||
ieee80211_radiotap_tx(vap, m); | ieee80211_radiotap_tx(vap, m); | ||||
#if 0 | #if 0 | ||||
medium_transmit(avp->av_md, avp->id, m); | medium_transmit(avp->av_md, avp->id, m); | ||||
#endif | #endif | ||||
wtap_medium_enqueue(avp, m); | wtap_medium_enqueue(avp, m); | ||||
callout_schedule(&avp->av_swba, avp->av_bcinterval); | callout_schedule(&avp->av_swba, avp->av_bcinterval); | ||||
Show All 18 Lines | wtap_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | ||||
if (error != 0) | if (error != 0) | ||||
goto bad; | goto bad; | ||||
if (nstate == IEEE80211_S_RUN) { | if (nstate == IEEE80211_S_RUN) { | ||||
/* NB: collect bss node again, it may have changed */ | /* NB: collect bss node again, it may have changed */ | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
ni = ieee80211_ref_node(vap->iv_bss); | ni = ieee80211_ref_node(vap->iv_bss); | ||||
switch (vap->iv_opmode) { | switch (vap->iv_opmode) { | ||||
case IEEE80211_M_IBSS: | |||||
case IEEE80211_M_MBSS: | case IEEE80211_M_MBSS: | ||||
/* | |||||
* Stop any previous beacon callout. This may be | |||||
* necessary, for example, when an ibss merge | |||||
* causes reconfiguration; there will be a state | |||||
* transition from RUN->RUN that means we may | |||||
* be called with beacon transmission active. | |||||
*/ | |||||
callout_stop(&avp->av_swba); | |||||
error = wtap_beacon_alloc(sc, ni); | error = wtap_beacon_alloc(sc, ni); | ||||
if (error != 0) | if (error != 0) | ||||
goto bad; | goto bad; | ||||
/* | |||||
* If joining an adhoc network defer beacon timer | |||||
* configuration to the next beacon frame so we | |||||
* have a current TSF to use. Otherwise we're | |||||
* starting an ibss/bss so there's no need to delay; | |||||
* if this is the first vap moving to RUN state, then | |||||
* beacon state needs to be [re]configured. | |||||
*/ | |||||
if (vap->iv_opmode == IEEE80211_M_IBSS && | |||||
ni->ni_tstamp.tsf != 0) | |||||
break; | |||||
wtap_beacon_config(sc, vap); | wtap_beacon_config(sc, vap); | ||||
/* Start TSF timer from now, and start s/w beacon alert */ | |||||
wtap_hal_reset_tsf(sc->hal); | |||||
callout_reset(&avp->av_swba, avp->av_bcinterval, | callout_reset(&avp->av_swba, avp->av_bcinterval, | ||||
wtap_beacon_intrp, vap); | wtap_beacon_intrp, vap); | ||||
break; | break; | ||||
default: | default: | ||||
goto bad; | goto bad; | ||||
} | } | ||||
} else if (nstate == IEEE80211_S_INIT) { | } else if (nstate == IEEE80211_S_INIT) { | ||||
callout_stop(&avp->av_swba); | callout_stop(&avp->av_swba); | ||||
Show All 29 Lines | wtap_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], | ||||
DWTAP_PRINTF("%s\n", __func__); | DWTAP_PRINTF("%s\n", __func__); | ||||
avp = malloc(sizeof(struct wtap_vap), M_80211_VAP, M_WAITOK | M_ZERO); | avp = malloc(sizeof(struct wtap_vap), M_80211_VAP, M_WAITOK | M_ZERO); | ||||
avp->id = sc->id; | avp->id = sc->id; | ||||
avp->av_md = sc->sc_md; | avp->av_md = sc->sc_md; | ||||
avp->av_bcinterval = msecs_to_ticks(BEACON_INTRERVAL + 100*sc->id); | avp->av_bcinterval = msecs_to_ticks(BEACON_INTRERVAL + 100*sc->id); | ||||
vap = (struct ieee80211vap *) avp; | vap = (struct ieee80211vap *) avp; | ||||
error = ieee80211_vap_setup(ic, vap, name, unit, IEEE80211_M_MBSS, | error = ieee80211_vap_setup(ic, vap, name, unit, opmode, | ||||
flags | IEEE80211_CLONE_NOBEACONS, bssid); | flags | IEEE80211_CLONE_NOBEACONS, bssid); | ||||
if (error) { | if (error) { | ||||
free(avp, M_80211_VAP); | free(avp, M_80211_VAP); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* override various methods */ | /* override various methods */ | ||||
avp->av_recv_mgmt = vap->iv_recv_mgmt; | avp->av_recv_mgmt = vap->iv_recv_mgmt; | ||||
vap->iv_recv_mgmt = wtap_recv_mgmt; | vap->iv_recv_mgmt = wtap_recv_mgmt; | ||||
vap->iv_reset = wtap_reset_vap; | vap->iv_reset = wtap_reset_vap; | ||||
vap->iv_update_beacon = wtap_beacon_update; | vap->iv_update_beacon = wtap_beacon_update; | ||||
avp->av_newstate = vap->iv_newstate; | avp->av_newstate = vap->iv_newstate; | ||||
vap->iv_newstate = wtap_newstate; | vap->iv_newstate = wtap_newstate; | ||||
avp->av_bmiss = vap->iv_bmiss; | avp->av_bmiss = vap->iv_bmiss; | ||||
vap->iv_bmiss = wtap_bmiss; | vap->iv_bmiss = wtap_bmiss; | ||||
/* complete setup */ | /* complete setup */ | ||||
ieee80211_vap_attach(vap, ieee80211_media_change, | ieee80211_vap_attach(vap, ieee80211_media_change, | ||||
ieee80211_media_status, mac); | ieee80211_media_status, mac); | ||||
avp->av_dev = make_dev(&wtap_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, | avp->av_dev = make_dev(&wtap_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, | ||||
"%s", (const char *)vap->iv_ifp->if_xname); | "%s", (const char *)vap->iv_ifp->if_xname); | ||||
avp->av_dev->si_drv1 = sc; | avp->av_dev->si_drv1 = sc; | ||||
callout_init(&avp->av_swba, 0); | |||||
/* TODO this is a hack to force it to choose the rate we want */ | /* TODO this is a hack to force it to choose the rate we want */ | ||||
ni = ieee80211_ref_node(vap->iv_bss); | ni = ieee80211_ref_node(vap->iv_bss); | ||||
ni->ni_txrate = 130; | ni->ni_txrate = 130; | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
return vap; | return vap; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | for(;;) { | ||||
KASSERT(bf != NULL, ("wtap_buf is NULL\n")); | KASSERT(bf != NULL, ("wtap_buf is NULL\n")); | ||||
m = bf->m; | m = bf->m; | ||||
DWTAP_PRINTF("[%d] receiving m=%p\n", sc->id, bf->m); | DWTAP_PRINTF("[%d] receiving m=%p\n", sc->id, bf->m); | ||||
if (m == NULL) { /* NB: shouldn't happen */ | if (m == NULL) { /* NB: shouldn't happen */ | ||||
ic_printf(ic, "%s: no mbuf!\n", __func__); | ic_printf(ic, "%s: no mbuf!\n", __func__); | ||||
free(bf, M_WTAP_RXBUF); | free(bf, M_WTAP_RXBUF); | ||||
return; | return; | ||||
} | } | ||||
/* | |||||
* It's weird to do this, but sometimes wtap will | |||||
* receive AMPDU packets (like ping(8)) even when | |||||
* the ic does not supports 11n HT. | |||||
*/ | |||||
m->m_flags &= ~M_AMPDU; | |||||
#if 0 | #if 0 | ||||
ieee80211_dump_pkt(ic, mtod(m, caddr_t), 0,0,0); | ieee80211_dump_pkt(ic, mtod(m, caddr_t), 0,0,0); | ||||
#endif | #endif | ||||
/* | /* | ||||
* Locate the node for sender, track state, and then | * Locate the node for sender, track state, and then | ||||
* pass the (referenced) node up to the 802.11 layer | * pass the (referenced) node up to the 802.11 layer | ||||
* for its use. | * for its use. | ||||
▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | sc->sc_tq = taskqueue_create("wtap_taskq", M_NOWAIT | M_ZERO, | ||||
taskqueue_thread_enqueue, &sc->sc_tq); | taskqueue_thread_enqueue, &sc->sc_tq); | ||||
taskqueue_start_threads(&sc->sc_tq, 1, PI_SOFT, "%s taskQ", sc->name); | taskqueue_start_threads(&sc->sc_tq, 1, PI_SOFT, "%s taskQ", sc->name); | ||||
NET_TASK_INIT(&sc->sc_rxtask, 0, wtap_rx_proc, sc); | NET_TASK_INIT(&sc->sc_rxtask, 0, wtap_rx_proc, sc); | ||||
ic->ic_softc = sc; | ic->ic_softc = sc; | ||||
ic->ic_name = sc->name; | ic->ic_name = sc->name; | ||||
ic->ic_phytype = IEEE80211_T_DS; | ic->ic_phytype = IEEE80211_T_DS; | ||||
ic->ic_opmode = IEEE80211_M_MBSS; | ic->ic_opmode = IEEE80211_M_MBSS; | ||||
ic->ic_caps = IEEE80211_C_MBSS; | ic->ic_caps = IEEE80211_C_MBSS | IEEE80211_C_IBSS; | ||||
ic->ic_max_keyix = 128; /* A value read from Atheros ATH_KEYMAX */ | ic->ic_max_keyix = 128; /* A value read from Atheros ATH_KEYMAX */ | ||||
ic->ic_regdomain.regdomain = SKU_ETSI; | ic->ic_regdomain.regdomain = SKU_ETSI; | ||||
ic->ic_regdomain.country = CTRY_SWEDEN; | ic->ic_regdomain.country = CTRY_SWEDEN; | ||||
ic->ic_regdomain.location = 1; /* Indoors */ | ic->ic_regdomain.location = 1; /* Indoors */ | ||||
ic->ic_regdomain.isocc[0] = 'S'; | ic->ic_regdomain.isocc[0] = 'S'; | ||||
ic->ic_regdomain.isocc[1] = 'E'; | ic->ic_regdomain.isocc[1] = 'E'; | ||||
▲ Show 20 Lines • Show All 97 Lines • Show Last 20 Lines |