From: Felix Fietkau Date: Sat, 15 Aug 2009 21:36:37 +0000 (+0000) Subject: merge madwifi and wprobe into 8.09 X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fsvn-archive%2Farchive.git;a=commitdiff_plain;hb=2c70e28117fc6d70431be00270d82e0ae5ad2718 merge madwifi and wprobe into 8.09 SVN-Revision: 17279 --- diff --git a/package/madwifi/files/lib/wifi/madwifi.sh b/package/madwifi/files/lib/wifi/madwifi.sh index 13c519225d..6d10e24f85 100755 --- a/package/madwifi/files/lib/wifi/madwifi.sh +++ b/package/madwifi/files/lib/wifi/madwifi.sh @@ -4,7 +4,7 @@ append DRIVERS "atheros" scan_atheros() { local device="$1" local wds - local adhoc sta ap + local adhoc ahdemo sta ap monitor config_get vifs "$device" vifs for vif in $vifs; do @@ -84,21 +84,61 @@ enable_atheros() { [ auto = "$channel" ] && channel=0 - local first=1 + config_get_bool antdiv "$device" diversity + config_get antrx "$device" rxantenna + config_get anttx "$device" txantenna + config_get_bool softled "$device" softled 1 + + devname="$(cat /proc/sys/dev/$device/dev_name)" + antgpio= + case "$devname" in + NanoStation2) antgpio=7;; + NanoStation5) antgpio=1;; + esac + if [ -n "$antgpio" ]; then + softled=0 + config_get antenna "$device" antenna + case "$antenna" in + external) antdiv=0; antrx=1; anttx=1 ;; + horizontal) antdiv=0; antrx=1; anttx=1 ;; + vertical) antdiv=0; antrx=2; anttx=2 ;; + auto) antdiv=1; antrx=0; anttx=0 ;; + esac + + [ -x "$(which gpioctl 2>/dev/null)" ] || antenna= + case "$antenna" in + horizontal|vertical|auto) + gpioctl "dirout" "$antgpio" >/dev/null 2>&1 + gpioctl "set" "$antgpio" >/dev/null 2>&1 + ;; + external) + gpioctl "dirout" "$antgpio" >/dev/null 2>&1 + gpioctl "clear" "$antgpio" >/dev/null 2>&1 + ;; + esac + fi + + [ -n "$antdiv" ] && sysctl -w dev."$device".diversity="$antdiv" >&- + [ -n "$antrx" ] && sysctl -w dev."$device".rxantenna="$antrx" >&- + [ -n "$anttx" ] && sysctl -w dev."$device".txantenna="$anttx" >&- + [ -n "$softled" ] && sysctl -w dev."$device".softled="$softled" >&- + + config_get distance "$device" distance + [ -n "$distance" ] && sysctl -w dev."$device".distance="$distance" >&- + for vif in $vifs; do - local start_hostapd vif_txpower - nosbeacon= + local start_hostapd= vif_txpower= nosbeacon= config_get ifname "$vif" ifname config_get enc "$vif" encryption config_get eap_type "$vif" eap_type config_get mode "$vif" mode case "$mode" in - sta) config_get nosbeacon "$device" nosbeacon;; - adhoc) config_get nosbeacon "$vif" sw_merge;; + sta) config_get_bool nosbeacon "$device" nosbeacon;; + adhoc) config_get_bool nosbeacon "$vif" sw_merge 1;; esac - config_get ifname "$vif" ifname + [ "$nosbeacon" = 1 ] || nosbeacon="" ifname=$(wlanconfig "$ifname" create wlandev "$device" wlanmode "$mode" ${nosbeacon:+nosbeacon}) [ $? -ne 0 ] && { echo "enable_atheros($device): Failed to set up $mode vif $ifname" >&2 @@ -106,7 +146,6 @@ enable_atheros() { } config_set "$vif" ifname "$ifname" - # only need to change freq band and channel on the first vif config_get hwmode "$device" hwmode [ -z "$hwmode" ] && config_get hwmode "$device" mode @@ -122,13 +161,11 @@ enable_atheros() { *fh) hwmode=fh;; *) hwmode=auto;; esac + iwpriv "$ifname" mode "$hwmode" iwpriv "$ifname" pureg "$pureg" - [ "$first" = 1 ] && { - iwpriv "$ifname" mode "$hwmode" - iwconfig "$ifname" channel "$channel" >/dev/null 2>/dev/null - } - + iwconfig "$ifname" channel "$channel" >/dev/null 2>/dev/null + config_get_bool hidden "$vif" hidden 0 iwpriv "$ifname" hide_ssid "$hidden" @@ -142,7 +179,7 @@ enable_atheros() { 1|on|enabled) wds=1;; *) wds=0;; esac - iwpriv "$ifname" wds "$wds" + iwpriv "$ifname" wds "$wds" >/dev/null 2>&1 [ "$mode" = ap -a "$wds" = 1 ] && { config_get_bool wdssep "$vif" wdssep 1 @@ -176,53 +213,10 @@ enable_atheros() { } ;; esac - config_get ssid "$vif" ssid config_get_bool bgscan "$vif" bgscan [ -n "$bgscan" ] && iwpriv "$ifname" bgscan "$bgscan" - config_get_bool antdiv "$device" diversity - config_get antrx "$device" rxantenna - config_get anttx "$device" txantenna - config_get_bool softled "$device" softled 1 - - devname="$(cat /proc/sys/dev/$device/dev_name)" - antgpio= - case "$devname" in - NanoStation2) antgpio=7;; - NanoStation5) antgpio=1;; - esac - if [ -n "$antgpio" ]; then - softled=0 - config_get antenna "$device" antenna - case "$antenna" in - external) antdiv=0; antrx=1; anttx=1 ;; - horizontal) antdiv=0; antrx=1; anttx=1 ;; - vertical) antdiv=0; antrx=2; anttx=2 ;; - auto) antdiv=1; antrx=0; anttx=0 ;; - esac - - [ -x "$(which gpioctl 2>/dev/null)" ] || antenna= - case "$antenna" in - horizontal|vertical|auto) - gpioctl "dirout" "$antgpio" >/dev/null 2>&1 - gpioctl "set" "$antgpio" >/dev/null 2>&1 - ;; - external) - gpioctl "dirout" "$antgpio" >/dev/null 2>&1 - gpioctl "clear" "$antgpio" >/dev/null 2>&1 - ;; - esac - fi - - [ -n "$antdiv" ] && sysctl -w dev."$device".diversity="$antdiv" >&- - [ -n "$antrx" ] && sysctl -w dev."$device".rxantenna="$antrx" >&- - [ -n "$anttx" ] && sysctl -w dev."$device".txantenna="$anttx" >&- - [ -n "$softled" ] && sysctl -w dev."$device".softled="$softled" >&- - - config_get distance "$device" distance - [ -n "$distance" ] && sysctl -w dev."$device".distance="$distance" >&- - config_get rate "$vif" rate [ -n "$rate" ] && iwconfig "$ifname" rate "${rate%%.*}" @@ -236,7 +230,7 @@ enable_atheros() { [ -n "$rts" ] && iwconfig "$ifname" rts "${rts%%.*}" config_get_bool comp "$vif" compression 0 - iwpriv "$ifname" compression "$comp" + iwpriv "$ifname" compression "$comp" >/dev/null 2>&1 config_get_bool minrate "$vif" minrate [ -n "$minrate" ] && iwpriv "$ifname" minrate "$minrate" @@ -297,10 +291,13 @@ enable_atheros() { config_set "$vif" bridge "$bridge" start_net "$ifname" "$net_cfg" } + + config_get ssid "$vif" ssid [ -n "$ssid" ] && { iwconfig "$ifname" essid on iwconfig "$ifname" essid "$ssid" } + set_wifi_up "$vif" "$ifname" # TXPower settings only work if device is up already @@ -339,7 +336,6 @@ enable_atheros() { fi ;; esac - first=0 done } @@ -358,7 +354,7 @@ detect_atheros() { " ;; esac - [ "$type" = atheros ] && return + [ "$type" = atheros ] && continue cat < --- a/Makefile.inc +++ b/Makefile.inc -@@ -148,7 +148,8 @@ ATH_RATE= $(TOP)/ath_rate +@@ -147,8 +147,9 @@ ATH_RATE= $(TOP)/ath_rate + # TOOLS= $(TOP)/tools - WARNINGS = -Werror +-WARNINGS = -Werror -COPTS+= $(WARNINGS) -+DEBUG = -DAR_DEBUG -DIEEE80211_DEBUG ++WARNINGS = -Wno-unused ++# DEBUG = -DAR_DEBUG -DIEEE80211_DEBUG +COPTS+= $(WARNINGS) $(DEBUG) INCS= -include $(TOP)/include/compat.h -I$(TOP)/include diff --git a/package/madwifi/patches/370-wdsvap.patch b/package/madwifi/patches/370-wdsvap.patch index d68973737e..488e7b2444 100644 --- a/package/madwifi/patches/370-wdsvap.patch +++ b/package/madwifi/patches/370-wdsvap.patch @@ -883,6 +883,15 @@ ieee80211_node_table_reset(&ic->ic_sta, vap); if (vap->iv_bss != NULL) { ieee80211_unref_node(&vap->iv_bss); +@@ -309,7 +314,7 @@ ieee80211_create_ibss(struct ieee80211va + /* Check to see if we already have a node for this mac + * NB: we gain a node reference here + */ +- ni = ieee80211_find_node(&ic->ic_sta, vap->iv_myaddr); ++ ni = ieee80211_find_txnode(vap, vap->iv_myaddr); + if (ni == NULL) { + ni = ieee80211_alloc_node_table(vap, vap->iv_myaddr); + IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, @@ -831,12 +836,18 @@ node_table_leave_locked(struct ieee80211 LIST_REMOVE(ni, ni_hash); } @@ -1356,7 +1365,20 @@ }; --- a/net80211/ieee80211_proto.c +++ b/net80211/ieee80211_proto.c -@@ -1081,6 +1081,8 @@ ieee80211_init(struct net_device *dev, i +@@ -979,6 +979,12 @@ ieee80211_init(struct net_device *dev, i + "start running (state=%d)\n", vap->iv_state); + + ++ if (vap->iv_master && vap->iv_master->iv_state == IEEE80211_S_INIT) { ++ int ret = ieee80211_init(vap->iv_master->iv_dev, forcescan); ++ if (ret < 0) ++ return ret; ++ } ++ + if ((dev->flags & IFF_RUNNING) == 0) { + if (ic->ic_nopened++ == 0 && + (parent->flags & IFF_RUNNING) == 0) +@@ -1081,6 +1087,8 @@ ieee80211_init(struct net_device *dev, i int ieee80211_open(struct net_device *dev) { @@ -1365,7 +1387,7 @@ return ieee80211_init(dev, 0); } -@@ -1090,7 +1092,7 @@ ieee80211_open(struct net_device *dev) +@@ -1090,7 +1098,7 @@ ieee80211_open(struct net_device *dev) void ieee80211_start_running(struct ieee80211com *ic) { @@ -1374,7 +1396,7 @@ struct net_device *dev; /* XXX locking */ -@@ -1099,6 +1101,16 @@ ieee80211_start_running(struct ieee80211 +@@ -1099,6 +1107,16 @@ ieee80211_start_running(struct ieee80211 /* NB: avoid recursion */ if ((dev->flags & IFF_UP) && !(dev->flags & IFF_RUNNING)) ieee80211_open(dev); @@ -1391,7 +1413,7 @@ } } EXPORT_SYMBOL(ieee80211_start_running); -@@ -1116,11 +1128,43 @@ ieee80211_stop(struct net_device *dev) +@@ -1116,11 +1134,43 @@ ieee80211_stop(struct net_device *dev) struct ieee80211vap *vap = dev->priv; struct ieee80211com *ic = vap->iv_ic; struct net_device *parent = ic->ic_dev; @@ -1435,7 +1457,7 @@ ieee80211_new_state(vap, IEEE80211_S_INIT, -1); if (dev->flags & IFF_RUNNING) { dev->flags &= ~IFF_RUNNING; /* mark us stopped */ -@@ -1148,7 +1192,7 @@ EXPORT_SYMBOL(ieee80211_stop); +@@ -1148,7 +1198,7 @@ EXPORT_SYMBOL(ieee80211_stop); void ieee80211_stop_running(struct ieee80211com *ic) { @@ -1444,7 +1466,7 @@ struct net_device *dev; /* XXX locking */ -@@ -1156,6 +1200,12 @@ ieee80211_stop_running(struct ieee80211c +@@ -1156,6 +1206,12 @@ ieee80211_stop_running(struct ieee80211c dev = vap->iv_dev; if (dev->flags & IFF_RUNNING) /* NB: avoid recursion */ ieee80211_stop(dev); @@ -1457,7 +1479,7 @@ } } EXPORT_SYMBOL(ieee80211_stop_running); -@@ -1342,9 +1392,9 @@ ieee80211_new_state(struct ieee80211vap +@@ -1342,9 +1398,9 @@ ieee80211_new_state(struct ieee80211vap struct ieee80211com *ic = vap->iv_ic; int rc; @@ -1469,7 +1491,7 @@ return rc; } -@@ -1557,57 +1607,12 @@ __ieee80211_newstate(struct ieee80211vap +@@ -1557,57 +1613,12 @@ __ieee80211_newstate(struct ieee80211vap switch (ostate) { case IEEE80211_S_INIT: if (vap->iv_opmode == IEEE80211_M_MONITOR || @@ -1527,7 +1549,7 @@ break; } /* fall thru... */ -@@ -1675,6 +1680,7 @@ __ieee80211_newstate(struct ieee80211vap +@@ -1675,6 +1686,7 @@ __ieee80211_newstate(struct ieee80211vap */ if (ni->ni_authmode != IEEE80211_AUTH_8021X) ieee80211_node_authorize(ni); @@ -1535,7 +1557,7 @@ #ifdef ATH_SUPERG_XR /* * fire a timer to bring up XR vap if configured. -@@ -1808,6 +1814,11 @@ ieee80211_newstate(struct ieee80211vap * +@@ -1808,6 +1820,11 @@ ieee80211_newstate(struct ieee80211vap * ieee80211_state_name[dstate]); ieee80211_update_link_status(vap, nstate, ostate); @@ -1547,7 +1569,7 @@ switch (nstate) { case IEEE80211_S_AUTH: case IEEE80211_S_ASSOC: -@@ -1930,8 +1941,15 @@ ieee80211_newstate(struct ieee80211vap * +@@ -1930,8 +1947,15 @@ ieee80211_newstate(struct ieee80211vap * if (ostate == IEEE80211_S_SCAN || ostate == IEEE80211_S_AUTH || ostate == IEEE80211_S_ASSOC) { diff --git a/package/madwifi/patches/384-hwdetect.patch b/package/madwifi/patches/384-hwdetect.patch index 397b69c2e1..b327e786c3 100644 --- a/package/madwifi/patches/384-hwdetect.patch +++ b/package/madwifi/patches/384-hwdetect.patch @@ -33,7 +33,7 @@ /* Allocate space for dynamically determined maximum VAP count */ sc->sc_bslot = kmalloc(ath_maxvaps * sizeof(struct ieee80211vap*), GFP_KERNEL); -@@ -1508,6 +1520,28 @@ ath_vap_create(struct ieee80211com *ic, +@@ -1508,6 +1520,29 @@ ath_vap_create(struct ieee80211com *ic, return vap; } @@ -55,6 +55,7 @@ + continue; + + sc->sc_hwinfo = c; ++ sc->sc_poweroffset = c->poweroffset; + break; + } +} @@ -62,7 +63,23 @@ static void ath_vap_delete(struct ieee80211vap *vap) { -@@ -10821,6 +10855,12 @@ ath_ioctl(struct net_device *dev, struct +@@ -10225,6 +10260,7 @@ static u_int32_t + ath_set_clamped_maxtxpower(struct ath_softc *sc, + u_int32_t new_clamped_maxtxpower) + { ++ new_clamped_maxtxpower -= sc->sc_poweroffset; + (void)ath_hal_settxpowlimit(sc->sc_ah, new_clamped_maxtxpower); + return ath_get_clamped_maxtxpower(sc); + } +@@ -10238,6 +10274,7 @@ ath_get_clamped_maxtxpower(struct ath_so + { + u_int32_t clamped_maxtxpower; + (void)ath_hal_getmaxtxpow(sc->sc_ah, &clamped_maxtxpower); ++ clamped_maxtxpower += sc->sc_poweroffset; + return clamped_maxtxpower; + } + +@@ -10821,6 +10858,12 @@ ath_ioctl(struct net_device *dev, struct * is to add module parameters. */ @@ -75,7 +92,7 @@ /* * Dynamic (i.e. per-device) sysctls. These are automatically * mirrored in /proc/sys. -@@ -10900,6 +10940,38 @@ ath_sysctl_get_intmit(struct ath_softc * +@@ -10900,6 +10943,38 @@ ath_sysctl_get_intmit(struct ath_softc * } static int @@ -114,7 +131,7 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos) { struct ath_softc *sc = ctl->extra1; -@@ -11179,6 +11251,24 @@ static int maxint = 0x7fffffff; /* 32-b +@@ -11179,6 +11254,24 @@ static int maxint = 0x7fffffff; /* 32-b static const ctl_table ath_sysctl_template[] = { { .ctl_name = CTL_AUTO, @@ -174,7 +191,15 @@ unsigned int sc_invalid:1; /* being detached */ unsigned int sc_mrretry:1; /* multi-rate retry support */ -@@ -929,4 +935,15 @@ int ar_device(int devid); +@@ -683,6 +689,7 @@ struct ath_softc { + const HAL_RATE_TABLE *sc_quarter_rates; /* quarter rate table */ + HAL_OPMODE sc_opmode; /* current hal operating mode */ + enum ieee80211_phymode sc_curmode; /* current phy mode */ ++ u_int sc_poweroffset; /* hardware power offset */ + u_int16_t sc_curtxpow; /* current tx power limit */ + u_int16_t sc_curaid; /* current association id */ + HAL_CHANNEL sc_curchan; /* current h/w channel */ +@@ -929,4 +936,16 @@ int ar_device(int devid); void ath_radar_detected(struct ath_softc *sc, const char* message); @@ -185,6 +210,7 @@ + u32 id; + u32 subvendor; + u32 subid; ++ u32 poweroffset; +}; + +extern void ath_hw_detect(struct ath_softc *sc, const struct ath_hw_detect *cards, int n_cards, u32 vendor, u32 id, u32 subvendor, u32 subid); @@ -200,92 +226,27 @@ #include #include -@@ -181,12 +182,97 @@ exit_ath_wmac(u_int16_t wlanNum, struct +@@ -181,12 +182,32 @@ exit_ath_wmac(u_int16_t wlanNum, struct return 0; } +static const char ubnt[] = "Ubiquiti Networks"; ++/* { vendorname, cardname, vendorid, cardid, subsys vendorid, subsys id, poweroffset } */ +static const struct ath_hw_detect cards[] = { -+ { -+ .vendor_name = ubnt, -+ .card_name = "PowerStation2 (18V)", -+ .vendor = PCI_ANY_ID, -+ .id = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subid = 0xb102, -+ }, -+ { -+ .vendor_name = ubnt, -+ .card_name = "PowerStation2 (16D)", -+ .vendor = PCI_ANY_ID, -+ .id = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subid = 0xb202, -+ }, -+ { -+ .vendor_name = ubnt, -+ .card_name = "PowerStation2 (EXT)", -+ .vendor = PCI_ANY_ID, -+ .id = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subid = 0xb302, -+ }, -+ { -+ .vendor_name = ubnt, -+ .card_name = "PowerStation5 (22V)", -+ .vendor = PCI_ANY_ID, -+ .id = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subid = 0xb105, -+ }, -+ { -+ .vendor_name = ubnt, -+ .card_name = "PowerStation5 (EXT)", -+ .vendor = PCI_ANY_ID, -+ .id = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subid = 0xb305, -+ }, -+ { -+ .vendor_name = ubnt, -+ .card_name = "WispStation5", -+ .vendor = PCI_ANY_ID, -+ .id = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subid = 0xa105, -+ }, -+ { -+ .vendor_name = ubnt, -+ .card_name = "LiteStation2", -+ .vendor = PCI_ANY_ID, -+ .id = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subid = 0xa002, -+ }, -+ { -+ .vendor_name = ubnt, -+ .card_name = "LiteStation5", -+ .vendor = PCI_ANY_ID, -+ .id = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subid = 0xa005, -+ }, -+ { -+ .vendor_name = ubnt, -+ .card_name = "NanoStation2", -+ .vendor = PCI_ANY_ID, -+ .id = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subid = 0xc002, -+ }, -+ { -+ .vendor_name = ubnt, -+ .card_name = "NanoStation5", -+ .vendor = PCI_ANY_ID, -+ .id = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subid = 0xc005, -+ }, ++ { ubnt, "PowerStation2 (18V)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb102 }, ++ { ubnt, "PowerStation2 (16D)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb202 }, ++ { ubnt, "PowerStation2 (EXT)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb302 }, ++ { ubnt, "PowerStation5 (22V)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb105 }, ++ { ubnt, "PowerStation5 (EXT)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb305 }, ++ { ubnt, "WispStation5", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xa105 }, ++ { ubnt, "LiteStation2", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xa002 }, ++ { ubnt, "LiteStation5", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xa005 }, ++ { ubnt, "NanoStation2", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc002 }, ++ { ubnt, "NanoStation5", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc005 }, ++ { ubnt, "NanoStation Loco2", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc102 }, ++ { ubnt, "NanoStation Loco5", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc105 }, ++ { ubnt, "Bullet2", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc202 }, ++ { ubnt, "Bullet5", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc205 }, +}; + static int @@ -298,7 +259,7 @@ if (((wlanNum != 0) && (wlanNum != 1)) || (sclist[wlanNum] != NULL)) -@@ -248,6 +334,16 @@ init_ath_wmac(u_int16_t devid, u_int16_t +@@ -248,6 +269,16 @@ init_ath_wmac(u_int16_t devid, u_int16_t sc->aps_sc.sc_softled = 1; /* SoftLED over GPIO */ sc->aps_sc.sc_ledpin = config->board->sysLedGpio; sc->aps_sc.sc_invalid = 0; @@ -315,3 +276,50 @@ return 0; bad4: +--- a/ath/if_ath_pci.c ++++ b/ath/if_ath_pci.c +@@ -123,6 +123,33 @@ static u16 ath_devidmap[][2] = { + { 0xff1a, 0x001a } + }; + ++static const char ubnt[] = "Ubiquiti Networks"; ++/* { vendorname, cardname, vendorid, cardid, subsys vendorid, subsys id, poweroffset } */ ++static const struct ath_hw_detect cards[] = { ++ { ubnt, "XR2", 0x168c, 0x001b, 0x0777, 0x3002, 10 }, ++ { ubnt, "XR2", 0x168c, 0x001b, 0x7777, 0x3002, 10 }, ++ { ubnt, "XR2.3", 0x168c, 0x001b, 0x0777, 0x3b02, 10 }, ++ { ubnt, "XR2.6", 0x168c, 0x001b, 0x0777, 0x3c02, 10 }, ++ { ubnt, "XR3-2.8", 0x168c, 0x001b, 0x0777, 0x3b03, 10 }, ++ { ubnt, "XR3-3.6", 0x168c, 0x001b, 0x0777, 0x3c03, 10 }, ++ { ubnt, "XR3", 0x168c, 0x001b, 0x0777, 0x3003, 10 }, ++ { ubnt, "XR4", 0x168c, 0x001b, 0x0777, 0x3004, 10 }, ++ { ubnt, "XR5", 0x168c, 0x001b, 0x0777, 0x3005, 10 }, ++ { ubnt, "XR5", 0x168c, 0x001b, 0x7777, 0x3005, 10 }, ++ { ubnt, "XR7", 0x168c, 0x001b, 0x0777, 0x3007, 10 }, ++ { ubnt, "XR9", 0x168c, 0x001b, 0x0777, 0x3009, 10 }, ++ { ubnt, "SRC", 0x168c, 0x0013, 0x168c, 0x1042, 1 }, ++ { ubnt, "SR2", 0x168c, 0x0013, 0x0777, 0x2041, 10 }, ++ { ubnt, "SR4", 0x168c, 0x0013, 0x0777, 0x2004, 6 }, ++ { ubnt, "SR4", 0x168c, 0x0013, 0x7777, 0x2004, 6 }, ++ { ubnt, "SR4C", 0x168c, 0x0013, 0x0777, 0x1004, 6 }, ++ { ubnt, "SR4C", 0x168c, 0x0013, 0x7777, 0x1004, 6 }, ++ { ubnt, "SR5", 0x168c, 0x0013, 0x168c, 0x2042, 7 }, ++ { ubnt, "SR9", 0x168c, 0x0013, 0x7777, 0x2009, 12 }, ++ { ubnt, "SR71A", 0x168c, 0x0027, 0x168c, 0x2082, 10 }, ++ { ubnt, "SR71", 0x168c, 0x0027, 0x0777, 0x4082, 10 }, ++}; ++ + static int + ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + { +@@ -257,6 +284,10 @@ ath_pci_probe(struct pci_dev *pdev, cons + printk(KERN_INFO "%s: %s: %s: mem=0x%lx, irq=%d\n", + dev_info, dev->name, athname ? athname : "Atheros ???", phymem, dev->irq); + ++ ath_hw_detect(&sc->aps_sc, cards, ARRAY_SIZE(cards), ++ pdev->vendor, pdev->device, ++ pdev->subsystem_vendor, pdev->subsystem_device); ++ + /* ready to process interrupts */ + sc->aps_sc.sc_invalid = 0; + diff --git a/package/madwifi/patches/385-antenna_fix.patch b/package/madwifi/patches/385-antenna_fix.patch index 9e34304402..e3899643be 100644 --- a/package/madwifi/patches/385-antenna_fix.patch +++ b/package/madwifi/patches/385-antenna_fix.patch @@ -1,6 +1,6 @@ --- a/ath/if_ath.c +++ b/ath/if_ath.c -@@ -6668,6 +6668,7 @@ ath_setdefantenna(struct ath_softc *sc, +@@ -6669,6 +6669,7 @@ ath_setdefantenna(struct ath_softc *sc, struct ath_hal *ah = sc->sc_ah; /* XXX block beacon interrupts */ diff --git a/package/madwifi/patches/389-autochannel.patch b/package/madwifi/patches/389-autochannel.patch index c818b89ef9..06c5c12a7d 100644 --- a/package/madwifi/patches/389-autochannel.patch +++ b/package/madwifi/patches/389-autochannel.patch @@ -8,7 +8,7 @@ /* calibrate every 30 secs in steady state but check every second at first. */ static int ath_calinterval = ATH_SHORT_CALINTERVAL; -@@ -2580,6 +2581,7 @@ ath_init(struct net_device *dev) +@@ -2581,6 +2582,7 @@ ath_init(struct net_device *dev) * be followed by initialization of the appropriate bits * and then setup of the interrupt mask. */ @@ -16,7 +16,7 @@ sc->sc_curchan.channel = ic->ic_curchan->ic_freq; sc->sc_curchan.channelFlags = ath_chan2flags(ic->ic_curchan); if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_FALSE, &status)) { -@@ -2913,6 +2915,48 @@ ath_hw_check_atim(struct ath_softc *sc, +@@ -2914,6 +2916,48 @@ ath_hw_check_atim(struct ath_softc *sc, return 0; } @@ -65,7 +65,7 @@ /* * Reset the hardware w/o losing operational state. This is -@@ -2940,6 +2984,7 @@ ath_reset(struct net_device *dev) +@@ -2941,6 +2985,7 @@ ath_reset(struct net_device *dev) * Convert to a HAL channel description with the flags * constrained to reflect the current operating mode. */ @@ -73,7 +73,7 @@ c = ic->ic_curchan; sc->sc_curchan.channel = c->ic_freq; sc->sc_curchan.channelFlags = ath_chan2flags(c); -@@ -9022,6 +9067,7 @@ ath_chan_set(struct ath_softc *sc, struc +@@ -9023,6 +9068,7 @@ ath_chan_set(struct ath_softc *sc, struc u_int8_t channel_change_required = 0; struct timeval tv; @@ -81,7 +81,7 @@ /* * Convert to a HAL channel description with * the flags constrained to reflect the current -@@ -9030,6 +9076,14 @@ ath_chan_set(struct ath_softc *sc, struc +@@ -9031,6 +9077,14 @@ ath_chan_set(struct ath_softc *sc, struc memset(&hchan, 0, sizeof(HAL_CHANNEL)); hchan.channel = chan->ic_freq; hchan.channelFlags = ath_chan2flags(chan); @@ -98,7 +98,7 @@ do_gettimeofday(&tv); --- a/ath/if_athvar.h +++ b/ath/if_athvar.h -@@ -773,6 +773,7 @@ struct ath_softc { +@@ -774,6 +774,7 @@ struct ath_softc { struct ieee80211vap **sc_bslot; /* beacon xmit slots */ int sc_bnext; /* next slot for beacon xmit */ diff --git a/package/madwifi/patches/390-frame_type.patch b/package/madwifi/patches/390-frame_type.patch index 130f3b6d61..71d658b4e5 100644 --- a/package/madwifi/patches/390-frame_type.patch +++ b/package/madwifi/patches/390-frame_type.patch @@ -5,7 +5,7 @@ skb->pkt_type = PACKET_OTHERHOST; - return eth->h_proto; -+ if (ntohs(eth->h_proto) >= 1536) ++ if ((ntohs(eth->h_proto) >= 1536) || (ntohs(eth->h_proto) < 38)) + return eth->h_proto; + return htons(ETH_P_802_2); } diff --git a/package/madwifi/patches/393-mbss_vap_auth.patch b/package/madwifi/patches/393-mbss_vap_auth.patch index e1c9cae0d0..e4c50f9d82 100644 --- a/package/madwifi/patches/393-mbss_vap_auth.patch +++ b/package/madwifi/patches/393-mbss_vap_auth.patch @@ -319,7 +319,7 @@ --- a/ath/if_ath.c +++ b/ath/if_ath.c -@@ -6588,9 +6588,8 @@ ath_recv_mgmt(struct ieee80211vap * vap, +@@ -6589,9 +6589,8 @@ ath_recv_mgmt(struct ieee80211vap * vap, sc->sc_recv_mgmt(vap, ni_or_null, skb, subtype, rssi, rtsf); @@ -330,7 +330,7 @@ (const struct ieee80211_frame_min *)skb->data); if (ni == NULL) { DPRINTF(sc, ATH_DEBUG_BEACON, "Dropping; node unknown.\n"); -@@ -6745,7 +6744,9 @@ ath_rx_poll(struct net_device *dev, int +@@ -6746,7 +6745,9 @@ ath_rx_poll(struct net_device *dev, int struct ath_desc *ds; struct ath_rx_status *rs; struct sk_buff *skb = NULL; @@ -340,7 +340,7 @@ unsigned int len; int type; u_int phyerr; -@@ -6900,12 +6901,15 @@ rx_accept: +@@ -6901,12 +6902,15 @@ rx_accept: skb_trim(skb, skb->len - IEEE80211_CRC_LEN); if (mic_fail) { @@ -358,7 +358,7 @@ if (ni && ni->ni_table) { ieee80211_check_mic(ni, skb); -@@ -6967,11 +6971,24 @@ drop_micfail: +@@ -6968,11 +6972,24 @@ drop_micfail: * for its use. If the sender is unknown spam the * frame; it'll be dropped where it's not wanted. */ @@ -385,7 +385,7 @@ ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi); type = ieee80211_input(ni->ni_vap, ni, skb, rs->rs_rssi, bf->bf_tsf); ieee80211_unref_node(&ni); -@@ -6980,24 +6997,35 @@ drop_micfail: +@@ -6981,24 +6998,35 @@ drop_micfail: * No key index or no entry, do a lookup and * add the node to the mapping table if possible. */ diff --git a/package/madwifi/patches/395-ath_ff_unmap.patch b/package/madwifi/patches/395-ath_ff_unmap.patch index 6ba99caf31..4f88d039e8 100644 --- a/package/madwifi/patches/395-ath_ff_unmap.patch +++ b/package/madwifi/patches/395-ath_ff_unmap.patch @@ -1,6 +1,6 @@ --- a/ath/if_ath.c +++ b/ath/if_ath.c -@@ -13527,7 +13527,7 @@ cleanup_ath_buf(struct ath_softc *sc, st +@@ -13530,7 +13530,7 @@ cleanup_ath_buf(struct ath_softc *sc, st bus_unmap_single( sc->sc_bdev, bf->bf_skbaddrff[i], diff --git a/package/madwifi/patches/396-napi_ff_fix.patch b/package/madwifi/patches/396-napi_ff_fix.patch index fbfd30e266..695a445f68 100644 --- a/package/madwifi/patches/396-napi_ff_fix.patch +++ b/package/madwifi/patches/396-napi_ff_fix.patch @@ -1,6 +1,6 @@ --- a/ath/if_ath.c +++ b/ath/if_ath.c -@@ -6733,10 +6733,10 @@ ath_rx_poll(struct net_device *dev, int +@@ -6734,10 +6734,10 @@ ath_rx_poll(struct net_device *dev, int #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) struct ath_softc *sc = container_of(napi, struct ath_softc, sc_napi); struct net_device *dev = sc->sc_dev; @@ -13,7 +13,7 @@ #endif struct ath_buf *bf; struct ieee80211com *ic = &sc->sc_ic; -@@ -6779,13 +6779,15 @@ process_rx_again: +@@ -6780,13 +6780,15 @@ process_rx_again: break; } @@ -33,7 +33,7 @@ skb = bf->bf_skb; if (skb == NULL) { -@@ -7069,8 +7071,8 @@ rx_next: +@@ -7070,8 +7072,8 @@ rx_next: if (sc->sc_isr & HAL_INT_RX) { u_int64_t hw_tsf = ath_hal_gettsf64(ah); sc->sc_isr &= ~HAL_INT_RX; diff --git a/package/madwifi/patches/400-new_hal.patch b/package/madwifi/patches/400-new_hal.patch index 7de829ae7d..d994c3a2f0 100644 --- a/package/madwifi/patches/400-new_hal.patch +++ b/package/madwifi/patches/400-new_hal.patch @@ -15,7 +15,7 @@ /* * Check if the MAC has multi-rate retry support. * We do this by trying to setup a fake extended -@@ -7563,7 +7571,7 @@ ath_txq_setup(struct ath_softc *sc, int +@@ -7564,7 +7572,7 @@ ath_txq_setup(struct ath_softc *sc, int if (qtype == HAL_TX_QUEUE_UAPSD) qi.tqi_qflags = HAL_TXQ_TXDESCINT_ENABLE; else diff --git a/package/madwifi/patches/406-monitor_r3711.patch b/package/madwifi/patches/406-monitor_r3711.patch index 13d1d54904..4e2c6aefb7 100644 --- a/package/madwifi/patches/406-monitor_r3711.patch +++ b/package/madwifi/patches/406-monitor_r3711.patch @@ -1,6 +1,6 @@ --- a/ath/if_ath.c +++ b/ath/if_ath.c -@@ -6529,7 +6529,7 @@ ath_capture(struct net_device *dev, cons +@@ -6530,7 +6530,7 @@ ath_capture(struct net_device *dev, cons /* Never copy the SKB, as it is ours on the RX side, and this is the * last process on the TX side and we only modify our own headers. */ @@ -9,7 +9,7 @@ if (tskb == NULL) { DPRINTF(sc, ATH_DEBUG_ANY, "Dropping; ath_skb_removepad failed!\n"); -@@ -6537,6 +6537,8 @@ ath_capture(struct net_device *dev, cons +@@ -6538,6 +6538,8 @@ ath_capture(struct net_device *dev, cons } ieee80211_input_monitor(ic, tskb, bf, tx, tsf, sc); diff --git a/package/madwifi/patches/408-changeset_r3337.patch b/package/madwifi/patches/408-changeset_r3337.patch index 78f89d273a..c78daf4c69 100644 --- a/package/madwifi/patches/408-changeset_r3337.patch +++ b/package/madwifi/patches/408-changeset_r3337.patch @@ -10,7 +10,7 @@ Please let us know if you think your name should be mentioned here! --- a/ath/if_ath.c +++ b/ath/if_ath.c -@@ -3146,7 +3146,7 @@ ath_tx_startraw(struct net_device *dev, +@@ -3147,7 +3147,7 @@ ath_tx_startraw(struct net_device *dev, struct ath_softc *sc = dev->priv; struct ath_hal *ah = sc->sc_ah; struct ieee80211_phy_params *ph = (struct ieee80211_phy_params *) diff --git a/package/madwifi/patches/410-ar231x_2.6.28.patch b/package/madwifi/patches/410-ar231x_2.6.28.patch index 87177c3986..30d1c56a4c 100644 --- a/package/madwifi/patches/410-ar231x_2.6.28.patch +++ b/package/madwifi/patches/410-ar231x_2.6.28.patch @@ -81,10 +81,10 @@ -} - static const char ubnt[] = "Ubiquiti Networks"; + /* { vendorname, cardname, vendorid, cardid, subsys vendorid, subsys id, poweroffset } */ static const struct ath_hw_detect cards[] = { - { -@@ -266,6 +238,114 @@ static const struct ath_hw_detect cards[ - }, +@@ -201,6 +173,114 @@ static const struct ath_hw_detect cards[ + { ubnt, "Bullet5", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc205 }, }; +static void @@ -198,7 +198,7 @@ static int init_ath_wmac(u_int16_t devid, u_int16_t wlanNum, struct ar531x_config *config) { -@@ -318,7 +398,7 @@ init_ath_wmac(u_int16_t devid, u_int16_t +@@ -253,7 +333,7 @@ init_ath_wmac(u_int16_t devid, u_int16_t sc->aps_sc.sc_iobase = (void __iomem *) dev->mem_start; sc->aps_sc.sc_bdev = NULL; @@ -207,7 +207,7 @@ printk(KERN_WARNING "%s: %s: request_irq failed\n", dev_info, dev->name); goto bad3; } -@@ -328,21 +408,12 @@ init_ath_wmac(u_int16_t devid, u_int16_t +@@ -263,21 +343,12 @@ init_ath_wmac(u_int16_t devid, u_int16_t athname = ath_hal_probe(ATHEROS_VENDOR_ID, devid); printk(KERN_INFO "%s: %s: %s: mem=0x%lx, irq=%d\n", dev_info, dev->name, athname ? athname : "Atheros ???", dev->mem_start, dev->irq); @@ -230,7 +230,7 @@ return 0; -@@ -357,6 +428,29 @@ init_ath_wmac(u_int16_t devid, u_int16_t +@@ -292,6 +363,29 @@ init_ath_wmac(u_int16_t devid, u_int16_t return -ENODEV; } @@ -260,7 +260,7 @@ static int ahb_wmac_probe(struct platform_device *pdev) { u_int16_t devid; -@@ -377,11 +471,18 @@ static int ahb_wmac_remove(struct platfo +@@ -312,11 +406,18 @@ static int ahb_wmac_remove(struct platfo return 0; } diff --git a/package/madwifi/patches/412-fragmentation_fix.patch b/package/madwifi/patches/412-fragmentation_fix.patch index dbe9f8e4f6..92c411b2bf 100644 --- a/package/madwifi/patches/412-fragmentation_fix.patch +++ b/package/madwifi/patches/412-fragmentation_fix.patch @@ -1,6 +1,6 @@ --- a/ath/if_ath.c +++ b/ath/if_ath.c -@@ -3683,6 +3683,7 @@ ff_bypass: +@@ -3684,6 +3684,7 @@ ff_bypass: * already alloc'd */ ATH_TXBUF_LOCK_IRQ(sc); diff --git a/package/madwifi/patches/413-rxorn.patch b/package/madwifi/patches/413-rxorn.patch index b4174716d7..0e8d885da6 100644 --- a/package/madwifi/patches/413-rxorn.patch +++ b/package/madwifi/patches/413-rxorn.patch @@ -1,6 +1,6 @@ --- a/ath/if_ath.c +++ b/ath/if_ath.c -@@ -2307,6 +2307,17 @@ ath_intr(int irq, void *dev_id, struct p +@@ -2308,6 +2308,17 @@ ath_intr(int irq, void *dev_id, struct p sc->sc_isr = status; status &= sc->sc_imask; /* discard unasked for bits */ @@ -18,7 +18,7 @@ /* As soon as we know we have a real interrupt we intend to service, * we will check to see if we need an initial hardware TSF reading. * Normally we would just populate this all the time to keep things -@@ -2319,10 +2330,6 @@ ath_intr(int irq, void *dev_id, struct p +@@ -2320,10 +2331,6 @@ ath_intr(int irq, void *dev_id, struct p sc->sc_stats.ast_hardware++; ath_hal_intrset(ah, 0); /* disable intr's until reset */ ATH_SCHEDULE_TQUEUE(&sc->sc_fataltq, &needmark); diff --git a/package/madwifi/patches/414-txpower.patch b/package/madwifi/patches/414-txpower.patch index 68e7942d48..86973229c8 100644 --- a/package/madwifi/patches/414-txpower.patch +++ b/package/madwifi/patches/414-txpower.patch @@ -12,7 +12,7 @@ KASSERT(c->ic_ieee < IEEE80211_CHAN_MAX, ("channel with bogus ieee number %u", c->ic_ieee)); setbit(ic->ic_chan_avail, c->ic_ieee); -+ ic->ic_max_txpower = max(ic->ic_max_txpower, (u16) c->ic_maxpower * 2); ++ ic->ic_max_txpower = max(ic->ic_max_txpower, (u16) (c->ic_maxpower * 2)); if (c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT) c->ic_scanflags |= IEEE80211_NOSCAN_SET; @@ -165,7 +165,7 @@ static void ath_poll_disable(struct net_device *dev); static void ath_poll_enable(struct net_device *dev); -@@ -3167,7 +3166,7 @@ ath_tx_startraw(struct net_device *dev, +@@ -3168,7 +3167,7 @@ ath_tx_startraw(struct net_device *dev, try0 = ph->try0; rt = sc->sc_currates; txrate = dot11_to_ratecode(sc, rt, ph->rate0); @@ -174,7 +174,7 @@ hdrlen = ieee80211_anyhdrsize(wh); pktlen = skb->len + IEEE80211_CRC_LEN; -@@ -8389,7 +8388,7 @@ ath_tx_start(struct net_device *dev, str +@@ -8390,7 +8389,7 @@ ath_tx_start(struct net_device *dev, str pktlen, /* packet length */ hdrlen, /* header length */ atype, /* Atheros packet type */ @@ -183,7 +183,7 @@ txrate, try0, /* series 0 rate/tries */ keyix, /* key cache index */ antenna, /* antenna mode */ -@@ -10380,59 +10379,16 @@ ath_get_clamped_maxtxpower(struct ath_so +@@ -10383,59 +10382,16 @@ ath_get_clamped_maxtxpower(struct ath_so /* XXX: this function needs some locking to avoid being called * twice/interrupted */ diff --git a/package/madwifi/patches/416-wprobe.patch b/package/madwifi/patches/416-wprobe.patch index 0eb5f8928d..73cf85fae4 100644 --- a/package/madwifi/patches/416-wprobe.patch +++ b/package/madwifi/patches/416-wprobe.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/ath/ath_wprobe.c -@@ -0,0 +1,392 @@ +@@ -0,0 +1,433 @@ +#include +#include + @@ -206,10 +206,38 @@ + if ((rate < 0) || (rate >= rt->rateCount)) + return -1; + -+ return rt->info[rate].rateKbps / 10; ++ return rt->info[rate].rateKbps; +} + +static void ++ath_wprobe_report_rx(struct ieee80211vap *vap, struct ath_rx_status *rs, struct sk_buff *skb) ++{ ++ const struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data; ++ struct wprobe_wlan_hdr hdr; ++ struct ath_vap *avp; ++ int hdrsize; ++ ++ if (wprobe_disabled()) ++ return; ++ ++ avp = ATH_VAP(vap); ++ avp->av_rxframes++; ++ if (wh->i_fc[0] == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ)) ++ avp->av_rxprobereq++; ++ ++ memset(&hdr, 0, sizeof(hdr)); ++ hdr.len = skb->len; ++ hdr.snr = rs->rs_rssi; ++ hdr.type = WPROBE_PKT_RX; ++ if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) ++ hdrsize = sizeof(struct ieee80211_ctlframe_addr2); ++ else ++ hdrsize = ieee80211_hdrsize(skb->data); ++ wprobe_add_frame(&avp->av_wpif, &hdr, skb->data, hdrsize + 0x42); ++} ++ ++ ++static void +ath_node_sample_rx(struct ieee80211_node *ni, struct ath_rx_status *rs) +{ + struct ath_node *an = ATH_NODE(ni); @@ -237,7 +265,33 @@ +} + +static void -+ath_node_sample_tx(struct ieee80211_node *ni, struct ath_tx_status *ts, int len) ++ath_wprobe_report_tx(struct ieee80211vap *vap, struct ath_tx_status *ts, struct sk_buff *skb) ++{ ++ const struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data; ++ struct wprobe_wlan_hdr hdr; ++ struct ath_vap *avp; ++ int hdrsize; ++ ++ if (wprobe_disabled()) ++ return; ++ ++ avp = ATH_VAP(vap); ++ ++ memset(&hdr, 0, sizeof(hdr)); ++ hdr.len = skb->len; ++ hdr.snr = ts->ts_rssi; ++ hdr.type = WPROBE_PKT_TX; ++ if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) ++ hdrsize = sizeof(struct ieee80211_ctlframe_addr2); ++ else ++ hdrsize = ieee80211_hdrsize(skb->data); ++ wprobe_add_frame(&avp->av_wpif, &hdr, skb->data, hdrsize + 0x42); ++} ++ ++ ++ ++static void ++ath_node_sample_tx(struct ieee80211_node *ni, struct ath_tx_status *ts, struct sk_buff *skb) +{ + struct ath_node *an = ATH_NODE(ni); + struct ieee80211vap *vap = ni->ni_vap; @@ -246,10 +300,12 @@ + struct wprobe_value *v = l->val; + unsigned long flags; + int rate, rexmit_counter; ++ int len = skb->len; + + if (wprobe_disabled() || !an->an_wplink_active || !l->val) + return; + ++ ath_wprobe_report_tx(vap, ts, skb); + rate = ath_lookup_rateval(ni, ts->ts_rate); + + spin_lock_irqsave(&l->iface->lock, flags); @@ -275,21 +331,6 @@ +} + +static void -+ath_wprobe_report_rx(struct ieee80211vap *vap, struct sk_buff *skb) -+{ -+ struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data; -+ struct ath_vap *avp; -+ -+ if (wprobe_disabled()) -+ return; -+ -+ avp = ATH_VAP(vap); -+ avp->av_rxframes++; -+ if (wh->i_fc[0] == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ)) -+ avp->av_rxprobereq++; -+} -+ -+static void +ath_wprobe_node_join(struct ieee80211vap *vap, struct ieee80211_node *ni) +{ + struct wprobe_iface *dev; @@ -411,7 +452,7 @@ return vap; } -@@ -1605,6 +1607,7 @@ ath_vap_delete(struct ieee80211vap *vap) +@@ -1606,6 +1608,7 @@ ath_vap_delete(struct ieee80211vap *vap) decrease = 0; ieee80211_vap_detach(vap); @@ -419,7 +460,7 @@ /* NB: memory is reclaimed through dev->destructor callback */ if (decrease) sc->sc_nvaps--; -@@ -5939,6 +5942,7 @@ ath_node_cleanup(struct ieee80211_node * +@@ -5940,6 +5943,7 @@ ath_node_cleanup(struct ieee80211_node * /* Clean up node-specific rate things - this currently appears to * always be a no-op */ sc->sc_rc->ops->node_cleanup(sc, ATH_NODE(ni)); @@ -427,27 +468,27 @@ ATH_NODE_UAPSD_LOCK_IRQ(an); #ifdef IEEE80211_DEBUG_REFCNT -@@ -7009,6 +7013,8 @@ drop_micfail: +@@ -7010,6 +7014,8 @@ drop_micfail: goto lookup_slowpath; } ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi); + ath_node_sample_rx(ni, rs); -+ ath_wprobe_report_rx(ni->ni_vap, skb); ++ ath_wprobe_report_rx(ni->ni_vap, rs, skb); type = ieee80211_input(ni->ni_vap, ni, skb, rs->rs_rssi, bf->bf_tsf); ieee80211_unref_node(&ni); } else { -@@ -7019,15 +7025,22 @@ drop_micfail: +@@ -7020,15 +7026,22 @@ drop_micfail: lookup_slowpath: vap = ieee80211_find_rxvap(ic, wh->i_addr1); - if (vap) + if (vap) { -+ ath_wprobe_report_rx(vap, skb); ++ ath_wprobe_report_rx(vap, rs, skb); ni = ieee80211_find_rxnode(ic, vap, wh); - else + } else { + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { -+ ath_wprobe_report_rx(vap, skb); ++ ath_wprobe_report_rx(vap, rs, skb); + } + vap = NULL; ni = NULL; @@ -461,15 +502,15 @@ type = ieee80211_input(vap, ni, skb, rs->rs_rssi, bf->bf_tsf); /* * If the station has a key cache slot assigned -@@ -8607,6 +8620,7 @@ ath_tx_processq(struct ath_softc *sc, st +@@ -8608,6 +8621,7 @@ ath_tx_processq(struct ath_softc *sc, st sc->sc_stats.ast_tx_rssi = ts->ts_rssi; ATH_RSSI_LPF(an->an_halstats.ns_avgtxrssi, ts->ts_rssi); -+ ath_node_sample_tx(&an->an_node, ts, bf->bf_skb->len); ++ ath_node_sample_tx(&an->an_node, ts, bf->bf_skb); if (bf->bf_skb->priority == WME_AC_VO || bf->bf_skb->priority == WME_AC_VI) ni->ni_ic->ic_wme.wme_hipri_traffic++; -@@ -10106,6 +10120,7 @@ ath_newassoc(struct ieee80211_node *ni, +@@ -10107,6 +10121,7 @@ ath_newassoc(struct ieee80211_node *ni, struct ath_softc *sc = ic->ic_dev->priv; sc->sc_rc->ops->newassoc(sc, ATH_NODE(ni), isnew); diff --git a/package/madwifi/patches/417-beacon_txpower.patch b/package/madwifi/patches/417-beacon_txpower.patch index 80d810a7db..5a336f8e52 100644 --- a/package/madwifi/patches/417-beacon_txpower.patch +++ b/package/madwifi/patches/417-beacon_txpower.patch @@ -9,7 +9,7 @@ static int countrycode = -1; static int maxvaps = -1; static int outdoor = -1; -@@ -4931,6 +4931,7 @@ ath_beacon_setup(struct ath_softc *sc, s +@@ -4932,6 +4932,7 @@ ath_beacon_setup(struct ath_softc *sc, s (((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\ == IEEE80211_F_SHPREAMBLE) struct ieee80211com *ic = bf->bf_node->ni_ic; @@ -17,7 +17,7 @@ struct sk_buff *skb = bf->bf_skb; struct ath_hal *ah = sc->sc_ah; struct ath_desc *ds; -@@ -4998,7 +4999,7 @@ ath_beacon_setup(struct ath_softc *sc, s +@@ -4999,7 +5000,7 @@ ath_beacon_setup(struct ath_softc *sc, s skb->len + IEEE80211_CRC_LEN, /* frame length */ sizeof(struct ieee80211_frame), /* header length */ HAL_PKT_TYPE_BEACON, /* Atheros packet type */ diff --git a/package/madwifi/patches/419-skb_unmap_crash.patch b/package/madwifi/patches/419-skb_unmap_crash.patch index 90c67edf58..54fd544d74 100644 --- a/package/madwifi/patches/419-skb_unmap_crash.patch +++ b/package/madwifi/patches/419-skb_unmap_crash.patch @@ -1,6 +1,6 @@ --- a/ath/if_ath.c +++ b/ath/if_ath.c -@@ -13493,7 +13493,7 @@ cleanup_ath_buf(struct ath_softc *sc, st +@@ -13496,7 +13496,7 @@ cleanup_ath_buf(struct ath_softc *sc, st if (bf == NULL) return bf; @@ -9,7 +9,7 @@ bus_unmap_single( sc->sc_bdev, bf->bf_skbaddr, -@@ -13501,8 +13501,6 @@ cleanup_ath_buf(struct ath_softc *sc, st +@@ -13504,8 +13504,6 @@ cleanup_ath_buf(struct ath_softc *sc, st sc->sc_rxbufsize : bf->bf_skb->len), direction); bf->bf_skbaddr = 0; diff --git a/package/madwifi/patches/420-diversity_fix.patch b/package/madwifi/patches/420-diversity_fix.patch index 8fc0ee7895..12bb77bc2e 100644 --- a/package/madwifi/patches/420-diversity_fix.patch +++ b/package/madwifi/patches/420-diversity_fix.patch @@ -8,7 +8,7 @@ sc->sc_rc = ieee80211_rate_attach(sc, ratectl); if (sc->sc_rc == NULL) { error = EIO; -@@ -2623,9 +2622,6 @@ ath_init(struct net_device *dev) +@@ -2624,9 +2623,6 @@ ath_init(struct net_device *dev) ath_radar_update(sc); ath_rp_flush(sc); @@ -18,7 +18,7 @@ /* * Setup the hardware after reset: the key cache * is filled as needed and the receive engine is -@@ -3018,7 +3014,6 @@ ath_reset(struct net_device *dev) +@@ -3019,7 +3015,6 @@ ath_reset(struct net_device *dev) ath_setintmit(sc); ath_update_txpow(sc); /* update tx power state */ ath_radar_update(sc); @@ -26,7 +26,7 @@ if (ath_startrecv(sc) != 0) /* restart recv */ EPRINTF(sc, "Unable to start receive logic.\n"); if (sc->sc_softled) -@@ -5352,27 +5347,6 @@ ath_beacon_send(struct ath_softc *sc, in +@@ -5353,27 +5348,6 @@ ath_beacon_send(struct ath_softc *sc, in } else if ((sc->sc_updateslot == COMMIT) && (sc->sc_slotupdate == slot)) ath_setslottime(sc); /* commit change to hardware */ @@ -54,7 +54,7 @@ if (bfaddr != 0) { /* * Stop any current DMA and put the new frame(s) on the queue. -@@ -6733,9 +6707,8 @@ ath_setdefantenna(struct ath_softc *sc, +@@ -6734,9 +6708,8 @@ ath_setdefantenna(struct ath_softc *sc, { struct ath_hal *ah = sc->sc_ah; @@ -65,7 +65,7 @@ if (sc->sc_defant != antenna) sc->sc_stats.ast_ant_defswitch++; sc->sc_defant = antenna; -@@ -11154,7 +11127,7 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl +@@ -11157,7 +11130,7 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl break; } sc->sc_diversity = val; diff --git a/package/madwifi/patches/421-channel_handling.patch b/package/madwifi/patches/421-channel_handling.patch index 6531a9ec19..8ccecdfdd2 100644 --- a/package/madwifi/patches/421-channel_handling.patch +++ b/package/madwifi/patches/421-channel_handling.patch @@ -184,7 +184,7 @@ #ifdef ATH_SUPERG_XR ic->ic_ath_cap |= (ath_hal_xrsupported(ah) ? IEEE80211_ATHC_XR : 0); #endif -@@ -4469,17 +4485,17 @@ ath_mode_init(struct net_device *dev) +@@ -4470,17 +4486,17 @@ ath_mode_init(struct net_device *dev) * Set the slot time based on the current setting. */ static void @@ -210,7 +210,7 @@ sc->sc_updateslot = OK; } -@@ -4501,7 +4517,7 @@ ath_updateslot(struct net_device *dev) +@@ -4502,7 +4518,7 @@ ath_updateslot(struct net_device *dev) if (ic->ic_opmode == IEEE80211_M_HOSTAP) sc->sc_updateslot = UPDATE; else if (dev->flags & IFF_RUNNING) @@ -219,7 +219,7 @@ } #ifdef ATH_SUPERG_DYNTURBO -@@ -5345,7 +5361,7 @@ ath_beacon_send(struct ath_softc *sc, in +@@ -5346,7 +5362,7 @@ ath_beacon_send(struct ath_softc *sc, in sc->sc_updateslot = COMMIT; /* commit next beacon */ sc->sc_slotupdate = slot; } else if ((sc->sc_updateslot == COMMIT) && (sc->sc_slotupdate == slot)) @@ -228,7 +228,7 @@ if (bfaddr != 0) { /* -@@ -7798,12 +7814,14 @@ ath_get_ivlen(struct ieee80211_key *k) +@@ -7799,12 +7815,14 @@ ath_get_ivlen(struct ieee80211_key *k) * Get transmit rate index using rate in Kbps */ static __inline int @@ -245,7 +245,7 @@ ndx = i; break; } -@@ -8096,7 +8114,7 @@ ath_tx_start(struct net_device *dev, str +@@ -8097,7 +8115,7 @@ ath_tx_start(struct net_device *dev, str atype = HAL_PKT_TYPE_NORMAL; /* default */ if (ismcast) { @@ -254,7 +254,7 @@ txrate = rt->info[rix].rateCode; if (shortPreamble) txrate |= rt->info[rix].shortPreamble; -@@ -9063,7 +9081,7 @@ ath_chan_change(struct ath_softc *sc, st +@@ -9064,7 +9082,7 @@ ath_chan_change(struct ath_softc *sc, st struct net_device *dev = sc->sc_dev; enum ieee80211_phymode mode; @@ -263,7 +263,7 @@ ath_rate_setup(dev, mode); ath_setcurmode(sc, mode); -@@ -10120,8 +10138,7 @@ ath_newassoc(struct ieee80211_node *ni, +@@ -10121,8 +10139,7 @@ ath_newassoc(struct ieee80211_node *ni, } static int @@ -273,7 +273,7 @@ { struct ath_softc *sc = dev->priv; struct ieee80211com *ic = &sc->sc_ic; -@@ -10135,17 +10152,31 @@ ath_getchannels(struct net_device *dev, +@@ -10136,17 +10153,31 @@ ath_getchannels(struct net_device *dev, EPRINTF(sc, "Insufficient memory for channel table!\n"); return -ENOMEM; } @@ -307,7 +307,7 @@ /* * Convert HAL channels to ieee80211 ones. */ -@@ -10389,7 +10420,7 @@ ath_xr_rate_setup(struct net_device *dev +@@ -10392,7 +10423,7 @@ ath_xr_rate_setup(struct net_device *dev struct ieee80211com *ic = &sc->sc_ic; const HAL_RATE_TABLE *rt; struct ieee80211_rateset *rs; @@ -316,7 +316,7 @@ sc->sc_xr_rates = ath_hal_getratetable(ah, HAL_MODE_XR); rt = sc->sc_xr_rates; if (rt == NULL) -@@ -10402,57 +10433,16 @@ ath_xr_rate_setup(struct net_device *dev +@@ -10405,57 +10436,16 @@ ath_xr_rate_setup(struct net_device *dev } else maxrates = rt->rateCount; rs = &ic->ic_sup_xr_rates; @@ -380,7 +380,7 @@ static int ath_rate_setup(struct net_device *dev, u_int mode) { -@@ -10461,7 +10451,7 @@ ath_rate_setup(struct net_device *dev, u +@@ -10464,7 +10454,7 @@ ath_rate_setup(struct net_device *dev, u struct ieee80211com *ic = &sc->sc_ic; const HAL_RATE_TABLE *rt; struct ieee80211_rateset *rs; @@ -389,7 +389,7 @@ switch (mode) { case IEEE80211_MODE_11A: -@@ -10479,6 +10469,12 @@ ath_rate_setup(struct net_device *dev, u +@@ -10482,6 +10472,12 @@ ath_rate_setup(struct net_device *dev, u case IEEE80211_MODE_TURBO_G: sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_108G); break; @@ -402,7 +402,7 @@ default: DPRINTF(sc, ATH_DEBUG_ANY, "Invalid mode %u\n", mode); return 0; -@@ -10493,10 +10489,16 @@ ath_rate_setup(struct net_device *dev, u +@@ -10496,10 +10492,16 @@ ath_rate_setup(struct net_device *dev, u maxrates = IEEE80211_RATE_MAXSIZE; } else maxrates = rt->rateCount; @@ -419,7 +419,7 @@ return 1; } -@@ -10525,13 +10527,18 @@ ath_setcurmode(struct ath_softc *sc, enu +@@ -10528,13 +10530,18 @@ ath_setcurmode(struct ath_softc *sc, enu { 0, 500, 130 }, }; const HAL_RATE_TABLE *rt; @@ -440,7 +440,7 @@ memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap)); for (i = 0; i < 32; i++) { u_int8_t ix = rt->rateCodeToIndex[i]; -@@ -10541,7 +10548,7 @@ ath_setcurmode(struct ath_softc *sc, enu +@@ -10544,7 +10551,7 @@ ath_setcurmode(struct ath_softc *sc, enu continue; } sc->sc_hwmap[i].ieeerate = @@ -449,7 +449,7 @@ if (rt->info[ix].shortPreamble || rt->info[ix].phy == IEEE80211_T_OFDM) sc->sc_hwmap[i].flags |= IEEE80211_RADIOTAP_F_SHORTPRE; -@@ -10942,9 +10949,106 @@ enum { +@@ -10945,9 +10952,106 @@ enum { ATH_MAXVAPS = 26, ATH_INTMIT = 27, ATH_NOISE_IMMUNITY = 28, @@ -557,7 +557,7 @@ static int ath_sysctl_set_intmit(struct ath_softc *sc, long ctl, u_int val) { -@@ -11023,6 +11127,7 @@ static int +@@ -11026,6 +11130,7 @@ static int ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos) { struct ath_softc *sc = ctl->extra1; @@ -565,7 +565,7 @@ struct ath_hal *ah = sc->sc_ah; u_int val; u_int tab_3_val[3]; -@@ -11046,25 +11151,34 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl +@@ -11049,25 +11154,34 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl lenp, ppos); if (ret == 0) { switch ((long)ctl->extra2) { @@ -613,7 +613,7 @@ break; case ATH_SOFTLED: if (val != sc->sc_softled) { -@@ -11217,6 +11331,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl +@@ -11220,6 +11334,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl } } else { switch ((long)ctl->extra2) { @@ -623,7 +623,7 @@ case ATH_SLOTTIME: val = ath_hal_getslottime(ah); break; -@@ -11235,6 +11352,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl +@@ -11238,6 +11355,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl case ATH_COUNTRYCODE: ath_hal_getcountrycode(ah, &val); break; @@ -633,7 +633,7 @@ case ATH_MAXVAPS: val = ath_maxvaps; break; -@@ -11348,11 +11468,17 @@ static const ctl_table ath_sysctl_templa +@@ -11351,11 +11471,17 @@ static const ctl_table ath_sysctl_templa }, { .ctl_name = CTL_AUTO, .procname = "countrycode", @@ -652,7 +652,7 @@ .procname = "maxvaps", .mode = 0444, .proc_handler = ath_sysctl_halparam, -@@ -11360,7 +11486,7 @@ static const ctl_table ath_sysctl_templa +@@ -11363,7 +11489,7 @@ static const ctl_table ath_sysctl_templa }, { .ctl_name = CTL_AUTO, .procname = "regdomain", @@ -661,7 +661,7 @@ .proc_handler = ath_sysctl_halparam, .extra2 = (void *)ATH_REGDOMAIN, }, -@@ -11423,6 +11549,12 @@ static const ctl_table ath_sysctl_templa +@@ -11426,6 +11552,12 @@ static const ctl_table ath_sysctl_templa .extra2 = (void *)ATH_ACKRATE, }, { .ctl_name = CTL_AUTO, @@ -674,7 +674,7 @@ .procname = "rp", .mode = 0200, .proc_handler = ath_sysctl_halparam, -@@ -11663,13 +11795,6 @@ static ctl_table ath_static_sysctls[] = +@@ -11666,13 +11798,6 @@ static ctl_table ath_static_sysctls[] = }, #endif { .ctl_name = CTL_AUTO, @@ -688,7 +688,7 @@ .procname = "maxvaps", .mode = 0444, .data = &ath_maxvaps, -@@ -11677,13 +11802,6 @@ static ctl_table ath_static_sysctls[] = +@@ -11680,13 +11805,6 @@ static ctl_table ath_static_sysctls[] = .proc_handler = proc_dointvec }, { .ctl_name = CTL_AUTO, @@ -704,7 +704,7 @@ .data = &ath_xchanmode, --- a/ath/if_athvar.h +++ b/ath/if_athvar.h -@@ -688,16 +688,17 @@ struct ath_softc { +@@ -688,17 +688,18 @@ struct ath_softc { int8_t sc_ofdm_weak_det; /* OFDM weak frames detection, -1 == auto */ /* rate tables */ @@ -718,6 +718,7 @@ - const HAL_RATE_TABLE *sc_quarter_rates; /* quarter rate table */ HAL_OPMODE sc_opmode; /* current hal operating mode */ enum ieee80211_phymode sc_curmode; /* current phy mode */ + u_int sc_poweroffset; /* hardware power offset */ u_int16_t sc_curtxpow; /* current tx power limit */ u_int16_t sc_curaid; /* current association id */ HAL_CHANNEL sc_curchan; /* current h/w channel */ @@ -725,7 +726,7 @@ u_int8_t sc_curbssid[IEEE80211_ADDR_LEN]; u_int8_t sc_rixmap[256]; /* IEEE to h/w rate table ix */ struct { -@@ -808,6 +809,8 @@ struct ath_softc { +@@ -809,6 +810,8 @@ struct ath_softc { u_int32_t sc_dturbo_bw_turbo; /* bandwidth threshold */ #endif u_int sc_slottimeconf; /* manual override for slottime */ @@ -734,7 +735,7 @@ struct timer_list sc_dfs_excl_timer; /* mark expiration timer task */ struct timer_list sc_dfs_cac_timer; /* dfs wait timer */ -@@ -826,6 +829,7 @@ struct ath_softc { +@@ -827,6 +830,7 @@ struct ath_softc { int sc_rp_num; int sc_rp_min; HAL_BOOL (*sc_rp_analyse)(struct ath_softc *sc); @@ -742,7 +743,7 @@ struct ATH_TQ_STRUCT sc_rp_tq; int sc_rp_ignored; /* if set, we ignored all -@@ -941,6 +945,48 @@ int ar_device(int devid); +@@ -942,6 +946,48 @@ int ar_device(int devid); DEV_NAME(_v->iv_ic->ic_dev)) void ath_radar_detected(struct ath_softc *sc, const char* message); diff --git a/package/madwifi/patches/423-phyerr_handling.patch b/package/madwifi/patches/423-phyerr_handling.patch index b5059af625..7f3cbafe23 100644 --- a/package/madwifi/patches/423-phyerr_handling.patch +++ b/package/madwifi/patches/423-phyerr_handling.patch @@ -1,6 +1,6 @@ --- a/ath/if_ath.c +++ b/ath/if_ath.c -@@ -4390,13 +4390,12 @@ ath_key_update_end(struct ieee80211vap * +@@ -4391,13 +4391,12 @@ ath_key_update_end(struct ieee80211vap * static u_int32_t ath_calcrxfilter(struct ath_softc *sc) { @@ -15,7 +15,7 @@ HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; if (ic->ic_opmode != IEEE80211_M_STA) -@@ -4415,9 +4414,8 @@ ath_calcrxfilter(struct ath_softc *sc) +@@ -4416,9 +4415,8 @@ ath_calcrxfilter(struct ath_softc *sc) if (sc->sc_hasintmit && !sc->sc_needmib && ath_hal_getintmit(ah, NULL)) rfilt |= HAL_RX_FILTER_PHYERR; if (sc->sc_curchan.privFlags & CHANNEL_DFS) diff --git a/package/madwifi/patches/424-timing.patch b/package/madwifi/patches/424-timing.patch index b4c00bd64b..93b699694f 100644 --- a/package/madwifi/patches/424-timing.patch +++ b/package/madwifi/patches/424-timing.patch @@ -16,7 +16,7 @@ return 0; bad3: -@@ -2672,6 +2674,7 @@ ath_init(struct net_device *dev) +@@ -2673,6 +2675,7 @@ ath_init(struct net_device *dev) */ ath_chan_change(sc, ic->ic_curchan); ath_set_ack_bitrate(sc, sc->sc_ackrate); @@ -24,7 +24,7 @@ dev->flags |= IFF_RUNNING; /* we are ready to go */ ieee80211_start_running(ic); /* start all VAPs */ #ifdef ATH_TX99_DIAG -@@ -4483,17 +4486,52 @@ ath_mode_init(struct net_device *dev) +@@ -4484,17 +4487,52 @@ ath_mode_init(struct net_device *dev) * Set the slot time based on the current setting. */ static void @@ -82,7 +82,7 @@ sc->sc_updateslot = OK; } -@@ -4515,7 +4553,7 @@ ath_updateslot(struct net_device *dev) +@@ -4516,7 +4554,7 @@ ath_updateslot(struct net_device *dev) if (ic->ic_opmode == IEEE80211_M_HOSTAP) sc->sc_updateslot = UPDATE; else if (dev->flags & IFF_RUNNING) @@ -91,7 +91,7 @@ } #ifdef ATH_SUPERG_DYNTURBO -@@ -5359,7 +5397,7 @@ ath_beacon_send(struct ath_softc *sc, in +@@ -5360,7 +5398,7 @@ ath_beacon_send(struct ath_softc *sc, in sc->sc_updateslot = COMMIT; /* commit next beacon */ sc->sc_slotupdate = slot; } else if ((sc->sc_updateslot == COMMIT) && (sc->sc_slotupdate == slot)) @@ -100,7 +100,7 @@ if (bfaddr != 0) { /* -@@ -9429,7 +9467,8 @@ ath_set_coverageclass(struct ieee80211co +@@ -9430,7 +9468,8 @@ ath_set_coverageclass(struct ieee80211co { struct ath_softc *sc = ic->ic_dev->priv; @@ -110,7 +110,7 @@ return; } -@@ -10950,6 +10989,7 @@ enum { +@@ -10953,6 +10992,7 @@ enum { ATH_OFDM_WEAK_DET = 29, ATH_CHANBW = 30, ATH_OUTDOOR = 31, @@ -118,7 +118,7 @@ }; /* -@@ -11162,21 +11202,31 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl +@@ -11165,21 +11205,31 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl sc->sc_slottimeconf = val; else sc->sc_slottimeconf = 0; @@ -153,7 +153,7 @@ break; case ATH_SOFTLED: if (val != sc->sc_softled) { -@@ -11332,6 +11382,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl +@@ -11335,6 +11385,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl case ATH_CHANBW: val = sc->sc_chanbw ?: 20; break; @@ -163,7 +163,7 @@ case ATH_SLOTTIME: val = ath_hal_getslottime(ah); break; -@@ -11453,6 +11506,12 @@ static const ctl_table ath_sysctl_templa +@@ -11456,6 +11509,12 @@ static const ctl_table ath_sysctl_templa .extra2 = (void *)ATH_CTSTIMEOUT, }, { .ctl_name = CTL_AUTO, @@ -232,7 +232,7 @@ struct ath_softc { struct ieee80211com sc_ic; /* NB: must be first */ struct net_device *sc_dev; -@@ -838,6 +847,8 @@ struct ath_softc { +@@ -839,6 +848,8 @@ struct ath_softc { * detected radars */ u_int32_t sc_nexttbtt; u_int64_t sc_last_tsf; @@ -241,7 +241,7 @@ }; typedef void (*ath_callback) (struct ath_softc *); -@@ -945,49 +956,76 @@ int ar_device(int devid); +@@ -946,49 +957,76 @@ int ar_device(int devid); DEV_NAME(_v->iv_ic->ic_dev)) void ath_radar_detected(struct ath_softc *sc, const char* message); diff --git a/package/madwifi/patches/425-rc_rexmit.patch b/package/madwifi/patches/425-rc_rexmit.patch index 407e4b3c16..3098169e7d 100644 --- a/package/madwifi/patches/425-rc_rexmit.patch +++ b/package/madwifi/patches/425-rc_rexmit.patch @@ -20,7 +20,7 @@ struct ath_ratectrl { --- a/ath/if_ath.c +++ b/ath/if_ath.c -@@ -8634,6 +8634,8 @@ ath_tx_processq(struct ath_softc *sc, st +@@ -8635,6 +8635,8 @@ ath_tx_processq(struct ath_softc *sc, st ni = bf->bf_node; if (ni != NULL) { @@ -29,7 +29,7 @@ an = ATH_NODE(ni); if (ts->ts_status == 0) { u_int8_t txant = ts->ts_antenna; -@@ -8686,15 +8688,43 @@ ath_tx_processq(struct ath_softc *sc, st +@@ -8687,15 +8689,43 @@ ath_tx_processq(struct ath_softc *sc, st lr = ts->ts_longretry; sc->sc_stats.ast_tx_shortretry += sr; sc->sc_stats.ast_tx_longretry += lr; diff --git a/package/madwifi/patches/430-use_netdev_priv.patch b/package/madwifi/patches/430-use_netdev_priv.patch index 7c420ebd50..37a9b28146 100644 --- a/package/madwifi/patches/430-use_netdev_priv.patch +++ b/package/madwifi/patches/430-use_netdev_priv.patch @@ -20,7 +20,7 @@ if ((!rt) || (rate < 0) || (rate >= ARRAY_SIZE(sc->sc_hwmap))) --- a/ath/if_ath_ahb.c +++ b/ath/if_ath_ahb.c -@@ -268,7 +268,7 @@ static int ahb_wmac_probe(struct platfor +@@ -203,7 +203,7 @@ static int ahb_wmac_probe(struct platfor if (!dev) return -ENOMEM; @@ -29,7 +29,7 @@ sc->aps_sc.sc_dev = dev; dev->irq = platform_get_irq(pdev, 0); -@@ -365,7 +365,7 @@ init_ath_wmac(u_int16_t devid, u_int16_t +@@ -300,7 +300,7 @@ init_ath_wmac(u_int16_t devid, u_int16_t printk(KERN_ERR "%s: no memory for device state\n", dev_info); goto bad2; } @@ -76,7 +76,7 @@ ieee80211_vap_setup(ic, dev, name, opmode, flags, master); /* override with driver methods */ vap = &avp->av_vap; -@@ -1570,7 +1570,7 @@ static void +@@ -1571,7 +1571,7 @@ static void ath_vap_delete(struct ieee80211vap *vap) { struct net_device *dev = vap->iv_ic->ic_dev; @@ -85,7 +85,7 @@ struct ath_hal *ah = sc->sc_ah; struct ath_vap *avp = ATH_VAP(vap); int decrease = 1; -@@ -1672,7 +1672,7 @@ void +@@ -1673,7 +1673,7 @@ void ath_suspend(struct net_device *dev) { #ifdef AR_DEBUG @@ -94,7 +94,7 @@ #endif DPRINTF(sc, ATH_DEBUG_ANY, "flags=%x\n", dev->flags); -@@ -1683,7 +1683,7 @@ void +@@ -1684,7 +1684,7 @@ void ath_resume(struct net_device *dev) { #ifdef AR_DEBUG @@ -103,7 +103,7 @@ #endif DPRINTF(sc, ATH_DEBUG_ANY, "flags=%x\n", dev->flags); -@@ -2247,7 +2247,7 @@ ath_intr(int irq, void *dev_id, struct p +@@ -2248,7 +2248,7 @@ ath_intr(int irq, void *dev_id, struct p #endif { struct net_device *dev = dev_id; @@ -112,7 +112,7 @@ struct ath_hal *ah = sc->sc_ah; u_int64_t hw_tsf = 0; HAL_INT status; -@@ -2468,7 +2468,7 @@ static void +@@ -2469,7 +2469,7 @@ static void ath_fatal_tasklet(TQUEUE_ARG data) { struct net_device *dev = (struct net_device *)data; @@ -121,7 +121,7 @@ EPRINTF(sc, "Hardware error; resetting.\n"); ath_reset(dev); -@@ -2478,7 +2478,7 @@ static void +@@ -2479,7 +2479,7 @@ static void ath_rxorn_tasklet(TQUEUE_ARG data) { struct net_device *dev = (struct net_device *)data; @@ -130,7 +130,7 @@ EPRINTF(sc, "Receive FIFO overrun; resetting.\n"); ath_reset(dev); -@@ -2488,7 +2488,7 @@ static void +@@ -2489,7 +2489,7 @@ static void ath_bmiss_tasklet(TQUEUE_ARG data) { struct net_device *dev = (struct net_device *)data; @@ -139,7 +139,7 @@ if (time_before(jiffies, sc->sc_ic.ic_bmiss_guard)) { /* Beacon miss interrupt occured too short after last beacon -@@ -2567,7 +2567,7 @@ done: +@@ -2568,7 +2568,7 @@ done: static int ath_init(struct net_device *dev) { @@ -148,7 +148,7 @@ struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; HAL_STATUS status; -@@ -2692,7 +2692,7 @@ done: +@@ -2693,7 +2693,7 @@ done: static int ath_stop_locked(struct net_device *dev) { @@ -157,7 +157,7 @@ struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; -@@ -2777,7 +2777,7 @@ static void ath_set_beacon_cal(struct at +@@ -2778,7 +2778,7 @@ static void ath_set_beacon_cal(struct at static int ath_stop(struct net_device *dev) { @@ -166,7 +166,7 @@ int error; ATH_LOCK(sc); -@@ -2997,7 +2997,7 @@ ath_fetch_idle_time(struct ath_softc *sc +@@ -2998,7 +2998,7 @@ ath_fetch_idle_time(struct ath_softc *sc static int ath_reset(struct net_device *dev) { @@ -175,7 +175,7 @@ struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; struct ieee80211_channel *c; -@@ -3163,7 +3163,7 @@ dot11_to_ratecode(struct ath_softc *sc, +@@ -3164,7 +3164,7 @@ dot11_to_ratecode(struct ath_softc *sc, static int ath_tx_startraw(struct net_device *dev, struct ath_buf *bf, struct sk_buff *skb) { @@ -184,7 +184,7 @@ struct ath_hal *ah = sc->sc_ah; struct ieee80211_phy_params *ph = (struct ieee80211_phy_params *) (SKB_CB(skb) + 1); /* NB: SKB_CB casts to CB struct*. */ -@@ -3476,7 +3476,7 @@ _take_txbuf(struct ath_softc *sc, int fo +@@ -3477,7 +3477,7 @@ _take_txbuf(struct ath_softc *sc, int fo static int ath_hardstart(struct sk_buff *skb, struct net_device *dev) { @@ -193,7 +193,7 @@ struct ieee80211_node *ni = NULL; struct ath_buf *bf = NULL; ath_bufhead bf_head; -@@ -3791,7 +3791,7 @@ static int +@@ -3792,7 +3792,7 @@ static int ath_mgtstart(struct ieee80211com *ic, struct sk_buff *skb) { struct net_device *dev = ic->ic_dev; @@ -202,7 +202,7 @@ struct ath_buf *bf = NULL; int error; -@@ -4150,7 +4150,7 @@ static ieee80211_keyix_t +@@ -4151,7 +4151,7 @@ static ieee80211_keyix_t ath_key_alloc(struct ieee80211vap *vap, const struct ieee80211_key *k) { struct net_device *dev = vap->iv_ic->ic_dev; @@ -211,7 +211,7 @@ /* * Group key allocation must be handled specially for -@@ -4215,7 +4215,7 @@ ath_key_delete(struct ieee80211vap *vap, +@@ -4216,7 +4216,7 @@ ath_key_delete(struct ieee80211vap *vap, struct ieee80211_node *ninfo) { struct net_device *dev = vap->iv_ic->ic_dev; @@ -220,7 +220,7 @@ struct ath_hal *ah = sc->sc_ah; struct ieee80211_node *ni = NULL; const struct ieee80211_cipher *cip = k->wk_cipher; -@@ -4291,14 +4291,14 @@ ath_key_set(struct ieee80211vap *vap, co +@@ -4292,14 +4292,14 @@ ath_key_set(struct ieee80211vap *vap, co const u_int8_t mac[IEEE80211_ADDR_LEN]) { struct net_device *dev = vap->iv_ic->ic_dev; @@ -237,7 +237,7 @@ /* * XXX Using in_softirq is not right since we might -@@ -4316,7 +4316,7 @@ static void ath_poll_disable(struct net_ +@@ -4317,7 +4317,7 @@ static void ath_poll_disable(struct net_ static void ath_poll_enable(struct net_device *dev) { @@ -246,7 +246,7 @@ /* NB: see above */ if (!in_softirq()) { -@@ -4342,7 +4342,7 @@ ath_key_update_begin(struct ieee80211vap +@@ -4343,7 +4343,7 @@ ath_key_update_begin(struct ieee80211vap { struct net_device *dev = vap->iv_ic->ic_dev; #ifdef AR_DEBUG @@ -255,7 +255,7 @@ #endif DPRINTF(sc, ATH_DEBUG_KEYCACHE, "Begin\n"); -@@ -4360,7 +4360,7 @@ ath_key_update_end(struct ieee80211vap * +@@ -4361,7 +4361,7 @@ ath_key_update_end(struct ieee80211vap * { struct net_device *dev = vap->iv_ic->ic_dev; #ifdef AR_DEBUG @@ -264,7 +264,7 @@ #endif DPRINTF(sc, ATH_DEBUG_KEYCACHE, "End\n"); -@@ -4453,7 +4453,7 @@ ath_merge_mcast(struct ath_softc *sc, u_ +@@ -4454,7 +4454,7 @@ ath_merge_mcast(struct ath_softc *sc, u_ static void ath_mode_init(struct net_device *dev) { @@ -273,7 +273,7 @@ struct ath_hal *ah = sc->sc_ah; u_int32_t rfilt, mfilt[2]; -@@ -4539,7 +4539,7 @@ ath_set_timing(struct ath_softc *sc) +@@ -4540,7 +4540,7 @@ ath_set_timing(struct ath_softc *sc) static void ath_updateslot(struct net_device *dev) { @@ -282,7 +282,7 @@ struct ieee80211com *ic = &sc->sc_ic; /* -@@ -4569,7 +4569,7 @@ ath_beacon_dturbo_config(struct ieee8021 +@@ -4570,7 +4570,7 @@ ath_beacon_dturbo_config(struct ieee8021 (vap->iv_bss && (vap->iv_bss->ni_ath_flags & (IEEE80211_ATHC_TURBOP)) == \ (IEEE80211_ATHC_TURBOP)) struct ieee80211com *ic = vap->iv_ic; @@ -291,7 +291,7 @@ if (ic->ic_opmode == IEEE80211_M_HOSTAP && IS_CAPABLE(vap)) { -@@ -4617,7 +4617,7 @@ static void +@@ -4618,7 +4618,7 @@ static void ath_beacon_dturbo_update(struct ieee80211vap *vap, int *needmark, u_int8_t dtim) { struct ieee80211com *ic = vap->iv_ic; @@ -300,7 +300,7 @@ u_int32_t bss_traffic; if (sc->sc_ignore_ar) { -@@ -4758,7 +4758,7 @@ static void +@@ -4759,7 +4759,7 @@ static void ath_turbo_switch_mode(unsigned long data) { struct net_device *dev = (struct net_device *)data; @@ -309,7 +309,7 @@ struct ieee80211com *ic = &sc->sc_ic; unsigned int newflags; -@@ -5437,7 +5437,7 @@ static void +@@ -5438,7 +5438,7 @@ static void ath_bstuck_tasklet(TQUEUE_ARG data) { struct net_device *dev = (struct net_device *)data; @@ -318,7 +318,7 @@ /* * XXX:if the bmisscount is cleared while the * tasklet execution is pending, the following -@@ -5890,7 +5890,7 @@ ath_node_alloc_debug(struct ieee80211vap +@@ -5891,7 +5891,7 @@ ath_node_alloc_debug(struct ieee80211vap ath_node_alloc(struct ieee80211vap *vap) #endif { @@ -327,7 +327,7 @@ const size_t space = sizeof(struct ath_node) + sc->sc_rc->arc_space; struct ath_node *an = kmalloc(space, GFP_ATOMIC); if (an != NULL) { -@@ -5926,7 +5926,7 @@ ath_node_cleanup(struct ieee80211_node * +@@ -5927,7 +5927,7 @@ ath_node_cleanup(struct ieee80211_node * #endif { struct ieee80211com *ic = ni->ni_ic; @@ -336,7 +336,7 @@ struct ath_node *an = ATH_NODE(ni); struct ath_buf *bf; -@@ -5984,7 +5984,7 @@ ath_node_free_debug(struct ieee80211_nod +@@ -5985,7 +5985,7 @@ ath_node_free_debug(struct ieee80211_nod ath_node_free(struct ieee80211_node *ni) #endif { @@ -345,7 +345,7 @@ #ifdef IEEE80211_DEBUG_REFCNT sc->sc_node_free_debug(ni, func, line); -@@ -6032,7 +6032,7 @@ ath_node_move_data(const struct ieee8021 +@@ -6033,7 +6033,7 @@ ath_node_move_data(const struct ieee8021 #ifdef NOT_YET struct ath_txq *txq = NULL; struct ieee80211com *ic = ni->ni_ic; @@ -354,7 +354,7 @@ struct ath_buf *bf, *prev, *bf_tmp, *bf_tmp1; struct ath_hal *ah = sc->sc_ah; struct sk_buff *skb = NULL; -@@ -6552,7 +6552,7 @@ static void +@@ -6553,7 +6553,7 @@ static void ath_capture(struct net_device *dev, const struct ath_buf *bf, struct sk_buff *skb, u_int64_t tsf, unsigned int tx) { @@ -363,7 +363,7 @@ struct ieee80211com *ic = &sc->sc_ic; struct sk_buff *tskb = NULL; -@@ -6612,7 +6612,7 @@ static void +@@ -6613,7 +6613,7 @@ static void ath_recv_mgmt(struct ieee80211vap * vap, struct ieee80211_node *ni_or_null, struct sk_buff *skb, int subtype, int rssi, u_int64_t rtsf) { @@ -372,7 +372,7 @@ #ifdef AR_DEBUG struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data; #endif -@@ -6779,7 +6779,7 @@ ath_rx_poll(struct net_device *dev, int +@@ -6780,7 +6780,7 @@ ath_rx_poll(struct net_device *dev, int struct net_device *dev = sc->sc_dev; int rx_limit = budget; #else @@ -381,7 +381,7 @@ int rx_limit = min(dev->quota, *budget); #endif struct ath_buf *bf; -@@ -7301,7 +7301,7 @@ static void ath_grppoll_start(struct iee +@@ -7302,7 +7302,7 @@ static void ath_grppoll_start(struct iee struct sk_buff *skb = NULL; struct ath_buf *bf, *head = NULL; struct ieee80211com *ic = vap->iv_ic; @@ -390,7 +390,7 @@ struct ath_hal *ah = sc->sc_ah; u_int8_t rate; unsigned int ctsrate = 0, ctsduration = 0; -@@ -7519,7 +7519,7 @@ static void ath_grppoll_start(struct iee +@@ -7520,7 +7520,7 @@ static void ath_grppoll_start(struct iee static void ath_grppoll_stop(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; @@ -399,7 +399,7 @@ struct ath_hal *ah = sc->sc_ah; struct ath_txq *txq = &sc->sc_grpplq; struct ath_buf *bf; -@@ -7731,7 +7731,7 @@ ath_txq_update(struct ath_softc *sc, str +@@ -7732,7 +7732,7 @@ ath_txq_update(struct ath_softc *sc, str static int ath_wme_update(struct ieee80211com *ic) { @@ -408,7 +408,7 @@ if (sc->sc_uapsdq) ath_txq_update(sc, sc->sc_uapsdq, WME_AC_VO); -@@ -7750,7 +7750,7 @@ ath_uapsd_flush(struct ieee80211_node *n +@@ -7751,7 +7751,7 @@ ath_uapsd_flush(struct ieee80211_node *n { struct ath_node *an = ATH_NODE(ni); struct ath_buf *bf; @@ -417,7 +417,7 @@ struct ath_txq *txq; ATH_NODE_UAPSD_LOCK_IRQ(an); -@@ -7941,7 +7941,7 @@ ath_tx_start(struct net_device *dev, str +@@ -7942,7 +7942,7 @@ ath_tx_start(struct net_device *dev, str struct ath_buf *bf, struct sk_buff *skb, int nextfraglen) { #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -426,7 +426,7 @@ struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; struct ath_hal *ah = sc->sc_ah; -@@ -8850,7 +8850,7 @@ static void +@@ -8851,7 +8851,7 @@ static void ath_tx_tasklet_q0(TQUEUE_ARG data) { struct net_device *dev = (struct net_device *)data; @@ -435,7 +435,7 @@ unsigned long flags; process_tx_again: -@@ -8881,7 +8881,7 @@ static void +@@ -8882,7 +8882,7 @@ static void ath_tx_tasklet_q0123(TQUEUE_ARG data) { struct net_device *dev = (struct net_device *)data; @@ -444,7 +444,7 @@ unsigned long flags; process_tx_again: -@@ -8926,7 +8926,7 @@ static void +@@ -8927,7 +8927,7 @@ static void ath_tx_tasklet(TQUEUE_ARG data) { struct net_device *dev = (struct net_device *)data; @@ -453,7 +453,7 @@ unsigned int i; unsigned long flags; -@@ -8954,7 +8954,7 @@ process_tx_again: +@@ -8955,7 +8955,7 @@ process_tx_again: static void ath_tx_timeout(struct net_device *dev) { @@ -462,7 +462,7 @@ if (ath_chan_unavail(sc)) return; -@@ -9362,7 +9362,7 @@ static void +@@ -9363,7 +9363,7 @@ static void ath_calibrate(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; @@ -471,7 +471,7 @@ struct ath_hal *ah = sc->sc_ah; struct ieee80211com *ic = &sc->sc_ic; /* u_int32_t nchans; */ -@@ -9437,7 +9437,7 @@ static void +@@ -9438,7 +9438,7 @@ static void ath_scan_start(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -480,7 +480,7 @@ struct ath_hal *ah = sc->sc_ah; u_int32_t rfilt; -@@ -9457,7 +9457,7 @@ static void +@@ -9458,7 +9458,7 @@ static void ath_scan_end(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -489,7 +489,7 @@ struct ath_hal *ah = sc->sc_ah; u_int32_t rfilt; -@@ -9475,7 +9475,7 @@ static void +@@ -9476,7 +9476,7 @@ static void ath_set_channel(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -498,7 +498,7 @@ (void) ath_chan_set(sc, ic->ic_curchan); ic->ic_channoise = ath_hal_get_channel_noise(sc->sc_ah, &(sc->sc_curchan)); -@@ -9492,7 +9492,7 @@ ath_set_channel(struct ieee80211com *ic) +@@ -9493,7 +9493,7 @@ ath_set_channel(struct ieee80211com *ic) static void ath_set_coverageclass(struct ieee80211com *ic) { @@ -507,7 +507,7 @@ sc->sc_coverage = ic->ic_coverageclass * 3; ath_set_timing(sc); -@@ -9503,7 +9503,7 @@ ath_set_coverageclass(struct ieee80211co +@@ -9504,7 +9504,7 @@ ath_set_coverageclass(struct ieee80211co static u_int ath_mhz2ieee(struct ieee80211com *ic, u_int freq, u_int flags) { @@ -516,7 +516,7 @@ return (ath_hal_mhz2ieee(sc->sc_ah, freq, flags)); } -@@ -9518,7 +9518,7 @@ ath_newstate(struct ieee80211vap *vap, e +@@ -9519,7 +9519,7 @@ ath_newstate(struct ieee80211vap *vap, e struct ath_vap *avp = ATH_VAP(vap); struct ieee80211com *ic = vap->iv_ic; struct net_device *dev = ic->ic_dev; @@ -525,7 +525,7 @@ struct ath_hal *ah = sc->sc_ah; struct ieee80211_node *ni, *wds_ni; unsigned int i; -@@ -9958,7 +9958,7 @@ ath_setup_comp(struct ieee80211_node *ni +@@ -9959,7 +9959,7 @@ ath_setup_comp(struct ieee80211_node *ni { #define IEEE80211_KEY_XR (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV) struct ieee80211vap *vap = ni->ni_vap; @@ -534,7 +534,7 @@ struct ath_node *an = ATH_NODE(ni); ieee80211_keyix_t keyix; -@@ -10012,7 +10012,7 @@ static void +@@ -10013,7 +10013,7 @@ static void ath_setup_stationkey(struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; @@ -543,7 +543,7 @@ ieee80211_keyix_t keyix; keyix = ath_key_alloc(vap, &ni->ni_ucastkey); -@@ -10173,7 +10173,7 @@ ath_newassoc(struct ieee80211_node *ni, +@@ -10174,7 +10174,7 @@ ath_newassoc(struct ieee80211_node *ni, { struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; @@ -552,7 +552,7 @@ sc->sc_rc->ops->newassoc(sc, ATH_NODE(ni), isnew); ath_wprobe_node_join(ni->ni_vap, ni); -@@ -10204,7 +10204,7 @@ ath_newassoc(struct ieee80211_node *ni, +@@ -10205,7 +10205,7 @@ ath_newassoc(struct ieee80211_node *ni, static int ath_getchannels(struct net_device *dev) { @@ -561,7 +561,7 @@ struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; HAL_CHANNEL *chans; -@@ -10479,7 +10479,7 @@ ath_update_txpow(struct ath_softc *sc) +@@ -10482,7 +10482,7 @@ ath_update_txpow(struct ath_softc *sc) static int ath_xr_rate_setup(struct net_device *dev) { @@ -570,7 +570,7 @@ struct ath_hal *ah = sc->sc_ah; struct ieee80211com *ic = &sc->sc_ic; const HAL_RATE_TABLE *rt; -@@ -10510,7 +10510,7 @@ ath_xr_rate_setup(struct net_device *dev +@@ -10513,7 +10513,7 @@ ath_xr_rate_setup(struct net_device *dev static int ath_rate_setup(struct net_device *dev, u_int mode) { @@ -579,7 +579,7 @@ struct ath_hal *ah = sc->sc_ah; struct ieee80211com *ic = &sc->sc_ic; const HAL_RATE_TABLE *rt; -@@ -10757,7 +10757,7 @@ ath_printtxbuf(const struct ath_buf *bf, +@@ -10760,7 +10760,7 @@ ath_printtxbuf(const struct ath_buf *bf, { const struct ath_tx_status *ts = &bf->bf_dsstatus.ds_txstat; const struct ath_desc *ds = bf->bf_desc; @@ -588,7 +588,7 @@ u_int8_t status = done ? ts->ts_status : 0; DPRINTF(sc, ATH_DEBUG_ANY, -@@ -10784,7 +10784,7 @@ ath_printtxbuf(const struct ath_buf *bf, +@@ -10787,7 +10787,7 @@ ath_printtxbuf(const struct ath_buf *bf, static struct net_device_stats * ath_getstats(struct net_device *dev) { @@ -597,7 +597,7 @@ struct net_device_stats *stats = &sc->sc_devstats; /* update according to private statistics */ -@@ -10807,7 +10807,7 @@ ath_getstats(struct net_device *dev) +@@ -10810,7 +10810,7 @@ ath_getstats(struct net_device *dev) static int ath_set_mac_address(struct net_device *dev, void *addr) { @@ -606,7 +606,7 @@ struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; struct sockaddr *mac = addr; -@@ -10836,7 +10836,7 @@ ath_set_mac_address(struct net_device *d +@@ -10839,7 +10839,7 @@ ath_set_mac_address(struct net_device *d static int ath_change_mtu(struct net_device *dev, int mtu) { @@ -615,7 +615,7 @@ int error = 0; if (!(ATH_MIN_MTU < mtu && mtu <= ATH_MAX_MTU)) { -@@ -10923,7 +10923,7 @@ bad: +@@ -10926,7 +10926,7 @@ bad: static int ath_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { @@ -624,7 +624,7 @@ struct ieee80211com *ic = &sc->sc_ic; int error; -@@ -11804,7 +11804,7 @@ static void +@@ -11807,7 +11807,7 @@ static void ath_announce(struct net_device *dev) { #define HAL_MODE_DUALBAND (HAL_MODE_11A|HAL_MODE_11B) @@ -633,7 +633,7 @@ struct ath_hal *ah = sc->sc_ah; u_int modes, cc; static const int MLEN = 1024; -@@ -11991,7 +11991,7 @@ static void +@@ -11994,7 +11994,7 @@ static void txcont_configure_radio(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -642,7 +642,7 @@ struct ath_hal *ah = sc->sc_ah; struct ieee80211_wme_state *wme = &ic->ic_wme; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); -@@ -12265,7 +12265,7 @@ static void +@@ -12268,7 +12268,7 @@ static void txcont_queue_packet(struct ieee80211com *ic, struct ath_txq* txq) { struct net_device *dev = ic->ic_dev; @@ -651,7 +651,7 @@ struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf = NULL; struct sk_buff *skb = NULL; -@@ -12398,7 +12398,7 @@ static void +@@ -12401,7 +12401,7 @@ static void txcont_on(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -660,7 +660,7 @@ if (IFF_RUNNING != (ic->ic_dev->flags & IFF_RUNNING)) { EPRINTF(sc, "Cannot enable txcont when" -@@ -12419,7 +12419,7 @@ static void +@@ -12422,7 +12422,7 @@ static void txcont_off(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -669,7 +669,7 @@ if (TAILQ_FIRST(&ic->ic_vaps)->iv_opmode != IEEE80211_M_WDS) sc->sc_beacons = 1; -@@ -12433,7 +12433,7 @@ static int +@@ -12436,7 +12436,7 @@ static int ath_get_dfs_testmode(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -678,7 +678,7 @@ return sc->sc_dfs_testmode; } -@@ -12460,7 +12460,7 @@ static void +@@ -12463,7 +12463,7 @@ static void ath_set_dfs_testmode(struct ieee80211com *ic, int value) { struct net_device *dev = ic->ic_dev; @@ -687,7 +687,7 @@ sc->sc_dfs_testmode = !!value; } -@@ -12470,7 +12470,7 @@ static int +@@ -12473,7 +12473,7 @@ static int ath_get_txcont(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -696,7 +696,7 @@ return sc->sc_txcont; } -@@ -12488,7 +12488,7 @@ static void +@@ -12491,7 +12491,7 @@ static void ath_set_txcont_power(struct ieee80211com *ic, unsigned int txpower) { struct net_device *dev = ic->ic_dev; @@ -705,7 +705,7 @@ int new_txcont_power = txpower > IEEE80211_TXPOWER_MAX ? IEEE80211_TXPOWER_MAX : txpower; if (sc->sc_txcont_power != new_txcont_power) { -@@ -12506,7 +12506,7 @@ static int +@@ -12509,7 +12509,7 @@ static int ath_get_txcont_power(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -714,7 +714,7 @@ /* VERY conservative default */ return sc->sc_txcont_power ? sc->sc_txcont_power : 0; } -@@ -12516,7 +12516,7 @@ ath_get_txcont_power(struct ieee80211com +@@ -12519,7 +12519,7 @@ ath_get_txcont_power(struct ieee80211com ath_set_txcont_rate(struct ieee80211com *ic, unsigned int new_rate) { struct net_device *dev = ic->ic_dev; @@ -723,7 +723,7 @@ if (sc->sc_txcont_rate != new_rate) { /* NOTE: This value is sanity checked and dropped down to * closest rate in txcont_on. */ -@@ -12533,7 +12533,7 @@ ath_set_txcont_rate(struct ieee80211com +@@ -12536,7 +12536,7 @@ ath_set_txcont_rate(struct ieee80211com ath_get_txcont_rate(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -732,7 +732,7 @@ return sc->sc_txcont_rate ? sc->sc_txcont_rate : 0; } -@@ -12543,7 +12543,7 @@ static void +@@ -12546,7 +12546,7 @@ static void ath_set_dfs_cac_time(struct ieee80211com *ic, unsigned int time_s) { struct net_device *dev = ic->ic_dev; @@ -741,7 +741,7 @@ sc->sc_dfs_cac_period = time_s; } -@@ -12553,7 +12553,7 @@ static unsigned int +@@ -12556,7 +12556,7 @@ static unsigned int ath_get_dfs_cac_time(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -750,7 +750,7 @@ return sc->sc_dfs_cac_period; } -@@ -12573,7 +12573,7 @@ static void +@@ -12576,7 +12576,7 @@ static void ath_set_dfs_excl_period(struct ieee80211com *ic, unsigned int time_s) { struct net_device *dev = ic->ic_dev; @@ -759,7 +759,7 @@ sc->sc_dfs_excl_period = time_s; } -@@ -12582,7 +12582,7 @@ static unsigned int +@@ -12585,7 +12585,7 @@ static unsigned int ath_get_dfs_excl_period(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -768,7 +768,7 @@ return sc->sc_dfs_excl_period; } -@@ -12594,7 +12594,7 @@ static unsigned int +@@ -12597,7 +12597,7 @@ static unsigned int ath_test_radar(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -777,7 +777,7 @@ if ((ic->ic_flags & IEEE80211_F_DOTH) && (sc->sc_curchan.privFlags & CHANNEL_DFS)) ath_radar_detected(sc, "ath_test_radar from user space"); else -@@ -12610,7 +12610,7 @@ static unsigned int +@@ -12613,7 +12613,7 @@ static unsigned int ath_dump_hal_map(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -786,7 +786,7 @@ ath_hal_dump_map(sc->sc_ah); return 0; } -@@ -12718,7 +12718,7 @@ ath_rcv_dev_event(struct notifier_block +@@ -12721,7 +12721,7 @@ ath_rcv_dev_event(struct notifier_block void *ptr) { struct net_device *dev = (struct net_device *)ptr; @@ -795,7 +795,7 @@ if (!dev || !sc || dev->open != &ath_init) return 0; -@@ -13453,7 +13453,7 @@ static unsigned int +@@ -13456,7 +13456,7 @@ static unsigned int ath_read_register(struct ieee80211com *ic, unsigned int address, unsigned int* value) { @@ -804,7 +804,7 @@ if (address >= MAX_REGISTER_ADDRESS) { IPRINTF(sc, "Illegal Atheros register access " "attempted: 0x%04x >= 0x%04x\n", -@@ -13483,7 +13483,7 @@ static unsigned int +@@ -13486,7 +13486,7 @@ static unsigned int ath_write_register(struct ieee80211com *ic, unsigned int address, unsigned int value) { @@ -813,7 +813,7 @@ if (address >= MAX_REGISTER_ADDRESS) { IPRINTF(sc, "Illegal Atheros register access " "attempted: 0x%04x >= 0x%04x\n", -@@ -13511,7 +13511,7 @@ static void +@@ -13514,7 +13514,7 @@ static void ath_registers_dump(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -822,7 +822,7 @@ ath_ar5212_registers_dump(sc); } #endif /* #ifdef ATH_REVERSE_ENGINEERING */ -@@ -13523,7 +13523,7 @@ static void +@@ -13526,7 +13526,7 @@ static void ath_registers_mark(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -831,7 +831,7 @@ ath_ar5212_registers_mark(sc); } #endif /* #ifdef ATH_REVERSE_ENGINEERING */ -@@ -13535,7 +13535,7 @@ static void +@@ -13538,7 +13538,7 @@ static void ath_registers_dump_delta(struct ieee80211com *ic) { struct net_device *dev = ic->ic_dev; @@ -842,7 +842,7 @@ #endif /* #ifdef ATH_REVERSE_ENGINEERING */ --- a/ath/if_ath_pci.c +++ b/ath/if_ath_pci.c -@@ -199,7 +199,7 @@ ath_pci_probe(struct pci_dev *pdev, cons +@@ -226,7 +226,7 @@ ath_pci_probe(struct pci_dev *pdev, cons printk(KERN_ERR "%s: no memory for device state\n", dev_info); goto bad2; } @@ -851,7 +851,7 @@ sc->aps_sc.sc_dev = dev; sc->aps_sc.sc_iobase = mem; -@@ -278,7 +278,7 @@ static void +@@ -309,7 +309,7 @@ static void ath_pci_remove(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -860,7 +860,7 @@ ath_detach(dev); if (dev->irq) -@@ -296,7 +296,7 @@ ath_pci_suspend(struct pci_dev *pdev, pm +@@ -327,7 +327,7 @@ ath_pci_suspend(struct pci_dev *pdev, pm struct net_device *dev = pci_get_drvdata(pdev); ath_suspend(dev); @@ -869,7 +869,7 @@ pci_disable_device(pdev); return pci_set_power_state(pdev, PCI_D3hot); } -@@ -313,7 +313,7 @@ ath_pci_resume(struct pci_dev *pdev) +@@ -344,7 +344,7 @@ ath_pci_resume(struct pci_dev *pdev) return err; /* XXX - Should this return nonzero on fail? */ diff --git a/package/madwifi/patches/431-compile_fixes.patch b/package/madwifi/patches/431-compile_fixes.patch index 16485cb8e5..c4d89b021a 100644 --- a/package/madwifi/patches/431-compile_fixes.patch +++ b/package/madwifi/patches/431-compile_fixes.patch @@ -1,6 +1,6 @@ --- a/ath/if_ath.c +++ b/ath/if_ath.c -@@ -2387,7 +2387,9 @@ ath_intr(int irq, void *dev_id, struct p +@@ -2388,7 +2388,9 @@ ath_intr(int irq, void *dev_id, struct p if (status & (HAL_INT_RX | HAL_INT_RXPHY)) { ath_uapsd_processtriggers(sc, hw_tsf); sc->sc_isr &= ~HAL_INT_RX; @@ -11,7 +11,7 @@ if (netif_rx_schedule_prep(dev, &sc->sc_napi)) #else if (netif_rx_schedule_prep(dev)) -@@ -2395,7 +2397,9 @@ ath_intr(int irq, void *dev_id, struct p +@@ -2396,7 +2398,9 @@ ath_intr(int irq, void *dev_id, struct p { sc->sc_imask &= ~HAL_INT_RX; ath_hal_intrset(ah, sc->sc_imask); @@ -22,7 +22,7 @@ __netif_rx_schedule(dev, &sc->sc_napi); #else __netif_rx_schedule(dev); -@@ -7131,7 +7135,9 @@ rx_next: +@@ -7132,7 +7136,9 @@ rx_next: local_irq_restore(flags); } diff --git a/package/madwifi/patches/432-backport_oops.patch b/package/madwifi/patches/432-backport_oops.patch deleted file mode 100644 index 5bcfa08093..0000000000 --- a/package/madwifi/patches/432-backport_oops.patch +++ /dev/null @@ -1,127 +0,0 @@ -Convert to net_device_ops for Linux 2.6.29+ -http://madwifi-project.org/changeset/4005 ---- a/ath/if_ath.c -+++ b/ath/if_ath.c -@@ -566,6 +566,20 @@ static inline int rate_factor(int mode) - - /* Initialize ath_softc structure */ - -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) -+static const struct net_device_ops ath_netdev_ops = { -+ .ndo_open = ath_init, -+ .ndo_stop = ath_stop, -+ .ndo_start_xmit = ath_hardstart, -+ .ndo_tx_timeout = ath_tx_timeout, -+ .ndo_set_multicast_list = ath_mode_init, -+ .ndo_do_ioctl = ath_ioctl, -+ .ndo_get_stats = ath_getstats, -+ .ndo_set_mac_address = ath_set_mac_address, -+ .ndo_change_mtu = ath_change_mtu, -+}; -+#endif -+ - int - ath_attach(u_int16_t devid, struct net_device *dev, HAL_BUS_TAG tag) - { -@@ -865,16 +879,20 @@ ath_attach(u_int16_t devid, struct net_d - } - - /* NB: ether_setup is done by bus-specific code */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) - dev->open = ath_init; - dev->stop = ath_stop; - dev->hard_start_xmit = ath_hardstart; - dev->tx_timeout = ath_tx_timeout; -- dev->watchdog_timeo = 5 * HZ; - dev->set_multicast_list = ath_mode_init; - dev->do_ioctl = ath_ioctl; - dev->get_stats = ath_getstats; - dev->set_mac_address = ath_set_mac_address; - dev->change_mtu = ath_change_mtu; -+#else -+ dev->netdev_ops = &ath_netdev_ops; -+#endif -+ dev->watchdog_timeo = 5 * HZ; - dev->tx_queue_len = ATH_TXBUF - ATH_TXBUF_MGT_RESERVED; - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) - netif_napi_add(dev, &sc->sc_napi, ath_rx_poll, 64); -@@ -12726,8 +12744,13 @@ ath_rcv_dev_event(struct notifier_block - struct net_device *dev = (struct net_device *)ptr; - struct ath_softc *sc = (struct ath_softc *)netdev_priv(dev); - -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) - if (!dev || !sc || dev->open != &ath_init) - return 0; -+#else -+ if (!dev || !sc || dev->netdev_ops->ndo_open != &ath_init) -+ return 0; -+#endif - - switch (event) { - case NETDEV_CHANGENAME: ---- a/net80211/ieee80211.c -+++ b/net80211/ieee80211.c -@@ -450,6 +450,17 @@ ieee80211_ifdetach(struct ieee80211com * - } - EXPORT_SYMBOL(ieee80211_ifdetach); - -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) -+static const struct net_device_ops ieee80211_netdev_ops = { -+ .ndo_get_stats = ieee80211_getstats, -+ .ndo_open = ieee80211_open, -+ .ndo_stop = ieee80211_stop, -+ .ndo_start_xmit = ieee80211_hardstart, -+ .ndo_set_multicast_list = ieee80211_set_multicast_list, -+ .ndo_change_mtu = ieee80211_change_mtu, -+}; -+#endif -+ - int - ieee80211_vap_setup(struct ieee80211com *ic, struct net_device *dev, - const char *name, int opmode, int flags, struct ieee80211vap *master) -@@ -470,12 +481,16 @@ ieee80211_vap_setup(struct ieee80211com - } else - strncpy(dev->name, name, sizeof(dev->name)); - } -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) - - dev->get_stats = ieee80211_getstats; - dev->open = ieee80211_open; - dev->stop = ieee80211_stop; - dev->hard_start_xmit = ieee80211_hardstart; - dev->set_multicast_list = ieee80211_set_multicast_list; -+#else -+ dev->netdev_ops = &ieee80211_netdev_ops; -+#endif - #if 0 - dev->set_mac_address = ieee80211_set_mac_address; - #endif -@@ -1823,7 +1838,11 @@ ieee80211_set_multicast_list(struct net_ - IEEE80211_UNLOCK_IRQ(ic); - - /* XXX: Merge multicast list into parent device */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) - parent->set_multicast_list(ic->ic_dev); -+#else -+ parent->netdev_ops->ndo_set_multicast_list(ic->ic_dev); -+#endif - } - - void ---- a/net80211/ieee80211_linux.c -+++ b/net80211/ieee80211_linux.c -@@ -984,8 +984,14 @@ ieee80211_rcv_dev_event(struct notifier_ - void *ptr) - { - struct net_device *dev = (struct net_device *) ptr; -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) - if (!dev || dev->open != &ieee80211_open) - return 0; -+#else -+ if (!dev || dev->netdev_ops->ndo_open != &ieee80211_open) -+ return 0; -+#endif - - switch (event) { - case NETDEV_CHANGENAME: diff --git a/package/madwifi/patches/432-netdev_ops.patch b/package/madwifi/patches/432-netdev_ops.patch new file mode 100644 index 0000000000..c3f8ae6846 --- /dev/null +++ b/package/madwifi/patches/432-netdev_ops.patch @@ -0,0 +1,180 @@ +Convert to net_device_ops for Linux 2.6.29+ +http://madwifi-project.org/changeset/4005 +--- a/ath/if_ath.c ++++ b/ath/if_ath.c +@@ -566,6 +566,20 @@ static inline int rate_factor(int mode) + + /* Initialize ath_softc structure */ + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) ++static const struct net_device_ops ath_netdev_ops = { ++ .ndo_open = ath_init, ++ .ndo_stop = ath_stop, ++ .ndo_start_xmit = ath_hardstart, ++ .ndo_tx_timeout = ath_tx_timeout, ++ .ndo_set_multicast_list = ath_mode_init, ++ .ndo_do_ioctl = ath_ioctl, ++ .ndo_get_stats = ath_getstats, ++ .ndo_set_mac_address = ath_set_mac_address, ++ .ndo_change_mtu = ath_change_mtu, ++}; ++#endif ++ + int + ath_attach(u_int16_t devid, struct net_device *dev, HAL_BUS_TAG tag) + { +@@ -865,16 +879,20 @@ ath_attach(u_int16_t devid, struct net_d + } + + /* NB: ether_setup is done by bus-specific code */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + dev->open = ath_init; + dev->stop = ath_stop; + dev->hard_start_xmit = ath_hardstart; + dev->tx_timeout = ath_tx_timeout; +- dev->watchdog_timeo = 5 * HZ; + dev->set_multicast_list = ath_mode_init; + dev->do_ioctl = ath_ioctl; + dev->get_stats = ath_getstats; + dev->set_mac_address = ath_set_mac_address; + dev->change_mtu = ath_change_mtu; ++#else ++ dev->netdev_ops = &ath_netdev_ops; ++#endif ++ dev->watchdog_timeo = 5 * HZ; + dev->tx_queue_len = ATH_TXBUF - ATH_TXBUF_MGT_RESERVED; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + netif_napi_add(dev, &sc->sc_napi, ath_rx_poll, 64); +@@ -1257,7 +1275,6 @@ ath_detach(struct net_device *dev) + ath_dynamic_sysctl_unregister(sc); + ATH_LOCK_DESTROY(sc); + ATH_HAL_LOCK_DESTROY(sc); +- dev->stop = NULL; /* prevent calling ath_stop again */ + unregister_netdev(dev); + return 0; + } +@@ -12729,8 +12746,13 @@ ath_rcv_dev_event(struct notifier_block + struct net_device *dev = (struct net_device *)ptr; + struct ath_softc *sc = (struct ath_softc *)netdev_priv(dev); + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + if (!dev || !sc || dev->open != &ath_init) + return 0; ++#else ++ if (!dev || !sc || dev->netdev_ops->ndo_open != &ath_init) ++ return 0; ++#endif + + switch (event) { + case NETDEV_CHANGENAME: +--- a/net80211/ieee80211.c ++++ b/net80211/ieee80211.c +@@ -450,6 +450,18 @@ ieee80211_ifdetach(struct ieee80211com * + } + EXPORT_SYMBOL(ieee80211_ifdetach); + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) ++static const struct net_device_ops ieee80211_netdev_ops = { ++ .ndo_get_stats = ieee80211_getstats, ++ .ndo_open = ieee80211_open, ++ .ndo_stop = ieee80211_stop, ++ .ndo_start_xmit = ieee80211_hardstart, ++ .ndo_set_multicast_list = ieee80211_set_multicast_list, ++ .ndo_change_mtu = ieee80211_change_mtu, ++ .ndo_do_ioctl = ieee80211_ioctl, ++}; ++#endif ++ + int + ieee80211_vap_setup(struct ieee80211com *ic, struct net_device *dev, + const char *name, int opmode, int flags, struct ieee80211vap *master) +@@ -470,12 +482,17 @@ ieee80211_vap_setup(struct ieee80211com + } else + strncpy(dev->name, name, sizeof(dev->name)); + } ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + + dev->get_stats = ieee80211_getstats; + dev->open = ieee80211_open; + dev->stop = ieee80211_stop; + dev->hard_start_xmit = ieee80211_hardstart; + dev->set_multicast_list = ieee80211_set_multicast_list; ++ dev->do_ioctl = ieee80211_ioctl; ++#else ++ dev->netdev_ops = &ieee80211_netdev_ops; ++#endif + #if 0 + dev->set_mac_address = ieee80211_set_mac_address; + #endif +@@ -1823,7 +1840,11 @@ ieee80211_set_multicast_list(struct net_ + IEEE80211_UNLOCK_IRQ(ic); + + /* XXX: Merge multicast list into parent device */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + parent->set_multicast_list(ic->ic_dev); ++#else ++ parent->netdev_ops->ndo_set_multicast_list(ic->ic_dev); ++#endif + } + + void +--- a/net80211/ieee80211_linux.c ++++ b/net80211/ieee80211_linux.c +@@ -984,8 +984,14 @@ ieee80211_rcv_dev_event(struct notifier_ + void *ptr) + { + struct net_device *dev = (struct net_device *) ptr; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + if (!dev || dev->open != &ieee80211_open) + return 0; ++#else ++ if (!dev || dev->netdev_ops->ndo_open != &ieee80211_open) ++ return 0; ++#endif + + switch (event) { + case NETDEV_CHANGENAME: +--- a/net80211/ieee80211_var.h ++++ b/net80211/ieee80211_var.h +@@ -740,6 +740,7 @@ void ieee80211_build_sc_ie(struct ieee80 + void ieee80211_dfs_action(struct ieee80211com *); + void ieee80211_expire_channel_excl_restrictions(struct ieee80211com *); + void ieee80211_setpuregbasicrates(struct ieee80211_rateset *rs); ++int ieee80211_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); + + /* + * Iterate through ic_channels to enumerate all distinct ic_ieee channel numbers. +--- a/net80211/ieee80211_wireless.c ++++ b/net80211/ieee80211_wireless.c +@@ -5945,7 +5945,7 @@ static struct iw_handler_def ieee80211_i + /* + * Handle private ioctl requests. + */ +-static int ++int + ieee80211_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) + { + struct ieee80211vap *vap = netdev_priv(dev); +@@ -6035,7 +6035,6 @@ ieee80211_ioctl_vattach(struct ieee80211 + { + struct net_device *dev = vap->iv_dev; + +- dev->do_ioctl = ieee80211_ioctl; + #if IW_HANDLER_VERSION < 7 + dev->get_wireless_stats = ieee80211_iw_getstats; + #endif +--- a/net80211/ieee80211_input.c ++++ b/net80211/ieee80211_input.c +@@ -1185,7 +1185,11 @@ ieee80211_deliver_data(struct ieee80211_ + skb1->protocol = __constant_htons(ETH_P_802_2); + /* XXX insert vlan tag before queue it? */ + ni_tmp = SKB_CB(skb1)->ni; /* remember node so we can free it */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + ret = dev->hard_start_xmit(skb1, dev); ++#else ++ ret = dev->netdev_ops->ndo_start_xmit(skb1, dev); ++#endif + + if (ret == NETDEV_TX_BUSY) + ieee80211_dev_kfree_skb(&skb1); diff --git a/package/madwifi/patches/434-name-alloc-fix.patch b/package/madwifi/patches/434-name-alloc-fix.patch index b3bb30067a..ab277630de 100644 --- a/package/madwifi/patches/434-name-alloc-fix.patch +++ b/package/madwifi/patches/434-name-alloc-fix.patch @@ -1,7 +1,6 @@ -diff -ur madwifi-trunk-r3314/ath/if_ath_ahb.c madwifi-trunk-r3314.patched/ath/if_ath_ahb.c ---- madwifi-trunk-r3314/ath/if_ath_ahb.c 2009-05-17 22:16:05.000000000 +0300 -+++ madwifi-trunk-r3314.patched/ath/if_ath_ahb.c 2009-05-17 22:15:47.000000000 +0300 -@@ -376,6 +376,11 @@ +--- a/ath/if_ath_ahb.c ++++ b/ath/if_ath_ahb.c +@@ -311,6 +311,11 @@ init_ath_wmac(u_int16_t devid, u_int16_t SET_MODULE_OWNER(dev); sclist[wlanNum] = sc; @@ -13,10 +12,9 @@ diff -ur madwifi-trunk-r3314/ath/if_ath_ahb.c madwifi-trunk-r3314.patched/ath/if switch (wlanNum) { case AR531X_WLAN0_NUM: if (((devid & AR5315_REV_MAJ_M) == AR5315_REV_MAJ) || -diff -ur madwifi-trunk-r3314/ath/if_ath_pci.c madwifi-trunk-r3314.patched/ath/if_ath_pci.c ---- madwifi-trunk-r3314/ath/if_ath_pci.c 2009-05-17 22:16:05.000000000 +0300 -+++ madwifi-trunk-r3314.patched/ath/if_ath_pci.c 2009-05-17 22:15:47.000000000 +0300 -@@ -209,6 +209,11 @@ +--- a/ath/if_ath_pci.c ++++ b/ath/if_ath_pci.c +@@ -236,6 +236,11 @@ ath_pci_probe(struct pci_dev *pdev, cons */ sc->aps_sc.sc_invalid = 1; diff --git a/package/madwifi/patches/436-injection_checks.patch b/package/madwifi/patches/436-injection_checks.patch new file mode 100644 index 0000000000..7bdd82c0f9 --- /dev/null +++ b/package/madwifi/patches/436-injection_checks.patch @@ -0,0 +1,26 @@ +--- a/ath/if_ath.c ++++ b/ath/if_ath.c +@@ -3199,7 +3199,13 @@ ath_tx_startraw(struct net_device *dev, + struct ieee80211_frame *wh; + + wh = (struct ieee80211_frame *)skb->data; ++ + try0 = ph->try0; ++ if (!try0) ++ try0 = 1; ++ else if (try0 > 11) ++ try0 = 11; ++ + rt = sc->sc_currates; + txrate = dot11_to_ratecode(sc, rt, ph->rate0); + power = ph->power > 63 ? 63 : ph->power; +@@ -3224,7 +3230,8 @@ ath_tx_startraw(struct net_device *dev, + rt = sc->sc_currates; + KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); + +- if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { ++ if (((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) || ++ IEEE80211_IS_MULTICAST(wh->i_addr1)) { + flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */ + sc->sc_stats.ast_tx_noack++; + try0 = 1; diff --git a/package/madwifi/patches/437-sysctl_cleanup.patch b/package/madwifi/patches/437-sysctl_cleanup.patch new file mode 100644 index 0000000000..cd8152bf24 --- /dev/null +++ b/package/madwifi/patches/437-sysctl_cleanup.patch @@ -0,0 +1,73 @@ +--- a/ath/if_ath.c ++++ b/ath/if_ath.c +@@ -11018,38 +11018,38 @@ enum { + * mirrored in /proc/sys. + */ + enum { +- ATH_SLOTTIME = 1, +- ATH_ACKTIMEOUT = 2, +- ATH_CTSTIMEOUT = 3, +- ATH_SOFTLED = 4, +- ATH_LEDPIN = 5, +- ATH_COUNTRYCODE = 6, +- ATH_REGDOMAIN = 7, +- ATH_DEBUG = 8, +- ATH_TXANTENNA = 9, +- ATH_RXANTENNA = 10, +- ATH_DIVERSITY = 11, +- ATH_TXINTRPERIOD = 12, +- ATH_FFTXQMIN = 13, +- ATH_XR_POLL_PERIOD = 14, +- ATH_XR_POLL_COUNT = 15, +- ATH_ACKRATE = 16, +- ATH_RP = 17, +- ATH_RP_PRINT = 18, +- ATH_RP_PRINT_ALL = 19, +- ATH_RP_PRINT_MEM = 20, +- ATH_RP_PRINT_MEM_ALL = 21, +- ATH_RP_FLUSH = 22, +- ATH_PANIC = 23, +- ATH_RP_IGNORED = 24, +- ATH_RADAR_IGNORED = 25, +- ATH_MAXVAPS = 26, +- ATH_INTMIT = 27, +- ATH_NOISE_IMMUNITY = 28, +- ATH_OFDM_WEAK_DET = 29, +- ATH_CHANBW = 30, +- ATH_OUTDOOR = 31, +- ATH_DISTANCE = 32, ++ ATH_SLOTTIME, ++ ATH_ACKTIMEOUT, ++ ATH_CTSTIMEOUT, ++ ATH_SOFTLED, ++ ATH_LEDPIN, ++ ATH_COUNTRYCODE, ++ ATH_REGDOMAIN, ++ ATH_DEBUG, ++ ATH_TXANTENNA, ++ ATH_RXANTENNA, ++ ATH_DIVERSITY, ++ ATH_TXINTRPERIOD, ++ ATH_FFTXQMIN, ++ ATH_XR_POLL_PERIOD, ++ ATH_XR_POLL_COUNT, ++ ATH_ACKRATE, ++ ATH_RP, ++ ATH_RP_PRINT, ++ ATH_RP_PRINT_ALL, ++ ATH_RP_PRINT_MEM, ++ ATH_RP_PRINT_MEM_ALL, ++ ATH_RP_FLUSH, ++ ATH_PANIC, ++ ATH_RP_IGNORED, ++ ATH_RADAR_IGNORED, ++ ATH_MAXVAPS, ++ ATH_INTMIT, ++ ATH_NOISE_IMMUNITY, ++ ATH_OFDM_WEAK_DET, ++ ATH_CHANBW, ++ ATH_OUTDOOR, ++ ATH_DISTANCE, + }; + + /* diff --git a/package/madwifi/patches/438-poweroffset_sysctl.patch b/package/madwifi/patches/438-poweroffset_sysctl.patch new file mode 100644 index 0000000000..9d5e71f0fc --- /dev/null +++ b/package/madwifi/patches/438-poweroffset_sysctl.patch @@ -0,0 +1,59 @@ +--- a/ath/if_ath.c ++++ b/ath/if_ath.c +@@ -10473,11 +10473,11 @@ set_node_txpower(void *arg, struct ieee8 + * XXX: this function needs some locking to avoid being called + * twice/interrupted. Returns the value actually stored. */ + static u_int32_t +-ath_set_clamped_maxtxpower(struct ath_softc *sc, +- u_int32_t new_clamped_maxtxpower) ++ath_set_clamped_maxtxpower(struct ath_softc *sc, u_int32_t new_txpwr) + { +- new_clamped_maxtxpower -= sc->sc_poweroffset; +- (void)ath_hal_settxpowlimit(sc->sc_ah, new_clamped_maxtxpower); ++ new_txpwr = ((new_txpwr < sc->sc_poweroffset) ? 0 : ++ new_txpwr - sc->sc_poweroffset); ++ (void)ath_hal_settxpowlimit(sc->sc_ah, new_txpwr); + return ath_get_clamped_maxtxpower(sc); + } + +@@ -11028,6 +11028,7 @@ enum { + ATH_DEBUG, + ATH_TXANTENNA, + ATH_RXANTENNA, ++ ATH_POWEROFFSET, + ATH_DIVERSITY, + ATH_TXINTRPERIOD, + ATH_FFTXQMIN, +@@ -11308,6 +11309,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl + ath_debug_global = (val & ATH_DEBUG_GLOBAL); + #endif + break; ++ case ATH_POWEROFFSET: ++ sc->sc_poweroffset = val; ++ break; + case ATH_TXANTENNA: + /* + * antenna can be: +@@ -11475,6 +11479,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl + case ATH_DEBUG: + val = sc->sc_debug | ath_debug_global; + break; ++ case ATH_POWEROFFSET: ++ val = sc->sc_poweroffset; ++ break; + case ATH_TXANTENNA: + val = sc->sc_txantenna; + break; +@@ -11616,6 +11623,12 @@ static const ctl_table ath_sysctl_templa + }, + #endif + { .ctl_name = CTL_AUTO, ++ .procname = "poweroffset", ++ .mode = 0644, ++ .proc_handler = ath_sysctl_halparam, ++ .extra2 = (void *)ATH_POWEROFFSET, ++ }, ++ { .ctl_name = CTL_AUTO, + .procname = "txantenna", + .mode = 0644, + .proc_handler = ath_sysctl_halparam, diff --git a/package/madwifi/patches/439-wlanconfig_stack_usage.patch b/package/madwifi/patches/439-wlanconfig_stack_usage.patch new file mode 100644 index 0000000000..f346143c3f --- /dev/null +++ b/package/madwifi/patches/439-wlanconfig_stack_usage.patch @@ -0,0 +1,20 @@ +--- a/tools/wlanconfig.c ++++ b/tools/wlanconfig.c +@@ -560,7 +560,7 @@ ieee80211_ntoa(const uint8_t mac[IEEE802 + static void + list_stations(const char *ifname) + { +- uint8_t buf[24*1024]; ++ static uint8_t buf[24*1024]; + struct iwreq iwr; + uint8_t *cp; + int s, len; +@@ -653,7 +653,7 @@ list_stations(const char *ifname) + static void + list_scan(const char *ifname) + { +- uint8_t buf[24 * 1024]; ++ static uint8_t buf[24 * 1024]; + char ssid[14]; + uint8_t *cp; + int len; diff --git a/package/madwifi/patches/440-wme_cleanup.patch b/package/madwifi/patches/440-wme_cleanup.patch new file mode 100644 index 0000000000..d6c1b26838 --- /dev/null +++ b/package/madwifi/patches/440-wme_cleanup.patch @@ -0,0 +1,136 @@ +--- a/net80211/ieee80211_output.c ++++ b/net80211/ieee80211_output.c +@@ -73,6 +73,29 @@ doprint(struct ieee80211vap *vap, int su + } + #endif + ++static const int ieee802_1d_to_ac[8] = { ++ WME_AC_BE, WME_AC_BK, WME_AC_BK, WME_AC_BE, ++ WME_AC_VI, WME_AC_VI, WME_AC_VO, WME_AC_VO ++}; ++ ++/* Given a data frame determine the 802.1p/1d tag to use. */ ++static unsigned int ieee80211_classify_ip(struct sk_buff *skb) ++{ ++ const struct ether_header *eh = (struct ether_header *) skb->data; ++ const struct iphdr *ip = (struct iphdr *) ++ (skb->data + sizeof (struct ether_header)); ++ unsigned int dscp; ++ ++ switch (skb->protocol) { ++ case __constant_htons(ETH_P_IP): ++ dscp = ip->tos & 0xfc; ++ break; ++ default: ++ return 0; ++ } ++ ++ return dscp >> 5; ++} + + /* + * Determine the priority based on VLAN and/or IP TOS. Priority is +@@ -83,90 +106,24 @@ static int + ieee80211_classify(struct ieee80211_node *ni, struct sk_buff *skb) + { + struct ieee80211vap *vap = ni->ni_vap; +- struct ether_header *eh = (struct ether_header *) skb->data; +- int v_wme_ac = 0, d_wme_ac = 0; +- +- /* default priority */ +- skb->priority = WME_AC_BE; +- +- if (!(ni->ni_flags & IEEE80211_NODE_QOS)) +- return 0; + +- /* +- * If node has a vlan tag then all traffic +- * to it must have a matching vlan id. ++ /* skb->priority values from 256->263 are magic values to ++ * directly indicate a specific 802.1d priority. This is used ++ * to allow 802.1d priority to be passed directly in from VLAN ++ * tags, etc. + */ +- if (ni->ni_vlan != 0 && vlan_tx_tag_present(skb)) { +- u_int32_t tag=0; +- int v_pri; +- +- if (vap->iv_vlgrp == NULL) { +- IEEE80211_NODE_STAT(ni, tx_novlantag); +- ni->ni_stats.ns_tx_novlantag++; +- return 1; +- } +- if (((tag = vlan_tx_tag_get(skb)) & VLAN_VID_MASK) != +- (ni->ni_vlan & VLAN_VID_MASK)) { +- IEEE80211_NODE_STAT(ni, tx_vlanmismatch); +- ni->ni_stats.ns_tx_vlanmismatch++; +- return 1; +- } +- if (ni->ni_flags & IEEE80211_NODE_QOS) { +- v_pri = (tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; +- switch (v_pri) { +- case 1: +- case 2: /* Background (BK) */ +- v_wme_ac = WME_AC_BK; +- break; +- case 0: +- case 3: /* Best Effort (BE) */ +- v_wme_ac = WME_AC_BE; +- break; +- case 4: +- case 5: /* Video (VI) */ +- v_wme_ac = WME_AC_VI; +- break; +- case 6: +- case 7: /* Voice (VO) */ +- v_wme_ac = WME_AC_VO; +- break; +- } +- } ++ if (skb->priority >= 256 && skb->priority <= 263) { ++ skb->priority = ieee802_1d_to_ac[skb->priority - 256]; ++ return 0; + } + +- if (eh->ether_type == __constant_htons(ETHERTYPE_IP)) { +- const struct iphdr *ip = (struct iphdr *) +- (skb->data + sizeof (struct ether_header)); +- /* +- * IP frame, map the TOS field. +- * +- * XXX: fill out these mappings??? +- */ +- switch (ip->tos) { +- case 0x08: /* Background */ +- case 0x20: +- d_wme_ac = WME_AC_BK; +- break; +- case 0x28: /* Video */ +- case 0xa0: +- d_wme_ac = WME_AC_VI; +- break; +- case 0x30: /* Voice */ +- case 0xe0: +- case 0x88: /* XXX UPSD */ +- case 0xb8: +- d_wme_ac = WME_AC_VO; +- break; +- default: /* All others */ +- d_wme_ac = WME_AC_BE; +- break; +- } +- } else { +- d_wme_ac = WME_AC_BE; ++ if (!(ni->ni_flags & IEEE80211_NODE_QOS)) { ++ /* default priority */ ++ skb->priority = WME_AC_BE; ++ return 0; + } +- skb->priority = d_wme_ac; +- if (v_wme_ac > d_wme_ac) +- skb->priority = v_wme_ac; ++ ++ skb->priority = ieee802_1d_to_ac[ieee80211_classify_ip(skb)]; + + /* Applying ACM policy */ + if (vap->iv_opmode == IEEE80211_M_STA) { diff --git a/package/madwifi/patches/441-fix_ibss_node_handling.patch b/package/madwifi/patches/441-fix_ibss_node_handling.patch new file mode 100644 index 0000000000..a98fe42d2e --- /dev/null +++ b/package/madwifi/patches/441-fix_ibss_node_handling.patch @@ -0,0 +1,90 @@ +--- a/ath/if_ath.c ++++ b/ath/if_ath.c +@@ -6641,10 +6641,8 @@ static void + ath_recv_mgmt(struct ieee80211vap * vap, struct ieee80211_node *ni_or_null, + struct sk_buff *skb, int subtype, int rssi, u_int64_t rtsf) + { ++ const struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data; + struct ath_softc *sc = netdev_priv(vap->iv_ic->ic_dev); +-#ifdef AR_DEBUG +- struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data; +-#endif + struct ieee80211_node * ni = ni_or_null; + u_int64_t hw_tsf, beacon_tsf; + u_int32_t hw_tu, beacon_tu, intval; +@@ -6686,7 +6684,7 @@ ath_recv_mgmt(struct ieee80211vap * vap, + } + if ((vap->iv_opmode == IEEE80211_M_IBSS) && + (sc->sc_opmode == HAL_M_HOSTAP) && +- IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) { ++ IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid)) { + /* In this mode, we drive the HAL in HOSTAP mode. Hence + * we do the IBSS merging in software. Also do not merge + * if the difference it too small. Otherwise we are playing +--- a/net80211/ieee80211_input.c ++++ b/net80211/ieee80211_input.c +@@ -311,7 +311,8 @@ ieee80211_input(struct ieee80211vap * va + } + /* Do not try to find a node reference if the packet really did come from the BSS */ + if (type == IEEE80211_FC0_TYPE_DATA && ni == vap->iv_bss && +- !IEEE80211_ADDR_EQ(vap->iv_bss->ni_macaddr, wh->i_addr2)) { ++ !IEEE80211_ADDR_EQ(vap->iv_bss->ni_macaddr, wh->i_addr2) && ++ IEEE80211_ADDR_EQ(vap->iv_bssid, wh->i_addr3)) { + /* Try to find sender in local node table. */ + ni = ieee80211_find_node(&ic->ic_sta, wh->i_addr2); + if (ni == NULL) { +@@ -513,6 +514,10 @@ ieee80211_input(struct ieee80211vap * va + break; + case IEEE80211_M_IBSS: + case IEEE80211_M_AHDEMO: ++ /* ignore foreign data frames */ ++ if (ni == vap->iv_bss) ++ goto out; ++ + if (dir != IEEE80211_FC1_DIR_NODS) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, + wh, "data", "invalid dir 0x%x", dir); +@@ -3552,6 +3557,11 @@ ieee80211_recv_mgmt(struct ieee80211vap + } else if (vap->iv_opmode == IEEE80211_M_WDS) { + found = 1; + ni = ni_or_null = vap->iv_wdsnode; ++ } else if (vap->iv_opmode == IEEE80211_M_IBSS) { ++ ni_or_null = ieee80211_find_node(&ic->ic_sta, wh->i_addr2); ++ if (ni_or_null) ++ ni = ni_or_null; ++ found = 1; + } + IEEE80211_UNLOCK_IRQ(vap->iv_ic); + +@@ -3676,19 +3686,8 @@ ieee80211_recv_mgmt(struct ieee80211vap + vap->iv_stats.is_rx_ssidmismatch++; /*XXX*/ + return; + } +- if (ni == vap->iv_bss) { +- if (vap->iv_opmode == IEEE80211_M_IBSS) { +- /* +- * XXX Cannot tell if the sender is operating +- * in ibss mode. But we need a new node to +- * send the response so blindly add them to the +- * neighbor table. +- */ +- ni = ieee80211_fakeup_adhoc_node(vap, +- wh->i_addr2); +- } else { +- ni = ieee80211_dup_bss(vap, wh->i_addr2, 1); +- } ++ if (ni == vap->iv_bss && vap->iv_opmode != IEEE80211_M_IBSS) { ++ ni = ieee80211_dup_bss(vap, wh->i_addr2, 1); + if (ni == NULL) + return; + allocbs = 1; +--- a/net80211/ieee80211_node.c ++++ b/net80211/ieee80211_node.c +@@ -601,6 +601,7 @@ ieee80211_ibss_merge(struct ieee80211_no + ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long", + ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", + ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : ""); ++ ieee80211_node_table_reset(&vap->iv_ic->ic_sta, vap); + return ieee80211_sta_join1(ieee80211_ref_node(ni)); + } + EXPORT_SYMBOL(ieee80211_ibss_merge); diff --git a/package/madwifi/patches/442-ibss_rx_filter.patch b/package/madwifi/patches/442-ibss_rx_filter.patch new file mode 100644 index 0000000000..eaf807118f --- /dev/null +++ b/package/madwifi/patches/442-ibss_rx_filter.patch @@ -0,0 +1,20 @@ +--- a/net80211/ieee80211_input.c ++++ b/net80211/ieee80211_input.c +@@ -294,6 +294,17 @@ ieee80211_input(struct ieee80211vap * va + break; + case IEEE80211_M_IBSS: + case IEEE80211_M_AHDEMO: ++ if (!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid) || ++ (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr) && ++ !IEEE80211_IS_MULTICAST(wh->i_addr1) && ++ (subtype != IEEE80211_FC0_SUBTYPE_BEACON))) { ++ if (!(vap->iv_dev->flags & IFF_PROMISC)) { ++ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, ++ bssid, NULL, "%s", "not to bss"); ++ vap->iv_stats.is_rx_wrongbss++; ++ goto out; ++ } ++ } + if (dir != IEEE80211_FC1_DIR_NODS) + bssid = wh->i_addr1; + else if (type == IEEE80211_FC0_TYPE_CTL) diff --git a/package/madwifi/patches/443-tx_drop_counter.patch b/package/madwifi/patches/443-tx_drop_counter.patch new file mode 100644 index 0000000000..13c154df2b --- /dev/null +++ b/package/madwifi/patches/443-tx_drop_counter.patch @@ -0,0 +1,25 @@ +--- a/net80211/ieee80211_node.c ++++ b/net80211/ieee80211_node.c +@@ -1591,10 +1591,6 @@ found: + ieee80211_ref_node(ni); + #endif + } +- } else { +- IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, mac, +- "no node, discard frame (%s)", __func__); +- vap->iv_stats.is_tx_nonode++; + } + } + return ni; +--- a/net80211/ieee80211_output.c ++++ b/net80211/ieee80211_output.c +@@ -208,6 +208,9 @@ ieee80211_hardstart(struct sk_buff *skb, + ni = ieee80211_find_txnode(vap, eh->ether_dhost); + if (ni == NULL) { + /* NB: ieee80211_find_txnode does stat+msg */ ++ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, mac, ++ "no node, discard frame (%s)", __func__); ++ vap->iv_stats.is_tx_nonode++; + goto bad; + } + diff --git a/package/wprobe/Makefile b/package/wprobe/Makefile index 902c9dc647..379aa37c2a 100644 --- a/package/wprobe/Makefile +++ b/package/wprobe/Makefile @@ -20,33 +20,33 @@ include $(INCLUDE_DIR)/package.mk define KernelPackage/wprobe SUBMENU:=Network Support + DEPENDS:=@LINUX_2_6 TITLE:=Wireless driver probe infrastructure FILES:= \ $(PKG_BUILD_DIR)/kernel/wprobe.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,01,wprobe) - DEPENDS:=@!LINUX_2_4 endef define KernelPackage/wprobe/description A module that exports measurement data from wireless driver to user space endef -define Package/wprobe-info +define Package/wprobe-util SECTION:=net CATEGORY:=Network DEPENDS:=+kmod-wprobe +libnl-tiny TITLE:=Wireless measurement utility endef -define Package/wprobe-info/description - wprobe-info uses the wprobe kernel module to query +define Package/wprobe-util/description + wprobe-util uses the wprobe kernel module to query wireless driver measurement data from an interface endef define Package/wprobe-export SECTION:=net CATEGORY:=Network - DEPENDS:=+kmod-wprobe +libnl-tiny + DEPENDS:=+wprobe-util TITLE:=Wireless measurement data exporter endef @@ -83,6 +83,7 @@ define Build/Compile/lib CFLAGS="$(TARGET_CFLAGS)" \ CPPFLAGS="$(TARGET_CPPFLAGS) -I$(PKG_BUILD_DIR)/kernel" \ LDFLAGS="$(TARGET_LDFLAGS)" \ + HOST_OS=Linux \ LIBNL="-lnl-tiny" endef @@ -108,17 +109,18 @@ define Build/InstallDev $(CP) $(PKG_BUILD_DIR)/kernel/linux $(1)/usr/include/wprobe endef -define Package/wprobe-info/install +define Package/wprobe-util/install $(INSTALL_DIR) $(1)/sbin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/user/wprobe-info $(1)/sbin/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/user/wprobe-util $(1)/sbin/ endef define Package/wprobe-export/install - $(INSTALL_DIR) $(1)/sbin $(1)/etc/init.d - $(INSTALL_BIN) ./files/wprobe.init $(1)/etc/init.d/ + $(INSTALL_DIR) $(1)/sbin $(1)/etc/init.d $(1)/etc/config + $(INSTALL_BIN) ./files/wprobe.init $(1)/etc/init.d/wprobe + $(INSTALL_BIN) ./files/wprobe.config $(1)/etc/config/wprobe $(INSTALL_BIN) $(PKG_BUILD_DIR)/exporter/wprobe-export $(1)/sbin/ endef $(eval $(call KernelPackage,wprobe)) -$(eval $(call BuildPackage,wprobe-info)) +$(eval $(call BuildPackage,wprobe-util)) $(eval $(call BuildPackage,wprobe-export)) diff --git a/package/wprobe/files/wprobe.config b/package/wprobe/files/wprobe.config new file mode 100644 index 0000000000..63518ef6e4 --- /dev/null +++ b/package/wprobe/files/wprobe.config @@ -0,0 +1,10 @@ +config export + # uncomment this line to enable ipfix export: + # option type ipfix + option ifname ath0 + option host ipfix-col + option proto tcp + +# enable public wprobe protocol access +config export + option type wprobe diff --git a/package/wprobe/files/wprobe.init b/package/wprobe/files/wprobe.init index 3c62a03066..26d5c3d312 100755 --- a/package/wprobe/files/wprobe.init +++ b/package/wprobe/files/wprobe.init @@ -1,19 +1,34 @@ #!/bin/sh /etc/rc.common START=90 +EXPORTER=/usr/sbin/wprobe-ipfix +UTIL=/sbin/wprobe-util wprobe_ssd() { - local cfg="$1"; shift local cmd="$1"; shift - start-stop-daemon "$cmd" -p "/var/run/wprobe-$cfg.pid" -b -x /sbin/wprobe-export -m -- "$@" + local type="$1"; shift + local app="$1"; shift + start-stop-daemon "$cmd" -p "/var/run/wprobe-$type.pid" -b ${app:+-x "$app"} -m -- "$@" } stop_wprobe() { - local cfg="$1" - [ -f "/var/run/wprobe-$cfg.pid" ] && wprobe_ssd "$cfg" -K - rm -f "/var/run/wprobe-$cfg.pid" + local type="$1" + [ -f "/var/run/wprobe-$type.pid" ] && wprobe_ssd -K "$type" + rm -f "/var/run/wprobe-$type.pid" +} + +config_wprobe() { + config_get ifname "$cfg" ifname + config_get interval "$cfg" interval + [ -n "$interval" ] || interval=100 + $UTIL "$ifname" -i "$interval" 2>/dev/null >/dev/null +} + +start_proxy() { + config_get port "$cfg" port + wprobe_ssd -S proxy "$UTIL" -P -p "${port:-17990}" } -start_wprobe() { +start_ipfix() { local cfg="$1" config_get ifname "$cfg" interface config_get host "$cfg" host @@ -29,7 +44,17 @@ start_wprobe() { echo "wprobe-export: missing host or interface name in config $cfg" return } - wprobe_ssd "$cfg" -S "$proto" -i "$ifname" -c "$host" -p "${port:-4739}" + config_wprobe "$cfg" + wprobe_ssd -S "export-$cfg" "$EXPORTER" "$proto" -i "$ifname" -c "$host" -p "${port:-4739}" +} + +start_export() { + local cfg="$1" + config_get export_type "$cfg" type + case "$export_type" in + ipfix) [ -x "$EXPORTER" ] && start_ipfix "$cfg";; + wprobe) start_proxy "$cfg";; + esac } stop() { @@ -42,5 +67,6 @@ stop() { start() { config_load wprobe - config_foreach start_wprobe wprobe + config_foreach config_wprobe interface + config_foreach start_export export } diff --git a/package/wprobe/src/Makefile.inc b/package/wprobe/src/Makefile.inc new file mode 100644 index 0000000000..05a2dd979f --- /dev/null +++ b/package/wprobe/src/Makefile.inc @@ -0,0 +1,12 @@ +HOST_OS=$(shell uname) + +CC=gcc +AR=ar +RANLIB=ranlib + +WFLAGS = -Wall -Werror +CFLAGS?=-O2 +CPPFLAGS= +LDFLAGS= +LIBS= + diff --git a/package/wprobe/src/exporter/Makefile b/package/wprobe/src/exporter/Makefile index c8e489a6b5..9f8150729c 100644 --- a/package/wprobe/src/exporter/Makefile +++ b/package/wprobe/src/exporter/Makefile @@ -1,2 +1,5 @@ +include ../Makefile.inc +CPPFLAGS += -I../kernel -I../user + wprobe-export: wprobe-export.c $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) diff --git a/package/wprobe/src/exporter/wprobe-export.c b/package/wprobe/src/exporter/wprobe-export.c index e9aa3de8c4..48be5f36bc 100644 --- a/package/wprobe/src/exporter/wprobe-export.c +++ b/package/wprobe/src/exporter/wprobe-export.c @@ -65,8 +65,8 @@ static struct wprobe_mapping map_globals[] = { }; static struct wprobe_mapping map_perlink[] = { - WMAP(IEEE_TX_RATE, "tx_rate", .scale = 10.0f), - WMAP(IEEE_RX_RATE, "rx_rate", .scale = 10.0f), + WMAP(IEEE_TX_RATE, "tx_rate"), + WMAP(IEEE_RX_RATE, "rx_rate"), WMAP(RSSI, "rssi"), WMAP(SIGNAL, "signal"), WMAP(RETRANSMIT_200, "retransmit_200"), @@ -77,9 +77,6 @@ static struct wprobe_mapping map_perlink[] = { static unsigned char link_local[6]; static char link_default[6]; -static LIST_HEAD(global_attr); -static LIST_HEAD(link_attr); -static LIST_HEAD(links); static int nfields = 0; #define FOKUS_USERID 12325 @@ -166,20 +163,20 @@ add_template_fields(ipfix_t *handle, ipfix_template_t *t, struct wprobe_mapping } static void -wprobe_dump_data(ipfix_t *ipfixh, ipfix_template_t *ipfixt, const char *ifname, struct list_head *gl, struct list_head *ll, struct list_head *ls) +wprobe_dump_data(ipfix_t *ipfixh, ipfix_template_t *ipfixt, struct wprobe_iface *dev) { struct wprobe_link *link; - wprobe_update_links(ifname, ls); - wprobe_request_data(ifname, gl, NULL, 2); - if (list_empty(ls)) { + wprobe_update_links(dev); + wprobe_request_data(dev, NULL); + if (list_empty(&dev->links)) { g_data.addrs[1] = link_default; ipfix_export_array(ipfixh, ipfixt, g_data.maxfields, g_data.addrs, g_data.lens); ipfix_export_flush(ipfixh); } - list_for_each_entry(link, ls, list) { + list_for_each_entry(link, &dev->links, list) { g_data.addrs[1] = link->addr; - wprobe_request_data(ifname, ll, link->addr, 2); + wprobe_request_data(dev, link->addr); ipfix_export_array(ipfixh, ipfixt, g_data.maxfields, g_data.addrs, g_data.lens); ipfix_export_flush(ipfixh); } @@ -187,6 +184,7 @@ wprobe_dump_data(ipfix_t *ipfixh, ipfix_template_t *ipfixt, const char *ifname, int main ( int argc, char **argv ) { + struct wprobe_iface *dev = NULL; ipfix_template_t *ipfixt = NULL; ipfix_t *ipfixh = NULL; int protocol = IPFIX_PROTO_TCP; @@ -196,6 +194,7 @@ int main ( int argc, char **argv ) int port = IPFIX_PORTNO; int verbose_level = 0; int opt, i = 10; + char *err = NULL; while ((opt = getopt(argc, argv, "hi:c:p:vstu")) != EOF) { switch (opt) { @@ -254,20 +253,14 @@ int main ( int argc, char **argv ) return -1; } - if (wprobe_init() != 0) { - fprintf(stderr, "wprobe init failed\n"); + dev = wprobe_get_auto(ifname, &err); + if (!dev || (list_empty(&dev->global_attr) && list_empty(&dev->link_attr))) { + fprintf(stderr, "Cannot connect to wprobe on interface '%s': %s\n", ifname, (err ? err : "Unknown error")); return -1; } - wprobe_dump_attributes(ifname, false, &global_attr, (char *) link_local); - wprobe_dump_attributes(ifname, true, &link_attr, NULL); - if (list_empty(&global_attr) && list_empty(&link_attr)) { - fprintf(stderr, "Cannot connect to wprobe on interface '%s'\n", ifname); - return -1; - } - - match_template(map_globals, ARRAY_SIZE(map_globals), &global_attr); - match_template(map_perlink, ARRAY_SIZE(map_perlink), &link_attr); + match_template(map_globals, ARRAY_SIZE(map_globals), &dev->global_attr); + match_template(map_perlink, ARRAY_SIZE(map_perlink), &dev->link_attr); if (nfields == 0) { fprintf(stderr, "No usable attributes found\n"); return -1; @@ -300,14 +293,8 @@ int main ( int argc, char **argv ) add_template_fields(ipfixh, ipfixt, map_perlink, ARRAY_SIZE(map_perlink)); while (!do_close) { - usleep(100 * 1000); - wprobe_measure(ifname); - - if (i-- > 0) - continue; - - i = 10; - wprobe_dump_data(ipfixh, ipfixt, ifname, &global_attr, &link_attr, &links); + sleep(1); + wprobe_dump_data(ipfixh, ipfixt, dev); } ipfix_delete_template( ipfixh, ipfixt ); diff --git a/package/wprobe/src/filter/README.txt b/package/wprobe/src/filter/README.txt new file mode 100644 index 0000000000..6fa265e4f8 --- /dev/null +++ b/package/wprobe/src/filter/README.txt @@ -0,0 +1 @@ +To compile pfc you need at least libpcap version 1.0, as it requires proper radiotap header support diff --git a/package/wprobe/src/filter/gen_filter.pl b/package/wprobe/src/filter/gen_filter.pl new file mode 100755 index 0000000000..f03f477a49 --- /dev/null +++ b/package/wprobe/src/filter/gen_filter.pl @@ -0,0 +1,63 @@ +#!/usr/bin/perl +use strict; + +# helpers for custom packet format +# bytes 0-7 are used by a dummy radiotap header +my $WLAN_LEN = "radio[8:2]"; +my $SNR = "radio[10:1]"; +my $DEFAULT = undef; + +my $MAGIC = "WPFF"; +my $VERSION = 1; # filter binary format version +my $HDRLEN = 3; # assumed storage space for custom fields + +my $output = "filter.bin"; +my $config = { + "packetsize" => [ + [ "small", "$WLAN_LEN < 250" ], + [ "medium", "$WLAN_LEN < 800" ], + [ "big", $DEFAULT ], + ], + "snr" => [ + [ "low", "$SNR < 10" ], + [ "medium", "$SNR < 20" ], + [ "high", $DEFAULT ], + ], + "type" => [ + [ "beacon", "type mgt subtype beacon" ], + [ "data", "type data subtype data" ], + [ "qosdata", "type data subtype qos-data" ], + [ "other", "$DEFAULT" ] + ] +}; + +sub escape_q($) { + my $str = shift; + $str =~ s/'/'\\''/g; + return $str; +} + +my $GROUPS = scalar(keys %$config); +open OUTPUT, ">$output" or die "Cannot open output file: $!\n"; +print OUTPUT pack("a4CCn", $MAGIC, $VERSION, $HDRLEN, $GROUPS); + +foreach my $groupname (keys %$config) { + my $default = 0; + my $group = $config->{$groupname}; + print OUTPUT pack("a32N", $groupname, scalar(@$group)); + foreach my $filter (@$group) { + if (!$filter->[1]) { + $default > 0 and print "Cannot add more than one default filter per group: $groupname -> ".$filter->[0]."\n"; + print OUTPUT pack("a32N", $filter->[0], 0); + $default++; + } else { + open FILTER, "./pfc '".escape_q($filter->[0])."' '".escape_q($filter->[1])."' |" + or die "Failed to run filter command for '".$filter->[0]."': $!\n"; + while () { + print OUTPUT $_; + } + close FILTER; + $? and die "Filter '".$filter->[0]."' did not compile.\n"; + } + } +} diff --git a/package/wprobe/src/filter/pfc.c b/package/wprobe/src/filter/pfc.c new file mode 100644 index 0000000000..76fb1412aa --- /dev/null +++ b/package/wprobe/src/filter/pfc.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +struct wprobe_filter_hdr { + char name[32]; + uint32_t len; +} hdr; + +int main (int argc, char ** argv) +{ + struct bpf_program filter; + pcap_t *pc; + int i; + + if (argc != 3) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + pc = pcap_open_dead(DLT_IEEE802_11_RADIO, 256); + if (pcap_compile(pc, &filter, argv[2], 1, 0) != 0) + { + pcap_perror(pc, argv[0]); + exit(1); + } + + /* fix up for linux */ + for (i = 0; i < filter.bf_len; i++) { + struct bpf_insn *bi = &filter.bf_insns[i]; + switch(BPF_CLASS(bi->code)) { + case BPF_RET: + if (BPF_MODE(bi->code) == BPF_K) { + if (bi->k != 0) + bi->k = 65535; + } + break; + } + bi->code = ntohs(bi->code); + bi->k = ntohl(bi->k); + } + + memset(&hdr, 0, sizeof(hdr)); + strncpy(hdr.name, argv[1], sizeof(hdr.name)); + hdr.len = htonl(filter.bf_len); + fwrite(&hdr, sizeof(hdr), 1, stdout); + fwrite(filter.bf_insns, 8, filter.bf_len, stdout); + fflush(stdout); + + return 0; +} diff --git a/package/wprobe/src/kernel/linux/wprobe.h b/package/wprobe/src/kernel/linux/wprobe.h index f145195cd4..901daf3d10 100644 --- a/package/wprobe/src/kernel/linux/wprobe.h +++ b/package/wprobe/src/kernel/linux/wprobe.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #endif @@ -32,13 +34,12 @@ * * @WPROBE_ATTR_INTERFACE: interface name to process query on (NLA_STRING) * @WPROBE_ATTR_MAC: mac address (used for wireless links) (NLA_STRING) - * @WPROBE_ATTR_FLAGS: interface/link/attribute flags (see enum wprobe_flags) (NLA_U32) - * @WPROBE_ATTR_DURATION: sampling duration (in milliseconds) (NLA_MSECS) + * @WPROBE_ATTR_FLAGS: interface/link/attribute flags (see enum wprobe_flags) (NLA_U32)a + * @WPROBE_ATTR_DURATION: sampling duration (in milliseconds) (NLA_MSECS) * * @WPROBE_ATTR_ID: attribute id (NLA_U32) * @WPROBE_ATTR_NAME: attribute name (NLA_STRING) * @WPROBE_ATTR_TYPE: attribute type (NLA_U8) - * @WPROBE_ATTR_SCALE: attribute scale factor (NLA_U32) * * attribute values: * @@ -56,22 +57,29 @@ * @WPROBE_VAL_SUM: sum of all samples * @WPROBE_VAL_SUM_SQ: sum of all samples^2 * @WPROBE_VAL_SAMPLES: number of samples + * @WPROBE_VAL_SCALE_TIME: last time the samples were scaled down + * + * configuration: + * @WPROBE_ATTR_INTERVAL: (measurement interval in milliseconds) (NLA_MSECS) + * @WPROBE_ATTR_SAMPLES_MIN: minimum samples to keep during inactivity (NLA_U32) + * @WPROBE_ATTR_SAMPLES_MAX: maximum samples to keep before scaling down (NLA_U32) + * @WPROBE_ATTR_SAMPLES_SCALE_M: multiplier for scaling down samples (NLA_U32) + * @WPROBE_ATTR_SAMPLES_SCALE_D: divisor for scaling down samples (NLA_U32) * * @WPROBE_ATTR_LAST: unused */ enum wprobe_attr { + /* query attributes */ WPROBE_ATTR_UNSPEC, WPROBE_ATTR_INTERFACE, WPROBE_ATTR_MAC, WPROBE_ATTR_FLAGS, - WPROBE_ATTR_DURATION, - WPROBE_ATTR_SCALE, - /* end of query attributes */ /* response data */ WPROBE_ATTR_ID, WPROBE_ATTR_NAME, WPROBE_ATTR_TYPE, + WPROBE_ATTR_DURATION, /* value type attributes */ WPROBE_VAL_STRING, @@ -88,6 +96,19 @@ enum wprobe_attr { WPROBE_VAL_SUM, WPROBE_VAL_SUM_SQ, WPROBE_VAL_SAMPLES, + WPROBE_VAL_SCALE_TIME, + + /* config attributes */ + WPROBE_ATTR_INTERVAL, + WPROBE_ATTR_SAMPLES_MIN, + WPROBE_ATTR_SAMPLES_MAX, + WPROBE_ATTR_SAMPLES_SCALE_M, + WPROBE_ATTR_SAMPLES_SCALE_D, + WPROBE_ATTR_FILTER, + + WPROBE_ATTR_FILTER_GROUP, + WPROBE_ATTR_RXCOUNT, + WPROBE_ATTR_TXCOUNT, WPROBE_ATTR_LAST }; @@ -103,6 +124,8 @@ enum wprobe_attr { * @WPROBE_CMD_SET_FLAGS: set global/link flags * @WPROBE_CMD_MEASURE: take a snapshot of the current data * @WPROBE_CMD_GET_LINKS: get a list of links + * @WPROBE_CMD_CONFIG: set config options + * @WPROBE_CMD_GET_FILTER: get counters for active filters * * @WPROBE_CMD_LAST: unused * @@ -117,13 +140,15 @@ enum wprobe_cmd { WPROBE_CMD_SET_FLAGS, WPROBE_CMD_MEASURE, WPROBE_CMD_GET_LINKS, + WPROBE_CMD_CONFIG, + WPROBE_CMD_GET_FILTER, WPROBE_CMD_LAST }; /** * enum wprobe_flags: flags for wprobe links and items * @WPROBE_F_KEEPSTAT: keep statistics for this link/device - * @WPROBE_F_RESET: reset statistics now (used only in WPROBE_CMD_SET_LINK) + * @WPROBE_F_RESET: reset statistics now * @WPROBE_F_NEWDATA: used to indicate that a value has been updated */ enum wprobe_flags { @@ -137,6 +162,7 @@ enum wprobe_flags { struct wprobe_link; struct wprobe_item; struct wprobe_source; +struct wprobe_value; /** * struct wprobe_link - data structure describing a wireless link @@ -154,7 +180,7 @@ struct wprobe_link { char addr[ETH_ALEN]; u32 flags; void *priv; - void *val; + struct wprobe_value *val; }; /** @@ -192,8 +218,61 @@ struct wprobe_value { /* timestamps */ u64 first, last; + u64 scale_timestamp; +}; + +struct wprobe_filter_item_hdr { + char name[32]; + __be32 n_items; +} __attribute__((packed)); + +struct wprobe_filter_item { + struct wprobe_filter_item_hdr hdr; + struct sock_filter filter[]; +} __attribute__((packed)); + +struct wprobe_filter_counter { + u64 tx; + u64 rx; }; +struct wprobe_filter_group { + const char *name; + int n_items; + struct wprobe_filter_item **items; + struct wprobe_filter_counter *counters; +}; + +struct wprobe_filter_hdr { + __u8 magic[4]; + __u8 version; + __u8 hdrlen; + __u16 n_groups; +} __attribute__((packed)); + +struct wprobe_filter { + spinlock_t lock; + struct sk_buff *skb; + void *data; + int n_groups; + int hdrlen; + struct wprobe_filter_item **items; + struct wprobe_filter_counter *counters; + struct wprobe_filter_group groups[]; +}; + +enum { + WPROBE_PKT_RX = 0x00, + WPROBE_PKT_TX = 0x10, +}; + +struct wprobe_wlan_hdr { + u16 len; + u8 snr; + u8 type; +} __attribute__((packed)); + + /** * struct wprobe_source - data structure describing a wireless interface * @@ -225,17 +304,28 @@ struct wprobe_iface { const struct wprobe_item *global_items; int n_global_items; - int (*sync_data)(struct wprobe_iface *dev, struct wprobe_link *l, struct wprobe_value *val, bool measure); + int (*sync_data)(struct wprobe_iface *dev, struct wprobe_link *l, + struct wprobe_value *val, bool measure); void *priv; /* handled by the wprobe core */ struct list_head list; struct list_head links; spinlock_t lock; - void *val; - void *query_val; + struct wprobe_value *val; + struct wprobe_value *query_val; + struct wprobe_filter *active_filter; + + u32 measure_interval; + struct timer_list measure_timer; + + u32 scale_min; + u32 scale_max; + u32 scale_m; + u32 scale_d; }; + #define WPROBE_FILL_BEGIN(_ptr, _list) do { \ struct wprobe_value *__val = (_ptr); \ const struct wprobe_item *__item = _list; \ @@ -293,6 +383,15 @@ extern void __weak wprobe_remove_link(struct wprobe_iface *dev, struct wprobe_li */ extern void __weak wprobe_update_stats(struct wprobe_iface *dev, struct wprobe_link *l); +/** + * wprobe_add_frame: add frame for layer 2 analysis + * @dev: wprobe_iface structure describing the interface + * @hdr: metadata for the frame + * @data: 802.11 header pointer + * @len: length of the 802.11 header + */ +extern int __weak wprobe_add_frame(struct wprobe_iface *dev, const struct wprobe_wlan_hdr *hdr, void *data, int len); + #endif /* __KERNEL__ */ #endif diff --git a/package/wprobe/src/kernel/wprobe-core.c b/package/wprobe/src/kernel/wprobe-core.c index 798cd7ddec..ebb5bedd87 100644 --- a/package/wprobe/src/kernel/wprobe-core.c +++ b/package/wprobe/src/kernel/wprobe-core.c @@ -34,6 +34,14 @@ #define list_for_each_rcu __list_for_each_rcu #endif +#ifndef BIT +#define BIT(x) (1 << (x)) +#endif + +#define WPROBE_MIN_INTERVAL 100 /* minimum measurement interval in msecs */ +#define WPROBE_MAX_FILTER_SIZE 1024 +#define WPROBE_MAX_FRAME_SIZE 1900 + static struct list_head wprobe_if; static spinlock_t wprobe_lock; @@ -43,10 +51,20 @@ static struct genl_family wprobe_fam = { .hdrsize = 0, .version = 1, /* only the first set of attributes is used for queries */ - .maxattr = WPROBE_ATTR_ID, + .maxattr = WPROBE_ATTR_LAST, +}; + +/* fake radiotap header */ +struct wprobe_rtap_hdr { + __u8 version; + __u8 padding; + __le16 len; + __le32 present; }; static void wprobe_update_stats(struct wprobe_iface *dev, struct wprobe_link *l); +static int wprobe_sync_data(struct wprobe_iface *dev, struct wprobe_link *l, bool query); +static void wprobe_free_filter(struct wprobe_filter *f); int wprobe_add_link(struct wprobe_iface *s, struct wprobe_link *l, const char *addr) @@ -81,6 +99,19 @@ wprobe_remove_link(struct wprobe_iface *s, struct wprobe_link *l) } EXPORT_SYMBOL(wprobe_remove_link); +static void +wprobe_measure_timer(unsigned long data) +{ + struct wprobe_iface *dev = (struct wprobe_iface *) data; + + /* set next measurement interval */ + mod_timer(&dev->measure_timer, jiffies + + msecs_to_jiffies(dev->measure_interval)); + + /* perform measurement */ + wprobe_sync_data(dev, NULL, false); +} + int wprobe_add_iface(struct wprobe_iface *s) { @@ -93,16 +124,26 @@ wprobe_add_iface(struct wprobe_iface *s) BUG_ON(!s->name); INIT_LIST_HEAD(&s->list); INIT_LIST_HEAD(&s->links); + setup_timer(&s->measure_timer, wprobe_measure_timer, (unsigned long) s); - vsize = max(s->n_link_items, s->n_global_items); - s->val = kzalloc(sizeof(struct wprobe_value) * vsize, GFP_ATOMIC); + s->val = kzalloc(sizeof(struct wprobe_value) * s->n_global_items, GFP_ATOMIC); if (!s->val) goto error; + vsize = max(s->n_link_items, s->n_global_items); s->query_val = kzalloc(sizeof(struct wprobe_value) * vsize, GFP_ATOMIC); if (!s->query_val) goto error; + /* initialize defaults to be able to handle overflow, + * user space will need to handle this if it keeps an + * internal histogram */ + s->scale_min = 20; + s->scale_max = (1 << 31); + + s->scale_m = 1; + s->scale_d = 10; + spin_lock_irqsave(&wprobe_lock, flags); list_add_rcu(&s->list, &wprobe_if); spin_unlock_irqrestore(&wprobe_lock, flags); @@ -123,6 +164,7 @@ wprobe_remove_iface(struct wprobe_iface *s) BUG_ON(!list_empty(&s->links)); + del_timer_sync(&s->measure_timer); spin_lock_irqsave(&wprobe_lock, flags); list_del_rcu(&s->list); spin_unlock_irqrestore(&wprobe_lock, flags); @@ -133,6 +175,8 @@ wprobe_remove_iface(struct wprobe_iface *s) kfree(s->val); kfree(s->query_val); + if (s->active_filter) + wprobe_free_filter(s->active_filter); } EXPORT_SYMBOL(wprobe_remove_iface); @@ -161,6 +205,73 @@ wprobe_get_dev(struct nlattr *attr) } int +wprobe_add_frame(struct wprobe_iface *dev, const struct wprobe_wlan_hdr *hdr, void *data, int len) +{ + struct wprobe_wlan_hdr *new_hdr; + struct wprobe_filter *f; + struct sk_buff *skb; + unsigned long flags; + int i, j; + + rcu_read_lock(); + f = rcu_dereference(dev->active_filter); + if (!f) + goto out; + + spin_lock_irqsave(&f->lock, flags); + + skb = f->skb; + skb->len = sizeof(struct wprobe_rtap_hdr); + skb->tail = skb->data + skb->len; + if (len + skb->len > WPROBE_MAX_FRAME_SIZE) + len = WPROBE_MAX_FRAME_SIZE - skb->len; + + new_hdr = (struct wprobe_wlan_hdr *) skb_put(skb, f->hdrlen); + memcpy(new_hdr, hdr, sizeof(struct wprobe_wlan_hdr)); + new_hdr->len = cpu_to_be16(new_hdr->len); + + memcpy(skb_put(skb, len), data, len); + + for(i = 0; i < f->n_groups; i++) { + struct wprobe_filter_group *fg = &f->groups[i]; + bool found = false; + int def = -1; + + for (j = 0; j < fg->n_items; j++) { + struct wprobe_filter_item *fi = fg->items[j]; + + if (!fi->hdr.n_items) { + def = j; + continue; + } + if (sk_run_filter(skb, fi->filter, fi->hdr.n_items) == 0) + continue; + + found = true; + break; + } + if (!found && def >= 0) { + j = def; + found = true; + } + if (found) { + struct wprobe_filter_counter *c = &fg->counters[j]; + + if (hdr->type >= WPROBE_PKT_TX) + c->tx++; + else + c->rx++; + } + } + + spin_unlock_irqrestore(&f->lock, flags); +out: + rcu_read_unlock(); + return 0; +} +EXPORT_SYMBOL(wprobe_add_frame); + +static int wprobe_sync_data(struct wprobe_iface *dev, struct wprobe_link *l, bool query) { struct wprobe_value *val; @@ -190,11 +301,40 @@ done: } EXPORT_SYMBOL(wprobe_sync_data); +static void +wprobe_scale_stats(struct wprobe_iface *dev, const struct wprobe_item *item, + struct wprobe_value *val, int n) +{ + u64 scale_ts = jiffies_64; + int i; + + for (i = 0; i < n; i++) { + if (!(item[i].flags & WPROBE_F_KEEPSTAT)) + continue; + + if (val[i].n <= dev->scale_min) + continue; + + /* FIXME: div_s64 seems to be very imprecise here, even when + * the values are scaled up */ + val[i].s *= dev->scale_m; + val[i].s = div_s64(val[i].s, dev->scale_d); + + val[i].ss *= dev->scale_m; + val[i].ss = div_s64(val[i].ss, dev->scale_d); + + val[i].n = (val[i].n * dev->scale_m) / dev->scale_d; + val[i].scale_timestamp = scale_ts; + } +} + + void wprobe_update_stats(struct wprobe_iface *dev, struct wprobe_link *l) { const struct wprobe_item *item; struct wprobe_value *val; + bool scale_stats = false; int i, n; if (l) { @@ -215,6 +355,10 @@ wprobe_update_stats(struct wprobe_iface *dev, struct wprobe_link *l) continue; val[i].n++; + if ((item[i].flags & WPROBE_F_KEEPSTAT) && + (dev->scale_max > 0) && (val[i].n > dev->scale_max)) { + scale_stats = true; + } switch(item[i].type) { case WPROBE_VAL_S8: @@ -249,15 +393,23 @@ wprobe_update_stats(struct wprobe_iface *dev, struct wprobe_link *l) val[i].ss += v * v; val[i].pending = false; } + if (scale_stats) + wprobe_scale_stats(dev, item, val, n); } EXPORT_SYMBOL(wprobe_update_stats); -static const struct nla_policy wprobe_policy[WPROBE_ATTR_ID+1] = { +static const struct nla_policy wprobe_policy[WPROBE_ATTR_LAST+1] = { [WPROBE_ATTR_INTERFACE] = { .type = NLA_NUL_STRING }, [WPROBE_ATTR_MAC] = { .type = NLA_STRING }, - [WPROBE_ATTR_DURATION] = { .type = NLA_MSECS }, [WPROBE_ATTR_FLAGS] = { .type = NLA_U32 }, - [WPROBE_ATTR_SCALE] = { .type = NLA_U32 }, + + /* config */ + [WPROBE_ATTR_INTERVAL] = { .type = NLA_MSECS }, + [WPROBE_ATTR_SAMPLES_MIN] = { .type = NLA_U32 }, + [WPROBE_ATTR_SAMPLES_MAX] = { .type = NLA_U32 }, + [WPROBE_ATTR_SAMPLES_SCALE_M] = { .type = NLA_U32 }, + [WPROBE_ATTR_SAMPLES_SCALE_D] = { .type = NLA_U32 }, + [WPROBE_ATTR_FILTER] = { .type = NLA_BINARY, .len = 32768 }, }; static bool @@ -322,6 +474,7 @@ wprobe_send_item_value(struct sk_buff *msg, struct netlink_callback *cb, NLA_PUT_U64(msg, WPROBE_VAL_SUM, val[i].s); NLA_PUT_U64(msg, WPROBE_VAL_SUM_SQ, val[i].ss); NLA_PUT_U32(msg, WPROBE_VAL_SAMPLES, (u32) val[i].n); + NLA_PUT_MSECS(msg, WPROBE_VAL_SCALE_TIME, val[i].scale_timestamp); } done: genlmsg_end(msg, hdr); @@ -369,6 +522,86 @@ wprobe_find_link(struct wprobe_iface *dev, const char *mac) return NULL; } +static bool +wprobe_dump_filter_group(struct sk_buff *msg, struct wprobe_filter_group *fg, struct netlink_callback *cb) +{ + struct genlmsghdr *hdr; + struct nlattr *group, *item; + int i; + + hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, + &wprobe_fam, NLM_F_MULTI, WPROBE_CMD_GET_FILTER); + if (!hdr) + return false; + + NLA_PUT_STRING(msg, WPROBE_ATTR_NAME, fg->name); + group = nla_nest_start(msg, WPROBE_ATTR_FILTER_GROUP); + for (i = 0; i < fg->n_items; i++) { + struct wprobe_filter_item *fi = fg->items[i]; + struct wprobe_filter_counter *fc = &fg->counters[i]; + + item = nla_nest_start(msg, WPROBE_ATTR_FILTER_GROUP); + NLA_PUT_STRING(msg, WPROBE_ATTR_NAME, fi->hdr.name); + NLA_PUT_U64(msg, WPROBE_ATTR_RXCOUNT, fc->rx); + NLA_PUT_U64(msg, WPROBE_ATTR_TXCOUNT, fc->tx); + nla_nest_end(msg, item); + } + + nla_nest_end(msg, group); + genlmsg_end(msg, hdr); + return true; + +nla_put_failure: + genlmsg_cancel(msg, hdr); + return false; +} + +static int +wprobe_dump_filters(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct wprobe_iface *dev = (struct wprobe_iface *)cb->args[0]; + struct wprobe_filter *f; + int err = 0; + int i = 0; + + if (!dev) { + err = nlmsg_parse(cb->nlh, GENL_HDRLEN + wprobe_fam.hdrsize, + wprobe_fam.attrbuf, wprobe_fam.maxattr, wprobe_policy); + if (err) + goto done; + + dev = wprobe_get_dev(wprobe_fam.attrbuf[WPROBE_ATTR_INTERFACE]); + if (!dev) { + err = -ENODEV; + goto done; + } + + cb->args[0] = (long) dev; + cb->args[1] = 0; + } else { + if (!wprobe_check_ptr(&wprobe_if, &dev->list)) { + err = -ENODEV; + goto done; + } + } + + rcu_read_lock(); + f = rcu_dereference(dev->active_filter); + if (!f) + goto abort; + + for (i = cb->args[1]; i < f->n_groups; i++) { + if (unlikely(!wprobe_dump_filter_group(skb, &f->groups[i], cb))) + break; + } + cb->args[1] = i; +abort: + rcu_read_unlock(); + err = skb->len; +done: + return err; +} + static bool wprobe_dump_link(struct sk_buff *msg, struct wprobe_link *l, struct netlink_callback *cb) { @@ -432,29 +665,6 @@ wprobe_dump_links(struct sk_buff *skb, struct netlink_callback *cb) done: return err; } -static void -wprobe_scale_stats(const struct wprobe_item *item, struct wprobe_value *val, int n, u32 flags) -{ - u32 scale = 0; - int i; - - for (i = 0; i < n; i++) { - if (!(item[i].flags & WPROBE_F_KEEPSTAT)) - continue; - - /* reset statistics, if requested */ - if (flags & WPROBE_F_RESET) - scale = val[i].n; - else if (wprobe_fam.attrbuf[WPROBE_ATTR_SCALE]) - scale = nla_get_u32(wprobe_fam.attrbuf[WPROBE_ATTR_SCALE]); - - if ((scale > 0) && (val[i].n > scale)) { - val[i].s = div_s64(val[i].s, scale); - val[i].ss = div_s64(val[i].ss, scale); - val[i].n = val[i].n / scale + 1; - } - } -} #define WPROBE_F_LINK (1 << 31) /* for internal use */ static int @@ -515,7 +725,6 @@ wprobe_dump_info(struct sk_buff *skb, struct netlink_callback *cb) err = wprobe_sync_data(dev, l, true); if (!err) memcpy(dev->query_val, val, n * sizeof(struct wprobe_value)); - wprobe_scale_stats(item, val, n, flags); spin_unlock_irqrestore(&dev->lock, flags); if (err) @@ -582,6 +791,25 @@ done: } #undef WPROBE_F_LINK +static int +wprobe_update_auto_measurement(struct wprobe_iface *dev, u32 interval) +{ + if (interval && (interval < WPROBE_MIN_INTERVAL)) + return -EINVAL; + + if (!interval && dev->measure_interval) + del_timer_sync(&dev->measure_timer); + + dev->measure_interval = interval; + if (!interval) + return 0; + + /* kick of a new measurement immediately */ + mod_timer(&dev->measure_timer, jiffies + 1); + + return 0; +} + static int wprobe_measure(struct sk_buff *skb, struct genl_info *info) { @@ -607,6 +835,256 @@ done: return err; } +static int +wprobe_check_filter(void *data, int datalen, int gs) +{ + struct wprobe_filter_item_hdr *hdr; + void *orig_data = data; + void *end = data + datalen; + int i, j, k, is, cur_is; + + for (i = j = is = 0; i < gs; i++) { + hdr = data; + data += sizeof(*hdr); + + if (data > end) + goto overrun; + + hdr->name[31] = 0; + cur_is = be32_to_cpu(hdr->n_items); + hdr->n_items = cur_is; + is += cur_is; + for (j = 0; j < cur_is; j++) { + struct sock_filter *sf; + int n_items; + + hdr = data; + data += sizeof(*hdr); + if (data > end) + goto overrun; + + hdr->name[31] = 0; + n_items = be32_to_cpu(hdr->n_items); + hdr->n_items = n_items; + + if (n_items > 1024) + goto overrun; + + sf = data; + if (n_items > 0) { + for (k = 0; k < n_items; k++) { + sf->code = be16_to_cpu(sf->code); + sf->k = be32_to_cpu(sf->k); + sf++; + } + if (sk_chk_filter(data, n_items) != 0) { + printk("%s: filter check failed at group %d, item %d\n", __func__, i, j); + return 0; + } + } + data += n_items * sizeof(struct sock_filter); + } + } + return is; + +overrun: + printk(KERN_ERR "%s: overrun during filter check at group %d, item %d, offset=%d, len=%d\n", __func__, i, j, (data - orig_data), datalen); + return 0; +} + +static void +wprobe_free_filter(struct wprobe_filter *f) +{ + if (f->skb) + kfree_skb(f->skb); + if (f->data) + kfree(f->data); + if (f->items) + kfree(f->items); + if (f->counters) + kfree(f->counters); + kfree(f); +} + + +static int +wprobe_set_filter(struct wprobe_iface *dev, void *data, int len) +{ + struct wprobe_filter_hdr *fhdr; + struct wprobe_rtap_hdr *rtap; + struct wprobe_filter *f; + int i, j, cur_is, is, gs; + + if (len < sizeof(*fhdr)) + return -EINVAL; + + fhdr = data; + data += sizeof(*fhdr); + len -= sizeof(*fhdr); + + if (memcmp(fhdr->magic, "WPFF", 4) != 0) { + printk(KERN_ERR "%s: filter rejected (invalid magic)\n", __func__); + return -EINVAL; + } + + gs = be16_to_cpu(fhdr->n_groups); + is = wprobe_check_filter(data, len, gs); + if (is == 0) + return -EINVAL; + + f = kzalloc(sizeof(struct wprobe_filter) + + gs * sizeof(struct wprobe_filter_group), GFP_ATOMIC); + if (!f) + return -ENOMEM; + + f->skb = alloc_skb(WPROBE_MAX_FRAME_SIZE, GFP_ATOMIC); + if (!f->skb) + goto error; + + f->data = kmalloc(len, GFP_ATOMIC); + if (!f->data) + goto error; + + f->items = kzalloc(sizeof(struct wprobe_filter_item *) * is, GFP_ATOMIC); + if (!f->items) + goto error; + + f->counters = kzalloc(sizeof(struct wprobe_filter_counter) * is, GFP_ATOMIC); + if (!f->counters) + goto error; + + spin_lock_init(&f->lock); + memcpy(f->data, data, len); + f->n_groups = gs; + + if (f->hdrlen < sizeof(struct wprobe_wlan_hdr)) + f->hdrlen = sizeof(struct wprobe_wlan_hdr); + + rtap = (struct wprobe_rtap_hdr *)skb_put(f->skb, sizeof(*rtap)); + memset(rtap, 0, sizeof(*rtap)); + rtap->len = cpu_to_le16(sizeof(struct wprobe_rtap_hdr) + f->hdrlen); + data = f->data; + + cur_is = 0; + for (i = 0; i < gs; i++) { + struct wprobe_filter_item_hdr *hdr = data; + struct wprobe_filter_group *g = &f->groups[i]; + + data += sizeof(*hdr); + g->name = hdr->name; + g->items = &f->items[cur_is]; + g->counters = &f->counters[cur_is]; + g->n_items = hdr->n_items; + + for (j = 0; j < g->n_items; j++) { + hdr = data; + f->items[cur_is++] = data; + data += sizeof(*hdr) + hdr->n_items * sizeof(struct sock_filter); + } + } + rcu_assign_pointer(dev->active_filter, f); + return 0; + +error: + wprobe_free_filter(f); + return -ENOMEM; +} + +static int +wprobe_set_config(struct sk_buff *skb, struct genl_info *info) +{ + struct wprobe_iface *dev; + unsigned long flags; + int err = -ENOENT; + u32 scale_min, scale_max; + u32 scale_m, scale_d; + struct nlattr *attr; + struct wprobe_filter *filter_free = NULL; + + rcu_read_lock(); + dev = wprobe_get_dev(info->attrs[WPROBE_ATTR_INTERFACE]); + if (!dev) + goto done_unlocked; + + err = -EINVAL; + spin_lock_irqsave(&dev->lock, flags); + if (info->attrs[WPROBE_ATTR_MAC]) { + /* not supported yet */ + goto done; + } + + if (info->attrs[WPROBE_ATTR_FLAGS]) { + u32 flags = nla_get_u32(info->attrs[WPROBE_ATTR_FLAGS]); + + if (flags & BIT(WPROBE_F_RESET)) { + struct wprobe_link *l; + + memset(dev->val, 0, sizeof(struct wprobe_value) * dev->n_global_items); + list_for_each_entry_rcu(l, &dev->links, list) { + memset(l->val, 0, sizeof(struct wprobe_value) * dev->n_link_items); + } + } + } + + if (info->attrs[WPROBE_ATTR_SAMPLES_MIN] || + info->attrs[WPROBE_ATTR_SAMPLES_MAX]) { + if ((attr = info->attrs[WPROBE_ATTR_SAMPLES_MIN])) + scale_min = nla_get_u32(attr); + else + scale_min = dev->scale_min; + + if ((attr = info->attrs[WPROBE_ATTR_SAMPLES_MAX])) + scale_max = nla_get_u32(attr); + else + scale_max = dev->scale_max; + + if ((!scale_min && !scale_max) || + (scale_min && scale_max && (scale_min < scale_max))) { + dev->scale_min = scale_min; + dev->scale_max = scale_max; + } else { + goto done; + } + } + + if (info->attrs[WPROBE_ATTR_SAMPLES_SCALE_M] && + info->attrs[WPROBE_ATTR_SAMPLES_SCALE_D]) { + + scale_m = nla_get_u32(info->attrs[WPROBE_ATTR_SAMPLES_SCALE_M]); + scale_d = nla_get_u32(info->attrs[WPROBE_ATTR_SAMPLES_SCALE_D]); + + if (!scale_d || (scale_m > scale_d)) + goto done; + + dev->scale_m = scale_m; + dev->scale_d = scale_d; + } + + if ((attr = info->attrs[WPROBE_ATTR_FILTER])) { + filter_free = rcu_dereference(dev->active_filter); + rcu_assign_pointer(dev->active_filter, NULL); + if (nla_len(attr) > 0) + wprobe_set_filter(dev, nla_data(attr), nla_len(attr)); + } + + err = 0; + if (info->attrs[WPROBE_ATTR_INTERVAL]) { + /* change of measurement interval requested */ + err = wprobe_update_auto_measurement(dev, + (u32) nla_get_u64(info->attrs[WPROBE_ATTR_INTERVAL])); + } + +done: + spin_unlock_irqrestore(&dev->lock, flags); +done_unlocked: + rcu_read_unlock(); + if (filter_free) { + synchronize_rcu(); + wprobe_free_filter(filter_free); + } + return err; +} + static struct genl_ops wprobe_ops[] = { { .cmd = WPROBE_CMD_GET_INFO, @@ -627,7 +1105,17 @@ static struct genl_ops wprobe_ops[] = { .cmd = WPROBE_CMD_GET_LINKS, .dumpit = wprobe_dump_links, .policy = wprobe_policy, - } + }, + { + .cmd = WPROBE_CMD_CONFIG, + .doit = wprobe_set_config, + .policy = wprobe_policy, + }, + { + .cmd = WPROBE_CMD_GET_FILTER, + .dumpit = wprobe_dump_filters, + .policy = wprobe_policy, + }, }; static void __exit diff --git a/package/wprobe/src/user/Makefile b/package/wprobe/src/user/Makefile index e10dfc0d24..01e83da3eb 100644 --- a/package/wprobe/src/user/Makefile +++ b/package/wprobe/src/user/Makefile @@ -1,21 +1,38 @@ -CFLAGS = -O2 -CPPFLAGS ?= -I../kernel -WFLAGS = -Wall -Werror +include ../Makefile.inc + +CPPFLAGS += -I../kernel LDFLAGS = +ifneq ($(HOST_OS),Linux) +USE_LIBNL_MICRO=1 +else +USE_LIBNL_MICRO= +endif + +ifeq ($(USE_LIBNL_MICRO),1) +LIBNL_PREFIX = /usr/local +LIBNL = $(LIBNL_PREFIX)/lib/libnl-micro.a +CPPFLAGS += -I$(LIBNL_PREFIX)/include/libnl-micro +EXTRA_CFLAGS += -DNO_LOCAL_ACCESS +else LIBNL = -lnl +endif + LIBM = -lm LIBS = $(LIBNL) $(LIBM) -all: libwprobe.a wprobe-info +all: libwprobe.a wprobe-util -libwprobe.a: wprobe.o +libwprobe.a: wprobe-lib.o rm -f $@ $(AR) rcu $@ $^ $(RANLIB) $@ %.o: %.c - $(CC) $(WFLAGS) -c -o $@ $(CPPFLAGS) $(CFLAGS) $< + $(CC) $(WFLAGS) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) $< -wprobe-info: wprobe-info.o wprobe.o +wprobe-util: wprobe-util.o wprobe-lib.o $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) + +clean: + rm -f *.o *.a wprobe-util diff --git a/package/wprobe/src/user/wprobe-info.c b/package/wprobe/src/user/wprobe-info.c deleted file mode 100644 index b8918711c6..0000000000 --- a/package/wprobe/src/user/wprobe-info.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * wprobe-test.c: Wireless probe user space test code - * Copyright (C) 2008-2009 Felix Fietkau - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "wprobe.h" - -static const char * -wprobe_dump_value(struct wprobe_attribute *attr) -{ - static char buf[128]; - -#define HANDLE_TYPE(_type, _format) \ - case WPROBE_VAL_##_type: \ - snprintf(buf, sizeof(buf), _format, attr->val._type); \ - break - - switch(attr->type) { - HANDLE_TYPE(S8, "%d"); - HANDLE_TYPE(S16, "%d"); - HANDLE_TYPE(S32, "%d"); - HANDLE_TYPE(S64, "%lld"); - HANDLE_TYPE(U8, "%d"); - HANDLE_TYPE(U16, "%d"); - HANDLE_TYPE(U32, "%d"); - HANDLE_TYPE(U64, "%lld"); - case WPROBE_VAL_STRING: - /* FIXME: implement this */ - default: - strncpy(buf, "", sizeof(buf)); - break; - } - if ((attr->flags & WPROBE_F_KEEPSTAT) && - (attr->val.n > 0)) { - int len = strlen(buf); - snprintf(buf + len, sizeof(buf) - len, " (avg: %.02f; stdev: %.02f, n=%d)", attr->val.avg, attr->val.stdev, attr->val.n); - } -#undef HANDLE_TYPE - - return buf; -} - - -static void -wprobe_dump_data(const char *ifname, struct list_head *gl, struct list_head *ll, struct list_head *ls) -{ - struct wprobe_attribute *attr; - struct wprobe_link *link; - bool first = true; - - fprintf(stderr, "\n"); - wprobe_request_data(ifname, gl, NULL, 2); - list_for_each_entry(attr, gl, list) { - fprintf(stderr, (first ? - "Global: %s=%s\n" : - " %s=%s\n"), - attr->name, - wprobe_dump_value(attr) - ); - first = false; - } - - list_for_each_entry(link, ls, list) { - first = true; - wprobe_request_data(ifname, ll, link->addr, 2); - list_for_each_entry(attr, ll, list) { - if (first) { - fprintf(stderr, - "%02x:%02x:%02x:%02x:%02x:%02x: %s=%s\n", - link->addr[0], link->addr[1], link->addr[2], - link->addr[3], link->addr[4], link->addr[5], - attr->name, - wprobe_dump_value(attr)); - first = false; - } else { - fprintf(stderr, - " %s=%s\n", - attr->name, - wprobe_dump_value(attr)); - } - } - } -} - -static const char *attr_typestr[] = { - [0] = "Unknown", - [WPROBE_VAL_STRING] = "String", - [WPROBE_VAL_U8] = "Unsigned 8 bit", - [WPROBE_VAL_U16] = "Unsigned 16 bit", - [WPROBE_VAL_U32] = "Unsigned 32 bit", - [WPROBE_VAL_U64] = "Unsigned 64 bit", - [WPROBE_VAL_S8] = "Signed 8 bit", - [WPROBE_VAL_S16] = "Signed 16 bit", - [WPROBE_VAL_S32] = "Signed 32 bit", - [WPROBE_VAL_S64] = "Signed 64 bit", -}; - -static int usage(const char *prog) -{ - fprintf(stderr, "Usage: %s \n", prog); - return 1; -} - -int main(int argc, char **argv) -{ - struct wprobe_attribute *attr; - const char *ifname; - LIST_HEAD(global_attr); - LIST_HEAD(link_attr); - LIST_HEAD(links); - int i = 0; - - if (argc < 2) - return usage(argv[0]); - - ifname = argv[1]; - - if (wprobe_init() != 0) - return -1; - - wprobe_dump_attributes(ifname, false, &global_attr, NULL); - wprobe_dump_attributes(ifname, true, &link_attr, NULL); - - if (list_empty(&global_attr) && - list_empty(&link_attr)) { - fprintf(stderr, "Interface '%s' not found\n", ifname); - return -1; - } - - list_for_each_entry(attr, &global_attr, list) { - fprintf(stderr, "Global attribute: '%s' (%s)\n", - attr->name, attr_typestr[attr->type]); - } - list_for_each_entry(attr, &link_attr, list) { - fprintf(stderr, "Link attribute: '%s' (%s)\n", - attr->name, attr_typestr[attr->type]); - } - - while (1) { - usleep(100 * 1000); - wprobe_measure(ifname); - - if (i-- > 0) - continue; - - i = 10; - wprobe_update_links(ifname, &links); - wprobe_dump_data(ifname, &global_attr, &link_attr, &links); - } - wprobe_free(); - - return 0; -} diff --git a/package/wprobe/src/user/wprobe-lib.c b/package/wprobe/src/user/wprobe-lib.c new file mode 100644 index 0000000000..a1a52f2054 --- /dev/null +++ b/package/wprobe/src/user/wprobe-lib.c @@ -0,0 +1,1204 @@ +/* + * wprobe.c: Wireless probe user space library + * Copyright (C) 2008-2009 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef NO_LOCAL_ACCESS +#include +#include +#include +#endif +#include "wprobe.h" + +#define DEBUG 1 +#ifdef DEBUG +#define DPRINTF(fmt, ...) fprintf(stderr, "%s(%d): " fmt, __func__, __LINE__, ##__VA_ARGS__) +#else +#define DPRINTF(fmt, ...) do {} while (0) +#endif + +#if defined(BYTE_ORDER) && !defined(__BYTE_ORDER) +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#define __BIG_ENDIAN BIG_ENDIAN +#define __BYTE_ORDER BYTE_ORDER +#endif + +#ifndef __BYTE_ORDER +#error Unknown endian type +#endif + +#define WPROBE_MAX_MSGLEN 65536 + +static inline __u16 __swab16(__u16 x) +{ + return x<<8 | x>>8; +} + +static inline __u32 __swab32(__u32 x) +{ + return x<<24 | x>>24 | + (x & (__u32)0x0000ff00UL)<<8 | + (x & (__u32)0x00ff0000UL)>>8; +} + +static inline __u64 __swab64(__u64 x) +{ + return x<<56 | x>>56 | + (x & (__u64)0x000000000000ff00ULL)<<40 | + (x & (__u64)0x0000000000ff0000ULL)<<24 | + (x & (__u64)0x00000000ff000000ULL)<< 8 | + (x & (__u64)0x000000ff00000000ULL)>> 8 | + (x & (__u64)0x0000ff0000000000ULL)>>24 | + (x & (__u64)0x00ff000000000000ULL)>>40; +} + + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define SWAP16(var) var = __swab16(var) +#define SWAP32(var) var = __swab32(var) +#define SWAP64(var) var = __swab64(var) +#else +#define SWAP16(var) do {} while(0) +#define SWAP32(var) do {} while(0) +#define SWAP64(var) do {} while(0) +#endif + +int wprobe_port = 17990; +static struct nlattr *tb[WPROBE_ATTR_LAST+1]; +static struct nla_policy attribute_policy[WPROBE_ATTR_LAST+1] = { + [WPROBE_ATTR_ID] = { .type = NLA_U32 }, + [WPROBE_ATTR_MAC] = { .type = NLA_UNSPEC, .minlen = 6, .maxlen = 6 }, + [WPROBE_ATTR_NAME] = { .type = NLA_STRING }, + [WPROBE_ATTR_FLAGS] = { .type = NLA_U32 }, + [WPROBE_ATTR_TYPE] = { .type = NLA_U8 }, + [WPROBE_ATTR_FLAGS] = { .type = NLA_U32 }, + [WPROBE_VAL_S8] = { .type = NLA_U8 }, + [WPROBE_VAL_S16] = { .type = NLA_U16 }, + [WPROBE_VAL_S32] = { .type = NLA_U32 }, + [WPROBE_VAL_S64] = { .type = NLA_U64 }, + [WPROBE_VAL_U8] = { .type = NLA_U8 }, + [WPROBE_VAL_U16] = { .type = NLA_U16 }, + [WPROBE_VAL_U32] = { .type = NLA_U32 }, + [WPROBE_VAL_U64] = { .type = NLA_U64 }, + [WPROBE_VAL_SUM] = { .type = NLA_U64 }, + [WPROBE_VAL_SUM_SQ] = { .type = NLA_U64 }, + [WPROBE_VAL_SAMPLES] = { .type = NLA_U32 }, + [WPROBE_VAL_SCALE_TIME] = { .type = NLA_U64 }, + [WPROBE_ATTR_INTERVAL] = { .type = NLA_U64 }, + [WPROBE_ATTR_SAMPLES_MIN] = { .type = NLA_U32 }, + [WPROBE_ATTR_SAMPLES_MAX] = { .type = NLA_U32 }, + [WPROBE_ATTR_SAMPLES_SCALE_M] = { .type = NLA_U32 }, + [WPROBE_ATTR_SAMPLES_SCALE_D] = { .type = NLA_U32 }, + [WPROBE_ATTR_FILTER_GROUP] = { .type = NLA_NESTED }, + [WPROBE_ATTR_RXCOUNT] = { .type = NLA_U64 }, + [WPROBE_ATTR_TXCOUNT] = { .type = NLA_U64 }, +}; + +typedef int (*wprobe_cb_t)(struct nl_msg *, void *); + +struct wprobe_iface_ops { + int (*send_msg)(struct wprobe_iface *dev, struct nl_msg *msg, wprobe_cb_t cb, void *arg); + void (*free)(struct wprobe_iface *dev); +}; + +struct wprobe_attr_cb { + struct list_head *list; + char *addr; +}; + +#define WPROBE_MAGIC_STR "WPROBE" +struct wprobe_init_hdr { + struct { + char magic[sizeof(WPROBE_MAGIC_STR)]; + + /* protocol version */ + uint8_t version; + + /* extra header length (unused for now) */ + uint16_t extra; + } pre __attribute__((packed)); + union { + struct { + uint16_t genl_family; + } v0 __attribute__((packed)); + }; +} __attribute__((packed)); + +struct wprobe_msg_hdr { + __u16 status; + __u16 error; + __u32 len; +}; + +enum wprobe_resp_status { + WPROBE_MSG_DONE = 0, + WPROBE_MSG_DATA = 1, +}; + +static inline void +wprobe_swap_msg_hdr(struct wprobe_msg_hdr *mhdr) +{ + SWAP16(mhdr->status); + SWAP16(mhdr->error); + SWAP32(mhdr->len); +} + +static int +save_attribute_handler(struct nl_msg *msg, void *arg) +{ + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + const char *name = "N/A"; + struct wprobe_attribute *attr; + int type = 0; + struct wprobe_attr_cb *cb = arg; + + nla_parse(tb, WPROBE_ATTR_LAST, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), attribute_policy); + + if (tb[WPROBE_ATTR_NAME]) + name = nla_data(tb[WPROBE_ATTR_NAME]); + + attr = malloc(sizeof(struct wprobe_attribute) + strlen(name) + 1); + if (!attr) + return -1; + + memset(attr, 0, sizeof(struct wprobe_attribute)); + + if (tb[WPROBE_ATTR_ID]) + attr->id = nla_get_u32(tb[WPROBE_ATTR_ID]); + + if (tb[WPROBE_ATTR_MAC] && cb->addr) + memcpy(cb->addr, nla_data(tb[WPROBE_ATTR_MAC]), 6); + + if (tb[WPROBE_ATTR_FLAGS]) + attr->flags = nla_get_u32(tb[WPROBE_ATTR_FLAGS]); + + if (tb[WPROBE_ATTR_TYPE]) + type = nla_get_u8(tb[WPROBE_ATTR_TYPE]); + + if ((type < WPROBE_VAL_STRING) || + (type > WPROBE_VAL_U64)) + type = 0; + + attr->type = type; + strcpy(attr->name, name); + INIT_LIST_HEAD(&attr->list); + list_add(&attr->list, cb->list); + return 0; +} + +static struct nl_msg * +wprobe_new_msg(struct wprobe_iface *dev, int cmd, bool dump) +{ + struct nl_msg *msg; + uint32_t flags = 0; + + msg = nlmsg_alloc_size(65536); + if (!msg) + return NULL; + + if (dump) + flags |= NLM_F_DUMP; + + genlmsg_put(msg, 0, 0, dev->genl_family, + 0, flags, cmd, 0); + + NLA_PUT_STRING(msg, WPROBE_ATTR_INTERFACE, dev->ifname); +nla_put_failure: + return msg; +} + + +static int +dump_attributes(struct wprobe_iface *dev, bool link, struct list_head *list, char *addr) +{ + struct nl_msg *msg; + struct wprobe_attr_cb cb; + + cb.list = list; + cb.addr = addr; + msg = wprobe_new_msg(dev, WPROBE_CMD_GET_LIST, true); + if (!msg) + return -ENOMEM; + + if (link) + NLA_PUT(msg, WPROBE_ATTR_MAC, 6, "\x00\x00\x00\x00\x00\x00"); + + return dev->ops->send_msg(dev, msg, save_attribute_handler, &cb); + +nla_put_failure: + nlmsg_free(msg); + return -EINVAL; +} + +static struct wprobe_iface * +wprobe_alloc_dev(void) +{ + struct wprobe_iface *dev; + + dev = malloc(sizeof(struct wprobe_iface)); + if (!dev) + return NULL; + + memset(dev, 0, sizeof(struct wprobe_iface)); + + dev->interval = -1; + dev->scale_min = -1; + dev->scale_max = -1; + dev->scale_m = -1; + dev->scale_d = -1; + dev->sockfd = -1; + + INIT_LIST_HEAD(&dev->global_attr); + INIT_LIST_HEAD(&dev->link_attr); + INIT_LIST_HEAD(&dev->links); + return dev; +} + +static int +wprobe_init_dev(struct wprobe_iface *dev) +{ + dump_attributes(dev, false, &dev->global_attr, NULL); + dump_attributes(dev, true, &dev->link_attr, NULL); + return 0; +} + +#ifndef NO_LOCAL_ACCESS +static int n_devs = 0; +static struct nl_sock *handle = NULL; +static struct nl_cache *cache = NULL; +static struct genl_family *family = NULL; + +static int +error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) +{ + int *ret = arg; + *ret = err->error; + return NL_STOP; +} + +static int +finish_handler(struct nl_msg *msg, void *arg) +{ + int *ret = arg; + *ret = 0; + return NL_SKIP; +} + +static int +ack_handler(struct nl_msg *msg, void *arg) +{ + int *ret = arg; + *ret = 0; + return NL_STOP; +} + +static void +wprobe_local_free(struct wprobe_iface *dev) +{ + /* should not happen */ + if (n_devs == 0) + return; + + if (--n_devs != 0) + return; + + if (cache) + nl_cache_free(cache); + if (handle) + nl_socket_free(handle); + handle = NULL; + cache = NULL; +} + +static int +wprobe_local_init(void) +{ + int ret; + + if (n_devs++ > 0) + return 0; + + handle = nl_socket_alloc(); + if (!handle) { + DPRINTF("Failed to create handle\n"); + goto err; + } + + if (genl_connect(handle)) { + DPRINTF("Failed to connect to generic netlink\n"); + goto err; + } + + ret = genl_ctrl_alloc_cache(handle, &cache); + if (ret < 0) { + DPRINTF("Failed to allocate netlink cache\n"); + goto err; + } + + family = genl_ctrl_search_by_name(cache, "wprobe"); + if (!family) { + DPRINTF("wprobe API not present\n"); + goto err; + } + return 0; + +err: + wprobe_local_free(NULL); + return -EINVAL; +} + + +static int +wprobe_local_send_msg(struct wprobe_iface *dev, struct nl_msg *msg, wprobe_cb_t callback, void *arg) +{ + struct nl_cb *cb; + int err = 0; + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) + goto out_no_cb; + + if (callback) + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, callback, arg); + + err = nl_send_auto_complete(handle, msg); + if (err < 0) + goto out; + + err = 1; + + nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); + + while (err > 0) + nl_recvmsgs(handle, cb); + +out: + nl_cb_put(cb); +out_no_cb: + nlmsg_free(msg); + return err; +} + +static const struct wprobe_iface_ops wprobe_local_ops = { + .send_msg = wprobe_local_send_msg, + .free = wprobe_local_free, +}; + +struct wprobe_iface * +wprobe_get_dev(const char *ifname) +{ + struct wprobe_iface *dev; + + if (wprobe_local_init() != 0) + return NULL; + + dev = wprobe_alloc_dev(); + if (!dev) + goto error_alloc; + + dev->ifname = strdup(ifname); + dev->ops = &wprobe_local_ops; + dev->genl_family = genl_family_get_id(family); + + if (wprobe_init_dev(dev) < 0) + goto error; + + return dev; + +error: + free(dev); +error_alloc: + wprobe_local_free(NULL); + return NULL; +} + +#endif + +static void swap_nlmsghdr(struct nlmsghdr *nlh) +{ + SWAP32(nlh->nlmsg_len); + SWAP16(nlh->nlmsg_type); + SWAP16(nlh->nlmsg_flags); + SWAP32(nlh->nlmsg_seq); + SWAP32(nlh->nlmsg_pid); +} + +static void swap_genlmsghdr(struct genlmsghdr *gnlh) +{ +#if 0 /* probably unnecessary */ + SWAP16(gnlh->reserved); +#endif +} + +static void +wprobe_swap_nested(void *data, int len, bool outgoing) +{ + void *end = data + len; + + while (data < end) { + struct nlattr *nla = data; + unsigned int type, len; + + if (!outgoing) { + SWAP16(nla->nla_len); + SWAP16(nla->nla_type); + + /* required for further sanity checks */ + if (data + nla->nla_len > end) + nla->nla_len = end - data; + } + + len = NLA_ALIGN(nla->nla_len); + type = nla->nla_type & NLA_TYPE_MASK; + + if (type <= WPROBE_ATTR_LAST) { +#if __BYTE_ORDER == __LITTLE_ENDIAN + switch(attribute_policy[type].type) { + case NLA_U16: + SWAP16(*(__u16 *)nla_data(nla)); + break; + case NLA_U32: + SWAP32(*(__u32 *)nla_data(nla)); + break; + case NLA_U64: + SWAP64(*(__u64 *)nla_data(nla)); + break; + case NLA_NESTED: + wprobe_swap_nested(nla_data(nla), nla_len(nla), outgoing); + break; + } +#endif + } + data += len; + + if (outgoing) { + SWAP16(nla->nla_len); + SWAP16(nla->nla_type); + } + if (!nla->nla_len) + break; + } +} + +static struct nl_msg * +wprobe_msg_from_network(int socket, int len) +{ + struct genlmsghdr *gnlh; + struct nlmsghdr *nlh; + struct nl_msg *msg; + void *data; + + msg = nlmsg_alloc_size(len + 32); + if (!msg) + return NULL; + + nlh = nlmsg_hdr(msg); + if (read(socket, nlh, len) != len) + goto free; + + swap_nlmsghdr(nlh); + if (nlh->nlmsg_len > len) + goto free; + + gnlh = nlmsg_data(nlh); + swap_genlmsghdr(gnlh); + + data = genlmsg_data(gnlh); + wprobe_swap_nested(data, genlmsg_len(gnlh), false); + + return msg; +free: + nlmsg_free(msg); + return NULL; +} + +static int +wprobe_msg_to_network(int socket, struct nl_msg *msg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct wprobe_msg_hdr mhdr; + struct genlmsghdr *gnlh; + void *buf, *data; + int buflen, datalen; + int ret; + + buflen = nlh->nlmsg_len; + buf = malloc(buflen); + if (!buf) + return -ENOMEM; + + memset(&mhdr, 0, sizeof(mhdr)); + mhdr.status = WPROBE_MSG_DATA; + mhdr.len = buflen; + wprobe_swap_msg_hdr(&mhdr); + write(socket, &mhdr, sizeof(mhdr)); + + memcpy(buf, nlh, buflen); + nlh = buf; + gnlh = nlmsg_data(nlh); + data = genlmsg_data(gnlh); + datalen = genlmsg_len(gnlh); + + wprobe_swap_nested(data, datalen, true); + swap_genlmsghdr(gnlh); + swap_nlmsghdr(nlh); + ret = write(socket, buf, buflen); + free(buf); + + return ret; +} + +static int +wprobe_remote_send_msg(struct wprobe_iface *dev, struct nl_msg *msg, wprobe_cb_t callback, void *arg) +{ + struct wprobe_msg_hdr mhdr; + int msgs = 0; + + wprobe_msg_to_network(dev->sockfd, msg); + nlmsg_free(msg); + do { + if (read(dev->sockfd, &mhdr, sizeof(mhdr)) != sizeof(mhdr)) { + DPRINTF("Failed to read response header\n"); + return -1; + } + wprobe_swap_msg_hdr(&mhdr); + + switch(mhdr.status) { + case WPROBE_MSG_DATA: + if (mhdr.len > WPROBE_MAX_MSGLEN) { + fprintf(stderr, "Invalid length in received response message.\n"); + exit(1); + } + + msg = wprobe_msg_from_network(dev->sockfd, mhdr.len); + if (!msg) + return -EINVAL; + + msgs++; + callback(msg, arg); + nlmsg_free(msg); + break; + } + } while (mhdr.status != WPROBE_MSG_DONE); + + if (mhdr.error) + return -mhdr.error; + else + return msgs; +} + + +static void +wprobe_socket_dev_free(struct wprobe_iface *dev) +{ + if (dev->sockfd >= 0) + close(dev->sockfd); +} + +static const struct wprobe_iface_ops wprobe_remote_ops = { + .send_msg = wprobe_remote_send_msg, + .free = wprobe_socket_dev_free, +}; + + +#ifndef NO_LOCAL_ACCESS +int +wprobe_server_init(int socket) +{ + struct wprobe_init_hdr hdr; + int ret; + + ret = wprobe_local_init(); + if (ret != 0) + return ret; + + memset(&hdr, 0, sizeof(hdr)); + memcpy(hdr.pre.magic, WPROBE_MAGIC_STR, sizeof(WPROBE_MAGIC_STR)); + hdr.pre.version = 0; + hdr.v0.genl_family = genl_family_get_id(family); + SWAP16(hdr.v0.genl_family); + write(socket, (unsigned char *)&hdr, sizeof(hdr)); + + return 0; +} + +static int +wprobe_server_cb(struct nl_msg *msg, void *arg) +{ + int *socket = arg; + int ret; + + ret = wprobe_msg_to_network(*socket, msg); + if (ret > 0) + ret = 0; + + return ret; +} + + +int +wprobe_server_handle(int socket) +{ + struct wprobe_msg_hdr mhdr; + struct nl_msg *msg; + int ret; + + ret = read(socket, &mhdr, sizeof(mhdr)); + if (ret != sizeof(mhdr)) { + if (ret <= 0) + return -1; + + DPRINTF("Failed to read request header\n"); + return -EINVAL; + } + wprobe_swap_msg_hdr(&mhdr); + + switch(mhdr.status) { + case WPROBE_MSG_DATA: + if (mhdr.len > WPROBE_MAX_MSGLEN) { + DPRINTF("Invalid length in received response message.\n"); + return -EINVAL; + } + msg = wprobe_msg_from_network(socket, mhdr.len); + break; + default: + DPRINTF("Invalid request header type\n"); + return -ENOENT; + } + + if (!msg) { + DPRINTF("Failed to get message\n"); + return -EINVAL; + } + + ret = wprobe_local_send_msg(NULL, msg, wprobe_server_cb, &socket); + + memset(&mhdr, 0, sizeof(mhdr)); + mhdr.status = WPROBE_MSG_DONE; + if (ret < 0) + mhdr.error = (uint16_t) -ret; + + ret = write(socket, (unsigned char *)&mhdr, sizeof(mhdr)); + if (ret > 0) + ret = 0; + + return ret; +} + +void +wprobe_server_done(void) +{ + wprobe_local_free(NULL); +} +#endif + +struct wprobe_iface * +wprobe_get_from_socket(int socket, const char *name) +{ + struct wprobe_iface *dev; + struct wprobe_init_hdr hdr; + + dev = wprobe_alloc_dev(); + if (!dev) + goto out; + + dev->ops = &wprobe_remote_ops; + dev->sockfd = socket; + dev->ifname = strdup(name); + + /* read version and header length */ + if (read(socket, &hdr.pre, sizeof(hdr.pre)) != sizeof(hdr.pre)) { + DPRINTF("Could not read header\n"); + goto error; + } + + /* magic not found */ + if (memcmp(hdr.pre.magic, WPROBE_MAGIC_STR, sizeof(hdr.pre.magic)) != 0) { + DPRINTF("Magic does not match\n"); + goto error; + } + + /* unsupported version */ + if (hdr.pre.version != 0) { + DPRINTF("Protocol version does not match\n"); + goto error; + } + + if (read(socket, &hdr.v0, sizeof(hdr.v0)) != sizeof(hdr.v0)) { + DPRINTF("Could not read header data\n"); + goto error; + } + + SWAP16(hdr.pre.extra); + SWAP16(hdr.v0.genl_family); + dev->genl_family = hdr.v0.genl_family; + + if (wprobe_init_dev(dev) < 0) { + DPRINTF("Could not initialize device\n"); + goto error; + } + +out: + return dev; + +error: + wprobe_free_dev(dev); + return NULL; +} + +struct wprobe_iface * +wprobe_get_auto(const char *arg, char **err) +{ + static struct sockaddr_in sa; + static char errbuf[512]; + + struct wprobe_iface *dev = NULL; + struct hostent *h; + char *devstr = strdup(arg); + char *sep = NULL; + int sock = -1; + int len; + + if (err) + *err = NULL; + + sep = strchr(devstr, ':'); + if (!sep) { +#ifndef NO_LOCAL_ACCESS + free(devstr); + return wprobe_get_dev(arg); +#else + if (err) + *err = "Invalid argument"; + goto out; +#endif + } + + *sep = 0; + sep++; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) + goto syserr; + + h = gethostbyname(devstr); + if (!h) { + sprintf(errbuf, "Host not found"); + goto out_err; + } + + memcpy(&sa.sin_addr, h->h_addr, h->h_length); + sa.sin_family = AF_INET; + sa.sin_port = htons(wprobe_port); + if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) + goto syserr; + + dev = wprobe_get_from_socket(sock, sep); + if (!dev) { + sprintf(errbuf, "wprobe connection initialization failed"); + goto out_err; + } + goto out; + +syserr: + if (err) { + strcpy(errbuf, "Connection failed: "); + len = strlen(errbuf); + strerror_r(errno, errbuf + len, sizeof(errbuf) - len - 1); + } +out_err: + if (err) + *err = errbuf; + if (sock >= 0) + close(sock); +out: + if (devstr) + free(devstr); + return dev; +} + +static void +free_attr_list(struct list_head *list) +{ + struct wprobe_attribute *attr, *tmp; + + list_for_each_entry_safe(attr, tmp, list, list) { + list_del(&attr->list); + free(attr); + } +} + +void +wprobe_free_dev(struct wprobe_iface *dev) +{ + if (dev->ops->free) + dev->ops->free(dev); + free_attr_list(&dev->global_attr); + free_attr_list(&dev->link_attr); + free((void *)dev->ifname); + free(dev); +} + +static struct wprobe_link * +get_link(struct list_head *list, const char *addr) +{ + struct wprobe_link *l; + + list_for_each_entry(l, list, list) { + if (!memcmp(l->addr, addr, 6)) { + list_del_init(&l->list); + goto out; + } + } + + /* no previous link found, allocate a new one */ + l = malloc(sizeof(struct wprobe_link)); + if (!l) + goto out; + + memset(l, 0, sizeof(struct wprobe_link)); + memcpy(l->addr, addr, sizeof(l->addr)); + INIT_LIST_HEAD(&l->list); + +out: + return l; +} + +struct wprobe_save_cb { + struct list_head *list; + struct list_head old_list; +}; + +static int +save_link_handler(struct nl_msg *msg, void *arg) +{ + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct wprobe_link *link; + struct wprobe_save_cb *cb = arg; + const char *addr; + + nla_parse(tb, WPROBE_ATTR_LAST, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), attribute_policy); + + if (!tb[WPROBE_ATTR_MAC] || (nla_len(tb[WPROBE_ATTR_MAC]) != 6)) + return -1; + + addr = nla_data(tb[WPROBE_ATTR_MAC]); + link = get_link(&cb->old_list, addr); + if (!link) + return -1; + + if (tb[WPROBE_ATTR_FLAGS]) + link->flags = nla_get_u32(tb[WPROBE_ATTR_FLAGS]); + + list_add_tail(&link->list, cb->list); + return 0; +} + + +int +wprobe_update_links(struct wprobe_iface *dev) +{ + struct wprobe_link *l, *tmp; + struct nl_msg *msg; + struct wprobe_save_cb cb; + int err; + + INIT_LIST_HEAD(&cb.old_list); + list_splice_init(&dev->links, &cb.old_list); + cb.list = &dev->links; + + msg = wprobe_new_msg(dev, WPROBE_CMD_GET_LINKS, true); + if (!msg) + return -ENOMEM; + + err = dev->ops->send_msg(dev, msg, save_link_handler, &cb); + if (err < 0) + return err; + + list_for_each_entry_safe(l, tmp, &cb.old_list, list) { + list_del(&l->list); + free(l); + } + + return 0; +} + + +struct wprobe_filter_data +{ + wprobe_filter_cb cb; + void *arg; + struct wprobe_filter_item *buf; + int buflen; +}; + +static int +dump_filter_handler(struct nl_msg *msg, void *arg) +{ + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct wprobe_filter_data *data = arg; + struct nlattr *p; + const char *name; + int count = 0; + int len; + + nla_parse(tb, WPROBE_ATTR_LAST, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), attribute_policy); + + if (!tb[WPROBE_ATTR_NAME] || !tb[WPROBE_ATTR_FILTER_GROUP]) + return -1; + + name = nla_data(tb[WPROBE_ATTR_NAME]); + nla_for_each_nested(p, tb[WPROBE_ATTR_FILTER_GROUP], len) { + count++; + } + + if (data->buflen < count) { + if (data->buf) + free(data->buf); + data->buflen = count; + data->buf = malloc(sizeof(struct wprobe_filter_item) * count); + memset(data->buf, 0, sizeof(struct wprobe_filter_item) * count); + } + + count = 0; + nla_for_each_nested(p, tb[WPROBE_ATTR_FILTER_GROUP], len) { + struct wprobe_filter_item *fi; + + nla_parse(tb, WPROBE_ATTR_LAST, nla_data(p), + nla_len(p), attribute_policy); + + if (!tb[WPROBE_ATTR_NAME] || !tb[WPROBE_ATTR_RXCOUNT] + || !tb[WPROBE_ATTR_TXCOUNT]) + continue; + + fi = &data->buf[count++]; + strncpy(fi->name, nla_data(tb[WPROBE_ATTR_NAME]), sizeof(fi->name) - 1); + fi->name[sizeof(fi->name) - 1] = 0; + fi->rx = nla_get_u64(tb[WPROBE_ATTR_RXCOUNT]); + fi->tx = nla_get_u64(tb[WPROBE_ATTR_TXCOUNT]); + } + data->cb(data->arg, name, data->buf, count); + + return 0; +} + +int +wprobe_dump_filters(struct wprobe_iface *dev, wprobe_filter_cb cb, void *arg) +{ + struct wprobe_filter_data data; + struct nl_msg *msg; + int err; + + data.buf = 0; + data.buflen = 0; + data.cb = cb; + data.arg = arg; + + msg = wprobe_new_msg(dev, WPROBE_CMD_GET_FILTER, true); + if (!msg) + return -ENOMEM; + + err = dev->ops->send_msg(dev, msg, dump_filter_handler, &data); + if (err < 0) + return err; + + return 0; +} + +int +wprobe_apply_config(struct wprobe_iface *dev) +{ + struct nl_msg *msg; + + msg = wprobe_new_msg(dev, WPROBE_CMD_CONFIG, false); + if (!msg) + return -ENOMEM; + + if (dev->interval >= 0) + NLA_PUT_MSECS(msg, WPROBE_ATTR_INTERVAL, dev->interval); + + if (dev->filter_len < 0) { + NLA_PUT(msg, WPROBE_ATTR_FILTER, 0, NULL); + dev->filter_len = 0; + } else if (dev->filter && dev->filter_len > 0) { + NLA_PUT(msg, WPROBE_ATTR_FILTER, dev->filter_len, dev->filter); + } + dev->filter = NULL; + + dev->ops->send_msg(dev, msg, NULL, NULL); + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -ENOMEM; +} + +int +wprobe_measure(struct wprobe_iface *dev) +{ + struct nl_msg *msg; + + msg = wprobe_new_msg(dev, WPROBE_CMD_MEASURE, false); + if (!msg) + return -ENOMEM; + + dev->ops->send_msg(dev, msg, NULL, NULL); + return 0; +} + +struct wprobe_request_cb { + struct list_head *list; + struct list_head old_list; + char *addr; +}; + +static int +save_attrdata_handler(struct nl_msg *msg, void *arg) +{ + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct wprobe_request_cb *cb = arg; + struct wprobe_attribute *attr; + int type, id; + + nla_parse(tb, WPROBE_ATTR_LAST, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), attribute_policy); + + if (!tb[WPROBE_ATTR_ID]) + return -1; + + if (!tb[WPROBE_ATTR_TYPE]) + return -1; + + id = nla_get_u32(tb[WPROBE_ATTR_ID]); + list_for_each_entry(attr, &cb->old_list, list) { + if (attr->id == id) + goto found; + } + /* not found */ + return -1; + +found: + list_del_init(&attr->list); + + type = nla_get_u8(tb[WPROBE_ATTR_TYPE]); + if (type != attr->type) { + DPRINTF("WARNING: type mismatch for %s attribute '%s' (%d != %d)\n", + (cb->addr ? "link" : "global"), + attr->name, + type, attr->type); + goto out; + } + + if ((type < WPROBE_VAL_STRING) || + (type > WPROBE_VAL_U64)) + goto out; + + memset(&attr->val, 0, sizeof(attr->val)); + +#define HANDLE_INT_TYPE(_idx, _type) \ + case WPROBE_VAL_S##_type: \ + case WPROBE_VAL_U##_type: \ + attr->val.U##_type = nla_get_u##_type(tb[_idx]); \ + break + + switch(type) { + HANDLE_INT_TYPE(type, 8); + HANDLE_INT_TYPE(type, 16); + HANDLE_INT_TYPE(type, 32); + HANDLE_INT_TYPE(type, 64); + case WPROBE_VAL_STRING: + /* unimplemented */ + break; + } +#undef HANDLE_TYPE + + if (attr->flags & WPROBE_F_KEEPSTAT) { + if (tb[WPROBE_VAL_SUM]) + attr->val.s = nla_get_u64(tb[WPROBE_VAL_SUM]); + + if (tb[WPROBE_VAL_SUM_SQ]) + attr->val.ss = nla_get_u64(tb[WPROBE_VAL_SUM_SQ]); + + if (tb[WPROBE_VAL_SAMPLES]) + attr->val.n = nla_get_u32(tb[WPROBE_VAL_SAMPLES]); + + if (attr->val.n > 0) { + float avg = ((float) attr->val.s) / attr->val.n; + float stdev = sqrt((((float) attr->val.ss) / attr->val.n) - (avg * avg)); + if (isnan(stdev)) + stdev = 0.0f; + if (isnan(avg)) + avg = 0.0f; + attr->val.avg = avg; + attr->val.stdev = stdev; + } + } + +out: + list_add_tail(&attr->list, cb->list); + return 0; +} + + +int +wprobe_request_data(struct wprobe_iface *dev, const unsigned char *addr) +{ + struct wprobe_request_cb cb; + struct list_head *attrs; + struct nl_msg *msg; + int err; + + msg = wprobe_new_msg(dev, WPROBE_CMD_GET_INFO, true); + if (!msg) + return -ENOMEM; + + if (addr) { + attrs = &dev->link_attr; + NLA_PUT(msg, WPROBE_ATTR_MAC, 6, addr); + } else { + attrs = &dev->global_attr; + } + + INIT_LIST_HEAD(&cb.old_list); + list_splice_init(attrs, &cb.old_list); + cb.list = attrs; + + err = dev->ops->send_msg(dev, msg, save_attrdata_handler, &cb); + list_splice(&cb.old_list, attrs->prev); + return err; + +nla_put_failure: + nlmsg_free(msg); + return -ENOMEM; +} + + diff --git a/package/wprobe/src/user/wprobe-util.c b/package/wprobe/src/user/wprobe-util.c new file mode 100644 index 0000000000..72feece025 --- /dev/null +++ b/package/wprobe/src/user/wprobe-util.c @@ -0,0 +1,441 @@ +/* + * wprobe-test.c: Wireless probe user space test code + * Copyright (C) 2008-2009 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "wprobe.h" + +static bool simple_mode = false; + +static const char * +wprobe_dump_value(struct wprobe_attribute *attr) +{ + static char buf[128]; + +#define HANDLE_TYPE(_type, _format) \ + case WPROBE_VAL_##_type: \ + snprintf(buf, sizeof(buf), _format, attr->val._type); \ + break + + switch(attr->type) { + HANDLE_TYPE(S8, "%d"); + HANDLE_TYPE(S16, "%d"); + HANDLE_TYPE(S32, "%d"); + HANDLE_TYPE(S64, "%lld"); + HANDLE_TYPE(U8, "%d"); + HANDLE_TYPE(U16, "%d"); + HANDLE_TYPE(U32, "%d"); + HANDLE_TYPE(U64, "%lld"); + case WPROBE_VAL_STRING: + /* FIXME: implement this */ + default: + strncpy(buf, "", sizeof(buf)); + break; + } + if ((attr->flags & WPROBE_F_KEEPSTAT) && + (attr->val.n > 0)) { + int len = strlen(buf); + if (simple_mode) + snprintf(buf + len, sizeof(buf) - len, ";%.02f;%.02f;%d;%lld;%lld", attr->val.avg, attr->val.stdev, attr->val.n, attr->val.s, attr->val.ss); + else + snprintf(buf + len, sizeof(buf) - len, " (avg: %.02f; stdev: %.02f, n=%d)", attr->val.avg, attr->val.stdev, attr->val.n); + } +#undef HANDLE_TYPE + + return buf; +} + + +static void +wprobe_dump_data(struct wprobe_iface *dev) +{ + struct wprobe_attribute *attr; + struct wprobe_link *link; + bool first = true; + + if (!simple_mode) + fprintf(stderr, "\n"); + wprobe_request_data(dev, NULL); + list_for_each_entry(attr, &dev->global_attr, list) { + if (simple_mode) { + if (first) + fprintf(stdout, "[global]\n"); + fprintf(stdout, "%s=%s\n", attr->name, wprobe_dump_value(attr)); + } else { + fprintf(stderr, (first ? + "Global: %s=%s\n" : + " %s=%s\n"), + attr->name, + wprobe_dump_value(attr) + ); + } + first = false; + } + + list_for_each_entry(link, &dev->links, list) { + first = true; + wprobe_request_data(dev, link->addr); + list_for_each_entry(attr, &dev->link_attr, list) { + if (first) { + fprintf((simple_mode ? stdout : stderr), + (simple_mode ? + "[%02x:%02x:%02x:%02x:%02x:%02x]\n%s=%s\n" : + "%02x:%02x:%02x:%02x:%02x:%02x: %s=%s\n"), + link->addr[0], link->addr[1], link->addr[2], + link->addr[3], link->addr[4], link->addr[5], + attr->name, + wprobe_dump_value(attr)); + first = false; + } else { + fprintf((simple_mode ? stdout : stderr), + (simple_mode ? "%s=%s\n" : + " %s=%s\n"), + attr->name, + wprobe_dump_value(attr)); + } + } + } + fflush(stdout); +} + +static const char *attr_typestr[] = { + [0] = "Unknown", + [WPROBE_VAL_STRING] = "String", + [WPROBE_VAL_U8] = "Unsigned 8 bit", + [WPROBE_VAL_U16] = "Unsigned 16 bit", + [WPROBE_VAL_U32] = "Unsigned 32 bit", + [WPROBE_VAL_U64] = "Unsigned 64 bit", + [WPROBE_VAL_S8] = "Signed 8 bit", + [WPROBE_VAL_S16] = "Signed 16 bit", + [WPROBE_VAL_S32] = "Signed 32 bit", + [WPROBE_VAL_S64] = "Signed 64 bit", +}; + +static int usage(const char *prog) +{ + fprintf(stderr, +#ifndef NO_LOCAL_ACCESS + "Usage: %s |:|-P [options]\n" +#else + "Usage: %s : [options]\n" +#endif + "\n" + "Options:\n" + " -c: Only apply configuration\n" + " -d: Delay between measurement dumps (in milliseconds, default: 1000)\n" + " -f: Dump contents of layer 2 filter counters during measurement\n" + " -F : Apply layer 2 filters from \n" + " -h: This help text\n" + " -i : Set measurement interval\n" + " -m: Run measurement loop\n" + " -p: Set the TCP port for server/client (default: 17990)\n" +#ifndef NO_LOCAL_ACCESS + " -P: Run in proxy mode (listen on network)\n" +#endif + "\n" + , prog); + exit(1); +} + +static void show_attributes(struct wprobe_iface *dev) +{ + struct wprobe_attribute *attr; + if (simple_mode) + return; + list_for_each_entry(attr, &dev->global_attr, list) { + fprintf(stderr, "Global attribute: '%s' (%s)\n", + attr->name, attr_typestr[attr->type]); + } + list_for_each_entry(attr, &dev->link_attr, list) { + fprintf(stderr, "Link attribute: '%s' (%s)\n", + attr->name, attr_typestr[attr->type]); + } +} + +static void show_filter_simple(void *arg, const char *group, struct wprobe_filter_item *items, int n_items) +{ + int i; + + fprintf(stdout, "[filter:%s]\n", group); + for (i = 0; i < n_items; i++) { + fprintf(stdout, "%s=%lld;%lld\n", + items[i].name, items[i].tx, items[i].rx); + } + fflush(stdout); +} + + +static void show_filter(void *arg, const char *group, struct wprobe_filter_item *items, int n_items) +{ + int i; + fprintf(stderr, "Filter group: '%s' (tx/rx)\n", group); + for (i = 0; i < n_items; i++) { + fprintf(stderr, " - %s (%lld/%lld)\n", + items[i].name, items[i].tx, items[i].rx); + } +} + +static void loop_measurement(struct wprobe_iface *dev, bool print_filters, unsigned long delay) +{ + while (1) { + usleep(delay * 1000); + wprobe_update_links(dev); + wprobe_dump_data(dev); + if (print_filters) + wprobe_dump_filters(dev, simple_mode ? show_filter_simple : show_filter, NULL); + } +} + +static void set_filter(struct wprobe_iface *dev, const char *filename) +{ + unsigned char *buf = NULL; + unsigned int buflen = 0; + unsigned int len = 0; + int fd; + + /* clear filter */ + if (filename[0] == 0) { + dev->filter_len = -1; + return; + } + + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror("open filter"); + return; + } + + do { + int rlen; + + if (!buf) { + len = 0; + buflen = 1024; + buf = malloc(1024); + } else { + buflen *= 2; + buf = realloc(buf, buflen); + } + rlen = read(fd, buf + len, buflen - len); + if (rlen < 0) + break; + + len += rlen; + } while (len == buflen); + + dev->filter = buf; + dev->filter_len = len; + close(fd); +} + +#ifndef NO_LOCAL_ACCESS + +static void sigchld_handler(int s) +{ + while (waitpid(-1, NULL, WNOHANG) > 0); +} + +static int run_proxy(int port) +{ + struct sockaddr_in sa; + struct sigaction sig; + int v = 1; + int s; + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) { + perror("socket"); + return 1; + } + + sig.sa_handler = sigchld_handler; // Signal Handler fuer Zombie Prozesse + sigemptyset(&sig.sa_mask); + sig.sa_flags = SA_RESTART; + sigaction(SIGCHLD, &sig, NULL); + + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = htonl(INADDR_ANY); + sa.sin_port = htons(wprobe_port); + + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)); + if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) { + perror("bind"); + return 1; + } + if (listen(s, 10)) { + perror("listen"); + return 1; + } + while(1) { + unsigned int addrlen = sizeof(struct sockaddr_in); + int ret, c; + + c = accept(s, (struct sockaddr *)&sa, &addrlen); + if (c < 0) { + if (errno == EINTR) + continue; + + perror("accept"); + return 1; + } + if (fork() == 0) { + /* close server socket, stdin, stdout, stderr */ + close(s); + close(0); + close(1); + close(2); + + wprobe_server_init(c); + do { + ret = wprobe_server_handle(c); + } while (ret >= 0); + wprobe_server_done(); + close(c); + exit(0); + } + close(c); + } + + return 0; +} +#endif + +int main(int argc, char **argv) +{ + struct wprobe_iface *dev = NULL; + const char *ifname; + const char *prog = argv[0]; + char *err = NULL; + enum { + CMD_NONE, + CMD_CONFIG, + CMD_MEASURE, + CMD_PROXY, + } cmd = CMD_NONE; + const char *filter = NULL; + bool print_filters = false; + unsigned long delay = 1000; + int interval = -1; + int ch; + + if (argc < 2) + return usage(prog); + +#ifndef NO_LOCAL_ACCESS + if (!strcmp(argv[1], "-P")) { + while ((ch = getopt(argc - 1, argv + 1, "p:")) != -1) { + switch(ch) { + case 'p': + /* set port */ + wprobe_port = strtoul(optarg, NULL, 0); + break; + default: + return usage(prog); + } + } + return run_proxy(wprobe_port); + } +#endif + + if (argv[1][0] == '-') + return usage(prog); + + ifname = argv[1]; + argv++; + argc--; + + while ((ch = getopt(argc, argv, "cd:fF:hi:msp:")) != -1) { + switch(ch) { + case 'c': + cmd = CMD_CONFIG; + break; + case 'd': + delay = strtoul(optarg, NULL, 10); + break; + case 'm': + cmd = CMD_MEASURE; + break; + case 'i': + interval = strtoul(optarg, NULL, 10); + break; + case 'f': + print_filters = true; + break; + case 'F': + if (filter) { + fprintf(stderr, "Cannot set multiple filters\n"); + return usage(prog); + } + filter = optarg; + break; + case 's': + simple_mode = true; + break; + case 'p': + /* set port */ + wprobe_port = strtoul(optarg, NULL, 0); + break; + case 'h': + default: + usage(prog); + break; + } + } + + dev = wprobe_get_auto(ifname, &err); + if (!dev || (list_empty(&dev->global_attr) && + list_empty(&dev->link_attr))) { + if (err) + fprintf(stderr, "%s\n", err); + else + fprintf(stderr, "Interface '%s' not found\n", ifname); + return 1; + } + + if (filter || interval >= 0) { + if (filter) + set_filter(dev, filter); + if (interval >= 0) + dev->interval = interval; + + wprobe_apply_config(dev); + } + + if (cmd != CMD_CONFIG) + show_attributes(dev); + if (cmd == CMD_MEASURE) + loop_measurement(dev, print_filters, delay); + + wprobe_free_dev(dev); + + return 0; +} diff --git a/package/wprobe/src/user/wprobe.c b/package/wprobe/src/user/wprobe.c deleted file mode 100644 index 1f8df6c7e9..0000000000 --- a/package/wprobe/src/user/wprobe.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * wprobe.c: Wireless probe user space library - * Copyright (C) 2008-2009 Felix Fietkau - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "wprobe.h" - -#define DEBUG 1 -#ifdef DEBUG -#define DPRINTF(fmt, ...) fprintf(stderr, "%s(%d): " fmt, __func__, __LINE__, ##__VA_ARGS__) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif - -static struct nl_sock *handle = NULL; -static struct nl_cache *cache = NULL; -static struct genl_family *family = NULL; -static struct nlattr *tb[WPROBE_ATTR_LAST+1]; -static struct nla_policy attribute_policy[WPROBE_ATTR_LAST+1] = { - [WPROBE_ATTR_ID] = { .type = NLA_U32 }, - [WPROBE_ATTR_MAC] = { .type = NLA_UNSPEC, .minlen = 6, .maxlen = 6 }, - [WPROBE_ATTR_NAME] = { .type = NLA_STRING }, - [WPROBE_ATTR_FLAGS] = { .type = NLA_U32 }, - [WPROBE_ATTR_TYPE] = { .type = NLA_U8 }, - [WPROBE_VAL_S8] = { .type = NLA_U8 }, - [WPROBE_VAL_S16] = { .type = NLA_U16 }, - [WPROBE_VAL_S32] = { .type = NLA_U32 }, - [WPROBE_VAL_S64] = { .type = NLA_U64 }, - [WPROBE_VAL_U8] = { .type = NLA_U8 }, - [WPROBE_VAL_U16] = { .type = NLA_U16 }, - [WPROBE_VAL_U32] = { .type = NLA_U32 }, - [WPROBE_VAL_U64] = { .type = NLA_U64 }, - [WPROBE_VAL_SUM] = { .type = NLA_U64 }, - [WPROBE_VAL_SUM_SQ] = { .type = NLA_U64 }, - [WPROBE_VAL_SAMPLES] = { .type = NLA_U32 }, -}; - -static int -error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) -{ - int *ret = arg; - *ret = err->error; - return NL_STOP; -} - -static int -finish_handler(struct nl_msg *msg, void *arg) -{ - int *ret = arg; - *ret = 0; - return NL_SKIP; -} - -static int -ack_handler(struct nl_msg *msg, void *arg) -{ - int *ret = arg; - *ret = 0; - return NL_STOP; -} - - -void -wprobe_free(void) -{ - if (cache) - nl_cache_free(cache); - if (handle) - nl_socket_free(handle); - handle = NULL; - cache = NULL; -} - -int -wprobe_init(void) -{ - int ret; - - handle = nl_socket_alloc(); - if (!handle) { - DPRINTF("Failed to create handle\n"); - goto err; - } - - if (genl_connect(handle)) { - DPRINTF("Failed to connect to generic netlink\n"); - goto err; - } - - ret = genl_ctrl_alloc_cache(handle, &cache); - if (ret < 0) { - DPRINTF("Failed to allocate netlink cache\n"); - goto err; - } - - family = genl_ctrl_search_by_name(cache, "wprobe"); - if (!family) { - DPRINTF("wprobe API not present\n"); - goto err; - } - return 0; - -err: - wprobe_free(); - return -EINVAL; -} - - -static struct nl_msg * -wprobe_new_msg(const char *ifname, int cmd, bool dump) -{ - struct nl_msg *msg; - uint32_t flags = 0; - - msg = nlmsg_alloc(); - if (!msg) - return NULL; - - if (dump) - flags |= NLM_F_DUMP; - - genlmsg_put(msg, 0, 0, genl_family_get_id(family), - 0, flags, cmd, 0); - - NLA_PUT_STRING(msg, WPROBE_ATTR_INTERFACE, ifname); -nla_put_failure: - return msg; -} - -static int -wprobe_send_msg(struct nl_msg *msg, void *callback, void *arg) -{ - struct nl_cb *cb; - int err = 0; - - cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!cb) - goto out_no_cb; - - if (callback) - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, callback, arg); - - err = nl_send_auto_complete(handle, msg); - if (err < 0) - goto out; - - err = 1; - - nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); - nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); - - while (err > 0) - nl_recvmsgs(handle, cb); - -out: - nl_cb_put(cb); -out_no_cb: - nlmsg_free(msg); - return err; -} - -struct wprobe_attr_cb { - struct list_head *list; - char *addr; -}; - -static int -save_attribute_handler(struct nl_msg *msg, void *arg) -{ - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - const char *name = "N/A"; - struct wprobe_attribute *attr; - int type = 0; - struct wprobe_attr_cb *cb = arg; - - nla_parse(tb, WPROBE_ATTR_LAST, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), attribute_policy); - - if (tb[WPROBE_ATTR_NAME]) - name = nla_data(tb[WPROBE_ATTR_NAME]); - - attr = malloc(sizeof(struct wprobe_attribute) + strlen(name) + 1); - if (!attr) - return -1; - - memset(attr, 0, sizeof(struct wprobe_attribute)); - - if (tb[WPROBE_ATTR_ID]) - attr->id = nla_get_u32(tb[WPROBE_ATTR_ID]); - - if (tb[WPROBE_ATTR_MAC] && cb->addr) - memcpy(cb->addr, nla_data(tb[WPROBE_ATTR_MAC]), 6); - - if (tb[WPROBE_ATTR_FLAGS]) - attr->flags = nla_get_u32(tb[WPROBE_ATTR_FLAGS]); - - if (tb[WPROBE_ATTR_TYPE]) - type = nla_get_u8(tb[WPROBE_ATTR_TYPE]); - - if ((type < WPROBE_VAL_STRING) || - (type > WPROBE_VAL_U64)) - type = 0; - - attr->type = type; - strcpy(attr->name, name); - INIT_LIST_HEAD(&attr->list); - list_add(&attr->list, cb->list); - return 0; -} - - -int -wprobe_dump_attributes(const char *ifname, bool link, struct list_head *list, char *addr) -{ - struct nl_msg *msg; - struct wprobe_attr_cb cb; - - cb.list = list; - cb.addr = addr; - msg = wprobe_new_msg(ifname, WPROBE_CMD_GET_LIST, true); - if (!msg) - return -ENOMEM; - - if (link) - NLA_PUT(msg, WPROBE_ATTR_MAC, 6, "\x00\x00\x00\x00\x00\x00"); - - return wprobe_send_msg(msg, save_attribute_handler, &cb); - -nla_put_failure: - nlmsg_free(msg); - return -EINVAL; -} - -static struct wprobe_link * -get_link(struct list_head *list, const char *addr) -{ - struct wprobe_link *l; - - list_for_each_entry(l, list, list) { - if (!memcmp(l->addr, addr, 6)) { - list_del_init(&l->list); - goto out; - } - } - - /* no previous link found, allocate a new one */ - l = malloc(sizeof(struct wprobe_link)); - if (!l) - goto out; - - memset(l, 0, sizeof(struct wprobe_link)); - memcpy(l->addr, addr, sizeof(l->addr)); - INIT_LIST_HEAD(&l->list); - -out: - return l; -} - -struct wprobe_save_cb { - struct list_head *list; - struct list_head old_list; -}; - -static int -save_link_handler(struct nl_msg *msg, void *arg) -{ - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct wprobe_link *link; - struct wprobe_save_cb *cb = arg; - const char *addr; - - nla_parse(tb, WPROBE_ATTR_LAST, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), attribute_policy); - - if (!tb[WPROBE_ATTR_MAC] || (nla_len(tb[WPROBE_ATTR_MAC]) != 6)) - return -1; - - addr = nla_data(tb[WPROBE_ATTR_MAC]); - link = get_link(&cb->old_list, addr); - if (!link) - return -1; - - if (tb[WPROBE_ATTR_FLAGS]) - link->flags = nla_get_u32(tb[WPROBE_ATTR_FLAGS]); - - list_add_tail(&link->list, cb->list); - return 0; -} - - -int -wprobe_update_links(const char *ifname, struct list_head *list) -{ - struct wprobe_link *l, *tmp; - struct nl_msg *msg; - struct wprobe_save_cb cb; - int err; - - INIT_LIST_HEAD(&cb.old_list); - list_splice_init(list, &cb.old_list); - cb.list = list; - - msg = wprobe_new_msg(ifname, WPROBE_CMD_GET_LINKS, true); - if (!msg) - return -ENOMEM; - - err = wprobe_send_msg(msg, save_link_handler, &cb); - if (err < 0) - return err; - - list_for_each_entry_safe(l, tmp, &cb.old_list, list) { - list_del(&l->list); - free(l); - } - - return 0; -} - -void -wprobe_measure(const char *ifname) -{ - struct nl_msg *msg; - - msg = wprobe_new_msg(ifname, WPROBE_CMD_MEASURE, false); - if (!msg) - return; - - wprobe_send_msg(msg, NULL, NULL); -} - -struct wprobe_request_cb { - struct list_head *list; - struct list_head old_list; - char *addr; -}; - -static int -save_attrdata_handler(struct nl_msg *msg, void *arg) -{ - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct wprobe_request_cb *cb = arg; - struct wprobe_attribute *attr; - int type, id; - - nla_parse(tb, WPROBE_ATTR_LAST, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), attribute_policy); - - if (!tb[WPROBE_ATTR_ID]) - return -1; - - if (!tb[WPROBE_ATTR_TYPE]) - return -1; - - id = nla_get_u32(tb[WPROBE_ATTR_ID]); - list_for_each_entry(attr, &cb->old_list, list) { - if (attr->id == id) - goto found; - } - /* not found */ - return -1; - -found: - list_del_init(&attr->list); - - type = nla_get_u8(tb[WPROBE_ATTR_TYPE]); - if (type != attr->type) { - DPRINTF("WARNING: type mismatch for %s attribute '%s' (%d != %d)\n", - (cb->addr ? "link" : "global"), - attr->name, - type, attr->type); - goto out; - } - - if ((type < WPROBE_VAL_STRING) || - (type > WPROBE_VAL_U64)) - goto out; - - memset(&attr->val, 0, sizeof(attr->val)); - -#define HANDLE_INT_TYPE(_idx, _type) \ - case WPROBE_VAL_S##_type: \ - case WPROBE_VAL_U##_type: \ - attr->val.U##_type = nla_get_u##_type(tb[_idx]); \ - break - - switch(type) { - HANDLE_INT_TYPE(type, 8); - HANDLE_INT_TYPE(type, 16); - HANDLE_INT_TYPE(type, 32); - HANDLE_INT_TYPE(type, 64); - case WPROBE_VAL_STRING: - /* unimplemented */ - break; - } -#undef HANDLE_TYPE - - if (attr->flags & WPROBE_F_KEEPSTAT) { - if (tb[WPROBE_VAL_SUM]) - attr->val.s = nla_get_u64(tb[WPROBE_VAL_SUM]); - - if (tb[WPROBE_VAL_SUM_SQ]) - attr->val.ss = nla_get_u64(tb[WPROBE_VAL_SUM_SQ]); - - if (tb[WPROBE_VAL_SAMPLES]) - attr->val.n = nla_get_u32(tb[WPROBE_VAL_SAMPLES]); - - if (attr->val.n > 0) { - float avg = ((float) attr->val.s) / attr->val.n; - float stdev = sqrt((((float) attr->val.ss) / attr->val.n) - (avg * avg)); - attr->val.avg = avg; - attr->val.stdev = stdev; - } - } - -out: - list_add_tail(&attr->list, cb->list); - return 0; -} - - -int -wprobe_request_data(const char *ifname, struct list_head *attrs, const unsigned char *addr, int scale) -{ - struct wprobe_request_cb cb; - struct nl_msg *msg; - int err; - - msg = wprobe_new_msg(ifname, WPROBE_CMD_GET_INFO, true); - if (!msg) - return -ENOMEM; - - if (scale < 0) - NLA_PUT_U32(msg, WPROBE_ATTR_FLAGS, WPROBE_F_RESET); - else if (scale > 0) - NLA_PUT_U32(msg, WPROBE_ATTR_SCALE, scale); - - if (addr) - NLA_PUT(msg, WPROBE_ATTR_MAC, 6, addr); - -nla_put_failure: - INIT_LIST_HEAD(&cb.old_list); - list_splice_init(attrs, &cb.old_list); - cb.list = attrs; - - err = wprobe_send_msg(msg, save_attrdata_handler, &cb); - list_splice(&cb.old_list, attrs->prev); - return err; -} - - diff --git a/package/wprobe/src/user/wprobe.h b/package/wprobe/src/user/wprobe.h index e0c33faef2..706facc808 100644 --- a/package/wprobe/src/user/wprobe.h +++ b/package/wprobe/src/user/wprobe.h @@ -87,57 +87,127 @@ struct wprobe_link { unsigned char addr[6]; }; -/** - * wprobe_init: initialize internal data structures and connect to the wprobe netlink api - */ -extern int wprobe_init(void); +struct wprobe_filter_item { + char name[32]; + uint64_t rx; + uint64_t tx; +}; -/** - * wprobe_free: free all internally allocated data structures - */ -extern void wprobe_free(void); +struct wprobe_iface_ops; +struct wprobe_iface { + const struct wprobe_iface_ops *ops; + + int sockfd; + const char *ifname; + unsigned int genl_family; + char addr[6]; + + struct list_head global_attr; + struct list_head link_attr; + struct list_head links; + + /* config */ + int interval; + int scale_min; + int scale_max; + int scale_m; + int scale_d; + + /* filter */ + void *filter; + + /* filter_len: + * set to -1 to drop the current filter + * automatically reset to 0 after config apply + */ + int filter_len; +}; + +typedef void (*wprobe_filter_cb)(void *arg, const char *group, struct wprobe_filter_item *items, int n_items); +extern int wprobe_port; /** * wprobe_update_links: get a list of all link partners - * @ifname: name of the wprobe interface + * @dev: wprobe device structure * @list: linked list for storing link descriptions * * when wprobe_update_links is called multiple times, the linked list * is updated with new link partners, old entries are automatically expired */ -extern int wprobe_update_links(const char *ifname, struct list_head *list); +extern int wprobe_update_links(struct wprobe_iface *dev); + +/** + * wprobe_dump_filters: dump all layer 2 filter counters + * @dev: wprobe device structure + * @cb: callback (called once per filter group) + * @arg: user argument for the callback + */ +extern int wprobe_dump_filters(struct wprobe_iface *dev, wprobe_filter_cb cb, void *arg); /** * wprobe_measure: start a measurement request for all global attributes - * @ifname: name of the wprobe interface + * @dev: wprobe device structure * * not all attributes are automatically filled with data, since for some * it may be desirable to control the sampling interval from user space * you can use this function to do that. */ -extern void wprobe_measure(const char *ifname); +extern int wprobe_measure(struct wprobe_iface *dev); /** - * wprobe_dump_attributes: create a linked list of available attributes + * wprobe_get_dev: get a handle to a local wprobe device * @ifname: name of the wprobe interface - * @link: false: get the list of global attributes; true: get the list of per-link attributes - * @list: linked list to store the attributes in - * @addr: buffer to store the interface's mac address in (optional) * - * attributes must be freed by the caller + * queries the wprobe interface for all attributes + * must be freed with wprobe_free_dev */ -extern int wprobe_dump_attributes(const char *ifname, bool link, struct list_head *list, char *addr); +extern struct wprobe_iface *wprobe_get_dev(const char *ifname); + +/** + * wprobe_get_auto: get a handle to a local or remote wprobe device + * @arg: pointer to the wprobe device, either (local) or : (remote) + */ +extern struct wprobe_iface *wprobe_get_auto(const char *arg, char **err); + +/** + * wprobe_get_dev: free all device information + * @dev: wprobe device structure + */ +extern void wprobe_free_dev(struct wprobe_iface *dev); + +/** + * wprobe_apply_config: apply configuration data + * @dev: wprobe device structure + * + * uploads all configuration values from @dev that are not set to -1 + */ +extern int wprobe_apply_config(struct wprobe_iface *dev); /** * wprobe_request_data: request new sampling values for the given list of attributes - * @ifname: name of the wprobe interface - * @attrs: attribute list + * @dev: wprobe device structure * @addr: (optional) mac address of the link partner - * @scale: scale down values by a factor (scale < 0: reset statistics entirely) * - * if addr is unset, attrs must point to the list of global attributes, - * if addr is set, attrs must point to the list of per-link attributes + * if addr is unset, global values are stored in the global attributes list + * if addr is set, per-link values for the given address are stored in the link attributes list + */ +extern int wprobe_request_data(struct wprobe_iface *dev, const unsigned char *addr); + +/** + * wprobe_server_init: send a wprobe server init message to a server's client socket + * @socket: socket of the connection to the client + */ +extern int wprobe_server_init(int socket); + +/** + * wprobe_server_handle: read a request from the client socket, process it, send the response + * @socket: socket of the connection to the client + */ +extern int wprobe_server_handle(int socket); + +/** + * wprobe_server_done: release memory allocated for the server connection */ -extern int wprobe_request_data(const char *ifname, struct list_head *attrs, const unsigned char *addr, int scale); +extern void wprobe_server_done(void); #endif