head 1.67; access; symbols netbsd-10-0-RC6:1.67 netbsd-10-0-RC5:1.67 netbsd-10-0-RC4:1.67 netbsd-10-0-RC3:1.67 netbsd-10-0-RC2:1.67 thorpej-ifq:1.67.0.6 thorpej-ifq-base:1.67 thorpej-altq-separation:1.67.0.4 thorpej-altq-separation-base:1.67 netbsd-10-0-RC1:1.67 netbsd-10:1.67.0.2 netbsd-10-base:1.67 bouyer-sunxi-drm:1.66.0.8 bouyer-sunxi-drm-base:1.66 netbsd-9-3-RELEASE:1.64 thorpej-i2c-spi-conf2:1.66.0.6 thorpej-i2c-spi-conf2-base:1.66 thorpej-futex2:1.66.0.4 thorpej-futex2-base:1.66 thorpej-cfargs2:1.66.0.2 thorpej-cfargs2-base:1.66 cjep_sun2x-base1:1.65 cjep_sun2x:1.65.0.14 cjep_sun2x-base:1.65 cjep_staticlib_x-base1:1.65 netbsd-9-2-RELEASE:1.64 cjep_staticlib_x:1.65.0.12 cjep_staticlib_x-base:1.65 thorpej-i2c-spi-conf:1.65.0.10 thorpej-i2c-spi-conf-base:1.66 thorpej-cfargs:1.65.0.8 thorpej-cfargs-base:1.65 thorpej-futex:1.65.0.6 thorpej-futex-base:1.65 netbsd-9-1-RELEASE:1.64 bouyer-xenpvh-base2:1.65 phil-wifi-20200421:1.65 bouyer-xenpvh-base1:1.65 phil-wifi-20200411:1.65 bouyer-xenpvh:1.65.0.4 bouyer-xenpvh-base:1.65 is-mlppp:1.65.0.2 is-mlppp-base:1.65 phil-wifi-20200406:1.65 netbsd-8-2-RELEASE:1.58.8.1 ad-namecache-base3:1.65 netbsd-9-0-RELEASE:1.64 netbsd-9-0-RC2:1.64 ad-namecache-base2:1.64 ad-namecache-base1:1.64 ad-namecache:1.64.0.6 ad-namecache-base:1.64 netbsd-9-0-RC1:1.64 phil-wifi-20191119:1.64 netbsd-9:1.64.0.4 netbsd-9-base:1.64 phil-wifi-20190609:1.64 netbsd-8-1-RELEASE:1.58.8.1 netbsd-8-1-RC1:1.58.8.1 isaki-audio2:1.64.0.2 isaki-audio2-base:1.64 pgoyette-compat-merge-20190127:1.61.2.2 pgoyette-compat-20190127:1.64 pgoyette-compat-20190118:1.64 pgoyette-compat-1226:1.64 pgoyette-compat-1126:1.63 pgoyette-compat-1020:1.63 pgoyette-compat-0930:1.63 pgoyette-compat-0906:1.63 netbsd-7-2-RELEASE:1.51 pgoyette-compat-0728:1.63 netbsd-8-0-RELEASE:1.58.8.1 phil-wifi-freebsd-base:1.63.2.1 phil-wifi:1.63.0.2 phil-wifi-base:1.63 pgoyette-compat-0625:1.63 netbsd-8-0-RC2:1.58.8.1 pgoyette-compat-0521:1.63 pgoyette-compat-0502:1.61 pgoyette-compat-0422:1.61 netbsd-8-0-RC1:1.58.8.1 pgoyette-compat-0415:1.61 pgoyette-compat-0407:1.61 pgoyette-compat-0330:1.61 pgoyette-compat-0322:1.61 pgoyette-compat-0315:1.61 netbsd-7-1-2-RELEASE:1.51 pgoyette-compat:1.61.0.2 pgoyette-compat-base:1.61 netbsd-7-1-1-RELEASE:1.51 tls-maxphys-base-20171202:1.59 matt-nb8-mediatek:1.58.8.1.0.2 matt-nb8-mediatek-base:1.58.8.1 nick-nhusb-base-20170825:1.58 perseant-stdc-iso10646:1.58.0.10 perseant-stdc-iso10646-base:1.58 netbsd-8:1.58.0.8 netbsd-8-base:1.58 prg-localcount2-base3:1.58 prg-localcount2-base2:1.58 prg-localcount2-base1:1.58 prg-localcount2:1.58.0.6 prg-localcount2-base:1.58 pgoyette-localcount-20170426:1.58 bouyer-socketcan-base1:1.58 jdolecek-ncq:1.58.0.4 jdolecek-ncq-base:1.58 pgoyette-localcount-20170320:1.58 netbsd-7-1:1.51.0.28 netbsd-7-1-RELEASE:1.51 netbsd-7-1-RC2:1.51 nick-nhusb-base-20170204:1.58 netbsd-7-nhusb-base-20170116:1.51 bouyer-socketcan:1.58.0.2 bouyer-socketcan-base:1.58 pgoyette-localcount-20170107:1.58 netbsd-7-1-RC1:1.51 nick-nhusb-base-20161204:1.57 pgoyette-localcount-20161104:1.57 netbsd-7-0-2-RELEASE:1.51 nick-nhusb-base-20161004:1.57 localcount-20160914:1.57 netbsd-7-nhusb:1.51.0.26 netbsd-7-nhusb-base:1.51 pgoyette-localcount-20160806:1.57 pgoyette-localcount-20160726:1.57 pgoyette-localcount:1.57.0.2 pgoyette-localcount-base:1.57 nick-nhusb-base-20160907:1.57 nick-nhusb-base-20160529:1.54 netbsd-7-0-1-RELEASE:1.51 nick-nhusb-base-20160422:1.53 nick-nhusb-base-20160319:1.53 nick-nhusb-base-20151226:1.53 netbsd-7-0:1.51.0.24 netbsd-7-0-RELEASE:1.51 nick-nhusb-base-20150921:1.53 netbsd-7-0-RC3:1.51 netbsd-7-0-RC2:1.51 netbsd-7-0-RC1:1.51 nick-nhusb-base-20150606:1.52 nick-nhusb-base-20150406:1.52 nick-nhusb:1.52.0.2 nick-nhusb-base:1.52 netbsd-5-2-3-RELEASE:1.48 netbsd-5-1-5-RELEASE:1.48 netbsd-6-0-6-RELEASE:1.51 netbsd-6-1-5-RELEASE:1.51 netbsd-7:1.51.0.22 netbsd-7-base:1.51 yamt-pagecache-base9:1.51 yamt-pagecache-tag8:1.50.4.1 netbsd-6-1-4-RELEASE:1.51 netbsd-6-0-5-RELEASE:1.51 tls-earlyentropy:1.51.0.20 tls-earlyentropy-base:1.51 riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.51 riastradh-drm2-base3:1.51 netbsd-6-1-3-RELEASE:1.51 netbsd-6-0-4-RELEASE:1.51 netbsd-5-2-2-RELEASE:1.48 netbsd-5-1-4-RELEASE:1.48 netbsd-6-1-2-RELEASE:1.51 netbsd-6-0-3-RELEASE:1.51 netbsd-5-2-1-RELEASE:1.48 netbsd-5-1-3-RELEASE:1.48 rmind-smpnet-nbase:1.51 netbsd-6-1-1-RELEASE:1.51 riastradh-drm2-base2:1.51 riastradh-drm2-base1:1.51 riastradh-drm2:1.51.0.18 riastradh-drm2-base:1.51 rmind-smpnet:1.51.0.10 rmind-smpnet-base:1.51 netbsd-6-1:1.51.0.16 netbsd-6-0-2-RELEASE:1.51 netbsd-6-1-RELEASE:1.51 khorben-n900:1.51.0.14 netbsd-6-1-RC4:1.51 netbsd-6-1-RC3:1.51 agc-symver:1.51.0.12 agc-symver-base:1.51 netbsd-6-1-RC2:1.51 netbsd-6-1-RC1:1.51 yamt-pagecache-base8:1.51 netbsd-5-2:1.48.0.20 netbsd-6-0-1-RELEASE:1.51 yamt-pagecache-base7:1.51 netbsd-5-2-RELEASE:1.48 netbsd-5-2-RC1:1.48 matt-nb6-plus-nbase:1.51 yamt-pagecache-base6:1.51 netbsd-6-0:1.51.0.8 netbsd-6-0-RELEASE:1.51 netbsd-6-0-RC2:1.51 tls-maxphys:1.51.0.6 tls-maxphys-base:1.51 matt-nb6-plus:1.51.0.4 matt-nb6-plus-base:1.51 netbsd-6-0-RC1:1.51 jmcneill-usbmp-base10:1.51 yamt-pagecache-base5:1.51 jmcneill-usbmp-base9:1.51 yamt-pagecache-base4:1.51 jmcneill-usbmp-base8:1.51 jmcneill-usbmp-base7:1.51 jmcneill-usbmp-base6:1.51 jmcneill-usbmp-base5:1.51 jmcneill-usbmp-base4:1.51 jmcneill-usbmp-base3:1.51 jmcneill-usbmp-pre-base2:1.50 jmcneill-usbmp-base2:1.51 netbsd-6:1.51.0.2 netbsd-6-base:1.51 netbsd-5-1-2-RELEASE:1.48 netbsd-5-1-1-RELEASE:1.48 jmcneill-usbmp:1.50.0.8 jmcneill-usbmp-base:1.50 jmcneill-audiomp3:1.50.0.6 jmcneill-audiomp3-base:1.50 yamt-pagecache-base3:1.50 yamt-pagecache-base2:1.50 yamt-pagecache:1.50.0.4 yamt-pagecache-base:1.50 rmind-uvmplock-nbase:1.50 cherry-xenmp:1.50.0.2 cherry-xenmp-base:1.50 bouyer-quota2-nbase:1.50 bouyer-quota2:1.49.0.8 bouyer-quota2-base:1.49 jruoho-x86intr:1.49.0.6 jruoho-x86intr-base:1.49 matt-mips64-premerge-20101231:1.49 matt-nb5-mips64-premerge-20101231:1.48 matt-nb5-pq3:1.48.0.18 matt-nb5-pq3-base:1.48 netbsd-5-1:1.48.0.16 netbsd-5-1-RELEASE:1.48 uebayasi-xip-base4:1.49 uebayasi-xip-base3:1.49 yamt-nfs-mp-base11:1.49 netbsd-5-1-RC4:1.48 matt-nb5-mips64-k15:1.48 uebayasi-xip-base2:1.49 yamt-nfs-mp-base10:1.49 netbsd-5-1-RC3:1.48 netbsd-5-1-RC2:1.48 uebayasi-xip-base1:1.49 netbsd-5-1-RC1:1.48 rmind-uvmplock:1.49.0.4 rmind-uvmplock-base:1.50 yamt-nfs-mp-base9:1.49 uebayasi-xip:1.49.0.2 uebayasi-xip-base:1.49 netbsd-5-0-2-RELEASE:1.48 matt-nb5-mips64-premerge-20091211:1.48 matt-premerge-20091211:1.48 yamt-nfs-mp-base8:1.48 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.48 matt-nb5-mips64:1.48.0.14 netbsd-5-0-1-RELEASE:1.48 jymxensuspend-base:1.48 yamt-nfs-mp-base6:1.48 yamt-nfs-mp-base5:1.48 yamt-nfs-mp-base4:1.48 jym-xensuspend-nbase:1.48 yamt-nfs-mp-base3:1.48 nick-hppapmap-base4:1.48 nick-hppapmap-base3:1.48 netbsd-5-0:1.48.0.12 netbsd-5-0-RELEASE:1.48 netbsd-5-0-RC4:1.48 netbsd-5-0-RC3:1.48 nick-hppapmap-base2:1.48 netbsd-5-0-RC2:1.48 jym-xensuspend:1.48.0.10 jym-xensuspend-base:1.48 netbsd-5-0-RC1:1.48 haad-dm-base2:1.48 haad-nbase2:1.48 ad-audiomp2:1.48.0.8 ad-audiomp2-base:1.48 netbsd-5:1.48.0.6 netbsd-5-base:1.48 nick-hppapmap:1.48.0.4 nick-hppapmap-base:1.48 matt-mips64-base2:1.48 matt-mips64:1.47.0.46 haad-dm-base1:1.48 wrstuden-revivesa-base-4:1.48 netbsd-4-0-1-RELEASE:1.45 wrstuden-revivesa-base-3:1.48 wrstuden-revivesa-base-2:1.48 wrstuden-fixsa-newbase:1.45 nick-csl-alignment-base5:1.47 haad-dm:1.48.0.2 haad-dm-base:1.48 wrstuden-revivesa-base-1:1.48 simonb-wapbl-nbase:1.48 yamt-pf42-base4:1.47 simonb-wapbl:1.47.0.44 simonb-wapbl-base:1.48 yamt-pf42-base3:1.47 hpcarm-cleanup-nbase:1.47 yamt-pf42-baseX:1.47 yamt-pf42-base2:1.47 yamt-nfs-mp-base2:1.47 wrstuden-revivesa:1.47.0.42 wrstuden-revivesa-base:1.48 yamt-nfs-mp:1.47.0.40 yamt-nfs-mp-base:1.47 yamt-pf42:1.47.0.38 yamt-pf42-base:1.47 ad-socklock-base1:1.47 yamt-lazymbuf-base15:1.47 yamt-lazymbuf-base14:1.47 keiichi-mipv6-nbase:1.47 mjf-devfs2:1.47.0.36 mjf-devfs2-base:1.48 nick-net80211-sync:1.47.0.34 nick-net80211-sync-base:1.47 keiichi-mipv6:1.47.0.32 keiichi-mipv6-base:1.47 bouyer-xeni386-merge1:1.47 matt-armv6-prevmlocking:1.47 wrstuden-fixsa-base-1:1.45 vmlocking2-base3:1.47 netbsd-4-0:1.45.0.8 netbsd-4-0-RELEASE:1.45 bouyer-xeni386-nbase:1.47 yamt-kmem-base3:1.47 cube-autoconf:1.47.0.30 cube-autoconf-base:1.47 yamt-kmem-base2:1.47 bouyer-xeni386:1.47.0.28 bouyer-xeni386-base:1.47 yamt-kmem:1.47.0.26 yamt-kmem-base:1.47 vmlocking2-base2:1.47 reinoud-bufcleanup-nbase:1.47 vmlocking2:1.47.0.24 vmlocking2-base1:1.47 netbsd-4-0-RC5:1.45 matt-nb4-arm:1.45.0.6 matt-nb4-arm-base:1.45 matt-armv6-nbase:1.47 jmcneill-base:1.47 netbsd-4-0-RC4:1.45 mjf-devfs:1.47.0.22 mjf-devfs-base:1.47 bouyer-xenamd64-base2:1.47 vmlocking-nbase:1.47 yamt-x86pmap-base4:1.47 bouyer-xenamd64:1.47.0.20 bouyer-xenamd64-base:1.47 netbsd-4-0-RC3:1.45 yamt-x86pmap-base3:1.47 yamt-x86pmap-base2:1.47 netbsd-4-0-RC2:1.45 yamt-x86pmap:1.47.0.18 yamt-x86pmap-base:1.47 netbsd-4-0-RC1:1.45 matt-armv6:1.47.0.16 matt-armv6-base:1.47 matt-mips64-base:1.47 jmcneill-pm:1.47.0.14 jmcneill-pm-base:1.47 hpcarm-cleanup:1.47.0.12 hpcarm-cleanup-base:1.47 nick-csl-alignment:1.47.0.10 nick-csl-alignment-base:1.47 netbsd-3-1-1-RELEASE:1.28 netbsd-3-0-3-RELEASE:1.28 yamt-idlelwp-base8:1.47 wrstuden-fixsa:1.45.0.4 wrstuden-fixsa-base:1.45 thorpej-atomic:1.47.0.8 thorpej-atomic-base:1.47 reinoud-bufcleanup:1.47.0.6 reinoud-bufcleanup-base:1.47 mjf-ufs-trans:1.47.0.4 mjf-ufs-trans-base:1.47 vmlocking:1.47.0.2 vmlocking-base:1.47 ad-audiomp:1.46.0.4 ad-audiomp-base:1.46 yamt-idlelwp:1.46.0.2 post-newlock2-merge:1.46 newlock2-nbase:1.46 yamt-splraiseipl-base5:1.45 yamt-splraiseipl-base4:1.45 yamt-splraiseipl-base3:1.45 abandoned-netbsd-4-base:1.43 abandoned-netbsd-4:1.43.0.12 netbsd-3-1:1.28.0.6 netbsd-3-1-RELEASE:1.28 netbsd-3-0-2-RELEASE:1.28 yamt-splraiseipl-base2:1.44 netbsd-3-1-RC4:1.28 yamt-splraiseipl:1.43.0.16 yamt-splraiseipl-base:1.43 netbsd-3-1-RC3:1.28 yamt-pdpolicy-base9:1.43 newlock2:1.43.0.14 newlock2-base:1.46 yamt-pdpolicy-base8:1.43 netbsd-3-1-RC2:1.28 netbsd-3-1-RC1:1.28 yamt-pdpolicy-base7:1.43 netbsd-4:1.45.0.2 netbsd-4-base:1.45 yamt-pdpolicy-base6:1.43 chap-midi-nbase:1.43 netbsd-3-0-1-RELEASE:1.28 gdamore-uart:1.43.0.10 gdamore-uart-base:1.43 simonb-timcounters-final:1.41.6.1 yamt-pdpolicy-base5:1.43 chap-midi:1.43.0.8 chap-midi-base:1.43 yamt-pdpolicy-base4:1.43 yamt-pdpolicy-base3:1.43 peter-altq-base:1.43 peter-altq:1.43.0.6 yamt-pdpolicy-base2:1.43 elad-kernelauth-base:1.43 elad-kernelauth:1.43.0.4 yamt-pdpolicy:1.43.0.2 yamt-pdpolicy-base:1.43 yamt-uio_vmspace-base5:1.43 simonb-timecounters:1.41.0.6 simonb-timecounters-base:1.43 rpaulo-netinet-merge-pcb:1.41.0.4 rpaulo-netinet-merge-pcb-base:1.43 yamt-uio_vmspace:1.41.0.2 netbsd-3-0:1.28.0.4 netbsd-3-0-RELEASE:1.28 netbsd-3-0-RC6:1.28 yamt-readahead-base3:1.39 netbsd-3-0-RC5:1.28 netbsd-3-0-RC4:1.28 netbsd-3-0-RC3:1.28 yamt-readahead-base2:1.39 netbsd-3-0-RC2:1.28 net80211-1-nov-2005:1.1.1.7 yamt-readahead-pervnode:1.38 yamt-readahead-perfile:1.38 yamt-readahead:1.38.0.6 yamt-readahead-base:1.38 netbsd-3-0-RC1:1.28 yamt-vop-base3:1.38 netbsd-2-0-3-RELEASE:1.11 netbsd-2-1:1.11.0.6 yamt-vop-base2:1.38 thorpej-vnode-attr:1.38.0.4 thorpej-vnode-attr-base:1.38 netbsd-2-1-RELEASE:1.11 yamt-vop:1.38.0.2 yamt-vop-base:1.38 netbsd-2-1-RC6:1.11 netbsd-2-1-RC5:1.11 netbsd-2-1-RC4:1.11 netbsd-2-1-RC3:1.11 netbsd-2-1-RC2:1.11 netbsd-2-1-RC1:1.11 net80211-2005-07-11:1.1.1.6 yamt-lazymbuf:1.32.0.2 net80211-2005-05-18:1.1.1.5 yamt-km-base4:1.28 netbsd-2-0-2-RELEASE:1.11 yamt-km-base3:1.28 netbsd-3:1.28.0.2 netbsd-3-base:1.28 yamt-km-base2:1.27 yamt-km:1.27.0.2 yamt-km-base:1.27 kent-audio2:1.26.0.2 kent-audio2-base:1.28 netbsd-2-0-1-RELEASE:1.11 kent-audio1-beforemerge:1.25 netbsd-2:1.11.0.4 netbsd-2-base:1.11 kent-audio1:1.17.0.2 kent-audio1-base:1.17 netbsd-2-0-RELEASE:1.11 netbsd-2-0-RC5:1.11 netbsd-2-0-RC4:1.11 netbsd-2-0-RC3:1.11 netbsd-2-0-RC2:1.11 netbsd-2-0-RC1:1.11 ktrace-lwp-base:1.40 ktrace-lwp:1.16.0.2 net80211-28-apr-2004:1.1.1.4 netbsd-2-0:1.11.0.2 netbsd-2-0-base:1.11 net80211-12-dec-2003:1.1.1.3 net80211-6-sep-2003:1.1.1.2 net80211-29-aug-2003:1.1.1.1 FreeBSD:1.1.1; locks; strict; comment @ * @; 1.67 date 2022.10.24.08.11.25; author msaitoh; state Exp; branches; next 1.66; commitid QakHRPKrm8gkHWYD; 1.66 date 2021.07.24.21.31.38; author andvar; state Exp; branches; next 1.65; commitid VtUn1ZIblDZfMh2D; 1.65 date 2020.02.29.16.56.58; author mlelstv; state Exp; branches 1.65.10.1; next 1.64; commitid 2X9NFMHGerTJIAYB; 1.64 date 2018.12.22.13.11.37; author maxv; state Exp; branches 1.64.6.1; next 1.63; commitid zynwY8DXvmslqN4B; 1.63 date 2018.05.08.07.02.07; author maxv; state Exp; branches 1.63.2.1; next 1.62; commitid pmxiza7E3y69IsBA; 1.62 date 2018.05.03.17.14.37; author maxv; state Exp; branches; next 1.61; commitid bELw1BYuZjKfgSAA; 1.61 date 2018.01.18.16.23.43; author maxv; state Exp; branches 1.61.2.1; next 1.60; commitid URO4miBuyxe3mnnA; 1.60 date 2018.01.18.13.24.01; author maxv; state Exp; branches; next 1.59; commitid 3ZtngU1dVp4kmmnA; 1.59 date 2017.09.26.07.42.06; author knakahara; state Exp; branches; next 1.58; commitid ZKzOBxwXvKWZ7G8A; 1.58 date 2017.01.04.03.05.24; author nonaka; state Exp; branches 1.58.8.1; next 1.57; 1.57 date 2016.07.07.06.55.43; author msaitoh; state Exp; branches 1.57.2.1; next 1.56; 1.56 date 2016.06.20.08.57.18; author ozaki-r; state Exp; branches; next 1.55; 1.55 date 2016.06.20.08.30.59; author knakahara; state Exp; branches; next 1.54; 1.54 date 2016.05.16.09.53.59; author ozaki-r; state Exp; branches; next 1.53; 1.53 date 2015.08.24.22.21.26; author pooka; state Exp; branches; next 1.52; 1.52 date 2014.10.18.08.33.29; author snj; state Exp; branches 1.52.2.1; next 1.51; 1.51 date 2011.12.31.20.41.58; author christos; state Exp; branches 1.51.6.1; next 1.50; 1.50 date 2011.02.21.23.50.08; author jmcneill; state Exp; branches 1.50.4.1 1.50.8.1; next 1.49; 1.49 date 2010.01.19.22.08.17; author pooka; state Exp; branches 1.49.4.1 1.49.6.1 1.49.8.1; next 1.48; 1.48 date 2008.06.19.23.13.10; author dyoung; state Exp; branches; next 1.47; 1.47 date 2007.03.04.06.03.19; author christos; state Exp; branches 1.47.34.1 1.47.36.1 1.47.40.1 1.47.42.1 1.47.44.1; next 1.46; 1.46 date 2007.01.06.06.02.33; author dyoung; state Exp; branches 1.46.2.1; next 1.45; 1.45 date 2006.11.16.01.33.41; author christos; state Exp; branches; next 1.44; 1.44 date 2006.10.12.01.32.31; author christos; state Exp; branches; next 1.43; 1.43 date 2006.02.19.07.52.43; author dyoung; state Exp; branches 1.43.14.1 1.43.16.1; next 1.42; 1.42 date 2006.02.19.07.49.28; author dyoung; state Exp; branches; next 1.41; 1.41 date 2005.12.29.21.08.26; author dyoung; state Exp; branches 1.41.2.1 1.41.4.1 1.41.6.1; next 1.40; 1.40 date 2005.12.11.00.55.42; author dyoung; state Exp; branches; next 1.39; 1.39 date 2005.11.18.16.40.09; author skrll; state Exp; branches; next 1.38; 1.38 date 2005.09.25.00.04.01; author dyoung; state Exp; branches 1.38.6.1; next 1.37; 1.37 date 2005.08.21.00.07.57; author dyoung; state Exp; branches; next 1.36; 1.36 date 2005.08.18.00.30.59; author yamt; state Exp; branches; next 1.35; 1.35 date 2005.08.16.02.12.58; author dyoung; state Exp; branches; next 1.34; 1.34 date 2005.08.15.21.33.26; author skrll; state Exp; branches; next 1.33; 1.33 date 2005.07.26.22.52.48; author dyoung; state Exp; branches; next 1.32; 1.32 date 2005.06.27.05.49.13; author dyoung; state Exp; branches 1.32.2.1; next 1.31; 1.31 date 2005.06.26.21.51.37; author erh; state Exp; branches; next 1.30; 1.30 date 2005.06.26.04.31.51; author dyoung; state Exp; branches; next 1.29; 1.29 date 2005.06.22.06.16.02; author dyoung; state Exp; branches; next 1.28; 1.28 date 2005.02.26.22.45.09; author perry; state Exp; branches; next 1.27; 1.27 date 2005.01.21.22.57.30; author dyoung; state Exp; branches 1.27.2.1; next 1.26; 1.26 date 2005.01.16.11.37.58; author dyoung; state Exp; branches 1.26.2.1; next 1.25; 1.25 date 2005.01.04.00.36.18; author dyoung; state Exp; branches; next 1.24; 1.24 date 2004.12.27.10.47.57; author dyoung; state Exp; branches; next 1.23; 1.23 date 2004.12.27.09.25.05; author dyoung; state Exp; branches; next 1.22; 1.22 date 2004.12.27.05.35.33; author mycroft; state Exp; branches; next 1.21; 1.21 date 2004.12.27.01.57.58; author mycroft; state Exp; branches; next 1.20; 1.20 date 2004.12.27.01.51.49; author mycroft; state Exp; branches; next 1.19; 1.19 date 2004.12.23.06.08.52; author dyoung; state Exp; branches; next 1.18; 1.18 date 2004.12.19.08.08.06; author dyoung; state Exp; branches; next 1.17; 1.17 date 2004.08.10.00.57.22; author dyoung; state Exp; branches; next 1.16; 1.16 date 2004.07.23.08.31.39; author mycroft; state Exp; branches 1.16.2.1; next 1.15; 1.15 date 2004.07.23.08.25.25; author mycroft; state Exp; branches; next 1.14; 1.14 date 2004.07.23.06.44.55; author mycroft; state Exp; branches; next 1.13; 1.13 date 2004.05.31.11.02.55; author dyoung; state Exp; branches; next 1.12; 1.12 date 2004.04.30.23.58.17; author dyoung; state Exp; branches; next 1.11; 1.11 date 2004.01.13.23.37.30; author dyoung; state Exp; branches; next 1.10; 1.10 date 2003.12.14.09.56.53; author dyoung; state Exp; branches; next 1.9; 1.9 date 2003.11.02.00.17.27; author dyoung; state Exp; branches; next 1.8; 1.8 date 2003.10.29.21.50.57; author dyoung; state Exp; branches; next 1.7; 1.7 date 2003.10.15.11.43.51; author dyoung; state Exp; branches; next 1.6; 1.6 date 2003.10.13.04.22.55; author dyoung; state Exp; branches; next 1.5; 1.5 date 2003.09.28.02.35.20; author dyoung; state Exp; branches; next 1.4; 1.4 date 2003.09.14.01.14.55; author dyoung; state Exp; branches; next 1.3; 1.3 date 2003.09.07.04.10.39; author dyoung; state Exp; branches; next 1.2; 1.2 date 2003.09.07.01.22.21; author dyoung; state Exp; branches; next 1.1; 1.1 date 2003.08.30.21.26.05; author dyoung; state Exp; branches 1.1.1.1; next ; 1.65.10.1 date 2021.08.01.22.42.41; author thorpej; state Exp; branches; next ; commitid NihqK3haIgTUWj3D; 1.64.6.1 date 2020.02.29.20.21.07; author ad; state Exp; branches; next ; commitid OjSb8ro7YQETQBYB; 1.63.2.1 date 2018.06.28.21.03.07; author phil; state Exp; branches; next 1.63.2.2; commitid fU5eenqZ23IoH5IA; 1.63.2.2 date 2018.07.12.16.35.34; author phil; state Exp; branches; next 1.63.2.3; commitid US0n8axK0fqSKRJA; 1.63.2.3 date 2018.07.16.20.11.11; author phil; state Exp; branches; next 1.63.2.4; commitid 57tT6pqTipGJQoKA; 1.63.2.4 date 2018.08.15.17.07.03; author phil; state Exp; branches; next 1.63.2.5; commitid xHTQHLRqLFKFReOA; 1.63.2.5 date 2019.06.10.22.09.46; author christos; state Exp; branches; next 1.63.2.6; commitid jtc8rnCzWiEEHGqB; 1.63.2.6 date 2020.04.13.08.05.16; author martin; state Exp; branches; next ; commitid X01YhRUPVUDaec4C; 1.61.2.1 date 2018.05.21.04.36.16; author pgoyette; state Exp; branches; next 1.61.2.2; commitid X5L8kSrBWQcDt7DA; 1.61.2.2 date 2018.12.26.14.02.05; author pgoyette; state Exp; branches; next ; commitid xUhK8IAeBM1azj5B; 1.58.8.1 date 2017.10.24.08.39.00; author snj; state Exp; branches; next ; commitid crgs94wfe9PZxhcA; 1.57.2.1 date 2017.01.07.08.56.51; author pgoyette; state Exp; branches; next ; 1.52.2.1 date 2015.09.22.12.06.11; author skrll; state Exp; branches; next 1.52.2.2; 1.52.2.2 date 2016.05.29.08.44.38; author skrll; state Exp; branches; next 1.52.2.3; 1.52.2.3 date 2016.07.09.20.25.21; author skrll; state Exp; branches; next 1.52.2.4; 1.52.2.4 date 2017.02.05.13.40.58; author skrll; state Exp; branches; next ; 1.51.6.1 date 2017.12.03.11.39.03; author jdolecek; state Exp; branches; next ; commitid XcIYRZTAh1LmerhA; 1.50.4.1 date 2012.04.17.00.08.39; author yamt; state Exp; branches; next ; 1.50.8.1 date 2012.02.18.07.35.38; author mrg; state Exp; branches; next ; 1.49.4.1 date 2011.03.05.20.55.56; author rmind; state Exp; branches; next ; 1.49.6.1 date 2011.06.06.09.09.54; author jruoho; state Exp; branches; next ; 1.49.8.1 date 2011.03.05.15.10.47; author bouyer; state Exp; branches; next ; 1.47.34.1 date 2008.02.22.16.50.25; author skrll; state Exp; branches; next ; 1.47.36.1 date 2008.06.29.09.33.19; author mjf; state Exp; branches; next ; 1.47.40.1 date 2009.05.04.08.14.16; author yamt; state Exp; branches; next 1.47.40.2; 1.47.40.2 date 2010.03.11.15.04.28; author yamt; state Exp; branches; next ; 1.47.42.1 date 2008.06.23.04.31.58; author wrstuden; state Exp; branches; next ; 1.47.44.1 date 2008.06.27.15.11.48; author simonb; state Exp; branches; next ; 1.46.2.1 date 2007.03.12.05.59.33; author rmind; state Exp; branches; next ; 1.43.14.1 date 2006.11.18.21.39.32; author ad; state Exp; branches; next 1.43.14.2; 1.43.14.2 date 2007.01.12.01.04.12; author ad; state Exp; branches; next ; 1.43.16.1 date 2006.10.22.06.07.28; author yamt; state Exp; branches; next 1.43.16.2; 1.43.16.2 date 2006.12.10.07.19.06; author yamt; state Exp; branches; next ; 1.41.2.1 date 2006.03.01.09.28.47; author yamt; state Exp; branches; next ; 1.41.4.1 date 2006.09.09.02.58.25; author rpaulo; state Exp; branches; next ; 1.41.6.1 date 2006.04.22.11.40.09; author simonb; state Exp; branches; next ; 1.38.6.1 date 2005.11.22.16.08.16; author yamt; state Exp; branches; next ; 1.32.2.1 date 2006.06.21.15.10.46; author yamt; state Exp; branches; next 1.32.2.2; 1.32.2.2 date 2006.12.30.20.50.28; author yamt; state Exp; branches; next 1.32.2.3; 1.32.2.3 date 2007.02.26.09.11.40; author yamt; state Exp; branches; next 1.32.2.4; 1.32.2.4 date 2007.09.03.14.42.29; author yamt; state Exp; branches; next ; 1.27.2.1 date 2005.03.19.08.36.35; author yamt; state Exp; branches; next ; 1.26.2.1 date 2005.01.16.11.37.58; author kent; state dead; branches; next 1.26.2.2; 1.26.2.2 date 2005.04.29.11.29.32; author kent; state Exp; branches; next ; 1.16.2.1 date 2004.07.23.08.31.39; author skrll; state dead; branches; next 1.16.2.2; 1.16.2.2 date 2004.08.03.10.54.21; author skrll; state Exp; branches; next 1.16.2.3; 1.16.2.3 date 2004.08.12.11.42.20; author skrll; state Exp; branches; next 1.16.2.4; 1.16.2.4 date 2004.09.18.14.54.39; author skrll; state Exp; branches; next 1.16.2.5; 1.16.2.5 date 2004.09.21.13.36.55; author skrll; state Exp; branches; next 1.16.2.6; 1.16.2.6 date 2005.01.17.19.32.39; author skrll; state Exp; branches; next 1.16.2.7; 1.16.2.7 date 2005.01.24.08.35.53; author skrll; state Exp; branches; next 1.16.2.8; 1.16.2.8 date 2005.03.04.16.53.17; author skrll; state Exp; branches; next 1.16.2.9; 1.16.2.9 date 2005.11.10.14.10.51; author skrll; state Exp; branches; next 1.16.2.10; 1.16.2.10 date 2005.12.11.10.29.22; author christos; state Exp; branches; next ; 1.1.1.1 date 2003.08.30.21.26.05; author dyoung; state Exp; branches; next 1.1.1.2; 1.1.1.2 date 2003.09.07.04.05.33; author dyoung; state Exp; branches; next 1.1.1.3; 1.1.1.3 date 2003.12.13.08.36.06; author dyoung; state Exp; branches; next 1.1.1.4; 1.1.1.4 date 2004.04.29.03.54.40; author dyoung; state Exp; branches; next 1.1.1.5; 1.1.1.5 date 2005.06.21.20.37.43; author dyoung; state Exp; branches; next 1.1.1.6; 1.1.1.6 date 2005.07.26.21.49.03; author dyoung; state Exp; branches; next 1.1.1.7; 1.1.1.7 date 2005.11.18.16.20.44; author skrll; state Exp; branches; next ; desc @@ 1.67 log @Make ifq_drops in struct ifqueue and struct ifaltq 64 bit. @ text @/* $NetBSD: ieee80211_output.c,v 1.66 2021/07/24 21:31:38 andvar 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_output.c,v 1.34 2005/08/10 16:22:29 sam Exp $"); #endif #ifdef __NetBSD__ __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.66 2021/07/24 21:31:38 andvar Exp $"); #endif #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 #include #include #include #endif static int ieee80211_fragment(struct ieee80211com *, struct mbuf *, u_int hdrsize, u_int ciphdrsize, u_int mtu); #ifdef IEEE80211_DEBUG /* * Decide if an outbound management frame should be * printed when debugging is enabled. This filters some * of the less interesting frames that come frequently * (e.g. beacons). */ static __inline int doprint(struct ieee80211com *ic, int subtype) { switch (subtype) { case IEEE80211_FC0_SUBTYPE_PROBE_RESP: return (ic->ic_opmode == IEEE80211_M_IBSS); } return 1; } #endif /* * Set the direction field and address fields of an outgoing * non-QoS frame. Note this should be called early on in * constructing a frame as it sets i_fc[1]; other bits can * then be or'd in. */ static void ieee80211_send_setup(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_frame *wh, int type, const u_int8_t sa[IEEE80211_ADDR_LEN], const u_int8_t da[IEEE80211_ADDR_LEN], const u_int8_t bssid[IEEE80211_ADDR_LEN]) { #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { switch (ic->ic_opmode) { case IEEE80211_M_STA: wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; IEEE80211_ADDR_COPY(wh->i_addr1, bssid); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, da); break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, bssid); break; case IEEE80211_M_HOSTAP: wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, bssid); IEEE80211_ADDR_COPY(wh->i_addr3, sa); break; case IEEE80211_M_MONITOR: /* NB: to quiet compiler */ break; } } else { wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, bssid); } *(u_int16_t *)&wh->i_dur[0] = 0; /* NB: use non-QoS tid */ *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; #undef WH4 } /* * Send a management frame to the specified node. The node pointer * must have a reference as the pointer will be passed to the driver * and potentially held for a long time. If the frame is successfully * dispatched to the driver, then it is responsible for freeing the * reference (and potentially free'ing up any associated storage). */ static int ieee80211_mgmt_output(struct ieee80211com *ic, struct ieee80211_node *ni, struct mbuf *m, int type, int timer) { struct ifnet *ifp = ic->ic_ifp; struct ieee80211_frame *wh; IASSERT(ni != NULL, ("null node")); /* * Yech, hack alert! We want to pass the node down to the * driver's start routine. If we don't do so then the start * routine must immediately look it up again and that can * cause a lock order reversal if, for example, this frame * is being sent because the station is being timedout and * the frame being sent is a DEAUTH message. We could stick * this in an m_tag and tack that on to the mbuf. However * that's rather expensive to do for every frame so instead * we stuff it in the rcvif field since outbound frames do * not (presently) use this. */ M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); if (m == NULL) return ENOMEM; M_SETCTX(m, ni); wh = mtod(m, struct ieee80211_frame *); ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_MGT | type, ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid); if ((m->m_flags & M_LINK0) != 0 && ni->ni_challenge != NULL) { m->m_flags &= ~M_LINK0; IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH, "[%s] encrypting frame (%s)\n", ether_sprintf(wh->i_addr1), __func__); wh->i_fc[1] |= IEEE80211_FC1_WEP; } #ifdef IEEE80211_DEBUG /* avoid printing too many frames */ if ((ieee80211_msg_debug(ic) && doprint(ic, type)) || ieee80211_msg_dumppkts(ic)) { printf("[%s] send %s on channel %u\n", ether_sprintf(wh->i_addr1), ieee80211_mgt_subtype_name[ (type & IEEE80211_FC0_SUBTYPE_MASK) >> IEEE80211_FC0_SUBTYPE_SHIFT], ieee80211_chan2ieee(ic, ic->ic_curchan)); } #endif IEEE80211_NODE_STAT(ni, tx_mgmt); IF_ENQUEUE(&ic->ic_mgtq, m); if (timer) { /* * Set the mgt frame timeout. */ ic->ic_mgt_timer = timer; ifp->if_timer = 1; } if_start_lock(ifp); return 0; } /* * Send a null data frame to the specified node. * * NB: the caller is assumed to have setup a node reference * for use; this is necessary to deal with a race condition * when probing for inactive stations. */ int ieee80211_send_nulldata(struct ieee80211_node *ni) { struct ieee80211com *ic = ni->ni_ic; struct ifnet *ifp = ic->ic_ifp; struct mbuf *m; struct ieee80211_frame *wh; MGETHDR(m, M_NOWAIT, MT_HEADER); if (m == NULL) { ic->ic_stats.is_tx_nobuf++; ieee80211_unref_node(&ni); return ENOMEM; } M_SETCTX(m, ni); wh = mtod(m, struct ieee80211_frame *); ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid); /* NB: power management bit is never sent by an AP */ if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && ic->ic_opmode != IEEE80211_M_HOSTAP) { wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; } m->m_len = m->m_pkthdr.len = sizeof(struct ieee80211_frame); IEEE80211_NODE_STAT(ni, tx_data); IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "[%s] send null data frame on channel %u, pwr mgt %s\n", ether_sprintf(ni->ni_macaddr), ieee80211_chan2ieee(ic, ic->ic_curchan), wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); IF_ENQUEUE(&ic->ic_mgtq, m); /* cheat */ if_start_lock(ifp); return 0; } /* * Assign priority to a frame based on any vlan tag assigned * to the station and/or any Diffserv setting in an IP header. * Finally, if an ACM policy is setup (in station mode) it's * applied. */ int ieee80211_classify(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni) { int v_wme_ac, d_wme_ac, ac; #ifdef INET struct ether_header *eh; #endif if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) { ac = WME_AC_BE; goto done; } /* * If node has a vlan tag then all traffic * to it must have a matching tag. */ v_wme_ac = 0; if (ni->ni_vlan != 0) { /* XXX used to check ec_nvlans. */ if (!vlan_has_tag(m)) { IEEE80211_NODE_STAT(ni, tx_novlantag); return 1; } if (EVL_VLANOFTAG(vlan_get_tag(m)) != EVL_VLANOFTAG(ni->ni_vlan)) { IEEE80211_NODE_STAT(ni, tx_vlanmismatch); return 1; } /* map vlan priority to AC */ switch (EVL_PRIOFTAG(ni->ni_vlan)) { case 1: case 2: v_wme_ac = WME_AC_BK; break; case 0: case 3: v_wme_ac = WME_AC_BE; break; case 4: case 5: v_wme_ac = WME_AC_VI; break; case 6: case 7: v_wme_ac = WME_AC_VO; break; } } #ifdef INET eh = mtod(m, struct ether_header *); if (eh->ether_type == htons(ETHERTYPE_IP)) { const struct ip *ip = (struct ip *) (mtod(m, u_int8_t *) + sizeof (*eh)); /* * IP frame, map the TOS field. */ switch (ip->ip_tos) { case 0x08: case 0x20: d_wme_ac = WME_AC_BK; /* background */ break; case 0x28: case 0xa0: d_wme_ac = WME_AC_VI; /* video */ break; case 0x30: /* voice */ case 0xe0: case 0x88: /* XXX UPSD */ case 0xb8: d_wme_ac = WME_AC_VO; break; default: d_wme_ac = WME_AC_BE; break; } } else { #endif /* INET */ d_wme_ac = WME_AC_BE; #ifdef INET } #endif /* * Use highest priority AC. */ if (v_wme_ac > d_wme_ac) ac = v_wme_ac; else ac = d_wme_ac; /* * Apply ACM policy. */ if (ic->ic_opmode == IEEE80211_M_STA) { static const int acmap[4] = { WME_AC_BK, /* WME_AC_BE */ WME_AC_BK, /* WME_AC_BK */ WME_AC_BE, /* WME_AC_VI */ WME_AC_VI, /* WME_AC_VO */ }; while (ac != WME_AC_BK && ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm) ac = acmap[ac]; } done: M_WME_SETAC(m, ac); return 0; } /* * Insure there is sufficient contiguous space to encapsulate the * 802.11 data frame. If room isn't already there, arrange for it. * Drivers and cipher modules assume we have done the necessary work * and fail rudely if they don't find the space they need. * * Basically, we are trying to make sure that the several M_PREPENDs * called after this function do not fail. */ static struct mbuf * ieee80211_mbuf_adjust(struct ieee80211com *ic, int hdrsize, struct ieee80211_key *key, struct mbuf *m) { #define TO_BE_RECLAIMED (sizeof(struct ether_header) - sizeof(struct llc)) int needed_space = hdrsize; int wlen = 0; if (key != NULL) { /* XXX belongs in crypto code? */ needed_space += key->wk_cipher->ic_header; /* XXX frags */ } /* * We know we are called just before stripping an Ethernet * header and prepending an LLC header. This means we know * there will be * sizeof(struct ether_header) - sizeof(struct llc) * bytes recovered to which we need additional space for the * 802.11 header and any crypto header. */ /* XXX check trailing space and copy instead? */ if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) { struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type); if (n == NULL) { ic->ic_stats.is_tx_nobuf++; m_freem(m); return NULL; } IASSERT(needed_space <= MHLEN, ("not enough room, need %u got %lu\n", needed_space, (u_long)MHLEN)); /* * Setup new mbuf to have leading space to prepend the * 802.11 header and any crypto header bits that are * required (the latter are added when the driver calls * back to ieee80211_crypto_encap to do crypto encapsulation). */ m_move_pkthdr(n, m); n->m_len = 0; n->m_data += needed_space; /* * Pull up Ethernet header to create the expected layout. * We could use m_pullup but that's overkill (i.e. we don't * need the actual data) and it cannot fail so do it inline * for speed. */ n->m_len += sizeof(struct ether_header); m->m_len -= sizeof(struct ether_header); m->m_data += sizeof(struct ether_header); /* * Replace the head of the chain. */ n->m_next = m; m = n; } else { /* * We will overwrite the ethernet header in the * 802.11 encapsulation stage. Make sure that it * is writable. */ wlen = sizeof(struct ether_header); } /* * If we're going to s/w encrypt the mbuf chain make sure it is * writable. */ if (key != NULL && (key->wk_flags & IEEE80211_KEY_SWCRYPT) != 0) { wlen = M_COPYALL; } if (wlen != 0 && m_makewritable(&m, 0, wlen, M_DONTWAIT) != 0) { m_freem(m); return NULL; } return m; #undef TO_BE_RECLAIMED } /* * Return the transmit key to use in sending a unicast frame. * If a unicast key is set we use that. When no unicast key is set * we fall back to the default transmit key. */ static __inline struct ieee80211_key * ieee80211_crypto_getucastkey(struct ieee80211com *ic, struct ieee80211_node *ni) { if (IEEE80211_KEY_UNDEFINED(ni->ni_ucastkey)) { if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE || IEEE80211_KEY_UNDEFINED(ic->ic_nw_keys[ic->ic_def_txkey])) return NULL; return &ic->ic_nw_keys[ic->ic_def_txkey]; } else { return &ni->ni_ucastkey; } } /* * Return the transmit key to use in sending a multicast frame. * Multicast traffic always uses the group key which is installed as * the default tx key. */ static __inline struct ieee80211_key * ieee80211_crypto_getmcastkey(struct ieee80211com *ic, struct ieee80211_node *ni) { if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE || IEEE80211_KEY_UNDEFINED(ic->ic_nw_keys[ic->ic_def_txkey])) return NULL; return &ic->ic_nw_keys[ic->ic_def_txkey]; } /* * Encapsulate an outbound data frame. The mbuf chain is updated. * If an error is encountered NULL is returned. The caller is required * to provide a node reference and pullup the ethernet header in the * first mbuf. */ struct mbuf * ieee80211_encap(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni) { struct ether_header eh; struct ieee80211_frame *wh; struct ieee80211_key *key; struct llc *llc; int hdrsize, datalen, addqos, txfrag; IASSERT(m->m_len >= sizeof(eh), ("no ethernet header!")); memcpy(&eh, mtod(m, void *), sizeof(struct ether_header)); /* * Insure space for additional headers. First identify * transmit key to use in calculating any buffer adjustments * required. This is also used below to do privacy * encapsulation work. Then calculate the 802.11 header * size and any padding required by the driver. * * Note key may be NULL if we fall back to the default * transmit key and that is not set. In that case the * buffer may not be expanded as needed by the cipher * routines, but they will/should discard it. */ if (ic->ic_flags & IEEE80211_F_PRIVACY) { if (ic->ic_opmode == IEEE80211_M_STA || !IEEE80211_IS_MULTICAST(eh.ether_dhost)) { key = ieee80211_crypto_getucastkey(ic, ni); } else { key = ieee80211_crypto_getmcastkey(ic, ni); } if (key == NULL && eh.ether_type != htons(ETHERTYPE_PAE)) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, "[%s] no default transmit key (%s) deftxkey %u\n", ether_sprintf(eh.ether_dhost), __func__, ic->ic_def_txkey); ic->ic_stats.is_tx_nodefkey++; } } else { key = NULL; } /* * XXX 4-address format. * * XXX Some ap's don't handle QoS-encapsulated EAPOL * frames so suppress use. This may be an issue if other * ap's require all data frames to be QoS-encapsulated * once negotiated in which case we'll need to make this * configurable. */ addqos = (ni->ni_flags & IEEE80211_NODE_QOS) && eh.ether_type != htons(ETHERTYPE_PAE); if (addqos) hdrsize = sizeof(struct ieee80211_qosframe); else hdrsize = sizeof(struct ieee80211_frame); if (ic->ic_flags & IEEE80211_F_DATAPAD) hdrsize = roundup(hdrsize, sizeof(u_int32_t)); m = ieee80211_mbuf_adjust(ic, hdrsize, key, m); if (m == NULL) { /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ goto bad; } /* NB: this could be optimized because of ieee80211_mbuf_adjust */ m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); llc = mtod(m, struct llc *); llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_control = LLC_UI; llc->llc_snap.org_code[0] = 0; llc->llc_snap.org_code[1] = 0; llc->llc_snap.org_code[2] = 0; llc->llc_snap.ether_type = eh.ether_type; datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */ M_PREPEND(m, hdrsize, M_DONTWAIT); if (m == NULL) { ic->ic_stats.is_tx_nobuf++; goto bad; } wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; *(u_int16_t *)wh->i_dur = 0; switch (ic->ic_opmode) { case IEEE80211_M_STA: wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); /* * NB: always use the bssid from ic_bss as the * neighbor's may be stale after an ibss merge */ IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid); break; case IEEE80211_M_HOSTAP: #ifndef IEEE80211_NO_HOSTAP wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); #endif break; case IEEE80211_M_MONITOR: goto bad; } if (m->m_flags & M_MORE_DATA) wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; if (addqos) { struct ieee80211_qosframe *qwh = (struct ieee80211_qosframe *)wh; int ac, tid; ac = M_WME_GETAC(m); /* map from access class/queue to 11e header priorty value */ tid = WME_AC_TO_TID(ac); qwh->i_qos[0] = tid & IEEE80211_QOS_TID; if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy) qwh->i_qos[0] |= 1 << IEEE80211_QOS_ACKPOLICY_S; qwh->i_qos[1] = 0; qwh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; *(u_int16_t *)wh->i_seq = htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[tid]++; } else { *(u_int16_t *)wh->i_seq = htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; } /* check if xmit fragmentation is required */ txfrag = (m->m_pkthdr.len > ic->ic_fragthreshold && !IEEE80211_IS_MULTICAST(wh->i_addr1) && (m->m_flags & M_FF) == 0); /* NB: don't fragment ff's */ if (key != NULL) { /* * IEEE 802.1X: send EAPOL frames always in the clear. * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. */ if (eh.ether_type != htons(ETHERTYPE_PAE) || ((ic->ic_flags & IEEE80211_F_WPA) && (ic->ic_opmode == IEEE80211_M_STA ? !IEEE80211_KEY_UNDEFINED(*key) : !IEEE80211_KEY_UNDEFINED(ni->ni_ucastkey)))) { wh->i_fc[1] |= IEEE80211_FC1_WEP; if (!ieee80211_crypto_enmic(ic, key, m, txfrag)) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, "[%s] enmic failed, discard frame\n", ether_sprintf(eh.ether_dhost)); ic->ic_stats.is_crypto_enmicfail++; goto bad; } } } if (txfrag && !ieee80211_fragment(ic, m, hdrsize, key != NULL ? key->wk_cipher->ic_header : 0, ic->ic_fragthreshold)) goto bad; IEEE80211_NODE_STAT(ni, tx_data); IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen); return m; bad: if (m != NULL) m_freem(m); return NULL; } /* * Arguments in: * * paylen: payload length (no FCS, no WEP header) * * hdrlen: header length * * rate: MSDU speed, units 500kb/s * * flags: IEEE80211_F_SHPREAMBLE (use short preamble), * IEEE80211_F_SHSLOT (use short slot length) * * Arguments out: * * d: 802.11 Duration field for RTS, * 802.11 Duration field for data frame, * PLCP Length for data frame, * residual octets at end of data slot */ static int ieee80211_compute_duration1(int len, int use_ack, uint32_t icflags, int rate, struct ieee80211_duration *d) { int pre, ctsrate; int ack, bitlen, data_dur, remainder; /* RTS reserves medium for SIFS | CTS | SIFS | (DATA) | SIFS | ACK * DATA reserves medium for SIFS | ACK, * * (XXX or SIFS | ACK | SIFS | DATA | SIFS | ACK, if more fragments) * * XXXMYC: no ACK on multicast/broadcast or control packets */ bitlen = len * 8; pre = IEEE80211_DUR_DS_SIFS; if ((icflags & IEEE80211_F_SHPREAMBLE) != 0) pre += IEEE80211_DUR_DS_SHORT_PREAMBLE + IEEE80211_DUR_DS_FAST_PLCPHDR; else pre += IEEE80211_DUR_DS_LONG_PREAMBLE + IEEE80211_DUR_DS_SLOW_PLCPHDR; d->d_residue = 0; data_dur = (bitlen * 2) / rate; remainder = (bitlen * 2) % rate; if (remainder != 0) { d->d_residue = (rate - remainder) / 16; data_dur++; } switch (rate) { case 2: /* 1 Mb/s */ case 4: /* 2 Mb/s */ /* 1 - 2 Mb/s WLAN: send ACK/CTS at 1 Mb/s */ ctsrate = 2; break; case 11: /* 5.5 Mb/s */ case 22: /* 11 Mb/s */ case 44: /* 22 Mb/s */ /* 5.5 - 11 Mb/s WLAN: send ACK/CTS at 2 Mb/s */ ctsrate = 4; break; default: /* TBD */ return -1; } d->d_plcp_len = data_dur; ack = (use_ack) ? pre + (IEEE80211_DUR_DS_SLOW_ACK * 2) / ctsrate : 0; d->d_rts_dur = pre + (IEEE80211_DUR_DS_SLOW_CTS * 2) / ctsrate + pre + data_dur + ack; d->d_data_dur = ack; return 0; } /* * Arguments in: * * wh: 802.11 header * * paylen: payload length (no FCS, no WEP header) * * rate: MSDU speed, units 500kb/s * * fraglen: fragment length, set to maximum (or higher) for no * fragmentation * * flags: IEEE80211_F_PRIVACY (hardware adds WEP), * IEEE80211_F_SHPREAMBLE (use short preamble), * IEEE80211_F_SHSLOT (use short slot length) * * Arguments out: * * d0: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields * of first/only fragment * * dn: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields * of last fragment * * ieee80211_compute_duration assumes crypto-encapsulation, if any, * has already taken place. */ int ieee80211_compute_duration(const struct ieee80211_frame_min *wh, const struct ieee80211_key *wk, int len, uint32_t icflags, int fraglen, int rate, struct ieee80211_duration *d0, struct ieee80211_duration *dn, int *npktp, int debug) { int ack, rc; int cryptolen, /* crypto overhead: header+trailer */ firstlen, /* first fragment's payload + overhead length */ hdrlen, /* header length w/o driver padding */ lastlen, /* last fragment's payload length w/ overhead */ lastlen0, /* last fragment's payload length w/o overhead */ npkt, /* number of fragments */ overlen, /* non-802.11 header overhead per fragment */ paylen; /* payload length w/o overhead */ hdrlen = ieee80211_anyhdrsize((const void *)wh); /* Account for padding required by the driver. */ if (icflags & IEEE80211_F_DATAPAD) { paylen = len - roundup(hdrlen, sizeof(u_int32_t)); if (paylen < 0) { panic("%s: paylen < 0", __func__); } } else { paylen = len - hdrlen; } overlen = IEEE80211_CRC_LEN; if (wk != NULL) { cryptolen = wk->wk_cipher->ic_header + wk->wk_cipher->ic_trailer; paylen -= cryptolen; overlen += cryptolen; } npkt = paylen / fraglen; lastlen0 = paylen % fraglen; if (npkt == 0) /* no fragments */ lastlen = paylen + overlen; else if (lastlen0 != 0) { /* a short "tail" fragment */ lastlen = lastlen0 + overlen; npkt++; } else /* full-length "tail" fragment */ lastlen = fraglen + overlen; if (npktp != NULL) *npktp = npkt; if (npkt > 1) firstlen = fraglen + overlen; else firstlen = paylen + overlen; if (debug) { printf("%s: npkt %d firstlen %d lastlen0 %d lastlen %d " "fraglen %d overlen %d len %d rate %d icflags %08x\n", __func__, npkt, firstlen, lastlen0, lastlen, fraglen, overlen, len, rate, icflags); } ack = !IEEE80211_IS_MULTICAST(wh->i_addr1) && (wh->i_fc[1] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL; rc = ieee80211_compute_duration1(firstlen + hdrlen, ack, icflags, rate, d0); if (rc == -1) return rc; if (npkt <= 1) { *dn = *d0; return 0; } return ieee80211_compute_duration1(lastlen + hdrlen, ack, icflags, rate, dn); } /* * Fragment the frame according to the specified mtu. * The size of the 802.11 header (w/o padding) is provided * so we don't need to recalculate it. We create a new * mbuf for each fragment and chain it through m_nextpkt; * we might be able to optimize this by reusing the original * packet's mbufs but that is significantly more complicated. */ static int ieee80211_fragment(struct ieee80211com *ic, struct mbuf *m0, u_int hdrsize, u_int ciphdrsize, u_int mtu) { struct ieee80211_frame *wh, *whf; struct mbuf *m, *prev, *next; const u_int totalhdrsize = hdrsize + ciphdrsize; u_int fragno, fragsize, off, remainder, payload; IASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?")); IASSERT(m0->m_pkthdr.len > mtu, ("pktlen %u mtu %u", m0->m_pkthdr.len, mtu)); wh = mtod(m0, struct ieee80211_frame *); /* NB: mark the first frag; it will be propagated below */ wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; fragno = 1; off = mtu - ciphdrsize; remainder = m0->m_pkthdr.len - off; prev = m0; do { fragsize = totalhdrsize + remainder; if (fragsize > mtu) fragsize = mtu; IASSERT(fragsize < MCLBYTES, ("fragment size %u too big!", fragsize)); if (fragsize > MHLEN) m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); else m = m_gethdr(M_DONTWAIT, MT_DATA); if (m == NULL) goto bad; /* leave room to prepend any cipher header */ m_align(m, fragsize - ciphdrsize); /* * Form the header in the fragment. Note that since * we mark the first fragment with the MORE_FRAG bit * it automatically is propagated to each fragment; we * need only clear it on the last fragment (done below). */ whf = mtod(m, struct ieee80211_frame *); memcpy(whf, wh, hdrsize); *(u_int16_t *)&whf->i_seq[0] |= htole16( (fragno & IEEE80211_SEQ_FRAG_MASK) << IEEE80211_SEQ_FRAG_SHIFT); fragno++; payload = fragsize - totalhdrsize; /* NB: destination is known to be contiguous */ m_copydata(m0, off, payload, mtod(m, u_int8_t *) + hdrsize); m->m_len = hdrsize + payload; m->m_pkthdr.len = hdrsize + payload; m->m_flags |= M_FRAG; /* chain up the fragment */ prev->m_nextpkt = m; prev = m; /* deduct fragment just formed */ remainder -= payload; off += payload; } while (remainder != 0); whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; /* strip first mbuf now that everything has been copied */ m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize))); m0->m_flags |= M_FIRSTFRAG | M_FRAG; ic->ic_stats.is_tx_fragframes++; ic->ic_stats.is_tx_frags += fragno-1; return 1; bad: /* reclaim fragments but leave original frame for caller to free */ for (m = m0->m_nextpkt; m != NULL; m = next) { next = m->m_nextpkt; m->m_nextpkt = NULL; m_freem(m); } m0->m_nextpkt = NULL; return 0; } /* * Add a supported rates element id to a frame. */ u_int8_t * ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *rs) { int nrates; *frm++ = IEEE80211_ELEMID_RATES; nrates = rs->rs_nrates; if (nrates > IEEE80211_RATE_SIZE) nrates = IEEE80211_RATE_SIZE; *frm++ = nrates; memcpy(frm, rs->rs_rates, nrates); return frm + nrates; } /* * Add an extended supported rates element id to a frame. */ u_int8_t * ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs) { /* * Add an extended supported rates element if operating in 11g mode. */ if (rs->rs_nrates > IEEE80211_RATE_SIZE) { int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; *frm++ = IEEE80211_ELEMID_XRATES; *frm++ = nrates; memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); frm += nrates; } return frm; } /* * Add an ssid elemet to a frame. */ u_int8_t * ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len) { *frm++ = IEEE80211_ELEMID_SSID; *frm++ = len; memcpy(frm, ssid, len); return frm + len; } /* * Add an erp element to a frame. */ static u_int8_t * ieee80211_add_erp(u_int8_t *frm, struct ieee80211com *ic) { u_int8_t erp; *frm++ = IEEE80211_ELEMID_ERP; *frm++ = 1; erp = 0; if (ic->ic_nonerpsta != 0) erp |= IEEE80211_ERP_NON_ERP_PRESENT; if (ic->ic_flags & IEEE80211_F_USEPROT) erp |= IEEE80211_ERP_USE_PROTECTION; if (ic->ic_flags & IEEE80211_F_USEBARKER) erp |= IEEE80211_ERP_LONG_PREAMBLE; *frm++ = erp; return frm; } static u_int8_t * ieee80211_setup_wpa_ie(struct ieee80211com *ic, u_int8_t *ie) { #define WPA_OUI_BYTES 0x00, 0x50, 0xf2 #define ADDSHORT(frm, v) do { \ frm[0] = (v) & 0xff; \ frm[1] = (v) >> 8; \ frm += 2; \ } while (0) #define ADDSELECTOR(frm, sel) do { \ memcpy(frm, sel, 4); \ frm += 4; \ } while (0) static const u_int8_t oui[4] = { WPA_OUI_BYTES, WPA_OUI_TYPE }; static const u_int8_t cipher_suite[][4] = { { WPA_OUI_BYTES, WPA_CSE_WEP40 }, /* NB: 40-bit */ { WPA_OUI_BYTES, WPA_CSE_TKIP }, { 0x00, 0x00, 0x00, 0x00 }, /* XXX WRAP */ { WPA_OUI_BYTES, WPA_CSE_CCMP }, { 0x00, 0x00, 0x00, 0x00 }, /* XXX CKIP */ { WPA_OUI_BYTES, WPA_CSE_NULL }, }; static const u_int8_t wep104_suite[4] = { WPA_OUI_BYTES, WPA_CSE_WEP104 }; static const u_int8_t key_mgt_unspec[4] = { WPA_OUI_BYTES, WPA_ASE_8021X_UNSPEC }; static const u_int8_t key_mgt_psk[4] = { WPA_OUI_BYTES, WPA_ASE_8021X_PSK }; const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn; u_int8_t *frm = ie; u_int8_t *selcnt; *frm++ = IEEE80211_ELEMID_VENDOR; *frm++ = 0; /* length filled in below */ memcpy(frm, oui, sizeof(oui)); /* WPA OUI */ frm += sizeof(oui); ADDSHORT(frm, WPA_VERSION); /* XXX filter out CKIP */ /* multicast cipher */ if (rsn->rsn_mcastcipher == IEEE80211_CIPHER_WEP && rsn->rsn_mcastkeylen >= 13) ADDSELECTOR(frm, wep104_suite); else ADDSELECTOR(frm, cipher_suite[rsn->rsn_mcastcipher]); /* unicast cipher list */ selcnt = frm; ADDSHORT(frm, 0); /* selector count */ if (rsn->rsn_ucastcipherset & (1 << IEEE80211_CIPHER_AES_CCM)) { selcnt[0]++; ADDSELECTOR(frm, cipher_suite[IEEE80211_CIPHER_AES_CCM]); } if (rsn->rsn_ucastcipherset & (1 << IEEE80211_CIPHER_TKIP)) { selcnt[0]++; ADDSELECTOR(frm, cipher_suite[IEEE80211_CIPHER_TKIP]); } /* authenticator selector list */ selcnt = frm; ADDSHORT(frm, 0); /* selector count */ if (rsn->rsn_keymgmtset & WPA_ASE_8021X_UNSPEC) { selcnt[0]++; ADDSELECTOR(frm, key_mgt_unspec); } if (rsn->rsn_keymgmtset & WPA_ASE_8021X_PSK) { selcnt[0]++; ADDSELECTOR(frm, key_mgt_psk); } /* optional capabilities */ if (rsn->rsn_caps != 0 && rsn->rsn_caps != RSN_CAP_PREAUTH) ADDSHORT(frm, rsn->rsn_caps); /* calculate element length */ ie[1] = frm - ie - 2; IASSERT(ie[1]+2 <= sizeof(struct ieee80211_ie_wpa), ("WPA IE too big, %u > %zu", ie[1]+2, sizeof(struct ieee80211_ie_wpa))); return frm; #undef ADDSHORT #undef ADDSELECTOR #undef WPA_OUI_BYTES } static u_int8_t * ieee80211_setup_rsn_ie(struct ieee80211com *ic, u_int8_t *ie) { #define RSN_OUI_BYTES 0x00, 0x0f, 0xac #define ADDSHORT(frm, v) do { \ frm[0] = (v) & 0xff; \ frm[1] = (v) >> 8; \ frm += 2; \ } while (0) #define ADDSELECTOR(frm, sel) do { \ memcpy(frm, sel, 4); \ frm += 4; \ } while (0) static const u_int8_t cipher_suite[][4] = { { RSN_OUI_BYTES, RSN_CSE_WEP40 }, /* NB: 40-bit */ { RSN_OUI_BYTES, RSN_CSE_TKIP }, { RSN_OUI_BYTES, RSN_CSE_WRAP }, { RSN_OUI_BYTES, RSN_CSE_CCMP }, { 0x00, 0x00, 0x00, 0x00 }, /* XXX CKIP */ { RSN_OUI_BYTES, RSN_CSE_NULL }, }; static const u_int8_t wep104_suite[4] = { RSN_OUI_BYTES, RSN_CSE_WEP104 }; static const u_int8_t key_mgt_unspec[4] = { RSN_OUI_BYTES, RSN_ASE_8021X_UNSPEC }; static const u_int8_t key_mgt_psk[4] = { RSN_OUI_BYTES, RSN_ASE_8021X_PSK }; const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn; u_int8_t *frm = ie; u_int8_t *selcnt; *frm++ = IEEE80211_ELEMID_RSN; *frm++ = 0; /* length filled in below */ ADDSHORT(frm, RSN_VERSION); /* XXX filter out CKIP */ /* multicast cipher */ if (rsn->rsn_mcastcipher == IEEE80211_CIPHER_WEP && rsn->rsn_mcastkeylen >= 13) ADDSELECTOR(frm, wep104_suite); else ADDSELECTOR(frm, cipher_suite[rsn->rsn_mcastcipher]); /* unicast cipher list */ selcnt = frm; ADDSHORT(frm, 0); /* selector count */ if (rsn->rsn_ucastcipherset & (1 << IEEE80211_CIPHER_AES_CCM)) { selcnt[0]++; ADDSELECTOR(frm, cipher_suite[IEEE80211_CIPHER_AES_CCM]); } if (rsn->rsn_ucastcipherset & (1 << IEEE80211_CIPHER_TKIP)) { selcnt[0]++; ADDSELECTOR(frm, cipher_suite[IEEE80211_CIPHER_TKIP]); } /* authenticator selector list */ selcnt = frm; ADDSHORT(frm, 0); /* selector count */ if (rsn->rsn_keymgmtset & WPA_ASE_8021X_UNSPEC) { selcnt[0]++; ADDSELECTOR(frm, key_mgt_unspec); } if (rsn->rsn_keymgmtset & WPA_ASE_8021X_PSK) { selcnt[0]++; ADDSELECTOR(frm, key_mgt_psk); } /* optional capabilities */ ADDSHORT(frm, rsn->rsn_caps); /* XXX PMKID */ /* calculate element length */ ie[1] = frm - ie - 2; IASSERT(ie[1]+2 <= sizeof(struct ieee80211_ie_wpa), ("RSN IE too big, %u > %zu", ie[1]+2, sizeof(struct ieee80211_ie_wpa))); return frm; #undef ADDSELECTOR #undef ADDSHORT #undef RSN_OUI_BYTES } /* * Add a WPA/RSN element to a frame. */ u_int8_t * ieee80211_add_wpa(u_int8_t *frm, struct ieee80211com *ic) { IASSERT(ic->ic_flags & IEEE80211_F_WPA, ("no WPA/RSN!")); if (ic->ic_flags & IEEE80211_F_WPA2) frm = ieee80211_setup_rsn_ie(ic, frm); if (ic->ic_flags & IEEE80211_F_WPA1) frm = ieee80211_setup_wpa_ie(ic, frm); return frm; } #define WME_OUI_BYTES 0x00, 0x50, 0xf2 /* * Add a WME information element to a frame. */ u_int8_t * ieee80211_add_wme_info(u_int8_t *frm, struct ieee80211_wme_state *wme) { static const struct ieee80211_wme_info info = { .wme_id = IEEE80211_ELEMID_VENDOR, .wme_len = sizeof(struct ieee80211_wme_info) - 2, .wme_oui = { WME_OUI_BYTES }, .wme_type = WME_OUI_TYPE, .wme_subtype = WME_INFO_OUI_SUBTYPE, .wme_version = WME_VERSION, .wme_info = 0, }; memcpy(frm, &info, sizeof(info)); return frm + sizeof(info); } /* * Add a WME parameters element to a frame. */ static u_int8_t * ieee80211_add_wme_param(u_int8_t *frm, struct ieee80211_wme_state *wme) { #define SM(_v, _f) (((_v) << _f##_S) & _f) #define ADDSHORT(frm, v) do { \ frm[0] = (v) & 0xff; \ frm[1] = (v) >> 8; \ frm += 2; \ } while (0) /* NB: this works because a param has an info at the front */ static const struct ieee80211_wme_info param = { .wme_id = IEEE80211_ELEMID_VENDOR, .wme_len = sizeof(struct ieee80211_wme_param) - 2, .wme_oui = { WME_OUI_BYTES }, .wme_type = WME_OUI_TYPE, .wme_subtype = WME_PARAM_OUI_SUBTYPE, .wme_version = WME_VERSION, }; int i; memcpy(frm, ¶m, sizeof(param)); frm += offsetof(struct ieee80211_wme_info, wme_info); *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */ *frm++ = 0; /* reserved field */ for (i = 0; i < WME_NUM_AC; i++) { const struct wmeParams *ac = &wme->wme_bssChanParams.cap_wmeParams[i]; *frm++ = SM(i, WME_PARAM_ACI) | SM(ac->wmep_acm, WME_PARAM_ACM) | SM(ac->wmep_aifsn, WME_PARAM_AIFSN); *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN); ADDSHORT(frm, ac->wmep_txopLimit); } return frm; #undef SM #undef ADDSHORT } #undef WME_OUI_BYTES /* * Send a probe request frame with the specified ssid * and any optional information element data. */ int ieee80211_send_probereq(struct ieee80211_node *ni, const u_int8_t sa[IEEE80211_ADDR_LEN], const u_int8_t da[IEEE80211_ADDR_LEN], const u_int8_t bssid[IEEE80211_ADDR_LEN], const u_int8_t *ssid, size_t ssidlen, const void *optie, size_t optielen) { struct ieee80211com *ic = ni->ni_ic; enum ieee80211_phymode mode; struct ieee80211_frame *wh; struct mbuf *m; u_int8_t *frm; /* * Hold a reference on the node so it doesn't go away until after * the xmit is complete all the way in the driver. On error we * will remove our reference. */ IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1); ieee80211_ref_node(ni); /* * prreq frame format * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates * [tlv] user-specified ie's */ m = ieee80211_getmgtframe(&frm, 2 + IEEE80211_NWID_LEN + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + (optie != NULL ? optielen : 0) ); if (m == NULL) { ic->ic_stats.is_tx_nobuf++; ieee80211_free_node(ni); return ENOMEM; } frm = ieee80211_add_ssid(frm, ssid, ssidlen); mode = ieee80211_chan2mode(ic, ic->ic_curchan); frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); if (optie != NULL) { memcpy(frm, optie, optielen); frm += optielen; } m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); if (m == NULL) { ic->ic_stats.is_tx_nobuf++; ieee80211_free_node(ni); return ENOMEM; } M_SETCTX(m, ni); wh = mtod(m, struct ieee80211_frame *); ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, sa, da, bssid); /* XXX power management? */ IEEE80211_NODE_STAT(ni, tx_probereq); IEEE80211_NODE_STAT(ni, tx_mgmt); IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "[%s] send probe req on channel %u\n", ether_sprintf(wh->i_addr1), ieee80211_chan2ieee(ic, ic->ic_curchan)); IF_ENQUEUE(&ic->ic_mgtq, m); if_start_lock(ic->ic_ifp); return 0; } /* * Send a management frame. The node is for the destination (or ic_bss * when in station mode). Nodes other than ic_bss have their reference * count bumped to reflect our use for an indeterminant time. */ int ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, int type, int arg) { #define senderr(_x, _v) do { ic->ic_stats._v++; ret = _x; goto bad; } while (0) struct mbuf *m; u_int8_t *frm; u_int16_t capinfo; int ret, timer, status; IASSERT(ni != NULL, ("null node")); /* * Hold a reference on the node so it doesn't go away until after * the xmit is complete all the way in the driver. On error we * will remove our reference. */ IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1); ieee80211_ref_node(ni); timer = 0; switch (type) { case IEEE80211_FC0_SUBTYPE_PROBE_RESP: { const bool has_wpa = (ic->ic_flags & IEEE80211_F_WPA) != 0; /* * probe response frame format * [8] time stamp * [2] beacon interval * [2] cabability information * [tlv] ssid * [tlv] supported rates * [tlv] parameter set (FH/DS) * [tlv] parameter set (IBSS) * [tlv] extended rate phy (ERP) * [tlv] extended supported rates * [tlv] WPA * [tlv] WME (optional) */ m = ieee80211_getmgtframe(&frm, 8 /* timestamp */ + sizeof(u_int16_t) /* interval */ + sizeof(u_int16_t) /* capinfo */ + 2 + IEEE80211_NWID_LEN /* ssid */ + 2 + IEEE80211_RATE_SIZE /* rates */ + 7 /* max(7,3) */ + 6 /* ibss (XXX could be 4?) */ + 3 /* erp */ + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) /* XXX !WPA1+WPA2 fits w/o a cluster */ + (has_wpa ? (2 * sizeof(struct ieee80211_ie_wpa)) : 0) + sizeof(struct ieee80211_wme_param) ); if (m == NULL) senderr(ENOMEM, is_tx_nobuf); /* timestamp (should be filled later) */ memset(frm, 0, 8); frm += 8; /* interval */ *(u_int16_t *)frm = htole16(ic->ic_bss->ni_intval); frm += 2; /* capinfo */ if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; *(u_int16_t *)frm = htole16(capinfo); frm += 2; /* ssid */ frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid, ic->ic_bss->ni_esslen); /* rates */ frm = ieee80211_add_rates(frm, &ni->ni_rates); /* variable */ if (ic->ic_phytype == IEEE80211_T_FH) { *frm++ = IEEE80211_ELEMID_FHPARMS; *frm++ = 5; *frm++ = ni->ni_fhdwell & 0x00ff; *frm++ = (ni->ni_fhdwell >> 8) & 0x00ff; *frm++ = IEEE80211_FH_CHANSET( ieee80211_chan2ieee(ic, ic->ic_curchan)); *frm++ = IEEE80211_FH_CHANPAT( ieee80211_chan2ieee(ic, ic->ic_curchan)); *frm++ = ni->ni_fhindex; } else { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan); } /* ibss */ if (ic->ic_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ } /* wpa */ if (has_wpa) frm = ieee80211_add_wpa(frm, ic); /* erp */ if (ic->ic_curmode == IEEE80211_MODE_11G) frm = ieee80211_add_erp(frm, ic); /* xrates */ frm = ieee80211_add_xrates(frm, &ni->ni_rates); /* wme */ if (ic->ic_flags & IEEE80211_F_WME) frm = ieee80211_add_wme_param(frm, &ic->ic_wme); m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); break; } case IEEE80211_FC0_SUBTYPE_AUTH: { status = arg >> 16; arg &= 0xffff; const bool has_challenge = (arg == IEEE80211_AUTH_SHARED_CHALLENGE || arg == IEEE80211_AUTH_SHARED_RESPONSE) && ni->ni_challenge != NULL; /* * Deduce whether we're doing open authentication or * shared key authentication. We do the latter if * we're in the middle of a shared key authentication * handshake or if we're initiating an authentication * request and configured to use shared key. */ const bool is_shared_key = has_challenge || (arg >= IEEE80211_AUTH_SHARED_RESPONSE) || (arg == IEEE80211_AUTH_SHARED_REQUEST && ic->ic_bss->ni_authmode == IEEE80211_AUTH_SHARED); const bool need_challenge = has_challenge && (status == IEEE80211_STATUS_SUCCESS); const int frm_size = 3 * sizeof(u_int16_t) + (need_challenge ? sizeof(u_int16_t)+IEEE80211_CHALLENGE_LEN : 0); m = ieee80211_getmgtframe(&frm, frm_size); if (m == NULL) senderr(ENOMEM, is_tx_nobuf); ((u_int16_t *)frm)[0] = is_shared_key ? htole16(IEEE80211_AUTH_ALG_SHARED) : htole16(IEEE80211_AUTH_ALG_OPEN); ((u_int16_t *)frm)[1] = htole16(arg); /* sequence number */ ((u_int16_t *)frm)[2] = htole16(status);/* status */ if (need_challenge) { ((u_int16_t *)frm)[3] = htole16((IEEE80211_CHALLENGE_LEN << 8) | IEEE80211_ELEMID_CHALLENGE); memcpy(&((u_int16_t *)frm)[4], ni->ni_challenge, IEEE80211_CHALLENGE_LEN); if (arg == IEEE80211_AUTH_SHARED_RESPONSE) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH, "[%s] request encrypt frame (%s)\n", ether_sprintf(ni->ni_macaddr), __func__); m->m_flags |= M_LINK0; /* WEP-encrypt, please */ } } m->m_pkthdr.len = m->m_len = frm_size; /* XXX not right for shared key */ if (status == IEEE80211_STATUS_SUCCESS) IEEE80211_NODE_STAT(ni, tx_auth); else IEEE80211_NODE_STAT(ni, tx_auth_fail); if (ic->ic_opmode == IEEE80211_M_STA) timer = IEEE80211_TRANS_WAIT; break; } case IEEE80211_FC0_SUBTYPE_DEAUTH: IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH, "[%s] send station deauthenticate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg); m = ieee80211_getmgtframe(&frm, sizeof(u_int16_t)); if (m == NULL) senderr(ENOMEM, is_tx_nobuf); *(u_int16_t *)frm = htole16(arg); /* reason */ m->m_pkthdr.len = m->m_len = sizeof(u_int16_t); IEEE80211_NODE_STAT(ni, tx_deauth); IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg); ieee80211_node_unauthorize(ni); /* port closed */ break; case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: /* * asreq frame format * [2] capability information * [2] listen interval * [6*] current AP address (reassoc only) * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates * [tlv] WME * [tlv] user-specified ie's */ m = ieee80211_getmgtframe(&frm, sizeof(u_int16_t) + sizeof(u_int16_t) + IEEE80211_ADDR_LEN + 2 + IEEE80211_NWID_LEN + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + sizeof(struct ieee80211_wme_info) + (ic->ic_opt_ie != NULL ? ic->ic_opt_ie_len : 0) ); if (m == NULL) senderr(ENOMEM, is_tx_nobuf); capinfo = 0; if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo |= IEEE80211_CAPINFO_IBSS; else /* IEEE80211_M_STA */ capinfo |= IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; /* * NB: Some 11a AP's reject the request when * short premable is set. */ if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) && (ic->ic_caps & IEEE80211_C_SHSLOT)) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; *(u_int16_t *)frm = htole16(capinfo); frm += 2; *(u_int16_t *)frm = htole16(ic->ic_lintval); frm += 2; if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { IEEE80211_ADDR_COPY(frm, ic->ic_bss->ni_bssid); frm += IEEE80211_ADDR_LEN; } frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); frm = ieee80211_add_rates(frm, &ni->ni_rates); frm = ieee80211_add_xrates(frm, &ni->ni_rates); if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL) frm = ieee80211_add_wme_info(frm, &ic->ic_wme); if (ic->ic_opt_ie != NULL) { memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len); frm += ic->ic_opt_ie_len; } m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); timer = IEEE80211_TRANS_WAIT; break; case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: /* * asreq frame format * [2] capability information * [2] status * [2] association ID * [tlv] supported rates * [tlv] extended supported rates * [tlv] WME (if enabled and STA enabled) */ m = ieee80211_getmgtframe(&frm, sizeof(u_int16_t) + sizeof(u_int16_t) + sizeof(u_int16_t) + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + sizeof(struct ieee80211_wme_param) ); if (m == NULL) senderr(ENOMEM, is_tx_nobuf); capinfo = IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; *(u_int16_t *)frm = htole16(capinfo); frm += 2; *(u_int16_t *)frm = htole16(arg); /* status */ frm += 2; if (arg == IEEE80211_STATUS_SUCCESS) { *(u_int16_t *)frm = htole16(ni->ni_associd); IEEE80211_NODE_STAT(ni, tx_assoc); } else { *(u_int16_t *)frm = 0; IEEE80211_NODE_STAT(ni, tx_assoc_fail); } frm += 2; frm = ieee80211_add_rates(frm, &ni->ni_rates); frm = ieee80211_add_xrates(frm, &ni->ni_rates); if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL) frm = ieee80211_add_wme_param(frm, &ic->ic_wme); m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); break; case IEEE80211_FC0_SUBTYPE_DISASSOC: IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, "[%s] send station disassociate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg); m = ieee80211_getmgtframe(&frm, sizeof(u_int16_t)); if (m == NULL) senderr(ENOMEM, is_tx_nobuf); *(u_int16_t *)frm = htole16(arg); /* reason */ m->m_pkthdr.len = m->m_len = sizeof(u_int16_t); IEEE80211_NODE_STAT(ni, tx_disassoc); IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg); break; default: IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, "[%s] invalid mgmt frame type %u\n", ether_sprintf(ni->ni_macaddr), type); senderr(EINVAL, is_tx_unknownmgt); /* NOTREACHED */ } ret = ieee80211_mgmt_output(ic, ni, m, type, timer); if (ret != 0) { bad: ieee80211_free_node(ni); } return ret; #undef senderr } /* * Build a RTS (Request To Send) control frame. */ struct mbuf * ieee80211_get_rts(struct ieee80211com *ic, const struct ieee80211_frame *wh, uint16_t dur) { struct ieee80211_frame_rts *rts; struct mbuf *m; MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) return NULL; m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts); rts = mtod(m, struct ieee80211_frame_rts *); rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(uint16_t *)rts->i_dur = htole16(dur); IEEE80211_ADDR_COPY(rts->i_ra, wh->i_addr1); IEEE80211_ADDR_COPY(rts->i_ta, wh->i_addr2); return m; } /* * Build a CTS-to-self (Clear To Send) control frame. */ struct mbuf * ieee80211_get_cts_to_self(struct ieee80211com *ic, uint16_t dur) { struct ieee80211_frame_cts *cts; struct mbuf *m; MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) return NULL; m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts); cts = mtod(m, struct ieee80211_frame_cts *); cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(uint16_t *)cts->i_dur = htole16(dur); IEEE80211_ADDR_COPY(cts->i_ra, ic->ic_myaddr); return m; } /* * Allocate a beacon frame and fill in the appropriate bits. */ struct mbuf * ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo) { struct ifnet *ifp = ic->ic_ifp; struct ieee80211_frame *wh; struct mbuf *m; int pktlen; u_int8_t *frm, *efrm; u_int16_t capinfo; struct ieee80211_rateset *rs; rs = &ni->ni_rates; /* * beacon frame format * [8] time stamp * [2] beacon interval * [2] cabability information * [tlv] ssid * [tlv] supported rates * [3] parameter set (DS) * [tlv] parameter set (IBSS/TIM) * [tlv] extended rate phy (ERP) * [tlv] extended supported rates * [tlv] WME parameters * [tlv] WPA/RSN parameters * XXX Vendor-specific OIDs (e.g. Atheros) * * NB: we allocate the max space required for the TIM bitmap * (ic_tim_len). */ pktlen = 8 /* time stamp */ + sizeof(u_int16_t) /* beacon interval */ + sizeof(u_int16_t) /* capabilities */ + 2 + ni->ni_esslen /* ssid */ + 2 + IEEE80211_RATE_SIZE /* supported rates */ + 2 + 1 /* DS parameters */ + 2 + 4 + ic->ic_tim_len /* DTIM/IBSSPARMS */ + 2 + 1 /* ERP */ + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + (ic->ic_caps & IEEE80211_C_WME ? /* WME */ sizeof(struct ieee80211_wme_param) : 0) + (ic->ic_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ 2*sizeof(struct ieee80211_ie_wpa) : 0) ; m = ieee80211_getmgtframe(&frm, pktlen); if (m == NULL) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, "%s: cannot get buf; size %u\n", __func__, pktlen); ic->ic_stats.is_tx_nobuf++; return NULL; } memset(frm, 0, 8); /* XXX timestamp is set by hardware/driver */ frm += 8; *(u_int16_t *)frm = htole16(ni->ni_intval); frm += 2; if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; bo->bo_caps = (u_int16_t *)frm; *(u_int16_t *)frm = htole16(capinfo); frm += 2; *frm++ = IEEE80211_ELEMID_SSID; if ((ic->ic_flags & IEEE80211_F_HIDESSID) == 0) { *frm++ = ni->ni_esslen; memcpy(frm, ni->ni_essid, ni->ni_esslen); frm += ni->ni_esslen; } else *frm++ = 0; frm = ieee80211_add_rates(frm, rs); if (ic->ic_curmode != IEEE80211_MODE_FH) { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); } bo->bo_tim = frm; if (ic->ic_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ bo->bo_tim_len = 0; } else { struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *)frm; tie->tim_ie = IEEE80211_ELEMID_TIM; tie->tim_len = 4; /* length */ tie->tim_count = 0; /* DTIM count */ tie->tim_period = ic->ic_dtim_period; /* DTIM period */ tie->tim_bitctl = 0; /* bitmap control */ tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ frm += sizeof(struct ieee80211_tim_ie); bo->bo_tim_len = 1; } bo->bo_trailer = frm; if (ic->ic_flags & IEEE80211_F_WME) { bo->bo_wme = frm; frm = ieee80211_add_wme_param(frm, &ic->ic_wme); ic->ic_flags &= ~IEEE80211_F_WMEUPDATE; } if (ic->ic_flags & IEEE80211_F_WPA) frm = ieee80211_add_wpa(frm, ic); if (ic->ic_curmode == IEEE80211_MODE_11G) frm = ieee80211_add_erp(frm, ic); efrm = ieee80211_add_xrates(frm, rs); bo->bo_trailer_len = efrm - bo->bo_trailer; m->m_pkthdr.len = m->m_len = efrm - mtod(m, u_int8_t *); M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); IASSERT(m != NULL, ("no space for 802.11 header?")); wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_BEACON; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(u_int16_t *)wh->i_dur = 0; IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); *(u_int16_t *)wh->i_seq = 0; return m; } /* * Update the dynamic parts of a beacon frame based on the current state. */ int ieee80211_beacon_update(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) { int len_changed = 0; u_int16_t capinfo; IEEE80211_BEACON_LOCK(ic); /* XXX faster to recalculate entirely or just changes? */ if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; *bo->bo_caps = htole16(capinfo); if (ic->ic_flags & IEEE80211_F_WME) { struct ieee80211_wme_state *wme = &ic->ic_wme; /* * Check for aggressive mode change. When there is * significant high priority traffic in the BSS * throttle back BE traffic by using conservative * parameters. Otherwise BE uses aggressive params * to optimize performance of legacy/non-QoS traffic. */ if (wme->wme_flags & WME_F_AGGRMODE) { if (wme->wme_hipri_traffic > wme->wme_hipri_switch_thresh) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, "%s: traffic %u, disable aggressive mode\n", __func__, wme->wme_hipri_traffic); wme->wme_flags &= ~WME_F_AGGRMODE; ieee80211_wme_updateparams_locked(ic); wme->wme_hipri_traffic = wme->wme_hipri_switch_hysteresis; } else wme->wme_hipri_traffic = 0; } else { if (wme->wme_hipri_traffic <= wme->wme_hipri_switch_thresh) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, "%s: traffic %u, enable aggressive mode\n", __func__, wme->wme_hipri_traffic); wme->wme_flags |= WME_F_AGGRMODE; ieee80211_wme_updateparams_locked(ic); wme->wme_hipri_traffic = 0; } else wme->wme_hipri_traffic = wme->wme_hipri_switch_hysteresis; } if (ic->ic_flags & IEEE80211_F_WMEUPDATE) { (void)ieee80211_add_wme_param(bo->bo_wme, wme); ic->ic_flags &= ~IEEE80211_F_WMEUPDATE; } } #ifndef IEEE80211_NO_HOSTAP if (ic->ic_opmode == IEEE80211_M_HOSTAP) { /* NB: no IBSS support*/ struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *)bo->bo_tim; if (ic->ic_flags & IEEE80211_F_TIMUPDATE) { u_int timlen, timoff, i; /* * ATIM/DTIM needs updating. If it fits in the * current space allocated then just copy in the * new bits. Otherwise we need to move any trailing * data to make room. Note that we know there is * contiguous space because ieee80211_beacon_allocate * insures there is space in the mbuf to write a * maximal-size virtual bitmap (based on ic_max_aid). */ /* * Calculate the bitmap size and offset, copy any * trailer out of the way, and then copy in the * new bitmap and update the information element. * Note that the tim bitmap must contain at least * one byte and any offset must be even. */ if (ic->ic_ps_pending != 0) { timoff = 128; /* impossibly large */ for (i = 0; i < ic->ic_tim_len; i++) if (ic->ic_tim_bitmap[i]) { timoff = i &~ 1; break; } IASSERT(timoff != 128, ("tim bitmap empty!")); for (i = ic->ic_tim_len-1; i >= timoff; i--) if (ic->ic_tim_bitmap[i]) break; timlen = 1 + (i - timoff); } else { timoff = 0; timlen = 1; } if (timlen != bo->bo_tim_len) { /* copy up/down trailer */ memmove(tie->tim_bitmap+timlen, bo->bo_trailer, bo->bo_trailer_len); bo->bo_trailer = tie->tim_bitmap+timlen; bo->bo_wme = bo->bo_trailer; bo->bo_tim_len = timlen; /* update information element */ tie->tim_len = 3 + timlen; tie->tim_bitctl = timoff; len_changed = 1; } memcpy(tie->tim_bitmap, ic->ic_tim_bitmap + timoff, bo->bo_tim_len); ic->ic_flags &= ~IEEE80211_F_TIMUPDATE; IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, "%s: TIM updated, pending %u, off %u, len %u\n", __func__, ic->ic_ps_pending, timoff, timlen); } /* count down DTIM period */ if (tie->tim_count == 0) tie->tim_count = tie->tim_period - 1; else tie->tim_count--; /* update state for buffered multicast frames on DTIM */ if (mcast && (tie->tim_count == 1 || tie->tim_period == 1)) tie->tim_bitctl |= 1; else tie->tim_bitctl &= ~1; } #endif /* !IEEE80211_NO_HOSTAP */ IEEE80211_BEACON_UNLOCK(ic); return len_changed; } /* * Save an outbound packet for a node in power-save sleep state. * The new packet is placed on the node's saved queue, and the TIM * is changed, if necessary. */ void ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni, struct mbuf *m) { int qlen, age; IEEE80211_NODE_SAVEQ_LOCK(ni); if (IF_QFULL(&ni->ni_savedq)) { IF_DROP(&ni->ni_savedq); IEEE80211_NODE_SAVEQ_UNLOCK(ni); IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, "[%s] pwr save q overflow, drops %" PRIu64 " (size %d)\n", ether_sprintf(ni->ni_macaddr), ni->ni_savedq.ifq_drops, IEEE80211_PS_MAX_QUEUE); #ifdef IEEE80211_DEBUG if (ieee80211_msg_dumppkts(ic)) ieee80211_dump_pkt(mtod(m, void *), m->m_len, -1, -1); #endif m_freem(m); return; } /* * Tag the frame with its expiry time and insert * it in the queue. The aging interval is 4 times * the listen interval specified by the station. * Frames that sit around too long are reclaimed * using this information. */ /* XXX handle overflow? */ age = ((ni->ni_intval * ic->ic_bintval) << 2) / 1024; /* TU -> secs */ _IEEE80211_NODE_SAVEQ_ENQUEUE(ni, m, qlen, age); IEEE80211_NODE_SAVEQ_UNLOCK(ni); IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, "[%s] save frame with age %d, %u now queued\n", ether_sprintf(ni->ni_macaddr), age, qlen); if (qlen == 1) ic->ic_set_tim(ni, 1); } @ 1.66 log @Fix all remaining typos, mainly in comments but also in few definitions and log messages, reported by me in PR kern/54889. Also fixed some additional typos in comments, found on review of same files or typos. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.65 2020/02/29 16:56:58 mlelstv Exp $ */ d40 1 a40 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.65 2020/02/29 16:56:58 mlelstv Exp $"); d2136 4 a2139 3 "[%s] pwr save q overflow, drops %d (size %d)\n", ether_sprintf(ni->ni_macaddr), ni->ni_savedq.ifq_drops, IEEE80211_PS_MAX_QUEUE); @ 1.65 log @Fix printf to handle various datatypes for MHLEN. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.64 2018/12/22 13:11:37 maxv Exp $ */ d40 1 a40 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.64 2018/12/22 13:11:37 maxv Exp $"); d2004 1 a2004 1 * Check for agressive mode change. When there is d2007 1 a2007 1 * parameters. Otherwise BE uses agressive params @ 1.65.10.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.66 2021/07/24 21:31:38 andvar Exp $ */ d40 1 a40 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.66 2021/07/24 21:31:38 andvar Exp $"); d2004 1 a2004 1 * Check for aggressive mode change. When there is d2007 1 a2007 1 * parameters. Otherwise BE uses aggressive params @ 1.64 log @Replace: M_MOVE_PKTHDR -> m_move_pkthdr. No functional change, since the former is a macro to the latter. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.63 2018/05/08 07:02:07 maxv Exp $ */ d40 1 a40 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.63 2018/05/08 07:02:07 maxv Exp $"); d439 1 a439 1 ("not enough room, need %u got %zu\n", needed_space, MHLEN)); @ 1.64.6.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.65 2020/02/29 16:56:58 mlelstv Exp $ */ d40 1 a40 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.65 2020/02/29 16:56:58 mlelstv Exp $"); d439 1 a439 1 ("not enough room, need %u got %lu\n", needed_space, (u_long)MHLEN)); @ 1.63 log @Remove three useless debug messages, remove meaningless XXXs, and remove ieee80211_note_frame (unused). @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.62 2018/05/03 17:14:37 maxv Exp $ */ d40 1 a40 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.62 2018/05/03 17:14:37 maxv Exp $"); d447 1 a447 1 M_MOVE_PKTHDR(n, m); @ 1.63.2.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 3 a3 3 /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * d5 1 a5 1 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting d16 6 d36 6 a41 1 __FBSDID("$FreeBSD$"); d43 1 d45 1 a45 2 #include "opt_inet6.h" #include "opt_wlan.h" d49 1 a50 2 #include #include d52 3 a55 4 #include #include #include a56 1 #include d59 4 a62 1 #include d64 1 a65 10 #include #ifdef IEEE80211_SUPPORT_SUPERG #include #endif #ifdef IEEE80211_SUPPORT_TDMA #include #endif #include #include #include d67 1 a67 3 #if defined(INET) || defined(INET6) #include #endif d70 1 a70 1 #include d72 1 d74 1 a74 3 #endif #ifdef INET6 #include d77 1 a77 6 #include #define ETHER_HEADER_COPY(dst, src) \ memcpy(dst, src, sizeof(struct ether_header)) static int ieee80211_fragment(struct ieee80211vap *, struct mbuf *, a78 1 static void ieee80211_tx_mgt_cb(struct ieee80211_node *, void *, int); d88 1 a88 1 doprint(struct ieee80211vap *vap, int subtype) d92 1 a92 1 return (vap->iv_opmode == IEEE80211_M_IBSS); a98 637 * Transmit a frame to the given destination on the given VAP. * * It's up to the caller to figure out the details of who this * is going to and resolving the node. * * This routine takes care of queuing it for power save, * A-MPDU state stuff, fast-frames state stuff, encapsulation * if required, then passing it up to the driver layer. * * This routine (for now) consumes the mbuf and frees the node * reference; it ideally will return a TX status which reflects * whether the mbuf was consumed or not, so the caller can * free the mbuf (if appropriate) and the node reference (again, * if appropriate.) */ int ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m, struct ieee80211_node *ni) { struct ieee80211com *ic = vap->iv_ic; struct ifnet *ifp = vap->iv_ifp; int mcast; if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && (m->m_flags & M_PWR_SAV) == 0) { /* * Station in power save mode; pass the frame * to the 802.11 layer and continue. We'll get * the frame back when the time is right. * XXX lose WDS vap linkage? */ if (ieee80211_pwrsave(ni, m) != 0) if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); /* * We queued it fine, so tell the upper layer * that we consumed it. */ return (0); } /* calculate priority so drivers can find the tx queue */ if (ieee80211_classify(ni, m)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, ni->ni_macaddr, NULL, "%s", "classification failure"); vap->iv_stats.is_tx_classify++; if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); m_freem(m); ieee80211_free_node(ni); /* XXX better status? */ return (0); } /* * Stash the node pointer. Note that we do this after * any call to ieee80211_dwds_mcast because that code * uses any existing value for rcvif to identify the * interface it (might have been) received on. */ m->m_pkthdr.rcvif = (void *)ni; mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1: 0; BPF_MTAP(ifp, m); /* 802.3 tx */ /* * Check if A-MPDU tx aggregation is setup or if we * should try to enable it. The sta must be associated * with HT and A-MPDU enabled for use. When the policy * routine decides we should enable A-MPDU we issue an * ADDBA request and wait for a reply. The frame being * encapsulated will go out w/o using A-MPDU, or possibly * it might be collected by the driver and held/retransmit. * The default ic_ampdu_enable routine handles staggering * ADDBA requests in case the receiver NAK's us or we are * otherwise unable to establish a BA stream. * * Don't treat group-addressed frames as candidates for aggregation; * net80211 doesn't support 802.11aa-2012 and so group addressed * frames will always have sequence numbers allocated from the NON_QOS * TID. */ if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) && (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX)) { if ((m->m_flags & M_EAPOL) == 0 && (! mcast)) { int tid = WME_AC_TO_TID(M_WME_GETAC(m)); struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[tid]; ieee80211_txampdu_count_packet(tap); if (IEEE80211_AMPDU_RUNNING(tap)) { /* * Operational, mark frame for aggregation. * * XXX do tx aggregation here */ m->m_flags |= M_AMPDU_MPDU; } else if (!IEEE80211_AMPDU_REQUESTED(tap) && ic->ic_ampdu_enable(ni, tap)) { /* * Not negotiated yet, request service. */ ieee80211_ampdu_request(ni, tap); /* XXX hold frame for reply? */ } } } #ifdef IEEE80211_SUPPORT_SUPERG /* * Check for AMSDU/FF; queue for aggregation * * Note: we don't bother trying to do fast frames or * A-MSDU encapsulation for 802.3 drivers. Now, we * likely could do it for FF (because it's a magic * atheros tunnel LLC type) but I don't think we're going * to really need to. For A-MSDU we'd have to set the * A-MSDU QoS bit in the wifi header, so we just plain * can't do it. * * Strictly speaking, we could actually /do/ A-MSDU / FF * with A-MPDU together which for certain circumstances * is beneficial (eg A-MSDU of TCK ACKs.) However, * I'll ignore that for now so existing behaviour is maintained. * Later on it would be good to make "amsdu + ampdu" configurable. */ else if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) { if ((! mcast) && ieee80211_amsdu_tx_ok(ni)) { m = ieee80211_amsdu_check(ni, m); if (m == NULL) { /* NB: any ni ref held on stageq */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, "%s: amsdu_check queued frame\n", __func__); return (0); } } else if ((! mcast) && IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) { m = ieee80211_ff_check(ni, m); if (m == NULL) { /* NB: any ni ref held on stageq */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, "%s: ff_check queued frame\n", __func__); return (0); } } } #endif /* IEEE80211_SUPPORT_SUPERG */ /* * Grab the TX lock - serialise the TX process from this * point (where TX state is being checked/modified) * through to driver queue. */ IEEE80211_TX_LOCK(ic); /* * XXX make the encap and transmit code a separate function * so things like the FF (and later A-MSDU) path can just call * it for flushed frames. */ if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) { /* * Encapsulate the packet in prep for transmission. */ m = ieee80211_encap(vap, ni, m); if (m == NULL) { /* NB: stat+msg handled in ieee80211_encap */ IEEE80211_TX_UNLOCK(ic); ieee80211_free_node(ni); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return (ENOBUFS); } } (void) ieee80211_parent_xmitpkt(ic, m); /* * Unlock at this point - no need to hold it across * ieee80211_free_node() (ie, the comlock) */ IEEE80211_TX_UNLOCK(ic); ic->ic_lastdata = ticks; return (0); } /* * Send the given mbuf through the given vap. * * This consumes the mbuf regardless of whether the transmit * was successful or not. * * This does none of the initial checks that ieee80211_start() * does (eg CAC timeout, interface wakeup) - the caller must * do this first. */ static int ieee80211_start_pkt(struct ieee80211vap *vap, struct mbuf *m) { #define IS_DWDS(vap) \ (vap->iv_opmode == IEEE80211_M_WDS && \ (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) == 0) struct ieee80211com *ic = vap->iv_ic; struct ifnet *ifp = vap->iv_ifp; struct ieee80211_node *ni; struct ether_header *eh; /* * Cancel any background scan. */ if (ic->ic_flags & IEEE80211_F_SCAN) ieee80211_cancel_anyscan(vap); /* * Find the node for the destination so we can do * things like power save and fast frames aggregation. * * NB: past this point various code assumes the first * mbuf has the 802.3 header present (and contiguous). */ ni = NULL; if (m->m_len < sizeof(struct ether_header) && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, "discard frame, %s\n", "m_pullup failed"); vap->iv_stats.is_tx_nobuf++; /* XXX */ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return (ENOBUFS); } eh = mtod(m, struct ether_header *); if (ETHER_IS_MULTICAST(eh->ether_dhost)) { if (IS_DWDS(vap)) { /* * Only unicast frames from the above go out * DWDS vaps; multicast frames are handled by * dispatching the frame as it comes through * the AP vap (see below). */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS, eh->ether_dhost, "mcast", "%s", "on DWDS"); vap->iv_stats.is_dwds_mcast++; m_freem(m); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); /* XXX better status? */ return (ENOBUFS); } if (vap->iv_opmode == IEEE80211_M_HOSTAP) { /* * Spam DWDS vap's w/ multicast traffic. */ /* XXX only if dwds in use? */ ieee80211_dwds_mcast(vap, m); } } #ifdef IEEE80211_SUPPORT_MESH if (vap->iv_opmode != IEEE80211_M_MBSS) { #endif ni = ieee80211_find_txnode(vap, eh->ether_dhost); if (ni == NULL) { /* NB: ieee80211_find_txnode does stat+msg */ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); m_freem(m); /* XXX better status? */ return (ENOBUFS); } if (ni->ni_associd == 0 && (ni->ni_flags & IEEE80211_NODE_ASSOCID)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, eh->ether_dhost, NULL, "sta not associated (type 0x%04x)", htons(eh->ether_type)); vap->iv_stats.is_tx_notassoc++; if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); m_freem(m); ieee80211_free_node(ni); /* XXX better status? */ return (ENOBUFS); } #ifdef IEEE80211_SUPPORT_MESH } else { if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) { /* * Proxy station only if configured. */ if (!ieee80211_mesh_isproxyena(vap)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_MESH, eh->ether_dhost, NULL, "%s", "proxy not enabled"); vap->iv_stats.is_mesh_notproxy++; if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); m_freem(m); /* XXX better status? */ return (ENOBUFS); } IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, "forward frame from DS SA(%6D), DA(%6D)\n", eh->ether_shost, ":", eh->ether_dhost, ":"); ieee80211_mesh_proxy_check(vap, eh->ether_shost); } ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m); if (ni == NULL) { /* * NB: ieee80211_mesh_discover holds/disposes * frame (e.g. queueing on path discovery). */ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); /* XXX better status? */ return (ENOBUFS); } } #endif /* * We've resolved the sender, so attempt to transmit it. */ if (vap->iv_state == IEEE80211_S_SLEEP) { /* * In power save; queue frame and then wakeup device * for transmit. */ ic->ic_lastdata = ticks; if (ieee80211_pwrsave(ni, m) != 0) if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); ieee80211_new_state(vap, IEEE80211_S_RUN, 0); return (0); } if (ieee80211_vap_pkt_send_dest(vap, m, ni) != 0) return (ENOBUFS); return (0); #undef IS_DWDS } /* * Start method for vap's. All packets from the stack come * through here. We handle common processing of the packets * before dispatching them to the underlying device. * * if_transmit() requires that the mbuf be consumed by this call * regardless of the return condition. */ int ieee80211_vap_transmit(struct ifnet *ifp, struct mbuf *m) { struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; /* * No data frames go out unless we're running. * Note in particular this covers CAC and CSA * states (though maybe we should check muting * for CSA). */ if (vap->iv_state != IEEE80211_S_RUN && vap->iv_state != IEEE80211_S_SLEEP) { IEEE80211_LOCK(ic); /* re-check under the com lock to avoid races */ if (vap->iv_state != IEEE80211_S_RUN && vap->iv_state != IEEE80211_S_SLEEP) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, "%s: ignore queue, in %s state\n", __func__, ieee80211_state_name[vap->iv_state]); vap->iv_stats.is_tx_badstate++; IEEE80211_UNLOCK(ic); ifp->if_drv_flags |= IFF_DRV_OACTIVE; m_freem(m); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return (ENETDOWN); } IEEE80211_UNLOCK(ic); } /* * Sanitize mbuf flags for net80211 use. We cannot * clear M_PWR_SAV or M_MORE_DATA because these may * be set for frames that are re-submitted from the * power save queue. * * NB: This must be done before ieee80211_classify as * it marks EAPOL in frames with M_EAPOL. */ m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA); /* * Bump to the packet transmission path. * The mbuf will be consumed here. */ return (ieee80211_start_pkt(vap, m)); } void ieee80211_vap_qflush(struct ifnet *ifp) { /* Empty for now */ } /* * 802.11 raw output routine. * * XXX TODO: this (and other send routines) should correctly * XXX keep the pwr mgmt bit set if it decides to call into the * XXX driver to send a frame whilst the state is SLEEP. * * Otherwise the peer may decide that we're awake and flood us * with traffic we are still too asleep to receive! */ int ieee80211_raw_output(struct ieee80211vap *vap, struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = vap->iv_ic; int error; /* * Set node - the caller has taken a reference, so ensure * that the mbuf has the same node value that * it would if it were going via the normal path. */ m->m_pkthdr.rcvif = (void *)ni; /* * Attempt to add bpf transmit parameters. * * For now it's ok to fail; the raw_xmit api still takes * them as an option. * * Later on when ic_raw_xmit() has params removed, * they'll have to be added - so fail the transmit if * they can't be. */ if (params) (void) ieee80211_add_xmit_params(m, params); error = ic->ic_raw_xmit(ni, m, params); if (error) { if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); } return (error); } static int ieee80211_validate_frame(struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211_frame *wh; int type; if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack)) return (EINVAL); wh = mtod(m, struct ieee80211_frame *); if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != IEEE80211_FC0_VERSION_0) return (EINVAL); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; if (type != IEEE80211_FC0_TYPE_DATA) { if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != IEEE80211_FC1_DIR_NODS) return (EINVAL); if (type != IEEE80211_FC0_TYPE_MGT && (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) != 0) return (EINVAL); /* XXX skip other field checks? */ } if ((params && (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0) || (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) != 0) { int subtype; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; /* * See IEEE Std 802.11-2012, * 8.2.4.1.9 'Protected Frame field' */ /* XXX no support for robust management frames yet. */ if (!(type == IEEE80211_FC0_TYPE_DATA || (type == IEEE80211_FC0_TYPE_MGT && subtype == IEEE80211_FC0_SUBTYPE_AUTH))) return (EINVAL); wh->i_fc[1] |= IEEE80211_FC1_PROTECTED; } if (m->m_pkthdr.len < ieee80211_anyhdrsize(wh)) return (EINVAL); return (0); } /* * 802.11 output routine. This is (currently) used only to * connect bpf write calls to the 802.11 layer for injecting * raw 802.11 frames. */ int ieee80211_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct route *ro) { #define senderr(e) do { error = (e); goto bad;} while (0) const struct ieee80211_bpf_params *params = NULL; struct ieee80211_node *ni = NULL; struct ieee80211vap *vap; struct ieee80211_frame *wh; struct ieee80211com *ic = NULL; int error; int ret; if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { /* * Short-circuit requests if the vap is marked OACTIVE * as this can happen because a packet came down through * ieee80211_start before the vap entered RUN state in * which case it's ok to just drop the frame. This * should not be necessary but callers of if_output don't * check OACTIVE. */ senderr(ENETDOWN); } vap = ifp->if_softc; ic = vap->iv_ic; /* * Hand to the 802.3 code if not tagged as * a raw 802.11 frame. */ if (dst->sa_family != AF_IEEE80211) return vap->iv_output(ifp, m, dst, ro); #ifdef MAC error = mac_ifnet_check_transmit(ifp, m); if (error) senderr(error); #endif if (ifp->if_flags & IFF_MONITOR) senderr(ENETDOWN); if (!IFNET_IS_UP_RUNNING(ifp)) senderr(ENETDOWN); if (vap->iv_state == IEEE80211_S_CAC) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, "block %s frame in CAC state\n", "raw data"); vap->iv_stats.is_tx_badstate++; senderr(EIO); /* XXX */ } else if (vap->iv_state == IEEE80211_S_SCAN) senderr(EIO); /* XXX bypass bridge, pfil, carp, etc. */ /* * NB: DLT_IEEE802_11_RADIO identifies the parameters are * present by setting the sa_len field of the sockaddr (yes, * this is a hack). * NB: we assume sa_data is suitably aligned to cast. */ if (dst->sa_len != 0) params = (const struct ieee80211_bpf_params *)dst->sa_data; error = ieee80211_validate_frame(m, params); if (error != 0) senderr(error); wh = mtod(m, struct ieee80211_frame *); /* locate destination node */ switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { case IEEE80211_FC1_DIR_NODS: case IEEE80211_FC1_DIR_FROMDS: ni = ieee80211_find_txnode(vap, wh->i_addr1); break; case IEEE80211_FC1_DIR_TODS: case IEEE80211_FC1_DIR_DSTODS: ni = ieee80211_find_txnode(vap, wh->i_addr3); break; default: senderr(EDOOFUS); } if (ni == NULL) { /* * Permit packets w/ bpf params through regardless * (see below about sa_len). */ if (dst->sa_len == 0) senderr(EHOSTUNREACH); ni = ieee80211_ref_node(vap->iv_bss); } /* * Sanitize mbuf for net80211 flags leaked from above. * * NB: This must be done before ieee80211_classify as * it marks EAPOL in frames with M_EAPOL. */ m->m_flags &= ~M_80211_TX; m->m_flags |= M_ENCAP; /* mark encapsulated */ if (IEEE80211_IS_DATA(wh)) { /* calculate priority so drivers can find the tx queue */ if (ieee80211_classify(ni, m)) senderr(EIO); /* XXX */ /* NB: ieee80211_encap does not include 802.11 header */ IEEE80211_NODE_STAT_ADD(ni, tx_bytes, m->m_pkthdr.len - ieee80211_hdrsize(wh)); } else M_WME_SETAC(m, WME_AC_BE); IEEE80211_NODE_STAT(ni, tx_data); if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { IEEE80211_NODE_STAT(ni, tx_mcast); m->m_flags |= M_MCAST; } else IEEE80211_NODE_STAT(ni, tx_ucast); IEEE80211_TX_LOCK(ic); ret = ieee80211_raw_output(vap, ni, m, params); IEEE80211_TX_UNLOCK(ic); return (ret); bad: if (m != NULL) m_freem(m); if (ni != NULL) ieee80211_free_node(ni); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return error; #undef senderr } /* d100 3 a102 2 * frame. Note this should be called early on in constructing * a frame as it sets i_fc[1]; other bits can then be or'd in. d104 2 a105 2 void ieee80211_send_setup( d107 5 a111 5 struct mbuf *m, int type, int tid, const uint8_t sa[IEEE80211_ADDR_LEN], const uint8_t da[IEEE80211_ADDR_LEN], const uint8_t bssid[IEEE80211_ADDR_LEN]) a113 4 struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_tx_ampdu *tap; struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); ieee80211_seq seqno; d115 1 a115 1 IEEE80211_TX_LOCK_ASSERT(ni->ni_ic); a116 1 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; d118 1 a118 1 switch (vap->iv_opmode) { d125 1 d133 1 d140 1 a140 25 case IEEE80211_M_WDS: wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, da); IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); break; case IEEE80211_M_MBSS: #ifdef IEEE80211_SUPPORT_MESH if (IEEE80211_IS_MULTICAST(da)) { wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; /* XXX next hop */ IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); } else { wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, da); IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); } #endif break; d148 1 a148 43 #ifdef IEEE80211_SUPPORT_MESH if (vap->iv_opmode == IEEE80211_M_MBSS) IEEE80211_ADDR_COPY(wh->i_addr3, sa); else #endif IEEE80211_ADDR_COPY(wh->i_addr3, bssid); } *(uint16_t *)&wh->i_dur[0] = 0; /* * XXX TODO: this is what the TX lock is for. * Here we're incrementing sequence numbers, and they * need to be in lock-step with what the driver is doing * both in TX ordering and crypto encap (IV increment.) * * If the driver does seqno itself, then we can skip * assigning sequence numbers here, and we can avoid * requiring the TX lock. */ tap = &ni->ni_tx_ampdu[tid]; if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) { m->m_flags |= M_AMPDU_MPDU; /* NB: zero out i_seq field (for s/w encryption etc) */ *(uint16_t *)&wh->i_seq[0] = 0; } else { if (IEEE80211_HAS_SEQ(type & IEEE80211_FC0_TYPE_MASK, type & IEEE80211_FC0_SUBTYPE_MASK)) /* * 802.11-2012 9.3.2.10 - QoS multicast frames * come out of a different seqno space. */ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; } else { seqno = ni->ni_txseqs[tid]++; } else seqno = 0; *(uint16_t *)&wh->i_seq[0] = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); M_SEQNO_SET(m, seqno); d151 5 a155 2 if (IEEE80211_IS_MULTICAST(wh->i_addr1)) m->m_flags |= M_MCAST; d164 1 a164 2 * reference (and potentially free'ing up any associated storage); * otherwise deal with reclaiming any reference (on error). d166 3 a168 3 int ieee80211_mgmt_output(struct ieee80211_node *ni, struct mbuf *m, int type, struct ieee80211_bpf_params *params) d170 1 a170 2 struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; a171 1 int ret; d173 1 a173 1 KASSERT(ni != NULL, ("null node")); d175 14 a188 13 if (vap->iv_state == IEEE80211_S_CAC) { IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, ni, "block %s frame in CAC state", ieee80211_mgt_subtype_name(type)); vap->iv_stats.is_tx_badstate++; ieee80211_free_node(ni); m_freem(m); return EIO; /* XXX */ } M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); if (m == NULL) { ieee80211_free_node(ni); d190 1 a190 1 } d192 3 a194 1 IEEE80211_TX_LOCK(ic); d196 6 a201 8 wh = mtod(m, struct ieee80211_frame *); ieee80211_send_setup(ni, m, IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1, "encrypting frame (%s)", __func__); wh->i_fc[1] |= IEEE80211_FC1_PROTECTED; a202 4 m->m_flags |= M_ENCAP; /* mark encapsulated */ KASSERT(type != IEEE80211_FC0_SUBTYPE_PROBE_RESP, ("probe response?")); M_WME_SETAC(m, params->ibp_pri); d206 2 a207 2 if ((ieee80211_msg_debug(vap) && doprint(vap, type)) || ieee80211_msg_dumppkts(vap)) { d210 3 a212 1 ieee80211_mgt_subtype_name(type), d216 1 d218 10 a227 13 ret = ieee80211_raw_output(vap, ni, m, params); IEEE80211_TX_UNLOCK(ic); return (ret); } static void ieee80211_nulldata_transmitted(struct ieee80211_node *ni, void *arg, int status) { struct ieee80211vap *vap = ni->ni_vap; wakeup(vap); d231 1 a231 3 * Send a null data frame to the specified node. If the station * is setup for QoS then a QoS Null Data frame is constructed. * If this is a WDS station then a 4-address frame is constructed. d235 1 a235 4 * when probing for inactive stations. Like ieee80211_mgmt_output * we must cleanup any node reference on error; however we * can safely just unref it as we know it will never be the * last reference to the node. a239 1 struct ieee80211vap *vap = ni->ni_vap; d241 1 a243 21 int hdrlen; uint8_t *frm; int ret; if (vap->iv_state == IEEE80211_S_CAC) { IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, ni, "block %s frame in CAC state", "null data"); ieee80211_unref_node(&ni); vap->iv_stats.is_tx_badstate++; return EIO; /* XXX */ } if (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) hdrlen = sizeof(struct ieee80211_qosframe); else hdrlen = sizeof(struct ieee80211_frame); /* NB: only WDS vap's get 4-address frames */ if (vap->iv_opmode == IEEE80211_M_WDS) hdrlen += IEEE80211_ADDR_LEN; if (ic->ic_flags & IEEE80211_F_DATAPAD) hdrlen = roundup(hdrlen, sizeof(uint32_t)); d245 1 a245 1 m = ieee80211_getmgtframe(&frm, ic->ic_headroom + hdrlen, 0); d247 1 a247 1 /* XXX debug msg */ a248 9 vap->iv_stats.is_tx_nobuf++; return ENOMEM; } KASSERT(M_LEADINGSPACE(m) >= hdrlen, ("leading space %zd", M_LEADINGSPACE(m))); M_PREPEND(m, hdrlen, M_NOWAIT); if (m == NULL) { /* NB: cannot happen */ ieee80211_free_node(ni); d251 1 d253 1 a253 1 IEEE80211_TX_LOCK(ic); d255 3 a257 8 wh = mtod(m, struct ieee80211_frame *); /* NB: a little lie */ if (ni->ni_flags & IEEE80211_NODE_QOS) { const int tid = WME_AC_TO_TID(WME_AC_BE); uint8_t *qos; ieee80211_send_setup(ni, m, IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL, tid, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); d259 4 a262 24 if (vap->iv_opmode == IEEE80211_M_WDS) qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; else qos = ((struct ieee80211_qosframe *) wh)->i_qos; qos[0] = tid & IEEE80211_QOS_TID; if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[WME_AC_BE].wmep_noackPolicy) qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; qos[1] = 0; } else { ieee80211_send_setup(ni, m, IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, IEEE80211_NONQOS_TID, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); } if (vap->iv_opmode != IEEE80211_M_WDS) { /* NB: power management bit is never sent by an AP */ if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && vap->iv_opmode != IEEE80211_M_HOSTAP) wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; } if ((ic->ic_flags & IEEE80211_F_SCAN) && (ni->ni_flags & IEEE80211_NODE_PWR_MGT)) { ieee80211_add_callback(m, ieee80211_nulldata_transmitted, NULL); a263 2 m->m_len = m->m_pkthdr.len = hdrlen; m->m_flags |= M_ENCAP; /* mark encapsulated */ d265 1 a265 1 M_WME_SETAC(m, WME_AC_BE); d269 3 a271 3 IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, ni, "send %snull data frame on channel %u, pwr mgt %s", ni->ni_flags & IEEE80211_NODE_QOS ? "QoS " : "", d275 4 a278 3 ret = ieee80211_raw_output(vap, ni, m, NULL); IEEE80211_TX_UNLOCK(ic); return (ret); d288 2 a289 1 ieee80211_classify(struct ieee80211_node *ni, struct mbuf *m) a290 2 const struct ether_header *eh = NULL; uint16_t ether_type; d292 3 a295 42 if (__predict_false(m->m_flags & M_ENCAP)) { struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); struct llc *llc; int hdrlen, subtype; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; if (subtype & IEEE80211_FC0_SUBTYPE_NODATA) { ac = WME_AC_BE; goto done; } hdrlen = ieee80211_hdrsize(wh); if (m->m_pkthdr.len < hdrlen + sizeof(*llc)) return 1; llc = (struct llc *)mtodo(m, hdrlen); if (llc->llc_dsap != LLC_SNAP_LSAP || llc->llc_ssap != LLC_SNAP_LSAP || llc->llc_control != LLC_UI || llc->llc_snap.org_code[0] != 0 || llc->llc_snap.org_code[1] != 0 || llc->llc_snap.org_code[2] != 0) return 1; ether_type = llc->llc_snap.ether_type; } else { eh = mtod(m, struct ether_header *); ether_type = eh->ether_type; } /* * Always promote PAE/EAPOL frames to high priority. */ if (ether_type == htons(ETHERTYPE_PAE)) { /* NB: mark so others don't need to check header */ m->m_flags |= M_EAPOL; ac = WME_AC_VO; goto done; } /* * Non-qos traffic goes to BE. */ d307 2 a308 1 if ((m->m_flags & M_VLANTAG) == 0) { d312 1 a312 1 if (EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) != d318 18 a335 1 v_wme_ac = TID_TO_WME_AC(EVL_PRIOFTAG(ni->ni_vlan)); a337 1 /* XXX m_copydata may be too slow for fast path */ d339 26 a364 10 if (eh && eh->ether_type == htons(ETHERTYPE_IP)) { uint8_t tos; /* * IP frame, map the DSCP bits from the TOS field. */ /* NB: ip header may not be in first mbuf */ m_copydata(m, sizeof(struct ether_header) + offsetof(struct ip, ip_tos), sizeof(tos), &tos); tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ d_wme_ac = TID_TO_WME_AC(tos); a366 15 #ifdef INET6 if (eh && eh->ether_type == htons(ETHERTYPE_IPV6)) { uint32_t flow; uint8_t tos; /* * IPv6 frame, map the DSCP bits from the traffic class field. */ m_copydata(m, sizeof(struct ether_header) + offsetof(struct ip6_hdr, ip6_flow), sizeof(flow), (caddr_t) &flow); tos = (uint8_t)(ntohl(flow) >> 20); tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ d_wme_ac = TID_TO_WME_AC(tos); } else { #endif /* INET6 */ a367 3 #ifdef INET6 } #endif d382 1 a382 1 if (ni->ni_vap->iv_opmode == IEEE80211_M_STA) { a388 2 struct ieee80211com *ic = ni->ni_ic; d403 3 d407 2 a408 2 struct mbuf * ieee80211_mbuf_adjust(struct ieee80211vap *vap, int hdrsize, d412 2 a413 1 int needed_space = vap->iv_ic->ic_headroom + hdrsize; a418 15 /* * When crypto is being done in the host we must insure * the data are writable for the cipher routines; clone * a writable mbuf chain. * XXX handle SWMIC specially */ if (key->wk_flags & (IEEE80211_KEY_SWENCRYPT|IEEE80211_KEY_SWENMIC)) { m = m_unshare(m, M_NOWAIT); if (m == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, "%s: cannot get writable mbuf\n", __func__); vap->iv_stats.is_tx_nobuf++; /* XXX new stat */ return NULL; } } d420 1 d433 1 a433 3 IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, "%s: cannot expand storage\n", __func__); vap->iv_stats.is_tx_nobuf++; d437 4 a440 2 KASSERT(needed_space <= MHLEN, ("not enough room, need %u got %d\n", needed_space, MHLEN)); d447 2 a448 3 /* NB: must be first 'cuz it clobbers m_data */ m_move_pkthdr(n, m); n->m_len = 0; /* NB: m_gethdr does not set */ d450 1 a456 1 /* NB: struct ether_header is known to be contiguous */ d460 1 d466 19 d486 1 d497 1 a497 2 ieee80211_crypto_getucastkey(struct ieee80211vap *vap, struct ieee80211_node *ni) d499 3 a501 3 if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) { if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) d503 1 a503 1 return &vap->iv_nw_keys[vap->iv_def_txkey]; d515 2 a516 2 ieee80211_crypto_getmcastkey(struct ieee80211vap *vap, struct ieee80211_node *ni) d518 2 a519 2 if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) d521 1 a521 1 return &vap->iv_nw_keys[vap->iv_def_txkey]; a528 3 * * NB: Packet is assumed to be processed by ieee80211_classify which * marked EAPOL frames w/ M_EAPOL. d531 2 a532 2 ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni, struct mbuf *m) a533 9 #define WH4(wh) ((struct ieee80211_frame_addr4 *)(wh)) #define MC01(mc) ((struct ieee80211_meshcntl_ae01 *)mc) struct ieee80211com *ic = ni->ni_ic; #ifdef IEEE80211_SUPPORT_MESH struct ieee80211_mesh_state *ms = vap->iv_mesh; struct ieee80211_meshcntl_ae10 *mc; struct ieee80211_mesh_route *rt = NULL; int dir = -1; #endif d538 1 a538 9 int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr, is_mcast; ieee80211_seq seqno; int meshhdrsize, meshae; uint8_t *qos; int is_amsdu = 0; IEEE80211_TX_LOCK_ASSERT(ic); is_mcast = !! (m->m_flags & (M_MCAST | M_BCAST)); d540 2 a541 7 /* * Copy existing Ethernet header to a safe place. The * rest of the code assumes it's ok to strip it when * reorganizing state for the final encapsulation. */ KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!")); ETHER_HEADER_COPY(&eh, mtod(m, caddr_t)); d555 13 a567 15 if (vap->iv_flags & IEEE80211_F_PRIVACY) { if (vap->iv_opmode == IEEE80211_M_STA || !IEEE80211_IS_MULTICAST(eh.ether_dhost) || (vap->iv_opmode == IEEE80211_M_WDS && (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY))) key = ieee80211_crypto_getucastkey(vap, ni); else key = ieee80211_crypto_getmcastkey(vap, ni); if (key == NULL && (m->m_flags & M_EAPOL) == 0) { IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, eh.ether_dhost, "no default transmit key (%s) deftxkey %u", __func__, vap->iv_def_txkey); vap->iv_stats.is_tx_nodefkey++; goto bad; d569 1 a569 1 } else d571 2 d574 2 a580 6 * * Don't send multicast QoS frames. * Technically multicast frames can be QoS if all stations in the * BSS are also QoS. * * NB: mesh data frames are QoS, including multicast frames. d582 2 a583 6 addqos = (((is_mcast == 0) && (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT))) || (vap->iv_opmode == IEEE80211_M_MBSS)) && (m->m_flags & M_EAPOL) == 0; a587 72 #ifdef IEEE80211_SUPPORT_MESH if (vap->iv_opmode == IEEE80211_M_MBSS) { /* * Mesh data frames are encapsulated according to the * rules of Section 11B.8.5 (p.139 of D3.0 spec). * o Group Addressed data (aka multicast) originating * at the local sta are sent w/ 3-address format and * address extension mode 00 * o Individually Addressed data (aka unicast) originating * at the local sta are sent w/ 4-address format and * address extension mode 00 * o Group Addressed data forwarded from a non-mesh sta are * sent w/ 3-address format and address extension mode 01 * o Individually Address data from another sta are sent * w/ 4-address format and address extension mode 10 */ is4addr = 0; /* NB: don't use, disable */ if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) { rt = ieee80211_mesh_rt_find(vap, eh.ether_dhost); KASSERT(rt != NULL, ("route is NULL")); dir = IEEE80211_FC1_DIR_DSTODS; hdrsize += IEEE80211_ADDR_LEN; if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) { if (IEEE80211_ADDR_EQ(rt->rt_mesh_gate, vap->iv_myaddr)) { IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, eh.ether_dhost, "%s", "trying to send to ourself"); goto bad; } meshae = IEEE80211_MESH_AE_10; meshhdrsize = sizeof(struct ieee80211_meshcntl_ae10); } else { meshae = IEEE80211_MESH_AE_00; meshhdrsize = sizeof(struct ieee80211_meshcntl); } } else { dir = IEEE80211_FC1_DIR_FROMDS; if (!IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) { /* proxy group */ meshae = IEEE80211_MESH_AE_01; meshhdrsize = sizeof(struct ieee80211_meshcntl_ae01); } else { /* group */ meshae = IEEE80211_MESH_AE_00; meshhdrsize = sizeof(struct ieee80211_meshcntl); } } } else { #endif /* * 4-address frames need to be generated for: * o packets sent through a WDS vap (IEEE80211_M_WDS) * o packets sent through a vap marked for relaying * (e.g. a station operating with dynamic WDS) */ is4addr = vap->iv_opmode == IEEE80211_M_WDS || ((vap->iv_flags_ext & IEEE80211_FEXT_4ADDR) && !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)); if (is4addr) hdrsize += IEEE80211_ADDR_LEN; meshhdrsize = meshae = 0; #ifdef IEEE80211_SUPPORT_MESH } #endif /* * Honor driver DATAPAD requirement. */ d589 1 a589 3 hdrspace = roundup(hdrsize, sizeof(uint32_t)); else hdrspace = hdrsize; d591 4 a594 37 if (__predict_true((m->m_flags & M_FF) == 0)) { /* * Normal frame. */ m = ieee80211_mbuf_adjust(vap, hdrspace + meshhdrsize, key, m); if (m == NULL) { /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ goto bad; } /* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */ m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); llc = mtod(m, struct llc *); llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_control = LLC_UI; llc->llc_snap.org_code[0] = 0; llc->llc_snap.org_code[1] = 0; llc->llc_snap.org_code[2] = 0; llc->llc_snap.ether_type = eh.ether_type; } else { #ifdef IEEE80211_SUPPORT_SUPERG /* * Aggregated frame. Check if it's for AMSDU or FF. * * XXX TODO: IEEE80211_NODE_AMSDU* isn't implemented * anywhere for some reason. But, since 11n requires * AMSDU RX, we can just assume "11n" == "AMSDU". */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, "%s: called; M_FF\n", __func__); if (ieee80211_amsdu_tx_ok(ni)) { m = ieee80211_amsdu_encap(vap, m, hdrspace + meshhdrsize, key); is_amsdu = 1; } else { m = ieee80211_ff_encap(vap, m, hdrspace + meshhdrsize, key); } if (m == NULL) #endif goto bad; d596 10 d608 1 a608 1 M_PREPEND(m, hdrspace + meshhdrsize, M_NOWAIT); d610 1 a610 1 vap->iv_stats.is_tx_nobuf++; d613 1 d616 3 a618 9 *(uint16_t *)wh->i_dur = 0; qos = NULL; /* NB: quiet compiler */ if (is4addr) { wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); } else switch (vap->iv_opmode) { d625 1 d632 1 a632 1 * NB: always use the bssid from iv_bss as the d635 1 a635 1 IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid); d637 1 d639 1 d644 1 d646 2 a647 64 #ifdef IEEE80211_SUPPORT_MESH case IEEE80211_M_MBSS: /* NB: offset by hdrspace to deal with DATAPAD */ mc = (struct ieee80211_meshcntl_ae10 *) (mtod(m, uint8_t *) + hdrspace); wh->i_fc[1] = dir; switch (meshae) { case IEEE80211_MESH_AE_00: /* no proxy */ mc->mc_flags = 0; if (dir == IEEE80211_FC1_DIR_DSTODS) { /* ucast */ IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); qos =((struct ieee80211_qosframe_addr4 *) wh)->i_qos; } else if (dir == IEEE80211_FC1_DIR_FROMDS) { /* mcast */ IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); qos = ((struct ieee80211_qosframe *) wh)->i_qos; } break; case IEEE80211_MESH_AE_01: /* mcast, proxy */ wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_myaddr); mc->mc_flags = 1; IEEE80211_ADDR_COPY(MC01(mc)->mc_addr4, eh.ether_shost); qos = ((struct ieee80211_qosframe *) wh)->i_qos; break; case IEEE80211_MESH_AE_10: /* ucast, proxy */ KASSERT(rt != NULL, ("route is NULL")); IEEE80211_ADDR_COPY(wh->i_addr1, rt->rt_nexthop); IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, rt->rt_mesh_gate); IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, vap->iv_myaddr); mc->mc_flags = IEEE80211_MESH_AE_10; IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_dhost); IEEE80211_ADDR_COPY(mc->mc_addr6, eh.ether_shost); qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; break; default: KASSERT(0, ("meshae %d", meshae)); break; } mc->mc_ttl = ms->ms_ttl; ms->ms_seq++; le32enc(mc->mc_seq, ms->ms_seq); break; #endif case IEEE80211_M_WDS: /* NB: is4addr should always be true */ default: d650 1 d653 1 d655 2 a658 5 if (is4addr) { qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; /* NB: mesh case handled earlier */ } else if (vap->iv_opmode != IEEE80211_M_MBSS) qos = ((struct ieee80211_qosframe *) wh)->i_qos; d662 1 a662 1 qos[0] = tid & IEEE80211_QOS_TID; d664 7 a670 58 qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; #ifdef IEEE80211_SUPPORT_MESH if (vap->iv_opmode == IEEE80211_M_MBSS) qos[1] = IEEE80211_QOS_MC; else #endif qos[1] = 0; wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; /* * If this is an A-MSDU then ensure we set the * relevant field. */ if (is_amsdu) qos[0] |= IEEE80211_QOS_AMSDU; /* * XXX TODO TX lock is needed for atomic updates of sequence * numbers. If the driver does it, then don't do it here; * and we don't need the TX lock held. */ if ((m->m_flags & M_AMPDU_MPDU) == 0) { /* * 802.11-2012 9.3.2.10 - * * If this is a multicast frame then we need * to ensure that the sequence number comes from * a separate seqno space and not the TID space. * * Otherwise multicast frames may actually cause * holes in the TX blockack window space and * upset various things. */ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; else seqno = ni->ni_txseqs[tid]++; /* * NB: don't assign a sequence # to potential * aggregates; we expect this happens at the * point the frame comes off any aggregation q * as otherwise we may introduce holes in the * BA sequence space and/or make window accouting * more difficult. * * XXX may want to control this with a driver * capability; this may also change when we pull * aggregation up into net80211 */ seqno = ni->ni_txseqs[tid]++; *(uint16_t *)wh->i_seq = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); M_SEQNO_SET(m, seqno); } else { /* NB: zero out i_seq field (for s/w encryption etc) */ *(uint16_t *)wh->i_seq = 0; } d672 3 a674 17 /* * XXX TODO TX lock is needed for atomic updates of sequence * numbers. If the driver does it, then don't do it here; * and we don't need the TX lock held. */ seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; *(uint16_t *)wh->i_seq = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); M_SEQNO_SET(m, seqno); /* * XXX TODO: we shouldn't allow EAPOL, etc that would * be forced to be non-QoS traffic to be A-MSDU encapsulated. */ if (is_amsdu) printf("%s: XXX ERROR: is_amsdu set; not QoS!\n", __func__); d677 4 a680 13 /* * Check if xmit fragmentation is required. * * If the hardware does fragmentation offload, then don't bother * doing it here. */ if (IEEE80211_CONF_FRAG_OFFLOAD(ic)) txfrag = 0; else txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold && !IEEE80211_IS_MULTICAST(wh->i_addr1) && (vap->iv_caps & IEEE80211_C_TXFRAG) && (m->m_flags & (M_FF | M_AMPDU_MPDU)) == 0); d687 11 a697 11 if ((m->m_flags & M_EAPOL) == 0 || ((vap->iv_flags & IEEE80211_F_WPA) && (vap->iv_opmode == IEEE80211_M_STA ? !IEEE80211_KEY_UNDEFINED(key) : !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) { wh->i_fc[1] |= IEEE80211_FC1_PROTECTED; if (!ieee80211_crypto_enmic(vap, key, m, txfrag)) { IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, eh.ether_dhost, "%s", "enmic failed, discard frame"); vap->iv_stats.is_crypto_enmicfail++; d702 3 a704 2 if (txfrag && !ieee80211_fragment(vap, m, hdrsize, key != NULL ? key->wk_cipher->ic_header : 0, vap->iv_fragthreshold)) a706 2 m->m_flags |= M_ENCAP; /* mark encapsulated */ a707 5 if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { IEEE80211_NODE_STAT(ni, tx_mcast); m->m_flags |= M_MCAST; } else IEEE80211_NODE_STAT(ni, tx_ucast); d711 1 a715 2 #undef WH4 #undef MC01 d718 22 a739 2 void ieee80211_free_mbuf(struct mbuf *m) d741 132 a872 1 struct mbuf *next; d874 22 a895 2 if (m == NULL) return; d897 6 a902 5 do { next = m->m_nextpkt; m->m_nextpkt = NULL; m_freem(m); } while ((m = next) != NULL); d914 1 a914 1 ieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0, a916 1 struct ieee80211com *ic = vap->iv_ic; d918 3 a920 3 struct mbuf *m, *prev; u_int totalhdrsize, fragno, fragsize, off, remainder, payload; u_int hdrspace; d922 2 a923 2 KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?")); KASSERT(m0->m_pkthdr.len > mtu, a925 8 /* * Honor driver DATAPAD requirement. */ if (ic->ic_flags & IEEE80211_F_DATAPAD) hdrspace = roundup(hdrsize, sizeof(uint32_t)); else hdrspace = hdrsize; d929 1 a929 1 totalhdrsize = hdrspace + ciphdrsize; d935 9 a943 2 fragsize = MIN(totalhdrsize + remainder, mtu); m = m_get2(fragsize, M_NOWAIT, MT_DATA, M_PKTHDR); d946 1 a954 1 * NB: frag 1+ dont have Mesh Control field present. d958 1 a958 11 #ifdef IEEE80211_SUPPORT_MESH if (vap->iv_opmode == IEEE80211_M_MBSS) { if (IEEE80211_IS_DSTODS(wh)) ((struct ieee80211_qosframe_addr4 *) whf)->i_qos[1] &= ~IEEE80211_QOS_MC; else ((struct ieee80211_qosframe *) whf)->i_qos[1] &= ~IEEE80211_QOS_MC; } #endif *(uint16_t *)&whf->i_seq[0] |= htole16( d965 3 a967 4 m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrspace); m->m_len = hdrspace + payload; m->m_pkthdr.len = hdrspace + payload; a978 2 /* set the last fragment */ m->m_flags |= M_LASTFRAG; d985 2 a986 2 vap->iv_stats.is_tx_fragframes++; vap->iv_stats.is_tx_frags += fragno-1; d989 1 d992 5 a996 1 ieee80211_free_mbuf(m0->m_nextpkt); d998 1 d1005 2 a1006 2 uint8_t * ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) d1022 2 a1023 2 uint8_t * ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) d1039 1 a1039 1 * Add an ssid element to a frame. d1041 2 a1042 2 uint8_t * ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) d1053 2 a1054 2 static uint8_t * ieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic) d1056 1 a1056 1 uint8_t erp; d1071 2 a1072 5 /* * Add a CFParams element to a frame. */ static uint8_t * ieee80211_add_cfparms(uint8_t *frm, struct ieee80211com *ic) d1074 5 a1078 3 #define ADDSHORT(frm, v) do { \ le16enc(frm, v); \ frm += 2; \ d1080 71 a1150 6 *frm++ = IEEE80211_ELEMID_CFPARMS; *frm++ = 6; *frm++ = 0; /* CFP count */ *frm++ = 2; /* CFP period */ ADDSHORT(frm, 0); /* CFP MaxDuration (TU) */ ADDSHORT(frm, 0); /* CFP CurRemaining (TU) */ d1153 2 d1157 2 a1158 2 static __inline uint8_t * add_appie(uint8_t *frm, const struct ieee80211_appie *ie) d1160 9 a1168 41 memcpy(frm, ie->ie_data, ie->ie_len); return frm + ie->ie_len; } static __inline uint8_t * add_ie(uint8_t *frm, const uint8_t *ie) { memcpy(frm, ie, 2 + ie[1]); return frm + 2 + ie[1]; } #define WME_OUI_BYTES 0x00, 0x50, 0xf2 /* * Add a WME information element to a frame. */ uint8_t * ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme) { static const struct ieee80211_wme_info info = { .wme_id = IEEE80211_ELEMID_VENDOR, .wme_len = sizeof(struct ieee80211_wme_info) - 2, .wme_oui = { WME_OUI_BYTES }, .wme_type = WME_OUI_TYPE, .wme_subtype = WME_INFO_OUI_SUBTYPE, .wme_version = WME_VERSION, .wme_info = 0, }; memcpy(frm, &info, sizeof(info)); return frm + sizeof(info); } /* * Add a WME parameters element to a frame. */ static uint8_t * ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme) { #define SM(_v, _f) (((_v) << _f##_S) & _f) #define ADDSHORT(frm, v) do { \ le16enc(frm, v); \ frm += 2; \ d1170 7 a1176 8 /* NB: this works 'cuz a param has an info at the front */ static const struct ieee80211_wme_info param = { .wme_id = IEEE80211_ELEMID_VENDOR, .wme_len = sizeof(struct ieee80211_wme_param) - 2, .wme_oui = { WME_OUI_BYTES }, .wme_type = WME_OUI_TYPE, .wme_subtype = WME_PARAM_OUI_SUBTYPE, .wme_version = WME_VERSION, d1178 22 a1199 1 int i; d1201 33 a1233 16 memcpy(frm, ¶m, sizeof(param)); frm += __offsetof(struct ieee80211_wme_info, wme_info); *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */ *frm++ = 0; /* reserved field */ for (i = 0; i < WME_NUM_AC; i++) { const struct wmeParams *ac = &wme->wme_bssChanParams.cap_wmeParams[i]; *frm++ = SM(i, WME_PARAM_ACI) | SM(ac->wmep_acm, WME_PARAM_ACM) | SM(ac->wmep_aifsn, WME_PARAM_AIFSN) ; *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN) ; ADDSHORT(frm, ac->wmep_txopLimit); } d1235 1 a1235 1 #undef SM d1237 1 a1237 79 } #undef WME_OUI_BYTES /* * Add an 11h Power Constraint element to a frame. */ static uint8_t * ieee80211_add_powerconstraint(uint8_t *frm, struct ieee80211vap *vap) { const struct ieee80211_channel *c = vap->iv_bss->ni_chan; /* XXX per-vap tx power limit? */ int8_t limit = vap->iv_ic->ic_txpowlimit / 2; frm[0] = IEEE80211_ELEMID_PWRCNSTR; frm[1] = 1; frm[2] = c->ic_maxregpower > limit ? c->ic_maxregpower - limit : 0; return frm + 3; } /* * Add an 11h Power Capability element to a frame. */ static uint8_t * ieee80211_add_powercapability(uint8_t *frm, const struct ieee80211_channel *c) { frm[0] = IEEE80211_ELEMID_PWRCAP; frm[1] = 2; frm[2] = c->ic_minpower; frm[3] = c->ic_maxpower; return frm + 4; } /* * Add an 11h Supported Channels element to a frame. */ static uint8_t * ieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic) { static const int ielen = 26; frm[0] = IEEE80211_ELEMID_SUPPCHAN; frm[1] = ielen; /* XXX not correct */ memcpy(frm+2, ic->ic_chan_avail, ielen); return frm + 2 + ielen; } /* * Add an 11h Quiet time element to a frame. */ static uint8_t * ieee80211_add_quiet(uint8_t *frm, struct ieee80211vap *vap, int update) { struct ieee80211_quiet_ie *quiet = (struct ieee80211_quiet_ie *) frm; quiet->quiet_ie = IEEE80211_ELEMID_QUIET; quiet->len = 6; /* * Only update every beacon interval - otherwise probe responses * would update the quiet count value. */ if (update) { if (vap->iv_quiet_count_value == 1) vap->iv_quiet_count_value = vap->iv_quiet_count; else if (vap->iv_quiet_count_value > 1) vap->iv_quiet_count_value--; } if (vap->iv_quiet_count_value == 0) { /* value 0 is reserved as per 802.11h standerd */ vap->iv_quiet_count_value = 1; } quiet->tbttcount = vap->iv_quiet_count_value; quiet->period = vap->iv_quiet_period; quiet->duration = htole16(vap->iv_quiet_duration); quiet->offset = htole16(vap->iv_quiet_offset); return frm + sizeof(*quiet); d1241 1 a1241 4 * Add an 11h Channel Switch Announcement element to a frame. * Note that we use the per-vap CSA count to adjust the global * counter so we can use this routine to form probe response * frames and get the current count. d1243 2 a1244 2 static uint8_t * ieee80211_add_csa(uint8_t *frm, struct ieee80211vap *vap) a1245 2 struct ieee80211com *ic = vap->iv_ic; struct ieee80211_csa_ie *csa = (struct ieee80211_csa_ie *) frm; d1247 6 a1252 6 csa->csa_ie = IEEE80211_ELEMID_CSA; csa->csa_len = 3; csa->csa_mode = 1; /* XXX force quiet on channel */ csa->csa_newchan = ieee80211_chan2ieee(ic, ic->ic_csa_newchan); csa->csa_count = ic->ic_csa_count - vap->iv_csa_count; return frm + sizeof(*csa); d1255 1 d1257 1 a1257 1 * Add an 11h country information element to a frame. d1259 2 a1260 2 static uint8_t * ieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic) d1262 11 a1272 16 if (ic->ic_countryie == NULL || ic->ic_countryie_chan != ic->ic_bsschan) { /* * Handle lazy construction of ie. This is done on * first use and after a channel change that requires * re-calculation. */ if (ic->ic_countryie != NULL) IEEE80211_FREE(ic->ic_countryie, M_80211_NODE_IE); ic->ic_countryie = ieee80211_alloc_countryie(ic); if (ic->ic_countryie == NULL) return frm; ic->ic_countryie_chan = ic->ic_bsschan; } return add_appie(frm, ic->ic_countryie); d1275 5 a1279 2 uint8_t * ieee80211_add_wpa(uint8_t *frm, const struct ieee80211vap *vap) d1281 16 a1296 7 if (vap->iv_flags & IEEE80211_F_WPA1 && vap->iv_wpa_ie != NULL) return (add_ie(frm, vap->iv_wpa_ie)); else { /* XXX else complain? */ return (frm); } } d1298 13 a1310 8 uint8_t * ieee80211_add_rsn(uint8_t *frm, const struct ieee80211vap *vap) { if (vap->iv_flags & IEEE80211_F_WPA2 && vap->iv_rsn_ie != NULL) return (add_ie(frm, vap->iv_rsn_ie)); else { /* XXX else complain? */ return (frm); a1311 1 } d1313 3 a1315 10 uint8_t * ieee80211_add_qos(uint8_t *frm, const struct ieee80211_node *ni) { if (ni->ni_flags & IEEE80211_NODE_QOS) { *frm++ = IEEE80211_ELEMID_QOS; *frm++ = 1; *frm++ = 0; } return (frm); d1317 1 d1325 5 a1329 4 const uint8_t sa[IEEE80211_ADDR_LEN], const uint8_t da[IEEE80211_ADDR_LEN], const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t *ssid, size_t ssidlen) a1330 1 struct ieee80211vap *vap = ni->ni_vap; d1332 2 a1333 4 struct ieee80211_node *bss; const struct ieee80211_txparam *tp; struct ieee80211_bpf_params params; const struct ieee80211_rateset *rs; d1335 1 a1335 12 uint8_t *frm; int ret; bss = ieee80211_ref_node(vap->iv_bss); if (vap->iv_state == IEEE80211_S_CAC) { IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni, "block %s frame in CAC state", "probe request"); vap->iv_stats.is_tx_badstate++; ieee80211_free_node(bss); return EIO; /* XXX */ } d1342 1 a1342 1 IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, a1352 1 * [tlv] RSN (optional) a1353 3 * [tlv] HT cap (optional) * [tlv] VHT cap (optional) * [tlv] WPA (optional) d1357 1 a1357 2 ic->ic_headroom + sizeof(struct ieee80211_frame), 2 + IEEE80211_NWID_LEN a1358 4 + sizeof(struct ieee80211_ie_htcap) + sizeof(struct ieee80211_ie_vhtcap) + sizeof(struct ieee80211_ie_htinfo) /* XXX not needed? */ + sizeof(struct ieee80211_ie_wpa) d1360 1 a1360 3 + sizeof(struct ieee80211_ie_wpa) + (vap->iv_appie_probereq != NULL ? vap->iv_appie_probereq->ie_len : 0) d1363 1 a1363 1 vap->iv_stats.is_tx_nobuf++; a1364 1 ieee80211_free_node(bss); d1369 3 a1371 24 rs = ieee80211_get_suprates(ic, ic->ic_curchan); frm = ieee80211_add_rates(frm, rs); frm = ieee80211_add_rsn(frm, vap); frm = ieee80211_add_xrates(frm, rs); /* * Note: we can't use bss; we don't have one yet. * * So, we should announce our capabilities * in this channel mode (2g/5g), not the * channel details itself. */ if ((vap->iv_opmode == IEEE80211_M_IBSS) && (vap->iv_flags_ht & IEEE80211_FHT_HT)) { struct ieee80211_channel *c; /* * Get the HT channel that we should try upgrading to. * If we can do 40MHz then this'll upgrade it appropriately. */ c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan, vap->iv_flags_ht); frm = ieee80211_add_htcap_ch(frm, vap, c); } d1373 3 a1375 12 /* * XXX TODO: need to figure out what/how to update the * VHT channel. */ #if 0 (vap->iv_flags_vht & IEEE80211_FVHT_VHT) { struct ieee80211_channel *c; c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan, vap->iv_flags_ht); c = ieee80211_vht_adjust_channel(ic, c, vap->iv_flags_vht); frm = ieee80211_add_vhtcap_ch(frm, vap, c); d1377 1 a1377 1 #endif d1379 1 a1379 8 frm = ieee80211_add_wpa(frm, vap); if (vap->iv_appie_probereq != NULL) frm = add_appie(frm, vap->iv_appie_probereq); m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame), ("leading space %zd", M_LEADINGSPACE(m))); M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); d1381 1 a1381 1 /* NB: cannot happen */ a1382 1 ieee80211_free_node(bss); d1385 1 d1387 4 a1390 4 IEEE80211_TX_LOCK(ic); ieee80211_send_setup(ni, m, IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, IEEE80211_NONQOS_TID, sa, da, bssid); a1391 3 m->m_flags |= M_ENCAP; /* mark encapsulated */ M_WME_SETAC(m, WME_AC_BE); d1396 4 a1399 34 IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "send probe req on channel %u bssid %s sa %6D da %6D ssid \"%.*s\"\n", ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(bssid), sa, ":", da, ":", ssidlen, ssid); memset(¶ms, 0, sizeof(params)); params.ibp_pri = M_WME_GETAC(m); tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; params.ibp_rate0 = tp->mgmtrate; if (IEEE80211_IS_MULTICAST(da)) { params.ibp_flags |= IEEE80211_BPF_NOACK; params.ibp_try0 = 1; } else params.ibp_try0 = tp->maxretry; params.ibp_power = ni->ni_txpower; ret = ieee80211_raw_output(vap, ni, m, ¶ms); IEEE80211_TX_UNLOCK(ic); ieee80211_free_node(bss); return (ret); } /* * Calculate capability information for mgt frames. */ uint16_t ieee80211_getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan) { struct ieee80211com *ic = vap->iv_ic; uint16_t capinfo; KASSERT(vap->iv_opmode != IEEE80211_M_STA, ("station mode")); d1401 3 a1403 16 if (vap->iv_opmode == IEEE80211_M_HOSTAP) capinfo = IEEE80211_CAPINFO_ESS; else if (vap->iv_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = 0; if (vap->iv_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; if (IEEE80211_IS_CHAN_5GHZ(chan) && (vap->iv_flags & IEEE80211_F_DOTH)) capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; return capinfo; d1412 2 a1413 1 ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg) d1415 1 a1415 6 #define HTFLAGS (IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT) #define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0) struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ieee80211_node *bss = vap->iv_bss; struct ieee80211_bpf_params params; d1417 3 a1419 3 uint8_t *frm; uint16_t capinfo; int has_challenge, is_shared_key, ret, status; d1421 1 a1421 1 KASSERT(ni != NULL, ("null node")); d1428 1 a1428 1 IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, d1435 1 a1435 1 memset(¶ms, 0, sizeof(params)); d1437 106 d1544 1 a1544 1 case IEEE80211_FC0_SUBTYPE_AUTH: d1547 4 a1550 3 has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || arg == IEEE80211_AUTH_SHARED_RESPONSE) && ni->ni_challenge != NULL); d1559 11 a1569 4 is_shared_key = has_challenge || arg >= IEEE80211_AUTH_SHARED_RESPONSE || (arg == IEEE80211_AUTH_SHARED_REQUEST && bss->ni_authmode == IEEE80211_AUTH_SHARED); d1571 1 a1571 6 m = ieee80211_getmgtframe(&frm, ic->ic_headroom + sizeof(struct ieee80211_frame), 3 * sizeof(uint16_t) + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0) ); d1575 2 a1576 2 ((uint16_t *)frm)[0] = (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED) d1578 2 a1579 2 ((uint16_t *)frm)[1] = htole16(arg); /* sequence number */ ((uint16_t *)frm)[2] = htole16(status);/* status */ d1581 2 a1582 2 if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { ((uint16_t *)frm)[3] = d1585 1 a1585 1 memcpy(&((uint16_t *)frm)[4], ni->ni_challenge, d1587 1 a1587 2 m->m_pkthdr.len = m->m_len = 4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN; d1589 4 a1592 4 IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, "request encrypt frame (%s)", __func__); /* mark frame for encryption */ params.ibp_flags |= IEEE80211_BPF_CRYPTO; d1594 3 a1596 2 } else m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t); d1604 2 a1605 3 if (vap->iv_opmode == IEEE80211_M_STA) ieee80211_add_callback(m, ieee80211_tx_mgt_cb, (void *) vap->iv_state); d1607 1 d1610 4 a1613 6 IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, "send station deauthenticate (reason: %d (%s))", arg, ieee80211_reason_to_string(arg)); m = ieee80211_getmgtframe(&frm, ic->ic_headroom + sizeof(struct ieee80211_frame), sizeof(uint16_t)); d1616 2 a1617 2 *(uint16_t *)frm = htole16(arg); /* reason */ m->m_pkthdr.len = m->m_len = sizeof(uint16_t); d1635 2 a1636 8 * [4] power capability (optional) * [28] supported channels (optional) * [tlv] HT capabilities * [tlv] VHT capabilities * [tlv] WME (optional) * [tlv] Vendor OUI HT capabilities (optional) * [tlv] Atheros capabilities (if negotiated) * [tlv] AppIE's (optional) d1639 2 a1640 3 ic->ic_headroom + sizeof(struct ieee80211_frame), sizeof(uint16_t) + sizeof(uint16_t) a1644 2 + 4 + 2 + 26 d1646 1 a1646 10 + sizeof(struct ieee80211_ie_htcap) + sizeof(struct ieee80211_ie_vhtcap) + 4 + sizeof(struct ieee80211_ie_htcap) #ifdef IEEE80211_SUPPORT_SUPERG + sizeof(struct ieee80211_ath_ie) #endif + (vap->iv_appie_wpa != NULL ? vap->iv_appie_wpa->ie_len : 0) + (vap->iv_appie_assocreq != NULL ? vap->iv_appie_assocreq->ie_len : 0) d1651 6 a1656 4 KASSERT(vap->iv_opmode == IEEE80211_M_STA, ("wrong mode %u", vap->iv_opmode)); capinfo = IEEE80211_CAPINFO_ESS; if (vap->iv_flags & IEEE80211_F_PRIVACY) d1660 1 a1660 1 * short preamble is set. d1665 1 a1665 1 if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) && d1668 1 a1668 4 if ((ni->ni_capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) && (vap->iv_flags & IEEE80211_F_DOTH)) capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; *(uint16_t *)frm = htole16(capinfo); d1671 1 a1671 3 KASSERT(bss->ni_intval != 0, ("beacon interval is zero!")); *(uint16_t *)frm = htole16(howmany(ic->ic_lintval, bss->ni_intval)); d1675 1 a1675 1 IEEE80211_ADDR_COPY(frm, bss->ni_bssid); a1680 1 frm = ieee80211_add_rsn(frm, vap); d1682 1 a1682 28 if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) { frm = ieee80211_add_powercapability(frm, ic->ic_curchan); frm = ieee80211_add_supportedchannels(frm, ic); } /* * Check the channel - we may be using an 11n NIC with an * 11n capable station, but we're configured to be an 11b * channel. */ if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_ies.htcap_ie != NULL && ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) { frm = ieee80211_add_htcap(frm, ni); } if ((vap->iv_flags_vht & IEEE80211_FVHT_VHT) && IEEE80211_IS_CHAN_VHT(ni->ni_chan) && ni->ni_ies.vhtcap_ie != NULL && ni->ni_ies.vhtcap_ie[0] == IEEE80211_ELEMID_VHT_CAP) { frm = ieee80211_add_vhtcap(frm, ni); } frm = ieee80211_add_wpa(frm, vap); if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_ies.wme_ie != NULL) d1684 3 a1686 10 /* * Same deal - only send HT info if we're on an 11n * capable channel. */ if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_ies.htcap_ie != NULL && ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) { frm = ieee80211_add_htcap_vendor(frm, ni); d1688 1 a1688 12 #ifdef IEEE80211_SUPPORT_SUPERG if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) { frm = ieee80211_add_ath(frm, IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), ((vap->iv_flags & IEEE80211_F_WPA) == 0 && ni->ni_authmode != IEEE80211_AUTH_8021X) ? vap->iv_def_txkey : IEEE80211_KEYIX_NONE); } #endif /* IEEE80211_SUPPORT_SUPERG */ if (vap->iv_appie_assocreq != NULL) frm = add_appie(frm, vap->iv_appie_assocreq); m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); d1690 1 a1690 2 ieee80211_add_callback(m, ieee80211_tx_mgt_cb, (void *) vap->iv_state); d1696 1 a1696 1 * asresp frame format d1702 1 a1702 9 * [tlv] HT capabilities (standard, if STA enabled) * [tlv] HT information (standard, if STA enabled) * [tlv] VHT capabilities (standard, if STA enabled) * [tlv] VHT information (standard, if STA enabled) * [tlv] WME (if configured and STA enabled) * [tlv] HT capabilities (vendor OUI, if STA enabled) * [tlv] HT information (vendor OUI, if STA enabled) * [tlv] Atheros capabilities (if STA enabled) * [tlv] AppIE's (optional) d1705 3 a1707 4 ic->ic_headroom + sizeof(struct ieee80211_frame), sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) a1709 4 + sizeof(struct ieee80211_ie_htcap) + 4 + sizeof(struct ieee80211_ie_htinfo) + 4 + sizeof(struct ieee80211_ie_vhtcap) + sizeof(struct ieee80211_ie_vht_operation) a1710 5 #ifdef IEEE80211_SUPPORT_SUPERG + sizeof(struct ieee80211_ath_ie) #endif + (vap->iv_appie_assocresp != NULL ? vap->iv_appie_assocresp->ie_len : 0) d1715 9 a1723 2 capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); *(uint16_t *)frm = htole16(capinfo); d1726 1 a1726 1 *(uint16_t *)frm = htole16(arg); /* status */ d1730 1 a1730 1 *(uint16_t *)frm = htole16(ni->ni_associd); d1732 2 a1733 1 } else d1735 1 d1740 1 a1740 7 /* NB: respond according to what we received */ if ((ni->ni_flags & HTFLAGS) == IEEE80211_NODE_HT) { frm = ieee80211_add_htcap(frm, ni); frm = ieee80211_add_htinfo(frm, ni); } if ((vap->iv_flags & IEEE80211_F_WME) && ni->ni_ies.wme_ie != NULL) d1742 1 a1742 35 if ((ni->ni_flags & HTFLAGS) == HTFLAGS) { frm = ieee80211_add_htcap_vendor(frm, ni); frm = ieee80211_add_htinfo_vendor(frm, ni); } if (ni->ni_flags & IEEE80211_NODE_VHT) { frm = ieee80211_add_vhtcap(frm, ni); frm = ieee80211_add_vhtinfo(frm, ni); } #ifdef IEEE80211_SUPPORT_SUPERG if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) frm = ieee80211_add_ath(frm, IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), ((vap->iv_flags & IEEE80211_F_WPA) == 0 && ni->ni_authmode != IEEE80211_AUTH_8021X) ? vap->iv_def_txkey : IEEE80211_KEYIX_NONE); #endif /* IEEE80211_SUPPORT_SUPERG */ if (vap->iv_appie_assocresp != NULL) frm = add_appie(frm, vap->iv_appie_assocresp); m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); break; case IEEE80211_FC0_SUBTYPE_DISASSOC: IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, "send station disassociate (reason: %d (%s))", arg, ieee80211_reason_to_string(arg)); m = ieee80211_getmgtframe(&frm, ic->ic_headroom + sizeof(struct ieee80211_frame), sizeof(uint16_t)); if (m == NULL) senderr(ENOMEM, is_tx_nobuf); *(uint16_t *)frm = htole16(arg); /* reason */ m->m_pkthdr.len = m->m_len = sizeof(uint16_t); IEEE80211_NODE_STAT(ni, tx_disassoc); IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg); d1745 9 a1753 239 default: IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, "invalid mgmt frame type %u", type); senderr(EINVAL, is_tx_unknownmgt); /* NOTREACHED */ } /* NB: force non-ProbeResp frames to the highest queue */ params.ibp_pri = WME_AC_VO; params.ibp_rate0 = bss->ni_txparms->mgmtrate; /* NB: we know all frames are unicast */ params.ibp_try0 = bss->ni_txparms->maxretry; params.ibp_power = bss->ni_txpower; return ieee80211_mgmt_output(ni, m, type, ¶ms); bad: ieee80211_free_node(ni); return ret; #undef senderr #undef HTFLAGS } /* * Return an mbuf with a probe response frame in it. * Space is left to prepend and 802.11 header at the * front but it's left to the caller to fill in. */ struct mbuf * ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy) { struct ieee80211vap *vap = bss->ni_vap; struct ieee80211com *ic = bss->ni_ic; const struct ieee80211_rateset *rs; struct mbuf *m; uint16_t capinfo; uint8_t *frm; /* * probe response frame format * [8] time stamp * [2] beacon interval * [2] cabability information * [tlv] ssid * [tlv] supported rates * [tlv] parameter set (FH/DS) * [tlv] parameter set (IBSS) * [tlv] country (optional) * [3] power control (optional) * [5] channel switch announcement (CSA) (optional) * [tlv] extended rate phy (ERP) * [tlv] extended supported rates * [tlv] RSN (optional) * [tlv] HT capabilities * [tlv] HT information * [tlv] VHT capabilities * [tlv] VHT information * [tlv] WPA (optional) * [tlv] WME (optional) * [tlv] Vendor OUI HT capabilities (optional) * [tlv] Vendor OUI HT information (optional) * [tlv] Atheros capabilities * [tlv] AppIE's (optional) * [tlv] Mesh ID (MBSS) * [tlv] Mesh Conf (MBSS) */ m = ieee80211_getmgtframe(&frm, ic->ic_headroom + sizeof(struct ieee80211_frame), 8 + sizeof(uint16_t) + sizeof(uint16_t) + 2 + IEEE80211_NWID_LEN + 2 + IEEE80211_RATE_SIZE + 7 /* max(7,3) */ + IEEE80211_COUNTRY_MAX_SIZE + 3 + sizeof(struct ieee80211_csa_ie) + sizeof(struct ieee80211_quiet_ie) + 3 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + sizeof(struct ieee80211_ie_wpa) + sizeof(struct ieee80211_ie_htcap) + sizeof(struct ieee80211_ie_htinfo) + sizeof(struct ieee80211_ie_wpa) + sizeof(struct ieee80211_wme_param) + 4 + sizeof(struct ieee80211_ie_htcap) + 4 + sizeof(struct ieee80211_ie_htinfo) + sizeof(struct ieee80211_ie_vhtcap) + sizeof(struct ieee80211_ie_vht_operation) #ifdef IEEE80211_SUPPORT_SUPERG + sizeof(struct ieee80211_ath_ie) #endif #ifdef IEEE80211_SUPPORT_MESH + 2 + IEEE80211_MESHID_LEN + sizeof(struct ieee80211_meshconf_ie) #endif + (vap->iv_appie_proberesp != NULL ? vap->iv_appie_proberesp->ie_len : 0) ); if (m == NULL) { vap->iv_stats.is_tx_nobuf++; return NULL; } memset(frm, 0, 8); /* timestamp should be filled later */ frm += 8; *(uint16_t *)frm = htole16(bss->ni_intval); frm += 2; capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); *(uint16_t *)frm = htole16(capinfo); frm += 2; frm = ieee80211_add_ssid(frm, bss->ni_essid, bss->ni_esslen); rs = ieee80211_get_suprates(ic, bss->ni_chan); frm = ieee80211_add_rates(frm, rs); if (IEEE80211_IS_CHAN_FHSS(bss->ni_chan)) { *frm++ = IEEE80211_ELEMID_FHPARMS; *frm++ = 5; *frm++ = bss->ni_fhdwell & 0x00ff; *frm++ = (bss->ni_fhdwell >> 8) & 0x00ff; *frm++ = IEEE80211_FH_CHANSET( ieee80211_chan2ieee(ic, bss->ni_chan)); *frm++ = IEEE80211_FH_CHANPAT( ieee80211_chan2ieee(ic, bss->ni_chan)); *frm++ = bss->ni_fhindex; } else { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, bss->ni_chan); } if (vap->iv_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ } if ((vap->iv_flags & IEEE80211_F_DOTH) || (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) frm = ieee80211_add_countryie(frm, ic); if (vap->iv_flags & IEEE80211_F_DOTH) { if (IEEE80211_IS_CHAN_5GHZ(bss->ni_chan)) frm = ieee80211_add_powerconstraint(frm, vap); if (ic->ic_flags & IEEE80211_F_CSAPENDING) frm = ieee80211_add_csa(frm, vap); } if (vap->iv_flags & IEEE80211_F_DOTH) { if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) { if (vap->iv_quiet) frm = ieee80211_add_quiet(frm, vap, 0); } } if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan)) frm = ieee80211_add_erp(frm, ic); frm = ieee80211_add_xrates(frm, rs); frm = ieee80211_add_rsn(frm, vap); /* * NB: legacy 11b clients do not get certain ie's. * The caller identifies such clients by passing * a token in legacy to us. Could expand this to be * any legacy client for stuff like HT ie's. */ if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && legacy != IEEE80211_SEND_LEGACY_11B) { frm = ieee80211_add_htcap(frm, bss); frm = ieee80211_add_htinfo(frm, bss); } if (IEEE80211_IS_CHAN_VHT(bss->ni_chan) && legacy != IEEE80211_SEND_LEGACY_11B) { frm = ieee80211_add_vhtcap(frm, bss); frm = ieee80211_add_vhtinfo(frm, bss); } frm = ieee80211_add_wpa(frm, vap); if (vap->iv_flags & IEEE80211_F_WME) frm = ieee80211_add_wme_param(frm, &ic->ic_wme); if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) && legacy != IEEE80211_SEND_LEGACY_11B) { frm = ieee80211_add_htcap_vendor(frm, bss); frm = ieee80211_add_htinfo_vendor(frm, bss); } #ifdef IEEE80211_SUPPORT_SUPERG if ((vap->iv_flags & IEEE80211_F_ATHEROS) && legacy != IEEE80211_SEND_LEGACY_11B) frm = ieee80211_add_athcaps(frm, bss); #endif if (vap->iv_appie_proberesp != NULL) frm = add_appie(frm, vap->iv_appie_proberesp); #ifdef IEEE80211_SUPPORT_MESH if (vap->iv_opmode == IEEE80211_M_MBSS) { frm = ieee80211_add_meshid(frm, vap); frm = ieee80211_add_meshconf(frm, vap); } #endif m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); return m; } /* * Send a probe response frame to the specified mac address. * This does not go through the normal mgt frame api so we * can specify the destination address and re-use the bss node * for the sta reference. */ int ieee80211_send_proberesp(struct ieee80211vap *vap, const uint8_t da[IEEE80211_ADDR_LEN], int legacy) { struct ieee80211_node *bss = vap->iv_bss; struct ieee80211com *ic = vap->iv_ic; struct mbuf *m; int ret; if (vap->iv_state == IEEE80211_S_CAC) { IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss, "block %s frame in CAC state", "probe response"); vap->iv_stats.is_tx_badstate++; return EIO; /* XXX */ } /* * Hold a reference on the node so it doesn't go away until after * the xmit is complete all the way in the driver. On error we * will remove our reference. */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__, bss, ether_sprintf(bss->ni_macaddr), ieee80211_node_refcnt(bss)+1); ieee80211_ref_node(bss); m = ieee80211_alloc_proberesp(bss, legacy); if (m == NULL) { ieee80211_free_node(bss); return ENOMEM; } M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); KASSERT(m != NULL, ("no room for header")); d1755 3 a1757 6 IEEE80211_TX_LOCK(ic); ieee80211_send_setup(bss, m, IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP, IEEE80211_NONQOS_TID, vap->iv_myaddr, da, bss->ni_bssid); /* XXX power management? */ m->m_flags |= M_ENCAP; /* mark encapsulated */ d1759 14 a1772 11 M_WME_SETAC(m, WME_AC_BE); IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "send probe resp on channel %u to %s%s\n", ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(da), legacy ? " " : ""); IEEE80211_NODE_STAT(bss, tx_mgmt); ret = ieee80211_raw_output(vap, bss, m, NULL); IEEE80211_TX_UNLOCK(ic); return (ret); d1776 1 a1776 1 * Allocate and build a RTS (Request To Send) control frame. d1779 2 a1780 4 ieee80211_alloc_rts(struct ieee80211com *ic, const uint8_t ra[IEEE80211_ADDR_LEN], const uint8_t ta[IEEE80211_ADDR_LEN], uint16_t dur) d1785 13 a1797 10 /* XXX honor ic_headroom */ m = m_gethdr(M_NOWAIT, MT_DATA); if (m != NULL) { rts = mtod(m, struct ieee80211_frame_rts *); rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(u_int16_t *)rts->i_dur = htole16(dur); IEEE80211_ADDR_COPY(rts->i_ra, ra); IEEE80211_ADDR_COPY(rts->i_ta, ta); a1798 2 m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts); } d1803 1 a1803 1 * Allocate and build a CTS (Clear To Send) control frame. d1806 1 a1806 2 ieee80211_alloc_cts(struct ieee80211com *ic, const uint8_t ra[IEEE80211_ADDR_LEN], uint16_t dur) d1811 12 a1822 9 /* XXX honor ic_headroom */ m = m_gethdr(M_NOWAIT, MT_DATA); if (m != NULL) { cts = mtod(m, struct ieee80211_frame_cts *); cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(u_int16_t *)cts->i_dur = htole16(dur); IEEE80211_ADDR_COPY(cts->i_ra, ra); a1823 2 m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts); } d1828 1 a1828 1 * Wrapper for CTS/RTS frame allocation. d1831 2 a1832 2 ieee80211_alloc_prot(struct ieee80211_node *ni, const struct mbuf *m, uint8_t rate, int prot) d1834 7 a1840 81 struct ieee80211com *ic = ni->ni_ic; const struct ieee80211_frame *wh; struct mbuf *mprot; uint16_t dur; int pktlen, isshort; KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, ("wrong protection type %d", prot)); wh = mtod(m, const struct ieee80211_frame *); pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) + ieee80211_ack_duration(ic->ic_rt, rate, isshort); if (prot == IEEE80211_PROT_RTSCTS) { /* NB: CTS is the same size as an ACK */ dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); } else mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); return (mprot); } static void ieee80211_tx_mgt_timeout(void *arg) { struct ieee80211vap *vap = arg; IEEE80211_LOCK(vap->iv_ic); if (vap->iv_state != IEEE80211_S_INIT && (vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) { /* * NB: it's safe to specify a timeout as the reason here; * it'll only be used in the right state. */ ieee80211_new_state_locked(vap, IEEE80211_S_SCAN, IEEE80211_SCAN_FAIL_TIMEOUT); } IEEE80211_UNLOCK(vap->iv_ic); } /* * This is the callback set on net80211-sourced transmitted * authentication request frames. * * This does a couple of things: * * + If the frame transmitted was a success, it schedules a future * event which will transition the interface to scan. * If a state transition _then_ occurs before that event occurs, * said state transition will cancel this callout. * * + If the frame transmit was a failure, it immediately schedules * the transition back to scan. */ static void ieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status) { struct ieee80211vap *vap = ni->ni_vap; enum ieee80211_state ostate = (enum ieee80211_state) arg; /* * Frame transmit completed; arrange timer callback. If * transmit was successfully we wait for response. Otherwise * we arrange an immediate callback instead of doing the * callback directly since we don't know what state the driver * is in (e.g. what locks it is holding). This work should * not be too time-critical and not happen too often so the * added overhead is acceptable. * * XXX what happens if !acked but response shows up before callback? */ if (vap->iv_state == ostate) { callout_reset(&vap->iv_mgtsend, status == 0 ? IEEE80211_TRANS_WAIT*hz : 0, ieee80211_tx_mgt_timeout, vap); } } d1842 1 a1842 9 static void ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; struct ieee80211com *ic = ni->ni_ic; struct ieee80211_rateset *rs = &ni->ni_rates; uint16_t capinfo; a1845 4 * * TODO: update to 802.11-2012; a lot of stuff has changed; * vendor extensions should be at the end, etc. * a1851 1 * [8] CF parameter set (optional) a1852 6 * [tlv] country (optional) * [3] power control (optional) * [5] channel switch announcement (CSA) (optional) * XXX TODO: Quiet * XXX TODO: IBSS DFS * XXX TODO: TPC report d1855 3 a1857 4 * [tlv] RSN parameters * XXX TODO: BSSLOAD * (XXX EDCA parameter set, QoS capability?) * XXX TODO: AP channel report d1859 2 a1860 28 * [tlv] HT capabilities * [tlv] HT information * XXX TODO: 20/40 BSS coexistence * Mesh: * XXX TODO: Meshid * XXX TODO: mesh config * XXX TODO: mesh awake window * XXX TODO: beacon timing (mesh, etc) * XXX TODO: MCCAOP Advertisement Overview * XXX TODO: MCCAOP Advertisement * XXX TODO: Mesh channel switch parameters * VHT: * XXX TODO: VHT capabilities * XXX TODO: VHT operation * XXX TODO: VHT transmit power envelope * XXX TODO: channel switch wrapper element * XXX TODO: extended BSS load element * * XXX Vendor-specific OIDs (e.g. Atheros) * [tlv] WPA parameters * [tlv] WME parameters * [tlv] Vendor OUI HT capabilities (optional) * [tlv] Vendor OUI HT information (optional) * [tlv] Atheros capabilities (optional) * [tlv] TDMA parameters (optional) * [tlv] Mesh ID (MBSS) * [tlv] Mesh Conf (MBSS) * [tlv] application data (optional) d1862 21 a1882 2 memset(bo, 0, sizeof(*bo)); d1886 2 a1887 1 *(uint16_t *)frm = htole16(ni->ni_intval); d1889 14 a1902 3 capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); bo->bo_caps = (uint16_t *)frm; *(uint16_t *)frm = htole16(capinfo); d1904 1 d1906 1 a1906 1 if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) { d1912 1 d1914 2 a1915 1 if (!IEEE80211_IS_CHAN_FHSS(ni->ni_chan)) { d1920 1 a1920 4 if (ic->ic_flags & IEEE80211_F_PCF) { bo->bo_cfp = frm; frm = ieee80211_add_cfparms(frm, ic); } d1922 1 a1922 1 if (vap->iv_opmode == IEEE80211_M_IBSS) { d1927 2 a1928 4 } else if (vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_MBSS) { /* TIM IE is the same for Mesh and Hostap */ struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; d1933 1 a1933 1 tie->tim_period = vap->iv_dtim_period; /* DTIM period */ a1938 51 bo->bo_tim_trailer = frm; if ((vap->iv_flags & IEEE80211_F_DOTH) || (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) frm = ieee80211_add_countryie(frm, ic); if (vap->iv_flags & IEEE80211_F_DOTH) { if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) frm = ieee80211_add_powerconstraint(frm, vap); bo->bo_csa = frm; if (ic->ic_flags & IEEE80211_F_CSAPENDING) frm = ieee80211_add_csa(frm, vap); } else bo->bo_csa = frm; bo->bo_quiet = NULL; if (vap->iv_flags & IEEE80211_F_DOTH) { if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && (vap->iv_flags_ext & IEEE80211_FEXT_DFS) && (vap->iv_quiet == 1)) { /* * We only insert the quiet IE offset if * the quiet IE is enabled. Otherwise don't * put it here or we'll just overwrite * some other beacon contents. */ if (vap->iv_quiet) { bo->bo_quiet = frm; frm = ieee80211_add_quiet(frm,vap, 0); } } } if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) { bo->bo_erp = frm; frm = ieee80211_add_erp(frm, ic); } frm = ieee80211_add_xrates(frm, rs); frm = ieee80211_add_rsn(frm, vap); if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { frm = ieee80211_add_htcap(frm, ni); bo->bo_htinfo = frm; frm = ieee80211_add_htinfo(frm, ni); } if (IEEE80211_IS_CHAN_VHT(ni->ni_chan)) { frm = ieee80211_add_vhtcap(frm, ni); bo->bo_vhtinfo = frm; frm = ieee80211_add_vhtinfo(frm, ni); /* Transmit power envelope */ /* Channel switch wrapper element */ /* Extended bss load element */ } d1940 2 a1941 2 frm = ieee80211_add_wpa(frm, vap); if (vap->iv_flags & IEEE80211_F_WME) { d1944 1 a1944 5 } if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT)) { frm = ieee80211_add_htcap_vendor(frm, ni); frm = ieee80211_add_htinfo_vendor(frm, ni); d1947 2 a1948 17 #ifdef IEEE80211_SUPPORT_SUPERG if (vap->iv_flags & IEEE80211_F_ATHEROS) { bo->bo_ath = frm; frm = ieee80211_add_athcaps(frm, ni); } #endif #ifdef IEEE80211_SUPPORT_TDMA if (vap->iv_caps & IEEE80211_C_TDMA) { bo->bo_tdma = frm; frm = ieee80211_add_tdma(frm, vap); } #endif if (vap->iv_appie_beacon != NULL) { bo->bo_appie = frm; bo->bo_appie_len = vap->iv_appie_beacon->ie_len; frm = add_appie(frm, vap->iv_appie_beacon); } d1950 2 a1951 12 /* XXX TODO: move meshid/meshconf up to before vendor extensions? */ #ifdef IEEE80211_SUPPORT_MESH if (vap->iv_opmode == IEEE80211_M_MBSS) { frm = ieee80211_add_meshid(frm, vap); bo->bo_meshconf = frm; frm = ieee80211_add_meshconf(frm, vap); } #endif bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer; bo->bo_csa_trailer_len = frm - bo->bo_csa; m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); } d1953 1 a1953 13 /* * Allocate a beacon frame and fillin the appropriate bits. */ struct mbuf * ieee80211_beacon_alloc(struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ifnet *ifp = vap->iv_ifp; struct ieee80211_frame *wh; struct mbuf *m; int pktlen; uint8_t *frm; d1955 2 a1956 7 /* * Update the "We're putting the quiet IE in the beacon" state. */ if (vap->iv_quiet == 1) vap->iv_flags_ext |= IEEE80211_FEXT_QUIET_IE; else if (vap->iv_quiet == 0) vap->iv_flags_ext &= ~IEEE80211_FEXT_QUIET_IE; d1958 2 a1959 80 /* * beacon frame format * * Note: This needs updating for 802.11-2012. * * [8] time stamp * [2] beacon interval * [2] cabability information * [tlv] ssid * [tlv] supported rates * [3] parameter set (DS) * [8] CF parameter set (optional) * [tlv] parameter set (IBSS/TIM) * [tlv] country (optional) * [3] power control (optional) * [5] channel switch announcement (CSA) (optional) * [tlv] extended rate phy (ERP) * [tlv] extended supported rates * [tlv] RSN parameters * [tlv] HT capabilities * [tlv] HT information * [tlv] VHT capabilities * [tlv] VHT operation * [tlv] Vendor OUI HT capabilities (optional) * [tlv] Vendor OUI HT information (optional) * XXX Vendor-specific OIDs (e.g. Atheros) * [tlv] WPA parameters * [tlv] WME parameters * [tlv] TDMA parameters (optional) * [tlv] Mesh ID (MBSS) * [tlv] Mesh Conf (MBSS) * [tlv] application data (optional) * NB: we allocate the max space required for the TIM bitmap. * XXX how big is this? */ pktlen = 8 /* time stamp */ + sizeof(uint16_t) /* beacon interval */ + sizeof(uint16_t) /* capabilities */ + 2 + ni->ni_esslen /* ssid */ + 2 + IEEE80211_RATE_SIZE /* supported rates */ + 2 + 1 /* DS parameters */ + 2 + 6 /* CF parameters */ + 2 + 4 + vap->iv_tim_len /* DTIM/IBSSPARMS */ + IEEE80211_COUNTRY_MAX_SIZE /* country */ + 2 + 1 /* power control */ + sizeof(struct ieee80211_csa_ie) /* CSA */ + sizeof(struct ieee80211_quiet_ie) /* Quiet */ + 2 + 1 /* ERP */ + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + (vap->iv_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ 2*sizeof(struct ieee80211_ie_wpa) : 0) /* XXX conditional? */ + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */ + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */ + sizeof(struct ieee80211_ie_vhtcap)/* VHT caps */ + sizeof(struct ieee80211_ie_vht_operation)/* VHT info */ + (vap->iv_caps & IEEE80211_C_WME ? /* WME */ sizeof(struct ieee80211_wme_param) : 0) #ifdef IEEE80211_SUPPORT_SUPERG + sizeof(struct ieee80211_ath_ie) /* ATH */ #endif #ifdef IEEE80211_SUPPORT_TDMA + (vap->iv_caps & IEEE80211_C_TDMA ? /* TDMA */ sizeof(struct ieee80211_tdma_param) : 0) #endif #ifdef IEEE80211_SUPPORT_MESH + 2 + ni->ni_meshidlen + sizeof(struct ieee80211_meshconf_ie) #endif + IEEE80211_MAX_APPIE ; m = ieee80211_getmgtframe(&frm, ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen); if (m == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, "%s: cannot get buf; size %u\n", __func__, pktlen); vap->iv_stats.is_tx_nobuf++; return NULL; } ieee80211_beacon_construct(m, frm, ni); a1960 2 M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); KASSERT(m != NULL, ("no space for 802.11 header?")); d1965 1 a1965 1 *(uint16_t *)wh->i_dur = 0; d1967 1 a1967 1 IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); d1969 1 a1969 1 *(uint16_t *)wh->i_seq = 0; d1978 2 a1979 1 ieee80211_beacon_update(struct ieee80211_node *ni, struct mbuf *m, int mcast) a1980 3 struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; struct ieee80211com *ic = ni->ni_ic; d1982 1 a1982 71 uint16_t capinfo; struct ieee80211_frame *wh; ieee80211_seq seqno; IEEE80211_LOCK(ic); /* * Handle 11h channel change when we've reached the count. * We must recalculate the beacon frame contents to account * for the new channel. Note we do this only for the first * vap that reaches this point; subsequent vaps just update * their beacon state to reflect the recalculated channel. */ if (isset(bo->bo_flags, IEEE80211_BEACON_CSA) && vap->iv_csa_count == ic->ic_csa_count) { vap->iv_csa_count = 0; /* * Effect channel change before reconstructing the beacon * frame contents as many places reference ni_chan. */ if (ic->ic_csa_newchan != NULL) ieee80211_csa_completeswitch(ic); /* * NB: ieee80211_beacon_construct clears all pending * updates in bo_flags so we don't need to explicitly * clear IEEE80211_BEACON_CSA. */ ieee80211_beacon_construct(m, mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), ni); /* XXX do WME aggressive mode processing? */ IEEE80211_UNLOCK(ic); return 1; /* just assume length changed */ } /* * Handle the quiet time element being added and removed. * Again, for now we just cheat and reconstruct the whole * beacon - that way the gap is provided as appropriate. * * So, track whether we have already added the IE versus * whether we want to be adding the IE. */ if ((vap->iv_flags_ext & IEEE80211_FEXT_QUIET_IE) && (vap->iv_quiet == 0)) { /* * Quiet time beacon IE enabled, but it's disabled; * recalc */ vap->iv_flags_ext &= ~IEEE80211_FEXT_QUIET_IE; ieee80211_beacon_construct(m, mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), ni); /* XXX do WME aggressive mode processing? */ IEEE80211_UNLOCK(ic); return 1; /* just assume length changed */ } if (((vap->iv_flags_ext & IEEE80211_FEXT_QUIET_IE) == 0) && (vap->iv_quiet == 1)) { /* * Quiet time beacon IE disabled, but it's now enabled; * recalc */ vap->iv_flags_ext |= IEEE80211_FEXT_QUIET_IE; ieee80211_beacon_construct(m, mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), ni); /* XXX do WME aggressive mode processing? */ IEEE80211_UNLOCK(ic); return 1; /* just assume length changed */ } wh = mtod(m, struct ieee80211_frame *); d1984 1 a1984 12 /* * XXX TODO Strictly speaking this should be incremented with the TX * lock held so as to serialise access to the non-qos TID sequence * number space. * * If the driver identifies it does its own TX seqno management then * we can skip this (and still not do the TX seqno.) */ seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; *(uint16_t *)&wh->i_seq[0] = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); M_SEQNO_SET(m, seqno); d1987 11 a1997 1 capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); d2000 1 a2000 1 if (vap->iv_flags & IEEE80211_F_WME) { d2004 1 a2004 1 * Check for aggressive mode change. When there is d2007 1 a2007 1 * parameters. Otherwise BE uses aggressive params d2013 1 a2013 1 IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, d2017 1 a2017 1 ieee80211_wme_updateparams_locked(vap); d2025 1 a2025 1 IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, d2029 1 a2029 1 ieee80211_wme_updateparams_locked(vap); d2035 3 a2037 3 if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) { (void) ieee80211_add_wme_param(bo->bo_wme, wme); clrbit(bo->bo_flags, IEEE80211_BEACON_WME); d2041 2 a2042 19 if (isset(bo->bo_flags, IEEE80211_BEACON_HTINFO)) { ieee80211_ht_update_beacon(vap, bo); clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO); } #ifdef IEEE80211_SUPPORT_TDMA if (vap->iv_caps & IEEE80211_C_TDMA) { /* * NB: the beacon is potentially updated every TBTT. */ ieee80211_tdma_update_beacon(vap, bo); } #endif #ifdef IEEE80211_SUPPORT_MESH if (vap->iv_opmode == IEEE80211_M_MBSS) ieee80211_mesh_update_beacon(vap, bo); #endif if (vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_MBSS) { /* NB: no IBSS support*/ d2044 2 a2045 2 (struct ieee80211_tim_ie *) bo->bo_tim; if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) { d2054 1 a2054 1 * maximal-size virtual bitmap (based on iv_max_aid). d2063 1 a2063 1 if (vap->iv_ps_pending != 0) { d2065 2 a2066 2 for (i = 0; i < vap->iv_tim_len; i++) if (vap->iv_tim_bitmap[i]) { d2070 3 a2072 3 KASSERT(timoff != 128, ("tim bitmap empty!")); for (i = vap->iv_tim_len-1; i >= timoff; i--) if (vap->iv_tim_bitmap[i]) a2078 4 /* * TODO: validate this! */ d2081 4 a2084 22 int adjust = tie->tim_bitmap+timlen - bo->bo_tim_trailer; ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust, bo->bo_tim_trailer_len); bo->bo_tim_trailer += adjust; bo->bo_erp += adjust; bo->bo_htinfo += adjust; bo->bo_vhtinfo += adjust; #ifdef IEEE80211_SUPPORT_SUPERG bo->bo_ath += adjust; #endif #ifdef IEEE80211_SUPPORT_TDMA bo->bo_tdma += adjust; #endif #ifdef IEEE80211_SUPPORT_MESH bo->bo_meshconf += adjust; #endif bo->bo_appie += adjust; bo->bo_wme += adjust; bo->bo_csa += adjust; bo->bo_quiet += adjust; d2092 1 a2092 1 memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff, d2095 1 a2095 1 clrbit(bo->bo_flags, IEEE80211_BEACON_TIM); d2097 1 a2097 1 IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, d2099 1 a2099 1 __func__, vap->iv_ps_pending, timoff, timlen); d2107 1 a2107 1 if (mcast && tie->tim_count == 0) a2110 64 if (isset(bo->bo_flags, IEEE80211_BEACON_CSA)) { struct ieee80211_csa_ie *csa = (struct ieee80211_csa_ie *) bo->bo_csa; /* * Insert or update CSA ie. If we're just starting * to count down to the channel switch then we need * to insert the CSA ie. Otherwise we just need to * drop the count. The actual change happens above * when the vap's count reaches the target count. */ if (vap->iv_csa_count == 0) { memmove(&csa[1], csa, bo->bo_csa_trailer_len); bo->bo_erp += sizeof(*csa); bo->bo_htinfo += sizeof(*csa); bo->bo_vhtinfo += sizeof(*csa); bo->bo_wme += sizeof(*csa); #ifdef IEEE80211_SUPPORT_SUPERG bo->bo_ath += sizeof(*csa); #endif #ifdef IEEE80211_SUPPORT_TDMA bo->bo_tdma += sizeof(*csa); #endif #ifdef IEEE80211_SUPPORT_MESH bo->bo_meshconf += sizeof(*csa); #endif bo->bo_appie += sizeof(*csa); bo->bo_csa_trailer_len += sizeof(*csa); bo->bo_quiet += sizeof(*csa); bo->bo_tim_trailer_len += sizeof(*csa); m->m_len += sizeof(*csa); m->m_pkthdr.len += sizeof(*csa); ieee80211_add_csa(bo->bo_csa, vap); } else csa->csa_count--; vap->iv_csa_count++; /* NB: don't clear IEEE80211_BEACON_CSA */ } /* * Only add the quiet time IE if we've enabled it * as appropriate. */ if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) { if (vap->iv_quiet && (vap->iv_flags_ext & IEEE80211_FEXT_QUIET_IE)) { ieee80211_add_quiet(bo->bo_quiet, vap, 1); } } if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) { /* * ERP element needs updating. */ (void) ieee80211_add_erp(bo->bo_erp, ic); clrbit(bo->bo_flags, IEEE80211_BEACON_ERP); } #ifdef IEEE80211_SUPPORT_SUPERG if (isset(bo->bo_flags, IEEE80211_BEACON_ATH)) { ieee80211_add_athcaps(bo->bo_ath, ni); clrbit(bo->bo_flags, IEEE80211_BEACON_ATH); } #endif d2112 1 a2112 16 if (isset(bo->bo_flags, IEEE80211_BEACON_APPIE)) { const struct ieee80211_appie *aie = vap->iv_appie_beacon; int aielen; uint8_t *frm; aielen = 0; if (aie != NULL) aielen += aie->ie_len; if (aielen != bo->bo_appie_len) { /* copy up/down trailer */ int adjust = aielen - bo->bo_appie_len; ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust, bo->bo_tim_trailer_len); bo->bo_tim_trailer += adjust; bo->bo_appie += adjust; bo->bo_appie_len = aielen; d2114 1 a2114 8 len_changed = 1; } frm = bo->bo_appie; if (aie != NULL) frm = add_appie(frm, aie); clrbit(bo->bo_flags, IEEE80211_BEACON_APPIE); } IEEE80211_UNLOCK(ic); d2120 3 a2122 5 * Do Ethernet-LLC encapsulation for each payload in a fast frame * tunnel encapsulation. The frame is assumed to have an Ethernet * header at the front that must be stripped before prepending the * LLC followed by the Ethernet header passed in (with an Ethernet * type that specifies the payload size). d2124 3 a2126 3 struct mbuf * ieee80211_ff_encap1(struct ieee80211vap *vap, struct mbuf *m, const struct ether_header *eh) d2128 1 a2128 2 struct llc *llc; uint16_t payload; d2130 13 a2142 10 /* XXX optimize by combining m_adj+M_PREPEND */ m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); llc = mtod(m, struct llc *); llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_control = LLC_UI; llc->llc_snap.org_code[0] = 0; llc->llc_snap.org_code[1] = 0; llc->llc_snap.org_code[2] = 0; llc->llc_snap.ether_type = eh->ether_type; payload = m->m_pkthdr.len; /* NB: w/o Ethernet header */ d2144 2 a2145 6 M_PREPEND(m, sizeof(struct ether_header), M_NOWAIT); if (m == NULL) { /* XXX cannot happen */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, "%s: no space for ether_header\n", __func__); vap->iv_stats.is_tx_nobuf++; return NULL; a2146 4 ETHER_HEADER_COPY(mtod(m, void *), eh); mtod(m, struct ether_header *)->ether_type = htons(payload); return m; } d2148 15 a2162 25 /* * Complete an mbuf transmission. * * For now, this simply processes a completed frame after the * driver has completed it's transmission and/or retransmission. * It assumes the frame is an 802.11 encapsulated frame. * * Later on it will grow to become the exit path for a given frame * from the driver and, depending upon how it's been encapsulated * and already transmitted, it may end up doing A-MPDU retransmission, * power save requeuing, etc. * * In order for the above to work, the driver entry point to this * must not hold any driver locks. Thus, the driver needs to delay * any actual mbuf completion until it can release said locks. * * This frees the mbuf and if the mbuf has a node reference, * the node reference will be freed. */ void ieee80211_tx_complete(struct ieee80211_node *ni, struct mbuf *m, int status) { if (ni != NULL) { struct ifnet *ifp = ni->ni_vap->iv_ifp; d2164 2 a2165 12 if (status == 0) { if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); if (m->m_flags & M_MCAST) if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); } else if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); if (m->m_flags & M_TXCB) ieee80211_process_callback(ni, m, status); ieee80211_free_node(ni); } m_freem(m); @ 1.63.2.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 #if __FreeBSD__ a30 1 #endif a45 1 #if __FreeBSD__ a46 1 #endif a47 1 #if __FreeBSD__ a48 1 #endif a50 1 #if __FreeBSD__ a51 5 #endif #ifdef __NetBSD__ #include #include #endif a69 1 #if __FreeBSD__ a70 1 #endif a77 1 #if __FreeBSD__ a78 6 #endif #ifdef __NetBSD__ #undef KASSERT #define KASSERT(__cond, __complaint) FBSDKASSERT(__cond, __complaint) #endif a165 1 #if __FreeBSD__ a166 3 #elif __NetBSD__ m_set_rcvif(m, (void *)ni); #endif a475 1 #if __FreeBSD__ a476 3 #elif __NetBSD__ ifp->if_flags |= IFF_OACTIVE; #endif a530 1 #if __FreeBSD__ a531 3 #elif __NetBSD__ m_set_rcvif(m, (void*)ni); #endif a624 1 #if __FreeBSD__ a625 3 #elif __NetBSD__ if (ifp->if_flags & IFF_OACTIVE) { #endif a648 1 #if __FreeBSD__ a650 1 #endif a1250 1 #if __FreeBSD__ a1252 4 #elif __NetBSD__ KASSERT(needed_space <= MHLEN, ("not enough room, need %u got %lu\n", needed_space, MHLEN)); #endif a1840 1 #if __FreeBSD__ a1841 3 #elif __NetBSD__ m = m_get(M_NOWAIT, MT_DATA); #endif @ 1.63.2.3 log @State save. urtwn now can attach and shows up in the "ifconfig -a" list. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.63.2.2 2018/07/12 16:35:34 phil Exp $ */ a646 1 #if __FreeBSD__ a649 5 #elif __NetBSD__ int ieee80211_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, const struct rtentry *ro) #endif @ 1.63.2.4 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_output.c,v 1.63.2.3 2018/07/16 20:11:11 phil Exp $ */ d1400 1 a1400 1 @ 1.63.2.5 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.64 2018/12/22 13:11:37 maxv Exp $ */ d32 2 a33 2 #ifdef __NetBSD__ __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.64 2018/12/22 13:11:37 maxv Exp $"); a35 1 #ifdef _KERNEL_OPT a38 1 #endif @ 1.63.2.6 log @Mostly merge changes from HEAD upto 20200411 @ text @d1 1 a1 1 /* $NetBSD$ */ d33 1 a33 1 __KERNEL_RCSID(0, "$NetBSD$"); d1305 1 a1305 1 ("not enough room, need %u got %lu\n", needed_space, (u_long)MHLEN)); a1306 1 @ 1.62 log @Remove ovbcopy from net80211. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.61 2018/01/18 16:23:43 maxv Exp $ */ d40 1 a40 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.61 2018/01/18 16:23:43 maxv Exp $"); a46 3 #ifdef __NetBSD__ #endif /* __NetBSD__ */ a246 1 /* XXX debug msg */ a432 2 IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, "%s: cannot expand storage\n", __func__); d994 1 a994 1 m->m_nextpkt = NULL; /* XXX paranoid */ @ 1.61 log @Several changes: * Make the code more readable. * Add a panic in ieee80211_compute_duration(). I'm not sure there's a bug here - I don't have the hardware -, but looking at the code, it may be possible for 'paylen' to go negative. Obviously that's not the correct way to fix it, but at least we'll see if it happens. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.60 2018/01/18 13:24:01 maxv Exp $ */ d40 1 a40 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.60 2018/01/18 13:24:01 maxv Exp $"); d2087 1 a2087 1 ovbcopy(bo->bo_trailer, tie->tim_bitmap+timlen, @ 1.61.2.1 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.63 2018/05/08 07:02:07 maxv Exp $ */ d40 1 a40 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.63 2018/05/08 07:02:07 maxv Exp $"); d47 3 d250 1 d437 2 d1000 1 a1000 1 m->m_nextpkt = NULL; d2087 1 a2087 1 memmove(tie->tim_bitmap+timlen, bo->bo_trailer, @ 1.61.2.2 log @Sync with HEAD, resolve a few conflicts @ text @d1 1 a1 1 /* $NetBSD$ */ d40 1 a40 1 __KERNEL_RCSID(0, "$NetBSD$"); d447 1 a447 1 m_move_pkthdr(n, m); @ 1.60 log @Several changes: * Make the code more readable. In particular, declare variables as const along the way. * Explain what we're doing in ieee80211_send_mgmt(). The IEEE80211_FC0_SUBTYPE_PROBE_RESP case has some inconsistencies, but they are not inherently wrong so I'm not changing that. * When sending IEEE80211_FC0_SUBTYPE_REASSOC_RESP frames, make sure to zero out the 'association ID', otherwise two bytes are leaked. * Fix a possible memory leak in ieee80211_send_probereq(). @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.59 2017/09/26 07:42:06 knakahara Exp $ */ d40 1 a40 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.59 2017/09/26 07:42:06 knakahara Exp $"); d407 3 a452 1 /* NB: must be first 'cuz it clobbers m_data */ d454 1 a454 1 n->m_len = 0; /* NB: m_gethdr does not set */ d456 1 a462 1 /* NB: struct ether_header is known to be contiguous */ d466 1 d473 1 a473 1 /* d475 2 a476 2 * 802.11 encapsulation stage. Make sure that it * is writable. d485 1 a485 1 if (key != NULL && (key->wk_flags & IEEE80211_KEY_SWCRYPT) != 0) d487 1 a487 1 d492 1 d850 2 a851 2 /* Account for padding required by the driver. */ if (icflags & IEEE80211_F_DATAPAD) d853 4 a856 1 else d858 1 d925 2 a926 1 u_int totalhdrsize, fragno, fragsize, off, remainder, payload; d935 1 a935 1 totalhdrsize = hdrsize + ciphdrsize; d952 1 d984 1 d995 1 d1000 1 a1000 1 m->m_nextpkt = NULL; /* XXX paranoid */ d1004 1 d1127 1 a1127 1 if (rsn->rsn_ucastcipherset & (1<rsn_ucastcipherset & (1<rsn_ucastcipherset & (1<rsn_ucastcipherset & (1<wmep_acm, WME_PARAM_ACM) | SM(ac->wmep_aifsn, WME_PARAM_AIFSN) ; *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN) ; d1318 1 d1509 5 a1513 5 *frm++ = IEEE80211_ELEMID_FHPARMS; *frm++ = 5; *frm++ = ni->ni_fhdwell & 0x00ff; *frm++ = (ni->ni_fhdwell >> 8) & 0x00ff; *frm++ = IEEE80211_FH_CHANSET( d1515 1 a1515 1 *frm++ = IEEE80211_FH_CHANPAT( d1517 1 a1517 1 *frm++ = ni->ni_fhindex; d1834 1 a1834 1 * Allocate a beacon frame and fillin the appropriate bits. d1848 2 d1864 3 a1866 1 * NB: we allocate the max space required for the TIM bitmap. a1867 1 rs = &ni->ni_rates; d1872 2 a1873 2 + 2 + IEEE80211_RATE_SIZE /* supported rates */ + 2 + 1 /* DS parameters */ d1876 1 a1876 1 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) d1892 1 d1895 1 d1910 1 d1918 1 d1920 1 d1926 1 d1934 1 a1934 1 struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; d1945 1 d1952 1 d1955 1 d1958 1 d1960 1 d1966 1 d1991 1 d2042 1 a2042 1 (void) ieee80211_add_wme_param(bo->bo_wme, wme); d2050 1 a2050 1 (struct ieee80211_tim_ie *) bo->bo_tim; d2119 1 d2132 1 a2132 1 struct mbuf *m) d2140 1 d2149 1 d2153 1 @ 1.59 log @VLAN ID uses pkthdr instead of mtag now. Contributed by s-yamaguchi@@IIJ. I just commit by proxy. Reviewed by joerg@@n.o and christos@@n.o, thanks. See http://mail-index.netbsd.org/tech-net/2017/09/26/msg006459.html XXX need pullup to -8 branch @ text @d1 3 a3 2 /* $NetBSD: ieee80211_output.c,v 1.58 2017/01/04 03:05:24 nonaka Exp $ */ /*- d40 1 a40 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.58 2017/01/04 03:05:24 nonaka Exp $"); d119 1 d128 1 d136 1 d143 1 d153 1 d196 3 a198 3 ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_MGT | type, ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid); d206 1 d219 1 d258 1 d260 3 a262 2 IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid); d265 1 a265 1 ic->ic_opmode != IEEE80211_M_HOSTAP) d267 2 d292 2 a293 1 ieee80211_classify(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni) d421 1 d440 1 d443 1 d470 2 a471 1 /* We will overwrite the ethernet header in the d559 1 a559 1 !IEEE80211_IS_MULTICAST(eh.ether_dhost)) d561 1 a561 1 else d563 1 d571 1 a571 1 } else d573 2 a574 1 /* XXX 4-address format */ d576 2 d585 1 a585 1 eh.ether_type != htons(ETHERTYPE_PAE); d592 1 d615 1 d619 1 d627 1 d639 1 d646 1 a646 1 #endif /* !IEEE80211_NO_HOSTAP */ d648 1 d652 1 d655 1 d658 1 a658 1 (struct ieee80211_qosframe *) wh; d678 1 d683 1 d704 1 d713 1 d1374 3 a1376 1 if (m == NULL) d1378 1 d1383 2 a1384 2 IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, sa, da, bssid); d1413 1 a1413 1 int has_challenge, is_shared_key, ret, timer, status; d1431 3 a1433 1 case IEEE80211_FC0_SUBTYPE_PROBE_RESP: d1449 8 a1456 8 8 + sizeof(u_int16_t) + sizeof(u_int16_t) + 2 + IEEE80211_NWID_LEN + 2 + IEEE80211_RATE_SIZE + 7 /* max(7,3) */ + 6 + 3 d1459 1 a1459 2 + (ic->ic_flags & IEEE80211_F_WPA ? 2*sizeof(struct ieee80211_ie_wpa) : 0) d1465 2 a1466 1 memset(frm, 0, 8); /* timestamp should be filled later */ d1468 2 d1472 2 d1488 1 d1490 3 a1492 1 ic->ic_bss->ni_esslen); d1495 1 d1512 1 d1516 1 a1516 1 *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ d1518 3 a1520 1 if (ic->ic_flags & IEEE80211_F_WPA) d1522 2 d1526 2 d1529 2 d1533 1 d1536 1 d1538 1 a1538 1 case IEEE80211_FC0_SUBTYPE_AUTH: d1541 4 a1544 3 has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || arg == IEEE80211_AUTH_SHARED_RESPONSE) && ni->ni_challenge != NULL); d1553 11 a1563 4 is_shared_key = has_challenge || arg >= IEEE80211_AUTH_SHARED_RESPONSE || (arg == IEEE80211_AUTH_SHARED_REQUEST && ic->ic_bss->ni_authmode == IEEE80211_AUTH_SHARED); d1565 1 a1565 5 m = ieee80211_getmgtframe(&frm, 3 * sizeof(u_int16_t) + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? sizeof(u_int16_t)+IEEE80211_CHALLENGE_LEN : 0) ); d1570 1 a1570 1 (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED) d1575 1 a1575 1 if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { d1581 1 a1581 2 m->m_pkthdr.len = m->m_len = 4 * sizeof(u_int16_t) + IEEE80211_CHALLENGE_LEN; d1588 3 a1590 2 } else m->m_pkthdr.len = m->m_len = 3 * sizeof(u_int16_t); d1601 1 d1648 1 a1648 1 else /* IEEE80211_M_STA */ d1726 2 a1727 1 } else d1729 1 @ 1.58 log @Export some 802.11 IE manipulate functions. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.57 2016/07/07 06:55:43 msaitoh Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.57 2016/07/07 06:55:43 msaitoh Exp $"); d299 1 a299 2 struct m_tag *mtag = m_tag_find(m, PACKET_TAG_VLAN, NULL); if (mtag == NULL) { d303 1 a303 1 if (EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag)) != @ 1.58.8.1 log @Pull up following revision(s) (requested by knakahara in ticket #302): sys/arch/powerpc/booke/dev/pq3etsec.c: 1.30-1.31 sys/arch/x86/pci/if_vmx.c: 1.20 sys/dev/ic/i82557.c: 1.148 sys/dev/ic/rtl8169.c: 1.152 sys/dev/pci/cxgb/cxgb_sge.c: 1.5 sys/dev/pci/if_age.c: 1.51 sys/dev/pci/if_alc.c: 1.25 sys/dev/pci/if_ale.c: 1.23 sys/dev/pci/if_bge.c: 1.311 sys/dev/pci/if_bge.c: 1.312 sys/dev/pci/if_bnx.c: 1.62 sys/dev/pci/if_jme.c: 1.32 sys/dev/pci/if_nfe.c: 1.64 sys/dev/pci/if_sip.c: 1.167 sys/dev/pci/if_stge.c: 1.63-1.64 sys/dev/pci/if_ti.c: 1.102 sys/dev/pci/if_txp.c: 1.48 sys/dev/pci/if_vge.c: 1.61 sys/dev/pci/if_wm.c: 1.538 sys/dev/pci/ixgbe/ix_txrx.c: 1.29 via patch sys/net/agr/if_agrether_hash.c: 1.4 sys/net/if_ether.h: 1.67-1.68 sys/net/if_ethersubr.c: 1.244 sys/net/if_vlan.c: 1.100 sys/net80211/ieee80211_input.c: 1.89 sys/net80211/ieee80211_output.c: 1.59 sys/sys/mbuf.h: 1.171 VLAN ID uses pkthdr instead of mtag now. Contributed by s-yamaguchi@@IIJ. I just commit by proxy. Reviewed by joerg@@n.o and christos@@n.o, thanks. See http://mail-index.netbsd.org/tech-net/2017/09/26/msg006459.html -- only get vtag when we have vtag like the other drivers. -- - only get the vtag if we have it like the other drivers - mask the hardware vlan tag -- - add a constant for the vlan mask. - enforce that we have a tag before we get it. only get vtag when we have vtag like the other drivers. like if_bge.c:1.312 and if_stge.c:1.64. fixed by s-yamaguchi@@IIJ, thanks. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.58 2017/01/04 03:05:24 nonaka Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.58 2017/01/04 03:05:24 nonaka Exp $"); d299 2 a300 1 if (!vlan_has_tag(m)) { d304 1 a304 1 if (EVL_VLANOFTAG(vlan_get_tag(m)) != @ 1.57 log @KNF. Remove extra spaces. No functional change. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.56 2016/06/20 08:57:18 ozaki-r Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.56 2016/06/20 08:57:18 ozaki-r Exp $"); d966 1 a966 1 static u_int8_t * d983 1 a983 1 static u_int8_t * d1002 1 a1002 1 static u_int8_t * d1204 1 a1204 1 static u_int8_t * d1220 1 a1220 1 static u_int8_t * @ 1.57.2.1 log @Sync with HEAD. (Note that most of these changes are simply $NetBSD$ tag issues.) @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.58 2017/01/04 03:05:24 nonaka Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.58 2017/01/04 03:05:24 nonaka Exp $"); d966 1 a966 1 u_int8_t * d983 1 a983 1 u_int8_t * d1002 1 a1002 1 u_int8_t * d1204 1 a1204 1 u_int8_t * d1220 1 a1220 1 u_int8_t * @ 1.56 log @Get rid of invalid KASSERT The mbuf being checked is allocated in ieee80211_getmgtframe just above, so checking NULL of its CTX is meaningless. Pointed out by mlelstv@@ @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.55 2016/06/20 08:30:59 knakahara Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.55 2016/06/20 08:30:59 knakahara Exp $"); d1233 1 a1233 1 return frm + sizeof(info); @ 1.55 log @apply if_start_lock() to L2 callers which call ifp->if_start() of device derivers @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.54 2016/05/16 09:53:59 ozaki-r Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.54 2016/05/16 09:53:59 ozaki-r Exp $"); a186 3 #ifdef __FreeBSD__ KASSERT(M_GETCTX(m, struct ieee80211_node *) == NULL); #endif a1343 1 KASSERT(M_GETCTX(m, struct ieee80211_node *) == NULL); @ 1.54 log @Use M_GETCTX and M_SETCTX instead of open-coding rcvif No functional change. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.53 2015/08/24 22:21:26 pooka Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.53 2015/08/24 22:21:26 pooka Exp $"); d224 1 a224 1 (*ifp->if_start)(ifp); d271 1 a271 1 (*ifp->if_start)(ifp); d1365 1 a1365 1 (*ic->ic_ifp->if_start)(ic->ic_ifp); @ 1.53 log @sprinkle _KERNEL_OPT @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.52 2014/10/18 08:33:29 snj Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.52 2014/10/18 08:33:29 snj Exp $"); d188 1 a188 1 KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null")); d190 1 a190 1 m->m_pkthdr.rcvif = (void *)ni; d250 1 a250 1 m->m_pkthdr.rcvif = (void *) ni; d1347 2 a1348 2 IASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null")); m->m_pkthdr.rcvif = (void *)ni; @ 1.52 log @src is too big these days to tolerate superfluous apostrophes. It's "its", people! @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.51 2011/12/31 20:41:58 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.51 2011/12/31 20:41:58 christos Exp $"); d42 1 d44 1 @ 1.52.2.1 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.53 2015/08/24 22:21:26 pooka Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.53 2015/08/24 22:21:26 pooka Exp $"); a41 1 #ifdef _KERNEL_OPT a42 1 #endif @ 1.52.2.2 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.52.2.1 2015/09/22 12:06:11 skrll Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.52.2.1 2015/09/22 12:06:11 skrll Exp $"); d188 1 a188 1 KASSERT(M_GETCTX(m, struct ieee80211_node *) == NULL); d190 1 a190 1 M_SETCTX(m, ni); d250 1 a250 1 M_SETCTX(m, ni); d1347 2 a1348 2 KASSERT(M_GETCTX(m, struct ieee80211_node *) == NULL); M_SETCTX(m, ni); @ 1.52.2.3 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.52.2.2 2016/05/29 08:44:38 skrll Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.52.2.2 2016/05/29 08:44:38 skrll Exp $"); d187 3 d224 1 a224 1 if_start_lock(ifp); d271 1 a271 1 if_start_lock(ifp); d1236 1 a1236 1 return frm + sizeof(info); d1347 1 d1365 1 a1365 1 if_start_lock(ic->ic_ifp); @ 1.52.2.4 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.52.2.3 2016/07/09 20:25:21 skrll Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.52.2.3 2016/07/09 20:25:21 skrll Exp $"); d966 1 a966 1 u_int8_t * d983 1 a983 1 u_int8_t * d1002 1 a1002 1 u_int8_t * d1204 1 a1204 1 u_int8_t * d1220 1 a1220 1 u_int8_t * @ 1.51 log @- fix offsetof usage, and redundant defines - kill pointer casts to 0 @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.50 2011/02/21 23:50:08 jmcneill Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.50 2011/02/21 23:50:08 jmcneill Exp $"); d2062 1 a2062 1 * Tag the frame with it's expiry time and insert @ 1.51.6.1 log @update from HEAD @ text @d1 1 a1 1 /* $NetBSD$ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD$"); a41 1 #ifdef _KERNEL_OPT a42 1 #endif d185 4 a188 1 M_SETCTX(m, ni); d222 1 a222 1 if_start_lock(ifp); d248 1 a248 1 M_SETCTX(m, ni); d269 1 a269 1 if_start_lock(ifp); d300 2 a301 1 if (!vlan_has_tag(m)) { d305 1 a305 1 if (EVL_VLANOFTAG(vlan_get_tag(m)) != d967 1 a967 1 u_int8_t * d984 1 a984 1 u_int8_t * d1003 1 a1003 1 u_int8_t * d1205 1 a1205 1 u_int8_t * d1221 1 a1221 1 u_int8_t * d1234 1 a1234 1 return frm + sizeof(info); d1345 2 a1346 1 M_SETCTX(m, ni); d1363 1 a1363 1 if_start_lock(ic->ic_ifp); d2062 1 a2062 1 * Tag the frame with its expiry time and insert @ 1.50 log @add ieee80211_get_rts and ieee80211_get_cts_to_self from openbsd, ok dyoung@@ @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.49 2010/01/19 22:08:17 pooka Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.49 2010/01/19 22:08:17 pooka Exp $"); d1261 1 a1261 1 frm += __offsetof(struct ieee80211_wme_info, wme_info); @ 1.50.4.1 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.50 2011/02/21 23:50:08 jmcneill Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.50 2011/02/21 23:50:08 jmcneill Exp $"); d1261 1 a1261 1 frm += offsetof(struct ieee80211_wme_info, wme_info); @ 1.50.8.1 log @merge to -current. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.51 2011/12/31 20:41:58 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.51 2011/12/31 20:41:58 christos Exp $"); d1261 1 a1261 1 frm += offsetof(struct ieee80211_wme_info, wme_info); @ 1.49 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_output.c,v 1.48 2008/06/19 23:13:10 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.48 2008/06/19 23:13:10 dyoung Exp $"); d1709 52 @ 1.49.6.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.50 2011/02/21 23:50:08 jmcneill Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.50 2011/02/21 23:50:08 jmcneill Exp $"); a1708 52 * Build a RTS (Request To Send) control frame. */ struct mbuf * ieee80211_get_rts(struct ieee80211com *ic, const struct ieee80211_frame *wh, uint16_t dur) { struct ieee80211_frame_rts *rts; struct mbuf *m; MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) return NULL; m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts); rts = mtod(m, struct ieee80211_frame_rts *); rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(uint16_t *)rts->i_dur = htole16(dur); IEEE80211_ADDR_COPY(rts->i_ra, wh->i_addr1); IEEE80211_ADDR_COPY(rts->i_ta, wh->i_addr2); return m; } /* * Build a CTS-to-self (Clear To Send) control frame. */ struct mbuf * ieee80211_get_cts_to_self(struct ieee80211com *ic, uint16_t dur) { struct ieee80211_frame_cts *cts; struct mbuf *m; MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) return NULL; m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts); cts = mtod(m, struct ieee80211_frame_cts *); cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(uint16_t *)cts->i_dur = htole16(dur); IEEE80211_ADDR_COPY(cts->i_ra, ic->ic_myaddr); return m; } /* @ 1.49.4.1 log @sync with head @ text @d1 1 a1 1 /* $NetBSD$ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD$"); a1708 52 * Build a RTS (Request To Send) control frame. */ struct mbuf * ieee80211_get_rts(struct ieee80211com *ic, const struct ieee80211_frame *wh, uint16_t dur) { struct ieee80211_frame_rts *rts; struct mbuf *m; MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) return NULL; m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts); rts = mtod(m, struct ieee80211_frame_rts *); rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(uint16_t *)rts->i_dur = htole16(dur); IEEE80211_ADDR_COPY(rts->i_ra, wh->i_addr1); IEEE80211_ADDR_COPY(rts->i_ta, wh->i_addr2); return m; } /* * Build a CTS-to-self (Clear To Send) control frame. */ struct mbuf * ieee80211_get_cts_to_self(struct ieee80211com *ic, uint16_t dur) { struct ieee80211_frame_cts *cts; struct mbuf *m; MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) return NULL; m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts); cts = mtod(m, struct ieee80211_frame_cts *); cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(uint16_t *)cts->i_dur = htole16(dur); IEEE80211_ADDR_COPY(cts->i_ra, ic->ic_myaddr); return m; } /* @ 1.49.8.1 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD$ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD$"); a1708 52 * Build a RTS (Request To Send) control frame. */ struct mbuf * ieee80211_get_rts(struct ieee80211com *ic, const struct ieee80211_frame *wh, uint16_t dur) { struct ieee80211_frame_rts *rts; struct mbuf *m; MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) return NULL; m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts); rts = mtod(m, struct ieee80211_frame_rts *); rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(uint16_t *)rts->i_dur = htole16(dur); IEEE80211_ADDR_COPY(rts->i_ra, wh->i_addr1); IEEE80211_ADDR_COPY(rts->i_ta, wh->i_addr2); return m; } /* * Build a CTS-to-self (Clear To Send) control frame. */ struct mbuf * ieee80211_get_cts_to_self(struct ieee80211com *ic, uint16_t dur) { struct ieee80211_frame_cts *cts; struct mbuf *m; MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) return NULL; m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts); cts = mtod(m, struct ieee80211_frame_cts *); cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(uint16_t *)cts->i_dur = htole16(dur); IEEE80211_ADDR_COPY(cts->i_ra, ic->ic_myaddr); return m; } /* @ 1.48 log @Note a defect in 802.11 Duration field calculations. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.47 2007/03/04 06:03:19 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.47 2007/03/04 06:03:19 christos Exp $"); a44 1 #include "bpfilter.h" a66 1 #if NBPFILTER > 0 a67 1 #endif @ 1.47 log @Kill caddr_t; there will be some MI fallout, but it will be fixed shortly. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.46 2007/01/06 06:02:33 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.46 2007/01/06 06:02:33 dyoung Exp $"); d719 3 a721 1 * DATA reserves medium for SIFS | ACK @ 1.47.40.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.47 2007/03/04 06:03:19 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.47 2007/03/04 06:03:19 christos Exp $"); d719 1 a719 3 * DATA reserves medium for SIFS | ACK, * * (XXX or SIFS | ACK | SIFS | DATA | SIFS | ACK, if more fragments) @ 1.47.40.2 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.47.40.1 2009/05/04 08:14:16 yamt Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.47.40.1 2009/05/04 08:14:16 yamt Exp $"); d45 1 d68 1 d70 1 @ 1.47.36.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD$ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD$"); d719 1 a719 3 * DATA reserves medium for SIFS | ACK, * * (XXX or SIFS | ACK | SIFS | DATA | SIFS | ACK, if more fragments) @ 1.47.44.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.48 2008/06/19 23:13:10 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.48 2008/06/19 23:13:10 dyoung Exp $"); d719 1 a719 3 * DATA reserves medium for SIFS | ACK, * * (XXX or SIFS | ACK | SIFS | DATA | SIFS | ACK, if more fragments) @ 1.47.42.1 log @Sync w/ -current. 34 merge conflicts to follow. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.47 2007/03/04 06:03:19 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.47 2007/03/04 06:03:19 christos Exp $"); d719 1 a719 3 * DATA reserves medium for SIFS | ACK, * * (XXX or SIFS | ACK | SIFS | DATA | SIFS | ACK, if more fragments) @ 1.47.34.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 d36 1 a36 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.57 2007/12/07 01:46:12 kmacy Exp $"); a66 1 #include a79 6 #define ETHER_HEADER_COPY(dst, src) \ memcpy(dst, src, sizeof(struct ether_header)) static struct mbuf *ieee80211_encap_fastframe(struct ieee80211com *ic, struct mbuf *m1, const struct ether_header *eh1, struct mbuf *m2, const struct ether_header *eh2); a81 1 static void ieee80211_tx_mgt_cb(struct ieee80211_node *, void *, int); d112 3 a114 3 const uint8_t sa[IEEE80211_ADDR_LEN], const uint8_t da[IEEE80211_ADDR_LEN], const uint8_t bssid[IEEE80211_ADDR_LEN]) a139 8 case IEEE80211_M_WDS: wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; /* XXX cheat, bssid holds RA */ IEEE80211_ADDR_COPY(wh->i_addr1, bssid); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, da); IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); break; d149 1 a149 1 *(uint16_t *)&wh->i_dur[0] = 0; d151 3 a153 3 *(uint16_t *)&wh->i_seq[0] = htole16(ni->ni_txseqs[IEEE80211_NONQOS_TID] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[IEEE80211_NONQOS_TID]++; d164 1 a164 1 int d166 1 a166 1 struct mbuf *m, int type) d189 1 a189 1 IASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null")); a203 5 if (ni->ni_flags & IEEE80211_NODE_QOS) { /* NB: force all management frames to the highest queue */ M_WME_SETAC(m, WME_AC_VO); } else M_WME_SETAC(m, WME_AC_BE); d218 1 a218 87 ifp->if_timer = 1; (*ifp->if_start)(ifp); ifp->if_opackets++; return 0; } /* * Raw packet transmit stub for legacy drivers. * Send the packet through the mgt q so we bypass * the normal encapsulation work. */ int ieee80211_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; struct ifnet *ifp = ic->ic_ifp; m->m_pkthdr.rcvif = (void *) ni; IF_ENQUEUE(&ic->ic_mgtq, m); (*ifp->if_start)(ifp); ifp->if_opackets++; return 0; } /* XXXNH */ #if 0 /* * 802.11 output routine. This is (currently) used only to * connect bpf write calls to the 802.11 layer for injecting * raw 802.11 frames. Note we locate the ieee80211com from * the ifnet using a spare field setup at attach time. This * will go away when the virtual ap support comes in. */ int ieee80211_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct rtentry *rt0) { #define senderr(e) do { error = (e); goto bad;} while (0) struct ieee80211com *ic = ifp->if_llsoftc; /* XXX */ struct ieee80211_node *ni = NULL; struct ieee80211_frame *wh; int error; /* * Hand to the 802.3 code if not tagged as * a raw 802.11 frame. */ if (dst->sa_family != AF_IEEE80211) return ether_output(ifp, m, dst, rt0); #ifdef MAC error = mac_check_ifnet_transmit(ifp, m); if (error) senderr(error); #endif if (ifp->if_flags & IFF_MONITOR) senderr(ENETDOWN); if ((ifp->if_flags & IFF_UP) == 0) senderr(ENETDOWN); /* XXX bypass bridge, pfil, carp, etc. */ if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack)) senderr(EIO); /* XXX */ wh = mtod(m, struct ieee80211_frame *); if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != IEEE80211_FC0_VERSION_0) senderr(EIO); /* XXX */ /* locate destination node */ switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { case IEEE80211_FC1_DIR_NODS: case IEEE80211_FC1_DIR_FROMDS: ni = ieee80211_find_txnode(ic, wh->i_addr1); break; case IEEE80211_FC1_DIR_TODS: case IEEE80211_FC1_DIR_DSTODS: if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) senderr(EIO); /* XXX */ ni = ieee80211_find_txnode(ic, wh->i_addr3); break; default: senderr(EIO); /* XXX */ } if (ni == NULL) { d220 1 a220 2 * Permit packets w/ bpf params through regardless * (see below about sa_len). d222 2 a223 3 if (dst->sa_len == 0) senderr(EHOSTUNREACH); ni = ieee80211_ref_node(ic->ic_bss); d225 2 a226 36 /* XXX ctrl frames should go through */ if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && (m->m_flags & M_PWR_SAV) == 0) { /* * Station in power save mode; pass the frame * to the 802.11 layer and continue. We'll get * the frame back when the time is right. */ ieee80211_pwrsave(ni, m); error = 0; goto reclaim; } /* calculate priority so drivers can find the tx queue */ /* XXX assumes an 802.3 frame */ if (ieee80211_classify(ic, m, ni)) senderr(EIO); /* XXX */ BPF_MTAP(ifp, m); /* * NB: DLT_IEEE802_11_RADIO identifies the parameters are * present by setting the sa_len field of the sockaddr (yes, * this is a hack). * NB: we assume sa_data is suitably aligned to cast. */ return ic->ic_raw_xmit(ni, m, (const struct ieee80211_bpf_params *) (dst->sa_len ? dst->sa_data : NULL)); bad: if (m != NULL) m_freem(m); reclaim: if (ni != NULL) ieee80211_free_node(ni); return error; #undef senderr a227 1 #endif d244 1 a244 1 MGETHDR(m, M_NOWAIT, MT_DATA); d247 1 a248 1 ic->ic_stats.is_tx_nobuf++; a250 1 MH_ALIGN(m, sizeof(struct ieee80211_frame)); d259 1 a259 2 ic->ic_opmode != IEEE80211_M_HOSTAP && ic->ic_opmode != IEEE80211_M_WDS) a261 1 M_WME_SETAC(m, WME_AC_BE); d314 18 a331 1 v_wme_ac = TID_TO_WME_AC(EVL_PRIOFTAG(ni->ni_vlan)); d337 2 a338 1 uint8_t tos; d340 1 a340 1 * IP frame, map the DSCP bits from the TOS field. d342 19 a360 6 /* XXX m_copydata may be too slow for fast path */ /* NB: ip header may not be in first mbuf */ m_copydata(m, sizeof(struct ether_header) + offsetof(struct ip, ip_tos), sizeof(tos), &tos); tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ d_wme_ac = TID_TO_WME_AC(tos); d405 1 a405 1 int needed_space = ic->ic_headroom + hdrsize; a473 3 IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, "%s: cannot get writable mbuf\n", __func__); ic->ic_stats.is_tx_nobuf++; /* XXX new stat */ d489 1 a489 1 if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) { d491 1 a491 1 IEEE80211_KEY_UNDEFINED(&ic->ic_nw_keys[ic->ic_def_txkey])) d509 1 a509 1 IEEE80211_KEY_UNDEFINED(&ic->ic_nw_keys[ic->ic_def_txkey])) d528 1 a528 1 int hdrsize, datalen, addqos, txfrag, isff; a529 5 /* * Copy existing Ethernet header to a safe place. The * rest of the code assumes it's ok to strip it when * reorganizing state for the final encapsulation. */ a556 1 goto bad; d568 1 a568 1 addqos = (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) && d575 6 a580 1 hdrsize = roundup(hdrsize, sizeof(uint32_t)); d582 9 a590 68 if ((isff = m->m_flags & M_FF) != 0) { struct mbuf *m2; struct ether_header eh2; /* * Fast frame encapsulation. There must be two packets * chained with m_nextpkt. We do header adjustment for * each, add the tunnel encapsulation, and then concatenate * the mbuf chains to form a single frame for transmission. */ m2 = m->m_nextpkt; if (m2 == NULL) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_SUPERG, "%s: only one frame\n", __func__); goto bad; } m->m_nextpkt = NULL; /* * Include fast frame headers in adjusting header * layout; this allocates space according to what * ieee80211_encap_fastframe will do. */ m = ieee80211_mbuf_adjust(ic, hdrsize + sizeof(struct llc) + sizeof(uint32_t) + 2 + sizeof(struct ether_header), key, m); if (m == NULL) { /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ m_freem(m2); goto bad; } /* * Copy second frame's Ethernet header out of line * and adjust for encapsulation headers. Note that * we make room for padding in case there isn't room * at the end of first frame. */ IASSERT(m2->m_len >= sizeof(eh2), ("no ethernet header!")); memcpy(&eh2, mtod(m2, void *), sizeof(struct ether_header)); m2 = ieee80211_mbuf_adjust(ic, ATH_FF_MAX_HDR_PAD + sizeof(struct ether_header), NULL, m2); if (m2 == NULL) { /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ goto bad; } m = ieee80211_encap_fastframe(ic, m, &eh, m2, &eh2); if (m == NULL) goto bad; } else { /* * Normal frame. */ m = ieee80211_mbuf_adjust(ic, hdrsize, key, m); if (m == NULL) { /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ goto bad; } /* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */ m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); llc = mtod(m, struct llc *); llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_control = LLC_UI; llc->llc_snap.org_code[0] = 0; llc->llc_snap.org_code[1] = 0; llc->llc_snap.org_code[2] = 0; llc->llc_snap.ether_type = eh.ether_type; } d600 1 a600 1 *(uint16_t *)wh->i_dur = 0; a627 1 case IEEE80211_M_WDS: a640 29 /* * Check if A-MPDU tx aggregation is setup or if we * should try to enable it. The sta must be associated * with HT and A-MPDU enabled for use. On the first * frame that goes out We issue an ADDBA request and * wait for a reply. The frame being encapsulated * will go out w/o using A-MPDU, or possibly it might * be collected by the driver and held/retransmit. * ieee80211_ampdu_request handles staggering requests * in case the receiver NAK's us or we are otherwise * unable to establish a BA stream. */ if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) && (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_TX)) { struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac]; if (IEEE80211_AMPDU_RUNNING(tap)) { /* * Operational, mark frame for aggregation. */ qwh->i_qos[0] |= IEEE80211_QOS_ACKPOLICY_BA; } else if (!IEEE80211_AMPDU_REQUESTED(tap)) { /* * Not negotiated yet, request service. */ ieee80211_ampdu_request(ni, tap); } } /* XXX works even when BA marked above */ d642 1 a642 1 qwh->i_qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; d646 1 a646 1 *(uint16_t *)wh->i_seq = d650 3 a652 3 *(uint16_t *)wh->i_seq = htole16(ni->ni_txseqs[IEEE80211_NONQOS_TID] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[IEEE80211_NONQOS_TID]++; d657 1 a657 2 (ic->ic_caps & IEEE80211_C_TXFRAG) && !isff); /* NB: don't fragment ff's */ d666 2 a667 2 !IEEE80211_KEY_UNDEFINED(key) : !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) { a677 6 /* * NB: frag flags may leak from above; they should only * be set on return to the caller if we fragment at * the 802.11 layer. */ m->m_flags &= ~(M_FRAG | M_FIRSTFRAG); a682 4 if (IEEE80211_IS_MULTICAST(wh->i_addr1)) IEEE80211_NODE_STAT(ni, tx_mcast); else IEEE80211_NODE_STAT(ni, tx_ucast); a873 129 * Do Ethernet-LLC encapsulation for each payload in a fast frame * tunnel encapsulation. The frame is assumed to have an Ethernet * header at the front that must be stripped before prepending the * LLC followed by the Ethernet header passed in (with an Ethernet * type that specifies the payload size). */ static struct mbuf * ieee80211_encap1(struct ieee80211com *ic, struct mbuf *m, const struct ether_header *eh) { struct llc *llc; uint16_t payload; /* XXX optimize by combining m_adj+M_PREPEND */ m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); llc = mtod(m, struct llc *); llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_control = LLC_UI; llc->llc_snap.org_code[0] = 0; llc->llc_snap.org_code[1] = 0; llc->llc_snap.org_code[2] = 0; llc->llc_snap.ether_type = eh->ether_type; payload = m->m_pkthdr.len; /* NB: w/o Ethernet header */ M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT); if (m == NULL) { /* XXX cannot happen */ IEEE80211_DPRINTF(ic, IEEE80211_MSG_SUPERG, "%s: no space for ether_header\n", __func__); ic->ic_stats.is_tx_nobuf++; return NULL; } ETHER_HEADER_COPY(mtod(m, void *), eh); mtod(m, struct ether_header *)->ether_type = htons(payload); return m; } /* * Do fast frame tunnel encapsulation. The two frames and * Ethernet headers are supplied. The caller is assumed to * have arrange for space in the mbuf chains for encapsulating * headers (to avoid major mbuf fragmentation). * * The encapsulated frame is returned or NULL if there is a * problem (should not happen). */ static struct mbuf * ieee80211_encap_fastframe(struct ieee80211com *ic, struct mbuf *m1, const struct ether_header *eh1, struct mbuf *m2, const struct ether_header *eh2) { struct llc *llc; struct mbuf *m; int pad; /* * First, each frame gets a standard encapsulation. */ m1 = ieee80211_encap1(ic, m1, eh1); if (m1 == NULL) { m_freem(m2); return NULL; } m2 = ieee80211_encap1(ic, m2, eh2); if (m2 == NULL) { m_freem(m1); return NULL; } /* * Pad leading frame to a 4-byte boundary. If there * is space at the end of the first frame, put it * there; otherwise prepend to the front of the second * frame. We know doing the second will always work * because we reserve space above. We prefer appending * as this typically has better DMA alignment properties. */ for (m = m1; m->m_next != NULL; m = m->m_next) ; pad = roundup2(m1->m_pkthdr.len, 4) - m1->m_pkthdr.len; if (pad) { if (M_TRAILINGSPACE(m) < pad) { /* prepend to second */ m2->m_data -= pad; m2->m_len += pad; m2->m_pkthdr.len += pad; } else { /* append to first */ m->m_len += pad; m1->m_pkthdr.len += pad; } } /* * Now, stick 'em together and prepend the tunnel headers; * first the Atheros tunnel header (all zero for now) and * then a special fast frame LLC. * * XXX optimize by prepending together */ m->m_next = m2; /* NB: last mbuf from above */ m1->m_pkthdr.len += m2->m_pkthdr.len; M_PREPEND(m1, sizeof(uint32_t)+2, M_DONTWAIT); if (m1 == NULL) { /* XXX cannot happen */ IEEE80211_DPRINTF(ic, IEEE80211_MSG_SUPERG, "%s: no space for tunnel header\n", __func__); ic->ic_stats.is_tx_nobuf++; return NULL; } memset(mtod(m1, void *), 0, sizeof(uint32_t)+2); M_PREPEND(m1, sizeof(struct llc), M_DONTWAIT); if (m1 == NULL) { /* XXX cannot happen */ IEEE80211_DPRINTF(ic, IEEE80211_MSG_SUPERG, "%s: no space for llc header\n", __func__); ic->ic_stats.is_tx_nobuf++; return NULL; } llc = mtod(m1, struct llc *); llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_control = LLC_UI; llc->llc_snap.org_code[0] = ATH_FF_SNAP_ORGCODE_0; llc->llc_snap.org_code[1] = ATH_FF_SNAP_ORGCODE_1; llc->llc_snap.org_code[2] = ATH_FF_SNAP_ORGCODE_2; llc->llc_snap.ether_type = htons(ATH_FF_ETH_TYPE); ic->ic_stats.is_ff_encap++; return m1; } /* d968 2 a969 2 static uint8_t * ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) d985 2 a986 2 static uint8_t * ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) d1004 2 a1005 2 static uint8_t * ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) d1016 2 a1017 2 static uint8_t * ieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic) d1019 1 a1019 1 uint8_t erp; d1034 2 a1035 2 static uint8_t * ieee80211_setup_wpa_ie(struct ieee80211com *ic, uint8_t *ie) d1047 2 a1048 2 static const uint8_t oui[4] = { WPA_OUI_BYTES, WPA_OUI_TYPE }; static const uint8_t cipher_suite[][4] = { d1056 1 a1056 1 static const uint8_t wep104_suite[4] = d1058 1 a1058 1 static const uint8_t key_mgt_unspec[4] = d1060 1 a1060 1 static const uint8_t key_mgt_psk[4] = d1063 2 a1064 2 uint8_t *frm = ie; uint8_t *selcnt; d1120 2 a1121 2 static uint8_t * ieee80211_setup_rsn_ie(struct ieee80211com *ic, uint8_t *ie) d1133 1 a1133 1 static const uint8_t cipher_suite[][4] = { d1141 1 a1141 1 static const uint8_t wep104_suite[4] = d1143 1 a1143 1 static const uint8_t key_mgt_unspec[4] = d1145 1 a1145 1 static const uint8_t key_mgt_psk[4] = d1148 2 a1149 2 uint8_t *frm = ie; uint8_t *selcnt; d1206 2 a1207 2 static uint8_t * ieee80211_add_wpa(uint8_t *frm, struct ieee80211com *ic) d1222 2 a1223 2 static uint8_t * ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme) d1241 2 a1242 2 static uint8_t * ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme) a1282 25 #define ATH_OUI_BYTES 0x00, 0x03, 0x7f /* * Add a WME information element to a frame. */ static uint8_t * ieee80211_add_ath(uint8_t *frm, uint8_t caps, uint16_t defkeyix) { static const struct ieee80211_ath_ie info = { .ath_id = IEEE80211_ELEMID_VENDOR, .ath_len = sizeof(struct ieee80211_ath_ie) - 2, .ath_oui = { ATH_OUI_BYTES }, .ath_oui_type = ATH_OUI_TYPE, .ath_oui_subtype= ATH_OUI_SUBTYPE, .ath_version = ATH_OUI_VERSION, }; struct ieee80211_ath_ie *ath = (struct ieee80211_ath_ie *) frm; memcpy(frm, &info, sizeof(info)); ath->ath_capability = caps; ath->ath_defkeyix[0] = (defkeyix & 0xff); ath->ath_defkeyix[1] = ((defkeyix >> 8) & 0xff); return frm + sizeof(info); } #undef ATH_OUI_BYTES d1289 4 a1292 4 const uint8_t sa[IEEE80211_ADDR_LEN], const uint8_t da[IEEE80211_ADDR_LEN], const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t *ssid, size_t ssidlen, d1296 1 a1297 1 const struct ieee80211_rateset *rs; d1299 1 a1299 1 uint8_t *frm; a1320 1 ic->ic_headroom + sizeof(struct ieee80211_frame), d1333 3 a1335 3 rs = ieee80211_get_suprates(ic, ic->ic_curchan); frm = ieee80211_add_rates(frm, rs); frm = ieee80211_add_xrates(frm, rs); d1341 1 a1341 1 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); a1368 26 * Calculate capability information for mgt frames. */ static uint16_t getcapinfo(struct ieee80211com *ic, struct ieee80211_channel *chan) { uint16_t capinfo; IASSERT(ic->ic_opmode != IEEE80211_M_STA, ("station mode")); if (ic->ic_opmode == IEEE80211_M_HOSTAP) capinfo = IEEE80211_CAPINFO_ESS; else if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = 0; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; return capinfo; } /* a1376 1 #define HTFLAGS (IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT) a1377 1 const struct ieee80211_rateset *rs; d1379 3 a1381 3 uint8_t *frm; uint16_t capinfo; int has_challenge, is_shared_key, ret, status; d1397 1 a1412 5 * [tlv] HT capabilities * [tlv] HT information * [tlv] Vendor OUI HT capabilities (optional) * [tlv] Vendor OUI HT information (optional) * [tlv] Atheros capabilities a1414 1 ic->ic_headroom + sizeof(struct ieee80211_frame), d1416 2 a1417 2 + sizeof(uint16_t) + sizeof(uint16_t) a1427 4 /* XXX check for cluster requirement */ + 2*sizeof(struct ieee80211_ie_htcap) + 4 + 2*sizeof(struct ieee80211_ie_htinfo) + 4 + sizeof(struct ieee80211_ath_ie) d1434 1 a1434 1 *(uint16_t *)frm = htole16(ic->ic_bss->ni_intval); d1436 12 a1447 2 capinfo = getcapinfo(ic, ic->ic_curchan); *(uint16_t *)frm = htole16(capinfo); d1452 1 a1452 2 rs = ieee80211_get_suprates(ic, ic->ic_curchan); frm = ieee80211_add_rates(frm, rs); d1454 1 a1454 1 if (IEEE80211_IS_CHAN_FHSS(ic->ic_curchan)) { d1477 1 a1477 1 if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) d1479 1 a1479 12 frm = ieee80211_add_xrates(frm, rs); /* * NB: legacy 11b clients do not get certain ie's. * The caller identifies such clients by passing * a token in arg to us. Could expand this to be * any legacy client for stuff like HT ie's. */ if (IEEE80211_IS_CHAN_HT(ic->ic_curchan) && arg != IEEE80211_SEND_LEGACY_11B) { frm = ieee80211_add_htcap(frm, ni); frm = ieee80211_add_htinfo(frm, ni); } d1482 1 a1482 10 if (IEEE80211_IS_CHAN_HT(ic->ic_curchan) && (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT) && arg != IEEE80211_SEND_LEGACY_11B) { frm = ieee80211_add_htcap_vendor(frm, ni); frm = ieee80211_add_htinfo_vendor(frm, ni); } if (ni->ni_ath_ie != NULL) frm = ieee80211_add_ath(frm, ni->ni_ath_flags, ni->ni_ath_defkeyix); m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); d1505 1 a1505 2 ic->ic_headroom + sizeof(struct ieee80211_frame), 3 * sizeof(uint16_t) d1507 1 a1507 1 sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0) d1512 1 a1512 1 ((uint16_t *)frm)[0] = d1515 2 a1516 2 ((uint16_t *)frm)[1] = htole16(arg); /* sequence number */ ((uint16_t *)frm)[2] = htole16(status);/* status */ d1519 1 a1519 1 ((uint16_t *)frm)[3] = d1522 1 a1522 1 memcpy(&((uint16_t *)frm)[4], ni->ni_challenge, d1525 1 a1525 1 4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN; d1533 1 a1533 1 m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t); d1542 1 a1542 2 ieee80211_add_callback(m, ieee80211_tx_mgt_cb, (void *) ic->ic_state); d1549 1 a1549 3 m = ieee80211_getmgtframe(&frm, ic->ic_headroom + sizeof(struct ieee80211_frame), sizeof(uint16_t)); d1552 2 a1553 2 *(uint16_t *)frm = htole16(arg); /* reason */ m->m_pkthdr.len = m->m_len = sizeof(uint16_t); a1571 3 * [tlv] HT capabilities * [tlv] Vendor OUI HT capabilities (optional) * [tlv] Atheros capabilities (if negotiated) d1575 2 a1576 3 ic->ic_headroom + sizeof(struct ieee80211_frame), sizeof(uint16_t) + sizeof(uint16_t) a1581 2 + 2*sizeof(struct ieee80211_ie_htcap) + 4 + sizeof(struct ieee80211_ath_ie) d1587 5 a1591 3 IASSERT(ic->ic_opmode == IEEE80211_M_STA, ("wrong mode %u", ic->ic_opmode)); capinfo = IEEE80211_CAPINFO_ESS; d1601 1 a1601 1 if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) && d1604 1 a1604 4 if ((ni->ni_capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) && (ic->ic_flags & IEEE80211_F_DOTH)) capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; *(uint16_t *)frm = htole16(capinfo); d1607 1 a1607 4 IASSERT(ic->ic_bss->ni_intval != 0, ("beacon interval is zero!")); *(uint16_t *)frm = htole16(howmany(ic->ic_lintval, ic->ic_bss->ni_intval)); a1617 4 if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) && ni->ni_htcap_ie != NULL && ni->ni_htcap_ie[0] == IEEE80211_ELEMID_HTCAP) frm = ieee80211_add_htcap(frm, ni); a1619 11 if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) && ni->ni_htcap_ie != NULL && ni->ni_htcap_ie[0] == IEEE80211_ELEMID_VENDOR) frm = ieee80211_add_htcap_vendor(frm, ni); if (IEEE80211_ATH_CAP(ic, ni, IEEE80211_F_ATHEROS)) frm = ieee80211_add_ath(frm, IEEE80211_ATH_CAP(ic, ni, IEEE80211_F_ATHEROS), (ic->ic_flags & IEEE80211_F_WPA) == 0 && ni->ni_authmode != IEEE80211_AUTH_8021X && ic->ic_def_txkey != IEEE80211_KEYIX_NONE ? ic->ic_def_txkey : 0x7fff); d1624 1 a1624 1 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); d1626 1 a1626 2 ieee80211_add_callback(m, ieee80211_tx_mgt_cb, (void *) ic->ic_state); d1632 1 a1632 1 * asresp frame format a1638 3 * [tlv] HT capabilities (standard or vendor OUI) * [tlv] HT information (standard or vendor OUI) * [tlv] Atheros capabilities (if enabled and STA enabled) d1641 3 a1643 4 ic->ic_headroom + sizeof(struct ieee80211_frame), sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) a1646 3 + sizeof(struct ieee80211_ie_htcap) + 4 + sizeof(struct ieee80211_ie_htinfo) + 4 + sizeof(struct ieee80211_ath_ie) d1651 9 a1659 2 capinfo = getcapinfo(ic, ic->ic_curchan); *(uint16_t *)frm = htole16(capinfo); d1662 1 a1662 1 *(uint16_t *)frm = htole16(arg); /* status */ d1666 1 a1666 1 *(uint16_t *)frm = htole16(ni->ni_associd); a1673 5 /* NB: respond according to what we received */ if ((ni->ni_flags & HTFLAGS) == IEEE80211_NODE_HT) { frm = ieee80211_add_htcap(frm, ni); frm = ieee80211_add_htinfo(frm, ni); } d1676 1 a1676 9 if ((ni->ni_flags & HTFLAGS) == HTFLAGS) { frm = ieee80211_add_htcap_vendor(frm, ni); frm = ieee80211_add_htinfo_vendor(frm, ni); } if (IEEE80211_ATH_CAP(ic, ni, IEEE80211_F_ATHEROS)) frm = ieee80211_add_ath(frm, IEEE80211_ATH_CAP(ic, ni, IEEE80211_F_ATHEROS), ni->ni_ath_defkeyix); m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); d1683 1 a1683 3 m = ieee80211_getmgtframe(&frm, ic->ic_headroom + sizeof(struct ieee80211_frame), sizeof(uint16_t)); d1686 2 a1687 2 *(uint16_t *)frm = htole16(arg); /* reason */ m->m_pkthdr.len = m->m_len = sizeof(uint16_t); d1700 2 a1701 5 ret = ieee80211_mgmt_output(ic, ni, m, type); if (ret != 0) goto bad; return 0; d1703 2 a1704 1 ieee80211_free_node(ni); a1706 41 #undef HTFLAGS } static void ieee80211_tx_mgt_timeout(void *arg) { struct ieee80211_node *ni = arg; struct ieee80211com *ic = ni->ni_ic; if (ic->ic_state != IEEE80211_S_INIT && (ic->ic_flags & IEEE80211_F_SCAN) == 0) { /* * NB: it's safe to specify a timeout as the reason here; * it'll only be used in the right state. */ ieee80211_new_state(ic, IEEE80211_S_SCAN, IEEE80211_SCAN_FAIL_TIMEOUT); } } static void ieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status) { struct ieee80211com *ic = ni->ni_ic; enum ieee80211_state ostate = (enum ieee80211_state) arg; /* * Frame transmit completed; arrange timer callback. If * transmit was successfuly we wait for response. Otherwise * we arrange an immediate callback instead of doing the * callback directly since we don't know what state the driver * is in (e.g. what locks it is holding). This work should * not be too time-critical and not happen too often so the * added overhead is acceptable. * * XXX what happens if !acked but response shows up before callback? */ if (ic->ic_state == ostate) callout_reset(&ic->ic_mgtsend, status == 0 ? IEEE80211_TRANS_WAIT*hz : 0, ieee80211_tx_mgt_timeout, ni); d1713 1 a1713 1 ieee80211_beacon_alloc(struct ieee80211_node *ni, a1715 1 struct ieee80211com *ic = ni->ni_ic; d1720 2 a1721 2 uint8_t *frm; uint16_t capinfo; a1732 1 * [tlv] country code a1736 4 * [tlv] HT capabilities * [tlv] HT information * [tlv] Vendor OUI HT capabilities (optional) * [tlv] Vendor OUI HT information (optional) d1742 2 a1743 2 + sizeof(uint16_t) /* beacon interval */ + sizeof(uint16_t) /* capabilities */ a1747 1 + sizeof(struct ieee80211_country_ie) /* country code */ a1753 3 /* XXX conditional? */ + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */ + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */ d1755 1 a1755 2 m = ieee80211_getmgtframe(&frm, ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen); a1762 2 memset(bo, 0, sizeof(*bo)); d1765 1 a1765 1 *(uint16_t *)frm = htole16(ni->ni_intval); d1767 13 a1779 3 capinfo = getcapinfo(ic, ni->ni_chan); bo->bo_caps = (uint16_t *)frm; *(uint16_t *)frm = htole16(capinfo); d1789 1 a1789 1 if (!IEEE80211_IS_CHAN_FHSS(ic->ic_bsschan)) { d1792 1 a1792 1 *frm++ = ieee80211_chan2ieee(ic, ic->ic_bsschan); d1800 1 a1800 1 } else if (ic->ic_opmode == IEEE80211_M_HOSTAP) { d1812 1 a1812 16 bo->bo_tim_trailer = frm; if (ic->ic_flags & IEEE80211_F_DOTH) frm = ieee80211_add_countryie(frm, ic, ic->ic_countrycode, ic->ic_location); if (ic->ic_flags & IEEE80211_F_WPA) frm = ieee80211_add_wpa(frm, ic); if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) { bo->bo_erp = frm; frm = ieee80211_add_erp(frm, ic); } frm = ieee80211_add_xrates(frm, rs); if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan)) { frm = ieee80211_add_htcap(frm, ni); bo->bo_htinfo = frm; frm = ieee80211_add_htinfo(frm, ni); } d1816 1 d1818 7 a1824 7 if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan) && (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT)) { frm = ieee80211_add_htcap_vendor(frm, ni); frm = ieee80211_add_htinfo_vendor(frm, ni); } bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer; m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); d1832 1 a1832 1 *(uint16_t *)wh->i_dur = 0; d1836 1 a1836 1 *(uint16_t *)wh->i_seq = 0; d1845 1 a1845 1 ieee80211_beacon_update(struct ieee80211_node *ni, a1847 1 struct ieee80211com *ic = ni->ni_ic; d1849 1 a1849 1 uint16_t capinfo; d1853 11 a1863 1 capinfo = getcapinfo(ic, ni->ni_chan); d1901 1 a1901 1 if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) { d1903 1 a1903 1 clrbit(bo->bo_flags, IEEE80211_BEACON_WME); a1906 5 if (isset(bo->bo_flags, IEEE80211_BEACON_HTINFO)) { ieee80211_ht_update_beacon(ic, bo); clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO); } d1911 1 a1911 1 if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) { d1947 4 a1950 9 int adjust = tie->tim_bitmap+timlen - bo->bo_tim_trailer; ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust, bo->bo_tim_trailer_len); bo->bo_tim_trailer += adjust; bo->bo_wme += adjust; bo->bo_erp += adjust; bo->bo_htinfo += adjust; d1961 1 a1961 1 clrbit(bo->bo_flags, IEEE80211_BEACON_TIM); d1973 1 a1973 1 if (mcast && tie->tim_count == 0) a1976 7 if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) { /* * ERP element needs updating. */ (void) ieee80211_add_erp(bo->bo_erp, ic); clrbit(bo->bo_flags, IEEE80211_BEACON_ERP); } d1983 46 @ 1.46 log @Add software fragmentation of 802.11 packets to net80211. Some wireless NICs need the host's help to fragment packets before the NIC transmits them. From Sam Leffler. Screen-scraped by me from the WWW source browser at perforce.freebsd.org. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.45 2006/11/16 01:33:41 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.45 2006/11/16 01:33:41 christos Exp $"); d531 1 a531 1 memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header)); d2005 1 a2005 1 ieee80211_dump_pkt(mtod(m, caddr_t), m->m_len, -1, -1); @ 1.46.2.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.46 2007/01/06 06:02:33 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.46 2007/01/06 06:02:33 dyoung Exp $"); d531 1 a531 1 memcpy(&eh, mtod(m, void *), sizeof(struct ether_header)); d2005 1 a2005 1 ieee80211_dump_pkt(mtod(m, void *), m->m_len, -1, -1); @ 1.45 log @__unused removal on arguments; approved by core. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.44 2006/10/12 01:32:31 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.44 2006/10/12 01:32:31 christos Exp $"); d80 3 d528 1 a528 1 int hdrsize, datalen, addqos; d654 4 d669 1 a669 2 /* XXX do fragmentation */ if (!ieee80211_crypto_enmic(ic, key, m, 0)) { d678 3 d874 92 @ 1.44 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_output.c,v 1.43 2006/02/19 07:52:43 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.43 2006/02/19 07:52:43 dyoung Exp $"); d503 1 a503 1 struct ieee80211_node *ni __unused) d1122 1 a1122 1 ieee80211_add_wme_info(u_int8_t *frm, struct ieee80211_wme_state *wme __unused) d1745 1 a1745 1 struct ieee80211_beacon_offsets *bo, struct mbuf *m __unused, int mcast) @ 1.43 log @From sam@@FreeBSD.org: set the mgt frame tx timer before dispatching the frame to the driver; this closes a race where a response could be processed before the timer was started and cause a RUN->SCAN state change when operating in station mode @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.42 2006/02/19 07:49:28 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.42 2006/02/19 07:49:28 dyoung Exp $"); d502 2 a503 1 ieee80211_crypto_getmcastkey(struct ieee80211com *ic, struct ieee80211_node *ni) d1122 1 a1122 1 ieee80211_add_wme_info(u_int8_t *frm, struct ieee80211_wme_state *wme) d1745 1 a1745 1 struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) @ 1.43.14.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.45 2006/11/16 01:33:41 christos Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.45 2006/11/16 01:33:41 christos Exp $"); d502 1 a502 2 ieee80211_crypto_getmcastkey(struct ieee80211com *ic, struct ieee80211_node *ni) d1744 1 a1744 1 struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) @ 1.43.14.2 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.46 2007/01/06 06:02:33 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.46 2007/01/06 06:02:33 dyoung Exp $"); a79 3 static int ieee80211_fragment(struct ieee80211com *, struct mbuf *, u_int hdrsize, u_int ciphdrsize, u_int mtu); d525 1 a525 1 int hdrsize, datalen, addqos, txfrag; a650 4 /* check if xmit fragmentation is required */ txfrag = (m->m_pkthdr.len > ic->ic_fragthreshold && !IEEE80211_IS_MULTICAST(wh->i_addr1) && (m->m_flags & M_FF) == 0); /* NB: don't fragment ff's */ d662 2 a663 1 if (!ieee80211_crypto_enmic(ic, key, m, txfrag)) { a671 3 if (txfrag && !ieee80211_fragment(ic, m, hdrsize, key != NULL ? key->wk_cipher->ic_header : 0, ic->ic_fragthreshold)) goto bad; a864 92 * Fragment the frame according to the specified mtu. * The size of the 802.11 header (w/o padding) is provided * so we don't need to recalculate it. We create a new * mbuf for each fragment and chain it through m_nextpkt; * we might be able to optimize this by reusing the original * packet's mbufs but that is significantly more complicated. */ static int ieee80211_fragment(struct ieee80211com *ic, struct mbuf *m0, u_int hdrsize, u_int ciphdrsize, u_int mtu) { struct ieee80211_frame *wh, *whf; struct mbuf *m, *prev, *next; u_int totalhdrsize, fragno, fragsize, off, remainder, payload; IASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?")); IASSERT(m0->m_pkthdr.len > mtu, ("pktlen %u mtu %u", m0->m_pkthdr.len, mtu)); wh = mtod(m0, struct ieee80211_frame *); /* NB: mark the first frag; it will be propagated below */ wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; totalhdrsize = hdrsize + ciphdrsize; fragno = 1; off = mtu - ciphdrsize; remainder = m0->m_pkthdr.len - off; prev = m0; do { fragsize = totalhdrsize + remainder; if (fragsize > mtu) fragsize = mtu; IASSERT(fragsize < MCLBYTES, ("fragment size %u too big!", fragsize)); if (fragsize > MHLEN) m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); else m = m_gethdr(M_DONTWAIT, MT_DATA); if (m == NULL) goto bad; /* leave room to prepend any cipher header */ m_align(m, fragsize - ciphdrsize); /* * Form the header in the fragment. Note that since * we mark the first fragment with the MORE_FRAG bit * it automatically is propagated to each fragment; we * need only clear it on the last fragment (done below). */ whf = mtod(m, struct ieee80211_frame *); memcpy(whf, wh, hdrsize); *(u_int16_t *)&whf->i_seq[0] |= htole16( (fragno & IEEE80211_SEQ_FRAG_MASK) << IEEE80211_SEQ_FRAG_SHIFT); fragno++; payload = fragsize - totalhdrsize; /* NB: destination is known to be contiguous */ m_copydata(m0, off, payload, mtod(m, u_int8_t *) + hdrsize); m->m_len = hdrsize + payload; m->m_pkthdr.len = hdrsize + payload; m->m_flags |= M_FRAG; /* chain up the fragment */ prev->m_nextpkt = m; prev = m; /* deduct fragment just formed */ remainder -= payload; off += payload; } while (remainder != 0); whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; /* strip first mbuf now that everything has been copied */ m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize))); m0->m_flags |= M_FIRSTFRAG | M_FRAG; ic->ic_stats.is_tx_fragframes++; ic->ic_stats.is_tx_frags += fragno-1; return 1; bad: /* reclaim fragments but leave original frame for caller to free */ for (m = m0->m_nextpkt; m != NULL; m = next) { next = m->m_nextpkt; m->m_nextpkt = NULL; /* XXX paranoid */ m_freem(m); } m0->m_nextpkt = NULL; return 0; } /* @ 1.43.16.1 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.43 2006/02/19 07:52:43 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.43 2006/02/19 07:52:43 dyoung Exp $"); d502 1 a502 2 ieee80211_crypto_getmcastkey(struct ieee80211com *ic, struct ieee80211_node *ni __unused) d1121 1 a1121 1 ieee80211_add_wme_info(u_int8_t *frm, struct ieee80211_wme_state *wme __unused) d1744 1 a1744 1 struct ieee80211_beacon_offsets *bo, struct mbuf *m __unused, int mcast) @ 1.43.16.2 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.43.16.1 2006/10/22 06:07:28 yamt Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.43.16.1 2006/10/22 06:07:28 yamt Exp $"); d503 1 a503 1 struct ieee80211_node *ni) d1122 1 a1122 1 ieee80211_add_wme_info(u_int8_t *frm, struct ieee80211_wme_state *wme) d1745 1 a1745 1 struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) @ 1.42 log @In 802.11 Duration and PLCP Length calculation, account for privacy overhead in both the header and the *trailer*. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.41 2005/12/29 21:08:26 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.41 2005/12/29 21:08:26 dyoung Exp $"); d163 1 a163 1 struct mbuf *m, int type) d215 7 a221 1 ifp->if_timer = 1; d1598 2 a1599 6 ret = ieee80211_mgmt_output(ic, ni, m, type); if (ret == 0) { if (timer) ic->ic_mgt_timer = timer; } else { @ 1.41 log @In atw(4), use ieee80211_compute_duration() to compute IEEE 802.11 Duration and PLCP Length fields, and delete the abominable atw_frame_setdurs() subroutine. Make rtw(4) use the new ieee80211_compute_duration() calling convention. Add an ieee80211_key argument to ieee80211_compute_duration() and lightly constify arguments. Get the crypto header length from the key argument instead of blithely assuming a WEP header. Add some inline documentation. Account for data padding (IEEE80211_F_DATAPAD). @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.40 2005/12/11 00:55:42 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.40 2005/12/11 00:55:42 dyoung Exp $"); d789 2 a790 1 int firstlen, /* first fragment's payload + overhead length */ d809 4 a812 2 paylen -= wk->wk_cipher->ic_header; overlen += wk->wk_cipher->ic_header; @ 1.41.4.1 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.43 2006/02/19 07:52:43 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.43 2006/02/19 07:52:43 dyoung Exp $"); d163 1 a163 1 struct mbuf *m, int type, int timer) d215 1 a215 7 if (timer) { /* * Set the mgt frame timeout. */ ic->ic_mgt_timer = timer; ifp->if_timer = 1; } d789 1 a789 2 int cryptolen, /* crypto overhead: header+trailer */ firstlen, /* first fragment's payload + overhead length */ d808 2 a809 4 cryptolen = wk->wk_cipher->ic_header + wk->wk_cipher->ic_trailer; paylen -= cryptolen; overlen += cryptolen; d1589 6 a1594 2 ret = ieee80211_mgmt_output(ic, ni, m, type, timer); if (ret != 0) { @ 1.41.6.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.43 2006/02/19 07:52:43 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.43 2006/02/19 07:52:43 dyoung Exp $"); d163 1 a163 1 struct mbuf *m, int type, int timer) d215 1 a215 7 if (timer) { /* * Set the mgt frame timeout. */ ic->ic_mgt_timer = timer; ifp->if_timer = 1; } d789 1 a789 2 int cryptolen, /* crypto overhead: header+trailer */ firstlen, /* first fragment's payload + overhead length */ d808 2 a809 4 cryptolen = wk->wk_cipher->ic_header + wk->wk_cipher->ic_trailer; paylen -= cryptolen; overlen += cryptolen; d1589 6 a1594 2 ret = ieee80211_mgmt_output(ic, ni, m, type, timer); if (ret != 0) { @ 1.41.2.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.41 2005/12/29 21:08:26 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.41 2005/12/29 21:08:26 dyoung Exp $"); d163 1 a163 1 struct mbuf *m, int type, int timer) d215 1 a215 7 if (timer) { /* * Set the mgt frame timeout. */ ic->ic_mgt_timer = timer; ifp->if_timer = 1; } d789 1 a789 2 int cryptolen, /* crypto overhead: header+trailer */ firstlen, /* first fragment's payload + overhead length */ d808 2 a809 4 cryptolen = wk->wk_cipher->ic_header + wk->wk_cipher->ic_trailer; paylen -= cryptolen; overlen += cryptolen; d1589 6 a1594 2 ret = ieee80211_mgmt_output(ic, ni, m, type, timer); if (ret != 0) { @ 1.40 log @Correct comment on ieee80211_compute_duration(). @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.39 2005/11/18 16:40:09 skrll Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.39 2005/11/18 16:40:09 skrll Exp $"); d696 1 a696 1 ieee80211_compute_duration1(int len, int use_ack, uint32_t flags, int rate, d711 1 a711 1 if ((flags & IEEE80211_F_SHPREAMBLE) != 0) d778 3 d783 3 a785 2 ieee80211_compute_duration(struct ieee80211_frame_min *wh, int len, uint32_t flags, int fraglen, int rate, struct ieee80211_duration *d0, d789 13 a801 4 int firstlen, hdrlen, lastlen, lastlen0, npkt, overlen, paylen; if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) hdrlen = sizeof(struct ieee80211_frame_addr4); d803 1 a803 1 hdrlen = sizeof(struct ieee80211_frame); d805 1 a805 1 paylen = len - hdrlen; d807 4 a810 6 if ((wh->i_fc[1] & IEEE80211_FC1_WEP) != 0) { /* XXX assumes the packet is already WEP encapsulated */ paylen -= IEEE80211_WEP_TOTLEN; overlen = IEEE80211_WEP_TOTLEN + IEEE80211_CRC_LEN; } else overlen = IEEE80211_CRC_LEN; d833 1 a833 1 "fraglen %d overlen %d len %d rate %d flags %08x\n", d835 1 a835 1 overlen, len, rate, flags); d842 1 a842 1 ack, flags, rate, d0); d850 1 a850 1 return ieee80211_compute_duration1(lastlen + hdrlen, ack, flags, rate, @ 1.39 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_output.c,v 1.38 2005/09/25 00:04:01 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.38 2005/09/25 00:04:01 dyoung Exp $"); d777 1 a777 1 * of first/only fragment @ 1.38 log @Cosmetic: fix indentation. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.37 2005/08/21 00:07:57 dyoung Exp $ */ d36 1 a36 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.26 2005/07/06 01:55:17 sam Exp $"); d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.37 2005/08/21 00:07:57 dyoung Exp $"); d99 56 d191 3 a193 24 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(u_int16_t *)wh->i_dur = 0; *(u_int16_t *)wh->i_seq = htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; /* * Hack. When sending PROBE_REQ frames while scanning we * explicitly force a broadcast rather than (as before) clobber * ni_macaddr and ni_bssid. This is stopgap, we need a way * to communicate this directly rather than do something * implicit based on surrounding state. */ if (type == IEEE80211_FC0_SUBTYPE_PROBE_REQ && (ic->ic_flags & IEEE80211_F_SCAN)) { IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); } else { IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); } d210 1 a210 1 ieee80211_chan2ieee(ic, ni->ni_chan)); d222 4 d228 1 a228 1 ieee80211_send_nulldata(struct ieee80211com *ic, struct ieee80211_node *ni) d230 1 d239 1 d242 1 a242 1 m->m_pkthdr.rcvif = (void *) ieee80211_ref_node(ni); d245 7 a251 12 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA; *(u_int16_t *)wh->i_dur = 0; *(u_int16_t *)wh->i_seq = htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; /* XXX WDS */ wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_myaddr); d256 6 d1162 85 a1257 1 enum ieee80211_phymode mode; a1276 32 case IEEE80211_FC0_SUBTYPE_PROBE_REQ: /* * prreq frame format * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates * [tlv] user-specified ie's */ m = ieee80211_getmgtframe(&frm, 2 + IEEE80211_NWID_LEN + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + (ic->ic_opt_ie != NULL ? ic->ic_opt_ie_len : 0) ); if (m == NULL) senderr(ENOMEM, is_tx_nobuf); frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen); mode = ieee80211_chan2mode(ic, ni->ni_chan); frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); if (ic->ic_opt_ie != NULL) { memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len); frm += ic->ic_opt_ie_len; } m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); IEEE80211_NODE_STAT(ni, tx_probereq); if (ic->ic_opmode == IEEE80211_M_STA) timer = IEEE80211_TRANS_WAIT; break; d1321 1 a1321 1 IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) d1338 1 a1338 1 ieee80211_chan2ieee(ic, ni->ni_chan)); d1340 1 a1340 1 ieee80211_chan2ieee(ic, ni->ni_chan)); d1345 1 a1345 1 *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); d1436 1 a1436 1 ieee80211_node_unauthorize(ic, ni); /* port closed */ d1477 1 a1477 1 IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) d1533 1 a1533 1 IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) d1900 1 a1900 1 age = ((ni->ni_intval * ic->ic_lintval) << 2) / 1024; /* TU -> secs */ d1905 2 a1906 2 "[%s] save frame, %u now queued\n", ether_sprintf(ni->ni_macaddr), qlen); d1909 1 a1909 1 ic->ic_set_tim(ic, ni, 1); @ 1.38.6.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.38 2005/09/25 00:04:01 dyoung Exp $ */ d36 1 a36 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.34 2005/08/10 16:22:29 sam Exp $"); d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.38 2005/09/25 00:04:01 dyoung Exp $"); a98 56 * Set the direction field and address fields of an outgoing * non-QoS frame. Note this should be called early on in * constructing a frame as it sets i_fc[1]; other bits can * then be or'd in. */ static void ieee80211_send_setup(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_frame *wh, int type, const u_int8_t sa[IEEE80211_ADDR_LEN], const u_int8_t da[IEEE80211_ADDR_LEN], const u_int8_t bssid[IEEE80211_ADDR_LEN]) { #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { switch (ic->ic_opmode) { case IEEE80211_M_STA: wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; IEEE80211_ADDR_COPY(wh->i_addr1, bssid); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, da); break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, bssid); break; case IEEE80211_M_HOSTAP: wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, bssid); IEEE80211_ADDR_COPY(wh->i_addr3, sa); break; case IEEE80211_M_MONITOR: /* NB: to quiet compiler */ break; } } else { wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, bssid); } *(u_int16_t *)&wh->i_dur[0] = 0; /* NB: use non-QoS tid */ *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; #undef WH4 } /* d135 24 a158 3 ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_MGT | type, ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid); d175 1 a175 1 ieee80211_chan2ieee(ic, ic->ic_curchan)); a186 4 * * NB: the caller is assumed to have setup a node reference * for use; this is necessary to deal with a race condition * when probing for inactive stations. d189 1 a189 1 ieee80211_send_nulldata(struct ieee80211_node *ni) a190 1 struct ieee80211com *ic = ni->ni_ic; a198 1 ieee80211_unref_node(&ni); d201 1 a201 1 m->m_pkthdr.rcvif = (void *) ni; d204 12 a215 7 ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid); /* NB: power management bit is never sent by an AP */ if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && ic->ic_opmode != IEEE80211_M_HOSTAP) wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; a219 6 IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "[%s] send null data frame on channel %u, pwr mgt %s\n", ether_sprintf(ni->ni_macaddr), ieee80211_chan2ieee(ic, ic->ic_curchan), wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); a1119 85 * Send a probe request frame with the specified ssid * and any optional information element data. */ int ieee80211_send_probereq(struct ieee80211_node *ni, const u_int8_t sa[IEEE80211_ADDR_LEN], const u_int8_t da[IEEE80211_ADDR_LEN], const u_int8_t bssid[IEEE80211_ADDR_LEN], const u_int8_t *ssid, size_t ssidlen, const void *optie, size_t optielen) { struct ieee80211com *ic = ni->ni_ic; enum ieee80211_phymode mode; struct ieee80211_frame *wh; struct mbuf *m; u_int8_t *frm; /* * Hold a reference on the node so it doesn't go away until after * the xmit is complete all the way in the driver. On error we * will remove our reference. */ IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1); ieee80211_ref_node(ni); /* * prreq frame format * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates * [tlv] user-specified ie's */ m = ieee80211_getmgtframe(&frm, 2 + IEEE80211_NWID_LEN + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + (optie != NULL ? optielen : 0) ); if (m == NULL) { ic->ic_stats.is_tx_nobuf++; ieee80211_free_node(ni); return ENOMEM; } frm = ieee80211_add_ssid(frm, ssid, ssidlen); mode = ieee80211_chan2mode(ic, ic->ic_curchan); frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); if (optie != NULL) { memcpy(frm, optie, optielen); frm += optielen; } m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); if (m == NULL) return ENOMEM; IASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null")); m->m_pkthdr.rcvif = (void *)ni; wh = mtod(m, struct ieee80211_frame *); ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, sa, da, bssid); /* XXX power management? */ IEEE80211_NODE_STAT(ni, tx_probereq); IEEE80211_NODE_STAT(ni, tx_mgmt); IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "[%s] send probe req on channel %u\n", ether_sprintf(wh->i_addr1), ieee80211_chan2ieee(ic, ic->ic_curchan)); IF_ENQUEUE(&ic->ic_mgtq, m); (*ic->ic_ifp->if_start)(ic->ic_ifp); return 0; } /* d1131 1 d1151 32 d1227 1 a1227 1 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) d1244 1 a1244 1 ieee80211_chan2ieee(ic, ic->ic_curchan)); d1246 1 a1246 1 ieee80211_chan2ieee(ic, ic->ic_curchan)); d1251 1 a1251 1 *frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan); d1342 1 a1342 1 ieee80211_node_unauthorize(ni); /* port closed */ d1383 1 a1383 1 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) d1439 1 a1439 1 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) d1806 1 a1806 1 age = ((ni->ni_intval * ic->ic_bintval) << 2) / 1024; /* TU -> secs */ d1811 2 a1812 2 "[%s] save frame with age %d, %u now queued\n", ether_sprintf(ni->ni_macaddr), age, qlen); d1815 1 a1815 1 ic->ic_set_tim(ni, 1); @ 1.37 log @In ieee80211_mbuf_adjust, cope with read-only mbufs: make the 802.11 header + opt(crypto header) + LLC writable, regardless of crypto state. If s/w crypto is enabled, still make the entire chain writable, as before. Reviewed by: Nick Hudson @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.36 2005/08/18 00:30:59 yamt Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.36 2005/08/18 00:30:59 yamt Exp $"); d252 2 a253 2 struct m_tag *mtag = m_tag_find(m, PACKET_TAG_VLAN, NULL); if (mtag == NULL) { @ 1.36 log @- introduce M_MOVE_PKTHDR and use it where appropriate. intended to be mostly API compatible with openbsd/freebsd. - remove a glue #define in netipsec/ipsec_osdep.h. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.35 2005/08/16 02:12:58 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.35 2005/08/16 02:12:58 dyoung Exp $"); d355 1 a355 1 int error; d407 6 d419 2 a420 2 if (key != NULL && (key->wk_flags & IEEE80211_KEY_SWCRYPT) != 0) { error = m_makewritable(&m, 0, M_COPYALL, M_DONTWAIT); d422 3 a424 4 if (error) { m_freem(m); m = NULL; } a425 1 @ 1.35 log @Fix previous patch for non-crypto operation: test for a NULL key before testing the key flags. XXX Problems remain. Nick Hudson points out my questionable XXX M_COPY_PKTHDR usage. Also, it seems to me that we may not be XXX protected against writing a read-only mbuf during the crypto XXX encapsulation stage, even if hardware does the actual crypto. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.34 2005/08/15 21:33:26 skrll Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.34 2005/08/15 21:33:26 skrll Exp $"); d389 1 a389 1 M_COPY_PKTHDR(n, m); @ 1.34 log @If we're going to s/w encrypt the mbuf chain make sure it is writable. Fixes wep on iwi(4). @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.33 2005/07/26 22:52:48 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.33 2005/07/26 22:52:48 dyoung Exp $"); d413 1 a413 1 if (key->wk_flags & IEEE80211_KEY_SWCRYPT) { @ 1.33 log @Resolve conflicts. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.31 2005/06/26 21:51:37 erh Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.31 2005/06/26 21:51:37 erh Exp $"); d355 1 d408 14 @ 1.32 log @rtw: Try to get hardware WEP to work. It seems to work in the RX direction, but not in the TX direction. The net80211 crypto framework doesn't seem to cope very well with the assymetry (I'm probably missing something), so I will use software WEP for now. net80211: In ieee80211_compute_duration, figure out whether to add the WEP header to the packet overhead by checking the WEP bit in the Frame Control field of the 802.11 header, instead of checking the IEEE80211_F_PRIVACY flag. Also, if the WEP bit is present, assume that the frame described by (wh, len) has already already been WEP encapsulated, and adjust the payload length accordingly. XXX that's a grotty hack that I will have to revisit, later. @ text @d36 1 a36 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.20 2005/02/10 17:00:48 sam Exp $"); d559 2 d595 1 a595 1 if (!ieee80211_crypto_enmic(ic, key, m)) { d923 1 a923 1 if (rsn->rsn_caps != 0) d1006 1 a1006 2 if (rsn->rsn_caps != 0) ADDSHORT(frm, rsn->rsn_caps); a1305 10 /* * When 802.1x is not in use mark the port * authorized at this point so traffic can flow. */ #ifndef IEEE80211_NO_HOSTAP if (ic->ic_opmode == IEEE80211_M_HOSTAP && status == IEEE80211_STATUS_SUCCESS && ni->ni_authmode != IEEE80211_AUTH_8021X) ieee80211_node_authorize(ic, ni); #endif /* !IEEE80211_NO_HOSTAP */ @ 1.32.2.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.32 2005/06/27 05:49:13 dyoung Exp $ */ d36 1 a36 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.34 2005/08/10 16:22:29 sam Exp $"); d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.32 2005/06/27 05:49:13 dyoung Exp $"); a98 56 * Set the direction field and address fields of an outgoing * non-QoS frame. Note this should be called early on in * constructing a frame as it sets i_fc[1]; other bits can * then be or'd in. */ static void ieee80211_send_setup(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_frame *wh, int type, const u_int8_t sa[IEEE80211_ADDR_LEN], const u_int8_t da[IEEE80211_ADDR_LEN], const u_int8_t bssid[IEEE80211_ADDR_LEN]) { #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { switch (ic->ic_opmode) { case IEEE80211_M_STA: wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; IEEE80211_ADDR_COPY(wh->i_addr1, bssid); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, da); break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, bssid); break; case IEEE80211_M_HOSTAP: wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, bssid); IEEE80211_ADDR_COPY(wh->i_addr3, sa); break; case IEEE80211_M_MONITOR: /* NB: to quiet compiler */ break; } } else { wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, bssid); } *(u_int16_t *)&wh->i_dur[0] = 0; /* NB: use non-QoS tid */ *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; #undef WH4 } /* d107 1 a107 1 struct mbuf *m, int type, int timer) d135 24 a158 3 ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_MGT | type, ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid); d175 1 a175 1 ieee80211_chan2ieee(ic, ic->ic_curchan)); d180 1 a180 7 if (timer) { /* * Set the mgt frame timeout. */ ic->ic_mgt_timer = timer; ifp->if_timer = 1; } a186 4 * * NB: the caller is assumed to have setup a node reference * for use; this is necessary to deal with a race condition * when probing for inactive stations. d189 1 a189 1 ieee80211_send_nulldata(struct ieee80211_node *ni) a190 1 struct ieee80211com *ic = ni->ni_ic; a198 1 ieee80211_unref_node(&ni); d201 1 a201 1 m->m_pkthdr.rcvif = (void *) ni; d204 12 a215 7 ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid); /* NB: power management bit is never sent by an AP */ if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && ic->ic_opmode != IEEE80211_M_HOSTAP) wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; a219 6 IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "[%s] send null data frame on channel %u, pwr mgt %s\n", ether_sprintf(ni->ni_macaddr), ieee80211_chan2ieee(ic, ic->ic_curchan), wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); d252 2 a253 2 struct m_tag *mtag = m_tag_find(m, PACKET_TAG_VLAN, NULL); if (mtag == NULL) { a354 1 int wlen = 0; d388 1 a388 1 M_MOVE_PKTHDR(n, m); a405 18 } else { /* We will overwrite the ethernet header in the * 802.11 encapsulation stage. Make sure that it * is writable. */ wlen = sizeof(struct ether_header); } /* * If we're going to s/w encrypt the mbuf chain make sure it is * writable. */ if (key != NULL && (key->wk_flags & IEEE80211_KEY_SWCRYPT) != 0) wlen = M_COPYALL; if (wlen != 0 && m_makewritable(&m, 0, wlen, M_DONTWAIT) != 0) { m_freem(m); return NULL; a558 2 if (m->m_flags & M_MORE_DATA) wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; d593 1 a593 1 if (!ieee80211_crypto_enmic(ic, key, m, 0)) { d633 1 a633 1 ieee80211_compute_duration1(int len, int use_ack, uint32_t icflags, int rate, d648 1 a648 1 if ((icflags & IEEE80211_F_SHPREAMBLE) != 0) d714 1 a714 4 * of last fragment * * ieee80211_compute_duration assumes crypto-encapsulation, if any, * has already taken place. d717 2 a718 3 ieee80211_compute_duration(const struct ieee80211_frame_min *wh, const struct ieee80211_key *wk, int len, uint32_t icflags, int fraglen, int rate, struct ieee80211_duration *d0, d722 4 a725 14 int cryptolen, /* crypto overhead: header+trailer */ firstlen, /* first fragment's payload + overhead length */ hdrlen, /* header length w/o driver padding */ lastlen, /* last fragment's payload length w/ overhead */ lastlen0, /* last fragment's payload length w/o overhead */ npkt, /* number of fragments */ overlen, /* non-802.11 header overhead per fragment */ paylen; /* payload length w/o overhead */ hdrlen = ieee80211_anyhdrsize((const void *)wh); /* Account for padding required by the driver. */ if (icflags & IEEE80211_F_DATAPAD) paylen = len - roundup(hdrlen, sizeof(u_int32_t)); d727 1 a727 1 paylen = len - hdrlen; d729 1 a729 1 overlen = IEEE80211_CRC_LEN; d731 6 a736 6 if (wk != NULL) { cryptolen = wk->wk_cipher->ic_header + wk->wk_cipher->ic_trailer; paylen -= cryptolen; overlen += cryptolen; } d759 1 a759 1 "fraglen %d overlen %d len %d rate %d icflags %08x\n", d761 1 a761 1 overlen, len, rate, icflags); d768 1 a768 1 ack, icflags, rate, d0); d776 1 a776 1 return ieee80211_compute_duration1(lastlen + hdrlen, ack, icflags, rate, d921 1 a921 1 if (rsn->rsn_caps != 0 && rsn->rsn_caps != RSN_CAP_PREAUTH) d1004 2 a1005 1 ADDSHORT(frm, rsn->rsn_caps); a1099 85 * Send a probe request frame with the specified ssid * and any optional information element data. */ int ieee80211_send_probereq(struct ieee80211_node *ni, const u_int8_t sa[IEEE80211_ADDR_LEN], const u_int8_t da[IEEE80211_ADDR_LEN], const u_int8_t bssid[IEEE80211_ADDR_LEN], const u_int8_t *ssid, size_t ssidlen, const void *optie, size_t optielen) { struct ieee80211com *ic = ni->ni_ic; enum ieee80211_phymode mode; struct ieee80211_frame *wh; struct mbuf *m; u_int8_t *frm; /* * Hold a reference on the node so it doesn't go away until after * the xmit is complete all the way in the driver. On error we * will remove our reference. */ IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1); ieee80211_ref_node(ni); /* * prreq frame format * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates * [tlv] user-specified ie's */ m = ieee80211_getmgtframe(&frm, 2 + IEEE80211_NWID_LEN + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + (optie != NULL ? optielen : 0) ); if (m == NULL) { ic->ic_stats.is_tx_nobuf++; ieee80211_free_node(ni); return ENOMEM; } frm = ieee80211_add_ssid(frm, ssid, ssidlen); mode = ieee80211_chan2mode(ic, ic->ic_curchan); frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); if (optie != NULL) { memcpy(frm, optie, optielen); frm += optielen; } m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); if (m == NULL) return ENOMEM; IASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null")); m->m_pkthdr.rcvif = (void *)ni; wh = mtod(m, struct ieee80211_frame *); ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, sa, da, bssid); /* XXX power management? */ IEEE80211_NODE_STAT(ni, tx_probereq); IEEE80211_NODE_STAT(ni, tx_mgmt); IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "[%s] send probe req on channel %u\n", ether_sprintf(wh->i_addr1), ieee80211_chan2ieee(ic, ic->ic_curchan)); IF_ENQUEUE(&ic->ic_mgtq, m); (*ic->ic_ifp->if_start)(ic->ic_ifp); return 0; } /* d1111 1 d1131 32 d1207 1 a1207 1 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) d1224 1 a1224 1 ieee80211_chan2ieee(ic, ic->ic_curchan)); d1226 1 a1226 1 ieee80211_chan2ieee(ic, ic->ic_curchan)); d1231 1 a1231 1 *frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan); d1305 10 d1332 1 a1332 1 ieee80211_node_unauthorize(ni); /* port closed */ d1373 1 a1373 1 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) d1429 1 a1429 1 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) d1474 6 a1479 2 ret = ieee80211_mgmt_output(ic, ni, m, type, timer); if (ret != 0) { d1796 1 a1796 1 age = ((ni->ni_intval * ic->ic_bintval) << 2) / 1024; /* TU -> secs */ d1801 2 a1802 2 "[%s] save frame with age %d, %u now queued\n", ether_sprintf(ni->ni_macaddr), age, qlen); d1805 1 a1805 1 ic->ic_set_tim(ni, 1); @ 1.32.2.2 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.32.2.1 2006/06/21 15:10:46 yamt Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.32.2.1 2006/06/21 15:10:46 yamt Exp $"); d502 1 a502 2 ieee80211_crypto_getmcastkey(struct ieee80211com *ic, struct ieee80211_node *ni) d1744 1 a1744 1 struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) @ 1.32.2.3 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.32.2.2 2006/12/30 20:50:28 yamt Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.32.2.2 2006/12/30 20:50:28 yamt Exp $"); a79 3 static int ieee80211_fragment(struct ieee80211com *, struct mbuf *, u_int hdrsize, u_int ciphdrsize, u_int mtu); d525 1 a525 1 int hdrsize, datalen, addqos, txfrag; a650 4 /* check if xmit fragmentation is required */ txfrag = (m->m_pkthdr.len > ic->ic_fragthreshold && !IEEE80211_IS_MULTICAST(wh->i_addr1) && (m->m_flags & M_FF) == 0); /* NB: don't fragment ff's */ d662 2 a663 1 if (!ieee80211_crypto_enmic(ic, key, m, txfrag)) { a671 3 if (txfrag && !ieee80211_fragment(ic, m, hdrsize, key != NULL ? key->wk_cipher->ic_header : 0, ic->ic_fragthreshold)) goto bad; a864 92 * Fragment the frame according to the specified mtu. * The size of the 802.11 header (w/o padding) is provided * so we don't need to recalculate it. We create a new * mbuf for each fragment and chain it through m_nextpkt; * we might be able to optimize this by reusing the original * packet's mbufs but that is significantly more complicated. */ static int ieee80211_fragment(struct ieee80211com *ic, struct mbuf *m0, u_int hdrsize, u_int ciphdrsize, u_int mtu) { struct ieee80211_frame *wh, *whf; struct mbuf *m, *prev, *next; u_int totalhdrsize, fragno, fragsize, off, remainder, payload; IASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?")); IASSERT(m0->m_pkthdr.len > mtu, ("pktlen %u mtu %u", m0->m_pkthdr.len, mtu)); wh = mtod(m0, struct ieee80211_frame *); /* NB: mark the first frag; it will be propagated below */ wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; totalhdrsize = hdrsize + ciphdrsize; fragno = 1; off = mtu - ciphdrsize; remainder = m0->m_pkthdr.len - off; prev = m0; do { fragsize = totalhdrsize + remainder; if (fragsize > mtu) fragsize = mtu; IASSERT(fragsize < MCLBYTES, ("fragment size %u too big!", fragsize)); if (fragsize > MHLEN) m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); else m = m_gethdr(M_DONTWAIT, MT_DATA); if (m == NULL) goto bad; /* leave room to prepend any cipher header */ m_align(m, fragsize - ciphdrsize); /* * Form the header in the fragment. Note that since * we mark the first fragment with the MORE_FRAG bit * it automatically is propagated to each fragment; we * need only clear it on the last fragment (done below). */ whf = mtod(m, struct ieee80211_frame *); memcpy(whf, wh, hdrsize); *(u_int16_t *)&whf->i_seq[0] |= htole16( (fragno & IEEE80211_SEQ_FRAG_MASK) << IEEE80211_SEQ_FRAG_SHIFT); fragno++; payload = fragsize - totalhdrsize; /* NB: destination is known to be contiguous */ m_copydata(m0, off, payload, mtod(m, u_int8_t *) + hdrsize); m->m_len = hdrsize + payload; m->m_pkthdr.len = hdrsize + payload; m->m_flags |= M_FRAG; /* chain up the fragment */ prev->m_nextpkt = m; prev = m; /* deduct fragment just formed */ remainder -= payload; off += payload; } while (remainder != 0); whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; /* strip first mbuf now that everything has been copied */ m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize))); m0->m_flags |= M_FIRSTFRAG | M_FRAG; ic->ic_stats.is_tx_fragframes++; ic->ic_stats.is_tx_frags += fragno-1; return 1; bad: /* reclaim fragments but leave original frame for caller to free */ for (m = m0->m_nextpkt; m != NULL; m = next) { next = m->m_nextpkt; m->m_nextpkt = NULL; /* XXX paranoid */ m_freem(m); } m0->m_nextpkt = NULL; return 0; } /* @ 1.32.2.4 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.32.2.3 2007/02/26 09:11:40 yamt Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.32.2.3 2007/02/26 09:11:40 yamt Exp $"); d531 1 a531 1 memcpy(&eh, mtod(m, void *), sizeof(struct ether_header)); d2005 1 a2005 1 ieee80211_dump_pkt(mtod(m, void *), m->m_len, -1, -1); @ 1.31 log @Make sure there is a valid transmit key, before trying to use information about it. Fixes a crash when configuring wi0. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.30 2005/06/26 04:31:51 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.30 2005/06/26 04:31:51 dyoung Exp $"); d717 1 a717 1 ieee80211_compute_duration(struct ieee80211_frame *wh, int len, d731 3 a733 1 if ((flags & IEEE80211_F_PRIVACY) != 0) d735 1 a735 1 else @ 1.30 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_output.c,v 1.29 2005/06/22 06:16:02 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.29 2005/06/22 06:16:02 dyoung Exp $"); a410 1 #define KEY_UNDEFINED(k) ((k).wk_cipher == &ieee80211_cipher_none) d419 1 a419 1 if (KEY_UNDEFINED(ni->ni_ucastkey)) { d421 1 a421 1 KEY_UNDEFINED(ic->ic_nw_keys[ic->ic_def_txkey])) d438 1 a438 1 KEY_UNDEFINED(ic->ic_nw_keys[ic->ic_def_txkey])) d589 2 a590 1 !KEY_UNDEFINED(*key) : !KEY_UNDEFINED(ni->ni_ucastkey)))) { @ 1.29 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_output.c,v 1.26 2005/01/16 11:37:58 dyoung Exp $ */ d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.26 2005/01/16 11:37:58 dyoung Exp $"); d550 1 d555 1 d1307 1 d1312 1 d1683 1 d1754 1 @ 1.28 log @nuke trailing whitespace @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.27 2005/01/21 22:57:30 dyoung Exp $ */ d4 1 a4 1 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting d36 4 a39 3 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.10 2004/04/02 23:25:39 sam Exp $"); #else __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.27 2005/01/21 22:57:30 dyoung Exp $"); d49 2 a50 3 #include #include #include a51 2 #include #include a53 3 #ifdef __FreeBSD__ #include #endif a56 4 #ifdef __FreeBSD__ #include #endif d58 1 a58 1 #include a60 3 #ifdef __FreeBSD__ #include #else a61 1 #endif d63 1 d65 1 a66 1 #include d74 3 a76 3 #ifdef __FreeBSD__ #include #else a78 1 #endif d106 1 a106 1 ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni, d109 1 a109 1 struct ieee80211com *ic = (void *)ifp; a112 1 ni->ni_inact = 0; d137 21 a157 7 *(u_int16_t *)&wh->i_dur[0] = 0; *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseq++; IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); d162 2 a163 2 ("%s: encrypting frame for %s\n", __func__, ether_sprintf(wh->i_addr1))); d170 2 a171 1 if_printf(ifp, "sending %s to %s on channel %u\n", d173 2 a174 3 (type & IEEE80211_FC0_SUBTYPE_MASK) >> IEEE80211_FC0_SUBTYPE_SHIFT], ether_sprintf(ni->ni_macaddr), d178 1 d186 263 a448 7 * Encapsulate an outbound data frame. The mbuf chain is updated and * a reference to the destination node is returned. If an error is * encountered NULL is returned and the node reference will also be NULL. * * NB: The caller is responsible for free'ing a returned node reference. * The convention is ic_bss is not reference counted; the caller must * maintain that. d451 2 a452 1 ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni) a453 1 struct ieee80211com *ic = (void *)ifp; d456 1 a456 1 struct ieee80211_node *ni = NULL; d458 1 d460 1 a460 7 if (m->m_len < sizeof(struct ether_header)) { m = m_pullup(m, sizeof(struct ether_header)); if (m == NULL) { ic->ic_stats.is_tx_nombuf++; goto bad; } } d463 46 a508 6 ni = ieee80211_find_txnode(ic, eh.ether_dhost); if (ni == NULL) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, ("%s: no node for dst %s, discard frame\n", __func__, ether_sprintf(eh.ether_dhost))); ic->ic_stats.is_tx_nonode++; a510 1 ni->ni_inact = 0; d512 1 d521 3 a523 1 M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); d525 1 a525 1 ic->ic_stats.is_tx_nombuf++; d530 1 a530 4 *(u_int16_t *)&wh->i_dur[0] = 0; *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseq++; d543 4 d558 46 a603 3 if (ic->ic_flags & IEEE80211_F_PRIVACY) wh->i_fc[1] |= IEEE80211_FC1_WEP; *pni = ni; a607 3 if (ni != NULL) ieee80211_release_node(ic, ni); *pni = NULL; d779 1 a779 1 u_int8_t * d796 1 a796 1 u_int8_t * d812 1 a812 1 /* d824 212 a1035 2 static struct mbuf * ieee80211_getmbuf(int flags, int type, u_int pktlen) d1037 12 a1048 1 struct mbuf *m; d1050 42 a1091 9 IASSERT(pktlen <= MCLBYTES, ("802.11 packet too large: %u", pktlen)); MGETHDR(m, flags, type); if (m == NULL || pktlen <= MHLEN) return m; MCLGET(m, flags); if ((m->m_flags & M_EXT) != 0) return m; m_free(m); return NULL; d1093 1 a1104 1 struct ifnet *ifp = &ic->ic_if; d1109 1 a1109 1 int has_challenge, is_shared_key, ret, timer; d1118 5 d1124 1 d1133 1 d1135 2 a1136 2 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, 2 + ic->ic_des_esslen d1138 3 a1140 1 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); d1142 2 a1143 3 senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); d1148 4 d1154 3 a1156 1 timer = IEEE80211_TRANS_WAIT; d1169 1 d1171 2 d1174 5 a1178 3 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, 8 + 2 + 2 + 2 + 2 + ni->ni_esslen d1180 1 a1180 1 + (ic->ic_phytype == IEEE80211_T_FH ? 7 : 3) d1182 7 a1188 1 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); d1190 1 a1190 3 senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); d1205 2 d1212 1 a1212 1 frm = ieee80211_add_rates(frm, &ic->ic_bss->ni_rates); a1233 8 } else { /* IEEE80211_M_HOSTAP */ /* TODO: TIM */ *frm++ = IEEE80211_ELEMID_TIM; *frm++ = 4; /* length */ *frm++ = 0; /* DTIM count */ *frm++ = 1; /* DTIM period */ *frm++ = 0; /* bitmap control */ *frm++ = 0; /* Partial Virtual Bitmap (variable length) */ d1235 7 a1241 1 frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates); d1246 2 a1247 4 MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); d1252 19 a1270 2 is_shared_key = has_challenge || (ni->ni_challenge != NULL && arg == IEEE80211_AUTH_SHARED_PASS); a1271 9 if (has_challenge) { MH_ALIGN(m, 2 * 3 + 2 + IEEE80211_CHALLENGE_LEN); m->m_pkthdr.len = m->m_len = 2 * 3 + 2 + IEEE80211_CHALLENGE_LEN; } else { MH_ALIGN(m, 2 * 3); m->m_pkthdr.len = m->m_len = 2 * 3; } frm = mtod(m, u_int8_t *); d1276 1 a1276 1 ((u_int16_t *)frm)[2] = 0; /* status */ d1278 1 a1278 1 if (has_challenge) { d1284 2 d1288 2 a1289 1 ("%s: request encrypt frame\n", __func__)); d1292 17 a1308 1 } d1315 3 a1317 3 ("send station %s deauthenticate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg)); MGETHDR(m, M_DONTWAIT, MT_DATA); d1319 8 a1326 4 senderr(ENOMEM, is_tx_nombuf); MH_ALIGN(m, 2); m->m_pkthdr.len = m->m_len = 2; *mtod(m, u_int16_t *) = htole16(arg); /* reason */ d1339 2 d1342 2 a1343 2 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, sizeof(capinfo) d1346 1 a1346 1 + 2 + ni->ni_esslen d1348 4 a1351 1 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); d1353 1 a1353 3 senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); d1369 2 a1370 1 if (ic->ic_flags & IEEE80211_F_SHSLOT) d1386 6 d1406 1 d1408 2 a1409 2 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, sizeof(capinfo) d1413 3 a1415 1 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); d1417 1 a1417 3 senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); d1425 2 d1433 1 a1433 1 if (arg == IEEE80211_STATUS_SUCCESS) d1435 3 d1442 2 d1449 3 a1451 3 ("send station %s disassociate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg)); MGETHDR(m, M_DONTWAIT, MT_DATA); d1453 6 a1458 4 senderr(ENOMEM, is_tx_nombuf); MH_ALIGN(m, 2); m->m_pkthdr.len = m->m_len = 2; *mtod(m, u_int16_t *) = htole16(arg); /* reason */ d1463 2 a1464 1 ("%s: invalid mgmt frame type %u\n", __func__, type)); d1469 1 a1469 1 ret = ieee80211_mgmt_output(ifp, ni, m, type); d1475 1 a1475 1 ieee80211_release_node(ic, ni); d1481 278 d1760 1 a1760 1 ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni, d1763 1 a1763 1 /* Store the new packet on our queue, changing the TIM if necessary */ d1765 2 a1766 4 if (IF_IS_EMPTY(&ni->ni_savedq)) { ic->ic_set_tim(ic, ni->ni_associd, 1); } if (ni->ni_savedq.ifq_len >= IEEE80211_PS_MAX_QUEUE) { d1768 9 d1778 1 a1778 13 if (ic->ic_if.if_flags & IFF_DEBUG) printf("%s: station %s power save queue overflow" " of size %d drops %d\n", ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr), IEEE80211_PS_MAX_QUEUE, ni->ni_savedq.ifq_drops); } else { /* Similar to ieee80211_mgmt_output, store the node in * the rcvif field. */ IF_ENQUEUE(&ni->ni_savedq, m); m->m_pkthdr.rcvif = (void *)ni; d1780 18 a1798 1 @ 1.27 log @Bug fix: when encapsulating 802.11 data packets, always copy the BSS node's BSSID into the frame header. It is incorrect to copy in the neighbor's BSSID because it may be out of date following an IBSS merge. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.26 2005/01/16 11:37:58 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.26 2005/01/16 11:37:58 dyoung Exp $"); d48 2 a49 2 #include #include d85 1 a85 1 #include d188 1 a188 1 * d216 1 a216 1 ic->ic_stats.is_tx_nonode++; d477 1 a477 1 /* d820 1 a820 1 ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni, d834 2 a835 2 ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr), @ 1.27.2.1 log @sync with head. xen and whitespace. xen part is not finished. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.27 2005/01/21 22:57:30 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.27 2005/01/21 22:57:30 dyoung Exp $"); d48 2 a49 2 #include #include d85 1 a85 1 #include d188 1 a188 1 * d216 1 a216 1 ic->ic_stats.is_tx_nonode++; d477 1 a477 1 /* d820 1 a820 1 ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni, d834 2 a835 2 ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr), @ 1.26 log @Cosmetic: shorten a staircase. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.25 2005/01/04 00:36:18 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.25 2005/01/04 00:36:18 dyoung Exp $"); d252 1 a252 1 IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); @ 1.26.2.1 log @file ieee80211_output.c was added on branch kent-audio2 on 2005-04-29 11:29:32 +0000 @ text @d1 846 @ 1.26.2.2 log @sync with -current @ text @a0 846 /* $NetBSD: ieee80211_output.c,v 1.26.2.1 2005/04/29 11:29:32 kent 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_output.c,v 1.10 2004/04/02 23:25:39 sam Exp $"); #else __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.26.2.1 2005/04/29 11:29:32 kent Exp $"); #endif #include "opt_inet.h" #ifdef __NetBSD__ #include "bpfilter.h" #endif /* __NetBSD__ */ #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 #if NBPFILTER > 0 #include #endif #ifdef INET #include #ifdef __FreeBSD__ #include #else #include #endif #endif #ifdef IEEE80211_DEBUG /* * Decide if an outbound management frame should be * printed when debugging is enabled. This filters some * of the less interesting frames that come frequently * (e.g. beacons). */ static __inline int doprint(struct ieee80211com *ic, int subtype) { switch (subtype) { case IEEE80211_FC0_SUBTYPE_PROBE_RESP: return (ic->ic_opmode == IEEE80211_M_IBSS); } return 1; } #endif /* * Send a management frame to the specified node. The node pointer * must have a reference as the pointer will be passed to the driver * and potentially held for a long time. If the frame is successfully * dispatched to the driver, then it is responsible for freeing the * reference (and potentially free'ing up any associated storage). */ static int ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni, struct mbuf *m, int type) { struct ieee80211com *ic = (void *)ifp; struct ieee80211_frame *wh; IASSERT(ni != NULL, ("null node")); ni->ni_inact = 0; /* * Yech, hack alert! We want to pass the node down to the * driver's start routine. If we don't do so then the start * routine must immediately look it up again and that can * cause a lock order reversal if, for example, this frame * is being sent because the station is being timedout and * the frame being sent is a DEAUTH message. We could stick * this in an m_tag and tack that on to the mbuf. However * that's rather expensive to do for every frame so instead * we stuff it in the rcvif field since outbound frames do * not (presently) use this. */ M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); if (m == NULL) return ENOMEM; #ifdef __FreeBSD__ KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null")); #endif m->m_pkthdr.rcvif = (void *)ni; wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(u_int16_t *)&wh->i_dur[0] = 0; *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseq++; IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); if ((m->m_flags & M_LINK0) != 0 && ni->ni_challenge != NULL) { m->m_flags &= ~M_LINK0; IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH, ("%s: encrypting frame for %s\n", __func__, ether_sprintf(wh->i_addr1))); wh->i_fc[1] |= IEEE80211_FC1_WEP; } #ifdef IEEE80211_DEBUG /* avoid printing too many frames */ if ((ieee80211_msg_debug(ic) && doprint(ic, type)) || ieee80211_msg_dumppkts(ic)) { if_printf(ifp, "sending %s to %s on channel %u\n", ieee80211_mgt_subtype_name[ (type & IEEE80211_FC0_SUBTYPE_MASK) >> IEEE80211_FC0_SUBTYPE_SHIFT], ether_sprintf(ni->ni_macaddr), ieee80211_chan2ieee(ic, ni->ni_chan)); } #endif IF_ENQUEUE(&ic->ic_mgtq, m); ifp->if_timer = 1; (*ifp->if_start)(ifp); return 0; } /* * Encapsulate an outbound data frame. The mbuf chain is updated and * a reference to the destination node is returned. If an error is * encountered NULL is returned and the node reference will also be NULL. * * NB: The caller is responsible for free'ing a returned node reference. * The convention is ic_bss is not reference counted; the caller must * maintain that. */ struct mbuf * ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni) { struct ieee80211com *ic = (void *)ifp; struct ether_header eh; struct ieee80211_frame *wh; struct ieee80211_node *ni = NULL; struct llc *llc; if (m->m_len < sizeof(struct ether_header)) { m = m_pullup(m, sizeof(struct ether_header)); if (m == NULL) { ic->ic_stats.is_tx_nombuf++; goto bad; } } memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header)); ni = ieee80211_find_txnode(ic, eh.ether_dhost); if (ni == NULL) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, ("%s: no node for dst %s, discard frame\n", __func__, ether_sprintf(eh.ether_dhost))); ic->ic_stats.is_tx_nonode++; goto bad; } ni->ni_inact = 0; m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); llc = mtod(m, struct llc *); llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_control = LLC_UI; llc->llc_snap.org_code[0] = 0; llc->llc_snap.org_code[1] = 0; llc->llc_snap.org_code[2] = 0; llc->llc_snap.ether_type = eh.ether_type; M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); if (m == NULL) { ic->ic_stats.is_tx_nombuf++; goto bad; } wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; *(u_int16_t *)&wh->i_dur[0] = 0; *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseq++; switch (ic->ic_opmode) { case IEEE80211_M_STA: wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid); break; case IEEE80211_M_HOSTAP: wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); break; case IEEE80211_M_MONITOR: goto bad; } if (ic->ic_flags & IEEE80211_F_PRIVACY) wh->i_fc[1] |= IEEE80211_FC1_WEP; *pni = ni; return m; bad: if (m != NULL) m_freem(m); if (ni != NULL) ieee80211_release_node(ic, ni); *pni = NULL; return NULL; } /* * Arguments in: * * paylen: payload length (no FCS, no WEP header) * * hdrlen: header length * * rate: MSDU speed, units 500kb/s * * flags: IEEE80211_F_SHPREAMBLE (use short preamble), * IEEE80211_F_SHSLOT (use short slot length) * * Arguments out: * * d: 802.11 Duration field for RTS, * 802.11 Duration field for data frame, * PLCP Length for data frame, * residual octets at end of data slot */ static int ieee80211_compute_duration1(int len, int use_ack, uint32_t flags, int rate, struct ieee80211_duration *d) { int pre, ctsrate; int ack, bitlen, data_dur, remainder; /* RTS reserves medium for SIFS | CTS | SIFS | (DATA) | SIFS | ACK * DATA reserves medium for SIFS | ACK * * XXXMYC: no ACK on multicast/broadcast or control packets */ bitlen = len * 8; pre = IEEE80211_DUR_DS_SIFS; if ((flags & IEEE80211_F_SHPREAMBLE) != 0) pre += IEEE80211_DUR_DS_SHORT_PREAMBLE + IEEE80211_DUR_DS_FAST_PLCPHDR; else pre += IEEE80211_DUR_DS_LONG_PREAMBLE + IEEE80211_DUR_DS_SLOW_PLCPHDR; d->d_residue = 0; data_dur = (bitlen * 2) / rate; remainder = (bitlen * 2) % rate; if (remainder != 0) { d->d_residue = (rate - remainder) / 16; data_dur++; } switch (rate) { case 2: /* 1 Mb/s */ case 4: /* 2 Mb/s */ /* 1 - 2 Mb/s WLAN: send ACK/CTS at 1 Mb/s */ ctsrate = 2; break; case 11: /* 5.5 Mb/s */ case 22: /* 11 Mb/s */ case 44: /* 22 Mb/s */ /* 5.5 - 11 Mb/s WLAN: send ACK/CTS at 2 Mb/s */ ctsrate = 4; break; default: /* TBD */ return -1; } d->d_plcp_len = data_dur; ack = (use_ack) ? pre + (IEEE80211_DUR_DS_SLOW_ACK * 2) / ctsrate : 0; d->d_rts_dur = pre + (IEEE80211_DUR_DS_SLOW_CTS * 2) / ctsrate + pre + data_dur + ack; d->d_data_dur = ack; return 0; } /* * Arguments in: * * wh: 802.11 header * * paylen: payload length (no FCS, no WEP header) * * rate: MSDU speed, units 500kb/s * * fraglen: fragment length, set to maximum (or higher) for no * fragmentation * * flags: IEEE80211_F_PRIVACY (hardware adds WEP), * IEEE80211_F_SHPREAMBLE (use short preamble), * IEEE80211_F_SHSLOT (use short slot length) * * Arguments out: * * d0: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields * of first/only fragment * * dn: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields * of first/only fragment */ int ieee80211_compute_duration(struct ieee80211_frame *wh, int len, uint32_t flags, int fraglen, int rate, struct ieee80211_duration *d0, struct ieee80211_duration *dn, int *npktp, int debug) { int ack, rc; int firstlen, hdrlen, lastlen, lastlen0, npkt, overlen, paylen; if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) hdrlen = sizeof(struct ieee80211_frame_addr4); else hdrlen = sizeof(struct ieee80211_frame); paylen = len - hdrlen; if ((flags & IEEE80211_F_PRIVACY) != 0) overlen = IEEE80211_WEP_TOTLEN + IEEE80211_CRC_LEN; else overlen = IEEE80211_CRC_LEN; npkt = paylen / fraglen; lastlen0 = paylen % fraglen; if (npkt == 0) /* no fragments */ lastlen = paylen + overlen; else if (lastlen0 != 0) { /* a short "tail" fragment */ lastlen = lastlen0 + overlen; npkt++; } else /* full-length "tail" fragment */ lastlen = fraglen + overlen; if (npktp != NULL) *npktp = npkt; if (npkt > 1) firstlen = fraglen + overlen; else firstlen = paylen + overlen; if (debug) { printf("%s: npkt %d firstlen %d lastlen0 %d lastlen %d " "fraglen %d overlen %d len %d rate %d flags %08x\n", __func__, npkt, firstlen, lastlen0, lastlen, fraglen, overlen, len, rate, flags); } ack = !IEEE80211_IS_MULTICAST(wh->i_addr1) && (wh->i_fc[1] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL; rc = ieee80211_compute_duration1(firstlen + hdrlen, ack, flags, rate, d0); if (rc == -1) return rc; if (npkt <= 1) { *dn = *d0; return 0; } return ieee80211_compute_duration1(lastlen + hdrlen, ack, flags, rate, dn); } /* * Add a supported rates element id to a frame. */ u_int8_t * ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *rs) { int nrates; *frm++ = IEEE80211_ELEMID_RATES; nrates = rs->rs_nrates; if (nrates > IEEE80211_RATE_SIZE) nrates = IEEE80211_RATE_SIZE; *frm++ = nrates; memcpy(frm, rs->rs_rates, nrates); return frm + nrates; } /* * Add an extended supported rates element id to a frame. */ u_int8_t * ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs) { /* * Add an extended supported rates element if operating in 11g mode. */ if (rs->rs_nrates > IEEE80211_RATE_SIZE) { int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; *frm++ = IEEE80211_ELEMID_XRATES; *frm++ = nrates; memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); frm += nrates; } return frm; } /* * Add an ssid elemet to a frame. */ static u_int8_t * ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len) { *frm++ = IEEE80211_ELEMID_SSID; *frm++ = len; memcpy(frm, ssid, len); return frm + len; } static struct mbuf * ieee80211_getmbuf(int flags, int type, u_int pktlen) { struct mbuf *m; IASSERT(pktlen <= MCLBYTES, ("802.11 packet too large: %u", pktlen)); MGETHDR(m, flags, type); if (m == NULL || pktlen <= MHLEN) return m; MCLGET(m, flags); if ((m->m_flags & M_EXT) != 0) return m; m_free(m); return NULL; } /* * Send a management frame. The node is for the destination (or ic_bss * when in station mode). Nodes other than ic_bss have their reference * count bumped to reflect our use for an indeterminant time. */ int ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, int type, int arg) { #define senderr(_x, _v) do { ic->ic_stats._v++; ret = _x; goto bad; } while (0) struct ifnet *ifp = &ic->ic_if; struct mbuf *m; u_int8_t *frm; enum ieee80211_phymode mode; u_int16_t capinfo; int has_challenge, is_shared_key, ret, timer; IASSERT(ni != NULL, ("null node")); /* * Hold a reference on the node so it doesn't go away until after * the xmit is complete all the way in the driver. On error we * will remove our reference. */ ieee80211_ref_node(ni); timer = 0; switch (type) { case IEEE80211_FC0_SUBTYPE_PROBE_REQ: /* * prreq frame format * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates */ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, 2 + ic->ic_des_esslen + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen); mode = ieee80211_chan2mode(ic, ni->ni_chan); frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); timer = IEEE80211_TRANS_WAIT; break; case IEEE80211_FC0_SUBTYPE_PROBE_RESP: /* * probe response frame format * [8] time stamp * [2] beacon interval * [2] cabability information * [tlv] ssid * [tlv] supported rates * [tlv] parameter set (FH/DS) * [tlv] parameter set (IBSS) * [tlv] extended supported rates */ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, 8 + 2 + 2 + 2 + 2 + ni->ni_esslen + 2 + IEEE80211_RATE_SIZE + (ic->ic_phytype == IEEE80211_T_FH ? 7 : 3) + 6 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); memset(frm, 0, 8); /* timestamp should be filled later */ frm += 8; *(u_int16_t *)frm = htole16(ic->ic_bss->ni_intval); frm += 2; if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; *(u_int16_t *)frm = htole16(capinfo); frm += 2; frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid, ic->ic_bss->ni_esslen); frm = ieee80211_add_rates(frm, &ic->ic_bss->ni_rates); if (ic->ic_phytype == IEEE80211_T_FH) { *frm++ = IEEE80211_ELEMID_FHPARMS; *frm++ = 5; *frm++ = ni->ni_fhdwell & 0x00ff; *frm++ = (ni->ni_fhdwell >> 8) & 0x00ff; *frm++ = IEEE80211_FH_CHANSET( ieee80211_chan2ieee(ic, ni->ni_chan)); *frm++ = IEEE80211_FH_CHANPAT( ieee80211_chan2ieee(ic, ni->ni_chan)); *frm++ = ni->ni_fhindex; } else { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); } if (ic->ic_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ } else { /* IEEE80211_M_HOSTAP */ /* TODO: TIM */ *frm++ = IEEE80211_ELEMID_TIM; *frm++ = 4; /* length */ *frm++ = 0; /* DTIM count */ *frm++ = 1; /* DTIM period */ *frm++ = 0; /* bitmap control */ *frm++ = 0; /* Partial Virtual Bitmap (variable length) */ } frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates); m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); break; case IEEE80211_FC0_SUBTYPE_AUTH: MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || arg == IEEE80211_AUTH_SHARED_RESPONSE) && ni->ni_challenge != NULL); is_shared_key = has_challenge || (ni->ni_challenge != NULL && arg == IEEE80211_AUTH_SHARED_PASS); if (has_challenge) { MH_ALIGN(m, 2 * 3 + 2 + IEEE80211_CHALLENGE_LEN); m->m_pkthdr.len = m->m_len = 2 * 3 + 2 + IEEE80211_CHALLENGE_LEN; } else { MH_ALIGN(m, 2 * 3); m->m_pkthdr.len = m->m_len = 2 * 3; } frm = mtod(m, u_int8_t *); ((u_int16_t *)frm)[0] = (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED) : htole16(IEEE80211_AUTH_ALG_OPEN); ((u_int16_t *)frm)[1] = htole16(arg); /* sequence number */ ((u_int16_t *)frm)[2] = 0; /* status */ if (has_challenge) { ((u_int16_t *)frm)[3] = htole16((IEEE80211_CHALLENGE_LEN << 8) | IEEE80211_ELEMID_CHALLENGE); memcpy(&((u_int16_t *)frm)[4], ni->ni_challenge, IEEE80211_CHALLENGE_LEN); if (arg == IEEE80211_AUTH_SHARED_RESPONSE) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH, ("%s: request encrypt frame\n", __func__)); m->m_flags |= M_LINK0; /* WEP-encrypt, please */ } } if (ic->ic_opmode == IEEE80211_M_STA) timer = IEEE80211_TRANS_WAIT; break; case IEEE80211_FC0_SUBTYPE_DEAUTH: IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH, ("send station %s deauthenticate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg)); MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); MH_ALIGN(m, 2); m->m_pkthdr.len = m->m_len = 2; *mtod(m, u_int16_t *) = htole16(arg); /* reason */ break; case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: /* * asreq frame format * [2] capability information * [2] listen interval * [6*] current AP address (reassoc only) * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates */ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, sizeof(capinfo) + sizeof(u_int16_t) + IEEE80211_ADDR_LEN + 2 + ni->ni_esslen + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); capinfo = 0; if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo |= IEEE80211_CAPINFO_IBSS; else /* IEEE80211_M_STA */ capinfo |= IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; /* * NB: Some 11a AP's reject the request when * short premable is set. */ if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; *(u_int16_t *)frm = htole16(capinfo); frm += 2; *(u_int16_t *)frm = htole16(ic->ic_lintval); frm += 2; if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { IEEE80211_ADDR_COPY(frm, ic->ic_bss->ni_bssid); frm += IEEE80211_ADDR_LEN; } frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); frm = ieee80211_add_rates(frm, &ni->ni_rates); frm = ieee80211_add_xrates(frm, &ni->ni_rates); m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); timer = IEEE80211_TRANS_WAIT; break; case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: /* * asreq frame format * [2] capability information * [2] status * [2] association ID * [tlv] supported rates * [tlv] extended supported rates */ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, sizeof(capinfo) + sizeof(u_int16_t) + sizeof(u_int16_t) + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); capinfo = IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; *(u_int16_t *)frm = htole16(capinfo); frm += 2; *(u_int16_t *)frm = htole16(arg); /* status */ frm += 2; if (arg == IEEE80211_STATUS_SUCCESS) *(u_int16_t *)frm = htole16(ni->ni_associd); frm += 2; frm = ieee80211_add_rates(frm, &ni->ni_rates); frm = ieee80211_add_xrates(frm, &ni->ni_rates); m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); break; case IEEE80211_FC0_SUBTYPE_DISASSOC: IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, ("send station %s disassociate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg)); MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); MH_ALIGN(m, 2); m->m_pkthdr.len = m->m_len = 2; *mtod(m, u_int16_t *) = htole16(arg); /* reason */ break; default: IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, ("%s: invalid mgmt frame type %u\n", __func__, type)); senderr(EINVAL, is_tx_unknownmgt); /* NOTREACHED */ } ret = ieee80211_mgmt_output(ifp, ni, m, type); if (ret == 0) { if (timer) ic->ic_mgt_timer = timer; } else { bad: ieee80211_release_node(ic, ni); } return ret; #undef senderr } void ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni, struct mbuf *m) { /* Store the new packet on our queue, changing the TIM if necessary */ if (IF_IS_EMPTY(&ni->ni_savedq)) { ic->ic_set_tim(ic, ni->ni_associd, 1); } if (ni->ni_savedq.ifq_len >= IEEE80211_PS_MAX_QUEUE) { IF_DROP(&ni->ni_savedq); m_freem(m); if (ic->ic_if.if_flags & IFF_DEBUG) printf("%s: station %s power save queue overflow" " of size %d drops %d\n", ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr), IEEE80211_PS_MAX_QUEUE, ni->ni_savedq.ifq_drops); } else { /* Similar to ieee80211_mgmt_output, store the node in * the rcvif field. */ IF_ENQUEUE(&ni->ni_savedq, m); m->m_pkthdr.rcvif = (void *)ni; } } @ 1.25 log @In ieee80211_getmbuf, remove the #ifdef __FreeBSD__ code. Check for MCLGET success using the (m->m_flags & M_EXT) idiom. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.24 2004/12/27 10:47:57 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.24 2004/12/27 10:47:57 dyoung Exp $"); d496 7 a502 8 if (m != NULL && pktlen > MHLEN) { MCLGET(m, flags); if ((m->m_flags & M_EXT) == 0) { m_free(m); m = NULL; } } return m; @ 1.24 log @Cosmetic: remove some dead code. Join some lines. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.23 2004/12/27 09:25:05 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.23 2004/12/27 09:25:05 dyoung Exp $"); a494 6 #ifdef __FreeBSD__ if (pktlen <= MHLEN) MGETHDR(m, flags, type); else m = m_getcl(flags, type, M_PKTHDR); #else d496 1 a496 1 if (m != NULL && pktlen > MHLEN) d498 5 a502 1 #endif @ 1.23 log @802.11 Control/multicast/broadcast packets are not acknowledged. Set a shorter 802.11 Duration field, accordingly. XXX We expect CTS/ACK at 1 Mb/s for 1 & 2 Mb/s stations; and CTS/ACK at 2 Mb/s for 5.5 & 11 Mb/s stations. We need to check with the 802.11 standard. Rate negotiation may need to be overhauld for standards compliance, too. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.22 2004/12/27 05:35:33 mycroft Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.22 2004/12/27 05:35:33 mycroft Exp $"); a315 4 #if 0 /* RTS is always sent at 1 Mb/s. (XXX Really?) */ d->d_rts_plcp_len = sizeof(struct ieee80211_frame_rts) * 8; #endif d394 1 a394 1 if ((flags & IEEE80211_F_PRIVACY) != 0) { d396 1 a396 10 #if 0 /* 802.11 lets us extend a fragment's length by the length of * a WEP header, AFTER fragmentation. Might want to disable * this while fancy link adaptations are running. */ fraglen -= IEEE80211_WEP_TOTLEN; #endif #if 0 /* Ditto CRC? */ fraglen -= IEEE80211_CRC_LEN; #endif } else d402 1 a402 2 if (npkt == 0) { /* no fragments */ d404 1 a404 2 } else if (lastlen0 != 0) { /* a short fragment */ d407 1 a407 1 } else @ 1.22 log @Simplify the duration calculations somewhat. * Add an intermediate variable, ctsrate, which is currently derived directly from rate, but may be handled differently later (especially for 11g). * Assume ACKs are sent at the same rate as the original data packet, as ath does, shortening the ACK reservation time substantially. * Add a note that we need to deal with not adding the ACK time for some packets, though this is not implemented yet. Questions: * How do we affect the control rate used to send RTS/CTS packets? * Is the PLCP header length actually controlled by the preamble length selection, or should this be based on the transmit rate? Of course short preamble is not actually implemented/working yet. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.21 2004/12/27 01:57:58 mycroft Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.21 2004/12/27 01:57:58 mycroft Exp $"); d296 1 a296 1 ieee80211_compute_duration1(int len, uint32_t flags, int rate, d300 1 a300 1 int bitlen, data_dur, remainder; d347 2 d352 1 a352 1 pre + (IEEE80211_DUR_DS_SLOW_ACK * 2) / ctsrate; d354 1 a354 2 d->d_data_dur = pre + (IEEE80211_DUR_DS_SLOW_ACK * 2) / rate; d388 1 a388 1 int rc; d439 6 a444 1 rc = ieee80211_compute_duration1(firstlen + hdrlen, flags, rate, d0); d452 2 a453 1 return ieee80211_compute_duration1(lastlen + hdrlen, flags, rate, dn); @ 1.21 log @Update a comment. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.20 2004/12/27 01:51:49 mycroft Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.20 2004/12/27 01:51:49 mycroft Exp $"); d299 2 a300 1 int ack, bitlen, cts, data_dur, remainder; d304 2 d310 6 d322 5 d332 1 a332 2 cts = IEEE80211_DUR_DS_SLOW_CTS; ack = IEEE80211_DUR_DS_SLOW_ACK; a336 6 remainder = (bitlen * 2) % rate; if (remainder != 0) { data_dur++; d->d_residue = (rate - remainder) / 16; } d338 1 a338 2 cts = IEEE80211_DUR_DS_FAST_CTS; ack = IEEE80211_DUR_DS_FAST_ACK; d347 4 a350 11 d->d_rts_dur = data_dur + 3 * (IEEE80211_DUR_DS_SIFS + IEEE80211_DUR_DS_SHORT_PREAMBLE + IEEE80211_DUR_DS_FAST_PLCPHDR) + cts + ack; /* Note that this is the amount of time reserved *after* * the packet is transmitted: just long enough for a SIFS * and an ACK. */ d->d_data_dur = IEEE80211_DUR_DS_SIFS + IEEE80211_DUR_DS_SHORT_PREAMBLE + IEEE80211_DUR_DS_FAST_PLCPHDR + ack; d352 2 a353 2 if ((flags & IEEE80211_F_SHPREAMBLE) != 0) return 0; a354 4 d->d_rts_dur += 3 * IEEE80211_DUR_DS_PREAMBLE_DIFFERENCE + 3 * IEEE80211_DUR_DS_PLCPHDR_DIFFERENCE; d->d_data_dur += IEEE80211_DUR_DS_PREAMBLE_DIFFERENCE + IEEE80211_DUR_DS_PLCPHDR_DIFFERENCE; @ 1.20 log @Replace d_plcp_svc with d_residue. The latter is the number of whole empty/unused octets to fill out the data time slot. The value is constrained by math to 0 for <= 5.5Mb, 0-1 for 11Mb, and 0-2 for 22Mb. It is used to signal to the MAC that there is residue. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.19 2004/12/23 06:08:52 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.19 2004/12/23 06:08:52 dyoung Exp $"); d290 2 a291 1 * d: 802.11 Duration field for data frame, d293 1 a293 2 * PLCP Service field for data frame, * 802.11 Duration field for RTS @ 1.19 log @Fix a bug in ieee80211_compute_duration: the 802.11 Duration field in an 802.11 unicast data packet is equal to the duration of the SIFS and Acknowledgement. That is, the amount of time reserved *after* the packet has finished transmitting. Change the arguments to ieee80211_compute_duration: pass the entire packet length, not just the payload length. Add a 'debug' argument to ieee80211_compute_duration and its helper subroutine, ieee80211_compute_duration1. If debug != 0, ieee80211_compute_duration printfs its arguments and several local variables. In rtw(4), load the 802.11 Duration field with the result from ieee80211_compute_duration. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.18 2004/12/19 08:08:06 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.18 2004/12/19 08:08:06 dyoung Exp $"); d311 2 a312 1 d->d_plcp_svc = 0; a316 2 data_dur = (bitlen * 2) / rate; a320 3 case 44: /* 22 Mb/s */ d->d_plcp_svc = IEEE80211_PLCP_SERVICE_PBCC; /*FALLTHROUGH*/ d323 1 d325 4 a328 8 if (remainder != 0) data_dur = (bitlen * 2) / rate + 1; else data_dur = (bitlen * 2) / rate; if (rate == 22 && remainder <= 6) d->d_plcp_svc |= IEEE80211_PLCP_SERVICE_LENEXT; @ 1.18 log @Define for more bits in the Service field of the 802.11 PLCP Header. For use by the subroutine ieee80211_compute_duration, add struct ieee80211_duration, and #define a number of microsecond constants used for the transmit timing of 802.11 packets. Add the subroutine ieee80211_compute_duration, which computes for any packet the appropriate 802.11 Duration field, the PLCP Length field, as well as the Duration and Length fields for an RTS frame. atw(4), rtw(4), future drivers, and possibly ath(4) will share ieee80211_compute_duration. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.17 2004/08/10 00:57:22 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.17 2004/08/10 00:57:22 dyoung Exp $"); d346 2 a350 3 d->d_data_dur = data_dur + IEEE80211_DUR_DS_SIFS + 2 * (IEEE80211_DUR_DS_SHORT_PREAMBLE + IEEE80211_DUR_DS_FAST_PLCPHDR) + ack; d352 7 a358 1 d->d_plcp_len = data_dur; d363 4 a366 8 d->d_rts_dur += 3 * (IEEE80211_DUR_DS_LONG_PREAMBLE - IEEE80211_DUR_DS_SHORT_PREAMBLE) + 3 * (IEEE80211_DUR_DS_SLOW_PLCPHDR - IEEE80211_DUR_DS_FAST_PLCPHDR); d->d_data_dur += 2 * (IEEE80211_DUR_DS_LONG_PREAMBLE - IEEE80211_DUR_DS_SHORT_PREAMBLE) + 2 * (IEEE80211_DUR_DS_SLOW_PLCPHDR - IEEE80211_DUR_DS_FAST_PLCPHDR); d395 1 a395 1 ieee80211_compute_duration(struct ieee80211_frame *wh, int paylen, d397 1 a397 1 struct ieee80211_duration *dn, int *npktp) d400 1 a400 1 int firstlen, hdrlen, lastlen, lastlen0, npkt, overlen; d407 2 d444 6 d453 2 a454 1 if (npkt > 1) { @ 1.17 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_output.c,v 1.16 2004/07/23 08:31:39 mycroft Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.16 2004/07/23 08:31:39 mycroft Exp $"); d277 175 @ 1.16 log @IEEE80211_F_WEPON -> IEEE80211_F_PRIVACY @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.15 2004/07/23 08:25:25 mycroft Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.15 2004/07/23 08:25:25 mycroft Exp $"); d270 2 a271 2 if (ni && ni != ic->ic_bss) ieee80211_free_node(ic, ni); d367 1 a367 2 if (ni != ic->ic_bss) ieee80211_ref_node(ni); d651 1 a651 2 if (ni != ic->ic_bss) /* remove ref we added */ ieee80211_free_node(ic, ni); @ 1.16.2.1 log @file ieee80211_output.c was added on branch ktrace-lwp on 2004-08-03 10:54:21 +0000 @ text @d1 686 @ 1.16.2.2 log @Sync with HEAD @ text @a0 686 /* $NetBSD: ieee80211_output.c,v 1.16.2.1 2004/08/03 10:54:21 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_output.c,v 1.10 2004/04/02 23:25:39 sam Exp $"); #else __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.16.2.1 2004/08/03 10:54:21 skrll Exp $"); #endif #include "opt_inet.h" #ifdef __NetBSD__ #include "bpfilter.h" #endif /* __NetBSD__ */ #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 #if NBPFILTER > 0 #include #endif #ifdef INET #include #ifdef __FreeBSD__ #include #else #include #endif #endif #ifdef IEEE80211_DEBUG /* * Decide if an outbound management frame should be * printed when debugging is enabled. This filters some * of the less interesting frames that come frequently * (e.g. beacons). */ static __inline int doprint(struct ieee80211com *ic, int subtype) { switch (subtype) { case IEEE80211_FC0_SUBTYPE_PROBE_RESP: return (ic->ic_opmode == IEEE80211_M_IBSS); } return 1; } #endif /* * Send a management frame to the specified node. The node pointer * must have a reference as the pointer will be passed to the driver * and potentially held for a long time. If the frame is successfully * dispatched to the driver, then it is responsible for freeing the * reference (and potentially free'ing up any associated storage). */ static int ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni, struct mbuf *m, int type) { struct ieee80211com *ic = (void *)ifp; struct ieee80211_frame *wh; IASSERT(ni != NULL, ("null node")); ni->ni_inact = 0; /* * Yech, hack alert! We want to pass the node down to the * driver's start routine. If we don't do so then the start * routine must immediately look it up again and that can * cause a lock order reversal if, for example, this frame * is being sent because the station is being timedout and * the frame being sent is a DEAUTH message. We could stick * this in an m_tag and tack that on to the mbuf. However * that's rather expensive to do for every frame so instead * we stuff it in the rcvif field since outbound frames do * not (presently) use this. */ M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); if (m == NULL) return ENOMEM; #ifdef __FreeBSD__ KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null")); #endif m->m_pkthdr.rcvif = (void *)ni; wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(u_int16_t *)&wh->i_dur[0] = 0; *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseq++; IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); if ((m->m_flags & M_LINK0) != 0 && ni->ni_challenge != NULL) { m->m_flags &= ~M_LINK0; IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH, ("%s: encrypting frame for %s\n", __func__, ether_sprintf(wh->i_addr1))); wh->i_fc[1] |= IEEE80211_FC1_WEP; } #ifdef IEEE80211_DEBUG /* avoid printing too many frames */ if ((ieee80211_msg_debug(ic) && doprint(ic, type)) || ieee80211_msg_dumppkts(ic)) { if_printf(ifp, "sending %s to %s on channel %u\n", ieee80211_mgt_subtype_name[ (type & IEEE80211_FC0_SUBTYPE_MASK) >> IEEE80211_FC0_SUBTYPE_SHIFT], ether_sprintf(ni->ni_macaddr), ieee80211_chan2ieee(ic, ni->ni_chan)); } #endif IF_ENQUEUE(&ic->ic_mgtq, m); ifp->if_timer = 1; (*ifp->if_start)(ifp); return 0; } /* * Encapsulate an outbound data frame. The mbuf chain is updated and * a reference to the destination node is returned. If an error is * encountered NULL is returned and the node reference will also be NULL. * * NB: The caller is responsible for free'ing a returned node reference. * The convention is ic_bss is not reference counted; the caller must * maintain that. */ struct mbuf * ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni) { struct ieee80211com *ic = (void *)ifp; struct ether_header eh; struct ieee80211_frame *wh; struct ieee80211_node *ni = NULL; struct llc *llc; if (m->m_len < sizeof(struct ether_header)) { m = m_pullup(m, sizeof(struct ether_header)); if (m == NULL) { ic->ic_stats.is_tx_nombuf++; goto bad; } } memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header)); ni = ieee80211_find_txnode(ic, eh.ether_dhost); if (ni == NULL) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, ("%s: no node for dst %s, discard frame\n", __func__, ether_sprintf(eh.ether_dhost))); ic->ic_stats.is_tx_nonode++; goto bad; } ni->ni_inact = 0; m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); llc = mtod(m, struct llc *); llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_control = LLC_UI; llc->llc_snap.org_code[0] = 0; llc->llc_snap.org_code[1] = 0; llc->llc_snap.org_code[2] = 0; llc->llc_snap.ether_type = eh.ether_type; M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); if (m == NULL) { ic->ic_stats.is_tx_nombuf++; goto bad; } wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; *(u_int16_t *)&wh->i_dur[0] = 0; *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseq++; switch (ic->ic_opmode) { case IEEE80211_M_STA: wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); break; case IEEE80211_M_HOSTAP: wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); break; case IEEE80211_M_MONITOR: goto bad; } if (ic->ic_flags & IEEE80211_F_PRIVACY) wh->i_fc[1] |= IEEE80211_FC1_WEP; *pni = ni; return m; bad: if (m != NULL) m_freem(m); if (ni && ni != ic->ic_bss) ieee80211_free_node(ic, ni); *pni = NULL; return NULL; } /* * Add a supported rates element id to a frame. */ u_int8_t * ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *rs) { int nrates; *frm++ = IEEE80211_ELEMID_RATES; nrates = rs->rs_nrates; if (nrates > IEEE80211_RATE_SIZE) nrates = IEEE80211_RATE_SIZE; *frm++ = nrates; memcpy(frm, rs->rs_rates, nrates); return frm + nrates; } /* * Add an extended supported rates element id to a frame. */ u_int8_t * ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs) { /* * Add an extended supported rates element if operating in 11g mode. */ if (rs->rs_nrates > IEEE80211_RATE_SIZE) { int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; *frm++ = IEEE80211_ELEMID_XRATES; *frm++ = nrates; memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); frm += nrates; } return frm; } /* * Add an ssid elemet to a frame. */ static u_int8_t * ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len) { *frm++ = IEEE80211_ELEMID_SSID; *frm++ = len; memcpy(frm, ssid, len); return frm + len; } static struct mbuf * ieee80211_getmbuf(int flags, int type, u_int pktlen) { struct mbuf *m; IASSERT(pktlen <= MCLBYTES, ("802.11 packet too large: %u", pktlen)); #ifdef __FreeBSD__ if (pktlen <= MHLEN) MGETHDR(m, flags, type); else m = m_getcl(flags, type, M_PKTHDR); #else MGETHDR(m, flags, type); if (m != NULL && pktlen > MHLEN) MCLGET(m, flags); #endif return m; } /* * Send a management frame. The node is for the destination (or ic_bss * when in station mode). Nodes other than ic_bss have their reference * count bumped to reflect our use for an indeterminant time. */ int ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, int type, int arg) { #define senderr(_x, _v) do { ic->ic_stats._v++; ret = _x; goto bad; } while (0) struct ifnet *ifp = &ic->ic_if; struct mbuf *m; u_int8_t *frm; enum ieee80211_phymode mode; u_int16_t capinfo; int has_challenge, is_shared_key, ret, timer; IASSERT(ni != NULL, ("null node")); /* * Hold a reference on the node so it doesn't go away until after * the xmit is complete all the way in the driver. On error we * will remove our reference. */ if (ni != ic->ic_bss) ieee80211_ref_node(ni); timer = 0; switch (type) { case IEEE80211_FC0_SUBTYPE_PROBE_REQ: /* * prreq frame format * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates */ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, 2 + ic->ic_des_esslen + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen); mode = ieee80211_chan2mode(ic, ni->ni_chan); frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); timer = IEEE80211_TRANS_WAIT; break; case IEEE80211_FC0_SUBTYPE_PROBE_RESP: /* * probe response frame format * [8] time stamp * [2] beacon interval * [2] cabability information * [tlv] ssid * [tlv] supported rates * [tlv] parameter set (FH/DS) * [tlv] parameter set (IBSS) * [tlv] extended supported rates */ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, 8 + 2 + 2 + 2 + 2 + ni->ni_esslen + 2 + IEEE80211_RATE_SIZE + (ic->ic_phytype == IEEE80211_T_FH ? 7 : 3) + 6 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); memset(frm, 0, 8); /* timestamp should be filled later */ frm += 8; *(u_int16_t *)frm = htole16(ic->ic_bss->ni_intval); frm += 2; if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; *(u_int16_t *)frm = htole16(capinfo); frm += 2; frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid, ic->ic_bss->ni_esslen); frm = ieee80211_add_rates(frm, &ic->ic_bss->ni_rates); if (ic->ic_phytype == IEEE80211_T_FH) { *frm++ = IEEE80211_ELEMID_FHPARMS; *frm++ = 5; *frm++ = ni->ni_fhdwell & 0x00ff; *frm++ = (ni->ni_fhdwell >> 8) & 0x00ff; *frm++ = IEEE80211_FH_CHANSET( ieee80211_chan2ieee(ic, ni->ni_chan)); *frm++ = IEEE80211_FH_CHANPAT( ieee80211_chan2ieee(ic, ni->ni_chan)); *frm++ = ni->ni_fhindex; } else { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); } if (ic->ic_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ } else { /* IEEE80211_M_HOSTAP */ /* TODO: TIM */ *frm++ = IEEE80211_ELEMID_TIM; *frm++ = 4; /* length */ *frm++ = 0; /* DTIM count */ *frm++ = 1; /* DTIM period */ *frm++ = 0; /* bitmap control */ *frm++ = 0; /* Partial Virtual Bitmap (variable length) */ } frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates); m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); break; case IEEE80211_FC0_SUBTYPE_AUTH: MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || arg == IEEE80211_AUTH_SHARED_RESPONSE) && ni->ni_challenge != NULL); is_shared_key = has_challenge || (ni->ni_challenge != NULL && arg == IEEE80211_AUTH_SHARED_PASS); if (has_challenge) { MH_ALIGN(m, 2 * 3 + 2 + IEEE80211_CHALLENGE_LEN); m->m_pkthdr.len = m->m_len = 2 * 3 + 2 + IEEE80211_CHALLENGE_LEN; } else { MH_ALIGN(m, 2 * 3); m->m_pkthdr.len = m->m_len = 2 * 3; } frm = mtod(m, u_int8_t *); ((u_int16_t *)frm)[0] = (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED) : htole16(IEEE80211_AUTH_ALG_OPEN); ((u_int16_t *)frm)[1] = htole16(arg); /* sequence number */ ((u_int16_t *)frm)[2] = 0; /* status */ if (has_challenge) { ((u_int16_t *)frm)[3] = htole16((IEEE80211_CHALLENGE_LEN << 8) | IEEE80211_ELEMID_CHALLENGE); memcpy(&((u_int16_t *)frm)[4], ni->ni_challenge, IEEE80211_CHALLENGE_LEN); if (arg == IEEE80211_AUTH_SHARED_RESPONSE) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH, ("%s: request encrypt frame\n", __func__)); m->m_flags |= M_LINK0; /* WEP-encrypt, please */ } } if (ic->ic_opmode == IEEE80211_M_STA) timer = IEEE80211_TRANS_WAIT; break; case IEEE80211_FC0_SUBTYPE_DEAUTH: IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH, ("send station %s deauthenticate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg)); MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); MH_ALIGN(m, 2); m->m_pkthdr.len = m->m_len = 2; *mtod(m, u_int16_t *) = htole16(arg); /* reason */ break; case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: /* * asreq frame format * [2] capability information * [2] listen interval * [6*] current AP address (reassoc only) * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates */ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, sizeof(capinfo) + sizeof(u_int16_t) + IEEE80211_ADDR_LEN + 2 + ni->ni_esslen + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); capinfo = 0; if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo |= IEEE80211_CAPINFO_IBSS; else /* IEEE80211_M_STA */ capinfo |= IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; /* * NB: Some 11a AP's reject the request when * short premable is set. */ if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; *(u_int16_t *)frm = htole16(capinfo); frm += 2; *(u_int16_t *)frm = htole16(ic->ic_lintval); frm += 2; if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { IEEE80211_ADDR_COPY(frm, ic->ic_bss->ni_bssid); frm += IEEE80211_ADDR_LEN; } frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); frm = ieee80211_add_rates(frm, &ni->ni_rates); frm = ieee80211_add_xrates(frm, &ni->ni_rates); m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); timer = IEEE80211_TRANS_WAIT; break; case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: /* * asreq frame format * [2] capability information * [2] status * [2] association ID * [tlv] supported rates * [tlv] extended supported rates */ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, sizeof(capinfo) + sizeof(u_int16_t) + sizeof(u_int16_t) + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); capinfo = IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; *(u_int16_t *)frm = htole16(capinfo); frm += 2; *(u_int16_t *)frm = htole16(arg); /* status */ frm += 2; if (arg == IEEE80211_STATUS_SUCCESS) *(u_int16_t *)frm = htole16(ni->ni_associd); frm += 2; frm = ieee80211_add_rates(frm, &ni->ni_rates); frm = ieee80211_add_xrates(frm, &ni->ni_rates); m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); break; case IEEE80211_FC0_SUBTYPE_DISASSOC: IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, ("send station %s disassociate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg)); MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); MH_ALIGN(m, 2); m->m_pkthdr.len = m->m_len = 2; *mtod(m, u_int16_t *) = htole16(arg); /* reason */ break; default: IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, ("%s: invalid mgmt frame type %u\n", __func__, type)); senderr(EINVAL, is_tx_unknownmgt); /* NOTREACHED */ } ret = ieee80211_mgmt_output(ifp, ni, m, type); if (ret == 0) { if (timer) ic->ic_mgt_timer = timer; } else { bad: if (ni != ic->ic_bss) /* remove ref we added */ ieee80211_free_node(ic, ni); } return ret; #undef senderr } void ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni, struct mbuf *m) { /* Store the new packet on our queue, changing the TIM if necessary */ if (IF_IS_EMPTY(&ni->ni_savedq)) { ic->ic_set_tim(ic, ni->ni_associd, 1); } if (ni->ni_savedq.ifq_len >= IEEE80211_PS_MAX_QUEUE) { IF_DROP(&ni->ni_savedq); m_freem(m); if (ic->ic_if.if_flags & IFF_DEBUG) printf("%s: station %s power save queue overflow" " of size %d drops %d\n", ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr), IEEE80211_PS_MAX_QUEUE, ni->ni_savedq.ifq_drops); } else { /* Similar to ieee80211_mgmt_output, store the node in * the rcvif field. */ IF_ENQUEUE(&ni->ni_savedq, m); m->m_pkthdr.rcvif = (void *)ni; } } @ 1.16.2.3 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.16.2.2 2004/08/12 11:42:20 skrll Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.16.2.2 2004/08/12 11:42:20 skrll Exp $"); d270 2 a271 2 if (ni != NULL) ieee80211_release_node(ic, ni); d367 2 a368 1 ieee80211_ref_node(ni); d652 2 a653 1 ieee80211_release_node(ic, ni); @ 1.16.2.4 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.16.2.3 2004/09/18 14:54:39 skrll Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.16.2.3 2004/09/18 14:54:39 skrll Exp $"); @ 1.16.2.5 log @Fix the sync with head I botched. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.16.2.4 2004/09/21 13:36:55 skrll Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.16.2.4 2004/09/21 13:36:55 skrll Exp $"); @ 1.16.2.6 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.16.2.5 2005/01/17 19:32:39 skrll Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.16.2.5 2005/01/17 19:32:39 skrll Exp $"); a276 165 * Arguments in: * * paylen: payload length (no FCS, no WEP header) * * hdrlen: header length * * rate: MSDU speed, units 500kb/s * * flags: IEEE80211_F_SHPREAMBLE (use short preamble), * IEEE80211_F_SHSLOT (use short slot length) * * Arguments out: * * d: 802.11 Duration field for RTS, * 802.11 Duration field for data frame, * PLCP Length for data frame, * residual octets at end of data slot */ static int ieee80211_compute_duration1(int len, int use_ack, uint32_t flags, int rate, struct ieee80211_duration *d) { int pre, ctsrate; int ack, bitlen, data_dur, remainder; /* RTS reserves medium for SIFS | CTS | SIFS | (DATA) | SIFS | ACK * DATA reserves medium for SIFS | ACK * * XXXMYC: no ACK on multicast/broadcast or control packets */ bitlen = len * 8; pre = IEEE80211_DUR_DS_SIFS; if ((flags & IEEE80211_F_SHPREAMBLE) != 0) pre += IEEE80211_DUR_DS_SHORT_PREAMBLE + IEEE80211_DUR_DS_FAST_PLCPHDR; else pre += IEEE80211_DUR_DS_LONG_PREAMBLE + IEEE80211_DUR_DS_SLOW_PLCPHDR; d->d_residue = 0; data_dur = (bitlen * 2) / rate; remainder = (bitlen * 2) % rate; if (remainder != 0) { d->d_residue = (rate - remainder) / 16; data_dur++; } switch (rate) { case 2: /* 1 Mb/s */ case 4: /* 2 Mb/s */ /* 1 - 2 Mb/s WLAN: send ACK/CTS at 1 Mb/s */ ctsrate = 2; break; case 11: /* 5.5 Mb/s */ case 22: /* 11 Mb/s */ case 44: /* 22 Mb/s */ /* 5.5 - 11 Mb/s WLAN: send ACK/CTS at 2 Mb/s */ ctsrate = 4; break; default: /* TBD */ return -1; } d->d_plcp_len = data_dur; ack = (use_ack) ? pre + (IEEE80211_DUR_DS_SLOW_ACK * 2) / ctsrate : 0; d->d_rts_dur = pre + (IEEE80211_DUR_DS_SLOW_CTS * 2) / ctsrate + pre + data_dur + ack; d->d_data_dur = ack; return 0; } /* * Arguments in: * * wh: 802.11 header * * paylen: payload length (no FCS, no WEP header) * * rate: MSDU speed, units 500kb/s * * fraglen: fragment length, set to maximum (or higher) for no * fragmentation * * flags: IEEE80211_F_PRIVACY (hardware adds WEP), * IEEE80211_F_SHPREAMBLE (use short preamble), * IEEE80211_F_SHSLOT (use short slot length) * * Arguments out: * * d0: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields * of first/only fragment * * dn: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields * of first/only fragment */ int ieee80211_compute_duration(struct ieee80211_frame *wh, int len, uint32_t flags, int fraglen, int rate, struct ieee80211_duration *d0, struct ieee80211_duration *dn, int *npktp, int debug) { int ack, rc; int firstlen, hdrlen, lastlen, lastlen0, npkt, overlen, paylen; if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) hdrlen = sizeof(struct ieee80211_frame_addr4); else hdrlen = sizeof(struct ieee80211_frame); paylen = len - hdrlen; if ((flags & IEEE80211_F_PRIVACY) != 0) overlen = IEEE80211_WEP_TOTLEN + IEEE80211_CRC_LEN; else overlen = IEEE80211_CRC_LEN; npkt = paylen / fraglen; lastlen0 = paylen % fraglen; if (npkt == 0) /* no fragments */ lastlen = paylen + overlen; else if (lastlen0 != 0) { /* a short "tail" fragment */ lastlen = lastlen0 + overlen; npkt++; } else /* full-length "tail" fragment */ lastlen = fraglen + overlen; if (npktp != NULL) *npktp = npkt; if (npkt > 1) firstlen = fraglen + overlen; else firstlen = paylen + overlen; if (debug) { printf("%s: npkt %d firstlen %d lastlen0 %d lastlen %d " "fraglen %d overlen %d len %d rate %d flags %08x\n", __func__, npkt, firstlen, lastlen0, lastlen, fraglen, overlen, len, rate, flags); } ack = !IEEE80211_IS_MULTICAST(wh->i_addr1) && (wh->i_fc[1] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL; rc = ieee80211_compute_duration1(firstlen + hdrlen, ack, flags, rate, d0); if (rc == -1) return rc; if (npkt <= 1) { *dn = *d0; return 0; } return ieee80211_compute_duration1(lastlen + hdrlen, ack, flags, rate, dn); } /* d330 6 d337 4 a340 7 if (m == NULL || pktlen <= MHLEN) return m; MCLGET(m, flags); if ((m->m_flags & M_EXT) != 0) return m; m_free(m); return NULL; @ 1.16.2.7 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.16.2.6 2005/01/24 08:35:53 skrll Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.16.2.6 2005/01/24 08:35:53 skrll Exp $"); d252 1 a252 1 IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid); @ 1.16.2.8 log @Sync with HEAD. Hi Perry! @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.16.2.7 2005/03/04 16:53:17 skrll Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.16.2.7 2005/03/04 16:53:17 skrll Exp $"); d48 2 a49 2 #include #include d85 1 a85 1 #include d188 1 a188 1 * d216 1 a216 1 ic->ic_stats.is_tx_nonode++; d477 1 a477 1 /* d820 1 a820 1 ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni, d834 2 a835 2 ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr), @ 1.16.2.9 log @Sync with HEAD. Here we go again... @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.16.2.8 2005/11/10 14:10:51 skrll Exp $ */ d4 1 a4 1 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting d36 3 a38 4 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.26 2005/07/06 01:55:17 sam Exp $"); #endif #ifdef __NetBSD__ __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.16.2.8 2005/11/10 14:10:51 skrll Exp $"); d48 3 a50 2 #include #include d52 2 d56 3 d62 4 d67 1 a67 1 #include d70 3 d74 1 a75 1 #include a76 1 #include d78 1 d86 3 a88 3 #include #include #include d91 1 d119 1 a119 1 ieee80211_mgmt_output(struct ieee80211com *ic, struct ieee80211_node *ni, d122 1 a122 1 struct ifnet *ifp = ic->ic_ifp; d126 1 d151 7 a157 21 *(u_int16_t *)wh->i_dur = 0; *(u_int16_t *)wh->i_seq = htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; /* * Hack. When sending PROBE_REQ frames while scanning we * explicitly force a broadcast rather than (as before) clobber * ni_macaddr and ni_bssid. This is stopgap, we need a way * to communicate this directly rather than do something * implicit based on surrounding state. */ if (type == IEEE80211_FC0_SUBTYPE_PROBE_REQ && (ic->ic_flags & IEEE80211_F_SCAN)) { IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); } else { IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); } d162 2 a163 2 "[%s] encrypting frame (%s)\n", ether_sprintf(wh->i_addr1), __func__); d170 1 a170 2 printf("[%s] send %s on channel %u\n", ether_sprintf(wh->i_addr1), d172 3 a174 2 (type & IEEE80211_FC0_SUBTYPE_MASK) >> IEEE80211_FC0_SUBTYPE_SHIFT], a177 1 IEEE80211_NODE_STAT(ni, tx_mgmt); d185 7 a191 281 * Send a null data frame to the specified node. */ int ieee80211_send_nulldata(struct ieee80211com *ic, struct ieee80211_node *ni) { struct ifnet *ifp = ic->ic_ifp; struct mbuf *m; struct ieee80211_frame *wh; MGETHDR(m, M_NOWAIT, MT_HEADER); if (m == NULL) { /* XXX debug msg */ ic->ic_stats.is_tx_nobuf++; return ENOMEM; } m->m_pkthdr.rcvif = (void *) ieee80211_ref_node(ni); wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA; *(u_int16_t *)wh->i_dur = 0; *(u_int16_t *)wh->i_seq = htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; /* XXX WDS */ wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_myaddr); m->m_len = m->m_pkthdr.len = sizeof(struct ieee80211_frame); IEEE80211_NODE_STAT(ni, tx_data); IF_ENQUEUE(&ic->ic_mgtq, m); /* cheat */ (*ifp->if_start)(ifp); return 0; } /* * Assign priority to a frame based on any vlan tag assigned * to the station and/or any Diffserv setting in an IP header. * Finally, if an ACM policy is setup (in station mode) it's * applied. */ int ieee80211_classify(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni) { int v_wme_ac, d_wme_ac, ac; #ifdef INET struct ether_header *eh; #endif if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) { ac = WME_AC_BE; goto done; } /* * If node has a vlan tag then all traffic * to it must have a matching tag. */ v_wme_ac = 0; if (ni->ni_vlan != 0) { /* XXX used to check ec_nvlans. */ struct m_tag *mtag = m_tag_find(m, PACKET_TAG_VLAN, NULL); if (mtag == NULL) { IEEE80211_NODE_STAT(ni, tx_novlantag); return 1; } if (EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag)) != EVL_VLANOFTAG(ni->ni_vlan)) { IEEE80211_NODE_STAT(ni, tx_vlanmismatch); return 1; } /* map vlan priority to AC */ switch (EVL_PRIOFTAG(ni->ni_vlan)) { case 1: case 2: v_wme_ac = WME_AC_BK; break; case 0: case 3: v_wme_ac = WME_AC_BE; break; case 4: case 5: v_wme_ac = WME_AC_VI; break; case 6: case 7: v_wme_ac = WME_AC_VO; break; } } #ifdef INET eh = mtod(m, struct ether_header *); if (eh->ether_type == htons(ETHERTYPE_IP)) { const struct ip *ip = (struct ip *) (mtod(m, u_int8_t *) + sizeof (*eh)); /* * IP frame, map the TOS field. */ switch (ip->ip_tos) { case 0x08: case 0x20: d_wme_ac = WME_AC_BK; /* background */ break; case 0x28: case 0xa0: d_wme_ac = WME_AC_VI; /* video */ break; case 0x30: /* voice */ case 0xe0: case 0x88: /* XXX UPSD */ case 0xb8: d_wme_ac = WME_AC_VO; break; default: d_wme_ac = WME_AC_BE; break; } } else { #endif /* INET */ d_wme_ac = WME_AC_BE; #ifdef INET } #endif /* * Use highest priority AC. */ if (v_wme_ac > d_wme_ac) ac = v_wme_ac; else ac = d_wme_ac; /* * Apply ACM policy. */ if (ic->ic_opmode == IEEE80211_M_STA) { static const int acmap[4] = { WME_AC_BK, /* WME_AC_BE */ WME_AC_BK, /* WME_AC_BK */ WME_AC_BE, /* WME_AC_VI */ WME_AC_VI, /* WME_AC_VO */ }; while (ac != WME_AC_BK && ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm) ac = acmap[ac]; } done: M_WME_SETAC(m, ac); return 0; } /* * Insure there is sufficient contiguous space to encapsulate the * 802.11 data frame. If room isn't already there, arrange for it. * Drivers and cipher modules assume we have done the necessary work * and fail rudely if they don't find the space they need. */ static struct mbuf * ieee80211_mbuf_adjust(struct ieee80211com *ic, int hdrsize, struct ieee80211_key *key, struct mbuf *m) { #define TO_BE_RECLAIMED (sizeof(struct ether_header) - sizeof(struct llc)) int needed_space = hdrsize; int wlen = 0; if (key != NULL) { /* XXX belongs in crypto code? */ needed_space += key->wk_cipher->ic_header; /* XXX frags */ } /* * We know we are called just before stripping an Ethernet * header and prepending an LLC header. This means we know * there will be * sizeof(struct ether_header) - sizeof(struct llc) * bytes recovered to which we need additional space for the * 802.11 header and any crypto header. */ /* XXX check trailing space and copy instead? */ if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) { struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type); if (n == NULL) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, "%s: cannot expand storage\n", __func__); ic->ic_stats.is_tx_nobuf++; m_freem(m); return NULL; } IASSERT(needed_space <= MHLEN, ("not enough room, need %u got %zu\n", needed_space, MHLEN)); /* * Setup new mbuf to have leading space to prepend the * 802.11 header and any crypto header bits that are * required (the latter are added when the driver calls * back to ieee80211_crypto_encap to do crypto encapsulation). */ /* NB: must be first 'cuz it clobbers m_data */ M_MOVE_PKTHDR(n, m); n->m_len = 0; /* NB: m_gethdr does not set */ n->m_data += needed_space; /* * Pull up Ethernet header to create the expected layout. * We could use m_pullup but that's overkill (i.e. we don't * need the actual data) and it cannot fail so do it inline * for speed. */ /* NB: struct ether_header is known to be contiguous */ n->m_len += sizeof(struct ether_header); m->m_len -= sizeof(struct ether_header); m->m_data += sizeof(struct ether_header); /* * Replace the head of the chain. */ n->m_next = m; m = n; } else { /* We will overwrite the ethernet header in the * 802.11 encapsulation stage. Make sure that it * is writable. */ wlen = sizeof(struct ether_header); } /* * If we're going to s/w encrypt the mbuf chain make sure it is * writable. */ if (key != NULL && (key->wk_flags & IEEE80211_KEY_SWCRYPT) != 0) wlen = M_COPYALL; if (wlen != 0 && m_makewritable(&m, 0, wlen, M_DONTWAIT) != 0) { m_freem(m); return NULL; } return m; #undef TO_BE_RECLAIMED } /* * Return the transmit key to use in sending a unicast frame. * If a unicast key is set we use that. When no unicast key is set * we fall back to the default transmit key. */ static __inline struct ieee80211_key * ieee80211_crypto_getucastkey(struct ieee80211com *ic, struct ieee80211_node *ni) { if (IEEE80211_KEY_UNDEFINED(ni->ni_ucastkey)) { if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE || IEEE80211_KEY_UNDEFINED(ic->ic_nw_keys[ic->ic_def_txkey])) return NULL; return &ic->ic_nw_keys[ic->ic_def_txkey]; } else { return &ni->ni_ucastkey; } } /* * Return the transmit key to use in sending a multicast frame. * Multicast traffic always uses the group key which is installed as * the default tx key. */ static __inline struct ieee80211_key * ieee80211_crypto_getmcastkey(struct ieee80211com *ic, struct ieee80211_node *ni) { if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE || IEEE80211_KEY_UNDEFINED(ic->ic_nw_keys[ic->ic_def_txkey])) return NULL; return &ic->ic_nw_keys[ic->ic_def_txkey]; } /* * Encapsulate an outbound data frame. The mbuf chain is updated. * If an error is encountered NULL is returned. The caller is required * to provide a node reference and pullup the ethernet header in the * first mbuf. d194 1 a194 2 ieee80211_encap(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni) d196 1 d199 1 a199 1 struct ieee80211_key *key; a200 1 int hdrsize, datalen, addqos; d202 7 a208 1 IASSERT(m->m_len >= sizeof(eh), ("no ethernet header!")); d211 6 a216 46 /* * Insure space for additional headers. First identify * transmit key to use in calculating any buffer adjustments * required. This is also used below to do privacy * encapsulation work. Then calculate the 802.11 header * size and any padding required by the driver. * * Note key may be NULL if we fall back to the default * transmit key and that is not set. In that case the * buffer may not be expanded as needed by the cipher * routines, but they will/should discard it. */ if (ic->ic_flags & IEEE80211_F_PRIVACY) { if (ic->ic_opmode == IEEE80211_M_STA || !IEEE80211_IS_MULTICAST(eh.ether_dhost)) key = ieee80211_crypto_getucastkey(ic, ni); else key = ieee80211_crypto_getmcastkey(ic, ni); if (key == NULL && eh.ether_type != htons(ETHERTYPE_PAE)) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, "[%s] no default transmit key (%s) deftxkey %u\n", ether_sprintf(eh.ether_dhost), __func__, ic->ic_def_txkey); ic->ic_stats.is_tx_nodefkey++; } } else key = NULL; /* XXX 4-address format */ /* * XXX Some ap's don't handle QoS-encapsulated EAPOL * frames so suppress use. This may be an issue if other * ap's require all data frames to be QoS-encapsulated * once negotiated in which case we'll need to make this * configurable. */ addqos = (ni->ni_flags & IEEE80211_NODE_QOS) && eh.ether_type != htons(ETHERTYPE_PAE); if (addqos) hdrsize = sizeof(struct ieee80211_qosframe); else hdrsize = sizeof(struct ieee80211_frame); if (ic->ic_flags & IEEE80211_F_DATAPAD) hdrsize = roundup(hdrsize, sizeof(u_int32_t)); m = ieee80211_mbuf_adjust(ic, hdrsize, key, m); if (m == NULL) { /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ d219 1 a220 1 /* NB: this could be optimized because of ieee80211_mbuf_adjust */ d229 1 a229 3 datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */ M_PREPEND(m, hdrsize, M_DONTWAIT); d231 1 a231 1 ic->ic_stats.is_tx_nobuf++; d236 4 a239 1 *(u_int16_t *)wh->i_dur = 0; a251 4 /* * NB: always use the bssid from ic_bss as the * neighbor's may be stale after an ibss merge */ a254 1 #ifndef IEEE80211_NO_HOSTAP a258 1 #endif /* !IEEE80211_NO_HOSTAP */ d263 3 a265 49 if (m->m_flags & M_MORE_DATA) wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; if (addqos) { struct ieee80211_qosframe *qwh = (struct ieee80211_qosframe *) wh; int ac, tid; ac = M_WME_GETAC(m); /* map from access class/queue to 11e header priorty value */ tid = WME_AC_TO_TID(ac); qwh->i_qos[0] = tid & IEEE80211_QOS_TID; if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy) qwh->i_qos[0] |= 1 << IEEE80211_QOS_ACKPOLICY_S; qwh->i_qos[1] = 0; qwh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; *(u_int16_t *)wh->i_seq = htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[tid]++; } else { *(u_int16_t *)wh->i_seq = htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; } if (key != NULL) { /* * IEEE 802.1X: send EAPOL frames always in the clear. * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. */ if (eh.ether_type != htons(ETHERTYPE_PAE) || ((ic->ic_flags & IEEE80211_F_WPA) && (ic->ic_opmode == IEEE80211_M_STA ? !IEEE80211_KEY_UNDEFINED(*key) : !IEEE80211_KEY_UNDEFINED(ni->ni_ucastkey)))) { wh->i_fc[1] |= IEEE80211_FC1_WEP; /* XXX do fragmentation */ if (!ieee80211_crypto_enmic(ic, key, m, 0)) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, "[%s] enmic failed, discard frame\n", ether_sprintf(eh.ether_dhost)); ic->ic_stats.is_crypto_enmicfail++; goto bad; } } } IEEE80211_NODE_STAT(ni, tx_data); IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen); d270 3 d380 1 a380 1 ieee80211_compute_duration(struct ieee80211_frame_min *wh, int len, d394 1 a394 3 if ((wh->i_fc[1] & IEEE80211_FC1_WEP) != 0) { /* XXX assumes the packet is already WEP encapsulated */ paylen -= IEEE80211_WEP_TOTLEN; d396 1 a396 1 } else d444 1 a444 1 static u_int8_t * d461 1 a461 1 static u_int8_t * d477 1 a477 1 /* d489 2 a490 5 /* * Add an erp element to a frame. */ static u_int8_t * ieee80211_add_erp(u_int8_t *frm, struct ieee80211com *ic) d492 1 a492 1 u_int8_t erp; d494 9 a502 11 *frm++ = IEEE80211_ELEMID_ERP; *frm++ = 1; erp = 0; if (ic->ic_nonerpsta != 0) erp |= IEEE80211_ERP_NON_ERP_PRESENT; if (ic->ic_flags & IEEE80211_F_USEPROT) erp |= IEEE80211_ERP_USE_PROTECTION; if (ic->ic_flags & IEEE80211_F_USEBARKER) erp |= IEEE80211_ERP_LONG_PREAMBLE; *frm++ = erp; return frm; a504 249 static u_int8_t * ieee80211_setup_wpa_ie(struct ieee80211com *ic, u_int8_t *ie) { #define WPA_OUI_BYTES 0x00, 0x50, 0xf2 #define ADDSHORT(frm, v) do { \ frm[0] = (v) & 0xff; \ frm[1] = (v) >> 8; \ frm += 2; \ } while (0) #define ADDSELECTOR(frm, sel) do { \ memcpy(frm, sel, 4); \ frm += 4; \ } while (0) static const u_int8_t oui[4] = { WPA_OUI_BYTES, WPA_OUI_TYPE }; static const u_int8_t cipher_suite[][4] = { { WPA_OUI_BYTES, WPA_CSE_WEP40 }, /* NB: 40-bit */ { WPA_OUI_BYTES, WPA_CSE_TKIP }, { 0x00, 0x00, 0x00, 0x00 }, /* XXX WRAP */ { WPA_OUI_BYTES, WPA_CSE_CCMP }, { 0x00, 0x00, 0x00, 0x00 }, /* XXX CKIP */ { WPA_OUI_BYTES, WPA_CSE_NULL }, }; static const u_int8_t wep104_suite[4] = { WPA_OUI_BYTES, WPA_CSE_WEP104 }; static const u_int8_t key_mgt_unspec[4] = { WPA_OUI_BYTES, WPA_ASE_8021X_UNSPEC }; static const u_int8_t key_mgt_psk[4] = { WPA_OUI_BYTES, WPA_ASE_8021X_PSK }; const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn; u_int8_t *frm = ie; u_int8_t *selcnt; *frm++ = IEEE80211_ELEMID_VENDOR; *frm++ = 0; /* length filled in below */ memcpy(frm, oui, sizeof(oui)); /* WPA OUI */ frm += sizeof(oui); ADDSHORT(frm, WPA_VERSION); /* XXX filter out CKIP */ /* multicast cipher */ if (rsn->rsn_mcastcipher == IEEE80211_CIPHER_WEP && rsn->rsn_mcastkeylen >= 13) ADDSELECTOR(frm, wep104_suite); else ADDSELECTOR(frm, cipher_suite[rsn->rsn_mcastcipher]); /* unicast cipher list */ selcnt = frm; ADDSHORT(frm, 0); /* selector count */ if (rsn->rsn_ucastcipherset & (1<rsn_ucastcipherset & (1<rsn_keymgmtset & WPA_ASE_8021X_UNSPEC) { selcnt[0]++; ADDSELECTOR(frm, key_mgt_unspec); } if (rsn->rsn_keymgmtset & WPA_ASE_8021X_PSK) { selcnt[0]++; ADDSELECTOR(frm, key_mgt_psk); } /* optional capabilities */ if (rsn->rsn_caps != 0 && rsn->rsn_caps != RSN_CAP_PREAUTH) ADDSHORT(frm, rsn->rsn_caps); /* calculate element length */ ie[1] = frm - ie - 2; IASSERT(ie[1]+2 <= sizeof(struct ieee80211_ie_wpa), ("WPA IE too big, %u > %zu", ie[1]+2, sizeof(struct ieee80211_ie_wpa))); return frm; #undef ADDSHORT #undef ADDSELECTOR #undef WPA_OUI_BYTES } static u_int8_t * ieee80211_setup_rsn_ie(struct ieee80211com *ic, u_int8_t *ie) { #define RSN_OUI_BYTES 0x00, 0x0f, 0xac #define ADDSHORT(frm, v) do { \ frm[0] = (v) & 0xff; \ frm[1] = (v) >> 8; \ frm += 2; \ } while (0) #define ADDSELECTOR(frm, sel) do { \ memcpy(frm, sel, 4); \ frm += 4; \ } while (0) static const u_int8_t cipher_suite[][4] = { { RSN_OUI_BYTES, RSN_CSE_WEP40 }, /* NB: 40-bit */ { RSN_OUI_BYTES, RSN_CSE_TKIP }, { RSN_OUI_BYTES, RSN_CSE_WRAP }, { RSN_OUI_BYTES, RSN_CSE_CCMP }, { 0x00, 0x00, 0x00, 0x00 }, /* XXX CKIP */ { RSN_OUI_BYTES, RSN_CSE_NULL }, }; static const u_int8_t wep104_suite[4] = { RSN_OUI_BYTES, RSN_CSE_WEP104 }; static const u_int8_t key_mgt_unspec[4] = { RSN_OUI_BYTES, RSN_ASE_8021X_UNSPEC }; static const u_int8_t key_mgt_psk[4] = { RSN_OUI_BYTES, RSN_ASE_8021X_PSK }; const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn; u_int8_t *frm = ie; u_int8_t *selcnt; *frm++ = IEEE80211_ELEMID_RSN; *frm++ = 0; /* length filled in below */ ADDSHORT(frm, RSN_VERSION); /* XXX filter out CKIP */ /* multicast cipher */ if (rsn->rsn_mcastcipher == IEEE80211_CIPHER_WEP && rsn->rsn_mcastkeylen >= 13) ADDSELECTOR(frm, wep104_suite); else ADDSELECTOR(frm, cipher_suite[rsn->rsn_mcastcipher]); /* unicast cipher list */ selcnt = frm; ADDSHORT(frm, 0); /* selector count */ if (rsn->rsn_ucastcipherset & (1<rsn_ucastcipherset & (1<rsn_keymgmtset & WPA_ASE_8021X_UNSPEC) { selcnt[0]++; ADDSELECTOR(frm, key_mgt_unspec); } if (rsn->rsn_keymgmtset & WPA_ASE_8021X_PSK) { selcnt[0]++; ADDSELECTOR(frm, key_mgt_psk); } /* optional capabilities */ ADDSHORT(frm, rsn->rsn_caps); /* XXX PMKID */ /* calculate element length */ ie[1] = frm - ie - 2; IASSERT(ie[1]+2 <= sizeof(struct ieee80211_ie_wpa), ("RSN IE too big, %u > %zu", ie[1]+2, sizeof(struct ieee80211_ie_wpa))); return frm; #undef ADDSELECTOR #undef ADDSHORT #undef RSN_OUI_BYTES } /* * Add a WPA/RSN element to a frame. */ static u_int8_t * ieee80211_add_wpa(u_int8_t *frm, struct ieee80211com *ic) { IASSERT(ic->ic_flags & IEEE80211_F_WPA, ("no WPA/RSN!")); if (ic->ic_flags & IEEE80211_F_WPA2) frm = ieee80211_setup_rsn_ie(ic, frm); if (ic->ic_flags & IEEE80211_F_WPA1) frm = ieee80211_setup_wpa_ie(ic, frm); return frm; } #define WME_OUI_BYTES 0x00, 0x50, 0xf2 /* * Add a WME information element to a frame. */ static u_int8_t * ieee80211_add_wme_info(u_int8_t *frm, struct ieee80211_wme_state *wme) { static const struct ieee80211_wme_info info = { .wme_id = IEEE80211_ELEMID_VENDOR, .wme_len = sizeof(struct ieee80211_wme_info) - 2, .wme_oui = { WME_OUI_BYTES }, .wme_type = WME_OUI_TYPE, .wme_subtype = WME_INFO_OUI_SUBTYPE, .wme_version = WME_VERSION, .wme_info = 0, }; memcpy(frm, &info, sizeof(info)); return frm + sizeof(info); } /* * Add a WME parameters element to a frame. */ static u_int8_t * ieee80211_add_wme_param(u_int8_t *frm, struct ieee80211_wme_state *wme) { #define SM(_v, _f) (((_v) << _f##_S) & _f) #define ADDSHORT(frm, v) do { \ frm[0] = (v) & 0xff; \ frm[1] = (v) >> 8; \ frm += 2; \ } while (0) /* NB: this works 'cuz a param has an info at the front */ static const struct ieee80211_wme_info param = { .wme_id = IEEE80211_ELEMID_VENDOR, .wme_len = sizeof(struct ieee80211_wme_param) - 2, .wme_oui = { WME_OUI_BYTES }, .wme_type = WME_OUI_TYPE, .wme_subtype = WME_PARAM_OUI_SUBTYPE, .wme_version = WME_VERSION, }; int i; memcpy(frm, ¶m, sizeof(param)); frm += __offsetof(struct ieee80211_wme_info, wme_info); *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */ *frm++ = 0; /* reserved field */ for (i = 0; i < WME_NUM_AC; i++) { const struct wmeParams *ac = &wme->wme_bssChanParams.cap_wmeParams[i]; *frm++ = SM(i, WME_PARAM_ACI) | SM(ac->wmep_acm, WME_PARAM_ACM) | SM(ac->wmep_aifsn, WME_PARAM_AIFSN) ; *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN) ; ADDSHORT(frm, ac->wmep_txopLimit); } return frm; #undef SM #undef ADDSHORT } #undef WME_OUI_BYTES d515 1 d520 1 a520 1 int has_challenge, is_shared_key, ret, timer, status; a528 5 IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1); a529 1 a537 1 * [tlv] user-specified ie's d539 2 a540 2 m = ieee80211_getmgtframe(&frm, 2 + IEEE80211_NWID_LEN d542 1 a542 3 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + (ic->ic_opt_ie != NULL ? ic->ic_opt_ie_len : 0) ); d544 3 a546 2 senderr(ENOMEM, is_tx_nobuf); a550 4 if (ic->ic_opt_ie != NULL) { memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len); frm += ic->ic_opt_ie_len; } d553 1 a553 3 IEEE80211_NODE_STAT(ni, tx_probereq); if (ic->ic_opmode == IEEE80211_M_STA) timer = IEEE80211_TRANS_WAIT; a565 1 * [tlv] extended rate phy (ERP) a566 2 * [tlv] WPA * [tlv] WME (optional) d568 3 a570 5 m = ieee80211_getmgtframe(&frm, 8 + sizeof(u_int16_t) + sizeof(u_int16_t) + 2 + IEEE80211_NWID_LEN d572 1 a572 1 + 7 /* max(7,3) */ d574 1 a574 7 + 3 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) /* XXX !WPA1+WPA2 fits w/o a cluster */ + (ic->ic_flags & IEEE80211_F_WPA ? 2*sizeof(struct ieee80211_ie_wpa) : 0) + sizeof(struct ieee80211_wme_param) ); d576 3 a578 1 senderr(ENOMEM, is_tx_nobuf); a592 2 if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; d598 1 a598 1 frm = ieee80211_add_rates(frm, &ni->ni_rates); d620 8 d629 1 a629 7 if (ic->ic_flags & IEEE80211_F_WPA) frm = ieee80211_add_wpa(frm, ic); if (ic->ic_curmode == IEEE80211_MODE_11G) frm = ieee80211_add_erp(frm, ic); frm = ieee80211_add_xrates(frm, &ni->ni_rates); if (ic->ic_flags & IEEE80211_F_WME) frm = ieee80211_add_wme_param(frm, &ic->ic_wme); d634 4 a637 2 status = arg >> 16; arg &= 0xffff; d642 2 a643 19 /* * Deduce whether we're doing open authentication or * shared key authentication. We do the latter if * we're in the middle of a shared key authentication * handshake or if we're initiating an authentication * request and configured to use shared key. */ is_shared_key = has_challenge || arg >= IEEE80211_AUTH_SHARED_RESPONSE || (arg == IEEE80211_AUTH_SHARED_REQUEST && ic->ic_bss->ni_authmode == IEEE80211_AUTH_SHARED); m = ieee80211_getmgtframe(&frm, 3 * sizeof(u_int16_t) + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? sizeof(u_int16_t)+IEEE80211_CHALLENGE_LEN : 0) ); if (m == NULL) senderr(ENOMEM, is_tx_nobuf); d645 9 d658 1 a658 1 ((u_int16_t *)frm)[2] = htole16(status);/* status */ d660 1 a660 1 if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { a665 2 m->m_pkthdr.len = m->m_len = 4 * sizeof(u_int16_t) + IEEE80211_CHALLENGE_LEN; d668 1 a668 2 "[%s] request encrypt frame (%s)\n", ether_sprintf(ni->ni_macaddr), __func__); d671 1 a671 9 } else m->m_pkthdr.len = m->m_len = 3 * sizeof(u_int16_t); /* XXX not right for shared key */ if (status == IEEE80211_STATUS_SUCCESS) IEEE80211_NODE_STAT(ni, tx_auth); else IEEE80211_NODE_STAT(ni, tx_auth_fail); d678 3 a680 3 "[%s] send station deauthenticate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg); m = ieee80211_getmgtframe(&frm, sizeof(u_int16_t)); d682 4 a685 8 senderr(ENOMEM, is_tx_nobuf); *(u_int16_t *)frm = htole16(arg); /* reason */ m->m_pkthdr.len = m->m_len = sizeof(u_int16_t); IEEE80211_NODE_STAT(ni, tx_deauth); IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg); ieee80211_node_unauthorize(ic, ni); /* port closed */ a697 2 * [tlv] WME * [tlv] user-specified ie's d699 2 a700 2 m = ieee80211_getmgtframe(&frm, sizeof(u_int16_t) d703 1 a703 1 + 2 + IEEE80211_NWID_LEN d705 1 a705 4 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + sizeof(struct ieee80211_wme_info) + (ic->ic_opt_ie != NULL ? ic->ic_opt_ie_len : 0) ); d707 3 a709 1 senderr(ENOMEM, is_tx_nobuf); d725 1 a725 2 if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) && (ic->ic_caps & IEEE80211_C_SHSLOT)) a740 6 if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL) frm = ieee80211_add_wme_info(frm, &ic->ic_wme); if (ic->ic_opt_ie != NULL) { memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len); frm += ic->ic_opt_ie_len; } a754 1 * [tlv] WME (if enabled and STA enabled) d756 2 a757 2 m = ieee80211_getmgtframe(&frm, sizeof(u_int16_t) d761 1 a761 3 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + sizeof(struct ieee80211_wme_param) ); d763 3 a765 1 senderr(ENOMEM, is_tx_nobuf); a772 2 if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; d779 1 a779 1 if (arg == IEEE80211_STATUS_SUCCESS) { a780 3 IEEE80211_NODE_STAT(ni, tx_assoc); } else IEEE80211_NODE_STAT(ni, tx_assoc_fail); a784 2 if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL) frm = ieee80211_add_wme_param(frm, &ic->ic_wme); d790 3 a792 3 "[%s] send station disassociate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg); m = ieee80211_getmgtframe(&frm, sizeof(u_int16_t)); d794 4 a797 6 senderr(ENOMEM, is_tx_nobuf); *(u_int16_t *)frm = htole16(arg); /* reason */ m->m_pkthdr.len = m->m_len = sizeof(u_int16_t); IEEE80211_NODE_STAT(ni, tx_disassoc); IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg); d802 1 a802 2 "[%s] invalid mgmt frame type %u\n", ether_sprintf(ni->ni_macaddr), type); d807 1 a807 1 ret = ieee80211_mgmt_output(ic, ni, m, type); d813 1 a813 1 ieee80211_free_node(ni); d819 3 a821 6 /* * Allocate a beacon frame and fillin the appropriate bits. */ struct mbuf * ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo) d823 1 a823 7 struct ifnet *ifp = ic->ic_ifp; struct ieee80211_frame *wh; struct mbuf *m; int pktlen; u_int8_t *frm, *efrm; u_int16_t capinfo; struct ieee80211_rateset *rs; d825 2 a826 37 /* * beacon frame format * [8] time stamp * [2] beacon interval * [2] cabability information * [tlv] ssid * [tlv] supported rates * [3] parameter set (DS) * [tlv] parameter set (IBSS/TIM) * [tlv] extended rate phy (ERP) * [tlv] extended supported rates * [tlv] WME parameters * [tlv] WPA/RSN parameters * XXX Vendor-specific OIDs (e.g. Atheros) * NB: we allocate the max space required for the TIM bitmap. */ rs = &ni->ni_rates; pktlen = 8 /* time stamp */ + sizeof(u_int16_t) /* beacon interval */ + sizeof(u_int16_t) /* capabilities */ + 2 + ni->ni_esslen /* ssid */ + 2 + IEEE80211_RATE_SIZE /* supported rates */ + 2 + 1 /* DS parameters */ + 2 + 4 + ic->ic_tim_len /* DTIM/IBSSPARMS */ + 2 + 1 /* ERP */ + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + (ic->ic_caps & IEEE80211_C_WME ? /* WME */ sizeof(struct ieee80211_wme_param) : 0) + (ic->ic_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ 2*sizeof(struct ieee80211_ie_wpa) : 0) ; m = ieee80211_getmgtframe(&frm, pktlen); if (m == NULL) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, "%s: cannot get buf; size %u\n", __func__, pktlen); ic->ic_stats.is_tx_nobuf++; return NULL; d828 10 a837 38 memset(frm, 0, 8); /* XXX timestamp is set by hardware/driver */ frm += 8; *(u_int16_t *)frm = htole16(ni->ni_intval); frm += 2; if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; bo->bo_caps = (u_int16_t *)frm; *(u_int16_t *)frm = htole16(capinfo); frm += 2; *frm++ = IEEE80211_ELEMID_SSID; if ((ic->ic_flags & IEEE80211_F_HIDESSID) == 0) { *frm++ = ni->ni_esslen; memcpy(frm, ni->ni_essid, ni->ni_esslen); frm += ni->ni_esslen; } else *frm++ = 0; frm = ieee80211_add_rates(frm, rs); if (ic->ic_curmode != IEEE80211_MODE_FH) { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); } bo->bo_tim = frm; if (ic->ic_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ bo->bo_tim_len = 0; d839 2 a840 74 struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; tie->tim_ie = IEEE80211_ELEMID_TIM; tie->tim_len = 4; /* length */ tie->tim_count = 0; /* DTIM count */ tie->tim_period = ic->ic_dtim_period; /* DTIM period */ tie->tim_bitctl = 0; /* bitmap control */ tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ frm += sizeof(struct ieee80211_tim_ie); bo->bo_tim_len = 1; } bo->bo_trailer = frm; if (ic->ic_flags & IEEE80211_F_WME) { bo->bo_wme = frm; frm = ieee80211_add_wme_param(frm, &ic->ic_wme); ic->ic_flags &= ~IEEE80211_F_WMEUPDATE; } if (ic->ic_flags & IEEE80211_F_WPA) frm = ieee80211_add_wpa(frm, ic); if (ic->ic_curmode == IEEE80211_MODE_11G) frm = ieee80211_add_erp(frm, ic); efrm = ieee80211_add_xrates(frm, rs); bo->bo_trailer_len = efrm - bo->bo_trailer; m->m_pkthdr.len = m->m_len = efrm - mtod(m, u_int8_t *); M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); IASSERT(m != NULL, ("no space for 802.11 header?")); wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_BEACON; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(u_int16_t *)wh->i_dur = 0; IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); *(u_int16_t *)wh->i_seq = 0; return m; } /* * Update the dynamic parts of a beacon frame based on the current state. */ int ieee80211_beacon_update(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) { int len_changed = 0; u_int16_t capinfo; IEEE80211_BEACON_LOCK(ic); /* XXX faster to recalculate entirely or just changes? */ if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; *bo->bo_caps = htole16(capinfo); if (ic->ic_flags & IEEE80211_F_WME) { struct ieee80211_wme_state *wme = &ic->ic_wme; /* * Check for agressive mode change. When there is * significant high priority traffic in the BSS * throttle back BE traffic by using conservative * parameters. Otherwise BE uses agressive params * to optimize performance of legacy/non-QoS traffic. d842 2 a843 29 if (wme->wme_flags & WME_F_AGGRMODE) { if (wme->wme_hipri_traffic > wme->wme_hipri_switch_thresh) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, "%s: traffic %u, disable aggressive mode\n", __func__, wme->wme_hipri_traffic); wme->wme_flags &= ~WME_F_AGGRMODE; ieee80211_wme_updateparams_locked(ic); wme->wme_hipri_traffic = wme->wme_hipri_switch_hysteresis; } else wme->wme_hipri_traffic = 0; } else { if (wme->wme_hipri_traffic <= wme->wme_hipri_switch_thresh) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, "%s: traffic %u, enable aggressive mode\n", __func__, wme->wme_hipri_traffic); wme->wme_flags |= WME_F_AGGRMODE; ieee80211_wme_updateparams_locked(ic); wme->wme_hipri_traffic = 0; } else wme->wme_hipri_traffic = wme->wme_hipri_switch_hysteresis; } if (ic->ic_flags & IEEE80211_F_WMEUPDATE) { (void) ieee80211_add_wme_param(bo->bo_wme, wme); ic->ic_flags &= ~IEEE80211_F_WMEUPDATE; } a844 76 #ifndef IEEE80211_NO_HOSTAP if (ic->ic_opmode == IEEE80211_M_HOSTAP) { /* NB: no IBSS support*/ struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) bo->bo_tim; if (ic->ic_flags & IEEE80211_F_TIMUPDATE) { u_int timlen, timoff, i; /* * ATIM/DTIM needs updating. If it fits in the * current space allocated then just copy in the * new bits. Otherwise we need to move any trailing * data to make room. Note that we know there is * contiguous space because ieee80211_beacon_allocate * insures there is space in the mbuf to write a * maximal-size virtual bitmap (based on ic_max_aid). */ /* * Calculate the bitmap size and offset, copy any * trailer out of the way, and then copy in the * new bitmap and update the information element. * Note that the tim bitmap must contain at least * one byte and any offset must be even. */ if (ic->ic_ps_pending != 0) { timoff = 128; /* impossibly large */ for (i = 0; i < ic->ic_tim_len; i++) if (ic->ic_tim_bitmap[i]) { timoff = i &~ 1; break; } IASSERT(timoff != 128, ("tim bitmap empty!")); for (i = ic->ic_tim_len-1; i >= timoff; i--) if (ic->ic_tim_bitmap[i]) break; timlen = 1 + (i - timoff); } else { timoff = 0; timlen = 1; } if (timlen != bo->bo_tim_len) { /* copy up/down trailer */ ovbcopy(bo->bo_trailer, tie->tim_bitmap+timlen, bo->bo_trailer_len); bo->bo_trailer = tie->tim_bitmap+timlen; bo->bo_wme = bo->bo_trailer; bo->bo_tim_len = timlen; /* update information element */ tie->tim_len = 3 + timlen; tie->tim_bitctl = timoff; len_changed = 1; } memcpy(tie->tim_bitmap, ic->ic_tim_bitmap + timoff, bo->bo_tim_len); ic->ic_flags &= ~IEEE80211_F_TIMUPDATE; IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, "%s: TIM updated, pending %u, off %u, len %u\n", __func__, ic->ic_ps_pending, timoff, timlen); } /* count down DTIM period */ if (tie->tim_count == 0) tie->tim_count = tie->tim_period - 1; else tie->tim_count--; /* update state for buffered multicast frames on DTIM */ if (mcast && (tie->tim_count == 1 || tie->tim_period == 1)) tie->tim_bitctl |= 1; else tie->tim_bitctl &= ~1; } #endif /* !IEEE80211_NO_HOSTAP */ IEEE80211_BEACON_UNLOCK(ic); return len_changed; a846 45 /* * Save an outbound packet for a node in power-save sleep state. * The new packet is placed on the node's saved queue, and the TIM * is changed, if necessary. */ void ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni, struct mbuf *m) { int qlen, age; IEEE80211_NODE_SAVEQ_LOCK(ni); if (IF_QFULL(&ni->ni_savedq)) { IF_DROP(&ni->ni_savedq); IEEE80211_NODE_SAVEQ_UNLOCK(ni); IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, "[%s] pwr save q overflow, drops %d (size %d)\n", ether_sprintf(ni->ni_macaddr), ni->ni_savedq.ifq_drops, IEEE80211_PS_MAX_QUEUE); #ifdef IEEE80211_DEBUG if (ieee80211_msg_dumppkts(ic)) ieee80211_dump_pkt(mtod(m, caddr_t), m->m_len, -1, -1); #endif m_freem(m); return; } /* * Tag the frame with it's expiry time and insert * it in the queue. The aging interval is 4 times * the listen interval specified by the station. * Frames that sit around too long are reclaimed * using this information. */ /* XXX handle overflow? */ age = ((ni->ni_intval * ic->ic_lintval) << 2) / 1024; /* TU -> secs */ _IEEE80211_NODE_SAVEQ_ENQUEUE(ni, m, qlen, age); IEEE80211_NODE_SAVEQ_UNLOCK(ni); IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, "[%s] save frame, %u now queued\n", ether_sprintf(ni->ni_macaddr), qlen); if (qlen == 1) ic->ic_set_tim(ic, ni, 1); } @ 1.16.2.10 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.16.2.9 2005/12/11 10:29:22 christos Exp $ */ d36 1 a36 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.34 2005/08/10 16:22:29 sam Exp $"); d39 1 a39 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.16.2.9 2005/12/11 10:29:22 christos Exp $"); a98 56 * Set the direction field and address fields of an outgoing * non-QoS frame. Note this should be called early on in * constructing a frame as it sets i_fc[1]; other bits can * then be or'd in. */ static void ieee80211_send_setup(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_frame *wh, int type, const u_int8_t sa[IEEE80211_ADDR_LEN], const u_int8_t da[IEEE80211_ADDR_LEN], const u_int8_t bssid[IEEE80211_ADDR_LEN]) { #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { switch (ic->ic_opmode) { case IEEE80211_M_STA: wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; IEEE80211_ADDR_COPY(wh->i_addr1, bssid); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, da); break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, bssid); break; case IEEE80211_M_HOSTAP: wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, bssid); IEEE80211_ADDR_COPY(wh->i_addr3, sa); break; case IEEE80211_M_MONITOR: /* NB: to quiet compiler */ break; } } else { wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, bssid); } *(u_int16_t *)&wh->i_dur[0] = 0; /* NB: use non-QoS tid */ *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; #undef WH4 } /* d135 24 a158 3 ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_MGT | type, ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid); d175 1 a175 1 ieee80211_chan2ieee(ic, ic->ic_curchan)); a186 4 * * NB: the caller is assumed to have setup a node reference * for use; this is necessary to deal with a race condition * when probing for inactive stations. d189 1 a189 1 ieee80211_send_nulldata(struct ieee80211_node *ni) a190 1 struct ieee80211com *ic = ni->ni_ic; a198 1 ieee80211_unref_node(&ni); d201 1 a201 1 m->m_pkthdr.rcvif = (void *) ni; d204 12 a215 7 ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid); /* NB: power management bit is never sent by an AP */ if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && ic->ic_opmode != IEEE80211_M_HOSTAP) wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; a219 6 IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "[%s] send null data frame on channel %u, pwr mgt %s\n", ether_sprintf(ni->ni_macaddr), ieee80211_chan2ieee(ic, ic->ic_curchan), wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); d735 1 a735 1 * of last fragment a1119 85 * Send a probe request frame with the specified ssid * and any optional information element data. */ int ieee80211_send_probereq(struct ieee80211_node *ni, const u_int8_t sa[IEEE80211_ADDR_LEN], const u_int8_t da[IEEE80211_ADDR_LEN], const u_int8_t bssid[IEEE80211_ADDR_LEN], const u_int8_t *ssid, size_t ssidlen, const void *optie, size_t optielen) { struct ieee80211com *ic = ni->ni_ic; enum ieee80211_phymode mode; struct ieee80211_frame *wh; struct mbuf *m; u_int8_t *frm; /* * Hold a reference on the node so it doesn't go away until after * the xmit is complete all the way in the driver. On error we * will remove our reference. */ IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1); ieee80211_ref_node(ni); /* * prreq frame format * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates * [tlv] user-specified ie's */ m = ieee80211_getmgtframe(&frm, 2 + IEEE80211_NWID_LEN + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + (optie != NULL ? optielen : 0) ); if (m == NULL) { ic->ic_stats.is_tx_nobuf++; ieee80211_free_node(ni); return ENOMEM; } frm = ieee80211_add_ssid(frm, ssid, ssidlen); mode = ieee80211_chan2mode(ic, ic->ic_curchan); frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); if (optie != NULL) { memcpy(frm, optie, optielen); frm += optielen; } m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); if (m == NULL) return ENOMEM; IASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null")); m->m_pkthdr.rcvif = (void *)ni; wh = mtod(m, struct ieee80211_frame *); ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, sa, da, bssid); /* XXX power management? */ IEEE80211_NODE_STAT(ni, tx_probereq); IEEE80211_NODE_STAT(ni, tx_mgmt); IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "[%s] send probe req on channel %u\n", ether_sprintf(wh->i_addr1), ieee80211_chan2ieee(ic, ic->ic_curchan)); IF_ENQUEUE(&ic->ic_mgtq, m); (*ic->ic_ifp->if_start)(ic->ic_ifp); return 0; } /* d1131 1 d1151 32 d1227 1 a1227 1 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) d1244 1 a1244 1 ieee80211_chan2ieee(ic, ic->ic_curchan)); d1246 1 a1246 1 ieee80211_chan2ieee(ic, ic->ic_curchan)); d1251 1 a1251 1 *frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan); d1342 1 a1342 1 ieee80211_node_unauthorize(ni); /* port closed */ d1383 1 a1383 1 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) d1439 1 a1439 1 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) d1806 1 a1806 1 age = ((ni->ni_intval * ic->ic_bintval) << 2) / 1024; /* TU -> secs */ d1811 2 a1812 2 "[%s] save frame with age %d, %u now queued\n", ether_sprintf(ni->ni_macaddr), age, qlen); d1815 1 a1815 1 ic->ic_set_tim(ni, 1); @ 1.15 log @Yet more DPRINTF() cleanup. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.14 2004/07/23 06:44:55 mycroft Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.14 2004/07/23 06:44:55 mycroft Exp $"); d263 1 a263 1 if (ic->ic_flags & IEEE80211_F_WEPON) d427 1 a427 1 if (ic->ic_flags & IEEE80211_F_WEPON) d555 1 a555 1 if (ic->ic_flags & IEEE80211_F_WEPON) d607 1 a607 1 if (ic->ic_flags & IEEE80211_F_WEPON) @ 1.14 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_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $"); d93 18 a165 4 if (ifp->if_flags & IFF_DEBUG) { /* avoid to print too many frames */ if (ic->ic_opmode == IEEE80211_M_IBSS || d167 10 a176 1 ieee80211_debug > 1 || a177 10 (type & IEEE80211_FC0_SUBTYPE_MASK) != IEEE80211_FC0_SUBTYPE_PROBE_RESP) if_printf(ifp, "sending %s to %s on channel %u\n", ieee80211_mgt_subtype_name[ (type & IEEE80211_FC0_SUBTYPE_MASK) >> IEEE80211_FC0_SUBTYPE_SHIFT], ether_sprintf(ni->ni_macaddr), ieee80211_chan2ieee(ic, ni->ni_chan)); } d516 3 a518 3 if (ifp->if_flags & IFF_DEBUG) if_printf(ifp, "station %s deauthenticate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg); d628 3 a630 3 if (ifp->if_flags & IFF_DEBUG) if_printf(ifp, "station %s disassociate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg); @ 1.13 log @If WEP is on, set a data packet's WEP flag when we 802.11-encapsulate it. Credit: Matthew Gream. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.12 2004/04/30 23:58:17 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.12 2004/04/30 23:58:17 dyoung Exp $"); d143 3 a145 2 IEEE80211_DPRINTF(("%s: encrypting frame for %s\n", __func__, ether_sprintf(wh->i_addr1))); d200 2 a201 1 IEEE80211_DPRINTF(("%s: no node for dst %s, discard frame\n", d493 2 a494 2 IEEE80211_DPRINTF(( "%s: request encrypt frame\n", __func__)); d627 2 a628 2 IEEE80211_DPRINTF(("%s: invalid mgmt frame type %u\n", __func__, type)); @ 1.12 log @From FreeBSD. Increase a stats counter when ieee80211_find_txnode fails. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.11 2004/01/13 23:37:30 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.11 2004/01/13 23:37:30 dyoung Exp $"); d248 2 @ 1.11 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_output.c,v 1.10 2003/12/14 09:56:53 dyoung Exp $ */ d36 1 a36 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.9 2003/10/17 23:15:30 sam Exp $"); d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.10 2003/12/14 09:56:53 dyoung Exp $"); d197 5 a201 1 if ((ni = ieee80211_find_txnode(ic, eh.ether_dhost)) == NULL) d203 1 a203 1 @ 1.10 log @Synchronize with FreeBSD sources from 12 Dec 2003. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.9 2003/11/02 00:17:27 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.9 2003/11/02 00:17:27 dyoung Exp $"); d107 1 a107 1 KASSERT(ni != NULL, ("null node")); d308 1 a308 1 KASSERT(pktlen <= MCLBYTES, ("802.11 packet too large: %u", pktlen)); d339 1 a339 1 KASSERT(ni != NULL, ("null node")); @ 1.9 log @On the output path, save a power-saving station's ieee80211_node in the mbuf's rcvif field so that the driver can get at it. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.8 2003/10/29 21:50:57 dyoung Exp $ */ d36 1 a36 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.5 2003/09/01 02:55:09 sam Exp $"); d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.8 2003/10/29 21:50:57 dyoung Exp $"); d191 1 a191 1 /* XXX statistic */ d211 2 a212 1 if (m == NULL) d214 1 d331 1 a331 1 #define senderr(_x) do { ret = _x; goto bad; } while (0) d362 1 a362 1 senderr(ENOMEM); d382 1 d390 1 d394 1 a394 1 senderr(ENOMEM); d408 3 d418 1 a418 2 switch (ic->ic_phytype) { case IEEE80211_T_FH: d428 5 a432 17 break; case IEEE80211_T_OFDM: /* probably multi-mode */ default: if (ieee80211_chan2mode(ic, ni->ni_chan) != IEEE80211_MODE_11B) { if_printf(ifp, "unhandled mode %d for %s\n", ieee80211_chan2mode(ic, ni->ni_chan), ether_sprintf(ni->ni_macaddr)); break; } /*FALLTHROUGH*/ case IEEE80211_T_DS: *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); break; } d454 1 a454 1 senderr(ENOMEM); d500 1 a500 1 senderr(ENOMEM); d525 1 a525 1 senderr(ENOMEM); d536 6 a541 1 if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) d581 1 a581 1 senderr(ENOMEM); d588 3 d612 1 a612 1 senderr(ENOMEM); d621 1 a621 1 senderr(EINVAL); @ 1.8 log @Add ieee80211_find_rxnode and its helper ieee80211_needs_rxnode. 802.11 drivers will use ieee80211_find_rxnode to match each received packet with the ieee80211_node belonging to the sender. The driver will use the ieee80211_node to track the sender's RSSI and other statistics for, e.g., rate adaptation. ieee80211_find_rxnode "fakes-up" missing ieee80211_nodes in IBSS mode and in ad-hoc demo mode when it is appropriate. See the comments in the source. Also add ieee80211_find_txnode, which looks up the ieee80211_node belonging to a MAC destination. ieee80211_find_txnode will also fake-up missing nodes in IBSS/ad-hoc demo mode. In ieee80211_encap, use ieee80211_find_txnode. This fixes the bug in ad hoc packet-transmission reported by Greg Troxel, Urban Boquist, and Kurt Schreiner. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.7 2003/10/15 11:43:51 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.7 2003/10/15 11:43:51 dyoung Exp $"); d656 3 d660 1 @ 1.7 log @Add WEP shared-key authentication. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.6 2003/10/13 04:22:55 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.6 2003/10/13 04:22:55 dyoung Exp $"); d197 3 a199 17 if (ic->ic_opmode != IEEE80211_M_STA) { ni = ieee80211_find_node(ic, eh.ether_dhost); if (ni == NULL) { /* * When not in station mode the * destination address should always be * in the node table unless this is a * multicast/broadcast frame. */ if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) { /* ic->ic_stats.st_tx_nonode++; XXX statistic */ goto bad; } ni = ic->ic_bss; } } else ni = ic->ic_bss; @ 1.6 log @Even more changes to the new 802.11 layer: * Add Kevin Lahey's power-saving support from the old 802.11 layer * Add a FHPARMS or DSPARMS info element to probe responses and beacons as appropriate. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.5 2003/09/28 02:35:20 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.5 2003/09/28 02:35:20 dyoung Exp $"); d141 7 d349 1 a349 1 int ret, timer; d475 16 a490 2 MH_ALIGN(m, 2 * 3); m->m_pkthdr.len = m->m_len = 6; d492 3 a494 2 /* TODO: shared key auth */ ((u_int16_t *)frm)[0] = htole16(IEEE80211_AUTH_ALG_OPEN); d497 13 @ 1.5 log @More NetBSD-FreeBSD compatibility changes in the pattern #ifdef __FreeBSD__ /* FreeBSDism */ #else /* NetBSDism */ #endif An important and non-obvious change is in ieee80211_mgmt_output, #ifdef __FreeBSD__ KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null")); #endif Because NetBSD mbufs are not bzero'd like FreeBSD's, we cannot count on rcvif == NULL. @ text @d1 1 a1 1 /* $NetBSD: ieee80211_output.c,v 1.4 2003/09/14 01:14:55 dyoung Exp $ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.4 2003/09/14 01:14:55 dyoung Exp $"); d43 4 d80 1 d82 1 d418 29 d614 25 @ 1.4 log @Insert RCSIDs. @ text @d1 1 a1 1 /* $NetBSD$ */ d38 1 a38 1 __KERNEL_RCSID(0, "$NetBSD$"); d52 1 d54 1 d68 2 d73 1 a74 1 #include d80 1 d82 3 d119 1 d121 1 @ 1.3 log @Complete merge. @ text @d1 1 d35 1 d37 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 @d34 1 a34 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.4 2003/08/19 22:17:03 sam Exp $"); d292 1 d294 1 a294 1 if (pktlen > MHLEN) @ 1.1 log @Initial revision @ text @d51 1 d53 2 a54 1 d59 1 d61 1 d64 1 d112 2 a113 2 *(u_int16_t *)wh->i_dur = 0; *(u_int16_t *)wh->i_seq = d201 2 a202 2 *(u_int16_t *)wh->i_dur = 0; *(u_int16_t *)wh->i_seq = d292 1 d297 5 @ 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 @Bring net80211/ sources up-to-date with FreeBSD. PR: Submitted by: Reviewed by: Approved by: Obtained from: MFC after: @ text @d34 1 a34 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.5 2003/09/01 02:55:09 sam Exp $"); d287 1 a287 2 KASSERT(pktlen <= MCLBYTES, ("802.11 packet too large: %u", pktlen)); if (pktlen <= MHLEN) @ 1.1.1.3 log @Import FreeBSD's net80211 of 12 Dec 2003 @ text @d34 1 a34 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.9 2003/10/17 23:15:30 sam Exp $"); d158 1 a158 1 ic->ic_stats.is_tx_nombuf++; d168 4 a171 12 * When not in station mode the destination * address should always be in the node table * if the device sends management frames to us; * unless this is a multicast/broadcast frame. * For devices that don't send management frames * to the host we have to cheat; use the bss * node instead; the card will/should clobber * the bssid address as necessary. * * XXX this handles AHDEMO because all devices * that support it don't send mgmt frames; * but it might be better to test explicitly d173 2 a174 6 if (!IEEE80211_IS_MULTICAST(eh.ether_dhost) && (ic->ic_caps & IEEE80211_C_RCVMGT)) { IEEE80211_DPRINTF(("%s: no node for dst %s, " "discard frame\n", __func__, ether_sprintf(eh.ether_dhost))); ic->ic_stats.is_tx_nonode++; d192 1 a192 2 if (m == NULL) { ic->ic_stats.is_tx_nombuf++; a193 1 } d304 1 a304 1 #define senderr(_x, _v) do { ic->ic_stats._v++; ret = _x; goto bad; } while (0) d335 1 a335 1 senderr(ENOMEM, is_tx_nombuf); a354 1 * [tlv] parameter set (FH/DS) a361 1 + (ic->ic_phytype == IEEE80211_T_FH ? 7 : 3) d365 1 a365 1 senderr(ENOMEM, is_tx_nombuf); a378 3 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; a385 16 if (ic->ic_phytype == IEEE80211_T_FH) { *frm++ = IEEE80211_ELEMID_FHPARMS; *frm++ = 5; *frm++ = ni->ni_fhdwell & 0x00ff; *frm++ = (ni->ni_fhdwell >> 8) & 0x00ff; *frm++ = IEEE80211_FH_CHANSET( ieee80211_chan2ieee(ic, ni->ni_chan)); *frm++ = IEEE80211_FH_CHANPAT( ieee80211_chan2ieee(ic, ni->ni_chan)); *frm++ = ni->ni_fhindex; } else { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); } d406 1 a406 1 senderr(ENOMEM, is_tx_nombuf); d424 1 a424 1 senderr(ENOMEM, is_tx_nombuf); d449 1 a449 1 senderr(ENOMEM, is_tx_nombuf); d460 1 a460 6 /* * NB: Some 11a AP's reject the request when * short premable is set. */ if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) d500 1 a500 1 senderr(ENOMEM, is_tx_nombuf); a506 3 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; d528 1 a528 1 senderr(ENOMEM, is_tx_nombuf); d537 1 a537 1 senderr(EINVAL, is_tx_unknownmgt); @ 1.1.1.4 log @Import FreeBSD's net80211 of 28-apr-2004 @ text @d34 1 a34 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.10 2004/04/02 23:25:39 sam Exp $"); d164 29 a192 7 ni = ieee80211_find_txnode(ic, eh.ether_dhost); if (ni == NULL) { IEEE80211_DPRINTF(("%s: no node for dst %s, discard frame\n", __func__, ether_sprintf(eh.ether_dhost))); ic->ic_stats.is_tx_nonode++; goto bad; } @ 1.1.1.5 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_output.c,v 1.22 2005/03/26 07:11:31 sam Exp $"); d41 1 d43 2 d46 4 d51 1 a51 1 #include d53 4 a56 1 #include a57 1 #include a58 2 #include #include d62 2 a66 20 #include #include #endif #ifdef IEEE80211_DEBUG /* * Decide if an outbound management frame should be * printed when debugging is enabled. This filters some * of the less interesting frames that come frequently * (e.g. beacons). */ static __inline int doprint(struct ieee80211com *ic, int subtype) { switch (subtype) { case IEEE80211_FC0_SUBTYPE_PROBE_RESP: return (ic->ic_opmode == IEEE80211_M_IBSS); } return 1; } d77 1 a77 1 ieee80211_mgmt_output(struct ieee80211com *ic, struct ieee80211_node *ni, d80 1 a80 1 struct ifnet *ifp = ic->ic_ifp; d84 1 d109 5 a113 19 htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; /* * Hack. When sending PROBE_REQ frames while scanning we * explicitly force a broadcast rather than (as before) clobber * ni_macaddr and ni_bssid. This is stopgap, we need a way * to communicate this directly rather than do something * implicit based on surrounding state. */ if (type == IEEE80211_FC0_SUBTYPE_PROBE_REQ && (ic->ic_flags & IEEE80211_F_SCAN)) { IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); } else { IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); } d115 3 a117 7 if ((m->m_flags & M_LINK0) != 0 && ni->ni_challenge != NULL) { m->m_flags &= ~M_LINK0; IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH, "[%s] encrypting frame (%s)\n", ether_sprintf(wh->i_addr1), __func__); wh->i_fc[1] |= IEEE80211_FC1_WEP; } d119 10 a128 9 /* avoid printing too many frames */ if ((ieee80211_msg_debug(ic) && doprint(ic, type)) || ieee80211_msg_dumppkts(ic)) { printf("[%s] send %s on channel %u\n", ether_sprintf(wh->i_addr1), ieee80211_mgt_subtype_name[ (type & IEEE80211_FC0_SUBTYPE_MASK) >> IEEE80211_FC0_SUBTYPE_SHIFT], ieee80211_chan2ieee(ic, ni->ni_chan)); d130 1 a130 2 #endif IEEE80211_NODE_STAT(ni, tx_mgmt); d133 1 a133 158 if_start(ifp); return 0; } /* * Send a null data frame to the specified node. */ int ieee80211_send_nulldata(struct ieee80211com *ic, struct ieee80211_node *ni) { struct ifnet *ifp = ic->ic_ifp; struct mbuf *m; struct ieee80211_frame *wh; MGETHDR(m, M_NOWAIT, MT_HEADER); if (m == NULL) { /* XXX debug msg */ ic->ic_stats.is_tx_nobuf++; return ENOMEM; } m->m_pkthdr.rcvif = (void *) ieee80211_ref_node(ni); wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA; *(u_int16_t *)wh->i_dur = 0; *(u_int16_t *)wh->i_seq = htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; /* XXX WDS */ wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_myaddr); m->m_len = m->m_pkthdr.len = sizeof(struct ieee80211_frame); IEEE80211_NODE_STAT(ni, tx_data); IF_ENQUEUE(&ic->ic_mgtq, m); /* cheat */ if_start(ifp); return 0; } /* * Assign priority to a frame based on any vlan tag assigned * to the station and/or any Diffserv setting in an IP header. * Finally, if an ACM policy is setup (in station mode) it's * applied. */ int ieee80211_classify(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni) { int v_wme_ac, d_wme_ac, ac; #ifdef INET struct ether_header *eh; #endif if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) { ac = WME_AC_BE; goto done; } /* * If node has a vlan tag then all traffic * to it must have a matching tag. */ v_wme_ac = 0; if (ni->ni_vlan != 0) { struct m_tag *mtag = VLAN_OUTPUT_TAG(ic->ic_ifp, m); if (mtag == NULL) { IEEE80211_NODE_STAT(ni, tx_novlantag); return 1; } if (EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag)) != EVL_VLANOFTAG(ni->ni_vlan)) { IEEE80211_NODE_STAT(ni, tx_vlanmismatch); return 1; } /* map vlan priority to AC */ switch (EVL_PRIOFTAG(ni->ni_vlan)) { case 1: case 2: v_wme_ac = WME_AC_BK; break; case 0: case 3: v_wme_ac = WME_AC_BE; break; case 4: case 5: v_wme_ac = WME_AC_VI; break; case 6: case 7: v_wme_ac = WME_AC_VO; break; } } #ifdef INET eh = mtod(m, struct ether_header *); if (eh->ether_type == htons(ETHERTYPE_IP)) { const struct ip *ip = (struct ip *) (mtod(m, u_int8_t *) + sizeof (*eh)); /* * IP frame, map the TOS field. */ switch (ip->ip_tos) { case 0x08: case 0x20: d_wme_ac = WME_AC_BK; /* background */ break; case 0x28: case 0xa0: d_wme_ac = WME_AC_VI; /* video */ break; case 0x30: /* voice */ case 0xe0: case 0x88: /* XXX UPSD */ case 0xb8: d_wme_ac = WME_AC_VO; break; default: d_wme_ac = WME_AC_BE; break; } } else { #endif /* INET */ d_wme_ac = WME_AC_BE; #ifdef INET } #endif /* * Use highest priority AC. */ if (v_wme_ac > d_wme_ac) ac = v_wme_ac; else ac = d_wme_ac; /* * Apply ACM policy. */ if (ic->ic_opmode == IEEE80211_M_STA) { static const int acmap[4] = { WME_AC_BK, /* WME_AC_BE */ WME_AC_BK, /* WME_AC_BK */ WME_AC_BE, /* WME_AC_VI */ WME_AC_VI, /* WME_AC_VO */ }; while (ac != WME_AC_BK && ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm) ac = acmap[ac]; } done: M_WME_SETAC(m, ac); d138 7 a144 105 * Insure there is sufficient contiguous space to encapsulate the * 802.11 data frame. If room isn't already there, arrange for it. * Drivers and cipher modules assume we have done the necessary work * and fail rudely if they don't find the space they need. */ static struct mbuf * ieee80211_mbuf_adjust(struct ieee80211com *ic, int hdrsize, struct ieee80211_key *key, struct mbuf *m) { #define TO_BE_RECLAIMED (sizeof(struct ether_header) - sizeof(struct llc)) int needed_space = hdrsize; if (key != NULL) { /* XXX belongs in crypto code? */ needed_space += key->wk_cipher->ic_header; /* XXX frags */ } /* * We know we are called just before stripping an Ethernet * header and prepending an LLC header. This means we know * there will be * sizeof(struct ether_header) - sizeof(struct llc) * bytes recovered to which we need additional space for the * 802.11 header and any crypto header. */ /* XXX check trailing space and copy instead? */ if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) { struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type); if (n == NULL) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, "%s: cannot expand storage\n", __func__); ic->ic_stats.is_tx_nobuf++; m_freem(m); return NULL; } KASSERT(needed_space <= MHLEN, ("not enough room, need %u got %zu\n", needed_space, MHLEN)); /* * Setup new mbuf to have leading space to prepend the * 802.11 header and any crypto header bits that are * required (the latter are added when the driver calls * back to ieee80211_crypto_encap to do crypto encapsulation). */ /* NB: must be first 'cuz it clobbers m_data */ m_move_pkthdr(n, m); n->m_len = 0; /* NB: m_gethdr does not set */ n->m_data += needed_space; /* * Pull up Ethernet header to create the expected layout. * We could use m_pullup but that's overkill (i.e. we don't * need the actual data) and it cannot fail so do it inline * for speed. */ /* NB: struct ether_header is known to be contiguous */ n->m_len += sizeof(struct ether_header); m->m_len -= sizeof(struct ether_header); m->m_data += sizeof(struct ether_header); /* * Replace the head of the chain. */ n->m_next = m; m = n; } return m; #undef TO_BE_RECLAIMED } #define KEY_UNDEFINED(k) ((k).wk_cipher == &ieee80211_cipher_none) /* * Return the transmit key to use in sending a unicast frame. * If a unicast key is set we use that. When no unicast key is set * we fall back to the default transmit key. */ static __inline struct ieee80211_key * ieee80211_crypto_getucastkey(struct ieee80211com *ic, struct ieee80211_node *ni) { if (KEY_UNDEFINED(ni->ni_ucastkey)) { if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE || KEY_UNDEFINED(ic->ic_nw_keys[ic->ic_def_txkey])) return NULL; return &ic->ic_nw_keys[ic->ic_def_txkey]; } else { return &ni->ni_ucastkey; } } /* * Return the transmit key to use in sending a multicast frame. * Multicast traffic always uses the group key which is installed as * the default tx key. */ static __inline struct ieee80211_key * ieee80211_crypto_getmcastkey(struct ieee80211com *ic, struct ieee80211_node *ni) { if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE || KEY_UNDEFINED(ic->ic_nw_keys[ic->ic_def_txkey])) return NULL; return &ic->ic_nw_keys[ic->ic_def_txkey]; } /* * Encapsulate an outbound data frame. The mbuf chain is updated. * If an error is encountered NULL is returned. The caller is required * to provide a node reference and pullup the ethernet header in the * first mbuf. d147 1 a147 2 ieee80211_encap(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni) d149 1 d152 1 a152 1 struct ieee80211_key *key; a153 1 int hdrsize, datalen, addqos; d155 7 a161 1 KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!")); d164 5 a168 46 /* * Insure space for additional headers. First identify * transmit key to use in calculating any buffer adjustments * required. This is also used below to do privacy * encapsulation work. Then calculate the 802.11 header * size and any padding required by the driver. * * Note key may be NULL if we fall back to the default * transmit key and that is not set. In that case the * buffer may not be expanded as needed by the cipher * routines, but they will/should discard it. */ if (ic->ic_flags & IEEE80211_F_PRIVACY) { if (ic->ic_opmode == IEEE80211_M_STA || !IEEE80211_IS_MULTICAST(eh.ether_dhost)) key = ieee80211_crypto_getucastkey(ic, ni); else key = ieee80211_crypto_getmcastkey(ic, ni); if (key == NULL && eh.ether_type != htons(ETHERTYPE_PAE)) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, "[%s] no default transmit key (%s) deftxkey %u\n", ether_sprintf(eh.ether_dhost), __func__, ic->ic_def_txkey); ic->ic_stats.is_tx_nodefkey++; } } else key = NULL; /* XXX 4-address format */ /* * XXX Some ap's don't handle QoS-encapsulated EAPOL * frames so suppress use. This may be an issue if other * ap's require all data frames to be QoS-encapsulated * once negotiated in which case we'll need to make this * configurable. */ addqos = (ni->ni_flags & IEEE80211_NODE_QOS) && eh.ether_type != htons(ETHERTYPE_PAE); if (addqos) hdrsize = sizeof(struct ieee80211_qosframe); else hdrsize = sizeof(struct ieee80211_frame); if (ic->ic_flags & IEEE80211_F_DATAPAD) hdrsize = roundup(hdrsize, sizeof(u_int32_t)); m = ieee80211_mbuf_adjust(ic, hdrsize, key, m); if (m == NULL) { /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ d171 1 a172 1 /* NB: this could be optimized because of ieee80211_mbuf_adjust */ d181 1 a181 3 datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */ M_PREPEND(m, hdrsize, M_DONTWAIT); d183 1 a183 1 ic->ic_stats.is_tx_nobuf++; d189 3 d204 1 a204 5 /* * NB: always use the bssid from ic_bss as the * neighbor's may be stale after an ibss merge */ IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid); d215 1 a215 46 if (addqos) { struct ieee80211_qosframe *qwh = (struct ieee80211_qosframe *) wh; int ac, tid; ac = M_WME_GETAC(m); /* map from access class/queue to 11e header priorty value */ tid = WME_AC_TO_TID(ac); qwh->i_qos[0] = tid & IEEE80211_QOS_TID; if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy) qwh->i_qos[0] |= 1 << IEEE80211_QOS_ACKPOLICY_S; qwh->i_qos[1] = 0; qwh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; *(u_int16_t *)wh->i_seq = htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[tid]++; } else { *(u_int16_t *)wh->i_seq = htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; } if (key != NULL) { /* * IEEE 802.1X: send EAPOL frames always in the clear. * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. */ if (eh.ether_type != htons(ETHERTYPE_PAE) || ((ic->ic_flags & IEEE80211_F_WPA) && (ic->ic_opmode == IEEE80211_M_STA ? !KEY_UNDEFINED(*key) : !KEY_UNDEFINED(ni->ni_ucastkey)))) { wh->i_fc[1] |= IEEE80211_FC1_WEP; /* XXX do fragmentation */ if (!ieee80211_crypto_enmic(ic, key, m)) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, "[%s] enmic failed, discard frame\n", ether_sprintf(eh.ether_dhost)); ic->ic_stats.is_crypto_enmicfail++; goto bad; } } } IEEE80211_NODE_STAT(ni, tx_data); IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen); d220 3 d229 1 a229 1 static u_int8_t * d246 1 a246 1 static u_int8_t * d274 2 a275 5 /* * Add an erp element to a frame. */ static u_int8_t * ieee80211_add_erp(u_int8_t *frm, struct ieee80211com *ic) d277 1 a277 1 u_int8_t erp; d279 3 a281 57 *frm++ = IEEE80211_ELEMID_ERP; *frm++ = 1; erp = 0; if (ic->ic_nonerpsta != 0) erp |= IEEE80211_ERP_NON_ERP_PRESENT; if (ic->ic_flags & IEEE80211_F_USEPROT) erp |= IEEE80211_ERP_USE_PROTECTION; if (ic->ic_flags & IEEE80211_F_USEBARKER) erp |= IEEE80211_ERP_LONG_PREAMBLE; *frm++ = erp; return frm; } static u_int8_t * ieee80211_setup_wpa_ie(struct ieee80211com *ic, u_int8_t *ie) { #define WPA_OUI_BYTES 0x00, 0x50, 0xf2 #define ADDSHORT(frm, v) do { \ frm[0] = (v) & 0xff; \ frm[1] = (v) >> 8; \ frm += 2; \ } while (0) #define ADDSELECTOR(frm, sel) do { \ memcpy(frm, sel, 4); \ frm += 4; \ } while (0) static const u_int8_t oui[4] = { WPA_OUI_BYTES, WPA_OUI_TYPE }; static const u_int8_t cipher_suite[][4] = { { WPA_OUI_BYTES, WPA_CSE_WEP40 }, /* NB: 40-bit */ { WPA_OUI_BYTES, WPA_CSE_TKIP }, { 0x00, 0x00, 0x00, 0x00 }, /* XXX WRAP */ { WPA_OUI_BYTES, WPA_CSE_CCMP }, { 0x00, 0x00, 0x00, 0x00 }, /* XXX CKIP */ { WPA_OUI_BYTES, WPA_CSE_NULL }, }; static const u_int8_t wep104_suite[4] = { WPA_OUI_BYTES, WPA_CSE_WEP104 }; static const u_int8_t key_mgt_unspec[4] = { WPA_OUI_BYTES, WPA_ASE_8021X_UNSPEC }; static const u_int8_t key_mgt_psk[4] = { WPA_OUI_BYTES, WPA_ASE_8021X_PSK }; const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn; u_int8_t *frm = ie; u_int8_t *selcnt; *frm++ = IEEE80211_ELEMID_VENDOR; *frm++ = 0; /* length filled in below */ memcpy(frm, oui, sizeof(oui)); /* WPA OUI */ frm += sizeof(oui); ADDSHORT(frm, WPA_VERSION); /* XXX filter out CKIP */ /* multicast cipher */ if (rsn->rsn_mcastcipher == IEEE80211_CIPHER_WEP && rsn->rsn_mcastkeylen >= 13) ADDSELECTOR(frm, wep104_suite); d283 2 a284 39 ADDSELECTOR(frm, cipher_suite[rsn->rsn_mcastcipher]); /* unicast cipher list */ selcnt = frm; ADDSHORT(frm, 0); /* selector count */ if (rsn->rsn_ucastcipherset & (1<rsn_ucastcipherset & (1<rsn_keymgmtset & WPA_ASE_8021X_UNSPEC) { selcnt[0]++; ADDSELECTOR(frm, key_mgt_unspec); } if (rsn->rsn_keymgmtset & WPA_ASE_8021X_PSK) { selcnt[0]++; ADDSELECTOR(frm, key_mgt_psk); } /* optional capabilities */ if (rsn->rsn_caps != 0) ADDSHORT(frm, rsn->rsn_caps); /* calculate element length */ ie[1] = frm - ie - 2; KASSERT(ie[1]+2 <= sizeof(struct ieee80211_ie_wpa), ("WPA IE too big, %u > %zu", ie[1]+2, sizeof(struct ieee80211_ie_wpa))); return frm; #undef ADDSHORT #undef ADDSELECTOR #undef WPA_OUI_BYTES a286 164 static u_int8_t * ieee80211_setup_rsn_ie(struct ieee80211com *ic, u_int8_t *ie) { #define RSN_OUI_BYTES 0x00, 0x0f, 0xac #define ADDSHORT(frm, v) do { \ frm[0] = (v) & 0xff; \ frm[1] = (v) >> 8; \ frm += 2; \ } while (0) #define ADDSELECTOR(frm, sel) do { \ memcpy(frm, sel, 4); \ frm += 4; \ } while (0) static const u_int8_t cipher_suite[][4] = { { RSN_OUI_BYTES, RSN_CSE_WEP40 }, /* NB: 40-bit */ { RSN_OUI_BYTES, RSN_CSE_TKIP }, { RSN_OUI_BYTES, RSN_CSE_WRAP }, { RSN_OUI_BYTES, RSN_CSE_CCMP }, { 0x00, 0x00, 0x00, 0x00 }, /* XXX CKIP */ { RSN_OUI_BYTES, RSN_CSE_NULL }, }; static const u_int8_t wep104_suite[4] = { RSN_OUI_BYTES, RSN_CSE_WEP104 }; static const u_int8_t key_mgt_unspec[4] = { RSN_OUI_BYTES, RSN_ASE_8021X_UNSPEC }; static const u_int8_t key_mgt_psk[4] = { RSN_OUI_BYTES, RSN_ASE_8021X_PSK }; const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn; u_int8_t *frm = ie; u_int8_t *selcnt; *frm++ = IEEE80211_ELEMID_RSN; *frm++ = 0; /* length filled in below */ ADDSHORT(frm, RSN_VERSION); /* XXX filter out CKIP */ /* multicast cipher */ if (rsn->rsn_mcastcipher == IEEE80211_CIPHER_WEP && rsn->rsn_mcastkeylen >= 13) ADDSELECTOR(frm, wep104_suite); else ADDSELECTOR(frm, cipher_suite[rsn->rsn_mcastcipher]); /* unicast cipher list */ selcnt = frm; ADDSHORT(frm, 0); /* selector count */ if (rsn->rsn_ucastcipherset & (1<rsn_ucastcipherset & (1<rsn_keymgmtset & WPA_ASE_8021X_UNSPEC) { selcnt[0]++; ADDSELECTOR(frm, key_mgt_unspec); } if (rsn->rsn_keymgmtset & WPA_ASE_8021X_PSK) { selcnt[0]++; ADDSELECTOR(frm, key_mgt_psk); } /* optional capabilities */ if (rsn->rsn_caps != 0) ADDSHORT(frm, rsn->rsn_caps); /* XXX PMKID */ /* calculate element length */ ie[1] = frm - ie - 2; KASSERT(ie[1]+2 <= sizeof(struct ieee80211_ie_wpa), ("RSN IE too big, %u > %zu", ie[1]+2, sizeof(struct ieee80211_ie_wpa))); return frm; #undef ADDSELECTOR #undef ADDSHORT #undef RSN_OUI_BYTES } /* * Add a WPA/RSN element to a frame. */ static u_int8_t * ieee80211_add_wpa(u_int8_t *frm, struct ieee80211com *ic) { KASSERT(ic->ic_flags & IEEE80211_F_WPA, ("no WPA/RSN!")); if (ic->ic_flags & IEEE80211_F_WPA2) frm = ieee80211_setup_rsn_ie(ic, frm); if (ic->ic_flags & IEEE80211_F_WPA1) frm = ieee80211_setup_wpa_ie(ic, frm); return frm; } #define WME_OUI_BYTES 0x00, 0x50, 0xf2 /* * Add a WME information element to a frame. */ static u_int8_t * ieee80211_add_wme_info(u_int8_t *frm, struct ieee80211_wme_state *wme) { static const struct ieee80211_wme_info info = { .wme_id = IEEE80211_ELEMID_VENDOR, .wme_len = sizeof(struct ieee80211_wme_info) - 2, .wme_oui = { WME_OUI_BYTES }, .wme_type = WME_OUI_TYPE, .wme_subtype = WME_INFO_OUI_SUBTYPE, .wme_version = WME_VERSION, .wme_info = 0, }; memcpy(frm, &info, sizeof(info)); return frm + sizeof(info); } /* * Add a WME parameters element to a frame. */ static u_int8_t * ieee80211_add_wme_param(u_int8_t *frm, struct ieee80211_wme_state *wme) { #define SM(_v, _f) (((_v) << _f##_S) & _f) #define ADDSHORT(frm, v) do { \ frm[0] = (v) & 0xff; \ frm[1] = (v) >> 8; \ frm += 2; \ } while (0) /* NB: this works 'cuz a param has an info at the front */ static const struct ieee80211_wme_info param = { .wme_id = IEEE80211_ELEMID_VENDOR, .wme_len = sizeof(struct ieee80211_wme_param) - 2, .wme_oui = { WME_OUI_BYTES }, .wme_type = WME_OUI_TYPE, .wme_subtype = WME_PARAM_OUI_SUBTYPE, .wme_version = WME_VERSION, }; int i; memcpy(frm, ¶m, sizeof(param)); frm += __offsetof(struct ieee80211_wme_info, wme_info); *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */ *frm++ = 0; /* reserved field */ for (i = 0; i < WME_NUM_AC; i++) { const struct wmeParams *ac = &wme->wme_bssChanParams.cap_wmeParams[i]; *frm++ = SM(i, WME_PARAM_ACI) | SM(ac->wmep_acm, WME_PARAM_ACM) | SM(ac->wmep_aifsn, WME_PARAM_AIFSN) ; *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN) ; ADDSHORT(frm, ac->wmep_txopLimit); } return frm; #undef SM #undef ADDSHORT } #undef WME_OUI_BYTES d297 1 d302 1 a302 1 int has_challenge, is_shared_key, ret, timer, status; d311 2 a312 7 IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1); ieee80211_ref_node(ni); a320 1 * [tlv] user-specified ie's d322 2 a323 2 m = ieee80211_getmgtframe(&frm, 2 + IEEE80211_NWID_LEN d325 1 a325 3 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + (ic->ic_opt_ie != NULL ? ic->ic_opt_ie_len : 0) ); d327 3 a329 2 senderr(ENOMEM, is_tx_nobuf); a333 4 if (ic->ic_opt_ie != NULL) { memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len); frm += ic->ic_opt_ie_len; } d336 1 a336 3 IEEE80211_NODE_STAT(ni, tx_probereq); if (ic->ic_opmode == IEEE80211_M_STA) timer = IEEE80211_TRANS_WAIT; a348 1 * [tlv] extended rate phy (ERP) a349 2 * [tlv] WPA * [tlv] WME (optional) d351 3 a353 5 m = ieee80211_getmgtframe(&frm, 8 + sizeof(u_int16_t) + sizeof(u_int16_t) + 2 + IEEE80211_NWID_LEN d355 1 a355 1 + 7 /* max(7,3) */ d357 1 a357 7 + 3 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) /* XXX !WPA1+WPA2 fits w/o a cluster */ + (ic->ic_flags & IEEE80211_F_WPA ? 2*sizeof(struct ieee80211_ie_wpa) : 0) + sizeof(struct ieee80211_wme_param) ); d359 3 a361 1 senderr(ENOMEM, is_tx_nobuf); d371 1 a371 1 if (ic->ic_flags & IEEE80211_F_PRIVACY) a375 2 if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; d381 1 a381 1 frm = ieee80211_add_rates(frm, &ni->ni_rates); d403 8 d412 1 a412 7 if (ic->ic_flags & IEEE80211_F_WPA) frm = ieee80211_add_wpa(frm, ic); if (ic->ic_curmode == IEEE80211_MODE_11G) frm = ieee80211_add_erp(frm, ic); frm = ieee80211_add_xrates(frm, &ni->ni_rates); if (ic->ic_flags & IEEE80211_F_WME) frm = ieee80211_add_wme_param(frm, &ic->ic_wme); d417 1 a417 23 status = arg >> 16; arg &= 0xffff; has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || arg == IEEE80211_AUTH_SHARED_RESPONSE) && ni->ni_challenge != NULL); /* * Deduce whether we're doing open authentication or * shared key authentication. We do the latter if * we're in the middle of a shared key authentication * handshake or if we're initiating an authentication * request and configured to use shared key. */ is_shared_key = has_challenge || arg >= IEEE80211_AUTH_SHARED_RESPONSE || (arg == IEEE80211_AUTH_SHARED_REQUEST && ic->ic_bss->ni_authmode == IEEE80211_AUTH_SHARED); m = ieee80211_getmgtframe(&frm, 3 * sizeof(u_int16_t) + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? sizeof(u_int16_t)+IEEE80211_CHALLENGE_LEN : 0) ); d419 6 a424 5 senderr(ENOMEM, is_tx_nobuf); ((u_int16_t *)frm)[0] = (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED) : htole16(IEEE80211_AUTH_ALG_OPEN); d426 1 a426 33 ((u_int16_t *)frm)[2] = htole16(status);/* status */ if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { ((u_int16_t *)frm)[3] = htole16((IEEE80211_CHALLENGE_LEN << 8) | IEEE80211_ELEMID_CHALLENGE); memcpy(&((u_int16_t *)frm)[4], ni->ni_challenge, IEEE80211_CHALLENGE_LEN); m->m_pkthdr.len = m->m_len = 4 * sizeof(u_int16_t) + IEEE80211_CHALLENGE_LEN; if (arg == IEEE80211_AUTH_SHARED_RESPONSE) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH, "[%s] request encrypt frame (%s)\n", ether_sprintf(ni->ni_macaddr), __func__); m->m_flags |= M_LINK0; /* WEP-encrypt, please */ } } else m->m_pkthdr.len = m->m_len = 3 * sizeof(u_int16_t); /* XXX not right for shared key */ if (status == IEEE80211_STATUS_SUCCESS) IEEE80211_NODE_STAT(ni, tx_auth); else IEEE80211_NODE_STAT(ni, tx_auth_fail); /* * When 802.1x is not in use mark the port * authorized at this point so traffic can flow. */ if (ic->ic_opmode == IEEE80211_M_HOSTAP && status == IEEE80211_STATUS_SUCCESS && ni->ni_authmode != IEEE80211_AUTH_8021X) ieee80211_node_authorize(ic, ni); d432 4 a435 4 IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH, "[%s] send station deauthenticate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg); m = ieee80211_getmgtframe(&frm, sizeof(u_int16_t)); d437 4 a440 8 senderr(ENOMEM, is_tx_nobuf); *(u_int16_t *)frm = htole16(arg); /* reason */ m->m_pkthdr.len = m->m_len = sizeof(u_int16_t); IEEE80211_NODE_STAT(ni, tx_deauth); IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg); ieee80211_node_unauthorize(ic, ni); /* port closed */ a452 2 * [tlv] WME * [tlv] user-specified ie's d454 2 a455 2 m = ieee80211_getmgtframe(&frm, sizeof(u_int16_t) d458 1 a458 1 + 2 + IEEE80211_NWID_LEN d460 1 a460 4 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + sizeof(struct ieee80211_wme_info) + (ic->ic_opt_ie != NULL ? ic->ic_opt_ie_len : 0) ); d462 3 a464 1 senderr(ENOMEM, is_tx_nobuf); d471 1 a471 1 if (ic->ic_flags & IEEE80211_F_PRIVACY) d480 1 a480 2 if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) && (ic->ic_caps & IEEE80211_C_SHSLOT)) a495 6 if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL) frm = ieee80211_add_wme_info(frm, &ic->ic_wme); if (ic->ic_opt_ie != NULL) { memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len); frm += ic->ic_opt_ie_len; } a509 1 * [tlv] WME (if enabled and STA enabled) d511 2 a512 2 m = ieee80211_getmgtframe(&frm, sizeof(u_int16_t) d516 1 a516 3 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + sizeof(struct ieee80211_wme_param) ); d518 3 a520 1 senderr(ENOMEM, is_tx_nobuf); d523 1 a523 1 if (ic->ic_flags & IEEE80211_F_PRIVACY) a527 2 if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; d534 1 a534 1 if (arg == IEEE80211_STATUS_SUCCESS) { a535 3 IEEE80211_NODE_STAT(ni, tx_assoc); } else IEEE80211_NODE_STAT(ni, tx_assoc_fail); a539 2 if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL) frm = ieee80211_add_wme_param(frm, &ic->ic_wme); d544 4 a547 4 IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, "[%s] send station disassociate (reason %d)\n", ether_sprintf(ni->ni_macaddr), arg); m = ieee80211_getmgtframe(&frm, sizeof(u_int16_t)); d549 4 a552 6 senderr(ENOMEM, is_tx_nobuf); *(u_int16_t *)frm = htole16(arg); /* reason */ m->m_pkthdr.len = m->m_len = sizeof(u_int16_t); IEEE80211_NODE_STAT(ni, tx_disassoc); IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg); d556 2 a557 3 IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, "[%s] invalid mgmt frame type %u\n", ether_sprintf(ni->ni_macaddr), type); d562 1 a562 1 ret = ieee80211_mgmt_output(ic, ni, m, type); d568 2 a569 1 ieee80211_free_node(ni); a573 319 /* * Allocate a beacon frame and fillin the appropriate bits. */ struct mbuf * ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo) { struct ifnet *ifp = ic->ic_ifp; struct ieee80211_frame *wh; struct mbuf *m; int pktlen; u_int8_t *frm, *efrm; u_int16_t capinfo; struct ieee80211_rateset *rs; /* * beacon frame format * [8] time stamp * [2] beacon interval * [2] cabability information * [tlv] ssid * [tlv] supported rates * [3] parameter set (DS) * [tlv] parameter set (IBSS/TIM) * [tlv] extended rate phy (ERP) * [tlv] extended supported rates * [tlv] WME parameters * [tlv] WPA/RSN parameters * XXX Vendor-specific OIDs (e.g. Atheros) * NB: we allocate the max space required for the TIM bitmap. */ rs = &ni->ni_rates; pktlen = 8 /* time stamp */ + sizeof(u_int16_t) /* beacon interval */ + sizeof(u_int16_t) /* capabilities */ + 2 + ni->ni_esslen /* ssid */ + 2 + IEEE80211_RATE_SIZE /* supported rates */ + 2 + 1 /* DS parameters */ + 2 + 4 + ic->ic_tim_len /* DTIM/IBSSPARMS */ + 2 + 1 /* ERP */ + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + (ic->ic_caps & IEEE80211_C_WME ? /* WME */ sizeof(struct ieee80211_wme_param) : 0) + (ic->ic_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ 2*sizeof(struct ieee80211_ie_wpa) : 0) ; m = ieee80211_getmgtframe(&frm, pktlen); if (m == NULL) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, "%s: cannot get buf; size %u\n", __func__, pktlen); ic->ic_stats.is_tx_nobuf++; return NULL; } memset(frm, 0, 8); /* XXX timestamp is set by hardware/driver */ frm += 8; *(u_int16_t *)frm = htole16(ni->ni_intval); frm += 2; if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; bo->bo_caps = (u_int16_t *)frm; *(u_int16_t *)frm = htole16(capinfo); frm += 2; *frm++ = IEEE80211_ELEMID_SSID; if ((ic->ic_flags & IEEE80211_F_HIDESSID) == 0) { *frm++ = ni->ni_esslen; memcpy(frm, ni->ni_essid, ni->ni_esslen); frm += ni->ni_esslen; } else *frm++ = 0; frm = ieee80211_add_rates(frm, rs); if (ic->ic_curmode != IEEE80211_MODE_FH) { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); } bo->bo_tim = frm; if (ic->ic_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ bo->bo_tim_len = 0; } else { struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; tie->tim_ie = IEEE80211_ELEMID_TIM; tie->tim_len = 4; /* length */ tie->tim_count = 0; /* DTIM count */ tie->tim_period = ic->ic_dtim_period; /* DTIM period */ tie->tim_bitctl = 0; /* bitmap control */ tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ frm += sizeof(struct ieee80211_tim_ie); bo->bo_tim_len = 1; } bo->bo_trailer = frm; if (ic->ic_flags & IEEE80211_F_WME) { bo->bo_wme = frm; frm = ieee80211_add_wme_param(frm, &ic->ic_wme); ic->ic_flags &= ~IEEE80211_F_WMEUPDATE; } if (ic->ic_flags & IEEE80211_F_WPA) frm = ieee80211_add_wpa(frm, ic); if (ic->ic_curmode == IEEE80211_MODE_11G) frm = ieee80211_add_erp(frm, ic); efrm = ieee80211_add_xrates(frm, rs); bo->bo_trailer_len = efrm - bo->bo_trailer; m->m_pkthdr.len = m->m_len = efrm - mtod(m, u_int8_t *); M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); KASSERT(m != NULL, ("no space for 802.11 header?")); wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_BEACON; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(u_int16_t *)wh->i_dur = 0; IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); *(u_int16_t *)wh->i_seq = 0; return m; } /* * Update the dynamic parts of a beacon frame based on the current state. */ int ieee80211_beacon_update(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) { int len_changed = 0; u_int16_t capinfo; IEEE80211_BEACON_LOCK(ic); /* XXX faster to recalculate entirely or just changes? */ if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; *bo->bo_caps = htole16(capinfo); if (ic->ic_flags & IEEE80211_F_WME) { struct ieee80211_wme_state *wme = &ic->ic_wme; /* * Check for agressive mode change. When there is * significant high priority traffic in the BSS * throttle back BE traffic by using conservative * parameters. Otherwise BE uses agressive params * to optimize performance of legacy/non-QoS traffic. */ if (wme->wme_flags & WME_F_AGGRMODE) { if (wme->wme_hipri_traffic > wme->wme_hipri_switch_thresh) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, "%s: traffic %u, disable aggressive mode\n", __func__, wme->wme_hipri_traffic); wme->wme_flags &= ~WME_F_AGGRMODE; ieee80211_wme_updateparams_locked(ic); wme->wme_hipri_traffic = wme->wme_hipri_switch_hysteresis; } else wme->wme_hipri_traffic = 0; } else { if (wme->wme_hipri_traffic <= wme->wme_hipri_switch_thresh) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, "%s: traffic %u, enable aggressive mode\n", __func__, wme->wme_hipri_traffic); wme->wme_flags |= WME_F_AGGRMODE; ieee80211_wme_updateparams_locked(ic); wme->wme_hipri_traffic = 0; } else wme->wme_hipri_traffic = wme->wme_hipri_switch_hysteresis; } if (ic->ic_flags & IEEE80211_F_WMEUPDATE) { (void) ieee80211_add_wme_param(bo->bo_wme, wme); ic->ic_flags &= ~IEEE80211_F_WMEUPDATE; } } if (ic->ic_opmode == IEEE80211_M_HOSTAP) { /* NB: no IBSS support*/ struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) bo->bo_tim; if (ic->ic_flags & IEEE80211_F_TIMUPDATE) { u_int timlen, timoff, i; /* * ATIM/DTIM needs updating. If it fits in the * current space allocated then just copy in the * new bits. Otherwise we need to move any trailing * data to make room. Note that we know there is * contiguous space because ieee80211_beacon_allocate * insures there is space in the mbuf to write a * maximal-size virtual bitmap (based on ic_max_aid). */ /* * Calculate the bitmap size and offset, copy any * trailer out of the way, and then copy in the * new bitmap and update the information element. * Note that the tim bitmap must contain at least * one byte and any offset must be even. */ if (ic->ic_ps_pending != 0) { timoff = 128; /* impossibly large */ for (i = 0; i < ic->ic_tim_len; i++) if (ic->ic_tim_bitmap[i]) { timoff = i &~ 1; break; } KASSERT(timoff != 128, ("tim bitmap empty!")); for (i = ic->ic_tim_len-1; i >= timoff; i--) if (ic->ic_tim_bitmap[i]) break; timlen = 1 + (i - timoff); } else { timoff = 0; timlen = 1; } if (timlen != bo->bo_tim_len) { /* copy up/down trailer */ ovbcopy(bo->bo_trailer, tie->tim_bitmap+timlen, bo->bo_trailer_len); bo->bo_trailer = tie->tim_bitmap+timlen; bo->bo_wme = bo->bo_trailer; bo->bo_tim_len = timlen; /* update information element */ tie->tim_len = 3 + timlen; tie->tim_bitctl = timoff; len_changed = 1; } memcpy(tie->tim_bitmap, ic->ic_tim_bitmap + timoff, bo->bo_tim_len); ic->ic_flags &= ~IEEE80211_F_TIMUPDATE; IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, "%s: TIM updated, pending %u, off %u, len %u\n", __func__, ic->ic_ps_pending, timoff, timlen); } /* count down DTIM period */ if (tie->tim_count == 0) tie->tim_count = tie->tim_period - 1; else tie->tim_count--; /* update state for buffered multicast frames on DTIM */ if (mcast && (tie->tim_count == 1 || tie->tim_period == 1)) tie->tim_bitctl |= 1; else tie->tim_bitctl &= ~1; } IEEE80211_BEACON_UNLOCK(ic); return len_changed; } /* * Save an outbound packet for a node in power-save sleep state. * The new packet is placed on the node's saved queue, and the TIM * is changed, if necessary. */ void ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni, struct mbuf *m) { int qlen, age; IEEE80211_NODE_SAVEQ_LOCK(ni); if (_IF_QFULL(&ni->ni_savedq)) { _IF_DROP(&ni->ni_savedq); IEEE80211_NODE_SAVEQ_UNLOCK(ni); IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, "[%s] pwr save q overflow, drops %d (size %d)\n", ether_sprintf(ni->ni_macaddr), ni->ni_savedq.ifq_drops, IEEE80211_PS_MAX_QUEUE); #ifdef IEEE80211_DEBUG if (ieee80211_msg_dumppkts(ic)) ieee80211_dump_pkt(mtod(m, caddr_t), m->m_len, -1, -1); #endif m_freem(m); return; } /* * Tag the frame with it's expiry time and insert * it in the queue. The aging interval is 4 times * the listen interval specified by the station. * Frames that sit around too long are reclaimed * using this information. */ /* XXX handle overflow? */ age = ((ni->ni_intval * ic->ic_lintval) << 2) / 1024; /* TU -> secs */ _IEEE80211_NODE_SAVEQ_ENQUEUE(ni, m, qlen, age); IEEE80211_NODE_SAVEQ_UNLOCK(ni); IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, "[%s] save frame, %u now queued\n", ether_sprintf(ni->ni_macaddr), qlen); if (qlen == 1) ic->ic_set_tim(ic, ni, 1); } @ 1.1.1.6 log @Import FreeBSD's net80211(9) of 2005-07-11 @ text @d34 1 a34 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.26 2005/07/06 01:55:17 sam Exp $"); a536 2 if (m->m_flags & M_MORE_DATA) wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; d570 1 a570 1 if (!ieee80211_crypto_enmic(ic, key, m, 0)) { d731 1 a731 1 if (rsn->rsn_caps != 0 && rsn->rsn_caps != RSN_CAP_PREAUTH) d814 2 a815 1 ADDSHORT(frm, rsn->rsn_caps); d1115 8 @ 1.1.1.7 log @Import FreeBSD's net80211(9) of 1-nov-2005 @ text @d34 1 a34 1 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.34 2005/08/10 16:22:29 sam Exp $"); a80 56 * Set the direction field and address fields of an outgoing * non-QoS frame. Note this should be called early on in * constructing a frame as it sets i_fc[1]; other bits can * then be or'd in. */ static void ieee80211_send_setup(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_frame *wh, int type, const u_int8_t sa[IEEE80211_ADDR_LEN], const u_int8_t da[IEEE80211_ADDR_LEN], const u_int8_t bssid[IEEE80211_ADDR_LEN]) { #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { switch (ic->ic_opmode) { case IEEE80211_M_STA: wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; IEEE80211_ADDR_COPY(wh->i_addr1, bssid); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, da); break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, bssid); break; case IEEE80211_M_HOSTAP: wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, bssid); IEEE80211_ADDR_COPY(wh->i_addr3, sa); break; case IEEE80211_M_MONITOR: /* NB: to quiet compiler */ break; } } else { wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, da); IEEE80211_ADDR_COPY(wh->i_addr2, sa); IEEE80211_ADDR_COPY(wh->i_addr3, bssid); } *(u_int16_t *)&wh->i_dur[0] = 0; /* NB: use non-QoS tid */ *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[0]++; #undef WH4 } /* d115 24 a138 3 ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_MGT | type, ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid); d155 1 a155 1 ieee80211_chan2ieee(ic, ic->ic_curchan)); a166 4 * * NB: the caller is assumed to have setup a node reference * for use; this is necessary to deal with a race condition * when probing for inactive stations. d169 1 a169 1 ieee80211_send_nulldata(struct ieee80211_node *ni) a170 1 struct ieee80211com *ic = ni->ni_ic; a178 1 ieee80211_unref_node(&ni); d181 1 a181 1 m->m_pkthdr.rcvif = (void *) ni; d184 12 a195 7 ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid); /* NB: power management bit is never sent by an AP */ if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && ic->ic_opmode != IEEE80211_M_HOSTAP) wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; a199 6 IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "[%s] send null data frame on channel %u, pwr mgt %s\n", ether_sprintf(ni->ni_macaddr), ieee80211_chan2ieee(ic, ic->ic_curchan), wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); a910 85 * Send a probe request frame with the specified ssid * and any optional information element data. */ int ieee80211_send_probereq(struct ieee80211_node *ni, const u_int8_t sa[IEEE80211_ADDR_LEN], const u_int8_t da[IEEE80211_ADDR_LEN], const u_int8_t bssid[IEEE80211_ADDR_LEN], const u_int8_t *ssid, size_t ssidlen, const void *optie, size_t optielen) { struct ieee80211com *ic = ni->ni_ic; enum ieee80211_phymode mode; struct ieee80211_frame *wh; struct mbuf *m; u_int8_t *frm; /* * Hold a reference on the node so it doesn't go away until after * the xmit is complete all the way in the driver. On error we * will remove our reference. */ IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1); ieee80211_ref_node(ni); /* * prreq frame format * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates * [tlv] user-specified ie's */ m = ieee80211_getmgtframe(&frm, 2 + IEEE80211_NWID_LEN + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + (optie != NULL ? optielen : 0) ); if (m == NULL) { ic->ic_stats.is_tx_nobuf++; ieee80211_free_node(ni); return ENOMEM; } frm = ieee80211_add_ssid(frm, ssid, ssidlen); mode = ieee80211_chan2mode(ic, ic->ic_curchan); frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); if (optie != NULL) { memcpy(frm, optie, optielen); frm += optielen; } m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); if (m == NULL) return ENOMEM; KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null")); m->m_pkthdr.rcvif = (void *)ni; wh = mtod(m, struct ieee80211_frame *); ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, sa, da, bssid); /* XXX power management? */ IEEE80211_NODE_STAT(ni, tx_probereq); IEEE80211_NODE_STAT(ni, tx_mgmt); IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "[%s] send probe req on channel %u\n", ether_sprintf(wh->i_addr1), ieee80211_chan2ieee(ic, ic->ic_curchan)); IF_ENQUEUE(&ic->ic_mgtq, m); if_start(ic->ic_ifp); return 0; } /* d922 1 d942 32 d1018 1 a1018 1 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) d1035 1 a1035 1 ieee80211_chan2ieee(ic, ic->ic_curchan)); d1037 1 a1037 1 ieee80211_chan2ieee(ic, ic->ic_curchan)); d1042 1 a1042 1 *frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan); d1133 1 a1133 1 ieee80211_node_unauthorize(ni); /* port closed */ d1174 1 a1174 1 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) d1230 1 a1230 1 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) d1595 1 a1595 1 age = ((ni->ni_intval * ic->ic_bintval) << 2) / 1024; /* TU -> secs */ d1600 2 a1601 2 "[%s] save frame with age %d, %u now queued\n", ether_sprintf(ni->ni_macaddr), age, qlen); d1604 1 a1604 1 ic->ic_set_tim(ni, 1); @