Author: avos
Date: Sat Jan 12 14:57:12 2019
New Revision: 342966
URL: https://svnweb.freebsd.org/changeset/base/342966

Log:
  net80211: fix possible panic for some drivers after r342211
  
  Check if rate control structures were allocated before trying to
  access them in various places; this was possible before on
  allocation failure (unlikely), but was revealed after r342211
  where allocation was deferred.
  
  In case if driver uses wlan_amrr(4) and it is loaded it
  is possible to reproduce the panic via
  
  sysctl net.wlan.<number>.rate_stats
  
  (for wlan0 the number will be 0).
  
  Tested with: RTL8188EE, AP mode + RTL8188CUS, STA mode.
  
  MFC after:    3 days

Modified:
  head/sys/net80211/ieee80211_amrr.c
  head/sys/net80211/ieee80211_rssadapt.c

Modified: head/sys/net80211/ieee80211_amrr.c
==============================================================================
--- head/sys/net80211/ieee80211_amrr.c  Sat Jan 12 12:57:32 2019        
(r342965)
+++ head/sys/net80211/ieee80211_amrr.c  Sat Jan 12 14:57:12 2019        
(r342966)
@@ -104,6 +104,9 @@ amrr_setinterval(const struct ieee80211vap *vap, int m
        struct ieee80211_amrr *amrr = vap->iv_rs;
        int t;
 
+       if (!amrr)
+               return;
+
        if (msecs < 100)
                msecs = 100;
        t = msecs_to_ticks(msecs);
@@ -166,6 +169,12 @@ amrr_node_init(struct ieee80211_node *ni)
        struct ieee80211_amrr_node *amn;
        uint8_t rate;
 
+       if (!amrr) {
+               if_printf(vap->iv_ifp, "ratectl structure was not allocated, "
+                   "per-node structure allocation skipped\n");
+               return;
+       }
+
        if (ni->ni_rctls == NULL) {
                ni->ni_rctls = amn = IEEE80211_MALLOC(sizeof(struct 
ieee80211_amrr_node),
                    M_80211_RATECTL, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
@@ -327,10 +336,19 @@ static int
 amrr_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg 
__unused)
 {
        struct ieee80211_amrr_node *amn = ni->ni_rctls;
-       struct ieee80211_amrr *amrr = amn->amn_amrr;
+       struct ieee80211_amrr *amrr;
        const struct ieee80211_rateset *rs = NULL;
        int rix;
 
+       /* XXX should return -1 here, but drivers may not expect this... */
+       if (!amn)
+       {
+               ni->ni_txrate = ni->ni_rates.rs_rates[0];
+               return 0;
+       }
+
+       amrr = amn->amn_amrr;
+
        /* 11n or not? Pick the right rateset */
        if (amrr_node_is_11n(ni)) {
                /* XXX ew */
@@ -369,6 +387,9 @@ amrr_tx_complete(const struct ieee80211_node *ni,
        struct ieee80211_amrr_node *amn = ni->ni_rctls;
        int retries;
 
+       if (!amn)
+               return;
+
        retries = 0;
        if (status->flags & IEEE80211_RATECTL_STATUS_LONG_RETRY)
                retries = status->long_retries;
@@ -386,6 +407,9 @@ amrr_tx_update_cb(void *arg, struct ieee80211_node *ni
        struct ieee80211_amrr_node *amn = ni->ni_rctls;
        int txcnt, success, retrycnt;
 
+       if (!amn)
+               return;
+
        txcnt = stats->nframes;
        success = stats->nsuccess;
        retrycnt = 0;
@@ -420,9 +444,12 @@ amrr_sysctl_interval(SYSCTL_HANDLER_ARGS)
 {
        struct ieee80211vap *vap = arg1;
        struct ieee80211_amrr *amrr = vap->iv_rs;
-       int msecs = ticks_to_msecs(amrr->amrr_interval);
-       int error;
+       int msecs, error;
 
+       if (!amrr)
+               return ENOMEM;
+
+       msecs = ticks_to_msecs(amrr->amrr_interval);
        error = sysctl_handle_int(oidp, &msecs, 0, req);
        if (error || !req->newptr)
                return error;
@@ -436,6 +463,9 @@ amrr_sysctlattach(struct ieee80211vap *vap,
 {
        struct ieee80211_amrr *amrr = vap->iv_rs;
 
+       if (!amrr)
+               return;
+
        SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
            "amrr_rate_interval", CTLTYPE_INT | CTLFLAG_RW, vap,
            0, amrr_sysctl_interval, "I", "amrr operation interval (ms)");
@@ -456,6 +486,9 @@ amrr_node_stats(struct ieee80211_node *ni, struct sbuf
        struct ieee80211_rateset *rs;
 
        /* XXX TODO: check locking? */
+
+       if (!amn)
+               return;
 
        /* XXX TODO: this should be a method */
        if (amrr_node_is_11n(ni)) {

Modified: head/sys/net80211/ieee80211_rssadapt.c
==============================================================================
--- head/sys/net80211/ieee80211_rssadapt.c      Sat Jan 12 12:57:32 2019        
(r342965)
+++ head/sys/net80211/ieee80211_rssadapt.c      Sat Jan 12 14:57:12 2019        
(r342966)
@@ -119,6 +119,9 @@ rssadapt_setinterval(const struct ieee80211vap *vap, i
        struct ieee80211_rssadapt *rs = vap->iv_rs;
        int t;
 
+       if (!rs)
+               return;
+
        if (msecs < 100)
                msecs = 100;
        t = msecs_to_ticks(msecs);
@@ -177,6 +180,12 @@ rssadapt_node_init(struct ieee80211_node *ni)
        struct ieee80211_rssadapt *rsa = vap->iv_rs;
        const struct ieee80211_rateset *rs = &ni->ni_rates;
 
+       if (!rsa) {
+               if_printf(vap->iv_ifp, "ratectl structure was not allocated, "
+                   "per-node structure allocation skipped\n");
+               return;
+       }
+
        if (ni->ni_rctls == NULL) {
                ni->ni_rctls = ra = 
                    IEEE80211_MALLOC(sizeof(struct ieee80211_rssadapt_node),
@@ -231,10 +240,18 @@ rssadapt_rate(struct ieee80211_node *ni, void *arg __u
 {
        struct ieee80211_rssadapt_node *ra = ni->ni_rctls;
        u_int pktlen = iarg;
-       const struct ieee80211_rateset *rs = &ra->ra_rates;
+       const struct ieee80211_rateset *rs;
        uint16_t (*thrs)[IEEE80211_RATE_SIZE];
        int rix, rssi;
 
+       /* XXX should return -1 here, but drivers may not expect this... */
+       if (!ra)
+       {
+               ni->ni_txrate = ni->ni_rates.rs_rates[0];
+               return 0;
+       }
+
+       rs = &ra->ra_rates;
        if ((ticks - ra->ra_ticks) > ra->ra_rs->interval) {
                rssadapt_updatestats(ra);
                ra->ra_ticks = ticks;
@@ -320,6 +337,9 @@ rssadapt_tx_complete(const struct ieee80211_node *ni,
        struct ieee80211_rssadapt_node *ra = ni->ni_rctls;
        int pktlen, rssi;
 
+       if (!ra)
+               return;
+
        if ((status->flags &
            (IEEE80211_RATECTL_STATUS_PKTLEN|IEEE80211_RATECTL_STATUS_RSSI)) !=
            (IEEE80211_RATECTL_STATUS_PKTLEN|IEEE80211_RATECTL_STATUS_RSSI))
@@ -344,9 +364,12 @@ rssadapt_sysctl_interval(SYSCTL_HANDLER_ARGS)
 {
        struct ieee80211vap *vap = arg1;
        struct ieee80211_rssadapt *rs = vap->iv_rs;
-       int msecs = ticks_to_msecs(rs->interval);
-       int error;
+       int msecs, error;
 
+       if (!rs)
+               return ENOMEM;
+
+       msecs = ticks_to_msecs(rs->interval);
        error = sysctl_handle_int(oidp, &msecs, 0, req);
        if (error || !req->newptr)
                return error;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to