head 1.61; access; symbols netbsd-10-0-RC6:1.61 netbsd-10-0-RC5:1.61 netbsd-10-0-RC4:1.61 netbsd-10-0-RC3:1.61 netbsd-10-0-RC2:1.61 thorpej-ifq:1.61.0.8 thorpej-ifq-base:1.61 thorpej-altq-separation:1.61.0.6 thorpej-altq-separation-base:1.61 netbsd-10-0-RC1:1.61 netbsd-10:1.61.0.4 netbsd-10-base:1.61 bouyer-sunxi-drm:1.61.0.2 bouyer-sunxi-drm-base:1.61 netbsd-9-3-RELEASE:1.56 thorpej-i2c-spi-conf2:1.60.0.16 thorpej-i2c-spi-conf2-base:1.60 thorpej-futex2:1.60.0.14 thorpej-futex2-base:1.60 thorpej-cfargs2:1.60.0.12 thorpej-cfargs2-base:1.60 cjep_sun2x-base1:1.60 cjep_sun2x:1.60.0.10 cjep_sun2x-base:1.60 cjep_staticlib_x-base1:1.60 netbsd-9-2-RELEASE:1.56 cjep_staticlib_x:1.60.0.8 cjep_staticlib_x-base:1.60 thorpej-i2c-spi-conf:1.60.0.6 thorpej-i2c-spi-conf-base:1.60 thorpej-cfargs:1.60.0.4 thorpej-cfargs-base:1.60 thorpej-futex:1.60.0.2 thorpej-futex-base:1.60 netbsd-9-1-RELEASE:1.56 bouyer-xenpvh-base2:1.59 phil-wifi-20200421:1.59 bouyer-xenpvh-base1:1.59 phil-wifi-20200411:1.59 bouyer-xenpvh:1.59.0.2 bouyer-xenpvh-base:1.59 is-mlppp:1.58.0.2 is-mlppp-base:1.58 phil-wifi-20200406:1.59 netbsd-8-2-RELEASE:1.56 ad-namecache-base3:1.58 netbsd-9-0-RELEASE:1.56 netbsd-9-0-RC2:1.56 ad-namecache-base2:1.57 ad-namecache-base1:1.57 ad-namecache:1.57.0.2 ad-namecache-base:1.57 netbsd-9-0-RC1:1.56 phil-wifi-20191119:1.57 netbsd-9:1.56.0.22 netbsd-9-base:1.56 phil-wifi-20190609:1.56 netbsd-8-1-RELEASE:1.56 netbsd-8-1-RC1:1.56 isaki-audio2:1.56.0.20 isaki-audio2-base:1.56 pgoyette-compat-merge-20190127:1.56 pgoyette-compat-20190127:1.56 pgoyette-compat-20190118:1.56 pgoyette-compat-1226:1.56 pgoyette-compat-1126:1.56 pgoyette-compat-1020:1.56 pgoyette-compat-0930:1.56 pgoyette-compat-0906:1.56 netbsd-7-2-RELEASE:1.54 pgoyette-compat-0728:1.56 netbsd-8-0-RELEASE:1.56 phil-wifi-freebsd-base:1.56.18.1 phil-wifi:1.56.0.18 phil-wifi-base:1.56 pgoyette-compat-0625:1.56 netbsd-8-0-RC2:1.56 pgoyette-compat-0521:1.56 pgoyette-compat-0502:1.56 pgoyette-compat-0422:1.56 netbsd-8-0-RC1:1.56 pgoyette-compat-0415:1.56 pgoyette-compat-0407:1.56 pgoyette-compat-0330:1.56 pgoyette-compat-0322:1.56 pgoyette-compat-0315:1.56 netbsd-7-1-2-RELEASE:1.54 pgoyette-compat:1.56.0.16 pgoyette-compat-base:1.56 netbsd-7-1-1-RELEASE:1.54 tls-maxphys-base-20171202:1.56 matt-nb8-mediatek:1.56.0.14 matt-nb8-mediatek-base:1.56 nick-nhusb-base-20170825:1.56 perseant-stdc-iso10646:1.56.0.12 perseant-stdc-iso10646-base:1.56 netbsd-8:1.56.0.10 netbsd-8-base:1.56 prg-localcount2-base3:1.56 prg-localcount2-base2:1.56 prg-localcount2-base1:1.56 prg-localcount2:1.56.0.8 prg-localcount2-base:1.56 pgoyette-localcount-20170426:1.56 bouyer-socketcan-base1:1.56 jdolecek-ncq:1.56.0.6 jdolecek-ncq-base:1.56 pgoyette-localcount-20170320:1.56 netbsd-7-1:1.54.0.18 netbsd-7-1-RELEASE:1.54 netbsd-7-1-RC2:1.54 nick-nhusb-base-20170204:1.56 netbsd-7-nhusb-base-20170116:1.54 bouyer-socketcan:1.56.0.4 bouyer-socketcan-base:1.56 pgoyette-localcount-20170107:1.56 netbsd-7-1-RC1:1.54 nick-nhusb-base-20161204:1.56 pgoyette-localcount-20161104:1.56 netbsd-7-0-2-RELEASE:1.54 nick-nhusb-base-20161004:1.56 localcount-20160914:1.56 netbsd-7-nhusb:1.54.0.16 netbsd-7-nhusb-base:1.54 pgoyette-localcount-20160806:1.56 pgoyette-localcount-20160726:1.56 pgoyette-localcount:1.56.0.2 pgoyette-localcount-base:1.56 nick-nhusb-base-20160907:1.56 nick-nhusb-base-20160529:1.56 netbsd-7-0-1-RELEASE:1.54 nick-nhusb-base-20160422:1.56 nick-nhusb-base-20160319:1.56 nick-nhusb-base-20151226:1.56 netbsd-7-0:1.54.0.14 netbsd-7-0-RELEASE:1.54 nick-nhusb-base-20150921:1.56 netbsd-7-0-RC3:1.54 netbsd-7-0-RC2:1.54 netbsd-7-0-RC1:1.54 nick-nhusb-base-20150606:1.55 nick-nhusb-base-20150406:1.55 nick-nhusb:1.55.0.2 nick-nhusb-base:1.55 netbsd-5-2-3-RELEASE:1.48 netbsd-5-1-5-RELEASE:1.48 netbsd-6-0-6-RELEASE:1.53 netbsd-6-1-5-RELEASE:1.53 netbsd-7:1.54.0.12 netbsd-7-base:1.54 yamt-pagecache-base9:1.54 yamt-pagecache-tag8:1.53 netbsd-6-1-4-RELEASE:1.53 netbsd-6-0-5-RELEASE:1.53 tls-earlyentropy:1.54.0.10 tls-earlyentropy-base:1.54 riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.54 riastradh-drm2-base3:1.54 netbsd-6-1-3-RELEASE:1.53 netbsd-6-0-4-RELEASE:1.53 netbsd-5-2-2-RELEASE:1.48 netbsd-5-1-4-RELEASE:1.48 netbsd-6-1-2-RELEASE:1.53 netbsd-6-0-3-RELEASE:1.53 netbsd-5-2-1-RELEASE:1.48 netbsd-5-1-3-RELEASE:1.48 rmind-smpnet-nbase:1.54 netbsd-6-1-1-RELEASE:1.53 riastradh-drm2-base2:1.54 riastradh-drm2-base1:1.54 riastradh-drm2:1.54.0.8 riastradh-drm2-base:1.54 rmind-smpnet:1.54.0.6 rmind-smpnet-base:1.54 netbsd-6-1:1.53.0.24 netbsd-6-0-2-RELEASE:1.53 netbsd-6-1-RELEASE:1.53 khorben-n900:1.54.0.4 netbsd-6-1-RC4:1.53 netbsd-6-1-RC3:1.53 agc-symver:1.54.0.2 agc-symver-base:1.54 netbsd-6-1-RC2:1.53 netbsd-6-1-RC1:1.53 yamt-pagecache-base8:1.53 netbsd-5-2:1.48.0.40 netbsd-6-0-1-RELEASE:1.53 yamt-pagecache-base7:1.53 netbsd-5-2-RELEASE:1.48 netbsd-5-2-RC1:1.48 matt-nb6-plus-nbase:1.53 yamt-pagecache-base6:1.53 netbsd-6-0:1.53.0.20 netbsd-6-0-RELEASE:1.53 netbsd-6-0-RC2:1.53 tls-maxphys:1.53.0.18 tls-maxphys-base:1.54 matt-nb6-plus:1.53.0.16 matt-nb6-plus-base:1.53 netbsd-6-0-RC1:1.53 jmcneill-usbmp-base10:1.53 yamt-pagecache-base5:1.53 jmcneill-usbmp-base9:1.53 yamt-pagecache-base4:1.53 jmcneill-usbmp-base8:1.53 jmcneill-usbmp-base7:1.53 jmcneill-usbmp-base6:1.53 jmcneill-usbmp-base5:1.53 jmcneill-usbmp-base4:1.53 jmcneill-usbmp-base3:1.53 jmcneill-usbmp-pre-base2:1.53 jmcneill-usbmp-base2:1.53 netbsd-6:1.53.0.14 netbsd-6-base:1.53 netbsd-5-1-2-RELEASE:1.48 netbsd-5-1-1-RELEASE:1.48 jmcneill-usbmp:1.53.0.12 jmcneill-usbmp-base:1.53 jmcneill-audiomp3:1.53.0.10 jmcneill-audiomp3-base:1.53 yamt-pagecache-base3:1.53 yamt-pagecache-base2:1.53 yamt-pagecache:1.53.0.8 yamt-pagecache-base:1.53 rmind-uvmplock-nbase:1.53 cherry-xenmp:1.53.0.6 cherry-xenmp-base:1.53 bouyer-quota2-nbase:1.53 bouyer-quota2:1.53.0.4 bouyer-quota2-base:1.53 jruoho-x86intr:1.53.0.2 jruoho-x86intr-base:1.53 matt-mips64-premerge-20101231:1.53 matt-nb5-mips64-premerge-20101231:1.48 matt-nb5-pq3:1.48.0.38 matt-nb5-pq3-base:1.48 netbsd-5-1:1.48.0.36 netbsd-5-1-RELEASE:1.48 uebayasi-xip-base4:1.53 uebayasi-xip-base3:1.53 yamt-nfs-mp-base11:1.53 netbsd-5-1-RC4:1.48 matt-nb5-mips64-k15:1.48 uebayasi-xip-base2:1.53 yamt-nfs-mp-base10:1.53 netbsd-5-1-RC3:1.48 netbsd-5-1-RC2:1.48 uebayasi-xip-base1:1.53 netbsd-5-1-RC1:1.48 rmind-uvmplock:1.50.0.4 rmind-uvmplock-base:1.53 yamt-nfs-mp-base9:1.50 uebayasi-xip:1.50.0.2 uebayasi-xip-base:1.50 netbsd-5-0-2-RELEASE:1.48 matt-nb5-mips64-premerge-20091211:1.48 matt-premerge-20091211:1.49 yamt-nfs-mp-base8:1.49 matt-nb5-mips64-u2-k2-k4-k7-k8-k9:1.48 matt-nb4-mips64-k7-u2a-k9b:1.48 matt-nb5-mips64-u1-k1-k5:1.48 yamt-nfs-mp-base7:1.49 matt-nb5-mips64:1.48.0.34 netbsd-5-0-1-RELEASE:1.48 jymxensuspend-base:1.49 yamt-nfs-mp-base6:1.49 yamt-nfs-mp-base5:1.49 yamt-nfs-mp-base4:1.49 jym-xensuspend-nbase:1.49 yamt-nfs-mp-base3:1.49 nick-hppapmap-base4:1.49 nick-hppapmap-base3:1.49 netbsd-5-0:1.48.0.32 netbsd-5-0-RELEASE:1.48 netbsd-5-0-RC4:1.48 netbsd-5-0-RC3:1.48 nick-hppapmap-base2:1.49 netbsd-5-0-RC2:1.48 jym-xensuspend:1.49.0.2 jym-xensuspend-base:1.49 netbsd-5-0-RC1:1.48 haad-dm-base2:1.48 haad-nbase2:1.48 ad-audiomp2:1.48.0.30 ad-audiomp2-base:1.48 netbsd-5:1.48.0.28 netbsd-5-base:1.48 nick-hppapmap:1.48.0.26 nick-hppapmap-base:1.49 matt-mips64-base2:1.48 matt-mips64:1.47.0.36 haad-dm-base1:1.48 wrstuden-revivesa-base-4:1.48 netbsd-4-0-1-RELEASE:1.47 wrstuden-revivesa-base-3:1.48 wrstuden-revivesa-base-2:1.48 wrstuden-fixsa-newbase:1.47 nick-csl-alignment-base5:1.47 haad-dm:1.48.0.24 haad-dm-base:1.48 wrstuden-revivesa-base-1:1.48 simonb-wapbl-nbase:1.48 yamt-pf42-base4:1.48 simonb-wapbl:1.48.0.22 simonb-wapbl-base:1.48 yamt-pf42-base3:1.48 hpcarm-cleanup-nbase:1.48 yamt-pf42-baseX:1.48 yamt-pf42-base2:1.48 yamt-nfs-mp-base2:1.48 wrstuden-revivesa:1.48.0.20 wrstuden-revivesa-base:1.48 yamt-nfs-mp:1.48.0.18 yamt-nfs-mp-base:1.48 yamt-pf42:1.48.0.16 yamt-pf42-base:1.48 ad-socklock-base1:1.48 yamt-lazymbuf-base15:1.48 yamt-lazymbuf-base14:1.48 keiichi-mipv6-nbase:1.48 mjf-devfs2:1.48.0.14 mjf-devfs2-base:1.49 nick-net80211-sync:1.48.0.12 nick-net80211-sync-base:1.48 keiichi-mipv6:1.48.0.10 keiichi-mipv6-base:1.48 bouyer-xeni386-merge1:1.48 matt-armv6-prevmlocking:1.47 wrstuden-fixsa-base-1:1.47 vmlocking2-base3:1.48 netbsd-4-0:1.47.0.34 netbsd-4-0-RELEASE:1.47 bouyer-xeni386-nbase:1.48 yamt-kmem-base3:1.48 cube-autoconf:1.48.0.8 cube-autoconf-base:1.48 yamt-kmem-base2:1.48 bouyer-xeni386:1.48.0.6 bouyer-xeni386-base:1.48 yamt-kmem:1.48.0.4 yamt-kmem-base:1.48 vmlocking2-base2:1.48 reinoud-bufcleanup-nbase:1.48 vmlocking2:1.48.0.2 vmlocking2-base1:1.48 netbsd-4-0-RC5:1.47 matt-nb4-arm:1.47.0.32 matt-nb4-arm-base:1.47 matt-armv6-nbase:1.48 jmcneill-base:1.47 netbsd-4-0-RC4:1.47 mjf-devfs:1.47.0.30 mjf-devfs-base:1.48 bouyer-xenamd64-base2:1.47 vmlocking-nbase:1.48 yamt-x86pmap-base4:1.47 bouyer-xenamd64:1.47.0.28 bouyer-xenamd64-base:1.47 netbsd-4-0-RC3:1.47 yamt-x86pmap-base3:1.47 yamt-x86pmap-base2:1.47 netbsd-4-0-RC2:1.47 yamt-x86pmap:1.47.0.26 yamt-x86pmap-base:1.47 netbsd-4-0-RC1:1.47 matt-armv6:1.47.0.24 matt-armv6-base:1.48 matt-mips64-base:1.47 jmcneill-pm:1.47.0.22 jmcneill-pm-base:1.48 hpcarm-cleanup:1.47.0.20 hpcarm-cleanup-base:1.48 nick-csl-alignment:1.47.0.18 nick-csl-alignment-base:1.47 netbsd-3-1-1-RELEASE:1.33 netbsd-3-0-3-RELEASE:1.33 yamt-idlelwp-base8:1.47 wrstuden-fixsa:1.47.0.16 wrstuden-fixsa-base:1.47 thorpej-atomic:1.47.0.14 thorpej-atomic-base:1.47 reinoud-bufcleanup:1.47.0.12 reinoud-bufcleanup-base:1.48 mjf-ufs-trans:1.47.0.10 mjf-ufs-trans-base:1.47 vmlocking:1.47.0.8 vmlocking-base:1.47 ad-audiomp:1.47.0.6 ad-audiomp-base:1.47 yamt-idlelwp:1.47.0.4 post-newlock2-merge:1.47 newlock2-nbase:1.47 yamt-splraiseipl-base5:1.47 yamt-splraiseipl-base4:1.47 yamt-splraiseipl-base3:1.47 abandoned-netbsd-4-base:1.45 abandoned-netbsd-4:1.45.0.8 netbsd-3-1:1.33.0.6 netbsd-3-1-RELEASE:1.33 netbsd-3-0-2-RELEASE:1.33 yamt-splraiseipl-base2:1.46 netbsd-3-1-RC4:1.33 yamt-splraiseipl:1.45.0.12 yamt-splraiseipl-base:1.45 netbsd-3-1-RC3:1.33 yamt-pdpolicy-base9:1.45 newlock2:1.45.0.10 newlock2-base:1.47 yamt-pdpolicy-base8:1.45 netbsd-3-1-RC2:1.33 netbsd-3-1-RC1:1.33 yamt-pdpolicy-base7:1.45 netbsd-4:1.47.0.2 netbsd-4-base:1.47 yamt-pdpolicy-base6:1.45 chap-midi-nbase:1.45 netbsd-3-0-1-RELEASE:1.33 gdamore-uart:1.45.0.6 gdamore-uart-base:1.45 simonb-timcounters-final:1.43.6.1 yamt-pdpolicy-base5:1.45 chap-midi:1.45.0.4 chap-midi-base:1.45 yamt-pdpolicy-base4:1.45 yamt-pdpolicy-base3:1.45 peter-altq-base:1.45 peter-altq:1.45.0.2 yamt-pdpolicy-base2:1.45 elad-kernelauth-base:1.45 elad-kernelauth:1.44.0.4 yamt-pdpolicy:1.44.0.2 yamt-pdpolicy-base:1.44 yamt-uio_vmspace-base5:1.43 simonb-timecounters:1.43.0.6 simonb-timecounters-base:1.45 rpaulo-netinet-merge-pcb:1.43.0.4 rpaulo-netinet-merge-pcb-base:1.45 yamt-uio_vmspace:1.43.0.2 netbsd-3-0:1.33.0.4 netbsd-3-0-RELEASE:1.33 netbsd-3-0-RC6:1.33 yamt-readahead-base3:1.42 netbsd-3-0-RC5:1.33 netbsd-3-0-RC4:1.33 netbsd-3-0-RC3:1.33 yamt-readahead-base2:1.41 netbsd-3-0-RC2:1.33 net80211-1-nov-2005:1.1.1.5 yamt-readahead-pervnode:1.40 yamt-readahead-perfile:1.40 yamt-readahead:1.40.0.6 yamt-readahead-base:1.40 netbsd-3-0-RC1:1.33 yamt-vop-base3:1.40 netbsd-2-0-3-RELEASE:1.9.2.2 netbsd-2-1:1.9.2.2.0.4 yamt-vop-base2:1.40 thorpej-vnode-attr:1.40.0.4 thorpej-vnode-attr-base:1.40 netbsd-2-1-RELEASE:1.9.2.2 yamt-vop:1.40.0.2 yamt-vop-base:1.40 netbsd-2-1-RC6:1.9.2.2 netbsd-2-1-RC5:1.9.2.2 netbsd-2-1-RC4:1.9.2.2 netbsd-2-1-RC3:1.9.2.2 netbsd-2-1-RC2:1.9.2.2 netbsd-2-1-RC1:1.9.2.2 net80211-2005-07-11:1.1.1.4 yamt-lazymbuf:1.38.0.2 net80211-2005-05-18:1.1.1.4 yamt-km-base4:1.33 netbsd-2-0-2-RELEASE:1.9.2.2 yamt-km-base3:1.33 netbsd-3:1.33.0.2 netbsd-3-base:1.33 yamt-km-base2:1.32 yamt-km:1.32.0.6 yamt-km-base:1.32 kent-audio2:1.32.0.4 kent-audio2-base:1.33 netbsd-2-0-1-RELEASE:1.9.2.2 kent-audio1-beforemerge:1.32 netbsd-2:1.9.2.2.0.2 netbsd-2-base:1.9.2.2 kent-audio1:1.32.0.2 kent-audio1-base:1.32 netbsd-2-0-RELEASE:1.9.2.2 netbsd-2-0-RC5:1.9.2.2 netbsd-2-0-RC4:1.9.2.2 netbsd-2-0-RC3:1.9.2.2 netbsd-2-0-RC2:1.9.2.2 netbsd-2-0-RC1:1.9.2.2 ktrace-lwp-base:1.42 ktrace-lwp:1.31.0.2 net80211-28-apr-2004:1.1.1.3 netbsd-2-0:1.9.0.2 netbsd-2-0-base:1.9 net80211-12-dec-2003:1.1.1.2 net80211-6-sep-2003:1.1.1.1 net80211-29-aug-2003:1.1.1.1 FreeBSD:1.1.1; locks; strict; comment @ * @; 1.61 date 2021.08.21.11.55.25; author andvar; state Exp; branches; next 1.60; commitid K6z2HL69VCHYIP5D; 1.60 date 2020.10.06.23.51.05; author roy; state Exp; branches; next 1.59; commitid ZCxNSbznoDkJUTqC; 1.59 date 2020.03.15.23.04.51; author thorpej; state Exp; branches; next 1.58; commitid R0dFG2H87iZWgy0C; 1.58 date 2020.02.04.05.46.32; author thorpej; state Exp; branches; next 1.57; commitid WD7VO04IjeNJOjVB; 1.57 date 2019.10.03.17.46.56; author jmcneill; state Exp; branches 1.57.2.1; next 1.56; commitid ey9keKzBunZ2NrFB; 1.56 date 2015.08.24.22.21.26; author pooka; state Exp; branches 1.56.18.1; next 1.55; 1.55 date 2014.10.18.08.33.29; author snj; state Exp; branches 1.55.2.1; next 1.54; 1.54 date 2013.03.21.18.30.09; author christos; state Exp; branches; next 1.53; 1.53 date 2010.04.05.07.22.24; author joerg; state Exp; branches 1.53.8.1 1.53.18.1; next 1.52; 1.52 date 2010.04.02.03.46.50; author dyoung; state Exp; branches; next 1.51; 1.51 date 2010.03.26.17.18.05; author dyoung; state Exp; branches; next 1.50; 1.50 date 2010.01.19.22.08.17; author pooka; state Exp; branches 1.50.2.1 1.50.4.1; next 1.49; 1.49 date 2009.01.10.12.53.45; author cegger; state Exp; branches; next 1.48; 1.48 date 2007.12.01.14.35.51; author jmcneill; state Exp; branches 1.48.12.1 1.48.14.1 1.48.18.1 1.48.26.1; next 1.47; 1.47 date 2006.11.16.01.33.40; author christos; state Exp; branches 1.47.22.1 1.47.24.1 1.47.30.1; next 1.46; 1.46 date 2006.10.12.01.32.30; author christos; state Exp; branches; next 1.45; 1.45 date 2006.03.08.23.46.27; author lukem; state Exp; branches 1.45.10.1 1.45.12.1; next 1.44; 1.44 date 2006.03.02.03.38.48; author dyoung; state Exp; branches 1.44.2.1 1.44.4.1; next 1.43; 1.43 date 2005.12.13.09.28.31; author dyoung; state Exp; branches 1.43.4.1 1.43.6.1; next 1.42; 1.42 date 2005.11.25.17.33.56; author thorpej; state Exp; branches; next 1.41; 1.41 date 2005.11.18.16.40.08; author skrll; state Exp; branches; next 1.40; 1.40 date 2005.07.26.22.52.48; author dyoung; state Exp; branches 1.40.6.1; next 1.39; 1.39 date 2005.07.11.17.15.30; author dyoung; state Exp; branches; next 1.38; 1.38 date 2005.06.26.04.31.51; author dyoung; state Exp; branches 1.38.2.1; next 1.37; 1.37 date 2005.06.22.06.16.02; author dyoung; state Exp; branches; next 1.36; 1.36 date 2005.06.20.02.49.18; author atatat; state Exp; branches; next 1.35; 1.35 date 2005.06.09.02.19.59; author atatat; state Exp; branches; next 1.34; 1.34 date 2005.05.30.04.16.56; author christos; state Exp; branches; next 1.33; 1.33 date 2005.02.26.22.45.09; author perry; state Exp; branches; next 1.32; 1.32 date 2004.08.10.00.57.21; author dyoung; state Exp; branches 1.32.4.1 1.32.6.1; next 1.31; 1.31 date 2004.07.30.17.05.18; author mycroft; state Exp; branches 1.31.2.1; next 1.30; 1.30 date 2004.07.30.04.32.10; author dyoung; state Exp; branches; next 1.29; 1.29 date 2004.07.30.04.29.52; author dyoung; state Exp; branches; next 1.28; 1.28 date 2004.07.23.10.15.13; author mycroft; state Exp; branches; next 1.27; 1.27 date 2004.07.23.09.22.15; author mycroft; state Exp; branches; next 1.26; 1.26 date 2004.07.23.08.05.00; author mycroft; state Exp; branches; next 1.25; 1.25 date 2004.07.23.06.44.55; author mycroft; state Exp; branches; next 1.24; 1.24 date 2004.07.23.05.33.41; author mycroft; state Exp; branches; next 1.23; 1.23 date 2004.07.22.14.44.17; author mycroft; state Exp; branches; next 1.22; 1.22 date 2004.07.16.03.02.41; author dyoung; state Exp; branches; next 1.21; 1.21 date 2004.07.16.02.54.05; author dyoung; state Exp; branches; next 1.20; 1.20 date 2004.07.16.02.36.58; author dyoung; state Exp; branches; next 1.19; 1.19 date 2004.06.06.05.45.29; author dyoung; state Exp; branches; next 1.18; 1.18 date 2004.06.06.05.44.25; author dyoung; state Exp; branches; next 1.17; 1.17 date 2004.06.06.05.43.17; author dyoung; state Exp; branches; next 1.16; 1.16 date 2004.06.06.05.28.58; author dyoung; state Exp; branches; next 1.15; 1.15 date 2004.05.25.04.33.59; author atatat; state Exp; branches; next 1.14; 1.14 date 2004.05.09.09.00.05; author dyoung; state Exp; branches; next 1.13; 1.13 date 2004.05.09.08.19.21; author dyoung; state Exp; branches; next 1.12; 1.12 date 2004.05.06.07.11.40; author dyoung; state Exp; branches; next 1.11; 1.11 date 2004.05.06.03.07.10; author dyoung; state Exp; branches; next 1.10; 1.10 date 2004.04.30.23.58.05; author dyoung; state Exp; branches; next 1.9; 1.9 date 2004.01.13.23.37.29; author dyoung; state Exp; branches 1.9.2.1; next 1.8; 1.8 date 2003.12.14.09.56.53; author dyoung; state Exp; branches; next 1.7; 1.7 date 2003.10.16.22.25.00; author matt; state Exp; branches; next 1.6; 1.6 date 2003.10.14.23.13.44; author dyoung; state Exp; branches; next 1.5; 1.5 date 2003.10.13.04.28.35; author dyoung; state Exp; branches; next 1.4; 1.4 date 2003.09.23.16.01.21; author dyoung; state Exp; branches; next 1.3; 1.3 date 2003.09.14.01.14.54; author dyoung; state Exp; branches; next 1.2; 1.2 date 2003.09.07.01.22.19; author dyoung; state Exp; branches; next 1.1; 1.1 date 2003.08.30.21.26.03; author dyoung; state Exp; branches 1.1.1.1; next ; 1.57.2.1 date 2020.02.29.20.21.07; author ad; state Exp; branches; next ; commitid OjSb8ro7YQETQBYB; 1.56.18.1 date 2018.06.28.21.03.07; author phil; state Exp; branches; next 1.56.18.2; commitid fU5eenqZ23IoH5IA; 1.56.18.2 date 2018.07.12.16.35.34; author phil; state Exp; branches; next 1.56.18.3; commitid US0n8axK0fqSKRJA; 1.56.18.3 date 2018.07.16.20.11.11; author phil; state Exp; branches; next 1.56.18.4; commitid 57tT6pqTipGJQoKA; 1.56.18.4 date 2018.07.20.20.33.05; author phil; state Exp; branches; next 1.56.18.5; commitid aRnRKvjLmzAeQUKA; 1.56.18.5 date 2018.07.28.00.49.43; author phil; state Exp; branches; next 1.56.18.6; commitid 6PG1W3p1b1dN1QLA; 1.56.18.6 date 2018.08.15.17.07.02; author phil; state Exp; branches; next 1.56.18.7; commitid xHTQHLRqLFKFReOA; 1.56.18.7 date 2019.06.10.22.09.46; author christos; state Exp; branches; next 1.56.18.8; commitid jtc8rnCzWiEEHGqB; 1.56.18.8 date 2020.04.13.08.05.15; author martin; state Exp; branches; next 1.56.18.9; commitid X01YhRUPVUDaec4C; 1.56.18.9 date 2020.04.16.15.30.00; author nat; state Exp; branches; next ; commitid e0Drnsq9WmF8JC4C; 1.55.2.1 date 2015.09.22.12.06.11; author skrll; state Exp; branches; next ; 1.53.8.1 date 2014.05.22.11.41.09; author yamt; state Exp; branches; next ; 1.53.18.1 date 2013.06.23.06.20.25; author tls; state Exp; branches; next 1.53.18.2; 1.53.18.2 date 2017.12.03.11.39.03; author jdolecek; state Exp; branches; next ; commitid XcIYRZTAh1LmerhA; 1.50.2.1 date 2010.04.30.14.44.20; author uebayasi; state Exp; branches; next ; 1.50.4.1 date 2010.05.30.05.18.02; author rmind; state Exp; branches; next ; 1.48.12.1 date 2008.02.22.16.50.25; author skrll; state Exp; branches; next ; 1.48.14.1 date 2009.01.17.13.29.32; author mjf; state Exp; branches; next ; 1.48.18.1 date 2009.05.04.08.14.16; author yamt; state Exp; branches; next 1.48.18.2; 1.48.18.2 date 2010.03.11.15.04.28; author yamt; state Exp; branches; next 1.48.18.3; 1.48.18.3 date 2010.08.11.22.54.56; author yamt; state Exp; branches; next ; 1.48.26.1 date 2009.01.19.13.20.12; author skrll; state Exp; branches; next ; 1.47.22.1 date 2007.12.01.14.40.39; author jmcneill; state Exp; branches; next ; 1.47.24.1 date 2008.01.09.01.57.17; author matt; state Exp; branches; next ; 1.47.30.1 date 2007.12.08.18.21.08; author mjf; state Exp; branches; next ; 1.45.10.1 date 2006.11.18.21.39.32; author ad; state Exp; branches; next ; 1.45.12.1 date 2006.10.22.06.07.27; author yamt; state Exp; branches; next 1.45.12.2; 1.45.12.2 date 2006.12.10.07.19.06; author yamt; state Exp; branches; next ; 1.44.2.1 date 2006.03.13.09.07.39; author yamt; state Exp; branches; next ; 1.44.4.1 date 2006.04.19.04.46.11; author elad; state Exp; branches; next ; 1.43.4.1 date 2006.09.09.02.58.25; author rpaulo; state Exp; branches; next ; 1.43.6.1 date 2006.04.22.11.40.08; author simonb; state Exp; branches; next ; 1.40.6.1 date 2005.11.22.16.08.15; author yamt; state Exp; branches; next 1.40.6.2; 1.40.6.2 date 2005.11.29.21.23.29; author yamt; state Exp; branches; next ; 1.38.2.1 date 2006.06.21.15.10.45; author yamt; state Exp; branches; next 1.38.2.2; 1.38.2.2 date 2007.12.07.17.34.21; author yamt; state Exp; branches; next ; 1.32.4.1 date 2005.04.29.11.29.32; author kent; state Exp; branches; next ; 1.32.6.1 date 2005.03.19.08.36.35; author yamt; state Exp; branches; next ; 1.31.2.1 date 2004.07.30.17.05.18; author skrll; state dead; branches; next 1.31.2.2; 1.31.2.2 date 2004.08.03.10.54.20; author skrll; state Exp; branches; next 1.31.2.3; 1.31.2.3 date 2004.08.12.11.42.20; author skrll; state Exp; branches; next 1.31.2.4; 1.31.2.4 date 2004.09.18.14.54.39; author skrll; state Exp; branches; next 1.31.2.5; 1.31.2.5 date 2004.09.21.13.36.55; author skrll; state Exp; branches; next 1.31.2.6; 1.31.2.6 date 2005.03.04.16.53.17; author skrll; state Exp; branches; next 1.31.2.7; 1.31.2.7 date 2005.11.10.14.10.51; author skrll; state Exp; branches; next 1.31.2.8; 1.31.2.8 date 2005.12.11.10.29.22; author christos; state Exp; branches; next ; 1.9.2.1 date 2004.06.07.06.36.41; author jdc; state Exp; branches; next 1.9.2.2; 1.9.2.2 date 2004.07.23.23.28.59; author he; state Exp; branches; next ; 1.1.1.1 date 2003.08.30.21.26.03; author dyoung; state Exp; branches; next 1.1.1.2; 1.1.1.2 date 2003.12.13.08.36.04; author dyoung; state Exp; branches; next 1.1.1.3; 1.1.1.3 date 2004.04.29.03.54.38; author dyoung; state Exp; branches; next 1.1.1.4; 1.1.1.4 date 2005.06.21.20.37.39; author dyoung; state Exp; branches; next 1.1.1.5; 1.1.1.5 date 2005.11.18.16.20.30; author skrll; state Exp; branches; next ; desc @@ 1.61 log @fix some more typos in comments/log messages, improve wording as well. @ text @/* $NetBSD: ieee80211.c,v 1.60 2020/10/06 23:51:05 roy Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #ifdef __FreeBSD__ __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.22 2005/08/10 16:22:29 sam Exp $"); #endif #ifdef __NetBSD__ __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.60 2020/10/06 23:51:05 roy Exp $"); #endif /* * IEEE 802.11 generic handler */ #ifdef _KERNEL_OPT #include "opt_inet.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET #include #include #endif const struct ieee80211_channel ieee80211_channel_anyc = { 0, 0 }; struct ieee80211com_head ieee80211com_head = LIST_HEAD_INITIALIZER(ieee80211com_head); const char *ieee80211_phymode_name[] = { "auto", /* IEEE80211_MODE_AUTO */ "11a", /* IEEE80211_MODE_11A */ "11b", /* IEEE80211_MODE_11B */ "11g", /* IEEE80211_MODE_11G */ "FH", /* IEEE80211_MODE_FH */ "turboA", /* IEEE80211_MODE_TURBO_A */ "turboG", /* IEEE80211_MODE_TURBO_G */ }; /* list of all instances */ SLIST_HEAD(ieee80211_list, ieee80211com); static struct ieee80211_list ieee80211_list = SLIST_HEAD_INITIALIZER(ieee80211_list); static u_int8_t ieee80211_vapmap[32]; /* enough for 256 */ static void ieee80211_add_vap(struct ieee80211com *ic) { #define N(a) (sizeof(a)/sizeof(a[0])) int i; int s; u_int8_t b; s = splnet(); ic->ic_vap = 0; for (i = 0; i < N(ieee80211_vapmap) && ieee80211_vapmap[i] == 0xff; i++) ic->ic_vap += NBBY; if (i == N(ieee80211_vapmap)) panic("vap table full"); for (b = ieee80211_vapmap[i]; b & 1; b >>= 1) ic->ic_vap++; setbit(ieee80211_vapmap, ic->ic_vap); SLIST_INSERT_HEAD(&ieee80211_list, ic, ic_next); splx(s); #undef N } static void ieee80211_remove_vap(struct ieee80211com *ic) { int s; s = splnet(); SLIST_REMOVE(&ieee80211_list, ic, ieee80211com, ic_next); IASSERT(ic->ic_vap < sizeof(ieee80211_vapmap)*NBBY, ("invalid vap id %d", ic->ic_vap)); IASSERT(isset(ieee80211_vapmap, ic->ic_vap), ("vap id %d not allocated", ic->ic_vap)); clrbit(ieee80211_vapmap, ic->ic_vap); splx(s); } /* * Default reset method for use with the ioctl support. This * method is invoked after any state change in the 802.11 * layer that should be propagated to the hardware but not * require re-initialization of the 802.11 state machine (e.g * rescanning for an ap). We always return ENETRESET which * should cause the driver to re-initialize the device. Drivers * can override this method to implement more optimized support. */ static int ieee80211_default_reset(struct ifnet *ifp) { return ENETRESET; } static void ieee80211_init_link_state(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; /* * Link state does not make sense in IBSS or HOSTAP modes. * We know that the link in MONITOR mode is DOWN as we cannot * transmit, only monitor. * That leaves BSS mode, which starts off DOWN and will * transition to UP when it joins a node. */ switch (ic->ic_opmode) { case IEEE80211_M_AHDEMO: case IEEE80211_M_HOSTAP: case IEEE80211_M_IBSS: if_link_state_change(ifp, LINK_STATE_UNKNOWN); break; default: if_link_state_change(ifp, LINK_STATE_DOWN); break; } } void ieee80211_ifattach(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; struct ieee80211_channel *c; int i; #ifdef __NetBSD__ ieee80211_init(); #endif /* __NetBSD__ */ ether_ifattach(ifp, ic->ic_myaddr); bpf_attach2(ifp, DLT_IEEE802_11, sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf); ieee80211_crypto_attach(ic); /* * Fill in 802.11 available channel set, mark * all available channels as active, and pick * a default channel if not already specified. */ memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); ic->ic_modecaps |= 1<ic_channels[i]; if (c->ic_flags) { /* * Verify driver passed us valid data. */ if (i != ieee80211_chan2ieee(ic, c)) { if_printf(ifp, "bad channel ignored; " "freq %u flags %x number %u\n", c->ic_freq, c->ic_flags, i); c->ic_flags = 0; /* NB: remove */ continue; } setbit(ic->ic_chan_avail, i); /* * Identify mode capabilities. */ if (IEEE80211_IS_CHAN_A(c)) ic->ic_modecaps |= 1<ic_modecaps |= 1<ic_modecaps |= 1<ic_modecaps |= 1<ic_modecaps |= 1<ic_modecaps |= 1<ic_curchan == NULL) { /* arbitrarily pick the first channel */ ic->ic_curchan = &ic->ic_channels[i]; } } } /* validate ic->ic_curmode */ if ((ic->ic_modecaps & (1<ic_curmode)) == 0) ic->ic_curmode = IEEE80211_MODE_AUTO; ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ #if 0 /* * Enable WME by default if we're capable. */ if (ic->ic_caps & IEEE80211_C_WME) ic->ic_flags |= IEEE80211_F_WME; #endif (void) ieee80211_setmode(ic, ic->ic_curmode); if (ic->ic_bintval == 0) ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; ic->ic_bmisstimeout = 7*ic->ic_bintval; /* default 7 beacons */ ic->ic_dtim_period = IEEE80211_DTIM_DEFAULT; IEEE80211_BEACON_LOCK_INIT(ic, "beacon"); if (ic->ic_lintval == 0) ic->ic_lintval = ic->ic_bintval; ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list); ieee80211_node_attach(ic); ieee80211_proto_attach(ic); ieee80211_add_vap(ic); ieee80211_sysctl_attach(ic); /* NB: requires ic_vap */ /* * Install a default reset method for the ioctl support. * The driver is expected to fill this in before calling us. */ if (ic->ic_reset == NULL) ic->ic_reset = ieee80211_default_reset; ieee80211_init_link_state(ic); } void ieee80211_ifdetach(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; ieee80211_remove_vap(ic); ieee80211_sysctl_detach(ic); ieee80211_proto_detach(ic); ieee80211_crypto_detach(ic); ieee80211_node_detach(ic); LIST_REMOVE(ic, ic_list); ifmedia_fini(&ic->ic_media); IEEE80211_BEACON_LOCK_DESTROY(ic); bpf_detach(ifp); ether_ifdetach(ifp); } /* * Convert MHz frequency to IEEE channel number. */ u_int ieee80211_mhz2ieee(u_int freq, u_int flags) { if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ if (freq == 2484) return 14; if (freq < 2484) return (freq - 2407) / 5; else return 15 + ((freq - 2512) / 20); } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5 GHz band */ return (freq - 5000) / 5; } else { /* either, guess */ if (freq == 2484) return 14; if (freq < 2484) return (freq - 2407) / 5; if (freq < 5000) return 15 + ((freq - 2512) / 20); return (freq - 5000) / 5; } } /* * Convert channel to IEEE channel number. */ u_int ieee80211_chan2ieee(struct ieee80211com *ic, struct ieee80211_channel *c) { if (ic->ic_channels <= c && c <= &ic->ic_channels[IEEE80211_CHAN_MAX]) return c - ic->ic_channels; else if (c == IEEE80211_CHAN_ANYC) return IEEE80211_CHAN_ANY; else if (c != NULL) { if_printf(ic->ic_ifp, "invalid channel freq %u flags %x\n", c->ic_freq, c->ic_flags); return 0; /* XXX */ } else { if_printf(ic->ic_ifp, "invalid channel (NULL)\n"); return 0; /* XXX */ } } /* * Convert IEEE channel number to MHz frequency. */ u_int ieee80211_ieee2mhz(u_int chan, u_int flags) { if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ if (chan == 14) return 2484; if (chan < 14) return 2407 + chan*5; else return 2512 + ((chan-15)*20); } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5 GHz band */ return 5000 + (chan*5); } else { /* either, guess */ if (chan == 14) return 2484; if (chan < 14) /* 0-13 */ return 2407 + chan*5; if (chan < 27) /* 15-26 */ return 2512 + ((chan-15)*20); return 5000 + (chan*5); } } /* * Setup the media data structures according to the channel and * rate tables. This must be called by the driver after * ieee80211_attach and before most anything else. */ void ieee80211_media_init_with_lock(struct ieee80211com *ic, ifm_change_cb_t media_change, ifm_stat_cb_t media_stat, ieee80211_media_lock_t *lock) { #define ADD(_ic, _s, _o) \ ifmedia_add(&(_ic)->ic_media, \ IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL) struct ifnet *ifp = ic->ic_ifp; struct ifmediareq imr; int i, j, mode, rate, maxrate, mword, mopt, r; const struct ieee80211_rateset *rs; struct ieee80211_rateset allrates; /* * Do late attach work that must wait for any subclass * (i.e. driver) work such as overriding methods. */ ieee80211_node_lateattach(ic); #ifdef IEEE80211_NO_HOSTAP ic->ic_caps &= ~IEEE80211_C_HOSTAP; #endif /* IEEE80211_NO_HOSTAP */ /* * Fill in media characteristics. */ ifmedia_init_with_lock(&ic->ic_media, 0, media_change, media_stat, lock); maxrate = 0; memset(&allrates, 0, sizeof(allrates)); for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_MAX; mode++) { static const u_int mopts[] = { IFM_AUTO, IFM_IEEE80211_11A, IFM_IEEE80211_11B, IFM_IEEE80211_11G, IFM_IEEE80211_FH, IFM_IEEE80211_11A | IFM_IEEE80211_TURBO, IFM_IEEE80211_11G | IFM_IEEE80211_TURBO, }; if ((ic->ic_modecaps & (1<ic_caps & IEEE80211_C_IBSS) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP); if (ic->ic_caps & IEEE80211_C_AHDEMO) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0); if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_MONITOR); if (mode == IEEE80211_MODE_AUTO) continue; rs = &ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rate = rs->rs_rates[i]; mword = ieee80211_rate2media(ic, rate, mode); if (mword == 0) continue; ADD(ic, mword, mopt); if (ic->ic_caps & IEEE80211_C_IBSS) ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP); if (ic->ic_caps & IEEE80211_C_AHDEMO) ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0); if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, mword, mopt | IFM_IEEE80211_MONITOR); /* * Add rate to the collection of all rates. */ r = rate & IEEE80211_RATE_VAL; for (j = 0; j < allrates.rs_nrates; j++) if (allrates.rs_rates[j] == r) break; if (j == allrates.rs_nrates) { /* unique, add to the set */ allrates.rs_rates[j] = r; allrates.rs_nrates++; } rate = (rate & IEEE80211_RATE_VAL) / 2; if (rate > maxrate) maxrate = rate; } } for (i = 0; i < allrates.rs_nrates; i++) { mword = ieee80211_rate2media(ic, allrates.rs_rates[i], IEEE80211_MODE_AUTO); if (mword == 0) continue; mword = IFM_SUBTYPE(mword); /* remove media options */ ADD(ic, mword, 0); if (ic->ic_caps & IEEE80211_C_IBSS) ADD(ic, mword, IFM_IEEE80211_ADHOC); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, mword, IFM_IEEE80211_HOSTAP); if (ic->ic_caps & IEEE80211_C_AHDEMO) ADD(ic, mword, IFM_IEEE80211_ADHOC | IFM_FLAG0); if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, mword, IFM_IEEE80211_MONITOR); } ieee80211_media_status(ifp, &imr); ifmedia_set(&ic->ic_media, imr.ifm_active); if (maxrate) ifp->if_baudrate = IF_Mbps(maxrate); #undef ADD } void ieee80211_media_init(struct ieee80211com *ic, ifm_change_cb_t media_change, ifm_stat_cb_t media_stat) { ieee80211_media_init_with_lock(ic, media_change, media_stat, NULL); } void ieee80211_announce(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; int i, mode, rate, mword; struct ieee80211_rateset *rs; for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) { if ((ic->ic_modecaps & (1<if_xname, ieee80211_phymode_name[mode]); rs = &ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rate = rs->rs_rates[i]; mword = ieee80211_rate2media(ic, rate, mode); if (mword == 0) continue; aprint_debug("%s%d%sMbps", (i != 0 ? " " : ""), (rate & IEEE80211_RATE_VAL) / 2, ((rate & 0x1) != 0 ? ".5" : "")); } aprint_debug("\n"); } } static int findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate) { #define IEEERATE(_ic,_m,_i) \ ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL) int i, nrates = ic->ic_sup_rates[mode].rs_nrates; for (i = 0; i < nrates; i++) if (IEEERATE(ic, mode, i) == rate) return i; return -1; #undef IEEERATE } /* * Find an instance by its mac address. */ struct ieee80211com * ieee80211_find_vap(const u_int8_t mac[IEEE80211_ADDR_LEN]) { int s; struct ieee80211com *ic; s = splnet(); SLIST_FOREACH(ic, &ieee80211_list, ic_next) if (IEEE80211_ADDR_EQ(mac, ic->ic_myaddr)) break; splx(s); return ic; } static struct ieee80211com * ieee80211_find_instance(struct ifnet *ifp) { int s; struct ieee80211com *ic; s = splnet(); /* XXX not right for multiple instances but works for now */ SLIST_FOREACH(ic, &ieee80211_list, ic_next) if (ic->ic_ifp == ifp) break; splx(s); return ic; } /* * Handle a media change request. */ int ieee80211_media_change(struct ifnet *ifp) { struct ieee80211com *ic; struct ifmedia_entry *ime; enum ieee80211_opmode newopmode; enum ieee80211_phymode newphymode; int i, j, newrate, error = 0; ic = ieee80211_find_instance(ifp); if (!ic) { if_printf(ifp, "%s: no 802.11 instance!\n", __func__); return EINVAL; } ime = ic->ic_media.ifm_cur; /* * First, identify the phy mode. */ switch (IFM_MODE(ime->ifm_media)) { case IFM_IEEE80211_11A: newphymode = IEEE80211_MODE_11A; break; case IFM_IEEE80211_11B: newphymode = IEEE80211_MODE_11B; break; case IFM_IEEE80211_11G: newphymode = IEEE80211_MODE_11G; break; case IFM_IEEE80211_FH: newphymode = IEEE80211_MODE_FH; break; case IFM_AUTO: newphymode = IEEE80211_MODE_AUTO; break; default: return EINVAL; } /* * Turbo mode is an ``option''. * XXX does not apply to AUTO */ if (ime->ifm_media & IFM_IEEE80211_TURBO) { if (newphymode == IEEE80211_MODE_11A) newphymode = IEEE80211_MODE_TURBO_A; else if (newphymode == IEEE80211_MODE_11G) newphymode = IEEE80211_MODE_TURBO_G; else return EINVAL; } /* * Validate requested mode is available. */ if ((ic->ic_modecaps & (1<ifm_media) != IFM_AUTO) { /* * Convert media subtype to rate. */ newrate = ieee80211_media2rate(ime->ifm_media); if (newrate == 0) return EINVAL; /* * Check the rate table for the specified/current phy. */ if (newphymode == IEEE80211_MODE_AUTO) { /* * In autoselect mode search for the rate. */ for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++) { if ((ic->ic_modecaps & (1<ifm_media & (IFM_IEEE80211_ADHOC|IFM_FLAG0)) == (IFM_IEEE80211_ADHOC|IFM_FLAG0)) newopmode = IEEE80211_M_AHDEMO; else if (ime->ifm_media & IFM_IEEE80211_HOSTAP) newopmode = IEEE80211_M_HOSTAP; else if (ime->ifm_media & IFM_IEEE80211_ADHOC) newopmode = IEEE80211_M_IBSS; else if (ime->ifm_media & IFM_IEEE80211_MONITOR) newopmode = IEEE80211_M_MONITOR; else newopmode = IEEE80211_M_STA; #ifndef IEEE80211_NO_HOSTAP /* * Autoselect doesn't make sense when operating as an AP. * If no phy mode has been selected, pick one and lock it * down so rate tables can be used in forming beacon frames * and the like. */ if (newopmode == IEEE80211_M_HOSTAP && newphymode == IEEE80211_MODE_AUTO) { for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++) if (ic->ic_modecaps & (1<ic_curmode != newphymode) { /* change phy mode */ error = ieee80211_setmode(ic, newphymode); if (error != 0) return error; error = ENETRESET; } /* * Committed to changes, install the rate setting. */ if (ic->ic_fixed_rate != i) { ic->ic_fixed_rate = i; /* set fixed tx rate */ error = ENETRESET; } /* * Handle operating mode change. */ if (ic->ic_opmode != newopmode) { ic->ic_opmode = newopmode; switch (newopmode) { case IEEE80211_M_AHDEMO: case IEEE80211_M_HOSTAP: case IEEE80211_M_STA: case IEEE80211_M_MONITOR: ic->ic_flags &= ~IEEE80211_F_IBSSON; break; case IEEE80211_M_IBSS: ic->ic_flags |= IEEE80211_F_IBSSON; break; } /* * Yech, slot time may change depending on the * operating mode so reset it to be sure everything * is setup appropriately. */ ieee80211_reset_erp(ic); ieee80211_wme_initparams(ic); /* after opmode change */ ieee80211_init_link_state(ic); /* after opmode change */ error = ENETRESET; } #ifdef notdef if (error == 0) ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media); #endif return error; } void ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr) { struct ieee80211com *ic; struct ieee80211_rateset *rs; ic = ieee80211_find_instance(ifp); if (!ic) { if_printf(ifp, "%s: no 802.11 instance!\n", __func__); return; } imr->ifm_status = IFM_AVALID; imr->ifm_active = IFM_IEEE80211; if (ic->ic_state == IEEE80211_S_RUN) imr->ifm_status |= IFM_ACTIVE; /* * Calculate a current rate if possible. */ if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { /* * A fixed rate is set, report that. */ rs = &ic->ic_sup_rates[ic->ic_curmode]; imr->ifm_active |= ieee80211_rate2media(ic, rs->rs_rates[ic->ic_fixed_rate], ic->ic_curmode); } else if (ic->ic_opmode == IEEE80211_M_STA) { /* * In station mode report the current transmit rate. */ rs = &ic->ic_bss->ni_rates; imr->ifm_active |= ieee80211_rate2media(ic, rs->rs_rates[ic->ic_bss->ni_txrate], ic->ic_curmode); } else imr->ifm_active |= IFM_AUTO; switch (ic->ic_opmode) { case IEEE80211_M_STA: break; case IEEE80211_M_IBSS: imr->ifm_active |= IFM_IEEE80211_ADHOC; break; case IEEE80211_M_AHDEMO: /* should not come here */ break; case IEEE80211_M_HOSTAP: imr->ifm_active |= IFM_IEEE80211_HOSTAP; break; case IEEE80211_M_MONITOR: imr->ifm_active |= IFM_IEEE80211_MONITOR; break; } switch (ic->ic_curmode) { case IEEE80211_MODE_11A: imr->ifm_active |= IFM_IEEE80211_11A; break; case IEEE80211_MODE_11B: imr->ifm_active |= IFM_IEEE80211_11B; break; case IEEE80211_MODE_11G: imr->ifm_active |= IFM_IEEE80211_11G; break; case IEEE80211_MODE_FH: imr->ifm_active |= IFM_IEEE80211_FH; break; case IEEE80211_MODE_TURBO_A: imr->ifm_active |= IFM_IEEE80211_11A | IFM_IEEE80211_TURBO; break; case IEEE80211_MODE_TURBO_G: imr->ifm_active |= IFM_IEEE80211_11G | IFM_IEEE80211_TURBO; break; } } void ieee80211_watchdog(struct ieee80211com *ic) { struct ieee80211_node_table *nt; int need_inact_timer = 0; if (ic->ic_state != IEEE80211_S_INIT) { if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0) ieee80211_new_state(ic, IEEE80211_S_SCAN, 0); nt = &ic->ic_scan; if (nt->nt_inact_timer) { if (--nt->nt_inact_timer == 0) nt->nt_timeout(nt); need_inact_timer += nt->nt_inact_timer; } nt = &ic->ic_sta; if (nt->nt_inact_timer) { if (--nt->nt_inact_timer == 0) nt->nt_timeout(nt); need_inact_timer += nt->nt_inact_timer; } } if (ic->ic_mgt_timer != 0 || need_inact_timer) ic->ic_ifp->if_timer = 1; } const struct ieee80211_rateset ieee80211_std_rateset_11a = { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } }; const struct ieee80211_rateset ieee80211_std_rateset_11b = { 4, { 2, 4, 11, 22 } }; const struct ieee80211_rateset ieee80211_std_rateset_11g = { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; /* * Set the current phy mode and recalculate the active channel * set based on the available channels for this mode. Also * select a new default/current channel if the current one is * inappropriate for this mode. */ int ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) { #define N(a) (sizeof(a) / sizeof(a[0])) static const u_int chanflags[] = { 0, /* IEEE80211_MODE_AUTO */ IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */ IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */ IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */ IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */ IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO_A */ IEEE80211_CHAN_108G, /* IEEE80211_MODE_TURBO_G */ }; struct ieee80211_channel *c; u_int modeflags; int i; /* validate new mode */ if ((ic->ic_modecaps & (1<ic_modecaps); return EINVAL; } /* * Verify at least one channel is present in the available * channel list before committing to the new mode. */ IASSERT(mode < N(chanflags), ("Unexpected mode %u", mode)); modeflags = chanflags[mode]; for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (c->ic_flags == 0) continue; if (mode == IEEE80211_MODE_AUTO) { /* ignore turbo channels for autoselect */ if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0) break; } else { if ((c->ic_flags & modeflags) == modeflags) break; } } if (i > IEEE80211_CHAN_MAX) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, "%s: no channels found for mode %u\n", __func__, mode); return EINVAL; } /* * Calculate the active channel set. */ memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active)); for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (c->ic_flags == 0) continue; if (mode == IEEE80211_MODE_AUTO) { /* take anything but pure turbo channels */ if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0) setbit(ic->ic_chan_active, i); } else { if ((c->ic_flags & modeflags) == modeflags) setbit(ic->ic_chan_active, i); } } /* * If no current/default channel is setup or the current * channel is wrong for the mode then pick the first * available channel from the active list. This is likely * not the right one. */ if (ic->ic_ibss_chan == NULL || isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { for (i = 0; i <= IEEE80211_CHAN_MAX; i++) if (isset(ic->ic_chan_active, i)) { ic->ic_ibss_chan = &ic->ic_channels[i]; break; } IASSERT(ic->ic_ibss_chan != NULL && isset(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan)), ("Bad IBSS channel %u", ieee80211_chan2ieee(ic, ic->ic_ibss_chan))); } /* * If the desired channel is set but no longer valid then reset it. */ if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_des_chan))) ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* * Do mode-specific rate setup. */ if (mode == IEEE80211_MODE_11G) { /* * Use a mixed 11b/11g rate set. */ ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], IEEE80211_MODE_11G); } else if (mode == IEEE80211_MODE_11B) { /* * Force pure 11b rate set. */ ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], IEEE80211_MODE_11B); } /* * Setup an initial rate set according to the * current/default channel selected above. This * will be changed when scanning but must exist * now so driver have a consistent state of ic_ibss_chan. */ if (ic->ic_bss) /* NB: can be called before lateattach */ ic->ic_bss->ni_rates = ic->ic_sup_rates[mode]; ic->ic_curmode = mode; ieee80211_reset_erp(ic); /* reset ERP state */ ieee80211_wme_initparams(ic); /* reset WME stat */ return 0; #undef N } /* * Return the phy mode for with the specified channel so the * caller can select a rate set. This is problematic for channels * where multiple operating modes are possible (e.g. 11g+11b). * In those cases we defer to the current operating mode when set. */ enum ieee80211_phymode ieee80211_chan2mode(struct ieee80211com *ic, struct ieee80211_channel *chan) { if (IEEE80211_IS_CHAN_T(chan)) { return IEEE80211_MODE_TURBO_A; } else if (IEEE80211_IS_CHAN_5GHZ(chan)) { return IEEE80211_MODE_11A; } else if (IEEE80211_IS_CHAN_FHSS(chan)) return IEEE80211_MODE_FH; else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) { /* * This assumes all 11g channels are also usable * for 11b, which is currently true. */ if (ic->ic_curmode == IEEE80211_MODE_TURBO_G) return IEEE80211_MODE_TURBO_G; if (ic->ic_curmode == IEEE80211_MODE_11B) return IEEE80211_MODE_11B; return IEEE80211_MODE_11G; } else return IEEE80211_MODE_11B; } /* * convert IEEE80211 rate value to ifmedia subtype. * ieee80211 rate is in unit of 0.5Mbps. */ int ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode) { #define N(a) (sizeof(a) / sizeof(a[0])) static const struct { u_int m; /* rate + mode */ u_int r; /* if_media rate */ } rates[] = { { 2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 }, { 4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 }, { 2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 }, { 4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 }, { 11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 }, { 22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 }, { 44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 }, { 12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 }, { 18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 }, { 24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 }, { 36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 }, { 48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 }, { 72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 }, { 96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 }, { 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 }, { 2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 }, { 4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 }, { 11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 }, { 22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 }, { 12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 }, { 18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 }, { 24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 }, { 36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 }, { 48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 }, { 72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 }, { 96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 }, { 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 }, /* NB: OFDM72 doesn't really exist so we don't handle it */ }; u_int mask, i; mask = rate & IEEE80211_RATE_VAL; switch (mode) { case IEEE80211_MODE_11A: case IEEE80211_MODE_TURBO_A: mask |= IFM_IEEE80211_11A; break; case IEEE80211_MODE_11B: mask |= IFM_IEEE80211_11B; break; case IEEE80211_MODE_FH: mask |= IFM_IEEE80211_FH; break; case IEEE80211_MODE_AUTO: /* NB: ic may be NULL for some drivers */ if (ic && ic->ic_phytype == IEEE80211_T_FH) { mask |= IFM_IEEE80211_FH; break; } /* NB: hack, 11g matches both 11b+11a rates */ /* fall thru... */ case IEEE80211_MODE_11G: case IEEE80211_MODE_TURBO_G: mask |= IFM_IEEE80211_11G; break; } for (i = 0; i < N(rates); i++) if (rates[i].m == mask) return rates[i].r; return IFM_AUTO; #undef N } int ieee80211_media2rate(int mword) { #define N(a) (sizeof(a) / sizeof(a[0])) static const int ieeerates[] = { -1, /* IFM_AUTO */ 0, /* IFM_MANUAL */ 0, /* IFM_NONE */ 2, /* IFM_IEEE80211_FH1 */ 4, /* IFM_IEEE80211_FH2 */ 4, /* IFM_IEEE80211_DS2 */ 11, /* IFM_IEEE80211_DS5 */ 22, /* IFM_IEEE80211_DS11 */ 2, /* IFM_IEEE80211_DS1 */ 44, /* IFM_IEEE80211_DS22 */ 12, /* IFM_IEEE80211_OFDM6 */ 18, /* IFM_IEEE80211_OFDM9 */ 24, /* IFM_IEEE80211_OFDM12 */ 36, /* IFM_IEEE80211_OFDM18 */ 48, /* IFM_IEEE80211_OFDM24 */ 72, /* IFM_IEEE80211_OFDM36 */ 96, /* IFM_IEEE80211_OFDM48 */ 108, /* IFM_IEEE80211_OFDM54 */ 144, /* IFM_IEEE80211_OFDM72 */ }; return IFM_SUBTYPE(mword) < N(ieeerates) ? ieeerates[IFM_SUBTYPE(mword)] : 0; #undef N } @ 1.60 log @net80211: Initialise the interface with a decent link state. Link state transitions to UP when a node is joined and DOWN when left. This means that with the interface UP, the link state could be UNKNOWN for a while, implying it can be used in BSS mode. Which is of course false. Add a function to set an initial link state based on the operating mode. Also call this when the operating mode changes. Basically in BSS and MONITOR it starts off down. BSS will transition UP and DOWN as before, MONITOR will stay down. IBSS, AHDEMO and HOSTAP will remain as link unknown because the state is ..... unknown. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.59 2020/03/15 23:04:51 thorpej Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.59 2020/03/15 23:04:51 thorpej Exp $"); d1051 1 a1051 1 /* NB: OFDM72 doesn't realy exist so we don't handle it */ @ 1.59 log @Define and implement a locking protocol for the ifmedia / mii layers: - MP-safe drivers provide a mutex to ifmedia that is used to serialize access to media-related structures / hardware regsiters. Converted drivers use the new ifmedia_init_with_lock() function for this. The new name is provided to ease the transition. - Un-converted drivers continue to call ifmedia_init(), which will supply a compatibility lock to be used instead. Several media-related entry points must be aware of this compatibility lock, and are able to acquire it recursively a limited number of times, if needed. This is a SPIN mutex with priority IPL_NET. - This same lock is used to serialize access to PHY registers and other MII-related data structures. The PHY drivers are modified to acquire and release the lock, as needed, and assert the lock is held as a diagnostic aid. The "usbnet" framework has had an overhaul of its internal locking protocols to fit in with the media / mii changes, and the drivers adapted. USB wifi drivers have been changed to provide their own adaptive mutex to the ifmedia later via a new ieee80211_media_init_with_lock() function. This is required because the USB drivers need an adaptive mutex. Besised "usbnet", a few other drivers are converted: vmx, wm, ixgbe / ixv. mcx also now calls ifmedia_init_with_lock() because it needs to also use an adaptive mutex. The mcx driver still needs to be fully converted to NET_MPSAFE. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.58 2020/02/04 05:46:32 thorpej Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.58 2020/02/04 05:46:32 thorpej Exp $"); d153 24 d273 2 d732 1 @ 1.58 log @Use ifmedia_fini(). @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.57 2019/10/03 17:46:56 jmcneill Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.57 2019/10/03 17:46:56 jmcneill Exp $"); d349 3 a351 2 ieee80211_media_init(struct ieee80211com *ic, ifm_change_cb_t media_change, ifm_stat_cb_t media_stat) d375 2 a376 1 ifmedia_init(&ic->ic_media, 0, media_change, media_stat); d460 8 @ 1.57 log @ieee80211_announce: Print supported rates with aprint_debug @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.56 2015/08/24 22:21:26 pooka Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.56 2015/08/24 22:21:26 pooka Exp $"); d263 1 a263 1 ifmedia_delete_instance(&ic->ic_media, IFM_INST_ANY); @ 1.57.2.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.58 2020/02/04 05:46:32 thorpej Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.58 2020/02/04 05:46:32 thorpej Exp $"); d263 1 a263 1 ifmedia_fini(&ic->ic_media); @ 1.56 log @sprinkle _KERNEL_OPT @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.55 2014/10/18 08:33:29 snj Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.55 2014/10/18 08:33:29 snj Exp $"); d467 1 a467 1 aprint_normal("%s: %s rates: ", ifp->if_xname, d475 1 a475 1 aprint_normal("%s%d%sMbps", (i != 0 ? " " : ""), d479 1 a479 1 aprint_normal("\n"); @ 1.56.18.1 log @Start of WiFi refresh. Copy of FreeBSD net80211 directory with git mirror commit id of 09e3123164ec345822e00465039503686efde455, no changes yet. ieee80211_netbsd.[ch] from ieee80211_freebsd.[ch]. @ text @d1 1 a2 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * d4 1 a4 1 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting d15 6 d35 6 a40 1 __FBSDID("$FreeBSD$"); d45 4 a48 1 #include "opt_wlan.h" d51 1 a51 1 #include d53 1 a53 1 #include d55 5 a59 3 #include #include a61 2 #include #include d63 3 a65 2 #include #include d67 1 d69 1 a69 6 #include #ifdef IEEE80211_SUPPORT_SUPERG #include #endif #include #include d73 3 a75 26 const char *ieee80211_phymode_name[IEEE80211_MODE_MAX] = { [IEEE80211_MODE_AUTO] = "auto", [IEEE80211_MODE_11A] = "11a", [IEEE80211_MODE_11B] = "11b", [IEEE80211_MODE_11G] = "11g", [IEEE80211_MODE_FH] = "FH", [IEEE80211_MODE_TURBO_A] = "turboA", [IEEE80211_MODE_TURBO_G] = "turboG", [IEEE80211_MODE_STURBO_A] = "sturboA", [IEEE80211_MODE_HALF] = "half", [IEEE80211_MODE_QUARTER] = "quarter", [IEEE80211_MODE_11NA] = "11na", [IEEE80211_MODE_11NG] = "11ng", [IEEE80211_MODE_VHT_2GHZ] = "11acg", [IEEE80211_MODE_VHT_5GHZ] = "11ac", }; /* map ieee80211_opmode to the corresponding capability bit */ const int ieee80211_opcap[IEEE80211_OPMODE_MAX] = { [IEEE80211_M_IBSS] = IEEE80211_C_IBSS, [IEEE80211_M_WDS] = IEEE80211_C_WDS, [IEEE80211_M_STA] = IEEE80211_C_STA, [IEEE80211_M_AHDEMO] = IEEE80211_C_AHDEMO, [IEEE80211_M_HOSTAP] = IEEE80211_C_HOSTAP, [IEEE80211_M_MONITOR] = IEEE80211_C_MONITOR, #ifdef IEEE80211_SUPPORT_MESH [IEEE80211_M_MBSS] = IEEE80211_C_MBSS, d77 3 d82 2 a83 2 const uint8_t ieee80211broadcastaddr[IEEE80211_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; d85 9 a93 10 static void ieee80211_syncflag_locked(struct ieee80211com *ic, int flag); static void ieee80211_syncflag_ht_locked(struct ieee80211com *ic, int flag); static void ieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag); static void ieee80211_syncflag_vht_locked(struct ieee80211com *ic, int flag); static int ieee80211_media_setup(struct ieee80211com *ic, struct ifmedia *media, int caps, int addsta, ifm_change_cb_t media_change, ifm_stat_cb_t media_stat); static int media_status(enum ieee80211_opmode, const struct ieee80211_channel *); static uint64_t ieee80211_get_counter(struct ifnet *, ift_counter); d95 5 a99 1 MALLOC_DEFINE(M_80211_VAP, "80211vap", "802.11 vap state"); d101 2 a102 26 /* * Default supported rates for 802.11 operation (in IEEE .5Mb units). */ #define B(r) ((r) | IEEE80211_RATE_BASIC) static const struct ieee80211_rateset ieee80211_rateset_11a = { 8, { B(12), 18, B(24), 36, B(48), 72, 96, 108 } }; static const struct ieee80211_rateset ieee80211_rateset_half = { 8, { B(6), 9, B(12), 18, B(24), 36, 48, 54 } }; static const struct ieee80211_rateset ieee80211_rateset_quarter = { 8, { B(3), 4, B(6), 9, B(12), 18, 24, 27 } }; static const struct ieee80211_rateset ieee80211_rateset_11b = { 4, { B(2), B(4), B(11), B(22) } }; /* NB: OFDM rates are handled specially based on mode */ static const struct ieee80211_rateset ieee80211_rateset_11g = { 12, { B(2), B(4), B(11), B(22), 12, 18, 24, 36, 48, 72, 96, 108 } }; #undef B static int set_vht_extchan(struct ieee80211_channel *c); /* * Fill in 802.11 available channel set, mark * all available channels as active, and pick * a default channel if not already specified. */ void ieee80211_chan_init(struct ieee80211com *ic) d104 1 a104 5 #define DEFAULTRATES(m, def) do { \ if (ic->ic_sup_rates[m].rs_nrates == 0) \ ic->ic_sup_rates[m] = def; \ } while (0) struct ieee80211_channel *c; d106 2 d109 12 a120 126 KASSERT(0 < ic->ic_nchans && ic->ic_nchans <= IEEE80211_CHAN_MAX, ("invalid number of channels specified: %u", ic->ic_nchans)); memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); memset(ic->ic_modecaps, 0, sizeof(ic->ic_modecaps)); setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO); for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; KASSERT(c->ic_flags != 0, ("channel with no flags")); /* * Help drivers that work only with frequencies by filling * in IEEE channel #'s if not already calculated. Note this * mimics similar work done in ieee80211_setregdomain when * changing regulatory state. */ if (c->ic_ieee == 0) c->ic_ieee = ieee80211_mhz2ieee(c->ic_freq,c->ic_flags); /* * Setup the HT40/VHT40 upper/lower bits. * The VHT80 math is done elsewhere. */ if (IEEE80211_IS_CHAN_HT40(c) && c->ic_extieee == 0) c->ic_extieee = ieee80211_mhz2ieee(c->ic_freq + (IEEE80211_IS_CHAN_HT40U(c) ? 20 : -20), c->ic_flags); /* Update VHT math */ /* * XXX VHT again, note that this assumes VHT80 channels * are legit already */ set_vht_extchan(c); /* default max tx power to max regulatory */ if (c->ic_maxpower == 0) c->ic_maxpower = 2*c->ic_maxregpower; setbit(ic->ic_chan_avail, c->ic_ieee); /* * Identify mode capabilities. */ if (IEEE80211_IS_CHAN_A(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11A); if (IEEE80211_IS_CHAN_B(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11B); if (IEEE80211_IS_CHAN_ANYG(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11G); if (IEEE80211_IS_CHAN_FHSS(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_FH); if (IEEE80211_IS_CHAN_108A(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_A); if (IEEE80211_IS_CHAN_108G(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_G); if (IEEE80211_IS_CHAN_ST(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_STURBO_A); if (IEEE80211_IS_CHAN_HALF(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_HALF); if (IEEE80211_IS_CHAN_QUARTER(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_QUARTER); if (IEEE80211_IS_CHAN_HTA(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11NA); if (IEEE80211_IS_CHAN_HTG(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11NG); if (IEEE80211_IS_CHAN_VHTA(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_VHT_5GHZ); if (IEEE80211_IS_CHAN_VHTG(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_VHT_2GHZ); } /* initialize candidate channels to all available */ memcpy(ic->ic_chan_active, ic->ic_chan_avail, sizeof(ic->ic_chan_avail)); /* sort channel table to allow lookup optimizations */ ieee80211_sort_channels(ic->ic_channels, ic->ic_nchans); /* invalidate any previous state */ ic->ic_bsschan = IEEE80211_CHAN_ANYC; ic->ic_prevchan = NULL; ic->ic_csa_newchan = NULL; /* arbitrarily pick the first channel */ ic->ic_curchan = &ic->ic_channels[0]; ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); /* fillin well-known rate sets if driver has not specified */ DEFAULTRATES(IEEE80211_MODE_11B, ieee80211_rateset_11b); DEFAULTRATES(IEEE80211_MODE_11G, ieee80211_rateset_11g); DEFAULTRATES(IEEE80211_MODE_11A, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_TURBO_A, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_TURBO_G, ieee80211_rateset_11g); DEFAULTRATES(IEEE80211_MODE_STURBO_A, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_HALF, ieee80211_rateset_half); DEFAULTRATES(IEEE80211_MODE_QUARTER, ieee80211_rateset_quarter); DEFAULTRATES(IEEE80211_MODE_11NA, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_11NG, ieee80211_rateset_11g); DEFAULTRATES(IEEE80211_MODE_VHT_2GHZ, ieee80211_rateset_11g); DEFAULTRATES(IEEE80211_MODE_VHT_5GHZ, ieee80211_rateset_11a); /* * Setup required information to fill the mcsset field, if driver did * not. Assume a 2T2R setup for historic reasons. */ if (ic->ic_rxstream == 0) ic->ic_rxstream = 2; if (ic->ic_txstream == 0) ic->ic_txstream = 2; ieee80211_init_suphtrates(ic); /* * Set auto mode to reset active channel state and any desired channel. */ (void) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); #undef DEFAULTRATES } static void null_update_mcast(struct ieee80211com *ic) { ic_printf(ic, "need multicast update callback\n"); } static void null_update_promisc(struct ieee80211com *ic) { ic_printf(ic, "need promiscuous mode update callback\n"); d124 1 a124 157 null_update_chw(struct ieee80211com *ic) { ic_printf(ic, "%s: need callback\n", __func__); } int ic_printf(struct ieee80211com *ic, const char * fmt, ...) { va_list ap; int retval; retval = printf("%s: ", ic->ic_name); va_start(ap, fmt); retval += vprintf(fmt, ap); va_end(ap); return (retval); } static LIST_HEAD(, ieee80211com) ic_head = LIST_HEAD_INITIALIZER(ic_head); static struct mtx ic_list_mtx; MTX_SYSINIT(ic_list, &ic_list_mtx, "ieee80211com list", MTX_DEF); static int sysctl_ieee80211coms(SYSCTL_HANDLER_ARGS) { struct ieee80211com *ic; struct sbuf sb; char *sp; int error; error = sysctl_wire_old_buffer(req, 0); if (error) return (error); sbuf_new_for_sysctl(&sb, NULL, 8, req); sbuf_clear_flags(&sb, SBUF_INCLUDENUL); sp = ""; mtx_lock(&ic_list_mtx); LIST_FOREACH(ic, &ic_head, ic_next) { sbuf_printf(&sb, "%s%s", sp, ic->ic_name); sp = " "; } mtx_unlock(&ic_list_mtx); error = sbuf_finish(&sb); sbuf_delete(&sb); return (error); } SYSCTL_PROC(_net_wlan, OID_AUTO, devices, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, sysctl_ieee80211coms, "A", "names of available 802.11 devices"); /* * Attach/setup the common net80211 state. Called by * the driver on attach to prior to creating any vap's. */ void ieee80211_ifattach(struct ieee80211com *ic) { IEEE80211_LOCK_INIT(ic, ic->ic_name); IEEE80211_TX_LOCK_INIT(ic, ic->ic_name); TAILQ_INIT(&ic->ic_vaps); /* Create a taskqueue for all state changes */ ic->ic_tq = taskqueue_create("ic_taskq", M_WAITOK | M_ZERO, taskqueue_thread_enqueue, &ic->ic_tq); taskqueue_start_threads(&ic->ic_tq, 1, PI_NET, "%s net80211 taskq", ic->ic_name); ic->ic_ierrors = counter_u64_alloc(M_WAITOK); ic->ic_oerrors = counter_u64_alloc(M_WAITOK); /* * Fill in 802.11 available channel set, mark all * available channels as active, and pick a default * channel if not already specified. */ ieee80211_chan_init(ic); ic->ic_update_mcast = null_update_mcast; ic->ic_update_promisc = null_update_promisc; ic->ic_update_chw = null_update_chw; ic->ic_hash_key = arc4random(); ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; ic->ic_lintval = ic->ic_bintval; ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; ieee80211_crypto_attach(ic); ieee80211_node_attach(ic); ieee80211_power_attach(ic); ieee80211_proto_attach(ic); #ifdef IEEE80211_SUPPORT_SUPERG ieee80211_superg_attach(ic); #endif ieee80211_ht_attach(ic); ieee80211_vht_attach(ic); ieee80211_scan_attach(ic); ieee80211_regdomain_attach(ic); ieee80211_dfs_attach(ic); ieee80211_sysctl_attach(ic); mtx_lock(&ic_list_mtx); LIST_INSERT_HEAD(&ic_head, ic, ic_next); mtx_unlock(&ic_list_mtx); } /* * Detach net80211 state on device detach. Tear down * all vap's and reclaim all common state prior to the * device state going away. Note we may call back into * driver; it must be prepared for this. */ void ieee80211_ifdetach(struct ieee80211com *ic) { struct ieee80211vap *vap; mtx_lock(&ic_list_mtx); LIST_REMOVE(ic, ic_next); mtx_unlock(&ic_list_mtx); taskqueue_drain(taskqueue_thread, &ic->ic_restart_task); /* * The VAP is responsible for setting and clearing * the VIMAGE context. */ while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL) ieee80211_vap_destroy(vap); ieee80211_waitfor_parent(ic); ieee80211_sysctl_detach(ic); ieee80211_dfs_detach(ic); ieee80211_regdomain_detach(ic); ieee80211_scan_detach(ic); #ifdef IEEE80211_SUPPORT_SUPERG ieee80211_superg_detach(ic); #endif ieee80211_vht_detach(ic); ieee80211_ht_detach(ic); /* NB: must be called before ieee80211_node_detach */ ieee80211_proto_detach(ic); ieee80211_crypto_detach(ic); ieee80211_power_detach(ic); ieee80211_node_detach(ic); counter_u64_free(ic->ic_ierrors); counter_u64_free(ic->ic_oerrors); taskqueue_free(ic->ic_tq); IEEE80211_TX_LOCK_DESTROY(ic); IEEE80211_LOCK_DESTROY(ic); } struct ieee80211com * ieee80211_find_com(const char *name) d126 1 a126 15 struct ieee80211com *ic; mtx_lock(&ic_list_mtx); LIST_FOREACH(ic, &ic_head, ic_next) if (strcmp(ic->ic_name, name) == 0) break; mtx_unlock(&ic_list_mtx); return (ic); } void ieee80211_iterate_coms(ieee80211_com_iter_func *f, void *arg) { struct ieee80211com *ic; d128 8 a135 4 mtx_lock(&ic_list_mtx); LIST_FOREACH(ic, &ic_head, ic_next) (*f)(arg, ic); mtx_unlock(&ic_list_mtx); d148 1 a148 1 default_reset(struct ieee80211vap *vap, u_long cmd) d153 2 a154 9 /* * Default for updating the VAP default TX key index. * * Drivers that support TX offload as well as hardware encryption offload * may need to be informed of key index changes separate from the key * update. */ static void default_update_deftxkey(struct ieee80211vap *vap, ieee80211_keyix kid) d156 3 d160 7 a166 4 /* XXX assert validity */ /* XXX assert we're in a key update block */ vap->iv_def_txkey = kid; } d168 1 a168 21 /* * Add underlying device errors to vap errors. */ static uint64_t ieee80211_get_counter(struct ifnet *ifp, ift_counter cnt) { struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; uint64_t rv; rv = if_get_counter_default(ifp, cnt); switch (cnt) { case IFCOUNTER_OERRORS: rv += counter_u64_fetch(ic->ic_oerrors); break; case IFCOUNTER_IERRORS: rv += counter_u64_fetch(ic->ic_ierrors); break; default: break; } d170 21 a190 69 return (rv); } /* * Prepare a vap for use. Drivers use this call to * setup net80211 state in new vap's prior attaching * them with ieee80211_vap_attach (below). */ int ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode, int flags, const uint8_t bssid[IEEE80211_ADDR_LEN]) { struct ifnet *ifp; ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { ic_printf(ic, "%s: unable to allocate ifnet\n", __func__); return ENOMEM; } if_initname(ifp, name, unit); ifp->if_softc = vap; /* back pointer */ ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; ifp->if_transmit = ieee80211_vap_transmit; ifp->if_qflush = ieee80211_vap_qflush; ifp->if_ioctl = ieee80211_ioctl; ifp->if_init = ieee80211_init; ifp->if_get_counter = ieee80211_get_counter; vap->iv_ifp = ifp; vap->iv_ic = ic; vap->iv_flags = ic->ic_flags; /* propagate common flags */ vap->iv_flags_ext = ic->ic_flags_ext; vap->iv_flags_ven = ic->ic_flags_ven; vap->iv_caps = ic->ic_caps &~ IEEE80211_C_OPMODE; /* 11n capabilities - XXX methodize */ vap->iv_htcaps = ic->ic_htcaps; vap->iv_htextcaps = ic->ic_htextcaps; /* 11ac capabilities - XXX methodize */ vap->iv_vhtcaps = ic->ic_vhtcaps; vap->iv_vhtextcaps = ic->ic_vhtextcaps; vap->iv_opmode = opmode; vap->iv_caps |= ieee80211_opcap[opmode]; IEEE80211_ADDR_COPY(vap->iv_myaddr, ic->ic_macaddr); switch (opmode) { case IEEE80211_M_WDS: /* * WDS links must specify the bssid of the far end. * For legacy operation this is a static relationship. * For non-legacy operation the station must associate * and be authorized to pass traffic. Plumbing the * vap to the proper node happens when the vap * transitions to RUN state. */ IEEE80211_ADDR_COPY(vap->iv_des_bssid, bssid); vap->iv_flags |= IEEE80211_F_DESBSSID; if (flags & IEEE80211_CLONE_WDSLEGACY) vap->iv_flags_ext |= IEEE80211_FEXT_WDSLEGACY; break; #ifdef IEEE80211_SUPPORT_TDMA case IEEE80211_M_AHDEMO: if (flags & IEEE80211_CLONE_TDMA) { /* NB: checked before clone operation allowed */ KASSERT(ic->ic_caps & IEEE80211_C_TDMA, ("not TDMA capable, ic_caps 0x%x", ic->ic_caps)); d192 1 a192 3 * Propagate TDMA capability to mark vap; this * cannot be removed and is used to distinguish * regular ahdemo operation from ahdemo+tdma. d194 16 a209 1 vap->iv_caps |= IEEE80211_C_TDMA; a210 4 break; #endif default: break; d212 5 a216 76 /* auto-enable s/w beacon miss support */ if (flags & IEEE80211_CLONE_NOBEACONS) vap->iv_flags_ext |= IEEE80211_FEXT_SWBMISS; /* auto-generated or user supplied MAC address */ if (flags & (IEEE80211_CLONE_BSSID|IEEE80211_CLONE_MACADDR)) vap->iv_flags_ext |= IEEE80211_FEXT_UNIQMAC; /* * Enable various functionality by default if we're * capable; the driver can override us if it knows better. */ if (vap->iv_caps & IEEE80211_C_WME) vap->iv_flags |= IEEE80211_F_WME; if (vap->iv_caps & IEEE80211_C_BURST) vap->iv_flags |= IEEE80211_F_BURST; /* NB: bg scanning only makes sense for station mode right now */ if (vap->iv_opmode == IEEE80211_M_STA && (vap->iv_caps & IEEE80211_C_BGSCAN)) vap->iv_flags |= IEEE80211_F_BGSCAN; vap->iv_flags |= IEEE80211_F_DOTH; /* XXX no cap, just ena */ /* NB: DFS support only makes sense for ap mode right now */ if (vap->iv_opmode == IEEE80211_M_HOSTAP && (vap->iv_caps & IEEE80211_C_DFS)) vap->iv_flags_ext |= IEEE80211_FEXT_DFS; vap->iv_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ vap->iv_bmissthreshold = IEEE80211_HWBMISS_DEFAULT; vap->iv_dtim_period = IEEE80211_DTIM_DEFAULT; /* * Install a default reset method for the ioctl support; * the driver can override this. */ vap->iv_reset = default_reset; /* * Install a default crypto key update method, the driver * can override this. */ vap->iv_update_deftxkey = default_update_deftxkey; ieee80211_sysctl_vattach(vap); ieee80211_crypto_vattach(vap); ieee80211_node_vattach(vap); ieee80211_power_vattach(vap); ieee80211_proto_vattach(vap); #ifdef IEEE80211_SUPPORT_SUPERG ieee80211_superg_vattach(vap); #endif ieee80211_ht_vattach(vap); ieee80211_vht_vattach(vap); ieee80211_scan_vattach(vap); ieee80211_regdomain_vattach(vap); ieee80211_radiotap_vattach(vap); ieee80211_ratectl_set(vap, IEEE80211_RATECTL_NONE); return 0; } /* * Activate a vap. State should have been prepared with a * call to ieee80211_vap_setup and by the driver. On return * from this call the vap is ready for use. */ int ieee80211_vap_attach(struct ieee80211vap *vap, ifm_change_cb_t media_change, ifm_stat_cb_t media_stat, const uint8_t macaddr[IEEE80211_ADDR_LEN]) { struct ifnet *ifp = vap->iv_ifp; struct ieee80211com *ic = vap->iv_ic; struct ifmediareq imr; int maxrate; IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s parent %s flags 0x%x flags_ext 0x%x\n", __func__, ieee80211_opmode_name[vap->iv_opmode], ic->ic_name, vap->iv_flags, vap->iv_flags_ext); d218 1 a218 2 * Do late attach work that cannot happen until after * the driver has had a chance to override defaults. d220 2 a221 24 ieee80211_node_latevattach(vap); ieee80211_power_latevattach(vap); maxrate = ieee80211_media_setup(ic, &vap->iv_media, vap->iv_caps, vap->iv_opmode == IEEE80211_M_STA, media_change, media_stat); ieee80211_media_status(ifp, &imr); /* NB: strip explicit mode; we're actually in autoselect */ ifmedia_set(&vap->iv_media, imr.ifm_active &~ (IFM_MMASK | IFM_IEEE80211_TURBO)); if (maxrate) ifp->if_baudrate = IF_Mbps(maxrate); ether_ifattach(ifp, macaddr); IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp)); /* hook output method setup by ether_ifattach */ vap->iv_output = ifp->if_output; ifp->if_output = ieee80211_output; /* NB: if_mtu set by ether_ifattach to ETHERMTU */ IEEE80211_LOCK(ic); TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next); ieee80211_syncflag_locked(ic, IEEE80211_F_WME); #ifdef IEEE80211_SUPPORT_SUPERG ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP); d223 1 a223 11 ieee80211_syncflag_locked(ic, IEEE80211_F_PCF); ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT); ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_VHT); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT40); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT80); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT80P80); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT160); IEEE80211_UNLOCK(ic); d225 5 a229 2 return 1; } d231 3 a233 11 /* * Tear down vap state and reclaim the ifnet. * The driver is assumed to have prepared for * this; e.g. by turning off interrupts for the * underlying device. */ void ieee80211_vap_detach(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; struct ifnet *ifp = vap->iv_ifp; d235 3 a237 1 CURVNET_SET(ifp->if_vnet); d239 1 a239 2 IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s parent %s\n", __func__, ieee80211_opmode_name[vap->iv_opmode], ic->ic_name); d241 1 a241 4 /* NB: bpfdetach is called by ether_ifdetach and claims all taps */ ether_ifdetach(ifp); ieee80211_stop(vap); d244 2 a245 1 * Flush any deferred vap tasks. d247 2 a248 54 ieee80211_draintask(ic, &vap->iv_nstate_task); ieee80211_draintask(ic, &vap->iv_swbmiss_task); ieee80211_draintask(ic, &vap->iv_wme_task); ieee80211_draintask(ic, &ic->ic_parent_task); /* XXX band-aid until ifnet handles this for us */ taskqueue_drain(taskqueue_swi, &ifp->if_linktask); IEEE80211_LOCK(ic); KASSERT(vap->iv_state == IEEE80211_S_INIT , ("vap still running")); TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next); ieee80211_syncflag_locked(ic, IEEE80211_F_WME); #ifdef IEEE80211_SUPPORT_SUPERG ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP); #endif ieee80211_syncflag_locked(ic, IEEE80211_F_PCF); ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT); ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_VHT); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT40); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT80); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT80P80); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT160); /* NB: this handles the bpfdetach done below */ ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_BPF); if (vap->iv_ifflags & IFF_PROMISC) ieee80211_promisc(vap, false); if (vap->iv_ifflags & IFF_ALLMULTI) ieee80211_allmulti(vap, false); IEEE80211_UNLOCK(ic); ifmedia_removeall(&vap->iv_media); ieee80211_radiotap_vdetach(vap); ieee80211_regdomain_vdetach(vap); ieee80211_scan_vdetach(vap); #ifdef IEEE80211_SUPPORT_SUPERG ieee80211_superg_vdetach(vap); #endif ieee80211_vht_vdetach(vap); ieee80211_ht_vdetach(vap); /* NB: must be before ieee80211_node_vdetach */ ieee80211_proto_vdetach(vap); ieee80211_crypto_vdetach(vap); ieee80211_power_vdetach(vap); ieee80211_node_vdetach(vap); ieee80211_sysctl_vdetach(vap); if_free(ifp); CURVNET_RESTORE(); a250 4 /* * Count number of vaps in promisc, and issue promisc on * parent respectively. */ d252 1 a252 1 ieee80211_promisc(struct ieee80211vap *vap, bool on) d254 1 a254 1 struct ieee80211com *ic = vap->iv_ic; d256 1 a256 1 IEEE80211_LOCK_ASSERT(ic); d258 6 a263 19 if (on) { if (++ic->ic_promisc == 1) ieee80211_runtask(ic, &ic->ic_promisc_task); } else { KASSERT(ic->ic_promisc > 0, ("%s: ic %p not promisc", __func__, ic)); if (--ic->ic_promisc == 0) ieee80211_runtask(ic, &ic->ic_promisc_task); } } /* * Count number of vaps in allmulti, and issue allmulti on * parent respectively. */ void ieee80211_allmulti(struct ieee80211vap *vap, bool on) { struct ieee80211com *ic = vap->iv_ic; d265 1 a265 1 IEEE80211_LOCK_ASSERT(ic); d267 2 a268 9 if (on) { if (++ic->ic_allmulti == 1) ieee80211_runtask(ic, &ic->ic_mcast_task); } else { KASSERT(ic->ic_allmulti > 0, ("%s: ic %p not allmulti", __func__, ic)); if (--ic->ic_allmulti == 0) ieee80211_runtask(ic, &ic->ic_mcast_task); } d272 1 a272 3 * Synchronize flag bit state in the com structure * according to the state of all vap's. This is used, * for example, to handle state changes via ioctls. d274 2 a275 2 static void ieee80211_syncflag_locked(struct ieee80211com *ic, int flag) d277 18 a294 30 struct ieee80211vap *vap; int bit; IEEE80211_LOCK_ASSERT(ic); bit = 0; TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) if (vap->iv_flags & flag) { bit = 1; break; } if (bit) ic->ic_flags |= flag; else ic->ic_flags &= ~flag; } void ieee80211_syncflag(struct ieee80211vap *vap, int flag) { struct ieee80211com *ic = vap->iv_ic; IEEE80211_LOCK(ic); if (flag < 0) { flag = -flag; vap->iv_flags &= ~flag; } else vap->iv_flags |= flag; ieee80211_syncflag_locked(ic, flag); IEEE80211_UNLOCK(ic); d298 1 a298 3 * Synchronize flags_ht bit state in the com structure * according to the state of all vap's. This is used, * for example, to handle state changes via ioctls. d300 2 a301 2 static void ieee80211_syncflag_ht_locked(struct ieee80211com *ic, int flag) d303 12 a314 30 struct ieee80211vap *vap; int bit; IEEE80211_LOCK_ASSERT(ic); bit = 0; TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) if (vap->iv_flags_ht & flag) { bit = 1; break; } if (bit) ic->ic_flags_ht |= flag; else ic->ic_flags_ht &= ~flag; } void ieee80211_syncflag_ht(struct ieee80211vap *vap, int flag) { struct ieee80211com *ic = vap->iv_ic; IEEE80211_LOCK(ic); if (flag < 0) { flag = -flag; vap->iv_flags_ht &= ~flag; } else vap->iv_flags_ht |= flag; ieee80211_syncflag_ht_locked(ic, flag); IEEE80211_UNLOCK(ic); d318 1 a318 3 * Synchronize flags_vht bit state in the com structure * according to the state of all vap's. This is used, * for example, to handle state changes via ioctls. d320 2 a321 2 static void ieee80211_syncflag_vht_locked(struct ieee80211com *ic, int flag) d323 8 a330 170 struct ieee80211vap *vap; int bit; IEEE80211_LOCK_ASSERT(ic); bit = 0; TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) if (vap->iv_flags_vht & flag) { bit = 1; break; } if (bit) ic->ic_flags_vht |= flag; else ic->ic_flags_vht &= ~flag; } void ieee80211_syncflag_vht(struct ieee80211vap *vap, int flag) { struct ieee80211com *ic = vap->iv_ic; IEEE80211_LOCK(ic); if (flag < 0) { flag = -flag; vap->iv_flags_vht &= ~flag; } else vap->iv_flags_vht |= flag; ieee80211_syncflag_vht_locked(ic, flag); IEEE80211_UNLOCK(ic); } /* * Synchronize flags_ext bit state in the com structure * according to the state of all vap's. This is used, * for example, to handle state changes via ioctls. */ static void ieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag) { struct ieee80211vap *vap; int bit; IEEE80211_LOCK_ASSERT(ic); bit = 0; TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) if (vap->iv_flags_ext & flag) { bit = 1; break; } if (bit) ic->ic_flags_ext |= flag; else ic->ic_flags_ext &= ~flag; } void ieee80211_syncflag_ext(struct ieee80211vap *vap, int flag) { struct ieee80211com *ic = vap->iv_ic; IEEE80211_LOCK(ic); if (flag < 0) { flag = -flag; vap->iv_flags_ext &= ~flag; } else vap->iv_flags_ext |= flag; ieee80211_syncflag_ext_locked(ic, flag); IEEE80211_UNLOCK(ic); } static __inline int mapgsm(u_int freq, u_int flags) { freq *= 10; if (flags & IEEE80211_CHAN_QUARTER) freq += 5; else if (flags & IEEE80211_CHAN_HALF) freq += 10; else freq += 20; /* NB: there is no 907/20 wide but leave room */ return (freq - 906*10) / 5; } static __inline int mappsb(u_int freq, u_int flags) { return 37 + ((freq * 10) + ((freq % 5) == 2 ? 5 : 0) - 49400) / 5; } /* * Convert MHz frequency to IEEE channel number. */ int ieee80211_mhz2ieee(u_int freq, u_int flags) { #define IS_FREQ_IN_PSB(_freq) ((_freq) > 4940 && (_freq) < 4990) if (flags & IEEE80211_CHAN_GSM) return mapgsm(freq, flags); if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ if (freq == 2484) return 14; if (freq < 2484) return ((int) freq - 2407) / 5; else return 15 + ((freq - 2512) / 20); } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */ if (freq <= 5000) { /* XXX check regdomain? */ if (IS_FREQ_IN_PSB(freq)) return mappsb(freq, flags); return (freq - 4000) / 5; } else return (freq - 5000) / 5; } else { /* either, guess */ if (freq == 2484) return 14; if (freq < 2484) { if (907 <= freq && freq <= 922) return mapgsm(freq, flags); return ((int) freq - 2407) / 5; } if (freq < 5000) { if (IS_FREQ_IN_PSB(freq)) return mappsb(freq, flags); else if (freq > 4900) return (freq - 4000) / 5; else return 15 + ((freq - 2512) / 20); } return (freq - 5000) / 5; } #undef IS_FREQ_IN_PSB } /* * Convert channel to IEEE channel number. */ int ieee80211_chan2ieee(struct ieee80211com *ic, const struct ieee80211_channel *c) { if (c == NULL) { ic_printf(ic, "invalid channel (NULL)\n"); return 0; /* XXX */ } return (c == IEEE80211_CHAN_ANYC ? IEEE80211_CHAN_ANY : c->ic_ieee); } /* * Convert IEEE channel number to MHz frequency. */ u_int ieee80211_ieee2mhz(u_int chan, u_int flags) { if (flags & IEEE80211_CHAN_GSM) return 907 + 5 * (chan / 10); if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ if (chan == 14) return 2484; if (chan < 14) return 2407 + chan*5; else return 2512 + ((chan-15)*20); } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */ if (flags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)) { chan -= 37; return 4940 + chan*5 + (chan % 5 ? 2 : 0); } a332 1 /* XXX can't distinguish PSB+GSM channels */ a342 698 static __inline void set_extchan(struct ieee80211_channel *c) { /* * IEEE Std 802.11-2012, page 1738, subclause 20.3.15.4: * "the secondary channel number shall be 'N + [1,-1] * 4' */ if (c->ic_flags & IEEE80211_CHAN_HT40U) c->ic_extieee = c->ic_ieee + 4; else if (c->ic_flags & IEEE80211_CHAN_HT40D) c->ic_extieee = c->ic_ieee - 4; else c->ic_extieee = 0; } /* * Populate the freq1/freq2 fields as appropriate for VHT channels. * * This for now uses a hard-coded list of 80MHz wide channels. * * For HT20/HT40, freq1 just is the centre frequency of the 40MHz * wide channel we've already decided upon. * * For VHT80 and VHT160, there are only a small number of fixed * 80/160MHz wide channels, so we just use those. * * This is all likely very very wrong - both the regulatory code * and this code needs to ensure that all four channels are * available and valid before the VHT80 (and eight for VHT160) channel * is created. */ struct vht_chan_range { uint16_t freq_start; uint16_t freq_end; }; struct vht_chan_range vht80_chan_ranges[] = { { 5170, 5250 }, { 5250, 5330 }, { 5490, 5570 }, { 5570, 5650 }, { 5650, 5730 }, { 5735, 5815 }, { 0, 0, } }; static int set_vht_extchan(struct ieee80211_channel *c) { int i; if (! IEEE80211_IS_CHAN_VHT(c)) { return (0); } if (IEEE80211_IS_CHAN_VHT20(c)) { c->ic_vht_ch_freq1 = c->ic_ieee; return (1); } if (IEEE80211_IS_CHAN_VHT40(c)) { if (IEEE80211_IS_CHAN_HT40U(c)) c->ic_vht_ch_freq1 = c->ic_ieee + 2; else if (IEEE80211_IS_CHAN_HT40D(c)) c->ic_vht_ch_freq1 = c->ic_ieee - 2; else return (0); return (1); } if (IEEE80211_IS_CHAN_VHT80(c)) { for (i = 0; vht80_chan_ranges[i].freq_start != 0; i++) { if (c->ic_freq >= vht80_chan_ranges[i].freq_start && c->ic_freq < vht80_chan_ranges[i].freq_end) { int midpoint; midpoint = vht80_chan_ranges[i].freq_start + 40; c->ic_vht_ch_freq1 = ieee80211_mhz2ieee(midpoint, c->ic_flags); c->ic_vht_ch_freq2 = 0; #if 0 printf("%s: %d, freq=%d, midpoint=%d, freq1=%d, freq2=%d\n", __func__, c->ic_ieee, c->ic_freq, midpoint, c->ic_vht_ch_freq1, c->ic_vht_ch_freq2); #endif return (1); } } return (0); } printf("%s: unknown VHT channel type (ieee=%d, flags=0x%08x)\n", __func__, c->ic_ieee, c->ic_flags); return (0); } /* * Return whether the current channel could possibly be a part of * a VHT80 channel. * * This doesn't check that the whole range is in the allowed list * according to regulatory. */ static int is_vht80_valid_freq(uint16_t freq) { int i; for (i = 0; vht80_chan_ranges[i].freq_start != 0; i++) { if (freq >= vht80_chan_ranges[i].freq_start && freq < vht80_chan_ranges[i].freq_end) return (1); } return (0); } static int addchan(struct ieee80211_channel chans[], int maxchans, int *nchans, uint8_t ieee, uint16_t freq, int8_t maxregpower, uint32_t flags) { struct ieee80211_channel *c; if (*nchans >= maxchans) return (ENOBUFS); #if 0 printf("%s: %d: ieee=%d, freq=%d, flags=0x%08x\n", __func__, *nchans, ieee, freq, flags); #endif c = &chans[(*nchans)++]; c->ic_ieee = ieee; c->ic_freq = freq != 0 ? freq : ieee80211_ieee2mhz(ieee, flags); c->ic_maxregpower = maxregpower; c->ic_maxpower = 2 * maxregpower; c->ic_flags = flags; c->ic_vht_ch_freq1 = 0; c->ic_vht_ch_freq2 = 0; set_extchan(c); set_vht_extchan(c); return (0); } static int copychan_prev(struct ieee80211_channel chans[], int maxchans, int *nchans, uint32_t flags) { struct ieee80211_channel *c; KASSERT(*nchans > 0, ("channel list is empty\n")); if (*nchans >= maxchans) return (ENOBUFS); #if 0 printf("%s: %d: flags=0x%08x\n", __func__, *nchans, flags); #endif c = &chans[(*nchans)++]; c[0] = c[-1]; c->ic_flags = flags; c->ic_vht_ch_freq1 = 0; c->ic_vht_ch_freq2 = 0; set_extchan(c); set_vht_extchan(c); return (0); } /* * XXX VHT-2GHz */ static void getflags_2ghz(const uint8_t bands[], uint32_t flags[], int ht40) { int nmodes; nmodes = 0; if (isset(bands, IEEE80211_MODE_11B)) flags[nmodes++] = IEEE80211_CHAN_B; if (isset(bands, IEEE80211_MODE_11G)) flags[nmodes++] = IEEE80211_CHAN_G; if (isset(bands, IEEE80211_MODE_11NG)) flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT20; if (ht40) { flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U; flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D; } flags[nmodes] = 0; } static void getflags_5ghz(const uint8_t bands[], uint32_t flags[], int ht40, int vht80) { int nmodes; /* * the addchan_list function seems to expect the flags array to * be in channel width order, so the VHT bits are interspersed * as appropriate to maintain said order. * * It also assumes HT40U is before HT40D. */ nmodes = 0; /* 20MHz */ if (isset(bands, IEEE80211_MODE_11A)) flags[nmodes++] = IEEE80211_CHAN_A; if (isset(bands, IEEE80211_MODE_11NA)) flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT20; if (isset(bands, IEEE80211_MODE_VHT_5GHZ)) { flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT20 | IEEE80211_CHAN_VHT20; } /* 40MHz */ if (ht40) { flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U; } if (ht40 && isset(bands, IEEE80211_MODE_VHT_5GHZ)) { flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U | IEEE80211_CHAN_VHT40U; } if (ht40) { flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D; } if (ht40 && isset(bands, IEEE80211_MODE_VHT_5GHZ)) { flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D | IEEE80211_CHAN_VHT40D; } /* 80MHz */ if (vht80 && isset(bands, IEEE80211_MODE_VHT_5GHZ)) { flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U | IEEE80211_CHAN_VHT80; flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D | IEEE80211_CHAN_VHT80; } /* XXX VHT80+80 */ /* XXX VHT160 */ flags[nmodes] = 0; } static void getflags(const uint8_t bands[], uint32_t flags[], int ht40, int vht80) { flags[0] = 0; if (isset(bands, IEEE80211_MODE_11A) || isset(bands, IEEE80211_MODE_11NA) || isset(bands, IEEE80211_MODE_VHT_5GHZ)) { if (isset(bands, IEEE80211_MODE_11B) || isset(bands, IEEE80211_MODE_11G) || isset(bands, IEEE80211_MODE_11NG) || isset(bands, IEEE80211_MODE_VHT_2GHZ)) return; getflags_5ghz(bands, flags, ht40, vht80); } else getflags_2ghz(bands, flags, ht40); } /* * Add one 20 MHz channel into specified channel list. */ /* XXX VHT */ int ieee80211_add_channel(struct ieee80211_channel chans[], int maxchans, int *nchans, uint8_t ieee, uint16_t freq, int8_t maxregpower, uint32_t chan_flags, const uint8_t bands[]) { uint32_t flags[IEEE80211_MODE_MAX]; int i, error; getflags(bands, flags, 0, 0); KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__)); error = addchan(chans, maxchans, nchans, ieee, freq, maxregpower, flags[0] | chan_flags); for (i = 1; flags[i] != 0 && error == 0; i++) { error = copychan_prev(chans, maxchans, nchans, flags[i] | chan_flags); } return (error); } static struct ieee80211_channel * findchannel(struct ieee80211_channel chans[], int nchans, uint16_t freq, uint32_t flags) { struct ieee80211_channel *c; int i; flags &= IEEE80211_CHAN_ALLTURBO; /* brute force search */ for (i = 0; i < nchans; i++) { c = &chans[i]; if (c->ic_freq == freq && (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags) return c; } return NULL; } /* * Add 40 MHz channel pair into specified channel list. */ /* XXX VHT */ int ieee80211_add_channel_ht40(struct ieee80211_channel chans[], int maxchans, int *nchans, uint8_t ieee, int8_t maxregpower, uint32_t flags) { struct ieee80211_channel *cent, *extc; uint16_t freq; int error; freq = ieee80211_ieee2mhz(ieee, flags); /* * Each entry defines an HT40 channel pair; find the * center channel, then the extension channel above. */ flags |= IEEE80211_CHAN_HT20; cent = findchannel(chans, *nchans, freq, flags); if (cent == NULL) return (EINVAL); extc = findchannel(chans, *nchans, freq + 20, flags); if (extc == NULL) return (ENOENT); flags &= ~IEEE80211_CHAN_HT; error = addchan(chans, maxchans, nchans, cent->ic_ieee, cent->ic_freq, maxregpower, flags | IEEE80211_CHAN_HT40U); if (error != 0) return (error); error = addchan(chans, maxchans, nchans, extc->ic_ieee, extc->ic_freq, maxregpower, flags | IEEE80211_CHAN_HT40D); return (error); } /* * Fetch the center frequency for the primary channel. */ uint32_t ieee80211_get_channel_center_freq(const struct ieee80211_channel *c) { return (c->ic_freq); } /* * Fetch the center frequency for the primary BAND channel. * * For 5, 10, 20MHz channels it'll be the normally configured channel * frequency. * * For 40MHz, 80MHz, 160Mhz channels it'll the the centre of the * wide channel, not the centre of the primary channel (that's ic_freq). * * For 80+80MHz channels this will be the centre of the primary * 80MHz channel; the secondary 80MHz channel will be center_freq2(). */ uint32_t ieee80211_get_channel_center_freq1(const struct ieee80211_channel *c) { /* * VHT - use the pre-calculated centre frequency * of the given channel. */ if (IEEE80211_IS_CHAN_VHT(c)) return (ieee80211_ieee2mhz(c->ic_vht_ch_freq1, c->ic_flags)); if (IEEE80211_IS_CHAN_HT40U(c)) { return (c->ic_freq + 10); } if (IEEE80211_IS_CHAN_HT40D(c)) { return (c->ic_freq - 10); } return (c->ic_freq); } /* * For now, no 80+80 support; it will likely always return 0. */ uint32_t ieee80211_get_channel_center_freq2(const struct ieee80211_channel *c) { if (IEEE80211_IS_CHAN_VHT(c) && (c->ic_vht_ch_freq2 != 0)) return (ieee80211_ieee2mhz(c->ic_vht_ch_freq2, c->ic_flags)); return (0); } /* * Adds channels into specified channel list (ieee[] array must be sorted). * Channels are already sorted. */ static int add_chanlist(struct ieee80211_channel chans[], int maxchans, int *nchans, const uint8_t ieee[], int nieee, uint32_t flags[]) { uint16_t freq; int i, j, error; int is_vht; for (i = 0; i < nieee; i++) { freq = ieee80211_ieee2mhz(ieee[i], flags[0]); for (j = 0; flags[j] != 0; j++) { /* * Notes: * + HT40 and VHT40 channels occur together, so * we need to be careful that we actually allow that. * + VHT80, VHT160 will coexist with HT40/VHT40, so * make sure it's not skipped because of the overlap * check used for (V)HT40. */ is_vht = !! (flags[j] & IEEE80211_CHAN_VHT); /* * Test for VHT80. * XXX This is all very broken right now. * What we /should/ do is: * * + check that the frequency is in the list of * allowed VHT80 ranges; and * + the other 3 channels in the list are actually * also available. */ if (is_vht && flags[j] & IEEE80211_CHAN_VHT80) if (! is_vht80_valid_freq(freq)) continue; /* * Test for (V)HT40. * * This is also a fall through from VHT80; as we only * allow a VHT80 channel if the VHT40 combination is * also valid. If the VHT40 form is not valid then * we certainly can't do VHT80.. */ if (flags[j] & IEEE80211_CHAN_HT40D) /* * Can't have a "lower" channel if we are the * first channel. * * Can't have a "lower" channel if it's below/ * within 20MHz of the first channel. * * Can't have a "lower" channel if the channel * below it is not 20MHz away. */ if (i == 0 || ieee[i] < ieee[0] + 4 || freq - 20 != ieee80211_ieee2mhz(ieee[i] - 4, flags[j])) continue; if (flags[j] & IEEE80211_CHAN_HT40U) /* * Can't have an "upper" channel if we are * the last channel. * * Can't have an "upper" channel be above the * last channel in the list. * * Can't have an "upper" channel if the next * channel according to the math isn't 20MHz * away. (Likely for channel 13/14.) */ if (i == nieee - 1 || ieee[i] + 4 > ieee[nieee - 1] || freq + 20 != ieee80211_ieee2mhz(ieee[i] + 4, flags[j])) continue; if (j == 0) { error = addchan(chans, maxchans, nchans, ieee[i], freq, 0, flags[j]); } else { error = copychan_prev(chans, maxchans, nchans, flags[j]); } if (error != 0) return (error); } } return (0); } int ieee80211_add_channel_list_2ghz(struct ieee80211_channel chans[], int maxchans, int *nchans, const uint8_t ieee[], int nieee, const uint8_t bands[], int ht40) { uint32_t flags[IEEE80211_MODE_MAX]; /* XXX no VHT for now */ getflags_2ghz(bands, flags, ht40); KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__)); return (add_chanlist(chans, maxchans, nchans, ieee, nieee, flags)); } int ieee80211_add_channel_list_5ghz(struct ieee80211_channel chans[], int maxchans, int *nchans, const uint8_t ieee[], int nieee, const uint8_t bands[], int ht40) { uint32_t flags[IEEE80211_MODE_MAX]; int vht80 = 0; /* * For now, assume VHT == VHT80 support as a minimum. */ if (isset(bands, IEEE80211_MODE_VHT_5GHZ)) vht80 = 1; getflags_5ghz(bands, flags, ht40, vht80); KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__)); return (add_chanlist(chans, maxchans, nchans, ieee, nieee, flags)); } /* * Locate a channel given a frequency+flags. We cache * the previous lookup to optimize switching between two * channels--as happens with dynamic turbo. */ struct ieee80211_channel * ieee80211_find_channel(struct ieee80211com *ic, int freq, int flags) { struct ieee80211_channel *c; flags &= IEEE80211_CHAN_ALLTURBO; c = ic->ic_prevchan; if (c != NULL && c->ic_freq == freq && (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags) return c; /* brute force search */ return (findchannel(ic->ic_channels, ic->ic_nchans, freq, flags)); } /* * Locate a channel given a channel number+flags. We cache * the previous lookup to optimize switching between two * channels--as happens with dynamic turbo. */ struct ieee80211_channel * ieee80211_find_channel_byieee(struct ieee80211com *ic, int ieee, int flags) { struct ieee80211_channel *c; int i; flags &= IEEE80211_CHAN_ALLTURBO; c = ic->ic_prevchan; if (c != NULL && c->ic_ieee == ieee && (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags) return c; /* brute force search */ for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; if (c->ic_ieee == ieee && (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags) return c; } return NULL; } /* * Lookup a channel suitable for the given rx status. * * This is used to find a channel for a frame (eg beacon, probe * response) based purely on the received PHY information. * * For now it tries to do it based on R_FREQ / R_IEEE. * This is enough for 11bg and 11a (and thus 11ng/11na) * but it will not be enough for GSM, PSB channels and the * like. It also doesn't know about legacy-turbog and * legacy-turbo modes, which some offload NICs actually * support in weird ways. * * Takes the ic and rxstatus; returns the channel or NULL * if not found. * * XXX TODO: Add support for that when the need arises. */ struct ieee80211_channel * ieee80211_lookup_channel_rxstatus(struct ieee80211vap *vap, const struct ieee80211_rx_stats *rxs) { struct ieee80211com *ic = vap->iv_ic; uint32_t flags; struct ieee80211_channel *c; if (rxs == NULL) return (NULL); /* * Strictly speaking we only use freq for now, * however later on we may wish to just store * the ieee for verification. */ if ((rxs->r_flags & IEEE80211_R_FREQ) == 0) return (NULL); if ((rxs->r_flags & IEEE80211_R_IEEE) == 0) return (NULL); /* * If the rx status contains a valid ieee/freq, then * ensure we populate the correct channel information * in rxchan before passing it up to the scan infrastructure. * Offload NICs will pass up beacons from all channels * during background scans. */ /* Determine a band */ /* XXX should be done by the driver? */ if (rxs->c_freq < 3000) { flags = IEEE80211_CHAN_G; } else { flags = IEEE80211_CHAN_A; } /* Channel lookup */ c = ieee80211_find_channel(ic, rxs->c_freq, flags); IEEE80211_DPRINTF(vap, IEEE80211_MSG_INPUT, "%s: freq=%d, ieee=%d, flags=0x%08x; c=%p\n", __func__, (int) rxs->c_freq, (int) rxs->c_ieee, flags, c); return (c); } static void addmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword) { #define ADD(_ic, _s, _o) \ ifmedia_add(media, \ IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL) static const u_int mopts[IEEE80211_MODE_MAX] = { [IEEE80211_MODE_AUTO] = IFM_AUTO, [IEEE80211_MODE_11A] = IFM_IEEE80211_11A, [IEEE80211_MODE_11B] = IFM_IEEE80211_11B, [IEEE80211_MODE_11G] = IFM_IEEE80211_11G, [IEEE80211_MODE_FH] = IFM_IEEE80211_FH, [IEEE80211_MODE_TURBO_A] = IFM_IEEE80211_11A|IFM_IEEE80211_TURBO, [IEEE80211_MODE_TURBO_G] = IFM_IEEE80211_11G|IFM_IEEE80211_TURBO, [IEEE80211_MODE_STURBO_A] = IFM_IEEE80211_11A|IFM_IEEE80211_TURBO, [IEEE80211_MODE_HALF] = IFM_IEEE80211_11A, /* XXX */ [IEEE80211_MODE_QUARTER] = IFM_IEEE80211_11A, /* XXX */ [IEEE80211_MODE_11NA] = IFM_IEEE80211_11NA, [IEEE80211_MODE_11NG] = IFM_IEEE80211_11NG, [IEEE80211_MODE_VHT_2GHZ] = IFM_IEEE80211_VHT2G, [IEEE80211_MODE_VHT_5GHZ] = IFM_IEEE80211_VHT5G, }; u_int mopt; mopt = mopts[mode]; if (addsta) ADD(ic, mword, mopt); /* STA mode has no cap */ if (caps & IEEE80211_C_IBSS) ADD(media, mword, mopt | IFM_IEEE80211_ADHOC); if (caps & IEEE80211_C_HOSTAP) ADD(media, mword, mopt | IFM_IEEE80211_HOSTAP); if (caps & IEEE80211_C_AHDEMO) ADD(media, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0); if (caps & IEEE80211_C_MONITOR) ADD(media, mword, mopt | IFM_IEEE80211_MONITOR); if (caps & IEEE80211_C_WDS) ADD(media, mword, mopt | IFM_IEEE80211_WDS); if (caps & IEEE80211_C_MBSS) ADD(media, mword, mopt | IFM_IEEE80211_MBSS); #undef ADD } d345 2 a346 1 * rate tables. d348 2 a349 3 static int ieee80211_media_setup(struct ieee80211com *ic, struct ifmedia *media, int caps, int addsta, d352 6 a357 2 int i, j, rate, maxrate, mword, r; enum ieee80211_phymode mode; d362 10 d374 1 a374 1 ifmedia_init(media, 0, media_change, media_stat); a375 3 /* * Add media for legacy operating modes. */ d377 11 a387 2 for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) { if (isclr(ic->ic_modecaps, mode)) d389 10 a398 1 addmedia(media, caps, addsta, mode, IFM_AUTO); d407 9 a415 1 addmedia(media, caps, addsta, mode, mword); d417 1 a417 1 * Add legacy rate to the collection of all rates. d438 10 a447 32 /* NB: remove media options from mword */ addmedia(media, caps, addsta, IEEE80211_MODE_AUTO, IFM_SUBTYPE(mword)); } /* * Add HT/11n media. Note that we do not have enough * bits in the media subtype to express the MCS so we * use a "placeholder" media subtype and any fixed MCS * must be specified with a different mechanism. */ for (; mode <= IEEE80211_MODE_11NG; mode++) { if (isclr(ic->ic_modecaps, mode)) continue; addmedia(media, caps, addsta, mode, IFM_AUTO); addmedia(media, caps, addsta, mode, IFM_IEEE80211_MCS); } if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) || isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) { addmedia(media, caps, addsta, IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS); i = ic->ic_txstream * 8 - 1; if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) rate = ieee80211_htrates[i].ht40_rate_400ns; else if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40)) rate = ieee80211_htrates[i].ht40_rate_800ns; else if ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20)) rate = ieee80211_htrates[i].ht20_rate_400ns; else rate = ieee80211_htrates[i].ht20_rate_800ns; if (rate > maxrate) maxrate = rate; d449 2 d452 3 a454 29 /* * Add VHT media. */ for (; mode <= IEEE80211_MODE_VHT_5GHZ; mode++) { if (isclr(ic->ic_modecaps, mode)) continue; addmedia(media, caps, addsta, mode, IFM_AUTO); addmedia(media, caps, addsta, mode, IFM_IEEE80211_VHT); /* XXX TODO: VHT maxrate */ } return maxrate; } /* XXX inline or eliminate? */ const struct ieee80211_rateset * ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *c) { /* XXX does this work for 11ng basic rates? */ return &ic->ic_sup_rates[ieee80211_chan2mode(c)]; } /* XXX inline or eliminate? */ const struct ieee80211_htrateset * ieee80211_get_suphtrates(struct ieee80211com *ic, const struct ieee80211_channel *c) { return &ic->ic_sup_htrates; d460 3 a462 3 int i, rate, mword; enum ieee80211_phymode mode; const struct ieee80211_rateset *rs; d464 2 a465 3 /* NB: skip AUTO since it has no rates */ for (mode = IEEE80211_MODE_AUTO+1; mode < IEEE80211_MODE_11NA; mode++) { if (isclr(ic->ic_modecaps, mode)) d467 2 a468 1 ic_printf(ic, "%s rates: ", ieee80211_phymode_name[mode]); d471 2 a472 1 mword = ieee80211_rate2media(ic, rs->rs_rates[i], mode); d475 3 a477 3 rate = ieee80211_media2rate(mword); printf("%s%d%sMbps", (i != 0 ? " " : ""), rate / 2, ((rate & 0x1) != 0 ? ".5" : "")); d479 1 a479 1 printf("\n"); a480 2 ieee80211_ht_announce(ic); ieee80211_vht_announce(ic); d483 32 a514 2 void ieee80211_announce_channels(struct ieee80211com *ic) d516 2 a517 3 const struct ieee80211_channel *c; char type; int i, cw; d519 7 a525 37 printf("Chan Freq CW RegPwr MinPwr MaxPwr\n"); for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; if (IEEE80211_IS_CHAN_ST(c)) type = 'S'; else if (IEEE80211_IS_CHAN_108A(c)) type = 'T'; else if (IEEE80211_IS_CHAN_108G(c)) type = 'G'; else if (IEEE80211_IS_CHAN_HT(c)) type = 'n'; else if (IEEE80211_IS_CHAN_A(c)) type = 'a'; else if (IEEE80211_IS_CHAN_ANYG(c)) type = 'g'; else if (IEEE80211_IS_CHAN_B(c)) type = 'b'; else type = 'f'; if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_TURBO(c)) cw = 40; else if (IEEE80211_IS_CHAN_HALF(c)) cw = 10; else if (IEEE80211_IS_CHAN_QUARTER(c)) cw = 5; else cw = 20; printf("%4d %4d%c %2d%c %6d %4d.%d %4d.%d\n" , c->ic_ieee, c->ic_freq, type , cw , IEEE80211_IS_CHAN_HT40U(c) ? '+' : IEEE80211_IS_CHAN_HT40D(c) ? '-' : ' ' , c->ic_maxregpower , c->ic_minpower / 2, c->ic_minpower & 1 ? 5 : 0 , c->ic_maxpower / 2, c->ic_maxpower & 1 ? 5 : 0 ); } d528 5 a532 2 static int media2mode(const struct ifmedia_entry *ime, uint32_t flags, uint16_t *mode) d534 15 d551 1 a551 1 *mode = IEEE80211_MODE_11A; d554 1 a554 1 *mode = IEEE80211_MODE_11B; d557 1 a557 1 *mode = IEEE80211_MODE_11G; d560 1 a560 7 *mode = IEEE80211_MODE_FH; break; case IFM_IEEE80211_11NA: *mode = IEEE80211_MODE_11NA; break; case IFM_IEEE80211_11NG: *mode = IEEE80211_MODE_11NG; d563 1 a563 1 *mode = IEEE80211_MODE_AUTO; d566 1 a566 1 return 0; d573 4 a576 7 if (*mode == IEEE80211_MODE_11A) { if (flags & IEEE80211_F_TURBOP) *mode = IEEE80211_MODE_TURBO_A; else *mode = IEEE80211_MODE_STURBO_A; } else if (*mode == IEEE80211_MODE_11G) *mode = IEEE80211_MODE_TURBO_G; d578 42 a619 1 return 0; d621 1 a621 3 /* XXX HT40 +/- */ return 1; } d623 14 a636 9 /* * Handle a media change request on the vap interface. */ int ieee80211_media_change(struct ifnet *ifp) { struct ieee80211vap *vap = ifp->if_softc; struct ifmedia_entry *ime = vap->iv_media.ifm_cur; uint16_t newmode; d638 14 a651 5 if (!media2mode(ime, vap->iv_flags, &newmode)) return EINVAL; if (vap->iv_des_mode != newmode) { vap->iv_des_mode = newmode; /* XXX kick state machine if up+running */ d653 1 a653 2 return 0; } d655 9 a663 8 /* * Common code to calculate the media status word * from the operating mode and channel state. */ static int media_status(enum ieee80211_opmode opmode, const struct ieee80211_channel *chan) { int status; d665 6 a670 35 status = IFM_IEEE80211; switch (opmode) { case IEEE80211_M_STA: break; case IEEE80211_M_IBSS: status |= IFM_IEEE80211_ADHOC; break; case IEEE80211_M_HOSTAP: status |= IFM_IEEE80211_HOSTAP; break; case IEEE80211_M_MONITOR: status |= IFM_IEEE80211_MONITOR; break; case IEEE80211_M_AHDEMO: status |= IFM_IEEE80211_ADHOC | IFM_FLAG0; break; case IEEE80211_M_WDS: status |= IFM_IEEE80211_WDS; break; case IEEE80211_M_MBSS: status |= IFM_IEEE80211_MBSS; break; } if (IEEE80211_IS_CHAN_HTA(chan)) { status |= IFM_IEEE80211_11NA; } else if (IEEE80211_IS_CHAN_HTG(chan)) { status |= IFM_IEEE80211_11NG; } else if (IEEE80211_IS_CHAN_A(chan)) { status |= IFM_IEEE80211_11A; } else if (IEEE80211_IS_CHAN_B(chan)) { status |= IFM_IEEE80211_11B; } else if (IEEE80211_IS_CHAN_ANYG(chan)) { status |= IFM_IEEE80211_11G; } else if (IEEE80211_IS_CHAN_FHSS(chan)) { status |= IFM_IEEE80211_FH; a671 1 /* XXX else complain? */ d673 28 a700 7 if (IEEE80211_IS_CHAN_TURBO(chan)) status |= IFM_IEEE80211_TURBO; #if 0 if (IEEE80211_IS_CHAN_HT20(chan)) status |= IFM_IEEE80211_HT20; if (IEEE80211_IS_CHAN_HT40(chan)) status |= IFM_IEEE80211_HT40; d702 1 a702 1 return status; d708 2 a709 3 struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; enum ieee80211_phymode mode; d711 5 d717 2 a718 7 /* * NB: use the current channel's mode to lock down a xmit * rate only when running; otherwise we may have a mismatch * in which case the rate will not be convertible. */ if (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP) { a719 4 mode = ieee80211_chan2mode(ic->ic_curchan); } else mode = IEEE80211_MODE_AUTO; imr->ifm_active = media_status(vap->iv_opmode, ic->ic_curchan); d723 1 a723 1 if (vap->iv_txparms[mode].ucastrate != IEEE80211_FIXED_RATE_NONE) { d727 1 d729 2 a730 2 vap->iv_txparms[mode].ucastrate, mode); } else if (vap->iv_opmode == IEEE80211_M_STA) { d734 1 d736 1 a736 1 vap->iv_bss->ni_txrate, mode); d739 64 a802 2 if (imr->ifm_status & IFM_ACTIVE) imr->ifm_current = imr->ifm_active; d805 9 d823 90 d914 1 a914 4 * Adjust basic rates in 11b/11g supported rate set. * Note that if operating on a hal/quarter rate channel * this is a noop as those rates sets are different * and used instead. d916 21 a936 2 if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11B) ieee80211_setbasicrates(&ic->ic_sup_rates[mode], mode); d940 1 d943 1 d947 4 a950 1 * Return the phy mode for with the specified channel. d953 1 a953 1 ieee80211_chan2mode(const struct ieee80211_channel *chan) d955 1 a955 14 if (IEEE80211_IS_CHAN_VHT_2GHZ(chan)) return IEEE80211_MODE_VHT_2GHZ; else if (IEEE80211_IS_CHAN_VHT_5GHZ(chan)) return IEEE80211_MODE_VHT_5GHZ; else if (IEEE80211_IS_CHAN_HTA(chan)) return IEEE80211_MODE_11NA; else if (IEEE80211_IS_CHAN_HTG(chan)) return IEEE80211_MODE_11NG; else if (IEEE80211_IS_CHAN_108G(chan)) return IEEE80211_MODE_TURBO_G; else if (IEEE80211_IS_CHAN_ST(chan)) return IEEE80211_MODE_STURBO_A; else if (IEEE80211_IS_CHAN_TURBO(chan)) d957 1 a957 5 else if (IEEE80211_IS_CHAN_HALF(chan)) return IEEE80211_MODE_HALF; else if (IEEE80211_IS_CHAN_QUARTER(chan)) return IEEE80211_MODE_QUARTER; else if (IEEE80211_IS_CHAN_A(chan)) d959 11 a969 1 else if (IEEE80211_IS_CHAN_ANYG(chan)) d971 1 a971 1 else if (IEEE80211_IS_CHAN_B(chan)) a972 23 else if (IEEE80211_IS_CHAN_FHSS(chan)) return IEEE80211_MODE_FH; /* NB: should not get here */ printf("%s: cannot map channel to mode; freq %u flags 0x%x\n", __func__, chan->ic_freq, chan->ic_flags); return IEEE80211_MODE_11B; } struct ratemedia { u_int match; /* rate + mode */ u_int media; /* if_media rate */ }; static int findmedia(const struct ratemedia rates[], int n, u_int match) { int i; for (i = 0; i < n; i++) if (rates[i].match == match) return rates[i].media; return IFM_AUTO; d976 2 a977 3 * Convert IEEE80211 rate value to ifmedia subtype. * Rate is either a legacy rate in units of 0.5Mbps * or an MCS index. d982 5 a986 1 static const struct ratemedia rates[] = { d1014 1 a1014 83 { 6 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM3 }, { 9 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM4 }, { 54 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM27 }, /* NB: OFDM72 doesn't really exist so we don't handle it */ }; static const struct ratemedia htrates[] = { { 0, IFM_IEEE80211_MCS }, { 1, IFM_IEEE80211_MCS }, { 2, IFM_IEEE80211_MCS }, { 3, IFM_IEEE80211_MCS }, { 4, IFM_IEEE80211_MCS }, { 5, IFM_IEEE80211_MCS }, { 6, IFM_IEEE80211_MCS }, { 7, IFM_IEEE80211_MCS }, { 8, IFM_IEEE80211_MCS }, { 9, IFM_IEEE80211_MCS }, { 10, IFM_IEEE80211_MCS }, { 11, IFM_IEEE80211_MCS }, { 12, IFM_IEEE80211_MCS }, { 13, IFM_IEEE80211_MCS }, { 14, IFM_IEEE80211_MCS }, { 15, IFM_IEEE80211_MCS }, { 16, IFM_IEEE80211_MCS }, { 17, IFM_IEEE80211_MCS }, { 18, IFM_IEEE80211_MCS }, { 19, IFM_IEEE80211_MCS }, { 20, IFM_IEEE80211_MCS }, { 21, IFM_IEEE80211_MCS }, { 22, IFM_IEEE80211_MCS }, { 23, IFM_IEEE80211_MCS }, { 24, IFM_IEEE80211_MCS }, { 25, IFM_IEEE80211_MCS }, { 26, IFM_IEEE80211_MCS }, { 27, IFM_IEEE80211_MCS }, { 28, IFM_IEEE80211_MCS }, { 29, IFM_IEEE80211_MCS }, { 30, IFM_IEEE80211_MCS }, { 31, IFM_IEEE80211_MCS }, { 32, IFM_IEEE80211_MCS }, { 33, IFM_IEEE80211_MCS }, { 34, IFM_IEEE80211_MCS }, { 35, IFM_IEEE80211_MCS }, { 36, IFM_IEEE80211_MCS }, { 37, IFM_IEEE80211_MCS }, { 38, IFM_IEEE80211_MCS }, { 39, IFM_IEEE80211_MCS }, { 40, IFM_IEEE80211_MCS }, { 41, IFM_IEEE80211_MCS }, { 42, IFM_IEEE80211_MCS }, { 43, IFM_IEEE80211_MCS }, { 44, IFM_IEEE80211_MCS }, { 45, IFM_IEEE80211_MCS }, { 46, IFM_IEEE80211_MCS }, { 47, IFM_IEEE80211_MCS }, { 48, IFM_IEEE80211_MCS }, { 49, IFM_IEEE80211_MCS }, { 50, IFM_IEEE80211_MCS }, { 51, IFM_IEEE80211_MCS }, { 52, IFM_IEEE80211_MCS }, { 53, IFM_IEEE80211_MCS }, { 54, IFM_IEEE80211_MCS }, { 55, IFM_IEEE80211_MCS }, { 56, IFM_IEEE80211_MCS }, { 57, IFM_IEEE80211_MCS }, { 58, IFM_IEEE80211_MCS }, { 59, IFM_IEEE80211_MCS }, { 60, IFM_IEEE80211_MCS }, { 61, IFM_IEEE80211_MCS }, { 62, IFM_IEEE80211_MCS }, { 63, IFM_IEEE80211_MCS }, { 64, IFM_IEEE80211_MCS }, { 65, IFM_IEEE80211_MCS }, { 66, IFM_IEEE80211_MCS }, { 67, IFM_IEEE80211_MCS }, { 68, IFM_IEEE80211_MCS }, { 69, IFM_IEEE80211_MCS }, { 70, IFM_IEEE80211_MCS }, { 71, IFM_IEEE80211_MCS }, { 72, IFM_IEEE80211_MCS }, { 73, IFM_IEEE80211_MCS }, { 74, IFM_IEEE80211_MCS }, { 75, IFM_IEEE80211_MCS }, { 76, IFM_IEEE80211_MCS }, d1016 1 a1016 1 int m; d1018 1 a1018 20 /* * Check 11n rates first for match as an MCS. */ if (mode == IEEE80211_MODE_11NA) { if (rate & IEEE80211_RATE_MCS) { rate &= ~IEEE80211_RATE_MCS; m = findmedia(htrates, nitems(htrates), rate); if (m != IFM_AUTO) return m | IFM_IEEE80211_11NA; } } else if (mode == IEEE80211_MODE_11NG) { /* NB: 12 is ambiguous, it will be treated as an MCS */ if (rate & IEEE80211_RATE_MCS) { rate &= ~IEEE80211_RATE_MCS; m = findmedia(htrates, nitems(htrates), rate); if (m != IFM_AUTO) return m | IFM_IEEE80211_11NG; } } rate &= IEEE80211_RATE_VAL; a1020 3 case IEEE80211_MODE_HALF: /* XXX good 'nuf */ case IEEE80211_MODE_QUARTER: case IEEE80211_MODE_11NA: d1022 2 a1023 3 case IEEE80211_MODE_STURBO_A: return findmedia(rates, nitems(rates), rate | IFM_IEEE80211_11A); d1025 2 a1026 2 return findmedia(rates, nitems(rates), rate | IFM_IEEE80211_11B); d1028 2 a1029 2 return findmedia(rates, nitems(rates), rate | IFM_IEEE80211_FH); d1032 4 a1035 3 if (ic != NULL && ic->ic_phytype == IEEE80211_T_FH) return findmedia(rates, nitems(rates), rate | IFM_IEEE80211_FH); a1038 1 case IEEE80211_MODE_11NG: d1040 2 a1041 5 return findmedia(rates, nitems(rates), rate | IFM_IEEE80211_11G); case IEEE80211_MODE_VHT_2GHZ: case IEEE80211_MODE_VHT_5GHZ: /* XXX TODO: need to figure out mapping for VHT rates */ return IFM_AUTO; d1043 3 d1047 1 d1053 1 a1059 1 2, /* IFM_IEEE80211_DS1 */ d1063 1 a1073 7 0, /* IFM_IEEE80211_DS354k */ 0, /* IFM_IEEE80211_DS512k */ 6, /* IFM_IEEE80211_OFDM3 */ 9, /* IFM_IEEE80211_OFDM4 */ 54, /* IFM_IEEE80211_OFDM27 */ -1, /* IFM_IEEE80211_MCS */ -1, /* IFM_IEEE80211_VHT */ d1075 1 a1075 1 return IFM_SUBTYPE(mword) < nitems(ieeerates) ? d1077 1 a1077 58 } /* * The following hash function is adapted from "Hash Functions" by Bob Jenkins * ("Algorithm Alley", Dr. Dobbs Journal, September 1997). */ #define mix(a, b, c) \ do { \ a -= b; a -= c; a ^= (c >> 13); \ b -= c; b -= a; b ^= (a << 8); \ c -= a; c -= b; c ^= (b >> 13); \ a -= b; a -= c; a ^= (c >> 12); \ b -= c; b -= a; b ^= (a << 16); \ c -= a; c -= b; c ^= (b >> 5); \ a -= b; a -= c; a ^= (c >> 3); \ b -= c; b -= a; b ^= (a << 10); \ c -= a; c -= b; c ^= (b >> 15); \ } while (/*CONSTCOND*/0) uint32_t ieee80211_mac_hash(const struct ieee80211com *ic, const uint8_t addr[IEEE80211_ADDR_LEN]) { uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = ic->ic_hash_key; b += addr[5] << 8; b += addr[4]; a += addr[3] << 24; a += addr[2] << 16; a += addr[1] << 8; a += addr[0]; mix(a, b, c); return c; } #undef mix char ieee80211_channel_type_char(const struct ieee80211_channel *c) { if (IEEE80211_IS_CHAN_ST(c)) return 'S'; if (IEEE80211_IS_CHAN_108A(c)) return 'T'; if (IEEE80211_IS_CHAN_108G(c)) return 'G'; if (IEEE80211_IS_CHAN_VHT(c)) return 'v'; if (IEEE80211_IS_CHAN_HT(c)) return 'n'; if (IEEE80211_IS_CHAN_A(c)) return 'a'; if (IEEE80211_IS_CHAN_ANYG(c)) return 'g'; if (IEEE80211_IS_CHAN_B(c)) return 'b'; return 'f'; @ 1.56.18.2 log @State save. New kernel config for this brach only. TESTWIFI does produce a kernel. It is not working. athn files not compiling yet and commented out of the TESTWIFI kernel, which only has urtwn 802.11 driver enabled. ieee80211_alq.c and ieee80211_ddb.c not compiling yet. @ text @a0 2 /* $NetBSD: $ */ a29 1 #ifdef __FreeBSD__ a30 1 #endif a43 1 #ifdef __FreeBSD__ a44 5 #elif __NetBSD__ #include #else #error #endif a46 1 #ifdef __FreeBSD__ a47 1 #endif a50 1 #ifdef __FreeBSD__ a51 5 #endif #ifdef __NetBSD__ #include #include #endif a62 5 #ifdef __NetBSD__ #undef KASSERT #define KASSERT(__cond, __complaint) FBSDKASSERT(__cond, __complaint) #endif a105 1 a276 1 #ifdef __FreeBSD__ a288 12 #elif __NetBSD__ void ic_printf(struct ieee80211com *ic, const char * fmt, ...) { va_list ap; printf("%s: ", ic->ic_name); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); } #endif a290 1 #ifdef __FreeBSD__ a292 3 #elif __NetBSD__ static kmutex_t ic_list_mtx; #endif a293 1 #if notyet a321 1 #endif a334 1 #ifdef notyet a341 1 #endif d485 1 a485 1 static __unused uint64_t a528 1 #ifdef __FreeBSD__ a529 2 #endif #ifdef notyet a531 2 #endif #ifdef __FreeBSD__ a532 1 #endif a679 1 #ifdef notyet a681 1 #endif @ 1.56.18.3 log @State save. urtwn now can attach and shows up in the "ifconfig -a" list. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.56.18.2 2018/07/12 16:35:34 phil Exp $ */ a332 2 static uint ic_list_mtx_needsinit = 1; static uint ic_list_mtx_ready = 0; a372 17 #if __NetBSD__ /* Initialize the ic_list_mtx the first time here. * Only want to use the big lock on first try to initialize. * Once initialized, it won't use the big lock any more. */ if (ic_list_mtx_needsinit) { KERNEL_LOCK(1, NULL); if (!ic_list_mtx_ready) { mutex_init(&ic_list_mtx, MUTEX_DEFAULT, IPL_NET); ic_list_mtx_ready = 1; ic_list_mtx_needsinit = 0; /* Doing this one-time initialization here also. */ ieee80211_auth_setup(); } KERNEL_UNLOCK_ONE(NULL); } #endif d378 1 a378 1 #if __FreeBSD__ a385 4 #elif__NetBSD__ /* NNN task/workqueue get it ready.... */ ic->ic_ierrors = 0; ic->ic_oerrors = 0; a386 1 a569 3 #if __NetBSD__ if_initialize(ifp); #endif d574 1 a574 1 #if __FreeBSD__ d577 1 d580 2 a581 2 #if notyet d584 1 d731 1 d734 1 a734 1 a754 4 #if __NetBSD__ if_register(ifp); #endif @ 1.56.18.4 log @State save: urtwn: ifp->if_softc points to a vap, not the urtwn softc, fix code for this. add missing routines, need to get them filled out correctly. 80211: Add back some NetBSD ioctls, start working on the sysctl tree. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.56.18.3 2018/07/16 20:11:11 phil Exp $ */ a50 1 #include d333 2 a367 10 #if __NetBSD__ static int ic_list_mtx_init (void) { mutex_init(&ic_list_mtx, MUTEX_DEFAULT, IPL_NET); ieee80211_auth_setup(); return 0; } #endif d376 15 a390 2 static ONCE_DECL(ic_list_mtx_once); RUN_ONCE(&ic_list_mtx_once, ic_list_mtx_init); a2013 1 printf ("[%d/%s]", mode, ieee80211_phymode_name[mode]); @ 1.56.18.5 log @End of the week state save: Got workqueues doing FreeBSD tasks. (still questions on how correct it is.) Incremental changes in many places. Still *lots* of debugging code that needs to go away some day. "ifconfig urtwn0 up" now does not crash, still needs scan to work properly. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.56.18.4 2018/07/20 20:33:05 phil Exp $ */ d401 2 a402 8 #elif __NetBSD__ /* * Create a workqueue for all state changes, ieee80211_netbsd.* * has glue to translate taskqueue functions to workqueue. */ if (workqueue_create(&ic->ic_tq, "net80211_wq", ieee80211_runwork, ic, PRI_SOFTNET, IPL_NET, WQ_MPSAFE)) panic("net80211 workqueue not created"); a457 1 #if __FreeBSD__ a458 1 #endif a811 1 #if __FreeBSD__ a813 1 #endif @ 1.56.18.6 log @Final changes for 200 hour contract. Still a lot of work to do. With these changes, Station mode works with an open AP. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.56.18.5 2018/07/28 00:49:43 phil Exp $ */ a630 1 /* NNN Done in vap_attach, where is the correct place? */ a757 1 /* NNN also done in vap_setup, which is correct? */ a758 1 @ 1.56.18.7 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.56.18.6 2018/08/15 17:07:02 phil Exp $ */ d32 2 a33 2 #ifdef __NetBSD__ __KERNEL_RCSID(0, "$NetBSD$"); a38 1 #ifdef _KERNEL_OPT a39 1 #endif @ 1.56.18.8 log @Mostly merge changes from HEAD upto 20200411 @ text @d1 1 a1 1 /* $NetBSD$ */ a2014 8 ieee80211_media_init(struct ieee80211com *ic, ifm_change_cb_t media_change, ifm_stat_cb_t media_stat) { ieee80211_media_init_with_lock(ic, media_change, media_stat, NULL); } void d2025 1 a2025 2 aprint_debug("%s: %s rates: ", ifp->if_xname, ieee80211_phymode_name[mode]); d2033 1 a2033 1 aprint_debug("%s%d%sMbps", (i != 0 ? " " : ""), d2036 1 a2036 1 aprint_debug("\n"); @ 1.56.18.9 log @Use if_stat functions. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.56.18.8 2020/04/13 08:05:15 martin Exp $ */ d33 1 a33 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.56.18.8 2020/04/13 08:05:15 martin Exp $"); d2019 1 a2019 7 struct ieee80211vap *vap; vap = TAILQ_FIRST(&ic->ic_vaps); KASSERT(vap != NULL, ("media vap is null")); ifmedia_init_with_lock(&vap->iv_media, 0, media_change, media_stat, NULL); d2033 2 a2034 2 //aprint_debug("%s: %s rates: ", ifp->if_xname, // ieee80211_phymode_name[mode]); @ 1.55 log @src is too big these days to tolerate superfluous apostrophes. It's "its", people! @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.54 2013/03/21 18:30:09 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.54 2013/03/21 18:30:09 christos Exp $"); d46 1 d48 1 @ 1.55.2.1 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.56 2015/08/24 22:21:26 pooka Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.56 2015/08/24 22:21:26 pooka Exp $"); a45 1 #ifdef _KERNEL_OPT a46 1 #endif @ 1.54 log @Instead of always checking for ANYC, make it a valid channel @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.53 2010/04/05 07:22:24 joerg Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.53 2010/04/05 07:22:24 joerg Exp $"); d495 1 a495 1 * Find an instance by it's mac address. @ 1.53 log @Push the bpf_ops usage back into bpf.h. Push the common ifp->if_bpf check into the inline functions as well the fourth argument for bpf_attach. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.52 2010/04/02 03:46:50 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.52 2010/04/02 03:46:50 dyoung Exp $"); d76 4 @ 1.53.8.1 log @sync with head. for a reference, the tree before this commit was tagged as yamt-pagecache-tag8. this commit was splitted into small chunks to avoid a limitation of cvs. ("Protocol error: too many arguments") @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.53 2010/04/05 07:22:24 joerg Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.53 2010/04/05 07:22:24 joerg Exp $"); a75 4 const struct ieee80211_channel ieee80211_channel_anyc = { 0, 0 }; @ 1.53.18.1 log @resync from head @ text @d1 1 a1 1 /* $NetBSD$ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD$"); a75 4 const struct ieee80211_channel ieee80211_channel_anyc = { 0, 0 }; @ 1.53.18.2 log @update from HEAD @ text @a45 1 #ifdef _KERNEL_OPT a46 1 #endif d495 1 a495 1 * Find an instance by its mac address. @ 1.52 log @Delete ieee80211_setbasicrates(). It's buggy, and we drivers can get along fine without it. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.51 2010/03/26 17:18:05 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.51 2010/03/26 17:18:05 dyoung Exp $"); d159 1 a159 1 bpf_ops->bpf_attach(ifp, DLT_IEEE802_11, d261 1 a261 1 bpf_ops->bpf_detach(ifp); @ 1.51 log @In ieee80211_media_init(), change a pointer that we never write through to a pointer to const. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.50 2010/01/19 22:08:17 pooka Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.50 2010/01/19 22:08:17 pooka Exp $"); a94 2 static void ieee80211_setbasicrates(struct ieee80211com *); a216 1 ieee80211_setbasicrates(ic); a808 35 * Mark the basic rates for the 11g rate table based on the * operating mode. For real 11g we mark all the 11b rates * and 6, 12, and 24 OFDM. For 11b compatibility we mark only * 11b rates. There's also a pseudo 11a-mode used to mark only * the basic OFDM rates. */ static void ieee80211_setbasicrates(struct ieee80211com *ic) { static const struct ieee80211_rateset basic[] = { { 0, { } }, /* IEEE80211_MODE_AUTO */ { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */ { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G */ { 0, { } }, /* IEEE80211_MODE_TURBO */ }; enum ieee80211_phymode mode; struct ieee80211_rateset *rs; int i, j; for (mode = 0; mode < IEEE80211_MODE_MAX; mode++) { rs = &ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rs->rs_rates[i] &= IEEE80211_RATE_VAL; for (j = 0; j < basic[mode].rs_nrates; j++) { if (basic[mode].rs_rates[j] != rs->rs_rates[i]) continue; rs->rs_rates[i] |= IEEE80211_RATE_BASIC; break; } } } } /* @ 1.50 log @Redefine bpf linkage through an always present op vector, i.e. #if NBPFILTER is no longer required in the client. This change doesn't yet add support for loading bpf as a module, since drivers can register before bpf is attached. However, callers of bpf can now be modularized. Dynamically loadable bpf could probably be done fairly easily with coordination from the stub driver and the real driver by registering attachments in the stub before the real driver is loaded and doing a handoff. ... and I'm not going to ponder the depths of unload here. Tested with i386/MONOLITHIC, modified MONOLITHIC without bpf and rump. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.49 2009/01/10 12:53:45 cegger Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.49 2009/01/10 12:53:45 cegger Exp $"); d355 1 a355 1 struct ieee80211_rateset *rs; @ 1.50.4.1 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.50 2010/01/19 22:08:17 pooka Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.50 2010/01/19 22:08:17 pooka Exp $"); d95 2 d161 1 a161 1 bpf_attach2(ifp, DLT_IEEE802_11, d219 1 d264 1 a264 1 bpf_detach(ifp); d355 1 a355 1 const struct ieee80211_rateset *rs; d812 35 @ 1.50.2.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD$ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD$"); d95 2 d161 1 a161 1 bpf_attach2(ifp, DLT_IEEE802_11, d219 1 d264 1 a264 1 bpf_detach(ifp); d355 1 a355 1 const struct ieee80211_rateset *rs; d812 35 @ 1.49 log @Introduce ieee80211_setbasicrates(). Use it to set speed in ieee80211_ifattach(). Export new ieee80211_std_rateset_11{a,b,g}. From OpenBSD. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.48 2007/12/01 14:35:51 jmcneill Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.48 2007/12/01 14:35:51 jmcneill Exp $"); a46 1 #include "bpfilter.h" d161 1 a161 2 #if NBPFILTER > 0 bpfattach2(ifp, DLT_IEEE802_11, a162 1 #endif d264 1 a264 3 #if NBPFILTER > 0 bpfdetach(ifp); #endif @ 1.48 log @aprintify @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.47 2006/11/16 01:33:40 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.47 2006/11/16 01:33:40 christos Exp $"); d96 2 d222 1 d807 44 @ 1.48.18.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.48 2007/12/01 14:35:51 jmcneill Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.48 2007/12/01 14:35:51 jmcneill Exp $"); a95 2 static void ieee80211_setbasicrates(struct ieee80211com *); a219 1 ieee80211_setbasicrates(ic); a803 44 const struct ieee80211_rateset ieee80211_std_rateset_11a = { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } }; const struct ieee80211_rateset ieee80211_std_rateset_11b = { 4, { 2, 4, 11, 22 } }; const struct ieee80211_rateset ieee80211_std_rateset_11g = { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; /* * Mark the basic rates for the 11g rate table based on the * operating mode. For real 11g we mark all the 11b rates * and 6, 12, and 24 OFDM. For 11b compatibility we mark only * 11b rates. There's also a pseudo 11a-mode used to mark only * the basic OFDM rates. */ static void ieee80211_setbasicrates(struct ieee80211com *ic) { static const struct ieee80211_rateset basic[] = { { 0, { } }, /* IEEE80211_MODE_AUTO */ { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */ { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G */ { 0, { } }, /* IEEE80211_MODE_TURBO */ }; enum ieee80211_phymode mode; struct ieee80211_rateset *rs; int i, j; for (mode = 0; mode < IEEE80211_MODE_MAX; mode++) { rs = &ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rs->rs_rates[i] &= IEEE80211_RATE_VAL; for (j = 0; j < basic[mode].rs_nrates; j++) { if (basic[mode].rs_rates[j] != rs->rs_rates[i]) continue; rs->rs_rates[i] |= IEEE80211_RATE_BASIC; break; } } } } @ 1.48.18.2 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.48.18.1 2009/05/04 08:14:16 yamt Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.48.18.1 2009/05/04 08:14:16 yamt Exp $"); d47 1 d162 2 a163 1 bpf_ops->bpf_attach(ifp, DLT_IEEE802_11, d165 1 d267 3 a269 1 bpf_ops->bpf_detach(ifp); @ 1.48.18.3 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.48.18.2 2010/03/11 15:04:28 yamt Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.48.18.2 2010/03/11 15:04:28 yamt Exp $"); d95 2 d161 1 a161 1 bpf_attach2(ifp, DLT_IEEE802_11, d219 1 d264 1 a264 1 bpf_detach(ifp); d355 1 a355 1 const struct ieee80211_rateset *rs; d812 35 @ 1.48.26.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.49 2009/01/10 12:53:45 cegger Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.49 2009/01/10 12:53:45 cegger Exp $"); a95 2 static void ieee80211_setbasicrates(struct ieee80211com *); a219 1 ieee80211_setbasicrates(ic); a803 44 const struct ieee80211_rateset ieee80211_std_rateset_11a = { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } }; const struct ieee80211_rateset ieee80211_std_rateset_11b = { 4, { 2, 4, 11, 22 } }; const struct ieee80211_rateset ieee80211_std_rateset_11g = { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; /* * Mark the basic rates for the 11g rate table based on the * operating mode. For real 11g we mark all the 11b rates * and 6, 12, and 24 OFDM. For 11b compatibility we mark only * 11b rates. There's also a pseudo 11a-mode used to mark only * the basic OFDM rates. */ static void ieee80211_setbasicrates(struct ieee80211com *ic) { static const struct ieee80211_rateset basic[] = { { 0, { } }, /* IEEE80211_MODE_AUTO */ { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */ { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G */ { 0, { } }, /* IEEE80211_MODE_TURBO */ }; enum ieee80211_phymode mode; struct ieee80211_rateset *rs; int i, j; for (mode = 0; mode < IEEE80211_MODE_MAX; mode++) { rs = &ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rs->rs_rates[i] &= IEEE80211_RATE_VAL; for (j = 0; j < basic[mode].rs_nrates; j++) { if (basic[mode].rs_rates[j] != rs->rs_rates[i]) continue; rs->rs_rates[i] |= IEEE80211_RATE_BASIC; break; } } } } @ 1.48.14.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD$ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD$"); a95 2 static void ieee80211_setbasicrates(struct ieee80211com *); a219 1 ieee80211_setbasicrates(ic); a803 44 const struct ieee80211_rateset ieee80211_std_rateset_11a = { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } }; const struct ieee80211_rateset ieee80211_std_rateset_11b = { 4, { 2, 4, 11, 22 } }; const struct ieee80211_rateset ieee80211_std_rateset_11g = { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; /* * Mark the basic rates for the 11g rate table based on the * operating mode. For real 11g we mark all the 11b rates * and 6, 12, and 24 OFDM. For 11b compatibility we mark only * 11b rates. There's also a pseudo 11a-mode used to mark only * the basic OFDM rates. */ static void ieee80211_setbasicrates(struct ieee80211com *ic) { static const struct ieee80211_rateset basic[] = { { 0, { } }, /* IEEE80211_MODE_AUTO */ { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */ { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G */ { 0, { } }, /* IEEE80211_MODE_TURBO */ }; enum ieee80211_phymode mode; struct ieee80211_rateset *rs; int i, j; for (mode = 0; mode < IEEE80211_MODE_MAX; mode++) { rs = &ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rs->rs_rates[i] &= IEEE80211_RATE_VAL; for (j = 0; j < basic[mode].rs_nrates; j++) { if (basic[mode].rs_rates[j] != rs->rs_rates[i]) continue; rs->rs_rates[i] |= IEEE80211_RATE_BASIC; break; } } } } @ 1.48.12.1 log @Beginning of a sync with net80211 from FreeBSD. Lots to do. Sources taken from 2008-02-22. @ text @d4 1 a4 1 * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting d15 6 d35 3 a40 3 #ifdef __FreeBSD__ __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.45 2007/12/07 01:46:12 kmacy Exp $"); #endif d77 3 a87 3 "sturboA", /* IEEE80211_MODE_STURBO_A */ "11na", /* IEEE80211_MODE_11NA */ "11ng", /* IEEE80211_MODE_11NG */ a89 20 /* * Default supported rates for 802.11 operation (in IEEE .5Mb units). */ #define B(r) ((r) | IEEE80211_RATE_BASIC) static const struct ieee80211_rateset ieee80211_rateset_11a = { 8, { B(12), 18, B(24), 36, B(48), 72, 96, 108 } }; static const struct ieee80211_rateset ieee80211_rateset_half = { 8, { B(6), 9, B(12), 18, B(24), 36, 48, 54 } }; static const struct ieee80211_rateset ieee80211_rateset_quarter = { 8, { B(3), 4, B(6), 9, B(12), 18, 24, 27 } }; static const struct ieee80211_rateset ieee80211_rateset_11b = { 4, { B(2), B(4), B(11), B(22) } }; /* NB: OFDM rates are handled specially based on mode */ static const struct ieee80211_rateset ieee80211_rateset_11g = { 12, { B(2), B(4), B(11), B(22), 12, 18, 24, 36, 48, 72, 96, 108 } }; #undef B static int media_status(enum ieee80211_opmode , const struct ieee80211_channel *); d91 2 a92 1 struct ieee80211_list ieee80211_list = d94 1 a94 1 static uint8_t ieee80211_vapmap[32]; /* enough for 256 */ d102 1 a102 1 uint8_t b; a147 71 /* * Fill in 802.11 available channel set, mark * all available channels as active, and pick * a default channel if not already specified. */ static void ieee80211_chan_init(struct ieee80211com *ic) { #define DEFAULTRATES(m, def) do { \ if (isset(ic->ic_modecaps, m) && ic->ic_sup_rates[m].rs_nrates == 0) \ ic->ic_sup_rates[m] = def; \ } while (0) struct ieee80211_channel *c; int i; IASSERT(0 < ic->ic_nchans && ic->ic_nchans < IEEE80211_CHAN_MAX, ("invalid number of channels specified: %u", ic->ic_nchans)); memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO); for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; IASSERT(c->ic_flags != 0, ("channel with no flags")); IASSERT(c->ic_ieee < IEEE80211_CHAN_MAX, ("channel with bogus ieee number %u", c->ic_ieee)); setbit(ic->ic_chan_avail, c->ic_ieee); /* * Identify mode capabilities. */ if (IEEE80211_IS_CHAN_A(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11A); if (IEEE80211_IS_CHAN_B(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11B); if (IEEE80211_IS_CHAN_ANYG(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11G); if (IEEE80211_IS_CHAN_FHSS(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_FH); if (IEEE80211_IS_CHAN_108A(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_A); if (IEEE80211_IS_CHAN_108G(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_G); if (IEEE80211_IS_CHAN_ST(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_STURBO_A); if (IEEE80211_IS_CHAN_HTA(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11NA); if (IEEE80211_IS_CHAN_HTG(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11NG); } /* initialize candidate channels to all available */ memcpy(ic->ic_chan_active, ic->ic_chan_avail, sizeof(ic->ic_chan_avail)); ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ ic->ic_bsschan = IEEE80211_CHAN_ANYC; ic->ic_prevchan = NULL; /* arbitrarily pick the first channel */ ic->ic_curchan = &ic->ic_channels[0]; /* fillin well-known rate sets if driver has not specified */ DEFAULTRATES(IEEE80211_MODE_11B, ieee80211_rateset_11b); DEFAULTRATES(IEEE80211_MODE_11G, ieee80211_rateset_11g); DEFAULTRATES(IEEE80211_MODE_11A, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_TURBO_A, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_TURBO_G, ieee80211_rateset_11g); /* * Set auto mode to reset active channel state and any desired channel. */ (void) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); #undef DEFAULTRATES } d152 2 d156 1 a156 1 net80211_init(); a159 2 ifp->if_output = ieee80211_output; d165 1 a165 12 /* override the 802.3 setting */ ifp->if_hdrlen = ic->ic_headroom + sizeof(struct ieee80211_qosframe_addr4) + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_EXTIVLEN; /* XXX no way to recalculate on ifdetach */ if (ALIGN(ifp->if_hdrlen) > max_linkhdr) { /* XXX sanity check... */ max_linkhdr = ALIGN(ifp->if_hdrlen); max_hdr = max_linkhdr + max_protohdr; max_datalen = MHLEN - max_hdr; } d168 3 a170 3 * Fill in 802.11 available channel set, mark all * available channels as active, and pick a default * channel if not already specified. d172 41 a212 4 ieee80211_chan_init(ic); if (ic->ic_caps & IEEE80211_C_BGSCAN) /* enable if capable */ ic->ic_flags |= IEEE80211_F_BGSCAN; d214 4 a217 2 /* XXX not until WME+WPA issues resolved */ if (ic->ic_caps & IEEE80211_C_WME) /* enable if capable */ d220 1 a220 3 if (ic->ic_caps & IEEE80211_C_BURST) ic->ic_flags |= IEEE80211_F_BURST; ic->ic_flags |= IEEE80211_F_DOTH; /* XXX out of caps, just ena */ d222 3 a224 2 ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; ic->ic_bmissthreshold = IEEE80211_HWBMISS_DEFAULT; a225 1 IEEE80211_LOCK_INIT(ic, "ieee80211com"); d228 2 a229 1 ic->ic_lintval = ic->ic_bintval; d232 1 a232 1 ieee80211_crypto_attach(ic); a233 1 ieee80211_power_attach(ic); a234 2 ieee80211_ht_attach(ic); ieee80211_scan_attach(ic); a245 5 #if !defined(__NetBSD__) IASSERT(ifp->if_llsoftc == NULL, ("oops, hosed")); ifp->if_llsoftc = ic; #endif a255 3 ieee80211_scan_detach(ic); ieee80211_ht_detach(ic); /* NB: must be called before ieee80211_node_detach */ a257 1 ieee80211_power_detach(ic); d259 1 a261 1 IEEE80211_LOCK_DESTROY(ic); a269 20 static __inline int mapgsm(u_int freq, u_int flags) { freq *= 10; if (flags & IEEE80211_CHAN_QUARTER) freq += 5; else if (flags & IEEE80211_CHAN_HALF) freq += 10; else freq += 20; /* NB: there is no 907/20 wide but leave room */ return (freq - 906*10) / 5; } static __inline int mappsb(u_int freq, u_int flags) { return 37 + ((freq * 10) + ((freq % 5) == 2 ? 5 : 0) - 49400) / 5; } d273 1 a273 1 int a275 3 #define IS_FREQ_IN_PSB(_freq) ((_freq) > 4940 && (_freq) < 4990) if (flags & IEEE80211_CHAN_GSM) return mapgsm(freq, flags); d280 1 a280 1 return ((int) freq - 2407) / 5; d283 2 a284 8 } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */ if (freq <= 5000) { /* XXX check regdomain? */ if (IS_FREQ_IN_PSB(freq)) return mappsb(freq, flags); return (freq - 4000) / 5; } else return (freq - 5000) / 5; d288 4 a291 13 if (freq < 2484) { if (907 <= freq && freq <= 922) return mapgsm(freq, flags); return ((int) freq - 2407) / 5; } if (freq < 5000) { if (IS_FREQ_IN_PSB(freq)) return mappsb(freq, flags); else if (freq > 4900) return (freq - 4000) / 5; else return 15 + ((freq - 2512) / 20); } a293 1 #undef IS_FREQ_IN_PSB d299 2 a300 2 int ieee80211_chan2ieee(struct ieee80211com *ic, const struct ieee80211_channel *c) d302 9 a310 1 if (c == NULL) { a313 1 return (c == IEEE80211_CHAN_ANYC ? IEEE80211_CHAN_ANY : c->ic_ieee); a321 2 if (flags & IEEE80211_CHAN_GSM) return 907 + 5 * (chan / 10); d329 1 a329 5 } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */ if (flags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)) { chan -= 37; return 4940 + chan*5 + (chan % 5 ? 2 : 0); } a331 1 /* XXX can't distinguish PSB+GSM channels */ a342 91 * Locate a channel given a frequency+flags. We cache * the previous lookup to optimize swithing between two * channels--as happens with dynamic turbo. */ struct ieee80211_channel * ieee80211_find_channel(struct ieee80211com *ic, int freq, int flags) { struct ieee80211_channel *c; int i; flags &= IEEE80211_CHAN_ALLTURBO; c = ic->ic_prevchan; if (c != NULL && c->ic_freq == freq && (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags) return c; /* brute force search */ for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; if (c->ic_freq == freq && (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags) return c; } return NULL; } /* * Locate a channel given a channel number+flags. We cache * the previous lookup to optimize switching between two * channels--as happens with dynamic turbo. */ struct ieee80211_channel * ieee80211_find_channel_byieee(struct ieee80211com *ic, int ieee, int flags) { struct ieee80211_channel *c; int i; flags &= IEEE80211_CHAN_ALLTURBO; c = ic->ic_prevchan; if (c != NULL && c->ic_ieee == ieee && (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags) return c; /* brute force search */ for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; if (c->ic_ieee == ieee && (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags) return c; } return NULL; } static void addmedia(struct ieee80211com *ic, int mode, int mword) { #define TURBO(m) ((m) | IFM_IEEE80211_TURBO) #define ADD(_ic, _s, _o) \ ifmedia_add(&(_ic)->ic_media, \ IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL) static const u_int mopts[IEEE80211_MODE_MAX] = { IFM_AUTO, /* IEEE80211_MODE_AUTO */ IFM_IEEE80211_11A, /* IEEE80211_MODE_11A */ IFM_IEEE80211_11B, /* IEEE80211_MODE_11B */ IFM_IEEE80211_11G, /* IEEE80211_MODE_11G */ IFM_IEEE80211_FH, /* IEEE80211_MODE_FH */ TURBO(IFM_IEEE80211_11A), /* IEEE80211_MODE_TURBO_A */ TURBO(IFM_IEEE80211_11G), /* IEEE80211_MODE_TURBO_G */ TURBO(IFM_IEEE80211_11A), /* IEEE80211_MODE_STURBO_A */ IFM_IEEE80211_11NA, /* IEEE80211_MODE_11NA */ IFM_IEEE80211_11NG, /* IEEE80211_MODE_11NG */ }; u_int mopt; IASSERT(mode < IEEE80211_MODE_MAX, ("bad mode %u", mode)); mopt = mopts[mode]; IASSERT(mopt != 0 || mode == IEEE80211_MODE_AUTO, ("no media mapping for mode %u", mode)); ADD(ic, mword, mopt); /* e.g. 11a auto */ if (ic->ic_caps & IEEE80211_C_IBSS) ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP); if (ic->ic_caps & IEEE80211_C_AHDEMO) ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0); if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, mword, mopt | IFM_IEEE80211_MONITOR); #undef ADD #undef TURBO } /* d351 3 d355 3 a357 2 int i, j, mode, rate, maxrate, mword, r; const struct ieee80211_rateset *rs; d360 5 a364 18 /* XXXNH */ /* NB: this works because the structure is initialized to zero */ if (TAILQ_EMPTY(&ic->ic_media.ifm_list)) { /* * Do late attach work that must wait for any subclass * (i.e. driver) work such as overriding methods. */ ieee80211_node_lateattach(ic); } else { /* * We are re-initializing the channel list; clear * the existing media state as the media routines * don't suppress duplicates. */ ifmedia_delete_instance(&ic->ic_media, IFM_INST_ANY); ieee80211_chan_init(ic); } ieee80211_power_lateattach(ic); a374 3 /* * Add media for legacy operating modes. */ d376 11 a386 2 for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) { if (isclr(ic->ic_modecaps, mode)) d388 10 a397 1 addmedia(ic, mode, IFM_AUTO); d406 9 a414 1 addmedia(ic, mode, mword); d416 1 a416 1 * Add legacy rate to the collection of all rates. d437 10 a446 14 /* NB: remove media options from mword */ addmedia(ic, IEEE80211_MODE_AUTO, IFM_SUBTYPE(mword)); } /* * Add HT/11n media. Note that we do not have enough * bits in the media subtype to express the MCS so we * use a "placeholder" media subtype and any fixed MCS * must be specified with a different mechanism. */ for (; mode < IEEE80211_MODE_MAX; mode++) { if (isclr(ic->ic_modecaps, mode)) continue; addmedia(ic, mode, IFM_AUTO); addmedia(ic, mode, IFM_IEEE80211_MCS); d448 2 a449 12 if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) || isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) { addmedia(ic, IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS); /* XXX could walk htrates */ /* XXX known array size */ if (ieee80211_htrates[15] > maxrate) maxrate = ieee80211_htrates[15]; } /* NB: strip explicit mode; we're actually in autoselect */ ifmedia_set(&ic->ic_media, media_status(ic->ic_opmode, ic->ic_curchan) &~ IFM_MMASK); d453 1 a453 16 } const struct ieee80211_rateset * ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *c) { if (IEEE80211_IS_CHAN_HALF(c)) return &ieee80211_rateset_half; if (IEEE80211_IS_CHAN_QUARTER(c)) return &ieee80211_rateset_quarter; if (IEEE80211_IS_CHAN_HTA(c)) return &ic->ic_sup_rates[IEEE80211_MODE_11A]; if (IEEE80211_IS_CHAN_HTG(c)) { /* XXX does this work for basic rates? */ return &ic->ic_sup_rates[IEEE80211_MODE_11G]; } return &ic->ic_sup_rates[ieee80211_chan2mode(c)]; d461 1 a461 1 const struct ieee80211_rateset *rs; d463 2 a464 3 /* NB: skip AUTO since it has no rates */ for (mode = IEEE80211_MODE_AUTO+1; mode < IEEE80211_MODE_11NA; mode++) { if (isclr(ic->ic_modecaps, mode)) d470 2 a471 1 mword = ieee80211_rate2media(ic, rs->rs_rates[i], mode); a473 1 rate = ieee80211_media2rate(mword); d475 2 a476 1 rate / 2, ((rate & 0x1) != 0 ? ".5" : "")); a479 1 ieee80211_ht_announce(ic); d482 2 a483 2 void ieee80211_announce_channels(struct ieee80211com *ic) d485 8 a492 41 const struct ieee80211_channel *c; char type; int i, cw; printf("Chan Freq CW RegPwr MinPwr MaxPwr\n"); for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; if (IEEE80211_IS_CHAN_ST(c)) type = 'S'; else if (IEEE80211_IS_CHAN_108A(c)) type = 'T'; else if (IEEE80211_IS_CHAN_108G(c)) type = 'G'; else if (IEEE80211_IS_CHAN_HT(c)) type = 'n'; else if (IEEE80211_IS_CHAN_A(c)) type = 'a'; else if (IEEE80211_IS_CHAN_ANYG(c)) type = 'g'; else if (IEEE80211_IS_CHAN_B(c)) type = 'b'; else type = 'f'; if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_TURBO(c)) cw = 40; else if (IEEE80211_IS_CHAN_HALF(c)) cw = 10; else if (IEEE80211_IS_CHAN_QUARTER(c)) cw = 5; else cw = 20; printf("%4d %4d%c %2d%c %6d %4d.%d %4d.%d\n" , c->ic_ieee, c->ic_freq, type , cw , IEEE80211_IS_CHAN_HT40U(c) ? '+' : IEEE80211_IS_CHAN_HT40D(c) ? '-' : ' ' , c->ic_maxregpower , c->ic_minpower / 2, c->ic_minpower & 1 ? 5 : 0 , c->ic_maxpower / 2, c->ic_maxpower & 1 ? 5 : 0 ); } d499 1 a499 1 ieee80211_find_vap(const uint8_t mac[IEEE80211_ADDR_LEN]) a526 44 static int findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate) { #define IEEERATE(_ic,_m,_i) \ ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL) int i, nrates = ic->ic_sup_rates[mode].rs_nrates; for (i = 0; i < nrates; i++) if (IEEERATE(ic, mode, i) == rate) return i; return -1; #undef IEEERATE } /* * Convert a media specification to a rate index and possibly a mode * (if the rate is fixed and the mode is specified as ``auto'' then * we need to lock down the mode so the index is meanginful). */ static int checkrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate) { /* * Check the rate table for the specified/current phy. */ if (mode == IEEE80211_MODE_AUTO) { int i; /* * In autoselect mode search for the rate. */ for (i = IEEE80211_MODE_11A; i < IEEE80211_MODE_MAX; i++) { if (isset(ic->ic_modecaps, i) && findrate(ic, i, rate) != -1) return 1; } return 0; } else { /* * Mode is fixed, check for rate. */ return (findrate(ic, mode, rate) != -1); } } d537 1 a537 1 int newrate, error = 0; a560 6 case IFM_IEEE80211_11NA: newphymode = IEEE80211_MODE_11NA; break; case IFM_IEEE80211_11NG: newphymode = IEEE80211_MODE_11NG; break; d572 3 a574 6 if (newphymode == IEEE80211_MODE_11A) { if (ic->ic_flags & IEEE80211_F_TURBOP) newphymode = IEEE80211_MODE_TURBO_A; else newphymode = IEEE80211_MODE_STURBO_A; } else if (newphymode == IEEE80211_MODE_11G) d579 6 a584 1 /* XXX HT40 +/- */ d588 1 a588 1 newrate = ic->ic_fixed_rate; d594 24 a617 1 if (newrate == 0 || !checkrate(ic, newphymode, newrate)) d619 2 a620 2 } else newrate = IEEE80211_FIXED_RATE_NONE; d637 17 d657 4 a660 2 if (ic->ic_des_mode != newphymode) { /* change phy mode */ ic->ic_des_mode = newphymode; d667 2 a668 2 if (ic->ic_fixed_rate != newrate) { ic->ic_fixed_rate = newrate; /* set fixed tx rate */ a681 1 case IEEE80211_M_WDS: a703 50 /* * Common code to calculate the media status word * from the operating mode and channel state. */ static int media_status(enum ieee80211_opmode opmode, const struct ieee80211_channel *chan) { int status; status = IFM_IEEE80211; switch (opmode) { case IEEE80211_M_STA: break; case IEEE80211_M_IBSS: status |= IFM_IEEE80211_ADHOC; break; case IEEE80211_M_HOSTAP: status |= IFM_IEEE80211_HOSTAP; break; case IEEE80211_M_MONITOR: status |= IFM_IEEE80211_MONITOR; break; case IEEE80211_M_AHDEMO: status |= IFM_IEEE80211_ADHOC | IFM_FLAG0; break; case IEEE80211_M_WDS: /* should not come here */ break; } if (IEEE80211_IS_CHAN_HTA(chan)) { status |= IFM_IEEE80211_11NA; } else if (IEEE80211_IS_CHAN_HTG(chan)) { status |= IFM_IEEE80211_11NG; } else if (IEEE80211_IS_CHAN_A(chan)) { status |= IFM_IEEE80211_11A; } else if (IEEE80211_IS_CHAN_B(chan)) { status |= IFM_IEEE80211_11B; } else if (IEEE80211_IS_CHAN_ANYG(chan)) { status |= IFM_IEEE80211_11G; } else if (IEEE80211_IS_CHAN_FHSS(chan)) { status |= IFM_IEEE80211_FH; } /* XXX else complain? */ if (IEEE80211_IS_CHAN_TURBO(chan)) status |= IFM_IEEE80211_TURBO; return status; } d708 1 a708 2 enum ieee80211_phymode mode; const struct ieee80211_rateset *rs; d716 2 a717 6 /* * NB: use the current channel's mode to lock down a xmit * rate only when running; otherwise we may have a mismatch * in which case the rate will not be convertible. */ if (ic->ic_state == IEEE80211_S_RUN) { a718 4 mode = ieee80211_chan2mode(ic->ic_curchan); } else mode = IEEE80211_MODE_AUTO; imr->ifm_active = media_status(ic->ic_opmode, ic->ic_curchan); d726 1 d728 1 a728 1 ic->ic_fixed_rate, mode); a731 1 * XXX HT rate d735 1 a735 1 rs->rs_rates[ic->ic_bss->ni_txrate], mode); d738 64 d813 22 d836 2 a837 4 * Adjust basic rates in 11b/11g supported rate set. * Note that if operating on a hal/quarter rate channel * this is a noop as those rates sets are different * and used instead. d839 88 a926 2 if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11B) ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], mode); d933 1 d937 4 a940 1 * Return the phy mode for with the specified channel. d943 1 a943 1 ieee80211_chan2mode(const struct ieee80211_channel *chan) d945 1 a945 9 if (IEEE80211_IS_CHAN_HTA(chan)) return IEEE80211_MODE_11NA; else if (IEEE80211_IS_CHAN_HTG(chan)) return IEEE80211_MODE_11NG; else if (IEEE80211_IS_CHAN_108G(chan)) return IEEE80211_MODE_TURBO_G; else if (IEEE80211_IS_CHAN_ST(chan)) return IEEE80211_MODE_STURBO_A; else if (IEEE80211_IS_CHAN_TURBO(chan)) d947 1 a947 1 else if (IEEE80211_IS_CHAN_A(chan)) d949 11 a959 1 else if (IEEE80211_IS_CHAN_ANYG(chan)) d961 1 a961 1 else if (IEEE80211_IS_CHAN_B(chan)) a962 23 else if (IEEE80211_IS_CHAN_FHSS(chan)) return IEEE80211_MODE_FH; /* NB: should not get here */ printf("%s: cannot map channel to mode; freq %u flags 0x%x\n", __func__, chan->ic_freq, chan->ic_flags); return IEEE80211_MODE_11B; } struct ratemedia { u_int match; /* rate + mode */ u_int media; /* if_media rate */ }; static int findmedia(const struct ratemedia rates[], int n, u_int match) { int i; for (i = 0; i < n; i++) if (rates[i].match == match) return rates[i].media; return IFM_AUTO; d966 2 a967 3 * Convert IEEE80211 rate value to ifmedia subtype. * Rate is either a legacy rate in units of 0.5Mbps * or an MCS index. d973 4 a976 1 static const struct ratemedia rates[] = { a1003 3 { 6 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM3 }, { 9 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM4 }, { 54 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM27 }, d1006 1 a1006 19 static const struct ratemedia htrates[] = { { 0, IFM_IEEE80211_MCS }, { 1, IFM_IEEE80211_MCS }, { 2, IFM_IEEE80211_MCS }, { 3, IFM_IEEE80211_MCS }, { 4, IFM_IEEE80211_MCS }, { 5, IFM_IEEE80211_MCS }, { 6, IFM_IEEE80211_MCS }, { 7, IFM_IEEE80211_MCS }, { 8, IFM_IEEE80211_MCS }, { 9, IFM_IEEE80211_MCS }, { 10, IFM_IEEE80211_MCS }, { 11, IFM_IEEE80211_MCS }, { 12, IFM_IEEE80211_MCS }, { 13, IFM_IEEE80211_MCS }, { 14, IFM_IEEE80211_MCS }, { 15, IFM_IEEE80211_MCS }, }; int m; d1008 1 a1008 20 /* * Check 11n rates first for match as an MCS. */ if (mode == IEEE80211_MODE_11NA) { if (rate & IEEE80211_RATE_MCS) { rate &= ~IEEE80211_RATE_MCS; m = findmedia(htrates, N(htrates), rate); if (m != IFM_AUTO) return m | IFM_IEEE80211_11NA; } } else if (mode == IEEE80211_MODE_11NG) { /* NB: 12 is ambiguous, it will be treated as an MCS */ if (rate & IEEE80211_RATE_MCS) { rate &= ~IEEE80211_RATE_MCS; m = findmedia(htrates, N(htrates), rate); if (m != IFM_AUTO) return m | IFM_IEEE80211_11NG; } } rate &= IEEE80211_RATE_VAL; a1010 1 case IEEE80211_MODE_11NA: d1012 2 a1013 2 case IEEE80211_MODE_STURBO_A: return findmedia(rates, N(rates), rate | IFM_IEEE80211_11A); d1015 2 a1016 1 return findmedia(rates, N(rates), rate | IFM_IEEE80211_11B); d1018 2 a1019 1 return findmedia(rates, N(rates), rate | IFM_IEEE80211_FH); d1022 4 a1025 3 if (ic && ic->ic_phytype == IEEE80211_T_FH) return findmedia(rates, N(rates), rate | IFM_IEEE80211_FH); a1028 1 case IEEE80211_MODE_11NG: d1030 2 a1031 1 return findmedia(rates, N(rates), rate | IFM_IEEE80211_11G); d1033 3 a1063 6 0, /* IFM_IEEE80211_DS354k */ 0, /* IFM_IEEE80211_DS512k */ 6, /* IFM_IEEE80211_OFDM3 */ 9, /* IFM_IEEE80211_OFDM4 */ 54, /* IFM_IEEE80211_OFDM27 */ -1, /* IFM_IEEE80211_MCS */ @ 1.47 log @__unused removal on arguments; approved by core. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.46 2006/10/12 01:32:30 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.46 2006/10/12 01:32:30 christos Exp $"); d466 2 a467 1 if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]); d474 1 a474 1 printf("%s%d%sMbps", (i != 0 ? " " : ""), d478 1 a478 1 printf("\n"); @ 1.47.24.1 log @sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.47 2006/11/16 01:33:40 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.47 2006/11/16 01:33:40 christos Exp $"); d466 1 a466 2 aprint_normal("%s: %s rates: ", ifp->if_xname, ieee80211_phymode_name[mode]); d473 1 a473 1 aprint_normal("%s%d%sMbps", (i != 0 ? " " : ""), d477 1 a477 1 aprint_normal("\n"); @ 1.47.30.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.48 2007/12/01 14:35:51 jmcneill Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.48 2007/12/01 14:35:51 jmcneill Exp $"); d466 1 a466 2 aprint_normal("%s: %s rates: ", ifp->if_xname, ieee80211_phymode_name[mode]); d473 1 a473 1 aprint_normal("%s%d%sMbps", (i != 0 ? " " : ""), d477 1 a477 1 aprint_normal("\n"); @ 1.47.22.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.47 2006/11/16 01:33:40 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.47 2006/11/16 01:33:40 christos Exp $"); d466 1 a466 2 aprint_normal("%s: %s rates: ", ifp->if_xname, ieee80211_phymode_name[mode]); d473 1 a473 1 aprint_normal("%s%d%sMbps", (i != 0 ? " " : ""), d477 1 a477 1 aprint_normal("\n"); @ 1.46 log @- sprinkle __unused on function decls. - fix a couple of unused bugs - no more -Wno-unused for i386 @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.45 2006/03/08 23:46:27 lukem Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.45 2006/03/08 23:46:27 lukem Exp $"); d143 1 a143 1 ieee80211_default_reset(struct ifnet *ifp __unused) @ 1.45 log @Use the SI capitalization for "Hz", "kHz", and "MHz" in comments and strings. Add a space between numbers and Hz unit. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.44 2006/03/02 03:38:48 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.44 2006/03/02 03:38:48 dyoung Exp $"); d143 1 a143 1 ieee80211_default_reset(struct ifnet *ifp) @ 1.45.10.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.47 2006/11/16 01:33:40 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.47 2006/11/16 01:33:40 christos Exp $"); @ 1.45.12.1 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.45 2006/03/08 23:46:27 lukem Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.45 2006/03/08 23:46:27 lukem Exp $"); d143 1 a143 1 ieee80211_default_reset(struct ifnet *ifp __unused) @ 1.45.12.2 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.45.12.1 2006/10/22 06:07:27 yamt Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.45.12.1 2006/10/22 06:07:27 yamt Exp $"); d143 1 a143 1 ieee80211_default_reset(struct ifnet *ifp) @ 1.44 log @Miscellaneous ath(4) and net80211 updates and bug-fixes coming from sam@@ and various open source repositories: ath(4): Ignore "phantom" beacon misses: should stabilize connections to access points (no more ceaseless link-UP/DOWN indications). Also, re-synchronize beacon timer using the TSF in the first beacon received after joining a BSS---this should also help suppress spurious beacon misses. I am hopeful that this will help ath(4) lossage reported by perry@@ and smb@@. Add new configuration through sysctl. Use a shorter calibration interval until IQ calibration finishes. Report antenna noise through radiotap. Rudiments of Radar Detection / Dynamic Frequency Selection. Update to HAL version 0.9.16.13. Update open sources for changes to the HAL API. Add HALs for additional architectures: add big-endian ELF HALs for sparc64 and for PowerPC. Also add a Alpha HAL. These new HALs are untested under NetBSD. ath(4) + net80211: Make the multicast transmit rate configurable by ioctl. Miscellaneous bug fixes. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.43 2005/12/13 09:28:31 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.43 2005/12/13 09:28:31 dyoung Exp $"); d283 1 a283 1 } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */ d329 1 a329 1 } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */ @ 1.44.4.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.45 2006/03/08 23:46:27 lukem Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.45 2006/03/08 23:46:27 lukem Exp $"); d283 1 a283 1 } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5 GHz band */ d329 1 a329 1 } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5 GHz band */ @ 1.44.2.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.44 2006/03/02 03:38:48 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.44 2006/03/02 03:38:48 dyoung Exp $"); d283 1 a283 1 } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5 GHz band */ d329 1 a329 1 } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5 GHz band */ @ 1.43 log @Fix ieee80211_media2rate to suit the funny order of NetBSD's DSSS media flags: DS2, DS5, DS11, DS1. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.42 2005/11/25 17:33:56 thorpej Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.42 2005/11/25 17:33:56 thorpej Exp $"); d842 2 d846 1 a846 1 if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0) d865 2 d869 1 a869 1 if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0) d944 3 a946 7 if (IEEE80211_IS_CHAN_5GHZ(chan)) { /* * This assumes all 11a turbo channels are also * usable withut turbo, which is currently true. */ if (ic->ic_curmode == IEEE80211_MODE_TURBO_A) return IEEE80211_MODE_TURBO_A; @ 1.43.4.1 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.45 2006/03/08 23:46:27 lukem Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.45 2006/03/08 23:46:27 lukem Exp $"); d283 1 a283 1 } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5 GHz band */ d329 1 a329 1 } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5 GHz band */ a841 2 if (c->ic_flags == 0) continue; d844 1 a844 1 if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0) a862 2 if (c->ic_flags == 0) continue; d865 1 a865 1 if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0) d940 7 a946 3 if (IEEE80211_IS_CHAN_T(chan)) { return IEEE80211_MODE_TURBO_A; } else if (IEEE80211_IS_CHAN_5GHZ(chan)) { @ 1.43.6.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.45 2006/03/08 23:46:27 lukem Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.45 2006/03/08 23:46:27 lukem Exp $"); d283 1 a283 1 } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5 GHz band */ d329 1 a329 1 } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5 GHz band */ a841 2 if (c->ic_flags == 0) continue; d844 1 a844 1 if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0) a862 2 if (c->ic_flags == 0) continue; d865 1 a865 1 if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0) d940 7 a946 3 if (IEEE80211_IS_CHAN_T(chan)) { return IEEE80211_MODE_TURBO_A; } else if (IEEE80211_IS_CHAN_5GHZ(chan)) { @ 1.42 log @Use a once control to call initialize the 802.11 layer when ieee80211_ifattach() is called. "wlan" no longer needs-flag, and remove the ieee80211_init() call from main(). @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.41 2005/11/18 16:40:08 skrll Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.41 2005/11/18 16:40:08 skrll Exp $"); a1048 1 2, /* IFM_IEEE80211_DS1 */ d1052 1 @ 1.41 log @Resolve conflicts and adapt to NetBSD. Thanks to dyoung@@, scw@@, and perry@@ for help testing. 2005-08-30 15:27 avatar Properly set ic_curchan before calling back to device driver to do channel switching(ifconfig devX channel Y). This fix should make channel changing works again in monitor mode. Submitted by: sam X-MFC-With: other ic_curchan changes 2005-08-13 18:50 sam revert 1.64: we cannot use the channel characteristics to decide when to do 11g erp sta accounting because b/g channels show up as false positives when operating in 11b. Noticed by: Michal Mertl 2005-08-13 18:31 sam Extend acl support to pass ioctl requests through and use this to add support for getting the current policy setting and collecting the list of mac addresses in the acl table. Submitted by: Michal Mertl (original version) MFC after: 2 weeks 2005-08-10 18:42 sam Don't use ic_curmode to decide when to do 11g station accounting, use the station channel properties. Fixes assert failure/bogus operation when an ap is operating in 11a and has associated stations then switches to 11g. Noticed by: Michal Mertl Reviewed by: avatar MFC after: 2 weeks 2005-08-10 17:22 sam Clarify/fix handling of the current channel: o add ic_curchan and use it uniformly for specifying the current channel instead of overloading ic->ic_bss->ni_chan (or in some drivers ic_ibss_chan) o add ieee80211_scanparams structure to encapsulate scanning-related state captured for rx frames o move rx beacon+probe response frame handling into separate routines o change beacon+probe response handling to treat the scan table more like a scan cache--look for an existing entry before adding a new one; this combined with ic_curchan use corrects handling of stations that were previously found at a different channel o move adhoc neighbor discovery by beacon+probe response frames to a new ieee80211_add_neighbor routine Reviewed by: avatar Tested by: avatar, Michal Mertl MFC after: 2 weeks 2005-08-09 11:19 rwatson Propagate rename of IFF_OACTIVE and IFF_RUNNING to IFF_DRV_OACTIVE and IFF_DRV_RUNNING, as well as the move from ifnet.if_flags to ifnet.if_drv_flags. Device drivers are now responsible for synchronizing access to these flags, as they are in if_drv_flags. This helps prevent races between the network stack and device driver in maintaining the interface flags field. Many __FreeBSD__ and __FreeBSD_version checks maintained and continued; some less so. Reviewed by: pjd, bz MFC after: 7 days 2005-08-08 19:46 sam Split crypto tx+rx key indices and add a key index -> node mapping table: Crypto changes: o change driver/net80211 key_alloc api to return tx+rx key indices; a driver can leave the rx key index set to IEEE80211_KEYIX_NONE or set it to be the same as the tx key index (the former disables use of the key index in building the keyix->node mapping table and is the default setup for naive drivers by null_key_alloc) o add cs_max_keyid to crypto state to specify the max h/w key index a driver will return; this is used to allocate the key index mapping table and to bounds check table loookups o while here introduce ieee80211_keyix (finally) for the type of a h/w key index o change crypto notifiers for rx failures to pass the rx key index up as appropriate (michael failure, replay, etc.) Node table changes: o optionally allocate a h/w key index to node mapping table for the station table using the max key index setting supplied by drivers (note the scan table does not get a map) o defer node table allocation to lateattach so the driver has a chance to set the max key id to size the key index map o while here also defer the aid bitmap allocation o add new ieee80211_find_rxnode_withkey api to find a sta/node entry on frame receive with an optional h/w key index to use in checking mapping table; also updates the map if it does a hash lookup and the found node has a rx key index set in the unicast key; note this work is separated from the old ieee80211_find_rxnode call so drivers do not need to be aware of the new mechanism o move some node table manipulation under the node table lock to close a race on node delete o add ieee80211_node_delucastkey to do the dirty work of deleting unicast key state for a node (deletes any key and handles key map references) Ath driver: o nuke private sc_keyixmap mechansim in favor of net80211 support o update key alloc api These changes close several race conditions for the ath driver operating in ap mode. Other drivers should see no change. Station mode operation for ath no longer uses the key index map but performance tests show no noticeable change and this will be fixed when the scan table is eliminated with the new scanning support. Tested by: Michal Mertl, avatar, others Reviewed by: avatar, others MFC after: 2 weeks 2005-08-08 06:49 sam use ieee80211_iterate_nodes to retrieve station data; the previous code walked the list w/o locking MFC after: 1 week 2005-08-08 04:30 sam Cleanup beacon/listen interval handling: o separate configured beacon interval from listen interval; this avoids potential use of one value for the other (e.g. setting powersavesleep to 0 clobbers the beacon interval used in hostap or ibss mode) o bounds check the beacon interval received in probe response and beacon frames and drop frames with bogus settings; not clear if we should instead clamp the value as any alteration would result in mismatched sta+ap configuration and probably be more confusing (don't want to log to the console but perhaps ok with rate limiting) o while here up max beacon interval to reflect WiFi standard Noticed by: Martin MFC after: 1 week 2005-08-06 05:57 sam fix debug msg typo MFC after: 3 days 2005-08-06 05:56 sam Fix handling of frames sent prior to a station being authorized when operating in ap mode. Previously we allocated a node from the station table, sent the frame (using the node), then released the reference that "held the frame in the table". But while the frame was in flight the node might be reclaimed which could lead to problems. The solution is to add an ieee80211_tmp_node routine that crafts a node that does exist in a table and so isn't ever reclaimed; it exists only so long as the associated frame is in flight. MFC after: 5 days 2005-07-31 07:12 sam close a race between reclaiming a node when a station is inactive and sending the null data frame used to probe inactive stations MFC after: 5 days 2005-07-27 05:41 sam when bridging internally bypass the bss node as traffic to it must follow the normal input path Submitted by: Michal Mertl MFC after: 5 days 2005-07-27 03:53 sam bandaid ni_fails handling so ap's with association failures are reconsidered after a bit; a proper fix involves more changes to the scanning infrastructure Reviewed by: avatar, David Young MFC after: 5 days 2005-07-23 01:16 sam the AREF flag is only meaningful in ap mode; adhoc neighbors now are timed out of the sta/neighbor table 2005-07-23 00:25 sam o move inactivity-related debug msgs under IEEE80211_MSG_INACT o probe inactive neighbors in adhoc mode (they don't have an association id so previously were being timed out) MFC after: 3 days 2005-07-22 22:11 sam split xmit of probe request frame out into a separate routine that takes explicit parameters; this will be needed when scanning is decoupled from the state machine to do bg scanning MFC after: 3 days 2005-07-22 21:48 sam split 802.11 frame xmit setup code into ieee80211_send_setup MFC after: 3 days 2005-07-22 18:57 sam simplify ic_newassoc callback MFC after: 3 days 2005-07-22 18:54 sam simplify ieee80211_ibss_merge api MFC after: 3 days 2005-07-22 18:50 sam add stats we know we'll need soon and some spare fields for future expansion MFC after: 3 days 2005-07-22 18:45 sam simplify tim callback api MFC after: 3 days 2005-07-22 18:42 sam don't include 802.3 header in min frame length calculation as it may not be present for a frag; fixes problem with small (fragmented) frames being dropped Obtained from: Atheros MFC after: 3 days 2005-07-22 18:36 sam simplify ieee80211_node_authorize and ieee80211_node_unauthorize api's MFC after: 3 days 2005-07-22 18:31 sam simplifiy ieee80211_send_nulldata api MFC after: 3 days 2005-07-22 18:29 sam simplify rate set api's by removing ic parameter (implicit in node reference) MFC after: 3 days 2005-07-22 18:21 sam reject association requests with a wpa/rsn ie when wpa/rsn is not configured on the ap; previously we either ignored the ie or (possibly) failed an assertion Obtained from: Atheros MFC after: 3 days 2005-07-22 18:16 sam missed one in last commit; add device name to discard msgs 2005-07-22 18:13 sam include device name in discard msgs 2005-07-22 18:12 sam add diag msgs for frames discarded because the direction field is wrong 2005-07-22 18:08 sam split data frame delivery out to a new function ieee80211_deliver_data 2005-07-22 18:00 sam o add IEEE80211_IOC_FRAGTHRESHOLD for getting+setting the tx fragmentation threshold o fix bounds checking on IEEE80211_IOC_RTSTHRESHOLD MFC after: 3 days 2005-07-22 17:55 sam o add IEEE80211_FRAG_DEFAULT o move default settings for RTS and frag thresholds to ieee80211_var.h 2005-07-22 17:50 sam diff reduction against p4: define IEEE80211_FIXED_RATE_NONE and use it instead of -1 2005-07-22 17:37 sam add flags missed in last merge 2005-07-22 17:36 sam Diff reduction against p4: o add ic_flags_ext for eventual extention of ic_flags o define/reserve flag+capabilities bits for superg, bg scan, and roaming support o refactor debug msg macros MFC after: 3 days 2005-07-22 06:17 sam send a response when an auth request is denied due to an acl; might be better to silently ignore the frame but this way we give stations a chance of figuring out what's wrong 2005-07-22 06:15 sam remove excess whitespace 2005-07-22 05:55 sam use IF_HANDOFF when bridging frames internally so if_start gets called; fixes communication between associated sta's MFC after: 3 days 2005-07-11 04:06 sam Handle encrypt of arbitarily fragmented mbuf chains: previously we bailed if we couldn't collect the 16-bytes of data required for an aes block cipher in 2 mbufs; now we deal with it. While here make space accounting signed so a sanity check does the right thing for malformed mbuf chains. Approved by: re (scottl) 2005-07-11 04:00 sam nuke assert that duplicates real check Reviewed by: avatar Approved by: re (scottl) @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.40 2005/07/26 22:52:48 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.40 2005/07/26 22:52:48 dyoung Exp $"); d155 4 @ 1.40 log @Resolve conflicts. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.38 2005/06/26 04:31:51 dyoung Exp $ */ d36 1 a36 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.19 2005/01/27 17:39:17 sam Exp $"); d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.38 2005/06/26 04:31:51 dyoung Exp $"); d199 4 d218 3 a220 3 if (ic->ic_lintval == 0) ic->ic_lintval = IEEE80211_BINTVAL_DEFAULT; ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */ d224 2 d717 1 a717 1 if (ic->ic_fixed_rate != -1) { @ 1.40.6.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.40 2005/07/26 22:52:48 dyoung Exp $ */ d36 1 a36 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.22 2005/08/10 16:22:29 sam Exp $"); d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.40 2005/07/26 22:52:48 dyoung Exp $"); a198 4 if (ic->ic_curchan == NULL) { /* arbitrarily pick the first channel */ ic->ic_curchan = &ic->ic_channels[i]; } d214 3 a216 3 if (ic->ic_bintval == 0) ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; ic->ic_bmisstimeout = 7*ic->ic_bintval; /* default 7 beacons */ a219 2 if (ic->ic_lintval == 0) ic->ic_lintval = ic->ic_bintval; d711 1 a711 1 if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { @ 1.40.6.2 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.40.6.1 2005/11/22 16:08:15 yamt Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.40.6.1 2005/11/22 16:08:15 yamt Exp $"); a154 4 #ifdef __NetBSD__ ieee80211_init(); #endif /* __NetBSD__ */ @ 1.39 log @Synchronize ieee80211_find_vap, ieee80211_find_instance. @ text @@ 1.38 log @Do not build AP support if 'options IEEE80211_NO_HOSTAP'. I will use this in the INSTALL kernel to save some space. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.37 2005/06/22 06:16:02 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.37 2005/06/22 06:16:02 dyoung Exp $"); d490 1 d493 1 a493 1 /* XXX lock */ d496 3 a498 2 return ic; return NULL; d504 1 d507 1 a507 1 /* XXX lock */ d511 3 a513 2 return ic; return NULL; @ 1.38.2.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.38 2005/06/26 04:31:51 dyoung Exp $ */ d36 1 a36 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.22 2005/08/10 16:22:29 sam Exp $"); d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.38 2005/06/26 04:31:51 dyoung Exp $"); a154 4 #ifdef __NetBSD__ ieee80211_init(); #endif /* __NetBSD__ */ a198 4 if (ic->ic_curchan == NULL) { /* arbitrarily pick the first channel */ ic->ic_curchan = &ic->ic_channels[i]; } d214 3 a216 3 if (ic->ic_bintval == 0) ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; ic->ic_bmisstimeout = 7*ic->ic_bintval; /* default 7 beacons */ a219 2 if (ic->ic_lintval == 0) ic->ic_lintval = ic->ic_bintval; d273 1 a273 1 } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5 GHz band */ d319 1 a319 1 } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5 GHz band */ a489 1 int s; d492 1 a492 1 s = splnet(); d495 2 a496 3 break; splx(s); return ic; a501 1 int s; d504 1 a504 1 s = splnet(); d508 2 a509 3 break; splx(s); return ic; d707 1 a707 1 if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { a827 2 if (c->ic_flags == 0) continue; d830 1 a830 1 if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0) a848 2 if (c->ic_flags == 0) continue; d851 1 a851 1 if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0) d926 7 a932 3 if (IEEE80211_IS_CHAN_T(chan)) { return IEEE80211_MODE_TURBO_A; } else if (IEEE80211_IS_CHAN_5GHZ(chan)) { d1035 1 a1038 1 2, /* IFM_IEEE80211_DS1 */ @ 1.38.2.2 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.38.2.1 2006/06/21 15:10:45 yamt Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.38.2.1 2006/06/21 15:10:45 yamt Exp $"); d466 1 a466 2 aprint_normal("%s: %s rates: ", ifp->if_xname, ieee80211_phymode_name[mode]); d473 1 a473 1 aprint_normal("%s%d%sMbps", (i != 0 ? " " : ""), d477 1 a477 1 aprint_normal("\n"); @ 1.37 log @Resolve conflicts in importation of 18-May-2005 ath(4) / net80211(9) from FreeBSD. Introduce compatibility shims (sys/dev/ic/ath_netbsd.[ch], sys/net80211/ieee80211_netbsd.[ch]). Update drivers (an, atu, atw, awi, ipw, iwi, rtw, wi) for the new net80211(9) API. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.31 2004/07/30 17:05:18 mycroft Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.31 2004/07/30 17:05:18 mycroft Exp $"); d356 4 d622 1 d637 1 @ 1.36 log @Change the rest of the sysctl subsystem to use const consistently. The __UNCONST macro is now used only where necessary and the RW macros are gone. Most of the changes here are consumers of the sysctl_createv(9) interface that now takes a pair of const pointers which used not to be. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.35 2005/06/09 02:19:59 atatat Exp $ */ d4 1 a4 1 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting d36 4 a39 3 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.11 2004/04/02 20:19:20 sam Exp $"); #else __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.35 2005/06/09 02:19:59 atatat Exp $"); d50 1 a50 3 #include #include #include d52 1 a56 3 #ifdef __FreeBSD__ #include #endif a59 4 #ifdef __FreeBSD__ #include #endif a60 1 #include a62 3 #ifdef __FreeBSD__ #include #else a63 1 #endif d66 1 a67 1 #include d73 1 a73 4 #include #ifdef __FreeBSD__ #include #else a75 16 #endif #ifdef IEEE80211_DEBUG int ieee80211_debug = 0; #ifdef __NetBSD__ static int ieee80211_debug_nodenum; #endif /* __NetBSD__ */ #ifdef __FreeBSD__ SYSCTL_INT(_debug, OID_AUTO, ieee80211, CTLFLAG_RW, &ieee80211_debug, 0, "IEEE 802.11 media debugging printfs"); #endif #endif int ieee80211_cache_size = IEEE80211_CACHE_SIZE; static int ieee80211_cache_size_nodenum; d80 1 a80 16 static void ieee80211_setbasicrates(struct ieee80211com *); #ifdef __NetBSD__ static void sysctl_ieee80211_fill_node(struct ieee80211_node *, struct ieee80211_node_sysctl *, int, struct ieee80211_channel *, int); static struct ieee80211_node *ieee80211_node_walknext( struct ieee80211_node_walk *); static struct ieee80211_node *ieee80211_node_walkfirst( struct ieee80211_node_walk *, u_short); static int sysctl_ieee80211_verify(SYSCTLFN_ARGS); static int sysctl_ieee80211_node(SYSCTLFN_ARGS); #endif /* __NetBSD__ */ #define LOGICALLY_EQUAL(x, y) (!(x) == !(y)) static const char *ieee80211_phymode_name[] = { d86 2 a87 1 "turbo", /* IEEE80211_MODE_TURBO */ d90 58 d149 1 a149 1 ieee80211_ifattach(struct ifnet *ifp) d151 1 a151 1 struct ieee80211com *ic = (void *)ifp; d160 2 a161 1 ieee80211_crypto_attach(ifp); d196 3 a198 1 ic->ic_modecaps |= 1<ic_lintval = 100; /* default sleep */ d217 4 d224 12 a235 1 ieee80211_proto_attach(ifp); d239 1 a239 1 ieee80211_ifdetach(struct ifnet *ifp) d241 3 a243 1 struct ieee80211com *ic = (void *)ifp; d245 3 a247 2 ieee80211_proto_detach(ifp); ieee80211_crypto_detach(ifp); d250 4 a253 5 #ifdef __FreeBSD__ ifmedia_removeall(&ic->ic_media); #else ifmedia_delete_instance(&ic->ic_media, IFM_INST_ANY); #endif d297 1 a297 1 if_printf(&ic->ic_if, "invalid channel freq %u flags %x\n", d301 1 a301 1 if_printf(&ic->ic_if, "invalid channel (NULL)\n"); d338 1 a338 1 ieee80211_media_init(struct ifnet *ifp, d344 1 a344 1 struct ieee80211com *ic = (void *)ifp; d363 1 a363 1 static const u_int mopts[] = { d370 1 a385 1 if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]); a391 3 printf("%s%d%sMbps", (i != 0 ? " " : ""), (rate & IEEE80211_RATE_VAL) / 2, ((rate & 0x1) != 0 ? ".5" : "")); a416 1 printf("\n"); d436 1 a436 1 #ifndef __linux__ a438 1 #endif d442 25 d481 28 d514 1 a514 1 struct ieee80211com *ic = (void *)ifp; d520 5 d549 2 a550 2 * Turbo mode is an ``option''. Eventually it * needs to be applied to 11g too. d553 5 a557 1 if (newphymode != IEEE80211_MODE_11A) a558 1 newphymode = IEEE80211_MODE_TURBO; d667 7 d686 2 a687 2 struct ieee80211com *ic = (void *)ifp; struct ieee80211_node *ni = NULL; d689 5 d698 19 a716 1 imr->ifm_active |= IFM_AUTO; a718 4 ni = ic->ic_bss; /* calculate rate subtype */ imr->ifm_active |= ieee80211_rate2media(ic, ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode); d746 1 a746 1 case IEEE80211_MODE_TURBO: d750 4 d758 1 a758 1 ieee80211_watchdog(struct ifnet *ifp) d760 2 a761 1 struct ieee80211com *ic = (void *)ifp; d763 14 a776 38 if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); if (ic->ic_mgt_timer != 0) ifp->if_timer = 1; } /* * Mark the basic rates for the 11g rate table based on the * operating mode. For real 11g we mark all the 11b rates * and 6, 12, and 24 OFDM. For 11b compatibility we mark only * 11b rates. There's also a pseudo 11a-mode used to mark only * the basic OFDM rates. */ static void ieee80211_setbasicrates(struct ieee80211com *ic) { static const struct ieee80211_rateset basic[] = { { 0 }, /* IEEE80211_MODE_AUTO */ { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */ { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G */ { 2, { 2, 4 } }, /* IEEE80211_MODE_FH */ { 0 }, /* IEEE80211_MODE_TURBO */ }; enum ieee80211_phymode mode; struct ieee80211_rateset *rs; int i, j; for (mode = 0; mode < IEEE80211_MODE_MAX; mode++) { rs = &ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rs->rs_rates[i] &= IEEE80211_RATE_VAL; for (j = 0; j < basic[mode].rs_nrates; j++) if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { rs->rs_rates[i] |= IEEE80211_RATE_BASIC; break; } d779 2 d799 2 a800 1 IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO */ d809 2 a810 2 ("%s: mode %u not supported (caps 0x%x)\n", __func__, mode, ic->ic_modecaps)); d833 1 a833 1 ("%s: no channels found for mode %u\n", __func__, mode)); d871 6 d879 1 a879 8 * Set/reset state flags that influence beacon contents, etc. * * XXX what if we have stations already associated??? * XXX probably not right for autoselect? * * Short preamble is not interoperable with legacy .11b * equipment, so it should not be the default for b or * mixed b/g networks. -dcy a880 4 #if 0 if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) ic->ic_flags |= IEEE80211_F_SHPREAMBLE; #endif d882 20 a901 4 if (ic->ic_caps & IEEE80211_C_SHSLOT) ic->ic_flags |= IEEE80211_F_SHSLOT; } else ic->ic_flags &= ~IEEE80211_F_SHSLOT; d904 3 d913 3 a915 4 * caller can select a rate set. This is problematic and the * work here assumes how things work elsewhere in this code. * * XXX never returns turbo modes -dcy d920 7 a926 13 /* * NB: this assumes the channel would not be supplied to us * unless it was already compatible with the current mode. */ if (ic->ic_curmode != IEEE80211_MODE_AUTO || chan == IEEE80211_CHAN_ANYC) return ic->ic_curmode; /* * In autoselect mode; deduce a mode based on the channel * characteristics. We assume that turbo-only channels * are not considered when the channel set is constructed. */ if (IEEE80211_IS_CHAN_5GHZ(chan)) d928 1 a928 1 else if (IEEE80211_IS_CHAN_FHSS(chan)) d930 9 a938 1 else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) d940 1 a940 1 else d990 1 a990 1 case IEEE80211_MODE_TURBO: d1008 1 d1029 1 a1032 1 2, /* IFM_IEEE80211_DS1 */ a1047 315 #ifdef __NetBSD__ static void ieee80211_clean_all_nodes(int cache_size) { struct ieee80211com *ic; LIST_FOREACH(ic, &ieee80211com_head, ic_list) { ic->ic_max_nnodes = cache_size; ieee80211_clean_nodes(ic); } } /* TBD factor with sysctl_ath_verify. */ static int sysctl_ieee80211_verify(SYSCTLFN_ARGS) { int error, t; struct sysctlnode node; node = *rnode; t = *(int*)rnode->sysctl_data; node.sysctl_data = &t; error = sysctl_lookup(SYSCTLFN_CALL(&node)); if (error || newp == NULL) return (error); if (node.sysctl_num == ieee80211_cache_size_nodenum) { if (t < 0) return (EINVAL); #ifdef IEEE80211_DEBUG } else if (node.sysctl_num != ieee80211_debug_nodenum) #else /* IEEE80211_DEBUG */ } else #endif /* IEEE80211_DEBUG */ return (EINVAL); *(int*)rnode->sysctl_data = t; if (node.sysctl_num == ieee80211_cache_size_nodenum) ieee80211_clean_all_nodes(t); return (0); } /* * Pointers for testing: * * If there are no interfaces, or else no 802.11 interfaces, * ieee80211_node_walkfirst must return NULL. * * If there is any single 802.11 interface, ieee80211_node_walkfirst * must not return NULL. */ static struct ieee80211_node * ieee80211_node_walkfirst(struct ieee80211_node_walk *nw, u_short if_index) { struct ieee80211com *ic; (void)memset(nw, 0, sizeof(*nw)); nw->nw_ifindex = if_index; LIST_FOREACH(ic, &ieee80211com_head, ic_list) { if (if_index != 0 && ic->ic_if.if_index != if_index) continue; nw->nw_ic = ic; nw->nw_ni = ic->ic_bss; break; } KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL)); return nw->nw_ni; } static struct ieee80211_node * ieee80211_node_walknext(struct ieee80211_node_walk *nw) { KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL)); if (nw->nw_ic == NULL && nw->nw_ni == NULL) return NULL; if (nw->nw_ni == nw->nw_ic->ic_bss) nw->nw_ni = TAILQ_FIRST(&nw->nw_ic->ic_node); else nw->nw_ni = TAILQ_NEXT(nw->nw_ni, ni_list); if (nw->nw_ni == NULL) { if (nw->nw_ifindex != 0) return NULL; nw->nw_ic = LIST_NEXT(nw->nw_ic, ic_list); if (nw->nw_ic == NULL) return NULL; nw->nw_ni = nw->nw_ic->ic_bss; } KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL)); return nw->nw_ni; } static void sysctl_ieee80211_fill_node(struct ieee80211_node *ni, struct ieee80211_node_sysctl *ns, int ifindex, struct ieee80211_channel *chan0, int is_bss) { ns->ns_ifindex = ifindex; ns->ns_capinfo = ni->ni_capinfo; ns->ns_flags = (is_bss) ? IEEE80211_NODE_SYSCTL_F_BSS : 0; (void)memcpy(ns->ns_macaddr, ni->ni_macaddr, sizeof(ns->ns_macaddr)); (void)memcpy(ns->ns_bssid, ni->ni_bssid, sizeof(ns->ns_bssid)); if (ni->ni_chan != IEEE80211_CHAN_ANYC) { ns->ns_freq = ni->ni_chan->ic_freq; ns->ns_chanflags = ni->ni_chan->ic_flags; ns->ns_chanidx = ni->ni_chan - chan0; } else { ns->ns_freq = ns->ns_chanflags = 0; ns->ns_chanidx = 0; } ns->ns_rssi = ni->ni_rssi; ns->ns_esslen = ni->ni_esslen; (void)memcpy(ns->ns_essid, ni->ni_essid, sizeof(ns->ns_essid)); ns->ns_pwrsave = ni->ni_pwrsave; ns->ns_erp = ni->ni_erp; ns->ns_associd = ni->ni_associd; ns->ns_inact = ni->ni_inact * IEEE80211_INACT_WAIT; ns->ns_rstamp = ni->ni_rstamp; ns->ns_rates = ni->ni_rates; ns->ns_txrate = ni->ni_txrate; ns->ns_intval = ni->ni_intval; (void)memcpy(ns->ns_tstamp, ni->ni_tstamp, sizeof(ns->ns_tstamp)); ns->ns_txseq = ni->ni_txseq; ns->ns_rxseq = ni->ni_rxseq; ns->ns_fhdwell = ni->ni_fhdwell; ns->ns_fhindex = ni->ni_fhindex; ns->ns_fails = ni->ni_fails; } /* Between two examinations of the sysctl tree, I expect each * interface to add no more than 5 nodes. */ #define IEEE80211_SYSCTL_NODE_GROWTH 5 static int sysctl_ieee80211_node(SYSCTLFN_ARGS) { struct ieee80211_node_walk nw; struct ieee80211_node *ni; struct ieee80211_node_sysctl ns; char *dp; u_int cur_ifindex, ifcount, ifindex, last_ifindex, op, arg, hdr_type; size_t len, needed, eltsize, out_size; int error, s, nelt; if (namelen == 1 && name[0] == CTL_QUERY) return (sysctl_query(SYSCTLFN_CALL(rnode))); if (namelen != IEEE80211_SYSCTL_NODENAMELEN) return (EINVAL); /* ifindex.op.arg.header-type.eltsize.nelt */ dp = oldp; len = (oldp != NULL) ? *oldlenp : 0; ifindex = name[IEEE80211_SYSCTL_NODENAME_IF]; op = name[IEEE80211_SYSCTL_NODENAME_OP]; arg = name[IEEE80211_SYSCTL_NODENAME_ARG]; hdr_type = name[IEEE80211_SYSCTL_NODENAME_TYPE]; eltsize = name[IEEE80211_SYSCTL_NODENAME_ELTSIZE]; nelt = name[IEEE80211_SYSCTL_NODENAME_ELTCOUNT]; out_size = MIN(sizeof(ns), eltsize); if (op != IEEE80211_SYSCTL_OP_ALL || arg != 0 || hdr_type != IEEE80211_SYSCTL_T_NODE || eltsize < 1 || nelt < 0) return (EINVAL); error = 0; needed = 0; ifcount = 0; last_ifindex = 0; s = splnet(); for (ni = ieee80211_node_walkfirst(&nw, ifindex); ni != NULL; ni = ieee80211_node_walknext(&nw)) { struct ieee80211com *ic; ic = nw.nw_ic; cur_ifindex = ic->ic_if.if_index; if (cur_ifindex != last_ifindex) { ifcount++; last_ifindex = cur_ifindex; } if (nelt <= 0) continue; if (len >= eltsize) { sysctl_ieee80211_fill_node(ni, &ns, cur_ifindex, &ic->ic_channels[0], ni == ic->ic_bss); error = copyout(&ns, dp, out_size); if (error) goto cleanup; dp += eltsize; len -= eltsize; } needed += eltsize; if (nelt != INT_MAX) nelt--; } cleanup: splx(s); *oldlenp = needed; if (oldp == NULL) *oldlenp += ifcount * IEEE80211_SYSCTL_NODE_GROWTH * eltsize; return (error); } /* * Setup sysctl(3) MIB, net.ieee80211.* * * TBD condition CTLFLAG_PERMANENT on being an LKM or not */ SYSCTL_SETUP(sysctl_ieee80211, "sysctl ieee80211 subtree setup") { int rc; const struct sysctlnode *cnode, *rnode; if ((rc = sysctl_createv(clog, 0, NULL, &rnode, CTLFLAG_PERMANENT, CTLTYPE_NODE, "net", NULL, NULL, 0, NULL, 0, CTL_NET, CTL_EOL)) != 0) goto err; if ((rc = sysctl_createv(clog, 0, &rnode, &rnode, CTLFLAG_PERMANENT, CTLTYPE_NODE, "link", "link-layer statistics and controls", NULL, 0, NULL, 0, PF_LINK, CTL_EOL)) != 0) goto err; if ((rc = sysctl_createv(clog, 0, &rnode, &rnode, CTLFLAG_PERMANENT, CTLTYPE_NODE, "ieee80211", "IEEE 802.11 WLAN statistics and controls", NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) goto err; if ((rc = sysctl_createv(clog, 0, &rnode, NULL, CTLFLAG_PERMANENT, CTLTYPE_NODE, "nodes", "client/peer stations", sysctl_ieee80211_node, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) goto err; #ifdef IEEE80211_DEBUG /* control debugging printfs */ if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "debug", SYSCTL_DESCR("Enable IEEE 802.11 debugging output"), sysctl_ieee80211_verify, 0, &ieee80211_debug, 0, CTL_CREATE, CTL_EOL)) != 0) goto err; ieee80211_debug_nodenum = cnode->sysctl_num; #endif /* IEEE80211_DEBUG */ /* control LRU cache size */ if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "maxnodecache", SYSCTL_DESCR("Maximum station cache size"), sysctl_ieee80211_verify, 0, &ieee80211_cache_size, 0, CTL_CREATE, CTL_EOL)) != 0) goto err; ieee80211_cache_size_nodenum = cnode->sysctl_num; return; err: printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); } #endif /* __NetBSD__ */ #ifdef __FreeBSD__ /* * Module glue. * * NB: the module name is "wlan" for compatibility with NetBSD. */ static int ieee80211_modevent(module_t mod, int type, void *unused) { switch (type) { case MOD_LOAD: if (bootverbose) printf("wlan: <802.11 Link Layer>\n"); return 0; case MOD_UNLOAD: return 0; } return EINVAL; } static moduledata_t ieee80211_mod = { "wlan", ieee80211_modevent, 0 }; DECLARE_MODULE(wlan, ieee80211_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); MODULE_VERSION(wlan, 1); MODULE_DEPEND(wlan, rc4, 1, 1, 1); MODULE_DEPEND(wlan, ether, 1, 1, 1); #endif @ 1.35 log @Properly fix the constipated lossage wrt -Wcast-qual and the sysctl code. I know it's not the prettiest code, but it seems to work rather well in spite of itself. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.34 2005/05/30 04:16:56 christos Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.34 2005/05/30 04:16:56 christos Exp $"); d1158 1 a1158 1 struct sysctlnode *cnode, *rnode; @ 1.34 log @Unconst sysctl_query... hi atatat @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.33 2005/02/26 22:45:09 perry Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.33 2005/02/26 22:45:09 perry Exp $"); d1085 1 a1085 2 /*XXXUNCONST*/ return (sysctl_query(SYSCTLFN_CALL(__UNCONST(rnode)))); @ 1.33 log @nuke trailing whitespace @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.32 2004/08/10 00:57:21 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.32 2004/08/10 00:57:21 dyoung Exp $"); d1085 2 a1086 1 return (sysctl_query(SYSCTLFN_CALL(rnode))); @ 1.32 log @Make the node table into an LRU cache: least-recently used nodes are at the end of the node queue. Change the reference-counting discipline: ni->ni_refcnt indicates how many times net80211 has granted ni to the driver. Every node in the table with ni_refcnt=0 is eligible to be garbage-collected. The mere presence of a node in the table does not any longer indicate its auth/assoc state; nodes have a ni_state variable, now. A sysctl, net.link.ieee80211.maxnodecache, controls the maximum LRU cache size. While I am here, patch ieee80211_find_node_for_beacon to do a "best match" by bssid/ssid/channel, not a "perfect match." This keeps net80211 from caching duplicate nodes in the table. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.31 2004/07/30 17:05:18 mycroft Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.31 2004/07/30 17:05:18 mycroft Exp $"); d49 2 a50 2 #include #include d66 1 a66 1 d85 1 a85 1 #include d325 1 a325 1 static const u_int mopts[] = { d979 1 a979 1 */ @ 1.32.4.1 log @sync with -current @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.33 2005/02/26 22:45:09 perry Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.33 2005/02/26 22:45:09 perry Exp $"); d49 2 a50 2 #include #include d66 1 a66 1 d85 1 a85 1 #include d325 1 a325 1 static const u_int mopts[] = { d979 1 a979 1 */ @ 1.32.6.1 log @sync with head. xen and whitespace. xen part is not finished. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.32 2004/08/10 00:57:21 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.32 2004/08/10 00:57:21 dyoung Exp $"); d49 2 a50 2 #include #include d66 1 a66 1 d85 1 a85 1 #include d325 1 a325 1 static const u_int mopts[] = { d979 1 a979 1 */ @ 1.31 log @Change the basic rate list for 11g to contain just the 11b modes, mimicking the behavior of other systems. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.30 2004/07/30 04:32:10 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.30 2004/07/30 04:32:10 dyoung Exp $"); d105 2 a106 2 int ieee80211_inact_max = IEEE80211_INACT_MAX; static int ieee80211_inact_max_nodenum; a639 2 if (ic->ic_inact_timer && --ic->ic_inact_timer == 0) ieee80211_timeout_nodes(ic); d641 1 a641 1 if (ic->ic_mgt_timer != 0 || ic->ic_inact_timer != 0) d930 10 d954 2 a955 2 if (node.sysctl_num == ieee80211_inact_max_nodenum) { if (t < 1) a956 1 t = roundup(t, IEEE80211_INACT_WAIT) / IEEE80211_INACT_WAIT; d966 2 d1196 1 a1196 1 /* control inactivity timer */ d1199 2 a1200 2 "maxinact", SYSCTL_DESCR("Station inactivity timeout"), sysctl_ieee80211_verify, 0, &ieee80211_inact_max, d1204 1 a1204 1 ieee80211_inact_max_nodenum = cnode->sysctl_num; @ 1.31.2.1 log @file ieee80211.c was added on branch ktrace-lwp on 2004-08-03 10:54:20 +0000 @ text @d1 1233 @ 1.31.2.2 log @Sync with HEAD @ text @a0 1233 /* $NetBSD: ieee80211.c,v 1.31.2.1 2004/08/03 10:54:20 skrll Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #ifdef __FreeBSD__ __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.11 2004/04/02 20:19:20 sam Exp $"); #else __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.31.2.1 2004/08/03 10:54:20 skrll Exp $"); #endif /* * IEEE 802.11 generic handler */ #include "opt_inet.h" #include "bpfilter.h" #include #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ #include #endif #include #include #ifdef __FreeBSD__ #include #endif #include #include #include #include #ifdef __FreeBSD__ #include #else #include #endif #include #include #include #include #include #ifdef INET #include #ifdef __FreeBSD__ #include #else #include #endif #endif #ifdef IEEE80211_DEBUG int ieee80211_debug = 0; #ifdef __NetBSD__ static int ieee80211_debug_nodenum; #endif /* __NetBSD__ */ #ifdef __FreeBSD__ SYSCTL_INT(_debug, OID_AUTO, ieee80211, CTLFLAG_RW, &ieee80211_debug, 0, "IEEE 802.11 media debugging printfs"); #endif #endif int ieee80211_inact_max = IEEE80211_INACT_MAX; static int ieee80211_inact_max_nodenum; struct ieee80211com_head ieee80211com_head = LIST_HEAD_INITIALIZER(ieee80211com_head); static void ieee80211_setbasicrates(struct ieee80211com *); #ifdef __NetBSD__ static void sysctl_ieee80211_fill_node(struct ieee80211_node *, struct ieee80211_node_sysctl *, int, struct ieee80211_channel *, int); static struct ieee80211_node *ieee80211_node_walknext( struct ieee80211_node_walk *); static struct ieee80211_node *ieee80211_node_walkfirst( struct ieee80211_node_walk *, u_short); static int sysctl_ieee80211_verify(SYSCTLFN_ARGS); static int sysctl_ieee80211_node(SYSCTLFN_ARGS); #endif /* __NetBSD__ */ #define LOGICALLY_EQUAL(x, y) (!(x) == !(y)) static const char *ieee80211_phymode_name[] = { "auto", /* IEEE80211_MODE_AUTO */ "11a", /* IEEE80211_MODE_11A */ "11b", /* IEEE80211_MODE_11B */ "11g", /* IEEE80211_MODE_11G */ "FH", /* IEEE80211_MODE_FH */ "turbo", /* IEEE80211_MODE_TURBO */ }; void ieee80211_ifattach(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; struct ieee80211_channel *c; int i; ether_ifattach(ifp, ic->ic_myaddr); #if NBPFILTER > 0 bpfattach2(ifp, DLT_IEEE802_11, sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf); #endif ieee80211_crypto_attach(ifp); /* * Fill in 802.11 available channel set, mark * all available channels as active, and pick * a default channel if not already specified. */ memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); ic->ic_modecaps |= 1<ic_channels[i]; if (c->ic_flags) { /* * Verify driver passed us valid data. */ if (i != ieee80211_chan2ieee(ic, c)) { if_printf(ifp, "bad channel ignored; " "freq %u flags %x number %u\n", c->ic_freq, c->ic_flags, i); c->ic_flags = 0; /* NB: remove */ continue; } setbit(ic->ic_chan_avail, i); /* * Identify mode capabilities. */ if (IEEE80211_IS_CHAN_A(c)) ic->ic_modecaps |= 1<ic_modecaps |= 1<ic_modecaps |= 1<ic_modecaps |= 1<ic_modecaps |= 1<ic_curmode */ if ((ic->ic_modecaps & (1<ic_curmode)) == 0) ic->ic_curmode = IEEE80211_MODE_AUTO; ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ ieee80211_setbasicrates(ic); (void) ieee80211_setmode(ic, ic->ic_curmode); if (ic->ic_lintval == 0) ic->ic_lintval = 100; /* default sleep */ ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */ LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list); ieee80211_node_attach(ic); ieee80211_proto_attach(ifp); } void ieee80211_ifdetach(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; ieee80211_proto_detach(ifp); ieee80211_crypto_detach(ifp); ieee80211_node_detach(ic); LIST_REMOVE(ic, ic_list); #ifdef __FreeBSD__ ifmedia_removeall(&ic->ic_media); #else ifmedia_delete_instance(&ic->ic_media, IFM_INST_ANY); #endif #if NBPFILTER > 0 bpfdetach(ifp); #endif ether_ifdetach(ifp); } /* * Convert MHz frequency to IEEE channel number. */ u_int ieee80211_mhz2ieee(u_int freq, u_int flags) { if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ if (freq == 2484) return 14; if (freq < 2484) return (freq - 2407) / 5; else return 15 + ((freq - 2512) / 20); } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */ return (freq - 5000) / 5; } else { /* either, guess */ if (freq == 2484) return 14; if (freq < 2484) return (freq - 2407) / 5; if (freq < 5000) return 15 + ((freq - 2512) / 20); return (freq - 5000) / 5; } } /* * Convert channel to IEEE channel number. */ u_int ieee80211_chan2ieee(struct ieee80211com *ic, struct ieee80211_channel *c) { if (ic->ic_channels <= c && c <= &ic->ic_channels[IEEE80211_CHAN_MAX]) return c - ic->ic_channels; else if (c == IEEE80211_CHAN_ANYC) return IEEE80211_CHAN_ANY; else if (c != NULL) { if_printf(&ic->ic_if, "invalid channel freq %u flags %x\n", c->ic_freq, c->ic_flags); return 0; /* XXX */ } else { if_printf(&ic->ic_if, "invalid channel (NULL)\n"); return 0; /* XXX */ } } /* * Convert IEEE channel number to MHz frequency. */ u_int ieee80211_ieee2mhz(u_int chan, u_int flags) { if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ if (chan == 14) return 2484; if (chan < 14) return 2407 + chan*5; else return 2512 + ((chan-15)*20); } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */ return 5000 + (chan*5); } else { /* either, guess */ if (chan == 14) return 2484; if (chan < 14) /* 0-13 */ return 2407 + chan*5; if (chan < 27) /* 15-26 */ return 2512 + ((chan-15)*20); return 5000 + (chan*5); } } /* * Setup the media data structures according to the channel and * rate tables. This must be called by the driver after * ieee80211_attach and before most anything else. */ void ieee80211_media_init(struct ifnet *ifp, ifm_change_cb_t media_change, ifm_stat_cb_t media_stat) { #define ADD(_ic, _s, _o) \ ifmedia_add(&(_ic)->ic_media, \ IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL) struct ieee80211com *ic = (void *)ifp; struct ifmediareq imr; int i, j, mode, rate, maxrate, mword, mopt, r; struct ieee80211_rateset *rs; struct ieee80211_rateset allrates; /* * Do late attach work that must wait for any subclass * (i.e. driver) work such as overriding methods. */ ieee80211_node_lateattach(ic); /* * Fill in media characteristics. */ ifmedia_init(&ic->ic_media, 0, media_change, media_stat); maxrate = 0; memset(&allrates, 0, sizeof(allrates)); for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_MAX; mode++) { static const u_int mopts[] = { IFM_AUTO, IFM_IEEE80211_11A, IFM_IEEE80211_11B, IFM_IEEE80211_11G, IFM_IEEE80211_FH, IFM_IEEE80211_11A | IFM_IEEE80211_TURBO, }; if ((ic->ic_modecaps & (1<ic_caps & IEEE80211_C_IBSS) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP); if (ic->ic_caps & IEEE80211_C_AHDEMO) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0); if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_MONITOR); if (mode == IEEE80211_MODE_AUTO) continue; if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]); rs = &ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rate = rs->rs_rates[i]; mword = ieee80211_rate2media(ic, rate, mode); if (mword == 0) continue; printf("%s%d%sMbps", (i != 0 ? " " : ""), (rate & IEEE80211_RATE_VAL) / 2, ((rate & 0x1) != 0 ? ".5" : "")); ADD(ic, mword, mopt); if (ic->ic_caps & IEEE80211_C_IBSS) ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP); if (ic->ic_caps & IEEE80211_C_AHDEMO) ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0); if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, mword, mopt | IFM_IEEE80211_MONITOR); /* * Add rate to the collection of all rates. */ r = rate & IEEE80211_RATE_VAL; for (j = 0; j < allrates.rs_nrates; j++) if (allrates.rs_rates[j] == r) break; if (j == allrates.rs_nrates) { /* unique, add to the set */ allrates.rs_rates[j] = r; allrates.rs_nrates++; } rate = (rate & IEEE80211_RATE_VAL) / 2; if (rate > maxrate) maxrate = rate; } printf("\n"); } for (i = 0; i < allrates.rs_nrates; i++) { mword = ieee80211_rate2media(ic, allrates.rs_rates[i], IEEE80211_MODE_AUTO); if (mword == 0) continue; mword = IFM_SUBTYPE(mword); /* remove media options */ ADD(ic, mword, 0); if (ic->ic_caps & IEEE80211_C_IBSS) ADD(ic, mword, IFM_IEEE80211_ADHOC); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, mword, IFM_IEEE80211_HOSTAP); if (ic->ic_caps & IEEE80211_C_AHDEMO) ADD(ic, mword, IFM_IEEE80211_ADHOC | IFM_FLAG0); if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, mword, IFM_IEEE80211_MONITOR); } ieee80211_media_status(ifp, &imr); ifmedia_set(&ic->ic_media, imr.ifm_active); #ifndef __linux__ if (maxrate) ifp->if_baudrate = IF_Mbps(maxrate); #endif #undef ADD } static int findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate) { #define IEEERATE(_ic,_m,_i) \ ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL) int i, nrates = ic->ic_sup_rates[mode].rs_nrates; for (i = 0; i < nrates; i++) if (IEEERATE(ic, mode, i) == rate) return i; return -1; #undef IEEERATE } /* * Handle a media change request. */ int ieee80211_media_change(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; struct ifmedia_entry *ime; enum ieee80211_opmode newopmode; enum ieee80211_phymode newphymode; int i, j, newrate, error = 0; ime = ic->ic_media.ifm_cur; /* * First, identify the phy mode. */ switch (IFM_MODE(ime->ifm_media)) { case IFM_IEEE80211_11A: newphymode = IEEE80211_MODE_11A; break; case IFM_IEEE80211_11B: newphymode = IEEE80211_MODE_11B; break; case IFM_IEEE80211_11G: newphymode = IEEE80211_MODE_11G; break; case IFM_IEEE80211_FH: newphymode = IEEE80211_MODE_FH; break; case IFM_AUTO: newphymode = IEEE80211_MODE_AUTO; break; default: return EINVAL; } /* * Turbo mode is an ``option''. Eventually it * needs to be applied to 11g too. */ if (ime->ifm_media & IFM_IEEE80211_TURBO) { if (newphymode != IEEE80211_MODE_11A) return EINVAL; newphymode = IEEE80211_MODE_TURBO; } /* * Validate requested mode is available. */ if ((ic->ic_modecaps & (1<ifm_media) != IFM_AUTO) { /* * Convert media subtype to rate. */ newrate = ieee80211_media2rate(ime->ifm_media); if (newrate == 0) return EINVAL; /* * Check the rate table for the specified/current phy. */ if (newphymode == IEEE80211_MODE_AUTO) { /* * In autoselect mode search for the rate. */ for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++) { if ((ic->ic_modecaps & (1<ifm_media & (IFM_IEEE80211_ADHOC|IFM_FLAG0)) == (IFM_IEEE80211_ADHOC|IFM_FLAG0)) newopmode = IEEE80211_M_AHDEMO; else if (ime->ifm_media & IFM_IEEE80211_HOSTAP) newopmode = IEEE80211_M_HOSTAP; else if (ime->ifm_media & IFM_IEEE80211_ADHOC) newopmode = IEEE80211_M_IBSS; else if (ime->ifm_media & IFM_IEEE80211_MONITOR) newopmode = IEEE80211_M_MONITOR; else newopmode = IEEE80211_M_STA; /* * Autoselect doesn't make sense when operating as an AP. * If no phy mode has been selected, pick one and lock it * down so rate tables can be used in forming beacon frames * and the like. */ if (newopmode == IEEE80211_M_HOSTAP && newphymode == IEEE80211_MODE_AUTO) { for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++) if (ic->ic_modecaps & (1<ic_curmode != newphymode) { /* change phy mode */ error = ieee80211_setmode(ic, newphymode); if (error != 0) return error; error = ENETRESET; } /* * Committed to changes, install the rate setting. */ if (ic->ic_fixed_rate != i) { ic->ic_fixed_rate = i; /* set fixed tx rate */ error = ENETRESET; } /* * Handle operating mode change. */ if (ic->ic_opmode != newopmode) { ic->ic_opmode = newopmode; switch (newopmode) { case IEEE80211_M_AHDEMO: case IEEE80211_M_HOSTAP: case IEEE80211_M_STA: case IEEE80211_M_MONITOR: ic->ic_flags &= ~IEEE80211_F_IBSSON; break; case IEEE80211_M_IBSS: ic->ic_flags |= IEEE80211_F_IBSSON; break; } error = ENETRESET; } #ifdef notdef if (error == 0) ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media); #endif return error; } void ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr) { struct ieee80211com *ic = (void *)ifp; struct ieee80211_node *ni = NULL; imr->ifm_status = IFM_AVALID; imr->ifm_active = IFM_IEEE80211; if (ic->ic_state == IEEE80211_S_RUN) imr->ifm_status |= IFM_ACTIVE; imr->ifm_active |= IFM_AUTO; switch (ic->ic_opmode) { case IEEE80211_M_STA: ni = ic->ic_bss; /* calculate rate subtype */ imr->ifm_active |= ieee80211_rate2media(ic, ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode); break; case IEEE80211_M_IBSS: imr->ifm_active |= IFM_IEEE80211_ADHOC; break; case IEEE80211_M_AHDEMO: /* should not come here */ break; case IEEE80211_M_HOSTAP: imr->ifm_active |= IFM_IEEE80211_HOSTAP; break; case IEEE80211_M_MONITOR: imr->ifm_active |= IFM_IEEE80211_MONITOR; break; } switch (ic->ic_curmode) { case IEEE80211_MODE_11A: imr->ifm_active |= IFM_IEEE80211_11A; break; case IEEE80211_MODE_11B: imr->ifm_active |= IFM_IEEE80211_11B; break; case IEEE80211_MODE_11G: imr->ifm_active |= IFM_IEEE80211_11G; break; case IEEE80211_MODE_FH: imr->ifm_active |= IFM_IEEE80211_FH; break; case IEEE80211_MODE_TURBO: imr->ifm_active |= IFM_IEEE80211_11A | IFM_IEEE80211_TURBO; break; } } void ieee80211_watchdog(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); if (ic->ic_inact_timer && --ic->ic_inact_timer == 0) ieee80211_timeout_nodes(ic); if (ic->ic_mgt_timer != 0 || ic->ic_inact_timer != 0) ifp->if_timer = 1; } /* * Mark the basic rates for the 11g rate table based on the * operating mode. For real 11g we mark all the 11b rates * and 6, 12, and 24 OFDM. For 11b compatibility we mark only * 11b rates. There's also a pseudo 11a-mode used to mark only * the basic OFDM rates. */ static void ieee80211_setbasicrates(struct ieee80211com *ic) { static const struct ieee80211_rateset basic[] = { { 0 }, /* IEEE80211_MODE_AUTO */ { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */ { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G */ { 2, { 2, 4 } }, /* IEEE80211_MODE_FH */ { 0 }, /* IEEE80211_MODE_TURBO */ }; enum ieee80211_phymode mode; struct ieee80211_rateset *rs; int i, j; for (mode = 0; mode < IEEE80211_MODE_MAX; mode++) { rs = &ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rs->rs_rates[i] &= IEEE80211_RATE_VAL; for (j = 0; j < basic[mode].rs_nrates; j++) if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { rs->rs_rates[i] |= IEEE80211_RATE_BASIC; break; } } } } /* * Set the current phy mode and recalculate the active channel * set based on the available channels for this mode. Also * select a new default/current channel if the current one is * inappropriate for this mode. */ int ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) { #define N(a) (sizeof(a) / sizeof(a[0])) static const u_int chanflags[] = { 0, /* IEEE80211_MODE_AUTO */ IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */ IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */ IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */ IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */ IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO */ }; struct ieee80211_channel *c; u_int modeflags; int i; /* validate new mode */ if ((ic->ic_modecaps & (1<ic_modecaps)); return EINVAL; } /* * Verify at least one channel is present in the available * channel list before committing to the new mode. */ IASSERT(mode < N(chanflags), ("Unexpected mode %u", mode)); modeflags = chanflags[mode]; for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (mode == IEEE80211_MODE_AUTO) { /* ignore turbo channels for autoselect */ if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0) break; } else { if ((c->ic_flags & modeflags) == modeflags) break; } } if (i > IEEE80211_CHAN_MAX) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, ("%s: no channels found for mode %u\n", __func__, mode)); return EINVAL; } /* * Calculate the active channel set. */ memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active)); for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (mode == IEEE80211_MODE_AUTO) { /* take anything but pure turbo channels */ if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0) setbit(ic->ic_chan_active, i); } else { if ((c->ic_flags & modeflags) == modeflags) setbit(ic->ic_chan_active, i); } } /* * If no current/default channel is setup or the current * channel is wrong for the mode then pick the first * available channel from the active list. This is likely * not the right one. */ if (ic->ic_ibss_chan == NULL || isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { for (i = 0; i <= IEEE80211_CHAN_MAX; i++) if (isset(ic->ic_chan_active, i)) { ic->ic_ibss_chan = &ic->ic_channels[i]; break; } IASSERT(ic->ic_ibss_chan != NULL && isset(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan)), ("Bad IBSS channel %u", ieee80211_chan2ieee(ic, ic->ic_ibss_chan))); } /* * Set/reset state flags that influence beacon contents, etc. * * XXX what if we have stations already associated??? * XXX probably not right for autoselect? * * Short preamble is not interoperable with legacy .11b * equipment, so it should not be the default for b or * mixed b/g networks. -dcy */ #if 0 if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) ic->ic_flags |= IEEE80211_F_SHPREAMBLE; #endif if (mode == IEEE80211_MODE_11G) { if (ic->ic_caps & IEEE80211_C_SHSLOT) ic->ic_flags |= IEEE80211_F_SHSLOT; } else ic->ic_flags &= ~IEEE80211_F_SHSLOT; ic->ic_curmode = mode; return 0; #undef N } /* * Return the phy mode for with the specified channel so the * caller can select a rate set. This is problematic and the * work here assumes how things work elsewhere in this code. * * XXX never returns turbo modes -dcy */ enum ieee80211_phymode ieee80211_chan2mode(struct ieee80211com *ic, struct ieee80211_channel *chan) { /* * NB: this assumes the channel would not be supplied to us * unless it was already compatible with the current mode. */ if (ic->ic_curmode != IEEE80211_MODE_AUTO || chan == IEEE80211_CHAN_ANYC) return ic->ic_curmode; /* * In autoselect mode; deduce a mode based on the channel * characteristics. We assume that turbo-only channels * are not considered when the channel set is constructed. */ if (IEEE80211_IS_CHAN_5GHZ(chan)) return IEEE80211_MODE_11A; else if (IEEE80211_IS_CHAN_FHSS(chan)) return IEEE80211_MODE_FH; else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) return IEEE80211_MODE_11G; else return IEEE80211_MODE_11B; } /* * convert IEEE80211 rate value to ifmedia subtype. * ieee80211 rate is in unit of 0.5Mbps. */ int ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode) { #define N(a) (sizeof(a) / sizeof(a[0])) static const struct { u_int m; /* rate + mode */ u_int r; /* if_media rate */ } rates[] = { { 2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 }, { 4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 }, { 2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 }, { 4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 }, { 11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 }, { 22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 }, { 44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 }, { 12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 }, { 18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 }, { 24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 }, { 36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 }, { 48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 }, { 72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 }, { 96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 }, { 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 }, { 2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 }, { 4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 }, { 11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 }, { 22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 }, { 12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 }, { 18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 }, { 24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 }, { 36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 }, { 48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 }, { 72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 }, { 96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 }, { 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 }, /* NB: OFDM72 doesn't realy exist so we don't handle it */ }; u_int mask, i; mask = rate & IEEE80211_RATE_VAL; switch (mode) { case IEEE80211_MODE_11A: case IEEE80211_MODE_TURBO: mask |= IFM_IEEE80211_11A; break; case IEEE80211_MODE_11B: mask |= IFM_IEEE80211_11B; break; case IEEE80211_MODE_FH: mask |= IFM_IEEE80211_FH; break; case IEEE80211_MODE_AUTO: /* NB: ic may be NULL for some drivers */ if (ic && ic->ic_phytype == IEEE80211_T_FH) { mask |= IFM_IEEE80211_FH; break; } /* NB: hack, 11g matches both 11b+11a rates */ /* fall thru... */ case IEEE80211_MODE_11G: mask |= IFM_IEEE80211_11G; break; } for (i = 0; i < N(rates); i++) if (rates[i].m == mask) return rates[i].r; return IFM_AUTO; #undef N } int ieee80211_media2rate(int mword) { #define N(a) (sizeof(a) / sizeof(a[0])) static const int ieeerates[] = { -1, /* IFM_AUTO */ 0, /* IFM_MANUAL */ 0, /* IFM_NONE */ 2, /* IFM_IEEE80211_FH1 */ 4, /* IFM_IEEE80211_FH2 */ 4, /* IFM_IEEE80211_DS2 */ 11, /* IFM_IEEE80211_DS5 */ 22, /* IFM_IEEE80211_DS11 */ 2, /* IFM_IEEE80211_DS1 */ 44, /* IFM_IEEE80211_DS22 */ 12, /* IFM_IEEE80211_OFDM6 */ 18, /* IFM_IEEE80211_OFDM9 */ 24, /* IFM_IEEE80211_OFDM12 */ 36, /* IFM_IEEE80211_OFDM18 */ 48, /* IFM_IEEE80211_OFDM24 */ 72, /* IFM_IEEE80211_OFDM36 */ 96, /* IFM_IEEE80211_OFDM48 */ 108, /* IFM_IEEE80211_OFDM54 */ 144, /* IFM_IEEE80211_OFDM72 */ }; return IFM_SUBTYPE(mword) < N(ieeerates) ? ieeerates[IFM_SUBTYPE(mword)] : 0; #undef N } #ifdef __NetBSD__ /* TBD factor with sysctl_ath_verify. */ static int sysctl_ieee80211_verify(SYSCTLFN_ARGS) { int error, t; struct sysctlnode node; node = *rnode; t = *(int*)rnode->sysctl_data; node.sysctl_data = &t; error = sysctl_lookup(SYSCTLFN_CALL(&node)); if (error || newp == NULL) return (error); if (node.sysctl_num == ieee80211_inact_max_nodenum) { if (t < 1) return (EINVAL); t = roundup(t, IEEE80211_INACT_WAIT) / IEEE80211_INACT_WAIT; #ifdef IEEE80211_DEBUG } else if (node.sysctl_num != ieee80211_debug_nodenum) #else /* IEEE80211_DEBUG */ } else #endif /* IEEE80211_DEBUG */ return (EINVAL); *(int*)rnode->sysctl_data = t; return (0); } /* * Pointers for testing: * * If there are no interfaces, or else no 802.11 interfaces, * ieee80211_node_walkfirst must return NULL. * * If there is any single 802.11 interface, ieee80211_node_walkfirst * must not return NULL. */ static struct ieee80211_node * ieee80211_node_walkfirst(struct ieee80211_node_walk *nw, u_short if_index) { struct ieee80211com *ic; (void)memset(nw, 0, sizeof(*nw)); nw->nw_ifindex = if_index; LIST_FOREACH(ic, &ieee80211com_head, ic_list) { if (if_index != 0 && ic->ic_if.if_index != if_index) continue; nw->nw_ic = ic; nw->nw_ni = ic->ic_bss; break; } KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL)); return nw->nw_ni; } static struct ieee80211_node * ieee80211_node_walknext(struct ieee80211_node_walk *nw) { KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL)); if (nw->nw_ic == NULL && nw->nw_ni == NULL) return NULL; if (nw->nw_ni == nw->nw_ic->ic_bss) nw->nw_ni = TAILQ_FIRST(&nw->nw_ic->ic_node); else nw->nw_ni = TAILQ_NEXT(nw->nw_ni, ni_list); if (nw->nw_ni == NULL) { if (nw->nw_ifindex != 0) return NULL; nw->nw_ic = LIST_NEXT(nw->nw_ic, ic_list); if (nw->nw_ic == NULL) return NULL; nw->nw_ni = nw->nw_ic->ic_bss; } KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL)); return nw->nw_ni; } static void sysctl_ieee80211_fill_node(struct ieee80211_node *ni, struct ieee80211_node_sysctl *ns, int ifindex, struct ieee80211_channel *chan0, int is_bss) { ns->ns_ifindex = ifindex; ns->ns_capinfo = ni->ni_capinfo; ns->ns_flags = (is_bss) ? IEEE80211_NODE_SYSCTL_F_BSS : 0; (void)memcpy(ns->ns_macaddr, ni->ni_macaddr, sizeof(ns->ns_macaddr)); (void)memcpy(ns->ns_bssid, ni->ni_bssid, sizeof(ns->ns_bssid)); if (ni->ni_chan != IEEE80211_CHAN_ANYC) { ns->ns_freq = ni->ni_chan->ic_freq; ns->ns_chanflags = ni->ni_chan->ic_flags; ns->ns_chanidx = ni->ni_chan - chan0; } else { ns->ns_freq = ns->ns_chanflags = 0; ns->ns_chanidx = 0; } ns->ns_rssi = ni->ni_rssi; ns->ns_esslen = ni->ni_esslen; (void)memcpy(ns->ns_essid, ni->ni_essid, sizeof(ns->ns_essid)); ns->ns_pwrsave = ni->ni_pwrsave; ns->ns_erp = ni->ni_erp; ns->ns_associd = ni->ni_associd; ns->ns_inact = ni->ni_inact * IEEE80211_INACT_WAIT; ns->ns_rstamp = ni->ni_rstamp; ns->ns_rates = ni->ni_rates; ns->ns_txrate = ni->ni_txrate; ns->ns_intval = ni->ni_intval; (void)memcpy(ns->ns_tstamp, ni->ni_tstamp, sizeof(ns->ns_tstamp)); ns->ns_txseq = ni->ni_txseq; ns->ns_rxseq = ni->ni_rxseq; ns->ns_fhdwell = ni->ni_fhdwell; ns->ns_fhindex = ni->ni_fhindex; ns->ns_fails = ni->ni_fails; } /* Between two examinations of the sysctl tree, I expect each * interface to add no more than 5 nodes. */ #define IEEE80211_SYSCTL_NODE_GROWTH 5 static int sysctl_ieee80211_node(SYSCTLFN_ARGS) { struct ieee80211_node_walk nw; struct ieee80211_node *ni; struct ieee80211_node_sysctl ns; char *dp; u_int cur_ifindex, ifcount, ifindex, last_ifindex, op, arg, hdr_type; size_t len, needed, eltsize, out_size; int error, s, nelt; if (namelen == 1 && name[0] == CTL_QUERY) return (sysctl_query(SYSCTLFN_CALL(rnode))); if (namelen != IEEE80211_SYSCTL_NODENAMELEN) return (EINVAL); /* ifindex.op.arg.header-type.eltsize.nelt */ dp = oldp; len = (oldp != NULL) ? *oldlenp : 0; ifindex = name[IEEE80211_SYSCTL_NODENAME_IF]; op = name[IEEE80211_SYSCTL_NODENAME_OP]; arg = name[IEEE80211_SYSCTL_NODENAME_ARG]; hdr_type = name[IEEE80211_SYSCTL_NODENAME_TYPE]; eltsize = name[IEEE80211_SYSCTL_NODENAME_ELTSIZE]; nelt = name[IEEE80211_SYSCTL_NODENAME_ELTCOUNT]; out_size = MIN(sizeof(ns), eltsize); if (op != IEEE80211_SYSCTL_OP_ALL || arg != 0 || hdr_type != IEEE80211_SYSCTL_T_NODE || eltsize < 1 || nelt < 0) return (EINVAL); error = 0; needed = 0; ifcount = 0; last_ifindex = 0; s = splnet(); for (ni = ieee80211_node_walkfirst(&nw, ifindex); ni != NULL; ni = ieee80211_node_walknext(&nw)) { struct ieee80211com *ic; ic = nw.nw_ic; cur_ifindex = ic->ic_if.if_index; if (cur_ifindex != last_ifindex) { ifcount++; last_ifindex = cur_ifindex; } if (nelt <= 0) continue; if (len >= eltsize) { sysctl_ieee80211_fill_node(ni, &ns, cur_ifindex, &ic->ic_channels[0], ni == ic->ic_bss); error = copyout(&ns, dp, out_size); if (error) goto cleanup; dp += eltsize; len -= eltsize; } needed += eltsize; if (nelt != INT_MAX) nelt--; } cleanup: splx(s); *oldlenp = needed; if (oldp == NULL) *oldlenp += ifcount * IEEE80211_SYSCTL_NODE_GROWTH * eltsize; return (error); } /* * Setup sysctl(3) MIB, net.ieee80211.* * * TBD condition CTLFLAG_PERMANENT on being an LKM or not */ SYSCTL_SETUP(sysctl_ieee80211, "sysctl ieee80211 subtree setup") { int rc; struct sysctlnode *cnode, *rnode; if ((rc = sysctl_createv(clog, 0, NULL, &rnode, CTLFLAG_PERMANENT, CTLTYPE_NODE, "net", NULL, NULL, 0, NULL, 0, CTL_NET, CTL_EOL)) != 0) goto err; if ((rc = sysctl_createv(clog, 0, &rnode, &rnode, CTLFLAG_PERMANENT, CTLTYPE_NODE, "link", "link-layer statistics and controls", NULL, 0, NULL, 0, PF_LINK, CTL_EOL)) != 0) goto err; if ((rc = sysctl_createv(clog, 0, &rnode, &rnode, CTLFLAG_PERMANENT, CTLTYPE_NODE, "ieee80211", "IEEE 802.11 WLAN statistics and controls", NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) goto err; if ((rc = sysctl_createv(clog, 0, &rnode, NULL, CTLFLAG_PERMANENT, CTLTYPE_NODE, "nodes", "client/peer stations", sysctl_ieee80211_node, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) goto err; #ifdef IEEE80211_DEBUG /* control debugging printfs */ if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "debug", SYSCTL_DESCR("Enable IEEE 802.11 debugging output"), sysctl_ieee80211_verify, 0, &ieee80211_debug, 0, CTL_CREATE, CTL_EOL)) != 0) goto err; ieee80211_debug_nodenum = cnode->sysctl_num; #endif /* IEEE80211_DEBUG */ /* control inactivity timer */ if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "maxinact", SYSCTL_DESCR("Station inactivity timeout"), sysctl_ieee80211_verify, 0, &ieee80211_inact_max, 0, CTL_CREATE, CTL_EOL)) != 0) goto err; ieee80211_inact_max_nodenum = cnode->sysctl_num; return; err: printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); } #endif /* __NetBSD__ */ #ifdef __FreeBSD__ /* * Module glue. * * NB: the module name is "wlan" for compatibility with NetBSD. */ static int ieee80211_modevent(module_t mod, int type, void *unused) { switch (type) { case MOD_LOAD: if (bootverbose) printf("wlan: <802.11 Link Layer>\n"); return 0; case MOD_UNLOAD: return 0; } return EINVAL; } static moduledata_t ieee80211_mod = { "wlan", ieee80211_modevent, 0 }; DECLARE_MODULE(wlan, ieee80211_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); MODULE_VERSION(wlan, 1); MODULE_DEPEND(wlan, rc4, 1, 1, 1); MODULE_DEPEND(wlan, ether, 1, 1, 1); #endif @ 1.31.2.3 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.31.2.2 2004/08/12 11:42:20 skrll Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.31.2.2 2004/08/12 11:42:20 skrll Exp $"); d105 2 a106 2 int ieee80211_cache_size = IEEE80211_CACHE_SIZE; static int ieee80211_cache_size_nodenum; d640 2 d643 1 a643 1 if (ic->ic_mgt_timer != 0) a931 10 static void ieee80211_clean_all_nodes(int cache_size) { struct ieee80211com *ic; LIST_FOREACH(ic, &ieee80211com_head, ic_list) { ic->ic_max_nnodes = cache_size; ieee80211_clean_nodes(ic); } } d946 2 a947 2 if (node.sysctl_num == ieee80211_cache_size_nodenum) { if (t < 0) d949 1 a958 2 if (node.sysctl_num == ieee80211_cache_size_nodenum) ieee80211_clean_all_nodes(t); d1187 1 a1187 1 /* control LRU cache size */ d1190 2 a1191 2 "maxnodecache", SYSCTL_DESCR("Maximum station cache size"), sysctl_ieee80211_verify, 0, &ieee80211_cache_size, d1195 1 a1195 1 ieee80211_cache_size_nodenum = cnode->sysctl_num; @ 1.31.2.4 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.31.2.3 2004/09/18 14:54:39 skrll Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.31.2.3 2004/09/18 14:54:39 skrll Exp $"); @ 1.31.2.5 log @Fix the sync with head I botched. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.31.2.4 2004/09/21 13:36:55 skrll Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.31.2.4 2004/09/21 13:36:55 skrll Exp $"); @ 1.31.2.6 log @Sync with HEAD. Hi Perry! @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.31.2.5 2005/03/04 16:53:17 skrll Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.31.2.5 2005/03/04 16:53:17 skrll Exp $"); d49 2 a50 2 #include #include d66 1 a66 1 d85 1 a85 1 #include d325 1 a325 1 static const u_int mopts[] = { d979 1 a979 1 */ @ 1.31.2.7 log @Sync with HEAD. Here we go again... @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.31.2.6 2005/11/10 14:10:51 skrll Exp $ */ d4 1 a4 1 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.31.2.6 2005/11/10 14:10:51 skrll Exp $"); d49 3 a51 1 #include a52 1 d57 3 d63 4 d68 1 d71 3 d75 1 a77 1 #include d79 1 d85 4 a88 1 #include d91 16 d111 16 a126 1 const char *ieee80211_phymode_name[] = { d132 1 a132 2 "turboA", /* IEEE80211_MODE_TURBO_A */ "turboG", /* IEEE80211_MODE_TURBO_G */ a134 58 /* list of all instances */ SLIST_HEAD(ieee80211_list, ieee80211com); static struct ieee80211_list ieee80211_list = SLIST_HEAD_INITIALIZER(ieee80211_list); static u_int8_t ieee80211_vapmap[32]; /* enough for 256 */ static void ieee80211_add_vap(struct ieee80211com *ic) { #define N(a) (sizeof(a)/sizeof(a[0])) int i; int s; u_int8_t b; s = splnet(); ic->ic_vap = 0; for (i = 0; i < N(ieee80211_vapmap) && ieee80211_vapmap[i] == 0xff; i++) ic->ic_vap += NBBY; if (i == N(ieee80211_vapmap)) panic("vap table full"); for (b = ieee80211_vapmap[i]; b & 1; b >>= 1) ic->ic_vap++; setbit(ieee80211_vapmap, ic->ic_vap); SLIST_INSERT_HEAD(&ieee80211_list, ic, ic_next); splx(s); #undef N } static void ieee80211_remove_vap(struct ieee80211com *ic) { int s; s = splnet(); SLIST_REMOVE(&ieee80211_list, ic, ieee80211com, ic_next); IASSERT(ic->ic_vap < sizeof(ieee80211_vapmap)*NBBY, ("invalid vap id %d", ic->ic_vap)); IASSERT(isset(ieee80211_vapmap, ic->ic_vap), ("vap id %d not allocated", ic->ic_vap)); clrbit(ieee80211_vapmap, ic->ic_vap); splx(s); } /* * Default reset method for use with the ioctl support. This * method is invoked after any state change in the 802.11 * layer that should be propagated to the hardware but not * require re-initialization of the 802.11 state machine (e.g * rescanning for an ap). We always return ENETRESET which * should cause the driver to re-initialize the device. Drivers * can override this method to implement more optimized support. */ static int ieee80211_default_reset(struct ifnet *ifp) { return ENETRESET; } d136 1 a136 1 ieee80211_ifattach(struct ieee80211com *ic) d138 1 a138 1 struct ifnet *ifp = ic->ic_ifp; d147 1 a147 2 ieee80211_crypto_attach(ic); d182 1 a182 3 ic->ic_modecaps |= 1<ic_modecaps |= 1<ic_caps & IEEE80211_C_WME) ic->ic_flags |= IEEE80211_F_WME; #endif d194 1 a194 1 ic->ic_lintval = IEEE80211_BINTVAL_DEFAULT; a195 4 ic->ic_dtim_period = IEEE80211_DTIM_DEFAULT; IEEE80211_BEACON_LOCK_INIT(ic, "beacon"); ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; d199 1 a199 12 ieee80211_proto_attach(ic); ieee80211_add_vap(ic); ieee80211_sysctl_attach(ic); /* NB: requires ic_vap */ /* * Install a default reset method for the ioctl support. * The driver is expected to fill this in before calling us. */ if (ic->ic_reset == NULL) ic->ic_reset = ieee80211_default_reset; d203 1 a203 1 ieee80211_ifdetach(struct ieee80211com *ic) d205 1 a205 3 struct ifnet *ifp = ic->ic_ifp; ieee80211_remove_vap(ic); d207 2 a208 3 ieee80211_sysctl_detach(ic); ieee80211_proto_detach(ic); ieee80211_crypto_detach(ic); d211 5 a215 4 ifmedia_delete_instance(&ic->ic_media, IFM_INST_ANY); IEEE80211_BEACON_LOCK_DESTROY(ic); d259 1 a259 1 if_printf(ic->ic_ifp, "invalid channel freq %u flags %x\n", d263 1 a263 1 if_printf(ic->ic_ifp, "invalid channel (NULL)\n"); d300 1 a300 1 ieee80211_media_init(struct ieee80211com *ic, d306 1 a306 1 struct ifnet *ifp = ic->ic_ifp; a317 4 #ifdef IEEE80211_NO_HOSTAP ic->ic_caps &= ~IEEE80211_C_HOSTAP; #endif /* IEEE80211_NO_HOSTAP */ d325 1 a325 1 static const u_int mopts[] = { a331 1 IFM_IEEE80211_11G | IFM_IEEE80211_TURBO, d347 1 d354 3 d382 1 d402 1 a402 1 d405 1 a408 25 void ieee80211_announce(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; int i, mode, rate, mword; struct ieee80211_rateset *rs; for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) { if ((ic->ic_modecaps & (1<ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rate = rs->rs_rates[i]; mword = ieee80211_rate2media(ic, rate, mode); if (mword == 0) continue; printf("%s%d%sMbps", (i != 0 ? " " : ""), (rate & IEEE80211_RATE_VAL) / 2, ((rate & 0x1) != 0 ? ".5" : "")); } printf("\n"); } } a422 32 * Find an instance by it's mac address. */ struct ieee80211com * ieee80211_find_vap(const u_int8_t mac[IEEE80211_ADDR_LEN]) { int s; struct ieee80211com *ic; s = splnet(); SLIST_FOREACH(ic, &ieee80211_list, ic_next) if (IEEE80211_ADDR_EQ(mac, ic->ic_myaddr)) break; splx(s); return ic; } static struct ieee80211com * ieee80211_find_instance(struct ifnet *ifp) { int s; struct ieee80211com *ic; s = splnet(); /* XXX not right for multiple instances but works for now */ SLIST_FOREACH(ic, &ieee80211_list, ic_next) if (ic->ic_ifp == ifp) break; splx(s); return ic; } /* d428 1 a428 1 struct ieee80211com *ic; a433 5 ic = ieee80211_find_instance(ifp); if (!ic) { if_printf(ifp, "%s: no 802.11 instance!\n", __func__); return EINVAL; } d458 2 a459 2 * Turbo mode is an ``option''. * XXX does not apply to AUTO d462 1 a462 5 if (newphymode == IEEE80211_MODE_11A) newphymode = IEEE80211_MODE_TURBO_A; else if (newphymode == IEEE80211_MODE_11G) newphymode = IEEE80211_MODE_TURBO_G; else d464 1 a523 1 #ifndef IEEE80211_NO_HOSTAP a537 1 #endif /* !IEEE80211_NO_HOSTAP */ a572 7 /* * Yech, slot time may change depending on the * operating mode so reset it to be sure everything * is setup appropriately. */ ieee80211_reset_erp(ic); ieee80211_wme_initparams(ic); /* after opmode change */ d585 2 a586 2 struct ieee80211com *ic; struct ieee80211_rateset *rs; a587 5 ic = ieee80211_find_instance(ifp); if (!ic) { if_printf(ifp, "%s: no 802.11 instance!\n", __func__); return; } d592 1 a592 19 /* * Calculate a current rate if possible. */ if (ic->ic_fixed_rate != -1) { /* * A fixed rate is set, report that. */ rs = &ic->ic_sup_rates[ic->ic_curmode]; imr->ifm_active |= ieee80211_rate2media(ic, rs->rs_rates[ic->ic_fixed_rate], ic->ic_curmode); } else if (ic->ic_opmode == IEEE80211_M_STA) { /* * In station mode report the current transmit rate. */ rs = &ic->ic_bss->ni_rates; imr->ifm_active |= ieee80211_rate2media(ic, rs->rs_rates[ic->ic_bss->ni_txrate], ic->ic_curmode); } else imr->ifm_active |= IFM_AUTO; d595 4 d626 1 a626 1 case IEEE80211_MODE_TURBO_A: a629 4 case IEEE80211_MODE_TURBO_G: imr->ifm_active |= IFM_IEEE80211_11G | IFM_IEEE80211_TURBO; break; d634 20 a653 1 ieee80211_watchdog(struct ieee80211com *ic) d655 11 a665 2 struct ieee80211_node_table *nt; int need_inact_timer = 0; d667 9 a675 14 if (ic->ic_state != IEEE80211_S_INIT) { if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0) ieee80211_new_state(ic, IEEE80211_S_SCAN, 0); nt = &ic->ic_scan; if (nt->nt_inact_timer) { if (--nt->nt_inact_timer == 0) nt->nt_timeout(nt); need_inact_timer += nt->nt_inact_timer; } nt = &ic->ic_sta; if (nt->nt_inact_timer) { if (--nt->nt_inact_timer == 0) nt->nt_timeout(nt); need_inact_timer += nt->nt_inact_timer; a677 2 if (ic->ic_mgt_timer != 0 || need_inact_timer) ic->ic_ifp->if_timer = 1; d696 1 a696 2 IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO_A */ IEEE80211_CHAN_108G, /* IEEE80211_MODE_TURBO_G */ d705 2 a706 2 "%s: mode %u not supported (caps 0x%x)\n", __func__, mode, ic->ic_modecaps); d729 1 a729 1 "%s: no channels found for mode %u\n", __func__, mode); a766 6 /* * If the desired channel is set but no longer valid then reset it. */ if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_des_chan))) ic->ic_des_chan = IEEE80211_CHAN_ANYC; d769 8 a776 1 * Do mode-specific rate setup. d778 4 d783 4 a786 20 /* * Use a mixed 11b/11g rate set. */ ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], IEEE80211_MODE_11G); } else if (mode == IEEE80211_MODE_11B) { /* * Force pure 11b rate set. */ ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], IEEE80211_MODE_11B); } /* * Setup an initial rate set according to the * current/default channel selected above. This * will be changed when scanning but must exist * now so driver have a consistent state of ic_ibss_chan. */ if (ic->ic_bss) /* NB: can be called before lateattach */ ic->ic_bss->ni_rates = ic->ic_sup_rates[mode]; a788 3 ieee80211_reset_erp(ic); /* reset ERP state */ ieee80211_wme_initparams(ic); /* reset WME stat */ d795 4 a798 3 * caller can select a rate set. This is problematic for channels * where multiple operating modes are possible (e.g. 11g+11b). * In those cases we defer to the current operating mode when set. d803 13 a815 7 if (IEEE80211_IS_CHAN_5GHZ(chan)) { /* * This assumes all 11a turbo channels are also * usable withut turbo, which is currently true. */ if (ic->ic_curmode == IEEE80211_MODE_TURBO_A) return IEEE80211_MODE_TURBO_A; d817 1 a817 1 } else if (IEEE80211_IS_CHAN_FHSS(chan)) d819 1 a819 9 else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) { /* * This assumes all 11g channels are also usable * for 11b, which is currently true. */ if (ic->ic_curmode == IEEE80211_MODE_TURBO_G) return IEEE80211_MODE_TURBO_G; if (ic->ic_curmode == IEEE80211_MODE_11B) return IEEE80211_MODE_11B; d821 1 a821 1 } else d871 1 a871 1 case IEEE80211_MODE_TURBO_A: a888 1 case IEEE80211_MODE_TURBO_G: a908 1 2, /* IFM_IEEE80211_DS1 */ d912 1 d928 315 @ 1.31.2.8 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.31.2.7 2005/12/11 10:29:22 christos Exp $ */ d36 3 a38 4 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.22 2005/08/10 16:22:29 sam Exp $"); #endif #ifdef __NetBSD__ __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.31.2.7 2005/12/11 10:29:22 christos Exp $"); a153 4 #ifdef __NetBSD__ ieee80211_init(); #endif /* __NetBSD__ */ a197 4 if (ic->ic_curchan == NULL) { /* arbitrarily pick the first channel */ ic->ic_curchan = &ic->ic_channels[i]; } d213 3 a215 3 if (ic->ic_bintval == 0) ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; ic->ic_bmisstimeout = 7*ic->ic_bintval; /* default 7 beacons */ a218 2 if (ic->ic_lintval == 0) ic->ic_lintval = ic->ic_bintval; d710 1 a710 1 if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { @ 1.30 log @For interoperability with legacy equipment, do not enable short preamble by default. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.29 2004/07/30 04:29:52 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.29 2004/07/30 04:29:52 dyoung Exp $"); d661 1 a661 1 { 7, { 2, 4, 11, 22, 12, 24, 48 } },/* IEEE80211_MODE_11G */ @ 1.29 log @Change sysctl range-checking: net.link.ieee80211.debug values are now 0x0 -> 0xffffffff, not 0 -> 2. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.28 2004/07/23 10:15:13 mycroft Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.28 2004/07/23 10:15:13 mycroft Exp $"); d775 4 d780 1 d783 1 @ 1.28 log @Cleanup of ieee80211_node from madwifi: * Don't use ifp pointers; use ieee80211com. * Implement the locking macros that are used under FreeBSD and Linux. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.27 2004/07/23 09:22:15 mycroft Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.27 2004/07/23 09:22:15 mycroft Exp $"); d945 3 a947 3 } else if (node.sysctl_num == ieee80211_debug_nodenum) { if (t < 0 || t > 2) return (EINVAL); a948 1 } else @ 1.27 log @Changes from madwifi: Abstract some of the node management code into separate functions, and use them throughout, plugging memory leaks. Allocate the AID allocation map dynamically. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.26 2004/07/23 08:05:00 mycroft Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.26 2004/07/23 08:05:00 mycroft Exp $"); d198 1 a198 1 ieee80211_node_attach(ifp); d209 1 a209 1 ieee80211_node_detach(ifp); d316 1 a316 1 ieee80211_node_lateattach(ifp); @ 1.26 log @More diff reduction; mainly IEEE80211_DPRINTF() stuff. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.25 2004/07/23 06:44:55 mycroft Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.25 2004/07/23 06:44:55 mycroft Exp $"); d402 1 a402 1 d405 1 a405 4 if (ic->ic_max_aid == 0) ic->ic_max_aid = IEEE80211_AID_MAX; @ 1.25 log @Diff reduction vs. madwifi. Change the signature of IEEE80211_DPRINTF() so that it uses a bitmask, and convert some of the if_printf()s to IEEE80211_DPRINTF()s. XXX I'm using a global variable at the moment rather than per-interface. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.24 2004/07/23 05:33:41 mycroft Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.24 2004/07/23 05:33:41 mycroft Exp $"); d769 1 a769 1 ("Bad IBSS channel %u\n", d902 20 a921 24 int i; static const struct { int subtype; int rate; } ieeerates[] = { { IFM_AUTO, -1 }, { IFM_MANUAL, 0 }, { IFM_NONE, 0 }, { IFM_IEEE80211_FH1, 2 }, { IFM_IEEE80211_FH2, 4 }, { IFM_IEEE80211_DS1, 2 }, { IFM_IEEE80211_DS2, 4 }, { IFM_IEEE80211_DS5, 11 }, { IFM_IEEE80211_DS11, 22 }, { IFM_IEEE80211_DS22, 44 }, { IFM_IEEE80211_OFDM6, 12 }, { IFM_IEEE80211_OFDM9, 18 }, { IFM_IEEE80211_OFDM12, 24 }, { IFM_IEEE80211_OFDM18, 36 }, { IFM_IEEE80211_OFDM24, 48 }, { IFM_IEEE80211_OFDM36, 72 }, { IFM_IEEE80211_OFDM48, 96 }, { IFM_IEEE80211_OFDM54, 108 }, { IFM_IEEE80211_OFDM72, 144 }, d923 2 a924 5 for (i = 0; i < N(ieeerates); i++) { if (ieeerates[i].subtype == IFM_SUBTYPE(mword)) return ieeerates[i].rate; } return 0; @ 1.24 log @IEEE80211_MAX_AID has been renamed to IEEE80211_AID_MAX. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.23 2004/07/22 14:44:17 mycroft Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.23 2004/07/22 14:44:17 mycroft Exp $"); d709 2 a710 1 IEEE80211_DPRINTF(("%s: mode %u not supported (caps 0x%x)\n", d733 2 a734 2 IEEE80211_DPRINTF(("%s: no channels found for mode %u\n", __func__, mode)); a949 3 IEEE80211_DPRINTF(("%s: t = %d, nodenum = %d, rnodenum = %d\n", __func__, t, node.sysctl_num, rnode->sysctl_num)); d986 1 a986 4 IEEE80211_DPRINTF(("%s: visiting ic %p\n", __func__, ic)); if (if_index != 0 && ic->ic_if.if_index != if_index) { IEEE80211_DPRINTF(("%s: wrong ifindex, " "skipping ic %p\n", __func__, ic)); a987 1 } a991 2 IEEE80211_DPRINTF(("%s: ic %p ni %p\n", __func__, nw->nw_ic, nw->nw_ni)); a1021 3 IEEE80211_DPRINTF(("%s: ic %p bss %p ni %p\n", __func__, nw->nw_ic, nw->nw_ic->ic_bss, nw->nw_ni)); a1096 4 IEEE80211_DPRINTF(("%s: ifindex %u op %u arg %u hdr_type %u eltsize %u " "nelt %d out_size %u\n", __func__, ifindex, op, arg, hdr_type, eltsize, nelt, out_size)); a1114 3 IEEE80211_DPRINTF(("%s: visit ic %p idx %u\n", __func__, ic, cur_ifindex)); a1119 3 IEEE80211_DPRINTF(("%s: ni %p dp %p len %u nelt %d\n", __func__, ni, dp, len, nelt)); a1134 1 IEEE80211_DPRINTF(("%s: needed %u\n", __func__, needed)); a1135 1 IEEE80211_DPRINTF(("%s: %u interfaces\n", __func__, ifcount)); @ 1.23 log @The low-level drivers are not setting the "basic rate" bit in the rateset. Instead, change *_set11gbasicrate() to *_setbasicrates(), have it operate on all modes, and call it from *_ifattach(). Also, fix obvious bugs in it (it had an off-by-one error, at least). @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.22 2004/07/16 03:02:41 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.22 2004/07/16 03:02:41 dyoung Exp $"); d407 1 a407 1 ic->ic_max_aid = IEEE80211_MAX_AID; @ 1.22 log @Add sysctl access to 802.11 node tables, step #2. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.21 2004/07/16 02:54:05 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.21 2004/07/16 02:54:05 dyoung Exp $"); d111 1 a111 2 static void ieee80211_set11gbasicrates(struct ieee80211_rateset *, enum ieee80211_phymode); d190 1 a573 6 #ifdef notdef if (ic->ic_curmode == IEEE80211_MODE_11G) ieee80211_set11gbasicrates( &ic->ic_sup_rates[newphymode], IEEE80211_MODE_11B); #endif d658 1 a658 1 ieee80211_set11gbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode mode) d661 1 d663 1 a663 1 { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11B */ d665 1 a665 1 { 0 }, /* IEEE80211_MODE_FH */ d668 2 d672 10 a681 7 for (i = 0; i < rs->rs_nrates; i++) { rs->rs_rates[i] &= IEEE80211_RATE_VAL; for (j = 0; j < basic[mode].rs_nrates; j++) if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { rs->rs_rates[i] |= IEEE80211_RATE_BASIC; break; } d783 1 a783 3 ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], IEEE80211_MODE_11G); } else { a784 1 } @ 1.21 log @Straggler: *really* chain the ieee80211coms. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.20 2004/07/16 02:36:58 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.20 2004/07/16 02:36:58 dyoung Exp $"); d80 1 d114 13 d973 200 d1199 5 @ 1.20 log @Chain ieee80211coms together so that the 802.11 sysctls can walk them all to retrieve their node tables. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $"); d183 1 d196 1 @ 1.19 log @Add sysctl(9) descriptions for net.link and net.link.ieee80211. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.18 2004/06/06 05:44:25 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.18 2004/06/06 05:44:25 dyoung Exp $"); d107 3 @ 1.18 log @Fix a typo in some #ifdef notdef code. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.17 2004/06/06 05:43:17 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.17 2004/06/06 05:43:17 dyoung Exp $"); d969 2 a970 1 CTLFLAG_PERMANENT, CTLTYPE_NODE, "link", NULL, d975 2 a976 1 CTLFLAG_PERMANENT, CTLTYPE_NODE, "ieee80211", NULL, @ 1.17 log @Improve argument checking. Convert from seconds to some number of inactivity countdown intervals (currently these are 5 seconds). @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.16 2004/06/06 05:28:58 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.16 2004/06/06 05:28:58 dyoung Exp $"); d558 1 a558 1 &ic->ic_suprates[newphymode], @ 1.16 log @Fix for kern/25604: ifconfig wi0 media DS11 panics system. In ieee80211_chan2mode, do not dereference the marker for "any channel," IEEE80211_CHAN_ANYC. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.15 2004/05/25 04:33:59 atatat Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.15 2004/05/25 04:33:59 atatat Exp $"); d937 1 a937 1 if (t < 0) d939 1 @ 1.15 log @Sysctl descriptions under net subtree (net.key not done) @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.14 2004/05/09 09:00:05 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.14 2004/05/09 09:00:05 dyoung Exp $"); d789 2 a790 1 if (ic->ic_curmode != IEEE80211_MODE_AUTO) @ 1.14 log @Undo last: I committed the wrong file. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.12 2004/05/06 07:11:40 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.12 2004/05/06 07:11:40 dyoung Exp $"); d981 2 a982 1 "debug", NULL, sysctl_ieee80211_verify, 0, &ieee80211_debug, 0, d993 2 a994 1 "maxinact", NULL, sysctl_ieee80211_verify, 0, &ieee80211_inact_max, @ 1.13 log @In ieee80211_find_rxnode, when we "fake up" a node for an ad hoc peer, we have to copy the "master" rate table to the faked-up node's rate table, or else ath0 will complain, "ath0: bogus xmit rate 0x0". Thank you Konstantin KABASSANOV for reporting this problem. @ text @a79 1 #include a106 3 struct ieee80211com_head ieee80211com_head = LIST_HEAD_INITIALIZER(ieee80211com_head); a179 1 LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list); a191 1 LIST_REMOVE(ic, ic_list); a917 6 struct ieee80211_node_walk { struct ieee80211com *nw_ic; struct ieee80211_node *nw_ni; u_short nw_ifindex; }; d936 1 a936 1 if (t < 1) a937 1 t = roundup(t, IEEE80211_INACT_WAIT) / IEEE80211_INACT_WAIT; a950 177 static struct ieee80211_node * ieee80211_node_walkfirst(struct ieee80211_node_walk *nw, u_short if_index) { struct ieee80211com *ic; (void)memset(nw, 0, sizeof(*nw)); nw->nw_ifindex = if_index; LIST_FOREACH(ic, &ieee80211com_head, ic_list) { IEEE80211_DPRINTF(("%s: visiting ic %p\n", __func__, ic)); if (if_index != 0 && ic->ic_if.if_index != if_index) { IEEE80211_DPRINTF(("%s: wrong ifindex, " "skipping ic %p\n", __func__, ic)); continue; } nw->nw_ic = ic; nw->nw_ni = ic->ic_bss; } IEEE80211_DPRINTF(("%s: ic %p ni %p\n", __func__, nw->nw_ic, nw->nw_ni)); return nw->nw_ni; } static struct ieee80211_node * ieee80211_node_walknext(struct ieee80211_node_walk *nw) { KASSERT(nw->nw_ic != NULL && nw->nw_ni != NULL); if (nw->nw_ni == nw->nw_ic->ic_bss) nw->nw_ni = TAILQ_FIRST(&nw->nw_ic->ic_node); else nw->nw_ni = TAILQ_NEXT(nw->nw_ni, ni_list); while (nw->nw_ni == NULL) { if (nw->nw_ifindex != 0) return NULL; nw->nw_ic = LIST_NEXT(nw->nw_ic, ic_list); if (nw->nw_ic == NULL) return NULL; nw->nw_ni = TAILQ_FIRST(&nw->nw_ic->ic_node); } IEEE80211_DPRINTF(("%s: ic %p bss %p ni %p\n", __func__, nw->nw_ic, nw->nw_ic->ic_bss, nw->nw_ni)); return nw->nw_ni; } static void sysctl_ieee80211_fill_node(struct ieee80211_node *ni, struct ieee80211_node_sysctl *ns, int ifindex, struct ieee80211_channel *chan0) { ns->ns_ifindex = ifindex; ns->ns_capinfo = ni->ni_capinfo; (void)memcpy(ns->ns_macaddr, ni->ni_macaddr, sizeof(ns->ns_macaddr)); (void)memcpy(ns->ns_bssid, ni->ni_bssid, sizeof(ns->ns_bssid)); if (ni->ni_chan != IEEE80211_CHAN_ANYC) { ns->ns_freq = ni->ni_chan->ic_freq; ns->ns_chanflags = ni->ni_chan->ic_flags; ns->ns_chanidx = ni->ni_chan - chan0; } else { ns->ns_freq = ns->ns_chanflags = 0; ns->ns_chanidx = 0; } ns->ns_rssi = ni->ni_rssi; ns->ns_esslen = ni->ni_esslen; (void)memcpy(ns->ns_essid, ni->ni_essid, sizeof(ns->ns_essid)); ns->ns_pwrsave = ni->ni_pwrsave; ns->ns_erp = ni->ni_erp; ns->ns_associd = ni->ni_associd; ns->ns_inact = ni->ni_inact * IEEE80211_INACT_WAIT; ns->ns_rstamp = ni->ni_rstamp; ns->ns_rates = ni->ni_rates; ns->ns_txrate = ni->ni_txrate; ns->ns_intval = ni->ni_intval; (void)memcpy(ns->ns_tstamp, ni->ni_tstamp, sizeof(ns->ns_tstamp)); ns->ns_txseq = ni->ni_txseq; ns->ns_rxseq = ni->ni_rxseq; ns->ns_fhdwell = ni->ni_fhdwell; ns->ns_fhindex = ni->ni_fhindex; ns->ns_fails = ni->ni_fails; } #define IEEE80211_SYSCTL_NODE_GROWTH 10 static int sysctl_ieee80211_node(SYSCTLFN_ARGS) { struct ieee80211_node_walk nw; struct ieee80211_node *ni; struct ieee80211_node_sysctl ns; char *dp; u_int cur_ifindex, ifcount, ifindex, last_ifindex, op, arg, hdr_type; size_t len, needed, eltsize, out_size; int error, s, nelt; if (namelen == 1 && name[0] == CTL_QUERY) return (sysctl_query(SYSCTLFN_CALL(rnode))); if (namelen != IEEE80211_SYSCTL_NODENAMELEN) return (EINVAL); /* ifindex.op.arg.header.eltsize.nelt */ dp = oldp; len = (oldp != NULL) ? *oldlenp : 0; ifindex = name[IEEE80211_SYSCTL_NODENAME_IF]; op = name[IEEE80211_SYSCTL_NODENAME_OP]; arg = name[IEEE80211_SYSCTL_NODENAME_ARG]; hdr_type = name[IEEE80211_SYSCTL_NODENAME_TYPE]; eltsize = name[IEEE80211_SYSCTL_NODENAME_ELTSIZE]; nelt = name[IEEE80211_SYSCTL_NODENAME_ELTCOUNT]; out_size = MIN(sizeof(ns), eltsize); IEEE80211_DPRINTF(("%s: ifindex %u op %u arg %u hdr_type %u eltsize %u " "nelt %d out_size %u\n", __func__, ifindex, op, arg, hdr_type, eltsize, nelt, out_size)); if (op != IEEE80211_SYSCTL_OP_ALL || arg != 0 || hdr_type != IEEE80211_SYSCTL_T_NODE || eltsize < 1 || nelt < 0) return (EINVAL); error = 0; needed = 0; ifcount = 0; last_ifindex = 0; s = splnet(); for (ni = ieee80211_node_walkfirst(&nw, ifindex); ni != NULL; ni = ieee80211_node_walknext(&nw)) { struct ieee80211com *ic; ic = nw.nw_ic; cur_ifindex = ic->ic_if.if_index; IEEE80211_DPRINTF(("%s: visit ic %p idx %u\n", __func__, ic, cur_ifindex)); if (cur_ifindex != last_ifindex) { ifcount++; last_ifindex = cur_ifindex; } IEEE80211_DPRINTF(("%s: ni %p dp %p len %u nelt %d\n", __func__, ni, dp, len, nelt)); if (len >= eltsize && nelt > 0) { sysctl_ieee80211_fill_node(ni, &ns, cur_ifindex, &ic->ic_channels[0]); error = copyout(&ns, dp, out_size); if (error) goto cleanup; dp += eltsize; len -= eltsize; } if (nelt > 0) { needed += eltsize; if (nelt != INT_MAX) nelt--; } IEEE80211_DPRINTF(("%s: needed %u\n", __func__, needed)); } IEEE80211_DPRINTF(("%s: %u interfaces\n", __func__, ifcount)); cleanup: splx(s); *oldlenp = needed; if (oldp == NULL) *oldlenp += ifcount * IEEE80211_SYSCTL_NODE_GROWTH * eltsize; return (error); } a975 5 if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, CTLFLAG_PERMANENT, CTLTYPE_NODE, "nodes", NULL, sysctl_ieee80211_node, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) goto err; @ 1.12 log @Following Andrew Brown's suggestion, move net.ieee80211 to net.link.ieee80211. The convention is that nodes directly under net are protocol families (PF_*). Also, simplify the sysctl setup for net80211 and rssadapt, following another suggestion by Andrew. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.11 2004/05/06 03:07:10 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.11 2004/05/06 03:07:10 dyoung Exp $"); d80 1 d108 3 d184 1 d197 1 d924 6 d948 1 a948 1 if (t < 0) d950 1 d964 177 d1166 5 @ 1.11 log @Add a sysctl, net.ieee80211.debug, for turning debug messages on and off. Add a sysctl, net.ieee80211.maxinact, for adjusting the node time-out interval. After net.ieee80211.maxinact seconds of inactivity, an AP will purge a peer/client-record. Now the client has to reassociate. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.10 2004/04/30 23:58:05 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.10 2004/04/30 23:58:05 dyoung Exp $"); d958 2 a959 2 int rc, ieee80211_node_num; struct sysctlnode *node; d961 1 a961 1 if ((rc = sysctl_createv(clog, 0, NULL, NULL, d966 6 a971 1 if ((rc = sysctl_createv(clog, 0, NULL, &node, d973 1 a973 1 NULL, 0, NULL, 0, CTL_NET, CTL_CREATE, CTL_EOL)) != 0) a975 2 ieee80211_node_num = node->sysctl_num; d979 1 a979 1 if ((rc = sysctl_createv(clog, 0, NULL, &node, d982 1 a982 1 CTL_NET, ieee80211_node_num, CTL_CREATE, CTL_EOL)) != 0) d985 1 a985 1 ieee80211_debug_nodenum = node->sysctl_num; d990 1 a990 1 if ((rc = sysctl_createv(clog, 0, NULL, &node, d993 1 a993 1 0, CTL_NET, ieee80211_node_num, CTL_CREATE, CTL_EOL)) != 0) d996 1 a996 1 ieee80211_inact_max_nodenum = node->sysctl_num; @ 1.10 log @From FreeBSD. Change ieee80211_phymode_name from a subroutine back to an array. Rearrange ieee80211_setmode. Miscellaneous small changes to make our code and FreeBSD's agree. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.9 2004/01/13 23:37:29 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.9 2004/01/13 23:37:29 dyoung Exp $"); d94 4 d104 3 d917 84 @ 1.9 log @NetBSD's KASSERT takes just one argument while FreeBSD's takes two, so I have added IASSERT(cond, complaint) to the compatibility header file and s/KASSERT/IASSERT/'d. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.8 2003/12/14 09:56:53 dyoung Exp $ */ d36 1 a36 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.8 2003/09/14 22:32:18 sam Exp $"); d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.8 2003/12/14 09:56:53 dyoung Exp $"); d103 8 a110 21 static const char * ieee80211_phymode_name(enum ieee80211_phymode mode) { int i; struct { enum ieee80211_phymode mode; const char *name; } modenames[] = { { IEEE80211_MODE_AUTO, "auto" }, { IEEE80211_MODE_11A, "11a" }, { IEEE80211_MODE_11B, "11b" }, { IEEE80211_MODE_11G, "11g" }, { IEEE80211_MODE_FH, "FH" }, { IEEE80211_MODE_TURBO, "turbo" } }; for (i = 0; i < sizeof(modenames) / sizeof(modenames[0]); i++) { if (mode == modenames[i].mode) return modenames[i].name; } return ""; } d165 1 a168 1 ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ d321 1 a321 1 if_printf(ifp, "%s rates: ", ieee80211_phymode_name(mode)); d692 1 a692 1 IASSERT(mode < N(chanflags), ("Unexpected mode %u\n", mode)); a853 3 case IEEE80211_MODE_11G: mask |= IFM_IEEE80211_11G; break; d855 2 a856 2 switch (ic->ic_phytype) { case IEEE80211_T_FH: a858 7 case IEEE80211_T_DS: mask |= IFM_IEEE80211_11B; break; case IEEE80211_T_OFDM: case IEEE80211_T_TURBO: mask |= IFM_IEEE80211_11G; break; d860 5 d939 1 @ 1.9.2.1 log @Pull up revision 1.16 (requested by dyoung in ticket #449). Fix for kern/25604: ifconfig wi0 media DS11 panics system. In ieee80211_chan2mode, do not dereference the marker for "any channel," IEEE80211_CHAN_ANYC. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.9 2004/01/13 23:37:29 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.9 2004/01/13 23:37:29 dyoung Exp $"); d795 1 a795 2 if (ic->ic_curmode != IEEE80211_MODE_AUTO || chan == IEEE80211_CHAN_ANYC) @ 1.9.2.2 log @Pull up revision 1.23 (via patch, requested by mycroft in ticket #700): Many bug fixes and performance fixes for the wi(4) driver, as well as changes paving the way for further performance improvements. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.9.2.1 2004/06/07 06:36:41 jdc Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.9.2.1 2004/06/07 06:36:41 jdc Exp $"); d100 2 a101 1 static void ieee80211_setbasicrates(struct ieee80211com *); a178 1 ieee80211_setbasicrates(ic); d561 6 d651 1 a651 1 ieee80211_setbasicrates(struct ieee80211com *ic) a653 1 { 0 }, /* IEEE80211_MODE_AUTO */ d655 1 a655 1 { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */ d657 1 a657 1 { 2, { 2, 4 } }, /* IEEE80211_MODE_FH */ a659 2 enum ieee80211_phymode mode; struct ieee80211_rateset *rs; d662 7 a668 10 for (mode = 0; mode < IEEE80211_MODE_MAX; mode++) { rs = &ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rs->rs_rates[i] &= IEEE80211_RATE_VAL; for (j = 0; j < basic[mode].rs_nrates; j++) if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { rs->rs_rates[i] |= IEEE80211_RATE_BASIC; break; } } d770 3 a772 1 } else d774 1 @ 1.8 log @Synchronize with FreeBSD sources from 12 Dec 2003. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.7 2003/10/16 22:25:00 matt Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.7 2003/10/16 22:25:00 matt Exp $"); d705 1 a705 1 KASSERT(mode < N(chanflags), ("Unexpected mode %u\n", mode)); d752 1 a752 1 KASSERT(ic->ic_ibss_chan != NULL && @ 1.7 log @bpfattach/bpfdetach need to be protected with NBPFILTER > 0 @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.6 2003/10/14 23:13:44 dyoung Exp $ */ d36 1 a36 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.7 2003/08/13 22:09:44 sam Exp $"); d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.6 2003/10/14 23:13:44 dyoung Exp $"); d765 2 a769 2 if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) ic->ic_flags |= IEEE80211_F_SHPREAMBLE; d773 1 a773 1 ic->ic_flags &= ~(IEEE80211_F_SHSLOT | IEEE80211_F_SHPREAMBLE); @ 1.6 log @Do not index arrays using enum constants, since enums can be re-ordered and extended. Instead, use a switch-statement or a key->value table with appropriate bounds-checking. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.5 2003/10/13 04:28:35 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.5 2003/10/13 04:28:35 dyoung Exp $"); d46 1 d133 1 d136 1 d203 1 d205 1 @ 1.5 log @More changes to the new 802.11 layer: * Add Kevin Lahey's power-saving support from the old 802.11 layer * Support for frequency-hopping PHYs * Add support frequency-hopping PHY mode, IFM_IEEE80211_FH * Add channel flags for frequency-hopping * Add mode<->media mappings in for FH PHY in ieee80211_media2rate and ieee80211_rate2media * Stop using IFM_MAKEMODE macro since the mode constants (e.g., IFM_IEEE80211_11A) are pre-shifted in sys/net/if_media.h * Add some PLCP constants. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.4 2003/09/23 16:01:21 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.4 2003/09/23 16:01:21 dyoung Exp $"); d102 21 a122 8 static const char *ieee80211_phymode_name[] = { "auto", /* IEEE80211_MODE_AUTO */ "11a", /* IEEE80211_MODE_11A */ "11b", /* IEEE80211_MODE_11B */ "11g", /* IEEE80211_MODE_11G */ "FH", /* IEEE80211_MODE_FH */ "turbo", /* IEEE80211_MODE_TURBO */ }; d329 1 a329 1 if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]); @ 1.4 log @Put FreeBSDisms in #ifdef __FreeBSD__, and add the equivalent NetBSDisms. @ text @d1 1 a1 1 /* $NetBSD: ieee80211.c,v 1.3 2003/09/14 01:14:54 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.3 2003/09/14 01:14:54 dyoung Exp $"); d107 1 d153 2 d296 5 a300 4 IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_MAKEMODE(IFM_IEEE80211_11A) | IFM_IEEE80211_TURBO, d374 4 d420 3 d593 1 a593 1 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A); d596 1 a596 1 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11B); d599 4 a602 1 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11G); d605 1 a605 1 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A) d639 1 d669 1 d734 5 d767 2 d786 2 d806 27 a832 25 { 2 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS1 }, { 4 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS2 }, { 11 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS5 }, { 22 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS11 }, { 44 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS22 }, { 12 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM6 }, { 18 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM9 }, { 24 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM12 }, { 36 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM18 }, { 48 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM24 }, { 72 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM36 }, { 96 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM48 }, { 108 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM54 }, { 2 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS1 }, { 4 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS2 }, { 11 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS5 }, { 22 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS11 }, { 12 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM6 }, { 18 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM9 }, { 24 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM12 }, { 36 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM18 }, { 48 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM24 }, { 72 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM36 }, { 96 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM48 }, { 108 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM54 }, d841 1 a841 1 mask |= IFM_MAKEMODE(IFM_IEEE80211_11A); d844 7 a850 1 mask |= IFM_MAKEMODE(IFM_IEEE80211_11B); d853 11 a863 8 /* NB: ic may be NULL for some drivers */ if (ic && ic->ic_phytype == IEEE80211_T_FH) { /* must handle these specially */ switch (mask) { case 2: return IFM_IEEE80211_FH1; case 4: return IFM_IEEE80211_FH2; } return IFM_AUTO; a864 5 /* NB: hack, 11g matches both 11b+11a rates */ /* fall thru... */ case IEEE80211_MODE_11G: mask |= IFM_MAKEMODE(IFM_IEEE80211_11G); break; d877 24 a900 20 static const int ieeerates[] = { -1, /* IFM_AUTO */ 0, /* IFM_MANUAL */ 0, /* IFM_NONE */ 2, /* IFM_IEEE80211_FH1 */ 4, /* IFM_IEEE80211_FH2 */ 2, /* IFM_IEEE80211_DS1 */ 4, /* IFM_IEEE80211_DS2 */ 11, /* IFM_IEEE80211_DS5 */ 22, /* IFM_IEEE80211_DS11 */ 44, /* IFM_IEEE80211_DS22 */ 12, /* IFM_IEEE80211_OFDM6 */ 18, /* IFM_IEEE80211_OFDM9 */ 24, /* IFM_IEEE80211_OFDM12 */ 36, /* IFM_IEEE80211_OFDM18 */ 48, /* IFM_IEEE80211_OFDM24 */ 72, /* IFM_IEEE80211_OFDM36 */ 96, /* IFM_IEEE80211_OFDM48 */ 108, /* IFM_IEEE80211_OFDM54 */ 144, /* IFM_IEEE80211_OFDM72 */ d902 5 a906 2 return IFM_SUBTYPE(mword) < N(ieeerates) ? ieeerates[IFM_SUBTYPE(mword)] : 0; @ 1.3 log @Insert RCSIDs. @ text @d1 1 a1 1 /* $NetBSD$ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD$"); d56 1 d58 1 d72 2 d78 1 d84 1 d86 3 d93 1 d97 1 d179 1 d181 3 @ 1.2 log @First stab at producing a unified NetBSD/FreeBSD 802.11 layer, striving to keep the diffs short and simple. * Replace FreeBSDisms (e.g. struct arpcom) with conditionally-compiled NetBSDism (struct ethercom). * Add compatibility shims in ieee80211_compat.*: provide NetBSD with if_printf, for example. * Convert FreeBSD node mutex uses to generic node critical-section protection (ieee80211_node_critsect_begin, _end), replace FreeBSD atomic arithmetic with generic alternative, and implement generics in NetBSD * Provide NetBSD-style 802.11 ioctls * Style nits @ text @d1 1 d35 1 d37 3 @ 1.1 log @Initial revision @ text @d55 1 d57 1 d63 1 d65 1 d852 1 d881 1 @ 1.1.1.1 log @Pull in net80211/ from FreeBSD. This contains Sam Leffler's enhancements to the 802.11 layer, which are necessary for ath(4), the Atheros-chipset driver. @ text @@ 1.1.1.2 log @Import FreeBSD's net80211 of 12 Dec 2003 @ text @d34 1 a34 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.8 2003/09/14 22:32:18 sam Exp $"); a701 2 if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) ic->ic_flags |= IEEE80211_F_SHPREAMBLE; d705 2 d710 1 a710 1 ic->ic_flags &= ~IEEE80211_F_SHSLOT; @ 1.1.1.3 log @Import FreeBSD's net80211 of 28-apr-2004 @ text @d34 1 a34 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.11 2004/04/02 20:19:20 sam Exp $"); d87 1 a87 2 "FH", /* IEEE80211_MODE_FH */ "turbo", /* IEEE80211_MODE_TURBO */ a131 2 if (IEEE80211_IS_CHAN_FHSS(c)) ic->ic_modecaps |= 1<ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ d142 1 d269 4 a272 5 IFM_IEEE80211_11A, IFM_IEEE80211_11B, IFM_IEEE80211_11G, IFM_IEEE80211_FH, IFM_IEEE80211_11A | IFM_IEEE80211_TURBO, a387 3 case IFM_IEEE80211_FH: newphymode = IEEE80211_MODE_FH; break; d558 1 a558 1 imr->ifm_active |= IFM_IEEE80211_11A; d561 1 a561 1 imr->ifm_active |= IFM_IEEE80211_11B; d564 1 a564 4 imr->ifm_active |= IFM_IEEE80211_11G; break; case IEEE80211_MODE_FH: imr->ifm_active |= IFM_IEEE80211_FH; d567 1 a567 1 imr->ifm_active |= IFM_IEEE80211_11A a600 1 { 0 }, /* IEEE80211_MODE_FH */ a629 1 IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */ d647 1 a647 1 KASSERT(mode < N(chanflags), ("Unexpected mode %u", mode)); a738 2 else if (IEEE80211_IS_CHAN_FHSS(chan)) return IEEE80211_MODE_FH; d757 25 a781 27 { 2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 }, { 4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 }, { 2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 }, { 4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 }, { 11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 }, { 22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 }, { 44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 }, { 12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 }, { 18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 }, { 24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 }, { 36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 }, { 48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 }, { 72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 }, { 96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 }, { 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 }, { 2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 }, { 4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 }, { 11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 }, { 22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 }, { 12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 }, { 18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 }, { 24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 }, { 36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 }, { 48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 }, { 72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 }, { 96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 }, { 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 }, d790 1 a790 1 mask |= IFM_IEEE80211_11A; d793 1 a793 4 mask |= IFM_IEEE80211_11B; break; case IEEE80211_MODE_FH: mask |= IFM_IEEE80211_FH; d798 6 a803 2 mask |= IFM_IEEE80211_FH; break; d808 1 a808 1 mask |= IFM_IEEE80211_11G; a875 1 MODULE_DEPEND(wlan, ether, 1, 1, 1); @ 1.1.1.4 log @Import FreeBSD's net80211(9) of 2005-05-18 @ text @d3 1 a3 1 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting d34 1 a34 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.19 2005/01/27 17:39:17 sam Exp $"); d40 2 d44 2 a46 1 d48 6 d55 2 d58 1 d60 1 d62 1 d68 15 a82 1 const char *ieee80211_phymode_name[] = { d88 1 a88 2 "turboA", /* IEEE80211_MODE_TURBO_A */ "turboG", /* IEEE80211_MODE_TURBO_G */ a90 57 /* list of all instances */ SLIST_HEAD(ieee80211_list, ieee80211com); static struct ieee80211_list ieee80211_list = SLIST_HEAD_INITIALIZER(ieee80211_list); static u_int8_t ieee80211_vapmap[32]; /* enough for 256 */ static struct mtx ieee80211_vap_mtx; MTX_SYSINIT(ieee80211, &ieee80211_vap_mtx, "net80211 instances", MTX_DEF); static void ieee80211_add_vap(struct ieee80211com *ic) { #define N(a) (sizeof(a)/sizeof(a[0])) int i; u_int8_t b; mtx_lock(&ieee80211_vap_mtx); ic->ic_vap = 0; for (i = 0; i < N(ieee80211_vapmap) && ieee80211_vapmap[i] == 0xff; i++) ic->ic_vap += NBBY; if (i == N(ieee80211_vapmap)) panic("vap table full"); for (b = ieee80211_vapmap[i]; b & 1; b >>= 1) ic->ic_vap++; setbit(ieee80211_vapmap, ic->ic_vap); SLIST_INSERT_HEAD(&ieee80211_list, ic, ic_next); mtx_unlock(&ieee80211_vap_mtx); #undef N } static void ieee80211_remove_vap(struct ieee80211com *ic) { mtx_lock(&ieee80211_vap_mtx); SLIST_REMOVE(&ieee80211_list, ic, ieee80211com, ic_next); KASSERT(ic->ic_vap < sizeof(ieee80211_vapmap)*NBBY, ("invalid vap id %d", ic->ic_vap)); KASSERT(isset(ieee80211_vapmap, ic->ic_vap), ("vap id %d not allocated", ic->ic_vap)); clrbit(ieee80211_vapmap, ic->ic_vap); mtx_unlock(&ieee80211_vap_mtx); } /* * Default reset method for use with the ioctl support. This * method is invoked after any state change in the 802.11 * layer that should be propagated to the hardware but not * require re-initialization of the 802.11 state machine (e.g * rescanning for an ap). We always return ENETRESET which * should cause the driver to re-initialize the device. Drivers * can override this method to implement more optimized support. */ static int ieee80211_default_reset(struct ifnet *ifp) { return ENETRESET; } d92 1 a92 1 ieee80211_ifattach(struct ieee80211com *ic) d94 1 a94 1 struct ifnet *ifp = ic->ic_ifp; d101 1 a101 2 ieee80211_crypto_attach(ic); d136 1 a136 3 ic->ic_modecaps |= 1<ic_modecaps |= 1<ic_caps & IEEE80211_C_WME) ic->ic_flags |= IEEE80211_F_WME; #endif d147 1 a147 1 ic->ic_lintval = IEEE80211_BINTVAL_DEFAULT; a148 11 ic->ic_dtim_period = IEEE80211_DTIM_DEFAULT; IEEE80211_BEACON_LOCK_INIT(ic, "beacon"); ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; ieee80211_node_attach(ic); ieee80211_proto_attach(ic); ieee80211_add_vap(ic); ieee80211_sysctl_attach(ic); /* NB: requires ic_vap */ d150 2 a151 6 /* * Install a default reset method for the ioctl support. * The driver is expected to fill this in before calling us. */ if (ic->ic_reset == NULL) ic->ic_reset = ieee80211_default_reset; d155 1 a155 1 ieee80211_ifdetach(struct ieee80211com *ic) d157 1 a157 3 struct ifnet *ifp = ic->ic_ifp; ieee80211_remove_vap(ic); d159 3 a161 4 ieee80211_sysctl_detach(ic); ieee80211_proto_detach(ic); ieee80211_crypto_detach(ic); ieee80211_node_detach(ic); a162 3 IEEE80211_BEACON_LOCK_DESTROY(ic); d204 1 a204 1 if_printf(ic->ic_ifp, "invalid channel freq %u flags %x\n", d208 1 a208 1 if_printf(ic->ic_ifp, "invalid channel (NULL)\n"); d245 1 a245 1 ieee80211_media_init(struct ieee80211com *ic, d251 1 a251 1 struct ifnet *ifp = ic->ic_ifp; d261 1 a261 1 ieee80211_node_lateattach(ic); a276 1 IFM_IEEE80211_11G | IFM_IEEE80211_TURBO, d292 1 d299 3 d327 1 a352 25 void ieee80211_announce(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; int i, mode, rate, mword; struct ieee80211_rateset *rs; for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) { if ((ic->ic_modecaps & (1<ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rate = rs->rs_rates[i]; mword = ieee80211_rate2media(ic, rate, mode); if (mword == 0) continue; printf("%s%d%sMbps", (i != 0 ? " " : ""), (rate & IEEE80211_RATE_VAL) / 2, ((rate & 0x1) != 0 ? ".5" : "")); } printf("\n"); } } a366 28 * Find an instance by it's mac address. */ struct ieee80211com * ieee80211_find_vap(const u_int8_t mac[IEEE80211_ADDR_LEN]) { struct ieee80211com *ic; /* XXX lock */ SLIST_FOREACH(ic, &ieee80211_list, ic_next) if (IEEE80211_ADDR_EQ(mac, ic->ic_myaddr)) return ic; return NULL; } static struct ieee80211com * ieee80211_find_instance(struct ifnet *ifp) { struct ieee80211com *ic; /* XXX lock */ /* XXX not right for multiple instances but works for now */ SLIST_FOREACH(ic, &ieee80211_list, ic_next) if (ic->ic_ifp == ifp) return ic; return NULL; } /* d372 1 a372 1 struct ieee80211com *ic; a377 5 ic = ieee80211_find_instance(ifp); if (!ic) { if_printf(ifp, "%s: no 802.11 instance!\n", __func__); return EINVAL; } d402 2 a403 2 * Turbo mode is an ``option''. * XXX does not apply to AUTO d406 1 a406 5 if (newphymode == IEEE80211_MODE_11A) newphymode = IEEE80211_MODE_TURBO_A; else if (newphymode == IEEE80211_MODE_11G) newphymode = IEEE80211_MODE_TURBO_G; else d408 1 d515 6 a522 7 /* * Yech, slot time may change depending on the * operating mode so reset it to be sure everything * is setup appropriately. */ ieee80211_reset_erp(ic); ieee80211_wme_initparams(ic); /* after opmode change */ d535 2 a536 2 struct ieee80211com *ic; struct ieee80211_rateset *rs; a537 5 ic = ieee80211_find_instance(ifp); if (!ic) { if_printf(ifp, "%s: no 802.11 instance!\n", __func__); return; } d542 1 a542 19 /* * Calculate a current rate if possible. */ if (ic->ic_fixed_rate != -1) { /* * A fixed rate is set, report that. */ rs = &ic->ic_sup_rates[ic->ic_curmode]; imr->ifm_active |= ieee80211_rate2media(ic, rs->rs_rates[ic->ic_fixed_rate], ic->ic_curmode); } else if (ic->ic_opmode == IEEE80211_M_STA) { /* * In station mode report the current transmit rate. */ rs = &ic->ic_bss->ni_rates; imr->ifm_active |= ieee80211_rate2media(ic, rs->rs_rates[ic->ic_bss->ni_txrate], ic->ic_curmode); } else imr->ifm_active |= IFM_AUTO; d545 4 d576 1 a576 1 case IEEE80211_MODE_TURBO_A: a579 4 case IEEE80211_MODE_TURBO_G: imr->ifm_active |= IFM_IEEE80211_11G | IFM_IEEE80211_TURBO; break; d584 22 a605 1 ieee80211_watchdog(struct ieee80211com *ic) d607 8 a614 2 struct ieee80211_node_table *nt; int need_inact_timer = 0; d616 7 a622 15 if (ic->ic_state != IEEE80211_S_INIT) { if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0) ieee80211_new_state(ic, IEEE80211_S_SCAN, 0); nt = &ic->ic_scan; if (nt->nt_inact_timer) { if (--nt->nt_inact_timer == 0) nt->nt_timeout(nt); need_inact_timer += nt->nt_inact_timer; } nt = &ic->ic_sta; if (nt->nt_inact_timer) { if (--nt->nt_inact_timer == 0) nt->nt_timeout(nt); need_inact_timer += nt->nt_inact_timer; } a623 2 if (ic->ic_mgt_timer != 0 || need_inact_timer) ic->ic_ifp->if_timer = 1; d642 1 a642 2 IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO_A */ IEEE80211_CHAN_108G, /* IEEE80211_MODE_TURBO_G */ d650 2 a651 3 IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, "%s: mode %u not supported (caps 0x%x)\n", __func__, mode, ic->ic_modecaps); d673 2 a674 2 IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, "%s: no channels found for mode %u\n", __func__, mode); a705 5 KASSERT(ic->ic_ibss_chan != NULL && isset(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan)), ("Bad IBSS channel %u", ieee80211_chan2ieee(ic, ic->ic_ibss_chan))); a706 6 /* * If the desired channel is set but no longer valid then reset it. */ if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_des_chan))) ic->ic_des_chan = IEEE80211_CHAN_ANYC; d709 4 a712 1 * Do mode-specific rate setup. d714 2 d717 2 a718 3 /* * Use a mixed 11b/11g rate set. */ d721 2 a722 6 } else if (mode == IEEE80211_MODE_11B) { /* * Force pure 11b rate set. */ ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], IEEE80211_MODE_11B); a723 8 /* * Setup an initial rate set according to the * current/default channel selected above. This * will be changed when scanning but must exist * now so driver have a consistent state of ic_ibss_chan. */ if (ic->ic_bss) /* NB: can be called before lateattach */ ic->ic_bss->ni_rates = ic->ic_sup_rates[mode]; a725 3 ieee80211_reset_erp(ic); /* reset ERP state */ ieee80211_wme_initparams(ic); /* reset WME stat */ d732 2 a733 3 * caller can select a rate set. This is problematic for channels * where multiple operating modes are possible (e.g. 11g+11b). * In those cases we defer to the current operating mode when set. d738 12 a749 7 if (IEEE80211_IS_CHAN_5GHZ(chan)) { /* * This assumes all 11a turbo channels are also * usable withut turbo, which is currently true. */ if (ic->ic_curmode == IEEE80211_MODE_TURBO_A) return IEEE80211_MODE_TURBO_A; d751 1 a751 1 } else if (IEEE80211_IS_CHAN_FHSS(chan)) d753 1 a753 9 else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) { /* * This assumes all 11g channels are also usable * for 11b, which is currently true. */ if (ic->ic_curmode == IEEE80211_MODE_TURBO_G) return IEEE80211_MODE_TURBO_G; if (ic->ic_curmode == IEEE80211_MODE_11B) return IEEE80211_MODE_11B; d755 1 a755 1 } else d805 1 a805 1 case IEEE80211_MODE_TURBO_A: a822 1 case IEEE80211_MODE_TURBO_G: d862 30 @ 1.1.1.5 log @Import FreeBSD's net80211(9) of 1-nov-2005 @ text @d34 1 a34 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.22 2005/08/10 16:22:29 sam Exp $"); a169 4 if (ic->ic_curchan == NULL) { /* arbitrarily pick the first channel */ ic->ic_curchan = &ic->ic_channels[i]; } d185 3 a187 3 if (ic->ic_bintval == 0) ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; ic->ic_bmisstimeout = 7*ic->ic_bintval; /* default 7 beacons */ a190 2 if (ic->ic_lintval == 0) ic->ic_lintval = ic->ic_bintval; d668 1 a668 1 if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { @