head 1.281; access; symbols netbsd-10-0-RELEASE:1.279.4.1 netbsd-10-0-RC6:1.279.4.1 netbsd-10-0-RC5:1.279.4.1 netbsd-10-0-RC4:1.279.4.1 netbsd-10-0-RC3:1.279.4.1 netbsd-10-0-RC2:1.279.4.1 thorpej-ifq:1.280.0.4 thorpej-ifq-base:1.280 thorpej-altq-separation:1.280.0.2 thorpej-altq-separation-base:1.280 netbsd-10-0-RC1:1.279 netbsd-10:1.279.0.4 netbsd-10-base:1.279 bouyer-sunxi-drm:1.279.0.2 bouyer-sunxi-drm-base:1.279 netbsd-9-3-RELEASE:1.256.2.8 thorpej-i2c-spi-conf2:1.276.0.14 thorpej-i2c-spi-conf2-base:1.276 thorpej-futex2:1.276.0.12 thorpej-futex2-base:1.276 thorpej-cfargs2:1.276.0.10 thorpej-cfargs2-base:1.276 cjep_sun2x-base1:1.276 cjep_sun2x:1.276.0.8 cjep_sun2x-base:1.276 cjep_staticlib_x-base1:1.276 netbsd-9-2-RELEASE:1.256.2.7 cjep_staticlib_x:1.276.0.6 cjep_staticlib_x-base:1.276 thorpej-i2c-spi-conf:1.276.0.4 thorpej-i2c-spi-conf-base:1.276 thorpej-cfargs:1.276.0.2 thorpej-cfargs-base:1.276 thorpej-futex:1.274.0.2 thorpej-futex-base:1.276 netbsd-9-1-RELEASE:1.256.2.7 bouyer-xenpvh-base2:1.269 phil-wifi-20200421:1.269 bouyer-xenpvh-base1:1.269 phil-wifi-20200411:1.268 bouyer-xenpvh:1.268.0.2 bouyer-xenpvh-base:1.268 is-mlppp:1.266.0.2 is-mlppp-base:1.266 phil-wifi-20200406:1.268 netbsd-8-2-RELEASE:1.232.2.13 ad-namecache-base3:1.266 netbsd-9-0-RELEASE:1.256.2.7 netbsd-9-0-RC2:1.256.2.7 ad-namecache-base2:1.266 ad-namecache-base1:1.265 ad-namecache:1.265.0.2 ad-namecache-base:1.265 netbsd-9-0-RC1:1.256.2.7 phil-wifi-20191119:1.265 netbsd-9:1.256.0.2 netbsd-9-base:1.256 phil-wifi-20190609:1.254 netbsd-8-1-RELEASE:1.232.2.9 netbsd-8-1-RC1:1.232.2.9 isaki-audio2:1.252.0.2 isaki-audio2-base:1.252 pgoyette-compat-merge-20190127:1.245.2.6 pgoyette-compat-20190127:1.252 pgoyette-compat-20190118:1.252 pgoyette-compat-1226:1.252 pgoyette-compat-1126:1.251 pgoyette-compat-1020:1.250 pgoyette-compat-0930:1.250 pgoyette-compat-0906:1.250 netbsd-7-2-RELEASE:1.152.2.4 pgoyette-compat-0728:1.249 netbsd-8-0-RELEASE:1.232.2.8 phil-wifi:1.249.0.2 phil-wifi-base:1.249 pgoyette-compat-0625:1.249 netbsd-8-0-RC2:1.232.2.8 pgoyette-compat-0521:1.248 pgoyette-compat-0502:1.248 pgoyette-compat-0422:1.247 netbsd-8-0-RC1:1.232.2.7 pgoyette-compat-0415:1.247 pgoyette-compat-0407:1.247 pgoyette-compat-0330:1.247 pgoyette-compat-0322:1.247 pgoyette-compat-0315:1.247 netbsd-7-1-2-RELEASE:1.152.2.3 pgoyette-compat:1.245.0.2 pgoyette-compat-base:1.245 netbsd-7-1-1-RELEASE:1.152.2.3 tls-maxphys-base-20171202:1.239 matt-nb8-mediatek:1.232.2.2.0.2 matt-nb8-mediatek-base:1.232.2.2 nick-nhusb-base-20170825:1.235 perseant-stdc-iso10646:1.235.0.2 perseant-stdc-iso10646-base:1.235 netbsd-8:1.232.0.2 netbsd-8-base:1.232 prg-localcount2-base3:1.231 prg-localcount2-base2:1.231 prg-localcount2-base1:1.231 prg-localcount2:1.231.0.4 prg-localcount2-base:1.231 pgoyette-localcount-20170426:1.231 bouyer-socketcan-base1:1.231 jdolecek-ncq:1.231.0.2 jdolecek-ncq-base:1.231 pgoyette-localcount-20170320:1.231 netbsd-7-1:1.152.2.3.0.6 netbsd-7-1-RELEASE:1.152.2.3 netbsd-7-1-RC2:1.152.2.3 nick-nhusb-base-20170204:1.226 netbsd-7-nhusb-base-20170116:1.152.2.3 bouyer-socketcan:1.224.0.2 bouyer-socketcan-base:1.224 pgoyette-localcount-20170107:1.223 netbsd-7-1-RC1:1.152.2.3 nick-nhusb-base-20161204:1.211 pgoyette-localcount-20161104:1.210 netbsd-7-0-2-RELEASE:1.152.2.3 nick-nhusb-base-20161004:1.207 localcount-20160914:1.207 netbsd-7-nhusb:1.152.2.3.0.4 netbsd-7-nhusb-base:1.152.2.3 pgoyette-localcount-20160806:1.205 pgoyette-localcount-20160726:1.204 pgoyette-localcount:1.203.0.2 pgoyette-localcount-base:1.203 nick-nhusb-base-20160907:1.202 nick-nhusb-base-20160529:1.195 netbsd-7-0-1-RELEASE:1.152.2.3 nick-nhusb-base-20160422:1.191 nick-nhusb-base-20160319:1.185 nick-nhusb-base-20151226:1.183 netbsd-7-0:1.152.2.3.0.2 netbsd-7-0-RELEASE:1.152.2.3 nick-nhusb-base-20150921:1.177 netbsd-7-0-RC3:1.152.2.3 netbsd-7-0-RC2:1.152.2.3 netbsd-7-0-RC1:1.152.2.3 nick-nhusb-base-20150606:1.162 nick-nhusb-base-20150406:1.161 nick-nhusb:1.154.0.2 nick-nhusb-base:1.154 netbsd-5-2-3-RELEASE:1.130.14.1 netbsd-5-1-5-RELEASE:1.130.10.1 netbsd-6-0-6-RELEASE:1.141.6.3 netbsd-6-1-5-RELEASE:1.141.8.3 netbsd-7:1.152.0.2 netbsd-7-base:1.152 yamt-pagecache-base9:1.148 yamt-pagecache-tag8:1.136.8.2 netbsd-6-1-4-RELEASE:1.141.8.2 netbsd-6-0-5-RELEASE:1.141.6.2 tls-earlyentropy:1.148.0.2 tls-earlyentropy-base:1.152 riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.148 riastradh-drm2-base3:1.147 netbsd-6-1-3-RELEASE:1.141.8.2 netbsd-6-0-4-RELEASE:1.141.6.2 netbsd-5-2-2-RELEASE:1.130.14.1 netbsd-5-1-4-RELEASE:1.130.10.1 netbsd-6-1-2-RELEASE:1.141.8.1 netbsd-6-0-3-RELEASE:1.141.6.1 netbsd-5-2-1-RELEASE:1.130 netbsd-5-1-3-RELEASE:1.130 rmind-smpnet-nbase:1.149 netbsd-6-1-1-RELEASE:1.141.8.1 riastradh-drm2-base2:1.145 riastradh-drm2-base1:1.145 riastradh-drm2:1.145.0.4 riastradh-drm2-base:1.145 rmind-smpnet:1.145.0.2 rmind-smpnet-base:1.149 netbsd-6-1:1.141.0.8 netbsd-6-0-2-RELEASE:1.141 netbsd-6-1-RELEASE:1.141 khorben-n900:1.144.0.6 netbsd-6-1-RC4:1.141 netbsd-6-1-RC3:1.141 agc-symver:1.144.0.4 agc-symver-base:1.144 netbsd-6-1-RC2:1.141 netbsd-6-1-RC1:1.141 yamt-pagecache-base8:1.143 netbsd-5-2:1.130.0.14 netbsd-6-0-1-RELEASE:1.141 yamt-pagecache-base7:1.143 netbsd-5-2-RELEASE:1.130 netbsd-5-2-RC1:1.130 matt-nb6-plus-nbase:1.141 yamt-pagecache-base6:1.143 netbsd-6-0:1.141.0.6 netbsd-6-0-RELEASE:1.141 netbsd-6-0-RC2:1.141 tls-maxphys:1.143.0.2 tls-maxphys-base:1.152 matt-nb6-plus:1.141.0.4 matt-nb6-plus-base:1.141 netbsd-6-0-RC1:1.141 jmcneill-usbmp-base10:1.142 yamt-pagecache-base5:1.142 jmcneill-usbmp-base9:1.142 yamt-pagecache-base4:1.142 jmcneill-usbmp-base8:1.142 jmcneill-usbmp-base7:1.141 jmcneill-usbmp-base6:1.141 jmcneill-usbmp-base5:1.141 jmcneill-usbmp-base4:1.141 jmcneill-usbmp-base3:1.141 jmcneill-usbmp-pre-base2:1.138 jmcneill-usbmp-base2:1.141 netbsd-6:1.141.0.2 netbsd-6-base:1.141 netbsd-5-1-2-RELEASE:1.130 netbsd-5-1-1-RELEASE:1.130 jmcneill-usbmp:1.138.0.2 jmcneill-usbmp-base:1.138 jmcneill-audiomp3:1.137.0.2 jmcneill-audiomp3-base:1.137 yamt-pagecache-base3:1.136 yamt-pagecache-base2:1.136 yamt-pagecache:1.136.0.8 yamt-pagecache-base:1.136 rmind-uvmplock-nbase:1.136 cherry-xenmp:1.136.0.6 cherry-xenmp-base:1.136 bouyer-quota2-nbase:1.136 bouyer-quota2:1.136.0.4 bouyer-quota2-base:1.136 jruoho-x86intr:1.136.0.2 jruoho-x86intr-base:1.136 matt-mips64-premerge-20101231:1.136 matt-nb5-mips64-premerge-20101231:1.130 matt-nb5-pq3:1.130.0.12 matt-nb5-pq3-base:1.130 netbsd-5-1:1.130.0.10 netbsd-5-1-RELEASE:1.130 uebayasi-xip-base4:1.136 uebayasi-xip-base3:1.136 yamt-nfs-mp-base11:1.136 netbsd-5-1-RC4:1.130 matt-nb5-mips64-k15:1.130 uebayasi-xip-base2:1.136 yamt-nfs-mp-base10:1.136 netbsd-5-1-RC3:1.130 netbsd-5-1-RC2:1.130 uebayasi-xip-base1:1.135 netbsd-5-1-RC1:1.130 rmind-uvmplock:1.135.0.4 rmind-uvmplock-base:1.136 yamt-nfs-mp-base9:1.135 uebayasi-xip:1.135.0.2 uebayasi-xip-base:1.135 netbsd-5-0-2-RELEASE:1.130 matt-nb5-mips64-premerge-20091211:1.130 matt-premerge-20091211:1.135 yamt-nfs-mp-base8:1.134 matt-nb5-mips64-u2-k2-k4-k7-k8-k9:1.130 matt-nb4-mips64-k7-u2a-k9b:1.130 matt-nb5-mips64-u1-k1-k5:1.130 yamt-nfs-mp-base7:1.133 matt-nb5-mips64:1.130.0.8 netbsd-5-0-1-RELEASE:1.130 jymxensuspend-base:1.131 yamt-nfs-mp-base6:1.131 yamt-nfs-mp-base5:1.131 yamt-nfs-mp-base4:1.131 jym-xensuspend-nbase:1.134 yamt-nfs-mp-base3:1.131 nick-hppapmap-base4:1.131 nick-hppapmap-base3:1.131 netbsd-5-0:1.130.0.6 netbsd-5-0-RELEASE:1.130 netbsd-5-0-RC4:1.130 netbsd-5-0-RC3:1.130 nick-hppapmap-base2:1.131 netbsd-5-0-RC2:1.130 jym-xensuspend:1.131.0.4 jym-xensuspend-base:1.131 netbsd-5-0-RC1:1.130 haad-dm-base2:1.131 haad-nbase2:1.131 ad-audiomp2:1.131.0.2 ad-audiomp2-base:1.131 netbsd-5:1.130.0.4 netbsd-5-base:1.130 nick-hppapmap:1.130.0.2 nick-hppapmap-base:1.131 matt-mips64-base2:1.130 matt-mips64:1.118.0.4 haad-dm-base1:1.128 wrstuden-revivesa-base-4:1.128 netbsd-4-0-1-RELEASE:1.109 wrstuden-revivesa-base-3:1.128 wrstuden-revivesa-base-2:1.128 wrstuden-fixsa-newbase:1.109 nick-csl-alignment-base5:1.120 haad-dm:1.128.0.4 haad-dm-base:1.131 wrstuden-revivesa-base-1:1.128 simonb-wapbl-nbase:1.128 yamt-pf42-base4:1.128 simonb-wapbl:1.128.0.2 simonb-wapbl-base:1.128 yamt-pf42-base3:1.128 hpcarm-cleanup-nbase:1.128 yamt-pf42-baseX:1.125 yamt-pf42-base2:1.128 yamt-nfs-mp-base2:1.128 wrstuden-revivesa:1.126.0.4 wrstuden-revivesa-base:1.128 yamt-nfs-mp:1.126.0.2 yamt-nfs-mp-base:1.126 yamt-pf42:1.125.0.2 yamt-pf42-base:1.125 ad-socklock-base1:1.123 yamt-lazymbuf-base15:1.123 yamt-lazymbuf-base14:1.123 keiichi-mipv6-nbase:1.123 mjf-devfs2:1.123.0.12 mjf-devfs2-base:1.131 nick-net80211-sync:1.123.0.10 nick-net80211-sync-base:1.123 keiichi-mipv6:1.123.0.8 keiichi-mipv6-base:1.123 bouyer-xeni386-merge1:1.123 matt-armv6-prevmlocking:1.118.2.1 wrstuden-fixsa-base-1:1.109 vmlocking2-base3:1.123 netbsd-4-0:1.109.0.10 netbsd-4-0-RELEASE:1.109 bouyer-xeni386-nbase:1.123 yamt-kmem-base3:1.123 cube-autoconf:1.123.0.6 cube-autoconf-base:1.123 yamt-kmem-base2:1.123 bouyer-xeni386:1.123.0.4 bouyer-xeni386-base:1.123 yamt-kmem:1.123.0.2 yamt-kmem-base:1.123 vmlocking2-base2:1.123 reinoud-bufcleanup-nbase:1.123 vmlocking2:1.122.0.2 vmlocking2-base1:1.122 netbsd-4-0-RC5:1.109 matt-nb4-arm:1.109.0.8 matt-nb4-arm-base:1.109 matt-armv6-nbase:1.123 jmcneill-base:1.121 netbsd-4-0-RC4:1.109 mjf-devfs:1.121.0.2 mjf-devfs-base:1.123 bouyer-xenamd64-base2:1.122 vmlocking-nbase:1.122 yamt-x86pmap-base4:1.120 bouyer-xenamd64:1.120.0.4 bouyer-xenamd64-base:1.122 netbsd-4-0-RC3:1.109 yamt-x86pmap-base3:1.120 yamt-x86pmap-base2:1.120 netbsd-4-0-RC2:1.109 yamt-x86pmap:1.120.0.2 yamt-x86pmap-base:1.120 netbsd-4-0-RC1:1.109 matt-armv6:1.118.0.2 matt-armv6-base:1.123 matt-mips64-base:1.118 jmcneill-pm:1.117.0.4 jmcneill-pm-base:1.123 hpcarm-cleanup:1.117.0.2 hpcarm-cleanup-base:1.123 nick-csl-alignment:1.116.0.2 nick-csl-alignment-base:1.116 netbsd-3-1-1-RELEASE:1.91.10.1 netbsd-3-0-3-RELEASE:1.91.10.1 yamt-idlelwp-base8:1.115 wrstuden-fixsa:1.109.0.6 wrstuden-fixsa-base:1.109 thorpej-atomic:1.113.0.2 thorpej-atomic-base:1.113 reinoud-bufcleanup:1.111.0.6 reinoud-bufcleanup-base:1.123 mjf-ufs-trans:1.111.0.4 mjf-ufs-trans-base:1.116 vmlocking:1.111.0.2 vmlocking-base:1.120 ad-audiomp:1.110.0.2 ad-audiomp-base:1.110 yamt-idlelwp:1.109.0.4 post-newlock2-merge:1.109 newlock2-nbase:1.109 yamt-splraiseipl-base5:1.109 yamt-splraiseipl-base4:1.109 yamt-splraiseipl-base3:1.109 abandoned-netbsd-4-base:1.103 abandoned-netbsd-4:1.103.0.4 netbsd-3-1:1.91.10.1.0.4 netbsd-3-1-RELEASE:1.91.10.1 netbsd-3-0-2-RELEASE:1.91.10.1 yamt-splraiseipl-base2:1.105 netbsd-3-1-RC4:1.91.10.1 yamt-splraiseipl:1.104.0.4 yamt-splraiseipl-base:1.104 netbsd-3-1-RC3:1.91.10.1 yamt-pdpolicy-base9:1.104 newlock2:1.104.0.2 newlock2-base:1.109 yamt-pdpolicy-base8:1.104 netbsd-3-1-RC2:1.91.10.1 netbsd-3-1-RC1:1.91.10.1 yamt-pdpolicy-base7:1.103 netbsd-4:1.109.0.2 netbsd-4-base:1.109 yamt-pdpolicy-base6:1.103 chap-midi-nbase:1.103 netbsd-3-0-1-RELEASE:1.91.10.1 gdamore-uart:1.103.0.2 gdamore-uart-base:1.103 simonb-timcounters-final:1.96.4.3 yamt-pdpolicy-base5:1.102 chap-midi:1.102.0.2 chap-midi-base:1.103 yamt-pdpolicy-base4:1.100 yamt-pdpolicy-base3:1.100 peter-altq-base:1.99 peter-altq:1.99.0.4 yamt-pdpolicy-base2:1.99 elad-kernelauth-base:1.101 elad-kernelauth:1.99.0.2 yamt-pdpolicy:1.98.0.2 yamt-pdpolicy-base:1.98 yamt-uio_vmspace-base5:1.96 simonb-timecounters:1.96.0.4 simonb-timecounters-base:1.102 rpaulo-netinet-merge-pcb:1.96.0.2 rpaulo-netinet-merge-pcb-base:1.104 yamt-uio_vmspace:1.95.0.2 netbsd-3-0:1.91.10.1.0.2 netbsd-3-0-RELEASE:1.91.10.1 netbsd-3-0-RC6:1.91.10.1 yamt-readahead-base3:1.94 netbsd-3-0-RC5:1.91.10.1 netbsd-3-0-RC4:1.91.10.1 netbsd-3-0-RC3:1.91.10.1 yamt-readahead-base2:1.94 netbsd-3-0-RC2:1.91.10.1 yamt-readahead-pervnode:1.94 yamt-readahead-perfile:1.94 yamt-readahead:1.94.0.8 yamt-readahead-base:1.94 netbsd-3-0-RC1:1.91.10.1 yamt-vop-base3:1.94 netbsd-2-0-3-RELEASE:1.89.2.1 netbsd-2-1:1.89.4.1.0.2 yamt-vop-base2:1.94 thorpej-vnode-attr:1.94.0.6 thorpej-vnode-attr-base:1.94 netbsd-2-1-RELEASE:1.89.4.1 yamt-vop:1.94.0.4 yamt-vop-base:1.94 netbsd-2-1-RC6:1.89.4.1 netbsd-2-1-RC5:1.89.4.1 netbsd-2-1-RC4:1.89.4.1 netbsd-2-1-RC3:1.89.4.1 netbsd-2-1-RC2:1.89.4.1 netbsd-2-1-RC1:1.89.4.1 yamt-lazymbuf:1.94.0.2 yamt-km-base4:1.91 netbsd-2-0-2-RELEASE:1.89 yamt-km-base3:1.91 netbsd-3:1.91.0.10 netbsd-3-base:1.91 yamt-km-base2:1.91 yamt-km:1.91.0.6 yamt-km-base:1.91 kent-audio2:1.91.0.4 kent-audio2-base:1.92 netbsd-2-0-1-RELEASE:1.89 kent-audio1-beforemerge:1.91 netbsd-2:1.89.0.4 netbsd-2-base:1.89 kent-audio1:1.91.0.2 kent-audio1-base:1.91 netbsd-2-0-RELEASE:1.89 netbsd-2-0-RC5:1.89 netbsd-2-0-RC4:1.89 netbsd-2-0-RC3:1.89 netbsd-2-0-RC2:1.89 netbsd-2-0-RC1:1.89 netbsd-2-0:1.89.0.2 netbsd-2-0-base:1.89 netbsd-1-6-PATCH002-RELEASE:1.57.6.1 netbsd-1-6-PATCH002:1.57.6.1 netbsd-1-6-PATCH002-RC4:1.57.6.1 netbsd-1-6-PATCH002-RC3:1.57.6.1 netbsd-1-6-PATCH002-RC2:1.57.6.1 netbsd-1-6-PATCH002-RC1:1.57.6.1 ktrace-lwp:1.86.0.2 ktrace-lwp-base:1.94 netbsd-1-6-PATCH001:1.57.6.1 netbsd-1-6-PATCH001-RELEASE:1.57.6.1 netbsd-1-6-PATCH001-RC3:1.57.6.1 netbsd-1-6-PATCH001-RC2:1.57.6.1 netbsd-1-6-PATCH001-RC1:1.57.6.1 nathanw_sa_end:1.42.2.12 nathanw_sa_before_merge:1.78 fvdl_fs64_base:1.77 gmcgarry_ctxsw:1.77.0.4 gmcgarry_ctxsw_base:1.77 gmcgarry_ucred:1.77.0.2 gmcgarry_ucred_base:1.77 nathanw_sa_base:1.78 kqueue-aftermerge:1.77 kqueue-beforemerge:1.77 netbsd-1-6-RELEASE:1.57.6.1 netbsd-1-6-RC3:1.57.6.1 netbsd-1-6-RC2:1.57.6.1 netbsd-1-6-RC1:1.57.6.1 netbsd-1-6:1.57.0.6 netbsd-1-6-base:1.57 gehenna-devsw:1.57.0.4 gehenna-devsw-base:1.71 netbsd-1-5-PATCH003:1.30.4.3 eeh-devprop:1.57.0.2 eeh-devprop-base:1.57 newlock:1.56.0.4 newlock-base:1.56 ifpoll-base:1.56 thorpej-mips-cache:1.54.0.2 thorpej-mips-cache-base:1.54 thorpej-devvp-base3:1.51 thorpej-devvp-base2:1.51 post-chs-ubcperf:1.51 pre-chs-ubcperf:1.51 thorpej-devvp:1.51.0.2 thorpej-devvp-base:1.51 netbsd-1-5-PATCH002:1.30.4.3 kqueue:1.49.0.2 kqueue-base:1.76 netbsd-1-5-PATCH001:1.30.4.3 thorpej_scsipi_beforemerge:1.45 nathanw_sa:1.42.0.2 thorpej_scsipi_nbase:1.45 netbsd-1-5-RELEASE:1.30.4.1 netbsd-1-5-BETA2:1.30.4.1 netbsd-1-5-BETA:1.30.4.1 netbsd-1-5-ALPHA2:1.30.4.1 netbsd-1-5:1.30.0.4 netbsd-1-5-base:1.30 minoura-xpg4dl-base:1.30 minoura-xpg4dl:1.30.0.2 chs-ubc2-newbase:1.17 wrstuden-devbsize-19991221:1.12 wrstuden-devbsize:1.10.0.8 wrstuden-devbsize-base:1.12 kame_141_19991130:1.1.2.3 comdex-fall-1999:1.10.0.6 comdex-fall-1999-base:1.10 fvdl-softdep:1.10.0.4 fvdl-softdep-base:1.10 thorpej_scsipi:1.10.0.2 thorpej_scsipi_base:1.45 kame_14_19990705:1.1.2.2 chs-ubc2-base:1.8 chs-ubc2:1.2.0.2 kame_14_19990628:1.1.2.1 kame:1.1.0.2; locks; strict; comment @ * @; 1.281 date 2023.12.09.15.21.02; author pgoyette; state Exp; branches; next 1.280; commitid mYXoODyAIzzXQNPE; 1.280 date 2023.10.11.09.13.51; author msaitoh; state Exp; branches; next 1.279; commitid jJ7blzcPt37mJbIE; 1.279 date 2022.09.01.18.32.17; author riastradh; state Exp; branches 1.279.4.1; next 1.278; commitid xu0IZ6LZcjz9QbSD; 1.278 date 2021.12.31.12.41.50; author andvar; state Exp; branches; next 1.277; commitid cG2tzZ9M4Np4KNmD; 1.277 date 2021.08.17.09.43.21; author ozaki-r; state Exp; branches; next 1.276; commitid vO1uZTqBqoh08j5D; 1.276 date 2020.12.28.20.19.50; author nia; state Exp; branches; next 1.275; commitid Kpt3378FlL7D6yBC; 1.275 date 2020.12.26.10.43.39; author nia; state Exp; branches; next 1.274; commitid Ne16xsP8stLRYeBC; 1.274 date 2020.09.15.10.05.36; author roy; state Exp; branches 1.274.2.1; next 1.273; commitid WU0lSQDXq0Yl28oC; 1.273 date 2020.09.14.15.09.57; author roy; state Exp; branches; next 1.272; commitid AL4vrNcdH2t7L1oC; 1.272 date 2020.09.11.15.03.33; author roy; state Exp; branches; next 1.271; commitid IwzHuv5D9Y14PDnC; 1.271 date 2020.06.12.11.04.45; author roy; state Exp; branches; next 1.270; commitid OaWPbwiyPUMQnVbC; 1.270 date 2020.04.28.15.12.28; author roy; state Exp; branches; next 1.269; commitid rtjv1CqhGl3Oea6C; 1.269 date 2020.04.12.12.13.52; author roy; state Exp; branches; next 1.268; commitid ZWTDGZEeUA0tL54C; 1.268 date 2020.04.03.14.04.27; author christos; state Exp; branches 1.268.2.1; next 1.267; commitid ajdxQsTJazHNFW2C; 1.267 date 2020.03.09.21.20.56; author roy; state Exp; branches; next 1.266; commitid XGwvZaFWCfVwTLZB; 1.266 date 2020.01.20.18.38.22; author thorpej; state Exp; branches; next 1.265; commitid 5IWAFx2BxNcmzsTB; 1.265 date 2019.09.25.09.53.38; author ozaki-r; state Exp; branches 1.265.2.1; next 1.264; commitid 5IkSPia7NxIBqnEB; 1.264 date 2019.09.25.09.52.32; author ozaki-r; state Exp; branches; next 1.263; commitid hBgdbRvbQ7OeqnEB; 1.263 date 2019.09.01.19.26.21; author roy; state Exp; branches; next 1.262; commitid 8yQb0Q0pk7enjlBB; 1.262 date 2019.09.01.18.54.38; author roy; state Exp; branches; next 1.261; commitid iGB6J80MsBlL8lBB; 1.261 date 2019.08.31.01.49.45; author roy; state Exp; branches; next 1.260; commitid zgcBlNKe0GbTw7BB; 1.260 date 2019.08.27.21.11.26; author roy; state Exp; branches; next 1.259; commitid pNkqXC9A5S8x5IAB; 1.259 date 2019.08.22.21.22.50; author roy; state Exp; branches; next 1.258; commitid c7pyEhR0coGZj4AB; 1.258 date 2019.08.22.21.14.46; author roy; state Exp; branches; next 1.257; commitid 4u73X5zqHiXLg4AB; 1.257 date 2019.08.14.08.34.44; author ozaki-r; state Exp; branches; next 1.256; commitid bHiiXIcWeXZflYyB; 1.256 date 2019.07.26.10.18.42; author christos; state Exp; branches 1.256.2.1; next 1.255; commitid ivGf81UM77gBwxwB; 1.255 date 2019.06.28.06.45.16; author ozaki-r; state Exp; branches; next 1.254; commitid Ucadr4Naz5ImfVsB; 1.254 date 2019.05.13.02.03.07; author christos; state Exp; branches; next 1.253; commitid VQ1vNCZSMt5caZmB; 1.253 date 2019.04.29.11.57.22; author roy; state Exp; branches; next 1.252; commitid u9oMahxjzdJFOelB; 1.252 date 2018.12.16.08.54.58; author roy; state Exp; branches; next 1.251; commitid wnAl5KxkrOHXb04B; 1.251 date 2018.10.30.05.54.41; author ozaki-r; state Exp; branches; next 1.250; commitid Qa4DO2fWI1ziIWXA; 1.250 date 2018.09.03.16.29.36; author riastradh; state Exp; branches; next 1.249; commitid BTC4S53hMH8f3GQA; 1.249 date 2018.05.29.04.38.29; author ozaki-r; state Exp; branches 1.249.2.1; next 1.248; commitid 2PZwUXYHFpd4f9EA; 1.248 date 2018.05.01.07.21.39; author maxv; state Exp; branches; next 1.247; commitid WJfFRrHJ8oMH2zAA; 1.247 date 2018.03.06.10.57.00; author roy; state Exp; branches; next 1.246; commitid QyEWBnkWgWdG0otA; 1.246 date 2018.03.06.07.24.01; author ozaki-r; state Exp; branches; next 1.245; commitid u8DjpCt86NVfRmtA; 1.245 date 2018.01.29.19.51.15; author christos; state Exp; branches 1.245.2.1; next 1.244; commitid 1bAmWiX69xue9OoA; 1.244 date 2018.01.29.03.42.53; author pgoyette; state Exp; branches; next 1.243; commitid SihSYcIFCBkUMIoA; 1.243 date 2018.01.29.03.35.23; author pgoyette; state Exp; branches; next 1.242; commitid boWjCTwLK65nKIoA; 1.242 date 2018.01.29.03.29.26; author pgoyette; state Exp; branches; next 1.241; commitid h8I7JYjRBUqnIIoA; 1.241 date 2018.01.29.02.02.14; author pgoyette; state Exp; branches; next 1.240; commitid coOPTx8gHDUqdIoA; 1.240 date 2017.12.15.04.03.46; author ozaki-r; state Exp; branches; next 1.239; commitid alcmYVD2DnBXlWiA; 1.239 date 2017.11.17.07.37.12; author ozaki-r; state Exp; branches; next 1.238; commitid 1NQBDXAUtBTZqmfA; 1.238 date 2017.11.10.07.25.39; author ozaki-r; state Exp; branches; next 1.237; commitid CgfInZbwJLNZAseA; 1.237 date 2017.11.10.07.24.28; author ozaki-r; state Exp; branches; next 1.236; commitid GsyBhSAIc6DAAseA; 1.236 date 2017.10.05.03.42.14; author ozaki-r; state Exp; branches; next 1.235; commitid FttvI4rSL5i6wO9A; 1.235 date 2017.06.22.09.24.02; author ozaki-r; state Exp; branches; next 1.234; 1.234 date 2017.06.21.09.05.31; author ozaki-r; state Exp; branches; next 1.233; 1.233 date 2017.06.16.02.24.54; author ozaki-r; state Exp; branches; next 1.232; 1.232 date 2017.06.01.02.45.14; author chs; state Exp; branches 1.232.2.1; next 1.231; 1.231 date 2017.03.01.03.02.35; author ozaki-r; state Exp; branches; next 1.230; 1.230 date 2017.02.22.07.46.00; author ozaki-r; state Exp; branches; next 1.229; 1.229 date 2017.02.22.03.41.54; author ozaki-r; state Exp; branches; next 1.228; 1.228 date 2017.02.22.03.02.55; author ozaki-r; state Exp; branches; next 1.227; 1.227 date 2017.02.14.03.05.06; author ozaki-r; state Exp; branches; next 1.226; 1.226 date 2017.01.16.15.44.47; author christos; state Exp; branches; next 1.225; 1.225 date 2017.01.16.07.33.36; author ryo; state Exp; branches; next 1.224; 1.224 date 2017.01.11.13.08.29; author ozaki-r; state Exp; branches 1.224.2.1; next 1.223; 1.223 date 2016.12.22.03.46.51; author ozaki-r; state Exp; branches; next 1.222; 1.222 date 2016.12.21.08.47.02; author ozaki-r; state Exp; branches; next 1.221; 1.221 date 2016.12.21.04.08.47; author ozaki-r; state Exp; branches; next 1.220; 1.220 date 2016.12.19.07.51.34; author ozaki-r; state Exp; branches; next 1.219; 1.219 date 2016.12.19.04.52.17; author ozaki-r; state Exp; branches; next 1.218; 1.218 date 2016.12.19.03.32.54; author ozaki-r; state Exp; branches; next 1.217; 1.217 date 2016.12.14.04.05.11; author ozaki-r; state Exp; branches; next 1.216; 1.216 date 2016.12.12.03.55.57; author ozaki-r; state Exp; branches; next 1.215; 1.215 date 2016.12.12.03.14.01; author ozaki-r; state Exp; branches; next 1.214; 1.214 date 2016.12.12.03.13.14; author ozaki-r; state Exp; branches; next 1.213; 1.213 date 2016.12.11.07.38.50; author ozaki-r; state Exp; branches; next 1.212; 1.212 date 2016.12.11.07.37.53; author ozaki-r; state Exp; branches; next 1.211; 1.211 date 2016.11.14.02.34.19; author ozaki-r; state Exp; branches; next 1.210; 1.210 date 2016.11.02.03.43.27; author ozaki-r; state Exp; branches; next 1.209; 1.209 date 2016.10.18.07.30.31; author ozaki-r; state Exp; branches; next 1.208; 1.208 date 2016.10.18.02.46.50; author ozaki-r; state Exp; branches; next 1.207; 1.207 date 2016.09.02.07.15.14; author ozaki-r; state Exp; branches; next 1.206; 1.206 date 2016.08.06.20.00.14; author roy; state Exp; branches; next 1.205; 1.205 date 2016.08.01.03.15.31; author ozaki-r; state Exp; branches; next 1.204; 1.204 date 2016.07.15.07.40.09; author ozaki-r; state Exp; branches; next 1.203; 1.203 date 2016.07.11.07.37.00; author ozaki-r; state Exp; branches 1.203.2.1; next 1.202; 1.202 date 2016.07.07.09.32.03; author ozaki-r; state Exp; branches; next 1.201; 1.201 date 2016.07.05.06.32.18; author ozaki-r; state Exp; branches; next 1.200; 1.200 date 2016.07.05.04.25.23; author ozaki-r; state Exp; branches; next 1.199; 1.199 date 2016.07.04.06.48.14; author ozaki-r; state Exp; branches; next 1.198; 1.198 date 2016.06.30.01.34.53; author ozaki-r; state Exp; branches; next 1.197; 1.197 date 2016.06.21.02.14.11; author ozaki-r; state Exp; branches; next 1.196; 1.196 date 2016.06.20.06.46.38; author knakahara; state Exp; branches; next 1.195; 1.195 date 2016.05.18.11.28.44; author ozaki-r; state Exp; branches; next 1.194; 1.194 date 2016.05.12.02.24.17; author ozaki-r; state Exp; branches; next 1.193; 1.193 date 2016.04.26.09.30.01; author ozaki-r; state Exp; branches; next 1.192; 1.192 date 2016.04.25.14.38.08; author ozaki-r; state Exp; branches; next 1.191; 1.191 date 2016.04.21.05.07.50; author ozaki-r; state Exp; branches; next 1.190; 1.190 date 2016.04.10.08.15.52; author ozaki-r; state Exp; branches; next 1.189; 1.189 date 2016.04.04.12.05.40; author roy; state Exp; branches; next 1.188; 1.188 date 2016.04.04.07.37.07; author ozaki-r; state Exp; branches; next 1.187; 1.187 date 2016.04.01.08.12.00; author ozaki-r; state Exp; branches; next 1.186; 1.186 date 2016.04.01.05.11.38; author ozaki-r; state Exp; branches; next 1.185; 1.185 date 2016.02.04.02.48.37; author riastradh; state Exp; branches; next 1.184; 1.184 date 2016.01.08.08.50.07; author ozaki-r; state Exp; branches; next 1.183; 1.183 date 2015.12.18.09.04.33; author ozaki-r; state Exp; branches; next 1.182; 1.182 date 2015.12.07.06.19.13; author ozaki-r; state Exp; branches; next 1.181; 1.181 date 2015.11.25.06.21.26; author ozaki-r; state Exp; branches; next 1.180; 1.180 date 2015.11.19.03.02.10; author ozaki-r; state Exp; branches; next 1.179; 1.179 date 2015.11.18.05.16.22; author ozaki-r; state Exp; branches; next 1.178; 1.178 date 2015.11.18.02.51.11; author ozaki-r; state Exp; branches; next 1.177; 1.177 date 2015.09.11.10.33.32; author roy; state Exp; branches; next 1.176; 1.176 date 2015.09.04.05.33.23; author ozaki-r; state Exp; branches; next 1.175; 1.175 date 2015.09.03.00.54.39; author ozaki-r; state Exp; branches; next 1.174; 1.174 date 2015.09.02.11.35.11; author ozaki-r; state Exp; branches; next 1.173; 1.173 date 2015.09.02.08.03.10; author ozaki-r; state Exp; branches; next 1.172; 1.172 date 2015.09.01.08.52.02; author ozaki-r; state Exp; branches; next 1.171; 1.171 date 2015.09.01.08.46.27; author ozaki-r; state Exp; branches; next 1.170; 1.170 date 2015.08.31.03.26.53; author ozaki-r; state Exp; branches; next 1.169; 1.169 date 2015.08.24.22.21.27; author pooka; state Exp; branches; next 1.168; 1.168 date 2015.08.11.09.30.32; author ozaki-r; state Exp; branches; next 1.167; 1.167 date 2015.08.11.08.27.08; author ozaki-r; state Exp; branches; next 1.166; 1.166 date 2015.08.07.08.11.33; author ozaki-r; state Exp; branches; next 1.165; 1.165 date 2015.07.17.02.21.08; author ozaki-r; state Exp; branches; next 1.164; 1.164 date 2015.07.15.09.20.18; author ozaki-r; state Exp; branches; next 1.163; 1.163 date 2015.06.30.08.31.42; author ozaki-r; state Exp; branches; next 1.162; 1.162 date 2015.04.30.10.00.04; author ozaki-r; state Exp; branches; next 1.161; 1.161 date 2015.03.30.04.25.26; author ozaki-r; state Exp; branches; next 1.160; 1.160 date 2015.02.25.12.45.34; author roy; state Exp; branches; next 1.159; 1.159 date 2015.02.25.00.26.58; author roy; state Exp; branches; next 1.158; 1.158 date 2015.02.23.19.15.59; author martin; state Exp; branches; next 1.157; 1.157 date 2015.02.17.15.14.28; author christos; state Exp; branches; next 1.156; 1.156 date 2014.12.16.11.42.27; author roy; state Exp; branches; next 1.155; 1.155 date 2014.12.03.01.32.11; author christos; state Exp; branches; next 1.154; 1.154 date 2014.10.18.08.33.29; author snj; state Exp; branches 1.154.2.1; next 1.153; 1.153 date 2014.10.14.15.29.43; author roy; state Exp; branches; next 1.152; 1.152 date 2014.06.06.01.02.47; author rmind; state Exp; branches 1.152.2.1; next 1.151; 1.151 date 2014.06.05.16.06.49; author roy; state Exp; branches; next 1.150; 1.150 date 2014.05.20.20.23.56; author bouyer; state Exp; branches; next 1.149; 1.149 date 2014.05.17.20.44.24; author rmind; state Exp; branches; next 1.148; 1.148 date 2014.03.20.13.34.35; author roy; state Exp; branches 1.148.2.1; next 1.147; 1.147 date 2014.01.15.10.25.04; author roy; state Exp; branches; next 1.146; 1.146 date 2013.12.17.20.25.00; author martin; state Exp; branches; next 1.145; 1.145 date 2013.05.21.08.37.27; author roy; state Exp; branches 1.145.2.1; next 1.144; 1.144 date 2013.01.24.14.23.09; author joerg; state Exp; branches; next 1.143; 1.143 date 2012.06.23.03.14.04; author christos; state Exp; branches 1.143.2.1; next 1.142; 1.142 date 2012.03.22.20.34.41; author drochner; state Exp; branches; next 1.141; 1.141 date 2012.02.03.03.32.45; author christos; state Exp; branches 1.141.2.1 1.141.6.1 1.141.8.1; next 1.140; 1.140 date 2012.02.02.19.35.18; author christos; state Exp; branches; next 1.139; 1.139 date 2011.12.19.11.59.58; author drochner; state Exp; branches; next 1.138; 1.138 date 2011.11.19.22.51.29; author tls; state Exp; branches 1.138.2.1; next 1.137; 1.137 date 2011.11.10.17.10.00; author seanb; state Exp; branches; next 1.136; 1.136 date 2010.07.15.19.15.30; author dyoung; state Exp; branches 1.136.8.1; next 1.135; 1.135 date 2009.11.06.20.41.22; author dyoung; state Exp; branches 1.135.2.1 1.135.4.1; next 1.134; 1.134 date 2009.08.31.12.37.59; author yamt; state Exp; branches; next 1.133; 1.133 date 2009.08.06.12.17.11; author cegger; state Exp; branches; next 1.132; 1.132 date 2009.07.25.23.12.09; author tonnerre; state Exp; branches; next 1.131; 1.131 date 2008.11.07.00.20.18; author dyoung; state Exp; branches; next 1.130; 1.130 date 2008.10.24.17.07.33; author dyoung; state Exp; branches 1.130.2.1 1.130.4.1 1.130.10.1 1.130.14.1; next 1.129; 1.129 date 2008.10.24.16.54.18; author dyoung; state Exp; branches; next 1.128; 1.128 date 2008.05.15.01.33.28; author dyoung; state Exp; branches 1.128.4.1; next 1.127; 1.127 date 2008.05.11.20.19.44; author dyoung; state Exp; branches; next 1.126; 1.126 date 2008.04.24.11.38.38; author ad; state Exp; branches 1.126.2.1 1.126.4.1; next 1.125; 1.125 date 2008.04.15.03.57.04; author thorpej; state Exp; branches 1.125.2.1; next 1.124; 1.124 date 2008.04.08.15.04.35; author thorpej; state Exp; branches; next 1.123; 1.123 date 2007.12.04.10.27.34; author dyoung; state Exp; branches 1.123.8.1 1.123.12.1; next 1.122; 1.122 date 2007.11.10.00.07.57; author dyoung; state Exp; branches 1.122.2.1; next 1.121; 1.121 date 2007.11.01.20.33.58; author dyoung; state Exp; branches 1.121.2.1; next 1.120; 1.120 date 2007.09.02.19.42.22; author dyoung; state Exp; branches 1.120.4.1; next 1.119; 1.119 date 2007.08.30.02.17.38; author dyoung; state Exp; branches; next 1.118; 1.118 date 2007.08.07.04.35.42; author dyoung; state Exp; branches 1.118.2.1 1.118.4.1; next 1.117; 1.117 date 2007.07.19.20.48.57; author dyoung; state Exp; branches 1.117.4.1; next 1.116; 1.116 date 2007.07.09.21.11.13; author ad; state Exp; branches 1.116.2.1; next 1.115; 1.115 date 2007.05.17.00.53.26; author dyoung; state Exp; branches; next 1.114; 1.114 date 2007.05.02.20.40.27; author dyoung; state Exp; branches; next 1.113; 1.113 date 2007.03.17.06.32.46; author dyoung; state Exp; branches; next 1.112; 1.112 date 2007.03.15.23.35.25; author dyoung; state Exp; branches; next 1.111; 1.111 date 2007.03.04.06.03.27; author christos; state Exp; branches 1.111.2.1 1.111.4.1 1.111.6.1; next 1.110; 1.110 date 2007.02.17.22.34.14; author dyoung; state Exp; branches; next 1.109; 1.109 date 2006.11.24.19.47.00; author christos; state Exp; branches 1.109.4.1; next 1.108; 1.108 date 2006.11.20.04.34.16; author dyoung; state Exp; branches; next 1.107; 1.107 date 2006.11.16.01.33.45; author christos; state Exp; branches; next 1.106; 1.106 date 2006.11.13.05.13.42; author dyoung; state Exp; branches; next 1.105; 1.105 date 2006.10.12.01.32.39; author christos; state Exp; branches; next 1.104; 1.104 date 2006.09.02.07.22.44; author christos; state Exp; branches 1.104.2.1 1.104.4.1; next 1.103; 1.103 date 2006.06.07.22.34.04; author kardel; state Exp; branches; next 1.102; 1.102 date 2006.05.18.09.05.51; author liamjfoy; state Exp; branches 1.102.2.1; next 1.101; 1.101 date 2006.04.15.00.09.29; author christos; state Exp; branches; next 1.100; 1.100 date 2006.03.24.19.24.38; author rpaulo; state Exp; branches; next 1.99; 1.99 date 2006.03.05.23.47.08; author rpaulo; state Exp; branches 1.99.2.1 1.99.4.1; next 1.98; 1.98 date 2006.03.03.14.07.06; author rpaulo; state Exp; branches 1.98.2.1; next 1.97; 1.97 date 2006.03.02.05.11.31; author dyoung; state Exp; branches; next 1.96; 1.96 date 2006.01.21.00.15.36; author rpaulo; state Exp; branches 1.96.2.1 1.96.4.1; next 1.95; 1.95 date 2005.12.11.12.25.02; author christos; state Exp; branches 1.95.2.1; next 1.94; 1.94 date 2005.05.29.21.43.51; author christos; state Exp; branches 1.94.2.1; next 1.93; 1.93 date 2005.05.27.22.26.25; author seanb; state Exp; branches; next 1.92; 1.92 date 2005.04.03.11.02.27; author tron; state Exp; branches; next 1.91; 1.91 date 2004.12.04.16.10.25; author peter; state Exp; branches 1.91.4.1 1.91.10.1; next 1.90; 1.90 date 2004.05.19.17.45.05; author itojun; state Exp; branches; next 1.89; 1.89 date 2004.02.11.10.37.33; author itojun; state Exp; branches 1.89.2.1 1.89.4.1; next 1.88; 1.88 date 2003.10.30.01.43.09; author simonb; state Exp; branches; next 1.87; 1.87 date 2003.08.22.22.11.46; author itojun; state Exp; branches; next 1.86; 1.86 date 2003.06.27.08.41.08; author itojun; state Exp; branches 1.86.2.1; next 1.85; 1.85 date 2003.06.24.07.54.48; author itojun; state Exp; branches; next 1.84; 1.84 date 2003.06.24.07.49.03; author itojun; state Exp; branches; next 1.83; 1.83 date 2003.06.24.07.39.26; author itojun; state Exp; branches; next 1.82; 1.82 date 2003.06.24.07.32.03; author itojun; state Exp; branches; next 1.81; 1.81 date 2003.05.04.13.43.09; author christos; state Exp; branches; next 1.80; 1.80 date 2003.02.25.22.17.47; author he; state Exp; branches; next 1.79; 1.79 date 2003.02.01.06.23.47; author thorpej; state Exp; branches; next 1.78; 1.78 date 2003.01.17.08.11.58; author itojun; state Exp; branches; next 1.77; 1.77 date 2002.10.09.20.22.16; author itojun; state Exp; branches; next 1.76; 1.76 date 2002.09.27.15.37.54; author provos; state Exp; branches; next 1.75; 1.75 date 2002.09.23.13.16.53; author itojun; state Exp; branches; next 1.74; 1.74 date 2002.09.23.05.51.15; author simonb; state Exp; branches; next 1.73; 1.73 date 2002.09.11.02.46.46; author itojun; state Exp; branches; next 1.72; 1.72 date 2002.09.04.07.22.28; author itojun; state Exp; branches; next 1.71; 1.71 date 2002.08.19.23.23.22; author itojun; state Exp; branches; next 1.70; 1.70 date 2002.08.19.23.21.11; author itojun; state Exp; branches; next 1.69; 1.69 date 2002.08.19.23.14.39; author itojun; state Exp; branches; next 1.68; 1.68 date 2002.08.19.07.23.22; author itojun; state Exp; branches; next 1.67; 1.67 date 2002.08.19.06.50.22; author itojun; state Exp; branches; next 1.66; 1.66 date 2002.06.09.14.43.13; author itojun; state Exp; branches; next 1.65; 1.65 date 2002.06.08.21.22.34; author itojun; state Exp; branches; next 1.64; 1.64 date 2002.06.07.17.15.12; author itojun; state Exp; branches; next 1.63; 1.63 date 2002.06.03.02.09.37; author itojun; state Exp; branches; next 1.62; 1.62 date 2002.06.03.00.51.47; author itojun; state Exp; branches; next 1.61; 1.61 date 2002.05.30.05.06.29; author itojun; state Exp; branches; next 1.60; 1.60 date 2002.05.29.13.56.14; author itojun; state Exp; branches; next 1.59; 1.59 date 2002.05.29.13.52.56; author itojun; state Exp; branches; next 1.58; 1.58 date 2002.05.29.07.53.41; author itojun; state Exp; branches; next 1.57; 1.57 date 2002.03.20.22.47.59; author itojun; state Exp; branches 1.57.4.1 1.57.6.1; next 1.56; 1.56 date 2001.12.18.03.04.04; author itojun; state Exp; branches; next 1.55; 1.55 date 2001.11.13.00.57.04; author lukem; state Exp; branches; next 1.54; 1.54 date 2001.10.17.10.55.09; author itojun; state Exp; branches; next 1.53; 1.53 date 2001.10.17.08.23.07; author itojun; state Exp; branches; next 1.52; 1.52 date 2001.10.16.06.24.45; author itojun; state Exp; branches; next 1.51; 1.51 date 2001.07.25.06.59.52; author itojun; state Exp; branches; next 1.50; 1.50 date 2001.07.20.20.26.35; author itojun; state Exp; branches; next 1.49; 1.49 date 2001.06.29.16.01.47; author itojun; state Exp; branches 1.49.2.1; next 1.48; 1.48 date 2001.06.27.17.36.14; author itojun; state Exp; branches; next 1.47; 1.47 date 2001.06.22.13.36.12; author itojun; state Exp; branches; next 1.46; 1.46 date 2001.05.24.08.17.22; author itojun; state Exp; branches; next 1.45; 1.45 date 2001.03.30.11.08.58; author itojun; state Exp; branches; next 1.44; 1.44 date 2001.03.21.21.56.29; author itojun; state Exp; branches; next 1.43; 1.43 date 2001.03.08.10.49.32; author itojun; state Exp; branches; next 1.42; 1.42 date 2001.02.23.08.02.41; author itojun; state Exp; branches 1.42.2.1; next 1.41; 1.41 date 2001.02.23.06.41.50; author itojun; state Exp; branches; next 1.40; 1.40 date 2001.02.21.17.23.09; author itojun; state Exp; branches; next 1.39; 1.39 date 2001.02.21.16.28.43; author itojun; state Exp; branches; next 1.38; 1.38 date 2001.02.10.04.14.29; author itojun; state Exp; branches; next 1.37; 1.37 date 2001.02.08.12.57.54; author itojun; state Exp; branches; next 1.36; 1.36 date 2001.02.07.08.59.48; author itojun; state Exp; branches; next 1.35; 1.35 date 2001.02.05.10.42.45; author chs; state Exp; branches; next 1.34; 1.34 date 2001.01.17.04.05.45; author itojun; state Exp; branches; next 1.33; 1.33 date 2000.11.05.17.17.16; author onoe; state Exp; branches; next 1.32; 1.32 date 2000.10.15.15.39.12; author itojun; state Exp; branches; next 1.31; 1.31 date 2000.07.06.12.36.19; author itojun; state Exp; branches; next 1.30; 1.30 date 2000.05.19.01.40.19; author itojun; state Exp; branches 1.30.4.1; next 1.29; 1.29 date 2000.05.09.11.51.12; author itojun; state Exp; branches; next 1.28; 1.28 date 2000.04.27.00.33.47; author itojun; state Exp; branches; next 1.27; 1.27 date 2000.04.19.07.13.03; author itojun; state Exp; branches; next 1.26; 1.26 date 2000.04.16.15.28.00; author itojun; state Exp; branches; next 1.25; 1.25 date 2000.04.16.15.00.57; author itojun; state Exp; branches; next 1.24; 1.24 date 2000.04.13.16.27.00; author itojun; state Exp; branches; next 1.23; 1.23 date 2000.04.13.14.32.53; author itojun; state Exp; branches; next 1.22; 1.22 date 2000.04.13.14.11.06; author itojun; state Exp; branches; next 1.21; 1.21 date 2000.04.12.10.36.45; author itojun; state Exp; branches; next 1.20; 1.20 date 2000.03.23.07.03.30; author thorpej; state Exp; branches; next 1.19; 1.19 date 2000.02.28.12.08.24; author itojun; state Exp; branches; next 1.18; 1.18 date 2000.02.26.08.39.20; author itojun; state Exp; branches; next 1.17; 1.17 date 2000.02.06.12.49.47; author itojun; state Exp; branches; next 1.16; 1.16 date 2000.02.04.14.34.27; author itojun; state Exp; branches; next 1.15; 1.15 date 2000.02.03.12.50.05; author itojun; state Exp; branches; next 1.14; 1.14 date 2000.02.01.22.52.11; author thorpej; state Exp; branches; next 1.13; 1.13 date 2000.01.06.15.46.10; author itojun; state Exp; branches; next 1.12; 1.12 date 99.12.13.15.17.23; author itojun; state Exp; branches; next 1.11; 1.11 date 99.12.10.17.56.13; author itojun; state Exp; branches; next 1.10; 1.10 date 99.09.20.02.35.44; author itojun; state Exp; branches 1.10.2.1 1.10.8.1; next 1.9; 1.9 date 99.09.19.21.31.35; author is; state Exp; branches; next 1.8; 1.8 date 99.07.31.18.41.17; author itojun; state Exp; branches; next 1.7; 1.7 date 99.07.30.10.35.37; author itojun; state Exp; branches; next 1.6; 1.6 date 99.07.06.12.23.22; author itojun; state Exp; branches; next 1.5; 1.5 date 99.07.04.02.01.15; author itojun; state Exp; branches; next 1.4; 1.4 date 99.07.03.21.30.19; author thorpej; state Exp; branches; next 1.3; 1.3 date 99.07.02.12.43.42; author itojun; state Exp; branches; next 1.2; 1.2 date 99.07.01.08.12.57; author itojun; state Exp; branches 1.2.2.1; next 1.1; 1.1 date 99.06.28.06.37.07; author itojun; state dead; branches 1.1.2.1; next ; 1.279.4.1 date 2023.12.10.13.06.16; author martin; state Exp; branches; next ; commitid CZHFuDAFp1RB5VPE; 1.274.2.1 date 2021.01.03.16.35.04; author thorpej; state Exp; branches; next ; commitid hSJGvbJZNH5wFiCC; 1.268.2.1 date 2020.04.20.11.29.12; author bouyer; state Exp; branches; next ; commitid 4WLfIgNPymVsg75C; 1.265.2.1 date 2020.01.25.22.38.52; author ad; state Exp; branches; next ; commitid ethRERRmx7bMJ7UB; 1.256.2.1 date 2019.08.19.16.08.19; author martin; state Exp; branches; next 1.256.2.2; commitid WRF4QnHTxHDTGEzB; 1.256.2.2 date 2019.08.26.13.42.36; author martin; state Exp; branches; next 1.256.2.3; commitid aKOPv7YYqmiXExAB; 1.256.2.3 date 2019.09.01.11.00.31; author martin; state Exp; branches; next 1.256.2.4; commitid YyFnH7qJvWnoziBB; 1.256.2.4 date 2019.09.01.14.06.22; author martin; state Exp; branches; next 1.256.2.5; commitid MogSk2PAaSt9BjBB; 1.256.2.5 date 2019.09.05.08.28.06; author martin; state Exp; branches; next 1.256.2.6; commitid AOn3qQptDfK7BNBB; 1.256.2.6 date 2019.09.05.08.32.34; author martin; state Exp; branches; next 1.256.2.7; commitid LiouwOApDT6FCNBB; 1.256.2.7 date 2019.09.30.15.55.40; author martin; state Exp; branches; next 1.256.2.8; commitid kTJFIuoveG2Qg3FB; 1.256.2.8 date 2021.08.20.19.32.49; author martin; state Exp; branches; next 1.256.2.9; commitid r0K2aOBTNSjfiK5D; 1.256.2.9 date 2022.08.08.17.09.20; author martin; state Exp; branches; next ; commitid PJESE1ZgfRv196PD; 1.249.2.1 date 2019.06.10.22.09.48; author christos; state Exp; branches; next 1.249.2.2; commitid jtc8rnCzWiEEHGqB; 1.249.2.2 date 2020.04.13.08.05.17; author martin; state Exp; branches; next 1.249.2.3; commitid X01YhRUPVUDaec4C; 1.249.2.3 date 2020.04.21.18.42.44; author martin; state Exp; branches; next ; commitid 86tA4aEmdr3VCh5C; 1.245.2.1 date 2018.03.15.09.12.07; author pgoyette; state Exp; branches; next 1.245.2.2; commitid lb7w3QtkrVH4axuA; 1.245.2.2 date 2018.05.02.07.20.23; author pgoyette; state Exp; branches; next 1.245.2.3; commitid o3kRuNRzl9360HAA; 1.245.2.3 date 2018.06.25.07.26.07; author pgoyette; state Exp; branches; next 1.245.2.4; commitid 8PtAu9af7VvhiDHA; 1.245.2.4 date 2018.09.06.06.56.45; author pgoyette; state Exp; branches; next 1.245.2.5; commitid HCi1bXD317XIK0RA; 1.245.2.5 date 2018.11.26.01.52.51; author pgoyette; state Exp; branches; next 1.245.2.6; commitid Zj4q5SspGdKXto1B; 1.245.2.6 date 2018.12.26.14.02.05; author pgoyette; state Exp; branches; next ; commitid xUhK8IAeBM1azj5B; 1.232.2.1 date 2017.07.07.13.57.26; author martin; state Exp; branches; next 1.232.2.2; 1.232.2.2 date 2017.10.24.09.00.22; author snj; state Exp; branches; next 1.232.2.3; commitid hVPA1aMUhsUiFhcA; 1.232.2.3 date 2017.11.17.20.24.05; author snj; state Exp; branches; next 1.232.2.4; commitid 4H75KOARkGsEFqfA; 1.232.2.4 date 2017.11.17.20.26.19; author snj; state Exp; branches; next 1.232.2.5; commitid PYeZYHjSWqZOGqfA; 1.232.2.5 date 2018.01.02.10.20.34; author snj; state Exp; branches; next 1.232.2.6; commitid 07oy8c4rjfdaRhlA; 1.232.2.6 date 2018.02.05.14.55.16; author martin; state Exp; branches; next 1.232.2.7; commitid mjQRLJIycWIQhGpA; 1.232.2.7 date 2018.03.13.13.27.10; author martin; state Exp; branches; next 1.232.2.8; commitid mNR8KDB8iBeTDiuA; 1.232.2.8 date 2018.06.07.17.48.31; author martin; state Exp; branches; next 1.232.2.9; commitid IOXBjZGuaYm9knFA; 1.232.2.9 date 2018.11.06.14.38.58; author martin; state Exp; branches; next 1.232.2.10; commitid ua57EAfnZcidoTYA; 1.232.2.10 date 2019.07.08.16.30.58; author martin; state Exp; branches; next 1.232.2.11; commitid td0uvrvZRvpmaguB; 1.232.2.11 date 2019.07.26.11.27.36; author martin; state Exp; branches; next 1.232.2.12; commitid sXsRoJd9BPEpUxwB; 1.232.2.12 date 2019.08.19.14.28.12; author martin; state Exp; branches; next 1.232.2.13; commitid MQr41i2d4Jny8EzB; 1.232.2.13 date 2019.09.30.15.48.45; author martin; state Exp; branches; next 1.232.2.14; commitid nR84Gj8qkMBte3FB; 1.232.2.14 date 2021.08.20.19.34.49; author martin; state Exp; branches; next ; commitid arZMVsCQYQTViK5D; 1.224.2.1 date 2017.04.21.16.54.06; author bouyer; state Exp; branches; next ; 1.203.2.1 date 2016.07.26.03.24.23; author pgoyette; state Exp; branches; next 1.203.2.2; 1.203.2.2 date 2016.08.06.00.19.10; author pgoyette; state Exp; branches; next 1.203.2.3; 1.203.2.3 date 2016.11.04.14.49.21; author pgoyette; state Exp; branches; next 1.203.2.4; 1.203.2.4 date 2017.01.07.08.56.51; author pgoyette; state Exp; branches; next 1.203.2.5; 1.203.2.5 date 2017.03.20.06.57.51; author pgoyette; state Exp; branches; next ; 1.154.2.1 date 2015.04.06.15.18.23; author skrll; state Exp; branches; next 1.154.2.2; 1.154.2.2 date 2015.06.06.14.40.26; author skrll; state Exp; branches; next 1.154.2.3; 1.154.2.3 date 2015.09.22.12.06.11; author skrll; state Exp; branches; next 1.154.2.4; 1.154.2.4 date 2015.12.27.12.10.07; author skrll; state Exp; branches; next 1.154.2.5; 1.154.2.5 date 2016.03.19.11.30.33; author skrll; state Exp; branches; next 1.154.2.6; 1.154.2.6 date 2016.04.22.15.44.18; author skrll; state Exp; branches; next 1.154.2.7; 1.154.2.7 date 2016.05.29.08.44.39; author skrll; state Exp; branches; next 1.154.2.8; 1.154.2.8 date 2016.07.09.20.25.22; author skrll; state Exp; branches; next 1.154.2.9; 1.154.2.9 date 2016.10.05.20.56.09; author skrll; state Exp; branches; next 1.154.2.10; 1.154.2.10 date 2016.12.05.10.55.28; author skrll; state Exp; branches; next 1.154.2.11; 1.154.2.11 date 2017.02.05.13.40.59; author skrll; state Exp; branches; next 1.154.2.12; 1.154.2.12 date 2017.08.28.17.53.12; author skrll; state Exp; branches; next ; commitid UQQpnjvcNkUZn05A; 1.152.2.1 date 2014.10.27.13.39.11; author martin; state Exp; branches; next 1.152.2.2; 1.152.2.2 date 2014.12.17.18.43.47; author martin; state Exp; branches; next 1.152.2.3; 1.152.2.3 date 2015.04.06.01.32.33; author snj; state Exp; branches; next 1.152.2.4; 1.152.2.4 date 2017.05.12.05.44.10; author snj; state Exp; branches; next ; 1.148.2.1 date 2014.08.10.06.56.30; author tls; state Exp; branches; next ; 1.145.2.1 date 2013.07.17.03.16.31; author rmind; state Exp; branches; next 1.145.2.2; 1.145.2.2 date 2014.05.18.17.46.13; author rmind; state Exp; branches; next ; 1.143.2.1 date 2013.02.25.00.30.05; author tls; state Exp; branches; next 1.143.2.2; 1.143.2.2 date 2013.06.23.06.20.26; author tls; state Exp; branches; next 1.143.2.3; 1.143.2.3 date 2014.08.20.00.04.36; author tls; state Exp; branches; next 1.143.2.4; 1.143.2.4 date 2017.12.03.11.39.04; author jdolecek; state Exp; branches; next ; commitid XcIYRZTAh1LmerhA; 1.141.2.1 date 2013.07.08.07.40.07; author jdc; state Exp; branches; next 1.141.2.2; 1.141.2.2 date 2013.12.17.20.47.33; author bouyer; state Exp; branches; next 1.141.2.3; 1.141.2.3 date 2014.06.03.15.34.00; author msaitoh; state Exp; branches; next ; 1.141.6.1 date 2013.07.08.07.40.34; author jdc; state Exp; branches; next 1.141.6.2; 1.141.6.2 date 2013.12.17.20.47.43; author bouyer; state Exp; branches; next 1.141.6.3; 1.141.6.3 date 2014.06.18.09.35.40; author msaitoh; state Exp; branches; next ; 1.141.8.1 date 2013.07.08.07.40.56; author jdc; state Exp; branches; next 1.141.8.2; 1.141.8.2 date 2013.12.17.20.47.49; author bouyer; state Exp; branches; next 1.141.8.3; 1.141.8.3 date 2014.06.18.09.34.27; author msaitoh; state Exp; branches; next ; 1.138.2.1 date 2012.02.18.07.35.43; author mrg; state Exp; branches; next 1.138.2.2; 1.138.2.2 date 2012.04.05.21.33.47; author mrg; state Exp; branches; next ; 1.136.8.1 date 2012.04.17.00.08.45; author yamt; state Exp; branches; next 1.136.8.2; 1.136.8.2 date 2012.10.30.17.22.49; author yamt; state Exp; branches; next 1.136.8.3; 1.136.8.3 date 2014.05.22.11.41.10; author yamt; state Exp; branches; next ; 1.135.2.1 date 2010.08.17.06.47.47; author uebayasi; state Exp; branches; next ; 1.135.4.1 date 2011.03.05.20.55.59; author rmind; state Exp; branches; next ; 1.130.2.1 date 2009.01.19.13.20.14; author skrll; state Exp; branches; next ; 1.130.4.1 date 2013.12.17.20.57.11; author bouyer; state Exp; branches; next ; 1.130.10.1 date 2013.12.17.20.57.21; author bouyer; state Exp; branches; next ; 1.130.14.1 date 2013.12.17.20.58.16; author bouyer; state Exp; branches; next ; 1.128.4.1 date 2008.12.13.01.15.27; author haad; state Exp; branches; next ; 1.126.2.1 date 2008.05.16.02.25.45; author yamt; state Exp; branches; next 1.126.2.2; 1.126.2.2 date 2009.05.04.08.14.19; author yamt; state Exp; branches; next 1.126.2.3; 1.126.2.3 date 2009.08.19.18.48.25; author yamt; state Exp; branches; next 1.126.2.4; 1.126.2.4 date 2009.09.16.13.38.03; author yamt; state Exp; branches; next 1.126.2.5; 1.126.2.5 date 2010.03.11.15.04.29; author yamt; state Exp; branches; next 1.126.2.6; 1.126.2.6 date 2010.08.11.22.54.57; author yamt; state Exp; branches; next ; 1.126.4.1 date 2008.06.23.04.31.59; author wrstuden; state Exp; branches; next ; 1.125.2.1 date 2008.05.18.12.35.35; author yamt; state Exp; branches; next ; 1.123.8.1 date 2008.02.22.02.53.34; author keiichi; state Exp; branches; next ; 1.123.12.1 date 2008.06.02.13.24.27; author mjf; state Exp; branches; next 1.123.12.2; 1.123.12.2 date 2009.01.17.13.29.33; author mjf; state Exp; branches; next ; 1.122.2.1 date 2007.12.08.17.57.58; author ad; state Exp; branches; next ; 1.121.2.1 date 2007.11.19.00.49.14; author mjf; state Exp; branches; next 1.121.2.2; 1.121.2.2 date 2007.12.08.18.21.17; author mjf; state Exp; branches; next ; 1.120.4.1 date 2007.11.13.16.02.59; author bouyer; state Exp; branches; next ; 1.118.2.1 date 2007.11.06.23.34.08; author matt; state Exp; branches; next 1.118.2.2; 1.118.2.2 date 2008.01.09.01.57.39; author matt; state Exp; branches; next ; 1.118.4.1 date 2007.08.07.04.35.42; author dyoung; state dead; branches; next 1.118.4.2; 1.118.4.2 date 2007.08.07.04.35.43; author dyoung; state Exp; branches; next ; 1.117.4.1 date 2007.08.09.02.37.24; author jmcneill; state Exp; branches; next 1.117.4.2; 1.117.4.2 date 2007.09.03.16.49.08; author jmcneill; state Exp; branches; next 1.117.4.3; 1.117.4.3 date 2007.11.04.21.03.44; author jmcneill; state Exp; branches; next 1.117.4.4; 1.117.4.4 date 2007.11.11.16.48.35; author joerg; state Exp; branches; next 1.117.4.5; 1.117.4.5 date 2007.12.09.19.38.38; author jmcneill; state Exp; branches; next ; 1.116.2.1 date 2007.08.15.13.49.52; author skrll; state Exp; branches; next 1.116.2.2; 1.116.2.2 date 2007.09.03.10.23.48; author skrll; state Exp; branches; next ; 1.111.2.1 date 2007.04.10.13.26.51; author ad; state Exp; branches; next 1.111.2.2; 1.111.2.2 date 2007.06.08.14.17.58; author ad; state Exp; branches; next 1.111.2.3; 1.111.2.3 date 2007.07.01.21.50.54; author ad; state Exp; branches; next 1.111.2.4; 1.111.2.4 date 2007.08.20.21.28.06; author ad; state Exp; branches; next 1.111.2.5; 1.111.2.5 date 2007.10.09.13.44.56; author ad; state Exp; branches; next ; 1.111.4.1 date 2007.07.11.20.11.47; author mjf; state Exp; branches; next ; 1.111.6.1 date 2007.03.18.00.06.46; author reinoud; state Exp; branches; next ; 1.109.4.1 date 2007.02.27.16.55.04; author yamt; state Exp; branches; next 1.109.4.2; 1.109.4.2 date 2007.03.12.05.59.59; author rmind; state Exp; branches; next 1.109.4.3; 1.109.4.3 date 2007.03.24.14.56.12; author yamt; state Exp; branches; next 1.109.4.4; 1.109.4.4 date 2007.05.07.10.56.06; author yamt; state Exp; branches; next 1.109.4.5; 1.109.4.5 date 2007.05.17.13.41.52; author yamt; state Exp; branches; next ; 1.104.2.1 date 2006.11.18.21.39.37; author ad; state Exp; branches; next 1.104.2.2; 1.104.2.2 date 2007.01.12.01.04.15; author ad; state Exp; branches; next ; 1.104.4.1 date 2006.10.22.06.07.35; author yamt; state Exp; branches; next 1.104.4.2; 1.104.4.2 date 2006.12.10.07.19.16; author yamt; state Exp; branches; next ; 1.102.2.1 date 2006.06.19.04.09.49; author chap; state Exp; branches; next ; 1.99.2.1 date 2006.04.19.04.46.12; author elad; state Exp; branches; next ; 1.99.4.1 date 2006.03.28.09.42.28; author tron; state Exp; branches; next 1.99.4.2; 1.99.4.2 date 2006.05.24.15.50.45; author tron; state Exp; branches; next ; 1.98.2.1 date 2006.03.13.09.07.39; author yamt; state Exp; branches; next 1.98.2.2; 1.98.2.2 date 2006.04.01.12.07.50; author yamt; state Exp; branches; next 1.98.2.3; 1.98.2.3 date 2006.05.24.10.59.09; author yamt; state Exp; branches; next 1.98.2.4; 1.98.2.4 date 2006.06.26.12.54.13; author yamt; state Exp; branches; next 1.98.2.5; 1.98.2.5 date 2006.09.03.15.25.42; author yamt; state Exp; branches; next ; 1.96.2.1 date 2006.09.09.02.58.55; author rpaulo; state Exp; branches; next ; 1.96.4.1 date 2006.02.04.14.18.52; author simonb; state Exp; branches; next 1.96.4.2; 1.96.4.2 date 2006.04.22.11.40.13; author simonb; state Exp; branches; next 1.96.4.3; 1.96.4.3 date 2006.06.01.22.39.03; author kardel; state Exp; branches; next ; 1.95.2.1 date 2006.02.01.14.52.42; author yamt; state Exp; branches; next ; 1.94.2.1 date 2006.06.21.15.11.09; author yamt; state Exp; branches; next 1.94.2.2; 1.94.2.2 date 2006.12.30.20.50.39; author yamt; state Exp; branches; next 1.94.2.3; 1.94.2.3 date 2007.02.26.09.11.53; author yamt; state Exp; branches; next 1.94.2.4; 1.94.2.4 date 2007.09.03.14.43.40; author yamt; state Exp; branches; next 1.94.2.5; 1.94.2.5 date 2007.11.15.11.45.14; author yamt; state Exp; branches; next 1.94.2.6; 1.94.2.6 date 2007.12.07.17.34.37; author yamt; state Exp; branches; next ; 1.91.4.1 date 2005.04.29.11.29.34; author kent; state Exp; branches; next ; 1.91.10.1 date 2005.04.07.17.06.56; author jmc; state Exp; branches; next ; 1.89.2.1 date 2005.04.07.15.33.01; author he; state Exp; branches; next ; 1.89.4.1 date 2005.04.07.15.25.59; author he; state Exp; branches; next ; 1.86.2.1 date 2004.08.03.10.55.14; author skrll; state Exp; branches; next 1.86.2.2; 1.86.2.2 date 2004.09.18.14.55.15; author skrll; state Exp; branches; next 1.86.2.3; 1.86.2.3 date 2004.09.21.13.37.36; author skrll; state Exp; branches; next 1.86.2.4; 1.86.2.4 date 2004.12.18.09.33.06; author skrll; state Exp; branches; next 1.86.2.5; 1.86.2.5 date 2005.11.10.14.11.25; author skrll; state Exp; branches; next ; 1.57.4.1 date 2002.05.30.13.52.34; author gehenna; state Exp; branches; next 1.57.4.2; 1.57.4.2 date 2002.06.20.15.52.50; author gehenna; state Exp; branches; next 1.57.4.3; 1.57.4.3 date 2002.08.29.00.56.53; author gehenna; state Exp; branches; next ; 1.57.6.1 date 2002.06.04.12.57.23; author lukem; state Exp; branches; next ; 1.49.2.1 date 2001.08.03.04.14.00; author lukem; state Exp; branches; next 1.49.2.2; 1.49.2.2 date 2002.01.10.20.03.27; author thorpej; state Exp; branches; next 1.49.2.3; 1.49.2.3 date 2002.06.23.17.51.20; author jdolecek; state Exp; branches; next 1.49.2.4; 1.49.2.4 date 2002.09.06.08.49.37; author jdolecek; state Exp; branches; next 1.49.2.5; 1.49.2.5 date 2002.10.10.18.44.23; author jdolecek; state Exp; branches; next ; 1.42.2.1 date 2001.04.09.01.58.41; author nathanw; state Exp; branches; next 1.42.2.2; 1.42.2.2 date 2001.06.21.20.09.03; author nathanw; state Exp; branches; next 1.42.2.3; 1.42.2.3 date 2001.08.24.00.12.44; author nathanw; state Exp; branches; next 1.42.2.4; 1.42.2.4 date 2001.10.22.20.42.04; author nathanw; state Exp; branches; next 1.42.2.5; 1.42.2.5 date 2001.11.14.19.18.13; author nathanw; state Exp; branches; next 1.42.2.6; 1.42.2.6 date 2002.01.08.00.34.24; author nathanw; state Exp; branches; next 1.42.2.7; 1.42.2.7 date 2002.04.01.07.48.52; author nathanw; state Exp; branches; next 1.42.2.8; 1.42.2.8 date 2002.06.20.03.49.27; author nathanw; state Exp; branches; next 1.42.2.9; 1.42.2.9 date 2002.08.27.23.48.14; author nathanw; state Exp; branches; next 1.42.2.10; 1.42.2.10 date 2002.09.17.21.23.30; author nathanw; state Exp; branches; next 1.42.2.11; 1.42.2.11 date 2002.10.18.02.45.25; author nathanw; state Exp; branches; next 1.42.2.12; 1.42.2.12 date 2003.01.17.16.37.22; author thorpej; state Exp; branches; next ; 1.30.4.1 date 2000.07.20.00.07.05; author itojun; state Exp; branches; next 1.30.4.2; 1.30.4.2 date 2001.02.26.22.59.26; author he; state Exp; branches; next 1.30.4.3; 1.30.4.3 date 2001.05.09.19.42.27; author he; state Exp; branches; next ; 1.10.2.1 date 2000.11.20.18.10.56; author bouyer; state Exp; branches; next 1.10.2.2; 1.10.2.2 date 2000.11.22.16.06.25; author bouyer; state Exp; branches; next 1.10.2.3; 1.10.2.3 date 2001.01.18.09.23.57; author bouyer; state Exp; branches; next 1.10.2.4; 1.10.2.4 date 2001.02.11.19.17.28; author bouyer; state Exp; branches; next 1.10.2.5; 1.10.2.5 date 2001.03.12.13.31.56; author bouyer; state Exp; branches; next 1.10.2.6; 1.10.2.6 date 2001.03.27.15.32.39; author bouyer; state Exp; branches; next 1.10.2.7; 1.10.2.7 date 2001.04.21.17.46.57; author bouyer; state Exp; branches; next ; 1.10.8.1 date 99.12.27.18.36.27; author wrstuden; state Exp; branches; next ; 1.2.2.1 date 99.07.01.08.12.57; author thorpej; state dead; branches; next 1.2.2.2; 1.2.2.2 date 99.07.01.23.48.29; author thorpej; state Exp; branches; next 1.2.2.3; 1.2.2.3 date 99.08.02.22.36.06; author thorpej; state Exp; branches; next ; 1.1.2.1 date 99.06.28.06.37.07; author itojun; state Exp; branches; next 1.1.2.2; 1.1.2.2 date 99.07.06.11.03.02; author itojun; state Exp; branches; next 1.1.2.3; 1.1.2.3 date 99.11.30.13.35.58; author itojun; state Exp; branches; next ; desc @@ 1.281 log @Modularize the COMPAT_90 code that resulted from the removal of netinet6/nd6 from the kernel. Now, the minimal compat code can be successfully loaded and unloaded along with the rest of the COMPAT_90 code. XXX pullup-10 - hopefully before RC2 @ text @/* $NetBSD: nd6.c,v 1.280 2023/10/11 09:13:51 msaitoh Exp $ */ /* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * 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. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS 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: nd6.c,v 1.280 2023/10/11 09:13:51 msaitoh Exp $"); #ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" #include "opt_net_mpsafe.h" #endif #include "bridge.h" #include "carp.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */ #define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */ /* timer values */ int nd6_prune = 1; /* walk list every 1 seconds */ int nd6_useloopback = 1; /* use loopback interface for local traffic */ /* preventing too many loops in ND option parsing */ int nd6_maxndopt = 10; /* max # of ND options allowed */ #ifdef ND6_DEBUG int nd6_debug = 1; #else int nd6_debug = 0; #endif krwlock_t nd6_lock __cacheline_aligned; int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; static void nd6_slowtimo(void *); static void nd6_free(struct llentry *, int); static bool nd6_nud_enabled(struct ifnet *); static unsigned int nd6_llinfo_reachable(struct ifnet *); static unsigned int nd6_llinfo_retrans(struct ifnet *); static union l3addr *nd6_llinfo_holdsrc(struct llentry *, union l3addr *); static void nd6_llinfo_output(struct ifnet *, const union l3addr *, const union l3addr *, const uint8_t *, const union l3addr *); static void nd6_llinfo_missed(struct ifnet *, const union l3addr *, int16_t, struct mbuf *); static void nd6_timer(void *); static void nd6_timer_work(struct work *, void *); static struct nd_opt_hdr *nd6_option(union nd_opts *); static callout_t nd6_slowtimo_ch; static callout_t nd6_timer_ch; static struct workqueue *nd6_timer_wq; static struct work nd6_timer_wk; struct nd_domain nd6_nd_domain = { .nd_family = AF_INET6, .nd_delay = 5, /* delay first probe time 5 second */ .nd_mmaxtries = 3, /* maximum unicast query */ .nd_umaxtries = 3, /* maximum multicast query */ .nd_retransmultiple = BACKOFF_MULTIPLE, .nd_maxretrans = MAX_RETRANS_TIMER, .nd_maxnudhint = 0, /* max # of subsequent upper layer hints */ .nd_maxqueuelen = 1, /* max # of packets in unresolved ND entries */ .nd_nud_enabled = nd6_nud_enabled, .nd_reachable = nd6_llinfo_reachable, .nd_retrans = nd6_llinfo_retrans, .nd_holdsrc = nd6_llinfo_holdsrc, .nd_output = nd6_llinfo_output, .nd_missed = nd6_llinfo_missed, .nd_free = nd6_free, }; MALLOC_DEFINE(M_IP6NDP, "NDP", "IPv6 Neighbour Discovery"); void nd6_init(void) { int error; nd_attach_domain(&nd6_nd_domain); nd6_nbr_init(); rw_init(&nd6_lock); callout_init(&nd6_slowtimo_ch, CALLOUT_MPSAFE); callout_init(&nd6_timer_ch, CALLOUT_MPSAFE); error = workqueue_create(&nd6_timer_wq, "nd6_timer", nd6_timer_work, NULL, PRI_SOFTNET, IPL_SOFTNET, WQ_MPSAFE); if (error) panic("%s: workqueue_create failed (%d)\n", __func__, error); /* start timer */ callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, nd6_slowtimo, NULL); callout_reset(&nd6_timer_ch, hz, nd6_timer, NULL); } struct nd_kifinfo * nd6_ifattach(struct ifnet *ifp) { struct nd_kifinfo *nd; nd = kmem_zalloc(sizeof(*nd), KM_SLEEP); nd->chlim = IPV6_DEFHLIM; nd->basereachable = REACHABLE_TIME; nd->reachable = ND_COMPUTE_RTIME(nd->basereachable); nd->retrans = RETRANS_TIMER; nd->flags = ND6_IFF_PERFORMNUD; /* A loopback interface always has ND6_IFF_AUTO_LINKLOCAL. * A bridge interface should not have ND6_IFF_AUTO_LINKLOCAL * because one of its members should. */ if ((ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) || (ifp->if_flags & IFF_LOOPBACK)) nd->flags |= ND6_IFF_AUTO_LINKLOCAL; return nd; } void nd6_ifdetach(struct ifnet *ifp, struct in6_ifextra *ext) { /* Ensure all IPv6 addresses are purged before calling nd6_purge */ if_purgeaddrs(ifp, AF_INET6, in6_purgeaddr); nd6_purge(ifp, ext); kmem_free(ext->nd_ifinfo, sizeof(struct nd_kifinfo)); } void nd6_option_init(void *opt, int icmp6len, union nd_opts *ndopts) { memset(ndopts, 0, sizeof(*ndopts)); ndopts->nd_opts_search = (struct nd_opt_hdr *)opt; ndopts->nd_opts_last = (struct nd_opt_hdr *)(((u_char *)opt) + icmp6len); if (icmp6len == 0) { ndopts->nd_opts_done = 1; ndopts->nd_opts_search = NULL; } } /* * Take one ND option. */ static struct nd_opt_hdr * nd6_option(union nd_opts *ndopts) { struct nd_opt_hdr *nd_opt; int olen; KASSERT(ndopts != NULL); KASSERT(ndopts->nd_opts_last != NULL); if (ndopts->nd_opts_search == NULL) return NULL; if (ndopts->nd_opts_done) return NULL; nd_opt = ndopts->nd_opts_search; /* make sure nd_opt_len is inside the buffer */ if ((void *)&nd_opt->nd_opt_len >= (void *)ndopts->nd_opts_last) { memset(ndopts, 0, sizeof(*ndopts)); return NULL; } olen = nd_opt->nd_opt_len << 3; if (olen == 0) { /* * Message validation requires that all included * options have a length that is greater than zero. */ memset(ndopts, 0, sizeof(*ndopts)); return NULL; } ndopts->nd_opts_search = (struct nd_opt_hdr *)((char *)nd_opt + olen); if (ndopts->nd_opts_search > ndopts->nd_opts_last) { /* option overruns the end of buffer, invalid */ memset(ndopts, 0, sizeof(*ndopts)); return NULL; } else if (ndopts->nd_opts_search == ndopts->nd_opts_last) { /* reached the end of options chain */ ndopts->nd_opts_done = 1; ndopts->nd_opts_search = NULL; } return nd_opt; } /* * Parse multiple ND options. * This function is much easier to use, for ND routines that do not need * multiple options of the same type. */ int nd6_options(union nd_opts *ndopts) { struct nd_opt_hdr *nd_opt; int i = 0; KASSERT(ndopts != NULL); KASSERT(ndopts->nd_opts_last != NULL); if (ndopts->nd_opts_search == NULL) return 0; while (1) { nd_opt = nd6_option(ndopts); if (nd_opt == NULL && ndopts->nd_opts_last == NULL) { /* * Message validation requires that all included * options have a length that is greater than zero. */ ICMP6_STATINC(ICMP6_STAT_ND_BADOPT); memset(ndopts, 0, sizeof(*ndopts)); return -1; } if (nd_opt == NULL) goto skip1; switch (nd_opt->nd_opt_type) { case ND_OPT_SOURCE_LINKADDR: case ND_OPT_TARGET_LINKADDR: case ND_OPT_MTU: case ND_OPT_REDIRECTED_HEADER: case ND_OPT_NONCE: if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { nd6log(LOG_INFO, "duplicated ND6 option found (type=%d)\n", nd_opt->nd_opt_type); /* XXX bark? */ } else { ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; } break; case ND_OPT_PREFIX_INFORMATION: if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) { ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; } ndopts->nd_opts_pi_end = (struct nd_opt_prefix_info *)nd_opt; break; default: /* * Unknown options must be silently ignored, * to accommodate future extension to the protocol. */ nd6log(LOG_DEBUG, "nd6_options: unsupported option %d - " "option ignored\n", nd_opt->nd_opt_type); } skip1: i++; if (i > nd6_maxndopt) { ICMP6_STATINC(ICMP6_STAT_ND_TOOMANYOPT); nd6log(LOG_INFO, "too many loop in nd opt\n"); break; } if (ndopts->nd_opts_done) break; } return 0; } /* * Gets source address of the first packet in hold queue * and stores it in @@src. * Returns pointer to @@src (if hold queue is not empty) or NULL. */ static struct in6_addr * nd6_llinfo_get_holdsrc(struct llentry *ln, struct in6_addr *src) { struct ip6_hdr *hip6; if (ln == NULL || ln->ln_hold == NULL) return NULL; /* * assuming every packet in ln_hold has the same IP header */ hip6 = mtod(ln->ln_hold, struct ip6_hdr *); /* XXX pullup? */ if (sizeof(*hip6) < ln->ln_hold->m_len) *src = hip6->ip6_src; else src = NULL; return src; } static union l3addr * nd6_llinfo_holdsrc(struct llentry *ln, union l3addr *src) { if (nd6_llinfo_get_holdsrc(ln, &src->addr6) == NULL) return NULL; return src; } static void nd6_llinfo_output(struct ifnet *ifp, const union l3addr *daddr, const union l3addr *taddr, __unused const uint8_t *tlladdr, const union l3addr *hsrc) { nd6_ns_output(ifp, daddr != NULL ? &daddr->addr6 : NULL, taddr != NULL ? &taddr->addr6 : NULL, hsrc != NULL ? &hsrc->addr6 : NULL, NULL); } static bool nd6_nud_enabled(struct ifnet *ifp) { struct nd_kifinfo *ndi = ND_IFINFO(ifp); return ndi->flags & ND6_IFF_PERFORMNUD; } static unsigned int nd6_llinfo_reachable(struct ifnet *ifp) { struct nd_kifinfo *ndi = ND_IFINFO(ifp); return ndi->reachable; } static unsigned int nd6_llinfo_retrans(struct ifnet *ifp) { struct nd_kifinfo *ndi = ND_IFINFO(ifp); return ndi->retrans; } static void nd6_llinfo_missed(struct ifnet *ifp, const union l3addr *taddr, int16_t type, struct mbuf *m) { struct in6_addr mdaddr6 = zeroin6_addr; struct sockaddr_in6 dsin6, tsin6; struct sockaddr *sa; if (m != NULL) { if (type == ND_LLINFO_PROBE) { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); /* XXX pullup? */ if (sizeof(*ip6) < m->m_len) mdaddr6 = ip6->ip6_src; m_freem(m); } else icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, ifp, &mdaddr6); } if (!IN6_IS_ADDR_UNSPECIFIED(&mdaddr6)) { sockaddr_in6_init(&dsin6, &mdaddr6, 0, 0, 0); sa = sin6tosa(&dsin6); } else sa = NULL; sockaddr_in6_init(&tsin6, &taddr->addr6, 0, 0, 0); rt_clonedmsg(RTM_MISS, sa, sin6tosa(&tsin6), NULL, ifp); } /* * ND6 timer routine to expire default route list and prefix list */ static void nd6_timer_work(struct work *wk, void *arg) { struct in6_ifaddr *ia6, *nia6; int s, bound; struct psref psref; callout_reset(&nd6_timer_ch, nd6_prune * hz, nd6_timer, NULL); SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); /* expire interface addresses */ bound = curlwp_bind(); s = pserialize_read_enter(); for (ia6 = IN6_ADDRLIST_READER_FIRST(); ia6; ia6 = nia6) { nia6 = IN6_ADDRLIST_READER_NEXT(ia6); ia6_acquire(ia6, &psref); pserialize_read_exit(s); /* check address lifetime */ if (IFA6_IS_INVALID(ia6)) { struct ifnet *ifp; ifp = ia6->ia_ifa.ifa_ifp; IFNET_LOCK(ifp); /* * Need to take the lock first to prevent if_detach * from running in6_purgeaddr concurrently. */ if (!if_is_deactivated(ifp)) { ia6_release(ia6, &psref); in6_purgeaddr(&ia6->ia_ifa); } else { /* * ifp is being destroyed, ia6 will be destroyed * by if_detach. */ ia6_release(ia6, &psref); } ia6 = NULL; IFNET_UNLOCK(ifp); } else if (IFA6_IS_DEPRECATED(ia6)) { int oldflags = ia6->ia6_flags; if ((oldflags & IN6_IFF_DEPRECATED) == 0) { ia6->ia6_flags |= IN6_IFF_DEPRECATED; rt_addrmsg(RTM_NEWADDR, (struct ifaddr *)ia6); } } else { /* * A new RA might have made a deprecated address * preferred. */ if (ia6->ia6_flags & IN6_IFF_DEPRECATED) { ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; rt_addrmsg(RTM_NEWADDR, (struct ifaddr *)ia6); } } s = pserialize_read_enter(); ia6_release(ia6, &psref); } pserialize_read_exit(s); curlwp_bindx(bound); SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); } static void nd6_timer(void *ignored_arg) { workqueue_enqueue(nd6_timer_wq, &nd6_timer_wk, NULL); } /* * Nuke neighbor cache/prefix/default router management table, right before * ifp goes away. */ void nd6_purge(struct ifnet *ifp, struct in6_ifextra *ext) { /* * During detach, the ND info might be already removed, but * then is explitly passed as argument. * Otherwise get it from ifp->if_afdata. */ if (ext == NULL) ext = ifp->if_afdata[AF_INET6]; if (ext == NULL) return; /* * We may not need to nuke the neighbor cache entries here * because the neighbor cache is kept in if_afdata[AF_INET6]. * nd6_purge() is invoked by in6_ifdetach() which is called * from if_detach() where everything gets purged. However * in6_ifdetach is directly called from vlan(4), so we still * need to purge entries here. */ if (ext->lltable != NULL) lltable_purge_entries(ext->lltable); } struct llentry * nd6_lookup(const struct in6_addr *addr6, const struct ifnet *ifp, bool wlock) { struct sockaddr_in6 sin6; struct llentry *ln; sockaddr_in6_init(&sin6, addr6, 0, 0, 0); IF_AFDATA_RLOCK(ifp); ln = lla_lookup(LLTABLE6(ifp), wlock ? LLE_EXCLUSIVE : 0, sin6tosa(&sin6)); IF_AFDATA_RUNLOCK(ifp); return ln; } struct llentry * nd6_create(const struct in6_addr *addr6, const struct ifnet *ifp) { struct sockaddr_in6 sin6; struct llentry *ln; struct rtentry *rt; sockaddr_in6_init(&sin6, addr6, 0, 0, 0); rt = rtalloc1(sin6tosa(&sin6), 0); IF_AFDATA_WLOCK(ifp); ln = lla_create(LLTABLE6(ifp), LLE_EXCLUSIVE, sin6tosa(&sin6), rt); IF_AFDATA_WUNLOCK(ifp); if (rt != NULL) rt_unref(rt); if (ln != NULL) ln->ln_state = ND_LLINFO_NOSTATE; return ln; } /* * Test whether a given IPv6 address is a neighbor or not, ignoring * the actual neighbor cache. The neighbor cache is ignored in order * to not reenter the routing code from within itself. */ static int nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) { struct ifaddr *dstaddr; int s; /* * A link-local address is always a neighbor. * XXX: a link does not necessarily specify a single interface. */ if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { struct sockaddr_in6 sin6_copy; u_int32_t zone; /* * We need sin6_copy since sa6_recoverscope() may modify the * content (XXX). */ sin6_copy = *addr; if (sa6_recoverscope(&sin6_copy)) return 0; /* XXX: should be impossible */ if (in6_setscope(&sin6_copy.sin6_addr, ifp, &zone)) return 0; if (sin6_copy.sin6_scope_id == zone) return 1; else return 0; } /* * If the address is assigned on the node of the other side of * a p2p interface, the address should be a neighbor. */ s = pserialize_read_enter(); dstaddr = ifa_ifwithdstaddr(sin6tocsa(addr)); if (dstaddr != NULL) { if (dstaddr->ifa_ifp == ifp) { pserialize_read_exit(s); return 1; } } pserialize_read_exit(s); return 0; } /* * Detect if a given IPv6 address identifies a neighbor on a given link. * XXX: should take care of the destination of a p2p link? */ int nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) { struct llentry *ln; struct rtentry *rt; /* * A link-local address is always a neighbor. * XXX: a link does not necessarily specify a single interface. */ if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { struct sockaddr_in6 sin6_copy; u_int32_t zone; /* * We need sin6_copy since sa6_recoverscope() may modify the * content (XXX). */ sin6_copy = *addr; if (sa6_recoverscope(&sin6_copy)) return 0; /* XXX: should be impossible */ if (in6_setscope(&sin6_copy.sin6_addr, ifp, &zone)) return 0; if (sin6_copy.sin6_scope_id == zone) return 1; else return 0; } if (nd6_is_new_addr_neighbor(addr, ifp)) return 1; /* * Even if the address matches none of our addresses, it might be * in the neighbor cache or a connected route. */ ln = nd6_lookup(&addr->sin6_addr, ifp, false); if (ln != NULL) { LLE_RUNLOCK(ln); return 1; } rt = rtalloc1(sin6tocsa(addr), 0); if (rt == NULL) return 0; if ((rt->rt_flags & RTF_CONNECTED) && (rt->rt_ifp == ifp #if NBRIDGE > 0 || rt->rt_ifp->if_bridge == ifp->if_bridge #endif #if NCARP > 0 || (ifp->if_type == IFT_CARP && rt->rt_ifp == ifp->if_carpdev) || (rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp)|| (ifp->if_type == IFT_CARP && rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp->if_carpdev) #endif )) { rt_unref(rt); return 1; } rt_unref(rt); return 0; } /* * Free an nd6 llinfo entry. * Since the function would cause significant changes in the kernel, DO NOT * make it global, unless you have a strong reason for the change, and are sure * that the change is safe. */ static void nd6_free(struct llentry *ln, int gc) { struct ifnet *ifp; KASSERT(ln != NULL); LLE_WLOCK_ASSERT(ln); /* * If the reason for the deletion is just garbage collection, * and the neighbor is an active router, do not delete it. * Instead, reset the GC timer using the router's lifetime. * XXX: the check for ln_state should be redundant, * but we intentionally keep it just in case. */ if (!ip6_forwarding && ln->ln_router && ln->ln_state == ND_LLINFO_STALE && gc) { nd_set_timer(ln, ND_TIMER_EXPIRE); LLE_WUNLOCK(ln); return; } ifp = ln->lle_tbl->llt_ifp; if (ln->la_flags & LLE_VALID || gc) { struct sockaddr_in6 sin6; const char *lladdr; sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); lladdr = ln->la_flags & LLE_VALID ? (const char *)&ln->ll_addr : NULL; rt_clonedmsg(RTM_DELETE, NULL, sin6tosa(&sin6), lladdr, ifp); } /* * Save to unlock. We still hold an extra reference and will not * free(9) in llentry_free() if someone else holds one as well. */ LLE_WUNLOCK(ln); IF_AFDATA_LOCK(ifp); LLE_WLOCK(ln); lltable_free_entry(LLTABLE6(ifp), ln); IF_AFDATA_UNLOCK(ifp); } /* * Upper-layer reachability hint for Neighbor Unreachability Detection. * * XXX cost-effective methods? */ void nd6_nud_hint(struct rtentry *rt) { struct llentry *ln; struct ifnet *ifp; if (rt == NULL) return; ifp = rt->rt_ifp; ln = nd6_lookup(&(satocsin6(rt_getkey(rt)))->sin6_addr, ifp, true); nd_nud_hint(ln); } struct gc_args { int gc_entries; const struct in6_addr *skip_in6; }; static int nd6_purge_entry(struct lltable *llt, struct llentry *ln, void *farg) { struct gc_args *args = farg; int *n = &args->gc_entries; const struct in6_addr *skip_in6 = args->skip_in6; if (*n <= 0) return 0; if (ND_IS_LLINFO_PERMANENT(ln)) return 0; if (IN6_ARE_ADDR_EQUAL(&ln->r_l3addr.addr6, skip_in6)) return 0; LLE_WLOCK(ln); if (ln->ln_state > ND_LLINFO_INCOMPLETE) ln->ln_state = ND_LLINFO_STALE; else ln->ln_state = ND_LLINFO_PURGE; nd_set_timer(ln, ND_TIMER_IMMEDIATE); LLE_WUNLOCK(ln); (*n)--; return 0; } static void nd6_gc_neighbors(struct lltable *llt, const struct in6_addr *in6) { if (ip6_neighborgcthresh >= 0 && lltable_get_entry_count(llt) >= ip6_neighborgcthresh) { struct gc_args gc_args = {10, in6}; /* * XXX entries that are "less recently used" should be * freed first. */ lltable_foreach_lle(llt, nd6_purge_entry, &gc_args); } } void nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) { struct sockaddr *gate = rt->rt_gateway; struct ifnet *ifp = rt->rt_ifp; uint8_t namelen = strlen(ifp->if_xname), addrlen = ifp->if_addrlen; struct ifaddr *ifa; RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); if (req == RTM_LLINFO_UPD) { int rc; struct in6_addr *in6; struct in6_addr in6_all; int anycast; if ((ifa = info->rti_ifa) == NULL) return; in6 = &ifatoia6(ifa)->ia_addr.sin6_addr; anycast = ifatoia6(ifa)->ia6_flags & IN6_IFF_ANYCAST; in6_all = in6addr_linklocal_allnodes; if ((rc = in6_setscope(&in6_all, ifa->ifa_ifp, NULL)) != 0) { log(LOG_ERR, "%s: failed to set scope %s " "(errno=%d)\n", __func__, if_name(ifp), rc); return; } /* XXX don't set Override for proxy addresses */ nd6_na_output(ifa->ifa_ifp, &in6_all, in6, (anycast ? 0 : ND_NA_FLAG_OVERRIDE) #if 0 | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) #endif , 1, NULL); return; } if ((rt->rt_flags & RTF_GATEWAY) != 0) { if (req != RTM_ADD) return; /* * linklayers with particular MTU limitation. */ switch(ifp->if_type) { #if NARCNET > 0 case IFT_ARCNET: if (rt->rt_rmx.rmx_mtu > ARC_PHDS_MAXMTU) /* RFC2497 */ rt->rt_rmx.rmx_mtu = ARC_PHDS_MAXMTU; break; #endif } return; } if (nd6_need_cache(ifp) == 0 && (rt->rt_flags & RTF_HOST) == 0) { RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); /* * This is probably an interface direct route for a link * which does not need neighbor caches (e.g. fe80::%lo0/64). * We do not need special treatment below for such a route. * Moreover, the RTF_LLINFO flag which would be set below * would annoy the ndp(8) command. */ return; } switch (req) { case RTM_ADD: { struct psref psref; RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); /* * There is no backward compatibility :) * * if ((rt->rt_flags & RTF_HOST) == 0 && * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) * rt->rt_flags |= RTF_CLONING; */ /* XXX should move to route.c? */ if (rt->rt_flags & (RTF_CONNECTED | RTF_LOCAL)) { union { struct sockaddr sa; struct sockaddr_dl sdl; struct sockaddr_storage ss; } u; /* * Case 1: This route should come from a route to * interface (RTF_CLONING case) or the route should be * treated as on-link but is currently not * (RTF_LLINFO && ln == NULL case). */ if (sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type, NULL, namelen, NULL, addrlen) == NULL) { printf("%s.%d: sockaddr_dl_init(, %zu, ) " "failed on %s\n", __func__, __LINE__, sizeof(u.ss), if_name(ifp)); } rt_setgate(rt, &u.sa); gate = rt->rt_gateway; RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); if (gate == NULL) { log(LOG_ERR, "%s: rt_setgate failed on %s\n", __func__, if_name(ifp)); break; } RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); if ((rt->rt_flags & RTF_CONNECTED) != 0) break; } RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); /* * In IPv4 code, we try to annonuce new RTF_ANNOUNCE entry here. * We don't do that here since llinfo is not ready yet. * * There are also couple of other things to be discussed: * - unsolicited NA code needs improvement beforehand * - RFC2461 says we MAY send multicast unsolicited NA * (7.2.6 paragraph 4), however, it also says that we * SHOULD provide a mechanism to prevent multicast NA storm. * we don't have anything like it right now. * note that the mechanism needs a mutual agreement * between proxies, which means that we need to implement * a new protocol, or a new kludge. * - from RFC2461 6.2.4, host MUST NOT send an unsolicited NA. * we need to check ip6forwarding before sending it. * (or should we allow proxy ND configuration only for * routers? there's no mention about proxy ND from hosts) */ #if 0 /* XXX it does not work */ if (rt->rt_flags & RTF_ANNOUNCE) nd6_na_output(ifp, &satocsin6(rt_getkey(rt))->sin6_addr, &satocsin6(rt_getkey(rt))->sin6_addr, ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1, NULL); #endif if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); /* * Address resolution isn't necessary for a point to * point link, so we can skip this test for a p2p link. */ if (gate->sa_family != AF_LINK || gate->sa_len < sockaddr_dl_measure(namelen, addrlen)) { log(LOG_DEBUG, "nd6_rtrequest: bad gateway value: %s\n", if_name(ifp)); break; } satosdl(gate)->sdl_type = ifp->if_type; satosdl(gate)->sdl_index = ifp->if_index; RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); } RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); /* * When called from rt_ifa_addlocal, we cannot depend on that * the address (rt_getkey(rt)) exits in the address list of the * interface. So check RTF_LOCAL instead. */ if (rt->rt_flags & RTF_LOCAL) { if (nd6_useloopback) rt->rt_ifp = lo0ifp; /* XXX */ break; } /* * check if rt_getkey(rt) is an address assigned * to the interface. */ ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &satocsin6(rt_getkey(rt))->sin6_addr, &psref); if (ifa != NULL) { if (nd6_useloopback) { rt->rt_ifp = lo0ifp; /* XXX */ /* * Make sure rt_ifa be equal to the ifaddr * corresponding to the address. * We need this because when we refer * rt_ifa->ia6_flags in ip6_input, we assume * that the rt_ifa points to the address instead * of the loopback address. */ if (!ISSET(info->rti_flags, RTF_DONTCHANGEIFA) && ifa != rt->rt_ifa) rt_replace_ifa(rt, ifa); } } else if (rt->rt_flags & RTF_ANNOUNCE) { /* join solicited node multicast for proxy ND */ if (ifp->if_flags & IFF_MULTICAST) { struct in6_addr llsol; int error; llsol = satocsin6(rt_getkey(rt))->sin6_addr; llsol.s6_addr32[0] = htonl(0xff020000); llsol.s6_addr32[1] = 0; llsol.s6_addr32[2] = htonl(1); llsol.s6_addr8[12] = 0xff; if (in6_setscope(&llsol, ifp, NULL)) goto out; if (!in6_addmulti(&llsol, ifp, &error, 0)) { char ip6buf[INET6_ADDRSTRLEN]; nd6log(LOG_ERR, "%s: failed to join " "%s (errno=%d)\n", if_name(ifp), IN6_PRINT(ip6buf, &llsol), error); } } } out: ifa_release(ifa, &psref); /* * If we have too many cache entries, initiate immediate * purging for some entries. */ if (rt->rt_ifp != NULL) nd6_gc_neighbors(LLTABLE6(rt->rt_ifp), NULL); break; } case RTM_DELETE: /* leave from solicited node multicast for proxy ND */ if ((rt->rt_flags & RTF_ANNOUNCE) != 0 && (ifp->if_flags & IFF_MULTICAST) != 0) { struct in6_addr llsol; llsol = satocsin6(rt_getkey(rt))->sin6_addr; llsol.s6_addr32[0] = htonl(0xff020000); llsol.s6_addr32[1] = 0; llsol.s6_addr32[2] = htonl(1); llsol.s6_addr8[12] = 0xff; if (in6_setscope(&llsol, ifp, NULL) == 0) in6_lookup_and_delete_multi(&llsol, ifp); } break; } } static void nd6_setifflags(struct ifnet *ifp, uint32_t flags) { struct nd_kifinfo *ndi = ND_IFINFO(ifp); struct ifaddr *ifa; struct in6_ifaddr *ia; int s; if (ndi->flags & ND6_IFF_IFDISABLED && !(flags & ND6_IFF_IFDISABLED)) { /* * If the interface is marked as ND6_IFF_IFDISABLED and * has a link-local address with IN6_IFF_DUPLICATED, * do not clear ND6_IFF_IFDISABLED. * See RFC 4862, section 5.4.5. */ bool duplicated_linklocal = false; s = pserialize_read_enter(); IFADDR_READER_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; if ((ia->ia6_flags & IN6_IFF_DUPLICATED) && IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) { duplicated_linklocal = true; break; } } pserialize_read_exit(s); if (duplicated_linklocal) { flags |= ND6_IFF_IFDISABLED; log(LOG_ERR, "%s: Cannot enable an interface" " with a link-local address marked" " duplicate.\n", if_name(ifp)); } else { ndi->flags &= ~ND6_IFF_IFDISABLED; if (ifp->if_flags & IFF_UP) in6_if_up(ifp); } } else if (!(ndi->flags & ND6_IFF_IFDISABLED) && (flags & ND6_IFF_IFDISABLED)) { struct psref psref; int bound = curlwp_bind(); /* Mark all IPv6 addresses as tentative. */ ndi->flags |= ND6_IFF_IFDISABLED; s = pserialize_read_enter(); IFADDR_READER_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ifa_acquire(ifa, &psref); pserialize_read_exit(s); nd6_dad_stop(ifa); ia = (struct in6_ifaddr *)ifa; ia->ia6_flags |= IN6_IFF_TENTATIVE; s = pserialize_read_enter(); ifa_release(ifa, &psref); } pserialize_read_exit(s); curlwp_bindx(bound); } if (flags & ND6_IFF_AUTO_LINKLOCAL) { if (!(ndi->flags & ND6_IFF_AUTO_LINKLOCAL)) { /* auto_linklocal 0->1 transition */ ndi->flags |= ND6_IFF_AUTO_LINKLOCAL; in6_ifattach(ifp, NULL); } else if (!(flags & ND6_IFF_IFDISABLED) && ifp->if_flags & IFF_UP) { /* * When the IF already has * ND6_IFF_AUTO_LINKLOCAL, no link-local * address is assigned, and IFF_UP, try to * assign one. */ bool haslinklocal = 0; s = pserialize_read_enter(); IFADDR_READER_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family !=AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))){ haslinklocal = true; break; } } pserialize_read_exit(s); if (!haslinklocal) in6_ifattach(ifp, NULL); } } ndi->flags = flags; } int nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) { #ifdef OSIOCGIFINFO_IN6_90 struct in6_ndireq90 *ondi = (struct in6_ndireq90 *)data; struct in6_ndifreq90 *ndif = (struct in6_ndifreq90 *)data; #define OND ondi->ndi #endif struct in6_ndireq *ndi = (struct in6_ndireq *)data; struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; struct nd_kifinfo *ifndi = ND_IFINFO(ifp); int error = 0; #define ND ndi->ndi switch (cmd) { #ifdef OSIOCSRTRFLUSH_IN6 case OSIOCGDRLST_IN6: /* FALLTHROUGH */ case OSIOCGPRLST_IN6: /* FALLTHROUGH */ case OSIOCSNDFLUSH_IN6: /* FALLTHROUGH */ case OSIOCSPFXFLUSH_IN6: /* FALLTHROUGH */ case OSIOCSRTRFLUSH_IN6: /* FALLTHROUGH */ break; case OSIOCGDEFIFACE_IN6: ndif->ifindex = 0; break; case OSIOCSDEFIFACE_IN6: error = ENOTSUP; break; #endif #ifdef OSIOCGIFINFO_IN6 case OSIOCGIFINFO_IN6: /* FALLTHROUGH */ #endif #ifdef OSIOCGIFINFO_IN6_90 case OSIOCGIFINFO_IN6_90: memset(&OND, 0, sizeof(OND)); OND.initialized = 1; OND.chlim = ifndi->chlim; OND.basereachable = ifndi->basereachable; OND.retrans = ifndi->retrans; OND.flags = ifndi->flags; break; case OSIOCSIFINFO_IN6_90: /* Allow userland to set Neighbor Unreachability Detection * timers. */ if (OND.chlim != 0) ifndi->chlim = OND.chlim; if (OND.basereachable != 0 && OND.basereachable != ifndi->basereachable) { ifndi->basereachable = OND.basereachable; ifndi->reachable = ND_COMPUTE_RTIME(OND.basereachable); } if (OND.retrans != 0) ifndi->retrans = OND.retrans; /* Retain the old behaviour .... */ /* FALLTHROUGH */ case OSIOCSIFINFO_FLAGS_90: nd6_setifflags(ifp, OND.flags); break; #undef OND #endif case SIOCGIFINFO_IN6: ND.chlim = ifndi->chlim; ND.basereachable = ifndi->basereachable; ND.retrans = ifndi->retrans; ND.flags = ifndi->flags; break; case SIOCSIFINFO_IN6: /* Allow userland to set Neighbor Unreachability Detection * timers. */ if (ND.chlim != 0) ifndi->chlim = ND.chlim; if (ND.basereachable != 0 && ND.basereachable != ifndi->basereachable) { ifndi->basereachable = ND.basereachable; ifndi->reachable = ND_COMPUTE_RTIME(ND.basereachable); } if (ND.retrans != 0) ifndi->retrans = ND.retrans; break; case SIOCSIFINFO_FLAGS: nd6_setifflags(ifp, ND.flags); break; #undef ND case SIOCGNBRINFO_IN6: { struct llentry *ln; struct in6_addr nb_addr = nbi->addr; /* make local for safety */ if ((error = in6_setscope(&nb_addr, ifp, NULL)) != 0) return error; ln = nd6_lookup(&nb_addr, ifp, false); if (ln == NULL) { error = EINVAL; break; } nbi->state = ln->ln_state; nbi->asked = ln->ln_asked; nbi->isrouter = ln->ln_router; nbi->expire = ln->ln_expire ? time_mono_to_wall(ln->ln_expire) : 0; LLE_RUNLOCK(ln); break; } } return error; } void nd6_llinfo_release_pkts(struct llentry *ln, struct ifnet *ifp) { struct mbuf *m_hold, *m_hold_next; struct sockaddr_in6 sin6; LLE_WLOCK_ASSERT(ln); sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); m_hold = ln->la_hold, ln->la_hold = NULL, ln->la_numheld = 0; LLE_ADDREF(ln); LLE_WUNLOCK(ln); for (; m_hold != NULL; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; /* * we assume ifp is not a p2p here, so * just set the 2nd argument as the * 1st one. */ ip6_if_output(ifp, ifp, m_hold, &sin6, NULL); } LLE_WLOCK(ln); LLE_REMREF(ln); } /* * Create neighbor cache entry and cache link-layer address, * on reception of inbound ND6 packets. (RS/RA/NS/redirect) */ void nd6_cache_lladdr( struct ifnet *ifp, struct in6_addr *from, char *lladdr, int lladdrlen, int type, /* ICMP6 type */ int code /* type dependent information */ ) { struct llentry *ln = NULL; int is_newentry; int do_update; int olladdr; int llchange; int newstate = 0; KASSERT(ifp != NULL); KASSERT(from != NULL); /* nothing must be updated for unspecified address */ if (IN6_IS_ADDR_UNSPECIFIED(from)) return; /* * Validation about ifp->if_addrlen and lladdrlen must be done in * the caller. * * XXX If the link does not have link-layer adderss, what should * we do? (ifp->if_addrlen == 0) * Spec says nothing in sections for RA, RS and NA. There's small * description on it in NS section (RFC 2461 7.2.3). */ ln = nd6_lookup(from, ifp, true); if (ln == NULL) { #if 0 /* nothing must be done if there's no lladdr */ if (!lladdr || !lladdrlen) return NULL; #endif ln = nd6_create(from, ifp); is_newentry = 1; } else { /* do nothing if static ndp is set */ if (ln->la_flags & LLE_STATIC) { LLE_WUNLOCK(ln); return; } is_newentry = 0; } if (ln == NULL) return; olladdr = (ln->la_flags & LLE_VALID) ? 1 : 0; if (olladdr && lladdr) { llchange = memcmp(lladdr, &ln->ll_addr, ifp->if_addrlen); } else llchange = 0; /* * newentry olladdr lladdr llchange (*=record) * 0 n n -- (1) * 0 y n -- (2) * 0 n y -- (3) * STALE * 0 y y n (4) * * 0 y y y (5) * STALE * 1 -- n -- (6) NOSTATE(= PASSIVE) * 1 -- y -- (7) * STALE */ if (lladdr) { /* (3-5) and (7) */ /* * Record source link-layer address * XXX is it dependent to ifp->if_type? */ memcpy(&ln->ll_addr, lladdr, ifp->if_addrlen); ln->la_flags |= LLE_VALID; } if (!is_newentry) { if ((!olladdr && lladdr) || /* (3) */ (olladdr && lladdr && llchange)) { /* (5) */ do_update = 1; newstate = ND_LLINFO_STALE; } else /* (1-2,4) */ do_update = 0; } else { do_update = 1; if (lladdr == NULL) /* (6) */ newstate = ND_LLINFO_NOSTATE; else /* (7) */ newstate = ND_LLINFO_STALE; } if (do_update) { /* * Update the state of the neighbor cache. */ ln->ln_state = newstate; if (ln->ln_state == ND_LLINFO_STALE) { /* * XXX: since nd6_output() below will cause * state tansition to DELAY and reset the timer, * we must set the timer now, although it is actually * meaningless. */ nd_set_timer(ln, ND_TIMER_GC); nd6_llinfo_release_pkts(ln, ifp); } else if (ln->ln_state == ND_LLINFO_INCOMPLETE) { /* probe right away */ nd_set_timer(ln, ND_TIMER_IMMEDIATE); } } /* * ICMP6 type dependent behavior. * * NS: clear IsRouter if new entry * RS: clear IsRouter * RA: set IsRouter if there's lladdr * redir: clear IsRouter if new entry * * RA case, (1): * The spec says that we must set IsRouter in the following cases: * - If lladdr exist, set IsRouter. This means (1-5). * - If it is old entry (!newentry), set IsRouter. This means (7). * So, based on the spec, in (1-5) and (7) cases we must set IsRouter. * A question arises for (1) case. (1) case has no lladdr in the * neighbor cache, this is similar to (6). * This case is rare but we figured that we MUST NOT set IsRouter. * * newentry olladdr lladdr llchange NS RS RA redir * D R * 0 n n -- (1) c ? s * 0 y n -- (2) c s s * 0 n y -- (3) c s s * 0 y y n (4) c s s * 0 y y y (5) c s s * 1 -- n -- (6) c c c s * 1 -- y -- (7) c c s c s * * (c=clear s=set) */ switch (type & 0xff) { case ND_NEIGHBOR_SOLICIT: /* * New entry must have is_router flag cleared. */ if (is_newentry) /* (6-7) */ ln->ln_router = 0; break; case ND_REDIRECT: /* * If the icmp is a redirect to a better router, always set the * is_router flag. Otherwise, if the entry is newly created, * clear the flag. [RFC 2461, sec 8.3] */ if (code == ND_REDIRECT_ROUTER) ln->ln_router = 1; else if (is_newentry) /* (6-7) */ ln->ln_router = 0; break; case ND_ROUTER_SOLICIT: /* * is_router flag must always be cleared. */ ln->ln_router = 0; break; case ND_ROUTER_ADVERT: /* * Mark an entry with lladdr as a router. */ if ((!is_newentry && (olladdr || lladdr)) || /* (2-5) */ (is_newentry && lladdr)) { /* (7) */ ln->ln_router = 1; } break; } if (do_update && lladdr != NULL) { struct sockaddr_in6 sin6; sockaddr_in6_init(&sin6, from, 0, 0, 0); rt_clonedmsg(is_newentry ? RTM_ADD : RTM_CHANGE, NULL, sin6tosa(&sin6), lladdr, ifp); } if (ln != NULL) LLE_WUNLOCK(ln); /* * If we have too many cache entries, initiate immediate * purging for some entries. */ if (is_newentry) nd6_gc_neighbors(LLTABLE6(ifp), &ln->r_l3addr.addr6); } static void nd6_slowtimo(void *ignored_arg) { struct nd_kifinfo *ndi; struct ifnet *ifp; struct psref psref; int s; SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, nd6_slowtimo, NULL); s = pserialize_read_enter(); IFNET_READER_FOREACH(ifp) { ndi = ND_IFINFO(ifp); if (ndi->basereachable && /* already initialized */ (ndi->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) { if_acquire(ifp, &psref); pserialize_read_exit(s); /* * Since reachable time rarely changes by router * advertisements, we SHOULD insure that a new random * value gets recomputed at least once every few hours. * (RFC 2461, 6.3.4) */ ndi->recalctm = nd6_recalc_reachtm_interval; ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable); s = pserialize_read_enter(); if_release(ifp, &psref); } } pserialize_read_exit(s); SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); } /* * Return 0 if a neighbor cache is found. Return EWOULDBLOCK if a cache is not * found and trying to resolve a neighbor; in this case the mbuf is queued in * the list. Otherwise return errno after freeing the mbuf. */ int nd6_resolve(struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m, const struct sockaddr *_dst, uint8_t *lldst, size_t dstsize) { struct llentry *ln = NULL; bool created = false; const struct sockaddr_in6 *dst = satocsin6(_dst); int error; struct nd_kifinfo *ndi = ND_IFINFO(ifp); /* discard the packet if IPv6 operation is disabled on the interface */ if (ndi->flags & ND6_IFF_IFDISABLED) { m_freem(m); return ENETDOWN; /* better error? */ } /* * Address resolution or Neighbor Unreachability Detection * for the next hop. * At this point, the destination of the packet must be a unicast * or an anycast address(i.e. not a multicast). */ /* Look up the neighbor cache for the nexthop */ ln = nd6_lookup(&dst->sin6_addr, ifp, false); if (ln != NULL && (ln->la_flags & LLE_VALID) != 0 && ln->ln_state == ND_LLINFO_REACHABLE) { /* Fast path */ memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); LLE_RUNLOCK(ln); return 0; } if (ln != NULL) LLE_RUNLOCK(ln); /* Slow path */ ln = nd6_lookup(&dst->sin6_addr, ifp, true); if (ln == NULL && nd6_is_addr_neighbor(dst, ifp)) { /* * Since nd6_is_addr_neighbor() internally calls nd6_lookup(), * the condition below is not very efficient. But we believe * it is tolerable, because this should be a rare case. */ ln = nd6_create(&dst->sin6_addr, ifp); if (ln == NULL) { char ip6buf[INET6_ADDRSTRLEN]; log(LOG_DEBUG, "%s: can't allocate llinfo for %s " "(ln=%p, rt=%p)\n", __func__, IN6_PRINT(ip6buf, &dst->sin6_addr), ln, rt); m_freem(m); return ENOBUFS; } created = true; } if (ln == NULL) { m_freem(m); return ENETDOWN; /* better error? */ } error = nd_resolve(ln, rt, m, lldst, dstsize); if (created) nd6_gc_neighbors(LLTABLE6(ifp), &dst->sin6_addr); return error; } int nd6_need_cache(struct ifnet *ifp) { /* * XXX: we currently do not make neighbor cache on any interface * other than ARCnet, Ethernet, and GIF. * * RFC2893 says: * - unidirectional tunnels needs no ND */ switch (ifp->if_type) { case IFT_ARCNET: case IFT_ETHER: case IFT_IEEE1394: case IFT_CARP: case IFT_GIF: /* XXX need more cases? */ case IFT_PPP: case IFT_TUNNEL: return 1; default: return 0; } } int nd6_sysctl( int name, void *oldp, /* syscall arg, need copyout */ size_t *oldlenp, void *newp, /* syscall arg, need copyin */ size_t newlen ) { int error; if (newp) return EPERM; switch (name) { /* call the nd6 compat_90 hook to validate the nd6-related names */ case OICMPV6CTL_ND6_DRLIST: /* FALLTHROUGH */ case OICMPV6CTL_ND6_PRLIST: MODULE_HOOK_CALL(net_inet6_nd_90_hook, (name), ENOPROTOOPT, error); if (error == 0) *oldlenp = 0; return error; case ICMPV6CTL_ND6_MAXQLEN: return 0; default: return ENOPROTOOPT; } } @ 1.280 log @s/Neighour/Neighbor/ in comment. No functional change. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.279 2022/09/01 18:32:17 riastradh Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.279 2022/09/01 18:32:17 riastradh Exp $"); d60 1 a80 1 #ifdef COMPAT_90 a82 1 #endif d1675 1 d1681 2 a1682 1 #ifdef COMPAT_90 d1685 6 a1690 3 *oldlenp = 0; return 0; #endif @ 1.279 log @nd6: Take ifnet psref around cprng_fast in nd6_slowtimo. This may sleep on an adpative mutex, the global entropy lock, so pserialize is forbidden. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.278 2021/12/31 12:41:50 andvar Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.278 2021/12/31 12:41:50 andvar Exp $"); d1227 1 a1227 1 /* Allow userland to set Neighour Unreachability Detection d1253 1 a1253 1 /* Allow userland to set Neighour Unreachability Detection @ 1.279.4.1 log @Pull up following revision(s) (requested by pgoyette in ticket #487): sys/compat/common/compat_90_mod.c: revision 1.5 sys/compat/common/compat_90_mod.c: revision 1.6 sys/netinet6/in6.c: revision 1.290 sys/netinet6/in6.c: revision 1.291 sys/compat/common/files.common: revision 1.11 sys/netinet6/icmp6.c: revision 1.255 sys/compat/common/net_inet6_nd_90.c: revision 1.1 sys/compat/common/net_inet6_nd_90.c: revision 1.2 sys/modules/compat_90/Makefile: revision 1.2 sys/modules/compat_90/Makefile: revision 1.3 sys/netinet6/nd6.c: revision 1.281 sys/compat/common/compat_mod.h: revision 1.10 sys/kern/compat_stub.c: revision 1.23 sys/sys/compat_stub.h: revision 1.27 Identify the need to rework the COMPAT_* code to be more module-aware. This is an XXX comment block only, NFCI. Modularize the COMPAT_90 code that resulted from the removal of netinet6/nd6 from the kernel. Now, the minimal compat code can be successfully loaded and unloaded along with the rest of the COMPAT_90 code. Allow kernels builds which don't define INET6 to compile compat bits too. Default the build of compat_90 module to include IPv6, as is done for other INET6-sensitive modules (see if_lagg). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.279 2022/09/01 18:32:17 riastradh Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.279 2022/09/01 18:32:17 riastradh Exp $"); a59 1 #include d80 1 d83 1 a1675 1 int error; d1681 1 a1681 2 /* call the nd6 compat_90 hook to validate the nd6-related names */ d1684 3 a1686 6 MODULE_HOOK_CALL(net_inet6_nd_90_hook, (name), ENOPROTOOPT, error); if (error == 0) *oldlenp = 0; return error; @ 1.278 log @s/quetion/question/ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.277 2021/08/17 09:43:21 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.277 2021/08/17 09:43:21 ozaki-r Exp $"); d1537 1 d1549 2 d1559 2 @ 1.277 log @nd6: prevent ln from being freed while releasing held packets @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.276 2020/12/28 20:19:50 nia Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.276 2020/12/28 20:19:50 nia Exp $"); d1461 1 a1461 1 * A quetion arises for (1) case. (1) case has no lladdr in the @ 1.276 log @Add more guards against NULL deref, since KUBSAN still complains. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.275 2020/12/26 10:43:39 nia Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.275 2020/12/26 10:43:39 nia Exp $"); d1308 1 d1322 1 @ 1.275 log @Avoid NULL pointer dereference, noticed by KUBSAN. "Looks fine" roy@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.274 2020/09/15 10:05:36 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.274 2020/09/15 10:05:36 roy Exp $"); d387 4 a390 2 nd6_ns_output(ifp, daddr != NULL ? &daddr->addr6 : NULL, &taddr->addr6, &hsrc->addr6, NULL); @ 1.274 log @Implement RFC 7048, making Neighbor Unreachability Detection less impatient RFC 7048 Section 3 says in the UNREACHABLE state packets continue to be sent to the link-layer address and then backoff exponentially. We adjust this slightly and move to the INCOMPLETE state after `nd_mmaxtries` probes and then start backing off. This results in simpler code whilst providing a more robust model which doubles the time to failure over what we did before. We don't want to be back to the old ARP model where no unreachability errors are returned because very few applications would look at unreachability hints provided such as ND_LLINFO_UNREACHABLE or RTM_MISS. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.273 2020/09/14 15:09:57 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.273 2020/09/14 15:09:57 roy Exp $"); d387 2 a388 2 nd6_ns_output(ifp, &daddr->addr6, &taddr->addr6, &hsrc->addr6, NULL); @ 1.274.2.1 log @Sync w/ HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.276 2020/12/28 20:19:50 nia Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.276 2020/12/28 20:19:50 nia Exp $"); d387 2 a388 4 nd6_ns_output(ifp, daddr != NULL ? &daddr->addr6 : NULL, taddr != NULL ? &taddr->addr6 : NULL, hsrc != NULL ? &hsrc->addr6 : NULL, NULL); @ 1.273 log @nd: Name l3addr union of llentry and use in-place of nd_addr. Probably makes more sense and makes nd.h less messy. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.272 2020/09/11 15:03:33 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.272 2020/09/11 15:03:33 roy Exp $"); d114 1 a114 1 struct mbuf *); d129 2 d416 2 a417 1 nd6_llinfo_missed(struct ifnet *ifp, const union l3addr *taddr, struct mbuf *m) d423 12 a434 3 if (m != NULL) icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, ifp, &mdaddr6); @ 1.272 log @inet6: Use generic Neighor Detection rather than IPv6 specific No functional change intended. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.271 2020/06/12 11:04:45 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.271 2020/06/12 11:04:45 roy Exp $"); d110 4 a113 4 static union nd_addr *nd6_llinfo_holdsrc(struct llentry *, union nd_addr *); static void nd6_llinfo_output(struct ifnet *, const union nd_addr *, const union nd_addr *, const uint8_t *, const union nd_addr *); static void nd6_llinfo_missed(struct ifnet *, const union nd_addr *, d370 2 a371 2 static union nd_addr * nd6_llinfo_holdsrc(struct llentry *ln, union nd_addr *src) d374 1 a374 1 if (nd6_llinfo_get_holdsrc(ln, &src->nd_addr6) == NULL) d380 3 a382 3 nd6_llinfo_output(struct ifnet *ifp, const union nd_addr *daddr, const union nd_addr *taddr, __unused const uint8_t *tlladdr, const union nd_addr *hsrc) d385 2 a386 2 nd6_ns_output(ifp, &daddr->nd_addr6, &taddr->nd_addr6, &hsrc->nd_addr6, NULL); d414 1 a414 1 nd6_llinfo_missed(struct ifnet *ifp, const union nd_addr *taddr, struct mbuf *m) d429 1 a429 1 sockaddr_in6_init(&tsin6, &taddr->nd_addr6, 0, 0, 0); @ 1.271 log @Remove in-kernel handling of Router Advertisements This is much better handled by a user-land tool. Proposed on tech-net here: https://mail-index.netbsd.org/tech-net/2020/04/22/msg007766.html Note that the ioctl SIOCGIFINFO_IN6 no longer sets flags. That now needs to be done using the pre-existing SIOCSIFINFO_FLAGS ioctl. Compat is fully provided where it makes sense, but trying to turn on RA handling will obviously throw an error as it no longer exists. Note that if you use IPv6 temporary addresses, this now needs to be turned on in dhcpcd.conf(5) rather than in sysctl.conf(5). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.270 2020/04/28 15:12:28 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.270 2020/04/28 15:12:28 roy Exp $"); d65 1 a89 3 int nd6_delay = 5; /* delay first probe time 5 second */ int nd6_umaxtries = 3; /* maximum unicast query */ int nd6_mmaxtries = 3; /* maximum multicast query */ a90 1 int nd6_gctimer = (60 * 60 * 24); /* 1 day: garbage collection timer */ a94 4 int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */ int nd6_maxqueuelen = 1; /* max # of packets cached in unresolved ND entries */ d107 8 a114 1 static void nd6_llinfo_timer(void *); a116 1 static void clear_llinfo_pqueue(struct llentry *); d124 16 d147 1 a344 38 * ND6 timer routine to handle ND6 entries */ void nd6_llinfo_settimer(struct llentry *ln, time_t xtick) { CTASSERT(sizeof(time_t) > sizeof(int)); LLE_WLOCK_ASSERT(ln); KASSERT(xtick >= 0); /* * We have to take care of a reference leak which occurs if * callout_reset overwrites a pending callout schedule. Unfortunately * we don't have a mean to know the overwrite, so we need to know it * using callout_stop. We need to call callout_pending first to exclude * the case that the callout has never been scheduled. */ if (callout_pending(&ln->la_timer)) { bool expired = callout_stop(&ln->la_timer); if (!expired) LLE_REMREF(ln); } ln->ln_expire = time_uptime + xtick / hz; LLE_ADDREF(ln); if (xtick > INT_MAX) { ln->ln_ntick = xtick - INT_MAX; callout_reset(&ln->ln_timer_ch, INT_MAX, nd6_llinfo_timer, ln); } else { ln->ln_ntick = 0; callout_reset(&ln->ln_timer_ch, xtick, nd6_llinfo_timer, ln); } } /* d370 2 a371 2 static void nd6_llinfo_timer(void *arg) a372 9 struct llentry *ln = arg; struct ifnet *ifp; struct nd_kifinfo *ndi; bool send_ns = false; const struct in6_addr *daddr6 = NULL; const struct in6_addr *taddr6 = &ln->r_l3addr.addr6; struct sockaddr_in6 dsin6, tsin6; struct mbuf *m = NULL; bool missed = false; d374 4 a377 1 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); d379 5 a383 7 LLE_WLOCK(ln); if ((ln->la_flags & LLE_LINKED) == 0) goto out; if (ln->ln_ntick > 0) { nd6_llinfo_settimer(ln, ln->ln_ntick); goto out; } d385 3 a387 2 ifp = ln->lle_tbl->llt_ifp; KASSERT(ifp != NULL); d389 4 a392 1 ndi = ND_IFINFO(ifp); d394 2 a395 6 switch (ln->ln_state) { case ND6_LLINFO_WAITDELETE: LLE_REMREF(ln); nd6_free(ln, 0); ln = NULL; break; d397 4 a400 5 case ND6_LLINFO_INCOMPLETE: if (ln->ln_asked++ < nd6_mmaxtries) { send_ns = true; break; } d402 2 a403 2 missed = true; sockaddr_in6_init(&tsin6, taddr6, 0, 0, 0); d405 4 a408 2 if (ln->ln_hold) { struct mbuf *m0; d410 2 a411 1 m = ln->ln_hold; d413 6 a418 9 /* * assuming every packet in ln_hold has * the same IP header */ m0 = m->m_nextpkt; m->m_nextpkt = NULL; ln->ln_hold = m0; clear_llinfo_pqueue(ln); } d420 8 a427 19 /* * Move to the ND6_LLINFO_WAITDELETE state for another * interval at which point the llentry will be freed * unless it's attempted to be used again and we'll * resend NS again, rinse and repeat. */ ln->ln_state = ND6_LLINFO_WAITDELETE; if (ln->ln_asked == nd6_mmaxtries) nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000); else send_ns = true; break; case ND6_LLINFO_REACHABLE: if (!ND6_LLINFO_PERMANENT(ln)) { ln->ln_state = ND6_LLINFO_STALE; nd6_llinfo_settimer(ln, nd6_gctimer * hz); } break; d429 2 a430 63 case ND6_LLINFO_PURGE: case ND6_LLINFO_STALE: /* Garbage Collection(RFC 2461 5.3) */ if (!ND6_LLINFO_PERMANENT(ln)) { LLE_REMREF(ln); nd6_free(ln, 1); ln = NULL; } break; case ND6_LLINFO_DELAY: if (ndi->flags & ND6_IFF_PERFORMNUD) { /* We need NUD */ ln->ln_asked = 1; ln->ln_state = ND6_LLINFO_PROBE; daddr6 = &ln->r_l3addr.addr6; send_ns = true; } else { ln->ln_state = ND6_LLINFO_STALE; /* XXX */ nd6_llinfo_settimer(ln, nd6_gctimer * hz); } break; case ND6_LLINFO_PROBE: if (ln->ln_asked < nd6_umaxtries) { ln->ln_asked++; daddr6 = &ln->r_l3addr.addr6; send_ns = true; } else { LLE_REMREF(ln); nd6_free(ln, 0); ln = NULL; } break; } if (send_ns) { struct in6_addr src, *psrc; nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000); psrc = nd6_llinfo_get_holdsrc(ln, &src); LLE_FREE_LOCKED(ln); ln = NULL; nd6_ns_output(ifp, daddr6, taddr6, psrc, NULL); } out: if (ln != NULL) LLE_FREE_LOCKED(ln); SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); if (missed) { struct in6_addr mdaddr6 = zeroin6_addr; struct sockaddr *sa; if (m != NULL) icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, ifp, &mdaddr6); if (!IN6_IS_ADDR_UNSPECIFIED(&mdaddr6)) { sockaddr_in6_init(&dsin6, &mdaddr6, 0, 0, 0); sa = sin6tosa(&dsin6); } else sa = NULL; rt_clonedmsg(RTM_MISS, sa, sin6tosa(&tsin6), NULL, ifp); } d575 1 a575 1 ln->ln_state = ND6_LLINFO_NOSTATE; d722 1 a722 1 ln->ln_state == ND6_LLINFO_STALE && gc) d724 1 a724 5 if (ln->ln_expire > time_uptime) nd6_llinfo_settimer(ln, (ln->ln_expire - time_uptime) * hz); else nd6_llinfo_settimer(ln, nd6_gctimer * hz); d770 1 a770 22 if (ln == NULL) return; if (ln->ln_state < ND6_LLINFO_REACHABLE) goto done; /* * if we get upper-layer reachability confirmation many times, * it is possible we have false information. */ ln->ln_byhint++; if (ln->ln_byhint > nd6_maxnudhint) goto done; ln->ln_state = ND6_LLINFO_REACHABLE; if (!ND6_LLINFO_PERMANENT(ln)) nd6_llinfo_settimer(ln, ND_IFINFO(rt->rt_ifp)->reachable * hz); done: LLE_WUNLOCK(ln); return; d788 1 a788 1 if (ND6_LLINFO_PERMANENT(ln)) d795 2 a796 2 if (ln->ln_state > ND6_LLINFO_INCOMPLETE) ln->ln_state = ND6_LLINFO_STALE; d798 2 a799 2 ln->ln_state = ND6_LLINFO_PURGE; nd6_llinfo_settimer(ln, 0); d1399 1 a1399 1 newstate = ND6_LLINFO_STALE; d1405 1 a1405 1 newstate = ND6_LLINFO_NOSTATE; d1407 1 a1407 1 newstate = ND6_LLINFO_STALE; d1416 1 a1416 1 if (ln->ln_state == ND6_LLINFO_STALE) { d1423 1 a1423 1 nd6_llinfo_settimer(ln, nd6_gctimer * hz); d1426 1 a1426 1 } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { d1428 1 a1428 1 nd6_llinfo_settimer((void *)ln, 0); d1579 1 a1579 1 ln->ln_state == ND6_LLINFO_REACHABLE) { d1614 1 a1614 86 LLE_WLOCK_ASSERT(ln); /* We don't have to do link-layer address resolution on a p2p link. */ if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && ln->ln_state < ND6_LLINFO_REACHABLE) { ln->ln_state = ND6_LLINFO_STALE; nd6_llinfo_settimer(ln, nd6_gctimer * hz); } /* * The first time we send a packet to a neighbor whose entry is * STALE, we have to change the state to DELAY and a sets a timer to * expire in DELAY_FIRST_PROBE_TIME seconds to ensure do * neighbor unreachability detection on expiration. * (RFC 2461 7.3.3) */ if (ln->ln_state == ND6_LLINFO_STALE) { ln->ln_asked = 0; ln->ln_state = ND6_LLINFO_DELAY; nd6_llinfo_settimer(ln, nd6_delay * hz); } /* * If the neighbor cache entry has a state other than INCOMPLETE * (i.e. its link-layer address is already resolved), just * send the packet. */ if (ln->ln_state > ND6_LLINFO_INCOMPLETE) { KASSERT((ln->la_flags & LLE_VALID) != 0); memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); LLE_WUNLOCK(ln); return 0; } /* * There is a neighbor cache entry, but no ethernet address * response yet. Append this latest packet to the end of the * packet queue in the mbuf, unless the number of the packet * does not exceed nd6_maxqueuelen. When it exceeds nd6_maxqueuelen, * the oldest packet in the queue will be removed. */ if (ln->ln_state == ND6_LLINFO_NOSTATE || ln->ln_state == ND6_LLINFO_WAITDELETE) ln->ln_state = ND6_LLINFO_INCOMPLETE; if (ln->ln_hold) { struct mbuf *m_hold; int i; i = 0; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold->m_nextpkt) { i++; if (m_hold->m_nextpkt == NULL) { m_hold->m_nextpkt = m; break; } } while (i >= nd6_maxqueuelen) { m_hold = ln->ln_hold; ln->ln_hold = ln->ln_hold->m_nextpkt; m_freem(m_hold); i--; } } else { ln->ln_hold = m; } if (ln->ln_asked >= nd6_mmaxtries) error = (rt != NULL && rt->rt_flags & RTF_GATEWAY) ? EHOSTUNREACH : EHOSTDOWN; else error = EWOULDBLOCK; /* * If there has been no NS for the neighbor after entering the * INCOMPLETE state, send the first solicitation. */ if (!ND6_LLINFO_PERMANENT(ln) && ln->ln_asked == 0) { struct in6_addr src, *psrc; ln->ln_asked++; nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000); psrc = nd6_llinfo_get_holdsrc(ln, &src); LLE_WUNLOCK(ln); nd6_ns_output(ifp, NULL, &dst->sin6_addr, psrc, NULL); } else LLE_WUNLOCK(ln); a1645 15 static void clear_llinfo_pqueue(struct llentry *ln) { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; m_freem(m_hold); } ln->ln_hold = NULL; return; } @ 1.270 log @inet6: Ensure that route MTU is guarded by ARC_PHDS_MAXMTU This mirrors the ARP behavior for ARCnet interfaces based on current kernel RA handling. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.269 2020/04/12 12:13:52 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.269 2020/04/12 12:13:52 roy Exp $"); d37 1 d79 5 a109 3 struct nd_drhead nd_defrouter; struct nd_prhead nd_prefix = { 0 }; a111 1 static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *); a112 1 static int regen_tmpaddr(const struct in6_ifaddr *); a124 8 static int fill_drlist(void *, size_t *); static int fill_prlist(void *, size_t *); static struct ifnet *nd6_defifp; static int nd6_defifindex; static int nd6_setdefaultiface(int); a135 3 /* initialization of the default router list */ ND_DEFROUTER_LIST_INIT(); d150 1 a150 1 struct nd_ifinfo * d153 1 a153 1 struct nd_ifinfo *nd; a156 2 nd->initialized = 1; d162 1 a162 1 nd->flags = ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV; a170 11 /* A loopback interface does not need to accept RTADV. * A bridge interface should not accept RTADV * because one of its members should. */ if (ip6_accept_rtadv && !(ifp->if_flags & IFF_LOOPBACK) && !(ifp->if_type != IFT_BRIDGE)) nd->flags |= ND6_IFF_ACCEPT_RTADV; /* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */ nd6_setmtu0(ifp, nd); d181 1 a181 40 kmem_free(ext->nd_ifinfo, sizeof(struct nd_ifinfo)); } void nd6_setmtu(struct ifnet *ifp) { nd6_setmtu0(ifp, ND_IFINFO(ifp)); } void nd6_setmtu0(struct ifnet *ifp, struct nd_ifinfo *ndi) { u_int32_t omaxmtu; omaxmtu = ndi->maxmtu; switch (ifp->if_type) { case IFT_ARCNET: ndi->maxmtu = MIN(ARC_PHDS_MAXMTU, ifp->if_mtu); /* RFC2497 */ break; default: ndi->maxmtu = ifp->if_mtu; break; } /* * Decreasing the interface MTU under IPV6 minimum MTU may cause * undesirable situation. We thus notify the operator of the change * explicitly. The check for omaxmtu is necessary to restrict the * log to the case of changing the MTU, not initializing it. */ if (omaxmtu >= IPV6_MMTU && ndi->maxmtu < IPV6_MMTU) { log(LOG_NOTICE, "nd6_setmtu0: new link MTU on %s (%lu) is too" " small for IPv6 which needs %lu\n", if_name(ifp), (unsigned long)ndi->maxmtu, (unsigned long) IPV6_MMTU); } if (ndi->maxmtu > in6_maxmtu) in6_setmaxmtu(); /* check all interfaces just in case */ d397 1 a397 1 struct nd_ifinfo *ndi = NULL; d482 1 a482 1 if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) { a541 2 struct nd_defrouter *next_dr, *dr; struct nd_prefix *next_pr, *pr; d551 1 a551 16 /* expire default router list */ ND6_WLOCK(); ND_DEFROUTER_LIST_FOREACH_SAFE(dr, next_dr) { if (dr->expire && dr->expire < time_uptime) { nd6_defrtrlist_del(dr, NULL); } } ND6_UNLOCK(); /* * expire interface addresses. * in the past the loop was inside prefix expiry processing. * However, from a stricter speci-confrmance standpoint, we should * rather separate address lifetimes and prefix lifetimes. */ a552 1 addrloop: a561 1 int regen = 0; a563 18 /* * If the expiring address is temporary, try * regenerating a new one. This would be useful when * we suspended a laptop PC, then turned it on after a * period that could invalidate all temporary * addresses. Although we may have to restart the * loop (see below), it must be after purging the * address. Otherwise, we'd see an infinite loop of * regeneration. */ if (ip6_use_tempaddr && (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { IFNET_LOCK(ia6->ia_ifa.ifa_ifp); if (regen_tmpaddr(ia6) == 0) regen = 1; IFNET_UNLOCK(ia6->ia_ifa.ifa_ifp); } a581 3 if (regen) goto addrloop; /* XXX: see below */ a588 30 /* * If a temporary address has just become deprecated, * regenerate a new one if possible. */ if (ip6_use_tempaddr && (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && (oldflags & IN6_IFF_DEPRECATED) == 0) { int ret; IFNET_LOCK(ia6->ia_ifa.ifa_ifp); ret = regen_tmpaddr(ia6); IFNET_UNLOCK(ia6->ia_ifa.ifa_ifp); if (ret == 0) { /* * A new temporary address is * generated. * XXX: this means the address chain * has changed while we are still in * the loop. Although the change * would not cause disaster (because * it's not a deletion, but an * addition,) we'd rather restart the * loop just for safety. Or does this * significantly reduce performance?? */ ia6_release(ia6, &psref); goto addrloop; } } a604 21 /* expire prefix list */ ND6_WLOCK(); ND_PREFIX_LIST_FOREACH_SAFE(pr, next_pr) { /* * check prefix lifetime. * since pltime is just for autoconf, pltime processing for * prefix is not necessary. */ if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME && time_uptime - pr->ndpr_lastupdate > pr->ndpr_vltime) { /* * Just invalidate the prefix here. Removing it * will be done when purging an associated address. */ KASSERTMSG(pr->ndpr_refcnt > 0, "ndpr_refcnt=%d", pr->ndpr_refcnt); nd6_invalidate_prefix(pr); } } ND6_UNLOCK(); a614 92 /* ia6: deprecated/invalidated temporary address */ static int regen_tmpaddr(const struct in6_ifaddr *ia6) { struct ifaddr *ifa; struct ifnet *ifp; struct in6_ifaddr *public_ifa6 = NULL; int s; ifp = ia6->ia_ifa.ifa_ifp; s = pserialize_read_enter(); IFADDR_READER_FOREACH(ifa, ifp) { struct in6_ifaddr *it6; if (ifa->ifa_addr->sa_family != AF_INET6) continue; it6 = (struct in6_ifaddr *)ifa; /* ignore no autoconf addresses. */ if ((it6->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; /* ignore autoconf addresses with different prefixes. */ if (it6->ia6_ndpr == NULL || it6->ia6_ndpr != ia6->ia6_ndpr) continue; /* * Now we are looking at an autoconf address with the same * prefix as ours. If the address is temporary and is still * preferred, do not create another one. It would be rare, but * could happen, for example, when we resume a laptop PC after * a long period. */ if ((it6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && !IFA6_IS_DEPRECATED(it6)) { public_ifa6 = NULL; break; } /* * This is a public autoconf address that has the same prefix * as ours. If it is preferred, keep it. We can't break the * loop here, because there may be a still-preferred temporary * address with the prefix. */ if (!IFA6_IS_DEPRECATED(it6)) public_ifa6 = it6; } if (public_ifa6 != NULL) { int e; struct psref psref; ia6_acquire(public_ifa6, &psref); pserialize_read_exit(s); /* * Random factor is introduced in the preferred lifetime, so * we do not need additional delay (3rd arg to in6_tmpifadd). */ ND6_WLOCK(); e = in6_tmpifadd(public_ifa6, 0, 0); ND6_UNLOCK(); if (e != 0) { ia6_release(public_ifa6, &psref); log(LOG_NOTICE, "regen_tmpaddr: failed to create a new" " tmp addr, errno=%d\n", e); return -1; } ia6_release(public_ifa6, &psref); return 0; } pserialize_read_exit(s); return -1; } bool nd6_accepts_rtadv(const struct nd_ifinfo *ndi) { switch (ndi->flags & (ND6_IFF_ACCEPT_RTADV|ND6_IFF_OVERRIDE_RTADV)) { case ND6_IFF_OVERRIDE_RTADV|ND6_IFF_ACCEPT_RTADV: return true; case ND6_IFF_ACCEPT_RTADV: return ip6_accept_rtadv != 0; case ND6_IFF_OVERRIDE_RTADV: case 0: default: return false; } } a621 2 struct nd_defrouter *dr, *ndr; struct nd_prefix *pr, *npr; a632 53 ND6_WLOCK(); /* * Nuke default router list entries toward ifp. * We defer removal of default router list entries that is installed * in the routing table, in order to keep additional side effects as * small as possible. */ ND_DEFROUTER_LIST_FOREACH_SAFE(dr, ndr) { if (dr->installed) continue; if (dr->ifp == ifp) { KASSERT(ext != NULL); nd6_defrtrlist_del(dr, ext); } } ND_DEFROUTER_LIST_FOREACH_SAFE(dr, ndr) { if (!dr->installed) continue; if (dr->ifp == ifp) { KASSERT(ext != NULL); nd6_defrtrlist_del(dr, ext); } } /* Nuke prefix list entries toward ifp */ ND_PREFIX_LIST_FOREACH_SAFE(pr, npr) { if (pr->ndpr_ifp == ifp) { /* * All addresses referencing pr should be already freed. */ KASSERTMSG(pr->ndpr_refcnt == 0, "ndpr_refcnt=%d", pr->ndpr_refcnt); nd6_prelist_remove(pr); } } /* cancel default outgoing interface setting */ if (nd6_defifindex == ifp->if_index) nd6_setdefaultiface(0); /* XXX: too restrictive? */ if (!ip6_forwarding && ifp->if_afdata[AF_INET6]) { struct nd_ifinfo *ndi = ND_IFINFO(ifp); if (ndi && nd6_accepts_rtadv(ndi)) { /* refresh default router list */ nd6_defrouter_select(); } } ND6_UNLOCK(); a644 23 void nd6_assert_purged(struct ifnet *ifp) { struct nd_defrouter *dr; struct nd_prefix *pr; char ip6buf[INET6_ADDRSTRLEN] __diagused; ND6_RLOCK(); ND_DEFROUTER_LIST_FOREACH(dr) { KASSERTMSG(dr->ifp != ifp, "defrouter %s remains on %s", IN6_PRINT(ip6buf, &dr->rtaddr), ifp->if_xname); } ND_PREFIX_LIST_FOREACH(pr) { KASSERTMSG(pr->ndpr_ifp != ifp, "prefix %s/%d remains on %s", IN6_PRINT(ip6buf, &pr->ndpr_prefix.sin6_addr), pr->ndpr_plen, ifp->if_xname); } ND6_UNLOCK(); } a690 1 struct nd_prefix *pr; a717 43 * If the address matches one of our addresses, * it should be a neighbor. * If the address matches one of our on-link prefixes, it should be a * neighbor. */ ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { if (pr->ndpr_ifp != ifp) continue; if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) { struct rtentry *rt; rt = rtalloc1(sin6tosa(&pr->ndpr_prefix), 0); if (rt == NULL) continue; /* * This is the case where multiple interfaces * have the same prefix, but only one is installed * into the routing table and that prefix entry * is not the one being examined here. In the case * where RADIX_MPATH is enabled, multiple route * entries (of the same rt_key value) will be * installed because the interface addresses all * differ. */ if (!IN6_ARE_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, &satocsin6(rt_getkey(rt))->sin6_addr)) { rt_unref(rt); continue; } rt_unref(rt); } if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, &addr->sin6_addr, &pr->ndpr_mask)) { ND6_UNLOCK(); return 1; } } ND6_UNLOCK(); /* a730 12 /* * If the default router list is empty, all addresses are regarded * as on-link, and thus, as a neighbor. */ ND6_RLOCK(); if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && ND_DEFROUTER_LIST_EMPTY() && nd6_defifindex == ifp->if_index) { ND6_UNLOCK(); return 1; } ND6_UNLOCK(); a740 1 struct nd_prefix *pr; a766 32 /* * If the address matches one of our on-link prefixes, it should be a * neighbor. */ ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { if (pr->ndpr_ifp != ifp) continue; if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) continue; if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, &addr->sin6_addr, &pr->ndpr_mask)) { ND6_UNLOCK(); return 1; } } /* * If the default router list is empty, all addresses are regarded * as on-link, and thus, as a neighbor. * XXX: we restrict the condition to hosts, because routers usually do * not have the "default router list". */ if (!ip6_forwarding && ND_DEFROUTER_LIST_EMPTY() && nd6_defifindex == ifp->if_index) { ND6_UNLOCK(); return 1; } ND6_UNLOCK(); a812 1 struct in6_addr *in6; a816 2 ifp = ln->lle_tbl->llt_ifp; in6 = &ln->r_l3addr.addr6; d818 5 a822 2 * we used to have pfctlinput(PRC_HOSTDEAD) here. * even though it is not harmful, it was not really necessary. d824 8 a831 40 if (!ip6_forwarding && ln->ln_router) { if (ln->ln_state == ND6_LLINFO_STALE && gc) { /* * If the reason for the deletion is just garbage * collection, and the neighbor is an active * router, do not delete it. Instead, reset the GC * timer using the router's lifetime. * Simply deleting the entry may affect default * router selection, which is not necessarily a good * thing, especially when we're using router preference * values. * XXX: the check for ln_state would be redundant, * but we intentionally keep it just in case. */ if (ln->ln_expire > time_uptime) nd6_llinfo_settimer(ln, (ln->ln_expire - time_uptime) * hz); else nd6_llinfo_settimer(ln, nd6_gctimer * hz); LLE_WUNLOCK(ln); return; } ND6_WLOCK(); /* * We need to unlock to avoid a LOR with nd6_rt_flush() * with the rnh and for the calls to * nd6_pfxlist_onlink_check() and nd6_defrouter_select() in the * block further down for calls into nd6_lookup(). * We still hold a ref. * * Temporarily fake the state to choose a new default * router and to perform on-link determination of * prefixes correctly. * Below the state will be set correctly, * or the entry itself will be deleted. */ ln->ln_state = ND6_LLINFO_INCOMPLETE; d833 2 d836 1 a836 36 /* * nd6_rt_flush must be called whether or not the neighbor * is in the Default Router List. * See a corresponding comment in nd6_na_input(). */ nd6_rt_flush(in6, ifp); /* * Unreachablity of a router might affect the default * router selection and on-link detection of advertised * prefixes. * * Since nd6_defrouter_select() does not affect the * on-link determination and MIP6 needs the check * before the default router selection, we perform * the check now. */ nd6_pfxlist_onlink_check(); /* * refresh default router list */ nd6_defrouter_select(); #ifdef __FreeBSD__ /* * If this entry was added by an on-link redirect, remove the * corresponding host route. */ if (ln->la_flags & LLE_REDIRECT) nd6_free_redirect(ln); #endif ND6_UNLOCK(); LLE_WLOCK(ln); } d842 1 a842 1 sockaddr_in6_init(&sin6, in6, 0, 0, 0); d1194 2 a1195 2 int nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) d1197 4 a1200 8 struct in6_drlist *drl = (struct in6_drlist *)data; struct in6_oprlist *oprl = (struct in6_oprlist *)data; struct in6_ndireq *ndi = (struct in6_ndireq *)data; struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; struct in6_ndifreq *ndif = (struct in6_ndifreq *)data; struct nd_defrouter *dr; struct nd_prefix *pr; int i = 0, error = 0; d1202 1 a1202 2 switch (cmd) { case SIOCGDRLST_IN6: d1204 4 a1207 1 * obsolete API, use sysctl under net.inet6.icmp6 d1209 11 a1219 4 memset(drl, 0, sizeof(*drl)); ND6_RLOCK(); ND_DEFROUTER_LIST_FOREACH(dr) { if (i >= DRLSTSIZ) d1221 3 a1223 2 drl->defrouter[i].rtaddr = dr->rtaddr; in6_clearscope(&drl->defrouter[i].rtaddr); d1225 9 a1233 6 drl->defrouter[i].flags = dr->flags; drl->defrouter[i].rtlifetime = dr->rtlifetime; drl->defrouter[i].expire = dr->expire ? time_mono_to_wall(dr->expire) : 0; drl->defrouter[i].if_index = dr->ifp->if_index; i++; d1235 7 a1241 20 ND6_UNLOCK(); break; case SIOCGPRLST_IN6: /* * obsolete API, use sysctl under net.inet6.icmp6 * * XXX the structure in6_prlist was changed in backward- * incompatible manner. in6_oprlist is used for SIOCGPRLST_IN6, * in6_prlist is used for nd6_sysctl() - fill_prlist(). */ /* * XXX meaning of fields, especialy "raflags", is very * differnet between RA prefix list and RR/static prefix list. * how about separating ioctls into two? */ memset(oprl, 0, sizeof(*oprl)); ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { struct nd_pfxrouter *pfr; int j; d1243 7 a1249 27 if (i >= PRLSTSIZ) break; oprl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; oprl->prefix[i].raflags = pr->ndpr_raf; oprl->prefix[i].prefixlen = pr->ndpr_plen; oprl->prefix[i].vltime = pr->ndpr_vltime; oprl->prefix[i].pltime = pr->ndpr_pltime; oprl->prefix[i].if_index = pr->ndpr_ifp->if_index; if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) oprl->prefix[i].expire = 0; else { time_t maxexpire; /* XXX: we assume time_t is signed. */ maxexpire = (-1) & ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); if (pr->ndpr_vltime < maxexpire - pr->ndpr_lastupdate) { time_t expire; expire = pr->ndpr_lastupdate + pr->ndpr_vltime; oprl->prefix[i].expire = expire ? time_mono_to_wall(expire) : 0; } else oprl->prefix[i].expire = maxexpire; } d1251 1 a1251 12 j = 0; LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { if (j < DRLSTSIZ) { #define RTRADDR oprl->prefix[i].advrtr[j] RTRADDR = pfr->router->rtaddr; in6_clearscope(&RTRADDR); #undef RTRADDR } j++; } oprl->prefix[i].advrtrs = j; oprl->prefix[i].origin = PR_ORIG_RA; d1253 2 a1254 3 i++; } ND6_UNLOCK(); d1256 2 a1257 30 break; case OSIOCGIFINFO_IN6: #define ND ndi->ndi /* XXX: old ndp(8) assumes a positive value for linkmtu. */ memset(&ND, 0, sizeof(ND)); ND.linkmtu = IN6_LINKMTU(ifp); ND.maxmtu = ND_IFINFO(ifp)->maxmtu; ND.basereachable = ND_IFINFO(ifp)->basereachable; ND.reachable = ND_IFINFO(ifp)->reachable; ND.retrans = ND_IFINFO(ifp)->retrans; ND.flags = ND_IFINFO(ifp)->flags; ND.recalctm = ND_IFINFO(ifp)->recalctm; ND.chlim = ND_IFINFO(ifp)->chlim; break; case SIOCGIFINFO_IN6: ND = *ND_IFINFO(ifp); break; case SIOCSIFINFO_IN6: /* * used to change host variables from userland. * intented for a use on router to reflect RA configurations. */ /* 0 means 'unspecified' */ if (ND.linkmtu != 0) { if (ND.linkmtu < IPV6_MMTU || ND.linkmtu > IN6_LINKMTU(ifp)) { error = EINVAL; break; } ND_IFINFO(ifp)->linkmtu = ND.linkmtu; d1259 3 d1263 3 a1265 18 if (ND.basereachable != 0) { int obasereachable = ND_IFINFO(ifp)->basereachable; ND_IFINFO(ifp)->basereachable = ND.basereachable; if (ND.basereachable != obasereachable) ND_IFINFO(ifp)->reachable = ND_COMPUTE_RTIME(ND.basereachable); } if (ND.retrans != 0) ND_IFINFO(ifp)->retrans = ND.retrans; if (ND.chlim != 0) ND_IFINFO(ifp)->chlim = ND.chlim; /* FALLTHROUGH */ case SIOCSIFINFO_FLAGS: { struct ifaddr *ifa; struct in6_ifaddr *ia; int s; d1267 4 a1270 2 if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && !(ND.flags & ND6_IFF_IFDISABLED)) d1273 4 a1276 4 * If the interface is marked as ND6_IFF_IFDISABLED and * has a link-local address with IN6_IFF_DUPLICATED, * do not clear ND6_IFF_IFDISABLED. * See RFC 4862, section 5.4.5. d1278 1 a1278 1 int duplicated_linklocal = 0; d1282 1 a1282 1 if (ifa->ifa_addr->sa_family != AF_INET6) d1285 2 a1286 4 if ((ia->ia6_flags & IN6_IFF_DUPLICATED) && IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) { duplicated_linklocal = 1; d1291 2 a1292 35 if (duplicated_linklocal) { ND.flags |= ND6_IFF_IFDISABLED; log(LOG_ERR, "%s: Cannot enable an interface" " with a link-local address marked" " duplicate.\n", if_name(ifp)); } else { ND_IFINFO(ifp)->flags &= ~ND6_IFF_IFDISABLED; if (ifp->if_flags & IFF_UP) in6_if_up(ifp); } } else if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && (ND.flags & ND6_IFF_IFDISABLED)) { int bound = curlwp_bind(); /* Mark all IPv6 addresses as tentative. */ ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED; s = pserialize_read_enter(); IFADDR_READER_FOREACH(ifa, ifp) { struct psref psref; if (ifa->ifa_addr->sa_family != AF_INET6) continue; ifa_acquire(ifa, &psref); pserialize_read_exit(s); nd6_dad_stop(ifa); ia = (struct in6_ifaddr *)ifa; ia->ia6_flags |= IN6_IFF_TENTATIVE; s = pserialize_read_enter(); ifa_release(ifa, &psref); } pserialize_read_exit(s); curlwp_bindx(bound); d1294 1 d1296 2 a1297 3 if (ND.flags & ND6_IFF_AUTO_LINKLOCAL) { if (!(ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL)) { /* auto_linklocal 0->1 transition */ d1299 13 a1311 12 ND_IFINFO(ifp)->flags |= ND6_IFF_AUTO_LINKLOCAL; in6_ifattach(ifp, NULL); } else if (!(ND.flags & ND6_IFF_IFDISABLED) && ifp->if_flags & IFF_UP) { /* * When the IF already has * ND6_IFF_AUTO_LINKLOCAL, no link-local * address is assigned, and IFF_UP, try to * assign one. */ int haslinklocal = 0; d1313 10 a1322 17 s = pserialize_read_enter(); IFADDR_READER_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family !=AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))){ haslinklocal = 1; break; } } pserialize_read_exit(s); if (!haslinklocal) in6_ifattach(ifp, NULL); } } } ND_IFINFO(ifp)->flags = ND.flags; d1324 2 a1325 7 #undef ND case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */ /* sync kernel routing table with the default router list */ ND6_WLOCK(); nd6_defrouter_reset(); nd6_defrouter_select(); ND6_UNLOCK(); d1327 23 a1349 75 case SIOCSPFXFLUSH_IN6: { /* flush all the prefix advertised by routers */ struct nd_prefix *pfx, *next; restart: ND6_WLOCK(); ND_PREFIX_LIST_FOREACH_SAFE(pfx, next) { struct in6_ifaddr *ia, *ia_next; int _s; /* Only flush prefixes for the given interface. */ if (ifp != lo0ifp && ifp != pfx->ndpr_ifp) continue; if (IN6_IS_ADDR_LINKLOCAL(&pfx->ndpr_prefix.sin6_addr)) continue; /* XXX */ /* do we really have to remove addresses as well? */ _s = pserialize_read_enter(); for (ia = IN6_ADDRLIST_READER_FIRST(); ia; ia = ia_next) { struct ifnet *ifa_ifp; int bound; struct psref psref; /* ia might be removed. keep the next ptr. */ ia_next = IN6_ADDRLIST_READER_NEXT(ia); if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; if (ia->ia6_ndpr != pfx) continue; bound = curlwp_bind(); ia6_acquire(ia, &psref); pserialize_read_exit(_s); ND6_UNLOCK(); ifa_ifp = ia->ia_ifa.ifa_ifp; if (ifa_ifp == ifp) { /* Already have IFNET_LOCK(ifp) */ KASSERT(!if_is_deactivated(ifp)); ia6_release(ia, &psref); in6_purgeaddr(&ia->ia_ifa); curlwp_bindx(bound); goto restart; } IFNET_LOCK(ifa_ifp); /* * Need to take the lock first to prevent * if_detach from running in6_purgeaddr * concurrently. */ if (!if_is_deactivated(ifa_ifp)) { ia6_release(ia, &psref); in6_purgeaddr(&ia->ia_ifa); } else { /* * ifp is being destroyed, ia will be * destroyed by if_detach. */ ia6_release(ia, &psref); /* XXX may cause busy loop */ } IFNET_UNLOCK(ifa_ifp); curlwp_bindx(bound); goto restart; } pserialize_read_exit(_s); KASSERTMSG(pfx->ndpr_refcnt == 0, "ndpr_refcnt=%d", pfx->ndpr_refcnt); nd6_prelist_remove(pfx); d1351 6 a1356 1 ND6_UNLOCK(); d1358 1 a1358 10 } case SIOCSRTRFLUSH_IN6: { /* flush all the default routers */ struct nd_defrouter *drtr, *next; ND6_WLOCK(); #if 0 /* XXX Is this really needed? */ nd6_defrouter_reset(); d1360 16 a1375 6 ND_DEFROUTER_LIST_FOREACH_SAFE(drtr, next) { /* Only flush routers for the given interface. */ if (ifp != lo0ifp && ifp != drtr->ifp) continue; nd6_defrtrlist_del(drtr, NULL); d1377 5 a1381 2 nd6_defrouter_select(); ND6_UNLOCK(); d1383 1 a1383 1 } a1405 5 case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ ndif->ifindex = nd6_defifindex; break; case SIOCSDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ return nd6_setdefaultiface(ndif->ifindex); a1450 1 struct nd_ifinfo *ndi = ND_IFINFO(ifp); a1456 1 uint16_t router = 0; d1633 1 a1633 2 if (ln != NULL) { router = ln->ln_router; a1634 1 } a1641 22 /* * When the link-layer address of a router changes, select the * best router again. In particular, when the neighbor entry is newly * created, it might affect the selection policy. * Question: can we restrict the first condition to the "is_newentry" * case? * XXX: when we hear an RA from a new router with the link-layer * address option, nd6_defrouter_select() is called twice, since * defrtrlist_update called the function as well. However, I believe * we can compromise the overhead, since it only happens the first * time. * XXX: although nd6_defrouter_select() should not have a bad effect * for those are not autoconfigured hosts, we explicitly avoid such * cases for safety. */ if (do_update && router && !ip6_forwarding && nd6_accepts_rtadv(ndi)) { ND6_WLOCK(); nd6_defrouter_select(); ND6_UNLOCK(); } d1647 1 a1647 1 struct nd_ifinfo *nd6if; d1657 3 a1659 3 nd6if = ND_IFINFO(ifp); if (nd6if->basereachable && /* already initialized */ (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) { d1666 2 a1667 2 nd6if->recalctm = nd6_recalc_reachtm_interval; nd6if->reachable = ND_COMPUTE_RTIME(nd6if->basereachable); d1688 1 d1691 1 a1691 1 if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { d1822 1 a1822 1 nd6_llinfo_settimer(ln, ND_IFINFO(ifp)->retrans * hz / 1000); d1873 1 a1873 1 a1882 1 int (*fill_func)(void *, size_t *); d1888 6 a1893 8 case ICMPV6CTL_ND6_DRLIST: fill_func = fill_drlist; break; case ICMPV6CTL_ND6_PRLIST: fill_func = fill_prlist; break; a1895 1 a1898 201 if (oldlenp == NULL) return EINVAL; size_t ol; int error = (*fill_func)(NULL, &ol); /* calc len needed */ if (error) return error; if (oldp == NULL) { *oldlenp = ol; return 0; } ol = *oldlenp = uimin(ol, *oldlenp); if (ol == 0) return 0; void *p = kmem_alloc(ol, KM_SLEEP); error = (*fill_func)(p, oldlenp); if (!error) error = copyout(p, oldp, *oldlenp); kmem_free(p, ol); return error; } static int fill_drlist(void *oldp, size_t *oldlenp) { int error = 0; struct in6_defrouter *d = NULL, *de = NULL; struct nd_defrouter *dr; size_t l; if (oldp) { d = (struct in6_defrouter *)oldp; de = (struct in6_defrouter *)((char *)oldp + *oldlenp); } l = 0; ND6_RLOCK(); ND_DEFROUTER_LIST_FOREACH(dr) { if (oldp && d + 1 <= de) { memset(d, 0, sizeof(*d)); sockaddr_in6_init(&d->rtaddr, &dr->rtaddr, 0, 0, 0); if (sa6_recoverscope(&d->rtaddr)) { char ip6buf[INET6_ADDRSTRLEN]; log(LOG_ERR, "scope error in router list (%s)\n", IN6_PRINT(ip6buf, &d->rtaddr.sin6_addr)); /* XXX: press on... */ } d->flags = dr->flags; d->rtlifetime = dr->rtlifetime; d->expire = dr->expire ? time_mono_to_wall(dr->expire) : 0; d->if_index = dr->ifp->if_index; } l += sizeof(*d); if (d) d++; } ND6_UNLOCK(); *oldlenp = l; /* (void *)d - (void *)oldp */ return error; } static int fill_prlist(void *oldp, size_t *oldlenp) { int error = 0; struct nd_prefix *pr; uint8_t *p = NULL, *ps = NULL; uint8_t *pe = NULL; size_t l; char ip6buf[INET6_ADDRSTRLEN]; if (oldp) { ps = p = (uint8_t*)oldp; pe = (uint8_t*)oldp + *oldlenp; } l = 0; ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { u_short advrtrs; struct sockaddr_in6 sin6; struct nd_pfxrouter *pfr; struct in6_prefix pfx; if (oldp && p + sizeof(struct in6_prefix) <= pe) { memset(&pfx, 0, sizeof(pfx)); ps = p; pfx.prefix = pr->ndpr_prefix; if (sa6_recoverscope(&pfx.prefix)) { log(LOG_ERR, "scope error in prefix list (%s)\n", IN6_PRINT(ip6buf, &pfx.prefix.sin6_addr)); /* XXX: press on... */ } pfx.raflags = pr->ndpr_raf; pfx.prefixlen = pr->ndpr_plen; pfx.vltime = pr->ndpr_vltime; pfx.pltime = pr->ndpr_pltime; pfx.if_index = pr->ndpr_ifp->if_index; if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) pfx.expire = 0; else { time_t maxexpire; /* XXX: we assume time_t is signed. */ maxexpire = (-1) & ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); if (pr->ndpr_vltime < maxexpire - pr->ndpr_lastupdate) { pfx.expire = pr->ndpr_lastupdate + pr->ndpr_vltime; } else pfx.expire = maxexpire; } pfx.refcnt = pr->ndpr_refcnt; pfx.flags = pr->ndpr_stateflags; pfx.origin = PR_ORIG_RA; p += sizeof(pfx); l += sizeof(pfx); advrtrs = 0; LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { if (p + sizeof(sin6) > pe) { advrtrs++; continue; } sockaddr_in6_init(&sin6, &pfr->router->rtaddr, 0, 0, 0); if (sa6_recoverscope(&sin6)) { log(LOG_ERR, "scope error in " "prefix list (%s)\n", IN6_PRINT(ip6buf, &pfr->router->rtaddr)); } advrtrs++; memcpy(p, &sin6, sizeof(sin6)); p += sizeof(sin6); l += sizeof(sin6); } pfx.advrtrs = advrtrs; memcpy(ps, &pfx, sizeof(pfx)); } else { l += sizeof(pfx); advrtrs = 0; LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { advrtrs++; l += sizeof(sin6); } } } ND6_UNLOCK(); *oldlenp = l; return error; } static int nd6_setdefaultiface(int ifindex) { ifnet_t *ifp; int error = 0; int s; s = pserialize_read_enter(); ifp = if_byindex(ifindex); if (ifp == NULL) { pserialize_read_exit(s); return EINVAL; } if (nd6_defifindex != ifindex) { nd6_defifindex = ifindex; nd6_defifp = nd6_defifindex > 0 ? ifp : NULL; /* * Our current implementation assumes one-to-one maping between * interfaces and links, so it would be natural to use the * default interface as the default link. */ scope6_setdefault(nd6_defifp); } pserialize_read_exit(s); return (error); @ 1.269 log @nd6: RTM_MISS reports RTA_AUTHOR once more Just moves the logic to send RTM_MISS after the ICMP6 report as we rely on that function to extract the requesting address. Fixes PR kern/55164. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.268 2020/04/03 14:04:27 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.268 2020/04/03 14:04:27 christos Exp $"); d1465 14 a1478 1 if ((rt->rt_flags & RTF_GATEWAY) != 0) d1480 1 @ 1.268 log @PR/55030: Avoid locking against myself panic by moving the icmp error outside the lock. Thanks ozaki-r! @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.267 2020/03/09 21:20:56 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.267 2020/03/09 21:20:56 roy Exp $"); a460 1 struct in6_addr mdaddr6 = zeroin6_addr; a463 1 struct sockaddr *sa; d465 1 d495 3 a512 9 sockaddr_in6_init(&tsin6, taddr6, 0, 0, 0); if (!IN6_IS_ADDR_UNSPECIFIED(&mdaddr6)) { sockaddr_in6_init(&dsin6, &mdaddr6, 0, 0, 0); sa = sin6tosa(&dsin6); } else sa = NULL; rt_clonedmsg(RTM_MISS, sa, sin6tosa(&tsin6), NULL, ifp); d582 13 a594 3 if (m) { icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, ifp, &mdaddr6); @ 1.268.2.1 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.269 2020/04/12 12:13:52 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.269 2020/04/12 12:13:52 roy Exp $"); d461 1 d465 1 a466 1 bool missed = false; a495 3 missed = true; sockaddr_in6_init(&tsin6, taddr6, 0, 0, 0); d511 9 d589 3 a591 13 if (missed) { struct in6_addr mdaddr6 = zeroin6_addr; struct sockaddr *sa; if (m != NULL) icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, ifp, &mdaddr6); if (!IN6_IS_ADDR_UNSPECIFIED(&mdaddr6)) { sockaddr_in6_init(&dsin6, &mdaddr6, 0, 0, 0); sa = sin6tosa(&dsin6); } else sa = NULL; rt_clonedmsg(RTM_MISS, sa, sin6tosa(&tsin6), NULL, ifp); @ 1.267 log @route: RTM_MISS now puts the message source address in RTA_AUTHOR route(8) also reports this. A userland app could use this to blacklist nodes who probe for machines that doesn't exist on a subnet / prefix. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.266 2020/01/20 18:38:22 thorpej Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.266 2020/01/20 18:38:22 thorpej Exp $"); d466 1 d497 3 a499 1 struct mbuf *m = ln->ln_hold, *m0; a508 3 icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, ifp, &mdaddr6); d589 4 @ 1.266 log @Remove FDDI support. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.265 2019/09/25 09:53:38 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.265 2019/09/25 09:53:38 ozaki-r Exp $"); d461 1 d464 2 a465 1 struct sockaddr_in6 sin6; d508 1 a508 1 ICMP6_DST_UNREACH_ADDR, 0, ifp); d511 8 a518 2 sockaddr_in6_init(&sin6, taddr6, 0, 0, 0); rt_clonedmsg(RTM_MISS, sin6tosa(&sin6), NULL, ifp); d1315 1 a1315 1 rt_clonedmsg(RTM_DELETE, sin6tosa(&sin6), lladdr, ifp); d2256 1 a2256 1 sin6tosa(&sin6), lladdr, ifp); @ 1.265 log @Make panic messages more informative @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.264 2019/09/25 09:52:32 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.264 2019/09/25 09:52:32 ozaki-r Exp $"); a65 1 #include a223 3 case IFT_FDDI: ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); break; d2481 1 a2481 1 * other than ARCnet, Ethernet, FDDI and GIF. a2488 1 case IFT_FDDI: @ 1.265.2.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.266 2020/01/20 18:38:22 thorpej Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.266 2020/01/20 18:38:22 thorpej Exp $"); d66 1 d225 3 d2485 1 a2485 1 * other than ARCnet, Ethernet, and GIF. d2493 1 @ 1.264 log @Initialize DAD components properly The original code initialized each component in non-init functions such as arp_dad_start and nd6_dad_find, conditionally based on a global flag for each. However, it was racy because the flag and the code around it were not protected by a lock and could cause a kernel panic at worst. Fix the issue by initializing the components in bootup as usual. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.263 2019/09/01 19:26:21 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.263 2019/09/01 19:26:21 roy Exp $"); d740 2 a741 1 KASSERT(pr->ndpr_refcnt > 0); d902 2 a903 1 KASSERT(pr->ndpr_refcnt == 0); d1971 2 a1972 1 KASSERT(pfx->ndpr_refcnt == 0); @ 1.263 log @inet6: Re-introduce ND6_LLINFO_WAITDELETE so we can return EHOSTDOWN Once we've sent nd6_mmaxtries NS messages, send RTM_MISS and move to the ND6_LLINFO_WAITDELETE state rather than freeing the llentry right away. Wait for a probe cycle and then free the llentry. If a connection attempts to re-use the llentry during ND6_LLINFO_WAITDELETE, return EHOSTDOWN (or EHOSTUNREACH if a gateway) to match inet behaviour. Continue to ND6_LLINFO_INCOMPLETE and send another NS probe in hope of a reply. Rinse and repeat. This reverts part of nd6.c r1.14 - an 18 year old commit! @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.262 2019/09/01 18:54:38 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.262 2019/09/01 18:54:38 roy Exp $"); d140 2 @ 1.262 log @inet6: Send RTM_MISS when we fail to resolve an address. Takes the same approach as when adding a new address - we no longer announce the new lladdr right away but we announce the result. This will either be RTM_ADD or RTM_MISS. RTM_DELETE is only sent if we have a lladdr assigned OR gc'ed. This results in less messages via route(4) and tells us when a new lladdr has been added (RTM_ADD), changed (RTM_CHANGE), deleted (RTM_DELETED) or has failed to been resolved (RTM_MISS). The latter case can be interpreted as unreachable. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.261 2019/08/31 01:49:45 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.261 2019/08/31 01:49:45 roy Exp $"); d483 6 d490 1 a490 2 if (ln->ln_asked < nd6_mmaxtries) { ln->ln_asked++; d514 11 a524 3 LLE_REMREF(ln); nd6_free(ln, 0); ln = NULL; d2328 1 d2423 2 a2424 1 if (ln->ln_state == ND6_LLINFO_NOSTATE) d2448 6 d2472 1 a2472 1 return EWOULDBLOCK; @ 1.261 log @inet6: don't set an invalid lladdr in nd6_free() We don't want to announce that we've deleted a hwaddr of all zeros. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.260 2019/08/27 21:11:26 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.260 2019/08/27 21:11:26 roy Exp $"); d464 2 a476 1 d487 14 a500 4 } else { struct mbuf *m = ln->ln_hold; if (m) { struct mbuf *m0; d502 2 a503 16 /* * assuming every packet in ln_hold has * the same IP header */ m0 = m->m_nextpkt; m->m_nextpkt = NULL; ln->ln_hold = m0; clear_llinfo_pqueue(ln); } LLE_REMREF(ln); nd6_free(ln, 0); ln = NULL; if (m != NULL) { icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, ifp); } d505 7 d513 1 a557 1 const struct in6_addr *taddr6 = &ln->r_l3addr.addr6; a1197 2 struct sockaddr_in6 sin6; const char *lladdr; d1287 9 a1295 3 sockaddr_in6_init(&sin6, in6, 0, 0, 0); lladdr = ln->la_flags & LLE_VALID ? (const char *)&ln->ll_addr : NULL; rt_clonedmsg(RTM_DELETE, sin6tosa(&sin6), lladdr, ifp); d2229 1 a2229 1 if (do_update) { a2344 1 struct sockaddr_in6 sin6; a2359 5 sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); if (rt != NULL) rt_clonedmsg(RTM_ADD, sin6tosa(&sin6), NULL, ifp); a2443 1 ln = NULL; d2445 1 a2445 2 } else { /* We did the lookup so we need to do the unlock here. */ a2446 1 } @ 1.260 log @inet6: nd6_free assumes all routers are processed by kernel RA This hasn't been the case for a long time if you're a dhcpcd user with a default config. As such, it's possible for the default IPv6 router as set by dhcpcd could be erroneously gc'ed by nd6_free. This reduces the scope of the ND6_WLOCK taken as well as fixing an issue where we write to ln->ln_state without a lock being held. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.259 2019/08/22 21:22:50 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.259 2019/08/22 21:22:50 roy Exp $"); d1195 1 d1286 2 a1287 2 rt_clonedmsg(RTM_DELETE, sin6tosa(&sin6), (const uint8_t *)&ln->ll_addr, ifp); @ 1.259 log @nd6: notify userland of neighbour lla updates once more XXX pullup -8 -9 @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.258 2019/08/22 21:14:46 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.258 2019/08/22 21:14:46 roy Exp $"); a1191 1 struct nd_defrouter *dr; d1206 2 a1207 6 if (!ip6_forwarding) { ND6_WLOCK(); dr = nd6_defrouter_lookup(in6, ifp); if (dr != NULL && dr->expire && ln->ln_state == ND6_LLINFO_STALE && gc) { d1210 1 a1210 1 * collection, and the neighbor is an active default d1213 1 a1213 1 * Simply deleting the entry would affect default d1220 1 a1220 1 if (dr->expire > time_uptime) d1222 1 a1222 1 (dr->expire - time_uptime) * hz); a1224 1 ND6_UNLOCK(); d1229 1 a1229 9 if (ln->ln_router || dr) { /* * We need to unlock to avoid a LOR with nd6_rt_flush() * with the rnh and for the calls to * nd6_pfxlist_onlink_check() and nd6_defrouter_select() in the * block further down for calls into nd6_lookup(). * We still hold a ref. */ LLE_WUNLOCK(ln); d1231 15 a1245 7 /* * nd6_rt_flush must be called whether or not the neighbor * is in the Default Router List. * See a corresponding comment in nd6_na_input(). */ nd6_rt_flush(in6, ifp); } d1247 6 a1252 6 if (dr) { /* * Unreachablity of a router might affect the default * router selection and on-link detection of advertised * prefixes. */ d1254 11 a1264 8 /* * Temporarily fake the state to choose a new default * router and to perform on-link determination of * prefixes correctly. * Below the state will be set correctly, * or the entry itself will be deleted. */ ln->ln_state = ND6_LLINFO_INCOMPLETE; d1266 4 a1269 13 /* * Since nd6_defrouter_select() does not affect the * on-link determination and MIP6 needs the check * before the default router selection, we perform * the check now. */ nd6_pfxlist_onlink_check(); /* * refresh default router list */ nd6_defrouter_select(); } d1279 1 d1281 1 a1281 3 if (ln->ln_router || dr) LLE_WLOCK(ln); @ 1.258 log @rtsock: rework rt_clonedmsg to take a message type and lladdr We will use this in a future patch to notify userland of lladdr changes. XXX pullup -8 -9 @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.257 2019/08/14 08:34:44 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.257 2019/08/14 08:34:44 ozaki-r Exp $"); d1195 1 d1297 4 d2233 7 a2239 5 #if 0 /* XXX should we send rtmsg as it used to be? */ if (do_update) rt_newmsg(RTM_CHANGE, rt); /* tell user process */ #endif @ 1.257 log @Add missing IFNET_LOCK for regen_tmpaddr Reported by ryo@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.256 2019/07/26 10:18:42 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.256 2019/07/26 10:18:42 christos Exp $"); d2360 2 a2361 1 rt_clonedmsg(sin6tosa(&sin6), ifp, rt); @ 1.256 log @Decrease the reference count before freeing, so that the entries actually get free'd. (Ryota Ozaki) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.255 2019/06/28 06:45:16 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.255 2019/06/28 06:45:16 ozaki-r Exp $"); d669 1 d671 4 a674 1 if (regen_tmpaddr(ia6) == 0) { @ 1.256.2.1 log @Pull up following revision(s) (requested by ozaki-r in ticket #97): sys/netinet6/nd6.c: revision 1.257 Add missing IFNET_LOCK for regen_tmpaddr Reported by ryo@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.256 2019/07/26 10:18:42 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.256 2019/07/26 10:18:42 christos Exp $"); a668 1 int ret; d670 1 a670 4 IFNET_LOCK(ia6->ia_ifa.ifa_ifp); ret = regen_tmpaddr(ia6); IFNET_UNLOCK(ia6->ia_ifa.ifa_ifp); if (ret == 0) { @ 1.256.2.2 log @Pull up following revision(s) (requested by roy in ticket #109): sys/net/route.h: revision 1.124 sys/netinet6/nd6.c: revision 1.258 sys/netinet6/nd6.c: revision 1.259 sys/net/rtsock.c: revision 1.251 sys/netinet/if_arp.c: revision 1.284 sys/netinet6/nd6_nbr.c: revision 1.167 rtsock: rework rt_clonedmsg to take a message type and lladdr We will use this in a future patch to notify userland of lladdr changes. XXX pullup -8 -9 - nd6: notify userland of neighbour lla updates once more XXX pullup -8 -9 @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.256.2.1 2019/08/19 16:08:19 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.256.2.1 2019/08/19 16:08:19 martin Exp $"); a1194 1 struct sockaddr_in6 sin6; a1295 4 sockaddr_in6_init(&sin6, in6, 0, 0, 0); rt_clonedmsg(RTM_DELETE, sin6tosa(&sin6), (const uint8_t *)&ln->ll_addr, ifp); d2228 5 a2232 7 if (do_update) { struct sockaddr_in6 sin6; sockaddr_in6_init(&sin6, from, 0, 0, 0); rt_clonedmsg(is_newentry ? RTM_ADD : RTM_CHANGE, sin6tosa(&sin6), lladdr, ifp); } d2360 1 a2360 2 if (rt != NULL) rt_clonedmsg(RTM_ADD, sin6tosa(&sin6), NULL, ifp); @ 1.256.2.3 log @Pull up following revision(s) (requested by roy in ticket #131): sys/netinet6/nd6.c: revision 1.260 inet6: nd6_free assumes all routers are processed by kernel RA This hasn't been the case for a long time if you're a dhcpcd user with a default config. As such, it's possible for the default IPv6 router as set by dhcpcd could be erroneously gc'ed by nd6_free. This reduces the scope of the ND6_WLOCK taken as well as fixing an issue where we write to ln->ln_state without a lock being held. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.256.2.2 2019/08/26 13:42:36 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.256.2.2 2019/08/26 13:42:36 martin Exp $"); d1192 1 d1207 6 a1212 2 if (!ip6_forwarding && ln->ln_router) { if (ln->ln_state == ND6_LLINFO_STALE && gc) { d1215 1 a1215 1 * collection, and the neighbor is an active d1218 1 a1218 1 * Simply deleting the entry may affect default d1225 1 a1225 1 if (ln->ln_expire > time_uptime) d1227 1 a1227 1 (ln->ln_expire - time_uptime) * hz); d1230 1 d1235 17 a1251 1 ND6_WLOCK(); d1253 6 a1258 15 /* * We need to unlock to avoid a LOR with nd6_rt_flush() * with the rnh and for the calls to * nd6_pfxlist_onlink_check() and nd6_defrouter_select() in the * block further down for calls into nd6_lookup(). * We still hold a ref. * * Temporarily fake the state to choose a new default * router and to perform on-link determination of * prefixes correctly. * Below the state will be set correctly, * or the entry itself will be deleted. */ ln->ln_state = ND6_LLINFO_INCOMPLETE; LLE_WUNLOCK(ln); d1260 8 a1267 6 /* * nd6_rt_flush must be called whether or not the neighbor * is in the Default Router List. * See a corresponding comment in nd6_na_input(). */ nd6_rt_flush(in6, ifp); d1269 7 a1275 11 /* * Unreachablity of a router might affect the default * router selection and on-link detection of advertised * prefixes. * * Since nd6_defrouter_select() does not affect the * on-link determination and MIP6 needs the check * before the default router selection, we perform * the check now. */ nd6_pfxlist_onlink_check(); d1277 5 a1281 4 /* * refresh default router list */ nd6_defrouter_select(); d1291 1 d1293 2 a1294 2 ND6_UNLOCK(); LLE_WLOCK(ln); @ 1.256.2.4 log @Pull up following revision(s) (requested by roy in ticket #148): sys/netinet6/nd6.c: revision 1.261 inet6: don't set an invalid lladdr in nd6_free() We don't want to announce that we've deleted a hwaddr of all zeros. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.256.2.3 2019/09/01 11:00:31 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.256.2.3 2019/09/01 11:00:31 martin Exp $"); a1194 1 const char *lladdr; d1285 2 a1286 2 lladdr = ln->la_flags & LLE_VALID ? (const char *)&ln->ll_addr : NULL; rt_clonedmsg(RTM_DELETE, sin6tosa(&sin6), lladdr, ifp); @ 1.256.2.5 log @Pull up following revision(s) (requested by roy in ticket #168): sys/net/rtsock.c: revision 1.252 sys/netinet6/nd6_nbr.c: revision 1.168 - 1.172 sys/netinet6/nd6.c: revision 1.262 inet6: Send RTM_MISS when we fail to resolve an address. Takes the same approach as when adding a new address - we no longer announce the new lladdr right away but we announce the result. This will either be RTM_ADD or RTM_MISS. RTM_DELETE is only sent if we have a lladdr assigned OR gc'ed. This results in less messages via route(4) and tells us when a new lladdr has been added (RTM_ADD), changed (RTM_CHANGE), deleted (RTM_DELETED) or has failed to been resolved (RTM_MISS). The latter case can be interpreted as unreachable. inet6: change rt_announce and llchange to bool in nd6_na_input() more bool @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.256.2.4 2019/09/01 14:06:22 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.256.2.4 2019/09/01 14:06:22 martin Exp $"); a463 2 const struct in6_addr *taddr6 = &ln->r_l3addr.addr6; struct sockaddr_in6 sin6; d475 1 d486 4 a489 2 break; } d491 16 a506 14 if (ln->ln_hold) { struct mbuf *m = ln->ln_hold, *m0; /* * assuming every packet in ln_hold has * the same IP header */ m0 = m->m_nextpkt; m->m_nextpkt = NULL; ln->ln_hold = m0; clear_llinfo_pqueue(ln); icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, ifp); a507 7 sockaddr_in6_init(&sin6, taddr6, 0, 0, 0); rt_clonedmsg(RTM_MISS, sin6tosa(&sin6), NULL, ifp); LLE_REMREF(ln); nd6_free(ln, 0); ln = NULL; a508 1 d553 1 d1194 2 d1285 3 a1287 9 if (ln->la_flags & LLE_VALID || gc) { struct sockaddr_in6 sin6; const char *lladdr; sockaddr_in6_init(&sin6, in6, 0, 0, 0); lladdr = ln->la_flags & LLE_VALID ? (const char *)&ln->ll_addr : NULL; rt_clonedmsg(RTM_DELETE, sin6tosa(&sin6), lladdr, ifp); } d2221 1 a2221 1 if (do_update && lladdr != NULL) { d2337 1 d2353 5 d2442 1 d2444 2 a2445 1 } else d2447 1 @ 1.256.2.6 log @Pull up following revision(s) (requested by roy in ticket #169): sys/netinet6/nd6.h: revision 1.87 sys/netinet6/nd6.c: revision 1.263 inet6: Re-introduce ND6_LLINFO_WAITDELETE so we can return EHOSTDOWN Once we've sent nd6_mmaxtries NS messages, send RTM_MISS and move to the ND6_LLINFO_WAITDELETE state rather than freeing the llentry right away. Wait for a probe cycle and then free the llentry. If a connection attempts to re-use the llentry during ND6_LLINFO_WAITDELETE, return EHOSTDOWN (or EHOSTUNREACH if a gateway) to match inet behaviour. Continue to ND6_LLINFO_INCOMPLETE and send another NS probe in hope of a reply. Rinse and repeat. This reverts part of nd6.c r1.14 - an 18 year old commit! @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.256.2.5 2019/09/05 08:28:06 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.256.2.5 2019/09/05 08:28:06 martin Exp $"); a482 6 case ND6_LLINFO_WAITDELETE: LLE_REMREF(ln); nd6_free(ln, 0); ln = NULL; break; d484 2 a485 1 if (ln->ln_asked++ < nd6_mmaxtries) { d509 3 a511 11 /* * Move to the ND6_LLINFO_WAITDELETE state for another * interval at which point the llentry will be freed * unless it's attempted to be used again and we'll * resend NS again, rinse and repeat. */ ln->ln_state = ND6_LLINFO_WAITDELETE; if (ln->ln_asked == nd6_mmaxtries) nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000); else send_ns = true; a2314 1 int error; d2409 1 a2409 2 if (ln->ln_state == ND6_LLINFO_NOSTATE || ln->ln_state == ND6_LLINFO_WAITDELETE) a2432 6 if (ln->ln_asked >= nd6_mmaxtries) error = (rt != NULL && rt->rt_flags & RTF_GATEWAY) ? EHOSTUNREACH : EHOSTDOWN; else error = EWOULDBLOCK; d2451 1 a2451 1 return error; @ 1.256.2.7 log @Pull up following revision(s) (requested by ozaki-r in ticket #269): sys/netinet6/nd6.h: revision 1.88 sys/net/rtsock_shared.c: revision 1.10 sys/netinet6/nd6_nbr.c: revision 1.174 sys/netinet6/nd6.c: revision 1.264 sys/netinet/if_arp.c: revision 1.283 sys/netinet/if_arp.c: revision 1.288 Initialize DAD components properly The original code initialized each component in non-init functions such as arp_dad_start and nd6_dad_find, conditionally based on a global flag for each. However, it was racy because the flag and the code around it were not protected by a lock and could cause a kernel panic at worst. Fix the issue by initializing the components in bootup as usual. - Initialize dom_mowner for MBUFTRACE @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.256.2.6 2019/09/05 08:32:34 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.256.2.6 2019/09/05 08:32:34 martin Exp $"); a139 2 nd6_nbr_init(); @ 1.256.2.8 log @Pull up following revision(s) (requested by ozaki-r in ticket #1338): sys/netinet6/nd6.c: revision 1.277 nd6: prevent ln from being freed while releasing held packets @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.256.2.7 2019/09/30 15:55:40 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.256.2.7 2019/09/30 15:55:40 martin Exp $"); a2038 1 LLE_ADDREF(ln); a2051 1 LLE_REMREF(ln); @ 1.256.2.9 log @Apply patch, requested by kim in ticket #1497: sys/netinet6/nd6.c (apply patch) PR 55680: avoid duplicate free of link layer entries (code in HEAD is different) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.256.2.8 2021/08/20 19:32:49 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.256.2.8 2021/08/20 19:32:49 martin Exp $"); d486 1 d540 1 d564 1 a1242 1 LLE_REMREF(ln); a1319 1 LLE_REMREF(ln); @ 1.255 log @nd6: restore a missing reachability confirmation On sending a packet over a STALE cache, the cache should be tried a reachability confirmation, which is described in RFC 2461/4861 7.3.3. On the fast path in nd6_resolve, however, the treatment for STALE caches has been skipped accidentally. So STALE caches never be back to the REACHABLE state. To fix the issue, branch to the fast path only when the cache entry is the REACHABLE state and leave other caches to the slow path that includes the treatment. To this end we need to allow to return a link-layer address if a valid address is available on the slow path too, which is the same behavior as FreeBSD and OpenBSD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.254 2019/05/13 02:03:07 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.254 2019/05/13 02:03:07 christos Exp $"); d500 1 d520 1 d544 1 @ 1.254 log @print the name of the interface that was disabled. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.253 2019/04/29 11:57:22 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.253 2019/04/29 11:57:22 roy Exp $"); d2322 2 a2323 2 if (ln != NULL && (ln->la_flags & LLE_VALID) != 0) { KASSERT(ln->ln_state > ND6_LLINFO_INCOMPLETE); d2386 12 @ 1.253 log @rtsock: Route address message simplification Rename rt_newaddrmsg to rt_addrmsg_rt. Add rt_addrmsg which drops the error and route arguments which are only needed by one caller. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.252 2018/12/16 08:54:58 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.252 2018/12/16 08:54:58 roy Exp $"); d1797 1 a1797 1 log(LOG_ERR, "Cannot enable an interface" d1799 1 a1799 1 " duplicate.\n"); @ 1.252 log @netinet6: only flush prefixes and routers for the given interface. Unless it's lo0, where we then flush the lot. The maintains the status-quo with ndp(8) and allows dhcpcd(8) to at least try and work with kernel RA on one interface and dhcpcd on another. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.251 2018/10/30 05:54:41 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.251 2018/10/30 05:54:41 ozaki-r Exp $"); d656 1 a656 2 rt_newaddrmsg(RTM_NEWADDR, (struct ifaddr *)ia6, 0, NULL); d691 1 a691 2 rt_newaddrmsg(RTM_NEWADDR, (struct ifaddr *)ia6, 0, NULL); @ 1.251 log @Avoid double rt_replace_ifa on rtrequest1(RTM_ADD) Some callers of rtrequest1(RTM_ADD) adjust rt_ifa of an rtentry created by rtrequest1 that may change rt_ifa (in ifa_rtrequest) with another ifa that is different from requested one. It's wasteful and even worse introduces a race condition. rtrequest1 should just use a passed ifa as is if a caller hopes so. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.250 2018/09/03 16:29:36 riastradh Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.250 2018/09/03 16:29:36 riastradh Exp $"); d1887 4 d1960 2 d1963 1 d1965 4 @ 1.250 log @Rename min/max -> uimin/uimax for better honesty. These functions are defined on unsigned int. The generic name min/max should not silently truncate to 32 bits on 64-bit systems. This is purely a name change -- no functional change intended. HOWEVER! Some subsystems have #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) even though our standard name for that is MIN/MAX. Although these may invite multiple evaluation bugs, these do _not_ cause integer truncation. To avoid `fixing' these cases, I first changed the name in libkern, and then compile-tested every file where min/max occurred in order to confirm that it failed -- and thus confirm that nothing shadowed min/max -- before changing it. I have left a handful of bootloaders that are too annoying to compile-test, and some dead code: cobalt ews4800mips hp300 hppa ia64 luna68k vax acorn32/if_ie.c (not included in any kernels) macppc/if_gm.c (superseded by gem(4)) It should be easy to fix the fallout once identified -- this way of doing things fails safe, and the goal here, after all, is to _avoid_ silent integer truncations, not introduce them. Maybe one day we can reintroduce min/max as type-generic things that never silently truncate. But we should avoid doing that for a while, so that existing code has a chance to be detected by the compiler for conversion to uimin/uimax without changing the semantics until we can properly audit it all. (Who knows, maybe in some cases integer truncation is actually intended!) @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d1569 2 a1570 1 if (ifa != rt->rt_ifa) @ 1.249 log @Make a deletion of in6m in nd6_rtrequest atomic @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.248 2018/05/01 07:21:39 maxv Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.248 2018/05/01 07:21:39 maxv Exp $"); d2513 1 a2513 1 ol = *oldlenp = min(ol, *oldlenp); @ 1.249.2.1 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.254 2019/05/13 02:03:07 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.254 2019/05/13 02:03:07 christos Exp $"); d656 2 a657 1 rt_addrmsg(RTM_NEWADDR, (struct ifaddr *)ia6); d692 2 a693 1 rt_addrmsg(RTM_NEWADDR, (struct ifaddr *)ia6); d1569 1 a1569 2 if (!ISSET(info->rti_flags, RTF_DONTCHANGEIFA) && ifa != rt->rt_ifa) d1798 1 a1798 1 log(LOG_ERR, "%s: Cannot enable an interface" d1800 1 a1800 1 " duplicate.\n", if_name(ifp)); a1885 4 /* Only flush prefixes for the given interface. */ if (ifp != lo0ifp && ifp != pfx->ndpr_ifp) continue; a1954 2 #if 0 /* XXX Is this really needed? */ a1955 1 #endif a1956 4 /* Only flush routers for the given interface. */ if (ifp != lo0ifp && ifp != drtr->ifp) continue; d2513 1 a2513 1 ol = *oldlenp = uimin(ol, *oldlenp); @ 1.249.2.2 log @Mostly merge changes from HEAD upto 20200411 @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d66 1 a139 2 nd6_nbr_init(); d223 3 a462 1 struct in6_addr mdaddr6 = zeroin6_addr; a463 4 const struct in6_addr *taddr6 = &ln->r_l3addr.addr6; struct sockaddr_in6 dsin6, tsin6; struct sockaddr *sa; struct mbuf *m = NULL; d475 1 a481 6 case ND6_LLINFO_WAITDELETE: LLE_REMREF(ln); nd6_free(ln, 0); ln = NULL; break; d483 2 a484 1 if (ln->ln_asked++ < nd6_mmaxtries) { d486 4 a489 2 break; } d491 15 a505 13 if (ln->ln_hold) { struct mbuf *m0; m = ln->ln_hold; /* * assuming every packet in ln_hold has * the same IP header */ m0 = m->m_nextpkt; m->m_nextpkt = NULL; ln->ln_hold = m0; clear_llinfo_pqueue(ln); a506 21 sockaddr_in6_init(&tsin6, taddr6, 0, 0, 0); if (!IN6_IS_ADDR_UNSPECIFIED(&mdaddr6)) { sockaddr_in6_init(&dsin6, &mdaddr6, 0, 0, 0); sa = sin6tosa(&dsin6); } else sa = NULL; rt_clonedmsg(RTM_MISS, sa, sin6tosa(&tsin6), NULL, ifp); /* * Move to the ND6_LLINFO_WAITDELETE state for another * interval at which point the llentry will be freed * unless it's attempted to be used again and we'll * resend NS again, rinse and repeat. */ ln->ln_state = ND6_LLINFO_WAITDELETE; if (ln->ln_asked == nd6_mmaxtries) nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000); else send_ns = true; a507 1 a518 1 LLE_REMREF(ln); a541 1 LLE_REMREF(ln); d550 1 a562 4 if (m) { icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, ifp, &mdaddr6); } a665 1 int ret; d667 1 a667 4 IFNET_LOCK(ia6->ia_ifa.ifa_ifp); ret = regen_tmpaddr(ia6); IFNET_UNLOCK(ia6->ia_ifa.ifa_ifp); if (ret == 0) { d714 1 a714 2 KASSERTMSG(pr->ndpr_refcnt > 0, "ndpr_refcnt=%d", pr->ndpr_refcnt); d875 1 a875 2 KASSERTMSG(pr->ndpr_refcnt == 0, "ndpr_refcnt=%d", pr->ndpr_refcnt); d1185 1 d1199 6 a1204 2 if (!ip6_forwarding && ln->ln_router) { if (ln->ln_state == ND6_LLINFO_STALE && gc) { d1207 1 a1207 1 * collection, and the neighbor is an active d1210 1 a1210 1 * Simply deleting the entry may affect default d1217 1 a1217 1 if (ln->ln_expire > time_uptime) d1219 1 a1219 1 (ln->ln_expire - time_uptime) * hz); d1222 1 d1227 17 a1243 1 ND6_WLOCK(); d1245 6 a1250 15 /* * We need to unlock to avoid a LOR with nd6_rt_flush() * with the rnh and for the calls to * nd6_pfxlist_onlink_check() and nd6_defrouter_select() in the * block further down for calls into nd6_lookup(). * We still hold a ref. * * Temporarily fake the state to choose a new default * router and to perform on-link determination of * prefixes correctly. * Below the state will be set correctly, * or the entry itself will be deleted. */ ln->ln_state = ND6_LLINFO_INCOMPLETE; LLE_WUNLOCK(ln); d1252 8 a1259 6 /* * nd6_rt_flush must be called whether or not the neighbor * is in the Default Router List. * See a corresponding comment in nd6_na_input(). */ nd6_rt_flush(in6, ifp); d1261 7 a1267 11 /* * Unreachablity of a router might affect the default * router selection and on-link detection of advertised * prefixes. * * Since nd6_defrouter_select() does not affect the * on-link determination and MIP6 needs the check * before the default router selection, we perform * the check now. */ nd6_pfxlist_onlink_check(); d1269 5 a1273 4 /* * refresh default router list */ nd6_defrouter_select(); a1282 1 a1283 6 LLE_WLOCK(ln); } if (ln->la_flags & LLE_VALID || gc) { struct sockaddr_in6 sin6; const char *lladdr; d1285 2 a1286 4 sockaddr_in6_init(&sin6, in6, 0, 0, 0); lladdr = ln->la_flags & LLE_VALID ? (const char *)&ln->ll_addr : NULL; rt_clonedmsg(RTM_DELETE, NULL, sin6tosa(&sin6), lladdr, ifp); d1946 1 a1946 2 KASSERTMSG(pfx->ndpr_refcnt == 0, "ndpr_refcnt=%d", pfx->ndpr_refcnt); d2221 5 a2225 7 if (do_update && lladdr != NULL) { struct sockaddr_in6 sin6; sockaddr_in6_init(&sin6, from, 0, 0, 0); rt_clonedmsg(is_newentry ? RTM_ADD : RTM_CHANGE, NULL, sin6tosa(&sin6), lladdr, ifp); } a2304 1 int error; d2322 2 a2323 2 if (ln != NULL && (ln->la_flags & LLE_VALID) != 0 && ln->ln_state == ND6_LLINFO_REACHABLE) { d2335 1 d2351 4 a2385 12 * If the neighbor cache entry has a state other than INCOMPLETE * (i.e. its link-layer address is already resolved), just * send the packet. */ if (ln->ln_state > ND6_LLINFO_INCOMPLETE) { KASSERT((ln->la_flags & LLE_VALID) != 0); memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); LLE_WUNLOCK(ln); return 0; } /* d2392 1 a2392 2 if (ln->ln_state == ND6_LLINFO_NOSTATE || ln->ln_state == ND6_LLINFO_WAITDELETE) a2415 6 if (ln->ln_asked >= nd6_mmaxtries) error = (rt != NULL && rt->rt_flags & RTF_GATEWAY) ? EHOSTUNREACH : EHOSTDOWN; else error = EWOULDBLOCK; d2427 1 d2429 2 a2430 1 } else d2432 1 d2437 1 a2437 1 return error; d2445 1 a2445 1 * other than ARCnet, Ethernet, and GIF. d2453 1 @ 1.249.2.3 log @Sync with HEAD @ text @d461 1 d465 1 a466 1 bool missed = false; a495 3 missed = true; sockaddr_in6_init(&tsin6, taddr6, 0, 0, 0); d511 9 d589 3 a591 13 if (missed) { struct in6_addr mdaddr6 = zeroin6_addr; struct sockaddr *sa; if (m != NULL) icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, ifp, &mdaddr6); if (!IN6_IS_ADDR_UNSPECIFIED(&mdaddr6)) { sockaddr_in6_init(&dsin6, &mdaddr6, 0, 0, 0); sa = sin6tosa(&dsin6); } else sa = NULL; rt_clonedmsg(RTM_MISS, sa, sin6tosa(&tsin6), NULL, ifp); @ 1.248 log @Remove now unused net_osdep.h includes, the other BSDs did the same. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.247 2018/03/06 10:57:00 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.247 2018/03/06 10:57:00 roy Exp $"); a1608 1 struct in6_multi *in6m; d1615 2 a1616 5 if (in6_setscope(&llsol, ifp, NULL) == 0) { in6m = in6_lookup_multi(&llsol, ifp); if (in6m) in6_delmulti(in6m); } @ 1.247 log @nd6: add a nonce to DaD probes in-case they are looped back to us This implements RFC 7527, based a similar change in FreeBSD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.246 2018/03/06 07:24:01 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.246 2018/03/06 07:24:01 ozaki-r Exp $"); a78 2 #include @ 1.246 log @Fix reference leaks of llentry callout_reset and callout_halt can cancel a pending callout without telling us. Detect a cancel and remove a reference by using callout_pending and callout_stop (it's a bit tricy though, we can detect it). While here, we can remove remaining abuses of mutex_owned for softnet_lock. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.245 2018/01/29 19:51:15 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.245 2018/01/29 19:51:15 christos Exp $"); d350 1 d558 1 a558 1 nd6_ns_output(ifp, daddr6, taddr6, psrc, 0); d2424 1 a2424 1 nd6_ns_output(ifp, NULL, &dst->sin6_addr, psrc, 0); @ 1.245 log @more cleanup (don't allow oldlenp == NULL) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.244 2018/01/29 03:42:53 pgoyette Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.244 2018/01/29 03:42:53 pgoyette Exp $"); d405 13 d467 1 a475 19 if (callout_pending(&ln->la_timer)) { /* * Here we are a bit odd here in the treatment of * active/pending. If the pending bit is set, it got * rescheduled before I ran. The active * bit we ignore, since if it was stopped * in ll_tablefree() and was currently running * it would have return 0 so the code would * not have deleted it since the callout could * not be stopped so we want to go through * with the delete here now. If the callout * was restarted, the pending bit will be back on and * we just want to bail since the callout_reset would * return 1 and our reference would have been removed * by nd6_llinfo_settimer above since canceled * would have been 1. */ goto out; } a477 1 @ 1.245.2.1 log @Synch with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.247 2018/03/06 10:57:00 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.247 2018/03/06 10:57:00 roy Exp $"); a349 1 case ND_OPT_NONCE: a404 13 /* * We have to take care of a reference leak which occurs if * callout_reset overwrites a pending callout schedule. Unfortunately * we don't have a mean to know the overwrite, so we need to know it * using callout_stop. We need to call callout_pending first to exclude * the case that the callout has never been scheduled. */ if (callout_pending(&ln->la_timer)) { bool expired = callout_stop(&ln->la_timer); if (!expired) LLE_REMREF(ln); } a453 1 d462 19 d483 1 d563 1 a563 1 nd6_ns_output(ifp, daddr6, taddr6, psrc, NULL); d2429 1 a2429 1 nd6_ns_output(ifp, NULL, &dst->sin6_addr, psrc, NULL); @ 1.245.2.2 log @Synch with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.248 2018/05/01 07:21:39 maxv Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.248 2018/05/01 07:21:39 maxv Exp $"); d79 2 @ 1.245.2.3 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.249 2018/05/29 04:38:29 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.249 2018/05/29 04:38:29 ozaki-r Exp $"); d1609 1 d1616 5 a1620 2 if (in6_setscope(&llsol, ifp, NULL) == 0) in6_lookup_and_delete_multi(&llsol, ifp); @ 1.245.2.4 log @Sync with HEAD Resolve a couple of conflicts (result of the uimin/uimax changes) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.250 2018/09/03 16:29:36 riastradh Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.250 2018/09/03 16:29:36 riastradh Exp $"); d2513 1 a2513 1 ol = *oldlenp = uimin(ol, *oldlenp); @ 1.245.2.5 log @Sync with HEAD, resolve a couple of conflicts @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.251 2018/10/30 05:54:41 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.251 2018/10/30 05:54:41 ozaki-r Exp $"); d1569 1 a1569 2 if (!ISSET(info->rti_flags, RTF_DONTCHANGEIFA) && ifa != rt->rt_ifa) @ 1.245.2.6 log @Sync with HEAD, resolve a few conflicts @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); a1886 4 /* Only flush prefixes for the given interface. */ if (ifp != lo0ifp && ifp != pfx->ndpr_ifp) continue; a1955 2 #if 0 /* XXX Is this really needed? */ a1956 1 #endif a1957 4 /* Only flush routers for the given interface. */ if (ifp != lo0ifp && ifp != drtr->ifp) continue; @ 1.244 log @One more from christos@@ No need to initialize fill_func @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.243 2018/01/29 03:35:23 pgoyette Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.243 2018/01/29 03:35:23 pgoyette Exp $"); a2489 4 void *p; size_t ol; int error; size_t bufsize = 0; a2491 2 error = 0; a2493 5 if (oldp && !oldlenp) return EINVAL; ol = oldlenp ? *oldlenp : 0; p = NULL; d2511 11 a2521 9 error = (*fill_func)(p, oldlenp); /* calc len needed */ if (error == 0 && oldp && *oldlenp > 0 ) { p = kmem_alloc(*oldlenp, KM_SLEEP); bufsize = *oldlenp; error = (*fill_func)(p, oldlenp); if (!error && oldp != NULL) error = copyout(p, oldp, min(ol, *oldlenp)); if (*oldlenp > ol) error = ENOMEM; d2523 10 a2532 2 if (p) kmem_free(p, bufsize); d2577 1 a2577 2 if (oldlenp) *oldlenp = l; /* (void *)d - (void *)oldp */ d2679 1 a2679 2 if (oldlenp) *oldlenp = l; @ 1.243 log @More simplification, this time from ozaki-r@@ No need to break after return. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.242 2018/01/29 03:29:26 pgoyette Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.242 2018/01/29 03:29:26 pgoyette Exp $"); a2505 2 fill_func = NULL; @ 1.242 log @Simplify, from christos@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.241 2018/01/29 02:02:14 pgoyette Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.241 2018/01/29 02:02:14 pgoyette Exp $"); a2518 1 break; a2521 1 break; @ 1.241 log @Use existing fill_[pd]rlist() functions to calculate size of buffer to allocate, rather than relying on an arbitrary length passed in from userland. Allow copyout() of partial results if the user buffer is too small, to be consistent with the way sysctl(3) is documented. Garbage-collect now-unused third parrameter in the fill_[pd]rlist() functions. As discussed on IRC. OK kamil@@ and christos@@ XXX Needs pull-up to netbsd-8 branch. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.240 2017/12/15 04:03:46 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.240 2017/12/15 04:03:46 ozaki-r Exp $"); d2518 1 d2522 1 a2522 1 error = ENOPROTOOPT; d2526 9 a2534 11 if (fill_func) { error = (*fill_func)(p, oldlenp); /* calc len needed */ if (error == 0 && oldp && *oldlenp > 0 ) { p = kmem_alloc(*oldlenp, KM_SLEEP); bufsize = *oldlenp; error = (*fill_func)(p, oldlenp); if (!error && oldp != NULL) error = copyout(p, oldp, min(ol, *oldlenp)); if (*oldlenp > ol) error = ENOMEM; } @ 1.240 log @Ensure to call if_mcast_op with holding IFNET_LOCK Note that CARP doesn't deal with IFNET_LOCK yet. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.239 2017/11/17 07:37:12 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.239 2017/11/17 07:37:12 ozaki-r Exp $"); d127 2 a128 2 static int fill_drlist(void *, size_t *, size_t); static int fill_prlist(void *, size_t *, size_t); d2494 1 d2504 4 a2507 5 if (oldp && *oldlenp > 0) { p = kmem_alloc(*oldlenp, KM_SLEEP); bufsize = *oldlenp; } else p = NULL; d2510 1 a2510 3 error = fill_drlist(p, oldlenp, ol); if (!error && p != NULL && oldp != NULL) error = copyout(p, oldp, *oldlenp); d2514 1 a2514 3 error = fill_prlist(p, oldlenp, ol); if (!error && p != NULL && oldp != NULL) error = copyout(p, oldp, *oldlenp); d2524 13 d2544 1 a2544 1 fill_drlist(void *oldp, size_t *oldlenp, size_t ol) a2582 4 if (oldp) { if (l > ol) error = ENOMEM; } d2590 1 a2590 1 fill_prlist(void *oldp, size_t *oldlenp, size_t ol) d2686 1 a2686 5 if (oldp) { *oldlenp = l; /* (void *)d - (void *)oldp */ if (l > ol) error = ENOMEM; } else @ 1.239 log @Provide macros for softnet_lock and KERNEL_LOCK hiding NET_MPSAFE switch It reduces C&P codes such as "#ifndef NET_MPSAFE KERNEL_LOCK(1, NULL); ..." scattered all over the source code and makes it easy to identify remaining KERNEL_LOCK and/or softnet_lock that are held even if NET_MPSAFE. No functional change @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.238 2017/11/10 07:25:39 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.238 2017/11/10 07:25:39 ozaki-r Exp $"); d617 1 d631 1 d634 1 d637 16 a652 2 ia6_release(ia6, &psref); in6_purgeaddr(&ia6->ia_ifa); d654 1 d1904 4 d1914 13 a1926 5 if (ia->ia6_ndpr == pfx) { pserialize_read_exit(_s); ND6_UNLOCK(); /* XXX NOMPSAFE? */ /* in6_purgeaddr may destroy pfx. */ d1928 1 d1931 20 @ 1.238 log @Use psref instead of pserialize because that code is sleepable @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.237 2017/11/10 07:24:28 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.237 2017/11/10 07:24:28 ozaki-r Exp $"); d453 1 a453 4 #ifndef NET_MPSAFE mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); #endif d569 1 a569 4 #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); #endif d587 1 a587 4 #ifndef NET_MPSAFE mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); #endif d711 1 a711 4 #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); #endif d2219 1 a2219 4 #ifndef NET_MPSAFE mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); #endif d2240 1 a2240 4 #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); #endif @ 1.237 log @Fix a deadlock between a route update and lltable It happens because rtalloc1 is called from lltable with holding IF_AFDATA_WLOCK. If a route update is in action, rtalloc1 would wait for its completion with holding IF_AFDATA_WLOCK. At the same moment, a softint (e.g., arpintr) may try to take IF_AFDATA_WLOCK and get stuck on it. Unfortunately the stuck softint prevents the route update from progressing because the route update calls psref_target_destroy that needs the softint to complete. A resource allocation graph of the senario looks like this: route update =(psref_target_destroy)=> softint => IF_AFDATA_WLOCK =(rt_update_wait)=> route update Fix the deadlock by pulling rtalloc1 out of the lltable codes inside IF_AFDATA_WLOCK. Note that the deadlock happens only if NET_MPSAFE is enabled. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.236 2017/10/05 03:42:14 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.236 2017/10/05 03:42:14 ozaki-r Exp $"); d1449 1 a1449 1 int s; d1557 2 a1558 3 s = pserialize_read_enter(); ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &satocsin6(rt_getkey(rt))->sin6_addr); d1595 1 a1595 1 pserialize_read_exit(s); @ 1.236 log @Add missing NULL check PR kern/52554 @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.235 2017/06/22 09:24:02 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.235 2017/06/22 09:24:02 ozaki-r Exp $"); d953 1 d956 1 d959 1 a959 2 ln = lla_create(LLTABLE6(ifp), LLE_EXCLUSIVE, sin6tosa(&sin6)); d962 2 @ 1.235 log @Remove unused function (nd6_rem_ifa_lle) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.234 2017/06/21 09:05:31 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.234 2017/06/21 09:05:31 ozaki-r Exp $"); d2324 5 @ 1.234 log @Don't create a permanent L2 cache entry on adding an address to an interface It was created to copy FreeBSD, however actually the cache isn't necessary. Remove it to simplify the code and reduce the cost to maintain it (e.g., keep a consistency with a corresponding local route). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.233 2017/06/16 02:24:54 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.233 2017/06/16 02:24:54 ozaki-r Exp $"); a2425 18 /* * Removes ALL lle records for interface address prefix. * XXXME: That's probably not we really want to do, we need * to remove address record only and keep other records * until we determine if given prefix is really going * to be removed. */ void nd6_rem_ifa_lle(struct in6_ifaddr *ia) { struct sockaddr_in6 mask, addr; memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); lltable_prefix_free(AF_INET6, sin6tosa(&addr), sin6tosa(&mask), LLE_STATIC); } @ 1.233 log @Sending a routing message (RTM_ADD) on adding an llentry A message used to be sent on adding a cloned route. Restore the behavior for backward compatibility. Requested by ryo@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232 2017/06/01 02:45:14 chs Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232 2017/06/01 02:45:14 chs Exp $"); a2426 37 * Add pernament ND6 link-layer record for given * interface address. * * Very similar to IPv4 arp_ifinit(), but: * 1) IPv6 DAD is performed in different place * 2) It is called by IPv6 protocol stack in contrast to * arp_ifinit() which is typically called in SIOCSIFADDR * driver ioctl handler. * */ int nd6_add_ifa_lle(struct in6_ifaddr *ia) { struct ifnet *ifp; struct llentry *ln; ifp = ia->ia_ifa.ifa_ifp; if (nd6_need_cache(ifp) == 0) return 0; ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; ia->ia_ifa.ifa_flags |= RTF_CONNECTED; IF_AFDATA_WLOCK(ifp); ln = lla_create(LLTABLE6(ifp), LLE_IFADDR | LLE_EXCLUSIVE, sin6tosa(&ia->ia_addr)); IF_AFDATA_WUNLOCK(ifp); if (ln == NULL) return ENOBUFS; ln->la_expire = 0; /* for IPv6 this means permanent */ ln->ln_state = ND6_LLINFO_REACHABLE; LLE_WUNLOCK(ln); return 0; } /* @ 1.232 log @remove checks for failure after memory allocation calls that cannot fail: kmem_alloc() with KM_SLEEP kmem_zalloc() with KM_SLEEP percpu_alloc() pserialize_create() psref_class_create() all of these paths include an assertion that the allocation has not failed, so callers should not assert that again. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.231 2017/03/01 03:02:35 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.231 2017/03/01 03:02:35 ozaki-r Exp $"); d2301 1 d2317 4 @ 1.232.2.1 log @Pull up following revision(s) (requested by ozaki-r in ticket #107): usr.sbin/arp/arp.c: revision 1.56 sys/net/rtsock.c: revision 1.218 sys/net/if_llatbl.c: revision 1.20 usr.sbin/arp/arp.c: revision 1.57 sys/net/rtsock.c: revision 1.219 sys/net/if_llatbl.c: revision 1.21 usr.sbin/arp/arp.c: revision 1.58 tests/net/net_common.sh: revision 1.19 sys/netinet6/nd6.h: revision 1.84 sys/netinet6/nd6.h: revision 1.85 tests/net/arp/t_arp.sh: revision 1.23 sys/netinet6/in6.c: revision 1.246 tests/net/arp/t_arp.sh: revision 1.24 sys/netinet6/in6.c: revision 1.247 tests/net/arp/t_arp.sh: revision 1.25 sys/netinet6/in6.c: revision 1.248 tests/net/arp/t_arp.sh: revision 1.26 usr.sbin/ndp/ndp.c: revision 1.49 tests/net/arp/t_arp.sh: revision 1.27 tests/net/ndp/t_ndp.sh: revision 1.20 tests/net/arp/t_arp.sh: revision 1.28 tests/net/ndp/t_ndp.sh: revision 1.21 tests/net/arp/t_arp.sh: revision 1.29 tests/net/ndp/t_ndp.sh: revision 1.22 tests/net/ndp/t_ndp.sh: revision 1.23 tests/net/route/t_flags6.sh: revision 1.13 tests/net/ndp/t_ndp.sh: revision 1.24 tests/net/route/t_flags6.sh: revision 1.14 tests/net/ndp/t_ndp.sh: revision 1.25 tests/net/route/t_flags6.sh: revision 1.15 tests/net/ndp/t_ndp.sh: revision 1.26 sbin/route/rtutil.c: revision 1.9 tests/net/ndp/t_ndp.sh: revision 1.27 tests/net/ndp/t_ndp.sh: revision 1.28 tests/net/net/t_ipv6address.sh: revision 1.14 tests/net/ndp/t_ra.sh: revision 1.28 tests/net/ndp/t_ndp.sh: revision 1.29 sys/net/route.h: revision 1.113 tests/net/ndp/t_ra.sh: revision 1.29 sys/net/rtsock.c: revision 1.220 sys/net/rtsock.c: revision 1.221 sys/net/rtsock.c: revision 1.222 sys/net/rtsock.c: revision 1.223 tests/net/route/t_route.sh: revision 1.13 sys/net/rtsock.c: revision 1.224 sys/net/route.c: revision 1.196 sys/net/if_llatbl.c: revision 1.19 sys/net/route.c: revision 1.197 sbin/route/route.c: revision 1.156 tests/net/route/t_flags.sh: revision 1.16 tests/net/route/t_flags.sh: revision 1.17 usr.sbin/ndp/ndp.c: revision 1.50 tests/net/route/t_flags.sh: revision 1.18 sys/netinet/in.c: revision 1.204 tests/net/route/t_flags.sh: revision 1.19 sys/netinet/in.c: revision 1.205 tests/net/arp/t_arp.sh: revision 1.30 tests/net/arp/t_arp.sh: revision 1.31 sys/net/if_llatbl.h: revision 1.11 tests/net/arp/t_arp.sh: revision 1.32 sys/net/if_llatbl.h: revision 1.12 tests/net/arp/t_arp.sh: revision 1.33 sys/netinet6/nd6.c: revision 1.233 sys/netinet6/nd6.c: revision 1.234 sys/netinet/if_arp.c: revision 1.251 sys/netinet6/nd6.c: revision 1.235 sys/netinet/if_arp.c: revision 1.252 sbin/route/route.8: revision 1.57 sys/net/rtsock.c: revision 1.214 sys/net/rtsock.c: revision 1.215 sys/net/rtsock.c: revision 1.216 sys/net/rtsock.c: revision 1.217 whitespace police Simplify We can assume that rt_ifp is always non-NULL. Sending a routing message (RTM_ADD) on adding an llentry A message used to be sent on adding a cloned route. Restore the behavior for backward compatibility. Requested by ryo@@ Drop RTF_CONNECTED from a result of RTM_GET for ARP/NDP entries ARP/NDP entries aren't connected routes. Reported by ryo@@ Support -c option for route monitor route command exits if it receives routing messages where is a value specified by -c. The option is useful to get only particular message(s) in a test script. Test routing messages emitted on operations of ARP/NDP entries Do netstat -a for an appropriate protocol Add missing declarations for cleanup Set net.inet.arp.keep only if it's required Don't create a permanent L2 cache entry on adding an address to an interface It was created to copy FreeBSD, however actually the cache isn't necessary. Remove it to simplify the code and reduce the cost to maintain it (e.g., keep a consistency with a corresponding local route). Fix typo Fix in_lltable_match_prefix The function has not been used but will be used soon. Remove unused function (nd6_rem_ifa_lle) Allow in6_lltable_free_entry to be called without holding the afdata lock of ifp as well as in_lltable_free_entry This behavior is a bit odd and should be fixed in the future... Purge ARP/NDP entries on an interface when the interface is down Fix PR kern/51179 Purge all related L2 caches on removing a route The change addresses situations similar to PR 51179. Purge L2 caches on changing an interface of a route The change addresses situations similar to PR 51179. Test implicit removals of ARP/NDP entries One test case reproudces PR 51179. Fix build of kernels without both INET and INET6 Tweak lltable_sysctl_dumparp - Rename lltable_sysctl_dumparp to lltable_sysctl_dump because it's not only for ARP - Enable it not only for INET but also for INET6 Fix usage of routing messages on arp -d and ndp -d It didn't work as we expected; we should set RTA_GATEWAY not RTA_IFP on RTM_GET to return an if_index and the kernel should use it on RTM_DELETE. Improve backward compatibility of (fake) routing messages on adding an ARP/NDP entry A message originally included only DST and GATEWAY. Restore it. Fix ifdef; care about a case w/ INET6 and w/o INET Drop RTF_UP from a routing message of a deleted ARP/NDP entry Check existence of ARP/NDP entries Checking ARP/NDP entries is valid rather than checking routes. Fix wrong comment Drop RTF_LLINFO flag (now it's RTF_LLDATA) from local routes They don't have llinfo anymore. And also the change fixes unexpected behavior of ARP proxy. Restore ARP/NDP entries to route show and netstat -r Requested by dyoung@@ some time ago Enable to remove multiple ARP/NDP entries for one destination The kernel can have multiple ARP/NDP entries which have an indentical destination on different interfaces. This is normal and can be reproduce easily by ping -I or ping6 -S. We should be able to remove such entries. arp -d and ndp -d are changed to fetch all ARP/NDP entries and remove matched entries. So we can remove multiple entries described above. This fetch all and selective removal behavior is the same as arp and ndp ; they also do fetch all entries and show only matched entries. Related to PR 51179 Check if ARP/NDP entries are purged when a related route is deleted @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232 2017/06/01 02:45:14 chs Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232 2017/06/01 02:45:14 chs Exp $"); a2300 1 struct sockaddr_in6 sin6; a2315 4 sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); rt_clonedmsg(sin6tosa(&sin6), ifp, rt); d2421 55 @ 1.232.2.2 log @Pull up following revision(s) (requested by ozaki-r in ticket #307): sys/netinet6/nd6.c: revision 1.236 Add missing NULL check PR kern/52554 @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232.2.1 2017/07/07 13:57:26 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.1 2017/07/07 13:57:26 martin Exp $"); a2323 5 if (ln == NULL) { m_freem(m); return ENETDOWN; /* better error? */ } @ 1.232.2.3 log @Pull up following revision(s) (requested by ozaki-r in ticket #353): sys/net/if_llatbl.c: 1.22 sys/net/if_llatbl.h: 1.13 sys/netinet/if_arp.c: 1.254 sys/netinet/in.c: 1.208-1.209 sys/netinet6/in6.c: 1.249-1.250 sys/netinet6/nd6.c: 1.237 Remove redundant KASSERTMSG The function is static, has just one caller and the caller does the same check. -- Fix a deadlock between a route update and lltable It happens because rtalloc1 is called from lltable with holding IF_AFDATA_WLOCK. If a route update is in action, rtalloc1 would wait for its completion with holding IF_AFDATA_WLOCK. At the same moment, a softint (e.g., arpintr) may try to take IF_AFDATA_WLOCK and get stuck on it. Unfortunately the stuck softint prevents the route update from progressing because the route update calls psref_target_destroy that needs the softint to complete. A resource allocation graph of the senario looks like this: route update =(psref_target_destroy)=> softint => IF_AFDATA_WLOCK =(rt_update_wait)=> route update Fix the deadlock by pulling rtalloc1 out of the lltable codes inside IF_AFDATA_WLOCK. Note that the deadlock happens only if NET_MPSAFE is enabled. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232.2.2 2017/10/24 09:00:22 snj Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.2 2017/10/24 09:00:22 snj Exp $"); a952 1 struct rtentry *rt; a954 1 rt = rtalloc1(sin6tosa(&sin6), 0); d957 2 a958 1 ln = lla_create(LLTABLE6(ifp), LLE_EXCLUSIVE, sin6tosa(&sin6), rt); a960 2 if (rt != NULL) rt_unref(rt); @ 1.232.2.4 log @Pull up following revision(s) (requested by ozaki-r in ticket #354): sys/netinet6/in6_ifattach.c: revision 1.113 sys/netinet6/nd6.c: revision 1.238 Use psref instead of pserialize because that code is sleepable -- Use psref instead of pserialize because that code is sleepable @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232.2.3 2017/11/17 20:24:05 snj Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.3 2017/11/17 20:24:05 snj Exp $"); d1449 1 a1449 1 struct psref psref; d1557 3 a1559 2 ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &satocsin6(rt_getkey(rt))->sin6_addr, &psref); d1596 1 a1596 1 ifa_release(ifa, &psref); @ 1.232.2.5 log @Pull up following revision(s) (requested by ozaki-r in ticket #456): sys/arch/arm/sunxi/sunxi_emac.c: 1.9 sys/dev/ic/dwc_gmac.c: 1.43-1.44 sys/dev/pci/if_iwm.c: 1.75 sys/dev/pci/if_wm.c: 1.543 sys/dev/pci/ixgbe/ixgbe.c: 1.112 sys/dev/pci/ixgbe/ixv.c: 1.74 sys/kern/sys_socket.c: 1.75 sys/net/agr/if_agr.c: 1.43 sys/net/bpf.c: 1.219 sys/net/if.c: 1.397, 1.399, 1.401-1.403, 1.406-1.410, 1.412-1.416 sys/net/if.h: 1.242-1.247, 1.250, 1.252-1.257 sys/net/if_bridge.c: 1.140 via patch, 1.142-1.146 sys/net/if_etherip.c: 1.40 sys/net/if_ethersubr.c: 1.243, 1.246 sys/net/if_faith.c: 1.57 sys/net/if_gif.c: 1.132 sys/net/if_l2tp.c: 1.15, 1.17 sys/net/if_loop.c: 1.98-1.101 sys/net/if_media.c: 1.35 sys/net/if_pppoe.c: 1.131-1.132 sys/net/if_spppsubr.c: 1.176-1.177 sys/net/if_tun.c: 1.142 sys/net/if_vlan.c: 1.107, 1.109, 1.114-1.121 sys/net/npf/npf_ifaddr.c: 1.3 sys/net/npf/npf_os.c: 1.8-1.9 sys/net/rtsock.c: 1.230 sys/netcan/if_canloop.c: 1.3-1.5 sys/netinet/if_arp.c: 1.255 sys/netinet/igmp.c: 1.65 sys/netinet/in.c: 1.210-1.211 sys/netinet/in_pcb.c: 1.180 sys/netinet/ip_carp.c: 1.92, 1.94 sys/netinet/ip_flow.c: 1.81 sys/netinet/ip_input.c: 1.362 sys/netinet/ip_mroute.c: 1.147 sys/netinet/ip_output.c: 1.283, 1.285, 1.287 sys/netinet6/frag6.c: 1.61 sys/netinet6/in6.c: 1.251, 1.255 sys/netinet6/in6_pcb.c: 1.162 sys/netinet6/ip6_flow.c: 1.35 sys/netinet6/ip6_input.c: 1.183 sys/netinet6/ip6_output.c: 1.196 sys/netinet6/mld6.c: 1.90 sys/netinet6/nd6.c: 1.239-1.240 sys/netinet6/nd6_nbr.c: 1.139 sys/netinet6/nd6_rtr.c: 1.136 sys/netipsec/ipsec_output.c: 1.65 sys/rump/net/lib/libnetinet/netinet_component.c: 1.9-1.10 kmem_intr_free kmem_intr_[z]alloced memory the underlying pools are the same but api-wise those should match Unify IFEF_*_MPSAFE into IFEF_MPSAFE There are already two flags for if_output and if_start, however, it seems such MPSAFE flags are eventually needed for all if_XXX operations. Having discrete flags for each operation is wasteful of if_extflags bits. So let's unify the flags into one: IFEF_MPSAFE. Fortunately IFEF_*_MPSAFE flags have never been included in any releases, so we can change them without breaking backward compatibility of the releases (though the kernel version of -current should be bumped). Note that if an interface have both MP-safe and non-MP-safe operations at a time, we have to set the IFEF_MPSAFE flag and let callees of non-MP-safe opeartions take the kernel lock. Proposed on tech-kern@@ and tech-net@@ Provide macros for softnet_lock and KERNEL_LOCK hiding NET_MPSAFE switch It reduces C&P codes such as "#ifndef NET_MPSAFE KERNEL_LOCK(1, NULL); ..." scattered all over the source code and makes it easy to identify remaining KERNEL_LOCK and/or softnet_lock that are held even if NET_MPSAFE. No functional change Hold KERNEL_LOCK on if_ioctl selectively based on IFEF_MPSAFE If IFEF_MPSAFE is set, hold the lock and otherwise don't hold. This change requires additions of KERNEL_LOCK to subsequence functions from if_ioctl such as ifmedia_ioctl and ifioctl_common to protect non-MP-safe components. Proposed on tech-kern@@ and tech-net@@ Ensure to hold if_ioctl_lock when calling if_flags_set Fix locking against myself on ifpromisc vlan_unconfig_locked could be called with holding if_ioctl_lock. Ensure to not turn on IFF_RUNNING of an interface until its initialization completes And ensure to turn off it before destruction as per IFF_RUNNING's description "resource allocated". (The description is a bit doubtful though, I believe the change is still proper.) Ensure to hold if_ioctl_lock on if_up and if_down One exception for if_down is if_detach; in the case the lock isn't needed because it's guaranteed that no other one can access ifp at that point. Make if_link_queue MP-safe if IFEF_MPSAFE if_link_queue is a queue to store events of link state changes, which is used to pass events from (typically) an interrupt handler to if_link_state_change softint. The queue was protected by KERNEL_LOCK so far, but if IFEF_MPSAFE is enabled, it becomes unsafe because (perhaps) an interrupt handler of an interface with IFEF_MPSAFE doesn't take KERNEL_LOCK. Protect it by a spin mutex. Additionally with this change KERNEL_LOCK of if_link_state_change softint is omitted if NET_MPSAFE is enabled. Note that the spin mutex is now ifp->if_snd.ifq_lock as well as the case of if_timer (see the comment). Use IFADDR_WRITER_FOREACH instead of IFADDR_READER_FOREACH At that point no other one modifies the list so IFADDR_READER_FOREACH is unnecessary. Use of IFADDR_READER_FOREACH is harmless in general though, if we try to detect contract violations of pserialize, using it violates the contract. So avoid using it makes life easy. Ensure to call if_addr_init with holding if_ioctl_lock Get rid of outdated comments Fix build of kernels without ether By throwing out if_enable_vlan_mtu and if_disable_vlan_mtu that created a unnecessary dependency from if.c to if_ethersubr.c. PR kern/52790 Rename IFNET_LOCK to IFNET_GLOBAL_LOCK IFNET_LOCK will be used in another lock, if_ioctl_lock (might be renamed then). Wrap if_ioctl_lock with IFNET_* macros (NFC) Also if_ioctl_lock perhaps needs to be renamed to something because it's now not just for ioctl... Reorder some destruction routines in if_detach - Destroy if_ioctl_lock at the end of the if_detach because it's used in various destruction routines - Move psref_target_destroy after pr_purgeif because we want to use psref in pr_purgeif (otherwise destruction procedures can be tricky) Ensure to call if_mcast_op with holding IFNET_LOCK Note that CARP doesn't deal with IFNET_LOCK yet. Remove IFNET_GLOBAL_LOCK where it's unnecessary because IFNET_LOCK is held Describe which lock is used to protect each member variable of struct ifnet Requested by skrll@@ Write a guideline for converting an interface to IFEF_MPSAFE Requested by skrll@@ Note that IFNET_LOCK must not be held in softint Don't set IFEF_MPSAFE unless NET_MPSAFE at this point Because recent investigations show that interfaces with IFEF_MPSAFE need to follow additional restrictions to work with the flag safely. We should enable it on an interface by default only if the interface surely satisfies the restrictions, which are described in if.h. Note that enabling IFEF_MPSAFE solely gains a few benefit on performance because the network stack is still serialized by the big kernel locks by default. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232.2.4 2017/11/17 20:26:19 snj Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.4 2017/11/17 20:26:19 snj Exp $"); d453 4 a456 1 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); d572 4 a575 1 SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); d593 4 a596 1 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); a625 1 struct ifnet *ifp; a638 1 IFNET_LOCK(ia6->ia_ifa.ifa_ifp); a640 1 IFNET_UNLOCK(ia6->ia_ifa.ifa_ifp); d643 2 a644 16 ifp = ia6->ia_ifa.ifa_ifp; IFNET_LOCK(ifp); /* * Need to take the lock first to prevent if_detach * from running in6_purgeaddr concurrently. */ if (!if_is_deactivated(ifp)) { ia6_release(ia6, &psref); in6_purgeaddr(&ia6->ia_ifa); } else { /* * ifp is being destroyed, ia6 will be destroyed * by if_detach. */ ia6_release(ia6, &psref); } a645 1 IFNET_UNLOCK(ifp); d720 4 a723 1 SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); a1897 4 struct ifnet *ifa_ifp; int bound; struct psref psref; d1904 5 a1908 13 if (ia->ia6_ndpr != pfx) continue; bound = curlwp_bind(); ia6_acquire(ia, &psref); pserialize_read_exit(_s); ND6_UNLOCK(); ifa_ifp = ia->ia_ifa.ifa_ifp; if (ifa_ifp == ifp) { /* Already have IFNET_LOCK(ifp) */ KASSERT(!if_is_deactivated(ifp)); ia6_release(ia, &psref); a1909 1 curlwp_bindx(bound); a1911 20 IFNET_LOCK(ifa_ifp); /* * Need to take the lock first to prevent * if_detach from running in6_purgeaddr * concurrently. */ if (!if_is_deactivated(ifa_ifp)) { ia6_release(ia, &psref); in6_purgeaddr(&ia->ia_ifa); } else { /* * ifp is being destroyed, ia will be * destroyed by if_detach. */ ia6_release(ia, &psref); /* XXX may cause busy loop */ } IFNET_UNLOCK(ifa_ifp); curlwp_bindx(bound); goto restart; d2231 4 a2234 1 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); d2255 4 a2258 1 SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); @ 1.232.2.6 log @Pull up following revision(s) (requested by ozaki-r in ticket #528): sys/net/agr/if_agr.c: revision 1.42 sys/netinet6/nd6_rtr.c: revision 1.137 sys/netinet6/nd6_rtr.c: revision 1.138 sys/net/agr/if_agr.c: revision 1.46 sys/net/route.c: revision 1.206 sys/net/if.c: revision 1.419 sys/net/agr/if_agrether.c: revision 1.10 sys/netinet6/nd6.c: revision 1.241 sys/netinet6/nd6.c: revision 1.242 sys/netinet6/nd6.c: revision 1.243 sys/netinet6/nd6.c: revision 1.244 sys/netinet6/nd6.c: revision 1.245 sys/netipsec/ipsec_input.c: revision 1.52 sys/netipsec/ipsec_input.c: revision 1.53 sys/net/agr/if_agrsubr.h: revision 1.5 sys/kern/subr_workqueue.c: revision 1.35 sys/netipsec/ipsec.c: revision 1.124 sys/net/agr/if_agrsubr.c: revision 1.11 sys/net/agr/if_agrsubr.c: revision 1.12 Simplify; share agr_vlan_add and agr_vlan_del (NFCI) Fix late NULL-checking (CID 1427782: Null pointer dereferences (REVERSE_INULL)) KNF: replace soft tabs with hard tabs Add missing NULL-checking for m_pullup (CID 1427770: Null pointer dereferences (NULL_RETURNS)) Add locking. Revert "Get rid of unnecessary splsoftnet" (v1.133) It's not always true that softnet_lock is held these places. See PR kern/52947. Get rid of unnecessary splsoftnet (redo) Unless NET_MPSAFE, splsoftnet is still needed for rt_* functions. Use existing fill_[pd]rlist() functions to calculate size of buffer to allocate, rather than relying on an arbitrary length passed in from userland. Allow copyout() of partial results if the user buffer is too small, to be consistent with the way sysctl(3) is documented. Garbage-collect now-unused third parrameter in the fill_[pd]rlist() functions. As discussed on IRC. OK kamil@@ and christos@@ XXX Needs pull-up to netbsd-8 branch. Simplify, from christos@@ More simplification, this time from ozaki-r@@ No need to break after return. One more from christos@@ No need to initialize fill_func more cleanup (don't allow oldlenp == NULL) Destroy ifq_lock at the end of if_detach It still can be used in if_detach. Prevent rt_free_global.wk from being enqueued to workqueue doubly Check if a queued work is tried to be enqueued again, which is not allowed @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232.2.5 2018/01/02 10:20:34 snj Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.5 2018/01/02 10:20:34 snj Exp $"); d127 2 a128 2 static int fill_drlist(void *, size_t *); static int fill_prlist(void *, size_t *); d2490 6 a2495 1 int (*fill_func)(void *, size_t *); d2499 3 d2503 5 d2510 3 a2512 1 fill_func = fill_drlist; d2516 3 a2518 1 fill_func = fill_prlist; d2522 1 a2522 1 return 0; d2525 2 a2526 1 return ENOPROTOOPT; d2528 2 a2529 23 if (oldlenp == NULL) return EINVAL; size_t ol; int error = (*fill_func)(NULL, &ol); /* calc len needed */ if (error) return error; if (oldp == NULL) { *oldlenp = ol; return 0; } ol = *oldlenp = min(ol, *oldlenp); if (ol == 0) return 0; void *p = kmem_alloc(ol, KM_SLEEP); error = (*fill_func)(p, oldlenp); if (!error) error = copyout(p, oldp, *oldlenp); kmem_free(p, ol); d2535 1 a2535 1 fill_drlist(void *oldp, size_t *oldlenp) d2574 6 a2579 1 *oldlenp = l; /* (void *)d - (void *)oldp */ d2585 1 a2585 1 fill_prlist(void *oldp, size_t *oldlenp) d2681 6 a2686 1 *oldlenp = l; @ 1.232.2.7 log @Pull up following revision(s) (requested by ozaki-r in ticket #622): sys/netinet/if_arp.c: revision 1.270 sys/net/if_llatbl.c: revision 1.24 (patch) sys/net/if_llatbl.c: revision 1.25 sys/net/if_llatbl.c: revision 1.26 sys/net/route.c: revision 1.204 sys/netinet6/in6.c: revision 1.261 sys/netinet6/in6.c: revision 1.262 (patch) sys/netinet6/in6.c: revision 1.263 sys/netinet/in.c: revision 1.216 sys/netinet6/in6.c: revision 1.264 sys/netinet6/nd6.c: revision 1.246 (patch) sys/netinet/if_arp.c: revision 1.269 sys/net/if_llatbl.h: revision 1.14 sys/netinet6/in6.c: revision 1.259 sys/netinet/in.c: revision 1.220 sys/netinet/in.c: revision 1.221 (patch) sys/netinet/in.c: revision 1.222 sys/netinet/in.c: revision 1.223 Suppress noisy debugging outputs Even if DEBUG they are too noisy under load. Tweak sanity checks Scheduling a timer of static entries is wrong. Add assertions We must not destroy llentries holding mbufs. Fix reference leaks of llentry callout_reset and callout_halt can cancel a pending callout without telling us. Detect a cancel and remove a reference by using callout_pending and callout_stop (it's a bit tricy though, we can detect it). While here, we can remove remaining abuses of mutex_owned for softnet_lock. Fix memory leaks on arp -d and ndp -d for static entries We have to delete entries on in_lltable_delete and in6_lltable_delete unconditionally. Note that we don't need to worry about LLE_IFADDR because there is no such entries now. Use pool(9) for llentry allocations llentry is easy to be leaked and pool suits for it because pool is usable to detect leaks. Also sweep unnecessary wrappers for llentry, in_llentry and in6_llentry. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232.2.6 2018/02/05 14:55:16 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.6 2018/02/05 14:55:16 martin Exp $"); a404 13 /* * We have to take care of a reference leak which occurs if * callout_reset overwrites a pending callout schedule. Unfortunately * we don't have a mean to know the overwrite, so we need to know it * using callout_stop. We need to call callout_pending first to exclude * the case that the callout has never been scheduled. */ if (callout_pending(&ln->la_timer)) { bool expired = callout_stop(&ln->la_timer); if (!expired) LLE_REMREF(ln); } a453 1 d462 19 d483 1 @ 1.232.2.8 log @Pull up following revision(s) (requested by ozaki-r in ticket #842): sys/netinet6/mld6.c: revision 1.93-1.99 sys/netinet6/in6_var.h: revision 1.99,1.100 sys/netinet6/in6.c: revision 1.267,1.268 sys/netinet6/nd6.c: revision 1.249 Don't hold softnet_lock in mld_timeo Then we can get rid of remaining abuses of mutex_owned(softnet_lock). Release in6_multilock on callout_halt of mld_timeo to avoid a deadlock Improve atomicity of in6_leavegroup and in6_delmulti Avoid NULL pointer dereference on imm->i6mm_maddr Make a refcount decrement and a removal from a list of an item atomic in6m_refcount of an in6m can be incremented if the in6m is on the list (if_multiaddrs) in in6_addmulti or mld_input. So we must avoid such an increment when we try to destroy an in6m. To this end we must make an in6m_refcount decrement and a removal of an in6m from if_multiaddrs atomic. Make a deletion of in6m in nd6_rtrequest atomic Move LIST_REMOVE mld_stoptimer releases in6_multilock temporarily, so we must LIST_REMOVE first. Avoid double LIST_REMOVE which corrupts lists Mark in6m as used for non-DIAGNOSTIC builds. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232.2.7 2018/03/13 13:27:10 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.7 2018/03/13 13:27:10 martin Exp $"); d1610 1 d1617 5 a1621 2 if (in6_setscope(&llsol, ifp, NULL) == 0) in6_lookup_and_delete_multi(&llsol, ifp); @ 1.232.2.9 log @Pull up following revision(s) (requested by ozaki-r in ticket #1080): sys/netinet6/nd6.c: revision 1.251 sys/netinet/if_arp.c: revision 1.276 sys/net/if.c: revision 1.438 sys/net/if.c: revision 1.439 sys/net/route.c: revision 1.214 sys/net/route.c: revision 1.215 sys/net/route.c: revision 1.216 sys/netinet6/in6.c: revision 1.270 sys/net/route.h: revision 1.120 sys/net/if.c: revision 1.440 Remove a wrong assertion in ifaref - Doing ifref on an ifa with IFA_DESTROYING is not a problem; the reference should be dropped during the destruction of the ifa. - Use atomic operations for ifa_refcnt - Avoid a dangling pointer during rt_replace_ifa - Avoid double rt_replace_ifa on rtrequest1(RTM_ADD) Some callers of rtrequest1(RTM_ADD) adjust rt_ifa of an rtentry created by rtrequest1 that may change rt_ifa (in ifa_rtrequest) with another ifa that is different from requested one. It's wasteful and even worse introduces a race condition. rtrequest1 should just use a passed ifa as is if a caller hopes so. - Use rt_update framework on updating a rtentry @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232.2.8 2018/06/07 17:48:31 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.8 2018/06/07 17:48:31 martin Exp $"); d1570 1 a1570 2 if (!ISSET(info->rti_flags, RTF_DONTCHANGEIFA) && ifa != rt->rt_ifa) @ 1.232.2.10 log @Pull up following revision(s) (requested by ozaki-r in ticket #1285): sys/netinet6/nd6.c: revision 1.255 tests/net/ndp/t_ndp.sh: revision 1.32 nd6: restore a missing reachability confirmation On sending a packet over a STALE cache, the cache should be tried a reachability confirmation, which is described in RFC 2461/4861 7.3.3. On the fast path in nd6_resolve, however, the treatment for STALE caches has been skipped accidentally. So STALE caches never be back to the REACHABLE state. To fix the issue, branch to the fast path only when the cache entry is the REACHABLE state and leave other caches to the slow path that includes the treatment. To this end we need to allow to return a link-layer address if a valid address is available on the slow path too, which is the same behavior as FreeBSD and OpenBSD. tests: test state transitions of neighbor caches @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232.2.9 2018/11/06 14:38:58 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.9 2018/11/06 14:38:58 martin Exp $"); d2314 2 a2315 2 if (ln != NULL && (ln->la_flags & LLE_VALID) != 0 && ln->ln_state == ND6_LLINFO_REACHABLE) { a2377 12 * If the neighbor cache entry has a state other than INCOMPLETE * (i.e. its link-layer address is already resolved), just * send the packet. */ if (ln->ln_state > ND6_LLINFO_INCOMPLETE) { KASSERT((ln->la_flags & LLE_VALID) != 0); memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); LLE_WUNLOCK(ln); return 0; } /* @ 1.232.2.11 log @Pull up following revision(s) (requested by christos in ticket #1307): sys/netinet6/nd6.c: revision 1.256 Decrease the reference count before freeing, so that the entries actually get free'd. (Ryota Ozaki) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232.2.10 2019/07/08 16:30:58 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.10 2019/07/08 16:30:58 martin Exp $"); a500 1 LLE_REMREF(ln); a519 1 LLE_REMREF(ln); a542 1 LLE_REMREF(ln); @ 1.232.2.12 log @Pull up following revision(s) (requested by ozaki-r in ticket #1340): sys/netinet6/nd6.c: revision 1.257 Add missing IFNET_LOCK for regen_tmpaddr Reported by ryo@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232.2.11 2019/07/26 11:27:36 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.11 2019/07/26 11:27:36 martin Exp $"); a670 1 int ret; d672 1 a672 4 IFNET_LOCK(ia6->ia_ifa.ifa_ifp); ret = regen_tmpaddr(ia6); IFNET_UNLOCK(ia6->ia_ifa.ifa_ifp); if (ret == 0) { @ 1.232.2.13 log @Pull up following revision(s) (requested by ozaki-r in ticket #1396): sys/netinet6/nd6.h: revision 1.88 sys/netinet6/nd6_nbr.c: revision 1.174 sys/netinet6/nd6.c: revision 1.264 sys/netinet/if_arp.c: revision 1.288 (patch) Initialize DAD components properly The original code initialized each component in non-init functions such as arp_dad_start and nd6_dad_find, conditionally based on a global flag for each. However, it was racy because the flag and the code around it were not protected by a lock and could cause a kernel panic at worst. Fix the issue by initializing the components in bootup as usual. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232.2.12 2019/08/19 14:28:12 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.12 2019/08/19 14:28:12 martin Exp $"); a141 2 nd6_nbr_init(); @ 1.232.2.14 log @Pull up following revision(s) (requested by ozaki-r in ticket #1692): sys/netinet6/nd6.c: revision 1.277 nd6: prevent ln from being freed while releasing held packets @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.232.2.13 2019/09/30 15:48:45 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.13 2019/09/30 15:48:45 martin Exp $"); a2016 1 LLE_ADDREF(ln); a2029 1 LLE_REMREF(ln); @ 1.231 log @Restore/add some softnet_lock for nd6_rt_flush and defrouter_addreq May help PR kern/52015 @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.230 2017/02/22 07:46:00 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.230 2017/02/22 07:46:00 ozaki-r Exp $"); a2514 2 if (p == NULL) return ENOMEM; @ 1.230 log @Stop using useless IN6_*_MULTI macros @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.229 2017/02/22 03:41:54 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.229 2017/02/22 03:41:54 ozaki-r Exp $"); d453 4 a512 4 #ifndef NET_MPSAFE mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); #endif a514 4 #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); #endif a565 4 #ifndef NET_MPSAFE mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); #endif a566 4 #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); #endif d572 4 @ 1.229 log @Use kmem istead of malloc @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.228 2017/02/22 03:02:55 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.228 2017/02/22 03:02:55 ozaki-r Exp $"); d1624 1 a1624 1 IN6_LOOKUP_MULTI(llsol, ifp, in6m); @ 1.228 log @Fix prefix invalidation via nd6_timer We cannot remove a prefix there. Instead just invalidate it; the prefix will be removed when purging an associated address. This is the same as the original behavior. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.227 2017/02/14 03:05:06 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.227 2017/02/14 03:05:06 ozaki-r Exp $"); d46 1 a46 1 #include d166 1 a166 1 nd = (struct nd_ifinfo *)malloc(sizeof(*nd), M_IP6NDP, M_WAITOK|M_ZERO); d205 1 a205 1 free(ext->nd_ifinfo, M_IP6NDP); d2511 1 d2521 2 a2522 2 if (oldp) { p = malloc(*oldlenp, M_TEMP, M_WAITOK); d2525 1 d2549 1 a2549 1 free(p, M_TEMP); @ 1.227 log @Do ND in L2_output in the same manner as arpresolve The benefits of this change are: - The flow is consistent with IPv4 (and FreeBSD and OpenBSD) - old: ip6_output => nd6_output (do ND if needed) => L2_output (lookup a stored cache) - new: ip6_output => L2_output (lookup a cache. Do ND if cache not found) - We can remove some workarounds in nd6_output - We can move L2 specific operations to their own place - The performance slightly improves because one cache lookup is reduced @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.226 2017/01/16 15:44:47 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.226 2017/01/16 15:44:47 christos Exp $"); a717 1 d719 2 a720 2 * address expiration and prefix expiration are * separate. NEVER perform in6_purgeaddr here. d722 2 a723 2 nd6_prelist_remove(pr); @ 1.226 log @ip6_sprintf -> IN6_PRINT so that we pass the size. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.225 2017/01/16 07:33:36 ryo Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.225 2017/01/16 07:33:36 ryo Exp $"); d1995 1 a1995 1 nd6_output(ifp, ifp, m_hold, &sin6, NULL); d2268 5 d2274 2 a2275 2 nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m, const struct sockaddr_in6 *dst, struct rtentry *rt) a2276 1 #define senderr(e) { error = (e); goto bad;} a2277 1 int error = 0; d2279 1 d2281 4 a2284 44 if (rt != NULL) { error = rt_check_reject_route(rt, ifp); if (error != 0) { m_freem(m); return error; } } if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) goto sendpkt; if (nd6_need_cache(ifp) == 0) goto sendpkt; if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) != 0) { struct sockaddr_in6 *gw6 = satosin6(rt->rt_gateway); int s; /* XXX remain the check to keep the original behavior. */ /* * We skip link-layer address resolution and NUD * if the gateway is not a neighbor from ND point * of view, regardless of the value of nd_ifinfo.flags. * The second condition is a bit tricky; we skip * if the gateway is our own address, which is * sometimes used to install a route to a p2p link. */ s = pserialize_read_enter(); if (!nd6_is_addr_neighbor(gw6, ifp) || in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { /* * We allow this kind of tricky route only * when the outgoing interface is p2p. * XXX: we may need a more generic rule here. */ if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { pserialize_read_exit(s); senderr(EHOSTUNREACH); } pserialize_read_exit(s); goto sendpkt; } pserialize_read_exit(s); d2295 13 d2309 1 a2309 1 if ((ln == NULL) && nd6_is_addr_neighbor(dst, ifp)) { d2316 1 a2316 7 if (ln != NULL) created = true; } if (ln == NULL) { if ((ifp->if_flags & IFF_POINTOPOINT) == 0 && !(ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD)) { d2319 2 a2320 2 "nd6_output: can't allocate llinfo for %s " "(ln=%p, rt=%p)\n", d2322 2 a2323 1 senderr(EIO); /* XXX: good error? */ d2325 1 a2325 1 goto sendpkt; /* send anyway */ a2350 8 * If the neighbor cache entry has a state other than INCOMPLETE * (i.e. its link-layer address is already resolved), just * send the packet. */ if (ln->ln_state > ND6_LLINFO_INCOMPLETE) goto sendpkt; /* a2398 23 error = 0; goto exit; sendpkt: /* discard the packet if IPv6 operation is disabled on the interface */ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { error = ENETDOWN; /* better error? */ goto bad; } if (ln != NULL) LLE_WUNLOCK(ln); if ((ifp->if_flags & IFF_LOOPBACK) != 0) error = if_output_lock(ifp, origifp, m, sin6tocsa(dst), rt); else error = if_output_lock(ifp, ifp, m, sin6tocsa(dst), rt); goto exit; bad: if (m != NULL) m_freem(m); exit: d2402 1 a2402 2 return error; #undef senderr a2484 62 int nd6_storelladdr(const struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m, const struct sockaddr *dst, uint8_t *lldst, size_t dstsize) { struct llentry *ln; if (m->m_flags & M_MCAST) { switch (ifp->if_type) { case IFT_ETHER: case IFT_FDDI: ETHER_MAP_IPV6_MULTICAST(&satocsin6(dst)->sin6_addr, lldst); return 1; case IFT_IEEE1394: memcpy(lldst, ifp->if_broadcastaddr, MIN(dstsize, ifp->if_addrlen)); return 1; case IFT_ARCNET: *lldst = 0; return 1; default: m_freem(m); return 0; } } /* * the entry should have been created in nd6_store_lladdr */ ln = nd6_lookup(&satocsin6(dst)->sin6_addr, ifp, false); if ((ln == NULL) || !(ln->la_flags & LLE_VALID)) { if (ln != NULL) LLE_RUNLOCK(ln); /* this could happen, if we could not allocate memory */ m_freem(m); return 0; } /* XXX llentry should have addrlen? */ #if 0 sdl = satocsdl(rt->rt_gateway); if (sdl->sdl_alen == 0 || sdl->sdl_alen > dstsize) { char sbuf[INET6_ADDRSTRLEN]; char dbuf[LINK_ADDRSTRLEN]; /* this should be impossible, but we bark here for debugging */ printf("%s: sdl_alen == %" PRIu8 ", if=%s, dst=%s, sdl=%s\n", __func__, sdl->sdl_alen, if_name(ifp), IN6_PRINT(sbuf, &satocsin6(dst)->sin6_addr), DL_PRINT(dbuf, &sdl->sdl_addr)); m_freem(m); return 0; } #endif memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); LLE_RUNLOCK(ln); return 1; } @ 1.225 log @Make ip6_sprintf(), in_fmtaddr(), lla_snprintf() and icmp6_redirect_diag() mpsafe. Reviewed by ozaki-r@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.224 2017/01/11 13:08:29 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.224 2017/01/11 13:08:29 ozaki-r Exp $"); d929 1 a929 1 ip6_sprintf(ip6buf, &dr->rtaddr), ifp->if_xname); d935 1 a935 1 ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), d1597 1 a1597 1 ip6_sprintf(ip6buf, &llsol), error); d2350 1 a2350 1 ip6_sprintf(ip6buf, &dst->sin6_addr), ln, rt); d2699 1 a2699 1 ip6_sprintf(ip6buf, &d->rtaddr.sin6_addr)); d2757 1 a2757 1 ip6_sprintf(ip6buf, &pfx.prefix.sin6_addr)); d2800 1 a2800 1 ip6_sprintf(ip6buf, @ 1.224 log @Get rid of unnecessary header inclusions @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.223 2016/12/22 03:46:51 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.223 2016/12/22 03:46:51 ozaki-r Exp $"); d923 1 d929 1 a929 1 ip6_sprintf(&dr->rtaddr), ifp->if_xname); d935 1 a935 1 ip6_sprintf(&pr->ndpr_prefix.sin6_addr), d1594 1 d1597 1 a1597 1 ip6_sprintf(&llsol), error); d2346 1 d2350 1 a2350 1 ip6_sprintf(&dst->sin6_addr), ln, rt); d2696 1 d2699 1 a2699 1 ip6_sprintf(&d->rtaddr.sin6_addr)); d2733 1 d2757 1 a2757 1 ip6_sprintf(&pfx.prefix.sin6_addr)); d2795 1 a2795 1 0, 0, 0); d2800 2 a2801 1 ip6_sprintf(&pfr->router->rtaddr)); @ 1.224.2.1 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.231 2017/03/01 03:02:35 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.231 2017/03/01 03:02:35 ozaki-r Exp $"); d46 1 a46 1 #include d166 1 a166 1 nd = kmem_zalloc(sizeof(*nd), KM_SLEEP); d205 1 a205 1 kmem_free(ext->nd_ifinfo, sizeof(struct nd_ifinfo)); a452 4 #ifndef NET_MPSAFE mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); #endif d509 4 d515 4 d570 4 d575 4 a583 4 #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); #endif d718 1 d720 2 a721 2 * Just invalidate the prefix here. Removing it * will be done when purging an associated address. d723 2 a724 2 KASSERT(pr->ndpr_refcnt > 0); nd6_invalidate_prefix(pr); a922 1 char ip6buf[INET6_ADDRSTRLEN] __diagused; d928 1 a928 1 IN6_PRINT(ip6buf, &dr->rtaddr), ifp->if_xname); d934 1 a934 1 IN6_PRINT(ip6buf, &pr->ndpr_prefix.sin6_addr), a1592 1 char ip6buf[INET6_ADDRSTRLEN]; d1595 1 a1595 1 IN6_PRINT(ip6buf, &llsol), error); d1623 1 a1623 1 in6m = in6_lookup_multi(&llsol, ifp); d1993 1 a1993 1 ip6_if_output(ifp, ifp, m_hold, &sin6, NULL); a2265 5 /* * Return 0 if a neighbor cache is found. Return EWOULDBLOCK if a cache is not * found and trying to resolve a neighbor; in this case the mbuf is queued in * the list. Otherwise return errno after freeing the mbuf. */ d2267 2 a2268 2 nd6_resolve(struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m, const struct sockaddr *_dst, uint8_t *lldst, size_t dstsize) d2270 1 d2272 1 a2273 1 const struct sockaddr_in6 *dst = satocsin6(_dst); d2275 44 a2318 4 /* discard the packet if IPv6 operation is disabled on the interface */ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { m_freem(m); return ENETDOWN; /* better error? */ a2328 13 ln = nd6_lookup(&dst->sin6_addr, ifp, false); if (ln != NULL && (ln->la_flags & LLE_VALID) != 0) { KASSERT(ln->ln_state > ND6_LLINFO_INCOMPLETE); /* Fast path */ memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); LLE_RUNLOCK(ln); return 0; } if (ln != NULL) LLE_RUNLOCK(ln); /* Slow path */ d2330 1 a2330 1 if (ln == NULL && nd6_is_addr_neighbor(dst, ifp)) { d2337 7 a2343 2 if (ln == NULL) { char ip6buf[INET6_ADDRSTRLEN]; d2345 4 a2348 5 "%s: can't allocate llinfo for %s " "(ln=%p, rt=%p)\n", __func__, IN6_PRINT(ip6buf, &dst->sin6_addr), ln, rt); m_freem(m); return ENOBUFS; d2350 1 a2350 1 created = true; d2376 8 d2432 23 d2458 2 a2459 1 return EWOULDBLOCK; d2542 62 a2630 1 size_t bufsize = 0; d2640 2 a2641 2 if (oldp && *oldlenp > 0) { p = kmem_alloc(*oldlenp, KM_SLEEP); a2643 1 bufsize = *oldlenp; d2667 1 a2667 1 kmem_free(p, bufsize); a2692 1 char ip6buf[INET6_ADDRSTRLEN]; d2695 1 a2695 1 IN6_PRINT(ip6buf, &d->rtaddr.sin6_addr)); a2728 1 char ip6buf[INET6_ADDRSTRLEN]; d2752 1 a2752 1 IN6_PRINT(ip6buf, &pfx.prefix.sin6_addr)); d2790 1 a2790 1 0, 0, 0); d2795 1 a2795 2 IN6_PRINT(ip6buf, &pfr->router->rtaddr)); @ 1.223 log @Remove assertion that the lock isn't held It's useless in this case, because without it we can know that the lock is held or not on a next lock acquisition and even more if LOCKDEBUG is enabled a failure on the acquisition will provide useful information for debugging while an assertion failure will provide just the fact that the assertion failed. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.222 2016/12/21 08:47:02 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.222 2016/12/21 08:47:02 ozaki-r Exp $"); a52 1 #include @ 1.222 log @Fix deadlock between llentry timers and destruction of llentry llentry timer (of nd6) holds both llentry's lock and softnet_lock. A caller also holds them and calls callout_halt to wait for the timer to quit. However we can pass only one lock to callout_halt, so passing either of them can cause a deadlock. Fix it by avoid calling callout_halt without holding llentry's lock. BTW in the first place we cannot pass llentry's lock to callout_halt because it's a rwlock... @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.221 2016/12/21 04:08:47 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.221 2016/12/21 04:08:47 ozaki-r Exp $"); a1148 1 IF_AFDATA_UNLOCK_ASSERT(ifp); @ 1.221 log @Hold the big locks only where they are needed @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.220 2016/12/19 07:51:34 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.220 2016/12/19 07:51:34 ozaki-r Exp $"); d404 9 a412 2 if (xtick < 0) { ln->ln_expire = 0; d414 2 a415 13 callout_halt(&ln->ln_timer_ch, &ln->lle_lock); } else { ln->ln_expire = time_uptime + xtick / hz; LLE_ADDREF(ln); if (xtick > INT_MAX) { ln->ln_ntick = xtick - INT_MAX; callout_reset(&ln->ln_timer_ch, INT_MAX, nd6_llinfo_timer, ln); } else { ln->ln_ntick = 0; callout_reset(&ln->ln_timer_ch, xtick, nd6_llinfo_timer, ln); } d455 2 a1208 3 /* cancel timer */ nd6_llinfo_settimer(ln, -1); d1307 1 a1307 6 /* Guard against race with other llentry_free(). */ if (ln->la_flags & LLE_LINKED) { LLE_REMREF(ln); llentry_free(ln); } else LLE_FREE_LOCKED(ln); @ 1.220 log @Protect IPv6 default router and prefix lists with coarse-grained rwlock in6_purgeaddr (in6_unlink_ifa) itself unrefernces a prefix entry and calls nd6_prelist_remove if the counter becomes 0, so callers doesn't need to handle the reference counting. Performance-sensitive paths (sending/forwarding packets) call just one reader lock. This is a trade-off between performance impact vs. the amount of efforts; if we want to remove the reader lock, we need huge amount of works including destroying objects with psz/psref in softint, for example. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.219 2016/12/19 04:52:17 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.219 2016/12/19 04:52:17 ozaki-r Exp $"); a457 5 #ifndef NET_MPSAFE mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); #endif d511 5 a515 1 if (m != NULL) d518 5 d573 4 d578 4 a586 4 #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); #endif @ 1.219 log @Kill pr->ndpr_refcnt = 0 The reference counter represents the numuber of references from IPv6 addresses to a prefix entry. If all IPv6 addresses assigned to an interface are purged, all references to a prefix for the interface are also released. For now nd6_purge is always called after purging all IPv6 addresses, so we can get rid of clearing pr->ndpr_refcnt from nd6_purge and instead we can assert it's 0 there. Note that nd6_ifdetach is only called via dom_ifdetach when processing if_detach where dom_ifdetach is called after pr_purgeif that eventually calls in6_ifdetach. So in the call path nd6_purge in nd6_ifdetach does nothing. That said, we should explicitly make it sure to purge all IPv6 addresses before nd6_purge for future changes (or the case I missed something). So if_purgeaddrs is added to nd6_ifdetach. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.218 2016/12/19 03:32:54 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.218 2016/12/19 03:32:54 ozaki-r Exp $"); d106 2 d143 2 d602 2 a603 1 d609 1 d704 1 d722 1 d797 4 a800 1 if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) { d849 1 d899 1 d919 1 d932 1 d1011 1 d1041 2 a1042 1 &addr->sin6_addr, &pr->ndpr_mask)) d1044 1 d1046 1 d1066 1 d1068 2 a1069 2 ND_DEFROUTER_LIST_EMPTY() && nd6_defifindex == ifp->if_index) { d1072 1 d1115 1 d1124 2 a1125 1 &addr->sin6_addr, &pr->ndpr_mask)) d1127 1 d1138 1 d1141 1 d1207 1 a1207 2 int s; s = splsoftnet(); d1229 1 a1229 1 splx(s); d1290 1 a1293 2 splx(s); a1646 1 int s; d1654 1 a1654 1 s = splsoftnet(); d1668 1 a1668 1 splx(s); d1684 1 a1684 1 s = splsoftnet(); d1732 1 a1732 1 splx(s); d1783 1 d1884 1 d1887 1 d1894 2 a1895 1 s = splsoftnet(); a1903 1 restart: d1915 1 d1917 1 d1923 2 d1927 1 a1927 1 splx(s); d1935 1 a1935 1 s = splsoftnet(); d1941 1 a1941 1 splx(s); d2226 2 a2227 1 nd6_accepts_rtadv(ndi)) d2229 2 d2679 1 a2679 1 int error = 0, s; a2683 2 s = splsoftnet(); d2690 1 d2713 1 a2721 2 splx(s); d2728 1 a2728 1 int error = 0, s; a2733 2 s = splsoftnet(); d2740 1 d2818 1 a2826 2 splx(s); @ 1.218 log @Get rid of extra nd6_purge from in6_ifdetach There were two nd6_purge in in6_ifdetach for some reason, but at least now We don't need extra nd6_purge. Remove it and instead add assertions that check if surely purged. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.217 2016/12/14 04:05:11 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.217 2016/12/14 04:05:11 ozaki-r Exp $"); d199 2 d868 1 a868 13 * Because if_detach() does *not* release prefixes * while purging addresses the reference count will * still be above zero. We therefore reset it to * make sure that the prefix really gets purged. */ pr->ndpr_refcnt = 0; /* * Previously, pr->ndpr_addr is removed as well, * but I strongly believe we don't have to do it. * nd6_purge() is only called from in6_ifdetach(), * which removes all the associated interface addresses * by itself. * (jinmei@@kame.net 20010129) d870 1 @ 1.217 log @Make functions static @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.216 2016/12/12 03:55:57 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.216 2016/12/12 03:55:57 ozaki-r Exp $"); d909 20 @ 1.216 log @Make the routing table and rtcaches MP-safe See the following descriptions for details. Proposed on tech-kern and tech-net Overview -------- We protect the routing table with a rwock and protect rtcaches with another rwlock. Each rtentry is protected from being freed or updated via reference counting and psref. Global rwlocks -------------- There are two rwlocks; one for the routing table (rt_lock) and the other for rtcaches (rtcache_lock). rtcache_lock covers all existing rtcaches; there may have room for optimizations (future work). The locking order is rtcache_lock first and rt_lock is next. rtentry references ------------------ References to an rtentry is managed with reference counting and psref. Either of the two mechanisms is used depending on where a rtentry is obtained. Reference counting is used when we obtain a rtentry from the routing table directly via rtalloc1 and rtrequest{,1} while psref is used when we obtain a rtentry from a rtcache via rtcache_* APIs. In both cases, a caller can sleep/block with holding an obtained rtentry. The reasons why we use two different mechanisms are (i) only using reference counting hurts the performance due to atomic instructions (rtcache case) (ii) ease of implementation; applying psref to APIs such rtaloc1 and rtrequest{,1} requires additional works (adding a local variable and an argument). We will finally migrate to use only psref but we can do it when we have a lockless routing table alternative. Reference counting for rtentry ------------------------------ rt_refcnt now doesn't count permanent references such as for rt_timers and rtcaches, instead it is used only for temporal references when obtaining a rtentry via rtalloc1 and rtrequest{,1}. We can do so because destroying a rtentry always involves removing references of rt_timers and rtcaches to the rtentry and we don't need to track such references. This also makes it easy to wait for readers to release references on deleting or updating a rtentry, i.e., we can simply wait until the reference counter is 0 or 1. (If there are permanent references the counter can be arbitrary.) rt_ref increments a reference counter of a rtentry and rt_unref decrements it. rt_ref is called inside APIs (rtalloc1 and rtrequest{,1} so users don't need to care about it while users must call rt_unref to an obtained rtentry after using it. rtfree is removed and we use rt_unref and rt_free instead. rt_unref now just decrements the counter of a given rtentry and rt_free just tries to destroy a given rtentry. See the next section for destructions of rtentries by rt_free. Destructions of rtentries ------------------------- We destroy a rtentry only when we call rtrequst{,1}(RTM_DELETE); the original implementation can destroy in any rtfree where it's the last reference. If we use reference counting or psref, it's easy to understand if the place that a rtentry is destroyed is fixed. rt_free waits for references to a given rtentry to be released before actually destroying the rtentry. rt_free uses a condition variable (cv_wait) (and psref_target_destroy for psref) to wait. Unfortunately rtrequst{,1}(RTM_DELETE) can be called in softint that we cannot use cv_wait. In that case, we have to defer the destruction to a workqueue. rtentry#rt_cv, rtentry#rt_psref and global variables (see rt_free_global) are added to conduct the procedure. Updates of rtentries -------------------- One difficulty to use refcnt/psref instead of rwlock for rtentry is updates of rtentries. We need an additional mechanism to prevent readers from seeing inconsistency of a rtentry being updated. We introduce RTF_UPDATING flag to rtentries that are updating. While the flag is set to a rtentry, users cannot acquire the rtentry. By doing so, we avoid users to see inconsistent rtentries. There are two options when a user tries to acquire a rtentry with the RTF_UPDATING flag; if a user runs in softint context the user fails to acquire a rtentry (NULL is returned). Otherwise a user waits until the update completes by waiting on cv. The procedure of a updater is simpler to destruction of a rtentry. Wait on cv (and psref) and after all readers left, proceed with the update. Global variables (see rt_update_global) are added to conduct the procedure. Currently we apply the mechanism to only RTM_CHANGE in rtsock.c. We would have to apply other codes. See "Known issues" section. psref for rtentry ----------------- When we obtain a rtentry from a rtcache via rtcache_* APIs, psref is used to reference to the rtentry. rtcache_ref acquires a reference to a rtentry with psref and rtcache_unref releases the reference after using it. rtcache_ref is called inside rtcache_* APIs and users don't need to take care of it while users must call rtcache_unref to release the reference. struct psref and int bound that is needed for psref is embedded into struct route. By doing so we don't need to add local variables and additional argument to APIs. However this adds another constraint to psref other than reference counting one's; holding a reference of an rtentry via a rtcache is allowed by just one caller at the same time. So we must not acquire a rtentry via a rtcache twice and avoid a recursive use of a rtcache. And also a rtcache must be arranged to be used by a LWP/softint at the same time somehow. For IP forwarding case, we have per-CPU rtcaches used in softint so the constraint is guaranteed. For a h rtcache of a PCB case, the constraint is guaranteed by the solock of each PCB. Any other cases (pf, ipf, stf and ipsec) are currently guaranteed by only the existence of the global locks (softnet_lock and/or KERNEL_LOCK). If we've found the cases that we cannot guarantee the constraint, we would need to introduce other rtcache APIs that use simple reference counting. psref of rtcache is created with IPL_SOFTNET and so rtcache shouldn't used at an IPL higher than IPL_SOFTNET. Note that rtcache_free is used to invalidate a given rtcache. We don't need another care by my change; just keep them as they are. Performance impact ------------------ When NET_MPSAFE is disabled the performance drop is 3% while when it's enabled the drop is increased to 11%. The difference comes from that currently we don't take any global locks and don't use psref if NET_MPSAFE is disabled. We can optimize the performance of the case of NET_MPSAFE on by reducing lookups of rtcache that uses psref; currently we do two lookups but we should be able to trim one of two. This is a future work. Known issues ------------ There are two known issues to be solved; one is that a caller of rtrequest(RTM_ADD) may change rtentry (see rtinit). We need to prevent new references during the update. Or we may be able to remove the code (perhaps, need more investigations). The other is rtredirect that updates a rtentry. We need to apply our update mechanism, however it's not easy because rtredirect is called in softint and we cannot apply our mechanism simply. One solution is to defer rtredirect to a workqueue but it requires some code restructuring. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.215 2016/12/12 03:14:01 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.215 2016/12/12 03:14:01 ozaki-r Exp $"); d119 1 d263 1 a263 1 struct nd_opt_hdr * @ 1.215 log @Introduce macros for the prefix list No functional change. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.214 2016/12/12 03:13:14 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.214 2016/12/12 03:13:14 ozaki-r Exp $"); d1006 1 a1006 1 rtfree(rt); d1009 1 a1009 1 rtfree(rt); d1134 1 a1134 1 rtfree(rt); d1137 1 a1137 1 rtfree(rt); @ 1.214 log @Introduce macros for the default router list No functional change. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.213 2016/12/11 07:38:50 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.213 2016/12/11 07:38:50 ozaki-r Exp $"); d695 1 a695 1 LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, next_pr) { d862 1 a862 1 LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, npr) { d984 1 a984 1 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { d1082 1 a1082 1 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { d1650 1 a1650 1 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { d1857 1 a1857 1 LIST_FOREACH_SAFE(pfx, &nd_prefix, ndpr_entry, next) { d2699 1 a2699 1 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { @ 1.213 log @Add nd6_ prefix to exported functions @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.212 2016/12/11 07:37:53 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.212 2016/12/11 07:37:53 ozaki-r Exp $"); d141 1 a141 1 TAILQ_INIT(&nd_defrouter); d596 1 a596 1 TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, next_dr) { d841 1 a841 1 TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, ndr) { d851 1 a851 1 TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, ndr) { d1036 1 a1036 1 TAILQ_EMPTY(&nd_defrouter) && d1100 1 a1100 1 if (!ip6_forwarding && TAILQ_FIRST(&nd_defrouter) == NULL && d1620 1 a1620 1 TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) { d1895 1 a1895 1 TAILQ_FOREACH_SAFE(drtr, &nd_defrouter, dr_entry, next) { d2647 1 a2647 1 TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) { @ 1.212 log @Move default interface things from nd6_rtr.c to nd6.c @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.211 2016/11/14 02:34:19 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.211 2016/11/14 02:34:19 ozaki-r Exp $"); d598 1 a598 1 defrtrlist_del(dr, NULL); d709 1 a709 1 prelist_remove(pr); d847 1 a847 1 defrtrlist_del(dr, ext); d857 1 a857 1 defrtrlist_del(dr, ext); d879 1 a879 1 prelist_remove(pr); d892 1 a892 1 defrouter_select(); d1171 1 a1171 1 dr = defrouter_lookup(in6, ifp); d1199 1 a1199 1 * We need to unlock to avoid a LOR with rt6_flush() d1201 1 a1201 1 * pfxlist_onlink_check() and defrouter_select() in the d1208 1 a1208 1 * rt6_flush must be called whether or not the neighbor d1212 1 a1212 1 rt6_flush(in6, ifp); d1232 1 a1232 1 * Since defrouter_select() does not affect the d1237 1 a1237 1 pfxlist_onlink_check(); d1242 1 a1242 1 defrouter_select(); d1848 2 a1849 2 defrouter_reset(); defrouter_select(); d1883 1 a1883 1 prelist_remove(pfx); d1894 1 a1894 1 defrouter_reset(); d1896 1 a1896 1 defrtrlist_del(drtr, NULL); d1898 1 a1898 1 defrouter_select(); d2175 1 a2175 1 * address option, defrouter_select() is called twice, since d2179 1 a2179 1 * XXX: although defrouter_select() should not have a bad effect d2185 1 a2185 1 defrouter_select(); @ 1.211 log @Add missing rtfree @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.210 2016/11/02 03:43:27 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.210 2016/11/02 03:43:27 ozaki-r Exp $"); d128 5 d2788 29 @ 1.210 log @Add missing pserialize_read_exit @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.209 2016/10/18 07:30:31 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.209 2016/10/18 07:30:31 ozaki-r Exp $"); d1001 1 d1004 1 @ 1.209 log @Don't hold global locks if NET_MPSAFE is enabled If NET_MPSAFE is enabled, don't hold KERNEL_LOCK and softnet_lock in part of the network stack such as IP forwarding paths. The aim of the change is to make it easy to test the network stack without the locks and reduce our local diffs. By default (i.e., if NET_MPSAFE isn't enabled), the locks are held as they used to be. Reviewed by knakahara@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.208 2016/10/18 02:46:50 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.208 2016/10/18 02:46:50 ozaki-r Exp $"); d2262 2 a2263 1 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) d2265 1 @ 1.208 log @Fix indentation @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.207 2016/09/02 07:15:14 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.207 2016/09/02 07:15:14 ozaki-r Exp $"); d446 1 d449 1 d563 1 d566 1 d584 1 d587 1 d708 1 d711 1 d2188 1 d2191 1 d2212 1 d2215 1 @ 1.207 log @Don't GC an NDP cache that is added just before GC This fixes unstable test results of ndp_neighborgcthresh. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.206 2016/08/06 20:00:14 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.206 2016/08/06 20:00:14 roy Exp $"); d782 1 a782 1 pserialize_read_exit(s); @ 1.206 log @Set RTF_CONNECTED instead of setting only RTF_CONNECTED. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.205 2016/08/01 03:15:31 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.205 2016/08/01 03:15:31 ozaki-r Exp $"); d1303 5 d1311 3 a1313 1 int *n = farg; d1321 3 d1337 1 a1337 1 nd6_gc_neighbors(struct lltable *llt) a1338 1 int max_gc_entries = 10; d1342 1 d1347 1 a1347 1 lltable_foreach_lle(llt, nd6_purge_entry, &max_gc_entries); d1559 1 a1559 1 nd6_gc_neighbors(LLTABLE6(rt->rt_ifp)); d2151 1 a2151 1 nd6_gc_neighbors(LLTABLE6(ifp)); d2394 1 a2394 1 nd6_gc_neighbors(LLTABLE6(ifp)); @ 1.205 log @Apply pserialize and psref to struct ifaddr and its variants This change makes struct ifaddr and its variants (in_ifaddr and in6_ifaddr) MP-safe by using pserialize and psref. At this moment, pserialize_perform and psref_target_destroy are disabled because (1) we don't need them because of softnet_lock (2) they cause a deadlock because of softnet_lock. So we'll enable them when we remove softnet_lock in the future. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.204 2016/07/15 07:40:09 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.204 2016/07/15 07:40:09 ozaki-r Exp $"); d2436 1 a2436 1 ia->ia_ifa.ifa_flags = RTF_CONNECTED; @ 1.204 log @Use sin6tosa and sin6tocsa macros No functional change. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.203 2016/07/11 07:37:00 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.203 2016/07/11 07:37:00 ozaki-r Exp $"); d574 2 d597 1 d599 7 a605 2 for (ia6 = IN6_ADDRLIST_WRITER_FIRST(); ia6; ia6 = nia6) { nia6 = IN6_ADDRLIST_WRITER_NEXT(ia6); d626 1 d628 1 d662 1 d677 2 d680 2 d720 1 d723 1 d765 1 d767 2 d774 1 d779 1 d782 1 d940 1 d1006 1 d1010 1 a1010 4 #ifdef __FreeBSD__ /* XXX we need to ifaref in ifa_ifwithdstaddr as well */ ifafree(dstaddr); #endif a1012 4 #ifdef __FreeBSD__ /* XXX we need to ifaref in ifa_ifwithdstaddr as well */ ifafree(dstaddr); #endif d1014 1 d1396 3 a1398 1 case RTM_ADD: d1505 1 a1541 1 d1543 1 d1551 1 d1735 1 d1747 1 d1760 2 a1761 2 (ND.flags & ND6_IFF_IFDISABLED)) { d1765 1 d1767 1 d1770 3 d1774 1 d1777 3 d1781 2 d1800 1 a1800 1 int haslinklocal = 0; d1802 2 a1803 1 IFADDR_READER_FOREACH(ifa, ifp) { d1811 3 a1813 2 } if (!haslinklocal) d1834 1 d1840 3 a1842 1 for (ia = IN6_ADDRLIST_WRITER_FIRST(); ia; d1845 1 a1845 1 ia_next = IN6_ADDRLIST_WRITER_NEXT(ia); d1850 3 a1852 1 if (ia->ia6_ndpr == pfx) d1854 2 d1857 1 d2221 1 d2232 1 d2243 1 d2246 1 @ 1.203 log @Run timers in workqueue Timers (such as nd6_timer) typically free/destroy some data in callout (softint). If we apply psz/psref for such data, we cannot do free/destroy process in there because synchronization of psz/psref cannot be used in softint. So run timer callbacks in workqueue works (normal LWP context). Doing workqueue_enqueue a work twice (i.e., call workqueue_enqueue before a previous task is scheduled) isn't allowed. For nd6_timer and rt_timer_timer, this doesn't happen because callout_reset is called only from workqueue's work. OTOH, ip{,6}flow_slowtimo's callout can be called before its work starts and completes because the callout is periodically called regardless of completion of the work. To avoid such a situation, add a flag for each protocol; the flag is set true when a work is enqueued and set false after the work finished. workqueue_enqueue is called only if the flag is false. Proposed on tech-net and tech-kern. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.202 2016/07/07 09:32:03 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.202 2016/07/07 09:32:03 ozaki-r Exp $"); d954 1 a954 1 rt = rtalloc1((struct sockaddr *)&pr->ndpr_prefix, 0); d982 1 a982 1 dstaddr = ifa_ifwithdstaddr((const struct sockaddr *)addr); d2390 1 a2390 1 (struct sockaddr *)&ia->ia_addr); d2416 2 a2417 2 lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr, (struct sockaddr *)&mask, LLE_STATIC); @ 1.203.2.1 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.204 2016/07/15 07:40:09 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.204 2016/07/15 07:40:09 ozaki-r Exp $"); d954 1 a954 1 rt = rtalloc1(sin6tosa(&pr->ndpr_prefix), 0); d982 1 a982 1 dstaddr = ifa_ifwithdstaddr(sin6tocsa(addr)); d2390 1 a2390 1 sin6tosa(&ia->ia_addr)); d2416 2 a2417 2 lltable_prefix_free(AF_INET6, sin6tosa(&addr), sin6tosa(&mask), LLE_STATIC); @ 1.203.2.2 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.205 2016/08/01 03:15:31 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.205 2016/08/01 03:15:31 ozaki-r Exp $"); a573 2 int s, bound; struct psref psref; a594 1 bound = curlwp_bind(); d596 2 a597 7 s = pserialize_read_enter(); for (ia6 = IN6_ADDRLIST_READER_FIRST(); ia6; ia6 = nia6) { nia6 = IN6_ADDRLIST_READER_NEXT(ia6); ia6_acquire(ia6, &psref); pserialize_read_exit(s); a617 1 ia6_release(ia6, &psref); a618 1 ia6 = NULL; a651 1 ia6_release(ia6, &psref); a665 2 s = pserialize_read_enter(); ia6_release(ia6, &psref); a666 2 pserialize_read_exit(s); curlwp_bindx(bound); a704 1 int s; a706 1 s = pserialize_read_enter(); a747 1 struct psref psref; a748 2 ia6_acquire(public_ifa6, &psref); pserialize_read_exit(s); a753 1 ia6_release(public_ifa6, &psref); a757 1 ia6_release(public_ifa6, &psref); a759 1 pserialize_read_exit(s); a916 1 int s; a981 1 s = pserialize_read_enter(); d985 4 a988 1 pserialize_read_exit(s); d991 4 a995 1 pserialize_read_exit(s); d1377 1 a1377 3 case RTM_ADD: { int s; a1483 1 s = pserialize_read_enter(); d1520 1 a1521 1 pserialize_read_exit(s); a1528 1 } a1711 1 s = pserialize_read_enter(); a1722 1 pserialize_read_exit(s); d1735 2 a1736 2 (ND.flags & ND6_IFF_IFDISABLED)) { int bound = curlwp_bind(); a1739 1 s = pserialize_read_enter(); a1740 1 struct psref psref; a1742 3 ifa_acquire(ifa, &psref); pserialize_read_exit(s); a1743 1 a1745 3 s = pserialize_read_enter(); ifa_release(ifa, &psref); a1746 2 pserialize_read_exit(s); curlwp_bindx(bound); d1764 1 a1764 1 int haslinklocal = 0; d1766 1 a1766 2 s = pserialize_read_enter(); IFADDR_READER_FOREACH(ifa, ifp) { d1774 2 a1775 3 } pserialize_read_exit(s); if (!haslinklocal) a1795 1 int _s; d1801 1 a1801 3 restart: _s = pserialize_read_enter(); for (ia = IN6_ADDRLIST_READER_FIRST(); ia; d1804 1 a1804 1 ia_next = IN6_ADDRLIST_READER_NEXT(ia); d1809 1 a1809 3 if (ia->ia6_ndpr == pfx) { pserialize_read_exit(_s); /* XXX NOMPSAFE? */ a1810 2 goto restart; } a1811 1 pserialize_read_exit(_s); a2174 1 int s; a2184 1 s = pserialize_read_enter(); a2194 1 pserialize_read_exit(s); a2196 1 pserialize_read_exit(s); @ 1.203.2.3 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.210 2016/11/02 03:43:27 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.210 2016/11/02 03:43:27 ozaki-r Exp $"); a445 1 #ifndef NET_MPSAFE a447 1 #endif a560 1 #ifndef NET_MPSAFE a562 1 #endif a579 1 #ifndef NET_MPSAFE a581 1 #endif a701 1 #ifndef NET_MPSAFE a703 1 #endif d782 1 a782 1 pserialize_read_exit(s); a2169 1 #ifndef NET_MPSAFE a2171 1 #endif a2191 1 #ifndef NET_MPSAFE a2193 1 #endif d2240 1 a2240 2 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { pserialize_read_exit(s); a2241 1 } @ 1.203.2.4 log @Sync with HEAD. (Note that most of these changes are simply $NetBSD$ tag issues.) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.223 2016/12/22 03:46:51 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.223 2016/12/22 03:46:51 ozaki-r Exp $"); a105 2 krwlock_t nd6_lock __cacheline_aligned; a118 1 static struct nd_opt_hdr *nd6_option(union nd_opts *); a127 5 static struct ifnet *nd6_defifp; static int nd6_defifindex; static int nd6_setdefaultiface(int); a134 2 rw_init(&nd6_lock); d136 1 a136 1 ND_DEFROUTER_LIST_INIT(); a192 2 /* Ensure all IPv6 addresses are purged before calling nd6_purge */ if_purgeaddrs(ifp, AF_INET6, in6_purgeaddr); d257 1 a257 1 static struct nd_opt_hdr * d392 4 a395 8 KASSERT(xtick >= 0); ln->ln_expire = time_uptime + xtick / hz; LLE_ADDREF(ln); if (xtick > INT_MAX) { ln->ln_ntick = xtick - INT_MAX; callout_reset(&ln->ln_timer_ch, INT_MAX, nd6_llinfo_timer, ln); d397 11 a407 3 ln->ln_ntick = 0; callout_reset(&ln->ln_timer_ch, xtick, nd6_llinfo_timer, ln); d446 5 a451 2 if ((ln->la_flags & LLE_LINKED) == 0) goto out; d504 1 a504 5 if (m != NULL) { #ifndef NET_MPSAFE mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); #endif a506 5 #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); #endif } a556 4 #ifndef NET_MPSAFE mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); #endif a557 4 #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); #endif d563 4 d590 2 a591 3 ND6_WLOCK(); ND_DEFROUTER_LIST_FOREACH_SAFE(dr, next_dr) { d593 1 a593 1 nd6_defrtrlist_del(dr, NULL); a595 1 ND6_UNLOCK(); d690 1 a690 2 ND6_WLOCK(); ND_PREFIX_LIST_FOREACH_SAFE(pr, next_pr) { d704 1 a704 1 nd6_prelist_remove(pr); a706 1 ND6_UNLOCK(); d781 1 a781 4 ND6_WLOCK(); e = in6_tmpifadd(public_ifa6, 0, 0); ND6_UNLOCK(); if (e != 0) { a829 1 ND6_WLOCK(); d836 1 a836 1 ND_DEFROUTER_LIST_FOREACH_SAFE(dr, ndr) { d842 1 a842 1 nd6_defrtrlist_del(dr, ext); d846 1 a846 1 ND_DEFROUTER_LIST_FOREACH_SAFE(dr, ndr) { d852 1 a852 1 nd6_defrtrlist_del(dr, ext); d857 1 a857 1 ND_PREFIX_LIST_FOREACH_SAFE(pr, npr) { d860 13 a872 1 * All addresses referencing pr should be already freed. d874 1 a874 2 KASSERT(pr->ndpr_refcnt == 0); nd6_prelist_remove(pr); d887 1 a887 1 nd6_defrouter_select(); a889 1 ND6_UNLOCK(); a902 22 void nd6_assert_purged(struct ifnet *ifp) { struct nd_defrouter *dr; struct nd_prefix *pr; ND6_RLOCK(); ND_DEFROUTER_LIST_FOREACH(dr) { KASSERTMSG(dr->ifp != ifp, "defrouter %s remains on %s", ip6_sprintf(&dr->rtaddr), ifp->if_xname); } ND_PREFIX_LIST_FOREACH(pr) { KASSERTMSG(pr->ndpr_ifp != ifp, "prefix %s/%d remains on %s", ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen, ifp->if_xname); } ND6_UNLOCK(); } d979 1 a979 2 ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { a1000 1 rt_unref(rt); a1002 1 rt_unref(rt); d1006 1 a1006 2 &addr->sin6_addr, &pr->ndpr_mask)) { ND6_UNLOCK(); a1007 1 } a1008 1 ND6_UNLOCK(); a1027 1 ND6_RLOCK(); d1029 2 a1030 2 ND_DEFROUTER_LIST_EMPTY() && nd6_defifindex == ifp->if_index) { ND6_UNLOCK(); a1032 1 ND6_UNLOCK(); d1075 1 a1075 2 ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { d1083 1 a1083 2 &addr->sin6_addr, &pr->ndpr_mask)) { ND6_UNLOCK(); a1084 1 } d1093 1 a1093 1 if (!ip6_forwarding && ND_DEFROUTER_LIST_EMPTY() && a1094 1 ND6_UNLOCK(); a1096 1 ND6_UNLOCK(); d1098 1 d1127 1 a1127 1 rt_unref(rt); d1130 1 a1130 1 rt_unref(rt); d1158 3 d1162 3 a1164 2 ND6_WLOCK(); dr = nd6_defrouter_lookup(in6, ifp); d1185 1 a1185 1 ND6_UNLOCK(); d1192 1 a1192 1 * We need to unlock to avoid a LOR with nd6_rt_flush() d1194 1 a1194 1 * nd6_pfxlist_onlink_check() and nd6_defrouter_select() in the d1201 1 a1201 1 * nd6_rt_flush must be called whether or not the neighbor d1205 1 a1205 1 nd6_rt_flush(in6, ifp); d1225 1 a1225 1 * Since nd6_defrouter_select() does not affect the d1230 1 a1230 1 nd6_pfxlist_onlink_check(); d1235 1 a1235 1 nd6_defrouter_select(); a1245 1 ND6_UNLOCK(); d1249 2 d1261 6 a1266 1 lltable_free_entry(LLTABLE6(ifp), ln); d1594 1 d1602 2 a1603 2 ND6_RLOCK(); ND_DEFROUTER_LIST_FOREACH(dr) { d1616 1 a1616 1 ND6_UNLOCK(); d1632 2 a1633 2 ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { d1680 1 a1680 1 ND6_UNLOCK(); a1730 1 int s; d1831 2 a1832 4 ND6_WLOCK(); nd6_defrouter_reset(); nd6_defrouter_select(); ND6_UNLOCK(); d1839 2 a1840 3 restart: ND6_WLOCK(); ND_PREFIX_LIST_FOREACH_SAFE(pfx, next) { d1848 1 a1859 1 ND6_UNLOCK(); a1860 1 /* in6_purgeaddr may destroy pfx. */ d1866 1 a1866 3 KASSERT(pfx->ndpr_refcnt == 0); nd6_prelist_remove(pfx); d1868 1 a1868 1 ND6_UNLOCK(); d1876 4 a1879 4 ND6_WLOCK(); nd6_defrouter_reset(); ND_DEFROUTER_LIST_FOREACH_SAFE(drtr, next) { nd6_defrtrlist_del(drtr, NULL); d1881 2 a1882 2 nd6_defrouter_select(); ND6_UNLOCK(); d2158 1 a2158 1 * address option, nd6_defrouter_select() is called twice, since d2162 1 a2162 1 * XXX: although nd6_defrouter_select() should not have a bad effect d2167 2 a2168 5 nd6_accepts_rtadv(ndi)) { ND6_WLOCK(); nd6_defrouter_select(); ND6_UNLOCK(); } d2617 1 a2617 1 int error = 0; d2622 2 d2630 1 a2630 2 ND6_RLOCK(); ND_DEFROUTER_LIST_FOREACH(dr) { a2651 1 ND6_UNLOCK(); d2660 2 d2668 1 a2668 1 int error = 0; d2674 2 d2682 1 a2682 2 ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { a2758 1 ND6_UNLOCK(); d2767 2 a2770 29 static int nd6_setdefaultiface(int ifindex) { ifnet_t *ifp; int error = 0; int s; s = pserialize_read_enter(); ifp = if_byindex(ifindex); if (ifp == NULL) { pserialize_read_exit(s); return EINVAL; } if (nd6_defifindex != ifindex) { nd6_defifindex = ifindex; nd6_defifp = nd6_defifindex > 0 ? ifp : NULL; /* * Our current implementation assumes one-to-one maping between * interfaces and links, so it would be natural to use the * default interface as the default link. */ scope6_setdefault(nd6_defifp); } pserialize_read_exit(s); return (error); } @ 1.203.2.5 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.231 2017/03/01 03:02:35 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.231 2017/03/01 03:02:35 ozaki-r Exp $"); d46 1 a46 1 #include d53 1 d167 1 a167 1 nd = kmem_zalloc(sizeof(*nd), KM_SLEEP); d206 1 a206 1 kmem_free(ext->nd_ifinfo, sizeof(struct nd_ifinfo)); a453 4 #ifndef NET_MPSAFE mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); #endif d510 4 d516 4 d571 4 d576 4 a584 4 #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); #endif d719 1 d721 2 a722 2 * Just invalidate the prefix here. Removing it * will be done when purging an associated address. d724 2 a725 2 KASSERT(pr->ndpr_refcnt > 0); nd6_invalidate_prefix(pr); a923 1 char ip6buf[INET6_ADDRSTRLEN] __diagused; d929 1 a929 1 IN6_PRINT(ip6buf, &dr->rtaddr), ifp->if_xname); d935 1 a935 1 IN6_PRINT(ip6buf, &pr->ndpr_prefix.sin6_addr), a1583 1 char ip6buf[INET6_ADDRSTRLEN]; d1586 1 a1586 1 IN6_PRINT(ip6buf, &llsol), error); d1614 1 a1614 1 in6m = in6_lookup_multi(&llsol, ifp); d1984 1 a1984 1 ip6_if_output(ifp, ifp, m_hold, &sin6, NULL); a2256 5 /* * Return 0 if a neighbor cache is found. Return EWOULDBLOCK if a cache is not * found and trying to resolve a neighbor; in this case the mbuf is queued in * the list. Otherwise return errno after freeing the mbuf. */ d2258 2 a2259 2 nd6_resolve(struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m, const struct sockaddr *_dst, uint8_t *lldst, size_t dstsize) d2261 1 d2263 1 a2264 1 const struct sockaddr_in6 *dst = satocsin6(_dst); d2266 44 a2309 4 /* discard the packet if IPv6 operation is disabled on the interface */ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { m_freem(m); return ENETDOWN; /* better error? */ a2319 13 ln = nd6_lookup(&dst->sin6_addr, ifp, false); if (ln != NULL && (ln->la_flags & LLE_VALID) != 0) { KASSERT(ln->ln_state > ND6_LLINFO_INCOMPLETE); /* Fast path */ memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); LLE_RUNLOCK(ln); return 0; } if (ln != NULL) LLE_RUNLOCK(ln); /* Slow path */ d2321 1 a2321 1 if (ln == NULL && nd6_is_addr_neighbor(dst, ifp)) { d2328 7 a2334 2 if (ln == NULL) { char ip6buf[INET6_ADDRSTRLEN]; d2336 4 a2339 5 "%s: can't allocate llinfo for %s " "(ln=%p, rt=%p)\n", __func__, IN6_PRINT(ip6buf, &dst->sin6_addr), ln, rt); m_freem(m); return ENOBUFS; d2341 1 a2341 1 created = true; d2367 8 d2423 23 d2449 2 a2450 1 return EWOULDBLOCK; d2533 62 a2621 1 size_t bufsize = 0; d2631 2 a2632 2 if (oldp && *oldlenp > 0) { p = kmem_alloc(*oldlenp, KM_SLEEP); a2634 1 bufsize = *oldlenp; d2658 1 a2658 1 kmem_free(p, bufsize); a2683 1 char ip6buf[INET6_ADDRSTRLEN]; d2686 1 a2686 1 IN6_PRINT(ip6buf, &d->rtaddr.sin6_addr)); a2719 1 char ip6buf[INET6_ADDRSTRLEN]; d2743 1 a2743 1 IN6_PRINT(ip6buf, &pfx.prefix.sin6_addr)); d2781 1 a2781 1 0, 0, 0); d2786 1 a2786 2 IN6_PRINT(ip6buf, &pfr->router->rtaddr)); @ 1.202 log @Switch the address list of intefaces to pslist(9) As usual, we leave the old list to avoid breaking kvm(3) users. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.201 2016/07/05 06:32:18 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.201 2016/07/05 06:32:18 ozaki-r Exp $"); d59 1 d117 1 d122 2 d133 1 d141 5 d569 1 a569 1 nd6_timer(void *ignored_arg) d691 7 @ 1.201 log @Constify an argument of regen_tmpaddr @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.200 2016/07/05 04:25:23 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.200 2016/07/05 04:25:23 ozaki-r Exp $"); d690 1 a690 1 IFADDR_FOREACH(ifa, ifp) { d1695 1 a1695 1 IFADDR_FOREACH(ifa, ifp) { d1723 1 a1723 1 IFADDR_FOREACH(ifa, ifp) { d1749 1 a1749 1 IFADDR_FOREACH(ifa, ifp) { @ 1.200 log @KNF @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.199 2016/07/04 06:48:14 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.199 2016/07/04 06:48:14 ozaki-r Exp $"); d112 1 a112 1 static int regen_tmpaddr(struct in6_ifaddr *); d683 1 a683 1 regen_tmpaddr(struct in6_ifaddr *ia6) @ 1.199 log @Use pslist(9) for the global in6_ifaddr list psz and psref will be applied in another commit. No functional change intended. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.198 2016/06/30 01:34:53 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.198 2016/06/30 01:34:53 ozaki-r Exp $"); d726 1 a726 1 public_ifa6 = it6; @ 1.198 log @Make sure that ifaddr is published after its initialization finished Basically we should insert an item to a collection (say a list) after item's initialization has been completed to avoid accessing an item that is initialized halfway. ifaddr (in{,6}_ifaddr) isn't processed like so and needs to be fixed. In order to do so, we need to tweak {arp,nd6}_rtrequest that depend on that an ifaddr is inserted during its initialization; they explore interface's address list to determine that rt_getkey(rt) of a given rtentry is in the list to know whether the route's interface should be a loopback, which doesn't work after the change. To make it work, first check RTF_LOCAL flag that is set in rt_ifa_addlocal that calls {arp,nd6}_rtrequest eventually. Note that we still need the original code for the case to remove and re-add a local interface route. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.197 2016/06/21 02:14:11 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.197 2016/06/21 02:14:11 ozaki-r Exp $"); d586 2 a587 2 for (ia6 = in6_ifaddr; ia6; ia6 = nia6) { nia6 = ia6->ia_next; d1784 2 a1785 1 for (ia = in6_ifaddr; ia; ia = ia_next) { d1787 1 a1787 1 ia_next = ia->ia_next; @ 1.197 log @Fix nd6_output (if_output_lock conversion mistake) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.196 2016/06/20 06:46:38 knakahara Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.196 2016/06/20 06:46:38 knakahara Exp $"); d1453 11 @ 1.196 log @apply if_output_lock() to L3 callers which call ifp->if_output() of L2(or L3 tunneling). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.195 2016/05/18 11:28:44 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.195 2016/05/18 11:28:44 ozaki-r Exp $"); d2295 1 a2295 1 error = if_output_lock(origifp, origifp, m, sin6tocsa(dst), rt); @ 1.195 log @Get rid of unnecessary assignment @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.194 2016/05/12 02:24:17 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.194 2016/05/12 02:24:17 ozaki-r Exp $"); a2293 3 #ifndef NET_MPSAFE KERNEL_LOCK(1, NULL); #endif d2295 1 a2295 1 error = (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); d2297 1 a2297 4 error = (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); #endif @ 1.194 log @Protect ifnet list with psz and psref The change ensures that ifnet objects in the ifnet list aren't freed during list iterations by using pserialize(9) and psref(9). Note that the change adds a pslist(9) for ifnet but doesn't remove the original ifnet list (ifnet_list) to avoid breaking kvm(3) users. We shouldn't use the original list in the kernel anymore. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.193 2016/04/26 09:30:01 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.193 2016/04/26 09:30:01 ozaki-r Exp $"); d1460 1 a1460 1 ifp = rt->rt_ifp = lo0ifp; /* XXX */ @ 1.193 log @Stop using rt_gwroute on packet sending paths rt_gwroute of rtentry is a reference to a rtentry of the gateway for a rtentry with RTF_GATEWAY. That was used by L2 (arp and ndp) to look up L2 addresses. By separating L2 nexthop caches, we don't need a route for the purpose and we can stop using rt_gwroute. By doing so, we can reduce referencing and modifying rtentries, which makes it easy to apply a lock (and/or psref) to the routing table and rtentries. One issue to do this is to keep RTF_REJECT behavior. It seems it was broken when we moved rtalloc1 things from L2 output routines (e.g., ether_output) to ip_hresolv_output, but (fortunately?) it works unexpectedly. What we mistook are: - RTF_REJECT was checked for any routes in L2 output routines, but in ip_hresolv_output it is checked only when the route is RTF_GATEWAY - The RTF_REJECT check wasn't copied to IPv6 (nd6_output) It seems that rt_gwroute checks hid the mistakes and it looked work (unexpectedly) and removing rt_gwroute checks unveil the issue. So we need to fix RTF_REJECT checks in ip_hresolv_output and also add them to nd6_output. One more point we have to care is returning an errno; we need to mimic looutput behavior. Originally RTF_REJECT check was done either in L2 output routines or in looutput. The latter is applied when a reject route directs to a loopback interface. However, now RTF_REJECT check is done before looutput so to keep the original behavior we need to return an errno which looutput chooses. Added rt_check_reject_route does such tweaks. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.192 2016/04/25 14:38:08 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.192 2016/04/25 14:38:08 ozaki-r Exp $"); d2093 1 d2099 3 a2101 1 IFNET_FOREACH(ifp) { d2115 2 @ 1.192 log @Check error of rt_setgate and rt_settag @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.191 2016/04/21 05:07:50 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.191 2016/04/21 05:07:50 ozaki-r Exp $"); a2115 64 /* * Next hop determination. This routine was derived from ip_output.c. */ static int nd6_determine_nexthop(struct ifnet *ifp, const struct sockaddr_in6 *dst, struct rtentry *rt0, struct rtentry **ret_rt, bool *sendpkt) { struct rtentry *rt = rt0; struct rtentry *gwrt = NULL; struct sockaddr_in6 *gw6 = satosin6(rt->rt_gateway); /* * We skip link-layer address resolution and NUD * if the gateway is not a neighbor from ND point * of view, regardless of the value of nd_ifinfo.flags. * The second condition is a bit tricky; we skip * if the gateway is our own address, which is * sometimes used to install a route to a p2p link. */ if (!nd6_is_addr_neighbor(gw6, ifp) || in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { /* * We allow this kind of tricky route only * when the outgoing interface is p2p. * XXX: we may need a more generic rule here. */ if ((ifp->if_flags & IFF_POINTOPOINT) == 0) goto hostunreach; *sendpkt = true; return 0; } /* Try to use a cached nexthop route (gwroute) if exists */ gwrt = rt_get_gwroute(rt); if (gwrt == NULL || (gwrt->rt_flags & RTF_UP) == 0) { if (gwrt != NULL) { rtfree(gwrt); } /* Look up a nexthop route */ gwrt = rtalloc1(rt->rt_gateway, 1); rt_set_gwroute(rt, gwrt); rt = gwrt; if (rt == NULL) goto hostunreach; /* the "G" test below also prevents rt == rt0 */ if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_ifp != ifp)) { if (rt0->rt_gwroute != NULL) rtfree(rt0->rt_gwroute); rt0->rt_gwroute = NULL; goto hostunreach; } } *ret_rt = gwrt; return 0; hostunreach: if (gwrt != NULL) rtfree(gwrt); return EHOSTUNREACH; } d2124 8 a2131 1 struct rtentry *nexthop = NULL; d2139 26 a2171 13 if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) != 0) { bool sendpkt = false; /* Still need a nexthop to reflect RTF_{REJECT,BLACKHOLE} */ error = nd6_determine_nexthop(ifp, dst, rt, &nexthop, &sendpkt); if (error != 0) senderr(error); if (nexthop != NULL) rt = nexthop; if (sendpkt) goto sendpkt; } a2304 3 if (nexthop != NULL) rtfree(nexthop); @ 1.191 log @Fix RTF_{REJECT,BLACKHOLE} behavior for IPv6 routes We still need a nexthop route to reflect RTF_{REJECT,BLACKHOLE}. In the future, we would do it w/o looking up a route. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.190 2016/04/10 08:15:52 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.190 2016/04/10 08:15:52 ozaki-r Exp $"); d1392 6 @ 1.190 log @Don't call pfxlist_onlink_check with holding llentry lock Sync nd6_free with FreeBSD (as of 2016-04-10). Should fix PR kern/51056. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.189 2016/04/04 12:05:40 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.189 2016/04/04 12:05:40 roy Exp $"); d2110 64 d2182 1 d2197 13 d2343 3 @ 1.189 log @all1_sa is no longer used. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.188 2016/04/04 07:37:07 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.188 2016/04/04 07:37:07 ozaki-r Exp $"); d1148 9 d1193 13 @ 1.188 log @Separate nexthop caches from the routing table By this change, nexthop caches (IP-MAC address pair) are not stored in the routing table anymore. Instead nexthop caches are stored in each network interface; we already have lltable/llentry data structure for this purpose. This change also obsoletes the concept of cloning/cloned routes. Cloned routes no longer exist while cloning routes still exist with renamed to connected routes. Noticeable changes are: - Nexthop caches aren't listed in route show/netstat -r - sysctl(NET_RT_DUMP) doesn't return them - If RTF_LLDATA is specified, it returns nexthop caches - Several definitions of routing flags and messages are removed - RTF_CLONING, RTF_XRESOLVE, RTF_LLINFO, RTF_CLONED and RTM_RESOLVE - RTF_CONNECTED is added - It has the same value of RTF_CLONING for backward compatibility - route's -xresolve, -[no]cloned and -llinfo options are removed - -[no]cloning remains because it seems there are users - -[no]connected is introduced and recommended to be used instead of -[no]cloning - route show/netstat -r drops some flags - 'L' and 'c' are not seen anymore - 'C' now indicates a connected route - Gateway value of a route of an interface address is now not a L2 address but "link#N" like a connected (cloning) route - Proxy ARP: "arp -s ... pub" doesn't create a route You can know details of behavior changes by seeing diffs under tests/. Proposed on tech-net and tech-kern: http://mail-index.netbsd.org/tech-net/2016/03/11/msg005701.html @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.187 2016/04/01 08:12:00 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.187 2016/04/01 08:12:00 ozaki-r Exp $"); a108 8 static const struct sockaddr_in6 all1_sa = { .sin6_family = AF_INET6 , .sin6_len = sizeof(struct sockaddr_in6) , .sin6_addr = {.s6_addr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}} }; @ 1.187 log @Refine nd6log Add __func__ to nd6log itself instead of adding it to callers. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.186 2016/04/01 05:11:38 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.186 2016/04/01 05:11:38 ozaki-r Exp $"); a104 3 /* for debugging? */ static int nd6_inuse, nd6_allocated; d121 1 a121 1 static void nd6_free(struct rtentry *, struct llentry *, int); d384 1 a384 1 nd6_llinfo_settimer_locked(struct llentry *ln, time_t xtick) a408 9 void nd6_llinfo_settimer(struct llentry *ln, time_t xtick) { LLE_WLOCK(ln); nd6_llinfo_settimer_locked(ln, xtick); LLE_WUNLOCK(ln); } a438 2 struct rtentry *rt; const struct sockaddr_in6 *dst; d449 1 a449 1 nd6_llinfo_settimer_locked(ln, ln->ln_ntick); d467 1 a467 1 * by nd6_llinfo_settimer_locked above since canceled a473 1 rt = ln->ln_rt; a474 1 KASSERT(rt != NULL); a477 8 dst = satocsin6(rt_getkey(rt)); /* sanity check */ if (rt->rt_llinfo && (struct llentry *)rt->rt_llinfo != ln) panic("rt_llinfo(%p) is not equal to ln(%p)", rt->rt_llinfo, ln); if (!dst) panic("dst=0 in nd6_timer(ln=%p)", ln); d498 1 a498 1 nd6_free(rt, ln, 0); d508 1 a508 1 nd6_llinfo_settimer_locked(ln, nd6_gctimer * hz); d516 1 a516 1 nd6_free(rt, ln, 1); d526 1 a526 1 daddr6 = &dst->sin6_addr; d530 1 a530 1 nd6_llinfo_settimer_locked(ln, nd6_gctimer * hz); d536 1 a536 1 daddr6 = &dst->sin6_addr; d539 1 a539 1 nd6_free(rt, ln, 0); d547 1 d549 1 a549 1 nd6_llinfo_settimer_locked(ln, ndi->retrans * hz / 1000); d553 1 a553 1 nd6_ns_output(ifp, daddr6, &dst->sin6_addr, psrc, 0); d863 18 a880 3 static struct rtentry * nd6_lookup1(const struct in6_addr *addr6, int create, struct ifnet *ifp, int cloning) a881 1 struct rtentry *rt; d883 1 d886 31 a916 2 rt = rtalloc1((struct sockaddr *)&sin6, create); if (rt != NULL && (rt->rt_flags & RTF_LLINFO) == 0) { d918 23 a940 14 * This is the case for the default route. * If we want to create a neighbor cache for the address, we * should free the route for the destination and allocate an * interface route. */ if (create) { rtfree(rt); rt = NULL; } } if (rt != NULL) ; else if (create && ifp) { int e; d942 2 a943 11 /* * If no route is available and create is set, * we allocate a host route for the destination * and treat it like an interface route. * This hack is necessary for a neighbor which can't * be covered by our own prefix. */ struct ifaddr *ifa = ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); if (ifa == NULL) return NULL; d945 17 a961 17 /* * Create a new route. RTF_LLINFO is necessary * to create a Neighbor Cache entry for the * destination in nd6_rtrequest which will be * called in rtrequest via ifa->ifa_rtrequest. */ if ((e = rtrequest(RTM_ADD, (const struct sockaddr *)&sin6, ifa->ifa_addr, (const struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) != 0) { #if 0 log(LOG_ERR, "nd6_lookup: failed to add route for a " "neighbor(%s), errno=%d\n", ip6_sprintf(addr6), e); #endif return NULL; d963 5 a967 8 if (rt == NULL) return NULL; if (rt->rt_llinfo) { struct llentry *ln = rt->rt_llinfo; ln->ln_state = ND6_LLINFO_NOSTATE; } } else return NULL; d970 9 a978 9 * Check for a cloning route to match the address. * This should only be set from in6_is_addr_neighbor so we avoid * a potentially expensive second call to rtalloc1. */ if (cloning && rt->rt_flags & (RTF_CLONING | RTF_CLONED) && (rt->rt_ifp == ifp #if NBRIDGE > 0 || rt->rt_ifp->if_bridge == ifp->if_bridge d980 5 a984 5 #if NCARP > 0 || (ifp->if_type == IFT_CARP && rt->rt_ifp == ifp->if_carpdev) || (rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp)|| (ifp->if_type == IFT_CARP && rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp->if_carpdev) d986 1 a986 2 )) return rt; d989 7 a995 26 * Validation for the entry. * Note that the check for rt_llinfo is necessary because a cloned * route from a parent route that has the L flag (e.g. the default * route to a p2p interface) may have the flag, too, while the * destination is not actually a neighbor. * XXX: we can't use rt->rt_ifp to check for the interface, since * it might be the loopback interface if the entry is for our * own address on a non-loopback interface. Instead, we should * use rt->rt_ifa->ifa_ifp, which would specify the REAL * interface. * Note also that ifa_ifp and ifp may differ when we connect two * interfaces to a same link, install a link prefix to an interface, * and try to install a neighbor cache on an interface that does not * have a route to the prefix. */ if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || rt->rt_gateway->sa_family != AF_LINK || rt->rt_llinfo == NULL || (ifp && rt->rt_ifa->ifa_ifp != ifp)) { if (create) { nd6log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec"); } rtfree(rt); return NULL; a996 2 return rt; } d998 1 a998 5 struct rtentry * nd6_lookup(const struct in6_addr *addr6, int create, struct ifnet *ifp) { return nd6_lookup1(addr6, create, ifp, 0); d1009 1 d1062 4 d1067 2 a1068 2 * Even if the address matches none of our addresses, it might match * a cloning route or be in the neighbor cache. d1070 21 a1090 2 rt = nd6_lookup1(&addr->sin6_addr, 0, ifp, 1); if (rt != NULL) { d1094 1 d1106 1 a1106 1 nd6_free(struct rtentry *rt, struct llentry *ln, int gc) a1107 1 struct in6_addr in6 = satocsin6(rt_getkey(rt))->sin6_addr; d1109 2 a1110 1 int error; a1112 1 KASSERT(ln == rt->rt_llinfo); d1115 2 d1123 1 a1123 1 nd6_llinfo_settimer_locked(ln, -1); d1128 1 a1128 2 dr = defrouter_lookup(&satocsin6(rt_getkey(rt))->sin6_addr, rt->rt_ifp); d1145 1 a1145 1 nd6_llinfo_settimer_locked(ln, d1148 1 a1148 2 nd6_llinfo_settimer_locked(ln, nd6_gctimer * hz); d1160 1 a1160 1 rt6_flush(&in6, rt->rt_ifp); d1195 4 d1200 11 a1210 10 /* * Detach the route from the routing tree and the list of neighbor * caches, and disable the route entry not to be used in already * cached routes. */ error = rtrequest_newmsg(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0); if (error != 0) { /* XXX need error message? */; } d1222 1 d1227 3 a1229 5 if ((rt->rt_flags & RTF_GATEWAY) != 0 || (rt->rt_flags & RTF_LLINFO) == 0 || !rt->rt_llinfo || !rt->rt_gateway || rt->rt_gateway->sa_family != AF_LINK) { /* This is not a host route. */ a1230 1 } a1231 1 ln = rt->rt_llinfo; d1233 1 a1233 1 return; d1241 1 a1241 1 return; d1244 5 a1248 4 if (!ND6_LLINFO_PERMANENT(ln)) { nd6_llinfo_settimer(ln, ND_IFINFO(rt->rt_ifp)->reachable * hz); } d1269 1 a1269 1 nd6_llinfo_settimer_locked(ln, 0); a1294 1 struct llentry *ln; a1297 2 int flags = 0; bool use_lo0ifp = false; a1344 26 IF_AFDATA_RLOCK(ifp); ln = lla_lookup(LLTABLE6(ifp), flags, rt_getkey(rt)); IF_AFDATA_RUNLOCK(ifp); if (req == RTM_RESOLVE && (nd6_need_cache(ifp) == 0 || /* stf case */ !nd6_is_addr_neighbor(satocsin6(rt_getkey(rt)), ifp))) { RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); /* * FreeBSD and BSD/OS often make a cloned host route based * on a less-specific route (e.g. the default route). * If the less specific route does not have a "gateway" * (this is the case when the route just goes to a p2p or an * stf interface), we'll mistakenly make a neighbor cache for * the host route, and will see strange neighbor solicitation * for the corresponding destination. In order to avoid the * confusion, we check if the destination of the route is * a neighbor in terms of neighbor discovery, and stop the * process if not. Additionally, we remove the LLINFO flag * so that ndp(8) will not try to get the neighbor information * of the destination. */ rt->rt_flags &= ~RTF_LLINFO; return; } d1355 2 a1356 2 if ((rt->rt_flags & RTF_CLONING) || ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && ln == NULL)) { d1378 1 a1378 2 if (ln != NULL) nd6_llinfo_settimer_locked(ln, 0); d1380 1 a1380 1 if ((rt->rt_flags & RTF_CLONING) != 0) d1411 1 a1411 2 /* FALLTHROUGH */ case RTM_RESOLVE: a1429 67 if (ln != NULL) break; /* This happens on a route change */ RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); /* Determine to use lo0ifp or not before lla_create */ ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &satocsin6(rt_getkey(rt))->sin6_addr); RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); if (ifa != NULL && nd6_useloopback) use_lo0ifp = true; /* * Case 2: This route may come from cloning, or a manual route * add with a LL address. */ flags = LLE_EXCLUSIVE; if ((rt->rt_flags & RTF_CLONED) == 0) flags |= LLE_IFADDR; #define _IFP() (use_lo0ifp ? lo0ifp : ifp) IF_AFDATA_WLOCK(_IFP()); ln = lla_create(LLTABLE6(_IFP()), flags, rt_getkey(rt)); IF_AFDATA_WUNLOCK(_IFP()); RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); if (ln == NULL) { log(LOG_DEBUG, "nd6_rtrequest: malloc failed\n"); break; } RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); nd6_inuse++; nd6_allocated++; ln->ln_rt = rt; rt->rt_refcnt++; rt->rt_llinfo = ln; LLE_ADDREF(ln); rt->rt_flags |= RTF_LLINFO; switch (_IFP()->if_type) { #if NTOKEN > 0 case IFT_ISO88025: ln->la_opaque = kmem_alloc(sizeof(struct token_rif), KM_SLEEP); break; #endif /* NTOKEN > 0 */ default: break; } #undef _IFP /* this is required for "ndp" command. - shin */ if (req == RTM_ADD) { /* * gate should have some valid AF_LINK entry, * and ln->ln_expire should have some lifetime * which is specified by ndp command. */ ln->ln_state = ND6_LLINFO_REACHABLE; ln->ln_byhint = 0; } else { /* * When req == RTM_RESOLVE, rt is created and * initialized in rtrequest(), so rt_expire is 0. */ ln->ln_state = ND6_LLINFO_NOSTATE; nd6_llinfo_settimer_locked(ln, 0); } d1436 2 a1438 16 const void *mac; nd6_llinfo_settimer_locked(ln, -1); ln->ln_state = ND6_LLINFO_REACHABLE; ln->ln_byhint = 0; if ((mac = nd6_ifptomac(ifp)) != NULL) { /* XXX check for error */ if (sockaddr_dl_setaddr(satosdl(gate), gate->sa_len, mac, ifp->if_addrlen) == NULL) { printf("%s.%d: " "sockaddr_dl_setaddr(, %d, ) " "failed on %s\n", __func__, __LINE__, gate->sa_len, if_name(ifp)); } } a1450 2 rt->rt_rmx.rmx_mtu = 0; rt->rt_flags &= ~RTF_CLONED; a1451 1 rt->rt_flags |= RTF_LOCAL; a1452 4 nd6_llinfo_settimer_locked(ln, -1); ln->ln_state = ND6_LLINFO_REACHABLE; ln->ln_byhint = 0; d1464 1 a1464 1 break; d1472 2 a1473 1 LLE_WUNLOCK(ln); d1478 2 a1479 3 nd6_gc_neighbors(ln->lle_tbl); ln = NULL; a1482 2 if (ln == NULL) break; d1500 1 a1500 51 nd6_inuse--; rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; /* Have to do before IF_AFDATA_WLOCK to avoid deadlock */ callout_halt(&ln->la_timer, &ln->lle_lock); /* XXX: LOR avoidance. We still have ref on lle. */ LLE_RUNLOCK(ln); IF_AFDATA_WLOCK(ifp); LLE_WLOCK(ln); clear_llinfo_pqueue(ln); if (ln->la_opaque != NULL) { switch (ifp->if_type) { #if NTOKEN > 0 case IFT_ISO88025: kmem_free(ln->la_opaque, sizeof(struct token_rif)); break; #endif /* NTOKEN > 0 */ default: break; } } if (ln->la_rt != NULL) { /* * Don't rtfree (may actually free objects) here. * Leave it to rtrequest1. */ ln->la_rt->rt_refcnt--; ln->la_rt = NULL; } /* Guard against race with other llentry_free(). */ if (ln->la_flags & LLE_LINKED) { LLE_REMREF(ln); llentry_free(ln); } else { LLE_FREE_LOCKED(ln); } IF_AFDATA_WUNLOCK(ifp); ln = NULL; } if (ln != NULL) { if (flags & LLE_EXCLUSIVE) LLE_WUNLOCK(ln); else LLE_RUNLOCK(ln); a1785 1 struct rtentry *rt; d1790 1 a1790 10 s = splsoftnet(); rt = nd6_lookup(&nb_addr, 0, ifp); if (rt == NULL) { error = EINVAL; splx(s); break; } ln = rt->rt_llinfo; rtfree(rt); a1792 1 splx(s); d1800 1 a1800 1 splx(s); d1814 1 a1814 2 nd6_llinfo_release_pkts(struct llentry *ln, struct ifnet *ifp, struct rtentry *rt) d1817 5 d1823 4 a1826 3 for (m_hold = ln->la_hold, ln->la_hold = NULL, ln->la_numheld = 0; m_hold != NULL; m_hold = m_hold_next) { d1835 1 a1835 1 nd6_output(ifp, ifp, m_hold, satocsin6(rt_getkey(rt)), rt); d1837 1 a1854 1 struct rtentry *rt = NULL; a1856 1 struct sockaddr_dl *sdl = NULL; d1861 1 d1880 2 a1881 2 rt = nd6_lookup(from, 0, ifp); if (rt == NULL) { d1888 1 a1888 1 rt = nd6_lookup(from, 1, ifp); d1892 2 a1893 2 if (rt->rt_flags & RTF_STATIC) { rtfree(rt); d1899 1 a1899 8 if (rt == NULL) return; if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) { fail: if (rt->rt_llinfo != NULL) LLE_WLOCK((struct llentry *)rt->rt_llinfo); nd6_free(rt, rt->rt_llinfo, 0); rtfree(rt); a1900 9 } ln = rt->rt_llinfo; if (ln == NULL) goto fail; if (rt->rt_gateway == NULL) goto fail; if (rt->rt_gateway->sa_family != AF_LINK) goto fail; sdl = satosdl(rt->rt_gateway); d1902 1 a1902 1 olladdr = (sdl->sdl_alen) ? 1 : 0; d1904 1 a1904 4 if (memcmp(lladdr, CLLADDR(sdl), ifp->if_addrlen)) llchange = 1; else llchange = 0; d1924 2 a1925 7 /* XXX check for error */ if (sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr, ifp->if_addrlen) == NULL) { printf("%s.%d: sockaddr_dl_setaddr(, %d, ) " "failed on %s\n", __func__, __LINE__, sdl->sdl_len, if_name(ifp)); } d1958 1 a1958 1 nd6_llinfo_release_pkts(ln, ifp, rt); d2030 2 d2034 13 d2063 1 a2063 1 if (do_update && ln->ln_router && !ip6_forwarding && a2065 2 rtfree(rt); d2096 3 a2098 6 /* * Next hop determination. This routine was derived from ether_output. */ static int nd6_determine_nexthop(struct ifnet *ifp, const struct sockaddr_in6 *dst, struct rtentry *rt00, struct rtentry **ret_rt, bool *sendpkt) a2099 86 struct rtentry *rt, *rt0; struct rtentry *gwrt; struct sockaddr_in6 *gw6; #define RTFREE_IF_NEEDED(_rt) \ if ((_rt) != NULL && (_rt) != rt00) \ rtfree((_rt)); KASSERT(rt00 != NULL); rt = rt0 = rt00; if ((rt->rt_flags & RTF_UP) == 0) { rt0 = rt = rtalloc1(sin6tocsa(dst), 1); if (rt == NULL) goto hostunreach; if (rt->rt_ifp != ifp) goto hostunreach; } if ((rt->rt_flags & RTF_GATEWAY) == 0) goto out; gw6 = (struct sockaddr_in6 *)rt->rt_gateway; /* * We skip link-layer address resolution and NUD * if the gateway is not a neighbor from ND point * of view, regardless of the value of nd_ifinfo.flags. * The second condition is a bit tricky; we skip * if the gateway is our own address, which is * sometimes used to install a route to a p2p link. */ if (!nd6_is_addr_neighbor(gw6, ifp) || in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { /* * We allow this kind of tricky route only * when the outgoing interface is p2p. * XXX: we may need a more generic rule here. */ if ((ifp->if_flags & IFF_POINTOPOINT) == 0) goto hostunreach; *sendpkt = true; goto out; } /* Try to use a cached nexthop route (gwroute) if exists */ gwrt = rt_get_gwroute(rt); if (gwrt == NULL) goto lookup; RTFREE_IF_NEEDED(rt); rt = gwrt; if ((rt->rt_flags & RTF_UP) == 0) { RTFREE_IF_NEEDED(rt); rt = rt0; lookup: /* Look up a nexthop route */ gwrt = rtalloc1(rt->rt_gateway, 1); rt_set_gwroute(rt, gwrt); RTFREE_IF_NEEDED(rt); rt = gwrt; if (rt == NULL) goto hostunreach; /* the "G" test below also prevents rt == rt0 */ if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_ifp != ifp)) { if (rt0->rt_gwroute != NULL) rtfree(rt0->rt_gwroute); rt0->rt_gwroute = NULL; goto hostunreach; } } out: *ret_rt = rt; return 0; hostunreach: RTFREE_IF_NEEDED(rt); return EHOSTUNREACH; #undef RTFREE_IF_NEEDED } a2100 6 int nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, const struct sockaddr_in6 *dst, struct rtentry *rt0) { struct mbuf *m = m0; struct rtentry *rt = rt0; d2103 1 a2103 4 #define RTFREE_IF_NEEDED(_rt) \ if ((_rt) != NULL && (_rt) != rt0) \ rtfree((_rt)); a2110 12 if (rt) { struct rtentry *nexthop = NULL; bool sendpkt = false; error = nd6_determine_nexthop(ifp, dst, rt, &nexthop, &sendpkt); if (error != 0) senderr(error); rt = nexthop; if (sendpkt) goto sendpkt; } d2119 2 a2120 3 if (rt != NULL && (rt->rt_flags & RTF_LLINFO) != 0) ln = rt->rt_llinfo; else { d2126 3 a2128 6 if (nd6_is_addr_neighbor(dst, ifp)) { RTFREE_IF_NEEDED(rt); rt = nd6_lookup(&dst->sin6_addr, 1, ifp); if (rt != NULL) ln = rt->rt_llinfo; } d2130 2 a2131 1 if (ln == NULL || rt == NULL) { a2139 1 d2143 2 d2212 1 a2212 2 nd6_llinfo_settimer(ln, ND_IFINFO(ifp)->retrans * hz / 1000); d2214 2 d2217 3 d2221 1 d2232 3 d2251 2 a2252 1 RTFREE_IF_NEEDED(rt); d2255 1 a2255 1 #undef RTFREE_IF_NEEDED a2256 1 #undef senderr d2283 55 d2343 1 a2343 1 const struct sockaddr_dl *sdl; d2365 7 a2371 1 if (rt == NULL) { d2376 3 a2378 11 if (rt->rt_gateway->sa_family != AF_LINK) { char gbuf[256]; char dbuf[LINK_ADDRSTRLEN]; sockaddr_format(rt->rt_gateway, gbuf, sizeof(gbuf)); printf("%s: bad gateway address type %s for dst %s" " through interface %s\n", __func__, gbuf, IN6_PRINT(dbuf, &satocsin6(dst)->sin6_addr), if_name(ifp)); m_freem(m); return 0; } d2391 5 a2396 1 memcpy(lldst, CLLADDR(sdl), MIN(dstsize, sdl->sdl_alen)); @ 1.186 log @Tidy up nd6_timer initialization @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.185 2016/02/04 02:48:37 riastradh Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.185 2016/02/04 02:48:37 riastradh Exp $"); d341 1 a341 1 nd6log((LOG_INFO, d343 1 a343 1 nd_opt->nd_opt_type)); d363 1 a363 1 nd6log((LOG_DEBUG, d365 1 a365 1 "option ignored\n", nd_opt->nd_opt_type)); d372 1 a372 1 nd6log((LOG_INFO, "too many loop in nd opt\n")); d991 1 a991 1 nd6log((LOG_DEBUG, d994 1 a994 1 ifp ? if_name(ifp) : "unspec")); d1566 1 a1566 1 nd6log((LOG_ERR, "%s: failed to join " d1568 1 a1568 1 ip6_sprintf(&llsol), error)); @ 1.185 log @Declare in6_tmpaddrtimer_ch in in6_var.h. Do not declare extern variables in .c files! @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.184 2016/01/08 08:50:07 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.184 2016/01/08 08:50:07 ozaki-r Exp $"); d126 1 d129 2 a130 2 callout_t nd6_slowtimo_ch; callout_t nd6_timer_ch; a139 6 static int nd6_init_done = 0; if (nd6_init_done) { log(LOG_NOTICE, "nd6_init called more than once(ignored)\n"); return; } a143 2 nd6_init_done = 1; d150 1 d589 1 a589 1 void @ 1.184 log @Add missing RTF_LOCAL; sync with arp_setgate @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.183 2015/12/18 09:04:33 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.183 2015/12/18 09:04:33 ozaki-r Exp $"); a129 1 extern callout_t in6_tmpaddrtimer_ch; @ 1.183 log @Add missing LLE_WUNLOCK to nd6_free @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.182 2015/12/07 06:19:13 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.182 2015/12/07 06:19:13 ozaki-r Exp $"); d1373 1 a1373 1 ((rt->rt_flags & RTF_LLINFO) && ln == NULL)) { @ 1.182 log @CID 1341546: Fix integer handling issue (CONSTANT_EXPRESSION_RESULT) n > INT_MAX where n is a long integer variable never be true on 32bit architectures. Use time_t(int64_t) instead of long for the variable. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.181 2015/11/25 06:21:26 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.181 2015/11/25 06:21:26 ozaki-r Exp $"); d1141 1 @ 1.181 log @Use lltable/llentry for NDP lltable and llentry were introduced to replace ARP cache data structure for further restructuring of the routing table: L2 nexthop cache separation. This change replaces the NDP cache data structure (llinfo_nd6) with them as well as ARP. One noticeable change is for neighbor cache GC mechanism that was introduced to prevent IPv6 DoS attacks. net.inet6.ip6.neighborgcthresh was the max number of caches that we store in the system. After introducing lltable/llentry, the value is changed to be per-interface basis because lltable/llentry stores neighbor caches in each interface separately. And the change brings one degradation; the old GC mechanism dropped exceeded packets based on LRU while the new implementation drops packets in order from the beginning of lltable (a hash table + linked lists). It would be improved in the future. Added functions in in6.c come from FreeBSD (as of r286629) and are tweaked for NetBSD. Proposed on tech-kern and tech-net. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.180 2015/11/19 03:02:10 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.180 2015/11/19 03:02:10 ozaki-r Exp $"); d394 1 a394 1 nd6_llinfo_settimer_locked(struct llentry *ln, long xtick) d397 1 d420 1 a420 1 nd6_llinfo_settimer(struct llentry *ln, long xtick) d539 1 a539 1 nd6_llinfo_settimer_locked(ln, (long)nd6_gctimer * hz); d561 1 a561 1 nd6_llinfo_settimer_locked(ln, (long)nd6_gctimer * hz); d579 1 a579 1 nd6_llinfo_settimer_locked(ln, (long)ndi->retrans * hz / 1000); d1139 1 a1139 1 (long)nd6_gctimer * hz); d1234 1 a1234 1 (long)ND_IFINFO(rt->rt_ifp)->reachable * hz); d2144 1 a2144 1 nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz); d2436 1 a2436 1 nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz); d2449 1 a2449 1 nd6_llinfo_settimer(ln, (long)nd6_delay * hz); d2500 1 a2500 1 (long)ND_IFINFO(ifp)->retrans * hz / 1000); @ 1.180 log @Call icmp6_error2 after releasing ln This is a restructuring for coming changes. From FreeBSD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.179 2015/11/18 05:16:22 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.179 2015/11/18 05:16:22 ozaki-r Exp $"); d62 1 a107 4 struct llinfo_nd6 llinfo_nd6 = { .ln_prev = &llinfo_nd6, .ln_next = &llinfo_nd6, }; d124 1 a124 1 static struct llinfo_nd6 *nd6_free(struct rtentry *, int); d126 1 a126 1 static void clear_llinfo_pqueue(struct llinfo_nd6 *); a136 10 #define LN_DEQUEUE(ln) do { \ (ln)->ln_next->ln_prev = (ln)->ln_prev; \ (ln)->ln_prev->ln_next = (ln)->ln_next; \ } while (/*CONSTCOND*/0) #define LN_INSERTHEAD(ln) do { \ (ln)->ln_next = llinfo_nd6.ln_next; \ llinfo_nd6.ln_next = (ln); \ (ln)->ln_prev = &llinfo_nd6; \ (ln)->ln_next->ln_prev = (ln); \ } while (/*CONSTCOND*/0) d394 1 a394 1 nd6_llinfo_settimer(struct llinfo_nd6 *ln, long xtick) a395 1 int s; d397 1 a397 1 s = splsoftnet(); d402 1 a402 1 callout_stop(&ln->ln_timer_ch); d405 1 d416 5 d422 3 a424 1 splx(s); d433 1 a433 1 nd6_llinfo_get_holdsrc(struct llinfo_nd6 *ln, struct in6_addr *src) d456 1 a456 1 struct llinfo_nd6 *ln; d467 5 a471 1 ln = (struct llinfo_nd6 *)arg; d473 18 a490 5 if (ln->ln_ntick > 0) { nd6_llinfo_settimer(ln, ln->ln_ntick); KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); return; d493 1 d495 1 a496 1 ifp = rt->rt_ifp; d503 1 a503 1 if (rt->rt_llinfo && (struct llinfo_nd6 *)rt->rt_llinfo != ln) d528 1 a528 1 (void)nd6_free(rt, 0); d538 1 a538 1 nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz); d546 1 a546 1 (void)nd6_free(rt, 1); d560 1 a560 1 nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz); d569 1 a569 1 (void)nd6_free(rt, 0); d578 1 a578 1 nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000); d580 2 d585 3 a805 1 struct llinfo_nd6 *ln, *nln; d881 6 a886 4 * Nuke neighbor cache entries for the ifp. * Note that rt->rt_ifp may not be the same as ifp, * due to KAME goto ours hack. See RTM_RESOLVE case in * nd6_rtrequest(), and ip6_input(). d888 2 a889 15 ln = llinfo_nd6.ln_next; while (ln != NULL && ln != &llinfo_nd6) { struct rtentry *rt; const struct sockaddr_dl *sdl; nln = ln->ln_next; rt = ln->ln_rt; if (rt && rt->rt_gateway && rt->rt_gateway->sa_family == AF_LINK) { sdl = satocsdl(rt->rt_gateway); if (sdl->sdl_index == ifp->if_index) nln = nd6_free(rt, 0); } ln = nln; } d951 1 a951 2 struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; d1094 2 a1095 2 static struct llinfo_nd6 * nd6_free(struct rtentry *rt, int gc) a1096 1 struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next; d1101 4 d1111 1 a1111 1 nd6_llinfo_settimer(ln, -1); d1134 1 a1134 1 nd6_llinfo_settimer(ln, d1137 2 a1138 1 nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz); d1140 1 a1140 1 return ln->ln_next; d1184 1 a1184 8 /* * Before deleting the entry, remember the next entry as the * return value. We need this because pfxlist_onlink_check() above * might have freed other entries (particularly the old next entry) as * a side effect (XXX). */ next = ln->ln_next; a1194 2 return next; d1205 1 a1205 1 struct llinfo_nd6 *ln; d1218 1 a1218 1 ln = (struct llinfo_nd6 *)rt->rt_llinfo; d1239 38 d1281 1 a1281 1 struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; d1285 2 d1334 4 d1394 1 a1394 1 nd6_llinfo_settimer(ln, 0); d1450 8 d1462 9 a1470 2 R_Malloc(ln, struct llinfo_nd6 *, sizeof(*ln)); rt->rt_llinfo = ln; d1476 1 a1479 1 memset(ln, 0, sizeof(*ln)); d1481 16 a1496 1 callout_init(&ln->ln_timer_ch, CALLOUT_MPSAFE); d1512 1 a1512 1 nd6_llinfo_settimer(ln, 0); a1514 5 rt->rt_flags |= RTF_LLINFO; ln->ln_next = llinfo_nd6.ln_next; llinfo_nd6.ln_next = ln; ln->ln_prev = &llinfo_nd6; ln->ln_next->ln_prev = ln; a1516 30 * If we have too many cache entries, initiate immediate * purging for some "less recently used" entries. Note that * we cannot directly call nd6_free() here because it would * cause re-entering rtable related routines triggering an LOR * problem for FreeBSD. */ if (ip6_neighborgcthresh >= 0 && nd6_inuse >= ip6_neighborgcthresh) { int i; for (i = 0; i < 10 && llinfo_nd6.ln_prev != ln; i++) { struct llinfo_nd6 *ln_end = llinfo_nd6.ln_prev; /* Move this entry to the head */ LN_DEQUEUE(ln_end); LN_INSERTHEAD(ln_end); if (ND6_LLINFO_PERMANENT(ln_end)) continue; if (ln_end->ln_state > ND6_LLINFO_INCOMPLETE) ln_end->ln_state = ND6_LLINFO_STALE; else ln_end->ln_state = ND6_LLINFO_PURGE; nd6_llinfo_settimer(ln_end, 0); } } RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); /* a1519 3 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &satocsin6(rt_getkey(rt))->sin6_addr); RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1522 1 a1522 1 nd6_llinfo_settimer(ln, -1); d1554 1 a1554 1 nd6_llinfo_settimer(ln, -1); d1577 8 d1608 1 a1608 5 ln->ln_next->ln_prev = ln->ln_prev; ln->ln_prev->ln_next = ln->ln_next; ln->ln_prev = NULL; nd6_llinfo_settimer(ln, -1); rt->rt_llinfo = 0; d1610 9 d1620 38 a1657 1 Free(ln); d1941 1 a1941 1 struct llinfo_nd6 *ln; d1956 1 a1956 1 ln = (struct llinfo_nd6 *)rt->rt_llinfo; d1982 1 a1982 1 nd6_llinfo_release_pkts(struct llinfo_nd6 *ln, struct ifnet *ifp, d1987 1 a1987 1 for (m_hold = ln->ln_hold, ln->ln_hold = NULL; d2018 1 a2018 1 struct llinfo_nd6 *ln = NULL; d2066 3 a2068 1 (void)nd6_free(rt, 0); d2072 1 a2072 1 ln = (struct llinfo_nd6 *)rt->rt_llinfo; d2370 1 a2370 1 struct llinfo_nd6 *ln = NULL; d2404 1 a2404 1 ln = (struct llinfo_nd6 *)rt->rt_llinfo; d2415 1 a2415 1 ln = (struct llinfo_nd6 *)rt->rt_llinfo; a2430 8 /* * Move this entry to the head of the queue so that it is less likely * for this entry to be a target of forced garbage collection (see * nd6_rtrequest()). */ LN_DEQUEUE(ln); LN_INSERTHEAD(ln); d2622 1 a2622 1 clear_llinfo_pqueue(struct llinfo_nd6 *ln) @ 1.179 log @Stop passing llinfo_nd6 to nd6_ns_output This is a restructuring for coming changes to nd6 (replacing llinfo_nd6 with llentry). Once we have a lock of llinfo_nd6, we need to pass it to nd6_ns_output with holding the lock. However, in a function subsequent to nd6_ns_output, the llinfo_nd6 may be looked up, i.e., its lock would be acquired again. To avoid such a situation, pass only required data (in6_addr) to nd6_ns_output instead of passing whole llinfo_nd6. Inspired by FreeBSD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.178 2015/11/18 02:51:11 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.178 2015/11/18 02:51:11 ozaki-r Exp $"); a512 3 icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, rt->rt_ifp); d518 3 @ 1.178 log @Unify nd6_ns_output calls in nd6_llinfo_timer Inspired by FreeBSD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.177 2015/09/11 10:33:32 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.177 2015/09/11 10:33:32 roy Exp $"); d433 26 d564 2 d567 2 a568 1 nd6_ns_output(ifp, daddr6, &dst->sin6_addr, ln, 0); d2416 2 d2421 2 a2422 1 nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); @ 1.177 log @If, for whatever reason, a local interface route is removed and then re-added, mark it as a local route. While here, if changing the route to go via the loopback interface remove any inherited MTU value. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.176 2015/09/04 05:33:23 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.176 2015/09/04 05:33:23 ozaki-r Exp $"); d441 2 d475 1 a475 2 nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000); nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); d518 2 a519 3 nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000); nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); d528 2 a529 3 nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000); nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); d537 5 @ 1.176 log @Pull nexthop determination routine from nd6_output It simplifies nd6_output and the nexthop determination routine slightly. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.175 2015/09/03 00:54:39 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.175 2015/09/03 00:54:39 ozaki-r Exp $"); d1481 1 d1484 1 @ 1.175 log @Fix rtfree in nd6_output We have to check and avoid to rtfree the original rtentry passed to nd6_output even when manipulating gateway routes. This fixes panic on assertion "ro->_ro_rt ==NULL || ro->_ro_rt->rt_refcnt > 0" failure and probably PR kern/50161. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.174 2015/09/02 11:35:11 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.174 2015/09/02 11:35:11 ozaki-r Exp $"); d2148 93 d2244 1 a2244 1 const struct sockaddr_in6 *dst, struct rtentry *rt00) d2247 1 a2247 2 struct rtentry *rt, *rt0; struct sockaddr_in6 *gw6 = NULL; d2252 1 a2252 1 if ((_rt) != NULL && (_rt) != rt00) \ a2254 2 rt = rt0 = rt00; a2260 3 /* * next hop determination. This routine is derived from ether_output. */ d2262 2 a2263 29 if ((rt->rt_flags & RTF_UP) == 0) { if ((rt0 = rt = rtalloc1(sin6tocsa(dst), 1)) != NULL) { if (rt->rt_ifp != ifp) senderr(EHOSTUNREACH); } else senderr(EHOSTUNREACH); } if (rt->rt_flags & RTF_GATEWAY) { struct rtentry *gwrt; gw6 = (struct sockaddr_in6 *)rt->rt_gateway; /* * We skip link-layer address resolution and NUD * if the gateway is not a neighbor from ND point * of view, regardless of the value of nd_ifinfo.flags. * The second condition is a bit tricky; we skip * if the gateway is our own address, which is * sometimes used to install a route to a p2p link. */ if (!nd6_is_addr_neighbor(gw6, ifp) || in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { /* * We allow this kind of tricky route only * when the outgoing interface is p2p. * XXX: we may need a more generic rule here. */ if ((ifp->if_flags & IFF_POINTOPOINT) == 0) senderr(EHOSTUNREACH); d2265 6 a2270 29 goto sendpkt; } gwrt = rt_get_gwroute(rt); if (gwrt == NULL) goto lookup; RTFREE_IF_NEEDED(rt); rt = gwrt; if ((rt->rt_flags & RTF_UP) == 0) { RTFREE_IF_NEEDED(rt); rt = rt0; lookup: gwrt = rtalloc1(rt->rt_gateway, 1); rt_set_gwroute(rt, gwrt); RTFREE_IF_NEEDED(rt); rt = gwrt; if (rt == NULL) senderr(EHOSTUNREACH); /* the "G" test below also prevents rt == rt0 */ if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_ifp != ifp)) { if (rt0->rt_gwroute != NULL) rtfree(rt0->rt_gwroute); rt0->rt_gwroute = NULL; senderr(EHOSTUNREACH); } } } @ 1.174 log @Do rt_refcnt++ when set a rtentry to another rtentry's rt_gwroute And also do rtfree when deref a rtentry from rt_gwroute. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.173 2015/09/02 08:03:10 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.173 2015/09/02 08:03:10 ozaki-r Exp $"); d2215 1 a2215 1 rtfree(rt); d2220 1 a2220 1 rtfree(rt); @ 1.173 log @Use KASSERT to check programming errors @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.172 2015/09/01 08:52:02 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.172 2015/09/01 08:52:02 ozaki-r Exp $"); d2218 2 a2219 2 gwrt = rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); d2227 2 @ 1.172 log @Move a rtentry definition to reduce its scope No functional change. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.171 2015/09/01 08:46:27 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.171 2015/09/01 08:46:27 ozaki-r Exp $"); d454 5 a458 4 if ((rt = ln->ln_rt) == NULL) panic("ln->ln_rt == NULL"); if ((ifp = rt->rt_ifp) == NULL) panic("ln->ln_rt->rt_ifp == NULL"); @ 1.171 log @Cleanup nd6_nud_hint The deleted rtfree was never called. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.170 2015/08/31 03:26:53 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.170 2015/08/31 03:26:53 ozaki-r Exp $"); a1549 1 struct rtentry *rt; d1822 1 @ 1.170 log @Remove leading whitespaces @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.169 2015/08/24 22:21:27 pooka Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.169 2015/08/24 22:21:27 pooka Exp $"); d1170 1 a1170 1 nd6_nud_hint(struct rtentry *rt0) a1172 1 struct rtentry *rt = rt0; d1182 1 a1182 1 goto exit; d1187 1 a1187 1 goto exit; d1195 1 a1195 1 goto exit; d1202 1 a1202 3 exit: if (rt != rt0) rtfree(rt); @ 1.169 log @sprinkle _KERNEL_OPT @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.168 2015/08/11 09:30:32 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.168 2015/08/11 09:30:32 ozaki-r Exp $"); d2130 1 a2130 1 callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, @ 1.168 log @Fix double rtfree @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.167 2015/08/11 08:27:08 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.167 2015/08/11 08:27:08 ozaki-r Exp $"); d36 1 d38 1 @ 1.167 log @Free rtentry when we successfully obtain it but return NULL @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.166 2015/08/07 08:11:33 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.166 2015/08/07 08:11:33 ozaki-r Exp $"); a2250 3 if (rt != NULL && rt != rt00) rtfree(rt); @ 1.166 log @Use time_uptime instead of time_second to avoid time leaps Some codes in sys/net* use time_second to manage time periods such as cache expirations. However, time_second doesn't increase monotonically and can leap by say settimeofday(2) according to time_second(9). We should use time_uptime instead of it to avoid such time leaps. This change replaces time_second with time_uptime. Additionally it converts a time based on time_uptime to a time based on time_second when the kernel passes the time to userland programs that expect the latter, and vice versa. Note that we shouldn't leak time_uptime to other hosts over the netowrk. My investigation shows there is no such leak: http://mail-index.netbsd.org/tech-net/2015/08/06/msg005332.html Discussed on tech-kern and tech-net. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.165 2015/07/17 02:21:08 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.165 2015/07/17 02:21:08 ozaki-r Exp $"); d962 1 @ 1.165 log @Reform use of rt_refcnt rt_refcnt of rtentry was used in bad manners, for example, direct rt_refcnt++ and rt_refcnt-- outside route.c, "rt->rt_refcnt++; rtfree(rt);" idiom, and touching rt after rt->rt_refcnt--. These abuses seem to be needed because rt_refcnt manages only references between rtentry and doesn't take care of references during packet processing (IOW references from local variables). In order to reduce the above abuses, the latter cases should be counted by rt_refcnt as well as the former cases. This change improves consistency of use of rt_refcnt: - rtentry is always accessed with rt_refcnt incremented - rtentry's rt_refcnt is decremented after use (rtfree is always used instead of rt_refcnt--) - functions returning rtentry increment its rt_refcnt (and caller rtfree it) Note that rt_refcnt prevents rtentry from being freed but doesn't prevent rtentry from being updated. Toward MP-safe, we need to provide another protection for rtentry, e.g., locks. (Or introduce a better data structure allowing concurrent readers during updates.) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.164 2015/07/15 09:20:18 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.164 2015/07/15 09:20:18 ozaki-r Exp $"); d416 1 a416 1 ln->ln_expire = time_second + xtick / hz; d558 1 a558 1 if (dr->expire && dr->expire < time_second) { d650 1 a650 1 time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) { d1089 1 a1089 1 if (dr->expire > time_second) d1091 1 a1091 1 (dr->expire - time_second) * hz); d1569 2 a1570 1 drl->defrouter[i].expire = dr->expire; d1614 5 a1618 3 oprl->prefix[i].expire = pr->ndpr_lastupdate + pr->ndpr_vltime; d1845 2 a1846 1 nbi->expire = ln->ln_expire; d2564 2 a2565 1 d->expire = dr->expire; @ 1.164 log @Remove unused arguments and the associated code from nd6_nud_hint() from OpenBSD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.163 2015/06/30 08:31:42 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.163 2015/06/30 08:31:42 ozaki-r Exp $"); a915 1 rt->rt_refcnt--; d982 1 d1038 3 a1040 1 if (nd6_lookup1(&addr->sin6_addr, 0, ifp, 1) != NULL) d1042 1 d1059 1 a1059 1 struct rtentry *oldrt; d1152 4 a1155 8 oldrt = NULL; rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, &oldrt); if (oldrt) { rt_newmsg(RTM_DELETE, oldrt); /* tell user process */ if (oldrt->rt_refcnt <= 0) { oldrt->rt_refcnt++; rtfree(oldrt); } d1167 1 a1167 1 nd6_nud_hint(struct rtentry *rt) d1170 1 d1180 1 a1180 1 return; d1185 1 a1185 1 return; d1193 1 a1193 1 return; d1200 4 d1825 10 a1834 2 if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL || (ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) { d1881 1 a1881 1 struct rtentry * d1906 1 a1906 1 return NULL; d1930 4 a1933 2 if (rt->rt_flags & RTF_STATIC) return NULL; d1938 1 a1938 1 return NULL; d1942 2 a1943 1 return NULL; d2112 1 a2112 1 return rt; d2146 1 a2146 1 const struct sockaddr_in6 *dst, struct rtentry *rt0) d2149 1 a2149 1 struct rtentry *rt = rt0; d2154 6 a2171 1 rt->rt_refcnt--; d2179 1 d2203 2 a2204 1 if (rt->rt_gwroute == NULL) d2206 6 a2211 2 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { rtfree(rt); rt = rt0; d2213 5 a2217 2 rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); if ((rt = rt->rt_gwroute) == NULL) a2221 1 rt->rt_refcnt--; d2245 9 a2253 3 if (nd6_is_addr_neighbor(dst, ifp) && (rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL) ln = (struct llinfo_nd6 *)rt->rt_llinfo; d2345 2 a2346 1 return 0; d2365 1 a2365 1 return error; d2370 3 d2374 1 @ 1.163 log @Use KASSERT for argument NULL checks @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.162 2015/04/30 10:00:04 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.162 2015/04/30 10:00:04 ozaki-r Exp $"); d1168 1 a1168 1 nd6_nud_hint(struct rtentry *rt, struct in6_addr *dst6, int force) d1172 2 a1173 10 /* * If the caller specified "rt", use that. Otherwise, resolve the * routing table by supplied "dst6". */ if (rt == NULL) { if (dst6 == NULL) return; if ((rt = nd6_lookup(dst6, 0, NULL)) == NULL) return; } d1191 3 a1193 5 if (!force) { ln->ln_byhint++; if (ln->ln_byhint > nd6_maxnudhint) return; } @ 1.162 log @Don't take KERNEL_LOCK for if_output when NET_MPSAFE @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.161 2015/03/30 04:25:26 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.161 2015/03/30 04:25:26 ozaki-r Exp $"); d282 3 a284 4 if (ndopts == NULL) panic("ndopts == NULL in nd6_option"); if (ndopts->nd_opts_last == NULL) panic("uninitialized ndopts in nd6_option"); d332 3 a334 4 if (ndopts == NULL) panic("ndopts == NULL in nd6_options"); if (ndopts->nd_opts_last == NULL) panic("uninitialized ndopts in nd6_options"); d1899 2 a1900 4 if (ifp == NULL) panic("ifp == NULL in nd6_cache_lladdr"); if (from == NULL) panic("from == NULL in nd6_cache_lladdr"); @ 1.161 log @Tidy up opt_ipsec.h inclusions @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.160 2015/02/25 12:45:34 roy Exp $ */ d34 3 a36 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.160 2015/02/25 12:45:34 roy Exp $"); d2334 1 d2336 1 d2341 1 d2343 1 @ 1.160 log @Rename nd6_rtmsg() to rt_newmsg() and move into the generic routing code as it's not IPv6 specific and will be used elsewhere. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.159 2015/02/25 00:26:58 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.159 2015/02/25 00:26:58 roy Exp $"); a37 1 #include "opt_ipsec.h" @ 1.159 log @Retire nd6_newaddrmsg and use rt_newaddrmsg directly instead so that we don't spam route changes when the route hasn't changed. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.158 2015/02/23 19:15:59 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.158 2015/02/23 19:15:59 martin Exp $"); d1153 1 a1153 1 nd6_rtmsg(RTM_DELETE, oldrt); /* tell user process */ d2089 1 a2089 1 nd6_rtmsg(RTM_CHANGE, rt); /* tell user process */ @ 1.158 log @Rearange interface detachement slightly: before we free the INET6 specific per-interface data, make sure to call nd6_purge() with it to remove routing entries pointing to the going interface. When we should happen to call this function again later, with the data already gone, just return. Fixes PR kern/49682, ok: christos. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.157 2015/02/17 15:14:28 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.157 2015/02/17 15:14:28 christos Exp $"); d602 2 a603 1 nd6_newaddrmsg((struct ifaddr *)ia6); d637 2 a638 1 nd6_newaddrmsg((struct ifaddr *)ia6); @ 1.157 log @"something odd happens" is not a useful error message. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.156 2014/12/16 11:42:27 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.156 2014/12/16 11:42:27 roy Exp $"); d208 1 a208 1 nd6_ifdetach(struct nd_ifinfo *nd) d211 2 a212 1 free(nd, M_IP6NDP); d560 1 a560 1 defrtrlist_del(dr); d750 1 a750 1 nd6_purge(struct ifnet *ifp) d757 10 d776 4 a779 2 if (dr->ifp == ifp) defrtrlist_del(dr); d786 4 a789 2 if (dr->ifp == ifp) defrtrlist_del(dr); d1815 1 a1815 1 defrtrlist_del(drtr); @ 1.156 log @Report route additions/changes/deletions for cached neighbours to userland. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.155 2014/12/03 01:32:11 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.155 2014/12/03 01:32:11 christos Exp $"); d2389 7 a2395 1 printf("%s: something odd happens\n", __func__); @ 1.155 log @more debugging info... @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.154 2014/10/18 08:33:29 snj Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.154 2014/10/18 08:33:29 snj Exp $"); d1040 1 d1133 9 a1141 1 rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL); d2071 3 @ 1.154 log @src is too big these days to tolerate superfluous apostrophes. It's "its", people! @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.153 2014/10/14 15:29:43 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.153 2014/10/14 15:29:43 roy Exp $"); d2383 2 d2386 4 a2389 3 printf("%s: sdl_alen == %" PRIu8 ", dst=%s, if=%s\n", __func__, sdl->sdl_alen, ip6_sprintf(&satocsin6(dst)->sin6_addr), if_name(ifp)); @ 1.154.2.1 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.161 2015/03/30 04:25:26 ozaki-r Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.161 2015/03/30 04:25:26 ozaki-r Exp $"); d38 1 d208 1 a208 1 nd6_ifdetach(struct ifnet *ifp, struct in6_ifextra *ext) d211 1 a211 2 nd6_purge(ifp, ext); free(ext->nd_ifinfo, M_IP6NDP); d559 1 a559 1 defrtrlist_del(dr, NULL); d601 1 a601 2 rt_newaddrmsg(RTM_NEWADDR, (struct ifaddr *)ia6, 0, NULL); d635 1 a635 2 rt_newaddrmsg(RTM_NEWADDR, (struct ifaddr *)ia6, 0, NULL); d749 1 a749 1 nd6_purge(struct ifnet *ifp, struct in6_ifextra *ext) a755 10 * During detach, the ND info might be already removed, but * then is explitly passed as argument. * Otherwise get it from ifp->if_afdata. */ if (ext == NULL) ext = ifp->if_afdata[AF_INET6]; if (ext == NULL) return; /* d765 2 a766 4 if (dr->ifp == ifp) { KASSERT(ext != NULL); defrtrlist_del(dr, ext); } d773 2 a774 4 if (dr->ifp == ifp) { KASSERT(ext != NULL); defrtrlist_del(dr, ext); } a1039 1 struct rtentry *oldrt; d1132 1 a1132 9 oldrt = NULL; rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, &oldrt); if (oldrt) { rt_newmsg(RTM_DELETE, oldrt); /* tell user process */ if (oldrt->rt_refcnt <= 0) { oldrt->rt_refcnt++; rtfree(oldrt); } } d1791 1 a1791 1 defrtrlist_del(drtr, NULL); a2061 3 if (do_update) rt_newmsg(RTM_CHANGE, rt); /* tell user process */ d2377 1 a2377 7 char gbuf[256]; char dbuf[LINK_ADDRSTRLEN]; sockaddr_format(rt->rt_gateway, gbuf, sizeof(gbuf)); printf("%s: bad gateway address type %s for dst %s" " through interface %s\n", __func__, gbuf, IN6_PRINT(dbuf, &satocsin6(dst)->sin6_addr), if_name(ifp)); a2382 2 char sbuf[INET6_ADDRSTRLEN]; char dbuf[LINK_ADDRSTRLEN]; d2384 3 a2386 4 printf("%s: sdl_alen == %" PRIu8 ", if=%s, dst=%s, sdl=%s\n", __func__, sdl->sdl_alen, if_name(ifp), IN6_PRINT(sbuf, &satocsin6(dst)->sin6_addr), DL_PRINT(dbuf, &sdl->sdl_addr)); @ 1.154.2.2 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.154.2.1 2015/04/06 15:18:23 skrll Exp $ */ d34 1 a34 3 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.154.2.1 2015/04/06 15:18:23 skrll Exp $"); #include "opt_net_mpsafe.h" d337 1 a337 1 d556 1 a556 1 d1661 1 a1661 1 /* d1868 1 a1868 1 * just set the 2nd argument as the a2331 1 #ifndef NET_MPSAFE a2332 1 #endif a2336 1 #ifndef NET_MPSAFE a2337 1 #endif d2409 1 a2409 1 " through interface %s\n", __func__, gbuf, d2432 1 a2432 1 static void d2446 1 a2446 1 @ 1.154.2.3 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.154.2.2 2015/06/06 14:40:26 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.154.2.2 2015/06/06 14:40:26 skrll Exp $"); a35 1 #ifdef _KERNEL_OPT a36 1 #endif d282 4 a285 3 KASSERT(ndopts != NULL); KASSERT(ndopts->nd_opts_last != NULL); d333 4 a336 3 KASSERT(ndopts != NULL); KASSERT(ndopts->nd_opts_last != NULL); d418 1 a418 1 ln->ln_expire = time_uptime + xtick / hz; d454 4 a457 5 rt = ln->ln_rt; KASSERT(rt != NULL); ifp = rt->rt_ifp; KASSERT(ifp != NULL); d560 1 a560 1 if (dr->expire && dr->expire < time_uptime) { d652 1 a652 1 time_uptime - pr->ndpr_lastupdate > pr->ndpr_vltime) { d918 1 a964 1 rtfree(rt); a984 1 struct rtentry *rt; d1040 1 a1040 3 rt = nd6_lookup1(&addr->sin6_addr, 0, ifp, 1); if (rt != NULL) { rtfree(rt); a1041 1 } d1058 1 a1058 1 int error; d1088 1 a1088 1 if (dr->expire > time_uptime) d1090 1 a1090 1 (dr->expire - time_uptime) * hz); d1151 8 a1158 4 error = rtrequest_newmsg(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0); if (error != 0) { /* XXX need error message? */; d1170 1 a1170 1 nd6_nud_hint(struct rtentry *rt) d1174 10 a1183 2 if (rt == NULL) return; d1201 5 a1205 3 ln->ln_byhint++; if (ln->ln_byhint > nd6_maxnudhint) return; a1211 2 return; a1487 1 rt->rt_rmx.rmx_mtu = 0; a1489 1 rt->rt_flags |= RTF_LOCAL; d1558 1 d1577 1 a1577 2 drl->defrouter[i].expire = dr->expire ? time_mono_to_wall(dr->expire) : 0; d1621 3 a1623 5 time_t expire; expire = pr->ndpr_lastupdate + pr->ndpr_vltime; oprl->prefix[i].expire = expire ? time_mono_to_wall(expire) : 0; a1827 1 struct rtentry *rt; d1833 2 a1834 10 rt = nd6_lookup(&nb_addr, 0, ifp); if (rt == NULL) { error = EINVAL; splx(s); break; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; rtfree(rt); if (ln == NULL) { d1842 1 a1842 2 nbi->expire = ln->ln_expire ? time_mono_to_wall(ln->ln_expire) : 0; d1881 1 a1881 1 void d1901 4 a1904 2 KASSERT(ifp != NULL); KASSERT(from != NULL); d1908 1 a1908 1 return; d1932 2 a1933 4 if (rt->rt_flags & RTF_STATIC) { rtfree(rt); return; } d1938 1 a1938 1 return; d1942 1 a1942 2 rtfree(rt); return; d2111 1 a2111 1 rtfree(rt); d2122 1 a2122 1 callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, a2141 93 /* * Next hop determination. This routine was derived from ether_output. */ static int nd6_determine_nexthop(struct ifnet *ifp, const struct sockaddr_in6 *dst, struct rtentry *rt00, struct rtentry **ret_rt, bool *sendpkt) { struct rtentry *rt, *rt0; struct rtentry *gwrt; struct sockaddr_in6 *gw6; #define RTFREE_IF_NEEDED(_rt) \ if ((_rt) != NULL && (_rt) != rt00) \ rtfree((_rt)); KASSERT(rt00 != NULL); rt = rt0 = rt00; if ((rt->rt_flags & RTF_UP) == 0) { rt0 = rt = rtalloc1(sin6tocsa(dst), 1); if (rt == NULL) goto hostunreach; if (rt->rt_ifp != ifp) goto hostunreach; } if ((rt->rt_flags & RTF_GATEWAY) == 0) goto out; gw6 = (struct sockaddr_in6 *)rt->rt_gateway; /* * We skip link-layer address resolution and NUD * if the gateway is not a neighbor from ND point * of view, regardless of the value of nd_ifinfo.flags. * The second condition is a bit tricky; we skip * if the gateway is our own address, which is * sometimes used to install a route to a p2p link. */ if (!nd6_is_addr_neighbor(gw6, ifp) || in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { /* * We allow this kind of tricky route only * when the outgoing interface is p2p. * XXX: we may need a more generic rule here. */ if ((ifp->if_flags & IFF_POINTOPOINT) == 0) goto hostunreach; *sendpkt = true; goto out; } /* Try to use a cached nexthop route (gwroute) if exists */ gwrt = rt_get_gwroute(rt); if (gwrt == NULL) goto lookup; RTFREE_IF_NEEDED(rt); rt = gwrt; if ((rt->rt_flags & RTF_UP) == 0) { RTFREE_IF_NEEDED(rt); rt = rt0; lookup: /* Look up a nexthop route */ gwrt = rtalloc1(rt->rt_gateway, 1); rt_set_gwroute(rt, gwrt); RTFREE_IF_NEEDED(rt); rt = gwrt; if (rt == NULL) goto hostunreach; /* the "G" test below also prevents rt == rt0 */ if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_ifp != ifp)) { if (rt0->rt_gwroute != NULL) rtfree(rt0->rt_gwroute); rt0->rt_gwroute = NULL; goto hostunreach; } } out: *ret_rt = rt; return 0; hostunreach: RTFREE_IF_NEEDED(rt); return EHOSTUNREACH; #undef RTFREE_IF_NEEDED } d2149 1 a2152 4 #define RTFREE_IF_NEEDED(_rt) \ if ((_rt) != NULL && (_rt) != rt0) \ rtfree((_rt)); d2159 3 d2163 29 a2191 2 struct rtentry *nexthop = NULL; bool sendpkt = false; d2193 20 a2212 6 error = nd6_determine_nexthop(ifp, dst, rt, &nexthop, &sendpkt); if (error != 0) senderr(error); rt = nexthop; if (sendpkt) goto sendpkt; d2231 3 a2233 6 if (nd6_is_addr_neighbor(dst, ifp)) { RTFREE_IF_NEEDED(rt); rt = nd6_lookup(&dst->sin6_addr, 1, ifp); if (rt != NULL) ln = (struct llinfo_nd6 *)rt->rt_llinfo; } d2325 1 a2325 2 error = 0; goto exit; d2344 1 a2344 1 goto exit; a2348 3 exit: RTFREE_IF_NEEDED(rt); a2349 1 #undef RTFREE_IF_NEEDED d2535 1 a2535 2 d->expire = dr->expire ? time_mono_to_wall(dr->expire) : 0; @ 1.154.2.4 log @Sync with HEAD (as of 26th Dec) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.154.2.3 2015/09/22 12:06:11 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.154.2.3 2015/09/22 12:06:11 skrll Exp $"); a61 1 #include d107 4 d127 1 a127 1 static void nd6_free(struct rtentry *, struct llentry *, int); d129 1 a129 1 static void clear_llinfo_pqueue(struct llentry *); d140 10 d407 1 a407 1 nd6_llinfo_settimer_locked(struct llentry *ln, time_t xtick) d409 1 d411 1 a411 2 CTASSERT(sizeof(time_t) > sizeof(int)); LLE_WLOCK_ASSERT(ln); d416 1 a416 1 callout_halt(&ln->ln_timer_ch, &ln->lle_lock); a418 1 LLE_ADDREF(ln); a428 1 } d430 1 a430 33 void nd6_llinfo_settimer(struct llentry *ln, time_t xtick) { LLE_WLOCK(ln); nd6_llinfo_settimer_locked(ln, xtick); LLE_WUNLOCK(ln); } /* * Gets source address of the first packet in hold queue * and stores it in @@src. * Returns pointer to @@src (if hold queue is not empty) or NULL. */ static struct in6_addr * nd6_llinfo_get_holdsrc(struct llentry *ln, struct in6_addr *src) { struct ip6_hdr *hip6; if (ln == NULL || ln->ln_hold == NULL) return NULL; /* * assuming every packet in ln_hold has the same IP header */ hip6 = mtod(ln->ln_hold, struct ip6_hdr *); /* XXX pullup? */ if (sizeof(*hip6) < ln->ln_hold->m_len) *src = hip6->ip6_src; else src = NULL; return src; d436 1 a436 1 struct llentry *ln = arg; a440 2 bool send_ns = false; const struct in6_addr *daddr6 = NULL; d445 2 a446 1 LLE_WLOCK(ln); d448 4 a451 2 nd6_llinfo_settimer_locked(ln, ln->ln_ntick); goto out; a453 21 if (callout_pending(&ln->la_timer)) { /* * Here we are a bit odd here in the treatment of * active/pending. If the pending bit is set, it got * rescheduled before I ran. The active * bit we ignore, since if it was stopped * in ll_tablefree() and was currently running * it would have return 0 so the code would * not have deleted it since the callout could * not be stopped so we want to go through * with the delete here now. If the callout * was restarted, the pending bit will be back on and * we just want to bail since the callout_reset would * return 1 and our reference would have been removed * by nd6_llinfo_settimer_locked above since canceled * would have been 1. */ goto out; } ifp = ln->lle_tbl->llt_ifp; a454 1 d456 1 d463 1 a463 1 if (rt->rt_llinfo && (struct llentry *)rt->rt_llinfo != ln) d473 2 a474 1 send_ns = true; d486 3 d492 1 a492 1 nd6_free(rt, ln, 0); a493 3 if (m != NULL) icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, ifp); d499 1 a499 1 nd6_llinfo_settimer_locked(ln, nd6_gctimer * hz); d507 1 a507 1 nd6_free(rt, ln, 1); d517 3 a519 2 daddr6 = &dst->sin6_addr; send_ns = true; d522 1 a522 1 nd6_llinfo_settimer_locked(ln, nd6_gctimer * hz); d528 3 a530 2 daddr6 = &dst->sin6_addr; send_ns = true; d532 1 a532 1 nd6_free(rt, ln, 0); a537 13 if (send_ns) { struct in6_addr src, *psrc; nd6_llinfo_settimer_locked(ln, ndi->retrans * hz / 1000); psrc = nd6_llinfo_get_holdsrc(ln, &src); LLE_FREE_LOCKED(ln); ln = NULL; nd6_ns_output(ifp, daddr6, &dst->sin6_addr, psrc, 0); } out: if (ln != NULL) LLE_FREE_LOCKED(ln); d756 1 d832 4 a835 6 * We may not need to nuke the neighbor cache entries here * because the neighbor cache is kept in if_afdata[AF_INET6]. * nd6_purge() is invoked by in6_ifdetach() which is called * from if_detach() where everything gets purged. However * in6_ifdetach is directly called from vlan(4), so we still * need to purge entries here. d837 15 a851 2 if (ext->lltable != NULL) lltable_purge_entries(ext->lltable); d913 2 a914 1 struct llentry *ln = rt->rt_llinfo; d1057 2 a1058 2 static void nd6_free(struct rtentry *rt, struct llentry *ln, int gc) d1060 1 a1064 4 KASSERT(ln != NULL); KASSERT(ln == rt->rt_llinfo); LLE_WLOCK_ASSERT(ln); d1071 1 a1071 1 nd6_llinfo_settimer_locked(ln, -1); d1094 1 a1094 1 nd6_llinfo_settimer_locked(ln, d1097 1 a1097 2 nd6_llinfo_settimer_locked(ln, nd6_gctimer * hz); d1099 1 a1099 2 LLE_WUNLOCK(ln); return; d1143 8 a1150 1 LLE_WUNLOCK(ln); d1161 2 d1173 1 a1173 1 struct llentry *ln; d1186 1 a1186 1 ln = rt->rt_llinfo; d1201 1 a1201 1 ND_IFINFO(rt->rt_ifp)->reachable * hz); a1206 38 static int nd6_purge_entry(struct lltable *llt, struct llentry *ln, void *farg) { int *n = farg; if (*n <= 0) return 0; if (ND6_LLINFO_PERMANENT(ln)) return 0; LLE_WLOCK(ln); if (ln->ln_state > ND6_LLINFO_INCOMPLETE) ln->ln_state = ND6_LLINFO_STALE; else ln->ln_state = ND6_LLINFO_PURGE; nd6_llinfo_settimer_locked(ln, 0); LLE_WUNLOCK(ln); (*n)--; return 0; } static void nd6_gc_neighbors(struct lltable *llt) { int max_gc_entries = 10; if (ip6_neighborgcthresh >= 0 && lltable_get_entry_count(llt) >= ip6_neighborgcthresh) { /* * XXX entries that are "less recently used" should be * freed first. */ lltable_foreach_lle(llt, nd6_purge_entry, &max_gc_entries); } } d1211 1 a1211 1 struct llentry *ln; a1214 2 int flags = 0; bool use_lo0ifp = false; a1261 4 IF_AFDATA_RLOCK(ifp); ln = lla_lookup(LLTABLE6(ifp), flags, rt_getkey(rt)); IF_AFDATA_RUNLOCK(ifp); d1318 1 a1318 1 nd6_llinfo_settimer_locked(ln, 0); a1373 8 /* Determine to use lo0ifp or not before lla_create */ ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &satocsin6(rt_getkey(rt))->sin6_addr); RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); if (ifa != NULL && nd6_useloopback) use_lo0ifp = true; d1378 2 a1379 9 flags = LLE_EXCLUSIVE; if ((rt->rt_flags & RTF_CLONED) == 0) flags |= LLE_IFADDR; #define _IFP() (use_lo0ifp ? lo0ifp : ifp) IF_AFDATA_WLOCK(_IFP()); ln = lla_create(LLTABLE6(_IFP()), flags, rt_getkey(rt)); IF_AFDATA_WUNLOCK(_IFP()); a1384 1 d1388 1 d1390 1 a1390 16 rt->rt_refcnt++; rt->rt_llinfo = ln; LLE_ADDREF(ln); rt->rt_flags |= RTF_LLINFO; switch (_IFP()->if_type) { #if NTOKEN > 0 case IFT_ISO88025: ln->la_opaque = kmem_alloc(sizeof(struct token_rif), KM_SLEEP); break; #endif /* NTOKEN > 0 */ default: break; } #undef _IFP d1406 1 a1406 1 nd6_llinfo_settimer_locked(ln, 0); d1409 34 d1444 1 d1449 3 d1454 1 a1454 1 nd6_llinfo_settimer_locked(ln, -1); d1486 1 a1486 1 nd6_llinfo_settimer_locked(ln, -1); a1508 8 LLE_WUNLOCK(ln); /* * If we have too many cache entries, initiate immediate * purging for some entries. */ nd6_gc_neighbors(ln->lle_tbl); ln = NULL; d1532 5 a1536 1 rt->rt_llinfo = NULL; a1537 9 /* Have to do before IF_AFDATA_WLOCK to avoid deadlock */ callout_halt(&ln->la_timer, &ln->lle_lock); /* XXX: LOR avoidance. We still have ref on lle. */ LLE_RUNLOCK(ln); IF_AFDATA_WLOCK(ifp); LLE_WLOCK(ln); d1539 1 a1539 38 if (ln->la_opaque != NULL) { switch (ifp->if_type) { #if NTOKEN > 0 case IFT_ISO88025: kmem_free(ln->la_opaque, sizeof(struct token_rif)); break; #endif /* NTOKEN > 0 */ default: break; } } if (ln->la_rt != NULL) { /* * Don't rtfree (may actually free objects) here. * Leave it to rtrequest1. */ ln->la_rt->rt_refcnt--; ln->la_rt = NULL; } /* Guard against race with other llentry_free(). */ if (ln->la_flags & LLE_LINKED) { LLE_REMREF(ln); llentry_free(ln); } else { LLE_FREE_LOCKED(ln); } IF_AFDATA_WUNLOCK(ifp); ln = NULL; } if (ln != NULL) { if (flags & LLE_EXCLUSIVE) LLE_WUNLOCK(ln); else LLE_RUNLOCK(ln); d1823 1 a1823 1 struct llentry *ln; d1838 1 a1838 1 ln = rt->rt_llinfo; d1864 1 a1864 1 nd6_llinfo_release_pkts(struct llentry *ln, struct ifnet *ifp, d1869 1 a1869 1 for (m_hold = ln->la_hold, ln->la_hold = NULL, ln->la_numheld = 0; d1900 1 a1900 1 struct llentry *ln = NULL; d1948 1 a1948 3 if (rt->rt_llinfo != NULL) LLE_WLOCK((struct llentry *)rt->rt_llinfo); nd6_free(rt, rt->rt_llinfo, 0); d1952 1 a1952 1 ln = rt->rt_llinfo; d2023 1 a2023 1 nd6_llinfo_settimer(ln, nd6_gctimer * hz); d2250 1 a2250 1 struct llentry *ln = NULL; d2284 1 a2284 1 ln = rt->rt_llinfo; d2295 1 a2295 1 ln = rt->rt_llinfo; d2311 8 d2323 1 a2323 1 nd6_llinfo_settimer(ln, nd6_gctimer * hz); d2336 1 a2336 1 nd6_llinfo_settimer(ln, nd6_delay * hz); a2382 2 struct in6_addr src, *psrc; d2385 2 a2386 3 ND_IFINFO(ifp)->retrans * hz / 1000); psrc = nd6_llinfo_get_holdsrc(ln, &src); nd6_ns_output(ifp, NULL, &dst->sin6_addr, psrc, 0); d2506 2 a2507 2 static void clear_llinfo_pqueue(struct llentry *ln) @ 1.154.2.5 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.154.2.4 2015/12/27 12:10:07 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.154.2.4 2015/12/27 12:10:07 skrll Exp $"); d130 1 d1373 1 a1373 1 ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && ln == NULL)) { @ 1.154.2.6 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.154.2.5 2016/03/19 11:30:33 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.154.2.5 2016/03/19 11:30:33 skrll Exp $"); d105 3 d112 8 d124 1 a124 1 static void nd6_free(struct llentry *, int); a125 1 static void nd6_timer(void *); d128 2 a129 2 static callout_t nd6_slowtimo_ch; static callout_t nd6_timer_ch; d139 6 d149 2 a156 1 callout_reset(&nd6_timer_ch, hz, nd6_timer, NULL); d347 1 a347 1 nd6log(LOG_INFO, d349 1 a349 1 nd_opt->nd_opt_type); d369 1 a369 1 nd6log(LOG_DEBUG, d371 1 a371 1 "option ignored\n", nd_opt->nd_opt_type); d378 1 a378 1 nd6log(LOG_INFO, "too many loop in nd opt\n"); d393 1 a393 1 nd6_llinfo_settimer(struct llentry *ln, time_t xtick) d418 9 d457 2 d469 1 a469 1 nd6_llinfo_settimer(ln, ln->ln_ntick); d487 1 a487 1 * by nd6_llinfo_settimer above since canceled d494 1 d496 1 d500 8 d528 1 a528 1 nd6_free(ln, 0); d538 1 a538 1 nd6_llinfo_settimer(ln, nd6_gctimer * hz); d546 1 a546 1 nd6_free(ln, 1); d556 1 a556 1 daddr6 = &ln->r_l3addr.addr6; d560 1 a560 1 nd6_llinfo_settimer(ln, nd6_gctimer * hz); d566 1 a566 1 daddr6 = &ln->r_l3addr.addr6; d569 1 a569 1 nd6_free(ln, 0); a576 1 const struct in6_addr *taddr6 = &ln->r_l3addr.addr6; d578 1 a578 1 nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000); d582 1 a582 1 nd6_ns_output(ifp, daddr6, taddr6, psrc, 0); d595 1 a595 1 static void d892 3 a894 2 struct llentry * nd6_lookup(const struct in6_addr *addr6, const struct ifnet *ifp, bool wlock) d896 1 a897 1 struct llentry *ln; d900 17 d918 11 a928 45 IF_AFDATA_RLOCK(ifp); ln = lla_lookup(LLTABLE6(ifp), wlock ? LLE_EXCLUSIVE : 0, sin6tosa(&sin6)); IF_AFDATA_RUNLOCK(ifp); return ln; } struct llentry * nd6_create(const struct in6_addr *addr6, const struct ifnet *ifp) { struct sockaddr_in6 sin6; struct llentry *ln; sockaddr_in6_init(&sin6, addr6, 0, 0, 0); IF_AFDATA_WLOCK(ifp); ln = lla_create(LLTABLE6(ifp), LLE_EXCLUSIVE, sin6tosa(&sin6)); IF_AFDATA_WUNLOCK(ifp); if (ln != NULL) ln->ln_state = ND6_LLINFO_NOSTATE; return ln; } /* * Test whether a given IPv6 address is a neighbor or not, ignoring * the actual neighbor cache. The neighbor cache is ignored in order * to not reenter the routing code from within itself. */ static int nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) { struct nd_prefix *pr; struct ifaddr *dstaddr; /* * A link-local address is always a neighbor. * XXX: a link does not necessarily specify a single interface. */ if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { struct sockaddr_in6 sin6_copy; u_int32_t zone; d931 22 a952 44 * We need sin6_copy since sa6_recoverscope() may modify the * content (XXX). */ sin6_copy = *addr; if (sa6_recoverscope(&sin6_copy)) return 0; /* XXX: should be impossible */ if (in6_setscope(&sin6_copy.sin6_addr, ifp, &zone)) return 0; if (sin6_copy.sin6_scope_id == zone) return 1; else return 0; } /* * If the address matches one of our addresses, * it should be a neighbor. * If the address matches one of our on-link prefixes, it should be a * neighbor. */ LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { if (pr->ndpr_ifp != ifp) continue; if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) { struct rtentry *rt; rt = rtalloc1((struct sockaddr *)&pr->ndpr_prefix, 0); if (rt == NULL) continue; /* * This is the case where multiple interfaces * have the same prefix, but only one is installed * into the routing table and that prefix entry * is not the one being examined here. In the case * where RADIX_MPATH is enabled, multiple route * entries (of the same rt_key value) will be * installed because the interface addresses all * differ. */ if (!IN6_ARE_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, &satocsin6(rt_getkey(rt))->sin6_addr)) { continue; } d954 2 a955 5 if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, &addr->sin6_addr, &pr->ndpr_mask)) return 1; } d958 9 a966 9 * If the address is assigned on the node of the other side of * a p2p interface, the address should be a neighbor. */ dstaddr = ifa_ifwithdstaddr((const struct sockaddr *)addr); if (dstaddr != NULL) { if (dstaddr->ifa_ifp == ifp) { #ifdef __FreeBSD__ /* XXX we need to ifaref in ifa_ifwithdstaddr as well */ ifafree(dstaddr); d968 5 a972 5 return 1; } #ifdef __FreeBSD__ /* XXX we need to ifaref in ifa_ifwithdstaddr as well */ ifafree(dstaddr); d974 2 a975 1 } d978 26 a1003 7 * If the default router list is empty, all addresses are regarded * as on-link, and thus, as a neighbor. */ if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && TAILQ_EMPTY(&nd_defrouter) && nd6_defifindex == ifp->if_index) { return 1; d1005 6 d1012 1 a1012 1 return 0; a1022 1 struct llentry *ln; a1074 4 IF_AFDATA_UNLOCK_ASSERT(ifp); if (nd6_is_new_addr_neighbor(addr, ifp)) return 1; d1076 2 a1077 2 * Even if the address matches none of our addresses, it might be * in the neighbor cache or a connected route. d1079 2 a1080 21 ln = nd6_lookup(&addr->sin6_addr, ifp, false); if (ln != NULL) { LLE_RUNLOCK(ln); return 1; } rt = rtalloc1(sin6tocsa(addr), 0); if (rt == NULL) return 0; if ((rt->rt_flags & RTF_CONNECTED) && (rt->rt_ifp == ifp #if NBRIDGE > 0 || rt->rt_ifp->if_bridge == ifp->if_bridge #endif #if NCARP > 0 || (ifp->if_type == IFT_CARP && rt->rt_ifp == ifp->if_carpdev) || (rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp)|| (ifp->if_type == IFT_CARP && rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp->if_carpdev) #endif )) { a1083 1 rtfree(rt); d1095 1 a1095 1 nd6_free(struct llentry *ln, int gc) d1097 1 d1099 1 a1099 2 struct ifnet *ifp; struct in6_addr *in6; d1102 1 a1104 2 ifp = ln->lle_tbl->llt_ifp; in6 = &ln->r_l3addr.addr6; d1111 1 a1111 1 nd6_llinfo_settimer(ln, -1); d1116 2 a1117 1 dr = defrouter_lookup(in6, ifp); d1134 1 a1134 1 nd6_llinfo_settimer(ln, d1137 2 a1138 1 nd6_llinfo_settimer(ln, nd6_gctimer * hz); a1145 9 * We need to unlock to avoid a LOR with rt6_flush() * with the rnh and for the calls to * pfxlist_onlink_check() and defrouter_select() in the * block further down for calls into nd6_lookup(). * We still hold a ref. */ LLE_WUNLOCK(ln); /* d1150 1 a1150 1 rt6_flush(in6, ifp); a1181 13 #ifdef __FreeBSD__ /* * If this entry was added by an on-link redirect, remove the * corresponding host route. */ if (ln->la_flags & LLE_REDIRECT) nd6_free_redirect(ln); #endif if (ln->ln_router || dr) LLE_WLOCK(ln); d1185 1 d1187 9 a1195 15 * Save to unlock. We still hold an extra reference and will not * free(9) in llentry_free() if someone else holds one as well. */ LLE_WUNLOCK(ln); IF_AFDATA_LOCK(ifp); LLE_WLOCK(ln); /* Guard against race with other llentry_free(). */ if (ln->la_flags & LLE_LINKED) { LLE_REMREF(ln); llentry_free(ln); } else LLE_FREE_LOCKED(ln); IF_AFDATA_UNLOCK(ifp); a1206 1 struct ifnet *ifp; d1211 5 a1215 3 ifp = rt->rt_ifp; ln = nd6_lookup(&(satocsin6(rt_getkey(rt)))->sin6_addr, ifp, true); if (ln == NULL) d1217 1 d1219 1 d1221 1 a1221 1 goto done; d1229 1 a1229 1 goto done; d1232 4 a1235 5 if (!ND6_LLINFO_PERMANENT(ln)) nd6_llinfo_settimer(ln, ND_IFINFO(rt->rt_ifp)->reachable * hz); done: LLE_WUNLOCK(ln); d1256 1 a1256 1 nd6_llinfo_settimer(ln, 0); d1282 1 d1286 2 d1335 26 d1371 2 a1372 2 /* XXX should move to route.c? */ if (rt->rt_flags & (RTF_CONNECTED | RTF_LOCAL)) { d1394 2 a1395 1 d1397 1 a1397 1 if ((rt->rt_flags & RTF_CONNECTED) != 0) d1428 2 a1429 1 d1448 67 a1520 2 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &satocsin6(rt_getkey(rt))->sin6_addr); d1522 16 d1550 2 d1553 1 d1555 4 d1570 1 a1570 1 goto out; d1572 1 a1572 1 nd6log(LOG_ERR, "%s: failed to join " d1574 1 a1574 1 ip6_sprintf(&llsol), error); d1578 1 a1578 2 out: d1583 3 a1585 2 if (rt->rt_ifp != NULL) nd6_gc_neighbors(LLTABLE6(rt->rt_ifp)); d1589 2 d1608 51 a1658 1 break; d1944 1 d1949 10 a1958 1 ln = nd6_lookup(&nb_addr, ifp, false); d1961 1 d1969 1 a1969 1 LLE_RUNLOCK(ln); d1983 2 a1984 1 nd6_llinfo_release_pkts(struct llentry *ln, struct ifnet *ifp) a1986 1 struct sockaddr_in6 sin6; d1988 3 a1990 8 LLE_WLOCK_ASSERT(ln); sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); m_hold = ln->la_hold, ln->la_hold = NULL, ln->la_numheld = 0; LLE_WUNLOCK(ln); for (; m_hold != NULL; m_hold = m_hold_next) { d1999 1 a1999 1 nd6_output(ifp, ifp, m_hold, &sin6, NULL); a2000 1 LLE_WLOCK(ln); d2018 1 d2021 1 a2025 1 uint16_t router = 0; d2044 2 a2045 2 ln = nd6_lookup(from, ifp, true); if (ln == NULL) { d2052 1 a2052 1 ln = nd6_create(from, ifp); d2056 2 a2057 2 if (ln->la_flags & LLE_STATIC) { LLE_WUNLOCK(ln); d2063 11 d2075 6 a2080 1 return; d2082 1 a2082 1 olladdr = (ln->la_flags & LLE_VALID) ? 1 : 0; d2084 4 a2087 1 llchange = memcmp(lladdr, &ln->ll_addr, ifp->if_addrlen); d2107 7 a2113 2 memcpy(&ln->ll_addr, lladdr, ifp->if_addrlen); ln->la_flags |= LLE_VALID; d2146 1 a2146 1 nd6_llinfo_release_pkts(ln, ifp); a2217 2 #if 0 /* XXX should we send rtmsg as it used to be? */ a2219 13 #endif if (ln != NULL) { router = ln->ln_router; LLE_WUNLOCK(ln); } /* * If we have too many cache entries, initiate immediate * purging for some entries. */ if (is_newentry) nd6_gc_neighbors(LLTABLE6(ifp)); d2236 1 a2236 1 if (do_update && router && !ip6_forwarding && d2239 2 d2272 1 a2272 1 * Next hop determination. This routine was derived from ip_output.c. d2276 1 a2276 1 struct rtentry *rt0, struct rtentry **ret_rt, bool *sendpkt) d2278 24 a2301 3 struct rtentry *rt = rt0; struct rtentry *gwrt = NULL; struct sockaddr_in6 *gw6 = satosin6(rt->rt_gateway); d2322 1 a2322 1 return 0; d2327 9 a2335 4 if (gwrt == NULL || (gwrt->rt_flags & RTF_UP) == 0) { if (gwrt != NULL) { rtfree(gwrt); } d2339 1 d2352 3 a2354 1 *ret_rt = gwrt; d2358 1 a2358 2 if (gwrt != NULL) rtfree(gwrt); d2361 1 d2364 1 d2366 2 a2367 2 nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m, const struct sockaddr_in6 *dst, struct rtentry *rt) d2369 2 a2370 1 #define senderr(e) { error = (e); goto bad;} d2373 4 a2376 2 bool created = false; struct rtentry *nexthop = NULL; d2384 2 a2385 8 /* * Address resolution or Neighbor Unreachability Detection * for the next hop. * At this point, the destination of the packet must be a unicast * or an anycast address(i.e. not a multicast). */ if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) != 0) { a2387 1 /* Still need a nexthop to reflect RTF_{REJECT,BLACKHOLE} */ d2391 1 a2391 2 if (nexthop != NULL) rt = nexthop; d2396 7 d2404 3 a2406 2 ln = nd6_lookup(&dst->sin6_addr, ifp, true); if ((ln == NULL) && nd6_is_addr_neighbor(dst, ifp)) { d2412 6 a2417 3 ln = nd6_create(&dst->sin6_addr, ifp); if (ln != NULL) created = true; d2419 1 a2419 2 if (ln == NULL) { d2428 1 a2431 2 LLE_WLOCK_ASSERT(ln); d2499 2 a2500 1 nd6_llinfo_settimer(ln, ND_IFINFO(ifp)->retrans * hz / 1000); a2501 2 LLE_WUNLOCK(ln); ln = NULL; a2502 3 } else { /* We did the lookup so we need to do the unlock here. */ LLE_WUNLOCK(ln); a2503 1 a2513 3 if (ln != NULL) LLE_WUNLOCK(ln); d2530 1 a2530 5 if (nexthop != NULL) rtfree(nexthop); if (created) nd6_gc_neighbors(LLTABLE6(ifp)); d2533 2 a2535 1 } a2561 55 /* * Add pernament ND6 link-layer record for given * interface address. * * Very similar to IPv4 arp_ifinit(), but: * 1) IPv6 DAD is performed in different place * 2) It is called by IPv6 protocol stack in contrast to * arp_ifinit() which is typically called in SIOCSIFADDR * driver ioctl handler. * */ int nd6_add_ifa_lle(struct in6_ifaddr *ia) { struct ifnet *ifp; struct llentry *ln; ifp = ia->ia_ifa.ifa_ifp; if (nd6_need_cache(ifp) == 0) return 0; ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; ia->ia_ifa.ifa_flags = RTF_CONNECTED; IF_AFDATA_WLOCK(ifp); ln = lla_create(LLTABLE6(ifp), LLE_IFADDR | LLE_EXCLUSIVE, (struct sockaddr *)&ia->ia_addr); IF_AFDATA_WUNLOCK(ifp); if (ln == NULL) return ENOBUFS; ln->la_expire = 0; /* for IPv6 this means permanent */ ln->ln_state = ND6_LLINFO_REACHABLE; LLE_WUNLOCK(ln); return 0; } /* * Removes ALL lle records for interface address prefix. * XXXME: That's probably not we really want to do, we need * to remove address record only and keep other records * until we determine if given prefix is really going * to be removed. */ void nd6_rem_ifa_lle(struct in6_ifaddr *ia) { struct sockaddr_in6 mask, addr; memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr, (struct sockaddr *)&mask, LLE_STATIC); } d2567 1 a2567 1 struct llentry *ln; d2589 1 a2589 7 /* * the entry should have been created in nd6_store_lladdr */ ln = nd6_lookup(&satocsin6(dst)->sin6_addr, ifp, false); if ((ln == NULL) || !(ln->la_flags & LLE_VALID)) { if (ln != NULL) LLE_RUNLOCK(ln); d2594 11 a2604 3 /* XXX llentry should have addrlen? */ #if 0 a2616 5 #endif memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); LLE_RUNLOCK(ln); d2618 1 @ 1.154.2.7 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.154.2.6 2016/04/22 15:44:18 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.154.2.6 2016/04/22 15:44:18 skrll Exp $"); a1391 6 if (gate == NULL) { log(LOG_ERR, "%s: rt_setgate failed on %s\n", __func__, if_name(ifp)); break; } d1454 1 a1454 1 rt->rt_ifp = lo0ifp; /* XXX */ a2086 1 int s; d2092 1 a2092 3 s = pserialize_read_enter(); IFNET_READER_FOREACH(ifp) { a2105 2 pserialize_read_exit(s); d2110 64 d2182 1 a2182 8 if (rt != NULL) { error = rt_check_reject_route(rt, ifp); if (error != 0) { m_freem(m); return error; } } a2189 26 if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) != 0) { struct sockaddr_in6 *gw6 = satosin6(rt->rt_gateway); /* XXX remain the check to keep the original behavior. */ /* * We skip link-layer address resolution and NUD * if the gateway is not a neighbor from ND point * of view, regardless of the value of nd_ifinfo.flags. * The second condition is a bit tricky; we skip * if the gateway is our own address, which is * sometimes used to install a route to a p2p link. */ if (!nd6_is_addr_neighbor(gw6, ifp) || in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { /* * We allow this kind of tricky route only * when the outgoing interface is p2p. * XXX: we may need a more generic rule here. */ if ((ifp->if_flags & IFF_POINTOPOINT) == 0) senderr(EHOSTUNREACH); goto sendpkt; } } d2197 13 d2343 3 @ 1.154.2.8 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.154.2.7 2016/05/29 08:44:39 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.154.2.7 2016/05/29 08:44:39 skrll Exp $"); d112 1 a112 1 static int regen_tmpaddr(const struct in6_ifaddr *); d586 2 a587 2 for (ia6 = IN6_ADDRLIST_WRITER_FIRST(); ia6; ia6 = nia6) { nia6 = IN6_ADDRLIST_WRITER_NEXT(ia6); d683 1 a683 1 regen_tmpaddr(const struct in6_ifaddr *ia6) d690 1 a690 1 IFADDR_READER_FOREACH(ifa, ifp) { d726 1 a726 1 public_ifa6 = it6; a1452 11 * When called from rt_ifa_addlocal, we cannot depend on that * the address (rt_getkey(rt)) exits in the address list of the * interface. So check RTF_LOCAL instead. */ if (rt->rt_flags & RTF_LOCAL) { if (nd6_useloopback) rt->rt_ifp = lo0ifp; /* XXX */ break; } /* d1684 1 a1684 1 IFADDR_READER_FOREACH(ifa, ifp) { d1712 1 a1712 1 IFADDR_READER_FOREACH(ifa, ifp) { d1738 1 a1738 1 IFADDR_READER_FOREACH(ifa, ifp) { d1773 1 a1773 2 for (ia = IN6_ADDRLIST_WRITER_FIRST(); ia; ia = ia_next) { d1775 1 a1775 1 ia_next = IN6_ADDRLIST_WRITER_NEXT(ia); d2294 3 d2298 1 a2298 1 error = if_output_lock(ifp, origifp, m, sin6tocsa(dst), rt); d2300 4 a2303 1 error = if_output_lock(ifp, ifp, m, sin6tocsa(dst), rt); @ 1.154.2.9 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.154.2.8 2016/07/09 20:25:22 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.154.2.8 2016/07/09 20:25:22 skrll Exp $"); a58 1 #include a115 1 static void nd6_timer_work(struct work *, void *); a119 2 static struct workqueue *nd6_timer_wq; static struct work nd6_timer_wk; a128 1 int error; a135 5 error = workqueue_create(&nd6_timer_wq, "nd6_timer", nd6_timer_work, NULL, PRI_SOFTNET, IPL_SOFTNET, WQ_MPSAFE); if (error) panic("%s: workqueue_create failed (%d)\n", __func__, error); d559 1 a559 1 nd6_timer_work(struct work *wk, void *arg) a563 2 int s, bound; struct psref psref; a584 1 bound = curlwp_bind(); d586 2 a587 7 s = pserialize_read_enter(); for (ia6 = IN6_ADDRLIST_READER_FIRST(); ia6; ia6 = nia6) { nia6 = IN6_ADDRLIST_READER_NEXT(ia6); ia6_acquire(ia6, &psref); pserialize_read_exit(s); a607 1 ia6_release(ia6, &psref); a608 1 ia6 = NULL; a641 1 ia6_release(ia6, &psref); a655 2 s = pserialize_read_enter(); ia6_release(ia6, &psref); a656 2 pserialize_read_exit(s); curlwp_bindx(bound); a680 7 static void nd6_timer(void *ignored_arg) { workqueue_enqueue(nd6_timer_wq, &nd6_timer_wk, NULL); } a687 1 int s; a689 1 s = pserialize_read_enter(); a730 1 struct psref psref; a731 2 ia6_acquire(public_ifa6, &psref); pserialize_read_exit(s); a736 1 ia6_release(public_ifa6, &psref); a740 1 ia6_release(public_ifa6, &psref); a742 1 pserialize_read_exit(s); a899 1 int s; d937 1 a937 1 rt = rtalloc1(sin6tosa(&pr->ndpr_prefix), 0); d965 1 a965 2 s = pserialize_read_enter(); dstaddr = ifa_ifwithdstaddr(sin6tocsa(addr)); d968 4 a971 1 pserialize_read_exit(s); d974 4 a978 1 pserialize_read_exit(s); a1266 5 struct gc_args { int gc_entries; const struct in6_addr *skip_in6; }; d1270 1 a1270 3 struct gc_args *args = farg; int *n = &args->gc_entries; const struct in6_addr *skip_in6 = args->skip_in6; a1277 3 if (IN6_ARE_ADDR_EQUAL(&ln->r_l3addr.addr6, skip_in6)) return 0; d1291 1 a1291 1 nd6_gc_neighbors(struct lltable *llt, const struct in6_addr *in6) d1293 1 a1296 1 struct gc_args gc_args = {10, in6}; d1301 1 a1301 1 lltable_foreach_lle(llt, nd6_purge_entry, &gc_args); d1360 1 a1360 3 case RTM_ADD: { int s; a1466 1 s = pserialize_read_enter(); d1503 1 a1504 1 pserialize_read_exit(s); d1510 1 a1510 1 nd6_gc_neighbors(LLTABLE6(rt->rt_ifp), NULL); a1511 1 } a1694 1 s = pserialize_read_enter(); a1705 1 pserialize_read_exit(s); d1718 2 a1719 2 (ND.flags & ND6_IFF_IFDISABLED)) { int bound = curlwp_bind(); a1722 1 s = pserialize_read_enter(); a1723 1 struct psref psref; a1725 3 ifa_acquire(ifa, &psref); pserialize_read_exit(s); a1726 1 a1728 3 s = pserialize_read_enter(); ifa_release(ifa, &psref); a1729 2 pserialize_read_exit(s); curlwp_bindx(bound); d1747 1 a1747 1 int haslinklocal = 0; d1749 1 a1749 2 s = pserialize_read_enter(); IFADDR_READER_FOREACH(ifa, ifp) { d1757 2 a1758 3 } pserialize_read_exit(s); if (!haslinklocal) a1778 1 int _s; d1784 1 a1784 3 restart: _s = pserialize_read_enter(); for (ia = IN6_ADDRLIST_READER_FIRST(); ia; d1787 1 a1787 1 ia_next = IN6_ADDRLIST_READER_NEXT(ia); d1792 1 a1792 3 if (ia->ia6_ndpr == pfx) { pserialize_read_exit(_s); /* XXX NOMPSAFE? */ a1793 2 goto restart; } a1794 1 pserialize_read_exit(_s); d2078 1 a2078 1 nd6_gc_neighbors(LLTABLE6(ifp), &ln->r_l3addr.addr6); a2157 1 int s; a2167 1 s = pserialize_read_enter(); a2177 1 pserialize_read_exit(s); a2179 1 pserialize_read_exit(s); d2317 1 a2317 1 nd6_gc_neighbors(LLTABLE6(ifp), &dst->sin6_addr); d2369 1 a2369 1 ia->ia_ifa.ifa_flags |= RTF_CONNECTED; d2373 1 a2373 1 sin6tosa(&ia->ia_addr)); d2399 2 a2400 2 lltable_prefix_free(AF_INET6, sin6tosa(&addr), sin6tosa(&mask), LLE_STATIC); d2465 1 a2465 1 static void @ 1.154.2.10 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.154.2.9 2016/10/05 20:56:09 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.154.2.9 2016/10/05 20:56:09 skrll Exp $"); a445 1 #ifndef NET_MPSAFE a447 1 #endif a560 1 #ifndef NET_MPSAFE a562 1 #endif a579 1 #ifndef NET_MPSAFE a581 1 #endif a701 1 #ifndef NET_MPSAFE a703 1 #endif d782 1 a782 1 pserialize_read_exit(s); a992 1 rtfree(rt); a994 1 rtfree(rt); a2179 1 #ifndef NET_MPSAFE a2181 1 #endif a2201 1 #ifndef NET_MPSAFE a2203 1 #endif d2250 1 a2250 2 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { pserialize_read_exit(s); a2251 1 } @ 1.154.2.11 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.154.2.10 2016/12/05 10:55:28 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.154.2.10 2016/12/05 10:55:28 skrll Exp $"); d53 1 a105 2 krwlock_t nd6_lock __cacheline_aligned; a118 1 static struct nd_opt_hdr *nd6_option(union nd_opts *); a127 5 static struct ifnet *nd6_defifp; static int nd6_defifindex; static int nd6_setdefaultiface(int); a134 2 rw_init(&nd6_lock); d136 1 a136 1 ND_DEFROUTER_LIST_INIT(); a192 2 /* Ensure all IPv6 addresses are purged before calling nd6_purge */ if_purgeaddrs(ifp, AF_INET6, in6_purgeaddr); d257 1 a257 1 static struct nd_opt_hdr * d392 4 a395 8 KASSERT(xtick >= 0); ln->ln_expire = time_uptime + xtick / hz; LLE_ADDREF(ln); if (xtick > INT_MAX) { ln->ln_ntick = xtick - INT_MAX; callout_reset(&ln->ln_timer_ch, INT_MAX, nd6_llinfo_timer, ln); d397 11 a407 3 ln->ln_ntick = 0; callout_reset(&ln->ln_timer_ch, xtick, nd6_llinfo_timer, ln); d446 5 a451 2 if ((ln->la_flags & LLE_LINKED) == 0) goto out; d504 1 a504 5 if (m != NULL) { #ifndef NET_MPSAFE mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); #endif a506 5 #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); #endif } a556 4 #ifndef NET_MPSAFE mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); #endif a557 4 #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); #endif d563 4 d591 1 a591 2 ND6_WLOCK(); ND_DEFROUTER_LIST_FOREACH_SAFE(dr, next_dr) { d593 1 a593 1 nd6_defrtrlist_del(dr, NULL); a595 1 ND6_UNLOCK(); d690 1 a690 2 ND6_WLOCK(); ND_PREFIX_LIST_FOREACH_SAFE(pr, next_pr) { d704 1 a704 1 nd6_prelist_remove(pr); a706 1 ND6_UNLOCK(); d781 1 a781 4 ND6_WLOCK(); e = in6_tmpifadd(public_ifa6, 0, 0); ND6_UNLOCK(); if (e != 0) { a829 1 ND6_WLOCK(); d836 1 a836 1 ND_DEFROUTER_LIST_FOREACH_SAFE(dr, ndr) { d842 1 a842 1 nd6_defrtrlist_del(dr, ext); d846 1 a846 1 ND_DEFROUTER_LIST_FOREACH_SAFE(dr, ndr) { d852 1 a852 1 nd6_defrtrlist_del(dr, ext); d857 1 a857 1 ND_PREFIX_LIST_FOREACH_SAFE(pr, npr) { d860 13 a872 1 * All addresses referencing pr should be already freed. d874 1 a874 2 KASSERT(pr->ndpr_refcnt == 0); nd6_prelist_remove(pr); d887 1 a887 1 nd6_defrouter_select(); a889 1 ND6_UNLOCK(); a902 23 void nd6_assert_purged(struct ifnet *ifp) { struct nd_defrouter *dr; struct nd_prefix *pr; char ip6buf[INET6_ADDRSTRLEN] __diagused; ND6_RLOCK(); ND_DEFROUTER_LIST_FOREACH(dr) { KASSERTMSG(dr->ifp != ifp, "defrouter %s remains on %s", IN6_PRINT(ip6buf, &dr->rtaddr), ifp->if_xname); } ND_PREFIX_LIST_FOREACH(pr) { KASSERTMSG(pr->ndpr_ifp != ifp, "prefix %s/%d remains on %s", IN6_PRINT(ip6buf, &pr->ndpr_prefix.sin6_addr), pr->ndpr_plen, ifp->if_xname); } ND6_UNLOCK(); } d979 1 a979 2 ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { d1001 1 a1001 1 rt_unref(rt); d1004 1 a1004 1 rt_unref(rt); d1008 1 a1008 2 &addr->sin6_addr, &pr->ndpr_mask)) { ND6_UNLOCK(); a1009 1 } a1010 1 ND6_UNLOCK(); a1029 1 ND6_RLOCK(); d1031 2 a1032 2 ND_DEFROUTER_LIST_EMPTY() && nd6_defifindex == ifp->if_index) { ND6_UNLOCK(); a1034 1 ND6_UNLOCK(); d1077 1 a1077 2 ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { d1085 1 a1085 2 &addr->sin6_addr, &pr->ndpr_mask)) { ND6_UNLOCK(); a1086 1 } d1095 1 a1095 1 if (!ip6_forwarding && ND_DEFROUTER_LIST_EMPTY() && a1096 1 ND6_UNLOCK(); a1098 1 ND6_UNLOCK(); d1100 1 d1129 1 a1129 1 rt_unref(rt); d1132 1 a1132 1 rt_unref(rt); d1160 3 d1164 3 a1166 2 ND6_WLOCK(); dr = nd6_defrouter_lookup(in6, ifp); d1187 1 a1187 1 ND6_UNLOCK(); d1194 1 a1194 1 * We need to unlock to avoid a LOR with nd6_rt_flush() d1196 1 a1196 1 * nd6_pfxlist_onlink_check() and nd6_defrouter_select() in the d1203 1 a1203 1 * nd6_rt_flush must be called whether or not the neighbor d1207 1 a1207 1 nd6_rt_flush(in6, ifp); d1227 1 a1227 1 * Since nd6_defrouter_select() does not affect the d1232 1 a1232 1 nd6_pfxlist_onlink_check(); d1237 1 a1237 1 nd6_defrouter_select(); a1247 1 ND6_UNLOCK(); d1251 2 d1263 6 a1268 1 lltable_free_entry(LLTABLE6(ifp), ln); a1555 1 char ip6buf[INET6_ADDRSTRLEN]; d1558 1 a1558 1 IN6_PRINT(ip6buf, &llsol), error); d1606 1 d1614 2 a1615 2 ND6_RLOCK(); ND_DEFROUTER_LIST_FOREACH(dr) { d1628 1 a1628 1 ND6_UNLOCK(); d1644 2 a1645 2 ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { d1692 1 a1692 1 ND6_UNLOCK(); a1742 1 int s; d1843 2 a1844 4 ND6_WLOCK(); nd6_defrouter_reset(); nd6_defrouter_select(); ND6_UNLOCK(); d1851 2 a1852 3 restart: ND6_WLOCK(); ND_PREFIX_LIST_FOREACH_SAFE(pfx, next) { d1860 1 a1871 1 ND6_UNLOCK(); a1872 1 /* in6_purgeaddr may destroy pfx. */ d1878 1 a1878 3 KASSERT(pfx->ndpr_refcnt == 0); nd6_prelist_remove(pfx); d1880 1 a1880 1 ND6_UNLOCK(); d1888 4 a1891 4 ND6_WLOCK(); nd6_defrouter_reset(); ND_DEFROUTER_LIST_FOREACH_SAFE(drtr, next) { nd6_defrtrlist_del(drtr, NULL); d1893 2 a1894 2 nd6_defrouter_select(); ND6_UNLOCK(); d2170 1 a2170 1 * address option, nd6_defrouter_select() is called twice, since d2174 1 a2174 1 * XXX: although nd6_defrouter_select() should not have a bad effect d2179 2 a2180 5 nd6_accepts_rtadv(ndi)) { ND6_WLOCK(); nd6_defrouter_select(); ND6_UNLOCK(); } a2297 1 char ip6buf[INET6_ADDRSTRLEN]; d2301 1 a2301 1 IN6_PRINT(ip6buf, &dst->sin6_addr), ln, rt); d2629 1 a2629 1 int error = 0; d2634 2 d2642 1 a2642 2 ND6_RLOCK(); ND_DEFROUTER_LIST_FOREACH(dr) { a2647 1 char ip6buf[INET6_ADDRSTRLEN]; d2650 1 a2650 1 IN6_PRINT(ip6buf, &d->rtaddr.sin6_addr)); a2663 1 ND6_UNLOCK(); d2672 2 d2680 1 a2680 1 int error = 0; d2685 2 a2686 1 char ip6buf[INET6_ADDRSTRLEN]; d2694 1 a2694 2 ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { d2709 1 a2709 1 IN6_PRINT(ip6buf, &pfx.prefix.sin6_addr)); d2747 1 a2747 1 0, 0, 0); d2752 1 a2752 2 IN6_PRINT(ip6buf, &pfr->router->rtaddr)); a2770 1 ND6_UNLOCK(); d2779 2 a2782 29 static int nd6_setdefaultiface(int ifindex) { ifnet_t *ifp; int error = 0; int s; s = pserialize_read_enter(); ifp = if_byindex(ifindex); if (ifp == NULL) { pserialize_read_exit(s); return EINVAL; } if (nd6_defifindex != ifindex) { nd6_defifindex = ifindex; nd6_defifp = nd6_defifindex > 0 ? ifp : NULL; /* * Our current implementation assumes one-to-one maping between * interfaces and links, so it would be natural to use the * default interface as the default link. */ scope6_setdefault(nd6_defifp); } pserialize_read_exit(s); return (error); } @ 1.154.2.12 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.154.2.11 2017/02/05 13:40:59 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.154.2.11 2017/02/05 13:40:59 skrll Exp $"); d46 1 a46 1 #include d166 1 a166 1 nd = kmem_zalloc(sizeof(*nd), KM_SLEEP); d205 1 a205 1 kmem_free(ext->nd_ifinfo, sizeof(struct nd_ifinfo)); a452 4 #ifndef NET_MPSAFE mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); #endif d509 4 d515 4 d570 4 d575 4 a583 4 #ifndef NET_MPSAFE KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); #endif d718 1 d720 2 a721 2 * Just invalidate the prefix here. Removing it * will be done when purging an associated address. d723 2 a724 2 KASSERT(pr->ndpr_refcnt > 0); nd6_invalidate_prefix(pr); d1625 1 a1625 1 in6m = in6_lookup_multi(&llsol, ifp); d1995 1 a1995 1 ip6_if_output(ifp, ifp, m_hold, &sin6, NULL); a2267 5 /* * Return 0 if a neighbor cache is found. Return EWOULDBLOCK if a cache is not * found and trying to resolve a neighbor; in this case the mbuf is queued in * the list. Otherwise return errno after freeing the mbuf. */ d2269 2 a2270 2 nd6_resolve(struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m, const struct sockaddr *_dst, uint8_t *lldst, size_t dstsize) d2272 1 d2274 1 a2275 1 const struct sockaddr_in6 *dst = satocsin6(_dst); d2277 44 a2320 4 /* discard the packet if IPv6 operation is disabled on the interface */ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { m_freem(m); return ENETDOWN; /* better error? */ a2330 13 ln = nd6_lookup(&dst->sin6_addr, ifp, false); if (ln != NULL && (ln->la_flags & LLE_VALID) != 0) { KASSERT(ln->ln_state > ND6_LLINFO_INCOMPLETE); /* Fast path */ memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); LLE_RUNLOCK(ln); return 0; } if (ln != NULL) LLE_RUNLOCK(ln); /* Slow path */ d2332 1 a2332 2 if (ln == NULL && nd6_is_addr_neighbor(dst, ifp)) { struct sockaddr_in6 sin6; d2339 7 a2345 1 if (ln == NULL) { d2348 2 a2349 2 "%s: can't allocate llinfo for %s " "(ln=%p, rt=%p)\n", __func__, d2351 1 a2351 2 m_freem(m); return ENOBUFS; d2353 1 a2353 5 sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); rt_clonedmsg(sin6tosa(&sin6), ifp, rt); created = true; d2379 8 d2435 23 d2461 2 a2462 1 return EWOULDBLOCK; d2490 118 a2607 1 static void a2633 1 size_t bufsize = 0; d2643 4 a2646 3 if (oldp && *oldlenp > 0) { p = kmem_alloc(*oldlenp, KM_SLEEP); bufsize = *oldlenp; d2670 1 a2670 1 kmem_free(p, bufsize); @ 1.153 log @Tests for neighbour now work correctly on bridge(4) and carp(4) interfaces. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.152 2014/06/06 01:02:47 rmind Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.152 2014/06/06 01:02:47 rmind Exp $"); d188 1 a188 1 * because one of it's members should. */ d195 1 a195 1 * because one of it's members should. */ @ 1.152 log @- Eliminate RTFREE() macro in favour of rtfree() function. - Make rtcache() function static. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.151 2014/06/05 16:06:49 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.151 2014/06/05 16:06:49 roy Exp $"); d36 2 d911 1 a911 1 || SAME_BRIDGE(rt->rt_ifp->if_bridgeport, ifp->if_bridgeport) @ 1.152.2.1 log @Pull up following revision(s) (requested by roy in ticket #159): sys/netinet6/nd6.c: revision 1.153 Tests for neighbour now work correctly on bridge(4) and carp(4) interfaces. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.152 2014/06/06 01:02:47 rmind Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.152 2014/06/06 01:02:47 rmind Exp $"); a35 2 #include "bridge.h" #include "carp.h" d909 1 a909 1 || rt->rt_ifp->if_bridge == ifp->if_bridge @ 1.152.2.2 log @Pull up following revision(s) (requested by roy in ticket #332): sys/netinet6/nd6_nbr.c: revision 1.103 sys/netinet6/nd6_rtr.c: revision 1.95 sys/netinet6/nd6.h: revision 1.61 sys/netinet6/nd6.c: revision 1.156 Report route additions/changes/deletions for cached neighbours to userland. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.152.2.1 2014/10/27 13:39:11 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.152.2.1 2014/10/27 13:39:11 martin Exp $"); a1039 1 struct rtentry *oldrt; d1132 1 a1132 9 oldrt = NULL; rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, &oldrt); if (oldrt) { nd6_rtmsg(RTM_DELETE, oldrt); /* tell user process */ if (oldrt->rt_refcnt <= 0) { oldrt->rt_refcnt++; rtfree(oldrt); } } a2061 3 if (do_update) nd6_rtmsg(RTM_CHANGE, rt); /* tell user process */ @ 1.152.2.3 log @Pull up following revision(s) (requested by martin in ticket #655): sys/netinet6/in6.c: revision 1.182 via patch sys/netinet6/in6_ifattach.c: revision 1.95 via patch sys/netinet6/nd6.c: revision 1.158 via patch sys/netinet6/nd6.h: revision 1.62 via patch sys/netinet6/nd6_nbr.c: revision 1.104 via patch sys/netinet6/nd6_rtr.c: revision 1.96 via patch Rearange interface detachement slightly: before we free the INET6 specific per-interface data, make sure to call nd6_purge() with it to remove routing entries pointing to the going interface. When we should happen to call this function again later, with the data already gone, just return. Fixes PR kern/49682, ok: christos. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.152.2.2 2014/12/17 18:43:47 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.152.2.2 2014/12/17 18:43:47 martin Exp $"); d208 1 a208 1 nd6_ifdetach(struct ifnet *ifp, struct in6_ifextra *ext) d211 1 a211 2 nd6_purge(ifp, ext); free(ext->nd_ifinfo, M_IP6NDP); d559 1 a559 1 defrtrlist_del(dr, NULL); d749 1 a749 1 nd6_purge(struct ifnet *ifp, struct in6_ifextra *ext) a755 10 * During detach, the ND info might be already removed, but * then is explitly passed as argument. * Otherwise get it from ifp->if_afdata. */ if (ext == NULL) ext = ifp->if_afdata[AF_INET6]; if (ext == NULL) return; /* d765 2 a766 4 if (dr->ifp == ifp) { KASSERT(ext != NULL); defrtrlist_del(dr, ext); } d773 2 a774 4 if (dr->ifp == ifp) { KASSERT(ext != NULL); defrtrlist_del(dr, ext); } d1800 1 a1800 1 defrtrlist_del(drtr, NULL); @ 1.152.2.4 log @Pull up following revision(s) (requested by skrll/ozaki-r in ticket #1402): sys/net/route.c: revision 1.170 via patch sys/netinet/ip_flow.c: revision 1.73 via patch sys/netinet6/ip6_flow.c: revision 1.28 via patch sys/netinet6/nd6.c: revision 1.203 via patch Run timers in workqueue Timers (such as nd6_timer) typically free/destroy some data in callout (softint). If we apply psz/psref for such data, we cannot do free/destroy process in there because synchronization of psz/psref cannot be used in softint. So run timer callbacks in workqueue works (normal LWP context). Doing workqueue_enqueue a work twice (i.e., call workqueue_enqueue before a previous task is scheduled) isn't allowed. For nd6_timer and rt_timer_timer, this doesn't happen because callout_reset is called only from workqueue's work. OTOH, ip{,6}flow_slowtimo's callout can be called before its work starts and completes because the callout is periodically called regardless of completion of the work. To avoid such a situation, add a flag for each protocol; the flag is set true when a work is enqueued and set false after the work finished. workqueue_enqueue is called only if the flag is false. Proposed on tech-net and tech-kern. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.152.2.3 2015/04/06 01:32:33 snj Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.152.2.3 2015/04/06 01:32:33 snj Exp $"); a55 1 #include a124 1 static void nd6_timer_work(struct work *, void *); a129 2 static struct workqueue *nd6_timer_wq; static struct work nd6_timer_wk; a150 1 int error; a164 5 error = workqueue_create(&nd6_timer_wq, "nd6_timer", nd6_timer_work, NULL, PRI_SOFTNET, IPL_SOFTNET, 0); if (error) panic("%s: workqueue_create failed (%d)\n", __func__, error); d544 1 a544 1 nd6_timer_work(struct work *wk, void *arg) a663 7 void nd6_timer(void *ignored_arg) { workqueue_enqueue(nd6_timer_wq, &nd6_timer_wk, NULL); } @ 1.151 log @Add IPV6CTL_AUTO_LINKLOCAL and ND6_IFF_AUTO_LINKLOCAL toggles which control the automatic creation of IPv6 link-local addresses when an interface is brought up. Taken from FreeBSD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.150 2014/05/20 20:23:56 bouyer Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.150 2014/05/20 20:23:56 bouyer Exp $"); d850 1 a850 1 RTFREE(rt); @ 1.150 log @Sync with the ipv4 code and call ifp->if_output() with KERNEL_LOCK held. Problem reported and fix tested by njoly@@ on current-users@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.149 2014/05/17 20:44:24 rmind Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.149 2014/05/17 20:44:24 rmind Exp $"); d69 1 d181 1 a181 5 /* * Note that the default value of ip6_accept_rtadv is 0. * Because we do not set ND6_IFF_OVERRIDE_RTADV here, we won't * accept RAs by default. */ d184 15 d1713 31 a1744 1 @ 1.149 log @- Move IFNET_*() macros under #ifdef _KERNEL. - Replace TAILQ_FOREACH on ifnet with IFNET_FOREACH(). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.148 2014/03/20 13:34:35 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.148 2014/03/20 13:34:35 roy Exp $"); d2260 1 d2262 5 a2266 2 return (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); return (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); @ 1.148 log @If IPv6 is disabled for an interface, mark all addresses as tentative. If enabled, check for a duplicated link-local address and abort enabling as per RFC 4862, section 5.4.5. If allowed to enable, perform DAD on the tentative addresses. Taken from FreeBSD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.147 2014/01/15 10:25:04 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.147 2014/01/15 10:25:04 roy Exp $"); d2050 1 a2050 1 TAILQ_FOREACH(ifp, &ifnet, if_list) { @ 1.148.2.1 log @Rebase. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.152 2014/06/06 01:02:47 rmind Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.152 2014/06/06 01:02:47 rmind Exp $"); a68 1 #include d180 5 a184 1 a186 15 /* A loopback interface always has ND6_IFF_AUTO_LINKLOCAL. * A bridge interface should not have ND6_IFF_AUTO_LINKLOCAL * because one of it's members should. */ if ((ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) || (ifp->if_flags & IFF_LOOPBACK)) nd->flags |= ND6_IFF_AUTO_LINKLOCAL; /* A loopback interface does not need to accept RTADV. * A bridge interface should not accept RTADV * because one of it's members should. */ if (ip6_accept_rtadv && !(ifp->if_flags & IFF_LOOPBACK) && !(ifp->if_type != IFT_BRIDGE)) nd->flags |= ND6_IFF_ACCEPT_RTADV; d838 1 a838 1 rtfree(rt); d1701 1 a1702 31 if (ND.flags & ND6_IFF_AUTO_LINKLOCAL) { if (!(ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL)) { /* auto_linklocal 0->1 transition */ ND_IFINFO(ifp)->flags |= ND6_IFF_AUTO_LINKLOCAL; in6_ifattach(ifp, NULL); } else if (!(ND.flags & ND6_IFF_IFDISABLED) && ifp->if_flags & IFF_UP) { /* * When the IF already has * ND6_IFF_AUTO_LINKLOCAL, no link-local * address is assigned, and IFF_UP, try to * assign one. */ int haslinklocal = 0; IFADDR_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family !=AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))){ haslinklocal = 1; break; } } if (!haslinklocal) in6_ifattach(ifp, NULL); } } } d2050 1 a2050 1 IFNET_FOREACH(ifp) { a2259 1 KERNEL_LOCK(1, NULL); d2261 2 a2262 5 error = (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); else error = (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); KERNEL_UNLOCK_ONE(NULL); return error; @ 1.147 log @If the address matches a cloning route, it is also a neighbor. This allows us to use prefixes which userland may have added. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.146 2013/12/17 20:25:00 martin Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.146 2013/12/17 20:25:00 martin Exp $"); d1650 53 @ 1.146 log @Instead of voodo casts use simple byte pointer arithmetic and memcpy to create the "packed" binary format we pass out to userland when querying the router/prefix list. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.145 2013/05/21 08:37:27 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.145 2013/05/21 08:37:27 roy Exp $"); d821 3 a823 2 struct rtentry * nd6_lookup(const struct in6_addr *addr6, int create, struct ifnet *ifp) d887 21 d938 7 d1005 2 a1006 2 * Even if the address matches none of our addresses, it might be * in the neighbor cache. d1008 1 a1008 1 if (nd6_lookup(&addr->sin6_addr, 0, ifp) != NULL) @ 1.145 log @For IPv6, emit RTM_NEWADDR once DAD completes and also when address flag changes. Tentative addresses are not emitted. Version bumped so userland can detect this behaviour change. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.144 2013/01/24 14:23:09 joerg Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.144 2013/01/24 14:23:09 joerg Exp $"); d2388 2 a2389 2 struct in6_prefix *p = NULL; struct in6_prefix *pe = NULL; d2395 2 a2396 2 p = (struct in6_prefix *)oldp; pe = (struct in6_prefix *)((char *)oldp + *oldlenp); d2402 1 a2402 3 size_t advance; struct sockaddr_in6 *sin6; struct sockaddr_in6 *s6; d2404 1 d2406 1 a2406 1 if (oldp && p + 1 <= pe) d2408 3 a2410 2 memset(p, 0, sizeof(*p)); sin6 = (struct sockaddr_in6 *)(p + 1); d2412 1 a2412 2 p->prefix = pr->ndpr_prefix; if (sa6_recoverscope(&p->prefix)) { d2415 1 a2415 1 ip6_sprintf(&p->prefix.sin6_addr)); d2418 5 a2422 5 p->raflags = pr->ndpr_raf; p->prefixlen = pr->ndpr_plen; p->vltime = pr->ndpr_vltime; p->pltime = pr->ndpr_pltime; p->if_index = pr->ndpr_ifp->if_index; d2424 1 a2424 1 p->expire = 0; d2434 1 a2434 1 p->expire = pr->ndpr_lastupdate + d2437 1 a2437 1 p->expire = maxexpire; d2439 6 a2444 3 p->refcnt = pr->ndpr_refcnt; p->flags = pr->ndpr_stateflags; p->origin = PR_ORIG_RA; d2447 1 a2447 1 if ((void *)&sin6[advrtrs + 1] > (void *)pe) { d2451 2 a2452 2 s6 = &sin6[advrtrs]; sockaddr_in6_init(s6, &pfr->router->rtaddr, d2454 1 a2454 1 if (sa6_recoverscope(s6)) { d2461 3 d2465 2 a2466 1 p->advrtrs = advrtrs; d2469 1 d2471 1 a2471 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) d2473 2 a2475 5 advance = sizeof(*p) + sizeof(*sin6) * advrtrs; l += advance; if (p) p = (struct in6_prefix *)((char *)p + advance); @ 1.145.2.1 log @Checkpoint work in progress: - Move PCB structures under __INPCB_PRIVATE, adjust most of the callers and thus make IPv4 PCB structures mostly opaque. Any volunteers for merging in6pcb with inpcb (see rpaulo-netinet-merge-pcb branch)? - Move various global vars to the modules where they belong, make them static. - Some preliminary work for IPv4 PCB locking scheme. - Make raw IP code mostly MP-safe. Simplify some of it. - Rework "fast" IP forwarding (ipflow) code to be mostly MP-safe. It should run from a software interrupt, rather than hard. - Rework tun(4) pseudo interface to be MP-safe. - Work towards making some other interfaces more strict. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.145 2013/05/21 08:37:27 roy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.145 2013/05/21 08:37:27 roy Exp $"); d1968 1 a1968 1 IFNET_FOREACH(ifp) { @ 1.145.2.2 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.145.2.1 2013/07/17 03:16:31 rmind Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.145.2.1 2013/07/17 03:16:31 rmind Exp $"); d821 2 a822 3 static struct rtentry * nd6_lookup1(const struct in6_addr *addr6, int create, struct ifnet *ifp, int cloning) a885 21 /* * Check for a cloning route to match the address. * This should only be set from in6_is_addr_neighbor so we avoid * a potentially expensive second call to rtalloc1. */ if (cloning && rt->rt_flags & (RTF_CLONING | RTF_CLONED) && (rt->rt_ifp == ifp #if NBRIDGE > 0 || SAME_BRIDGE(rt->rt_ifp->if_bridgeport, ifp->if_bridgeport) #endif #if NCARP > 0 || (ifp->if_type == IFT_CARP && rt->rt_ifp == ifp->if_carpdev) || (rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp)|| (ifp->if_type == IFT_CARP && rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp->if_carpdev) #endif )) return rt; a915 7 struct rtentry * nd6_lookup(const struct in6_addr *addr6, int create, struct ifnet *ifp) { return nd6_lookup1(addr6, create, ifp, 0); } d976 2 a977 2 * Even if the address matches none of our addresses, it might match * a cloning route or be in the neighbor cache. d979 1 a979 1 if (nd6_lookup1(&addr->sin6_addr, 0, ifp, 1) != NULL) a1620 53 { struct ifaddr *ifa; struct in6_ifaddr *ia; if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && !(ND.flags & ND6_IFF_IFDISABLED)) { /* * If the interface is marked as ND6_IFF_IFDISABLED and * has a link-local address with IN6_IFF_DUPLICATED, * do not clear ND6_IFF_IFDISABLED. * See RFC 4862, section 5.4.5. */ int duplicated_linklocal = 0; IFADDR_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; if ((ia->ia6_flags & IN6_IFF_DUPLICATED) && IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) { duplicated_linklocal = 1; break; } } if (duplicated_linklocal) { ND.flags |= ND6_IFF_IFDISABLED; log(LOG_ERR, "Cannot enable an interface" " with a link-local address marked" " duplicate.\n"); } else { ND_IFINFO(ifp)->flags &= ~ND6_IFF_IFDISABLED; if (ifp->if_flags & IFF_UP) in6_if_up(ifp); } } else if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && (ND.flags & ND6_IFF_IFDISABLED)) { /* Mark all IPv6 addresses as tentative. */ ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED; IFADDR_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; nd6_dad_stop(ifa); ia = (struct in6_ifaddr *)ifa; ia->ia6_flags |= IN6_IFF_TENTATIVE; } } } d2388 2 a2389 2 uint8_t *p = NULL, *ps = NULL; uint8_t *pe = NULL; d2395 2 a2396 2 ps = p = (uint8_t*)oldp; pe = (uint8_t*)oldp + *oldlenp; d2402 3 a2404 1 struct sockaddr_in6 sin6; a2405 1 struct in6_prefix pfx; d2407 1 a2407 1 if (oldp && p + sizeof(struct in6_prefix) <= pe) d2409 2 a2410 3 memset(&pfx, 0, sizeof(pfx)); ps = p; pfx.prefix = pr->ndpr_prefix; d2412 2 a2413 1 if (sa6_recoverscope(&pfx.prefix)) { d2416 1 a2416 1 ip6_sprintf(&pfx.prefix.sin6_addr)); d2419 5 a2423 5 pfx.raflags = pr->ndpr_raf; pfx.prefixlen = pr->ndpr_plen; pfx.vltime = pr->ndpr_vltime; pfx.pltime = pr->ndpr_pltime; pfx.if_index = pr->ndpr_ifp->if_index; d2425 1 a2425 1 pfx.expire = 0; d2435 1 a2435 1 pfx.expire = pr->ndpr_lastupdate + d2438 1 a2438 1 pfx.expire = maxexpire; d2440 3 a2442 6 pfx.refcnt = pr->ndpr_refcnt; pfx.flags = pr->ndpr_stateflags; pfx.origin = PR_ORIG_RA; p += sizeof(pfx); l += sizeof(pfx); d2445 1 a2445 1 if (p + sizeof(sin6) > pe) { d2449 2 a2450 2 sockaddr_in6_init(&sin6, &pfr->router->rtaddr, d2452 1 a2452 1 if (sa6_recoverscope(&sin6)) { a2458 3 memcpy(p, &sin6, sizeof(sin6)); p += sizeof(sin6); l += sizeof(sin6); d2460 1 a2460 2 pfx.advrtrs = advrtrs; memcpy(ps, &pfx, sizeof(pfx)); a2462 1 l += sizeof(pfx); d2464 1 a2464 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { a2465 2 l += sizeof(sin6); } d2467 5 @ 1.144 log @Use rt_getkey. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.143 2012/06/23 03:14:04 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.143 2012/06/23 03:14:04 christos Exp $"); d585 4 a588 1 ia6->ia6_flags |= IN6_IFF_DEPRECATED; d619 4 a622 1 ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; @ 1.143 log @4 new sysctls to avoid ipv6 DoS attacks from OpenBSD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.142 2012/03/22 20:34:41 drochner Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.142 2012/03/22 20:34:41 drochner Exp $"); d1147 1 a1147 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1182 1 a1182 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1196 1 a1196 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1217 1 a1217 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1247 1 a1247 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1250 1 a1250 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1254 1 a1254 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1285 1 a1285 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1300 1 a1300 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1304 1 a1304 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1311 1 a1311 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1316 1 a1316 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1339 1 a1339 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1375 1 a1375 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1382 1 a1382 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); @ 1.143.2.1 log @resync with head @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.143 2012/06/23 03:14:04 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.143 2012/06/23 03:14:04 christos Exp $"); d1147 1 a1147 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1182 1 a1182 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1196 1 a1196 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1217 1 a1217 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1247 1 a1247 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1250 1 a1250 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1254 1 a1254 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1285 1 a1285 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1300 1 a1300 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1304 1 a1304 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1311 1 a1311 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1316 1 a1316 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1339 1 a1339 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1375 1 a1375 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1382 1 a1382 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); @ 1.143.2.2 log @resync from head @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d585 1 a585 4 if ((oldflags & IN6_IFF_DEPRECATED) == 0) { ia6->ia6_flags |= IN6_IFF_DEPRECATED; nd6_newaddrmsg((struct ifaddr *)ia6); } d616 1 a616 4 if (ia6->ia6_flags & IN6_IFF_DEPRECATED) { ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; nd6_newaddrmsg((struct ifaddr *)ia6); } @ 1.143.2.3 log @Rebase to HEAD as of a few days ago. @ text @a68 1 #include d180 5 a184 1 a186 15 /* A loopback interface always has ND6_IFF_AUTO_LINKLOCAL. * A bridge interface should not have ND6_IFF_AUTO_LINKLOCAL * because one of it's members should. */ if ((ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) || (ifp->if_flags & IFF_LOOPBACK)) nd->flags |= ND6_IFF_AUTO_LINKLOCAL; /* A loopback interface does not need to accept RTADV. * A bridge interface should not accept RTADV * because one of it's members should. */ if (ip6_accept_rtadv && !(ifp->if_flags & IFF_LOOPBACK) && !(ifp->if_type != IFT_BRIDGE)) nd->flags |= ND6_IFF_ACCEPT_RTADV; d821 2 a822 3 static struct rtentry * nd6_lookup1(const struct in6_addr *addr6, int create, struct ifnet *ifp, int cloning) d837 1 a837 1 rtfree(rt); a885 21 /* * Check for a cloning route to match the address. * This should only be set from in6_is_addr_neighbor so we avoid * a potentially expensive second call to rtalloc1. */ if (cloning && rt->rt_flags & (RTF_CLONING | RTF_CLONED) && (rt->rt_ifp == ifp #if NBRIDGE > 0 || SAME_BRIDGE(rt->rt_ifp->if_bridgeport, ifp->if_bridgeport) #endif #if NCARP > 0 || (ifp->if_type == IFT_CARP && rt->rt_ifp == ifp->if_carpdev) || (rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp)|| (ifp->if_type == IFT_CARP && rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp->if_carpdev) #endif )) return rt; a915 7 struct rtentry * nd6_lookup(const struct in6_addr *addr6, int create, struct ifnet *ifp) { return nd6_lookup1(addr6, create, ifp, 0); } d976 2 a977 2 * Even if the address matches none of our addresses, it might match * a cloning route or be in the neighbor cache. d979 1 a979 1 if (nd6_lookup1(&addr->sin6_addr, 0, ifp, 1) != NULL) a1620 83 { struct ifaddr *ifa; struct in6_ifaddr *ia; if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && !(ND.flags & ND6_IFF_IFDISABLED)) { /* * If the interface is marked as ND6_IFF_IFDISABLED and * has a link-local address with IN6_IFF_DUPLICATED, * do not clear ND6_IFF_IFDISABLED. * See RFC 4862, section 5.4.5. */ int duplicated_linklocal = 0; IFADDR_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; if ((ia->ia6_flags & IN6_IFF_DUPLICATED) && IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) { duplicated_linklocal = 1; break; } } if (duplicated_linklocal) { ND.flags |= ND6_IFF_IFDISABLED; log(LOG_ERR, "Cannot enable an interface" " with a link-local address marked" " duplicate.\n"); } else { ND_IFINFO(ifp)->flags &= ~ND6_IFF_IFDISABLED; if (ifp->if_flags & IFF_UP) in6_if_up(ifp); } } else if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && (ND.flags & ND6_IFF_IFDISABLED)) { /* Mark all IPv6 addresses as tentative. */ ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED; IFADDR_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; nd6_dad_stop(ifa); ia = (struct in6_ifaddr *)ifa; ia->ia6_flags |= IN6_IFF_TENTATIVE; } } if (ND.flags & ND6_IFF_AUTO_LINKLOCAL) { if (!(ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL)) { /* auto_linklocal 0->1 transition */ ND_IFINFO(ifp)->flags |= ND6_IFF_AUTO_LINKLOCAL; in6_ifattach(ifp, NULL); } else if (!(ND.flags & ND6_IFF_IFDISABLED) && ifp->if_flags & IFF_UP) { /* * When the IF already has * ND6_IFF_AUTO_LINKLOCAL, no link-local * address is assigned, and IFF_UP, try to * assign one. */ int haslinklocal = 0; IFADDR_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family !=AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))){ haslinklocal = 1; break; } } if (!haslinklocal) in6_ifattach(ifp, NULL); } } } d1968 1 a1968 1 IFNET_FOREACH(ifp) { a2177 1 KERNEL_LOCK(1, NULL); d2179 2 a2180 5 error = (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); else error = (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); KERNEL_UNLOCK_ONE(NULL); return error; d2388 2 a2389 2 uint8_t *p = NULL, *ps = NULL; uint8_t *pe = NULL; d2395 2 a2396 2 ps = p = (uint8_t*)oldp; pe = (uint8_t*)oldp + *oldlenp; d2402 3 a2404 1 struct sockaddr_in6 sin6; a2405 1 struct in6_prefix pfx; d2407 1 a2407 1 if (oldp && p + sizeof(struct in6_prefix) <= pe) d2409 2 a2410 3 memset(&pfx, 0, sizeof(pfx)); ps = p; pfx.prefix = pr->ndpr_prefix; d2412 2 a2413 1 if (sa6_recoverscope(&pfx.prefix)) { d2416 1 a2416 1 ip6_sprintf(&pfx.prefix.sin6_addr)); d2419 5 a2423 5 pfx.raflags = pr->ndpr_raf; pfx.prefixlen = pr->ndpr_plen; pfx.vltime = pr->ndpr_vltime; pfx.pltime = pr->ndpr_pltime; pfx.if_index = pr->ndpr_ifp->if_index; d2425 1 a2425 1 pfx.expire = 0; d2435 1 a2435 1 pfx.expire = pr->ndpr_lastupdate + d2438 1 a2438 1 pfx.expire = maxexpire; d2440 3 a2442 6 pfx.refcnt = pr->ndpr_refcnt; pfx.flags = pr->ndpr_stateflags; pfx.origin = PR_ORIG_RA; p += sizeof(pfx); l += sizeof(pfx); d2445 1 a2445 1 if (p + sizeof(sin6) > pe) { d2449 2 a2450 2 sockaddr_in6_init(&sin6, &pfr->router->rtaddr, d2452 1 a2452 1 if (sa6_recoverscope(&sin6)) { a2458 3 memcpy(p, &sin6, sizeof(sin6)); p += sizeof(sin6); l += sizeof(sin6); d2460 1 a2460 2 pfx.advrtrs = advrtrs; memcpy(ps, &pfx, sizeof(pfx)); a2462 1 l += sizeof(pfx); d2464 1 a2464 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { a2465 2 l += sizeof(sin6); } d2467 5 @ 1.143.2.4 log @update from HEAD @ text @d36 1 a36 6 #ifdef _KERNEL_OPT #include "opt_net_mpsafe.h" #endif #include "bridge.h" #include "carp.h" d41 1 a41 1 #include d48 1 a53 1 #include a56 1 #include d99 2 a100 1 krwlock_t nd6_lock __cacheline_aligned; d102 4 d110 8 d121 2 a122 2 static int regen_tmpaddr(const struct in6_ifaddr *); static void nd6_free(struct llentry *, int); d124 5 a128 9 static void nd6_timer(void *); static void nd6_timer_work(struct work *, void *); static void clear_llinfo_pqueue(struct llentry *); static struct nd_opt_hdr *nd6_option(union nd_opts *); static callout_t nd6_slowtimo_ch; static callout_t nd6_timer_ch; static struct workqueue *nd6_timer_wq; static struct work nd6_timer_wk; a132 5 static struct ifnet *nd6_defifp; static int nd6_defifindex; static int nd6_setdefaultiface(int); d135 10 d148 1 a148 1 int error; d150 4 a153 1 rw_init(&nd6_lock); d156 3 a158 1 ND_DEFROUTER_LIST_INIT(); a162 5 error = workqueue_create(&nd6_timer_wq, "nd6_timer", nd6_timer_work, NULL, PRI_SOFTNET, IPL_SOFTNET, WQ_MPSAFE); if (error) panic("%s: workqueue_create failed (%d)\n", __func__, error); a165 1 callout_reset(&nd6_timer_ch, hz, nd6_timer, NULL); d173 1 a173 1 nd = kmem_zalloc(sizeof(*nd), KM_SLEEP); d186 1 a186 1 * because one of its members should. */ d193 1 a193 1 * because one of its members should. */ d206 1 a206 1 nd6_ifdetach(struct ifnet *ifp, struct in6_ifextra *ext) d209 1 a209 4 /* Ensure all IPv6 addresses are purged before calling nd6_purge */ if_purgeaddrs(ifp, AF_INET6, in6_purgeaddr); nd6_purge(ifp, ext); kmem_free(ext->nd_ifinfo, sizeof(struct nd_ifinfo)); d272 1 a272 1 static struct nd_opt_hdr * d278 4 a281 3 KASSERT(ndopts != NULL); KASSERT(ndopts->nd_opts_last != NULL); d329 4 a332 3 KASSERT(ndopts != NULL); KASSERT(ndopts->nd_opts_last != NULL); d357 1 a357 1 nd6log(LOG_INFO, d359 1 a359 1 nd_opt->nd_opt_type); d379 1 a379 1 nd6log(LOG_DEBUG, d381 1 a381 1 "option ignored\n", nd_opt->nd_opt_type); d388 1 a388 1 nd6log(LOG_INFO, "too many loop in nd opt\n"); d403 1 a403 1 nd6_llinfo_settimer(struct llentry *ln, time_t xtick) d405 1 d407 1 a407 2 CTASSERT(sizeof(time_t) > sizeof(int)); LLE_WLOCK_ASSERT(ln); d409 4 a412 8 KASSERT(xtick >= 0); ln->ln_expire = time_uptime + xtick / hz; LLE_ADDREF(ln); if (xtick > INT_MAX) { ln->ln_ntick = xtick - INT_MAX; callout_reset(&ln->ln_timer_ch, INT_MAX, nd6_llinfo_timer, ln); d414 10 a423 3 ln->ln_ntick = 0; callout_reset(&ln->ln_timer_ch, xtick, nd6_llinfo_timer, ln); a424 14 } /* * Gets source address of the first packet in hold queue * and stores it in @@src. * Returns pointer to @@src (if hold queue is not empty) or NULL. */ static struct in6_addr * nd6_llinfo_get_holdsrc(struct llentry *ln, struct in6_addr *src) { struct ip6_hdr *hip6; if (ln == NULL || ln->ln_hold == NULL) return NULL; d426 1 a426 11 /* * assuming every packet in ln_hold has the same IP header */ hip6 = mtod(ln->ln_hold, struct ip6_hdr *); /* XXX pullup? */ if (sizeof(*hip6) < ln->ln_hold->m_len) *src = hip6->ip6_src; else src = NULL; return src; d432 3 a434 1 struct llentry *ln = arg; a436 2 bool send_ns = false; const struct in6_addr *daddr6 = NULL; d438 5 a442 4 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); LLE_WLOCK(ln); if ((ln->la_flags & LLE_LINKED) == 0) goto out; d445 3 a447 1 goto out; d450 6 a455 21 if (callout_pending(&ln->la_timer)) { /* * Here we are a bit odd here in the treatment of * active/pending. If the pending bit is set, it got * rescheduled before I ran. The active * bit we ignore, since if it was stopped * in ll_tablefree() and was currently running * it would have return 0 so the code would * not have deleted it since the callout could * not be stopped so we want to go through * with the delete here now. If the callout * was restarted, the pending bit will be back on and * we just want to bail since the callout_reset would * return 1 and our reference would have been removed * by nd6_llinfo_settimer above since canceled * would have been 1. */ goto out; } ifp = ln->lle_tbl->llt_ifp; d457 6 a462 3 KASSERT(ifp != NULL); ndi = ND_IFINFO(ifp); d468 2 a469 1 send_ns = true; d481 3 d487 1 a487 1 nd6_free(ln, 0); a488 4 if (m != NULL) { icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, ifp); } d494 1 a494 1 nd6_llinfo_settimer(ln, nd6_gctimer * hz); d502 1 a502 1 nd6_free(ln, 1); d512 3 a514 2 daddr6 = &ln->r_l3addr.addr6; send_ns = true; d517 1 a517 1 nd6_llinfo_settimer(ln, nd6_gctimer * hz); d523 3 a525 2 daddr6 = &ln->r_l3addr.addr6; send_ns = true; d527 1 a527 1 nd6_free(ln, 0); d533 2 a534 15 if (send_ns) { struct in6_addr src, *psrc; const struct in6_addr *taddr6 = &ln->r_l3addr.addr6; nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000); psrc = nd6_llinfo_get_holdsrc(ln, &src); LLE_FREE_LOCKED(ln); ln = NULL; nd6_ns_output(ifp, daddr6, taddr6, psrc, 0); } out: if (ln != NULL) LLE_FREE_LOCKED(ln); SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); d540 2 a541 2 static void nd6_timer_work(struct work *wk, void *arg) a545 2 int s, bound; struct psref psref; d550 2 a551 1 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); d554 4 a557 5 ND6_WLOCK(); ND_DEFROUTER_LIST_FOREACH_SAFE(dr, next_dr) { if (dr->expire && dr->expire < time_uptime) { nd6_defrtrlist_del(dr, NULL); a559 1 ND6_UNLOCK(); a566 1 bound = curlwp_bind(); d568 2 a569 7 s = pserialize_read_enter(); for (ia6 = IN6_ADDRLIST_READER_FIRST(); ia6; ia6 = nia6) { nia6 = IN6_ADDRLIST_READER_NEXT(ia6); ia6_acquire(ia6, &psref); pserialize_read_exit(s); a589 1 ia6_release(ia6, &psref); a590 1 ia6 = NULL; d599 1 a599 2 rt_newaddrmsg(RTM_NEWADDR, (struct ifaddr *)ia6, 0, NULL); a622 1 ia6_release(ia6, &psref); d633 1 a633 2 rt_newaddrmsg(RTM_NEWADDR, (struct ifaddr *)ia6, 0, NULL); a635 2 s = pserialize_read_enter(); ia6_release(ia6, &psref); a636 2 pserialize_read_exit(s); curlwp_bindx(bound); d639 1 a639 2 ND6_WLOCK(); ND_PREFIX_LIST_FOREACH_SAFE(pr, next_pr) { d646 2 a647 1 time_uptime - pr->ndpr_lastupdate > pr->ndpr_vltime) { d649 2 a650 2 * Just invalidate the prefix here. Removing it * will be done when purging an associated address. d652 2 a653 2 KASSERT(pr->ndpr_refcnt > 0); nd6_invalidate_prefix(pr); a655 8 ND6_UNLOCK(); SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); } static void nd6_timer(void *ignored_arg) { d657 2 a658 1 workqueue_enqueue(nd6_timer_wq, &nd6_timer_wk, NULL); d663 1 a663 1 regen_tmpaddr(const struct in6_ifaddr *ia6) a667 1 int s; d670 1 a670 2 s = pserialize_read_enter(); IFADDR_READER_FOREACH(ifa, ifp) { d706 1 a706 1 public_ifa6 = it6; a710 1 struct psref psref; a711 2 ia6_acquire(public_ifa6, &psref); pserialize_read_exit(s); d716 1 a716 5 ND6_WLOCK(); e = in6_tmpifadd(public_ifa6, 0, 0); ND6_UNLOCK(); if (e != 0) { ia6_release(public_ifa6, &psref); a720 1 ia6_release(public_ifa6, &psref); a722 1 pserialize_read_exit(s); d747 1 a747 1 nd6_purge(struct ifnet *ifp, struct in6_ifextra *ext) d749 1 a753 11 * During detach, the ND info might be already removed, but * then is explitly passed as argument. * Otherwise get it from ifp->if_afdata. */ if (ext == NULL) ext = ifp->if_afdata[AF_INET6]; if (ext == NULL) return; ND6_WLOCK(); /* d759 1 a759 1 ND_DEFROUTER_LIST_FOREACH_SAFE(dr, ndr) { d763 2 a764 4 if (dr->ifp == ifp) { KASSERT(ext != NULL); nd6_defrtrlist_del(dr, ext); } d767 1 a767 1 ND_DEFROUTER_LIST_FOREACH_SAFE(dr, ndr) { d771 2 a772 4 if (dr->ifp == ifp) { KASSERT(ext != NULL); nd6_defrtrlist_del(dr, ext); } d776 1 a776 1 ND_PREFIX_LIST_FOREACH_SAFE(pr, npr) { d779 13 a791 1 * All addresses referencing pr should be already freed. d793 1 a793 2 KASSERT(pr->ndpr_refcnt == 0); nd6_prelist_remove(pr); d806 1 a806 1 nd6_defrouter_select(); a808 1 ND6_UNLOCK(); d811 4 a814 6 * We may not need to nuke the neighbor cache entries here * because the neighbor cache is kept in if_afdata[AF_INET6]. * nd6_purge() is invoked by in6_ifdetach() which is called * from if_detach() where everything gets purged. However * in6_ifdetach is directly called from vlan(4), so we still * need to purge entries here. d816 4 a819 3 if (ext->lltable != NULL) lltable_purge_entries(ext->lltable); } d821 9 a829 12 void nd6_assert_purged(struct ifnet *ifp) { struct nd_defrouter *dr; struct nd_prefix *pr; char ip6buf[INET6_ADDRSTRLEN] __diagused; ND6_RLOCK(); ND_DEFROUTER_LIST_FOREACH(dr) { KASSERTMSG(dr->ifp != ifp, "defrouter %s remains on %s", IN6_PRINT(ip6buf, &dr->rtaddr), ifp->if_xname); a830 8 ND_PREFIX_LIST_FOREACH(pr) { KASSERTMSG(pr->ndpr_ifp != ifp, "prefix %s/%d remains on %s", IN6_PRINT(ip6buf, &pr->ndpr_prefix.sin6_addr), pr->ndpr_plen, ifp->if_xname); } ND6_UNLOCK(); d833 3 a835 2 struct llentry * nd6_lookup(const struct in6_addr *addr6, const struct ifnet *ifp, bool wlock) d837 1 a838 1 struct llentry *ln; d841 13 a853 23 IF_AFDATA_RLOCK(ifp); ln = lla_lookup(LLTABLE6(ifp), wlock ? LLE_EXCLUSIVE : 0, sin6tosa(&sin6)); IF_AFDATA_RUNLOCK(ifp); return ln; } struct llentry * nd6_create(const struct in6_addr *addr6, const struct ifnet *ifp) { struct sockaddr_in6 sin6; struct llentry *ln; struct rtentry *rt; sockaddr_in6_init(&sin6, addr6, 0, 0, 0); rt = rtalloc1(sin6tosa(&sin6), 0); IF_AFDATA_WLOCK(ifp); ln = lla_create(LLTABLE6(ifp), LLE_EXCLUSIVE, sin6tosa(&sin6), rt); IF_AFDATA_WUNLOCK(ifp); d855 3 a857 3 rt_unref(rt); if (ln != NULL) ln->ln_state = ND6_LLINFO_NOSTATE; d859 11 a869 22 return ln; } /* * Test whether a given IPv6 address is a neighbor or not, ignoring * the actual neighbor cache. The neighbor cache is ignored in order * to not reenter the routing code from within itself. */ static int nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) { struct nd_prefix *pr; struct ifaddr *dstaddr; int s; /* * A link-local address is always a neighbor. * XXX: a link does not necessarily specify a single interface. */ if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { struct sockaddr_in6 sin6_copy; u_int32_t zone; d872 27 a898 13 * We need sin6_copy since sa6_recoverscope() may modify the * content (XXX). */ sin6_copy = *addr; if (sa6_recoverscope(&sin6_copy)) return 0; /* XXX: should be impossible */ if (in6_setscope(&sin6_copy.sin6_addr, ifp, &zone)) return 0; if (sin6_copy.sin6_scope_id == zone) return 1; else return 0; } d901 3 a903 4 * If the address matches one of our addresses, * it should be a neighbor. * If the address matches one of our on-link prefixes, it should be a * neighbor. d905 14 a918 36 ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { if (pr->ndpr_ifp != ifp) continue; if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) { struct rtentry *rt; rt = rtalloc1(sin6tosa(&pr->ndpr_prefix), 0); if (rt == NULL) continue; /* * This is the case where multiple interfaces * have the same prefix, but only one is installed * into the routing table and that prefix entry * is not the one being examined here. In the case * where RADIX_MPATH is enabled, multiple route * entries (of the same rt_key value) will be * installed because the interface addresses all * differ. */ if (!IN6_ARE_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, &satocsin6(rt_getkey(rt))->sin6_addr)) { rt_unref(rt); continue; } rt_unref(rt); } if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, &addr->sin6_addr, &pr->ndpr_mask)) { ND6_UNLOCK(); return 1; } } ND6_UNLOCK(); d921 23 a943 9 * If the address is assigned on the node of the other side of * a p2p interface, the address should be a neighbor. */ s = pserialize_read_enter(); dstaddr = ifa_ifwithdstaddr(sin6tocsa(addr)); if (dstaddr != NULL) { if (dstaddr->ifa_ifp == ifp) { pserialize_read_exit(s); return 1; d945 1 d947 2 a948 1 pserialize_read_exit(s); d950 3 a952 11 /* * If the default router list is empty, all addresses are regarded * as on-link, and thus, as a neighbor. */ ND6_RLOCK(); if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && ND_DEFROUTER_LIST_EMPTY() && nd6_defifindex == ifp->if_index) { ND6_UNLOCK(); return 1; } ND6_UNLOCK(); d954 1 a954 1 return 0; a964 2 struct llentry *ln; struct rtentry *rt; d993 1 a993 2 ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { d1001 1 a1001 2 &addr->sin6_addr, &pr->ndpr_mask)) { ND6_UNLOCK(); a1002 1 } d1011 1 a1011 1 if (!ip6_forwarding && ND_DEFROUTER_LIST_EMPTY() && a1012 1 ND6_UNLOCK(); a1014 4 ND6_UNLOCK(); if (nd6_is_new_addr_neighbor(addr, ifp)) return 1; d1017 2 a1018 2 * Even if the address matches none of our addresses, it might be * in the neighbor cache or a connected route. d1020 1 a1020 3 ln = nd6_lookup(&addr->sin6_addr, ifp, false); if (ln != NULL) { LLE_RUNLOCK(ln); a1021 21 } rt = rtalloc1(sin6tocsa(addr), 0); if (rt == NULL) return 0; if ((rt->rt_flags & RTF_CONNECTED) && (rt->rt_ifp == ifp #if NBRIDGE > 0 || rt->rt_ifp->if_bridge == ifp->if_bridge #endif #if NCARP > 0 || (ifp->if_type == IFT_CARP && rt->rt_ifp == ifp->if_carpdev) || (rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp)|| (ifp->if_type == IFT_CARP && rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp->if_carpdev) #endif )) { rt_unref(rt); return 1; } rt_unref(rt); d1032 2 a1033 2 static void nd6_free(struct llentry *ln, int gc) d1035 2 a1037 5 struct ifnet *ifp; struct in6_addr *in6; KASSERT(ln != NULL); LLE_WLOCK_ASSERT(ln); a1038 2 ifp = ln->lle_tbl->llt_ifp; in6 = &ln->r_l3addr.addr6; d1044 3 d1048 4 a1051 2 ND6_WLOCK(); dr = nd6_defrouter_lookup(in6, ifp); d1067 1 a1067 1 if (dr->expire > time_uptime) d1069 1 a1069 1 (dr->expire - time_uptime) * hz); d1071 3 a1073 4 nd6_llinfo_settimer(ln, nd6_gctimer * hz); ND6_UNLOCK(); LLE_WUNLOCK(ln); return; d1078 1 a1078 10 * We need to unlock to avoid a LOR with nd6_rt_flush() * with the rnh and for the calls to * nd6_pfxlist_onlink_check() and nd6_defrouter_select() in the * block further down for calls into nd6_lookup(). * We still hold a ref. */ LLE_WUNLOCK(ln); /* * nd6_rt_flush must be called whether or not the neighbor d1082 1 a1082 1 nd6_rt_flush(in6, ifp); d1102 1 a1102 1 * Since nd6_defrouter_select() does not affect the d1107 1 a1107 1 nd6_pfxlist_onlink_check(); d1112 1 a1112 1 nd6_defrouter_select(); d1114 1 a1114 13 #ifdef __FreeBSD__ /* * If this entry was added by an on-link redirect, remove the * corresponding host route. */ if (ln->la_flags & LLE_REDIRECT) nd6_free_redirect(ln); #endif ND6_UNLOCK(); if (ln->ln_router || dr) LLE_WLOCK(ln); d1118 4 a1121 2 * Save to unlock. We still hold an extra reference and will not * free(9) in llentry_free() if someone else holds one as well. d1123 1 a1123 3 LLE_WUNLOCK(ln); IF_AFDATA_LOCK(ifp); LLE_WLOCK(ln); d1125 6 a1130 1 lltable_free_entry(LLTABLE6(ifp), ln); d1132 1 a1132 1 IF_AFDATA_UNLOCK(ifp); d1141 1 a1141 1 nd6_nud_hint(struct rtentry *rt) d1143 1 a1143 2 struct llentry *ln; struct ifnet *ifp; d1145 10 a1154 2 if (rt == NULL) return; d1156 5 a1160 3 ifp = rt->rt_ifp; ln = nd6_lookup(&(satocsin6(rt_getkey(rt)))->sin6_addr, ifp, true); if (ln == NULL) d1162 1 d1164 1 d1166 1 a1166 1 goto done; d1172 5 a1176 3 ln->ln_byhint++; if (ln->ln_byhint > nd6_maxnudhint) goto done; d1179 3 a1181 54 if (!ND6_LLINFO_PERMANENT(ln)) nd6_llinfo_settimer(ln, ND_IFINFO(rt->rt_ifp)->reachable * hz); done: LLE_WUNLOCK(ln); return; } struct gc_args { int gc_entries; const struct in6_addr *skip_in6; }; static int nd6_purge_entry(struct lltable *llt, struct llentry *ln, void *farg) { struct gc_args *args = farg; int *n = &args->gc_entries; const struct in6_addr *skip_in6 = args->skip_in6; if (*n <= 0) return 0; if (ND6_LLINFO_PERMANENT(ln)) return 0; if (IN6_ARE_ADDR_EQUAL(&ln->r_l3addr.addr6, skip_in6)) return 0; LLE_WLOCK(ln); if (ln->ln_state > ND6_LLINFO_INCOMPLETE) ln->ln_state = ND6_LLINFO_STALE; else ln->ln_state = ND6_LLINFO_PURGE; nd6_llinfo_settimer(ln, 0); LLE_WUNLOCK(ln); (*n)--; return 0; } static void nd6_gc_neighbors(struct lltable *llt, const struct in6_addr *in6) { if (ip6_neighborgcthresh >= 0 && lltable_get_entry_count(llt) >= ip6_neighborgcthresh) { struct gc_args gc_args = {10, in6}; /* * XXX entries that are "less recently used" should be * freed first. */ lltable_foreach_lle(llt, nd6_purge_entry, &gc_args); d1189 1 d1240 22 d1263 1 a1263 3 case RTM_ADD: { struct psref psref; d1272 2 a1273 2 /* XXX should move to route.c? */ if (rt->rt_flags & (RTF_CONNECTED | RTF_LOCAL)) { d1295 2 a1296 7 if (gate == NULL) { log(LOG_ERR, "%s: rt_setgate failed on %s\n", __func__, if_name(ifp)); break; } d1298 1 a1298 1 if ((rt->rt_flags & RTF_CONNECTED) != 0) d1329 2 a1330 1 d1349 14 d1364 28 d1394 26 a1419 8 * When called from rt_ifa_addlocal, we cannot depend on that * the address (rt_getkey(rt)) exits in the address list of the * interface. So check RTF_LOCAL instead. */ if (rt->rt_flags & RTF_LOCAL) { if (nd6_useloopback) rt->rt_ifp = lo0ifp; /* XXX */ break; d1422 1 d1427 3 a1429 2 ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &satocsin6(rt_getkey(rt))->sin6_addr, &psref); d1431 16 d1448 1 a1448 1 rt->rt_ifp = lo0ifp; /* XXX */ d1459 1 d1462 4 d1477 1 a1477 1 goto out; d1479 1 a1479 2 char ip6buf[INET6_ADDRSTRLEN]; nd6log(LOG_ERR, "%s: failed to join " d1481 1 a1481 1 IN6_PRINT(ip6buf, &llsol), error); a1484 8 out: ifa_release(ifa, &psref); /* * If we have too many cache entries, initiate immediate * purging for some entries. */ if (rt->rt_ifp != NULL) nd6_gc_neighbors(LLTABLE6(rt->rt_ifp), NULL); a1485 1 } d1488 2 d1502 1 a1502 1 in6m = in6_lookup_multi(&llsol, ifp); d1507 9 a1515 1 break; d1529 1 d1531 1 d1539 2 a1540 2 ND6_RLOCK(); ND_DEFROUTER_LIST_FOREACH(dr) { d1548 1 a1548 2 drl->defrouter[i].expire = dr->expire ? time_mono_to_wall(dr->expire) : 0; d1552 1 a1552 1 ND6_UNLOCK(); d1568 2 a1569 2 ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { d1592 3 a1594 5 time_t expire; expire = pr->ndpr_lastupdate + pr->ndpr_vltime; oprl->prefix[i].expire = expire ? time_mono_to_wall(expire) : 0; d1614 1 a1614 1 ND6_UNLOCK(); a1664 1 int s; d1677 1 a1677 2 s = pserialize_read_enter(); IFADDR_READER_FOREACH(ifa, ifp) { a1687 1 pserialize_read_exit(s); d1700 2 a1701 2 (ND.flags & ND6_IFF_IFDISABLED)) { int bound = curlwp_bind(); d1705 1 a1705 3 s = pserialize_read_enter(); IFADDR_READER_FOREACH(ifa, ifp) { struct psref psref; a1707 3 ifa_acquire(ifa, &psref); pserialize_read_exit(s); a1708 1 a1710 3 s = pserialize_read_enter(); ifa_release(ifa, &psref); a1711 2 pserialize_read_exit(s); curlwp_bindx(bound); d1729 1 a1729 1 int haslinklocal = 0; d1731 1 a1731 2 s = pserialize_read_enter(); IFADDR_READER_FOREACH(ifa, ifp) { d1739 2 a1740 3 } pserialize_read_exit(s); if (!haslinklocal) d1750 2 a1751 4 ND6_WLOCK(); nd6_defrouter_reset(); nd6_defrouter_select(); ND6_UNLOCK(); d1758 2 a1759 3 restart: ND6_WLOCK(); ND_PREFIX_LIST_FOREACH_SAFE(pfx, next) { a1760 1 int _s; d1766 1 a1766 3 _s = pserialize_read_enter(); for (ia = IN6_ADDRLIST_READER_FIRST(); ia; ia = ia_next) { d1768 1 a1768 1 ia_next = IN6_ADDRLIST_READER_NEXT(ia); d1773 1 a1773 5 if (ia->ia6_ndpr == pfx) { pserialize_read_exit(_s); ND6_UNLOCK(); /* XXX NOMPSAFE? */ /* in6_purgeaddr may destroy pfx. */ a1774 2 goto restart; } d1776 1 a1776 4 pserialize_read_exit(_s); KASSERT(pfx->ndpr_refcnt == 0); nd6_prelist_remove(pfx); d1778 1 a1778 1 ND6_UNLOCK(); d1786 4 a1789 4 ND6_WLOCK(); nd6_defrouter_reset(); ND_DEFROUTER_LIST_FOREACH_SAFE(drtr, next) { nd6_defrtrlist_del(drtr, NULL); d1791 2 a1792 2 nd6_defrouter_select(); ND6_UNLOCK(); d1797 1 a1797 1 struct llentry *ln; d1803 3 a1805 2 ln = nd6_lookup(&nb_addr, ifp, false); if (ln == NULL) { d1807 1 d1813 2 a1814 3 nbi->expire = ln->ln_expire ? time_mono_to_wall(ln->ln_expire) : 0; LLE_RUNLOCK(ln); d1828 2 a1829 1 nd6_llinfo_release_pkts(struct llentry *ln, struct ifnet *ifp) a1831 5 struct sockaddr_in6 sin6; LLE_WLOCK_ASSERT(ln); sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); d1833 3 a1835 4 m_hold = ln->la_hold, ln->la_hold = NULL, ln->la_numheld = 0; LLE_WUNLOCK(ln); for (; m_hold != NULL; m_hold = m_hold_next) { d1844 1 a1844 1 ip6_if_output(ifp, ifp, m_hold, &sin6, NULL); a1845 1 LLE_WLOCK(ln); d1852 1 a1852 1 void d1863 2 a1864 1 struct llentry *ln = NULL; d1866 1 a1870 1 uint16_t router = 0; d1872 4 a1875 2 KASSERT(ifp != NULL); KASSERT(from != NULL); d1879 1 a1879 1 return; d1891 2 a1892 2 ln = nd6_lookup(from, ifp, true); if (ln == NULL) { d1899 1 a1899 1 ln = nd6_create(from, ifp); d1903 2 a1904 4 if (ln->la_flags & LLE_STATIC) { LLE_WUNLOCK(ln); return; } d1908 8 d1917 6 a1922 1 return; d1924 1 a1924 1 olladdr = (ln->la_flags & LLE_VALID) ? 1 : 0; d1926 4 a1929 1 llchange = memcmp(lladdr, &ln->ll_addr, ifp->if_addrlen); d1949 7 a1955 2 memcpy(&ln->ll_addr, lladdr, ifp->if_addrlen); ln->la_flags |= LLE_VALID; d1986 1 a1986 1 nd6_llinfo_settimer(ln, nd6_gctimer * hz); d1988 1 a1988 1 nd6_llinfo_release_pkts(ln, ifp); a2059 18 #if 0 /* XXX should we send rtmsg as it used to be? */ if (do_update) rt_newmsg(RTM_CHANGE, rt); /* tell user process */ #endif if (ln != NULL) { router = ln->ln_router; LLE_WUNLOCK(ln); } /* * If we have too many cache entries, initiate immediate * purging for some entries. */ if (is_newentry) nd6_gc_neighbors(LLTABLE6(ifp), &ln->r_l3addr.addr6); d2067 1 a2067 1 * address option, nd6_defrouter_select() is called twice, since d2071 1 a2071 1 * XXX: although nd6_defrouter_select() should not have a bad effect d2075 5 a2079 6 if (do_update && router && !ip6_forwarding && nd6_accepts_rtadv(ndi)) { ND6_WLOCK(); nd6_defrouter_select(); ND6_UNLOCK(); } a2086 1 int s; d2088 3 a2090 2 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, d2092 1 a2092 3 s = pserialize_read_enter(); IFNET_READER_FOREACH(ifp) { d2106 2 a2107 3 pserialize_read_exit(s); SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); d2110 1 a2110 5 /* * Return 0 if a neighbor cache is found. Return EWOULDBLOCK if a cache is not * found and trying to resolve a neighbor; in this case the mbuf is queued in * the list. Otherwise return errno after freeing the mbuf. */ d2112 2 a2113 2 nd6_resolve(struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m, const struct sockaddr *_dst, uint8_t *lldst, size_t dstsize) d2115 45 a2159 3 struct llentry *ln = NULL; bool created = false; const struct sockaddr_in6 *dst = satocsin6(_dst); d2161 20 a2180 4 /* discard the packet if IPv6 operation is disabled on the interface */ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { m_freem(m); return ENETDOWN; /* better error? */ d2191 3 a2193 16 ln = nd6_lookup(&dst->sin6_addr, ifp, false); if (ln != NULL && (ln->la_flags & LLE_VALID) != 0) { KASSERT(ln->ln_state > ND6_LLINFO_INCOMPLETE); /* Fast path */ memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); LLE_RUNLOCK(ln); return 0; } if (ln != NULL) LLE_RUNLOCK(ln); /* Slow path */ ln = nd6_lookup(&dst->sin6_addr, ifp, true); if (ln == NULL && nd6_is_addr_neighbor(dst, ifp)) { struct sockaddr_in6 sin6; d2199 7 a2205 3 ln = nd6_create(&dst->sin6_addr, ifp); if (ln == NULL) { char ip6buf[INET6_ADDRSTRLEN]; d2207 4 a2210 5 "%s: can't allocate llinfo for %s " "(ln=%p, rt=%p)\n", __func__, IN6_PRINT(ip6buf, &dst->sin6_addr), ln, rt); m_freem(m); return ENOBUFS; d2213 1 a2213 4 sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); rt_clonedmsg(sin6tosa(&sin6), ifp, rt); created = true; d2216 7 a2222 6 if (ln == NULL) { m_freem(m); return ENETDOWN; /* better error? */ } LLE_WLOCK_ASSERT(ln); d2228 1 a2228 1 nd6_llinfo_settimer(ln, nd6_gctimer * hz); d2241 1 a2241 1 nd6_llinfo_settimer(ln, nd6_delay * hz); d2245 8 d2288 6 a2293 1 struct in6_addr src, *psrc; d2295 5 a2299 9 ln->ln_asked++; nd6_llinfo_settimer(ln, ND_IFINFO(ifp)->retrans * hz / 1000); psrc = nd6_llinfo_get_holdsrc(ln, &src); LLE_WUNLOCK(ln); ln = NULL; nd6_ns_output(ifp, NULL, &dst->sin6_addr, psrc, 0); } else { /* We did the lookup so we need to do the unlock here. */ LLE_WUNLOCK(ln); d2302 7 a2308 2 if (created) nd6_gc_neighbors(LLTABLE6(ifp), &dst->sin6_addr); d2310 4 a2313 1 return EWOULDBLOCK; d2315 1 d2342 51 d2394 1 a2394 1 clear_llinfo_pqueue(struct llentry *ln) a2419 1 size_t bufsize = 0; d2429 4 a2432 3 if (oldp && *oldlenp > 0) { p = kmem_alloc(*oldlenp, KM_SLEEP); bufsize = *oldlenp; d2456 1 a2456 1 kmem_free(p, bufsize); d2464 1 a2464 1 int error = 0; d2469 2 d2477 1 a2477 2 ND6_RLOCK(); ND_DEFROUTER_LIST_FOREACH(dr) { a2482 1 char ip6buf[INET6_ADDRSTRLEN]; d2485 1 a2485 1 IN6_PRINT(ip6buf, &d->rtaddr.sin6_addr)); d2490 1 a2490 2 d->expire = dr->expire ? time_mono_to_wall(dr->expire) : 0; a2497 1 ND6_UNLOCK(); d2506 2 d2514 1 a2514 1 int error = 0; d2519 2 a2520 1 char ip6buf[INET6_ADDRSTRLEN]; d2528 1 a2528 2 ND6_RLOCK(); ND_PREFIX_LIST_FOREACH(pr) { d2543 1 a2543 1 IN6_PRINT(ip6buf, &pfx.prefix.sin6_addr)); d2581 1 a2581 1 0, 0, 0); d2586 1 a2586 2 IN6_PRINT(ip6buf, &pfr->router->rtaddr)); a2604 1 ND6_UNLOCK(); d2613 2 a2616 29 static int nd6_setdefaultiface(int ifindex) { ifnet_t *ifp; int error = 0; int s; s = pserialize_read_enter(); ifp = if_byindex(ifindex); if (ifp == NULL) { pserialize_read_exit(s); return EINVAL; } if (nd6_defifindex != ifindex) { nd6_defifindex = ifindex; nd6_defifp = nd6_defifindex > 0 ? ifp : NULL; /* * Our current implementation assumes one-to-one maping between * interfaces and links, so it would be natural to use the * default interface as the default link. */ scope6_setdefault(nd6_defifp); } pserialize_read_exit(s); return (error); } @ 1.142 log @remove KAME IPSEC, replaced by FAST_IPSEC @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.141 2012/02/03 03:32:45 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.141 2012/02/03 03:32:45 christos Exp $"); d134 10 d486 1 d1346 29 d2086 8 @ 1.141 log @PR/45764, PR/45914 Part 1: nd6_purge can be called after dom_ifdetach, and if_afdata[AF_INET6] is going to be freed and point to garbage. Make sure we check for NULL, before taking the pointer offset. While I am here, add an M_ZERO. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.140 2012/02/02 19:35:18 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.140 2012/02/02 19:35:18 christos Exp $"); a71 4 #ifdef KAME_IPSEC #include #endif a2123 4 #ifdef KAME_IPSEC /* clean ipsec history once it goes out of the node */ ipsec_delaux(m); #endif @ 1.141.8.1 log @Pull up revisions: src/share/man/man7/sysctl.7 revision 1.73 via patch src/sys/netinet6/icmp6.c revision 1.161 via patch src/sys/netinet6/in6.c revision 1.161 via patch src/sys/netinet6/in6_proto.c revision 1.97 via patch src/sys/netinet6/in6_var.h revision 1.65 via patch src/sys/netinet6/ip6_input.c revision 1.139 via patch src/sys/netinet6/ip6_var.h revision 1.59 via patch src/sys/netinet6/nd6.c revision 1.143 via patch src/sys/netinet6/nd6.h revision 1.57 via patch src/sys/netinet6/nd6_rtr.c revision 1.83 via patch (requested by christos in ticket #905). Patch by Loganaden Velvindron. 4 new sysctls to avoid ipv6 DoS attacks from OpenBSD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.141 2012/02/03 03:32:45 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.141 2012/02/03 03:32:45 christos Exp $"); a137 11 #define LN_DEQUEUE(ln) do { \ (ln)->ln_next->ln_prev = (ln)->ln_prev; \ (ln)->ln_prev->ln_next = (ln)->ln_next; \ } while (/*CONSTCOND*/0) #define LN_INSERTHEAD(ln) do { \ (ln)->ln_next = llinfo_nd6.ln_next; \ llinfo_nd6.ln_next = (ln); \ (ln)->ln_prev = &llinfo_nd6; \ (ln)->ln_next->ln_prev = (ln); \ } while (/*CONSTCOND*/0) d479 1 a479 1 case ND6_LLINFO_PURGE: a1338 29 /* * If we have too many cache entries, initiate immediate * purging for some "less recently used" entries. Note that * we cannot directly call nd6_free() here because it would * cause re-entering rtable related routines triggering an LOR * problem for FreeBSD. */ if (ip6_neighborgcthresh >= 0 && nd6_inuse >= ip6_neighborgcthresh) { int i; for (i = 0; i < 10 && llinfo_nd6.ln_prev != ln; i++) { struct llinfo_nd6 *ln_end = llinfo_nd6.ln_prev; /* Move this entry to the head */ LN_DEQUEUE(ln_end); LN_INSERTHEAD(ln_end); if (ND6_LLINFO_PERMANENT(ln_end)) continue; if (ln_end->ln_state > ND6_LLINFO_INCOMPLETE) ln_end->ln_state = ND6_LLINFO_STALE; else ln_end->ln_state = ND6_LLINFO_PURGE; nd6_llinfo_settimer(ln_end, 0); } } a2049 8 /* * Move this entry to the head of the queue so that it is less likely * for this entry to be a target of forced garbage collection (see * nd6_rtrequest()). */ LN_DEQUEUE(ln); LN_INSERTHEAD(ln); @ 1.141.8.2 log @Pull up following revision(s) (requested by martin in ticket #998): usr.sbin/ndp/ndp.c: revision 1.42 sys/netinet6/nd6.c: revision 1.146 Instead of voodo casts use simple byte pointer arithmetic and memcpy to create the "packed" binary format we pass out to userland when querying the router/prefix list. Simplify code to print the router/prefix list: use memcpy and local structs properly aligned on the stack to decode the binary format passed by the kernel - instead of (bogusly) assuming the format will obey all local alignement requirements. @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d2390 2 a2391 2 uint8_t *p = NULL, *ps = NULL; uint8_t *pe = NULL; d2397 2 a2398 2 ps = p = (uint8_t*)oldp; pe = (uint8_t*)oldp + *oldlenp; d2404 3 a2406 1 struct sockaddr_in6 sin6; a2407 1 struct in6_prefix pfx; d2409 1 a2409 1 if (oldp && p + sizeof(struct in6_prefix) <= pe) d2411 2 a2412 3 memset(&pfx, 0, sizeof(pfx)); ps = p; pfx.prefix = pr->ndpr_prefix; d2414 2 a2415 1 if (sa6_recoverscope(&pfx.prefix)) { d2418 1 a2418 1 ip6_sprintf(&pfx.prefix.sin6_addr)); d2421 5 a2425 5 pfx.raflags = pr->ndpr_raf; pfx.prefixlen = pr->ndpr_plen; pfx.vltime = pr->ndpr_vltime; pfx.pltime = pr->ndpr_pltime; pfx.if_index = pr->ndpr_ifp->if_index; d2427 1 a2427 1 pfx.expire = 0; d2437 1 a2437 1 pfx.expire = pr->ndpr_lastupdate + d2440 1 a2440 1 pfx.expire = maxexpire; d2442 3 a2444 6 pfx.refcnt = pr->ndpr_refcnt; pfx.flags = pr->ndpr_stateflags; pfx.origin = PR_ORIG_RA; p += sizeof(pfx); l += sizeof(pfx); d2447 1 a2447 1 if (p + sizeof(sin6) > pe) { d2451 2 a2452 2 sockaddr_in6_init(&sin6, &pfr->router->rtaddr, d2454 1 a2454 1 if (sa6_recoverscope(&sin6)) { a2460 3 memcpy(p, &sin6, sizeof(sin6)); p += sizeof(sin6); l += sizeof(sin6); d2462 1 a2462 2 pfx.advrtrs = advrtrs; memcpy(ps, &pfx, sizeof(pfx)); a2464 1 l += sizeof(pfx); d2466 1 a2466 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { a2467 2 l += sizeof(sin6); } d2469 5 @ 1.141.8.3 log @Pull up following revision(s) (requested by bouyer in ticket #1067): sys/dist/ipf/netinet/ip_fil_netbsd.c 1.9 via patch sys/net/if_ethersubr.c 1.197 via patch sys/net/if_loop.c 1.77 via patch sys/net/if_vlan.c 1.70 via patch sys/netinet/if_arp.c 1.158 sys/netinet/ip_carp.c 1.54 via patch sys/netinet6/ip6_flow.c 1.23 via patch sys/netinet6/nd6.c 1.150 via patch sys/rump/librump/rumpkern/klock.c 1.4 Make sure *(if_output)() is called with KERNEL_LOCK held to avoid mbuf leak. See http://mail-index.netbsd.org/tech-net/2014/04/09/msg004511.html for details. For netinet6, the problem report, fix and test were done by njoly@@ on current-users@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.141.8.2 2013/12/17 20:47:49 bouyer Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.141.8.2 2013/12/17 20:47:49 bouyer Exp $"); a2179 1 KERNEL_LOCK(1, NULL); d2181 2 a2182 5 error = (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); else error = (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); KERNEL_UNLOCK_ONE(NULL); return error; @ 1.141.6.1 log @Pull up revisions: src/share/man/man7/sysctl.7 revision 1.73 via patch src/sys/netinet6/icmp6.c revision 1.161 via patch src/sys/netinet6/in6.c revision 1.161 via patch src/sys/netinet6/in6_proto.c revision 1.97 via patch src/sys/netinet6/in6_var.h revision 1.65 via patch src/sys/netinet6/ip6_input.c revision 1.139 via patch src/sys/netinet6/ip6_var.h revision 1.59 via patch src/sys/netinet6/nd6.c revision 1.143 via patch src/sys/netinet6/nd6.h revision 1.57 via patch src/sys/netinet6/nd6_rtr.c revision 1.83 via patch (requested by christos in ticket #905). Patch by Loganaden Velvindron. 4 new sysctls to avoid ipv6 DoS attacks from OpenBSD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.141 2012/02/03 03:32:45 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.141 2012/02/03 03:32:45 christos Exp $"); a137 11 #define LN_DEQUEUE(ln) do { \ (ln)->ln_next->ln_prev = (ln)->ln_prev; \ (ln)->ln_prev->ln_next = (ln)->ln_next; \ } while (/*CONSTCOND*/0) #define LN_INSERTHEAD(ln) do { \ (ln)->ln_next = llinfo_nd6.ln_next; \ llinfo_nd6.ln_next = (ln); \ (ln)->ln_prev = &llinfo_nd6; \ (ln)->ln_next->ln_prev = (ln); \ } while (/*CONSTCOND*/0) d479 1 a479 1 case ND6_LLINFO_PURGE: a1338 29 /* * If we have too many cache entries, initiate immediate * purging for some "less recently used" entries. Note that * we cannot directly call nd6_free() here because it would * cause re-entering rtable related routines triggering an LOR * problem for FreeBSD. */ if (ip6_neighborgcthresh >= 0 && nd6_inuse >= ip6_neighborgcthresh) { int i; for (i = 0; i < 10 && llinfo_nd6.ln_prev != ln; i++) { struct llinfo_nd6 *ln_end = llinfo_nd6.ln_prev; /* Move this entry to the head */ LN_DEQUEUE(ln_end); LN_INSERTHEAD(ln_end); if (ND6_LLINFO_PERMANENT(ln_end)) continue; if (ln_end->ln_state > ND6_LLINFO_INCOMPLETE) ln_end->ln_state = ND6_LLINFO_STALE; else ln_end->ln_state = ND6_LLINFO_PURGE; nd6_llinfo_settimer(ln_end, 0); } } a2049 8 /* * Move this entry to the head of the queue so that it is less likely * for this entry to be a target of forced garbage collection (see * nd6_rtrequest()). */ LN_DEQUEUE(ln); LN_INSERTHEAD(ln); @ 1.141.6.2 log @Pull up following revision(s) (requested by martin in ticket #998): usr.sbin/ndp/ndp.c: revision 1.42 sys/netinet6/nd6.c: revision 1.146 Instead of voodo casts use simple byte pointer arithmetic and memcpy to create the "packed" binary format we pass out to userland when querying the router/prefix list. Simplify code to print the router/prefix list: use memcpy and local structs properly aligned on the stack to decode the binary format passed by the kernel - instead of (bogusly) assuming the format will obey all local alignement requirements. @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d2390 2 a2391 2 uint8_t *p = NULL, *ps = NULL; uint8_t *pe = NULL; d2397 2 a2398 2 ps = p = (uint8_t*)oldp; pe = (uint8_t*)oldp + *oldlenp; d2404 3 a2406 1 struct sockaddr_in6 sin6; a2407 1 struct in6_prefix pfx; d2409 1 a2409 1 if (oldp && p + sizeof(struct in6_prefix) <= pe) d2411 2 a2412 3 memset(&pfx, 0, sizeof(pfx)); ps = p; pfx.prefix = pr->ndpr_prefix; d2414 2 a2415 1 if (sa6_recoverscope(&pfx.prefix)) { d2418 1 a2418 1 ip6_sprintf(&pfx.prefix.sin6_addr)); d2421 5 a2425 5 pfx.raflags = pr->ndpr_raf; pfx.prefixlen = pr->ndpr_plen; pfx.vltime = pr->ndpr_vltime; pfx.pltime = pr->ndpr_pltime; pfx.if_index = pr->ndpr_ifp->if_index; d2427 1 a2427 1 pfx.expire = 0; d2437 1 a2437 1 pfx.expire = pr->ndpr_lastupdate + d2440 1 a2440 1 pfx.expire = maxexpire; d2442 3 a2444 6 pfx.refcnt = pr->ndpr_refcnt; pfx.flags = pr->ndpr_stateflags; pfx.origin = PR_ORIG_RA; p += sizeof(pfx); l += sizeof(pfx); d2447 1 a2447 1 if (p + sizeof(sin6) > pe) { d2451 2 a2452 2 sockaddr_in6_init(&sin6, &pfr->router->rtaddr, d2454 1 a2454 1 if (sa6_recoverscope(&sin6)) { a2460 3 memcpy(p, &sin6, sizeof(sin6)); p += sizeof(sin6); l += sizeof(sin6); d2462 1 a2462 2 pfx.advrtrs = advrtrs; memcpy(ps, &pfx, sizeof(pfx)); a2464 1 l += sizeof(pfx); d2466 1 a2466 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { a2467 2 l += sizeof(sin6); } d2469 5 @ 1.141.6.3 log @Pull up following revision(s) (requested by bouyer in ticket #1067): sys/dist/ipf/netinet/ip_fil_netbsd.c 1.9 via patch sys/net/if_ethersubr.c 1.197 via patch sys/net/if_loop.c 1.77 via patch sys/net/if_vlan.c 1.70 via patch sys/netinet/if_arp.c 1.158 sys/netinet/ip_carp.c 1.54 via patch sys/netinet6/ip6_flow.c 1.23 via patch sys/netinet6/nd6.c 1.150 via patch sys/rump/librump/rumpkern/klock.c 1.4 Make sure *(if_output)() is called with KERNEL_LOCK held to avoid mbuf leak. See http://mail-index.netbsd.org/tech-net/2014/04/09/msg004511.html for details. For netinet6, the problem report, fix and test were done by njoly@@ on current-users@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.141.6.2 2013/12/17 20:47:43 bouyer Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.141.6.2 2013/12/17 20:47:43 bouyer Exp $"); a2179 1 KERNEL_LOCK(1, NULL); d2181 2 a2182 5 error = (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); else error = (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); KERNEL_UNLOCK_ONE(NULL); return error; @ 1.141.2.1 log @Pull up revisions: src/share/man/man7/sysctl.7 revision 1.73 via patch src/sys/netinet6/icmp6.c revision 1.161 via patch src/sys/netinet6/in6.c revision 1.161 via patch src/sys/netinet6/in6_proto.c revision 1.97 via patch src/sys/netinet6/in6_var.h revision 1.65 via patch src/sys/netinet6/ip6_input.c revision 1.139 via patch src/sys/netinet6/ip6_var.h revision 1.59 via patch src/sys/netinet6/nd6.c revision 1.143 via patch src/sys/netinet6/nd6.h revision 1.57 via patch src/sys/netinet6/nd6_rtr.c revision 1.83 via patch (requested by christos in ticket #905). Patch by Loganaden Velvindron. 4 new sysctls to avoid ipv6 DoS attacks from OpenBSD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.141 2012/02/03 03:32:45 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.141 2012/02/03 03:32:45 christos Exp $"); a137 11 #define LN_DEQUEUE(ln) do { \ (ln)->ln_next->ln_prev = (ln)->ln_prev; \ (ln)->ln_prev->ln_next = (ln)->ln_next; \ } while (/*CONSTCOND*/0) #define LN_INSERTHEAD(ln) do { \ (ln)->ln_next = llinfo_nd6.ln_next; \ llinfo_nd6.ln_next = (ln); \ (ln)->ln_prev = &llinfo_nd6; \ (ln)->ln_next->ln_prev = (ln); \ } while (/*CONSTCOND*/0) d479 1 a479 1 case ND6_LLINFO_PURGE: a1338 29 /* * If we have too many cache entries, initiate immediate * purging for some "less recently used" entries. Note that * we cannot directly call nd6_free() here because it would * cause re-entering rtable related routines triggering an LOR * problem for FreeBSD. */ if (ip6_neighborgcthresh >= 0 && nd6_inuse >= ip6_neighborgcthresh) { int i; for (i = 0; i < 10 && llinfo_nd6.ln_prev != ln; i++) { struct llinfo_nd6 *ln_end = llinfo_nd6.ln_prev; /* Move this entry to the head */ LN_DEQUEUE(ln_end); LN_INSERTHEAD(ln_end); if (ND6_LLINFO_PERMANENT(ln_end)) continue; if (ln_end->ln_state > ND6_LLINFO_INCOMPLETE) ln_end->ln_state = ND6_LLINFO_STALE; else ln_end->ln_state = ND6_LLINFO_PURGE; nd6_llinfo_settimer(ln_end, 0); } } a2049 8 /* * Move this entry to the head of the queue so that it is less likely * for this entry to be a target of forced garbage collection (see * nd6_rtrequest()). */ LN_DEQUEUE(ln); LN_INSERTHEAD(ln); @ 1.141.2.2 log @Pull up following revision(s) (requested by martin in ticket #998): usr.sbin/ndp/ndp.c: revision 1.42 sys/netinet6/nd6.c: revision 1.146 Instead of voodo casts use simple byte pointer arithmetic and memcpy to create the "packed" binary format we pass out to userland when querying the router/prefix list. Simplify code to print the router/prefix list: use memcpy and local structs properly aligned on the stack to decode the binary format passed by the kernel - instead of (bogusly) assuming the format will obey all local alignement requirements. @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d2390 2 a2391 2 uint8_t *p = NULL, *ps = NULL; uint8_t *pe = NULL; d2397 2 a2398 2 ps = p = (uint8_t*)oldp; pe = (uint8_t*)oldp + *oldlenp; d2404 3 a2406 1 struct sockaddr_in6 sin6; a2407 1 struct in6_prefix pfx; d2409 1 a2409 1 if (oldp && p + sizeof(struct in6_prefix) <= pe) d2411 2 a2412 3 memset(&pfx, 0, sizeof(pfx)); ps = p; pfx.prefix = pr->ndpr_prefix; d2414 2 a2415 1 if (sa6_recoverscope(&pfx.prefix)) { d2418 1 a2418 1 ip6_sprintf(&pfx.prefix.sin6_addr)); d2421 5 a2425 5 pfx.raflags = pr->ndpr_raf; pfx.prefixlen = pr->ndpr_plen; pfx.vltime = pr->ndpr_vltime; pfx.pltime = pr->ndpr_pltime; pfx.if_index = pr->ndpr_ifp->if_index; d2427 1 a2427 1 pfx.expire = 0; d2437 1 a2437 1 pfx.expire = pr->ndpr_lastupdate + d2440 1 a2440 1 pfx.expire = maxexpire; d2442 3 a2444 6 pfx.refcnt = pr->ndpr_refcnt; pfx.flags = pr->ndpr_stateflags; pfx.origin = PR_ORIG_RA; p += sizeof(pfx); l += sizeof(pfx); d2447 1 a2447 1 if (p + sizeof(sin6) > pe) { d2451 2 a2452 2 sockaddr_in6_init(&sin6, &pfr->router->rtaddr, d2454 1 a2454 1 if (sa6_recoverscope(&sin6)) { a2460 3 memcpy(p, &sin6, sizeof(sin6)); p += sizeof(sin6); l += sizeof(sin6); d2462 1 a2462 2 pfx.advrtrs = advrtrs; memcpy(ps, &pfx, sizeof(pfx)); a2464 1 l += sizeof(pfx); d2466 1 a2466 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { a2467 2 l += sizeof(sin6); } d2469 5 @ 1.141.2.3 log @Pull up following revision(s) (requested by bouyer in ticket #1067): sys/dist/ipf/netinet/ip_fil_netbsd.c 1.9 via patch sys/net/if_ethersubr.c 1.197 via patch sys/net/if_loop.c 1.77 via patch sys/net/if_vlan.c 1.70 via patch sys/netinet/if_arp.c 1.158 sys/netinet/ip_carp.c 1.54 via patch sys/netinet6/ip6_flow.c 1.23 via patch sys/netinet6/nd6.c 1.150 via patch sys/rump/librump/rumpkern/klock.c 1.4 Make sure *(if_output)() is called with KERNEL_LOCK held to avoid mbuf leak. See http://mail-index.netbsd.org/tech-net/2014/04/09/msg004511.html for details. For netinet6, the problem report, fix and test were done by njoly@@ on current-users@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.141.2.2 2013/12/17 20:47:33 bouyer Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.141.2.2 2013/12/17 20:47:33 bouyer Exp $"); a2179 1 KERNEL_LOCK(1, NULL); d2181 2 a2182 5 error = (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); else error = (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); KERNEL_UNLOCK_ONE(NULL); return error; @ 1.140 log @use FOREACH_SAFE. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.139 2011/12/19 11:59:58 drochner Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.139 2011/12/19 11:59:58 drochner Exp $"); d166 1 a166 2 nd = (struct nd_ifinfo *)malloc(sizeof(*nd), M_IP6NDP, M_WAITOK); memset(nd, 0, sizeof(*nd)); a723 1 struct nd_ifinfo *ndi = ND_IFINFO(ifp); d777 6 a782 3 if (!ip6_forwarding && ndi && nd6_accepts_rtadv(ndi)) { /* refresh default router list */ defrouter_select(); @ 1.139 log @rename the IPSEC in-kernel CPP variable and config(8) option to KAME_IPSEC, and make IPSEC define it so that existing kernel config files work as before Now the default can be easily be changed to FAST_IPSEC just by setting the IPSEC alias to FAST_IPSEC. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.138 2011/11/19 22:51:29 tls Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.138 2011/11/19 22:51:29 tls Exp $"); d537 1 a537 2 for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = next_dr) { next_dr = TAILQ_NEXT(dr, dr_entry); d615 1 a615 2 for (pr = LIST_FIRST(&nd_prefix); pr != NULL; pr = next_pr) { next_pr = LIST_NEXT(pr, ndpr_entry); d736 1 a736 2 for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = ndr) { ndr = TAILQ_NEXT(dr, dr_entry); d743 2 a744 2 for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = ndr) { ndr = TAILQ_NEXT(dr, dr_entry); d753 1 a753 2 for (pr = LIST_FIRST(&nd_prefix); pr != NULL; pr = npr) { npr = LIST_NEXT(pr, ndpr_entry); d1592 1 a1592 1 for (pfx = LIST_FIRST(&nd_prefix); pfx; pfx = next) { a1594 2 next = LIST_NEXT(pfx, ndpr_entry); d1621 1 a1621 2 for (drtr = TAILQ_FIRST(&nd_defrouter); drtr; drtr = next) { next = TAILQ_NEXT(drtr, dr_entry); @ 1.138 log @First step of random number subsystem rework described in <20111022023242.BA26F14A158@@mail.netbsd.org>. This change includes the following: An initial cleanup and minor reorganization of the entropy pool code in sys/dev/rnd.c and sys/dev/rndpool.c. Several bugs are fixed. Some effort is made to accumulate entropy more quickly at boot time. A generic interface, "rndsink", is added, for stream generators to request that they be re-keyed with good quality entropy from the pool as soon as it is available. The arc4random()/arc4randbytes() implementation in libkern is adjusted to use the rndsink interface for rekeying, which helps address the problem of low-quality keys at boot time. An implementation of the FIPS 140-2 statistical tests for random number generator quality is provided (libkern/rngtest.c). This is based on Greg Rose's implementation from Qualcomm. A new random stream generator, nist_ctr_drbg, is provided. It is based on an implementation of the NIST SP800-90 CTR_DRBG by Henric Jungheim. This generator users AES in a modified counter mode to generate a backtracking-resistant random stream. An abstraction layer, "cprng", is provided for in-kernel consumers of randomness. The arc4random/arc4randbytes API is deprecated for in-kernel use. It is replaced by "cprng_strong". The current cprng_fast implementation wraps the existing arc4random implementation. The current cprng_strong implementation wraps the new CTR_DRBG implementation. Both interfaces are rekeyed from the entropy pool automatically at intervals justifiable from best current cryptographic practice. In some quick tests, cprng_fast() is about the same speed as the old arc4randbytes(), and cprng_strong() is about 20% faster than rnd_extract_data(). Performance is expected to improve. The AES code in src/crypto/rijndael is no longer an optional kernel component, as it is required by cprng_strong, which is not an optional kernel component. The entropy pool output is subjected to the rngtest tests at startup time; if it fails, the system will reboot. There is approximately a 3/10000 chance of a false positive from these tests. Entropy pool _input_ from hardware random numbers is subjected to the rngtest tests at attach time, as well as the FIPS continuous-output test, to detect bad or stuck hardware RNGs; if any are detected, they are detached, but the system continues to run. A problem with rndctl(8) is fixed -- datastructures with pointers in arrays are no longer passed to userspace (this was not a security problem, but rather a major issue for compat32). A new kernel will require a new rndctl. The sysctl kern.arandom() and kern.urandom() nodes are hooked up to the new generators, but the /dev/*random pseudodevices are not, yet. Manual pages for the new kernel interfaces are forthcoming. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.137 2011/11/10 17:10:00 seanb Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.137 2011/11/10 17:10:00 seanb Exp $"); d72 1 a72 1 #ifdef IPSEC d2134 1 a2134 1 #ifdef IPSEC @ 1.138.2.1 log @merge to -current. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.141 2012/02/03 03:32:45 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.141 2012/02/03 03:32:45 christos Exp $"); d72 1 a72 1 #ifdef KAME_IPSEC d166 2 a167 1 nd = (struct nd_ifinfo *)malloc(sizeof(*nd), M_IP6NDP, M_WAITOK|M_ZERO); d537 2 a538 1 TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, next_dr) { d616 2 a617 1 LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, next_pr) { d727 1 d738 2 a739 1 TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, ndr) { d746 2 a747 2 TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, ndr) { d756 2 a757 1 LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, npr) { d783 3 a785 6 if (!ip6_forwarding && ifp->if_afdata[AF_INET6]) { struct nd_ifinfo *ndi = ND_IFINFO(ifp); if (ndi && nd6_accepts_rtadv(ndi)) { /* refresh default router list */ defrouter_select(); } d1596 1 a1596 1 LIST_FOREACH_SAFE(pfx, &nd_prefix, ndpr_entry, next) { d1599 2 d1627 2 a1628 1 TAILQ_FOREACH_SAFE(drtr, &nd_defrouter, dr_entry, next) { d2134 1 a2134 1 #ifdef KAME_IPSEC @ 1.138.2.2 log @sync to latest -current. @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d72 4 d2128 4 @ 1.137 log @- Remove unused variable from nd6_timer(). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.136 2010/07/15 19:15:30 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.136 2010/07/15 19:15:30 dyoung Exp $"); d53 1 @ 1.136 log @To help find the cause of kernel complaints such as "/netbsd: nd6_storelladdr: sdl_alen == 0, dst=... if=wm1", add printfs for some "impossible" conditions, and make the nd6_storelladdr() printf more informative by printing the value of sdl_alen. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.135 2009/11/06 20:41:22 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.135 2009/11/06 20:41:22 dyoung Exp $"); a526 1 struct in6_addrlifetime *lt6; a552 1 lt6 = &ia6->ia6_lifetime; @ 1.136.8.1 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.136 2010/07/15 19:15:30 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.136 2010/07/15 19:15:30 dyoung Exp $"); a52 1 #include d71 4 d165 2 a166 1 nd = (struct nd_ifinfo *)malloc(sizeof(*nd), M_IP6NDP, M_WAITOK|M_ZERO); d527 1 d537 2 a538 1 TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, next_dr) { d554 1 d617 2 a618 1 LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, next_pr) { d728 1 d739 2 a740 1 TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, ndr) { d747 2 a748 2 TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, ndr) { d757 2 a758 1 LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, npr) { d784 3 a786 6 if (!ip6_forwarding && ifp->if_afdata[AF_INET6]) { struct nd_ifinfo *ndi = ND_IFINFO(ifp); if (ndi && nd6_accepts_rtadv(ndi)) { /* refresh default router list */ defrouter_select(); } d1597 1 a1597 1 LIST_FOREACH_SAFE(pfx, &nd_prefix, ndpr_entry, next) { d1600 2 d1628 2 a1629 1 TAILQ_FOREACH_SAFE(drtr, &nd_defrouter, dr_entry, next) { d2135 4 @ 1.136.8.2 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.136.8.1 2012/04/17 00:08:45 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.136.8.1 2012/04/17 00:08:45 yamt Exp $"); a133 10 #define LN_DEQUEUE(ln) do { \ (ln)->ln_next->ln_prev = (ln)->ln_prev; \ (ln)->ln_prev->ln_next = (ln)->ln_next; \ } while (/*CONSTCOND*/0) #define LN_INSERTHEAD(ln) do { \ (ln)->ln_next = llinfo_nd6.ln_next; \ llinfo_nd6.ln_next = (ln); \ (ln)->ln_prev = &llinfo_nd6; \ (ln)->ln_next->ln_prev = (ln); \ } while (/*CONSTCOND*/0) a475 1 case ND6_LLINFO_PURGE: a1334 29 /* * If we have too many cache entries, initiate immediate * purging for some "less recently used" entries. Note that * we cannot directly call nd6_free() here because it would * cause re-entering rtable related routines triggering an LOR * problem for FreeBSD. */ if (ip6_neighborgcthresh >= 0 && nd6_inuse >= ip6_neighborgcthresh) { int i; for (i = 0; i < 10 && llinfo_nd6.ln_prev != ln; i++) { struct llinfo_nd6 *ln_end = llinfo_nd6.ln_prev; /* Move this entry to the head */ LN_DEQUEUE(ln_end); LN_INSERTHEAD(ln_end); if (ND6_LLINFO_PERMANENT(ln_end)) continue; if (ln_end->ln_state > ND6_LLINFO_INCOMPLETE) ln_end->ln_state = ND6_LLINFO_STALE; else ln_end->ln_state = ND6_LLINFO_PURGE; nd6_llinfo_settimer(ln_end, 0); } } a2045 8 /* * Move this entry to the head of the queue so that it is less likely * for this entry to be a target of forced garbage collection (see * nd6_rtrequest()). */ LN_DEQUEUE(ln); LN_INSERTHEAD(ln); @ 1.136.8.3 log @sync with head. for a reference, the tree before this commit was tagged as yamt-pagecache-tag8. this commit was splitted into small chunks to avoid a limitation of cvs. ("Protocol error: too many arguments") @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.136.8.2 2012/10/30 17:22:49 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.136.8.2 2012/10/30 17:22:49 yamt Exp $"); d585 1 a585 4 if ((oldflags & IN6_IFF_DEPRECATED) == 0) { ia6->ia6_flags |= IN6_IFF_DEPRECATED; nd6_newaddrmsg((struct ifaddr *)ia6); } d616 1 a616 4 if (ia6->ia6_flags & IN6_IFF_DEPRECATED) { ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; nd6_newaddrmsg((struct ifaddr *)ia6); } d815 2 a816 3 static struct rtentry * nd6_lookup1(const struct in6_addr *addr6, int create, struct ifnet *ifp, int cloning) a879 21 /* * Check for a cloning route to match the address. * This should only be set from in6_is_addr_neighbor so we avoid * a potentially expensive second call to rtalloc1. */ if (cloning && rt->rt_flags & (RTF_CLONING | RTF_CLONED) && (rt->rt_ifp == ifp #if NBRIDGE > 0 || SAME_BRIDGE(rt->rt_ifp->if_bridgeport, ifp->if_bridgeport) #endif #if NCARP > 0 || (ifp->if_type == IFT_CARP && rt->rt_ifp == ifp->if_carpdev) || (rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp)|| (ifp->if_type == IFT_CARP && rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp->if_carpdev) #endif )) return rt; a909 7 struct rtentry * nd6_lookup(const struct in6_addr *addr6, int create, struct ifnet *ifp) { return nd6_lookup1(addr6, create, ifp, 0); } d970 2 a971 2 * Even if the address matches none of our addresses, it might match * a cloning route or be in the neighbor cache. d973 1 a973 1 if (nd6_lookup1(&addr->sin6_addr, 0, ifp, 1) != NULL) d1147 1 a1147 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1182 1 a1182 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1196 1 a1196 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1217 1 a1217 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1247 1 a1247 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1250 1 a1250 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1254 1 a1254 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1285 1 a1285 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1300 1 a1300 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1304 1 a1304 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1311 1 a1311 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1316 1 a1316 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1339 1 a1339 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1375 1 a1375 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); d1382 1 a1382 1 RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); a1614 53 { struct ifaddr *ifa; struct in6_ifaddr *ia; if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && !(ND.flags & ND6_IFF_IFDISABLED)) { /* * If the interface is marked as ND6_IFF_IFDISABLED and * has a link-local address with IN6_IFF_DUPLICATED, * do not clear ND6_IFF_IFDISABLED. * See RFC 4862, section 5.4.5. */ int duplicated_linklocal = 0; IFADDR_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; if ((ia->ia6_flags & IN6_IFF_DUPLICATED) && IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) { duplicated_linklocal = 1; break; } } if (duplicated_linklocal) { ND.flags |= ND6_IFF_IFDISABLED; log(LOG_ERR, "Cannot enable an interface" " with a link-local address marked" " duplicate.\n"); } else { ND_IFINFO(ifp)->flags &= ~ND6_IFF_IFDISABLED; if (ifp->if_flags & IFF_UP) in6_if_up(ifp); } } else if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && (ND.flags & ND6_IFF_IFDISABLED)) { /* Mark all IPv6 addresses as tentative. */ ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED; IFADDR_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; nd6_dad_stop(ifa); ia = (struct in6_ifaddr *)ifa; ia->ia6_flags |= IN6_IFF_TENTATIVE; } } } d2382 2 a2383 2 uint8_t *p = NULL, *ps = NULL; uint8_t *pe = NULL; d2389 2 a2390 2 ps = p = (uint8_t*)oldp; pe = (uint8_t*)oldp + *oldlenp; d2396 3 a2398 1 struct sockaddr_in6 sin6; a2399 1 struct in6_prefix pfx; d2401 1 a2401 1 if (oldp && p + sizeof(struct in6_prefix) <= pe) d2403 2 a2404 3 memset(&pfx, 0, sizeof(pfx)); ps = p; pfx.prefix = pr->ndpr_prefix; d2406 2 a2407 1 if (sa6_recoverscope(&pfx.prefix)) { d2410 1 a2410 1 ip6_sprintf(&pfx.prefix.sin6_addr)); d2413 5 a2417 5 pfx.raflags = pr->ndpr_raf; pfx.prefixlen = pr->ndpr_plen; pfx.vltime = pr->ndpr_vltime; pfx.pltime = pr->ndpr_pltime; pfx.if_index = pr->ndpr_ifp->if_index; d2419 1 a2419 1 pfx.expire = 0; d2429 1 a2429 1 pfx.expire = pr->ndpr_lastupdate + d2432 1 a2432 1 pfx.expire = maxexpire; d2434 3 a2436 6 pfx.refcnt = pr->ndpr_refcnt; pfx.flags = pr->ndpr_stateflags; pfx.origin = PR_ORIG_RA; p += sizeof(pfx); l += sizeof(pfx); d2439 1 a2439 1 if (p + sizeof(sin6) > pe) { d2443 2 a2444 2 sockaddr_in6_init(&sin6, &pfr->router->rtaddr, d2446 1 a2446 1 if (sa6_recoverscope(&sin6)) { a2452 3 memcpy(p, &sin6, sizeof(sin6)); p += sizeof(sin6); l += sizeof(sin6); d2454 1 a2454 2 pfx.advrtrs = advrtrs; memcpy(ps, &pfx, sizeof(pfx)); a2456 1 l += sizeof(pfx); d2458 1 a2458 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { a2459 2 l += sizeof(sin6); } d2461 5 @ 1.135 log @Fix net.inet6.ip6.accept_rtadv and 'ndp -i accept_rtadv': Add a flag ND6_IFF_OVERRIDE_RTADV that tells the kernel to override ip6_accept_rtadv (net.inet6.ip6.accept_rtadv) on an interface. Add a routine nd6_accepts_rtadv(ndi) that evaluates both the flags on the interface represented by ndi and ip6_accept_rtadv, and returns 'true' if the given interface should accept Router Advertisements, and 'false' if not. Now, ND6_IFF_ACCEPT_RTADV works as it was historically documented: if it is set, then accept router advertisements iff ip6_accept_rtadv != 0. Otherwise, do not accept router advertisements. If ND6_IFF_OVERRIDE_RTADV is set, then the flag ND6_IFF_ACCEPT_RTADV overrides ip6_accept_rtadv: if ND6_IFF_ACCEPT_RTADV is set, accept; otherwise reject. Ignore ip6_accept_rtadv. If neither ND6_IFF_ACCEPT_RTADV nor ND6_IFF_OVERRIDE_RTADV is set, reject Router Advertisements. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.134 2009/08/31 12:37:59 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.134 2009/08/31 12:37:59 yamt Exp $"); d1235 1 a1235 1 sockaddr_dl_init(&u.sdl, sizeof(u.ss), d1237 5 a1241 1 NULL, namelen, NULL, addrlen); d1358 9 a1366 2 (void)sockaddr_dl_setaddr(satosdl(gate), gate->sa_len, mac, ifp->if_addrlen); d1791 6 a1796 2 (void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr, ifp->if_addrlen); d2215 3 a2217 2 printf("%s: sdl_alen == 0, dst=%s, if=%s\n", __func__, ip6_sprintf(&satocsin6(dst)->sin6_addr), if_name(ifp)); @ 1.135.4.1 log @sync with head @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d1235 1 a1235 1 if (sockaddr_dl_init(&u.sdl, sizeof(u.ss), d1237 1 a1237 5 NULL, namelen, NULL, addrlen) == NULL) { printf("%s.%d: sockaddr_dl_init(, %zu, ) " "failed on %s\n", __func__, __LINE__, sizeof(u.ss), if_name(ifp)); } d1354 2 a1355 9 if (sockaddr_dl_setaddr(satosdl(gate), gate->sa_len, mac, ifp->if_addrlen) == NULL) { printf("%s.%d: " "sockaddr_dl_setaddr(, %d, ) " "failed on %s\n", __func__, __LINE__, gate->sa_len, if_name(ifp)); } d1780 2 a1781 6 if (sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr, ifp->if_addrlen) == NULL) { printf("%s.%d: sockaddr_dl_setaddr(, %d, ) " "failed on %s\n", __func__, __LINE__, sdl->sdl_len, if_name(ifp)); } d2200 2 a2201 3 printf("%s: sdl_alen == %" PRIu8 ", dst=%s, if=%s\n", __func__, sdl->sdl_alen, ip6_sprintf(&satocsin6(dst)->sin6_addr), if_name(ifp)); @ 1.135.2.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d1235 1 a1235 1 if (sockaddr_dl_init(&u.sdl, sizeof(u.ss), d1237 1 a1237 5 NULL, namelen, NULL, addrlen) == NULL) { printf("%s.%d: sockaddr_dl_init(, %zu, ) " "failed on %s\n", __func__, __LINE__, sizeof(u.ss), if_name(ifp)); } d1354 2 a1355 9 if (sockaddr_dl_setaddr(satosdl(gate), gate->sa_len, mac, ifp->if_addrlen) == NULL) { printf("%s.%d: " "sockaddr_dl_setaddr(, %d, ) " "failed on %s\n", __func__, __LINE__, gate->sa_len, if_name(ifp)); } d1780 2 a1781 6 if (sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr, ifp->if_addrlen) == NULL) { printf("%s.%d: sockaddr_dl_setaddr(, %d, ) " "failed on %s\n", __func__, __LINE__, sdl->sdl_len, if_name(ifp)); } d2200 2 a2201 3 printf("%s: sdl_alen == %" PRIu8 ", dst=%s, if=%s\n", __func__, sdl->sdl_alen, ip6_sprintf(&satocsin6(dst)->sin6_addr), if_name(ifp)); @ 1.134 log @nd6_ifattach: fix a missing parens bug in rev.1.132. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.133 2009/08/06 12:17:11 cegger Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.133 2009/08/06 12:17:11 cegger Exp $"); d175 3 a177 3 * Note that the default value of ip6_accept_rtadv is 0, which means * we won't accept RAs by default even if we set ND6_IFF_ACCEPT_RTADV * here. d179 1 a179 2 nd->flags = (ND6_IFF_PERFORMNUD | (ip6_accept_rtadv ? ND6_IFF_ACCEPT_RTADV : 0)); d706 15 d784 1 a784 1 if (!ip6_forwarding && ndi && (ndi->flags & ND6_IFF_ACCEPT_RTADV)) { d1902 1 a1902 1 (ndi->flags & ND6_IFF_ACCEPT_RTADV)) @ 1.133 log @Check if ndi is valid before use. ok tonnerre@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.132 2009/07/25 23:12:09 tonnerre Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.132 2009/07/25 23:12:09 tonnerre Exp $"); d180 1 a180 1 ip6_accept_rtadv ? ND6_IFF_ACCEPT_RTADV : 0); @ 1.132 log @Instead of using the net.inet6.ip6.accept_rtadv sysctl for all devices, make net.inet6.ip6.accept_rtadv the default for individual per-device settings so people can use the ndp(8) utility to set per-device whether or not to accept route advertisements. rtadvd changes to follow. (Debated on tech-net@@ before but almost two weeks passed by without any comment on the patch.) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.131 2008/11/07 00:20:18 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.131 2008/11/07 00:20:18 dyoung Exp $"); d770 1 a770 1 if (!ip6_forwarding && (ndi->flags & ND6_IFF_ACCEPT_RTADV)) { @ 1.131 log @*** Summary *** When a link-layer address changes (e.g., ifconfig ex0 link 02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor Advertisement to update the network-/link-layer address bindings on our LAN peers. Refuse a change of ethernet address to the address 00:00:00:00:00:00 or to any multicast/broadcast address. (Thanks matt@@.) Reorder ifnet ioctl operations so that driver ioctls may inherit the functions of their "class"---ether_ioctl(), fddi_ioctl(), et cetera---and the class ioctls may inherit from the generic ioctl, ifioctl_common(), but both driver- and class-ioctls may override the generic behavior. Make network drivers share more code. Distinguish a "factory" link-layer address from others for the purposes of both protecting that address from deletion and computing EUI64. Return consistent, appropriate error codes from network drivers. Improve readability. KNF. *** Details *** In if_attach(), always initialize the interface ioctl routine, ifnet->if_ioctl, if the driver has not already initialized it. Delete if_ioctl == NULL tests everywhere else, because it cannot happen. In the ioctl routines of network interfaces, inherit common ioctl behaviors by calling either ifioctl_common() or whichever ioctl routine is appropriate for the class of interface---e.g., ether_ioctl() for ethernets. Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In the user->kernel interface, SIOCSIFADDR's argument was an ifreq, but on the protocol->ifnet interface, SIOCSIFADDR's argument was an ifaddr. That was confusing, and it would work against me as I make it possible for a network interface to overload most ioctls. On the protocol->ifnet interface, replace SIOCSIFADDR with SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to invoke SIOCINITIFADDR. In ifioctl(), give the interface the first shot at handling most interface ioctls, and give the protocol the second shot, instead of the other way around. Finally, let compatibility code (COMPAT_OSOCK) take a shot. Pull device initialization out of switch statements under SIOCINITIFADDR. For example, pull ..._init() out of any switch statement that looks like this: switch (...->sa_family) { case ...: ..._init(); ... break; ... default: ..._init(); ... break; } Rewrite many if-else clauses that handle all permutations of IFF_UP and IFF_RUNNING to use a switch statement, switch (x & (IFF_UP|IFF_RUNNING)) { case 0: ... break; case IFF_RUNNING: ... break; case IFF_UP: ... break; case IFF_UP|IFF_RUNNING: ... break; } unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and #ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4). In ipw(4), remove an if_set_sadl() call that is out of place. In nfe(4), reuse the jumbo MTU logic in ether_ioctl(). Let ethernets register a callback for setting h/w state such as promiscuous mode and the multicast filter in accord with a change in the if_flags: ether_set_ifflags_cb() registers a callback that returns ENETRESET if the caller should reset the ethernet by calling if_init(), 0 on success, != 0 on failure. Pull common code from ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(), and register if_flags callbacks for those drivers. Return ENOTTY instead of EINVAL for inappropriate ioctls. In zyd(4), use ENXIO instead of ENOTTY to indicate that the device is not any longer attached. Add to if_set_sadl() a boolean 'factory' argument that indicates whether a link-layer address was assigned by the factory or some other source. In a comment, recommend using the factory address for generating an EUI64, and update in6_get_hw_ifid() to prefer a factory address to any other link-layer address. Add a routing message, RTM_LLINFO_UPD, that tells protocols to update the binding of network-layer addresses to link-layer addresses. Implement this message in IPv4 and IPv6 by sending a gratuitous ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD messages on a change of an interface's link-layer address. In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address that is broadcast/multicast or equal to 00:00:00:00:00:00. Make ether_ioctl() call ifioctl_common() to handle ioctls that it does not understand. In gif(4), initialize if_softc and use it, instead of assuming that the gif_softc and ifp overlap. Let ifioctl_common() handle SIOCGIFADDR. Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels that certain invariants on a struct route are satisfied. In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit about the ioctls that we do not allow on an agr(4) member interface. bzero -> memset. Delete unnecessary casts to void *. Use sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with NULL instead of "testing truth". Replace some instances of (type *)0 with NULL. Change some K&R prototypes to ANSI C, and join lines. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.130 2008/10/24 17:07:33 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.130 2008/10/24 17:07:33 dyoung Exp $"); d179 2 a180 1 nd->flags = (ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV); d714 1 d769 2 a770 1 if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */ d1678 1 d1887 2 a1888 1 if (do_update && ln->ln_router && !ip6_forwarding && ip6_accept_rtadv) @ 1.130 log @Constify the rt_addrinfo argument to the ifa_rtrequest member function of struct ifaddr. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.129 2008/10/24 16:54:18 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.129 2008/10/24 16:54:18 dyoung Exp $"); d1129 29 @ 1.130.14.1 log @Pull up following revision(s) (requested by martin in ticket #1892): usr.sbin/ndp/ndp.c: revision 1.42 sys/netinet6/nd6.c: revision 1.146 Instead of voodo casts use simple byte pointer arithmetic and memcpy to create the "packed" binary format we pass out to userland when querying the router/prefix list. Simplify code to print the router/prefix list: use memcpy and local structs properly aligned on the stack to decode the binary format passed by the kernel - instead of (bogusly) assuming the format will obey all local alignement requirements. @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d2285 2 a2286 2 uint8_t *p = NULL, *ps = NULL; uint8_t *pe = NULL; d2292 2 a2293 2 ps = p = (uint8_t*)oldp; pe = (uint8_t*)oldp + *oldlenp; d2299 3 a2301 1 struct sockaddr_in6 sin6; a2302 1 struct in6_prefix pfx; d2304 1 a2304 1 if (oldp && p + sizeof(struct in6_prefix) <= pe) d2306 2 a2307 3 memset(&pfx, 0, sizeof(pfx)); ps = p; pfx.prefix = pr->ndpr_prefix; d2309 2 a2310 1 if (sa6_recoverscope(&pfx.prefix)) { d2313 1 a2313 1 ip6_sprintf(&pfx.prefix.sin6_addr)); d2316 5 a2320 5 pfx.raflags = pr->ndpr_raf; pfx.prefixlen = pr->ndpr_plen; pfx.vltime = pr->ndpr_vltime; pfx.pltime = pr->ndpr_pltime; pfx.if_index = pr->ndpr_ifp->if_index; d2322 1 a2322 1 pfx.expire = 0; d2332 1 a2332 1 pfx.expire = pr->ndpr_lastupdate + d2335 1 a2335 1 pfx.expire = maxexpire; d2337 3 a2339 6 pfx.refcnt = pr->ndpr_refcnt; pfx.flags = pr->ndpr_stateflags; pfx.origin = PR_ORIG_RA; p += sizeof(pfx); l += sizeof(pfx); d2342 1 a2342 1 if (p + sizeof(sin6) > pe) { d2346 2 a2347 2 sockaddr_in6_init(&sin6, &pfr->router->rtaddr, d2349 1 a2349 1 if (sa6_recoverscope(&sin6)) { a2355 3 memcpy(p, &sin6, sizeof(sin6)); p += sizeof(sin6); l += sizeof(sin6); d2357 1 a2357 2 pfx.advrtrs = advrtrs; memcpy(ps, &pfx, sizeof(pfx)); a2359 1 l += sizeof(pfx); d2361 1 a2361 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { a2362 2 l += sizeof(sin6); } d2364 5 @ 1.130.10.1 log @Pull up following revision(s) (requested by martin in ticket #1892): usr.sbin/ndp/ndp.c: revision 1.42 sys/netinet6/nd6.c: revision 1.146 Instead of voodo casts use simple byte pointer arithmetic and memcpy to create the "packed" binary format we pass out to userland when querying the router/prefix list. Simplify code to print the router/prefix list: use memcpy and local structs properly aligned on the stack to decode the binary format passed by the kernel - instead of (bogusly) assuming the format will obey all local alignement requirements. @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d2285 2 a2286 2 uint8_t *p = NULL, *ps = NULL; uint8_t *pe = NULL; d2292 2 a2293 2 ps = p = (uint8_t*)oldp; pe = (uint8_t*)oldp + *oldlenp; d2299 3 a2301 1 struct sockaddr_in6 sin6; a2302 1 struct in6_prefix pfx; d2304 1 a2304 1 if (oldp && p + sizeof(struct in6_prefix) <= pe) d2306 2 a2307 3 memset(&pfx, 0, sizeof(pfx)); ps = p; pfx.prefix = pr->ndpr_prefix; d2309 2 a2310 1 if (sa6_recoverscope(&pfx.prefix)) { d2313 1 a2313 1 ip6_sprintf(&pfx.prefix.sin6_addr)); d2316 5 a2320 5 pfx.raflags = pr->ndpr_raf; pfx.prefixlen = pr->ndpr_plen; pfx.vltime = pr->ndpr_vltime; pfx.pltime = pr->ndpr_pltime; pfx.if_index = pr->ndpr_ifp->if_index; d2322 1 a2322 1 pfx.expire = 0; d2332 1 a2332 1 pfx.expire = pr->ndpr_lastupdate + d2335 1 a2335 1 pfx.expire = maxexpire; d2337 3 a2339 6 pfx.refcnt = pr->ndpr_refcnt; pfx.flags = pr->ndpr_stateflags; pfx.origin = PR_ORIG_RA; p += sizeof(pfx); l += sizeof(pfx); d2342 1 a2342 1 if (p + sizeof(sin6) > pe) { d2346 2 a2347 2 sockaddr_in6_init(&sin6, &pfr->router->rtaddr, d2349 1 a2349 1 if (sa6_recoverscope(&sin6)) { a2355 3 memcpy(p, &sin6, sizeof(sin6)); p += sizeof(sin6); l += sizeof(sin6); d2357 1 a2357 2 pfx.advrtrs = advrtrs; memcpy(ps, &pfx, sizeof(pfx)); a2359 1 l += sizeof(pfx); d2361 1 a2361 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { a2362 2 l += sizeof(sin6); } d2364 5 @ 1.130.4.1 log @Pull up following revision(s) (requested by martin in ticket #1892): usr.sbin/ndp/ndp.c: revision 1.42 sys/netinet6/nd6.c: revision 1.146 Instead of voodo casts use simple byte pointer arithmetic and memcpy to create the "packed" binary format we pass out to userland when querying the router/prefix list. Simplify code to print the router/prefix list: use memcpy and local structs properly aligned on the stack to decode the binary format passed by the kernel - instead of (bogusly) assuming the format will obey all local alignement requirements. @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d2285 2 a2286 2 uint8_t *p = NULL, *ps = NULL; uint8_t *pe = NULL; d2292 2 a2293 2 ps = p = (uint8_t*)oldp; pe = (uint8_t*)oldp + *oldlenp; d2299 3 a2301 1 struct sockaddr_in6 sin6; a2302 1 struct in6_prefix pfx; d2304 1 a2304 1 if (oldp && p + sizeof(struct in6_prefix) <= pe) d2306 2 a2307 3 memset(&pfx, 0, sizeof(pfx)); ps = p; pfx.prefix = pr->ndpr_prefix; d2309 2 a2310 1 if (sa6_recoverscope(&pfx.prefix)) { d2313 1 a2313 1 ip6_sprintf(&pfx.prefix.sin6_addr)); d2316 5 a2320 5 pfx.raflags = pr->ndpr_raf; pfx.prefixlen = pr->ndpr_plen; pfx.vltime = pr->ndpr_vltime; pfx.pltime = pr->ndpr_pltime; pfx.if_index = pr->ndpr_ifp->if_index; d2322 1 a2322 1 pfx.expire = 0; d2332 1 a2332 1 pfx.expire = pr->ndpr_lastupdate + d2335 1 a2335 1 pfx.expire = maxexpire; d2337 3 a2339 6 pfx.refcnt = pr->ndpr_refcnt; pfx.flags = pr->ndpr_stateflags; pfx.origin = PR_ORIG_RA; p += sizeof(pfx); l += sizeof(pfx); d2342 1 a2342 1 if (p + sizeof(sin6) > pe) { d2346 2 a2347 2 sockaddr_in6_init(&sin6, &pfr->router->rtaddr, d2349 1 a2349 1 if (sa6_recoverscope(&sin6)) { a2355 3 memcpy(p, &sin6, sizeof(sin6)); p += sizeof(sin6); l += sizeof(sin6); d2357 1 a2357 2 pfx.advrtrs = advrtrs; memcpy(ps, &pfx, sizeof(pfx)); a2359 1 l += sizeof(pfx); d2361 1 a2361 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { a2362 2 l += sizeof(sin6); } d2364 5 @ 1.130.2.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.131 2008/11/07 00:20:18 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.131 2008/11/07 00:20:18 dyoung Exp $"); a1128 29 if (req == RTM_LLINFO_UPD) { int rc; struct in6_addr *in6; struct in6_addr in6_all; int anycast; if ((ifa = info->rti_ifa) == NULL) return; in6 = &ifatoia6(ifa)->ia_addr.sin6_addr; anycast = ifatoia6(ifa)->ia6_flags & IN6_IFF_ANYCAST; in6_all = in6addr_linklocal_allnodes; if ((rc = in6_setscope(&in6_all, ifa->ifa_ifp, NULL)) != 0) { log(LOG_ERR, "%s: failed to set scope %s " "(errno=%d)\n", __func__, if_name(ifp), rc); return; } /* XXX don't set Override for proxy addresses */ nd6_na_output(ifa->ifa_ifp, &in6_all, in6, (anycast ? 0 : ND_NA_FLAG_OVERRIDE) #if 0 | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) #endif , 1, NULL); return; } @ 1.129 log @bzero -> memset. Do not "test truth" of pointers, but compare with NULL, instead. Do not gratuitously cast to void *. Use NULL instead of (type *)0. No functional changes intended. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.128 2008/05/15 01:33:28 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.128 2008/05/15 01:33:28 dyoung Exp $"); d1119 1 a1119 1 nd6_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) @ 1.128 log @Simplify RT_DPRINTF() calls. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.127 2008/05/11 20:19:44 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.127 2008/05/11 20:19:44 dyoung Exp $"); d166 1 a166 1 bzero(nd, sizeof(*nd)); d240 1 a240 1 bzero(ndopts, sizeof(*ndopts)); d273 1 a273 1 bzero(ndopts, sizeof(*ndopts)); d283 1 a283 1 bzero(ndopts, sizeof(*ndopts)); d290 1 a290 1 bzero(ndopts, sizeof(*ndopts)); d326 1 a326 1 bzero(ndopts, sizeof(*ndopts)); d723 1 a723 1 for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) { d731 1 a731 1 for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) { d779 1 a779 1 while (ln && ln != &llinfo_nd6) { d803 1 a803 1 if (rt && (rt->rt_flags & RTF_LLINFO) == 0) { d1063 1 a1063 2 rtrequest(RTM_DELETE, rt_getkey(rt), (struct sockaddr *)0, rt_mask(rt), 0, (struct rtentry **)0); d1177 1 a1177 1 ((rt->rt_flags & RTF_LLINFO) && !ln)) { d1187 1 a1187 1 * (RTF_LLINFO && !ln case). d1195 1 a1195 1 if (ln) d1257 1 a1257 1 rt->rt_llinfo = (void *)ln; d1266 1 a1266 1 bzero(ln, sizeof(*ln)); d1301 1 a1301 1 if (ifa) { d1379 1 a1379 1 Free((void *)ln); d1402 1 a1402 1 bzero(drl, sizeof(*drl)); d1431 1 a1431 1 bzero(oprl, sizeof(*oprl)); d2306 1 a2306 1 bzero(p, sizeof(*p)); @ 1.128.4.1 log @Update haad-dm branch to haad-dm-base2. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.131 2008/11/07 00:20:18 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.131 2008/11/07 00:20:18 dyoung Exp $"); d166 1 a166 1 memset(nd, 0, sizeof(*nd)); d240 1 a240 1 memset(ndopts, 0, sizeof(*ndopts)); d273 1 a273 1 memset(ndopts, 0, sizeof(*ndopts)); d283 1 a283 1 memset(ndopts, 0, sizeof(*ndopts)); d290 1 a290 1 memset(ndopts, 0, sizeof(*ndopts)); d326 1 a326 1 memset(ndopts, 0, sizeof(*ndopts)); d723 1 a723 1 for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = ndr) { d731 1 a731 1 for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = ndr) { d779 1 a779 1 while (ln != NULL && ln != &llinfo_nd6) { d803 1 a803 1 if (rt != NULL && (rt->rt_flags & RTF_LLINFO) == 0) { d1063 2 a1064 1 rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL); d1120 1 a1120 1 nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) a1129 29 if (req == RTM_LLINFO_UPD) { int rc; struct in6_addr *in6; struct in6_addr in6_all; int anycast; if ((ifa = info->rti_ifa) == NULL) return; in6 = &ifatoia6(ifa)->ia_addr.sin6_addr; anycast = ifatoia6(ifa)->ia6_flags & IN6_IFF_ANYCAST; in6_all = in6addr_linklocal_allnodes; if ((rc = in6_setscope(&in6_all, ifa->ifa_ifp, NULL)) != 0) { log(LOG_ERR, "%s: failed to set scope %s " "(errno=%d)\n", __func__, if_name(ifp), rc); return; } /* XXX don't set Override for proxy addresses */ nd6_na_output(ifa->ifa_ifp, &in6_all, in6, (anycast ? 0 : ND_NA_FLAG_OVERRIDE) #if 0 | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) #endif , 1, NULL); return; } d1178 1 a1178 1 ((rt->rt_flags & RTF_LLINFO) && ln == NULL)) { d1188 1 a1188 1 * (RTF_LLINFO && ln == NULL case). d1196 1 a1196 1 if (ln != NULL) d1258 1 a1258 1 rt->rt_llinfo = ln; d1267 1 a1267 1 memset(ln, 0, sizeof(*ln)); d1302 1 a1302 1 if (ifa != NULL) { d1380 1 a1380 1 Free(ln); d1403 1 a1403 1 memset(drl, 0, sizeof(*drl)); d1432 1 a1432 1 memset(oprl, 0, sizeof(*oprl)); d2307 1 a2307 1 memset(p, 0, sizeof(*p)); @ 1.127 log @Compare route with NULL instead of testing truth. Where applicable, s/0/NULL/. s/u_char/uint8_t/. Remove superfluous curly braces. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.126 2008/04/24 11:38:38 ad Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.126 2008/04/24 11:38:38 ad Exp $"); d1128 1 a1128 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1134 1 a1134 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1148 1 a1148 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1169 1 a1169 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1195 1 a1195 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1198 1 a1198 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1202 1 a1202 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1233 1 a1233 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1248 1 a1248 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1252 1 a1252 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1259 1 a1259 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1264 1 a1264 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1287 1 a1287 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1294 1 a1294 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1301 1 a1301 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); @ 1.126 log @Merge the socket locking patch: - Socket layer becomes MP safe. - Unix protocols become MP safe. - Allows protocol processing interrupts to safely block on locks. - Fixes a number of race conditions. With much feedback from matt@@ and plunky@@. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.125 2008/04/15 03:57:04 thorpej Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.125 2008/04/15 03:57:04 thorpej Exp $"); d1958 1 a1958 1 if (rt->rt_gwroute == 0) d1964 1 a1964 1 if ((rt = rt->rt_gwroute) == 0) d1970 1 a1970 1 rt0->rt_gwroute = 0; d1985 1 a1985 1 if (rt && (rt->rt_flags & RTF_LLINFO) != 0) d2092 1 a2092 1 if ((ifp->if_flags & IFF_LOOPBACK) != 0) { a2093 1 } d2130 1 a2130 1 struct mbuf *m, const struct sockaddr *dst, u_char *lldst, @ 1.126.4.1 log @Sync w/ -current. 34 merge conflicts to follow. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.126 2008/04/24 11:38:38 ad Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.126 2008/04/24 11:38:38 ad Exp $"); d1128 2 a1129 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1135 2 a1136 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1150 2 a1151 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1172 2 a1173 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1199 2 a1200 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1203 2 a1204 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1208 2 a1209 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1240 2 a1241 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1256 2 a1257 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1261 2 a1262 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1269 2 a1270 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1275 2 a1276 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1299 2 a1300 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1307 2 a1308 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1315 2 a1316 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1958 1 a1958 1 if (rt->rt_gwroute == NULL) d1964 1 a1964 1 if ((rt = rt->rt_gwroute) == NULL) d1970 1 a1970 1 rt0->rt_gwroute = NULL; d1985 1 a1985 1 if (rt != NULL && (rt->rt_flags & RTF_LLINFO) != 0) d2092 1 a2092 1 if ((ifp->if_flags & IFF_LOOPBACK) != 0) d2094 1 d2131 1 a2131 1 struct mbuf *m, const struct sockaddr *dst, uint8_t *lldst, @ 1.126.2.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.126 2008/04/24 11:38:38 ad Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.126 2008/04/24 11:38:38 ad Exp $"); d1128 2 a1129 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1135 2 a1136 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1150 2 a1151 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1172 2 a1173 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1199 2 a1200 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1203 2 a1204 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1208 2 a1209 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1240 2 a1241 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1256 2 a1257 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1261 2 a1262 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1269 2 a1270 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1275 2 a1276 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1299 2 a1300 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1307 2 a1308 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1315 2 a1316 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1958 1 a1958 1 if (rt->rt_gwroute == NULL) d1964 1 a1964 1 if ((rt = rt->rt_gwroute) == NULL) d1970 1 a1970 1 rt0->rt_gwroute = NULL; d1985 1 a1985 1 if (rt != NULL && (rt->rt_flags & RTF_LLINFO) != 0) d2092 1 a2092 1 if ((ifp->if_flags & IFF_LOOPBACK) != 0) d2094 1 d2131 1 a2131 1 struct mbuf *m, const struct sockaddr *dst, uint8_t *lldst, @ 1.126.2.2 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.126.2.1 2008/05/16 02:25:45 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.126.2.1 2008/05/16 02:25:45 yamt Exp $"); d166 1 a166 1 memset(nd, 0, sizeof(*nd)); d240 1 a240 1 memset(ndopts, 0, sizeof(*ndopts)); d273 1 a273 1 memset(ndopts, 0, sizeof(*ndopts)); d283 1 a283 1 memset(ndopts, 0, sizeof(*ndopts)); d290 1 a290 1 memset(ndopts, 0, sizeof(*ndopts)); d326 1 a326 1 memset(ndopts, 0, sizeof(*ndopts)); d723 1 a723 1 for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = ndr) { d731 1 a731 1 for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = ndr) { d779 1 a779 1 while (ln != NULL && ln != &llinfo_nd6) { d803 1 a803 1 if (rt != NULL && (rt->rt_flags & RTF_LLINFO) == 0) { d1063 2 a1064 1 rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL); d1120 1 a1120 1 nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) a1129 29 if (req == RTM_LLINFO_UPD) { int rc; struct in6_addr *in6; struct in6_addr in6_all; int anycast; if ((ifa = info->rti_ifa) == NULL) return; in6 = &ifatoia6(ifa)->ia_addr.sin6_addr; anycast = ifatoia6(ifa)->ia6_flags & IN6_IFF_ANYCAST; in6_all = in6addr_linklocal_allnodes; if ((rc = in6_setscope(&in6_all, ifa->ifa_ifp, NULL)) != 0) { log(LOG_ERR, "%s: failed to set scope %s " "(errno=%d)\n", __func__, if_name(ifp), rc); return; } /* XXX don't set Override for proxy addresses */ nd6_na_output(ifa->ifa_ifp, &in6_all, in6, (anycast ? 0 : ND_NA_FLAG_OVERRIDE) #if 0 | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) #endif , 1, NULL); return; } d1178 1 a1178 1 ((rt->rt_flags & RTF_LLINFO) && ln == NULL)) { d1188 1 a1188 1 * (RTF_LLINFO && ln == NULL case). d1196 1 a1196 1 if (ln != NULL) d1258 1 a1258 1 rt->rt_llinfo = ln; d1267 1 a1267 1 memset(ln, 0, sizeof(*ln)); d1302 1 a1302 1 if (ifa != NULL) { d1380 1 a1380 1 Free(ln); d1403 1 a1403 1 memset(drl, 0, sizeof(*drl)); d1432 1 a1432 1 memset(oprl, 0, sizeof(*oprl)); d2307 1 a2307 1 memset(p, 0, sizeof(*p)); @ 1.126.2.3 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.126.2.2 2009/05/04 08:14:19 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.126.2.2 2009/05/04 08:14:19 yamt Exp $"); d179 1 a179 2 nd->flags = (ND6_IFF_PERFORMNUD | ip6_accept_rtadv ? ND6_IFF_ACCEPT_RTADV : 0); a712 1 struct nd_ifinfo *ndi = ND_IFINFO(ifp); d767 1 a767 2 /* XXX: too restrictive? */ if (!ip6_forwarding && ndi && (ndi->flags & ND6_IFF_ACCEPT_RTADV)) { a1674 1 struct nd_ifinfo *ndi = ND_IFINFO(ifp); d1883 1 a1883 2 if (do_update && ln->ln_router && !ip6_forwarding && (ndi->flags & ND6_IFF_ACCEPT_RTADV)) @ 1.126.2.4 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.126.2.3 2009/08/19 18:48:25 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.126.2.3 2009/08/19 18:48:25 yamt Exp $"); d180 1 a180 1 (ip6_accept_rtadv ? ND6_IFF_ACCEPT_RTADV : 0)); @ 1.126.2.5 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.126.2.4 2009/09/16 13:38:03 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.126.2.4 2009/09/16 13:38:03 yamt Exp $"); d175 3 a177 3 * Note that the default value of ip6_accept_rtadv is 0. * Because we do not set ND6_IFF_OVERRIDE_RTADV here, we won't * accept RAs by default. d179 2 a180 1 nd->flags = ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV; a706 15 bool nd6_accepts_rtadv(const struct nd_ifinfo *ndi) { switch (ndi->flags & (ND6_IFF_ACCEPT_RTADV|ND6_IFF_OVERRIDE_RTADV)) { case ND6_IFF_OVERRIDE_RTADV|ND6_IFF_ACCEPT_RTADV: return true; case ND6_IFF_ACCEPT_RTADV: return ip6_accept_rtadv != 0; case ND6_IFF_OVERRIDE_RTADV: case 0: default: return false; } } d770 1 a770 1 if (!ip6_forwarding && ndi && nd6_accepts_rtadv(ndi)) { d1888 1 a1888 1 nd6_accepts_rtadv(ndi)) @ 1.126.2.6 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.126.2.5 2010/03/11 15:04:29 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.126.2.5 2010/03/11 15:04:29 yamt Exp $"); d1235 1 a1235 1 if (sockaddr_dl_init(&u.sdl, sizeof(u.ss), d1237 1 a1237 5 NULL, namelen, NULL, addrlen) == NULL) { printf("%s.%d: sockaddr_dl_init(, %zu, ) " "failed on %s\n", __func__, __LINE__, sizeof(u.ss), if_name(ifp)); } d1354 2 a1355 9 if (sockaddr_dl_setaddr(satosdl(gate), gate->sa_len, mac, ifp->if_addrlen) == NULL) { printf("%s.%d: " "sockaddr_dl_setaddr(, %d, ) " "failed on %s\n", __func__, __LINE__, gate->sa_len, if_name(ifp)); } d1780 2 a1781 6 if (sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr, ifp->if_addrlen) == NULL) { printf("%s.%d: sockaddr_dl_setaddr(, %d, ) " "failed on %s\n", __func__, __LINE__, sdl->sdl_len, if_name(ifp)); } d2200 2 a2201 3 printf("%s: sdl_alen == %" PRIu8 ", dst=%s, if=%s\n", __func__, sdl->sdl_alen, ip6_sprintf(&satocsin6(dst)->sin6_addr), if_name(ifp)); @ 1.125 log @Make ip6 and icmp6 stats per-cpu. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.124 2008/04/08 15:04:35 thorpej Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.124 2008/04/08 15:04:35 thorpej Exp $"); d44 1 d152 2 a153 2 callout_init(&nd6_slowtimo_ch, 0); callout_init(&nd6_timer_ch, 0); a413 1 int s; d420 2 a421 1 s = splsoftnet(); d427 2 a428 1 splx(s); d514 2 a515 1 splx(s); a523 1 int s; a528 1 s = splsoftnet(); d532 3 d635 3 a637 1 splx(s); d1281 1 a1281 1 callout_init(&ln->ln_timer_ch, 0); a1878 1 int s = splsoftnet(); d1882 3 a1884 1 callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, d1900 2 a1901 1 splx(s); @ 1.125.2.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.125 2008/04/15 03:57:04 thorpej Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.125 2008/04/15 03:57:04 thorpej Exp $"); a43 1 #include d151 2 a152 2 callout_init(&nd6_slowtimo_ch, CALLOUT_MPSAFE); callout_init(&nd6_timer_ch, CALLOUT_MPSAFE); d413 1 d420 1 a420 2 mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); d426 1 a426 2 KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); d512 1 a512 2 KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); d521 1 d527 1 a530 3 mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); d631 1 a631 3 KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); d1122 2 a1123 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1129 2 a1130 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1144 2 a1145 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1166 2 a1167 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1193 2 a1194 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1197 2 a1198 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1202 2 a1203 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1234 2 a1235 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1250 2 a1251 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1255 2 a1256 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1263 2 a1264 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1269 2 a1270 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1275 1 a1275 1 callout_init(&ln->ln_timer_ch, CALLOUT_MPSAFE); d1293 2 a1294 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1301 2 a1302 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1309 2 a1310 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1873 1 d1877 1 a1877 3 mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, d1893 1 a1893 2 KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); d1950 1 a1950 1 if (rt->rt_gwroute == NULL) d1956 1 a1956 1 if ((rt = rt->rt_gwroute) == NULL) d1962 1 a1962 1 rt0->rt_gwroute = NULL; d1977 1 a1977 1 if (rt != NULL && (rt->rt_flags & RTF_LLINFO) != 0) d2084 1 a2084 1 if ((ifp->if_flags & IFF_LOOPBACK) != 0) d2086 1 d2123 1 a2123 1 struct mbuf *m, const struct sockaddr *dst, uint8_t *lldst, @ 1.124 log @Change ICMP6 stats from a structure to an array of uint64_t's. Note: This is ABI-compatible with the old icmp6stat structure; old netstat binaries will continue to work properly. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.123 2007/12/04 10:27:34 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.123 2007/12/04 10:27:34 dyoung Exp $"); d68 1 d324 1 a324 1 icmp6stat[ICMP6_STAT_ND_BADOPT]++; d368 1 a368 1 icmp6stat[ICMP6_STAT_ND_TOOMANYOPT]++; @ 1.123 log @Use IFNET_FOREACH() and IFADDR_FOREACH(). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.122 2007/11/10 00:07:57 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.122 2007/11/10 00:07:57 dyoung Exp $"); d323 1 a323 1 icmp6stat.icp6s_nd_badopt++; d367 1 a367 1 icmp6stat.icp6s_nd_toomanyopt++; @ 1.123.12.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); a43 1 #include a67 1 #include d150 2 a151 2 callout_init(&nd6_slowtimo_ch, CALLOUT_MPSAFE); callout_init(&nd6_timer_ch, CALLOUT_MPSAFE); d323 1 a323 1 ICMP6_STATINC(ICMP6_STAT_ND_BADOPT); d367 1 a367 1 ICMP6_STATINC(ICMP6_STAT_ND_TOOMANYOPT); d412 1 d419 1 a419 2 mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); d425 1 a425 2 KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); d511 1 a511 2 KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); d520 1 d526 1 a529 3 mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); d630 1 a630 3 KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); d1121 2 a1122 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1128 2 a1129 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1143 2 a1144 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1165 2 a1166 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1192 2 a1193 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1196 2 a1197 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1201 2 a1202 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1233 2 a1234 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1249 2 a1250 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1254 2 a1255 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1262 2 a1263 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1268 2 a1269 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1274 1 a1274 1 callout_init(&ln->ln_timer_ch, CALLOUT_MPSAFE); d1292 2 a1293 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1300 2 a1301 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1308 2 a1309 1 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); d1872 1 d1876 1 a1876 3 mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, d1892 1 a1892 2 KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); d1949 1 a1949 1 if (rt->rt_gwroute == NULL) d1955 1 a1955 1 if ((rt = rt->rt_gwroute) == NULL) d1961 1 a1961 1 rt0->rt_gwroute = NULL; d1976 1 a1976 1 if (rt != NULL && (rt->rt_flags & RTF_LLINFO) != 0) d2083 1 a2083 1 if ((ifp->if_flags & IFF_LOOPBACK) != 0) d2085 1 d2122 1 a2122 1 struct mbuf *m, const struct sockaddr *dst, uint8_t *lldst, @ 1.123.12.2 log @Sync with HEAD. @ text @d166 1 a166 1 memset(nd, 0, sizeof(*nd)); d240 1 a240 1 memset(ndopts, 0, sizeof(*ndopts)); d273 1 a273 1 memset(ndopts, 0, sizeof(*ndopts)); d283 1 a283 1 memset(ndopts, 0, sizeof(*ndopts)); d290 1 a290 1 memset(ndopts, 0, sizeof(*ndopts)); d326 1 a326 1 memset(ndopts, 0, sizeof(*ndopts)); d723 1 a723 1 for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = ndr) { d731 1 a731 1 for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = ndr) { d779 1 a779 1 while (ln != NULL && ln != &llinfo_nd6) { d803 1 a803 1 if (rt != NULL && (rt->rt_flags & RTF_LLINFO) == 0) { d1063 2 a1064 1 rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL); d1120 1 a1120 1 nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) a1129 29 if (req == RTM_LLINFO_UPD) { int rc; struct in6_addr *in6; struct in6_addr in6_all; int anycast; if ((ifa = info->rti_ifa) == NULL) return; in6 = &ifatoia6(ifa)->ia_addr.sin6_addr; anycast = ifatoia6(ifa)->ia6_flags & IN6_IFF_ANYCAST; in6_all = in6addr_linklocal_allnodes; if ((rc = in6_setscope(&in6_all, ifa->ifa_ifp, NULL)) != 0) { log(LOG_ERR, "%s: failed to set scope %s " "(errno=%d)\n", __func__, if_name(ifp), rc); return; } /* XXX don't set Override for proxy addresses */ nd6_na_output(ifa->ifa_ifp, &in6_all, in6, (anycast ? 0 : ND_NA_FLAG_OVERRIDE) #if 0 | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) #endif , 1, NULL); return; } d1178 1 a1178 1 ((rt->rt_flags & RTF_LLINFO) && ln == NULL)) { d1188 1 a1188 1 * (RTF_LLINFO && ln == NULL case). d1196 1 a1196 1 if (ln != NULL) d1258 1 a1258 1 rt->rt_llinfo = ln; d1267 1 a1267 1 memset(ln, 0, sizeof(*ln)); d1302 1 a1302 1 if (ifa != NULL) { d1380 1 a1380 1 Free(ln); d1403 1 a1403 1 memset(drl, 0, sizeof(*drl)); d1432 1 a1432 1 memset(oprl, 0, sizeof(*oprl)); d2307 1 a2307 1 memset(p, 0, sizeof(*p)); @ 1.123.8.1 log @imported Mobile IPv6 code developed by the SHISA project (http://www.mobileip.jp/). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.123 2007/12/04 10:27:34 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.123 2007/12/04 10:27:34 dyoung Exp $"); a68 11 #ifdef MOBILE_IPV6 #include "mip.h" #include #include #if NMIP > 0 #include #include #include #endif /* NMIP > 0 */ #endif /* MOBILE_IPV6 */ d760 1 a760 3 if ((!ip6_forwarding && ip6_accept_rtadv) || in6_mip6_is_mr()) { /* XXX: too restrictive? */ a890 1 struct ifaddr *dstaddr; a931 8 * If the address is assigned on the node of the other side of * a p2p interface, the address should be a neighbor. */ dstaddr = ifa_ifwithdstaddr((const struct sockaddr *)addr); if ((dstaddr != NULL) && (dstaddr->ifa_ifp == ifp)) return (1); /* d1863 1 a1863 2 if (do_update && ln->ln_router && ((!ip6_forwarding && ip6_accept_rtadv) || in6_mip6_is_mr())) a1904 57 #if defined(MOBILE_IPV6) && NMIP > 0 int presence; struct ip6_hdr *ip6; struct in6_ifaddr *src_ia6; struct sockaddr_in6 sin6_src; struct in6_addr in6_src, in6_dst; struct mip6_bul_internal *bul, *cnbul; #endif /* MOBILE_IPV6 && NMIP > 0 */ #if defined(MOBILE_IPV6) && NMIP > 0 ip6 = mtod(m0, struct ip6_hdr *); bzero(&sin6_src, sizeof(struct sockaddr_in6)); sin6_src.sin6_len = sizeof(struct sockaddr_in6); sin6_src.sin6_family = AF_INET6; sin6_src.sin6_addr = ip6->ip6_src; src_ia6 = (struct in6_ifaddr *)ifa_ifwithaddr( (struct sockaddr *)&sin6_src); if (src_ia6 && ((src_ia6->ia6_flags & IN6_IFF_DEREGISTERING) == 0)) { /* * if R flag is set, skip kernel tunnel. * packets are tunneled by gif */ bul = mip6_bul_get_home_agent(&ip6->ip6_src); if ((bul != NULL) && (bul->mbul_mip != NULL) && (bul->mbul_flags & IP6_MH_BU_ROUTER) == 0) { if (ip6->ip6_nxt == IPPROTO_MH) goto dontstartrr; if (mip6_get_ip6hdrinfo(m, &in6_src, &in6_dst, NULL, NULL, 1 /* logical */, &presence)) { mip6log((LOG_ERR, "nd6_output: " "failed to get logical source and " "destination addresses.\n")); senderr(EIO); /* XXX ? */ } if (IN6_IS_ADDR_MULTICAST(&in6_dst)) goto dontstartrr; if (IN6_IS_ADDR_LINKLOCAL(&in6_dst)) goto dontstartrr; cnbul = mip6_bul_get(&in6_src, &in6_dst, 0); if (cnbul != NULL) goto dontstartrr; /* send a hint to start RR to this node. */ mip6_notify_rr_hint(&in6_src, &in6_dst); dontstartrr: /* send this packet via bi-directional tunnel. */ return ((*bul->mbul_mip->mip_if.if_output)( (struct ifnet *)bul->mbul_mip, m, (const struct sockaddr *)dst, rt)); } } #endif /* MOBILE_IPV6 && NMIP > 0 */ @ 1.122 log @Use sockaddr_in6_init(). Use a static initializer for all1_sa. Constify a cast (may as well). No functional change intended. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.121 2007/11/01 20:33:58 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.121 2007/11/01 20:33:58 dyoung Exp $"); d642 1 a642 1 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { @ 1.122.2.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.123 2007/12/04 10:27:34 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.123 2007/12/04 10:27:34 dyoung Exp $"); d642 1 a642 1 IFADDR_FOREACH(ifa, ifp) { @ 1.121 log @De-__P(). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.120 2007/09/02 19:42:22 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.120 2007/09/02 19:42:22 dyoung Exp $"); d110 8 a117 1 static struct sockaddr_in6 all1_sa; a138 1 int i; a144 5 all1_sa.sin6_family = AF_INET6; all1_sa.sin6_len = sizeof(struct sockaddr_in6); for (i = 0; i < sizeof(all1_sa.sin6_addr); i++) all1_sa.sin6_addr.s6_addr[i] = 0xff; d794 1 a794 4 bzero(&sin6, sizeof(sin6)); sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_family = AF_INET6; sin6.sin6_addr = *addr6; d831 2 a832 2 if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6, ifa->ifa_addr, (struct sockaddr *)&all1_sa, d2257 2 a2258 4 bzero(d, sizeof(*d)); d->rtaddr.sin6_family = AF_INET6; d->rtaddr.sin6_len = sizeof(struct sockaddr_in6); d->rtaddr.sin6_addr = dr->rtaddr; d2355 2 a2356 4 s6->sin6_family = AF_INET6; s6->sin6_len = sizeof(struct sockaddr_in6); s6->sin6_addr = pfr->router->rtaddr; s6->sin6_scope_id = 0; @ 1.121.2.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.122 2007/11/10 00:07:57 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.122 2007/11/10 00:07:57 dyoung Exp $"); d110 1 a110 8 static const struct sockaddr_in6 all1_sa = { .sin6_family = AF_INET6 , .sin6_len = sizeof(struct sockaddr_in6) , .sin6_addr = {.s6_addr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}} }; d132 1 d139 5 d793 4 a796 1 sockaddr_in6_init(&sin6, addr6, 0, 0, 0); d833 2 a834 2 if ((e = rtrequest(RTM_ADD, (const struct sockaddr *)&sin6, ifa->ifa_addr, (const struct sockaddr *)&all1_sa, d2259 4 a2262 2 memset(d, 0, sizeof(*d)); sockaddr_in6_init(&d->rtaddr, &dr->rtaddr, 0, 0, 0); d2359 4 a2362 2 sockaddr_in6_init(s6, &pfr->router->rtaddr, 0, 0, 0); @ 1.121.2.2 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.123 2007/12/04 10:27:34 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.123 2007/12/04 10:27:34 dyoung Exp $"); d642 1 a642 1 IFADDR_FOREACH(ifa, ifp) { @ 1.120 log @We cannot sleep in a software interrupt, so do not sockaddr_dl_alloc(..., M_WAITOK). Instead, sockaddr_dl_init() a sockaddr_dl on the stack. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.119 2007/08/30 02:17:38 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.119 2007/08/30 02:17:38 dyoung Exp $"); d112 6 a117 6 static void nd6_setmtu0 __P((struct ifnet *, struct nd_ifinfo *)); static void nd6_slowtimo __P((void *)); static int regen_tmpaddr __P((struct in6_ifaddr *)); static struct llinfo_nd6 *nd6_free __P((struct rtentry *, int)); static void nd6_llinfo_timer __P((void *)); static void clear_llinfo_pqueue __P((struct llinfo_nd6 *)); d123 2 a124 2 static int fill_drlist __P((void *, size_t *, size_t)); static int fill_prlist __P((void *, size_t *, size_t)); @ 1.120.4.1 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d110 1 a110 8 static const struct sockaddr_in6 all1_sa = { .sin6_family = AF_INET6 , .sin6_len = sizeof(struct sockaddr_in6) , .sin6_addr = {.s6_addr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}} }; d112 6 a117 6 static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *); static void nd6_slowtimo(void *); static int regen_tmpaddr(struct in6_ifaddr *); static struct llinfo_nd6 *nd6_free(struct rtentry *, int); static void nd6_llinfo_timer(void *); static void clear_llinfo_pqueue(struct llinfo_nd6 *); d123 2 a124 2 static int fill_drlist(void *, size_t *, size_t); static int fill_prlist(void *, size_t *, size_t); d132 1 d139 5 d793 4 a796 1 sockaddr_in6_init(&sin6, addr6, 0, 0, 0); d833 2 a834 2 if ((e = rtrequest(RTM_ADD, (const struct sockaddr *)&sin6, ifa->ifa_addr, (const struct sockaddr *)&all1_sa, d2259 4 a2262 2 memset(d, 0, sizeof(*d)); sockaddr_in6_init(&d->rtaddr, &dr->rtaddr, 0, 0, 0); d2359 4 a2362 2 sockaddr_in6_init(s6, &pfr->router->rtaddr, 0, 0, 0); @ 1.119 log @Use malloc(9) for sockaddrs instead of pool(9), and remove dom_sa_pool and dom_sa_len members from struct domain. Pools of fixed-size objects are too rigid for sockaddr_dls, whose size can vary over a wide range. Return sockaddr_dl to its "historical" size. Now that I'm using malloc(9) instead of pool(9) to allocate sockaddr_dl, I can create a sockaddr_dl of any size in the kernel, so expanding sockaddr_dl is useless. Avoid using sizeof(struct sockaddr_dl) in the kernel. Introduce sockaddr_dl_alloc() for allocating & initializing an arbitrary sockaddr_dl on the heap. Add an argument, the sockaddr length, to sockaddr_alloc(), sockaddr_copy(), and sockaddr_dl_setaddr(). Constify: LLADDR() -> CLLADDR(). Where the kernel overwrites LLADDR(), use sockaddr_dl_setaddr(), instead. Used properly, sockaddr_dl_setaddr() will not overrun the end of the sockaddr. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.118 2007/08/07 04:35:42 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.118 2007/08/07 04:35:42 dyoung Exp $"); d1178 5 a1182 1 struct sockaddr *sa; d1189 4 a1192 4 sa = sockaddr_dl_alloc(ifp->if_index, ifp->if_type, NULL, namelen, NULL, addrlen, M_WAITOK); rt_setgate(rt, sa); sockaddr_free(sa); @ 1.118 log @Avoid writing past the end of the buffer [lldst, lldst + dstsize) in nd6_storelladdr(). Use sockaddr_dl_setaddr(). Constify some sockaddr_dl's. Constify a sockaddr argument to nd6_na_output(). Change SDL() to "standard" satocsdl() or satosdl(). Change SIN6() to satocsin6() or satosin6(). bcmp -> memcmp, bcopy -> memcpy. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.117 2007/07/19 20:48:57 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.117 2007/07/19 20:48:57 dyoung Exp $"); a1118 4 static const struct sockaddr_dl null_sdl = { .sdl_len = sizeof(null_sdl), .sdl_family = AF_LINK, }; d1120 1 d1178 1 d1185 5 a1189 1 rt_setgate(rt, (const struct sockaddr *)&null_sdl); a1191 3 gate = rt->rt_gateway; satosdl(gate)->sdl_type = ifp->if_type; satosdl(gate)->sdl_index = ifp->if_index; d1238 2 a1239 1 gate->sa_len < sizeof(null_sdl)) { d1304 1 a1304 1 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, d1309 1 a1309 1 void *macp = nd6_ifptomac(ifp); d1313 1 a1313 1 if (macp) { d1315 2 a1316 2 (void)sockaddr_dl_setaddr(satosdl(gate), macp, ifp->if_addrlen); d1319 1 a1319 1 rt->rt_ifp = lo0ifp; /* XXX */ d1740 2 a1741 1 (void)sockaddr_dl_setaddr(sdl, lladdr, ifp->if_addrlen); @ 1.118.4.1 log @file nd6.c was added on branch matt-mips64 on 2007-08-07 04:35:43 +0000 @ text @d1 2390 @ 1.118.4.2 log @Avoid writing past the end of the buffer [lldst, lldst + dstsize) in nd6_storelladdr(). Use sockaddr_dl_setaddr(). Constify some sockaddr_dl's. Constify a sockaddr argument to nd6_na_output(). Change SDL() to "standard" satocsdl() or satosdl(). Change SIN6() to satocsin6() or satosin6(). bcmp -> memcmp, bcopy -> memcpy. @ text @a0 2390 /* $NetBSD: nd6.c,v 1.118 2007/08/07 04:35:42 dyoung Exp $ */ /* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * 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. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS 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: nd6.c,v 1.118 2007/08/07 04:35:42 dyoung Exp $"); #include "opt_ipsec.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef IPSEC #include #endif #include #define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */ #define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */ /* timer values */ int nd6_prune = 1; /* walk list every 1 seconds */ int nd6_delay = 5; /* delay first probe time 5 second */ int nd6_umaxtries = 3; /* maximum unicast query */ int nd6_mmaxtries = 3; /* maximum multicast query */ int nd6_useloopback = 1; /* use loopback interface for local traffic */ int nd6_gctimer = (60 * 60 * 24); /* 1 day: garbage collection timer */ /* preventing too many loops in ND option parsing */ int nd6_maxndopt = 10; /* max # of ND options allowed */ int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */ int nd6_maxqueuelen = 1; /* max # of packets cached in unresolved ND entries */ #ifdef ND6_DEBUG int nd6_debug = 1; #else int nd6_debug = 0; #endif /* for debugging? */ static int nd6_inuse, nd6_allocated; struct llinfo_nd6 llinfo_nd6 = { .ln_prev = &llinfo_nd6, .ln_next = &llinfo_nd6, }; struct nd_drhead nd_defrouter; struct nd_prhead nd_prefix = { 0 }; int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; static struct sockaddr_in6 all1_sa; static void nd6_setmtu0 __P((struct ifnet *, struct nd_ifinfo *)); static void nd6_slowtimo __P((void *)); static int regen_tmpaddr __P((struct in6_ifaddr *)); static struct llinfo_nd6 *nd6_free __P((struct rtentry *, int)); static void nd6_llinfo_timer __P((void *)); static void clear_llinfo_pqueue __P((struct llinfo_nd6 *)); callout_t nd6_slowtimo_ch; callout_t nd6_timer_ch; extern callout_t in6_tmpaddrtimer_ch; static int fill_drlist __P((void *, size_t *, size_t)); static int fill_prlist __P((void *, size_t *, size_t)); MALLOC_DEFINE(M_IP6NDP, "NDP", "IPv6 Neighbour Discovery"); void nd6_init(void) { static int nd6_init_done = 0; int i; if (nd6_init_done) { log(LOG_NOTICE, "nd6_init called more than once(ignored)\n"); return; } all1_sa.sin6_family = AF_INET6; all1_sa.sin6_len = sizeof(struct sockaddr_in6); for (i = 0; i < sizeof(all1_sa.sin6_addr); i++) all1_sa.sin6_addr.s6_addr[i] = 0xff; /* initialization of the default router list */ TAILQ_INIT(&nd_defrouter); nd6_init_done = 1; callout_init(&nd6_slowtimo_ch, 0); callout_init(&nd6_timer_ch, 0); /* start timer */ callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, nd6_slowtimo, NULL); } struct nd_ifinfo * nd6_ifattach(struct ifnet *ifp) { struct nd_ifinfo *nd; nd = (struct nd_ifinfo *)malloc(sizeof(*nd), M_IP6NDP, M_WAITOK); bzero(nd, sizeof(*nd)); nd->initialized = 1; nd->chlim = IPV6_DEFHLIM; nd->basereachable = REACHABLE_TIME; nd->reachable = ND_COMPUTE_RTIME(nd->basereachable); nd->retrans = RETRANS_TIMER; /* * Note that the default value of ip6_accept_rtadv is 0, which means * we won't accept RAs by default even if we set ND6_IFF_ACCEPT_RTADV * here. */ nd->flags = (ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV); /* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */ nd6_setmtu0(ifp, nd); return nd; } void nd6_ifdetach(struct nd_ifinfo *nd) { free(nd, M_IP6NDP); } void nd6_setmtu(struct ifnet *ifp) { nd6_setmtu0(ifp, ND_IFINFO(ifp)); } void nd6_setmtu0(struct ifnet *ifp, struct nd_ifinfo *ndi) { u_int32_t omaxmtu; omaxmtu = ndi->maxmtu; switch (ifp->if_type) { case IFT_ARCNET: ndi->maxmtu = MIN(ARC_PHDS_MAXMTU, ifp->if_mtu); /* RFC2497 */ break; case IFT_FDDI: ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); break; default: ndi->maxmtu = ifp->if_mtu; break; } /* * Decreasing the interface MTU under IPV6 minimum MTU may cause * undesirable situation. We thus notify the operator of the change * explicitly. The check for omaxmtu is necessary to restrict the * log to the case of changing the MTU, not initializing it. */ if (omaxmtu >= IPV6_MMTU && ndi->maxmtu < IPV6_MMTU) { log(LOG_NOTICE, "nd6_setmtu0: new link MTU on %s (%lu) is too" " small for IPv6 which needs %lu\n", if_name(ifp), (unsigned long)ndi->maxmtu, (unsigned long) IPV6_MMTU); } if (ndi->maxmtu > in6_maxmtu) in6_setmaxmtu(); /* check all interfaces just in case */ } void nd6_option_init(void *opt, int icmp6len, union nd_opts *ndopts) { bzero(ndopts, sizeof(*ndopts)); ndopts->nd_opts_search = (struct nd_opt_hdr *)opt; ndopts->nd_opts_last = (struct nd_opt_hdr *)(((u_char *)opt) + icmp6len); if (icmp6len == 0) { ndopts->nd_opts_done = 1; ndopts->nd_opts_search = NULL; } } /* * Take one ND option. */ struct nd_opt_hdr * nd6_option(union nd_opts *ndopts) { struct nd_opt_hdr *nd_opt; int olen; if (ndopts == NULL) panic("ndopts == NULL in nd6_option"); if (ndopts->nd_opts_last == NULL) panic("uninitialized ndopts in nd6_option"); if (ndopts->nd_opts_search == NULL) return NULL; if (ndopts->nd_opts_done) return NULL; nd_opt = ndopts->nd_opts_search; /* make sure nd_opt_len is inside the buffer */ if ((void *)&nd_opt->nd_opt_len >= (void *)ndopts->nd_opts_last) { bzero(ndopts, sizeof(*ndopts)); return NULL; } olen = nd_opt->nd_opt_len << 3; if (olen == 0) { /* * Message validation requires that all included * options have a length that is greater than zero. */ bzero(ndopts, sizeof(*ndopts)); return NULL; } ndopts->nd_opts_search = (struct nd_opt_hdr *)((char *)nd_opt + olen); if (ndopts->nd_opts_search > ndopts->nd_opts_last) { /* option overruns the end of buffer, invalid */ bzero(ndopts, sizeof(*ndopts)); return NULL; } else if (ndopts->nd_opts_search == ndopts->nd_opts_last) { /* reached the end of options chain */ ndopts->nd_opts_done = 1; ndopts->nd_opts_search = NULL; } return nd_opt; } /* * Parse multiple ND options. * This function is much easier to use, for ND routines that do not need * multiple options of the same type. */ int nd6_options(union nd_opts *ndopts) { struct nd_opt_hdr *nd_opt; int i = 0; if (ndopts == NULL) panic("ndopts == NULL in nd6_options"); if (ndopts->nd_opts_last == NULL) panic("uninitialized ndopts in nd6_options"); if (ndopts->nd_opts_search == NULL) return 0; while (1) { nd_opt = nd6_option(ndopts); if (nd_opt == NULL && ndopts->nd_opts_last == NULL) { /* * Message validation requires that all included * options have a length that is greater than zero. */ icmp6stat.icp6s_nd_badopt++; bzero(ndopts, sizeof(*ndopts)); return -1; } if (nd_opt == NULL) goto skip1; switch (nd_opt->nd_opt_type) { case ND_OPT_SOURCE_LINKADDR: case ND_OPT_TARGET_LINKADDR: case ND_OPT_MTU: case ND_OPT_REDIRECTED_HEADER: if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { nd6log((LOG_INFO, "duplicated ND6 option found (type=%d)\n", nd_opt->nd_opt_type)); /* XXX bark? */ } else { ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; } break; case ND_OPT_PREFIX_INFORMATION: if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) { ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; } ndopts->nd_opts_pi_end = (struct nd_opt_prefix_info *)nd_opt; break; default: /* * Unknown options must be silently ignored, * to accommodate future extension to the protocol. */ nd6log((LOG_DEBUG, "nd6_options: unsupported option %d - " "option ignored\n", nd_opt->nd_opt_type)); } skip1: i++; if (i > nd6_maxndopt) { icmp6stat.icp6s_nd_toomanyopt++; nd6log((LOG_INFO, "too many loop in nd opt\n")); break; } if (ndopts->nd_opts_done) break; } return 0; } /* * ND6 timer routine to handle ND6 entries */ void nd6_llinfo_settimer(struct llinfo_nd6 *ln, long xtick) { int s; s = splsoftnet(); if (xtick < 0) { ln->ln_expire = 0; ln->ln_ntick = 0; callout_stop(&ln->ln_timer_ch); } else { ln->ln_expire = time_second + xtick / hz; if (xtick > INT_MAX) { ln->ln_ntick = xtick - INT_MAX; callout_reset(&ln->ln_timer_ch, INT_MAX, nd6_llinfo_timer, ln); } else { ln->ln_ntick = 0; callout_reset(&ln->ln_timer_ch, xtick, nd6_llinfo_timer, ln); } } splx(s); } static void nd6_llinfo_timer(void *arg) { int s; struct llinfo_nd6 *ln; struct rtentry *rt; const struct sockaddr_in6 *dst; struct ifnet *ifp; struct nd_ifinfo *ndi = NULL; s = splsoftnet(); ln = (struct llinfo_nd6 *)arg; if (ln->ln_ntick > 0) { nd6_llinfo_settimer(ln, ln->ln_ntick); splx(s); return; } if ((rt = ln->ln_rt) == NULL) panic("ln->ln_rt == NULL"); if ((ifp = rt->rt_ifp) == NULL) panic("ln->ln_rt->rt_ifp == NULL"); ndi = ND_IFINFO(ifp); dst = satocsin6(rt_getkey(rt)); /* sanity check */ if (rt->rt_llinfo && (struct llinfo_nd6 *)rt->rt_llinfo != ln) panic("rt_llinfo(%p) is not equal to ln(%p)", rt->rt_llinfo, ln); if (!dst) panic("dst=0 in nd6_timer(ln=%p)", ln); switch (ln->ln_state) { case ND6_LLINFO_INCOMPLETE: if (ln->ln_asked < nd6_mmaxtries) { ln->ln_asked++; nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000); nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); } else { struct mbuf *m = ln->ln_hold; if (m) { struct mbuf *m0; /* * assuming every packet in ln_hold has * the same IP header */ m0 = m->m_nextpkt; m->m_nextpkt = NULL; icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, rt->rt_ifp); ln->ln_hold = m0; clear_llinfo_pqueue(ln); } (void)nd6_free(rt, 0); ln = NULL; } break; case ND6_LLINFO_REACHABLE: if (!ND6_LLINFO_PERMANENT(ln)) { ln->ln_state = ND6_LLINFO_STALE; nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz); } break; case ND6_LLINFO_STALE: /* Garbage Collection(RFC 2461 5.3) */ if (!ND6_LLINFO_PERMANENT(ln)) { (void)nd6_free(rt, 1); ln = NULL; } break; case ND6_LLINFO_DELAY: if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) { /* We need NUD */ ln->ln_asked = 1; ln->ln_state = ND6_LLINFO_PROBE; nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000); nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); } else { ln->ln_state = ND6_LLINFO_STALE; /* XXX */ nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz); } break; case ND6_LLINFO_PROBE: if (ln->ln_asked < nd6_umaxtries) { ln->ln_asked++; nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000); nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); } else { (void)nd6_free(rt, 0); ln = NULL; } break; } splx(s); } /* * ND6 timer routine to expire default route list and prefix list */ void nd6_timer(void *ignored_arg) { int s; struct nd_defrouter *next_dr, *dr; struct nd_prefix *next_pr, *pr; struct in6_ifaddr *ia6, *nia6; struct in6_addrlifetime *lt6; s = splsoftnet(); callout_reset(&nd6_timer_ch, nd6_prune * hz, nd6_timer, NULL); /* expire default router list */ for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = next_dr) { next_dr = TAILQ_NEXT(dr, dr_entry); if (dr->expire && dr->expire < time_second) { defrtrlist_del(dr); } } /* * expire interface addresses. * in the past the loop was inside prefix expiry processing. * However, from a stricter speci-confrmance standpoint, we should * rather separate address lifetimes and prefix lifetimes. */ addrloop: for (ia6 = in6_ifaddr; ia6; ia6 = nia6) { nia6 = ia6->ia_next; /* check address lifetime */ lt6 = &ia6->ia6_lifetime; if (IFA6_IS_INVALID(ia6)) { int regen = 0; /* * If the expiring address is temporary, try * regenerating a new one. This would be useful when * we suspended a laptop PC, then turned it on after a * period that could invalidate all temporary * addresses. Although we may have to restart the * loop (see below), it must be after purging the * address. Otherwise, we'd see an infinite loop of * regeneration. */ if (ip6_use_tempaddr && (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { if (regen_tmpaddr(ia6) == 0) regen = 1; } in6_purgeaddr(&ia6->ia_ifa); if (regen) goto addrloop; /* XXX: see below */ } else if (IFA6_IS_DEPRECATED(ia6)) { int oldflags = ia6->ia6_flags; ia6->ia6_flags |= IN6_IFF_DEPRECATED; /* * If a temporary address has just become deprecated, * regenerate a new one if possible. */ if (ip6_use_tempaddr && (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && (oldflags & IN6_IFF_DEPRECATED) == 0) { if (regen_tmpaddr(ia6) == 0) { /* * A new temporary address is * generated. * XXX: this means the address chain * has changed while we are still in * the loop. Although the change * would not cause disaster (because * it's not a deletion, but an * addition,) we'd rather restart the * loop just for safety. Or does this * significantly reduce performance?? */ goto addrloop; } } } else { /* * A new RA might have made a deprecated address * preferred. */ ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; } } /* expire prefix list */ for (pr = LIST_FIRST(&nd_prefix); pr != NULL; pr = next_pr) { next_pr = LIST_NEXT(pr, ndpr_entry); /* * check prefix lifetime. * since pltime is just for autoconf, pltime processing for * prefix is not necessary. */ if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME && time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) { /* * address expiration and prefix expiration are * separate. NEVER perform in6_purgeaddr here. */ prelist_remove(pr); } } splx(s); } /* ia6: deprecated/invalidated temporary address */ static int regen_tmpaddr(struct in6_ifaddr *ia6) { struct ifaddr *ifa; struct ifnet *ifp; struct in6_ifaddr *public_ifa6 = NULL; ifp = ia6->ia_ifa.ifa_ifp; TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { struct in6_ifaddr *it6; if (ifa->ifa_addr->sa_family != AF_INET6) continue; it6 = (struct in6_ifaddr *)ifa; /* ignore no autoconf addresses. */ if ((it6->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; /* ignore autoconf addresses with different prefixes. */ if (it6->ia6_ndpr == NULL || it6->ia6_ndpr != ia6->ia6_ndpr) continue; /* * Now we are looking at an autoconf address with the same * prefix as ours. If the address is temporary and is still * preferred, do not create another one. It would be rare, but * could happen, for example, when we resume a laptop PC after * a long period. */ if ((it6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && !IFA6_IS_DEPRECATED(it6)) { public_ifa6 = NULL; break; } /* * This is a public autoconf address that has the same prefix * as ours. If it is preferred, keep it. We can't break the * loop here, because there may be a still-preferred temporary * address with the prefix. */ if (!IFA6_IS_DEPRECATED(it6)) public_ifa6 = it6; } if (public_ifa6 != NULL) { int e; /* * Random factor is introduced in the preferred lifetime, so * we do not need additional delay (3rd arg to in6_tmpifadd). */ if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) { log(LOG_NOTICE, "regen_tmpaddr: failed to create a new" " tmp addr, errno=%d\n", e); return -1; } return 0; } return -1; } /* * Nuke neighbor cache/prefix/default router management table, right before * ifp goes away. */ void nd6_purge(struct ifnet *ifp) { struct llinfo_nd6 *ln, *nln; struct nd_defrouter *dr, *ndr; struct nd_prefix *pr, *npr; /* * Nuke default router list entries toward ifp. * We defer removal of default router list entries that is installed * in the routing table, in order to keep additional side effects as * small as possible. */ for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) { ndr = TAILQ_NEXT(dr, dr_entry); if (dr->installed) continue; if (dr->ifp == ifp) defrtrlist_del(dr); } for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) { ndr = TAILQ_NEXT(dr, dr_entry); if (!dr->installed) continue; if (dr->ifp == ifp) defrtrlist_del(dr); } /* Nuke prefix list entries toward ifp */ for (pr = LIST_FIRST(&nd_prefix); pr != NULL; pr = npr) { npr = LIST_NEXT(pr, ndpr_entry); if (pr->ndpr_ifp == ifp) { /* * Because if_detach() does *not* release prefixes * while purging addresses the reference count will * still be above zero. We therefore reset it to * make sure that the prefix really gets purged. */ pr->ndpr_refcnt = 0; /* * Previously, pr->ndpr_addr is removed as well, * but I strongly believe we don't have to do it. * nd6_purge() is only called from in6_ifdetach(), * which removes all the associated interface addresses * by itself. * (jinmei@@kame.net 20010129) */ prelist_remove(pr); } } /* cancel default outgoing interface setting */ if (nd6_defifindex == ifp->if_index) nd6_setdefaultiface(0); if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */ /* refresh default router list */ defrouter_select(); } /* * Nuke neighbor cache entries for the ifp. * Note that rt->rt_ifp may not be the same as ifp, * due to KAME goto ours hack. See RTM_RESOLVE case in * nd6_rtrequest(), and ip6_input(). */ ln = llinfo_nd6.ln_next; while (ln && ln != &llinfo_nd6) { struct rtentry *rt; const struct sockaddr_dl *sdl; nln = ln->ln_next; rt = ln->ln_rt; if (rt && rt->rt_gateway && rt->rt_gateway->sa_family == AF_LINK) { sdl = satocsdl(rt->rt_gateway); if (sdl->sdl_index == ifp->if_index) nln = nd6_free(rt, 0); } ln = nln; } } struct rtentry * nd6_lookup(const struct in6_addr *addr6, int create, struct ifnet *ifp) { struct rtentry *rt; struct sockaddr_in6 sin6; bzero(&sin6, sizeof(sin6)); sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_family = AF_INET6; sin6.sin6_addr = *addr6; rt = rtalloc1((struct sockaddr *)&sin6, create); if (rt && (rt->rt_flags & RTF_LLINFO) == 0) { /* * This is the case for the default route. * If we want to create a neighbor cache for the address, we * should free the route for the destination and allocate an * interface route. */ if (create) { RTFREE(rt); rt = NULL; } } if (rt != NULL) ; else if (create && ifp) { int e; /* * If no route is available and create is set, * we allocate a host route for the destination * and treat it like an interface route. * This hack is necessary for a neighbor which can't * be covered by our own prefix. */ struct ifaddr *ifa = ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); if (ifa == NULL) return NULL; /* * Create a new route. RTF_LLINFO is necessary * to create a Neighbor Cache entry for the * destination in nd6_rtrequest which will be * called in rtrequest via ifa->ifa_rtrequest. */ if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6, ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) != 0) { #if 0 log(LOG_ERR, "nd6_lookup: failed to add route for a " "neighbor(%s), errno=%d\n", ip6_sprintf(addr6), e); #endif return NULL; } if (rt == NULL) return NULL; if (rt->rt_llinfo) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; ln->ln_state = ND6_LLINFO_NOSTATE; } } else return NULL; rt->rt_refcnt--; /* * Validation for the entry. * Note that the check for rt_llinfo is necessary because a cloned * route from a parent route that has the L flag (e.g. the default * route to a p2p interface) may have the flag, too, while the * destination is not actually a neighbor. * XXX: we can't use rt->rt_ifp to check for the interface, since * it might be the loopback interface if the entry is for our * own address on a non-loopback interface. Instead, we should * use rt->rt_ifa->ifa_ifp, which would specify the REAL * interface. * Note also that ifa_ifp and ifp may differ when we connect two * interfaces to a same link, install a link prefix to an interface, * and try to install a neighbor cache on an interface that does not * have a route to the prefix. */ if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || rt->rt_gateway->sa_family != AF_LINK || rt->rt_llinfo == NULL || (ifp && rt->rt_ifa->ifa_ifp != ifp)) { if (create) { nd6log((LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec")); } return NULL; } return rt; } /* * Detect if a given IPv6 address identifies a neighbor on a given link. * XXX: should take care of the destination of a p2p link? */ int nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) { struct nd_prefix *pr; /* * A link-local address is always a neighbor. * XXX: a link does not necessarily specify a single interface. */ if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { struct sockaddr_in6 sin6_copy; u_int32_t zone; /* * We need sin6_copy since sa6_recoverscope() may modify the * content (XXX). */ sin6_copy = *addr; if (sa6_recoverscope(&sin6_copy)) return 0; /* XXX: should be impossible */ if (in6_setscope(&sin6_copy.sin6_addr, ifp, &zone)) return 0; if (sin6_copy.sin6_scope_id == zone) return 1; else return 0; } /* * If the address matches one of our on-link prefixes, it should be a * neighbor. */ LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { if (pr->ndpr_ifp != ifp) continue; if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) continue; if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, &addr->sin6_addr, &pr->ndpr_mask)) return 1; } /* * If the default router list is empty, all addresses are regarded * as on-link, and thus, as a neighbor. * XXX: we restrict the condition to hosts, because routers usually do * not have the "default router list". */ if (!ip6_forwarding && TAILQ_FIRST(&nd_defrouter) == NULL && nd6_defifindex == ifp->if_index) { return 1; } /* * Even if the address matches none of our addresses, it might be * in the neighbor cache. */ if (nd6_lookup(&addr->sin6_addr, 0, ifp) != NULL) return 1; return 0; } /* * Free an nd6 llinfo entry. * Since the function would cause significant changes in the kernel, DO NOT * make it global, unless you have a strong reason for the change, and are sure * that the change is safe. */ static struct llinfo_nd6 * nd6_free(struct rtentry *rt, int gc) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next; struct in6_addr in6 = satocsin6(rt_getkey(rt))->sin6_addr; struct nd_defrouter *dr; /* * we used to have pfctlinput(PRC_HOSTDEAD) here. * even though it is not harmful, it was not really necessary. */ /* cancel timer */ nd6_llinfo_settimer(ln, -1); if (!ip6_forwarding) { int s; s = splsoftnet(); dr = defrouter_lookup(&satocsin6(rt_getkey(rt))->sin6_addr, rt->rt_ifp); if (dr != NULL && dr->expire && ln->ln_state == ND6_LLINFO_STALE && gc) { /* * If the reason for the deletion is just garbage * collection, and the neighbor is an active default * router, do not delete it. Instead, reset the GC * timer using the router's lifetime. * Simply deleting the entry would affect default * router selection, which is not necessarily a good * thing, especially when we're using router preference * values. * XXX: the check for ln_state would be redundant, * but we intentionally keep it just in case. */ if (dr->expire > time_second) nd6_llinfo_settimer(ln, (dr->expire - time_second) * hz); else nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz); splx(s); return ln->ln_next; } if (ln->ln_router || dr) { /* * rt6_flush must be called whether or not the neighbor * is in the Default Router List. * See a corresponding comment in nd6_na_input(). */ rt6_flush(&in6, rt->rt_ifp); } if (dr) { /* * Unreachablity of a router might affect the default * router selection and on-link detection of advertised * prefixes. */ /* * Temporarily fake the state to choose a new default * router and to perform on-link determination of * prefixes correctly. * Below the state will be set correctly, * or the entry itself will be deleted. */ ln->ln_state = ND6_LLINFO_INCOMPLETE; /* * Since defrouter_select() does not affect the * on-link determination and MIP6 needs the check * before the default router selection, we perform * the check now. */ pfxlist_onlink_check(); /* * refresh default router list */ defrouter_select(); } splx(s); } /* * Before deleting the entry, remember the next entry as the * return value. We need this because pfxlist_onlink_check() above * might have freed other entries (particularly the old next entry) as * a side effect (XXX). */ next = ln->ln_next; /* * Detach the route from the routing tree and the list of neighbor * caches, and disable the route entry not to be used in already * cached routes. */ rtrequest(RTM_DELETE, rt_getkey(rt), (struct sockaddr *)0, rt_mask(rt), 0, (struct rtentry **)0); return next; } /* * Upper-layer reachability hint for Neighbor Unreachability Detection. * * XXX cost-effective methods? */ void nd6_nud_hint(struct rtentry *rt, struct in6_addr *dst6, int force) { struct llinfo_nd6 *ln; /* * If the caller specified "rt", use that. Otherwise, resolve the * routing table by supplied "dst6". */ if (rt == NULL) { if (dst6 == NULL) return; if ((rt = nd6_lookup(dst6, 0, NULL)) == NULL) return; } if ((rt->rt_flags & RTF_GATEWAY) != 0 || (rt->rt_flags & RTF_LLINFO) == 0 || !rt->rt_llinfo || !rt->rt_gateway || rt->rt_gateway->sa_family != AF_LINK) { /* This is not a host route. */ return; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; if (ln->ln_state < ND6_LLINFO_REACHABLE) return; /* * if we get upper-layer reachability confirmation many times, * it is possible we have false information. */ if (!force) { ln->ln_byhint++; if (ln->ln_byhint > nd6_maxnudhint) return; } ln->ln_state = ND6_LLINFO_REACHABLE; if (!ND6_LLINFO_PERMANENT(ln)) { nd6_llinfo_settimer(ln, (long)ND_IFINFO(rt->rt_ifp)->reachable * hz); } } void nd6_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) { struct sockaddr *gate = rt->rt_gateway; struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; static const struct sockaddr_dl null_sdl = { .sdl_len = sizeof(null_sdl), .sdl_family = AF_LINK, }; struct ifnet *ifp = rt->rt_ifp; struct ifaddr *ifa; RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); if ((rt->rt_flags & RTF_GATEWAY) != 0) return; if (nd6_need_cache(ifp) == 0 && (rt->rt_flags & RTF_HOST) == 0) { RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); /* * This is probably an interface direct route for a link * which does not need neighbor caches (e.g. fe80::%lo0/64). * We do not need special treatment below for such a route. * Moreover, the RTF_LLINFO flag which would be set below * would annoy the ndp(8) command. */ return; } if (req == RTM_RESOLVE && (nd6_need_cache(ifp) == 0 || /* stf case */ !nd6_is_addr_neighbor(satocsin6(rt_getkey(rt)), ifp))) { RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); /* * FreeBSD and BSD/OS often make a cloned host route based * on a less-specific route (e.g. the default route). * If the less specific route does not have a "gateway" * (this is the case when the route just goes to a p2p or an * stf interface), we'll mistakenly make a neighbor cache for * the host route, and will see strange neighbor solicitation * for the corresponding destination. In order to avoid the * confusion, we check if the destination of the route is * a neighbor in terms of neighbor discovery, and stop the * process if not. Additionally, we remove the LLINFO flag * so that ndp(8) will not try to get the neighbor information * of the destination. */ rt->rt_flags &= ~RTF_LLINFO; return; } switch (req) { case RTM_ADD: RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); /* * There is no backward compatibility :) * * if ((rt->rt_flags & RTF_HOST) == 0 && * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) * rt->rt_flags |= RTF_CLONING; */ if ((rt->rt_flags & RTF_CLONING) || ((rt->rt_flags & RTF_LLINFO) && !ln)) { /* * Case 1: This route should come from a route to * interface (RTF_CLONING case) or the route should be * treated as on-link but is currently not * (RTF_LLINFO && !ln case). */ rt_setgate(rt, (const struct sockaddr *)&null_sdl); RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); gate = rt->rt_gateway; satosdl(gate)->sdl_type = ifp->if_type; satosdl(gate)->sdl_index = ifp->if_index; if (ln) nd6_llinfo_settimer(ln, 0); RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); if ((rt->rt_flags & RTF_CLONING) != 0) break; } RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); /* * In IPv4 code, we try to annonuce new RTF_ANNOUNCE entry here. * We don't do that here since llinfo is not ready yet. * * There are also couple of other things to be discussed: * - unsolicited NA code needs improvement beforehand * - RFC2461 says we MAY send multicast unsolicited NA * (7.2.6 paragraph 4), however, it also says that we * SHOULD provide a mechanism to prevent multicast NA storm. * we don't have anything like it right now. * note that the mechanism needs a mutual agreement * between proxies, which means that we need to implement * a new protocol, or a new kludge. * - from RFC2461 6.2.4, host MUST NOT send an unsolicited NA. * we need to check ip6forwarding before sending it. * (or should we allow proxy ND configuration only for * routers? there's no mention about proxy ND from hosts) */ #if 0 /* XXX it does not work */ if (rt->rt_flags & RTF_ANNOUNCE) nd6_na_output(ifp, &satocsin6(rt_getkey(rt))->sin6_addr, &satocsin6(rt_getkey(rt))->sin6_addr, ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1, NULL); #endif /* FALLTHROUGH */ case RTM_RESOLVE: if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); /* * Address resolution isn't necessary for a point to * point link, so we can skip this test for a p2p link. */ if (gate->sa_family != AF_LINK || gate->sa_len < sizeof(null_sdl)) { log(LOG_DEBUG, "nd6_rtrequest: bad gateway value: %s\n", if_name(ifp)); break; } satosdl(gate)->sdl_type = ifp->if_type; satosdl(gate)->sdl_index = ifp->if_index; RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); } if (ln != NULL) break; /* This happens on a route change */ RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); /* * Case 2: This route may come from cloning, or a manual route * add with a LL address. */ R_Malloc(ln, struct llinfo_nd6 *, sizeof(*ln)); rt->rt_llinfo = (void *)ln; RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); if (ln == NULL) { log(LOG_DEBUG, "nd6_rtrequest: malloc failed\n"); break; } RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); nd6_inuse++; nd6_allocated++; bzero(ln, sizeof(*ln)); ln->ln_rt = rt; callout_init(&ln->ln_timer_ch, 0); /* this is required for "ndp" command. - shin */ if (req == RTM_ADD) { /* * gate should have some valid AF_LINK entry, * and ln->ln_expire should have some lifetime * which is specified by ndp command. */ ln->ln_state = ND6_LLINFO_REACHABLE; ln->ln_byhint = 0; } else { /* * When req == RTM_RESOLVE, rt is created and * initialized in rtrequest(), so rt_expire is 0. */ ln->ln_state = ND6_LLINFO_NOSTATE; nd6_llinfo_settimer(ln, 0); } RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); rt->rt_flags |= RTF_LLINFO; ln->ln_next = llinfo_nd6.ln_next; llinfo_nd6.ln_next = ln; ln->ln_prev = &llinfo_nd6; ln->ln_next->ln_prev = ln; RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); /* * check if rt_getkey(rt) is an address assigned * to the interface. */ ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, &satocsin6(rt_getkey(rt))->sin6_addr); RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); if (ifa) { void *macp = nd6_ifptomac(ifp); nd6_llinfo_settimer(ln, -1); ln->ln_state = ND6_LLINFO_REACHABLE; ln->ln_byhint = 0; if (macp) { /* XXX check for error */ (void)sockaddr_dl_setaddr(satosdl(gate), macp, ifp->if_addrlen); } if (nd6_useloopback) { rt->rt_ifp = lo0ifp; /* XXX */ /* * Make sure rt_ifa be equal to the ifaddr * corresponding to the address. * We need this because when we refer * rt_ifa->ia6_flags in ip6_input, we assume * that the rt_ifa points to the address instead * of the loopback address. */ if (ifa != rt->rt_ifa) rt_replace_ifa(rt, ifa); rt->rt_flags &= ~RTF_CLONED; } } else if (rt->rt_flags & RTF_ANNOUNCE) { nd6_llinfo_settimer(ln, -1); ln->ln_state = ND6_LLINFO_REACHABLE; ln->ln_byhint = 0; /* join solicited node multicast for proxy ND */ if (ifp->if_flags & IFF_MULTICAST) { struct in6_addr llsol; int error; llsol = satocsin6(rt_getkey(rt))->sin6_addr; llsol.s6_addr32[0] = htonl(0xff020000); llsol.s6_addr32[1] = 0; llsol.s6_addr32[2] = htonl(1); llsol.s6_addr8[12] = 0xff; if (in6_setscope(&llsol, ifp, NULL)) break; if (!in6_addmulti(&llsol, ifp, &error, 0)) { nd6log((LOG_ERR, "%s: failed to join " "%s (errno=%d)\n", if_name(ifp), ip6_sprintf(&llsol), error)); } } } break; case RTM_DELETE: if (ln == NULL) break; /* leave from solicited node multicast for proxy ND */ if ((rt->rt_flags & RTF_ANNOUNCE) != 0 && (ifp->if_flags & IFF_MULTICAST) != 0) { struct in6_addr llsol; struct in6_multi *in6m; llsol = satocsin6(rt_getkey(rt))->sin6_addr; llsol.s6_addr32[0] = htonl(0xff020000); llsol.s6_addr32[1] = 0; llsol.s6_addr32[2] = htonl(1); llsol.s6_addr8[12] = 0xff; if (in6_setscope(&llsol, ifp, NULL) == 0) { IN6_LOOKUP_MULTI(llsol, ifp, in6m); if (in6m) in6_delmulti(in6m); } } nd6_inuse--; ln->ln_next->ln_prev = ln->ln_prev; ln->ln_prev->ln_next = ln->ln_next; ln->ln_prev = NULL; nd6_llinfo_settimer(ln, -1); rt->rt_llinfo = 0; rt->rt_flags &= ~RTF_LLINFO; clear_llinfo_pqueue(ln); Free((void *)ln); } } int nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) { struct in6_drlist *drl = (struct in6_drlist *)data; struct in6_oprlist *oprl = (struct in6_oprlist *)data; struct in6_ndireq *ndi = (struct in6_ndireq *)data; struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; struct in6_ndifreq *ndif = (struct in6_ndifreq *)data; struct nd_defrouter *dr; struct nd_prefix *pr; struct rtentry *rt; int i = 0, error = 0; int s; switch (cmd) { case SIOCGDRLST_IN6: /* * obsolete API, use sysctl under net.inet6.icmp6 */ bzero(drl, sizeof(*drl)); s = splsoftnet(); TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) { if (i >= DRLSTSIZ) break; drl->defrouter[i].rtaddr = dr->rtaddr; in6_clearscope(&drl->defrouter[i].rtaddr); drl->defrouter[i].flags = dr->flags; drl->defrouter[i].rtlifetime = dr->rtlifetime; drl->defrouter[i].expire = dr->expire; drl->defrouter[i].if_index = dr->ifp->if_index; i++; } splx(s); break; case SIOCGPRLST_IN6: /* * obsolete API, use sysctl under net.inet6.icmp6 * * XXX the structure in6_prlist was changed in backward- * incompatible manner. in6_oprlist is used for SIOCGPRLST_IN6, * in6_prlist is used for nd6_sysctl() - fill_prlist(). */ /* * XXX meaning of fields, especialy "raflags", is very * differnet between RA prefix list and RR/static prefix list. * how about separating ioctls into two? */ bzero(oprl, sizeof(*oprl)); s = splsoftnet(); LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { struct nd_pfxrouter *pfr; int j; if (i >= PRLSTSIZ) break; oprl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; oprl->prefix[i].raflags = pr->ndpr_raf; oprl->prefix[i].prefixlen = pr->ndpr_plen; oprl->prefix[i].vltime = pr->ndpr_vltime; oprl->prefix[i].pltime = pr->ndpr_pltime; oprl->prefix[i].if_index = pr->ndpr_ifp->if_index; if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) oprl->prefix[i].expire = 0; else { time_t maxexpire; /* XXX: we assume time_t is signed. */ maxexpire = (-1) & ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); if (pr->ndpr_vltime < maxexpire - pr->ndpr_lastupdate) { oprl->prefix[i].expire = pr->ndpr_lastupdate + pr->ndpr_vltime; } else oprl->prefix[i].expire = maxexpire; } j = 0; LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { if (j < DRLSTSIZ) { #define RTRADDR oprl->prefix[i].advrtr[j] RTRADDR = pfr->router->rtaddr; in6_clearscope(&RTRADDR); #undef RTRADDR } j++; } oprl->prefix[i].advrtrs = j; oprl->prefix[i].origin = PR_ORIG_RA; i++; } splx(s); break; case OSIOCGIFINFO_IN6: #define ND ndi->ndi /* XXX: old ndp(8) assumes a positive value for linkmtu. */ memset(&ND, 0, sizeof(ND)); ND.linkmtu = IN6_LINKMTU(ifp); ND.maxmtu = ND_IFINFO(ifp)->maxmtu; ND.basereachable = ND_IFINFO(ifp)->basereachable; ND.reachable = ND_IFINFO(ifp)->reachable; ND.retrans = ND_IFINFO(ifp)->retrans; ND.flags = ND_IFINFO(ifp)->flags; ND.recalctm = ND_IFINFO(ifp)->recalctm; ND.chlim = ND_IFINFO(ifp)->chlim; break; case SIOCGIFINFO_IN6: ND = *ND_IFINFO(ifp); break; case SIOCSIFINFO_IN6: /* * used to change host variables from userland. * intented for a use on router to reflect RA configurations. */ /* 0 means 'unspecified' */ if (ND.linkmtu != 0) { if (ND.linkmtu < IPV6_MMTU || ND.linkmtu > IN6_LINKMTU(ifp)) { error = EINVAL; break; } ND_IFINFO(ifp)->linkmtu = ND.linkmtu; } if (ND.basereachable != 0) { int obasereachable = ND_IFINFO(ifp)->basereachable; ND_IFINFO(ifp)->basereachable = ND.basereachable; if (ND.basereachable != obasereachable) ND_IFINFO(ifp)->reachable = ND_COMPUTE_RTIME(ND.basereachable); } if (ND.retrans != 0) ND_IFINFO(ifp)->retrans = ND.retrans; if (ND.chlim != 0) ND_IFINFO(ifp)->chlim = ND.chlim; /* FALLTHROUGH */ case SIOCSIFINFO_FLAGS: ND_IFINFO(ifp)->flags = ND.flags; break; #undef ND case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */ /* sync kernel routing table with the default router list */ defrouter_reset(); defrouter_select(); break; case SIOCSPFXFLUSH_IN6: { /* flush all the prefix advertised by routers */ struct nd_prefix *pfx, *next; s = splsoftnet(); for (pfx = LIST_FIRST(&nd_prefix); pfx; pfx = next) { struct in6_ifaddr *ia, *ia_next; next = LIST_NEXT(pfx, ndpr_entry); if (IN6_IS_ADDR_LINKLOCAL(&pfx->ndpr_prefix.sin6_addr)) continue; /* XXX */ /* do we really have to remove addresses as well? */ for (ia = in6_ifaddr; ia; ia = ia_next) { /* ia might be removed. keep the next ptr. */ ia_next = ia->ia_next; if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; if (ia->ia6_ndpr == pfx) in6_purgeaddr(&ia->ia_ifa); } prelist_remove(pfx); } splx(s); break; } case SIOCSRTRFLUSH_IN6: { /* flush all the default routers */ struct nd_defrouter *drtr, *next; s = splsoftnet(); defrouter_reset(); for (drtr = TAILQ_FIRST(&nd_defrouter); drtr; drtr = next) { next = TAILQ_NEXT(drtr, dr_entry); defrtrlist_del(drtr); } defrouter_select(); splx(s); break; } case SIOCGNBRINFO_IN6: { struct llinfo_nd6 *ln; struct in6_addr nb_addr = nbi->addr; /* make local for safety */ if ((error = in6_setscope(&nb_addr, ifp, NULL)) != 0) return error; s = splsoftnet(); if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL || (ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) { error = EINVAL; splx(s); break; } nbi->state = ln->ln_state; nbi->asked = ln->ln_asked; nbi->isrouter = ln->ln_router; nbi->expire = ln->ln_expire; splx(s); break; } case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ ndif->ifindex = nd6_defifindex; break; case SIOCSDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ return nd6_setdefaultiface(ndif->ifindex); } return error; } void nd6_llinfo_release_pkts(struct llinfo_nd6 *ln, struct ifnet *ifp, struct rtentry *rt) { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold, ln->ln_hold = NULL; m_hold != NULL; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; /* * we assume ifp is not a p2p here, so * just set the 2nd argument as the * 1st one. */ nd6_output(ifp, ifp, m_hold, satocsin6(rt_getkey(rt)), rt); } } /* * Create neighbor cache entry and cache link-layer address, * on reception of inbound ND6 packets. (RS/RA/NS/redirect) */ struct rtentry * nd6_cache_lladdr( struct ifnet *ifp, struct in6_addr *from, char *lladdr, int lladdrlen, int type, /* ICMP6 type */ int code /* type dependent information */ ) { struct rtentry *rt = NULL; struct llinfo_nd6 *ln = NULL; int is_newentry; struct sockaddr_dl *sdl = NULL; int do_update; int olladdr; int llchange; int newstate = 0; if (ifp == NULL) panic("ifp == NULL in nd6_cache_lladdr"); if (from == NULL) panic("from == NULL in nd6_cache_lladdr"); /* nothing must be updated for unspecified address */ if (IN6_IS_ADDR_UNSPECIFIED(from)) return NULL; /* * Validation about ifp->if_addrlen and lladdrlen must be done in * the caller. * * XXX If the link does not have link-layer adderss, what should * we do? (ifp->if_addrlen == 0) * Spec says nothing in sections for RA, RS and NA. There's small * description on it in NS section (RFC 2461 7.2.3). */ rt = nd6_lookup(from, 0, ifp); if (rt == NULL) { #if 0 /* nothing must be done if there's no lladdr */ if (!lladdr || !lladdrlen) return NULL; #endif rt = nd6_lookup(from, 1, ifp); is_newentry = 1; } else { /* do nothing if static ndp is set */ if (rt->rt_flags & RTF_STATIC) return NULL; is_newentry = 0; } if (rt == NULL) return NULL; if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) { fail: (void)nd6_free(rt, 0); return NULL; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; if (ln == NULL) goto fail; if (rt->rt_gateway == NULL) goto fail; if (rt->rt_gateway->sa_family != AF_LINK) goto fail; sdl = satosdl(rt->rt_gateway); olladdr = (sdl->sdl_alen) ? 1 : 0; if (olladdr && lladdr) { if (memcmp(lladdr, CLLADDR(sdl), ifp->if_addrlen)) llchange = 1; else llchange = 0; } else llchange = 0; /* * newentry olladdr lladdr llchange (*=record) * 0 n n -- (1) * 0 y n -- (2) * 0 n y -- (3) * STALE * 0 y y n (4) * * 0 y y y (5) * STALE * 1 -- n -- (6) NOSTATE(= PASSIVE) * 1 -- y -- (7) * STALE */ if (lladdr) { /* (3-5) and (7) */ /* * Record source link-layer address * XXX is it dependent to ifp->if_type? */ /* XXX check for error */ (void)sockaddr_dl_setaddr(sdl, lladdr, ifp->if_addrlen); } if (!is_newentry) { if ((!olladdr && lladdr) || /* (3) */ (olladdr && lladdr && llchange)) { /* (5) */ do_update = 1; newstate = ND6_LLINFO_STALE; } else /* (1-2,4) */ do_update = 0; } else { do_update = 1; if (lladdr == NULL) /* (6) */ newstate = ND6_LLINFO_NOSTATE; else /* (7) */ newstate = ND6_LLINFO_STALE; } if (do_update) { /* * Update the state of the neighbor cache. */ ln->ln_state = newstate; if (ln->ln_state == ND6_LLINFO_STALE) { /* * XXX: since nd6_output() below will cause * state tansition to DELAY and reset the timer, * we must set the timer now, although it is actually * meaningless. */ nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz); nd6_llinfo_release_pkts(ln, ifp, rt); } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { /* probe right away */ nd6_llinfo_settimer((void *)ln, 0); } } /* * ICMP6 type dependent behavior. * * NS: clear IsRouter if new entry * RS: clear IsRouter * RA: set IsRouter if there's lladdr * redir: clear IsRouter if new entry * * RA case, (1): * The spec says that we must set IsRouter in the following cases: * - If lladdr exist, set IsRouter. This means (1-5). * - If it is old entry (!newentry), set IsRouter. This means (7). * So, based on the spec, in (1-5) and (7) cases we must set IsRouter. * A quetion arises for (1) case. (1) case has no lladdr in the * neighbor cache, this is similar to (6). * This case is rare but we figured that we MUST NOT set IsRouter. * * newentry olladdr lladdr llchange NS RS RA redir * D R * 0 n n -- (1) c ? s * 0 y n -- (2) c s s * 0 n y -- (3) c s s * 0 y y n (4) c s s * 0 y y y (5) c s s * 1 -- n -- (6) c c c s * 1 -- y -- (7) c c s c s * * (c=clear s=set) */ switch (type & 0xff) { case ND_NEIGHBOR_SOLICIT: /* * New entry must have is_router flag cleared. */ if (is_newentry) /* (6-7) */ ln->ln_router = 0; break; case ND_REDIRECT: /* * If the icmp is a redirect to a better router, always set the * is_router flag. Otherwise, if the entry is newly created, * clear the flag. [RFC 2461, sec 8.3] */ if (code == ND_REDIRECT_ROUTER) ln->ln_router = 1; else if (is_newentry) /* (6-7) */ ln->ln_router = 0; break; case ND_ROUTER_SOLICIT: /* * is_router flag must always be cleared. */ ln->ln_router = 0; break; case ND_ROUTER_ADVERT: /* * Mark an entry with lladdr as a router. */ if ((!is_newentry && (olladdr || lladdr)) || /* (2-5) */ (is_newentry && lladdr)) { /* (7) */ ln->ln_router = 1; } break; } /* * When the link-layer address of a router changes, select the * best router again. In particular, when the neighbor entry is newly * created, it might affect the selection policy. * Question: can we restrict the first condition to the "is_newentry" * case? * XXX: when we hear an RA from a new router with the link-layer * address option, defrouter_select() is called twice, since * defrtrlist_update called the function as well. However, I believe * we can compromise the overhead, since it only happens the first * time. * XXX: although defrouter_select() should not have a bad effect * for those are not autoconfigured hosts, we explicitly avoid such * cases for safety. */ if (do_update && ln->ln_router && !ip6_forwarding && ip6_accept_rtadv) defrouter_select(); return rt; } static void nd6_slowtimo(void *ignored_arg) { int s = splsoftnet(); struct nd_ifinfo *nd6if; struct ifnet *ifp; callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, nd6_slowtimo, NULL); TAILQ_FOREACH(ifp, &ifnet, if_list) { nd6if = ND_IFINFO(ifp); if (nd6if->basereachable && /* already initialized */ (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) { /* * Since reachable time rarely changes by router * advertisements, we SHOULD insure that a new random * value gets recomputed at least once every few hours. * (RFC 2461, 6.3.4) */ nd6if->recalctm = nd6_recalc_reachtm_interval; nd6if->reachable = ND_COMPUTE_RTIME(nd6if->basereachable); } } splx(s); } #define senderr(e) { error = (e); goto bad;} int nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, const struct sockaddr_in6 *dst, struct rtentry *rt0) { struct mbuf *m = m0; struct rtentry *rt = rt0; struct sockaddr_in6 *gw6 = NULL; struct llinfo_nd6 *ln = NULL; int error = 0; if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) goto sendpkt; if (nd6_need_cache(ifp) == 0) goto sendpkt; /* * next hop determination. This routine is derived from ether_output. */ if (rt) { if ((rt->rt_flags & RTF_UP) == 0) { if ((rt0 = rt = rtalloc1(sin6tocsa(dst), 1)) != NULL) { rt->rt_refcnt--; if (rt->rt_ifp != ifp) senderr(EHOSTUNREACH); } else senderr(EHOSTUNREACH); } if (rt->rt_flags & RTF_GATEWAY) { gw6 = (struct sockaddr_in6 *)rt->rt_gateway; /* * We skip link-layer address resolution and NUD * if the gateway is not a neighbor from ND point * of view, regardless of the value of nd_ifinfo.flags. * The second condition is a bit tricky; we skip * if the gateway is our own address, which is * sometimes used to install a route to a p2p link. */ if (!nd6_is_addr_neighbor(gw6, ifp) || in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { /* * We allow this kind of tricky route only * when the outgoing interface is p2p. * XXX: we may need a more generic rule here. */ if ((ifp->if_flags & IFF_POINTOPOINT) == 0) senderr(EHOSTUNREACH); goto sendpkt; } if (rt->rt_gwroute == 0) goto lookup; if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { rtfree(rt); rt = rt0; lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); if ((rt = rt->rt_gwroute) == 0) senderr(EHOSTUNREACH); /* the "G" test below also prevents rt == rt0 */ if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_ifp != ifp)) { rt->rt_refcnt--; rt0->rt_gwroute = 0; senderr(EHOSTUNREACH); } } } } /* * Address resolution or Neighbor Unreachability Detection * for the next hop. * At this point, the destination of the packet must be a unicast * or an anycast address(i.e. not a multicast). */ /* Look up the neighbor cache for the nexthop */ if (rt && (rt->rt_flags & RTF_LLINFO) != 0) ln = (struct llinfo_nd6 *)rt->rt_llinfo; else { /* * Since nd6_is_addr_neighbor() internally calls nd6_lookup(), * the condition below is not very efficient. But we believe * it is tolerable, because this should be a rare case. */ if (nd6_is_addr_neighbor(dst, ifp) && (rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL) ln = (struct llinfo_nd6 *)rt->rt_llinfo; } if (ln == NULL || rt == NULL) { if ((ifp->if_flags & IFF_POINTOPOINT) == 0 && !(ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD)) { log(LOG_DEBUG, "nd6_output: can't allocate llinfo for %s " "(ln=%p, rt=%p)\n", ip6_sprintf(&dst->sin6_addr), ln, rt); senderr(EIO); /* XXX: good error? */ } goto sendpkt; /* send anyway */ } /* We don't have to do link-layer address resolution on a p2p link. */ if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && ln->ln_state < ND6_LLINFO_REACHABLE) { ln->ln_state = ND6_LLINFO_STALE; nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz); } /* * The first time we send a packet to a neighbor whose entry is * STALE, we have to change the state to DELAY and a sets a timer to * expire in DELAY_FIRST_PROBE_TIME seconds to ensure do * neighbor unreachability detection on expiration. * (RFC 2461 7.3.3) */ if (ln->ln_state == ND6_LLINFO_STALE) { ln->ln_asked = 0; ln->ln_state = ND6_LLINFO_DELAY; nd6_llinfo_settimer(ln, (long)nd6_delay * hz); } /* * If the neighbor cache entry has a state other than INCOMPLETE * (i.e. its link-layer address is already resolved), just * send the packet. */ if (ln->ln_state > ND6_LLINFO_INCOMPLETE) goto sendpkt; /* * There is a neighbor cache entry, but no ethernet address * response yet. Append this latest packet to the end of the * packet queue in the mbuf, unless the number of the packet * does not exceed nd6_maxqueuelen. When it exceeds nd6_maxqueuelen, * the oldest packet in the queue will be removed. */ if (ln->ln_state == ND6_LLINFO_NOSTATE) ln->ln_state = ND6_LLINFO_INCOMPLETE; if (ln->ln_hold) { struct mbuf *m_hold; int i; i = 0; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold->m_nextpkt) { i++; if (m_hold->m_nextpkt == NULL) { m_hold->m_nextpkt = m; break; } } while (i >= nd6_maxqueuelen) { m_hold = ln->ln_hold; ln->ln_hold = ln->ln_hold->m_nextpkt; m_freem(m_hold); i--; } } else { ln->ln_hold = m; } /* * If there has been no NS for the neighbor after entering the * INCOMPLETE state, send the first solicitation. */ if (!ND6_LLINFO_PERMANENT(ln) && ln->ln_asked == 0) { ln->ln_asked++; nd6_llinfo_settimer(ln, (long)ND_IFINFO(ifp)->retrans * hz / 1000); nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); } return 0; sendpkt: /* discard the packet if IPv6 operation is disabled on the interface */ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { error = ENETDOWN; /* better error? */ goto bad; } #ifdef IPSEC /* clean ipsec history once it goes out of the node */ ipsec_delaux(m); #endif if ((ifp->if_flags & IFF_LOOPBACK) != 0) { return (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); } return (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); bad: if (m != NULL) m_freem(m); return error; } #undef senderr int nd6_need_cache(struct ifnet *ifp) { /* * XXX: we currently do not make neighbor cache on any interface * other than ARCnet, Ethernet, FDDI and GIF. * * RFC2893 says: * - unidirectional tunnels needs no ND */ switch (ifp->if_type) { case IFT_ARCNET: case IFT_ETHER: case IFT_FDDI: case IFT_IEEE1394: case IFT_CARP: case IFT_GIF: /* XXX need more cases? */ case IFT_PPP: case IFT_TUNNEL: return 1; default: return 0; } } int nd6_storelladdr(const struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m, const struct sockaddr *dst, u_char *lldst, size_t dstsize) { const struct sockaddr_dl *sdl; if (m->m_flags & M_MCAST) { switch (ifp->if_type) { case IFT_ETHER: case IFT_FDDI: ETHER_MAP_IPV6_MULTICAST(&satocsin6(dst)->sin6_addr, lldst); return 1; case IFT_IEEE1394: memcpy(lldst, ifp->if_broadcastaddr, MIN(dstsize, ifp->if_addrlen)); return 1; case IFT_ARCNET: *lldst = 0; return 1; default: m_freem(m); return 0; } } if (rt == NULL) { /* this could happen, if we could not allocate memory */ m_freem(m); return 0; } if (rt->rt_gateway->sa_family != AF_LINK) { printf("%s: something odd happens\n", __func__); m_freem(m); return 0; } sdl = satocsdl(rt->rt_gateway); if (sdl->sdl_alen == 0 || sdl->sdl_alen > dstsize) { /* this should be impossible, but we bark here for debugging */ printf("%s: sdl_alen == 0, dst=%s, if=%s\n", __func__, ip6_sprintf(&satocsin6(dst)->sin6_addr), if_name(ifp)); m_freem(m); return 0; } memcpy(lldst, CLLADDR(sdl), MIN(dstsize, sdl->sdl_alen)); return 1; } static void clear_llinfo_pqueue(struct llinfo_nd6 *ln) { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; m_freem(m_hold); } ln->ln_hold = NULL; return; } int nd6_sysctl( int name, void *oldp, /* syscall arg, need copyout */ size_t *oldlenp, void *newp, /* syscall arg, need copyin */ size_t newlen ) { void *p; size_t ol; int error; error = 0; if (newp) return EPERM; if (oldp && !oldlenp) return EINVAL; ol = oldlenp ? *oldlenp : 0; if (oldp) { p = malloc(*oldlenp, M_TEMP, M_WAITOK); if (p == NULL) return ENOMEM; } else p = NULL; switch (name) { case ICMPV6CTL_ND6_DRLIST: error = fill_drlist(p, oldlenp, ol); if (!error && p != NULL && oldp != NULL) error = copyout(p, oldp, *oldlenp); break; case ICMPV6CTL_ND6_PRLIST: error = fill_prlist(p, oldlenp, ol); if (!error && p != NULL && oldp != NULL) error = copyout(p, oldp, *oldlenp); break; case ICMPV6CTL_ND6_MAXQLEN: break; default: error = ENOPROTOOPT; break; } if (p) free(p, M_TEMP); return error; } static int fill_drlist(void *oldp, size_t *oldlenp, size_t ol) { int error = 0, s; struct in6_defrouter *d = NULL, *de = NULL; struct nd_defrouter *dr; size_t l; s = splsoftnet(); if (oldp) { d = (struct in6_defrouter *)oldp; de = (struct in6_defrouter *)((char *)oldp + *oldlenp); } l = 0; TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) { if (oldp && d + 1 <= de) { bzero(d, sizeof(*d)); d->rtaddr.sin6_family = AF_INET6; d->rtaddr.sin6_len = sizeof(struct sockaddr_in6); d->rtaddr.sin6_addr = dr->rtaddr; if (sa6_recoverscope(&d->rtaddr)) { log(LOG_ERR, "scope error in router list (%s)\n", ip6_sprintf(&d->rtaddr.sin6_addr)); /* XXX: press on... */ } d->flags = dr->flags; d->rtlifetime = dr->rtlifetime; d->expire = dr->expire; d->if_index = dr->ifp->if_index; } l += sizeof(*d); if (d) d++; } if (oldp) { if (l > ol) error = ENOMEM; } if (oldlenp) *oldlenp = l; /* (void *)d - (void *)oldp */ splx(s); return error; } static int fill_prlist(void *oldp, size_t *oldlenp, size_t ol) { int error = 0, s; struct nd_prefix *pr; struct in6_prefix *p = NULL; struct in6_prefix *pe = NULL; size_t l; s = splsoftnet(); if (oldp) { p = (struct in6_prefix *)oldp; pe = (struct in6_prefix *)((char *)oldp + *oldlenp); } l = 0; LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { u_short advrtrs; size_t advance; struct sockaddr_in6 *sin6; struct sockaddr_in6 *s6; struct nd_pfxrouter *pfr; if (oldp && p + 1 <= pe) { bzero(p, sizeof(*p)); sin6 = (struct sockaddr_in6 *)(p + 1); p->prefix = pr->ndpr_prefix; if (sa6_recoverscope(&p->prefix)) { log(LOG_ERR, "scope error in prefix list (%s)\n", ip6_sprintf(&p->prefix.sin6_addr)); /* XXX: press on... */ } p->raflags = pr->ndpr_raf; p->prefixlen = pr->ndpr_plen; p->vltime = pr->ndpr_vltime; p->pltime = pr->ndpr_pltime; p->if_index = pr->ndpr_ifp->if_index; if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) p->expire = 0; else { time_t maxexpire; /* XXX: we assume time_t is signed. */ maxexpire = (-1) & ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); if (pr->ndpr_vltime < maxexpire - pr->ndpr_lastupdate) { p->expire = pr->ndpr_lastupdate + pr->ndpr_vltime; } else p->expire = maxexpire; } p->refcnt = pr->ndpr_refcnt; p->flags = pr->ndpr_stateflags; p->origin = PR_ORIG_RA; advrtrs = 0; LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { if ((void *)&sin6[advrtrs + 1] > (void *)pe) { advrtrs++; continue; } s6 = &sin6[advrtrs]; s6->sin6_family = AF_INET6; s6->sin6_len = sizeof(struct sockaddr_in6); s6->sin6_addr = pfr->router->rtaddr; s6->sin6_scope_id = 0; if (sa6_recoverscope(s6)) { log(LOG_ERR, "scope error in " "prefix list (%s)\n", ip6_sprintf(&pfr->router->rtaddr)); } advrtrs++; } p->advrtrs = advrtrs; } else { advrtrs = 0; LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) advrtrs++; } advance = sizeof(*p) + sizeof(*sin6) * advrtrs; l += advance; if (p) p = (struct in6_prefix *)((char *)p + advance); } if (oldp) { *oldlenp = l; /* (void *)d - (void *)oldp */ if (l > ol) error = ENOMEM; } else *oldlenp = l; splx(s); return error; } @ 1.118.2.1 log @sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.121 2007/11/01 20:33:58 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.121 2007/11/01 20:33:58 dyoung Exp $"); d112 6 a117 6 static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *); static void nd6_slowtimo(void *); static int regen_tmpaddr(struct in6_ifaddr *); static struct llinfo_nd6 *nd6_free(struct rtentry *, int); static void nd6_llinfo_timer(void *); static void clear_llinfo_pqueue(struct llinfo_nd6 *); d123 2 a124 2 static int fill_drlist(void *, size_t *, size_t); static int fill_prlist(void *, size_t *, size_t); d1119 4 a1123 1 uint8_t namelen = strlen(ifp->if_xname), addrlen = ifp->if_addrlen; a1180 5 union { struct sockaddr sa; struct sockaddr_dl sdl; struct sockaddr_storage ss; } u; d1187 1 a1187 5 sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type, NULL, namelen, NULL, addrlen); rt_setgate(rt, &u.sa); gate = rt->rt_gateway; d1190 3 d1239 1 a1239 2 gate->sa_len < sockaddr_dl_measure(namelen, addrlen)) { d1304 1 a1304 1 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, d1309 1 a1309 1 const void *mac; d1313 1 a1313 1 if ((mac = nd6_ifptomac(ifp)) != NULL) { d1315 2 a1316 2 (void)sockaddr_dl_setaddr(satosdl(gate), gate->sa_len, mac, ifp->if_addrlen); d1319 1 a1319 1 ifp = rt->rt_ifp = lo0ifp; /* XXX */ d1740 1 a1740 2 (void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr, ifp->if_addrlen); @ 1.118.2.2 log @sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.118.2.1 2007/11/06 23:34:08 matt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.118.2.1 2007/11/06 23:34:08 matt Exp $"); d110 1 a110 8 static const struct sockaddr_in6 all1_sa = { .sin6_family = AF_INET6 , .sin6_len = sizeof(struct sockaddr_in6) , .sin6_addr = {.s6_addr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}} }; d132 1 d139 5 d641 1 a641 1 IFADDR_FOREACH(ifa, ifp) { d793 4 a796 1 sockaddr_in6_init(&sin6, addr6, 0, 0, 0); d833 2 a834 2 if ((e = rtrequest(RTM_ADD, (const struct sockaddr *)&sin6, ifa->ifa_addr, (const struct sockaddr *)&all1_sa, d2259 4 a2262 2 memset(d, 0, sizeof(*d)); sockaddr_in6_init(&d->rtaddr, &dr->rtaddr, 0, 0, 0); d2359 4 a2362 2 sockaddr_in6_init(s6, &pfr->router->rtaddr, 0, 0, 0); @ 1.117 log @Take steps to hide the radix_node implementation of the forwarding table from the forwarding table's users: Introduce rt_walktree() for walking the routing table and applying a function to each rtentry. Replace most rn_walktree() calls with it. Use rt_getkey()/rt_setkey() to get/set a route's destination. Keep a pointer to the sockaddr key in the rtentry, so that rtentry users do not have to grovel in the radix_node for the key. Add a RTM_GET method to rtrequest. Use that instead of radix_node lookups in, e.g., carp(4). Add sys/net/link_proto.c, which supplies sockaddr routines for link-layer socket addresses (sockaddr_dl). Cosmetic: Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH, et cetera. Use NULL instead of 0 for null pointers. Use __arraycount(). Reduce gratuitous parenthesization. Stop using variadic arguments for rip6_output(), it is unnecessary. Remove the unnecessary rtentry member rt_genmask and the code to maintain it, since nothing actually used it. Make rt_maskedcopy() easier to read by using meaningful variable names. Extract a subroutine intern_netmask() for looking up a netmask in the masks table. Start converting backslash-ridden IPv6 macros in sys/netinet6/in6_var.h into inline subroutines that one can read without special eyeglasses. One functional change: when the kernel serves an RTM_GET, RTM_LOCK, or RTM_CHANGE request, it applies the netmask (if supplied) to a destination before searching for it in the forwarding table. I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove the unlawful radix_node knowledge. Apart from the changes to carp(4), netiso, ATM, and strip(4), I have run the changes on three nodes in my wireless routing testbed, which involves IPv4 + IPv6 dynamic routing acrobatics, and it's working beautifully so far. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.116 2007/07/09 21:11:13 ad Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.116 2007/07/09 21:11:13 ad Exp $"); a77 3 #define SIN6(s) ((const struct sockaddr_in6 *)s) #define SDL(s) ((struct sockaddr_dl *)s) d773 1 a773 1 struct sockaddr_dl *sdl; d779 1 a779 1 sdl = (struct sockaddr_dl *)rt->rt_gateway; d1191 2 a1192 2 SDL(gate)->sdl_type = ifp->if_type; SDL(gate)->sdl_index = ifp->if_index; d1224 2 a1225 2 &SIN6(rt_getkey(rt))->sin6_addr, &SIN6(rt_getkey(rt))->sin6_addr, d1245 2 a1246 2 SDL(gate)->sdl_type = ifp->if_type; SDL(gate)->sdl_index = ifp->if_index; d1305 1 a1305 1 &SIN6(rt_getkey(rt))->sin6_addr); d1314 3 a1316 2 bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); SDL(gate)->sdl_alen = ifp->if_addrlen; d1342 1 a1342 1 llsol = SIN6(rt_getkey(rt))->sin6_addr; d1367 1 a1367 1 llsol = SIN6(rt_getkey(rt))->sin6_addr; d1712 1 a1712 1 sdl = SDL(rt->rt_gateway); d1716 1 a1716 1 if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen)) d1739 2 a1740 2 sdl->sdl_alen = ifp->if_addrlen; bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen); d2128 2 a2129 1 ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, lldst); d2132 2 a2133 1 bcopy(ifp->if_broadcastaddr, lldst, ifp->if_addrlen); d2154 1 a2154 1 sdl = SDL(rt->rt_gateway); d2158 1 a2158 1 ip6_sprintf(&SIN6(dst)->sin6_addr), if_name(ifp)); @ 1.117.4.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.118 2007/08/07 04:35:42 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.118 2007/08/07 04:35:42 dyoung Exp $"); d78 3 d776 1 a776 1 const struct sockaddr_dl *sdl; d782 1 a782 1 sdl = satocsdl(rt->rt_gateway); d1194 2 a1195 2 satosdl(gate)->sdl_type = ifp->if_type; satosdl(gate)->sdl_index = ifp->if_index; d1227 2 a1228 2 &satocsin6(rt_getkey(rt))->sin6_addr, &satocsin6(rt_getkey(rt))->sin6_addr, d1248 2 a1249 2 satosdl(gate)->sdl_type = ifp->if_type; satosdl(gate)->sdl_index = ifp->if_index; d1308 1 a1308 1 &satocsin6(rt_getkey(rt))->sin6_addr); d1317 2 a1318 3 /* XXX check for error */ (void)sockaddr_dl_setaddr(satosdl(gate), macp, ifp->if_addrlen); d1344 1 a1344 1 llsol = satocsin6(rt_getkey(rt))->sin6_addr; d1369 1 a1369 1 llsol = satocsin6(rt_getkey(rt))->sin6_addr; d1714 1 a1714 1 sdl = satosdl(rt->rt_gateway); d1718 1 a1718 1 if (memcmp(lladdr, CLLADDR(sdl), ifp->if_addrlen)) d1741 2 a1742 2 /* XXX check for error */ (void)sockaddr_dl_setaddr(sdl, lladdr, ifp->if_addrlen); d2130 1 a2130 2 ETHER_MAP_IPV6_MULTICAST(&satocsin6(dst)->sin6_addr, lldst); d2133 1 a2133 2 memcpy(lldst, ifp->if_broadcastaddr, MIN(dstsize, ifp->if_addrlen)); d2154 1 a2154 1 sdl = satocsdl(rt->rt_gateway); d2158 1 a2158 1 ip6_sprintf(&satocsin6(dst)->sin6_addr), if_name(ifp)); @ 1.117.4.2 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.120 2007/09/02 19:42:22 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.120 2007/09/02 19:42:22 dyoung Exp $"); d1119 4 a1123 1 uint8_t namelen = strlen(ifp->if_xname), addrlen = ifp->if_addrlen; a1180 5 union { struct sockaddr sa; struct sockaddr_dl sdl; struct sockaddr_storage ss; } u; d1187 1 a1187 5 sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type, NULL, namelen, NULL, addrlen); rt_setgate(rt, &u.sa); gate = rt->rt_gateway; d1190 3 d1239 1 a1239 2 gate->sa_len < sockaddr_dl_measure(namelen, addrlen)) { d1304 1 a1304 1 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, d1309 1 a1309 1 const void *mac; d1313 1 a1313 1 if ((mac = nd6_ifptomac(ifp)) != NULL) { d1315 2 a1316 2 (void)sockaddr_dl_setaddr(satosdl(gate), gate->sa_len, mac, ifp->if_addrlen); d1319 1 a1319 1 ifp = rt->rt_ifp = lo0ifp; /* XXX */ d1740 1 a1740 2 (void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr, ifp->if_addrlen); @ 1.117.4.3 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.121 2007/11/01 20:33:58 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.121 2007/11/01 20:33:58 dyoung Exp $"); d112 6 a117 6 static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *); static void nd6_slowtimo(void *); static int regen_tmpaddr(struct in6_ifaddr *); static struct llinfo_nd6 *nd6_free(struct rtentry *, int); static void nd6_llinfo_timer(void *); static void clear_llinfo_pqueue(struct llinfo_nd6 *); d123 2 a124 2 static int fill_drlist(void *, size_t *, size_t); static int fill_prlist(void *, size_t *, size_t); @ 1.117.4.4 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.117.4.3 2007/11/04 21:03:44 jmcneill Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.117.4.3 2007/11/04 21:03:44 jmcneill Exp $"); d110 1 a110 8 static const struct sockaddr_in6 all1_sa = { .sin6_family = AF_INET6 , .sin6_len = sizeof(struct sockaddr_in6) , .sin6_addr = {.s6_addr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}} }; d132 1 d139 5 d793 4 a796 1 sockaddr_in6_init(&sin6, addr6, 0, 0, 0); d833 2 a834 2 if ((e = rtrequest(RTM_ADD, (const struct sockaddr *)&sin6, ifa->ifa_addr, (const struct sockaddr *)&all1_sa, d2259 4 a2262 2 memset(d, 0, sizeof(*d)); sockaddr_in6_init(&d->rtaddr, &dr->rtaddr, 0, 0, 0); d2359 4 a2362 2 sockaddr_in6_init(s6, &pfr->router->rtaddr, 0, 0, 0); @ 1.117.4.5 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.123 2007/12/04 10:27:34 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.123 2007/12/04 10:27:34 dyoung Exp $"); d642 1 a642 1 IFADDR_FOREACH(ifa, ifp) { @ 1.116 log @Merge some of the less invasive changes from the vmlocking branch: - kthread, callout, devsw API changes - select()/poll() improvements - miscellaneous MT safety improvements @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.115 2007/05/17 00:53:26 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.115 2007/05/17 00:53:26 dyoung Exp $"); d436 1 a436 1 dst = (struct sockaddr_in6 *)rt_key(rt); d967 1 a967 1 struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; d981 1 a981 1 dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, d1061 1 a1061 1 rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, d1129 3 d1136 2 d1150 3 a1152 1 !nd6_is_addr_neighbor(satocsin6(rt_key(rt)), ifp))) { d1173 2 d1190 3 a1192 2 rt_setgate(rt, rt_key(rt), (const struct sockaddr *)&null_sdl); d1198 2 d1203 2 d1227 2 a1228 2 &SIN6(rt_key(rt))->sin6_addr, &SIN6(rt_key(rt))->sin6_addr, d1235 2 d1250 2 d1255 2 d1263 2 d1269 2 d1293 2 d1301 2 d1304 1 a1304 1 * check if rt_key(rt) is one of my address assigned d1308 3 a1310 1 &SIN6(rt_key(rt))->sin6_addr); d1344 1 a1344 1 llsol = SIN6(rt_key(rt))->sin6_addr; d1369 1 a1369 1 llsol = SIN6(rt_key(rt))->sin6_addr; d1637 1 a1637 1 nd6_output(ifp, ifp, m_hold, satocsin6(rt_key(rt)), rt); @ 1.116.2.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.118 2007/08/07 04:35:42 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.118 2007/08/07 04:35:42 dyoung Exp $"); d78 3 d436 1 a436 1 dst = satocsin6(rt_getkey(rt)); d776 1 a776 1 const struct sockaddr_dl *sdl; d782 1 a782 1 sdl = satocsdl(rt->rt_gateway); d967 1 a967 1 struct in6_addr in6 = satocsin6(rt_getkey(rt))->sin6_addr; d981 1 a981 1 dr = defrouter_lookup(&satocsin6(rt_getkey(rt))->sin6_addr, d1061 1 a1061 1 rtrequest(RTM_DELETE, rt_getkey(rt), (struct sockaddr *)0, a1128 3 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1132 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1145 1 a1145 3 !nd6_is_addr_neighbor(satocsin6(rt_getkey(rt)), ifp))) { RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1165 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1181 2 a1182 3 rt_setgate(rt, (const struct sockaddr *)&null_sdl); RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1184 2 a1185 2 satosdl(gate)->sdl_type = ifp->if_type; satosdl(gate)->sdl_index = ifp->if_index; a1187 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1190 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1213 2 a1214 2 &satocsin6(rt_getkey(rt))->sin6_addr, &satocsin6(rt_getkey(rt))->sin6_addr, a1220 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1232 2 a1233 4 satosdl(gate)->sdl_type = ifp->if_type; satosdl(gate)->sdl_index = ifp->if_index; RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1236 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1242 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1246 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1268 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1274 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1276 1 a1276 1 * check if rt_getkey(rt) is an address assigned d1280 1 a1280 3 &satocsin6(rt_getkey(rt))->sin6_addr); RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1287 2 a1288 3 /* XXX check for error */ (void)sockaddr_dl_setaddr(satosdl(gate), macp, ifp->if_addrlen); d1314 1 a1314 1 llsol = satocsin6(rt_getkey(rt))->sin6_addr; d1339 1 a1339 1 llsol = satocsin6(rt_getkey(rt))->sin6_addr; d1607 1 a1607 1 nd6_output(ifp, ifp, m_hold, satocsin6(rt_getkey(rt)), rt); d1684 1 a1684 1 sdl = satosdl(rt->rt_gateway); d1688 1 a1688 1 if (memcmp(lladdr, CLLADDR(sdl), ifp->if_addrlen)) d1711 2 a1712 2 /* XXX check for error */ (void)sockaddr_dl_setaddr(sdl, lladdr, ifp->if_addrlen); d2100 1 a2100 2 ETHER_MAP_IPV6_MULTICAST(&satocsin6(dst)->sin6_addr, lldst); d2103 1 a2103 2 memcpy(lldst, ifp->if_broadcastaddr, MIN(dstsize, ifp->if_addrlen)); d2124 1 a2124 1 sdl = satocsdl(rt->rt_gateway); d2128 1 a2128 1 ip6_sprintf(&satocsin6(dst)->sin6_addr), if_name(ifp)); @ 1.116.2.2 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.116.2.1 2007/08/15 13:49:52 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.116.2.1 2007/08/15 13:49:52 skrll Exp $"); d1119 4 a1123 1 uint8_t namelen = strlen(ifp->if_xname), addrlen = ifp->if_addrlen; a1180 5 union { struct sockaddr sa; struct sockaddr_dl sdl; struct sockaddr_storage ss; } u; d1187 1 a1187 5 sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type, NULL, namelen, NULL, addrlen); rt_setgate(rt, &u.sa); gate = rt->rt_gateway; d1190 3 d1239 1 a1239 2 gate->sa_len < sockaddr_dl_measure(namelen, addrlen)) { d1304 1 a1304 1 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, d1309 1 a1309 1 const void *mac; d1313 1 a1313 1 if ((mac = nd6_ifptomac(ifp)) != NULL) { d1315 2 a1316 2 (void)sockaddr_dl_setaddr(satosdl(gate), gate->sa_len, mac, ifp->if_addrlen); d1319 1 a1319 1 ifp = rt->rt_ifp = lo0ifp; /* XXX */ d1740 1 a1740 2 (void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr, ifp->if_addrlen); @ 1.115 log @Fix the memory leak reported in kern/36337. Thanks Matthias Scheler for the heads-up. My fix is based on the following patches from FreeBSD, however, I extracted the code into a subroutine, nd6_llinfo_release_pkts(): http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/netinet6/nd6.c.diff?r1=1.48.2.18;r2=1.48.2.19 http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/netinet6/nd6_nbr.c.diff?r1=1.29.2.8;r2=1.29.2.9 @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.114 2007/05/02 20:40:27 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.114 2007/05/02 20:40:27 dyoung Exp $"); d122 3 a124 3 struct callout nd6_slowtimo_ch = CALLOUT_INITIALIZER; struct callout nd6_timer_ch = CALLOUT_INITIALIZER; extern struct callout in6_tmpaddrtimer_ch; d152 3 d1251 1 a1251 1 callout_init(&ln->ln_timer_ch); @ 1.114 log @Eliminate address family-specific route caches (struct route, struct route_in6, struct route_iso), replacing all caches with a struct route. The principle benefit of this change is that all of the protocol families can benefit from route cache-invalidation, which is necessary for correct routing. Route-cache invalidation fixes an ancient PR, kern/3508, at long last; it fixes various other PRs, also. Discussions with and ideas from Joerg Sonnenberger influenced this work tremendously. Of course, all design oversights and bugs are mine. DETAILS 1 I added to each address family a pool of sockaddrs. I have introduced routines for allocating, copying, and duplicating, and freeing sockaddrs: struct sockaddr *sockaddr_alloc(sa_family_t af, int flags); struct sockaddr *sockaddr_copy(struct sockaddr *dst, const struct sockaddr *src); struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags); void sockaddr_free(struct sockaddr *sa); sockaddr_alloc() returns either a sockaddr from the pool belonging to the specified family, or NULL if the pool is exhausted. The returned sockaddr has the right size for that family; sa_family and sa_len fields are initialized to the family and sockaddr length---e.g., sa_family = AF_INET and sa_len = sizeof(struct sockaddr_in). sockaddr_free() puts the given sockaddr back into its family's pool. sockaddr_dup() and sockaddr_copy() work analogously to strdup() and strcpy(), respectively. sockaddr_copy() KASSERTs that the family of the destination and source sockaddrs are alike. The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is passed directly to pool_get(9). 2 I added routines for initializing sockaddrs in each address family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(), etc. They are fairly self-explanatory. 3 structs route_in6 and route_iso are no more. All protocol families use struct route. I have changed the route cache, 'struct route', so that it does not contain storage space for a sockaddr. Instead, struct route points to a sockaddr coming from the pool the sockaddr belongs to. I added a new method to struct route, rtcache_setdst(), for setting the cache destination: int rtcache_setdst(struct route *, const struct sockaddr *); rtcache_setdst() returns 0 on success, or ENOMEM if no memory is available to create the sockaddr storage. It is now possible for rtcache_getdst() to return NULL if, say, rtcache_setdst() failed. I check the return value for NULL everywhere in the kernel. 4 Each routing domain (struct domain) has a list of live route caches, dom_rtcache. rtflushall(sa_family_t af) looks up the domain indicated by 'af', walks the domain's list of route caches and invalidates each one. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.113 2007/03/17 06:32:46 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.113 2007/03/17 06:32:46 dyoung Exp $"); d1587 21 d1742 1 a1742 25 if (ln->ln_hold) { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { struct mbuf *mpkt = NULL; m_hold_next = m_hold->m_nextpkt; mpkt = m_copym(m_hold, 0, M_COPYALL, M_DONTWAIT); if (mpkt == NULL) { m_freem(m_hold); break; } mpkt->m_nextpkt = NULL; /* * we assume ifp is not a p2p here, so * just set the 2nd argument as the * 1st one. */ nd6_output(ifp, ifp, mpkt, (struct sockaddr_in6 *)rt_key(rt), rt); } ln->ln_hold = NULL; } @ 1.113 log @In nd6_rtrequest(), when we lookup/create a route whose destination is equal to one of the host's IPv6 addresses, do not stop at setting the route's interface to lo0, but also clear the route's RTF_CLONED flag, if it is present, so that ip6_input() will accept packets sent to that destination. This is necessary because ip6_input() will not accept a packet if it looks up the packet's destination and finds a route with RTF_CLONED set. I believe this will help IPv6 networking survive '/etc/rc.d/network restart'. See the problem report, kern/33279. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.112 2007/03/15 23:35:25 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.112 2007/03/15 23:35:25 dyoung Exp $"); d1867 1 a1867 1 struct sockaddr_in6 *dst, struct rtentry *rt0) d1886 1 a1886 3 if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1)) != NULL) { d2053 1 a2053 2 return (*ifp->if_output)(origifp, m, (struct sockaddr *)dst, rt); d2055 1 a2055 1 return (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt); d2058 1 a2058 1 if (m) @ 1.112 log @In nd6_lookup, shorten a staircase. KNF: change return (expr); to return expr; throughout. Fix K&R prototypes and parameter type declarations. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.111 2007/03/04 06:03:27 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.111 2007/03/04 06:03:27 christos Exp $"); d1299 1 @ 1.111 log @Kill caddr_t; there will be some MI fallout, but it will be fixed shortly. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.110 2007/02/17 22:34:14 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.110 2007/02/17 22:34:14 dyoung Exp $"); d132 1 a132 1 nd6_init() d158 1 a158 2 nd6_ifattach(ifp) struct ifnet *ifp; d185 1 a185 2 nd6_ifdetach(nd) struct nd_ifinfo *nd; d192 1 a192 2 nd6_setmtu(ifp) struct ifnet *ifp; d198 1 a198 3 nd6_setmtu0(ifp, ndi) struct ifnet *ifp; struct nd_ifinfo *ndi; d234 1 a234 4 nd6_option_init(opt, icmp6len, ndopts) void *opt; int icmp6len; union nd_opts *ndopts; d252 1 a252 2 nd6_option(ndopts) union nd_opts *ndopts; d303 1 a303 2 nd6_options(ndopts) union nd_opts *ndopts; d382 1 a382 3 nd6_llinfo_settimer(ln, xtick) struct llinfo_nd6 *ln; long xtick; d409 1 a409 2 nd6_llinfo_timer(arg) void *arg; d632 1 d634 1 a634 2 regen_tmpaddr(ia6) struct in6_ifaddr *ia6; /* deprecated/invalidated temporary address */ d690 1 a690 1 return (-1); d692 1 a692 1 return (0); d695 1 a695 1 return (-1); d703 1 a703 2 nd6_purge(ifp) struct ifnet *ifp; d788 1 a788 4 nd6_lookup(addr6, create, ifp) const struct in6_addr *addr6; int create; struct ifnet *ifp; d810 4 a813 3 if (rt == NULL) { if (create && ifp) { int e; d815 11 a825 11 /* * If no route is available and create is set, * we allocate a host route for the destination * and treat it like an interface route. * This hack is necessary for a neighbor which can't * be covered by our own prefix. */ struct ifaddr *ifa = ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); if (ifa == NULL) return (NULL); d827 10 a836 10 /* * Create a new route. RTF_LLINFO is necessary * to create a Neighbor Cache entry for the * destination in nd6_rtrequest which will be * called in rtrequest via ifa->ifa_rtrequest. */ if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6, ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) != 0) { d838 4 a841 4 log(LOG_ERR, "nd6_lookup: failed to add route for a " "neighbor(%s), errno=%d\n", ip6_sprintf(addr6), e); d843 11 a853 12 return (NULL); } if (rt == NULL) return (NULL); if (rt->rt_llinfo) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; ln->ln_state = ND6_LLINFO_NOSTATE; } } else return (NULL); } d880 1 a880 1 return (NULL); d882 1 a882 1 return (rt); d908 1 a908 1 return (0); /* XXX: should be impossible */ d910 1 a910 1 return (0); d912 1 a912 1 return (1); d914 1 a914 1 return (0); d930 1 a930 1 return (1); d941 1 a941 1 return (1); d949 1 a949 1 return (1); d951 1 a951 1 return (0); d961 1 a961 3 nd6_free(rt, gc) struct rtentry *rt; int gc; d1001 1 a1001 1 return (ln->ln_next); d1061 1 a1061 1 return (next); d1070 1 a1070 4 nd6_nud_hint(rt, dst6, force) struct rtentry *rt; struct in6_addr *dst6; int force; d1359 1 a1359 4 nd6_ioctl(cmd, data, ifp) u_long cmd; void * data; struct ifnet *ifp; d1560 1 a1560 1 return (error); d1581 1 a1581 1 return (nd6_setdefaultiface(ndif->ifindex)); d1583 1 a1583 1 return (error); d1865 2 a1866 6 nd6_output(ifp, origifp, m0, dst, rt0) struct ifnet *ifp; struct ifnet *origifp; struct mbuf *m0; struct sockaddr_in6 *dst; struct rtentry *rt0; d2040 1 a2040 1 return (0); d2054 2 a2055 2 return ((*ifp->if_output)(origifp, m, (struct sockaddr *)dst, rt)); d2057 1 a2057 1 return ((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt)); d2062 1 a2062 1 return (error); d2067 1 a2067 2 nd6_need_cache(ifp) struct ifnet *ifp; d2085 1 a2085 1 return (1); d2087 1 a2087 1 return (0); d2140 1 a2140 2 clear_llinfo_pqueue(ln) struct llinfo_nd6 *ln; d2204 1 a2204 1 return (error); d2208 1 a2208 3 fill_drlist(oldp, oldlenp, ol) void *oldp; size_t *oldlenp, ol; d2256 1 a2256 1 return (error); d2260 1 a2260 3 fill_prlist(oldp, oldlenp, ol) void *oldp; size_t *oldlenp, ol; d2361 1 a2361 1 return (error); @ 1.111.4.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.116 2007/07/09 21:11:13 ad Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.116 2007/07/09 21:11:13 ad Exp $"); d122 3 a124 3 callout_t nd6_slowtimo_ch; callout_t nd6_timer_ch; extern callout_t in6_tmpaddrtimer_ch; d132 1 a132 1 nd6_init(void) a151 3 callout_init(&nd6_slowtimo_ch, 0); callout_init(&nd6_timer_ch, 0); d158 2 a159 1 nd6_ifattach(struct ifnet *ifp) d186 2 a187 1 nd6_ifdetach(struct nd_ifinfo *nd) d194 2 a195 1 nd6_setmtu(struct ifnet *ifp) d201 3 a203 1 nd6_setmtu0(struct ifnet *ifp, struct nd_ifinfo *ndi) d239 4 a242 1 nd6_option_init(void *opt, int icmp6len, union nd_opts *ndopts) d260 2 a261 1 nd6_option(union nd_opts *ndopts) d312 2 a313 1 nd6_options(union nd_opts *ndopts) d392 3 a394 1 nd6_llinfo_settimer(struct llinfo_nd6 *ln, long xtick) d421 2 a422 1 nd6_llinfo_timer(void *arg) a644 1 /* ia6: deprecated/invalidated temporary address */ d646 2 a647 1 regen_tmpaddr(struct in6_ifaddr *ia6) d703 1 a703 1 return -1; d705 1 a705 1 return 0; d708 1 a708 1 return -1; d716 2 a717 1 nd6_purge(struct ifnet *ifp) d802 4 a805 1 nd6_lookup(const struct in6_addr *addr6, int create, struct ifnet *ifp) d827 3 a829 4 if (rt != NULL) ; else if (create && ifp) { int e; d831 11 a841 11 /* * If no route is available and create is set, * we allocate a host route for the destination * and treat it like an interface route. * This hack is necessary for a neighbor which can't * be covered by our own prefix. */ struct ifaddr *ifa = ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); if (ifa == NULL) return NULL; d843 10 a852 10 /* * Create a new route. RTF_LLINFO is necessary * to create a Neighbor Cache entry for the * destination in nd6_rtrequest which will be * called in rtrequest via ifa->ifa_rtrequest. */ if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6, ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) != 0) { d854 4 a857 4 log(LOG_ERR, "nd6_lookup: failed to add route for a " "neighbor(%s), errno=%d\n", ip6_sprintf(addr6), e); d859 12 a870 11 return NULL; } if (rt == NULL) return NULL; if (rt->rt_llinfo) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; ln->ln_state = ND6_LLINFO_NOSTATE; } } else return NULL; d897 1 a897 1 return NULL; d899 1 a899 1 return rt; d925 1 a925 1 return 0; /* XXX: should be impossible */ d927 1 a927 1 return 0; d929 1 a929 1 return 1; d931 1 a931 1 return 0; d947 1 a947 1 return 1; d958 1 a958 1 return 1; d966 1 a966 1 return 1; d968 1 a968 1 return 0; d978 3 a980 1 nd6_free(struct rtentry *rt, int gc) d1020 1 a1020 1 return ln->ln_next; d1080 1 a1080 1 return next; d1089 4 a1092 1 nd6_nud_hint(struct rtentry *rt, struct in6_addr *dst6, int force) d1270 1 a1270 1 callout_init(&ln->ln_timer_ch, 0); a1320 1 rt->rt_flags &= ~RTF_CLONED; d1381 4 a1384 1 nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) d1585 1 a1585 1 return error; d1606 1 a1606 23 return nd6_setdefaultiface(ndif->ifindex); } return error; } void nd6_llinfo_release_pkts(struct llinfo_nd6 *ln, struct ifnet *ifp, struct rtentry *rt) { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold, ln->ln_hold = NULL; m_hold != NULL; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; /* * we assume ifp is not a p2p here, so * just set the 2nd argument as the * 1st one. */ nd6_output(ifp, ifp, m_hold, satocsin6(rt_key(rt)), rt); d1608 1 d1745 25 a1769 1 nd6_llinfo_release_pkts(ln, ifp, rt); d1890 6 a1895 2 nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, const struct sockaddr_in6 *dst, struct rtentry *rt0) d1914 3 a1916 1 if ((rt0 = rt = rtalloc1(sin6tocsa(dst), 1)) != NULL) { d2069 1 a2069 1 return 0; d2083 2 a2084 1 return (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); d2086 1 a2086 1 return (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); d2089 1 a2089 1 if (m != NULL) d2091 1 a2091 1 return error; d2096 2 a2097 1 nd6_need_cache(struct ifnet *ifp) d2115 1 a2115 1 return 1; d2117 1 a2117 1 return 0; d2170 2 a2171 1 clear_llinfo_pqueue(struct llinfo_nd6 *ln) d2235 1 a2235 1 return error; d2239 3 a2241 1 fill_drlist(void *oldp, size_t *oldlenp, size_t ol) d2289 1 a2289 1 return error; d2293 3 a2295 1 fill_prlist(void *oldp, size_t *oldlenp, size_t ol) d2396 1 a2396 1 return error; @ 1.111.2.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.111 2007/03/04 06:03:27 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.111 2007/03/04 06:03:27 christos Exp $"); d132 1 a132 1 nd6_init(void) d158 2 a159 1 nd6_ifattach(struct ifnet *ifp) d186 2 a187 1 nd6_ifdetach(struct nd_ifinfo *nd) d194 2 a195 1 nd6_setmtu(struct ifnet *ifp) d201 3 a203 1 nd6_setmtu0(struct ifnet *ifp, struct nd_ifinfo *ndi) d239 4 a242 1 nd6_option_init(void *opt, int icmp6len, union nd_opts *ndopts) d260 2 a261 1 nd6_option(union nd_opts *ndopts) d312 2 a313 1 nd6_options(union nd_opts *ndopts) d392 3 a394 1 nd6_llinfo_settimer(struct llinfo_nd6 *ln, long xtick) d421 2 a422 1 nd6_llinfo_timer(void *arg) a644 1 /* ia6: deprecated/invalidated temporary address */ d646 2 a647 1 regen_tmpaddr(struct in6_ifaddr *ia6) d703 1 a703 1 return -1; d705 1 a705 1 return 0; d708 1 a708 1 return -1; d716 2 a717 1 nd6_purge(struct ifnet *ifp) d802 4 a805 1 nd6_lookup(const struct in6_addr *addr6, int create, struct ifnet *ifp) d827 3 a829 4 if (rt != NULL) ; else if (create && ifp) { int e; d831 11 a841 11 /* * If no route is available and create is set, * we allocate a host route for the destination * and treat it like an interface route. * This hack is necessary for a neighbor which can't * be covered by our own prefix. */ struct ifaddr *ifa = ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); if (ifa == NULL) return NULL; d843 10 a852 10 /* * Create a new route. RTF_LLINFO is necessary * to create a Neighbor Cache entry for the * destination in nd6_rtrequest which will be * called in rtrequest via ifa->ifa_rtrequest. */ if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6, ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) != 0) { d854 4 a857 4 log(LOG_ERR, "nd6_lookup: failed to add route for a " "neighbor(%s), errno=%d\n", ip6_sprintf(addr6), e); d859 12 a870 11 return NULL; } if (rt == NULL) return NULL; if (rt->rt_llinfo) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; ln->ln_state = ND6_LLINFO_NOSTATE; } } else return NULL; d897 1 a897 1 return NULL; d899 1 a899 1 return rt; d925 1 a925 1 return 0; /* XXX: should be impossible */ d927 1 a927 1 return 0; d929 1 a929 1 return 1; d931 1 a931 1 return 0; d947 1 a947 1 return 1; d958 1 a958 1 return 1; d966 1 a966 1 return 1; d968 1 a968 1 return 0; d978 3 a980 1 nd6_free(struct rtentry *rt, int gc) d1020 1 a1020 1 return ln->ln_next; d1080 1 a1080 1 return next; d1089 4 a1092 1 nd6_nud_hint(struct rtentry *rt, struct in6_addr *dst6, int force) a1320 1 rt->rt_flags &= ~RTF_CLONED; d1381 4 a1384 1 nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) d1585 1 a1585 1 return error; d1606 1 a1606 1 return nd6_setdefaultiface(ndif->ifindex); d1608 1 a1608 1 return error; d1890 6 a1895 2 nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, struct sockaddr_in6 *dst, struct rtentry *rt0) d2069 1 a2069 1 return 0; d2083 2 a2084 2 return (*ifp->if_output)(origifp, m, (struct sockaddr *)dst, rt); d2086 1 a2086 1 return (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt); d2091 1 a2091 1 return error; d2096 2 a2097 1 nd6_need_cache(struct ifnet *ifp) d2115 1 a2115 1 return 1; d2117 1 a2117 1 return 0; d2170 2 a2171 1 clear_llinfo_pqueue(struct llinfo_nd6 *ln) d2235 1 a2235 1 return error; d2239 3 a2241 1 fill_drlist(void *oldp, size_t *oldlenp, size_t ol) d2289 1 a2289 1 return error; d2293 3 a2295 1 fill_prlist(void *oldp, size_t *oldlenp, size_t ol) d2396 1 a2396 1 return error; @ 1.111.2.2 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.111.2.1 2007/04/10 13:26:51 ad Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.111.2.1 2007/04/10 13:26:51 ad Exp $"); a1586 21 void nd6_llinfo_release_pkts(struct llinfo_nd6 *ln, struct ifnet *ifp, struct rtentry *rt) { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold, ln->ln_hold = NULL; m_hold != NULL; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; /* * we assume ifp is not a p2p here, so * just set the 2nd argument as the * 1st one. */ nd6_output(ifp, ifp, m_hold, satocsin6(rt_key(rt)), rt); } } d1721 25 a1745 1 nd6_llinfo_release_pkts(ln, ifp, rt); d1867 1 a1867 1 const struct sockaddr_in6 *dst, struct rtentry *rt0) d1886 3 a1888 1 if ((rt0 = rt = rtalloc1(sin6tocsa(dst), 1)) != NULL) { d2055 2 a2056 1 return (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); d2058 1 a2058 1 return (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); d2061 1 a2061 1 if (m != NULL) @ 1.111.2.3 log @Adapt to callout API change. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.111.2.2 2007/06/08 14:17:58 ad Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.111.2.2 2007/06/08 14:17:58 ad Exp $"); d122 3 a124 3 callout_t nd6_slowtimo_ch; callout_t nd6_timer_ch; extern callout_t in6_tmpaddrtimer_ch; a151 3 callout_init(&nd6_slowtimo_ch, 0); callout_init(&nd6_timer_ch, 0); d1248 1 a1248 1 callout_init(&ln->ln_timer_ch, 0); @ 1.111.2.4 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.111.2.3 2007/07/01 21:50:54 ad Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.111.2.3 2007/07/01 21:50:54 ad Exp $"); d78 3 d436 1 a436 1 dst = satocsin6(rt_getkey(rt)); d776 1 a776 1 const struct sockaddr_dl *sdl; d782 1 a782 1 sdl = satocsdl(rt->rt_gateway); d967 1 a967 1 struct in6_addr in6 = satocsin6(rt_getkey(rt))->sin6_addr; d981 1 a981 1 dr = defrouter_lookup(&satocsin6(rt_getkey(rt))->sin6_addr, d1061 1 a1061 1 rtrequest(RTM_DELETE, rt_getkey(rt), (struct sockaddr *)0, a1128 3 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1132 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1145 1 a1145 3 !nd6_is_addr_neighbor(satocsin6(rt_getkey(rt)), ifp))) { RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1165 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1181 2 a1182 3 rt_setgate(rt, (const struct sockaddr *)&null_sdl); RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1184 2 a1185 2 satosdl(gate)->sdl_type = ifp->if_type; satosdl(gate)->sdl_index = ifp->if_index; a1187 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1190 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1213 2 a1214 2 &satocsin6(rt_getkey(rt))->sin6_addr, &satocsin6(rt_getkey(rt))->sin6_addr, a1220 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1232 2 a1233 4 satosdl(gate)->sdl_type = ifp->if_type; satosdl(gate)->sdl_index = ifp->if_index; RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1236 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1242 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1246 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1268 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1274 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1276 1 a1276 1 * check if rt_getkey(rt) is an address assigned d1280 1 a1280 3 &satocsin6(rt_getkey(rt))->sin6_addr); RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1287 2 a1288 3 /* XXX check for error */ (void)sockaddr_dl_setaddr(satosdl(gate), macp, ifp->if_addrlen); d1314 1 a1314 1 llsol = satocsin6(rt_getkey(rt))->sin6_addr; d1339 1 a1339 1 llsol = satocsin6(rt_getkey(rt))->sin6_addr; d1607 1 a1607 1 nd6_output(ifp, ifp, m_hold, satocsin6(rt_getkey(rt)), rt); d1684 1 a1684 1 sdl = satosdl(rt->rt_gateway); d1688 1 a1688 1 if (memcmp(lladdr, CLLADDR(sdl), ifp->if_addrlen)) d1711 2 a1712 2 /* XXX check for error */ (void)sockaddr_dl_setaddr(sdl, lladdr, ifp->if_addrlen); d2100 1 a2100 2 ETHER_MAP_IPV6_MULTICAST(&satocsin6(dst)->sin6_addr, lldst); d2103 1 a2103 2 memcpy(lldst, ifp->if_broadcastaddr, MIN(dstsize, ifp->if_addrlen)); d2124 1 a2124 1 sdl = satocsdl(rt->rt_gateway); d2128 1 a2128 1 ip6_sprintf(&satocsin6(dst)->sin6_addr), if_name(ifp)); @ 1.111.2.5 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.111.2.4 2007/08/20 21:28:06 ad Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.111.2.4 2007/08/20 21:28:06 ad Exp $"); d1119 4 a1123 1 uint8_t namelen = strlen(ifp->if_xname), addrlen = ifp->if_addrlen; a1180 5 union { struct sockaddr sa; struct sockaddr_dl sdl; struct sockaddr_storage ss; } u; d1187 1 a1187 5 sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type, NULL, namelen, NULL, addrlen); rt_setgate(rt, &u.sa); gate = rt->rt_gateway; d1190 3 d1239 1 a1239 2 gate->sa_len < sockaddr_dl_measure(namelen, addrlen)) { d1304 1 a1304 1 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, d1309 1 a1309 1 const void *mac; d1313 1 a1313 1 if ((mac = nd6_ifptomac(ifp)) != NULL) { d1315 2 a1316 2 (void)sockaddr_dl_setaddr(satosdl(gate), gate->sa_len, mac, ifp->if_addrlen); d1319 1 a1319 1 ifp = rt->rt_ifp = lo0ifp; /* XXX */ d1740 1 a1740 2 (void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr, ifp->if_addrlen); @ 1.111.6.1 log @First attempt to bring branch in sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.111 2007/03/04 06:03:27 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.111 2007/03/04 06:03:27 christos Exp $"); d132 1 a132 1 nd6_init(void) d158 2 a159 1 nd6_ifattach(struct ifnet *ifp) d186 2 a187 1 nd6_ifdetach(struct nd_ifinfo *nd) d194 2 a195 1 nd6_setmtu(struct ifnet *ifp) d201 3 a203 1 nd6_setmtu0(struct ifnet *ifp, struct nd_ifinfo *ndi) d239 4 a242 1 nd6_option_init(void *opt, int icmp6len, union nd_opts *ndopts) d260 2 a261 1 nd6_option(union nd_opts *ndopts) d312 2 a313 1 nd6_options(union nd_opts *ndopts) d392 3 a394 1 nd6_llinfo_settimer(struct llinfo_nd6 *ln, long xtick) d421 2 a422 1 nd6_llinfo_timer(void *arg) a644 1 /* ia6: deprecated/invalidated temporary address */ d646 2 a647 1 regen_tmpaddr(struct in6_ifaddr *ia6) d703 1 a703 1 return -1; d705 1 a705 1 return 0; d708 1 a708 1 return -1; d716 2 a717 1 nd6_purge(struct ifnet *ifp) d802 4 a805 1 nd6_lookup(const struct in6_addr *addr6, int create, struct ifnet *ifp) d827 3 a829 4 if (rt != NULL) ; else if (create && ifp) { int e; d831 11 a841 11 /* * If no route is available and create is set, * we allocate a host route for the destination * and treat it like an interface route. * This hack is necessary for a neighbor which can't * be covered by our own prefix. */ struct ifaddr *ifa = ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); if (ifa == NULL) return NULL; d843 10 a852 10 /* * Create a new route. RTF_LLINFO is necessary * to create a Neighbor Cache entry for the * destination in nd6_rtrequest which will be * called in rtrequest via ifa->ifa_rtrequest. */ if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6, ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) != 0) { d854 4 a857 4 log(LOG_ERR, "nd6_lookup: failed to add route for a " "neighbor(%s), errno=%d\n", ip6_sprintf(addr6), e); d859 12 a870 11 return NULL; } if (rt == NULL) return NULL; if (rt->rt_llinfo) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; ln->ln_state = ND6_LLINFO_NOSTATE; } } else return NULL; d897 1 a897 1 return NULL; d899 1 a899 1 return rt; d925 1 a925 1 return 0; /* XXX: should be impossible */ d927 1 a927 1 return 0; d929 1 a929 1 return 1; d931 1 a931 1 return 0; d947 1 a947 1 return 1; d958 1 a958 1 return 1; d966 1 a966 1 return 1; d968 1 a968 1 return 0; d978 3 a980 1 nd6_free(struct rtentry *rt, int gc) d1020 1 a1020 1 return ln->ln_next; d1080 1 a1080 1 return next; d1089 4 a1092 1 nd6_nud_hint(struct rtentry *rt, struct in6_addr *dst6, int force) a1320 1 rt->rt_flags &= ~RTF_CLONED; d1381 4 a1384 1 nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) d1585 1 a1585 1 return error; d1606 1 a1606 1 return nd6_setdefaultiface(ndif->ifindex); d1608 1 a1608 1 return error; d1890 6 a1895 2 nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, struct sockaddr_in6 *dst, struct rtentry *rt0) d2069 1 a2069 1 return 0; d2083 2 a2084 2 return (*ifp->if_output)(origifp, m, (struct sockaddr *)dst, rt); d2086 1 a2086 1 return (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt); d2091 1 a2091 1 return error; d2096 2 a2097 1 nd6_need_cache(struct ifnet *ifp) d2115 1 a2115 1 return 1; d2117 1 a2117 1 return 0; d2170 2 a2171 1 clear_llinfo_pqueue(struct llinfo_nd6 *ln) d2235 1 a2235 1 return error; d2239 3 a2241 1 fill_drlist(void *oldp, size_t *oldlenp, size_t ol) d2289 1 a2289 1 return error; d2293 3 a2295 1 fill_prlist(void *oldp, size_t *oldlenp, size_t ol) d2396 1 a2396 1 return error; @ 1.110 log @KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous parentheses in return statements. Cosmetic: don't open-code TAILQ_FOREACH(). Cosmetic: change types of variables to avoid oodles of casts: in in6_src.c, avoid casts by changing several route_in6 pointers to struct route pointers. Remove unnecessary casts to caddr_t elsewhere. Pave the way for eliminating address family-specific route caches: soon, struct route will not embed a sockaddr, but it will hold a reference to an external sockaddr, instead. We will set the destination sockaddr using rtcache_setdst(). (I created a stub for it, but it isn't used anywhere, yet.) rtcache_free() will free the sockaddr. I have extracted from rtcache_free() a helper subroutine, rtcache_clear(). rtcache_clear() will "forget" a cached route, but it will not forget the destination by releasing the sockaddr. I use rtcache_clear() instead of rtcache_free() in rtcache_update(), because rtcache_update() is not supposed to forget the destination. Constify: 1 Introduce const accessor for route->ro_dst, rtcache_getdst(). 2 Constify the 'dst' argument to ifnet->if_output(). This led me to constify a lot of code called by output routines. 3 Constify the sockaddr argument to protosw->pr_ctlinput. This led me to constify a lot of code called by ctlinput routines. 4 Introduce const macros for converting from a generic sockaddr to family-specific sockaddrs, e.g., sockaddr_in: satocsin6, satocsin, et cetera. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.109 2006/11/24 19:47:00 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.109 2006/11/24 19:47:00 christos Exp $"); d278 1 a278 1 if ((caddr_t)&nd_opt->nd_opt_len >= (caddr_t)ndopts->nd_opts_last) { d293 1 a293 1 ndopts->nd_opts_search = (struct nd_opt_hdr *)((caddr_t)nd_opt + olen); d1261 1 a1261 1 rt->rt_llinfo = (caddr_t)ln; d1301 1 a1301 1 caddr_t macp = nd6_ifptomac(ifp); d1376 1 a1376 1 Free((caddr_t)ln); d1383 1 a1383 1 caddr_t data; d2252 1 a2252 1 de = (struct in6_defrouter *)((caddr_t)oldp + *oldlenp); d2285 1 a2285 1 *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ d2307 1 a2307 1 pe = (struct in6_prefix *)((caddr_t)oldp + *oldlenp); d2384 1 a2384 1 p = (struct in6_prefix *)((caddr_t)p + advance); d2388 1 a2388 1 *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ @ 1.109 log @fix spelling of accommodate; from Zapher. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.108 2006/11/20 04:34:16 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.108 2006/11/20 04:34:16 dyoung Exp $"); d78 1 a78 1 #define SIN6(s) ((struct sockaddr_in6 *)s) d803 1 a803 1 struct in6_addr *addr6; d907 1 a907 3 nd6_is_addr_neighbor(addr, ifp) struct sockaddr_in6 *addr; struct ifnet *ifp; d1164 1 a1164 1 !nd6_is_addr_neighbor((struct sockaddr_in6 *)rt_key(rt), ifp))) { d2122 3 a2124 6 nd6_storelladdr(ifp, rt, m, dst, desten) struct ifnet *ifp; struct rtentry *rt; struct mbuf *m; struct sockaddr *dst; u_char *desten; d2126 1 a2126 1 struct sockaddr_dl *sdl; d2132 2 a2133 3 ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, desten); return (1); d2135 2 a2136 2 bcopy(ifp->if_broadcastaddr, desten, ifp->if_addrlen); return (1); d2138 2 a2139 2 *desten = 0; return (1); d2142 1 a2142 1 return (0); d2149 1 a2149 1 return (0); d2152 1 a2152 1 printf("nd6_storelladdr: something odd happens\n"); d2154 1 a2154 1 return (0); d2157 1 a2157 1 if (sdl->sdl_alen == 0) { d2159 1 a2159 1 printf("nd6_storelladdr: sdl_alen == 0, dst=%s, if=%s\n", d2162 1 a2162 1 return (0); d2165 2 a2166 2 bcopy(LLADDR(sdl), desten, sdl->sdl_alen); return (1); @ 1.109.4.1 log @- sync with head. - move sched_changepri back to kern_synch.c as it doesn't know PPQ anymore. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.109 2006/11/24 19:47:00 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.109 2006/11/24 19:47:00 christos Exp $"); d78 1 a78 1 #define SIN6(s) ((const struct sockaddr_in6 *)s) d803 1 a803 1 const struct in6_addr *addr6; d907 3 a909 1 nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) d1166 1 a1166 1 !nd6_is_addr_neighbor(satocsin6(rt_key(rt)), ifp))) { d2124 6 a2129 3 nd6_storelladdr(const struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m, const struct sockaddr *dst, u_char *lldst, size_t dstsize) d2131 1 a2131 1 const struct sockaddr_dl *sdl; d2137 3 a2139 2 ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, lldst); return 1; d2141 2 a2142 2 bcopy(ifp->if_broadcastaddr, lldst, ifp->if_addrlen); return 1; d2144 2 a2145 2 *lldst = 0; return 1; d2148 1 a2148 1 return 0; d2155 1 a2155 1 return 0; d2158 1 a2158 1 printf("%s: something odd happens\n", __func__); d2160 1 a2160 1 return 0; d2163 1 a2163 1 if (sdl->sdl_alen == 0 || sdl->sdl_alen > dstsize) { d2165 1 a2165 1 printf("%s: sdl_alen == 0, dst=%s, if=%s\n", __func__, d2168 1 a2168 1 return 0; d2171 2 a2172 2 memcpy(lldst, CLLADDR(sdl), MIN(dstsize, sdl->sdl_alen)); return 1; @ 1.109.4.2 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.109.4.1 2007/02/27 16:55:04 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.109.4.1 2007/02/27 16:55:04 yamt Exp $"); d278 1 a278 1 if ((void *)&nd_opt->nd_opt_len >= (void *)ndopts->nd_opts_last) { d293 1 a293 1 ndopts->nd_opts_search = (struct nd_opt_hdr *)((char *)nd_opt + olen); d1261 1 a1261 1 rt->rt_llinfo = (void *)ln; d1301 1 a1301 1 void *macp = nd6_ifptomac(ifp); d1376 1 a1376 1 Free((void *)ln); d1383 1 a1383 1 void * data; d2252 1 a2252 1 de = (struct in6_defrouter *)((char *)oldp + *oldlenp); d2285 1 a2285 1 *oldlenp = l; /* (void *)d - (void *)oldp */ d2307 1 a2307 1 pe = (struct in6_prefix *)((char *)oldp + *oldlenp); d2384 1 a2384 1 p = (struct in6_prefix *)((char *)p + advance); d2388 1 a2388 1 *oldlenp = l; /* (void *)d - (void *)oldp */ @ 1.109.4.3 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.109.4.2 2007/03/12 05:59:59 rmind Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.109.4.2 2007/03/12 05:59:59 rmind Exp $"); d132 1 a132 1 nd6_init(void) d158 2 a159 1 nd6_ifattach(struct ifnet *ifp) d186 2 a187 1 nd6_ifdetach(struct nd_ifinfo *nd) d194 2 a195 1 nd6_setmtu(struct ifnet *ifp) d201 3 a203 1 nd6_setmtu0(struct ifnet *ifp, struct nd_ifinfo *ndi) d239 4 a242 1 nd6_option_init(void *opt, int icmp6len, union nd_opts *ndopts) d260 2 a261 1 nd6_option(union nd_opts *ndopts) d312 2 a313 1 nd6_options(union nd_opts *ndopts) d392 3 a394 1 nd6_llinfo_settimer(struct llinfo_nd6 *ln, long xtick) d421 2 a422 1 nd6_llinfo_timer(void *arg) a644 1 /* ia6: deprecated/invalidated temporary address */ d646 2 a647 1 regen_tmpaddr(struct in6_ifaddr *ia6) d703 1 a703 1 return -1; d705 1 a705 1 return 0; d708 1 a708 1 return -1; d716 2 a717 1 nd6_purge(struct ifnet *ifp) d802 4 a805 1 nd6_lookup(const struct in6_addr *addr6, int create, struct ifnet *ifp) d827 3 a829 4 if (rt != NULL) ; else if (create && ifp) { int e; d831 11 a841 11 /* * If no route is available and create is set, * we allocate a host route for the destination * and treat it like an interface route. * This hack is necessary for a neighbor which can't * be covered by our own prefix. */ struct ifaddr *ifa = ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); if (ifa == NULL) return NULL; d843 10 a852 10 /* * Create a new route. RTF_LLINFO is necessary * to create a Neighbor Cache entry for the * destination in nd6_rtrequest which will be * called in rtrequest via ifa->ifa_rtrequest. */ if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6, ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) != 0) { d854 4 a857 4 log(LOG_ERR, "nd6_lookup: failed to add route for a " "neighbor(%s), errno=%d\n", ip6_sprintf(addr6), e); d859 12 a870 11 return NULL; } if (rt == NULL) return NULL; if (rt->rt_llinfo) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; ln->ln_state = ND6_LLINFO_NOSTATE; } } else return NULL; d897 1 a897 1 return NULL; d899 1 a899 1 return rt; d925 1 a925 1 return 0; /* XXX: should be impossible */ d927 1 a927 1 return 0; d929 1 a929 1 return 1; d931 1 a931 1 return 0; d947 1 a947 1 return 1; d958 1 a958 1 return 1; d966 1 a966 1 return 1; d968 1 a968 1 return 0; d978 3 a980 1 nd6_free(struct rtentry *rt, int gc) d1020 1 a1020 1 return ln->ln_next; d1080 1 a1080 1 return next; d1089 4 a1092 1 nd6_nud_hint(struct rtentry *rt, struct in6_addr *dst6, int force) a1320 1 rt->rt_flags &= ~RTF_CLONED; d1381 4 a1384 1 nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) d1585 1 a1585 1 return error; d1606 1 a1606 1 return nd6_setdefaultiface(ndif->ifindex); d1608 1 a1608 1 return error; d1890 6 a1895 2 nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, struct sockaddr_in6 *dst, struct rtentry *rt0) d2069 1 a2069 1 return 0; d2083 2 a2084 2 return (*ifp->if_output)(origifp, m, (struct sockaddr *)dst, rt); d2086 1 a2086 1 return (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt); d2091 1 a2091 1 return error; d2096 2 a2097 1 nd6_need_cache(struct ifnet *ifp) d2115 1 a2115 1 return 1; d2117 1 a2117 1 return 0; d2170 2 a2171 1 clear_llinfo_pqueue(struct llinfo_nd6 *ln) d2235 1 a2235 1 return error; d2239 3 a2241 1 fill_drlist(void *oldp, size_t *oldlenp, size_t ol) d2289 1 a2289 1 return error; d2293 3 a2295 1 fill_prlist(void *oldp, size_t *oldlenp, size_t ol) d2396 1 a2396 1 return error; @ 1.109.4.4 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.109.4.3 2007/03/24 14:56:12 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.109.4.3 2007/03/24 14:56:12 yamt Exp $"); d1867 1 a1867 1 const struct sockaddr_in6 *dst, struct rtentry *rt0) d1886 3 a1888 1 if ((rt0 = rt = rtalloc1(sin6tocsa(dst), 1)) != NULL) { d2055 2 a2056 1 return (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); d2058 1 a2058 1 return (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); d2061 1 a2061 1 if (m != NULL) @ 1.109.4.5 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.109.4.4 2007/05/07 10:56:06 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.109.4.4 2007/05/07 10:56:06 yamt Exp $"); a1586 21 void nd6_llinfo_release_pkts(struct llinfo_nd6 *ln, struct ifnet *ifp, struct rtentry *rt) { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold, ln->ln_hold = NULL; m_hold != NULL; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; /* * we assume ifp is not a p2p here, so * just set the 2nd argument as the * 1st one. */ nd6_output(ifp, ifp, m_hold, satocsin6(rt_key(rt)), rt); } } d1721 25 a1745 1 nd6_llinfo_release_pkts(ln, ifp, rt); @ 1.108 log @Use LIST_/TAILQ_ macros, esp. LIST_FOREACH() and TAILQ_FOREACH(). Use the usual idiom for iterating over a list where we might _REMOVE() entries, for (x = TAILQ_FIRST(...); x != NULL; x = nx) { nx = TAILQ_NEXT(x, ...); ... } @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.107 2006/11/16 01:33:45 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.107 2006/11/16 01:33:45 christos Exp $"); d366 1 a366 1 * to accomodate future extension to the protocol. @ 1.107 log @__unused removal on arguments; approved by core. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.106 2006/11/13 05:13:42 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.106 2006/11/13 05:13:42 dyoung Exp $"); d533 2 a534 2 struct nd_defrouter *dr; struct nd_prefix *pr; d543 3 a545 2 dr = TAILQ_FIRST(&nd_defrouter); while (dr) { a546 2 struct nd_defrouter *t; t = TAILQ_NEXT(dr, dr_entry); a547 3 dr = t; } else { dr = TAILQ_NEXT(dr, dr_entry); d624 2 a625 2 pr = nd_prefix.lh_first; while (pr) { a632 2 struct nd_prefix *t; t = pr->ndpr_next; d640 1 a640 3 pr = t; } else pr = pr->ndpr_next; d654 1 a654 2 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { d747 2 a748 2 for (pr = nd_prefix.lh_first; pr; pr = npr) { npr = pr->ndpr_next; d940 1 a940 1 for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { d1406 3 a1408 2 dr = TAILQ_FIRST(&nd_defrouter); while (dr && i < DRLSTSIZ) { a1416 1 dr = TAILQ_NEXT(dr, dr_entry); d1435 1 a1435 2 pr = nd_prefix.lh_first; while (pr && i < PRLSTSIZ) { d1439 2 a1464 1 pfr = pr->ndpr_advrtrs.lh_first; d1466 1 a1466 1 while (pfr) { a1473 1 pfr = pfr->pfr_next; a1478 1 pr = pr->ndpr_next; d1542 1 a1542 1 for (pfx = nd_prefix.lh_first; pfx; pfx = next) { d1545 1 a1545 1 next = pfx->ndpr_next; d1873 1 a1873 2 for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { d2262 1 a2262 2 for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = TAILQ_NEXT(dr, dr_entry)) { d2317 1 a2317 1 for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { d2361 1 a2361 2 for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = pfr->pfr_next) { d2383 1 a2383 2 for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = pfr->pfr_next) @ 1.106 log @Add a source-address selection policy mechanism to the kernel. Also, add ioctls SIOCGIFADDRPREF/SIOCSIFADDRPREF to get/set preference numbers for addresses. Make ifconfig(8) set/display preference numbers. To activate source-address selection policies in your kernel, add 'options IPSELSRC' to your kernel configuration. Miscellaneous changes in support of source-address selection: 1 Factor out some common code, producing rt_replace_ifa(). 2 Abbreviate a for-loop with TAILQ_FOREACH(). 3 Add the predicates on IPv4 addresses IN_LINKLOCAL() and IN_PRIVATE(), that are true for link-local unicast (169.254/16) and RFC1918 private addresses, respectively. Add the predicate IN_ANY_LOCAL() that is true for link-local unicast and multicast. 4 Add IPv4-specific interface attach/detach routines, in_domifattach and in_domifdetach, which build #ifdef IPSELSRC. See in_getifa(9) for a more thorough description of source-address selection policy. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.105 2006/10/12 01:32:39 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.105 2006/10/12 01:32:39 christos Exp $"); d530 1 a530 1 nd6_timer(void *ignored_arg __unused) d1148 1 a1148 1 nd6_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info __unused) d1633 1 a1633 1 int lladdrlen __unused, d1876 1 a1876 1 nd6_slowtimo(void *ignored_arg __unused) d2209 1 a2209 1 size_t newlen __unused @ 1.105 log @- sprinkle __unused on function decls. - fix a couple of unused bugs - no more -Wno-unused for i386 @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.104 2006/09/02 07:22:44 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.104 2006/09/02 07:22:44 christos Exp $"); d1330 2 a1331 5 if (ifa != rt->rt_ifa) { IFAFREE(rt->rt_ifa); IFAREF(ifa); rt->rt_ifa = ifa; } @ 1.104 log @- fix initializers - add const - remove dead code @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.103 2006/06/07 22:34:04 kardel Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.103 2006/06/07 22:34:04 kardel Exp $"); d530 1 a530 2 nd6_timer(ignored_arg) void *ignored_arg; d1148 1 a1148 4 nd6_rtrequest(req, rt, info) int req; struct rtentry *rt; struct rt_addrinfo *info; /* xxx unused */ d1632 8 a1639 7 nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code) struct ifnet *ifp; struct in6_addr *from; char *lladdr; int lladdrlen; int type; /* ICMP6 type */ int code; /* type dependent information */ d1879 1 a1879 2 nd6_slowtimo(ignored_arg) void *ignored_arg; d2207 7 a2213 6 nd6_sysctl(name, oldp, oldlenp, newp, newlen) int name; void *oldp; /* syscall arg, need copyout */ size_t *oldlenp; void *newp; /* syscall arg, need copyin */ size_t newlen; @ 1.104.2.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.107 2006/11/16 01:33:45 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.107 2006/11/16 01:33:45 christos Exp $"); d530 2 a531 1 nd6_timer(void *ignored_arg) d1149 4 a1152 1 nd6_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) d1334 5 a1338 2 if (ifa != rt->rt_ifa) rt_replace_ifa(rt, ifa); d1636 7 a1642 8 nd6_cache_lladdr( struct ifnet *ifp, struct in6_addr *from, char *lladdr, int lladdrlen, int type, /* ICMP6 type */ int code /* type dependent information */ ) d1882 2 a1883 1 nd6_slowtimo(void *ignored_arg) d2211 6 a2216 7 nd6_sysctl( int name, void *oldp, /* syscall arg, need copyout */ size_t *oldlenp, void *newp, /* syscall arg, need copyin */ size_t newlen ) @ 1.104.2.2 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.109 2006/11/24 19:47:00 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.109 2006/11/24 19:47:00 christos Exp $"); d366 1 a366 1 * to accommodate future extension to the protocol. d533 2 a534 2 struct nd_defrouter *next_dr, *dr; struct nd_prefix *next_pr, *pr; d543 2 a544 3 for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = next_dr) { next_dr = TAILQ_NEXT(dr, dr_entry); d546 2 d549 3 d628 2 a629 2 for (pr = LIST_FIRST(&nd_prefix); pr != NULL; pr = next_pr) { next_pr = LIST_NEXT(pr, ndpr_entry); d637 2 d646 3 a648 1 } d662 2 a663 1 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { d756 2 a757 2 for (pr = LIST_FIRST(&nd_prefix); pr != NULL; pr = npr) { npr = LIST_NEXT(pr, ndpr_entry); d949 1 a949 1 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { d1415 2 a1416 3 TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) { if (i >= DRLSTSIZ) break; d1425 1 d1444 2 a1445 1 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { a1448 2 if (i >= PRLSTSIZ) break; d1473 1 d1475 1 a1475 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { d1483 1 d1489 1 d1553 1 a1553 1 for (pfx = LIST_FIRST(&nd_prefix); pfx; pfx = next) { d1556 1 a1556 1 next = LIST_NEXT(pfx, ndpr_entry); d1884 2 a1885 1 TAILQ_FOREACH(ifp, &ifnet, if_list) { d2274 2 a2275 1 TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) { d2330 1 a2330 1 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { d2374 2 a2375 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { d2397 2 a2398 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) @ 1.104.4.1 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.104 2006/09/02 07:22:44 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.104 2006/09/02 07:22:44 christos Exp $"); d530 2 a531 1 nd6_timer(void *ignored_arg __unused) d1149 4 a1152 1 nd6_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info __unused) d1636 7 a1642 8 nd6_cache_lladdr( struct ifnet *ifp, struct in6_addr *from, char *lladdr, int lladdrlen __unused, int type, /* ICMP6 type */ int code /* type dependent information */ ) d1882 2 a1883 1 nd6_slowtimo(void *ignored_arg __unused) d2211 6 a2216 7 nd6_sysctl( int name, void *oldp, /* syscall arg, need copyout */ size_t *oldlenp, void *newp, /* syscall arg, need copyin */ size_t newlen __unused ) @ 1.104.4.2 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.104.4.1 2006/10/22 06:07:35 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.104.4.1 2006/10/22 06:07:35 yamt Exp $"); d366 1 a366 1 * to accommodate future extension to the protocol. d530 1 a530 1 nd6_timer(void *ignored_arg) d533 2 a534 2 struct nd_defrouter *next_dr, *dr; struct nd_prefix *next_pr, *pr; d543 2 a544 3 for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = next_dr) { next_dr = TAILQ_NEXT(dr, dr_entry); d546 2 d549 3 d628 2 a629 2 for (pr = LIST_FIRST(&nd_prefix); pr != NULL; pr = next_pr) { next_pr = LIST_NEXT(pr, ndpr_entry); d637 2 d646 3 a648 1 } d662 2 a663 1 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { d756 2 a757 2 for (pr = LIST_FIRST(&nd_prefix); pr != NULL; pr = npr) { npr = LIST_NEXT(pr, ndpr_entry); d949 1 a949 1 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { d1148 1 a1148 1 nd6_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) d1330 5 a1334 2 if (ifa != rt->rt_ifa) rt_replace_ifa(rt, ifa); d1418 2 a1419 3 TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) { if (i >= DRLSTSIZ) break; d1428 1 d1447 2 a1448 1 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { a1451 2 if (i >= PRLSTSIZ) break; d1476 1 d1478 1 a1478 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { d1486 1 d1492 1 d1556 1 a1556 1 for (pfx = LIST_FIRST(&nd_prefix); pfx; pfx = next) { d1559 1 a1559 1 next = LIST_NEXT(pfx, ndpr_entry); d1636 1 a1636 1 int lladdrlen, d1879 1 a1879 1 nd6_slowtimo(void *ignored_arg) d1887 2 a1888 1 TAILQ_FOREACH(ifp, &ifnet, if_list) { d2212 1 a2212 1 size_t newlen d2277 2 a2278 1 TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) { d2333 1 a2333 1 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { d2377 2 a2378 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { d2400 2 a2401 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) @ 1.103 log @merge FreeBSD timecounters from branch simonb-timecounters - struct timeval time is gone time.tv_sec -> time_second - struct timeval mono_time is gone mono_time.tv_sec -> time_uptime - access to time via {get,}{micro,nano,bin}time() get* versions are fast but less precise - support NTP nanokernel implementation (NTP API 4) - further reading: Timecounter Paper: http://phk.freebsd.dk/pubs/timecounter.pdf NTP Nanokernel: http://www.eecis.udel.edu/~mills/ntp/html/kern.html @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.102 2006/05/18 09:05:51 liamjfoy Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.102 2006/05/18 09:05:51 liamjfoy Exp $"); d105 4 a108 1 struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6}; d1156 4 a1159 1 static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; d1216 1 a1216 1 (struct sockaddr *)&null_sdl); d1384 1 a1384 2 } else ; /* XXX: should not happen. bark here? */ @ 1.102 log @Integrate Common Address Redundancy Procotol (CARP) from OpenBSD 'pseudo-device carp' Thanks to: joerg@@ christos@@ riz@@ and others who tested Ok: core@@ @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.101 2006/04/15 00:09:29 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.101 2006/04/15 00:09:29 christos Exp $"); d402 1 a402 1 ln->ln_expire = time.tv_sec + xtick / hz; d543 1 a543 1 if (dr->expire && dr->expire < time.tv_sec) { d634 1 a634 1 time.tv_sec - pr->ndpr_lastupdate > pr->ndpr_vltime) { d1023 1 a1023 1 if (dr->expire > time.tv_sec) d1025 1 a1025 1 (dr->expire - time.tv_sec) * hz); @ 1.102.2.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.103 2006/06/07 22:34:04 kardel Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.103 2006/06/07 22:34:04 kardel Exp $"); d402 1 a402 1 ln->ln_expire = time_second + xtick / hz; d543 1 a543 1 if (dr->expire && dr->expire < time_second) { d634 1 a634 1 time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) { d1023 1 a1023 1 if (dr->expire > time_second) d1025 1 a1025 1 (dr->expire - time_second) * hz); @ 1.101 log @Coverity CID 857: Prevent NULL deref. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.100 2006/03/24 19:24:38 rpaulo Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.100 2006/03/24 19:24:38 rpaulo Exp $"); d2127 1 @ 1.100 log @From KAME via SUZUKI Shinsuke: fixed a memory leak when net.inet6.icmp6.nd6_maxqueuelen is greater than 1. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.99 2006/03/05 23:47:08 rpaulo Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.99 2006/03/05 23:47:08 rpaulo Exp $"); a2299 1 *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ d2302 3 a2304 2 } else *oldlenp = l; @ 1.99 log @NDP-related improvements: RFC4191 - supports host-side router-preference RFC3542 - if DAD fails on a interface, disables IPv6 operation on the interface - don't advertise MLD report before DAD finishes Others - fixes integer overflow for valid and preferred lifetimes - improves timer granularity for MLD, using callout-timer. - reflects rtadvd's IPv6 host variable information into kernel (router only) - adds a sysctl option to enable/disable pMTUd for multicast packets - performs NUD on PPP/GRE interface by default - Redirect works regardless of ip6_accept_rtadv - removes RFC1885-related code From the KAME project via SUZUKI Shinsuke. Reviewed by core. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.98 2006/03/03 14:07:06 rpaulo Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.98 2006/03/03 14:07:06 rpaulo Exp $"); d117 1 d461 2 d467 2 a468 1 ln->ln_hold = NULL; d471 4 a474 1 } d1388 1 a1388 2 if (ln->ln_hold) m_freem(ln->ln_hold); d2068 1 a2068 1 m_free(m_hold); d2188 16 @ 1.99.2.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.101 2006/04/15 00:09:29 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.101 2006/04/15 00:09:29 christos Exp $"); a116 1 static void clear_llinfo_pqueue __P((struct llinfo_nd6 *)); a459 2 struct mbuf *m0; d464 1 a464 2 m0 = m->m_nextpkt; m->m_nextpkt = NULL; d467 1 a467 4 ln->ln_hold = m0; clear_llinfo_pqueue(ln); } d1381 2 a1382 1 clear_llinfo_pqueue(ln); d2062 1 a2062 1 m_freem(m_hold); a2181 16 static void clear_llinfo_pqueue(ln) struct llinfo_nd6 *ln; { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; m_freem(m_hold); } ln->ln_hold = NULL; return; } d2278 1 d2281 2 a2282 3 } if (oldlenp) *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ @ 1.99.4.1 log @Merge 2006-03-28 NetBSD-current into the "peter-altq" branch. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.100 2006/03/24 19:24:38 rpaulo Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.100 2006/03/24 19:24:38 rpaulo Exp $"); a116 1 static void clear_llinfo_pqueue __P((struct llinfo_nd6 *)); a459 2 struct mbuf *m0; d464 1 a464 2 m0 = m->m_nextpkt; m->m_nextpkt = NULL; d467 1 a467 4 ln->ln_hold = m0; clear_llinfo_pqueue(ln); } d1381 2 a1382 1 clear_llinfo_pqueue(ln); d2062 1 a2062 1 m_freem(m_hold); a2181 16 static void clear_llinfo_pqueue(ln) struct llinfo_nd6 *ln; { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; m_freem(m_hold); } ln->ln_hold = NULL; return; } @ 1.99.4.2 log @Merge 2006-05-24 NetBSD-current into the "peter-altq" branch. @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); a2126 1 case IFT_CARP: d2300 1 d2303 2 a2304 3 } if (oldlenp) *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ @ 1.98 log @Fix typos in comments. From: the KAME project via SUZUKI Shinsuke. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.97 2006/03/02 05:11:31 dyoung Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.97 2006/03/02 05:11:31 dyoung Exp $"); d94 2 d114 1 d120 1 d262 1 a262 1 if (!ndopts) d264 1 a264 1 if (!ndopts->nd_opts_last) d266 1 a266 1 if (!ndopts->nd_opts_search) d314 1 a314 1 if (!ndopts) d316 1 a316 1 if (!ndopts->nd_opts_last) d318 1 a318 1 if (!ndopts->nd_opts_search) d320 1 a320 1 d323 1 a323 1 if (!nd_opt && !ndopts->nd_opts_last) { d333 1 a333 1 if (!nd_opt) d527 1 d552 1 d556 1 d558 51 a608 4 in6_purgeaddr(&ia6->ia_ifa); } if (IFA6_IS_DEPRECATED(ia6)) { ia6->ia6_flags |= IN6_IFF_DEPRECATED; d644 67 d824 1 a824 1 rt = 0; d827 1 a827 1 if (!rt) { d883 4 d1102 2 a1103 2 if (!rt) { if (!dst6) d1105 1 a1105 1 if (!(rt = nd6_lookup(dst6, 0, NULL))) d1264 1 a1264 1 if (!ln) { d1270 1 a1270 1 Bzero(ln, sizeof(*ln)); d1308 1 a1308 1 Bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); d1344 1 a1344 1 if (!in6_addmulti(&llsol, ifp, &error)) { d1354 1 a1354 1 if (!ln) d1451 17 a1467 1 oprl->prefix[i].expire = pr->ndpr_expire; d1491 1 d1493 9 a1501 9 bzero(&ndi->ndi, sizeof(ndi->ndi)); ndi->ndi.linkmtu = IN6_LINKMTU(ifp); ndi->ndi.maxmtu = ND_IFINFO(ifp)->maxmtu; ndi->ndi.basereachable = ND_IFINFO(ifp)->basereachable; ndi->ndi.reachable = ND_IFINFO(ifp)->reachable; ndi->ndi.retrans = ND_IFINFO(ifp)->retrans; ndi->ndi.flags = ND_IFINFO(ifp)->flags; ndi->ndi.recalctm = ND_IFINFO(ifp)->recalctm; ndi->ndi.chlim = ND_IFINFO(ifp)->chlim; d1504 1 a1504 1 ndi->ndi = *ND_IFINFO(ifp); d1506 28 d1535 1 a1535 1 ND_IFINFO(ifp)->flags = ndi->ndi.flags; d1537 1 d1589 1 a1589 1 { d1642 1 a1642 1 if (!ifp) d1644 1 a1644 1 if (!from) d1662 1 a1662 1 if (!rt) { d1678 1 a1678 1 if (!rt) d1686 1 a1686 1 if (!ln) d1688 1 a1688 1 if (!rt->rt_gateway) d1732 1 a1732 1 if (!lladdr) /* (6) */ d1753 25 a1777 9 if (ln->ln_hold) { /* * we assume ifp is not a p2p here, so just * set the 2nd argument as the 1st one. */ nd6_output(ifp, ifp, ln->ln_hold, (struct sockaddr_in6 *)rt_key(rt), rt); ln->ln_hold = NULL; } d1997 1 a1997 1 if (!ln || !rt) { d2027 1 a2027 1 nd6_llinfo_settimer(ln, nd6_delay * hz); d2040 4 a2043 2 * response yet. Replace the held mbuf (if any) with this * latest one. d2047 22 a2068 3 if (ln->ln_hold) m_freem(ln->ln_hold); ln->ln_hold = m; d2082 5 d2122 2 d2204 1 a2204 1 if (!p) d2211 1 a2211 1 if (!error && p && oldp) d2217 1 a2217 1 if (!error && p && oldp) d2221 3 d2339 2 a2340 1 ~(1 << ((sizeof(maxexpire) * 8) - 1)); @ 1.98.2.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.98 2006/03/03 14:07:06 rpaulo Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.98 2006/03/03 14:07:06 rpaulo Exp $"); a93 2 int nd6_maxqueuelen = 1; /* max # of packets cached in unresolved ND entries */ a111 1 static int regen_tmpaddr __P((struct in6_ifaddr *)); a116 1 extern struct callout in6_tmpaddrtimer_ch; d258 1 a258 1 if (ndopts == NULL) d260 1 a260 1 if (ndopts->nd_opts_last == NULL) d262 1 a262 1 if (ndopts->nd_opts_search == NULL) d310 1 a310 1 if (ndopts == NULL) d312 1 a312 1 if (ndopts->nd_opts_last == NULL) d314 1 a314 1 if (ndopts->nd_opts_search == NULL) d316 1 a316 1 d319 1 a319 1 if (nd_opt == NULL && ndopts->nd_opts_last == NULL) { d329 1 a329 1 if (nd_opt == NULL) a522 1 struct in6_addrlifetime *lt6; a546 1 addrloop: a549 1 lt6 = &ia6->ia6_lifetime; d551 4 a554 51 int regen = 0; /* * If the expiring address is temporary, try * regenerating a new one. This would be useful when * we suspended a laptop PC, then turned it on after a * period that could invalidate all temporary * addresses. Although we may have to restart the * loop (see below), it must be after purging the * address. Otherwise, we'd see an infinite loop of * regeneration. */ if (ip6_use_tempaddr && (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { if (regen_tmpaddr(ia6) == 0) regen = 1; } in6_purgeaddr(&ia6->ia_ifa); if (regen) goto addrloop; /* XXX: see below */ } else if (IFA6_IS_DEPRECATED(ia6)) { int oldflags = ia6->ia6_flags; ia6->ia6_flags |= IN6_IFF_DEPRECATED; /* * If a temporary address has just become deprecated, * regenerate a new one if possible. */ if (ip6_use_tempaddr && (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && (oldflags & IN6_IFF_DEPRECATED) == 0) { if (regen_tmpaddr(ia6) == 0) { /* * A new temporary address is * generated. * XXX: this means the address chain * has changed while we are still in * the loop. Although the change * would not cause disaster (because * it's not a deletion, but an * addition,) we'd rather restart the * loop just for safety. Or does this * significantly reduce performance?? */ goto addrloop; } } a589 67 static int regen_tmpaddr(ia6) struct in6_ifaddr *ia6; /* deprecated/invalidated temporary address */ { struct ifaddr *ifa; struct ifnet *ifp; struct in6_ifaddr *public_ifa6 = NULL; ifp = ia6->ia_ifa.ifa_ifp; for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { struct in6_ifaddr *it6; if (ifa->ifa_addr->sa_family != AF_INET6) continue; it6 = (struct in6_ifaddr *)ifa; /* ignore no autoconf addresses. */ if ((it6->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; /* ignore autoconf addresses with different prefixes. */ if (it6->ia6_ndpr == NULL || it6->ia6_ndpr != ia6->ia6_ndpr) continue; /* * Now we are looking at an autoconf address with the same * prefix as ours. If the address is temporary and is still * preferred, do not create another one. It would be rare, but * could happen, for example, when we resume a laptop PC after * a long period. */ if ((it6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && !IFA6_IS_DEPRECATED(it6)) { public_ifa6 = NULL; break; } /* * This is a public autoconf address that has the same prefix * as ours. If it is preferred, keep it. We can't break the * loop here, because there may be a still-preferred temporary * address with the prefix. */ if (!IFA6_IS_DEPRECATED(it6)) public_ifa6 = it6; } if (public_ifa6 != NULL) { int e; /* * Random factor is introduced in the preferred lifetime, so * we do not need additional delay (3rd arg to in6_tmpifadd). */ if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) { log(LOG_NOTICE, "regen_tmpaddr: failed to create a new" " tmp addr, errno=%d\n", e); return (-1); } return (0); } return (-1); } d703 1 a703 1 rt = NULL; d706 1 a706 1 if (rt == NULL) { a761 4 * Note also that ifa_ifp and ifp may differ when we connect two * interfaces to a same link, install a link prefix to an interface, * and try to install a neighbor cache on an interface that does not * have a route to the prefix. d977 2 a978 2 if (rt == NULL) { if (dst6 == NULL) d980 1 a980 1 if ((rt = nd6_lookup(dst6, 0, NULL)) == NULL) d1139 1 a1139 1 if (ln == NULL) { d1145 1 a1145 1 bzero(ln, sizeof(*ln)); d1183 1 a1183 1 bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); d1219 1 a1219 1 if (!in6_addmulti(&llsol, ifp, &error, 0)) { d1229 1 a1229 1 if (ln == NULL) d1326 1 a1326 17 if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) oprl->prefix[i].expire = 0; else { time_t maxexpire; /* XXX: we assume time_t is signed. */ maxexpire = (-1) & ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); if (pr->ndpr_vltime < maxexpire - pr->ndpr_lastupdate) { oprl->prefix[i].expire = pr->ndpr_lastupdate + pr->ndpr_vltime; } else oprl->prefix[i].expire = maxexpire; } a1349 1 #define ND ndi->ndi d1351 9 a1359 9 memset(&ND, 0, sizeof(ND)); ND.linkmtu = IN6_LINKMTU(ifp); ND.maxmtu = ND_IFINFO(ifp)->maxmtu; ND.basereachable = ND_IFINFO(ifp)->basereachable; ND.reachable = ND_IFINFO(ifp)->reachable; ND.retrans = ND_IFINFO(ifp)->retrans; ND.flags = ND_IFINFO(ifp)->flags; ND.recalctm = ND_IFINFO(ifp)->recalctm; ND.chlim = ND_IFINFO(ifp)->chlim; d1362 1 a1362 1 ND = *ND_IFINFO(ifp); a1363 28 case SIOCSIFINFO_IN6: /* * used to change host variables from userland. * intented for a use on router to reflect RA configurations. */ /* 0 means 'unspecified' */ if (ND.linkmtu != 0) { if (ND.linkmtu < IPV6_MMTU || ND.linkmtu > IN6_LINKMTU(ifp)) { error = EINVAL; break; } ND_IFINFO(ifp)->linkmtu = ND.linkmtu; } if (ND.basereachable != 0) { int obasereachable = ND_IFINFO(ifp)->basereachable; ND_IFINFO(ifp)->basereachable = ND.basereachable; if (ND.basereachable != obasereachable) ND_IFINFO(ifp)->reachable = ND_COMPUTE_RTIME(ND.basereachable); } if (ND.retrans != 0) ND_IFINFO(ifp)->retrans = ND.retrans; if (ND.chlim != 0) ND_IFINFO(ifp)->chlim = ND.chlim; /* FALLTHROUGH */ d1365 1 a1365 1 ND_IFINFO(ifp)->flags = ND.flags; a1366 1 #undef ND d1418 1 a1418 1 { d1471 1 a1471 1 if (ifp == NULL) d1473 1 a1473 1 if (from == NULL) d1491 1 a1491 1 if (rt == NULL) { d1507 1 a1507 1 if (rt == NULL) d1515 1 a1515 1 if (ln == NULL) d1517 1 a1517 1 if (rt->rt_gateway == NULL) d1561 1 a1561 1 if (lladdr == NULL) /* (6) */ d1582 9 a1590 25 if (ln->ln_hold) { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { struct mbuf *mpkt = NULL; m_hold_next = m_hold->m_nextpkt; mpkt = m_copym(m_hold, 0, M_COPYALL, M_DONTWAIT); if (mpkt == NULL) { m_freem(m_hold); break; } mpkt->m_nextpkt = NULL; /* * we assume ifp is not a p2p here, so * just set the 2nd argument as the * 1st one. */ nd6_output(ifp, ifp, mpkt, (struct sockaddr_in6 *)rt_key(rt), rt); } ln->ln_hold = NULL; } d1810 1 a1810 1 if (ln == NULL || rt == NULL) { d1840 1 a1840 1 nd6_llinfo_settimer(ln, (long)nd6_delay * hz); d1853 2 a1854 4 * response yet. Append this latest packet to the end of the * packet queue in the mbuf, unless the number of the packet * does not exceed nd6_maxqueuelen. When it exceeds nd6_maxqueuelen, * the oldest packet in the queue will be removed. d1858 3 a1860 22 if (ln->ln_hold) { struct mbuf *m_hold; int i; i = 0; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold->m_nextpkt) { i++; if (m_hold->m_nextpkt == NULL) { m_hold->m_nextpkt = m; break; } } while (i >= nd6_maxqueuelen) { m_hold = ln->ln_hold; ln->ln_hold = ln->ln_hold->m_nextpkt; m_free(m_hold); i--; } } else { ln->ln_hold = m; } a1873 5 /* discard the packet if IPv6 operation is disabled on the interface */ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { error = ENETDOWN; /* better error? */ goto bad; } a1908 2 case IFT_PPP: case IFT_TUNNEL: d1989 1 a1989 1 if (p == NULL) d1996 1 a1996 1 if (!error && p != NULL && oldp != NULL) d2002 1 a2002 1 if (!error && p != NULL && oldp != NULL) a2005 3 case ICMPV6CTL_ND6_MAXQLEN: break; d2121 1 a2121 2 ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); @ 1.98.2.2 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.98.2.1 2006/03/13 09:07:39 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.98.2.1 2006/03/13 09:07:39 yamt Exp $"); a116 1 static void clear_llinfo_pqueue __P((struct llinfo_nd6 *)); a459 2 struct mbuf *m0; d464 1 a464 2 m0 = m->m_nextpkt; m->m_nextpkt = NULL; d467 1 a467 4 ln->ln_hold = m0; clear_llinfo_pqueue(ln); } d1381 2 a1382 1 clear_llinfo_pqueue(ln); d2062 1 a2062 1 m_freem(m_hold); a2181 16 static void clear_llinfo_pqueue(ln) struct llinfo_nd6 *ln; { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; m_freem(m_hold); } ln->ln_hold = NULL; return; } @ 1.98.2.3 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.98.2.2 2006/04/01 12:07:50 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.98.2.2 2006/04/01 12:07:50 yamt Exp $"); a2126 1 case IFT_CARP: d2300 1 d2303 2 a2304 3 } if (oldlenp) *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ @ 1.98.2.4 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.98.2.3 2006/05/24 10:59:09 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.98.2.3 2006/05/24 10:59:09 yamt Exp $"); d402 1 a402 1 ln->ln_expire = time_second + xtick / hz; d543 1 a543 1 if (dr->expire && dr->expire < time_second) { d634 1 a634 1 time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) { d1023 1 a1023 1 if (dr->expire > time_second) d1025 1 a1025 1 (dr->expire - time_second) * hz); @ 1.98.2.5 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.98.2.4 2006/06/26 12:54:13 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.98.2.4 2006/06/26 12:54:13 yamt Exp $"); d105 1 a105 4 struct llinfo_nd6 llinfo_nd6 = { .ln_prev = &llinfo_nd6, .ln_next = &llinfo_nd6, }; d1153 1 a1153 4 static const struct sockaddr_dl null_sdl = { .sdl_len = sizeof(null_sdl), .sdl_family = AF_LINK, }; d1210 1 a1210 1 (const struct sockaddr *)&null_sdl); d1378 2 a1379 1 } @ 1.97 log @In nd6_llinfo_timer, don't duplicate part of nd6_llinfo_settimer's logic, and then call nd6_llinfo_settimer. Instead, call nd6_llinfo_settimer immediately. This should cause no functional change. I've been running this patch for months. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.96 2006/01/21 00:15:36 rpaulo Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.96 2006/01/21 00:15:36 rpaulo Exp $"); d963 1 a963 1 * XXX cost-effective metods? d1733 1 a1733 1 * next hop determination. This routine is derived from ether_outpout. @ 1.96 log @Better support of IPv6 scoped addresses. - most of the kernel code will not care about the actual encoding of scope zone IDs and won't touch "s6_addr16[1]" directly. - similarly, most of the kernel code will not care about link-local scoped addresses as a special case. - scope boundary check will be stricter. For example, the current *BSD code allows a packet with src=::1 and dst=(some global IPv6 address) to be sent outside of the node, if the application do: s = socket(AF_INET6); bind(s, "::1"); sendto(s, some_global_IPv6_addr); This is clearly wrong, since ::1 is only meaningful within a single node, but the current implementation of the *BSD kernel cannot reject this attempt. - and, while there, don't try to remove the ff02::/32 interface route entry in in6_ifdetach() as it's already gone. This also includes some level of support for the standard source address selection algorithm defined in RFC3484, which will be completed on in the future. From the KAME project via JINMEI Tatuya. Approved by core@@. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.95 2005/12/11 12:25:02 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.95 2005/12/11 12:25:02 christos Exp $"); d428 1 a428 7 if (ln->ln_ntick > INT_MAX) { ln->ln_ntick -= INT_MAX; nd6_llinfo_settimer(ln, INT_MAX); } else { ln->ln_ntick = 0; nd6_llinfo_settimer(ln, ln->ln_ntick); } @ 1.96.2.1 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.104 2006/09/02 07:22:44 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.104 2006/09/02 07:22:44 christos Exp $"); a93 2 int nd6_maxqueuelen = 1; /* max # of packets cached in unresolved ND entries */ d103 1 a103 4 struct llinfo_nd6 llinfo_nd6 = { .ln_prev = &llinfo_nd6, .ln_next = &llinfo_nd6, }; a111 1 static int regen_tmpaddr __P((struct in6_ifaddr *)); a113 1 static void clear_llinfo_pqueue __P((struct llinfo_nd6 *)); a116 1 extern struct callout in6_tmpaddrtimer_ch; d258 1 a258 1 if (ndopts == NULL) d260 1 a260 1 if (ndopts->nd_opts_last == NULL) d262 1 a262 1 if (ndopts->nd_opts_search == NULL) d310 1 a310 1 if (ndopts == NULL) d312 1 a312 1 if (ndopts->nd_opts_last == NULL) d314 1 a314 1 if (ndopts->nd_opts_search == NULL) d316 1 a316 1 d319 1 a319 1 if (nd_opt == NULL && ndopts->nd_opts_last == NULL) { d329 1 a329 1 if (nd_opt == NULL) d397 1 a397 1 ln->ln_expire = time_second + xtick / hz; d428 7 a434 1 nd6_llinfo_settimer(ln, ln->ln_ntick); a461 2 struct mbuf *m0; d466 1 a466 2 m0 = m->m_nextpkt; m->m_nextpkt = NULL; d469 1 a469 4 ln->ln_hold = m0; clear_llinfo_pqueue(ln); } a528 1 struct in6_addrlifetime *lt6; d537 1 a537 1 if (dr->expire && dr->expire < time_second) { a552 1 addrloop: a555 1 lt6 = &ia6->ia6_lifetime; d557 4 a560 51 int regen = 0; /* * If the expiring address is temporary, try * regenerating a new one. This would be useful when * we suspended a laptop PC, then turned it on after a * period that could invalidate all temporary * addresses. Although we may have to restart the * loop (see below), it must be after purging the * address. Otherwise, we'd see an infinite loop of * regeneration. */ if (ip6_use_tempaddr && (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { if (regen_tmpaddr(ia6) == 0) regen = 1; } in6_purgeaddr(&ia6->ia_ifa); if (regen) goto addrloop; /* XXX: see below */ } else if (IFA6_IS_DEPRECATED(ia6)) { int oldflags = ia6->ia6_flags; ia6->ia6_flags |= IN6_IFF_DEPRECATED; /* * If a temporary address has just become deprecated, * regenerate a new one if possible. */ if (ip6_use_tempaddr && (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && (oldflags & IN6_IFF_DEPRECATED) == 0) { if (regen_tmpaddr(ia6) == 0) { /* * A new temporary address is * generated. * XXX: this means the address chain * has changed while we are still in * the loop. Although the change * would not cause disaster (because * it's not a deletion, but an * addition,) we'd rather restart the * loop just for safety. Or does this * significantly reduce performance?? */ goto addrloop; } } d579 1 a579 1 time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) { a595 67 static int regen_tmpaddr(ia6) struct in6_ifaddr *ia6; /* deprecated/invalidated temporary address */ { struct ifaddr *ifa; struct ifnet *ifp; struct in6_ifaddr *public_ifa6 = NULL; ifp = ia6->ia_ifa.ifa_ifp; for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { struct in6_ifaddr *it6; if (ifa->ifa_addr->sa_family != AF_INET6) continue; it6 = (struct in6_ifaddr *)ifa; /* ignore no autoconf addresses. */ if ((it6->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; /* ignore autoconf addresses with different prefixes. */ if (it6->ia6_ndpr == NULL || it6->ia6_ndpr != ia6->ia6_ndpr) continue; /* * Now we are looking at an autoconf address with the same * prefix as ours. If the address is temporary and is still * preferred, do not create another one. It would be rare, but * could happen, for example, when we resume a laptop PC after * a long period. */ if ((it6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && !IFA6_IS_DEPRECATED(it6)) { public_ifa6 = NULL; break; } /* * This is a public autoconf address that has the same prefix * as ours. If it is preferred, keep it. We can't break the * loop here, because there may be a still-preferred temporary * address with the prefix. */ if (!IFA6_IS_DEPRECATED(it6)) public_ifa6 = it6; } if (public_ifa6 != NULL) { int e; /* * Random factor is introduced in the preferred lifetime, so * we do not need additional delay (3rd arg to in6_tmpifadd). */ if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) { log(LOG_NOTICE, "regen_tmpaddr: failed to create a new" " tmp addr, errno=%d\n", e); return (-1); } return (0); } return (-1); } d709 1 a709 1 rt = NULL; d712 1 a712 1 if (rt == NULL) { a767 4 * Note also that ifa_ifp and ifp may differ when we connect two * interfaces to a same link, install a link prefix to an interface, * and try to install a neighbor cache on an interface that does not * have a route to the prefix. d897 1 a897 1 if (dr->expire > time_second) d899 1 a899 1 (dr->expire - time_second) * hz); d969 1 a969 1 * XXX cost-effective methods? d983 2 a984 2 if (rt == NULL) { if (dst6 == NULL) d986 1 a986 1 if ((rt = nd6_lookup(dst6, 0, NULL)) == NULL) d1027 1 a1027 4 static const struct sockaddr_dl null_sdl = { .sdl_len = sizeof(null_sdl), .sdl_family = AF_LINK, }; d1084 1 a1084 1 (const struct sockaddr *)&null_sdl); d1145 1 a1145 1 if (ln == NULL) { d1151 1 a1151 1 bzero(ln, sizeof(*ln)); d1189 1 a1189 1 bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); d1225 1 a1225 1 if (!in6_addmulti(&llsol, ifp, &error, 0)) { d1235 1 a1235 1 if (ln == NULL) d1252 2 a1253 1 } d1262 2 a1263 1 clear_llinfo_pqueue(ln); d1332 1 a1332 17 if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) oprl->prefix[i].expire = 0; else { time_t maxexpire; /* XXX: we assume time_t is signed. */ maxexpire = (-1) & ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); if (pr->ndpr_vltime < maxexpire - pr->ndpr_lastupdate) { oprl->prefix[i].expire = pr->ndpr_lastupdate + pr->ndpr_vltime; } else oprl->prefix[i].expire = maxexpire; } a1355 1 #define ND ndi->ndi d1357 9 a1365 9 memset(&ND, 0, sizeof(ND)); ND.linkmtu = IN6_LINKMTU(ifp); ND.maxmtu = ND_IFINFO(ifp)->maxmtu; ND.basereachable = ND_IFINFO(ifp)->basereachable; ND.reachable = ND_IFINFO(ifp)->reachable; ND.retrans = ND_IFINFO(ifp)->retrans; ND.flags = ND_IFINFO(ifp)->flags; ND.recalctm = ND_IFINFO(ifp)->recalctm; ND.chlim = ND_IFINFO(ifp)->chlim; d1368 1 a1368 1 ND = *ND_IFINFO(ifp); a1369 28 case SIOCSIFINFO_IN6: /* * used to change host variables from userland. * intented for a use on router to reflect RA configurations. */ /* 0 means 'unspecified' */ if (ND.linkmtu != 0) { if (ND.linkmtu < IPV6_MMTU || ND.linkmtu > IN6_LINKMTU(ifp)) { error = EINVAL; break; } ND_IFINFO(ifp)->linkmtu = ND.linkmtu; } if (ND.basereachable != 0) { int obasereachable = ND_IFINFO(ifp)->basereachable; ND_IFINFO(ifp)->basereachable = ND.basereachable; if (ND.basereachable != obasereachable) ND_IFINFO(ifp)->reachable = ND_COMPUTE_RTIME(ND.basereachable); } if (ND.retrans != 0) ND_IFINFO(ifp)->retrans = ND.retrans; if (ND.chlim != 0) ND_IFINFO(ifp)->chlim = ND.chlim; /* FALLTHROUGH */ d1371 1 a1371 1 ND_IFINFO(ifp)->flags = ND.flags; a1372 1 #undef ND d1424 1 a1424 1 { d1477 1 a1477 1 if (ifp == NULL) d1479 1 a1479 1 if (from == NULL) d1497 1 a1497 1 if (rt == NULL) { d1513 1 a1513 1 if (rt == NULL) d1521 1 a1521 1 if (ln == NULL) d1523 1 a1523 1 if (rt->rt_gateway == NULL) d1567 1 a1567 1 if (lladdr == NULL) /* (6) */ d1588 9 a1596 25 if (ln->ln_hold) { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { struct mbuf *mpkt = NULL; m_hold_next = m_hold->m_nextpkt; mpkt = m_copym(m_hold, 0, M_COPYALL, M_DONTWAIT); if (mpkt == NULL) { m_freem(m_hold); break; } mpkt->m_nextpkt = NULL; /* * we assume ifp is not a p2p here, so * just set the 2nd argument as the * 1st one. */ nd6_output(ifp, ifp, mpkt, (struct sockaddr_in6 *)rt_key(rt), rt); } ln->ln_hold = NULL; } d1739 1 a1739 1 * next hop determination. This routine is derived from ether_output. d1816 1 a1816 1 if (ln == NULL || rt == NULL) { d1846 1 a1846 1 nd6_llinfo_settimer(ln, (long)nd6_delay * hz); d1859 2 a1860 4 * response yet. Append this latest packet to the end of the * packet queue in the mbuf, unless the number of the packet * does not exceed nd6_maxqueuelen. When it exceeds nd6_maxqueuelen, * the oldest packet in the queue will be removed. d1864 3 a1866 22 if (ln->ln_hold) { struct mbuf *m_hold; int i; i = 0; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold->m_nextpkt) { i++; if (m_hold->m_nextpkt == NULL) { m_hold->m_nextpkt = m; break; } } while (i >= nd6_maxqueuelen) { m_hold = ln->ln_hold; ln->ln_hold = ln->ln_hold->m_nextpkt; m_freem(m_hold); i--; } } else { ln->ln_hold = m; } a1879 5 /* discard the packet if IPv6 operation is disabled on the interface */ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { error = ENETDOWN; /* better error? */ goto bad; } a1913 1 case IFT_CARP: a1914 2 case IFT_PPP: case IFT_TUNNEL: a1972 16 static void clear_llinfo_pqueue(ln) struct llinfo_nd6 *ln; { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; m_freem(m_hold); } ln->ln_hold = NULL; return; } d1995 1 a1995 1 if (p == NULL) d2002 1 a2002 1 if (!error && p != NULL && oldp != NULL) d2008 1 a2008 1 if (!error && p != NULL && oldp != NULL) a2011 3 case ICMPV6CTL_ND6_MAXQLEN: break; d2066 1 d2069 2 a2070 3 } if (oldlenp) *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ d2127 1 a2127 2 ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); @ 1.96.4.1 log @Adapt for timecounters: mostly use get*time(), use bintime's for timeout calculations and use "time_second" instead of "time.tv_sec". @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.96 2006/01/21 00:15:36 rpaulo Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.96 2006/01/21 00:15:36 rpaulo Exp $"); d397 1 a397 1 ln->ln_expire = time_second + xtick / hz; d537 1 a537 1 if (dr->expire && dr->expire < time_second) { d579 1 a579 1 time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) { d897 1 a897 1 if (dr->expire > time_second) d899 1 a899 1 (dr->expire - time_second) * hz); @ 1.96.4.2 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.101 2006/04/15 00:09:29 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.101 2006/04/15 00:09:29 christos Exp $"); a93 2 int nd6_maxqueuelen = 1; /* max # of packets cached in unresolved ND entries */ a111 1 static int regen_tmpaddr __P((struct in6_ifaddr *)); a113 1 static void clear_llinfo_pqueue __P((struct llinfo_nd6 *)); a116 1 extern struct callout in6_tmpaddrtimer_ch; d258 1 a258 1 if (ndopts == NULL) d260 1 a260 1 if (ndopts->nd_opts_last == NULL) d262 1 a262 1 if (ndopts->nd_opts_search == NULL) d310 1 a310 1 if (ndopts == NULL) d312 1 a312 1 if (ndopts->nd_opts_last == NULL) d314 1 a314 1 if (ndopts->nd_opts_search == NULL) d316 1 a316 1 d319 1 a319 1 if (nd_opt == NULL && ndopts->nd_opts_last == NULL) { d329 1 a329 1 if (nd_opt == NULL) d428 7 a434 1 nd6_llinfo_settimer(ln, ln->ln_ntick); a461 2 struct mbuf *m0; d466 1 a466 2 m0 = m->m_nextpkt; m->m_nextpkt = NULL; d469 1 a469 4 ln->ln_hold = m0; clear_llinfo_pqueue(ln); } a528 1 struct in6_addrlifetime *lt6; a552 1 addrloop: a555 1 lt6 = &ia6->ia6_lifetime; d557 4 a560 51 int regen = 0; /* * If the expiring address is temporary, try * regenerating a new one. This would be useful when * we suspended a laptop PC, then turned it on after a * period that could invalidate all temporary * addresses. Although we may have to restart the * loop (see below), it must be after purging the * address. Otherwise, we'd see an infinite loop of * regeneration. */ if (ip6_use_tempaddr && (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { if (regen_tmpaddr(ia6) == 0) regen = 1; } in6_purgeaddr(&ia6->ia_ifa); if (regen) goto addrloop; /* XXX: see below */ } else if (IFA6_IS_DEPRECATED(ia6)) { int oldflags = ia6->ia6_flags; ia6->ia6_flags |= IN6_IFF_DEPRECATED; /* * If a temporary address has just become deprecated, * regenerate a new one if possible. */ if (ip6_use_tempaddr && (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && (oldflags & IN6_IFF_DEPRECATED) == 0) { if (regen_tmpaddr(ia6) == 0) { /* * A new temporary address is * generated. * XXX: this means the address chain * has changed while we are still in * the loop. Although the change * would not cause disaster (because * it's not a deletion, but an * addition,) we'd rather restart the * loop just for safety. Or does this * significantly reduce performance?? */ goto addrloop; } } a595 67 static int regen_tmpaddr(ia6) struct in6_ifaddr *ia6; /* deprecated/invalidated temporary address */ { struct ifaddr *ifa; struct ifnet *ifp; struct in6_ifaddr *public_ifa6 = NULL; ifp = ia6->ia_ifa.ifa_ifp; for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { struct in6_ifaddr *it6; if (ifa->ifa_addr->sa_family != AF_INET6) continue; it6 = (struct in6_ifaddr *)ifa; /* ignore no autoconf addresses. */ if ((it6->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; /* ignore autoconf addresses with different prefixes. */ if (it6->ia6_ndpr == NULL || it6->ia6_ndpr != ia6->ia6_ndpr) continue; /* * Now we are looking at an autoconf address with the same * prefix as ours. If the address is temporary and is still * preferred, do not create another one. It would be rare, but * could happen, for example, when we resume a laptop PC after * a long period. */ if ((it6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && !IFA6_IS_DEPRECATED(it6)) { public_ifa6 = NULL; break; } /* * This is a public autoconf address that has the same prefix * as ours. If it is preferred, keep it. We can't break the * loop here, because there may be a still-preferred temporary * address with the prefix. */ if (!IFA6_IS_DEPRECATED(it6)) public_ifa6 = it6; } if (public_ifa6 != NULL) { int e; /* * Random factor is introduced in the preferred lifetime, so * we do not need additional delay (3rd arg to in6_tmpifadd). */ if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) { log(LOG_NOTICE, "regen_tmpaddr: failed to create a new" " tmp addr, errno=%d\n", e); return (-1); } return (0); } return (-1); } d709 1 a709 1 rt = NULL; d712 1 a712 1 if (rt == NULL) { a767 4 * Note also that ifa_ifp and ifp may differ when we connect two * interfaces to a same link, install a link prefix to an interface, * and try to install a neighbor cache on an interface that does not * have a route to the prefix. d969 1 a969 1 * XXX cost-effective methods? d983 2 a984 2 if (rt == NULL) { if (dst6 == NULL) d986 1 a986 1 if ((rt = nd6_lookup(dst6, 0, NULL)) == NULL) d1145 1 a1145 1 if (ln == NULL) { d1151 1 a1151 1 bzero(ln, sizeof(*ln)); d1189 1 a1189 1 bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); d1225 1 a1225 1 if (!in6_addmulti(&llsol, ifp, &error, 0)) { d1235 1 a1235 1 if (ln == NULL) d1262 2 a1263 1 clear_llinfo_pqueue(ln); d1332 1 a1332 17 if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) oprl->prefix[i].expire = 0; else { time_t maxexpire; /* XXX: we assume time_t is signed. */ maxexpire = (-1) & ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); if (pr->ndpr_vltime < maxexpire - pr->ndpr_lastupdate) { oprl->prefix[i].expire = pr->ndpr_lastupdate + pr->ndpr_vltime; } else oprl->prefix[i].expire = maxexpire; } a1355 1 #define ND ndi->ndi d1357 9 a1365 9 memset(&ND, 0, sizeof(ND)); ND.linkmtu = IN6_LINKMTU(ifp); ND.maxmtu = ND_IFINFO(ifp)->maxmtu; ND.basereachable = ND_IFINFO(ifp)->basereachable; ND.reachable = ND_IFINFO(ifp)->reachable; ND.retrans = ND_IFINFO(ifp)->retrans; ND.flags = ND_IFINFO(ifp)->flags; ND.recalctm = ND_IFINFO(ifp)->recalctm; ND.chlim = ND_IFINFO(ifp)->chlim; d1368 1 a1368 1 ND = *ND_IFINFO(ifp); a1369 28 case SIOCSIFINFO_IN6: /* * used to change host variables from userland. * intented for a use on router to reflect RA configurations. */ /* 0 means 'unspecified' */ if (ND.linkmtu != 0) { if (ND.linkmtu < IPV6_MMTU || ND.linkmtu > IN6_LINKMTU(ifp)) { error = EINVAL; break; } ND_IFINFO(ifp)->linkmtu = ND.linkmtu; } if (ND.basereachable != 0) { int obasereachable = ND_IFINFO(ifp)->basereachable; ND_IFINFO(ifp)->basereachable = ND.basereachable; if (ND.basereachable != obasereachable) ND_IFINFO(ifp)->reachable = ND_COMPUTE_RTIME(ND.basereachable); } if (ND.retrans != 0) ND_IFINFO(ifp)->retrans = ND.retrans; if (ND.chlim != 0) ND_IFINFO(ifp)->chlim = ND.chlim; /* FALLTHROUGH */ d1371 1 a1371 1 ND_IFINFO(ifp)->flags = ND.flags; a1372 1 #undef ND d1424 1 a1424 1 { d1477 1 a1477 1 if (ifp == NULL) d1479 1 a1479 1 if (from == NULL) d1497 1 a1497 1 if (rt == NULL) { d1513 1 a1513 1 if (rt == NULL) d1521 1 a1521 1 if (ln == NULL) d1523 1 a1523 1 if (rt->rt_gateway == NULL) d1567 1 a1567 1 if (lladdr == NULL) /* (6) */ d1588 9 a1596 25 if (ln->ln_hold) { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { struct mbuf *mpkt = NULL; m_hold_next = m_hold->m_nextpkt; mpkt = m_copym(m_hold, 0, M_COPYALL, M_DONTWAIT); if (mpkt == NULL) { m_freem(m_hold); break; } mpkt->m_nextpkt = NULL; /* * we assume ifp is not a p2p here, so * just set the 2nd argument as the * 1st one. */ nd6_output(ifp, ifp, mpkt, (struct sockaddr_in6 *)rt_key(rt), rt); } ln->ln_hold = NULL; } d1739 1 a1739 1 * next hop determination. This routine is derived from ether_output. d1816 1 a1816 1 if (ln == NULL || rt == NULL) { d1846 1 a1846 1 nd6_llinfo_settimer(ln, (long)nd6_delay * hz); d1859 2 a1860 4 * response yet. Append this latest packet to the end of the * packet queue in the mbuf, unless the number of the packet * does not exceed nd6_maxqueuelen. When it exceeds nd6_maxqueuelen, * the oldest packet in the queue will be removed. d1864 3 a1866 22 if (ln->ln_hold) { struct mbuf *m_hold; int i; i = 0; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold->m_nextpkt) { i++; if (m_hold->m_nextpkt == NULL) { m_hold->m_nextpkt = m; break; } } while (i >= nd6_maxqueuelen) { m_hold = ln->ln_hold; ln->ln_hold = ln->ln_hold->m_nextpkt; m_freem(m_hold); i--; } } else { ln->ln_hold = m; } a1879 5 /* discard the packet if IPv6 operation is disabled on the interface */ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { error = ENETDOWN; /* better error? */ goto bad; } a1914 2 case IFT_PPP: case IFT_TUNNEL: a1972 16 static void clear_llinfo_pqueue(ln) struct llinfo_nd6 *ln; { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; m_freem(m_hold); } ln->ln_hold = NULL; return; } d1995 1 a1995 1 if (p == NULL) d2002 1 a2002 1 if (!error && p != NULL && oldp != NULL) d2008 1 a2008 1 if (!error && p != NULL && oldp != NULL) a2011 3 case ICMPV6CTL_ND6_MAXQLEN: break; d2066 1 d2069 2 a2070 3 } if (oldlenp) *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ d2127 1 a2127 2 ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); @ 1.96.4.3 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.96.4.2 2006/04/22 11:40:13 simonb Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.96.4.2 2006/04/22 11:40:13 simonb Exp $"); a2126 1 case IFT_CARP: @ 1.95 log @merge ktrace-lwp. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.86.2.5 2005/11/10 14:11:25 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.86.2.5 2005/11/10 14:11:25 skrll Exp $"); d65 1 a461 1 ln->ln_hold = NULL; d463 2 a464 5 * Fake rcvif to make the ICMP error * more helpful in diagnosing for the * receiver. * XXX: should we consider * older rcvif? d466 3 a468 4 m->m_pkthdr.rcvif = rt->rt_ifp; icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0); a795 2 * XXX: we should use the sin6_scope_id field rather than the embedded * interface index. d798 18 a815 3 if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr) && ntohs(addr->sin6_addr.s6_addr16[1]) == ifp->if_index) return (1); d1219 1 a1219 2 llsol.s6_addr16[0] = htons(0xff02); llsol.s6_addr16[1] = htons(ifp->if_index); d1223 2 a1224 1 d1244 1 a1244 2 llsol.s6_addr16[0] = htons(0xff02); llsol.s6_addr16[1] = htons(ifp->if_index); d1248 6 a1253 4 IN6_LOOKUP_MULTI(llsol, ifp, in6m); if (in6m) in6_delmulti(in6m); d1295 1 a1295 8 if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) { /* XXX: need to this hack for KAME stack */ drl->defrouter[i].rtaddr.s6_addr16[1] = 0; } else log(LOG_ERR, "default router list contains a " "non-linklocal address(%s)\n", ip6_sprintf(&drl->defrouter[i].rtaddr)); d1340 1 a1340 9 if (IN6_IS_ADDR_LINKLOCAL(&RTRADDR)) { /* XXX: hack for KAME */ RTRADDR.s6_addr16[1] = 0; } else log(LOG_ERR, "a router(%s) advertises " "a prefix with " "non-link local address\n", ip6_sprintf(&RTRADDR)); d1428 2 a1429 11 /* * XXX: KAME specific hack for scoped addresses * XXXX: for other scopes than link-local? */ if (IN6_IS_ADDR_LINKLOCAL(&nbi->addr) || IN6_IS_ADDR_MC_LINKLOCAL(&nbi->addr)) { u_int16_t *idp = (u_int16_t *)&nb_addr.s6_addr[2]; if (*idp == 0) *idp = htons(ifp->if_index); } d2048 6 a2053 2 in6_recoverscope(&d->rtaddr, &d->rtaddr.sin6_addr, dr->ifp); d2109 1 a2109 2 if (in6_recoverscope(&p->prefix, &p->prefix.sin6_addr, pr->ndpr_ifp) != 0) d2113 2 d2149 7 a2155 2 in6_recoverscope(s6, &s6->sin6_addr, pfr->router->ifp); @ 1.95.2.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.95 2005/12/11 12:25:02 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.95 2005/12/11 12:25:02 christos Exp $"); a64 1 #include d461 1 d463 5 a467 2 * assuming every packet in ln_hold has * the same IP header d469 4 a472 3 ln->ln_hold = NULL; icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, rt->rt_ifp); d800 2 d804 3 a806 18 if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { struct sockaddr_in6 sin6_copy; u_int32_t zone; /* * We need sin6_copy since sa6_recoverscope() may modify the * content (XXX). */ sin6_copy = *addr; if (sa6_recoverscope(&sin6_copy)) return (0); /* XXX: should be impossible */ if (in6_setscope(&sin6_copy.sin6_addr, ifp, &zone)) return (0); if (sin6_copy.sin6_scope_id == zone) return (1); else return (0); } d1210 2 a1211 1 llsol.s6_addr32[0] = htonl(0xff020000); d1215 1 a1215 2 if (in6_setscope(&llsol, ifp, NULL)) break; d1235 2 a1236 1 llsol.s6_addr32[0] = htonl(0xff020000); d1240 4 a1243 6 if (in6_setscope(&llsol, ifp, NULL) == 0) { IN6_LOOKUP_MULTI(llsol, ifp, in6m); if (in6m) in6_delmulti(in6m); } else ; /* XXX: should not happen. bark here? */ d1285 8 a1292 1 in6_clearscope(&drl->defrouter[i].rtaddr); d1337 9 a1345 1 in6_clearscope(&RTRADDR); d1433 11 a1443 2 if ((error = in6_setscope(&nb_addr, ifp, NULL)) != 0) return (error); d2062 2 a2063 6 if (sa6_recoverscope(&d->rtaddr)) { log(LOG_ERR, "scope error in router list (%s)\n", ip6_sprintf(&d->rtaddr.sin6_addr)); /* XXX: press on... */ } d2119 2 a2120 1 if (sa6_recoverscope(&p->prefix)) { a2123 2 /* XXX: press on... */ } d2158 2 a2159 7 s6->sin6_scope_id = 0; if (sa6_recoverscope(s6)) { log(LOG_ERR, "scope error in " "prefix list (%s)\n", ip6_sprintf(&pfr->router->rtaddr)); } @ 1.94 log @- avoid shadowed variables - sprinkle const. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.93 2005/05/27 22:26:25 seanb Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.93 2005/05/27 22:26:25 seanb Exp $"); @ 1.94.2.1 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.94 2005/05/29 21:43:51 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.94 2005/05/29 21:43:51 christos Exp $"); a64 1 #include a92 2 int nd6_maxqueuelen = 1; /* max # of packets cached in unresolved ND entries */ a110 1 static int regen_tmpaddr __P((struct in6_ifaddr *)); a112 1 static void clear_llinfo_pqueue __P((struct llinfo_nd6 *)); a115 1 extern struct callout in6_tmpaddrtimer_ch; d257 1 a257 1 if (ndopts == NULL) d259 1 a259 1 if (ndopts->nd_opts_last == NULL) d261 1 a261 1 if (ndopts->nd_opts_search == NULL) d309 1 a309 1 if (ndopts == NULL) d311 1 a311 1 if (ndopts->nd_opts_last == NULL) d313 1 a313 1 if (ndopts->nd_opts_search == NULL) d315 1 a315 1 d318 1 a318 1 if (nd_opt == NULL && ndopts->nd_opts_last == NULL) { d328 1 a328 1 if (nd_opt == NULL) d396 1 a396 1 ln->ln_expire = time_second + xtick / hz; d427 7 a433 1 nd6_llinfo_settimer(ln, ln->ln_ntick); d461 1 a461 2 struct mbuf *m0; d463 5 a467 2 * assuming every packet in ln_hold has * the same IP header d469 5 a473 8 m0 = m->m_nextpkt; m->m_nextpkt = NULL; icmp6_error2(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0, rt->rt_ifp); ln->ln_hold = m0; clear_llinfo_pqueue(ln); } a532 1 struct in6_addrlifetime *lt6; d541 1 a541 1 if (dr->expire && dr->expire < time_second) { a556 1 addrloop: a559 1 lt6 = &ia6->ia6_lifetime; d561 4 a564 51 int regen = 0; /* * If the expiring address is temporary, try * regenerating a new one. This would be useful when * we suspended a laptop PC, then turned it on after a * period that could invalidate all temporary * addresses. Although we may have to restart the * loop (see below), it must be after purging the * address. Otherwise, we'd see an infinite loop of * regeneration. */ if (ip6_use_tempaddr && (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { if (regen_tmpaddr(ia6) == 0) regen = 1; } in6_purgeaddr(&ia6->ia_ifa); if (regen) goto addrloop; /* XXX: see below */ } else if (IFA6_IS_DEPRECATED(ia6)) { int oldflags = ia6->ia6_flags; ia6->ia6_flags |= IN6_IFF_DEPRECATED; /* * If a temporary address has just become deprecated, * regenerate a new one if possible. */ if (ip6_use_tempaddr && (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && (oldflags & IN6_IFF_DEPRECATED) == 0) { if (regen_tmpaddr(ia6) == 0) { /* * A new temporary address is * generated. * XXX: this means the address chain * has changed while we are still in * the loop. Although the change * would not cause disaster (because * it's not a deletion, but an * addition,) we'd rather restart the * loop just for safety. Or does this * significantly reduce performance?? */ goto addrloop; } } d583 1 a583 1 time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) { a599 67 static int regen_tmpaddr(ia6) struct in6_ifaddr *ia6; /* deprecated/invalidated temporary address */ { struct ifaddr *ifa; struct ifnet *ifp; struct in6_ifaddr *public_ifa6 = NULL; ifp = ia6->ia_ifa.ifa_ifp; for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { struct in6_ifaddr *it6; if (ifa->ifa_addr->sa_family != AF_INET6) continue; it6 = (struct in6_ifaddr *)ifa; /* ignore no autoconf addresses. */ if ((it6->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; /* ignore autoconf addresses with different prefixes. */ if (it6->ia6_ndpr == NULL || it6->ia6_ndpr != ia6->ia6_ndpr) continue; /* * Now we are looking at an autoconf address with the same * prefix as ours. If the address is temporary and is still * preferred, do not create another one. It would be rare, but * could happen, for example, when we resume a laptop PC after * a long period. */ if ((it6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && !IFA6_IS_DEPRECATED(it6)) { public_ifa6 = NULL; break; } /* * This is a public autoconf address that has the same prefix * as ours. If it is preferred, keep it. We can't break the * loop here, because there may be a still-preferred temporary * address with the prefix. */ if (!IFA6_IS_DEPRECATED(it6)) public_ifa6 = it6; } if (public_ifa6 != NULL) { int e; /* * Random factor is introduced in the preferred lifetime, so * we do not need additional delay (3rd arg to in6_tmpifadd). */ if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) { log(LOG_NOTICE, "regen_tmpaddr: failed to create a new" " tmp addr, errno=%d\n", e); return (-1); } return (0); } return (-1); } d713 1 a713 1 rt = NULL; d716 1 a716 1 if (rt == NULL) { a771 4 * Note also that ifa_ifp and ifp may differ when we connect two * interfaces to a same link, install a link prefix to an interface, * and try to install a neighbor cache on an interface that does not * have a route to the prefix. d800 2 d804 3 a806 18 if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { struct sockaddr_in6 sin6_copy; u_int32_t zone; /* * We need sin6_copy since sa6_recoverscope() may modify the * content (XXX). */ sin6_copy = *addr; if (sa6_recoverscope(&sin6_copy)) return (0); /* XXX: should be impossible */ if (in6_setscope(&sin6_copy.sin6_addr, ifp, &zone)) return (0); if (sin6_copy.sin6_scope_id == zone) return (1); else return (0); } d888 1 a888 1 if (dr->expire > time_second) d890 1 a890 1 (dr->expire - time_second) * hz); d960 1 a960 1 * XXX cost-effective methods? d974 2 a975 2 if (rt == NULL) { if (dst6 == NULL) d977 1 a977 1 if ((rt = nd6_lookup(dst6, 0, NULL)) == NULL) d1136 1 a1136 1 if (ln == NULL) { d1142 1 a1142 1 bzero(ln, sizeof(*ln)); d1180 1 a1180 1 bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); d1210 2 a1211 1 llsol.s6_addr32[0] = htonl(0xff020000); d1215 2 a1216 3 if (in6_setscope(&llsol, ifp, NULL)) break; if (!in6_addmulti(&llsol, ifp, &error, 0)) { d1226 1 a1226 1 if (ln == NULL) d1235 2 a1236 1 llsol.s6_addr32[0] = htonl(0xff020000); d1240 4 a1243 6 if (in6_setscope(&llsol, ifp, NULL) == 0) { IN6_LOOKUP_MULTI(llsol, ifp, in6m); if (in6m) in6_delmulti(in6m); } else ; /* XXX: should not happen. bark here? */ d1252 2 a1253 1 clear_llinfo_pqueue(ln); d1285 8 a1292 1 in6_clearscope(&drl->defrouter[i].rtaddr); d1329 1 a1329 17 if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) oprl->prefix[i].expire = 0; else { time_t maxexpire; /* XXX: we assume time_t is signed. */ maxexpire = (-1) & ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); if (pr->ndpr_vltime < maxexpire - pr->ndpr_lastupdate) { oprl->prefix[i].expire = pr->ndpr_lastupdate + pr->ndpr_vltime; } else oprl->prefix[i].expire = maxexpire; } d1337 9 a1345 1 in6_clearscope(&RTRADDR); a1360 1 #define ND ndi->ndi d1362 9 a1370 9 memset(&ND, 0, sizeof(ND)); ND.linkmtu = IN6_LINKMTU(ifp); ND.maxmtu = ND_IFINFO(ifp)->maxmtu; ND.basereachable = ND_IFINFO(ifp)->basereachable; ND.reachable = ND_IFINFO(ifp)->reachable; ND.retrans = ND_IFINFO(ifp)->retrans; ND.flags = ND_IFINFO(ifp)->flags; ND.recalctm = ND_IFINFO(ifp)->recalctm; ND.chlim = ND_IFINFO(ifp)->chlim; d1373 1 a1373 1 ND = *ND_IFINFO(ifp); a1374 28 case SIOCSIFINFO_IN6: /* * used to change host variables from userland. * intented for a use on router to reflect RA configurations. */ /* 0 means 'unspecified' */ if (ND.linkmtu != 0) { if (ND.linkmtu < IPV6_MMTU || ND.linkmtu > IN6_LINKMTU(ifp)) { error = EINVAL; break; } ND_IFINFO(ifp)->linkmtu = ND.linkmtu; } if (ND.basereachable != 0) { int obasereachable = ND_IFINFO(ifp)->basereachable; ND_IFINFO(ifp)->basereachable = ND.basereachable; if (ND.basereachable != obasereachable) ND_IFINFO(ifp)->reachable = ND_COMPUTE_RTIME(ND.basereachable); } if (ND.retrans != 0) ND_IFINFO(ifp)->retrans = ND.retrans; if (ND.chlim != 0) ND_IFINFO(ifp)->chlim = ND.chlim; /* FALLTHROUGH */ d1376 1 a1376 1 ND_IFINFO(ifp)->flags = ND.flags; a1377 1 #undef ND d1429 1 a1429 1 { d1433 11 a1443 2 if ((error = in6_setscope(&nb_addr, ifp, NULL)) != 0) return (error); d1491 1 a1491 1 if (ifp == NULL) d1493 1 a1493 1 if (from == NULL) d1511 1 a1511 1 if (rt == NULL) { d1527 1 a1527 1 if (rt == NULL) d1535 1 a1535 1 if (ln == NULL) d1537 1 a1537 1 if (rt->rt_gateway == NULL) d1581 1 a1581 1 if (lladdr == NULL) /* (6) */ d1602 9 a1610 25 if (ln->ln_hold) { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { struct mbuf *mpkt = NULL; m_hold_next = m_hold->m_nextpkt; mpkt = m_copym(m_hold, 0, M_COPYALL, M_DONTWAIT); if (mpkt == NULL) { m_freem(m_hold); break; } mpkt->m_nextpkt = NULL; /* * we assume ifp is not a p2p here, so * just set the 2nd argument as the * 1st one. */ nd6_output(ifp, ifp, mpkt, (struct sockaddr_in6 *)rt_key(rt), rt); } ln->ln_hold = NULL; } d1753 1 a1753 1 * next hop determination. This routine is derived from ether_output. d1830 1 a1830 1 if (ln == NULL || rt == NULL) { d1860 1 a1860 1 nd6_llinfo_settimer(ln, (long)nd6_delay * hz); d1873 2 a1874 4 * response yet. Append this latest packet to the end of the * packet queue in the mbuf, unless the number of the packet * does not exceed nd6_maxqueuelen. When it exceeds nd6_maxqueuelen, * the oldest packet in the queue will be removed. d1878 3 a1880 22 if (ln->ln_hold) { struct mbuf *m_hold; int i; i = 0; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold->m_nextpkt) { i++; if (m_hold->m_nextpkt == NULL) { m_hold->m_nextpkt = m; break; } } while (i >= nd6_maxqueuelen) { m_hold = ln->ln_hold; ln->ln_hold = ln->ln_hold->m_nextpkt; m_freem(m_hold); i--; } } else { ln->ln_hold = m; } a1893 5 /* discard the packet if IPv6 operation is disabled on the interface */ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { error = ENETDOWN; /* better error? */ goto bad; } a1927 1 case IFT_CARP: a1928 2 case IFT_PPP: case IFT_TUNNEL: a1986 16 static void clear_llinfo_pqueue(ln) struct llinfo_nd6 *ln; { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; m_freem(m_hold); } ln->ln_hold = NULL; return; } d2009 1 a2009 1 if (p == NULL) d2016 1 a2016 1 if (!error && p != NULL && oldp != NULL) d2022 1 a2022 1 if (!error && p != NULL && oldp != NULL) a2025 3 case ICMPV6CTL_ND6_MAXQLEN: break; d2062 2 a2063 6 if (sa6_recoverscope(&d->rtaddr)) { log(LOG_ERR, "scope error in router list (%s)\n", ip6_sprintf(&d->rtaddr.sin6_addr)); /* XXX: press on... */ } d2076 1 d2079 2 a2080 3 } if (oldlenp) *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ d2119 2 a2120 1 if (sa6_recoverscope(&p->prefix)) { a2123 2 /* XXX: press on... */ } d2136 1 a2136 2 ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); d2158 2 a2159 7 s6->sin6_scope_id = 0; if (sa6_recoverscope(s6)) { log(LOG_ERR, "scope error in " "prefix list (%s)\n", ip6_sprintf(&pfr->router->rtaddr)); } @ 1.94.2.2 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.94.2.1 2006/06/21 15:11:09 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.94.2.1 2006/06/21 15:11:09 yamt Exp $"); d105 1 a105 4 struct llinfo_nd6 llinfo_nd6 = { .ln_prev = &llinfo_nd6, .ln_next = &llinfo_nd6, }; d363 1 a363 1 * to accommodate future extension to the protocol. d527 2 a528 1 nd6_timer(void *ignored_arg) d531 2 a532 2 struct nd_defrouter *next_dr, *dr; struct nd_prefix *next_pr, *pr; d541 2 a542 3 for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = next_dr) { next_dr = TAILQ_NEXT(dr, dr_entry); d544 2 d547 3 d626 2 a627 2 for (pr = LIST_FIRST(&nd_prefix); pr != NULL; pr = next_pr) { next_pr = LIST_NEXT(pr, ndpr_entry); d635 2 d644 3 a646 1 } d660 2 a661 1 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { d754 2 a755 2 for (pr = LIST_FIRST(&nd_prefix); pr != NULL; pr = npr) { npr = LIST_NEXT(pr, ndpr_entry); d947 1 a947 1 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { d1146 4 a1149 1 nd6_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) d1153 1 a1153 4 static const struct sockaddr_dl null_sdl = { .sdl_len = sizeof(null_sdl), .sdl_family = AF_LINK, }; d1210 1 a1210 1 (const struct sockaddr *)&null_sdl); d1328 5 a1332 2 if (ifa != rt->rt_ifa) rt_replace_ifa(rt, ifa); d1378 2 a1379 1 } d1417 2 a1418 3 TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) { if (i >= DRLSTSIZ) break; d1427 1 d1446 2 a1447 1 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { a1450 2 if (i >= PRLSTSIZ) break; d1475 1 d1477 1 a1477 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { d1485 1 d1491 1 d1555 1 a1555 1 for (pfx = LIST_FIRST(&nd_prefix); pfx; pfx = next) { d1558 1 a1558 1 next = LIST_NEXT(pfx, ndpr_entry); d1631 7 a1637 8 nd6_cache_lladdr( struct ifnet *ifp, struct in6_addr *from, char *lladdr, int lladdrlen, int type, /* ICMP6 type */ int code /* type dependent information */ ) d1877 2 a1878 1 nd6_slowtimo(void *ignored_arg) d1886 2 a1887 1 TAILQ_FOREACH(ifp, &ifnet, if_list) { d2206 6 a2211 7 nd6_sysctl( int name, void *oldp, /* syscall arg, need copyout */ size_t *oldlenp, void *newp, /* syscall arg, need copyin */ size_t newlen ) d2275 2 a2276 1 TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) { d2331 1 a2331 1 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { d2375 2 a2376 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { d2398 2 a2399 1 LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) @ 1.94.2.3 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.94.2.2 2006/12/30 20:50:39 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.94.2.2 2006/12/30 20:50:39 yamt Exp $"); d78 1 a78 1 #define SIN6(s) ((const struct sockaddr_in6 *)s) d803 1 a803 1 const struct in6_addr *addr6; d907 3 a909 1 nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) d1166 1 a1166 1 !nd6_is_addr_neighbor(satocsin6(rt_key(rt)), ifp))) { d2124 6 a2129 3 nd6_storelladdr(const struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m, const struct sockaddr *dst, u_char *lldst, size_t dstsize) d2131 1 a2131 1 const struct sockaddr_dl *sdl; d2137 3 a2139 2 ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, lldst); return 1; d2141 2 a2142 2 bcopy(ifp->if_broadcastaddr, lldst, ifp->if_addrlen); return 1; d2144 2 a2145 2 *lldst = 0; return 1; d2148 1 a2148 1 return 0; d2155 1 a2155 1 return 0; d2158 1 a2158 1 printf("%s: something odd happens\n", __func__); d2160 1 a2160 1 return 0; d2163 1 a2163 1 if (sdl->sdl_alen == 0 || sdl->sdl_alen > dstsize) { d2165 1 a2165 1 printf("%s: sdl_alen == 0, dst=%s, if=%s\n", __func__, d2168 1 a2168 1 return 0; d2171 2 a2172 2 memcpy(lldst, CLLADDR(sdl), MIN(dstsize, sdl->sdl_alen)); return 1; @ 1.94.2.4 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.94.2.3 2007/02/26 09:11:53 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.94.2.3 2007/02/26 09:11:53 yamt Exp $"); d78 3 d122 3 a124 3 callout_t nd6_slowtimo_ch; callout_t nd6_timer_ch; extern callout_t in6_tmpaddrtimer_ch; d132 1 a132 1 nd6_init(void) a151 3 callout_init(&nd6_slowtimo_ch, 0); callout_init(&nd6_timer_ch, 0); d158 2 a159 1 nd6_ifattach(struct ifnet *ifp) d186 2 a187 1 nd6_ifdetach(struct nd_ifinfo *nd) d194 2 a195 1 nd6_setmtu(struct ifnet *ifp) d201 3 a203 1 nd6_setmtu0(struct ifnet *ifp, struct nd_ifinfo *ndi) d239 4 a242 1 nd6_option_init(void *opt, int icmp6len, union nd_opts *ndopts) d260 2 a261 1 nd6_option(union nd_opts *ndopts) d278 1 a278 1 if ((void *)&nd_opt->nd_opt_len >= (void *)ndopts->nd_opts_last) { d293 1 a293 1 ndopts->nd_opts_search = (struct nd_opt_hdr *)((char *)nd_opt + olen); d312 2 a313 1 nd6_options(union nd_opts *ndopts) d392 3 a394 1 nd6_llinfo_settimer(struct llinfo_nd6 *ln, long xtick) d421 2 a422 1 nd6_llinfo_timer(void *arg) d446 1 a446 1 dst = satocsin6(rt_getkey(rt)); a644 1 /* ia6: deprecated/invalidated temporary address */ d646 2 a647 1 regen_tmpaddr(struct in6_ifaddr *ia6) d703 1 a703 1 return -1; d705 1 a705 1 return 0; d708 1 a708 1 return -1; d716 2 a717 1 nd6_purge(struct ifnet *ifp) d787 1 a787 1 const struct sockaddr_dl *sdl; d793 1 a793 1 sdl = satocsdl(rt->rt_gateway); d802 4 a805 1 nd6_lookup(const struct in6_addr *addr6, int create, struct ifnet *ifp) d827 3 a829 4 if (rt != NULL) ; else if (create && ifp) { int e; d831 11 a841 11 /* * If no route is available and create is set, * we allocate a host route for the destination * and treat it like an interface route. * This hack is necessary for a neighbor which can't * be covered by our own prefix. */ struct ifaddr *ifa = ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); if (ifa == NULL) return NULL; d843 10 a852 10 /* * Create a new route. RTF_LLINFO is necessary * to create a Neighbor Cache entry for the * destination in nd6_rtrequest which will be * called in rtrequest via ifa->ifa_rtrequest. */ if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6, ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) != 0) { d854 4 a857 4 log(LOG_ERR, "nd6_lookup: failed to add route for a " "neighbor(%s), errno=%d\n", ip6_sprintf(addr6), e); d859 12 a870 11 return NULL; } if (rt == NULL) return NULL; if (rt->rt_llinfo) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; ln->ln_state = ND6_LLINFO_NOSTATE; } } else return NULL; d897 1 a897 1 return NULL; d899 1 a899 1 return rt; d925 1 a925 1 return 0; /* XXX: should be impossible */ d927 1 a927 1 return 0; d929 1 a929 1 return 1; d931 1 a931 1 return 0; d947 1 a947 1 return 1; d958 1 a958 1 return 1; d966 1 a966 1 return 1; d968 1 a968 1 return 0; d978 3 a980 1 nd6_free(struct rtentry *rt, int gc) d983 1 a983 1 struct in6_addr in6 = satocsin6(rt_getkey(rt))->sin6_addr; d997 1 a997 1 dr = defrouter_lookup(&satocsin6(rt_getkey(rt))->sin6_addr, d1020 1 a1020 1 return ln->ln_next; d1077 1 a1077 1 rtrequest(RTM_DELETE, rt_getkey(rt), (struct sockaddr *)0, d1080 1 a1080 1 return next; d1089 4 a1092 1 nd6_nud_hint(struct rtentry *rt, struct in6_addr *dst6, int force) d1141 4 a1145 1 uint8_t namelen = strlen(ifp->if_xname), addrlen = ifp->if_addrlen; a1147 3 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1151 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1164 1 a1164 3 !nd6_is_addr_neighbor(satocsin6(rt_getkey(rt)), ifp))) { RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1184 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1193 5 union { struct sockaddr sa; struct sockaddr_dl sdl; struct sockaddr_storage ss; } u; d1200 2 a1201 4 sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type, NULL, namelen, NULL, addrlen); rt_setgate(rt, &u.sa); d1203 2 a1204 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1206 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1209 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1232 2 a1233 2 &satocsin6(rt_getkey(rt))->sin6_addr, &satocsin6(rt_getkey(rt))->sin6_addr, a1239 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1245 1 a1245 2 gate->sa_len < sockaddr_dl_measure(namelen, addrlen)) { d1251 2 a1252 4 satosdl(gate)->sdl_type = ifp->if_type; satosdl(gate)->sdl_index = ifp->if_index; RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1255 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1261 1 a1261 3 rt->rt_llinfo = (void *)ln; RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1265 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1270 1 a1270 1 callout_init(&ln->ln_timer_ch, 0); a1287 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); a1293 2 RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1295 1 a1295 1 * check if rt_getkey(rt) is an address assigned d1298 2 a1299 4 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &satocsin6(rt_getkey(rt))->sin6_addr); RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, (void *)rt->_rt_key); d1301 1 a1301 1 const void *mac; d1305 3 a1307 4 if ((mac = nd6_ifptomac(ifp)) != NULL) { /* XXX check for error */ (void)sockaddr_dl_setaddr(satosdl(gate), gate->sa_len, mac, ifp->if_addrlen); d1310 1 a1310 1 ifp = rt->rt_ifp = lo0ifp; /* XXX */ a1320 1 rt->rt_flags &= ~RTF_CLONED; d1332 1 a1332 1 llsol = satocsin6(rt_getkey(rt))->sin6_addr; d1357 1 a1357 1 llsol = satocsin6(rt_getkey(rt))->sin6_addr; d1376 1 a1376 1 Free((void *)ln); d1381 4 a1384 1 nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) d1585 1 a1585 1 return error; d1606 1 a1606 23 return nd6_setdefaultiface(ndif->ifindex); } return error; } void nd6_llinfo_release_pkts(struct llinfo_nd6 *ln, struct ifnet *ifp, struct rtentry *rt) { struct mbuf *m_hold, *m_hold_next; for (m_hold = ln->ln_hold, ln->ln_hold = NULL; m_hold != NULL; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; /* * we assume ifp is not a p2p here, so * just set the 2nd argument as the * 1st one. */ nd6_output(ifp, ifp, m_hold, satocsin6(rt_getkey(rt)), rt); d1608 1 d1684 1 a1684 1 sdl = satosdl(rt->rt_gateway); d1688 1 a1688 1 if (memcmp(lladdr, CLLADDR(sdl), ifp->if_addrlen)) d1711 2 a1712 3 /* XXX check for error */ (void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr, ifp->if_addrlen); d1745 25 a1769 1 nd6_llinfo_release_pkts(ln, ifp, rt); d1890 6 a1895 2 nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, const struct sockaddr_in6 *dst, struct rtentry *rt0) d1914 3 a1916 1 if ((rt0 = rt = rtalloc1(sin6tocsa(dst), 1)) != NULL) { d2069 1 a2069 1 return 0; d2083 2 a2084 1 return (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); d2086 1 a2086 1 return (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); d2089 1 a2089 1 if (m != NULL) d2091 1 a2091 1 return error; d2096 2 a2097 1 nd6_need_cache(struct ifnet *ifp) d2115 1 a2115 1 return 1; d2117 1 a2117 1 return 0; d2132 1 a2132 2 ETHER_MAP_IPV6_MULTICAST(&satocsin6(dst)->sin6_addr, lldst); d2135 1 a2135 2 memcpy(lldst, ifp->if_broadcastaddr, MIN(dstsize, ifp->if_addrlen)); d2156 1 a2156 1 sdl = satocsdl(rt->rt_gateway); d2160 1 a2160 1 ip6_sprintf(&satocsin6(dst)->sin6_addr), if_name(ifp)); d2170 2 a2171 1 clear_llinfo_pqueue(struct llinfo_nd6 *ln) d2235 1 a2235 1 return error; d2239 3 a2241 1 fill_drlist(void *oldp, size_t *oldlenp, size_t ol) d2252 1 a2252 1 de = (struct in6_defrouter *)((char *)oldp + *oldlenp); d2285 1 a2285 1 *oldlenp = l; /* (void *)d - (void *)oldp */ d2289 1 a2289 1 return error; d2293 3 a2295 1 fill_prlist(void *oldp, size_t *oldlenp, size_t ol) d2307 1 a2307 1 pe = (struct in6_prefix *)((char *)oldp + *oldlenp); d2384 1 a2384 1 p = (struct in6_prefix *)((char *)p + advance); d2388 1 a2388 1 *oldlenp = l; /* (void *)d - (void *)oldp */ d2396 1 a2396 1 return error; @ 1.94.2.5 log @sync with head. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.94.2.4 2007/09/03 14:43:40 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.94.2.4 2007/09/03 14:43:40 yamt Exp $"); d110 1 a110 8 static const struct sockaddr_in6 all1_sa = { .sin6_family = AF_INET6 , .sin6_len = sizeof(struct sockaddr_in6) , .sin6_addr = {.s6_addr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}} }; d112 6 a117 6 static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *); static void nd6_slowtimo(void *); static int regen_tmpaddr(struct in6_ifaddr *); static struct llinfo_nd6 *nd6_free(struct rtentry *, int); static void nd6_llinfo_timer(void *); static void clear_llinfo_pqueue(struct llinfo_nd6 *); d123 2 a124 2 static int fill_drlist(void *, size_t *, size_t); static int fill_prlist(void *, size_t *, size_t); d132 1 d139 5 d793 4 a796 1 sockaddr_in6_init(&sin6, addr6, 0, 0, 0); d833 2 a834 2 if ((e = rtrequest(RTM_ADD, (const struct sockaddr *)&sin6, ifa->ifa_addr, (const struct sockaddr *)&all1_sa, d2259 4 a2262 2 memset(d, 0, sizeof(*d)); sockaddr_in6_init(&d->rtaddr, &dr->rtaddr, 0, 0, 0); d2359 4 a2362 2 sockaddr_in6_init(s6, &pfr->router->rtaddr, 0, 0, 0); @ 1.94.2.6 log @sync with head @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.94.2.5 2007/11/15 11:45:14 yamt Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.94.2.5 2007/11/15 11:45:14 yamt Exp $"); d642 1 a642 1 IFADDR_FOREACH(ifa, ifp) { @ 1.93 log @- Arithmetic error when calculating ticks to nd6_llinfo_settimer(). - Reviewed by christos. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.92 2005/04/03 11:02:27 tron Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.92 2005/04/03 11:02:27 tron Exp $"); d383 1 a383 1 nd6_llinfo_settimer(ln, tick) d385 1 a385 1 long tick; d391 1 a391 1 if (tick < 0) { d396 3 a398 3 ln->ln_expire = time.tv_sec + tick / hz; if (tick > INT_MAX) { ln->ln_ntick = tick - INT_MAX; d403 1 a403 1 callout_reset(&ln->ln_timer_ch, tick, d1386 1 a1386 1 struct nd_prefix *pr, *next; d1389 1 a1389 1 for (pr = nd_prefix.lh_first; pr; pr = next) { d1392 1 a1392 1 next = pr->ndpr_next; d1394 1 a1394 1 if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) d1405 1 a1405 1 if (ia->ia6_ndpr == pr) d1408 1 a1408 1 prelist_remove(pr); d1416 1 a1416 1 struct nd_defrouter *dr, *next; d1420 3 a1422 3 for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = next) { next = TAILQ_NEXT(dr, dr_entry); defrtrlist_del(dr); @ 1.92 log @Make sure that prefixes get purged. This fixes PR kern/21189, PR kern/25968 and PR kern/27873. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.91 2004/12/04 16:10:25 peter Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.91 2004/12/04 16:10:25 peter Exp $"); d888 1 a888 1 if (dr->expire > time.tv_sec * hz) d890 1 a890 1 dr->expire - time.tv_sec * hz); @ 1.91 log @Convert lo(4) to a clonable device. This also removes the loif array and changes all code to use the new lo0ifp pointer which points to the lo0 ifnet structure. Approved by christos. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.90 2004/05/19 17:45:05 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.90 2004/05/19 17:45:05 itojun Exp $"); d640 7 @ 1.91.4.1 log @sync with -current @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.92 2005/04/03 11:02:27 tron Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.92 2005/04/03 11:02:27 tron Exp $"); a639 7 * Because if_detach() does *not* release prefixes * while purging addresses the reference count will * still be above zero. We therefore reset it to * make sure that the prefix really gets purged. */ pr->ndpr_refcnt = 0; /* @ 1.91.10.1 log @Pullup rev 1.92 (requested by tron in ticket #105) Make sure that prefixes get purged. PR#21189, PR#25968, PR#27873 @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.91 2004/12/04 16:10:25 peter Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.91 2004/12/04 16:10:25 peter Exp $"); a639 7 * Because if_detach() does *not* release prefixes * while purging addresses the reference count will * still be above zero. We therefore reset it to * make sure that the prefix really gets purged. */ pr->ndpr_refcnt = 0; /* @ 1.90 log @do not loop on nd6_output() when transmission fails. from kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.89 2004/02/11 10:37:33 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.89 2004/02/11 10:37:33 itojun Exp $"); a71 3 #include "loop.h" extern struct ifnet loif[NLOOP]; d1177 1 a1177 1 rt->rt_ifp = &loif[0]; /* XXX */ @ 1.89 log @avoid ugly typecast @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.88 2003/10/30 01:43:09 simonb Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.88 2003/10/30 01:43:09 simonb Exp $"); d1757 2 a1758 5 if (rt->rt_ifp != ifp) { /* XXX: loop care? */ return nd6_output(ifp, origifp, m0, dst, rt); } @ 1.89.2.1 log @Pull up revision 1.92 (requested by tron in ticket #1394): Make sure that prefixes get purged. Fixes PR#21189, PR#25968, and PR#37873. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.89 2004/02/11 10:37:33 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.89 2004/02/11 10:37:33 itojun Exp $"); a642 7 * Because if_detach() does *not* release prefixes * while purging addresses the reference count will * still be above zero. We therefore reset it to * make sure that the prefix really gets purged. */ pr->ndpr_refcnt = 0; /* @ 1.89.4.1 log @Pull up revision 1.92 (requested by tron in ticket #1394): Make sure that prefixes get purged. Fixes PR#21189, PR#25968, and PR#37873. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.89 2004/02/11 10:37:33 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.89 2004/02/11 10:37:33 itojun Exp $"); a642 7 * Because if_detach() does *not* release prefixes * while purging addresses the reference count will * still be above zero. We therefore reset it to * make sure that the prefix really gets purged. */ pr->ndpr_refcnt = 0; /* @ 1.88 log @Remove some assigned-to but otherwise unused variables. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.87 2003/08/22 22:11:46 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.87 2003/08/22 22:11:46 itojun Exp $"); d801 1 a801 1 ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]) == ifp->if_index) @ 1.87 log @correct missing inclusion of opt_ipsec.h @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.86 2003/06/27 08:41:08 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.86 2003/06/27 08:41:08 itojun Exp $"); a535 1 struct in6_addrlifetime *lt6; a562 1 lt6 = &ia6->ia6_lifetime; a792 1 struct rtentry *rt; d835 1 a835 1 if ((rt = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL) a1016 1 int mine = 0; a1174 1 mine = 1; d1995 1 a1995 1 size_t ol, l; a1998 1 l = 0; @ 1.86 log @split ND6 cache timer management to per-entry. increased accuracy, no O(N) loop. sync w/ kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.85 2003/06/24 07:54:48 itojun Exp $ */ d34 3 a36 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.85 2003/06/24 07:54:48 itojun Exp $"); d67 4 @ 1.86.2.1 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.90 2004/05/19 17:45:05 itojun Exp $ */ d34 1 a34 3 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.90 2004/05/19 17:45:05 itojun Exp $"); #include "opt_ipsec.h" a65 4 #ifdef IPSEC #include #endif d530 1 d558 1 d789 1 d798 1 a798 1 ntohs(addr->sin6_addr.s6_addr16[1]) == ifp->if_index) d832 1 a832 1 if (nd6_lookup(&addr->sin6_addr, 0, ifp) != NULL) d1014 1 d1173 1 d1756 5 a1760 2 if (rt->rt_ifp != ifp) senderr(EHOSTUNREACH); d1994 1 a1994 1 size_t ol; d1998 1 @ 1.86.2.2 log @Sync with HEAD. @ text @@ 1.86.2.3 log @Fix the sync with head I botched. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.86.2.1 2004/08/03 10:55:14 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.86.2.1 2004/08/03 10:55:14 skrll Exp $"); @ 1.86.2.4 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.86.2.3 2004/09/21 13:37:36 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.86.2.3 2004/09/21 13:37:36 skrll Exp $"); d72 3 d1180 1 a1180 1 rt->rt_ifp = lo0ifp; /* XXX */ @ 1.86.2.5 log @Sync with HEAD. Here we go again... @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.86.2.4 2004/12/18 09:33:06 skrll Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.86.2.4 2004/12/18 09:33:06 skrll Exp $"); d383 1 a383 1 nd6_llinfo_settimer(ln, xtick) d385 1 a385 1 long xtick; d391 1 a391 1 if (xtick < 0) { d396 3 a398 3 ln->ln_expire = time.tv_sec + xtick / hz; if (xtick > INT_MAX) { ln->ln_ntick = xtick - INT_MAX; d403 1 a403 1 callout_reset(&ln->ln_timer_ch, xtick, a639 7 * Because if_detach() does *not* release prefixes * while purging addresses the reference count will * still be above zero. We therefore reset it to * make sure that the prefix really gets purged. */ pr->ndpr_refcnt = 0; /* d881 1 a881 1 if (dr->expire > time.tv_sec) d883 1 a883 1 (dr->expire - time.tv_sec) * hz); d1379 1 a1379 1 struct nd_prefix *pfx, *next; d1382 1 a1382 1 for (pfx = nd_prefix.lh_first; pfx; pfx = next) { d1385 1 a1385 1 next = pfx->ndpr_next; d1387 1 a1387 1 if (IN6_IS_ADDR_LINKLOCAL(&pfx->ndpr_prefix.sin6_addr)) d1398 1 a1398 1 if (ia->ia6_ndpr == pfx) d1401 1 a1401 1 prelist_remove(pfx); d1409 1 a1409 1 struct nd_defrouter *drtr, *next; d1413 3 a1415 3 for (drtr = TAILQ_FIRST(&nd_defrouter); drtr; drtr = next) { next = TAILQ_NEXT(drtr, dr_entry); defrtrlist_del(drtr); @ 1.85 log @remove unneeded checks of accept_rtadv. from kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.84 2003/06/24 07:49:03 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.84 2003/06/24 07:49:03 itojun Exp $"); d109 1 d377 1 a377 1 * ND6 timer routine to expire default route list and prefix list d380 31 a410 2 nd6_timer(ignored_arg) void *ignored_arg; d414 2 a415 2 struct nd_defrouter *dr; struct nd_prefix *pr; d417 1 a417 2 struct in6_ifaddr *ia6, *nia6; struct in6_addrlifetime *lt6; a419 2 callout_reset(&nd6_timer_ch, nd6_prune * hz, nd6_timer, NULL); d421 46 a466 7 ln = llinfo_nd6.ln_next; while (ln && ln != &llinfo_nd6) { struct rtentry *rt; struct sockaddr_in6 *dst; struct llinfo_nd6 *next = ln->ln_next; /* XXX: used for the DELAY case only: */ struct nd_ifinfo *ndi = NULL; d468 5 a472 3 if ((rt = ln->ln_rt) == NULL) { ln = next; continue; d474 5 a478 3 if ((ifp = rt->rt_ifp) == NULL) { ln = next; continue; d480 1 a480 2 ndi = ND_IFINFO(ifp); dst = (struct sockaddr_in6 *)rt_key(rt); d482 5 a486 3 if (ln->ln_expire > time.tv_sec) { ln = next; continue; d488 1 d490 25 a514 29 /* sanity check */ if (!rt) panic("rt=0 in nd6_timer(ln=%p)", ln); if (rt->rt_llinfo && (struct llinfo_nd6 *)rt->rt_llinfo != ln) panic("rt_llinfo(%p) is not equal to ln(%p)", rt->rt_llinfo, ln); if (!dst) panic("dst=0 in nd6_timer(ln=%p)", ln); switch (ln->ln_state) { case ND6_LLINFO_INCOMPLETE: if (ln->ln_asked < nd6_mmaxtries) { ln->ln_asked++; ln->ln_expire = time.tv_sec + ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); } else { struct mbuf *m = ln->ln_hold; if (m) { ln->ln_hold = NULL; /* * Fake rcvif to make the ICMP error * more helpful in diagnosing for the * receiver. * XXX: should we consider * older rcvif? */ m->m_pkthdr.rcvif = rt->rt_ifp; d516 2 a517 12 icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0); } next = nd6_free(rt, 0); } break; case ND6_LLINFO_REACHABLE: if (ln->ln_expire) { ln->ln_state = ND6_LLINFO_STALE; ln->ln_expire = time.tv_sec + nd6_gctimer; } break; d519 12 a530 5 case ND6_LLINFO_STALE: /* Garbage Collection(RFC 2461 5.3) */ if (ln->ln_expire) next = nd6_free(rt, 1); break; d532 3 a534 28 case ND6_LLINFO_DELAY: if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) { /* We need NUD */ ln->ln_asked = 1; ln->ln_state = ND6_LLINFO_PROBE; ln->ln_expire = time.tv_sec + ND6_RETRANS_SEC(ndi->retrans); nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); } else { ln->ln_state = ND6_LLINFO_STALE; /* XXX */ ln->ln_expire = time.tv_sec + nd6_gctimer; } break; case ND6_LLINFO_PROBE: if (ln->ln_asked < nd6_umaxtries) { ln->ln_asked++; ln->ln_expire = time.tv_sec + ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); } else { next = nd6_free(rt, 0); } break; } ln = next; } d858 3 d881 5 a885 1 ln->ln_expire = dr->expire; d997 4 a1000 2 if (ln->ln_expire) ln->ln_expire = time.tv_sec + ND_IFINFO(rt->rt_ifp)->reachable; d1074 1 a1074 11 ln->ln_expire = time.tv_sec; #if 1 if (ln && ln->ln_expire == 0) { /* kludge for desktops */ #if 0 printf("nd6_rtrequest: time.tv_sec is zero; " "treat it as 1\n"); #endif ln->ln_expire = 1; } #endif d1138 1 d1154 1 a1154 1 ln->ln_expire = time.tv_sec; d1170 1 a1170 1 ln->ln_expire = 0; d1195 1 a1195 1 ln->ln_expire = 0; d1244 1 d1595 1 a1595 1 ln->ln_expire = time.tv_sec + nd6_gctimer; d1608 1 a1608 1 ln->ln_expire = time.tv_sec; d1845 1 a1845 1 ln->ln_expire = time.tv_sec + nd6_gctimer; d1858 1 a1858 1 ln->ln_expire = time.tv_sec + nd6_delay; a1881 6 * Technically this can be against the rate-limiting rule described in * Section 7.2.2 of RFC 2461 because the interval to the next scheduled * solicitation issued in nd6_timer() may be less than the specified * retransmission time. This should not be a problem from a practical * point of view, because we'll typically see an immediate response * from the neighbor, which suppresses the succeeding solicitations. d1883 1 a1883 1 if (ln->ln_expire && ln->ln_asked == 0) { d1885 2 a1886 2 ln->ln_expire = time.tv_sec + ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); @ 1.84 log @* kame/sys/netinet6/nd6.c (nd6_rtrequest): changed a condition to decide whether to create an empty llinfo stricter so that a user can manually change the link-layer address of an existing neighbor cache. Pointed out by: KIU Shueng Chuan from kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.83 2003/06/24 07:39:26 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.83 2003/06/24 07:39:26 itojun Exp $"); d818 1 a818 1 if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */ @ 1.83 log @use time.tv_sec directly @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.82 2003/06/24 07:32:03 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.82 2003/06/24 07:32:03 itojun Exp $"); d1011 2 a1012 1 if (rt->rt_flags & (RTF_CLONING | RTF_LLINFO)) { d1014 4 a1017 4 * Case 1: This route should come from * a route to interface. RTF_LLINFO flag is set * for a host route whose destination should be * treated as on-link. @ 1.82 log @clear ln_hold earlier. from kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.81 2003/05/04 13:43:09 christos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.81 2003/05/04 13:43:09 christos Exp $"); a385 1 long time_second = time.tv_sec; d413 1 a413 1 if (ln->ln_expire > time_second) { d431 1 a431 1 ln->ln_expire = time_second + d457 1 a457 1 ln->ln_expire = time_second + nd6_gctimer; d472 1 a472 1 ln->ln_expire = time_second + d478 1 a478 1 ln->ln_expire = time_second + nd6_gctimer; d484 1 a484 1 ln->ln_expire = time_second + d499 1 a499 1 if (dr->expire && dr->expire < time_second) { d542 1 a542 1 time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) { a914 1 long time_second = time.tv_sec; d951 1 a951 1 ln->ln_expire = time_second + ND_IFINFO(rt->rt_ifp)->reachable; a964 1 long time_second = time.tv_sec; d1024 1 a1024 1 ln->ln_expire = time_second; d1113 1 a1113 1 ln->ln_expire = time_second; a1442 1 long time_second = time.tv_sec; d1553 1 a1553 1 ln->ln_expire = time_second + nd6_gctimer; d1566 1 a1566 1 ln->ln_expire = time_second; a1697 1 long time_second = time.tv_sec; d1803 1 a1803 1 ln->ln_expire = time_second + nd6_gctimer; d1816 1 a1816 1 ln->ln_expire = time_second + nd6_delay; d1849 1 a1849 1 ln->ln_expire = time_second + @ 1.81 log @print how big the mtu needs to be for ipv6 ppp. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.80 2003/02/25 22:17:47 he Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.80 2003/02/25 22:17:47 he Exp $"); d439 1 a450 1 ln->ln_hold = NULL; @ 1.80 log @Make sure to initialize callout structs. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.79 2003/02/01 06:23:47 thorpej Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.79 2003/02/01 06:23:47 thorpej Exp $"); d215 4 a218 3 log(LOG_NOTICE, "nd6_setmtu0: " "new link MTU on %s (%lu) is too small for IPv6\n", if_name(ifp), (unsigned long)ndi->maxmtu); @ 1.79 log @Add extensible malloc types, adapted from FreeBSD. This turns malloc types into a structure, a pointer to which is passed around, instead of an int constant. Allow the limit to be adjusted when the malloc type is defined, or with a function call, as suggested by Jonathan Stone. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.78 2003/01/17 08:11:58 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.78 2003/01/17 08:11:58 itojun Exp $"); d110 2 a111 2 struct callout nd6_slowtimo_ch; struct callout nd6_timer_ch; @ 1.78 log @switch from kame-based m_aux mbuf auxiliary data, to openbsd m_tag implementation. it will simplify porting across *bsd (such as kame/altq), and make us more synchronized. from Joel Wilsson @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.77 2002/10/09 20:22:16 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.77 2002/10/09 20:22:16 itojun Exp $"); d115 2 @ 1.77 log @suppress too noisy log by default (can be re-enabled by sysctl). sync w/kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.76 2002/09/27 15:37:54 provos Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.76 2002/09/27 15:37:54 provos Exp $"); d1859 4 @ 1.76 log @remove trailing \n in panic(). approved perry. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.75 2002/09/23 13:16:53 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.75 2002/09/23 13:16:53 itojun Exp $"); d727 1 a727 1 log(LOG_DEBUG, d730 1 a730 1 ifp ? if_name(ifp) : "unspec"); @ 1.75 log @better fix to PR 18163 ("deprecated" flag manipulation). sync w/kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.74 2002/09/23 05:51:15 simonb Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.74 2002/09/23 05:51:15 simonb Exp $"); d251 1 a251 1 panic("ndopts == NULL in nd6_option\n"); d253 1 a253 1 panic("uninitialized ndopts in nd6_option\n"); d303 1 a303 1 panic("ndopts == NULL in nd6_options\n"); d305 1 a305 1 panic("uninitialized ndopts in nd6_options\n"); d418 1 a418 1 panic("rt=0 in nd6_timer(ln=%p)\n", ln); d420 1 a420 1 panic("rt_llinfo(%p) is not equal to ln(%p)\n", d423 1 a423 1 panic("dst=0 in nd6_timer(ln=%p)\n", ln); @ 1.74 log @Remove breaks after returns, unreachable returns and returns after returns(!). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.73 2002/09/11 02:46:46 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.73 2002/09/11 02:46:46 itojun Exp $"); d520 1 a520 2 if ((ia6->ia6_flags & IN6_IFF_DEPRECATED) != 0 || IFA6_IS_DEPRECATED(ia6)) { @ 1.73 log @KNF - return is not a function. sync w/kame. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.72 2002/09/04 07:22:28 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.72 2002/09/04 07:22:28 itojun Exp $"); a1418 1 break; @ 1.72 log @allow "deprecated" bit to be manually set. PR 18163 @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.71 2002/08/19 23:23:22 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.71 2002/08/19 23:23:22 itojun Exp $"); d681 1 a681 1 return(NULL); d699 1 a699 1 return(NULL); d702 1 a702 1 return(NULL); d709 1 a709 1 return(NULL); d733 1 a733 1 return(NULL); d735 1 a735 1 return(rt); d758 1 a758 1 return(1); d784 1 a784 1 return(1); d792 1 a792 1 return(1); d794 1 a794 1 return(0); d839 1 a839 1 return(ln->ln_next); d899 1 a899 1 return(next); d1418 1 a1418 1 return(nd6_setdefaultiface(ndif->ifindex)); d1421 1 a1421 1 return(error); d1857 1 a1857 1 return(0); d1862 1 a1862 1 return((*ifp->if_output)(origifp, m, (struct sockaddr *)dst, d1865 1 a1865 1 return((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt)); d1891 1 a1891 1 return(1); d1893 1 a1893 1 return(0); d1913 1 a1913 1 return(1); d1916 1 a1916 1 return(1); d1919 1 a1919 1 return(1); d1922 1 a1922 1 return(0); d1929 1 a1929 1 return(0); d1934 1 a1934 1 return(0); d1942 1 a1942 1 return(0); d1946 1 a1946 1 return(1); d1996 1 a1996 1 return(error); d2047 1 a2047 1 return(error); d2149 1 a2149 1 return(error); @ 1.71 log @check error from copyout @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.70 2002/08/19 23:21:11 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.70 2002/08/19 23:21:11 itojun Exp $"); d520 2 a521 1 if (IFA6_IS_DEPRECATED(ia6)) { @ 1.70 log @typo in comment @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.69 2002/08/19 23:14:39 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.69 2002/08/19 23:14:39 itojun Exp $"); d1979 1 a1979 1 copyout(p, oldp, *oldlenp); d1985 1 a1985 1 copyout(p, oldp, *oldlenp); @ 1.69 log @fix copyout() logic. more proper fix to be done on kame tree. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.68 2002/08/19 07:23:22 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.68 2002/08/19 07:23:22 itojun Exp $"); d1953 1 a1953 1 void *newp; /* syscall arg, need in */ @ 1.68 log @copyout only if oldp is non-null @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.67 2002/08/19 06:50:22 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.67 2002/08/19 06:50:22 itojun Exp $"); d1951 1 a1951 1 void *oldp; d1953 1 a1953 1 void *newp; d1956 1 d1969 6 d1977 3 a1979 3 error = fill_drlist(oldp, oldlenp, ol); if (!error && oldp) copyout(oldp, oldp, *oldlenp); d1983 3 a1985 3 error = fill_prlist(oldp, oldlenp, ol); if (!error && oldp) copyout(oldp, oldp, *oldlenp); d1992 2 @ 1.67 log @need explicit copyout(), apparently @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.66 2002/06/09 14:43:13 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.66 2002/06/09 14:43:13 itojun Exp $"); d1971 1 a1971 1 if (!error) d1977 1 a1977 1 if (!error) @ 1.66 log @whitespace cleanup @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.65 2002/06/08 21:22:34 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.65 2002/06/08 21:22:34 itojun Exp $"); d1971 2 d1977 2 @ 1.65 log @sync with latest KAME in6_ifaddr/prefix/default router manipulation. behavior changes: - two iocts used by ndp(8) are now obsolete (backward compat provided). use sysctl path instead. - lo0 does not get ::1 automatically. it will get ::1 when lo0 comes up. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.64 2002/06/07 17:15:12 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.64 2002/06/07 17:15:12 itojun Exp $"); d1996 1 a1996 1 @ 1.64 log @If there has been no NS for the neighbor after entering the INCOMPLETE state, send the first solicitation in nd6_output(), regardless of the timer value. revised comments about rate-limiting accordingly. sync w/kame @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.63 2002/06/03 02:09:37 itojun Exp $ */ /* $KAME: nd6.c,v 1.151 2001/06/19 14:24:41 sumikawa Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.63 2002/06/03 02:09:37 itojun Exp $"); a63 1 #include d113 3 d157 6 a162 1 nd->flags = ND6_IFF_PERFORMNUD; d384 3 a394 1 struct ifnet *ifp; d432 1 a432 1 ln, 0); d436 9 a444 10 if (rt->rt_ifp) { /* * Fake rcvif to make ICMP error * more helpful in diagnosing * for the receiver. * XXX: should we consider * older rcvif? */ m->m_pkthdr.rcvif = rt->rt_ifp; } d471 1 a471 1 ND6_RETRANS_SEC(ndi->retrans); d473 1 a473 2 &dst->sin6_addr, ln, 0); d485 1 a485 1 &dst->sin6_addr, ln, 0); a505 4 pr = nd_prefix.lh_first; while (pr) { struct in6_ifaddr *ia6; struct in6_addrlifetime *lt6; d507 21 a527 15 if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) ia6 = NULL; else ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); if (ia6) { /* check address lifetime */ lt6 = &ia6->ia6_lifetime; if (lt6->ia6t_preferred && lt6->ia6t_preferred < time_second) ia6->ia6_flags |= IN6_IFF_DEPRECATED; if (lt6->ia6t_expire && lt6->ia6t_expire < time_second) { if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); /* xxx ND_OPT_PI_FLAG_ONLINK processing */ } d529 1 d531 3 a537 5 * * we offset expire time by NDPR_KEEP_EXPIRE, so that we * can use the old prefix information to validate the * next prefix information to come. See prelist_update() * for actual validation. d539 2 a540 2 if (pr->ndpr_expire && pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) { d546 1 a546 1 * separate. NEVER perform in6_ifdel here. d566 1 a566 1 struct nd_defrouter *dr, *ndr, drany; d569 19 a587 12 /* Nuke default router list entries toward ifp */ if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { /* * The first entry of the list may be stored in * the routing table, so we'll delete it later. */ for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = ndr) { ndr = TAILQ_NEXT(dr, dr_entry); if (dr->ifp == ifp) defrtrlist_del(dr); } dr = TAILQ_FIRST(&nd_defrouter); d596 8 a603 2 if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); a613 2 bzero(&drany, sizeof(drany)); defrouter_delreq(&drany, 0); d678 1 a678 1 ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); d689 3 a691 6 ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) != 0) { d704 1 a704 1 (struct llinfo_nd6 *)rt->rt_llinfo; d713 4 d720 2 a721 1 * use rt->rt_ifa->ifa_ifp, which would specify the REAL interface. d724 1 a724 1 rt->rt_gateway->sa_family != AF_LINK || d727 4 a730 2 log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec"); d732 1 a732 1 return(0); d746 2 a747 5 struct ifaddr *ifa; int i; #define IFADDR6(a) ((((struct in6_ifaddr *)(a))->ia_addr).sin6_addr) #define IFMASK6(a) ((((struct in6_ifaddr *)(a))->ia_prefixmask).sin6_addr) d760 2 a761 2 * If the address matches one of our addresses, * it should be a neighbor. d763 11 a773 6 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { if (ifa->ifa_addr->sa_family != AF_INET6) next: continue; d775 8 a782 6 for (i = 0; i < 4; i++) { if ((IFADDR6(ifa).s6_addr32[i] ^ addr->sin6_addr.s6_addr32[i]) & IFMASK6(ifa).s6_addr32[i]) goto next; } d790 1 a790 1 if (nd6_lookup(&addr->sin6_addr, 0, ifp)) a793 2 #undef IFADDR6 #undef IFMASK6 d820 1 a820 1 rt->rt_ifp); d874 4 a877 13 if (dr == TAILQ_FIRST(&nd_defrouter)) { /* * It is used as the current default router, * so we have to move it to the end of the * list and choose a new one. * XXX: it is not very efficient if this is * the only router. */ TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); TAILQ_INSERT_TAIL(&nd_defrouter, dr, dr_entry); defrouter_select(); } d896 1 a896 1 rt_mask(rt), 0, (struct rtentry **)0); d965 1 d967 1 a967 1 if ((rt->rt_flags & RTF_GATEWAY)) d981 21 d1029 1 a1029 1 printf("nd6_rtequest: time.tv_sec is zero; " d1035 1 a1035 1 if ((rt->rt_flags & RTF_CLONING)) d1067 1 a1067 1 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { d1126 1 a1126 1 &SIN6(rt_key(rt))->sin6_addr); d1132 1 a1210 59 void nd6_p2p_rtrequest(req, rt, info) int req; struct rtentry *rt; struct rt_addrinfo *info; /* xxx unused */ { struct sockaddr *gate = rt->rt_gateway; static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; struct ifnet *ifp = rt->rt_ifp; struct ifaddr *ifa; if (rt->rt_flags & RTF_GATEWAY) return; switch (req) { case RTM_ADD: /* * There is no backward compatibility :) * * if ((rt->rt_flags & RTF_HOST) == 0 && * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) * rt->rt_flags |= RTF_CLONING; */ if (rt->rt_flags & RTF_CLONING) { /* * Case 1: This route should come from * a route to interface. */ rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl); gate = rt->rt_gateway; SDL(gate)->sdl_type = ifp->if_type; SDL(gate)->sdl_index = ifp->if_index; break; } /* Announce a new entry if requested. */ if (rt->rt_flags & RTF_ANNOUNCE) nd6_na_output(ifp, &SIN6(rt_key(rt))->sin6_addr, &SIN6(rt_key(rt))->sin6_addr, ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1, NULL); /* FALLTHROUGH */ case RTM_RESOLVE: /* * check if rt_key(rt) is one of my address assigned * to the interface. */ ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, &SIN6(rt_key(rt))->sin6_addr); if (ifa) { if (nd6_useloopback) { rt->rt_ifp = &loif[0]; /*XXX*/ } } break; } } d1218 1 a1218 1 struct in6_prlist *prl = (struct in6_prlist *)data; d1222 1 a1222 1 struct nd_defrouter *dr, any; d1230 3 d1258 7 d1269 1 a1269 1 bzero(prl, sizeof(*prl)); d1276 7 a1282 7 prl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; prl->prefix[i].raflags = pr->ndpr_raf; prl->prefix[i].prefixlen = pr->ndpr_plen; prl->prefix[i].vltime = pr->ndpr_vltime; prl->prefix[i].pltime = pr->ndpr_pltime; prl->prefix[i].if_index = pr->ndpr_ifp->if_index; prl->prefix[i].expire = pr->ndpr_expire; d1288 1 a1288 1 #define RTRADDR prl->prefix[i].advrtr[j] d1304 2 a1305 2 prl->prefix[i].advrtrs = j; prl->prefix[i].origin = PR_ORIG_RA; a1309 19 { struct rr_prefix *rpp; for (rpp = LIST_FIRST(&rr_prefix); rpp; rpp = LIST_NEXT(rpp, rp_entry)) { if (i >= PRLSTSIZ) break; prl->prefix[i].prefix = rpp->rp_prefix.sin6_addr; prl->prefix[i].raflags = rpp->rp_raf; prl->prefix[i].prefixlen = rpp->rp_plen; prl->prefix[i].vltime = rpp->rp_vltime; prl->prefix[i].pltime = rpp->rp_pltime; prl->prefix[i].if_index = rpp->rp_ifp->if_index; prl->prefix[i].expire = rpp->rp_expire; prl->prefix[i].advrtrs = 0; prl->prefix[i].origin = rpp->rp_origin; i++; } } d1332 2 a1333 7 /* flush default router list */ /* * xxx sumikawa: should not delete route if default * route equals to the top of default router list */ bzero(&any, sizeof(any)); defrouter_delreq(&any, 0); a1334 1 /* xxx sumikawa: flush prefix list */ d1337 1 a1337 1 { d1343 2 d1346 15 a1360 2 if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); d1365 1 a1365 1 } d1367 1 a1367 1 { d1372 4 a1375 10 if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { /* * The first entry of the list may be stored in * the routing table, so we'll delete it later. */ for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = next) { next = TAILQ_NEXT(dr, dr_entry); defrtrlist_del(dr); } defrtrlist_del(TAILQ_FIRST(&nd_defrouter)); d1377 1 d1380 1 a1380 1 } d1399 2 a1400 1 if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL) { a1404 1 ln = (struct llinfo_nd6 *)rt->rt_llinfo; d1412 1 a1412 1 } d1528 2 a1529 2 if ((!olladdr && lladdr) /* (3) */ || (olladdr && lladdr && llchange)) { /* (5) */ d1563 1 a1563 2 (struct sockaddr_in6 *)rt_key(rt), rt); d1630 2 a1631 2 if ((!is_newentry && (olladdr || lladdr)) /* (2-5) */ || (is_newentry && lladdr)) { /* (7) */ d1713 2 a1714 2 if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1)) != NULL) d1720 1 a1720 1 dst, rt); d1732 1 a1732 1 * of view, regardless the value of nd_ifinfo.flags. d1848 1 a1848 1 * from the neighbor, which suppresses the succeeding solicitations. d1939 1 a1939 1 ip6_sprintf(&SIN6(dst)->sin6_addr), if_name(ifp)); d1946 190 @ 1.63 log @whitespace at EOL @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.62 2002/06/03 00:51:47 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.62 2002/06/03 00:51:47 itojun Exp $"); d463 1 a463 1 ndi->retrans / 1000; a1859 3 * This code conforms to the rate-limiting rule described in Section * 7.2.2 of RFC 2461, because the timer is set correctly after sending * an NS below. d1866 15 a1880 8 if (ln->ln_expire) { if (ln->ln_asked < nd6_mmaxtries && ln->ln_expire < time_second) { ln->ln_asked++; ln->ln_expire = time_second + ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); } @ 1.62 log @do not hardcode if_mtu values in here, except for IFT_{ARC,FDDI} - they need special handling. makes it possible to take advantage of 9k ether frames. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.61 2002/05/30 05:06:29 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.61 2002/05/30 05:06:29 itojun Exp $"); d203 1 a203 1 * log to the case of changing the MTU, not initializing it. d377 1 a377 1 d486 1 a486 1 d1435 1 a1435 1 d1879 1 a1879 1 d1892 1 a1892 1 } d1931 1 a1931 1 case IFT_FDDI: @ 1.61 log @improve nd6_setmtu(), to warn too-small MTU on SIOCSIFMTU. sync w/kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.60 2002/05/29 13:56:14 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.60 2002/05/29 13:56:14 itojun Exp $"); a53 2 #include #include d55 3 a59 4 #include #include #include #include d188 2 a189 5 case IFT_ARCNET: /* XXX MTU handling needs more work */ ndi->maxmtu = MIN(60480, ifp->if_mtu); break; case IFT_ETHER: ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); a192 9 break; case IFT_ATM: ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); break; case IFT_IEEE1394: ndi->maxmtu = MIN(IEEE1394MTU, ifp->if_mtu); break; case IFT_IEEE80211: ndi->maxmtu = MIN(IEEE80211_MTU, ifp->if_mtu); @ 1.60 log @missing bzero @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.59 2002/05/29 13:52:56 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.59 2002/05/29 13:52:56 itojun Exp $"); d110 1 d159 3 a161 1 nd6_setmtu(ifp, nd); d175 8 a182 1 nd6_setmtu(ifp, ndi) d186 3 d214 10 a223 4 if (ndi->maxmtu < IPV6_MMTU) { nd6log((LOG_INFO, "nd6_setmtu: " "link MTU on %s (%lu) is too small for IPv6\n", if_name(ifp), (unsigned long)ndi->maxmtu)); @ 1.59 log @receivedra field is gone @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.58 2002/05/29 07:53:41 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.58 2002/05/29 07:53:41 itojun Exp $"); d1340 1 @ 1.58 log @attach nd_ifinfo structure into if_afdata. split IPv6 link MTU (advertised by RA) from real link MTU. sync with kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.57 2002/03/20 22:47:59 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.57 2002/03/20 22:47:59 itojun Exp $"); a1347 1 ndi->ndi.receivedra = ND_IFINFO(ifp)->receivedra; @ 1.57 log @remove obsolete comment @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.56 2001/12/18 03:04:04 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.56 2001/12/18 03:04:04 itojun Exp $"); d62 1 a103 2 static size_t nd_ifinfo_indexlim = 8; struct nd_ifinfo *nd_ifinfo = NULL; d142 1 a142 1 void d146 1 d148 2 a149 7 /* * We have some arrays that should be indexed by if_index. * since if_index will grow dynamically, they should grow too. */ if (nd_ifinfo == NULL || if_index >= nd_ifinfo_indexlim) { size_t n; caddr_t q; d151 1 a151 2 while (if_index >= nd_ifinfo_indexlim) nd_ifinfo_indexlim <<= 1; d153 6 a158 10 /* grow nd_ifinfo */ n = nd_ifinfo_indexlim * sizeof(struct nd_ifinfo); q = (caddr_t)malloc(n, M_IP6NDP, M_WAITOK); bzero(q, n); if (nd_ifinfo) { bcopy((caddr_t)nd_ifinfo, q, n/2); free((caddr_t)nd_ifinfo, M_IP6NDP); } nd_ifinfo = (struct nd_ifinfo *)q; } d160 2 a161 1 #define ND nd_ifinfo[ifp->if_index] d163 4 a166 9 /* * Don't initialize if called twice. * XXX: to detect this, we should choose a member that is never set * before initialization of the ND structure itself. We formaly used * the linkmtu member, which was not suitable because it could be * initialized via "ifconfig mtu". */ if (ND.basereachable) return; d168 1 a168 13 #ifdef DIAGNOSTIC if (!ifindex2ifnet[ifp->if_index]) panic("nd6_ifattach: ifindex2ifnet is NULL"); #endif ND.linkmtu = ifindex2ifnet[ifp->if_index]->if_mtu; ND.chlim = IPV6_DEFHLIM; ND.basereachable = REACHABLE_TIME; ND.reachable = ND_COMPUTE_RTIME(ND.basereachable); ND.retrans = RETRANS_TIMER; ND.receivedra = 0; ND.flags = ND6_IFF_PERFORMNUD; nd6_setmtu(ifp); #undef ND a170 4 /* * Reset ND level link MTU. This function is called when the physical MTU * changes, which means we might have to adjust the ND level MTU. */ d172 1 a172 1 nd6_setmtu(ifp) d174 1 a175 3 struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; u_long oldmaxmtu = ndi->maxmtu; u_long oldlinkmtu = ndi->linkmtu; d184 3 d193 3 d201 4 a204 22 if (oldmaxmtu != ndi->maxmtu) { /* * If the ND level MTU is not set yet, or if the maxmtu * is reset to a smaller value than the ND level MTU, * also reset the ND level MTU. */ if (ndi->linkmtu == 0 || ndi->maxmtu < ndi->linkmtu) { ndi->linkmtu = ndi->maxmtu; /* also adjust in6_maxmtu if necessary. */ if (oldlinkmtu == 0) { /* * XXX: the case analysis is grotty, but * it is not efficient to call in6_setmaxmtu() * here when we are during the initialization * procedure. */ if (in6_maxmtu < ndi->linkmtu) in6_maxmtu = ndi->linkmtu; } else in6_setmaxmtu(); } d206 3 a208 1 #undef MIN d217 1 d395 1 a395 1 ndi = &nd_ifinfo[ifp->if_index]; d417 1 a417 1 nd_ifinfo[ifp->if_index].retrans / 1000; d472 1 a472 1 nd_ifinfo[ifp->if_index].retrans / 1000; d930 1 a930 2 ln->ln_expire = time_second + nd_ifinfo[rt->rt_ifp->if_index].reachable; d1338 12 d1351 1 a1351 5 if (!nd_ifinfo || i >= nd_ifinfo_indexlim) { error = EINVAL; break; } ndi->ndi = nd_ifinfo[ifp->if_index]; d1354 1 a1354 6 /* XXX: almost all other fields of ndi->ndi is unused */ if (!nd_ifinfo || i >= nd_ifinfo_indexlim) { error = EINVAL; break; } nd_ifinfo[ifp->if_index].flags = ndi->ndi.flags; a1684 1 int i; d1686 1 d1690 3 a1692 4 for (i = 1; i < if_index + 1; i++) { if (!nd_ifinfo || i >= nd_ifinfo_indexlim) continue; nd6if = &nd_ifinfo[i]; d1813 1 a1813 1 !(nd_ifinfo[ifp->if_index].flags & ND6_IFF_PERFORMNUD)) { d1870 1 a1870 1 nd_ifinfo[ifp->if_index].retrans / 1000; @ 1.57.6.1 log @Pull up revision 1.62 (via manual patch) (requested by itojun in ticket #145): do not hardcode if_mtu values in here, except for IFT_{ARC,FDDI} - they need special handling. makes it possible to take advantage of 9k ether frames. @ text @d1 1 a1 1 /* $NetBSD$ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d54 2 d57 2 d60 1 a61 3 #include #include d210 8 a217 2 case IFT_ARCNET: ndi->maxmtu = MIN(ARC_PHDS_MAXMTU, ifp->if_mtu); /* RFC2497 */ d219 2 a220 2 case IFT_FDDI: ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); @ 1.57.4.1 log @Catch up with -current. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.61 2002/05/30 05:06:29 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.61 2002/05/30 05:06:29 itojun Exp $"); a61 1 #include d103 2 a110 1 static void nd6_setmtu0 __P((struct ifnet *, struct nd_ifinfo *)); d143 1 a143 1 struct nd_ifinfo * a146 1 struct nd_ifinfo *nd; d148 7 a154 2 nd = (struct nd_ifinfo *)malloc(sizeof(*nd), M_IP6NDP, M_WAITOK); bzero(nd, sizeof(*nd)); d156 2 a157 1 nd->initialized = 1; d159 10 a168 5 nd->chlim = IPV6_DEFHLIM; nd->basereachable = REACHABLE_TIME; nd->reachable = ND_COMPUTE_RTIME(nd->basereachable); nd->retrans = RETRANS_TIMER; nd->flags = ND6_IFF_PERFORMNUD; d170 1 a170 2 /* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */ nd6_setmtu0(ifp, nd); d172 9 a180 2 return nd; } d182 13 a194 6 void nd6_ifdetach(nd) struct nd_ifinfo *nd; { free(nd, M_IP6NDP); d197 4 d205 3 a207 11 nd6_setmtu0(ifp, ND_IFINFO(ifp)); } void nd6_setmtu0(ifp, ndi) struct ifnet *ifp; struct nd_ifinfo *ndi; { u_int32_t omaxmtu; omaxmtu = ndi->maxmtu; a215 3 case IFT_FDDI: ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); break; a221 3 case IFT_IEEE80211: ndi->maxmtu = MIN(IEEE80211_MTU, ifp->if_mtu); break; d227 22 a248 10 /* * Decreasing the interface MTU under IPV6 minimum MTU may cause * undesirable situation. We thus notify the operator of the change * explicitly. The check for omaxmtu is necessary to restrict the * log to the case of changing the MTU, not initializing it. */ if (omaxmtu >= IPV6_MMTU && ndi->maxmtu < IPV6_MMTU) { log(LOG_NOTICE, "nd6_setmtu0: " "new link MTU on %s (%lu) is too small for IPv6\n", if_name(ifp), (unsigned long)ndi->maxmtu); d250 1 a250 3 if (ndi->maxmtu > in6_maxmtu) in6_setmaxmtu(); /* check all interfaces just in case */ a258 1 d436 1 a436 1 ndi = ND_IFINFO(ifp); d458 1 a458 1 ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); d513 1 a513 1 ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); d971 2 a972 1 ln->ln_expire = time_second + ND_IFINFO(rt->rt_ifp)->reachable; a1379 12 case OSIOCGIFINFO_IN6: /* XXX: old ndp(8) assumes a positive value for linkmtu. */ bzero(&ndi->ndi, sizeof(ndi->ndi)); ndi->ndi.linkmtu = IN6_LINKMTU(ifp); ndi->ndi.maxmtu = ND_IFINFO(ifp)->maxmtu; ndi->ndi.basereachable = ND_IFINFO(ifp)->basereachable; ndi->ndi.reachable = ND_IFINFO(ifp)->reachable; ndi->ndi.retrans = ND_IFINFO(ifp)->retrans; ndi->ndi.flags = ND_IFINFO(ifp)->flags; ndi->ndi.recalctm = ND_IFINFO(ifp)->recalctm; ndi->ndi.chlim = ND_IFINFO(ifp)->chlim; break; d1381 5 a1385 1 ndi->ndi = *ND_IFINFO(ifp); d1388 6 a1393 1 ND_IFINFO(ifp)->flags = ndi->ndi.flags; d1724 1 a1725 1 struct ifnet *ifp; d1729 4 a1732 3 for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { nd6if = ND_IFINFO(ifp); d1853 1 a1853 1 !(ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD)) { d1910 1 a1910 1 ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); @ 1.57.4.2 log @catch up with -current. @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.66 2002/06/09 14:43:13 itojun Exp $ */ /* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.66 2002/06/09 14:43:13 itojun Exp $"); d54 2 d57 2 d60 1 d62 1 a62 3 #include #include d67 1 a116 3 static int fill_drlist __P((void *, size_t *, size_t)); static int fill_prlist __P((void *, size_t *, size_t)); d158 1 a158 6 /* * Note that the default value of ip6_accept_rtadv is 0, which means * we won't accept RAs by default even if we set ND6_IFF_ACCEPT_RTADV * here. */ nd->flags = (ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV); d191 5 a195 2 case IFT_ARCNET: ndi->maxmtu = MIN(ARC_PHDS_MAXMTU, ifp->if_mtu); /* RFC2497 */ d200 9 d218 1 a218 1 * log to the case of changing the MTU, not initializing it. d392 1 a392 4 struct ifnet *ifp; struct in6_ifaddr *ia6, *nia6; struct in6_addrlifetime *lt6; d400 1 d438 1 a438 1 ln, 0); d442 10 a451 9 /* * Fake rcvif to make the ICMP error * more helpful in diagnosing for the * receiver. * XXX: should we consider * older rcvif? */ m->m_pkthdr.rcvif = rt->rt_ifp; d478 1 a478 1 ND6_RETRANS_SEC(ndi->retrans); d480 2 a481 1 &dst->sin6_addr, ln, 0); d493 1 a493 1 &dst->sin6_addr, ln, 0); d501 1 a501 1 d514 9 d524 10 a533 12 /* * expire interface addresses. * in the past the loop was inside prefix expiry processing. * However, from a stricter speci-confrmance standpoint, we should * rather separate address lifetimes and prefix lifetimes. */ for (ia6 = in6_ifaddr; ia6; ia6 = nia6) { nia6 = ia6->ia_next; /* check address lifetime */ lt6 = &ia6->ia6_lifetime; if (IFA6_IS_INVALID(ia6)) { in6_purgeaddr(&ia6->ia_ifa); a534 10 if (IFA6_IS_DEPRECATED(ia6)) { ia6->ia6_flags |= IN6_IFF_DEPRECATED; } else { /* * A new RA might have made a deprecated address * preferred. */ ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; } } a535 3 /* expire prefix list */ pr = nd_prefix.lh_first; while (pr) { d540 5 d546 2 a547 2 if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME && time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) { d553 1 a553 1 * separate. NEVER perform in6_purgeaddr here. d573 1 a573 1 struct nd_defrouter *dr, *ndr; d576 12 a587 19 /* * Nuke default router list entries toward ifp. * We defer removal of default router list entries that is installed * in the routing table, in order to keep additional side effects as * small as possible. */ for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) { ndr = TAILQ_NEXT(dr, dr_entry); if (dr->installed) continue; if (dr->ifp == ifp) defrtrlist_del(dr); } for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) { ndr = TAILQ_NEXT(dr, dr_entry); if (!dr->installed) continue; d596 2 a597 8 /* * Previously, pr->ndpr_addr is removed as well, * but I strongly believe we don't have to do it. * nd6_purge() is only called from in6_ifdetach(), * which removes all the associated interface addresses * by itself. * (jinmei@@kame.net 20010129) */ d608 2 d674 1 a674 1 ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); d685 6 a690 3 ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) != 0) { d703 1 a703 1 (struct llinfo_nd6 *)rt->rt_llinfo; a711 4 * Note that the check for rt_llinfo is necessary because a cloned * route from a parent route that has the L flag (e.g. the default * route to a p2p interface) may have the flag, too, while the * destination is not actually a neighbor. d715 1 a715 2 * use rt->rt_ifa->ifa_ifp, which would specify the REAL * interface. d718 1 a718 1 rt->rt_gateway->sa_family != AF_LINK || rt->rt_llinfo == NULL || d721 2 a722 4 log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec"); d724 1 a724 1 return(NULL); d738 5 a742 2 struct nd_prefix *pr; struct rtentry *rt; d755 2 a756 2 * If the address matches one of our on-link prefixes, it should be a * neighbor. d758 6 a763 3 for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { if (pr->ndpr_ifp != ifp) continue; d765 6 a770 16 if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) continue; if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, &addr->sin6_addr, &pr->ndpr_mask)) return (1); } /* * If the default router list is empty, all addresses are regarded * as on-link, and thus, as a neighbor. * XXX: we restrict the condition to hosts, because routers usually do * not have the "default router list". */ if (!ip6_forwarding && TAILQ_FIRST(&nd_defrouter) == NULL && nd6_defifindex == ifp->if_index) { d778 1 a778 1 if ((rt = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL) d782 2 d810 1 a810 1 rt->rt_ifp); d864 13 a876 4 /* * refresh default router list */ defrouter_select(); d895 1 a895 1 rt_mask(rt), 0, (struct rtentry **)0); a963 1 int mine = 0; d965 1 a965 1 if ((rt->rt_flags & RTF_GATEWAY) != 0) a978 21 if (req == RTM_RESOLVE && (nd6_need_cache(ifp) == 0 || /* stf case */ !nd6_is_addr_neighbor((struct sockaddr_in6 *)rt_key(rt), ifp))) { /* * FreeBSD and BSD/OS often make a cloned host route based * on a less-specific route (e.g. the default route). * If the less specific route does not have a "gateway" * (this is the case when the route just goes to a p2p or an * stf interface), we'll mistakenly make a neighbor cache for * the host route, and will see strange neighbor solicitation * for the corresponding destination. In order to avoid the * confusion, we check if the destination of the route is * a neighbor in terms of neighbor discovery, and stop the * process if not. Additionally, we remove the LLINFO flag * so that ndp(8) will not try to get the neighbor information * of the destination. */ rt->rt_flags &= ~RTF_LLINFO; return; } d1006 1 a1006 1 printf("nd6_rtrequest: time.tv_sec is zero; " d1012 1 a1012 1 if ((rt->rt_flags & RTF_CLONING) != 0) d1044 1 a1044 1 if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { d1103 1 a1103 1 &SIN6(rt_key(rt))->sin6_addr); a1108 1 mine = 1; d1187 59 d1253 1 a1253 1 struct in6_oprlist *oprl = (struct in6_oprlist *)data; d1257 1 a1257 1 struct nd_defrouter *dr; a1264 3 /* * obsolete API, use sysctl under net.inet6.icmp6 */ a1289 7 * obsolete API, use sysctl under net.inet6.icmp6 * * XXX the structure in6_prlist was changed in backward- * incompatible manner. in6_oprlist is used for SIOCGPRLST_IN6, * in6_prlist is used for nd6_sysctl() - fill_prlist(). */ /* d1294 1 a1294 1 bzero(oprl, sizeof(*oprl)); d1301 7 a1307 7 oprl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; oprl->prefix[i].raflags = pr->ndpr_raf; oprl->prefix[i].prefixlen = pr->ndpr_plen; oprl->prefix[i].vltime = pr->ndpr_vltime; oprl->prefix[i].pltime = pr->ndpr_pltime; oprl->prefix[i].if_index = pr->ndpr_ifp->if_index; oprl->prefix[i].expire = pr->ndpr_expire; d1313 1 a1313 1 #define RTRADDR oprl->prefix[i].advrtr[j] d1329 2 a1330 2 oprl->prefix[i].advrtrs = j; oprl->prefix[i].origin = PR_ORIG_RA; d1335 19 d1376 7 a1382 2 /* sync kernel routing table with the default router list */ defrouter_reset(); d1384 1 d1387 1 a1387 1 { a1392 2 struct in6_ifaddr *ia, *ia_next; d1394 2 a1395 15 if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) continue; /* XXX */ /* do we really have to remove addresses as well? */ for (ia = in6_ifaddr; ia; ia = ia_next) { /* ia might be removed. keep the next ptr. */ ia_next = ia->ia_next; if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; if (ia->ia6_ndpr == pr) in6_purgeaddr(&ia->ia_ifa); } d1400 1 a1400 1 } d1402 1 a1402 1 { d1407 10 a1416 4 defrouter_reset(); for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = next) { next = TAILQ_NEXT(dr, dr_entry); defrtrlist_del(dr); a1417 1 defrouter_select(); d1420 1 a1420 1 } d1439 1 a1439 2 if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL || (ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) { d1444 1 d1450 1 a1450 1 d1452 1 a1452 1 } d1568 2 a1569 2 if ((!olladdr && lladdr) || /* (3) */ (olladdr && lladdr && llchange)) { /* (5) */ d1603 2 a1604 1 (struct sockaddr_in6 *)rt_key(rt), rt); d1671 2 a1672 2 if ((!is_newentry && (olladdr || lladdr)) || /* (2-5) */ (is_newentry && lladdr)) { /* (7) */ d1754 2 a1755 2 if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1)) != NULL) d1761 1 a1761 1 dst, rt); d1773 1 a1773 1 * of view, regardless of the value of nd_ifinfo.flags. d1875 3 d1884 8 a1891 15 /* * If there has been no NS for the neighbor after entering the * INCOMPLETE state, send the first solicitation. * Technically this can be against the rate-limiting rule described in * Section 7.2.2 of RFC 2461 because the interval to the next scheduled * solicitation issued in nd6_timer() may be less than the specified * retransmission time. This should not be a problem from a practical * point of view, because we'll typically see an immediate response * from the neighbor, which suppresses the succeeding solicitations. */ if (ln->ln_expire && ln->ln_asked == 0) { ln->ln_asked++; ln->ln_expire = time_second + ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); d1894 1 a1894 1 d1907 1 a1907 1 } d1946 1 a1946 1 case IFT_FDDI: d1976 1 a1976 1 ip6_sprintf(&SIN6(dst)->sin6_addr), if_name(ifp)); a1982 190 } int nd6_sysctl(name, oldp, oldlenp, newp, newlen) int name; void *oldp; size_t *oldlenp; void *newp; size_t newlen; { size_t ol, l; int error; error = 0; l = 0; if (newp) return EPERM; if (oldp && !oldlenp) return EINVAL; ol = oldlenp ? *oldlenp : 0; switch (name) { case ICMPV6CTL_ND6_DRLIST: error = fill_drlist(oldp, oldlenp, ol); break; case ICMPV6CTL_ND6_PRLIST: error = fill_prlist(oldp, oldlenp, ol); break; default: error = ENOPROTOOPT; break; } return(error); } static int fill_drlist(oldp, oldlenp, ol) void *oldp; size_t *oldlenp, ol; { int error = 0, s; struct in6_defrouter *d = NULL, *de = NULL; struct nd_defrouter *dr; size_t l; s = splsoftnet(); if (oldp) { d = (struct in6_defrouter *)oldp; de = (struct in6_defrouter *)((caddr_t)oldp + *oldlenp); } l = 0; for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = TAILQ_NEXT(dr, dr_entry)) { if (oldp && d + 1 <= de) { bzero(d, sizeof(*d)); d->rtaddr.sin6_family = AF_INET6; d->rtaddr.sin6_len = sizeof(struct sockaddr_in6); d->rtaddr.sin6_addr = dr->rtaddr; in6_recoverscope(&d->rtaddr, &d->rtaddr.sin6_addr, dr->ifp); d->flags = dr->flags; d->rtlifetime = dr->rtlifetime; d->expire = dr->expire; d->if_index = dr->ifp->if_index; } l += sizeof(*d); if (d) d++; } if (oldp) { *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ if (l > ol) error = ENOMEM; } else *oldlenp = l; splx(s); return(error); } static int fill_prlist(oldp, oldlenp, ol) void *oldp; size_t *oldlenp, ol; { int error = 0, s; struct nd_prefix *pr; struct in6_prefix *p = NULL; struct in6_prefix *pe = NULL; size_t l; s = splsoftnet(); if (oldp) { p = (struct in6_prefix *)oldp; pe = (struct in6_prefix *)((caddr_t)oldp + *oldlenp); } l = 0; for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { u_short advrtrs; size_t advance; struct sockaddr_in6 *sin6; struct sockaddr_in6 *s6; struct nd_pfxrouter *pfr; if (oldp && p + 1 <= pe) { bzero(p, sizeof(*p)); sin6 = (struct sockaddr_in6 *)(p + 1); p->prefix = pr->ndpr_prefix; if (in6_recoverscope(&p->prefix, &p->prefix.sin6_addr, pr->ndpr_ifp) != 0) log(LOG_ERR, "scope error in prefix list (%s)\n", ip6_sprintf(&p->prefix.sin6_addr)); p->raflags = pr->ndpr_raf; p->prefixlen = pr->ndpr_plen; p->vltime = pr->ndpr_vltime; p->pltime = pr->ndpr_pltime; p->if_index = pr->ndpr_ifp->if_index; if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) p->expire = 0; else { time_t maxexpire; /* XXX: we assume time_t is signed. */ maxexpire = (-1) & ~(1 << ((sizeof(maxexpire) * 8) - 1)); if (pr->ndpr_vltime < maxexpire - pr->ndpr_lastupdate) { p->expire = pr->ndpr_lastupdate + pr->ndpr_vltime; } else p->expire = maxexpire; } p->refcnt = pr->ndpr_refcnt; p->flags = pr->ndpr_stateflags; p->origin = PR_ORIG_RA; advrtrs = 0; for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = pfr->pfr_next) { if ((void *)&sin6[advrtrs + 1] > (void *)pe) { advrtrs++; continue; } s6 = &sin6[advrtrs]; s6->sin6_family = AF_INET6; s6->sin6_len = sizeof(struct sockaddr_in6); s6->sin6_addr = pfr->router->rtaddr; in6_recoverscope(s6, &s6->sin6_addr, pfr->router->ifp); advrtrs++; } p->advrtrs = advrtrs; } else { advrtrs = 0; for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = pfr->pfr_next) advrtrs++; } advance = sizeof(*p) + sizeof(*sin6) * advrtrs; l += advance; if (p) p = (struct in6_prefix *)((caddr_t)p + advance); } if (oldp) { *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ if (l > ol) error = ENOMEM; } else *oldlenp = l; splx(s); return(error); @ 1.57.4.3 log @catch up with -current. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.71 2002/08/19 23:23:22 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.71 2002/08/19 23:23:22 itojun Exp $"); d1951 1 a1951 1 void *oldp; /* syscall arg, need copyout */ d1953 1 a1953 1 void *newp; /* syscall arg, need copyin */ a1955 1 void *p; a1967 6 if (oldp) { p = malloc(*oldlenp, M_TEMP, M_WAITOK); if (!p) return ENOMEM; } else p = NULL; d1970 1 a1970 3 error = fill_drlist(p, oldlenp, ol); if (!error && p && oldp) error = copyout(p, oldp, *oldlenp); d1974 1 a1974 3 error = fill_prlist(p, oldlenp, ol); if (!error && p && oldp) error = copyout(p, oldp, *oldlenp); a1980 2 if (p) free(p, M_TEMP); @ 1.56 log @reduce white space/cosmetic diffs w/kame. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.55 2001/11/13 00:57:04 lukem Exp $ */ a32 8 /* * XXX * KAME 970409 note: * BSD/OS version heavily modifies this code, related to llinfo. * Since we don't have BSD/OS version of net/route.c in our hand, * I left the code mostly as it was in 970310. -- itojun */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.55 2001/11/13 00:57:04 lukem Exp $"); @ 1.55 log @add RCSIDs @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.54 2001/10/17 10:55:09 itojun Exp $ */ d42 1 a42 1 __KERNEL_RCSID(0, "$NetBSD$"); a427 1 /* XXX BSD/OS separates this code -- itojun */ d996 1 a996 1 if (rt->rt_flags & RTF_GATEWAY) d1043 1 a1043 1 if (rt->rt_flags & RTF_CLONING) d1802 2 a1803 3 * of view, regardless the value of the * nd_ifinfo.flags. * The second condition is a bit tricky: we skip d2004 2 a2005 1 printf("nd6_storelladdr: sdl_alen == 0\n"); @ 1.54 log @do not change neighbor cache state on entry timeout, if the cache entry is for outgoing router. perform on-linkness check before default router (re-)seletion. do not play with interface direct route on nd6_rtrequest. sync a lot of cosmetic changes. sync with kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.53 2001/10/17 08:23:07 itojun Exp $ */ d40 3 @ 1.53 log @unifdef OLDIP6OUTPUT @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.52 2001/10/16 06:24:45 itojun Exp $ */ d117 1 d449 1 a449 1 d484 1 a484 1 next = nd6_free(rt); d497 1 a497 1 next = nd6_free(rt); d522 3 a524 2 } else next = nd6_free(rt); d658 1 a658 1 nln = nd6_free(rt); d718 2 a719 1 &rt)) != 0) d724 3 a750 1 /* xxx more logs... kazu */ d816 3 d820 2 a821 2 struct llinfo_nd6 * nd6_free(rt) d823 1 d830 2 a831 2 * Clear all destination cache entries for the neighbor. * XXX: is it better to restrict this to hosts? a832 1 pfctlinput(PRC_HOSTDEAD, rt_key(rt)); d839 20 d878 1 a878 1 * prefixes coreectly. d884 8 a904 1 pfxlist_onlink_check(); d997 11 d1035 1 a1035 1 printf("nd6_request: time.tv_sec is zero; " d1143 1 a1143 1 rt->rt_ifp = &loif[0]; /*XXX*/ d1176 3 a1178 4 nd6log((LOG_ERR, "%s: " "failed to join %s (errno=%d)\n", if_name(ifp), ip6_sprintf(&llsol), error)); d1552 1 a1552 1 (void)nd6_free(rt); d1697 2 a1698 2 if ((!is_newentry && (olladdr || lladdr)) /*(2-5)*/ || (is_newentry && lladdr)) { /*(7)*/ d1773 1 a1773 15 /* * XXX: we currently do not make neighbor cache on any interface * other than ARCnet, Ethernet, FDDI and GIF. * * RFC2893 says: * - unidirectional tunnels needs no ND */ switch (ifp->if_type) { case IFT_ARCNET: case IFT_ETHER: case IFT_FDDI: case IFT_IEEE1394: case IFT_GIF: /* XXX need more cases? */ break; default: a1774 1 } d1777 1 a1777 1 * next hop determination. This routine is derived from ether_outpout. d1937 23 @ 1.52 log @more whitespace/comment sync with kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.51 2001/07/25 06:59:52 itojun Exp $ */ a945 97 #ifdef OLDIP6OUTPUT /* * Resolve an IP6 address into an ethernet address. If success, * desten is filled in. If there is no entry in ndptab, * set one up and multicast a solicitation for the IP6 address. * Hold onto this mbuf and resend it once the address * is finally resolved. A return value of 1 indicates * that desten has been filled in and the packet should be sent * normally; a 0 return indicates that the packet has been * taken over here, either now or for later transmission. */ int nd6_resolve(ifp, rt, m, dst, desten) struct ifnet *ifp; struct rtentry *rt; struct mbuf *m; struct sockaddr *dst; u_char *desten; { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL; struct sockaddr_dl *sdl; long time_second = time.tv_sec; if (m->m_flags & M_MCAST) { switch (ifp->if_type) { case IFT_ETHER: case IFT_FDDI: ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, desten); return(1); case IFT_IEEE1394: bcopy(ifp->if_broadcastaddr, desten, ifp->if_addrlen); return(1); case IFT_ARCNET: *desten = 0; return(1); default: m_freem(m); return(0); } } if (rt && (rt->rt_flags & RTF_LLINFO) != 0) ln = (struct llinfo_nd6 *)rt->rt_llinfo; else { if ((rt = nd6_lookup(&(SIN6(dst)->sin6_addr), 1, ifp)) != NULL) ln = (struct llinfo_nd6 *)rt->rt_llinfo; } if (!ln || !rt) { log(LOG_DEBUG, "nd6_resolve: can't allocate llinfo for %s\n", ip6_sprintf(&(SIN6(dst)->sin6_addr))); m_freem(m); return(0); } sdl = SDL(rt->rt_gateway); /* * Ckeck the address family and length is valid, the address * is resolved; otherwise, try to resolve. */ if (ln->ln_state >= ND6_LLINFO_REACHABLE && sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { bcopy(LLADDR(sdl), desten, sdl->sdl_alen); if (ln->ln_state == ND6_LLINFO_STALE) { ln->ln_asked = 0; ln->ln_state = ND6_LLINFO_DELAY; ln->ln_expire = time_second + nd6_delay; } return(1); } /* * There is an ndp entry, but no ethernet address * response yet. Replace the held mbuf with this * latest one. * * XXX Does the code conform to rate-limiting rule? * (RFC 2461 7.2.2) */ if (ln->ln_state == ND6_LLINFO_NOSTATE) ln->ln_state = ND6_LLINFO_INCOMPLETE; if (ln->ln_hold) m_freem(ln->ln_hold); ln->ln_hold = m; if (ln->ln_expire) { if (ln->ln_asked < nd6_mmaxtries && ln->ln_expire < time_second) { ln->ln_asked++; ln->ln_expire = time_second + nd_ifinfo[ifp->if_index].retrans / 1000; nd6_ns_output(ifp, NULL, &(SIN6(dst)->sin6_addr), ln, 0); } } /* do not free mbuf here, it is queued into llinfo_nd6 */ return(0); } #endif /* OLDIP6OUTPUT */ a1578 7 #ifdef OLDIP6OUTPUT ln->ln_asked = 0; ln->ln_state = ND6_LLINFO_DELAY; ln->ln_expire = time_second + nd6_delay; (*ifp->if_output)(ifp, ln->ln_hold, rt_key(rt), rt); #else a1585 1 #endif @ 1.51 log @ifidex2ifnet could contain NULL after if_detach(). sync with kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.50 2001/07/20 20:26:35 itojun Exp $ */ d705 1 a705 1 * Create a new route. RTF_LLINFO is necessary d708 1 a708 1 * called in rtequest via ifa->ifa_rtrequest. d771 1 d878 1 a878 1 * a side effect (XXX). d1071 1 a1071 1 * a route to interface. RTF_LLINFO flag is set d1543 1 a1543 1 * on reception of inbound ND6 packets. (RS/RA/NS/redirect) d1636 1 a1636 1 if (lladdr) { /*(3-5) and (7)*/ d1646 2 a1647 2 if ((!olladdr && lladdr) /*(3)*/ || (olladdr && lladdr && llchange)) { /*(5)*/ d1650 1 a1650 1 } else /*(1-2,4)*/ d1654 1 a1654 1 if (!lladdr) /*(6)*/ d1656 1 a1656 1 else /*(7)*/ d1733 1 a1733 1 if (is_newentry) /*(6-7)*/ d1739 2 a1740 2 * is_router flag. Otherwise, if the entry is newly created, * clear the flag. [RFC 2461, sec 8.3] d1744 1 a1744 1 else if (is_newentry) /*(6-7)*/ d1775 3 d1926 1 a1926 1 * the condition below is not very efficient. But we believe d1968 1 a1968 1 * (i.e. its link-layer address is already reloved), just d1976 1 a1976 1 * response yet. Replace the held mbuf (if any) with this d1978 3 a1980 3 * * XXX Does the code conform to rate-limiting rule? * (RFC 2461 7.2.2) @ 1.50 log @sync rt_ifp check with IPv4 counterpart (see sys/net/if_ethersubr.c 1.27). sync with kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.49 2001/06/29 16:01:47 itojun Exp $ */ d186 4 @ 1.49 log @call defrouter_select() only if it is autoconfigured host. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.48 2001/06/27 17:36:14 itojun Exp $ */ d1890 2 a1891 1 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); d1894 7 @ 1.49.2.1 log @update to -current @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.51 2001/07/25 06:59:52 itojun Exp $ */ a185 4 #ifdef DIAGNOSTIC if (!ifindex2ifnet[ifp->if_index]) panic("nd6_ifattach: ifindex2ifnet is NULL"); #endif d1890 1 a1890 2 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); a1892 7 /* the "G" test below also prevents rt == rt0 */ if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_ifp != ifp)) { rt->rt_refcnt--; rt0->rt_gwroute = 0; senderr(EHOSTUNREACH); } @ 1.49.2.2 log @Sync kqueue branch with -current. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.49.2.1 2001/08/03 04:14:00 lukem Exp $ */ a40 3 #include __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.56 2001/12/18 03:04:04 itojun Exp $"); a116 1 static struct llinfo_nd6 *nd6_free __P((struct rtentry *, int)); d424 1 d448 1 a448 1 d483 1 a483 1 next = nd6_free(rt, 0); d496 1 a496 1 next = nd6_free(rt, 1); d521 2 a522 3 } else { next = nd6_free(rt, 0); } d656 1 a656 1 nln = nd6_free(rt, 0); d705 1 a705 1 * Create a new route. RTF_LLINFO is necessary d708 1 a708 1 * called in rtrequest via ifa->ifa_rtrequest. d716 1 a716 2 &rt)) != 0) { #if 0 a720 3 #endif return(NULL); } d745 1 a770 1 * XXX: a link does not necessarily specify a single interface. a809 3 * Since the function would cause significant changes in the kernel, DO NOT * make it global, unless you have a strong reason for the change, and are sure * that the change is safe. d811 2 a812 2 static struct llinfo_nd6 * nd6_free(rt, gc) a813 1 int gc; d820 2 a821 2 * we used to have pfctlinput(PRC_HOSTDEAD) here. * even though it is not harmful, it was not really necessary. d823 1 a829 20 if (dr != NULL && dr->expire && ln->ln_state == ND6_LLINFO_STALE && gc) { /* * If the reason for the deletion is just garbage * collection, and the neighbor is an active default * router, do not delete it. Instead, reset the GC * timer using the router's lifetime. * Simply deleting the entry would affect default * router selection, which is not necessarily a good * thing, especially when we're using router preference * values. * XXX: the check for ln_state would be redundant, * but we intentionally keep it just in case. */ ln->ln_expire = dr->expire; splx(s); return(ln->ln_next); } d849 1 a849 1 * prefixes correctly. a854 8 /* * Since defrouter_select() does not affect the * on-link determination and MIP6 needs the check * before the default router selection, we perform * the check now. */ pfxlist_onlink_check(); d868 1 d877 1 a877 1 * a side effect (XXX). d945 97 d1055 1 a1055 1 if ((rt->rt_flags & RTF_GATEWAY)) a1057 11 if (nd6_need_cache(ifp) == 0 && (rt->rt_flags & RTF_HOST) == 0) { /* * This is probably an interface direct route for a link * which does not need neighbor caches (e.g. fe80::%lo0/64). * We do not need special treatment below for such a route. * Moreover, the RTF_LLINFO flag which would be set below * would annoy the ndp(8) command. */ return; } d1070 1 a1070 1 * a route to interface. RTF_LLINFO flag is set d1085 1 a1085 1 printf("nd6_rtequest: time.tv_sec is zero; " d1091 1 a1091 1 if ((rt->rt_flags & RTF_CLONING)) d1193 1 a1193 1 rt->rt_ifp = &loif[0]; /* XXX */ d1226 4 a1229 3 nd6log((LOG_ERR, "%s: failed to join " "%s (errno=%d)\n", if_name(ifp), ip6_sprintf(&llsol), error)); d1542 1 a1542 1 * on reception of inbound ND6 packets. (RS/RA/NS/redirect) d1603 1 a1603 1 (void)nd6_free(rt, 0); d1635 1 a1635 1 if (lladdr) { /* (3-5) and (7) */ d1645 2 a1646 2 if ((!olladdr && lladdr) /* (3) */ || (olladdr && lladdr && llchange)) { /* (5) */ d1649 1 a1649 1 } else /* (1-2,4) */ d1653 1 a1653 1 if (!lladdr) /* (6) */ d1655 1 a1655 1 else /* (7) */ d1675 7 d1689 1 d1732 1 a1732 1 if (is_newentry) /* (6-7) */ d1738 2 a1739 2 * is_router flag. Otherwise, if the entry is newly created, * clear the flag. [RFC 2461, sec 8.3] d1743 1 a1743 1 else if (is_newentry) /* (6-7) */ d1756 2 a1757 2 if ((!is_newentry && (olladdr || lladdr)) /* (2-5) */ || (is_newentry && lladdr)) { /* (7) */ a1773 3 * XXX: although defrouter_select() should not have a bad effect * for those are not autoconfigured hosts, we explicitly avoid such * cases for safety. d1829 15 a1843 1 if (nd6_need_cache(ifp) == 0) d1845 1 d1848 1 a1848 1 * next hop determination. This routine is derived from ether_outpout. d1871 3 a1873 2 * of view, regardless the value of nd_ifinfo.flags. * The second condition is a bit tricky; we skip d1922 1 a1922 1 * the condition below is not very efficient. But we believe d1964 1 a1964 1 * (i.e. its link-layer address is already resolved), just d1972 1 a1972 1 * response yet. Replace the held mbuf (if any) with this d1974 3 a1976 3 * This code conforms to the rate-limiting rule described in Section * 7.2.2 of RFC 2461, because the timer is set correctly after sending * an NS below. a2009 23 nd6_need_cache(ifp) struct ifnet *ifp; { /* * XXX: we currently do not make neighbor cache on any interface * other than ARCnet, Ethernet, FDDI and GIF. * * RFC2893 says: * - unidirectional tunnels needs no ND */ switch (ifp->if_type) { case IFT_ARCNET: case IFT_ETHER: case IFT_FDDI: case IFT_IEEE1394: case IFT_GIF: /* XXX need more cases? */ return(1); default: return(0); } } int d2051 1 a2051 2 printf("nd6_storelladdr: sdl_alen == 0, dst=%s, if=%s\n", ip6_sprintf(&SIN6(dst)->sin6_addr), if_name(ifp)); @ 1.49.2.3 log @catch up with -current on kqueue branch @ text @d1 2 a2 2 /* $NetBSD$ */ /* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */ d33 8 d42 1 a42 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.49.2.2 2002/01/10 20:03:27 thorpej Exp $"); d62 2 d65 2 d68 1 a69 3 #include #include d74 1 d111 2 a118 1 static void nd6_setmtu0 __P((struct ifnet *, struct nd_ifinfo *)); a124 3 static int fill_drlist __P((void *, size_t *, size_t)); static int fill_prlist __P((void *, size_t *, size_t)); d151 1 a151 1 struct nd_ifinfo * a154 4 struct nd_ifinfo *nd; nd = (struct nd_ifinfo *)malloc(sizeof(*nd), M_IP6NDP, M_WAITOK); bzero(nd, sizeof(*nd)); a155 6 nd->initialized = 1; nd->chlim = IPV6_DEFHLIM; nd->basereachable = REACHABLE_TIME; nd->reachable = ND_COMPUTE_RTIME(nd->basereachable); nd->retrans = RETRANS_TIMER; d157 2 a158 3 * Note that the default value of ip6_accept_rtadv is 0, which means * we won't accept RAs by default even if we set ND6_IFF_ACCEPT_RTADV * here. d160 6 a165 1 nd->flags = (ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV); d167 10 a176 2 /* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */ nd6_setmtu0(ifp, nd); d178 1 a178 2 return nd; } d180 9 a188 4 void nd6_ifdetach(nd) struct nd_ifinfo *nd; { d190 13 a202 1 free(nd, M_IP6NDP); d205 4 d213 3 a215 11 nd6_setmtu0(ifp, ND_IFINFO(ifp)); } void nd6_setmtu0(ifp, ndi) struct ifnet *ifp; struct nd_ifinfo *ndi; { u_int32_t omaxmtu; omaxmtu = ndi->maxmtu; d218 8 a225 2 case IFT_ARCNET: ndi->maxmtu = MIN(ARC_PHDS_MAXMTU, ifp->if_mtu); /* RFC2497 */ d227 2 a228 2 case IFT_FDDI: ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); d235 22 a256 10 /* * Decreasing the interface MTU under IPV6 minimum MTU may cause * undesirable situation. We thus notify the operator of the change * explicitly. The check for omaxmtu is necessary to restrict the * log to the case of changing the MTU, not initializing it. */ if (omaxmtu >= IPV6_MMTU && ndi->maxmtu < IPV6_MMTU) { log(LOG_NOTICE, "nd6_setmtu0: " "new link MTU on %s (%lu) is too small for IPv6\n", if_name(ifp), (unsigned long)ndi->maxmtu); d258 1 a258 3 if (ndi->maxmtu > in6_maxmtu) in6_setmaxmtu(); /* check all interfaces just in case */ a266 1 d422 1 a422 4 struct ifnet *ifp; struct in6_ifaddr *ia6, *nia6; struct in6_addrlifetime *lt6; d430 1 d444 1 a444 1 ndi = ND_IFINFO(ifp); d466 1 a466 1 ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); d468 1 a468 1 ln, 0); d472 10 a481 9 /* * Fake rcvif to make the ICMP error * more helpful in diagnosing for the * receiver. * XXX: should we consider * older rcvif? */ m->m_pkthdr.rcvif = rt->rt_ifp; d508 1 a508 1 ND6_RETRANS_SEC(ndi->retrans); d510 2 a511 1 &dst->sin6_addr, ln, 0); d521 1 a521 1 ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); d523 1 a523 1 &dst->sin6_addr, ln, 0); d531 1 a531 1 d544 4 d549 15 a563 12 /* * expire interface addresses. * in the past the loop was inside prefix expiry processing. * However, from a stricter speci-confrmance standpoint, we should * rather separate address lifetimes and prefix lifetimes. */ for (ia6 = in6_ifaddr; ia6; ia6 = nia6) { nia6 = ia6->ia_next; /* check address lifetime */ lt6 = &ia6->ia6_lifetime; if (IFA6_IS_INVALID(ia6)) { in6_purgeaddr(&ia6->ia_ifa); a564 10 if (IFA6_IS_DEPRECATED(ia6)) { ia6->ia6_flags |= IN6_IFF_DEPRECATED; } else { /* * A new RA might have made a deprecated address * preferred. */ ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; } } a565 3 /* expire prefix list */ pr = nd_prefix.lh_first; while (pr) { d570 5 d576 2 a577 2 if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME && time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) { d583 1 a583 1 * separate. NEVER perform in6_purgeaddr here. d603 1 a603 1 struct nd_defrouter *dr, *ndr; d606 12 a617 19 /* * Nuke default router list entries toward ifp. * We defer removal of default router list entries that is installed * in the routing table, in order to keep additional side effects as * small as possible. */ for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) { ndr = TAILQ_NEXT(dr, dr_entry); if (dr->installed) continue; if (dr->ifp == ifp) defrtrlist_del(dr); } for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) { ndr = TAILQ_NEXT(dr, dr_entry); if (!dr->installed) continue; d626 2 a627 8 /* * Previously, pr->ndpr_addr is removed as well, * but I strongly believe we don't have to do it. * nd6_purge() is only called from in6_ifdetach(), * which removes all the associated interface addresses * by itself. * (jinmei@@kame.net 20010129) */ d638 2 d704 1 a704 1 ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); d715 6 a720 3 ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) != 0) { d733 1 a733 1 (struct llinfo_nd6 *)rt->rt_llinfo; a741 4 * Note that the check for rt_llinfo is necessary because a cloned * route from a parent route that has the L flag (e.g. the default * route to a p2p interface) may have the flag, too, while the * destination is not actually a neighbor. d745 1 a745 2 * use rt->rt_ifa->ifa_ifp, which would specify the REAL * interface. d748 1 a748 1 rt->rt_gateway->sa_family != AF_LINK || rt->rt_llinfo == NULL || d751 2 a752 4 log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec"); d754 1 a754 1 return(NULL); d768 5 a772 2 struct nd_prefix *pr; struct rtentry *rt; d785 2 a786 2 * If the address matches one of our on-link prefixes, it should be a * neighbor. d788 6 a793 3 for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { if (pr->ndpr_ifp != ifp) continue; d795 6 a800 16 if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) continue; if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, &addr->sin6_addr, &pr->ndpr_mask)) return (1); } /* * If the default router list is empty, all addresses are regarded * as on-link, and thus, as a neighbor. * XXX: we restrict the condition to hosts, because routers usually do * not have the "default router list". */ if (!ip6_forwarding && TAILQ_FIRST(&nd_defrouter) == NULL && nd6_defifindex == ifp->if_index) { d808 1 a808 1 if ((rt = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL) d812 2 d840 1 a840 1 rt->rt_ifp); d894 13 a906 4 /* * refresh default router list */ defrouter_select(); d925 1 a925 1 rt_mask(rt), 0, (struct rtentry **)0); d979 2 a980 1 ln->ln_expire = time_second + ND_IFINFO(rt->rt_ifp)->reachable; a994 1 int mine = 0; d996 1 a996 1 if ((rt->rt_flags & RTF_GATEWAY) != 0) a1009 21 if (req == RTM_RESOLVE && (nd6_need_cache(ifp) == 0 || /* stf case */ !nd6_is_addr_neighbor((struct sockaddr_in6 *)rt_key(rt), ifp))) { /* * FreeBSD and BSD/OS often make a cloned host route based * on a less-specific route (e.g. the default route). * If the less specific route does not have a "gateway" * (this is the case when the route just goes to a p2p or an * stf interface), we'll mistakenly make a neighbor cache for * the host route, and will see strange neighbor solicitation * for the corresponding destination. In order to avoid the * confusion, we check if the destination of the route is * a neighbor in terms of neighbor discovery, and stop the * process if not. Additionally, we remove the LLINFO flag * so that ndp(8) will not try to get the neighbor information * of the destination. */ rt->rt_flags &= ~RTF_LLINFO; return; } d1037 1 a1037 1 printf("nd6_rtrequest: time.tv_sec is zero; " d1043 1 a1043 1 if ((rt->rt_flags & RTF_CLONING) != 0) d1075 1 a1075 1 if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { d1134 1 a1134 1 &SIN6(rt_key(rt))->sin6_addr); a1139 1 mine = 1; d1218 59 d1284 1 a1284 1 struct in6_oprlist *oprl = (struct in6_oprlist *)data; d1288 1 a1288 1 struct nd_defrouter *dr; a1295 3 /* * obsolete API, use sysctl under net.inet6.icmp6 */ a1320 7 * obsolete API, use sysctl under net.inet6.icmp6 * * XXX the structure in6_prlist was changed in backward- * incompatible manner. in6_oprlist is used for SIOCGPRLST_IN6, * in6_prlist is used for nd6_sysctl() - fill_prlist(). */ /* d1325 1 a1325 1 bzero(oprl, sizeof(*oprl)); d1332 7 a1338 7 oprl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; oprl->prefix[i].raflags = pr->ndpr_raf; oprl->prefix[i].prefixlen = pr->ndpr_plen; oprl->prefix[i].vltime = pr->ndpr_vltime; oprl->prefix[i].pltime = pr->ndpr_pltime; oprl->prefix[i].if_index = pr->ndpr_ifp->if_index; oprl->prefix[i].expire = pr->ndpr_expire; d1344 1 a1344 1 #define RTRADDR oprl->prefix[i].advrtr[j] d1360 2 a1361 2 oprl->prefix[i].advrtrs = j; oprl->prefix[i].origin = PR_ORIG_RA; d1366 19 a1387 12 case OSIOCGIFINFO_IN6: /* XXX: old ndp(8) assumes a positive value for linkmtu. */ bzero(&ndi->ndi, sizeof(ndi->ndi)); ndi->ndi.linkmtu = IN6_LINKMTU(ifp); ndi->ndi.maxmtu = ND_IFINFO(ifp)->maxmtu; ndi->ndi.basereachable = ND_IFINFO(ifp)->basereachable; ndi->ndi.reachable = ND_IFINFO(ifp)->reachable; ndi->ndi.retrans = ND_IFINFO(ifp)->retrans; ndi->ndi.flags = ND_IFINFO(ifp)->flags; ndi->ndi.recalctm = ND_IFINFO(ifp)->recalctm; ndi->ndi.chlim = ND_IFINFO(ifp)->chlim; break; d1389 5 a1393 1 ndi->ndi = *ND_IFINFO(ifp); d1396 6 a1401 1 ND_IFINFO(ifp)->flags = ndi->ndi.flags; d1404 7 a1410 2 /* sync kernel routing table with the default router list */ defrouter_reset(); d1412 1 d1415 1 a1415 1 { a1420 2 struct in6_ifaddr *ia, *ia_next; d1422 2 a1423 15 if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) continue; /* XXX */ /* do we really have to remove addresses as well? */ for (ia = in6_ifaddr; ia; ia = ia_next) { /* ia might be removed. keep the next ptr. */ ia_next = ia->ia_next; if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; if (ia->ia6_ndpr == pr) in6_purgeaddr(&ia->ia_ifa); } d1428 1 a1428 1 } d1430 1 a1430 1 { d1435 10 a1444 4 defrouter_reset(); for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = next) { next = TAILQ_NEXT(dr, dr_entry); defrtrlist_del(dr); a1445 1 defrouter_select(); d1448 1 a1448 1 } d1467 1 a1467 2 if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL || (ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) { d1472 1 d1478 1 a1478 1 d1480 1 a1480 1 } d1596 2 a1597 2 if ((!olladdr && lladdr) || /* (3) */ (olladdr && lladdr && llchange)) { /* (5) */ d1631 2 a1632 1 (struct sockaddr_in6 *)rt_key(rt), rt); d1699 2 a1700 2 if ((!is_newentry && (olladdr || lladdr)) || /* (2-5) */ (is_newentry && lladdr)) { /* (7) */ d1732 1 a1733 1 struct ifnet *ifp; d1737 4 a1740 3 for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { nd6if = ND_IFINFO(ifp); d1783 2 a1784 2 if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1)) != NULL) d1790 1 a1790 1 dst, rt); d1802 1 a1802 1 * of view, regardless of the value of nd_ifinfo.flags. d1861 1 a1861 1 !(ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD)) { d1904 3 d1913 8 a1920 15 /* * If there has been no NS for the neighbor after entering the * INCOMPLETE state, send the first solicitation. * Technically this can be against the rate-limiting rule described in * Section 7.2.2 of RFC 2461 because the interval to the next scheduled * solicitation issued in nd6_timer() may be less than the specified * retransmission time. This should not be a problem from a practical * point of view, because we'll typically see an immediate response * from the neighbor, which suppresses the succeeding solicitations. */ if (ln->ln_expire && ln->ln_asked == 0) { ln->ln_asked++; ln->ln_expire = time_second + ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); d1923 1 a1923 1 d1936 1 a1936 1 } d1975 1 a1975 1 case IFT_FDDI: d2005 1 a2005 1 ip6_sprintf(&SIN6(dst)->sin6_addr), if_name(ifp)); a2011 190 } int nd6_sysctl(name, oldp, oldlenp, newp, newlen) int name; void *oldp; size_t *oldlenp; void *newp; size_t newlen; { size_t ol, l; int error; error = 0; l = 0; if (newp) return EPERM; if (oldp && !oldlenp) return EINVAL; ol = oldlenp ? *oldlenp : 0; switch (name) { case ICMPV6CTL_ND6_DRLIST: error = fill_drlist(oldp, oldlenp, ol); break; case ICMPV6CTL_ND6_PRLIST: error = fill_prlist(oldp, oldlenp, ol); break; default: error = ENOPROTOOPT; break; } return(error); } static int fill_drlist(oldp, oldlenp, ol) void *oldp; size_t *oldlenp, ol; { int error = 0, s; struct in6_defrouter *d = NULL, *de = NULL; struct nd_defrouter *dr; size_t l; s = splsoftnet(); if (oldp) { d = (struct in6_defrouter *)oldp; de = (struct in6_defrouter *)((caddr_t)oldp + *oldlenp); } l = 0; for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = TAILQ_NEXT(dr, dr_entry)) { if (oldp && d + 1 <= de) { bzero(d, sizeof(*d)); d->rtaddr.sin6_family = AF_INET6; d->rtaddr.sin6_len = sizeof(struct sockaddr_in6); d->rtaddr.sin6_addr = dr->rtaddr; in6_recoverscope(&d->rtaddr, &d->rtaddr.sin6_addr, dr->ifp); d->flags = dr->flags; d->rtlifetime = dr->rtlifetime; d->expire = dr->expire; d->if_index = dr->ifp->if_index; } l += sizeof(*d); if (d) d++; } if (oldp) { *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ if (l > ol) error = ENOMEM; } else *oldlenp = l; splx(s); return(error); } static int fill_prlist(oldp, oldlenp, ol) void *oldp; size_t *oldlenp, ol; { int error = 0, s; struct nd_prefix *pr; struct in6_prefix *p = NULL; struct in6_prefix *pe = NULL; size_t l; s = splsoftnet(); if (oldp) { p = (struct in6_prefix *)oldp; pe = (struct in6_prefix *)((caddr_t)oldp + *oldlenp); } l = 0; for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { u_short advrtrs; size_t advance; struct sockaddr_in6 *sin6; struct sockaddr_in6 *s6; struct nd_pfxrouter *pfr; if (oldp && p + 1 <= pe) { bzero(p, sizeof(*p)); sin6 = (struct sockaddr_in6 *)(p + 1); p->prefix = pr->ndpr_prefix; if (in6_recoverscope(&p->prefix, &p->prefix.sin6_addr, pr->ndpr_ifp) != 0) log(LOG_ERR, "scope error in prefix list (%s)\n", ip6_sprintf(&p->prefix.sin6_addr)); p->raflags = pr->ndpr_raf; p->prefixlen = pr->ndpr_plen; p->vltime = pr->ndpr_vltime; p->pltime = pr->ndpr_pltime; p->if_index = pr->ndpr_ifp->if_index; if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) p->expire = 0; else { time_t maxexpire; /* XXX: we assume time_t is signed. */ maxexpire = (-1) & ~(1 << ((sizeof(maxexpire) * 8) - 1)); if (pr->ndpr_vltime < maxexpire - pr->ndpr_lastupdate) { p->expire = pr->ndpr_lastupdate + pr->ndpr_vltime; } else p->expire = maxexpire; } p->refcnt = pr->ndpr_refcnt; p->flags = pr->ndpr_stateflags; p->origin = PR_ORIG_RA; advrtrs = 0; for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = pfr->pfr_next) { if ((void *)&sin6[advrtrs + 1] > (void *)pe) { advrtrs++; continue; } s6 = &sin6[advrtrs]; s6->sin6_family = AF_INET6; s6->sin6_len = sizeof(struct sockaddr_in6); s6->sin6_addr = pfr->router->rtaddr; in6_recoverscope(s6, &s6->sin6_addr, pfr->router->ifp); advrtrs++; } p->advrtrs = advrtrs; } else { advrtrs = 0; for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = pfr->pfr_next) advrtrs++; } advance = sizeof(*p) + sizeof(*sin6) * advrtrs; l += advance; if (p) p = (struct in6_prefix *)((caddr_t)p + advance); } if (oldp) { *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ if (l > ol) error = ENOMEM; } else *oldlenp = l; splx(s); return(error); @ 1.49.2.4 log @sync kqueue branch with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.49.2.3 2002/06/23 17:51:20 jdolecek Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.49.2.3 2002/06/23 17:51:20 jdolecek Exp $"); d1951 1 a1951 1 void *oldp; /* syscall arg, need copyout */ d1953 1 a1953 1 void *newp; /* syscall arg, need copyin */ a1955 1 void *p; a1967 6 if (oldp) { p = malloc(*oldlenp, M_TEMP, M_WAITOK); if (!p) return ENOMEM; } else p = NULL; d1970 1 a1970 3 error = fill_drlist(p, oldlenp, ol); if (!error && p && oldp) error = copyout(p, oldp, *oldlenp); d1974 1 a1974 3 error = fill_prlist(p, oldlenp, ol); if (!error && p && oldp) error = copyout(p, oldp, *oldlenp); a1980 2 if (p) free(p, M_TEMP); @ 1.49.2.5 log @sync kqueue with -current; this includes merge of gehenna-devsw branch, merge of i386 MP branch, and part of autoconf rototil work @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.49.2.4 2002/09/06 08:49:37 jdolecek Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.49.2.4 2002/09/06 08:49:37 jdolecek Exp $"); d251 1 a251 1 panic("ndopts == NULL in nd6_option"); d253 1 a253 1 panic("uninitialized ndopts in nd6_option"); d303 1 a303 1 panic("ndopts == NULL in nd6_options"); d305 1 a305 1 panic("uninitialized ndopts in nd6_options"); d418 1 a418 1 panic("rt=0 in nd6_timer(ln=%p)", ln); d420 1 a420 1 panic("rt_llinfo(%p) is not equal to ln(%p)", d423 1 a423 1 panic("dst=0 in nd6_timer(ln=%p)", ln); d680 1 a680 1 return (NULL); d698 1 a698 1 return (NULL); d701 1 a701 1 return (NULL); d708 1 a708 1 return (NULL); d732 1 a732 1 return (NULL); d734 1 a734 1 return (rt); d757 1 a757 1 return (1); d783 1 a783 1 return (1); d791 1 a791 1 return (1); d793 1 a793 1 return (0); d838 1 a838 1 return (ln->ln_next); d898 1 a898 1 return (next); d1417 2 a1418 1 return (nd6_setdefaultiface(ndif->ifindex)); d1420 1 a1420 1 return (error); d1856 1 a1856 1 return (0); d1861 1 a1861 1 return ((*ifp->if_output)(origifp, m, (struct sockaddr *)dst, d1864 1 a1864 1 return ((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt)); d1890 1 a1890 1 return (1); d1892 1 a1892 1 return (0); d1912 1 a1912 1 return (1); d1915 1 a1915 1 return (1); d1918 1 a1918 1 return (1); d1921 1 a1921 1 return (0); d1928 1 a1928 1 return (0); d1933 1 a1933 1 return (0); d1941 1 a1941 1 return (0); d1945 1 a1945 1 return (1); d1995 1 a1995 1 return (error); d2046 1 a2046 1 return (error); d2148 1 a2148 1 return (error); @ 1.48 log @refresh default router list on nd6_detach(), only if we are an autoconfigured host. bug was that, we will lose default route on "ifconfig gif0 destroy" even if default is not pointing to gif0. reported by ume@@mahoroba.org. sync with kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.47 2001/06/22 13:36:12 itojun Exp $ */ d1771 1 a1771 1 if (do_update && ln->ln_router) @ 1.47 log @select default router again, when L2 address of the router changes @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.46 2001/05/24 08:17:22 itojun Exp $ */ d628 6 a633 4 /* refresh default router list */ bzero(&drany, sizeof(drany)); defrouter_delreq(&drany, 0); defrouter_select(); @ 1.46 log @print more diag message on in6_addmulti() failures. @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.45 2001/03/30 11:08:58 itojun Exp $ */ /* $KAME: nd6.c,v 1.137 2001/03/21 21:52:06 jinmei Exp $ */ d1756 15 @ 1.45 log @enable FAKE_LOOPBACK_IF case by default. now traffic on loopback interface will be presented to bpf as normal wire format packet (without KAME scopeid in s6_addr16[1]). fix KAME PR 250 (host mistakenly accepts packets to fe80::x%lo0). sync with kame. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.44 2001/03/21 21:56:29 itojun Exp $ */ d1219 6 a1224 4 (void)in6_addmulti(&llsol, ifp, &error); if (error) printf( "nd6_rtrequest: could not join solicited node multicast (errno=%d)\n", error); @ 1.44 log @in nd6_cache_lladdr(), set nd6_gctimer to ln_expire just after the state transition to STALE. fixes tahi test breakage. sync with kame. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.43 2001/03/08 10:49:32 itojun Exp $ */ a1964 1 #ifdef FAKE_LOOPBACK_IF a1968 1 #endif @ 1.43 log @nd6_storelladdr() was not consistent about m_freem() policy. do not touch RTF_STATIC entries (static ND entries) on ND cache update. couple of costmetic sync. sync with kame @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.42 2001/02/23 08:02:41 itojun Exp $ */ /* $KAME: nd6.c,v 1.136 2001/03/06 12:26:07 itojun Exp $ */ d1658 8 d1668 3 d1682 1 a1682 1 ln->ln_hold = 0; a1683 1 ln->ln_expire = time_second + nd6_gctimer; @ 1.42 log @garbage-collect stale ND entries (default: 1 day). RFC 2461 5.3. sync with kame. @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.41 2001/02/23 06:41:50 itojun Exp $ */ /* $KAME: nd6.c,v 1.131 2001/02/21 16:28:18 itojun Exp $ */ d524 1 a524 1 /* expire */ d883 1 a883 1 return next; d976 1 d1031 1 d1077 1 a1077 1 /* cludge for desktops */ d1383 1 a1383 1 while(pfr) { d1584 4 a1587 1 } else d1589 1 d1956 1 a1956 1 if (ifp->if_flags & IFF_LOOPBACK) { d1994 1 d2001 1 d2006 1 d2013 1 @ 1.42.2.1 log @Catch up with -current. @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.45 2001/03/30 11:08:58 itojun Exp $ */ /* $KAME: nd6.c,v 1.137 2001/03/21 21:52:06 jinmei Exp $ */ d524 1 a524 1 /* expire default router list */ d883 1 a883 1 return(next); a975 1 m_freem(m); a1029 1 /* do not free mbuf here, it is queued into llinfo_nd6 */ d1075 1 a1075 1 /* kludge for desktops */ d1381 1 a1381 1 while (pfr) { d1582 1 a1582 4 } else { /* do nothing if static ndp is set */ if (rt->rt_flags & RTF_STATIC) return NULL; a1583 1 } a1651 8 /* * XXX: since nd6_output() below will cause * state tansition to DELAY and reset the timer, * we must set the timer now, although it is actually * meaningless. */ ln->ln_expire = time_second + nd6_gctimer; a1653 3 ln->ln_asked = 0; ln->ln_state = ND6_LLINFO_DELAY; ln->ln_expire = time_second + nd6_delay; d1665 1 a1665 1 ln->ln_hold = NULL; d1667 1 d1949 2 a1950 1 if ((ifp->if_flags & IFF_LOOPBACK) != 0) { d1954 1 a1987 1 m_freem(m); a1993 1 m_freem(m); a1997 1 m_freem(m); a2003 1 m_freem(m); @ 1.42.2.2 log @Catch up to -current. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.42.2.1 2001/04/09 01:58:41 nathanw Exp $ */ d1219 4 a1222 6 if (!in6_addmulti(&llsol, ifp, &error)) { nd6log((LOG_ERR, "%s: " "failed to join %s (errno=%d)\n", if_name(ifp), ip6_sprintf(&llsol), error)); } @ 1.42.2.3 log @Catch up with -current. @ text @d1 2 a2 2 /* $NetBSD$ */ /* $KAME: nd6.c,v 1.151 2001/06/19 14:24:41 sumikawa Exp $ */ a185 4 #ifdef DIAGNOSTIC if (!ifindex2ifnet[ifp->if_index]) panic("nd6_ifattach: ifindex2ifnet is NULL"); #endif d628 4 a631 6 if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */ /* refresh default router list */ bzero(&drany, sizeof(drany)); defrouter_delreq(&drany, 0); defrouter_select(); } a1756 15 /* * When the link-layer address of a router changes, select the * best router again. In particular, when the neighbor entry is newly * created, it might affect the selection policy. * Question: can we restrict the first condition to the "is_newentry" * case? * XXX: when we hear an RA from a new router with the link-layer * address option, defrouter_select() is called twice, since * defrtrlist_update called the function as well. However, I believe * we can compromise the overhead, since it only happens the first * time. */ if (do_update && ln->ln_router && !ip6_forwarding && ip6_accept_rtadv) defrouter_select(); d1873 1 a1873 2 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); a1875 7 /* the "G" test below also prevents rt == rt0 */ if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_ifp != ifp)) { rt->rt_refcnt--; rt0->rt_gwroute = 0; senderr(EHOSTUNREACH); } @ 1.42.2.4 log @Catch up to -current. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.42.2.3 2001/08/24 00:12:44 nathanw Exp $ */ a116 1 static struct llinfo_nd6 *nd6_free __P((struct rtentry *, int)); d448 1 a448 1 d483 1 a483 1 next = nd6_free(rt, 0); d496 1 a496 1 next = nd6_free(rt, 1); d521 2 a522 3 } else { next = nd6_free(rt, 0); } d656 1 a656 1 nln = nd6_free(rt, 0); d705 1 a705 1 * Create a new route. RTF_LLINFO is necessary d708 1 a708 1 * called in rtrequest via ifa->ifa_rtrequest. d716 1 a716 2 &rt)) != 0) { #if 0 a720 3 #endif return(NULL); } d745 1 a770 1 * XXX: a link does not necessarily specify a single interface. a809 3 * Since the function would cause significant changes in the kernel, DO NOT * make it global, unless you have a strong reason for the change, and are sure * that the change is safe. d811 2 a812 2 static struct llinfo_nd6 * nd6_free(rt, gc) a813 1 int gc; d820 2 a821 2 * we used to have pfctlinput(PRC_HOSTDEAD) here. * even though it is not harmful, it was not really necessary. d823 1 a829 20 if (dr != NULL && dr->expire && ln->ln_state == ND6_LLINFO_STALE && gc) { /* * If the reason for the deletion is just garbage * collection, and the neighbor is an active default * router, do not delete it. Instead, reset the GC * timer using the router's lifetime. * Simply deleting the entry would affect default * router selection, which is not necessarily a good * thing, especially when we're using router preference * values. * XXX: the check for ln_state would be redundant, * but we intentionally keep it just in case. */ ln->ln_expire = dr->expire; splx(s); return(ln->ln_next); } d849 1 a849 1 * prefixes correctly. a854 8 /* * Since defrouter_select() does not affect the * on-link determination and MIP6 needs the check * before the default router selection, we perform * the check now. */ pfxlist_onlink_check(); d868 1 d877 1 a877 1 * a side effect (XXX). d945 97 a1057 11 if (nd6_need_cache(ifp) == 0 && (rt->rt_flags & RTF_HOST) == 0) { /* * This is probably an interface direct route for a link * which does not need neighbor caches (e.g. fe80::%lo0/64). * We do not need special treatment below for such a route. * Moreover, the RTF_LLINFO flag which would be set below * would annoy the ndp(8) command. */ return; } d1070 1 a1070 1 * a route to interface. RTF_LLINFO flag is set d1085 1 a1085 1 printf("nd6_rtequest: time.tv_sec is zero; " d1193 1 a1193 1 rt->rt_ifp = &loif[0]; /* XXX */ d1226 4 a1229 3 nd6log((LOG_ERR, "%s: failed to join " "%s (errno=%d)\n", if_name(ifp), ip6_sprintf(&llsol), error)); d1542 1 a1542 1 * on reception of inbound ND6 packets. (RS/RA/NS/redirect) d1603 1 a1603 1 (void)nd6_free(rt, 0); d1635 1 a1635 1 if (lladdr) { /* (3-5) and (7) */ d1645 2 a1646 2 if ((!olladdr && lladdr) /* (3) */ || (olladdr && lladdr && llchange)) { /* (5) */ d1649 1 a1649 1 } else /* (1-2,4) */ d1653 1 a1653 1 if (!lladdr) /* (6) */ d1655 1 a1655 1 else /* (7) */ d1675 7 d1689 1 d1732 1 a1732 1 if (is_newentry) /* (6-7) */ d1738 2 a1739 2 * is_router flag. Otherwise, if the entry is newly created, * clear the flag. [RFC 2461, sec 8.3] d1743 1 a1743 1 else if (is_newentry) /* (6-7) */ d1756 2 a1757 2 if ((!is_newentry && (olladdr || lladdr)) /* (2-5) */ || (is_newentry && lladdr)) { /* (7) */ a1773 3 * XXX: although defrouter_select() should not have a bad effect * for those are not autoconfigured hosts, we explicitly avoid such * cases for safety. d1829 15 a1843 1 if (nd6_need_cache(ifp) == 0) d1845 1 d1848 1 a1848 1 * next hop determination. This routine is derived from ether_outpout. d1922 1 a1922 1 * the condition below is not very efficient. But we believe d1964 1 a1964 1 * (i.e. its link-layer address is already resolved), just d1972 1 a1972 1 * response yet. Replace the held mbuf (if any) with this d1974 3 a1976 3 * This code conforms to the rate-limiting rule described in Section * 7.2.2 of RFC 2461, because the timer is set correctly after sending * an NS below. a2007 23 int nd6_need_cache(ifp) struct ifnet *ifp; { /* * XXX: we currently do not make neighbor cache on any interface * other than ARCnet, Ethernet, FDDI and GIF. * * RFC2893 says: * - unidirectional tunnels needs no ND */ switch (ifp->if_type) { case IFT_ARCNET: case IFT_ETHER: case IFT_FDDI: case IFT_IEEE1394: case IFT_GIF: /* XXX need more cases? */ return(1); default: return(0); } } @ 1.42.2.5 log @Catch up to -current. @ text @d1 1 a1 1 /* $NetBSD$ */ a39 3 #include __KERNEL_RCSID(0, "$NetBSD$"); @ 1.42.2.6 log @Catch up to -current. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.42.2.5 2001/11/14 19:18:13 nathanw Exp $ */ d42 1 a42 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.42.2.5 2001/11/14 19:18:13 nathanw Exp $"); d428 1 d997 1 a997 1 if ((rt->rt_flags & RTF_GATEWAY)) d1044 1 a1044 1 if ((rt->rt_flags & RTF_CLONING)) d1803 3 a1805 2 * of view, regardless the value of nd_ifinfo.flags. * The second condition is a bit tricky; we skip d2006 1 a2006 2 printf("nd6_storelladdr: sdl_alen == 0, dst=%s, if=%s\n", ip6_sprintf(&SIN6(dst)->sin6_addr), if_name(ifp)); @ 1.42.2.7 log @Catch up to -current. (CVS: It's not just a program. It's an adventure!) @ text @d1 1 a1 1 /* $NetBSD$ */ d33 8 d42 1 a42 1 __KERNEL_RCSID(0, "$NetBSD$"); @ 1.42.2.8 log @Catch up to -current. @ text @d2 1 a2 1 /* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.42.2.7 2002/04/01 07:48:52 nathanw Exp $"); d54 2 d57 2 d60 1 a61 3 #include #include d66 1 d103 2 a110 1 static void nd6_setmtu0 __P((struct ifnet *, struct nd_ifinfo *)); a116 3 static int fill_drlist __P((void *, size_t *, size_t)); static int fill_prlist __P((void *, size_t *, size_t)); d143 1 a143 1 struct nd_ifinfo * a146 6 struct nd_ifinfo *nd; nd = (struct nd_ifinfo *)malloc(sizeof(*nd), M_IP6NDP, M_WAITOK); bzero(nd, sizeof(*nd)); nd->initialized = 1; a147 4 nd->chlim = IPV6_DEFHLIM; nd->basereachable = REACHABLE_TIME; nd->reachable = ND_COMPUTE_RTIME(nd->basereachable); nd->retrans = RETRANS_TIMER; d149 2 a150 3 * Note that the default value of ip6_accept_rtadv is 0, which means * we won't accept RAs by default even if we set ND6_IFF_ACCEPT_RTADV * here. d152 3 a154 1 nd->flags = (ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV); d156 2 a157 2 /* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */ nd6_setmtu0(ifp, nd); d159 12 a170 2 return nd; } d172 9 a180 4 void nd6_ifdetach(nd) struct nd_ifinfo *nd; { d182 13 a194 1 free(nd, M_IP6NDP); d197 4 d205 3 a207 11 nd6_setmtu0(ifp, ND_IFINFO(ifp)); } void nd6_setmtu0(ifp, ndi) struct ifnet *ifp; struct nd_ifinfo *ndi; { u_int32_t omaxmtu; omaxmtu = ndi->maxmtu; d210 8 a217 2 case IFT_ARCNET: ndi->maxmtu = MIN(ARC_PHDS_MAXMTU, ifp->if_mtu); /* RFC2497 */ d219 2 a220 2 case IFT_FDDI: ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); d227 22 a248 10 /* * Decreasing the interface MTU under IPV6 minimum MTU may cause * undesirable situation. We thus notify the operator of the change * explicitly. The check for omaxmtu is necessary to restrict the * log to the case of changing the MTU, not initializing it. */ if (omaxmtu >= IPV6_MMTU && ndi->maxmtu < IPV6_MMTU) { log(LOG_NOTICE, "nd6_setmtu0: " "new link MTU on %s (%lu) is too small for IPv6\n", if_name(ifp), (unsigned long)ndi->maxmtu); d250 1 a250 3 if (ndi->maxmtu > in6_maxmtu) in6_setmaxmtu(); /* check all interfaces just in case */ a258 1 d414 1 a414 4 struct ifnet *ifp; struct in6_ifaddr *ia6, *nia6; struct in6_addrlifetime *lt6; d422 1 d436 1 a436 1 ndi = ND_IFINFO(ifp); d458 1 a458 1 ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); d460 1 a460 1 ln, 0); d464 10 a473 9 /* * Fake rcvif to make the ICMP error * more helpful in diagnosing for the * receiver. * XXX: should we consider * older rcvif? */ m->m_pkthdr.rcvif = rt->rt_ifp; d500 1 a500 1 ND6_RETRANS_SEC(ndi->retrans); d502 2 a503 1 &dst->sin6_addr, ln, 0); d513 1 a513 1 ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); d515 1 a515 1 &dst->sin6_addr, ln, 0); d523 1 a523 1 d536 9 d546 10 a555 12 /* * expire interface addresses. * in the past the loop was inside prefix expiry processing. * However, from a stricter speci-confrmance standpoint, we should * rather separate address lifetimes and prefix lifetimes. */ for (ia6 = in6_ifaddr; ia6; ia6 = nia6) { nia6 = ia6->ia_next; /* check address lifetime */ lt6 = &ia6->ia6_lifetime; if (IFA6_IS_INVALID(ia6)) { in6_purgeaddr(&ia6->ia_ifa); a556 10 if (IFA6_IS_DEPRECATED(ia6)) { ia6->ia6_flags |= IN6_IFF_DEPRECATED; } else { /* * A new RA might have made a deprecated address * preferred. */ ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; } } a557 3 /* expire prefix list */ pr = nd_prefix.lh_first; while (pr) { d562 5 d568 2 a569 2 if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME && time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) { d575 1 a575 1 * separate. NEVER perform in6_purgeaddr here. d595 1 a595 1 struct nd_defrouter *dr, *ndr; d598 12 a609 19 /* * Nuke default router list entries toward ifp. * We defer removal of default router list entries that is installed * in the routing table, in order to keep additional side effects as * small as possible. */ for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) { ndr = TAILQ_NEXT(dr, dr_entry); if (dr->installed) continue; if (dr->ifp == ifp) defrtrlist_del(dr); } for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) { ndr = TAILQ_NEXT(dr, dr_entry); if (!dr->installed) continue; d618 2 a619 8 /* * Previously, pr->ndpr_addr is removed as well, * but I strongly believe we don't have to do it. * nd6_purge() is only called from in6_ifdetach(), * which removes all the associated interface addresses * by itself. * (jinmei@@kame.net 20010129) */ d630 2 d696 1 a696 1 ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); d707 6 a712 3 ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) != 0) { d725 1 a725 1 (struct llinfo_nd6 *)rt->rt_llinfo; a733 4 * Note that the check for rt_llinfo is necessary because a cloned * route from a parent route that has the L flag (e.g. the default * route to a p2p interface) may have the flag, too, while the * destination is not actually a neighbor. d737 1 a737 2 * use rt->rt_ifa->ifa_ifp, which would specify the REAL * interface. d740 1 a740 1 rt->rt_gateway->sa_family != AF_LINK || rt->rt_llinfo == NULL || d743 2 a744 4 log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec"); d746 1 a746 1 return(NULL); d760 5 a764 2 struct nd_prefix *pr; struct rtentry *rt; d777 2 a778 2 * If the address matches one of our on-link prefixes, it should be a * neighbor. d780 6 a785 3 for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { if (pr->ndpr_ifp != ifp) continue; d787 6 a792 16 if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) continue; if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, &addr->sin6_addr, &pr->ndpr_mask)) return (1); } /* * If the default router list is empty, all addresses are regarded * as on-link, and thus, as a neighbor. * XXX: we restrict the condition to hosts, because routers usually do * not have the "default router list". */ if (!ip6_forwarding && TAILQ_FIRST(&nd_defrouter) == NULL && nd6_defifindex == ifp->if_index) { d800 1 a800 1 if ((rt = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL) d804 2 d832 1 a832 1 rt->rt_ifp); d886 13 a898 4 /* * refresh default router list */ defrouter_select(); d917 1 a917 1 rt_mask(rt), 0, (struct rtentry **)0); d971 2 a972 1 ln->ln_expire = time_second + ND_IFINFO(rt->rt_ifp)->reachable; a986 1 int mine = 0; d988 1 a988 1 if ((rt->rt_flags & RTF_GATEWAY) != 0) a1001 21 if (req == RTM_RESOLVE && (nd6_need_cache(ifp) == 0 || /* stf case */ !nd6_is_addr_neighbor((struct sockaddr_in6 *)rt_key(rt), ifp))) { /* * FreeBSD and BSD/OS often make a cloned host route based * on a less-specific route (e.g. the default route). * If the less specific route does not have a "gateway" * (this is the case when the route just goes to a p2p or an * stf interface), we'll mistakenly make a neighbor cache for * the host route, and will see strange neighbor solicitation * for the corresponding destination. In order to avoid the * confusion, we check if the destination of the route is * a neighbor in terms of neighbor discovery, and stop the * process if not. Additionally, we remove the LLINFO flag * so that ndp(8) will not try to get the neighbor information * of the destination. */ rt->rt_flags &= ~RTF_LLINFO; return; } d1029 1 a1029 1 printf("nd6_rtrequest: time.tv_sec is zero; " d1035 1 a1035 1 if ((rt->rt_flags & RTF_CLONING) != 0) d1067 1 a1067 1 if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { d1126 1 a1126 1 &SIN6(rt_key(rt))->sin6_addr); a1131 1 mine = 1; d1210 59 d1276 1 a1276 1 struct in6_oprlist *oprl = (struct in6_oprlist *)data; d1280 1 a1280 1 struct nd_defrouter *dr; a1287 3 /* * obsolete API, use sysctl under net.inet6.icmp6 */ a1312 7 * obsolete API, use sysctl under net.inet6.icmp6 * * XXX the structure in6_prlist was changed in backward- * incompatible manner. in6_oprlist is used for SIOCGPRLST_IN6, * in6_prlist is used for nd6_sysctl() - fill_prlist(). */ /* d1317 1 a1317 1 bzero(oprl, sizeof(*oprl)); d1324 7 a1330 7 oprl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; oprl->prefix[i].raflags = pr->ndpr_raf; oprl->prefix[i].prefixlen = pr->ndpr_plen; oprl->prefix[i].vltime = pr->ndpr_vltime; oprl->prefix[i].pltime = pr->ndpr_pltime; oprl->prefix[i].if_index = pr->ndpr_ifp->if_index; oprl->prefix[i].expire = pr->ndpr_expire; d1336 1 a1336 1 #define RTRADDR oprl->prefix[i].advrtr[j] d1352 2 a1353 2 oprl->prefix[i].advrtrs = j; oprl->prefix[i].origin = PR_ORIG_RA; d1358 19 a1379 12 case OSIOCGIFINFO_IN6: /* XXX: old ndp(8) assumes a positive value for linkmtu. */ bzero(&ndi->ndi, sizeof(ndi->ndi)); ndi->ndi.linkmtu = IN6_LINKMTU(ifp); ndi->ndi.maxmtu = ND_IFINFO(ifp)->maxmtu; ndi->ndi.basereachable = ND_IFINFO(ifp)->basereachable; ndi->ndi.reachable = ND_IFINFO(ifp)->reachable; ndi->ndi.retrans = ND_IFINFO(ifp)->retrans; ndi->ndi.flags = ND_IFINFO(ifp)->flags; ndi->ndi.recalctm = ND_IFINFO(ifp)->recalctm; ndi->ndi.chlim = ND_IFINFO(ifp)->chlim; break; d1381 5 a1385 1 ndi->ndi = *ND_IFINFO(ifp); d1388 6 a1393 1 ND_IFINFO(ifp)->flags = ndi->ndi.flags; d1396 7 a1402 2 /* sync kernel routing table with the default router list */ defrouter_reset(); d1404 1 d1407 1 a1407 1 { a1412 2 struct in6_ifaddr *ia, *ia_next; d1414 2 a1415 15 if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) continue; /* XXX */ /* do we really have to remove addresses as well? */ for (ia = in6_ifaddr; ia; ia = ia_next) { /* ia might be removed. keep the next ptr. */ ia_next = ia->ia_next; if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; if (ia->ia6_ndpr == pr) in6_purgeaddr(&ia->ia_ifa); } d1420 1 a1420 1 } d1422 1 a1422 1 { d1427 10 a1436 4 defrouter_reset(); for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = next) { next = TAILQ_NEXT(dr, dr_entry); defrtrlist_del(dr); a1437 1 defrouter_select(); d1440 1 a1440 1 } d1459 1 a1459 2 if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL || (ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) { d1464 1 d1470 1 a1470 1 d1472 1 a1472 1 } d1588 2 a1589 2 if ((!olladdr && lladdr) || /* (3) */ (olladdr && lladdr && llchange)) { /* (5) */ d1623 2 a1624 1 (struct sockaddr_in6 *)rt_key(rt), rt); d1691 2 a1692 2 if ((!is_newentry && (olladdr || lladdr)) || /* (2-5) */ (is_newentry && lladdr)) { /* (7) */ d1724 1 a1725 1 struct ifnet *ifp; d1729 4 a1732 3 for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { nd6if = ND_IFINFO(ifp); d1775 2 a1776 2 if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1)) != NULL) d1782 1 a1782 1 dst, rt); d1794 1 a1794 1 * of view, regardless of the value of nd_ifinfo.flags. d1853 1 a1853 1 !(ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD)) { d1896 3 d1905 8 a1912 15 /* * If there has been no NS for the neighbor after entering the * INCOMPLETE state, send the first solicitation. * Technically this can be against the rate-limiting rule described in * Section 7.2.2 of RFC 2461 because the interval to the next scheduled * solicitation issued in nd6_timer() may be less than the specified * retransmission time. This should not be a problem from a practical * point of view, because we'll typically see an immediate response * from the neighbor, which suppresses the succeeding solicitations. */ if (ln->ln_expire && ln->ln_asked == 0) { ln->ln_asked++; ln->ln_expire = time_second + ND6_RETRANS_SEC(ND_IFINFO(ifp)->retrans); nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); d1915 1 a1915 1 d1928 1 a1928 1 } d1967 1 a1967 1 case IFT_FDDI: d1997 1 a1997 1 ip6_sprintf(&SIN6(dst)->sin6_addr), if_name(ifp)); a2003 190 } int nd6_sysctl(name, oldp, oldlenp, newp, newlen) int name; void *oldp; size_t *oldlenp; void *newp; size_t newlen; { size_t ol, l; int error; error = 0; l = 0; if (newp) return EPERM; if (oldp && !oldlenp) return EINVAL; ol = oldlenp ? *oldlenp : 0; switch (name) { case ICMPV6CTL_ND6_DRLIST: error = fill_drlist(oldp, oldlenp, ol); break; case ICMPV6CTL_ND6_PRLIST: error = fill_prlist(oldp, oldlenp, ol); break; default: error = ENOPROTOOPT; break; } return(error); } static int fill_drlist(oldp, oldlenp, ol) void *oldp; size_t *oldlenp, ol; { int error = 0, s; struct in6_defrouter *d = NULL, *de = NULL; struct nd_defrouter *dr; size_t l; s = splsoftnet(); if (oldp) { d = (struct in6_defrouter *)oldp; de = (struct in6_defrouter *)((caddr_t)oldp + *oldlenp); } l = 0; for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = TAILQ_NEXT(dr, dr_entry)) { if (oldp && d + 1 <= de) { bzero(d, sizeof(*d)); d->rtaddr.sin6_family = AF_INET6; d->rtaddr.sin6_len = sizeof(struct sockaddr_in6); d->rtaddr.sin6_addr = dr->rtaddr; in6_recoverscope(&d->rtaddr, &d->rtaddr.sin6_addr, dr->ifp); d->flags = dr->flags; d->rtlifetime = dr->rtlifetime; d->expire = dr->expire; d->if_index = dr->ifp->if_index; } l += sizeof(*d); if (d) d++; } if (oldp) { *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ if (l > ol) error = ENOMEM; } else *oldlenp = l; splx(s); return(error); } static int fill_prlist(oldp, oldlenp, ol) void *oldp; size_t *oldlenp, ol; { int error = 0, s; struct nd_prefix *pr; struct in6_prefix *p = NULL; struct in6_prefix *pe = NULL; size_t l; s = splsoftnet(); if (oldp) { p = (struct in6_prefix *)oldp; pe = (struct in6_prefix *)((caddr_t)oldp + *oldlenp); } l = 0; for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { u_short advrtrs; size_t advance; struct sockaddr_in6 *sin6; struct sockaddr_in6 *s6; struct nd_pfxrouter *pfr; if (oldp && p + 1 <= pe) { bzero(p, sizeof(*p)); sin6 = (struct sockaddr_in6 *)(p + 1); p->prefix = pr->ndpr_prefix; if (in6_recoverscope(&p->prefix, &p->prefix.sin6_addr, pr->ndpr_ifp) != 0) log(LOG_ERR, "scope error in prefix list (%s)\n", ip6_sprintf(&p->prefix.sin6_addr)); p->raflags = pr->ndpr_raf; p->prefixlen = pr->ndpr_plen; p->vltime = pr->ndpr_vltime; p->pltime = pr->ndpr_pltime; p->if_index = pr->ndpr_ifp->if_index; if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) p->expire = 0; else { time_t maxexpire; /* XXX: we assume time_t is signed. */ maxexpire = (-1) & ~(1 << ((sizeof(maxexpire) * 8) - 1)); if (pr->ndpr_vltime < maxexpire - pr->ndpr_lastupdate) { p->expire = pr->ndpr_lastupdate + pr->ndpr_vltime; } else p->expire = maxexpire; } p->refcnt = pr->ndpr_refcnt; p->flags = pr->ndpr_stateflags; p->origin = PR_ORIG_RA; advrtrs = 0; for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = pfr->pfr_next) { if ((void *)&sin6[advrtrs + 1] > (void *)pe) { advrtrs++; continue; } s6 = &sin6[advrtrs]; s6->sin6_family = AF_INET6; s6->sin6_len = sizeof(struct sockaddr_in6); s6->sin6_addr = pfr->router->rtaddr; in6_recoverscope(s6, &s6->sin6_addr, pfr->router->ifp); advrtrs++; } p->advrtrs = advrtrs; } else { advrtrs = 0; for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = pfr->pfr_next) advrtrs++; } advance = sizeof(*p) + sizeof(*sin6) * advrtrs; l += advance; if (p) p = (struct in6_prefix *)((caddr_t)p + advance); } if (oldp) { *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */ if (l > ol) error = ENOMEM; } else *oldlenp = l; splx(s); return(error); @ 1.42.2.9 log @Catch up to -current. @ text @d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD$"); d1951 1 a1951 1 void *oldp; /* syscall arg, need copyout */ d1953 1 a1953 1 void *newp; /* syscall arg, need copyin */ a1955 1 void *p; a1967 6 if (oldp) { p = malloc(*oldlenp, M_TEMP, M_WAITOK); if (!p) return ENOMEM; } else p = NULL; d1970 1 a1970 3 error = fill_drlist(p, oldlenp, ol); if (!error && p && oldp) error = copyout(p, oldp, *oldlenp); d1974 1 a1974 3 error = fill_prlist(p, oldlenp, ol); if (!error && p && oldp) error = copyout(p, oldp, *oldlenp); a1980 2 if (p) free(p, M_TEMP); @ 1.42.2.10 log @Catch up to -current. @ text @d520 1 a520 2 if ((ia6->ia6_flags & IN6_IFF_DEPRECATED) != 0 || IFA6_IS_DEPRECATED(ia6)) { d680 1 a680 1 return (NULL); d698 1 a698 1 return (NULL); d701 1 a701 1 return (NULL); d708 1 a708 1 return (NULL); d732 1 a732 1 return (NULL); d734 1 a734 1 return (rt); d757 1 a757 1 return (1); d783 1 a783 1 return (1); d791 1 a791 1 return (1); d793 1 a793 1 return (0); d838 1 a838 1 return (ln->ln_next); d898 1 a898 1 return (next); d1417 1 a1417 1 return (nd6_setdefaultiface(ndif->ifindex)); d1420 1 a1420 1 return (error); d1856 1 a1856 1 return (0); d1861 1 a1861 1 return ((*ifp->if_output)(origifp, m, (struct sockaddr *)dst, d1864 1 a1864 1 return ((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt)); d1890 1 a1890 1 return (1); d1892 1 a1892 1 return (0); d1912 1 a1912 1 return (1); d1915 1 a1915 1 return (1); d1918 1 a1918 1 return (1); d1921 1 a1921 1 return (0); d1928 1 a1928 1 return (0); d1933 1 a1933 1 return (0); d1941 1 a1941 1 return (0); d1945 1 a1945 1 return (1); d1995 1 a1995 1 return (error); d2046 1 a2046 1 return (error); d2148 1 a2148 1 return (error); @ 1.42.2.11 log @Catch up to -current. @ text @d251 1 a251 1 panic("ndopts == NULL in nd6_option"); d253 1 a253 1 panic("uninitialized ndopts in nd6_option"); d303 1 a303 1 panic("ndopts == NULL in nd6_options"); d305 1 a305 1 panic("uninitialized ndopts in nd6_options"); d418 1 a418 1 panic("rt=0 in nd6_timer(ln=%p)", ln); d420 1 a420 1 panic("rt_llinfo(%p) is not equal to ln(%p)", d423 1 a423 1 panic("dst=0 in nd6_timer(ln=%p)", ln); d520 2 a521 1 if (IFA6_IS_DEPRECATED(ia6)) { d728 1 a728 1 nd6log((LOG_DEBUG, d731 1 a731 1 ifp ? if_name(ifp) : "unspec")); d1419 1 @ 1.42.2.12 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.42.2.11 2002/10/18 02:45:25 nathanw Exp $ */ d34 1 a34 1 __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.42.2.11 2002/10/18 02:45:25 nathanw Exp $"); a1858 4 #ifdef IPSEC /* clean ipsec history once it goes out of the node */ ipsec_delaux(m); #endif @ 1.41 log @remove unnecessary state, ND6_LLINFO_WAITDELETE, from neighbor cache state machine. no need for RTF_REJECT on neighbor cache entires, they are leftover from ARP code. sync with kame. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.40 2001/02/21 17:23:09 itojun Exp $ */ d91 1 d483 8 d492 1 a492 1 ln->ln_state = ND6_LLINFO_STALE; d494 1 a494 4 /* * ND6_LLINFO_STALE state requires nothing for timer * routine. */ d505 1 a505 1 } else d507 2 d1667 1 d1832 1 a1832 1 * of view, regardless the value of the value of d1897 1 a1897 1 ln->ln_state < ND6_LLINFO_REACHABLE) d1899 2 @ 1.40 log @make validation code more strict for ND6/dest6 variable length headers. check duplicated nd6_ifinfo table initialization in a better way. sync with kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.39 2001/02/21 16:28:43 itojun Exp $ */ a511 3 case ND6_LLINFO_WAITDELETE: next = nd6_free(rt); break; a645 23 /* * Neighbor cache entry for interface route will be retained * with ND6_LLINFO_WAITDELETE state, by nd6_free(). Nuke it. */ ln = llinfo_nd6.ln_next; while (ln && ln != &llinfo_nd6) { struct rtentry *rt; struct sockaddr_dl *sdl; nln = ln->ln_next; rt = ln->ln_rt; if (rt && rt->rt_gateway && rt->rt_gateway->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *)rt->rt_gateway; if (sdl->sdl_index == ifp->if_index) { rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), 0, (struct rtentry **)0); } } ln = nln; } a801 1 struct sockaddr_dl *sdl; a858 9 if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && sdl->sdl_family == AF_LINK) { sdl->sdl_alen = 0; ln->ln_state = ND6_LLINFO_WAITDELETE; ln->ln_asked = 0; rt->rt_flags &= ~RTF_REJECT; return ln->ln_next; } d1007 1 a1007 2 if (ln->ln_state == ND6_LLINFO_WAITDELETE || ln->ln_state == ND6_LLINFO_NOSTATE) a1012 1 rt->rt_flags &= ~RTF_REJECT; a1643 1 rt->rt_flags &= ~RTF_REJECT; a1830 3 if (rt->rt_flags & RTF_REJECT) senderr(EHOSTDOWN); a1850 2 if (rt->rt_flags & RTF_REJECT) senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); d1920 1 a1920 2 if (ln->ln_state == ND6_LLINFO_WAITDELETE || ln->ln_state == ND6_LLINFO_NOSTATE) a1925 1 rt->rt_flags &= ~RTF_REJECT; @ 1.39 log @style, to make kame sync easier @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.38 2001/02/10 04:14:29 itojun Exp $ */ /* $KAME: nd6.c,v 1.118 2001/02/08 12:14:33 itojun Exp $ */ d175 8 a182 2 /* don't initialize if called twice */ if (ND.linkmtu) d208 1 a208 1 switch(ifp->if_type) { d290 6 d307 6 a312 1 if (!(ndopts->nd_opts_search < ndopts->nd_opts_last)) { @ 1.38 log @to sync with kame better, (1) remove register declaration for variables, (2) sync whitespaces, (3) update comments. (4) bring in some of portability and logging enhancements. no functional changes here. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.37 2001/02/08 12:57:54 itojun Exp $ */ d203 15 a217 15 case IFT_ARCNET: /* XXX MTU handling needs more work */ ndi->maxmtu = MIN(60480, ifp->if_mtu); break; case IFT_ETHER: ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); break; case IFT_ATM: ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); break; case IFT_IEEE1394: ndi->maxmtu = MIN(IEEE1394MTU, ifp->if_mtu); break; default: ndi->maxmtu = ifp->if_mtu; break; @ 1.37 log @when chasing nd6_llinfo chain, make sure we do not touch dangling pointer (due to RTM_DELETE during default router list management). from kame @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.36 2001/02/07 08:59:48 itojun Exp $ */ d392 3 a394 3 register struct llinfo_nd6 *ln; register struct nd_defrouter *dr; register struct nd_prefix *pr; d756 1 a756 1 register struct ifaddr *ifa; d1109 1 a1109 1 * note that the mechanism need a mutual agreement d1111 2 a1112 2 * a new protocol, or new kludge. * - from RFC2461 6.2.4, host MUST NOT send unsolicited NA. d1760 2 a1761 2 register int i; register struct nd_ifinfo *nd6if; d1787 1 a1787 1 register struct ifnet *ifp; d1793 2 a1794 2 register struct mbuf *m = m0; register struct rtentry *rt = rt0; d1807 1 a1807 1 * draft-ietf-ngtrans-mech-06.txt says: @ 1.36 log @during ip6/icmp6 inbound packet processing, do not call log() nor printf() in normal operation (/var can get filled up by flodding bogus packets). sysctl net.inet6.icmp6.nd6_debug will turn on diagnostic messages. (#define ND6_DEBUG will turn it on by default) improve stats in ND6 code. lots of synchronziation with kame (including comments and cometic ones). @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.35 2001/02/05 10:42:45 chs Exp $ */ /* $KAME: nd6.c,v 1.110 2001/02/06 09:14:38 jinmei Exp $ */ d461 1 a461 1 nd6_free(rt); d492 2 a493 3 } else { nd6_free(rt); } d496 1 a496 1 nd6_free(rt); d628 1 a628 1 nd6_free(rt); d806 1 a806 1 void d810 1 a810 1 struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; d875 1 a875 1 return; d878 13 d893 2 d1602 1 a1602 1 nd6_free(rt); @ 1.35 log @expose the definitions of MIN() and MAX() in sys/param.h to the kernel and use those in favor of a dozen copies scattered around the source tree. @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.34 2001/01/17 04:05:45 itojun Exp $ */ /* $KAME: nd6.c,v 1.75 2000/10/15 15:23:11 itojun Exp $ */ d97 6 d328 1 d342 3 a344 2 printf("duplicated ND6 option found " "(type=%d)\n", nd_opt->nd_opt_type); d364 1 a364 1 log(LOG_DEBUG, d366 1 a366 1 "option ignored\n", nd_opt->nd_opt_type); d373 1 a373 1 printf("too many loop in nd opt\n"); d1122 2 a1123 1 "nd6_rtrequest: bad gateway value\n"); @ 1.34 log @pull post-4.4BSD change to sys/net/route.c from BSD/OS 4.2 (UCB copyrighted). have sys/net/route.c:rtrequest1(), which takes rt_addrinfo * as the argument. pass rt_addrinfo all the way down to rtrequest, and ifa->ifa_rtrequest. 3rd arg of ifa->ifa_rtrequest is now rt_addrinfo * instead of sockaddr * (almost noone is using it anyways). benefit: the follwoing command now works. previously we need two route(8) invocations, "add" then "change". # route add -inet6 default ::1 -ifp gif0 remove unsafe typecast in rtrequest(), from rtentry * to sockaddr *. it was introduced by 4.3BSD-reno and never corrected. XXX is eon_rtrequest() change correct regarding to 3rd arg? eon_rtrequest() and rtrequest() were incorrect since 4.3BSD-reno, so i do not have correct answer in the source code. someone with more clue about netiso-over-ip, please help. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.33 2000/11/05 17:17:16 onoe Exp $ */ a191 1 #define MIN(a,b) ((a) < (b) ? (a) : (b)) @ 1.33 log @First Prototype implementation of network interface part for IEEE1394 (if_fw). Current status: Only OHCI chip is supported (fwohci). ping (IPv4) works with Sony's implementation (SmartConnect) on Win98. sometimes works but not stable. Not implemented yet: IRM (Isochronous Resource Manager) functionality. Link layer fragmentation. Topology map. More to do: clean ups MCAP charactor device part dhcp There is no entry in GENERIC config file yet. Follow sys/dev/ieee1394/IMPLEMENTATION to enable if_fw. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.32 2000/10/15 15:39:12 itojun Exp $ */ d1027 1 a1027 1 nd6_rtrequest(req, rt, sa) d1030 1 a1030 1 struct sockaddr *sa; /* xxx unused */ d1249 1 a1249 1 nd6_p2p_rtrequest(req, rt, sa) d1252 1 a1252 1 struct sockaddr *sa; /* xxx unused */ @ 1.32 log @suppress warning on nd6_storelladdr failure. the failure could happen easily when we have routing table with too many entries. sync with kame. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.31 2000/07/06 12:36:19 itojun Exp $ */ d60 1 d207 3 d959 3 a961 1 break; a964 1 break; d1792 1 d1977 3 a1979 1 break; @ 1.31 log @- do not use bitfield for router renumbering header. - add protection mechanism against ND cache corruption due to bad NUD hints. - more stats - icmp6 pps limitation. TOOD: should implement ppsratecheck(9). @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.30 2000/05/19 01:40:19 itojun Exp $ */ /* $KAME: nd6.c,v 1.68 2000/07/02 14:48:02 itojun Exp $ */ d1980 5 a1984 2 if (rt == NULL || rt->rt_gateway->sa_family != AF_LINK) { @ 1.30 log @do not mistakingly forward link-local scoped packet (the bug was added with "beyondscope" icmp6 support). "options FAKE_LOOPBACK_IF" will honor scope on loopback outputs. rcvif will be real interface, not the loopback, just like when multicast loopback. (sync with kame) @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.29 2000/05/09 11:51:12 itojun Exp $ */ /* $KAME: nd6.c,v 1.63 2000/05/17 12:35:59 jinmei Exp $ */ d94 2 d230 1 a230 2 } else d471 1 a471 2 } else d500 1 a500 1 } else d502 1 d713 1 a713 2 } else d878 1 a878 1 nd6_nud_hint(rt, dst6) d881 1 d897 4 a900 5 if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || !rt->rt_llinfo || !rt->rt_gateway || rt->rt_gateway->sa_family != AF_LINK) { d909 10 d1140 1 d1165 1 d1189 1 d1329 1 a1329 2 } else d1374 1 a1374 2 } else @ 1.30.4.1 log @pullup from main trunc (approved by releng-1-5) - add protection mechanism against ND cache corruption due to bad NUD hints. this is part of: sys/netinet/icmp6.h 1.9 -> 1.10 sys/netinet/tcp_input.c 1.111 -> 1.112 sys/netinet6/icmp6.c 1.34 -> 1.35 sys/netinet6/nd6.c 1.30 -> 1.31 sys/netinet6/nd6.h 1.14 -> 1.15 @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.30 2000/05/19 01:40:19 itojun Exp $ */ /* $KAME: nd6.c,v 1.68 2000/07/02 14:48:02 itojun Exp $ */ a93 2 int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */ d228 2 a229 1 } else d470 2 a471 1 } else d500 1 a500 1 } else { a501 1 } d712 2 a713 1 } else d878 1 a878 1 nd6_nud_hint(rt, dst6, force) a880 1 int force; d896 5 a900 4 if ((rt->rt_flags & RTF_GATEWAY) != 0 || (rt->rt_flags & RTF_LLINFO) == 0 || !rt->rt_llinfo || !rt->rt_gateway || rt->rt_gateway->sa_family != AF_LINK) { a908 10 /* * if we get upper-layer reachability confirmation many times, * it is possible we have false information. */ if (!force) { ln->ln_byhint++; if (ln->ln_byhint > nd6_maxnudhint) return; } a1129 1 ln->ln_byhint = 0; a1153 1 ln->ln_byhint = 0; a1176 1 ln->ln_byhint = 0; d1316 2 a1317 1 } else d1362 2 a1363 1 } else @ 1.30.4.2 log @Pull up revision 1.40 (via patch, requested by itojun): Tighten IPv6 ND6/dest6 option chasing bounds check. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.30.4.1 2000/07/20 00:07:05 itojun Exp $ */ d168 2 a169 8 /* * Don't initialize if called twice. * XXX: to detect this, we should choose a member that is never set * before initialization of the ND structure itself. We formaly used * the linkmtu member, which was not suitable because it could be * initialized via "ifconfig mtu". */ if (ND.basereachable) a274 6 /* make sure nd_opt_len is inside the buffer */ if ((caddr_t)&nd_opt->nd_opt_len >= (caddr_t)ndopts->nd_opts_last) { bzero(ndopts, sizeof(*ndopts)); return NULL; } d286 1 a286 6 if (ndopts->nd_opts_search > ndopts->nd_opts_last) { /* option overruns the end of buffer, invalid */ bzero(ndopts, sizeof(*ndopts)); return NULL; } else if (ndopts->nd_opts_search == ndopts->nd_opts_last) { /* reached the end of options chain */ @ 1.30.4.3 log @Pull up revision 1.36 (requested by itojun): Suppress ND6 logs that are too noisy for normal use. Can be re-enabled by net.inet6.icmp6.nd6_debug. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.30.4.2 2001/02/26 22:59:26 he Exp $ */ a94 6 #ifdef ND6_DEBUG int nd6_debug = 1; #else int nd6_debug = 0; #endif @ 1.29 log @do not try NUD unless the gateway is a real neighbor. real fix to KAME PR 245 (workaround has been implemented). @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.28 2000/04/27 00:33:47 itojun Exp $ */ /* $KAME: nd6.c,v 1.62 2000/05/09 11:35:55 itojun Exp $ */ d1633 5 a1637 1 nd6_output(ifp, ln->ln_hold, d1748 1 a1748 1 nd6_output(ifp, m0, dst, rt0) d1750 1 d1791 5 a1795 2 if (rt->rt_ifp != ifp) return nd6_output(ifp, m0, dst, rt); /* XXX: loop care? */ d1927 7 @ 1.28 log @temporary workaround against GIF NUD issue (when you configure globals onto GIF, NUD prevents packet from going out) KAME PR 245. From: Andreas Wrede @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.27 2000/04/19 07:13:03 itojun Exp $ */ /* $KAME: nd6.c,v 1.56 2000/04/19 06:17:43 itojun Exp $ */ a175 7 #if 1 /* XXX temporary workaround */ if (ifp->if_flags & IFF_POINTOPOINT) ND.flags = 0; else ND.flags = ND6_IFF_PERFORMNUD; #else a176 1 #endif d743 1 a743 1 struct in6_addr *addr; d752 7 a758 2 /* A link-local address is always a neighbor. */ if (IN6_IS_ADDR_LINKLOCAL(addr)) d773 2 a774 1 if ((IFADDR6(ifa).s6_addr32[i] ^ addr->s6_addr32[i]) & d785 1 a785 1 if (nd6_lookup(addr, 0, ifp)) d1752 1 d1764 1 a1764 1 * draft-ietf-ngtrans-mech-04.txt says: a1776 4 if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && (nd_ifinfo[ifp->if_index].flags & ND6_IFF_PERFORMNUD) == 0) goto sendpkt; d1791 1 d1793 27 d1844 7 a1850 1 if ((rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL) d1854 10 a1863 4 log(LOG_DEBUG, "nd6_output: can't allocate llinfo for %s " "(ln=%p, rt=%p)\n", ip6_sprintf(&dst->sin6_addr), ln, rt); senderr(EIO); /* XXX: good error? */ @ 1.27 log @add boundary check for nd6_ifinfo (otherwise ndp -i can make out-of-bound accesses). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.26 2000/04/16 15:28:00 itojun Exp $ */ d176 7 d184 1 @ 1.26 log @perform neighbor unreachability detection on p2p links (spec requires it for bidir p2p links). improve -i in ndp(8) to allow tweaking per-interface ND flag on. fix ndp(8) infinite loop on certain routing table setup. @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.25 2000/04/16 15:00:57 itojun Exp $ */ /* $KAME: nd6.c,v 1.55 2000/04/16 14:08:30 itojun Exp $ */ d98 1 a140 1 static size_t if_indexlim = 8; d146 1 a146 1 if (nd_ifinfo == NULL || if_index >= if_indexlim) { d150 2 a151 2 while (if_index >= if_indexlim) if_indexlim <<= 1; d154 1 a154 1 n = if_indexlim * sizeof(struct nd_ifinfo); d1397 4 d1405 4 d1718 2 @ 1.25 log @better sync with latest kame (cosmetic only). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.24 2000/04/13 16:27:00 itojun Exp $ */ d176 1 d396 2 d407 1 d461 12 a472 6 ln->ln_asked = 1; ln->ln_state = ND6_LLINFO_PROBE; ln->ln_expire = time_second + nd_ifinfo[ifp->if_index].retrans / 1000; nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); a473 1 d1086 13 a1098 4 if (gate->sa_family != AF_LINK || gate->sa_len < sizeof(null_sdl)) { log(LOG_DEBUG, "nd6_rtrequest: bad gateway value\n"); break; d1100 1 a1100 3 SDL(gate)->sdl_type = ifp->if_type; SDL(gate)->sdl_index = ifp->if_index; if (ln != 0) d1399 4 d1745 4 a1748 1 * other than ARCnet, Ethernet and FDDI. d1754 1 d1760 4 d1813 4 @ 1.24 log @add comment on sdl_alen check (sync with kame) @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.23 2000/04/13 14:32:53 itojun Exp $ */ /* $KAME: nd6.c,v 1.41 2000/02/24 16:34:50 itojun Exp $ */ d7 1 a7 1 * d19 1 a19 1 * d351 1 a351 1 log(LOG_INFO, d414 3 d452 1 a452 1 /* d654 1 a654 1 * If we want to create a neighbor cache for the address, we d665 2 d683 1 a683 1 * called in rtequest via ifa->ifa_rtrequest. d685 7 a691 6 if (rtrequest(RTM_ADD, (struct sockaddr *)&sin6, ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) d694 2 a695 1 "neighbor(%s)\n", ip6_sprintf(addr6)); d730 1 a730 1 * XXX: should take care of the destination of a p2p link? d1109 1 a1109 1 /* d1602 1 a1602 1 #endif d1651 1 a1651 1 * is_router flag. Otherwise, if the entry is newly created, a1652 1 * d1737 1 a1737 1 * next hop determination. This routine is derived from ether_outpout. d1747 1 a1747 1 } else d1835 1 a1835 1 @ 1.23 log @bark if sdl_alen == 0. test code for KAME PR 235. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.22 2000/04/13 14:11:06 itojun Exp $ */ d1870 1 @ 1.22 log @even if nd6_nud_hint is called, do not change a neighbor's status unless the old status is probably reachable (i.e. the link-layer address has already been resolved). KAME PR 235. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.21 2000/04/12 10:36:45 itojun Exp $ */ d1869 4 a1872 2 if (sdl->sdl_alen != 0) bcopy(LLADDR(sdl), desten, sdl->sdl_alen); d1874 1 @ 1.21 log @revisit in6_ifattach(). - be persistent on initializing interfaces, even if there's manually- assigned linklocal, multicast/whatever initialization is necessary. - do not cache mac addr in the kernel. grab mac addr from existing cards (this is important when you swap ethernet cards back and forth) now ppp6 works just fine! call in6_ifattach() on ATM PVC interface to assign link-local, using hardware MAC address as seed. (the change is in sync with kame tree). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.20 2000/03/23 07:03:30 thorpej Exp $ */ d884 1 a884 1 if (ln->ln_state == ND6_LLINFO_INCOMPLETE) @ 1.20 log @New callout mechanism with two major improvements over the old timeout()/untimeout() API: - Clients supply callout handle storage, thus eliminating problems of resource allocation. - Insertion and removal of callouts is constant time, important as this facility is used quite a lot in the kernel. The old timeout()/untimeout() API has been removed from the kernel. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.19 2000/02/28 12:08:24 itojun Exp $ */ d165 5 @ 1.19 log @remove some of cross-BSD portability #ifdef. remove xxCTL_VARS, which is BSDI specific. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.18 2000/02/26 08:39:20 itojun Exp $ */ d43 1 d107 3 d132 2 a133 1 timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); d380 2 a381 1 timeout(nd6_timer, (caddr_t)0, nd6_prune * hz); d1676 2 a1677 1 timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); @ 1.18 log @bring in recent KAME changes (only important and stable ones, as usual). - remove net.inet6.ip6.nd6_proxyall. introduce proxy NDP code works just like "arp -s". - revise source address selection. be more careful about use of yet-to-be-valid addresses as source. - as router, transmit ICMP6_DST_UNREACH_BEYONDSCOPE against out-of-scope packet forwarding attempt. - path MTU discovery takes care of routing header properly. - be more strict about mbuf chain parsing. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.17 2000/02/06 12:49:47 itojun Exp $ */ a779 1 #ifdef __NetBSD__ a780 3 #else s = splnet(); #endif @ 1.17 log @fix include pathname for better rfc2292 compliance. @ text @d1 2 a2 1 /* $NetBSD: nd6.c,v 1.16 2000/02/04 14:34:27 itojun Exp $ */ d49 1 a88 1 int nd6_proxyall = 0; /* enable Proxy Neighbor Advertisement */ d435 1 a435 1 if (ln->ln_expire) { a436 1 } d581 1 a581 1 * nd6_rtrequest(), and ip6_input()). d600 2 a601 1 * Interface route will be retained by nd6_free(). Nuke it. d772 6 d780 1 d782 3 d1007 1 a1007 1 if (rt->rt_flags & RTF_CLONING || rt->rt_flags & RTF_LLINFO) { d1034 20 a1053 1 /* Announce a new entry if requested. */ d1056 5 a1060 4 &SIN6(rt_key(rt))->sin6_addr, &SIN6(rt_key(rt))->sin6_addr, ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1); d1064 1 a1064 1 gate->sa_len < sizeof(null_sdl)) { d1138 21 d1165 17 d1235 1 a1235 1 1); d1297 5 d1339 1 a1343 1 splx(s); d1359 1 d1363 1 @ 1.16 log @avoid calling in6_control(SIOCDIFADDR_IN6) from interrupt context. it is not supposed to work. logging fix: add "\n" to some of log() in in6_prefix.c. improve in6_ifdetach(). now almost all structure depend on ifnet will be cleared up. possible loose ends: - cached route_in6 in static varaiables needs to be cleared as well - there are ifaddr manipulation without reference counting, which should be fixed we still see panics after card removal, though... not sure what is left. (sync with kame) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.15 2000/02/03 12:50:05 itojun Exp $ */ d64 1 a64 1 #include d68 1 a68 1 #include @ 1.15 log @remove #if 0'ed code @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.14 2000/02/01 22:52:11 thorpej Exp $ */ d528 92 @ 1.14 log @First-draft if_detach() implementation, originally from Bill Studnemund, although this version has been changed somewhat: - reference counting on ifaddrs isn't as complete as Bill's original work was. This is hard to get right, and we should attack one protocol at a time. - This doesn't do reference counting or dynamic allocation of ifnets yet. - This version introduces a new PRU -- PRU_PURGEADDR, which is used to purge an ifaddr from a protocol. The old method Bill used didn't work on all protocols, and it only worked on some because it was Very Lucky. This mostly works ... i.e. works for my USB Ethernet, except for a dangling ifaddr reference left by the IPv6 code; have not yet tracked this down. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.13 2000/01/06 15:46:10 itojun Exp $ */ a979 3 #if 0 insque(ln, &llinfo_nd6); #else a983 1 #endif a1021 3 #if 0 remque(ln); #else a1024 1 #endif @ 1.13 log @remove extra portability #ifdef (like #ifdef __FreeBSD__) in KAME IPv6/IPsec code, from netbsd-current repository. #ifdef'ed version is always available from ftp.kame.net. XXX please do not make too many diff-unfriendly changes, we'll need to take bunch of diffs on upgrade... @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.12 1999/12/13 15:17:23 itojun Exp $ */ d1014 2 a1015 2 rt->rt_ifa->ifa_refcnt--; ifa->ifa_refcnt++; @ 1.12 log @sync IPv6 part with latest KAME tree. IPsec part is left unmodified due to massive changes in KAME side. - IPv6 output goes through nd6_output - faith can capture IPv4 packets as well - you can run IPv4-to-IPv6 translator using heavily modified DNS servers - per-interface statistics (required for IPv6 MIB) - interface autoconfig is revisited - udp input handling has a big change for mapped address support. - introduce in4_cksum() for non-overwriting checksumming - introduce m_pulldown() - neighbor discovery cleanups/improvements - netinet/in.h strictly conforms to RFC2553 (no extra defs visible to userland) - IFA_STATS is fixed a bit (not tested) - and more more more. TODO: - cleanup os-independency #ifdef - avoid rcvif dual use (for IPsec) to help ifdetach (sorry for jumbo commit, I can't separate this any more...) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.11 1999/12/10 17:56:13 itojun Exp $ */ a48 1 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) a49 1 #endif a55 1 #if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) a56 1 #endif a59 9 #ifndef __NetBSD__ #include #ifdef __FreeBSD__ #include #endif #ifdef __bsdi__ #include #endif #else /* __NetBSD__ */ a62 1 #endif /* __NetBSD__ */ a69 1 #ifndef __bsdi__ a70 2 #endif #if defined(__NetBSD__) || defined(__OpenBSD__) a71 1 #endif a100 3 #if 0 extern int ip6_forwarding; #endif a188 10 #if defined(__FreeBSD__) || defined(__bsdi__) case IFT_FDDI: #if defined(__bsdi__) && _BSDI_VERSION >= 199802 ndi->maxmtu = MIN(FDDIMTU, ifp->if_mtu); #else ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); #endif break; #endif #if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) a191 1 #endif a370 1 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) a371 1 #endif a372 1 #ifdef __NetBSD__ a373 3 #else s = splnet(); #endif d543 1 a543 5 rt = rtalloc1((struct sockaddr *)&sin6, create #ifdef __FreeBSD__ , 0UL #endif /*__FreeBSD__*/ ); a639 3 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) #else a642 1 #endif a680 1 #ifdef __NetBSD__ a681 3 #else s = splnet(); #endif a750 1 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) a751 1 #endif a803 1 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) a804 1 #endif a879 6 #if defined(__bsdi__) && _BSDI_VERSION >= 199802 nd6_rtrequest(req, rt, info) int req; struct rtentry *rt; struct rt_addrinfo *info; /* xxx unused */ #else a883 1 #endif a889 1 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) a890 1 #endif a1003 9 #ifdef __bsdi__ #if _BSDI_VERSION >= 199802 extern struct ifnet *loifp; rt->rt_ifp = loifp; /*XXX*/ #else extern struct ifnet loif; rt->rt_ifp = &loif; /*XXX*/ #endif #else /* non-bsdi */ a1004 1 #endif a1041 6 #if defined(__bsdi__) && _BSDI_VERSION >= 199802 nd6_p2p_rtrequest(req, rt, info) int req; struct rtentry *rt; struct rt_addrinfo *info; /* xxx unused */ #else a1045 1 #endif a1092 9 #ifdef __bsdi__ #if _BSDI_VERSION >= 199802 extern struct ifnet *loifp; rt->rt_ifp = loifp; /*XXX*/ #else extern struct ifnet loif; rt->rt_ifp = &loif; /*XXX*/ #endif #else a1093 1 #endif /*__bsdi__*/ a1119 1 #ifdef __NetBSD__ a1120 3 #else s = splnet(); #endif a1144 1 #ifdef __NetBSD__ a1145 3 #else s = splnet(); #endif a1224 1 #ifdef __NetBSD__ a1225 3 #else s = splnet(); #endif a1239 1 #ifdef __NetBSD__ a1240 3 #else s = splnet(); #endif a1271 1 #ifdef __NetBSD__ a1272 3 #else s = splnet(); #endif a1317 1 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) a1318 1 #endif a1509 1 #ifdef __NetBSD__ a1510 3 #else int s = splnet(); #endif a1543 1 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) a1544 1 #endif a1566 4 #ifdef __FreeBSD__ if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1, 0UL)) != NULL) #else a1568 1 #endif a1580 3 #ifdef __FreeBSD__ lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL); #else a1581 1 #endif a1583 9 #ifdef __bsdi__ /* the "G" test below also prevents rt == rt0 */ if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_ifp != ifp)) { rt->rt_refcnt--; rt0->rt_gwroute = 0; senderr(EHOSTUNREACH); } #endif @ 1.11 log @add missing splx(). a critical bug fix from kame. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.10 1999/09/20 02:35:44 itojun Exp $ */ d49 1 a49 1 #if !defined(__FreeBSD__) || __FreeBSD__ < 3 d58 1 d60 1 d81 1 d84 1 d86 2 a87 1 #ifdef __NetBSD__ d91 2 a95 4 #if !defined(__FreeBSD__) || __FreeBSD__ < 3 #define time_second time.tv_sec #endif d107 3 d114 2 a115 2 struct nd_ifinfo *nd_ifinfo; struct nd_drhead nd_defrouter = { 0 }; d122 1 d130 1 d136 9 d212 3 d216 1 d219 1 d223 1 d379 2 a380 1 if (i > 10) { d403 3 d407 1 d409 3 d508 1 a508 1 dr = nd_defrouter.lh_first; d512 1 a512 1 t = dr->dr_next; d516 1 a516 1 dr = dr->dr_next; a567 4 static struct sockaddr_in6 all1_sa = { sizeof(struct sockaddr_in6), AF_INET6, 0, 0, {{{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}}}, 0}; d639 7 d647 2 a648 1 rt->rt_gateway->sa_family != AF_LINK) { d650 2 a651 2 log(LOG_DEBUG, "nd6_lookup: failed to lookup %s\n", ip6_sprintf(addr6)); d682 1 a682 1 #ifdef __bsdi__ d722 2 d725 1 a725 4 if (ln->ln_router) { /* remove from default router list */ struct nd_defrouter *dr; struct in6_addr *in6; d727 1 a727 2 in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; d729 4 a732 2 dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))-> sin6_addr, d734 16 a749 3 if (dr) defrtrlist_del(dr); else if (!ip6_forwarding && ip6_accept_rtadv) { d751 5 a755 2 * rt6_flush must be called in any case. * see the comment in nd6_na_input(). d757 16 a772 1 rt6_flush(in6, rt->rt_ifp); d776 1 a776 1 d778 1 a778 1 sdl->sdl_family == AF_LINK) { d785 3 a787 2 rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), 0, (struct rtentry **)0); d801 3 d835 1 d856 3 d871 1 d931 1 d934 6 d944 1 d951 3 d1039 1 a1039 1 ln->ln_state = ND6_LLINFO_INCOMPLETE; d1068 4 d1074 2 a1075 2 #endif /*__bsdi__*/ #if defined(__FreeBSD__) || defined(__NetBSD__) d1115 6 d1125 1 d1156 1 a1156 1 /* Announce a new entry if rqquested. */ d1174 4 d1180 3 a1183 3 #if defined(__FreeBSD__) || defined(__NetBSD__) rt->rt_ifp = &loif[0]; /*XXX*/ #endif d1200 1 d1210 1 d1212 4 a1215 1 dr = nd_defrouter.lh_first; d1233 1 a1233 1 dr = dr->dr_next; d1239 1 d1241 3 d1284 19 d1307 1 a1307 1 case SIOCSNDFLUSH_IN6: d1315 1 d1323 1 d1325 3 d1342 1 d1344 4 a1347 1 if ((dr = nd_defrouter.lh_first) != NULL) { d1352 2 a1353 2 for (dr = dr->dr_next; dr; dr = next) { next = dr->dr_next; d1356 1 a1356 1 defrtrlist_del(nd_defrouter.lh_first); d1363 14 a1376 1 struct llinfo_nd6 *ln; d1378 18 a1395 14 s = splsoftnet(); if ((rt = nd6_lookup(&nbi->addr, 0, ifp)) == NULL) { error = EINVAL; splx(s); break; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; nbi->state = ln->ln_state; nbi->asked = ln->ln_asked; nbi->isrouter = ln->ln_router; nbi->expire = ln->ln_expire; splx(s); break; d1397 6 d1428 3 d1533 1 d1536 5 d1622 1 d1624 3 a1647 2 #ifdef NEWIP6OUTPUT /* for experimental */ d1660 3 d1687 1 a1687 1 NULL) { d1690 1 a1690 1 NULL) { d1692 1 a1825 1 break; a1841 1 #endif /* NEWIP6OUTPUT */ @ 1.10 log @tiny fix to ARCnet IPv6 support. - in in6_ifattach_getifid(), we can grab interface id source iff the source is universally (worldwide) unique. ARCnet hardware address is of 8bit and does not satisfy the condition. (in6_ifattach_getifid() is for getting interface id usable for pseudo interfaces like gif*) - xx_to_eui64() should return EUI64 format, not IPv6 interface id format. this may seem awkward so I wish to clean these things up. - in nd6.c, change if clause into case clause to allow future addition of IFT_xxx easier. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.9 1999/09/19 21:31:35 is Exp $ */ d1230 1 @ 1.10.2.1 log @Update thorpej_scsipi to -current as of a month ago @ text @d1 1 a1 2 /* $NetBSD: nd6.c,v 1.32 2000/10/15 15:39:12 itojun Exp $ */ /* $KAME: nd6.c,v 1.75 2000/10/15 15:23:11 itojun Exp $ */ d6 1 a6 1 * d18 1 a18 1 * a41 1 #include a47 1 #include d49 1 d51 1 d62 9 d74 1 d76 1 a76 1 #include d79 1 a79 2 #include #include d82 1 d84 1 a84 2 #include d89 4 d102 1 a102 5 /* preventing too many loops in ND option parsing */ int nd6_maxndopt = 10; /* max # of ND options allowed */ int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */ d108 2 a109 3 static size_t nd_ifinfo_indexlim = 8; struct nd_ifinfo *nd_ifinfo = NULL; struct nd_drhead nd_defrouter; d113 3 a115 1 static struct sockaddr_in6 all1_sa; a118 3 struct callout nd6_slowtimo_ch; struct callout nd6_timer_ch; a122 1 int i; a127 9 all1_sa.sin6_family = AF_INET6; all1_sa.sin6_len = sizeof(struct sockaddr_in6); for (i = 0; i < sizeof(all1_sa.sin6_addr); i++) all1_sa.sin6_addr.s6_addr[i] = 0xff; /* initialization of the default router list */ TAILQ_INIT(&nd_defrouter); d131 1 a131 2 callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, nd6_slowtimo, NULL); d138 1 d144 1 a144 1 if (nd_ifinfo == NULL || if_index >= nd_ifinfo_indexlim) { d148 2 a149 2 while (if_index >= nd_ifinfo_indexlim) nd_ifinfo_indexlim <<= 1; d152 1 a152 1 n = nd_ifinfo_indexlim * sizeof(struct nd_ifinfo); a162 5 /* don't initialize if called twice */ if (ND.linkmtu) return; a168 1 ND.flags = ND6_IFF_PERFORMNUD; d193 5 d225 2 a226 1 } else d349 1 a349 1 log(LOG_DEBUG, d356 1 a356 2 if (i > nd6_maxndopt) { icmp6stat.icp6s_nd_toomanyopt++; a378 1 long time_second = time.tv_sec; d381 1 a381 2 callout_reset(&nd6_timer_ch, nd6_prune * hz, nd6_timer, NULL); a389 2 /* XXX: used for the DELAY case only: */ struct nd_ifinfo *ndi = NULL; a398 1 ndi = &nd_ifinfo[ifp->if_index]; a408 3 if (rt->rt_llinfo && (struct llinfo_nd6 *)rt->rt_llinfo != ln) panic("rt_llinfo(%p) is not equal to ln(%p)\n", rt->rt_llinfo, ln); d441 1 a441 1 if (ln->ln_expire) d443 1 d445 1 a445 1 /* d450 6 a455 11 if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) { /* We need NUD */ ln->ln_asked = 1; ln->ln_state = ND6_LLINFO_PROBE; ln->ln_expire = time_second + ndi->retrans / 1000; nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); } else ln->ln_state = ND6_LLINFO_STALE; /* XXX */ d457 1 d477 1 a477 1 dr = TAILQ_FIRST(&nd_defrouter); d481 1 a481 1 t = TAILQ_NEXT(dr, dr_entry); d484 2 a485 3 } else { dr = TAILQ_NEXT(dr, dr_entry); } d537 3 a539 92 /* * Nuke neighbor cache/prefix/default router management table, right before * ifp goes away. */ void nd6_purge(ifp) struct ifnet *ifp; { struct llinfo_nd6 *ln, *nln; struct nd_defrouter *dr, *ndr, drany; struct nd_prefix *pr, *npr; /* Nuke default router list entries toward ifp */ if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { /* * The first entry of the list may be stored in * the routing table, so we'll delete it later. */ for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = ndr) { ndr = TAILQ_NEXT(dr, dr_entry); if (dr->ifp == ifp) defrtrlist_del(dr); } dr = TAILQ_FIRST(&nd_defrouter); if (dr->ifp == ifp) defrtrlist_del(dr); } /* Nuke prefix list entries toward ifp */ for (pr = nd_prefix.lh_first; pr; pr = npr) { npr = pr->ndpr_next; if (pr->ndpr_ifp == ifp) { if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); prelist_remove(pr); } } /* cancel default outgoing interface setting */ if (nd6_defifindex == ifp->if_index) nd6_setdefaultiface(0); /* refresh default router list */ bzero(&drany, sizeof(drany)); defrouter_delreq(&drany, 0); defrouter_select(); /* * Nuke neighbor cache entries for the ifp. * Note that rt->rt_ifp may not be the same as ifp, * due to KAME goto ours hack. See RTM_RESOLVE case in * nd6_rtrequest(), and ip6_input(). */ ln = llinfo_nd6.ln_next; while (ln && ln != &llinfo_nd6) { struct rtentry *rt; struct sockaddr_dl *sdl; nln = ln->ln_next; rt = ln->ln_rt; if (rt && rt->rt_gateway && rt->rt_gateway->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *)rt->rt_gateway; if (sdl->sdl_index == ifp->if_index) nd6_free(rt); } ln = nln; } /* * Neighbor cache entry for interface route will be retained * with ND6_LLINFO_WAITDELETE state, by nd6_free(). Nuke it. */ ln = llinfo_nd6.ln_next; while (ln && ln != &llinfo_nd6) { struct rtentry *rt; struct sockaddr_dl *sdl; nln = ln->ln_next; rt = ln->ln_rt; if (rt && rt->rt_gateway && rt->rt_gateway->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *)rt->rt_gateway; if (sdl->sdl_index == ifp->if_index) { rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), 0, (struct rtentry **)0); } } ln = nln; } } d554 5 a558 1 rt = rtalloc1((struct sockaddr *)&sin6, create); d562 1 a562 1 * If we want to create a neighbor cache for the address, we a572 2 int e; d589 1 a589 1 * called in rtequest via ifa->ifa_rtrequest. d591 6 a596 7 if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6, ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) != 0) d599 1 a599 2 "neighbor(%s), errno=%d\n", ip6_sprintf(addr6), e); d607 2 a608 1 } else a611 7 /* * Validation for the entry. * XXX: we can't use rt->rt_ifp to check for the interface, since * it might be the loopback interface if the entry is for our * own address on a non-loopback interface. Instead, we should * use rt->rt_ifa->ifa_ifp, which would specify the REAL interface. */ d613 1 a613 2 rt->rt_gateway->sa_family != AF_LINK || (ifp && rt->rt_ifa->ifa_ifp != ifp)) { d615 2 a616 2 log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec"); d626 1 a626 1 * XXX: should take care of the destination of a p2p link? d630 1 a630 1 struct sockaddr_in6 *addr; d639 2 a640 7 /* * A link-local address is always a neighbor. * XXX: we should use the sin6_scope_id field rather than the embedded * interface index. */ if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr) && ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]) == ifp->if_index) d647 3 d653 1 d659 1 a659 2 if ((IFADDR6(ifa).s6_addr32[i] ^ addr->sin6_addr.s6_addr32[i]) & d670 1 a670 1 if (nd6_lookup(&addr->sin6_addr, 0, ifp)) a686 2 struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; struct nd_defrouter *dr; d688 6 a693 5 /* * Clear all destination cache entries for the neighbor. * XXX: is it better to restrict this to hosts? */ pfctlinput(PRC_HOSTDEAD, rt_key(rt)); a694 2 if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */ int s; d696 2 a697 1 dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, d699 3 a701 10 if (ln->ln_router || dr) { /* * rt6_flush must be called whether or not the neighbor * is in the Default Router List. * See a corresponding comment in nd6_na_input(). */ rt6_flush(&in6, rt->rt_ifp); } if (dr) { d703 2 a704 3 * Unreachablity of a router might affect the default * router selection and on-link detection of advertised * prefixes. d706 1 a706 24 /* * Temporarily fake the state to choose a new default * router and to perform on-link determination of * prefixes coreectly. * Below the state will be set correctly, * or the entry itself will be deleted. */ ln->ln_state = ND6_LLINFO_INCOMPLETE; if (dr == TAILQ_FIRST(&nd_defrouter)) { /* * It is used as the current default router, * so we have to move it to the end of the * list and choose a new one. * XXX: it is not very efficient if this is * the only router. */ TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); TAILQ_INSERT_TAIL(&nd_defrouter, dr, dr_entry); defrouter_select(); } pfxlist_onlink_check(); d710 1 a710 1 d712 1 a712 1 sdl->sdl_family == AF_LINK) { d719 2 a720 3 rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), 0, (struct rtentry **)0); d729 1 a729 1 nd6_nud_hint(rt, dst6, force) a731 1 int force; a733 1 long time_second = time.tv_sec; d746 5 a750 4 if ((rt->rt_flags & RTF_GATEWAY) != 0 || (rt->rt_flags & RTF_LLINFO) == 0 || !rt->rt_llinfo || !rt->rt_gateway || rt->rt_gateway->sa_family != AF_LINK) { d756 1 a756 1 if (ln->ln_state < ND6_LLINFO_REACHABLE) a758 10 /* * if we get upper-layer reachability confirmation many times, * it is possible we have false information. */ if (!force) { ln->ln_byhint++; if (ln->ln_byhint > nd6_maxnudhint) return; } a764 1 #ifdef OLDIP6OUTPUT a784 1 long time_second = time.tv_sec; a796 1 break; a855 1 #endif /* OLDIP6OUTPUT */ a867 1 long time_second = time.tv_sec; d881 1 a881 1 if (rt->rt_flags & (RTF_CLONING | RTF_LLINFO)) { d908 1 a908 20 /* * In IPv4 code, we try to annonuce new RTF_ANNOUNCE entry here. * We don't do that here since llinfo is not ready yet. * * There are also couple of other things to be discussed: * - unsolicited NA code needs improvement beforehand * - RFC2461 says we MAY send multicast unsolicited NA * (7.2.6 paragraph 4), however, it also says that we * SHOULD provide a mechanism to prevent multicast NA storm. * we don't have anything like it right now. * note that the mechanism need a mutual agreement * between proxies, which means that we need to implement * a new protocol, or new kludge. * - from RFC2461 6.2.4, host MUST NOT send unsolicited NA. * we need to check ip6forwarding before sending it. * (or should we allow proxy ND configuration only for * routers? there's no mention about proxy ND from hosts) */ #if 0 /* XXX it does not work */ d911 4 a914 5 &SIN6(rt_key(rt))->sin6_addr, &SIN6(rt_key(rt))->sin6_addr, ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1, NULL); #endif d917 4 a920 13 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { /* * Address resolution isn't necessary for a point to * point link, so we can skip this test for a p2p link. */ if (gate->sa_family != AF_LINK || gate->sa_len < sizeof(null_sdl)) { log(LOG_DEBUG, "nd6_rtrequest: bad gateway value\n"); break; } SDL(gate)->sdl_type = ifp->if_type; SDL(gate)->sdl_index = ifp->if_index; d922 3 a924 1 if (ln != NULL) a947 1 ln->ln_byhint = 0; d949 1 a949 1 /* d953 1 a953 1 ln->ln_state = ND6_LLINFO_NOSTATE; d957 3 d964 1 a975 1 ln->ln_byhint = 0; d981 5 d987 1 d997 2 a998 2 IFAFREE(rt->rt_ifa); IFAREF(ifa); a1001 22 } else if (rt->rt_flags & RTF_ANNOUNCE) { ln->ln_expire = 0; ln->ln_state = ND6_LLINFO_REACHABLE; ln->ln_byhint = 0; /* join solicited node multicast for proxy ND */ if (ifp->if_flags & IFF_MULTICAST) { struct in6_addr llsol; int error; llsol = SIN6(rt_key(rt))->sin6_addr; llsol.s6_addr16[0] = htons(0xff02); llsol.s6_addr16[1] = htons(ifp->if_index); llsol.s6_addr32[1] = 0; llsol.s6_addr32[2] = htonl(1); llsol.s6_addr8[12] = 0xff; (void)in6_addmulti(&llsol, ifp, &error); if (error) printf( "nd6_rtrequest: could not join solicited node multicast (errno=%d)\n", error); } a1007 17 /* leave from solicited node multicast for proxy ND */ if ((rt->rt_flags & RTF_ANNOUNCE) != 0 && (ifp->if_flags & IFF_MULTICAST) != 0) { struct in6_addr llsol; struct in6_multi *in6m; llsol = SIN6(rt_key(rt))->sin6_addr; llsol.s6_addr16[0] = htons(0xff02); llsol.s6_addr16[1] = htons(ifp->if_index); llsol.s6_addr32[1] = 0; llsol.s6_addr32[2] = htonl(1); llsol.s6_addr8[12] = 0xff; IN6_LOOKUP_MULTI(llsol, ifp, in6m); if (in6m) in6_delmulti(in6m); } d1009 3 d1015 1 d1059 1 a1059 1 /* Announce a new entry if requested. */ d1065 1 a1065 1 1, NULL); d1076 5 d1082 1 a1098 1 struct in6_ndifreq *ndif = (struct in6_ndifreq *)data; d1109 1 a1109 1 dr = TAILQ_FIRST(&nd_defrouter); d1115 2 a1116 1 } else d1127 1 a1127 1 dr = TAILQ_NEXT(dr, dr_entry); a1131 5 /* * XXX meaning of fields, especialy "raflags", is very * differnet between RA prefix list and RR/static prefix list. * how about separating ioctls into two? */ d1156 2 a1157 1 } else a1168 1 prl->prefix[i].origin = PR_ORIG_RA; a1172 19 { struct rr_prefix *rpp; for (rpp = LIST_FIRST(&rr_prefix); rpp; rpp = LIST_NEXT(rpp, rp_entry)) { if (i >= PRLSTSIZ) break; prl->prefix[i].prefix = rpp->rp_prefix.sin6_addr; prl->prefix[i].raflags = rpp->rp_raf; prl->prefix[i].prefixlen = rpp->rp_plen; prl->prefix[i].vltime = rpp->rp_vltime; prl->prefix[i].pltime = rpp->rp_pltime; prl->prefix[i].if_index = rpp->rp_ifp->if_index; prl->prefix[i].expire = rpp->rp_expire; prl->prefix[i].advrtrs = 0; prl->prefix[i].origin = rpp->rp_origin; i++; } } a1173 1 a1175 4 if (!nd_ifinfo || i >= nd_ifinfo_indexlim) { error = EINVAL; break; } d1178 1 a1178 9 case SIOCSIFINFO_FLAGS: /* XXX: almost all other fields of ndi->ndi is unused */ if (!nd_ifinfo || i >= nd_ifinfo_indexlim) { error = EINVAL; break; } nd_ifinfo[ifp->if_index].flags = ndi->ndi.flags; break; case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */ a1185 1 defrouter_select(); d1209 1 a1209 1 if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { d1214 2 a1215 2 for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = next) { next = TAILQ_NEXT(dr, dr_entry); d1218 1 a1218 1 defrtrlist_del(TAILQ_FIRST(&nd_defrouter)); d1225 1 a1225 10 struct llinfo_nd6 *ln; struct in6_addr nb_addr = nbi->addr; /* make local for safety */ /* * XXX: KAME specific hack for scoped addresses * XXXX: for other scopes than link-local? */ if (IN6_IS_ADDR_LINKLOCAL(&nbi->addr) || IN6_IS_ADDR_MC_LINKLOCAL(&nbi->addr)) { u_int16_t *idp = (u_int16_t *)&nb_addr.s6_addr[2]; d1227 13 a1239 18 if (*idp == 0) *idp = htons(ifp->if_index); } s = splsoftnet(); if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL) { error = EINVAL; splx(s); break; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; nbi->state = ln->ln_state; nbi->asked = ln->ln_asked; nbi->isrouter = ln->ln_router; nbi->expire = ln->ln_expire; splx(s); break; a1240 6 case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ ndif->ifindex = nd6_defifindex; break; case SIOCSDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ return(nd6_setdefaultiface(ndif->ifindex)); break; a1265 1 long time_second = time.tv_sec; a1367 1 #ifdef OLDIP6OUTPUT a1369 9 #else /* * we assume ifp is not a p2p here, so just * set the 2nd argument as the 1st one. */ nd6_output(ifp, ifp, ln->ln_hold, (struct sockaddr_in6 *)rt_key(rt), rt); #endif d1418 1 a1418 1 * is_router flag. Otherwise, if the entry is newly created, d1420 1 d1455 1 a1455 2 callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, nd6_slowtimo, NULL); a1456 2 if (!nd_ifinfo || i >= nd_ifinfo_indexlim) continue; d1473 2 d1477 1 a1477 1 nd6_output(ifp, origifp, m0, dst, rt0) a1478 1 struct ifnet *origifp; a1484 1 struct sockaddr_in6 *gw6 = NULL; a1486 1 long time_second = time.tv_sec; d1493 1 a1493 4 * other than ARCnet, Ethernet, FDDI and GIF. * * draft-ietf-ngtrans-mech-06.txt says: * - unidirectional tunnels needs no ND a1498 1 case IFT_GIF: /* XXX need more cases? */ d1505 1 a1505 1 * next hop determination. This routine is derived from ether_outpout. d1509 4 d1514 2 a1515 2 NULL) { d1517 3 a1519 6 if (rt->rt_ifp != ifp) { /* XXX: loop care? */ return nd6_output(ifp, origifp, m0, dst, rt); } } else a1521 1 a1522 27 gw6 = (struct sockaddr_in6 *)rt->rt_gateway; /* * We skip link-layer address resolution and NUD * if the gateway is not a neighbor from ND point * of view, regardless the value of the value of * nd_ifinfo.flags. * The second condition is a bit tricky: we skip * if the gateway is our own address, which is * sometimes used to install a route to a p2p link. */ if (!nd6_is_addr_neighbor(gw6, ifp) || in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { if (rt->rt_flags & RTF_REJECT) senderr(EHOSTDOWN); /* * We allow this kind of tricky route only * when the outgoing interface is p2p. * XXX: we may need a more generic rule here. */ if ((ifp->if_flags & IFF_POINTOPOINT) == 0) senderr(EHOSTUNREACH); goto sendpkt; } d1527 3 d1531 1 d1534 9 d1560 1 a1560 7 /* * Since nd6_is_addr_neighbor() internally calls nd6_lookup(), * the condition below is not very efficient. But we believe * it is tolerable, because this should be a rare case. */ if (nd6_is_addr_neighbor(dst, ifp) && (rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL) d1564 6 a1569 16 if ((ifp->if_flags & IFF_POINTOPOINT) == 0 && !(nd_ifinfo[ifp->if_index].flags & ND6_IFF_PERFORMNUD)) { log(LOG_DEBUG, "nd6_output: can't allocate llinfo for %s " "(ln=%p, rt=%p)\n", ip6_sprintf(&dst->sin6_addr), ln, rt); senderr(EIO); /* XXX: good error? */ } goto sendpkt; /* send anyway */ } /* We don't have to do link-layer address resolution on a p2p link. */ if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && ln->ln_state < ND6_LLINFO_REACHABLE) ln->ln_state = ND6_LLINFO_STALE; a1618 7 #ifdef FAKE_LOOPBACK_IF if (ifp->if_flags & IFF_LOOPBACK) { return((*ifp->if_output)(origifp, m, (struct sockaddr *)dst, rt)); } #endif d1620 1 a1620 1 d1649 1 d1655 2 a1656 5 if (rt == NULL) { /* this could happen, if we could not allocate memory */ return(0); } if (rt->rt_gateway->sa_family != AF_LINK) { d1661 2 a1662 5 if (sdl->sdl_alen == 0) { /* this should be impossible, but we bark here for debugging */ printf("nd6_storelladdr: sdl_alen == 0\n"); return(0); } a1663 1 bcopy(LLADDR(sdl), desten, sdl->sdl_alen); d1666 1 @ 1.10.2.2 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD$ */ a59 1 #include a205 3 case IFT_IEEE1394: ndi->maxmtu = MIN(IEEE1394MTU, ifp->if_mtu); break; d955 1 a955 3 case IFT_IEEE1394: bcopy(ifp->if_broadcastaddr, desten, ifp->if_addrlen); return(1); d959 1 a1786 1 case IFT_IEEE1394: d1971 1 a1971 3 case IFT_IEEE1394: bcopy(ifp->if_broadcastaddr, desten, ifp->if_addrlen); return(1); @ 1.10.2.3 log @Sync with head (for UBC+NFS fixes, mostly). @ text @d1027 1 a1027 1 nd6_rtrequest(req, rt, info) d1030 1 a1030 1 struct rt_addrinfo *info; /* xxx unused */ d1249 1 a1249 1 nd6_p2p_rtrequest(req, rt, info) d1252 1 a1252 1 struct rt_addrinfo *info; /* xxx unused */ @ 1.10.2.4 log @Sync with HEAD. @ text @d1 2 a2 2 /* $NetBSD: nd6.c,v 1.38 2001/02/10 04:14:29 itojun Exp $ */ /* $KAME: nd6.c,v 1.118 2001/02/08 12:14:33 itojun Exp $ */ a96 6 #ifdef ND6_DEBUG int nd6_debug = 1; #else int nd6_debug = 0; #endif d192 1 a322 1 icmp6stat.icp6s_nd_badopt++; d336 2 a337 3 nd6log((LOG_INFO, "duplicated ND6 option found (type=%d)\n", nd_opt->nd_opt_type)); d357 1 a357 1 nd6log((LOG_DEBUG, d359 1 a359 1 "option ignored\n", nd_opt->nd_opt_type)); d366 1 a366 1 nd6log((LOG_INFO, "too many loop in nd opt\n")); d385 3 a387 3 struct llinfo_nd6 *ln; struct nd_defrouter *dr; struct nd_prefix *pr; d454 1 a454 1 next = nd6_free(rt); d485 3 a487 2 } else next = nd6_free(rt); d490 1 a490 1 next = nd6_free(rt); d622 1 a622 1 nln = nd6_free(rt); d750 1 a750 1 struct ifaddr *ifa; d800 1 a800 1 struct llinfo_nd6 * d804 1 a804 1 struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next; d869 1 a869 1 return ln->ln_next; a871 13 /* * Before deleting the entry, remember the next entry as the * return value. We need this because pfxlist_onlink_check() above * might have freed other entries (particularly the old next entry) as * a side effect (XXX). */ next = ln->ln_next; /* * Detach the route from the routing tree and the list of neighbor * caches, and disable the route entry not to be used in already * cached routes. */ a873 2 return next; d1088 1 a1088 1 * note that the mechanism needs a mutual agreement d1090 2 a1091 2 * a new protocol, or a new kludge. * - from RFC2461 6.2.4, host MUST NOT send an unsolicited NA. d1115 1 a1115 2 "nd6_rtrequest: bad gateway value: %s\n", if_name(ifp)); d1580 1 a1580 1 (void)nd6_free(rt); d1738 2 a1739 2 int i; struct nd_ifinfo *nd6if; d1765 1 a1765 1 struct ifnet *ifp; d1771 2 a1772 2 struct mbuf *m = m0; struct rtentry *rt = rt0; d1785 1 a1785 1 * RFC2893 says: @ 1.10.2.5 log @Sync with HEAD. @ text @d1 2 a2 2 /* $NetBSD$ */ /* $KAME: nd6.c,v 1.136 2001/03/06 12:26:07 itojun Exp $ */ a90 1 int nd6_gctimer = (60 * 60 * 24); /* 1 day: garbage collection timer */ d175 2 a176 8 /* * Don't initialize if called twice. * XXX: to detect this, we should choose a member that is never set * before initialization of the ND structure itself. We formaly used * the linkmtu member, which was not suitable because it could be * initialized via "ifconfig mtu". */ if (ND.basereachable) d202 16 a217 16 switch (ifp->if_type) { case IFT_ARCNET: /* XXX MTU handling needs more work */ ndi->maxmtu = MIN(60480, ifp->if_mtu); break; case IFT_ETHER: ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); break; case IFT_ATM: ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); break; case IFT_IEEE1394: ndi->maxmtu = MIN(IEEE1394MTU, ifp->if_mtu); break; default: ndi->maxmtu = ifp->if_mtu; break; a283 6 /* make sure nd_opt_len is inside the buffer */ if ((caddr_t)&nd_opt->nd_opt_len >= (caddr_t)ndopts->nd_opts_last) { bzero(ndopts, sizeof(*ndopts)); return NULL; } d295 1 a295 6 if (ndopts->nd_opts_search > ndopts->nd_opts_last) { /* option overruns the end of buffer, invalid */ bzero(ndopts, sizeof(*ndopts)); return NULL; } else if (ndopts->nd_opts_search == ndopts->nd_opts_last) { /* reached the end of options chain */ d465 1 a465 1 if (ln->ln_expire) { a466 2 ln->ln_expire = time_second + nd6_gctimer; } d468 4 a471 7 case ND6_LLINFO_STALE: /* Garbage Collection(RFC 2461 5.3) */ if (ln->ln_expire) next = nd6_free(rt); break; d482 1 a482 1 } else { a483 2 ln->ln_expire = time_second + nd6_gctimer; } d495 3 d502 1 a502 1 /* expire default router list */ d632 23 d811 1 d869 9 d894 1 a894 1 return(next); a986 1 m_freem(m); d1026 2 a1027 1 if (ln->ln_state == ND6_LLINFO_NOSTATE) d1033 1 a1042 1 /* do not free mbuf here, it is queued into llinfo_nd6 */ d1088 1 a1088 1 /* kludge for desktops */ d1394 1 a1394 1 while (pfr) { d1595 1 a1595 4 } else { /* do nothing if static ndp is set */ if (rt->rt_flags & RTF_STATIC) return NULL; a1596 1 } d1665 1 a1680 1 ln->ln_expire = time_second + nd6_gctimer; d1845 1 a1845 1 * of view, regardless the value of the d1853 3 d1876 2 d1915 1 a1915 1 ln->ln_state < ND6_LLINFO_REACHABLE) { a1916 2 ln->ln_expire = time_second + nd6_gctimer; } d1947 2 a1948 1 if (ln->ln_state == ND6_LLINFO_NOSTATE) d1954 1 d1968 1 a1968 1 if ((ifp->if_flags & IFF_LOOPBACK) != 0) { a2005 1 m_freem(m); a2011 1 m_freem(m); a2015 1 m_freem(m); a2021 1 m_freem(m); @ 1.10.2.6 log @Sync with HEAD. @ text @d2 1 a2 1 /* $KAME: nd6.c,v 1.137 2001/03/21 21:52:06 jinmei Exp $ */ a1657 8 /* * XXX: since nd6_output() below will cause * state tansition to DELAY and reset the timer, * we must set the timer now, although it is actually * meaningless. */ ln->ln_expire = time_second + nd6_gctimer; a1659 3 ln->ln_asked = 0; ln->ln_state = ND6_LLINFO_DELAY; ln->ln_expire = time_second + nd6_delay; d1671 1 a1671 1 ln->ln_hold = NULL; d1673 1 @ 1.10.2.7 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.10.2.6 2001/03/27 15:32:39 bouyer Exp $ */ d1965 1 d1970 1 @ 1.10.8.1 log @Pull up to last week's -current. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.12 1999/12/13 15:17:23 itojun Exp $ */ d49 1 a49 1 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) a57 1 #if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) a58 1 #endif a78 1 #include a80 1 #ifndef __bsdi__ d82 1 a82 2 #endif #if defined(__NetBSD__) || defined(__OpenBSD__) a85 2 #include d89 4 a103 3 /* preventing too many loops in ND option parsing */ int nd6_maxndopt = 10; /* max # of ND options allowed */ d108 2 a109 2 struct nd_ifinfo *nd_ifinfo = NULL; struct nd_drhead nd_defrouter; a115 1 static struct sockaddr_in6 all1_sa; a122 1 int i; a127 9 all1_sa.sin6_family = AF_INET6; all1_sa.sin6_len = sizeof(struct sockaddr_in6); for (i = 0; i < sizeof(all1_sa.sin6_addr); i++) all1_sa.sin6_addr.s6_addr[i] = 0xff; /* initialization of the default router list */ TAILQ_INIT(&nd_defrouter); a194 3 #if defined(__bsdi__) && _BSDI_VERSION >= 199802 ndi->maxmtu = MIN(FDDIMTU, ifp->if_mtu); #else a195 1 #endif a197 1 #if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) a200 1 #endif d356 1 a356 2 if (i > nd6_maxndopt) { icmp6stat.icp6s_nd_toomanyopt++; a378 3 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec; #endif a379 1 #ifdef __NetBSD__ a380 3 #else s = splnet(); #endif d477 1 a477 1 dr = TAILQ_FIRST(&nd_defrouter); d481 1 a481 1 t = TAILQ_NEXT(dr, dr_entry); d485 1 a485 1 dr = TAILQ_NEXT(dr, dr_entry); d537 4 a611 7 /* * Validation for the entry. * XXX: we can't use rt->rt_ifp to check for the interface, since * it might be the loopback interface if the entry is for our * own address on a non-loopback interface. Instead, we should * use rt->rt_ifa->ifa_ifp, which would specify the REAL interface. */ d613 1 a613 2 rt->rt_gateway->sa_family != AF_LINK || (ifp && rt->rt_ifa->ifa_ifp != ifp)) { d615 2 a616 2 log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec"); d647 1 a647 1 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) a686 2 struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; struct nd_defrouter *dr; d688 4 a691 1 if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */ d693 2 a694 1 #ifdef __NetBSD__ d696 2 a697 4 #else s = splnet(); #endif dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, d699 3 a701 1 if (ln->ln_router || dr) { d703 2 a704 3 * rt6_flush must be called whether or not the neighbor * is in the Default Router List. * See a corresponding comment in nd6_na_input(). d706 1 a706 33 rt6_flush(&in6, rt->rt_ifp); } if (dr) { /* * Unreachablity of a router might affect the default * router selection and on-link detection of advertised * prefixes. */ /* * Temporarily fake the state to choose a new default * router and to perform on-link determination of * prefixes coreectly. * Below the state will be set correctly, * or the entry itself will be deleted. */ ln->ln_state = ND6_LLINFO_INCOMPLETE; if (dr == TAILQ_FIRST(&nd_defrouter)) { /* * It is used as the current default router, * so we have to move it to the end of the * list and choose a new one. * XXX: it is not very efficient if this is * the only router. */ TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); TAILQ_INSERT_TAIL(&nd_defrouter, dr, dr_entry); defrouter_select(); } pfxlist_onlink_check(); d710 1 a710 1 d712 1 a712 1 sdl->sdl_family == AF_LINK) { d719 2 a720 3 rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), 0, (struct rtentry **)0); a733 3 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec; #endif a764 1 #ifdef OLDIP6OUTPUT a784 3 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec; #endif a796 1 break; a855 1 #endif /* OLDIP6OUTPUT */ a857 6 #if defined(__bsdi__) && _BSDI_VERSION >= 199802 nd6_rtrequest(req, rt, info) int req; struct rtentry *rt; struct rt_addrinfo *info; /* xxx unused */ #else a861 1 #endif a867 3 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec; #endif d953 1 a953 1 ln->ln_state = ND6_LLINFO_NOSTATE; a981 4 #if _BSDI_VERSION >= 199802 extern struct ifnet *loifp; rt->rt_ifp = loifp; /*XXX*/ #else d984 2 a985 2 #endif #else /* non-bsdi */ a1024 6 #if defined(__bsdi__) && _BSDI_VERSION >= 199802 nd6_p2p_rtrequest(req, rt, info) int req; struct rtentry *rt; struct rt_addrinfo *info; /* xxx unused */ #else a1028 1 #endif d1059 1 a1059 1 /* Announce a new entry if requested. */ a1076 4 #if _BSDI_VERSION >= 199802 extern struct ifnet *loifp; rt->rt_ifp = loifp; /*XXX*/ #else d1079 3 a1082 3 #else rt->rt_ifp = &loif[0]; /*XXX*/ #endif /*__bsdi__*/ a1098 1 struct in6_ndifreq *ndif = (struct in6_ndifreq *)data; a1107 1 #ifdef __NetBSD__ d1109 1 a1109 4 #else s = splnet(); #endif dr = TAILQ_FIRST(&nd_defrouter); d1127 1 a1127 1 dr = TAILQ_NEXT(dr, dr_entry); a1132 1 #ifdef __NetBSD__ a1133 3 #else s = splnet(); #endif a1173 19 { struct rr_prefix *rpp; for (rpp = LIST_FIRST(&rr_prefix); rpp; rpp = LIST_NEXT(rpp, rp_entry)) { if (i >= PRLSTSIZ) break; prl->prefix[i].prefix = rpp->rp_prefix.sin6_addr; prl->prefix[i].raflags = rpp->rp_raf; prl->prefix[i].prefixlen = rpp->rp_plen; prl->prefix[i].vltime = rpp->rp_vltime; prl->prefix[i].pltime = rpp->rp_pltime; prl->prefix[i].if_index = rpp->rp_ifp->if_index; prl->prefix[i].expire = rpp->rp_expire; prl->prefix[i].advrtrs = 0; i++; } } d1178 1 a1178 1 case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */ a1185 1 defrouter_select(); a1192 1 #ifdef __NetBSD__ a1193 3 #else s = splnet(); #endif a1207 1 #ifdef __NetBSD__ d1209 1 a1209 4 #else s = splnet(); #endif if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { d1214 2 a1215 2 for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = next) { next = TAILQ_NEXT(dr, dr_entry); d1218 1 a1218 1 defrtrlist_del(TAILQ_FIRST(&nd_defrouter)); d1225 1 a1225 14 struct llinfo_nd6 *ln; struct in6_addr nb_addr = nbi->addr; /* make local for safety */ /* * XXX: KAME specific hack for scoped addresses * XXXX: for other scopes than link-local? */ if (IN6_IS_ADDR_LINKLOCAL(&nbi->addr) || IN6_IS_ADDR_MC_LINKLOCAL(&nbi->addr)) { u_int16_t *idp = (u_int16_t *)&nb_addr.s6_addr[2]; if (*idp == 0) *idp = htons(ifp->if_index); } d1227 13 a1239 18 #ifdef __NetBSD__ s = splsoftnet(); #else s = splnet(); #endif if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL) { error = EINVAL; splx(s); break; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; nbi->state = ln->ln_state; nbi->asked = ln->ln_asked; nbi->isrouter = ln->ln_router; nbi->expire = ln->ln_expire; splx(s); break; a1240 6 case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ ndif->ifindex = nd6_defifindex; break; case SIOCSDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ return(nd6_setdefaultiface(ndif->ifindex)); break; a1265 3 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec; #endif a1367 1 #ifdef OLDIP6OUTPUT a1369 5 #else nd6_output(ifp, ln->ln_hold, (struct sockaddr_in6 *)rt_key(rt), rt); #endif a1450 1 #ifdef __NetBSD__ a1451 3 #else int s = splnet(); #endif d1473 2 a1486 3 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec; #endif d1511 1 a1511 1 NULL) d1514 1 a1514 1 NULL) a1515 1 { d1649 1 d1666 1 @ 1.9 log @Zeroth version of IPv6 support for ARCnet. Correct MTU handling still needs to be done. @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.8 1999/07/31 18:41:17 itojun Exp $ */ d1495 6 a1500 2 if (ifp->if_type != IFT_ARCNET && ifp->if_type != IFT_ETHER && ifp->if_type != IFT_FDDI) d1502 1 @ 1.8 log @sync with recent KAME. - loosen ipsec restriction on packet diredtion. - revise icmp6 redirect handling on IsRouter bit. - tcp/udp notification processing (link-local address case) - cosmetic fixes (better code share across *BSD). @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.7 1999/07/30 10:35:37 itojun Exp $ */ d187 3 d794 3 d1493 1 a1493 1 * other than Ethernet and FDDI. d1495 2 a1496 1 if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_FDDI) d1639 4 @ 1.7 log @remove reference to in6_systm.h (file itself will be removed afterwords) @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.6 1999/07/06 12:23:22 itojun Exp $ */ d1244 1 a1244 1 nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type) d1250 1 d1390 8 a1397 7 * 0 n n -- (1) c ? * 0 y n -- (2) c s * 0 n y -- (3) c s * 0 y y n (4) c s * 0 y y y (5) c s * 1 -- n -- (6) c c c * 1 -- y -- (7) c c s c a1402 1 case ND_REDIRECT: d1407 12 @ 1.6 log @sync with KAME/NetBSD 1.4, SNAP kit 19990705. key changes are: - icmp6 redirect fix (dst check) - revised ip6 multicast check for loopback i/f - several RCS ID cleanups @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.5 1999/07/04 02:01:15 itojun Exp $ */ a74 1 #include @ 1.5 log @s/splnet/splsoftnet/ in IPv6/IPsec part. hope I made no mistake (the kernel works fine but I need a regress test) Suggested by: thorpej @ text @d1 1 a1 1 /* $NetBSD: nd6.c,v 1.4 1999/07/03 21:30:19 thorpej Exp $ */ d620 54 @ 1.4 log @RCS ID police. @ text @d1 1 a1 1 /* $NetBSD$ */ d378 1 a378 1 s = splnet(); d639 1 a639 1 s = splnet(); d1049 1 a1049 1 s = splnet(); d1074 1 a1074 1 s = splnet(); d1134 1 a1134 1 s = splnet(); d1149 1 a1149 1 s = splnet(); d1168 1 a1168 1 s = splnet(); d1379 1 a1379 1 int s = splnet(); @ 1.3 log @expand insque/remque (quick hack). fundamental fix should be done while clarifying relationship between inpcb and in6pcb. PR: 7891 @ text @d1 2 @ 1.2 log @IPv6 kernel code, based on KAME/NetBSD 1.4, SNAP kit 19990628. (Sorry for a big commit, I can't separate this into several pieces...) Pls check sys/netinet6/TODO and sys/netinet6/IMPLEMENTATION for details. - sys/kern: do not assume single mbuf, accept chained mbuf on passing data from userland to kernel (or other way round). - "midway" ATM card: ATM PVC pseudo device support, like those done in ALTQ package (ftp://ftp.csl.sony.co.jp/pub/kjc/). - sys/netinet/tcp*: IPv4/v6 dual stack tcp support. - sys/netinet/{ip6,icmp6}.h, sys/net/pfkeyv2.h: IETF document assumes those file to be there so we patch it up. - sys/netinet: IPsec additions are here and there. - sys/netinet6/*: most of IPv6 code sits here. - sys/netkey: IPsec key management code - dev/pci/pcidevs: regen In my understanding no code here is subject to export control so it should be safe. @ text @d896 1 d898 6 d948 1 d950 5 @ 1.2.2.1 log @file nd6.c was added on branch chs-ubc2 on 1999-07-01 23:48:29 +0000 @ text @d1 1569 @ 1.2.2.2 log @Sync w/ -current. @ text @a0 1569 /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * 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. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS 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. */ /* * XXX * KAME 970409 note: * BSD/OS version heavily modifies this code, related to llinfo. * Since we don't have BSD/OS version of net/route.c in our hand, * I left the code mostly as it was in 970310. -- itojun */ #include #include #include #include #include #include #include #include #include #if !defined(__FreeBSD__) || __FreeBSD__ < 3 #include #endif #include #include #include #include #include #include #include #include #ifndef __NetBSD__ #include #ifdef __FreeBSD__ #include #endif #ifdef __bsdi__ #include #endif #else /* __NetBSD__ */ #include #include #include #endif /* __NetBSD__ */ #include #include #include #include #include #include #include "loop.h" #ifdef __NetBSD__ extern struct ifnet loif[NLOOP]; #endif #define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */ #define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */ #if !defined(__FreeBSD__) || __FreeBSD__ < 3 #define time_second time.tv_sec #endif #define SIN6(s) ((struct sockaddr_in6 *)s) #define SDL(s) ((struct sockaddr_dl *)s) /* timer values */ int nd6_prune = 1; /* walk list every 1 seconds */ int nd6_delay = 5; /* delay first probe time 5 second */ int nd6_umaxtries = 3; /* maximum unicast query */ int nd6_mmaxtries = 3; /* maximum multicast query */ int nd6_useloopback = 1; /* use loopback interface for local traffic */ int nd6_proxyall = 0; /* enable Proxy Neighbor Advertisement */ /* for debugging? */ static int nd6_inuse, nd6_allocated; struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6}; struct nd_ifinfo *nd_ifinfo; struct nd_drhead nd_defrouter = { 0 }; struct nd_prhead nd_prefix = { 0 }; int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; #if 0 extern int ip6_forwarding; #endif static void nd6_slowtimo __P((void *)); void nd6_init() { static int nd6_init_done = 0; if (nd6_init_done) { log(LOG_NOTICE, "nd6_init called more than once(ignored)\n"); return; } nd6_init_done = 1; /* start timer */ timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); } void nd6_ifattach(ifp) struct ifnet *ifp; { static size_t if_indexlim = 8; /* * We have some arrays that should be indexed by if_index. * since if_index will grow dynamically, they should grow too. */ if (nd_ifinfo == NULL || if_index >= if_indexlim) { size_t n; caddr_t q; while (if_index >= if_indexlim) if_indexlim <<= 1; /* grow nd_ifinfo */ n = if_indexlim * sizeof(struct nd_ifinfo); q = (caddr_t)malloc(n, M_IP6NDP, M_WAITOK); bzero(q, n); if (nd_ifinfo) { bcopy((caddr_t)nd_ifinfo, q, n/2); free((caddr_t)nd_ifinfo, M_IP6NDP); } nd_ifinfo = (struct nd_ifinfo *)q; } #define ND nd_ifinfo[ifp->if_index] ND.linkmtu = ifindex2ifnet[ifp->if_index]->if_mtu; ND.chlim = IPV6_DEFHLIM; ND.basereachable = REACHABLE_TIME; ND.reachable = ND_COMPUTE_RTIME(ND.basereachable); ND.retrans = RETRANS_TIMER; ND.receivedra = 0; nd6_setmtu(ifp); #undef ND } /* * Reset ND level link MTU. This function is called when the physical MTU * changes, which means we might have to adjust the ND level MTU. */ void nd6_setmtu(ifp) struct ifnet *ifp; { #define MIN(a,b) ((a) < (b) ? (a) : (b)) struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; u_long oldmaxmtu = ndi->maxmtu; u_long oldlinkmtu = ndi->linkmtu; switch(ifp->if_type) { case IFT_ETHER: ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); break; #if defined(__FreeBSD__) || defined(__bsdi__) case IFT_FDDI: ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); break; #endif case IFT_ATM: ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); break; default: ndi->maxmtu = ifp->if_mtu; break; } if (oldmaxmtu != ndi->maxmtu) { /* * If the ND level MTU is not set yet, or if the maxmtu * is reset to a smaller value than the ND level MTU, * also reset the ND level MTU. */ if (ndi->linkmtu == 0 || ndi->maxmtu < ndi->linkmtu) { ndi->linkmtu = ndi->maxmtu; /* also adjust in6_maxmtu if necessary. */ if (oldlinkmtu == 0) { /* * XXX: the case analysis is grotty, but * it is not efficient to call in6_setmaxmtu() * here when we are during the initialization * procedure. */ if (in6_maxmtu < ndi->linkmtu) in6_maxmtu = ndi->linkmtu; } else in6_setmaxmtu(); } } #undef MIN } void nd6_option_init(opt, icmp6len, ndopts) void *opt; int icmp6len; union nd_opts *ndopts; { bzero(ndopts, sizeof(*ndopts)); ndopts->nd_opts_search = (struct nd_opt_hdr *)opt; ndopts->nd_opts_last = (struct nd_opt_hdr *)(((u_char *)opt) + icmp6len); if (icmp6len == 0) { ndopts->nd_opts_done = 1; ndopts->nd_opts_search = NULL; } } /* * Take one ND option. */ struct nd_opt_hdr * nd6_option(ndopts) union nd_opts *ndopts; { struct nd_opt_hdr *nd_opt; int olen; if (!ndopts) panic("ndopts == NULL in nd6_option\n"); if (!ndopts->nd_opts_last) panic("uninitialized ndopts in nd6_option\n"); if (!ndopts->nd_opts_search) return NULL; if (ndopts->nd_opts_done) return NULL; nd_opt = ndopts->nd_opts_search; olen = nd_opt->nd_opt_len << 3; if (olen == 0) { /* * Message validation requires that all included * options have a length that is greater than zero. */ bzero(ndopts, sizeof(*ndopts)); return NULL; } ndopts->nd_opts_search = (struct nd_opt_hdr *)((caddr_t)nd_opt + olen); if (!(ndopts->nd_opts_search < ndopts->nd_opts_last)) { ndopts->nd_opts_done = 1; ndopts->nd_opts_search = NULL; } return nd_opt; } /* * Parse multiple ND options. * This function is much easier to use, for ND routines that do not need * multiple options of the same type. */ int nd6_options(ndopts) union nd_opts *ndopts; { struct nd_opt_hdr *nd_opt; int i = 0; if (!ndopts) panic("ndopts == NULL in nd6_options\n"); if (!ndopts->nd_opts_last) panic("uninitialized ndopts in nd6_options\n"); if (!ndopts->nd_opts_search) return 0; while (1) { nd_opt = nd6_option(ndopts); if (!nd_opt && !ndopts->nd_opts_last) { /* * Message validation requires that all included * options have a length that is greater than zero. */ bzero(ndopts, sizeof(*ndopts)); return -1; } if (!nd_opt) goto skip1; switch (nd_opt->nd_opt_type) { case ND_OPT_SOURCE_LINKADDR: case ND_OPT_TARGET_LINKADDR: case ND_OPT_MTU: case ND_OPT_REDIRECTED_HEADER: if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { printf("duplicated ND6 option found " "(type=%d)\n", nd_opt->nd_opt_type); /* XXX bark? */ } else { ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; } break; case ND_OPT_PREFIX_INFORMATION: if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) { ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; } ndopts->nd_opts_pi_end = (struct nd_opt_prefix_info *)nd_opt; break; default: /* * Unknown options must be silently ignored, * to accomodate future extension to the protocol. */ log(LOG_INFO, "nd6_options: unsupported option %d - " "option ignored\n", nd_opt->nd_opt_type); } skip1: i++; if (i > 10) { printf("too many loop in nd opt\n"); break; } if (ndopts->nd_opts_done) break; } return 0; } /* * ND6 timer routine to expire default route list and prefix list */ void nd6_timer(ignored_arg) void *ignored_arg; { int s; register struct llinfo_nd6 *ln; register struct nd_defrouter *dr; register struct nd_prefix *pr; s = splnet(); timeout(nd6_timer, (caddr_t)0, nd6_prune * hz); ln = llinfo_nd6.ln_next; /* XXX BSD/OS separates this code -- itojun */ while (ln && ln != &llinfo_nd6) { struct rtentry *rt; struct ifnet *ifp; struct sockaddr_in6 *dst; struct llinfo_nd6 *next = ln->ln_next; if ((rt = ln->ln_rt) == NULL) { ln = next; continue; } if ((ifp = rt->rt_ifp) == NULL) { ln = next; continue; } dst = (struct sockaddr_in6 *)rt_key(rt); if (ln->ln_expire > time_second) { ln = next; continue; } /* sanity check */ if (!rt) panic("rt=0 in nd6_timer(ln=%p)\n", ln); if (!dst) panic("dst=0 in nd6_timer(ln=%p)\n", ln); switch (ln->ln_state) { case ND6_LLINFO_INCOMPLETE: if (ln->ln_asked < nd6_mmaxtries) { ln->ln_asked++; ln->ln_expire = time_second + nd_ifinfo[ifp->if_index].retrans / 1000; nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); } else { struct mbuf *m = ln->ln_hold; if (m) { if (rt->rt_ifp) { /* * Fake rcvif to make ICMP error * more helpful in diagnosing * for the receiver. * XXX: should we consider * older rcvif? */ m->m_pkthdr.rcvif = rt->rt_ifp; } icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0); ln->ln_hold = NULL; } nd6_free(rt); } break; case ND6_LLINFO_REACHABLE: if (ln->ln_expire) { ln->ln_state = ND6_LLINFO_STALE; } break; /* * ND6_LLINFO_STALE state requires nothing for timer * routine. */ case ND6_LLINFO_DELAY: ln->ln_asked = 1; ln->ln_state = ND6_LLINFO_PROBE; ln->ln_expire = time_second + nd_ifinfo[ifp->if_index].retrans / 1000; nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); break; case ND6_LLINFO_PROBE: if (ln->ln_asked < nd6_umaxtries) { ln->ln_asked++; ln->ln_expire = time_second + nd_ifinfo[ifp->if_index].retrans / 1000; nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); } else { nd6_free(rt); } break; case ND6_LLINFO_WAITDELETE: nd6_free(rt); break; } ln = next; } /* expire */ dr = nd_defrouter.lh_first; while (dr) { if (dr->expire && dr->expire < time_second) { struct nd_defrouter *t; t = dr->dr_next; defrtrlist_del(dr); dr = t; } else dr = dr->dr_next; } pr = nd_prefix.lh_first; while (pr) { struct in6_ifaddr *ia6; struct in6_addrlifetime *lt6; if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) ia6 = NULL; else ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); if (ia6) { /* check address lifetime */ lt6 = &ia6->ia6_lifetime; if (lt6->ia6t_preferred && lt6->ia6t_preferred < time_second) ia6->ia6_flags |= IN6_IFF_DEPRECATED; if (lt6->ia6t_expire && lt6->ia6t_expire < time_second) { if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); /* xxx ND_OPT_PI_FLAG_ONLINK processing */ } } /* * check prefix lifetime. * since pltime is just for autoconf, pltime processing for * prefix is not necessary. * * we offset expire time by NDPR_KEEP_EXPIRE, so that we * can use the old prefix information to validate the * next prefix information to come. See prelist_update() * for actual validation. */ if (pr->ndpr_expire && pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) { struct nd_prefix *t; t = pr->ndpr_next; /* * address expiration and prefix expiration are * separate. NEVER perform in6_ifdel here. */ prelist_remove(pr); pr = t; } else pr = pr->ndpr_next; } splx(s); } static struct sockaddr_in6 all1_sa = { sizeof(struct sockaddr_in6), AF_INET6, 0, 0, {{{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}}}, 0}; struct rtentry * nd6_lookup(addr6, create, ifp) struct in6_addr *addr6; int create; struct ifnet *ifp; { struct rtentry *rt; struct sockaddr_in6 sin6; bzero(&sin6, sizeof(sin6)); sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_family = AF_INET6; sin6.sin6_addr = *addr6; rt = rtalloc1((struct sockaddr *)&sin6, create #ifdef __FreeBSD__ , 0UL #endif /*__FreeBSD__*/ ); if (rt && (rt->rt_flags & RTF_LLINFO) == 0) { /* * This is the case for the default route. * If we want to create a neighbor cache for the address, we * should free the route for the destination and allocate an * interface route. */ if (create) { RTFREE(rt); rt = 0; } } if (!rt) { if (create && ifp) { /* * If no route is available and create is set, * we allocate a host route for the destination * and treat it like an interface route. * This hack is necessary for a neighbor which can't * be covered by our own prefix. */ struct ifaddr *ifa = ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); if (ifa == NULL) return(NULL); /* * Create a new route. RTF_LLINFO is necessary * to create a Neighbor Cache entry for the * destination in nd6_rtrequest which will be * called in rtequest via ifa->ifa_rtrequest. */ if (rtrequest(RTM_ADD, (struct sockaddr *)&sin6, ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) log(LOG_ERR, "nd6_lookup: failed to add route for a " "neighbor(%s)\n", ip6_sprintf(addr6)); if (rt == NULL) return(NULL); if (rt->rt_llinfo) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; ln->ln_state = ND6_LLINFO_NOSTATE; } } else return(NULL); } rt->rt_refcnt--; if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || rt->rt_gateway->sa_family != AF_LINK) { if (create) { log(LOG_DEBUG, "nd6_lookup: failed to lookup %s\n", ip6_sprintf(addr6)); /* xxx more logs... kazu */ } return(0); } return(rt); } /* * Free an nd6 llinfo entry. */ void nd6_free(rt) struct rtentry *rt; { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; struct sockaddr_dl *sdl; if (ln->ln_router) { /* remove from default router list */ struct nd_defrouter *dr; struct in6_addr *in6; int s; in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; s = splnet(); dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))-> sin6_addr, rt->rt_ifp); if (dr) defrtrlist_del(dr); else if (!ip6_forwarding && ip6_accept_rtadv) { /* * rt6_flush must be called in any case. * see the comment in nd6_na_input(). */ rt6_flush(in6, rt->rt_ifp); } splx(s); } if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && sdl->sdl_family == AF_LINK) { sdl->sdl_alen = 0; ln->ln_state = ND6_LLINFO_WAITDELETE; ln->ln_asked = 0; rt->rt_flags &= ~RTF_REJECT; return; } rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), 0, (struct rtentry **)0); } /* * Upper-layer reachability hint for Neighbor Unreachability Detection. * * XXX cost-effective metods? */ void nd6_nud_hint(rt, dst6) struct rtentry *rt; struct in6_addr *dst6; { struct llinfo_nd6 *ln; /* * If the caller specified "rt", use that. Otherwise, resolve the * routing table by supplied "dst6". */ if (!rt) { if (!dst6) return; if (!(rt = nd6_lookup(dst6, 0, NULL))) return; } if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || !rt->rt_llinfo || !rt->rt_gateway || rt->rt_gateway->sa_family != AF_LINK) { /* This is not a host route. */ return; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; if (ln->ln_state == ND6_LLINFO_INCOMPLETE) return; ln->ln_state = ND6_LLINFO_REACHABLE; if (ln->ln_expire) ln->ln_expire = time_second + nd_ifinfo[rt->rt_ifp->if_index].reachable; } /* * Resolve an IP6 address into an ethernet address. If success, * desten is filled in. If there is no entry in ndptab, * set one up and multicast a solicitation for the IP6 address. * Hold onto this mbuf and resend it once the address * is finally resolved. A return value of 1 indicates * that desten has been filled in and the packet should be sent * normally; a 0 return indicates that the packet has been * taken over here, either now or for later transmission. */ int nd6_resolve(ifp, rt, m, dst, desten) struct ifnet *ifp; struct rtentry *rt; struct mbuf *m; struct sockaddr *dst; u_char *desten; { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL; struct sockaddr_dl *sdl; if (m->m_flags & M_MCAST) { switch (ifp->if_type) { case IFT_ETHER: case IFT_FDDI: ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, desten); return(1); break; default: return(0); } } if (rt && (rt->rt_flags & RTF_LLINFO) != 0) ln = (struct llinfo_nd6 *)rt->rt_llinfo; else { if ((rt = nd6_lookup(&(SIN6(dst)->sin6_addr), 1, ifp)) != NULL) ln = (struct llinfo_nd6 *)rt->rt_llinfo; } if (!ln || !rt) { log(LOG_DEBUG, "nd6_resolve: can't allocate llinfo for %s\n", ip6_sprintf(&(SIN6(dst)->sin6_addr))); m_freem(m); return(0); } sdl = SDL(rt->rt_gateway); /* * Ckeck the address family and length is valid, the address * is resolved; otherwise, try to resolve. */ if (ln->ln_state >= ND6_LLINFO_REACHABLE && sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { bcopy(LLADDR(sdl), desten, sdl->sdl_alen); if (ln->ln_state == ND6_LLINFO_STALE) { ln->ln_asked = 0; ln->ln_state = ND6_LLINFO_DELAY; ln->ln_expire = time_second + nd6_delay; } return(1); } /* * There is an ndp entry, but no ethernet address * response yet. Replace the held mbuf with this * latest one. * * XXX Does the code conform to rate-limiting rule? * (RFC 2461 7.2.2) */ if (ln->ln_state == ND6_LLINFO_WAITDELETE || ln->ln_state == ND6_LLINFO_NOSTATE) ln->ln_state = ND6_LLINFO_INCOMPLETE; if (ln->ln_hold) m_freem(ln->ln_hold); ln->ln_hold = m; if (ln->ln_expire) { rt->rt_flags &= ~RTF_REJECT; if (ln->ln_asked < nd6_mmaxtries && ln->ln_expire < time_second) { ln->ln_asked++; ln->ln_expire = time_second + nd_ifinfo[ifp->if_index].retrans / 1000; nd6_ns_output(ifp, NULL, &(SIN6(dst)->sin6_addr), ln, 0); } } return(0); } void nd6_rtrequest(req, rt, sa) int req; struct rtentry *rt; struct sockaddr *sa; /* xxx unused */ { struct sockaddr *gate = rt->rt_gateway; struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; struct ifnet *ifp = rt->rt_ifp; struct ifaddr *ifa; if (rt->rt_flags & RTF_GATEWAY) return; switch (req) { case RTM_ADD: /* * There is no backward compatibility :) * * if ((rt->rt_flags & RTF_HOST) == 0 && * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) * rt->rt_flags |= RTF_CLONING; */ if (rt->rt_flags & RTF_CLONING || rt->rt_flags & RTF_LLINFO) { /* * Case 1: This route should come from * a route to interface. RTF_LLINFO flag is set * for a host route whose destination should be * treated as on-link. */ rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl); gate = rt->rt_gateway; SDL(gate)->sdl_type = ifp->if_type; SDL(gate)->sdl_index = ifp->if_index; if (ln) ln->ln_expire = time_second; #if 1 if (ln && ln->ln_expire == 0) { /* cludge for desktops */ #if 0 printf("nd6_request: time.tv_sec is zero; " "treat it as 1\n"); #endif ln->ln_expire = 1; } #endif if (rt->rt_flags & RTF_CLONING) break; } /* Announce a new entry if requested. */ if (rt->rt_flags & RTF_ANNOUNCE) nd6_na_output(ifp, &SIN6(rt_key(rt))->sin6_addr, &SIN6(rt_key(rt))->sin6_addr, ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1); /* FALLTHROUGH */ case RTM_RESOLVE: if (gate->sa_family != AF_LINK || gate->sa_len < sizeof(null_sdl)) { log(LOG_DEBUG, "nd6_rtrequest: bad gateway value\n"); break; } SDL(gate)->sdl_type = ifp->if_type; SDL(gate)->sdl_index = ifp->if_index; if (ln != 0) break; /* This happens on a route change */ /* * Case 2: This route may come from cloning, or a manual route * add with a LL address. */ R_Malloc(ln, struct llinfo_nd6 *, sizeof(*ln)); rt->rt_llinfo = (caddr_t)ln; if (!ln) { log(LOG_DEBUG, "nd6_rtrequest: malloc failed\n"); break; } nd6_inuse++; nd6_allocated++; Bzero(ln, sizeof(*ln)); ln->ln_rt = rt; /* this is required for "ndp" command. - shin */ if (req == RTM_ADD) { /* * gate should have some valid AF_LINK entry, * and ln->ln_expire should have some lifetime * which is specified by ndp command. */ ln->ln_state = ND6_LLINFO_REACHABLE; } else { /* * When req == RTM_RESOLVE, rt is created and * initialized in rtrequest(), so rt_expire is 0. */ ln->ln_state = ND6_LLINFO_INCOMPLETE; ln->ln_expire = time_second; } rt->rt_flags |= RTF_LLINFO; insque(ln, &llinfo_nd6); /* * check if rt_key(rt) is one of my address assigned * to the interface. */ ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, &SIN6(rt_key(rt))->sin6_addr); if (ifa) { caddr_t macp = nd6_ifptomac(ifp); ln->ln_expire = 0; ln->ln_state = ND6_LLINFO_REACHABLE; if (macp) { Bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); SDL(gate)->sdl_alen = ifp->if_addrlen; } if (nd6_useloopback) { #ifdef __bsdi__ extern struct ifnet loif; rt->rt_ifp = &loif; /*XXX*/ #endif /*__bsdi__*/ #if defined(__FreeBSD__) || defined(__NetBSD__) rt->rt_ifp = &loif[0]; /*XXX*/ #endif /* * Make sure rt_ifa be equal to the ifaddr * corresponding to the address. * We need this because when we refer * rt_ifa->ia6_flags in ip6_input, we assume * that the rt_ifa points to the address instead * of the loopback address. */ if (ifa != rt->rt_ifa) { rt->rt_ifa->ifa_refcnt--; ifa->ifa_refcnt++; rt->rt_ifa = ifa; } } } break; case RTM_DELETE: if (!ln) break; nd6_inuse--; remque(ln); rt->rt_llinfo = 0; rt->rt_flags &= ~RTF_LLINFO; if (ln->ln_hold) m_freem(ln->ln_hold); Free((caddr_t)ln); } } void nd6_p2p_rtrequest(req, rt, sa) int req; struct rtentry *rt; struct sockaddr *sa; /* xxx unused */ { struct sockaddr *gate = rt->rt_gateway; static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; struct ifnet *ifp = rt->rt_ifp; struct ifaddr *ifa; if (rt->rt_flags & RTF_GATEWAY) return; switch (req) { case RTM_ADD: /* * There is no backward compatibility :) * * if ((rt->rt_flags & RTF_HOST) == 0 && * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) * rt->rt_flags |= RTF_CLONING; */ if (rt->rt_flags & RTF_CLONING) { /* * Case 1: This route should come from * a route to interface. */ rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl); gate = rt->rt_gateway; SDL(gate)->sdl_type = ifp->if_type; SDL(gate)->sdl_index = ifp->if_index; break; } /* Announce a new entry if rqquested. */ if (rt->rt_flags & RTF_ANNOUNCE) nd6_na_output(ifp, &SIN6(rt_key(rt))->sin6_addr, &SIN6(rt_key(rt))->sin6_addr, ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1); /* FALLTHROUGH */ case RTM_RESOLVE: /* * check if rt_key(rt) is one of my address assigned * to the interface. */ ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, &SIN6(rt_key(rt))->sin6_addr); if (ifa) { if (nd6_useloopback) { #ifdef __bsdi__ extern struct ifnet loif; rt->rt_ifp = &loif; /*XXX*/ #endif /*__bsdi__*/ #if defined(__FreeBSD__) || defined(__NetBSD__) rt->rt_ifp = &loif[0]; /*XXX*/ #endif } } break; } } int nd6_ioctl(cmd, data, ifp) u_long cmd; caddr_t data; struct ifnet *ifp; { struct in6_drlist *drl = (struct in6_drlist *)data; struct in6_prlist *prl = (struct in6_prlist *)data; struct in6_ndireq *ndi = (struct in6_ndireq *)data; struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; struct nd_defrouter *dr, any; struct nd_prefix *pr; struct rtentry *rt; int i = 0, error = 0; int s; switch (cmd) { case SIOCGDRLST_IN6: bzero(drl, sizeof(*drl)); s = splnet(); dr = nd_defrouter.lh_first; while (dr && i < DRLSTSIZ) { drl->defrouter[i].rtaddr = dr->rtaddr; if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) { /* XXX: need to this hack for KAME stack */ drl->defrouter[i].rtaddr.s6_addr16[1] = 0; } else log(LOG_ERR, "default router list contains a " "non-linklocal address(%s)\n", ip6_sprintf(&drl->defrouter[i].rtaddr)); drl->defrouter[i].flags = dr->flags; drl->defrouter[i].rtlifetime = dr->rtlifetime; drl->defrouter[i].expire = dr->expire; drl->defrouter[i].if_index = dr->ifp->if_index; i++; dr = dr->dr_next; } splx(s); break; case SIOCGPRLST_IN6: bzero(prl, sizeof(*prl)); s = splnet(); pr = nd_prefix.lh_first; while (pr && i < PRLSTSIZ) { struct nd_pfxrouter *pfr; int j; prl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; prl->prefix[i].raflags = pr->ndpr_raf; prl->prefix[i].prefixlen = pr->ndpr_plen; prl->prefix[i].vltime = pr->ndpr_vltime; prl->prefix[i].pltime = pr->ndpr_pltime; prl->prefix[i].if_index = pr->ndpr_ifp->if_index; prl->prefix[i].expire = pr->ndpr_expire; pfr = pr->ndpr_advrtrs.lh_first; j = 0; while(pfr) { if (j < DRLSTSIZ) { #define RTRADDR prl->prefix[i].advrtr[j] RTRADDR = pfr->router->rtaddr; if (IN6_IS_ADDR_LINKLOCAL(&RTRADDR)) { /* XXX: hack for KAME */ RTRADDR.s6_addr16[1] = 0; } else log(LOG_ERR, "a router(%s) advertises " "a prefix with " "non-link local address\n", ip6_sprintf(&RTRADDR)); #undef RTRADDR } j++; pfr = pfr->pfr_next; } prl->prefix[i].advrtrs = j; i++; pr = pr->ndpr_next; } splx(s); break; case SIOCGIFINFO_IN6: ndi->ndi = nd_ifinfo[ifp->if_index]; break; case SIOCSNDFLUSH_IN6: /* flush default router list */ /* * xxx sumikawa: should not delete route if default * route equals to the top of default router list */ bzero(&any, sizeof(any)); defrouter_delreq(&any, 0); /* xxx sumikawa: flush prefix list */ break; case SIOCSPFXFLUSH_IN6: { /* flush all the prefix advertised by routers */ struct nd_prefix *pr, *next; s = splnet(); for (pr = nd_prefix.lh_first; pr; pr = next) { next = pr->ndpr_next; if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); prelist_remove(pr); } splx(s); break; } case SIOCSRTRFLUSH_IN6: { /* flush all the default routers */ struct nd_defrouter *dr, *next; s = splnet(); if ((dr = nd_defrouter.lh_first) != NULL) { /* * The first entry of the list may be stored in * the routing table, so we'll delete it later. */ for (dr = dr->dr_next; dr; dr = next) { next = dr->dr_next; defrtrlist_del(dr); } defrtrlist_del(nd_defrouter.lh_first); } splx(s); break; } case SIOCGNBRINFO_IN6: { struct llinfo_nd6 *ln; s = splnet(); if ((rt = nd6_lookup(&nbi->addr, 0, ifp)) == NULL) { error = EINVAL; break; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; nbi->state = ln->ln_state; nbi->asked = ln->ln_asked; nbi->isrouter = ln->ln_router; nbi->expire = ln->ln_expire; splx(s); break; } } return(error); } /* * Create neighbor cache entry and cache link-layer address, * on reception of inbound ND6 packets. (RS/RA/NS/redirect) */ struct rtentry * nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type) struct ifnet *ifp; struct in6_addr *from; char *lladdr; int lladdrlen; int type; /* ICMP6 type */ { struct rtentry *rt = NULL; struct llinfo_nd6 *ln = NULL; int is_newentry; struct sockaddr_dl *sdl = NULL; int do_update; int olladdr; int llchange; int newstate = 0; if (!ifp) panic("ifp == NULL in nd6_cache_lladdr"); if (!from) panic("from == NULL in nd6_cache_lladdr"); /* nothing must be updated for unspecified address */ if (IN6_IS_ADDR_UNSPECIFIED(from)) return NULL; /* * Validation about ifp->if_addrlen and lladdrlen must be done in * the caller. * * XXX If the link does not have link-layer adderss, what should * we do? (ifp->if_addrlen == 0) * Spec says nothing in sections for RA, RS and NA. There's small * description on it in NS section (RFC 2461 7.2.3). */ rt = nd6_lookup(from, 0, ifp); if (!rt) { #if 0 /* nothing must be done if there's no lladdr */ if (!lladdr || !lladdrlen) return NULL; #endif rt = nd6_lookup(from, 1, ifp); is_newentry = 1; } else is_newentry = 0; if (!rt) return NULL; if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) { fail: nd6_free(rt); return NULL; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; if (!ln) goto fail; if (!rt->rt_gateway) goto fail; if (rt->rt_gateway->sa_family != AF_LINK) goto fail; sdl = SDL(rt->rt_gateway); olladdr = (sdl->sdl_alen) ? 1 : 0; if (olladdr && lladdr) { if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen)) llchange = 1; else llchange = 0; } else llchange = 0; /* * newentry olladdr lladdr llchange (*=record) * 0 n n -- (1) * 0 y n -- (2) * 0 n y -- (3) * STALE * 0 y y n (4) * * 0 y y y (5) * STALE * 1 -- n -- (6) NOSTATE(= PASSIVE) * 1 -- y -- (7) * STALE */ if (lladdr) { /*(3-5) and (7)*/ /* * Record source link-layer address * XXX is it dependent to ifp->if_type? */ sdl->sdl_alen = ifp->if_addrlen; bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen); } if (!is_newentry) { if ((!olladdr && lladdr) /*(3)*/ || (olladdr && lladdr && llchange)) { /*(5)*/ do_update = 1; newstate = ND6_LLINFO_STALE; } else /*(1-2,4)*/ do_update = 0; } else { do_update = 1; if (!lladdr) /*(6)*/ newstate = ND6_LLINFO_NOSTATE; else /*(7)*/ newstate = ND6_LLINFO_STALE; } if (do_update) { /* * Update the state of the neighbor cache. */ ln->ln_state = newstate; if (ln->ln_state == ND6_LLINFO_STALE) { rt->rt_flags &= ~RTF_REJECT; if (ln->ln_hold) { (*ifp->if_output)(ifp, ln->ln_hold, rt_key(rt), rt); ln->ln_hold = 0; } } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { /* probe right away */ ln->ln_expire = time_second; } } /* * ICMP6 type dependent behavior. * * NS: clear IsRouter if new entry * RS: clear IsRouter * RA: set IsRouter if there's lladdr * redir: clear IsRouter if new entry * * RA case, (1): * The spec says that we must set IsRouter in the following cases: * - If lladdr exist, set IsRouter. This means (1-5). * - If it is old entry (!newentry), set IsRouter. This means (7). * So, based on the spec, in (1-5) and (7) cases we must set IsRouter. * A quetion arises for (1) case. (1) case has no lladdr in the * neighbor cache, this is similar to (6). * This case is rare but we figured that we MUST NOT set IsRouter. * * newentry olladdr lladdr llchange NS RS RA redir * 0 n n -- (1) c ? * 0 y n -- (2) c s * 0 n y -- (3) c s * 0 y y n (4) c s * 0 y y y (5) c s * 1 -- n -- (6) c c c * 1 -- y -- (7) c c s c * * (c=clear s=set) */ switch (type & 0xff) { case ND_NEIGHBOR_SOLICIT: case ND_REDIRECT: /* * New entry must have is_router flag cleared. */ if (is_newentry) /*(6-7)*/ ln->ln_router = 0; break; case ND_ROUTER_SOLICIT: /* * is_router flag must always be cleared. */ ln->ln_router = 0; break; case ND_ROUTER_ADVERT: /* * Mark an entry with lladdr as a router. */ if ((!is_newentry && (olladdr || lladdr)) /*(2-5)*/ || (is_newentry && lladdr)) { /*(7)*/ ln->ln_router = 1; } break; } return rt; } static void nd6_slowtimo(ignored_arg) void *ignored_arg; { int s = splnet(); register int i; register struct nd_ifinfo *nd6if; timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); for (i = 1; i < if_index + 1; i++) { nd6if = &nd_ifinfo[i]; if (nd6if->basereachable && /* already initialized */ (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) { /* * Since reachable time rarely changes by router * advertisements, we SHOULD insure that a new random * value gets recomputed at least once every few hours. * (RFC 2461, 6.3.4) */ nd6if->recalctm = nd6_recalc_reachtm_interval; nd6if->reachable = ND_COMPUTE_RTIME(nd6if->basereachable); } } splx(s); } #ifdef NEWIP6OUTPUT /* for experimental */ #define senderr(e) { error = (e); goto bad;} int nd6_output(ifp, m0, dst, rt0) register struct ifnet *ifp; struct mbuf *m0; struct sockaddr_in6 *dst; struct rtentry *rt0; { register struct mbuf *m = m0; register struct rtentry *rt = rt0; struct llinfo_nd6 *ln = NULL; int error = 0; if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) goto sendpkt; /* * XXX: we currently do not make neighbor cache on any interface * other than Ethernet and FDDI. */ if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_FDDI) goto sendpkt; /* * next hop determination. This routine is derived from ether_outpout. */ if (rt) { if ((rt->rt_flags & RTF_UP) == 0) { #ifdef __FreeBSD__ if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1, 0UL)) != NULL) { #else if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1)) != NULL) { #endif rt->rt_refcnt--; if (rt->rt_ifp != ifp) return nd6_output(ifp, m0, dst, rt); /* XXX: loop care? */ } else senderr(EHOSTUNREACH); } if (rt->rt_flags & RTF_GATEWAY) { if (rt->rt_gwroute == 0) goto lookup; if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { rtfree(rt); rt = rt0; #ifdef __FreeBSD__ lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL); #else lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); #endif if ((rt = rt->rt_gwroute) == 0) senderr(EHOSTUNREACH); #ifdef __bsdi__ /* the "G" test below also prevents rt == rt0 */ if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_ifp != ifp)) { rt->rt_refcnt--; rt0->rt_gwroute = 0; senderr(EHOSTUNREACH); } #endif } } if (rt->rt_flags & RTF_REJECT) senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); } /* * Address resolution or Neighbor Unreachability Detection * for the next hop. * At this point, the destination of the packet must be a unicast * or an anycast address(i.e. not a multicast). */ /* Look up the neighbor cache for the nexthop */ if (rt && (rt->rt_flags & RTF_LLINFO) != 0) ln = (struct llinfo_nd6 *)rt->rt_llinfo; else { if ((rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL) ln = (struct llinfo_nd6 *)rt->rt_llinfo; } if (!ln || !rt) { log(LOG_DEBUG, "nd6_output: can't allocate llinfo for %s " "(ln=%p, rt=%p)\n", ip6_sprintf(&dst->sin6_addr), ln, rt); senderr(EIO); /* XXX: good error? */ } /* * The first time we send a packet to a neighbor whose entry is * STALE, we have to change the state to DELAY and a sets a timer to * expire in DELAY_FIRST_PROBE_TIME seconds to ensure do * neighbor unreachability detection on expiration. * (RFC 2461 7.3.3) */ if (ln->ln_state == ND6_LLINFO_STALE) { ln->ln_asked = 0; ln->ln_state = ND6_LLINFO_DELAY; ln->ln_expire = time_second + nd6_delay; } /* * If the neighbor cache entry has a state other than INCOMPLETE * (i.e. its link-layer address is already reloved), just * send the packet. */ if (ln->ln_state > ND6_LLINFO_INCOMPLETE) goto sendpkt; /* * There is a neighbor cache entry, but no ethernet address * response yet. Replace the held mbuf (if any) with this * latest one. * * XXX Does the code conform to rate-limiting rule? * (RFC 2461 7.2.2) */ if (ln->ln_state == ND6_LLINFO_WAITDELETE || ln->ln_state == ND6_LLINFO_NOSTATE) ln->ln_state = ND6_LLINFO_INCOMPLETE; if (ln->ln_hold) m_freem(ln->ln_hold); ln->ln_hold = m; if (ln->ln_expire) { rt->rt_flags &= ~RTF_REJECT; if (ln->ln_asked < nd6_mmaxtries && ln->ln_expire < time_second) { ln->ln_asked++; ln->ln_expire = time_second + nd_ifinfo[ifp->if_index].retrans / 1000; nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); } } return(0); sendpkt: return((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt)); bad: if (m) m_freem(m); return (error); } #undef senderr int nd6_storelladdr(ifp, rt, m, dst, desten) struct ifnet *ifp; struct rtentry *rt; struct mbuf *m; struct sockaddr *dst; u_char *desten; { struct sockaddr_dl *sdl; if (m->m_flags & M_MCAST) { switch (ifp->if_type) { case IFT_ETHER: case IFT_FDDI: ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, desten); return(1); break; default: return(0); } } if (rt == NULL || rt->rt_gateway->sa_family != AF_LINK) { printf("nd6_storelladdr: something odd happens\n"); return(0); } sdl = SDL(rt->rt_gateway); if (sdl->sdl_alen != 0) bcopy(LLADDR(sdl), desten, sdl->sdl_alen); return(1); } #endif /* NEWIP6OUTPUT */ @ 1.2.2.3 log @Update from trunk. @ text @a0 2 /* $NetBSD: nd6.c,v 1.2.2.2 1999/08/02 22:36:06 thorpej Exp $ */ d73 1 d376 1 a376 1 s = splsoftnet(); a620 54 * Detect if a given IPv6 address identifies a neighbor on a given link. * XXX: should take care of the destination of a p2p link? */ int nd6_is_addr_neighbor(addr, ifp) struct in6_addr *addr; struct ifnet *ifp; { register struct ifaddr *ifa; int i; #define IFADDR6(a) ((((struct in6_ifaddr *)(a))->ia_addr).sin6_addr) #define IFMASK6(a) ((((struct in6_ifaddr *)(a))->ia_prefixmask).sin6_addr) /* A link-local address is always a neighbor. */ if (IN6_IS_ADDR_LINKLOCAL(addr)) return(1); /* * If the address matches one of our addresses, * it should be a neighbor. */ #ifdef __bsdi__ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) #else for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) #endif { if (ifa->ifa_addr->sa_family != AF_INET6) next: continue; for (i = 0; i < 4; i++) { if ((IFADDR6(ifa).s6_addr32[i] ^ addr->s6_addr32[i]) & IFMASK6(ifa).s6_addr32[i]) goto next; } return(1); } /* * Even if the address matches none of our addresses, it might be * in the neighbor cache. */ if (nd6_lookup(addr, 0, ifp)) return(1); return(0); #undef IFADDR6 #undef IFMASK6 } /* d637 1 a637 1 s = splsoftnet(); a895 1 #if 0 a896 6 #else ln->ln_next = llinfo_nd6.ln_next; llinfo_nd6.ln_next = ln; ln->ln_prev = &llinfo_nd6; ln->ln_next->ln_prev = ln; #endif a940 1 #if 0 a941 5 #else ln->ln_next->ln_prev = ln->ln_prev; ln->ln_prev->ln_next = ln->ln_next; ln->ln_prev = NULL; #endif d1034 1 a1034 1 s = splsoftnet(); d1059 1 a1059 1 s = splsoftnet(); d1119 1 a1119 1 s = splsoftnet(); d1134 1 a1134 1 s = splsoftnet(); d1153 1 a1153 1 s = splsoftnet(); d1176 1 a1176 1 nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code) a1181 1 int code; /* type dependent information */ d1321 7 a1327 8 * D R * 0 n n -- (1) c ? s * 0 y n -- (2) c s s * 0 n y -- (3) c s s * 0 y y n (4) c s s * 0 y y y (5) c s s * 1 -- n -- (6) c c c s * 1 -- y -- (7) c c s c s d1333 1 a1339 12 case ND_REDIRECT: /* * If the icmp is a redirect to a better router, always set the * is_router flag. Otherwise, if the entry is newly created, * clear the flag. [RFC 2461, sec 8.3] * */ if (code == ND_REDIRECT_ROUTER) ln->ln_router = 1; else if (is_newentry) /*(6-7)*/ ln->ln_router = 0; break; d1364 1 a1364 1 int s = splsoftnet(); @ 1.1 log @file nd6.c was initially added on branch kame. @ text @d1 1569 @ 1.1.2.1 log @KAME/NetBSD 1.4 SNAP kit, dated 19990628. NOTE: this branch (kame) is used just for refernce. this may not compile due to multiple reasons. @ text @a0 1569 /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * 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. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS 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. */ /* * XXX * KAME 970409 note: * BSD/OS version heavily modifies this code, related to llinfo. * Since we don't have BSD/OS version of net/route.c in our hand, * I left the code mostly as it was in 970310. -- itojun */ #include #include #include #include #include #include #include #include #include #if !defined(__FreeBSD__) || __FreeBSD__ < 3 #include #endif #include #include #include #include #include #include #include #include #ifndef __NetBSD__ #include #ifdef __FreeBSD__ #include #endif #ifdef __bsdi__ #include #endif #else /* __NetBSD__ */ #include #include #include #endif /* __NetBSD__ */ #include #include #include #include #include #include #include "loop.h" #ifdef __NetBSD__ extern struct ifnet loif[NLOOP]; #endif #define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */ #define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */ #if !defined(__FreeBSD__) || __FreeBSD__ < 3 #define time_second time.tv_sec #endif #define SIN6(s) ((struct sockaddr_in6 *)s) #define SDL(s) ((struct sockaddr_dl *)s) /* timer values */ int nd6_prune = 1; /* walk list every 1 seconds */ int nd6_delay = 5; /* delay first probe time 5 second */ int nd6_umaxtries = 3; /* maximum unicast query */ int nd6_mmaxtries = 3; /* maximum multicast query */ int nd6_useloopback = 1; /* use loopback interface for local traffic */ int nd6_proxyall = 0; /* enable Proxy Neighbor Advertisement */ /* for debugging? */ static int nd6_inuse, nd6_allocated; struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6}; struct nd_ifinfo *nd_ifinfo; struct nd_drhead nd_defrouter = { 0 }; struct nd_prhead nd_prefix = { 0 }; int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; #if 0 extern int ip6_forwarding; #endif static void nd6_slowtimo __P((void *)); void nd6_init() { static int nd6_init_done = 0; if (nd6_init_done) { log(LOG_NOTICE, "nd6_init called more than once(ignored)\n"); return; } nd6_init_done = 1; /* start timer */ timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); } void nd6_ifattach(ifp) struct ifnet *ifp; { static size_t if_indexlim = 8; /* * We have some arrays that should be indexed by if_index. * since if_index will grow dynamically, they should grow too. */ if (nd_ifinfo == NULL || if_index >= if_indexlim) { size_t n; caddr_t q; while (if_index >= if_indexlim) if_indexlim <<= 1; /* grow nd_ifinfo */ n = if_indexlim * sizeof(struct nd_ifinfo); q = (caddr_t)malloc(n, M_IP6NDP, M_WAITOK); bzero(q, n); if (nd_ifinfo) { bcopy((caddr_t)nd_ifinfo, q, n/2); free((caddr_t)nd_ifinfo, M_IP6NDP); } nd_ifinfo = (struct nd_ifinfo *)q; } #define ND nd_ifinfo[ifp->if_index] ND.linkmtu = ifindex2ifnet[ifp->if_index]->if_mtu; ND.chlim = IPV6_DEFHLIM; ND.basereachable = REACHABLE_TIME; ND.reachable = ND_COMPUTE_RTIME(ND.basereachable); ND.retrans = RETRANS_TIMER; ND.receivedra = 0; nd6_setmtu(ifp); #undef ND } /* * Reset ND level link MTU. This function is called when the physical MTU * changes, which means we might have to adjust the ND level MTU. */ void nd6_setmtu(ifp) struct ifnet *ifp; { #define MIN(a,b) ((a) < (b) ? (a) : (b)) struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; u_long oldmaxmtu = ndi->maxmtu; u_long oldlinkmtu = ndi->linkmtu; switch(ifp->if_type) { case IFT_ETHER: ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); break; #if defined(__FreeBSD__) || defined(__bsdi__) case IFT_FDDI: ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); break; #endif case IFT_ATM: ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); break; default: ndi->maxmtu = ifp->if_mtu; break; } if (oldmaxmtu != ndi->maxmtu) { /* * If the ND level MTU is not set yet, or if the maxmtu * is reset to a smaller value than the ND level MTU, * also reset the ND level MTU. */ if (ndi->linkmtu == 0 || ndi->maxmtu < ndi->linkmtu) { ndi->linkmtu = ndi->maxmtu; /* also adjust in6_maxmtu if necessary. */ if (oldlinkmtu == 0) { /* * XXX: the case analysis is grotty, but * it is not efficient to call in6_setmaxmtu() * here when we are during the initialization * procedure. */ if (in6_maxmtu < ndi->linkmtu) in6_maxmtu = ndi->linkmtu; } else in6_setmaxmtu(); } } #undef MIN } void nd6_option_init(opt, icmp6len, ndopts) void *opt; int icmp6len; union nd_opts *ndopts; { bzero(ndopts, sizeof(*ndopts)); ndopts->nd_opts_search = (struct nd_opt_hdr *)opt; ndopts->nd_opts_last = (struct nd_opt_hdr *)(((u_char *)opt) + icmp6len); if (icmp6len == 0) { ndopts->nd_opts_done = 1; ndopts->nd_opts_search = NULL; } } /* * Take one ND option. */ struct nd_opt_hdr * nd6_option(ndopts) union nd_opts *ndopts; { struct nd_opt_hdr *nd_opt; int olen; if (!ndopts) panic("ndopts == NULL in nd6_option\n"); if (!ndopts->nd_opts_last) panic("uninitialized ndopts in nd6_option\n"); if (!ndopts->nd_opts_search) return NULL; if (ndopts->nd_opts_done) return NULL; nd_opt = ndopts->nd_opts_search; olen = nd_opt->nd_opt_len << 3; if (olen == 0) { /* * Message validation requires that all included * options have a length that is greater than zero. */ bzero(ndopts, sizeof(*ndopts)); return NULL; } ndopts->nd_opts_search = (struct nd_opt_hdr *)((caddr_t)nd_opt + olen); if (!(ndopts->nd_opts_search < ndopts->nd_opts_last)) { ndopts->nd_opts_done = 1; ndopts->nd_opts_search = NULL; } return nd_opt; } /* * Parse multiple ND options. * This function is much easier to use, for ND routines that do not need * multiple options of the same type. */ int nd6_options(ndopts) union nd_opts *ndopts; { struct nd_opt_hdr *nd_opt; int i = 0; if (!ndopts) panic("ndopts == NULL in nd6_options\n"); if (!ndopts->nd_opts_last) panic("uninitialized ndopts in nd6_options\n"); if (!ndopts->nd_opts_search) return 0; while (1) { nd_opt = nd6_option(ndopts); if (!nd_opt && !ndopts->nd_opts_last) { /* * Message validation requires that all included * options have a length that is greater than zero. */ bzero(ndopts, sizeof(*ndopts)); return -1; } if (!nd_opt) goto skip1; switch (nd_opt->nd_opt_type) { case ND_OPT_SOURCE_LINKADDR: case ND_OPT_TARGET_LINKADDR: case ND_OPT_MTU: case ND_OPT_REDIRECTED_HEADER: if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { printf("duplicated ND6 option found " "(type=%d)\n", nd_opt->nd_opt_type); /* XXX bark? */ } else { ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; } break; case ND_OPT_PREFIX_INFORMATION: if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) { ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; } ndopts->nd_opts_pi_end = (struct nd_opt_prefix_info *)nd_opt; break; default: /* * Unknown options must be silently ignored, * to accomodate future extension to the protocol. */ log(LOG_INFO, "nd6_options: unsupported option %d - " "option ignored\n", nd_opt->nd_opt_type); } skip1: i++; if (i > 10) { printf("too many loop in nd opt\n"); break; } if (ndopts->nd_opts_done) break; } return 0; } /* * ND6 timer routine to expire default route list and prefix list */ void nd6_timer(ignored_arg) void *ignored_arg; { int s; register struct llinfo_nd6 *ln; register struct nd_defrouter *dr; register struct nd_prefix *pr; s = splnet(); timeout(nd6_timer, (caddr_t)0, nd6_prune * hz); ln = llinfo_nd6.ln_next; /* XXX BSD/OS separates this code -- itojun */ while (ln && ln != &llinfo_nd6) { struct rtentry *rt; struct ifnet *ifp; struct sockaddr_in6 *dst; struct llinfo_nd6 *next = ln->ln_next; if ((rt = ln->ln_rt) == NULL) { ln = next; continue; } if ((ifp = rt->rt_ifp) == NULL) { ln = next; continue; } dst = (struct sockaddr_in6 *)rt_key(rt); if (ln->ln_expire > time_second) { ln = next; continue; } /* sanity check */ if (!rt) panic("rt=0 in nd6_timer(ln=%p)\n", ln); if (!dst) panic("dst=0 in nd6_timer(ln=%p)\n", ln); switch (ln->ln_state) { case ND6_LLINFO_INCOMPLETE: if (ln->ln_asked < nd6_mmaxtries) { ln->ln_asked++; ln->ln_expire = time_second + nd_ifinfo[ifp->if_index].retrans / 1000; nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); } else { struct mbuf *m = ln->ln_hold; if (m) { if (rt->rt_ifp) { /* * Fake rcvif to make ICMP error * more helpful in diagnosing * for the receiver. * XXX: should we consider * older rcvif? */ m->m_pkthdr.rcvif = rt->rt_ifp; } icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0); ln->ln_hold = NULL; } nd6_free(rt); } break; case ND6_LLINFO_REACHABLE: if (ln->ln_expire) { ln->ln_state = ND6_LLINFO_STALE; } break; /* * ND6_LLINFO_STALE state requires nothing for timer * routine. */ case ND6_LLINFO_DELAY: ln->ln_asked = 1; ln->ln_state = ND6_LLINFO_PROBE; ln->ln_expire = time_second + nd_ifinfo[ifp->if_index].retrans / 1000; nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); break; case ND6_LLINFO_PROBE: if (ln->ln_asked < nd6_umaxtries) { ln->ln_asked++; ln->ln_expire = time_second + nd_ifinfo[ifp->if_index].retrans / 1000; nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); } else { nd6_free(rt); } break; case ND6_LLINFO_WAITDELETE: nd6_free(rt); break; } ln = next; } /* expire */ dr = nd_defrouter.lh_first; while (dr) { if (dr->expire && dr->expire < time_second) { struct nd_defrouter *t; t = dr->dr_next; defrtrlist_del(dr); dr = t; } else dr = dr->dr_next; } pr = nd_prefix.lh_first; while (pr) { struct in6_ifaddr *ia6; struct in6_addrlifetime *lt6; if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) ia6 = NULL; else ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); if (ia6) { /* check address lifetime */ lt6 = &ia6->ia6_lifetime; if (lt6->ia6t_preferred && lt6->ia6t_preferred < time_second) ia6->ia6_flags |= IN6_IFF_DEPRECATED; if (lt6->ia6t_expire && lt6->ia6t_expire < time_second) { if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); /* xxx ND_OPT_PI_FLAG_ONLINK processing */ } } /* * check prefix lifetime. * since pltime is just for autoconf, pltime processing for * prefix is not necessary. * * we offset expire time by NDPR_KEEP_EXPIRE, so that we * can use the old prefix information to validate the * next prefix information to come. See prelist_update() * for actual validation. */ if (pr->ndpr_expire && pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) { struct nd_prefix *t; t = pr->ndpr_next; /* * address expiration and prefix expiration are * separate. NEVER perform in6_ifdel here. */ prelist_remove(pr); pr = t; } else pr = pr->ndpr_next; } splx(s); } static struct sockaddr_in6 all1_sa = { sizeof(struct sockaddr_in6), AF_INET6, 0, 0, {{{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}}}, 0}; struct rtentry * nd6_lookup(addr6, create, ifp) struct in6_addr *addr6; int create; struct ifnet *ifp; { struct rtentry *rt; struct sockaddr_in6 sin6; bzero(&sin6, sizeof(sin6)); sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_family = AF_INET6; sin6.sin6_addr = *addr6; rt = rtalloc1((struct sockaddr *)&sin6, create #ifdef __FreeBSD__ , 0UL #endif /*__FreeBSD__*/ ); if (rt && (rt->rt_flags & RTF_LLINFO) == 0) { /* * This is the case for the default route. * If we want to create a neighbor cache for the address, we * should free the route for the destination and allocate an * interface route. */ if (create) { RTFREE(rt); rt = 0; } } if (!rt) { if (create && ifp) { /* * If no route is available and create is set, * we allocate a host route for the destination * and treat it like an interface route. * This hack is necessary for a neighbor which can't * be covered by our own prefix. */ struct ifaddr *ifa = ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); if (ifa == NULL) return(NULL); /* * Create a new route. RTF_LLINFO is necessary * to create a Neighbor Cache entry for the * destination in nd6_rtrequest which will be * called in rtequest via ifa->ifa_rtrequest. */ if (rtrequest(RTM_ADD, (struct sockaddr *)&sin6, ifa->ifa_addr, (struct sockaddr *)&all1_sa, (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, &rt)) log(LOG_ERR, "nd6_lookup: failed to add route for a " "neighbor(%s)\n", ip6_sprintf(addr6)); if (rt == NULL) return(NULL); if (rt->rt_llinfo) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; ln->ln_state = ND6_LLINFO_NOSTATE; } } else return(NULL); } rt->rt_refcnt--; if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || rt->rt_gateway->sa_family != AF_LINK) { if (create) { log(LOG_DEBUG, "nd6_lookup: failed to lookup %s\n", ip6_sprintf(addr6)); /* xxx more logs... kazu */ } return(0); } return(rt); } /* * Free an nd6 llinfo entry. */ void nd6_free(rt) struct rtentry *rt; { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; struct sockaddr_dl *sdl; if (ln->ln_router) { /* remove from default router list */ struct nd_defrouter *dr; struct in6_addr *in6; int s; in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; s = splnet(); dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))-> sin6_addr, rt->rt_ifp); if (dr) defrtrlist_del(dr); else if (!ip6_forwarding && ip6_accept_rtadv) { /* * rt6_flush must be called in any case. * see the comment in nd6_na_input(). */ rt6_flush(in6, rt->rt_ifp); } splx(s); } if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && sdl->sdl_family == AF_LINK) { sdl->sdl_alen = 0; ln->ln_state = ND6_LLINFO_WAITDELETE; ln->ln_asked = 0; rt->rt_flags &= ~RTF_REJECT; return; } rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), 0, (struct rtentry **)0); } /* * Upper-layer reachability hint for Neighbor Unreachability Detection. * * XXX cost-effective metods? */ void nd6_nud_hint(rt, dst6) struct rtentry *rt; struct in6_addr *dst6; { struct llinfo_nd6 *ln; /* * If the caller specified "rt", use that. Otherwise, resolve the * routing table by supplied "dst6". */ if (!rt) { if (!dst6) return; if (!(rt = nd6_lookup(dst6, 0, NULL))) return; } if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || !rt->rt_llinfo || !rt->rt_gateway || rt->rt_gateway->sa_family != AF_LINK) { /* This is not a host route. */ return; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; if (ln->ln_state == ND6_LLINFO_INCOMPLETE) return; ln->ln_state = ND6_LLINFO_REACHABLE; if (ln->ln_expire) ln->ln_expire = time_second + nd_ifinfo[rt->rt_ifp->if_index].reachable; } /* * Resolve an IP6 address into an ethernet address. If success, * desten is filled in. If there is no entry in ndptab, * set one up and multicast a solicitation for the IP6 address. * Hold onto this mbuf and resend it once the address * is finally resolved. A return value of 1 indicates * that desten has been filled in and the packet should be sent * normally; a 0 return indicates that the packet has been * taken over here, either now or for later transmission. */ int nd6_resolve(ifp, rt, m, dst, desten) struct ifnet *ifp; struct rtentry *rt; struct mbuf *m; struct sockaddr *dst; u_char *desten; { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL; struct sockaddr_dl *sdl; if (m->m_flags & M_MCAST) { switch (ifp->if_type) { case IFT_ETHER: case IFT_FDDI: ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, desten); return(1); break; default: return(0); } } if (rt && (rt->rt_flags & RTF_LLINFO) != 0) ln = (struct llinfo_nd6 *)rt->rt_llinfo; else { if ((rt = nd6_lookup(&(SIN6(dst)->sin6_addr), 1, ifp)) != NULL) ln = (struct llinfo_nd6 *)rt->rt_llinfo; } if (!ln || !rt) { log(LOG_DEBUG, "nd6_resolve: can't allocate llinfo for %s\n", ip6_sprintf(&(SIN6(dst)->sin6_addr))); m_freem(m); return(0); } sdl = SDL(rt->rt_gateway); /* * Ckeck the address family and length is valid, the address * is resolved; otherwise, try to resolve. */ if (ln->ln_state >= ND6_LLINFO_REACHABLE && sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { bcopy(LLADDR(sdl), desten, sdl->sdl_alen); if (ln->ln_state == ND6_LLINFO_STALE) { ln->ln_asked = 0; ln->ln_state = ND6_LLINFO_DELAY; ln->ln_expire = time_second + nd6_delay; } return(1); } /* * There is an ndp entry, but no ethernet address * response yet. Replace the held mbuf with this * latest one. * * XXX Does the code conform to rate-limiting rule? * (RFC 2461 7.2.2) */ if (ln->ln_state == ND6_LLINFO_WAITDELETE || ln->ln_state == ND6_LLINFO_NOSTATE) ln->ln_state = ND6_LLINFO_INCOMPLETE; if (ln->ln_hold) m_freem(ln->ln_hold); ln->ln_hold = m; if (ln->ln_expire) { rt->rt_flags &= ~RTF_REJECT; if (ln->ln_asked < nd6_mmaxtries && ln->ln_expire < time_second) { ln->ln_asked++; ln->ln_expire = time_second + nd_ifinfo[ifp->if_index].retrans / 1000; nd6_ns_output(ifp, NULL, &(SIN6(dst)->sin6_addr), ln, 0); } } return(0); } void nd6_rtrequest(req, rt, sa) int req; struct rtentry *rt; struct sockaddr *sa; /* xxx unused */ { struct sockaddr *gate = rt->rt_gateway; struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; struct ifnet *ifp = rt->rt_ifp; struct ifaddr *ifa; if (rt->rt_flags & RTF_GATEWAY) return; switch (req) { case RTM_ADD: /* * There is no backward compatibility :) * * if ((rt->rt_flags & RTF_HOST) == 0 && * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) * rt->rt_flags |= RTF_CLONING; */ if (rt->rt_flags & RTF_CLONING || rt->rt_flags & RTF_LLINFO) { /* * Case 1: This route should come from * a route to interface. RTF_LLINFO flag is set * for a host route whose destination should be * treated as on-link. */ rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl); gate = rt->rt_gateway; SDL(gate)->sdl_type = ifp->if_type; SDL(gate)->sdl_index = ifp->if_index; if (ln) ln->ln_expire = time_second; #if 1 if (ln && ln->ln_expire == 0) { /* cludge for desktops */ #if 0 printf("nd6_request: time.tv_sec is zero; " "treat it as 1\n"); #endif ln->ln_expire = 1; } #endif if (rt->rt_flags & RTF_CLONING) break; } /* Announce a new entry if requested. */ if (rt->rt_flags & RTF_ANNOUNCE) nd6_na_output(ifp, &SIN6(rt_key(rt))->sin6_addr, &SIN6(rt_key(rt))->sin6_addr, ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1); /* FALLTHROUGH */ case RTM_RESOLVE: if (gate->sa_family != AF_LINK || gate->sa_len < sizeof(null_sdl)) { log(LOG_DEBUG, "nd6_rtrequest: bad gateway value\n"); break; } SDL(gate)->sdl_type = ifp->if_type; SDL(gate)->sdl_index = ifp->if_index; if (ln != 0) break; /* This happens on a route change */ /* * Case 2: This route may come from cloning, or a manual route * add with a LL address. */ R_Malloc(ln, struct llinfo_nd6 *, sizeof(*ln)); rt->rt_llinfo = (caddr_t)ln; if (!ln) { log(LOG_DEBUG, "nd6_rtrequest: malloc failed\n"); break; } nd6_inuse++; nd6_allocated++; Bzero(ln, sizeof(*ln)); ln->ln_rt = rt; /* this is required for "ndp" command. - shin */ if (req == RTM_ADD) { /* * gate should have some valid AF_LINK entry, * and ln->ln_expire should have some lifetime * which is specified by ndp command. */ ln->ln_state = ND6_LLINFO_REACHABLE; } else { /* * When req == RTM_RESOLVE, rt is created and * initialized in rtrequest(), so rt_expire is 0. */ ln->ln_state = ND6_LLINFO_INCOMPLETE; ln->ln_expire = time_second; } rt->rt_flags |= RTF_LLINFO; insque(ln, &llinfo_nd6); /* * check if rt_key(rt) is one of my address assigned * to the interface. */ ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, &SIN6(rt_key(rt))->sin6_addr); if (ifa) { caddr_t macp = nd6_ifptomac(ifp); ln->ln_expire = 0; ln->ln_state = ND6_LLINFO_REACHABLE; if (macp) { Bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); SDL(gate)->sdl_alen = ifp->if_addrlen; } if (nd6_useloopback) { #ifdef __bsdi__ extern struct ifnet loif; rt->rt_ifp = &loif; /*XXX*/ #endif /*__bsdi__*/ #if defined(__FreeBSD__) || defined(__NetBSD__) rt->rt_ifp = &loif[0]; /*XXX*/ #endif /* * Make sure rt_ifa be equal to the ifaddr * corresponding to the address. * We need this because when we refer * rt_ifa->ia6_flags in ip6_input, we assume * that the rt_ifa points to the address instead * of the loopback address. */ if (ifa != rt->rt_ifa) { rt->rt_ifa->ifa_refcnt--; ifa->ifa_refcnt++; rt->rt_ifa = ifa; } } } break; case RTM_DELETE: if (!ln) break; nd6_inuse--; remque(ln); rt->rt_llinfo = 0; rt->rt_flags &= ~RTF_LLINFO; if (ln->ln_hold) m_freem(ln->ln_hold); Free((caddr_t)ln); } } void nd6_p2p_rtrequest(req, rt, sa) int req; struct rtentry *rt; struct sockaddr *sa; /* xxx unused */ { struct sockaddr *gate = rt->rt_gateway; static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; struct ifnet *ifp = rt->rt_ifp; struct ifaddr *ifa; if (rt->rt_flags & RTF_GATEWAY) return; switch (req) { case RTM_ADD: /* * There is no backward compatibility :) * * if ((rt->rt_flags & RTF_HOST) == 0 && * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) * rt->rt_flags |= RTF_CLONING; */ if (rt->rt_flags & RTF_CLONING) { /* * Case 1: This route should come from * a route to interface. */ rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl); gate = rt->rt_gateway; SDL(gate)->sdl_type = ifp->if_type; SDL(gate)->sdl_index = ifp->if_index; break; } /* Announce a new entry if rqquested. */ if (rt->rt_flags & RTF_ANNOUNCE) nd6_na_output(ifp, &SIN6(rt_key(rt))->sin6_addr, &SIN6(rt_key(rt))->sin6_addr, ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1); /* FALLTHROUGH */ case RTM_RESOLVE: /* * check if rt_key(rt) is one of my address assigned * to the interface. */ ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, &SIN6(rt_key(rt))->sin6_addr); if (ifa) { if (nd6_useloopback) { #ifdef __bsdi__ extern struct ifnet loif; rt->rt_ifp = &loif; /*XXX*/ #endif /*__bsdi__*/ #if defined(__FreeBSD__) || defined(__NetBSD__) rt->rt_ifp = &loif[0]; /*XXX*/ #endif } } break; } } int nd6_ioctl(cmd, data, ifp) u_long cmd; caddr_t data; struct ifnet *ifp; { struct in6_drlist *drl = (struct in6_drlist *)data; struct in6_prlist *prl = (struct in6_prlist *)data; struct in6_ndireq *ndi = (struct in6_ndireq *)data; struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; struct nd_defrouter *dr, any; struct nd_prefix *pr; struct rtentry *rt; int i = 0, error = 0; int s; switch (cmd) { case SIOCGDRLST_IN6: bzero(drl, sizeof(*drl)); s = splnet(); dr = nd_defrouter.lh_first; while (dr && i < DRLSTSIZ) { drl->defrouter[i].rtaddr = dr->rtaddr; if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) { /* XXX: need to this hack for KAME stack */ drl->defrouter[i].rtaddr.s6_addr16[1] = 0; } else log(LOG_ERR, "default router list contains a " "non-linklocal address(%s)\n", ip6_sprintf(&drl->defrouter[i].rtaddr)); drl->defrouter[i].flags = dr->flags; drl->defrouter[i].rtlifetime = dr->rtlifetime; drl->defrouter[i].expire = dr->expire; drl->defrouter[i].if_index = dr->ifp->if_index; i++; dr = dr->dr_next; } splx(s); break; case SIOCGPRLST_IN6: bzero(prl, sizeof(*prl)); s = splnet(); pr = nd_prefix.lh_first; while (pr && i < PRLSTSIZ) { struct nd_pfxrouter *pfr; int j; prl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; prl->prefix[i].raflags = pr->ndpr_raf; prl->prefix[i].prefixlen = pr->ndpr_plen; prl->prefix[i].vltime = pr->ndpr_vltime; prl->prefix[i].pltime = pr->ndpr_pltime; prl->prefix[i].if_index = pr->ndpr_ifp->if_index; prl->prefix[i].expire = pr->ndpr_expire; pfr = pr->ndpr_advrtrs.lh_first; j = 0; while(pfr) { if (j < DRLSTSIZ) { #define RTRADDR prl->prefix[i].advrtr[j] RTRADDR = pfr->router->rtaddr; if (IN6_IS_ADDR_LINKLOCAL(&RTRADDR)) { /* XXX: hack for KAME */ RTRADDR.s6_addr16[1] = 0; } else log(LOG_ERR, "a router(%s) advertises " "a prefix with " "non-link local address\n", ip6_sprintf(&RTRADDR)); #undef RTRADDR } j++; pfr = pfr->pfr_next; } prl->prefix[i].advrtrs = j; i++; pr = pr->ndpr_next; } splx(s); break; case SIOCGIFINFO_IN6: ndi->ndi = nd_ifinfo[ifp->if_index]; break; case SIOCSNDFLUSH_IN6: /* flush default router list */ /* * xxx sumikawa: should not delete route if default * route equals to the top of default router list */ bzero(&any, sizeof(any)); defrouter_delreq(&any, 0); /* xxx sumikawa: flush prefix list */ break; case SIOCSPFXFLUSH_IN6: { /* flush all the prefix advertised by routers */ struct nd_prefix *pr, *next; s = splnet(); for (pr = nd_prefix.lh_first; pr; pr = next) { next = pr->ndpr_next; if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); prelist_remove(pr); } splx(s); break; } case SIOCSRTRFLUSH_IN6: { /* flush all the default routers */ struct nd_defrouter *dr, *next; s = splnet(); if ((dr = nd_defrouter.lh_first) != NULL) { /* * The first entry of the list may be stored in * the routing table, so we'll delete it later. */ for (dr = dr->dr_next; dr; dr = next) { next = dr->dr_next; defrtrlist_del(dr); } defrtrlist_del(nd_defrouter.lh_first); } splx(s); break; } case SIOCGNBRINFO_IN6: { struct llinfo_nd6 *ln; s = splnet(); if ((rt = nd6_lookup(&nbi->addr, 0, ifp)) == NULL) { error = EINVAL; break; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; nbi->state = ln->ln_state; nbi->asked = ln->ln_asked; nbi->isrouter = ln->ln_router; nbi->expire = ln->ln_expire; splx(s); break; } } return(error); } /* * Create neighbor cache entry and cache link-layer address, * on reception of inbound ND6 packets. (RS/RA/NS/redirect) */ struct rtentry * nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type) struct ifnet *ifp; struct in6_addr *from; char *lladdr; int lladdrlen; int type; /* ICMP6 type */ { struct rtentry *rt = NULL; struct llinfo_nd6 *ln = NULL; int is_newentry; struct sockaddr_dl *sdl = NULL; int do_update; int olladdr; int llchange; int newstate = 0; if (!ifp) panic("ifp == NULL in nd6_cache_lladdr"); if (!from) panic("from == NULL in nd6_cache_lladdr"); /* nothing must be updated for unspecified address */ if (IN6_IS_ADDR_UNSPECIFIED(from)) return NULL; /* * Validation about ifp->if_addrlen and lladdrlen must be done in * the caller. * * XXX If the link does not have link-layer adderss, what should * we do? (ifp->if_addrlen == 0) * Spec says nothing in sections for RA, RS and NA. There's small * description on it in NS section (RFC 2461 7.2.3). */ rt = nd6_lookup(from, 0, ifp); if (!rt) { #if 0 /* nothing must be done if there's no lladdr */ if (!lladdr || !lladdrlen) return NULL; #endif rt = nd6_lookup(from, 1, ifp); is_newentry = 1; } else is_newentry = 0; if (!rt) return NULL; if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) { fail: nd6_free(rt); return NULL; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; if (!ln) goto fail; if (!rt->rt_gateway) goto fail; if (rt->rt_gateway->sa_family != AF_LINK) goto fail; sdl = SDL(rt->rt_gateway); olladdr = (sdl->sdl_alen) ? 1 : 0; if (olladdr && lladdr) { if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen)) llchange = 1; else llchange = 0; } else llchange = 0; /* * newentry olladdr lladdr llchange (*=record) * 0 n n -- (1) * 0 y n -- (2) * 0 n y -- (3) * STALE * 0 y y n (4) * * 0 y y y (5) * STALE * 1 -- n -- (6) NOSTATE(= PASSIVE) * 1 -- y -- (7) * STALE */ if (lladdr) { /*(3-5) and (7)*/ /* * Record source link-layer address * XXX is it dependent to ifp->if_type? */ sdl->sdl_alen = ifp->if_addrlen; bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen); } if (!is_newentry) { if ((!olladdr && lladdr) /*(3)*/ || (olladdr && lladdr && llchange)) { /*(5)*/ do_update = 1; newstate = ND6_LLINFO_STALE; } else /*(1-2,4)*/ do_update = 0; } else { do_update = 1; if (!lladdr) /*(6)*/ newstate = ND6_LLINFO_NOSTATE; else /*(7)*/ newstate = ND6_LLINFO_STALE; } if (do_update) { /* * Update the state of the neighbor cache. */ ln->ln_state = newstate; if (ln->ln_state == ND6_LLINFO_STALE) { rt->rt_flags &= ~RTF_REJECT; if (ln->ln_hold) { (*ifp->if_output)(ifp, ln->ln_hold, rt_key(rt), rt); ln->ln_hold = 0; } } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { /* probe right away */ ln->ln_expire = time_second; } } /* * ICMP6 type dependent behavior. * * NS: clear IsRouter if new entry * RS: clear IsRouter * RA: set IsRouter if there's lladdr * redir: clear IsRouter if new entry * * RA case, (1): * The spec says that we must set IsRouter in the following cases: * - If lladdr exist, set IsRouter. This means (1-5). * - If it is old entry (!newentry), set IsRouter. This means (7). * So, based on the spec, in (1-5) and (7) cases we must set IsRouter. * A quetion arises for (1) case. (1) case has no lladdr in the * neighbor cache, this is similar to (6). * This case is rare but we figured that we MUST NOT set IsRouter. * * newentry olladdr lladdr llchange NS RS RA redir * 0 n n -- (1) c ? * 0 y n -- (2) c s * 0 n y -- (3) c s * 0 y y n (4) c s * 0 y y y (5) c s * 1 -- n -- (6) c c c * 1 -- y -- (7) c c s c * * (c=clear s=set) */ switch (type & 0xff) { case ND_NEIGHBOR_SOLICIT: case ND_REDIRECT: /* * New entry must have is_router flag cleared. */ if (is_newentry) /*(6-7)*/ ln->ln_router = 0; break; case ND_ROUTER_SOLICIT: /* * is_router flag must always be cleared. */ ln->ln_router = 0; break; case ND_ROUTER_ADVERT: /* * Mark an entry with lladdr as a router. */ if ((!is_newentry && (olladdr || lladdr)) /*(2-5)*/ || (is_newentry && lladdr)) { /*(7)*/ ln->ln_router = 1; } break; } return rt; } static void nd6_slowtimo(ignored_arg) void *ignored_arg; { int s = splnet(); register int i; register struct nd_ifinfo *nd6if; timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); for (i = 1; i < if_index + 1; i++) { nd6if = &nd_ifinfo[i]; if (nd6if->basereachable && /* already initialized */ (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) { /* * Since reachable time rarely changes by router * advertisements, we SHOULD insure that a new random * value gets recomputed at least once every few hours. * (RFC 2461, 6.3.4) */ nd6if->recalctm = nd6_recalc_reachtm_interval; nd6if->reachable = ND_COMPUTE_RTIME(nd6if->basereachable); } } splx(s); } #ifdef NEWIP6OUTPUT /* for experimental */ #define senderr(e) { error = (e); goto bad;} int nd6_output(ifp, m0, dst, rt0) register struct ifnet *ifp; struct mbuf *m0; struct sockaddr_in6 *dst; struct rtentry *rt0; { register struct mbuf *m = m0; register struct rtentry *rt = rt0; struct llinfo_nd6 *ln = NULL; int error = 0; if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) goto sendpkt; /* * XXX: we currently do not make neighbor cache on any interface * other than Ethernet and FDDI. */ if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_FDDI) goto sendpkt; /* * next hop determination. This routine is derived from ether_outpout. */ if (rt) { if ((rt->rt_flags & RTF_UP) == 0) { #ifdef __FreeBSD__ if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1, 0UL)) != NULL) { #else if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1)) != NULL) { #endif rt->rt_refcnt--; if (rt->rt_ifp != ifp) return nd6_output(ifp, m0, dst, rt); /* XXX: loop care? */ } else senderr(EHOSTUNREACH); } if (rt->rt_flags & RTF_GATEWAY) { if (rt->rt_gwroute == 0) goto lookup; if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { rtfree(rt); rt = rt0; #ifdef __FreeBSD__ lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL); #else lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); #endif if ((rt = rt->rt_gwroute) == 0) senderr(EHOSTUNREACH); #ifdef __bsdi__ /* the "G" test below also prevents rt == rt0 */ if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_ifp != ifp)) { rt->rt_refcnt--; rt0->rt_gwroute = 0; senderr(EHOSTUNREACH); } #endif } } if (rt->rt_flags & RTF_REJECT) senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); } /* * Address resolution or Neighbor Unreachability Detection * for the next hop. * At this point, the destination of the packet must be a unicast * or an anycast address(i.e. not a multicast). */ /* Look up the neighbor cache for the nexthop */ if (rt && (rt->rt_flags & RTF_LLINFO) != 0) ln = (struct llinfo_nd6 *)rt->rt_llinfo; else { if ((rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL) ln = (struct llinfo_nd6 *)rt->rt_llinfo; } if (!ln || !rt) { log(LOG_DEBUG, "nd6_output: can't allocate llinfo for %s " "(ln=%p, rt=%p)\n", ip6_sprintf(&dst->sin6_addr), ln, rt); senderr(EIO); /* XXX: good error? */ } /* * The first time we send a packet to a neighbor whose entry is * STALE, we have to change the state to DELAY and a sets a timer to * expire in DELAY_FIRST_PROBE_TIME seconds to ensure do * neighbor unreachability detection on expiration. * (RFC 2461 7.3.3) */ if (ln->ln_state == ND6_LLINFO_STALE) { ln->ln_asked = 0; ln->ln_state = ND6_LLINFO_DELAY; ln->ln_expire = time_second + nd6_delay; } /* * If the neighbor cache entry has a state other than INCOMPLETE * (i.e. its link-layer address is already reloved), just * send the packet. */ if (ln->ln_state > ND6_LLINFO_INCOMPLETE) goto sendpkt; /* * There is a neighbor cache entry, but no ethernet address * response yet. Replace the held mbuf (if any) with this * latest one. * * XXX Does the code conform to rate-limiting rule? * (RFC 2461 7.2.2) */ if (ln->ln_state == ND6_LLINFO_WAITDELETE || ln->ln_state == ND6_LLINFO_NOSTATE) ln->ln_state = ND6_LLINFO_INCOMPLETE; if (ln->ln_hold) m_freem(ln->ln_hold); ln->ln_hold = m; if (ln->ln_expire) { rt->rt_flags &= ~RTF_REJECT; if (ln->ln_asked < nd6_mmaxtries && ln->ln_expire < time_second) { ln->ln_asked++; ln->ln_expire = time_second + nd_ifinfo[ifp->if_index].retrans / 1000; nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); } } return(0); sendpkt: return((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt)); bad: if (m) m_freem(m); return (error); } #undef senderr int nd6_storelladdr(ifp, rt, m, dst, desten) struct ifnet *ifp; struct rtentry *rt; struct mbuf *m; struct sockaddr *dst; u_char *desten; { struct sockaddr_dl *sdl; if (m->m_flags & M_MCAST) { switch (ifp->if_type) { case IFT_ETHER: case IFT_FDDI: ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, desten); return(1); break; default: return(0); } } if (rt == NULL || rt->rt_gateway->sa_family != AF_LINK) { printf("nd6_storelladdr: something odd happens\n"); return(0); } sdl = SDL(rt->rt_gateway); if (sdl->sdl_alen != 0) bcopy(LLADDR(sdl), desten, sdl->sdl_alen); return(1); } #endif /* NEWIP6OUTPUT */ @ 1.1.2.2 log @KAME/NetBSD 1.4, SNAP kit 1999/07/05. NOTE: this branch is just for reference purposes (i.e. for taking cvs diff). do not touch anything on the branch. actual work must be done on HEAD branch. @ text @d376 1 a376 1 s = splsoftnet(); a620 54 * Detect if a given IPv6 address identifies a neighbor on a given link. * XXX: should take care of the destination of a p2p link? */ int nd6_is_addr_neighbor(addr, ifp) struct in6_addr *addr; struct ifnet *ifp; { register struct ifaddr *ifa; int i; #define IFADDR6(a) ((((struct in6_ifaddr *)(a))->ia_addr).sin6_addr) #define IFMASK6(a) ((((struct in6_ifaddr *)(a))->ia_prefixmask).sin6_addr) /* A link-local address is always a neighbor. */ if (IN6_IS_ADDR_LINKLOCAL(addr)) return(1); /* * If the address matches one of our addresses, * it should be a neighbor. */ #ifdef __bsdi__ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) #else for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) #endif { if (ifa->ifa_addr->sa_family != AF_INET6) next: continue; for (i = 0; i < 4; i++) { if ((IFADDR6(ifa).s6_addr32[i] ^ addr->s6_addr32[i]) & IFMASK6(ifa).s6_addr32[i]) goto next; } return(1); } /* * Even if the address matches none of our addresses, it might be * in the neighbor cache. */ if (nd6_lookup(addr, 0, ifp)) return(1); return(0); #undef IFADDR6 #undef IFMASK6 } /* d637 1 a637 1 s = splsoftnet(); d1034 1 a1034 1 s = splsoftnet(); d1059 1 a1059 1 s = splsoftnet(); d1119 1 a1119 1 s = splsoftnet(); d1134 1 a1134 1 s = splsoftnet(); d1153 1 a1153 1 s = splsoftnet(); d1364 1 a1364 1 int s = splsoftnet(); @ 1.1.2.3 log @bring in latest KAME (as of 19991130, KAME/NetBSD141) into kame branch just for reference purposes. This commit includes 1.4 -> 1.4.1 sync for kame branch. The branch does not compile at all (due to the lack of ALTQ and some other source code). Please do not try to modify the branch, this is just for referenre purposes. synchronization to latest KAME will take place on HEAD branch soon. @ text @d47 1 a47 1 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) a55 1 #if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) a56 1 #endif d73 1 a77 1 #include a79 1 #ifndef __bsdi__ a80 1 #endif a84 2 #include d88 4 a102 3 /* preventing too many loops in ND option parsing */ int nd6_maxndopt = 10; /* max # of ND options allowed */ d107 1 a107 1 struct nd_ifinfo *nd_ifinfo = NULL; a114 1 static struct sockaddr_in6 all1_sa; a121 1 int i; a126 6 all1_sa.sin6_family = AF_INET6; all1_sa.sin6_len = sizeof(struct sockaddr_in6); for (i = 0; i < sizeof(all1_sa.sin6_addr); i++) all1_sa.sin6_addr.s6_addr[i] = 0xff; a185 3 case IFT_ARCNET: /* XXX MTU handling needs more work */ ndi->maxmtu = MIN(60480, ifp->if_mtu); break; a190 3 #if defined(__bsdi__) && _BSDI_VERSION >= 199802 ndi->maxmtu = MIN(FDDIMTU, ifp->if_mtu); #else a191 1 #endif a193 1 #if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) a196 1 #endif d352 1 a352 2 if (i > nd6_maxndopt) { icmp6stat.icp6s_nd_toomanyopt++; a374 3 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec; #endif a375 1 #ifdef __NetBSD__ a376 3 #else s = splnet(); #endif d533 4 a607 7 /* * Validation for the entry. * XXX: we can't use rt->rt_ifp to check for the interface, since * it might be the loopback interface if the entry is for our * own address on a non-loopback interface. Instead, we should * use rt->rt_ifa->ifa_ifp, which would specify the REAL interface. */ d609 1 a609 2 rt->rt_gateway->sa_family != AF_LINK || (ifp && rt->rt_ifa->ifa_ifp != ifp)) { d611 2 a612 2 log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec"); d643 1 a643 1 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) a690 1 #ifdef __NetBSD__ a691 3 #else s = splnet(); #endif a729 3 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec; #endif a760 1 #ifdef OLDIP6OUTPUT a780 3 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec; #endif a789 4 case IFT_ARCNET: *desten = 0; return(1); break; a848 1 #endif /* OLDIP6OUTPUT */ a850 6 #if defined(__bsdi__) && _BSDI_VERSION >= 199802 nd6_rtrequest(req, rt, info) int req; struct rtentry *rt; struct rt_addrinfo *info; /* xxx unused */ #else a854 1 #endif a860 3 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec; #endif d946 1 a946 1 ln->ln_state = ND6_LLINFO_NOSTATE; a949 1 #if 0 a950 6 #else ln->ln_next = llinfo_nd6.ln_next; llinfo_nd6.ln_next = ln; ln->ln_prev = &llinfo_nd6; ln->ln_next->ln_prev = ln; #endif a967 4 #if _BSDI_VERSION >= 199802 extern struct ifnet *loifp; rt->rt_ifp = loifp; /*XXX*/ #else a969 1 #endif a994 1 #if 0 a995 5 #else ln->ln_next->ln_prev = ln->ln_prev; ln->ln_prev->ln_next = ln->ln_next; ln->ln_prev = NULL; #endif a1004 6 #if defined(__bsdi__) && _BSDI_VERSION >= 199802 nd6_p2p_rtrequest(req, rt, info) int req; struct rtentry *rt; struct rt_addrinfo *info; /* xxx unused */ #else a1008 1 #endif d1039 1 a1039 1 /* Announce a new entry if requested. */ a1056 4 #if _BSDI_VERSION >= 199802 extern struct ifnet *loifp; rt->rt_ifp = loifp; /*XXX*/ #else a1058 1 #endif a1087 1 #ifdef __NetBSD__ a1088 3 #else s = splnet(); #endif a1112 1 #ifdef __NetBSD__ a1113 3 #else s = splnet(); #endif a1153 19 { struct rr_prefix *rpp; for (rpp = LIST_FIRST(&rr_prefix); rpp; rpp = LIST_NEXT(rpp, rp_entry)) { if (i >= PRLSTSIZ) break; prl->prefix[i].prefix = rpp->rp_prefix.sin6_addr; prl->prefix[i].raflags = rpp->rp_raf; prl->prefix[i].prefixlen = rpp->rp_plen; prl->prefix[i].vltime = rpp->rp_vltime; prl->prefix[i].pltime = rpp->rp_pltime; prl->prefix[i].if_index = rpp->rp_ifp->if_index; prl->prefix[i].expire = rpp->rp_expire; prl->prefix[i].advrtrs = 0; i++; } } a1172 1 #ifdef __NetBSD__ a1173 3 #else s = splnet(); #endif a1187 1 #ifdef __NetBSD__ a1188 3 #else s = splnet(); #endif d1205 1 a1205 14 struct llinfo_nd6 *ln; struct in6_addr nb_addr = nbi->addr; /* make local for safety */ /* * XXX: KAME specific hack for scoped addresses * XXXX: for other scopes than link-local? */ if (IN6_IS_ADDR_LINKLOCAL(&nbi->addr) || IN6_IS_ADDR_MC_LINKLOCAL(&nbi->addr)) { u_int16_t *idp = (u_int16_t *)&nb_addr.s6_addr[2]; if (*idp == 0) *idp = htons(ifp->if_index); } d1207 13 a1219 17 #ifdef __NetBSD__ s = splsoftnet(); #else s = splnet(); #endif if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL) { error = EINVAL; break; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; nbi->state = ln->ln_state; nbi->asked = ln->ln_asked; nbi->isrouter = ln->ln_router; nbi->expire = ln->ln_expire; splx(s); break; d1230 1 a1230 1 nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code) a1235 1 int code; /* type dependent information */ a1244 3 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec; #endif a1346 1 #ifdef OLDIP6OUTPUT a1348 5 #else nd6_output(ifp, ln->ln_hold, (struct sockaddr_in6 *)rt_key(rt), rt); #endif d1375 7 a1381 8 * D R * 0 n n -- (1) c ? s * 0 y n -- (2) c s s * 0 n y -- (3) c s s * 0 y y n (4) c s s * 0 y y y (5) c s s * 1 -- n -- (6) c c c s * 1 -- y -- (7) c c s c s d1387 1 a1393 12 case ND_REDIRECT: /* * If the icmp is a redirect to a better router, always set the * is_router flag. Otherwise, if the entry is newly created, * clear the flag. [RFC 2461, sec 8.3] * */ if (code == ND_REDIRECT_ROUTER) ln->ln_router = 1; else if (is_newentry) /*(6-7)*/ ln->ln_router = 0; break; a1417 1 #ifdef __NetBSD__ a1418 3 #else int s = splnet(); #endif d1440 2 a1453 3 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec; #endif d1460 1 a1460 1 * other than ARCnet, Ethernet and FDDI. d1462 1 a1462 6 switch (ifp->if_type) { case IFT_ARCNET: case IFT_ETHER: case IFT_FDDI: break; default: a1463 1 } d1472 1 a1472 1 NULL) d1475 1 a1475 1 NULL) a1476 1 { a1606 3 case IFT_ARCNET: *desten = 0; return(1); d1623 1 @