head 1.19; access; symbols netbsd-10-0-RC6:1.19 netbsd-10-0-RC5:1.19 netbsd-10-0-RC4:1.19 netbsd-10-0-RC3:1.19 netbsd-10-0-RC2:1.19 thorpej-ifq:1.19.0.50 thorpej-ifq-base:1.19 thorpej-altq-separation:1.19.0.48 thorpej-altq-separation-base:1.19 netbsd-10-0-RC1:1.19 netbsd-10:1.19.0.46 netbsd-10-base:1.19 bouyer-sunxi-drm:1.19.0.44 bouyer-sunxi-drm-base:1.19 netbsd-9-3-RELEASE:1.19 thorpej-i2c-spi-conf2:1.19.0.42 thorpej-i2c-spi-conf2-base:1.19 thorpej-futex2:1.19.0.40 thorpej-futex2-base:1.19 thorpej-cfargs2:1.19.0.38 thorpej-cfargs2-base:1.19 cjep_sun2x-base1:1.19 cjep_sun2x:1.19.0.36 cjep_sun2x-base:1.19 cjep_staticlib_x-base1:1.19 netbsd-9-2-RELEASE:1.19 cjep_staticlib_x:1.19.0.34 cjep_staticlib_x-base:1.19 thorpej-i2c-spi-conf:1.19.0.32 thorpej-i2c-spi-conf-base:1.19 thorpej-cfargs:1.19.0.30 thorpej-cfargs-base:1.19 thorpej-futex:1.19.0.28 thorpej-futex-base:1.19 netbsd-9-1-RELEASE:1.19 bouyer-xenpvh-base2:1.19 phil-wifi-20200421:1.19 bouyer-xenpvh-base1:1.19 phil-wifi-20200411:1.19 bouyer-xenpvh:1.19.0.26 bouyer-xenpvh-base:1.19 is-mlppp:1.19.0.24 is-mlppp-base:1.19 phil-wifi-20200406:1.19 netbsd-8-2-RELEASE:1.19 ad-namecache-base3:1.19 netbsd-9-0-RELEASE:1.19 netbsd-9-0-RC2:1.19 ad-namecache-base2:1.19 ad-namecache-base1:1.19 ad-namecache:1.19.0.22 ad-namecache-base:1.19 netbsd-9-0-RC1:1.19 phil-wifi-20191119:1.19 netbsd-9:1.19.0.20 netbsd-9-base:1.19 phil-wifi-20190609:1.19 netbsd-8-1-RELEASE:1.19 netbsd-8-1-RC1:1.19 isaki-audio2:1.19.0.18 isaki-audio2-base:1.19 pgoyette-compat-merge-20190127:1.19 pgoyette-compat-20190127:1.19 pgoyette-compat-20190118:1.19 pgoyette-compat-1226:1.19 pgoyette-compat-1126:1.19 pgoyette-compat-1020:1.19 pgoyette-compat-0930:1.19 pgoyette-compat-0906:1.19 netbsd-7-2-RELEASE:1.18 pgoyette-compat-0728:1.19 netbsd-8-0-RELEASE:1.19 phil-wifi:1.19.0.16 phil-wifi-base:1.19 pgoyette-compat-0625:1.19 netbsd-8-0-RC2:1.19 pgoyette-compat-0521:1.19 pgoyette-compat-0502:1.19 pgoyette-compat-0422:1.19 netbsd-8-0-RC1:1.19 pgoyette-compat-0415:1.19 pgoyette-compat-0407:1.19 pgoyette-compat-0330:1.19 pgoyette-compat-0322:1.19 pgoyette-compat-0315:1.19 netbsd-7-1-2-RELEASE:1.18 pgoyette-compat:1.19.0.14 pgoyette-compat-base:1.19 netbsd-7-1-1-RELEASE:1.18 tls-maxphys-base-20171202:1.19 matt-nb8-mediatek:1.19.0.12 matt-nb8-mediatek-base:1.19 nick-nhusb-base-20170825:1.19 perseant-stdc-iso10646:1.19.0.10 perseant-stdc-iso10646-base:1.19 netbsd-8:1.19.0.8 netbsd-8-base:1.19 prg-localcount2-base3:1.19 prg-localcount2-base2:1.19 prg-localcount2-base1:1.19 prg-localcount2:1.19.0.6 prg-localcount2-base:1.19 pgoyette-localcount-20170426:1.19 bouyer-socketcan-base1:1.19 jdolecek-ncq:1.19.0.4 jdolecek-ncq-base:1.19 pgoyette-localcount-20170320:1.19 netbsd-7-1:1.18.0.12 netbsd-7-1-RELEASE:1.18 netbsd-7-1-RC2:1.18 nick-nhusb-base-20170204:1.19 netbsd-7-nhusb-base-20170116:1.18 bouyer-socketcan:1.19.0.2 bouyer-socketcan-base:1.19 pgoyette-localcount-20170107:1.19 netbsd-7-1-RC1:1.18 nick-nhusb-base-20161204:1.18 pgoyette-localcount-20161104:1.18 netbsd-7-0-2-RELEASE:1.18 nick-nhusb-base-20161004:1.18 localcount-20160914:1.18 netbsd-7-nhusb:1.18.0.10 netbsd-7-nhusb-base:1.18 pgoyette-localcount-20160806:1.18 pgoyette-localcount-20160726:1.18 pgoyette-localcount:1.18.0.8 pgoyette-localcount-base:1.18 nick-nhusb-base-20160907:1.18 nick-nhusb-base-20160529:1.18 netbsd-7-0-1-RELEASE:1.18 nick-nhusb-base-20160422:1.18 nick-nhusb-base-20160319:1.18 nick-nhusb-base-20151226:1.18 netbsd-7-0:1.18.0.6 netbsd-7-0-RELEASE:1.18 nick-nhusb-base-20150921:1.18 netbsd-7-0-RC3:1.18 netbsd-7-0-RC2:1.18 netbsd-7-0-RC1:1.18 nick-nhusb-base-20150606:1.18 nick-nhusb-base-20150406:1.18 nick-nhusb:1.18.0.4 nick-nhusb-base:1.18 netbsd-5-2-3-RELEASE:1.9 netbsd-5-1-5-RELEASE:1.9 netbsd-6-0-6-RELEASE:1.11 netbsd-6-1-5-RELEASE:1.11 netbsd-7:1.18.0.2 netbsd-7-base:1.18 yamt-pagecache-base9:1.11 yamt-pagecache-tag8:1.11 netbsd-6-1-4-RELEASE:1.11 netbsd-6-0-5-RELEASE:1.11 tls-earlyentropy:1.11.0.36 tls-earlyentropy-base:1.18 riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.11 riastradh-drm2-base3:1.11 netbsd-6-1-3-RELEASE:1.11 netbsd-6-0-4-RELEASE:1.11 netbsd-5-2-2-RELEASE:1.9 netbsd-5-1-4-RELEASE:1.9 netbsd-6-1-2-RELEASE:1.11 netbsd-6-0-3-RELEASE:1.11 netbsd-5-2-1-RELEASE:1.9 netbsd-5-1-3-RELEASE:1.9 rmind-smpnet-nbase:1.11 netbsd-6-1-1-RELEASE:1.11 riastradh-drm2-base2:1.11 riastradh-drm2-base1:1.11 riastradh-drm2:1.11.0.34 riastradh-drm2-base:1.11 rmind-smpnet:1.11.0.26 rmind-smpnet-base:1.11 netbsd-6-1:1.11.0.32 netbsd-6-0-2-RELEASE:1.11 netbsd-6-1-RELEASE:1.11 khorben-n900:1.11.0.30 netbsd-6-1-RC4:1.11 netbsd-6-1-RC3:1.11 agc-symver:1.11.0.28 agc-symver-base:1.11 netbsd-6-1-RC2:1.11 netbsd-6-1-RC1:1.11 yamt-pagecache-base8:1.11 netbsd-5-2:1.9.0.18 netbsd-6-0-1-RELEASE:1.11 yamt-pagecache-base7:1.11 netbsd-5-2-RELEASE:1.9 netbsd-5-2-RC1:1.9 matt-nb6-plus-nbase:1.11 yamt-pagecache-base6:1.11 netbsd-6-0:1.11.0.24 netbsd-6-0-RELEASE:1.11 netbsd-6-0-RC2:1.11 tls-maxphys:1.11.0.22 tls-maxphys-base:1.18 matt-nb6-plus:1.11.0.20 matt-nb6-plus-base:1.11 netbsd-6-0-RC1:1.11 jmcneill-usbmp-base10:1.11 yamt-pagecache-base5:1.11 jmcneill-usbmp-base9:1.11 yamt-pagecache-base4:1.11 jmcneill-usbmp-base8:1.11 jmcneill-usbmp-base7:1.11 jmcneill-usbmp-base6:1.11 jmcneill-usbmp-base5:1.11 jmcneill-usbmp-base4:1.11 jmcneill-usbmp-base3:1.11 jmcneill-usbmp-pre-base2:1.11 jmcneill-usbmp-base2:1.11 netbsd-6:1.11.0.18 netbsd-6-base:1.11 netbsd-5-1-2-RELEASE:1.9 netbsd-5-1-1-RELEASE:1.9 jmcneill-usbmp:1.11.0.16 jmcneill-usbmp-base:1.11 jmcneill-audiomp3:1.11.0.14 jmcneill-audiomp3-base:1.11 yamt-pagecache-base3:1.11 yamt-pagecache-base2:1.11 yamt-pagecache:1.11.0.12 yamt-pagecache-base:1.11 rmind-uvmplock-nbase:1.11 cherry-xenmp:1.11.0.10 cherry-xenmp-base:1.11 bouyer-quota2-nbase:1.11 bouyer-quota2:1.11.0.8 bouyer-quota2-base:1.11 jruoho-x86intr:1.11.0.6 jruoho-x86intr-base:1.11 matt-mips64-premerge-20101231:1.11 matt-nb5-mips64-premerge-20101231:1.9 matt-nb5-pq3:1.9.0.16 matt-nb5-pq3-base:1.9 netbsd-5-1:1.9.0.14 netbsd-5-1-RELEASE:1.9 uebayasi-xip-base4:1.11 uebayasi-xip-base3:1.11 yamt-nfs-mp-base11:1.11 netbsd-5-1-RC4:1.9 matt-nb5-mips64-k15:1.9 uebayasi-xip-base2:1.11 yamt-nfs-mp-base10:1.11 netbsd-5-1-RC3:1.9 netbsd-5-1-RC2:1.9 uebayasi-xip-base1:1.11 netbsd-5-1-RC1:1.9 rmind-uvmplock:1.11.0.4 rmind-uvmplock-base:1.11 yamt-nfs-mp-base9:1.11 uebayasi-xip:1.11.0.2 uebayasi-xip-base:1.11 netbsd-5-0-2-RELEASE:1.9 matt-nb5-mips64-premerge-20091211:1.9 matt-premerge-20091211:1.10 yamt-nfs-mp-base8:1.9 matt-nb5-mips64-u2-k2-k4-k7-k8-k9:1.9 matt-nb4-mips64-k7-u2a-k9b:1.9 matt-nb5-mips64-u1-k1-k5:1.9 yamt-nfs-mp-base7:1.9 matt-nb5-mips64:1.9.0.12 netbsd-5-0-1-RELEASE:1.9 jymxensuspend-base:1.9 yamt-nfs-mp-base6:1.9 yamt-nfs-mp-base5:1.9 yamt-nfs-mp-base4:1.9 jym-xensuspend-nbase:1.10 yamt-nfs-mp-base3:1.9 nick-hppapmap-base4:1.9 nick-hppapmap-base3:1.9 netbsd-5-0:1.9.0.10 netbsd-5-0-RELEASE:1.9 netbsd-5-0-RC4:1.9 netbsd-5-0-RC3:1.9 nick-hppapmap-base2:1.9 netbsd-5-0-RC2:1.9 jym-xensuspend:1.9.0.8 jym-xensuspend-base:1.9 netbsd-5-0-RC1:1.9 haad-dm-base2:1.9 haad-nbase2:1.9 ad-audiomp2:1.9.0.6 ad-audiomp2-base:1.9 netbsd-5:1.9.0.4 netbsd-5-base:1.9 nick-hppapmap:1.9.0.2 nick-hppapmap-base:1.9 matt-mips64-base2:1.9 matt-mips64:1.8.0.40 haad-dm-base1:1.9 wrstuden-revivesa-base-4:1.9 netbsd-4-0-1-RELEASE:1.1.18.1 wrstuden-revivesa-base-3:1.9 wrstuden-revivesa-base-2:1.9 wrstuden-fixsa-newbase:1.1.18.1 nick-csl-alignment-base5:1.8 haad-dm:1.8.0.38 haad-dm-base:1.9 wrstuden-revivesa-base-1:1.8 simonb-wapbl-nbase:1.8 yamt-pf42-base4:1.8 simonb-wapbl:1.8.0.36 simonb-wapbl-base:1.8 yamt-pf42-base3:1.8 hpcarm-cleanup-nbase:1.8 yamt-pf42-baseX:1.8 yamt-pf42-base2:1.8 yamt-nfs-mp-base2:1.8 wrstuden-revivesa:1.8.0.34 wrstuden-revivesa-base:1.8 yamt-nfs-mp:1.8.0.32 yamt-nfs-mp-base:1.8 yamt-pf42:1.8.0.30 yamt-pf42-base:1.8 ad-socklock-base1:1.8 yamt-lazymbuf-base15:1.8 yamt-lazymbuf-base14:1.8 keiichi-mipv6-nbase:1.8 mjf-devfs2:1.8.0.28 mjf-devfs2-base:1.9 nick-net80211-sync:1.8.0.26 nick-net80211-sync-base:1.8 keiichi-mipv6:1.8.0.24 keiichi-mipv6-base:1.8 bouyer-xeni386-merge1:1.8 matt-armv6-prevmlocking:1.8 wrstuden-fixsa-base-1:1.1.18.1 vmlocking2-base3:1.8 netbsd-4-0:1.1.18.1.0.4 netbsd-4-0-RELEASE:1.1.18.1 bouyer-xeni386-nbase:1.8 yamt-kmem-base3:1.8 cube-autoconf:1.8.0.22 cube-autoconf-base:1.8 yamt-kmem-base2:1.8 bouyer-xeni386:1.8.0.20 bouyer-xeni386-base:1.8 yamt-kmem:1.8.0.18 yamt-kmem-base:1.8 vmlocking2-base2:1.8 reinoud-bufcleanup-nbase:1.8 vmlocking2:1.8.0.16 vmlocking2-base1:1.8 netbsd-4-0-RC5:1.1.18.1 matt-nb4-arm:1.1.18.1.0.2 matt-nb4-arm-base:1.1.18.1 matt-armv6-nbase:1.8 jmcneill-base:1.8 netbsd-4-0-RC4:1.1.18.1 mjf-devfs:1.8.0.14 mjf-devfs-base:1.8 bouyer-xenamd64-base2:1.8 vmlocking-nbase:1.8 yamt-x86pmap-base4:1.8 bouyer-xenamd64:1.8.0.12 bouyer-xenamd64-base:1.8 netbsd-4-0-RC3:1.1.18.1 yamt-x86pmap-base3:1.8 yamt-x86pmap-base2:1.8 netbsd-4-0-RC2:1.1.18.1 yamt-x86pmap:1.8.0.10 yamt-x86pmap-base:1.8 netbsd-4-0-RC1:1.1.18.1 matt-armv6:1.8.0.8 matt-armv6-base:1.8 matt-mips64-base:1.8 jmcneill-pm:1.8.0.6 jmcneill-pm-base:1.8 hpcarm-cleanup:1.8.0.4 hpcarm-cleanup-base:1.8 nick-csl-alignment:1.8.0.2 nick-csl-alignment-base:1.8 yamt-idlelwp-base8:1.8 wrstuden-fixsa:1.1.0.24 wrstuden-fixsa-base:1.1.18.1 thorpej-atomic:1.6.0.2 thorpej-atomic-base:1.6 reinoud-bufcleanup:1.3.0.2 reinoud-bufcleanup-base:1.8 mjf-ufs-trans:1.2.0.4 mjf-ufs-trans-base:1.8 vmlocking:1.2.0.2 vmlocking-base:1.8 ad-audiomp:1.1.0.22 ad-audiomp-base:1.1 yamt-idlelwp:1.1.0.20 post-newlock2-merge:1.1 newlock2-nbase:1.1 yamt-splraiseipl-base5:1.1 yamt-splraiseipl-base4:1.1 yamt-splraiseipl-base3:1.1 abandoned-netbsd-4-base:1.1 abandoned-netbsd-4:1.1.0.10 yamt-splraiseipl-base2:1.1 yamt-splraiseipl:1.1.0.16 yamt-splraiseipl-base:1.1 yamt-pdpolicy-base9:1.1 rpaulo-netinet-merge-pcb-base:1.1 rpaulo-netinet-merge-pcb:1.1.0.14 newlock2:1.1.0.12 newlock2-base:1.1 yamt-pdpolicy-base8:1.1 yamt-pdpolicy-base7:1.1 netbsd-4:1.1.0.18 netbsd-4-base:1.1 gdamore-uart:1.1.0.8 yamt-pdpolicy:1.1.0.6 yamt-pdpolicy-base6:1.1 chap-midi-base:1.1 chap-midi:1.1.0.4 yamt-lazymbuf:1.1.0.2 chap-midi-nbase:1.1; locks; strict; comment @ * @; 1.19 date 2016.12.12.15.58.45; author maya; state Exp; branches; next 1.18; commitid V50zZxDGHKSq8Ixz; 1.18 date 2014.08.05.07.55.32; author rtr; state Exp; branches 1.18.4.1 1.18.8.1; next 1.17; commitid EyuFMH7eaCHt69Lx; 1.17 date 2014.07.31.03.39.35; author rtr; state Exp; branches; next 1.16; commitid 8risrLdDyvQGQtKx; 1.16 date 2014.07.30.10.04.26; author rtr; state Exp; branches; next 1.15; commitid wecR9bnggHUK0oKx; 1.15 date 2014.07.24.15.12.03; author rtr; state Exp; branches; next 1.14; commitid FqfZrLaT60wYTDJx; 1.14 date 2014.07.09.04.54.03; author rtr; state Exp; branches; next 1.13; commitid lxAEoci2TpEaYEHx; 1.13 date 2014.05.20.18.25.54; author rmind; state Exp; branches; next 1.12; commitid iUG1PXVDoOtq4jBx; 1.12 date 2014.05.19.02.51.24; author rmind; state Exp; branches; next 1.11; commitid 9u0WtQcwaTaPV5Bx; 1.11 date 2010.01.04.19.20.05; author plunky; state Exp; branches 1.11.22.1 1.11.26.1 1.11.36.1; next 1.10; 1.10 date 2009.09.25.19.44.57; author plunky; state Exp; branches; next 1.9; 1.9 date 2008.08.06.15.01.24; author plunky; state Exp; branches; next 1.8; 1.8 date 2007.04.29.20.23.36; author msaitoh; state Exp; branches 1.8.28.1 1.8.32.1 1.8.34.1 1.8.38.1; next 1.7; 1.7 date 2007.04.21.06.15.23; author plunky; state Exp; branches; next 1.6; 1.6 date 2007.04.06.17.09.00; author plunky; state Exp; branches; next 1.5; 1.5 date 2007.03.30.20.47.03; author plunky; state Exp; branches; next 1.4; 1.4 date 2007.03.15.19.47.51; author plunky; state Exp; branches; next 1.3; 1.3 date 2007.03.12.20.34.54; author plunky; state Exp; branches 1.3.2.1; next 1.2; 1.2 date 2007.03.05.19.11.54; author plunky; state Exp; branches 1.2.2.1 1.2.4.1; next 1.1; 1.1 date 2006.06.19.15.44.45; author gdamore; state Exp; branches 1.1.2.1 1.1.4.1 1.1.6.1 1.1.8.1 1.1.14.1 1.1.18.1 1.1.20.1 1.1.24.1; next ; 1.18.4.1 date 2017.02.05.13.40.59; author skrll; state Exp; branches; next ; commitid 8hwpk1aHl2UuyLEz; 1.18.8.1 date 2017.01.07.08.56.51; author pgoyette; state Exp; branches; next ; commitid uEL0C1YuiJrlV0Bz; 1.11.22.1 date 2014.08.20.00.04.35; author tls; state Exp; branches; next 1.11.22.2; commitid jTnpym9Qu0o4R1Nx; 1.11.22.2 date 2017.12.03.11.39.03; author jdolecek; state Exp; branches; next ; commitid XcIYRZTAh1LmerhA; 1.11.26.1 date 2013.08.28.15.21.48; author rmind; state Exp; branches; next ; commitid 6VTytZQcOxQfze3x; 1.11.36.1 date 2014.08.10.06.56.23; author tls; state Exp; branches; next ; commitid Q3VWPxpfW0ywCMLx; 1.8.28.1 date 2008.09.28.10.40.57; author mjf; state Exp; branches; next ; 1.8.32.1 date 2009.05.04.08.14.17; author yamt; state Exp; branches; next 1.8.32.2; 1.8.32.2 date 2010.03.11.15.04.28; author yamt; state Exp; branches; next ; 1.8.34.1 date 2008.09.18.04.37.00; author wrstuden; state Exp; branches; next ; 1.8.38.1 date 2008.10.19.22.17.45; author haad; state Exp; branches; next ; 1.3.2.1 date 2007.03.18.00.06.45; author reinoud; state Exp; branches; next ; 1.2.2.1 date 2007.03.13.16.52.01; author ad; state Exp; branches; next 1.2.2.2; 1.2.2.2 date 2007.04.10.13.26.48; author ad; state Exp; branches; next 1.2.2.3; 1.2.2.3 date 2007.06.08.14.17.42; author ad; state Exp; branches; next ; 1.2.4.1 date 2007.07.11.20.11.13; author mjf; state Exp; branches; next ; 1.1.2.1 date 2006.06.19.15.44.45; author yamt; state dead; branches; next 1.1.2.2; 1.1.2.2 date 2006.06.21.15.10.51; author yamt; state Exp; branches; next 1.1.2.3; 1.1.2.3 date 2007.09.03.14.42.42; author yamt; state Exp; branches; next ; 1.1.4.1 date 2006.06.19.15.44.45; author chap; state dead; branches; next 1.1.4.2; 1.1.4.2 date 2006.06.22.03.39.50; author chap; state Exp; branches; next ; 1.1.6.1 date 2006.06.19.15.44.45; author yamt; state dead; branches; next 1.1.6.2; 1.1.6.2 date 2006.06.26.12.53.57; author yamt; state Exp; branches; next ; 1.1.8.1 date 2006.06.19.15.44.45; author gdamore; state dead; branches; next 1.1.8.2; 1.1.8.2 date 2006.07.13.17.49.58; author gdamore; state Exp; branches; next ; 1.1.14.1 date 2006.06.19.15.44.45; author rpaulo; state dead; branches; next 1.1.14.2; 1.1.14.2 date 2006.09.09.02.58.39; author rpaulo; state Exp; branches; next ; 1.1.18.1 date 2007.07.19.16.04.20; author liamjfoy; state Exp; branches; next ; 1.1.20.1 date 2007.03.12.05.59.34; author rmind; state Exp; branches; next 1.1.20.2; 1.1.20.2 date 2007.03.24.14.56.09; author yamt; state Exp; branches; next 1.1.20.3; 1.1.20.3 date 2007.04.15.16.03.59; author yamt; state Exp; branches; next 1.1.20.4; 1.1.20.4 date 2007.05.07.10.55.56; author yamt; state Exp; branches; next ; 1.1.24.1 date 2007.09.03.07.05.11; author wrstuden; state Exp; branches; next ; desc @@ 1.19 log @acknowleg -> acknowledg, proceedure -> procedure. only comments were changed. from miod @ text @/* $NetBSD: l2cap_upper.c,v 1.18 2014/08/05 07:55:32 rtr Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. * Copyright (c) 2006 Itronix Inc. * 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 Itronix Inc. may not be used to endorse * or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.18 2014/08/05 07:55:32 rtr Exp $"); #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * * L2CAP Channel - Upper Protocol API */ /* * l2cap_attach_pcb(handle, btproto, upper) * * attach new l2cap_channel to handle, populate * with reasonable defaults */ int l2cap_attach_pcb(struct l2cap_channel **handle, const struct btproto *proto, void *upper) { struct l2cap_channel *chan; KASSERT(handle != NULL); KASSERT(proto != NULL); KASSERT(upper != NULL); chan = malloc(sizeof(struct l2cap_channel), M_BLUETOOTH, M_NOWAIT | M_ZERO); if (chan == NULL) return ENOMEM; chan->lc_proto = proto; chan->lc_upper = upper; chan->lc_state = L2CAP_CLOSED; chan->lc_lcid = L2CAP_NULL_CID; chan->lc_rcid = L2CAP_NULL_CID; chan->lc_laddr.bt_len = sizeof(struct sockaddr_bt); chan->lc_laddr.bt_family = AF_BLUETOOTH; chan->lc_laddr.bt_psm = L2CAP_PSM_ANY; chan->lc_raddr.bt_len = sizeof(struct sockaddr_bt); chan->lc_raddr.bt_family = AF_BLUETOOTH; chan->lc_raddr.bt_psm = L2CAP_PSM_ANY; chan->lc_imtu = L2CAP_MTU_DEFAULT; chan->lc_omtu = L2CAP_MTU_DEFAULT; chan->lc_flush = L2CAP_FLUSH_TIMO_DEFAULT; memcpy(&chan->lc_iqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); memcpy(&chan->lc_oqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); MBUFQ_INIT(&chan->lc_txq); *handle = chan; return 0; } /* * l2cap_bind_pcb(l2cap_channel, sockaddr) * * set local address of channel */ int l2cap_bind_pcb(struct l2cap_channel *chan, struct sockaddr_bt *addr) { if (chan->lc_lcid != L2CAP_NULL_CID) return EINVAL; memcpy(&chan->lc_laddr, addr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_sockaddr_pcb(l2cap_channel, sockaddr) * * get local address of channel */ int l2cap_sockaddr_pcb(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(addr, &chan->lc_laddr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_connect_pcb(l2cap_channel, sockaddr) * * Initiate a connection to destination. This corresponds to * "Open Channel Request" in the L2CAP specification and will * result in one of the following: * * proto->connected(upper) * proto->disconnected(upper, error) * * and, optionally * proto->connecting(upper) */ int l2cap_connect_pcb(struct l2cap_channel *chan, struct sockaddr_bt *dest) { struct hci_unit *unit; int err; memcpy(&chan->lc_raddr, dest, sizeof(struct sockaddr_bt)); if (L2CAP_PSM_INVALID(chan->lc_raddr.bt_psm)) return EINVAL; if (bdaddr_any(&chan->lc_raddr.bt_bdaddr)) return EDESTADDRREQ; /* set local address if it needs setting */ if (bdaddr_any(&chan->lc_laddr.bt_bdaddr)) { err = hci_route_lookup(&chan->lc_laddr.bt_bdaddr, &chan->lc_raddr.bt_bdaddr); if (err) return err; } unit = hci_unit_lookup(&chan->lc_laddr.bt_bdaddr); if (unit == NULL) return EHOSTUNREACH; /* attach to active list */ err = l2cap_cid_alloc(chan); if (err) return err; /* open link to remote device */ chan->lc_link = hci_acl_open(unit, &chan->lc_raddr.bt_bdaddr); if (chan->lc_link == NULL) return EHOSTUNREACH; /* set the link mode */ err = l2cap_setmode(chan); if (err == EINPROGRESS) { chan->lc_state = L2CAP_WAIT_SEND_CONNECT_REQ; (*chan->lc_proto->connecting)(chan->lc_upper); return 0; } if (err) goto fail; /* * We can queue a connect request now even though the link may * not yet be open; Our mode setting is assured, and the queue * will be started automatically at the right time. */ chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP; err = l2cap_send_connect_req(chan); if (err) goto fail; return 0; fail: chan->lc_state = L2CAP_CLOSED; hci_acl_close(chan->lc_link, err); chan->lc_link = NULL; return err; } /* * l2cap_peeraddr_pcb(l2cap_channel, sockaddr) * * get remote address of channel */ int l2cap_peeraddr_pcb(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(addr, &chan->lc_raddr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_disconnect_pcb(l2cap_channel, linger) * * Initiate L2CAP disconnection. This corresponds to * "Close Channel Request" in the L2CAP specification * and will result in a call to * * proto->disconnected(upper, error) * * when the disconnection is complete. If linger is set, * the call will not be made until data has flushed from * the queue. */ int l2cap_disconnect_pcb(struct l2cap_channel *chan, int linger) { int err = 0; if (chan->lc_state == L2CAP_CLOSED || chan->lc_state == L2CAP_WAIT_DISCONNECT) return EINVAL; chan->lc_flags |= L2CAP_SHUTDOWN; /* * no need to do anything unless the queue is empty or * we are not lingering.. */ if ((MBUFQ_FIRST(&chan->lc_txq) == NULL && chan->lc_pending == 0) || linger == 0) { chan->lc_state = L2CAP_WAIT_DISCONNECT; err = l2cap_send_disconnect_req(chan); if (err) l2cap_close(chan, err); } return err; } /* * l2cap_detach_pcb(handle) * * Detach l2cap channel from handle & close it down */ void l2cap_detach_pcb(struct l2cap_channel **handle) { struct l2cap_channel *chan; chan = *handle; *handle = NULL; if (chan->lc_state != L2CAP_CLOSED) l2cap_close(chan, 0); if (chan->lc_lcid != L2CAP_NULL_CID) { LIST_REMOVE(chan, lc_ncid); chan->lc_lcid = L2CAP_NULL_CID; } MBUFQ_DRAIN(&chan->lc_txq); /* * Could implement some kind of delayed expunge to make sure that the * CID is really dead before it becomes available for reuse? */ free(chan, M_BLUETOOTH); } /* * l2cap_listen_pcb(l2cap_channel) * * Use this channel as a listening post (until detached). This will * result in calls to: * * proto->newconn(upper, laddr, raddr) * * for incoming connections matching the psm and local address of * the channel. NULL address is permitted and matches any device. * If L2CAP_PSM_ANY is bound the next higher unused value from the * dynamic range (above 0x1001) will be selected. * * The upper layer should create and return a new channel. * * You cannot use this channel for anything else subsequent to this call */ int l2cap_listen_pcb(struct l2cap_channel *chan) { struct l2cap_channel *used, *prev = NULL; uint32_t psm; if (chan->lc_lcid != L2CAP_NULL_CID) return EINVAL; /* * This is simplistic but its not really worth spending a * lot of time looking for an unused PSM.. */ if (chan->lc_laddr.bt_psm == L2CAP_PSM_ANY) { psm = 0x1001; used = LIST_FIRST(&l2cap_listen_list); if (used != NULL && used->lc_laddr.bt_psm >= psm) { psm = used->lc_laddr.bt_psm + 0x0002; if ((psm & 0x0100) != 0) psm += 0x0100; if (psm > UINT16_MAX) return EADDRNOTAVAIL; } chan->lc_laddr.bt_psm = psm; } else if (L2CAP_PSM_INVALID(chan->lc_laddr.bt_psm)) return EINVAL; /* * This CID is irrelevant, as the channel is not stored on the active * list and the socket code does not allow operations on listening * sockets, but we set it so the detach code knows to LIST_REMOVE the * channel. */ chan->lc_lcid = L2CAP_SIGNAL_CID; /* * The list of listening channels is stored in an order such that new * listeners dont usurp current listeners, but that specific listening * takes precedence over promiscuous, and the connect request code can * easily use the first matching entry. */ LIST_FOREACH(used, &l2cap_listen_list, lc_ncid) { if (used->lc_laddr.bt_psm < chan->lc_laddr.bt_psm) break; if (used->lc_laddr.bt_psm == chan->lc_laddr.bt_psm && bdaddr_any(&used->lc_laddr.bt_bdaddr) && !bdaddr_any(&chan->lc_laddr.bt_bdaddr)) break; prev = used; } if (prev == NULL) LIST_INSERT_HEAD(&l2cap_listen_list, chan, lc_ncid); else LIST_INSERT_AFTER(prev, chan, lc_ncid); return 0; } /* * l2cap_send_pcb(l2cap_channel, mbuf) * * Output SDU on channel described by channel. This corresponds * to "Send Data Request" in the L2CAP specification. The upper * layer will be notified when SDU's have completed sending by a * call to: * * proto->complete(upper, n) * * (currently n == 1) * * Note: I'm not sure how this will work out, but I think that * if outgoing Retransmission Mode or Flow Control Mode is * negotiated then this call will not be made until the SDU has * been acknowledged by the peer L2CAP entity. For 'Best Effort' * it will be made when the packet has cleared the controller * buffers. * * We only support Basic mode so far, so encapsulate with a * B-Frame header and start sending if we are not already */ int l2cap_send_pcb(struct l2cap_channel *chan, struct mbuf *m) { l2cap_hdr_t *hdr; int plen; if (chan->lc_state == L2CAP_CLOSED) { m_freem(m); return ENOTCONN; } plen = m->m_pkthdr.len; DPRINTFN(5, "send %d bytes on CID #%d (pending = %d)\n", plen, chan->lc_lcid, chan->lc_pending); /* Encapsulate with B-Frame */ M_PREPEND(m, sizeof(l2cap_hdr_t), M_DONTWAIT); if (m == NULL) return ENOMEM; hdr = mtod(m, l2cap_hdr_t *); hdr->length = htole16(plen); hdr->dcid = htole16(chan->lc_rcid); /* Queue it on our list */ MBUFQ_ENQUEUE(&chan->lc_txq, m); /* If we are not sending, then start doing so */ if (chan->lc_pending == 0) return l2cap_start(chan); return 0; } /* * l2cap_setopt(l2cap_channel, sopt) * * Apply configuration options to channel. This corresponds to * "Configure Channel Request" in the L2CAP specification. * * for SO_L2CAP_LM, the settings will take effect when the * channel is established. If the channel is already open, * a call to * proto->linkmode(upper, new) * * will be made when the change is complete. */ int l2cap_setopt(struct l2cap_channel *chan, const struct sockopt *sopt) { int mode, err = 0; uint16_t mtu; switch (sopt->sopt_name) { case SO_L2CAP_IMTU: /* set Incoming MTU */ err = sockopt_get(sopt, &mtu, sizeof(mtu)); if (err) break; if (mtu < L2CAP_MTU_MINIMUM) err = EINVAL; else if (chan->lc_state == L2CAP_CLOSED) chan->lc_imtu = mtu; else err = EBUSY; break; case SO_L2CAP_LM: /* set link mode */ err = sockopt_getint(sopt, &mode); if (err) break; mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH); if (mode & L2CAP_LM_SECURE) mode |= L2CAP_LM_ENCRYPT; if (mode & L2CAP_LM_ENCRYPT) mode |= L2CAP_LM_AUTH; chan->lc_mode = mode; if (chan->lc_state == L2CAP_OPEN) err = l2cap_setmode(chan); break; case SO_L2CAP_OQOS: /* set Outgoing QoS flow spec */ case SO_L2CAP_FLUSH: /* set Outgoing Flush Timeout */ default: err = ENOPROTOOPT; break; } return err; } /* * l2cap_getopt(l2cap_channel, sopt) * * Return configuration parameters. */ int l2cap_getopt(struct l2cap_channel *chan, struct sockopt *sopt) { switch (sopt->sopt_name) { case SO_L2CAP_IMTU: /* get Incoming MTU */ return sockopt_set(sopt, &chan->lc_imtu, sizeof(uint16_t)); case SO_L2CAP_OMTU: /* get Outgoing MTU */ return sockopt_set(sopt, &chan->lc_omtu, sizeof(uint16_t)); case SO_L2CAP_IQOS: /* get Incoming QoS flow spec */ return sockopt_set(sopt, &chan->lc_iqos, sizeof(l2cap_qos_t)); case SO_L2CAP_OQOS: /* get Outgoing QoS flow spec */ return sockopt_set(sopt, &chan->lc_oqos, sizeof(l2cap_qos_t)); case SO_L2CAP_FLUSH: /* get Flush Timeout */ return sockopt_set(sopt, &chan->lc_flush, sizeof(uint16_t)); case SO_L2CAP_LM: /* get link mode */ return sockopt_setint(sopt, chan->lc_mode); default: break; } return ENOPROTOOPT; } @ 1.18 log @split PRU_SEND function out of pr_generic() usrreq switches and put into separate functions xxx_send(struct socket *, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *) - always KASSERT(solocked(so)) even if not implemented - replace calls to pr_generic() with req = PRU_SEND with calls to pr_send() rename existing functions that operate on PCB for consistency (and to free up their names for xxx_send() PRUs - l2cap_send() -> l2cap_send_pcb() - sco_send() -> sco_send_pcb() - rfcomm_send() -> rfcomm_send_pcb() patch reviewed by rmind @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.17 2014/07/31 03:39:35 rtr Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.17 2014/07/31 03:39:35 rtr Exp $"); d389 1 a389 1 * been acknowleged by the peer L2CAP entity. For 'Best Effort' @ 1.18.4.1 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.19 2016/12/12 15:58:45 maya Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.19 2016/12/12 15:58:45 maya Exp $"); d389 1 a389 1 * been acknowledged by the peer L2CAP entity. For 'Best Effort' @ 1.18.8.1 log @Sync with HEAD. (Note that most of these changes are simply $NetBSD$ tag issues.) @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.19 2016/12/12 15:58:45 maya Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.19 2016/12/12 15:58:45 maya Exp $"); d389 1 a389 1 * been acknowledged by the peer L2CAP entity. For 'Best Effort' @ 1.17 log @split PRU_DISCONNECT, PRU_SHUTDOWN and PRU_ABORT function out of pr_generic() usrreq switches and put into separate functions xxx_disconnect(struct socket *) xxx_shutdown(struct socket *) xxx_abort(struct socket *) - always KASSERT(solocked(so)) even if not implemented - replace calls to pr_generic() with req = PRU_{DISCONNECT,SHUTDOWN,ABORT} with calls to pr_{disconnect,shutdown,abort}() respectively rename existing internal functions used to implement above functionality to permit use of the names for xxx_{disconnect,shutdown,abort}(). - {l2cap,sco,rfcomm}_disconnect() -> {l2cap,sco,rfcomm}_disconnect_pcb() - {unp,rip,tcp}_disconnect() -> {unp,rip,tcp}_disconnect1() - unp_shutdown() -> unp_shutdown1() patch reviewed by rmind @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.16 2014/07/30 10:04:26 rtr Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.16 2014/07/30 10:04:26 rtr Exp $"); d375 1 a375 1 * l2cap_send(l2cap_channel, mbuf) d397 1 a397 1 l2cap_send(struct l2cap_channel *chan, struct mbuf *m) @ 1.16 log @split PRU_CONNECT function out of pr_generic() usrreq switches and put into seaparate functions xxx_listen(struct socket *, struct mbuf *) - always KASSERT(solocked(so)) and KASSERT(nam != NULL) - replace calls to pr_generic() with req = PRU_CONNECT with pr_connect() - rename existin {l2cap,sco,rfcomm}_connect() to {l2cap,sco,rfcomm}_connect_pcb() respectively to permit naming consistency with other protocols functions. - drop struct lwp * parameter from unp_connect() and at_pcbconnect() and use curlwp instead where appropriate. patch reviewed by rmind @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.15 2014/07/24 15:12:03 rtr Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.15 2014/07/24 15:12:03 rtr Exp $"); d225 1 a225 1 * l2cap_disconnect(l2cap_channel, linger) d238 1 a238 1 l2cap_disconnect(struct l2cap_channel *chan, int linger) @ 1.15 log @split PRU_BIND and PRU_LISTEN function out of pr_generic() usrreq switches and put into separate functions xxx_bind(struct socket *, struct mbuf *) xxx_listen(struct socket *) - always KASSERT(solocked(so)) even if not implemented - replace calls to pr_generic() with req = PRU_BIND with call to pr_bind() - replace calls to pr_generic() with req = PRU_LISTEN with call to pr_listen() - drop struct lwp * parameter from at_pcbsetaddr(), in_pcbbind() and unp_bind() and always use curlwp. rename existing functions that operate on PCB for consistency (and to free up their names for xxx_{bind,listen}() PRUs - l2cap_{bind,listen}() -> l2cap_{bind,listen}_pcb() - sco_{bind,listen}() -> sco_{bind,listen}_pcb() - rfcomm_{bind,listen}() -> rfcomm_{bind,listen}_pcb() patch reviewed by rmind welcome to netbsd 6.99.48 @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.14 2014/07/09 04:54:03 rtr Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.14 2014/07/09 04:54:03 rtr Exp $"); d134 1 a134 1 * l2cap_connect(l2cap_channel, sockaddr) d147 1 a147 1 l2cap_connect(struct l2cap_channel *chan, struct sockaddr_bt *dest) @ 1.14 log @* split PRU_PEERADDR and PRU_SOCKADDR function out of pr_generic() usrreq switches and put into separate functions xxx_{peer,sock}addr(struct socket *, struct mbuf *). - KASSERT(solocked(so)) always in new functions even if request is not implemented - KASSERT(pcb != NULL) and KASSERT(nam) if the request is implemented and not for tcp. * for tcp roll #ifdef KPROF and #ifdef DEBUG code from tcp_usrreq() into easier to cut & paste functions tcp_debug_capture() and tcp_debug_trace() - functions provided by rmind - remaining use of PRU_{PEER,SOCK}ADDR #define to be removed in a future commit. * rename netbt functions to permit consistency of pru function names (as has been done with other requests already split out). - l2cap_{peer,sock}addr() -> l2cap_{peer,sock}_addr_pcb() - rfcomm_{peer,sock}addr() -> rfcomm_{peer,sock}_addr_pcb() - sco_{peer,sock}addr() -> sco_{peer,sock}_addr_pcb() * split/refactor do_sys_getsockname(lwp, fd, which, nam) into two functions do_sys_get{peer,sock}name(fd, nam). - move PRU_PEERADDR handling into do_sys_getpeername() from do_sys_getsockname() - have svr4_stream directly call do_sys_get{sock,peer}name() respectively instead of providing `which' & fix a DPRINTF string that incorrectly wrote "getpeername" when it meant "getsockname" - fix sys_getpeername() and sys_getsockname() to call do_sys_get{sock,peer}name() without `which' and `lwp' & adjust comments - bump kernel version for removal of lwp & which parameters from do_sys_getsockname() note: future cleanup to remove struct mbuf * abuse in xxx_{peer,sock}name() still to come, not done in this commit since it is easier to do post split. patch reviewed by rmind welcome to 6.99.47 @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.13 2014/05/20 18:25:54 rmind Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.13 2014/05/20 18:25:54 rmind Exp $"); d105 1 a105 1 * l2cap_bind(l2cap_channel, sockaddr) d110 1 a110 1 l2cap_bind(struct l2cap_channel *chan, struct sockaddr_bt *addr) d294 1 a294 1 * l2cap_listen(l2cap_channel) d311 1 a311 1 l2cap_listen(struct l2cap_channel *chan) @ 1.13 log @netbt: rename some attach/detach functions to have _pcb suffix, so we could use standard attach/detach naming for pr_usrreq functions. No functional change. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.12 2014/05/19 02:51:24 rmind Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.12 2014/05/19 02:51:24 rmind Exp $"); d121 1 a121 1 * l2cap_sockaddr(l2cap_channel, sockaddr) d126 1 a126 1 l2cap_sockaddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) d212 1 a212 1 * l2cap_peeraddr(l2cap_channel, sockaddr) d217 1 a217 1 l2cap_peeraddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) @ 1.12 log @- Split off PRU_ATTACH and PRU_DETACH logic into separate functions. - Replace malloc with kmem and eliminate M_PCB while here. - Sprinkle more asserts. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.11 2010/01/04 19:20:05 plunky Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.11 2010/01/04 19:20:05 plunky Exp $"); d55 1 a55 1 * l2cap_attach(handle, btproto, upper) d61 1 a61 1 l2cap_attach(struct l2cap_channel **handle, d263 1 a263 1 * l2cap_detach(handle) d268 1 a268 1 l2cap_detach(struct l2cap_channel **handle) @ 1.11 log @prevent local socket address from being changed after socket is in use (connect or listen) @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.10 2009/09/25 19:44:57 plunky Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.10 2009/09/25 19:44:57 plunky Exp $"); d267 1 a267 1 int a290 1 return 0; @ 1.11.22.1 log @Rebase to HEAD as of a few days ago. @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d55 1 a55 1 * l2cap_attach_pcb(handle, btproto, upper) d61 1 a61 1 l2cap_attach_pcb(struct l2cap_channel **handle, d105 1 a105 1 * l2cap_bind_pcb(l2cap_channel, sockaddr) d110 1 a110 1 l2cap_bind_pcb(struct l2cap_channel *chan, struct sockaddr_bt *addr) d121 1 a121 1 * l2cap_sockaddr_pcb(l2cap_channel, sockaddr) d126 1 a126 1 l2cap_sockaddr_pcb(struct l2cap_channel *chan, struct sockaddr_bt *addr) d134 1 a134 1 * l2cap_connect_pcb(l2cap_channel, sockaddr) d147 1 a147 1 l2cap_connect_pcb(struct l2cap_channel *chan, struct sockaddr_bt *dest) d212 1 a212 1 * l2cap_peeraddr_pcb(l2cap_channel, sockaddr) d217 1 a217 1 l2cap_peeraddr_pcb(struct l2cap_channel *chan, struct sockaddr_bt *addr) d225 1 a225 1 * l2cap_disconnect_pcb(l2cap_channel, linger) d238 1 a238 1 l2cap_disconnect_pcb(struct l2cap_channel *chan, int linger) d263 1 a263 1 * l2cap_detach_pcb(handle) d267 2 a268 2 void l2cap_detach_pcb(struct l2cap_channel **handle) d291 1 d295 1 a295 1 * l2cap_listen_pcb(l2cap_channel) d312 1 a312 1 l2cap_listen_pcb(struct l2cap_channel *chan) d376 1 a376 1 * l2cap_send_pcb(l2cap_channel, mbuf) d398 1 a398 1 l2cap_send_pcb(struct l2cap_channel *chan, struct mbuf *m) @ 1.11.22.2 log @update from HEAD @ text @d389 1 a389 1 * been acknowledged by the peer L2CAP entity. For 'Best Effort' @ 1.11.36.1 log @Rebase. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.18 2014/08/05 07:55:32 rtr Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.18 2014/08/05 07:55:32 rtr Exp $"); d55 1 a55 1 * l2cap_attach_pcb(handle, btproto, upper) d61 1 a61 1 l2cap_attach_pcb(struct l2cap_channel **handle, d105 1 a105 1 * l2cap_bind_pcb(l2cap_channel, sockaddr) d110 1 a110 1 l2cap_bind_pcb(struct l2cap_channel *chan, struct sockaddr_bt *addr) d121 1 a121 1 * l2cap_sockaddr_pcb(l2cap_channel, sockaddr) d126 1 a126 1 l2cap_sockaddr_pcb(struct l2cap_channel *chan, struct sockaddr_bt *addr) d134 1 a134 1 * l2cap_connect_pcb(l2cap_channel, sockaddr) d147 1 a147 1 l2cap_connect_pcb(struct l2cap_channel *chan, struct sockaddr_bt *dest) d212 1 a212 1 * l2cap_peeraddr_pcb(l2cap_channel, sockaddr) d217 1 a217 1 l2cap_peeraddr_pcb(struct l2cap_channel *chan, struct sockaddr_bt *addr) d225 1 a225 1 * l2cap_disconnect_pcb(l2cap_channel, linger) d238 1 a238 1 l2cap_disconnect_pcb(struct l2cap_channel *chan, int linger) d263 1 a263 1 * l2cap_detach_pcb(handle) d267 2 a268 2 void l2cap_detach_pcb(struct l2cap_channel **handle) d291 1 d295 1 a295 1 * l2cap_listen_pcb(l2cap_channel) d312 1 a312 1 l2cap_listen_pcb(struct l2cap_channel *chan) d376 1 a376 1 * l2cap_send_pcb(l2cap_channel, mbuf) d398 1 a398 1 l2cap_send_pcb(struct l2cap_channel *chan, struct mbuf *m) @ 1.11.26.1 log @Checkpoint work in progress: - Initial split of the protocol user-request method into the following methods: pr_attach, pr_detach and pr_generic for old the pr_usrreq. - Adjust socreate(9) and sonewconn(9) to call pr_attach without the socket lock held (as a preparation for the locking scheme adjustment). - Adjust all pr_attach routines to assert that PCB is not set. - Sprinkle various comments, document some routines and their locking. - Remove M_PCB, replace with kmem(9). - Fix few bugs spotted on the way. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.11 2010/01/04 19:20:05 plunky Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.11 2010/01/04 19:20:05 plunky Exp $"); d267 1 a267 1 void d291 1 @ 1.10 log @When the special L2CAP_PSM_ANY value is used for listening sockets, select the next unused PSM from the dynamic range (0x1001->) @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.9 2008/08/06 15:01:24 plunky Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.9 2008/08/06 15:01:24 plunky Exp $"); d113 3 @ 1.9 log @Convert socket options code to use a sockopt structure instead of laying everything into an mbuf. approved by core @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.8 2007/04/29 20:23:36 msaitoh Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.8 2007/04/29 20:23:36 msaitoh Exp $"); d299 4 a302 2 * for incoming connections matching the psm and local address of the * channel (NULL psm/address are permitted and match any protocol/device). d312 1 d317 20 a336 3 if (chan->lc_laddr.bt_psm != L2CAP_PSM_ANY && L2CAP_PSM_INVALID(chan->lc_laddr.bt_psm)) return EADDRNOTAVAIL; @ 1.8 log @fix typos @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.7 2007/04/21 06:15:23 plunky Exp $"); d410 1 a410 1 * l2cap_setopt(l2cap_channel, opt, addr) d423 1 a423 1 l2cap_setopt(struct l2cap_channel *chan, int opt, void *addr) d428 1 a428 1 switch (opt) { d430 4 a433 1 mtu = *(uint16_t *)addr; d444 4 a447 1 mode = *(int *)addr; d474 1 a474 1 * l2cap_getopt(l2cap_channel, opt, addr) d479 1 a479 1 l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr) d482 1 a482 1 switch (opt) { d484 1 a484 2 *(uint16_t *)addr = chan->lc_imtu; return sizeof(uint16_t); d487 1 a487 2 *(uint16_t *)addr = chan->lc_omtu; return sizeof(uint16_t); d490 1 a490 2 memcpy(addr, &chan->lc_iqos, sizeof(l2cap_qos_t)); return sizeof(l2cap_qos_t); d493 1 a493 2 memcpy(addr, &chan->lc_oqos, sizeof(l2cap_qos_t)); return sizeof(l2cap_qos_t); d496 1 a496 2 *(uint16_t *)addr = chan->lc_flush; return sizeof(uint16_t); d499 1 a499 2 *(int *)addr = chan->lc_mode; return sizeof(int); d505 1 a505 1 return 0; @ 1.8.32.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.8 2007/04/29 20:23:36 msaitoh Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.8 2007/04/29 20:23:36 msaitoh Exp $"); d410 1 a410 1 * l2cap_setopt(l2cap_channel, sopt) d423 1 a423 1 l2cap_setopt(struct l2cap_channel *chan, const struct sockopt *sopt) d428 1 a428 1 switch (sopt->sopt_name) { d430 1 a430 4 err = sockopt_get(sopt, &mtu, sizeof(mtu)); if (err) break; d441 1 a441 4 err = sockopt_getint(sopt, &mode); if (err) break; d468 1 a468 1 * l2cap_getopt(l2cap_channel, sopt) d473 1 a473 1 l2cap_getopt(struct l2cap_channel *chan, struct sockopt *sopt) d476 1 a476 1 switch (sopt->sopt_name) { d478 2 a479 1 return sockopt_set(sopt, &chan->lc_imtu, sizeof(uint16_t)); d482 2 a483 1 return sockopt_set(sopt, &chan->lc_omtu, sizeof(uint16_t)); d486 2 a487 1 return sockopt_set(sopt, &chan->lc_iqos, sizeof(l2cap_qos_t)); d490 2 a491 1 return sockopt_set(sopt, &chan->lc_oqos, sizeof(l2cap_qos_t)); d494 2 a495 1 return sockopt_set(sopt, &chan->lc_flush, sizeof(uint16_t)); d498 2 a499 1 return sockopt_setint(sopt, chan->lc_mode); d505 1 a505 1 return ENOPROTOOPT; @ 1.8.32.2 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.8.32.1 2009/05/04 08:14:17 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.8.32.1 2009/05/04 08:14:17 yamt Exp $"); a112 3 if (chan->lc_lcid != L2CAP_NULL_CID) return EINVAL; d299 2 a300 4 * for incoming connections matching the psm and local address of * the channel. NULL address is permitted and matches any device. * If L2CAP_PSM_ANY is bound the next higher unused value from the * dynamic range (above 0x1001) will be selected. a309 1 uint32_t psm; d314 3 a316 20 /* * This is simplistic but its not really worth spending a * lot of time looking for an unused PSM.. */ if (chan->lc_laddr.bt_psm == L2CAP_PSM_ANY) { psm = 0x1001; used = LIST_FIRST(&l2cap_listen_list); if (used != NULL && used->lc_laddr.bt_psm >= psm) { psm = used->lc_laddr.bt_psm + 0x0002; if ((psm & 0x0100) != 0) psm += 0x0100; if (psm > UINT16_MAX) return EADDRNOTAVAIL; } chan->lc_laddr.bt_psm = psm; } else if (L2CAP_PSM_INVALID(chan->lc_laddr.bt_psm)) return EINVAL; @ 1.8.38.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.9 2008/08/06 15:01:24 plunky Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.9 2008/08/06 15:01:24 plunky Exp $"); d410 1 a410 1 * l2cap_setopt(l2cap_channel, sopt) d423 1 a423 1 l2cap_setopt(struct l2cap_channel *chan, const struct sockopt *sopt) d428 1 a428 1 switch (sopt->sopt_name) { d430 1 a430 4 err = sockopt_get(sopt, &mtu, sizeof(mtu)); if (err) break; d441 1 a441 4 err = sockopt_getint(sopt, &mode); if (err) break; d468 1 a468 1 * l2cap_getopt(l2cap_channel, sopt) d473 1 a473 1 l2cap_getopt(struct l2cap_channel *chan, struct sockopt *sopt) d476 1 a476 1 switch (sopt->sopt_name) { d478 2 a479 1 return sockopt_set(sopt, &chan->lc_imtu, sizeof(uint16_t)); d482 2 a483 1 return sockopt_set(sopt, &chan->lc_omtu, sizeof(uint16_t)); d486 2 a487 1 return sockopt_set(sopt, &chan->lc_iqos, sizeof(l2cap_qos_t)); d490 2 a491 1 return sockopt_set(sopt, &chan->lc_oqos, sizeof(l2cap_qos_t)); d494 2 a495 1 return sockopt_set(sopt, &chan->lc_flush, sizeof(uint16_t)); d498 2 a499 1 return sockopt_setint(sopt, chan->lc_mode); d505 1 a505 1 return ENOPROTOOPT; @ 1.8.28.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d410 1 a410 1 * l2cap_setopt(l2cap_channel, sopt) d423 1 a423 1 l2cap_setopt(struct l2cap_channel *chan, const struct sockopt *sopt) d428 1 a428 1 switch (sopt->sopt_name) { d430 1 a430 4 err = sockopt_get(sopt, &mtu, sizeof(mtu)); if (err) break; d441 1 a441 4 err = sockopt_getint(sopt, &mode); if (err) break; d468 1 a468 1 * l2cap_getopt(l2cap_channel, sopt) d473 1 a473 1 l2cap_getopt(struct l2cap_channel *chan, struct sockopt *sopt) d476 1 a476 1 switch (sopt->sopt_name) { d478 2 a479 1 return sockopt_set(sopt, &chan->lc_imtu, sizeof(uint16_t)); d482 2 a483 1 return sockopt_set(sopt, &chan->lc_omtu, sizeof(uint16_t)); d486 2 a487 1 return sockopt_set(sopt, &chan->lc_iqos, sizeof(l2cap_qos_t)); d490 2 a491 1 return sockopt_set(sopt, &chan->lc_oqos, sizeof(l2cap_qos_t)); d494 2 a495 1 return sockopt_set(sopt, &chan->lc_flush, sizeof(uint16_t)); d498 2 a499 1 return sockopt_setint(sopt, chan->lc_mode); d505 1 a505 1 return ENOPROTOOPT; @ 1.8.34.1 log @Sync with wrstuden-revivesa-base-2. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.8 2007/04/29 20:23:36 msaitoh Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.8 2007/04/29 20:23:36 msaitoh Exp $"); d410 1 a410 1 * l2cap_setopt(l2cap_channel, sopt) d423 1 a423 1 l2cap_setopt(struct l2cap_channel *chan, const struct sockopt *sopt) d428 1 a428 1 switch (sopt->sopt_name) { d430 1 a430 4 err = sockopt_get(sopt, &mtu, sizeof(mtu)); if (err) break; d441 1 a441 4 err = sockopt_getint(sopt, &mode); if (err) break; d468 1 a468 1 * l2cap_getopt(l2cap_channel, sopt) d473 1 a473 1 l2cap_getopt(struct l2cap_channel *chan, struct sockopt *sopt) d476 1 a476 1 switch (sopt->sopt_name) { d478 2 a479 1 return sockopt_set(sopt, &chan->lc_imtu, sizeof(uint16_t)); d482 2 a483 1 return sockopt_set(sopt, &chan->lc_omtu, sizeof(uint16_t)); d486 2 a487 1 return sockopt_set(sopt, &chan->lc_iqos, sizeof(l2cap_qos_t)); d490 2 a491 1 return sockopt_set(sopt, &chan->lc_oqos, sizeof(l2cap_qos_t)); d494 2 a495 1 return sockopt_set(sopt, &chan->lc_flush, sizeof(uint16_t)); d498 2 a499 1 return sockopt_setint(sopt, chan->lc_mode); d505 1 a505 1 return ENOPROTOOPT; @ 1.7 log @Add 'service level' security for L2CAP and RFCOMM connections, following the Linux (BlueZ) API. - L2CAP or RFCOMM connections can require the baseband radio link mode be any of: authenticated (devices are paired) encrypted (implies authentication) secured (encryption, plus generate new link key) - for sockets, the mode is set using setsockopt(2) and the socket connection will be aborted if the mode change fails. - mode settings will be applied during connection establishment, and for safety, we enter a wait state and will only proceed when the mode settings are successfuly set. - It is possible to change the mode on already open connections, but not possible to guarantee that data already queued (from either end) will not be delivered. (this is a feature, not a bug) - bthidev(4) and rfcomm_sppd(1) support "auth", "encrypt" and "secure" options - btdevctl(8) by default enables "auth" for HIDs, and "encrypt" for keyboards (which are required to support it) @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.6 2007/04/06 17:09:00 plunky Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.6 2007/04/06 17:09:00 plunky Exp $"); d58 1 a58 1 * with with reasonable defaults @ 1.6 log @rework ordering of error conditions for setopt, prefer to return EINVAL rather than EBUSY. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.5 2007/03/30 20:47:03 plunky Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.5 2007/03/30 20:47:03 plunky Exp $"); d179 10 d190 3 a192 3 * We queue a connect request right away even though the link * may not yet be open; the queue will be started automatically * at the right time. d194 1 a194 1 chan->lc_state = L2CAP_WAIT_CONNECT_RSP; d196 2 a197 6 if (err) { chan->lc_state = L2CAP_CLOSED; hci_acl_close(chan->lc_link, err); chan->lc_link = NULL; return err; } d200 6 d410 1 a410 1 * l2cap_setopt(channel, opt, addr) d414 7 d425 1 a425 1 int err = 0; d440 17 d467 5 d497 4 @ 1.5 log @be more explicit and consistent in use of KASSERT with pointers, test against NULL @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.4 2007/03/15 19:47:51 plunky Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.4 2007/03/15 19:47:51 plunky Exp $"); d407 1 a407 9 uint16_t tmp; /* * currently we dont allow changing any options when channel * is other than closed. We could allow this (not sure why?) * but would have to instigate a configure request. */ if (chan->lc_state != L2CAP_CLOSED) return EBUSY; d411 2 a412 2 tmp = *(uint16_t *)addr; if (tmp < L2CAP_MTU_MINIMUM) { d414 4 a417 2 break; } a418 1 chan->lc_imtu = tmp; @ 1.4 log @remove C++ style comments @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.3 2007/03/12 20:34:54 plunky Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.3 2007/03/12 20:34:54 plunky Exp $"); d66 3 a68 3 KASSERT(handle); KASSERT(proto); KASSERT(upper); @ 1.3 log @clean up the mess that is the channel state, now lc_state is channel state lc_flags is channel flags @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.2 2007/03/05 19:11:54 plunky Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.2 2007/03/05 19:11:54 plunky Exp $"); a428 4 // XXX // memcpy(&chan->lc_oqos, addr, sizeof(l2cap_qos_t)); //break; a429 4 // XXX // chan->lc_flush = *(uint16_t *)addr; //break; @ 1.3.2.1 log @First attempt to bring branch in sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.3 2007/03/12 20:34:54 plunky Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.3 2007/03/12 20:34:54 plunky Exp $"); d429 4 d434 4 @ 1.2 log @return ENOPROTOOPT when protocol options are not known @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.1 2006/06/19 15:44:45 gdamore Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.1 2006/06/19 15:44:45 gdamore Exp $"); d227 2 a228 1 if (chan->lc_state & (L2CAP_CLOSED | L2CAP_WAIT_DISCONNECT)) @ 1.2.4.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.8 2007/04/29 20:23:36 msaitoh Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.8 2007/04/29 20:23:36 msaitoh Exp $"); d58 1 a58 1 * with reasonable defaults d66 3 a68 3 KASSERT(handle != NULL); KASSERT(proto != NULL); KASSERT(upper != NULL); a178 10 /* set the link mode */ err = l2cap_setmode(chan); if (err == EINPROGRESS) { chan->lc_state = L2CAP_WAIT_SEND_CONNECT_REQ; (*chan->lc_proto->connecting)(chan->lc_upper); return 0; } if (err) goto fail; d180 3 a182 3 * We can queue a connect request now even though the link may * not yet be open; Our mode setting is assured, and the queue * will be started automatically at the right time. d184 1 a184 1 chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP; d186 6 a191 2 if (err) goto fail; a193 6 fail: chan->lc_state = L2CAP_CLOSED; hci_acl_close(chan->lc_link, err); chan->lc_link = NULL; return err; d227 1 a227 2 if (chan->lc_state == L2CAP_CLOSED || chan->lc_state == L2CAP_WAIT_DISCONNECT) d397 1 a397 1 * l2cap_setopt(l2cap_channel, opt, addr) a400 7 * * for SO_L2CAP_LM, the settings will take effect when the * channel is established. If the channel is already open, * a call to * proto->linkmode(upper, new) * * will be made when the change is complete. d405 10 a414 2 int mode, err = 0; uint16_t mtu; d418 2 a419 2 mtu = *(uint16_t *)addr; if (mtu < L2CAP_MTU_MINIMUM) d421 2 a422 4 else if (chan->lc_state == L2CAP_CLOSED) chan->lc_imtu = mtu; else err = EBUSY; d424 1 d427 4 a430 3 case SO_L2CAP_LM: /* set link mode */ mode = *(int *)addr; mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH); d432 4 a435 2 if (mode & L2CAP_LM_SECURE) mode |= L2CAP_LM_ENCRYPT; a436 12 if (mode & L2CAP_LM_ENCRYPT) mode |= L2CAP_LM_AUTH; chan->lc_mode = mode; if (chan->lc_state == L2CAP_OPEN) err = l2cap_setmode(chan); break; case SO_L2CAP_OQOS: /* set Outgoing QoS flow spec */ case SO_L2CAP_FLUSH: /* set Outgoing Flush Timeout */ a444 5 /* * l2cap_getopt(l2cap_channel, opt, addr) * * Return configuration parameters. */ a469 4 case SO_L2CAP_LM: /* get link mode */ *(int *)addr = chan->lc_mode; return sizeof(int); @ 1.2.2.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.2 2007/03/05 19:11:54 plunky Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.2 2007/03/05 19:11:54 plunky Exp $"); d227 1 a227 2 if (chan->lc_state == L2CAP_CLOSED || chan->lc_state == L2CAP_WAIT_DISCONNECT) @ 1.2.2.2 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.2.2.1 2007/03/13 16:52:01 ad Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.2.2.1 2007/03/13 16:52:01 ad Exp $"); d66 3 a68 3 KASSERT(handle != NULL); KASSERT(proto != NULL); KASSERT(upper != NULL); d407 9 a415 1 uint16_t mtu; d419 2 a420 2 mtu = *(uint16_t *)addr; if (mtu < L2CAP_MTU_MINIMUM) d422 2 a423 4 else if (chan->lc_state == L2CAP_CLOSED) chan->lc_imtu = mtu; else err = EBUSY; d425 1 d429 4 d434 4 @ 1.2.2.3 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.2.2.2 2007/04/10 13:26:48 ad Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.2.2.2 2007/04/10 13:26:48 ad Exp $"); d58 1 a58 1 * with reasonable defaults a178 10 /* set the link mode */ err = l2cap_setmode(chan); if (err == EINPROGRESS) { chan->lc_state = L2CAP_WAIT_SEND_CONNECT_REQ; (*chan->lc_proto->connecting)(chan->lc_upper); return 0; } if (err) goto fail; d180 3 a182 3 * We can queue a connect request now even though the link may * not yet be open; Our mode setting is assured, and the queue * will be started automatically at the right time. d184 1 a184 1 chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP; d186 6 a191 2 if (err) goto fail; a193 6 fail: chan->lc_state = L2CAP_CLOSED; hci_acl_close(chan->lc_link, err); chan->lc_link = NULL; return err; d398 1 a398 1 * l2cap_setopt(l2cap_channel, opt, addr) a401 7 * * for SO_L2CAP_LM, the settings will take effect when the * channel is established. If the channel is already open, * a call to * proto->linkmode(upper, new) * * will be made when the change is complete. d406 1 a406 1 int mode, err = 0; a420 17 case SO_L2CAP_LM: /* set link mode */ mode = *(int *)addr; mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH); if (mode & L2CAP_LM_SECURE) mode |= L2CAP_LM_ENCRYPT; if (mode & L2CAP_LM_ENCRYPT) mode |= L2CAP_LM_AUTH; chan->lc_mode = mode; if (chan->lc_state == L2CAP_OPEN) err = l2cap_setmode(chan); break; a430 5 /* * l2cap_getopt(l2cap_channel, opt, addr) * * Return configuration parameters. */ a455 4 case SO_L2CAP_LM: /* get link mode */ *(int *)addr = chan->lc_mode; return sizeof(int); @ 1.1 log @Initial import of bluetooth stack on behalf of Iain Hibbert. (plunky@@, NetBSD Foundation Membership still pending.) This stack was written by Iain under sponsorship from Itronix Inc. The stack includes support for rfcomm networking (networking via your bluetooth enabled cell phone), hid devices (keyboards/mice), and headsets. Drivers for both PCMCIA and USB bluetooth controllers are included. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c$"); d438 1 a438 1 err = EINVAL; @ 1.1.4.1 log @file l2cap_upper.c was added on branch chap-midi on 2006-06-22 03:39:50 +0000 @ text @d1 475 @ 1.1.4.2 log @Complete a sync sys/ with head. @ text @a0 475 /* $NetBSD: l2cap_upper.c,v 1.1.4.1 2006/06/22 03:39:50 chap Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. * Copyright (c) 2006 Itronix Inc. * 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 Itronix Inc. may not be used to endorse * or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.1.4.1 2006/06/22 03:39:50 chap Exp $"); #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * * L2CAP Channel - Upper Protocol API */ /* * l2cap_attach(handle, btproto, upper) * * attach new l2cap_channel to handle, populate * with with reasonable defaults */ int l2cap_attach(struct l2cap_channel **handle, const struct btproto *proto, void *upper) { struct l2cap_channel *chan; KASSERT(handle); KASSERT(proto); KASSERT(upper); chan = malloc(sizeof(struct l2cap_channel), M_BLUETOOTH, M_NOWAIT | M_ZERO); if (chan == NULL) return ENOMEM; chan->lc_proto = proto; chan->lc_upper = upper; chan->lc_state = L2CAP_CLOSED; chan->lc_lcid = L2CAP_NULL_CID; chan->lc_rcid = L2CAP_NULL_CID; chan->lc_laddr.bt_len = sizeof(struct sockaddr_bt); chan->lc_laddr.bt_family = AF_BLUETOOTH; chan->lc_laddr.bt_psm = L2CAP_PSM_ANY; chan->lc_raddr.bt_len = sizeof(struct sockaddr_bt); chan->lc_raddr.bt_family = AF_BLUETOOTH; chan->lc_raddr.bt_psm = L2CAP_PSM_ANY; chan->lc_imtu = L2CAP_MTU_DEFAULT; chan->lc_omtu = L2CAP_MTU_DEFAULT; chan->lc_flush = L2CAP_FLUSH_TIMO_DEFAULT; memcpy(&chan->lc_iqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); memcpy(&chan->lc_oqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); MBUFQ_INIT(&chan->lc_txq); *handle = chan; return 0; } /* * l2cap_bind(l2cap_channel, sockaddr) * * set local address of channel */ int l2cap_bind(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(&chan->lc_laddr, addr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_sockaddr(l2cap_channel, sockaddr) * * get local address of channel */ int l2cap_sockaddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(addr, &chan->lc_laddr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_connect(l2cap_channel, sockaddr) * * Initiate a connection to destination. This corresponds to * "Open Channel Request" in the L2CAP specification and will * result in one of the following: * * proto->connected(upper) * proto->disconnected(upper, error) * * and, optionally * proto->connecting(upper) */ int l2cap_connect(struct l2cap_channel *chan, struct sockaddr_bt *dest) { struct hci_unit *unit; int err; memcpy(&chan->lc_raddr, dest, sizeof(struct sockaddr_bt)); if (L2CAP_PSM_INVALID(chan->lc_raddr.bt_psm)) return EINVAL; if (bdaddr_any(&chan->lc_raddr.bt_bdaddr)) return EDESTADDRREQ; /* set local address if it needs setting */ if (bdaddr_any(&chan->lc_laddr.bt_bdaddr)) { err = hci_route_lookup(&chan->lc_laddr.bt_bdaddr, &chan->lc_raddr.bt_bdaddr); if (err) return err; } unit = hci_unit_lookup(&chan->lc_laddr.bt_bdaddr); if (unit == NULL) return EHOSTUNREACH; /* attach to active list */ err = l2cap_cid_alloc(chan); if (err) return err; /* open link to remote device */ chan->lc_link = hci_acl_open(unit, &chan->lc_raddr.bt_bdaddr); if (chan->lc_link == NULL) return EHOSTUNREACH; /* * We queue a connect request right away even though the link * may not yet be open; the queue will be started automatically * at the right time. */ chan->lc_state = L2CAP_WAIT_CONNECT_RSP; err = l2cap_send_connect_req(chan); if (err) { chan->lc_state = L2CAP_CLOSED; hci_acl_close(chan->lc_link, err); chan->lc_link = NULL; return err; } return 0; } /* * l2cap_peeraddr(l2cap_channel, sockaddr) * * get remote address of channel */ int l2cap_peeraddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(addr, &chan->lc_raddr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_disconnect(l2cap_channel, linger) * * Initiate L2CAP disconnection. This corresponds to * "Close Channel Request" in the L2CAP specification * and will result in a call to * * proto->disconnected(upper, error) * * when the disconnection is complete. If linger is set, * the call will not be made until data has flushed from * the queue. */ int l2cap_disconnect(struct l2cap_channel *chan, int linger) { int err = 0; if (chan->lc_state & (L2CAP_CLOSED | L2CAP_WAIT_DISCONNECT)) return EINVAL; chan->lc_flags |= L2CAP_SHUTDOWN; /* * no need to do anything unless the queue is empty or * we are not lingering.. */ if ((MBUFQ_FIRST(&chan->lc_txq) == NULL && chan->lc_pending == 0) || linger == 0) { chan->lc_state = L2CAP_WAIT_DISCONNECT; err = l2cap_send_disconnect_req(chan); if (err) l2cap_close(chan, err); } return err; } /* * l2cap_detach(handle) * * Detach l2cap channel from handle & close it down */ int l2cap_detach(struct l2cap_channel **handle) { struct l2cap_channel *chan; chan = *handle; *handle = NULL; if (chan->lc_state != L2CAP_CLOSED) l2cap_close(chan, 0); if (chan->lc_lcid != L2CAP_NULL_CID) { LIST_REMOVE(chan, lc_ncid); chan->lc_lcid = L2CAP_NULL_CID; } MBUFQ_DRAIN(&chan->lc_txq); /* * Could implement some kind of delayed expunge to make sure that the * CID is really dead before it becomes available for reuse? */ free(chan, M_BLUETOOTH); return 0; } /* * l2cap_listen(l2cap_channel) * * Use this channel as a listening post (until detached). This will * result in calls to: * * proto->newconn(upper, laddr, raddr) * * for incoming connections matching the psm and local address of the * channel (NULL psm/address are permitted and match any protocol/device). * * The upper layer should create and return a new channel. * * You cannot use this channel for anything else subsequent to this call */ int l2cap_listen(struct l2cap_channel *chan) { struct l2cap_channel *used, *prev = NULL; if (chan->lc_lcid != L2CAP_NULL_CID) return EINVAL; if (chan->lc_laddr.bt_psm != L2CAP_PSM_ANY && L2CAP_PSM_INVALID(chan->lc_laddr.bt_psm)) return EADDRNOTAVAIL; /* * This CID is irrelevant, as the channel is not stored on the active * list and the socket code does not allow operations on listening * sockets, but we set it so the detach code knows to LIST_REMOVE the * channel. */ chan->lc_lcid = L2CAP_SIGNAL_CID; /* * The list of listening channels is stored in an order such that new * listeners dont usurp current listeners, but that specific listening * takes precedence over promiscuous, and the connect request code can * easily use the first matching entry. */ LIST_FOREACH(used, &l2cap_listen_list, lc_ncid) { if (used->lc_laddr.bt_psm < chan->lc_laddr.bt_psm) break; if (used->lc_laddr.bt_psm == chan->lc_laddr.bt_psm && bdaddr_any(&used->lc_laddr.bt_bdaddr) && !bdaddr_any(&chan->lc_laddr.bt_bdaddr)) break; prev = used; } if (prev == NULL) LIST_INSERT_HEAD(&l2cap_listen_list, chan, lc_ncid); else LIST_INSERT_AFTER(prev, chan, lc_ncid); return 0; } /* * l2cap_send(l2cap_channel, mbuf) * * Output SDU on channel described by channel. This corresponds * to "Send Data Request" in the L2CAP specification. The upper * layer will be notified when SDU's have completed sending by a * call to: * * proto->complete(upper, n) * * (currently n == 1) * * Note: I'm not sure how this will work out, but I think that * if outgoing Retransmission Mode or Flow Control Mode is * negotiated then this call will not be made until the SDU has * been acknowleged by the peer L2CAP entity. For 'Best Effort' * it will be made when the packet has cleared the controller * buffers. * * We only support Basic mode so far, so encapsulate with a * B-Frame header and start sending if we are not already */ int l2cap_send(struct l2cap_channel *chan, struct mbuf *m) { l2cap_hdr_t *hdr; int plen; if (chan->lc_state == L2CAP_CLOSED) { m_freem(m); return ENOTCONN; } plen = m->m_pkthdr.len; DPRINTFN(5, "send %d bytes on CID #%d (pending = %d)\n", plen, chan->lc_lcid, chan->lc_pending); /* Encapsulate with B-Frame */ M_PREPEND(m, sizeof(l2cap_hdr_t), M_DONTWAIT); if (m == NULL) return ENOMEM; hdr = mtod(m, l2cap_hdr_t *); hdr->length = htole16(plen); hdr->dcid = htole16(chan->lc_rcid); /* Queue it on our list */ MBUFQ_ENQUEUE(&chan->lc_txq, m); /* If we are not sending, then start doing so */ if (chan->lc_pending == 0) return l2cap_start(chan); return 0; } /* * l2cap_setopt(channel, opt, addr) * * Apply configuration options to channel. This corresponds to * "Configure Channel Request" in the L2CAP specification. */ int l2cap_setopt(struct l2cap_channel *chan, int opt, void *addr) { int err = 0; uint16_t tmp; /* * currently we dont allow changing any options when channel * is other than closed. We could allow this (not sure why?) * but would have to instigate a configure request. */ if (chan->lc_state != L2CAP_CLOSED) return EBUSY; switch (opt) { case SO_L2CAP_IMTU: /* set Incoming MTU */ tmp = *(uint16_t *)addr; if (tmp < L2CAP_MTU_MINIMUM) { err = EINVAL; break; } chan->lc_imtu = tmp; break; case SO_L2CAP_OQOS: /* set Outgoing QoS flow spec */ // XXX // memcpy(&chan->lc_oqos, addr, sizeof(l2cap_qos_t)); //break; case SO_L2CAP_FLUSH: /* set Outgoing Flush Timeout */ // XXX // chan->lc_flush = *(uint16_t *)addr; //break; default: err = EINVAL; break; } return err; } int l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr) { switch (opt) { case SO_L2CAP_IMTU: /* get Incoming MTU */ *(uint16_t *)addr = chan->lc_imtu; return sizeof(uint16_t); case SO_L2CAP_OMTU: /* get Outgoing MTU */ *(uint16_t *)addr = chan->lc_omtu; return sizeof(uint16_t); case SO_L2CAP_IQOS: /* get Incoming QoS flow spec */ memcpy(addr, &chan->lc_iqos, sizeof(l2cap_qos_t)); return sizeof(l2cap_qos_t); case SO_L2CAP_OQOS: /* get Outgoing QoS flow spec */ memcpy(addr, &chan->lc_oqos, sizeof(l2cap_qos_t)); return sizeof(l2cap_qos_t); case SO_L2CAP_FLUSH: /* get Flush Timeout */ *(uint16_t *)addr = chan->lc_flush; return sizeof(uint16_t); default: break; } return 0; } @ 1.1.8.1 log @file l2cap_upper.c was added on branch gdamore-uart on 2006-07-13 17:49:58 +0000 @ text @d1 475 @ 1.1.8.2 log @Merge from HEAD. @ text @a0 475 /* $NetBSD: l2cap_upper.c,v 1.1.8.1 2006/07/13 17:49:58 gdamore Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. * Copyright (c) 2006 Itronix Inc. * 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 Itronix Inc. may not be used to endorse * or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.1.8.1 2006/07/13 17:49:58 gdamore Exp $"); #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * * L2CAP Channel - Upper Protocol API */ /* * l2cap_attach(handle, btproto, upper) * * attach new l2cap_channel to handle, populate * with with reasonable defaults */ int l2cap_attach(struct l2cap_channel **handle, const struct btproto *proto, void *upper) { struct l2cap_channel *chan; KASSERT(handle); KASSERT(proto); KASSERT(upper); chan = malloc(sizeof(struct l2cap_channel), M_BLUETOOTH, M_NOWAIT | M_ZERO); if (chan == NULL) return ENOMEM; chan->lc_proto = proto; chan->lc_upper = upper; chan->lc_state = L2CAP_CLOSED; chan->lc_lcid = L2CAP_NULL_CID; chan->lc_rcid = L2CAP_NULL_CID; chan->lc_laddr.bt_len = sizeof(struct sockaddr_bt); chan->lc_laddr.bt_family = AF_BLUETOOTH; chan->lc_laddr.bt_psm = L2CAP_PSM_ANY; chan->lc_raddr.bt_len = sizeof(struct sockaddr_bt); chan->lc_raddr.bt_family = AF_BLUETOOTH; chan->lc_raddr.bt_psm = L2CAP_PSM_ANY; chan->lc_imtu = L2CAP_MTU_DEFAULT; chan->lc_omtu = L2CAP_MTU_DEFAULT; chan->lc_flush = L2CAP_FLUSH_TIMO_DEFAULT; memcpy(&chan->lc_iqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); memcpy(&chan->lc_oqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); MBUFQ_INIT(&chan->lc_txq); *handle = chan; return 0; } /* * l2cap_bind(l2cap_channel, sockaddr) * * set local address of channel */ int l2cap_bind(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(&chan->lc_laddr, addr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_sockaddr(l2cap_channel, sockaddr) * * get local address of channel */ int l2cap_sockaddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(addr, &chan->lc_laddr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_connect(l2cap_channel, sockaddr) * * Initiate a connection to destination. This corresponds to * "Open Channel Request" in the L2CAP specification and will * result in one of the following: * * proto->connected(upper) * proto->disconnected(upper, error) * * and, optionally * proto->connecting(upper) */ int l2cap_connect(struct l2cap_channel *chan, struct sockaddr_bt *dest) { struct hci_unit *unit; int err; memcpy(&chan->lc_raddr, dest, sizeof(struct sockaddr_bt)); if (L2CAP_PSM_INVALID(chan->lc_raddr.bt_psm)) return EINVAL; if (bdaddr_any(&chan->lc_raddr.bt_bdaddr)) return EDESTADDRREQ; /* set local address if it needs setting */ if (bdaddr_any(&chan->lc_laddr.bt_bdaddr)) { err = hci_route_lookup(&chan->lc_laddr.bt_bdaddr, &chan->lc_raddr.bt_bdaddr); if (err) return err; } unit = hci_unit_lookup(&chan->lc_laddr.bt_bdaddr); if (unit == NULL) return EHOSTUNREACH; /* attach to active list */ err = l2cap_cid_alloc(chan); if (err) return err; /* open link to remote device */ chan->lc_link = hci_acl_open(unit, &chan->lc_raddr.bt_bdaddr); if (chan->lc_link == NULL) return EHOSTUNREACH; /* * We queue a connect request right away even though the link * may not yet be open; the queue will be started automatically * at the right time. */ chan->lc_state = L2CAP_WAIT_CONNECT_RSP; err = l2cap_send_connect_req(chan); if (err) { chan->lc_state = L2CAP_CLOSED; hci_acl_close(chan->lc_link, err); chan->lc_link = NULL; return err; } return 0; } /* * l2cap_peeraddr(l2cap_channel, sockaddr) * * get remote address of channel */ int l2cap_peeraddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(addr, &chan->lc_raddr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_disconnect(l2cap_channel, linger) * * Initiate L2CAP disconnection. This corresponds to * "Close Channel Request" in the L2CAP specification * and will result in a call to * * proto->disconnected(upper, error) * * when the disconnection is complete. If linger is set, * the call will not be made until data has flushed from * the queue. */ int l2cap_disconnect(struct l2cap_channel *chan, int linger) { int err = 0; if (chan->lc_state & (L2CAP_CLOSED | L2CAP_WAIT_DISCONNECT)) return EINVAL; chan->lc_flags |= L2CAP_SHUTDOWN; /* * no need to do anything unless the queue is empty or * we are not lingering.. */ if ((MBUFQ_FIRST(&chan->lc_txq) == NULL && chan->lc_pending == 0) || linger == 0) { chan->lc_state = L2CAP_WAIT_DISCONNECT; err = l2cap_send_disconnect_req(chan); if (err) l2cap_close(chan, err); } return err; } /* * l2cap_detach(handle) * * Detach l2cap channel from handle & close it down */ int l2cap_detach(struct l2cap_channel **handle) { struct l2cap_channel *chan; chan = *handle; *handle = NULL; if (chan->lc_state != L2CAP_CLOSED) l2cap_close(chan, 0); if (chan->lc_lcid != L2CAP_NULL_CID) { LIST_REMOVE(chan, lc_ncid); chan->lc_lcid = L2CAP_NULL_CID; } MBUFQ_DRAIN(&chan->lc_txq); /* * Could implement some kind of delayed expunge to make sure that the * CID is really dead before it becomes available for reuse? */ free(chan, M_BLUETOOTH); return 0; } /* * l2cap_listen(l2cap_channel) * * Use this channel as a listening post (until detached). This will * result in calls to: * * proto->newconn(upper, laddr, raddr) * * for incoming connections matching the psm and local address of the * channel (NULL psm/address are permitted and match any protocol/device). * * The upper layer should create and return a new channel. * * You cannot use this channel for anything else subsequent to this call */ int l2cap_listen(struct l2cap_channel *chan) { struct l2cap_channel *used, *prev = NULL; if (chan->lc_lcid != L2CAP_NULL_CID) return EINVAL; if (chan->lc_laddr.bt_psm != L2CAP_PSM_ANY && L2CAP_PSM_INVALID(chan->lc_laddr.bt_psm)) return EADDRNOTAVAIL; /* * This CID is irrelevant, as the channel is not stored on the active * list and the socket code does not allow operations on listening * sockets, but we set it so the detach code knows to LIST_REMOVE the * channel. */ chan->lc_lcid = L2CAP_SIGNAL_CID; /* * The list of listening channels is stored in an order such that new * listeners dont usurp current listeners, but that specific listening * takes precedence over promiscuous, and the connect request code can * easily use the first matching entry. */ LIST_FOREACH(used, &l2cap_listen_list, lc_ncid) { if (used->lc_laddr.bt_psm < chan->lc_laddr.bt_psm) break; if (used->lc_laddr.bt_psm == chan->lc_laddr.bt_psm && bdaddr_any(&used->lc_laddr.bt_bdaddr) && !bdaddr_any(&chan->lc_laddr.bt_bdaddr)) break; prev = used; } if (prev == NULL) LIST_INSERT_HEAD(&l2cap_listen_list, chan, lc_ncid); else LIST_INSERT_AFTER(prev, chan, lc_ncid); return 0; } /* * l2cap_send(l2cap_channel, mbuf) * * Output SDU on channel described by channel. This corresponds * to "Send Data Request" in the L2CAP specification. The upper * layer will be notified when SDU's have completed sending by a * call to: * * proto->complete(upper, n) * * (currently n == 1) * * Note: I'm not sure how this will work out, but I think that * if outgoing Retransmission Mode or Flow Control Mode is * negotiated then this call will not be made until the SDU has * been acknowleged by the peer L2CAP entity. For 'Best Effort' * it will be made when the packet has cleared the controller * buffers. * * We only support Basic mode so far, so encapsulate with a * B-Frame header and start sending if we are not already */ int l2cap_send(struct l2cap_channel *chan, struct mbuf *m) { l2cap_hdr_t *hdr; int plen; if (chan->lc_state == L2CAP_CLOSED) { m_freem(m); return ENOTCONN; } plen = m->m_pkthdr.len; DPRINTFN(5, "send %d bytes on CID #%d (pending = %d)\n", plen, chan->lc_lcid, chan->lc_pending); /* Encapsulate with B-Frame */ M_PREPEND(m, sizeof(l2cap_hdr_t), M_DONTWAIT); if (m == NULL) return ENOMEM; hdr = mtod(m, l2cap_hdr_t *); hdr->length = htole16(plen); hdr->dcid = htole16(chan->lc_rcid); /* Queue it on our list */ MBUFQ_ENQUEUE(&chan->lc_txq, m); /* If we are not sending, then start doing so */ if (chan->lc_pending == 0) return l2cap_start(chan); return 0; } /* * l2cap_setopt(channel, opt, addr) * * Apply configuration options to channel. This corresponds to * "Configure Channel Request" in the L2CAP specification. */ int l2cap_setopt(struct l2cap_channel *chan, int opt, void *addr) { int err = 0; uint16_t tmp; /* * currently we dont allow changing any options when channel * is other than closed. We could allow this (not sure why?) * but would have to instigate a configure request. */ if (chan->lc_state != L2CAP_CLOSED) return EBUSY; switch (opt) { case SO_L2CAP_IMTU: /* set Incoming MTU */ tmp = *(uint16_t *)addr; if (tmp < L2CAP_MTU_MINIMUM) { err = EINVAL; break; } chan->lc_imtu = tmp; break; case SO_L2CAP_OQOS: /* set Outgoing QoS flow spec */ // XXX // memcpy(&chan->lc_oqos, addr, sizeof(l2cap_qos_t)); //break; case SO_L2CAP_FLUSH: /* set Outgoing Flush Timeout */ // XXX // chan->lc_flush = *(uint16_t *)addr; //break; default: err = EINVAL; break; } return err; } int l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr) { switch (opt) { case SO_L2CAP_IMTU: /* get Incoming MTU */ *(uint16_t *)addr = chan->lc_imtu; return sizeof(uint16_t); case SO_L2CAP_OMTU: /* get Outgoing MTU */ *(uint16_t *)addr = chan->lc_omtu; return sizeof(uint16_t); case SO_L2CAP_IQOS: /* get Incoming QoS flow spec */ memcpy(addr, &chan->lc_iqos, sizeof(l2cap_qos_t)); return sizeof(l2cap_qos_t); case SO_L2CAP_OQOS: /* get Outgoing QoS flow spec */ memcpy(addr, &chan->lc_oqos, sizeof(l2cap_qos_t)); return sizeof(l2cap_qos_t); case SO_L2CAP_FLUSH: /* get Flush Timeout */ *(uint16_t *)addr = chan->lc_flush; return sizeof(uint16_t); default: break; } return 0; } @ 1.1.6.1 log @file l2cap_upper.c was added on branch yamt-pdpolicy on 2006-06-26 12:53:57 +0000 @ text @d1 475 @ 1.1.6.2 log @sync with head. @ text @a0 475 /* $NetBSD: l2cap_upper.c,v 1.1.6.1 2006/06/26 12:53:57 yamt Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. * Copyright (c) 2006 Itronix Inc. * 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 Itronix Inc. may not be used to endorse * or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.1.6.1 2006/06/26 12:53:57 yamt Exp $"); #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * * L2CAP Channel - Upper Protocol API */ /* * l2cap_attach(handle, btproto, upper) * * attach new l2cap_channel to handle, populate * with with reasonable defaults */ int l2cap_attach(struct l2cap_channel **handle, const struct btproto *proto, void *upper) { struct l2cap_channel *chan; KASSERT(handle); KASSERT(proto); KASSERT(upper); chan = malloc(sizeof(struct l2cap_channel), M_BLUETOOTH, M_NOWAIT | M_ZERO); if (chan == NULL) return ENOMEM; chan->lc_proto = proto; chan->lc_upper = upper; chan->lc_state = L2CAP_CLOSED; chan->lc_lcid = L2CAP_NULL_CID; chan->lc_rcid = L2CAP_NULL_CID; chan->lc_laddr.bt_len = sizeof(struct sockaddr_bt); chan->lc_laddr.bt_family = AF_BLUETOOTH; chan->lc_laddr.bt_psm = L2CAP_PSM_ANY; chan->lc_raddr.bt_len = sizeof(struct sockaddr_bt); chan->lc_raddr.bt_family = AF_BLUETOOTH; chan->lc_raddr.bt_psm = L2CAP_PSM_ANY; chan->lc_imtu = L2CAP_MTU_DEFAULT; chan->lc_omtu = L2CAP_MTU_DEFAULT; chan->lc_flush = L2CAP_FLUSH_TIMO_DEFAULT; memcpy(&chan->lc_iqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); memcpy(&chan->lc_oqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); MBUFQ_INIT(&chan->lc_txq); *handle = chan; return 0; } /* * l2cap_bind(l2cap_channel, sockaddr) * * set local address of channel */ int l2cap_bind(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(&chan->lc_laddr, addr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_sockaddr(l2cap_channel, sockaddr) * * get local address of channel */ int l2cap_sockaddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(addr, &chan->lc_laddr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_connect(l2cap_channel, sockaddr) * * Initiate a connection to destination. This corresponds to * "Open Channel Request" in the L2CAP specification and will * result in one of the following: * * proto->connected(upper) * proto->disconnected(upper, error) * * and, optionally * proto->connecting(upper) */ int l2cap_connect(struct l2cap_channel *chan, struct sockaddr_bt *dest) { struct hci_unit *unit; int err; memcpy(&chan->lc_raddr, dest, sizeof(struct sockaddr_bt)); if (L2CAP_PSM_INVALID(chan->lc_raddr.bt_psm)) return EINVAL; if (bdaddr_any(&chan->lc_raddr.bt_bdaddr)) return EDESTADDRREQ; /* set local address if it needs setting */ if (bdaddr_any(&chan->lc_laddr.bt_bdaddr)) { err = hci_route_lookup(&chan->lc_laddr.bt_bdaddr, &chan->lc_raddr.bt_bdaddr); if (err) return err; } unit = hci_unit_lookup(&chan->lc_laddr.bt_bdaddr); if (unit == NULL) return EHOSTUNREACH; /* attach to active list */ err = l2cap_cid_alloc(chan); if (err) return err; /* open link to remote device */ chan->lc_link = hci_acl_open(unit, &chan->lc_raddr.bt_bdaddr); if (chan->lc_link == NULL) return EHOSTUNREACH; /* * We queue a connect request right away even though the link * may not yet be open; the queue will be started automatically * at the right time. */ chan->lc_state = L2CAP_WAIT_CONNECT_RSP; err = l2cap_send_connect_req(chan); if (err) { chan->lc_state = L2CAP_CLOSED; hci_acl_close(chan->lc_link, err); chan->lc_link = NULL; return err; } return 0; } /* * l2cap_peeraddr(l2cap_channel, sockaddr) * * get remote address of channel */ int l2cap_peeraddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(addr, &chan->lc_raddr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_disconnect(l2cap_channel, linger) * * Initiate L2CAP disconnection. This corresponds to * "Close Channel Request" in the L2CAP specification * and will result in a call to * * proto->disconnected(upper, error) * * when the disconnection is complete. If linger is set, * the call will not be made until data has flushed from * the queue. */ int l2cap_disconnect(struct l2cap_channel *chan, int linger) { int err = 0; if (chan->lc_state & (L2CAP_CLOSED | L2CAP_WAIT_DISCONNECT)) return EINVAL; chan->lc_flags |= L2CAP_SHUTDOWN; /* * no need to do anything unless the queue is empty or * we are not lingering.. */ if ((MBUFQ_FIRST(&chan->lc_txq) == NULL && chan->lc_pending == 0) || linger == 0) { chan->lc_state = L2CAP_WAIT_DISCONNECT; err = l2cap_send_disconnect_req(chan); if (err) l2cap_close(chan, err); } return err; } /* * l2cap_detach(handle) * * Detach l2cap channel from handle & close it down */ int l2cap_detach(struct l2cap_channel **handle) { struct l2cap_channel *chan; chan = *handle; *handle = NULL; if (chan->lc_state != L2CAP_CLOSED) l2cap_close(chan, 0); if (chan->lc_lcid != L2CAP_NULL_CID) { LIST_REMOVE(chan, lc_ncid); chan->lc_lcid = L2CAP_NULL_CID; } MBUFQ_DRAIN(&chan->lc_txq); /* * Could implement some kind of delayed expunge to make sure that the * CID is really dead before it becomes available for reuse? */ free(chan, M_BLUETOOTH); return 0; } /* * l2cap_listen(l2cap_channel) * * Use this channel as a listening post (until detached). This will * result in calls to: * * proto->newconn(upper, laddr, raddr) * * for incoming connections matching the psm and local address of the * channel (NULL psm/address are permitted and match any protocol/device). * * The upper layer should create and return a new channel. * * You cannot use this channel for anything else subsequent to this call */ int l2cap_listen(struct l2cap_channel *chan) { struct l2cap_channel *used, *prev = NULL; if (chan->lc_lcid != L2CAP_NULL_CID) return EINVAL; if (chan->lc_laddr.bt_psm != L2CAP_PSM_ANY && L2CAP_PSM_INVALID(chan->lc_laddr.bt_psm)) return EADDRNOTAVAIL; /* * This CID is irrelevant, as the channel is not stored on the active * list and the socket code does not allow operations on listening * sockets, but we set it so the detach code knows to LIST_REMOVE the * channel. */ chan->lc_lcid = L2CAP_SIGNAL_CID; /* * The list of listening channels is stored in an order such that new * listeners dont usurp current listeners, but that specific listening * takes precedence over promiscuous, and the connect request code can * easily use the first matching entry. */ LIST_FOREACH(used, &l2cap_listen_list, lc_ncid) { if (used->lc_laddr.bt_psm < chan->lc_laddr.bt_psm) break; if (used->lc_laddr.bt_psm == chan->lc_laddr.bt_psm && bdaddr_any(&used->lc_laddr.bt_bdaddr) && !bdaddr_any(&chan->lc_laddr.bt_bdaddr)) break; prev = used; } if (prev == NULL) LIST_INSERT_HEAD(&l2cap_listen_list, chan, lc_ncid); else LIST_INSERT_AFTER(prev, chan, lc_ncid); return 0; } /* * l2cap_send(l2cap_channel, mbuf) * * Output SDU on channel described by channel. This corresponds * to "Send Data Request" in the L2CAP specification. The upper * layer will be notified when SDU's have completed sending by a * call to: * * proto->complete(upper, n) * * (currently n == 1) * * Note: I'm not sure how this will work out, but I think that * if outgoing Retransmission Mode or Flow Control Mode is * negotiated then this call will not be made until the SDU has * been acknowleged by the peer L2CAP entity. For 'Best Effort' * it will be made when the packet has cleared the controller * buffers. * * We only support Basic mode so far, so encapsulate with a * B-Frame header and start sending if we are not already */ int l2cap_send(struct l2cap_channel *chan, struct mbuf *m) { l2cap_hdr_t *hdr; int plen; if (chan->lc_state == L2CAP_CLOSED) { m_freem(m); return ENOTCONN; } plen = m->m_pkthdr.len; DPRINTFN(5, "send %d bytes on CID #%d (pending = %d)\n", plen, chan->lc_lcid, chan->lc_pending); /* Encapsulate with B-Frame */ M_PREPEND(m, sizeof(l2cap_hdr_t), M_DONTWAIT); if (m == NULL) return ENOMEM; hdr = mtod(m, l2cap_hdr_t *); hdr->length = htole16(plen); hdr->dcid = htole16(chan->lc_rcid); /* Queue it on our list */ MBUFQ_ENQUEUE(&chan->lc_txq, m); /* If we are not sending, then start doing so */ if (chan->lc_pending == 0) return l2cap_start(chan); return 0; } /* * l2cap_setopt(channel, opt, addr) * * Apply configuration options to channel. This corresponds to * "Configure Channel Request" in the L2CAP specification. */ int l2cap_setopt(struct l2cap_channel *chan, int opt, void *addr) { int err = 0; uint16_t tmp; /* * currently we dont allow changing any options when channel * is other than closed. We could allow this (not sure why?) * but would have to instigate a configure request. */ if (chan->lc_state != L2CAP_CLOSED) return EBUSY; switch (opt) { case SO_L2CAP_IMTU: /* set Incoming MTU */ tmp = *(uint16_t *)addr; if (tmp < L2CAP_MTU_MINIMUM) { err = EINVAL; break; } chan->lc_imtu = tmp; break; case SO_L2CAP_OQOS: /* set Outgoing QoS flow spec */ // XXX // memcpy(&chan->lc_oqos, addr, sizeof(l2cap_qos_t)); //break; case SO_L2CAP_FLUSH: /* set Outgoing Flush Timeout */ // XXX // chan->lc_flush = *(uint16_t *)addr; //break; default: err = EINVAL; break; } return err; } int l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr) { switch (opt) { case SO_L2CAP_IMTU: /* get Incoming MTU */ *(uint16_t *)addr = chan->lc_imtu; return sizeof(uint16_t); case SO_L2CAP_OMTU: /* get Outgoing MTU */ *(uint16_t *)addr = chan->lc_omtu; return sizeof(uint16_t); case SO_L2CAP_IQOS: /* get Incoming QoS flow spec */ memcpy(addr, &chan->lc_iqos, sizeof(l2cap_qos_t)); return sizeof(l2cap_qos_t); case SO_L2CAP_OQOS: /* get Outgoing QoS flow spec */ memcpy(addr, &chan->lc_oqos, sizeof(l2cap_qos_t)); return sizeof(l2cap_qos_t); case SO_L2CAP_FLUSH: /* get Flush Timeout */ *(uint16_t *)addr = chan->lc_flush; return sizeof(uint16_t); default: break; } return 0; } @ 1.1.14.1 log @file l2cap_upper.c was added on branch rpaulo-netinet-merge-pcb on 2006-09-09 02:58:39 +0000 @ text @d1 475 @ 1.1.14.2 log @sync with head @ text @a0 475 /* $NetBSD: l2cap_upper.c,v 1.1.14.1 2006/09/09 02:58:39 rpaulo Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. * Copyright (c) 2006 Itronix Inc. * 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 Itronix Inc. may not be used to endorse * or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.1.14.1 2006/09/09 02:58:39 rpaulo Exp $"); #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * * L2CAP Channel - Upper Protocol API */ /* * l2cap_attach(handle, btproto, upper) * * attach new l2cap_channel to handle, populate * with with reasonable defaults */ int l2cap_attach(struct l2cap_channel **handle, const struct btproto *proto, void *upper) { struct l2cap_channel *chan; KASSERT(handle); KASSERT(proto); KASSERT(upper); chan = malloc(sizeof(struct l2cap_channel), M_BLUETOOTH, M_NOWAIT | M_ZERO); if (chan == NULL) return ENOMEM; chan->lc_proto = proto; chan->lc_upper = upper; chan->lc_state = L2CAP_CLOSED; chan->lc_lcid = L2CAP_NULL_CID; chan->lc_rcid = L2CAP_NULL_CID; chan->lc_laddr.bt_len = sizeof(struct sockaddr_bt); chan->lc_laddr.bt_family = AF_BLUETOOTH; chan->lc_laddr.bt_psm = L2CAP_PSM_ANY; chan->lc_raddr.bt_len = sizeof(struct sockaddr_bt); chan->lc_raddr.bt_family = AF_BLUETOOTH; chan->lc_raddr.bt_psm = L2CAP_PSM_ANY; chan->lc_imtu = L2CAP_MTU_DEFAULT; chan->lc_omtu = L2CAP_MTU_DEFAULT; chan->lc_flush = L2CAP_FLUSH_TIMO_DEFAULT; memcpy(&chan->lc_iqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); memcpy(&chan->lc_oqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); MBUFQ_INIT(&chan->lc_txq); *handle = chan; return 0; } /* * l2cap_bind(l2cap_channel, sockaddr) * * set local address of channel */ int l2cap_bind(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(&chan->lc_laddr, addr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_sockaddr(l2cap_channel, sockaddr) * * get local address of channel */ int l2cap_sockaddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(addr, &chan->lc_laddr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_connect(l2cap_channel, sockaddr) * * Initiate a connection to destination. This corresponds to * "Open Channel Request" in the L2CAP specification and will * result in one of the following: * * proto->connected(upper) * proto->disconnected(upper, error) * * and, optionally * proto->connecting(upper) */ int l2cap_connect(struct l2cap_channel *chan, struct sockaddr_bt *dest) { struct hci_unit *unit; int err; memcpy(&chan->lc_raddr, dest, sizeof(struct sockaddr_bt)); if (L2CAP_PSM_INVALID(chan->lc_raddr.bt_psm)) return EINVAL; if (bdaddr_any(&chan->lc_raddr.bt_bdaddr)) return EDESTADDRREQ; /* set local address if it needs setting */ if (bdaddr_any(&chan->lc_laddr.bt_bdaddr)) { err = hci_route_lookup(&chan->lc_laddr.bt_bdaddr, &chan->lc_raddr.bt_bdaddr); if (err) return err; } unit = hci_unit_lookup(&chan->lc_laddr.bt_bdaddr); if (unit == NULL) return EHOSTUNREACH; /* attach to active list */ err = l2cap_cid_alloc(chan); if (err) return err; /* open link to remote device */ chan->lc_link = hci_acl_open(unit, &chan->lc_raddr.bt_bdaddr); if (chan->lc_link == NULL) return EHOSTUNREACH; /* * We queue a connect request right away even though the link * may not yet be open; the queue will be started automatically * at the right time. */ chan->lc_state = L2CAP_WAIT_CONNECT_RSP; err = l2cap_send_connect_req(chan); if (err) { chan->lc_state = L2CAP_CLOSED; hci_acl_close(chan->lc_link, err); chan->lc_link = NULL; return err; } return 0; } /* * l2cap_peeraddr(l2cap_channel, sockaddr) * * get remote address of channel */ int l2cap_peeraddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(addr, &chan->lc_raddr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_disconnect(l2cap_channel, linger) * * Initiate L2CAP disconnection. This corresponds to * "Close Channel Request" in the L2CAP specification * and will result in a call to * * proto->disconnected(upper, error) * * when the disconnection is complete. If linger is set, * the call will not be made until data has flushed from * the queue. */ int l2cap_disconnect(struct l2cap_channel *chan, int linger) { int err = 0; if (chan->lc_state & (L2CAP_CLOSED | L2CAP_WAIT_DISCONNECT)) return EINVAL; chan->lc_flags |= L2CAP_SHUTDOWN; /* * no need to do anything unless the queue is empty or * we are not lingering.. */ if ((MBUFQ_FIRST(&chan->lc_txq) == NULL && chan->lc_pending == 0) || linger == 0) { chan->lc_state = L2CAP_WAIT_DISCONNECT; err = l2cap_send_disconnect_req(chan); if (err) l2cap_close(chan, err); } return err; } /* * l2cap_detach(handle) * * Detach l2cap channel from handle & close it down */ int l2cap_detach(struct l2cap_channel **handle) { struct l2cap_channel *chan; chan = *handle; *handle = NULL; if (chan->lc_state != L2CAP_CLOSED) l2cap_close(chan, 0); if (chan->lc_lcid != L2CAP_NULL_CID) { LIST_REMOVE(chan, lc_ncid); chan->lc_lcid = L2CAP_NULL_CID; } MBUFQ_DRAIN(&chan->lc_txq); /* * Could implement some kind of delayed expunge to make sure that the * CID is really dead before it becomes available for reuse? */ free(chan, M_BLUETOOTH); return 0; } /* * l2cap_listen(l2cap_channel) * * Use this channel as a listening post (until detached). This will * result in calls to: * * proto->newconn(upper, laddr, raddr) * * for incoming connections matching the psm and local address of the * channel (NULL psm/address are permitted and match any protocol/device). * * The upper layer should create and return a new channel. * * You cannot use this channel for anything else subsequent to this call */ int l2cap_listen(struct l2cap_channel *chan) { struct l2cap_channel *used, *prev = NULL; if (chan->lc_lcid != L2CAP_NULL_CID) return EINVAL; if (chan->lc_laddr.bt_psm != L2CAP_PSM_ANY && L2CAP_PSM_INVALID(chan->lc_laddr.bt_psm)) return EADDRNOTAVAIL; /* * This CID is irrelevant, as the channel is not stored on the active * list and the socket code does not allow operations on listening * sockets, but we set it so the detach code knows to LIST_REMOVE the * channel. */ chan->lc_lcid = L2CAP_SIGNAL_CID; /* * The list of listening channels is stored in an order such that new * listeners dont usurp current listeners, but that specific listening * takes precedence over promiscuous, and the connect request code can * easily use the first matching entry. */ LIST_FOREACH(used, &l2cap_listen_list, lc_ncid) { if (used->lc_laddr.bt_psm < chan->lc_laddr.bt_psm) break; if (used->lc_laddr.bt_psm == chan->lc_laddr.bt_psm && bdaddr_any(&used->lc_laddr.bt_bdaddr) && !bdaddr_any(&chan->lc_laddr.bt_bdaddr)) break; prev = used; } if (prev == NULL) LIST_INSERT_HEAD(&l2cap_listen_list, chan, lc_ncid); else LIST_INSERT_AFTER(prev, chan, lc_ncid); return 0; } /* * l2cap_send(l2cap_channel, mbuf) * * Output SDU on channel described by channel. This corresponds * to "Send Data Request" in the L2CAP specification. The upper * layer will be notified when SDU's have completed sending by a * call to: * * proto->complete(upper, n) * * (currently n == 1) * * Note: I'm not sure how this will work out, but I think that * if outgoing Retransmission Mode or Flow Control Mode is * negotiated then this call will not be made until the SDU has * been acknowleged by the peer L2CAP entity. For 'Best Effort' * it will be made when the packet has cleared the controller * buffers. * * We only support Basic mode so far, so encapsulate with a * B-Frame header and start sending if we are not already */ int l2cap_send(struct l2cap_channel *chan, struct mbuf *m) { l2cap_hdr_t *hdr; int plen; if (chan->lc_state == L2CAP_CLOSED) { m_freem(m); return ENOTCONN; } plen = m->m_pkthdr.len; DPRINTFN(5, "send %d bytes on CID #%d (pending = %d)\n", plen, chan->lc_lcid, chan->lc_pending); /* Encapsulate with B-Frame */ M_PREPEND(m, sizeof(l2cap_hdr_t), M_DONTWAIT); if (m == NULL) return ENOMEM; hdr = mtod(m, l2cap_hdr_t *); hdr->length = htole16(plen); hdr->dcid = htole16(chan->lc_rcid); /* Queue it on our list */ MBUFQ_ENQUEUE(&chan->lc_txq, m); /* If we are not sending, then start doing so */ if (chan->lc_pending == 0) return l2cap_start(chan); return 0; } /* * l2cap_setopt(channel, opt, addr) * * Apply configuration options to channel. This corresponds to * "Configure Channel Request" in the L2CAP specification. */ int l2cap_setopt(struct l2cap_channel *chan, int opt, void *addr) { int err = 0; uint16_t tmp; /* * currently we dont allow changing any options when channel * is other than closed. We could allow this (not sure why?) * but would have to instigate a configure request. */ if (chan->lc_state != L2CAP_CLOSED) return EBUSY; switch (opt) { case SO_L2CAP_IMTU: /* set Incoming MTU */ tmp = *(uint16_t *)addr; if (tmp < L2CAP_MTU_MINIMUM) { err = EINVAL; break; } chan->lc_imtu = tmp; break; case SO_L2CAP_OQOS: /* set Outgoing QoS flow spec */ // XXX // memcpy(&chan->lc_oqos, addr, sizeof(l2cap_qos_t)); //break; case SO_L2CAP_FLUSH: /* set Outgoing Flush Timeout */ // XXX // chan->lc_flush = *(uint16_t *)addr; //break; default: err = EINVAL; break; } return err; } int l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr) { switch (opt) { case SO_L2CAP_IMTU: /* get Incoming MTU */ *(uint16_t *)addr = chan->lc_imtu; return sizeof(uint16_t); case SO_L2CAP_OMTU: /* get Outgoing MTU */ *(uint16_t *)addr = chan->lc_omtu; return sizeof(uint16_t); case SO_L2CAP_IQOS: /* get Incoming QoS flow spec */ memcpy(addr, &chan->lc_iqos, sizeof(l2cap_qos_t)); return sizeof(l2cap_qos_t); case SO_L2CAP_OQOS: /* get Outgoing QoS flow spec */ memcpy(addr, &chan->lc_oqos, sizeof(l2cap_qos_t)); return sizeof(l2cap_qos_t); case SO_L2CAP_FLUSH: /* get Flush Timeout */ *(uint16_t *)addr = chan->lc_flush; return sizeof(uint16_t); default: break; } return 0; } @ 1.1.2.1 log @file l2cap_upper.c was added on branch yamt-lazymbuf on 2006-06-21 15:10:51 +0000 @ text @d1 475 @ 1.1.2.2 log @sync with head. @ text @a0 475 /* $NetBSD: l2cap_upper.c,v 1.1.2.1 2006/06/21 15:10:51 yamt Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. * Copyright (c) 2006 Itronix Inc. * 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 Itronix Inc. may not be used to endorse * or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.1.2.1 2006/06/21 15:10:51 yamt Exp $"); #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * * L2CAP Channel - Upper Protocol API */ /* * l2cap_attach(handle, btproto, upper) * * attach new l2cap_channel to handle, populate * with with reasonable defaults */ int l2cap_attach(struct l2cap_channel **handle, const struct btproto *proto, void *upper) { struct l2cap_channel *chan; KASSERT(handle); KASSERT(proto); KASSERT(upper); chan = malloc(sizeof(struct l2cap_channel), M_BLUETOOTH, M_NOWAIT | M_ZERO); if (chan == NULL) return ENOMEM; chan->lc_proto = proto; chan->lc_upper = upper; chan->lc_state = L2CAP_CLOSED; chan->lc_lcid = L2CAP_NULL_CID; chan->lc_rcid = L2CAP_NULL_CID; chan->lc_laddr.bt_len = sizeof(struct sockaddr_bt); chan->lc_laddr.bt_family = AF_BLUETOOTH; chan->lc_laddr.bt_psm = L2CAP_PSM_ANY; chan->lc_raddr.bt_len = sizeof(struct sockaddr_bt); chan->lc_raddr.bt_family = AF_BLUETOOTH; chan->lc_raddr.bt_psm = L2CAP_PSM_ANY; chan->lc_imtu = L2CAP_MTU_DEFAULT; chan->lc_omtu = L2CAP_MTU_DEFAULT; chan->lc_flush = L2CAP_FLUSH_TIMO_DEFAULT; memcpy(&chan->lc_iqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); memcpy(&chan->lc_oqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); MBUFQ_INIT(&chan->lc_txq); *handle = chan; return 0; } /* * l2cap_bind(l2cap_channel, sockaddr) * * set local address of channel */ int l2cap_bind(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(&chan->lc_laddr, addr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_sockaddr(l2cap_channel, sockaddr) * * get local address of channel */ int l2cap_sockaddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(addr, &chan->lc_laddr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_connect(l2cap_channel, sockaddr) * * Initiate a connection to destination. This corresponds to * "Open Channel Request" in the L2CAP specification and will * result in one of the following: * * proto->connected(upper) * proto->disconnected(upper, error) * * and, optionally * proto->connecting(upper) */ int l2cap_connect(struct l2cap_channel *chan, struct sockaddr_bt *dest) { struct hci_unit *unit; int err; memcpy(&chan->lc_raddr, dest, sizeof(struct sockaddr_bt)); if (L2CAP_PSM_INVALID(chan->lc_raddr.bt_psm)) return EINVAL; if (bdaddr_any(&chan->lc_raddr.bt_bdaddr)) return EDESTADDRREQ; /* set local address if it needs setting */ if (bdaddr_any(&chan->lc_laddr.bt_bdaddr)) { err = hci_route_lookup(&chan->lc_laddr.bt_bdaddr, &chan->lc_raddr.bt_bdaddr); if (err) return err; } unit = hci_unit_lookup(&chan->lc_laddr.bt_bdaddr); if (unit == NULL) return EHOSTUNREACH; /* attach to active list */ err = l2cap_cid_alloc(chan); if (err) return err; /* open link to remote device */ chan->lc_link = hci_acl_open(unit, &chan->lc_raddr.bt_bdaddr); if (chan->lc_link == NULL) return EHOSTUNREACH; /* * We queue a connect request right away even though the link * may not yet be open; the queue will be started automatically * at the right time. */ chan->lc_state = L2CAP_WAIT_CONNECT_RSP; err = l2cap_send_connect_req(chan); if (err) { chan->lc_state = L2CAP_CLOSED; hci_acl_close(chan->lc_link, err); chan->lc_link = NULL; return err; } return 0; } /* * l2cap_peeraddr(l2cap_channel, sockaddr) * * get remote address of channel */ int l2cap_peeraddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) { memcpy(addr, &chan->lc_raddr, sizeof(struct sockaddr_bt)); return 0; } /* * l2cap_disconnect(l2cap_channel, linger) * * Initiate L2CAP disconnection. This corresponds to * "Close Channel Request" in the L2CAP specification * and will result in a call to * * proto->disconnected(upper, error) * * when the disconnection is complete. If linger is set, * the call will not be made until data has flushed from * the queue. */ int l2cap_disconnect(struct l2cap_channel *chan, int linger) { int err = 0; if (chan->lc_state & (L2CAP_CLOSED | L2CAP_WAIT_DISCONNECT)) return EINVAL; chan->lc_flags |= L2CAP_SHUTDOWN; /* * no need to do anything unless the queue is empty or * we are not lingering.. */ if ((MBUFQ_FIRST(&chan->lc_txq) == NULL && chan->lc_pending == 0) || linger == 0) { chan->lc_state = L2CAP_WAIT_DISCONNECT; err = l2cap_send_disconnect_req(chan); if (err) l2cap_close(chan, err); } return err; } /* * l2cap_detach(handle) * * Detach l2cap channel from handle & close it down */ int l2cap_detach(struct l2cap_channel **handle) { struct l2cap_channel *chan; chan = *handle; *handle = NULL; if (chan->lc_state != L2CAP_CLOSED) l2cap_close(chan, 0); if (chan->lc_lcid != L2CAP_NULL_CID) { LIST_REMOVE(chan, lc_ncid); chan->lc_lcid = L2CAP_NULL_CID; } MBUFQ_DRAIN(&chan->lc_txq); /* * Could implement some kind of delayed expunge to make sure that the * CID is really dead before it becomes available for reuse? */ free(chan, M_BLUETOOTH); return 0; } /* * l2cap_listen(l2cap_channel) * * Use this channel as a listening post (until detached). This will * result in calls to: * * proto->newconn(upper, laddr, raddr) * * for incoming connections matching the psm and local address of the * channel (NULL psm/address are permitted and match any protocol/device). * * The upper layer should create and return a new channel. * * You cannot use this channel for anything else subsequent to this call */ int l2cap_listen(struct l2cap_channel *chan) { struct l2cap_channel *used, *prev = NULL; if (chan->lc_lcid != L2CAP_NULL_CID) return EINVAL; if (chan->lc_laddr.bt_psm != L2CAP_PSM_ANY && L2CAP_PSM_INVALID(chan->lc_laddr.bt_psm)) return EADDRNOTAVAIL; /* * This CID is irrelevant, as the channel is not stored on the active * list and the socket code does not allow operations on listening * sockets, but we set it so the detach code knows to LIST_REMOVE the * channel. */ chan->lc_lcid = L2CAP_SIGNAL_CID; /* * The list of listening channels is stored in an order such that new * listeners dont usurp current listeners, but that specific listening * takes precedence over promiscuous, and the connect request code can * easily use the first matching entry. */ LIST_FOREACH(used, &l2cap_listen_list, lc_ncid) { if (used->lc_laddr.bt_psm < chan->lc_laddr.bt_psm) break; if (used->lc_laddr.bt_psm == chan->lc_laddr.bt_psm && bdaddr_any(&used->lc_laddr.bt_bdaddr) && !bdaddr_any(&chan->lc_laddr.bt_bdaddr)) break; prev = used; } if (prev == NULL) LIST_INSERT_HEAD(&l2cap_listen_list, chan, lc_ncid); else LIST_INSERT_AFTER(prev, chan, lc_ncid); return 0; } /* * l2cap_send(l2cap_channel, mbuf) * * Output SDU on channel described by channel. This corresponds * to "Send Data Request" in the L2CAP specification. The upper * layer will be notified when SDU's have completed sending by a * call to: * * proto->complete(upper, n) * * (currently n == 1) * * Note: I'm not sure how this will work out, but I think that * if outgoing Retransmission Mode or Flow Control Mode is * negotiated then this call will not be made until the SDU has * been acknowleged by the peer L2CAP entity. For 'Best Effort' * it will be made when the packet has cleared the controller * buffers. * * We only support Basic mode so far, so encapsulate with a * B-Frame header and start sending if we are not already */ int l2cap_send(struct l2cap_channel *chan, struct mbuf *m) { l2cap_hdr_t *hdr; int plen; if (chan->lc_state == L2CAP_CLOSED) { m_freem(m); return ENOTCONN; } plen = m->m_pkthdr.len; DPRINTFN(5, "send %d bytes on CID #%d (pending = %d)\n", plen, chan->lc_lcid, chan->lc_pending); /* Encapsulate with B-Frame */ M_PREPEND(m, sizeof(l2cap_hdr_t), M_DONTWAIT); if (m == NULL) return ENOMEM; hdr = mtod(m, l2cap_hdr_t *); hdr->length = htole16(plen); hdr->dcid = htole16(chan->lc_rcid); /* Queue it on our list */ MBUFQ_ENQUEUE(&chan->lc_txq, m); /* If we are not sending, then start doing so */ if (chan->lc_pending == 0) return l2cap_start(chan); return 0; } /* * l2cap_setopt(channel, opt, addr) * * Apply configuration options to channel. This corresponds to * "Configure Channel Request" in the L2CAP specification. */ int l2cap_setopt(struct l2cap_channel *chan, int opt, void *addr) { int err = 0; uint16_t tmp; /* * currently we dont allow changing any options when channel * is other than closed. We could allow this (not sure why?) * but would have to instigate a configure request. */ if (chan->lc_state != L2CAP_CLOSED) return EBUSY; switch (opt) { case SO_L2CAP_IMTU: /* set Incoming MTU */ tmp = *(uint16_t *)addr; if (tmp < L2CAP_MTU_MINIMUM) { err = EINVAL; break; } chan->lc_imtu = tmp; break; case SO_L2CAP_OQOS: /* set Outgoing QoS flow spec */ // XXX // memcpy(&chan->lc_oqos, addr, sizeof(l2cap_qos_t)); //break; case SO_L2CAP_FLUSH: /* set Outgoing Flush Timeout */ // XXX // chan->lc_flush = *(uint16_t *)addr; //break; default: err = EINVAL; break; } return err; } int l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr) { switch (opt) { case SO_L2CAP_IMTU: /* get Incoming MTU */ *(uint16_t *)addr = chan->lc_imtu; return sizeof(uint16_t); case SO_L2CAP_OMTU: /* get Outgoing MTU */ *(uint16_t *)addr = chan->lc_omtu; return sizeof(uint16_t); case SO_L2CAP_IQOS: /* get Incoming QoS flow spec */ memcpy(addr, &chan->lc_iqos, sizeof(l2cap_qos_t)); return sizeof(l2cap_qos_t); case SO_L2CAP_OQOS: /* get Outgoing QoS flow spec */ memcpy(addr, &chan->lc_oqos, sizeof(l2cap_qos_t)); return sizeof(l2cap_qos_t); case SO_L2CAP_FLUSH: /* get Flush Timeout */ *(uint16_t *)addr = chan->lc_flush; return sizeof(uint16_t); default: break; } return 0; } @ 1.1.2.3 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.1.2.2 2007/09/03 14:42:42 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.1.2.2 2007/09/03 14:42:42 yamt Exp $"); d58 1 a58 1 * with reasonable defaults d66 3 a68 3 KASSERT(handle != NULL); KASSERT(proto != NULL); KASSERT(upper != NULL); a178 10 /* set the link mode */ err = l2cap_setmode(chan); if (err == EINPROGRESS) { chan->lc_state = L2CAP_WAIT_SEND_CONNECT_REQ; (*chan->lc_proto->connecting)(chan->lc_upper); return 0; } if (err) goto fail; d180 3 a182 3 * We can queue a connect request now even though the link may * not yet be open; Our mode setting is assured, and the queue * will be started automatically at the right time. d184 1 a184 1 chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP; d186 6 a191 2 if (err) goto fail; a193 6 fail: chan->lc_state = L2CAP_CLOSED; hci_acl_close(chan->lc_link, err); chan->lc_link = NULL; return err; d227 1 a227 2 if (chan->lc_state == L2CAP_CLOSED || chan->lc_state == L2CAP_WAIT_DISCONNECT) d397 1 a397 1 * l2cap_setopt(l2cap_channel, opt, addr) a400 7 * * for SO_L2CAP_LM, the settings will take effect when the * channel is established. If the channel is already open, * a call to * proto->linkmode(upper, new) * * will be made when the change is complete. d405 10 a414 2 int mode, err = 0; uint16_t mtu; d418 2 a419 2 mtu = *(uint16_t *)addr; if (mtu < L2CAP_MTU_MINIMUM) d421 2 a422 4 else if (chan->lc_state == L2CAP_CLOSED) chan->lc_imtu = mtu; else err = EBUSY; d424 1 d427 4 a430 3 case SO_L2CAP_LM: /* set link mode */ mode = *(int *)addr; mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH); d432 4 a435 2 if (mode & L2CAP_LM_SECURE) mode |= L2CAP_LM_ENCRYPT; a436 12 if (mode & L2CAP_LM_ENCRYPT) mode |= L2CAP_LM_AUTH; chan->lc_mode = mode; if (chan->lc_state == L2CAP_OPEN) err = l2cap_setmode(chan); break; case SO_L2CAP_OQOS: /* set Outgoing QoS flow spec */ case SO_L2CAP_FLUSH: /* set Outgoing Flush Timeout */ d438 1 a438 1 err = ENOPROTOOPT; a444 5 /* * l2cap_getopt(l2cap_channel, opt, addr) * * Return configuration parameters. */ a469 4 case SO_L2CAP_LM: /* get link mode */ *(int *)addr = chan->lc_mode; return sizeof(int); @ 1.1.24.1 log @Sync w/ NetBSD-4-RC_1 @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.1.18.1 2007/07/19 16:04:20 liamjfoy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.1.18.1 2007/07/19 16:04:20 liamjfoy Exp $"); a178 10 /* set the link mode */ err = l2cap_setmode(chan); if (err == EINPROGRESS) { chan->lc_state = L2CAP_WAIT_SEND_CONNECT_REQ; (*chan->lc_proto->connecting)(chan->lc_upper); return 0; } if (err) goto fail; d180 3 a182 3 * We can queue a connect request now even though the link may * not yet be open; Our mode setting is assured, and the queue * will be started automatically at the right time. d184 1 a184 1 chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP; d186 6 a191 2 if (err) goto fail; a193 6 fail: chan->lc_state = L2CAP_CLOSED; hci_acl_close(chan->lc_link, err); chan->lc_link = NULL; return err; d227 1 a227 2 if (chan->lc_state == L2CAP_CLOSED || chan->lc_state == L2CAP_WAIT_DISCONNECT) d397 1 a397 1 * l2cap_setopt(l2cap_channel, opt, addr) a400 7 * * for SO_L2CAP_LM, the settings will take effect when the * channel is established. If the channel is already open, * a call to * proto->linkmode(upper, new) * * will be made when the change is complete. d405 10 a414 2 int mode, err = 0; uint16_t mtu; d418 2 a419 2 mtu = *(uint16_t *)addr; if (mtu < L2CAP_MTU_MINIMUM) d421 2 a422 21 else if (chan->lc_state == L2CAP_CLOSED) chan->lc_imtu = mtu; else err = EBUSY; break; case SO_L2CAP_LM: /* set link mode */ mode = *(int *)addr; mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH); if (mode & L2CAP_LM_SECURE) mode |= L2CAP_LM_ENCRYPT; if (mode & L2CAP_LM_ENCRYPT) mode |= L2CAP_LM_AUTH; chan->lc_mode = mode; if (chan->lc_state == L2CAP_OPEN) err = l2cap_setmode(chan); d424 1 a444 5 /* * l2cap_getopt(l2cap_channel, opt, addr) * * Return configuration parameters. */ a469 4 case SO_L2CAP_LM: /* get link mode */ *(int *)addr = chan->lc_mode; return sizeof(int); @ 1.1.18.1 log @Pull up following revision(s) (requested by plunky in ticket #744): sys/netbt/l2cap_lower.c: revision 1.6 sys/dev/bluetooth/btdev.h: revision 1.6 sys/netbt/sco_socket.c: revision 1.9 sys/netbt/rfcomm_upper.c: revision 1.3 sys/netbt/l2cap_socket.c: revision 1.7 sys/netbt/rfcomm_upper.c: revision 1.5 lib/libusbhid/usbhid.h: revision 1.5 sys/netbt/rfcomm_upper.c: revision 1.6 usr.sbin/btdevctl/btdevctl.c: revision 1.4 usr.sbin/btdevctl/btdevctl.h: revision 1.3 usr.sbin/btdevctl/btdevctl.8: revision 1.4 sys/netbt/rfcomm_session.c: revision 1.5 sys/netbt/hci.h: revision 1.10 usr.bin/rfcomm_sppd/rfcomm_sppd.c: revision 1.6 sys/netbt/hci_link.c: revision 1.11 usr.bin/rfcomm_sppd/rfcomm_sppd.c: revision 1.7 usr.bin/rfcomm_sppd/rfcomm_sppd.c: revision 1.8 sys/dev/bluetooth/btsco.c: revision 1.14 sys/netbt/rfcomm_session.c: revision 1.9 usr.sbin/btdevctl/sdp.c: revision 1.2 share/man/man9/bluetooth.9: revision 1.2 usr.sbin/btdevctl/sdp.c: revision 1.3 sys/dev/bluetooth/bthidev.c: revision 1.8 sys/netbt/l2cap.h: revision 1.4 sys/netbt/rfcomm.h: revision 1.3 sys/netbt/l2cap.h: revision 1.5 sys/netbt/l2cap_misc.c: revision 1.3 share/man/man4/bluetooth.4: revision 1.5 lib/libusbhid/usbhid.3: revision 1.11 sys/netbt/bluetooth.h: revision 1.5 share/man/man4/bthidev.4: revision 1.8 sys/netbt/rfcomm_dlc.c: revision 1.3 usr.sbin/btdevctl/print.c: revision 1.8 sys/netbt/rfcomm_socket.c: revision 1.7 sys/netbt/l2cap_signal.c: revision 1.4 sys/netbt/l2cap_signal.c: revision 1.5 sys/netbt/l2cap_signal.c: revision 1.7 sys/netbt/hci_event.c: revision 1.6 usr.bin/rfcomm_sppd/rfcomm_sppd.1: revision 1.5 sys/netbt/l2cap_upper.c: revision 1.3 sys/netbt/l2cap_lower.c: revision 1.2 usr.sbin/btdevctl/db.c: revision 1.3 sys/netbt/l2cap_upper.c: revision 1.6 lib/libusbhid/descr.c: revision 1.5 sys/netbt/l2cap_upper.c: revision 1.7 sys/netbt/l2cap_lower.c: revision 1.4 Add 'service level' security for L2CAP and RFCOMM connections, following the Linux (BlueZ) API. - L2CAP or RFCOMM connections can require the baseband radio link mode be any of: authenticated (devices are paired) encrypted (implies authentication) secured (encryption, plus generate new link key) - for sockets, the mode is set using setsockopt(2) and the socket connection will be aborted if the mode change fails. - mode settings will be applied during connection establishment, and for safety, we enter a wait state and will only proceed when the mode settings are successfuly set. - It is possible to change the mode on already open connections, but not possible to guarantee that data already queued (from either end) will not be delivered. (this is a feature, not a bug) - bthidev(4) and rfcomm_sppd(1) support "auth", "encrypt" and "secure" options - btdevctl(8) by default enables "auth" for HIDs, and "encrypt" for keyboards (which are required to support it) - ALSO INCLUDES OTHER MINOR FIXES @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); a178 10 /* set the link mode */ err = l2cap_setmode(chan); if (err == EINPROGRESS) { chan->lc_state = L2CAP_WAIT_SEND_CONNECT_REQ; (*chan->lc_proto->connecting)(chan->lc_upper); return 0; } if (err) goto fail; d180 3 a182 3 * We can queue a connect request now even though the link may * not yet be open; Our mode setting is assured, and the queue * will be started automatically at the right time. d184 1 a184 1 chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP; d186 6 a191 2 if (err) goto fail; a193 6 fail: chan->lc_state = L2CAP_CLOSED; hci_acl_close(chan->lc_link, err); chan->lc_link = NULL; return err; d227 1 a227 2 if (chan->lc_state == L2CAP_CLOSED || chan->lc_state == L2CAP_WAIT_DISCONNECT) d397 1 a397 1 * l2cap_setopt(l2cap_channel, opt, addr) a400 7 * * for SO_L2CAP_LM, the settings will take effect when the * channel is established. If the channel is already open, * a call to * proto->linkmode(upper, new) * * will be made when the change is complete. d405 10 a414 2 int mode, err = 0; uint16_t mtu; d418 2 a419 2 mtu = *(uint16_t *)addr; if (mtu < L2CAP_MTU_MINIMUM) d421 2 a422 21 else if (chan->lc_state == L2CAP_CLOSED) chan->lc_imtu = mtu; else err = EBUSY; break; case SO_L2CAP_LM: /* set link mode */ mode = *(int *)addr; mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH); if (mode & L2CAP_LM_SECURE) mode |= L2CAP_LM_ENCRYPT; if (mode & L2CAP_LM_ENCRYPT) mode |= L2CAP_LM_AUTH; chan->lc_mode = mode; if (chan->lc_state == L2CAP_OPEN) err = l2cap_setmode(chan); d424 1 a444 5 /* * l2cap_getopt(l2cap_channel, opt, addr) * * Return configuration parameters. */ a469 4 case SO_L2CAP_LM: /* get link mode */ *(int *)addr = chan->lc_mode; return sizeof(int); @ 1.1.20.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.1 2006/06/19 15:44:45 gdamore Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.1 2006/06/19 15:44:45 gdamore Exp $"); d438 1 a438 1 err = ENOPROTOOPT; @ 1.1.20.2 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.1.20.1 2007/03/12 05:59:34 rmind Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.1.20.1 2007/03/12 05:59:34 rmind Exp $"); d227 1 a227 2 if (chan->lc_state == L2CAP_CLOSED || chan->lc_state == L2CAP_WAIT_DISCONNECT) d428 4 d433 4 @ 1.1.20.3 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.1.20.2 2007/03/24 14:56:09 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.1.20.2 2007/03/24 14:56:09 yamt Exp $"); d66 3 a68 3 KASSERT(handle != NULL); KASSERT(proto != NULL); KASSERT(upper != NULL); d407 9 a415 1 uint16_t mtu; d419 2 a420 2 mtu = *(uint16_t *)addr; if (mtu < L2CAP_MTU_MINIMUM) d422 2 a423 4 else if (chan->lc_state == L2CAP_CLOSED) chan->lc_imtu = mtu; else err = EBUSY; d425 1 @ 1.1.20.4 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: l2cap_upper.c,v 1.1.20.3 2007/04/15 16:03:59 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.1.20.3 2007/04/15 16:03:59 yamt Exp $"); d58 1 a58 1 * with reasonable defaults a178 10 /* set the link mode */ err = l2cap_setmode(chan); if (err == EINPROGRESS) { chan->lc_state = L2CAP_WAIT_SEND_CONNECT_REQ; (*chan->lc_proto->connecting)(chan->lc_upper); return 0; } if (err) goto fail; d180 3 a182 3 * We can queue a connect request now even though the link may * not yet be open; Our mode setting is assured, and the queue * will be started automatically at the right time. d184 1 a184 1 chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP; d186 6 a191 2 if (err) goto fail; a193 6 fail: chan->lc_state = L2CAP_CLOSED; hci_acl_close(chan->lc_link, err); chan->lc_link = NULL; return err; d398 1 a398 1 * l2cap_setopt(l2cap_channel, opt, addr) a401 7 * * for SO_L2CAP_LM, the settings will take effect when the * channel is established. If the channel is already open, * a call to * proto->linkmode(upper, new) * * will be made when the change is complete. d406 1 a406 1 int mode, err = 0; a420 17 case SO_L2CAP_LM: /* set link mode */ mode = *(int *)addr; mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH); if (mode & L2CAP_LM_SECURE) mode |= L2CAP_LM_ENCRYPT; if (mode & L2CAP_LM_ENCRYPT) mode |= L2CAP_LM_AUTH; chan->lc_mode = mode; if (chan->lc_state == L2CAP_OPEN) err = l2cap_setmode(chan); break; a430 5 /* * l2cap_getopt(l2cap_channel, opt, addr) * * Return configuration parameters. */ a455 4 case SO_L2CAP_LM: /* get link mode */ *(int *)addr = chan->lc_mode; return sizeof(int); @