ieee80211_media_change() will return ENETRESET if the interface is
switched into 11a/b/g/n mode from any other mode.
ifmedia_ioctl() considers this an error and reverts ifmedia's state
to the previous setting, even though net80211 has actually succeeded.
The result is that if_media and net80211 have conflicting ideas about the
current media mode of the interface, which can be observed with ifconfig.

The commands below were run while the interface is down.
Note how 'ifconfig mode' needs to be run twice to get consistent results:

        # ifconfig iwm0 | grep media:                        
                media: IEEE802.11 autoselect
        # ifconfig iwm0 mode 11b                             
        # ifconfig iwm0 | grep media: 
                media: IEEE802.11 autoselect (autoselect mode 11b)
        # ifconfig iwm0 mode 11b      
        # ifconfig iwm0 | grep media: 
                media: IEEE802.11 autoselect mode 11b
        # ifconfig iwm0 mode 11g      
        # ifconfig iwm0 | grep media: 
                media: IEEE802.11 autoselect mode 11b (autoselect mode 11g)
        # ifconfig iwm0 mode 11g      
        # ifconfig iwm0 | grep media: 
                media: IEEE802.11 autoselect mode 11g

The diff below fixes this issue for me:

        # ifconfig iwm0 | grep media:                        
                media: IEEE802.11 autoselect
        # ifconfig iwm0 mode 11b                             
        # ifconfig iwm0 | grep media: 
                media: IEEE802.11 autoselect mode 11b
        # ifconfig iwm0 mode 11g      
        # ifconfig iwm0 | grep media: 
                media: IEEE802.11 autoselect mode 11g

OK?

diff 23a4e4a1e8913390694e35727d2131b2938cb472 /usr/src
blob - 5168b074cbdd5a95f9945134cdd47c0649ad76a1
file + sys/net/if_media.c
--- sys/net/if_media.c
+++ sys/net/if_media.c
@@ -277,7 +277,7 @@ ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, st
                ifm->ifm_cur = match;
                ifm->ifm_media = newmedia;
                error = (*ifm->ifm_change)(ifp);
-               if (error) {
+               if (error && error != ENETRESET) {
                        ifm->ifm_cur = oldentry;
                        ifm->ifm_media = oldmedia;
                }

Reply via email to