My athn RA patch resulted in mixed test reports. People running the
device in client mode were happy all around, while others using the
device as an access point reported mixed results. I have now figured
out what goes wrong in hostap mode.

When auto-selecing a channel an athn(4) access point may end up running
on a different channel than it should be. E.g. the athn device's radio
might be tuned to channel 1 while net80211 has selected channel 2.
Since neighbouring 802.11 channels overlap the AP might still appear
to work somewhat, and clients will experience a lot of packet loss.

Additionally, net80211 will run the hostap in MODE_AUTO if no mode
was configured, which causes issues with selecting the set of 11a/b/g
rates to use and also reslts in association problems (e.g. an iwn client
will not manage to connect to the AP).

As a workaround, both a channel and an operating mode can be set
explicitly, like this:

        ifconfig athn0 nwid foo wpakey mysecretkey
        ifconfig athn0 mediaopt hostap mode 11n chan 1
        ifconfig athn0 up

This patch fixes the auto-selection case.
1. Make athn actually configure the channel channel selected by net80211.
   This is currently broken in hostap mode and monitor mode.
2. Fix the net80211 operating mode when the hostap comes up.

With this, an athn hostap will work correctly after:

        ifconfig athn0 nwid foo wpakey mysecretkey
        ifconfig athn0 mediaopt hostap
        ifconfig athn0 up

diff 85f491dae6d227f10e75412df0c572c8e5b04442 /usr/src
blob - d20bb5615c20f30c2d7bc1bc4bfc66370dfeb232
file + sys/dev/ic/athn.c
--- sys/dev/ic/athn.c
+++ sys/dev/ic/athn.c
@@ -2660,9 +2660,19 @@ athn_newstate(struct ieee80211com *ic, enum ieee80211_
                break;
        case IEEE80211_S_RUN:
                athn_set_led(sc, 1);
-
-               if (ic->ic_opmode == IEEE80211_M_MONITOR)
+#ifndef IEEE80211_STA_ONLY
+               if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
+                       error = athn_switch_chan(sc, ic->ic_bss->ni_chan, NULL);
+                       if (error != 0)
+                               return (error);
+               } else
+#endif
+               if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+                       error = athn_switch_chan(sc, ic->ic_bss->ni_chan, NULL);
+                       if (error != 0)
+                               return (error);
                        break;
+               }
 
                /* Fake a join to initialize the Tx rate. */
                athn_newassoc(ic, ic->ic_bss, 1);
blob - 610db9f671d581f847f227bbeeca30312d8d53aa
file + sys/net80211/ieee80211_node.c
--- sys/net80211/ieee80211_node.c
+++ sys/net80211/ieee80211_node.c
@@ -903,6 +903,7 @@ ieee80211_next_scan(struct ifnet *ifp)
 void
 ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
 {
+       enum ieee80211_phymode mode;
        struct ieee80211_node *ni;
        struct ifnet *ifp = &ic->ic_if;
 
@@ -911,7 +912,25 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct 
                printf("%s: creating ibss\n", ifp->if_xname);
        ic->ic_flags |= IEEE80211_F_SIBSS;
        ni->ni_chan = chan;
-       ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
+       if ((ic->ic_flags & IEEE80211_F_VHTON) && IEEE80211_IS_CHAN_5GHZ(chan))
+               mode = IEEE80211_MODE_11AC;
+       else if (ic->ic_flags & IEEE80211_F_HTON)
+               mode = IEEE80211_MODE_11N;
+       else
+               mode = ieee80211_chan2mode(ic, ni->ni_chan);
+       ieee80211_setmode(ic, mode);
+       /* Pick an appropriate mode for supported legacy rates. */
+       if (ic->ic_curmode == IEEE80211_MODE_11AC) {
+               mode = IEEE80211_MODE_11A;
+       } else if (ic->ic_curmode == IEEE80211_MODE_11N) {
+               if (IEEE80211_IS_CHAN_5GHZ(chan))
+                       mode = IEEE80211_MODE_11A;
+               else
+                       mode = IEEE80211_MODE_11G;
+       } else {
+               mode = ic->ic_curmode;
+       }
+       ni->ni_rates = ic->ic_sup_rates[mode];
        ni->ni_txrate = 0;
        IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr);
        IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);

Reply via email to