summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2001-06-11 12:39:29 +0000
committerume <ume@FreeBSD.org>2001-06-11 12:39:29 +0000
commit832f8d224926758a9ae0b23a6b45353e44fbc87a (patch)
treea79fc7ad2b97862c4a404f352f0211ad93a7b5f1 /sys
parent2693854b01a52b0395a91322aa3edf926bddff38 (diff)
downloadFreeBSD-src-832f8d224926758a9ae0b23a6b45353e44fbc87a.zip
FreeBSD-src-832f8d224926758a9ae0b23a6b45353e44fbc87a.tar.gz
Sync with recent KAME.
This work was based on kame-20010528-freebsd43-snap.tgz and some critical problem after the snap was out were fixed. There are many many changes since last KAME merge. TODO: - The definitions of SADB_* in sys/net/pfkeyv2.h are still different from RFC2407/IANA assignment because of binary compatibility issue. It should be fixed under 5-CURRENT. - ip6po_m member of struct ip6_pktopts is no longer used. But, it is still there because of binary compatibility issue. It should be removed under 5-CURRENT. Reviewed by: itojun Obtained from: KAME MFC after: 3 weeks
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files13
-rw-r--r--sys/crypto/blowfish/bf_cbc.c151
-rw-r--r--sys/crypto/blowfish/bf_cbc_m.c343
-rw-r--r--sys/crypto/blowfish/bf_enc.c124
-rw-r--r--sys/crypto/blowfish/bf_locl.h62
-rw-r--r--sys/crypto/blowfish/bf_skey.c85
-rw-r--r--sys/crypto/blowfish/blowfish.h49
-rw-r--r--sys/crypto/cast128/cast128.c2
-rw-r--r--sys/crypto/cast128/cast128.h6
-rw-r--r--sys/crypto/cast128/cast128_cbc.c222
-rw-r--r--sys/crypto/des/des.h205
-rw-r--r--sys/crypto/des/des_3cbc.c250
-rw-r--r--sys/crypto/des/des_cbc.c331
-rw-r--r--sys/crypto/des/des_ecb.c4
-rw-r--r--sys/crypto/des/des_locl.h105
-rw-r--r--sys/crypto/des/des_setkey.c10
-rw-r--r--sys/crypto/md5.c2
-rw-r--r--sys/crypto/rc5/rc5.c219
-rw-r--r--sys/crypto/rc5/rc5_cbc.c215
-rw-r--r--sys/crypto/rijndael/boxes-fst.dat76
-rw-r--r--sys/crypto/rijndael/rijndael-alg-fst.c57
-rw-r--r--sys/crypto/rijndael/rijndael-alg-fst.h3
-rw-r--r--sys/crypto/rijndael/rijndael-api-fst.c52
-rw-r--r--sys/crypto/rijndael/rijndael-api-fst.h9
-rw-r--r--sys/crypto/rijndael/rijndael_local.h2
-rw-r--r--sys/crypto/sha1.c2
-rw-r--r--sys/crypto/sha2/sha2.c1048
-rw-r--r--sys/crypto/sha2/sha2.h141
-rw-r--r--sys/kern/uipc_domain.c26
-rw-r--r--sys/kern/uipc_mbuf.c9
-rw-r--r--sys/kern/uipc_mbuf2.c146
-rw-r--r--sys/net/if.c21
-rw-r--r--sys/net/if_faith.c241
-rw-r--r--sys/net/if_faith.h41
-rw-r--r--sys/net/if_gif.c184
-rw-r--r--sys/net/if_gif.h4
-rw-r--r--sys/net/if_loop.c29
-rw-r--r--sys/net/if_sppp.h14
-rw-r--r--sys/net/if_spppsubr.c795
-rw-r--r--sys/net/if_stf.c93
-rw-r--r--sys/net/net_osdep.c16
-rw-r--r--sys/net/net_osdep.h111
-rw-r--r--sys/net/pfkeyv2.h46
-rw-r--r--sys/net/ppp_defs.h2
-rw-r--r--sys/net/rtsock.c15
-rw-r--r--sys/netinet/icmp6.h117
-rw-r--r--sys/netinet/in.c23
-rw-r--r--sys/netinet/in_gif.c61
-rw-r--r--sys/netinet/in_pcb.c17
-rw-r--r--sys/netinet/in_pcb.h32
-rw-r--r--sys/netinet/in_proto.c27
-rw-r--r--sys/netinet/ip6.h36
-rw-r--r--sys/netinet/ip_ecn.c21
-rw-r--r--sys/netinet/ip_ecn.h10
-rw-r--r--sys/netinet/ip_encap.c14
-rw-r--r--sys/netinet/ip_icmp.c9
-rw-r--r--sys/netinet/ip_input.c66
-rw-r--r--sys/netinet/ip_output.c313
-rw-r--r--sys/netinet/ip_var.h4
-rw-r--r--sys/netinet/raw_ip.c29
-rw-r--r--sys/netinet/tcp_input.c109
-rw-r--r--sys/netinet/tcp_output.c8
-rw-r--r--sys/netinet/tcp_reass.c109
-rw-r--r--sys/netinet/tcp_subr.c65
-rw-r--r--sys/netinet/tcp_timewait.c65
-rw-r--r--sys/netinet/tcp_usrreq.c13
-rw-r--r--sys/netinet/udp_usrreq.c8
-rw-r--r--sys/netinet6/ah.h14
-rw-r--r--sys/netinet6/ah6.h6
-rw-r--r--sys/netinet6/ah_core.c547
-rw-r--r--sys/netinet6/ah_input.c204
-rw-r--r--sys/netinet6/ah_output.c42
-rw-r--r--sys/netinet6/dest6.c27
-rw-r--r--sys/netinet6/esp.h34
-rw-r--r--sys/netinet6/esp6.h4
-rw-r--r--sys/netinet6/esp_core.c1581
-rw-r--r--sys/netinet6/esp_input.c264
-rw-r--r--sys/netinet6/esp_output.c184
-rw-r--r--sys/netinet6/esp_rijndael.c116
-rw-r--r--sys/netinet6/esp_rijndael.h (renamed from sys/crypto/rc5/rc5.h)64
-rw-r--r--sys/netinet6/frag6.c27
-rw-r--r--sys/netinet6/icmp6.c1041
-rw-r--r--sys/netinet6/in6.c1527
-rw-r--r--sys/netinet6/in6.h183
-rw-r--r--sys/netinet6/in6_cksum.c10
-rw-r--r--sys/netinet6/in6_gif.c73
-rw-r--r--sys/netinet6/in6_ifattach.c750
-rw-r--r--sys/netinet6/in6_ifattach.h5
-rw-r--r--sys/netinet6/in6_pcb.c145
-rw-r--r--sys/netinet6/in6_pcb.h9
-rw-r--r--sys/netinet6/in6_prefix.c45
-rw-r--r--sys/netinet6/in6_prefix.h5
-rw-r--r--sys/netinet6/in6_proto.c240
-rw-r--r--sys/netinet6/in6_rmx.c19
-rw-r--r--sys/netinet6/in6_src.c37
-rw-r--r--sys/netinet6/in6_var.h44
-rw-r--r--sys/netinet6/ip6_ecn.h4
-rw-r--r--sys/netinet6/ip6_forward.c91
-rw-r--r--sys/netinet6/ip6_fw.c15
-rw-r--r--sys/netinet6/ip6_fw.h2
-rw-r--r--sys/netinet6/ip6_input.c833
-rw-r--r--sys/netinet6/ip6_mroute.c246
-rw-r--r--sys/netinet6/ip6_mroute.h6
-rw-r--r--sys/netinet6/ip6_output.c800
-rw-r--r--sys/netinet6/ip6_var.h88
-rw-r--r--sys/netinet6/ip6protosw.h24
-rw-r--r--sys/netinet6/ipcomp.h8
-rw-r--r--sys/netinet6/ipcomp6.h2
-rw-r--r--sys/netinet6/ipcomp_core.c220
-rw-r--r--sys/netinet6/ipcomp_input.c160
-rw-r--r--sys/netinet6/ipcomp_output.c126
-rw-r--r--sys/netinet6/ipsec.c1004
-rw-r--r--sys/netinet6/ipsec.h49
-rw-r--r--sys/netinet6/ipsec6.h7
-rw-r--r--sys/netinet6/mld6.c59
-rw-r--r--sys/netinet6/nd6.c832
-rw-r--r--sys/netinet6/nd6.h105
-rw-r--r--sys/netinet6/nd6_nbr.c250
-rw-r--r--sys/netinet6/nd6_rtr.c1431
-rw-r--r--sys/netinet6/raw_ip6.c108
-rw-r--r--sys/netinet6/raw_ip6.h54
-rw-r--r--sys/netinet6/route6.c26
-rw-r--r--sys/netinet6/scope6.c3
-rw-r--r--sys/netinet6/udp6_output.c67
-rw-r--r--sys/netinet6/udp6_usrreq.c90
-rw-r--r--sys/netkey/key.c975
-rw-r--r--sys/netkey/key.h7
-rw-r--r--sys/netkey/key_debug.c7
-rw-r--r--sys/netkey/key_debug.h9
-rw-r--r--sys/netkey/key_var.h39
-rw-r--r--sys/netkey/keydb.h13
-rw-r--r--sys/netkey/keysock.c19
-rw-r--r--sys/netsmb/smb_crypt.c4
-rw-r--r--sys/sys/mbuf.h25
-rw-r--r--sys/sys/protosw.h2
-rw-r--r--sys/sys/socket.h26
-rw-r--r--sys/sys/sockio.h2
137 files changed, 13173 insertions, 8649 deletions
diff --git a/sys/conf/files b/sys/conf/files
index cb6a4a2..d39e829 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -163,19 +163,15 @@ contrib/ipfilter/netinet/ip_nat.c optional ipfilter inet
contrib/ipfilter/netinet/ip_proxy.c optional ipfilter inet
contrib/ipfilter/netinet/ip_state.c optional ipfilter inet
contrib/ipfilter/netinet/mlfk_ipl.c optional ipfilter inet
-crypto/blowfish/bf_cbc.c optional ipsec ipsec_esp
-crypto/blowfish/bf_cbc_m.c optional ipsec ipsec_esp
crypto/blowfish/bf_enc.c optional ipsec ipsec_esp
crypto/blowfish/bf_skey.c optional ipsec ipsec_esp
crypto/cast128/cast128.c optional ipsec ipsec_esp
-crypto/cast128/cast128_cbc.c optional ipsec ipsec_esp
-crypto/des/des_3cbc.c optional ipsec ipsec_esp
-crypto/des/des_cbc.c optional ipsec ipsec_esp
crypto/des/des_ecb.c optional ipsec ipsec_esp
crypto/des/des_setkey.c optional ipsec ipsec_esp
-crypto/rc5/rc5.c optional ipsec ipsec_esp
-crypto/rc5/rc5_cbc.c optional ipsec ipsec_esp
+crypto/rijndael/rijndael-alg-fst.c optional ipsec ipsec_esp
+crypto/rijndael/rijndael-api-fst.c optional ipsec ipsec_esp
crypto/sha1.c optional ipsec
+crypto/sha2/sha2.c optional ipsec
ddb/db_access.c optional ddb
ddb/db_break.c optional ddb
ddb/db_command.c optional ddb
@@ -1083,6 +1079,7 @@ netinet6/dest6.c optional inet6
netinet6/esp_core.c optional ipsec ipsec_esp
netinet6/esp_input.c optional ipsec ipsec_esp
netinet6/esp_output.c optional ipsec ipsec_esp
+netinet6/esp_rijndael.c optional ipsec ipsec_esp
netinet6/frag6.c optional inet6
netinet6/icmp6.c optional inet6
netinet6/in6.c optional inet6
@@ -1124,8 +1121,8 @@ netipx/ipx_usrreq.c optional ipx
netipx/spx_debug.c optional ipx
netipx/spx_usrreq.c optional ipx
netkey/key.c optional ipsec
-netkey/keydb.c optional ipsec
netkey/key_debug.c optional ipsec
+netkey/keydb.c optional ipsec
netkey/keysock.c optional ipsec
netnatm/natm.c optional natm
netnatm/natm_pcb.c optional natm
diff --git a/sys/crypto/blowfish/bf_cbc.c b/sys/crypto/blowfish/bf_cbc.c
deleted file mode 100644
index 6eb6d3b..0000000
--- a/sys/crypto/blowfish/bf_cbc.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: bf_cbc.c,v 1.3 2000/03/27 04:36:25 sumikawa Exp $ */
-
-/* crypto/bf/bf_cbc.c */
-/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@mincom.oz.au).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@mincom.oz.au).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@mincom.oz.au)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <crypto/blowfish/blowfish.h>
-#include <crypto/blowfish/bf_locl.h>
-
-void BF_cbc_encrypt(in, out, length, ks, iv, encrypt)
-unsigned char *in;
-unsigned char *out;
-long length;
-BF_KEY *ks;
-unsigned char *iv;
-int encrypt;
- {
- register BF_LONG tin0,tin1;
- register BF_LONG tout0,tout1,xor0,xor1;
- register long l=length;
- BF_LONG tin[2];
-
- if (encrypt)
- {
- n2l(iv,tout0);
- n2l(iv,tout1);
- iv-=8;
- for (l-=8; l>=0; l-=8)
- {
- n2l(in,tin0);
- n2l(in,tin1);
- tin0^=tout0;
- tin1^=tout1;
- tin[0]=tin0;
- tin[1]=tin1;
- BF_encrypt(tin,ks,BF_ENCRYPT);
- tout0=tin[0];
- tout1=tin[1];
- l2n(tout0,out);
- l2n(tout1,out);
- }
- if (l != -8)
- {
- n2ln(in,tin0,tin1,l+8);
- tin0^=tout0;
- tin1^=tout1;
- tin[0]=tin0;
- tin[1]=tin1;
- BF_encrypt(tin,ks,BF_ENCRYPT);
- tout0=tin[0];
- tout1=tin[1];
- l2n(tout0,out);
- l2n(tout1,out);
- }
- l2n(tout0,iv);
- l2n(tout1,iv);
- }
- else
- {
- n2l(iv,xor0);
- n2l(iv,xor1);
- iv-=8;
- for (l-=8; l>=0; l-=8)
- {
- n2l(in,tin0);
- n2l(in,tin1);
- tin[0]=tin0;
- tin[1]=tin1;
- BF_encrypt(tin,ks,BF_DECRYPT);
- tout0=tin[0]^xor0;
- tout1=tin[1]^xor1;
- l2n(tout0,out);
- l2n(tout1,out);
- xor0=tin0;
- xor1=tin1;
- }
- if (l != -8)
- {
- n2l(in,tin0);
- n2l(in,tin1);
- tin[0]=tin0;
- tin[1]=tin1;
- BF_encrypt(tin,ks,BF_DECRYPT);
- tout0=tin[0]^xor0;
- tout1=tin[1]^xor1;
- l2nn(tout0,tout1,out,l+8);
- xor0=tin0;
- xor1=tin1;
- }
- l2n(xor0,iv);
- l2n(xor1,iv);
- }
- tin0=tin1=tout0=tout1=xor0=xor1=0;
- tin[0]=tin[1]=0;
- }
-
diff --git a/sys/crypto/blowfish/bf_cbc_m.c b/sys/crypto/blowfish/bf_cbc_m.c
deleted file mode 100644
index 088adad..0000000
--- a/sys/crypto/blowfish/bf_cbc_m.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: bf_cbc_m.c,v 1.4 2000/06/14 10:41:16 itojun Exp $ */
-
-/*
- * heavily modified to accept mbuf, by Jun-ichiro itojun Itoh
- * <itojun@itojun.org>, 1997.
- */
-/* crypto/bf/bf_cbc.c */
-/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@mincom.oz.au).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@mincom.oz.au).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@mincom.oz.au)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <sys/param.h>
-#include <sys/mbuf.h>
-#include <sys/systm.h>
-
-#include <crypto/blowfish/blowfish.h>
-#include <crypto/blowfish/bf_locl.h>
-
-#define panic(x) do { printf(x); return EINVAL; } while (0)
-
-int BF_cbc_encrypt_m(m0, skip, length, key, iv, mode)
- struct mbuf *m0;
- int skip;
- int length;
- BF_KEY *key;
- unsigned char *iv;
- int mode;
-{
- u_int8_t inbuf[8], outbuf[8];
- struct mbuf *m;
- size_t off;
- register BF_LONG tin0, tin1;
- register BF_LONG tout0, tout1;
- BF_LONG tin[2];
-
- /* sanity checks */
- if (m0->m_pkthdr.len < skip) {
- printf("mbuf length < skip\n");
- return EINVAL;
- }
- if (m0->m_pkthdr.len < length) {
- printf("mbuf length < encrypt length\n");
- return EINVAL;
- }
- if (m0->m_pkthdr.len < skip + length) {
- printf("mbuf length < skip + encrypt length\n");
- return EINVAL;
- }
- if (length % 8) {
- printf("length is not multiple of 8\n");
- return EINVAL;
- }
-
- m = m0;
- off = 0;
-
- /* skip over the header */
- while (skip) {
- if (!m)
- panic("mbuf chain?\n");
- if (m->m_len <= skip) {
- skip -= m->m_len;
- m = m->m_next;
- off = 0;
- } else {
- off = skip;
- skip = 0;
- }
- }
-
- /* initialize */
- tin0 = tin1 = tout0 = tout1 = 0;
- tin[0] = tin[1] = 0;
-
- if (mode == BF_ENCRYPT) {
- u_int8_t *in, *out;
-
- n2l(iv, tout0);
- n2l(iv, tout1);
-
- while (0 < length) {
- if (!m)
- panic("mbuf chain?\n");
-
- /*
- * copy the source into input buffer.
- * don't update off or m, since we need to use them * later.
- */
- if (off + 8 <= m->m_len)
- bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8);
- else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p;
- u_int8_t *in;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- in = &inbuf[0];
- while (in - &inbuf[0] < 8) {
- if (!p)
- panic("mbuf chain?\n");
-
- *in++ = *p++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && ! n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *) + noff;
- else
- p = NULL;
- }
- }
-
- in = &inbuf[0];
- out = &outbuf[0];
- n2l(in, tin0);
- n2l(in, tin1);
-
- tin0 ^= tout0; tin[0] = tin0;
- tin1 ^= tout1; tin[1] = tin1;
- BF_encrypt(tin, key, BF_ENCRYPT);
- tout0 = tin[0]; l2n(tout0, out);
- tout1 = tin[1]; l2n(tout1, out);
-
- /*
- * copy the output buffer into the result.
- * need to update off and m.
- */
- if (off + 8 < m->m_len) {
- bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8);
- off += 8;
- } else if (off + 8 == m->m_len) {
- bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8);
- do {
- m = m->m_next;
- } while (m && ! m->m_len);
- off = 0;
- } else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p;
- u_int8_t *out;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- out = &outbuf[0];
- while (out - &outbuf[0] < 8) {
- if (!p)
- panic("mbuf chain?");
- *p++ = *out++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && ! n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *) + noff;
- else
- p = NULL;
- }
-
- m = n;
- off = noff;
- }
-
- length -= 8;
- }
- } else if (mode == BF_DECRYPT) {
- register BF_LONG xor0, xor1;
- u_int8_t *in, *out;
-
- xor0 = xor1 = 0;
- n2l(iv, xor0);
- n2l(iv, xor1);
-
- while (0 < length) {
- if (!m)
- panic("mbuf chain?\n");
-
- /*
- * copy the source into input buffer.
- * don't update off or m, since we need to use them * later.
- */
- if (off + 8 <= m->m_len)
- bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8);
- else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p;
- u_int8_t *in;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- in = &inbuf[0];
- while (in - &inbuf[0] < 8) {
- if (!p)
- panic("mbuf chain?\n");
- *in++ = *p++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && ! n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *) + noff;
- else
- p = NULL;
- }
- }
-
- in = &inbuf[0];
- out = &outbuf[0];
- n2l(in, tin0); tin[0] = tin0;
- n2l(in, tin1); tin[1] = tin1;
- BF_encrypt(tin, key, BF_DECRYPT);
- tout0 = tin[0] ^ xor0;
- tout1 = tin[1] ^ xor1;
- l2n(tout0, out);
- l2n(tout1, out);
- xor0 = tin0;
- xor1 = tin1;
-
-
- /*
- * copy the output buffer into the result.
- * need to update off and m.
- */
- if (off + 8 < m->m_len) {
- bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8);
- off += 8;
- } else if (off + 8 == m->m_len) {
- bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8);
- do {
- m = m->m_next;
- } while (m && ! m->m_len);
- off = 0;
- } else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p;
- u_int8_t *out;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- out = &outbuf[0];
- while (out - &outbuf[0] < 8) {
- if (!p)
- panic("mbuf chain?\n");
- *p++ = *out++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && ! n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *) + noff;
- else
- p = NULL;
- }
-
- m = n;
- off = noff;
- }
-
- length -= 8;
- }
- }
-
- return 0;
-}
diff --git a/sys/crypto/blowfish/bf_enc.c b/sys/crypto/blowfish/bf_enc.c
index 6a3bef6..5edd6db 100644
--- a/sys/crypto/blowfish/bf_enc.c
+++ b/sys/crypto/blowfish/bf_enc.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: bf_enc.c,v 1.3 2000/03/27 04:36:26 sumikawa Exp $ */
+/* $KAME: bf_enc.c,v 1.5 2000/09/18 21:21:19 itojun Exp $ */
/* crypto/bf/bf_enc.c */
/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
@@ -59,6 +59,7 @@
* [including the GNU Public Licence.]
*/
+#include <sys/types.h>
#include <crypto/blowfish/blowfish.h>
#include <crypto/blowfish/bf_locl.h>
@@ -72,72 +73,71 @@ If you set BF_ROUNDS to some value other than 16 or 20, you will have
to modify the code.
#endif
-void BF_encrypt(data,key,encrypt)
-BF_LONG *data;
-BF_KEY *key;
-int encrypt;
- {
- register BF_LONG l,r,*p,*s;
+/* XXX "data" is host endian */
+void
+BF_encrypt(data, key, encrypt)
+ BF_LONG *data;
+ BF_KEY *key;
+ int encrypt;
+{
+ register BF_LONG l, r, *p, *s;
- p=key->P;
- s= &(key->S[0]);
- l=data[0];
- r=data[1];
+ p = key->P;
+ s= &key->S[0];
+ l = data[0];
+ r = data[1];
- if (encrypt)
- {
+ if (encrypt) {
l^=p[0];
- BF_ENC(r,l,s,p[ 1]);
- BF_ENC(l,r,s,p[ 2]);
- BF_ENC(r,l,s,p[ 3]);
- BF_ENC(l,r,s,p[ 4]);
- BF_ENC(r,l,s,p[ 5]);
- BF_ENC(l,r,s,p[ 6]);
- BF_ENC(r,l,s,p[ 7]);
- BF_ENC(l,r,s,p[ 8]);
- BF_ENC(r,l,s,p[ 9]);
- BF_ENC(l,r,s,p[10]);
- BF_ENC(r,l,s,p[11]);
- BF_ENC(l,r,s,p[12]);
- BF_ENC(r,l,s,p[13]);
- BF_ENC(l,r,s,p[14]);
- BF_ENC(r,l,s,p[15]);
- BF_ENC(l,r,s,p[16]);
+ BF_ENC(r, l, s, p[ 1]);
+ BF_ENC(l, r, s, p[ 2]);
+ BF_ENC(r, l, s, p[ 3]);
+ BF_ENC(l, r, s, p[ 4]);
+ BF_ENC(r, l, s, p[ 5]);
+ BF_ENC(l, r, s, p[ 6]);
+ BF_ENC(r, l, s, p[ 7]);
+ BF_ENC(l, r, s, p[ 8]);
+ BF_ENC(r, l, s, p[ 9]);
+ BF_ENC(l, r, s, p[10]);
+ BF_ENC(r, l, s, p[11]);
+ BF_ENC(l, r, s, p[12]);
+ BF_ENC(r, l, s, p[13]);
+ BF_ENC(l, r, s, p[14]);
+ BF_ENC(r, l, s, p[15]);
+ BF_ENC(l, r, s, p[16]);
#if BF_ROUNDS == 20
- BF_ENC(r,l,s,p[17]);
- BF_ENC(l,r,s,p[18]);
- BF_ENC(r,l,s,p[19]);
- BF_ENC(l,r,s,p[20]);
+ BF_ENC(r, l, s, p[17]);
+ BF_ENC(l, r, s, p[18]);
+ BF_ENC(r, l, s, p[19]);
+ BF_ENC(l, r, s, p[20]);
#endif
- r^=p[BF_ROUNDS+1];
- }
- else
- {
- l^=p[BF_ROUNDS+1];
+ r ^= p[BF_ROUNDS + 1];
+ } else {
+ l ^= p[BF_ROUNDS + 1];
#if BF_ROUNDS == 20
- BF_ENC(r,l,s,p[20]);
- BF_ENC(l,r,s,p[19]);
- BF_ENC(r,l,s,p[18]);
- BF_ENC(l,r,s,p[17]);
+ BF_ENC(r, l, s, p[20]);
+ BF_ENC(l, r, s, p[19]);
+ BF_ENC(r, l, s, p[18]);
+ BF_ENC(l, r, s, p[17]);
#endif
- BF_ENC(r,l,s,p[16]);
- BF_ENC(l,r,s,p[15]);
- BF_ENC(r,l,s,p[14]);
- BF_ENC(l,r,s,p[13]);
- BF_ENC(r,l,s,p[12]);
- BF_ENC(l,r,s,p[11]);
- BF_ENC(r,l,s,p[10]);
- BF_ENC(l,r,s,p[ 9]);
- BF_ENC(r,l,s,p[ 8]);
- BF_ENC(l,r,s,p[ 7]);
- BF_ENC(r,l,s,p[ 6]);
- BF_ENC(l,r,s,p[ 5]);
- BF_ENC(r,l,s,p[ 4]);
- BF_ENC(l,r,s,p[ 3]);
- BF_ENC(r,l,s,p[ 2]);
- BF_ENC(l,r,s,p[ 1]);
- r^=p[0];
- }
- data[1]=l&0xffffffff;
- data[0]=r&0xffffffff;
+ BF_ENC(r, l, s, p[16]);
+ BF_ENC(l, r, s, p[15]);
+ BF_ENC(r, l, s, p[14]);
+ BF_ENC(l, r, s, p[13]);
+ BF_ENC(r, l, s, p[12]);
+ BF_ENC(l, r, s, p[11]);
+ BF_ENC(r, l, s, p[10]);
+ BF_ENC(l, r, s, p[ 9]);
+ BF_ENC(r, l, s, p[ 8]);
+ BF_ENC(l, r, s, p[ 7]);
+ BF_ENC(r, l, s, p[ 6]);
+ BF_ENC(l, r, s, p[ 5]);
+ BF_ENC(r, l, s, p[ 4]);
+ BF_ENC(l, r, s, p[ 3]);
+ BF_ENC(r, l, s, p[ 2]);
+ BF_ENC(l, r, s, p[ 1]);
+ r ^= p[0];
}
+ data[1] = l & 0xffffffff;
+ data[0] = r & 0xffffffff;
+}
diff --git a/sys/crypto/blowfish/bf_locl.h b/sys/crypto/blowfish/bf_locl.h
index 07598d2..52585bb 100644
--- a/sys/crypto/blowfish/bf_locl.h
+++ b/sys/crypto/blowfish/bf_locl.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: bf_locl.h,v 1.3 2000/03/27 04:36:26 sumikawa Exp $ */
+/* $KAME: bf_locl.h,v 1.5 2000/08/31 06:03:48 itojun Exp $ */
/* crypto/bf/bf_local.h */
/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
@@ -67,10 +67,10 @@
*/
#undef c2l
-#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \
- l|=((unsigned long)(*((c)++)))<< 8L, \
- l|=((unsigned long)(*((c)++)))<<16L, \
- l|=((unsigned long)(*((c)++)))<<24L)
+#define c2l(c,l) (l =((BF_LONG)(*((c)++))) , \
+ l|=((BF_LONG)(*((c)++)))<< 8L, \
+ l|=((BF_LONG)(*((c)++)))<<16L, \
+ l|=((BF_LONG)(*((c)++)))<<24L)
/* NOTE - c is not incremented as per c2l */
#undef c2ln
@@ -78,14 +78,14 @@
c+=n; \
l1=l2=0; \
switch (n) { \
- case 8: l2 =((unsigned long)(*(--(c))))<<24L; \
- case 7: l2|=((unsigned long)(*(--(c))))<<16L; \
- case 6: l2|=((unsigned long)(*(--(c))))<< 8L; \
- case 5: l2|=((unsigned long)(*(--(c)))); \
- case 4: l1 =((unsigned long)(*(--(c))))<<24L; \
- case 3: l1|=((unsigned long)(*(--(c))))<<16L; \
- case 2: l1|=((unsigned long)(*(--(c))))<< 8L; \
- case 1: l1|=((unsigned long)(*(--(c)))); \
+ case 8: l2 =((BF_LONG)(*(--(c))))<<24L; \
+ case 7: l2|=((BF_LONG)(*(--(c))))<<16L; \
+ case 6: l2|=((BF_LONG)(*(--(c))))<< 8L; \
+ case 5: l2|=((BF_LONG)(*(--(c)))); \
+ case 4: l1 =((BF_LONG)(*(--(c))))<<24L; \
+ case 3: l1|=((BF_LONG)(*(--(c))))<<16L; \
+ case 2: l1|=((BF_LONG)(*(--(c))))<< 8L; \
+ case 1: l1|=((BF_LONG)(*(--(c)))); \
} \
}
@@ -116,14 +116,14 @@
c+=n; \
l1=l2=0; \
switch (n) { \
- case 8: l2 =((unsigned long)(*(--(c)))) ; \
- case 7: l2|=((unsigned long)(*(--(c))))<< 8; \
- case 6: l2|=((unsigned long)(*(--(c))))<<16; \
- case 5: l2|=((unsigned long)(*(--(c))))<<24; \
- case 4: l1 =((unsigned long)(*(--(c)))) ; \
- case 3: l1|=((unsigned long)(*(--(c))))<< 8; \
- case 2: l1|=((unsigned long)(*(--(c))))<<16; \
- case 1: l1|=((unsigned long)(*(--(c))))<<24; \
+ case 8: l2 =((BF_LONG)(*(--(c)))) ; \
+ case 7: l2|=((BF_LONG)(*(--(c))))<< 8; \
+ case 6: l2|=((BF_LONG)(*(--(c))))<<16; \
+ case 5: l2|=((BF_LONG)(*(--(c))))<<24; \
+ case 4: l1 =((BF_LONG)(*(--(c)))) ; \
+ case 3: l1|=((BF_LONG)(*(--(c))))<< 8; \
+ case 2: l1|=((BF_LONG)(*(--(c))))<<16; \
+ case 1: l1|=((BF_LONG)(*(--(c))))<<24; \
} \
}
@@ -143,10 +143,10 @@
}
#undef n2l
-#define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24L, \
- l|=((unsigned long)(*((c)++)))<<16L, \
- l|=((unsigned long)(*((c)++)))<< 8L, \
- l|=((unsigned long)(*((c)++))))
+#define n2l(c,l) (l =((BF_LONG)(*((c)++)))<<24L, \
+ l|=((BF_LONG)(*((c)++)))<<16L, \
+ l|=((BF_LONG)(*((c)++)))<< 8L, \
+ l|=((BF_LONG)(*((c)++))))
#undef l2n
#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
@@ -161,9 +161,17 @@
* BF_PTR for sparc and MIPS/SGI
* use nothing for Alpha and HP.
*/
-#if !defined(BF_PTR) && !defined(BF_PTR2)
-#undef BF_PTR
+#undef BF_PTR
+#undef BF_PTR2
+#ifdef __NetBSD__
+#ifdef __i386__
+#define BF_PTR2
+#else
+#ifdef __mips__
+#define BF_PTR
+#endif
#endif
+#endif /*NetBSD*/
#define BF_M 0x3fc
#define BF_0 22L
diff --git a/sys/crypto/blowfish/bf_skey.c b/sys/crypto/blowfish/bf_skey.c
index 5717c3f..4bbe036 100644
--- a/sys/crypto/blowfish/bf_skey.c
+++ b/sys/crypto/blowfish/bf_skey.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: bf_skey.c,v 1.3 2000/03/27 04:36:27 sumikawa Exp $ */
+/* $KAME: bf_skey.c,v 1.5 2000/11/06 13:58:08 itojun Exp $ */
/* crypto/bf/bf_skey.c */
/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
@@ -66,58 +66,55 @@
#include <crypto/blowfish/bf_locl.h>
#include <crypto/blowfish/bf_pi.h>
-void BF_set_key(key,len,data)
-BF_KEY *key;
-int len;
-unsigned char *data;
- {
+void
+BF_set_key(key, len, data)
+ BF_KEY *key;
+ int len;
+ unsigned char *data;
+{
int i;
- BF_LONG *p,ri,in[2];
- unsigned char *d,*end;
+ BF_LONG *p, ri, in[2];
+ unsigned char *d, *end;
+ memcpy((char *)key, (char *)&bf_init, sizeof(BF_KEY));
+ p = key->P;
- memcpy((char *)key,(char *)&bf_init,sizeof(BF_KEY));
- p=key->P;
+ if (len > ((BF_ROUNDS + 2) * 4))
+ len = (BF_ROUNDS + 2) * 4;
- if (len > ((BF_ROUNDS+2)*4)) len=(BF_ROUNDS+2)*4;
-
- d=data;
+ d = data;
end= &(data[len]);
- for (i=0; i<(BF_ROUNDS+2); i++)
- {
- ri= *(d++);
- if (d >= end) d=data;
-
- ri<<=8;
- ri|= *(d++);
- if (d >= end) d=data;
+ for (i = 0; i < BF_ROUNDS + 2; i++) {
+ ri = *(d++);
+ if (d >= end) d = data;
- ri<<=8;
- ri|= *(d++);
- if (d >= end) d=data;
+ ri <<= 8;
+ ri |= *(d++);
+ if (d >= end) d = data;
- ri<<=8;
- ri|= *(d++);
- if (d >= end) d=data;
+ ri <<= 8;
+ ri |= *(d++);
+ if (d >= end) d = data;
- p[i]^=ri;
- }
+ ri <<= 8;
+ ri |= *(d++);
+ if (d >= end) d = data;
- in[0]=0L;
- in[1]=0L;
- for (i=0; i<(BF_ROUNDS+2); i+=2)
- {
- BF_encrypt(in,key,BF_ENCRYPT);
- p[i ]=in[0];
- p[i+1]=in[1];
- }
+ p[i] ^= ri;
+ }
- p=key->S;
- for (i=0; i<4*256; i+=2)
- {
- BF_encrypt(in,key,BF_ENCRYPT);
- p[i ]=in[0];
- p[i+1]=in[1];
- }
+ in[0] = 0L;
+ in[1] = 0L;
+ for (i = 0; i < BF_ROUNDS + 2; i += 2) {
+ BF_encrypt(in, key, BF_ENCRYPT);
+ p[i ] = in[0];
+ p[i+1] = in[1];
}
+ p = key->S;
+ for (i = 0; i < 4 * 256; i += 2) {
+ BF_encrypt(in, key, BF_ENCRYPT);
+ p[i ] = in[0];
+ p[i+1] = in[1];
+ }
+}
diff --git a/sys/crypto/blowfish/blowfish.h b/sys/crypto/blowfish/blowfish.h
index c96b4ec..76605f8 100644
--- a/sys/crypto/blowfish/blowfish.h
+++ b/sys/crypto/blowfish/blowfish.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: blowfish.h,v 1.4 2000/06/14 10:41:16 itojun Exp $ */
+/* $KAME: blowfish.h,v 1.10 2000/09/18 21:21:20 itojun Exp $ */
/* crypto/bf/blowfish.h */
/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
@@ -69,54 +69,19 @@ extern "C" {
#define BF_ENCRYPT 1
#define BF_DECRYPT 0
-/* If you make this 'unsigned int' the pointer variants will work on
- * the Alpha, otherwise they will not. Strangly using the '8 byte'
- * BF_LONG and the default 'non-pointer' inner loop is the best configuration
- * for the Alpha */
-#define BF_LONG unsigned long
+/* must be 32bit quantity */
+#define BF_LONG u_int32_t
#define BF_ROUNDS 16
#define BF_BLOCK 8
-typedef struct bf_key_st
- {
+typedef struct bf_key_st {
BF_LONG P[BF_ROUNDS+2];
BF_LONG S[4*256];
- } BF_KEY;
-
-#ifndef NOPROTO
-
-void BF_set_key(BF_KEY *key, int len, unsigned char *data);
-void BF_ecb_encrypt(unsigned char *in,unsigned char *out,BF_KEY *key,
- int encrypt);
-void BF_encrypt(BF_LONG *data,BF_KEY *key,int encrypt);
-void BF_cbc_encrypt(unsigned char *in, unsigned char *out, long length,
- BF_KEY *ks, unsigned char *iv, int encrypt);
-void BF_cfb64_encrypt(unsigned char *in, unsigned char *out, long length,
- BF_KEY *schedule, unsigned char *ivec, int *num, int encrypt);
-void BF_ofb64_encrypt(unsigned char *in, unsigned char *out, long length,
- BF_KEY *schedule, unsigned char *ivec, int *num);
-char *BF_options(void);
-
-/* added by itojun */
-struct mbuf;
-int BF_cbc_encrypt_m(struct mbuf *, int, int, BF_KEY *, unsigned char *, int);
-
-#else
-
-void BF_set_key();
-void BF_ecb_encrypt();
-void BF_encrypt();
-void BF_cbc_encrypt();
-void BF_cfb64_encrypt();
-void BF_ofb64_encrypt();
-char *BF_options();
-
-/* added by itojun */
-void BF_cbc_encrypt_m();
-
-#endif
+} BF_KEY;
+void BF_set_key __P((BF_KEY *, int, unsigned char *));
+void BF_encrypt __P((BF_LONG *, BF_KEY *, int));
#ifdef __cplusplus
}
#endif
diff --git a/sys/crypto/cast128/cast128.c b/sys/crypto/cast128/cast128.c
index 4df1be9..88873f2 100644
--- a/sys/crypto/cast128/cast128.c
+++ b/sys/crypto/cast128/cast128.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: cast128.c,v 1.3 2000/03/27 04:36:29 sumikawa Exp $ */
+/* $KAME: cast128.c,v 1.4 2000/11/06 13:58:08 itojun Exp $ */
/*
* heavily modified by Tomomi Suzuki <suzuki@grelot.elec.ryukoku.ac.jp>
diff --git a/sys/crypto/cast128/cast128.h b/sys/crypto/cast128/cast128.h
index 019c2de..4057a1f 100644
--- a/sys/crypto/cast128/cast128.h
+++ b/sys/crypto/cast128/cast128.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: cast128.h,v 1.4 2000/06/14 10:41:16 itojun Exp $ */
+/* $KAME: cast128.h,v 1.6 2000/09/18 20:59:20 itojun Exp $ */
/*
* heavily modified by Tomomi Suzuki <suzuki@grelot.elec.ryukoku.ac.jp>
@@ -40,7 +40,6 @@
#define RFC2144_CAST_128_H
#include <sys/param.h>
-#include <sys/mbuf.h>
#define CAST128_ENCRYPT 1
@@ -56,8 +55,5 @@ extern void cast128_encrypt_round12 __P((u_int8_t *, const u_int8_t *,
u_int32_t *));
extern void cast128_decrypt_round12 __P((u_int8_t *, const u_int8_t *,
u_int32_t *));
-extern int cast128_cbc_process __P((struct mbuf *, size_t, size_t,
- u_int32_t *, u_int8_t *, size_t, int));
-
#endif
diff --git a/sys/crypto/cast128/cast128_cbc.c b/sys/crypto/cast128/cast128_cbc.c
deleted file mode 100644
index e4725a9..0000000
--- a/sys/crypto/cast128/cast128_cbc.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: cast128_cbc.c,v 1.4 2000/06/14 10:41:17 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.
- */
-/*
- * based on sys/crypto/des/des_cbc.c, rewrote by Tomomi Suzuki
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/mbuf.h>
-#include <crypto/cast128/cast128.h>
-
-#define panic(x) do { printf(x); return EINVAL; } while (0)
-
-int
-cast128_cbc_process(m0, skip, length, subkey, iv, keylen, mode)
- struct mbuf *m0;
- size_t skip;
- size_t length;
- u_int32_t *subkey;
- u_int8_t *iv;
- size_t keylen;
- int mode;
-{
- struct mbuf *m;
- u_int8_t inbuf[8], outbuf[8];
- size_t off;
-
- /* sanity check */
- if (m0->m_pkthdr.len < skip) {
- printf("cast128_cbc_process: mbuf length < skip\n");
- return EINVAL;
- }
- if (m0->m_pkthdr.len < length) {
- printf("cast128_cbc_process: mbuf length < encrypt length\n");
- return EINVAL;
- }
- if (m0->m_pkthdr.len < skip + length) {
- printf("cast128_cbc_process: "
- "mbuf length < skip + encrypt length\n");
- return EINVAL;
- }
- if (length % 8) {
- printf("cast128_cbc_process: length is not multiple of 8\n");
- return EINVAL;
- }
-
- m = m0;
- off = 0;
-
- /* skip over the header */
- while (skip) {
- if (!m)
- panic("cast128_cbc_process: mbuf chain?\n");
- if (m->m_len <= skip) {
- skip -= m->m_len;
- m = m->m_next;
- off = 0;
- } else {
- off = skip;
- skip = 0;
- }
- }
-
- /* copy iv into outbuf for XOR (encrypt) */
- bcopy(iv, outbuf, 8);
-
- /*
- * encrypt/decrypt packet
- */
- while (length > 0) {
- int i;
-
- if (!m)
- panic("cast128_cbc_process: mbuf chain?\n");
-
- /*
- * copy the source into input buffer.
- * don't update off or m, since we need to use them
- * later.
- */
- if (off + 8 <= m->m_len)
- bcopy(mtod(m, u_int8_t *)+off, inbuf, 8);
- else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p, *in;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- in = inbuf;
- while (in - inbuf < 8) {
- if (!p) {
- panic("cast128_cbc_process: "
- "mbuf chain?\n");
- }
- *in++ = *p++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && !n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *);
- else
- p = NULL;
- }
- }
-
- /* encrypt/decrypt */
- switch (mode) {
- case CAST128_ENCRYPT:
- /* XOR */
- for (i = 0; i < 8; i++)
- inbuf[i] ^= outbuf[i];
-
- /* encrypt */
- if (keylen <= 80/8)
- cast128_encrypt_round12(outbuf, inbuf, subkey);
- else
- cast128_encrypt_round16(outbuf, inbuf, subkey);
- break;
-
- case CAST128_DECRYPT:
- /* decrypt */
- if (keylen <= 80/8)
- cast128_decrypt_round12(outbuf, inbuf, subkey);
- else
- cast128_decrypt_round16(outbuf, inbuf, subkey);
-
- /* XOR */
- for (i = 0; i < 8; i++)
- outbuf[i] ^= iv[i];
-
- /* copy inbuf into iv for next XOR */
- bcopy(inbuf, iv, 8);
- break;
- }
-
- /*
- * copy the output buffer into the result.
- * need to update off and m.
- */
- if (off + 8 < m->m_len) {
- bcopy(outbuf, mtod(m, u_int8_t *) + off, 8);
- off += 8;
- } else if (off + 8 == m->m_len) {
- bcopy(outbuf, mtod(m, u_int8_t *) + off, 8);
- do {
- m = m->m_next;
- } while (m && !m->m_len);
- off = 0;
- } else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p, *out;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- out = outbuf;
- while (out - outbuf < 8) {
- if (!p) {
- panic("cast128_cbc_process: "
- "mbuf chain?\n");
- }
- *p++ = *out++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && !n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *);
- else
- p = NULL;
- }
-
- m = n;
- off = noff;
- }
-
- length -= 8;
- }
-
- return 0;
-}
diff --git a/sys/crypto/des/des.h b/sys/crypto/des/des.h
index 536f0c9..c21f972 100644
--- a/sys/crypto/des/des.h
+++ b/sys/crypto/des/des.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: des.h,v 1.4 2000/06/14 10:41:17 itojun Exp $ */
+/* $KAME: des.h,v 1.7 2000/09/18 20:59:21 itojun Exp $ */
/* lib/des/des.h */
/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
@@ -55,11 +55,8 @@
extern "C" {
#endif
-/* If this is set to 'unsigned int' on a DEC Alpha, this gives about a
- * %20 speed up (longs are 8 bytes, int's are 4). */
-#ifndef DES_LONG
-#define DES_LONG unsigned long
-#endif
+/* must be 32bit quantity */
+#define DES_LONG u_int32_t
typedef unsigned char des_cblock[8];
typedef struct des_ks_struct
@@ -83,196 +80,18 @@ typedef struct des_ks_struct
#define DES_CBC_MODE 0
#define DES_PCBC_MODE 1
-#define des_ecb2_encrypt(i,o,k1,k2,e) \
- des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e))
-
-#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
- des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e))
-
-#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \
- des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e))
-
-#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \
- des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n))
-
-#define C_Block des_cblock
-#define Key_schedule des_key_schedule
-#ifdef KERBEROS
-#define ENCRYPT DES_ENCRYPT
-#define DECRYPT DES_DECRYPT
-#endif
-#define KEY_SZ DES_KEY_SZ
-#define string_to_key des_string_to_key
-#define read_pw_string des_read_pw_string
-#define random_key des_random_key
-#define pcbc_encrypt des_pcbc_encrypt
-#define set_key des_set_key
-#define key_sched des_key_sched
-#define ecb_encrypt des_ecb_encrypt
-#define cbc_encrypt des_cbc_encrypt
-#define ncbc_encrypt des_ncbc_encrypt
-#define xcbc_encrypt des_xcbc_encrypt
-#define cbc_cksum des_cbc_cksum
-#define quad_cksum des_quad_cksum
-
-/* For compatibility with the MIT lib - eay 20/05/92 */
-typedef des_key_schedule bit_64;
-#define des_fixup_key_parity des_set_odd_parity
-#define des_check_key_parity check_parity
-
extern int des_check_key; /* defaults to false */
-extern int des_rw_mode; /* defaults to DES_PCBC_MODE */
-/* The next line is used to disable full ANSI prototypes, if your
- * compiler has problems with the prototypes, make sure this line always
- * evaluates to true :-) */
-#if defined(MSDOS) || defined(__STDC__)
-#undef NOPROTO
-#endif
-#ifndef NOPROTO
-char *des_options(void);
-void des_ecb3_encrypt(des_cblock *input,des_cblock *output,
- des_key_schedule ks1,des_key_schedule ks2,
- des_key_schedule ks3, int enc);
-DES_LONG des_cbc_cksum(des_cblock *input,des_cblock *output,
- long length,des_key_schedule schedule,des_cblock *ivec);
-/*
-void des_cbc_encrypt(des_cblock *input,des_cblock *output,long length,
- des_key_schedule schedule,des_cblock *ivec,int enc);
-*/
-int des_cbc_encrypt(struct mbuf *, size_t, size_t,
- des_key_schedule schedule,des_cblock *ivec, int enc);
-void des_ncbc_encrypt(des_cblock *input,des_cblock *output,long length,
- des_key_schedule schedule,des_cblock *ivec,int enc);
-void des_xcbc_encrypt(des_cblock *input,des_cblock *output,long length,
- des_key_schedule schedule,des_cblock *ivec,
- des_cblock *inw,des_cblock *outw,int enc);
-void des_3cbc_encrypt(des_cblock *input,des_cblock *output,long length,
- des_key_schedule sk1,des_key_schedule sk2,
- des_cblock *ivec1,des_cblock *ivec2,int enc);
-extern int des_3cbc_process(struct mbuf *, size_t, size_t,
- des_key_schedule *schedule, des_cblock *ivec, int mode);
-void des_cfb_encrypt(unsigned char *in,unsigned char *out,int numbits,
- long length,des_key_schedule schedule,des_cblock *ivec,int enc);
-void des_ecb_encrypt(des_cblock *input,des_cblock *output,
- des_key_schedule ks,int enc);
-void des_encrypt(DES_LONG *data,des_key_schedule ks, int enc);
-void des_encrypt2(DES_LONG *data,des_key_schedule ks, int enc);
-void des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output,
- long length, des_key_schedule ks1, des_key_schedule ks2,
- des_key_schedule ks3, des_cblock *ivec, int enc);
-void des_ede3_cfb64_encrypt(unsigned char *in, unsigned char *out,
- long length, des_key_schedule ks1, des_key_schedule ks2,
- des_key_schedule ks3, des_cblock *ivec, int *num, int encrypt);
-void des_ede3_ofb64_encrypt(unsigned char *in, unsigned char *out,
- long length, des_key_schedule ks1, des_key_schedule ks2,
- des_key_schedule ks3, des_cblock *ivec, int *num);
+char *des_options __P((void));
+void des_ecb_encrypt __P((des_cblock *, des_cblock *,
+ des_key_schedule, int));
+void des_encrypt __P((DES_LONG *, des_key_schedule, int));
+void des_encrypt2 __P((DES_LONG *, des_key_schedule, int));
-int des_enc_read(int fd,char *buf,int len,des_key_schedule sched,
- des_cblock *iv);
-int des_enc_write(int fd,char *buf,int len,des_key_schedule sched,
- des_cblock *iv);
-#ifdef PERL5
-char *des_crypt(const char *buf,const char *salt);
-#else
-/* some stupid compilers complain because I have declared char instead
- * of const char */
-#if 1
-char *crypt(const char *buf,const char *salt);
-#else
-char *crypt();
-#endif
-#endif
-void des_ofb_encrypt(unsigned char *in,unsigned char *out,
- int numbits,long length,des_key_schedule schedule,des_cblock *ivec);
-void des_pcbc_encrypt(des_cblock *input,des_cblock *output,long length,
- des_key_schedule schedule,des_cblock *ivec,int enc);
-DES_LONG des_quad_cksum(des_cblock *input,des_cblock *output,
- long length,int out_count,des_cblock *seed);
-void des_random_seed(des_cblock key);
-void des_random_key(des_cblock ret);
-int des_read_password(des_cblock *key,char *prompt,int verify);
-int des_read_2passwords(des_cblock *key1,des_cblock *key2,
- char *prompt,int verify);
-int des_read_pw_string(char *buf,int length,char *prompt,int verify);
-void des_set_odd_parity(des_cblock *key);
-int des_is_weak_key(des_cblock *key);
-int des_set_key(des_cblock *key,des_key_schedule schedule);
-int des_key_sched(des_cblock *key,des_key_schedule schedule);
-void des_string_to_key(char *str,des_cblock *key);
-void des_string_to_2keys(char *str,des_cblock *key1,des_cblock *key2);
-void des_cfb64_encrypt(unsigned char *in, unsigned char *out, long length,
- des_key_schedule schedule, des_cblock *ivec, int *num, int enc);
-void des_ofb64_encrypt(unsigned char *in, unsigned char *out, long length,
- des_key_schedule schedule, des_cblock *ivec, int *num);
-
-/* Extra functions from Mark Murray <mark@grondar.za> */
-/*
-void des_cblock_print_file(des_cblock *cb, FILE *fp);
-*/
-/* The following functions are not in the normal unix build or the
- * SSLeay build. When using the SSLeay build, use RAND_seed()
- * and RAND_bytes() instead. */
-int des_new_random_key(des_cblock *key);
-void des_init_random_number_generator(des_cblock *key);
-void des_set_random_generator_seed(des_cblock *key);
-void des_set_sequence_number(des_cblock new_sequence_number);
-void des_generate_random_block(des_cblock *block);
-
-#else
-
-char *des_options();
-void des_ecb3_encrypt();
-DES_LONG des_cbc_cksum();
-void des_cbc_encrypt();
-void des_ncbc_encrypt();
-void des_xcbc_encrypt();
-void des_3cbc_encrypt();
-void des_cfb_encrypt();
-void des_ede3_cfb64_encrypt();
-void des_ede3_ofb64_encrypt();
-void des_ecb_encrypt();
-void des_encrypt();
-void des_encrypt2();
-void des_ede3_cbc_encrypt();
-int des_enc_read();
-int des_enc_write();
-#ifdef PERL5
-char *des_crypt();
-#else
-char *crypt();
-#endif
-void des_ofb_encrypt();
-void des_pcbc_encrypt();
-DES_LONG des_quad_cksum();
-void des_random_seed();
-void des_random_key();
-int des_read_password();
-int des_read_2passwords();
-int des_read_pw_string();
-void des_set_odd_parity();
-int des_is_weak_key();
-int des_set_key();
-int des_key_sched();
-void des_string_to_key();
-void des_string_to_2keys();
-void des_cfb64_encrypt();
-void des_ofb64_encrypt();
-
-/* Extra functions from Mark Murray <mark@grondar.za> */
-void des_cblock_print_file();
-/* The following functions are not in the normal unix build or the
- * SSLeay build. When using the SSLeay build, use RAND_seed()
- * and RAND_bytes() instead. */
-#ifdef FreeBSD
-int des_new_random_key();
-void des_init_random_number_generator();
-void des_set_random_generator_seed();
-void des_set_sequence_number();
-void des_generate_random_block();
-#endif
-
-#endif
+void des_set_odd_parity __P((des_cblock *));
+int des_is_weak_key __P((des_cblock *));
+int des_set_key __P((des_cblock *, des_key_schedule));
+int des_key_sched __P((des_cblock *, des_key_schedule));
#ifdef __cplusplus
}
diff --git a/sys/crypto/des/des_3cbc.c b/sys/crypto/des/des_3cbc.c
deleted file mode 100644
index e675871..0000000
--- a/sys/crypto/des/des_3cbc.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: des_3cbc.c,v 1.4 2000/06/14 10:41:17 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.
- */
-/*
- * based on sys/crypto/des/des_cbc.c, rewrote by Tomomi Suzuki
- */
-#include <crypto/des/des_locl.h>
-
-#define panic(x) do { printf(x); return EINVAL; } while (0)
-
-int des_3cbc_process(m0, skip, length, schedule, ivec, mode)
- struct mbuf *m0;
- size_t skip;
- size_t length;
- des_key_schedule *schedule;
- des_cblock (*ivec);
- int mode;
-{
- u_int8_t inbuf[8], outbuf[8];
- struct mbuf *m;
- size_t off;
- DES_LONG tin0, tin1;
- DES_LONG tout0, tout1;
- DES_LONG tin[2];
- DES_LONG xor0 = 0, xor1 = 0;
- u_int8_t *iv;
- u_int8_t *in, *out;
-
- /* sanity check */
- if (m0->m_pkthdr.len < skip) {
- printf("des_3cbc_process: mbuf length < skip\n");
- return EINVAL;
- }
- if (m0->m_pkthdr.len < length) {
- printf("des_3cbc_process: mbuf length < encrypt length\n");
- return EINVAL;
- }
- if (m0->m_pkthdr.len < skip + length) {
- printf("des_3cbc_process: mbuf length < "
- "skip + encrypt length\n");
- return EINVAL;
- }
- if (length % 8) {
- printf("des_3cbc_process: length(%lu) is not multiple of 8\n",
- (u_long)length);
- return EINVAL;
- }
-
- m = m0;
- off = 0;
-
- /* skip over the header */
- while (skip) {
- if (!m)
- panic("des_3cbc_process: mbuf chain?\n");
- if (m->m_len <= skip) {
- skip -= m->m_len;
- m = m->m_next;
- off = 0;
- } else {
- off = skip;
- skip = 0;
- }
- }
-
- /* initialize */
- tin0 = tin1 = tout0 = tout1 = 0;
- tin[0] = tin[1] = 0;
-
- switch (mode) {
- case DES_ENCRYPT:
- iv = (u_int8_t *)ivec;
- c2l(iv, tout0);
- c2l(iv, tout1);
- break;
- case DES_DECRYPT:
- xor0 = xor1 = 0;
- iv = (u_int8_t *)ivec;
- c2l(iv, xor0);
- c2l(iv, xor1);
- break;
- }
-
- /*
- * encrypt/decrypt packet
- */
- while (length > 0) {
- if (!m)
- panic("des_3cbc_process: mbuf chain?\n");
-
- /*
- * copy the source into input buffer.
- * don't update off or m, since we need to use them
- * later.
- */
- if (off + 8 <= m->m_len)
- bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8);
- else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p;
- u_int8_t *in;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- in = &inbuf[0];
- while (in - &inbuf[0] < 8) {
- if (!p) {
- panic("des_3cbc_process: "
- "mbuf chain?\n");
- }
- *in++ = *p++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && !n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *) + noff;
- else
- p = NULL;
- }
- }
-
- /* encrypt/decrypt */
- switch (mode) {
- case DES_ENCRYPT:
- in = &inbuf[0];
- out = &outbuf[0];
- c2l(in, tin0);
- c2l(in, tin1);
-
- /* XOR */
- tin0 ^= tout0; tin[0] = tin0;
- tin1 ^= tout1; tin[1] = tin1;
-
- des_encrypt((DES_LONG *)tin, schedule[0], DES_ENCRYPT);
- des_encrypt((DES_LONG *)tin, schedule[1], DES_DECRYPT);
- des_encrypt((DES_LONG *)tin, schedule[2], DES_ENCRYPT);
-
- tout0 = tin[0]; l2c(tout0, out);
- tout1 = tin[1]; l2c(tout1, out);
- break;
- case DES_DECRYPT:
- in = &inbuf[0];
- out = &outbuf[0];
- c2l(in, tin0); tin[0] = tin0;
- c2l(in, tin1); tin[1] = tin1;
-
- des_encrypt((DES_LONG *)tin, schedule[2], DES_DECRYPT);
- des_encrypt((DES_LONG *)tin, schedule[1], DES_ENCRYPT);
- des_encrypt((DES_LONG *)tin, schedule[0], DES_DECRYPT);
-
- /* XOR */
- tout0 = tin[0] ^ xor0;
- tout1 = tin[1] ^ xor1;
- l2c(tout0, out);
- l2c(tout1, out);
-
- /* for next iv */
- xor0 = tin0;
- xor1 = tin1;
- break;
- }
-
- /*
- * copy the output buffer int the result.
- * need to update off and m.
- */
- if (off + 8 < m->m_len) {
- bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8);
- off += 8;
- } else if (off + 8 == m->m_len) {
- bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8);
- do {
- m = m->m_next;
- } while (m && !m->m_len);
- off = 0;
- } else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p;
- u_int8_t *out;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- out = &outbuf[0];
- while (out - &outbuf[0] < 8) {
- if (!p) {
- panic("des_3cbc_process: "
- "mbuf chain?\n");
- }
- *p++ = *out++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && !n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *) + noff;
- else
- p = NULL;
- }
-
- m = n;
- off = noff;
- }
-
- length -= 8;
- }
-
- return 0;
-}
-
diff --git a/sys/crypto/des/des_cbc.c b/sys/crypto/des/des_cbc.c
deleted file mode 100644
index 92de8f8..0000000
--- a/sys/crypto/des/des_cbc.c
+++ /dev/null
@@ -1,331 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: des_cbc.c,v 1.4 2000/06/14 10:41:17 itojun Exp $ */
-
-/*
- * heavily modified by Yoshifumi Nishida <nishida@sfc.wide.ad.jp>.
- * then, completely rewrote by Jun-ichiro itojun Itoh <itojun@itojun.org>,
- * 1997.
- */
-/* crypto/des/cbc_enc.c */
-/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
- * All rights reserved.
- *
- * This file is part of an SSL implementation written
- * by Eric Young (eay@mincom.oz.au).
- * The implementation was written so as to conform with Netscapes SSL
- * specification. This library and applications are
- * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE
- * as long as the following conditions are aheared to.
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed. If this code is used in a product,
- * Eric Young should be given attribution as the author of the parts used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Eric Young (eay@mincom.oz.au)
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <crypto/des/des_locl.h>
-
-#define panic(x) do {printf(x); return EINVAL;} while (0)
-
-int des_cbc_encrypt(m0, skip, length, schedule, ivec, mode)
- struct mbuf *m0;
- size_t skip;
- size_t length;
- des_key_schedule schedule;
- des_cblock (*ivec);
- int mode;
-{
- u_int8_t inbuf[8], outbuf[8];
- struct mbuf *m;
- size_t off;
- register DES_LONG tin0, tin1;
- register DES_LONG tout0, tout1;
- DES_LONG tin[2];
- u_int8_t *iv;
-
- /* sanity checks */
- if (m0->m_pkthdr.len < skip) {
- printf("mbuf length < skip\n");
- return EINVAL;
- }
- if (m0->m_pkthdr.len < length) {
- printf("mbuf length < encrypt length\n");
- return EINVAL;
- }
- if (m0->m_pkthdr.len < skip + length) {
- printf("mbuf length < skip + encrypt length\n");
- return EINVAL;
- }
- if (length % 8) {
- printf("length is not multiple of 8\n");
- return EINVAL;
- }
-
- m = m0;
- off = 0;
-
- /* skip over the header */
- while (skip) {
- if (!m)
- panic("mbuf chain?\n");
- if (m->m_len <= skip) {
- skip -= m->m_len;
- m = m->m_next;
- off = 0;
- } else {
- off = skip;
- skip = 0;
- }
- }
-
- /* initialize */
- tin0 = tin1 = tout0 = tout1 = 0;
- tin[0] = tin[1] = 0;
-
- if (mode == DES_ENCRYPT) {
- u_int8_t *in, *out;
-
- iv = (u_int8_t *)ivec;
- c2l(iv, tout0);
- c2l(iv, tout1);
-
- while (0 < length) {
- if (!m)
- panic("mbuf chain?\n");
-
- /*
- * copy the source into input buffer.
- * don't update off or m, since we need to use them * later.
- */
- if (off + 8 <= m->m_len)
- bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8);
- else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p;
- u_int8_t *in;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- in = &inbuf[0];
- while (in - &inbuf[0] < 8) {
- if (!p)
- panic("mbuf chain?\n");
-
- *in++ = *p++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && ! n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *) + noff;
- else
- p = NULL;
- }
- }
-
- in = &inbuf[0];
- out = &outbuf[0];
- c2l(in, tin0);
- c2l(in, tin1);
-
- tin0 ^= tout0; tin[0] = tin0;
- tin1 ^= tout1; tin[1] = tin1;
- des_encrypt((DES_LONG *)tin, schedule, DES_ENCRYPT);
- tout0 = tin[0]; l2c(tout0, out);
- tout1 = tin[1]; l2c(tout1, out);
-
- /*
- * copy the output buffer into the result.
- * need to update off and m.
- */
- if (off + 8 < m->m_len) {
- bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8);
- off += 8;
- } else if (off + 8 == m->m_len) {
- bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8);
- do {
- m = m->m_next;
- } while (m && ! m->m_len);
- off = 0;
- } else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p;
- u_int8_t *out;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- out = &outbuf[0];
- while (out - &outbuf[0] < 8) {
- if (!p)
- panic("mbuf chain?");
- *p++ = *out++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && ! n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *) + noff;
- else
- p = NULL;
- }
-
- m = n;
- off = noff;
- }
-
- length -= 8;
- }
- } else if (mode == DES_DECRYPT) {
- register DES_LONG xor0, xor1;
- u_int8_t *in, *out;
-
- xor0 = xor1 = 0;
- iv = (u_int8_t *)ivec;
- c2l(iv, xor0);
- c2l(iv, xor1);
-
- while (0 < length) {
- if (!m)
- panic("mbuf chain?\n");
-
- /*
- * copy the source into input buffer.
- * don't update off or m, since we need to use them * later.
- */
- if (off + 8 <= m->m_len)
- bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8);
- else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p;
- u_int8_t *in;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- in = &inbuf[0];
- while (in - &inbuf[0] < 8) {
- if (!p)
- panic("mbuf chain?\n");
- *in++ = *p++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && ! n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *) + noff;
- else
- p = NULL;
- }
- }
-
- in = &inbuf[0];
- out = &outbuf[0];
- c2l(in, tin0); tin[0] = tin0;
- c2l(in, tin1); tin[1] = tin1;
- des_encrypt((DES_LONG *)tin, schedule, DES_DECRYPT);
- tout0 = tin[0] ^ xor0;
- tout1 = tin[1] ^ xor1;
- l2c(tout0, out);
- l2c(tout1, out);
- xor0 = tin0;
- xor1 = tin1;
-
-
- /*
- * copy the output buffer into the result.
- * need to update off and m.
- */
- if (off + 8 < m->m_len) {
- bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8);
- off += 8;
- } else if (off + 8 == m->m_len) {
- bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8);
- do {
- m = m->m_next;
- } while (m && ! m->m_len);
- off = 0;
- } else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p;
- u_int8_t *out;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- out = &outbuf[0];
- while (out - &outbuf[0] < 8) {
- if (!p)
- panic("mbuf chain?\n");
- *p++ = *out++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && ! n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *) + noff;
- else
- p = NULL;
- }
-
- m = n;
- off = noff;
- }
-
- length -= 8;
- }
- }
-
- return 0;
-}
diff --git a/sys/crypto/des/des_ecb.c b/sys/crypto/des/des_ecb.c
index d828b91..aa1b22b 100644
--- a/sys/crypto/des/des_ecb.c
+++ b/sys/crypto/des/des_ecb.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: des_ecb.c,v 1.3 2000/03/27 04:36:33 sumikawa Exp $ */
+/* $KAME: des_ecb.c,v 1.5 2000/11/06 13:58:08 itojun Exp $ */
/* crypto/des/ecb_enc.c */
/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
@@ -48,6 +48,8 @@
* [including the GNU Public Licence.]
*/
+#include <sys/param.h>
+#include <sys/systm.h>
#include <crypto/des/des_locl.h>
#include <crypto/des/spr.h>
diff --git a/sys/crypto/des/des_locl.h b/sys/crypto/des/des_locl.h
index ae6e828..82486dc 100644
--- a/sys/crypto/des/des_locl.h
+++ b/sys/crypto/des/des_locl.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: des_locl.h,v 1.4 2000/03/27 04:43:46 sumikawa Exp $ */
+/* $KAME: des_locl.h,v 1.6 2000/11/06 13:58:09 itojun Exp $ */
/* lib/des/des_locl.h */
/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
@@ -55,83 +55,17 @@
* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
*/
-#include <sys/param.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/systm.h>
-
#ifndef HEADER_DES_LOCL_H
#define HEADER_DES_LOCL_H
-#if defined(WIN32) || defined(WIN16)
-#ifndef MSDOS
-#define MSDOS
-#endif
-#endif
-
-/*
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef MSDOS
-#include <unistd.h>
-#endif
-*/
#include <crypto/des/des.h>
-/* the following is tweaked from a config script, that is why it is a
- * protected undef/define */
-#ifndef DES_PTR
#undef DES_PTR
-#endif
-
-#ifdef MSDOS /* Visual C++ 2.1 (Windows NT/95) */
-#include <stdlib.h>
-#include <errno.h>
-#include <time.h>
-#include <io.h>
-#ifndef RAND
-#define RAND
-#endif
-#undef NOPROTO
-#endif
-
-#if !defined(_KERNEL) && (defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS))
-#ifndef __NetBSD__
-#include <string.h>
-#endif
-#endif
-
-#ifdef __NetBSD__
-#include <sys/systm.h>
-#endif
-
-#ifndef RAND
-#define RAND
-#endif
-
-#ifdef linux
-#undef RAND
-#endif
-
-#ifdef MSDOS
-#define getpid() 2
-#define RAND
-#undef NOPROTO
-#endif
-
-#if defined(NOCONST)
-#define const
-#endif
#ifdef __STDC__
#undef NOPROTO
#endif
-#ifdef RAND
-#define srandom(s) srand(s)
-#define random rand
-#endif
-
#define ITERATIONS 16
#define HALF_ITERATIONS 8
@@ -194,11 +128,7 @@
} \
}
-#if defined(WIN32)
-#define ROTATE(a,n) (_lrotr(a,n))
-#else
#define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n))))
-#endif
/* The changes to this macro may help or hinder, depending on the
* compiler and the achitecture. gcc2 always seems to do well :-).
@@ -313,36 +243,3 @@
PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \
}
#endif
-
-
-/*
-#define mbuf2char(i_mbuf, i_index, in) \
- { \
- register int i; \
- struct mbuf *m; \
- char *buf; \
- m = i_mbuf; \
- for (i = 0; i < 8; i ++){ \
- if (i_index + i == m->m_len){ \
- m = m->m_next; \
- } \
- buf = mtod(m, char *); \
- in[i] = *(buf + i); \
- }
-
-
-#define char2mbuf(o_mbuf, o_index, out) \
- { \
- register int i; \
- struct mbuf *m; \
- char *buf; \
- m = o_mbuf; \
- for (i = 0; i < 8; i ++){ \
- if (i_index + i == m->m_len){ \
- m = m->m_next; \
- } \
- buf = mtod(m, char *); \
- *(buf + i) = out[i]; \
- }
-*/
-
diff --git a/sys/crypto/des/des_setkey.c b/sys/crypto/des/des_setkey.c
index 48d13fc..2ddf8bd 100644
--- a/sys/crypto/des/des_setkey.c
+++ b/sys/crypto/des/des_setkey.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: des_setkey.c,v 1.3 2000/03/27 04:36:33 sumikawa Exp $ */
+/* $KAME: des_setkey.c,v 1.5 2000/11/06 13:58:09 itojun Exp $ */
/* crypto/des/set_key.c */
/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
@@ -55,15 +55,13 @@
* 1.1 added norm_expand_bits
* 1.0 First working version
*/
+#include <sys/param.h>
+#include <sys/systm.h>
#include <crypto/des/des_locl.h>
#include <crypto/des/podd.h>
#include <crypto/des/sk.h>
-#ifndef NOPROTO
-static int check_parity(des_cblock (*key));
-#else
-static int check_parity();
-#endif
+static int check_parity __P((des_cblock (*)));
int des_check_key=0;
diff --git a/sys/crypto/md5.c b/sys/crypto/md5.c
index e827700..3351d41 100644
--- a/sys/crypto/md5.c
+++ b/sys/crypto/md5.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: md5.c,v 1.4 2000/03/27 04:36:22 sumikawa Exp $ */
+/* $KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
diff --git a/sys/crypto/rc5/rc5.c b/sys/crypto/rc5/rc5.c
deleted file mode 100644
index 99a8ac6..0000000
--- a/sys/crypto/rc5/rc5.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: rc5.c,v 1.3 2000/03/27 04:36:36 sumikawa 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 <crypto/rc5/rc5.h>
-
-
-void
-set_rc5_expandkey(e_key, key, keylen, rounds)
- RC5_WORD *e_key;
- u_int8_t *key;
- size_t keylen;
- int rounds;
-{
- int i, j, k, LL, t, T;
- RC5_WORD L[256/WW];
- RC5_WORD A, B;
-
- LL = (keylen + WW - 1) / WW;
-
- bzero(L, sizeof(RC5_WORD)*LL);
-
- for (i = 0; i < keylen; i++) {
- t = (key[i] & 0xff) << (8*(i%4));
- L[i/WW] = L[i/WW] + t;
- }
-
- T = 2 * (rounds + 1);
- e_key[0] = Pw;
- for (i = 1; i < T; i++)
- e_key[i] = e_key[i-1] + Qw;
-
- i = j = 0;
- A = B = 0;
- if (LL > T)
- k = 3 * LL;
- else
- k = 3 * T;
-
- for (; k > 0; k--) {
- A = ROTL(e_key[i]+A+B, 3, W);
- e_key[i] = A;
- B = ROTL(L[j]+A+B, A+B, W);
- L[j] = B;
-
- i = (i + 1) % T;
- j = (j + 1) % LL;
- }
-}
-
-
-/*
- *
- */
-void
-rc5_encrypt_round16(out, in, e_key)
- u_int8_t *out;
- const u_int8_t *in;
- const RC5_WORD *e_key;
-{
- RC5_WORD A, B;
- const RC5_WORD *e_keyA, *e_keyB;
-
- A = in[0] & 0xff;
- A += (in[1] & 0xff) << 8;
- A += (in[2] & 0xff) << 16;
- A += (in[3] & 0xff) << 24;
- B = in[4] & 0xff;
- B += (in[5] & 0xff) << 8;
- B += (in[6] & 0xff) << 16;
- B += (in[7] & 0xff) << 24;
-
- e_keyA = e_key;
- e_keyB = e_key + 1;
-
- A += *e_keyA; e_keyA += 2;
- B += *e_keyB; e_keyB += 2;
-
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2;
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2;
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2;
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 4 */
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2;
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2;
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2;
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 8 */
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2;
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2;
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2;
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 12 */
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2;
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2;
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2;
- A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2;
- B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 16 */
-
- out[0] = A & 0xff;
- out[1] = (A >> 8) & 0xff;
- out[2] = (A >> 16) & 0xff;
- out[3] = (A >> 24) & 0xff;
- out[4] = B & 0xff;
- out[5] = (B >> 8) & 0xff;
- out[6] = (B >> 16) & 0xff;
- out[7] = (B >> 24) & 0xff;
-}
-
-
-/*
- *
- */
-void
-rc5_decrypt_round16(out, in, e_key)
- u_int8_t *out;
- const u_int8_t *in;
- const RC5_WORD *e_key;
-{
- RC5_WORD A, B;
- const RC5_WORD *e_keyA, *e_keyB;
-
- A = in[0] & 0xff;
- A += (in[1] & 0xff) << 8;
- A += (in[2] & 0xff) << 16;
- A += (in[3] & 0xff) << 24;
- B = in[4] & 0xff;
- B += (in[5] & 0xff) << 8;
- B += (in[6] & 0xff) << 16;
- B += (in[7] & 0xff) << 24;
-
- e_keyA = e_key + 2*16;
- e_keyB = e_key + 2*16 + 1;
-
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2;
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2;
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2;
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 4 */
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2;
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2;
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2;
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 8 */
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2;
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2;
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2;
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 12 */
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2;
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2;
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2;
- B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2;
- A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 16 */
-
- B = B - *e_keyB;
- A = A - *e_keyA;
-
- out[0] = A & 0xff;
- out[1] = (A >> 8) & 0xff;
- out[2] = (A >> 16) & 0xff;
- out[3] = (A >> 24) & 0xff;
- out[4] = B & 0xff;
- out[5] = (B >> 8) & 0xff;
- out[6] = (B >> 16) & 0xff;
- out[7] = (B >> 24) & 0xff;
-}
-
diff --git a/sys/crypto/rc5/rc5_cbc.c b/sys/crypto/rc5/rc5_cbc.c
deleted file mode 100644
index 5972cc6..0000000
--- a/sys/crypto/rc5/rc5_cbc.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: rc5_cbc.c,v 1.4 2000/06/14 10:41:17 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.
- */
-/*
- * based on sys/crypto/des/des_cbc.c, rewrote by Tomomi Suzuki
- */
-#include <crypto/rc5/rc5.h>
-
-#define panic(x) do { printf(x); return EINVAL; } while (0)
-
-int
-rc5_cbc_process(m0, skip, length, e_key, iv, mode)
- struct mbuf *m0;
- size_t skip;
- size_t length;
- RC5_WORD *e_key;
- u_int8_t *iv;
- int mode;
-{
- u_int8_t inbuf[8], outbuf[8];
- struct mbuf *m;
- size_t off;
-
- /* sanity check */
- if (m0->m_pkthdr.len < skip) {
- printf("rc5_cbc_process: mbuf length < skip\n");
- return EINVAL;
- }
- if (m0->m_pkthdr.len < length) {
- printf("rc5_cbc_process: mbuf length < encrypt length\n");
- return EINVAL;
- }
- if (m0->m_pkthdr.len < skip + length) {
- printf("rc5_cbc_process: mbuf length < "
- "skip + encrypt length\n");
- return EINVAL;
- }
- if (length % 8) {
- printf("rc5_cbc_process: length(%lu)is not multipleof 8\n",
- (u_long)length);
- return EINVAL;
- }
-
- m = m0;
- off = 0;
-
- /* skip over the header */
- while (skip) {
- if (!m)
- panic("rc5_cbc_process: mbuf chain?\n");
- if (m->m_len <= skip) {
- skip -= m->m_len;
- m = m->m_next;
- off = 0;
- } else {
- off = skip;
- skip = 0;
- }
- }
-
- /* copy iv into outbuf for XOR (encrypt) */
- bcopy(iv, outbuf, 8);
-
- /*
- * encrypt/decrypt packet
- */
- while (length > 0) {
- int i;
-
- if (!m)
- panic("rc5_cbc_process: mbuf chain?\n");
-
- /*
- * copy the source into input buffer.
- * don't update off or m, since we need to use them
- * later.
- */
- if (off + 8 <= m->m_len)
- bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8);
- else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p;
- u_int8_t *in;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- in = &inbuf[0];
- while (in - &inbuf[0] < 8) {
- if (!p) {
- panic("rc5_cbc_process: "
- "mbuf chain?\n");
- }
- *in++ = *p++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && !n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *) + noff;
- else
- p = NULL;
- }
- }
-
- /* encrypt/decrypt */
- switch (mode) {
- case RC5_ENCRYPT:
- /* XOR */
- for (i = 0; i < 8; i++)
- inbuf[i] ^= outbuf[i];
-
- /* encrypt */
- rc5_encrypt_round16(outbuf, inbuf, e_key);
- break;
-
- case RC5_DECRYPT:
- /* decrypt */
- rc5_decrypt_round16(outbuf, inbuf, e_key);
-
- /* XOR */
- for (i = 0; i < 8; i++)
- outbuf[i] ^= iv[i];
-
- /* copy inbuf into iv for next XOR */
- bcopy(inbuf, iv, 8);
- break;
- }
-
- /*
- * copy the output buffer into the result.
- * need to update off and m.
- */
- if (off + 8 < m->m_len) {
- bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8);
- off += 8;
- } else if (off + 8 == m->m_len) {
- bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8);
- do {
- m = m->m_next;
- } while (m && !m->m_len);
- off = 0;
- } else {
- struct mbuf *n;
- size_t noff;
- u_int8_t *p;
- u_int8_t *out;
-
- n = m;
- noff = off;
- p = mtod(n, u_int8_t *) + noff;
-
- out = &outbuf[0];
- while (out - &outbuf[0] < 8) {
- if (!p) {
- panic("rc5_cbc_process: "
- "mbuf chain?\n");
- }
- *p++ = *out++;
- noff++;
- if (noff < n->m_len)
- continue;
- do {
- n = n->m_next;
- } while (n && !n->m_len);
- noff = 0;
- if (n)
- p = mtod(n, u_int8_t *) + noff;
- else
- p = NULL;
- }
-
- m = n;
- off = noff;
- }
-
- length -= 8;
- }
-
- return 0;
-}
-
diff --git a/sys/crypto/rijndael/boxes-fst.dat b/sys/crypto/rijndael/boxes-fst.dat
index 6315523..3fed9c0 100644
--- a/sys/crypto/rijndael/boxes-fst.dat
+++ b/sys/crypto/rijndael/boxes-fst.dat
@@ -1,6 +1,7 @@
-/* $KAME$ */
+/* $FreeBSD$ */
+/* $KAME: boxes-fst.dat,v 1.6 2001/05/27 00:23:22 itojun Exp $ */
-word8 S[256] = {
+const word8 S[256] = {
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
@@ -20,7 +21,7 @@ word8 S[256] = {
};
#ifdef INTERMEDIATE_VALUE_KAT
-static word8 Si[256] = {
+static const word8 Si[256] = {
82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251,
124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203,
84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78,
@@ -40,7 +41,13 @@ static word8 Si[256] = {
};
#endif /* INTERMEDIATE_VALUE_KAT */
-static word8 T1[256][4] = {
+union xtab {
+ word32 xt32[256];
+ word8 xt8[256][4];
+};
+
+static const union xtab xT1 = {
+ .xt8 = {
{0xc6,0x63,0x63,0xa5}, {0xf8,0x7c,0x7c,0x84}, {0xee,0x77,0x77,0x99}, {0xf6,0x7b,0x7b,0x8d},
{0xff,0xf2,0xf2,0x0d}, {0xd6,0x6b,0x6b,0xbd}, {0xde,0x6f,0x6f,0xb1}, {0x91,0xc5,0xc5,0x54},
{0x60,0x30,0x30,0x50}, {0x02,0x01,0x01,0x03}, {0xce,0x67,0x67,0xa9}, {0x56,0x2b,0x2b,0x7d},
@@ -105,9 +112,12 @@ static word8 T1[256][4] = {
{0x65,0xbf,0xbf,0xda}, {0xd7,0xe6,0xe6,0x31}, {0x84,0x42,0x42,0xc6}, {0xd0,0x68,0x68,0xb8},
{0x82,0x41,0x41,0xc3}, {0x29,0x99,0x99,0xb0}, {0x5a,0x2d,0x2d,0x77}, {0x1e,0x0f,0x0f,0x11},
{0x7b,0xb0,0xb0,0xcb}, {0xa8,0x54,0x54,0xfc}, {0x6d,0xbb,0xbb,0xd6}, {0x2c,0x16,0x16,0x3a}
+ }
};
+#define T1 xT1.xt8
-static word8 T2[256][4] = {
+static const union xtab xT2 = {
+ .xt8 = {
{0xa5,0xc6,0x63,0x63}, {0x84,0xf8,0x7c,0x7c}, {0x99,0xee,0x77,0x77}, {0x8d,0xf6,0x7b,0x7b},
{0x0d,0xff,0xf2,0xf2}, {0xbd,0xd6,0x6b,0x6b}, {0xb1,0xde,0x6f,0x6f}, {0x54,0x91,0xc5,0xc5},
{0x50,0x60,0x30,0x30}, {0x03,0x02,0x01,0x01}, {0xa9,0xce,0x67,0x67}, {0x7d,0x56,0x2b,0x2b},
@@ -172,9 +182,12 @@ static word8 T2[256][4] = {
{0xda,0x65,0xbf,0xbf}, {0x31,0xd7,0xe6,0xe6}, {0xc6,0x84,0x42,0x42}, {0xb8,0xd0,0x68,0x68},
{0xc3,0x82,0x41,0x41}, {0xb0,0x29,0x99,0x99}, {0x77,0x5a,0x2d,0x2d}, {0x11,0x1e,0x0f,0x0f},
{0xcb,0x7b,0xb0,0xb0}, {0xfc,0xa8,0x54,0x54}, {0xd6,0x6d,0xbb,0xbb}, {0x3a,0x2c,0x16,0x16}
+ }
};
+#define T2 xT2.xt8
-static word8 T3[256][4] = {
+static const union xtab xT3 = {
+ .xt8 = {
{0x63,0xa5,0xc6,0x63}, {0x7c,0x84,0xf8,0x7c}, {0x77,0x99,0xee,0x77}, {0x7b,0x8d,0xf6,0x7b},
{0xf2,0x0d,0xff,0xf2}, {0x6b,0xbd,0xd6,0x6b}, {0x6f,0xb1,0xde,0x6f}, {0xc5,0x54,0x91,0xc5},
{0x30,0x50,0x60,0x30}, {0x01,0x03,0x02,0x01}, {0x67,0xa9,0xce,0x67}, {0x2b,0x7d,0x56,0x2b},
@@ -239,9 +252,12 @@ static word8 T3[256][4] = {
{0xbf,0xda,0x65,0xbf}, {0xe6,0x31,0xd7,0xe6}, {0x42,0xc6,0x84,0x42}, {0x68,0xb8,0xd0,0x68},
{0x41,0xc3,0x82,0x41}, {0x99,0xb0,0x29,0x99}, {0x2d,0x77,0x5a,0x2d}, {0x0f,0x11,0x1e,0x0f},
{0xb0,0xcb,0x7b,0xb0}, {0x54,0xfc,0xa8,0x54}, {0xbb,0xd6,0x6d,0xbb}, {0x16,0x3a,0x2c,0x16}
+ }
};
+#define T3 xT3.xt8
-static word8 T4[256][4] = {
+static const union xtab xT4 = {
+ .xt8 = {
{0x63,0x63,0xa5,0xc6}, {0x7c,0x7c,0x84,0xf8}, {0x77,0x77,0x99,0xee}, {0x7b,0x7b,0x8d,0xf6},
{0xf2,0xf2,0x0d,0xff}, {0x6b,0x6b,0xbd,0xd6}, {0x6f,0x6f,0xb1,0xde}, {0xc5,0xc5,0x54,0x91},
{0x30,0x30,0x50,0x60}, {0x01,0x01,0x03,0x02}, {0x67,0x67,0xa9,0xce}, {0x2b,0x2b,0x7d,0x56},
@@ -306,9 +322,12 @@ static word8 T4[256][4] = {
{0xbf,0xbf,0xda,0x65}, {0xe6,0xe6,0x31,0xd7}, {0x42,0x42,0xc6,0x84}, {0x68,0x68,0xb8,0xd0},
{0x41,0x41,0xc3,0x82}, {0x99,0x99,0xb0,0x29}, {0x2d,0x2d,0x77,0x5a}, {0x0f,0x0f,0x11,0x1e},
{0xb0,0xb0,0xcb,0x7b}, {0x54,0x54,0xfc,0xa8}, {0xbb,0xbb,0xd6,0x6d}, {0x16,0x16,0x3a,0x2c}
+ }
};
+#define T4 xT4.xt8
-static word8 T5[256][4] = {
+static const union xtab xT5 = {
+ .xt8 = {
{0x51,0xf4,0xa7,0x50}, {0x7e,0x41,0x65,0x53}, {0x1a,0x17,0xa4,0xc3}, {0x3a,0x27,0x5e,0x96},
{0x3b,0xab,0x6b,0xcb}, {0x1f,0x9d,0x45,0xf1}, {0xac,0xfa,0x58,0xab}, {0x4b,0xe3,0x03,0x93},
{0x20,0x30,0xfa,0x55}, {0xad,0x76,0x6d,0xf6}, {0x88,0xcc,0x76,0x91}, {0xf5,0x02,0x4c,0x25},
@@ -373,9 +392,12 @@ static word8 T5[256][4] = {
{0x16,0x1d,0xc3,0x72}, {0xbc,0xe2,0x25,0x0c}, {0x28,0x3c,0x49,0x8b}, {0xff,0x0d,0x95,0x41},
{0x39,0xa8,0x01,0x71}, {0x08,0x0c,0xb3,0xde}, {0xd8,0xb4,0xe4,0x9c}, {0x64,0x56,0xc1,0x90},
{0x7b,0xcb,0x84,0x61}, {0xd5,0x32,0xb6,0x70}, {0x48,0x6c,0x5c,0x74}, {0xd0,0xb8,0x57,0x42}
+ }
};
+#define T5 xT5.xt8
-static word8 T6[256][4] = {
+static const union xtab xT6 = {
+ .xt8 = {
{0x50,0x51,0xf4,0xa7}, {0x53,0x7e,0x41,0x65}, {0xc3,0x1a,0x17,0xa4}, {0x96,0x3a,0x27,0x5e},
{0xcb,0x3b,0xab,0x6b}, {0xf1,0x1f,0x9d,0x45}, {0xab,0xac,0xfa,0x58}, {0x93,0x4b,0xe3,0x03},
{0x55,0x20,0x30,0xfa}, {0xf6,0xad,0x76,0x6d}, {0x91,0x88,0xcc,0x76}, {0x25,0xf5,0x02,0x4c},
@@ -440,9 +462,12 @@ static word8 T6[256][4] = {
{0x72,0x16,0x1d,0xc3}, {0x0c,0xbc,0xe2,0x25}, {0x8b,0x28,0x3c,0x49}, {0x41,0xff,0x0d,0x95},
{0x71,0x39,0xa8,0x01}, {0xde,0x08,0x0c,0xb3}, {0x9c,0xd8,0xb4,0xe4}, {0x90,0x64,0x56,0xc1},
{0x61,0x7b,0xcb,0x84}, {0x70,0xd5,0x32,0xb6}, {0x74,0x48,0x6c,0x5c}, {0x42,0xd0,0xb8,0x57}
+ }
};
+#define T6 xT6.xt8
-static word8 T7[256][4] = {
+static const union xtab xT7 = {
+ .xt8 = {
{0xa7,0x50,0x51,0xf4}, {0x65,0x53,0x7e,0x41}, {0xa4,0xc3,0x1a,0x17}, {0x5e,0x96,0x3a,0x27},
{0x6b,0xcb,0x3b,0xab}, {0x45,0xf1,0x1f,0x9d}, {0x58,0xab,0xac,0xfa}, {0x03,0x93,0x4b,0xe3},
{0xfa,0x55,0x20,0x30}, {0x6d,0xf6,0xad,0x76}, {0x76,0x91,0x88,0xcc}, {0x4c,0x25,0xf5,0x02},
@@ -507,9 +532,12 @@ static word8 T7[256][4] = {
{0xc3,0x72,0x16,0x1d}, {0x25,0x0c,0xbc,0xe2}, {0x49,0x8b,0x28,0x3c}, {0x95,0x41,0xff,0x0d},
{0x01,0x71,0x39,0xa8}, {0xb3,0xde,0x08,0x0c}, {0xe4,0x9c,0xd8,0xb4}, {0xc1,0x90,0x64,0x56},
{0x84,0x61,0x7b,0xcb}, {0xb6,0x70,0xd5,0x32}, {0x5c,0x74,0x48,0x6c}, {0x57,0x42,0xd0,0xb8}
+ }
};
+#define T7 xT7.xt8
-static word8 T8[256][4] = {
+static const union xtab xT8 = {
+ .xt8 = {
{0xf4,0xa7,0x50,0x51}, {0x41,0x65,0x53,0x7e}, {0x17,0xa4,0xc3,0x1a}, {0x27,0x5e,0x96,0x3a},
{0xab,0x6b,0xcb,0x3b}, {0x9d,0x45,0xf1,0x1f}, {0xfa,0x58,0xab,0xac}, {0xe3,0x03,0x93,0x4b},
{0x30,0xfa,0x55,0x20}, {0x76,0x6d,0xf6,0xad}, {0xcc,0x76,0x91,0x88}, {0x02,0x4c,0x25,0xf5},
@@ -574,9 +602,11 @@ static word8 T8[256][4] = {
{0x1d,0xc3,0x72,0x16}, {0xe2,0x25,0x0c,0xbc}, {0x3c,0x49,0x8b,0x28}, {0x0d,0x95,0x41,0xff},
{0xa8,0x01,0x71,0x39}, {0x0c,0xb3,0xde,0x08}, {0xb4,0xe4,0x9c,0xd8}, {0x56,0xc1,0x90,0x64},
{0xcb,0x84,0x61,0x7b}, {0x32,0xb6,0x70,0xd5}, {0x6c,0x5c,0x74,0x48}, {0xb8,0x57,0x42,0xd0}
+ }
};
+#define T8 xT8.xt8
-static word8 S5[256] = {
+static const word8 S5[256] = {
0x52,0x09,0x6a,0xd5,
0x30,0x36,0xa5,0x38,
0xbf,0x40,0xa3,0x9e,
@@ -643,7 +673,8 @@ static word8 S5[256] = {
0x55,0x21,0x0c,0x7d
};
-static word8 U1[256][4] = {
+static const union xtab xU1 = {
+ .xt8 = {
{0x00,0x00,0x00,0x00}, {0x0e,0x09,0x0d,0x0b}, {0x1c,0x12,0x1a,0x16}, {0x12,0x1b,0x17,0x1d},
{0x38,0x24,0x34,0x2c}, {0x36,0x2d,0x39,0x27}, {0x24,0x36,0x2e,0x3a}, {0x2a,0x3f,0x23,0x31},
{0x70,0x48,0x68,0x58}, {0x7e,0x41,0x65,0x53}, {0x6c,0x5a,0x72,0x4e}, {0x62,0x53,0x7f,0x45},
@@ -708,9 +739,12 @@ static word8 U1[256][4] = {
{0xef,0x15,0xe8,0xe6}, {0xe1,0x1c,0xe5,0xed}, {0xf3,0x07,0xf2,0xf0}, {0xfd,0x0e,0xff,0xfb},
{0xa7,0x79,0xb4,0x92}, {0xa9,0x70,0xb9,0x99}, {0xbb,0x6b,0xae,0x84}, {0xb5,0x62,0xa3,0x8f},
{0x9f,0x5d,0x80,0xbe}, {0x91,0x54,0x8d,0xb5}, {0x83,0x4f,0x9a,0xa8}, {0x8d,0x46,0x97,0xa3}
+ }
};
+#define U1 xU1.xt8
-static word8 U2[256][4] = {
+static const union xtab xU2 = {
+ .xt8 = {
{0x00,0x00,0x00,0x00}, {0x0b,0x0e,0x09,0x0d}, {0x16,0x1c,0x12,0x1a}, {0x1d,0x12,0x1b,0x17},
{0x2c,0x38,0x24,0x34}, {0x27,0x36,0x2d,0x39}, {0x3a,0x24,0x36,0x2e}, {0x31,0x2a,0x3f,0x23},
{0x58,0x70,0x48,0x68}, {0x53,0x7e,0x41,0x65}, {0x4e,0x6c,0x5a,0x72}, {0x45,0x62,0x53,0x7f},
@@ -775,9 +809,12 @@ static word8 U2[256][4] = {
{0xe6,0xef,0x15,0xe8}, {0xed,0xe1,0x1c,0xe5}, {0xf0,0xf3,0x07,0xf2}, {0xfb,0xfd,0x0e,0xff},
{0x92,0xa7,0x79,0xb4}, {0x99,0xa9,0x70,0xb9}, {0x84,0xbb,0x6b,0xae}, {0x8f,0xb5,0x62,0xa3},
{0xbe,0x9f,0x5d,0x80}, {0xb5,0x91,0x54,0x8d}, {0xa8,0x83,0x4f,0x9a}, {0xa3,0x8d,0x46,0x97}
+ }
};
+#define U2 xU2.xt8
-static word8 U3[256][4] = {
+static const union xtab xU3 = {
+ .xt8 = {
{0x00,0x00,0x00,0x00}, {0x0d,0x0b,0x0e,0x09}, {0x1a,0x16,0x1c,0x12}, {0x17,0x1d,0x12,0x1b},
{0x34,0x2c,0x38,0x24}, {0x39,0x27,0x36,0x2d}, {0x2e,0x3a,0x24,0x36}, {0x23,0x31,0x2a,0x3f},
{0x68,0x58,0x70,0x48}, {0x65,0x53,0x7e,0x41}, {0x72,0x4e,0x6c,0x5a}, {0x7f,0x45,0x62,0x53},
@@ -842,9 +879,12 @@ static word8 U3[256][4] = {
{0xe8,0xe6,0xef,0x15}, {0xe5,0xed,0xe1,0x1c}, {0xf2,0xf0,0xf3,0x07}, {0xff,0xfb,0xfd,0x0e},
{0xb4,0x92,0xa7,0x79}, {0xb9,0x99,0xa9,0x70}, {0xae,0x84,0xbb,0x6b}, {0xa3,0x8f,0xb5,0x62},
{0x80,0xbe,0x9f,0x5d}, {0x8d,0xb5,0x91,0x54}, {0x9a,0xa8,0x83,0x4f}, {0x97,0xa3,0x8d,0x46}
+ }
};
+#define U3 xU3.xt8
-static word8 U4[256][4] = {
+static const union xtab xU4 = {
+ .xt8 = {
{0x00,0x00,0x00,0x00}, {0x09,0x0d,0x0b,0x0e}, {0x12,0x1a,0x16,0x1c}, {0x1b,0x17,0x1d,0x12},
{0x24,0x34,0x2c,0x38}, {0x2d,0x39,0x27,0x36}, {0x36,0x2e,0x3a,0x24}, {0x3f,0x23,0x31,0x2a},
{0x48,0x68,0x58,0x70}, {0x41,0x65,0x53,0x7e}, {0x5a,0x72,0x4e,0x6c}, {0x53,0x7f,0x45,0x62},
@@ -909,8 +949,10 @@ static word8 U4[256][4] = {
{0x15,0xe8,0xe6,0xef}, {0x1c,0xe5,0xed,0xe1}, {0x07,0xf2,0xf0,0xf3}, {0x0e,0xff,0xfb,0xfd},
{0x79,0xb4,0x92,0xa7}, {0x70,0xb9,0x99,0xa9}, {0x6b,0xae,0x84,0xbb}, {0x62,0xa3,0x8f,0xb5},
{0x5d,0x80,0xbe,0x9f}, {0x54,0x8d,0xb5,0x91}, {0x4f,0x9a,0xa8,0x83}, {0x46,0x97,0xa3,0x8d}
+ }
};
+#define U4 xU4.xt8
-static word32 rcon[30] = {
+static const word32 rcon[30] = {
0x01,0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
};
diff --git a/sys/crypto/rijndael/rijndael-alg-fst.c b/sys/crypto/rijndael/rijndael-alg-fst.c
index 33d0d8a..ac9668e 100644
--- a/sys/crypto/rijndael/rijndael-alg-fst.c
+++ b/sys/crypto/rijndael/rijndael-alg-fst.c
@@ -1,4 +1,5 @@
-/* $KAME$ */
+/* $FreeBSD$ */
+/* $KAME: rijndael-alg-fst.c,v 1.7 2001/05/27 00:23:23 itojun Exp $ */
/*
* rijndael-alg-fst.c v2.3 April '2000
@@ -14,6 +15,11 @@
#include <sys/cdefs.h>
#include <sys/types.h>
+#ifdef _KERNEL
+#include <sys/systm.h>
+#else
+#include <string.h>
+#endif
#include <crypto/rijndael/rijndael-alg-fst.h>
#include <crypto/rijndael/rijndael_local.h>
@@ -24,7 +30,11 @@ int rijndaelKeySched(word8 k[MAXKC][4], word8 W[MAXROUNDS+1][4][4], int ROUNDS)
* The number of calculations depends on keyBits and blockBits
*/
int j, r, t, rconpointer = 0;
- word8 tk[MAXKC][4];
+ union {
+ word8 x8[MAXKC][4];
+ word32 x32[MAXKC];
+ } xtk;
+#define tk xtk.x8
int KC = ROUNDS - 6;
for (j = KC-1; j >= 0; j--) {
@@ -79,6 +89,7 @@ int rijndaelKeySched(word8 k[MAXKC][4], word8 W[MAXROUNDS+1][4][4], int ROUNDS)
}
}
return 0;
+#undef tk
}
int rijndaelKeyEncToDec(word8 W[MAXROUNDS+1][4][4], int ROUNDS) {
@@ -120,9 +131,21 @@ int rijndaelKeyEncToDec(word8 W[MAXROUNDS+1][4][4], int ROUNDS) {
/**
* Encrypt a single block.
*/
-int rijndaelEncrypt(word8 a[16], word8 b[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) {
+int rijndaelEncrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) {
int r;
- word8 temp[4][4];
+ union {
+ word8 x8[16];
+ word32 x32[4];
+ } xa, xb;
+#define a xa.x8
+#define b xb.x8
+ union {
+ word8 x8[4][4];
+ word32 x32[4];
+ } xtemp;
+#define temp xtemp.x8
+
+ memcpy(a, in, sizeof a);
*((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[0][0]);
*((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[0][1]);
@@ -193,7 +216,12 @@ int rijndaelEncrypt(word8 a[16], word8 b[16], word8 rk[MAXROUNDS+1][4][4], int R
*((word32*)(b+ 8)) ^= *((word32*)rk[ROUNDS][2]);
*((word32*)(b+12)) ^= *((word32*)rk[ROUNDS][3]);
+ memcpy(out, b, sizeof b /* XXX out */);
+
return 0;
+#undef a
+#undef b
+#undef temp
}
#ifdef INTERMEDIATE_VALUE_KAT
@@ -268,10 +296,22 @@ int rijndaelEncryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS,
/**
* Decrypt a single block.
*/
-int rijndaelDecrypt(word8 a[16], word8 b[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) {
+int rijndaelDecrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) {
int r;
- word8 temp[4][4];
+ union {
+ word8 x8[16];
+ word32 x32[4];
+ } xa, xb;
+#define a xa.x8
+#define b xb.x8
+ union {
+ word8 x8[4][4];
+ word32 x32[4];
+ } xtemp;
+#define temp xtemp.x8
+ memcpy(a, in, sizeof a);
+
*((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[ROUNDS][0]);
*((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[ROUNDS][1]);
*((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[ROUNDS][2]);
@@ -341,7 +381,12 @@ int rijndaelDecrypt(word8 a[16], word8 b[16], word8 rk[MAXROUNDS+1][4][4], int R
*((word32*)(b+ 8)) ^= *((word32*)rk[0][2]);
*((word32*)(b+12)) ^= *((word32*)rk[0][3]);
+ memcpy(out, b, sizeof b /* XXX out */);
+
return 0;
+#undef a
+#undef b
+#undef temp
}
diff --git a/sys/crypto/rijndael/rijndael-alg-fst.h b/sys/crypto/rijndael/rijndael-alg-fst.h
index 6061bf4..5b22ef4c 100644
--- a/sys/crypto/rijndael/rijndael-alg-fst.h
+++ b/sys/crypto/rijndael/rijndael-alg-fst.h
@@ -1,4 +1,5 @@
-/* $KAME$ */
+/* $FreeBSD$ */
+/* $KAME: rijndael-alg-fst.h,v 1.4 2000/10/02 17:14:26 itojun Exp $ */
/*
* rijndael-alg-fst.h v2.3 April '2000
diff --git a/sys/crypto/rijndael/rijndael-api-fst.c b/sys/crypto/rijndael/rijndael-api-fst.c
index 1a2de50..1eec694 100644
--- a/sys/crypto/rijndael/rijndael-api-fst.c
+++ b/sys/crypto/rijndael/rijndael-api-fst.c
@@ -1,4 +1,5 @@
-/* $KAME: $ */
+/* $FreeBSD$ */
+/* $KAME: rijndael-api-fst.c,v 1.10 2001/05/27 09:34:18 itojun Exp $ */
/*
* rijndael-api-fst.c v2.3 April '2000
@@ -16,8 +17,12 @@
*/
#include <sys/param.h>
-#include <sys/systm.h>
#include <sys/types.h>
+#ifdef _KERNEL
+#include <sys/systm.h>
+#else
+#include <string.h>
+#endif
#include <crypto/rijndael/rijndael-alg-fst.h>
#include <crypto/rijndael/rijndael-api-fst.h>
#include <crypto/rijndael/rijndael_local.h>
@@ -44,36 +49,16 @@ int rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMate
}
if (keyMaterial != NULL) {
- strncpy(key->keyMaterial, keyMaterial, keyLen/4);
+ bcopy(keyMaterial, key->keyMaterial, keyLen/8);
}
key->ROUNDS = keyLen/32 + 6;
/* initialize key schedule: */
keyMat = key->keyMaterial;
-#ifndef BINARY_KEY_MATERIAL
- for (i = 0; i < key->keyLen/8; i++) {
- int t, j;
-
- t = *keyMat++;
- if ((t >= '0') && (t <= '9')) j = (t - '0') << 4;
- else if ((t >= 'a') && (t <= 'f')) j = (t - 'a' + 10) << 4;
- else if ((t >= 'A') && (t <= 'F')) j = (t - 'A' + 10) << 4;
- else return BAD_KEY_MAT;
-
- t = *keyMat++;
- if ((t >= '0') && (t <= '9')) j ^= (t - '0');
- else if ((t >= 'a') && (t <= 'f')) j ^= (t - 'a' + 10);
- else if ((t >= 'A') && (t <= 'F')) j ^= (t - 'A' + 10);
- else return BAD_KEY_MAT;
-
- k[i >> 2][i & 3] = (word8)j;
- }
-#else
for (i = 0; i < key->keyLen/8; i++) {
k[i >> 2][i & 3] = (word8)keyMat[i];
}
-#endif /* ?BINARY_KEY_MATERIAL */
rijndaelKeySched(k, key->keySched, key->ROUNDS);
if (direction == DIR_DECRYPT) {
rijndaelKeyEncToDec(key->keySched, key->ROUNDS);
@@ -89,28 +74,7 @@ int rijndael_cipherInit(cipherInstance *cipher, BYTE mode, char *IV) {
return BAD_CIPHER_MODE;
}
if (IV != NULL) {
-#ifndef BINARY_KEY_MATERIAL
- int i;
- for (i = 0; i < MAX_IV_SIZE; i++) {
- int t, j;
-
- t = IV[2*i];
- if ((t >= '0') && (t <= '9')) j = (t - '0') << 4;
- else if ((t >= 'a') && (t <= 'f')) j = (t - 'a' + 10) << 4;
- else if ((t >= 'A') && (t <= 'F')) j = (t - 'A' + 10) << 4;
- else return BAD_CIPHER_INSTANCE;
-
- t = IV[2*i+1];
- if ((t >= '0') && (t <= '9')) j ^= (t - '0');
- else if ((t >= 'a') && (t <= 'f')) j ^= (t - 'a' + 10);
- else if ((t >= 'A') && (t <= 'F')) j ^= (t - 'A' + 10);
- else return BAD_CIPHER_INSTANCE;
-
- cipher->IV[i] = (word8)j;
- }
-#else
bcopy(IV, cipher->IV, MAX_IV_SIZE);
-#endif /* ?BINARY_KEY_MATERIAL */
} else {
bzero(cipher->IV, MAX_IV_SIZE);
}
diff --git a/sys/crypto/rijndael/rijndael-api-fst.h b/sys/crypto/rijndael/rijndael-api-fst.h
index c98f3f4..a4ab920 100644
--- a/sys/crypto/rijndael/rijndael-api-fst.h
+++ b/sys/crypto/rijndael/rijndael-api-fst.h
@@ -1,4 +1,5 @@
-/* $KAME$ */
+/* $FreeBSD$ */
+/* $KAME: rijndael-api-fst.h,v 1.6 2001/05/27 00:23:23 itojun Exp $ */
/*
* rijndael-api-fst.h v2.3 April '2000
@@ -55,7 +56,11 @@ typedef struct {
/* The following parameters are algorithm dependent, replace or add as necessary */
int ROUNDS; /* key-length-dependent number of rounds */
int blockLen; /* block length */
- u_int8_t keySched[RIJNDAEL_MAXROUNDS+1][4][4]; /* key schedule */
+ union {
+ u_int8_t xkS8[RIJNDAEL_MAXROUNDS+1][4][4]; /* key schedule */
+ u_int32_t xkS32[RIJNDAEL_MAXROUNDS+1][4]; /* key schedule */
+ } xKeySched;
+#define keySched xKeySched.xkS8
} keyInstance;
/* The structure for cipher information */
diff --git a/sys/crypto/rijndael/rijndael_local.h b/sys/crypto/rijndael/rijndael_local.h
index 23e909c..a959b1b 100644
--- a/sys/crypto/rijndael/rijndael_local.h
+++ b/sys/crypto/rijndael/rijndael_local.h
@@ -9,5 +9,3 @@ typedef u_int32_t word32;
#define MAXKC RIJNDAEL_MAXKC
#define MAXROUNDS RIJNDAEL_MAXROUNDS
-
-#define BINARY_KEY_MATERIAL 1
diff --git a/sys/crypto/sha1.c b/sys/crypto/sha1.c
index bbf20b8..b210b52 100644
--- a/sys/crypto/sha1.c
+++ b/sys/crypto/sha1.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: sha1.c,v 1.4 2000/03/27 04:36:23 sumikawa Exp $ */
+/* $KAME: sha1.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
diff --git a/sys/crypto/sha2/sha2.c b/sys/crypto/sha2/sha2.c
new file mode 100644
index 0000000..9b3a5c6
--- /dev/null
+++ b/sys/crypto/sha2/sha2.c
@@ -0,0 +1,1048 @@
+/* $FreeBSD$ */
+/* $KAME: sha2.c,v 1.6 2001/03/12 11:31:04 itojun Exp $ */
+
+/*
+ * sha2.c
+ *
+ * Version 1.0.0beta1
+ *
+ * Written by Aaron D. Gifford <me@aarongifford.com>
+ *
+ * Copyright 2000 Aaron D. Gifford. 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 copyright holder nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) 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 <sys/types.h>
+#include <sys/time.h>
+#include <sys/systm.h>
+#include <machine/endian.h>
+#include <crypto/sha2/sha2.h>
+
+/*
+ * ASSERT NOTE:
+ * Some sanity checking code is included using assert(). On my FreeBSD
+ * system, this additional code can be removed by compiling with NDEBUG
+ * defined. Check your own systems manpage on assert() to see how to
+ * compile WITHOUT the sanity checking code on your system.
+ *
+ * UNROLLED TRANSFORM LOOP NOTE:
+ * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
+ * loop version for the hash transform rounds (defined using macros
+ * later in this file). Either define on the command line, for example:
+ *
+ * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
+ *
+ * or define below:
+ *
+ * #define SHA2_UNROLL_TRANSFORM
+ *
+ */
+
+#if defined(__bsdi__) || defined(__FreeBSD__)
+#define assert(x)
+#endif
+
+
+/*** SHA-256/384/512 Machine Architecture Definitions *****************/
+/*
+ * BYTE_ORDER NOTE:
+ *
+ * Please make sure that your system defines BYTE_ORDER. If your
+ * architecture is little-endian, make sure it also defines
+ * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
+ * equivilent.
+ *
+ * If your system does not define the above, then you can do so by
+ * hand like this:
+ *
+ * #define LITTLE_ENDIAN 1234
+ * #define BIG_ENDIAN 4321
+ *
+ * And for little-endian machines, add:
+ *
+ * #define BYTE_ORDER LITTLE_ENDIAN
+ *
+ * Or for big-endian machines:
+ *
+ * #define BYTE_ORDER BIG_ENDIAN
+ *
+ * The FreeBSD machine this was written on defines BYTE_ORDER
+ * appropriately by including <sys/types.h> (which in turn includes
+ * <machine/endian.h> where the appropriate definitions are actually
+ * made).
+ */
+#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN)
+#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN
+#endif
+
+/*
+ * Define the followingsha2_* types to types of the correct length on
+ * the native archtecture. Most BSD systems and Linux define u_intXX_t
+ * types. Machines with very recent ANSI C headers, can use the
+ * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H
+ * during compile or in the sha.h header file.
+ *
+ * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t
+ * will need to define these three typedefs below (and the appropriate
+ * ones in sha.h too) by hand according to their system architecture.
+ *
+ * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t
+ * types and pointing out recent ANSI C support for uintXX_t in inttypes.h.
+ */
+#if 0 /*def SHA2_USE_INTTYPES_H*/
+
+typedef uint8_t sha2_byte; /* Exactly 1 byte */
+typedef uint32_t sha2_word32; /* Exactly 4 bytes */
+typedef uint64_t sha2_word64; /* Exactly 8 bytes */
+
+#else /* SHA2_USE_INTTYPES_H */
+
+typedef u_int8_t sha2_byte; /* Exactly 1 byte */
+typedef u_int32_t sha2_word32; /* Exactly 4 bytes */
+typedef u_int64_t sha2_word64; /* Exactly 8 bytes */
+
+#endif /* SHA2_USE_INTTYPES_H */
+
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+/* NOTE: Most of these are in sha2.h */
+#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8)
+#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16)
+#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16)
+
+
+/*** ENDIAN REVERSAL MACROS *******************************************/
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define REVERSE32(w,x) { \
+ sha2_word32 tmp = (w); \
+ tmp = (tmp >> 16) | (tmp << 16); \
+ (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
+}
+#define REVERSE64(w,x) { \
+ sha2_word64 tmp = (w); \
+ tmp = (tmp >> 32) | (tmp << 32); \
+ tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
+ ((tmp & 0x00ff00ff00ff00ffULL) << 8); \
+ (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
+ ((tmp & 0x0000ffff0000ffffULL) << 16); \
+}
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+/*
+ * Macro for incrementally adding the unsigned 64-bit integer n to the
+ * unsigned 128-bit integer (represented using a two-element array of
+ * 64-bit words):
+ */
+#define ADDINC128(w,n) { \
+ (w)[0] += (sha2_word64)(n); \
+ if ((w)[0] < (n)) { \
+ (w)[1]++; \
+ } \
+}
+
+/*** THE SIX LOGICAL FUNCTIONS ****************************************/
+/*
+ * Bit shifting and rotation (used by the six SHA-XYZ logical functions:
+ *
+ * NOTE: The naming of R and S appears backwards here (R is a SHIFT and
+ * S is a ROTATION) because the SHA-256/384/512 description document
+ * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
+ * same "backwards" definition.
+ */
+/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
+#define R(b,x) ((x) >> (b))
+/* 32-bit Rotate-right (used in SHA-256): */
+#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b))))
+/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
+#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b))))
+
+/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
+#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+/* Four of six logical functions used in SHA-256: */
+#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x)))
+#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x)))
+#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x)))
+#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x)))
+
+/* Four of six logical functions used in SHA-384 and SHA-512: */
+#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
+#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
+#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x)))
+#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x)))
+
+/*** INTERNAL FUNCTION PROTOTYPES *************************************/
+/* NOTE: These should not be accessed directly from outside this
+ * library -- they are intended for private internal visibility/use
+ * only.
+ */
+void SHA512_Last(SHA512_CTX*);
+void SHA256_Transform(SHA256_CTX*, const sha2_word32*);
+void SHA512_Transform(SHA512_CTX*, const sha2_word64*);
+
+
+/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
+/* Hash constant words K for SHA-256: */
+const static sha2_word32 K256[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+ 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+ 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+ 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+ 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+ 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+ 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
+ 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+ 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+ 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+ 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+ 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+ 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Initial hash value H for SHA-256: */
+const static sha2_word32 sha256_initial_hash_value[8] = {
+ 0x6a09e667UL,
+ 0xbb67ae85UL,
+ 0x3c6ef372UL,
+ 0xa54ff53aUL,
+ 0x510e527fUL,
+ 0x9b05688cUL,
+ 0x1f83d9abUL,
+ 0x5be0cd19UL
+};
+
+/* Hash constant words K for SHA-384 and SHA-512: */
+const static sha2_word64 K512[80] = {
+ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
+ 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+ 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+ 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
+ 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
+ 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+ 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+ 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
+ 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
+ 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+ 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+ 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
+ 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
+ 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+ 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+ 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
+ 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
+ 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+ 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+ 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
+ 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
+ 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+ 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+ 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
+ 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
+ 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+ 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+/* Initial hash value H for SHA-384 */
+const static sha2_word64 sha384_initial_hash_value[8] = {
+ 0xcbbb9d5dc1059ed8ULL,
+ 0x629a292a367cd507ULL,
+ 0x9159015a3070dd17ULL,
+ 0x152fecd8f70e5939ULL,
+ 0x67332667ffc00b31ULL,
+ 0x8eb44a8768581511ULL,
+ 0xdb0c2e0d64f98fa7ULL,
+ 0x47b5481dbefa4fa4ULL
+};
+
+/* Initial hash value H for SHA-512 */
+const static sha2_word64 sha512_initial_hash_value[8] = {
+ 0x6a09e667f3bcc908ULL,
+ 0xbb67ae8584caa73bULL,
+ 0x3c6ef372fe94f82bULL,
+ 0xa54ff53a5f1d36f1ULL,
+ 0x510e527fade682d1ULL,
+ 0x9b05688c2b3e6c1fULL,
+ 0x1f83d9abfb41bd6bULL,
+ 0x5be0cd19137e2179ULL
+};
+
+/*
+ * Constant used by SHA256/384/512_End() functions for converting the
+ * digest to a readable hexadecimal character string:
+ */
+static const char *sha2_hex_digits = "0123456789abcdef";
+
+
+/*** SHA-256: *********************************************************/
+void SHA256_Init(SHA256_CTX* context) {
+ if (context == (SHA256_CTX*)0) {
+ return;
+ }
+ bcopy(sha256_initial_hash_value, context->state, SHA256_DIGEST_LENGTH);
+ bzero(context->buffer, SHA256_BLOCK_LENGTH);
+ context->bitcount = 0;
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-256 round macros: */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
+ REVERSE32(*data++, W256[j]); \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+ K256[j] + W256[j]; \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+ K256[j] + (W256[j] = *data++); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256(a,b,c,d,e,f,g,h) \
+ s0 = W256[(j+1)&0x0f]; \
+ s0 = sigma0_256(s0); \
+ s1 = W256[(j+14)&0x0f]; \
+ s1 = sigma1_256(s1); \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
+ sha2_word32 a, b, c, d, e, f, g, h, s0, s1;
+ sha2_word32 T1, *W256;
+ int j;
+
+ W256 = (sha2_word32*)context->buffer;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+ /* Rounds 0 to 15 (unrolled): */
+ ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
+ ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
+ ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
+ ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
+ ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
+ ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
+ ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
+ ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
+ } while (j < 16);
+
+ /* Now for the remaining rounds to 64: */
+ do {
+ ROUND256(a,b,c,d,e,f,g,h);
+ ROUND256(h,a,b,c,d,e,f,g);
+ ROUND256(g,h,a,b,c,d,e,f);
+ ROUND256(f,g,h,a,b,c,d,e);
+ ROUND256(e,f,g,h,a,b,c,d);
+ ROUND256(d,e,f,g,h,a,b,c);
+ ROUND256(c,d,e,f,g,h,a,b);
+ ROUND256(b,c,d,e,f,g,h,a);
+ } while (j < 64);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
+ sha2_word32 a, b, c, d, e, f, g, h, s0, s1;
+ sha2_word32 T1, T2, *W256;
+ int j;
+
+ W256 = (sha2_word32*)context->buffer;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Copy data while converting to host byte order */
+ REVERSE32(*data++,W256[j]);
+ /* Apply the SHA-256 compression function to update a..h */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+ /* Apply the SHA-256 compression function to update a..h with copy */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+ T2 = Sigma0_256(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 16);
+
+ do {
+ /* Part of the message block expansion: */
+ s0 = W256[(j+1)&0x0f];
+ s0 = sigma0_256(s0);
+ s1 = W256[(j+14)&0x0f];
+ s1 = sigma1_256(s1);
+
+ /* Apply the SHA-256 compression function to update a..h */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
+ T2 = Sigma0_256(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 64);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) {
+ unsigned int freespace, usedspace;
+
+ if (len == 0) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0);
+
+ usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
+ if (usedspace > 0) {
+ /* Calculate how much free space is available in the buffer */
+ freespace = SHA256_BLOCK_LENGTH - usedspace;
+
+ if (len >= freespace) {
+ /* Fill the buffer completely and process it */
+ bcopy(data, &context->buffer[usedspace], freespace);
+ context->bitcount += freespace << 3;
+ len -= freespace;
+ data += freespace;
+ SHA256_Transform(context, (sha2_word32*)context->buffer);
+ } else {
+ /* The buffer is not yet full */
+ bcopy(data, &context->buffer[usedspace], len);
+ context->bitcount += len << 3;
+ /* Clean up: */
+ usedspace = freespace = 0;
+ return;
+ }
+ }
+ while (len >= SHA256_BLOCK_LENGTH) {
+ /* Process as many complete blocks as we can */
+ SHA256_Transform(context, (sha2_word32*)data);
+ context->bitcount += SHA256_BLOCK_LENGTH << 3;
+ len -= SHA256_BLOCK_LENGTH;
+ data += SHA256_BLOCK_LENGTH;
+ }
+ if (len > 0) {
+ /* There's left-overs, so save 'em */
+ bcopy(data, context->buffer, len);
+ context->bitcount += len << 3;
+ }
+ /* Clean up: */
+ usedspace = freespace = 0;
+}
+
+void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) {
+ sha2_word32 *d = (sha2_word32*)digest;
+ unsigned int usedspace;
+
+ /* Sanity check: */
+ assert(context != (SHA256_CTX*)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (sha2_byte*)0) {
+ usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert FROM host byte order */
+ REVERSE64(context->bitcount,context->bitcount);
+#endif
+ if (usedspace > 0) {
+ /* Begin padding with a 1 bit: */
+ context->buffer[usedspace++] = 0x80;
+
+ if (usedspace < SHA256_SHORT_BLOCK_LENGTH) {
+ /* Set-up for the last transform: */
+ bzero(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace);
+ } else {
+ if (usedspace < SHA256_BLOCK_LENGTH) {
+ bzero(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace);
+ }
+ /* Do second-to-last transform: */
+ SHA256_Transform(context, (sha2_word32*)context->buffer);
+
+ /* And set-up for the last transform: */
+ bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH);
+ }
+ } else {
+ /* Set-up for the last transform: */
+ bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH);
+
+ /* Begin padding with a 1 bit: */
+ *context->buffer = 0x80;
+ }
+ /* Set the bit count: */
+ *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount;
+
+ /* Final transform: */
+ SHA256_Transform(context, (sha2_word32*)context->buffer);
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < 8; j++) {
+ REVERSE32(context->state[j],context->state[j]);
+ *d++ = context->state[j];
+ }
+ }
+#else
+ bcopy(context->state, d, SHA256_DIGEST_LENGTH);
+#endif
+ }
+
+ /* Clean up state data: */
+ bzero(context, sizeof(context));
+ usedspace = 0;
+}
+
+char *SHA256_End(SHA256_CTX* context, char buffer[]) {
+ sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest;
+ int i;
+
+ /* Sanity check: */
+ assert(context != (SHA256_CTX*)0);
+
+ if (buffer != (char*)0) {
+ SHA256_Final(digest, context);
+
+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+ bzero(context, sizeof(context));
+ }
+ bzero(digest, SHA256_DIGEST_LENGTH);
+ return buffer;
+}
+
+char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) {
+ SHA256_CTX context;
+
+ SHA256_Init(&context);
+ SHA256_Update(&context, data, len);
+ return SHA256_End(&context, digest);
+}
+
+
+/*** SHA-512: *********************************************************/
+void SHA512_Init(SHA512_CTX* context) {
+ if (context == (SHA512_CTX*)0) {
+ return;
+ }
+ bcopy(sha512_initial_hash_value, context->state, SHA512_DIGEST_LENGTH);
+ bzero(context->buffer, SHA512_BLOCK_LENGTH);
+ context->bitcount[0] = context->bitcount[1] = 0;
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-512 round macros: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
+ REVERSE64(*data++, W512[j]); \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+ K512[j] + W512[j]; \
+ (d) += T1, \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \
+ j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+ K512[j] + (W512[j] = *data++); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+ j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512(a,b,c,d,e,f,g,h) \
+ s0 = W512[(j+1)&0x0f]; \
+ s0 = sigma0_512(s0); \
+ s1 = W512[(j+14)&0x0f]; \
+ s1 = sigma1_512(s1); \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \
+ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+ j++
+
+void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
+ sha2_word64 a, b, c, d, e, f, g, h, s0, s1;
+ sha2_word64 T1, *W512 = (sha2_word64*)context->buffer;
+ int j;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+ ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
+ ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
+ ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
+ ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
+ ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
+ ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
+ ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
+ ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
+ } while (j < 16);
+
+ /* Now for the remaining rounds up to 79: */
+ do {
+ ROUND512(a,b,c,d,e,f,g,h);
+ ROUND512(h,a,b,c,d,e,f,g);
+ ROUND512(g,h,a,b,c,d,e,f);
+ ROUND512(f,g,h,a,b,c,d,e);
+ ROUND512(e,f,g,h,a,b,c,d);
+ ROUND512(d,e,f,g,h,a,b,c);
+ ROUND512(c,d,e,f,g,h,a,b);
+ ROUND512(b,c,d,e,f,g,h,a);
+ } while (j < 80);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
+ sha2_word64 a, b, c, d, e, f, g, h, s0, s1;
+ sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer;
+ int j;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert TO host byte order */
+ REVERSE64(*data++, W512[j]);
+ /* Apply the SHA-512 compression function to update a..h */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+ /* Apply the SHA-512 compression function to update a..h with copy */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+ T2 = Sigma0_512(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 16);
+
+ do {
+ /* Part of the message block expansion: */
+ s0 = W512[(j+1)&0x0f];
+ s0 = sigma0_512(s0);
+ s1 = W512[(j+14)&0x0f];
+ s1 = sigma1_512(s1);
+
+ /* Apply the SHA-512 compression function to update a..h */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
+ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
+ T2 = Sigma0_512(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 80);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) {
+ unsigned int freespace, usedspace;
+
+ if (len == 0) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0);
+
+ usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+ if (usedspace > 0) {
+ /* Calculate how much free space is available in the buffer */
+ freespace = SHA512_BLOCK_LENGTH - usedspace;
+
+ if (len >= freespace) {
+ /* Fill the buffer completely and process it */
+ bcopy(data, &context->buffer[usedspace], freespace);
+ ADDINC128(context->bitcount, freespace << 3);
+ len -= freespace;
+ data += freespace;
+ SHA512_Transform(context, (sha2_word64*)context->buffer);
+ } else {
+ /* The buffer is not yet full */
+ bcopy(data, &context->buffer[usedspace], len);
+ ADDINC128(context->bitcount, len << 3);
+ /* Clean up: */
+ usedspace = freespace = 0;
+ return;
+ }
+ }
+ while (len >= SHA512_BLOCK_LENGTH) {
+ /* Process as many complete blocks as we can */
+ SHA512_Transform(context, (sha2_word64*)data);
+ ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
+ len -= SHA512_BLOCK_LENGTH;
+ data += SHA512_BLOCK_LENGTH;
+ }
+ if (len > 0) {
+ /* There's left-overs, so save 'em */
+ bcopy(data, context->buffer, len);
+ ADDINC128(context->bitcount, len << 3);
+ }
+ /* Clean up: */
+ usedspace = freespace = 0;
+}
+
+void SHA512_Last(SHA512_CTX* context) {
+ unsigned int usedspace;
+
+ usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert FROM host byte order */
+ REVERSE64(context->bitcount[0],context->bitcount[0]);
+ REVERSE64(context->bitcount[1],context->bitcount[1]);
+#endif
+ if (usedspace > 0) {
+ /* Begin padding with a 1 bit: */
+ context->buffer[usedspace++] = 0x80;
+
+ if (usedspace < SHA512_SHORT_BLOCK_LENGTH) {
+ /* Set-up for the last transform: */
+ bzero(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace);
+ } else {
+ if (usedspace < SHA512_BLOCK_LENGTH) {
+ bzero(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace);
+ }
+ /* Do second-to-last transform: */
+ SHA512_Transform(context, (sha2_word64*)context->buffer);
+
+ /* And set-up for the last transform: */
+ bzero(context->buffer, SHA512_BLOCK_LENGTH - 2);
+ }
+ } else {
+ /* Prepare for final transform: */
+ bzero(context->buffer, SHA512_SHORT_BLOCK_LENGTH);
+
+ /* Begin padding with a 1 bit: */
+ *context->buffer = 0x80;
+ }
+ /* Store the length of input data (in bits): */
+ *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1];
+ *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0];
+
+ /* Final transform: */
+ SHA512_Transform(context, (sha2_word64*)context->buffer);
+}
+
+void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {
+ sha2_word64 *d = (sha2_word64*)digest;
+
+ /* Sanity check: */
+ assert(context != (SHA512_CTX*)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (sha2_byte*)0) {
+ SHA512_Last(context);
+
+ /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < 8; j++) {
+ REVERSE64(context->state[j],context->state[j]);
+ *d++ = context->state[j];
+ }
+ }
+#else
+ bcopy(context->state, d, SHA512_DIGEST_LENGTH);
+#endif
+ }
+
+ /* Zero out state data */
+ bzero(context, sizeof(context));
+}
+
+char *SHA512_End(SHA512_CTX* context, char buffer[]) {
+ sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest;
+ int i;
+
+ /* Sanity check: */
+ assert(context != (SHA512_CTX*)0);
+
+ if (buffer != (char*)0) {
+ SHA512_Final(digest, context);
+
+ for (i = 0; i < SHA512_DIGEST_LENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+ bzero(context, sizeof(context));
+ }
+ bzero(digest, SHA512_DIGEST_LENGTH);
+ return buffer;
+}
+
+char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) {
+ SHA512_CTX context;
+
+ SHA512_Init(&context);
+ SHA512_Update(&context, data, len);
+ return SHA512_End(&context, digest);
+}
+
+
+/*** SHA-384: *********************************************************/
+void SHA384_Init(SHA384_CTX* context) {
+ if (context == (SHA384_CTX*)0) {
+ return;
+ }
+ bcopy(sha384_initial_hash_value, context->state, SHA512_DIGEST_LENGTH);
+ bzero(context->buffer, SHA384_BLOCK_LENGTH);
+ context->bitcount[0] = context->bitcount[1] = 0;
+}
+
+void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) {
+ SHA512_Update((SHA512_CTX*)context, data, len);
+}
+
+void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) {
+ sha2_word64 *d = (sha2_word64*)digest;
+
+ /* Sanity check: */
+ assert(context != (SHA384_CTX*)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (sha2_byte*)0) {
+ SHA512_Last((SHA512_CTX*)context);
+
+ /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < 6; j++) {
+ REVERSE64(context->state[j],context->state[j]);
+ *d++ = context->state[j];
+ }
+ }
+#else
+ bcopy(context->state, d, SHA384_DIGEST_LENGTH);
+#endif
+ }
+
+ /* Zero out state data */
+ bzero(context, sizeof(context));
+}
+
+char *SHA384_End(SHA384_CTX* context, char buffer[]) {
+ sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest;
+ int i;
+
+ /* Sanity check: */
+ assert(context != (SHA384_CTX*)0);
+
+ if (buffer != (char*)0) {
+ SHA384_Final(digest, context);
+
+ for (i = 0; i < SHA384_DIGEST_LENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+ bzero(context, sizeof(context));
+ }
+ bzero(digest, SHA384_DIGEST_LENGTH);
+ return buffer;
+}
+
+char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) {
+ SHA384_CTX context;
+
+ SHA384_Init(&context);
+ SHA384_Update(&context, data, len);
+ return SHA384_End(&context, digest);
+}
+
diff --git a/sys/crypto/sha2/sha2.h b/sys/crypto/sha2/sha2.h
new file mode 100644
index 0000000..084faa7
--- /dev/null
+++ b/sys/crypto/sha2/sha2.h
@@ -0,0 +1,141 @@
+/* $FreeBSD$ */
+/* $KAME: sha2.h,v 1.3 2001/03/12 08:27:48 itojun Exp $ */
+
+/*
+ * sha2.h
+ *
+ * Version 1.0.0beta1
+ *
+ * Written by Aaron D. Gifford <me@aarongifford.com>
+ *
+ * Copyright 2000 Aaron D. Gifford. 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 copyright holder nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) 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.
+ *
+ */
+
+#ifndef __SHA2_H__
+#define __SHA2_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+#define SHA256_BLOCK_LENGTH 64
+#define SHA256_DIGEST_LENGTH 32
+#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1)
+#define SHA384_BLOCK_LENGTH 128
+#define SHA384_DIGEST_LENGTH 48
+#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1)
+#define SHA512_BLOCK_LENGTH 128
+#define SHA512_DIGEST_LENGTH 64
+#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1)
+
+
+/*** SHA-256/384/512 Context Structures *******************************/
+/* NOTE: If your architecture does not define either u_intXX_t types or
+ * uintXX_t (from inttypes.h), you may need to define things by hand
+ * for your system:
+ */
+#if 0
+typedef unsigned char u_int8_t; /* 1-byte (8-bits) */
+typedef unsigned int u_int32_t; /* 4-bytes (32-bits) */
+typedef unsigned long long u_int64_t; /* 8-bytes (64-bits) */
+#endif
+/*
+ * Most BSD systems already define u_intXX_t types, as does Linux.
+ * Some systems, however, like Compaq's Tru64 Unix instead can use
+ * uintXX_t types defined by very recent ANSI C standards and included
+ * in the file:
+ *
+ * #include <inttypes.h>
+ *
+ * If you choose to use <inttypes.h> then please define:
+ *
+ * #define SHA2_USE_INTTYPES_H
+ *
+ * Or on the command line during compile:
+ *
+ * cc -DSHA2_USE_INTTYPES_H ...
+ */
+#if 0 /*def SHA2_USE_INTTYPES_H*/
+
+typedef struct _SHA256_CTX {
+ uint32_t state[8];
+ uint64_t bitcount;
+ uint8_t buffer[SHA256_BLOCK_LENGTH];
+} SHA256_CTX;
+typedef struct _SHA512_CTX {
+ uint64_t state[8];
+ uint64_t bitcount[2];
+ uint8_t buffer[SHA512_BLOCK_LENGTH];
+} SHA512_CTX;
+
+#else /* SHA2_USE_INTTYPES_H */
+
+typedef struct _SHA256_CTX {
+ u_int32_t state[8];
+ u_int64_t bitcount;
+ u_int8_t buffer[SHA256_BLOCK_LENGTH];
+} SHA256_CTX;
+typedef struct _SHA512_CTX {
+ u_int64_t state[8];
+ u_int64_t bitcount[2];
+ u_int8_t buffer[SHA512_BLOCK_LENGTH];
+} SHA512_CTX;
+
+#endif /* SHA2_USE_INTTYPES_H */
+
+typedef SHA512_CTX SHA384_CTX;
+
+
+/*** SHA-256/384/512 Function Prototypes ******************************/
+
+void SHA256_Init __P((SHA256_CTX *));
+void SHA256_Update __P((SHA256_CTX*, const u_int8_t*, size_t));
+void SHA256_Final __P((u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*));
+char* SHA256_End __P((SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]));
+char* SHA256_Data __P((const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]));
+
+void SHA384_Init __P((SHA384_CTX*));
+void SHA384_Update __P((SHA384_CTX*, const u_int8_t*, size_t));
+void SHA384_Final __P((u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*));
+char* SHA384_End __P((SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]));
+char* SHA384_Data __P((const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]));
+
+void SHA512_Init __P((SHA512_CTX*));
+void SHA512_Update __P((SHA512_CTX*, const u_int8_t*, size_t));
+void SHA512_Final __P((u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*));
+char* SHA512_End __P((SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]));
+char* SHA512_Data __P((const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]));
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __SHA2_H__ */
+
diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c
index 0e3b6a3..6223bad 100644
--- a/sys/kern/uipc_domain.c
+++ b/sys/kern/uipc_domain.c
@@ -209,6 +209,32 @@ pfctlinput(cmd, sa)
(*pr->pr_ctlinput)(cmd, sa, (void *)0);
}
+void
+pfctlinput2(cmd, sa, ctlparam)
+ int cmd;
+ struct sockaddr *sa;
+ void *ctlparam;
+{
+ struct domain *dp;
+ struct protosw *pr;
+
+ if (!sa)
+ return;
+ for (dp = domains; dp; dp = dp->dom_next) {
+ /*
+ * the check must be made by xx_ctlinput() anyways, to
+ * make sure we use data item pointed to by ctlparam in
+ * correct way. the following check is made just for safety.
+ */
+ if (dp->dom_family != sa->sa_family)
+ continue;
+
+ for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
+ if (pr->pr_ctlinput)
+ (*pr->pr_ctlinput)(cmd, sa, ctlparam);
+ }
+}
+
static void
pfslowtimo(arg)
void *arg;
diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c
index df9db28..b30975b 100644
--- a/sys/kern/uipc_mbuf.c
+++ b/sys/kern/uipc_mbuf.c
@@ -570,15 +570,6 @@ m_freem(struct mbuf *m)
if (m == NULL)
return;
do {
- /*
- * we do need to check non-first mbuf, since some of existing
- * code does not call M_PREPEND properly.
- * (example: call to bpf_mtap from drivers)
- */
- if ((m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.aux) {
- m_freem(m->m_pkthdr.aux);
- m->m_pkthdr.aux = NULL;
- }
MFREE(m, n);
m = n;
} while (m);
diff --git a/sys/kern/uipc_mbuf2.c b/sys/kern/uipc_mbuf2.c
index b00bf7f..f2ce41f 100644
--- a/sys/kern/uipc_mbuf2.c
+++ b/sys/kern/uipc_mbuf2.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: uipc_mbuf2.c,v 1.15 2000/02/22 14:01:37 itojun Exp $ */
+/* $KAME: uipc_mbuf2.c,v 1.29 2001/02/14 13:42:10 itojun Exp $ */
/* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */
/*
@@ -75,6 +75,9 @@
#include <sys/mbuf.h>
#include <sys/mutex.h>
+/* can't call it m_dup(), as freebsd[34] uses m_dup() with different arg */
+static struct mbuf *m_dup1 __P((struct mbuf *, int, int, int));
+
/*
* ensure that [off, off + len) is contiguous on the mbuf chain "m".
* packet chain before "off" is kept untouched.
@@ -125,20 +128,47 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp)
}
/*
+ * XXX: This code is flawed because it considers a "writable" mbuf
+ * data region to require all of the following:
+ * (i) mbuf _has_ to have M_EXT set; if it is just a regular
+ * mbuf, it is still not considered "writable."
+ * (ii) since mbuf has M_EXT, the ext_type _has_ to be
+ * EXT_CLUSTER. Anything else makes it non-writable.
+ * (iii) M_WRITABLE() must evaluate true.
+ * Ideally, the requirement should only be (iii).
+ *
+ * If we're writable, we're sure we're writable, because the ref. count
+ * cannot increase from 1, as that would require posession of mbuf
+ * n by someone else (which is impossible). However, if we're _not_
+ * writable, we may eventually become writable )if the ref. count drops
+ * to 1), but we'll fail to notice it unless we re-evaluate
+ * M_WRITABLE(). For now, we only evaluate once at the beginning and
+ * live with this.
+ */
+ /*
+ * XXX: This is dumb. If we're just a regular mbuf with no M_EXT,
+ * then we're not "writable," according to this code.
+ */
+ writable = 0;
+ if ((n->m_flags & M_EXT) == 0 ||
+ (n->m_ext.ext_type == EXT_CLUSTER && M_WRITABLE(n)))
+ writable = 1;
+
+ /*
* the target data is on <n, off>.
* if we got enough data on the mbuf "n", we're done.
*/
- if ((off == 0 || offp) && len <= n->m_len - off)
+ if ((off == 0 || offp) && len <= n->m_len - off && writable)
goto ok;
/*
- * when len < n->m_len - off and off != 0, it is a special case.
+ * when len <= n->m_len - off and off != 0, it is a special case.
* len bytes from <n, off> sits in single mbuf, but the caller does
* not like the starting position (off).
* chop the current mbuf into two pieces, set off to 0.
*/
- if (len < n->m_len - off) {
- o = m_copym(n, off, n->m_len - off, M_DONTWAIT);
+ if (len <= n->m_len - off) {
+ o = m_dup1(n, off, n->m_len - off, M_DONTWAIT);
if (o == NULL) {
m_freem(m);
return NULL; /* ENOBUFS */
@@ -175,33 +205,6 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp)
* easy cases first.
* we need to use m_copydata() to get data from <n->m_next, 0>.
*/
- /*
- * XXX: This code is flawed because it considers a "writable" mbuf
- * data region to require all of the following:
- * (i) mbuf _has_ to have M_EXT set; if it is just a regular
- * mbuf, it is still not considered "writable."
- * (ii) since mbuf has M_EXT, the ext_type _has_ to be
- * EXT_CLUSTER. Anything else makes it non-writable.
- * (iii) M_WRITABLE() must evaluate true.
- * Ideally, the requirement should only be (iii).
- *
- * If we're writable, we're sure we're writable, because the ref. count
- * cannot increase from 1, as that would require posession of mbuf
- * n by someone else (which is impossible). However, if we're _not_
- * writable, we may eventually become writable )if the ref. count drops
- * to 1), but we'll fail to notice it unless we re-evaluate
- * M_WRITABLE(). For now, we only evaluate once at the beginning and
- * live with this.
- */
- /*
- * XXX: This is dumb. If we're just a regular mbuf with no M_EXT,
- * then we're not "writable," according to this code.
- */
- writable = 0;
- if ((n->m_flags & M_EXT) && (n->m_ext.ext_type == EXT_CLUSTER) &&
- M_WRITABLE(n))
- writable = 1;
-
if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
&& writable) {
m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
@@ -225,18 +228,17 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp)
* on both end.
*/
MGET(o, M_DONTWAIT, m->m_type);
- if (o == NULL) {
- m_freem(m);
- return NULL; /* ENOBUFS */
- }
- if (len > MHLEN) { /* use MHLEN just for safety */
+ if (o && len > MLEN) {
MCLGET(o, M_DONTWAIT);
if ((o->m_flags & M_EXT) == 0) {
- m_freem(m);
m_free(o);
- return NULL; /* ENOBUFS */
+ o = NULL;
}
}
+ if (!o) {
+ m_freem(m);
+ return NULL; /* ENOBUFS */
+ }
/* get hlen from <n, off> into <o, 0> */
o->m_len = hlen;
bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
@@ -265,12 +267,46 @@ ok:
return n;
}
+static struct mbuf *
+m_dup1(struct mbuf *m, int off, int len, int wait)
+{
+ struct mbuf *n;
+ int l;
+ int copyhdr;
+
+ if (len > MCLBYTES)
+ return NULL;
+ if (off == 0 && (m->m_flags & M_PKTHDR) != 0) {
+ copyhdr = 1;
+ MGETHDR(n, wait, m->m_type);
+ l = MHLEN;
+ } else {
+ copyhdr = 0;
+ MGET(n, wait, m->m_type);
+ l = MLEN;
+ }
+ if (n && len > l) {
+ MCLGET(n, wait);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_free(n);
+ n = NULL;
+ }
+ }
+ if (!n)
+ return NULL;
+
+ if (copyhdr)
+ M_COPY_PKTHDR(n, m);
+ m_copydata(m, off, len, mtod(n, caddr_t));
+ return n;
+}
+
/*
* pkthdr.aux chain manipulation.
* we don't allow clusters at this moment.
*/
struct mbuf *
-m_aux_add(struct mbuf *m, int af, int type)
+m_aux_add2(struct mbuf *m, int af, int type, void *p)
{
struct mbuf *n;
struct mauxtag *t;
@@ -287,8 +323,10 @@ m_aux_add(struct mbuf *m, int af, int type)
return NULL;
t = mtod(n, struct mauxtag *);
+ bzero(t, sizeof(*t));
t->af = af;
t->type = type;
+ t->p = p;
n->m_data += sizeof(struct mauxtag);
n->m_len = 0;
n->m_next = m->m_pkthdr.aux;
@@ -297,7 +335,7 @@ m_aux_add(struct mbuf *m, int af, int type)
}
struct mbuf *
-m_aux_find(struct mbuf *m, int af, int type)
+m_aux_find2(struct mbuf *m, int af, int type, void *p)
{
struct mbuf *n;
struct mauxtag *t;
@@ -307,12 +345,30 @@ m_aux_find(struct mbuf *m, int af, int type)
for (n = m->m_pkthdr.aux; n; n = n->m_next) {
t = (struct mauxtag *)n->m_dat;
- if (t->af == af && t->type == type)
+ if (n->m_data != ((caddr_t)t) + sizeof(struct mauxtag)) {
+ printf("m_aux_find: invalid m_data for mbuf=%p (%p %p)\n", n, t, n->m_data);
+ continue;
+ }
+ if (t->af == af && t->type == type && t->p == p)
return n;
}
return NULL;
}
+struct mbuf *
+m_aux_find(struct mbuf *m, int af, int type)
+{
+
+ return m_aux_find2(m, af, type, NULL);
+}
+
+struct mbuf *
+m_aux_add(struct mbuf *m, int af, int type)
+{
+
+ return m_aux_add2(m, af, type, NULL);
+}
+
void
m_aux_delete(struct mbuf *m, struct mbuf *victim)
{
@@ -327,6 +383,12 @@ m_aux_delete(struct mbuf *m, struct mbuf *victim)
while (n) {
t = (struct mauxtag *)n->m_dat;
next = n->m_next;
+ if (n->m_data != ((caddr_t)t) + sizeof(struct mauxtag)) {
+ printf("m_aux_delete: invalid m_data for mbuf=%p (%p %p)\n", n, t, n->m_data);
+ prev = n;
+ n = next;
+ continue;
+ }
if (n == victim) {
if (prev)
prev->m_next = n->m_next;
diff --git a/sys/net/if.c b/sys/net/if.c
index f98d85e..f52d74d 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -269,7 +269,7 @@ if_detach(ifp)
#endif /* INET */
#ifdef INET6
if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) {
- in6_purgeaddr(ifa, ifp);
+ in6_purgeaddr(ifa);
/* ifp_addrhead is already updated */
continue;
}
@@ -278,6 +278,16 @@ if_detach(ifp)
IFAFREE(ifa);
}
+#ifdef INET6
+ /*
+ * Remove all IPv6 kernel structs related to ifp. This should be done
+ * before removing routing entries below, since IPv6 interface direct
+ * routes are expected to be removed by the IPv6-specific kernel API.
+ * Otherwise, the kernel will detect some inconsistency and bark it.
+ */
+ in6_ifdetach(ifp);
+#endif
+
/*
* Delete all remaining routes using this interface
* Unfortuneatly the only way to do this is to slog through
@@ -290,11 +300,6 @@ if_detach(ifp)
(void) rnh->rnh_walktree(rnh, if_rtdel, ifp);
}
-#ifdef INET6
- /* nuke all IPv6 kernel structs related to ifp */
- in6_ifdetach(ifp);
-#endif
-
TAILQ_REMOVE(&ifnet, ifp, if_link);
mtx_destroy(&ifp->if_snd.ifq_mtx);
splx(s);
@@ -897,6 +902,7 @@ ifioctl(so, cmd, data, p)
#ifdef INET6
case SIOCSIFPHYADDR_IN6:
#endif
+ case SIOCSLIFPHYADDR:
case SIOCSIFMEDIA:
case SIOCSIFGENERIC:
error = suser(p);
@@ -913,6 +919,9 @@ ifioctl(so, cmd, data, p)
ifs = (struct ifstat *)data;
ifs->ascii[0] = '\0';
+ case SIOCGIFPSRCADDR:
+ case SIOCGIFPDSTADDR:
+ case SIOCGLIFPHYADDR:
case SIOCGIFMEDIA:
case SIOCGIFGENERIC:
if (ifp->if_ioctl == 0)
diff --git a/sys/net/if_faith.c b/sys/net/if_faith.c
index b28fecd..840b77b 100644
--- a/sys/net/if_faith.c
+++ b/sys/net/if_faith.c
@@ -1,3 +1,5 @@
+/* $KAME: if_faith.c,v 1.21 2001/02/20 07:59:26 itojun Exp $ */
+
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
@@ -41,30 +43,58 @@
/*
* Loopback interface driver for protocol testing and timing.
*/
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include "faith.h"
+#if NFAITH > 0
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
+#include <sys/errno.h>
#include <sys/sockio.h>
+#include <sys/time.h>
+#include <sys/queue.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/netisr.h>
#include <net/route.h>
#include <net/bpf.h>
+#include <net/if_faith.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#ifdef INET6
+#ifndef INET
+#include <netinet/in.h>
+#endif
+#include <netinet6/in6_var.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#endif
+
+#include "bpf.h"
+#define NBPFILTER NBPF
#include <net/net_osdep.h>
-extern int loioctl __P((struct ifnet *, u_long, caddr_t));
-extern int looutput __P((struct ifnet *ifp,
- struct mbuf *m, struct sockaddr *dst, struct rtentry *rt));
+static int faithioctl __P((struct ifnet *, u_long, caddr_t));
+int faithoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
+ struct rtentry *));
+static void faithrtrequest __P((int, struct rtentry *, struct sockaddr *));
void faithattach __P((void *));
PSEUDO_SET(faithattach, if_faith);
+
static struct ifnet faithif[NFAITH];
#define FAITHMTU 1500
@@ -74,8 +104,8 @@ void
faithattach(faith)
void *faith;
{
- register struct ifnet *ifp;
- register int i;
+ struct ifnet *ifp;
+ int i;
for (i = 0; i < NFAITH; i++) {
ifp = &faithif[i];
@@ -85,13 +115,210 @@ faithattach(faith)
ifp->if_mtu = FAITHMTU;
/* LOOPBACK commented out to announce IPv6 routes to faith */
ifp->if_flags = /* IFF_LOOPBACK | */ IFF_MULTICAST;
- ifp->if_ioctl = loioctl;
- ifp->if_output = looutput;
+ ifp->if_ioctl = faithioctl;
+ ifp->if_output = faithoutput;
ifp->if_type = IFT_FAITH;
ifp->if_snd.ifq_maxlen = ifqmaxlen;
ifp->if_hdrlen = 0;
ifp->if_addrlen = 0;
if_attach(ifp);
+#if NBPFILTER > 0
+#ifdef HAVE_OLD_BPF
bpfattach(ifp, DLT_NULL, sizeof(u_int));
+#else
+ bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
+#endif
+#endif
+ }
+}
+
+int
+faithoutput(ifp, m, dst, rt)
+ struct ifnet *ifp;
+ struct mbuf *m;
+ struct sockaddr *dst;
+ struct rtentry *rt;
+{
+ int isr;
+ struct ifqueue *ifq = 0;
+
+ if ((m->m_flags & M_PKTHDR) == 0)
+ panic("faithoutput no HDR");
+#if NBPFILTER > 0
+ /* BPF write needs to be handled specially */
+ if (dst->sa_family == AF_UNSPEC) {
+ dst->sa_family = *(mtod(m, int *));
+ m->m_len -= sizeof(int);
+ m->m_pkthdr.len -= sizeof(int);
+ m->m_data += sizeof(int);
}
+
+ if (ifp->if_bpf) {
+ /*
+ * We need to prepend the address family as
+ * a four byte field. Cons up a faith header
+ * to pacify bpf. This is safe because bpf
+ * will only read from the mbuf (i.e., it won't
+ * try to free it or keep a pointer a to it).
+ */
+ struct mbuf m0;
+ u_int32_t af = dst->sa_family;
+
+ m0.m_next = m;
+ m0.m_len = 4;
+ m0.m_data = (char *)&af;
+
+#ifdef HAVE_OLD_BPF
+ bpf_mtap(ifp, &m0);
+#else
+ bpf_mtap(ifp->if_bpf, &m0);
+#endif
+ }
+#endif
+
+ if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
+ m_freem(m);
+ return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
+ rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
+ }
+ ifp->if_opackets++;
+ ifp->if_obytes += m->m_pkthdr.len;
+ switch (dst->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ifq = &ipintrq;
+ isr = NETISR_IP;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ ifq = &ip6intrq;
+ isr = NETISR_IPV6;
+ break;
+#endif
+ default:
+ m_freem(m);
+ return EAFNOSUPPORT;
+ }
+
+ /* XXX do we need more sanity checks? */
+
+ m->m_pkthdr.rcvif = ifp;
+ ifp->if_ipackets++;
+ ifp->if_ibytes += m->m_pkthdr.len;
+ (void) IF_HANDOFF(ifq, m, NULL);
+ schednetisr(isr);
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+faithrtrequest(cmd, rt, sa)
+ int cmd;
+ struct rtentry *rt;
+ struct sockaddr *sa;
+{
+ if (rt) {
+ rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
+ /*
+ * For optimal performance, the send and receive buffers
+ * should be at least twice the MTU plus a little more for
+ * overhead.
+ */
+ rt->rt_rmx.rmx_recvpipe =
+ rt->rt_rmx.rmx_sendpipe = 3 * FAITHMTU;
+ }
+}
+
+/*
+ * Process an ioctl request.
+ */
+/* ARGSUSED */
+static int
+faithioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct ifaddr *ifa;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int error = 0;
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP | IFF_RUNNING;
+ ifa = (struct ifaddr *)data;
+ ifa->ifa_rtrequest = faithrtrequest;
+ /*
+ * Everything else is done at a higher level.
+ */
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ if (ifr == 0) {
+ error = EAFNOSUPPORT; /* XXX */
+ break;
+ }
+ switch (ifr->ifr_addr.sa_family) {
+#ifdef INET
+ case AF_INET:
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ break;
+#endif
+
+ default:
+ error = EAFNOSUPPORT;
+ break;
+ }
+ break;
+
+#ifdef SIOCSIFMTU
+ case SIOCSIFMTU:
+ ifp->if_mtu = ifr->ifr_mtu;
+ break;
+#endif
+
+ case SIOCSIFFLAGS:
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ return (error);
+}
+
+/*
+ * XXX could be slow
+ * XXX could be layer violation to call sys/net from sys/netinet6
+ */
+int
+faithprefix(in6)
+ struct in6_addr *in6;
+{
+ struct rtentry *rt;
+ struct sockaddr_in6 sin6;
+ int ret;
+
+ if (ip6_keepfaith == 0)
+ return 0;
+
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_addr = *in6;
+ rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
+ if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH &&
+ (rt->rt_ifp->if_flags & IFF_UP) != 0)
+ ret = 1;
+ else
+ ret = 0;
+ if (rt)
+ RTFREE(rt);
+ return ret;
}
+#endif /* NFAITH > 0 */
diff --git a/sys/net/if_faith.h b/sys/net/if_faith.h
new file mode 100644
index 0000000..1e30bfb
--- /dev/null
+++ b/sys/net/if_faith.h
@@ -0,0 +1,41 @@
+/* $FreeBSD$ */
+/* $KAME: if_faith.h,v 1.1 2000/07/26 05:49:21 itojun Exp $ */
+
+/*
+ * Copyright (C) 2000 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.
+ */
+
+#ifndef _NET_IF_FAITH_H_
+#define _NET_IF_FAITH_H_
+
+#ifdef _KERNEL
+struct in6_addr;
+int faithprefix __P((struct in6_addr *));
+#endif
+
+#endif /* _NET_IF_FAITH_H_ */
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index 68031cb..465063c 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: if_gif.c,v 1.28 2000/06/20 12:30:03 jinmei Exp $ */
+/* $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -52,11 +52,11 @@
#include <net/route.h>
#include <net/bpf.h>
-#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
-#include <netinet/in_var.h>
#include <netinet/ip.h>
+#ifdef INET
+#include <netinet/in_var.h>
#include <netinet/in_gif.h>
#endif /* INET */
@@ -114,11 +114,11 @@ void
gifattach(dummy)
void *dummy;
{
- register struct gif_softc *sc;
- register int i;
+ struct gif_softc *sc;
+ int i;
ngif = NGIF;
- gif = sc = malloc (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
+ gif = sc = malloc(ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
bzero(sc, ngif * sizeof(struct gif_softc));
for (i = 0; i < ngif; sc++, i++) {
sc->gif_if.if_name = "gif";
@@ -148,6 +148,10 @@ gifattach(dummy)
sc->gif_if.if_mtu = GIF_MTU;
sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
+#if 0
+ /* turn off ingress filter */
+ sc->gif_if.if_flags |= IFF_LINK2;
+#endif
sc->gif_if.if_ioctl = gif_ioctl;
sc->gif_if.if_output = gif_output;
sc->gif_if.if_type = IFT_GIF;
@@ -229,7 +233,7 @@ gif_output(ifp, m, dst, rt)
struct sockaddr *dst;
struct rtentry *rt; /* added in net2 */
{
- register struct gif_softc *sc = (struct gif_softc*)ifp;
+ struct gif_softc *sc = (struct gif_softc*)ifp;
int error = 0;
static int called = 0; /* XXX: MUTEX */
@@ -268,7 +272,7 @@ gif_output(ifp, m, dst, rt)
* try to free it or keep a pointer a to it).
*/
struct mbuf m0;
- u_int af = dst->sa_family;
+ u_int32_t af = dst->sa_family;
m0.m_next = m;
m0.m_len = 4;
@@ -284,8 +288,11 @@ gif_output(ifp, m, dst, rt)
ifp->if_opackets++;
ifp->if_obytes += m->m_pkthdr.len;
+ /* inner AF-specific encapsulation */
+
/* XXX should we check if our outer source is legal? */
+ /* dispatch to output logic based on outer AF */
switch (sc->gif_psrc->sa_family) {
#ifdef INET
case AF_INET:
@@ -300,11 +307,13 @@ gif_output(ifp, m, dst, rt)
default:
m_freem(m);
error = ENETDOWN;
+ goto end;
}
end:
called = 0; /* reset recursion counter */
- if (error) ifp->if_oerrors++;
+ if (error)
+ ifp->if_oerrors++;
return error;
}
@@ -315,7 +324,7 @@ gif_input(m, af, gifp)
struct ifnet *gifp;
{
int isr;
- register struct ifqueue *ifq = 0;
+ struct ifqueue *ifq = 0;
if (gifp == NULL) {
/* just in case */
@@ -335,11 +344,11 @@ gif_input(m, af, gifp)
* try to free it or keep a pointer a to it).
*/
struct mbuf m0;
- u_int af = AF_INET6;
+ u_int32_t af1 = af;
m0.m_next = m;
m0.m_len = 4;
- m0.m_data = (char *)&af;
+ m0.m_data = (char *)&af1;
#ifdef HAVE_OLD_BPF
bpf_mtap(gifp, &m0);
@@ -435,13 +444,16 @@ gif_ioctl(ifp, cmd, data)
#ifdef INET6
case SIOCSIFPHYADDR_IN6:
#endif /* INET6 */
+ case SIOCSLIFPHYADDR:
switch (cmd) {
+#ifdef INET
case SIOCSIFPHYADDR:
src = (struct sockaddr *)
&(((struct in_aliasreq *)data)->ifra_addr);
dst = (struct sockaddr *)
&(((struct in_aliasreq *)data)->ifra_dstaddr);
break;
+#endif
#ifdef INET6
case SIOCSIFPHYADDR_IN6:
src = (struct sockaddr *)
@@ -450,6 +462,66 @@ gif_ioctl(ifp, cmd, data)
&(((struct in6_aliasreq *)data)->ifra_dstaddr);
break;
#endif
+ case SIOCSLIFPHYADDR:
+ src = (struct sockaddr *)
+ &(((struct if_laddrreq *)data)->addr);
+ dst = (struct sockaddr *)
+ &(((struct if_laddrreq *)data)->dstaddr);
+ }
+
+ /* sa_family must be equal */
+ if (src->sa_family != dst->sa_family)
+ return EINVAL;
+
+ /* validate sa_len */
+ switch (src->sa_family) {
+#ifdef INET
+ case AF_INET:
+ if (src->sa_len != sizeof(struct sockaddr_in))
+ return EINVAL;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (src->sa_len != sizeof(struct sockaddr_in6))
+ return EINVAL;
+ break;
+#endif
+ default:
+ return EAFNOSUPPORT;
+ }
+ switch (dst->sa_family) {
+#ifdef INET
+ case AF_INET:
+ if (dst->sa_len != sizeof(struct sockaddr_in))
+ return EINVAL;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (dst->sa_len != sizeof(struct sockaddr_in6))
+ return EINVAL;
+ break;
+#endif
+ default:
+ return EAFNOSUPPORT;
+ }
+
+ /* check sa_family looks sane for the cmd */
+ switch (cmd) {
+ case SIOCSIFPHYADDR:
+ if (src->sa_family == AF_INET)
+ break;
+ return EAFNOSUPPORT;
+#ifdef INET6
+ case SIOCSIFPHYADDR_IN6:
+ if (src->sa_family == AF_INET6)
+ break;
+ return EAFNOSUPPORT;
+#endif /* INET6 */
+ case SIOCSLIFPHYADDR:
+ /* checks done in the above */
+ break;
}
for (i = 0; i < ngif; i++) {
@@ -493,41 +565,16 @@ gif_ioctl(ifp, cmd, data)
#endif
}
- if (src->sa_family != dst->sa_family ||
- src->sa_len != dst->sa_len) {
- error = EINVAL;
- break;
- }
- switch (src->sa_family) {
-#ifdef INET
- case AF_INET:
- size = sizeof(struct sockaddr_in);
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- size = sizeof(struct sockaddr_in6);
- break;
-#endif
- default:
- error = EAFNOSUPPORT;
- goto bad;
- }
- if (src->sa_len != size) {
- error = EINVAL;
- break;
- }
-
if (sc->gif_psrc)
free((caddr_t)sc->gif_psrc, M_IFADDR);
- sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK);
- bcopy((caddr_t)src, (caddr_t)sa, size);
+ sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
+ bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
sc->gif_psrc = sa;
if (sc->gif_pdst)
free((caddr_t)sc->gif_pdst, M_IFADDR);
- sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK);
- bcopy((caddr_t)dst, (caddr_t)sa, size);
+ sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
+ bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
sc->gif_pdst = sa;
ifp->if_flags |= IFF_RUNNING;
@@ -548,7 +595,7 @@ gif_ioctl(ifp, cmd, data)
free((caddr_t)sc->gif_pdst, M_IFADDR);
sc->gif_pdst = NULL;
}
- /* change the IFF_UP flag as well? */
+ /* change the IFF_{UP, RUNNING} flag as well? */
break;
#endif
@@ -561,25 +608,27 @@ gif_ioctl(ifp, cmd, data)
goto bad;
}
src = sc->gif_psrc;
- switch (sc->gif_psrc->sa_family) {
+ switch (cmd) {
#ifdef INET
- case AF_INET:
+ case SIOCGIFPSRCADDR:
dst = &ifr->ifr_addr;
- size = sizeof(struct sockaddr_in);
+ size = sizeof(ifr->ifr_addr);
break;
#endif /* INET */
#ifdef INET6
- case AF_INET6:
+ case SIOCGIFPSRCADDR_IN6:
dst = (struct sockaddr *)
&(((struct in6_ifreq *)data)->ifr_addr);
- size = sizeof(struct sockaddr_in6);
+ size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
break;
#endif /* INET6 */
default:
error = EADDRNOTAVAIL;
goto bad;
}
- bcopy((caddr_t)src, (caddr_t)dst, size);
+ if (src->sa_len > size)
+ return EINVAL;
+ bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
break;
case SIOCGIFPDSTADDR:
@@ -591,25 +640,52 @@ gif_ioctl(ifp, cmd, data)
goto bad;
}
src = sc->gif_pdst;
- switch (sc->gif_pdst->sa_family) {
+ switch (cmd) {
#ifdef INET
- case AF_INET:
+ case SIOCGIFPDSTADDR:
dst = &ifr->ifr_addr;
- size = sizeof(struct sockaddr_in);
+ size = sizeof(ifr->ifr_addr);
break;
#endif /* INET */
#ifdef INET6
- case AF_INET6:
+ case SIOCGIFPDSTADDR_IN6:
dst = (struct sockaddr *)
&(((struct in6_ifreq *)data)->ifr_addr);
- size = sizeof(struct sockaddr_in6);
+ size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
break;
#endif /* INET6 */
default:
error = EADDRNOTAVAIL;
goto bad;
}
- bcopy((caddr_t)src, (caddr_t)dst, size);
+ if (src->sa_len > size)
+ return EINVAL;
+ bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
+ break;
+
+ case SIOCGLIFPHYADDR:
+ if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
+ error = EADDRNOTAVAIL;
+ goto bad;
+ }
+
+ /* copy src */
+ src = sc->gif_psrc;
+ dst = (struct sockaddr *)
+ &(((struct if_laddrreq *)data)->addr);
+ size = sizeof(((struct if_laddrreq *)data)->addr);
+ if (src->sa_len > size)
+ return EINVAL;
+ bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
+
+ /* copy dst */
+ src = sc->gif_pdst;
+ dst = (struct sockaddr *)
+ &(((struct if_laddrreq *)data)->dstaddr);
+ size = sizeof(((struct if_laddrreq *)data)->dstaddr);
+ if (src->sa_len > size)
+ return EINVAL;
+ bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
break;
case SIOCSIFFLAGS:
diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h
index 3699286..3978e7b 100644
--- a/sys/net/if_gif.h
+++ b/sys/net/if_gif.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: if_gif.h,v 1.13 2000/06/17 20:34:24 itojun Exp $ */
+/* $KAME: if_gif.h,v 1.17 2000/09/11 11:36:41 sumikawa Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -38,11 +38,9 @@
#define _NET_IF_GIF_H_
-#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
#if defined(_KERNEL) && !defined(_LKM)
#include "opt_inet.h"
#endif
-#endif
#include <netinet/in.h>
/* xxx sigh, why route have struct route instead of pointer? */
diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c
index 0e9ac65..f8e11f7 100644
--- a/sys/net/if_loop.c
+++ b/sys/net/if_loop.c
@@ -58,6 +58,7 @@
#include <net/netisr.h>
#include <net/route.h>
#include <net/bpf.h>
+#include <net/bpfdesc.h>
#ifdef INET
#include <netinet/in.h>
@@ -236,6 +237,8 @@ looutput(ifp, m, dst, rt)
m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t));
n->m_pkthdr = m->m_pkthdr;
n->m_len = m->m_pkthdr.len;
+ n->m_pkthdr.aux = m->m_pkthdr.aux;
+ m->m_pkthdr.aux = (struct mbuf *)NULL;
m_freem(m);
m = n;
}
@@ -277,7 +280,7 @@ contiguousfail:
int
if_simloop(ifp, m, af, hlen)
struct ifnet *ifp;
- register struct mbuf *m;
+ struct mbuf *m;
int af;
int hlen;
{
@@ -300,17 +303,19 @@ if_simloop(ifp, m, af, hlen)
if (ifp->if_bpf) {
struct mbuf m0, *n = m;
- /*
- * We need to prepend the address family as
- * a four byte field. Cons up a dummy header
- * to pacify bpf. This is safe because bpf
- * will only read from the mbuf (i.e., it won't
- * try to free it or keep a pointer a to it).
- */
- m0.m_next = m;
- m0.m_len = 4;
- m0.m_data = (char *)&af;
- n = &m0;
+ if (ifp->if_bpf->bif_dlt == DLT_NULL) {
+ /*
+ * We need to prepend the address family as
+ * a four byte field. Cons up a dummy header
+ * to pacify bpf. This is safe because bpf
+ * will only read from the mbuf (i.e., it won't
+ * try to free it or keep a pointer a to it).
+ */
+ m0.m_next = m;
+ m0.m_len = 4;
+ m0.m_data = (char *)&af;
+ n = &m0;
+ }
bpf_mtap(ifp, n);
}
diff --git a/sys/net/if_sppp.h b/sys/net/if_sppp.h
index 84fede3..0c2a201 100644
--- a/sys/net/if_sppp.h
+++ b/sys/net/if_sppp.h
@@ -39,6 +39,7 @@ struct slcp {
};
#define IDX_IPCP 1 /* idx into state table */
+#define IDX_IPV6CP 2 /* idx into state table */
struct sipcp {
u_long opts; /* IPCP options to send (bitfield) */
@@ -46,6 +47,10 @@ struct sipcp {
#define IPCP_HISADDR_SEEN 1 /* have seen his address already */
#define IPCP_MYADDR_DYN 2 /* my address is dynamically assigned */
#define IPCP_MYADDR_SEEN 4 /* have seen his address already */
+#ifdef notdef
+#define IPV6CP_MYIFID_DYN 2 /* my ifid is dynamically assigned */
+#endif
+#define IPV6CP_MYIFID_SEEN 4 /* have seen his ifid already */
};
#define AUTHNAMELEN 32
@@ -62,8 +67,8 @@ struct sauth {
u_char challenge[AUTHKEYLEN]; /* random challenge */
};
-#define IDX_PAP 2
-#define IDX_CHAP 3
+#define IDX_PAP 3
+#define IDX_CHAP 4
#define IDX_COUNT (IDX_CHAP + 1) /* bump this when adding cp's! */
@@ -87,8 +92,8 @@ struct sppp {
u_int pp_flags; /* sub modes */
u_short pp_alivecnt; /* keepalive packets counter */
u_short pp_loopcnt; /* loopback detection counter */
- u_long pp_seq; /* local sequence number */
- u_long pp_rseq; /* remote sequence number */
+ u_long pp_seq[IDX_COUNT]; /* local sequence number */
+ u_long pp_rseq[IDX_COUNT]; /* remote sequence number */
enum ppp_phase pp_phase; /* phase we're currently in */
int state[IDX_COUNT]; /* state machine */
u_char confid[IDX_COUNT]; /* id of last configuration request */
@@ -98,6 +103,7 @@ struct sppp {
struct callout_handle pap_my_to_ch; /* PAP needs one more... */
struct slcp lcp; /* LCP params */
struct sipcp ipcp; /* IPCP params */
+ struct sipcp ipv6cp; /* IPv6CP params */
struct sauth myauth; /* auth params, i'm peer */
struct sauth hisauth; /* auth params, i'm authenticator */
/*
diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c
index 6928c95..e489c58 100644
--- a/sys/net/if_spppsubr.c
+++ b/sys/net/if_spppsubr.c
@@ -135,10 +135,12 @@
#define PPP_ISO 0x0023 /* ISO OSI Protocol */
#define PPP_XNS 0x0025 /* Xerox NS Protocol */
#define PPP_IPX 0x002b /* Novell IPX Protocol */
+#define PPP_IPV6 0x0057 /* Internet Protocol Version 6 */
#define PPP_LCP 0xc021 /* Link Control Protocol */
#define PPP_PAP 0xc023 /* Password Authentication Protocol */
#define PPP_CHAP 0xc223 /* Challenge-Handshake Auth Protocol */
#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */
+#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */
#define CONF_REQ 1 /* PPP configure request */
#define CONF_ACK 2 /* PPP configure acknowledge */
@@ -165,6 +167,9 @@
#define IPCP_OPT_COMPRESSION 2 /* IP compression protocol (VJ) */
#define IPCP_OPT_ADDRESS 3 /* local IP address */
+#define IPV6CP_OPT_IFID 1 /* interface identifier */
+#define IPV6CP_OPT_COMPRESSION 2 /* IPv6 compression protocol */
+
#define PAP_REQ 1 /* PAP name/password request */
#define PAP_ACK 2 /* PAP acknowledge */
#define PAP_NAK 3 /* PAP fail */
@@ -340,6 +345,21 @@ static void sppp_ipcp_tls(struct sppp *sp);
static void sppp_ipcp_tlf(struct sppp *sp);
static void sppp_ipcp_scr(struct sppp *sp);
+static void sppp_ipv6cp_init(struct sppp *sp);
+static void sppp_ipv6cp_up(struct sppp *sp);
+static void sppp_ipv6cp_down(struct sppp *sp);
+static void sppp_ipv6cp_open(struct sppp *sp);
+static void sppp_ipv6cp_close(struct sppp *sp);
+static void sppp_ipv6cp_TO(void *sp);
+static int sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len);
+static void sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
+static void sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
+static void sppp_ipv6cp_tlu(struct sppp *sp);
+static void sppp_ipv6cp_tld(struct sppp *sp);
+static void sppp_ipv6cp_tls(struct sppp *sp);
+static void sppp_ipv6cp_tlf(struct sppp *sp);
+static void sppp_ipv6cp_scr(struct sppp *sp);
+
static void sppp_pap_input(struct sppp *sp, struct mbuf *m);
static void sppp_pap_init(struct sppp *sp);
static void sppp_pap_open(struct sppp *sp);
@@ -363,6 +383,9 @@ static const char *sppp_auth_type_name(u_short proto, u_char type);
static const char *sppp_cp_type_name(u_char type);
static const char *sppp_dotted_quad(u_long addr);
static const char *sppp_ipcp_opt_name(u_char opt);
+#ifdef INET6
+static const char *sppp_ipv6cp_opt_name(u_char opt);
+#endif
static const char *sppp_lcp_opt_name(u_char opt);
static const char *sppp_phase_name(enum ppp_phase phase);
static const char *sppp_proto_name(u_short proto);
@@ -377,6 +400,15 @@ static void sppp_print_bytes(const u_char *p, u_short len);
static void sppp_print_string(const char *p, u_short len);
static void sppp_qflush(struct ifqueue *ifq);
static void sppp_set_ip_addr(struct sppp *sp, u_long src);
+#ifdef INET6
+static void sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src,
+ struct in6_addr *dst, struct in6_addr *srcmask);
+#ifdef IPV6CP_MYIFID_DYN
+static void sppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src);
+static void sppp_gen_ip6_addr(struct sppp *sp, const struct in6_addr *src);
+#endif
+static void sppp_suggest_ip6_addr(struct sppp *sp, struct in6_addr *src);
+#endif
/* our control protocol descriptors */
static const struct cp lcp = {
@@ -395,6 +427,20 @@ static const struct cp ipcp = {
sppp_ipcp_scr
};
+static const struct cp ipv6cp = {
+ PPP_IPV6CP, IDX_IPV6CP,
+#ifdef INET6 /*don't run IPv6CP if there's no IPv6 support*/
+ CP_NCP,
+#else
+ 0,
+#endif
+ "ipv6cp",
+ sppp_ipv6cp_up, sppp_ipv6cp_down, sppp_ipv6cp_open, sppp_ipv6cp_close,
+ sppp_ipv6cp_TO, sppp_ipv6cp_RCR, sppp_ipv6cp_RCN_rej, sppp_ipv6cp_RCN_nak,
+ sppp_ipv6cp_tlu, sppp_ipv6cp_tld, sppp_ipv6cp_tls, sppp_ipv6cp_tlf,
+ sppp_ipv6cp_scr
+};
+
static const struct cp pap = {
PPP_PAP, IDX_PAP, CP_AUTH, "pap",
sppp_null, sppp_null, sppp_pap_open, sppp_pap_close,
@@ -414,6 +460,7 @@ static const struct cp chap = {
static const struct cp *cps[IDX_COUNT] = {
&lcp, /* IDX_LCP */
&ipcp, /* IDX_IPCP */
+ &ipv6cp, /* IDX_IPV6CP */
&pap, /* IDX_PAP */
&chap, /* IDX_CHAP */
};
@@ -499,7 +546,7 @@ sppp_input(struct ifnet *ifp, struct mbuf *m)
h->address, h->control, ntohs(h->protocol));
if (sp->state[IDX_LCP] == STATE_OPENED)
sppp_cp_send (sp, PPP_LCP, PROTO_REJ,
- ++sp->pp_seq, m->m_pkthdr.len + 2,
+ ++sp->pp_seq[IDX_LCP], m->m_pkthdr.len + 2,
&h->protocol);
++ifp->if_noproto;
goto drop;
@@ -530,6 +577,20 @@ sppp_input(struct ifnet *ifp, struct mbuf *m)
}
break;
#endif
+#ifdef INET6
+ case PPP_IPV6CP:
+ if (sp->pp_phase == PHASE_NETWORK)
+ sppp_cp_input(&ipv6cp, sp, m);
+ m_freem (m);
+ return;
+
+ case PPP_IPV6:
+ if (sp->state[IDX_IPV6CP] == STATE_OPENED) {
+ schednetisr (NETISR_IPV6);
+ inq = &ip6intrq;
+ }
+ break;
+#endif
#ifdef IPX
case PPP_IPX:
/* IPX IPXCP not implemented yet */
@@ -628,7 +689,7 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
{
struct sppp *sp = (struct sppp*) ifp;
struct ppp_header *h;
- struct ifqueue *ifq;
+ struct ifqueue *ifq = NULL;
int s, rv = 0;
int debug = ifp->if_flags & IFF_DEBUG;
@@ -652,7 +713,6 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
s = splimp();
}
- ifq = &ifp->if_snd;
#ifdef INET
if (dst->sa_family == AF_INET) {
/* XXX Check mbuf length here? */
@@ -699,6 +759,12 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
}
#endif
+#ifdef INET6
+ if (dst->sa_family == AF_INET6) {
+ /* XXX do something tricky here? */
+ }
+#endif
+
/*
* Prepend general data packet PPP header. For now, IP only.
*/
@@ -750,7 +816,18 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
if (sp->pp_mode == IFF_CISCO)
h->protocol = htons (ETHERTYPE_IPV6);
else {
- goto nosupport;
+ /*
+ * Don't choke with an ENETDOWN early. It's
+ * possible that we just started dialing out,
+ * so don't drop the packet immediately. If
+ * we notice that we run out of buffer space
+ * below, we will however remember that we are
+ * not ready to carry IP packets, and return
+ * ENETDOWN, as opposed to ENOBUFS.
+ */
+ h->protocol = htons(PPP_IPV6);
+ if (sp->state[IDX_IPV6CP] != STATE_OPENED)
+ rv = ENETDOWN;
}
break;
#endif
@@ -812,8 +889,8 @@ sppp_attach(struct ifnet *ifp)
sp->pp_cpq.ifq_maxlen = 20;
sp->pp_loopcnt = 0;
sp->pp_alivecnt = 0;
- sp->pp_seq = 0;
- sp->pp_rseq = 0;
+ bzero(&sp->pp_seq[0], sizeof(sp->pp_seq));
+ bzero(&sp->pp_rseq[0], sizeof(sp->pp_rseq));
sp->pp_phase = PHASE_DEAD;
sp->pp_up = lcp.Up;
sp->pp_down = lcp.Down;
@@ -822,6 +899,7 @@ sppp_attach(struct ifnet *ifp)
sppp_lcp_init(sp);
sppp_ipcp_init(sp);
+ sppp_ipv6cp_init(sp);
sppp_pap_init(sp);
sppp_chap_init(sp);
}
@@ -1079,8 +1157,8 @@ sppp_cisco_input(struct sppp *sp, struct mbuf *m)
break;
case CISCO_KEEPALIVE_REQ:
sp->pp_alivecnt = 0;
- sp->pp_rseq = ntohl (h->par1);
- if (sp->pp_seq == sp->pp_rseq) {
+ sp->pp_rseq[IDX_LCP] = ntohl (h->par1);
+ if (sp->pp_seq[IDX_LCP] == sp->pp_rseq[IDX_LCP]) {
/* Local and remote sequence numbers are equal.
* Probably, the line is in loopback mode. */
if (sp->pp_loopcnt >= MAXALIVECNT) {
@@ -1096,9 +1174,9 @@ sppp_cisco_input(struct sppp *sp, struct mbuf *m)
/* Generate new local sequence number */
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
- sp->pp_seq = random();
+ sp->pp_seq[IDX_LCP] = random();
#else
- sp->pp_seq ^= time.tv_sec ^ time.tv_usec;
+ sp->pp_seq[IDX_LCP] ^= time.tv_sec ^ time.tv_usec;
#endif
break;
}
@@ -1574,8 +1652,8 @@ sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m)
if (debug)
log(-1, SPP_FMT "%s send code-rej for 0x%x\n",
SPP_ARGS(ifp), cp->name, h->type);
- sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq,
- m->m_pkthdr.len, h);
+ sppp_cp_send(sp, cp->proto, CODE_REJ,
+ ++sp->pp_seq[cp->protoidx], m->m_pkthdr.len, h);
++ifp->if_ierrors;
}
}
@@ -1730,7 +1808,8 @@ sppp_close_event(const struct cp *cp, struct sppp *sp)
case STATE_ACK_RCVD:
case STATE_ACK_SENT:
sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate;
- sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0);
+ sppp_cp_send(sp, cp->proto, TERM_REQ,
+ ++sp->pp_seq[cp->protoidx], 0, 0);
sppp_cp_change_state(cp, sp, STATE_CLOSING);
break;
}
@@ -1772,8 +1851,8 @@ sppp_to_event(const struct cp *cp, struct sppp *sp)
switch (sp->state[cp->protoidx]) {
case STATE_CLOSING:
case STATE_STOPPING:
- sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq,
- 0, 0);
+ sppp_cp_send(sp, cp->proto, TERM_REQ,
+ ++sp->pp_seq[cp->protoidx], 0, 0);
TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout,
sp->ch[cp->protoidx]);
break;
@@ -1835,6 +1914,8 @@ sppp_lcp_init(struct sppp *sp)
sp->lcp.magic = 0;
sp->state[IDX_LCP] = STATE_INITIAL;
sp->fail_counter[IDX_LCP] = 0;
+ sp->pp_seq[IDX_LCP] = 0;
+ sp->pp_rseq[IDX_LCP] = 0;
sp->lcp.protos = 0;
sp->lcp.mru = sp->lcp.their_mru = PP_MTU;
@@ -2468,7 +2549,7 @@ sppp_lcp_scr(struct sppp *sp)
opt[i++] = CHAP_MD5;
}
- sp->confid[IDX_LCP] = ++sp->pp_seq;
+ sp->confid[IDX_LCP] = ++sp->pp_seq[IDX_LCP];
sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt);
}
@@ -2519,6 +2600,8 @@ sppp_ipcp_init(struct sppp *sp)
sp->ipcp.flags = 0;
sp->state[IDX_IPCP] = STATE_INITIAL;
sp->fail_counter[IDX_IPCP] = 0;
+ sp->pp_seq[IDX_IPCP] = 0;
+ sp->pp_rseq[IDX_IPCP] = 0;
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
callout_handle_init(&sp->ch[IDX_IPCP]);
#endif
@@ -2894,13 +2977,516 @@ sppp_ipcp_scr(struct sppp *sp)
opt[i++] = ouraddr;
}
- sp->confid[IDX_IPCP] = ++sp->pp_seq;
+ sp->confid[IDX_IPCP] = ++sp->pp_seq[IDX_IPCP];
sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt);
}
/*
*--------------------------------------------------------------------------*
* *
+ * The IPv6CP implementation. *
+ * *
+ *--------------------------------------------------------------------------*
+ */
+
+#ifdef INET6
+static void
+sppp_ipv6cp_init(struct sppp *sp)
+{
+ sp->ipv6cp.opts = 0;
+ sp->ipv6cp.flags = 0;
+ sp->state[IDX_IPV6CP] = STATE_INITIAL;
+ sp->fail_counter[IDX_IPV6CP] = 0;
+ sp->pp_seq[IDX_IPV6CP] = 0;
+ sp->pp_rseq[IDX_IPV6CP] = 0;
+#if defined(__NetBSD__)
+ callout_init(&sp->ch[IDX_IPV6CP]);
+#endif
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+ callout_handle_init(&sp->ch[IDX_IPV6CP]);
+#endif
+}
+
+static void
+sppp_ipv6cp_up(struct sppp *sp)
+{
+ sppp_up_event(&ipv6cp, sp);
+}
+
+static void
+sppp_ipv6cp_down(struct sppp *sp)
+{
+ sppp_down_event(&ipv6cp, sp);
+}
+
+static void
+sppp_ipv6cp_open(struct sppp *sp)
+{
+ STDDCL;
+ struct in6_addr myaddr, hisaddr;
+
+#ifdef IPV6CP_MYIFID_DYN
+ sp->ipv6cp.flags &= ~(IPV6CP_MYIFID_SEEN|IPV6CP_MYIFID_DYN);
+#else
+ sp->ipv6cp.flags &= ~IPV6CP_MYIFID_SEEN;
+#endif
+
+ sppp_get_ip6_addrs(sp, &myaddr, &hisaddr, 0);
+ /*
+ * If we don't have our address, this probably means our
+ * interface doesn't want to talk IPv6 at all. (This could
+ * be the case if somebody wants to speak only IPX, for
+ * example.) Don't open IPv6CP in this case.
+ */
+ if (IN6_IS_ADDR_UNSPECIFIED(&myaddr)) {
+ /* XXX this message should go away */
+ if (debug)
+ log(LOG_DEBUG, SPP_FMT "ipv6cp_open(): no IPv6 interface\n",
+ SPP_ARGS(ifp));
+ return;
+ }
+
+ sp->ipv6cp.flags |= IPV6CP_MYIFID_SEEN;
+ sp->ipv6cp.opts |= (1 << IPV6CP_OPT_IFID);
+ sppp_open_event(&ipv6cp, sp);
+}
+
+static void
+sppp_ipv6cp_close(struct sppp *sp)
+{
+ sppp_close_event(&ipv6cp, sp);
+}
+
+static void
+sppp_ipv6cp_TO(void *cookie)
+{
+ sppp_to_event(&ipv6cp, (struct sppp *)cookie);
+}
+
+/*
+ * Analyze a configure request. Return true if it was agreeable, and
+ * caused action sca, false if it has been rejected or nak'ed, and
+ * caused action scn. (The return value is used to make the state
+ * transition decision in the state automaton.)
+ */
+static int
+sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len)
+{
+ u_char *buf, *r, *p;
+ struct ifnet *ifp = &sp->pp_if;
+ int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
+ struct in6_addr myaddr, desiredaddr, suggestaddr;
+ int ifidcount;
+ int type;
+ int collision, nohisaddr;
+
+ len -= 4;
+ origlen = len;
+ /*
+ * Make sure to allocate a buf that can at least hold a
+ * conf-nak with an `address' option. We might need it below.
+ */
+ buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT);
+ if (! buf)
+ return (0);
+
+ /* pass 1: see if we can recognize them */
+ if (debug)
+ log(LOG_DEBUG, SPP_FMT "ipv6cp parse opts:",
+ SPP_ARGS(ifp));
+ p = (void*) (h+1);
+ ifidcount = 0;
+ for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
+ if (debug)
+ addlog(" %s", sppp_ipv6cp_opt_name(*p));
+ switch (*p) {
+ case IPV6CP_OPT_IFID:
+ if (len >= 10 && p[1] == 10 && ifidcount == 0) {
+ /* correctly formed address option */
+ ifidcount++;
+ continue;
+ }
+ if (debug)
+ addlog(" [invalid]");
+ break;
+#ifdef notyet
+ case IPV6CP_OPT_COMPRESSION:
+ if (len >= 4 && p[1] >= 4) {
+ /* correctly formed compress option */
+ continue;
+ }
+ if (debug)
+ addlog(" [invalid]");
+ break;
+#endif
+ default:
+ /* Others not supported. */
+ if (debug)
+ addlog(" [rej]");
+ break;
+ }
+ /* Add the option to rejected list. */
+ bcopy (p, r, p[1]);
+ r += p[1];
+ rlen += p[1];
+ }
+ if (rlen) {
+ if (debug)
+ addlog(" send conf-rej\n");
+ sppp_cp_send (sp, PPP_IPV6CP, CONF_REJ, h->ident, rlen, buf);
+ goto end;
+ } else if (debug)
+ addlog("\n");
+
+ /* pass 2: parse option values */
+ sppp_get_ip6_addrs(sp, &myaddr, 0, 0);
+ if (debug)
+ log(LOG_DEBUG, SPP_FMT "ipv6cp parse opt values: ",
+ SPP_ARGS(ifp));
+ p = (void*) (h+1);
+ len = origlen;
+ type = CONF_ACK;
+ for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
+ if (debug)
+ addlog(" %s", sppp_ipv6cp_opt_name(*p));
+ switch (*p) {
+#ifdef notyet
+ case IPV6CP_OPT_COMPRESSION:
+ continue;
+#endif
+ case IPV6CP_OPT_IFID:
+ bzero(&desiredaddr, sizeof(desiredaddr));
+ bcopy(&p[2], &desiredaddr.s6_addr[8], 8);
+ collision = (bcmp(&desiredaddr.s6_addr[8],
+ &myaddr.s6_addr[8], 8) == 0);
+ nohisaddr = IN6_IS_ADDR_UNSPECIFIED(&desiredaddr);
+
+ desiredaddr.s6_addr16[0] = htons(0xfe80);
+ desiredaddr.s6_addr16[1] = htons(sp->pp_if.if_index);
+
+ if (!collision && !nohisaddr) {
+ /* no collision, hisaddr known - Conf-Ack */
+ type = CONF_ACK;
+
+ if (debug) {
+ addlog(" %s [%s]",
+ ip6_sprintf(&desiredaddr),
+ sppp_cp_type_name(type));
+ }
+ continue;
+ }
+
+ bzero(&suggestaddr, sizeof(&suggestaddr));
+ if (collision && nohisaddr) {
+ /* collision, hisaddr unknown - Conf-Rej */
+ type = CONF_REJ;
+ bzero(&p[2], 8);
+ } else {
+ /*
+ * - no collision, hisaddr unknown, or
+ * - collision, hisaddr known
+ * Conf-Nak, suggest hisaddr
+ */
+ type = CONF_NAK;
+ sppp_suggest_ip6_addr(sp, &suggestaddr);
+ bcopy(&suggestaddr.s6_addr[8], &p[2], 8);
+ }
+ if (debug)
+ addlog(" %s [%s]", ip6_sprintf(&desiredaddr),
+ sppp_cp_type_name(type));
+ break;
+ }
+ /* Add the option to nak'ed list. */
+ bcopy (p, r, p[1]);
+ r += p[1];
+ rlen += p[1];
+ }
+
+ if (rlen == 0 && type == CONF_ACK) {
+ if (debug)
+ addlog(" send %s\n", sppp_cp_type_name(type));
+ sppp_cp_send (sp, PPP_IPV6CP, type, h->ident, origlen, h+1);
+ } else {
+#ifdef DIAGNOSTIC
+ if (type == CONF_ACK)
+ panic("IPv6CP RCR: CONF_ACK with non-zero rlen");
+#endif
+
+ if (debug) {
+ addlog(" send %s suggest %s\n",
+ sppp_cp_type_name(type), ip6_sprintf(&suggestaddr));
+ }
+ sppp_cp_send (sp, PPP_IPV6CP, type, h->ident, rlen, buf);
+ }
+
+ end:
+ free (buf, M_TEMP);
+ return (rlen == 0);
+}
+
+/*
+ * Analyze the IPv6CP Configure-Reject option list, and adjust our
+ * negotiation.
+ */
+static void
+sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
+{
+ u_char *buf, *p;
+ struct ifnet *ifp = &sp->pp_if;
+ int debug = ifp->if_flags & IFF_DEBUG;
+
+ len -= 4;
+ buf = malloc (len, M_TEMP, M_NOWAIT);
+ if (!buf)
+ return;
+
+ if (debug)
+ log(LOG_DEBUG, SPP_FMT "ipv6cp rej opts:",
+ SPP_ARGS(ifp));
+
+ p = (void*) (h+1);
+ for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
+ if (debug)
+ addlog(" %s", sppp_ipv6cp_opt_name(*p));
+ switch (*p) {
+ case IPV6CP_OPT_IFID:
+ /*
+ * Peer doesn't grok address option. This is
+ * bad. XXX Should we better give up here?
+ */
+ sp->ipv6cp.opts &= ~(1 << IPV6CP_OPT_IFID);
+ break;
+#ifdef notyet
+ case IPV6CP_OPT_COMPRESS:
+ sp->ipv6cp.opts &= ~(1 << IPV6CP_OPT_COMPRESS);
+ break;
+#endif
+ }
+ }
+ if (debug)
+ addlog("\n");
+ free (buf, M_TEMP);
+ return;
+}
+
+/*
+ * Analyze the IPv6CP Configure-NAK option list, and adjust our
+ * negotiation.
+ */
+static void
+sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
+{
+ u_char *buf, *p;
+ struct ifnet *ifp = &sp->pp_if;
+ int debug = ifp->if_flags & IFF_DEBUG;
+ struct in6_addr suggestaddr;
+
+ len -= 4;
+ buf = malloc (len, M_TEMP, M_NOWAIT);
+ if (!buf)
+ return;
+
+ if (debug)
+ log(LOG_DEBUG, SPP_FMT "ipv6cp nak opts:",
+ SPP_ARGS(ifp));
+
+ p = (void*) (h+1);
+ for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
+ if (debug)
+ addlog(" %s", sppp_ipv6cp_opt_name(*p));
+ switch (*p) {
+ case IPV6CP_OPT_IFID:
+ /*
+ * Peer doesn't like our local ifid. See
+ * if we can do something for him. We'll drop
+ * him our address then.
+ */
+ if (len < 10 || p[1] != 10)
+ break;
+ bzero(&suggestaddr, sizeof(suggestaddr));
+ suggestaddr.s6_addr16[0] = htons(0xfe80);
+ suggestaddr.s6_addr16[1] = htons(sp->pp_if.if_index);
+ bcopy(&p[2], &suggestaddr.s6_addr[8], 8);
+
+ sp->ipv6cp.opts |= (1 << IPV6CP_OPT_IFID);
+ if (debug)
+ addlog(" [suggestaddr %s]",
+ ip6_sprintf(&suggestaddr));
+#ifdef IPV6CP_MYIFID_DYN
+ /*
+ * When doing dynamic address assignment,
+ * we accept his offer.
+ */
+ if (sp->ipv6cp.flags & IPV6CP_MYIFID_DYN) {
+ struct in6_addr lastsuggest;
+ /*
+ * If <suggested myaddr from peer> equals to
+ * <hisaddr we have suggested last time>,
+ * we have a collision. generate new random
+ * ifid.
+ */
+ sppp_suggest_ip6_addr(&lastsuggest);
+ if (IN6_ARE_ADDR_EQUAL(&suggestaddr,
+ lastsuggest)) {
+ if (debug)
+ addlog(" [random]");
+ sppp_gen_ip6_addr(sp, &suggestaddr);
+ }
+ sppp_set_ip6_addr(sp, &suggestaddr, 0);
+ if (debug)
+ addlog(" [agree]");
+ sp->ipv6cp.flags |= IPV6CP_MYIFID_SEEN;
+ }
+#else
+ /*
+ * Since we do not do dynamic address assignment,
+ * we ignore it and thus continue to negotiate
+ * our already existing value. This can possibly
+ * go into infinite request-reject loop.
+ *
+ * This is not likely because we normally use
+ * ifid based on MAC-address.
+ * If you have no ethernet card on the node, too bad.
+ * XXX should we use fail_counter?
+ */
+#endif
+ break;
+#ifdef notyet
+ case IPV6CP_OPT_COMPRESS:
+ /*
+ * Peer wants different compression parameters.
+ */
+ break;
+#endif
+ }
+ }
+ if (debug)
+ addlog("\n");
+ free (buf, M_TEMP);
+ return;
+}
+static void
+sppp_ipv6cp_tlu(struct sppp *sp)
+{
+ /* we are up - notify isdn daemon */
+ if (sp->pp_con)
+ sp->pp_con(sp);
+}
+
+static void
+sppp_ipv6cp_tld(struct sppp *sp)
+{
+}
+
+static void
+sppp_ipv6cp_tls(struct sppp *sp)
+{
+ /* indicate to LCP that it must stay alive */
+ sp->lcp.protos |= (1 << IDX_IPV6CP);
+}
+
+static void
+sppp_ipv6cp_tlf(struct sppp *sp)
+{
+
+#if 0 /* need #if 0 to close IPv6CP properly */
+ /* we no longer need LCP */
+ sp->lcp.protos &= ~(1 << IDX_IPV6CP);
+ sppp_lcp_check_and_close(sp);
+#endif
+}
+
+static void
+sppp_ipv6cp_scr(struct sppp *sp)
+{
+ char opt[10 /* ifid */ + 4 /* compression, minimum */];
+ struct in6_addr ouraddr;
+ int i = 0;
+
+ if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_IFID)) {
+ sppp_get_ip6_addrs(sp, &ouraddr, 0, 0);
+ opt[i++] = IPV6CP_OPT_IFID;
+ opt[i++] = 10;
+ bcopy(&ouraddr.s6_addr[8], &opt[i], 8);
+ i += 8;
+ }
+
+#ifdef notyet
+ if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_COMPRESSION)) {
+ opt[i++] = IPV6CP_OPT_COMPRESSION;
+ opt[i++] = 4;
+ opt[i++] = 0; /* TBD */
+ opt[i++] = 0; /* TBD */
+ /* variable length data may follow */
+ }
+#endif
+
+ sp->confid[IDX_IPV6CP] = ++sp->pp_seq[IDX_IPV6CP];
+ sppp_cp_send(sp, PPP_IPV6CP, CONF_REQ, sp->confid[IDX_IPV6CP], i, &opt);
+}
+#else /*INET6*/
+static void sppp_ipv6cp_init(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_up(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_down(struct sppp *sp)
+{
+}
+
+
+static void sppp_ipv6cp_open(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_close(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_TO(void *sp)
+{
+}
+
+static int sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len)
+{
+ return 0;
+}
+
+static void sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
+{
+}
+
+static void sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
+{
+}
+
+static void sppp_ipv6cp_tlu(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_tld(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_tls(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_tlf(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_scr(struct sppp *sp)
+{
+}
+#endif /*INET6*/
+
+/*
+ *--------------------------------------------------------------------------*
+ * *
* The CHAP implementation. *
* *
*--------------------------------------------------------------------------*
@@ -3213,6 +3799,8 @@ sppp_chap_init(struct sppp *sp)
/* Chap doesn't have STATE_INITIAL at all. */
sp->state[IDX_CHAP] = STATE_CLOSED;
sp->fail_counter[IDX_CHAP] = 0;
+ sp->pp_seq[IDX_CHAP] = 0;
+ sp->pp_rseq[IDX_CHAP] = 0;
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
callout_handle_init(&sp->ch[IDX_CHAP]);
#endif
@@ -3371,7 +3959,7 @@ sppp_chap_scr(struct sppp *sp)
ch[3] = seed ^ random();
clen = AUTHKEYLEN;
- sp->confid[IDX_CHAP] = ++sp->pp_seq;
+ sp->confid[IDX_CHAP] = ++sp->pp_seq[IDX_CHAP];
sppp_auth_send(&chap, sp, CHAP_CHALLENGE, sp->confid[IDX_CHAP],
sizeof clen, (const char *)&clen,
@@ -3544,6 +4132,8 @@ sppp_pap_init(struct sppp *sp)
/* PAP doesn't have STATE_INITIAL at all. */
sp->state[IDX_PAP] = STATE_CLOSED;
sp->fail_counter[IDX_PAP] = 0;
+ sp->pp_seq[IDX_PAP] = 0;
+ sp->pp_rseq[IDX_PAP] = 0;
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
callout_handle_init(&sp->ch[IDX_PAP]);
callout_handle_init(&sp->pap_my_to_ch);
@@ -3678,7 +4268,7 @@ sppp_pap_scr(struct sppp *sp)
{
u_char idlen, pwdlen;
- sp->confid[IDX_PAP] = ++sp->pp_seq;
+ sp->confid[IDX_PAP] = ++sp->pp_seq[IDX_PAP];
pwdlen = sppp_strnlen(sp->myauth.secret, AUTHKEYLEN);
idlen = sppp_strnlen(sp->myauth.name, AUTHNAMELEN);
@@ -3824,11 +4414,11 @@ sppp_keepalive(void *dummy)
if (sp->pp_alivecnt <= MAXALIVECNT)
++sp->pp_alivecnt;
if (sp->pp_mode == IFF_CISCO)
- sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
- sp->pp_rseq);
+ sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ,
+ ++sp->pp_seq[IDX_LCP], sp->pp_rseq[IDX_LCP]);
else if (sp->pp_phase >= PHASE_AUTHENTICATE) {
long nmagic = htonl (sp->lcp.magic);
- sp->lcp.echoid = ++sp->pp_seq;
+ sp->lcp.echoid = ++sp->pp_seq[IDX_LCP];
sppp_cp_send (sp, PPP_LCP, ECHO_REQ,
sp->lcp.echoid, 4, &nmagic);
}
@@ -3957,8 +4547,154 @@ sppp_set_ip_addr(struct sppp *sp, u_long src)
}
#endif
}
+}
+
+#ifdef INET6
+/*
+ * Get both IPv6 addresses.
+ */
+static void
+sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src, struct in6_addr *dst,
+ struct in6_addr *srcmask)
+{
+ struct ifnet *ifp = &sp->pp_if;
+ struct ifaddr *ifa;
+ struct sockaddr_in6 *si, *sm;
+ struct in6_addr ssrc, ddst;
+
+ sm = NULL;
+ bzero(&ssrc, sizeof(ssrc));
+ bzero(&ddst, sizeof(ddst));
+ /*
+ * Pick the first link-local AF_INET6 address from the list,
+ * aliases don't make any sense on a p2p link anyway.
+ */
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+ for (ifa = ifp->if_addrhead.tqh_first, si = 0;
+ ifa;
+ ifa = ifa->ifa_link.tqe_next)
+#elif defined(__NetBSD__) || defined (__OpenBSD__)
+ for (ifa = ifp->if_addrlist.tqh_first, si = 0;
+ ifa;
+ ifa = ifa->ifa_list.tqe_next)
+#else
+ for (ifa = ifp->if_addrlist, si = 0;
+ ifa;
+ ifa = ifa->ifa_next)
+#endif
+ if (ifa->ifa_addr->sa_family == AF_INET6) {
+ si = (struct sockaddr_in6 *)ifa->ifa_addr;
+ sm = (struct sockaddr_in6 *)ifa->ifa_netmask;
+ if (si && IN6_IS_ADDR_LINKLOCAL(&si->sin6_addr))
+ break;
+ }
+ if (ifa) {
+ if (si && !IN6_IS_ADDR_UNSPECIFIED(&si->sin6_addr)) {
+ bcopy(&si->sin6_addr, &ssrc, sizeof(ssrc));
+ if (srcmask) {
+ bcopy(&sm->sin6_addr, srcmask,
+ sizeof(*srcmask));
+ }
+ }
+
+ si = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
+ if (si && !IN6_IS_ADDR_UNSPECIFIED(&si->sin6_addr))
+ bcopy(&si->sin6_addr, &ddst, sizeof(ddst));
+ }
+
+ if (dst)
+ bcopy(&ddst, dst, sizeof(*dst));
+ if (src)
+ bcopy(&ssrc, src, sizeof(*src));
}
+#ifdef IPV6CP_MYIFID_DYN
+/*
+ * Generate random ifid.
+ */
+static void
+sppp_gen_ip6_addr(struct sppp *sp, struct in6_addr *addr)
+{
+ /* TBD */
+}
+
+/*
+ * Set my IPv6 address. Must be called at splimp.
+ */
+static void
+sppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src)
+{
+ STDDCL;
+ struct ifaddr *ifa;
+ struct sockaddr_in6 *sin6;
+
+ /*
+ * Pick the first link-local AF_INET6 address from the list,
+ * aliases don't make any sense on a p2p link anyway.
+ */
+
+ sin6 = NULL;
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+ for (ifa = ifp->if_addrhead.tqh_first;
+ ifa;
+ ifa = ifa->ifa_link.tqe_next)
+#elif defined(__NetBSD__) || defined (__OpenBSD__)
+ for (ifa = ifp->if_addrlist.tqh_first;
+ ifa;
+ ifa = ifa->ifa_list.tqe_next)
+#else
+ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
+#endif
+ {
+ if (ifa->ifa_addr->sa_family == AF_INET6)
+ {
+ sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ if (sin6 && IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ break;
+ }
+ }
+
+ if (ifa && sin6)
+ {
+ int error;
+ struct sockaddr_in6 new_sin6 = *sin6;
+
+ bcopy(src, &new_sin6.sin6_addr, sizeof(new_sin6.sin6_addr));
+ error = in6_ifinit(ifp, ifatoia6(ifa), &new_sin6, 1);
+ if (debug && error)
+ {
+ log(LOG_DEBUG, SPP_FMT "sppp_set_ip6_addr: in6_ifinit "
+ " failed, error=%d\n", SPP_ARGS(ifp), error);
+ }
+ }
+}
+#endif
+
+/*
+ * Suggest a candidate address to be used by peer.
+ */
+static void
+sppp_suggest_ip6_addr(struct sppp *sp, struct in6_addr *suggest)
+{
+ struct in6_addr myaddr;
+ struct timeval tv;
+
+ sppp_get_ip6_addrs(sp, &myaddr, 0, 0);
+
+ myaddr.s6_addr[8] &= ~0x02; /* u bit to "local" */
+ microtime(&tv);
+ if ((tv.tv_usec & 0xff) == 0 && (tv.tv_sec & 0xff) == 0) {
+ myaddr.s6_addr[14] ^= 0xff;
+ myaddr.s6_addr[15] ^= 0xff;
+ } else {
+ myaddr.s6_addr[14] ^= (tv.tv_usec & 0xff);
+ myaddr.s6_addr[15] ^= (tv.tv_sec & 0xff);
+ }
+ if (suggest)
+ bcopy(&myaddr, suggest, sizeof(myaddr));
+}
+#endif /*INET6*/
+
static int
sppp_params(struct sppp *sp, u_long cmd, void *data)
{
@@ -4165,6 +4901,20 @@ sppp_ipcp_opt_name(u_char opt)
return buf;
}
+#ifdef INET6
+static const char *
+sppp_ipv6cp_opt_name(u_char opt)
+{
+ static char buf[12];
+ switch (opt) {
+ case IPV6CP_OPT_IFID: return "ifid";
+ case IPV6CP_OPT_COMPRESSION: return "compression";
+ }
+ sprintf (buf, "0x%x", opt);
+ return buf;
+}
+#endif
+
static const char *
sppp_state_name(int state)
{
@@ -4205,6 +4955,7 @@ sppp_proto_name(u_short proto)
case PPP_IPCP: return "ipcp";
case PPP_PAP: return "pap";
case PPP_CHAP: return "chap";
+ case PPP_IPV6CP: return "ipv6cp";
}
snprintf(buf, sizeof(buf), "proto/0x%x", (unsigned)proto);
return buf;
diff --git a/sys/net/if_stf.c b/sys/net/if_stf.c
index d6a6495..979e6c5 100644
--- a/sys/net/if_stf.c
+++ b/sys/net/if_stf.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: if_stf.c,v 1.42 2000/08/15 07:24:23 itojun Exp $ */
+/* $KAME: if_stf.c,v 1.60 2001/05/03 14:51:47 itojun Exp $ */
/*
* Copyright (C) 2000 WIDE Project.
@@ -31,7 +31,7 @@
*/
/*
- * 6to4 interface, based on draft-ietf-ngtrans-6to4-06.txt.
+ * 6to4 interface, based on RFC3056.
*
* 6to4 interface is NOT capable of link-layer (I mean, IPv4) multicasting.
* There is no address mapping defined from IPv6 multicast address to IPv4
@@ -60,12 +60,13 @@
* ICMPv6:
* - Redirects cannot be used due to the lack of link-local address.
*
- * Starting from 04 draft, the specification suggests how to construct
- * link-local address for 6to4 interface.
- * However, it seems to have no real use and does not help the above symptom
- * much. Even if we assign link-locals to interface, we cannot really
- * use link-local unicast/multicast on top of 6to4 cloud, and the above
- * analysis does not change.
+ * stf interface does not have, and will not need, a link-local address.
+ * It seems to have no real benefit and does not help the above symptoms much.
+ * Even if we assign link-locals to interface, we cannot really
+ * use link-local unicast/multicast on top of 6to4 cloud (since there's no
+ * encapsulation defined for link-local address), and the above analysis does
+ * not change. RFC3056 does not mandate the assignment of link-local address
+ * either.
*
* 6to4 interface has security issues. Refer to
* http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt
@@ -159,8 +160,10 @@ static int stf_encapcheck __P((const struct mbuf *, int, int, void *));
static struct in6_ifaddr *stf_getsrcifa6 __P((struct ifnet *));
static int stf_output __P((struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *));
-static int stf_checkaddr4 __P((struct in_addr *, struct ifnet *));
-static int stf_checkaddr6 __P((struct in6_addr *, struct ifnet *));
+static int stf_checkaddr4 __P((struct stf_softc *, struct in_addr *,
+ struct ifnet *));
+static int stf_checkaddr6 __P((struct stf_softc *, struct in6_addr *,
+ struct ifnet *));
static void stf_rtrequest __P((int, struct rtentry *, struct sockaddr *));
static int stf_ioctl __P((struct ifnet *, u_long, caddr_t));
@@ -197,6 +200,10 @@ stfattach(dummy)
sc->sc_if.if_ioctl = stf_ioctl;
sc->sc_if.if_output = stf_output;
sc->sc_if.if_type = IFT_STF;
+#if 0
+ /* turn off ingress filter */
+ sc->sc_if.if_flags |= IFF_LINK2;
+#endif
sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
if_attach(&sc->sc_if);
#if NBPFILTER > 0
@@ -230,6 +237,10 @@ stf_encapcheck(m, off, proto, arg)
if ((sc->sc_if.if_flags & IFF_UP) == 0)
return 0;
+ /* IFF_LINK0 means "no decapsulation" */
+ if ((sc->sc_if.if_flags & IFF_LINK0) != 0)
+ return 0;
+
if (proto != IPPROTO_IPV6)
return 0;
@@ -317,6 +328,7 @@ stf_output(ifp, m, dst, rt)
{
struct stf_softc *sc;
struct sockaddr_in6 *dst6;
+ struct in_addr *in4;
struct sockaddr_in *dst4;
u_int8_t tos;
struct ip *ip;
@@ -351,6 +363,19 @@ stf_output(ifp, m, dst, rt)
ip6 = mtod(m, struct ip6_hdr *);
tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
+ /*
+ * Pickup the right outer dst addr from the list of candidates.
+ * ip6_dst has priority as it may be able to give us shorter IPv4 hops.
+ */
+ if (IN6_IS_ADDR_6TO4(&ip6->ip6_dst))
+ in4 = GET_V4(&ip6->ip6_dst);
+ else if (IN6_IS_ADDR_6TO4(&dst6->sin6_addr))
+ in4 = GET_V4(&dst6->sin6_addr);
+ else {
+ m_freem(m);
+ return ENETUNREACH;
+ }
+
M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
if (m && m->m_len < sizeof(struct ip))
m = m_pullup(m, sizeof(struct ip));
@@ -362,12 +387,14 @@ stf_output(ifp, m, dst, rt)
bcopy(GET_V4(&((struct sockaddr_in6 *)&ia6->ia_addr)->sin6_addr),
&ip->ip_src, sizeof(ip->ip_src));
- bcopy(GET_V4(&dst6->sin6_addr), &ip->ip_dst, sizeof(ip->ip_dst));
+ bcopy(in4, &ip->ip_dst, sizeof(ip->ip_dst));
ip->ip_p = IPPROTO_IPV6;
ip->ip_ttl = ip_gif_ttl; /*XXX*/
ip->ip_len = m->m_pkthdr.len; /*host order*/
if (ifp->if_flags & IFF_LINK1)
ip_ecn_ingress(ECN_ALLOWED, &ip->ip_tos, &tos);
+ else
+ ip_ecn_ingress(ECN_NOCARE, &ip->ip_tos, &tos);
dst4 = (struct sockaddr_in *)&sc->sc_ro.ro_dst;
if (dst4->sin_family != AF_INET ||
@@ -394,9 +421,10 @@ stf_output(ifp, m, dst, rt)
}
static int
-stf_checkaddr4(in, ifp)
+stf_checkaddr4(sc, in, inifp)
+ struct stf_softc *sc;
struct in_addr *in;
- struct ifnet *ifp; /* incoming interface */
+ struct ifnet *inifp; /* incoming interface */
{
struct in_ifaddr *ia4;
@@ -427,7 +455,7 @@ stf_checkaddr4(in, ifp)
/*
* perform ingress filter
*/
- if (ifp) {
+ if (sc && (sc->sc_if.if_flags & IFF_LINK2) == 0 && inifp) {
struct sockaddr_in sin;
struct rtentry *rt;
@@ -436,10 +464,14 @@ stf_checkaddr4(in, ifp)
sin.sin_len = sizeof(struct sockaddr_in);
sin.sin_addr = *in;
rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
- if (!rt)
- return -1;
- if (rt->rt_ifp != ifp) {
- rtfree(rt);
+ if (!rt || rt->rt_ifp != inifp) {
+#if 0
+ log(LOG_WARNING, "%s: packet from 0x%x dropped "
+ "due to ingress filter\n", if_name(&sc->sc_if),
+ (u_int32_t)ntohl(sin.sin_addr.s_addr));
+#endif
+ if (rt)
+ rtfree(rt);
return -1;
}
rtfree(rt);
@@ -449,15 +481,16 @@ stf_checkaddr4(in, ifp)
}
static int
-stf_checkaddr6(in6, ifp)
+stf_checkaddr6(sc, in6, inifp)
+ struct stf_softc *sc;
struct in6_addr *in6;
- struct ifnet *ifp; /* incoming interface */
+ struct ifnet *inifp; /* incoming interface */
{
/*
* check 6to4 addresses
*/
if (IN6_IS_ADDR_6TO4(in6))
- return stf_checkaddr4(GET_V4(in6), ifp);
+ return stf_checkaddr4(sc, GET_V4(in6), inifp);
/*
* reject anything that look suspicious. the test is implemented
@@ -476,7 +509,7 @@ void
in_stf_input(struct mbuf *m, ...)
#else
in_stf_input(m, va_alist)
- register struct mbuf *m;
+ struct mbuf *m;
#endif
{
int off, proto;
@@ -514,8 +547,8 @@ in_stf_input(m, va_alist)
* perform sanity check against outer src/dst.
* for source, perform ingress filter as well.
*/
- if (stf_checkaddr4(&ip->ip_dst, NULL) < 0 ||
- stf_checkaddr4(&ip->ip_src, m->m_pkthdr.rcvif) < 0) {
+ if (stf_checkaddr4(sc, &ip->ip_dst, NULL) < 0 ||
+ stf_checkaddr4(sc, &ip->ip_src, m->m_pkthdr.rcvif) < 0) {
m_freem(m);
return;
}
@@ -534,8 +567,8 @@ in_stf_input(m, va_alist)
* perform sanity check against inner src/dst.
* for source, perform ingress filter as well.
*/
- if (stf_checkaddr6(&ip6->ip6_dst, NULL) < 0 ||
- stf_checkaddr6(&ip6->ip6_src, m->m_pkthdr.rcvif) < 0) {
+ if (stf_checkaddr6(sc, &ip6->ip6_dst, NULL) < 0 ||
+ stf_checkaddr6(sc, &ip6->ip6_src, m->m_pkthdr.rcvif) < 0) {
m_freem(m);
return;
}
@@ -543,6 +576,8 @@ in_stf_input(m, va_alist)
itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
if ((ifp->if_flags & IFF_LINK1) != 0)
ip_ecn_egress(ECN_ALLOWED, &otos, &itos);
+ else
+ ip_ecn_egress(ECN_NOCARE, &otos, &itos);
ip6->ip6_flow &= ~htonl(0xff << 20);
ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
@@ -558,7 +593,7 @@ in_stf_input(m, va_alist)
* try to free it or keep a pointer a to it).
*/
struct mbuf m0;
- u_int af = AF_INET6;
+ u_int32_t af = AF_INET6;
m0.m_next = m;
m0.m_len = 4;
@@ -594,11 +629,7 @@ static void
stf_rtrequest(cmd, rt, sa)
int cmd;
struct rtentry *rt;
-#if defined(__bsdi__) && _BSDI_VERSION >= 199802
- struct rt_addrinfo *sa;
-#else
struct sockaddr *sa;
-#endif
{
if (rt)
diff --git a/sys/net/net_osdep.c b/sys/net/net_osdep.c
index 02000f6..ef3bb01 100644
--- a/sys/net/net_osdep.c
+++ b/sys/net/net_osdep.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: net_osdep.c,v 1.4 2000/03/25 07:23:34 sumikawa Exp $ */
+/* $KAME: net_osdep.c,v 1.9 2001/04/06 09:22:05 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -32,6 +32,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
@@ -52,8 +53,15 @@ const char *
if_name(ifp)
struct ifnet *ifp;
{
- static char nam[IFNAMSIZ + 10]; /*enough?*/
+#define MAXNUMBUF 8
+ static char nam[MAXNUMBUF][IFNAMSIZ + 10]; /*enough?*/
+ static int ifbufround = 0;
+ char *cp;
- snprintf(nam, sizeof(nam), "%s%d", ifp->if_name, ifp->if_unit);
- return nam;
+ ifbufround = (ifbufround + 1) % MAXNUMBUF;
+ cp = nam[ifbufround];
+
+ snprintf(cp, sizeof(nam), "%s%d", ifp->if_name, ifp->if_unit);
+ return((const char *)cp);
+#undef MAXNUMBUF
}
diff --git a/sys/net/net_osdep.h b/sys/net/net_osdep.h
index 3bb3c18..399dd31 100644
--- a/sys/net/net_osdep.h
+++ b/sys/net/net_osdep.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: net_osdep.h,v 1.22 2000/08/15 07:23:10 itojun Exp $ */
+/* $KAME: net_osdep.h,v 1.44 2001/05/16 03:13:40 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -36,16 +36,40 @@
/*
* OS dependencies:
*
+ * - whether the IPv4 input routine convert the byte order of some fileds
+ * of the IP header (x: convert to the host byte order, s: strip the header
+ * length for possible reassembly)
+ * ip_len ip_id ip_off
+ * bsdi3: xs x x
+ * bsdi4: xs x
+ * FreeBSD: xs x
+ * NetBSD: x x
+ * OpenBSD: xs x x
+ *
+ * - ifa_ifwithaf()
+ * bsdi[34], netbsd, and openbsd define it in sys/net/if.c
+ * freebsd (all versions) does not have it.
+ *
* - struct rt_addrinfo
- * all *BSDs except bsdi4 only have two members; rti_addrs and rti_info[].
- * bsdi4 has additional members; rti_flags, rti_ifa, rti_ifp, and rti_rtm.
+ * bsdi4, netbsd 1.5R and beyond: rti_addrs, rti_info[], rti_flags, rti_ifa,
+ * rti_ifp, and rti_rtm.
+ * others: rti_addrs and rti_info[] only.
+ *
+ * - ifa->ifa_rtrequest
+ * bsdi4, netbsd 1.5R and beyond: rt_addrinfo *
+ * others: sockaddr * (note that sys/net/route.c:rtrequest() has an unsafe
+ * typecast code, from 4.3BSD-reno)
*
- * - side effects of rtrequest[1](RTM_DELETE)
+ * - side effects of rtrequest{,1}(RTM_DELETE)
* BSDI[34]: delete all cloned routes underneath the route.
* FreeBSD[234]: delete all protocol-cloned routes underneath the route.
* note that cloned routes from an interface direct route
* still remain.
- * NetBSD, OpenBSD: no side effects.
+ * NetBSD: 1.5 have no side effects. KAME/netbsd15, and post-1.5R, have
+ * the same effects as of BSDI.
+ * OpenBSD: have no side effects. KAME/openbsd has the same effects as
+ * of BSDI (the change is not merged - yet).
+ *
* - privileged process
* NetBSD, FreeBSD 3
* struct proc *p;
@@ -64,11 +88,13 @@
* needs to give struct proc * as argument
* OpenBSD, BSDI [34], FreeBSD 2
* do not need struct proc *
+ *
* - bpf:
- * OpenBSD, NetBSD, BSDI [34]
+ * OpenBSD, NetBSD 1.5, BSDI [34]
* need caddr_t * (= if_bpf **) and struct ifnet *
- * FreeBSD 2, FreeBSD 3
+ * FreeBSD 2, FreeBSD 3, NetBSD post-1.5N
* need only struct ifnet * as argument
+ *
* - struct ifnet
* use queue.h? member names if name
* --- --- ---
@@ -77,34 +103,57 @@
* OpenBSD yes standard if_xname
* NetBSD yes standard if_xname
* BSDI [34] no old standard if_name+unit
+ *
* - usrreq
* NetBSD, OpenBSD, BSDI [34], FreeBSD 2
* single function with PRU_xx, arguments are mbuf
* FreeBSD 3
* separates functions, non-mbuf arguments
+ *
* - {set,get}sockopt
* NetBSD, OpenBSD, BSDI [34], FreeBSD 2
* manipulation based on mbuf
* FreeBSD 3
* non-mbuf manipulation using sooptcopy{in,out}()
+ *
* - timeout() and untimeout()
- * NetBSD, OpenBSD, BSDI [34], FreeBSD 2
+ * NetBSD 1.4.x, OpenBSD, BSDI [34], FreeBSD 2
* timeout() is a void function
* FreeBSD 3
* timeout() is non-void, must keep returned value for untimeout()
+ * callout_xx is also available (sys/callout.h)
+ * NetBSD 1.5
+ * timeout() is obsoleted, use callout_xx (sys/callout.h)
+ * OpenBSD 2.8
+ * timeout_{add,set,del} is encouraged (sys/timeout.h)
+ *
* - sysctl
* NetBSD, OpenBSD
* foo_sysctl()
* BSDI [34]
- * foo_sysctl() but with different style
- * FreeBSD 2, FreeBSD 3
- * linker hack
+ * foo_sysctl() but with different style. sysctl_int_arr() takes
+ * care of most of the cases.
+ * FreeBSD
+ * linker hack. however, there are freebsd version differences
+ * (how wonderful!).
+ * on FreeBSD[23] function arg #define includes paren.
+ * int foo SYSCTL_HANDLER_ARGS;
+ * on FreeBSD4, function arg #define does not include paren.
+ * int foo(SYSCTL_HANDLER_ARGS);
+ * on some versions, forward reference to the tree is okay.
+ * on some versions, you need SYSCTL_DECL(). you need things
+ * like this.
+ * #ifdef SYSCTL_DECL
+ * SYSCTL_DECL(net_inet_ip6);
+ * #endif
+ * it is hard to share functions between freebsd and non-freebsd.
*
* - if_ioctl
* NetBSD, FreeBSD 3, BSDI [34]
* 2nd argument is u_long cmd
* FreeBSD 2
* 2nd argument is int cmd
+ *
* - if attach routines
* NetBSD
* void xxattach(int);
@@ -115,6 +164,7 @@
* - ovbcopy()
* in NetBSD 1.4 or later, ovbcopy() is not supplied in the kernel.
* bcopy() is safe against overwrites.
+ *
* - splnet()
* NetBSD 1.4 or later requires splsoftnet().
* other operating systems use splnet().
@@ -125,7 +175,8 @@
* - struct ifnet for loopback interface
* BSDI3: struct ifnet loif;
* BSDI4: struct ifnet *loifp;
- * NetBSD, OpenBSD, FreeBSD2: struct ifnet loif[NLOOP];
+ * NetBSD, OpenBSD 2.8, FreeBSD2: struct ifnet loif[NLOOP];
+ * OpenBSD 2.9: struct ifnet *lo0ifp;
*
* odd thing is that many of them refers loif as ifnet *loif,
* not loif[NLOOP], from outside of if_loop.c.
@@ -145,6 +196,12 @@
* FreeBSD4: struct ipprotosw in netinet/ipprotosw.h
* others: struct protosw in sys/protosw.h
*
+ * - protosw in general.
+ * NetBSD 1.5 has extra member for ipfilter (netbsd-current dropped
+ * it so it will go away in 1.6).
+ * NetBSD 1.5 requires PR_LISTEN flag bit with protocols that permit
+ * listen/accept (like tcp).
+ *
* - header files with defopt (opt_xx.h)
* FreeBSD3: opt_{inet,ipsec,ip6fw,altq}.h
* FreeBSD4: opt_{inet,inet6,ipsec,ip6fw,altq}.h
@@ -154,6 +211,23 @@
* - IN_MULTICAST/IN_CLASS[A-D] macro.
* OpenBSD and NetBSD: net endian (kernel) or host endian (userland)
* others: always host endian
+ *
+ * - (m->m_flags & M_EXT) != 0 does *not* mean that the max data length of
+ * the mbuf == MCLBYTES.
+ *
+ * - sys/kern/uipc_mbuf.c:m_dup()
+ * freebsd[34]: copies the whole mbuf chain.
+ * netbsd: similar arg with m_copym().
+ * others: no m_dup().
+ *
+ * - ifa_refcnt (struct ifaddr) management (IFAREF/IFAFREE).
+ * NetBSD 1.5: always use IFAREF whenever reference gets added.
+ * always use IFAFREE whenever reference gets freed.
+ * IFAFREE frees ifaddr when ifa_refcnt reaches 0.
+ * others: do not increase refcnt for ifp->if_addrlist and in_ifaddr.
+ * use IFAFREE once when ifaddr is disconnected from
+ * ifp->if_addrlist and in_ifaddr. IFAFREE frees ifaddr when
+ * ifa_refcnt goes negative.
*/
#ifndef __NET_NET_OSDEP_H_DEFINED_
@@ -165,6 +239,19 @@ extern const char *if_name __P((struct ifnet *));
#define HAVE_OLD_BPF
+#define ifa_list ifa_link
+#define if_addrlist if_addrhead
+#define if_list if_link
+
+/* sys/net/if.h */
+#define IFAREF(ifa) do { ++(ifa)->ifa_refcnt; } while (0)
+
+#define WITH_CONVERT_AND_STRIP_IP_LEN
+
+#if 1 /* at this moment, all OSes do this */
+#define WITH_CONVERT_IP_OFF
+#endif
+
/*
* Deprecated.
*/
diff --git a/sys/net/pfkeyv2.h b/sys/net/pfkeyv2.h
index 4c41c80..f1c22ad 100644
--- a/sys/net/pfkeyv2.h
+++ b/sys/net/pfkeyv2.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: pfkeyv2.h,v 1.17 2000/06/22 08:38:33 sakane Exp $ */
+/* $KAME: pfkeyv2.h,v 1.25 2001/03/12 08:34:06 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -73,7 +73,7 @@ you leave this credit intact on any copies of this file.
#define SADB_X_SPDDUMP 18
#define SADB_X_SPDFLUSH 19
#define SADB_X_SPDSETIDX 20
-#define SADB_X_SPDEXPIRE 21 /* not yet */
+#define SADB_X_SPDEXPIRE 21
#define SADB_X_SPDDELETE2 22 /* by policy id */
#define SADB_MAX 22
@@ -298,22 +298,32 @@ struct sadb_x_ipsecrequest {
#define SADB_SAFLAGS_PFS 1
-#define SADB_AALG_NONE 0
-#define SADB_AALG_MD5HMAC 1 /* 2 */
-#define SADB_AALG_SHA1HMAC 2 /* 3 */
-#define SADB_AALG_MD5 3 /* Keyed MD5 */
-#define SADB_AALG_SHA 4 /* Keyed SHA */
-#define SADB_AALG_NULL 5 /* null authentication */
-#define SADB_AALG_MAX 6
-
-#define SADB_EALG_NONE 0
-#define SADB_EALG_DESCBC 1 /* 2 */
-#define SADB_EALG_3DESCBC 2 /* 3 */
-#define SADB_EALG_NULL 3 /* 11 */
-#define SADB_EALG_BLOWFISHCBC 4
-#define SADB_EALG_CAST128CBC 5
-#define SADB_EALG_RC5CBC 6
-#define SADB_EALG_MAX 7
+/* RFC2367 numbers - meets RFC2407 */
+#define SADB_AALG_NONE 0
+#define SADB_AALG_MD5HMAC 1 /*2*/
+#define SADB_AALG_SHA1HMAC 2 /*3*/
+#define SADB_AALG_MAX 8
+/* private allocations - based on RFC2407/IANA assignment */
+#define SADB_X_AALG_SHA2_256 6 /*5*/
+#define SADB_X_AALG_SHA2_384 7 /*6*/
+#define SADB_X_AALG_SHA2_512 8 /*7*/
+/* private allocations should use 249-255 (RFC2407) */
+#define SADB_X_AALG_MD5 3 /*249*/ /* Keyed MD5 */
+#define SADB_X_AALG_SHA 4 /*250*/ /* Keyed SHA */
+#define SADB_X_AALG_NULL 5 /*251*/ /* null authentication */
+
+/* RFC2367 numbers - meets RFC2407 */
+#define SADB_EALG_NONE 0
+#define SADB_EALG_DESCBC 1 /*2*/
+#define SADB_EALG_3DESCBC 2 /*3*/
+#define SADB_EALG_NULL 3 /*11*/
+#define SADB_EALG_MAX 12
+/* private allocations - based on RFC2407/IANA assignment */
+#define SADB_X_EALG_CAST128CBC 5 /*6*/
+#define SADB_X_EALG_BLOWFISHCBC 4 /*7*/
+#define SADB_X_EALG_RIJNDAELCBC 12
+#define SADB_X_EALG_AES 12
+/* private allocations should use 249-255 (RFC2407) */
#if 1 /*nonstandard */
#define SADB_X_CALG_NONE 0
diff --git a/sys/net/ppp_defs.h b/sys/net/ppp_defs.h
index ac86be2..be891ee 100644
--- a/sys/net/ppp_defs.h
+++ b/sys/net/ppp_defs.h
@@ -69,6 +69,8 @@
#define PPP_LQR 0xc025 /* Link Quality Report protocol */
#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */
#define PPP_CBCP 0xc029 /* Callback Control Protocol */
+#define PPP_IPV6 0x57 /* Internet Protocol version 6*/
+#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */
/*
* Values for FCS calculations.
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index dc4ae26..6588f56 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -573,9 +573,6 @@ rt_msg1(type, rtinfo)
register struct sockaddr *sa;
int len, dlen;
- m = m_gethdr(M_DONTWAIT, MT_DATA);
- if (m == 0)
- return (m);
switch (type) {
case RTM_DELADDR:
@@ -595,8 +592,18 @@ rt_msg1(type, rtinfo)
default:
len = sizeof(struct rt_msghdr);
}
- if (len > MHLEN)
+ if (len > MCLBYTES)
panic("rt_msg1");
+ m = m_gethdr(M_DONTWAIT, MT_DATA);
+ if (m && len > MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_free(m);
+ m = NULL;
+ }
+ }
+ if (m == 0)
+ return (m);
m->m_pkthdr.len = m->m_len = len;
m->m_pkthdr.rcvif = 0;
rtm = mtod(m, struct rt_msghdr *);
diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h
index 3625ee4..425495d 100644
--- a/sys/netinet/icmp6.h
+++ b/sys/netinet/icmp6.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: icmp6.h,v 1.18 2000/07/03 02:51:08 itojun Exp $ */
+/* $KAME: icmp6.h,v 1.46 2001/04/27 15:09:48 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -80,7 +80,7 @@ struct icmp6_hdr {
u_int16_t icmp6_un_data16[2]; /* type-specific field */
u_int8_t icmp6_un_data8[4]; /* type-specific field */
} icmp6_dataun;
-};
+} __attribute__((__packed__));
#define icmp6_data32 icmp6_dataun.icmp6_un_data32
#define icmp6_data16 icmp6_dataun.icmp6_un_data16
@@ -124,7 +124,10 @@ struct icmp6_hdr {
#define MLD6_MTRACE_RESP 141 /* mtrace response(to sender) */
#define MLD6_MTRACE 142 /* mtrace messages */
-#define ICMP6_MAXTYPE 142
+#define ICMP6_HADISCOV_REQUEST 143 /* XXX To be defined */
+#define ICMP6_HADISCOV_REPLY 144 /* XXX To be defined */
+
+#define ICMP6_MAXTYPE 144
#define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */
#define ICMP6_DST_UNREACH_ADMIN 1 /* administratively prohibited */
@@ -146,7 +149,7 @@ struct icmp6_hdr {
#define ICMP6_NI_SUBJ_FQDN 1 /* Query Subject is a Domain name */
#define ICMP6_NI_SUBJ_IPV4 2 /* Query Subject is an IPv4 address */
-#define ICMP6_NI_SUCESS 0 /* node information successful reply */
+#define ICMP6_NI_SUCCESS 0 /* node information successful reply */
#define ICMP6_NI_REFUSED 1 /* node information request is refused */
#define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */
@@ -164,7 +167,7 @@ struct icmp6_hdr {
struct mld6_hdr {
struct icmp6_hdr mld6_hdr;
struct in6_addr mld6_addr; /* multicast address */
-};
+} __attribute__((__packed__));
#define mld6_type mld6_hdr.icmp6_type
#define mld6_code mld6_hdr.icmp6_code
@@ -179,7 +182,7 @@ struct mld6_hdr {
struct nd_router_solicit { /* router solicitation */
struct icmp6_hdr nd_rs_hdr;
/* could be followed by options */
-};
+} __attribute__((__packed__));
#define nd_rs_type nd_rs_hdr.icmp6_type
#define nd_rs_code nd_rs_hdr.icmp6_code
@@ -191,7 +194,7 @@ struct nd_router_advert { /* router advertisement */
u_int32_t nd_ra_reachable; /* reachable time */
u_int32_t nd_ra_retransmit; /* retransmit timer */
/* could be followed by options */
-};
+} __attribute__((__packed__));
#define nd_ra_type nd_ra_hdr.icmp6_type
#define nd_ra_code nd_ra_hdr.icmp6_code
@@ -200,13 +203,26 @@ struct nd_router_advert { /* router advertisement */
#define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1]
#define ND_RA_FLAG_MANAGED 0x80
#define ND_RA_FLAG_OTHER 0x40
+#define ND_RA_FLAG_HA 0x20
+
+/*
+ * Router preference values based on draft-draves-ipngwg-router-selection-01.
+ * These are non-standard definitions.
+ */
+#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
+
+#define ND_RA_FLAG_RTPREF_HIGH 0x08 /* 00001000 */
+#define ND_RA_FLAG_RTPREF_MEDIUM 0x00 /* 00000000 */
+#define ND_RA_FLAG_RTPREF_LOW 0x18 /* 00011000 */
+#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
+
#define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1]
struct nd_neighbor_solicit { /* neighbor solicitation */
struct icmp6_hdr nd_ns_hdr;
struct in6_addr nd_ns_target; /*target address */
/* could be followed by options */
-};
+} __attribute__((__packed__));
#define nd_ns_type nd_ns_hdr.icmp6_type
#define nd_ns_code nd_ns_hdr.icmp6_code
@@ -217,7 +233,7 @@ struct nd_neighbor_advert { /* neighbor advertisement */
struct icmp6_hdr nd_na_hdr;
struct in6_addr nd_na_target; /* target address */
/* could be followed by options */
-};
+} __attribute__((__packed__));
#define nd_na_type nd_na_hdr.icmp6_type
#define nd_na_code nd_na_hdr.icmp6_code
@@ -240,7 +256,7 @@ struct nd_redirect { /* redirect */
struct in6_addr nd_rd_target; /* target address */
struct in6_addr nd_rd_dst; /* destination address */
/* could be followed by options */
-};
+} __attribute__((__packed__));
#define nd_rd_type nd_rd_hdr.icmp6_type
#define nd_rd_code nd_rd_hdr.icmp6_code
@@ -251,13 +267,14 @@ struct nd_opt_hdr { /* Neighbor discovery option header */
u_int8_t nd_opt_type;
u_int8_t nd_opt_len;
/* followed by option specific data*/
-};
+} __attribute__((__packed__));
#define ND_OPT_SOURCE_LINKADDR 1
#define ND_OPT_TARGET_LINKADDR 2
#define ND_OPT_PREFIX_INFORMATION 3
#define ND_OPT_REDIRECTED_HEADER 4
#define ND_OPT_MTU 5
+#define ND_OPT_ROUTE_INFO 9 /* draft-draves-router-preference, not officially assigned yet */
struct nd_opt_prefix_info { /* prefix information */
u_int8_t nd_opt_pi_type;
@@ -268,7 +285,7 @@ struct nd_opt_prefix_info { /* prefix information */
u_int32_t nd_opt_pi_preferred_time;
u_int32_t nd_opt_pi_reserved2;
struct in6_addr nd_opt_pi_prefix;
-};
+} __attribute__((__packed__));
#define ND_OPT_PI_FLAG_ONLINK 0x80
#define ND_OPT_PI_FLAG_AUTO 0x40
@@ -279,15 +296,23 @@ struct nd_opt_rd_hdr { /* redirected header */
u_int16_t nd_opt_rh_reserved1;
u_int32_t nd_opt_rh_reserved2;
/* followed by IP header and data */
-};
+} __attribute__((__packed__));
struct nd_opt_mtu { /* MTU option */
u_int8_t nd_opt_mtu_type;
u_int8_t nd_opt_mtu_len;
u_int16_t nd_opt_mtu_reserved;
u_int32_t nd_opt_mtu_mtu;
-};
-
+} __attribute__((__packed__));
+
+struct nd_opt_route_info { /* route info */
+ u_int8_t nd_opt_rti_type;
+ u_int8_t nd_opt_rti_len;
+ u_int8_t nd_opt_rti_prefixlen;
+ u_int8_t nd_opt_rti_flags;
+ u_int32_t nd_opt_rti_lifetime;
+ /* followed by prefix */
+} __attribute__((__packed__));
/*
* icmp6 namelookup
*/
@@ -301,7 +326,7 @@ struct icmp6_namelookup {
u_int8_t icmp6_nl_name[3];
#endif
/* could be followed by options */
-};
+} __attribute__((__packed__));
/*
* icmp6 node information
@@ -310,7 +335,7 @@ struct icmp6_nodeinfo {
struct icmp6_hdr icmp6_ni_hdr;
u_int8_t icmp6_ni_nonce[8];
/* could be followed by reply data */
-};
+} __attribute__((__packed__));
#define ni_type icmp6_ni_hdr.icmp6_type
#define ni_code icmp6_ni_hdr.icmp6_code
@@ -320,8 +345,10 @@ struct icmp6_nodeinfo {
#define NI_QTYPE_NOOP 0 /* NOOP */
#define NI_QTYPE_SUPTYPES 1 /* Supported Qtypes */
-#define NI_QTYPE_FQDN 2 /* FQDN */
-#define NI_QTYPE_NODEADDR 3 /* Node Addresses. XXX: spec says 2, but it may be a typo... */
+#define NI_QTYPE_FQDN 2 /* FQDN (draft 04) */
+#define NI_QTYPE_DNSNAME 2 /* DNS Name */
+#define NI_QTYPE_NODEADDR 3 /* Node Addresses */
+#define NI_QTYPE_IPV4ADDR 4 /* IPv4 Addresses */
#if BYTE_ORDER == BIG_ENDIAN
#define NI_SUPTYPE_FLAG_COMPRESS 0x1
@@ -371,7 +398,7 @@ struct ni_reply_fqdn {
u_int32_t ni_fqdn_ttl; /* TTL */
u_int8_t ni_fqdn_namelen; /* length in octets of the FQDN */
u_int8_t ni_fqdn_name[3]; /* XXX: alignment */
-};
+} __attribute__((__packed__));
/*
* Router Renumbering. as router-renum-08.txt
@@ -382,13 +409,13 @@ struct icmp6_router_renum { /* router renumbering header */
u_int8_t rr_flags;
u_int16_t rr_maxdelay;
u_int32_t rr_reserved;
-};
-#define ICMP6_RR_FLAGS_SEGNUM 0x80
-#define ICMP6_RR_FLAGS_TEST 0x40
-#define ICMP6_RR_FLAGS_REQRESULT 0x20
-#define ICMP6_RR_FLAGS_FORCEAPPLY 0x10
-#define ICMP6_RR_FLAGS_SPECSITE 0x08
-#define ICMP6_RR_FLAGS_PREVDONE 0x04
+} __attribute__((__packed__));
+
+#define ICMP6_RR_FLAGS_TEST 0x80
+#define ICMP6_RR_FLAGS_REQRESULT 0x40
+#define ICMP6_RR_FLAGS_FORCEAPPLY 0x20
+#define ICMP6_RR_FLAGS_SPECSITE 0x10
+#define ICMP6_RR_FLAGS_PREVDONE 0x08
#define rr_type rr_hdr.icmp6_type
#define rr_code rr_hdr.icmp6_code
@@ -404,7 +431,7 @@ struct rr_pco_match { /* match prefix part */
u_int8_t rpm_maxlen;
u_int16_t rpm_reserved;
struct in6_addr rpm_prefix;
-};
+} __attribute__((__packed__));
#define RPM_PCO_ADD 1
#define RPM_PCO_CHANGE 2
@@ -420,7 +447,7 @@ struct rr_pco_use { /* use prefix part */
u_int32_t rpu_pltime;
u_int32_t rpu_flags;
struct in6_addr rpu_prefix;
-};
+} __attribute__((__packed__));
#define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x80
#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x40
@@ -438,13 +465,13 @@ struct rr_result { /* router renumbering result message */
u_int8_t rrr_matchedlen;
u_int32_t rrr_ifid;
struct in6_addr rrr_prefix;
-};
+} __attribute__((__packed__));
#if BYTE_ORDER == BIG_ENDIAN
#define ICMP6_RR_RESULT_FLAGS_OOB 0x0002
#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0001
#elif BYTE_ORDER == LITTLE_ENDIAN
-#define ICMP6_RR_RESULT_FLAGS_OOB 0x02
-#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x01
+#define ICMP6_RR_RESULT_FLAGS_OOB 0x0200
+#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0100
#endif
/*
@@ -534,6 +561,13 @@ struct icmp6stat {
#define icp6s_oparamprob_option icp6s_outerrhist.icp6errs_paramprob_option
#define icp6s_oredirect icp6s_outerrhist.icp6errs_redirect
#define icp6s_ounknown icp6s_outerrhist.icp6errs_unknown
+ u_quad_t icp6s_pmtuchg; /* path MTU changes */
+ u_quad_t icp6s_nd_badopt; /* bad ND options */
+ u_quad_t icp6s_badns; /* bad neighbor solicitation */
+ u_quad_t icp6s_badna; /* bad neighbor advertisement */
+ u_quad_t icp6s_badrs; /* bad router advertisement */
+ u_quad_t icp6s_badra; /* bad router advertisement */
+ u_quad_t icp6s_badredirect; /* bad redirect message */
};
/*
@@ -542,7 +576,9 @@ struct icmp6stat {
#define ICMPV6CTL_STATS 1
#define ICMPV6CTL_REDIRACCEPT 2 /* accept/process redirects */
#define ICMPV6CTL_REDIRTIMEOUT 3 /* redirect cache time */
+#if 0 /*obsoleted*/
#define ICMPV6CTL_ERRRATELIMIT 5 /* ICMPv6 error rate limitation */
+#endif
#define ICMPV6CTL_ND6_PRUNE 6
#define ICMPV6CTL_ND6_DELAY 8
#define ICMPV6CTL_ND6_UMAXTRIES 9
@@ -552,7 +588,12 @@ struct icmp6stat {
#define ICMPV6CTL_NODEINFO 13
#define ICMPV6CTL_ERRPPSLIMIT 14 /* ICMPv6 error pps limitation */
#define ICMPV6CTL_ND6_MAXNUDHINT 15
-#define ICMPV6CTL_MAXID 16
+#define ICMPV6CTL_MTUDISC_HIWAT 16
+#define ICMPV6CTL_MTUDISC_LOWAT 17
+#define ICMPV6CTL_ND6_DEBUG 18
+#define ICMPV6CTL_ND6_DRLIST 19
+#define ICMPV6CTL_ND6_PRLIST 20
+#define ICMPV6CTL_MAXID 21
#define ICMPV6CTL_NAMES { \
{ 0, 0 }, \
@@ -560,7 +601,7 @@ struct icmp6stat {
{ "rediraccept", CTLTYPE_INT }, \
{ "redirtimeout", CTLTYPE_INT }, \
{ 0, 0 }, \
- { "errratelimit", CTLTYPE_INT }, \
+ { 0, 0 }, \
{ "nd6_prune", CTLTYPE_INT }, \
{ 0, 0 }, \
{ "nd6_delay", CTLTYPE_INT }, \
@@ -571,6 +612,11 @@ struct icmp6stat {
{ "nodeinfo", CTLTYPE_INT }, \
{ "errppslimit", CTLTYPE_INT }, \
{ "nd6_maxnudhint", CTLTYPE_INT }, \
+ { "mtudisc_hiwat", CTLTYPE_INT }, \
+ { "mtudisc_lowat", CTLTYPE_INT }, \
+ { "nd6_debug", CTLTYPE_INT }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
}
#define RTF_PROBEMTU RTF_PROTO1
@@ -591,6 +637,9 @@ void icmp6_prepare __P((struct mbuf *));
void icmp6_redirect_input __P((struct mbuf *, int));
void icmp6_redirect_output __P((struct mbuf *, struct rtentry *));
+struct ip6ctlparam;
+void icmp6_mtudisc_update __P((struct ip6ctlparam *, int));
+
/* XXX: is this the right place for these macros? */
#define icmp6_ifstat_inc(ifp, tag) \
do { \
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index 95abe3f..170a343 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -51,11 +51,6 @@
#include <netinet/igmp_var.h>
-#include "gif.h"
-#if NGIF > 0
-#include <net/if_gif.h>
-#endif
-
static MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address");
static int in_mask2len __P((struct in_addr *));
@@ -200,21 +195,6 @@ in_control(so, cmd, data, ifp, p)
int error, hostIsNew, maskIsNew, s;
u_long i;
-#if NGIF > 0
- if (ifp && ifp->if_type == IFT_GIF) {
- switch (cmd) {
- case SIOCSIFPHYADDR:
- case SIOCDIFPHYADDR:
- if (p &&
- (error = suser(p)) != 0)
- return(error);
- case SIOCGIFPSRCADDR:
- case SIOCGIFPDSTADDR:
- return gif_ioctl(ifp, cmd, data);
- }
- }
-#endif
-
switch (cmd) {
case SIOCALIFADDR:
case SIOCDLIFADDR:
@@ -713,6 +693,9 @@ in_ifinit(ifp, ia, sin, scrub)
}
if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
ia->ia_flags |= IFA_ROUTE;
+ /* XXX check if the subnet route points to the same interface */
+ if (error == EEXIST)
+ error = 0;
/*
* If the interface supports multicast, join the "all hosts"
diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c
index 17955ad..5ad92e1 100644
--- a/sys/netinet/in_gif.c
+++ b/sys/netinet/in_gif.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in_gif.c,v 1.44 2000/08/15 07:24:24 itojun Exp $ */
+/* $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -88,7 +88,7 @@ in_gif_output(ifp, family, m, rt)
struct mbuf *m;
struct rtentry *rt;
{
- register struct gif_softc *sc = (struct gif_softc*)ifp;
+ struct gif_softc *sc = (struct gif_softc*)ifp;
struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst;
struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc;
struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst;
@@ -146,29 +146,12 @@ in_gif_output(ifp, family, m, rt)
bzero(&iphdr, sizeof(iphdr));
iphdr.ip_src = sin_src->sin_addr;
- if (ifp->if_flags & IFF_LINK0) {
- /* multi-destination mode */
- if (sin_dst->sin_addr.s_addr != INADDR_ANY)
- iphdr.ip_dst = sin_dst->sin_addr;
- else if (rt) {
- if (family != AF_INET) {
- m_freem(m);
- return EINVAL; /*XXX*/
- }
- iphdr.ip_dst = ((struct sockaddr_in *)
- (rt->rt_gateway))->sin_addr;
- } else {
- m_freem(m);
- return ENETUNREACH;
- }
- } else {
- /* bidirectional configured tunnel mode */
- if (sin_dst->sin_addr.s_addr != INADDR_ANY)
- iphdr.ip_dst = sin_dst->sin_addr;
- else {
- m_freem(m);
- return ENETUNREACH;
- }
+ /* bidirectional configured tunnel mode */
+ if (sin_dst->sin_addr.s_addr != INADDR_ANY)
+ iphdr.ip_dst = sin_dst->sin_addr;
+ else {
+ m_freem(m);
+ return ENETUNREACH;
}
iphdr.ip_p = proto;
/* version will be set in ip_output() */
@@ -176,6 +159,8 @@ in_gif_output(ifp, family, m, rt)
iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip);
if (ifp->if_flags & IFF_LINK1)
ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos);
+ else
+ ip_ecn_ingress(ECN_NOCARE, &iphdr.ip_tos, &tos);
/* prepend new IP header */
M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
@@ -272,6 +257,8 @@ in_gif_input(m, va_alist)
ip = mtod(m, struct ip *);
if (gifp->if_flags & IFF_LINK1)
ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos);
+ else
+ ip_ecn_egress(ECN_NOCARE, &otos, &ip->ip_tos);
break;
}
#endif
@@ -290,6 +277,8 @@ in_gif_input(m, va_alist)
itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
if (gifp->if_flags & IFF_LINK1)
ip_ecn_egress(ECN_ALLOWED, &otos, &itos);
+ else
+ ip_ecn_egress(ECN_NOCARE, &otos, &itos);
ip6->ip6_flow &= ~htonl(0xff << 20);
ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
break;
@@ -335,10 +324,6 @@ gif_encapcheck4(m, off, proto, arg)
addrmatch |= 1;
if (dst->sin_addr.s_addr == ip.ip_src.s_addr)
addrmatch |= 2;
- else if ((sc->gif_if.if_flags & IFF_LINK0) != 0 &&
- dst->sin_addr.s_addr == INADDR_ANY) {
- addrmatch |= 2; /* we accept any source */
- }
if (addrmatch != 3)
return 0;
@@ -359,7 +344,8 @@ gif_encapcheck4(m, off, proto, arg)
}
/* ingress filters on outer source */
- if ((m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) {
+ if ((sc->gif_if.if_flags & IFF_LINK2) == 0 &&
+ (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) {
struct sockaddr_in sin;
struct rtentry *rt;
@@ -368,15 +354,18 @@ gif_encapcheck4(m, off, proto, arg)
sin.sin_len = sizeof(struct sockaddr_in);
sin.sin_addr = ip.ip_src;
rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
- if (!rt)
- return 0;
- if (rt->rt_ifp != m->m_pkthdr.rcvif) {
- rtfree(rt);
+ if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) {
+#if 0
+ log(LOG_WARNING, "%s: packet from 0x%x dropped "
+ "due to ingress filter\n", if_name(&sc->gif_if),
+ (u_int32_t)ntohl(sin.sin_addr.s_addr));
+#endif
+ if (rt)
+ rtfree(rt);
return 0;
}
rtfree(rt);
}
- /* prioritize: IFF_LINK0 mode is less preferred */
- return (sc->gif_if.if_flags & IFF_LINK0) ? 32 : 32 * 2;
+ return 32 * 2;
}
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index b24b404..ba5f77f 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -151,14 +151,16 @@ in_pcballoc(so, pcbinfo, p)
inp->inp_pcbinfo = pcbinfo;
inp->inp_socket = so;
#if defined(INET6)
- if (ip6_mapped_addr_on)
- inp->inp_flags &= ~IN6P_BINDV6ONLY;
- else
- inp->inp_flags |= IN6P_BINDV6ONLY;
+ if (INP_SOCKAF(so) == AF_INET6 && !ip6_mapped_addr_on)
+ inp->inp_flags |= IN6P_IPV6_V6ONLY;
#endif
LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
pcbinfo->ipi_count++;
so->so_pcb = (caddr_t)inp;
+#ifdef INET6
+ if (ip6_auto_flowlabel)
+ inp->inp_flags |= IN6P_AUTOFLOWLABEL;
+#endif
return (0);
}
@@ -234,9 +236,7 @@ in_pcbbind(inp, nam, p)
(so->so_cred->cr_uid !=
t->inp_socket->so_cred->cr_uid)) {
#if defined(INET6)
- if ((inp->inp_flags &
- IN6P_BINDV6ONLY) != 0 ||
- ntohl(sin->sin_addr.s_addr) !=
+ if (ntohl(sin->sin_addr.s_addr) !=
INADDR_ANY ||
ntohl(t->inp_laddr.s_addr) !=
INADDR_ANY ||
@@ -254,8 +254,7 @@ in_pcbbind(inp, nam, p)
if (t &&
(reuseport & t->inp_socket->so_options) == 0) {
#if defined(INET6)
- if ((inp->inp_flags & IN6P_BINDV6ONLY) != 0 ||
- ntohl(sin->sin_addr.s_addr) !=
+ if (ntohl(sin->sin_addr.s_addr) !=
INADDR_ANY ||
ntohl(t->inp_laddr.s_addr) !=
INADDR_ANY ||
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index f4abb4d..1ae93d2 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -226,25 +226,27 @@ struct inpcbinfo { /* XXX documentation, prefixes */
#define INP_RECVIF 0x80 /* receive incoming interface */
#define INP_MTUDISC 0x100 /* user can do MTU discovery */
#define INP_FAITH 0x200 /* accept FAITH'ed connections */
-#define IN6P_PKTINFO 0x010000
-#define IN6P_HOPLIMIT 0x020000
-#define IN6P_NEXTHOP 0x040000
-#define IN6P_HOPOPTS 0x080000
-#define IN6P_DSTOPTS 0x100000
-#define IN6P_RTHDR 0x200000
-#define IN6P_BINDV6ONLY 0x400000
+
+#define IN6P_IPV6_V6ONLY 0x008000 /* restrict AF_INET6 socket for v6 */
+
+#define IN6P_PKTINFO 0x010000 /* receive IP6 dst and I/F */
+#define IN6P_HOPLIMIT 0x020000 /* receive hoplimit */
+#define IN6P_HOPOPTS 0x040000 /* receive hop-by-hop options */
+#define IN6P_DSTOPTS 0x080000 /* receive dst options after rthdr */
+#define IN6P_RTHDR 0x100000 /* receive routing header */
+#define IN6P_RTHDRDSTOPTS 0x200000 /* receive dstoptions before rthdr */
+#define IN6P_AUTOFLOWLABEL 0x800000 /* attach flowlabel automatically */
+#define IN6P_BINDV6ONLY 0x10000000 /* do not grab IPv4 traffic */
+
#define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\
INP_RECVIF|\
- IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_NEXTHOP|\
- IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR)
-
-#define INP_UNMAPPABLEOPTS (IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR)
+ IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_HOPOPTS|\
+ IN6P_DSTOPTS|IN6P_RTHDR|IN6P_RTHDRDSTOPTS|\
+ IN6P_AUTOFLOWLABEL)
+#define INP_UNMAPPABLEOPTS (IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR|\
+ IN6P_AUTOFLOWLABEL)
/* for KAME src sync over BSD*'s */
-#define IN6P_RECVOPTS INP_RECVOPTS
-#define IN6P_RECVRETOPTS INP_RECVRETOPTS
-#define IN6P_RECVDSTADDR INP_RECVDSTADDR
-#define IN6P_HDRINCL INP_HDRINCL
#define IN6P_HIGHPORT INP_HIGHPORT
#define IN6P_LOWPORT INP_LOWPORT
#define IN6P_ANONPORT INP_ANONPORT
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index 02e6313..4c07a04 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -75,6 +75,7 @@
#ifdef IPSEC_ESP
#include <netinet6/esp.h>
#endif
+#include <netinet6/ipcomp.h>
#endif /* IPSEC */
#include "gif.h"
@@ -125,19 +126,19 @@ struct ipprotosw inetsw[] = {
0, 0, 0, 0,
&rip_usrreqs
},
-{ SOCK_RAW, &inetdomain, IPPROTO_ICMP, PR_ATOMIC|PR_ADDR,
+{ SOCK_RAW, &inetdomain, IPPROTO_ICMP, PR_ATOMIC|PR_ADDR|PR_LASTHDR,
icmp_input, 0, 0, rip_ctloutput,
0,
0, 0, 0, 0,
&rip_usrreqs
},
-{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR,
+{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR|PR_LASTHDR,
igmp_input, 0, 0, rip_ctloutput,
0,
igmp_init, igmp_fasttimo, igmp_slowtimo, 0,
&rip_usrreqs
},
-{ SOCK_RAW, &inetdomain, IPPROTO_RSVP, PR_ATOMIC|PR_ADDR,
+{ SOCK_RAW, &inetdomain, IPPROTO_RSVP, PR_ATOMIC|PR_ADDR|PR_LASTHDR,
rsvp_input, 0, 0, rip_ctloutput,
0,
0, 0, 0, 0,
@@ -158,19 +159,25 @@ struct ipprotosw inetsw[] = {
&nousrreqs
},
#endif
+{ SOCK_RAW, &inetdomain, IPPROTO_IPCOMP, PR_ATOMIC|PR_ADDR,
+ ipcomp4_input, 0, 0, 0,
+ 0,
+ 0, 0, 0, 0,
+ &nousrreqs
+},
#endif /* IPSEC */
-{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR,
+{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR|PR_LASTHDR,
encap4_input, 0, 0, rip_ctloutput,
0,
encap_init, 0, 0, 0,
- &nousrreqs
+ &rip_usrreqs
},
# ifdef INET6
-{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR,
+{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR|PR_LASTHDR,
encap4_input, 0, 0, rip_ctloutput,
0,
- 0, 0, 0, 0,
- &nousrreqs
+ encap_init, 0, 0, 0,
+ &rip_usrreqs
},
#endif
#ifdef IPDIVERT
@@ -182,7 +189,7 @@ struct ipprotosw inetsw[] = {
},
#endif
#ifdef IPXIP
-{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR,
+{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR|PR_LASTHDR,
ipxip_input, 0, ipxip_ctlinput, 0,
0,
0, 0, 0, 0,
@@ -190,7 +197,7 @@ struct ipprotosw inetsw[] = {
},
#endif
#ifdef NSIP
-{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR,
+{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR|PR_LASTHDR,
idpip_input, 0, nsip_ctlinput, 0,
0,
0, 0, 0, 0,
diff --git a/sys/netinet/ip6.h b/sys/netinet/ip6.h
index 77d1ab6..ec2c216 100644
--- a/sys/netinet/ip6.h
+++ b/sys/netinet/ip6.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip6.h,v 1.9 2000/07/02 21:01:32 itojun Exp $ */
+/* $KAME: ip6.h,v 1.18 2001/03/29 05:34:30 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -85,7 +85,7 @@ struct ip6_hdr {
} ip6_ctlun;
struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */
-};
+} __attribute__((__packed__));
#define ip6_vfc ip6_ctlun.ip6_un2_vfc
#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
@@ -106,18 +106,20 @@ struct ip6_hdr {
#define IPV6_FLOWLABEL_MASK 0xffff0f00 /* flow label (20 bits) */
#endif /* LITTLE_ENDIAN */
#endif
+#if 1
/* ECN bits proposed by Sally Floyd */
#define IP6TOS_CE 0x01 /* congestion experienced */
#define IP6TOS_ECT 0x02 /* ECN-capable transport */
+#endif
/*
* Extension Headers
*/
struct ip6_ext {
- u_char ip6e_nxt;
- u_char ip6e_len;
-};
+ u_int8_t ip6e_nxt;
+ u_int8_t ip6e_len;
+} __attribute__((__packed__));
/* Hop-by-Hop options header */
/* XXX should we pad it to force alignment on an 8-byte boundary? */
@@ -125,7 +127,7 @@ struct ip6_hbh {
u_int8_t ip6h_nxt; /* next header */
u_int8_t ip6h_len; /* length in units of 8 octets */
/* followed by options */
-};
+} __attribute__((__packed__));
/* Destination options header */
/* XXX should we pad it to force alignment on an 8-byte boundary? */
@@ -133,20 +135,28 @@ struct ip6_dest {
u_int8_t ip6d_nxt; /* next header */
u_int8_t ip6d_len; /* length in units of 8 octets */
/* followed by options */
-};
+} __attribute__((__packed__));
/* Option types and related macros */
#define IP6OPT_PAD1 0x00 /* 00 0 00000 */
#define IP6OPT_PADN 0x01 /* 00 0 00001 */
#define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */
-#define IP6OPT_JUMBO_LEN 6
-#define IP6OPT_RTALERT 0x05 /* 00 0 00101 */
+#define IP6OPT_NSAP_ADDR 0xC3 /* 11 0 00011 */
+#define IP6OPT_TUNNEL_LIMIT 0x04 /* 00 0 00100 */
+#define IP6OPT_RTALERT 0x05 /* 00 0 00101 (KAME definition) */
+
#define IP6OPT_RTALERT_LEN 4
#define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */
#define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */
#define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */
#define IP6OPT_MINLEN 2
+#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */
+#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */
+#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */
+#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */
+#define IP6OPT_EID 0x8a /* 10 0 01010 */
+
#define IP6OPT_TYPE(o) ((o) & 0xC0)
#define IP6OPT_TYPE_SKIP 0x00
#define IP6OPT_TYPE_DISCARD 0x40
@@ -155,6 +165,8 @@ struct ip6_dest {
#define IP6OPT_MUTABLE 0x20
+#define IP6OPT_JUMBO_LEN 6
+
/* Routing header */
struct ip6_rthdr {
u_int8_t ip6r_nxt; /* next header */
@@ -162,7 +174,7 @@ struct ip6_rthdr {
u_int8_t ip6r_type; /* routing type */
u_int8_t ip6r_segleft; /* segments left */
/* followed by routing type specific data */
-};
+} __attribute__((__packed__));
/* Type 0 Routing header */
struct ip6_rthdr0 {
@@ -173,7 +185,7 @@ struct ip6_rthdr0 {
u_int8_t ip6r0_reserved; /* reserved field */
u_int8_t ip6r0_slmap[3]; /* strict/loose bit map */
struct in6_addr ip6r0_addr[1]; /* up to 23 addresses */
-};
+} __attribute__((__packed__));
/* Fragment header */
struct ip6_frag {
@@ -181,7 +193,7 @@ struct ip6_frag {
u_int8_t ip6f_reserved; /* reserved field */
u_int16_t ip6f_offlg; /* offset, reserved, and flag */
u_int32_t ip6f_ident; /* identification */
-};
+} __attribute__((__packed__));
#if BYTE_ORDER == BIG_ENDIAN
#define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */
diff --git a/sys/netinet/ip_ecn.c b/sys/netinet/ip_ecn.c
index 047f82e..3abc3b6 100644
--- a/sys/netinet/ip_ecn.c
+++ b/sys/netinet/ip_ecn.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip_ecn.c,v 1.7 2000/05/05 11:00:56 sumikawa Exp $ */
+/* $KAME: ip_ecn.c,v 1.11 2001/05/03 16:09:29 itojun Exp $ */
/*
* Copyright (C) 1999 WIDE Project.
@@ -43,16 +43,10 @@
#include <sys/mbuf.h>
#include <sys/errno.h>
-#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
-#endif
-
#ifdef INET6
-#ifndef INET
-#include <netinet/in.h>
-#endif
#include <netinet/ip6.h>
#endif
@@ -63,17 +57,17 @@
/*
* modify outer ECN (TOS) field on ingress operation (tunnel encapsulation).
- * call it after you've done the default initialization/copy for the outer.
*/
void
ip_ecn_ingress(mode, outer, inner)
int mode;
u_int8_t *outer;
- u_int8_t *inner;
+ const u_int8_t *inner;
{
if (!outer || !inner)
panic("NULL pointer passed to ip_ecn_ingress");
+ *outer = *inner;
switch (mode) {
case ECN_ALLOWED: /* ECN allowed */
*outer &= ~IPTOS_CE;
@@ -88,12 +82,11 @@ ip_ecn_ingress(mode, outer, inner)
/*
* modify inner ECN (TOS) field on egress operation (tunnel decapsulation).
- * call it after you've done the default initialization/copy for the inner.
*/
void
ip_ecn_egress(mode, outer, inner)
int mode;
- u_int8_t *outer;
+ const u_int8_t *outer;
u_int8_t *inner;
{
if (!outer || !inner)
@@ -115,14 +108,13 @@ void
ip6_ecn_ingress(mode, outer, inner)
int mode;
u_int32_t *outer;
- u_int32_t *inner;
+ const u_int32_t *inner;
{
u_int8_t outer8, inner8;
if (!outer || !inner)
panic("NULL pointer passed to ip6_ecn_ingress");
- outer8 = (ntohl(*outer) >> 20) & 0xff;
inner8 = (ntohl(*inner) >> 20) & 0xff;
ip_ecn_ingress(mode, &outer8, &inner8);
*outer &= ~htonl(0xff << 20);
@@ -132,7 +124,7 @@ ip6_ecn_ingress(mode, outer, inner)
void
ip6_ecn_egress(mode, outer, inner)
int mode;
- u_int32_t *outer;
+ const u_int32_t *outer;
u_int32_t *inner;
{
u_int8_t outer8, inner8;
@@ -141,7 +133,6 @@ ip6_ecn_egress(mode, outer, inner)
panic("NULL pointer passed to ip6_ecn_egress");
outer8 = (ntohl(*outer) >> 20) & 0xff;
- inner8 = (ntohl(*inner) >> 20) & 0xff;
ip_ecn_egress(mode, &outer8, &inner8);
*inner &= ~htonl(0xff << 20);
*inner |= htonl((u_int32_t)inner8 << 20);
diff --git a/sys/netinet/ip_ecn.h b/sys/netinet/ip_ecn.h
index 6445d0f..9aca731 100644
--- a/sys/netinet/ip_ecn.h
+++ b/sys/netinet/ip_ecn.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip_ecn.h,v 1.5 2000/03/27 04:58:38 sumikawa Exp $ */
+/* $KAME: ip_ecn.h,v 1.6 2001/05/03 14:51:48 itojun Exp $ */
/*
* Copyright (C) 1999 WIDE Project.
@@ -35,11 +35,15 @@
* http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt
*/
+#if defined(_KERNEL) && !defined(_LKM)
+#include "opt_inet.h"
+#endif
+
#define ECN_ALLOWED 1 /* ECN allowed */
#define ECN_FORBIDDEN 0 /* ECN forbidden */
#define ECN_NOCARE (-1) /* no consideration to ECN */
#ifdef _KERNEL
-extern void ip_ecn_ingress __P((int, u_int8_t *, u_int8_t *));
-extern void ip_ecn_egress __P((int, u_int8_t *, u_int8_t *));
+extern void ip_ecn_ingress __P((int, u_int8_t *, const u_int8_t *));
+extern void ip_ecn_egress __P((int, const u_int8_t *, u_int8_t *));
#endif
diff --git a/sys/netinet/ip_encap.c b/sys/netinet/ip_encap.c
index 7d623ea..7463300 100644
--- a/sys/netinet/ip_encap.c
+++ b/sys/netinet/ip_encap.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip_encap.c,v 1.36 2000/06/17 20:34:24 itojun Exp $ */
+/* $KAME: ip_encap.c,v 1.41 2001/03/15 08:35:08 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -67,6 +67,7 @@
#include <sys/mbuf.h>
#include <sys/errno.h>
#include <sys/protosw.h>
+#include <sys/queue.h>
#include <net/if.h>
#include <net/route.h>
@@ -100,12 +101,21 @@ static int mask_match __P((const struct encaptab *, const struct sockaddr *,
const struct sockaddr *));
static void encap_fillarg __P((struct mbuf *, const struct encaptab *));
+#ifndef LIST_HEAD_INITIALIZER
/* rely upon BSS initialization */
LIST_HEAD(, encaptab) encaptab;
+#else
+LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab);
+#endif
void
encap_init()
{
+ static int initialized = 0;
+
+ if (initialized)
+ return;
+ initialized++;
#if 0
/*
* we cannot use LIST_INIT() here, since drivers may want to call
@@ -118,6 +128,7 @@ encap_init()
#endif
}
+#ifdef INET
void
#if __STDC__
encap4_input(struct mbuf *m, ...)
@@ -221,6 +232,7 @@ encap4_input(m, va_alist)
/* last resort: inject to raw socket */
rip_input(m, off, proto);
}
+#endif
#ifdef INET6
int
diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c
index ddb95f0..7e8c722 100644
--- a/sys/netinet/ip_icmp.c
+++ b/sys/netinet/ip_icmp.c
@@ -296,15 +296,6 @@ icmp_input(m, off, proto)
icp->icmp_code);
#endif
-#ifdef IPSEC
- /* drop it if it does not match the policy */
- /* XXX Is there meaning of check in here ? */
- if (ipsec4_in_reject(m, NULL)) {
- ipsecstat.in_polvio++;
- goto freeit;
- }
-#endif
-
/*
* Message type specific processing.
*/
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 7cd8568..3cf13cf 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -350,6 +350,16 @@ ip_input(struct mbuf *m)
}
ip = mtod(m, struct ip *);
}
+
+ /* 127/8 must not appear on wire - RFC1122 */
+ if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
+ (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
+ if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
+ ipstat.ips_badaddr++;
+ goto bad;
+ }
+ }
+
if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) {
sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
} else {
@@ -393,15 +403,10 @@ tooshort:
m_adj(m, ip->ip_len - m->m_pkthdr.len);
}
- /*
- * Don't accept packets with a loopback destination address
- * unless they arrived via the loopback interface.
- */
- if ((ntohl(ip->ip_dst.s_addr) & IN_CLASSA_NET) ==
- (IN_LOOPBACKNET << IN_CLASSA_NSHIFT) &&
- (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
- goto bad;
- }
+#ifdef IPSEC
+ if (ipsec_gethist(m, NULL))
+ goto pass;
+#endif
/*
* IpHack's section.
@@ -796,6 +801,19 @@ found:
}
#endif
+#ifdef IPSEC
+ /*
+ * enforce IPsec policy checking if we are seeing last header.
+ * note that we do not visit this with protocols with pcb layer
+ * code - like udp/tcp/raw ip.
+ */
+ if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 &&
+ ipsec4_in_reject(m, NULL)) {
+ ipsecstat.in_polvio++;
+ goto bad;
+ }
+#endif
+
/*
* Switch out to protocol's input routine.
*/
@@ -1189,6 +1207,10 @@ ip_dooptions(m)
*/
case IPOPT_LSRR:
case IPOPT_SSRR:
+ if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
+ code = &cp[IPOPT_OLEN] - (u_char *)ip;
+ goto bad;
+ }
if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
code = &cp[IPOPT_OFFSET] - (u_char *)ip;
goto bad;
@@ -1308,12 +1330,21 @@ nosourcerouting:
case IPOPT_TS:
code = cp - (u_char *)ip;
ipt = (struct ip_timestamp *)cp;
- if (ipt->ipt_len < 5)
+ if (ipt->ipt_len < 4 || ipt->ipt_len > 40) {
+ code = (u_char *)&ipt->ipt_len - (u_char *)ip;
goto bad;
+ }
+ if (ipt->ipt_ptr < 5) {
+ code = (u_char *)&ipt->ipt_ptr - (u_char *)ip;
+ goto bad;
+ }
if (ipt->ipt_ptr >
ipt->ipt_len - (int)sizeof(int32_t)) {
- if (++ipt->ipt_oflw == 0)
+ if (++ipt->ipt_oflw == 0) {
+ code = (u_char *)&ipt->ipt_ptr -
+ (u_char *)ip;
goto bad;
+ }
break;
}
sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
@@ -1324,8 +1355,11 @@ nosourcerouting:
case IPOPT_TS_TSANDADDR:
if (ipt->ipt_ptr - 1 + sizeof(n_time) +
- sizeof(struct in_addr) > ipt->ipt_len)
+ sizeof(struct in_addr) > ipt->ipt_len) {
+ code = (u_char *)&ipt->ipt_ptr -
+ (u_char *)ip;
goto bad;
+ }
ipaddr.sin_addr = dst;
ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
m->m_pkthdr.rcvif);
@@ -1338,8 +1372,11 @@ nosourcerouting:
case IPOPT_TS_PRESPEC:
if (ipt->ipt_ptr - 1 + sizeof(n_time) +
- sizeof(struct in_addr) > ipt->ipt_len)
+ sizeof(struct in_addr) > ipt->ipt_len) {
+ code = (u_char *)&ipt->ipt_ptr -
+ (u_char *)ip;
goto bad;
+ }
(void)memcpy(&ipaddr.sin_addr, sin,
sizeof(struct in_addr));
if (ifa_ifwithaddr((SA)&ipaddr) == 0)
@@ -1348,6 +1385,9 @@ nosourcerouting:
break;
default:
+ /* XXX can't take &ipt->ipt_flg */
+ code = (u_char *)&ipt->ipt_ptr -
+ (u_char *)ip + 1;
goto bad;
}
ntime = iptime();
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 1025e37..10de694 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -95,6 +95,7 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
u_short ip_id;
static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
+static struct ifnet *ip_multicast_if __P((struct in_addr *, int *));
static void ip_mloopback
__P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int));
static int ip_getmoptions
@@ -177,7 +178,7 @@ ip_output(m0, opt, ro, flags, imo)
m0 = m = m->m_next ;
#ifdef IPSEC
so = ipsec_getsocket(m);
- ipsec_setsocket(m, NULL);
+ (void)ipsec_setsocket(m, NULL);
#endif
ip = mtod(m, struct ip *);
hlen = IP_VHL_HL(ip->ip_vhl) << 2 ;
@@ -188,7 +189,7 @@ ip_output(m0, opt, ro, flags, imo)
#endif
#ifdef IPSEC
so = ipsec_getsocket(m);
- ipsec_setsocket(m, NULL);
+ (void)ipsec_setsocket(m, NULL);
#endif
#ifdef DIAGNOSTIC
@@ -430,6 +431,133 @@ ip_output(m0, opt, ro, flags, imo)
}
sendit:
+#ifdef IPSEC
+ /* get SP for this packet */
+ if (so == NULL)
+ sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error);
+ else
+ sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error);
+
+ if (sp == NULL) {
+ ipsecstat.out_inval++;
+ goto bad;
+ }
+
+ error = 0;
+
+ /* check policy */
+ switch (sp->policy) {
+ case IPSEC_POLICY_DISCARD:
+ /*
+ * This packet is just discarded.
+ */
+ ipsecstat.out_polvio++;
+ goto bad;
+
+ case IPSEC_POLICY_BYPASS:
+ case IPSEC_POLICY_NONE:
+ /* no need to do IPsec. */
+ goto skip_ipsec;
+
+ case IPSEC_POLICY_IPSEC:
+ if (sp->req == NULL) {
+ /* acquire a policy */
+ error = key_spdacquire(sp);
+ goto bad;
+ }
+ break;
+
+ case IPSEC_POLICY_ENTRUST:
+ default:
+ printf("ip_output: Invalid policy found. %d\n", sp->policy);
+ }
+ {
+ struct ipsec_output_state state;
+ bzero(&state, sizeof(state));
+ state.m = m;
+ if (flags & IP_ROUTETOIF) {
+ state.ro = &iproute;
+ bzero(&iproute, sizeof(iproute));
+ } else
+ state.ro = ro;
+ state.dst = (struct sockaddr *)dst;
+
+ ip->ip_sum = 0;
+
+ /*
+ * XXX
+ * delayed checksums are not currently compatible with IPsec
+ */
+ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+ in_delayed_cksum(m);
+ m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
+ }
+
+ HTONS(ip->ip_len);
+ HTONS(ip->ip_off);
+
+ error = ipsec4_output(&state, sp, flags);
+
+ m = state.m;
+ if (flags & IP_ROUTETOIF) {
+ /*
+ * if we have tunnel mode SA, we may need to ignore
+ * IP_ROUTETOIF.
+ */
+ if (state.ro != &iproute || state.ro->ro_rt != NULL) {
+ flags &= ~IP_ROUTETOIF;
+ ro = state.ro;
+ }
+ } else
+ ro = state.ro;
+ dst = (struct sockaddr_in *)state.dst;
+ if (error) {
+ /* mbuf is already reclaimed in ipsec4_output. */
+ m0 = NULL;
+ switch (error) {
+ case EHOSTUNREACH:
+ case ENETUNREACH:
+ case EMSGSIZE:
+ case ENOBUFS:
+ case ENOMEM:
+ break;
+ default:
+ printf("ip4_output (ipsec): error code %d\n", error);
+ /*fall through*/
+ case ENOENT:
+ /* don't show these error codes to the user */
+ error = 0;
+ break;
+ }
+ goto bad;
+ }
+ }
+
+ /* be sure to update variables that are affected by ipsec4_output() */
+ ip = mtod(m, struct ip *);
+#ifdef _IP_VHL
+ hlen = IP_VHL_HL(ip->ip_vhl) << 2;
+#else
+ hlen = ip->ip_hl << 2;
+#endif
+ if (ro->ro_rt == NULL) {
+ if ((flags & IP_ROUTETOIF) == 0) {
+ printf("ip_output: "
+ "can't update route after IPsec processing\n");
+ error = EHOSTUNREACH; /*XXX*/
+ goto bad;
+ }
+ } else {
+ ia = ifatoia(ro->ro_rt->rt_ifa);
+ ifp = ro->ro_rt->rt_ifp;
+ }
+
+ /* make it flipped, again. */
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
+skip_ipsec:
+#endif /*IPSEC*/
+
/*
* IpHack's section.
* - Xlate: translate packet's addr/port (NAT).
@@ -661,134 +789,6 @@ sendit:
}
pass:
-#ifdef IPSEC
- /* get SP for this packet */
- if (so == NULL)
- sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error);
- else
- sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error);
-
- if (sp == NULL) {
- ipsecstat.out_inval++;
- goto bad;
- }
-
- error = 0;
-
- /* check policy */
- switch (sp->policy) {
- case IPSEC_POLICY_DISCARD:
- /*
- * This packet is just discarded.
- */
- ipsecstat.out_polvio++;
- goto bad;
-
- case IPSEC_POLICY_BYPASS:
- case IPSEC_POLICY_NONE:
- /* no need to do IPsec. */
- goto skip_ipsec;
-
- case IPSEC_POLICY_IPSEC:
- if (sp->req == NULL) {
- /* XXX should be panic ? */
- printf("ip_output: No IPsec request specified.\n");
- error = EINVAL;
- goto bad;
- }
- break;
-
- case IPSEC_POLICY_ENTRUST:
- default:
- printf("ip_output: Invalid policy found. %d\n", sp->policy);
- }
- {
- struct ipsec_output_state state;
- bzero(&state, sizeof(state));
- state.m = m;
- if (flags & IP_ROUTETOIF) {
- state.ro = &iproute;
- bzero(&iproute, sizeof(iproute));
- } else
- state.ro = ro;
- state.dst = (struct sockaddr *)dst;
-
- ip->ip_sum = 0;
-
- /*
- * XXX
- * delayed checksums are not currently compatible with IPsec
- */
- if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
- in_delayed_cksum(m);
- m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
- }
-
- HTONS(ip->ip_len);
- HTONS(ip->ip_off);
-
- error = ipsec4_output(&state, sp, flags);
-
- m = state.m;
- if (flags & IP_ROUTETOIF) {
- /*
- * if we have tunnel mode SA, we may need to ignore
- * IP_ROUTETOIF.
- */
- if (state.ro != &iproute || state.ro->ro_rt != NULL) {
- flags &= ~IP_ROUTETOIF;
- ro = state.ro;
- }
- } else
- ro = state.ro;
- dst = (struct sockaddr_in *)state.dst;
- if (error) {
- /* mbuf is already reclaimed in ipsec4_output. */
- m0 = NULL;
- switch (error) {
- case EHOSTUNREACH:
- case ENETUNREACH:
- case EMSGSIZE:
- case ENOBUFS:
- case ENOMEM:
- break;
- default:
- printf("ip4_output (ipsec): error code %d\n", error);
- /*fall through*/
- case ENOENT:
- /* don't show these error codes to the user */
- error = 0;
- break;
- }
- goto bad;
- }
- }
-
- /* be sure to update variables that are affected by ipsec4_output() */
- ip = mtod(m, struct ip *);
-#ifdef _IP_VHL
- hlen = IP_VHL_HL(ip->ip_vhl) << 2;
-#else
- hlen = ip->ip_hl << 2;
-#endif
- if (ro->ro_rt == NULL) {
- if ((flags & IP_ROUTETOIF) == 0) {
- printf("ip_output: "
- "can't update route after IPsec processing\n");
- error = EHOSTUNREACH; /*XXX*/
- goto bad;
- }
- } else {
- ia = ifatoia(ro->ro_rt->rt_ifa);
- ifp = ro->ro_rt->rt_ifp;
- }
-
- /* make it flipped, again. */
- NTOHS(ip->ip_len);
- NTOHS(ip->ip_off);
-skip_ipsec:
-#endif /*IPSEC*/
-
m->m_pkthdr.csum_flags |= CSUM_IP;
sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_hwassist;
if (sw_csum & CSUM_DELAY_DATA) {
@@ -820,6 +820,11 @@ skip_ipsec:
ia->ia_ifa.if_obytes += m->m_pkthdr.len;
}
+#ifdef IPSEC
+ /* clean ipsec history once it goes out of the node */
+ ipsec_delaux(m);
+#endif
+
error = (*ifp->if_output)(ifp, m,
(struct sockaddr *)dst, ro->ro_rt);
goto done;
@@ -946,6 +951,10 @@ sendorfree:
for (m = m0; m; m = m0) {
m0 = m->m_nextpkt;
m->m_nextpkt = 0;
+#ifdef IPSEC
+ /* clean ipsec history once it goes out of the node */
+ ipsec_delaux(m);
+#endif
if (error == 0) {
/* Record statistics for this interface address. */
ia->ia_ifa.if_opackets++;
@@ -1480,6 +1489,33 @@ bad:
* transmission, and one (IP_MULTICAST_TTL) totally duplicates a
* standard option (IP_TTL).
*/
+
+/*
+ * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index.
+ */
+static struct ifnet *
+ip_multicast_if(a, ifindexp)
+ struct in_addr *a;
+ int *ifindexp;
+{
+ int ifindex;
+ struct ifnet *ifp;
+
+ if (ifindexp)
+ *ifindexp = 0;
+ if (ntohl(a->s_addr) >> 24 == 0) {
+ ifindex = ntohl(a->s_addr) & 0xffffff;
+ if (ifindex < 0 || if_index < ifindex)
+ return NULL;
+ ifp = ifindex2ifnet[ifindex];
+ if (ifindexp)
+ *ifindexp = ifindex;
+ } else {
+ INADDR_TO_IFP(*a, ifp);
+ }
+ return ifp;
+}
+
/*
* Set the IP multicast options in response to user setsockopt().
*/
@@ -1496,6 +1532,7 @@ ip_setmoptions(sopt, imop)
struct ip_moptions *imo = *imop;
struct route ro;
struct sockaddr_in *dst;
+ int ifindex;
int s;
if (imo == NULL) {
@@ -1510,6 +1547,7 @@ ip_setmoptions(sopt, imop)
return (ENOBUFS);
*imop = imo;
imo->imo_multicast_ifp = NULL;
+ imo->imo_multicast_addr.s_addr = INADDR_ANY;
imo->imo_multicast_vif = -1;
imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
@@ -1555,13 +1593,17 @@ ip_setmoptions(sopt, imop)
* it supports multicasting.
*/
s = splimp();
- INADDR_TO_IFP(addr, ifp);
+ ifp = ip_multicast_if(&addr, &ifindex);
if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
splx(s);
error = EADDRNOTAVAIL;
break;
}
imo->imo_multicast_ifp = ifp;
+ if (ifindex)
+ imo->imo_multicast_addr = addr;
+ else
+ imo->imo_multicast_addr.s_addr = INADDR_ANY;
splx(s);
break;
@@ -1648,7 +1690,7 @@ ip_setmoptions(sopt, imop)
rtfree(ro.ro_rt);
}
else {
- INADDR_TO_IFP(mreq.imr_interface, ifp);
+ ifp = ip_multicast_if(&mreq.imr_interface, NULL);
}
/*
@@ -1716,7 +1758,7 @@ ip_setmoptions(sopt, imop)
if (mreq.imr_interface.s_addr == INADDR_ANY)
ifp = NULL;
else {
- INADDR_TO_IFP(mreq.imr_interface, ifp);
+ ifp = ip_multicast_if(&mreq.imr_interface, NULL);
if (ifp == NULL) {
error = EADDRNOTAVAIL;
splx(s);
@@ -1798,7 +1840,10 @@ ip_getmoptions(sopt, imo)
case IP_MULTICAST_IF:
if (imo == NULL || imo->imo_multicast_ifp == NULL)
addr.s_addr = INADDR_ANY;
- else {
+ else if (imo->imo_multicast_addr.s_addr) {
+ /* return the value user has set */
+ addr = imo->imo_multicast_addr;
+ } else {
IFP_TO_IA(imo->imo_multicast_ifp, ia);
addr.s_addr = (ia == NULL) ? INADDR_ANY
: IA_SIN(ia)->sin_addr.s_addr;
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index 6354d84..b318a1c 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -37,6 +37,8 @@
#ifndef _NETINET_IP_VAR_H_
#define _NETINET_IP_VAR_H_
+#include <sys/queue.h>
+
/*
* Overlay for ip header used by other protocols (tcp, udp).
*/
@@ -86,6 +88,7 @@ struct ipoption {
*/
struct ip_moptions {
struct ifnet *imo_multicast_ifp; /* ifp for outgoing multicasts */
+ struct in_addr imo_multicast_addr; /* ifindex/addr on MULTICAST_IF */
u_char imo_multicast_ttl; /* TTL for outgoing multicasts */
u_char imo_multicast_loop; /* 1 => hear sends if a member */
u_short imo_num_memberships; /* no. memberships this socket */
@@ -122,6 +125,7 @@ struct ipstat {
u_long ips_toolong; /* ip length > max ip packet size */
u_long ips_notmember; /* multicasts for unregistered grps */
u_long ips_nogif; /* no match gif found */
+ u_long ips_badaddr; /* invalid address on header */
};
#ifdef _KERNEL
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index 4fdcf95..32c909a 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -137,6 +137,15 @@ rip_input(m, off, proto)
continue;
if (last) {
struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
+
+#ifdef IPSEC
+ /* check AH/ESP integrity. */
+ if (n && ipsec4_in_reject_so(n, last->inp_socket)) {
+ m_freem(n);
+ ipsecstat.in_polvio++;
+ /* do not inject data to pcb */
+ } else
+#endif /*IPSEC*/
if (n) {
if (last->inp_flags & INP_CONTROLOPTS ||
last->inp_socket->so_options & SO_TIMESTAMP)
@@ -155,6 +164,15 @@ rip_input(m, off, proto)
}
last = inp;
}
+#ifdef IPSEC
+ /* check AH/ESP integrity. */
+ if (last && ipsec4_in_reject_so(m, last->inp_socket)) {
+ m_freem(m);
+ ipsecstat.in_polvio++;
+ ipstat.ips_delivered--;
+ /* do not inject data to pcb */
+ } else
+#endif /*IPSEC*/
if (last) {
if (last->inp_flags & INP_CONTROLOPTS ||
last->inp_socket->so_options & SO_TIMESTAMP)
@@ -168,9 +186,9 @@ rip_input(m, off, proto)
sorwakeup(last->inp_socket);
} else {
m_freem(m);
- ipstat.ips_noproto++;
- ipstat.ips_delivered--;
- }
+ ipstat.ips_noproto++;
+ ipstat.ips_delivered--;
+ }
}
/*
@@ -232,7 +250,10 @@ rip_output(m, so, dst)
}
#ifdef IPSEC
- ipsec_setsocket(m, so);
+ if (ipsec_setsocket(m, so) != 0) {
+ m_freem(m);
+ return ENOBUFS;
+ }
#endif /*IPSEC*/
return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 34c2006..3554dae 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -305,6 +305,7 @@ tcp6_input(mp, offp, proto)
int *offp, proto;
{
register struct mbuf *m = *mp;
+ struct in6_ifaddr *ia6;
IP6_EXTHDR_CHECK(m, *offp, sizeof(struct tcphdr), IPPROTO_DONE);
@@ -312,7 +313,8 @@ tcp6_input(mp, offp, proto)
* draft-itojun-ipv6-tcp-to-anycast
* better place to put this in?
*/
- if (m->m_flags & M_ANYCAST6) {
+ ia6 = ip6_getdstifaddr(m);
+ if (ia6 && (ia6->ia6_flags & IN6_IFF_ANYCAST)) {
struct ip6_hdr *ip6;
ip6 = mtod(m, struct ip6_hdr *);
@@ -379,6 +381,19 @@ tcp_input(m, off0, proto)
goto drop;
}
th = (struct tcphdr *)((caddr_t)ip6 + off0);
+
+ /*
+ * Be proactive about unspecified IPv6 address in source.
+ * As we use all-zero to indicate unbounded/unconnected pcb,
+ * unspecified IPv6 address can be used to confuse us.
+ *
+ * Note that packets with unspecified IPv6 destination is
+ * already dropped in ip6_input.
+ */
+ if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
+ /* XXX stat */
+ goto drop;
+ }
} else
#endif /* INET6 */
{
@@ -627,18 +642,6 @@ findpcb:
else
tiwin = th->th_win;
-#ifdef INET6
- /* save packet options if user wanted */
- if (isipv6 && inp->in6p_flags & INP_CONTROLOPTS) {
- if (inp->in6p_options) {
- m_freem(inp->in6p_options);
- inp->in6p_options = 0;
- }
- ip6_savecontrol(inp, &inp->in6p_options, ip6, m);
- }
- /* else, should also do ip_srcroute() here? */
-#endif /* INET6 */
-
so = inp->inp_socket;
if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) {
#ifdef TCPDEBUG
@@ -683,6 +686,50 @@ findpcb:
goto drop;
}
#endif
+
+#ifdef INET6
+ /*
+ * If deprecated address is forbidden,
+ * we do not accept SYN to deprecated interface
+ * address to prevent any new inbound connection from
+ * getting established.
+ * When we do not accept SYN, we send a TCP RST,
+ * with deprecated source address (instead of dropping
+ * it). We compromise it as it is much better for peer
+ * to send a RST, and RST will be the final packet
+ * for the exchange.
+ *
+ * If we do not forbid deprecated addresses, we accept
+ * the SYN packet. RFC2462 does not suggest dropping
+ * SYN in this case.
+ * If we decipher RFC2462 5.5.4, it says like this:
+ * 1. use of deprecated addr with existing
+ * communication is okay - "SHOULD continue to be
+ * used"
+ * 2. use of it with new communication:
+ * (2a) "SHOULD NOT be used if alternate address
+ * with sufficient scope is available"
+ * (2b) nothing mentioned otherwise.
+ * Here we fall into (2b) case as we have no choice in
+ * our source address selection - we must obey the peer.
+ *
+ * The wording in RFC2462 is confusing, and there are
+ * multiple description text for deprecated address
+ * handling - worse, they are not exactly the same.
+ * I believe 5.5.4 is the best one, so we follow 5.5.4.
+ */
+ if (isipv6 && !ip6_use_deprecated) {
+ struct in6_ifaddr *ia6;
+
+ if ((ia6 = ip6_getdstifaddr(m)) &&
+ (ia6->ia6_flags & IN6_IFF_DEPRECATED)) {
+ tp = NULL;
+ rstreason = BANDLIM_RST_OPENPORT;
+ goto dropwithreset;
+ }
+ }
+#endif
+
so2 = sonewconn(so, 0);
if (so2 == 0) {
/*
@@ -731,10 +778,8 @@ findpcb:
if (isipv6)
inp->in6p_laddr = ip6->ip6_dst;
else {
- if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) {
- inp->inp_vflag &= ~INP_IPV6;
- inp->inp_vflag |= INP_IPV4;
- }
+ inp->inp_vflag &= ~INP_IPV6;
+ inp->inp_vflag |= INP_IPV4;
#endif /* INET6 */
inp->inp_laddr = ip->ip_dst;
#ifdef INET6
@@ -779,21 +824,25 @@ findpcb:
#endif
#ifdef INET6
if (isipv6) {
- /*
- * inherit socket options from the listening
- * socket.
- */
+ /*
+ * Inherit socket options from the listening
+ * socket.
+ * Note that in6p_inputopts are not (even
+ * should not be) copied, since it stores
+ * previously received options and is used to
+ * detect if each new option is different than
+ * the previous one and hence should be passed
+ * to a user.
+ * If we copied in6p_inputopts, a user would
+ * not be able to receive options just after
+ * calling the accept system call.
+ */
inp->inp_flags |=
oinp->inp_flags & INP_CONTROLOPTS;
- if (inp->inp_flags & INP_CONTROLOPTS) {
- if (inp->in6p_options) {
- m_freem(inp->in6p_options);
- inp->in6p_options = 0;
- }
- ip6_savecontrol(inp,
- &inp->in6p_options,
- ip6, m);
- }
+ if (oinp->in6p_outputopts)
+ inp->in6p_outputopts =
+ ip6_copypktopts(oinp->in6p_outputopts,
+ M_NOWAIT);
} else
#endif /* INET6 */
inp->inp_options = ip_srcroute();
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 286b420..a2a2cf3 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -376,7 +376,7 @@ send:
* NOTE: we assume that the IP/TCP header plus TCP options
* always fit in a single mbuf, leaving room for a maximum
* link header, i.e.
- * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN
+ * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MCLBYTES
*/
optlen = 0;
#ifdef INET6
@@ -823,7 +823,11 @@ send:
/* TODO: IPv6 IP6TOS_ECT bit on */
#ifdef IPSEC
- ipsec_setsocket(m, so);
+ if (ipsec_setsocket(m, so) != 0) {
+ m_freem(m);
+ error = ENOBUFS;
+ goto out;
+ }
#endif /*IPSEC*/
error = ip6_output(m,
tp->t_inpcb->in6p_outputopts,
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index 34c2006..3554dae 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -305,6 +305,7 @@ tcp6_input(mp, offp, proto)
int *offp, proto;
{
register struct mbuf *m = *mp;
+ struct in6_ifaddr *ia6;
IP6_EXTHDR_CHECK(m, *offp, sizeof(struct tcphdr), IPPROTO_DONE);
@@ -312,7 +313,8 @@ tcp6_input(mp, offp, proto)
* draft-itojun-ipv6-tcp-to-anycast
* better place to put this in?
*/
- if (m->m_flags & M_ANYCAST6) {
+ ia6 = ip6_getdstifaddr(m);
+ if (ia6 && (ia6->ia6_flags & IN6_IFF_ANYCAST)) {
struct ip6_hdr *ip6;
ip6 = mtod(m, struct ip6_hdr *);
@@ -379,6 +381,19 @@ tcp_input(m, off0, proto)
goto drop;
}
th = (struct tcphdr *)((caddr_t)ip6 + off0);
+
+ /*
+ * Be proactive about unspecified IPv6 address in source.
+ * As we use all-zero to indicate unbounded/unconnected pcb,
+ * unspecified IPv6 address can be used to confuse us.
+ *
+ * Note that packets with unspecified IPv6 destination is
+ * already dropped in ip6_input.
+ */
+ if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
+ /* XXX stat */
+ goto drop;
+ }
} else
#endif /* INET6 */
{
@@ -627,18 +642,6 @@ findpcb:
else
tiwin = th->th_win;
-#ifdef INET6
- /* save packet options if user wanted */
- if (isipv6 && inp->in6p_flags & INP_CONTROLOPTS) {
- if (inp->in6p_options) {
- m_freem(inp->in6p_options);
- inp->in6p_options = 0;
- }
- ip6_savecontrol(inp, &inp->in6p_options, ip6, m);
- }
- /* else, should also do ip_srcroute() here? */
-#endif /* INET6 */
-
so = inp->inp_socket;
if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) {
#ifdef TCPDEBUG
@@ -683,6 +686,50 @@ findpcb:
goto drop;
}
#endif
+
+#ifdef INET6
+ /*
+ * If deprecated address is forbidden,
+ * we do not accept SYN to deprecated interface
+ * address to prevent any new inbound connection from
+ * getting established.
+ * When we do not accept SYN, we send a TCP RST,
+ * with deprecated source address (instead of dropping
+ * it). We compromise it as it is much better for peer
+ * to send a RST, and RST will be the final packet
+ * for the exchange.
+ *
+ * If we do not forbid deprecated addresses, we accept
+ * the SYN packet. RFC2462 does not suggest dropping
+ * SYN in this case.
+ * If we decipher RFC2462 5.5.4, it says like this:
+ * 1. use of deprecated addr with existing
+ * communication is okay - "SHOULD continue to be
+ * used"
+ * 2. use of it with new communication:
+ * (2a) "SHOULD NOT be used if alternate address
+ * with sufficient scope is available"
+ * (2b) nothing mentioned otherwise.
+ * Here we fall into (2b) case as we have no choice in
+ * our source address selection - we must obey the peer.
+ *
+ * The wording in RFC2462 is confusing, and there are
+ * multiple description text for deprecated address
+ * handling - worse, they are not exactly the same.
+ * I believe 5.5.4 is the best one, so we follow 5.5.4.
+ */
+ if (isipv6 && !ip6_use_deprecated) {
+ struct in6_ifaddr *ia6;
+
+ if ((ia6 = ip6_getdstifaddr(m)) &&
+ (ia6->ia6_flags & IN6_IFF_DEPRECATED)) {
+ tp = NULL;
+ rstreason = BANDLIM_RST_OPENPORT;
+ goto dropwithreset;
+ }
+ }
+#endif
+
so2 = sonewconn(so, 0);
if (so2 == 0) {
/*
@@ -731,10 +778,8 @@ findpcb:
if (isipv6)
inp->in6p_laddr = ip6->ip6_dst;
else {
- if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) {
- inp->inp_vflag &= ~INP_IPV6;
- inp->inp_vflag |= INP_IPV4;
- }
+ inp->inp_vflag &= ~INP_IPV6;
+ inp->inp_vflag |= INP_IPV4;
#endif /* INET6 */
inp->inp_laddr = ip->ip_dst;
#ifdef INET6
@@ -779,21 +824,25 @@ findpcb:
#endif
#ifdef INET6
if (isipv6) {
- /*
- * inherit socket options from the listening
- * socket.
- */
+ /*
+ * Inherit socket options from the listening
+ * socket.
+ * Note that in6p_inputopts are not (even
+ * should not be) copied, since it stores
+ * previously received options and is used to
+ * detect if each new option is different than
+ * the previous one and hence should be passed
+ * to a user.
+ * If we copied in6p_inputopts, a user would
+ * not be able to receive options just after
+ * calling the accept system call.
+ */
inp->inp_flags |=
oinp->inp_flags & INP_CONTROLOPTS;
- if (inp->inp_flags & INP_CONTROLOPTS) {
- if (inp->in6p_options) {
- m_freem(inp->in6p_options);
- inp->in6p_options = 0;
- }
- ip6_savecontrol(inp,
- &inp->in6p_options,
- ip6, m);
- }
+ if (oinp->in6p_outputopts)
+ inp->in6p_outputopts =
+ ip6_copypktopts(oinp->in6p_outputopts,
+ M_NOWAIT);
} else
#endif /* INET6 */
inp->inp_options = ip_srcroute();
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 3857b75..06849be 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -443,7 +443,10 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags)
tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0);
#endif
#ifdef IPSEC
- ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL);
+ if (ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL) != 0) {
+ m_freem(m);
+ return;
+ }
#endif
#ifdef INET6
if (isipv6) {
@@ -1020,13 +1023,17 @@ tcp6_ctlinput(cmd, sa, d)
struct sockaddr *sa;
void *d;
{
- register struct tcphdr *thp;
struct tcphdr th;
void (*notify) __P((struct inpcb *, int)) = tcp_notify;
- struct sockaddr_in6 sa6;
struct ip6_hdr *ip6;
struct mbuf *m;
+ struct ip6ctlparam *ip6cp = NULL;
+ const struct sockaddr_in6 *sa6_src = NULL;
int off;
+ struct tcp_portonly {
+ u_int16_t th_sport;
+ u_int16_t th_dport;
+ } *thp;
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
@@ -1042,56 +1049,36 @@ tcp6_ctlinput(cmd, sa, d)
/* if the parameter is from icmp6, decode it. */
if (d != NULL) {
- struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
+ ip6cp = (struct ip6ctlparam *)d;
m = ip6cp->ip6c_m;
ip6 = ip6cp->ip6c_ip6;
off = ip6cp->ip6c_off;
+ sa6_src = ip6cp->ip6c_src;
} else {
m = NULL;
ip6 = NULL;
off = 0; /* fool gcc */
+ sa6_src = &sa6_any;
}
- /*
- * Translate addresses into internal form.
- * Sa check if it is AF_INET6 is done at the top of this funciton.
- */
- sa6 = *(struct sockaddr_in6 *)sa;
- if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) != 0 && m != NULL &&
- m->m_pkthdr.rcvif != NULL)
- sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
-
if (ip6) {
/*
* XXX: We assume that when IPV6 is non NULL,
* M and OFF are valid.
*/
- struct in6_addr s;
-
- /* translate addresses into internal form */
- memcpy(&s, &ip6->ip6_src, sizeof(s));
- if (IN6_IS_ADDR_LINKLOCAL(&s) != 0 && m != NULL &&
- m->m_pkthdr.rcvif != NULL)
- s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
/* check if we can safely examine src and dst ports */
- if (m->m_pkthdr.len < off + sizeof(th))
+ if (m->m_pkthdr.len < off + sizeof(*thp))
return;
- if (m->m_len < off + sizeof(th)) {
- /*
- * this should be rare case
- * because now MINCLSIZE is "(MHLEN + 1)",
- * so we compromise on this copy...
- */
- m_copydata(m, off, sizeof(th), (caddr_t)&th);
- thp = &th;
- } else
- thp = (struct tcphdr *)(mtod(m, caddr_t) + off);
- in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, thp->th_dport,
- &s, thp->th_sport, cmd, notify);
+ bzero(&th, sizeof(th));
+ m_copydata(m, off, sizeof(*thp), (caddr_t)&th);
+
+ in6_pcbnotify(&tcb, sa, th.th_dport,
+ (struct sockaddr *)ip6cp->ip6c_src,
+ th.th_sport, cmd, notify);
} else
- in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, 0, &zeroin6_addr,
+ in6_pcbnotify(&tcb, sa, 0, (struct sockaddr *)sa6_src,
0, cmd, notify);
}
#endif /* INET6 */
@@ -1323,9 +1310,12 @@ tcp_rtlookup6(inp)
if (rt == NULL || !(rt->rt_flags & RTF_UP)) {
/* No route yet, so try to acquire one */
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
- ro6->ro_dst.sin6_family = AF_INET6;
- ro6->ro_dst.sin6_len = sizeof(ro6->ro_dst);
- ro6->ro_dst.sin6_addr = inp->in6p_faddr;
+ struct sockaddr_in6 *dst6;
+
+ dst6 = (struct sockaddr_in6 *)&ro6->ro_dst;
+ dst6->sin6_family = AF_INET6;
+ dst6->sin6_len = sizeof(ro6->ro_dst);
+ dst6->sin6_addr = inp->in6p_faddr;
rtalloc((struct route *)ro6);
rt = ro6->ro_rt;
}
@@ -1376,6 +1366,7 @@ ipsec_hdrsiz_tcp(tp)
sizeof(struct ip));
bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th,
sizeof(struct tcphdr));
+ ip->ip_vhl = IP_VHL_BORING;
hdrsiz = ipsec4_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp);
}
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index 3857b75..06849be 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -443,7 +443,10 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags)
tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0);
#endif
#ifdef IPSEC
- ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL);
+ if (ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL) != 0) {
+ m_freem(m);
+ return;
+ }
#endif
#ifdef INET6
if (isipv6) {
@@ -1020,13 +1023,17 @@ tcp6_ctlinput(cmd, sa, d)
struct sockaddr *sa;
void *d;
{
- register struct tcphdr *thp;
struct tcphdr th;
void (*notify) __P((struct inpcb *, int)) = tcp_notify;
- struct sockaddr_in6 sa6;
struct ip6_hdr *ip6;
struct mbuf *m;
+ struct ip6ctlparam *ip6cp = NULL;
+ const struct sockaddr_in6 *sa6_src = NULL;
int off;
+ struct tcp_portonly {
+ u_int16_t th_sport;
+ u_int16_t th_dport;
+ } *thp;
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
@@ -1042,56 +1049,36 @@ tcp6_ctlinput(cmd, sa, d)
/* if the parameter is from icmp6, decode it. */
if (d != NULL) {
- struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
+ ip6cp = (struct ip6ctlparam *)d;
m = ip6cp->ip6c_m;
ip6 = ip6cp->ip6c_ip6;
off = ip6cp->ip6c_off;
+ sa6_src = ip6cp->ip6c_src;
} else {
m = NULL;
ip6 = NULL;
off = 0; /* fool gcc */
+ sa6_src = &sa6_any;
}
- /*
- * Translate addresses into internal form.
- * Sa check if it is AF_INET6 is done at the top of this funciton.
- */
- sa6 = *(struct sockaddr_in6 *)sa;
- if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) != 0 && m != NULL &&
- m->m_pkthdr.rcvif != NULL)
- sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
-
if (ip6) {
/*
* XXX: We assume that when IPV6 is non NULL,
* M and OFF are valid.
*/
- struct in6_addr s;
-
- /* translate addresses into internal form */
- memcpy(&s, &ip6->ip6_src, sizeof(s));
- if (IN6_IS_ADDR_LINKLOCAL(&s) != 0 && m != NULL &&
- m->m_pkthdr.rcvif != NULL)
- s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
/* check if we can safely examine src and dst ports */
- if (m->m_pkthdr.len < off + sizeof(th))
+ if (m->m_pkthdr.len < off + sizeof(*thp))
return;
- if (m->m_len < off + sizeof(th)) {
- /*
- * this should be rare case
- * because now MINCLSIZE is "(MHLEN + 1)",
- * so we compromise on this copy...
- */
- m_copydata(m, off, sizeof(th), (caddr_t)&th);
- thp = &th;
- } else
- thp = (struct tcphdr *)(mtod(m, caddr_t) + off);
- in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, thp->th_dport,
- &s, thp->th_sport, cmd, notify);
+ bzero(&th, sizeof(th));
+ m_copydata(m, off, sizeof(*thp), (caddr_t)&th);
+
+ in6_pcbnotify(&tcb, sa, th.th_dport,
+ (struct sockaddr *)ip6cp->ip6c_src,
+ th.th_sport, cmd, notify);
} else
- in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, 0, &zeroin6_addr,
+ in6_pcbnotify(&tcb, sa, 0, (struct sockaddr *)sa6_src,
0, cmd, notify);
}
#endif /* INET6 */
@@ -1323,9 +1310,12 @@ tcp_rtlookup6(inp)
if (rt == NULL || !(rt->rt_flags & RTF_UP)) {
/* No route yet, so try to acquire one */
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
- ro6->ro_dst.sin6_family = AF_INET6;
- ro6->ro_dst.sin6_len = sizeof(ro6->ro_dst);
- ro6->ro_dst.sin6_addr = inp->in6p_faddr;
+ struct sockaddr_in6 *dst6;
+
+ dst6 = (struct sockaddr_in6 *)&ro6->ro_dst;
+ dst6->sin6_family = AF_INET6;
+ dst6->sin6_len = sizeof(ro6->ro_dst);
+ dst6->sin6_addr = inp->in6p_faddr;
rtalloc((struct route *)ro6);
rt = ro6->ro_rt;
}
@@ -1376,6 +1366,7 @@ ipsec_hdrsiz_tcp(tp)
sizeof(struct ip));
bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th,
sizeof(struct tcphdr));
+ ip->ip_vhl = IP_VHL_BORING;
hdrsiz = ipsec4_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp);
}
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 25834d4..aea92c0 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -240,8 +240,7 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
}
inp->inp_vflag &= ~INP_IPV4;
inp->inp_vflag |= INP_IPV6;
- if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) {
-
+ if (ip6_mapped_addr_on && (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr))
inp->inp_vflag |= INP_IPV4;
else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
@@ -292,7 +291,8 @@ tcp6_usr_listen(struct socket *so, struct proc *p)
COMMON_START();
if (inp->inp_lport == 0) {
inp->inp_vflag &= ~INP_IPV4;
- if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0)
+ if (ip6_mapped_addr_on &&
+ (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
inp->inp_vflag |= INP_IPV4;
error = in6_pcbbind(inp, (struct sockaddr *)0, p);
}
@@ -361,10 +361,13 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
goto out;
}
- if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0 &&
- IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
+ if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
struct sockaddr_in sin;
+ if (!ip6_mapped_addr_on ||
+ (inp->inp_flags & IN6P_IPV6_V6ONLY))
+ return(EINVAL);
+
in6_sin6_2_sin(&sin, sin6p);
inp->inp_vflag |= INP_IPV4;
inp->inp_vflag &= ~INP_IPV6;
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 350a384..d546b1f 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -392,8 +392,7 @@ udp_input(m, off, proto)
#endif
ip_savecontrol(inp, &opts, ip, m);
}
- iphlen += sizeof(struct udphdr);
- m_adj(m, iphlen);
+ m_adj(m, iphlen + sizeof(struct udphdr));
#ifdef INET6
if (inp->inp_vflag & INP_IPV6) {
in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin);
@@ -744,7 +743,10 @@ udp_output(inp, m, addr, control, p)
udpstat.udps_opackets++;
#ifdef IPSEC
- ipsec_setsocket(m, inp->inp_socket);
+ if (ipsec_setsocket(m, inp->inp_socket) != 0) {
+ error = ENOBUFS;
+ goto release;
+ }
#endif /*IPSEC*/
error = ip_output(m, inp->inp_options, &inp->inp_route,
(inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)),
diff --git a/sys/netinet6/ah.h b/sys/netinet6/ah.h
index 3c7d0a6..0846466 100644
--- a/sys/netinet6/ah.h
+++ b/sys/netinet6/ah.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ah.h,v 1.10 2000/07/02 13:23:33 itojun Exp $ */
+/* $KAME: ah.h,v 1.13 2000/10/18 21:28:00 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -37,7 +37,9 @@
#ifndef _NETINET6_AH_H_
#define _NETINET6_AH_H_
-struct secasvar;
+#if defined(_KERNEL) && !defined(_LKM)
+#include "opt_inet.h"
+#endif
struct ah {
u_int8_t ah_nxt; /* Next Header */
@@ -56,6 +58,9 @@ struct newah {
/* variable size, 32bit bound*/ /* Authentication data */
};
+#ifdef _KERNEL
+struct secasvar;
+
struct ah_algorithm_state {
struct secasvar *sav;
void* foo; /*per algorithm data - maybe*/
@@ -74,8 +79,7 @@ struct ah_algorithm {
#define AH_MAXSUMSIZE 16
-#ifdef _KERNEL
-extern struct ah_algorithm ah_algorithms[];
+extern const struct ah_algorithm *ah_algorithm_lookup __P((int));
/* cksum routines */
extern int ah_hdrlen __P((struct secasvar *));
@@ -84,7 +88,7 @@ extern size_t ah_hdrsiz __P((struct ipsecrequest *));
extern void ah4_input __P((struct mbuf *, ...));
extern int ah4_output __P((struct mbuf *, struct ipsecrequest *));
extern int ah4_calccksum __P((struct mbuf *, caddr_t, size_t,
- struct ah_algorithm *, struct secasvar *));
+ const struct ah_algorithm *, struct secasvar *));
#endif /*_KERNEL*/
#endif /*_NETINET6_AH_H_*/
diff --git a/sys/netinet6/ah6.h b/sys/netinet6/ah6.h
index 4010f13..ead07bf 100644
--- a/sys/netinet6/ah6.h
+++ b/sys/netinet6/ah6.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ah.h,v 1.10 2000/07/02 13:23:33 itojun Exp $ */
+/* $KAME: ah.h,v 1.13 2000/10/18 21:28:00 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -44,7 +44,9 @@ extern int ah6_input __P((struct mbuf **, int *, int));
extern int ah6_output __P((struct mbuf *, u_char *, struct mbuf *,
struct ipsecrequest *));
extern int ah6_calccksum __P((struct mbuf *, caddr_t, size_t,
- struct ah_algorithm *, struct secasvar *));
+ const struct ah_algorithm *, struct secasvar *));
+
+extern void ah6_ctlinput __P((int, struct sockaddr *, void *));
#endif
#endif /*_NETINET6_AH6_H_*/
diff --git a/sys/netinet6/ah_core.c b/sys/netinet6/ah_core.c
index 477de51..5c7afaf 100644
--- a/sys/netinet6/ah_core.c
+++ b/sys/netinet6/ah_core.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ah_core.c,v 1.35 2000/06/14 11:14:03 itojun Exp $ */
+/* $KAME: ah_core.c,v 1.44 2001/03/12 11:24:39 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -34,6 +34,8 @@
* RFC1826/2402 authentication header.
*/
+/* TODO: have shared routines for hmac-* algorithms */
+
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
@@ -82,6 +84,7 @@
#include <netkey/keydb.h>
#include <sys/md5.h>
#include <crypto/sha1.h>
+#include <crypto/sha2/sha2.h>
#include <net/net_osdep.h>
@@ -90,8 +93,7 @@
static int ah_sumsiz_1216 __P((struct secasvar *));
static int ah_sumsiz_zero __P((struct secasvar *));
static int ah_none_mature __P((struct secasvar *));
-static int ah_none_init __P((struct ah_algorithm_state *,
- struct secasvar *));
+static int ah_none_init __P((struct ah_algorithm_state *, struct secasvar *));
static void ah_none_loop __P((struct ah_algorithm_state *, caddr_t, size_t));
static void ah_none_result __P((struct ah_algorithm_state *, caddr_t));
static int ah_keyed_md5_mature __P((struct secasvar *));
@@ -118,25 +120,84 @@ static int ah_hmac_sha1_init __P((struct ah_algorithm_state *,
static void ah_hmac_sha1_loop __P((struct ah_algorithm_state *, caddr_t,
size_t));
static void ah_hmac_sha1_result __P((struct ah_algorithm_state *, caddr_t));
+static int ah_hmac_sha2_256_mature __P((struct secasvar *));
+static int ah_hmac_sha2_256_init __P((struct ah_algorithm_state *,
+ struct secasvar *));
+static void ah_hmac_sha2_256_loop __P((struct ah_algorithm_state *, caddr_t,
+ size_t));
+static void ah_hmac_sha2_256_result __P((struct ah_algorithm_state *, caddr_t));
+static int ah_hmac_sha2_384_mature __P((struct secasvar *));
+static int ah_hmac_sha2_384_init __P((struct ah_algorithm_state *,
+ struct secasvar *));
+static void ah_hmac_sha2_384_loop __P((struct ah_algorithm_state *, caddr_t,
+ size_t));
+static void ah_hmac_sha2_384_result __P((struct ah_algorithm_state *, caddr_t));
+static int ah_hmac_sha2_512_mature __P((struct secasvar *));
+static int ah_hmac_sha2_512_init __P((struct ah_algorithm_state *,
+ struct secasvar *));
+static void ah_hmac_sha2_512_loop __P((struct ah_algorithm_state *, caddr_t,
+ size_t));
+static void ah_hmac_sha2_512_result __P((struct ah_algorithm_state *, caddr_t));
+
+static void ah_update_mbuf __P((struct mbuf *, int, int,
+ const struct ah_algorithm *, struct ah_algorithm_state *));
+
+const struct ah_algorithm *
+ah_algorithm_lookup(idx)
+ int idx;
+{
+ /* checksum algorithms */
+ static struct ah_algorithm ah_algorithms[] = {
+ { ah_sumsiz_1216, ah_hmac_md5_mature, 128, 128, "hmac-md5",
+ ah_hmac_md5_init, ah_hmac_md5_loop,
+ ah_hmac_md5_result, },
+ { ah_sumsiz_1216, ah_hmac_sha1_mature, 160, 160, "hmac-sha1",
+ ah_hmac_sha1_init, ah_hmac_sha1_loop,
+ ah_hmac_sha1_result, },
+ { ah_sumsiz_1216, ah_keyed_md5_mature, 128, 128, "keyed-md5",
+ ah_keyed_md5_init, ah_keyed_md5_loop,
+ ah_keyed_md5_result, },
+ { ah_sumsiz_1216, ah_keyed_sha1_mature, 160, 160, "keyed-sha1",
+ ah_keyed_sha1_init, ah_keyed_sha1_loop,
+ ah_keyed_sha1_result, },
+ { ah_sumsiz_zero, ah_none_mature, 0, 2048, "none",
+ ah_none_init, ah_none_loop, ah_none_result, },
+ { ah_sumsiz_1216, ah_hmac_sha2_256_mature, 256, 256,
+ "hmac-sha2-256",
+ ah_hmac_sha2_256_init, ah_hmac_sha2_256_loop,
+ ah_hmac_sha2_256_result, },
+ { ah_sumsiz_1216, ah_hmac_sha2_384_mature, 384, 384,
+ "hmac-sha2-384",
+ ah_hmac_sha2_384_init, ah_hmac_sha2_384_loop,
+ ah_hmac_sha2_384_result, },
+ { ah_sumsiz_1216, ah_hmac_sha2_512_mature, 512, 512,
+ "hmac-sha2-512",
+ ah_hmac_sha2_512_init, ah_hmac_sha2_512_loop,
+ ah_hmac_sha2_512_result, },
+ };
+
+ switch (idx) {
+ case SADB_AALG_MD5HMAC:
+ return &ah_algorithms[0];
+ case SADB_AALG_SHA1HMAC:
+ return &ah_algorithms[1];
+ case SADB_X_AALG_MD5:
+ return &ah_algorithms[2];
+ case SADB_X_AALG_SHA:
+ return &ah_algorithms[3];
+ case SADB_X_AALG_NULL:
+ return &ah_algorithms[4];
+ case SADB_X_AALG_SHA2_256:
+ return &ah_algorithms[5];
+ case SADB_X_AALG_SHA2_384:
+ return &ah_algorithms[6];
+ case SADB_X_AALG_SHA2_512:
+ return &ah_algorithms[7];
+ default:
+ return NULL;
+ }
+}
-static void ah_update_mbuf __P((struct mbuf *, int, int, struct ah_algorithm *,
- struct ah_algorithm_state *));
-
-/* checksum algorithms */
-/* NOTE: The order depends on SADB_AALG_x in net/pfkeyv2.h */
-struct ah_algorithm ah_algorithms[] = {
- { 0, 0, 0, 0, 0, 0, },
- { ah_sumsiz_1216, ah_hmac_md5_mature, 128, 128, "hmac-md5",
- ah_hmac_md5_init, ah_hmac_md5_loop, ah_hmac_md5_result, },
- { ah_sumsiz_1216, ah_hmac_sha1_mature, 160, 160, "hmac-sha1",
- ah_hmac_sha1_init, ah_hmac_sha1_loop, ah_hmac_sha1_result, },
- { ah_sumsiz_1216, ah_keyed_md5_mature, 128, 128, "keyed-md5",
- ah_keyed_md5_init, ah_keyed_md5_loop, ah_keyed_md5_result, },
- { ah_sumsiz_1216, ah_keyed_sha1_mature, 160, 160, "keyed-sha1",
- ah_keyed_sha1_init, ah_keyed_sha1_loop, ah_keyed_sha1_result, },
- { ah_sumsiz_zero, ah_none_mature, 0, 2048, "none",
- ah_none_init, ah_none_loop, ah_none_result, },
-};
static int
ah_sumsiz_1216(sav)
@@ -297,13 +358,19 @@ static int
ah_keyed_sha1_mature(sav)
struct secasvar *sav;
{
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
if (!sav->key_auth) {
ipseclog((LOG_ERR, "ah_keyed_sha1_mature: no key is given.\n"));
return 1;
}
- algo = &ah_algorithms[sav->alg_auth];
+
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
+ ipseclog((LOG_ERR, "ah_keyed_sha1_mature: unsupported algorithm.\n"));
+ return 1;
+ }
+
if (sav->key_auth->sadb_key_bits < algo->keymin
|| algo->keymax < sav->key_auth->sadb_key_bits) {
ipseclog((LOG_ERR,
@@ -385,7 +452,7 @@ ah_keyed_sha1_loop(state, addr, len)
panic("ah_keyed_sha1_loop: what?");
ctxt = (SHA1_CTX *)state->foo;
- SHA1Update(ctxt, (u_int8_t *)addr, (size_t)len);
+ SHA1Update(ctxt, (caddr_t)addr, (size_t)len);
}
static void
@@ -414,13 +481,19 @@ static int
ah_hmac_md5_mature(sav)
struct secasvar *sav;
{
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
if (!sav->key_auth) {
ipseclog((LOG_ERR, "ah_hmac_md5_mature: no key is given.\n"));
return 1;
}
- algo = &ah_algorithms[sav->alg_auth];
+
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
+ ipseclog((LOG_ERR, "ah_hmac_md5_mature: unsupported algorithm.\n"));
+ return 1;
+ }
+
if (sav->key_auth->sadb_key_bits < algo->keymin
|| algo->keymax < sav->key_auth->sadb_key_bits) {
ipseclog((LOG_ERR,
@@ -532,13 +605,19 @@ static int
ah_hmac_sha1_mature(sav)
struct secasvar *sav;
{
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
if (!sav->key_auth) {
ipseclog((LOG_ERR, "ah_hmac_sha1_mature: no key is given.\n"));
return 1;
}
- algo = &ah_algorithms[sav->alg_auth];
+
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
+ ipseclog((LOG_ERR, "ah_hmac_sha1_mature: unsupported algorithm.\n"));
+ return 1;
+ }
+
if (sav->key_auth->sadb_key_bits < algo->keymin
|| algo->keymax < sav->key_auth->sadb_key_bits) {
ipseclog((LOG_ERR,
@@ -579,7 +658,7 @@ ah_hmac_sha1_init(state, sav)
/* compress the key if necessery */
if (64 < _KEYLEN(state->sav->key_auth)) {
SHA1Init(ctxt);
- SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sav->key_auth),
+ SHA1Update(ctxt, _KEYBUF(state->sav->key_auth),
_KEYLEN(state->sav->key_auth));
SHA1Final(&tk[0], ctxt);
key = &tk[0];
@@ -616,7 +695,7 @@ ah_hmac_sha1_loop(state, addr, len)
panic("ah_hmac_sha1_loop: what?");
ctxt = (SHA1_CTX *)(((u_char *)state->foo) + 128);
- SHA1Update(ctxt, (u_int8_t *)addr, (size_t)len);
+ SHA1Update(ctxt, (caddr_t)addr, (size_t)len);
}
static void
@@ -640,7 +719,7 @@ ah_hmac_sha1_result(state, addr)
SHA1Init(ctxt);
SHA1Update(ctxt, opad, 64);
- SHA1Update(ctxt, (u_int8_t *)&digest[0], sizeof(digest));
+ SHA1Update(ctxt, (caddr_t)&digest[0], sizeof(digest));
SHA1Final((caddr_t)&digest[0], ctxt);
bcopy(&digest[0], (void *)addr, HMACSIZE);
@@ -648,6 +727,404 @@ ah_hmac_sha1_result(state, addr)
free(state->foo, M_TEMP);
}
+static int
+ah_hmac_sha2_256_mature(sav)
+ struct secasvar *sav;
+{
+ const struct ah_algorithm *algo;
+
+ if (!sav->key_auth) {
+ ipseclog((LOG_ERR,
+ "ah_hmac_sha2_256_mature: no key is given.\n"));
+ return 1;
+ }
+
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
+ ipseclog((LOG_ERR,
+ "ah_hmac_sha2_256_mature: unsupported algorithm.\n"));
+ return 1;
+ }
+
+ if (sav->key_auth->sadb_key_bits < algo->keymin ||
+ algo->keymax < sav->key_auth->sadb_key_bits) {
+ ipseclog((LOG_ERR,
+ "ah_hmac_sha2_256_mature: invalid key length %d.\n",
+ sav->key_auth->sadb_key_bits));
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+ah_hmac_sha2_256_init(state, sav)
+ struct ah_algorithm_state *state;
+ struct secasvar *sav;
+{
+ u_char *ipad;
+ u_char *opad;
+ SHA256_CTX *ctxt;
+ u_char tk[SHA256_DIGEST_LENGTH];
+ u_char *key;
+ size_t keylen;
+ size_t i;
+
+ if (!state)
+ panic("ah_hmac_sha2_256_init: what?");
+
+ state->sav = sav;
+ state->foo = (void *)malloc(64 + 64 + sizeof(SHA256_CTX),
+ M_TEMP, M_NOWAIT);
+ if (!state->foo)
+ return ENOBUFS;
+
+ ipad = (u_char *)state->foo;
+ opad = (u_char *)(ipad + 64);
+ ctxt = (SHA256_CTX *)(opad + 64);
+
+ /* compress the key if necessery */
+ if (64 < _KEYLEN(state->sav->key_auth)) {
+ bzero(tk, sizeof(tk));
+ bzero(ctxt, sizeof(*ctxt));
+ SHA256_Init(ctxt);
+ SHA256_Update(ctxt, _KEYBUF(state->sav->key_auth),
+ _KEYLEN(state->sav->key_auth));
+ SHA256_Final(&tk[0], ctxt);
+ key = &tk[0];
+ keylen = sizeof(tk) < 64 ? sizeof(tk) : 64;
+ } else {
+ key = _KEYBUF(state->sav->key_auth);
+ keylen = _KEYLEN(state->sav->key_auth);
+ }
+
+ bzero(ipad, 64);
+ bzero(opad, 64);
+ bcopy(key, ipad, keylen);
+ bcopy(key, opad, keylen);
+ for (i = 0; i < 64; i++) {
+ ipad[i] ^= 0x36;
+ opad[i] ^= 0x5c;
+ }
+
+ bzero(ctxt, sizeof(*ctxt));
+ SHA256_Init(ctxt);
+ SHA256_Update(ctxt, ipad, 64);
+
+ return 0;
+}
+
+static void
+ah_hmac_sha2_256_loop(state, addr, len)
+ struct ah_algorithm_state *state;
+ caddr_t addr;
+ size_t len;
+{
+ SHA256_CTX *ctxt;
+
+ if (!state || !state->foo)
+ panic("ah_hmac_sha2_256_loop: what?");
+
+ ctxt = (SHA256_CTX *)(((u_char *)state->foo) + 128);
+ SHA256_Update(ctxt, (caddr_t)addr, (size_t)len);
+}
+
+static void
+ah_hmac_sha2_256_result(state, addr)
+ struct ah_algorithm_state *state;
+ caddr_t addr;
+{
+ u_char digest[SHA256_DIGEST_LENGTH];
+ u_char *ipad;
+ u_char *opad;
+ SHA256_CTX *ctxt;
+
+ if (!state || !state->foo)
+ panic("ah_hmac_sha2_256_result: what?");
+
+ ipad = (u_char *)state->foo;
+ opad = (u_char *)(ipad + 64);
+ ctxt = (SHA256_CTX *)(opad + 64);
+
+ SHA256_Final((caddr_t)&digest[0], ctxt);
+
+ bzero(ctxt, sizeof(*ctxt));
+ SHA256_Init(ctxt);
+ SHA256_Update(ctxt, opad, 64);
+ SHA256_Update(ctxt, (caddr_t)&digest[0], sizeof(digest));
+ SHA256_Final((caddr_t)&digest[0], ctxt);
+
+ bcopy(&digest[0], (void *)addr, HMACSIZE);
+
+ free(state->foo, M_TEMP);
+}
+
+static int
+ah_hmac_sha2_384_mature(sav)
+ struct secasvar *sav;
+{
+ const struct ah_algorithm *algo;
+
+ if (!sav->key_auth) {
+ ipseclog((LOG_ERR,
+ "ah_hmac_sha2_384_mature: no key is given.\n"));
+ return 1;
+ }
+
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
+ ipseclog((LOG_ERR,
+ "ah_hmac_sha2_384_mature: unsupported algorithm.\n"));
+ return 1;
+ }
+
+ if (sav->key_auth->sadb_key_bits < algo->keymin ||
+ algo->keymax < sav->key_auth->sadb_key_bits) {
+ ipseclog((LOG_ERR,
+ "ah_hmac_sha2_384_mature: invalid key length %d.\n",
+ sav->key_auth->sadb_key_bits));
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+ah_hmac_sha2_384_init(state, sav)
+ struct ah_algorithm_state *state;
+ struct secasvar *sav;
+{
+ u_char *ipad;
+ u_char *opad;
+ SHA384_CTX *ctxt;
+ u_char tk[SHA384_DIGEST_LENGTH];
+ u_char *key;
+ size_t keylen;
+ size_t i;
+
+ if (!state)
+ panic("ah_hmac_sha2_384_init: what?");
+
+ state->sav = sav;
+ state->foo = (void *)malloc(64 + 64 + sizeof(SHA384_CTX),
+ M_TEMP, M_NOWAIT);
+ if (!state->foo)
+ return ENOBUFS;
+ bzero(state->foo, 64 + 64 + sizeof(SHA384_CTX));
+
+ ipad = (u_char *)state->foo;
+ opad = (u_char *)(ipad + 64);
+ ctxt = (SHA384_CTX *)(opad + 64);
+
+ /* compress the key if necessery */
+ if (64 < _KEYLEN(state->sav->key_auth)) {
+ bzero(tk, sizeof(tk));
+ bzero(ctxt, sizeof(*ctxt));
+ SHA384_Init(ctxt);
+ SHA384_Update(ctxt, _KEYBUF(state->sav->key_auth),
+ _KEYLEN(state->sav->key_auth));
+ SHA384_Final(&tk[0], ctxt);
+ key = &tk[0];
+ keylen = sizeof(tk) < 64 ? sizeof(tk) : 64;
+ } else {
+ key = _KEYBUF(state->sav->key_auth);
+ keylen = _KEYLEN(state->sav->key_auth);
+ }
+
+ bzero(ipad, 64);
+ bzero(opad, 64);
+ bcopy(key, ipad, keylen);
+ bcopy(key, opad, keylen);
+ for (i = 0; i < 64; i++) {
+ ipad[i] ^= 0x36;
+ opad[i] ^= 0x5c;
+ }
+
+ bzero(ctxt, sizeof(*ctxt));
+ SHA384_Init(ctxt);
+ SHA384_Update(ctxt, ipad, 64);
+
+ return 0;
+}
+
+static void
+ah_hmac_sha2_384_loop(state, addr, len)
+ struct ah_algorithm_state *state;
+ caddr_t addr;
+ size_t len;
+{
+ SHA384_CTX *ctxt;
+
+ if (!state || !state->foo)
+ panic("ah_hmac_sha2_384_loop: what?");
+
+ ctxt = (SHA384_CTX *)(((u_char *)state->foo) + 128);
+ SHA384_Update(ctxt, (caddr_t)addr, (size_t)len);
+}
+
+static void
+ah_hmac_sha2_384_result(state, addr)
+ struct ah_algorithm_state *state;
+ caddr_t addr;
+{
+ u_char digest[SHA384_DIGEST_LENGTH];
+ u_char *ipad;
+ u_char *opad;
+ SHA384_CTX *ctxt;
+
+ if (!state || !state->foo)
+ panic("ah_hmac_sha2_384_result: what?");
+
+ ipad = (u_char *)state->foo;
+ opad = (u_char *)(ipad + 64);
+ ctxt = (SHA384_CTX *)(opad + 64);
+
+ SHA384_Final((caddr_t)&digest[0], ctxt);
+
+ bzero(ctxt, sizeof(*ctxt));
+ SHA384_Init(ctxt);
+ SHA384_Update(ctxt, opad, 64);
+ SHA384_Update(ctxt, (caddr_t)&digest[0], sizeof(digest));
+ SHA384_Final((caddr_t)&digest[0], ctxt);
+
+ bcopy(&digest[0], (void *)addr, HMACSIZE);
+
+ free(state->foo, M_TEMP);
+}
+
+static int
+ah_hmac_sha2_512_mature(sav)
+ struct secasvar *sav;
+{
+ const struct ah_algorithm *algo;
+
+ if (!sav->key_auth) {
+ ipseclog((LOG_ERR,
+ "ah_hmac_sha2_512_mature: no key is given.\n"));
+ return 1;
+ }
+
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
+ ipseclog((LOG_ERR,
+ "ah_hmac_sha2_512_mature: unsupported algorithm.\n"));
+ return 1;
+ }
+
+ if (sav->key_auth->sadb_key_bits < algo->keymin ||
+ algo->keymax < sav->key_auth->sadb_key_bits) {
+ ipseclog((LOG_ERR,
+ "ah_hmac_sha2_512_mature: invalid key length %d.\n",
+ sav->key_auth->sadb_key_bits));
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+ah_hmac_sha2_512_init(state, sav)
+ struct ah_algorithm_state *state;
+ struct secasvar *sav;
+{
+ u_char *ipad;
+ u_char *opad;
+ SHA512_CTX *ctxt;
+ u_char tk[SHA512_DIGEST_LENGTH];
+ u_char *key;
+ size_t keylen;
+ size_t i;
+
+ if (!state)
+ panic("ah_hmac_sha2_512_init: what?");
+
+ state->sav = sav;
+ state->foo = (void *)malloc(64 + 64 + sizeof(SHA512_CTX),
+ M_TEMP, M_NOWAIT);
+ if (!state->foo)
+ return ENOBUFS;
+ bzero(state->foo, 64 + 64 + sizeof(SHA512_CTX));
+
+ ipad = (u_char *)state->foo;
+ opad = (u_char *)(ipad + 64);
+ ctxt = (SHA512_CTX *)(opad + 64);
+
+ /* compress the key if necessery */
+ if (64 < _KEYLEN(state->sav->key_auth)) {
+ bzero(tk, sizeof(tk));
+ bzero(ctxt, sizeof(*ctxt));
+ SHA512_Init(ctxt);
+ SHA512_Update(ctxt, _KEYBUF(state->sav->key_auth),
+ _KEYLEN(state->sav->key_auth));
+ SHA512_Final(&tk[0], ctxt);
+ key = &tk[0];
+ keylen = sizeof(tk) < 64 ? sizeof(tk) : 64;
+ } else {
+ key = _KEYBUF(state->sav->key_auth);
+ keylen = _KEYLEN(state->sav->key_auth);
+ }
+
+ bzero(ipad, 64);
+ bzero(opad, 64);
+ bcopy(key, ipad, keylen);
+ bcopy(key, opad, keylen);
+ for (i = 0; i < 64; i++) {
+ ipad[i] ^= 0x36;
+ opad[i] ^= 0x5c;
+ }
+
+ bzero(ctxt, sizeof(*ctxt));
+ SHA512_Init(ctxt);
+ SHA512_Update(ctxt, ipad, 64);
+
+ return 0;
+}
+
+static void
+ah_hmac_sha2_512_loop(state, addr, len)
+ struct ah_algorithm_state *state;
+ caddr_t addr;
+ size_t len;
+{
+ SHA512_CTX *ctxt;
+
+ if (!state || !state->foo)
+ panic("ah_hmac_sha2_512_loop: what?");
+
+ ctxt = (SHA512_CTX *)(((u_char *)state->foo) + 128);
+ SHA512_Update(ctxt, (caddr_t)addr, (size_t)len);
+}
+
+static void
+ah_hmac_sha2_512_result(state, addr)
+ struct ah_algorithm_state *state;
+ caddr_t addr;
+{
+ u_char digest[SHA512_DIGEST_LENGTH];
+ u_char *ipad;
+ u_char *opad;
+ SHA512_CTX *ctxt;
+
+ if (!state || !state->foo)
+ panic("ah_hmac_sha2_512_result: what?");
+
+ ipad = (u_char *)state->foo;
+ opad = (u_char *)(ipad + 64);
+ ctxt = (SHA512_CTX *)(opad + 64);
+
+ SHA512_Final((caddr_t)&digest[0], ctxt);
+
+ bzero(ctxt, sizeof(*ctxt));
+ SHA512_Init(ctxt);
+ SHA512_Update(ctxt, opad, 64);
+ SHA512_Update(ctxt, (caddr_t)&digest[0], sizeof(digest));
+ SHA512_Final((caddr_t)&digest[0], ctxt);
+
+ bcopy(&digest[0], (void *)addr, HMACSIZE);
+
+ free(state->foo, M_TEMP);
+}
+
/*------------------------------------------------------------*/
/*
@@ -658,7 +1135,7 @@ ah_update_mbuf(m, off, len, algo, algos)
struct mbuf *m;
int off;
int len;
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
struct ah_algorithm_state *algos;
{
struct mbuf *n;
@@ -695,6 +1172,7 @@ ah_update_mbuf(m, off, len, algo, algos)
}
}
+#ifdef INET
/*
* Go generate the checksum. This function won't modify the mbuf chain
* except AH itself.
@@ -707,7 +1185,7 @@ ah4_calccksum(m, ahdat, len, algo, sav)
struct mbuf *m;
caddr_t ahdat;
size_t len;
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
struct secasvar *sav;
{
int off;
@@ -935,6 +1413,7 @@ fail:
m_free(n);
return error;
}
+#endif
#ifdef INET6
/*
@@ -949,7 +1428,7 @@ ah6_calccksum(m, ahdat, len, algo, sav)
struct mbuf *m;
caddr_t ahdat;
size_t len;
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
struct secasvar *sav;
{
int newoff, off;
diff --git a/sys/netinet6/ah_input.c b/sys/netinet6/ah_input.c
index b0489d1..070883e 100644
--- a/sys/netinet6/ah_input.c
+++ b/sys/netinet6/ah_input.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ah_input.c,v 1.29 2000/05/29 08:33:53 itojun Exp $ */
+/* $KAME: ah_input.c,v 1.59 2001/05/16 04:01:27 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -66,7 +66,9 @@
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
+#include <netinet6/in6_pcb.h>
#include <netinet/icmp6.h>
+#include <netinet6/ip6protosw.h>
#endif
#include <netinet6/ipsec.h>
@@ -107,16 +109,16 @@ ah4_input(m, va_alist)
struct ip *ip;
struct ah *ah;
u_int32_t spi;
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
size_t siz;
size_t siz1;
u_char *cksum;
struct secasvar *sav = NULL;
u_int16_t nxt;
size_t hlen;
- int s;
int off, proto;
va_list ap;
+ size_t stripsiz = 0;
va_start(ap, m);
off = va_arg(ap, int);
@@ -175,16 +177,16 @@ ah4_input(m, va_alist)
ipsecstat.in_badspi++;
goto fail;
}
- if (sav->alg_auth == SADB_AALG_NONE) {
+
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
ipseclog((LOG_DEBUG, "IPv4 AH input: "
- "unspecified authentication algorithm for spi %u\n",
+ "unsupported authentication algorithm for spi %u\n",
(u_int32_t)ntohl(spi)));
ipsecstat.in_badspi++;
goto fail;
}
- algo = &ah_algorithms[sav->alg_auth];
-
siz = (*algo->sumsiz)(sav);
siz1 = ((siz + 3) & ~(4 - 1));
@@ -284,29 +286,23 @@ ah4_input(m, va_alist)
goto fail;
}
- {
-#if 1
/*
* some of IP header fields are flipped to the host endian.
* convert them back to network endian. VERY stupid.
*/
ip->ip_len = htons(ip->ip_len + hlen);
ip->ip_off = htons(ip->ip_off);
-#endif
if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
free(cksum, M_TEMP);
ipsecstat.in_inval++;
goto fail;
}
ipsecstat.in_ahhist[sav->alg_auth]++;
-#if 1
/*
* flip them back.
*/
ip->ip_len = ntohs(ip->ip_len) - hlen;
ip->ip_off = ntohs(ip->ip_off);
-#endif
- }
{
caddr_t sumpos = NULL;
@@ -397,7 +393,14 @@ ah4_input(m, va_alist)
}
/* was it transmitted over the IPsec tunnel SA? */
- if (ipsec4_tunnel_validate(ip, nxt, sav) && nxt == IPPROTO_IPV4) {
+ if (sav->flags & SADB_X_EXT_OLD) {
+ /* RFC 1826 */
+ stripsiz = sizeof(struct ah) + siz1;
+ } else {
+ /* RFC 2402 */
+ stripsiz = sizeof(struct newah) + siz1;
+ }
+ if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav)) {
/*
* strip off all the headers that precedes AH.
* IP xx AH IP' payload -> IP' payload
@@ -405,17 +408,9 @@ ah4_input(m, va_alist)
* XXX more sanity checks
* XXX relationship with gif?
*/
- size_t stripsiz = 0;
u_int8_t tos;
tos = ip->ip_tos;
- if (sav->flags & SADB_X_EXT_OLD) {
- /* RFC 1826 */
- stripsiz = sizeof(struct ah) + siz1;
- } else {
- /* RFC 2402 */
- stripsiz = sizeof(struct newah) + siz1;
- }
m_adj(m, off + stripsiz);
if (m->m_len < sizeof(*ip)) {
m = m_pullup(m, sizeof(*ip));
@@ -469,6 +464,11 @@ ah4_input(m, va_alist)
#endif
key_sa_recordxfer(sav, m);
+ if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
+ ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
+ ipsecstat.in_nomem++;
+ goto fail;
+ }
if (! IF_HANDOFF(&ipintrq, m, NULL)) {
ipsecstat.in_inval++;
@@ -482,15 +482,6 @@ ah4_input(m, va_alist)
/*
* strip off AH.
*/
- size_t stripsiz = 0;
-
- if (sav->flags & SADB_X_EXT_OLD) {
- /* RFC 1826 */
- stripsiz = sizeof(struct ah) + siz1;
- } else {
- /* RFC 2402 */
- stripsiz = sizeof(struct newah) + siz1;
- }
ip = mtod(m, struct ip *);
#ifndef PULLDOWN_TEST
@@ -548,10 +539,19 @@ ah4_input(m, va_alist)
/* forget about IP hdr checksum, the check has already been passed */
key_sa_recordxfer(sav, m);
+ if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
+ ipsecstat.in_nomem++;
+ goto fail;
+ }
- if (nxt != IPPROTO_DONE)
+ if (nxt != IPPROTO_DONE) {
+ if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
+ ipsec4_in_reject(m, NULL)) {
+ ipsecstat.in_polvio++;
+ goto fail;
+ }
(*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
- else
+ } else
m_freem(m);
m = NULL;
}
@@ -587,12 +587,13 @@ ah6_input(mp, offp, proto)
struct ip6_hdr *ip6;
struct ah *ah;
u_int32_t spi;
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
size_t siz;
size_t siz1;
u_char *cksum;
struct secasvar *sav = NULL;
u_int16_t nxt;
+ size_t stripsiz = 0;
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE);
@@ -601,7 +602,7 @@ ah6_input(mp, offp, proto)
IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
if (ah == NULL) {
ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n"));
- ipsecstat.in_inval++;
+ ipsec6stat.in_inval++;
return IPPROTO_DONE;
}
#endif
@@ -637,16 +638,16 @@ ah6_input(mp, offp, proto)
ipsec6stat.in_badspi++;
goto fail;
}
- if (sav->alg_auth == SADB_AALG_NONE) {
+
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
ipseclog((LOG_DEBUG, "IPv6 AH input: "
- "unspecified authentication algorithm for spi %u\n",
+ "unsupported authentication algorithm for spi %u\n",
(u_int32_t)ntohl(spi)));
ipsec6stat.in_badspi++;
goto fail;
}
- algo = &ah_algorithms[sav->alg_auth];
-
siz = (*algo->sumsiz)(sav);
siz1 = ((siz + 3) & ~(4 - 1));
@@ -685,7 +686,7 @@ ah6_input(mp, offp, proto)
sizeof(struct ah) + sizoff + siz1);
if (ah == NULL) {
ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part"));
- ipsecstat.in_inval++;
+ ipsec6stat.in_inval++;
m = NULL;
goto fail;
}
@@ -808,7 +809,14 @@ ah6_input(mp, offp, proto)
}
/* was it transmitted over the IPsec tunnel SA? */
- if (ipsec6_tunnel_validate(ip6, nxt, sav) && nxt == IPPROTO_IPV6) {
+ if (sav->flags & SADB_X_EXT_OLD) {
+ /* RFC 1826 */
+ stripsiz = sizeof(struct ah) + siz1;
+ } else {
+ /* RFC 2402 */
+ stripsiz = sizeof(struct newah) + siz1;
+ }
+ if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) {
/*
* strip off all the headers that precedes AH.
* IP6 xx AH IP6' payload -> IP6' payload
@@ -816,17 +824,9 @@ ah6_input(mp, offp, proto)
* XXX more sanity checks
* XXX relationship with gif?
*/
- size_t stripsiz = 0;
u_int32_t flowinfo; /*net endian*/
flowinfo = ip6->ip6_flow;
- if (sav->flags & SADB_X_EXT_OLD) {
- /* RFC 1826 */
- stripsiz = sizeof(struct ah) + siz1;
- } else {
- /* RFC 2402 */
- stripsiz = sizeof(struct newah) + siz1;
- }
m_adj(m, off + stripsiz);
if (m->m_len < sizeof(*ip6)) {
/*
@@ -870,6 +870,11 @@ ah6_input(mp, offp, proto)
#endif
key_sa_recordxfer(sav, m);
+ if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
+ ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
+ ipsec6stat.in_nomem++;
+ goto fail;
+ }
if (! IF_HANDOFF(&ip6intrq, m, NULL)) {
ipsec6stat.in_inval++;
@@ -883,7 +888,6 @@ ah6_input(mp, offp, proto)
/*
* strip off AH.
*/
- size_t stripsiz = 0;
char *prvnxtp;
/*
@@ -894,14 +898,6 @@ ah6_input(mp, offp, proto)
prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
*prvnxtp = nxt;
- if (sav->flags & SADB_X_EXT_OLD) {
- /* RFC 1826 */
- stripsiz = sizeof(struct ah) + siz1;
- } else {
- /* RFC 2402 */
- stripsiz = sizeof(struct newah) + siz1;
- }
-
ip6 = mtod(m, struct ip6_hdr *);
#ifndef PULLDOWN_TEST
/*
@@ -945,6 +941,10 @@ ah6_input(mp, offp, proto)
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
key_sa_recordxfer(sav, m);
+ if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
+ ipsec6stat.in_nomem++;
+ goto fail;
+ }
}
*offp = off;
@@ -968,4 +968,92 @@ fail:
m_freem(m);
return IPPROTO_DONE;
}
+
+void
+ah6_ctlinput(cmd, sa, d)
+ int cmd;
+ struct sockaddr *sa;
+ void *d;
+{
+ const struct newah *ahp;
+ struct newah ah;
+ struct secasvar *sav;
+ struct ip6_hdr *ip6;
+ struct mbuf *m;
+ struct ip6ctlparam *ip6cp = NULL;
+ int off;
+ struct sockaddr_in6 sa6_src, sa6_dst;
+
+ if (sa->sa_family != AF_INET6 ||
+ sa->sa_len != sizeof(struct sockaddr_in6))
+ return;
+ if ((unsigned)cmd >= PRC_NCMDS)
+ return;
+
+ /* if the parameter is from icmp6, decode it. */
+ if (d != NULL) {
+ ip6cp = (struct ip6ctlparam *)d;
+ m = ip6cp->ip6c_m;
+ ip6 = ip6cp->ip6c_ip6;
+ off = ip6cp->ip6c_off;
+ } else {
+ m = NULL;
+ ip6 = NULL;
+ }
+
+ if (ip6) {
+ /*
+ * XXX: We assume that when ip6 is non NULL,
+ * M and OFF are valid.
+ */
+
+ /* check if we can safely examine src and dst ports */
+ if (m->m_pkthdr.len < off + sizeof(ah))
+ return;
+
+ if (m->m_len < off + sizeof(ah)) {
+ /*
+ * this should be rare case,
+ * so we compromise on this copy...
+ */
+ m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
+ ahp = &ah;
+ } else
+ ahp = (struct newah *)(mtod(m, caddr_t) + off);
+
+ if (cmd == PRC_MSGSIZE) {
+ int valid = 0;
+
+ /*
+ * Check to see if we have a valid SA corresponding to
+ * the address in the ICMP message payload.
+ */
+ sav = key_allocsa(AF_INET6,
+ (caddr_t)&sa6_src.sin6_addr,
+ (caddr_t)&sa6_dst.sin6_addr,
+ IPPROTO_AH, ahp->ah_spi);
+ if (sav) {
+ if (sav->state == SADB_SASTATE_MATURE ||
+ sav->state == SADB_SASTATE_DYING)
+ valid++;
+ key_freesav(sav);
+ }
+
+ /* XXX Further validation? */
+
+ /*
+ * Depending on the value of "valid" and routing table
+ * size (mtudisc_{hi,lo}wat), we will:
+ * - recalcurate the new MTU and create the
+ * corresponding routing entry, or
+ * - ignore the MTU change notification.
+ */
+ icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
+ }
+
+ /* we normally notify single pcb here */
+ } else {
+ /* we normally notify any pcb here */
+ }
+}
#endif /* INET6 */
diff --git a/sys/netinet6/ah_output.c b/sys/netinet6/ah_output.c
index 59263cd..983ecab 100644
--- a/sys/netinet6/ah_output.c
+++ b/sys/netinet6/ah_output.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ah_output.c,v 1.22 2000/07/03 13:23:28 itojun Exp $ */
+/* $KAME: ah_output.c,v 1.30 2001/02/21 00:50:53 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -76,7 +76,9 @@
#include <net/net_osdep.h>
+#ifdef INET
static struct in_addr *ah4_finaldst __P((struct mbuf *));
+#endif
/*
* compute AH header size.
@@ -87,7 +89,7 @@ size_t
ah_hdrsiz(isr)
struct ipsecrequest *isr;
{
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
size_t hdrsiz;
/* sanity check */
@@ -104,7 +106,7 @@ ah_hdrsiz(isr)
goto estimate;
/* we need transport mode AH. */
- algo = &ah_algorithms[isr->sav->alg_auth];
+ algo = ah_algorithm_lookup(isr->sav->alg_auth);
if (!algo)
goto estimate;
@@ -131,6 +133,7 @@ ah_hdrsiz(isr)
return sizeof(struct newah) + 16;
}
+#ifdef INET
/*
* Modify the packet so that it includes the authentication data.
* The mbuf passed must start with IPv4 header.
@@ -144,7 +147,7 @@ ah4_output(m, isr)
struct ipsecrequest *isr;
{
struct secasvar *sav = isr->sav;
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
u_int32_t spi;
u_char *ahdrpos;
u_char *ahsumpos = NULL;
@@ -171,7 +174,14 @@ ah4_output(m, isr)
return EINVAL;
}
- algo = &ah_algorithms[sav->alg_auth];
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
+ ipseclog((LOG_ERR, "ah4_output: unsupported algorithm: "
+ "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
+ ipsecstat.out_inval++;
+ m_freem(m);
+ return EINVAL;
+ }
spi = sav->spi;
/*
@@ -314,16 +324,19 @@ ah4_output(m, isr)
return 0;
}
+#endif
/* Calculate AH length */
int
ah_hdrlen(sav)
struct secasvar *sav;
{
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
int plen, ahlen;
- algo = &ah_algorithms[sav->alg_auth];
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo)
+ return 0;
if (sav->flags & SADB_X_EXT_OLD) {
/* RFC 1826 */
plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/
@@ -351,7 +364,7 @@ ah6_output(m, nexthdrp, md, isr)
struct mbuf *mprev;
struct mbuf *mah;
struct secasvar *sav = isr->sav;
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
u_int32_t spi;
u_char *ahsumpos = NULL;
size_t plen; /*AH payload size in bytes*/
@@ -414,7 +427,14 @@ ah6_output(m, nexthdrp, md, isr)
return EINVAL;
}
- algo = &ah_algorithms[sav->alg_auth];
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
+ ipseclog((LOG_ERR, "ah6_output: unsupported algorithm: "
+ "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
+ ipsec6stat.out_inval++;
+ m_freem(m);
+ return EINVAL;
+ }
spi = sav->spi;
/*
@@ -447,7 +467,7 @@ ah6_output(m, nexthdrp, md, isr)
ipseclog((LOG_WARNING,
"replay counter overflowed. %s\n",
ipsec_logsastr(sav)));
- ipsecstat.out_inval++;
+ ipsec6stat.out_inval++;
m_freem(m);
return EINVAL;
}
@@ -479,6 +499,7 @@ ah6_output(m, nexthdrp, md, isr)
}
#endif
+#ifdef INET
/*
* Find the final destination if there is loose/strict source routing option.
* Returns NULL if there's no source routing options.
@@ -564,3 +585,4 @@ ah4_finaldst(m)
}
return NULL;
}
+#endif
diff --git a/sys/netinet6/dest6.c b/sys/netinet6/dest6.c
index 8d3987c..8ecde86 100644
--- a/sys/netinet6/dest6.c
+++ b/sys/netinet6/dest6.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: dest6.c,v 1.12 2000/05/05 11:00:57 sumikawa Exp $ */
+/* $KAME: dest6.c,v 1.27 2001/03/29 05:34:30 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -35,12 +35,14 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <sys/time.h>
+#include <sys/kernel.h>
#include <net/if.h>
#include <net/route.h>
@@ -59,10 +61,13 @@ dest6_input(mp, offp, proto)
struct mbuf **mp;
int *offp, proto;
{
- register struct mbuf *m = *mp;
+ struct mbuf *m = *mp;
int off = *offp, dstoptlen, optlen;
struct ip6_dest *dstopts;
u_int8_t *opt;
+ struct ip6_hdr *ip6;
+
+ ip6 = mtod(m, struct ip6_hdr *);
/* validation of the length of the header */
#ifndef PULLDOWN_TEST
@@ -102,19 +107,21 @@ dest6_input(mp, offp, proto)
case IP6OPT_PADN:
optlen = *(opt + 1) + 2;
break;
- default: /* unknown option */
- if ((optlen = ip6_unknown_opt(opt, m,
- opt-mtod(m, u_int8_t *))) == -1)
- return(IPPROTO_DONE);
- optlen += 2;
- break;
+
+ default: /* unknown option */
+ optlen = ip6_unknown_opt(opt, m,
+ opt - mtod(m, u_int8_t *));
+ if (optlen == -1)
+ return (IPPROTO_DONE);
+ optlen += 2;
+ break;
}
}
*offp = off;
- return(dstopts->ip6d_nxt);
+ return (dstopts->ip6d_nxt);
bad:
m_freem(m);
- return(IPPROTO_DONE);
+ return (IPPROTO_DONE);
}
diff --git a/sys/netinet6/esp.h b/sys/netinet6/esp.h
index 95deec3..6f794a8 100644
--- a/sys/netinet6/esp.h
+++ b/sys/netinet6/esp.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: esp.h,v 1.8 2000/07/02 13:23:33 itojun Exp $ */
+/* $KAME: esp.h,v 1.16 2000/10/18 21:28:00 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -37,7 +37,9 @@
#ifndef _NETINET6_ESP_H_
#define _NETINET6_ESP_H_
-struct secasvar;
+#if defined(_KERNEL) && !defined(_LKM)
+#include "opt_inet.h"
+#endif
struct esp {
u_int32_t esp_spi; /* ESP */
@@ -67,35 +69,41 @@ struct esptail {
/*variable size, 32bit bound*/ /* Authentication data (new IPsec)*/
};
-struct esp_algorithm_state {
- struct secasvar *sav;
- void* foo; /*per algorithm data - maybe*/
-};
+#ifdef _KERNEL
+struct secasvar;
-/* XXX yet to be defined */
struct esp_algorithm {
size_t padbound; /* pad boundary, in byte */
+ int ivlenval; /* iv length, in byte */
int (*mature) __P((struct secasvar *));
int keymin; /* in bits */
int keymax; /* in bits */
+ int (*schedlen) __P((const struct esp_algorithm *));
const char *name;
- int (*ivlen) __P((struct secasvar *));
+ int (*ivlen) __P((const struct esp_algorithm *, struct secasvar *));
int (*decrypt) __P((struct mbuf *, size_t,
- struct secasvar *, struct esp_algorithm *, int));
+ struct secasvar *, const struct esp_algorithm *, int));
int (*encrypt) __P((struct mbuf *, size_t, size_t,
- struct secasvar *, struct esp_algorithm *, int));
+ struct secasvar *, const struct esp_algorithm *, int));
+ /* not supposed to be called directly */
+ int (*schedule) __P((const struct esp_algorithm *, struct secasvar *));
+ int (*blockdecrypt) __P((const struct esp_algorithm *,
+ struct secasvar *, u_int8_t *, u_int8_t *));
+ int (*blockencrypt) __P((const struct esp_algorithm *,
+ struct secasvar *, u_int8_t *, u_int8_t *));
};
-#ifdef _KERNEL
-extern struct esp_algorithm esp_algorithms[];
+extern const struct esp_algorithm *esp_algorithm_lookup __P((int));
+extern int esp_max_ivlen __P((void));
/* crypt routines */
extern int esp4_output __P((struct mbuf *, struct ipsecrequest *));
extern void esp4_input __P((struct mbuf *, ...));
extern size_t esp_hdrsiz __P((struct ipsecrequest *));
-#endif /*_KERNEL*/
+extern int esp_schedule __P((const struct esp_algorithm *, struct secasvar *));
extern int esp_auth __P((struct mbuf *, size_t, size_t,
struct secasvar *, u_char *));
+#endif /*_KERNEL*/
#endif /*_NETINET6_ESP_H_*/
diff --git a/sys/netinet6/esp6.h b/sys/netinet6/esp6.h
index 5d2f984..d774d24 100644
--- a/sys/netinet6/esp6.h
+++ b/sys/netinet6/esp6.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: esp.h,v 1.8 2000/07/02 13:23:33 itojun Exp $ */
+/* $KAME: esp.h,v 1.16 2000/10/18 21:28:00 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -41,6 +41,8 @@
extern int esp6_output __P((struct mbuf *, u_char *, struct mbuf *,
struct ipsecrequest *));
extern int esp6_input __P((struct mbuf **, int *, int));
+
+extern void esp6_ctlinput __P((int, struct sockaddr *, void *));
#endif /*_KERNEL*/
#endif /*_NETINET6_ESP6_H_*/
diff --git a/sys/netinet6/esp_core.c b/sys/netinet6/esp_core.c
index e5f8ec5..0319255 100644
--- a/sys/netinet6/esp_core.c
+++ b/sys/netinet6/esp_core.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: esp_core.c,v 1.15 2000/06/14 10:41:18 itojun Exp $ */
+/* $KAME: esp_core.c,v 1.50 2000/11/02 12:27:38 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -35,6 +35,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
#include <sys/protosw.h>
@@ -66,87 +67,181 @@
#ifdef INET6
#include <netinet6/esp6.h>
#endif
+#include <netinet6/esp_rijndael.h>
#include <net/pfkeyv2.h>
#include <netkey/keydb.h>
+#include <netkey/key.h>
#include <crypto/des/des.h>
#include <crypto/blowfish/blowfish.h>
#include <crypto/cast128/cast128.h>
-#include <crypto/rc5/rc5.h>
#include <net/net_osdep.h>
static int esp_null_mature __P((struct secasvar *));
-static int esp_null_ivlen __P((struct secasvar *));
static int esp_null_decrypt __P((struct mbuf *, size_t,
- struct secasvar *, struct esp_algorithm *, int));
+ struct secasvar *, const struct esp_algorithm *, int));
static int esp_null_encrypt __P((struct mbuf *, size_t, size_t,
- struct secasvar *, struct esp_algorithm *, int));
+ struct secasvar *, const struct esp_algorithm *, int));
static int esp_descbc_mature __P((struct secasvar *));
-static int esp_descbc_ivlen __P((struct secasvar *));
-static int esp_descbc_decrypt __P((struct mbuf *, size_t,
- struct secasvar *, struct esp_algorithm *, int));
-static int esp_descbc_encrypt __P((struct mbuf *, size_t, size_t,
- struct secasvar *, struct esp_algorithm *, int));
+static int esp_descbc_ivlen __P((const struct esp_algorithm *,
+ struct secasvar *));
+static int esp_des_schedule __P((const struct esp_algorithm *,
+ struct secasvar *));
+static int esp_des_schedlen __P((const struct esp_algorithm *));
+static int esp_des_blockdecrypt __P((const struct esp_algorithm *,
+ struct secasvar *, u_int8_t *, u_int8_t *));
+static int esp_des_blockencrypt __P((const struct esp_algorithm *,
+ struct secasvar *, u_int8_t *, u_int8_t *));
static int esp_cbc_mature __P((struct secasvar *));
-static int esp_blowfish_cbc_decrypt __P((struct mbuf *, size_t,
- struct secasvar *, struct esp_algorithm *, int));
-static int esp_blowfish_cbc_encrypt __P((struct mbuf *, size_t,
- size_t, struct secasvar *, struct esp_algorithm *, int));
-static int esp_blowfish_cbc_ivlen __P((struct secasvar *));
-static int esp_cast128cbc_ivlen __P((struct secasvar *));
-static int esp_cast128cbc_decrypt __P((struct mbuf *, size_t,
- struct secasvar *, struct esp_algorithm *, int));
-static int esp_cast128cbc_encrypt __P((struct mbuf *, size_t, size_t,
- struct secasvar *, struct esp_algorithm *, int));
-static int esp_3descbc_ivlen __P((struct secasvar *));
-static int esp_3descbc_decrypt __P((struct mbuf *, size_t,
- struct secasvar *, struct esp_algorithm *, int));
-static int esp_3descbc_encrypt __P((struct mbuf *, size_t, size_t,
- struct secasvar *, struct esp_algorithm *, int));
-static int esp_rc5cbc_ivlen __P((struct secasvar *));
-static int esp_rc5cbc_decrypt __P((struct mbuf *, size_t,
- struct secasvar *, struct esp_algorithm *, int));
-static int esp_rc5cbc_encrypt __P((struct mbuf *, size_t, size_t,
- struct secasvar *, struct esp_algorithm *, int));
-static void esp_increment_iv __P((struct secasvar *));
-static caddr_t mbuf_find_offset __P((struct mbuf *, size_t, size_t));
-
-/* NOTE: The order depends on SADB_EALG_x in netkey/keyv2.h */
-struct esp_algorithm esp_algorithms[] = {
- { 0, 0, 0, 0, 0, 0, 0, },
- { 8, esp_descbc_mature, 64, 64, "des-cbc",
- esp_descbc_ivlen, esp_descbc_decrypt, esp_descbc_encrypt, },
- { 8, esp_cbc_mature, 192, 192, "3des-cbc",
- esp_3descbc_ivlen, esp_3descbc_decrypt, esp_3descbc_encrypt, },
- { 1, esp_null_mature, 0, 2048, "null",
- esp_null_ivlen, esp_null_decrypt, esp_null_encrypt, },
- { 8, esp_cbc_mature, 40, 448, "blowfish-cbc",
- esp_blowfish_cbc_ivlen, esp_blowfish_cbc_decrypt,
- esp_blowfish_cbc_encrypt, },
- { 8, esp_cbc_mature, 40, 128, "cast128-cbc",
- esp_cast128cbc_ivlen, esp_cast128cbc_decrypt,
- esp_cast128cbc_encrypt, },
- { 8, esp_cbc_mature, 40, 2040, "rc5-cbc",
- esp_rc5cbc_ivlen, esp_rc5cbc_decrypt, esp_rc5cbc_encrypt, },
+static int esp_blowfish_schedule __P((const struct esp_algorithm *,
+ struct secasvar *));
+static int esp_blowfish_schedlen __P((const struct esp_algorithm *));
+static int esp_blowfish_blockdecrypt __P((const struct esp_algorithm *,
+ struct secasvar *, u_int8_t *, u_int8_t *));
+static int esp_blowfish_blockencrypt __P((const struct esp_algorithm *,
+ struct secasvar *, u_int8_t *, u_int8_t *));
+static int esp_cast128_schedule __P((const struct esp_algorithm *,
+ struct secasvar *));
+static int esp_cast128_schedlen __P((const struct esp_algorithm *));
+static int esp_cast128_blockdecrypt __P((const struct esp_algorithm *,
+ struct secasvar *, u_int8_t *, u_int8_t *));
+static int esp_cast128_blockencrypt __P((const struct esp_algorithm *,
+ struct secasvar *, u_int8_t *, u_int8_t *));
+static int esp_3des_schedule __P((const struct esp_algorithm *,
+ struct secasvar *));
+static int esp_3des_schedlen __P((const struct esp_algorithm *));
+static int esp_3des_blockdecrypt __P((const struct esp_algorithm *,
+ struct secasvar *, u_int8_t *, u_int8_t *));
+static int esp_3des_blockencrypt __P((const struct esp_algorithm *,
+ struct secasvar *, u_int8_t *, u_int8_t *));
+static int esp_common_ivlen __P((const struct esp_algorithm *,
+ struct secasvar *));
+static int esp_cbc_decrypt __P((struct mbuf *, size_t,
+ struct secasvar *, const struct esp_algorithm *, int));
+static int esp_cbc_encrypt __P((struct mbuf *, size_t, size_t,
+ struct secasvar *, const struct esp_algorithm *, int));
+
+#define MAXIVLEN 16
+
+static const struct esp_algorithm esp_algorithms[] = {
+ { 8, -1, esp_descbc_mature, 64, 64, esp_des_schedlen,
+ "des-cbc",
+ esp_descbc_ivlen, esp_cbc_decrypt,
+ esp_cbc_encrypt, esp_des_schedule,
+ esp_des_blockdecrypt, esp_des_blockencrypt, },
+ { 8, 8, esp_cbc_mature, 192, 192, esp_3des_schedlen,
+ "3des-cbc",
+ esp_common_ivlen, esp_cbc_decrypt,
+ esp_cbc_encrypt, esp_3des_schedule,
+ esp_3des_blockdecrypt, esp_3des_blockencrypt, },
+ { 1, 0, esp_null_mature, 0, 2048, 0, "null",
+ esp_common_ivlen, esp_null_decrypt,
+ esp_null_encrypt, NULL, },
+ { 8, 8, esp_cbc_mature, 40, 448, esp_blowfish_schedlen, "blowfish-cbc",
+ esp_common_ivlen, esp_cbc_decrypt,
+ esp_cbc_encrypt, esp_blowfish_schedule,
+ esp_blowfish_blockdecrypt, esp_blowfish_blockencrypt, },
+ { 8, 8, esp_cbc_mature, 40, 128, esp_cast128_schedlen,
+ "cast128-cbc",
+ esp_common_ivlen, esp_cbc_decrypt,
+ esp_cbc_encrypt, esp_cast128_schedule,
+ esp_cast128_blockdecrypt, esp_cast128_blockencrypt, },
+ { 16, 16, esp_cbc_mature, 128, 256, esp_rijndael_schedlen,
+ "rijndael-cbc",
+ esp_common_ivlen, esp_cbc_decrypt,
+ esp_cbc_encrypt, esp_rijndael_schedule,
+ esp_rijndael_blockdecrypt, esp_rijndael_blockencrypt },
};
-/*
- * mbuf assumption: foo_encrypt() assumes that IV part is placed in a single
- * mbuf, not across multiple mbufs.
- */
+const struct esp_algorithm *
+esp_algorithm_lookup(idx)
+ int idx;
+{
-static int
-esp_null_mature(sav)
+ switch (idx) {
+ case SADB_EALG_DESCBC:
+ return &esp_algorithms[0];
+ case SADB_EALG_3DESCBC:
+ return &esp_algorithms[1];
+ case SADB_EALG_NULL:
+ return &esp_algorithms[2];
+ case SADB_X_EALG_BLOWFISHCBC:
+ return &esp_algorithms[3];
+ case SADB_X_EALG_CAST128CBC:
+ return &esp_algorithms[4];
+ case SADB_X_EALG_RIJNDAELCBC:
+ return &esp_algorithms[5];
+ default:
+ return NULL;
+ }
+}
+
+int
+esp_max_ivlen()
+{
+ int idx;
+ int ivlen;
+
+ ivlen = 0;
+ for (idx = 0; idx < sizeof(esp_algorithms)/sizeof(esp_algorithms[0]);
+ idx++) {
+ if (esp_algorithms[idx].ivlenval > ivlen)
+ ivlen = esp_algorithms[idx].ivlenval;
+ }
+
+ return ivlen;
+}
+
+int
+esp_schedule(algo, sav)
+ const struct esp_algorithm *algo;
struct secasvar *sav;
{
- /* anything is okay */
- return 0;
+ int error;
+
+ /* check for key length */
+ if (_KEYBITS(sav->key_enc) < algo->keymin ||
+ _KEYBITS(sav->key_enc) > algo->keymax) {
+ ipseclog((LOG_ERR,
+ "esp_schedule %s: unsupported key length %d: "
+ "needs %d to %d bits\n", algo->name, _KEYBITS(sav->key_enc),
+ algo->keymin, algo->keymax));
+ return EINVAL;
+ }
+
+ /* already allocated */
+ if (sav->sched && sav->schedlen != 0)
+ return 0;
+ /* no schedule necessary */
+ if (!algo->schedule || !algo->schedlen)
+ return 0;
+
+ sav->schedlen = (*algo->schedlen)(algo);
+ if (sav->schedlen < 0)
+ return EINVAL;
+ sav->sched = malloc(sav->schedlen, M_SECA, M_DONTWAIT);
+ if (!sav->sched) {
+ sav->schedlen = 0;
+ return ENOBUFS;
+ }
+
+ error = (*algo->schedule)(algo, sav);
+ if (error) {
+ ipseclog((LOG_ERR, "esp_schedule %s: error %d\n",
+ algo->name, error));
+ free(sav->sched, M_SECA);
+ sav->sched = NULL;
+ sav->schedlen = 0;
+ }
+ return error;
}
static int
-esp_null_ivlen(sav)
+esp_null_mature(sav)
struct secasvar *sav;
{
+
+ /* anything is okay */
return 0;
}
@@ -155,9 +250,10 @@ esp_null_decrypt(m, off, sav, algo, ivlen)
struct mbuf *m;
size_t off; /* offset to ESP header */
struct secasvar *sav;
- struct esp_algorithm *algo;
+ const struct esp_algorithm *algo;
int ivlen;
{
+
return 0; /* do nothing */
}
@@ -167,9 +263,10 @@ esp_null_encrypt(m, off, plen, sav, algo, ivlen)
size_t off; /* offset to ESP header */
size_t plen; /* payload length (to be encrypted) */
struct secasvar *sav;
- struct esp_algorithm *algo;
+ const struct esp_algorithm *algo;
int ivlen;
{
+
return 0; /* do nothing */
}
@@ -177,7 +274,7 @@ static int
esp_descbc_mature(sav)
struct secasvar *sav;
{
- struct esp_algorithm *algo;
+ const struct esp_algorithm *algo;
if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) {
ipseclog((LOG_ERR, "esp_cbc_mature: "
@@ -189,9 +286,16 @@ esp_descbc_mature(sav)
ipseclog((LOG_ERR, "esp_descbc_mature: no key is given.\n"));
return 1;
}
- algo = &esp_algorithms[sav->alg_enc];
- if (_KEYBITS(sav->key_enc) < algo->keymin
- || algo->keymax < _KEYBITS(sav->key_enc)) {
+
+ algo = esp_algorithm_lookup(sav->alg_enc);
+ if (!algo) {
+ ipseclog((LOG_ERR,
+ "esp_descbc_mature: unsupported algorithm.\n"));
+ return 1;
+ }
+
+ if (_KEYBITS(sav->key_enc) < algo->keymin ||
+ _KEYBITS(sav->key_enc) > algo->keymax) {
ipseclog((LOG_ERR,
"esp_descbc_mature: invalid key length %d.\n",
_KEYBITS(sav->key_enc)));
@@ -199,7 +303,7 @@ esp_descbc_mature(sav)
}
/* weak key check */
- if (des_is_weak_key((C_Block *)_KEYBUF(sav->key_enc))) {
+ if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc))) {
ipseclog((LOG_ERR,
"esp_descbc_mature: weak key was passed.\n"));
return 1;
@@ -209,246 +313,69 @@ esp_descbc_mature(sav)
}
static int
-esp_descbc_ivlen(sav)
+esp_descbc_ivlen(algo, sav)
+ const struct esp_algorithm *algo;
struct secasvar *sav;
{
- if (sav && (sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B))
- return 4;
- if (sav && !(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV))
- return 4;
- else
+ if (!sav)
return 8;
+ if ((sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B))
+ return 4;
+ if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV))
+ return 4;
+ return 8;
}
static int
-esp_descbc_decrypt(m, off, sav, algo, ivlen)
- struct mbuf *m;
- size_t off; /* offset to ESP header */
- struct secasvar *sav;
- struct esp_algorithm *algo;
- int ivlen;
+esp_des_schedlen(algo)
+ const struct esp_algorithm *algo;
{
- size_t ivoff = 0;
- size_t bodyoff = 0;
- u_int8_t *iv;
- size_t plen;
- u_int8_t tiv[8];
- int derived;
- int error;
-
- derived = 0;
- /* sanity check */
- if (ivlen != sav->ivlen) {
- ipseclog((LOG_ERR, "esp_descbc_decrypt: bad ivlen %d/%d\n",
- ivlen, sav->ivlen));
- return EINVAL;
- }
- if (_KEYBITS(sav->key_enc) < algo->keymin
- || algo->keymax < _KEYBITS(sav->key_enc)) {
- ipseclog((LOG_ERR, "esp_descbc_decrypt: bad keylen %d\n",
- _KEYBITS(sav->key_enc)));
- return EINVAL;
- }
- if (sav->flags & SADB_X_EXT_OLD) {
- /* RFC 1827 */
- ivoff = off + sizeof(struct esp);
- bodyoff = off + sizeof(struct esp) + ivlen;
- derived = 0;
- } else {
- /* RFC 2406 */
- if (sav->flags & SADB_X_EXT_DERIV) {
- /*
- * draft-ietf-ipsec-ciph-des-derived-00.txt
- * uses sequence number field as IV field.
- * This draft has been deleted, but you can get from
- * ftp://ftp.kame.net/pub/internet-drafts/.
- */
- ivoff = off + sizeof(struct esp);
- bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);
- ivlen = sizeof(u_int32_t);
- derived = 1;
- } else {
- ivoff = off + sizeof(struct newesp);
- bodyoff = off + sizeof(struct newesp) + ivlen;
- derived = 0;
- }
- }
- if (ivlen == 4) {
- iv = &tiv[0];
- m_copydata(m, ivoff, 4, &tiv[0]);
- m_copydata(m, ivoff, 4, &tiv[4]);
- tiv[4] ^= 0xff;
- tiv[5] ^= 0xff;
- tiv[6] ^= 0xff;
- tiv[7] ^= 0xff;
- } else if (ivlen == 8) {
- iv = &tiv[0];
- m_copydata(m, ivoff, 8, &tiv[0]);
- } else {
- ipseclog((LOG_ERR, "esp_descbc_decrypt: unsupported ivlen %d\n",
- ivlen));
- return EINVAL;
- }
-
- plen = m->m_pkthdr.len;
- if (plen < bodyoff)
- panic("esp_descbc_decrypt: too short packet: len=%lu",
- (u_long)plen);
- plen -= bodyoff;
-
- if (plen % 8) {
- ipseclog((LOG_ERR, "esp_descbc_decrypt: "
- "payload length must be multiple of 8\n"));
- return EINVAL;
- }
-
- {
- int deserr;
- des_key_schedule ks;
-
- deserr = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks);
- if (deserr != 0) {
- ipseclog((LOG_ERR,
- "esp_descbc_decrypt: key error %d\n", deserr));
- return EINVAL;
- }
-
- error = des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv,
- DES_DECRYPT);
-
- /* for safety */
- bzero(&ks, sizeof(des_key_schedule));
- }
-
- /* for safety */
- bzero(&tiv[0], sizeof(tiv));
-
- return error;
+ return sizeof(des_key_schedule);
}
static int
-esp_descbc_encrypt(m, off, plen, sav, algo, ivlen)
- struct mbuf *m;
- size_t off; /* offset to ESP header */
- size_t plen; /* payload length (to be decrypted) */
+esp_des_schedule(algo, sav)
+ const struct esp_algorithm *algo;
struct secasvar *sav;
- struct esp_algorithm *algo;
- int ivlen;
{
- size_t ivoff = 0;
- size_t bodyoff = 0;
- u_int8_t *iv;
- u_int8_t tiv[8];
- int derived;
- int error;
-
- derived = 0;
- /* sanity check */
- if (plen % 8) {
- ipseclog((LOG_ERR, "esp_descbc_encrypt: "
- "payload length must be multiple of 8\n"));
- return EINVAL;
- }
- if (sav->ivlen != ivlen) {
- ipseclog((LOG_ERR, "esp_descbc_encrypt: bad ivlen %d/%d\n",
- ivlen, sav->ivlen));
- return EINVAL;
- }
- if (_KEYBITS(sav->key_enc) < algo->keymin
- || algo->keymax < _KEYBITS(sav->key_enc)) {
- ipseclog((LOG_ERR, "esp_descbc_encrypt: bad keylen %d\n",
- _KEYBITS(sav->key_enc)));
+ if (des_key_sched((des_cblock *)_KEYBUF(sav->key_enc),
+ *(des_key_schedule *)sav->sched))
return EINVAL;
- }
-
- if (sav->flags & SADB_X_EXT_OLD) {
- /* RFC 1827 */
- /*
- * draft-ietf-ipsec-ciph-des-derived-00.txt
- * uses sequence number field as IV field.
- * This draft has been deleted, see above.
- */
- ivoff = off + sizeof(struct esp);
- bodyoff = off + sizeof(struct esp) + ivlen;
- derived = 0;
- } else {
- /* RFC 2406 */
- if (sav->flags & SADB_X_EXT_DERIV) {
- /*
- * draft-ietf-ipsec-ciph-des-derived-00.txt
- * uses sequence number field as IV field.
- * This draft has been deleted, see above.
- */
- ivoff = off + sizeof(struct esp);
- bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);
- ivlen = sizeof(u_int32_t);
- derived = 1;
- } else {
- ivoff = off + sizeof(struct newesp);
- bodyoff = off + sizeof(struct newesp) + ivlen;
- derived = 0;
- }
- }
-
- if (m->m_pkthdr.len < bodyoff)
- panic("assumption failed: mbuf too short");
- iv = mbuf_find_offset(m, ivoff, ivlen);
- if (!iv)
- panic("assumption failed: bad mbuf chain");
- if (ivlen == 4) {
- if (!derived) {
- bcopy(sav->iv, &tiv[0], 4);
- bcopy(sav->iv, &tiv[4], 4);
- tiv[4] ^= 0xff;
- tiv[5] ^= 0xff;
- tiv[6] ^= 0xff;
- tiv[7] ^= 0xff;
- bcopy(&tiv[0], iv, 4);
- iv = &tiv[0];
- } else {
- bcopy(iv, &tiv[0], 4);
- bcopy(iv, &tiv[4], 4);
- tiv[4] ^= 0xff;
- tiv[5] ^= 0xff;
- tiv[6] ^= 0xff;
- tiv[7] ^= 0xff;
- iv = &tiv[0];
- }
- } else if (ivlen == 8)
- bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen);
- else {
- ipseclog((LOG_ERR,
- "esp_descbc_encrypt: unsupported ivlen %d\n", ivlen));
- return EINVAL;
- }
-
- {
- int deserr;
- des_key_schedule ks;
-
- deserr = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks);
- if (deserr != 0) {
- ipseclog((LOG_ERR,
- "esp_descbc_encrypt: key error %d\n", deserr));
- return EINVAL;
- }
-
- error = des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv,
- DES_ENCRYPT);
+ else
+ return 0;
+}
- /* for safety */
- bzero(&ks, sizeof(des_key_schedule));
- }
+static int
+esp_des_blockdecrypt(algo, sav, s, d)
+ const struct esp_algorithm *algo;
+ struct secasvar *sav;
+ u_int8_t *s;
+ u_int8_t *d;
+{
- esp_increment_iv(sav);
+ /* assumption: d has a good alignment */
+ bcopy(s, d, sizeof(DES_LONG) * 2);
+ des_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
+ *(des_key_schedule *)sav->sched, DES_DECRYPT);
+ return 0;
+}
- /* for safety */
- bzero(&tiv[0], sizeof(tiv));
+static int
+esp_des_blockencrypt(algo, sav, s, d)
+ const struct esp_algorithm *algo;
+ struct secasvar *sav;
+ u_int8_t *s;
+ u_int8_t *d;
+{
- return error;
+ /* assumption: d has a good alignment */
+ bcopy(s, d, sizeof(DES_LONG) * 2);
+ des_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
+ *(des_key_schedule *)sav->sched, DES_ENCRYPT);
+ return 0;
}
static int
@@ -456,7 +383,7 @@ esp_cbc_mature(sav)
struct secasvar *sav;
{
int keylen;
- struct esp_algorithm *algo;
+ const struct esp_algorithm *algo;
if (sav->flags & SADB_X_EXT_OLD) {
ipseclog((LOG_ERR,
@@ -470,31 +397,47 @@ esp_cbc_mature(sav)
}
if (!sav->key_enc) {
+ ipseclog((LOG_ERR, "esp_cbc_mature: no key is given.\n"));
+ return 1;
+ }
+
+ algo = esp_algorithm_lookup(sav->alg_enc);
+ if (!algo) {
ipseclog((LOG_ERR,
- "esp_cbc_mature: no key is given.\n"));
+ "esp_cbc_mature %s: unsupported algorithm.\n", algo->name));
return 1;
}
- algo = &esp_algorithms[sav->alg_enc];
+
keylen = sav->key_enc->sadb_key_bits;
if (keylen < algo->keymin || algo->keymax < keylen) {
- ipseclog((LOG_ERR, "esp_cbc_mature: invalid key length %d.\n",
- sav->key_enc->sadb_key_bits));
+ ipseclog((LOG_ERR,
+ "esp_cbc_mature %s: invalid key length %d.\n",
+ algo->name, sav->key_enc->sadb_key_bits));
return 1;
}
switch (sav->alg_enc) {
case SADB_EALG_3DESCBC:
/* weak key check */
- if (des_is_weak_key((C_Block *)_KEYBUF(sav->key_enc))
- || des_is_weak_key((C_Block *)(_KEYBUF(sav->key_enc) + 8))
- || des_is_weak_key((C_Block *)(_KEYBUF(sav->key_enc) + 16))) {
+ if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc)) ||
+ des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 8)) ||
+ des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 16))) {
ipseclog((LOG_ERR,
- "esp_cbc_mature: weak key was passed.\n"));
+ "esp_cbc_mature %s: weak key was passed.\n",
+ algo->name));
return 1;
}
break;
- case SADB_EALG_BLOWFISHCBC:
- case SADB_EALG_CAST128CBC:
- case SADB_EALG_RC5CBC:
+ case SADB_X_EALG_BLOWFISHCBC:
+ case SADB_X_EALG_CAST128CBC:
+ break;
+ case SADB_X_EALG_RIJNDAELCBC:
+ /* allows specific key sizes only */
+ if (!(keylen == 128 || keylen == 192 || keylen == 256)) {
+ ipseclog((LOG_ERR,
+ "esp_cbc_mature %s: invalid key length %d.\n",
+ algo->name, keylen));
+ return 1;
+ }
break;
}
@@ -502,694 +445,596 @@ esp_cbc_mature(sav)
}
static int
-esp_blowfish_cbc_decrypt(m, off, sav, algo, ivlen)
- struct mbuf *m;
- size_t off; /* offset to ESP header */
- struct secasvar *sav;
- struct esp_algorithm *algo;
- int ivlen;
+esp_blowfish_schedlen(algo)
+ const struct esp_algorithm *algo;
{
- size_t ivoff;
- size_t bodyoff;
- u_int8_t *iv;
- u_int8_t tiv[8];
- size_t plen;
- static BF_KEY key; /* made static to avoid kernel stack overflow */
- int s;
- int error;
-
- /* sanity check */
- if (sav->ivlen != ivlen) {
- ipseclog((LOG_ERR,
- "esp_blowfish_cbc_decrypt: bad ivlen %d/%d\n",
- ivlen, sav->ivlen));
- return EINVAL;
- }
- if (_KEYBITS(sav->key_enc) < algo->keymin
- || algo->keymax < _KEYBITS(sav->key_enc)) {
- ipseclog((LOG_ERR,
- "esp_blowfish_cbc_decrypt: unsupported key length %d: "
- "need %d to %d bits\n", _KEYBITS(sav->key_enc),
- algo->keymin, algo->keymax));
- return EINVAL;
- }
- if (sav->flags & SADB_X_EXT_OLD) {
- ipseclog((LOG_ERR,
- "esp_blowfish_cbc_decrypt: unsupported ESP version\n"));
- return EINVAL;
- }
- if (ivlen != 8) {
- ipseclog((LOG_ERR,
- "esp_blowfish_cbc_decrypt: unsupported ivlen %d\n", ivlen));
- return EINVAL;
- }
-
- ivoff = off + sizeof(struct newesp);
- bodyoff = off + sizeof(struct newesp) + ivlen;
- iv = &tiv[0];
- m_copydata(m, ivoff, 8, &tiv[0]);
-
- plen = m->m_pkthdr.len;
- if (plen < bodyoff)
- panic("esp_blowfish_cbc_decrypt: too short packet: len=%lu",
- (u_long)plen);
- plen -= bodyoff;
-
- if (plen % 8) {
- ipseclog((LOG_ERR, "esp_blowfish_cbc_decrypt: "
- "payload length must be multiple of 8\n"));
- return EINVAL;
- }
-
-#ifdef __NetBSD__
- s = splsoftnet(); /* XXX correct? */
-#else
- s = splnet(); /* XXX correct? */
-#endif
-
- BF_set_key(&key, _KEYBITS(sav->key_enc) / 8, _KEYBUF(sav->key_enc));
- error = BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_DECRYPT);
-
- /* for safety */
- bzero(&key, sizeof(BF_KEY));
- splx(s);
-
- /* for safety */
- bzero(&tiv[0], sizeof(tiv));
-
- return error;
+ return sizeof(BF_KEY);
}
static int
-esp_blowfish_cbc_encrypt(m, off, plen, sav, algo, ivlen)
- struct mbuf *m;
- size_t off; /* offset to ESP header */
- size_t plen; /* payload length (to be decrypted) */
+esp_blowfish_schedule(algo, sav)
+ const struct esp_algorithm *algo;
struct secasvar *sav;
- struct esp_algorithm *algo;
- int ivlen;
{
- size_t ivoff;
- size_t bodyoff;
- u_int8_t *iv;
- static BF_KEY key; /* made static to avoid kernel stack overflow */
- int s;
- int error;
- /* sanity check */
- if (plen % 8) {
- ipseclog((LOG_ERR, "esp_blowfish_cbc_encrypt: "
- "payload length must be multiple of 8\n"));
- return EINVAL;
- }
- if (sav->ivlen != ivlen) {
- ipseclog((LOG_ERR,
- "esp_blowfish_cbc_encrypt: bad ivlen %d/%d\n",
- ivlen, sav->ivlen));
- return EINVAL;
- }
- if (_KEYBITS(sav->key_enc) < algo->keymin
- || algo->keymax < _KEYBITS(sav->key_enc)) {
- ipseclog((LOG_ERR,
- "esp_blowfish_cbc_encrypt: unsupported key length %d: "
- "need %d to %d bits\n", _KEYBITS(sav->key_enc),
- algo->keymin, algo->keymax));
- return EINVAL;
- }
- if (sav->flags & SADB_X_EXT_OLD) {
- ipseclog((LOG_ERR,
- "esp_blowfish_cbc_encrypt: unsupported ESP version\n"));
- return EINVAL;
- }
- if (ivlen != 8) {
- ipseclog((LOG_ERR,
- "esp_blowfish_cbc_encrypt: unsupported ivlen %d\n", ivlen));
- return EINVAL;
- }
-
- ivoff = off + sizeof(struct newesp);
- bodyoff = off + sizeof(struct newesp) + ivlen;
-
- if (m->m_pkthdr.len < bodyoff)
- panic("assumption failed: mbuf too short");
- iv = mbuf_find_offset(m, ivoff, ivlen);
- if (!iv)
- panic("assumption failed: bad mbuf chain");
-
- bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen);
-
-#ifdef __NetBSD__
- s = splsoftnet(); /* XXX correct? */
-#else
- s = splnet(); /* XXX correct? */
-#endif
-
- BF_set_key(&key, _KEYBITS(sav->key_enc) / 8, _KEYBUF(sav->key_enc));
- error = BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_ENCRYPT);
-
- /* for safety */
- bzero(&key, sizeof(BF_KEY));
-
- splx(s);
-
- esp_increment_iv(sav);
-
- return error;
+ BF_set_key((BF_KEY *)sav->sched, _KEYLEN(sav->key_enc),
+ _KEYBUF(sav->key_enc));
+ return 0;
}
static int
-esp_blowfish_cbc_ivlen(sav)
+esp_blowfish_blockdecrypt(algo, sav, s, d)
+ const struct esp_algorithm *algo;
struct secasvar *sav;
+ u_int8_t *s;
+ u_int8_t *d;
{
- return 8;
+ /* HOLY COW! BF_encrypt() takes values in host byteorder */
+ BF_LONG t[2];
+
+ bcopy(s, t, sizeof(t));
+ t[0] = ntohl(t[0]);
+ t[1] = ntohl(t[1]);
+ BF_encrypt(t, (BF_KEY *)sav->sched, BF_DECRYPT);
+ t[0] = htonl(t[0]);
+ t[1] = htonl(t[1]);
+ bcopy(t, d, sizeof(t));
+ return 0;
}
static int
-esp_cast128cbc_ivlen(sav)
+esp_blowfish_blockencrypt(algo, sav, s, d)
+ const struct esp_algorithm *algo;
struct secasvar *sav;
+ u_int8_t *s;
+ u_int8_t *d;
{
- return 8;
+ /* HOLY COW! BF_encrypt() takes values in host byteorder */
+ BF_LONG t[2];
+
+ bcopy(s, t, sizeof(t));
+ t[0] = ntohl(t[0]);
+ t[1] = ntohl(t[1]);
+ BF_encrypt(t, (BF_KEY *)sav->sched, BF_ENCRYPT);
+ t[0] = htonl(t[0]);
+ t[1] = htonl(t[1]);
+ bcopy(t, d, sizeof(t));
+ return 0;
}
static int
-esp_cast128cbc_decrypt(m, off, sav, algo, ivlen)
- struct mbuf *m;
- size_t off;
- struct secasvar *sav;
- struct esp_algorithm *algo;
- int ivlen;
+esp_cast128_schedlen(algo)
+ const struct esp_algorithm *algo;
{
- size_t ivoff;
- size_t bodyoff;
- u_int8_t iv[8];
- size_t plen;
- int error;
- /* sanity check */
- if (ivlen != sav->ivlen) {
- ipseclog((LOG_ERR, "esp_cast128cbc_decrypt: bad ivlen %d/%d\n",
- ivlen, sav->ivlen));
- return EINVAL;
- }
- if (_KEYBITS(sav->key_enc) < algo->keymin
- || _KEYBITS(sav->key_enc) > algo->keymax) {
- ipseclog((LOG_ERR,
- "esp_cast128cbc_decrypt: unsupported key length %d: "
- "need %d to %d bits\n", _KEYBITS(sav->key_enc),
- algo->keymin, algo->keymax));
- return EINVAL;
- }
- if (sav->flags & SADB_X_EXT_OLD) {
- ipseclog((LOG_ERR,
- "esp_cast128cbc_decrypt: unsupported ESP version\n"));
- return EINVAL;
- }
- if (ivlen != 8) {
- ipseclog((LOG_ERR,
- "esp_cast128cbc_decrypt: unsupported ivlen %d\n", ivlen));
- return EINVAL;
- }
-
- ivoff = off + sizeof(struct newesp);
- bodyoff = off + sizeof(struct newesp) + ivlen;
+ return sizeof(u_int32_t) * 32;
+}
- /* copy mbuf's IV into iv */
- m_copydata(m, ivoff, 8, iv);
+static int
+esp_cast128_schedule(algo, sav)
+ const struct esp_algorithm *algo;
+ struct secasvar *sav;
+{
- plen = m->m_pkthdr.len;
- if (plen < bodyoff) {
- panic("esp_cast128cbc_decrypt: too short packet: len=%lu\n",
- (u_long)plen);
- }
- plen -= bodyoff;
+ set_cast128_subkey((u_int32_t *)sav->sched, _KEYBUF(sav->key_enc));
+ return 0;
+}
- if (plen % 8) {
- ipseclog((LOG_ERR, "esp_cast128cbc_decrypt: "
- "payload length must be multiple of 8\n"));
- return EINVAL;
- }
+static int
+esp_cast128_blockdecrypt(algo, sav, s, d)
+ const struct esp_algorithm *algo;
+ struct secasvar *sav;
+ u_int8_t *s;
+ u_int8_t *d;
+{
- /* decrypt */
- {
- u_int8_t key[16];
- u_int32_t subkey[32];
+ if (_KEYLEN(sav->key_enc) <= 80 / 8)
+ cast128_decrypt_round12(d, s, (u_int32_t *)sav->sched);
+ else
+ cast128_decrypt_round16(d, s, (u_int32_t *)sav->sched);
+ return 0;
+}
- bzero(key, sizeof(key));
- bcopy(_KEYBUF(sav->key_enc), key, _KEYLEN(sav->key_enc));
+static int
+esp_cast128_blockencrypt(algo, sav, s, d)
+ const struct esp_algorithm *algo;
+ struct secasvar *sav;
+ u_int8_t *s;
+ u_int8_t *d;
+{
- set_cast128_subkey(subkey, key);
- error = cast128_cbc_process(m, bodyoff, plen, subkey, iv,
- _KEYBITS(sav->key_enc) / 8, CAST128_DECRYPT);
+ if (_KEYLEN(sav->key_enc) <= 80 / 8)
+ cast128_encrypt_round12(d, s, (u_int32_t *)sav->sched);
+ else
+ cast128_encrypt_round16(d, s, (u_int32_t *)sav->sched);
+ return 0;
+}
- /* for safety */
- bzero(subkey, sizeof(subkey));
- bzero(key, sizeof(key));
- }
+static int
+esp_3des_schedlen(algo)
+ const struct esp_algorithm *algo;
+{
- return error;
+ return sizeof(des_key_schedule) * 3;
}
static int
-esp_cast128cbc_encrypt(m, off, plen, sav, algo, ivlen)
- struct mbuf *m;
- size_t off;
- size_t plen;
+esp_3des_schedule(algo, sav)
+ const struct esp_algorithm *algo;
struct secasvar *sav;
- struct esp_algorithm *algo;
- int ivlen;
{
- size_t ivoff;
- size_t bodyoff;
- u_int8_t *iv;
int error;
+ des_key_schedule *p;
+ int i;
+ char *k;
- /* sanity check */
- if (plen % 8) {
- ipseclog((LOG_ERR, "esp_cast128cbc_encrypt: "
- "payload length must be multiple of 8\n"));
- return EINVAL;
- }
- if (sav->ivlen != ivlen) {
- ipseclog((LOG_ERR, "esp_cast128cbc_encrypt: bad ivlen %d/%d\n",
- ivlen, sav->ivlen));
- return EINVAL;
+ p = (des_key_schedule *)sav->sched;
+ k = _KEYBUF(sav->key_enc);
+ for (i = 0; i < 3; i++) {
+ error = des_key_sched((des_cblock *)(k + 8 * i), p[i]);
+ if (error)
+ return EINVAL;
}
- if (_KEYBITS(sav->key_enc) < algo->keymin
- || _KEYBITS(sav->key_enc) > algo->keymax) {
- ipseclog((LOG_ERR,
- "esp_cast128cbc_encrypt: unsupported key length %d: "
- "needs %d to %d bits\n", _KEYBITS(sav->key_enc),
- algo->keymin, algo->keymax));
- return EINVAL;
- }
- if (sav->flags & SADB_X_EXT_OLD) {
- ipseclog((LOG_ERR,
- "esp_cast128cbc_encrypt: unsupported ESP version\n"));
- return EINVAL;
- }
- if (ivlen != 8) {
- ipseclog((LOG_ERR,
- "esp_cast128cbc_encrypt: unsupported ivlen %d\n", ivlen));
- return EINVAL;
- }
-
- ivoff = off + sizeof(struct newesp);
- bodyoff = off + sizeof(struct newesp) + ivlen;
-
- if (m->m_pkthdr.len < bodyoff)
- panic("assumption failed: mbuf too short");
- iv = mbuf_find_offset(m, ivoff, ivlen);
- if (!iv)
- panic("assumption failed: bad mbuf chain");
-
- bcopy(sav->iv, iv, ivlen);
-
- /* encrypt */
- {
- u_int8_t key[16];
- u_int32_t subkey[32];
-
- bzero(key, sizeof(key));
- bcopy(_KEYBUF(sav->key_enc), key, _KEYLEN(sav->key_enc));
-
- set_cast128_subkey(subkey, key);
- error = cast128_cbc_process(m, bodyoff, plen, subkey, iv,
- _KEYBITS(sav->key_enc) / 8, CAST128_ENCRYPT);
-
- /* for safety */
- bzero(subkey, sizeof(subkey));
- bzero(key, sizeof(key));
- }
+ return 0;
+}
- esp_increment_iv(sav);
+static int
+esp_3des_blockdecrypt(algo, sav, s, d)
+ const struct esp_algorithm *algo;
+ struct secasvar *sav;
+ u_int8_t *s;
+ u_int8_t *d;
+{
+ des_key_schedule *p;
+
+ /* assumption: d has a good alignment */
+ p = (des_key_schedule *)sav->sched;
+ bcopy(s, d, sizeof(DES_LONG) * 2);
+ des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[2], DES_DECRYPT);
+ des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[1], DES_ENCRYPT);
+ des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[0], DES_DECRYPT);
+ return 0;
+}
- return error;
+static int
+esp_3des_blockencrypt(algo, sav, s, d)
+ const struct esp_algorithm *algo;
+ struct secasvar *sav;
+ u_int8_t *s;
+ u_int8_t *d;
+{
+ des_key_schedule *p;
+
+ /* assumption: d has a good alignment */
+ p = (des_key_schedule *)sav->sched;
+ bcopy(s, d, sizeof(DES_LONG) * 2);
+ des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[0], DES_ENCRYPT);
+ des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[1], DES_DECRYPT);
+ des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[2], DES_ENCRYPT);
+ return 0;
}
static int
-esp_3descbc_ivlen(sav)
+esp_common_ivlen(algo, sav)
+ const struct esp_algorithm *algo;
struct secasvar *sav;
{
- return 8;
+
+ if (!algo)
+ panic("esp_common_ivlen: unknown algorithm");
+ return algo->ivlenval;
}
static int
-esp_3descbc_decrypt(m, off, sav, algo, ivlen)
+esp_cbc_decrypt(m, off, sav, algo, ivlen)
struct mbuf *m;
size_t off;
struct secasvar *sav;
- struct esp_algorithm *algo;
+ const struct esp_algorithm *algo;
int ivlen;
{
- size_t ivoff;
- size_t bodyoff;
- u_int8_t *iv;
- size_t plen;
- u_int8_t tiv[8];
+ struct mbuf *s;
+ struct mbuf *d, *d0, *dp;
+ int soff, doff; /*offset from the head of chain, to head of this mbuf */
+ int sn, dn; /*offset from the head of the mbuf, to meat */
+ size_t ivoff, bodyoff;
+ u_int8_t iv[MAXIVLEN], *ivp;
+ u_int8_t sbuf[MAXIVLEN], *sp;
+ u_int8_t *p, *q;
+ struct mbuf *scut;
+ int scutoff;
+ int i;
+ int blocklen;
+ int derived;
- /* sanity check */
- if (ivlen != sav->ivlen) {
- ipseclog((LOG_ERR, "esp_3descbc_decrypt: bad ivlen %d/%d\n",
- ivlen, sav->ivlen));
+ if (ivlen != sav->ivlen || ivlen > sizeof(iv)) {
+ ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
+ "unsupported ivlen %d\n", algo->name, ivlen));
+ m_freem(m);
return EINVAL;
}
- if (_KEYBITS(sav->key_enc) < algo->keymin
- || algo->keymax < _KEYBITS(sav->key_enc)) {
- ipseclog((LOG_ERR, "esp_3descbc_decrypt: bad keylen %d\n",
- _KEYBITS(sav->key_enc)));
- return EINVAL;
- }
- if (sav->flags & SADB_X_EXT_OLD) {
- ipseclog((LOG_ERR,
- "esp_3descbc_decrypt: unsupported ESP version\n"));
- return EINVAL;
- }
- if (ivlen != 8) {
- ipseclog((LOG_ERR,
- "esp_3descbc_decrypt: unsupported ivlen %d\n", ivlen));
- return EINVAL;
- }
-
- ivoff = off + sizeof(struct newesp);
- bodyoff = off + sizeof(struct newesp) + ivlen;
- iv = &tiv[0];
- m_copydata(m, ivoff, 8, &tiv[0]);
- plen = m->m_pkthdr.len;
- if (plen < bodyoff)
- panic("esp_3descbc_decrypt: too short packet: len=%lu",
- (u_long)plen);
+ /* assumes blocklen == padbound */
+ blocklen = algo->padbound;
- plen -= bodyoff;
-
- if (plen % 8) {
- ipseclog((LOG_ERR, "esp_3descbc_decrypt: "
- "payload length must be multiple of 8\n"));
+#ifdef DIAGNOSTIC
+ if (blocklen > sizeof(iv)) {
+ ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
+ "unsupported blocklen %d\n", algo->name, blocklen));
+ m_freem(m);
return EINVAL;
}
+#endif
- /* decrypt packet */
- {
- int deserr[3];
- des_key_schedule ks[3];
-
- deserr[0] = des_key_sched((C_Block *)_KEYBUF(sav->key_enc),ks[0]);
- deserr[1] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), ks[1]);
- deserr[2] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), ks[2]);
- if ((deserr[0] != 0) || (deserr[1] != 0) || (deserr[2] != 0)) {
- ipseclog((LOG_ERR, "esp_3descbc_decrypt: key error %d/%d/%d\n",
- deserr[0], deserr[1], deserr[2]));
- return EINVAL;
+ if (sav->flags & SADB_X_EXT_OLD) {
+ /* RFC 1827 */
+ ivoff = off + sizeof(struct esp);
+ bodyoff = off + sizeof(struct esp) + ivlen;
+ derived = 0;
+ } else {
+ /* RFC 2406 */
+ if (sav->flags & SADB_X_EXT_DERIV) {
+ /*
+ * draft-ietf-ipsec-ciph-des-derived-00.txt
+ * uses sequence number field as IV field.
+ */
+ ivoff = off + sizeof(struct esp);
+ bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);
+ ivlen = sizeof(u_int32_t);
+ derived = 1;
+ } else {
+ ivoff = off + sizeof(struct newesp);
+ bodyoff = off + sizeof(struct newesp) + ivlen;
+ derived = 0;
+ }
}
- des_3cbc_process(m, bodyoff, plen, ks, (C_Block *)iv, DES_DECRYPT);
-
- /* for safety */
- bzero(ks[0], sizeof(des_key_schedule)*3);
- }
+ /* grab iv */
+ m_copydata(m, ivoff, ivlen, iv);
- /* for safety */
- bzero(&tiv[0], sizeof(tiv));
-
- return 0;
-}
-
-static int
-esp_3descbc_encrypt(m, off, plen, sav, algo, ivlen)
- struct mbuf *m;
- size_t off;
- size_t plen;
- struct secasvar *sav;
- struct esp_algorithm *algo;
- int ivlen;
-{
- size_t ivoff;
- size_t bodyoff;
- u_int8_t *iv;
-
- /* sanity check */
- if (plen % 8) {
- ipseclog((LOG_ERR, "esp_3descbc_encrypt: "
- "payload length must be multiple of 8\n"));
- return EINVAL;
- }
- if (sav->ivlen != ivlen) {
- ipseclog((LOG_ERR, "esp_3descbc_encrypt: bad ivlen %d/%d\n",
- ivlen, sav->ivlen));
- return EINVAL;
- }
- if (_KEYBITS(sav->key_enc) < algo->keymin
- || algo->keymax < _KEYBITS(sav->key_enc)) {
- ipseclog((LOG_ERR, "esp_3descbc_encrypt: bad keylen %d\n",
- _KEYBITS(sav->key_enc)));
+ /* extend iv */
+ if (ivlen == blocklen)
+ ;
+ else if (ivlen == 4 && blocklen == 8) {
+ bcopy(&iv[0], &iv[4], 4);
+ iv[4] ^= 0xff;
+ iv[5] ^= 0xff;
+ iv[6] ^= 0xff;
+ iv[7] ^= 0xff;
+ } else {
+ ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
+ "unsupported ivlen/blocklen: %d %d\n",
+ algo->name, ivlen, blocklen));
+ m_freem(m);
return EINVAL;
}
- if (sav->flags & SADB_X_EXT_OLD) {
- ipseclog((LOG_ERR,
- "esp_3descbc_encrypt: unsupported ESP version\n"));
+
+ if (m->m_pkthdr.len < bodyoff) {
+ ipseclog((LOG_ERR, "esp_cbc_decrypt %s: bad len %d/%lu\n",
+ algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
+ m_freem(m);
return EINVAL;
}
- if (ivlen != 8) {
- ipseclog((LOG_ERR,
- "esp_3descbc_encrypt: unsupported ivlen %d\n", ivlen));
+ if ((m->m_pkthdr.len - bodyoff) % blocklen) {
+ ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
+ "payload length must be multiple of %d\n",
+ algo->name, blocklen));
+ m_freem(m);
return EINVAL;
}
- ivoff = off + sizeof(struct newesp);
- bodyoff = off + sizeof(struct newesp) + ivlen;
+ s = m;
+ d = d0 = dp = NULL;
+ soff = doff = sn = dn = 0;
+ ivp = sp = NULL;
- if (m->m_pkthdr.len < bodyoff)
- panic("assumption failed: mbuf too short");
- iv = mbuf_find_offset(m, ivoff, ivlen);
- if (!iv)
- panic("assumption failed: bad mbuf chain");
-
- bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen);
-
- /* encrypt packet */
- {
- int deserr[3];
- des_key_schedule ks[3];
+ /* skip bodyoff */
+ while (soff < bodyoff) {
+ if (soff + s->m_len > bodyoff) {
+ sn = bodyoff - soff;
+ break;
+ }
- deserr[0] = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks[0]);
- deserr[1] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), ks[1]);
- deserr[2] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), ks[2]);
- if ((deserr[0] != 0) || (deserr[1] != 0) || (deserr[2] != 0)) {
- ipseclog((LOG_ERR, "esp_3descbc_encrypt: key error %d/%d/%d\n",
- deserr[0], deserr[1], deserr[2]));
- return EINVAL;
+ soff += s->m_len;
+ s = s->m_next;
}
+ scut = s;
+ scutoff = sn;
- des_3cbc_process(m, bodyoff, plen, ks, (C_Block *)iv, DES_ENCRYPT);
-
- /* for safety */
- bzero(ks[0], sizeof(des_key_schedule)*3);
- }
+ /* skip over empty mbuf */
+ while (s && s->m_len == 0)
+ s = s->m_next;
- esp_increment_iv(sav);
-
- return 0;
-}
+ while (soff < m->m_pkthdr.len) {
+ /* source */
+ if (sn + blocklen <= s->m_len) {
+ /* body is continuous */
+ sp = mtod(s, u_int8_t *) + sn;
+ } else {
+ /* body is non-continuous */
+ m_copydata(s, sn, blocklen, sbuf);
+ sp = sbuf;
+ }
-static int
-esp_rc5cbc_ivlen(sav)
- struct secasvar *sav;
-{
- return 8;
-}
+ /* destination */
+ if (!d || dn + blocklen > d->m_len) {
+ if (d)
+ dp = d;
+ MGET(d, M_DONTWAIT, MT_DATA);
+ i = m->m_pkthdr.len - (soff + sn);
+ if (d && i > MLEN) {
+ MCLGET(d, M_DONTWAIT);
+ if ((d->m_flags & M_EXT) == 0) {
+ m_free(d);
+ d = NULL;
+ }
+ }
+ if (!d) {
+ m_freem(m);
+ if (d0)
+ m_freem(d0);
+ return ENOBUFS;
+ }
+ if (!d0)
+ d0 = d;
+ if (dp)
+ dp->m_next = d;
+ d->m_len = 0;
+ d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
+ if (d->m_len > i)
+ d->m_len = i;
+ dn = 0;
+ }
-static int
-esp_rc5cbc_decrypt(m, off, sav, algo, ivlen)
- struct mbuf *m;
- size_t off;
- struct secasvar *sav;
- struct esp_algorithm *algo;
- int ivlen;
-{
- size_t ivoff;
- size_t bodyoff;
- u_int8_t iv[8];
- size_t plen;
- int error;
+ /* decrypt */
+ (*algo->blockdecrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);
- /* sanity check */
- if (sav->ivlen != ivlen) {
- ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: bad ivlen %d/%d\n",
- ivlen, sav->ivlen));
- return EINVAL;
- }
- if ((_KEYBITS(sav->key_enc) < 40) || (_KEYBITS(sav->key_enc) > 2040)) {
- ipseclog((LOG_ERR,
- "esp_rc5cbc_decrypt: unsupported key length %d: "
- "need 40 to 2040 bit\n", _KEYBITS(sav->key_enc)));
- return EINVAL;
- }
- if (sav->flags & SADB_X_EXT_OLD) {
- ipseclog((LOG_ERR,
- "esp_rc5cbc_decrypt: unsupported ESP version\n"));
- return EINVAL;
- }
- if (ivlen != 8) {
- ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: unsupported ivlen %d\n",
- ivlen));
- return EINVAL;
- }
+ /* xor */
+ p = ivp ? ivp : iv;
+ q = mtod(d, u_int8_t *) + dn;
+ for (i = 0; i < blocklen; i++)
+ q[i] ^= p[i];
- ivoff = off + sizeof(struct newesp);
- bodyoff = off + sizeof(struct newesp) + ivlen;
+ /* next iv */
+ if (sp == sbuf) {
+ bcopy(sbuf, iv, blocklen);
+ ivp = NULL;
+ } else
+ ivp = sp;
- /* copy mbuf's IV into iv */
- m_copydata(m, ivoff, 8, iv);
+ sn += blocklen;
+ dn += blocklen;
- plen = m->m_pkthdr.len;
- if (plen < bodyoff) {
- panic("esp_rc5cbc_decrypt: too short packet: len=%lu",
- (u_long)plen);
- }
- plen -= bodyoff;
+ /* find the next source block */
+ while (s && sn >= s->m_len) {
+ sn -= s->m_len;
+ soff += s->m_len;
+ s = s->m_next;
+ }
- if (plen % 8) {
- ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: "
- "payload length must be multiple of 8\n"));
- return EINVAL;
+ /* skip over empty mbuf */
+ while (s && s->m_len == 0)
+ s = s->m_next;
}
- /* decrypt */
- {
- RC5_WORD e_key[34];
+ m_freem(scut->m_next);
+ scut->m_len = scutoff;
+ scut->m_next = d0;
- set_rc5_expandkey(e_key, _KEYBUF(sav->key_enc),
- _KEYBITS(sav->key_enc) / 8, 16);
- error = rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_DECRYPT);
+ /* just in case */
+ bzero(iv, sizeof(iv));
+ bzero(sbuf, sizeof(sbuf));
- /* for safety */
- bzero(e_key, sizeof(e_key));
- }
-
- return error;
+ return 0;
}
static int
-esp_rc5cbc_encrypt(m, off, plen, sav, algo, ivlen)
+esp_cbc_encrypt(m, off, plen, sav, algo, ivlen)
struct mbuf *m;
size_t off;
size_t plen;
struct secasvar *sav;
- struct esp_algorithm *algo;
+ const struct esp_algorithm *algo;
int ivlen;
{
- size_t ivoff;
- size_t bodyoff;
- u_int8_t *iv;
- int error;
+ struct mbuf *s;
+ struct mbuf *d, *d0, *dp;
+ int soff, doff; /*offset from the head of chain, to head of this mbuf */
+ int sn, dn; /*offset from the head of the mbuf, to meat */
+ size_t ivoff, bodyoff;
+ u_int8_t iv[MAXIVLEN], *ivp;
+ u_int8_t sbuf[MAXIVLEN], *sp;
+ u_int8_t *p, *q;
+ struct mbuf *scut;
+ int scutoff;
+ int i;
+ int blocklen;
+ int derived;
- /* sanity check */
- if (plen % 8) {
- ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: "
- "payload length must be multiple of 8\n"));
+ if (ivlen != sav->ivlen || ivlen > sizeof(iv)) {
+ ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
+ "unsupported ivlen %d\n", algo->name, ivlen));
+ m_freem(m);
return EINVAL;
}
- if (sav->ivlen != ivlen) {
- ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: bad ivlen %d/%d\n",
- ivlen, sav->ivlen));
+
+ /* assumes blocklen == padbound */
+ blocklen = algo->padbound;
+
+#ifdef DIAGNOSTIC
+ if (blocklen > sizeof(iv)) {
+ ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
+ "unsupported blocklen %d\n", algo->name, blocklen));
+ m_freem(m);
return EINVAL;
}
- if (_KEYBITS(sav->key_enc) < algo->keymin
- || _KEYBITS(sav->key_enc) > algo->keymax) {
- ipseclog((LOG_ERR,
- "esp_rc5cbc_encrypt: unsupported key length %d: "
- "need %d to %d bits\n", _KEYBITS(sav->key_enc),
- algo->keymin, algo->keymax));
+#endif
+
+ if (sav->flags & SADB_X_EXT_OLD) {
+ /* RFC 1827 */
+ ivoff = off + sizeof(struct esp);
+ bodyoff = off + sizeof(struct esp) + ivlen;
+ derived = 0;
+ } else {
+ /* RFC 2406 */
+ if (sav->flags & SADB_X_EXT_DERIV) {
+ /*
+ * draft-ietf-ipsec-ciph-des-derived-00.txt
+ * uses sequence number field as IV field.
+ */
+ ivoff = off + sizeof(struct esp);
+ bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);
+ ivlen = sizeof(u_int32_t);
+ derived = 1;
+ } else {
+ ivoff = off + sizeof(struct newesp);
+ bodyoff = off + sizeof(struct newesp) + ivlen;
+ derived = 0;
+ }
+ }
+
+ /* put iv into the packet. if we are in derived mode, use seqno. */
+ if (derived)
+ m_copydata(m, ivoff, ivlen, iv);
+ else {
+ bcopy(sav->iv, iv, ivlen);
+ /* maybe it is better to overwrite dest, not source */
+ m_copyback(m, ivoff, ivlen, iv);
+ }
+
+ /* extend iv */
+ if (ivlen == blocklen)
+ ;
+ else if (ivlen == 4 && blocklen == 8) {
+ bcopy(&iv[0], &iv[4], 4);
+ iv[4] ^= 0xff;
+ iv[5] ^= 0xff;
+ iv[6] ^= 0xff;
+ iv[7] ^= 0xff;
+ } else {
+ ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
+ "unsupported ivlen/blocklen: %d %d\n",
+ algo->name, ivlen, blocklen));
+ m_freem(m);
return EINVAL;
}
- if (sav->flags & SADB_X_EXT_OLD) {
- ipseclog((LOG_ERR,
- "esp_rc5cbc_encrypt: unsupported ESP version\n"));
+
+ if (m->m_pkthdr.len < bodyoff) {
+ ipseclog((LOG_ERR, "esp_cbc_encrypt %s: bad len %d/%lu\n",
+ algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
+ m_freem(m);
return EINVAL;
}
- if (ivlen != 8) {
- ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: unsupported ivlen %d\n",
- ivlen));
+ if ((m->m_pkthdr.len - bodyoff) % blocklen) {
+ ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
+ "payload length must be multiple of %lu\n",
+ algo->name, (unsigned long)algo->padbound));
+ m_freem(m);
return EINVAL;
}
- ivoff = off + sizeof(struct newesp);
- bodyoff = off + sizeof(struct newesp) + ivlen;
+ s = m;
+ d = d0 = dp = NULL;
+ soff = doff = sn = dn = 0;
+ ivp = sp = NULL;
- if (m->m_pkthdr.len < bodyoff)
- panic("assumption failed: mbuf too short");
- iv = mbuf_find_offset(m, ivoff, ivlen);
- if (!iv)
- panic("assumption failed: bad mbuf chain");
+ /* skip bodyoff */
+ while (soff < bodyoff) {
+ if (soff + s->m_len > bodyoff) {
+ sn = bodyoff - soff;
+ break;
+ }
- bcopy(sav->iv, iv, ivlen);
+ soff += s->m_len;
+ s = s->m_next;
+ }
+ scut = s;
+ scutoff = sn;
- /* encrypt */
- {
- RC5_WORD e_key[34];
+ /* skip over empty mbuf */
+ while (s && s->m_len == 0)
+ s = s->m_next;
- set_rc5_expandkey(e_key, _KEYBUF(sav->key_enc),
- _KEYBITS(sav->key_enc) / 8, 16);
- error = rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_ENCRYPT);
+ while (soff < m->m_pkthdr.len) {
+ /* source */
+ if (sn + blocklen <= s->m_len) {
+ /* body is continuous */
+ sp = mtod(s, u_int8_t *) + sn;
+ } else {
+ /* body is non-continuous */
+ m_copydata(s, sn, blocklen, sbuf);
+ sp = sbuf;
+ }
- /* for safety */
- bzero(e_key, sizeof(e_key));
- }
+ /* destination */
+ if (!d || dn + blocklen > d->m_len) {
+ if (d)
+ dp = d;
+ MGET(d, M_DONTWAIT, MT_DATA);
+ i = m->m_pkthdr.len - (soff + sn);
+ if (d && i > MLEN) {
+ MCLGET(d, M_DONTWAIT);
+ if ((d->m_flags & M_EXT) == 0) {
+ m_free(d);
+ d = NULL;
+ }
+ }
+ if (!d) {
+ m_freem(m);
+ if (d0)
+ m_freem(d0);
+ return ENOBUFS;
+ }
+ if (!d0)
+ d0 = d;
+ if (dp)
+ dp->m_next = d;
+ d->m_len = 0;
+ d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
+ if (d->m_len > i)
+ d->m_len = i;
+ dn = 0;
+ }
- esp_increment_iv(sav);
+ /* xor */
+ p = ivp ? ivp : iv;
+ q = sp;
+ for (i = 0; i < blocklen; i++)
+ q[i] ^= p[i];
- return error;
-}
+ /* encrypt */
+ (*algo->blockencrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);
-/*
- * increment iv.
- */
-static void
-esp_increment_iv(sav)
- struct secasvar *sav;
-{
- u_int8_t *x;
- u_int8_t y;
- int i;
+ /* next iv */
+ ivp = mtod(d, u_int8_t *) + dn;
-#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
- y = time.tv_sec & 0xff;
-#else
- y = time_second & 0xff;
-#endif
- if (!y) y++;
- x = (u_int8_t *)sav->iv;
- for (i = 0; i < sav->ivlen; i++) {
- *x = (*x + y) & 0xff;
- x++;
- }
-}
+ sn += blocklen;
+ dn += blocklen;
-static caddr_t
-mbuf_find_offset(m, off, len)
- struct mbuf *m;
- size_t off;
- size_t len;
-{
- struct mbuf *n;
- size_t cnt;
-
- if (m->m_pkthdr.len < off || m->m_pkthdr.len < off + len)
- return (caddr_t)NULL;
- cnt = 0;
- for (n = m; n; n = n->m_next) {
- if (cnt + n->m_len <= off) {
- cnt += n->m_len;
- continue;
+ /* find the next source block */
+ while (s && sn >= s->m_len) {
+ sn -= s->m_len;
+ soff += s->m_len;
+ s = s->m_next;
}
- if (cnt <= off && off < cnt + n->m_len
- && cnt <= off + len && off + len <= cnt + n->m_len) {
- return mtod(n, caddr_t) + off - cnt;
- } else
- return (caddr_t)NULL;
+
+ /* skip over empty mbuf */
+ while (s && s->m_len == 0)
+ s = s->m_next;
}
- return (caddr_t)NULL;
+
+ m_freem(scut->m_next);
+ scut->m_len = scutoff;
+ scut->m_next = d0;
+
+ /* just in case */
+ bzero(iv, sizeof(iv));
+ bzero(sbuf, sizeof(sbuf));
+
+ key_sa_stir_iv(sav);
+
+ return 0;
}
/*------------------------------------------------------------*/
@@ -1207,7 +1052,7 @@ esp_auth(m0, skip, length, sav, sum)
size_t off;
struct ah_algorithm_state s;
u_char sumbuf[AH_MAXSUMSIZE];
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
size_t siz;
int error;
@@ -1233,7 +1078,8 @@ esp_auth(m0, skip, length, sav, sum)
ipseclog((LOG_DEBUG, "esp_auth: NULL SA passed\n"));
return EINVAL;
}
- if (!sav->alg_auth) {
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
ipseclog((LOG_ERR,
"esp_auth: bad ESP auth algorithm passed: %d\n",
sav->alg_auth));
@@ -1243,7 +1089,6 @@ esp_auth(m0, skip, length, sav, sum)
m = m0;
off = 0;
- algo = &ah_algorithms[sav->alg_auth];
siz = (((*algo->sumsiz)(sav) + 3) & ~(4 - 1));
if (sizeof(sumbuf) < siz) {
ipseclog((LOG_DEBUG,
diff --git a/sys/netinet6/esp_input.c b/sys/netinet6/esp_input.c
index 4d4344b..4542f13 100644
--- a/sys/netinet6/esp_input.c
+++ b/sys/netinet6/esp_input.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: esp_input.c,v 1.25 2000/05/08 08:04:30 itojun Exp $ */
+/* $KAME: esp_input.c,v 1.55 2001/03/23 08:08:47 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -64,8 +64,10 @@
#ifdef INET6
#include <netinet/ip6.h>
+#include <netinet6/in6_pcb.h>
#include <netinet6/ip6_var.h>
#include <netinet/icmp6.h>
+#include <netinet6/ip6protosw.h>
#endif
#include <netinet6/ipsec.h>
@@ -82,11 +84,7 @@
#endif
#include <netkey/key.h>
#include <netkey/keydb.h>
-#ifdef IPSEC_DEBUG
#include <netkey/key_debug.h>
-#else
-#define KEYDEBUG(lev,arg)
-#endif
#include <machine/stdarg.h>
@@ -94,14 +92,14 @@
#define IPLEN_FLIPPED
-#ifdef INET
-#include <netinet/ipprotosw.h>
-extern struct ipprotosw inetsw[];
-
#define ESPMAXLEN \
(sizeof(struct esp) < sizeof(struct newesp) \
? sizeof(struct newesp) : sizeof(struct esp))
+#ifdef INET
+#include <netinet/ipprotosw.h>
+extern struct ipprotosw inetsw[];
+
void
#if __STDC__
esp4_input(struct mbuf *m, ...)
@@ -118,7 +116,7 @@ esp4_input(m, va_alist)
struct secasvar *sav = NULL;
size_t taillen;
u_int16_t nxt;
- struct esp_algorithm *algo;
+ const struct esp_algorithm *algo;
int ivlen;
size_t hlen;
size_t esplen;
@@ -178,16 +176,15 @@ esp4_input(m, va_alist)
ipsecstat.in_badspi++;
goto bad;
}
- if (sav->alg_enc == SADB_EALG_NONE) {
+ algo = esp_algorithm_lookup(sav->alg_enc);
+ if (!algo) {
ipseclog((LOG_DEBUG, "IPv4 ESP input: "
- "unspecified encryption algorithm for spi %u\n",
+ "unsupported encryption algorithm for spi %u\n",
(u_int32_t)ntohl(spi)));
ipsecstat.in_badspi++;
goto bad;
}
- algo = &esp_algorithms[sav->alg_enc]; /*XXX*/
-
/* check if we have proper ivlen information */
ivlen = sav->ivlen;
if (ivlen < 0) {
@@ -201,7 +198,8 @@ esp4_input(m, va_alist)
&& (sav->alg_auth && sav->key_auth)))
goto noreplaycheck;
- if (sav->alg_auth == SADB_AALG_NULL)
+ if (sav->alg_auth == SADB_X_AALG_NULL ||
+ sav->alg_auth == SADB_AALG_NONE)
goto noreplaycheck;
/*
@@ -221,10 +219,12 @@ esp4_input(m, va_alist)
{
u_char sum0[AH_MAXSUMSIZE];
u_char sum[AH_MAXSUMSIZE];
- struct ah_algorithm *sumalgo;
+ const struct ah_algorithm *sumalgo;
size_t siz;
- sumalgo = &ah_algorithms[sav->alg_auth];
+ sumalgo = ah_algorithm_lookup(sav->alg_auth);
+ if (!sumalgo)
+ goto noreplaycheck;
siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1));
if (AH_MAXSUMSIZE < siz) {
ipseclog((LOG_DEBUG,
@@ -303,22 +303,30 @@ noreplaycheck:
}
}
- {
+ /*
+ * pre-compute and cache intermediate key
+ */
+ if (esp_schedule(algo, sav) != 0) {
+ ipsecstat.in_inval++;
+ goto bad;
+ }
+
/*
* decrypt the packet.
*/
if (!algo->decrypt)
panic("internal error: no decrypt function");
if ((*algo->decrypt)(m, off, sav, algo, ivlen)) {
- ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s %s\n",
- ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
+ /* m is already freed */
+ m = NULL;
+ ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s\n",
+ ipsec_logsastr(sav)));
ipsecstat.in_inval++;
goto bad;
}
ipsecstat.in_esphist[sav->alg_enc]++;
m->m_flags |= M_DECRYPTED;
- }
/*
* find the trailer of the ESP.
@@ -347,7 +355,7 @@ noreplaycheck:
#endif
/* was it transmitted over the IPsec tunnel SA? */
- if (ipsec4_tunnel_validate(ip, nxt, sav)) {
+ if (ipsec4_tunnel_validate(m, off + esplen + ivlen, nxt, sav)) {
/*
* strip off all the headers that precedes ESP header.
* IP4 xx ESP IP4' payload -> IP4' payload
@@ -387,6 +395,11 @@ noreplaycheck:
#endif
key_sa_recordxfer(sav, m);
+ if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 ||
+ ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
+ ipsecstat.in_nomem++;
+ goto bad;
+ }
if (! IF_HANDOFF(&ipintrq, m, NULL)) {
ipsecstat.in_inval++;
@@ -421,10 +434,19 @@ noreplaycheck:
ip->ip_p = nxt;
key_sa_recordxfer(sav, m);
+ if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) {
+ ipsecstat.in_nomem++;
+ goto bad;
+ }
- if (nxt != IPPROTO_DONE)
+ if (nxt != IPPROTO_DONE) {
+ if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
+ ipsec4_in_reject(m, NULL)) {
+ ipsecstat.in_polvio++;
+ goto bad;
+ }
(*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
- else
+ } else
m_freem(m);
m = NULL;
}
@@ -464,10 +486,9 @@ esp6_input(mp, offp, proto)
struct secasvar *sav = NULL;
size_t taillen;
u_int16_t nxt;
- struct esp_algorithm *algo;
+ const struct esp_algorithm *algo;
int ivlen;
size_t esplen;
- int s;
/* sanity check for alignment. */
if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) {
@@ -518,16 +539,15 @@ esp6_input(mp, offp, proto)
ipsec6stat.in_badspi++;
goto bad;
}
- if (sav->alg_enc == SADB_EALG_NONE) {
+ algo = esp_algorithm_lookup(sav->alg_enc);
+ if (!algo) {
ipseclog((LOG_DEBUG, "IPv6 ESP input: "
- "unspecified encryption algorithm for spi %u\n",
+ "unsupported encryption algorithm for spi %u\n",
(u_int32_t)ntohl(spi)));
ipsec6stat.in_badspi++;
goto bad;
}
- algo = &esp_algorithms[sav->alg_enc]; /*XXX*/
-
/* check if we have proper ivlen information */
ivlen = sav->ivlen;
if (ivlen < 0) {
@@ -541,7 +561,8 @@ esp6_input(mp, offp, proto)
&& (sav->alg_auth && sav->key_auth)))
goto noreplaycheck;
- if (sav->alg_auth == SADB_AALG_NULL)
+ if (sav->alg_auth == SADB_X_AALG_NULL ||
+ sav->alg_auth == SADB_AALG_NONE)
goto noreplaycheck;
/*
@@ -561,10 +582,12 @@ esp6_input(mp, offp, proto)
{
u_char sum0[AH_MAXSUMSIZE];
u_char sum[AH_MAXSUMSIZE];
- struct ah_algorithm *sumalgo;
+ const struct ah_algorithm *sumalgo;
size_t siz;
- sumalgo = &ah_algorithms[sav->alg_auth];
+ sumalgo = ah_algorithm_lookup(sav->alg_auth);
+ if (!sumalgo)
+ goto noreplaycheck;
siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1));
if (AH_MAXSUMSIZE < siz) {
ipseclog((LOG_DEBUG,
@@ -643,13 +666,23 @@ noreplaycheck:
ip6 = mtod(m, struct ip6_hdr *); /*set it again just in case*/
/*
+ * pre-compute and cache intermediate key
+ */
+ if (esp_schedule(algo, sav) != 0) {
+ ipsec6stat.in_inval++;
+ goto bad;
+ }
+
+ /*
* decrypt the packet.
*/
if (!algo->decrypt)
panic("internal error: no decrypt function");
if ((*algo->decrypt)(m, off, sav, algo, ivlen)) {
- ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s %s\n",
- ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
+ /* m is already freed */
+ m = NULL;
+ ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s\n",
+ ipsec_logsastr(sav)));
ipsec6stat.in_inval++;
goto bad;
}
@@ -680,7 +713,7 @@ noreplaycheck:
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - taillen);
/* was it transmitted over the IPsec tunnel SA? */
- if (ipsec6_tunnel_validate(ip6, nxt, sav)) {
+ if (ipsec6_tunnel_validate(m, off + esplen + ivlen, nxt, sav)) {
/*
* strip off all the headers that precedes ESP header.
* IP6 xx ESP IP6' payload -> IP6' payload
@@ -728,6 +761,11 @@ noreplaycheck:
#endif
key_sa_recordxfer(sav, m);
+ if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 ||
+ ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
+ ipsec6stat.in_nomem++;
+ goto bad;
+ }
if (! IF_HANDOFF(&ip6intrq, m, NULL)) {
ipsec6stat.in_inval++;
@@ -778,10 +816,60 @@ noreplaycheck:
m->m_pkthdr.len += n->m_pkthdr.len;
}
+#ifndef PULLDOWN_TEST
+ /*
+ * KAME requires that the packet to be contiguous on the
+ * mbuf. We need to make that sure.
+ * this kind of code should be avoided.
+ * XXX other conditions to avoid running this part?
+ */
+ if (m->m_len != m->m_pkthdr.len) {
+ struct mbuf *n = NULL;
+ int maxlen;
+
+ MGETHDR(n, M_DONTWAIT, MT_HEADER);
+ maxlen = MHLEN;
+ if (n)
+ M_COPY_PKTHDR(n, m);
+ if (n && m->m_pkthdr.len > maxlen) {
+ MCLGET(n, M_DONTWAIT);
+ maxlen = MCLBYTES;
+ if ((n->m_flags & M_EXT) == 0) {
+ m_free(n);
+ n = NULL;
+ }
+ }
+ if (!n) {
+ printf("esp6_input: mbuf allocation failed\n");
+ goto bad;
+ }
+
+ if (m->m_pkthdr.len <= maxlen) {
+ m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t));
+ n->m_len = m->m_pkthdr.len;
+ n->m_pkthdr.len = m->m_pkthdr.len;
+ n->m_next = NULL;
+ m_freem(m);
+ } else {
+ m_copydata(m, 0, maxlen, mtod(n, caddr_t));
+ m_adj(m, maxlen);
+ n->m_len = maxlen;
+ n->m_pkthdr.len = m->m_pkthdr.len;
+ n->m_next = m;
+ m->m_flags &= ~M_PKTHDR;
+ }
+ m = n;
+ }
+#endif
+
ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
key_sa_recordxfer(sav, m);
+ if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) {
+ ipsec6stat.in_nomem++;
+ goto bad;
+ }
}
*offp = off;
@@ -805,4 +893,108 @@ bad:
m_freem(m);
return IPPROTO_DONE;
}
+
+void
+esp6_ctlinput(cmd, sa, d)
+ int cmd;
+ struct sockaddr *sa;
+ void *d;
+{
+ const struct newesp *espp;
+ struct newesp esp;
+ struct ip6ctlparam *ip6cp = NULL, ip6cp1;
+ struct secasvar *sav;
+ struct ip6_hdr *ip6;
+ struct mbuf *m;
+ int off;
+ struct sockaddr_in6 sa6_src, sa6_dst;
+
+ if (sa->sa_family != AF_INET6 ||
+ sa->sa_len != sizeof(struct sockaddr_in6))
+ return;
+ if ((unsigned)cmd >= PRC_NCMDS)
+ return;
+
+ /* if the parameter is from icmp6, decode it. */
+ if (d != NULL) {
+ ip6cp = (struct ip6ctlparam *)d;
+ m = ip6cp->ip6c_m;
+ ip6 = ip6cp->ip6c_ip6;
+ off = ip6cp->ip6c_off;
+ } else {
+ m = NULL;
+ ip6 = NULL;
+ }
+
+ if (ip6) {
+ /*
+ * Notify the error to all possible sockets via pfctlinput2.
+ * Since the upper layer information (such as protocol type,
+ * source and destination ports) is embedded in the encrypted
+ * data and might have been cut, we can't directly call
+ * an upper layer ctlinput function. However, the pcbnotify
+ * function will consider source and destination addresses
+ * as well as the flow info value, and may be able to find
+ * some PCB that should be notified.
+ * Although pfctlinput2 will call esp6_ctlinput(), there is
+ * no possibility of an infinite loop of function calls,
+ * because we don't pass the inner IPv6 header.
+ */
+ bzero(&ip6cp1, sizeof(ip6cp1));
+ ip6cp1.ip6c_src = ip6cp->ip6c_src;
+ pfctlinput2(cmd, sa, (void *)&ip6cp1);
+
+ /*
+ * Then go to special cases that need ESP header information.
+ * XXX: We assume that when ip6 is non NULL,
+ * M and OFF are valid.
+ */
+
+ /* check if we can safely examine src and dst ports */
+ if (m->m_pkthdr.len < off + sizeof(esp))
+ return;
+
+ if (m->m_len < off + sizeof(esp)) {
+ /*
+ * this should be rare case,
+ * so we compromise on this copy...
+ */
+ m_copydata(m, off, sizeof(esp), (caddr_t)&esp);
+ espp = &esp;
+ } else
+ espp = (struct newesp*)(mtod(m, caddr_t) + off);
+
+ if (cmd == PRC_MSGSIZE) {
+ int valid = 0;
+
+ /*
+ * Check to see if we have a valid SA corresponding to
+ * the address in the ICMP message payload.
+ */
+ sav = key_allocsa(AF_INET6,
+ (caddr_t)&sa6_src.sin6_addr,
+ (caddr_t)&sa6_dst, IPPROTO_ESP,
+ espp->esp_spi);
+ if (sav) {
+ if (sav->state == SADB_SASTATE_MATURE ||
+ sav->state == SADB_SASTATE_DYING)
+ valid++;
+ key_freesav(sav);
+ }
+
+ /* XXX Further validation? */
+
+ /*
+ * Depending on the value of "valid" and routing table
+ * size (mtudisc_{hi,lo}wat), we will:
+ * - recalcurate the new MTU and create the
+ * corresponding routing entry, or
+ * - ignore the MTU change notification.
+ */
+ icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
+ }
+ } else {
+ /* we normally notify any pcb here */
+ }
+}
#endif /* INET6 */
diff --git a/sys/netinet6/esp_output.c b/sys/netinet6/esp_output.c
index 8d505ae..7770b78 100644
--- a/sys/netinet6/esp_output.c
+++ b/sys/netinet6/esp_output.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: esp_output.c,v 1.22 2000/07/03 13:23:28 itojun Exp $ */
+/* $KAME: esp_output.c,v 1.43 2001/03/01 07:10:45 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -90,7 +90,8 @@ esp_hdrsiz(isr)
struct ipsecrequest *isr;
{
struct secasvar *sav;
- struct esp_algorithm *algo;
+ const struct esp_algorithm *algo;
+ const struct ah_algorithm *aalgo;
size_t ivlen;
size_t authlen;
size_t hdrsiz;
@@ -111,7 +112,7 @@ esp_hdrsiz(isr)
goto estimate;
/* we need transport mode ESP. */
- algo = &esp_algorithms[sav->alg_enc];
+ algo = esp_algorithm_lookup(sav->alg_enc);
if (!algo)
goto estimate;
ivlen = sav->ivlen;
@@ -130,8 +131,9 @@ esp_hdrsiz(isr)
hdrsiz = sizeof(struct esp) + ivlen + 9;
} else {
/* RFC 2406 */
- if (sav->replay && sav->alg_auth && sav->key_auth)
- authlen = (*ah_algorithms[sav->alg_auth].sumsiz)(sav);
+ aalgo = ah_algorithm_lookup(sav->alg_auth);
+ if (aalgo && sav->replay && sav->key_auth)
+ authlen = (aalgo->sumsiz)(sav);
else
authlen = 0;
hdrsiz = sizeof(struct newesp) + ivlen + 9 + authlen;
@@ -143,12 +145,12 @@ esp_hdrsiz(isr)
/*
* ASSUMING:
* sizeof(struct newesp) > sizeof(struct esp).
- * 8 = ivlen for CBC mode (RFC2451).
+ * esp_max_ivlen() = max ivlen for CBC mode
* 9 = (maximum padding length without random padding length)
* + (Pad Length field) + (Next Header field).
* 16 = maximum ICV we support.
*/
- return sizeof(struct newesp) + 8 + 9 + 16;
+ return sizeof(struct newesp) + esp_max_ivlen() + 9 + 16;
}
/*
@@ -184,7 +186,7 @@ esp_output(m, nexthdrp, md, isr, af)
struct esp *esp;
struct esptail *esptail;
struct secasvar *sav = isr->sav;
- struct esp_algorithm *algo;
+ const struct esp_algorithm *algo;
u_int32_t spi;
u_int8_t nxt = 0;
size_t plen; /*payload length to be encrypted*/
@@ -193,16 +195,19 @@ esp_output(m, nexthdrp, md, isr, af)
int afnumber;
size_t extendsiz;
int error = 0;
+ struct ipsecstat *stat;
switch (af) {
#ifdef INET
case AF_INET:
afnumber = 4;
+ stat = &ipsecstat;
break;
#endif
#ifdef INET6
case AF_INET6:
afnumber = 6;
+ stat = &ipsec6stat;
break;
#endif
default:
@@ -225,28 +230,31 @@ esp_output(m, nexthdrp, md, isr, af)
(u_int32_t)ntohl(ip->ip_dst.s_addr),
(u_int32_t)ntohl(sav->spi)));
ipsecstat.out_inval++;
- m_freem(m);
- return EINVAL;
+ break;
}
#endif /*INET*/
#ifdef INET6
case AF_INET6:
- {
- struct ip6_hdr *ip6;
-
- ip6 = mtod(m, struct ip6_hdr *);
ipseclog((LOG_DEBUG, "esp6_output: internal error: "
"sav->replay is null: SPI=%u\n",
(u_int32_t)ntohl(sav->spi)));
ipsec6stat.out_inval++;
- m_freem(m);
- return EINVAL;
- }
+ break;
#endif /*INET6*/
+ default:
+ panic("esp_output: should not reach here");
}
+ m_freem(m);
+ return EINVAL;
}
- algo = &esp_algorithms[sav->alg_enc]; /*XXX*/
+ algo = esp_algorithm_lookup(sav->alg_enc);
+ if (!algo) {
+ ipseclog((LOG_ERR, "esp_output: unsupported algorithm: "
+ "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
+ m_freem(m);
+ return EINVAL;
+ }
spi = sav->spi;
ivlen = sav->ivlen;
/* should be okey */
@@ -331,7 +339,7 @@ esp_output(m, nexthdrp, md, isr, af)
* before: IP ... payload
* after: IP ... ESP IV payload
*/
- if (M_LEADINGSPACE(md) < esphlen) {
+ if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) {
MGET(n, M_DONTWAIT, MT_DATA);
if (!n) {
m_freem(m);
@@ -386,7 +394,7 @@ esp_output(m, nexthdrp, md, isr, af)
ipseclog((LOG_WARNING,
"replay counter overflowed. %s\n",
ipsec_logsastr(sav)));
- ipsecstat.out_inval++;
+ stat->out_inval++;
m_freem(m);
return EINVAL;
}
@@ -402,7 +410,6 @@ esp_output(m, nexthdrp, md, isr, af)
{
/*
* find the last mbuf. make some room for ESP trailer.
- * XXX new-esp authentication data
*/
#ifdef INET
struct ip *ip = NULL;
@@ -410,6 +417,7 @@ esp_output(m, nexthdrp, md, isr, af)
size_t padbound;
u_char *extend;
int i;
+ int randpadmax;
if (algo->padbound)
padbound = algo->padbound;
@@ -423,13 +431,62 @@ esp_output(m, nexthdrp, md, isr, af)
if (extendsiz == 1)
extendsiz = padbound + 1;
+ /* random padding */
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ randpadmax = ip4_esp_randpad;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ randpadmax = ip6_esp_randpad;
+ break;
+#endif
+ default:
+ randpadmax = -1;
+ break;
+ }
+ if (randpadmax < 0 || plen + extendsiz >= randpadmax)
+ ;
+ else {
+ int n;
+
+ /* round */
+ randpadmax = (randpadmax / padbound) * padbound;
+ n = (randpadmax - plen + extendsiz) / padbound;
+
+ if (n > 0)
+ n = (random() % n) * padbound;
+ else
+ n = 0;
+
+ /*
+ * make sure we do not pad too much.
+ * MLEN limitation comes from the trailer attachment
+ * code below.
+ * 256 limitation comes from sequential padding.
+ * also, the 1-octet length field in ESP trailer imposes
+ * limitation (but is less strict than sequential padding
+ * as length field do not count the last 2 octets).
+ */
+ if (extendsiz + n <= MLEN && extendsiz + n < 256)
+ extendsiz += n;
+ }
+
+#ifdef DIAGNOSTIC
+ if (extendsiz > MLEN || extendsiz >= 256)
+ panic("extendsiz too big in esp_output");
+#endif
+
n = m;
while (n->m_next)
n = n->m_next;
/*
- * if M_EXT, the external part may be shared among
- * two consequtive TCP packets.
+ * if M_EXT, the external mbuf data may be shared among
+ * two consequtive TCP packets, and it may be unsafe to use the
+ * trailing space.
*/
if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) {
extend = mtod(n, u_char *) + n->m_len;
@@ -455,8 +512,7 @@ esp_output(m, nexthdrp, md, isr, af)
}
switch (sav->flags & SADB_X_EXT_PMASK) {
case SADB_X_EXT_PRAND:
- for (i = 0; i < extendsiz; i++)
- extend[i] = random() & 0xff;
+ key_randomfill(extend, extendsiz);
break;
case SADB_X_EXT_PZERO:
bzero(extend, extendsiz);
@@ -499,26 +555,25 @@ esp_output(m, nexthdrp, md, isr, af)
}
/*
+ * pre-compute and cache intermediate key
+ */
+ error = esp_schedule(algo, sav);
+ if (error) {
+ m_freem(m);
+ stat->out_inval++;
+ goto fail;
+ }
+
+ /*
* encrypt the packet, based on security association
* and the algorithm specified.
*/
if (!algo->encrypt)
panic("internal error: no encrypt function");
if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) {
+ /* m is already freed */
ipseclog((LOG_ERR, "packet encryption failure\n"));
- m_freem(m);
- switch (af) {
-#ifdef INET
- case AF_INET:
- ipsecstat.out_inval++;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- ipsec6stat.out_inval++;
- break;
-#endif
- }
+ stat->out_inval++;
error = EINVAL;
goto fail;
}
@@ -530,16 +585,23 @@ esp_output(m, nexthdrp, md, isr, af)
goto noantireplay;
if (!sav->key_auth)
goto noantireplay;
- if (!sav->alg_auth)
+ if (sav->key_auth == SADB_AALG_NONE)
goto noantireplay;
+
{
+ const struct ah_algorithm *aalgo;
u_char authbuf[AH_MAXSUMSIZE];
struct mbuf *n;
u_char *p;
size_t siz;
+#ifdef INET
struct ip *ip;
+#endif
- siz = (((*ah_algorithms[sav->alg_auth].sumsiz)(sav) + 3) & ~(4 - 1));
+ aalgo = ah_algorithm_lookup(sav->alg_auth);
+ if (!aalgo)
+ goto noantireplay;
+ siz = ((aalgo->sumsiz)(sav) + 3) & ~(4 - 1);
if (AH_MAXSUMSIZE < siz)
panic("assertion failed for AH_MAXSUMSIZE");
@@ -547,18 +609,7 @@ esp_output(m, nexthdrp, md, isr, af)
ipseclog((LOG_ERR, "ESP checksum generation failure\n"));
m_freem(m);
error = EINVAL;
- switch (af) {
-#ifdef INET
- case AF_INET:
- ipsecstat.out_inval++;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- ipsec6stat.out_inval++;
- break;
-#endif
- }
+ stat->out_inval++;
goto fail;
}
@@ -619,32 +670,9 @@ noantireplay:
if (!m) {
ipseclog((LOG_ERR,
"NULL mbuf after encryption in esp%d_output", afnumber));
- } else {
- switch (af) {
-#ifdef INET
- case AF_INET:
- ipsecstat.out_success++;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- ipsec6stat.out_success++;
- break;
-#endif
- }
- }
- switch (af) {
-#ifdef INET
- case AF_INET:
- ipsecstat.out_esphist[sav->alg_enc]++;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- ipsec6stat.out_esphist[sav->alg_enc]++;
- break;
-#endif
- }
+ } else
+ stat->out_success++;
+ stat->out_esphist[sav->alg_enc]++;
key_sa_recordxfer(sav, m);
return 0;
diff --git a/sys/netinet6/esp_rijndael.c b/sys/netinet6/esp_rijndael.c
new file mode 100644
index 0000000..5b0e5fa
--- /dev/null
+++ b/sys/netinet6/esp_rijndael.c
@@ -0,0 +1,116 @@
+/* $FreeBSD$ */
+/* $KAME: esp_rijndael.c,v 1.4 2001/03/02 05:53:05 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 "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet6/ipsec.h>
+#include <netinet6/esp.h>
+#include <netinet6/esp_rijndael.h>
+
+#include <crypto/rijndael/rijndael.h>
+
+#include <net/net_osdep.h>
+
+/* as rijndael uses assymetric scheduled keys, we need to do it twice. */
+int
+esp_rijndael_schedlen(algo)
+ const struct esp_algorithm *algo;
+{
+
+ return sizeof(keyInstance) * 2;
+}
+
+int
+esp_rijndael_schedule(algo, sav)
+ const struct esp_algorithm *algo;
+ struct secasvar *sav;
+{
+ keyInstance *k;
+
+ k = (keyInstance *)sav->sched;
+ if (rijndael_makeKey(&k[0], DIR_DECRYPT, _KEYLEN(sav->key_enc) * 8,
+ _KEYBUF(sav->key_enc)) < 0)
+ return -1;
+ if (rijndael_makeKey(&k[1], DIR_ENCRYPT, _KEYLEN(sav->key_enc) * 8,
+ _KEYBUF(sav->key_enc)) < 0)
+ return -1;
+ return 0;
+}
+
+int
+esp_rijndael_blockdecrypt(algo, sav, s, d)
+ const struct esp_algorithm *algo;
+ struct secasvar *sav;
+ u_int8_t *s;
+ u_int8_t *d;
+{
+ cipherInstance c;
+ keyInstance *p;
+
+ /* does not take advantage of CBC mode support */
+ bzero(&c, sizeof(c));
+ if (rijndael_cipherInit(&c, MODE_ECB, NULL) < 0)
+ return -1;
+ p = (keyInstance *)sav->sched;
+ if (rijndael_blockDecrypt(&c, &p[0], s, algo->padbound * 8, d) < 0)
+ return -1;
+ return 0;
+}
+
+int
+esp_rijndael_blockencrypt(algo, sav, s, d)
+ const struct esp_algorithm *algo;
+ struct secasvar *sav;
+ u_int8_t *s;
+ u_int8_t *d;
+{
+ cipherInstance c;
+ keyInstance *p;
+
+ /* does not take advantage of CBC mode support */
+ bzero(&c, sizeof(c));
+ if (rijndael_cipherInit(&c, MODE_ECB, NULL) < 0)
+ return -1;
+ p = (keyInstance *)sav->sched;
+ if (rijndael_blockEncrypt(&c, &p[1], s, algo->padbound * 8, d) < 0)
+ return -1;
+ return 0;
+}
diff --git a/sys/crypto/rc5/rc5.h b/sys/netinet6/esp_rijndael.h
index ae2339b..0c40d78 100644
--- a/sys/crypto/rc5/rc5.h
+++ b/sys/netinet6/esp_rijndael.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: rc5.h,v 1.4 2000/06/14 10:41:17 itojun Exp $ */
+/* $KAME: esp_rijndael.h,v 1.1 2000/09/20 18:15:22 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -30,58 +30,10 @@
* SUCH DAMAGE.
*/
-#ifndef _RFC2040_RC5_H_
-#define _RFC2040_RC5_H_
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/mbuf.h>
-
-/*
- * if RC5_WORD change, W also may be changed.
- */
-typedef u_int32_t RC5_WORD;
-
-#define W (32)
-#define WW (W / 8)
-#define ROT_MASK (W - 1)
-#define BB ((2 * W) / 8)
-
-#define SHLL(x, s) ((RC5_WORD)((x) << ((s)&ROT_MASK)))
-#define SHLR(x, s, w) ((RC5_WORD)((x) >> ((w)-((s)&ROT_MASK))))
-#define SHRL(x, s, w) ((RC5_WORD)((x) << ((w)-((s)&ROT_MASK))))
-#define SHRR(x, s) ((RC5_WORD)((x) >> ((s)&ROT_MASK)))
-
-#define ROTL(x, s, w) ((RC5_WORD)(SHLL((x), (s))|SHLR((x), (s), (w))))
-#define ROTR(x, s, w) ((RC5_WORD)(SHRL((x), (s), (w))|SHRR((x), (s))))
-
-#define P16 0xb7e1
-#define Q16 0x9e37
-#define P32 0xb7e15163
-#define Q32 0x9e3779b9
-#define P64 0xb7e151628aed2a6b
-#define Q64 0x9e3779b97f4a7c15
-
-#if W == 16
-#define Pw P16
-#define Qw Q16
-#elif W == 32
-#define Pw P32
-#define Qw Q32
-#elif W == 64
-#define Pw P64
-#define Qw Q64
-#endif
-
-#define RC5_ENCRYPT 1
-#define RC5_DECRYPT 0
-
-extern void set_rc5_expandkey __P((RC5_WORD *, u_int8_t *, size_t, int));
-extern void rc5_encrypt_round16 __P((u_int8_t *, const u_int8_t *,
- const RC5_WORD *));
-extern void rc5_decrypt_round16 __P((u_int8_t *, const u_int8_t *,
- const RC5_WORD *));
-extern int rc5_cbc_process __P((struct mbuf *, size_t, size_t, RC5_WORD *,
- u_int8_t *, int));
-
-#endif
+int esp_rijndael_schedlen __P((const struct esp_algorithm *));
+int esp_rijndael_schedule __P((const struct esp_algorithm *,
+ struct secasvar *));
+int esp_rijndael_blockdecrypt __P((const struct esp_algorithm *,
+ struct secasvar *, u_int8_t *, u_int8_t *));
+int esp_rijndael_blockencrypt __P((const struct esp_algorithm *,
+ struct secasvar *, u_int8_t *, u_int8_t *));
diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c
index ea4e6ca..dbf9279 100644
--- a/sys/netinet6/frag6.c
+++ b/sys/netinet6/frag6.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: frag6.c,v 1.24 2000/03/25 07:23:41 sumikawa Exp $ */
+/* $KAME: frag6.c,v 1.31 2001/05/17 13:45:34 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -66,6 +66,7 @@ static void frag6_insque __P((struct ip6q *, struct ip6q *));
static void frag6_remque __P((struct ip6q *));
static void frag6_freef __P((struct ip6q *));
+/* XXX we eventually need splreass6, or some real semaphore */
int frag6_doing_reass;
u_int frag6_nfragpackets;
struct ip6q ip6q; /* ip6 reassemble queue */
@@ -206,6 +207,8 @@ frag6_input(mp, offp, proto)
/* offset now points to data portion */
offset += sizeof(struct ip6_frag);
+ frag6_doing_reass = 1;
+
for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next)
if (ip6f->ip6f_ident == q6->ip6q_ident &&
IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) &&
@@ -217,7 +220,6 @@ frag6_input(mp, offp, proto)
* the first fragment to arrive, create a reassembly queue.
*/
first_frag = 1;
- frag6_nfragpackets++;
/*
* Enforce upper bound on number of fragmented packets
@@ -225,11 +227,11 @@ frag6_input(mp, offp, proto)
* If maxfrag is 0, never accept fragments.
* If maxfrag is -1, accept all fragments without limitation.
*/
- if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets) {
- ip6stat.ip6s_fragoverflow++;
- in6_ifstat_inc(dstifp, ifs6_reass_fail);
- frag6_freef(ip6q.ip6q_prev);
- }
+ if (ip6_maxfragpackets < 0)
+ ;
+ else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets)
+ goto dropfrag;
+ frag6_nfragpackets++;
q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FTABLE,
M_DONTWAIT);
if (q6 == NULL)
@@ -274,6 +276,7 @@ frag6_input(mp, offp, proto)
icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
offset - sizeof(struct ip6_frag) +
offsetof(struct ip6_frag, ip6f_offlg));
+ frag6_doing_reass = 0;
return(IPPROTO_DONE);
}
}
@@ -281,6 +284,7 @@ frag6_input(mp, offp, proto)
icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
offset - sizeof(struct ip6_frag) +
offsetof(struct ip6_frag, ip6f_offlg));
+ frag6_doing_reass = 0;
return(IPPROTO_DONE);
}
/*
@@ -531,6 +535,7 @@ insert:
in6_ifstat_inc(dstifp, ifs6_reass_fail);
ip6stat.ip6s_fragdropped++;
m_freem(m);
+ frag6_doing_reass = 0;
return IPPROTO_DONE;
}
@@ -620,7 +625,7 @@ frag6_remque(p6)
}
/*
- * IP timer processing;
+ * IPv6 reassembling timer processing;
* if a timer expires on a reassembly
* queue, discard it.
*/
@@ -629,9 +634,6 @@ frag6_slowtimo()
{
struct ip6q *q6;
int s = splnet();
-#if 0
- extern struct route_in6 ip6_forward_rt;
-#endif
frag6_doing_reass = 1;
q6 = ip6q.ip6q_next;
@@ -650,7 +652,8 @@ frag6_slowtimo()
* (due to the limit being lowered), drain off
* enough to get down to the new limit.
*/
- while (frag6_nfragpackets > (u_int)ip6_maxfragpackets) {
+ while (frag6_nfragpackets > (u_int)ip6_maxfragpackets &&
+ ip6q.ip6q_prev) {
ip6stat.ip6s_fragoverflow++;
/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
frag6_freef(ip6q.ip6q_prev);
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 9dca71e..4ea9a3a 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: icmp6.c,v 1.119 2000/07/03 14:16:46 itojun Exp $ */
+/* $KAME: icmp6.c,v 1.211 2001/04/04 05:56:20 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -71,6 +71,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
@@ -99,16 +100,45 @@
#ifdef IPSEC
#include <netinet6/ipsec.h>
-#ifdef INET6
-#include <netinet6/ipsec6.h>
-#endif
#include <netkey/key.h>
#endif
#include "faith.h"
+#if defined(NFAITH) && 0 < NFAITH
+#include <net/if_faith.h>
+#endif
#include <net/net_osdep.h>
+#ifdef HAVE_NRL_INPCB
+/* inpcb members */
+#define in6pcb inpcb
+#define in6p_laddr inp_laddr6
+#define in6p_faddr inp_faddr6
+#define in6p_icmp6filt inp_icmp6filt
+#define in6p_route inp_route
+#define in6p_socket inp_socket
+#define in6p_flags inp_flags
+#define in6p_moptions inp_moptions6
+#define in6p_outputopts inp_outputopts6
+#define in6p_ip6 inp_ipv6
+#define in6p_flowinfo inp_flowinfo
+#define in6p_sp inp_sp
+#define in6p_next inp_next
+#define in6p_prev inp_prev
+/* macro names */
+#define sotoin6pcb sotoinpcb
+/* function names */
+#define in6_pcbdetach in_pcbdetach
+#define in6_rtchange in_rtchange
+
+/*
+ * for KAME src sync over BSD*'s. XXX: FreeBSD (>=3) are VERY different from
+ * others...
+ */
+#define in6p_ip6_nxt inp_ipv6.ip6_nxt
+#endif
+
extern struct domain inet6domain;
extern struct ip6protosw inet6sw[];
extern u_char ip6_protox[];
@@ -116,34 +146,33 @@ extern u_char ip6_protox[];
struct icmp6stat icmp6stat;
extern struct inpcbhead ripcb;
-extern struct timeval icmp6errratelim;
-static struct timeval icmp6errratelim_last;
extern int icmp6errppslim;
static int icmp6errpps_count = 0;
+static struct timeval icmp6errppslim_last;
extern int icmp6_nodeinfo;
static void icmp6_errcount __P((struct icmp6errstat *, int, int));
static int icmp6_rip6_input __P((struct mbuf **, int));
-static void icmp6_mtudisc_update __P((struct in6_addr *, struct icmp6_hdr *,
- struct mbuf *));
static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int));
static const char *icmp6_redirect_diag __P((struct in6_addr *,
struct in6_addr *, struct in6_addr *));
-#ifndef HAVE_RATECHECK
-static int ratecheck __P((struct timeval *, struct timeval *));
+#ifndef HAVE_PPSRATECHECK
+static int ppsratecheck __P((struct timeval *, int *, int));
#endif
static struct mbuf *ni6_input __P((struct mbuf *, int));
static struct mbuf *ni6_nametodns __P((const char *, int, int));
static int ni6_dnsmatch __P((const char *, int, const char *, int));
static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *,
- struct ifnet **));
+ struct ifnet **, char *));
static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
struct ifnet *, int));
+static int icmp6_notify_error __P((struct mbuf *, int, int, int));
#ifdef COMPAT_RFC1885
static struct route_in6 icmp6_reflect_rt;
#endif
+
void
icmp6_init()
{
@@ -155,7 +184,7 @@ icmp6_errcount(stat, type, code)
struct icmp6errstat *stat;
int type, code;
{
- switch(type) {
+ switch (type) {
case ICMP6_DST_UNREACH:
switch (code) {
case ICMP6_DST_UNREACH_NOROUTE:
@@ -179,7 +208,7 @@ icmp6_errcount(stat, type, code)
stat->icp6errs_packet_too_big++;
return;
case ICMP6_TIME_EXCEEDED:
- switch(code) {
+ switch (code) {
case ICMP6_TIME_EXCEED_TRANSIT:
stat->icp6errs_time_exceed_transit++;
return;
@@ -189,7 +218,7 @@ icmp6_errcount(stat, type, code)
}
break;
case ICMP6_PARAM_PROB:
- switch(code) {
+ switch (code) {
case ICMP6_PARAMPROB_HEADER:
stat->icp6errs_paramprob_header++;
return;
@@ -318,7 +347,7 @@ icmp6_error(m, type, code, param)
if (m && m->m_len < preplen)
m = m_pullup(m, preplen);
if (m == NULL) {
- printf("ENOBUFS in icmp6_error %d\n", __LINE__);
+ nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__));
return;
}
@@ -336,6 +365,15 @@ icmp6_error(m, type, code, param)
icmp6->icmp6_code = code;
icmp6->icmp6_pptr = htonl((u_int32_t)param);
+ /*
+ * icmp6_reflect() is designed to be in the input path.
+ * icmp6_error() can be called from both input and outut path,
+ * and if we are in output path rcvif could contain bogus value.
+ * clear m->m_pkthdr.rcvif for safety, we should have enough scope
+ * information in ip header (nip6).
+ */
+ m->m_pkthdr.rcvif = NULL;
+
icmp6stat.icp6s_outhist[type]++;
icmp6_reflect(m, sizeof(struct ip6_hdr)); /*header order: IPv6 - ICMPv6*/
@@ -362,7 +400,6 @@ icmp6_input(mp, offp, proto)
int off = *offp;
int icmp6len = m->m_pkthdr.len - *offp;
int code, sum, noff;
- struct sockaddr_in6 icmp6src;
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE);
@@ -395,17 +432,15 @@ icmp6_input(mp, offp, proto)
code = icmp6->icmp6_code;
if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
- log(LOG_ERR,
+ nd6log((LOG_ERR,
"ICMP6 checksum error(%d|%x) %s\n",
- icmp6->icmp6_type,
- sum,
- ip6_sprintf(&ip6->ip6_src));
+ icmp6->icmp6_type, sum, ip6_sprintf(&ip6->ip6_src)));
icmp6stat.icp6s_checksum++;
goto freeit;
}
#if defined(NFAITH) && 0 < NFAITH
- if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
+ if (faithprefix(&ip6->ip6_dst)) {
/*
* Deliver very specific ICMP6 type only.
* This is important to deilver TOOBIG. Otherwise PMTUD
@@ -422,21 +457,12 @@ icmp6_input(mp, offp, proto)
}
#endif
-#ifdef IPSEC
- /* drop it if it does not match the default policy */
- if (ipsec6_in_reject(m, NULL)) {
- ipsecstat.in_polvio++;
- goto freeit;
- }
-#endif
-
icmp6stat.icp6s_inhist[icmp6->icmp6_type]++;
icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg);
if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK)
icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);
switch (icmp6->icmp6_type) {
-
case ICMP6_DST_UNREACH:
icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach);
switch (code) {
@@ -530,9 +556,6 @@ icmp6_input(mp, offp, proto)
* always copy the length we specified.
*/
if (maxlen >= MCLBYTES) {
-#ifdef DIAGNOSTIC
- printf("MCLBYTES too small\n");
-#endif
/* Give up remote */
m_freem(n0);
break;
@@ -648,13 +671,13 @@ icmp6_input(mp, offp, proto)
u_char *p;
int maxlen, maxhlen;
+ if ((icmp6_nodeinfo & 5) != 5)
+ break;
+
if (code != 0)
goto badcode;
maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4;
if (maxlen >= MCLBYTES) {
-#ifdef DIAGNOSTIC
- printf("MCLBYTES too small\n");
-#endif
/* Give up remote */
break;
}
@@ -670,6 +693,7 @@ icmp6_input(mp, offp, proto)
/* Give up remote */
break;
}
+ n->m_pkthdr.rcvif = NULL;
n->m_len = 0;
maxhlen = M_TRAILINGSPACE(n) - maxlen;
if (maxhlen > hostnamelen)
@@ -794,10 +818,11 @@ icmp6_input(mp, offp, proto)
break;
default:
- printf("icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n",
- icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src),
- ip6_sprintf(&ip6->ip6_dst),
- m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0);
+ nd6log((LOG_DEBUG,
+ "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n",
+ icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&ip6->ip6_dst),
+ m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0));
if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
/* ICMPv6 error: MUST deliver it by spec... */
code = PRC_NCMDS;
@@ -807,32 +832,63 @@ icmp6_input(mp, offp, proto)
break;
}
deliver:
- if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
- icmp6stat.icp6s_tooshort++;
- goto freeit;
+ if (icmp6_notify_error(m, off, icmp6len, code)) {
+ /* In this case, m should've been freed. */
+ return(IPPROTO_DONE);
}
+ break;
+
+ badcode:
+ icmp6stat.icp6s_badcode++;
+ break;
+
+ badlen:
+ icmp6stat.icp6s_badlen++;
+ break;
+ }
+
+ /* deliver the packet to appropriate sockets */
+ icmp6_rip6_input(&m, *offp);
+
+ return IPPROTO_DONE;
+
+ freeit:
+ m_freem(m);
+ return IPPROTO_DONE;
+}
+
+static int
+icmp6_notify_error(m, off, icmp6len, code)
+ struct mbuf *m;
+ int off, icmp6len;
+{
+ struct icmp6_hdr *icmp6;
+ struct ip6_hdr *eip6;
+ u_int32_t notifymtu;
+ struct sockaddr_in6 icmp6src, icmp6dst;
+
+ if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
+ icmp6stat.icp6s_tooshort++;
+ goto freeit;
+ }
#ifndef PULLDOWN_TEST
- IP6_EXTHDR_CHECK(m, off,
- sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr),
- IPPROTO_DONE);
- icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
+ IP6_EXTHDR_CHECK(m, off,
+ sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr),
+ -1);
+ icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
#else
- IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
- sizeof(*icmp6) + sizeof(struct ip6_hdr));
- if (icmp6 == NULL) {
- icmp6stat.icp6s_tooshort++;
- return IPPROTO_DONE;
- }
+ IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
+ sizeof(*icmp6) + sizeof(struct ip6_hdr));
+ if (icmp6 == NULL) {
+ icmp6stat.icp6s_tooshort++;
+ return(-1);
+ }
#endif
- bzero(&icmp6src, sizeof(icmp6src));
- icmp6src.sin6_len = sizeof(struct sockaddr_in6);
- icmp6src.sin6_family = AF_INET6;
- icmp6src.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
+ eip6 = (struct ip6_hdr *)(icmp6 + 1);
- /* Detect the upper level protocol */
- {
+ /* Detect the upper level protocol */
+ {
void (*ctlfunc) __P((int, struct sockaddr *, void *));
- struct ip6_hdr *eip6 = (struct ip6_hdr *)(icmp6 + 1);
u_int8_t nxt = eip6->ip6_nxt;
int eoff = off + sizeof(struct icmp6_hdr) +
sizeof(struct ip6_hdr);
@@ -847,22 +903,22 @@ icmp6_input(mp, offp, proto)
while (1) { /* XXX: should avoid inf. loop explicitly? */
struct ip6_ext *eh;
- switch(nxt) {
+ switch (nxt) {
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
case IPPROTO_AH:
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, 0, eoff +
sizeof(struct ip6_ext),
- IPPROTO_DONE);
+ -1);
eh = (struct ip6_ext *)(mtod(m, caddr_t)
+ eoff);
#else
IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
- eoff, sizeof(*eh));
+ eoff, sizeof(*eh));
if (eh == NULL) {
icmp6stat.icp6s_tooshort++;
- return IPPROTO_DONE;
+ return(-1);
}
#endif
@@ -883,15 +939,15 @@ icmp6_input(mp, offp, proto)
*/
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth),
- IPPROTO_DONE);
+ -1);
rth = (struct ip6_rthdr *)(mtod(m, caddr_t)
+ eoff);
#else
IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
- eoff, sizeof(*rth));
+ eoff, sizeof(*rth));
if (rth == NULL) {
icmp6stat.icp6s_tooshort++;
- return IPPROTO_DONE;
+ return(-1);
}
#endif
rthlen = (rth->ip6r_len + 1) << 3;
@@ -909,7 +965,7 @@ icmp6_input(mp, offp, proto)
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, 0, eoff + rthlen,
- IPPROTO_DONE);
+ -1);
rth0 = (struct ip6_rthdr0 *)(mtod(m, caddr_t) + eoff);
#else
IP6_EXTHDR_GET(rth0,
@@ -917,7 +973,7 @@ icmp6_input(mp, offp, proto)
eoff, rthlen);
if (rth0 == NULL) {
icmp6stat.icp6s_tooshort++;
- return IPPROTO_DONE;
+ return(-1);
}
#endif
/* just ignore a bogus header */
@@ -932,15 +988,15 @@ icmp6_input(mp, offp, proto)
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, 0, eoff +
sizeof(struct ip6_frag),
- IPPROTO_DONE);
+ -1);
fh = (struct ip6_frag *)(mtod(m, caddr_t)
+ eoff);
#else
IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
- eoff, sizeof(*fh));
+ eoff, sizeof(*fh));
if (fh == NULL) {
icmp6stat.icp6s_tooshort++;
- return IPPROTO_DONE;
+ return(-1);
}
#endif
/*
@@ -967,69 +1023,114 @@ icmp6_input(mp, offp, proto)
goto notify;
}
}
- notify:
+ notify:
#ifndef PULLDOWN_TEST
icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
#else
IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
- sizeof(*icmp6) + sizeof(struct ip6_hdr));
+ sizeof(*icmp6) + sizeof(struct ip6_hdr));
if (icmp6 == NULL) {
icmp6stat.icp6s_tooshort++;
- return IPPROTO_DONE;
+ return(-1);
+ }
+#endif
+
+ eip6 = (struct ip6_hdr *)(icmp6 + 1);
+ bzero(&icmp6dst, sizeof(icmp6dst));
+ icmp6dst.sin6_len = sizeof(struct sockaddr_in6);
+ icmp6dst.sin6_family = AF_INET6;
+ if (finaldst == NULL)
+ icmp6dst.sin6_addr = eip6->ip6_dst;
+ else
+ icmp6dst.sin6_addr = *finaldst;
+ icmp6dst.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
+ &icmp6dst.sin6_addr);
+#ifndef SCOPEDROUTING
+ if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst,
+ NULL, NULL)) {
+ /* should be impossbile */
+ nd6log((LOG_DEBUG,
+ "icmp6_notify_error: in6_embedscope failed\n"));
+ goto freeit;
+ }
+#endif
+
+ /*
+ * retrieve parameters from the inner IPv6 header, and convert
+ * them into sockaddr structures.
+ */
+ bzero(&icmp6src, sizeof(icmp6src));
+ icmp6src.sin6_len = sizeof(struct sockaddr_in6);
+ icmp6src.sin6_family = AF_INET6;
+ icmp6src.sin6_addr = eip6->ip6_src;
+ icmp6src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
+ &icmp6src.sin6_addr);
+#ifndef SCOPEDROUTING
+ if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src,
+ NULL, NULL)) {
+ /* should be impossbile */
+ nd6log((LOG_DEBUG,
+ "icmp6_notify_error: in6_embedscope failed\n"));
+ goto freeit;
}
#endif
+ icmp6src.sin6_flowinfo =
+ (eip6->ip6_flow & IPV6_FLOWLABEL_MASK);
+
+ if (finaldst == NULL)
+ finaldst = &eip6->ip6_dst;
+ ip6cp.ip6c_m = m;
+ ip6cp.ip6c_icmp6 = icmp6;
+ ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1);
+ ip6cp.ip6c_off = eoff;
+ ip6cp.ip6c_finaldst = finaldst;
+ ip6cp.ip6c_src = &icmp6src;
+ ip6cp.ip6c_nxt = nxt;
+
if (icmp6type == ICMP6_PACKET_TOO_BIG) {
- if (finaldst == NULL)
- finaldst = &((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
- icmp6_mtudisc_update(finaldst, icmp6, m);
+ notifymtu = ntohl(icmp6->icmp6_mtu);
+ ip6cp.ip6c_cmdarg = (void *)&notifymtu;
+ icmp6_mtudisc_update(&ip6cp, 1); /*XXX*/
}
ctlfunc = (void (*) __P((int, struct sockaddr *, void *)))
(inet6sw[ip6_protox[nxt]].pr_ctlinput);
if (ctlfunc) {
- ip6cp.ip6c_m = m;
- ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1);
- ip6cp.ip6c_off = eoff;
- (*ctlfunc)(code, (struct sockaddr *)&icmp6src, &ip6cp);
+ (void) (*ctlfunc)(code, (struct sockaddr *)&icmp6dst,
+ &ip6cp);
}
- }
- break;
-
- badcode:
- icmp6stat.icp6s_badcode++;
- break;
-
- badlen:
- icmp6stat.icp6s_badlen++;
- break;
}
+ return(0);
-#ifdef HAVE_NRL_INPCB
- rip6_input(&m, offp, IPPROTO_ICMPV6);
-#else
- icmp6_rip6_input(&m, *offp);
-#endif
- return IPPROTO_DONE;
-
- freeit:
+ freeit:
m_freem(m);
- return IPPROTO_DONE;
+ return(-1);
}
-static void
-icmp6_mtudisc_update(dst, icmp6, m)
- struct in6_addr *dst;
- struct icmp6_hdr *icmp6;/* we can assume the validity of the pointer */
- struct mbuf *m; /* currently unused but added for scoped addrs */
+void
+icmp6_mtudisc_update(ip6cp, validated)
+ struct ip6ctlparam *ip6cp;
+ int validated;
{
+ struct in6_addr *dst = ip6cp->ip6c_finaldst;
+ struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6;
+ struct mbuf *m = ip6cp->ip6c_m; /* will be necessary for scope issue */
u_int mtu = ntohl(icmp6->icmp6_mtu);
struct rtentry *rt = NULL;
struct sockaddr_in6 sin6;
+ if (!validated)
+ return;
+
bzero(&sin6, sizeof(sin6));
sin6.sin6_family = PF_INET6;
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_addr = *dst;
+ /* XXX normally, this won't happen */
+ if (IN6_IS_ADDR_LINKLOCAL(dst)) {
+ sin6.sin6_addr.s6_addr16[1] =
+ htons(m->m_pkthdr.rcvif->if_index);
+ }
/* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */
rt = rtalloc1((struct sockaddr *)&sin6, 0,
RTF_CLONING | RTF_PRCLONING);
@@ -1041,6 +1142,7 @@ icmp6_mtudisc_update(dst, icmp6, m)
rt->rt_rmx.rmx_locks |= RTV_MTU;
} else if (mtu < rt->rt_ifp->if_mtu &&
rt->rt_rmx.rmx_mtu > mtu) {
+ icmp6stat.icp6s_pmtuchg++;
rt->rt_rmx.rmx_mtu = mtu;
}
}
@@ -1049,19 +1151,17 @@ icmp6_mtudisc_update(dst, icmp6, m)
}
/*
- * Process a Node Information Query packet, (roughly) based on
- * draft-ietf-ipngwg-icmp-name-lookups-05.
+ * Process a Node Information Query packet, based on
+ * draft-ietf-ipngwg-icmp-name-lookups-07.
*
* Spec incompatibilities:
* - IPv6 Subject address handling
* - IPv4 Subject address handling support missing
* - Proxy reply (answer even if it's not for me)
- * - "Supported Qtypes" support missing
* - joins NI group address at in6_ifattach() time only, does not cope
* with hostname changes by sethostname(3)
*/
#define hostnamelen strlen(hostname)
-
static struct mbuf *
ni6_input(m, off)
struct mbuf *m;
@@ -1075,10 +1175,12 @@ ni6_input(m, off)
struct ni_reply_fqdn *fqdn;
int addrs; /* for NI_QTYPE_NODEADDR */
struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */
- struct sockaddr_in6 sin6;
+ struct sockaddr_in6 sin6; /* double meaning; ip6_dst and subjectaddr */
+ struct sockaddr_in6 sin6_d; /* XXX: we should retrieve this from m_aux */
struct ip6_hdr *ip6;
int oldfqdn = 0; /* if 1, return pascal string (03 draft) */
- char *subj;
+ char *subj = NULL;
+ struct in6_ifaddr *ia6 = NULL;
ip6 = mtod(m, struct ip6_hdr *);
#ifndef PULLDOWN_TEST
@@ -1094,81 +1196,40 @@ ni6_input(m, off)
/*
* Validate IPv6 destination address.
*
- * We accept packets with the following IPv6 destination address:
- * - Responder's unicast/anycast address,
- * - link-local multicast address
- * This is a violation to last paragraph in icmp-name-lookups-05
- * page 4, which restricts IPv6 destination address of a query to:
- * - Responder's unicast/anycast address,
- * - NI group address for a name belongs to the Responder, or
- * - NI group address for a name for which the Responder is providing
- * proxy service.
- * (note: NI group address is a link-local multicast address)
- *
- * We allow any link-local multicast address, since "ping6 -w ff02::1"
- * has been really useful for us debugging our network. Also this is
- * still questionable if the restriction in spec buy us security at all,
- * since RFC2463 permits echo packet to multicast destination.
- * Even if we forbid NI query to ff02::1, we can effectively get the
- * same result as "ping6 -w ff02::1" by the following steps:
- * - run "ping6 ff02::1", then
- * - run "ping6 -w" for all addresses replied.
+ * The Responder must discard the Query without further processing
+ * unless it is one of the Responder's unicast or anycast addresses, or
+ * a link-local scope multicast address which the Responder has joined.
+ * [icmp-name-lookups-07, Section 4.]
*/
bzero(&sin6, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_len = sizeof(struct sockaddr_in6);
bcopy(&ip6->ip6_dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr));
/* XXX scopeid */
- if (ifa_ifwithaddr((struct sockaddr *)&sin6))
- ; /*unicast/anycast, fine*/
- else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr))
- ; /*violates spec slightly, see above*/
+ if ((ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)&sin6)) != NULL) {
+ /* unicast/anycast, fine */
+ if ((ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
+ (icmp6_nodeinfo & 4) == 0) {
+ nd6log((LOG_DEBUG, "ni6_input: ignore node info to "
+ "a temporary address in %s:%d",
+ __FILE__, __LINE__));
+ goto bad;
+ }
+ } else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr))
+ ; /* link-local multicast, fine */
else
goto bad;
- /* guess reply length */
- qtype = ntohs(ni6->ni_qtype);
- switch (qtype) {
- case NI_QTYPE_NOOP:
- break; /* no reply data */
- case NI_QTYPE_SUPTYPES:
- goto bad; /* xxx: to be implemented */
- break;
- case NI_QTYPE_FQDN:
- /* XXX will append a mbuf */
- replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
- break;
- case NI_QTYPE_NODEADDR:
- addrs = ni6_addrs(ni6, m, &ifp);
- if ((replylen += addrs * sizeof(struct in6_addr)) > MCLBYTES)
- replylen = MCLBYTES; /* XXX: we'll truncate later */
- break;
- default:
- /*
- * XXX: We must return a reply with the ICMP6 code
- * `unknown Qtype' in this case. However we regard the case
- * as an FQDN query for backward compatibility.
- * Older versions set a random value to this field,
- * so it rarely varies in the defined qtypes.
- * But the mechanism is not reliable...
- * maybe we should obsolete older versions.
- */
- qtype = NI_QTYPE_FQDN;
- /* XXX will append a mbuf */
- replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
- oldfqdn++;
- break;
- }
-
/* validate query Subject field. */
+ qtype = ntohs(ni6->ni_qtype);
subjlen = m->m_pkthdr.len - off - sizeof(struct icmp6_nodeinfo);
switch (qtype) {
case NI_QTYPE_NOOP:
case NI_QTYPE_SUPTYPES:
- if (subjlen != 0)
- goto bad;
- break;
-
+ /* 07 draft */
+ if (ni6->ni_code == ICMP6_NI_SUBJ_FQDN && subjlen == 0)
+ break;
+ /* FALLTHROUGH */
case NI_QTYPE_FQDN:
case NI_QTYPE_NODEADDR:
switch (ni6->ni_code) {
@@ -1180,10 +1241,15 @@ ni6_input(m, off)
* backward compatibility - try to accept 03 draft
* format, where no Subject is present.
*/
- if (subjlen == 0) {
+ if (qtype == NI_QTYPE_FQDN && ni6->ni_code == 0 &&
+ subjlen == 0) {
oldfqdn++;
break;
}
+#if ICMP6_NI_SUBJ_IPV6 != 0
+ if (ni6->ni_code != ICMP6_NI_SUBJ_IPV6)
+ goto bad;
+#endif
if (subjlen != sizeof(sin6.sin6_addr))
goto bad;
@@ -1191,8 +1257,8 @@ ni6_input(m, off)
/*
* Validate Subject address.
*
- * Not sure what exactly does "address belongs to the
- * node" mean in the spec, is it just unicast, or what?
+ * Not sure what exactly "address belongs to the node"
+ * means in the spec, is it just unicast, or what?
*
* At this moment we consider Subject address as
* "belong to the node" if the Subject address equals
@@ -1205,23 +1271,24 @@ ni6_input(m, off)
/* m_pulldown instead of copy? */
m_copydata(m, off + sizeof(struct icmp6_nodeinfo),
subjlen, (caddr_t)&sin6.sin6_addr);
- /* XXX kame scope hack */
- if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) {
-#ifdef FAKE_LOOPBACK_IF
- if ((m->m_flags & M_PKTHDR) != 0 &&
- m->m_pkthdr.rcvif) {
- sin6.sin6_addr.s6_addr16[1] =
- htons(m->m_pkthdr.rcvif->if_index);
- }
-#else
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
- sin6.sin6_addr.s6_addr16[1] =
- ip6->ip6_dst.s6_addr16[1];
- }
+ sin6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
+ &sin6.sin6_addr);
+#ifndef SCOPEDROUTING
+ in6_embedscope(&sin6.sin6_addr, &sin6, NULL, NULL);
#endif
- }
- if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6.sin6_addr))
+ bzero(&sin6_d, sizeof(sin6_d));
+ sin6_d.sin6_family = AF_INET6; /* not used, actually */
+ sin6_d.sin6_len = sizeof(sin6_d); /* ditto */
+ sin6_d.sin6_addr = ip6->ip6_dst;
+ sin6_d.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
+ &ip6->ip6_dst);
+#ifndef SCOPEDROUTING
+ in6_embedscope(&sin6_d.sin6_addr, &sin6_d, NULL, NULL);
+#endif
+ subj = (char *)&sin6;
+ if (SA6_ARE_ADDR_EQUAL(&sin6, &sin6_d))
break;
+
/*
* XXX if we are to allow other cases, we should really
* be careful about scope here.
@@ -1259,18 +1326,60 @@ ni6_input(m, off)
n = NULL;
break;
- case ICMP6_NI_SUBJ_IPV4: /* xxx: to be implemented? */
+ case ICMP6_NI_SUBJ_IPV4: /* XXX: to be implemented? */
default:
goto bad;
}
break;
+ }
+
+ /* refuse based on configuration. XXX ICMP6_NI_REFUSED? */
+ switch (qtype) {
+ case NI_QTYPE_FQDN:
+ if ((icmp6_nodeinfo & 1) == 0)
+ goto bad;
+ break;
+ case NI_QTYPE_NODEADDR:
+ if ((icmp6_nodeinfo & 2) == 0)
+ goto bad;
+ break;
+ }
+ /* guess reply length */
+ switch (qtype) {
+ case NI_QTYPE_NOOP:
+ break; /* no reply data */
+ case NI_QTYPE_SUPTYPES:
+ replylen += sizeof(u_int32_t);
+ break;
+ case NI_QTYPE_FQDN:
+ /* XXX will append an mbuf */
+ replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
+ break;
+ case NI_QTYPE_NODEADDR:
+ addrs = ni6_addrs(ni6, m, &ifp, subj);
+ if ((replylen += addrs * (sizeof(struct in6_addr) +
+ sizeof(u_int32_t))) > MCLBYTES)
+ replylen = MCLBYTES; /* XXX: will truncate pkt later */
+ break;
default:
- /* should never be here due to "switch (qtype)" above */
- goto bad;
+ /*
+ * XXX: We must return a reply with the ICMP6 code
+ * `unknown Qtype' in this case. However we regard the case
+ * as an FQDN query for backward compatibility.
+ * Older versions set a random value to this field,
+ * so it rarely varies in the defined qtypes.
+ * But the mechanism is not reliable...
+ * maybe we should obsolete older versions.
+ */
+ qtype = NI_QTYPE_FQDN;
+ /* XXX will append an mbuf */
+ replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
+ oldfqdn++;
+ break;
}
- /* allocate a mbuf to reply. */
+ /* allocate an mbuf to reply. */
MGETHDR(n, M_DONTWAIT, m->m_type);
if (n == NULL) {
m_freem(m);
@@ -1279,10 +1388,10 @@ ni6_input(m, off)
M_COPY_PKTHDR(n, m); /* just for recvif */
if (replylen > MHLEN) {
if (replylen > MCLBYTES) {
- /*
- * XXX: should we try to allocate more? But MCLBYTES is
- * probably much larger than IPV6_MMTU...
- */
+ /*
+ * XXX: should we try to allocate more? But MCLBYTES
+ * is probably much larger than IPV6_MMTU...
+ */
goto bad;
}
MCLGET(n, M_DONTWAIT);
@@ -1300,12 +1409,21 @@ ni6_input(m, off)
/* qtype dependent procedure */
switch (qtype) {
case NI_QTYPE_NOOP:
+ nni6->ni_code = ICMP6_NI_SUCCESS;
nni6->ni_flags = 0;
break;
case NI_QTYPE_SUPTYPES:
- goto bad; /* xxx: to be implemented */
+ {
+ u_int32_t v;
+ nni6->ni_code = ICMP6_NI_SUCCESS;
+ nni6->ni_flags = htons(0x0000); /* raw bitmap */
+ /* supports NOOP, SUPTYPES, FQDN, and NODEADDR */
+ v = (u_int32_t)htonl(0x0000000f);
+ bcopy(&v, nni6 + 1, sizeof(u_int32_t));
break;
+ }
case NI_QTYPE_FQDN:
+ nni6->ni_code = ICMP6_NI_SUCCESS;
fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) +
sizeof(struct ip6_hdr) +
sizeof(struct icmp6_nodeinfo));
@@ -1326,12 +1444,10 @@ ni6_input(m, off)
{
int lenlim, copied;
- if (n->m_flags & M_EXT)
- lenlim = MCLBYTES - sizeof(struct ip6_hdr) -
- sizeof(struct icmp6_nodeinfo);
- else
- lenlim = MHLEN - sizeof(struct ip6_hdr) -
- sizeof(struct icmp6_nodeinfo);
+ nni6->ni_code = ICMP6_NI_SUCCESS;
+ n->m_pkthdr.len = n->m_len =
+ sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
+ lenlim = M_TRAILINGSPACE(n);
copied = ni6_store_addrs(ni6, nni6, ifp, lenlim);
/* XXX: reset mbuf length */
n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
@@ -1343,7 +1459,6 @@ ni6_input(m, off)
}
nni6->ni_type = ICMP6_NI_REPLY;
- nni6->ni_code = ICMP6_NI_SUCESS;
m_freem(m);
return(n);
@@ -1455,6 +1570,7 @@ ni6_nametodns(name, namelen, old)
/*
* check if two DNS-encoded string matches. takes care of truncated
* form (with \0\0 at the end). no compression support.
+ * XXX upper/lowercase match (see RFC2065)
*/
static int
ni6_dnsmatch(a, alen, b, blen)
@@ -1521,16 +1637,34 @@ ni6_dnsmatch(a, alen, b, blen)
* calculate the number of addresses to be returned in the node info reply.
*/
static int
-ni6_addrs(ni6, m, ifpp)
+ni6_addrs(ni6, m, ifpp, subj)
struct icmp6_nodeinfo *ni6;
struct mbuf *m;
struct ifnet **ifpp;
+ char *subj;
{
- register struct ifnet *ifp;
- register struct in6_ifaddr *ifa6;
- register struct ifaddr *ifa;
- struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+ struct ifnet *ifp;
+ struct in6_ifaddr *ifa6;
+ struct ifaddr *ifa;
+ struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */
int addrs = 0, addrsofif, iffound = 0;
+ int niflags = ni6->ni_flags;
+
+ if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) {
+ switch (ni6->ni_code) {
+ case ICMP6_NI_SUBJ_IPV6:
+ if (subj == NULL) /* must be impossible... */
+ return(0);
+ subj_ip6 = (struct sockaddr_in6 *)subj;
+ break;
+ default:
+ /*
+ * XXX: we only support IPv6 subject address for
+ * this Qtype.
+ */
+ return(0);
+ }
+ }
for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
{
@@ -1542,8 +1676,8 @@ ni6_addrs(ni6, m, ifpp)
continue;
ifa6 = (struct in6_ifaddr *)ifa;
- if (!(ni6->ni_flags & NI_NODEADDR_FLAG_ALL) &&
- IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
+ if ((niflags & NI_NODEADDR_FLAG_ALL) == 0 &&
+ IN6_ARE_ADDR_EQUAL(&subj_ip6->sin6_addr,
&ifa6->ia_addr.sin6_addr))
iffound = 1;
@@ -1552,36 +1686,41 @@ ni6_addrs(ni6, m, ifpp)
* Node Information proxy, since they represent
* addresses of IPv4-only nodes, which perforce do
* not implement this protocol.
- * [icmp-name-lookups-05]
+ * [icmp-name-lookups-07, Section 5.4]
* So we don't support NI_NODEADDR_FLAG_COMPAT in
* this function at this moment.
*/
- if (ifa6->ia6_flags & IN6_IFF_ANYCAST)
- continue; /* we need only unicast addresses */
-
- if ((ni6->ni_flags & (NI_NODEADDR_FLAG_LINKLOCAL |
- NI_NODEADDR_FLAG_SITELOCAL |
- NI_NODEADDR_FLAG_GLOBAL)) == 0)
- continue;
-
/* What do we have to do about ::1? */
- switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
- case IPV6_ADDR_SCOPE_LINKLOCAL:
- if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL)
- addrsofif++;
+ switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
+ case IPV6_ADDR_SCOPE_LINKLOCAL:
+ if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0)
+ continue;
break;
- case IPV6_ADDR_SCOPE_SITELOCAL:
- if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL)
- addrsofif++;
+ case IPV6_ADDR_SCOPE_SITELOCAL:
+ if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0)
+ continue;
+ break;
+ case IPV6_ADDR_SCOPE_GLOBAL:
+ if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0)
+ continue;
break;
- case IPV6_ADDR_SCOPE_GLOBAL:
- if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL)
- addrsofif++;
- break;
- default:
- continue;
+ default:
+ continue;
+ }
+
+ /*
+ * check if anycast is okay.
+ * XXX: just experimental. not in the spec.
+ */
+ if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 &&
+ (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0)
+ continue; /* we need only unicast addresses */
+ if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
+ (icmp6_nodeinfo & 4) == 0) {
+ continue;
}
+ addrsofif++; /* count the address */
}
if (iffound) {
*ifpp = ifp;
@@ -1600,82 +1739,139 @@ ni6_store_addrs(ni6, nni6, ifp0, resid)
struct ifnet *ifp0;
int resid;
{
- register struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet);
- register struct in6_ifaddr *ifa6;
- register struct ifaddr *ifa;
- int docopy, copied = 0;
+ struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet);
+ struct in6_ifaddr *ifa6;
+ struct ifaddr *ifa;
+ struct ifnet *ifp_dep = NULL;
+ int copied = 0, allow_deprecated = 0;
u_char *cp = (u_char *)(nni6 + 1);
+ int niflags = ni6->ni_flags;
+ u_int32_t ltime;
- if (ifp0 == NULL && !(ni6->ni_flags & NI_NODEADDR_FLAG_ALL))
+ if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL))
return(0); /* needless to copy */
+ again:
+
for (; ifp; ifp = TAILQ_NEXT(ifp, if_list))
{
for (ifa = ifp->if_addrlist.tqh_first; ifa;
ifa = ifa->ifa_list.tqe_next)
{
- docopy = 0;
-
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ifa6 = (struct in6_ifaddr *)ifa;
- if (ifa6->ia6_flags & IN6_IFF_ANYCAST) {
- /* just experimental. not in the spec. */
- if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST)
- docopy = 1;
- else
- continue;
- }
- else { /* unicast address */
- if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST)
- continue;
- else
- docopy = 1;
+ if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) != 0 &&
+ allow_deprecated == 0) {
+ /*
+ * prefererred address should be put before
+ * deprecated addresses.
+ */
+
+ /* record the interface for later search */
+ if (ifp_dep == NULL)
+ ifp_dep = ifp;
+
+ continue;
}
+ else if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) == 0 &&
+ allow_deprecated != 0)
+ continue; /* we now collect deprecated addrs */
/* What do we have to do about ::1? */
- switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
- case IPV6_ADDR_SCOPE_LINKLOCAL:
- if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL)
- docopy = 1;
+ switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
+ case IPV6_ADDR_SCOPE_LINKLOCAL:
+ if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0)
+ continue;
+ break;
+ case IPV6_ADDR_SCOPE_SITELOCAL:
+ if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0)
+ continue;
break;
- case IPV6_ADDR_SCOPE_SITELOCAL:
- if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL)
- docopy = 1;
+ case IPV6_ADDR_SCOPE_GLOBAL:
+ if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0)
+ continue;
break;
- case IPV6_ADDR_SCOPE_GLOBAL:
- if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL)
- docopy = 1;
- break;
- default:
- continue;
+ default:
+ continue;
}
- if (docopy) {
- if (resid < sizeof(struct in6_addr)) {
- /*
- * We give up much more copy.
- * Set the truncate flag and return.
- */
- nni6->ni_flags |=
- NI_NODEADDR_FLAG_TRUNCATE;
- return(copied);
- }
- bcopy(&ifa6->ia_addr.sin6_addr, cp,
- sizeof(struct in6_addr));
- /* XXX: KAME link-local hack; remove ifindex */
- if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr))
- ((struct in6_addr *)cp)->s6_addr16[1] = 0;
- cp += sizeof(struct in6_addr);
- resid -= sizeof(struct in6_addr);
- copied += sizeof(struct in6_addr);
+ /*
+ * check if anycast is okay.
+ * XXX: just experimental. not in the spec.
+ */
+ if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 &&
+ (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0)
+ continue;
+ if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
+ (icmp6_nodeinfo & 4) == 0) {
+ continue;
}
+
+ /* now we can copy the address */
+ if (resid < sizeof(struct in6_addr) +
+ sizeof(u_int32_t)) {
+ /*
+ * We give up much more copy.
+ * Set the truncate flag and return.
+ */
+ nni6->ni_flags |=
+ NI_NODEADDR_FLAG_TRUNCATE;
+ return(copied);
+ }
+
+ /*
+ * Set the TTL of the address.
+ * The TTL value should be one of the following
+ * according to the specification:
+ *
+ * 1. The remaining lifetime of a DHCP lease on the
+ * address, or
+ * 2. The remaining Valid Lifetime of a prefix from
+ * which the address was derived through Stateless
+ * Autoconfiguration.
+ *
+ * Note that we currently do not support stateful
+ * address configuration by DHCPv6, so the former
+ * case can't happen.
+ */
+ if (ifa6->ia6_lifetime.ia6t_expire == 0)
+ ltime = ND6_INFINITE_LIFETIME;
+ else {
+ if (ifa6->ia6_lifetime.ia6t_expire >
+ time_second)
+ ltime = htonl(ifa6->ia6_lifetime.ia6t_expire - time_second);
+ else
+ ltime = 0;
+ }
+
+ bcopy(&ltime, cp, sizeof(u_int32_t));
+ cp += sizeof(u_int32_t);
+
+ /* copy the address itself */
+ bcopy(&ifa6->ia_addr.sin6_addr, cp,
+ sizeof(struct in6_addr));
+ /* XXX: KAME link-local hack; remove ifindex */
+ if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr))
+ ((struct in6_addr *)cp)->s6_addr16[1] = 0;
+ cp += sizeof(struct in6_addr);
+
+ resid -= (sizeof(struct in6_addr) + sizeof(u_int32_t));
+ copied += (sizeof(struct in6_addr) +
+ sizeof(u_int32_t));
}
if (ifp0) /* we need search only on the specified IF */
break;
}
+ if (allow_deprecated == 0 && ifp_dep != NULL) {
+ ifp = ifp_dep;
+ allow_deprecated = 1;
+
+ goto again;
+ }
+
return(copied);
}
@@ -1688,8 +1884,8 @@ icmp6_rip6_input(mp, off)
int off;
{
struct mbuf *m = *mp;
- register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
- register struct in6pcb *in6p;
+ struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+ struct in6pcb *in6p;
struct in6pcb *last = NULL;
struct sockaddr_in6 rip6src;
struct icmp6_hdr *icmp6;
@@ -1714,8 +1910,12 @@ icmp6_rip6_input(mp, off)
LIST_FOREACH(in6p, &ripcb, inp_list)
{
- if ((in6p->inp_vflag & INP_IPV6) == NULL)
+ if ((in6p->inp_vflag & INP_IPV6) == 0)
+ continue;
+#ifdef HAVE_NRL_INPCB
+ if (!(in6p->in6p_flags & INP_IPV6))
continue;
+#endif
if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6)
continue;
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
@@ -1740,8 +1940,9 @@ icmp6_rip6_input(mp, off)
n, opts) == 0) {
/* should notify about lost packet */
m_freem(n);
- if (opts)
+ if (opts) {
m_freem(opts);
+ }
} else
sorwakeup(last->in6p_socket);
opts = NULL;
@@ -1755,7 +1956,7 @@ icmp6_rip6_input(mp, off)
/* strip intermediate headers */
m_adj(m, off);
if (sbappendaddr(&last->in6p_socket->so_rcv,
- (struct sockaddr *)&rip6src, m, opts) == 0) {
+ (struct sockaddr *)&rip6src, m, opts) == 0) {
m_freem(m);
if (opts)
m_freem(opts);
@@ -1784,6 +1985,7 @@ icmp6_reflect(m, off)
int plen;
int type, code;
struct ifnet *outif = NULL;
+ struct sockaddr_in6 sa6_src, sa6_dst;
#ifdef COMPAT_RFC1885
int mtu = IPV6_MMTU;
struct sockaddr_in6 *sin6 = &icmp6_reflect_rt.ro_dst;
@@ -1791,9 +1993,10 @@ icmp6_reflect(m, off)
/* too short to reflect */
if (off < sizeof(struct ip6_hdr)) {
- printf("sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n",
- (u_long)off, (u_long)sizeof(struct ip6_hdr),
- __FILE__, __LINE__);
+ nd6log((LOG_DEBUG,
+ "sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n",
+ (u_long)off, (u_long)sizeof(struct ip6_hdr),
+ __FILE__, __LINE__));
goto bad;
}
@@ -1840,12 +2043,24 @@ icmp6_reflect(m, off)
*/
ip6->ip6_dst = ip6->ip6_src;
- /* XXX hack for link-local addresses */
- if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
- ip6->ip6_dst.s6_addr16[1] =
- htons(m->m_pkthdr.rcvif->if_index);
- if (IN6_IS_ADDR_LINKLOCAL(&t))
- t.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
+ /*
+ * XXX: make sure to embed scope zone information, using
+ * already embedded IDs or the received interface (if any).
+ * Note that rcvif may be NULL.
+ * TODO: scoped routing case (XXX).
+ */
+ bzero(&sa6_src, sizeof(sa6_src));
+ sa6_src.sin6_family = AF_INET6;
+ sa6_src.sin6_len = sizeof(sa6_src);
+ sa6_src.sin6_addr = ip6->ip6_dst;
+ in6_recoverscope(&sa6_src, &ip6->ip6_dst, m->m_pkthdr.rcvif);
+ in6_embedscope(&ip6->ip6_dst, &sa6_src, NULL, NULL);
+ bzero(&sa6_dst, sizeof(sa6_dst));
+ sa6_dst.sin6_family = AF_INET6;
+ sa6_dst.sin6_len = sizeof(sa6_dst);
+ sa6_dst.sin6_addr = t;
+ in6_recoverscope(&sa6_dst, &t, m->m_pkthdr.rcvif);
+ in6_embedscope(&t, &sa6_dst, NULL, NULL);
#ifdef COMPAT_RFC1885
/*
@@ -1902,19 +2117,27 @@ icmp6_reflect(m, off)
src = &t;
}
- if (src == 0)
+ if (src == 0) {
+ int e;
+ struct route_in6 ro;
+
/*
* This case matches to multicasts, our anycast, or unicasts
- * that we do not own. Select a source address which has the
- * same scope.
- * XXX: for (non link-local) multicast addresses, this might
- * not be a good choice.
+ * that we do not own. Select a source address based on the
+ * source address of the erroneous packet.
*/
- if ((ia = in6_ifawithscope(m->m_pkthdr.rcvif, &t)) != 0)
- src = &IA6_SIN6(ia)->sin6_addr;
-
- if (src == 0)
- goto bad;
+ bzero(&ro, sizeof(ro));
+ src = in6_selectsrc(&sa6_src, NULL, NULL, &ro, NULL, &e);
+ if (ro.ro_rt)
+ RTFREE(ro.ro_rt); /* XXX: we could use this */
+ if (src == NULL) {
+ nd6log((LOG_DEBUG,
+ "icmp6_reflect: source can't be determined: "
+ "dst=%s, error=%d\n",
+ ip6_sprintf(&sa6_src.sin6_addr), e));
+ goto bad;
+ }
+ }
ip6->ip6_src = *src;
@@ -1925,20 +2148,21 @@ icmp6_reflect(m, off)
if (m->m_pkthdr.rcvif) {
/* XXX: This may not be the outgoing interface */
ip6->ip6_hlim = nd_ifinfo[m->m_pkthdr.rcvif->if_index].chlim;
- }
+ } else
+ ip6->ip6_hlim = ip6_defhlim;
icmp6->icmp6_cksum = 0;
icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6,
sizeof(struct ip6_hdr), plen);
/*
- * xxx option handling
+ * XXX option handling
*/
m->m_flags &= ~(M_BCAST|M_MCAST);
#ifdef IPSEC
/* Don't lookup socket */
- ipsec_setsocket(m, NULL);
+ (void)ipsec_setsocket(m, NULL);
#endif /*IPSEC*/
#ifdef COMPAT_RFC1885
@@ -1961,9 +2185,6 @@ icmp6_fasttimo()
{
mld6_fasttimeo();
-
- /* reset ICMPv6 pps limit */
- icmp6errpps_count = 0;
}
static const char *
@@ -1980,7 +2201,7 @@ icmp6_redirect_diag(src6, dst6, tgt6)
void
icmp6_redirect_input(m, off)
- register struct mbuf *m;
+ struct mbuf *m;
int off;
{
struct ifnet *ifp = m->m_pkthdr.rcvif;
@@ -2028,17 +2249,17 @@ icmp6_redirect_input(m, off)
/* validation */
if (!IN6_IS_ADDR_LINKLOCAL(&src6)) {
- log(LOG_ERR,
+ nd6log((LOG_ERR,
"ICMP6 redirect sent from %s rejected; "
- "must be from linklocal\n", ip6_sprintf(&src6));
- goto freeit;
+ "must be from linklocal\n", ip6_sprintf(&src6)));
+ goto bad;
}
if (ip6->ip6_hlim != 255) {
- log(LOG_ERR,
+ nd6log((LOG_ERR,
"ICMP6 redirect sent from %s rejected; "
"hlim=%d (must be 255)\n",
- ip6_sprintf(&src6), ip6->ip6_hlim);
- goto freeit;
+ ip6_sprintf(&src6), ip6->ip6_hlim));
+ goto bad;
}
{
/* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */
@@ -2053,41 +2274,41 @@ icmp6_redirect_input(m, off)
if (rt) {
if (rt->rt_gateway == NULL ||
rt->rt_gateway->sa_family != AF_INET6) {
- log(LOG_ERR,
+ nd6log((LOG_ERR,
"ICMP6 redirect rejected; no route "
"with inet6 gateway found for redirect dst: %s\n",
- icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
+ icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
RTFREE(rt);
- goto freeit;
+ goto bad;
}
gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr);
if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) {
- log(LOG_ERR,
+ nd6log((LOG_ERR,
"ICMP6 redirect rejected; "
"not equal to gw-for-src=%s (must be same): "
"%s\n",
ip6_sprintf(gw6),
- icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
+ icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
RTFREE(rt);
- goto freeit;
+ goto bad;
}
} else {
- log(LOG_ERR,
+ nd6log((LOG_ERR,
"ICMP6 redirect rejected; "
"no route found for redirect dst: %s\n",
- icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
- goto freeit;
+ icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
+ goto bad;
}
RTFREE(rt);
rt = NULL;
}
if (IN6_IS_ADDR_MULTICAST(&reddst6)) {
- log(LOG_ERR,
+ nd6log((LOG_ERR,
"ICMP6 redirect rejected; "
"redirect dst must be unicast: %s\n",
- icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
- goto freeit;
+ icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
+ goto bad;
}
is_router = is_onlink = 0;
@@ -2096,20 +2317,21 @@ icmp6_redirect_input(m, off)
if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0)
is_onlink = 1; /* on-link destination case */
if (!is_router && !is_onlink) {
- log(LOG_ERR,
+ nd6log((LOG_ERR,
"ICMP6 redirect rejected; "
"neither router case nor onlink case: %s\n",
- icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
- goto freeit;
+ icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
+ goto bad;
}
/* validation passed */
icmp6len -= sizeof(*nd_rd);
nd6_option_init(nd_rd + 1, icmp6len, &ndopts);
if (nd6_options(&ndopts) < 0) {
- log(LOG_INFO, "icmp6_redirect_input: "
+ nd6log((LOG_INFO, "icmp6_redirect_input: "
"invalid ND option, rejected: %s\n",
- icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
+ icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
+ /* nd6_options have incremented stats */
goto freeit;
}
@@ -2124,11 +2346,12 @@ icmp6_redirect_input(m, off)
}
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
- log(LOG_INFO,
+ nd6log((LOG_INFO,
"icmp6_redirect_input: lladdrlen mismatch for %s "
"(if %d, icmp6 packet %d): %s\n",
ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2,
- icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
+ icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
+ goto bad;
}
/* RFC 2461 8.3 */
@@ -2171,6 +2394,11 @@ icmp6_redirect_input(m, off)
freeit:
m_freem(m);
+ return;
+
+ bad:
+ icmp6stat.icp6s_badredirect++;
+ m_freem(m);
}
void
@@ -2235,7 +2463,9 @@ icmp6_redirect_output(m0, rt)
MCLGET(m, M_DONTWAIT);
if (!m)
goto fail;
- maxlen = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN;
+ m->m_pkthdr.rcvif = NULL;
+ m->m_len = 0;
+ maxlen = M_TRAILINGSPACE(m);
maxlen = min(IPV6_MMTU, maxlen);
/* just for safety */
if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) +
@@ -2440,7 +2670,7 @@ noredhdropt:;
/* send the packet to outside... */
#ifdef IPSEC
/* Don't lookup socket */
- ipsec_setsocket(m, NULL);
+ (void)ipsec_setsocket(m, NULL);
#endif /*IPSEC*/
ip6_output(m, NULL, NULL, 0, NULL, &outif);
if (outif) {
@@ -2458,11 +2688,13 @@ fail:
m_freem(m0);
}
+#ifdef HAVE_NRL_INPCB
+#define sotoin6pcb sotoinpcb
+#define in6pcb inpcb
+#define in6p_icmp6filt inp_icmp6filt
+#endif
/*
* ICMPv6 socket option processing.
- *
- * NOTE: for OSes that use NRL inpcb (bsdi4/openbsd), do not forget to modify
- * sys/netinet6/raw_ipv6.c:rip6_ctloutput().
*/
int
icmp6_ctloutput(so, sopt)
@@ -2471,7 +2703,7 @@ icmp6_ctloutput(so, sopt)
{
int error = 0;
int optlen;
- register struct inpcb *inp = sotoinpcb(so);
+ struct inpcb *inp = sotoinpcb(so);
int level, op, optname;
if (sopt) {
@@ -2481,11 +2713,12 @@ icmp6_ctloutput(so, sopt)
optlen = sopt->sopt_valsize;
} else
level = op = optname = optlen = 0;
+
if (level != IPPROTO_ICMPV6) {
return EINVAL;
}
- switch(op) {
+ switch (op) {
case PRCO_SETOPT:
switch (optname) {
case ICMP6_FILTER:
@@ -2533,42 +2766,79 @@ icmp6_ctloutput(so, sopt)
return(error);
}
+#ifdef HAVE_NRL_INPCB
+#undef sotoin6pcb
+#undef in6pcb
+#undef in6p_icmp6filt
+#endif
+
+#ifndef HAVE_PPSRATECHECK
+#ifndef timersub
+#define timersub(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif
-#ifndef HAVE_RATECHECK
/*
- * ratecheck() returns true if it is okay to send. We return
- * true if it is not okay to send.
+ * ppsratecheck(): packets (or events) per second limitation.
*/
static int
-ratecheck(last, limit)
- struct timeval *last;
- struct timeval *limit;
+ppsratecheck(lasttime, curpps, maxpps)
+ struct timeval *lasttime;
+ int *curpps;
+ int maxpps; /* maximum pps allowed */
{
- struct timeval tp;
- struct timeval nextsend;
+ struct timeval tv, delta;
+ int s, rv;
- microtime(&tp);
- tp.tv_sec = time_second;
+ s = splclock();
+ microtime(&tv);
+ splx(s);
- /* rate limit */
- if (last->tv_sec != 0 || last->tv_usec != 0) {
- nextsend.tv_sec = last->tv_sec + limit->tv_sec;
- nextsend.tv_usec = last->tv_usec + limit->tv_usec;
- nextsend.tv_sec += (nextsend.tv_usec / 1000000);
- nextsend.tv_usec %= 1000000;
-
- if (nextsend.tv_sec == tp.tv_sec && nextsend.tv_usec <= tp.tv_usec)
- ;
- else if (nextsend.tv_sec <= tp.tv_sec)
- ;
- else {
- /* The packet is subject to rate limit */
- return 0;
- }
- }
+ timersub(&tv, lasttime, &delta);
+
+ /*
+ * check for 0,0 is so that the message will be seen at least once.
+ * if more than one second have passed since the last update of
+ * lasttime, reset the counter.
+ *
+ * we do increment *curpps even in *curpps < maxpps case, as some may
+ * try to use *curpps for stat purposes as well.
+ */
+ if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
+ delta.tv_sec >= 1) {
+ *lasttime = tv;
+ *curpps = 0;
+ rv = 1;
+ } else if (maxpps < 0)
+ rv = 1;
+ else if (*curpps < maxpps)
+ rv = 1;
+ else
+ rv = 0;
+
+#if 1 /*DIAGNOSTIC?*/
+ /* be careful about wrap-around */
+ if (*curpps + 1 > *curpps)
+ *curpps = *curpps + 1;
+#else
+ /*
+ * assume that there's not too many calls to this function.
+ * not sure if the assumption holds, as it depends on *caller's*
+ * behavior, not the behavior of this function.
+ * IMHO it is wrong to make assumption on the caller's behavior,
+ * so the above #if is #if 1, not #ifdef DIAGNOSTIC.
+ */
+ *curpps = *curpps + 1;
+#endif
- *last = tp;
- return 1;
+ return (rv);
}
#endif
@@ -2578,14 +2848,6 @@ ratecheck(last, limit)
* Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate
* limitation.
*
- * There are two limitations defined:
- * - pps limit: ICMPv6 error packet cannot exceed defined packet-per-second.
- * we measure it every 0.2 second, since fasttimo works every 0.2 second.
- * - rate limit: ICMPv6 error packet cannot appear more than once per
- * defined interval.
- * In any case, if we perform rate limitation, we'll see jitter in the ICMPv6
- * error packets.
- *
* XXX per-destination/type check necessary?
*/
static int
@@ -2599,13 +2861,8 @@ icmp6_ratelimit(dst, type, code)
ret = 0; /*okay to send*/
/* PPS limit */
- icmp6errpps_count++;
- if (icmp6errppslim && icmp6errpps_count > icmp6errppslim / 5) {
- /* The packet is subject to pps limit */
- ret++;
- }
-
- if (!ratecheck(&icmp6errratelim_last, &icmp6errratelim)) {
+ if (!ppsratecheck(&icmp6errppslim_last, &icmp6errpps_count,
+ icmp6errppslim)) {
/* The packet is subject to rate limit */
ret++;
}
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 5f51cef..1fd566b 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6.c,v 1.99 2000/07/11 17:00:58 jinmei Exp $ */
+/* $KAME: in6.c,v 1.187 2001/05/24 07:43:59 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -88,6 +88,11 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/if_ether.h>
+#ifndef SCOPEDROUTING
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#endif
#include <netinet6/nd6.h>
#include <netinet/ip6.h>
@@ -96,6 +101,9 @@
#include <netinet6/ip6_mroute.h>
#include <netinet6/in6_ifattach.h>
#include <netinet6/scope6_var.h>
+#ifndef SCOPEDROUTING
+#include <netinet6/in6_pcb.h>
+#endif
#include "gif.h"
#if NGIF > 0
@@ -124,103 +132,105 @@ const struct in6_addr in6mask64 = IN6MASK64;
const struct in6_addr in6mask96 = IN6MASK96;
const struct in6_addr in6mask128 = IN6MASK128;
+const struct sockaddr_in6 sa6_any = {sizeof(sa6_any), AF_INET6,
+ 0, 0, IN6ADDR_ANY_INIT, 0};
+
static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
struct ifnet *, struct proc *));
+static int in6_ifinit __P((struct ifnet *, struct in6_ifaddr *,
+ struct sockaddr_in6 *, int));
+static void in6_unlink_ifa __P((struct in6_ifaddr *, struct ifnet *));
struct in6_multihead in6_multihead; /* XXX BSS initialization */
/*
- * Check if the loopback entry will be automatically generated.
- * if 0 returned, will not be automatically generated.
- * if 1 returned, will be automatically generated.
- */
-static int
-in6_is_ifloop_auto(struct ifaddr *ifa)
-{
-#define SIN6(s) ((struct sockaddr_in6 *)s)
- /*
- * If RTF_CLONING is unset, or (IFF_LOOPBACK | IFF_POINTOPOINT),
- * or netmask is all0 or all1, then cloning will not happen,
- * then we can't rely on its loopback entry generation.
- */
- if ((ifa->ifa_flags & RTF_CLONING) == 0 ||
- (ifa->ifa_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) ||
- (SIN6(ifa->ifa_netmask)->sin6_len == sizeof(struct sockaddr_in6)
- &&
- IN6_ARE_ADDR_EQUAL(&SIN6(ifa->ifa_netmask)->sin6_addr,
- &in6mask128)) ||
- ((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_len == 0)
- return 0;
- else
- return 1;
-#undef SIN6
-}
-
-/*
* Subroutine for in6_ifaddloop() and in6_ifremloop().
* This routine does actual work.
*/
static void
in6_ifloop_request(int cmd, struct ifaddr *ifa)
{
- struct sockaddr_in6 lo_sa;
struct sockaddr_in6 all1_sa;
- struct rtentry *nrt = NULL, **nrtp = NULL;
+ struct rtentry *nrt = NULL;
+ int e;
- bzero(&lo_sa, sizeof(lo_sa));
bzero(&all1_sa, sizeof(all1_sa));
- lo_sa.sin6_family = AF_INET6;
- lo_sa.sin6_len = sizeof(struct sockaddr_in6);
- all1_sa = lo_sa;
- lo_sa.sin6_addr = in6addr_loopback;
+ all1_sa.sin6_family = AF_INET6;
+ all1_sa.sin6_len = sizeof(struct sockaddr_in6);
all1_sa.sin6_addr = in6mask128;
-
+
/*
- * So we add or remove static loopback entry, here.
- * This request for deletion could fail, e.g. when we remove
- * an address right after adding it.
+ * We specify the address itself as the gateway, and set the
+ * RTF_LLINFO flag, so that the corresponding host route would have
+ * the flag, and thus applications that assume traditional behavior
+ * would be happy. Note that we assume the caller of the function
+ * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest,
+ * which changes the outgoing interface to the loopback interface.
*/
- if (cmd == RTM_ADD)
- nrtp = &nrt;
- rtrequest(cmd, ifa->ifa_addr,
- (struct sockaddr *)&lo_sa,
- (struct sockaddr *)&all1_sa,
- RTF_UP|RTF_HOST, nrtp);
+ e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr,
+ (struct sockaddr *)&all1_sa,
+ RTF_UP|RTF_HOST|RTF_LLINFO, &nrt);
+ if (e != 0) {
+ log(LOG_ERR, "in6_ifloop_request: "
+ "%s operation failed for %s (errno=%d)\n",
+ cmd == RTM_ADD ? "ADD" : "DELETE",
+ ip6_sprintf(&((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr),
+ e);
+ }
/*
* Make sure rt_ifa be equal to IFA, the second argument of the
* function.
- * 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.
+ * We need this because when we refer to rt_ifa->ia6_flags in
+ * ip6_input, we assume that the rt_ifa points to the address instead
+ * of the loopback address.
*/
if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) {
IFAFREE(nrt->rt_ifa);
- ifa->ifa_refcnt++;
+ IFAREF(ifa);
nrt->rt_ifa = ifa;
}
- if (nrt)
- nrt->rt_refcnt--;
+
+ /*
+ * Report the addition/removal of the address to the routing socket.
+ * XXX: since we called rtinit for a p2p interface with a destination,
+ * we end up reporting twice in such a case. Should we rather
+ * omit the second report?
+ */
+ if (nrt) {
+ rt_newaddrmsg(cmd, ifa, e, nrt);
+ if (cmd == RTM_DELETE) {
+ if (nrt->rt_refcnt <= 0) {
+ /* XXX: we should free the entry ourselves. */
+ nrt->rt_refcnt++;
+ rtfree(nrt);
+ }
+ } else {
+ /* the cmd must be RTM_ADD here */
+ nrt->rt_refcnt--;
+ }
+ }
}
/*
- * Add ownaddr as loopback rtentry, if necessary(ex. on p2p link).
- * Because, KAME needs loopback rtentry for ownaddr check in
- * ip6_input().
+ * Add ownaddr as loopback rtentry. We previously add the route only if
+ * necessary (ex. on a p2p link). However, since we now manage addresses
+ * separately from prefixes, we should always add the route. We can't
+ * rely on the cloning mechanism from the corresponding interface route
+ * any more.
*/
static void
in6_ifaddloop(struct ifaddr *ifa)
{
- if (!in6_is_ifloop_auto(ifa)) {
- struct rtentry *rt;
-
- /* If there is no loopback entry, allocate one. */
- rt = rtalloc1(ifa->ifa_addr, 0, 0);
- if (rt == 0 || (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
- in6_ifloop_request(RTM_ADD, ifa);
- if (rt)
- rt->rt_refcnt--;
- }
+ struct rtentry *rt;
+
+ /* If there is no loopback entry, allocate one. */
+ rt = rtalloc1(ifa->ifa_addr, 0, 0);
+ if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
+ (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
+ in6_ifloop_request(RTM_ADD, ifa);
+ if (rt)
+ rt->rt_refcnt--;
}
/*
@@ -231,28 +241,48 @@ static void
in6_ifremloop(struct ifaddr *ifa)
{
struct in6_ifaddr *ia;
+ struct rtentry *rt;
int ia_count = 0;
/*
- * All BSD variants except BSD/OS do not remove cloned routes
+ * Some of BSD variants do not remove cloned routes
* from an interface direct route, when removing the direct route
- * (see commens in net/net_osdep.h).
- * So we should remove the route corresponding to the deleted address
+ * (see comments in net/net_osdep.h). Even for variants that do remove
+ * cloned routes, they could fail to remove the cloned routes when
+ * we handle multple addresses that share a common prefix.
+ * So, we should remove the route corresponding to the deleted address
* regardless of the result of in6_is_ifloop_auto().
*/
- if (1)
- {
- /* If only one ifa for the loopback entry, delete it. */
- for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
- if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa),
- &ia->ia_addr.sin6_addr)) {
- ia_count++;
- if (ia_count > 1)
- break;
- }
+
+ /*
+ * Delete the entry only if exact one ifa exists. More than one ifa
+ * can exist if we assign a same single address to multiple
+ * (probably p2p) interfaces.
+ * XXX: we should avoid such a configuration in IPv6...
+ */
+ for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
+ if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr)) {
+ ia_count++;
+ if (ia_count > 1)
+ break;
}
- if (ia_count == 1)
+ }
+
+ if (ia_count == 1) {
+ /*
+ * Before deleting, check if a corresponding loopbacked host
+ * route surely exists. With this check, we can avoid to
+ * delete an interface direct route whose destination is same
+ * as the address being removed. This can happen when remofing
+ * a subnet-router anycast address on an interface attahced
+ * to a shared medium.
+ */
+ rt = rtalloc1(ifa->ifa_addr, 0, 0);
+ if (rt != NULL && (rt->rt_flags & RTF_HOST) != 0 &&
+ (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
+ rt->rt_refcnt--;
in6_ifloop_request(RTM_DELETE, ifa);
+ }
}
}
@@ -281,22 +311,40 @@ in6_ifindex2scopeid(idx)
}
int
-in6_mask2len(mask)
+in6_mask2len(mask, lim0)
struct in6_addr *mask;
+ u_char *lim0;
{
- int x, y;
-
- for (x = 0; x < sizeof(*mask); x++) {
- if (mask->s6_addr8[x] != 0xff)
+ int x = 0, y;
+ u_char *lim = lim0, *p;
+
+ if (lim0 == NULL ||
+ lim0 - (u_char *)mask > sizeof(*mask)) /* ignore the scope_id part */
+ lim = (u_char *)mask + sizeof(*mask);
+ for (p = (u_char *)mask; p < lim; x++, p++) {
+ if (*p != 0xff)
break;
}
y = 0;
- if (x < sizeof(*mask)) {
+ if (p < lim) {
for (y = 0; y < 8; y++) {
- if ((mask->s6_addr8[x] & (0x80 >> y)) == 0)
+ if ((*p & (0x80 >> y)) == 0)
break;
}
}
+
+ /*
+ * when the limit pointer is given, do a stricter check on the
+ * remaining bits.
+ */
+ if (p < lim) {
+ if (y != 0 && (*p & (0x00ff >> y)) != 0)
+ return(-1);
+ for (p = p + 1; p < lim; p++)
+ if (*p != 0)
+ return(-1);
+ }
+
return x * 8 + y;
}
@@ -326,36 +374,14 @@ in6_control(so, cmd, data, ifp, p)
struct proc *p;
{
struct in6_ifreq *ifr = (struct in6_ifreq *)data;
- struct in6_ifaddr *ia = NULL, *oia;
+ struct in6_ifaddr *ia = NULL;
struct in6_aliasreq *ifra = (struct in6_aliasreq *)data;
- struct sockaddr_in6 oldaddr;
-#ifdef COMPAT_IN6IFIOCTL
- struct sockaddr_in6 net;
-#endif
- int error = 0, hostIsNew, prefixIsNew;
- int newifaddr;
int privileged;
privileged = 0;
if (p == NULL || !suser(p))
privileged++;
- /*
- * xxx should prevent processes for link-local addresses?
- */
-#if NGIF > 0
- if (ifp && ifp->if_type == IFT_GIF) {
- switch (cmd) {
- case SIOCSIFPHYADDR_IN6:
- if (!privileged)
- return(EPERM);
- /*fall through*/
- case SIOCGIFPSRCADDR_IN6:
- case SIOCGIFPDSTADDR_IN6:
- return gif_ioctl(ifp, cmd, data);
- }
- }
-#endif
switch (cmd) {
case SIOCGETSGCNT_IN6:
case SIOCGETMIFCNT_IN6:
@@ -374,6 +400,7 @@ in6_control(so, cmd, data, ifp, p)
if (!privileged)
return(EPERM);
/*fall through*/
+ case OSIOCGIFINFO_IN6:
case SIOCGIFINFO_IN6:
case SIOCGDRLST_IN6:
case SIOCGPRLST_IN6:
@@ -388,13 +415,11 @@ in6_control(so, cmd, data, ifp, p)
case SIOCAIFPREFIX_IN6:
case SIOCCIFPREFIX_IN6:
case SIOCSGIFPREFIX_IN6:
- if (!privileged)
- return(EPERM);
- /*fall through*/
case SIOCGIFPREFIX_IN6:
- if (ip6_forwarding == 0)
- return(EPERM);
- return(in6_prefix_ioctl(so, cmd, data, ifp));
+ log(LOG_NOTICE,
+ "prefix ioctls are now invalidated. "
+ "please use ifconfig.\n");
+ return(EOPNOTSUPP);
}
switch(cmd) {
@@ -430,12 +455,12 @@ in6_control(so, cmd, data, ifp, p)
if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
if (sa6->sin6_addr.s6_addr16[1] == 0) {
- /* interface ID is not embedded by the user */
+ /* link ID is not embedded by the user */
sa6->sin6_addr.s6_addr16[1] =
htons(ifp->if_index);
} else if (sa6->sin6_addr.s6_addr16[1] !=
htons(ifp->if_index)) {
- return(EINVAL); /* ifid is contradict */
+ return(EINVAL); /* link ID contradicts */
}
if (sa6->sin6_scope_id) {
if (sa6->sin6_scope_id !=
@@ -448,92 +473,39 @@ in6_control(so, cmd, data, ifp, p)
}
switch (cmd) {
+ case SIOCSIFADDR_IN6:
+ case SIOCSIFDSTADDR_IN6:
+ case SIOCSIFNETMASK_IN6:
+ /*
+ * Since IPv6 allows a node to assign multiple addresses
+ * on a single interface, SIOCSIFxxx ioctls are not suitable
+ * and should be unused.
+ */
+ /* we decided to obsolete this command (20000704) */
+ return(EINVAL);
case SIOCDIFADDR_IN6:
/*
- * for IPv4, we look for existing in6_ifaddr here to allow
+ * for IPv4, we look for existing in_ifaddr here to allow
* "ifconfig if0 delete" to remove first IPv4 address on the
* interface. For IPv6, as the spec allow multiple interface
* address from the day one, we consider "remove the first one"
- * semantics to be not preferrable.
+ * semantics to be not preferable.
*/
if (ia == NULL)
return(EADDRNOTAVAIL);
/* FALLTHROUGH */
case SIOCAIFADDR_IN6:
- case SIOCSIFADDR_IN6:
-#ifdef COMPAT_IN6IFIOCTL
- case SIOCSIFDSTADDR_IN6:
- case SIOCSIFNETMASK_IN6:
/*
- * Since IPv6 allows a node to assign multiple addresses
- * on a single interface, SIOCSIFxxx ioctls are not suitable
- * and should be unused.
+ * We always require users to specify a valid IPv6 address for
+ * the corresponding operation.
*/
-#endif
- if (ifra->ifra_addr.sin6_family != AF_INET6)
+ if (ifra->ifra_addr.sin6_family != AF_INET6 ||
+ ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6))
return(EAFNOSUPPORT);
if (!privileged)
return(EPERM);
- if (ia == NULL) {
- ia = (struct in6_ifaddr *)
- malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
- if (ia == NULL)
- return (ENOBUFS);
- bzero((caddr_t)ia, sizeof(*ia));
- /* Initialize the address and masks */
- ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
- ia->ia_addr.sin6_family = AF_INET6;
- ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
-#if 1
- if (ifp->if_flags & IFF_POINTOPOINT) {
- ia->ia_ifa.ifa_dstaddr
- = (struct sockaddr *)&ia->ia_dstaddr;
- ia->ia_dstaddr.sin6_family = AF_INET6;
- ia->ia_dstaddr.sin6_len = sizeof(ia->ia_dstaddr);
- } else {
- ia->ia_ifa.ifa_dstaddr = NULL;
- bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
- }
-#else /* always initilize by NULL */
- ia->ia_ifa.ifa_dstaddr = NULL;
- bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
-#endif
- ia->ia_ifa.ifa_netmask
- = (struct sockaddr *)&ia->ia_prefixmask;
-
- ia->ia_ifp = ifp;
- if ((oia = in6_ifaddr) != NULL) {
- for ( ; oia->ia_next; oia = oia->ia_next)
- continue;
- oia->ia_next = ia;
- } else
- in6_ifaddr = ia;
- /* gain a refcnt for the link from in6_ifaddr */
- ia->ia_ifa.ifa_refcnt++;
- TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa,
- ifa_list);
- /* gain another refcnt for the link from if_addrlist */
- ia->ia_ifa.ifa_refcnt++;
-
- newifaddr = 1;
- } else
- newifaddr = 0;
-
- if (cmd == SIOCAIFADDR_IN6) {
- /* sanity for overflow - beware unsigned */
- struct in6_addrlifetime *lt;
- lt = &ifra->ifra_lifetime;
- if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME
- && lt->ia6t_vltime + time_second < time_second) {
- return EINVAL;
- }
- if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME
- && lt->ia6t_pltime + time_second < time_second) {
- return EINVAL;
- }
- }
break;
case SIOCGIFADDR_IN6:
@@ -618,42 +590,6 @@ in6_control(so, cmd, data, ifp, p)
*icmp6_ifstat[ifp->if_index];
break;
-#ifdef COMPAT_IN6IFIOCTL /* should be unused */
- case SIOCSIFDSTADDR_IN6:
- if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
- return(EINVAL);
- oldaddr = ia->ia_dstaddr;
- ia->ia_dstaddr = ifr->ifr_dstaddr;
-
- /* link-local index check */
- if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) {
- if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) {
- /* interface ID is not embedded by the user */
- ia->ia_dstaddr.sin6_addr.s6_addr16[1]
- = htons(ifp->if_index);
- } else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] !=
- htons(ifp->if_index)) {
- ia->ia_dstaddr = oldaddr;
- return(EINVAL); /* ifid is contradict */
- }
- }
-
- if (ifp->if_ioctl && (error = (ifp->if_ioctl)
- (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
- ia->ia_dstaddr = oldaddr;
- return(error);
- }
- ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
- if (ia->ia_flags & IFA_ROUTE) {
- ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
- rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
- ia->ia_ifa.ifa_dstaddr =
- (struct sockaddr *)&ia->ia_dstaddr;
- rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
- }
- break;
-
-#endif
case SIOCGIFALIFETIME_IN6:
ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime;
break;
@@ -673,129 +609,400 @@ in6_control(so, cmd, data, ifp, p)
ia->ia6_lifetime.ia6t_preferred = 0;
break;
- case SIOCSIFADDR_IN6:
- error = in6_ifinit(ifp, ia, &ifr->ifr_addr, 1);
-#if 0
+ case SIOCAIFADDR_IN6:
+ {
+ int i, error = 0;
+ struct nd_prefix pr0, *pr;
+
+ /*
+ * first, make or update the interface address structure,
+ * and link it to the list.
+ */
+ if ((error = in6_update_ifa(ifp, ifra, ia)) != 0)
+ return(error);
+
/*
- * the code chokes if we are to assign multiple addresses with
- * the same address prefix (rtinit() will return EEXIST, which
- * is not fatal actually). we will get memory leak if we
- * don't do it.
- * -> we may want to hide EEXIST from rtinit().
+ * then, make the prefix on-link on the interface.
+ * XXX: we'd rather create the prefix before the address, but
+ * we need at least one address to install the corresponding
+ * interface route, so we configure the address first.
*/
- undo:
- if (error && newifaddr) {
- TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
- /* release a refcnt for the link from if_addrlist */
- IFAFREE(&ia->ia_ifa);
-
- oia = ia;
- if (oia == (ia = in6_ifaddr))
- in6_ifaddr = ia->ia_next;
- else {
- while (ia->ia_next && (ia->ia_next != oia))
- ia = ia->ia_next;
- if (ia->ia_next)
- ia->ia_next = oia->ia_next;
- else {
- printf("Didn't unlink in6_ifaddr "
- "from list\n");
+
+ /*
+ * convert mask to prefix length (prefixmask has already
+ * been validated in in6_update_ifa().
+ */
+ bzero(&pr0, sizeof(pr0));
+ pr0.ndpr_ifp = ifp;
+ pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
+ NULL);
+ if (pr0.ndpr_plen == 128)
+ break; /* we don't need to install a host route. */
+ pr0.ndpr_prefix = ifra->ifra_addr;
+ pr0.ndpr_mask = ifra->ifra_prefixmask.sin6_addr;
+ /* apply the mask for safety. */
+ for (i = 0; i < 4; i++) {
+ pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
+ ifra->ifra_prefixmask.sin6_addr.s6_addr32[i];
+ }
+ /*
+ * XXX: since we don't have enough APIs, we just set inifinity
+ * to lifetimes. They can be overridden by later advertised
+ * RAs (when accept_rtadv is non 0), but we'd rather intend
+ * such a behavior.
+ */
+ pr0.ndpr_raf_onlink = 1; /* should be configurable? */
+ pr0.ndpr_raf_auto =
+ ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0);
+ pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime;
+ pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime;
+
+ /* add the prefix if there's one. */
+ if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {
+ /*
+ * nd6_prelist_add will install the corresponding
+ * interface route.
+ */
+ if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0)
+ return(error);
+ if (pr == NULL) {
+ log(LOG_ERR, "nd6_prelist_add succedded but "
+ "no prefix\n");
+ return(EINVAL); /* XXX panic here? */
+ }
+ }
+ if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
+ == NULL) {
+ /* XXX: this should not happen! */
+ log(LOG_ERR, "in6_control: addition succeeded, but"
+ " no ifaddr\n");
+ } else {
+ if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 &&
+ ia->ia6_ndpr == NULL) { /* new autoconfed addr */
+ ia->ia6_ndpr = pr;
+ pr->ndpr_refcnt++;
+
+ /*
+ * If this is the first autoconf address from
+ * the prefix, create a temporary address
+ * as well (when specified).
+ */
+ if (ip6_use_tempaddr &&
+ pr->ndpr_refcnt == 1) {
+ int e;
+ if ((e = in6_tmpifadd(ia, 1)) != 0) {
+ log(LOG_NOTICE, "in6_control: "
+ "failed to create a "
+ "temporary address, "
+ "errno=%d\n",
+ e);
+ }
}
}
- /* release another refcnt for the link from in6_ifaddr */
- IFAFREE(&oia->ia_ifa);
+
+ /*
+ * this might affect the status of autoconfigured
+ * addresses, that is, this address might make
+ * other addresses detached.
+ */
+ pfxlist_onlink_check();
}
-#endif
- return error;
+ break;
+ }
-#ifdef COMPAT_IN6IFIOCTL /* XXX should be unused */
- case SIOCSIFNETMASK_IN6:
- ia->ia_prefixmask = ifr->ifr_addr;
- bzero(&net, sizeof(net));
- net.sin6_len = sizeof(struct sockaddr_in6);
- net.sin6_family = AF_INET6;
- net.sin6_port = htons(0);
- net.sin6_flowinfo = htonl(0);
- net.sin6_addr.s6_addr32[0]
- = ia->ia_addr.sin6_addr.s6_addr32[0] &
- ia->ia_prefixmask.sin6_addr.s6_addr32[0];
- net.sin6_addr.s6_addr32[1]
- = ia->ia_addr.sin6_addr.s6_addr32[1] &
- ia->ia_prefixmask.sin6_addr.s6_addr32[1];
- net.sin6_addr.s6_addr32[2]
- = ia->ia_addr.sin6_addr.s6_addr32[2] &
- ia->ia_prefixmask.sin6_addr.s6_addr32[2];
- net.sin6_addr.s6_addr32[3]
- = ia->ia_addr.sin6_addr.s6_addr32[3] &
- ia->ia_prefixmask.sin6_addr.s6_addr32[3];
- ia->ia_net = net;
+ case SIOCDIFADDR_IN6:
+ {
+ int i = 0;
+ struct nd_prefix pr0, *pr;
+
+ /*
+ * If the address being deleted is the only one that owns
+ * the corresponding prefix, expire the prefix as well.
+ * XXX: theoretically, we don't have to warry about such
+ * relationship, since we separate the address management
+ * and the prefix management. We do this, however, to provide
+ * as much backward compatibility as possible in terms of
+ * the ioctl operation.
+ */
+ bzero(&pr0, sizeof(pr0));
+ pr0.ndpr_ifp = ifp;
+ pr0.ndpr_plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr,
+ NULL);
+ if (pr0.ndpr_plen == 128)
+ goto purgeaddr;
+ pr0.ndpr_prefix = ia->ia_addr;
+ pr0.ndpr_mask = ia->ia_prefixmask.sin6_addr;
+ for (i = 0; i < 4; i++) {
+ pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
+ ia->ia_prefixmask.sin6_addr.s6_addr32[i];
+ }
+ /*
+ * The logic of the following condition is a bit complicated.
+ * We expire the prefix when
+ * 1. the address obeys autoconfiguration and it is the
+ * only owner of the associated prefix, or
+ * 2. the address does not obey autoconf and there is no
+ * other owner of the prefix.
+ */
+ if ((pr = nd6_prefix_lookup(&pr0)) != NULL &&
+ (((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 &&
+ pr->ndpr_refcnt == 1) ||
+ ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0 &&
+ pr->ndpr_refcnt == 0))) {
+ pr->ndpr_expire = 1; /* XXX: just for expiration */
+ }
+
+ purgeaddr:
+ in6_purgeaddr(&ia->ia_ifa);
break;
-#endif
+ }
- case SIOCAIFADDR_IN6:
- prefixIsNew = 0;
- hostIsNew = 1;
+ default:
+ if (ifp == NULL || ifp->if_ioctl == 0)
+ return(EOPNOTSUPP);
+ return((*ifp->if_ioctl)(ifp, cmd, data));
+ }
+
+ return(0);
+}
+
+/*
+ * Update parameters of an IPv6 interface address.
+ * If necessary, a new entry is created and linked into address chains.
+ * This function is separated from in6_control().
+ * XXX: should this be performed under splnet()?
+ */
+int
+in6_update_ifa(ifp, ifra, ia)
+ struct ifnet *ifp;
+ struct in6_aliasreq *ifra;
+ struct in6_ifaddr *ia;
+{
+ int error = 0, hostIsNew = 0, plen = -1;
+ struct in6_ifaddr *oia;
+ struct sockaddr_in6 dst6;
+ struct in6_addrlifetime *lt;
- if (ifra->ifra_addr.sin6_len == 0) {
- ifra->ifra_addr = ia->ia_addr;
- hostIsNew = 0;
- } else if (IN6_ARE_ADDR_EQUAL(&ifra->ifra_addr.sin6_addr,
- &ia->ia_addr.sin6_addr))
- hostIsNew = 0;
+ /* Validate parameters */
+ if (ifp == NULL || ifra == NULL) /* this maybe redundant */
+ return(EINVAL);
- /* Validate address families: */
+ /*
+ * The destination address for a p2p link must have a family
+ * of AF_UNSPEC or AF_INET6.
+ */
+ if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
+ ifra->ifra_dstaddr.sin6_family != AF_INET6 &&
+ ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
+ return(EAFNOSUPPORT);
+ /*
+ * validate ifra_prefixmask. don't check sin6_family, netmask
+ * does not carry fields other than sin6_len.
+ */
+ if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6))
+ return(EINVAL);
+ /*
+ * Because the IPv6 address architecture is classless, we require
+ * users to specify a (non 0) prefix length (mask) for a new address.
+ * We also require the prefix (when specified) mask is valid, and thus
+ * reject a non-consecutive mask.
+ */
+ if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0)
+ return(EINVAL);
+ if (ifra->ifra_prefixmask.sin6_len != 0) {
+ plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
+ (u_char *)&ifra->ifra_prefixmask +
+ ifra->ifra_prefixmask.sin6_len);
+ if (plen <= 0)
+ return(EINVAL);
+ }
+ else {
/*
- * The destination address for a p2p link must have a family
- * of AF_UNSPEC or AF_INET6.
+ * In this case, ia must not be NULL. We just use its prefix
+ * length.
*/
- if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
- ifra->ifra_dstaddr.sin6_family != AF_INET6 &&
- ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
- return(EAFNOSUPPORT);
+ plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);
+ }
+ /*
+ * If the destination address on a p2p interface is specified,
+ * and the address is a scoped one, validate/set the scope
+ * zone identifier.
+ */
+ dst6 = ifra->ifra_dstaddr;
+ if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) &&
+ (dst6.sin6_family == AF_INET6)) {
+ int scopeid;
+
+#ifndef SCOPEDROUTING
+ if ((error = in6_recoverscope(&dst6,
+ &ifra->ifra_dstaddr.sin6_addr,
+ ifp)) != 0)
+ return(error);
+#endif
+ scopeid = in6_addr2scopeid(ifp, &dst6.sin6_addr);
+ if (dst6.sin6_scope_id == 0) /* user omit to specify the ID. */
+ dst6.sin6_scope_id = scopeid;
+ else if (dst6.sin6_scope_id != scopeid)
+ return(EINVAL); /* scope ID mismatch. */
+#ifndef SCOPEDROUTING
+ if ((error = in6_embedscope(&dst6.sin6_addr, &dst6, NULL, NULL))
+ != 0)
+ return(error);
+ dst6.sin6_scope_id = 0; /* XXX */
+#endif
+ }
+ /*
+ * The destination address can be specified only for a p2p or a
+ * loopback interface. If specified, the corresponding prefix length
+ * must be 128.
+ */
+ if (ifra->ifra_dstaddr.sin6_family == AF_INET6) {
+ if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) {
+ /* XXX: noisy message */
+ log(LOG_INFO, "in6_update_ifa: a destination can be "
+ "specified for a p2p or a loopback IF only\n");
+ return(EINVAL);
+ }
+ if (plen != 128) {
+ /*
+ * The following message seems noisy, but we dare to
+ * add it for diagnosis.
+ */
+ log(LOG_INFO, "in6_update_ifa: prefixlen must be 128 "
+ "when dstaddr is specified\n");
+ return(EINVAL);
+ }
+ }
+ /* lifetime consistency check */
+ lt = &ifra->ifra_lifetime;
+ if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME
+ && lt->ia6t_vltime + time_second < time_second) {
+ return EINVAL;
+ }
+ if (lt->ia6t_vltime == 0) {
/*
- * The prefixmask must have a family of AF_UNSPEC or AF_INET6.
+ * the following log might be noisy, but this is a typical
+ * configuration mistake or a tool's bug.
*/
- if (ifra->ifra_prefixmask.sin6_family != AF_INET6 &&
- ifra->ifra_prefixmask.sin6_family != AF_UNSPEC)
- return(EAFNOSUPPORT);
+ log(LOG_INFO,
+ "in6_update_ifa: valid lifetime is 0 for %s\n",
+ ip6_sprintf(&ifra->ifra_addr.sin6_addr));
+ }
+ if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME
+ && lt->ia6t_pltime + time_second < time_second) {
+ return EINVAL;
+ }
- if (ifra->ifra_prefixmask.sin6_len) {
- in6_ifscrub(ifp, ia);
- ia->ia_prefixmask = ifra->ifra_prefixmask;
- prefixIsNew = 1;
+ /*
+ * If this is a new address, allocate a new ifaddr and link it
+ * into chains.
+ */
+ if (ia == NULL) {
+ hostIsNew = 1;
+ ia = (struct in6_ifaddr *)
+ malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
+ if (ia == NULL)
+ return (ENOBUFS);
+ bzero((caddr_t)ia, sizeof(*ia));
+ /* Initialize the address and masks */
+ ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
+ ia->ia_addr.sin6_family = AF_INET6;
+ ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
+ if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) {
+ /*
+ * XXX: some functions expect that ifa_dstaddr is not
+ * NULL for p2p interfaces.
+ */
+ ia->ia_ifa.ifa_dstaddr
+ = (struct sockaddr *)&ia->ia_dstaddr;
+ } else {
+ ia->ia_ifa.ifa_dstaddr = NULL;
}
- if ((ifp->if_flags & IFF_POINTOPOINT) &&
- (ifra->ifra_dstaddr.sin6_family == AF_INET6)) {
- in6_ifscrub(ifp, ia);
- oldaddr = ia->ia_dstaddr;
- ia->ia_dstaddr = ifra->ifra_dstaddr;
- /* link-local index check: should be a separate function? */
- if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) {
- if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) {
- /*
- * interface ID is not embedded by
- * the user
- */
- ia->ia_dstaddr.sin6_addr.s6_addr16[1]
- = htons(ifp->if_index);
- } else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] !=
- htons(ifp->if_index)) {
- ia->ia_dstaddr = oldaddr;
- return(EINVAL); /* ifid is contradict */
- }
- }
- prefixIsNew = 1; /* We lie; but effect's the same */
+ ia->ia_ifa.ifa_netmask
+ = (struct sockaddr *)&ia->ia_prefixmask;
+
+ ia->ia_ifp = ifp;
+ if ((oia = in6_ifaddr) != NULL) {
+ for ( ; oia->ia_next; oia = oia->ia_next)
+ continue;
+ oia->ia_next = ia;
+ } else
+ in6_ifaddr = ia;
+
+ TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa,
+ ifa_list);
+ }
+
+ /* set prefix mask */
+ if (ifra->ifra_prefixmask.sin6_len) {
+ /*
+ * We prohibit changing the prefix length of an existing
+ * address, because
+ * + such an operation should be rare in IPv6, and
+ * + the operation would confuse prefix management.
+ */
+ if (ia->ia_prefixmask.sin6_len &&
+ in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) {
+ log(LOG_INFO, "in6_update_ifa: the prefix length of an"
+ " existing (%s) address should not be changed\n",
+ ip6_sprintf(&ia->ia_addr.sin6_addr));
+ error = EINVAL;
+ goto unlink;
}
- if (hostIsNew || prefixIsNew) {
- error = in6_ifinit(ifp, ia, &ifra->ifra_addr, 0);
-#if 0
- if (error)
- goto undo;
-#endif
+ ia->ia_prefixmask = ifra->ifra_prefixmask;
+ }
+
+ /*
+ * If a new destination address is specified, scrub the old one and
+ * install the new destination. Note that the interface must be
+ * p2p or loopback (see the check above.)
+ */
+ if (dst6.sin6_family == AF_INET6 &&
+ !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr,
+ &ia->ia_dstaddr.sin6_addr)) {
+ int e;
+
+ if ((ia->ia_flags & IFA_ROUTE) != 0 &&
+ (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST))
+ != 0) {
+ log(LOG_ERR, "in6_update_ifa: failed to remove "
+ "a route to the old destination: %s\n",
+ ip6_sprintf(&ia->ia_addr.sin6_addr));
+ /* proceed anyway... */
}
- if (hostIsNew && (ifp->if_flags & IFF_MULTICAST)) {
- int error_local = 0;
+ else
+ ia->ia_flags &= ~IFA_ROUTE;
+ ia->ia_dstaddr = dst6;
+ }
+ /* reset the interface and routing table appropriately. */
+ if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0)
+ goto unlink;
+
+ /*
+ * Beyond this point, we should call in6_purgeaddr upon an error,
+ * not just go to unlink.
+ */
+
+#if 0 /* disable this mechanism for now */
+ /* update prefix list */
+ if (hostIsNew &&
+ (ifra->ifra_flags & IN6_IFF_NOPFX) == 0) { /* XXX */
+ int iilen;
+
+ iilen = (sizeof(ia->ia_prefixmask.sin6_addr) << 3) - plen;
+ if ((error = in6_prefix_add_ifid(iilen, ia)) != 0) {
+ in6_purgeaddr((struct ifaddr *)ia);
+ return(error);
+ }
+ }
+#endif
+
+ if ((ifp->if_flags & IFF_MULTICAST) != 0) {
+ struct sockaddr_in6 mltaddr, mltmask;
+ struct in6_multi *in6m;
+
+ if (hostIsNew) {
/*
* join solicited multicast addr for new host id
*/
@@ -808,98 +1015,182 @@ in6_control(so, cmd, data, ifp, p)
llsol.s6_addr32[3] =
ifra->ifra_addr.sin6_addr.s6_addr32[3];
llsol.s6_addr8[12] = 0xff;
- (void)in6_addmulti(&llsol, ifp, &error_local);
- if (error == 0)
- error = error_local;
+ (void)in6_addmulti(&llsol, ifp, &error);
+ if (error != 0) {
+ log(LOG_WARNING,
+ "in6_update_ifa: addmulti failed for "
+ "%s on %s (errno=%d)\n",
+ ip6_sprintf(&llsol), if_name(ifp),
+ error);
+ in6_purgeaddr((struct ifaddr *)ia);
+ return(error);
+ }
}
- ia->ia6_flags = ifra->ifra_flags;
- ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /*safety*/
-
- ia->ia6_lifetime = ifra->ifra_lifetime;
- /* for sanity */
- if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
- ia->ia6_lifetime.ia6t_expire =
- time_second + ia->ia6_lifetime.ia6t_vltime;
- } else
- ia->ia6_lifetime.ia6t_expire = 0;
- if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
- ia->ia6_lifetime.ia6t_preferred =
- time_second + ia->ia6_lifetime.ia6t_pltime;
- } else
- ia->ia6_lifetime.ia6t_preferred = 0;
+ bzero(&mltmask, sizeof(mltmask));
+ mltmask.sin6_len = sizeof(struct sockaddr_in6);
+ mltmask.sin6_family = AF_INET6;
+ mltmask.sin6_addr = in6mask32;
/*
- * make sure to initialize ND6 information. this is to
- * workaround issues with interfaces with IPv6 addresses,
- * which have never brought # up. we are assuming that it is
- * safe to nd6_ifattach multiple times.
+ * join link-local all-nodes address
*/
- nd6_ifattach(ifp);
+ bzero(&mltaddr, sizeof(mltaddr));
+ mltaddr.sin6_len = sizeof(struct sockaddr_in6);
+ mltaddr.sin6_family = AF_INET6;
+ mltaddr.sin6_addr = in6addr_linklocal_allnodes;
+ mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
+
+ IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
+ if (in6m == NULL) {
+ rtrequest(RTM_ADD,
+ (struct sockaddr *)&mltaddr,
+ (struct sockaddr *)&ia->ia_addr,
+ (struct sockaddr *)&mltmask,
+ RTF_UP|RTF_CLONING, /* xxx */
+ (struct rtentry **)0);
+ (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
+ if (error != 0) {
+ log(LOG_WARNING,
+ "in6_update_ifa: addmulti failed for "
+ "%s on %s (errno=%d)\n",
+ ip6_sprintf(&mltaddr.sin6_addr),
+ if_name(ifp), error);
+ }
+ }
/*
- * Perform DAD, if needed.
- * XXX It may be of use, if we can administratively
- * disable DAD.
+ * join node information group address
*/
- switch (ifp->if_type) {
- case IFT_ARCNET:
- case IFT_ETHER:
- case IFT_FDDI:
-#if 0
- case IFT_ATM:
- case IFT_SLIP:
- case IFT_PPP:
-#endif
- {
- ia->ia6_flags |= IN6_IFF_TENTATIVE;
- nd6_dad_start((struct ifaddr *)ia, NULL);
+#define hostnamelen strlen(hostname)
+ if (in6_nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr)
+ == 0) {
+ IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
+ if (in6m == NULL && ia != NULL) {
+ (void)in6_addmulti(&mltaddr.sin6_addr,
+ ifp, &error);
+ if (error != 0) {
+ log(LOG_WARNING, "in6_update_ifa: "
+ "addmulti failed for "
+ "%s on %s (errno=%d)\n",
+ ip6_sprintf(&mltaddr.sin6_addr),
+ if_name(ifp), error);
+ }
}
- break;
-#ifdef IFT_DUMMY
- case IFT_DUMMY:
-#endif
- case IFT_FAITH:
- case IFT_GIF:
- case IFT_LOOP:
- default:
- break;
}
+#undef hostnamelen
- if (hostIsNew) {
- int iilen;
- int error_local = 0;
-
- iilen = (sizeof(ia->ia_prefixmask.sin6_addr) << 3) -
- in6_mask2len(&ia->ia_prefixmask.sin6_addr);
- error_local = in6_prefix_add_ifid(iilen, ia);
- if (error == 0)
- error = error_local;
+ /*
+ * join node-local all-nodes address, on loopback.
+ * XXX: since "node-local" is obsoleted by interface-local,
+ * we have to join the group on every interface with
+ * some interface-boundary restriction.
+ */
+ if (ifp->if_flags & IFF_LOOPBACK) {
+ struct in6_addr loop6 = in6addr_loopback;
+ ia = in6ifa_ifpwithaddr(ifp, &loop6);
+
+ mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
+
+ IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
+ if (in6m == NULL && ia != NULL) {
+ rtrequest(RTM_ADD,
+ (struct sockaddr *)&mltaddr,
+ (struct sockaddr *)&ia->ia_addr,
+ (struct sockaddr *)&mltmask,
+ RTF_UP,
+ (struct rtentry **)0);
+ (void)in6_addmulti(&mltaddr.sin6_addr, ifp,
+ &error);
+ if (error != 0) {
+ log(LOG_WARNING, "in6_update_ifa: "
+ "addmulti failed for %s on %s "
+ "(errno=%d)\n",
+ ip6_sprintf(&mltaddr.sin6_addr),
+ if_name(ifp), error);
+ }
+ }
}
+ }
- return(error);
+ ia->ia6_flags = ifra->ifra_flags;
+ ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /*safety*/
+ ia->ia6_flags &= ~IN6_IFF_NODAD; /* Mobile IPv6 */
+
+ ia->ia6_lifetime = ifra->ifra_lifetime;
+ /* for sanity */
+ if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
+ ia->ia6_lifetime.ia6t_expire =
+ time_second + ia->ia6_lifetime.ia6t_vltime;
+ } else
+ ia->ia6_lifetime.ia6t_expire = 0;
+ if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
+ ia->ia6_lifetime.ia6t_preferred =
+ time_second + ia->ia6_lifetime.ia6t_pltime;
+ } else
+ ia->ia6_lifetime.ia6t_preferred = 0;
- case SIOCDIFADDR_IN6:
- in6_purgeaddr(&ia->ia_ifa, ifp);
- break;
+ /*
+ * make sure to initialize ND6 information. this is to workaround
+ * issues with interfaces with IPv6 addresses, which have never brought
+ * up. We are assuming that it is safe to nd6_ifattach multiple times.
+ */
+ nd6_ifattach(ifp);
- default:
- if (ifp == NULL || ifp->if_ioctl == 0)
- return(EOPNOTSUPP);
- return((*ifp->if_ioctl)(ifp, cmd, data));
+ /*
+ * Perform DAD, if needed.
+ * XXX It may be of use, if we can administratively
+ * disable DAD.
+ */
+ if (in6if_do_dad(ifp) && (ifra->ifra_flags & IN6_IFF_NODAD) == 0) {
+ ia->ia6_flags |= IN6_IFF_TENTATIVE;
+ nd6_dad_start((struct ifaddr *)ia, NULL);
}
- return(0);
+
+ return(error);
+
+ unlink:
+ /*
+ * XXX: if a change of an existing address failed, keep the entry
+ * anyway.
+ */
+ if (hostIsNew)
+ in6_unlink_ifa(ia, ifp);
+ return(error);
}
void
-in6_purgeaddr(ifa, ifp)
+in6_purgeaddr(ifa)
struct ifaddr *ifa;
- struct ifnet *ifp;
{
- struct in6_ifaddr *oia, *ia = (void *) ifa;
- int plen;
+ struct ifnet *ifp = ifa->ifa_ifp;
+ struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
- in6_ifscrub(ifp, ia);
+ /* stop DAD processing */
+ nd6_dad_stop(ifa);
+
+ /*
+ * delete route to the destination of the address being purged.
+ * The interface must be p2p or loopback in this case.
+ */
+ if ((ia->ia_flags & IFA_ROUTE) != 0 && ia->ia_dstaddr.sin6_len != 0) {
+ int e;
+
+ if ((e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST))
+ != 0) {
+ log(LOG_ERR, "in6_purgeaddr: failed to remove "
+ "a route to the p2p destination: %s on %s, "
+ "errno=%d\n",
+ ip6_sprintf(&ia->ia_addr.sin6_addr), if_name(ifp),
+ e);
+ /* proceed anyway... */
+ }
+ else
+ ia->ia_flags &= ~IFA_ROUTE;
+ }
+
+ /* Remove ownaddr's loopback rtentry, if it exists. */
+ in6_ifremloop(&(ia->ia_ifa));
if (ifp->if_flags & IFF_MULTICAST) {
/*
@@ -921,9 +1212,19 @@ in6_purgeaddr(ifa, ifp)
in6_delmulti(in6m);
}
+ in6_unlink_ifa(ia, ifp);
+}
+
+static void
+in6_unlink_ifa(ia, ifp)
+ struct in6_ifaddr *ia;
+ struct ifnet *ifp;
+{
+ int plen, iilen;
+ struct in6_ifaddr *oia;
+ int s = splnet();
+
TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
- /* release a refcnt for the link from if_addrlist */
- IFAFREE(&ia->ia_ifa);
oia = ia;
if (oia == (ia = in6_ifaddr))
@@ -933,45 +1234,61 @@ in6_purgeaddr(ifa, ifp)
ia = ia->ia_next;
if (ia->ia_next)
ia->ia_next = oia->ia_next;
- else
- printf("Didn't unlink in6_ifaddr from list\n");
+ else {
+ /* search failed */
+ printf("Couldn't unlink in6_ifaddr from in6_ifaddr\n");
+ }
}
- {
- int iilen;
- plen = in6_mask2len(&oia->ia_prefixmask.sin6_addr);
+ if (oia->ia6_ifpr) { /* check for safety */
+ plen = in6_mask2len(&oia->ia_prefixmask.sin6_addr, NULL);
iilen = (sizeof(oia->ia_prefixmask.sin6_addr) << 3) - plen;
in6_prefix_remove_ifid(iilen, oia);
}
/*
- * Check if we have another address that has the same prefix of
- * the purged address. If we have one, reinstall the corresponding
- * interface route.
+ * When an autoconfigured address is being removed, release the
+ * reference to the base prefix. Also, since the release might
+ * affect the status of other (detached) addresses, call
+ * pfxlist_onlink_check().
*/
- for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
- int e;
-
- if (in6_are_prefix_equal(&ia->ia_addr.sin6_addr,
- &oia->ia_addr.sin6_addr, plen)) {
- if ((e = rtinit(&(ia->ia_ifa), (int)RTM_ADD,
- ia->ia_flags)) == 0) {
- ia->ia_flags |= IFA_ROUTE;
- break;
- }
- else {
- log(LOG_NOTICE,
- "in6_purgeaddr: failed to add an interface"
- " route for %s/%d on %s, errno = %d\n",
- ip6_sprintf(&ia->ia_addr.sin6_addr),
- plen, if_name(ia->ia_ifp), e);
- /* still trying */
- }
+ if ((oia->ia6_flags & IN6_IFF_AUTOCONF) != 0) {
+ if (oia->ia6_ndpr == NULL) {
+ log(LOG_NOTICE, "in6_unlink_ifa: autoconf'ed address "
+ "%p has no prefix\n", oia);
+ } else {
+ oia->ia6_ndpr->ndpr_refcnt--;
+ oia->ia6_flags &= ~IN6_IFF_AUTOCONF;
+ oia->ia6_ndpr = NULL;
}
+
+ pfxlist_onlink_check();
}
-
- /* release another refcnt for the link from in6_ifaddr */
+
+ /*
+ * release another refcnt for the link from in6_ifaddr.
+ * Note that we should decrement the refcnt at least once for all *BSD.
+ */
IFAFREE(&oia->ia_ifa);
+
+ splx(s);
+}
+
+void
+in6_purgeif(ifp)
+ struct ifnet *ifp;
+{
+ struct ifaddr *ifa, *nifa;
+
+ for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa != NULL; ifa = nifa)
+ {
+ nifa = TAILQ_NEXT(ifa, ifa_list);
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ in6_purgeaddr(ifa);
+ }
+
+ in6_ifdetach(ifp);
}
/*
@@ -1107,7 +1424,6 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p)
}
}
- ifra.ifra_prefixmask.sin6_family = AF_INET6;
ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
in6_len2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
@@ -1159,7 +1475,17 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p)
continue;
if (!cmp)
break;
+
bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate));
+#ifndef SCOPEDROUTING
+ /*
+ * XXX: this is adhoc, but is necessary to allow
+ * a user to specify fe80::/64 (not /10) for a
+ * link-local address.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(&candidate))
+ candidate.s6_addr16[1] = 0;
+#endif
candidate.s6_addr32[0] &= mask.s6_addr32[0];
candidate.s6_addr32[1] &= mask.s6_addr32[1];
candidate.s6_addr32[2] &= mask.s6_addr32[2];
@@ -1172,17 +1498,38 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p)
ia = ifa2ia6(ifa);
if (cmd == SIOCGLIFADDR) {
+#ifndef SCOPEDROUTING
+ struct sockaddr_in6 *s6;
+#endif
+
/* fill in the if_laddrreq structure */
bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);
-
+#ifndef SCOPEDROUTING /* XXX see above */
+ s6 = (struct sockaddr_in6 *)&iflr->addr;
+ if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) {
+ s6->sin6_addr.s6_addr16[1] = 0;
+ s6->sin6_scope_id =
+ in6_addr2scopeid(ifp, &s6->sin6_addr);
+ }
+#endif
if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
ia->ia_dstaddr.sin6_len);
+#ifndef SCOPEDROUTING /* XXX see above */
+ s6 = (struct sockaddr_in6 *)&iflr->dstaddr;
+ if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) {
+ s6->sin6_addr.s6_addr16[1] = 0;
+ s6->sin6_scope_id =
+ in6_addr2scopeid(ifp,
+ &s6->sin6_addr);
+ }
+#endif
} else
bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
iflr->prefixlen =
- in6_mask2len(&ia->ia_prefixmask.sin6_addr);
+ in6_mask2len(&ia->ia_prefixmask.sin6_addr,
+ NULL);
iflr->flags = ia->ia6_flags; /*XXX*/
@@ -1218,96 +1565,73 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p)
}
/*
- * Delete any existing route for an interface.
- */
-void
-in6_ifscrub(ifp, ia)
- register struct ifnet *ifp;
- register struct in6_ifaddr *ia;
-{
- if ((ia->ia_flags & IFA_ROUTE) == 0)
- return;
- if (ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
- rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
- else
- rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
- ia->ia_flags &= ~IFA_ROUTE;
-
- /* Remove ownaddr's loopback rtentry, if it exists. */
- in6_ifremloop(&(ia->ia_ifa));
-}
-
-/*
* Initialize an interface's intetnet6 address
* and routing table entry.
*/
-int
-in6_ifinit(ifp, ia, sin6, scrub)
+static int
+in6_ifinit(ifp, ia, sin6, newhost)
struct ifnet *ifp;
struct in6_ifaddr *ia;
struct sockaddr_in6 *sin6;
- int scrub;
+ int newhost;
{
- struct sockaddr_in6 oldaddr;
- int error, flags = RTF_UP;
+ int error = 0, plen, ifacount = 0;
int s = splimp();
+ struct ifaddr *ifa;
- oldaddr = ia->ia_addr;
- ia->ia_addr = *sin6;
/*
* Give the interface a chance to initialize
* if this is its first address,
* and to validate the address if necessary.
*/
- if (ifp->if_ioctl &&
- (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
+ {
+ if (ifa->ifa_addr == NULL)
+ continue; /* just for safety */
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ ifacount++;
+ }
+
+ ia->ia_addr = *sin6;
+
+ if (ifacount <= 1 && ifp->if_ioctl &&
+ (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
splx(s);
- ia->ia_addr = oldaddr;
return(error);
}
+ splx(s);
- switch (ifp->if_type) {
- case IFT_ARCNET:
- case IFT_ETHER:
- case IFT_FDDI:
- ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
- ia->ia_ifa.ifa_flags |= RTF_CLONING;
- break;
- case IFT_PPP:
- ia->ia_ifa.ifa_rtrequest = nd6_p2p_rtrequest;
- ia->ia_ifa.ifa_flags |= RTF_CLONING;
- break;
- }
+ ia->ia_ifa.ifa_metric = ifp->if_metric;
+
+ /* we could do in(6)_socktrim here, but just omit it at this moment. */
- splx(s);
- if (scrub) {
- ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
- in6_ifscrub(ifp, ia);
- ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
- }
- /* xxx
- * in_socktrim
- */
/*
- * Add route for the network.
+ * Special case:
+ * If the destination address is specified for a point-to-point
+ * interface, install a route to the destination as an interface
+ * direct route.
*/
- ia->ia_ifa.ifa_metric = ifp->if_metric;
- if (ifp->if_flags & IFF_LOOPBACK) {
- ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
- flags |= RTF_HOST;
- } else if (ifp->if_flags & IFF_POINTOPOINT) {
- if (ia->ia_dstaddr.sin6_family != AF_INET6)
- return(0);
- flags |= RTF_HOST;
- }
- if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
+ plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
+ if (plen == 128 && ia->ia_dstaddr.sin6_family == AF_INET6) {
+ if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD,
+ RTF_UP | RTF_HOST)) != 0)
+ return(error);
ia->ia_flags |= IFA_ROUTE;
- /* XXX check if the subnet route points to the same interface */
- if (error == EEXIST)
- error = 0;
+ }
+ if (plen < 128) {
+ /*
+ * The RTF_CLONING flag is necessary for in6_is_ifloop_auto().
+ */
+ ia->ia_ifa.ifa_flags |= RTF_CLONING;
+ }
/* Add ownaddr as loopback rtentry, if necessary(ex. on p2p link). */
- in6_ifaddloop(&(ia->ia_ifa));
+ if (newhost) {
+ /* set the rtrequest function to create llinfo */
+ ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
+ in6_ifaddloop(&(ia->ia_ifa));
+ }
return(error);
}
@@ -1318,8 +1642,8 @@ in6_ifinit(ifp, ia, sin6, scrub)
*/
struct in6_multi *
in6_addmulti(maddr6, ifp, errorp)
- register struct in6_addr *maddr6;
- register struct ifnet *ifp;
+ struct in6_addr *maddr6;
+ struct ifnet *ifp;
int *errorp;
{
struct in6_multi *in6m;
@@ -1408,7 +1732,7 @@ in6ifa_ifpforlinklocal(ifp, ignoreflags)
struct ifnet *ifp;
int ignoreflags;
{
- register struct ifaddr *ifa;
+ struct ifaddr *ifa;
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
@@ -1436,7 +1760,7 @@ in6ifa_ifpwithaddr(ifp, addr)
struct ifnet *ifp;
struct in6_addr *addr;
{
- register struct ifaddr *ifa;
+ struct ifaddr *ifa;
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
@@ -1458,13 +1782,13 @@ static char digits[] = "0123456789abcdef";
static int ip6round = 0;
char *
ip6_sprintf(addr)
-register struct in6_addr *addr;
+ const struct in6_addr *addr;
{
static char ip6buf[8][48];
- register int i;
- register char *cp;
- register u_short *a = (u_short *)addr;
- register u_char *d;
+ int i;
+ char *cp;
+ u_short *a = (u_short *)addr;
+ u_char *d;
int dcolon = 0;
ip6round = (ip6round + 1) & 7;
@@ -1522,6 +1846,27 @@ in6_localaddr(in6)
return (0);
}
+int
+in6_is_addr_deprecated(sa6)
+ struct sockaddr_in6 *sa6;
+{
+ struct in6_ifaddr *ia;
+
+ for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
+ if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
+ &sa6->sin6_addr) &&
+#ifdef SCOPEDROUTING
+ ia->ia_addr.sin6_scope_id == sa6->sin6_scope_id &&
+#endif
+ (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0)
+ return(1); /* true */
+
+ /* XXX: do we still have to go thru the rest of the list? */
+ }
+
+ return(0); /* false */
+}
+
/*
* return length of part which dst and src are equal
* hard coding...
@@ -1602,8 +1947,8 @@ in6_prefixlen2mask(maskp, len)
*/
struct in6_ifaddr *
in6_ifawithscope(oifp, dst)
- register struct ifnet *oifp;
- register struct in6_addr *dst;
+ struct ifnet *oifp;
+ struct in6_addr *dst;
{
int dst_scope = in6_addrscope(dst), src_scope, best_scope = 0;
int blen = -1;
@@ -1612,7 +1957,9 @@ in6_ifawithscope(oifp, dst)
struct in6_ifaddr *ifa_best = NULL;
if (oifp == NULL) {
+#if 0
printf("in6_ifawithscope: output interface is not specified\n");
+#endif
return(NULL);
}
@@ -1675,13 +2022,20 @@ in6_ifawithscope(oifp, dst)
* Also, if the current address has a smaller scope
* than dst, ignore it unless ifa_best also has a
* smaller scope.
+ * Consequently, after the two if-clause below,
+ * the followings must be satisfied:
+ * (scope(src) < scope(dst) &&
+ * scope(best) < scope(dst))
+ * OR
+ * (scope(best) >= scope(dst) &&
+ * scope(src) >= scope(dst))
*/
if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0 &&
IN6_ARE_SCOPE_CMP(src_scope, dst_scope) >= 0)
- goto replace;
+ goto replace; /* (A) */
if (IN6_ARE_SCOPE_CMP(src_scope, dst_scope) < 0 &&
IN6_ARE_SCOPE_CMP(best_scope, dst_scope) >= 0)
- continue;
+ continue; /* (B) */
/*
* A deprecated address SHOULD NOT be used in new
@@ -1710,7 +2064,8 @@ in6_ifawithscope(oifp, dst)
/*
* A non-deprecated address is always preferred
* to a deprecated one regardless of scopes and
- * address matching.
+ * address matching (Note invariants ensured by the
+ * conditions (A) and (B) above.)
*/
if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) &&
(((struct in6_ifaddr *)ifa)->ia6_flags &
@@ -1718,6 +2073,37 @@ in6_ifawithscope(oifp, dst)
goto replace;
/*
+ * When we use temporary addresses described in
+ * RFC 3041, we prefer temporary addresses to
+ * public autoconf addresses. Again, note the
+ * invariants from (A) and (B). Also note that we
+ * don't have any preference between static addresses
+ * and autoconf addresses (despite of whether or not
+ * the latter is temporary or public.)
+ */
+ if (ip6_use_tempaddr) {
+ struct in6_ifaddr *ifat;
+
+ ifat = (struct in6_ifaddr *)ifa;
+ if ((ifa_best->ia6_flags &
+ (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY))
+ == IN6_IFF_AUTOCONF &&
+ (ifat->ia6_flags &
+ (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY))
+ == (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) {
+ goto replace;
+ }
+ if ((ifa_best->ia6_flags &
+ (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY))
+ == (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY) &&
+ (ifat->ia6_flags &
+ (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY))
+ == IN6_IFF_AUTOCONF) {
+ continue;
+ }
+ }
+
+ /*
* At this point, we have two cases:
* 1. we are looking at a non-deprecated address,
* and ifa_best is also non-deprecated.
@@ -1743,64 +2129,68 @@ in6_ifawithscope(oifp, dst)
* Smaller scopes are the last resort.
* - A deprecated address is chosen only when we have
* no address that has an enough scope, but is
- * prefered to any addresses of smaller scopes.
- * - Longest address match against dst is considered
- * only for addresses that has the same scope of dst.
+ * prefered to any addresses of smaller scopes
+ * (this must be already done above.)
+ * - addresses on the outgoing I/F are preferred to
+ * ones on other interfaces if none of above
+ * tiebreaks. In the table below, the column "bI"
+ * means if the best_ifa is on the outgoing
+ * interface, and the column "sI" means if the ifa
+ * is on the outgoing interface.
* - If there is no other reasons to choose one,
- * addresses on the outgoing I/F are preferred.
+ * longest address match against dst is considered.
*
* The precise decision table is as follows:
- * dscopecmp bscopecmp matchcmp outI/F | replace?
- * !equal equal N/A Yes | Yes (1)
- * !equal equal N/A No | No (2)
- * larger larger N/A N/A | No (3)
- * larger smaller N/A N/A | Yes (4)
- * smaller larger N/A N/A | Yes (5)
- * smaller smaller N/A N/A | No (6)
- * equal smaller N/A N/A | Yes (7)
- * equal larger (already done)
- * equal equal larger N/A | Yes (8)
- * equal equal smaller N/A | No (9)
- * equal equal equal Yes | Yes (a)
- * eaual eqaul equal No | No (b)
+ * dscopecmp bscopecmp match bI oI | replace?
+ * N/A equal N/A Y N | No (1)
+ * N/A equal N/A N Y | Yes (2)
+ * N/A equal larger N/A | Yes (3)
+ * N/A equal !larger N/A | No (4)
+ * larger larger N/A N/A | No (5)
+ * larger smaller N/A N/A | Yes (6)
+ * smaller larger N/A N/A | Yes (7)
+ * smaller smaller N/A N/A | No (8)
+ * equal smaller N/A N/A | Yes (9)
+ * equal larger (already done at A above)
*/
dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope);
bscopecmp = IN6_ARE_SCOPE_CMP(src_scope, best_scope);
- if (dscopecmp && bscopecmp == 0) {
- if (oifp == ifp) /* (1) */
+ if (bscopecmp == 0) {
+ struct ifnet *bifp = ifa_best->ia_ifp;
+
+ if (bifp == oifp && ifp != oifp) /* (1) */
+ continue;
+ if (bifp != oifp && ifp == oifp) /* (2) */
+ goto replace;
+
+ /*
+ * Both bifp and ifp are on the outgoing
+ * interface, or both two are on a different
+ * interface from the outgoing I/F.
+ * now we need address matching against dst
+ * for tiebreaking.
+ */
+ tlen = in6_matchlen(IFA_IN6(ifa), dst);
+ matchcmp = tlen - blen;
+ if (matchcmp > 0) /* (3) */
goto replace;
- continue; /* (2) */
+ continue; /* (4) */
}
if (dscopecmp > 0) {
- if (bscopecmp > 0) /* (3) */
+ if (bscopecmp > 0) /* (5) */
continue;
- goto replace; /* (4) */
+ goto replace; /* (6) */
}
if (dscopecmp < 0) {
- if (bscopecmp > 0) /* (5) */
+ if (bscopecmp > 0) /* (7) */
goto replace;
- continue; /* (6) */
+ continue; /* (8) */
}
/* now dscopecmp must be 0 */
if (bscopecmp < 0)
- goto replace; /* (7) */
-
- /*
- * At last both dscopecmp and bscopecmp must be 0.
- * We need address matching against dst for
- * tiebreaking.
- */
- tlen = in6_matchlen(IFA_IN6(ifa), dst);
- matchcmp = tlen - blen;
- if (matchcmp > 0) /* (8) */
- goto replace;
- if (matchcmp < 0) /* (9) */
- continue;
- if (oifp == ifp) /* (a) */
- goto replace;
- continue; /* (b) */
+ goto replace; /* (9) */
replace:
ifa_best = (struct in6_ifaddr *)ifa;
@@ -1837,8 +2227,8 @@ in6_ifawithscope(oifp, dst)
*/
struct in6_ifaddr *
in6_ifawithifp(ifp, dst)
- register struct ifnet *ifp;
- register struct in6_addr *dst;
+ struct ifnet *ifp;
+ struct in6_addr *dst;
{
int dst_scope = in6_addrscope(dst), blen = -1, tlen;
struct ifaddr *ifa;
@@ -1943,6 +2333,43 @@ in6_if_up(ifp)
}
}
+int
+in6if_do_dad(ifp)
+ struct ifnet *ifp;
+{
+ if ((ifp->if_flags & IFF_LOOPBACK) != 0)
+ return(0);
+
+ switch (ifp->if_type) {
+#ifdef IFT_DUMMY
+ case IFT_DUMMY:
+#endif
+ case IFT_FAITH:
+ /*
+ * These interfaces do not have the IFF_LOOPBACK flag,
+ * but loop packets back. We do not have to do DAD on such
+ * interfaces. We should even omit it, because loop-backed
+ * NS would confuse the DAD procedure.
+ */
+ return(0);
+ default:
+ /*
+ * Our DAD routine requires the interface up and running.
+ * However, some interfaces can be up before the RUNNING
+ * status. Additionaly, users may try to assign addresses
+ * before the interface becomes up (or running).
+ * We simply skip DAD in such a case as a work around.
+ * XXX: we should rather mark "tentative" on such addresses,
+ * and do DAD after the interface becomes ready.
+ */
+ if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) !=
+ (IFF_UP|IFF_RUNNING))
+ return(0);
+
+ return(1);
+ }
+}
+
/*
* Calculate max IPv6 MTU through all the interfaces and store it
* to in6_maxmtu.
diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h
index 1159e52..168d1df 100644
--- a/sys/netinet6/in6.h
+++ b/sys/netinet6/in6.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6.h,v 1.48 2000/06/26 15:55:32 itojun Exp $ */
+/* $KAME: in6.h,v 1.89 2001/05/27 13:28:35 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -66,21 +66,19 @@
*/
#ifndef __KAME_NETINET_IN_H_INCLUDED_
-#error "do not include netinet6/in6.h directly, include netinet/in.h"
+#error "do not include netinet6/in6.h directly, include netinet/in.h. see RFC2553"
#endif
#ifndef _NETINET6_IN6_H_
#define _NETINET6_IN6_H_
-#ifndef _XOPEN_SOURCE
-#include <sys/queue.h>
-#endif
-
/*
* Identification of the network protocol stack
+ * for *BSD-current/release: http://www.kame.net/dev/cvsweb.cgi/kame/COVERAGE
+ * has the table of implementation/integration differences.
*/
#define __KAME__
-#define __KAME_VERSION "20000701/FreeBSD-current"
+#define __KAME_VERSION "20010528/FreeBSD"
/*
* Local port number conventions:
@@ -148,7 +146,7 @@ struct sockaddr_in6 {
u_int16_t sin6_port; /* Transport layer port # (in_port_t)*/
u_int32_t sin6_flowinfo; /* IP6 flow information */
struct in6_addr sin6_addr; /* IP6 address */
- u_int32_t sin6_scope_id; /* intface scope id */
+ u_int32_t sin6_scope_id; /* scope zone index */
};
/*
@@ -167,6 +165,8 @@ struct sockaddr_in6 {
#endif
#ifdef _KERNEL
+extern const struct sockaddr_in6 sa6_any;
+
extern const struct in6_addr in6mask0;
extern const struct in6_addr in6mask32;
extern const struct in6_addr in6mask64;
@@ -238,41 +238,49 @@ extern const struct in6_addr in6addr_linklocal_allrouters;
(memcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0)
#endif
+#ifdef _KERNEL /* non standard */
+/* see if two addresses are equal in a scope-conscious manner. */
+#define SA6_ARE_ADDR_EQUAL(a, b) \
+ (((a)->sin6_scope_id == 0 || (b)->sin6_scope_id == 0 || \
+ ((a)->sin6_scope_id == (b)->sin6_scope_id)) && \
+ (bcmp(&(a)->sin6_addr, &(b)->sin6_addr, sizeof(struct in6_addr)) == 0))
+#endif
+
/*
* Unspecified
*/
#define IN6_IS_ADDR_UNSPECIFIED(a) \
- ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \
- (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \
- (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \
- (*(u_int32_t *)(&(a)->s6_addr[12]) == 0))
+ ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
+ (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
+ (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \
+ (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) == 0))
/*
* Loopback
*/
#define IN6_IS_ADDR_LOOPBACK(a) \
- ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \
- (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \
- (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \
- (*(u_int32_t *)(&(a)->s6_addr[12]) == ntohl(1)))
+ ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
+ (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
+ (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \
+ (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) == ntohl(1)))
/*
* IPv4 compatible
*/
#define IN6_IS_ADDR_V4COMPAT(a) \
- ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \
- (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \
- (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \
- (*(u_int32_t *)(&(a)->s6_addr[12]) != 0) && \
- (*(u_int32_t *)(&(a)->s6_addr[12]) != ntohl(1)))
+ ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
+ (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
+ (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \
+ (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) != 0) && \
+ (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) != ntohl(1)))
/*
* Mapped
*/
#define IN6_IS_ADDR_V4MAPPED(a) \
- ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \
- (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \
- (*(u_int32_t *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)))
+ ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
+ (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
+ (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)))
/*
* KAME Scope Values
@@ -350,13 +358,27 @@ extern const struct in6_addr in6addr_linklocal_allrouters;
#endif
/*
- * KAME Scope
+ * Wildcard Socket
*/
+#if 0 /*pre-RFC2553*/
+#define IN6_IS_ADDR_ANY(a) IN6_IS_ADDR_UNSPECIFIED(a)
+#endif
+
#ifdef _KERNEL /*nonstandard*/
+/*
+ * KAME Scope
+ */
#define IN6_IS_SCOPE_LINKLOCAL(a) \
((IN6_IS_ADDR_LINKLOCAL(a)) || \
(IN6_IS_ADDR_MC_LINKLOCAL(a)))
-#endif
+
+#define IFA6_IS_DEPRECATED(a) \
+ ((a)->ia6_lifetime.ia6t_preferred != 0 && \
+ (a)->ia6_lifetime.ia6t_preferred < time_second)
+#define IFA6_IS_INVALID(a) \
+ ((a)->ia6_lifetime.ia6t_expire != 0 && \
+ (a)->ia6_lifetime.ia6t_expire < time_second)
+#endif /* _KERNEL */
/*
* IP6 route structure
@@ -389,26 +411,34 @@ struct route_in6 {
#define IPV6_LEAVE_GROUP 13 /* ip6_mreq; leave a group membership */
#define IPV6_PORTRANGE 14 /* int; range to choose for unspec port */
#define ICMP6_FILTER 18 /* icmp6_filter; icmp6 filter */
-#define IPV6_PKTINFO 19 /* bool; send/rcv if, src/dst addr */
+/* RFC2292 options */
+#define IPV6_PKTINFO 19 /* bool; send/recv if, src/dst addr */
#define IPV6_HOPLIMIT 20 /* bool; hop limit */
#define IPV6_NEXTHOP 21 /* bool; next hop addr */
#define IPV6_HOPOPTS 22 /* bool; hop-by-hop option */
#define IPV6_DSTOPTS 23 /* bool; destination option */
#define IPV6_RTHDR 24 /* bool; routing header */
#define IPV6_PKTOPTIONS 25 /* buf/cmsghdr; set/get IPv6 options */
+
#define IPV6_CHECKSUM 26 /* int; checksum offset for raw socket */
-#define IPV6_BINDV6ONLY 27 /* bool; only bind INET6 at null bind */
+#define IPV6_V6ONLY 27 /* bool; only bind INET6 at wildcard bind */
+#ifndef _KERNEL
+#define IPV6_BINDV6ONLY IPV6_V6ONLY
+#endif
-/* for IPsec */
+#if 1 /*IPSEC*/
#define IPV6_IPSEC_POLICY 28 /* struct; get/set security policy */
+#endif
#define IPV6_FAITH 29 /* bool; accept FAITH'ed connections */
-/* for IPV6FIREWALL */
+#if 1 /*IPV6FIREWALL*/
#define IPV6_FW_ADD 30 /* add a firewall rule to chain */
#define IPV6_FW_DEL 31 /* delete a firewall rule from chain */
#define IPV6_FW_FLUSH 32 /* flush firewall rule chain */
#define IPV6_FW_ZERO 33 /* clear single/all firewall counter(s) */
#define IPV6_FW_GET 34 /* get entire firewall rule chain */
+#endif
+
/* to define items, should talk with KAME guys first, for *BSD compatibility */
#define IPV6_RTHDR_LOOSE 0 /* this hop need not be a neighbor. XXX old spec */
@@ -528,39 +558,44 @@ struct in6_pktinfo {
#define IPV6CTL_KAME_VERSION 20
#define IPV6CTL_USE_DEPRECATED 21 /* use deprecated addr (RFC2462 5.5.4) */
#define IPV6CTL_RR_PRUNE 22 /* walk timer for router renumbering */
+#if 0 /*obsolete*/
#define IPV6CTL_MAPPED_ADDR 23
-#ifdef notdef /*__NetBSD__ - reserved, don't delete*/
-#define IPV6CTL_BINDV6ONLY 24
#endif
+#define IPV6CTL_V6ONLY 24
#define IPV6CTL_RTEXPIRE 25 /* cloned route expiration time */
#define IPV6CTL_RTMINEXPIRE 26 /* min value for expiration time */
#define IPV6CTL_RTMAXCACHE 27 /* trigger level for dynamic expire */
+
+#define IPV6CTL_USETEMPADDR 32 /* use temporary addresses (RFC3041) */
+#define IPV6CTL_TEMPPLTIME 33 /* preferred lifetime for tmpaddrs */
+#define IPV6CTL_TEMPVLTIME 34 /* valid lifetime for tmpaddrs */
+#define IPV6CTL_AUTO_LINKLOCAL 35 /* automatic link-local addr assign */
+#define IPV6CTL_RIP6STATS 36 /* raw_ip6 stats */
+
/* New entries should be added here from current IPV6CTL_MAXID value. */
/* to define items, should talk with KAME guys first, for *BSD compatibility */
-#define IPV6CTL_MAXID 28
+#define IPV6CTL_MAXID 37
+
#endif /* !_XOPEN_SOURCE */
/*
* Redefinition of mbuf flags
*/
-#define M_ANYCAST6 M_PROTO1
-#define M_AUTHIPHDR M_PROTO2
-#define M_DECRYPTED M_PROTO3
-#define M_LOOP M_PROTO4
-#define M_AUTHIPDGM M_PROTO5
+#define M_AUTHIPHDR M_PROTO2
+#define M_DECRYPTED M_PROTO3
+#define M_LOOP M_PROTO4
+#define M_AUTHIPDGM M_PROTO5
#ifdef _KERNEL
-struct cmsghdr;
-struct mbuf;
-struct ifnet;
+struct cmsghdr;
int in6_cksum __P((struct mbuf *, u_int8_t, u_int32_t, u_int32_t));
int in6_localaddr __P((struct in6_addr *));
int in6_addrscope __P((struct in6_addr *));
struct in6_ifaddr *in6_ifawithscope __P((struct ifnet *, struct in6_addr *));
struct in6_ifaddr *in6_ifawithifp __P((struct ifnet *, struct in6_addr *));
-extern void in6_if_up __P((struct ifnet *));
-struct sockaddr;
+extern void in6_if_up __P((struct ifnet *));
+struct sockaddr;
void in6_sin6_2_sin __P((struct sockaddr_in *sin,
struct sockaddr_in6 *sin6));
@@ -569,33 +604,51 @@ void in6_sin_2_v4mapsin6 __P((struct sockaddr_in *sin,
void in6_sin6_2_sin_in_sock __P((struct sockaddr *nam));
void in6_sin_2_v4mapsin6_in_sock __P((struct sockaddr **nam));
-#define satosin6(sa) ((struct sockaddr_in6 *)(sa))
-#define sin6tosa(sin6) ((struct sockaddr *)(sin6))
-#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
+#define satosin6(sa) ((struct sockaddr_in6 *)(sa))
+#define sin6tosa(sin6) ((struct sockaddr *)(sin6))
+#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
#endif /* _KERNEL */
__BEGIN_DECLS
struct cmsghdr;
-extern int inet6_option_space __P((int));
-extern int inet6_option_init __P((void *, struct cmsghdr **, int));
-extern int inet6_option_append __P((struct cmsghdr *, const u_int8_t *,
- int, int));
-extern u_int8_t *inet6_option_alloc __P((struct cmsghdr *, int, int, int));
-extern int inet6_option_next __P((const struct cmsghdr *, u_int8_t **));
-extern int inet6_option_find __P((const struct cmsghdr *, u_int8_t **,
- int));
-
-extern size_t inet6_rthdr_space __P((int, int));
-extern struct cmsghdr *inet6_rthdr_init __P((void *, int));
-extern int inet6_rthdr_add __P((struct cmsghdr *, const struct in6_addr *,
- u_int));
-extern int inet6_rthdr_lasthop __P((struct cmsghdr *, u_int));
-extern int inet6_rthdr_segments __P((const struct cmsghdr *));
-extern struct in6_addr *inet6_rthdr_getaddr __P((struct cmsghdr *, int));
-extern int inet6_rthdr_getflags __P((const struct cmsghdr *, int));
-extern int inet6_rthdr_reverse __P((const struct cmsghdr *,
- struct cmsghdr *));
+extern int inet6_option_space __P((int));
+extern int inet6_option_init __P((void *, struct cmsghdr **, int));
+extern int inet6_option_append __P((struct cmsghdr *, const u_int8_t *,
+ int, int));
+extern u_int8_t *inet6_option_alloc __P((struct cmsghdr *, int, int, int));
+extern int inet6_option_next __P((const struct cmsghdr *, u_int8_t **));
+extern int inet6_option_find __P((const struct cmsghdr *, u_int8_t **, int));
+
+extern size_t inet6_rthdr_space __P((int, int));
+extern struct cmsghdr *inet6_rthdr_init __P((void *, int));
+extern int inet6_rthdr_add __P((struct cmsghdr *, const struct in6_addr *,
+ unsigned int));
+extern int inet6_rthdr_lasthop __P((struct cmsghdr *, unsigned int));
+#if 0 /* not implemented yet */
+extern int inet6_rthdr_reverse __P((const struct cmsghdr *, struct cmsghdr *));
+#endif
+extern int inet6_rthdr_segments __P((const struct cmsghdr *));
+extern struct in6_addr *inet6_rthdr_getaddr __P((struct cmsghdr *, int));
+extern int inet6_rthdr_getflags __P((const struct cmsghdr *, int));
+
+extern int inet6_opt_init __P((void *, size_t));
+extern int inet6_opt_append __P((void *, size_t, int, u_int8_t,
+ size_t, u_int8_t, void **));
+extern int inet6_opt_finish __P((void *, size_t, int));
+extern int inet6_opt_set_val __P((void *, size_t, void *, int));
+
+extern int inet6_opt_next __P((void *, size_t, int, u_int8_t *,
+ size_t *, void **));
+extern int inet6_opt_find __P((void *, size_t, int, u_int8_t,
+ size_t *, void **));
+extern int inet6_opt_get_val __P((void *, size_t, void *, int));
+extern size_t inet6_rth_space __P((int, int));
+extern void *inet6_rth_init __P((void *, int, int, int));
+extern int inet6_rth_add __P((void *, const struct in6_addr *));
+extern int inet6_rth_reverse __P((const void *, void *));
+extern int inet6_rth_segments __P((const void *));
+extern struct in6_addr *inet6_rth_getaddr __P((const void *, int));
__END_DECLS
#endif /* !_NETINET6_IN6_H_ */
diff --git a/sys/netinet6/in6_cksum.c b/sys/netinet6/in6_cksum.c
index db564cf..fbd95cb 100644
--- a/sys/netinet6/in6_cksum.c
+++ b/sys/netinet6/in6_cksum.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6_cksum.c,v 1.9 2000/09/09 15:33:31 itojun Exp $ */
+/* $KAME: in6_cksum.c,v 1.10 2000/12/03 00:53:59 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -92,13 +92,13 @@
int
in6_cksum(m, nxt, off, len)
- register struct mbuf *m;
+ struct mbuf *m;
u_int8_t nxt;
u_int32_t off, len;
{
- register u_int16_t *w;
- register int sum = 0;
- register int mlen = 0;
+ u_int16_t *w;
+ int sum = 0;
+ int mlen = 0;
int byte_swapped = 0;
#if 0
int srcifid = 0, dstifid = 0;
diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c
index c8c1450..57bec0e 100644
--- a/sys/netinet6/in6_gif.c
+++ b/sys/netinet6/in6_gif.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6_gif.c,v 1.37 2000/06/17 20:34:25 itojun Exp $ */
+/* $KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -30,10 +30,6 @@
* SUCH DAMAGE.
*/
-/*
- * in6_gif.c
- */
-
#include "opt_inet.h"
#include "opt_inet6.h"
@@ -43,6 +39,10 @@
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/errno.h>
+#include <sys/queue.h>
+#include <sys/syslog.h>
+
+#include <sys/malloc.h>
#include <net/if.h>
#include <net/route.h>
@@ -148,34 +148,19 @@ in6_gif_output(ifp, family, m, rt)
ip6->ip6_nxt = proto;
ip6->ip6_hlim = ip6_gif_hlim;
ip6->ip6_src = sin6_src->sin6_addr;
- if (ifp->if_flags & IFF_LINK0) {
- /* multi-destination mode */
- if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
- ip6->ip6_dst = sin6_dst->sin6_addr;
- else if (rt) {
- if (family != AF_INET6) {
- m_freem(m);
- return EINVAL; /*XXX*/
- }
- ip6->ip6_dst = ((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr;
- } else {
- m_freem(m);
- return ENETUNREACH;
- }
- } else {
- /* bidirectional configured tunnel mode */
- if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
- ip6->ip6_dst = sin6_dst->sin6_addr;
- else {
- m_freem(m);
- return ENETUNREACH;
- }
+ /* bidirectional configured tunnel mode */
+ if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
+ ip6->ip6_dst = sin6_dst->sin6_addr;
+ else {
+ m_freem(m);
+ return ENETUNREACH;
}
- if (ifp->if_flags & IFF_LINK1) {
- otos = 0;
+ if (ifp->if_flags & IFF_LINK1)
ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
- ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
- }
+ else
+ ip_ecn_ingress(ECN_NOCARE, &otos, &itos);
+ ip6->ip6_flow &= ~ntohl(0xff00000);
+ ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
if (dst->sin6_family != sin6_dst->sin6_family ||
!IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
@@ -262,6 +247,8 @@ int in6_gif_input(mp, offp, proto)
ip = mtod(m, struct ip *);
if (gifp->if_flags & IFF_LINK1)
ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos);
+ else
+ ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos);
break;
}
#endif /* INET */
@@ -278,6 +265,8 @@ int in6_gif_input(mp, offp, proto)
ip6 = mtod(m, struct ip6_hdr *);
if (gifp->if_flags & IFF_LINK1)
ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow);
+ else
+ ip6_ecn_egress(ECN_NOCARE, &otos, &ip6->ip6_flow);
break;
}
#endif
@@ -321,17 +310,14 @@ gif_encapcheck6(m, off, proto, arg)
addrmatch |= 1;
if (IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6.ip6_src))
addrmatch |= 2;
- else if ((sc->gif_if.if_flags & IFF_LINK0) != 0 &&
- IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr)) {
- addrmatch |= 2; /* we accept any source */
- }
if (addrmatch != 3)
return 0;
/* martian filters on outer source - done in ip6_input */
/* ingress filters on outer source */
- if ((m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) {
+ if ((sc->gif_if.if_flags & IFF_LINK2) == 0 &&
+ (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) {
struct sockaddr_in6 sin6;
struct rtentry *rt;
@@ -341,15 +327,18 @@ gif_encapcheck6(m, off, proto, arg)
sin6.sin6_addr = ip6.ip6_src;
/* XXX scopeid */
rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
- if (!rt)
- return 0;
- if (rt->rt_ifp != m->m_pkthdr.rcvif) {
- rtfree(rt);
+ if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) {
+#if 0
+ log(LOG_WARNING, "%s: packet from %s dropped "
+ "due to ingress filter\n", if_name(&sc->gif_if),
+ ip6_sprintf(&sin6.sin6_addr));
+#endif
+ if (rt)
+ rtfree(rt);
return 0;
}
rtfree(rt);
}
- /* prioritize: IFF_LINK0 mode is less preferred */
- return (sc->gif_if.if_flags & IFF_LINK0) ? 128 : 128 * 2;
+ return 128 * 2;
}
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c
index c839d01..516826d 100644
--- a/sys/netinet6/in6_ifattach.c
+++ b/sys/netinet6/in6_ifattach.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6_ifattach.c,v 1.67 2000/10/01 10:51:54 itojun Exp $ */
+/* $KAME: in6_ifattach.c,v 1.118 2001/05/24 07:44:00 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -36,6 +36,7 @@
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/kernel.h>
+#include <sys/syslog.h>
#include <sys/md5.h>
#include <net/if.h>
@@ -49,6 +50,7 @@
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
+#include <netinet6/in6_var.h>
#include <netinet6/in6_ifattach.h>
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
@@ -62,13 +64,20 @@ size_t in6_ifstatmax = 0;
size_t icmp6_ifstatmax = 0;
unsigned long in6_maxmtu = 0;
+#ifdef IP6_AUTO_LINKLOCAL
+int ip6_auto_linklocal = IP6_AUTO_LINKLOCAL;
+#else
+int ip6_auto_linklocal = 1; /* enable by default */
+#endif
+
+struct callout in6_tmpaddrtimer_ch;
+
static int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
+static int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *));
static int get_hw_ifid __P((struct ifnet *, struct in6_addr *));
static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *));
-static int in6_ifattach_addaddr __P((struct ifnet *, struct in6_ifaddr *));
static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *));
static int in6_ifattach_loopback __P((struct ifnet *));
-static int nigroup __P((struct ifnet *, const char *, int, struct in6_addr *));
#define EUI64_GBIT 0x01
#define EUI64_UBIT 0x02
@@ -122,6 +131,90 @@ get_rand_ifid(ifp, in6)
return 0;
}
+static int
+generate_tmp_ifid(seed0, seed1, ret)
+ u_int8_t *seed0, *ret;
+ const u_int8_t *seed1;
+{
+ MD5_CTX ctxt;
+ u_int8_t seed[16], digest[16], nullbuf[8];
+ u_int32_t val32;
+ struct timeval tv;
+
+ /* If there's no hisotry, start with a random seed. */
+ bzero(nullbuf, sizeof(nullbuf));
+ if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) {
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ microtime(&tv);
+ val32 = random() ^ tv.tv_usec;
+ bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32));
+ }
+ } else
+ bcopy(seed0, seed, 8);
+
+ /* copy the right-most 64-bits of the given address */
+ /* XXX assumption on the size of IFID */
+ bcopy(seed1, &seed[8], 8);
+
+ if (0) { /* for debugging purposes only */
+ int i;
+
+ printf("generate_tmp_ifid: new randomized ID from: ");
+ for (i = 0; i < 16; i++)
+ printf("%02x", seed[i]);
+ printf(" ");
+ }
+
+ /* generate 16 bytes of pseudo-random value. */
+ bzero(&ctxt, sizeof(ctxt));
+ MD5Init(&ctxt);
+ MD5Update(&ctxt, seed, sizeof(seed));
+ MD5Final(digest, &ctxt);
+
+ /*
+ * RFC 3041 3.2.1. (3)
+ * Take the left-most 64-bits of the MD5 digest and set bit 6 (the
+ * left-most bit is numbered 0) to zero.
+ */
+ bcopy(digest, ret, 8);
+ ret[0] &= ~EUI64_UBIT;
+
+ /*
+ * XXX: we'd like to ensure that the generated value is not zero
+ * for simplicity. If the caclculated digest happens to be zero,
+ * use a random non-zero value as the last resort.
+ */
+ if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) {
+ log(LOG_INFO,
+ "generate_tmp_ifid: computed MD5 value is zero.\n");
+
+ microtime(&tv);
+ val32 = random() ^ tv.tv_usec;
+ val32 = 1 + (val32 % (0xffffffff - 1));
+ }
+
+ /*
+ * RFC 3041 3.2.1. (4)
+ * Take the rightmost 64-bits of the MD5 digest and save them in
+ * stable storage as the history value to be used in the next
+ * iteration of the algorithm.
+ */
+ bcopy(&digest[8], seed0, 8);
+
+ if (0) { /* for debugging purposes only */
+ int i;
+
+ printf("to: ");
+ for (i = 0; i < 16; i++)
+ printf("%02x", digest[i]);
+ printf("\n");
+ }
+
+ return 0;
+}
+
/*
* Get interface identifier for the specified interface.
* XXX assumes single sockaddr_dl (AF_LINK address) per an interface
@@ -165,7 +258,14 @@ found:
case IFT_ETHER:
case IFT_FDDI:
case IFT_ATM:
+ case IFT_IEEE1394:
+#ifdef IFT_IEEE80211
+ case IFT_IEEE80211:
+#endif
/* IEEE802/EUI64 cases - what others? */
+ /* IEEE1394 uses 16byte length address starting with EUI64 */
+ if (addrlen > 8)
+ addrlen = 8;
/* look at IEEE802/EUI64 only */
if (addrlen != 8 && addrlen != 6)
@@ -217,7 +317,7 @@ found:
case IFT_STF:
#endif
/*
- * mech-06 says: "SHOULD use IPv4 address as ifid source".
+ * RFC2893 says: "SHOULD use IPv4 address as ifid source".
* however, IPv4 address is not very suitable as unique
* identifier source (can be renumbered).
* we don't do this.
@@ -262,19 +362,15 @@ get_ifid(ifp0, altifp, in6)
/* first, try to get it from the interface itself */
if (get_hw_ifid(ifp0, in6) == 0) {
-#ifdef ND6_DEBUG
- printf("%s: got interface identifier from itself\n",
- if_name(ifp0));
-#endif
+ nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
+ if_name(ifp0)));
goto success;
}
/* try secondary EUI64 source. this basically is for ATM PVC */
if (altifp && get_hw_ifid(altifp, in6) == 0) {
-#ifdef ND6_DEBUG
- printf("%s: got interface identifier from %s\n",
- if_name(ifp0), if_name(altifp));
-#endif
+ nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
+ if_name(ifp0), if_name(altifp)));
goto success;
}
@@ -291,21 +387,18 @@ get_ifid(ifp0, altifp, in6)
* globally unique
*/
if (IFID_UNIVERSAL(in6)) {
-
-#ifdef ND6_DEBUG
- printf("%s: borrow interface identifier from %s\n",
- if_name(ifp0), if_name(ifp));
-#endif
+ nd6log((LOG_DEBUG,
+ "%s: borrow interface identifier from %s\n",
+ if_name(ifp0), if_name(ifp)));
goto success;
}
}
/* last resort: get from random number source */
if (get_rand_ifid(ifp, in6) == 0) {
-#ifdef ND6_DEBUG
- printf("%s: interface identifier generated by random number\n",
- if_name(ifp0));
-#endif
+ nd6log((LOG_DEBUG,
+ "%s: interface identifier generated by random number\n",
+ if_name(ifp0)));
goto success;
}
@@ -313,223 +406,152 @@ get_ifid(ifp0, altifp, in6)
return -1;
success:
-#ifdef ND6_DEBUG
- printf("%s: ifid: "
+ nd6log((LOG_INFO, "%s: ifid: "
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
if_name(ifp0),
in6->s6_addr[8], in6->s6_addr[9],
in6->s6_addr[10], in6->s6_addr[11],
in6->s6_addr[12], in6->s6_addr[13],
- in6->s6_addr[14], in6->s6_addr[15]);
-#endif
+ in6->s6_addr[14], in6->s6_addr[15]));
return 0;
}
-/*
- * configure IPv6 interface address. XXX code duplicated with in.c
- */
static int
-in6_ifattach_addaddr(ifp, ia)
+in6_ifattach_linklocal(ifp, altifp)
struct ifnet *ifp;
- struct in6_ifaddr *ia;
+ struct ifnet *altifp; /* secondary EUI64 source */
{
- struct in6_ifaddr *oia;
- struct ifaddr *ifa;
- int error;
- int rtflag;
- struct in6_addr llsol;
-
- /*
- * initialize if_addrlist, if we are the very first one
- */
- ifa = TAILQ_FIRST(&ifp->if_addrlist);
- if (ifa == NULL) {
- TAILQ_INIT(&ifp->if_addrlist);
- }
+ struct in6_ifaddr *ia;
+ struct in6_aliasreq ifra;
+ struct nd_prefix pr0;
+ int i, error;
/*
- * link the interface address to global list
+ * configure link-local address.
*/
- TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
- /* gain a refcnt for the link from if_addrlist */
- ia->ia_ifa.ifa_refcnt++;
+ bzero(&ifra, sizeof(ifra));
/*
- * Also link into the IPv6 address chain beginning with in6_ifaddr.
- * kazu opposed it, but itojun & jinmei wanted.
+ * in6_update_ifa() does not use ifra_name, but we accurately set it
+ * for safety.
*/
- if ((oia = in6_ifaddr) != NULL) {
- for (; oia->ia_next; oia = oia->ia_next)
- continue;
- oia->ia_next = ia;
- } else
- in6_ifaddr = ia;
- /* gain another refcnt for the link from in6_ifaddr */
- ia->ia_ifa.ifa_refcnt++;
+ strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
- /*
- * give the interface a chance to initialize, in case this
- * is the first address to be added.
- */
- if (ifp->if_ioctl != NULL) {
- int s;
- s = splimp();
- error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
- splx(s);
- } else
- error = 0;
- if (error) {
- switch (error) {
- case EAFNOSUPPORT:
- printf("%s: IPv6 not supported\n", if_name(ifp));
- break;
- default:
- printf("%s: SIOCSIFADDR error %d\n", if_name(ifp),
- error);
- break;
+ ifra.ifra_addr.sin6_family = AF_INET6;
+ ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
+ ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
+#ifdef SCOPEDROUTING
+ ifra.ifra_addr.sin6_addr.s6_addr16[1] = 0
+#else
+ ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); /* XXX */
+#endif
+ ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
+ if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
+ ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
+ ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
+ } else {
+ if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
+ nd6log((LOG_ERR,
+ "%s: no ifid available\n", if_name(ifp)));
+ return -1;
}
-
- /* undo changes */
- TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
- IFAFREE(&ia->ia_ifa);
- if (oia)
- oia->ia_next = ia->ia_next;
- else
- in6_ifaddr = ia->ia_next;
- IFAFREE(&ia->ia_ifa);
- return -1;
}
+#ifdef SCOPEDROUTING
+ ifra.ifra_addr.sin6_scope_id =
+ in6_addr2scopeid(ifp, &ifra.ifra_addr.sin6_addr);
+#endif
- /* configure link-layer address resolution */
- rtflag = 0;
- if (IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr, &in6mask128))
- rtflag = RTF_HOST;
- else {
- switch (ifp->if_type) {
- case IFT_LOOP:
-#ifdef IFT_STF
- case IFT_STF:
+ ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
+ ifra.ifra_prefixmask.sin6_family = AF_INET6;
+ ifra.ifra_prefixmask.sin6_addr = in6mask64;
+#ifdef SCOPEDROUTING
+ /* take into accound the sin6_scope_id field for routing */
+ ifra.ifra_prefixmask.sin6_scope_id = 0xffffffff;
#endif
- rtflag = 0;
- break;
- default:
- ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
- ia->ia_ifa.ifa_flags |= RTF_CLONING;
- rtflag = RTF_CLONING;
- break;
- }
- }
+ /* link-local addresses should NEVER expire. */
+ ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
+ ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
- /* add route to the interface. */
- {
- int e;
-
- e = rtrequest(RTM_ADD,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&ia->ia_prefixmask,
- RTF_UP | rtflag,
- (struct rtentry **)0);
- if (e) {
- printf("in6_ifattach_addaddr: rtrequest failed. errno = %d\n", e);
- }
- }
- ia->ia_flags |= IFA_ROUTE;
+ /*
+ * Do not let in6_update_ifa() do DAD, since we need a random delay
+ * before sending an NS at the first time the inteface becomes up.
+ * Instead, in6_if_up() will start DAD with a proper random delay.
+ */
+ ifra.ifra_flags |= IN6_IFF_NODAD;
- if ((rtflag & RTF_CLONING) != 0 &&
- (ifp->if_flags & IFF_MULTICAST) != 0) {
+ /*
+ * Now call in6_update_ifa() to do a bunch of procedures to configure
+ * a link-local address. We can set NULL to the 3rd argument, because
+ * we know there's no other link-local address on the interface.
+ */
+ if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
/*
- * join solicited multicast address
+ * XXX: When the interface does not support IPv6, this call
+ * would fail in the SIOCSIFADDR ioctl. I believe the
+ * notification is rather confusing in this case, so just
+ * supress it. (jinmei@kame.net 20010130)
*/
- bzero(&llsol, sizeof(llsol));
- 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_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
- llsol.s6_addr8[12] = 0xff;
- (void)in6_addmulti(&llsol, ifp, &error);
-
- /* XXX should we run DAD on other interface types? */
- switch (ifp->if_type) {
-#if 1
- case IFT_ARCNET:
- case IFT_ETHER:
- case IFT_FDDI:
-#else
- default:
-#endif
- /* mark the address TENTATIVE, if needed. */
- ia->ia6_flags |= IN6_IFF_TENTATIVE;
- /* nd6_dad_start() will be called in in6_if_up */
- }
+ if (error != EAFNOSUPPORT)
+ log(LOG_NOTICE, "in6_ifattach_linklocal: failed to "
+ "configure a link-local address on %s "
+ "(errno=%d)\n",
+ if_name(ifp), error);
+ return(-1);
}
- return 0;
-}
-
-static int
-in6_ifattach_linklocal(ifp, altifp)
- struct ifnet *ifp;
- struct ifnet *altifp; /*secondary EUI64 source*/
-{
- struct in6_ifaddr *ia;
-
/*
- * configure link-local address
+ * Adjust ia6_flags so that in6_if_up will perform DAD.
+ * XXX: Some P2P interfaces seem not to send packets just after
+ * becoming up, so we skip p2p interfaces for safety.
*/
- ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
- bzero((caddr_t)ia, sizeof(*ia));
- ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
- if (ifp->if_flags & IFF_POINTOPOINT)
- ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
- else
- ia->ia_ifa.ifa_dstaddr = NULL;
- ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
- ia->ia_ifp = ifp;
-
- bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
- ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
- ia->ia_prefixmask.sin6_family = AF_INET6;
-#ifdef SCOPEDROUTING
- /* take into accound the sin6_scope_id field for routing */
- ia->ia_prefixmask.sin6_scope_id = 0xffffffff;
-#endif
- ia->ia_prefixmask.sin6_addr = in6mask64;
-
- /* just in case */
- bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
- ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
- ia->ia_dstaddr.sin6_family = AF_INET6;
-
- bzero(&ia->ia_addr, sizeof(ia->ia_addr));
- ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
- ia->ia_addr.sin6_family = AF_INET6;
- ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
- ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
- ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
- if (ifp->if_flags & IFF_LOOPBACK) {
- ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
- ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
- } else {
- if (get_ifid(ifp, altifp, &ia->ia_addr.sin6_addr) != 0) {
-#ifdef ND6_DEBUG
- printf("%s: no ifid available\n", if_name(ifp));
-#endif
- free(ia, M_IFADDR);
- return -1;
- }
+ ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
+#ifdef DIAGNOSTIC
+ if (!ia) {
+ panic("ia == NULL in in6_ifattach_linklocal");
+ /*NOTREACHED*/
}
-#ifdef SCOPEDROUTING
- ia->ia_addr.sin6_scope_id = in6_addr2scopeid(ifp,
- &ia->ia_addr.sin6_addr);
#endif
+ if (in6if_do_dad(ifp) && (ifp->if_flags & IFF_POINTOPOINT) == 0) {
+ ia->ia6_flags &= ~IN6_IFF_NODAD;
+ ia->ia6_flags |= IN6_IFF_TENTATIVE;
+ }
- ia->ia_ifa.ifa_metric = ifp->if_metric;
-
- if (in6_ifattach_addaddr(ifp, ia) != 0) {
- /* ia will be freed on failure */
- return -1;
+ /*
+ * Make the link-local prefix (fe80::/64%link) as on-link.
+ * Since we'd like to manage prefixes separately from addresses,
+ * we make an ND6 prefix structure for the link-local prefix,
+ * and add it to the prefix list as a never-expire prefix.
+ * XXX: this change might affect some existing code base...
+ */
+ bzero(&pr0, sizeof(pr0));
+ pr0.ndpr_ifp = ifp;
+ /* this should be 64 at this moment. */
+ pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
+ pr0.ndpr_mask = ifra.ifra_prefixmask.sin6_addr;
+ pr0.ndpr_prefix = ifra.ifra_addr;
+ /* apply the mask for safety. (nd6_prelist_add will apply it again) */
+ for (i = 0; i < 4; i++) {
+ pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
+ in6mask64.s6_addr32[i];
+ }
+ /*
+ * Initialize parameters. The link-local prefix must always be
+ * on-link, and its lifetimes never expire.
+ */
+ pr0.ndpr_raf_onlink = 1;
+ pr0.ndpr_raf_auto = 1; /* probably meaningless */
+ pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
+ pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
+ /*
+ * Since there is no other link-local addresses, nd6_prefix_lookup()
+ * probably returns NULL. However, we cannot always expect the result.
+ * For example, if we first remove the (only) existing link-local
+ * address, and then reconfigure another one, the prefix is still
+ * valid with referring to the old link-local address.
+ */
+ if (nd6_prefix_lookup(&pr0) == NULL) {
+ if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
+ return(error);
}
return 0;
@@ -539,47 +561,52 @@ static int
in6_ifattach_loopback(ifp)
struct ifnet *ifp; /* must be IFT_LOOP */
{
- struct in6_ifaddr *ia;
+ struct in6_aliasreq ifra;
+ int error;
+
+ bzero(&ifra, sizeof(ifra));
/*
- * configure link-local address
+ * in6_update_ifa() does not use ifra_name, but we accurately set it
+ * for safety.
*/
- ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
- bzero((caddr_t)ia, sizeof(*ia));
- ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
- ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
- ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
- ia->ia_ifp = ifp;
-
- bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
- ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
- ia->ia_prefixmask.sin6_family = AF_INET6;
- ia->ia_prefixmask.sin6_addr = in6mask128;
+ strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
+
+ ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
+ ifra.ifra_prefixmask.sin6_family = AF_INET6;
+ ifra.ifra_prefixmask.sin6_addr = in6mask128;
/*
* Always initialize ia_dstaddr (= broadcast address) to loopback
- * address, to make getifaddr happier.
- *
- * For BSDI, it is mandatory. The BSDI version of
- * ifa_ifwithroute() rejects to add a route to the loopback
- * interface. Even for other systems, loopback looks somewhat
- * special.
+ * address. Follows IPv4 practice - see in_ifinit().
*/
- bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
- ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
- ia->ia_dstaddr.sin6_family = AF_INET6;
- ia->ia_dstaddr.sin6_addr = in6addr_loopback;
+ ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
+ ifra.ifra_dstaddr.sin6_family = AF_INET6;
+ ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
- bzero(&ia->ia_addr, sizeof(ia->ia_addr));
- ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
- ia->ia_addr.sin6_family = AF_INET6;
- ia->ia_addr.sin6_addr = in6addr_loopback;
+ ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
+ ifra.ifra_addr.sin6_family = AF_INET6;
+ ifra.ifra_addr.sin6_addr = in6addr_loopback;
- ia->ia_ifa.ifa_metric = ifp->if_metric;
+ /* the loopback address should NEVER expire. */
+ ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
+ ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
- if (in6_ifattach_addaddr(ifp, ia) != 0) {
- /* ia will be freed on failure */
- return -1;
+ /* we don't need to perfrom DAD on loopback interfaces. */
+ ifra.ifra_flags |= IN6_IFF_NODAD;
+
+ /* skip registration to the prefix list. XXX should be temporary. */
+ ifra.ifra_flags |= IN6_IFF_NOPFX;
+
+ /*
+ * We can set NULL to the 3rd arg. See comments in
+ * in6_ifattach_linklocal().
+ */
+ if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
+ log(LOG_ERR, "in6_ifattach_loopback: failed to configure "
+ "the loopback address on %s (errno=%d)\n",
+ if_name(ifp), error);
+ return(-1);
}
return 0;
@@ -591,17 +618,19 @@ in6_ifattach_loopback(ifp)
*
* when ifp == NULL, the caller is responsible for filling scopeid.
*/
-static int
-nigroup(ifp, name, namelen, in6)
+int
+in6_nigroup(ifp, name, namelen, in6)
struct ifnet *ifp;
const char *name;
int namelen;
struct in6_addr *in6;
{
const char *p;
+ u_char *q;
MD5_CTX ctxt;
u_int8_t digest[16];
char l;
+ char n[64]; /* a single label must not exceed 63 chars */
if (!namelen || !name)
return -1;
@@ -609,16 +638,21 @@ nigroup(ifp, name, namelen, in6)
p = name;
while (p && *p && *p != '.' && p - name < namelen)
p++;
- if (p - name > 63)
+ if (p - name > sizeof(n) - 1)
return -1; /*label too long*/
l = p - name;
+ strncpy(n, name, l);
+ n[(int)l] = '\0';
+ for (q = n; *q; q++) {
+ if ('A' <= *q && *q <= 'Z')
+ *q = *q - 'A' + 'a';
+ }
/* generate 8 bytes of pseudo-random value. */
bzero(&ctxt, sizeof(ctxt));
MD5Init(&ctxt);
MD5Update(&ctxt, &l, sizeof(l));
- /* LINTED const cast */
- MD5Update(&ctxt, (void *)name, p - name);
+ MD5Update(&ctxt, n, l);
MD5Final(digest, &ctxt);
bzero(in6, sizeof(*in6));
@@ -644,15 +678,21 @@ in6_nigroup_attach(name, namelen)
bzero(&mltaddr, sizeof(mltaddr));
mltaddr.sin6_family = AF_INET6;
mltaddr.sin6_len = sizeof(struct sockaddr_in6);
- if (nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
+ if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
return;
for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
{
mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
- if (!in6m)
- (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
+ if (!in6m) {
+ if (!in6_addmulti(&mltaddr.sin6_addr, ifp, &error)) {
+ nd6log((LOG_ERR, "%s: failed to join %s "
+ "(errno=%d)\n", if_name(ifp),
+ ip6_sprintf(&mltaddr.sin6_addr),
+ error));
+ }
+ }
}
}
@@ -668,7 +708,7 @@ in6_nigroup_detach(name, namelen)
bzero(&mltaddr, sizeof(mltaddr));
mltaddr.sin6_family = AF_INET6;
mltaddr.sin6_len = sizeof(struct sockaddr_in6);
- if (nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
+ if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
return;
for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
@@ -691,13 +731,16 @@ in6_ifattach(ifp, altifp)
struct ifnet *altifp; /* secondary EUI64 source */
{
static size_t if_indexlim = 8;
- struct sockaddr_in6 mltaddr;
- struct sockaddr_in6 mltmask;
- struct sockaddr_in6 gate;
- struct sockaddr_in6 mask;
struct in6_ifaddr *ia;
struct in6_addr in6;
- int hostnamelen = strlen(hostname);
+
+ /* some of the interfaces are inherently not IPv6 capable */
+ switch (ifp->if_type) {
+#ifdef IFT_BRIDGE /*OpenBSD 2.8*/
+ case IFT_BRIDGE:
+ return;
+#endif
+ }
/*
* We have some arrays that should be indexed by if_index.
@@ -763,134 +806,41 @@ in6_ifattach(ifp, altifp)
* usually, we require multicast capability to the interface
*/
if ((ifp->if_flags & IFF_MULTICAST) == 0) {
- printf("%s: not multicast capable, IPv6 not enabled\n",
+ log(LOG_INFO, "in6_ifattach: "
+ "%s is not multicast capable, IPv6 not enabled\n",
if_name(ifp));
return;
}
/*
- * assign link-local address, if there's none
- */
- ia = in6ifa_ifpforlinklocal(ifp, 0);
- if (ia == NULL) {
- if (in6_ifattach_linklocal(ifp, altifp) != 0)
- return;
- ia = in6ifa_ifpforlinklocal(ifp, 0);
-
- if (ia == NULL) {
- printf("%s: failed to add link-local address\n",
- if_name(ifp));
-
- /* we can't initialize multicasts without link-local */
- goto statinit;
- }
- }
-
- if (ifp->if_flags & IFF_POINTOPOINT) {
- /*
- * route local address to loopback
- */
- bzero(&gate, sizeof(gate));
- gate.sin6_len = sizeof(struct sockaddr_in6);
- gate.sin6_family = AF_INET6;
- gate.sin6_addr = in6addr_loopback;
- bzero(&mask, sizeof(mask));
- mask.sin6_len = sizeof(struct sockaddr_in6);
- mask.sin6_family = AF_INET6;
- mask.sin6_addr = in6mask64;
- rtrequest(RTM_ADD,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&gate,
- (struct sockaddr *)&mask,
- RTF_UP|RTF_HOST,
- (struct rtentry **)0);
- }
-
- /*
- * assign loopback address for loopback interface
- * XXX multiple loopback interface case
+ * assign loopback address for loopback interface.
+ * XXX multiple loopback interface case.
*/
- in6 = in6addr_loopback;
- if (ifp->if_flags & IFF_LOOPBACK) {
+ if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
+ in6 = in6addr_loopback;
if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
if (in6_ifattach_loopback(ifp) != 0)
return;
}
}
-#ifdef DIAGNOSTIC
- if (!ia) {
- panic("ia == NULL in in6_ifattach");
- /*NOTREACHED*/
- }
-#endif
-
/*
- * join multicast
+ * assign a link-local address, if there's none.
*/
- if (ifp->if_flags & IFF_MULTICAST) {
- int error; /* not used */
- struct in6_multi *in6m;
-
- bzero(&mltmask, sizeof(mltmask));
- mltmask.sin6_len = sizeof(struct sockaddr_in6);
- mltmask.sin6_family = AF_INET6;
- mltmask.sin6_addr = in6mask32;
-
- /*
- * join link-local all-nodes address
- */
- bzero(&mltaddr, sizeof(mltaddr));
- mltaddr.sin6_len = sizeof(struct sockaddr_in6);
- mltaddr.sin6_family = AF_INET6;
- mltaddr.sin6_addr = in6addr_linklocal_allnodes;
- mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
-
- IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
- if (in6m == NULL) {
- rtrequest(RTM_ADD,
- (struct sockaddr *)&mltaddr,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&mltmask,
- RTF_UP|RTF_CLONING, /* xxx */
- (struct rtentry **)0);
- (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
- }
-
- /*
- * join node information group address
- */
- if (nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr)
- == 0) {
- IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
- if (in6m == NULL && ia != NULL) {
- (void)in6_addmulti(&mltaddr.sin6_addr,
- ifp, &error);
- }
- }
-
- if (ifp->if_flags & IFF_LOOPBACK) {
- in6 = in6addr_loopback;
- ia = in6ifa_ifpwithaddr(ifp, &in6);
- /*
- * join node-local all-nodes address, on loopback
- */
- mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
-
- IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
- if (in6m == NULL && ia != NULL) {
- rtrequest(RTM_ADD,
- (struct sockaddr *)&mltaddr,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&mltmask,
- RTF_UP,
- (struct rtentry **)0);
- (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
+ if (ip6_auto_linklocal) {
+ ia = in6ifa_ifpforlinklocal(ifp, 0);
+ if (ia == NULL) {
+ if (in6_ifattach_linklocal(ifp, altifp) == 0) {
+ /* linklocal address assigned */
+ } else {
+ /* failed to assign linklocal address. bark? */
}
}
}
-statinit:;
+#ifdef IFT_STF /* XXX */
+statinit:
+#endif
/* update dynamically. */
if (in6_maxmtu < ifp->if_mtu)
@@ -913,6 +863,8 @@ statinit:;
/*
* NOTE: in6_ifdetach() does not support loopback if at this moment.
+ * We don't need this function in bsdi, because interfaces are never removed
+ * from the ifnet list in bsdi.
*/
void
in6_ifdetach(ifp)
@@ -938,7 +890,7 @@ in6_ifdetach(ifp)
next = ifa->ifa_list.tqe_next;
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
- in6_purgeaddr(ifa, ifp);
+ in6_purgeaddr(ifa);
}
/* undo everything done by in6_ifattach(), just in case */
@@ -979,11 +931,11 @@ in6_ifdetach(ifp)
ia = ia->ia_next;
if (ia->ia_next)
ia->ia_next = oia->ia_next;
-#ifdef ND6_DEBUG
- else
- printf("%s: didn't unlink in6ifaddr from "
- "list\n", if_name(ifp));
-#endif
+ else {
+ nd6log((LOG_ERR,
+ "%s: didn't unlink in6ifaddr from "
+ "list\n", if_name(ifp)));
+ }
}
IFAFREE(&oia->ia_ifa);
@@ -998,7 +950,14 @@ in6_ifdetach(ifp)
in6m = NULL;
}
- /* remove neighbor management table */
+ /*
+ * remove neighbor management table. we call it twice just to make
+ * sure we nuke everything. maybe we need just one call.
+ * XXX: since the first call did not release addresses, some prefixes
+ * might remain. We should call nd6_purge() again to release the
+ * prefixes after removing all addresses above.
+ * (Or can we just delay calling nd6_purge until at this point?)
+ */
nd6_purge(ifp);
/* remove route to link-local allnodes multicast (ff02::1) */
@@ -1014,3 +973,60 @@ in6_ifdetach(ifp)
rtfree(rt);
}
}
+
+void
+in6_get_tmpifid(ifp, retbuf, baseid, generate)
+ struct ifnet *ifp;
+ u_int8_t *retbuf;
+ const u_int8_t *baseid;
+ int generate;
+{
+ u_int8_t nullbuf[8];
+ struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
+
+ bzero(nullbuf, sizeof(nullbuf));
+ if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
+ /* we've never created a random ID. Create a new one. */
+ generate = 1;
+ }
+
+ if (generate) {
+ bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1));
+
+ /* generate_tmp_ifid will update seedn and buf */
+ (void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1,
+ ndi->randomid);
+ }
+ bcopy(ndi->randomid, retbuf, 8);
+}
+
+void
+in6_tmpaddrtimer(ignored_arg)
+ void *ignored_arg;
+{
+ int i;
+ struct nd_ifinfo *ndi;
+ u_int8_t nullbuf[8];
+ int s = splnet();
+
+ callout_reset(&in6_tmpaddrtimer_ch,
+ (ip6_temp_preferred_lifetime - ip6_desync_factor -
+ ip6_temp_regen_advance) * hz,
+ in6_tmpaddrtimer, NULL);
+
+ bzero(nullbuf, sizeof(nullbuf));
+ for (i = 1; i < if_index + 1; i++) {
+ ndi = &nd_ifinfo[i];
+ if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
+ /*
+ * We've been generating a random ID on this interface.
+ * Create a new one.
+ */
+ (void)generate_tmp_ifid(ndi->randomseed0,
+ ndi->randomseed1,
+ ndi->randomid);
+ }
+ }
+
+ splx(s);
+}
diff --git a/sys/netinet6/in6_ifattach.h b/sys/netinet6/in6_ifattach.h
index 4f82e41..fa4434f 100644
--- a/sys/netinet6/in6_ifattach.h
+++ b/sys/netinet6/in6_ifattach.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6_ifattach.h,v 1.10 2000/05/27 02:57:05 itojun Exp $ */
+/* $KAME: in6_ifattach.h,v 1.14 2001/02/08 12:48:39 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -38,6 +38,9 @@ void in6_nigroup_attach __P((const char *, int));
void in6_nigroup_detach __P((const char *, int));
void in6_ifattach __P((struct ifnet *, struct ifnet *));
void in6_ifdetach __P((struct ifnet *));
+void in6_get_tmpifid __P((struct ifnet *, u_int8_t *, const u_int8_t *, int));
+void in6_tmpaddrtimer __P((void *));
+int in6_nigroup __P((struct ifnet *, const char *, int, struct in6_addr *));
#endif /* _KERNEL */
#endif /* _NETINET6_IN6_IFATTACH_H_ */
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 67409be..9175a65 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6_pcb.c,v 1.8 2000/06/09 00:37:02 itojun Exp $ */
+/* $KAME: in6_pcb.c,v 1.31 2001/05/21 05:45:10 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -66,6 +66,8 @@
* @(#)in_pcb.c 8.2 (Berkeley) 1/4/94
*/
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_ipsec.h"
#include <sys/param.h>
@@ -99,12 +101,19 @@
#include <netinet6/in6_pcb.h>
#include "faith.h"
+#if defined(NFAITH) && NFAITH > 0
+#include <net/if_faith.h>
+#endif
#ifdef IPSEC
#include <netinet6/ipsec.h>
-#include <netinet6/ah.h>
+#ifdef INET6
#include <netinet6/ipsec6.h>
+#endif
+#include <netinet6/ah.h>
+#ifdef INET6
#include <netinet6/ah6.h>
+#endif
#include <netkey/key.h>
#endif /* IPSEC */
@@ -165,11 +174,12 @@ in6_pcbbind(inp, nam, p)
/*
* XXX: bind to an anycast address might accidentally
* cause sending a packet with anycast source address.
+ * We should allow to bind to a deprecated address, since
+ * the application dare to use it.
*/
if (ia &&
((struct in6_ifaddr *)ia)->ia6_flags &
- (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
- IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
+ (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) {
return(EADDRNOTAVAIL);
}
}
@@ -193,7 +203,7 @@ in6_pcbbind(inp, nam, p)
(so->so_cred->cr_uid !=
t->inp_socket->so_cred->cr_uid))
return (EADDRINUSE);
- if (ip6_mapped_addr_on != 0 &&
+ if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
@@ -215,7 +225,7 @@ in6_pcbbind(inp, nam, p)
lport, wild);
if (t && (reuseport & t->inp_socket->so_options) == 0)
return(EADDRINUSE);
- if (ip6_mapped_addr_on != 0 &&
+ if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
@@ -247,7 +257,6 @@ in6_pcbbind(inp, nam, p)
return (EAGAIN);
}
}
- inp->in6p_flowinfo = sin6 ? sin6->sin6_flowinfo : 0; /*XXX*/
return(0);
}
@@ -270,7 +279,6 @@ in6_pcbladdr(inp, nam, plocal_addr6)
struct in6_addr **plocal_addr6;
{
register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
- struct in6_pktinfo *pi;
struct ifnet *ifp = NULL;
int error = 0;
@@ -361,15 +369,11 @@ in6_pcbconnect(inp, nam, p)
}
inp->in6p_faddr = sin6->sin6_addr;
inp->inp_fport = sin6->sin6_port;
- /*
- * xxx kazu flowlabel is necessary for connect?
- * but if this line is missing, the garbage value remains.
- */
- inp->in6p_flowinfo = sin6->sin6_flowinfo;
- if ((inp->in6p_flowinfo & IPV6_FLOWLABEL_MASK) == 0 &&
- ip6_auto_flowlabel != 0)
+ /* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */
+ inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
+ if (inp->in6p_flags & IN6P_AUTOFLOWLABEL)
inp->in6p_flowinfo |=
- (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK);
+ (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK);
in_pcbrehash(inp);
return (0);
@@ -521,11 +525,14 @@ in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
}
if (ro->ro_rt == (struct rtentry *)0 ||
ro->ro_rt->rt_ifp == (struct ifnet *)0) {
+ struct sockaddr_in6 *dst6;
+
/* No route yet, so try to acquire one */
bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
- ro->ro_dst.sin6_family = AF_INET6;
- ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6);
- ro->ro_dst.sin6_addr = *dst;
+ dst6 = (struct sockaddr_in6 *)&ro->ro_dst;
+ dst6->sin6_family = AF_INET6;
+ dst6->sin6_len = sizeof(struct sockaddr_in6);
+ dst6->sin6_addr = *dst;
if (IN6_IS_ADDR_MULTICAST(dst)) {
ro->ro_rt = rtalloc1(&((struct route *)ro)
->ro_dst, 0, 0UL);
@@ -584,6 +591,8 @@ in6_pcbdisconnect(inp)
{
bzero((caddr_t)&inp->in6p_faddr, sizeof(inp->in6p_faddr));
inp->inp_fport = 0;
+ /* clear flowinfo - draft-itojun-ipv6-flowlabel-api-00 */
+ inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
in_pcbrehash(inp);
if (inp->inp_socket->so_state & SS_NOFDREF)
in6_pcbdetach(inp);
@@ -604,20 +613,13 @@ in6_pcbdetach(inp)
in_pcbremlists(inp);
sotoinpcb(so) = 0;
sofree(so);
+
if (inp->in6p_options)
m_freem(inp->in6p_options);
- if (inp->in6p_outputopts) {
- if (inp->in6p_outputopts->ip6po_rthdr &&
- inp->in6p_outputopts->ip6po_route.ro_rt)
- RTFREE(inp->in6p_outputopts->ip6po_route.ro_rt);
- if (inp->in6p_outputopts->ip6po_m)
- (void)m_free(inp->in6p_outputopts->ip6po_m);
- free(inp->in6p_outputopts, M_IP6OPT);
- }
+ ip6_freepcbopts(inp->in6p_outputopts);
+ ip6_freemoptions(inp->in6p_moptions);
if (inp->in6p_route.ro_rt)
rtfree(inp->in6p_route.ro_rt);
- ip6_freemoptions(inp->in6p_moptions);
-
/* Check and free IPv4 related resources in case of mapped addr */
if (inp->inp_options)
(void)m_free(inp->inp_options);
@@ -761,27 +763,33 @@ in6_mapped_peeraddr(struct socket *so, struct sockaddr **nam)
* Must be called at splnet.
*/
void
-in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
+in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, notify)
struct inpcbhead *head;
- struct sockaddr *dst;
+ struct sockaddr *dst, *src;
u_int fport_arg, lport_arg;
- struct in6_addr *laddr6;
int cmd;
void (*notify) __P((struct inpcb *, int));
{
struct inpcb *inp, *ninp;
- struct in6_addr faddr6;
+ struct sockaddr_in6 sa6_src, *sa6_dst;
u_short fport = fport_arg, lport = lport_arg;
+ u_int32_t flowinfo;
int errno, s;
- int do_rtchange = (notify == in6_rtchange);
if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6)
return;
- faddr6 = ((struct sockaddr_in6 *)dst)->sin6_addr;
- if (IN6_IS_ADDR_UNSPECIFIED(&faddr6))
+
+ sa6_dst = (struct sockaddr_in6 *)dst;
+ if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr))
return;
/*
+ * note that src can be NULL when we get notify by local fragmentation.
+ */
+ sa6_src = (src == NULL) ? sa6_any : *(struct sockaddr_in6 *)src;
+ flowinfo = sa6_src.sin6_flowinfo;
+
+ /*
* Redirects go to all references to the destination,
* and use in6_rtchange to invalidate the route cache.
* Dead host indications: also use in6_rtchange to invalidate
@@ -792,44 +800,45 @@ in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
fport = 0;
lport = 0;
- bzero((caddr_t)laddr6, sizeof(*laddr6));
+ bzero((caddr_t)&sa6_src.sin6_addr, sizeof(sa6_src.sin6_addr));
- do_rtchange = 1;
+ if (cmd != PRC_HOSTDEAD)
+ notify = in6_rtchange;
}
errno = inet6ctlerrmap[cmd];
s = splnet();
for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) {
ninp = LIST_NEXT(inp, inp_list);
- if ((inp->inp_vflag & INP_IPV6) == NULL)
+ if ((inp->inp_vflag & INP_IPV6) == 0)
continue;
- if (do_rtchange) {
- /*
- * Since a non-connected PCB might have a cached route,
- * we always call in6_rtchange without matching
- * the PCB to the src/dst pair.
- *
- * XXX: we assume in6_rtchange does not free the PCB.
- */
- if (IN6_ARE_ADDR_EQUAL(&inp->in6p_route.ro_dst.sin6_addr,
- &faddr6))
- in6_rtchange(inp, errno);
-
- if (notify == in6_rtchange)
- continue; /* there's nothing to do any more */
- }
-
- if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, &faddr6) ||
- inp->inp_socket == 0 ||
- (lport && inp->inp_lport != lport) ||
- (!IN6_IS_ADDR_UNSPECIFIED(laddr6) &&
- !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr6)) ||
- (fport && inp->inp_fport != fport))
+ /*
+ * Detect if we should notify the error. If no source and
+ * destination ports are specifed, but non-zero flowinfo and
+ * local address match, notify the error. This is the case
+ * when the error is delivered with an encrypted buffer
+ * by ESP. Otherwise, just compare addresses and ports
+ * as usual.
+ */
+ if (lport == 0 && fport == 0 && flowinfo &&
+ inp->inp_socket != NULL &&
+ flowinfo == (inp->in6p_flowinfo & IPV6_FLOWLABEL_MASK) &&
+ IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, &sa6_src.sin6_addr))
+ goto do_notify;
+ else if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr,
+ &sa6_dst->sin6_addr) ||
+ inp->inp_socket == 0 ||
+ (lport && inp->inp_lport != lport) ||
+ (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) &&
+ !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr,
+ &sa6_src.sin6_addr)) ||
+ (fport && inp->inp_fport != fport))
continue;
+ do_notify:
if (notify)
- (*notify)(inp, errno);
+ (*notify)(inp, errno);
}
splx(s);
}
@@ -990,6 +999,13 @@ in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp)
struct inpcbhead *head;
register struct inpcb *inp;
u_short fport = fport_arg, lport = lport_arg;
+ int faith;
+
+#if defined(NFAITH) && NFAITH > 0
+ faith = faithprefix(laddr);
+#else
+ faith = 0;
+#endif
/*
* First look for an exact match.
@@ -1020,11 +1036,8 @@ in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp)
continue;
if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) &&
inp->inp_lport == lport) {
-#if defined(NFAITH) && NFAITH > 0
- if (ifp && ifp->if_type == IFT_FAITH &&
- (inp->inp_flags & INP_FAITH) == 0)
+ if (faith && (inp->inp_flags & INP_FAITH) == 0)
continue;
-#endif
if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr,
laddr))
return (inp);
diff --git a/sys/netinet6/in6_pcb.h b/sys/netinet6/in6_pcb.h
index 2ea3107..15cd033 100644
--- a/sys/netinet6/in6_pcb.h
+++ b/sys/netinet6/in6_pcb.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6_pcb.h,v 1.5 2000/07/03 06:19:53 itojun Exp $ */
+/* $KAME: in6_pcb.h,v 1.13 2001/02/06 09:16:53 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -90,7 +90,7 @@ struct inpcb *
struct in6_addr *, u_int, struct in6_addr *,
u_int, int, struct ifnet *));
void in6_pcbnotify __P((struct inpcbhead *, struct sockaddr *,
- u_int, struct in6_addr *, u_int, int,
+ u_int, struct sockaddr *, u_int, int,
void (*)(struct inpcb *, int)));
void in6_rtchange __P((struct inpcb *, int));
int in6_setpeeraddr __P((struct socket *so, struct sockaddr **nam));
@@ -105,11 +105,6 @@ struct in6_addr *in6_selectsrc __P((struct sockaddr_in6 *,
int in6_selecthlim __P((struct in6pcb *, struct ifnet *));
int in6_pcbsetport __P((struct in6_addr *, struct inpcb *, struct proc *));
void init_sin6 __P((struct sockaddr_in6 *sin6, struct mbuf *m));
-
-int in6_embedscope __P((struct in6_addr *, const struct sockaddr_in6 *,
- struct inpcb *, struct ifnet **));
-int in6_recoverscope __P((struct sockaddr_in6 *, const struct in6_addr *,
- struct ifnet *));
#endif /* _KERNEL */
#endif /* !_NETINET6_IN6_PCB_H_ */
diff --git a/sys/netinet6/in6_prefix.c b/sys/netinet6/in6_prefix.c
index 1eaea50..e3325f9 100644
--- a/sys/netinet6/in6_prefix.c
+++ b/sys/netinet6/in6_prefix.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6_prefix.c,v 1.30 2000/06/12 14:53:17 jinmei Exp $ */
+/* $KAME: in6_prefix.c,v 1.47 2001/03/25 08:41:39 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -88,6 +88,8 @@ static MALLOC_DEFINE(M_RR_ADDR, "rp_addr", "IPv6 Router Renumbering Ifid");
struct rr_prhead rr_prefix;
+struct callout in6_rr_timer_ch;
+
#include <net/net_osdep.h>
static void add_each_addr __P((struct socket *so, struct rr_prefix *rpp,
@@ -399,7 +401,7 @@ assign_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia)
sizeof(*IA6_IN6(ia)) << 3, rpp->rp_plen, iilen);
/* link to ia, and put into list */
rap->ra_addr = ia;
- rap->ra_addr->ia_ifa.ifa_refcnt++;
+ IFAREF(&rap->ra_addr->ia_ifa);
#if 0 /* Can't do this now, because rpp may be on th stack. should fix it? */
ia->ia6_ifpr = rp2ifpr(rpp);
#endif
@@ -465,7 +467,7 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
if (ifpr == NULL) {
struct rr_prefix rp;
struct socket so;
- int pplen = (plen == 128) ? 64 : plen;
+ int pplen = (plen == 128) ? 64 : plen; /* XXX hardcoded 64 is bad */
/* allocate a prefix for ia, with default properties */
@@ -514,11 +516,11 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
if (rap != NULL) {
if (rap->ra_addr == NULL) {
rap->ra_addr = ia;
- rap->ra_addr->ia_ifa.ifa_refcnt++;
+ IFAREF(&rap->ra_addr->ia_ifa);
} else if (rap->ra_addr != ia) {
/* There may be some inconsistencies between addrs. */
log(LOG_ERR, "ip6_prefix.c: addr %s/%d matched prefix"
- "has already another ia %p(%s) on its ifid list\n",
+ " already has another ia %p(%s) on its ifid list\n",
ip6_sprintf(IA6_IN6(ia)), plen,
rap->ra_addr,
ip6_sprintf(IA6_IN6(rap->ra_addr)));
@@ -599,6 +601,14 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap)
in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, rpp->rp_plen);
/* don't care ifra_flags for now */
+ /*
+ * XXX: if we did this with finite lifetime values, the lifetimes would
+ * decrese in time and never incremented.
+ * we should need more clarifications on the prefix mechanism...
+ */
+ ifra.ifra_lifetime.ia6t_vltime = rpp->rp_vltime;
+ ifra.ifra_lifetime.ia6t_pltime = rpp->rp_pltime;
+
ia6 = in6ifa_ifpwithaddr(rpp->rp_ifp, &ifra.ifra_addr.sin6_addr);
if (ia6 != NULL) {
if (ia6->ia6_ifpr == NULL) {
@@ -606,7 +616,7 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap)
if (rap->ra_addr)
IFAFREE(&rap->ra_addr->ia_ifa);
rap->ra_addr = ia6;
- rap->ra_addr->ia_ifa.ifa_refcnt++;
+ IFAREF(&rap->ra_addr->ia_ifa);
ia6->ia6_ifpr = rp2ifpr(rpp);
return;
}
@@ -614,7 +624,7 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap)
if (rap->ra_addr)
IFAFREE(&rap->ra_addr->ia_ifa);
rap->ra_addr = ia6;
- rap->ra_addr->ia_ifa.ifa_refcnt++;
+ IFAREF(&rap->ra_addr->ia_ifa);
return;
}
/*
@@ -627,24 +637,26 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap)
* Or, completely duplicated prefixes?
* log it and return.
*/
- log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr"
- "%s/%d failed because there is already another addr %s/%d\n",
+ log(LOG_ERR,
+ "in6_prefix.c: add_each_addr: addition of an addr %s/%d "
+ "failed because there is already another addr %s/%d\n",
ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen,
ip6_sprintf(IA6_IN6(ia6)),
- in6_mask2len(&ia6->ia_prefixmask.sin6_addr));
+ in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL));
return;
}
/* propagate ANYCAST flag if it is set for ancestor addr */
if (rap->ra_flags.anycast != 0)
ifra.ifra_flags |= IN6_IFF_ANYCAST;
error = in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, rpp->rp_ifp,
- curproc);
- if (error != 0)
+ curproc);
+ if (error != 0) {
log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr"
"%s/%d failed because in6_control failed for error %d\n",
ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen,
error);
return;
+ }
/*
* link beween this addr and the prefix will be done
@@ -957,8 +969,10 @@ delete_each_prefix(struct rr_prefix *rpp, u_char origin)
s = splnet();
rap = LIST_FIRST(&rpp->rp_addrhead);
- if (rap == NULL)
+ if (rap == NULL) {
+ splx(s);
break;
+ }
LIST_REMOVE(rap, ra_entry);
splx(s);
if (rap->ra_addr == NULL) {
@@ -967,7 +981,7 @@ delete_each_prefix(struct rr_prefix *rpp, u_char origin)
}
rap->ra_addr->ia6_ifpr = NULL;
- in6_purgeaddr(&rap->ra_addr->ia_ifa, rpp->rp_ifp);
+ in6_purgeaddr(&rap->ra_addr->ia_ifa);
IFAFREE(&rap->ra_addr->ia_ifa);
free(rap, M_RR_ADDR);
}
@@ -1166,7 +1180,8 @@ in6_rr_timer(void *ignored_arg)
int s;
struct rr_prefix *rpp;
- timeout(in6_rr_timer, (caddr_t)0, ip6_rr_prune * hz);
+ callout_reset(&in6_rr_timer_ch, ip6_rr_prune * hz,
+ in6_rr_timer, NULL);
s = splnet();
/* expire */
diff --git a/sys/netinet6/in6_prefix.h b/sys/netinet6/in6_prefix.h
index 2ce18db..3ae6a63 100644
--- a/sys/netinet6/in6_prefix.h
+++ b/sys/netinet6/in6_prefix.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6_prefix.h,v 1.6 2000/03/25 07:23:45 sumikawa Exp $ */
+/* $KAME: in6_prefix.h,v 1.10 2001/02/08 16:30:30 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, 1998 and 1999 WIDE Project.
@@ -30,6 +30,8 @@
* SUCH DAMAGE.
*/
+#include <sys/callout.h>
+
struct rr_prefix {
struct ifprefix rp_ifpr;
LIST_ENTRY(rr_prefix) rp_entry;
@@ -85,4 +87,5 @@ LIST_HEAD(rr_prhead, rr_prefix);
extern struct rr_prhead rr_prefix;
void in6_rr_timer __P((void *));
+extern struct callout in6_rr_timer_ch;
int delete_each_prefix __P((struct rr_prefix *rpp, u_char origin));
diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c
index b221f8a..e73e4bb 100644
--- a/sys/netinet6/in6_proto.c
+++ b/sys/netinet6/in6_proto.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6_proto.c,v 1.64 2000/06/20 16:20:27 itojun Exp $ */
+/* $KAME: in6_proto.c,v 1.91 2001/05/27 13:28:35 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -99,25 +99,31 @@
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include <netinet6/tcp6_var.h>
-
+#include <netinet6/raw_ip6.h>
#include <netinet6/udp6_var.h>
-
#include <netinet6/pim6_var.h>
-
#include <netinet6/nd6.h>
#include <netinet6/in6_prefix.h>
#ifdef IPSEC
#include <netinet6/ipsec.h>
+#ifdef INET6
#include <netinet6/ipsec6.h>
+#endif
#include <netinet6/ah.h>
+#ifdef INET6
#include <netinet6/ah6.h>
+#endif
#ifdef IPSEC_ESP
#include <netinet6/esp.h>
+#ifdef INET6
#include <netinet6/esp6.h>
#endif
+#endif
#include <netinet6/ipcomp.h>
+#ifdef INET6
#include <netinet6/ipcomp6.h>
+#endif
#endif /*IPSEC*/
#include <netinet6/ip6protosw.h>
@@ -136,6 +142,9 @@
extern struct domain inet6domain;
static struct pr_usrreqs nousrreqs;
+#define PR_LISTEN 0
+#define PR_ABRTACPTDIS 0
+
struct ip6protosw inet6sw[] = {
{ 0, &inet6domain, IPPROTO_IPV6, 0,
0, 0, 0, 0,
@@ -143,30 +152,30 @@ struct ip6protosw inet6sw[] = {
ip6_init, 0, frag6_slowtimo, frag6_drain,
&nousrreqs,
},
-{ SOCK_DGRAM, &inet6domain, IPPROTO_UDP, PR_ATOMIC | PR_ADDR,
+{ SOCK_DGRAM, &inet6domain, IPPROTO_UDP, PR_ATOMIC|PR_ADDR,
udp6_input, 0, udp6_ctlinput, ip6_ctloutput,
0,
0, 0, 0, 0,
&udp6_usrreqs,
},
-{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED | PR_WANTRCVD,
+{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN,
tcp6_input, 0, tcp6_ctlinput, tcp_ctloutput,
0,
-#ifdef INET /* don't call timeout routines twice */
- tcp_init, 0, 0, tcp_drain,
+#ifdef INET /* don't call initialization and timeout routines twice */
+ 0, 0, 0, tcp_drain,
#else
tcp_init, tcp_fasttimo, tcp_slowtimo, tcp_drain,
#endif
&tcp6_usrreqs,
},
-{ SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC | PR_ADDR,
+{ SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR,
rip6_input, rip6_output, rip6_ctlinput, rip6_ctloutput,
0,
0, 0, 0, 0,
&rip6_usrreqs
},
-{ SOCK_RAW, &inet6domain, IPPROTO_ICMPV6, PR_ATOMIC | PR_ADDR,
- icmp6_input, rip6_output, 0, rip6_ctloutput,
+{ SOCK_RAW, &inet6domain, IPPROTO_ICMPV6, PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+ icmp6_input, rip6_output, rip6_ctlinput, rip6_ctloutput,
0,
icmp6_init, icmp6_fasttimo, 0, 0,
&rip6_usrreqs
@@ -191,15 +200,17 @@ struct ip6protosw inet6sw[] = {
},
#ifdef IPSEC
{ SOCK_RAW, &inet6domain, IPPROTO_AH, PR_ATOMIC|PR_ADDR,
- ah6_input, 0, 0, 0,
+ ah6_input, 0, 0, 0,
0,
0, 0, 0, 0,
&nousrreqs,
},
#ifdef IPSEC_ESP
{ SOCK_RAW, &inet6domain, IPPROTO_ESP, PR_ATOMIC|PR_ADDR,
- esp6_input, 0, 0, 0,
- 0,
+ esp6_input, 0,
+ esp6_ctlinput,
+ 0,
+ 0,
0, 0, 0, 0,
&nousrreqs,
},
@@ -212,34 +223,30 @@ struct ip6protosw inet6sw[] = {
},
#endif /* IPSEC */
#ifdef INET
-{ SOCK_RAW, &inet6domain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR,
+{ SOCK_RAW, &inet6domain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR|PR_LASTHDR,
encap6_input, rip6_output, 0, rip6_ctloutput,
0,
- 0, 0, 0, 0,
+ encap_init, 0, 0, 0,
&rip6_usrreqs
},
#endif /*INET*/
-{ SOCK_RAW, &inet6domain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR,
- encap6_input, rip6_output, 0, rip6_ctloutput,
+{ SOCK_RAW, &inet6domain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+ encap6_input, rip6_output, 0, rip6_ctloutput,
0,
-#ifndef INET
encap_init, 0, 0, 0,
-#else
- 0, 0, 0, 0,
-#endif
&rip6_usrreqs
},
-{ SOCK_RAW, &inet6domain, IPPROTO_PIM, PR_ATOMIC|PR_ADDR,
- pim6_input, rip6_output, 0, rip6_ctloutput,
+{ SOCK_RAW, &inet6domain, IPPROTO_PIM, PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+ pim6_input, rip6_output, 0, rip6_ctloutput,
0,
0, 0, 0, 0,
&rip6_usrreqs
},
/* raw wildcard */
-{ SOCK_RAW, &inet6domain, 0, PR_ATOMIC | PR_ADDR,
+{ SOCK_RAW, &inet6domain, 0, PR_ATOMIC|PR_ADDR,
rip6_input, rip6_output, 0, rip6_ctloutput,
- 0, 0,
- 0, 0, 0,
+ 0,
+ 0, 0, 0, 0,
&rip6_usrreqs
},
};
@@ -300,7 +307,7 @@ int ip6_gif_hlim = 0;
int ip6_use_deprecated = 1; /* allow deprecated addr (RFC2462 5.5.4) */
int ip6_rr_prune = 5; /* router renumbering prefix
* walk list every 5 sec. */
-int ip6_mapped_addr_on = 1;
+int ip6_v6only = 0;
u_int32_t ip6_id = 0UL;
int ip6_keepfaith = 0;
@@ -328,84 +335,8 @@ u_long rip6_recvspace = RIPV6RCVQ;
/* ICMPV6 parameters */
int icmp6_rediraccept = 1; /* accept and process redirects */
int icmp6_redirtimeout = 10 * 60; /* 10 minutes */
-struct timeval icmp6errratelim = { 0, 0 }; /* no ratelimit */
int icmp6errppslim = 100; /* 100pps */
-int icmp6_nodeinfo = 1; /* enable/disable NI response */
-
-#ifdef TCP6
-/* TCP on IP6 parameters */
-int tcp6_sendspace = 1024 * 8;
-int tcp6_recvspace = 1024 * 8;
-int tcp6_mssdflt = TCP6_MSS;
-int tcp6_rttdflt = TCP6TV_SRTTDFLT / PR_SLOWHZ;
-int tcp6_do_rfc1323 = 1;
-int tcp6_conntimeo = TCP6TV_KEEP_INIT; /* initial connection timeout */
-int tcp6_43maxseg = 0;
-int tcp6_pmtu = 0;
-
-/*
- * Parameters for keepalive option.
- * Connections for which SO_KEEPALIVE is set will be probed
- * after being idle for a time of tcp6_keepidle (in units of PR_SLOWHZ).
- * Starting at that time, the connection is probed at intervals
- * of tcp6_keepintvl (same units) until a response is received
- * or until tcp6_keepcnt probes have been made, at which time
- * the connection is dropped. Note that a tcp6_keepidle value
- * under 2 hours is nonconformant with RFC-1122, Internet Host Requirements.
- */
-int tcp6_keepidle = TCP6TV_KEEP_IDLE; /* time before probing idle */
-int tcp6_keepintvl = TCP6TV_KEEPINTVL; /* interval betwn idle probes */
-int tcp6_keepcnt = TCP6TV_KEEPCNT; /* max idle probes */
-int tcp6_maxpersistidle = TCP6TV_KEEP_IDLE; /* max idle time in persist */
-
-#ifndef INET_SERVER
-#define TCP6_LISTEN_HASH_SIZE 17
-#define TCP6_CONN_HASH_SIZE 97
-#define TCP6_SYN_HASH_SIZE 293
-#define TCP6_SYN_BUCKET_SIZE 35
-#else
-#define TCP6_LISTEN_HASH_SIZE 97
-#define TCP6_CONN_HASH_SIZE 9973
-#define TCP6_SYN_HASH_SIZE 997
-#define TCP6_SYN_BUCKET_SIZE 35
-#endif
-int tcp6_listen_hash_size = TCP6_LISTEN_HASH_SIZE;
-int tcp6_conn_hash_size = TCP6_CONN_HASH_SIZE;
-struct tcp6_hash_list tcp6_listen_hash[TCP6_LISTEN_HASH_SIZE],
- tcp6_conn_hash[TCP6_CONN_HASH_SIZE];
-
-int tcp6_syn_cache_size = TCP6_SYN_HASH_SIZE;
-int tcp6_syn_cache_limit = TCP6_SYN_HASH_SIZE*TCP6_SYN_BUCKET_SIZE;
-int tcp6_syn_bucket_limit = 3*TCP6_SYN_BUCKET_SIZE;
-struct syn_cache_head6 tcp6_syn_cache[TCP6_SYN_HASH_SIZE];
-struct syn_cache_head6 *tcp6_syn_cache_first;
-int tcp6_syn_cache_interval = 8; /* runs timer every 4 seconds */
-int tcp6_syn_cache_timeo = TCP6TV_KEEP_INIT;
-
-/*
- * Parameters for computing a desirable data segment size
- * given an upper bound (either interface MTU, or peer's MSS option)_.
- * As applications tend to use a buffer size that is a multiple
- * of kilobytes, try for something that divides evenly. However,
- * do not round down too much.
- *
- * Round segment size down to a multiple of TCP6_ROUNDSIZE if this
- * does not result in lowering by more than (size/TCP6_ROUNDFRAC).
- * For example, round 536 to 512. Older versions of the system
- * effectively used MCLBYTES (1K or 2K) as TCP6_ROUNDSIZE, with
- * a value of 1 for TCP6_ROUNDFRAC (eliminating its effect).
- * We round to a multiple of 256 for SLIP.
- */
-#ifndef TCP6_ROUNDSIZE
-#define TCP6_ROUNDSIZE 256 /* round to multiple of 256 */
-#endif
-#ifndef TCP6_ROUNDFRAC
-#define TCP6_ROUNDFRAC 10 /* round down at most N/10, or 10% */
-#endif
-
-int tcp6_roundsize = TCP6_ROUNDSIZE;
-int tcp6_roundfrac = TCP6_ROUNDFRAC;
-#endif /*TCP6*/
+int icmp6_nodeinfo = 3; /* enable/disable NI response */
/* UDP on IP6 parameters */
int udp6_sendspace = 9216; /* really max datagram size */
@@ -429,76 +360,44 @@ SYSCTL_NODE(_net_inet6, IPPROTO_ESP, ipsec6, CTLFLAG_RW, 0, "IPSEC6");
/* net.inet6.ip6 */
static int
-sysctl_ip6_forwarding(SYSCTL_HANDLER_ARGS)
+sysctl_ip6_temppltime(SYSCTL_HANDLER_ARGS)
{
int error = 0;
- int old_ip6_forwarding;
- int changed;
+ int old;
error = SYSCTL_OUT(req, arg1, sizeof(int));
if (error || !req->newptr)
return (error);
- old_ip6_forwarding = ip6_forwarding;
+ old = ip6_temp_preferred_lifetime;
error = SYSCTL_IN(req, arg1, sizeof(int));
- if (error != 0)
- return (error);
- changed = (ip6_forwarding ? 1 : 0) ^ (old_ip6_forwarding ? 1 : 0);
- if (changed == 0)
- return (error);
- /*
- * XXX while host->router removes prefix got from RA,
- * router->host case nukes all the prefixes managed by in6_prefix.c
- * (both RR and static). therefore, switching from host->router->host
- * will remove statically configured addresses/prefixes.
- * not sure if it is intended behavior or not.
- */
- if (ip6_forwarding != 0) { /* host becomes router */
- int s = splnet();
- struct nd_prefix *pr, *next;
-
- 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);
- } else { /* router becomes host */
- while(!LIST_EMPTY(&rr_prefix))
- delete_each_prefix(LIST_FIRST(&rr_prefix),
- PR_ORIG_KERNEL);
+ if (ip6_temp_preferred_lifetime <
+ ip6_desync_factor + ip6_temp_regen_advance) {
+ ip6_temp_preferred_lifetime = old;
+ return(EINVAL);
}
-
- return (error);
+ return(error);
}
static int
-sysctl_icmp6_ratelimit (SYSCTL_HANDLER_ARGS)
+sysctl_ip6_tempvltime(SYSCTL_HANDLER_ARGS)
{
- int rate_usec, error, s;
-
- /*
- * The sysctl specifies the rate in usec-between-icmp,
- * so we must convert from/to a timeval.
- */
- rate_usec = (icmp6errratelim.tv_sec * 1000000) +
- icmp6errratelim.tv_usec;
- error = sysctl_handle_int(oidp, &rate_usec, 0, req);
- if (error)
+ int error = 0;
+ int old;
+
+ error = SYSCTL_OUT(req, arg1, sizeof(int));
+ if (error || !req->newptr)
return (error);
- if (rate_usec < 0)
- return (EINVAL);
- s = splnet();
- icmp6errratelim.tv_sec = rate_usec / 1000000;
- icmp6errratelim.tv_usec = rate_usec % 1000000;
- splx(s);
-
- return (0);
+ old = ip6_temp_valid_lifetime;
+ error = SYSCTL_IN(req, arg1, sizeof(int));
+ if (ip6_temp_valid_lifetime < ip6_temp_preferred_lifetime) {
+ ip6_temp_preferred_lifetime = old;
+ return(EINVAL);
+ }
+ return(error);
}
-SYSCTL_OID(_net_inet6_ip6, IPV6CTL_FORWARDING, forwarding,
- CTLTYPE_INT|CTLFLAG_RW, &ip6_forwarding, 0, sysctl_ip6_forwarding,
- "I", "");
+SYSCTL_INT(_net_inet6_ip6, IPV6CTL_FORWARDING,
+ forwarding, CTLFLAG_RW, &ip6_forwarding, 0, "");
SYSCTL_INT(_net_inet6_ip6, IPV6CTL_SENDREDIRECTS,
redirect, CTLFLAG_RW, &ip6_sendredirects, 0, "");
SYSCTL_INT(_net_inet6_ip6, IPV6CTL_DEFHLIM,
@@ -527,8 +426,20 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_USE_DEPRECATED,
use_deprecated, CTLFLAG_RW, &ip6_use_deprecated, 0, "");
SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RR_PRUNE,
rr_prune, CTLFLAG_RW, &ip6_rr_prune, 0, "");
-SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAPPED_ADDR,
- mapped_addr, CTLFLAG_RW, &ip6_mapped_addr_on, 0, "");
+SYSCTL_INT(_net_inet6_ip6, IPV6CTL_USETEMPADDR,
+ use_tempaddr, CTLFLAG_RW, &ip6_use_tempaddr, 0, "");
+SYSCTL_OID(_net_inet6_ip6, IPV6CTL_TEMPPLTIME, temppltime,
+ CTLTYPE_INT|CTLFLAG_RW, &ip6_temp_preferred_lifetime, 0,
+ sysctl_ip6_temppltime, "I", "");
+SYSCTL_OID(_net_inet6_ip6, IPV6CTL_TEMPVLTIME, tempvltime,
+ CTLTYPE_INT|CTLFLAG_RW, &ip6_temp_valid_lifetime, 0,
+ sysctl_ip6_tempvltime, "I", "");
+SYSCTL_INT(_net_inet6_ip6, IPV6CTL_V6ONLY,
+ v6only, CTLFLAG_RW, &ip6_v6only, 0, "");
+SYSCTL_INT(_net_inet6_ip6, IPV6CTL_AUTO_LINKLOCAL,
+ auto_linklocal, CTLFLAG_RW, &ip6_auto_linklocal, 0, "");
+SYSCTL_STRUCT(_net_inet6_ip6, IPV6CTL_RIP6STATS, rip6stats, CTLFLAG_RD,
+ &rip6stat, rip6stat, "");
/* net.inet6.icmp6 */
SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_REDIRACCEPT,
@@ -537,9 +448,6 @@ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_REDIRTIMEOUT,
redirtimeout, CTLFLAG_RW, &icmp6_redirtimeout, 0, "");
SYSCTL_STRUCT(_net_inet6_icmp6, ICMPV6CTL_STATS, stats, CTLFLAG_RD,
&icmp6stat, icmp6stat, "");
-SYSCTL_PROC(_net_inet6_icmp6, ICMPV6CTL_ERRRATELIMIT,
- errratelimit, CTLTYPE_INT|CTLFLAG_RW,
- 0, sizeof(int), sysctl_icmp6_ratelimit, "I", "");
SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_PRUNE,
nd6_prune, CTLFLAG_RW, &nd6_prune, 0, "");
SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_DELAY,
@@ -556,3 +464,5 @@ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ERRPPSLIMIT,
errppslimit, CTLFLAG_RW, &icmp6errppslim, 0, "");
SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_MAXNUDHINT,
nd6_maxnudhint, CTLFLAG_RW, &nd6_maxnudhint, 0, "");
+SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_DEBUG,
+ nd6_debug, CTLFLAG_RW, &nd6_debug, 0, "");
diff --git a/sys/netinet6/in6_rmx.c b/sys/netinet6/in6_rmx.c
index 14f72d2..a56cfe2 100644
--- a/sys/netinet6/in6_rmx.c
+++ b/sys/netinet6/in6_rmx.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6_rmx.c,v 1.7 2000/04/06 08:30:43 sumikawa Exp $ */
+/* $KAME: in6_rmx.c,v 1.10 2001/05/24 05:44:58 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -146,23 +146,6 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
}
}
- /*
- * We also specify a send and receive pipe size for every
- * route added, to help TCP a bit. TCP doesn't actually
- * want a true pipe size, which would be prohibitive in memory
- * costs and is hard to compute anyway; it simply uses these
- * values to size its buffers. So, we fill them in with the
- * same values that TCP would have used anyway, and allow the
- * installing program or the link layer to override these values
- * as it sees fit. This will hopefully allow TCP more
- * opportunities to save its ssthresh value.
- */
- if (!rt->rt_rmx.rmx_sendpipe && !(rt->rt_rmx.rmx_locks & RTV_SPIPE))
- rt->rt_rmx.rmx_sendpipe = tcp_sendspace;
-
- if (!rt->rt_rmx.rmx_recvpipe && !(rt->rt_rmx.rmx_locks & RTV_RPIPE))
- rt->rt_rmx.rmx_recvpipe = tcp_recvspace;
-
if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU)
&& rt->rt_ifp)
rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu;
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c
index 765a692..7bf28d2 100644
--- a/sys/netinet6/in6_src.c
+++ b/sys/netinet6/in6_src.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6_src.c,v 1.27 2000/06/21 08:07:13 itojun Exp $ */
+/* $KAME: in6_src.c,v 1.37 2001/03/29 05:34:31 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -70,6 +70,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
@@ -97,9 +98,9 @@
#include <net/net_osdep.h>
/*
- * Return an IPv6 address, which is the most appropriate for given
+ * Return an IPv6 address, which is the most appropriate for a given
* destination and user specified options.
- * If necessary, this function lookups the routing table and return
+ * If necessary, this function lookups the routing table and returns
* an entry to the caller for later use.
*/
struct in6_addr *
@@ -241,12 +242,15 @@ in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
}
if (ro->ro_rt == (struct rtentry *)0 ||
ro->ro_rt->rt_ifp == (struct ifnet *)0) {
+ struct sockaddr_in6 *sa6;
+
/* No route yet, so try to acquire one */
bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
- ro->ro_dst.sin6_family = AF_INET6;
- ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6);
- ro->ro_dst.sin6_addr = *dst;
- ro->ro_dst.sin6_scope_id = dstsock->sin6_scope_id;
+ sa6 = (struct sockaddr_in6 *)&ro->ro_dst;
+ sa6->sin6_family = AF_INET6;
+ sa6->sin6_len = sizeof(struct sockaddr_in6);
+ sa6->sin6_addr = *dst;
+ sa6->sin6_scope_id = dstsock->sin6_scope_id;
if (IN6_IS_ADDR_MULTICAST(dst)) {
ro->ro_rt = rtalloc1(&((struct route *)ro)
->ro_dst, 0, 0UL);
@@ -529,15 +533,8 @@ in6_recoverscope(sin6, in6, ifp)
/* sanity check */
if (scopeid < 0 || if_index < scopeid)
return ENXIO;
-#ifndef FAKE_LOOPBACK_IF
- if (ifp && (ifp->if_flags & IFF_LOOPBACK) == 0 &&
- ifp->if_index != scopeid) {
- return ENXIO;
- }
-#else
if (ifp && ifp->if_index != scopeid)
return ENXIO;
-#endif
sin6->sin6_addr.s6_addr16[1] = 0;
sin6->sin6_scope_id = scopeid;
}
@@ -545,3 +542,15 @@ in6_recoverscope(sin6, in6, ifp)
return 0;
}
+
+/*
+ * just clear the embedded scope identifer.
+ * XXX: currently used for bsdi4 only as a supplement function.
+ */
+void
+in6_clearscope(addr)
+ struct in6_addr *addr;
+{
+ if (IN6_IS_SCOPE_LINKLOCAL(addr))
+ addr->s6_addr16[1] = 0;
+}
diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h
index f2f644e..bb5abc9 100644
--- a/sys/netinet6/in6_var.h
+++ b/sys/netinet6/in6_var.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: in6_var.h,v 1.33 2000/05/17 05:07:26 jinmei Exp $ */
+/* $KAME: in6_var.h,v 1.56 2001/03/29 05:34:31 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -102,8 +102,12 @@ struct in6_ifaddr {
struct in6_ifaddr *ia_next; /* next in6 list of IP6 addresses */
int ia6_flags;
- struct in6_addrlifetime ia6_lifetime; /* NULL = infty */
+ struct in6_addrlifetime ia6_lifetime;
struct ifprefix *ia6_ifpr; /* back pointer to ifprefix */
+
+ struct nd_prefix *ia6_ndpr; /* back pointer to the ND prefix
+ * (for autoconfigured addresses only)
+ */
};
/*
@@ -380,7 +384,10 @@ struct in6_rrenumreq {
#define SIOCGDRLST_IN6 _IOWR('i', 74, struct in6_drlist)
#define SIOCGPRLST_IN6 _IOWR('i', 75, struct in6_prlist)
-#define SIOCGIFINFO_IN6 _IOWR('i', 76, struct in6_ndireq)
+#ifdef _KERNEL
+#define OSIOCGIFINFO_IN6 _IOWR('i', 76, struct in6_ondireq)
+#endif
+#define SIOCGIFINFO_IN6 _IOWR('i', 108, struct in6_ndireq)
#define SIOCSNDFLUSH_IN6 _IOWR('i', 77, struct in6_ifreq)
#define SIOCGNBRINFO_IN6 _IOWR('i', 78, struct in6_nbrinfo)
#define SIOCSPFXFLUSH_IN6 _IOWR('i', 79, struct in6_ifreq)
@@ -419,6 +426,14 @@ struct in6_rrenumreq {
#define IN6_IFF_DUPLICATED 0x04 /* DAD detected duplicate */
#define IN6_IFF_DETACHED 0x08 /* may be detached from the link */
#define IN6_IFF_DEPRECATED 0x10 /* deprecated address */
+#define IN6_IFF_NODAD 0x20 /* don't perform DAD on this address
+ * (used only at first SIOC* call)
+ */
+#define IN6_IFF_AUTOCONF 0x40 /* autoconfigurable address. */
+#define IN6_IFF_TEMPORARY 0x80 /* temporary (anonymous) address. */
+#define IN6_IFF_NOPFX 0x8000 /* skip kernel prefix management.
+ * XXX: this should be temporary.
+ */
/* do not input/output */
#define IN6_IFF_NOTREADY (IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED)
@@ -516,7 +531,7 @@ struct in6_multistep {
/* struct ifnet *ifp; */ \
/* struct in6_multi *in6m; */ \
do { \
- register struct ifmultiaddr *ifma; \
+ struct ifmultiaddr *ifma; \
TAILQ_FOREACH(ifma, &(ifp)->if_multiaddrs, ifma_link) { \
if (ifma->ifma_addr->sa_family == AF_INET6 \
&& IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)ifma->ifma_addr)->sin6_addr, \
@@ -549,18 +564,19 @@ do { \
IN6_NEXT_MULTI((step), (in6m)); \
} while(0)
-int in6_ifinit __P((struct ifnet *,
- struct in6_ifaddr *, struct sockaddr_in6 *, int));
struct in6_multi *in6_addmulti __P((struct in6_addr *, struct ifnet *,
int *));
void in6_delmulti __P((struct in6_multi *));
-void in6_ifscrub __P((struct ifnet *, struct in6_ifaddr *));
extern int in6_ifindex2scopeid __P((int));
-extern int in6_mask2len __P((struct in6_addr *));
+extern int in6_mask2len __P((struct in6_addr *, u_char *));
extern void in6_len2mask __P((struct in6_addr *, int));
int in6_control __P((struct socket *,
u_long, caddr_t, struct ifnet *, struct proc *));
-void in6_purgeaddr __P((struct ifaddr *, struct ifnet *));
+int in6_update_ifa __P((struct ifnet *, struct in6_aliasreq *,
+ struct in6_ifaddr *));
+void in6_purgeaddr __P((struct ifaddr *));
+int in6if_do_dad __P((struct ifnet *));
+void in6_purgeif __P((struct ifnet *));
void in6_savemkludge __P((struct in6_ifaddr *));
void in6_setmaxmtu __P((void));
void in6_restoremkludge __P((struct in6_ifaddr *, struct ifnet *));
@@ -568,7 +584,7 @@ void in6_purgemkludge __P((struct ifnet *));
struct in6_ifaddr *in6ifa_ifpforlinklocal __P((struct ifnet *, int));
struct in6_ifaddr *in6ifa_ifpwithaddr __P((struct ifnet *,
struct in6_addr *));
-char *ip6_sprintf __P((struct in6_addr *));
+char *ip6_sprintf __P((const struct in6_addr *));
int in6_addr2scopeid __P((struct ifnet *, struct in6_addr *));
int in6_matchlen __P((struct in6_addr *, struct in6_addr *));
int in6_are_prefix_equal __P((struct in6_addr *p1, struct in6_addr *p2,
@@ -579,6 +595,14 @@ int in6_prefix_ioctl __P((struct socket *so, u_long cmd, caddr_t data,
int in6_prefix_add_ifid __P((int iilen, struct in6_ifaddr *ia));
void in6_prefix_remove_ifid __P((int iilen, struct in6_ifaddr *ia));
void in6_purgeprefix __P((struct ifnet *));
+
+int in6_is_addr_deprecated __P((struct sockaddr_in6 *));
+struct inpcb;
+int in6_embedscope __P((struct in6_addr *, const struct sockaddr_in6 *,
+ struct inpcb *, struct ifnet **));
+int in6_recoverscope __P((struct sockaddr_in6 *, const struct in6_addr *,
+ struct ifnet *));
+void in6_clearscope __P((struct in6_addr *));
#endif /* _KERNEL */
#endif /* _NETINET6_IN6_VAR_H_ */
diff --git a/sys/netinet6/ip6_ecn.h b/sys/netinet6/ip6_ecn.h
index e8dd11f..4107cf0 100644
--- a/sys/netinet6/ip6_ecn.h
+++ b/sys/netinet6/ip6_ecn.h
@@ -36,6 +36,6 @@
*/
#ifdef _KERNEL
-extern void ip6_ecn_ingress __P((int, u_int32_t *, u_int32_t *));
-extern void ip6_ecn_egress __P((int, u_int32_t *, u_int32_t *));
+extern void ip6_ecn_ingress __P((int, u_int32_t *, const u_int32_t *));
+extern void ip6_ecn_egress __P((int, const u_int32_t *, u_int32_t *));
#endif
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index 2664ccb..444cd2c 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip6_forward.c,v 1.43 2000/07/16 07:50:49 itojun Exp $ */
+/* $KAME: ip6_forward.c,v 1.69 2001/05/17 03:48:30 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -37,12 +37,14 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <sys/time.h>
+#include <sys/kernel.h>
#include <sys/syslog.h>
#include <net/if.h>
@@ -50,15 +52,22 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
#include <netinet/ip_var.h>
+#include <netinet6/in6_var.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet/icmp6.h>
#include <netinet6/nd6.h>
+#include <netinet/in_pcb.h>
+
#ifdef IPSEC
#include <netinet6/ipsec.h>
+#ifdef INET6
#include <netinet6/ipsec6.h>
+#endif
#include <netkey/key.h>
#endif /* IPSEC */
@@ -87,8 +96,8 @@ ip6_forward(m, srcrt)
int srcrt;
{
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
- register struct sockaddr_in6 *dst;
- register struct rtentry *rt;
+ struct sockaddr_in6 *dst;
+ struct rtentry *rt;
int error, type = 0, code = 0;
struct mbuf *mcopy = NULL;
struct ifnet *origifp; /* maybe unnecessary */
@@ -111,8 +120,15 @@ ip6_forward(m, srcrt)
}
#endif /*IPSEC*/
+ /*
+ * Do not forward packets to multicast destination (should be handled
+ * by ip6_mforward().
+ * Do not forward packets with unspecified source. It was discussed
+ * in July 2000, on ipngwg mailing list.
+ */
if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
- IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
+ IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
+ IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
ip6stat.ip6s_cantforward++;
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
if (ip6_log_time + ip6_log_interval < time_second) {
@@ -150,7 +166,8 @@ ip6_forward(m, srcrt)
#ifdef IPSEC
/* get a security policy for this packet */
- sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error);
+ sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, IP_FORWARDING,
+ &error);
if (sp == NULL) {
ipsec6stat.out_inval++;
ip6stat.ip6s_cantforward++;
@@ -238,10 +255,6 @@ ip6_forward(m, srcrt)
error = ipsec6_output_tunnel(&state, sp, 0);
m = state.m;
-#if 0 /* XXX allocate a route (ro, dst) again later */
- ro = (struct route_in6 *)state.ro;
- dst = (struct sockaddr_in6 *)state.dst;
-#endif
key_freesp(sp);
if (error) {
@@ -275,7 +288,7 @@ ip6_forward(m, srcrt)
skip_ipsec:
#endif /* IPSEC */
- dst = &ip6_forward_rt.ro_dst;
+ dst = (struct sockaddr_in6 *)&ip6_forward_rt.ro_dst;
if (!srcrt) {
/*
* ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst
@@ -293,7 +306,7 @@ ip6_forward(m, srcrt)
if (ip6_forward_rt.ro_rt == 0) {
ip6stat.ip6s_noroute++;
- /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
if (mcopy) {
icmp6_error(mcopy, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_NOROUTE, 0);
@@ -315,7 +328,7 @@ ip6_forward(m, srcrt)
rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING);
if (ip6_forward_rt.ro_rt == 0) {
ip6stat.ip6s_noroute++;
- /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
if (mcopy) {
icmp6_error(mcopy, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_NOROUTE, 0);
@@ -410,8 +423,25 @@ ip6_forward(m, srcrt)
* modified by a redirect.
*/
if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt &&
- (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0)
+ (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
+ if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) != 0) {
+ /*
+ * If the incoming interface is equal to the outgoing
+ * one, and the link attached to the interface is
+ * point-to-point, then it will be highly probable
+ * that a routing loop occurs. Thus, we immediately
+ * drop the packet and send an ICMPv6 error message.
+ *
+ * type/code is based on suggestion by Rich Draves.
+ * not sure if it is the best pick.
+ */
+ icmp6_error(mcopy, ICMP6_DST_UNREACH,
+ ICMP6_DST_UNREACH_ADDR, 0);
+ m_freem(m);
+ return;
+ }
type = ND_REDIRECT;
+ }
/*
* Check with the firewall...
@@ -432,8 +462,8 @@ ip6_forward(m, srcrt)
* destinaion can appear, if the originating node just sends the
* packet to us (without address resolution for the destination).
* Since both icmp6_error and icmp6_redirect_output fill the embedded
- * link identifiers, we can do this stuff after make a copy for
- * returning error.
+ * link identifiers, we can do this stuff after making a copy for
+ * returning an error.
*/
if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
/*
@@ -459,34 +489,21 @@ ip6_forward(m, srcrt)
if_name(rt->rt_ifp));
}
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
- origifp = ifindex2ifnet[ntohs(ip6->ip6_src.s6_addr16[1])];
- else if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
- origifp = ifindex2ifnet[ntohs(ip6->ip6_dst.s6_addr16[1])];
- else
- origifp = rt->rt_ifp;
+ /* we can just use rcvif in forwarding. */
+ origifp = m->m_pkthdr.rcvif;
}
else
origifp = rt->rt_ifp;
-#ifndef FAKE_LOOPBACK_IF
- if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
-#else
- if (1)
+#ifndef SCOPEDROUTING
+ /*
+ * clear embedded scope identifiers if necessary.
+ * in6_clearscope will touch the addresses only when necessary.
+ */
+ in6_clearscope(&ip6->ip6_src);
+ in6_clearscope(&ip6->ip6_dst);
#endif
- {
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
- ip6->ip6_src.s6_addr16[1] = 0;
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
- ip6->ip6_dst.s6_addr16[1] = 0;
- }
-#ifdef OLDIP6OUTPUT
- error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m,
- (struct sockaddr *)dst,
- ip6_forward_rt.ro_rt);
-#else
error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
-#endif
if (error) {
in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
ip6stat.ip6s_cantforward++;
diff --git a/sys/netinet6/ip6_fw.c b/sys/netinet6/ip6_fw.c
index ae1c0f1..f0245cf 100644
--- a/sys/netinet6/ip6_fw.c
+++ b/sys/netinet6/ip6_fw.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip6_fw.c,v 1.15 2000/07/02 14:17:37 itojun Exp $ */
+/* $KAME: ip6_fw.c,v 1.21 2001/01/24 01:25:32 itojun Exp $ */
/*
* Copyright (c) 1993 Daniel Boulet
@@ -87,7 +87,7 @@ LIST_HEAD (ip6_fw_head, ip6_fw_chain) ip6_fw_chain;
SYSCTL_DECL(_net_inet6_ip6);
SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, enable, CTLFLAG_RW,
- &ip6_fw_enable, 0, "Enable ip6fw");
+ &ip6_fw_enable, 0, "Enable ip6fw");
SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, debug, CTLFLAG_RW, &fw6_debug, 0, "");
SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw6_verbose, 0, "");
SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw6_verbose_limit, 0, "");
@@ -479,7 +479,7 @@ ip6_fw_chk(struct ip6_hdr **pip6,
}
#endif /* IP6FW_DIVERT_RESTART */
for (; chain; chain = LIST_NEXT(chain, chain)) {
- register struct ip6_fw *const f = chain->rule;
+ struct ip6_fw *const f = chain->rule;
if (oif) {
/* Check direction outbound */
@@ -758,7 +758,8 @@ got_match:
flags = TH_RST|TH_ACK;
}
bcopy(&ti, ip6, sizeof(ti));
- m_freem(*m);
+ tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1),
+ *m, ack, seq, flags);
*m = NULL;
break;
}
@@ -1064,7 +1065,7 @@ ip6_fw_ctl(int stage, struct mbuf **mm)
}
}
for (; fcp; fcp = fcp->chain.le_next) {
- memcpy(m->m_data, fcp->rule, sizeof *(fcp->rule));
+ bcopy(fcp->rule, m->m_data, sizeof *(fcp->rule));
m->m_len = sizeof *(fcp->rule);
m->m_next = m_get(M_TRYWAIT, MT_DATA); /* XXX */
if (!m->m_next) {
@@ -1204,7 +1205,7 @@ static int
ip6fw_modevent(module_t mod, int type, void *unused)
{
int s;
-
+
switch (type) {
case MOD_LOAD:
s = splnet();
@@ -1225,7 +1226,7 @@ ip6fw_modevent(module_t mod, int type, void *unused)
free(fcp->rule, M_IP6FW);
free(fcp, M_IP6FW);
}
-
+
splx(s);
printf("IPv6 firewall unloaded\n");
return 0;
diff --git a/sys/netinet6/ip6_fw.h b/sys/netinet6/ip6_fw.h
index bcd1a03..2298804 100644
--- a/sys/netinet6/ip6_fw.h
+++ b/sys/netinet6/ip6_fw.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip6_fw.h,v 1.3 2000/04/06 08:30:44 sumikawa Exp $ */
+/* $KAME: ip6_fw.h,v 1.7 2001/01/24 01:25:33 itojun Exp $ */
/*
* Copyright (c) 1993 Daniel Boulet
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index 4745347..4b10d8e 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip6_input.c,v 1.95 2000/07/02 07:49:37 jinmei Exp $ */
+/* $KAME: ip6_input.c,v 1.194 2001/05/27 13:28:35 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -73,6 +73,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
#include <sys/protosw.h>
@@ -108,6 +109,13 @@
#include <netinet6/nd6.h>
#include <netinet6/in6_prefix.h>
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#ifdef INET6
+#include <netinet6/ipsec6.h>
+#endif
+#endif
+
#include <netinet6/ip6_fw.h>
#include <netinet6/ip6protosw.h>
@@ -124,11 +132,16 @@ u_char ip6_protox[IPPROTO_MAX];
static int ip6qmaxlen = IFQ_MAXLEN;
struct in6_ifaddr *in6_ifaddr;
+extern struct callout in6_tmpaddrtimer_ch;
+
int ip6_forward_srcrt; /* XXX */
int ip6_sourcecheck; /* XXX */
int ip6_sourcecheck_interval; /* XXX */
const int int6intrq_present = 1;
+int ip6_ours_check_algorithm;
+
+
/* firewall hooks */
ip6_fw_chk_t *ip6_fw_chk_ptr;
ip6_fw_ctl_t *ip6_fw_ctl_ptr;
@@ -137,12 +150,14 @@ int ip6_fw_enable = 1;
struct ip6stat ip6stat;
static void ip6_init2 __P((void *));
+static struct mbuf *ip6_setdstifaddr __P((struct mbuf *, struct in6_ifaddr *));
static int ip6_hopopts_input __P((u_int32_t *, u_int32_t *, struct mbuf **, int *));
#ifdef PULLDOWN_TEST
static struct mbuf *ip6_pullexthdr __P((struct mbuf *, size_t, int));
#endif
+
/*
* IP6 initialization: fill in IP6 protocol switch table.
* All protocols not implemented in kernel go to raw IP6 protocol handler.
@@ -150,10 +165,14 @@ static struct mbuf *ip6_pullexthdr __P((struct mbuf *, size_t, int));
void
ip6_init()
{
- register struct ip6protosw *pr;
- register int i;
+ struct ip6protosw *pr;
+ int i;
struct timeval tv;
+#ifdef DIAGNOSTIC
+ if (sizeof(struct protosw) != sizeof(struct ip6protosw))
+ panic("sizeof(protosw) != sizeof(ip6protosw)");
+#endif
pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW);
if (pr == 0)
panic("ip6_init");
@@ -175,6 +194,8 @@ ip6_init()
*/
microtime(&tv);
ip6_flow_seq = random() ^ tv.tv_usec;
+ microtime(&tv);
+ ip6_desync_factor = (random() ^ tv.tv_usec) % MAX_TEMP_DESYNC_FACTOR;
}
static void
@@ -189,9 +210,18 @@ ip6_init2(dummy)
in6_ifattach(&loif[0], NULL);
/* nd6_timer_init */
- timeout(nd6_timer, (caddr_t)0, hz);
+ callout_init(&nd6_timer_ch, 0);
+ callout_reset(&nd6_timer_ch, hz, nd6_timer, NULL);
+
/* router renumbering prefix list maintenance */
- timeout(in6_rr_timer, (caddr_t)0, hz);
+ callout_init(&in6_rr_timer_ch, 0);
+ callout_reset(&in6_rr_timer_ch, hz, in6_rr_timer, NULL);
+
+ /* timer for regeneranation of temporary addresses randomize ID */
+ callout_reset(&in6_tmpaddrtimer_ch,
+ (ip6_temp_preferred_lifetime - ip6_desync_factor -
+ ip6_temp_regen_advance) * hz,
+ in6_tmpaddrtimer, NULL);
}
/* cheat */
@@ -247,6 +277,11 @@ ip6_input(m)
#endif
/*
+ * make sure we don't have onion peering information into m_aux.
+ */
+ ip6_delaux(m);
+
+ /*
* mbuf statistics by kazu
*/
if (m->m_flags & M_EXT) {
@@ -255,15 +290,17 @@ ip6_input(m)
else
ip6stat.ip6s_mext1++;
} else {
+#define M2MMAX (sizeof(ip6stat.ip6s_m2m)/sizeof(ip6stat.ip6s_m2m[0]))
if (m->m_next) {
if (m->m_flags & M_LOOP) {
ip6stat.ip6s_m2m[loif[0].if_index]++; /*XXX*/
- } else if (m->m_pkthdr.rcvif->if_index <= 31)
+ } else if (m->m_pkthdr.rcvif->if_index < M2MMAX)
ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++;
else
ip6stat.ip6s_m2m[0]++;
} else
ip6stat.ip6s_m1++;
+#undef M2MMAX
}
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive);
@@ -360,20 +397,42 @@ ip6_input(m)
}
/*
- * Scope check
+ * Check against address spoofing/corruption.
*/
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) ||
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) {
+ /*
+ * XXX: "badscope" is not very suitable for a multicast source.
+ */
+ ip6stat.ip6s_badscope++;
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
+ goto bad;
+ }
+ if ((IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) ||
+ IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) &&
+ (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
ip6stat.ip6s_badscope++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
goto bad;
}
-
/*
- * Don't check IPv4 mapped address here. SIIT assumes that
- * routers would forward IPv6 native packets with IPv4 mapped
- * address normally.
+ * The following check is not documented in specs. A malicious
+ * party may be able to use IPv4 mapped addr to confuse tcp/udp stack
+ * and bypass security checks (act as if it was from 127.0.0.1 by using
+ * IPv6 src ::ffff:127.0.0.1). Be cautious.
+ *
+ * This check chokes if we are in an SIIT cloud. As none of BSDs
+ * support IPv4-less kernel compilation, we cannot support SIIT
+ * environment at all. So, it makes more sense for us to reject any
+ * malicious packets for non-SIIT environment, than try to do a
+ * partical support for SIIT environment.
*/
+ if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
+ IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
+ ip6stat.ip6s_badscope++;
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
+ goto bad;
+ }
#if 0
/*
* Reject packets with IPv4 compatible addresses (auto tunnel).
@@ -389,105 +448,52 @@ ip6_input(m)
goto bad;
}
#endif
- if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) ||
- IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
- if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) {
- struct in6_ifaddr *ia6;
-
- if ((ia6 = in6ifa_ifpwithaddr(m->m_pkthdr.rcvif,
- &ip6->ip6_dst)) != NULL) {
- ia6->ia_ifa.if_ipackets++;
- ia6->ia_ifa.if_ibytes += m->m_pkthdr.len;
- } else {
- /*
- * The packet is looped back, but we do not
- * have the destination address for some
- * reason.
- * XXX: should we return an icmp6 error?
- */
- goto bad;
- }
- ours = 1;
- deliverifp = m->m_pkthdr.rcvif;
- goto hbhcheck;
- } else {
+
+ /* drop packets if interface ID portion is already filled */
+ if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src) &&
+ ip6->ip6_src.s6_addr16[1]) {
+ ip6stat.ip6s_badscope++;
+ goto bad;
+ }
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst) &&
+ ip6->ip6_dst.s6_addr16[1]) {
ip6stat.ip6s_badscope++;
- in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
goto bad;
}
}
-#ifndef FAKE_LOOPBACK_IF
- if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0)
-#else
- if (1)
-#endif
- {
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
- ip6->ip6_src.s6_addr16[1]
- = htons(m->m_pkthdr.rcvif->if_index);
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
- ip6->ip6_dst.s6_addr16[1]
- = htons(m->m_pkthdr.rcvif->if_index);
- }
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
+ ip6->ip6_src.s6_addr16[1]
+ = htons(m->m_pkthdr.rcvif->if_index);
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
+ ip6->ip6_dst.s6_addr16[1]
+ = htons(m->m_pkthdr.rcvif->if_index);
+#if 0 /* this case seems to be unnecessary. (jinmei, 20010401) */
/*
- * XXX we need this since we do not have "goto ours" hack route
- * for some of our ifaddrs on loopback interface.
- * we should correct it by changing in6_ifattach to install
- * "goto ours" hack route.
+ * We use rt->rt_ifp to determine if the address is ours or not.
+ * If rt_ifp is lo0, the address is ours.
+ * The problem here is, rt->rt_ifp for fe80::%lo0/64 is set to lo0,
+ * so any address under fe80::%lo0/64 will be mistakenly considered
+ * local. The special case is supplied to handle the case properly
+ * by actually looking at interface addresses
+ * (using in6ifa_ifpwithaddr).
*/
- if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) != 0) {
- if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) {
- struct in6_ifaddr *ia6;
-#ifndef FAKE_LOOPBACK_IF
- int deliverifid;
-
- /*
- * Get the "real" delivered interface, which should be
- * embedded in the second 16 bits of the destination
- * address. We can probably trust the value, but we
- * add validation for the value just for safety.
- */
- deliverifid = ntohs(ip6->ip6_dst.s6_addr16[1]);
- if (deliverifid > 0 && deliverifid <= if_index) {
- deliverifp = ifindex2ifnet[deliverifid];
-
- /*
- * XXX: fake the rcvif to the real interface.
- * Since m_pkthdr.rcvif should be lo0 (or a
- * variant), it would confuse scope handling
- * code later.
- */
- m->m_pkthdr.rcvif = deliverifp;
- }
- else {
- /*
- * Last resort; just use rcvif.
- * XXX: the packet would be discarded by the
- * succeeding check.
- */
- deliverifp = m->m_pkthdr.rcvif;
- }
-#else
- deliverifp = m->m_pkthdr.rcvif;
-#endif
- if ((ia6 = in6ifa_ifpwithaddr(deliverifp,
- &ip6->ip6_dst)) != NULL) {
- ia6->ia_ifa.if_ipackets++;
- ia6->ia_ifa.if_ibytes += m->m_pkthdr.len;
- } else {
- /*
- * We do not have the link-local address
- * specified as the destination.
- * XXX: should we return an icmp6 error?
- */
- goto bad;
- }
- ours = 1;
- goto hbhcheck;
+ if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) != 0 &&
+ IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) {
+ if (!in6ifa_ifpwithaddr(m->m_pkthdr.rcvif, &ip6->ip6_dst)) {
+ icmp6_error(m, ICMP6_DST_UNREACH,
+ ICMP6_DST_UNREACH_ADDR, 0);
+ /* m is already freed */
+ return;
}
+
+ ours = 1;
+ deliverifp = m->m_pkthdr.rcvif;
+ goto hbhcheck;
}
+#endif
/*
* Multicast check
@@ -516,12 +522,21 @@ ip6_input(m)
/*
* Unicast check
*/
+ switch (ip6_ours_check_algorithm) {
+ default:
+ /*
+ * XXX: I intentionally broke our indentation rule here,
+ * since this switch-case is just for measurement and
+ * therefore should soon be removed.
+ */
if (ip6_forward_rt.ro_rt != NULL &&
(ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 &&
IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
- &ip6_forward_rt.ro_dst.sin6_addr))
+ &((struct sockaddr_in6 *)(&ip6_forward_rt.ro_dst))->sin6_addr))
ip6stat.ip6s_forward_cachehit++;
else {
+ struct sockaddr_in6 *dst6;
+
if (ip6_forward_rt.ro_rt) {
/* route is down or destination is different */
ip6stat.ip6s_forward_cachemiss++;
@@ -530,9 +545,10 @@ ip6_input(m)
}
bzero(&ip6_forward_rt.ro_dst, sizeof(struct sockaddr_in6));
- ip6_forward_rt.ro_dst.sin6_len = sizeof(struct sockaddr_in6);
- ip6_forward_rt.ro_dst.sin6_family = AF_INET6;
- ip6_forward_rt.ro_dst.sin6_addr = ip6->ip6_dst;
+ dst6 = (struct sockaddr_in6 *)&ip6_forward_rt.ro_dst;
+ dst6->sin6_len = sizeof(struct sockaddr_in6);
+ dst6->sin6_family = AF_INET6;
+ dst6->sin6_addr = ip6->ip6_dst;
#ifdef SCOPEDROUTING
ip6_forward_rt.ro_dst.sin6_scope_id =
in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_dst);
@@ -551,10 +567,27 @@ ip6_input(m)
* route to the loopback interface for the destination of the packet.
* But we think it's even useful in some situations, e.g. when using
* a special daemon which wants to intercept the packet.
+ *
+ * XXX: some OSes automatically make a cloned route for the destination
+ * of an outgoing packet. If the outgoing interface of the packet
+ * is a loopback one, the kernel would consider the packet to be
+ * accepted, even if we have no such address assinged on the interface.
+ * We check the cloned flag of the route entry to reject such cases,
+ * assuming that route entries for our own addresses are not made by
+ * cloning (it should be true because in6_addloop explicitly installs
+ * the host route). However, we might have to do an explicit check
+ * while it would be less efficient. Or, should we rather install a
+ * reject route for such a case?
*/
if (ip6_forward_rt.ro_rt &&
(ip6_forward_rt.ro_rt->rt_flags &
(RTF_HOST|RTF_GATEWAY)) == RTF_HOST &&
+#ifdef RTF_WASCLONED
+ !(ip6_forward_rt.ro_rt->rt_flags & RTF_WASCLONED) &&
+#endif
+#ifdef RTF_CLONED
+ !(ip6_forward_rt.ro_rt->rt_flags & RTF_CLONED) &&
+#endif
#if 0
/*
* The check below is redundant since the comparison of
@@ -562,13 +595,17 @@ ip6_input(m)
* already done through looking up the routing table.
*/
IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
- &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr) &&
+ &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr)
#endif
ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_LOOP) {
struct in6_ifaddr *ia6 =
(struct in6_ifaddr *)ip6_forward_rt.ro_rt->rt_ifa;
- if (ia6->ia6_flags & IN6_IFF_ANYCAST)
- m->m_flags |= M_ANYCAST6;
+
+ /*
+ * record address information into m_aux.
+ */
+ (void)ip6_setdstifaddr(m, ia6);
+
/*
* packets to a tentative, duplicated, or somehow invalid
* address must not be accepted.
@@ -577,22 +614,21 @@ ip6_input(m)
/* this address is ready */
ours = 1;
deliverifp = ia6->ia_ifp; /* correct? */
-
/* Count the packet in the ip address stats */
ia6->ia_ifa.if_ipackets++;
ia6->ia_ifa.if_ibytes += m->m_pkthdr.len;
-
goto hbhcheck;
} else {
/* address is not ready, so discard the packet. */
- log(LOG_INFO,
- "ip6_input: packet to an unready address %s->%s",
+ nd6log((LOG_INFO,
+ "ip6_input: packet to an unready address %s->%s\n",
ip6_sprintf(&ip6->ip6_src),
- ip6_sprintf(&ip6->ip6_dst));
+ ip6_sprintf(&ip6->ip6_dst)));
goto bad;
}
}
+ } /* XXX indentation (see above) */
/*
* FAITH(Firewall Aided Internet Translator)
@@ -621,6 +657,27 @@ ip6_input(m)
hbhcheck:
/*
+ * record address information into m_aux, if we don't have one yet.
+ * note that we are unable to record it, if the address is not listed
+ * as our interface address (e.g. multicast addresses, addresses
+ * within FAITH prefixes and such).
+ */
+ if (deliverifp && !ip6_getdstifaddr(m)) {
+ struct in6_ifaddr *ia6;
+
+ ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst);
+ if (ia6) {
+ if (!ip6_setdstifaddr(m, ia6)) {
+ /*
+ * XXX maybe we should drop the packet here,
+ * as we could not provide enough information
+ * to the upper layers.
+ */
+ }
+ }
+ }
+
+ /*
* Process Hop-by-Hop options header if it's contained.
* m may be modified in ip6_hopopts_input().
* If a JumboPayload option is included, plen will also be modified.
@@ -749,6 +806,7 @@ ip6_input(m)
ip6stat.ip6s_delivered++;
in6_ifstat_inc(deliverifp, ifs6_in_deliver);
nest = 0;
+
while (nxt != IPPROTO_DONE) {
if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
ip6stat.ip6s_toomanyhdr++;
@@ -765,6 +823,35 @@ ip6_input(m)
goto bad;
}
+#if 0
+ /*
+ * do we need to do it for every header? yeah, other
+ * functions can play with it (like re-allocate and copy).
+ */
+ mhist = ip6_addaux(m);
+ if (mhist && M_TRAILINGSPACE(mhist) >= sizeof(nxt)) {
+ hist = mtod(mhist, caddr_t) + mhist->m_len;
+ bcopy(&nxt, hist, sizeof(nxt));
+ mhist->m_len += sizeof(nxt);
+ } else {
+ ip6stat.ip6s_toomanyhdr++;
+ goto bad;
+ }
+#endif
+
+#ifdef IPSEC
+ /*
+ * enforce IPsec policy checking if we are seeing last header.
+ * note that we do not visit this with protocols with pcb layer
+ * code - like udp/tcp/raw ip.
+ */
+ if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
+ ipsec6_in_reject(m, NULL)) {
+ ipsec6stat.in_polvio++;
+ goto bad;
+ }
+#endif
+
nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt);
}
return;
@@ -773,6 +860,36 @@ ip6_input(m)
}
/*
+ * set/grab in6_ifaddr correspond to IPv6 destination address.
+ * XXX backward compatibility wrapper
+ */
+static struct mbuf *
+ip6_setdstifaddr(m, ia6)
+ struct mbuf *m;
+ struct in6_ifaddr *ia6;
+{
+ struct mbuf *n;
+
+ n = ip6_addaux(m);
+ if (n)
+ mtod(n, struct ip6aux *)->ip6a_dstia6 = ia6;
+ return n; /* NULL if failed to set */
+}
+
+struct in6_ifaddr *
+ip6_getdstifaddr(m)
+ struct mbuf *m;
+{
+ struct mbuf *n;
+
+ n = ip6_findaux(m);
+ if (n)
+ return mtod(n, struct ip6aux *)->ip6a_dstia6;
+ else
+ return NULL;
+}
+
+/*
* Hop-by-Hop options header processing. If a valid jumbo payload option is
* included, the real payload length will be stored in plenp.
*/
@@ -783,7 +900,7 @@ ip6_hopopts_input(plenp, rtalertp, mp, offp)
struct mbuf **mp;
int *offp;
{
- register struct mbuf *m = *mp;
+ struct mbuf *m = *mp;
int off = *offp, hbhlen;
struct ip6_hbh *hbh;
u_int8_t *opt;
@@ -829,6 +946,10 @@ ip6_hopopts_input(plenp, rtalertp, mp, offp)
* This function is separate from ip6_hopopts_input() in order to
* handle a case where the sending node itself process its hop-by-hop
* options header. In such a case, the function is called from ip6_output().
+ *
+ * The function assumes that hbh header is located right after the IPv6 header
+ * (RFC2460 p7), opthead is pointer into data content in m, and opthead to
+ * opthead + hbhlen is located in continuous memory region.
*/
int
ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
@@ -843,58 +964,62 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
u_int8_t *opt = opthead;
u_int16_t rtalert_val;
u_int32_t jumboplen;
+ const int erroff = sizeof(struct ip6_hdr) + sizeof(struct ip6_hbh);
for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) {
- switch(*opt) {
- case IP6OPT_PAD1:
- optlen = 1;
- break;
- case IP6OPT_PADN:
- if (hbhlen < IP6OPT_MINLEN) {
- ip6stat.ip6s_toosmall++;
- goto bad;
- }
- optlen = *(opt + 1) + 2;
- break;
- case IP6OPT_RTALERT:
- /* XXX may need check for alignment */
- if (hbhlen < IP6OPT_RTALERT_LEN) {
- ip6stat.ip6s_toosmall++;
- goto bad;
- }
- if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2)
- /* XXX: should we discard the packet? */
- log(LOG_ERR, "length of router alert opt is inconsitent(%d)",
- *(opt + 1));
- optlen = IP6OPT_RTALERT_LEN;
- bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2);
- *rtalertp = ntohs(rtalert_val);
- break;
- case IP6OPT_JUMBO:
+ switch (*opt) {
+ case IP6OPT_PAD1:
+ optlen = 1;
+ break;
+ case IP6OPT_PADN:
+ if (hbhlen < IP6OPT_MINLEN) {
+ ip6stat.ip6s_toosmall++;
+ goto bad;
+ }
+ optlen = *(opt + 1) + 2;
+ break;
+ case IP6OPT_RTALERT:
+ /* XXX may need check for alignment */
+ if (hbhlen < IP6OPT_RTALERT_LEN) {
+ ip6stat.ip6s_toosmall++;
+ goto bad;
+ }
+ if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) {
+ /* XXX stat */
+ icmp6_error(m, ICMP6_PARAM_PROB,
+ ICMP6_PARAMPROB_HEADER,
+ erroff + opt + 1 - opthead);
+ return(-1);
+ }
+ optlen = IP6OPT_RTALERT_LEN;
+ bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2);
+ *rtalertp = ntohs(rtalert_val);
+ break;
+ case IP6OPT_JUMBO:
/* XXX may need check for alignment */
if (hbhlen < IP6OPT_JUMBO_LEN) {
ip6stat.ip6s_toosmall++;
goto bad;
}
- if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2)
- /* XXX: should we discard the packet? */
- log(LOG_ERR, "length of jumbopayload opt "
- "is inconsistent(%d)",
- *(opt + 1));
+ if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) {
+ /* XXX stat */
+ icmp6_error(m, ICMP6_PARAM_PROB,
+ ICMP6_PARAMPROB_HEADER,
+ erroff + opt + 1 - opthead);
+ return(-1);
+ }
optlen = IP6OPT_JUMBO_LEN;
/*
* IPv6 packets that have non 0 payload length
- * must not contain a jumbo paylod option.
+ * must not contain a jumbo payload option.
*/
ip6 = mtod(m, struct ip6_hdr *);
if (ip6->ip6_plen) {
ip6stat.ip6s_badoptions++;
icmp6_error(m, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
- sizeof(struct ip6_hdr) +
- sizeof(struct ip6_hbh) +
- opt - opthead);
+ erroff + opt - opthead);
return(-1);
}
@@ -918,9 +1043,7 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
ip6stat.ip6s_badoptions++;
icmp6_error(m, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
- sizeof(struct ip6_hdr) +
- sizeof(struct ip6_hbh) +
- opt + 2 - opthead);
+ erroff + opt + 2 - opthead);
return(-1);
}
#endif
@@ -932,26 +1055,23 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
ip6stat.ip6s_badoptions++;
icmp6_error(m, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
- sizeof(struct ip6_hdr) +
- sizeof(struct ip6_hbh) +
- opt + 2 - opthead);
+ erroff + opt + 2 - opthead);
return(-1);
}
*plenp = jumboplen;
break;
- default: /* unknown option */
- if (hbhlen < IP6OPT_MINLEN) {
- ip6stat.ip6s_toosmall++;
- goto bad;
- }
- if ((optlen = ip6_unknown_opt(opt, m,
- sizeof(struct ip6_hdr) +
- sizeof(struct ip6_hbh) +
- opt - opthead)) == -1)
- return(-1);
- optlen += 2;
- break;
+ default: /* unknown option */
+ if (hbhlen < IP6OPT_MINLEN) {
+ ip6stat.ip6s_toosmall++;
+ goto bad;
+ }
+ optlen = ip6_unknown_opt(opt, m,
+ erroff + opt - opthead);
+ if (optlen == -1)
+ return(-1);
+ optlen += 2;
+ break;
}
}
@@ -976,26 +1096,26 @@ ip6_unknown_opt(optp, m, off)
{
struct ip6_hdr *ip6;
- switch(IP6OPT_TYPE(*optp)) {
- case IP6OPT_TYPE_SKIP: /* ignore the option */
- return((int)*(optp + 1));
- case IP6OPT_TYPE_DISCARD: /* silently discard */
- m_freem(m);
- return(-1);
- case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */
- ip6stat.ip6s_badoptions++;
- icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off);
- return(-1);
- case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */
- ip6stat.ip6s_badoptions++;
- ip6 = mtod(m, struct ip6_hdr *);
- if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
- (m->m_flags & (M_BCAST|M_MCAST)))
- m_freem(m);
- else
- icmp6_error(m, ICMP6_PARAM_PROB,
- ICMP6_PARAMPROB_OPTION, off);
- return(-1);
+ switch (IP6OPT_TYPE(*optp)) {
+ case IP6OPT_TYPE_SKIP: /* ignore the option */
+ return((int)*(optp + 1));
+ case IP6OPT_TYPE_DISCARD: /* silently discard */
+ m_freem(m);
+ return(-1);
+ case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */
+ ip6stat.ip6s_badoptions++;
+ icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off);
+ return(-1);
+ case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */
+ ip6stat.ip6s_badoptions++;
+ ip6 = mtod(m, struct ip6_hdr *);
+ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
+ (m->m_flags & (M_BCAST|M_MCAST)))
+ m_freem(m);
+ else
+ icmp6_error(m, ICMP6_PARAM_PROB,
+ ICMP6_PARAMPROB_OPTION, off);
+ return(-1);
}
m_freem(m); /* XXX: NOTREACHED */
@@ -1004,50 +1124,44 @@ ip6_unknown_opt(optp, m, off)
/*
* Create the "control" list for this pcb.
+ * The function will not modify mbuf chain at all.
*
+ * with KAME mbuf chain restriction:
* The routine will be called from upper layer handlers like tcp6_input().
* Thus the routine assumes that the caller (tcp6_input) have already
* called IP6_EXTHDR_CHECK() and all the extension headers are located in the
* very first mbuf on the mbuf chain.
- * We may want to add some infinite loop prevention or sanity checks for safety.
- * (This applies only when you are using KAME mbuf chain restriction, i.e.
- * you are using IP6_EXTHDR_CHECK() not m_pulldown())
*/
void
ip6_savecontrol(in6p, mp, ip6, m)
- register struct in6pcb *in6p;
- register struct mbuf **mp;
- register struct ip6_hdr *ip6;
- register struct mbuf *m;
+ struct inpcb *in6p;
+ struct mbuf **mp;
+ struct ip6_hdr *ip6;
+ struct mbuf *m;
{
struct proc *p = curproc; /* XXX */
- int privileged;
+ int privileged = 0;
+ int rthdr_exist = 0;
+
- privileged = 0;
if (p && !suser(p))
- privileged++;
+ privileged++;
- if (in6p->in6p_socket->so_options & SO_TIMESTAMP) {
+#ifdef SO_TIMESTAMP
+ if ((in6p->in6p_socket->so_options & SO_TIMESTAMP) != 0) {
struct timeval tv;
microtime(&tv);
*mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
- SCM_TIMESTAMP, SOL_SOCKET);
- if (*mp)
+ SCM_TIMESTAMP, SOL_SOCKET);
+ if (*mp) {
mp = &(*mp)->m_next;
+ }
}
-
-#ifdef noyet
- /* options were tossed above */
- if (in6p->in6p_flags & IN6P_RECVOPTS)
- /* broken */
- /* ip6_srcroute doesn't do what we want here, need to fix */
- if (in6p->in6p_flags & IPV6P_RECVRETOPTS)
- /* broken */
#endif
/* RFC 2292 sec. 5 */
- if (in6p->in6p_flags & IN6P_PKTINFO) {
+ if ((in6p->in6p_flags & IN6P_PKTINFO) != 0) {
struct in6_pktinfo pi6;
bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr));
if (IN6_IS_SCOPE_LINKLOCAL(&pi6.ipi6_addr))
@@ -1061,14 +1175,14 @@ ip6_savecontrol(in6p, mp, ip6, m)
if (*mp)
mp = &(*mp)->m_next;
}
- if (in6p->in6p_flags & IN6P_HOPLIMIT) {
+
+ if ((in6p->in6p_flags & IN6P_HOPLIMIT) != 0) {
int hlim = ip6->ip6_hlim & 0xff;
*mp = sbcreatecontrol((caddr_t) &hlim,
sizeof(int), IPV6_HOPLIMIT, IPPROTO_IPV6);
if (*mp)
mp = &(*mp)->m_next;
}
- /* IN6P_NEXTHOP - for outgoing packet only */
/*
* IPV6_HOPOPTS socket option. We require super-user privilege
@@ -1076,7 +1190,7 @@ ip6_savecontrol(in6p, mp, ip6, m)
* be some hop-by-hop options which can be returned to normal user.
* See RFC 2292 section 6.
*/
- if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) {
+ if ((in6p->in6p_flags & IN6P_HOPOPTS) != 0 && privileged) {
/*
* Check if a hop-by-hop options header is contatined in the
* received packet, and if so, store the options as ancillary
@@ -1087,22 +1201,25 @@ ip6_savecontrol(in6p, mp, ip6, m)
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
struct ip6_hbh *hbh;
- int hbhlen;
+ int hbhlen = 0;
+#ifdef PULLDOWN_TEST
+ struct mbuf *ext;
+#endif
#ifndef PULLDOWN_TEST
hbh = (struct ip6_hbh *)(ip6 + 1);
hbhlen = (hbh->ip6h_len + 1) << 3;
#else
- IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
- sizeof(struct ip6_hdr), sizeof(struct ip6_hbh));
- if (hbh == NULL) {
+ ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr),
+ ip6->ip6_nxt);
+ if (ext == NULL) {
ip6stat.ip6s_tooshort++;
return;
}
+ hbh = mtod(ext, struct ip6_hbh *);
hbhlen = (hbh->ip6h_len + 1) << 3;
- IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
- sizeof(struct ip6_hdr), hbhlen);
- if (hbh == NULL) {
+ if (hbhlen != ext->m_len) {
+ m_freem(ext);
ip6stat.ip6s_tooshort++;
return;
}
@@ -1112,19 +1229,53 @@ ip6_savecontrol(in6p, mp, ip6, m)
* XXX: We copy whole the header even if a jumbo
* payload option is included, which option is to
* be removed before returning in the RFC 2292.
- * But it's too painful operation...
+ * Note: this constraint is removed in 2292bis.
*/
*mp = sbcreatecontrol((caddr_t)hbh, hbhlen,
IPV6_HOPOPTS, IPPROTO_IPV6);
if (*mp)
mp = &(*mp)->m_next;
+#ifdef PULLDOWN_TEST
+ m_freem(ext);
+#endif
}
}
/* IPV6_DSTOPTS and IPV6_RTHDR socket options */
- if (in6p->in6p_flags & (IN6P_DSTOPTS | IN6P_RTHDR)) {
+ if ((in6p->in6p_flags & (IN6P_DSTOPTS | IN6P_RTHDRDSTOPTS)) != 0) {
+ int proto, off, nxt;
+
+ /*
+ * go through the header chain to see if a routing header is
+ * contained in the packet. We need this information to store
+ * destination options headers (if any) properly.
+ * XXX: performance issue. We should record this info when
+ * processing extension headers in incoming routine.
+ * (todo) use m_aux?
+ */
+ proto = IPPROTO_IPV6;
+ off = 0;
+ nxt = -1;
+ while (1) {
+ int newoff;
+
+ newoff = ip6_nexthdr(m, off, proto, &nxt);
+ if (newoff < 0)
+ break;
+ if (newoff < off) /* invalid, check for safety */
+ break;
+ if ((proto = nxt) == IPPROTO_ROUTING) {
+ rthdr_exist = 1;
+ break;
+ }
+ off = newoff;
+ }
+ }
+
+ if ((in6p->in6p_flags &
+ (IN6P_RTHDR | IN6P_DSTOPTS | IN6P_RTHDRDSTOPTS)) != 0) {
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
- int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr);;
+ int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr);
/*
* Search for destination options headers or routing
@@ -1133,95 +1284,172 @@ ip6_savecontrol(in6p, mp, ip6, m)
* Note that the order of the headers remains in
* the chain of ancillary data.
*/
- while(1) { /* is explicit loop prevention necessary? */
- struct ip6_ext *ip6e;
+ while (1) { /* is explicit loop prevention necessary? */
+ struct ip6_ext *ip6e = NULL;
int elen;
+#ifdef PULLDOWN_TEST
+ struct mbuf *ext = NULL;
+#endif
+
+ /*
+ * if it is not an extension header, don't try to
+ * pull it from the chain.
+ */
+ switch (nxt) {
+ case IPPROTO_DSTOPTS:
+ case IPPROTO_ROUTING:
+ case IPPROTO_HOPOPTS:
+ case IPPROTO_AH: /* is it possible? */
+ break;
+ default:
+ goto loopend;
+ }
#ifndef PULLDOWN_TEST
+ if (off + sizeof(*ip6e) > m->m_len)
+ goto loopend;
ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off);
if (nxt == IPPROTO_AH)
elen = (ip6e->ip6e_len + 2) << 2;
else
elen = (ip6e->ip6e_len + 1) << 3;
+ if (off + elen > m->m_len)
+ goto loopend;
#else
- IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off,
- sizeof(struct ip6_ext));
- if (ip6e == NULL) {
+ ext = ip6_pullexthdr(m, off, nxt);
+ if (ext == NULL) {
ip6stat.ip6s_tooshort++;
return;
}
+ ip6e = mtod(ext, struct ip6_ext *);
if (nxt == IPPROTO_AH)
elen = (ip6e->ip6e_len + 2) << 2;
else
elen = (ip6e->ip6e_len + 1) << 3;
- IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off, elen);
- if (ip6e == NULL) {
+ if (elen != ext->m_len) {
+ m_freem(ext);
ip6stat.ip6s_tooshort++;
return;
}
#endif
- switch(nxt) {
- case IPPROTO_DSTOPTS:
- if (!in6p->in6p_flags & IN6P_DSTOPTS)
- break;
-
- /*
- * We also require super-user privilege for
- * the option.
- * See the comments on IN6_HOPOPTS.
- */
- if (!privileged)
- break;
-
- *mp = sbcreatecontrol((caddr_t)ip6e, elen,
- IPV6_DSTOPTS,
- IPPROTO_IPV6);
- if (*mp)
- mp = &(*mp)->m_next;
- break;
-
- case IPPROTO_ROUTING:
- if (!in6p->in6p_flags & IN6P_RTHDR)
- break;
-
- *mp = sbcreatecontrol((caddr_t)ip6e, elen,
- IPV6_RTHDR,
- IPPROTO_IPV6);
- if (*mp)
- mp = &(*mp)->m_next;
- break;
-
- case IPPROTO_UDP:
- case IPPROTO_TCP:
- case IPPROTO_ICMPV6:
- default:
- /*
- * stop search if we encounter an upper
- * layer protocol headers.
- */
- goto loopend;
-
- case IPPROTO_HOPOPTS:
- case IPPROTO_AH: /* is it possible? */
- break;
+ switch (nxt) {
+ case IPPROTO_DSTOPTS:
+ if ((in6p->in6p_flags & IN6P_DSTOPTS) == 0)
+ break;
+
+ /*
+ * We also require super-user privilege for
+ * the option.
+ * See the comments on IN6_HOPOPTS.
+ */
+ if (!privileged)
+ break;
+
+ *mp = sbcreatecontrol((caddr_t)ip6e, elen,
+ IPV6_DSTOPTS,
+ IPPROTO_IPV6);
+ if (*mp)
+ mp = &(*mp)->m_next;
+ break;
+ case IPPROTO_ROUTING:
+ if (!in6p->in6p_flags & IN6P_RTHDR)
+ break;
+
+ *mp = sbcreatecontrol((caddr_t)ip6e, elen,
+ IPV6_RTHDR,
+ IPPROTO_IPV6);
+ if (*mp)
+ mp = &(*mp)->m_next;
+ break;
+ case IPPROTO_HOPOPTS:
+ case IPPROTO_AH: /* is it possible? */
+ break;
+
+ default:
+ /*
+ * other cases have been filtered in the above.
+ * none will visit this case. here we supply
+ * the code just in case (nxt overwritten or
+ * other cases).
+ */
+#ifdef PULLDOWN_TEST
+ m_freem(ext);
+#endif
+ goto loopend;
+
}
/* proceed with the next header. */
off += elen;
nxt = ip6e->ip6e_nxt;
+ ip6e = NULL;
+#ifdef PULLDOWN_TEST
+ m_freem(ext);
+ ext = NULL;
+#endif
}
loopend:
+ ;
}
- if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) {
- /* to be done */
+
+}
+
+#ifdef PULLDOWN_TEST
+/*
+ * pull single extension header from mbuf chain. returns single mbuf that
+ * contains the result, or NULL on error.
+ */
+static struct mbuf *
+ip6_pullexthdr(m, off, nxt)
+ struct mbuf *m;
+ size_t off;
+ int nxt;
+{
+ struct ip6_ext ip6e;
+ size_t elen;
+ struct mbuf *n;
+
+#ifdef DIAGNOSTIC
+ switch (nxt) {
+ case IPPROTO_DSTOPTS:
+ case IPPROTO_ROUTING:
+ case IPPROTO_HOPOPTS:
+ case IPPROTO_AH: /* is it possible? */
+ break;
+ default:
+ printf("ip6_pullexthdr: invalid nxt=%d\n", nxt);
+ }
+#endif
+
+ m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
+ if (nxt == IPPROTO_AH)
+ elen = (ip6e.ip6e_len + 2) << 2;
+ else
+ elen = (ip6e.ip6e_len + 1) << 3;
+
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (n && elen >= MLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_free(n);
+ n = NULL;
+ }
}
- if ((in6p->in6p_flags & IN6P_DSTOPTS) && privileged) {
- /* to be done */
+ if (!n)
+ return NULL;
+
+ n->m_len = 0;
+ if (elen >= M_TRAILINGSPACE(n)) {
+ m_free(n);
+ return NULL;
}
- /* IN6P_RTHDR - to be done */
+ m_copydata(m, off, elen, mtod(n, caddr_t));
+ n->m_len = elen;
+ return n;
}
+#endif
/*
* Get pointer to the previous header followed by the header
@@ -1253,7 +1481,7 @@ ip6_get_prevhdr(m, off)
while (len < off) {
ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len);
- switch(nxt) {
+ switch (nxt) {
case IPPROTO_FRAGMENT:
len += sizeof(struct ip6_frag);
break;
@@ -1382,6 +1610,55 @@ ip6_lasthdr(m, off, proto, nxtp)
}
}
+struct mbuf *
+ip6_addaux(m)
+ struct mbuf *m;
+{
+ struct mbuf *n;
+
+#ifdef DIAGNOSTIC
+ if (sizeof(struct ip6aux) > MHLEN)
+ panic("assumption failed on sizeof(ip6aux)");
+#endif
+ n = m_aux_find(m, AF_INET6, -1);
+ if (n) {
+ if (n->m_len < sizeof(struct ip6aux)) {
+ printf("conflicting use of ip6aux");
+ return NULL;
+ }
+ } else {
+ n = m_aux_add(m, AF_INET6, -1);
+ n->m_len = sizeof(struct ip6aux);
+ bzero(mtod(n, caddr_t), n->m_len);
+ }
+ return n;
+}
+
+struct mbuf *
+ip6_findaux(m)
+ struct mbuf *m;
+{
+ struct mbuf *n;
+
+ n = m_aux_find(m, AF_INET6, -1);
+ if (n && n->m_len < sizeof(struct ip6aux)) {
+ printf("conflicting use of ip6aux");
+ n = NULL;
+ }
+ return n;
+}
+
+void
+ip6_delaux(m)
+ struct mbuf *m;
+{
+ struct mbuf *n;
+
+ n = m_aux_find(m, AF_INET6, -1);
+ if (n)
+ m_aux_delete(m, n);
+}
+
/*
* System control for IP6
*/
diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c
index 82b0d4b..2be8796 100644
--- a/sys/netinet6/ip6_mroute.c
+++ b/sys/netinet6/ip6_mroute.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip6_mroute.c,v 1.33 2000/10/19 02:23:43 jinmei Exp $ */
+/* $KAME: ip6_mroute.c,v 1.46 2001/04/04 05:17:30 itojun Exp $ */
/*
* Copyright (C) 1998 WIDE Project.
@@ -50,6 +50,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/callout.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
@@ -143,7 +144,6 @@ static mifi_t nummifs = 0;
static mifi_t reg_mif_num = (mifi_t)-1;
static struct pim6stat pim6stat;
-static struct callout_handle expire_upcalls_ch;
/*
* one-back cache used by ipip_input to locate a tunnel's mif
@@ -165,7 +165,7 @@ static int pim6;
*/
#define MF6CFIND(o, g, rt) do { \
- register struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \
+ struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \
rt = NULL; \
mrt6stat.mrt6s_mfc_lookups++; \
while (_rt) { \
@@ -187,7 +187,7 @@ static int pim6;
* Borrowed from Van Jacobson's scheduling code
*/
#define TV_DELTA(a, b, delta) do { \
- register int xxs; \
+ int xxs; \
\
delta = (a).tv_usec - (b).tv_usec; \
if ((xxs = (a).tv_sec - (b).tv_sec)) { \
@@ -221,6 +221,8 @@ static int del_m6if __P((mifi_t *));
static int add_m6fc __P((struct mf6cctl *));
static int del_m6fc __P((struct mf6cctl *));
+static struct callout expire_upcalls_ch;
+
/*
* Handle MRT setsockopt commands to modify the multicast routing tables.
*/
@@ -241,33 +243,33 @@ ip6_mrouter_set(so, sopt)
return (error);
switch (sopt->sopt_name) {
- case MRT6_INIT:
+ case MRT6_INIT:
#ifdef MRT6_OINIT
- case MRT6_OINIT:
+ case MRT6_OINIT:
#endif
- error = ip6_mrouter_init(so, m, sopt->sopt_name);
- break;
- case MRT6_DONE:
- error = ip6_mrouter_done();
- break;
- case MRT6_ADD_MIF:
- error = add_m6if(mtod(m, struct mif6ctl *));
- break;
- case MRT6_DEL_MIF:
- error = del_m6if(mtod(m, mifi_t *));
- break;
- case MRT6_ADD_MFC:
- error = add_m6fc(mtod(m, struct mf6cctl *));
- break;
- case MRT6_DEL_MFC:
- error = del_m6fc(mtod(m, struct mf6cctl *));
- break;
- case MRT6_PIM:
- error = set_pim6(mtod(m, int *));
- break;
- default:
- error = EOPNOTSUPP;
- break;
+ error = ip6_mrouter_init(so, m, sopt->sopt_name);
+ break;
+ case MRT6_DONE:
+ error = ip6_mrouter_done();
+ break;
+ case MRT6_ADD_MIF:
+ error = add_m6if(mtod(m, struct mif6ctl *));
+ break;
+ case MRT6_DEL_MIF:
+ error = del_m6if(mtod(m, mifi_t *));
+ break;
+ case MRT6_ADD_MFC:
+ error = add_m6fc(mtod(m, struct mf6cctl *));
+ break;
+ case MRT6_DEL_MFC:
+ error = del_m6fc(mtod(m, struct mf6cctl *));
+ break;
+ case MRT6_PIM:
+ error = set_pim6(mtod(m, int *));
+ break;
+ default:
+ error = EOPNOTSUPP;
+ break;
}
(void)m_freem(m);
@@ -302,20 +304,20 @@ mrt6_ioctl(cmd, data)
int cmd;
caddr_t data;
{
- int error = 0;
-
- switch (cmd) {
- case SIOCGETSGCNT_IN6:
- return(get_sg_cnt((struct sioc_sg_req6 *)data));
- break; /* for safety */
- case SIOCGETMIFCNT_IN6:
- return(get_mif6_cnt((struct sioc_mif_req6 *)data));
- break; /* for safety */
- default:
- return (EINVAL);
- break;
- }
- return error;
+ int error = 0;
+
+ switch (cmd) {
+ case SIOCGETSGCNT_IN6:
+ return(get_sg_cnt((struct sioc_sg_req6 *)data));
+ break; /* for safety */
+ case SIOCGETMIFCNT_IN6:
+ return(get_mif6_cnt((struct sioc_mif_req6 *)data));
+ break; /* for safety */
+ default:
+ return (EINVAL);
+ break;
+ }
+ return error;
}
/*
@@ -323,9 +325,9 @@ mrt6_ioctl(cmd, data)
*/
static int
get_sg_cnt(req)
- register struct sioc_sg_req6 *req;
+ struct sioc_sg_req6 *req;
{
- register struct mf6c *rt;
+ struct mf6c *rt;
int s;
s = splnet();
@@ -349,9 +351,9 @@ get_sg_cnt(req)
*/
static int
get_mif6_cnt(req)
- register struct sioc_mif_req6 *req;
+ struct sioc_mif_req6 *req;
{
- register mifi_t mifi = req->mifi;
+ mifi_t mifi = req->mifi;
if (mifi >= nummifs)
return EINVAL;
@@ -415,8 +417,8 @@ ip6_mrouter_init(so, m, cmd)
pim6 = 0;/* used for stubbing out/in pim stuff */
- expire_upcalls_ch =
- timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);
+ callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
+ expire_upcalls, NULL);
#ifdef MRT6DEBUG
if (mrt6debug)
@@ -478,7 +480,7 @@ ip6_mrouter_done()
pim6 = 0; /* used to stub out/in pim specific code */
- untimeout(expire_upcalls, (caddr_t)NULL, expire_upcalls_ch);
+ callout_stop(&expire_upcalls_ch);
/*
* Free all multicast forwarding cache entries.
@@ -528,9 +530,9 @@ static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
*/
static int
add_m6if(mifcp)
- register struct mif6ctl *mifcp;
+ struct mif6ctl *mifcp;
{
- register struct mif6 *mifp;
+ struct mif6 *mifp;
struct ifnet *ifp;
int error, s;
#ifdef notyet
@@ -605,8 +607,8 @@ static int
del_m6if(mifip)
mifi_t *mifip;
{
- register struct mif6 *mifp = mif6table + *mifip;
- register mifi_t mifi;
+ struct mif6 *mifp = mif6table + *mifip;
+ mifi_t mifi;
struct ifnet *ifp;
int s;
@@ -659,7 +661,7 @@ add_m6fc(mfccp)
struct mf6c *rt;
u_long hash;
struct rtdetq *rte;
- register u_short nstl;
+ u_short nstl;
int s;
MF6CFIND(mfccp->mf6cc_origin.sin6_addr,
@@ -809,11 +811,11 @@ add_m6fc(mfccp)
*/
static void
collate(t)
- register struct timeval *t;
+ struct timeval *t;
{
- register u_long d;
- register struct timeval tp;
- register u_long delta;
+ u_long d;
+ struct timeval tp;
+ u_long delta;
GET_TIME(tp);
@@ -912,13 +914,13 @@ socket_send(s, mm, src)
int
ip6_mforward(ip6, ifp, m)
- register struct ip6_hdr *ip6;
+ struct ip6_hdr *ip6;
struct ifnet *ifp;
struct mbuf *m;
{
- register struct mf6c *rt;
- register struct mif6 *mifp;
- register struct mbuf *mm;
+ struct mf6c *rt;
+ struct mif6 *mifp;
+ struct mbuf *mm;
int s;
mifi_t mifi;
@@ -977,10 +979,10 @@ ip6_mforward(ip6, ifp, m)
* send message to routing daemon
*/
- register struct mbuf *mb0;
- register struct rtdetq *rte;
- register u_long hash;
-/* register int i, npkts;*/
+ struct mbuf *mb0;
+ struct rtdetq *rte;
+ u_long hash;
+/* int i, npkts;*/
#ifdef UPCALL_TIMING
struct timeval tp;
@@ -1144,7 +1146,7 @@ ip6_mforward(ip6, ifp, m)
} else {
/* determine if q has overflowed */
struct rtdetq **p;
- register int npkts = 0;
+ int npkts = 0;
for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next)
if (++npkts > MAX_UPQ6) {
@@ -1227,8 +1229,8 @@ expire_upcalls(unused)
}
}
splx(s);
- expire_upcalls_ch =
- timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);
+ callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
+ expire_upcalls, NULL);
}
/*
@@ -1236,14 +1238,14 @@ expire_upcalls(unused)
*/
static int
ip6_mdq(m, ifp, rt)
- register struct mbuf *m;
- register struct ifnet *ifp;
- register struct mf6c *rt;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct mf6c *rt;
{
- register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
- register mifi_t mifi, iif;
- register struct mif6 *mifp;
- register int plen = m->m_pkthdr.len;
+ struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+ mifi_t mifi, iif;
+ struct mif6 *mifp;
+ int plen = m->m_pkthdr.len;
/*
* Macro to send packet on mif. Since RSVP packets don't get counted on
@@ -1290,7 +1292,7 @@ ip6_mdq(m, ifp, rt)
static struct sockaddr_in6 sin6 =
{ sizeof(sin6), AF_INET6 };
- register struct mbuf *mm;
+ struct mbuf *mm;
struct mrt6msg *im;
#ifdef MRT6_OINIT
struct omrt6msg *oim;
@@ -1319,6 +1321,7 @@ ip6_mdq(m, ifp, rt)
case MRT6_INIT:
im = mtod(mm, struct mrt6msg *);
im->im6_msgtype = MRT6MSG_WRONGMIF;
+ im->im6_mbz = 0;
break;
default:
m_freem(mm);
@@ -1408,12 +1411,13 @@ phyint_send(ip6, mifp, m)
struct mif6 *mifp;
struct mbuf *m;
{
- register struct mbuf *mb_copy;
+ struct mbuf *mb_copy;
struct ifnet *ifp = mifp->m6_ifp;
int error = 0;
- int s = splnet();
- static struct route_in6 ro6;
+ int s = splnet(); /* needs to protect static "ro" below. */
+ static struct route_in6 ro;
struct in6_multi *in6m;
+ struct sockaddr_in6 *dst6;
/*
* Make a new reference to the packet; make sure that
@@ -1424,8 +1428,10 @@ phyint_send(ip6, mifp, m)
if (mb_copy &&
(M_HASCL(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr)))
mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr));
- if (mb_copy == NULL)
+ if (mb_copy == NULL) {
+ splx(s);
return;
+ }
/* set MCAST flag to the outgoing packet */
mb_copy->m_flags |= M_MCAST;
@@ -1443,7 +1449,7 @@ phyint_send(ip6, mifp, m)
/* XXX: ip6_output will override ip6->ip6_hlim */
im6o.im6o_multicast_hlim = ip6->ip6_hlim;
im6o.im6o_multicast_loop = 1;
- error = ip6_output(mb_copy, NULL, &ro6,
+ error = ip6_output(mb_copy, NULL, &ro,
IPV6_FORWARDING, &im6o, NULL);
#ifdef MRT6DEBUG
@@ -1459,63 +1465,62 @@ phyint_send(ip6, mifp, m)
* If we belong to the destination multicast group
* on the outgoing interface, loop back a copy.
*/
+ dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
if (in6m != NULL) {
- ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6);
- ro6.ro_dst.sin6_family = AF_INET6;
- ro6.ro_dst.sin6_addr = ip6->ip6_dst;
- ip6_mloopback(ifp, m, &ro6.ro_dst);
+ dst6->sin6_len = sizeof(struct sockaddr_in6);
+ dst6->sin6_family = AF_INET6;
+ dst6->sin6_addr = ip6->ip6_dst;
+ ip6_mloopback(ifp, m, (struct sockaddr_in6 *)&ro.ro_dst);
}
/*
* Put the packet into the sending queue of the outgoing interface
* if it would fit in the MTU of the interface.
*/
if (mb_copy->m_pkthdr.len < ifp->if_mtu || ifp->if_mtu < IPV6_MMTU) {
- ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6);
- ro6.ro_dst.sin6_family = AF_INET6;
- ro6.ro_dst.sin6_addr = ip6->ip6_dst;
+ dst6->sin6_len = sizeof(struct sockaddr_in6);
+ dst6->sin6_family = AF_INET6;
+ dst6->sin6_addr = ip6->ip6_dst;
/*
* We just call if_output instead of nd6_output here, since
* we need no ND for a multicast forwarded packet...right?
*/
error = (*ifp->if_output)(ifp, mb_copy,
- (struct sockaddr *)&ro6.ro_dst,
- NULL);
+ (struct sockaddr *)&ro.ro_dst, NULL);
#ifdef MRT6DEBUG
if (mrt6debug & DEBUG_XMIT)
log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
mifp - mif6table, error);
#endif
- }
- else {
+ } else {
#ifdef MULTICAST_PMTUD
icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
- return;
#else
#ifdef MRT6DEBUG
if (mrt6debug & DEBUG_XMIT)
log(LOG_DEBUG,
- "phyint_send: packet too big on %s%u o %s g %s"
+ "phyint_send: packet too big on %s o %s g %s"
" size %d(discarded)\n",
- ifp->if_name, ifp->if_unit,
+ if_name(ifp),
ip6_sprintf(&ip6->ip6_src),
ip6_sprintf(&ip6->ip6_dst),
mb_copy->m_pkthdr.len);
#endif /* MRT6DEBUG */
m_freem(mb_copy); /* simply discard the packet */
- return;
#endif
}
+
+ splx(s);
}
static int
register_send(ip6, mif, m)
- register struct ip6_hdr *ip6;
+ struct ip6_hdr *ip6;
struct mif6 *mif;
- register struct mbuf *m;
+ struct mbuf *m;
{
- register struct mbuf *mm;
- register int i, len = m->m_pkthdr.len;
+ struct mbuf *mm;
+ int i, len = m->m_pkthdr.len;
static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
struct mrt6msg *im6;
@@ -1530,6 +1535,7 @@ register_send(ip6, mif, m)
MGETHDR(mm, M_DONTWAIT, MT_HEADER);
if (mm == NULL)
return ENOBUFS;
+ mm->m_pkthdr.rcvif = NULL;
mm->m_data += max_linkhdr;
mm->m_len = sizeof(struct ip6_hdr);
@@ -1568,8 +1574,8 @@ register_send(ip6, mif, m)
log(LOG_WARNING,
"register_send: ip_mrouter socket queue full\n");
#endif
- ++mrt6stat.mrt6s_upq_sockfull;
- return ENOBUFS;
+ ++mrt6stat.mrt6s_upq_sockfull;
+ return ENOBUFS;
}
return 0;
}
@@ -1586,21 +1592,21 @@ pim6_input(mp, offp, proto)
struct mbuf **mp;
int *offp, proto;
{
- register struct pim *pim; /* pointer to a pim struct */
- register struct ip6_hdr *ip6;
- register int pimlen;
+ struct pim *pim; /* pointer to a pim struct */
+ struct ip6_hdr *ip6;
+ int pimlen;
struct mbuf *m = *mp;
- int minlen;
+ int minlen;
int off = *offp;
++pim6stat.pim6s_rcv_total;
- ip6 = mtod(m, struct ip6_hdr *);
- pimlen = m->m_pkthdr.len - *offp;
+ ip6 = mtod(m, struct ip6_hdr *);
+ pimlen = m->m_pkthdr.len - *offp;
- /*
- * Validate lengths
- */
+ /*
+ * Validate lengths
+ */
if (pimlen < PIM_MINLEN) {
++pim6stat.pim6s_rcv_tooshort;
#ifdef MRT6DEBUG
@@ -1736,6 +1742,18 @@ pim6_input(mp, offp, proto)
ip6_sprintf(&eip6->ip6_dst),
ntohs(eip6->ip6_plen));
#endif
+
+ /* verify the version number of the inner packet */
+ if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
+ ++pim6stat.pim6s_rcv_badregisters;
+#ifdef MRT6DEBUG
+ log(LOG_DEBUG, "pim6_input: invalid IP version (%d) "
+ "of the inner packet\n",
+ (eip6->ip6_vfc & IPV6_VERSION));
+#endif
+ m_freem(m);
+ return(IPPROTO_NONE);
+ }
/* verify the inner packet is destined to a mcast group */
if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) {
@@ -1781,7 +1799,7 @@ pim6_input(mp, offp, proto)
#endif
rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m,
- dst.sin6_family, NULL);
+ dst.sin6_family, NULL);
/* prepare the register head to send to the mrouting daemon */
m = mcp;
diff --git a/sys/netinet6/ip6_mroute.h b/sys/netinet6/ip6_mroute.h
index 34ec538..7871150 100644
--- a/sys/netinet6/ip6_mroute.h
+++ b/sys/netinet6/ip6_mroute.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip6_mroute.h,v 1.10 2000/05/19 02:38:53 itojun Exp $ */
+/* $KAME: ip6_mroute.h,v 1.17 2001/02/10 02:05:52 itojun Exp $ */
/*
* Copyright (C) 1998 WIDE Project.
@@ -79,7 +79,7 @@ typedef u_short mifi_t; /* type of a mif index */
#define IF_SETSIZE 256
#endif
-typedef long if_mask;
+typedef u_int32_t if_mask;
#define NIFBITS (sizeof(if_mask) * NBBY) /* bits per mask */
#ifndef howmany
@@ -87,7 +87,7 @@ typedef long if_mask;
#endif
typedef struct if_set {
- fd_mask ifs_bits[howmany(IF_SETSIZE, NIFBITS)];
+ if_mask ifs_bits[howmany(IF_SETSIZE, NIFBITS)];
} if_set;
#define IF_SET(n, p) ((p)->ifs_bits[(n)/NIFBITS] |= (1 << ((n) % NIFBITS)))
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 4176bc4..928f3d3 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip6_output.c,v 1.115 2000/07/03 13:23:28 itojun Exp $ */
+/* $KAME: ip6_output.c,v 1.180 2001/05/21 05:37:50 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -89,6 +89,7 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
+#include <netinet6/in6_var.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <netinet6/ip6_var.h>
@@ -103,10 +104,10 @@
#include <netkey/key.h>
#endif /* IPSEC */
-#include <net/net_osdep.h>
-
#include <netinet6/ip6_fw.h>
+#include <net/net_osdep.h>
+
#include <netinet6/ip6protosw.h>
static MALLOC_DEFINE(M_IPMOPTS, "ip6_moptions", "internet multicast options");
@@ -138,6 +139,22 @@ extern u_char ip6_protox[IPPROTO_MAX];
* This function may modify ver and hlim only.
* The mbuf chain containing the packet will be freed.
* The mbuf opt, if present, will not be freed.
+ *
+ * type of "mtu": rt_rmx.rmx_mtu is u_long, ifnet.ifr_mtu is int, and
+ * nd_ifinfo.linkmtu is u_int32_t. so we use u_long to hold largest one,
+ * which is rt_rmx.rmx_mtu.
+ *
+ * If MIP6 is active it will have to add a Home Address option to DH1 if
+ * the mobile node is roaming or a Routing Header type 0 if there exist
+ * a Binding Cache entry for the destination node or a BU option to DH2
+ * if the mobile node initiates communication and no BUL entry exist.
+ * The only way to do this is to allocate new memory, copy the user data
+ * to the new buffer and then add the Home Address option, BU option and
+ * routing header type 0 respectively. MIP6 will set two flags in "struct
+ * pktopts" to restore the original contents once ip6_output is completed.
+ * To make this work, make sure that function exit is made through label
+ * alldone.
+ *
*/
int
ip6_output(m0, opt, ro, flags, im6o, ifpp)
@@ -175,7 +192,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
/* for AH processing. stupid to have "socket" variable in IP layer... */
so = ipsec_getsocket(m);
- ipsec_setsocket(m, NULL);
+ (void)ipsec_setsocket(m, NULL);
ip6 = mtod(m, struct ip6_hdr *);
#endif /* IPSEC */
@@ -419,13 +436,13 @@ skip_ipsec2:;
struct ip6_rthdr0 *rh0;
finaldst = ip6->ip6_dst;
- switch(rh->ip6r_type) {
+ switch (rh->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
rh0 = (struct ip6_rthdr0 *)rh;
ip6->ip6_dst = rh0->ip6r0_addr[0];
bcopy((caddr_t)&rh0->ip6r0_addr[1],
- (caddr_t)&rh0->ip6r0_addr[0],
- sizeof(struct in6_addr)*(rh0->ip6r0_segleft - 1)
+ (caddr_t)&rh0->ip6r0_addr[0],
+ sizeof(struct in6_addr)*(rh0->ip6r0_segleft - 1)
);
rh0->ip6r0_addr[rh0->ip6r0_segleft - 1] = finaldst;
break;
@@ -745,7 +762,7 @@ skip_ipsec2:;
u_int32_t ifmtu = nd_ifinfo[ifp->if_index].linkmtu;
mtu = ro_pmtu->ro_rt->rt_rmx.rmx_mtu;
- if (mtu > ifmtu) {
+ if (mtu > ifmtu || mtu == 0) {
/*
* The MTU on the route is larger than the MTU on
* the interface! This shouldn't happen, unless the
@@ -753,6 +770,9 @@ skip_ipsec2:;
* interface was brought up. Change the MTU in the
* route to match the interface MTU (as long as the
* field isn't locked).
+ *
+ * if MTU on the route is 0, we need to fix the MTU.
+ * this case happens with path MTU discovery timeouts.
*/
mtu = ifmtu;
if ((ro_pmtu->ro_rt->rt_rmx.rmx_locks & RTV_MTU) == 0)
@@ -762,6 +782,12 @@ skip_ipsec2:;
mtu = nd_ifinfo[ifp->if_index].linkmtu;
}
+ /*
+ * advanced API (IPV6_USE_MIN_MTU) overrides mtu setting
+ */
+ if ((flags & IPV6_MINMTU) != 0 && mtu > IPV6_MMTU)
+ mtu = IPV6_MMTU;
+
/* Fake scoped addresses */
if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
/*
@@ -776,34 +802,44 @@ skip_ipsec2:;
* field of the structure here.
* We rely on the consistency between two scope zone ids
* of source add destination, which should already be assured
- * Larger scopes than link will be supported in the near
+ * larger scopes than link will be supported in the near
* future.
*/
+ origifp = NULL;
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
origifp = ifindex2ifnet[ntohs(ip6->ip6_src.s6_addr16[1])];
else if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
origifp = ifindex2ifnet[ntohs(ip6->ip6_dst.s6_addr16[1])];
- else
+ /*
+ * XXX: origifp can be NULL even in those two cases above.
+ * For example, if we remove the (only) link-local address
+ * from the loopback interface, and try to send a link-local
+ * address without link-id information. Then the source
+ * address is ::1, and the destination address is the
+ * link-local address with its s6_addr16[1] being zero.
+ * What is worse, if the packet goes to the loopback interface
+ * by a default rejected route, the null pointer would be
+ * passed to looutput, and the kernel would hang.
+ * The following last resort would prevent such disaster.
+ */
+ if (origifp == NULL)
origifp = ifp;
}
else
origifp = ifp;
-#ifndef FAKE_LOOPBACK_IF
- if ((ifp->if_flags & IFF_LOOPBACK) == 0)
-#else
- if (1)
+#ifndef SCOPEDROUTING
+ /*
+ * clear embedded scope identifiers if necessary.
+ * in6_clearscope will touch the addresses only when necessary.
+ */
+ in6_clearscope(&ip6->ip6_src);
+ in6_clearscope(&ip6->ip6_dst);
#endif
- {
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
- ip6->ip6_src.s6_addr16[1] = 0;
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
- ip6->ip6_dst.s6_addr16[1] = 0;
- }
/*
* Check with the firewall...
*/
- if (ip6_fw_enable && ip6_fw_chk_ptr) {
+ if (ip6_fw_enable && ip6_fw_chk_ptr) {
u_short port = 0;
m->m_pkthdr.rcvif = NULL; /*XXX*/
/* If ipfw says divert, we have to just drop packet */
@@ -823,11 +859,14 @@ skip_ipsec2:;
* (RFC 2460, section 4.)
*/
if (exthdrs.ip6e_hbh) {
- struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh,
- struct ip6_hbh *);
+ struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, struct ip6_hbh *);
u_int32_t dummy1; /* XXX unused */
u_int32_t dummy2; /* XXX unused */
+#ifdef DIAGNOSTIC
+ if ((hbh->ip6h_len + 1) << 3 > exthdrs.ip6e_hbh->m_len)
+ panic("ip6e_hbh is not continuous");
+#endif
/*
* XXX: if we have to send an ICMPv6 error to the sender,
* we need the M_LOOP flag since icmp6_error() expects
@@ -889,12 +928,15 @@ skip_ipsec2:;
#endif
)
{
- /* Record statistics for this interface address. */
- if (ia && !(flags & IPV6_FORWARDING)) {
- ia->ia_ifa.if_opackets++;
- ia->ia_ifa.if_obytes += m->m_pkthdr.len;
- }
-
+ /* Record statistics for this interface address. */
+ if (ia && !(flags & IPV6_FORWARDING)) {
+ ia->ia_ifa.if_opackets++;
+ ia->ia_ifa.if_obytes += m->m_pkthdr.len;
+ }
+#ifdef IPSEC
+ /* clean ipsec history once it goes out of the node */
+ ipsec_delaux(m);
+#endif
error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
goto done;
} else if (mtu < IPV6_MMTU) {
@@ -923,6 +965,7 @@ skip_ipsec2:;
hlen = unfragpartlen;
if (mtu > IPV6_MAXPACKET)
mtu = IPV6_MAXPACKET;
+
len = (mtu - hlen - sizeof(struct ip6_frag)) & ~7;
if (len < 8) {
error = EMSGSIZE;
@@ -962,6 +1005,7 @@ skip_ipsec2:;
ip6stat.ip6s_odropped++;
goto sendorfree;
}
+ m->m_pkthdr.rcvif = NULL;
m->m_flags = m0->m_flags & M_COPYFLAGS;
*mnext = m;
mnext = &m->m_nextpkt;
@@ -1011,12 +1055,15 @@ sendorfree:
m0 = m->m_nextpkt;
m->m_nextpkt = 0;
if (error == 0) {
- /* Record statistics for this interface address. */
- if (ia) {
- ia->ia_ifa.if_opackets++;
- ia->ia_ifa.if_obytes += m->m_pkthdr.len;
- }
-
+ /* Record statistics for this interface address. */
+ if (ia) {
+ ia->ia_ifa.if_opackets++;
+ ia->ia_ifa.if_obytes += m->m_pkthdr.len;
+ }
+#ifdef IPSEC
+ /* clean ipsec history once it goes out of the node */
+ ipsec_delaux(m);
+#endif
error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
} else
m_freem(m);
@@ -1090,6 +1137,7 @@ ip6_insert_jumboopt(exthdrs, plen)
{
struct mbuf *mopt;
u_char *optbuf;
+ u_int32_t v;
#define JUMBOOPTLEN 8 /* length of jumbo payload option and padding */
@@ -1112,18 +1160,42 @@ ip6_insert_jumboopt(exthdrs, plen)
mopt = exthdrs->ip6e_hbh;
if (M_TRAILINGSPACE(mopt) < JUMBOOPTLEN) {
- caddr_t oldoptp = mtod(mopt, caddr_t);
+ /*
+ * XXX assumption:
+ * - exthdrs->ip6e_hbh is not referenced from places
+ * other than exthdrs.
+ * - exthdrs->ip6e_hbh is not an mbuf chain.
+ */
int oldoptlen = mopt->m_len;
+ struct mbuf *n;
- if (mopt->m_flags & M_EXT)
- return(ENOBUFS); /* XXX */
- MCLGET(mopt, M_DONTWAIT);
- if ((mopt->m_flags & M_EXT) == 0)
+ /*
+ * XXX: give up if the whole (new) hbh header does
+ * not fit even in an mbuf cluster.
+ */
+ if (oldoptlen + JUMBOOPTLEN > MCLBYTES)
return(ENOBUFS);
- bcopy(oldoptp, mtod(mopt, caddr_t), oldoptlen);
- optbuf = mtod(mopt, caddr_t) + oldoptlen;
- mopt->m_len = oldoptlen + JUMBOOPTLEN;
+ /*
+ * As a consequence, we must always prepare a cluster
+ * at this point.
+ */
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (n) {
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_freem(n);
+ n = NULL;
+ }
+ }
+ if (!n)
+ return(ENOBUFS);
+ n->m_len = oldoptlen + JUMBOOPTLEN;
+ bcopy(mtod(mopt, caddr_t), mtod(n, caddr_t),
+ oldoptlen);
+ optbuf = mtod(n, caddr_t) + oldoptlen;
+ m_freem(mopt);
+ mopt = exthdrs->ip6e_hbh = n;
} else {
optbuf = mtod(mopt, u_char *) + mopt->m_len;
mopt->m_len += JUMBOOPTLEN;
@@ -1142,7 +1214,8 @@ ip6_insert_jumboopt(exthdrs, plen)
/* fill in the option. */
optbuf[2] = IP6OPT_JUMBO;
optbuf[3] = 4;
- *(u_int32_t *)&optbuf[4] = htonl(plen + JUMBOOPTLEN);
+ v = (u_int32_t)htonl(plen + JUMBOOPTLEN);
+ bcopy(&v, &optbuf[4], sizeof(u_int32_t));
/* finally, adjust the packet header length */
exthdrs->ip6e_ip6->m_pkthdr.len += JUMBOOPTLEN;
@@ -1206,7 +1279,7 @@ ip6_ctloutput(so, sopt)
struct sockopt *sopt;
{
int privileged;
- register struct inpcb *in6p = sotoinpcb(so);
+ struct inpcb *in6p = sotoinpcb(so);
int error, optval;
int level, op, optname;
int optlen;
@@ -1227,93 +1300,131 @@ ip6_ctloutput(so, sopt)
if (level == IPPROTO_IPV6) {
switch (op) {
+
case SOPT_SET:
switch (optname) {
case IPV6_PKTOPTIONS:
- {
+ {
struct mbuf *m;
error = soopt_getm(sopt, &m); /* XXX */
- if (error != 0)
+ if (error != NULL)
break;
error = soopt_mcopyin(sopt, m); /* XXX */
- if (error != 0)
- break;
- return (ip6_pcbopts(&in6p->in6p_outputopts,
- m, so, sopt));
- }
- case IPV6_HOPOPTS:
- case IPV6_DSTOPTS:
- if (!privileged) {
- error = EPERM;
+ if (error != NULL)
break;
- }
- /* fall through */
+ error = ip6_pcbopts(&in6p->in6p_outputopts,
+ m, so, sopt);
+ m_freem(m); /* XXX */
+ break;
+ }
+
+ /*
+ * Use of some Hop-by-Hop options or some
+ * Destination options, might require special
+ * privilege. That is, normal applications
+ * (without special privilege) might be forbidden
+ * from setting certain options in outgoing packets,
+ * and might never see certain options in received
+ * packets. [RFC 2292 Section 6]
+ * KAME specific note:
+ * KAME prevents non-privileged users from sending or
+ * receiving ANY hbh/dst options in order to avoid
+ * overhead of parsing options in the kernel.
+ */
case IPV6_UNICAST_HOPS:
- case IPV6_PKTINFO:
- case IPV6_HOPLIMIT:
- case IPV6_RTHDR:
case IPV6_CHECKSUM:
case IPV6_FAITH:
- case IPV6_BINDV6ONLY:
- if (optlen != sizeof(int))
+
+ case IPV6_V6ONLY:
+ if (optlen != sizeof(int)) {
error = EINVAL;
- else {
- error = sooptcopyin(sopt, &optval,
- sizeof optval, sizeof optval);
- if (error)
- break;
- switch (optname) {
-
- case IPV6_UNICAST_HOPS:
- if (optval < -1 || optval >= 256)
- error = EINVAL;
- else {
- /* -1 = kernel default */
- in6p->in6p_hops = optval;
- if ((in6p->in6p_vflag &
- INP_IPV4) != 0)
- in6p->inp_ip_ttl = optval;
- }
- break;
+ break;
+ }
+ error = sooptcopyin(sopt, &optval,
+ sizeof optval, sizeof optval);
+ if (error)
+ break;
+ switch (optname) {
+
+ case IPV6_UNICAST_HOPS:
+ if (optval < -1 || optval >= 256)
+ error = EINVAL;
+ else {
+ /* -1 = kernel default */
+ in6p->in6p_hops = optval;
+
+ if ((in6p->in6p_vflag &
+ INP_IPV4) != 0)
+ in6p->inp_ip_ttl = optval;
+ }
+ break;
#define OPTSET(bit) \
+do { \
if (optval) \
- in6p->in6p_flags |= bit; \
+ in6p->in6p_flags |= (bit); \
else \
- in6p->in6p_flags &= ~bit;
-
- case IPV6_PKTINFO:
- OPTSET(IN6P_PKTINFO);
- break;
-
- case IPV6_HOPLIMIT:
- OPTSET(IN6P_HOPLIMIT);
- break;
-
- case IPV6_HOPOPTS:
- OPTSET(IN6P_HOPOPTS);
- break;
-
- case IPV6_DSTOPTS:
- OPTSET(IN6P_DSTOPTS);
- break;
+ in6p->in6p_flags &= ~(bit); \
+} while (0)
+#define OPTBIT(bit) (in6p->in6p_flags & (bit) ? 1 : 0)
- case IPV6_RTHDR:
- OPTSET(IN6P_RTHDR);
- break;
+ case IPV6_CHECKSUM:
+ in6p->in6p_cksum = optval;
+ break;
- case IPV6_CHECKSUM:
- in6p->in6p_cksum = optval;
- break;
+ case IPV6_FAITH:
+ OPTSET(IN6P_FAITH);
+ break;
- case IPV6_FAITH:
- OPTSET(IN6P_FAITH);
- break;
+ case IPV6_V6ONLY:
+ /*
+ * XXX: BINDV6ONLY should be integrated
+ * into V6ONLY.
+ */
+ OPTSET(IN6P_BINDV6ONLY);
+ OPTSET(IN6P_IPV6_V6ONLY);
+ break;
+ }
+ break;
- case IPV6_BINDV6ONLY:
- OPTSET(IN6P_BINDV6ONLY);
- break;
- }
+ case IPV6_PKTINFO:
+ case IPV6_HOPLIMIT:
+ case IPV6_HOPOPTS:
+ case IPV6_DSTOPTS:
+ case IPV6_RTHDR:
+ /* RFC 2292 */
+ if (optlen != sizeof(int)) {
+ error = EINVAL;
+ break;
+ }
+ error = sooptcopyin(sopt, &optval,
+ sizeof optval, sizeof optval);
+ if (error)
+ break;
+ switch (optname) {
+ case IPV6_PKTINFO:
+ OPTSET(IN6P_PKTINFO);
+ break;
+ case IPV6_HOPLIMIT:
+ OPTSET(IN6P_HOPLIMIT);
+ break;
+ case IPV6_HOPOPTS:
+ /*
+ * Check super-user privilege.
+ * See comments for IPV6_RECVHOPOPTS.
+ */
+ if (!privileged)
+ return(EPERM);
+ OPTSET(IN6P_HOPOPTS);
+ break;
+ case IPV6_DSTOPTS:
+ if (!privileged)
+ return(EPERM);
+ OPTSET(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */
+ break;
+ case IPV6_RTHDR:
+ OPTSET(IN6P_RTHDR);
+ break;
}
break;
#undef OPTSET
@@ -1393,7 +1504,7 @@ ip6_ctloutput(so, sopt)
m_freem(m);
}
break;
-#endif /* IPSEC */
+#endif /* KAME IPSEC */
case IPV6_FW_ADD:
case IPV6_FW_DEL:
@@ -1405,11 +1516,9 @@ ip6_ctloutput(so, sopt)
if (ip6_fw_ctl_ptr == NULL)
return EINVAL;
- if ((error = soopt_getm(sopt, &m))
- != 0) /* XXX */
+ if (error = soopt_getm(sopt, &m)) /* XXX */
break;
- if ((error = soopt_mcopyin(sopt, m))
- != 0) /* XXX */
+ if (error = soopt_mcopyin(sopt, m)) /* XXX */
break;
error = (*ip6_fw_ctl_ptr)(optname, mp);
m = *mp;
@@ -1433,20 +1542,11 @@ ip6_ctloutput(so, sopt)
sopt->sopt_valsize = 0;
break;
- case IPV6_HOPOPTS:
- case IPV6_DSTOPTS:
- if (!privileged) {
- error = EPERM;
- break;
- }
- /* fall through */
case IPV6_UNICAST_HOPS:
- case IPV6_PKTINFO:
- case IPV6_HOPLIMIT:
- case IPV6_RTHDR:
case IPV6_CHECKSUM:
+
case IPV6_FAITH:
- case IPV6_BINDV6ONLY:
+ case IPV6_V6ONLY:
case IPV6_PORTRANGE:
switch (optname) {
@@ -1454,28 +1554,6 @@ ip6_ctloutput(so, sopt)
optval = in6p->in6p_hops;
break;
-#define OPTBIT(bit) (in6p->in6p_flags & bit ? 1 : 0)
-
- case IPV6_PKTINFO:
- optval = OPTBIT(IN6P_PKTINFO);
- break;
-
- case IPV6_HOPLIMIT:
- optval = OPTBIT(IN6P_HOPLIMIT);
- break;
-
- case IPV6_HOPOPTS:
- optval = OPTBIT(IN6P_HOPOPTS);
- break;
-
- case IPV6_DSTOPTS:
- optval = OPTBIT(IN6P_DSTOPTS);
- break;
-
- case IPV6_RTHDR:
- optval = OPTBIT(IN6P_RTHDR);
- break;
-
case IPV6_CHECKSUM:
optval = in6p->in6p_cksum;
break;
@@ -1484,14 +1562,14 @@ ip6_ctloutput(so, sopt)
optval = OPTBIT(IN6P_FAITH);
break;
- case IPV6_BINDV6ONLY:
+ case IPV6_V6ONLY:
+ /* XXX: see the setopt case. */
optval = OPTBIT(IN6P_BINDV6ONLY);
break;
case IPV6_PORTRANGE:
{
int flags;
-
flags = in6p->in6p_flags;
if (flags & IN6P_HIGHPORT)
optval = IPV6_PORTRANGE_HIGH;
@@ -1506,6 +1584,40 @@ ip6_ctloutput(so, sopt)
sizeof optval);
break;
+ case IPV6_PKTINFO:
+ case IPV6_HOPLIMIT:
+ case IPV6_HOPOPTS:
+ case IPV6_RTHDR:
+ case IPV6_DSTOPTS:
+ if (optname == IPV6_HOPOPTS ||
+ optname == IPV6_DSTOPTS ||
+ !privileged)
+ return(EPERM);
+ switch (optname) {
+ case IPV6_PKTINFO:
+ optval = OPTBIT(IN6P_PKTINFO);
+ break;
+ case IPV6_HOPLIMIT:
+ optval = OPTBIT(IN6P_HOPLIMIT);
+ break;
+ case IPV6_HOPOPTS:
+ if (!privileged)
+ return(EPERM);
+ optval = OPTBIT(IN6P_HOPOPTS);
+ break;
+ case IPV6_RTHDR:
+ optval = OPTBIT(IN6P_RTHDR);
+ break;
+ case IPV6_DSTOPTS:
+ if (!privileged)
+ return(EPERM);
+ optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS);
+ break;
+ }
+ error = sooptcopyout(sopt, &optval,
+ sizeof optval);
+ break;
+
case IPV6_MULTICAST_IF:
case IPV6_MULTICAST_HOPS:
case IPV6_MULTICAST_LOOP:
@@ -1543,10 +1655,11 @@ ip6_ctloutput(so, sopt)
error = ipsec6_get_policy(in6p, req, len, mp);
if (error == 0)
error = soopt_mcopyout(sopt, m); /*XXX*/
- m_freem(m);
+ if (error == 0 && m)
+ m_freem(m);
break;
}
-#endif /* IPSEC */
+#endif /* KAME IPSEC */
case IPV6_FW_GET:
{
@@ -1555,6 +1668,8 @@ ip6_ctloutput(so, sopt)
if (ip6_fw_ctl_ptr == NULL)
{
+ if (m)
+ (void)m_free(m);
return EINVAL;
}
error = (*ip6_fw_ctl_ptr)(optname, mp);
@@ -1578,29 +1693,33 @@ ip6_ctloutput(so, sopt)
}
/*
- * Set up IP6 options in pcb for insertion in output packets.
- * Store in mbuf with pointer in pcbopt, adding pseudo-option
- * with destination address if source routed.
+ * Set up IP6 options in pcb for insertion in output packets or
+ * specifying behavior of outgoing packets.
*/
static int
ip6_pcbopts(pktopt, m, so, sopt)
struct ip6_pktopts **pktopt;
- register struct mbuf *m;
+ struct mbuf *m;
struct socket *so;
struct sockopt *sopt;
{
- register struct ip6_pktopts *opt = *pktopt;
+ struct ip6_pktopts *opt = *pktopt;
int error = 0;
struct proc *p = sopt->sopt_p;
int priv = 0;
/* turn off any old options. */
if (opt) {
- if (opt->ip6po_m)
- (void)m_free(opt->ip6po_m);
+#ifdef DIAGNOSTIC
+ if (opt->ip6po_pktinfo || opt->ip6po_nexthop ||
+ opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 ||
+ opt->ip6po_rhinfo.ip6po_rhi_rthdr)
+ printf("ip6_pcbopts: all specified options are cleared.\n");
+#endif
+ ip6_clearpktopts(opt, 1, -1);
} else
opt = malloc(sizeof(*opt), M_IP6OPT, M_WAITOK);
- *pktopt = 0;
+ *pktopt = NULL;
if (!m || m->m_len == 0) {
/*
@@ -1608,16 +1727,14 @@ ip6_pcbopts(pktopt, m, so, sopt)
*/
if (opt)
free(opt, M_IP6OPT);
- if (m)
- (void)m_free(m);
return(0);
}
/* set options specified by user. */
if (p && !suser(p))
priv = 1;
- if ((error = ip6_setpktoptions(m, opt, priv)) != 0) {
- (void)m_free(m);
+ if ((error = ip6_setpktoptions(m, opt, priv, 1)) != 0) {
+ ip6_clearpktopts(opt, 1, -1); /* XXX: discard all options */
return(error);
}
*pktopt = opt;
@@ -1625,6 +1742,140 @@ ip6_pcbopts(pktopt, m, so, sopt)
}
/*
+ * initialize ip6_pktopts. beware that there are non-zero default values in
+ * the struct.
+ */
+void
+init_ip6pktopts(opt)
+ struct ip6_pktopts *opt;
+{
+
+ bzero(opt, sizeof(*opt));
+ opt->ip6po_hlim = -1; /* -1 means default hop limit */
+}
+
+void
+ip6_clearpktopts(pktopt, needfree, optname)
+ struct ip6_pktopts *pktopt;
+ int needfree, optname;
+{
+ if (pktopt == NULL)
+ return;
+
+ if (optname == -1) {
+ if (needfree && pktopt->ip6po_pktinfo)
+ free(pktopt->ip6po_pktinfo, M_IP6OPT);
+ pktopt->ip6po_pktinfo = NULL;
+ }
+ if (optname == -1)
+ pktopt->ip6po_hlim = -1;
+ if (optname == -1) {
+ if (needfree && pktopt->ip6po_nexthop)
+ free(pktopt->ip6po_nexthop, M_IP6OPT);
+ pktopt->ip6po_nexthop = NULL;
+ }
+ if (optname == -1) {
+ if (needfree && pktopt->ip6po_hbh)
+ free(pktopt->ip6po_hbh, M_IP6OPT);
+ pktopt->ip6po_hbh = NULL;
+ }
+ if (optname == -1) {
+ if (needfree && pktopt->ip6po_dest1)
+ free(pktopt->ip6po_dest1, M_IP6OPT);
+ pktopt->ip6po_dest1 = NULL;
+ }
+ if (optname == -1) {
+ if (needfree && pktopt->ip6po_rhinfo.ip6po_rhi_rthdr)
+ free(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT);
+ pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL;
+ if (pktopt->ip6po_route.ro_rt) {
+ RTFREE(pktopt->ip6po_route.ro_rt);
+ pktopt->ip6po_route.ro_rt = NULL;
+ }
+ }
+ if (optname == -1) {
+ if (needfree && pktopt->ip6po_dest2)
+ free(pktopt->ip6po_dest2, M_IP6OPT);
+ pktopt->ip6po_dest2 = NULL;
+ }
+}
+
+#define PKTOPT_EXTHDRCPY(type) \
+do {\
+ if (src->type) {\
+ int hlen =\
+ (((struct ip6_ext *)src->type)->ip6e_len + 1) << 3;\
+ dst->type = malloc(hlen, M_IP6OPT, canwait);\
+ if (dst->type == NULL && canwait == M_NOWAIT)\
+ goto bad;\
+ bcopy(src->type, dst->type, hlen);\
+ }\
+} while (0)
+
+struct ip6_pktopts *
+ip6_copypktopts(src, canwait)
+ struct ip6_pktopts *src;
+ int canwait;
+{
+ struct ip6_pktopts *dst;
+
+ if (src == NULL) {
+ printf("ip6_clearpktopts: invalid argument\n");
+ return(NULL);
+ }
+
+ dst = malloc(sizeof(*dst), M_IP6OPT, canwait);
+ if (dst == NULL && canwait == M_NOWAIT)
+ goto bad;
+ bzero(dst, sizeof(*dst));
+
+ dst->ip6po_hlim = src->ip6po_hlim;
+ if (src->ip6po_pktinfo) {
+ dst->ip6po_pktinfo = malloc(sizeof(*dst->ip6po_pktinfo),
+ M_IP6OPT, canwait);
+ if (dst->ip6po_pktinfo == NULL && canwait == M_NOWAIT)
+ goto bad;
+ *dst->ip6po_pktinfo = *src->ip6po_pktinfo;
+ }
+ if (src->ip6po_nexthop) {
+ dst->ip6po_nexthop = malloc(src->ip6po_nexthop->sa_len,
+ M_IP6OPT, canwait);
+ if (dst->ip6po_nexthop == NULL && canwait == M_NOWAIT)
+ goto bad;
+ bcopy(src->ip6po_nexthop, dst->ip6po_nexthop,
+ src->ip6po_nexthop->sa_len);
+ }
+ PKTOPT_EXTHDRCPY(ip6po_hbh);
+ PKTOPT_EXTHDRCPY(ip6po_dest1);
+ PKTOPT_EXTHDRCPY(ip6po_dest2);
+ PKTOPT_EXTHDRCPY(ip6po_rthdr); /* not copy the cached route */
+ return(dst);
+
+ bad:
+ printf("ip6_copypktopts: copy failed");
+ if (dst->ip6po_pktinfo) free(dst->ip6po_pktinfo, M_IP6OPT);
+ if (dst->ip6po_nexthop) free(dst->ip6po_nexthop, M_IP6OPT);
+ if (dst->ip6po_hbh) free(dst->ip6po_hbh, M_IP6OPT);
+ if (dst->ip6po_dest1) free(dst->ip6po_dest1, M_IP6OPT);
+ if (dst->ip6po_dest2) free(dst->ip6po_dest2, M_IP6OPT);
+ if (dst->ip6po_rthdr) free(dst->ip6po_rthdr, M_IP6OPT);
+ return(NULL);
+}
+#undef PKTOPT_EXTHDRCPY
+
+void
+ip6_freepcbopts(pktopt)
+ struct ip6_pktopts *pktopt;
+{
+ if (pktopt == NULL)
+ return;
+
+ ip6_clearpktopts(pktopt, 1, -1);
+
+ free(pktopt, M_IP6OPT);
+}
+
+/*
* Set the IP6 multicast options in response to user setsockopt().
*/
static int
@@ -1670,7 +1921,7 @@ ip6_setmoptions(optname, im6op, m)
error = EINVAL;
break;
}
- ifindex = *(mtod(m, u_int *));
+ bcopy(mtod(m, u_int *), &ifindex, sizeof(ifindex));
if (ifindex < 0 || if_index < ifindex) {
error = ENXIO; /* XXX EINVAL? */
break;
@@ -1693,7 +1944,7 @@ ip6_setmoptions(optname, im6op, m)
error = EINVAL;
break;
}
- optval = *(mtod(m, u_int *));
+ bcopy(mtod(m, u_int *), &optval, sizeof(optval));
if (optval < -1 || optval >= 256)
error = EINVAL;
else if (optval == -1)
@@ -1708,8 +1959,12 @@ ip6_setmoptions(optname, im6op, m)
* Set the loopback flag for outgoing multicast packets.
* Must be zero or one.
*/
- if (m == NULL || m->m_len != sizeof(u_int) ||
- (loop = *(mtod(m, u_int *))) > 1) {
+ if (m == NULL || m->m_len != sizeof(u_int)) {
+ error = EINVAL;
+ break;
+ }
+ bcopy(mtod(m, u_int *), &loop, sizeof(loop));
+ if (loop > 1) {
error = EINVAL;
break;
}
@@ -1915,8 +2170,8 @@ ip6_setmoptions(optname, im6op, m)
static int
ip6_getmoptions(optname, im6o, mp)
int optname;
- register struct ip6_moptions *im6o;
- register struct mbuf **mp;
+ struct ip6_moptions *im6o;
+ struct mbuf **mp;
{
u_int *hlim, *loop, *ifindex;
@@ -1961,7 +2216,7 @@ ip6_getmoptions(optname, im6o, mp)
*/
void
ip6_freemoptions(im6o)
- register struct ip6_moptions *im6o;
+ struct ip6_moptions *im6o;
{
struct in6_multi_mship *imm;
@@ -1981,18 +2236,17 @@ ip6_freemoptions(im6o)
* Set IPv6 outgoing packet options based on advanced API.
*/
int
-ip6_setpktoptions(control, opt, priv)
+ip6_setpktoptions(control, opt, priv, needcopy)
struct mbuf *control;
struct ip6_pktopts *opt;
- int priv;
+ int priv, needcopy;
{
- register struct cmsghdr *cm = 0;
+ struct cmsghdr *cm = 0;
if (control == 0 || opt == 0)
return(EINVAL);
- bzero(opt, sizeof(*opt));
- opt->ip6po_hlim = -1; /* -1 means to use default hop limit */
+ init_ip6pktopts(opt);
/*
* XXX: Currently, we assume all the optional information is stored
@@ -2001,21 +2255,31 @@ ip6_setpktoptions(control, opt, priv)
if (control->m_next)
return(EINVAL);
- opt->ip6po_m = control;
-
- for (; control->m_len; control->m_data += ALIGN(cm->cmsg_len),
- control->m_len -= ALIGN(cm->cmsg_len)) {
+ for (; control->m_len; control->m_data += CMSG_ALIGN(cm->cmsg_len),
+ control->m_len -= CMSG_ALIGN(cm->cmsg_len)) {
cm = mtod(control, struct cmsghdr *);
if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len)
return(EINVAL);
if (cm->cmsg_level != IPPROTO_IPV6)
continue;
- switch(cm->cmsg_type) {
+ /*
+ * XXX should check if RFC2292 API is mixed with 2292bis API
+ */
+ switch (cm->cmsg_type) {
case IPV6_PKTINFO:
if (cm->cmsg_len != CMSG_LEN(sizeof(struct in6_pktinfo)))
return(EINVAL);
- opt->ip6po_pktinfo = (struct in6_pktinfo *)CMSG_DATA(cm);
+ if (needcopy) {
+ /* XXX: Is it really WAITOK? */
+ opt->ip6po_pktinfo =
+ malloc(sizeof(struct in6_pktinfo),
+ M_IP6OPT, M_WAITOK);
+ bcopy(CMSG_DATA(cm), opt->ip6po_pktinfo,
+ sizeof(struct in6_pktinfo));
+ } else
+ opt->ip6po_pktinfo =
+ (struct in6_pktinfo *)CMSG_DATA(cm);
if (opt->ip6po_pktinfo->ipi6_ifindex &&
IN6_IS_ADDR_LINKLOCAL(&opt->ip6po_pktinfo->ipi6_addr))
opt->ip6po_pktinfo->ipi6_addr.s6_addr16[1] =
@@ -2026,8 +2290,13 @@ ip6_setpktoptions(control, opt, priv)
return(ENXIO);
}
+ /*
+ * Check if the requested source address is indeed a
+ * unicast address assigned to the node, and can be
+ * used as the packet's source address.
+ */
if (!IN6_IS_ADDR_UNSPECIFIED(&opt->ip6po_pktinfo->ipi6_addr)) {
- struct ifaddr *ia;
+ struct in6_ifaddr *ia6;
struct sockaddr_in6 sin6;
bzero(&sin6, sizeof(sin6));
@@ -2035,19 +2304,10 @@ ip6_setpktoptions(control, opt, priv)
sin6.sin6_family = AF_INET6;
sin6.sin6_addr =
opt->ip6po_pktinfo->ipi6_addr;
- ia = ifa_ifwithaddr(sin6tosa(&sin6));
- if (ia == NULL ||
- (opt->ip6po_pktinfo->ipi6_ifindex &&
- (ia->ifa_ifp->if_index !=
- opt->ip6po_pktinfo->ipi6_ifindex))) {
- return(EADDRNOTAVAIL);
- }
- /*
- * Check if the requested source address is
- * indeed a unicast address assigned to the
- * node.
- */
- if (IN6_IS_ADDR_MULTICAST(&opt->ip6po_pktinfo->ipi6_addr))
+ ia6 = (struct in6_ifaddr *)ifa_ifwithaddr(sin6tosa(&sin6));
+ if (ia6 == NULL ||
+ (ia6->ia6_flags & (IN6_IFF_ANYCAST |
+ IN6_IFF_NOTREADY)) != 0)
return(EADDRNOTAVAIL);
}
break;
@@ -2064,66 +2324,120 @@ ip6_setpktoptions(control, opt, priv)
case IPV6_NEXTHOP:
if (!priv)
return(EPERM);
+
if (cm->cmsg_len < sizeof(u_char) ||
+ /* check if cmsg_len is large enough for sa_len */
cm->cmsg_len < CMSG_LEN(*CMSG_DATA(cm)))
return(EINVAL);
- opt->ip6po_nexthop = (struct sockaddr *)CMSG_DATA(cm);
-
+ if (needcopy) {
+ opt->ip6po_nexthop =
+ malloc(*CMSG_DATA(cm),
+ M_IP6OPT, M_WAITOK);
+ bcopy(CMSG_DATA(cm),
+ opt->ip6po_nexthop,
+ *CMSG_DATA(cm));
+ } else
+ opt->ip6po_nexthop =
+ (struct sockaddr *)CMSG_DATA(cm);
break;
case IPV6_HOPOPTS:
+ {
+ struct ip6_hbh *hbh;
+ int hbhlen;
+
if (cm->cmsg_len < CMSG_LEN(sizeof(struct ip6_hbh)))
return(EINVAL);
- opt->ip6po_hbh = (struct ip6_hbh *)CMSG_DATA(cm);
- if (cm->cmsg_len !=
- CMSG_LEN((opt->ip6po_hbh->ip6h_len + 1) << 3))
+ hbh = (struct ip6_hbh *)CMSG_DATA(cm);
+ hbhlen = (hbh->ip6h_len + 1) << 3;
+ if (cm->cmsg_len != CMSG_LEN(hbhlen))
return(EINVAL);
+
+ if (needcopy) {
+ opt->ip6po_hbh =
+ malloc(hbhlen, M_IP6OPT, M_WAITOK);
+ bcopy(hbh, opt->ip6po_hbh, hbhlen);
+ } else
+ opt->ip6po_hbh = hbh;
break;
+ }
case IPV6_DSTOPTS:
+ {
+ struct ip6_dest *dest, **newdest;
+ int destlen;
+
if (cm->cmsg_len < CMSG_LEN(sizeof(struct ip6_dest)))
return(EINVAL);
+ dest = (struct ip6_dest *)CMSG_DATA(cm);
+ destlen = (dest->ip6d_len + 1) << 3;
+ if (cm->cmsg_len != CMSG_LEN(destlen))
+ return(EINVAL);
- /*
- * If there is no routing header yet, the destination
- * options header should be put on the 1st part.
- * Otherwise, the header should be on the 2nd part.
- * (See RFC 2460, section 4.1)
+ /*
+ * The old advacned API is ambiguous on this
+ * point. Our approach is to determine the
+ * position based according to the existence
+ * of a routing header. Note, however, that
+ * this depends on the order of the extension
+ * headers in the ancillary data; the 1st part
+ * of the destination options header must
+ * appear before the routing header in the
+ * ancillary data, too.
+ * RFC2292bis solved the ambiguity by
+ * introducing separate cmsg types.
*/
- if (opt->ip6po_rthdr == NULL) {
- opt->ip6po_dest1 =
- (struct ip6_dest *)CMSG_DATA(cm);
- if (cm->cmsg_len !=
- CMSG_LEN((opt->ip6po_dest1->ip6d_len + 1)
- << 3))
- return(EINVAL);
- } else {
- opt->ip6po_dest2 =
- (struct ip6_dest *)CMSG_DATA(cm);
- if (cm->cmsg_len !=
- CMSG_LEN((opt->ip6po_dest2->ip6d_len + 1)
- << 3))
- return(EINVAL);
- }
+ if (opt->ip6po_rthdr == NULL)
+ newdest = &opt->ip6po_dest1;
+ else
+ newdest = &opt->ip6po_dest2;
+
+ if (needcopy) {
+ *newdest = malloc(destlen, M_IP6OPT, M_WAITOK);
+ bcopy(dest, *newdest, destlen);
+ } else
+ *newdest = dest;
+
break;
+ }
case IPV6_RTHDR:
+ {
+ struct ip6_rthdr *rth;
+ int rthlen;
+
if (cm->cmsg_len < CMSG_LEN(sizeof(struct ip6_rthdr)))
return(EINVAL);
- opt->ip6po_rthdr = (struct ip6_rthdr *)CMSG_DATA(cm);
- if (cm->cmsg_len !=
- CMSG_LEN((opt->ip6po_rthdr->ip6r_len + 1) << 3))
+ rth = (struct ip6_rthdr *)CMSG_DATA(cm);
+ rthlen = (rth->ip6r_len + 1) << 3;
+ if (cm->cmsg_len != CMSG_LEN(rthlen))
return(EINVAL);
- switch(opt->ip6po_rthdr->ip6r_type) {
+
+ switch (rth->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
- if (opt->ip6po_rthdr->ip6r_segleft == 0)
+ /* must contain one addr */
+ if (rth->ip6r_len == 0)
+ return(EINVAL);
+ /* length must be even */
+ if (rth->ip6r_len % 2)
+ return(EINVAL);
+ if (rth->ip6r_len / 2 != rth->ip6r_segleft)
return(EINVAL);
break;
default:
- return(EINVAL);
+ return(EINVAL); /* not supported */
}
+
+ if (needcopy) {
+ opt->ip6po_rthdr = malloc(rthlen, M_IP6OPT,
+ M_WAITOK);
+ bcopy(rth, opt->ip6po_rthdr, rthlen);
+ } else
+ opt->ip6po_rthdr = rth;
+
break;
+ }
default:
return(ENOPROTOOPT);
@@ -2142,8 +2456,8 @@ ip6_setpktoptions(control, opt, priv)
void
ip6_mloopback(ifp, m, dst)
struct ifnet *ifp;
- register struct mbuf *m;
- register struct sockaddr_in6 *dst;
+ struct mbuf *m;
+ struct sockaddr_in6 *dst;
{
struct mbuf *copym;
struct ip6_hdr *ip6;
@@ -2171,18 +2485,15 @@ ip6_mloopback(ifp, m, dst)
}
#endif
-#ifndef FAKE_LOOPBACK_IF
- if ((ifp->if_flags & IFF_LOOPBACK) == 0)
-#else
- if (1)
+ ip6 = mtod(copym, struct ip6_hdr *);
+#ifndef SCOPEDROUTING
+ /*
+ * clear embedded scope identifiers if necessary.
+ * in6_clearscope will touch the addresses only when necessary.
+ */
+ in6_clearscope(&ip6->ip6_src);
+ in6_clearscope(&ip6->ip6_dst);
#endif
- {
- ip6 = mtod(copym, struct ip6_hdr *);
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
- ip6->ip6_src.s6_addr16[1] = 0;
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
- ip6->ip6_dst.s6_addr16[1] = 0;
- }
(void)if_simloop(ifp, copym, dst->sin6_family, NULL);
}
@@ -2236,10 +2547,11 @@ ip6_optlen(in6p)
(((struct ip6_ext *)(x)) ? (((struct ip6_ext *)(x))->ip6e_len + 1) << 3 : 0)
len += elen(in6p->in6p_outputopts->ip6po_hbh);
- len += elen(in6p->in6p_outputopts->ip6po_dest1);
+ if (in6p->in6p_outputopts->ip6po_rthdr)
+ /* dest1 is valid with rthdr only */
+ len += elen(in6p->in6p_outputopts->ip6po_dest1);
len += elen(in6p->in6p_outputopts->ip6po_rthdr);
len += elen(in6p->in6p_outputopts->ip6po_dest2);
return len;
#undef elen
}
-
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
index 234b2e9..dea9c07 100644
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */
+/* $KAME: ip6_var.h,v 1.62 2001/05/03 14:51:48 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -129,15 +129,29 @@ struct ip6po_rhinfo {
struct ip6_pktopts {
struct mbuf *ip6po_m; /* Pointer to mbuf storing the data */
- int ip6po_hlim; /* Hoplimit for outgoing packets */
- struct in6_pktinfo *ip6po_pktinfo; /* Outgoing IF/address information */
- struct sockaddr *ip6po_nexthop; /* Next-hop address */
+ int ip6po_hlim; /* Hoplimit for outgoing packets */
+
+ /* Outgoing IF/address information */
+ struct in6_pktinfo *ip6po_pktinfo;
+
+ struct sockaddr *ip6po_nexthop; /* Next-hop address */
+
struct ip6_hbh *ip6po_hbh; /* Hop-by-Hop options header */
- struct ip6_dest *ip6po_dest1; /* Destination options header(1st part) */
- struct ip6po_rhinfo ip6po_rhinfo; /* Routing header related info. */
- struct ip6_dest *ip6po_dest2; /* Destination options header(2nd part) */
+
+ /* Destination options header (before a routing header) */
+ struct ip6_dest *ip6po_dest1;
+
+ /* Routing header related info. */
+ struct ip6po_rhinfo ip6po_rhinfo;
+
+ /* Destination options header (after a routing header) */
+ struct ip6_dest *ip6po_dest2;
};
+/*
+ * Control options for incoming packets
+ */
+
struct ip6stat {
u_quad_t ip6s_total; /* total packets received */
u_quad_t ip6s_tooshort; /* packet too short */
@@ -200,6 +214,37 @@ struct ip6stat {
};
#ifdef _KERNEL
+/*
+ * IPv6 onion peeling state.
+ * it will be initialized when we come into ip6_input().
+ * XXX do not make it a kitchen sink!
+ */
+struct ip6aux {
+ u_int32_t ip6a_flags;
+#define IP6A_SWAP 0x01 /* swapped home/care-of on packet */
+#define IP6A_HASEEN 0x02 /* HA was present */
+#define IP6A_BRUID 0x04 /* BR Unique Identifier was present */
+#define IP6A_RTALERTSEEN 0x08 /* rtalert present */
+
+ /* ip6.ip6_src */
+ struct in6_addr ip6a_careof; /* care-of address of the peer */
+ struct in6_addr ip6a_home; /* home address of the peer */
+ u_int16_t ip6a_bruid; /* BR unique identifier */
+
+ /* ip6.ip6_dst */
+ struct in6_ifaddr *ip6a_dstia6; /* my ifaddr that matches ip6_dst */
+
+ /* rtalert */
+ u_int16_t ip6a_rtalert; /* rtalert option value */
+
+ /*
+ * decapsulation history will be here.
+ * with IPsec it may not be accurate.
+ */
+};
+#endif
+
+#ifdef _KERNEL
/* flags passed to ip6_output as last parameter */
#define IPV6_DADOUTPUT 0x01 /* DAD */
#define IPV6_FORWARDING 0x02 /* most of IPv6 header exists */
@@ -215,7 +260,8 @@ extern int ip6_gif_hlim; /* Hop limit for gif encap packet */
extern int ip6_use_deprecated; /* allow deprecated addr as source */
extern int ip6_rr_prune; /* router renumbering prefix
* walk list every 5 sec. */
-extern int ip6_mapped_addr_on;
+#define ip6_mapped_addr_on (!ip6_v6only)
+extern int ip6_v6only;
extern struct socket *ip6_mrouter; /* multicast routing daemon */
extern int ip6_sendredirects; /* send IP redirects when forwarding? */
@@ -231,6 +277,14 @@ extern int ip6_dad_count; /* DupAddrDetectionTransmits */
extern u_int32_t ip6_flow_seq;
extern int ip6_auto_flowlabel;
+extern int ip6_auto_linklocal;
+
+extern int ip6_anonportmin; /* minimum ephemeral port */
+extern int ip6_anonportmax; /* maximum ephemeral port */
+extern int ip6_lowportmin; /* minimum reserved port */
+extern int ip6_lowportmax; /* maximum reserved port */
+
+extern int ip6_use_tempaddr; /* whether to use temporary addresses. */
extern struct pr_usrreqs rip6_usrreqs;
struct sockopt;
@@ -239,29 +293,41 @@ struct inpcb;
int icmp6_ctloutput __P((struct socket *, struct sockopt *sopt));
+struct in6_ifaddr;
void ip6_init __P((void));
void ip6intr __P((void));
void ip6_input __P((struct mbuf *));
+struct in6_ifaddr *ip6_getdstifaddr __P((struct mbuf *));
+void ip6_freepcbopts __P((struct ip6_pktopts *));
void ip6_freemoptions __P((struct ip6_moptions *));
int ip6_unknown_opt __P((u_int8_t *, struct mbuf *, int));
char * ip6_get_prevhdr __P((struct mbuf *, int));
int ip6_nexthdr __P((struct mbuf *, int, int, int *));
int ip6_lasthdr __P((struct mbuf *, int, int, int *));
+
+struct mbuf *ip6_addaux __P((struct mbuf *));
+struct mbuf *ip6_findaux __P((struct mbuf *));
+void ip6_delaux __P((struct mbuf *));
+
int ip6_mforward __P((struct ip6_hdr *, struct ifnet *, struct mbuf *));
int ip6_process_hopopts __P((struct mbuf *, u_int8_t *, int, u_int32_t *,
u_int32_t *));
void ip6_savecontrol __P((struct inpcb *, struct mbuf **, struct ip6_hdr *,
- struct mbuf *));
+ struct mbuf *));
+void ip6_notify_pmtu __P((struct inpcb *, struct sockaddr_in6 *,
+ u_int32_t *));
int ip6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
void ip6_forward __P((struct mbuf *, int));
void ip6_mloopback __P((struct ifnet *, struct mbuf *, struct sockaddr_in6 *));
int ip6_output __P((struct mbuf *, struct ip6_pktopts *,
- struct route_in6 *, int,
+ struct route_in6 *,
+ int,
struct ip6_moptions *, struct ifnet **));
int ip6_ctloutput __P((struct socket *, struct sockopt *sopt));
-int ip6_setpktoptions __P((struct mbuf *, struct ip6_pktopts *, int));
+void init_ip6pktopts __P((struct ip6_pktopts *));
+int ip6_setpktoptions __P((struct mbuf *, struct ip6_pktopts *, int, int));
void ip6_clearpktopts __P((struct ip6_pktopts *, int, int));
struct ip6_pktopts *ip6_copypktopts __P((struct ip6_pktopts *, int));
int ip6_optlen __P((struct inpcb *));
diff --git a/sys/netinet6/ip6protosw.h b/sys/netinet6/ip6protosw.h
index bd89793..c2f38fc 100644
--- a/sys/netinet6/ip6protosw.h
+++ b/sys/netinet6/ip6protosw.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip6protosw.h,v 1.11 2000/10/03 09:59:35 jinmei Exp $ */
+/* $KAME: ip6protosw.h,v 1.22 2001/02/08 18:02:08 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -87,16 +87,38 @@ struct socket;
struct domain;
struct proc;
struct ip6_hdr;
+struct icmp6_hdr;
+struct in6_addr;
struct pr_usrreqs;
/*
* argument type for the last arg of pr_ctlinput().
* should be consulted only with AF_INET6 family.
+ *
+ * IPv6 ICMP IPv6 [exthdrs] finalhdr paylaod
+ * ^ ^ ^ ^
+ * | | ip6c_ip6 ip6c_off
+ * | ip6c_icmp6
+ * ip6c_m
+ *
+ * ip6c_finaldst usually points to ip6c_ip6->ip6_dst. if the original
+ * (internal) packet carries a routing header, it may point the final
+ * dstination address in the routing header.
+ *
+ * ip6c_src: ip6c_ip6->ip6_src + scope info + flowlabel in ip6c_ip6
+ * (beware of flowlabel, if you try to compare it against others)
+ * ip6c_dst: ip6c_finaldst + scope info
*/
struct ip6ctlparam {
struct mbuf *ip6c_m; /* start of mbuf chain */
+ struct icmp6_hdr *ip6c_icmp6; /* icmp6 header of target packet */
struct ip6_hdr *ip6c_ip6; /* ip6 header of target packet */
int ip6c_off; /* offset of the target proto header */
+ struct sockaddr_in6 *ip6c_src; /* srcaddr w/ additional info */
+ struct sockaddr_in6 *ip6c_dst; /* (final) dstaddr w/ additional info */
+ struct in6_addr *ip6c_finaldst; /* final destination address */
+ void *ip6c_cmdarg; /* control command dependent data */
+ u_int8_t ip6c_nxt; /* final next header field */
};
struct ip6protosw {
diff --git a/sys/netinet6/ipcomp.h b/sys/netinet6/ipcomp.h
index dea5ea8..08d62da 100644
--- a/sys/netinet6/ipcomp.h
+++ b/sys/netinet6/ipcomp.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ipcomp.h,v 1.7 2000/05/18 12:45:13 sumikawa Exp $ */
+/* $KAME: ipcomp.h,v 1.8 2000/09/26 07:55:14 itojun Exp $ */
/*
* Copyright (C) 1999 WIDE Project.
@@ -37,6 +37,10 @@
#ifndef _NETINET6_IPCOMP_H_
#define _NETINET6_IPCOMP_H_
+#if defined(_KERNEL) && !defined(_LKM)
+#include "opt_inet.h"
+#endif
+
struct ipcomp {
u_int8_t comp_nxt; /* Next Header */
u_int8_t comp_flags; /* reserved, must be zero */
@@ -59,7 +63,7 @@ struct ipcomp_algorithm {
};
struct ipsecrequest;
-extern struct ipcomp_algorithm ipcomp_algorithms[];
+extern const struct ipcomp_algorithm *ipcomp_algorithm_lookup __P((int));
extern void ipcomp4_input __P((struct mbuf *, ...));
extern int ipcomp4_output __P((struct mbuf *, struct ipsecrequest *));
#endif /*KERNEL*/
diff --git a/sys/netinet6/ipcomp6.h b/sys/netinet6/ipcomp6.h
index 553c8df..4a1046a 100644
--- a/sys/netinet6/ipcomp6.h
+++ b/sys/netinet6/ipcomp6.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ipcomp.h,v 1.7 2000/05/18 12:45:13 sumikawa Exp $ */
+/* $KAME: ipcomp.h,v 1.8 2000/09/26 07:55:14 itojun Exp $ */
/*
* Copyright (C) 1999 WIDE Project.
diff --git a/sys/netinet6/ipcomp_core.c b/sys/netinet6/ipcomp_core.c
index 1eee253..ec031f6 100644
--- a/sys/netinet6/ipcomp_core.c
+++ b/sys/netinet6/ipcomp_core.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ipcomp_core.c,v 1.12 2000/05/05 11:01:01 sumikawa Exp $ */
+/* $KAME: ipcomp_core.c,v 1.24 2000/10/23 04:24:22 itojun Exp $ */
/*
* Copyright (C) 1999 WIDE Project.
@@ -85,13 +85,20 @@ static int deflate_window_out = -12;
static const int deflate_window_in = -1 * MAX_WBITS; /* don't change it */
static int deflate_memlevel = MAX_MEM_LEVEL;
-struct ipcomp_algorithm ipcomp_algorithms[] = {
- { NULL, NULL, -1 },
- { NULL, NULL, -1 },
+static const struct ipcomp_algorithm ipcomp_algorithms[] = {
{ deflate_compress, deflate_decompress, 90 },
- { NULL, NULL, 90 },
};
+const struct ipcomp_algorithm *
+ipcomp_algorithm_lookup(idx)
+ int idx;
+{
+
+ if (idx == SADB_X_CALG_DEFLATE)
+ return &ipcomp_algorithms[0];
+ return NULL;
+}
+
static void *
deflate_alloc(aux, items, siz)
void *aux;
@@ -99,7 +106,7 @@ deflate_alloc(aux, items, siz)
u_int siz;
{
void *ptr;
- MALLOC(ptr, void *, items * siz, M_TEMP, M_NOWAIT);
+ ptr = malloc(items * siz, M_TEMP, M_NOWAIT);
return ptr;
}
@@ -108,7 +115,7 @@ deflate_free(aux, ptr)
void *aux;
void *ptr;
{
- FREE(ptr, M_TEMP);
+ free(ptr, M_TEMP);
}
static int
@@ -120,12 +127,47 @@ deflate_common(m, md, lenp, mode)
{
struct mbuf *mprev;
struct mbuf *p;
- struct mbuf *n, *n0 = NULL, **np;
+ struct mbuf *n = NULL, *n0 = NULL, **np;
z_stream zs;
int error = 0;
int zerror;
size_t offset;
- int firsttime, final, flush;
+
+#define MOREBLOCK() \
+do { \
+ /* keep the reply buffer into our chain */ \
+ if (n) { \
+ n->m_len = zs.total_out - offset; \
+ offset = zs.total_out; \
+ *np = n; \
+ np = &n->m_next; \
+ n = NULL; \
+ } \
+ \
+ /* get a fresh reply buffer */ \
+ MGET(n, M_DONTWAIT, MT_DATA); \
+ if (n) { \
+ MCLGET(n, M_DONTWAIT); \
+ } \
+ if (!n) { \
+ error = ENOBUFS; \
+ goto fail; \
+ } \
+ n->m_len = 0; \
+ n->m_len = M_TRAILINGSPACE(n); \
+ n->m_next = NULL; \
+ /* \
+ * if this is the first reply buffer, reserve \
+ * region for ipcomp header. \
+ */ \
+ if (*np == NULL) { \
+ n->m_len -= sizeof(struct ipcomp); \
+ n->m_data += sizeof(struct ipcomp); \
+ } \
+ \
+ zs.next_out = mtod(n, u_int8_t *); \
+ zs.avail_out = n->m_len; \
+} while (0)
for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
;
@@ -148,113 +190,107 @@ deflate_common(m, md, lenp, mode)
n0 = n = NULL;
np = &n0;
offset = 0;
- firsttime = 1;
- final = 0;
- flush = Z_NO_FLUSH;
zerror = 0;
p = md;
- while (1) {
- /*
- * first time, we need to setup the buffer before calling
- * compression function.
- */
- if (firsttime)
- firsttime = 0;
- else {
- zerror = mode ? inflate(&zs, flush)
- : deflate(&zs, flush);
- }
+ while (p && p->m_len == 0) {
+ p = p->m_next;
+ }
+ /* input stream and output stream are available */
+ while (p && zs.avail_in == 0) {
/* get input buffer */
if (p && zs.avail_in == 0) {
zs.next_in = mtod(p, u_int8_t *);
zs.avail_in = p->m_len;
p = p->m_next;
- if (!p) {
- final = 1;
- flush = Z_PARTIAL_FLUSH;
+ while (p && p->m_len == 0) {
+ p = p->m_next;
}
}
/* get output buffer */
if (zs.next_out == NULL || zs.avail_out == 0) {
- /* keep the reply buffer into our chain */
- if (n) {
- n->m_len = zs.total_out - offset;
- offset = zs.total_out;
- *np = n;
- np = &n->m_next;
- }
+ MOREBLOCK();
+ }
- /* get a fresh reply buffer */
- MGET(n, M_DONTWAIT, MT_DATA);
- if (n) {
- MCLGET(n, M_DONTWAIT);
- }
- if (!n) {
- error = ENOBUFS;
- goto fail;
- }
- n->m_len = 0;
- n->m_len = M_TRAILINGSPACE(n);
- n->m_next = NULL;
- /*
- * if this is the first reply buffer, reserve
- * region for ipcomp header.
- */
- if (*np == NULL) {
- n->m_len -= sizeof(struct ipcomp);
- n->m_data += sizeof(struct ipcomp);
+ zerror = mode ? inflate(&zs, Z_NO_FLUSH)
+ : deflate(&zs, Z_NO_FLUSH);
+
+ if (zerror == Z_STREAM_END)
+ ; /*once more.*/
+ else if (zerror == Z_OK) {
+ /* inflate: Z_OK can indicate the end of decode */
+ if (mode && !p && zs.avail_out != 0)
+ goto terminate;
+ else
+ ; /*once more.*/
+ } else {
+ if (zs.msg) {
+ ipseclog((LOG_ERR, "ipcomp_%scompress: "
+ "%sflate(Z_NO_FLUSH): %s\n",
+ mode ? "de" : "", mode ? "in" : "de",
+ zs.msg));
+ } else {
+ ipseclog((LOG_ERR, "ipcomp_%scompress: "
+ "%sflate(Z_NO_FLUSH): unknown error (%d)\n",
+ mode ? "de" : "", mode ? "in" : "de",
+ zerror));
}
+ mode ? inflateEnd(&zs) : deflateEnd(&zs);
+ error = EINVAL;
+ goto fail;
+ }
+ }
- zs.next_out = mtod(n, u_int8_t *);
- zs.avail_out = n->m_len;
+ if (zerror == Z_STREAM_END)
+ goto terminate;
+
+ /* termination */
+ while (1) {
+ /* get output buffer */
+ if (zs.next_out == NULL || zs.avail_out == 0) {
+ MOREBLOCK();
}
- if (zerror == Z_OK) {
- /*
- * to terminate deflate/inflate process, we need to
- * call {in,de}flate() with different flushing methods.
- *
- * deflate() needs at least one Z_PARTIAL_FLUSH,
- * then use Z_FINISH until we get to the end.
- * (if we use Z_FLUSH without Z_PARTIAL_FLUSH, deflate()
- * will assume contiguous single output buffer, and that
- * is not what we want)
- * inflate() does not care about flushing method, but
- * needs output buffer until it gets to the end.
- *
- * the most outer loop will be terminated with
- * Z_STREAM_END.
- */
- if (final == 1) {
- /* reached end of mbuf chain */
- if (mode == 0)
- final = 2;
- else
- final = 3;
- } else if (final == 2) {
- /* terminate deflate case */
- flush = Z_FINISH;
- } else if (final == 3) {
- /* terminate inflate case */
- ;
- }
- } else if (zerror == Z_STREAM_END)
+ zerror = mode ? inflate(&zs, Z_FINISH)
+ : deflate(&zs, Z_FINISH);
+
+ if (zerror == Z_STREAM_END)
break;
+ else if (zerror == Z_OK)
+ ; /*once more.*/
else {
- ipseclog((LOG_ERR, "ipcomp_%scompress: %sflate: %s\n",
- mode ? "de" : "", mode ? "in" : "de",
- zs.msg ? zs.msg : "unknown error"));
+ if (zs.msg) {
+ ipseclog((LOG_ERR, "ipcomp_%scompress: "
+ "%sflate(Z_FINISH): %s\n",
+ mode ? "de" : "", mode ? "in" : "de",
+ zs.msg));
+ } else {
+ ipseclog((LOG_ERR, "ipcomp_%scompress: "
+ "%sflate(Z_FINISH): unknown error (%d)\n",
+ mode ? "de" : "", mode ? "in" : "de",
+ zerror));
+ }
+ mode ? inflateEnd(&zs) : deflateEnd(&zs);
error = EINVAL;
goto fail;
}
}
+
+terminate:
zerror = mode ? inflateEnd(&zs) : deflateEnd(&zs);
if (zerror != Z_OK) {
- ipseclog((LOG_ERR, "ipcomp_%scompress: %sflate: %s\n",
- mode ? "de" : "", mode ? "in" : "de",
- zs.msg ? zs.msg : "unknown error"));
+ if (zs.msg) {
+ ipseclog((LOG_ERR, "ipcomp_%scompress: "
+ "%sflateEnd: %s\n",
+ mode ? "de" : "", mode ? "in" : "de",
+ zs.msg));
+ } else {
+ ipseclog((LOG_ERR, "ipcomp_%scompress: "
+ "%sflateEnd: unknown error (%d)\n",
+ mode ? "de" : "", mode ? "in" : "de",
+ zerror));
+ }
error = EINVAL;
goto fail;
}
@@ -264,6 +300,7 @@ deflate_common(m, md, lenp, mode)
offset = zs.total_out;
*np = n;
np = &n->m_next;
+ n = NULL;
}
/* switch the mbuf to the new one */
@@ -276,9 +313,12 @@ deflate_common(m, md, lenp, mode)
fail:
if (m)
m_freem(m);
+ if (n)
+ m_freem(n);
if (n0)
m_freem(n0);
return error;
+#undef MOREBLOCK
}
static int
diff --git a/sys/netinet6/ipcomp_input.c b/sys/netinet6/ipcomp_input.c
index da0184c..0a6e2f5 100644
--- a/sys/netinet6/ipcomp_input.c
+++ b/sys/netinet6/ipcomp_input.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ipcomp_input.c,v 1.15 2000/07/03 13:23:28 itojun Exp $ */
+/* $KAME: ipcomp_input.c,v 1.25 2001/03/01 09:12:09 itojun Exp $ */
/*
* Copyright (C) 1999 WIDE Project.
@@ -95,9 +95,10 @@ ipcomp4_input(m, va_alist)
va_dcl
#endif
{
+ struct mbuf *md;
struct ip *ip;
struct ipcomp *ipcomp;
- struct ipcomp_algorithm *algo;
+ const struct ipcomp_algorithm *algo;
u_int16_t cpi; /* host order */
u_int16_t nxt;
size_t hlen;
@@ -112,42 +113,23 @@ ipcomp4_input(m, va_alist)
proto = va_arg(ap, int);
va_end(ap);
- if (off + sizeof(struct ipcomp) > MHLEN) {
- /*XXX the restriction should be relaxed*/
+ if (m->m_pkthdr.len < off + sizeof(struct ipcomp)) {
ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed "
- "(header too long)\n"));
+ "(packet too short)\n"));
ipsecstat.in_inval++;
goto fail;
}
- if (m->m_len < off + sizeof(struct ipcomp)) {
- m = m_pullup(m, off + sizeof(struct ipcomp));
- if (!m) {
- ipseclog((LOG_DEBUG, "IPv4 IPComp input: can't pullup;"
- "dropping the packet for simplicity\n"));
- ipsecstat.in_nomem++;
- goto fail;
- }
- } else if (m->m_len > off + sizeof(struct ipcomp)) {
- /* chop header part from the packet header chain */
- struct mbuf *n;
- MGETHDR(n, M_DONTWAIT, MT_HEADER);
- if (!n) {
- ipsecstat.in_nomem++;
- goto fail;
- }
- M_COPY_PKTHDR(n, m);
- MH_ALIGN(n, off + sizeof(struct ipcomp));
- n->m_len = off + sizeof(struct ipcomp);
- bcopy(mtod(m, caddr_t), mtod(n, caddr_t),
- off + sizeof(struct ipcomp));
- m_adj(m, off + sizeof(struct ipcomp));
- m->m_flags &= ~M_PKTHDR;
- n->m_next = m;
- m = n;
- }
+ md = m_pulldown(m, off, sizeof(*ipcomp), NULL);
+ if (!m) {
+ m = NULL; /*already freed*/
+ ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed "
+ "(pulldown failure)\n"));
+ ipsecstat.in_inval++;
+ goto fail;
+ }
+ ipcomp = mtod(md, struct ipcomp *);
ip = mtod(m, struct ip *);
- ipcomp = (struct ipcomp *)(((caddr_t)ip) + off);
nxt = ipcomp->comp_nxt;
#ifdef _IP_VHL
hlen = IP_VHL_HL(ip->ip_vhl) << 2;
@@ -167,10 +149,7 @@ ipcomp4_input(m, va_alist)
/* other parameters to look at? */
}
}
- if (cpi < IPCOMP_MAX && ipcomp_algorithms[cpi].decompress != NULL)
- algo = &ipcomp_algorithms[cpi];
- else
- algo = NULL;
+ algo = ipcomp_algorithm_lookup(cpi);
if (!algo) {
ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n",
cpi));
@@ -180,7 +159,8 @@ ipcomp4_input(m, va_alist)
/* chop ipcomp header */
ipcomp = NULL;
- m->m_len -= sizeof(struct ipcomp);
+ md->m_data += sizeof(struct ipcomp);
+ md->m_len -= sizeof(struct ipcomp);
m->m_pkthdr.len -= sizeof(struct ipcomp);
#ifdef IPLEN_FLIPPED
ip->ip_len -= sizeof(struct ipcomp);
@@ -237,13 +217,22 @@ ipcomp4_input(m, va_alist)
if (sav) {
key_sa_recordxfer(sav, m);
+ if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) {
+ ipsecstat.in_nomem++;
+ goto fail;
+ }
key_freesav(sav);
sav = NULL;
}
- if (nxt != IPPROTO_DONE)
+ if (nxt != IPPROTO_DONE) {
+ if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
+ ipsec4_in_reject(m, NULL)) {
+ ipsecstat.in_polvio++;
+ goto fail;
+ }
(*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
- else
+ } else
m_freem(m);
m = NULL;
@@ -268,66 +257,30 @@ ipcomp6_input(mp, offp, proto)
struct mbuf *m, *md;
int off;
struct ip6_hdr *ip6;
- struct mbuf *ipcompm;
struct ipcomp *ipcomp;
- struct ipcomp_algorithm *algo;
+ const struct ipcomp_algorithm *algo;
u_int16_t cpi; /* host order */
u_int16_t nxt;
int error;
size_t newlen;
struct secasvar *sav = NULL;
+ char *prvnxtp;
m = *mp;
off = *offp;
- IP6_EXTHDR_CHECK(m, off, sizeof(struct ipcomp), IPPROTO_DONE);
-
- {
- int skip;
- struct mbuf *n;
- struct mbuf *p, *q;
- size_t l;
-
- skip = off;
- for (n = m; n && skip > 0; n = n->m_next) {
- if (n->m_len <= skip) {
- skip -= n->m_len;
- continue;
- }
- break;
- }
- if (!n) {
- ipseclog((LOG_DEBUG, "IPv6 IPComp input: wrong mbuf chain\n"));
- ipsecstat.in_inval++;
- goto fail;
- }
- if (n->m_len < skip + sizeof(struct ipcomp)) {
- ipseclog((LOG_DEBUG, "IPv6 IPComp input: wrong mbuf chain\n"));
- ipsecstat.in_inval++;
+ md = m_pulldown(m, off, sizeof(*ipcomp), NULL);
+ if (!m) {
+ m = NULL; /*already freed*/
+ ipseclog((LOG_DEBUG, "IPv6 IPComp input: assumption failed "
+ "(pulldown failure)\n"));
+ ipsec6stat.in_inval++;
goto fail;
}
+ ipcomp = mtod(md, struct ipcomp *);
ip6 = mtod(m, struct ip6_hdr *);
- ipcompm = n;
- ipcomp = (struct ipcomp *)(mtod(n, caddr_t) + skip);
- if (n->m_len > skip + sizeof(struct ipcomp)) {
- /* split mbuf to ease the following steps*/
- l = n->m_len - (skip + sizeof(struct ipcomp));
- p = m_copym(n, skip + sizeof(struct ipcomp), l , M_DONTWAIT);
- if (!p) {
- ipsecstat.in_nomem++;
- goto fail;
- }
- for (q = p; q && q->m_next; q = q->m_next)
- ;
- q->m_next = n->m_next;
- n->m_next = p;
- n->m_len -= l;
- md = p;
- } else
- md = n->m_next;
- }
-
nxt = ipcomp->comp_nxt;
+
cpi = ntohs(ipcomp->comp_cpi);
if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) {
@@ -340,10 +293,7 @@ ipcomp6_input(mp, offp, proto)
/* other parameters to look at? */
}
}
- if (cpi < IPCOMP_MAX && ipcomp_algorithms[cpi].decompress != NULL)
- algo = &ipcomp_algorithms[cpi];
- else
- algo = NULL;
+ algo = ipcomp_algorithm_lookup(cpi);
if (!algo) {
ipseclog((LOG_WARNING, "IPv6 IPComp input: unknown cpi %u; "
"dropping the packet for simplicity\n", cpi));
@@ -351,7 +301,13 @@ ipcomp6_input(mp, offp, proto)
goto fail;
}
- newlen = m->m_pkthdr.len - off - sizeof(struct ipcomp);
+ /* chop ipcomp header */
+ ipcomp = NULL;
+ md->m_data += sizeof(struct ipcomp);
+ md->m_len -= sizeof(struct ipcomp);
+ m->m_pkthdr.len -= sizeof(struct ipcomp);
+
+ newlen = m->m_pkthdr.len - off;
error = (*algo->decompress)(m, md, &newlen);
if (error != 0) {
if (error == EINVAL)
@@ -362,7 +318,7 @@ ipcomp6_input(mp, offp, proto)
goto fail;
}
ipsec6stat.in_comphist[cpi]++;
- m->m_pkthdr.len = off + sizeof(struct ipcomp) + newlen;
+ m->m_pkthdr.len = off + newlen;
/*
* returning decompressed packet onto icmp is meaningless.
@@ -370,25 +326,21 @@ ipcomp6_input(mp, offp, proto)
*/
m->m_flags |= M_DECRYPTED;
- {
- char *prvnxtp;
-
- /* chop IPComp header */
+ /* update next header field */
prvnxtp = ip6_get_prevhdr(m, off);
*prvnxtp = nxt;
- ipcompm->m_len -= sizeof(struct ipcomp);
- ipcompm->m_pkthdr.len -= sizeof(struct ipcomp);
- /* adjust payload length */
- ip6 = mtod(m, struct ip6_hdr *);
- if (((m->m_pkthdr.len - sizeof(struct ip6_hdr)) & ~0xffff) != 0)
- ip6->ip6_plen = 0; /*now a jumbogram*/
- else
- ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
- }
+ /*
+ * no need to adjust payload length, as all the IPv6 protocols
+ * look at m->m_pkthdr.len
+ */
if (sav) {
key_sa_recordxfer(sav, m);
+ if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) {
+ ipsec6stat.in_nomem++;
+ goto fail;
+ }
key_freesav(sav);
sav = NULL;
}
diff --git a/sys/netinet6/ipcomp_output.c b/sys/netinet6/ipcomp_output.c
index 265700e..b82840a 100644
--- a/sys/netinet6/ipcomp_output.c
+++ b/sys/netinet6/ipcomp_output.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ipcomp_output.c,v 1.15 2000/07/03 13:23:28 itojun Exp $ */
+/* $KAME: ipcomp_output.c,v 1.23 2001/01/23 08:59:37 itojun Exp $ */
/*
* Copyright (C) 1999 WIDE Project.
@@ -87,7 +87,7 @@ static int ipcomp_output __P((struct mbuf *, u_char *, struct mbuf *,
/*
* Modify the packet so that the payload is compressed.
* The mbuf (m) must start with IPv4 or IPv6 header.
- * On failure, free the given mbuf and return NULL.
+ * On failure, free the given mbuf and return non-zero.
*
* on invocation:
* m nexthdrp md
@@ -112,25 +112,29 @@ ipcomp_output(m, nexthdrp, md, isr, af)
{
struct mbuf *n;
struct mbuf *md0;
+ struct mbuf *mcopy;
struct mbuf *mprev;
struct ipcomp *ipcomp;
struct secasvar *sav = isr->sav;
- struct ipcomp_algorithm *algo;
+ const struct ipcomp_algorithm *algo;
u_int16_t cpi; /* host order */
size_t plen0, plen; /*payload length to be compressed*/
size_t compoff;
int afnumber;
int error = 0;
+ struct ipsecstat *stat;
switch (af) {
#ifdef INET
case AF_INET:
afnumber = 4;
+ stat = &ipsecstat;
break;
#endif
#ifdef INET6
case AF_INET6:
afnumber = 6;
+ stat = &ipsec6stat;
break;
#endif
default:
@@ -139,9 +143,9 @@ ipcomp_output(m, nexthdrp, md, isr, af)
}
/* grab parameters */
- if ((ntohl(sav->spi) & ~0xffff) != 0 || sav->alg_enc >= IPCOMP_MAX
- || ipcomp_algorithms[sav->alg_enc].compress == NULL) {
- ipsecstat.out_inval++;
+ algo = ipcomp_algorithm_lookup(sav->alg_enc);
+ if ((ntohl(sav->spi) & ~0xffff) != 0 || !algo) {
+ stat->out_inval++;
m_freem(m);
return EINVAL;
}
@@ -149,7 +153,6 @@ ipcomp_output(m, nexthdrp, md, isr, af)
cpi = sav->alg_enc;
else
cpi = ntohl(sav->spi) & 0xffff;
- algo = &ipcomp_algorithms[sav->alg_enc]; /*XXX*/
/* compute original payload length */
plen = 0;
@@ -161,11 +164,21 @@ ipcomp_output(m, nexthdrp, md, isr, af)
return 0;
/*
- * keep the original data packet, so that we can backout
- * our changes when compression is not necessary.
+ * retain the original packet for two purposes:
+ * (1) we need to backout our changes when compression is not necessary.
+ * (2) byte lifetime computation should use the original packet.
+ * see RFC2401 page 23.
+ * compromise two m_copym(). we will be going through every byte of
+ * the payload during compression process anyways.
*/
+ mcopy = m_copym(m, 0, M_COPYALL, M_NOWAIT);
+ if (mcopy == NULL) {
+ error = ENOBUFS;
+ return 0;
+ }
md0 = m_copym(md, 0, M_COPYALL, M_NOWAIT);
if (md0 == NULL) {
+ m_freem(mcopy);
error = ENOBUFS;
return 0;
}
@@ -177,26 +190,17 @@ ipcomp_output(m, nexthdrp, md, isr, af)
if (mprev == NULL || mprev->m_next != md) {
ipseclog((LOG_DEBUG, "ipcomp%d_output: md is not in chain\n",
afnumber));
- switch (af) {
-#ifdef INET
- case AF_INET:
- ipsecstat.out_inval++;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- ipsec6stat.out_inval++;
- break;
-#endif
- }
+ stat->out_inval++;
m_freem(m);
m_freem(md0);
+ m_freem(mcopy);
return EINVAL;
}
mprev->m_next = NULL;
if ((md = ipsec_copypkt(md)) == NULL) {
m_freem(m);
m_freem(md0);
+ m_freem(mcopy);
error = ENOBUFS;
goto fail;
}
@@ -207,33 +211,12 @@ ipcomp_output(m, nexthdrp, md, isr, af)
ipseclog((LOG_ERR, "packet compression failure\n"));
m = NULL;
m_freem(md0);
- switch (af) {
-#ifdef INET
- case AF_INET:
- ipsecstat.out_inval++;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- ipsec6stat.out_inval++;
- break;
-#endif
- }
+ m_freem(mcopy);
+ stat->out_inval++;
error = EINVAL;
goto fail;
}
- switch (af) {
-#ifdef INET
- case AF_INET:
- ipsecstat.out_comphist[sav->alg_enc]++;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- ipsec6stat.out_comphist[sav->alg_enc]++;
- break;
-#endif
- }
+ stat->out_comphist[sav->alg_enc]++;
md = mprev->m_next;
/*
@@ -242,13 +225,17 @@ ipcomp_output(m, nexthdrp, md, isr, af)
*/
if (plen0 < plen) {
m_freem(md);
+ m_freem(mcopy);
mprev->m_next = md0;
return 0;
}
- /* no need to backout change beyond here */
+ /*
+ * no need to backout change beyond here.
+ */
m_freem(md0);
md0 = NULL;
+
m->m_pkthdr.len -= plen0;
m->m_pkthdr.len += plen;
@@ -341,47 +328,14 @@ ipcomp_output(m, nexthdrp, md, isr, af)
ipseclog((LOG_DEBUG,
"NULL mbuf after compression in ipcomp%d_output",
afnumber));
- switch (af) {
-#ifdef INET
- case AF_INET:
- ipsecstat.out_inval++;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- ipsec6stat.out_inval++;
- break;
-#endif
- }
- } else {
- switch (af) {
-#ifdef INET
- case AF_INET:
- ipsecstat.out_success++;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- ipsec6stat.out_success++;
- break;
-#endif
- }
+ stat->out_inval++;
}
-#if 0
- switch (af) {
-#ifdef INET
- case AF_INET:
- ipsecstat.out_esphist[sav->alg_enc]++;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- ipsec6stat.out_esphist[sav->alg_enc]++;
- break;
-#endif
- }
-#endif
- key_sa_recordxfer(sav, m);
+ stat->out_success++;
+
+ /* compute byte lifetime against original packet */
+ key_sa_recordxfer(sav, mcopy);
+ m_freem(mcopy);
+
return 0;
fail:
diff --git a/sys/netinet6/ipsec.c b/sys/netinet6/ipsec.c
index b8a2447..3cb835d 100644
--- a/sys/netinet6/ipsec.c
+++ b/sys/netinet6/ipsec.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ipsec.c,v 1.66 2000/06/15 04:08:54 itojun Exp $ */
+/* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -67,9 +67,11 @@
#ifdef INET6
#include <netinet6/ip6_ecn.h>
#endif
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
-#ifdef INET6
#include <netinet/ip6.h>
+#ifdef INET6
#include <netinet6/ip6_var.h>
#endif
#include <netinet/in_pcb.h>
@@ -97,25 +99,12 @@
#endif
#include <netkey/key.h>
#include <netkey/keydb.h>
-#ifdef IPSEC_DEBUG
#include <netkey/key_debug.h>
-#else
-#define KEYDEBUG(lev,arg)
-#endif
#include <machine/in_cksum.h>
#include <net/net_osdep.h>
-#ifdef HAVE_NRL_INPCB
-#define in6pcb inpcb
-#define in6p_sp inp_sp
-#define in6p_fport inp_fport
-#define in6p_lport inp_lport
-#define in6p_socket inp_socket
-#define sotoin6pcb(so) ((struct inpcb *)(so)->so_pcb)
-#endif
-
#ifdef IPSEC_DEBUG
int ipsec_debug = 1;
#else
@@ -132,11 +121,14 @@ int ip4_ah_trans_deflev = IPSEC_LEVEL_USE;
int ip4_ah_net_deflev = IPSEC_LEVEL_USE;
struct secpolicy ip4_def_policy;
int ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */
+int ip4_esp_randpad = -1;
+#ifdef SYSCTL_DECL
SYSCTL_DECL(_net_inet_ipsec);
#ifdef INET6
SYSCTL_DECL(_net_inet6_ipsec6);
#endif
+#endif
/* net.inet.ipsec */
SYSCTL_STRUCT(_net_inet_ipsec, IPSECCTL_STATS,
@@ -161,6 +153,8 @@ SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN,
ecn, CTLFLAG_RW, &ip4_ipsec_ecn, 0, "");
SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEBUG,
debug, CTLFLAG_RW, &ipsec_debug, 0, "");
+SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ESP_RANDPAD,
+ esp_randpad, CTLFLAG_RW, &ip4_esp_randpad, 0, "");
#ifdef INET6
struct ipsecstat ipsec6stat;
@@ -170,6 +164,7 @@ int ip6_ah_trans_deflev = IPSEC_LEVEL_USE;
int ip6_ah_net_deflev = IPSEC_LEVEL_USE;
struct secpolicy ip6_def_policy;
int ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */
+int ip6_esp_randpad = -1;
/* net.inet6.ipsec6 */
SYSCTL_STRUCT(_net_inet6_ipsec6, IPSECCTL_STATS,
@@ -188,16 +183,22 @@ SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN,
ecn, CTLFLAG_RW, &ip6_ipsec_ecn, 0, "");
SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG,
debug, CTLFLAG_RW, &ipsec_debug, 0, "");
+SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ESP_RANDPAD,
+ esp_randpad, CTLFLAG_RW, &ip6_esp_randpad, 0, "");
#endif /* INET6 */
static int ipsec_setspidx_mbuf
- __P((struct secpolicyindex *, u_int, u_int, struct mbuf *));
-static void ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb));
-static void ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *));
+ __P((struct secpolicyindex *, u_int, u_int, struct mbuf *, int));
+static int ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb));
+#ifdef INET6
+static int ipsec6_setspidx_in6pcb __P((struct mbuf *, struct in6pcb *pcb));
+#endif
+static int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int));
+static void ipsec4_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int));
+static int ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *));
#ifdef INET6
-static void ipsec6_get_ulp __P((struct mbuf *m, struct secpolicyindex *));
-static void ipsec6_setspidx_in6pcb __P((struct mbuf *, struct in6pcb *pcb));
-static void ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *));
+static void ipsec6_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int));
+static int ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *));
#endif
static struct inpcbpolicy *ipsec_newpcbpolicy __P((void));
static void ipsec_delpcbpolicy __P((struct inpcbpolicy *));
@@ -208,14 +209,21 @@ static int ipsec_get_policy __P((struct secpolicy *pcb_sp, struct mbuf **mp));
static void vshiftl __P((unsigned char *, int, int));
static int ipsec_in_reject __P((struct secpolicy *, struct mbuf *));
static size_t ipsec_hdrsiz __P((struct secpolicy *));
+#ifdef INET
static struct mbuf *ipsec4_splithdr __P((struct mbuf *));
+#endif
#ifdef INET6
static struct mbuf *ipsec6_splithdr __P((struct mbuf *));
#endif
+#ifdef INET
static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *));
+#endif
#ifdef INET6
static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *));
#endif
+static struct mbuf *ipsec_addaux __P((struct mbuf *));
+static struct mbuf *ipsec_findaux __P((struct mbuf *));
+static void ipsec_optaux __P((struct mbuf *, struct mbuf *));
/*
* For OUTBOUND packet having a socket. Searching SPD for packet,
@@ -247,19 +255,29 @@ ipsec4_getpolicybysock(m, dir, so, error)
switch (so->so_proto->pr_domain->dom_family) {
case AF_INET:
/* set spidx in pcb */
- ipsec4_setspidx_inpcb(m, sotoinpcb(so));
- pcbsp = sotoinpcb(so)->inp_sp;
+ *error = ipsec4_setspidx_inpcb(m, sotoinpcb(so));
break;
#ifdef INET6
case AF_INET6:
/* set spidx in pcb */
- ipsec6_setspidx_in6pcb(m, sotoin6pcb(so));
- pcbsp = sotoin6pcb(so)->in6p_sp;
+ *error = ipsec6_setspidx_in6pcb(m, sotoin6pcb(so));
break;
#endif
default:
panic("ipsec4_getpolicybysock: unsupported address family\n");
}
+ if (*error)
+ return NULL;
+ switch (so->so_proto->pr_domain->dom_family) {
+ case AF_INET:
+ pcbsp = sotoinpcb(so)->inp_sp;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ pcbsp = sotoin6pcb(so)->in6p_sp;
+ break;
+#endif
+ }
/* sanity check */
if (pcbsp == NULL)
@@ -404,7 +422,8 @@ ipsec4_getpolicybyaddr(m, dir, flag, error)
bzero(&spidx, sizeof(spidx));
/* make a index to look for a policy */
- *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m);
+ *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m,
+ (flag & IP_FORWARDING) ? 0 : 1);
if (*error != 0)
return NULL;
@@ -460,6 +479,11 @@ ipsec6_getpolicybysock(m, dir, so, error)
if (m == NULL || so == NULL || error == NULL)
panic("ipsec6_getpolicybysock: NULL pointer was passed.\n");
+#ifdef DIAGNOSTIC
+ if (so->so_proto->pr_domain->dom_family != AF_INET6)
+ panic("ipsec6_getpolicybysock: socket domain != inet6\n");
+#endif
+
/* set spidx in pcb */
ipsec6_setspidx_in6pcb(m, sotoin6pcb(so));
@@ -615,7 +639,8 @@ ipsec6_getpolicybyaddr(m, dir, flag, error)
bzero(&spidx, sizeof(spidx));
/* make a index to look for a policy */
- *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m);
+ *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m,
+ (flag & IP_FORWARDING) ? 0 : 1);
if (*error != 0)
return NULL;
@@ -656,302 +681,286 @@ ipsec6_getpolicybyaddr(m, dir, flag, error)
* other: failure, and set errno.
*/
int
-ipsec_setspidx_mbuf(spidx, dir, family, m)
+ipsec_setspidx_mbuf(spidx, dir, family, m, needport)
struct secpolicyindex *spidx;
u_int dir, family;
struct mbuf *m;
+ int needport;
{
+ int error;
/* sanity check */
if (spidx == NULL || m == NULL)
panic("ipsec_setspidx_mbuf: NULL pointer was passed.\n");
- KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
- printf("ipsec_setspidx_mbuf: begin\n"); kdebug_mbuf(m));
-
- /* initialize */
bzero(spidx, sizeof(*spidx));
+ error = ipsec_setspidx(m, spidx, needport);
+ if (error)
+ goto bad;
spidx->dir = dir;
- {
- /* sanity check for packet length. */
- struct mbuf *n;
- int tlen;
-
- tlen = 0;
- for (n = m; n; n = n->m_next)
- tlen += n->m_len;
- if (m->m_pkthdr.len != tlen) {
- KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
- printf("ipsec_setspidx_mbuf: "
- "total of m_len(%d) != pkthdr.len(%d), "
- "ignored.\n",
- tlen, m->m_pkthdr.len));
- goto bad;
- }
- }
+ return 0;
- switch (family) {
- case AF_INET:
- {
- struct ip *ip;
- struct ip ipbuf;
- struct sockaddr_in *sin;
+ bad:
+ /* XXX initialize */
+ bzero(spidx, sizeof(*spidx));
+ return EINVAL;
+}
- /* sanity check 1 for minimum ip header length */
- if (m->m_pkthdr.len < sizeof(struct ip)) {
- KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
- printf("ipsec_setspidx_mbuf: "
- "pkthdr.len(%d) < sizeof(struct ip), "
- "ignored.\n",
- m->m_pkthdr.len));
- goto bad;
- }
+static int
+ipsec4_setspidx_inpcb(m, pcb)
+ struct mbuf *m;
+ struct inpcb *pcb;
+{
+ struct secpolicyindex *spidx;
+ int error;
- /*
- * get IPv4 header packet. usually the mbuf is contiguous
- * and we need no copies.
- */
- if (m->m_len >= sizeof(*ip))
- ip = mtod(m, struct ip *);
- else {
- m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf);
- ip = &ipbuf;
- }
+ /* sanity check */
+ if (pcb == NULL)
+ panic("ipsec4_setspidx_inpcb: no PCB found.\n");
+ if (pcb->inp_sp == NULL)
+ panic("ipsec4_setspidx_inpcb: no inp_sp found.\n");
+ if (pcb->inp_sp->sp_out == NULL || pcb->inp_sp->sp_in == NULL)
+ panic("ipsec4_setspidx_inpcb: no sp_in/out found.\n");
- /* XXX some more checks on IPv4 header. */
+ bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx));
+ bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx));
- sin = (struct sockaddr_in *)&spidx->src;
- sin->sin_family = AF_INET;
- sin->sin_len = sizeof(*sin);
- bcopy(&ip->ip_src, &sin->sin_addr, sizeof(sin->sin_addr));
- sin->sin_port = IPSEC_PORT_ANY;
+ spidx = &pcb->inp_sp->sp_in->spidx;
+ error = ipsec_setspidx(m, spidx, 1);
+ if (error)
+ goto bad;
+ spidx->dir = IPSEC_DIR_INBOUND;
- sin = (struct sockaddr_in *)&spidx->dst;
- sin->sin_family = AF_INET;
- sin->sin_len = sizeof(*sin);
- bcopy(&ip->ip_dst, &sin->sin_addr, sizeof(sin->sin_addr));
- sin->sin_port = IPSEC_PORT_ANY;
+ spidx = &pcb->inp_sp->sp_out->spidx;
+ error = ipsec_setspidx(m, spidx, 1);
+ if (error)
+ goto bad;
+ spidx->dir = IPSEC_DIR_OUTBOUND;
- spidx->prefs = spidx->prefd = sizeof(struct in_addr) << 3;
+ return 0;
- spidx->ul_proto = ip->ip_p;
- break;
- }
+bad:
+ bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx));
+ bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx));
+ return error;
+}
#ifdef INET6
- case AF_INET6:
- {
- struct ip6_hdr *ip6;
- struct ip6_hdr ip6buf;
- struct sockaddr_in6 *sin6;
+static int
+ipsec6_setspidx_in6pcb(m, pcb)
+ struct mbuf *m;
+ struct in6pcb *pcb;
+{
+ struct secpolicyindex *spidx;
+ int error;
- /* sanity check 1 for minimum ip header length */
- if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) {
- KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
- printf("ipsec_setspidx_mbuf: "
- "pkthdr.len(%d) < sizeof(struct ip6_hdr), "
- "ignored.\n",
- m->m_pkthdr.len));
- goto bad;
- }
+ /* sanity check */
+ if (pcb == NULL)
+ panic("ipsec6_setspidx_in6pcb: no PCB found.\n");
+ if (pcb->in6p_sp == NULL)
+ panic("ipsec6_setspidx_in6pcb: no in6p_sp found.\n");
+ if (pcb->in6p_sp->sp_out == NULL || pcb->in6p_sp->sp_in == NULL)
+ panic("ipsec6_setspidx_in6pcb: no sp_in/out found.\n");
- /*
- * get IPv6 header packet. usually the mbuf is contiguous
- * and we need no copies.
- */
- if (m->m_len >= sizeof(*ip6))
- ip6 = mtod(m, struct ip6_hdr *);
- else {
- m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf);
- ip6 = &ip6buf;
- }
+ bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx));
+ bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx));
- /* some more checks on IPv4 header. */
- if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
- KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
- printf("ipsec_setspidx_mbuf: "
- "wrong ip version on packet "
- "(expected IPv6), ignored.\n"));
- goto bad;
- }
+ spidx = &pcb->in6p_sp->sp_in->spidx;
+ error = ipsec_setspidx(m, spidx, 1);
+ if (error)
+ goto bad;
+ spidx->dir = IPSEC_DIR_INBOUND;
- sin6 = (struct sockaddr_in6 *)&spidx->src;
- sin6->sin6_family = AF_INET6;
- sin6->sin6_len = sizeof(*sin6);
- bcopy(&ip6->ip6_src, &sin6->sin6_addr, sizeof(sin6->sin6_addr));
- sin6->sin6_port = IPSEC_PORT_ANY;
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
- /* fix scope id for comparing SPD */
- sin6->sin6_addr.s6_addr16[1] = 0;
- sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
- }
+ spidx = &pcb->in6p_sp->sp_out->spidx;
+ error = ipsec_setspidx(m, spidx, 1);
+ if (error)
+ goto bad;
+ spidx->dir = IPSEC_DIR_OUTBOUND;
- sin6 = (struct sockaddr_in6 *)&spidx->dst;
- sin6->sin6_family = AF_INET6;
- sin6->sin6_len = sizeof(*sin6);
- bcopy(&ip6->ip6_dst, &sin6->sin6_addr, sizeof(sin6->sin6_addr));
- sin6->sin6_port = IPSEC_PORT_ANY;
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
- /* fix scope id for comparing SPD */
- sin6->sin6_addr.s6_addr16[1] = 0;
- sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
- }
+ return 0;
- spidx->prefs = spidx->prefd = sizeof(struct in6_addr) << 3;
+bad:
+ bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx));
+ bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx));
+ return error;
+}
+#endif
- ipsec6_get_ulp(m, spidx);
- break;
- }
-#endif /* INET6 */
- default:
- panic("ipsec_secsecidx: no supported family passed.\n");
- }
+/*
+ * configure security policy index (src/dst/proto/sport/dport)
+ * by looking at the content of mbuf.
+ * the caller is responsible for error recovery (like clearing up spidx).
+ */
+static int
+ipsec_setspidx(m, spidx, needport)
+ struct mbuf *m;
+ struct secpolicyindex *spidx;
+ int needport;
+{
+ struct ip *ip = NULL;
+ struct ip ipbuf;
+ u_int v;
+ struct mbuf *n;
+ int len;
+ int error;
- KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
- printf("ipsec_setspidx_mbuf: end\n");
- kdebug_secpolicyindex(spidx));
+ if (m == NULL)
+ panic("ipsec_setspidx: m == 0 passed.\n");
- return 0;
+ /*
+ * validate m->m_pkthdr.len. we see incorrect length if we
+ * mistakenly call this function with inconsistent mbuf chain
+ * (like 4.4BSD tcp/udp processing). XXX should we panic here?
+ */
+ len = 0;
+ for (n = m; n; n = n->m_next)
+ len += n->m_len;
+ if (m->m_pkthdr.len != len) {
+ KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
+ printf("ipsec_setspidx: "
+ "total of m_len(%d) != pkthdr.len(%d), "
+ "ignored.\n",
+ len, m->m_pkthdr.len));
+ return EINVAL;
+ }
- bad:
- /* XXX initialize */
- bzero(spidx, sizeof(*spidx));
- return EINVAL;
-}
+ if (m->m_pkthdr.len < sizeof(struct ip)) {
+ KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
+ printf("ipsec_setspidx: "
+ "pkthdr.len(%d) < sizeof(struct ip), ignored.\n",
+ m->m_pkthdr.len));
+ return EINVAL;
+ }
+ if (m->m_len >= sizeof(*ip))
+ ip = mtod(m, struct ip *);
+ else {
+ m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf);
+ ip = &ipbuf;
+ }
+#ifdef _IP_VHL
+ v = _IP_VHL_V(ip->ip_vhl);
+#else
+ v = ip->ip_v;
+#endif
+ switch (v) {
+ case 4:
+ error = ipsec4_setspidx_ipaddr(m, spidx);
+ if (error)
+ return error;
+ ipsec4_get_ulp(m, spidx, needport);
+ return 0;
#ifdef INET6
-/*
- * Get upper layer protocol number and port number if there.
- * Assumed all extension headers are in single mbuf.
- */
-#include <netinet/tcp.h>
-#include <netinet/udp.h>
+ case 6:
+ if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) {
+ KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
+ printf("ipsec_setspidx: "
+ "pkthdr.len(%d) < sizeof(struct ip6_hdr), "
+ "ignored.\n", m->m_pkthdr.len));
+ return EINVAL;
+ }
+ error = ipsec6_setspidx_ipaddr(m, spidx);
+ if (error)
+ return error;
+ ipsec6_get_ulp(m, spidx, needport);
+ return 0;
+#endif
+ default:
+ KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
+ printf("ipsec_setspidx: "
+ "unknown IP version %u, ignored.\n", v));
+ return EINVAL;
+ }
+}
+
static void
-ipsec6_get_ulp(m, spidx)
+ipsec4_get_ulp(m, spidx, needport)
struct mbuf *m;
struct secpolicyindex *spidx;
+ int needport;
{
- int off, nxt;
+ struct ip ip;
+ struct ip6_ext ip6e;
+ u_int8_t nxt;
+ int off;
+ struct tcphdr th;
+ struct udphdr uh;
/* sanity check */
if (m == NULL)
- panic("ipsec6_get_ulp: NULL pointer was passed.\n");
-
- KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
- printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m));
+ panic("ipsec4_get_ulp: NULL pointer was passed.\n");
+ if (m->m_pkthdr.len < sizeof(ip))
+ panic("ipsec4_get_ulp: too short\n");
/* set default */
spidx->ul_proto = IPSEC_ULPROTO_ANY;
- ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY;
- ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY;
+ ((struct sockaddr_in *)&spidx->src)->sin_port = IPSEC_PORT_ANY;
+ ((struct sockaddr_in *)&spidx->dst)->sin_port = IPSEC_PORT_ANY;
- nxt = -1;
- off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
- if (off < 0 || m->m_pkthdr.len < off)
+ m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
+ /* ip_input() flips it into host endian XXX need more checking */
+ if (ip.ip_off & (IP_MF | IP_OFFMASK))
return;
- switch (nxt) {
- case IPPROTO_TCP:
- spidx->ul_proto = nxt;
- if (off + sizeof(struct tcphdr) <= m->m_pkthdr.len) {
- struct tcphdr th;
+ nxt = ip.ip_p;
+#ifdef _IP_VHL
+ off = _IP_VHL_HL(ip->ip_vhl) << 2;
+#else
+ off = ip.ip_hl << 2;
+#endif
+ while (off < m->m_pkthdr.len) {
+ switch (nxt) {
+ case IPPROTO_TCP:
+ spidx->ul_proto = nxt;
+ if (!needport)
+ return;
+ if (off + sizeof(struct tcphdr) > m->m_pkthdr.len)
+ return;
m_copydata(m, off, sizeof(th), (caddr_t)&th);
- ((struct sockaddr_in6 *)&spidx->src)->sin6_port =
+ ((struct sockaddr_in *)&spidx->src)->sin_port =
th.th_sport;
- ((struct sockaddr_in6 *)&spidx->dst)->sin6_port =
+ ((struct sockaddr_in *)&spidx->dst)->sin_port =
th.th_dport;
- }
- break;
- case IPPROTO_UDP:
- spidx->ul_proto = nxt;
- if (off + sizeof(struct udphdr) <= m->m_pkthdr.len) {
- struct udphdr uh;
+ return;
+ case IPPROTO_UDP:
+ spidx->ul_proto = nxt;
+ if (!needport)
+ return;
+ if (off + sizeof(struct udphdr) > m->m_pkthdr.len)
+ return;
m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
- ((struct sockaddr_in6 *)&spidx->src)->sin6_port =
+ ((struct sockaddr_in *)&spidx->src)->sin_port =
uh.uh_sport;
- ((struct sockaddr_in6 *)&spidx->dst)->sin6_port =
+ ((struct sockaddr_in *)&spidx->dst)->sin_port =
uh.uh_dport;
+ return;
+ case IPPROTO_AH:
+ if (m->m_pkthdr.len > off + sizeof(ip6e))
+ return;
+ m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
+ off += (ip6e.ip6e_len + 2) << 2;
+ nxt = ip6e.ip6e_nxt;
+ break;
+ case IPPROTO_ICMP:
+ default:
+ /* XXX intermediate headers??? */
+ spidx->ul_proto = nxt;
+ return;
}
- break;
- case IPPROTO_ICMPV6:
- spidx->ul_proto = nxt;
- break;
- default:
- break;
}
}
-#endif
-
-static void
-ipsec4_setspidx_inpcb(m, pcb)
- struct mbuf *m;
- struct inpcb *pcb;
-{
- struct secpolicyindex *spidx;
- struct sockaddr_in *sin1, *sin2;
-
- /* sanity check */
- if (pcb == NULL)
- panic("ipsec4_setspidx_inpcb: no PCB found.\n");
- if (pcb->inp_sp == NULL)
- panic("ipsec4_setspidx_inpcb: no inp_sp found.\n");
- if (pcb->inp_sp->sp_out ==NULL || pcb->inp_sp->sp_in == NULL)
- panic("ipsec4_setspidx_inpcb: no sp_in/out found.\n");
-
- bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx));
- bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx));
-
- spidx = &pcb->inp_sp->sp_in->spidx;
- spidx->dir = IPSEC_DIR_INBOUND;
- sin1 = (struct sockaddr_in *)&spidx->src;
- sin2 = (struct sockaddr_in *)&spidx->dst;
- sin1->sin_len = sin2->sin_len = sizeof(struct sockaddr_in);
- sin1->sin_family = sin2->sin_family = AF_INET;
- spidx->prefs = sizeof(struct in_addr) << 3;
- spidx->prefd = sizeof(struct in_addr) << 3;
- spidx->ul_proto = pcb->inp_socket->so_proto->pr_protocol;
- sin1->sin_port = pcb->inp_fport;
- sin2->sin_port = pcb->inp_lport;
- ipsec4_setspidx_ipaddr(m, spidx);
-
- spidx = &pcb->inp_sp->sp_out->spidx;
- spidx->dir = IPSEC_DIR_OUTBOUND;
- sin1 = (struct sockaddr_in *)&spidx->src;
- sin2 = (struct sockaddr_in *)&spidx->dst;
- sin1->sin_len = sin2->sin_len = sizeof(struct sockaddr_in);
- sin1->sin_family = sin2->sin_family = AF_INET;
- spidx->prefs = sizeof(struct in_addr) << 3;
- spidx->prefd = sizeof(struct in_addr) << 3;
- spidx->ul_proto = pcb->inp_socket->so_proto->pr_protocol;
- sin1->sin_port = pcb->inp_lport;
- sin2->sin_port = pcb->inp_fport;
- ipsec4_setspidx_ipaddr(m, spidx);
-
- return;
-}
-static void
+/* assumes that m is sane */
+static int
ipsec4_setspidx_ipaddr(m, spidx)
struct mbuf *m;
struct secpolicyindex *spidx;
{
struct ip *ip = NULL;
struct ip ipbuf;
-
- /* sanity check 1 for minimum ip header length */
- if (m == NULL)
- panic("ipsec4_setspidx_ipaddr: m == 0 passed.\n");
-
- if (m->m_pkthdr.len < sizeof(struct ip)) {
- KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
- printf("ipsec4_setspidx_ipaddr: "
- "pkthdr.len(%d) < sizeof(struct ip), "
- "ignored.\n",
- m->m_pkthdr.len));
- return;
- }
+ struct sockaddr_in *sin;
if (m->m_len >= sizeof(*ip))
ip = mtod(m, struct ip *);
@@ -960,64 +969,81 @@ ipsec4_setspidx_ipaddr(m, spidx)
ip = &ipbuf;
}
- bcopy(&ip->ip_src, &((struct sockaddr_in *)&spidx->src)->sin_addr,
- sizeof(ip->ip_src));
- bcopy(&ip->ip_dst, &((struct sockaddr_in *)&spidx->dst)->sin_addr,
- sizeof(ip->ip_dst));
+ sin = (struct sockaddr_in *)&spidx->src;
+ bzero(sin, sizeof(*sin));
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(struct sockaddr_in);
+ bcopy(&ip->ip_src, &sin->sin_addr, sizeof(ip->ip_src));
+ spidx->prefs = sizeof(struct in_addr) << 3;
- return;
+ sin = (struct sockaddr_in *)&spidx->dst;
+ bzero(sin, sizeof(*sin));
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(struct sockaddr_in);
+ bcopy(&ip->ip_dst, &sin->sin_addr, sizeof(ip->ip_dst));
+ spidx->prefd = sizeof(struct in_addr) << 3;
+ return 0;
}
#ifdef INET6
static void
-ipsec6_setspidx_in6pcb(m, pcb)
+ipsec6_get_ulp(m, spidx, needport)
struct mbuf *m;
- struct in6pcb *pcb;
-{
struct secpolicyindex *spidx;
- struct sockaddr_in6 *sin1, *sin2;
+ int needport;
+{
+ int off, nxt;
+ struct tcphdr th;
+ struct udphdr uh;
/* sanity check */
- if (pcb == NULL)
- panic("ipsec6_setspidx_in6pcb: no PCB found.\n");
- if (pcb->in6p_sp == NULL)
- panic("ipsec6_setspidx_in6pcb: no in6p_sp found.\n");
- if (pcb->in6p_sp->sp_out ==NULL || pcb->in6p_sp->sp_in == NULL)
- panic("ipsec6_setspidx_in6pcb: no sp_in/out found.\n");
+ if (m == NULL)
+ panic("ipsec6_get_ulp: NULL pointer was passed.\n");
- bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx));
- bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx));
+ KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
+ printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m));
- spidx = &pcb->in6p_sp->sp_in->spidx;
- spidx->dir = IPSEC_DIR_INBOUND;
- sin1 = (struct sockaddr_in6 *)&spidx->src;
- sin2 = (struct sockaddr_in6 *)&spidx->dst;
- sin1->sin6_len = sin2->sin6_len = sizeof(struct sockaddr_in6);
- sin1->sin6_family = sin2->sin6_family = AF_INET6;
- spidx->prefs = sizeof(struct in6_addr) << 3;
- spidx->prefd = sizeof(struct in6_addr) << 3;
- spidx->ul_proto = pcb->in6p_socket->so_proto->pr_protocol;
- sin1->sin6_port = pcb->in6p_fport;
- sin2->sin6_port = pcb->in6p_lport;
- ipsec6_setspidx_ipaddr(m, spidx);
+ /* set default */
+ spidx->ul_proto = IPSEC_ULPROTO_ANY;
+ ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY;
+ ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY;
- spidx = &pcb->in6p_sp->sp_out->spidx;
- spidx->dir = IPSEC_DIR_OUTBOUND;
- sin1 = (struct sockaddr_in6 *)&spidx->src;
- sin2 = (struct sockaddr_in6 *)&spidx->dst;
- sin1->sin6_len = sin2->sin6_len = sizeof(struct sockaddr_in6);
- sin1->sin6_family = sin2->sin6_family = AF_INET6;
- spidx->prefs = sizeof(struct in6_addr) << 3;
- spidx->prefd = sizeof(struct in6_addr) << 3;
- spidx->ul_proto = pcb->in6p_socket->so_proto->pr_protocol;
- sin1->sin6_port = pcb->in6p_lport;
- sin2->sin6_port = pcb->in6p_fport;
- ipsec6_setspidx_ipaddr(m, spidx);
+ nxt = -1;
+ off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
+ if (off < 0 || m->m_pkthdr.len < off)
+ return;
- return;
+ switch (nxt) {
+ case IPPROTO_TCP:
+ spidx->ul_proto = nxt;
+ if (!needport)
+ break;
+ if (off + sizeof(struct tcphdr) > m->m_pkthdr.len)
+ break;
+ m_copydata(m, off, sizeof(th), (caddr_t)&th);
+ ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport;
+ ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport;
+ break;
+ case IPPROTO_UDP:
+ spidx->ul_proto = nxt;
+ if (!needport)
+ break;
+ if (off + sizeof(struct udphdr) > m->m_pkthdr.len)
+ break;
+ m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
+ ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport;
+ ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport;
+ break;
+ case IPPROTO_ICMPV6:
+ default:
+ /* XXX intermediate headers??? */
+ spidx->ul_proto = nxt;
+ break;
+ }
}
-static void
+/* assumes that m is sane */
+static int
ipsec6_setspidx_ipaddr(m, spidx)
struct mbuf *m;
struct secpolicyindex *spidx;
@@ -1026,19 +1052,6 @@ ipsec6_setspidx_ipaddr(m, spidx)
struct ip6_hdr ip6buf;
struct sockaddr_in6 *sin6;
- /* sanity check 1 for minimum ip header length */
- if (m == NULL)
- panic("ipsec6_setspidx_in6pcb: m == 0 passed.\n");
-
- if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) {
- KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
- printf("ipsec6_setspidx_ipaddr: "
- "pkthdr.len(%d) < sizeof(struct ip6_hdr), "
- "ignored.\n",
- m->m_pkthdr.len));
- return;
- }
-
if (m->m_len >= sizeof(*ip6))
ip6 = mtod(m, struct ip6_hdr *);
else {
@@ -1046,29 +1059,29 @@ ipsec6_setspidx_ipaddr(m, spidx)
ip6 = &ip6buf;
}
- if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
- KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
- printf("ipsec_setspidx_mbuf: "
- "wrong ip version on packet "
- "(expected IPv6), ignored.\n"));
- return;
- }
-
sin6 = (struct sockaddr_in6 *)&spidx->src;
+ bzero(sin6, sizeof(*sin6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
bcopy(&ip6->ip6_src, &sin6->sin6_addr, sizeof(ip6->ip6_src));
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
sin6->sin6_addr.s6_addr16[1] = 0;
sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
}
+ spidx->prefs = sizeof(struct in6_addr) << 3;
sin6 = (struct sockaddr_in6 *)&spidx->dst;
+ bzero(sin6, sizeof(*sin6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
bcopy(&ip6->ip6_dst, &sin6->sin6_addr, sizeof(ip6->ip6_dst));
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
sin6->sin6_addr.s6_addr16[1] = 0;
sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
}
+ spidx->prefd = sizeof(struct in6_addr) << 3;
- return;
+ return 0;
}
#endif
@@ -1628,6 +1641,8 @@ ipsec_in_reject(sp, m)
need_conf = 0;
need_icv = 0;
+ /* XXX should compare policy against ipsec header history */
+
for (isr = sp->req; isr != NULL; isr = isr->next) {
/* get current level */
@@ -1653,7 +1668,8 @@ ipsec_in_reject(sp, m)
case IPPROTO_IPCOMP:
/*
* we don't really care, as IPcomp document says that
- * we shouldn't compress small packets
+ * we shouldn't compress small packets, IPComp policy
+ * should always be treated as being in "use" level.
*/
break;
}
@@ -1717,12 +1733,10 @@ ipsec4_in_reject(m, inp)
{
if (inp == NULL)
return ipsec4_in_reject_so(m, NULL);
- else {
- if (inp->inp_socket)
- return ipsec4_in_reject_so(m, inp->inp_socket);
- else
- panic("ipsec4_in_reject: invalid inpcb/socket");
- }
+ if (inp->inp_socket)
+ return ipsec4_in_reject_so(m, inp->inp_socket);
+ else
+ panic("ipsec4_in_reject: invalid inpcb/socket");
}
#ifdef INET6
@@ -1771,12 +1785,10 @@ ipsec6_in_reject(m, in6p)
{
if (in6p == NULL)
return ipsec6_in_reject_so(m, NULL);
- else {
- if (in6p->in6p_socket)
- return ipsec6_in_reject_so(m, in6p->in6p_socket);
- else
- panic("ipsec6_in_reject: invalid in6p/socket");
- }
+ if (in6p->in6p_socket)
+ return ipsec6_in_reject_so(m, in6p->in6p_socket);
+ else
+ panic("ipsec6_in_reject: invalid in6p/socket");
}
#endif
@@ -2054,6 +2066,7 @@ ipsec4_encapsulate(m, sav)
&ip->ip_src, sizeof(ip->ip_src));
bcopy(&((struct sockaddr_in *)&sav->sah->saidx.dst)->sin_addr,
&ip->ip_dst, sizeof(ip->ip_dst));
+ ip->ip_ttl = IPDEFTTL;
/* XXX Should ip_src be updated later ? */
@@ -2133,6 +2146,7 @@ ipsec6_encapsulate(m, sav)
&ip6->ip6_src, sizeof(ip6->ip6_src));
bcopy(&((struct sockaddr_in6 *)&sav->sah->saidx.dst)->sin6_addr,
&ip6->ip6_dst, sizeof(ip6->ip6_dst));
+ ip6->ip6_hlim = IPV6_DEFHLIM;
/* XXX Should ip6_src be updated later ? */
@@ -2345,11 +2359,11 @@ ipsec4_logpacketstr(ip, spi)
snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi));
while (p && *p)
p++;
- snprintf(p, sizeof(buf) - (p - buf), "src=%d.%d.%d.%d",
+ snprintf(p, sizeof(buf) - (p - buf), "src=%u.%u.%u.%u",
s[0], s[1], s[2], s[3]);
while (p && *p)
p++;
- snprintf(p, sizeof(buf) - (p - buf), " dst=%d.%d.%d.%d",
+ snprintf(p, sizeof(buf) - (p - buf), " dst=%u.%u.%u.%u",
d[0], d[1], d[2], d[3]);
while (p && *p)
p++;
@@ -2454,6 +2468,7 @@ ipsec_dumpmbuf(m)
printf("---\n");
}
+#ifdef INET
/*
* IPsec output logic for IPv4.
*/
@@ -2500,6 +2515,8 @@ ipsec4_output(state, sp, flags)
/* make SA index for search proper SA */
ip = mtod(state->m, struct ip *);
bcopy(&isr->saidx, &saidx, sizeof(saidx));
+ saidx.mode = isr->saidx.mode;
+ saidx.reqid = isr->saidx.reqid;
sin = (struct sockaddr_in *)&saidx.src;
if (sin->sin_len == 0) {
sin->sin_len = sizeof(*sin);
@@ -2595,7 +2612,7 @@ ipsec4_output(state, sp, flags)
&& ((state->ro->ro_rt->rt_flags & RTF_UP) == 0
|| dst4->sin_addr.s_addr != ip->ip_dst.s_addr)) {
RTFREE(state->ro->ro_rt);
- bzero((caddr_t)state->ro, sizeof (*state->ro));
+ state->ro->ro_rt = NULL;
}
if (state->ro->ro_rt == 0) {
dst4->sin_family = AF_INET;
@@ -2672,6 +2689,7 @@ bad:
state->m = NULL;
return error;
}
+#endif
#ifdef INET6
/*
@@ -2720,6 +2738,8 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun)
/* make SA index for search proper SA */
ip6 = mtod(state->m, struct ip6_hdr *);
bcopy(&isr->saidx, &saidx, sizeof(saidx));
+ saidx.mode = isr->saidx.mode;
+ saidx.reqid = isr->saidx.reqid;
sin6 = (struct sockaddr_in6 *)&saidx.src;
if (sin6->sin6_len == 0) {
sin6->sin6_len = sizeof(*sin6);
@@ -2757,6 +2777,18 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun)
*/
ipsec6stat.out_nosa++;
error = ENOENT;
+
+ /*
+ * Notify the fact that the packet is discarded
+ * to ourselves. I believe this is better than
+ * just silently discarding. (jinmei@kame.net)
+ * XXX: should we restrict the error to TCP packets?
+ * XXX: should we directly notify sockets via
+ * pfctlinputs?
+ */
+ icmp6_error(state->m, ICMP6_DST_UNREACH,
+ ICMP6_DST_UNREACH_ADMIN, 0);
+ state->m = NULL; /* icmp6_error freed the mbuf */
goto bad;
}
@@ -2951,7 +2983,7 @@ ipsec6_output_tunnel(state, sp, flags)
&& ((state->ro->ro_rt->rt_flags & RTF_UP) == 0
|| !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ip6->ip6_dst))) {
RTFREE(state->ro->ro_rt);
- bzero((caddr_t)state->ro, sizeof (*state->ro));
+ state->ro->ro_rt = NULL;
}
if (state->ro->ro_rt == 0) {
bzero(dst6, sizeof(*dst6));
@@ -3030,6 +3062,7 @@ bad:
}
#endif /*INET6*/
+#ifdef INET
/*
* Chop IP header and option off from the payload.
*/
@@ -3071,6 +3104,7 @@ ipsec4_splithdr(m)
}
return m;
}
+#endif
#ifdef INET6
static struct mbuf *
@@ -3111,38 +3145,89 @@ ipsec6_splithdr(m)
/* validate inbound IPsec tunnel packet. */
int
-ipsec4_tunnel_validate(ip, nxt0, sav)
- struct ip *ip;
+ipsec4_tunnel_validate(m, off, nxt0, sav)
+ struct mbuf *m; /* no pullup permitted, m->m_len >= ip */
+ int off;
u_int nxt0;
struct secasvar *sav;
{
u_int8_t nxt = nxt0 & 0xff;
struct sockaddr_in *sin;
+ struct sockaddr_in osrc, odst, isrc, idst;
int hlen;
+ struct secpolicy *sp;
+ struct ip *oip;
+#ifdef DIAGNOSTIC
+ if (m->m_len < sizeof(struct ip))
+ panic("too short mbuf on ipsec4_tunnel_validate");
+#endif
if (nxt != IPPROTO_IPV4)
return 0;
+ if (m->m_pkthdr.len < off + sizeof(struct ip))
+ return 0;
+ /* do not decapsulate if the SA is for transport mode only */
+ if (sav->sah->saidx.mode == IPSEC_MODE_TRANSPORT)
+ return 0;
+
+ oip = mtod(m, struct ip *);
#ifdef _IP_VHL
- hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
+ hlen = _IP_VHL_HL(oip->ip_vhl) << 2;
#else
- hlen = ip->ip_hl << 2;
+ hlen = oip->ip_hl << 2;
#endif
if (hlen != sizeof(struct ip))
return 0;
- switch (((struct sockaddr *)&sav->sah->saidx.dst)->sa_family) {
- case AF_INET:
- sin = (struct sockaddr_in *)&sav->sah->saidx.dst;
- if (bcmp(&ip->ip_dst, &sin->sin_addr, sizeof(ip->ip_dst)) != 0)
- return 0;
- break;
-#ifdef INET6
- case AF_INET6:
- /* should be supported, but at this moment we don't. */
- /*FALLTHROUGH*/
-#endif
- default:
+
+ /* AF_INET6 should be supported, but at this moment we don't. */
+ sin = (struct sockaddr_in *)&sav->sah->saidx.dst;
+ if (sin->sin_family != AF_INET)
return 0;
- }
+ if (bcmp(&oip->ip_dst, &sin->sin_addr, sizeof(oip->ip_dst)) != 0)
+ return 0;
+
+ /* XXX slow */
+ bzero(&osrc, sizeof(osrc));
+ bzero(&odst, sizeof(odst));
+ bzero(&isrc, sizeof(isrc));
+ bzero(&idst, sizeof(idst));
+ osrc.sin_family = odst.sin_family = isrc.sin_family = idst.sin_family =
+ AF_INET;
+ osrc.sin_len = odst.sin_len = isrc.sin_len = idst.sin_len =
+ sizeof(struct sockaddr_in);
+ osrc.sin_addr = oip->ip_src;
+ odst.sin_addr = oip->ip_dst;
+ m_copydata(m, off + offsetof(struct ip, ip_src), sizeof(isrc.sin_addr),
+ (caddr_t)&isrc.sin_addr);
+ m_copydata(m, off + offsetof(struct ip, ip_dst), sizeof(idst.sin_addr),
+ (caddr_t)&idst.sin_addr);
+
+ /*
+ * RFC2401 5.2.1 (b): (assume that we are using tunnel mode)
+ * - if the inner destination is multicast address, there can be
+ * multiple permissible inner source address. implementation
+ * may want to skip verification of inner source address against
+ * SPD selector.
+ * - if the inner protocol is ICMP, the packet may be an error report
+ * from routers on the other side of the VPN cloud (R in the
+ * following diagram). in this case, we cannot verify inner source
+ * address against SPD selector.
+ * me -- gw === gw -- R -- you
+ *
+ * we consider the first bullet to be users responsibility on SPD entry
+ * configuration (if you need to encrypt multicast traffic, set
+ * the source range of SPD selector to 0.0.0.0/0, or have explicit
+ * address ranges for possible senders).
+ * the second bullet is not taken care of (yet).
+ *
+ * therefore, we do not do anything special about inner source.
+ */
+
+ sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst,
+ (struct sockaddr *)&isrc, (struct sockaddr *)&idst);
+ if (!sp)
+ return 0;
+ key_freesp(sp);
return 1;
}
@@ -3150,28 +3235,64 @@ ipsec4_tunnel_validate(ip, nxt0, sav)
#ifdef INET6
/* validate inbound IPsec tunnel packet. */
int
-ipsec6_tunnel_validate(ip6, nxt0, sav)
- struct ip6_hdr *ip6;
+ipsec6_tunnel_validate(m, off, nxt0, sav)
+ struct mbuf *m; /* no pullup permitted, m->m_len >= ip */
+ int off;
u_int nxt0;
struct secasvar *sav;
{
u_int8_t nxt = nxt0 & 0xff;
struct sockaddr_in6 *sin6;
+ struct sockaddr_in6 osrc, odst, isrc, idst;
+ struct secpolicy *sp;
+ struct ip6_hdr *oip6;
+#ifdef DIAGNOSTIC
+ if (m->m_len < sizeof(struct ip6_hdr))
+ panic("too short mbuf on ipsec6_tunnel_validate");
+#endif
if (nxt != IPPROTO_IPV6)
return 0;
- switch (((struct sockaddr *)&sav->sah->saidx.dst)->sa_family) {
- case AF_INET6:
- sin6 = ((struct sockaddr_in6 *)&sav->sah->saidx.dst);
- if (!IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6->sin6_addr))
- return 0;
- break;
- case AF_INET:
- /* should be supported, but at this moment we don't. */
- /*FALLTHROUGH*/
- default:
+ if (m->m_pkthdr.len < off + sizeof(struct ip6_hdr))
+ return 0;
+ /* do not decapsulate if the SA is for transport mode only */
+ if (sav->sah->saidx.mode == IPSEC_MODE_TRANSPORT)
+ return 0;
+
+ oip6 = mtod(m, struct ip6_hdr *);
+ /* AF_INET should be supported, but at this moment we don't. */
+ sin6 = (struct sockaddr_in6 *)&sav->sah->saidx.dst;
+ if (sin6->sin6_family != AF_INET6)
+ return 0;
+ if (!IN6_ARE_ADDR_EQUAL(&oip6->ip6_dst, &sin6->sin6_addr))
return 0;
- }
+
+ /* XXX slow */
+ bzero(&osrc, sizeof(osrc));
+ bzero(&odst, sizeof(odst));
+ bzero(&isrc, sizeof(isrc));
+ bzero(&idst, sizeof(idst));
+ osrc.sin6_family = odst.sin6_family = isrc.sin6_family =
+ idst.sin6_family = AF_INET6;
+ osrc.sin6_len = odst.sin6_len = isrc.sin6_len = idst.sin6_len =
+ sizeof(struct sockaddr_in6);
+ osrc.sin6_addr = oip6->ip6_src;
+ odst.sin6_addr = oip6->ip6_dst;
+ m_copydata(m, off + offsetof(struct ip6_hdr, ip6_src),
+ sizeof(isrc.sin6_addr), (caddr_t)&isrc.sin6_addr);
+ m_copydata(m, off + offsetof(struct ip6_hdr, ip6_dst),
+ sizeof(idst.sin6_addr), (caddr_t)&idst.sin6_addr);
+
+ /*
+ * regarding to inner source address validation, see a long comment
+ * in ipsec4_tunnel_validate.
+ */
+
+ sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst,
+ (struct sockaddr *)&isrc, (struct sockaddr *)&idst);
+ if (!sp)
+ return 0;
+ key_freesp(sp);
return 1;
}
@@ -3235,7 +3356,7 @@ ipsec_copypkt(m)
*/
remain = n->m_len;
copied = 0;
- while(1) {
+ while (1) {
int len;
struct mbuf *mn;
@@ -3265,6 +3386,7 @@ ipsec_copypkt(m)
MGETHDR(mn, M_DONTWAIT, MT_HEADER);
if (mn == NULL)
goto fail;
+ mn->m_pkthdr.rcvif = NULL;
mm->m_next = mn;
mm = mn;
}
@@ -3288,27 +3410,78 @@ ipsec_copypkt(m)
return(NULL);
}
+static struct mbuf *
+ipsec_addaux(m)
+ struct mbuf *m;
+{
+ struct mbuf *n;
+
+ n = m_aux_find(m, AF_INET, IPPROTO_ESP);
+ if (!n)
+ n = m_aux_add(m, AF_INET, IPPROTO_ESP);
+ if (!n)
+ return n; /* ENOBUFS */
+ n->m_len = sizeof(struct socket *);
+ bzero(mtod(n, void *), n->m_len);
+ return n;
+}
+
+static struct mbuf *
+ipsec_findaux(m)
+ struct mbuf *m;
+{
+ struct mbuf *n;
+
+ n = m_aux_find(m, AF_INET, IPPROTO_ESP);
+#ifdef DIAGNOSTIC
+ if (n && n->m_len < sizeof(struct socket *))
+ panic("invalid ipsec m_aux");
+#endif
+ return n;
+}
+
void
+ipsec_delaux(m)
+ struct mbuf *m;
+{
+ struct mbuf *n;
+
+ n = m_aux_find(m, AF_INET, IPPROTO_ESP);
+ if (n)
+ m_aux_delete(m, n);
+}
+
+/* if the aux buffer is unnecessary, nuke it. */
+static void
+ipsec_optaux(m, n)
+ struct mbuf *m;
+ struct mbuf *n;
+{
+
+ if (!n)
+ return;
+ if (n->m_len == sizeof(struct socket *) && !*mtod(n, struct socket **))
+ ipsec_delaux(m);
+}
+
+int
ipsec_setsocket(m, so)
struct mbuf *m;
struct socket *so;
{
struct mbuf *n;
- n = m_aux_find(m, AF_INET, IPPROTO_ESP);
- if (so && !n)
- n = m_aux_add(m, AF_INET, IPPROTO_ESP);
- if (n) {
- if (so) {
- *mtod(n, struct socket **) = so;
- /*
- * XXX think again about it when we put decryption
- * histrory into aux mbuf
- */
- n->m_len = sizeof(struct socket *);
- } else
- m_aux_delete(m, n);
- }
+ /* if so == NULL, don't insist on getting the aux mbuf */
+ if (so) {
+ n = ipsec_addaux(m);
+ if (!n)
+ return ENOBUFS;
+ } else
+ n = ipsec_findaux(m);
+ if (n && n->m_len >= sizeof(struct socket *))
+ *mtod(n, struct socket **) = so;
+ ipsec_optaux(m, n);
+ return 0;
}
struct socket *
@@ -3317,9 +3490,66 @@ ipsec_getsocket(m)
{
struct mbuf *n;
- n = m_aux_find(m, AF_INET, IPPROTO_ESP);
+ n = ipsec_findaux(m);
if (n && n->m_len >= sizeof(struct socket *))
return *mtod(n, struct socket **);
else
return NULL;
}
+
+int
+ipsec_addhist(m, proto, spi)
+ struct mbuf *m;
+ int proto;
+ u_int32_t spi;
+{
+ struct mbuf *n;
+ struct ipsec_history *p;
+
+ n = ipsec_addaux(m);
+ if (!n)
+ return ENOBUFS;
+ if (M_TRAILINGSPACE(n) < sizeof(*p))
+ return ENOSPC; /*XXX*/
+ p = (struct ipsec_history *)(mtod(n, caddr_t) + n->m_len);
+ n->m_len += sizeof(*p);
+ bzero(p, sizeof(*p));
+ p->ih_proto = proto;
+ p->ih_spi = spi;
+ return 0;
+}
+
+struct ipsec_history *
+ipsec_gethist(m, lenp)
+ struct mbuf *m;
+ int *lenp;
+{
+ struct mbuf *n;
+ int l;
+
+ n = ipsec_findaux(m);
+ if (!n)
+ return NULL;
+ l = n->m_len;
+ if (sizeof(struct socket *) > l)
+ return NULL;
+ if ((l - sizeof(struct socket *)) % sizeof(struct ipsec_history))
+ return NULL;
+ /* XXX does it make more sense to divide by sizeof(ipsec_history)? */
+ if (lenp)
+ *lenp = l - sizeof(struct socket *);
+ return (struct ipsec_history *)
+ (mtod(n, caddr_t) + sizeof(struct socket *));
+}
+
+void
+ipsec_clearhist(m)
+ struct mbuf *m;
+{
+ struct mbuf *n;
+
+ n = ipsec_findaux(m);
+ if ((n) && n->m_len > sizeof(struct socket *))
+ n->m_len = sizeof(struct socket *);
+ ipsec_optaux(m, n);
+}
diff --git a/sys/netinet6/ipsec.h b/sys/netinet6/ipsec.h
index 80be10c..33cef87 100644
--- a/sys/netinet6/ipsec.h
+++ b/sys/netinet6/ipsec.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ipsec.h,v 1.33 2000/06/19 14:31:49 sakane Exp $ */
+/* $KAME: ipsec.h,v 1.44 2001/03/23 08:08:47 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -37,6 +37,11 @@
#ifndef _NETINET6_IPSEC_H_
#define _NETINET6_IPSEC_H_
+#if defined(_KERNEL) && !defined(_LKM) && !defined(KLD_MODULE)
+#include "opt_inet.h"
+#include "opt_ipsec.h"
+#endif
+
#include <net/pfkeyv2.h>
#include <netkey/keydb.h>
@@ -79,6 +84,18 @@ struct secpolicy {
struct ipsecrequest *req;
/* pointer to the ipsec request tree, */
/* if policy == IPSEC else this value == NULL.*/
+
+ /*
+ * lifetime handler.
+ * the policy can be used without limitiation if both lifetime and
+ * validtime are zero.
+ * "lifetime" is passed by sadb_lifetime.sadb_lifetime_addtime.
+ * "validtime" is passed by sadb_lifetime.sadb_lifetime_usetime.
+ */
+ long created; /* time created the policy */
+ long lastused; /* updated every when kernel sends a packet */
+ long lifetime; /* duration of the lifetime of this policy */
+ long validtime; /* duration this policy is valid without use */
};
/* Request for IPsec */
@@ -107,7 +124,7 @@ struct secspacq {
struct secpolicyindex spidx;
- u_int32_t tick; /* for lifetime */
+ long created; /* for lifetime */
int count; /* for lifetime */
/* XXX: here is mbuf place holder to be sent ? */
};
@@ -137,9 +154,9 @@ struct secspacq {
/* Policy level */
/*
- * IPSEC, ENTRUST and BYPASS are allowd for setsockopt() in PCB,
- * DISCARD, IPSEC and NONE are allowd for setkey() in SPD.
- * DISCARD and NONE are allowd for system default.
+ * IPSEC, ENTRUST and BYPASS are allowed for setsockopt() in PCB,
+ * DISCARD, IPSEC and NONE are allowed for setkey() in SPD.
+ * DISCARD and NONE are allowed for system default.
*/
#define IPSEC_POLICY_DISCARD 0 /* discarding packet */
#define IPSEC_POLICY_NONE 1 /* through IPsec engine */
@@ -216,7 +233,8 @@ struct ipsecstat {
#define IPSECCTL_DFBIT 10
#define IPSECCTL_ECN 11
#define IPSECCTL_DEBUG 12
-#define IPSECCTL_MAXID 13
+#define IPSECCTL_ESP_RANDPAD 13
+#define IPSECCTL_MAXID 14
#define IPSECCTL_NAMES { \
{ 0, 0 }, \
@@ -232,6 +250,7 @@ struct ipsecstat {
{ "dfbit", CTLTYPE_INT }, \
{ "ecn", CTLTYPE_INT }, \
{ "debug", CTLTYPE_INT }, \
+ { "esp_randpad", CTLTYPE_INT }, \
}
#define IPSEC6CTL_NAMES { \
@@ -248,6 +267,7 @@ struct ipsecstat {
{ 0, 0 }, \
{ "ecn", CTLTYPE_INT }, \
{ "debug", CTLTYPE_INT }, \
+ { "esp_randpad", CTLTYPE_INT }, \
}
#ifdef _KERNEL
@@ -257,6 +277,11 @@ struct ipsec_output_state {
struct sockaddr *dst;
};
+struct ipsec_history {
+ int ih_proto;
+ u_int32_t ih_spi;
+};
+
extern int ipsec_debug;
extern struct ipsecstat ipsecstat;
@@ -269,6 +294,7 @@ extern int ip4_ah_cleartos;
extern int ip4_ah_offsetmask;
extern int ip4_ipsec_dfbit;
extern int ip4_ipsec_ecn;
+extern int ip4_esp_randpad;
#define ipseclog(x) do { if (ipsec_debug) log x; } while (0)
@@ -307,10 +333,15 @@ extern void ipsec_dumpmbuf __P((struct mbuf *));
extern int ipsec4_output __P((struct ipsec_output_state *, struct secpolicy *,
int));
-extern int ipsec4_tunnel_validate __P((struct ip *, u_int, struct secasvar *));
+extern int ipsec4_tunnel_validate __P((struct mbuf *, int, u_int,
+ struct secasvar *));
extern struct mbuf *ipsec_copypkt __P((struct mbuf *));
-extern void ipsec_setsocket __P((struct mbuf *, struct socket *));
+extern void ipsec_delaux __P((struct mbuf *));
+extern int ipsec_setsocket __P((struct mbuf *, struct socket *));
extern struct socket *ipsec_getsocket __P((struct mbuf *));
+extern int ipsec_addhist __P((struct mbuf *, int, u_int32_t));
+extern struct ipsec_history *ipsec_gethist __P((struct mbuf *, int *));
+extern void ipsec_clearhist __P((struct mbuf *));
#endif /*_KERNEL*/
#ifndef _KERNEL
@@ -318,7 +349,7 @@ extern caddr_t ipsec_set_policy __P((char *, int));
extern int ipsec_get_policylen __P((caddr_t));
extern char *ipsec_dump_policy __P((caddr_t, char *));
-extern char *ipsec_strerror __P((void));
+extern const char *ipsec_strerror __P((void));
#endif /*!_KERNEL*/
#endif /*_NETINET6_IPSEC_H_*/
diff --git a/sys/netinet6/ipsec6.h b/sys/netinet6/ipsec6.h
index 383c125..e9b8a2c 100644
--- a/sys/netinet6/ipsec6.h
+++ b/sys/netinet6/ipsec6.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ipsec.h,v 1.33 2000/06/19 14:31:49 sakane Exp $ */
+/* $KAME: ipsec.h,v 1.44 2001/03/23 08:08:47 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -48,6 +48,7 @@ extern int ip6_esp_net_deflev;
extern int ip6_ah_trans_deflev;
extern int ip6_ah_net_deflev;
extern int ip6_ipsec_ecn;
+extern int ip6_esp_randpad;
extern struct secpolicy *ipsec6_getpolicybysock
__P((struct mbuf *, u_int, struct socket *, int *));
@@ -64,6 +65,8 @@ extern int ipsec6_get_policy
__P((struct inpcb *inp, caddr_t request, size_t len, struct mbuf **mp));
extern int ipsec6_in_reject __P((struct mbuf *, struct inpcb *));
+struct tcp6cb;
+
extern size_t ipsec6_hdrsiz __P((struct mbuf *, u_int, struct inpcb *));
struct ip6_hdr;
@@ -73,7 +76,7 @@ extern int ipsec6_output_trans __P((struct ipsec_output_state *, u_char *,
struct mbuf *, struct secpolicy *, int, int *));
extern int ipsec6_output_tunnel __P((struct ipsec_output_state *,
struct secpolicy *, int));
-extern int ipsec6_tunnel_validate __P((struct ip6_hdr *, u_int,
+extern int ipsec6_tunnel_validate __P((struct mbuf *, int, u_int,
struct secasvar *));
#endif /*_KERNEL*/
diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c
index 4739856..27b8480 100644
--- a/sys/netinet6/mld6.c
+++ b/sys/netinet6/mld6.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: mld6.c,v 1.19 2000/05/05 11:01:03 sumikawa Exp $ */
+/* $KAME: mld6.c,v 1.27 2001/04/04 05:17:30 itojun Exp $ */
/*
* Copyright (C) 1998 WIDE Project.
@@ -129,9 +129,8 @@ mld6_init()
hbh_buf[5] = IP6OPT_RTALERT_LEN - 2;
bcopy((caddr_t)&rtalert_code, &hbh_buf[6], sizeof(u_int16_t));
+ init_ip6pktopts(&ip6_opts);
ip6_opts.ip6po_hbh = hbh;
- /* We will specify the hoplimit by a multicast option. */
- ip6_opts.ip6po_hlim = -1;
}
void
@@ -192,31 +191,34 @@ mld6_input(m, off)
struct ifmultiaddr *ifma;
int timer; /* timer value in the MLD query header */
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, off, sizeof(*mldh),);
+ mldh = (struct mld6_hdr *)(mtod(m, caddr_t) + off);
+#else
+ IP6_EXTHDR_GET(mldh, struct mld6_hdr *, m, off, sizeof(*mldh));
+ if (mldh == NULL) {
+ icmp6stat.icp6s_tooshort++;
+ return;
+ }
+#endif
+
/* source address validation */
+ ip6 = mtod(m, struct ip6_hdr *);/* in case mpullup */
if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) {
log(LOG_ERR,
- "mld6_input: src %s is not link-local\n",
- ip6_sprintf(&ip6->ip6_src));
+ "mld6_input: src %s is not link-local (grp=%s)\n",
+ ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&mldh->mld6_addr));
/*
* spec (RFC2710) does not explicitly
* specify to discard the packet from a non link-local
* source address. But we believe it's expected to do so.
+ * XXX: do we have to allow :: as source?
*/
m_freem(m);
return;
}
-#ifndef PULLDOWN_TEST
- IP6_EXTHDR_CHECK(m, off, sizeof(*mldh),);
- mldh = (struct mld6_hdr *)(mtod(m, caddr_t) + off);
-#else
- IP6_EXTHDR_GET(mldh, struct mld6_hdr *, m, off, sizeof(*mldh));
- if (mldh == NULL) {
- icmp6stat.icp6s_tooshort++;
- return;
- }
-#endif
-
/*
* In the MLD6 specification, there are 3 states and a flag.
*
@@ -234,7 +236,7 @@ mld6_input(m, off)
break;
if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld6_addr) &&
- !IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr))
+ !IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr))
break; /* print error or log stat? */
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr))
mldh->mld6_addr.s6_addr16[1] =
@@ -343,7 +345,7 @@ mld6_input(m, off)
void
mld6_fasttimeo()
{
- register struct in6_multi *in6m;
+ struct in6_multi *in6m;
struct in6_multistep step;
int s;
@@ -408,6 +410,7 @@ mld6_sendpkt(in6m, type, dst)
}
mh->m_next = md;
+ mh->m_pkthdr.rcvif = NULL;
mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld6_hdr);
mh->m_len = sizeof(struct ip6_hdr);
MH_ALIGN(mh, sizeof(struct ip6_hdr));
@@ -455,16 +458,16 @@ mld6_sendpkt(in6m, type, dst)
ip6_output(mh, &ip6_opts, NULL, 0, &im6o, &outif);
if (outif) {
icmp6_ifstat_inc(outif, ifs6_out_msg);
- switch(type) {
- case MLD6_LISTENER_QUERY:
- icmp6_ifstat_inc(outif, ifs6_out_mldquery);
- break;
- case MLD6_LISTENER_REPORT:
- icmp6_ifstat_inc(outif, ifs6_out_mldreport);
- break;
- case MLD6_LISTENER_DONE:
- icmp6_ifstat_inc(outif, ifs6_out_mlddone);
- break;
+ switch (type) {
+ case MLD6_LISTENER_QUERY:
+ icmp6_ifstat_inc(outif, ifs6_out_mldquery);
+ break;
+ case MLD6_LISTENER_REPORT:
+ icmp6_ifstat_inc(outif, ifs6_out_mldreport);
+ break;
+ case MLD6_LISTENER_DONE:
+ icmp6_ifstat_inc(outif, ifs6_out_mlddone);
+ break;
}
}
}
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index 833e902..270550b 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: nd6.c,v 1.68 2000/07/02 14:48:02 itojun Exp $ */
+/* $KAME: nd6.c,v 1.144 2001/05/24 07:44:00 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -43,6 +43,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/callout.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
@@ -53,6 +54,7 @@
#include <sys/errno.h>
#include <sys/syslog.h>
#include <sys/queue.h>
+#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
@@ -84,12 +86,19 @@ 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 */
+#ifdef ND6_DEBUG
+int nd6_debug = 1;
+#else
+int nd6_debug = 0;
+#endif
+
/* for debugging? */
static int nd6_inuse, nd6_allocated;
@@ -103,6 +112,11 @@ int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL;
static struct sockaddr_in6 all1_sa;
static void nd6_slowtimo __P((void *));
+static int regen_tmpaddr __P((struct in6_ifaddr *));
+
+struct callout nd6_slowtimo_ch;
+struct callout nd6_timer_ch;
+extern struct callout in6_tmpaddrtimer_ch;
void
nd6_init()
@@ -126,7 +140,8 @@ nd6_init()
nd6_init_done = 1;
/* start timer */
- timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz);
+ callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz,
+ nd6_slowtimo, NULL);
}
void
@@ -192,22 +207,30 @@ nd6_setmtu(ifp)
u_long oldmaxmtu = ndi->maxmtu;
u_long oldlinkmtu = ndi->linkmtu;
- 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_FDDI:
- ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu);
- break;
- case IFT_ATM:
- ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu);
- break;
- default:
- ndi->maxmtu = ifp->if_mtu;
- break;
+ 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_FDDI:
+ ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu);
+ break;
+ case IFT_ATM:
+ ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu);
+ break;
+ case IFT_IEEE1394: /* XXX should be IEEE1394MTU(1500) */
+ ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu);
+ break;
+#ifdef IFT_IEEE80211
+ case IFT_IEEE80211: /* XXX should be IEEE80211MTU(1500) */
+ ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu);
+ break;
+#endif
+ default:
+ ndi->maxmtu = ifp->if_mtu;
+ break;
}
if (oldmaxmtu != ndi->maxmtu) {
@@ -329,6 +352,7 @@ nd6_options(ndopts)
* 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;
}
@@ -342,8 +366,9 @@ nd6_options(ndopts)
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);
+ 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]
@@ -363,16 +388,16 @@ nd6_options(ndopts)
* Unknown options must be silently ignored,
* to accomodate future extension to the protocol.
*/
- log(LOG_DEBUG,
+ nd6log((LOG_DEBUG,
"nd6_options: unsupported option %d - "
- "option ignored\n", nd_opt->nd_opt_type);
+ "option ignored\n", nd_opt->nd_opt_type));
}
skip1:
i++;
if (i > nd6_maxndopt) {
icmp6stat.icp6s_nd_toomanyopt++;
- printf("too many loop in nd opt\n");
+ nd6log((LOG_INFO, "too many loop in nd opt\n"));
break;
}
@@ -391,18 +416,21 @@ nd6_timer(ignored_arg)
void *ignored_arg;
{
int s;
- register struct llinfo_nd6 *ln;
- register struct nd_defrouter *dr;
- register struct nd_prefix *pr;
+ struct llinfo_nd6 *ln;
+ struct nd_defrouter *dr;
+ struct nd_prefix *pr;
+ struct ifnet *ifp;
+ struct in6_ifaddr *ia6, *nia6;
+ struct in6_addrlifetime *lt6;
s = splnet();
- timeout(nd6_timer, (caddr_t)0, nd6_prune * hz);
+ callout_reset(&nd6_timer_ch, nd6_prune * hz,
+ nd6_timer, NULL);
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;
/* XXX: used for the DELAY case only: */
@@ -458,17 +486,22 @@ nd6_timer(ignored_arg)
ICMP6_DST_UNREACH_ADDR, 0);
ln->ln_hold = NULL;
}
- nd6_free(rt);
+ next = nd6_free(rt);
}
break;
case ND6_LLINFO_REACHABLE:
- if (ln->ln_expire)
+ if (ln->ln_expire) {
ln->ln_state = ND6_LLINFO_STALE;
+ ln->ln_expire = time_second + nd6_gctimer;
+ }
break;
- /*
- * ND6_LLINFO_STALE state requires nothing for timer
- * routine.
- */
+
+ case ND6_LLINFO_STALE:
+ /* Garbage Collection(RFC 2461 5.3) */
+ if (ln->ln_expire)
+ next = nd6_free(rt);
+ break;
+
case ND6_LLINFO_DELAY:
if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) {
/* We need NUD */
@@ -479,8 +512,10 @@ nd6_timer(ignored_arg)
nd6_ns_output(ifp, &dst->sin6_addr,
&dst->sin6_addr,
ln, 0);
- } else
+ } else {
ln->ln_state = ND6_LLINFO_STALE; /* XXX */
+ ln->ln_expire = time_second + nd6_gctimer;
+ }
break;
case ND6_LLINFO_PROBE:
if (ln->ln_asked < nd6_umaxtries) {
@@ -490,17 +525,14 @@ nd6_timer(ignored_arg)
nd6_ns_output(ifp, &dst->sin6_addr,
&dst->sin6_addr, ln, 0);
} else {
- nd6_free(rt);
+ next = nd6_free(rt);
}
break;
- case ND6_LLINFO_WAITDELETE:
- nd6_free(rt);
- break;
}
ln = next;
}
- /* expire */
+ /* expire default router list */
dr = TAILQ_FIRST(&nd_defrouter);
while (dr) {
if (dr->expire && dr->expire < time_second) {
@@ -512,28 +544,82 @@ nd6_timer(ignored_arg)
dr = TAILQ_NEXT(dr, dr_entry);
}
}
- 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 */
+ /*
+ * 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 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 an addition, but a
+ * deletion,) we'd rather restart the
+ * loop just for safety. Or does this
+ * significantly reduce performance??
+ */
+ goto addrloop;
+ }
+ }
+ } else if (IFA6_IS_DEPRECATED(ia6)) {
+ /*
+ * A new RA might have made a deprecated address
+ * preferred.
+ */
+ ia6->ia6_flags &= ~IN6_IFF_DEPRECATED;
}
+ }
+ /* expire prefix list */
+ pr = nd_prefix.lh_first;
+ while (pr) {
/*
* check prefix lifetime.
* since pltime is just for autoconf, pltime processing for
@@ -543,15 +629,17 @@ nd6_timer(ignored_arg)
* can use the old prefix information to validate the
* next prefix information to come. See prelist_update()
* for actual validation.
+ *
+ * I don't think such an offset is necessary.
+ * (jinmei@kame.net, 20010130).
*/
- if (pr->ndpr_expire
- && pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) {
+ if (pr->ndpr_expire && pr->ndpr_expire < time_second) {
struct nd_prefix *t;
t = pr->ndpr_next;
/*
* address expiration and prefix expiration are
- * separate. NEVER perform in6_ifdel here.
+ * separate. NEVER perform in6_purgeaddr here.
*/
prelist_remove(pr);
@@ -562,6 +650,70 @@ nd6_timer(ignored_arg)
splx(s);
}
+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;
+
+ if ((e = in6_tmpifadd(public_ifa6, 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.
@@ -594,8 +746,14 @@ nd6_purge(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);
+ /*
+ * 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);
}
}
@@ -626,30 +784,7 @@ nd6_purge(ifp)
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);
- }
+ nln = nd6_free(rt);
}
ln = nln;
}
@@ -757,7 +892,7 @@ nd6_is_addr_neighbor(addr, ifp)
struct sockaddr_in6 *addr;
struct ifnet *ifp;
{
- register struct ifaddr *ifa;
+ struct ifaddr *ifa;
int i;
#define IFADDR6(a) ((((struct in6_ifaddr *)(a))->ia_addr).sin6_addr)
@@ -807,26 +942,25 @@ nd6_is_addr_neighbor(addr, ifp)
/*
* Free an nd6 llinfo entry.
*/
-void
+struct llinfo_nd6 *
nd6_free(rt)
struct rtentry *rt;
{
- struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo;
- struct sockaddr_dl *sdl;
+ struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next;
struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr;
struct nd_defrouter *dr;
/*
- * Clear all destination cache entries for the neighbor.
- * XXX: is it better to restrict this to hosts?
+ * we used to have pfctlinput(PRC_HOSTDEAD) here.
+ * even though it is not harmful, it was not really necessary.
*/
- pfctlinput(PRC_HOSTDEAD, rt_key(rt));
if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */
int s;
s = splnet();
dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
rt->rt_ifp);
+
if (ln->ln_router || dr) {
/*
* rt6_flush must be called whether or not the neighbor
@@ -852,6 +986,14 @@ nd6_free(rt)
*/
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();
+
if (dr == TAILQ_FIRST(&nd_defrouter)) {
/*
* It is used as the current default router,
@@ -865,22 +1007,27 @@ nd6_free(rt)
defrouter_select();
}
- pfxlist_onlink_check();
}
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;
- }
+ /*
+ * 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_key(rt), (struct sockaddr *)0,
rt_mask(rt), 0, (struct rtentry **)0);
+
+ return(next);
}
/*
@@ -935,103 +1082,6 @@ nd6_nud_hint(rt, dst6, force)
nd_ifinfo[rt->rt_ifp->if_index].reachable;
}
-#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;
-
- 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;
- case IFT_ARCNET:
- *desten = 0;
- return(1);
- break;
- 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_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);
- }
- }
- /* Do not free mbuf chain here as it is queued in llinfo_nd6 */
- return(0);
-}
-#endif /* OLDIP6OUTPUT */
-
void
nd6_rtrequest(req, rt, sa)
int req;
@@ -1047,6 +1097,17 @@ nd6_rtrequest(req, rt, sa)
if (rt->rt_flags & RTF_GATEWAY)
return;
+ 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;
+ }
+
switch (req) {
case RTM_ADD:
/*
@@ -1072,7 +1133,7 @@ nd6_rtrequest(req, rt, sa)
ln->ln_expire = time_second;
#if 1
if (ln && ln->ln_expire == 0) {
- /* cludge for desktops */
+ /* kludge for desktops */
#if 0
printf("nd6_request: time.tv_sec is zero; "
"treat it as 1\n");
@@ -1093,10 +1154,10 @@ nd6_rtrequest(req, rt, sa)
* (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
+ * note that the mechanism needs 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.
+ * 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)
@@ -1112,7 +1173,7 @@ nd6_rtrequest(req, rt, sa)
#endif
/* FALLTHROUGH */
case RTM_RESOLVE:
- if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
+ if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) {
/*
* Address resolution isn't necessary for a point to
* point link, so we can skip this test for a p2p link.
@@ -1120,7 +1181,8 @@ nd6_rtrequest(req, rt, sa)
if (gate->sa_family != AF_LINK ||
gate->sa_len < sizeof(null_sdl)) {
log(LOG_DEBUG,
- "nd6_rtrequest: bad gateway value\n");
+ "nd6_rtrequest: bad gateway value: %s\n",
+ if_name(ifp));
break;
}
SDL(gate)->sdl_type = ifp->if_type;
@@ -1192,7 +1254,7 @@ nd6_rtrequest(req, rt, sa)
*/
if (ifa != rt->rt_ifa) {
IFAFREE(rt->rt_ifa);
- ifa->ifa_refcnt++;
+ IFAREF(ifa);
rt->rt_ifa = ifa;
}
}
@@ -1213,10 +1275,11 @@ nd6_rtrequest(req, rt, sa)
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);
+ if (!in6_addmulti(&llsol, ifp, &error)) {
+ nd6log((LOG_ERR, "%s: failed to join "
+ "%s (errno=%d)\n", if_name(ifp),
+ ip6_sprintf(&llsol), error));
+ }
}
}
break;
@@ -1253,65 +1316,6 @@ nd6_rtrequest(req, rt, sa)
}
}
-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 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;
- }
-}
-
int
nd6_ioctl(cmd, data, ifp)
u_long cmd;
@@ -1331,6 +1335,9 @@ nd6_ioctl(cmd, data, ifp)
switch (cmd) {
case SIOCGDRLST_IN6:
+ /*
+ * obsolete API, use sysctl under net.inet6.icmp6
+ */
bzero(drl, sizeof(*drl));
s = splnet();
dr = TAILQ_FIRST(&nd_defrouter);
@@ -1356,6 +1363,9 @@ nd6_ioctl(cmd, data, ifp)
break;
case SIOCGPRLST_IN6:
/*
+ * obsolete API, use sysctl under net.inet6.icmp6
+ */
+ /*
* XXX meaning of fields, especialy "raflags", is very
* differnet between RA prefix list and RR/static prefix list.
* how about separating ioctls into two?
@@ -1367,7 +1377,8 @@ nd6_ioctl(cmd, data, ifp)
struct nd_pfxrouter *pfr;
int j;
- prl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr;
+ (void)in6_embedscope(&prl->prefix[i].prefix,
+ &pr->ndpr_prefix, NULL, NULL);
prl->prefix[i].raflags = pr->ndpr_raf;
prl->prefix[i].prefixlen = pr->ndpr_plen;
prl->prefix[i].vltime = pr->ndpr_vltime;
@@ -1377,7 +1388,7 @@ nd6_ioctl(cmd, data, ifp)
pfr = pr->ndpr_advrtrs.lh_first;
j = 0;
- while(pfr) {
+ while (pfr) {
if (j < DRLSTSIZ) {
#define RTRADDR prl->prefix[i].advrtr[j]
RTRADDR = pfr->router->rtaddr;
@@ -1408,7 +1419,8 @@ nd6_ioctl(cmd, data, ifp)
rpp = LIST_NEXT(rpp, rp_entry)) {
if (i >= PRLSTSIZ)
break;
- prl->prefix[i].prefix = rpp->rp_prefix.sin6_addr;
+ (void)in6_embedscope(&prl->prefix[i].prefix,
+ &pr->ndpr_prefix, NULL, NULL);
prl->prefix[i].raflags = rpp->rp_raf;
prl->prefix[i].prefixlen = rpp->rp_plen;
prl->prefix[i].vltime = rpp->rp_vltime;
@@ -1423,6 +1435,22 @@ nd6_ioctl(cmd, data, ifp)
splx(s);
break;
+ case OSIOCGIFINFO_IN6:
+ if (!nd_ifinfo || i >= nd_ifinfo_indexlim) {
+ error = EINVAL;
+ break;
+ }
+ ndi->ndi.linkmtu = nd_ifinfo[ifp->if_index].linkmtu;
+ ndi->ndi.maxmtu = nd_ifinfo[ifp->if_index].maxmtu;
+ ndi->ndi.basereachable =
+ nd_ifinfo[ifp->if_index].basereachable;
+ ndi->ndi.reachable = nd_ifinfo[ifp->if_index].reachable;
+ ndi->ndi.retrans = nd_ifinfo[ifp->if_index].retrans;
+ ndi->ndi.flags = nd_ifinfo[ifp->if_index].flags;
+ ndi->ndi.recalctm = nd_ifinfo[ifp->if_index].recalctm;
+ ndi->ndi.chlim = nd_ifinfo[ifp->if_index].chlim;
+ ndi->ndi.receivedra = nd_ifinfo[ifp->if_index].receivedra;
+ break;
case SIOCGIFINFO_IN6:
if (!nd_ifinfo || i >= nd_ifinfo_indexlim) {
error = EINVAL;
@@ -1456,9 +1484,24 @@ nd6_ioctl(cmd, data, ifp)
s = splnet();
for (pr = nd_prefix.lh_first; pr; pr = next) {
+ struct in6_ifaddr *ia, *ia_next;
+
next = pr->ndpr_next;
- if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
- in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr);
+
+ 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);
+ }
prelist_remove(pr);
}
splx(s);
@@ -1577,14 +1620,18 @@ nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code)
rt = nd6_lookup(from, 1, ifp);
is_newentry = 1;
- } else
+ } else {
+ /* do nothing if static ndp is set */
+ if (rt->rt_flags & RTF_STATIC)
+ return NULL;
is_newentry = 0;
+ }
if (!rt)
return NULL;
if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) {
fail:
- nd6_free(rt);
+ (void)nd6_free(rt);
return NULL;
}
ln = (struct llinfo_nd6 *)rt->rt_llinfo;
@@ -1647,12 +1694,15 @@ fail:
ln->ln_state = newstate;
if (ln->ln_state == ND6_LLINFO_STALE) {
- rt->rt_flags &= ~RTF_REJECT;
+ /*
+ * 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;
+
if (ln->ln_hold) {
-#ifdef OLDIP6OUTPUT
- (*ifp->if_output)(ifp, ln->ln_hold,
- rt_key(rt), rt);
-#else
/*
* we assume ifp is not a p2p here, so just
* set the 2nd argument as the 1st one.
@@ -1660,8 +1710,7 @@ fail:
nd6_output(ifp, ifp, ln->ln_hold,
(struct sockaddr_in6 *)rt_key(rt),
rt);
-#endif
- ln->ln_hold = 0;
+ ln->ln_hold = NULL;
}
} else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
/* probe right away */
@@ -1742,10 +1791,11 @@ nd6_slowtimo(ignored_arg)
void *ignored_arg;
{
int s = splnet();
- register int i;
- register struct nd_ifinfo *nd6if;
+ int i;
+ struct nd_ifinfo *nd6if;
- timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz);
+ callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz,
+ nd6_slowtimo, NULL);
for (i = 1; i < if_index + 1; i++) {
if (!nd_ifinfo || i >= nd_ifinfo_indexlim)
continue;
@@ -1768,14 +1818,14 @@ nd6_slowtimo(ignored_arg)
#define senderr(e) { error = (e); goto bad;}
int
nd6_output(ifp, origifp, m0, dst, rt0)
- register struct ifnet *ifp;
+ struct ifnet *ifp;
struct ifnet *origifp;
struct mbuf *m0;
struct sockaddr_in6 *dst;
struct rtentry *rt0;
{
- register struct mbuf *m = m0;
- register struct rtentry *rt = rt0;
+ struct mbuf *m = m0;
+ struct rtentry *rt = rt0;
struct sockaddr_in6 *gw6 = NULL;
struct llinfo_nd6 *ln = NULL;
int error = 0;
@@ -1783,22 +1833,8 @@ nd6_output(ifp, origifp, m0, dst, rt0)
if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
goto sendpkt;
- /*
- * XXX: we currently do not make neighbor cache on any interface
- * other than ARCnet, Ethernet, FDDI and GIF.
- *
- * draft-ietf-ngtrans-mech-06.txt says:
- * - unidirectional tunnels needs no ND
- */
- switch (ifp->if_type) {
- case IFT_ARCNET:
- case IFT_ETHER:
- case IFT_FDDI:
- case IFT_GIF: /* XXX need more cases? */
- break;
- default:
+ if (nd6_need_cache(ifp) == 0)
goto sendpkt;
- }
/*
* next hop determination. This routine is derived from ether_outpout.
@@ -1824,7 +1860,7 @@ nd6_output(ifp, origifp, m0, dst, rt0)
/*
* 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
+ * of view, regardless the value of the
* nd_ifinfo.flags.
* The second condition is a bit tricky: we skip
* if the gateway is our own address, which is
@@ -1832,9 +1868,6 @@ nd6_output(ifp, origifp, m0, dst, rt0)
*/
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.
@@ -1855,8 +1888,6 @@ nd6_output(ifp, origifp, m0, dst, rt0)
senderr(EHOSTUNREACH);
}
}
- if (rt->rt_flags & RTF_REJECT)
- senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
}
/*
@@ -1894,8 +1925,10 @@ nd6_output(ifp, origifp, m0, dst, rt0)
/* 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_REACHABLE) {
ln->ln_state = ND6_LLINFO_STALE;
+ ln->ln_expire = time_second + nd6_gctimer;
+ }
/*
* The first time we send a packet to a neighbor whose entry is
@@ -1926,14 +1959,12 @@ nd6_output(ifp, origifp, m0, dst, rt0)
* 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)
+ 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) {
- rt->rt_flags &= ~RTF_REJECT;
if (ln->ln_asked < nd6_mmaxtries &&
ln->ln_expire < time_second) {
ln->ln_asked++;
@@ -1946,12 +1977,10 @@ nd6_output(ifp, origifp, m0, dst, rt0)
sendpkt:
-#ifdef FAKE_LOOPBACK_IF
- if (ifp->if_flags & IFF_LOOPBACK) {
+ if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
return((*ifp->if_output)(origifp, m, (struct sockaddr *)dst,
rt));
}
-#endif
return((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt));
bad:
@@ -1962,6 +1991,32 @@ nd6_output(ifp, origifp, m0, dst, rt0)
#undef senderr
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:
+#ifdef IFT_IEEE80211
+ case IFT_IEEE80211:
+#endif
+ case IFT_GIF: /* XXX need more cases? */
+ return(1);
+ default:
+ return(0);
+ }
+}
+
+int
nd6_storelladdr(ifp, rt, m, dst, desten)
struct ifnet *ifp;
struct rtentry *rt;
@@ -1969,16 +2024,23 @@ nd6_storelladdr(ifp, rt, m, dst, desten)
struct sockaddr *dst;
u_char *desten;
{
+ int i;
struct sockaddr_dl *sdl;
if (m->m_flags & M_MCAST) {
switch (ifp->if_type) {
case IFT_ETHER:
- case IFT_FDDI:
+ case IFT_FDDI:
+#ifdef IFT_IEEE80211
+ case IFT_IEEE80211:
+#endif
ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr,
desten);
return(1);
- break;
+ case IFT_IEEE1394:
+ for (i = 0; i < ifp->if_addrlen; i++)
+ desten[i] = ~0;
+ return(1);
case IFT_ARCNET:
*desten = 0;
return(1);
@@ -1989,12 +2051,12 @@ nd6_storelladdr(ifp, rt, m, dst, desten)
}
if (rt == NULL) {
- /* This could happen if we could not allocate memory */
+ /* this could happen, if we could not allocate memory */
m_freem(m);
return(0);
}
if (rt->rt_gateway->sa_family != AF_LINK) {
- printf("nd6_storelladdr: something odd happened\n");
+ printf("nd6_storelladdr: something odd happens\n");
m_freem(m);
return(0);
}
@@ -2009,3 +2071,129 @@ nd6_storelladdr(ifp, rt, m, dst, desten)
bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
return(1);
}
+
+static int nd6_sysctl_drlist(SYSCTL_HANDLER_ARGS);
+static int nd6_sysctl_prlist(SYSCTL_HANDLER_ARGS);
+#ifdef SYSCTL_DECL
+SYSCTL_DECL(_net_inet6_icmp6);
+#endif
+SYSCTL_NODE(_net_inet6_icmp6, ICMPV6CTL_ND6_DRLIST, nd6_drlist,
+ CTLFLAG_RD, nd6_sysctl_drlist, "");
+SYSCTL_NODE(_net_inet6_icmp6, ICMPV6CTL_ND6_PRLIST, nd6_prlist,
+ CTLFLAG_RD, nd6_sysctl_prlist, "");
+
+static int
+nd6_sysctl_drlist(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+ char buf[1024];
+ struct in6_defrouter *d, *de;
+ struct nd_defrouter *dr;
+
+ if (req->newptr)
+ return EPERM;
+ error = 0;
+
+ for (dr = TAILQ_FIRST(&nd_defrouter);
+ dr;
+ dr = TAILQ_NEXT(dr, dr_entry)) {
+ d = (struct in6_defrouter *)buf;
+ de = (struct in6_defrouter *)(buf + sizeof(buf));
+
+ if (d + 1 <= de) {
+ bzero(d, sizeof(*d));
+ d->rtaddr.sin6_family = AF_INET6;
+ d->rtaddr.sin6_len = sizeof(d->rtaddr);
+ if (in6_recoverscope(&d->rtaddr, &dr->rtaddr,
+ dr->ifp) != 0)
+ log(LOG_ERR,
+ "scope error in "
+ "default router list (%s)\n",
+ ip6_sprintf(&dr->rtaddr));
+ d->flags = dr->flags;
+ d->rtlifetime = dr->rtlifetime;
+ d->expire = dr->expire;
+ d->if_index = dr->ifp->if_index;
+ } else
+ panic("buffer too short");
+
+ error = SYSCTL_OUT(req, buf, sizeof(*d));
+ if (error)
+ break;
+ }
+ return error;
+}
+
+static int
+nd6_sysctl_prlist(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+ char buf[1024];
+ struct in6_prefix *p, *pe;
+ struct nd_prefix *pr;
+
+ if (req->newptr)
+ return EPERM;
+ error = 0;
+
+ for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
+ u_short advrtrs;
+ size_t advance;
+ struct sockaddr_in6 *sin6, *s6;
+ struct nd_pfxrouter *pfr;
+
+ p = (struct in6_prefix *)buf;
+ pe = (struct in6_prefix *)(buf + sizeof(buf));
+
+ if (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;
+ p->expire = pr->ndpr_expire;
+ 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];
+ bzero(s6, sizeof(*s6));
+ s6->sin6_family = AF_INET6;
+ s6->sin6_len = sizeof(*sin6);
+ if (in6_recoverscope(s6,
+ &pfr->router->rtaddr,
+ pfr->router->ifp) != 0)
+ log(LOG_ERR,
+ "scope error in "
+ "prefix list (%s)\n",
+ ip6_sprintf(&pfr->router->rtaddr));
+ advrtrs++;
+ }
+ p->advrtrs = advrtrs;
+ } else
+ panic("buffer too short");
+
+ advance = sizeof(*p) + sizeof(*sin6) * advrtrs;
+ error = SYSCTL_OUT(req, buf, advance);
+ if (error)
+ break;
+ }
+ return error;
+}
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index 26f58b5..73bbcd5 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: nd6.h,v 1.23 2000/06/04 12:54:57 itojun Exp $ */
+/* $KAME: nd6.h,v 1.55 2001/04/27 15:09:49 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -39,6 +39,7 @@
#endif
#include <sys/queue.h>
+#include <sys/callout.h>
struct llinfo_nd6 {
struct llinfo_nd6 *ln_next;
@@ -53,7 +54,14 @@ struct llinfo_nd6 {
};
#define ND6_LLINFO_NOSTATE -2
-#define ND6_LLINFO_WAITDELETE -1
+/*
+ * We don't need the WAITDELETE state any more, but we keep the definition
+ * in a comment line instead of removing it. This is necessary to avoid
+ * unintentionally reusing the value for another purpose, which might
+ * affect backward compatibility with old applications.
+ * (20000711 jinmei@kame.net)
+ */
+/* #define ND6_LLINFO_WAITDELETE -1 */
#define ND6_LLINFO_INCOMPLETE 0
#define ND6_LLINFO_REACHABLE 1
#define ND6_LLINFO_STALE 2
@@ -72,6 +80,10 @@ struct nd_ifinfo {
int recalctm; /* BaseReacable re-calculation timer */
u_int8_t chlim; /* CurHopLimit */
u_int8_t receivedra;
+ /* the followings are for privacy extension for addrconf */
+ u_int8_t randomseed0[8]; /* upper 64 bits of MD5 digest */
+ u_int8_t randomseed1[8]; /* lower 64 bits (usually the EUI64 IFID) */
+ u_int8_t randomid[8]; /* current random ID */
};
#define ND6_IFF_PERFORMNUD 0x1
@@ -98,6 +110,14 @@ struct in6_drlist {
} defrouter[DRLSTSIZ];
};
+struct in6_defrouter {
+ struct sockaddr_in6 rtaddr;
+ u_char flags;
+ u_short rtlifetime;
+ u_long expire;
+ u_short if_index;
+} __attribute__((__packed__));
+
struct in6_prlist {
char ifname[IFNAMSIZ];
struct {
@@ -114,6 +134,38 @@ struct in6_prlist {
} prefix[PRLSTSIZ];
};
+struct in6_prefix {
+ struct sockaddr_in6 prefix;
+ struct prf_ra raflags;
+ u_char prefixlen;
+ u_char origin;
+ u_long vltime;
+ u_long pltime;
+ u_long expire;
+ u_int32_t flags;
+ int refcnt;
+ u_short if_index;
+ u_short advrtrs; /* number of advertisement routers */
+ /* struct sockaddr_in6 advrtr[] */
+} __attribute__((__packed__));
+
+#ifdef _KERNEL
+struct in6_ondireq {
+ char ifname[IFNAMSIZ];
+ struct {
+ u_int32_t linkmtu; /* LinkMTU */
+ u_int32_t maxmtu; /* Upper bound of LinkMTU */
+ u_int32_t basereachable; /* BaseReachableTime */
+ u_int32_t reachable; /* Reachable Time */
+ u_int32_t retrans; /* Retrans Timer */
+ u_int32_t flags; /* Flags */
+ int recalctm; /* BaseReacable re-calculation timer */
+ u_int8_t chlim; /* CurHopLimit */
+ u_int8_t receivedra;
+ } ndi;
+};
+#endif
+
struct in6_ndireq {
char ifname[IFNAMSIZ];
struct nd_ifinfo ndi;
@@ -124,6 +176,9 @@ struct in6_ndifreq {
u_long ifindex;
};
+/* Prefix status */
+#define NDPRF_ONLINK 0x1
+#define NDPRF_DETACHED 0x2
/* protocol constants */
#define MAX_RTR_SOLICITATION_DELAY 1 /*1sec*/
@@ -139,6 +194,10 @@ struct in6_ndifreq {
#define RETRANS_TIMER 1000 /* msec */
#define MIN_RANDOM_FACTOR 512 /* 1024 * 0.5 */
#define MAX_RANDOM_FACTOR 1536 /* 1024 * 1.5 */
+#define DEF_TEMP_VALID_LIFETIME 604800 /* 1 week */
+#define DEF_TEMP_PREFERRED_LIFETIME 86400 /* 1 day */
+#define TEMPADDR_REGEN_ADVANCE 5 /* sec */
+#define MAX_TEMP_DESYNC_FACTOR 600 /* 10 min */
#define ND_COMPUTE_RTIME(x) \
(((MIN_RANDOM_FACTOR * (x >> 10)) + (random() & \
((MAX_RANDOM_FACTOR - MIN_RANDOM_FACTOR) * (x >> 10)))) /1000)
@@ -167,13 +226,11 @@ struct nd_prefix {
time_t ndpr_expire; /* expiration time of the prefix */
time_t ndpr_preferred; /* preferred time of the prefix */
struct prf_ra ndpr_flags;
+ u_int32_t ndpr_stateflags; /* actual state flags */
/* list of routers that advertise the prefix: */
LIST_HEAD(pr_rtrhead, nd_pfxrouter) ndpr_advrtrs;
u_char ndpr_plen;
- struct ndpr_stateflags {
- /* if this prefix can be regarded as on-link */
- u_char onlink : 1;
- } ndpr_stateflags;
+ int ndpr_refcnt; /* reference couter from addresses */
};
#define ndpr_next ndpr_entry.le_next
@@ -182,9 +239,6 @@ struct nd_prefix {
#define ndpr_raf_onlink ndpr_flags.onlink
#define ndpr_raf_auto ndpr_flags.autonomous
-#define ndpr_statef_onlink ndpr_stateflags.onlink
-#define ndpr_statef_addmark ndpr_stateflags.addmark
-
/*
* We keep expired prefix for certain amount of time, for validation purposes.
* 1800s = MaxRtrAdvInterval
@@ -235,13 +289,23 @@ extern int nd6_umaxtries;
extern int nd6_mmaxtries;
extern int nd6_useloopback;
extern int nd6_maxnudhint;
+extern int nd6_gctimer;
extern struct llinfo_nd6 llinfo_nd6;
extern struct nd_ifinfo *nd_ifinfo;
extern struct nd_drhead nd_defrouter;
extern struct nd_prhead nd_prefix;
+extern int nd6_debug;
+
+#define nd6log(x) do { if (nd6_debug) log x; } while (0)
+
+extern struct callout nd6_timer_ch;
/* nd6_rtr.c */
extern int nd6_defifindex;
+extern int ip6_desync_factor; /* seconds */
+extern u_int32_t ip6_temp_preferred_lifetime; /* seconds */
+extern u_int32_t ip6_temp_valid_lifetime; /* seconds */
+extern int ip6_temp_regen_advance; /* seconds */
union nd_opts {
struct nd_opt_hdr *nd_opt_array[9]; /*max = home agent info*/
@@ -285,30 +349,30 @@ struct rtentry *nd6_lookup __P((struct in6_addr *, int, struct ifnet *));
void nd6_setmtu __P((struct ifnet *));
void nd6_timer __P((void *));
void nd6_purge __P((struct ifnet *));
-void nd6_free __P((struct rtentry *));
+struct llinfo_nd6 *nd6_free __P((struct rtentry *));
void nd6_nud_hint __P((struct rtentry *, struct in6_addr *, int));
int nd6_resolve __P((struct ifnet *, struct rtentry *,
struct mbuf *, struct sockaddr *, u_char *));
void nd6_rtrequest __P((int, struct rtentry *, struct sockaddr *));
-void nd6_p2p_rtrequest __P((int, struct rtentry *, struct sockaddr *));
int nd6_ioctl __P((u_long, caddr_t, struct ifnet *));
struct rtentry *nd6_cache_lladdr __P((struct ifnet *, struct in6_addr *,
char *, int, int, int));
-/* for test */
int nd6_output __P((struct ifnet *, struct ifnet *, struct mbuf *,
struct sockaddr_in6 *, struct rtentry *));
int nd6_storelladdr __P((struct ifnet *, struct rtentry *, struct mbuf *,
struct sockaddr *, u_char *));
+int nd6_need_cache __P((struct ifnet *));
/* nd6_nbr.c */
void nd6_na_input __P((struct mbuf *, int, int));
-void nd6_na_output __P((struct ifnet *, struct in6_addr *,
- struct in6_addr *, u_long, int, struct sockaddr *));
+void nd6_na_output __P((struct ifnet *, const struct in6_addr *,
+ const struct in6_addr *, u_long, int, struct sockaddr *));
void nd6_ns_input __P((struct mbuf *, int, int));
-void nd6_ns_output __P((struct ifnet *, struct in6_addr *,
- struct in6_addr *, struct llinfo_nd6 *, int));
+void nd6_ns_output __P((struct ifnet *, const struct in6_addr *,
+ const struct in6_addr *, struct llinfo_nd6 *, int));
caddr_t nd6_ifptomac __P((struct ifnet *));
void nd6_dad_start __P((struct ifaddr *, int *));
+void nd6_dad_stop __P((struct ifaddr *));
void nd6_dad_duplicated __P((struct ifaddr *));
/* nd6_rtr.c */
@@ -321,14 +385,19 @@ void defrouter_select __P((void));
void defrtrlist_del __P((struct nd_defrouter *));
void prelist_remove __P((struct nd_prefix *));
int prelist_update __P((struct nd_prefix *, struct nd_defrouter *,
- struct mbuf *));
+ struct mbuf *));
+int nd6_prelist_add __P((struct nd_prefix *, struct nd_defrouter *,
+ struct nd_prefix **));
+int nd6_prefix_onlink __P((struct nd_prefix *));
+int nd6_prefix_offlink __P((struct nd_prefix *));
void pfxlist_onlink_check __P((void));
struct nd_defrouter *defrouter_lookup __P((struct in6_addr *,
struct ifnet *));
-int in6_ifdel __P((struct ifnet *, struct in6_addr *));
+struct nd_prefix *nd6_prefix_lookup __P((struct nd_prefix *));
int in6_init_prefix_ltimes __P((struct nd_prefix *ndpr));
void rt6_flush __P((struct in6_addr *, struct ifnet *));
int nd6_setdefaultiface __P((int));
+int in6_tmpifadd __P((const struct in6_ifaddr *, int));
#endif /* _KERNEL */
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index d3fa831..7527d43 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: nd6_nbr.c,v 1.37 2000/06/04 12:46:13 itojun Exp $ */
+/* $KAME: nd6_nbr.c,v 1.64 2001/05/17 03:48:30 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -45,6 +45,7 @@
#include <sys/errno.h>
#include <sys/syslog.h>
#include <sys/queue.h>
+#include <sys/callout.h>
#include <net/if.h>
#include <net/if_types.h>
@@ -72,6 +73,8 @@
struct dadq;
static struct dadq *nd6_dad_find __P((struct ifaddr *));
+static void nd6_dad_starttimer __P((struct dadq *, int));
+static void nd6_dad_stoptimer __P((struct dadq *));
static void nd6_dad_timer __P((struct ifaddr *));
static void nd6_dad_ns_output __P((struct dadq *, struct ifaddr *));
static void nd6_dad_ns_input __P((struct ifaddr *));
@@ -106,10 +109,25 @@ nd6_ns_input(m, off, icmp6len)
union nd_opts ndopts;
struct sockaddr_dl *proxydl = NULL;
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, off, icmp6len,);
+ nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
+#else
+ IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len);
+ if (nd_ns == NULL) {
+ icmp6stat.icp6s_tooshort++;
+ return;
+ }
+#endif
+ ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */
+ taddr6 = nd_ns->nd_ns_target;
+
if (ip6->ip6_hlim != 255) {
- log(LOG_ERR,
- "nd6_ns_input: invalid hlim %d\n", ip6->ip6_hlim);
- goto freeit;
+ nd6log((LOG_ERR,
+ "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n",
+ ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
+ goto bad;
}
if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
@@ -121,26 +139,14 @@ nd6_ns_input(m, off, icmp6len)
&& daddr6.s6_addr8[12] == 0xff) {
; /*good*/
} else {
- log(LOG_INFO, "nd6_ns_input: bad DAD packet "
- "(wrong ip6 dst)\n");
+ nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
+ "(wrong ip6 dst)\n"));
goto bad;
}
}
-#ifndef PULLDOWN_TEST
- IP6_EXTHDR_CHECK(m, off, icmp6len,);
- nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
-#else
- IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len);
- if (nd_ns == NULL) {
- icmp6stat.icp6s_tooshort++;
- return;
- }
-#endif
- taddr6 = nd_ns->nd_ns_target;
-
if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
- log(LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n");
+ nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"));
goto bad;
}
@@ -150,8 +156,10 @@ nd6_ns_input(m, off, icmp6len)
icmp6len -= sizeof(*nd_ns);
nd6_option_init(nd_ns + 1, icmp6len, &ndopts);
if (nd6_options(&ndopts) < 0) {
- log(LOG_INFO, "nd6_ns_input: invalid ND option, ignored\n");
- goto bad;
+ nd6log((LOG_INFO,
+ "nd6_ns_input: invalid ND option, ignored\n"));
+ /* nd6_options have incremented stats */
+ goto freeit;
}
if (ndopts.nd_opts_src_lladdr) {
@@ -160,8 +168,8 @@ nd6_ns_input(m, off, icmp6len)
}
if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) {
- log(LOG_INFO, "nd6_ns_input: bad DAD packet "
- "(link-layer address option)\n");
+ nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
+ "(link-layer address option)\n"));
goto bad;
}
@@ -223,7 +231,7 @@ nd6_ns_input(m, off, icmp6len)
}
if (!ifa) {
/*
- * We've got a NS packet, and we don't have that adddress
+ * We've got an NS packet, and we don't have that adddress
* assigned for us. We MUST silently ignore it.
* See RFC2461 7.2.3.
*/
@@ -236,10 +244,11 @@ nd6_ns_input(m, off, icmp6len)
goto freeit;
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
- log(LOG_INFO,
+ nd6log((LOG_INFO,
"nd6_ns_input: lladdrlen mismatch for %s "
"(if %d, NS packet %d)\n",
- ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2);
+ ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2));
+ goto bad;
}
if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
@@ -306,9 +315,10 @@ nd6_ns_input(m, off, icmp6len)
return;
bad:
- log(LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6));
- log(LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6));
- log(LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6));
+ nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6)));
+ nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6)));
+ nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6)));
+ icmp6stat.icp6s_badns++;
m_freem(m);
}
@@ -324,7 +334,7 @@ nd6_ns_input(m, off, icmp6len)
void
nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
struct ifnet *ifp;
- struct in6_addr *daddr6, *taddr6;
+ const struct in6_addr *daddr6, *taddr6;
struct llinfo_nd6 *ln; /* for source address determination */
int dad; /* duplicated address detection */
{
@@ -362,6 +372,7 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
}
if (m == NULL)
return;
+ m->m_pkthdr.rcvif = NULL;
if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) {
m->m_flags |= M_MCAST;
@@ -495,7 +506,7 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
#ifdef IPSEC
/* Don't lookup socket */
- ipsec_setsocket(m, NULL);
+ (void)ipsec_setsocket(m, NULL);
#endif
ip6_output(m, NULL, NULL, dad ? IPV6_DADOUTPUT : 0, &im6o, &outif);
if (outif) {
@@ -541,9 +552,11 @@ nd6_na_input(m, off, icmp6len)
union nd_opts ndopts;
if (ip6->ip6_hlim != 255) {
- log(LOG_ERR,
- "nd6_na_input: invalid hlim %d\n", ip6->ip6_hlim);
- goto freeit;
+ nd6log((LOG_ERR,
+ "nd6_na_input: invalid hlim (%d) from %s to %s on %s\n",
+ ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
+ goto bad;
}
#ifndef PULLDOWN_TEST
@@ -566,22 +579,24 @@ nd6_na_input(m, off, icmp6len)
taddr6.s6_addr16[1] = htons(ifp->if_index);
if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
- log(LOG_ERR,
+ nd6log((LOG_ERR,
"nd6_na_input: invalid target address %s\n",
- ip6_sprintf(&taddr6));
- goto freeit;
+ ip6_sprintf(&taddr6)));
+ goto bad;
}
if (IN6_IS_ADDR_MULTICAST(&daddr6))
if (is_solicited) {
- log(LOG_ERR,
- "nd6_na_input: a solicited adv is multicasted\n");
- goto freeit;
+ nd6log((LOG_ERR,
+ "nd6_na_input: a solicited adv is multicasted\n"));
+ goto bad;
}
icmp6len -= sizeof(*nd_na);
nd6_option_init(nd_na + 1, icmp6len, &ndopts);
if (nd6_options(&ndopts) < 0) {
- log(LOG_INFO, "nd6_na_input: invalid ND option, ignored\n");
+ nd6log((LOG_INFO,
+ "nd6_na_input: invalid ND option, ignored\n"));
+ /* nd6_options have incremented stats */
goto freeit;
}
@@ -616,10 +631,11 @@ nd6_na_input(m, off, icmp6len)
}
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
- log(LOG_INFO,
+ nd6log((LOG_INFO,
"nd6_na_input: lladdrlen mismatch for %s "
"(if %d, NA packet %d)\n",
- ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2);
+ ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2));
+ goto bad;
}
/*
@@ -649,10 +665,19 @@ nd6_na_input(m, off, icmp6len)
ln->ln_byhint = 0;
if (ln->ln_expire)
ln->ln_expire = time_second +
- nd_ifinfo[rt->rt_ifp->if_index].reachable;
- } else
+ nd_ifinfo[rt->rt_ifp->if_index].reachable;
+ } else {
ln->ln_state = ND6_LLINFO_STALE;
- ln->ln_router = is_router;
+ ln->ln_expire = time_second + nd6_gctimer;
+ }
+ if ((ln->ln_router = is_router) != 0) {
+ /*
+ * This means a router's state has changed from
+ * non-reachable to probably reachable, and might
+ * affect the status of associated prefixes..
+ */
+ pfxlist_onlink_check();
+ }
} else {
int llchange;
@@ -695,8 +720,10 @@ nd6_na_input(m, off, icmp6len)
* If state is REACHABLE, make it STALE.
* no other updates should be done.
*/
- if (ln->ln_state == ND6_LLINFO_REACHABLE)
+ if (ln->ln_state == ND6_LLINFO_REACHABLE) {
ln->ln_state = ND6_LLINFO_STALE;
+ ln->ln_expire = time_second + nd6_gctimer;
+ }
goto freeit;
} else if (is_override /* (2a) */
|| (!is_override && (lladdr && !llchange)) /* (2b) */
@@ -719,11 +746,13 @@ nd6_na_input(m, off, icmp6len)
ln->ln_byhint = 0;
if (ln->ln_expire) {
ln->ln_expire = time_second +
- nd_ifinfo[ifp->if_index].reachable;
+ nd_ifinfo[ifp->if_index].reachable;
}
} else {
- if (lladdr && llchange)
+ if (lladdr && llchange) {
ln->ln_state = ND6_LLINFO_STALE;
+ ln->ln_expire = time_second + nd6_gctimer;
+ }
}
}
@@ -759,21 +788,22 @@ nd6_na_input(m, off, icmp6len)
rt->rt_flags &= ~RTF_REJECT;
ln->ln_asked = 0;
if (ln->ln_hold) {
-#ifdef OLDIP6OUTPUT
- (*ifp->if_output)(ifp, ln->ln_hold, rt_key(rt), rt);
-#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
ln->ln_hold = 0;
}
freeit:
m_freem(m);
+ return;
+
+ bad:
+ icmp6stat.icp6s_badna++;
+ m_freem(m);
}
/*
@@ -788,7 +818,7 @@ nd6_na_input(m, off, icmp6len)
void
nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
struct ifnet *ifp;
- struct in6_addr *daddr6, *taddr6;
+ const struct in6_addr *daddr6, *taddr6;
u_long flags;
int tlladdr; /* 1 if include target link-layer address */
struct sockaddr *sdl0; /* sockaddr_dl (= proxy NA) or NULL */
@@ -824,6 +854,7 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
}
if (m == NULL)
return;
+ m->m_pkthdr.rcvif = NULL;
if (IN6_IS_ADDR_MULTICAST(daddr6)) {
m->m_flags |= M_MCAST;
@@ -917,7 +948,7 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
#ifdef IPSEC
/* Don't lookup socket */
- ipsec_setsocket(m, NULL);
+ (void)ipsec_setsocket(m, NULL);
#endif
ip6_output(m, NULL, NULL, 0, &im6o, &outif);
if (outif) {
@@ -935,6 +966,10 @@ nd6_ifptomac(ifp)
case IFT_ARCNET:
case IFT_ETHER:
case IFT_FDDI:
+ case IFT_IEEE1394:
+#ifdef IFT_IEEE80211
+ case IFT_IEEE80211:
+#endif
return ((caddr_t)(ifp + 1));
break;
default:
@@ -951,10 +986,11 @@ struct dadq {
int dad_ns_ocount; /* NS sent so far */
int dad_ns_icount;
int dad_na_icount;
- struct callout_handle dad_timer;
+ struct callout dad_timer_ch;
};
static struct dadq_head dadq;
+static int dad_init = 0;
static struct dadq *
nd6_dad_find(ifa)
@@ -969,6 +1005,24 @@ nd6_dad_find(ifa)
return NULL;
}
+static void
+nd6_dad_starttimer(dp, ticks)
+ struct dadq *dp;
+ int ticks;
+{
+
+ callout_reset(&dp->dad_timer_ch, ticks,
+ (void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa);
+}
+
+static void
+nd6_dad_stoptimer(dp)
+ struct dadq *dp;
+{
+
+ callout_stop(&dp->dad_timer_ch);
+}
+
/*
* Start Duplicated Address Detection (DAD) for specified interface address.
*/
@@ -979,7 +1033,6 @@ nd6_dad_start(ifa, tick)
{
struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
struct dadq *dp;
- static int dad_init = 0;
if (!dad_init) {
TAILQ_INIT(&dadq);
@@ -1026,12 +1079,11 @@ nd6_dad_start(ifa, tick)
return;
}
bzero(dp, sizeof(*dp));
+ callout_init(&dp->dad_timer_ch, 0);
TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);
-#ifdef ND6_DEBUG
- log(LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
- ip6_sprintf(&ia->ia_addr.sin6_addr));
-#endif
+ nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
+ ip6_sprintf(&ia->ia_addr.sin6_addr)));
/*
* Send NS packet for DAD, ip6_dad_count times.
@@ -1040,15 +1092,14 @@ nd6_dad_start(ifa, tick)
* (re)initialization.
*/
dp->dad_ifa = ifa;
- ifa->ifa_refcnt++; /*just for safety*/
+ IFAREF(ifa); /*just for safety*/
dp->dad_count = ip6_dad_count;
dp->dad_ns_icount = dp->dad_na_icount = 0;
dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
if (!tick) {
nd6_dad_ns_output(dp, ifa);
- dp->dad_timer =
- timeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa,
- nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);
+ nd6_dad_starttimer(dp,
+ nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);
} else {
int ntick;
@@ -1057,12 +1108,35 @@ nd6_dad_start(ifa, tick)
else
ntick = *tick + random() % (hz / 2);
*tick = ntick;
- dp->dad_timer =
- timeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa,
- ntick);
+ nd6_dad_starttimer(dp, ntick);
}
}
+/*
+ * terminate DAD unconditionally. used for address removals.
+ */
+void
+nd6_dad_stop(ifa)
+ struct ifaddr *ifa;
+{
+ struct dadq *dp;
+
+ if (!dad_init)
+ return;
+ dp = nd6_dad_find(ifa);
+ if (!dp) {
+ /* DAD wasn't started yet */
+ return;
+ }
+
+ nd6_dad_stoptimer(dp);
+
+ TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
+ free(dp, M_IP6NDP);
+ dp = NULL;
+ IFAFREE(ifa);
+}
+
static void
nd6_dad_timer(ifa)
struct ifaddr *ifa;
@@ -1100,8 +1174,8 @@ nd6_dad_timer(ifa)
/* timeouted with IFF_{RUNNING,UP} check */
if (dp->dad_ns_tcount > dad_maxtry) {
- log(LOG_ERR, "%s: could not run DAD, driver problem?\n",
- if_name(ifa->ifa_ifp));
+ nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n",
+ if_name(ifa->ifa_ifp)));
TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
free(dp, M_IP6NDP);
@@ -1116,9 +1190,8 @@ nd6_dad_timer(ifa)
* We have more NS to go. Send NS packet for DAD.
*/
nd6_dad_ns_output(dp, ifa);
- dp->dad_timer =
- timeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa,
- nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);
+ nd6_dad_starttimer(dp,
+ nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);
} else {
/*
* We have transmitted sufficient number of DAD packets.
@@ -1177,12 +1250,10 @@ nd6_dad_timer(ifa)
*/
ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
-#ifdef ND6_DEBUG
- log(LOG_INFO,
+ nd6log((LOG_DEBUG,
"%s: DAD complete for %s - no duplicates found\n",
if_name(ifa->ifa_ifp),
- ip6_sprintf(&ia->ia_addr.sin6_addr));
-#endif
+ ip6_sprintf(&ia->ia_addr.sin6_addr)));
TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
free(dp, M_IP6NDP);
@@ -1208,18 +1279,16 @@ nd6_dad_duplicated(ifa)
return;
}
- log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: %d NS, "
- "%d NA\n", if_name(ifa->ifa_ifp),
- ip6_sprintf(&ia->ia_addr.sin6_addr),
- dp->dad_ns_icount, dp->dad_na_icount);
+ log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: "
+ "NS in/out=%d/%d, NA in=%d\n",
+ if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr),
+ dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount);
ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
ia->ia6_flags |= IN6_IFF_DUPLICATED;
/* We are done with DAD, with duplicated address found. (failure) */
- untimeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa
- , dp->dad_timer
- );
+ nd6_dad_stoptimer(dp);
log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n",
if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr));
@@ -1264,7 +1333,7 @@ nd6_dad_ns_input(ifa)
{
struct in6_ifaddr *ia;
struct ifnet *ifp;
- struct in6_addr *taddr6;
+ const struct in6_addr *taddr6;
struct dadq *dp;
int duplicate;
@@ -1277,17 +1346,12 @@ nd6_dad_ns_input(ifa)
duplicate = 0;
dp = nd6_dad_find(ifa);
- /*
- * If it is from myself, ignore this.
- */
- if (ifp && (ifp->if_flags & IFF_LOOPBACK))
- return;
-
/* Quickhack - completely ignore DAD NS packets */
if (dad_ignore_ns) {
- log(LOG_INFO, "nd6_dad_ns_input: ignoring DAD NS packet for "
+ nd6log((LOG_INFO,
+ "nd6_dad_ns_input: ignoring DAD NS packet for "
"address %s(%s)\n", ip6_sprintf(taddr6),
- if_name(ifa->ifa_ifp));
+ if_name(ifa->ifa_ifp)));
return;
}
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
index 258a59c..715ccf0 100644
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: nd6_rtr.c,v 1.47 2000/08/08 08:58:42 jinmei Exp $ */
+/* $KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -40,8 +40,10 @@
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/time.h>
+#include <sys/kernel.h>
#include <sys/errno.h>
#include <sys/syslog.h>
+#include <sys/queue.h>
#include <net/if.h>
#include <net/if_types.h>
@@ -51,6 +53,7 @@
#include <netinet/in.h>
#include <netinet6/in6_var.h>
+#include <netinet6/in6_ifattach.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
@@ -62,34 +65,39 @@
#define SDL(s) ((struct sockaddr_dl *)s)
static struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *));
-static int prelist_add __P((struct nd_prefix *, struct nd_defrouter *));
-static struct nd_prefix *prefix_lookup __P((struct nd_prefix *));
-static struct in6_ifaddr *in6_ifadd __P((struct ifnet *, struct in6_addr *,
- struct in6_addr *, int));
+static struct in6_ifaddr *in6_ifadd __P((struct nd_prefix *,
+ struct in6_addr *));
static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
- struct nd_defrouter *));
+ struct nd_defrouter *));
static void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *));
static void pfxrtr_del __P((struct nd_pfxrouter *));
static struct nd_pfxrouter *find_pfxlist_reachable_router
- __P((struct nd_prefix *));
-static void nd6_detach_prefix __P((struct nd_prefix *));
-static void nd6_attach_prefix __P((struct nd_prefix *));
+ __P((struct nd_prefix *));
static void defrouter_addifreq __P((struct ifnet *));
-#ifdef ND6_USE_RTSOCK
-static void defrouter_msg __P((int, struct rtentry *));
-#endif
+static void nd6_rtmsg __P((int, struct rtentry *));
static void in6_init_address_ltimes __P((struct nd_prefix *ndpr,
- struct in6_addrlifetime *lt6,
- int update_vltime));
+ struct in6_addrlifetime *lt6));
static int rt6_deleteroute __P((struct radix_node *, void *));
extern int nd6_recalc_reachtm_interval;
-struct ifnet *nd6_defifp;
+static struct ifnet *nd6_defifp;
int nd6_defifindex;
+int ip6_use_tempaddr = 0;
+
+int ip6_desync_factor;
+u_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME;
+u_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME;
+/*
+ * shorter lifetimes for debugging purposes.
+int ip6_temp_preferred_lifetime = 800;
+static int ip6_temp_valid_lifetime = 1800;
+*/
+int ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE;
+
/*
* Receive Router Solicitation Message - just for routers.
* Router solicitation/advertisement is mostly managed by userland program
@@ -125,9 +133,11 @@ nd6_rs_input(m, off, icmp6len)
/* Sanity checks */
if (ip6->ip6_hlim != 255) {
- log(LOG_ERR,
- "nd6_rs_input: invalid hlim %d\n", ip6->ip6_hlim);
- goto freeit;
+ nd6log((LOG_ERR,
+ "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n",
+ ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
+ goto bad;
}
/*
@@ -151,7 +161,9 @@ nd6_rs_input(m, off, icmp6len)
icmp6len -= sizeof(*nd_rs);
nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
if (nd6_options(&ndopts) < 0) {
- log(LOG_INFO, "nd6_rs_input: invalid ND option, ignored\n");
+ nd6log((LOG_INFO,
+ "nd6_rs_input: invalid ND option, ignored\n"));
+ /* nd6_options have incremented stats */
goto freeit;
}
@@ -161,16 +173,22 @@ nd6_rs_input(m, off, icmp6len)
}
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
- log(LOG_INFO,
+ nd6log((LOG_INFO,
"nd6_rs_input: lladdrlen mismatch for %s "
"(if %d, RS packet %d)\n",
- ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2);
+ ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2));
+ goto bad;
}
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
freeit:
m_freem(m);
+ return;
+
+ bad:
+ icmp6stat.icp6s_badrs++;
+ m_freem(m);
}
/*
@@ -203,16 +221,18 @@ nd6_ra_input(m, off, icmp6len)
goto freeit;
if (ip6->ip6_hlim != 255) {
- log(LOG_ERR,
- "nd6_ra_input: invalid hlim %d\n", ip6->ip6_hlim);
- goto freeit;
+ nd6log((LOG_ERR,
+ "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n",
+ ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
+ goto bad;
}
if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
- log(LOG_ERR,
+ nd6log((LOG_ERR,
"nd6_ra_input: src %s is not link-local\n",
- ip6_sprintf(&saddr6));
- goto freeit;
+ ip6_sprintf(&saddr6)));
+ goto bad;
}
#ifndef PULLDOWN_TEST
@@ -229,7 +249,9 @@ nd6_ra_input(m, off, icmp6len)
icmp6len -= sizeof(*nd_ra);
nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
if (nd6_options(&ndopts) < 0) {
- log(LOG_INFO, "nd6_ra_input: invalid ND option, ignored\n");
+ nd6log((LOG_INFO,
+ "nd6_ra_input: invalid ND option, ignored\n"));
+ /* nd6_options have incremented stats */
goto freeit;
}
@@ -267,7 +289,7 @@ nd6_ra_input(m, off, icmp6len)
*/
if (ndopts.nd_opts_pi) {
struct nd_opt_hdr *pt;
- struct nd_opt_prefix_info *pi;
+ struct nd_opt_prefix_info *pi = NULL;
struct nd_prefix pr;
for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
@@ -279,34 +301,38 @@ nd6_ra_input(m, off, icmp6len)
pi = (struct nd_opt_prefix_info *)pt;
if (pi->nd_opt_pi_len != 4) {
- log(LOG_INFO, "nd6_ra_input: invalid option "
- "len %d for prefix information option, "
- "ignored\n", pi->nd_opt_pi_len);
+ nd6log((LOG_INFO,
+ "nd6_ra_input: invalid option "
+ "len %d for prefix information option, "
+ "ignored\n", pi->nd_opt_pi_len));
continue;
}
if (128 < pi->nd_opt_pi_prefix_len) {
- log(LOG_INFO, "nd6_ra_input: invalid prefix "
- "len %d for prefix information option, "
- "ignored\n", pi->nd_opt_pi_prefix_len);
+ nd6log((LOG_INFO,
+ "nd6_ra_input: invalid prefix "
+ "len %d for prefix information option, "
+ "ignored\n", pi->nd_opt_pi_prefix_len));
continue;
}
if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
|| IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
- log(LOG_INFO, "nd6_ra_input: invalid prefix "
- "%s, ignored\n",
- ip6_sprintf(&pi->nd_opt_pi_prefix));
+ nd6log((LOG_INFO,
+ "nd6_ra_input: invalid prefix "
+ "%s, ignored\n",
+ ip6_sprintf(&pi->nd_opt_pi_prefix)));
continue;
}
/* aggregatable unicast address, rfc2374 */
if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20
&& pi->nd_opt_pi_prefix_len != 64) {
- log(LOG_INFO, "nd6_ra_input: invalid prefixlen "
- "%d for rfc2374 prefix %s, ignored\n",
- pi->nd_opt_pi_prefix_len,
- ip6_sprintf(&pi->nd_opt_pi_prefix));
+ nd6log((LOG_INFO,
+ "nd6_ra_input: invalid prefixlen "
+ "%d for rfc2374 prefix %s, ignored\n",
+ pi->nd_opt_pi_prefix_len,
+ ip6_sprintf(&pi->nd_opt_pi_prefix)));
continue;
}
@@ -340,9 +366,9 @@ nd6_ra_input(m, off, icmp6len)
/* lower bound */
if (mtu < IPV6_MMTU) {
- log(LOG_INFO, "nd6_ra_input: bogus mtu option "
+ nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option "
"mtu=%d sent from %s, ignoring\n",
- mtu, ip6_sprintf(&ip6->ip6_src));
+ mtu, ip6_sprintf(&ip6->ip6_src)));
goto skip;
}
@@ -355,17 +381,17 @@ nd6_ra_input(m, off, icmp6len)
if (change) /* in6_maxmtu may change */
in6_setmaxmtu();
} else {
- log(LOG_INFO, "nd6_ra_input: bogus mtu "
+ nd6log((LOG_INFO, "nd6_ra_input: bogus mtu "
"mtu=%d sent from %s; "
"exceeds maxmtu %d, ignoring\n",
mtu, ip6_sprintf(&ip6->ip6_src),
- ndi->maxmtu);
+ ndi->maxmtu));
}
} else {
- log(LOG_INFO, "nd6_ra_input: mtu option "
+ nd6log((LOG_INFO, "nd6_ra_input: mtu option "
"mtu=%d sent from %s; maxmtu unknown, "
"ignoring\n",
- mtu, ip6_sprintf(&ip6->ip6_src));
+ mtu, ip6_sprintf(&ip6->ip6_src)));
}
}
@@ -384,10 +410,11 @@ nd6_ra_input(m, off, icmp6len)
}
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
- log(LOG_INFO,
+ nd6log((LOG_INFO,
"nd6_ra_input: lladdrlen mismatch for %s "
"(if %d, RA packet %d)\n",
- ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2);
+ ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2));
+ goto bad;
}
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0);
@@ -400,7 +427,12 @@ nd6_ra_input(m, off, icmp6len)
pfxlist_onlink_check();
}
-freeit:
+ freeit:
+ m_freem(m);
+ return;
+
+ bad:
+ icmp6stat.icp6s_badra++;
m_freem(m);
}
@@ -408,10 +440,9 @@ freeit:
* default router list proccessing sub routines
*/
-#ifdef ND6_USE_RTSOCK
/* tell the change to user processes watching the routing socket. */
static void
-defrouter_msg(cmd, rt)
+nd6_rtmsg(cmd, rt)
int cmd;
struct rtentry *rt;
{
@@ -421,10 +452,12 @@ defrouter_msg(cmd, rt)
info.rti_info[RTAX_DST] = rt_key(rt);
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
info.rti_info[RTAX_NETMASK] = rt_mask(rt);
+ info.rti_info[RTAX_IFP] =
+ (struct sockaddr *)TAILQ_FIRST(&rt->rt_ifp->if_addrlist);
+ info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
rt_missmsg(cmd, &info, rt->rt_flags, 0);
}
-#endif
void
defrouter_addreq(new)
@@ -448,9 +481,7 @@ defrouter_addreq(new)
(struct sockaddr *)&gate, (struct sockaddr *)&mask,
RTF_GATEWAY, &newrt);
if (newrt) {
-#ifdef ND6_USE_RTSOCK
- defrouter_msg(RTM_ADD, newrt); /* tell user process */
-#endif
+ nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
newrt->rt_refcnt--;
}
splx(s);
@@ -478,31 +509,27 @@ defrouter_addifreq(ifp)
* XXX: An IPv6 address are required to be assigned on the interface.
*/
if ((ifa = ifaof_ifpforaddr((struct sockaddr *)&def, ifp)) == NULL) {
- log(LOG_ERR, /* better error? */
+ nd6log((LOG_ERR, /* better error? */
"defrouter_addifreq: failed to find an ifaddr "
"to install a route to interface %s\n",
- if_name(ifp));
+ if_name(ifp)));
return;
}
flags = ifa->ifa_flags;
- if ((ifp->if_flags & IFF_POINTOPOINT) != 0)
- flags &= ~RTF_CLONING;
- if ((error = rtrequest(RTM_ADD, (struct sockaddr *)&def,
- ifa->ifa_addr, (struct sockaddr *)&mask,
- flags, &newrt)) != 0) {
- log(LOG_ERR,
+ error = rtrequest(RTM_ADD, (struct sockaddr *)&def, ifa->ifa_addr,
+ (struct sockaddr *)&mask, flags, &newrt);
+ if (error != 0) {
+ nd6log((LOG_ERR,
"defrouter_addifreq: failed to install a route to "
"interface %s (errno = %d)\n",
- if_name(ifp), error);
+ if_name(ifp), error));
if (newrt) /* maybe unnecessary, but do it for safety */
newrt->rt_refcnt--;
} else {
if (newrt) {
-#ifdef ND6_USE_RTSOCK
- defrouter_msg(RTM_ADD, newrt);
-#endif
+ nd6_rtmsg(RTM_ADD, newrt);
newrt->rt_refcnt--;
}
}
@@ -546,9 +573,7 @@ defrouter_delreq(dr, dofree)
(struct sockaddr *)&mask,
RTF_GATEWAY, &oldrt);
if (oldrt) {
-#ifdef ND6_USE_RTSOCK
- defrouter_msg(RTM_DELETE, oldrt);
-#endif
+ nd6_rtmsg(RTM_DELETE, oldrt);
if (oldrt->rt_refcnt <= 0) {
/*
* XXX: borrowed from the RTM_DELETE case of
@@ -669,15 +694,17 @@ defrouter_select()
/*
* Install a route to the default interface
* as default route.
+ * XXX: we enable this for host only, because
+ * this may override a default route installed
+ * a user process (e.g. routing daemon) in a
+ * router case.
*/
defrouter_addifreq(nd6_defifp);
- }
-#ifdef ND6_DEBUG
- else /* noisy log? */
- log(LOG_INFO, "defrouter_select: "
+ } else {
+ nd6log((LOG_INFO, "defrouter_select: "
"there's no default router and no default"
- " interface\n");
-#endif
+ " interface\n"));
+ }
}
}
@@ -775,8 +802,8 @@ pfxrtr_del(pfr)
free(pfr, M_IP6NDP);
}
-static struct nd_prefix *
-prefix_lookup(pr)
+struct nd_prefix *
+nd6_prefix_lookup(pr)
struct nd_prefix *pr;
{
struct nd_prefix *search;
@@ -795,12 +822,12 @@ prefix_lookup(pr)
return(search);
}
-static int
-prelist_add(pr, dr)
- struct nd_prefix *pr;
+int
+nd6_prelist_add(pr, dr, newp)
+ struct nd_prefix *pr, **newp;
struct nd_defrouter *dr;
{
- struct nd_prefix *new;
+ struct nd_prefix *new = NULL;
int i, s;
new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
@@ -808,9 +835,10 @@ prelist_add(pr, dr)
return ENOMEM;
bzero(new, sizeof(*new));
*new = *pr;
+ if (newp != NULL)
+ *newp = new;
/* initilization */
- new->ndpr_statef_onlink = pr->ndpr_statef_onlink;
LIST_INIT(&new->ndpr_advrtrs);
in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
/* make prefix in the canonical form */
@@ -818,13 +846,24 @@ prelist_add(pr, dr)
new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
new->ndpr_mask.s6_addr32[i];
- /* xxx ND_OPT_PI_FLAG_ONLINK processing */
-
s = splnet();
/* link ndpr_entry to nd_prefix list */
LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
splx(s);
+ /* ND_OPT_PI_FLAG_ONLINK processing */
+ if (new->ndpr_raf_onlink) {
+ int e;
+
+ if ((e = nd6_prefix_onlink(new)) != 0) {
+ nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
+ "the prefix %s/%d on-link on %s (errno=%d)\n",
+ ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
+ pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
+ /* proceed anyway. XXX: is it correct? */
+ }
+ }
+
if (dr) {
pfxrtr_add(new, dr);
}
@@ -837,12 +876,35 @@ prelist_remove(pr)
struct nd_prefix *pr;
{
struct nd_pfxrouter *pfr, *next;
- int s;
+ int e, s;
+
+ /* make sure to invalidate the prefix until it is really freed. */
+ pr->ndpr_vltime = 0;
+ pr->ndpr_pltime = 0;
+#if 0
+ /*
+ * Though these flags are now meaningless, we'd rather keep the value
+ * not to confuse users when executing "ndp -p".
+ */
+ pr->ndpr_raf_onlink = 0;
+ pr->ndpr_raf_auto = 0;
+#endif
+ if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 &&
+ (e = nd6_prefix_offlink(pr)) != 0) {
+ nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink "
+ "on %s, errno=%d\n",
+ ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
+ pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
+ /* what should we do? */
+ }
+
+ if (pr->ndpr_refcnt > 0)
+ return; /* notice here? */
s = splnet();
+
/* unlink ndpr_entry from nd_prefix list */
LIST_REMOVE(pr, ndpr_entry);
- splx(s);
/* free list of routers that adversed the prefix */
for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
@@ -850,30 +912,28 @@ prelist_remove(pr)
free(pfr, M_IP6NDP);
}
+ splx(s);
+
free(pr, M_IP6NDP);
pfxlist_onlink_check();
}
-/*
- * NOTE: We set address lifetime to keep
- * address lifetime <= prefix lifetime
- * invariant. This is to simplify on-link determination code.
- * If onlink determination is udated, this routine may have to be updated too.
- */
int
prelist_update(new, dr, m)
struct nd_prefix *new;
struct nd_defrouter *dr; /* may be NULL */
struct mbuf *m;
{
- struct in6_ifaddr *ia6 = NULL;
+ struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL;
+ struct ifaddr *ifa;
+ struct ifnet *ifp = new->ndpr_ifp;
struct nd_prefix *pr;
int s = splnet();
int error = 0;
+ int newprefix = 0;
int auth;
- struct in6_addrlifetime *lt6;
- u_char onlink; /* Mobile IPv6 */
+ struct in6_addrlifetime lt6_tmp;
auth = 0;
if (m) {
@@ -887,170 +947,259 @@ prelist_update(new, dr, m)
#endif
}
- if ((pr = prefix_lookup(new)) != NULL) {
- if (pr->ndpr_ifp != new->ndpr_ifp) {
- error = EADDRNOTAVAIL;
- goto end;
- }
-
- /* update prefix information */
- pr->ndpr_flags = new->ndpr_flags;
- pr->ndpr_vltime = new->ndpr_vltime;
- pr->ndpr_pltime = new->ndpr_pltime;
- pr->ndpr_preferred = new->ndpr_preferred;
- pr->ndpr_expire = new->ndpr_expire;
+ if ((pr = nd6_prefix_lookup(new)) != NULL) {
/*
- * RFC 2462 5.5.3 (d) or (e)
- * We got a prefix which we have seen in the past.
+ * nd6_prefix_lookup() ensures that pr and new have the same
+ * prefix on a same interface.
*/
- if (!new->ndpr_raf_auto)
- goto noautoconf1;
- if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
- ia6 = NULL;
- else
- ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
+ /*
+ * Update prefix information. Note that the on-link (L) bit
+ * and the autonomous (A) bit should NOT be changed from 1
+ * to 0.
+ */
+ if (new->ndpr_raf_onlink == 1)
+ pr->ndpr_raf_onlink = 1;
+ if (new->ndpr_raf_auto == 1)
+ pr->ndpr_raf_auto = 1;
+ if (new->ndpr_raf_onlink) {
+ pr->ndpr_vltime = new->ndpr_vltime;
+ pr->ndpr_pltime = new->ndpr_pltime;
+ pr->ndpr_preferred = new->ndpr_preferred;
+ pr->ndpr_expire = new->ndpr_expire;
+ }
- if (ia6 == NULL) {
- /*
- * Special case:
- * (1) We have seen the prefix advertised before, but
- * we have never performed autoconfig for this prefix.
- * This is because Autonomous bit was 0 previously, or
- * autoconfig failed due to some other reasons.
- * (2) We have seen the prefix advertised before and
- * we have performed autoconfig in the past, but
- * we seem to have no interface address right now.
- * This is because the interface address have expired.
- *
- * This prefix is fresh, with respect to autoconfig
- * process.
- *
- * Add an address based on RFC 2462 5.5.3 (d).
- */
- ia6 = in6_ifadd(pr->ndpr_ifp,
- &pr->ndpr_prefix.sin6_addr, &pr->ndpr_addr,
- new->ndpr_plen);
- if (!ia6) {
- error = EADDRNOTAVAIL;
- log(LOG_ERR, "prelist_update: failed to add a "
- "new address\n");
- goto noautoconf1;
+ if (new->ndpr_raf_onlink &&
+ (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
+ int e;
+
+ if ((e = nd6_prefix_onlink(pr)) != 0) {
+ nd6log((LOG_ERR,
+ "prelist_update: failed to make "
+ "the prefix %s/%d on-link on %s "
+ "(errno=%d)\n",
+ ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
+ pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
+ /* proceed anyway. XXX: is it correct? */
}
+ }
- lt6 = &ia6->ia6_lifetime;
+ if (dr && pfxrtr_lookup(pr, dr) == NULL)
+ pfxrtr_add(pr, dr);
+ } else {
+ struct nd_prefix *newpr = NULL;
- /* address lifetime <= prefix lifetime */
- lt6->ia6t_vltime = new->ndpr_vltime;
- lt6->ia6t_pltime = new->ndpr_pltime;
- in6_init_address_ltimes(new, lt6, 1);
- } else {
-#define TWOHOUR (120*60)
- /*
- * We have seen the prefix before, and we have added
- * interface address in the past. We still have
- * the interface address assigned.
- *
- * update address lifetime based on RFC 2462
- * 5.5.3 (e).
- */
- int update = 0;
-
- lt6 = &ia6->ia6_lifetime;
-
-#if 0 /* RFC 2462 5.5.3 (e) */
- lt6->ia6t_pltime = new->ndpr_pltime;
- if (TWOHOUR < new->ndpr_vltime
- || lt6pr->nd < new->ndpr_vltime) {
- lt6->ia6t_vltime = new->ndpr_vltime;
- update++;
- } else if (auth
- && lt6->ia6t_vltime <= TWOHOUR0
- && new->ndpr_vltime <= lt6->ia6t_vltime) {
- lt6->ia6t_vltime = new->ndpr_vltime;
- update++;
- } else {
- lt6->ia6t_vltime = TWOHOUR;
- update++;
- }
+ newprefix = 1;
- /* 2 hour rule is not imposed for pref lifetime */
- new->ndpr_apltime = new->ndpr_pltime;
- lt6->ia6t_pltime = new->ndpr_pltime;
-#else /* update from Jim Bound, (ipng 6712) */
- if (TWOHOUR < new->ndpr_vltime
- || lt6->ia6t_vltime < new->ndpr_vltime) {
- lt6->ia6t_vltime = new->ndpr_vltime;
- update++;
- } else if (auth) {
- lt6->ia6t_vltime = new->ndpr_vltime;
- update++;
- }
+ if (new->ndpr_vltime == 0)
+ goto end;
+ if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0)
+ goto end;
- /* jim bound rule is not imposed for pref lifetime */
- lt6->ia6t_pltime = new->ndpr_pltime;
-#endif
- in6_init_address_ltimes(new, lt6, update);
+ bzero(&new->ndpr_addr, sizeof(struct in6_addr));
+
+ error = nd6_prelist_add(new, dr, &newpr);
+ if (error != 0 || newpr == NULL) {
+ nd6log((LOG_NOTICE, "prelist_update: "
+ "nd6_prelist_add failed for %s/%d on %s "
+ "errno=%d, returnpr=%p\n",
+ ip6_sprintf(&new->ndpr_prefix.sin6_addr),
+ new->ndpr_plen, if_name(new->ndpr_ifp),
+ error, newpr));
+ goto end; /* we should just give up in this case. */
}
- noautoconf1:
+ /*
+ * XXX: from the ND point of view, we can ignore a prefix
+ * with the on-link bit being zero. However, we need a
+ * prefix structure for references from autoconfigured
+ * addresses. Thus, we explicitly make suret that the prefix
+ * itself expires now.
+ */
+ if (newpr->ndpr_raf_onlink == 0) {
+ newpr->ndpr_vltime = 0;
+ newpr->ndpr_pltime = 0;
+ in6_init_prefix_ltimes(newpr);
+ }
-#if 0
- /* address lifetime expire processing, RFC 2462 5.5.4. */
- if (pr->ndpr_preferred && pr->ndpr_preferred < time_second) {
- struct in6_ifaddr *ia6;
+ pr = newpr;
+ }
- ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
- if (ia6)
- ia6->ia6_flags &= ~IN6_IFF_DEPRECATED;
- }
-#endif
+ /*
+ * Address autoconfiguration based on Section 5.5.3 of RFC 2462.
+ * Note that pr must be non NULL at this point.
+ */
- onlink = pr->ndpr_statef_onlink; /* Mobile IPv6 */
+ /* 5.5.3 (a). Ignore the prefix without the A bit set. */
+ if (!new->ndpr_raf_auto)
+ goto afteraddrconf;
- if (dr && pfxrtr_lookup(pr, dr) == NULL)
- pfxrtr_add(pr, dr);
+ /*
+ * 5.5.3 (b). the link-local prefix should have been ignored in
+ * nd6_ra_input.
+ */
- } else {
- int error_tmp;
+ /*
+ * 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime.
+ * This should have been done in nd6_ra_input.
+ */
- if (new->ndpr_vltime == 0) goto end;
+ /*
+ * 5.5.3 (d). If the prefix advertised does not match the prefix of an
+ * address already in the list, and the Valid Lifetime is not 0,
+ * form an address. Note that even a manually configured address
+ * should reject autoconfiguration of a new address.
+ */
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
+ {
+ struct in6_ifaddr *ifa6;
+ int ifa_plen;
+ u_int32_t storedlifetime;
- bzero(&new->ndpr_addr, sizeof(struct in6_addr));
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+
+ ifa6 = (struct in6_ifaddr *)ifa;
+
+ /*
+ * Spec is not clear here, but I believe we should concentrate
+ * on unicast (i.e. not anycast) addresses.
+ * XXX: other ia6_flags? detached or duplicated?
+ */
+ if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0)
+ continue;
+
+ ifa_plen = in6_mask2len(&ifa6->ia_prefixmask.sin6_addr, NULL);
+ if (ifa_plen != new->ndpr_plen ||
+ !in6_are_prefix_equal(&ifa6->ia_addr.sin6_addr,
+ &new->ndpr_prefix.sin6_addr,
+ ifa_plen))
+ continue;
+
+ if (ia6_match == NULL) /* remember the first one */
+ ia6_match = ifa6;
+
+ if ((ifa6->ia6_flags & IN6_IFF_AUTOCONF) == 0)
+ continue;
/*
- * RFC 2462 5.5.3 (d)
- * We got a fresh prefix. Perform some sanity checks
- * and add an interface address by appending interface ID
- * to the advertised prefix.
+ * An already autoconfigured address matched. Now that we
+ * are sure there is at least one matched address, we can
+ * proceed to 5.5.3. (e): update the lifetimes according to the
+ * "two hours" rule and the privacy extension.
*/
- if (!new->ndpr_raf_auto)
- goto noautoconf2;
-
- ia6 = in6_ifadd(new->ndpr_ifp, &new->ndpr_prefix.sin6_addr,
- &new->ndpr_addr, new->ndpr_plen);
- if (!ia6) {
- error = EADDRNOTAVAIL;
- log(LOG_ERR, "prelist_update: "
- "failed to add a new address\n");
- goto noautoconf2;
+#define TWOHOUR (120*60)
+ lt6_tmp = ifa6->ia6_lifetime;
+
+ storedlifetime = IFA6_IS_INVALID(ifa6) ? 0 :
+ (lt6_tmp.ia6t_expire - time_second);
+
+ if (TWOHOUR < new->ndpr_vltime ||
+ storedlifetime < new->ndpr_vltime) {
+ lt6_tmp.ia6t_vltime = new->ndpr_vltime;
+ } else if (storedlifetime <= TWOHOUR
+#if 0
+ /*
+ * This condition is logically redundant, so we just
+ * omit it.
+ * See IPng 6712, 6717, and 6721.
+ */
+ && new->ndpr_vltime <= storedlifetime
+#endif
+ ) {
+ if (auth) {
+ lt6_tmp.ia6t_vltime = new->ndpr_vltime;
+ }
+ } else {
+ /*
+ * new->ndpr_vltime <= TWOHOUR &&
+ * TWOHOUR < storedlifetime
+ */
+ lt6_tmp.ia6t_vltime = TWOHOUR;
}
- /* set onlink bit if an interface route is configured */
- new->ndpr_statef_onlink = (ia6->ia_flags & IFA_ROUTE) ? 1 : 0;
- lt6 = &ia6->ia6_lifetime;
+ /* The 2 hour rule is not imposed for preferred lifetime. */
+ lt6_tmp.ia6t_pltime = new->ndpr_pltime;
+
+ in6_init_address_ltimes(pr, &lt6_tmp);
+
+ /*
+ * When adjusting the lifetimes of an existing temporary
+ * address, only lower the lifetimes.
+ * RFC 3041 3.3. (1).
+ * XXX: how should we modify ia6t_[pv]ltime?
+ */
+ if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
+ if (lt6_tmp.ia6t_expire == 0 || /* no expire */
+ lt6_tmp.ia6t_expire >
+ ifa6->ia6_lifetime.ia6t_expire) {
+ lt6_tmp.ia6t_expire =
+ ifa6->ia6_lifetime.ia6t_expire;
+ }
+ if (lt6_tmp.ia6t_preferred == 0 || /* no expire */
+ lt6_tmp.ia6t_preferred >
+ ifa6->ia6_lifetime.ia6t_preferred) {
+ lt6_tmp.ia6t_preferred =
+ ifa6->ia6_lifetime.ia6t_preferred;
+ }
+ }
+
+ ifa6->ia6_lifetime = lt6_tmp;
+ }
+ if (ia6_match == NULL && new->ndpr_vltime) {
+ /*
+ * No address matched and the valid lifetime is non-zero.
+ * Create a new address.
+ */
+ if ((ia6 = in6_ifadd(new, NULL)) != NULL) {
+ /*
+ * note that we should use pr (not new) for reference.
+ */
+ pr->ndpr_refcnt++;
+ ia6->ia6_ndpr = pr;
+
+#if 0
+ /* XXXYYY Don't do this, according to Jinmei. */
+ pr->ndpr_addr = new->ndpr_addr;
+#endif
- /* address lifetime <= prefix lifetime */
- lt6->ia6t_vltime = new->ndpr_vltime;
- lt6->ia6t_pltime = new->ndpr_pltime;
- in6_init_address_ltimes(new, lt6, 1);
+ /*
+ * RFC 3041 3.3 (2).
+ * When a new public address is created as described
+ * in RFC2462, also create a new temporary address.
+ *
+ * RFC 3041 3.5.
+ * When an interface connects to a new link, a new
+ * randomized interface identifier should be generated
+ * immediately together with a new set of temporary
+ * addresses. Thus, we specifiy 1 as the 2nd arg of
+ * in6_tmpifadd().
+ */
+ if (ip6_use_tempaddr) {
+ int e;
+ if ((e = in6_tmpifadd(ia6, 1)) != 0) {
+ nd6log((LOG_NOTICE, "prelist_update: "
+ "failed to create a temporary "
+ "address, errno=%d\n",
+ e));
+ }
+ }
- noautoconf2:
- error_tmp = prelist_add(new, dr);
- error = error_tmp ? error_tmp : error;
+ /*
+ * A newly added address might affect the status
+ * of other addresses, so we check and update it.
+ * XXX: what if address duplication happens?
+ */
+ pfxlist_onlink_check();
+ } else {
+ /* just set an error. do not bark here. */
+ error = EADDRNOTAVAIL; /* XXX: might be unused. */
+ }
}
+ afteraddrconf:
+
end:
splx(s);
return error;
@@ -1061,7 +1210,7 @@ prelist_update(new, dr, m)
* detect if a given prefix has a (probably) reachable advertising router.
* XXX: lengthy function name...
*/
-struct nd_pfxrouter *
+static struct nd_pfxrouter *
find_pfxlist_reachable_router(pr)
struct nd_prefix *pr;
{
@@ -1084,14 +1233,14 @@ find_pfxlist_reachable_router(pr)
/*
* Check if each prefix in the prefix list has at least one available router
- * that advertised the prefix (A router is "available" if its neighbor cache
- * entry has reachable or probably reachable).
+ * that advertised the prefix (a router is "available" if its neighbor cache
+ * entry is reachable or probably reachable).
* If the check fails, the prefix may be off-link, because, for example,
* we have moved from the network but the lifetime of the prefix has not
- * been expired yet. So we should not use the prefix if there is another
- * prefix that has an available router.
- * But if there is no prefix that has an available router, we still regards
- * all the prefixes as on-link. This is because we can't tell if all the
+ * expired yet. So we should not use the prefix if there is another prefix
+ * that has an available router.
+ * But, if there is no prefix that has an available router, we still regards
+ * all the prefixes as on-link. This is because we can't tell if all the
* routers are simply dead or if we really moved from the network and there
* is no router around us.
*/
@@ -1099,55 +1248,275 @@ void
pfxlist_onlink_check()
{
struct nd_prefix *pr;
+ struct in6_ifaddr *ifa;
/*
* Check if there is a prefix that has a reachable advertising
* router.
*/
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
- if (find_pfxlist_reachable_router(pr))
+ if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr))
break;
}
if (pr) {
/*
* There is at least one prefix that has a reachable router.
- * First, detach prefixes which has no reachable advertising
- * router and then attach other prefixes.
- * The order is important since an attached prefix and a
- * detached prefix may have a same interface route.
+ * Detach prefixes which have no reachable advertising
+ * router, and attach other prefixes.
*/
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
- if (find_pfxlist_reachable_router(pr) == NULL &&
- pr->ndpr_statef_onlink) {
- pr->ndpr_statef_onlink = 0;
- nd6_detach_prefix(pr);
- }
+ /* XXX: a link-local prefix should never be detached */
+ if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
+ continue;
+
+ /*
+ * we aren't interested in prefixes without the L bit
+ * set.
+ */
+ if (pr->ndpr_raf_onlink == 0)
+ continue;
+
+ if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
+ find_pfxlist_reachable_router(pr) == NULL)
+ pr->ndpr_stateflags |= NDPRF_DETACHED;
+ if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
+ find_pfxlist_reachable_router(pr) != 0)
+ pr->ndpr_stateflags &= ~NDPRF_DETACHED;
}
+ } else {
+ /* there is no prefix that has a reachable router */
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
- if (find_pfxlist_reachable_router(pr) &&
- pr->ndpr_statef_onlink == 0)
- nd6_attach_prefix(pr);
+ if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
+ continue;
+
+ if (pr->ndpr_raf_onlink == 0)
+ continue;
+
+ if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0)
+ pr->ndpr_stateflags &= ~NDPRF_DETACHED;
+ }
+ }
+
+ /*
+ * Remove each interface route associated with a (just) detached
+ * prefix, and reinstall the interface route for a (just) attached
+ * prefix. Note that all attempt of reinstallation does not
+ * necessarily success, when a same prefix is shared among multiple
+ * interfaces. Such cases will be handled in nd6_prefix_onlink,
+ * so we don't have to care about them.
+ */
+ for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
+ int e;
+
+ if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
+ continue;
+
+ if (pr->ndpr_raf_onlink == 0)
+ continue;
+
+ if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
+ (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
+ if ((e = nd6_prefix_offlink(pr)) != 0) {
+ nd6log((LOG_ERR,
+ "pfxlist_onlink_check: failed to "
+ "make %s/%d offlink, errno=%d\n",
+ ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
+ pr->ndpr_plen, e));
+ }
+ }
+ if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
+ (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 &&
+ pr->ndpr_raf_onlink) {
+ if ((e = nd6_prefix_onlink(pr)) != 0) {
+ nd6log((LOG_ERR,
+ "pfxlist_onlink_check: failed to "
+ "make %s/%d offlink, errno=%d\n",
+ ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
+ pr->ndpr_plen, e));
+ }
+ }
+ }
+
+ /*
+ * Changes on the prefix status might affect address status as well.
+ * Make sure that all addresses derived from an attached prefix are
+ * attached, and that all addresses derived from a detached prefix are
+ * detached. Note, however, that a manually configured address should
+ * always be attached.
+ * The precise detection logic is same as the one for prefixes.
+ */
+ for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
+ if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
+ continue;
+
+ if (ifa->ia6_ndpr == NULL) {
+ /*
+ * This can happen when we first configure the address
+ * (i.e. the address exists, but the prefix does not).
+ * XXX: complicated relationships...
+ */
+ continue;
+ }
+
+ if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
+ break;
+ }
+ if (ifa) {
+ for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
+ if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
+ continue;
+
+ if (ifa->ia6_ndpr == NULL) /* XXX: see above. */
+ continue;
+
+ if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
+ ifa->ia6_flags &= ~IN6_IFF_DETACHED;
+ else
+ ifa->ia6_flags |= IN6_IFF_DETACHED;
}
}
else {
- /* there is no prefix that has a reachable router */
- for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next)
- if (pr->ndpr_statef_onlink == 0)
- nd6_attach_prefix(pr);
+ for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
+ if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
+ continue;
+
+ ifa->ia6_flags &= ~IN6_IFF_DETACHED;
+ }
}
}
-static void
-nd6_detach_prefix(pr)
+int
+nd6_prefix_onlink(pr)
struct nd_prefix *pr;
{
- struct in6_ifaddr *ia6;
- struct sockaddr_in6 sa6, mask6;
+ struct ifaddr *ifa;
+ struct ifnet *ifp = pr->ndpr_ifp;
+ struct sockaddr_in6 mask6;
+ struct nd_prefix *opr;
+ u_long rtflags;
+ int error = 0;
+ struct rtentry *rt = NULL;
+
+ /* sanity check */
+ if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
+ nd6log((LOG_ERR,
+ "nd6_prefix_onlink: %s/%d is already on-link\n",
+ ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen);
+ return(EEXIST));
+ }
/*
- * Delete the interface route associated with the prefix.
+ * Add the interface route associated with the prefix. Before
+ * installing the route, check if there's the same prefix on another
+ * interface, and the prefix has already installed the interface route.
+ * Although such a configuration is expected to be rare, we explicitly
+ * allow it.
*/
+ for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
+ if (opr == pr)
+ continue;
+
+ if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0)
+ continue;
+
+ if (opr->ndpr_plen == pr->ndpr_plen &&
+ in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
+ &opr->ndpr_prefix.sin6_addr,
+ pr->ndpr_plen))
+ return(0);
+ }
+
+ /*
+ * We prefer link-local addresses as the associated interface address.
+ */
+ /* search for a link-local addr */
+ ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
+ IN6_IFF_NOTREADY|
+ IN6_IFF_ANYCAST);
+ if (ifa == NULL) {
+ /* XXX: freebsd does not have ifa_ifwithaf */
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
+ {
+ if (ifa->ifa_addr->sa_family == AF_INET6)
+ break;
+ }
+ /* should we care about ia6_flags? */
+ }
+ if (ifa == NULL) {
+ /*
+ * This can still happen, when, for example, we receive an RA
+ * containing a prefix with the L bit set and the A bit clear,
+ * after removing all IPv6 addresses on the receiving
+ * interface. This should, of course, be rare though.
+ */
+ nd6log((LOG_NOTICE,
+ "nd6_prefix_onlink: failed to find any ifaddr"
+ " to add route for a prefix(%s/%d) on %s\n",
+ ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
+ pr->ndpr_plen, if_name(ifp)));
+ return(0);
+ }
+
+ /*
+ * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
+ * ifa->ifa_rtrequest = nd6_rtrequest;
+ */
+ bzero(&mask6, sizeof(mask6));
+ mask6.sin6_len = sizeof(mask6);
+ mask6.sin6_addr = pr->ndpr_mask;
+ rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP;
+ if (nd6_need_cache(ifp)) {
+ /* explicitly set in case ifa_flags does not set the flag. */
+ rtflags |= RTF_CLONING;
+ } else {
+ /*
+ * explicitly clear the cloning bit in case ifa_flags sets it.
+ */
+ rtflags &= ~RTF_CLONING;
+ }
+ error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
+ ifa->ifa_addr, (struct sockaddr *)&mask6,
+ rtflags, &rt);
+ if (error == 0) {
+ if (rt != NULL) /* this should be non NULL, though */
+ nd6_rtmsg(RTM_ADD, rt);
+ pr->ndpr_stateflags |= NDPRF_ONLINK;
+ }
+ else {
+ nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a"
+ " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx "
+ "errno = %d\n",
+ ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
+ pr->ndpr_plen, if_name(ifp),
+ ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
+ ip6_sprintf(&mask6.sin6_addr), rtflags, error));
+ }
+
+ if (rt != NULL)
+ rt->rt_refcnt--;
+
+ return(error);
+}
+
+int
+nd6_prefix_offlink(pr)
+ struct nd_prefix *pr;
+{
+ int error = 0;
+ struct ifnet *ifp = pr->ndpr_ifp;
+ struct nd_prefix *opr;
+ struct sockaddr_in6 sa6, mask6;
+ struct rtentry *rt = NULL;
+
+ /* sanity check */
+ if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
+ nd6log((LOG_ERR,
+ "nd6_prefix_offlink: %s/%d is already off-link\n",
+ ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen));
+ return(EEXIST);
+ }
+
bzero(&sa6, sizeof(sa6));
sa6.sin6_family = AF_INET6;
sa6.sin6_len = sizeof(sa6);
@@ -1157,103 +1526,113 @@ nd6_detach_prefix(pr)
mask6.sin6_family = AF_INET6;
mask6.sin6_len = sizeof(sa6);
bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
- {
- int e;
+ error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
+ (struct sockaddr *)&mask6, 0, &rt);
+ if (error == 0) {
+ pr->ndpr_stateflags &= ~NDPRF_ONLINK;
- e = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
- (struct sockaddr *)&mask6, 0, NULL);
- if (e) {
- log(LOG_ERR,
- "nd6_detach_prefix: failed to delete route: "
- "%s/%d (errno = %d)\n",
- ip6_sprintf(&sa6.sin6_addr),
- pr->ndpr_plen,
- e);
- }
- }
+ /* report the route deletion to the routing socket. */
+ if (rt != NULL)
+ nd6_rtmsg(RTM_DELETE, rt);
- /*
- * Mark the address derived from the prefix detached so that
- * it won't be used as a source address for a new connection.
- */
- if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
- ia6 = NULL;
- else
- ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
- if (ia6)
- ia6->ia6_flags |= IN6_IFF_DETACHED;
-}
+ /*
+ * There might be the same prefix on another interface,
+ * the prefix which could not be on-link just because we have
+ * the interface route (see comments in nd6_prefix_onlink).
+ * If there's one, try to make the prefix on-link on the
+ * interface.
+ */
+ for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
+ if (opr == pr)
+ continue;
-static void
-nd6_attach_prefix(pr)
- struct nd_prefix *pr;
-{
- struct ifaddr *ifa;
- struct in6_ifaddr *ia6;
+ if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0)
+ continue;
- /*
- * Add the interface route associated with the prefix(if necessary)
- * Should we consider if the L bit is set in pr->ndpr_flags?
- */
- ifa = ifaof_ifpforaddr((struct sockaddr *)&pr->ndpr_prefix,
- pr->ndpr_ifp);
- if (ifa == NULL) {
- log(LOG_ERR,
- "nd6_attach_prefix: failed to find any ifaddr"
- " to add route for a prefix(%s/%d)\n",
- ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen);
+ /*
+ * KAME specific: detached prefixes should not be
+ * on-link.
+ */
+ if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0)
+ continue;
+
+ if (opr->ndpr_plen == pr->ndpr_plen &&
+ in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
+ &opr->ndpr_prefix.sin6_addr,
+ pr->ndpr_plen)) {
+ int e;
+
+ if ((e = nd6_prefix_onlink(opr)) != 0) {
+ nd6log((LOG_ERR,
+ "nd6_prefix_offlink: failed to "
+ "recover a prefix %s/%d from %s "
+ "to %s (errno = %d)\n",
+ ip6_sprintf(&opr->ndpr_prefix.sin6_addr),
+ opr->ndpr_plen, if_name(ifp),
+ if_name(opr->ndpr_ifp), e));
+ }
+ }
+ }
}
else {
- int e;
- struct sockaddr_in6 mask6;
-
- bzero(&mask6, sizeof(mask6));
- mask6.sin6_family = AF_INET6;
- mask6.sin6_len = sizeof(mask6);
- mask6.sin6_addr = pr->ndpr_mask;
- e = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
- ifa->ifa_addr, (struct sockaddr *)&mask6,
- ifa->ifa_flags, NULL);
- if (e == 0)
- pr->ndpr_statef_onlink = 1;
- else {
- log(LOG_ERR,
- "nd6_attach_prefix: failed to add route for"
- " a prefix(%s/%d), errno = %d\n",
- ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen, e);
- }
+ /* XXX: can we still set the NDPRF_ONLINK flag? */
+ nd6log((LOG_ERR,
+ "nd6_prefix_offlink: failed to delete route: "
+ "%s/%d on %s (errno = %d)\n",
+ ip6_sprintf(&sa6.sin6_addr), pr->ndpr_plen, if_name(ifp),
+ error));
}
- /*
- * Now the address derived from the prefix can be used as a source
- * for a new connection, so clear the detached flag.
- */
- if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
- ia6 = NULL;
- else
- ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
- if (ia6) {
- ia6->ia6_flags &= ~IN6_IFF_DETACHED;
- if (pr->ndpr_statef_onlink)
- ia6->ia_flags |= IFA_ROUTE;
+ if (rt != NULL) {
+ if (rt->rt_refcnt <= 0) {
+ /* XXX: we should free the entry ourselves. */
+ rt->rt_refcnt++;
+ rtfree(rt);
+ }
}
+
+ return(error);
}
static struct in6_ifaddr *
-in6_ifadd(ifp, in6, addr, prefixlen)
- struct ifnet *ifp;
- struct in6_addr *in6;
- struct in6_addr *addr;
- int prefixlen; /* prefix len of the new prefix in "in6" */
+in6_ifadd(pr, ifid)
+ struct nd_prefix *pr;
+ struct in6_addr *ifid; /* Mobile IPv6 addition */
{
+ struct ifnet *ifp = pr->ndpr_ifp;
struct ifaddr *ifa;
- struct in6_ifaddr *ia, *ib, *oia;
- int s, error;
+ struct in6_aliasreq ifra;
+ struct in6_ifaddr *ia, *ib;
+ int error, plen0;
struct in6_addr mask;
+ int prefixlen = pr->ndpr_plen;
in6_len2mask(&mask, prefixlen);
- /* find link-local address (will be interface ID) */
+ /*
+ * find a link-local address (will be interface ID).
+ * Is it really mandatory? Theoretically, a global or a site-local
+ * address can be configured without a link-local address, if we
+ * have a unique interface identifier...
+ *
+ * it is not mandatory to have a link-local address, we can generate
+ * interface identifier on the fly. we do this because:
+ * (1) it should be the easiest way to find interface identifier.
+ * (2) RFC2462 5.4 suggesting the use of the same interface identifier
+ * for multiple addresses on a single interface, and possible shortcut
+ * of DAD. we omitted DAD for this reason in the past.
+ * (3) a user can prevent autoconfiguration of global address
+ * by removing link-local address by hand (this is partly because we
+ * don't have other way to control the use of IPv6 on a interface.
+ * this has been our design choice - cf. NRL's "ifconfig auto").
+ * (4) it is easier to manage when an interface has addresses
+ * with the same interface identifier, than to have multiple addresses
+ * with different interface identifiers.
+ *
+ * Mobile IPv6 addition: allow for caller to specify a wished interface
+ * ID. This is to not break connections when moving addresses between
+ * interfaces.
+ */
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);/* 0 is OK? */
if (ifa)
ib = (struct in6_ifaddr *)ifa;
@@ -1269,204 +1648,199 @@ in6_ifadd(ifp, in6, addr, prefixlen)
#endif
/* prefixlen + ifidlen must be equal to 128 */
- if (prefixlen != in6_mask2len(&ib->ia_prefixmask.sin6_addr)) {
- log(LOG_ERR, "in6_ifadd: wrong prefixlen for %s"
- "(prefix=%d ifid=%d)\n", if_name(ifp),
- prefixlen,
- 128 - in6_mask2len(&ib->ia_prefixmask.sin6_addr));
+ plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL);
+ if (prefixlen != plen0) {
+ nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s "
+ "(prefix=%d ifid=%d)\n",
+ if_name(ifp), prefixlen, 128 - plen0));
return NULL;
}
/* make ifaddr */
- ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_DONTWAIT);
- if (ia == NULL) {
- printf("ENOBUFS in in6_ifadd %d\n", __LINE__);
- return NULL;
- }
- bzero((caddr_t)ia, sizeof(*ia));
- ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
- if (ifp->if_flags & IFF_POINTOPOINT)
- ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
- else
- ia->ia_ifa.ifa_dstaddr = NULL;
- ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
- ia->ia_ifp = ifp;
-
- /* link to in6_ifaddr */
- if ((oia = in6_ifaddr) != NULL) {
- for( ; oia->ia_next; oia = oia->ia_next)
- continue;
- oia->ia_next = ia;
- } else {
- /*
- * This should be impossible, since we have at least one
- * link-local address (see the beginning of this function).
- * XXX: should we rather panic here?
- */
- printf("in6_ifadd: in6_ifaddr is NULL (impossible!)\n");
- in6_ifaddr = ia;
- }
- /* gain a refcnt for the link from in6_ifaddr */
- ia->ia_ifa.ifa_refcnt++;
-
- /* link to if_addrlist */
- TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
- /* gain another refcnt for the link from if_addrlist */
- ia->ia_ifa.ifa_refcnt++;
-
- /* new address */
- ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
- ia->ia_addr.sin6_family = AF_INET6;
+ bzero(&ifra, sizeof(ifra));
+ /*
+ * in6_update_ifa() does not use ifra_name, but we accurately set it
+ * for safety.
+ */
+ strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
+ ifra.ifra_addr.sin6_family = AF_INET6;
+ ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
/* prefix */
- bcopy(in6, &ia->ia_addr.sin6_addr, sizeof(ia->ia_addr.sin6_addr));
- ia->ia_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
- ia->ia_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
- ia->ia_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
- ia->ia_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
- /* interface ID */
- ia->ia_addr.sin6_addr.s6_addr32[0]
- |= (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]);
- ia->ia_addr.sin6_addr.s6_addr32[1]
- |= (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]);
- ia->ia_addr.sin6_addr.s6_addr32[2]
- |= (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
- ia->ia_addr.sin6_addr.s6_addr32[3]
- |= (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
-
- /* new prefix */
- ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
- ia->ia_prefixmask.sin6_family = AF_INET6;
- bcopy(&mask, &ia->ia_prefixmask.sin6_addr,
- sizeof(ia->ia_prefixmask.sin6_addr));
-
- /* same routine */
- ia->ia_ifa.ifa_rtrequest =
- (ifp->if_type == IFT_PPP) ? nd6_p2p_rtrequest : nd6_rtrequest;
- ia->ia_ifa.ifa_flags |= RTF_CLONING;
- ia->ia_ifa.ifa_metric = ifp->if_metric;
-
- /* add interface route */
- if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP|RTF_CLONING))) {
- log(LOG_NOTICE, "in6_ifadd: failed to add an interface route "
- "for %s/%d on %s, errno = %d\n",
- ip6_sprintf(&ia->ia_addr.sin6_addr), prefixlen,
- if_name(ifp), error);
- } else
- ia->ia_flags |= IFA_ROUTE;
+ bcopy(&pr->ndpr_prefix.sin6_addr, &ifra.ifra_addr.sin6_addr,
+ sizeof(ifra.ifra_addr.sin6_addr));
+ ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
+ ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
+ ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
+ ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
- *addr = ia->ia_addr.sin6_addr;
+ /* interface ID */
+ if (ifid == NULL || IN6_IS_ADDR_UNSPECIFIED(ifid))
+ ifid = &ib->ia_addr.sin6_addr;
+ ifra.ifra_addr.sin6_addr.s6_addr32[0]
+ |= (ifid->s6_addr32[0] & ~mask.s6_addr32[0]);
+ ifra.ifra_addr.sin6_addr.s6_addr32[1]
+ |= (ifid->s6_addr32[1] & ~mask.s6_addr32[1]);
+ ifra.ifra_addr.sin6_addr.s6_addr32[2]
+ |= (ifid->s6_addr32[2] & ~mask.s6_addr32[2]);
+ ifra.ifra_addr.sin6_addr.s6_addr32[3]
+ |= (ifid->s6_addr32[3] & ~mask.s6_addr32[3]);
+
+ /* new prefix mask. */
+ ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
+ ifra.ifra_prefixmask.sin6_family = AF_INET6;
+ bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr,
+ sizeof(ifra.ifra_prefixmask.sin6_addr));
- if (ifp->if_flags & IFF_MULTICAST) {
- int error; /* not used */
- struct in6_addr sol6;
+ /*
+ * lifetime.
+ * XXX: in6_init_address_ltimes would override these values later.
+ * We should reconsider this logic.
+ */
+ ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime;
+ ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime;
- /* join solicited node multicast address */
- bzero(&sol6, sizeof(sol6));
- sol6.s6_addr16[0] = htons(0xff02);
- sol6.s6_addr16[1] = htons(ifp->if_index);
- sol6.s6_addr32[1] = 0;
- sol6.s6_addr32[2] = htonl(1);
- sol6.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
- sol6.s6_addr8[12] = 0xff;
- (void)in6_addmulti(&sol6, ifp, &error);
- }
+ /* XXX: scope zone ID? */
- ia->ia6_flags |= IN6_IFF_TENTATIVE;
+ ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */
+ /*
+ * temporarily set the nopfx flag to avoid conflict.
+ * XXX: we should reconsider the entire mechanism about prefix
+ * manipulation.
+ */
+ ifra.ifra_flags |= IN6_IFF_NOPFX;
/*
- * To make the interface up. Only AF_INET6 in ia is used...
+ * keep the new address, regardless of the result of in6_update_ifa.
+ * XXX: this address is now meaningless.
+ * We should reconsider its role.
*/
- s = splimp();
- if (ifp->if_ioctl && (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia)) {
- splx(s);
- return NULL;
+ pr->ndpr_addr = ifra.ifra_addr.sin6_addr;
+
+ /* allocate ifaddr structure, link into chain, etc. */
+ if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
+ nd6log((LOG_ERR,
+ "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n",
+ ip6_sprintf(&ifra.ifra_addr.sin6_addr), if_name(ifp),
+ error));
+ return(NULL); /* ifaddr must not have been allocated. */
}
- splx(s);
- /* Perform DAD, if needed. */
- nd6_dad_start((struct ifaddr *)ia, NULL);
+ ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
- return ia;
+ return(ia); /* this must NOT be NULL. */
}
int
-in6_ifdel(ifp, in6)
- struct ifnet *ifp;
- struct in6_addr *in6;
+in6_tmpifadd(ia0, forcegen)
+ const struct in6_ifaddr *ia0; /* corresponding public address */
{
- struct in6_ifaddr *ia = (struct in6_ifaddr *)NULL;
- struct in6_ifaddr *oia = (struct in6_ifaddr *)NULL;
+ struct ifnet *ifp = ia0->ia_ifa.ifa_ifp;
+ struct in6_ifaddr *newia;
+ struct in6_aliasreq ifra;
+ int i, error;
+ int trylimit = 3; /* XXX: adhoc value */
+ u_int32_t randid[2];
+ time_t vltime0, pltime0;
+
+ bzero(&ifra, sizeof(ifra));
+ strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
+ ifra.ifra_addr = ia0->ia_addr;
+ /* copy prefix mask */
+ ifra.ifra_prefixmask = ia0->ia_prefixmask;
+ /* clear the old IFID */
+ for (i = 0; i < 4; i++) {
+ ifra.ifra_addr.sin6_addr.s6_addr32[i]
+ &= ifra.ifra_prefixmask.sin6_addr.s6_addr32[i];
+ }
- if (!ifp)
- return -1;
+ again:
+ in6_get_tmpifid(ifp, (u_int8_t *)randid,
+ (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8],
+ forcegen);
+ ifra.ifra_addr.sin6_addr.s6_addr32[2]
+ |= (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2]));
+ ifra.ifra_addr.sin6_addr.s6_addr32[3]
+ |= (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3]));
- ia = in6ifa_ifpwithaddr(ifp, in6);
- if (!ia)
- return -1;
+ /*
+ * If by chance the new temporary address is the same as an address
+ * already assigned to the interface, generate a new randomized
+ * interface identifier and repeat this step.
+ * RFC 3041 3.3 (4).
+ */
+ if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) {
+ if (trylimit-- == 0) {
+ nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find "
+ "a unique random IFID\n"));
+ return(EEXIST);
+ }
+ forcegen = 1;
+ goto again;
+ }
- if (ifp->if_flags & IFF_MULTICAST) {
- /*
- * delete solicited multicast addr for deleting host id
- */
- struct in6_multi *in6m;
- struct in6_addr llsol;
- bzero(&llsol, sizeof(struct in6_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_addr32[3] =
- ia->ia_addr.sin6_addr.s6_addr32[3];
- llsol.s6_addr8[12] = 0xff;
-
- IN6_LOOKUP_MULTI(llsol, ifp, in6m);
- if (in6m)
- in6_delmulti(in6m);
- }
-
- if (ia->ia_flags & IFA_ROUTE) {
- rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
- ia->ia_flags &= ~IFA_ROUTE;
- }
-
- TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
- IFAFREE(&ia->ia_ifa);
-
- /* lladdr is never deleted */
- oia = ia;
- if (oia == (ia = in6_ifaddr))
- in6_ifaddr = ia->ia_next;
- else {
- while (ia->ia_next && (ia->ia_next != oia))
- ia = ia->ia_next;
- if (ia->ia_next)
- ia->ia_next = oia->ia_next;
- else
- return -1;
+ /*
+ * The Valid Lifetime is the lower of the Valid Lifetime of the
+ * public address or TEMP_VALID_LIFETIME.
+ * The Preferred Lifetime is the lower of the Preferred Lifetime
+ * of the public address or TEMP_PREFERRED_LIFETIME -
+ * DESYNC_FACTOR.
+ */
+ if (ia0->ia6_lifetime.ia6t_expire != 0) {
+ vltime0 = IFA6_IS_INVALID(ia0) ? 0 :
+ (ia0->ia6_lifetime.ia6t_expire - time_second);
+ if (vltime0 > ip6_temp_valid_lifetime)
+ vltime0 = ip6_temp_valid_lifetime;
+ } else
+ vltime0 = ip6_temp_valid_lifetime;
+ if (ia0->ia6_lifetime.ia6t_preferred != 0) {
+ pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 :
+ (ia0->ia6_lifetime.ia6t_preferred - time_second);
+ if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){
+ pltime0 = ip6_temp_preferred_lifetime -
+ ip6_desync_factor;
+ }
+ } else
+ pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor;
+ ifra.ifra_lifetime.ia6t_vltime = vltime0;
+ ifra.ifra_lifetime.ia6t_pltime = pltime0;
+
+ /*
+ * A temporary address is created only if this calculated Preferred
+ * Lifetime is greater than REGEN_ADVANCE time units.
+ */
+ if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance)
+ return(0);
+
+ /* XXX: scope zone ID? */
+
+ ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY);
+
+ /* allocate ifaddr structure, link into chain, etc. */
+ if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0)
+ return(error);
+
+ newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
+ if (newia == NULL) { /* XXX: can it happen? */
+ nd6log((LOG_ERR,
+ "in6_tmpifadd: ifa update succeeded, but we got "
+ "no ifaddr\n"));
+ return(EINVAL); /* XXX */
}
+ newia->ia6_ndpr = ia0->ia6_ndpr;
+ newia->ia6_ndpr->ndpr_refcnt++;
- IFAFREE((&oia->ia_ifa));
-/* xxx
- rtrequest(RTM_DELETE,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)0
- (struct sockaddr *)&ia->ia_prefixmask,
- RTF_UP|RTF_CLONING,
- (struct rtentry **)0);
-*/
- return 0;
-}
+ return(0);
+}
int
in6_init_prefix_ltimes(struct nd_prefix *ndpr)
{
-
- /* check if preferred lifetime > valid lifetime */
+ /* check if preferred lifetime > valid lifetime. RFC2462 5.5.3 (c) */
if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) {
- log(LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime"
+ nd6log((LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime"
"(%d) is greater than valid lifetime(%d)\n",
- (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime);
+ (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime));
return (EINVAL);
}
if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
@@ -1482,24 +1856,15 @@ in6_init_prefix_ltimes(struct nd_prefix *ndpr)
}
static void
-in6_init_address_ltimes(struct nd_prefix *new,
- struct in6_addrlifetime *lt6,
- int update_vltime)
+in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
{
-
/* Valid lifetime must not be updated unless explicitly specified. */
- if (update_vltime) {
- /* init ia6t_expire */
- if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
- lt6->ia6t_expire = 0;
- else {
- lt6->ia6t_expire = time_second;
- lt6->ia6t_expire += lt6->ia6t_vltime;
- }
- /* Ensure addr lifetime <= prefix lifetime. */
- if (new->ndpr_expire && lt6->ia6t_expire &&
- new->ndpr_expire < lt6->ia6t_expire)
- lt6->ia6t_expire = new->ndpr_expire;
+ /* init ia6t_expire */
+ if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
+ lt6->ia6t_expire = 0;
+ else {
+ lt6->ia6t_expire = time_second;
+ lt6->ia6t_expire += lt6->ia6t_vltime;
}
/* init ia6t_preferred */
@@ -1509,10 +1874,6 @@ in6_init_address_ltimes(struct nd_prefix *new,
lt6->ia6t_preferred = time_second;
lt6->ia6t_preferred += lt6->ia6t_pltime;
}
- /* Ensure addr lifetime <= prefix lifetime. */
- if (new->ndpr_preferred && lt6->ia6t_preferred
- && new->ndpr_preferred < lt6->ia6t_preferred)
- lt6->ia6t_preferred = new->ndpr_preferred;
}
/*
@@ -1522,8 +1883,8 @@ in6_init_address_ltimes(struct nd_prefix *new,
*/
void
rt6_flush(gateway, ifp)
- struct in6_addr *gateway;
- struct ifnet *ifp;
+ struct in6_addr *gateway;
+ struct ifnet *ifp;
{
struct radix_node_head *rnh = rt_tables[AF_INET6];
int s = splnet();
@@ -1556,6 +1917,14 @@ rt6_deleteroute(rn, arg)
return(0);
/*
+ * Do not delete a static route.
+ * XXX: this seems to be a bit ad-hoc. Should we consider the
+ * 'cloned' bit instead?
+ */
+ if ((rt->rt_flags & RTF_STATIC) != 0)
+ return(0);
+
+ /*
* We delete only host route. This means, in particular, we don't
* delete default route.
*/
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 42f38fd..eda8bfa 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -65,6 +65,7 @@
*/
#include "opt_ipsec.h"
+#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/malloc.h>
@@ -94,6 +95,7 @@
#ifdef ENABLE_DEFAULT_SCOPE
#include <netinet6/scope6_var.h>
#endif
+#include <netinet6/raw_ip6.h>
#ifdef IPSEC
#include <netinet6/ipsec.h>
@@ -103,6 +105,9 @@
#include <machine/stdarg.h>
#include "faith.h"
+#if defined(NFAITH) && 0 < NFAITH
+#include <net/if_faith.h>
+#endif
#define satosin6(sa) ((struct sockaddr_in6 *)(sa))
#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
@@ -116,6 +121,8 @@ extern struct inpcbinfo ripcbinfo;
extern u_long rip_sendspace;
extern u_long rip_recvspace;
+struct rip6stat rip6stat;
+
/*
* Setup generic address and protocol structures
* for raw_input routine, then pass them along with
@@ -130,18 +137,19 @@ rip6_input(mp, offp, proto)
register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
register struct inpcb *in6p;
struct inpcb *last = 0;
- struct mbuf *opts = 0;
+ struct mbuf *opts = NULL;
struct sockaddr_in6 rip6src;
+ rip6stat.rip6s_ipackets++;
+
#if defined(NFAITH) && 0 < NFAITH
- if (m->m_pkthdr.rcvif) {
- if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
- /* XXX send icmp6 host/port unreach? */
- m_freem(m);
- return IPPROTO_DONE;
- }
+ if (faithprefix(&ip6->ip6_dst)) {
+ /* XXX send icmp6 host/port unreach? */
+ m_freem(m);
+ return IPPROTO_DONE;
}
#endif
+
init_sin6(&rip6src, m); /* general init */
LIST_FOREACH(in6p, &ripcb, inp_list) {
@@ -156,14 +164,27 @@ rip6_input(mp, offp, proto)
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
continue;
- if (in6p->in6p_cksum != -1
- && in6_cksum(m, ip6->ip6_nxt, *offp,
- m->m_pkthdr.len - *offp)) {
- /* XXX bark something */
- continue;
+ if (in6p->in6p_cksum != -1) {
+ rip6stat.rip6s_isum++;
+ if (in6_cksum(m, ip6->ip6_nxt, *offp,
+ m->m_pkthdr.len - *offp)) {
+ rip6stat.rip6s_badsum++;
+ continue;
+ }
}
if (last) {
struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
+
+#ifdef IPSEC
+ /*
+ * Check AH/ESP integrity.
+ */
+ if (n && ipsec6_in_reject_so(n, last->inp_socket)) {
+ m_freem(n);
+ ipsec6stat.in_polvio++;
+ /* do not inject data into pcb */
+ } else
+#endif /*IPSEC*/
if (n) {
if (last->in6p_flags & IN6P_CONTROLOPTS ||
last->in6p_socket->so_options & SO_TIMESTAMP)
@@ -173,10 +194,10 @@ rip6_input(mp, offp, proto)
if (sbappendaddr(&last->in6p_socket->so_rcv,
(struct sockaddr *)&rip6src,
n, opts) == 0) {
- /* should notify about lost packet */
m_freem(n);
if (opts)
m_freem(opts);
+ rip6stat.rip6s_fullsock++;
} else
sorwakeup(last->in6p_socket);
opts = NULL;
@@ -184,6 +205,17 @@ rip6_input(mp, offp, proto)
}
last = in6p;
}
+#ifdef IPSEC
+ /*
+ * Check AH/ESP integrity.
+ */
+ if (last && ipsec6_in_reject_so(m, last->inp_socket)) {
+ m_freem(m);
+ ipsec6stat.in_polvio++;
+ ip6stat.ip6s_delivered--;
+ /* do not inject data into pcb */
+ } else
+#endif /*IPSEC*/
if (last) {
if (last->in6p_flags & IN6P_CONTROLOPTS ||
last->in6p_socket->so_options & SO_TIMESTAMP)
@@ -195,9 +227,13 @@ rip6_input(mp, offp, proto)
m_freem(m);
if (opts)
m_freem(opts);
+ rip6stat.rip6s_fullsock++;
} else
sorwakeup(last->in6p_socket);
} else {
+ rip6stat.rip6s_nosock++;
+ if (m->m_flags & M_MCAST)
+ rip6stat.rip6s_nosockmcast++;
if (proto == IPPROTO_NONE)
m_freem(m);
else {
@@ -217,10 +253,11 @@ rip6_ctlinput(cmd, sa, d)
struct sockaddr *sa;
void *d;
{
- struct sockaddr_in6 sa6;
struct ip6_hdr *ip6;
struct mbuf *m;
int off = 0;
+ struct ip6ctlparam *ip6cp = NULL;
+ const struct sockaddr_in6 *sa6_src = NULL;
void (*notify) __P((struct inpcb *, int)) = in6_rtchange;
if (sa->sa_family != AF_INET6 ||
@@ -238,37 +275,19 @@ rip6_ctlinput(cmd, sa, d)
/* if the parameter is from icmp6, decode it. */
if (d != NULL) {
- struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
+ ip6cp = (struct ip6ctlparam *)d;
m = ip6cp->ip6c_m;
ip6 = ip6cp->ip6c_ip6;
off = ip6cp->ip6c_off;
+ sa6_src = ip6cp->ip6c_src;
} else {
m = NULL;
ip6 = NULL;
+ sa6_src = &sa6_any;
}
- /* translate addresses into internal form */
- sa6 = *(struct sockaddr_in6 *)sa;
- if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif)
- sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
-
- if (ip6) {
- /*
- * XXX: We assume that when IPV6 is non NULL,
- * M and OFF are valid.
- */
- struct in6_addr s;
-
- /* translate addresses into internal form */
- memcpy(&s, &ip6->ip6_src, sizeof(s));
- if (IN6_IS_ADDR_LINKLOCAL(&s))
- s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
-
- (void) in6_pcbnotify(&ripcb, (struct sockaddr *)&sa6,
- 0, &s, 0, cmd, notify);
- } else
- (void) in6_pcbnotify(&ripcb, (struct sockaddr *)&sa6, 0,
- &zeroin6_addr, 0, cmd, notify);
+ (void) in6_pcbnotify(&ripcb, sa, 0, (struct sockaddr *)sa6_src,
+ 0, cmd, notify);
}
/*
@@ -311,7 +330,7 @@ rip6_output(m, va_alist)
priv = 1;
dst = &dstsock->sin6_addr;
if (control) {
- if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
+ if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0)
goto bad;
optp = &opt;
} else
@@ -431,7 +450,10 @@ rip6_output(m, va_alist)
}
#ifdef IPSEC
- ipsec_setsocket(m, so);
+ if (ipsec_setsocket(m, so) != 0) {
+ error = ENOBUFS;
+ goto bad;
+ }
#endif /*IPSEC*/
error = ip6_output(m, optp, &in6p->in6p_route, 0,
@@ -440,7 +462,8 @@ rip6_output(m, va_alist)
if (oifp)
icmp6_ifoutstat_inc(oifp, type, code);
icmp6stat.icp6s_outhist[type]++;
- }
+ } else
+ rip6stat.rip6s_opackets++;
goto freectl;
@@ -451,8 +474,11 @@ rip6_output(m, va_alist)
freectl:
if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt)
RTFREE(optp->ip6po_route.ro_rt);
- if (control)
+ if (control) {
+ if (optp == &opt)
+ ip6_clearpktopts(optp, 0, -1);
m_freem(control);
+ }
return(error);
}
diff --git a/sys/netinet6/raw_ip6.h b/sys/netinet6/raw_ip6.h
new file mode 100644
index 0000000..cfb390b
--- /dev/null
+++ b/sys/netinet6/raw_ip6.h
@@ -0,0 +1,54 @@
+/* $FreeBSD$ */
+/* $KAME: raw_ip6.h,v 1.2 2001/05/27 13:28:35 itojun Exp $ */
+
+/*
+ * Copyright (C) 2001 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.
+ */
+
+#ifndef _NETINET6_RAW_IP6_H_
+#define _NETINET6_RAW_IP6_H_
+
+/*
+ * ICMPv6 stat is counted separately. see netinet/icmp6.h
+ */
+struct rip6stat {
+ u_quad_t rip6s_ipackets; /* total input packets */
+ u_quad_t rip6s_isum; /* input checksum computations */
+ u_quad_t rip6s_badsum; /* of above, checksum error */
+ u_quad_t rip6s_nosock; /* no matching socket */
+ u_quad_t rip6s_nosockmcast; /* of above, arrived as multicast */
+ u_quad_t rip6s_fullsock; /* not delivered, input socket full */
+
+ u_quad_t rip6s_opackets; /* total output packets */
+};
+
+#ifdef _KERNEL
+extern struct rip6stat rip6stat;
+#endif
+
+#endif
diff --git a/sys/netinet6/route6.c b/sys/netinet6/route6.c
index 3cd95a1..807c6ad 100644
--- a/sys/netinet6/route6.c
+++ b/sys/netinet6/route6.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: route6.c,v 1.15 2000/06/23 16:18:20 itojun Exp $ */
+/* $KAME: route6.c,v 1.24 2001/03/14 03:07:05 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -37,6 +37,7 @@
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/systm.h>
+#include <sys/queue.h>
#include <net/if.h>
@@ -55,10 +56,22 @@ route6_input(mp, offp, proto)
struct mbuf **mp;
int *offp, proto; /* proto is unused */
{
- register struct ip6_hdr *ip6;
- register struct mbuf *m = *mp;
- register struct ip6_rthdr *rh;
+ struct ip6_hdr *ip6;
+ struct mbuf *m = *mp;
+ struct ip6_rthdr *rh;
int off = *offp, rhlen;
+ struct mbuf *n;
+
+ n = ip6_findaux(m);
+ if (n) {
+ struct ip6aux *ip6a = mtod(n, struct ip6aux *);
+ /* XXX reject home-address option before rthdr */
+ if (ip6a->ip6a_flags & IP6A_SWAP) {
+ ip6stat.ip6s_badoptions++;
+ m_freem(m);
+ return IPPROTO_DONE;
+ }
+ }
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, sizeof(*rh), IPPROTO_DONE);
@@ -119,6 +132,9 @@ route6_input(mp, offp, proto)
/*
* Type0 routing header processing
+ *
+ * RFC2292 backward compatibility warning: no support for strict/loose bitmap,
+ * as it was dropped between RFC1883 and RFC2460.
*/
static int
ip6_rthdr0(m, ip6, rh0)
@@ -176,7 +192,7 @@ ip6_rthdr0(m, ip6, rh0)
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst) ||
IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst) ||
- IN6_IS_ADDR_V4COMPAT(nextaddr)) {
+ IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) {
ip6stat.ip6s_badoptions++;
m_freem(m);
return(-1);
diff --git a/sys/netinet6/scope6.c b/sys/netinet6/scope6.c
index 43a6fb7..09bba0c 100644
--- a/sys/netinet6/scope6.c
+++ b/sys/netinet6/scope6.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: scope6.c,v 1.9 2000/05/18 15:03:26 jinmei Exp $ */
+/* $KAME: scope6.c,v 1.10 2000/07/24 13:29:31 itojun Exp $ */
/*
* Copyright (C) 2000 WIDE Project.
@@ -35,6 +35,7 @@
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/systm.h>
+#include <sys/queue.h>
#include <net/route.h>
#include <net/if.h>
diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c
index ee05019..fd4d6f3 100644
--- a/sys/netinet6/udp6_output.c
+++ b/sys/netinet6/udp6_output.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: udp6_output.c,v 1.14 2000/06/13 10:31:23 itojun Exp $ */
+/* $KAME: udp6_output.c,v 1.31 2001/05/21 16:39:15 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -69,6 +69,7 @@
#include "opt_inet.h"
#include <sys/param.h>
+#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
@@ -120,22 +121,22 @@
int
udp6_output(in6p, m, addr6, control, p)
- register struct in6pcb *in6p;
- register struct mbuf *m;
+ struct in6pcb *in6p;
+ struct mbuf *m;
struct mbuf *control;
struct sockaddr *addr6;
struct proc *p;
{
- register u_int32_t ulen = m->m_pkthdr.len;
+ u_int32_t ulen = m->m_pkthdr.len;
u_int32_t plen = sizeof(struct udphdr) + ulen;
struct ip6_hdr *ip6;
struct udphdr *udp6;
- struct in6_addr *laddr, *faddr;
+ struct in6_addr *laddr, *faddr;
u_short fport;
int error = 0;
struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
int priv;
- int af, hlen;
+ int af = AF_INET6, hlen = sizeof(struct ip6_hdr);
int flags;
struct sockaddr_in6 tmp;
@@ -143,7 +144,7 @@ udp6_output(in6p, m, addr6, control, p)
if (p && !suser(p))
priv = 1;
if (control) {
- if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
+ if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0)
goto release;
in6p->in6p_outputopts = &opt;
}
@@ -164,6 +165,7 @@ udp6_output(in6p, m, addr6, control, p)
}
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
+ /* how about ::ffff:0.0.0.0 case? */
error = EISCONN;
goto release;
}
@@ -175,6 +177,24 @@ udp6_output(in6p, m, addr6, control, p)
faddr = &sin6->sin6_addr;
fport = sin6->sin6_port; /* allow 0 port */
+ if (IN6_IS_ADDR_V4MAPPED(faddr)) {
+ if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) {
+ /*
+ * I believe we should explicitly discard the
+ * packet when mapped addresses are disabled,
+ * rather than send the packet as an IPv6 one.
+ * If we chose the latter approach, the packet
+ * might be sent out on the wire based on the
+ * default route, the situation which we'd
+ * probably want to avoid.
+ * (20010421 jinmei@kame.net)
+ */
+ error = EINVAL;
+ goto release;
+ } else
+ af = AF_INET;
+ }
+
/* KAME hack: embed scopeid */
if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0) {
error = EINVAL;
@@ -187,7 +207,7 @@ udp6_output(in6p, m, addr6, control, p)
&in6p->in6p_route,
&in6p->in6p_laddr, &error);
} else
- laddr = &in6p->in6p_laddr; /*XXX*/
+ laddr = &in6p->in6p_laddr; /* XXX */
if (laddr == NULL) {
if (error == 0)
error = EADDRNOTAVAIL;
@@ -201,18 +221,29 @@ udp6_output(in6p, m, addr6, control, p)
error = ENOTCONN;
goto release;
}
+ if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)) {
+ if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) {
+ /*
+ * XXX: this case would happen when the
+ * application sets the V6ONLY flag after
+ * connecting the foreign address.
+ * Such applications should be fixed,
+ * so we bark here.
+ */
+ log(LOG_INFO, "udp6_output: IPV6_V6ONLY "
+ "option was set for a connected socket\n");
+ error = EINVAL;
+ goto release;
+ } else
+ af = AF_INET;
+ }
laddr = &in6p->in6p_laddr;
faddr = &in6p->in6p_faddr;
fport = in6p->in6p_fport;
}
- if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
- af = AF_INET6;
- hlen = sizeof(struct ip6_hdr);
- } else {
- af = AF_INET;
+ if (af == AF_INET)
hlen = sizeof(struct ip);
- }
/*
* Calculate data length and get a mbuf
@@ -261,10 +292,13 @@ udp6_output(in6p, m, addr6, control, p)
udp6stat.udp6s_opackets++;
#ifdef IPSEC
- ipsec_setsocket(m, in6p->in6p_socket);
+ if (ipsec_setsocket(m, in6p->in6p_socket) != 0) {
+ error = ENOBUFS;
+ goto release;
+ }
#endif /*IPSEC*/
error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
- flags, in6p->in6p_moptions, NULL);
+ flags, in6p->in6p_moptions, NULL);
break;
case AF_INET:
error = EAFNOSUPPORT;
@@ -277,6 +311,7 @@ release:
releaseopt:
if (control) {
+ ip6_clearpktopts(in6p->in6p_outputopts, 0, -1);
in6p->in6p_outputopts = stickyopt;
m_freem(control);
}
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index ca9ce2f..bb5a38a 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: udp6_usrreq.c,v 1.17 2000/10/13 17:46:21 itojun Exp $ */
+/* $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -107,6 +107,9 @@
#endif /*IPSEC*/
#include "faith.h"
+#if defined(NFAITH) && NFAITH > 0
+#include <net/if_faith.h>
+#endif
/*
* UDP protocol inplementation.
@@ -149,25 +152,25 @@ udp6_input(mp, offp, proto)
register struct ip6_hdr *ip6;
register struct udphdr *uh;
register struct inpcb *in6p;
- struct mbuf *opts = 0;
+ struct mbuf *opts = NULL;
int off = *offp;
int plen, ulen;
struct sockaddr_in6 udp_in6;
+ IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
+
+ ip6 = mtod(m, struct ip6_hdr *);
+
#if defined(NFAITH) && 0 < NFAITH
- if (m->m_pkthdr.rcvif) {
- if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
- /* XXX send icmp6 host/port unreach? */
- m_freem(m);
- return IPPROTO_DONE;
- }
+ if (faithprefix(&ip6->ip6_dst)) {
+ /* XXX send icmp6 host/port unreach? */
+ m_freem(m);
+ return IPPROTO_DONE;
}
#endif
- udpstat.udps_ipackets++;
- IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
+ udpstat.udps_ipackets++;
- ip6 = mtod(m, struct ip6_hdr *);
plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6);
uh = (struct udphdr *)((caddr_t)ip6 + off);
ulen = ntohs((u_short)uh->uh_ulen);
@@ -274,6 +277,7 @@ udp6_input(mp, offp, proto)
|| last->in6p_socket->so_options & SO_TIMESTAMP)
ip6_savecontrol(last, &opts,
ip6, n);
+
m_adj(n, off + sizeof(struct udphdr));
if (sbappendaddr(&last->in6p_socket->so_rcv,
(struct sockaddr *)&udp_in6,
@@ -284,7 +288,7 @@ udp6_input(mp, offp, proto)
udpstat.udps_fullsock++;
} else
sorwakeup(last->in6p_socket);
- opts = 0;
+ opts = NULL;
}
}
last = in6p;
@@ -401,13 +405,17 @@ udp6_ctlinput(cmd, sa, d)
struct sockaddr *sa;
void *d;
{
- register struct udphdr *uhp;
struct udphdr uh;
- struct sockaddr_in6 sa6;
struct ip6_hdr *ip6;
struct mbuf *m;
int off = 0;
+ struct ip6ctlparam *ip6cp = NULL;
+ const struct sockaddr_in6 *sa6_src = NULL;
void (*notify) __P((struct inpcb *, int)) = udp_notify;
+ struct udp_portonly {
+ u_int16_t uh_sport;
+ u_int16_t uh_dport;
+ } *uhp;
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
@@ -424,51 +432,35 @@ udp6_ctlinput(cmd, sa, d)
/* if the parameter is from icmp6, decode it. */
if (d != NULL) {
- struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
+ ip6cp = (struct ip6ctlparam *)d;
m = ip6cp->ip6c_m;
ip6 = ip6cp->ip6c_ip6;
off = ip6cp->ip6c_off;
+ sa6_src = ip6cp->ip6c_src;
} else {
m = NULL;
ip6 = NULL;
+ sa6_src = &sa6_any;
}
- /* translate addresses into internal form */
- sa6 = *(struct sockaddr_in6 *)sa;
- if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif)
- sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
-
if (ip6) {
/*
* XXX: We assume that when IPV6 is non NULL,
* M and OFF are valid.
*/
- struct in6_addr s;
-
- /* translate addresses into internal form */
- memcpy(&s, &ip6->ip6_src, sizeof(s));
- if (IN6_IS_ADDR_LINKLOCAL(&s))
- s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
/* check if we can safely examine src and dst ports */
- if (m->m_pkthdr.len < off + sizeof(uh))
+ if (m->m_pkthdr.len < off + sizeof(*uhp))
return;
- if (m->m_len < off + sizeof(uh)) {
- /*
- * this should be rare case,
- * so we compromise on this copy...
- */
- m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
- uhp = &uh;
- } else
- uhp = (struct udphdr *)(mtod(m, caddr_t) + off);
- (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6,
- uhp->uh_dport, &s,
- uhp->uh_sport, cmd, notify);
+ bzero(&uh, sizeof(uh));
+ m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh);
+
+ (void) in6_pcbnotify(&udb, sa, uh.uh_dport, ip6cp->ip6c_src,
+ uh.uh_sport, cmd, notify);
} else
- (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6, 0,
- &zeroin6_addr, 0, cmd, notify);
+ (void) in6_pcbnotify(&udb, sa, 0, (struct sockaddr *)&sa6_src,
+ 0, cmd, notify);
}
static int
@@ -583,7 +575,7 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
inp->inp_vflag &= ~INP_IPV4;
inp->inp_vflag |= INP_IPV6;
- if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) {
+ if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
struct sockaddr_in6 *sin6_p;
sin6_p = (struct sockaddr_in6 *)nam;
@@ -618,7 +610,8 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
inp = sotoinpcb(so);
if (inp == 0)
return EINVAL;
- if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) {
+
+ if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
struct sockaddr_in6 *sin6_p;
sin6_p = (struct sockaddr_in6 *)nam;
@@ -644,15 +637,12 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
return EISCONN;
s = splnet();
error = in6_pcbconnect(inp, nam, p);
- if (ip6_auto_flowlabel) {
- inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
- inp->in6p_flowinfo |=
- (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK);
- }
splx(s);
if (error == 0) {
- inp->inp_vflag &= ~INP_IPV4;
- inp->inp_vflag |= INP_IPV6;
+ if (ip6_mapped_addr_on) { /* should be non mapped addr */
+ inp->inp_vflag &= ~INP_IPV4;
+ inp->inp_vflag |= INP_IPV6;
+ }
soisconnected(so);
}
return error;
diff --git a/sys/netkey/key.c b/sys/netkey/key.c
index 497695a..31dc63b 100644
--- a/sys/netkey/key.c
+++ b/sys/netkey/key.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: key.c,v 1.137 2000/06/24 00:47:07 itojun Exp $ */
+/* $KAME: key.c,v 1.187 2001/05/24 07:41:22 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -79,11 +79,7 @@
#include <netkey/keydb.h>
#include <netkey/key.h>
#include <netkey/keysock.h>
-#ifdef IPSEC_DEBUG
#include <netkey/key_debug.h>
-#else
-#define KEYDEBUG(lev,arg)
-#endif
#include <netinet6/ipsec.h>
#ifdef INET6
@@ -100,9 +96,15 @@
#endif
#endif
#include <netinet6/ipcomp.h>
+#ifdef INET6
+#include <netinet6/ipcomp6.h>
+#endif
#include <machine/stdarg.h>
+/* randomness */
+#include <sys/random.h>
+
#include <net/net_osdep.h>
#ifndef satosin
@@ -208,6 +210,10 @@ static const int maxsize[] = {
sizeof(struct sadb_x_sa2), /* SADB_X_SA2 */
};
+static int ipsec_esp_keymin = 256;
+static int ipsec_esp_auth = 0;
+static int ipsec_ah_keymin = 128;
+
#ifdef SYSCTL_DECL
SYSCTL_DECL(_net_key);
#endif
@@ -245,9 +251,13 @@ SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_COUNT, blockacq_count, CTLFLAG_RW, \
SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \
&key_blockacq_lifetime, 0, "");
-static const int ipsec_esp_keymin = 256;
-static const int ipsec_esp_auth = 0;
-static const int ipsec_ah_keymin = 128;
+/* minimum ESP key length */
+SYSCTL_INT(_net_key, KEYCTL_ESP_KEYMIN, esp_keymin, CTLFLAG_RW, \
+ &ipsec_esp_keymin, 0, "");
+
+/* minimum AH key length */
+SYSCTL_INT(_net_key, KEYCTL_AH_KEYMIN, ah_keymin, CTLFLAG_RW, \
+ &ipsec_ah_keymin, 0, "");
#ifndef LIST_FOREACH
#define LIST_FOREACH(elm, head, field) \
@@ -371,6 +381,7 @@ static int key_spddump __P((struct socket *, struct mbuf *,
static struct mbuf *key_setdumpsp __P((struct secpolicy *,
u_int8_t, u_int32_t, u_int32_t));
static u_int key_getspreqmsglen __P((struct secpolicy *));
+static int key_spdexpire __P((struct secpolicy *));
static struct secashead *key_newsah __P((struct secasindex *));
static void key_delsah __P((struct secashead *));
static struct secasvar *key_newsav __P((struct mbuf *,
@@ -404,6 +415,8 @@ static int key_cmpsaidx_exactly
__P((struct secasindex *, struct secasindex *));
static int key_cmpsaidx_withmode
__P((struct secasindex *, struct secasindex *));
+static int key_cmpsaidx_withoutmode2
+ __P((struct secasindex *, struct secasindex *));
static int key_cmpsaidx_withoutmode
__P((struct secasindex *, struct secasindex *));
static int key_cmpspidx_exactly
@@ -413,7 +426,6 @@ static int key_cmpspidx_withmask
static int key_sockaddrcmp __P((struct sockaddr *, struct sockaddr *, int));
static int key_bbcmp __P((caddr_t, caddr_t, u_int));
static void key_srandom __P((void));
-static u_long key_random __P((void));
static u_int16_t key_satype2proto __P((u_int8_t));
static u_int8_t key_proto2satype __P((u_int16_t));
@@ -437,10 +449,12 @@ static int key_delete __P((struct socket *, struct mbuf *,
static int key_get __P((struct socket *, struct mbuf *,
const struct sadb_msghdr *));
+static void key_getcomb_setlifetime __P((struct sadb_comb *));
#ifdef IPSEC_ESP
static struct mbuf *key_getcomb_esp __P((void));
#endif
static struct mbuf *key_getcomb_ah __P((void));
+static struct mbuf *key_getcomb_ipcomp __P((void));
static struct mbuf *key_getprop __P((const struct secasindex *));
static int key_acquire __P((struct secasindex *, struct secpolicy *));
@@ -485,6 +499,7 @@ key_allocsp(spidx, dir)
u_int dir;
{
struct secpolicy *sp;
+ struct timeval tv;
int s;
/* sanity check */
@@ -525,6 +540,8 @@ found:
KEY_CHKSPDIR(sp->spidx.dir, dir, "key_allocsp");
/* found a SPD entry */
+ microtime(&tv);
+ sp->lastused = tv.tv_sec;
sp->refcnt++;
splx(s);
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
@@ -535,8 +552,75 @@ found:
}
/*
- * allocating a SA entry for a *OUTBOUND* packet.
- * checking each request entries in SP, and acquire SA if need.
+ * return a policy that matches this particular inbound packet.
+ * XXX slow
+ */
+struct secpolicy *
+key_gettunnel(osrc, odst, isrc, idst)
+ struct sockaddr *osrc, *odst, *isrc, *idst;
+{
+ struct secpolicy *sp;
+ const int dir = IPSEC_DIR_INBOUND;
+ struct timeval tv;
+ int s;
+ struct ipsecrequest *r1, *r2, *p;
+ struct sockaddr *os, *od, *is, *id;
+ struct secpolicyindex spidx;
+
+ s = splnet(); /*called from softclock()*/
+ LIST_FOREACH(sp, &sptree[dir], chain) {
+ if (sp->state == IPSEC_SPSTATE_DEAD)
+ continue;
+
+ r1 = r2 = NULL;
+ for (p = sp->req; p; p = p->next) {
+ if (p->saidx.mode != IPSEC_MODE_TUNNEL)
+ continue;
+
+ r1 = r2;
+ r2 = p;
+
+ if (!r1) {
+ /* here we look at address matches only */
+ spidx = sp->spidx;
+ if (isrc->sa_len > sizeof(spidx.src) ||
+ idst->sa_len > sizeof(spidx.dst))
+ continue;
+ bcopy(isrc, &spidx.src, isrc->sa_len);
+ bcopy(idst, &spidx.dst, idst->sa_len);
+ if (!key_cmpspidx_withmask(&sp->spidx, &spidx))
+ continue;
+ } else {
+ is = (struct sockaddr *)&r1->saidx.src;
+ id = (struct sockaddr *)&r1->saidx.dst;
+ if (key_sockaddrcmp(is, isrc, 0) ||
+ key_sockaddrcmp(id, idst, 0))
+ continue;
+ }
+
+ os = (struct sockaddr *)&r2->saidx.src;
+ od = (struct sockaddr *)&r2->saidx.dst;
+ if (key_sockaddrcmp(os, osrc, 0) ||
+ key_sockaddrcmp(od, odst, 0))
+ continue;
+
+ goto found;
+ }
+ }
+ splx(s);
+ return NULL;
+
+found:
+ microtime(&tv);
+ sp->lastused = tv.tv_sec;
+ sp->refcnt++;
+ splx(s);
+ return sp;
+}
+
+/*
+ * allocating an SA entry for an *OUTBOUND* packet.
+ * checking each request entries in SP, and acquire an SA if need.
* OUT: 0: there are valid requests.
* ENOENT: policy may be valid, but SA with REQUIRE is on acquiring.
*/
@@ -987,7 +1071,7 @@ key_freesav(sav)
sav->refcnt--;
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
- printf("DP freesav cause refcnt--:%d SA:%p SPI %d\n",
+ printf("DP freesav cause refcnt--:%d SA:%p SPI %u\n",
sav->refcnt, sav, (u_int32_t)ntohl(sav->spi)));
if (sav->refcnt == 0)
@@ -1212,9 +1296,7 @@ key_msg2sp(xpl0, len, error)
switch (xisr->sadb_x_ipsecrequest_proto) {
case IPPROTO_ESP:
case IPPROTO_AH:
-#if 1 /*nonstandard*/
case IPPROTO_IPCOMP:
-#endif
break;
default:
#ifdef IPSEC_DEBUG
@@ -1534,11 +1616,11 @@ fail:
/*
* SADB_X_SPDADD, SADB_X_SPDSETIDX or SADB_X_SPDUPDATE processing
* add a entry to SP database, when received
- * <base, address(SD), policy>
+ * <base, address(SD), (lifetime(H),) policy>
* from the user(?).
* Adding to SP database,
* and send
- * <base, address(SD), policy>
+ * <base, address(SD), (lifetime(H),) policy>
* to the socket which was send.
*
* SPDADD set a unique policy entry.
@@ -1555,8 +1637,10 @@ key_spdadd(so, m, mhp)
{
struct sadb_address *src0, *dst0;
struct sadb_x_policy *xpl0, *xpl;
+ struct sadb_lifetime *lft = NULL;
struct secpolicyindex spidx;
struct secpolicy *newsp;
+ struct timeval tv;
int error;
/* sanity check */
@@ -1579,6 +1663,16 @@ key_spdadd(so, m, mhp)
#endif
return key_senderror(so, m, EINVAL);
}
+ if (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL) {
+ if (mhp->extlen[SADB_EXT_LIFETIME_HARD]
+ < sizeof(struct sadb_lifetime)) {
+#ifdef IPSEC_DEBUG
+ printf("key_spdadd: invalid message is passed.\n");
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+ lft = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_HARD];
+ }
src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
@@ -1702,6 +1796,12 @@ key_spdadd(so, m, mhp)
}
#endif
+ microtime(&tv);
+ newsp->created = tv.tv_sec;
+ newsp->lastused = tv.tv_sec;
+ newsp->lifetime = lft ? lft->sadb_lifetime_addtime : 0;
+ newsp->validtime = lft ? lft->sadb_lifetime_usetime : 0;
+
newsp->refcnt = 1; /* do not reclaim until I say I do */
newsp->state = IPSEC_SPSTATE_ALIVE;
LIST_INSERT_TAIL(&sptree[newsp->spidx.dir], newsp, secpolicy, chain);
@@ -1710,8 +1810,9 @@ key_spdadd(so, m, mhp)
if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) {
struct secspacq *spacq;
if ((spacq = key_getspacq(&spidx)) != NULL) {
- /* reset counter in order to deletion by timehander. */
- spacq->tick = key_blockacq_lifetime;
+ /* reset counter in order to deletion by timehandler. */
+ microtime(&tv);
+ spacq->created = tv.tv_sec;
spacq->count = 0;
}
}
@@ -1722,8 +1823,15 @@ key_spdadd(so, m, mhp)
int off;
/* create new sadb_msg to reply. */
- n = key_gather_mbuf(m, mhp, 2, 4, SADB_EXT_RESERVED,
- SADB_X_EXT_POLICY, SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST);
+ if (lft) {
+ n = key_gather_mbuf(m, mhp, 2, 4, SADB_EXT_RESERVED,
+ SADB_X_EXT_POLICY, SADB_EXT_LIFETIME_HARD,
+ SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST);
+ } else {
+ n = key_gather_mbuf(m, mhp, 2, 4, SADB_EXT_RESERVED,
+ SADB_X_EXT_POLICY,
+ SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST);
+ }
if (!n)
return key_senderror(so, m, ENOBUFS);
@@ -2308,6 +2416,123 @@ key_getspreqmsglen(sp)
return tlen;
}
+/*
+ * SADB_SPDEXPIRE processing
+ * send
+ * <base, address(SD), lifetime(CH), policy>
+ * to KMD by PF_KEY.
+ *
+ * OUT: 0 : succeed
+ * others : error number
+ */
+static int
+key_spdexpire(sp)
+ struct secpolicy *sp;
+{
+ int s;
+ struct mbuf *result = NULL, *m;
+ int len;
+ int error = -1;
+ struct sadb_lifetime *lt;
+
+ /* XXX: Why do we lock ? */
+ s = splnet(); /*called from softclock()*/
+
+ /* sanity check */
+ if (sp == NULL)
+ panic("key_spdexpire: NULL pointer is passed.\n");
+
+ /* set msg header */
+ m = key_setsadbmsg(SADB_X_SPDEXPIRE, 0, 0, 0, 0, 0);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ result = m;
+
+ /* create lifetime extension (current and hard) */
+ len = PFKEY_ALIGN8(sizeof(*lt)) * 2;
+ m = key_alloc_mbuf(len);
+ if (!m || m->m_next) { /*XXX*/
+ if (m)
+ m_freem(m);
+ error = ENOBUFS;
+ goto fail;
+ }
+ bzero(mtod(m, caddr_t), len);
+ lt = mtod(m, struct sadb_lifetime *);
+ lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime));
+ lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
+ lt->sadb_lifetime_allocations = 0;
+ lt->sadb_lifetime_bytes = 0;
+ lt->sadb_lifetime_addtime = sp->created;
+ lt->sadb_lifetime_usetime = sp->lastused;
+ lt = (struct sadb_lifetime *)(mtod(m, caddr_t) + len / 2);
+ lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime));
+ lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
+ lt->sadb_lifetime_allocations = 0;
+ lt->sadb_lifetime_bytes = 0;
+ lt->sadb_lifetime_addtime = sp->lifetime;
+ lt->sadb_lifetime_usetime = sp->validtime;
+ m_cat(result, m);
+
+ /* set sadb_address for source */
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
+ (struct sockaddr *)&sp->spidx.src,
+ sp->spidx.prefs, sp->spidx.ul_proto);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
+
+ /* set sadb_address for destination */
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,
+ (struct sockaddr *)&sp->spidx.dst,
+ sp->spidx.prefd, sp->spidx.ul_proto);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
+
+ /* set secpolicy */
+ m = key_sp2msg(sp);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
+
+ if ((result->m_flags & M_PKTHDR) == 0) {
+ error = EINVAL;
+ goto fail;
+ }
+
+ if (result->m_len < sizeof(struct sadb_msg)) {
+ result = m_pullup(result, sizeof(struct sadb_msg));
+ if (result == NULL) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ }
+
+ result->m_pkthdr.len = 0;
+ for (m = result; m; m = m->m_next)
+ result->m_pkthdr.len += m->m_len;
+
+ mtod(result, struct sadb_msg *)->sadb_msg_len =
+ PFKEY_UNIT64(result->m_pkthdr.len);
+
+ return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED);
+
+ fail:
+ if (result)
+ m_freem(result);
+ splx(s);
+ return error;
+}
+
/* %%% SAD management */
/*
* allocating a memory for new SA head, and copy from the values of mhp.
@@ -2484,8 +2709,12 @@ key_newsav(m, mhp, sah, errp)
}
}
- /* reset tick */
- newsav->tick = 0;
+ /* reset created */
+ {
+ struct timeval tv;
+ microtime(&tv);
+ newsav->created = tv.tv_sec;
+ }
newsav->pid = mhp->msg->sadb_msg_pid;
@@ -2517,28 +2746,41 @@ key_delsav(sav)
if (__LIST_CHAINED(sav))
LIST_REMOVE(sav, chain);
- if (sav->key_auth != NULL)
+ if (sav->key_auth != NULL) {
+ bzero(_KEYBUF(sav->key_auth), _KEYLEN(sav->key_auth));
KFREE(sav->key_auth);
- if (sav->key_enc != NULL)
+ sav->key_auth = NULL;
+ }
+ if (sav->key_enc != NULL) {
+ bzero(_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc));
KFREE(sav->key_enc);
- if (sav->replay != NULL)
+ sav->key_enc = NULL;
+ }
+ if (sav->sched) {
+ bzero(sav->sched, sav->schedlen);
+ KFREE(sav->sched);
+ sav->sched = NULL;
+ }
+ if (sav->replay != NULL) {
keydb_delsecreplay(sav->replay);
- if (sav->lft_c != NULL)
+ sav->replay = NULL;
+ }
+ if (sav->lft_c != NULL) {
KFREE(sav->lft_c);
- if (sav->lft_h != NULL)
+ sav->lft_c = NULL;
+ }
+ if (sav->lft_h != NULL) {
KFREE(sav->lft_h);
- if (sav->lft_s != NULL)
+ sav->lft_h = NULL;
+ }
+ if (sav->lft_s != NULL) {
KFREE(sav->lft_s);
- if (sav->iv != NULL)
+ sav->lft_s = NULL;
+ }
+ if (sav->iv != NULL) {
KFREE(sav->iv);
-#if notyet
- if (sav->misc1 != NULL)
- KFREE(sav->misc1);
- if (sav->misc2 != NULL)
- KFREE(sav->misc2);
- if (sav->misc3 != NULL)
- KFREE(sav->misc3);
-#endif
+ sav->iv = NULL;
+ }
KFREE(sav);
@@ -2560,8 +2802,8 @@ key_getsah(saidx)
LIST_FOREACH(sah, &sahtree, chain) {
if (sah->state == SADB_SASTATE_DEAD)
continue;
- if (key_cmpsaidx_exactly(&sah->saidx, saidx))
- return(sah);
+ if (key_cmpsaidx_withoutmode2(&sah->saidx, saidx))
+ return sah;
}
return NULL;
@@ -2671,15 +2913,12 @@ key_setsaval(sav, m, mhp)
sav->replay = NULL;
sav->key_auth = NULL;
sav->key_enc = NULL;
+ sav->sched = NULL;
+ sav->schedlen = 0;
sav->iv = NULL;
sav->lft_c = NULL;
sav->lft_h = NULL;
sav->lft_s = NULL;
-#if notyet
- sav->misc1 = NULL;
- sav->misc2 = NULL;
- sav->misc3 = NULL;
-#endif
/* SA */
if (mhp->ext[SADB_EXT_SA] != NULL) {
@@ -2725,7 +2964,7 @@ key_setsaval(sav, m, mhp)
case SADB_SATYPE_AH:
case SADB_SATYPE_ESP:
if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) &&
- sav->alg_auth != SADB_AALG_NULL)
+ sav->alg_auth != SADB_X_AALG_NULL)
error = EINVAL;
break;
case SADB_X_SATYPE_IPCOMP:
@@ -2766,11 +3005,26 @@ key_setsaval(sav, m, mhp)
switch (mhp->msg->sadb_msg_satype) {
case SADB_SATYPE_ESP:
if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) &&
- sav->alg_enc != SADB_EALG_NULL)
+ sav->alg_enc != SADB_EALG_NULL) {
error = EINVAL;
+ break;
+ }
+ sav->key_enc = (struct sadb_key *)key_newbuf(key0, len);
+ if (sav->key_enc == NULL) {
+#ifdef IPSEC_DEBUG
+ printf("key_setsaval: No more memory.\n");
+#endif
+ error = ENOBUFS;
+ goto fail;
+ }
break;
- case SADB_SATYPE_AH:
case SADB_X_SATYPE_IPCOMP:
+ if (len != PFKEY_ALIGN8(sizeof(struct sadb_key)))
+ error = EINVAL;
+ sav->key_enc = NULL; /*just in case*/
+ break;
+ case SADB_SATYPE_AH:
+ default:
error = EINVAL;
break;
}
@@ -2780,15 +3034,6 @@ key_setsaval(sav, m, mhp)
#endif
goto fail;
}
-
- sav->key_enc = (struct sadb_key *)key_newbuf(key0, len);
- if (sav->key_enc == NULL) {
-#ifdef IPSEC_DEBUG
- printf("key_setsaval: No more memory.\n");
-#endif
- error = ENOBUFS;
- goto fail;
- }
}
/* set iv */
@@ -2797,9 +3042,9 @@ key_setsaval(sav, m, mhp)
switch (mhp->msg->sadb_msg_satype) {
case SADB_SATYPE_ESP:
#ifdef IPSEC_ESP
- algo = &esp_algorithms[sav->alg_enc];
+ algo = esp_algorithm_lookup(sav->alg_enc);
if (algo && algo->ivlen)
- sav->ivlen = (*algo->ivlen)(sav);
+ sav->ivlen = (*algo->ivlen)(algo, sav);
if (sav->ivlen == 0)
break;
KMALLOC(sav->iv, caddr_t, sav->ivlen);
@@ -2812,20 +3057,11 @@ key_setsaval(sav, m, mhp)
}
/* initialize */
- {
- int i;
- u_int8_t *p = (u_int8_t *)sav->iv;
- for (i = 0; i < sav->ivlen; i++)
- p[i] = key_random() & 0xff;
- }
- break;
-#else
- break;
+ key_randomfill(sav->iv, sav->ivlen);
#endif
+ break;
case SADB_SATYPE_AH:
-#if 1 /*nonstandard*/
case SADB_X_SATYPE_IPCOMP:
-#endif
break;
default:
#ifdef IPSEC_DEBUG
@@ -2835,8 +3071,9 @@ key_setsaval(sav, m, mhp)
goto fail;
}
- /* reset tick */
- sav->tick = 0;
+ /* reset created */
+ microtime(&tv);
+ sav->created = tv.tv_sec;
/* make lifetime for CURRENT */
KMALLOC(sav->lft_c, struct sadb_lifetime *,
@@ -2900,63 +3137,42 @@ key_setsaval(sav, m, mhp)
}
}
-#if notyet
- /* pre-processing for DES */
- switch (sav->alg_enc) {
- case SADB_EALG_DESCBC:
- if (des_key_sched((C_Block *)_KEYBUF(sav->key_enc),
- (des_key_schedule)sav->misc1) != 0) {
-#ifdef IPSEC_DEBUG
- printf("key_setsaval: error des_key_sched.\n");
-#endif
- sav->misc1 = NULL;
- /* THROUGH */
- }
- break;
- case SADB_EALG_3DESCBC:
- if (des_key_sched((C_Block *)_KEYBUF(sav->key_enc),
- (des_key_schedule)sav->misc1) != 0
- || des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8),
- (des_key_schedule)sav->misc2) != 0
- || des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16),
- (des_key_schedule)sav->misc3) != 0) {
-#ifdef IPSEC_DEBUG
- printf("key_setsaval: error des_key_sched.\n");
-#endif
- sav->misc1 = NULL;
- sav->misc2 = NULL;
- sav->misc3 = NULL;
- /* THROUGH */
- }
- }
-#endif
-
return 0;
fail:
/* initialization */
- if (sav->replay != NULL)
+ if (sav->replay != NULL) {
keydb_delsecreplay(sav->replay);
- if (sav->key_auth != NULL)
+ sav->replay = NULL;
+ }
+ if (sav->key_auth != NULL) {
KFREE(sav->key_auth);
- if (sav->key_enc != NULL)
+ sav->key_auth = NULL;
+ }
+ if (sav->key_enc != NULL) {
KFREE(sav->key_enc);
- if (sav->iv != NULL)
+ sav->key_enc = NULL;
+ }
+ if (sav->sched) {
+ KFREE(sav->sched);
+ sav->sched = NULL;
+ }
+ if (sav->iv != NULL) {
KFREE(sav->iv);
- if (sav->lft_c != NULL)
+ sav->iv = NULL;
+ }
+ if (sav->lft_c != NULL) {
KFREE(sav->lft_c);
- if (sav->lft_h != NULL)
+ sav->lft_c = NULL;
+ }
+ if (sav->lft_h != NULL) {
KFREE(sav->lft_h);
- if (sav->lft_s != NULL)
+ sav->lft_h = NULL;
+ }
+ if (sav->lft_s != NULL) {
KFREE(sav->lft_s);
-#if notyet
- if (sav->misc1 != NULL)
- KFREE(sav->misc1);
- if (sav->misc2 != NULL)
- KFREE(sav->misc2);
- if (sav->misc3 != NULL)
- KFREE(sav->misc3);
-#endif
+ sav->lft_s = NULL;
+ }
return error;
}
@@ -2977,11 +3193,17 @@ key_mature(sav)
mature = 0;
/* check SPI value */
- if (ntohl(sav->spi) >= 0 && ntohl(sav->spi) <= 255) {
+ switch (sav->sah->saidx.proto) {
+ case IPPROTO_ESP:
+ case IPPROTO_AH:
+ if (ntohl(sav->spi) >= 0 && ntohl(sav->spi) <= 255) {
#ifdef IPSEC_DEBUG
- printf("key_mature: illegal range of SPI %d.\n", sav->spi);
+ printf("key_mature: illegal range of SPI %u.\n",
+ (u_int32_t)ntohl(sav->spi));
#endif
- return EINVAL;
+ return EINVAL;
+ }
+ break;
}
/* check satype */
@@ -2996,7 +3218,10 @@ key_mature(sav)
#endif
return EINVAL;
}
- checkmask = 3;
+ if (sav->alg_auth == SADB_AALG_NONE)
+ checkmask = 1;
+ else
+ checkmask = 3;
mustmask = 1;
break;
case IPPROTO_AH:
@@ -3018,7 +3243,6 @@ key_mature(sav)
checkmask = 2;
mustmask = 2;
break;
-#if 1 /*nonstandard*/
case IPPROTO_IPCOMP:
if (sav->alg_auth != SADB_AALG_NONE) {
#ifdef IPSEC_DEBUG
@@ -3037,7 +3261,6 @@ key_mature(sav)
checkmask = 4;
mustmask = 4;
break;
-#endif
default:
#ifdef IPSEC_DEBUG
printf("key_mature: Invalid satype.\n");
@@ -3047,19 +3270,11 @@ key_mature(sav)
/* check authentication algorithm */
if ((checkmask & 2) != 0) {
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
int keylen;
- /* XXX: should use algorithm map to check. */
- switch (sav->alg_auth) {
- case SADB_AALG_NONE:
- case SADB_AALG_MD5HMAC:
- case SADB_AALG_SHA1HMAC:
- case SADB_AALG_MD5:
- case SADB_AALG_SHA:
- case SADB_AALG_NULL:
- break;
- default:
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
#ifdef IPSEC_DEBUG
printf("key_mature: "
"unknown authentication algorithm.\n");
@@ -3068,8 +3283,6 @@ key_mature(sav)
}
/* algorithm-dependent check */
- algo = &ah_algorithms[sav->alg_auth];
-
if (sav->key_auth)
keylen = sav->key_auth->sadb_key_bits;
else
@@ -3102,19 +3315,11 @@ key_mature(sav)
/* check encryption algorithm */
if ((checkmask & 1) != 0) {
#ifdef IPSEC_ESP
- struct esp_algorithm *algo;
+ const struct esp_algorithm *algo;
int keylen;
- switch (sav->alg_enc) {
- case SADB_EALG_NONE:
- case SADB_EALG_DESCBC:
- case SADB_EALG_3DESCBC:
- case SADB_EALG_NULL:
- case SADB_EALG_BLOWFISHCBC:
- case SADB_EALG_CAST128CBC:
- case SADB_EALG_RC5CBC:
- break;
- default:
+ algo = esp_algorithm_lookup(sav->alg_enc);
+ if (!algo) {
#ifdef IPSEC_DEBUG
printf("key_mature: unknown encryption algorithm.\n");
#endif
@@ -3122,8 +3327,6 @@ key_mature(sav)
}
/* algorithm-dependent check */
- algo = &esp_algorithms[sav->alg_enc];
-
if (sav->key_enc)
keylen = sav->key_enc->sadb_key_bits;
else
@@ -3161,28 +3364,13 @@ key_mature(sav)
/* check compression algorithm */
if ((checkmask & 4) != 0) {
- struct ipcomp_algorithm *algo;
-
- switch (sav->alg_enc) {
- case SADB_X_CALG_NONE:
- case SADB_X_CALG_OUI:
- case SADB_X_CALG_DEFLATE:
- case SADB_X_CALG_LZS:
- break;
- default:
-#ifdef IPSEC_DEBUG
- printf("key_mature: unknown compression algorithm.\n");
-#endif
- return EINVAL;
- }
+ const struct ipcomp_algorithm *algo;
/* algorithm-dependent check */
- algo = &ipcomp_algorithms[sav->alg_enc];
-
- if (!(algo->compress && algo->decompress)) {
+ algo = ipcomp_algorithm_lookup(sav->alg_enc);
+ if (!algo) {
#ifdef IPSEC_DEBUG
- printf("key_mature: "
- "unsupported compression algorithm.\n");
+ printf("key_mature: unknown compression algorithm.\n");
#endif
return EINVAL;
}
@@ -3752,7 +3940,50 @@ key_cmpsaidx_withmode(saidx0, saidx1)
}
/*
- * compare two secasindex structure without mode.
+ * compare two secasindex structure without mode, but think reqid.
+ * don't compare port.
+ * IN:
+ * saidx0: source, it is often in SAD.
+ * saidx1: object, it is often from user.
+ * OUT:
+ * 1 : equal
+ * 0 : not equal
+ */
+static int
+key_cmpsaidx_withoutmode2(saidx0, saidx1)
+ struct secasindex *saidx0, *saidx1;
+{
+ /* sanity */
+ if (saidx0 == NULL && saidx1 == NULL)
+ return 1;
+
+ if (saidx0 == NULL || saidx1 == NULL)
+ return 0;
+
+ if (saidx0->proto != saidx1->proto)
+ return 0;
+
+ /*
+ * If reqid of SPD is non-zero, unique SA is required.
+ * The result must be of same reqid in this case.
+ */
+ if (saidx1->reqid != 0 && saidx0->reqid != saidx1->reqid)
+ return 0;
+
+ if (key_sockaddrcmp((struct sockaddr *)&saidx0->src,
+ (struct sockaddr *)&saidx1->src, 0) != 0) {
+ return 0;
+ }
+ if (key_sockaddrcmp((struct sockaddr *)&saidx0->dst,
+ (struct sockaddr *)&saidx1->dst, 0) != 0) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * compare two secasindex structure without both mode and reqid.
* don't compare port.
* IN:
* saidx0: source, it is often in SAD.
@@ -3870,7 +4101,13 @@ key_cmpspidx_withmask(spidx0, spidx1)
&& satosin6(&spidx0->src)->sin6_port !=
satosin6(&spidx1->src)->sin6_port)
return 0;
- if (satosin6(&spidx0->src)->sin6_scope_id !=
+ /*
+ * scope_id check. if sin6_scope_id is 0, we regard it
+ * as a wildcard scope, which matches any scope zone ID.
+ */
+ if (satosin6(&spidx0->src)->sin6_scope_id &&
+ satosin6(&spidx1->src)->sin6_scope_id &&
+ satosin6(&spidx0->src)->sin6_scope_id !=
satosin6(&spidx1->src)->sin6_scope_id)
return 0;
if (!key_bbcmp((caddr_t)&satosin6(&spidx0->src)->sin6_addr,
@@ -3899,7 +4136,13 @@ key_cmpspidx_withmask(spidx0, spidx1)
&& satosin6(&spidx0->dst)->sin6_port !=
satosin6(&spidx1->dst)->sin6_port)
return 0;
- if (satosin6(&spidx0->dst)->sin6_scope_id !=
+ /*
+ * scope_id check. if sin6_scope_id is 0, we regard it
+ * as a wildcard scope, which matches any scope zone ID.
+ */
+ if (satosin6(&spidx0->src)->sin6_scope_id &&
+ satosin6(&spidx1->src)->sin6_scope_id &&
+ satosin6(&spidx0->dst)->sin6_scope_id !=
satosin6(&spidx1->dst)->sin6_scope_id)
return 0;
if (!key_bbcmp((caddr_t)&satosin6(&spidx0->dst)->sin6_addr,
@@ -4005,12 +4248,16 @@ key_bbcmp(p1, p2, bits)
* time handler.
* scanning SPD and SAD to check status for each entries,
* and do to remove or to expire.
+ * XXX: year 2038 problem may remain.
*/
void
key_timehandler(void)
{
u_int dir;
int s;
+ struct timeval tv;
+
+ microtime(&tv);
s = splnet(); /*called from softclock()*/
@@ -4025,8 +4272,23 @@ key_timehandler(void)
nextsp = LIST_NEXT(sp, chain);
- if (sp->state == IPSEC_SPSTATE_DEAD)
+ if (sp->state == IPSEC_SPSTATE_DEAD) {
key_freesp(sp);
+ continue;
+ }
+
+ if (sp->lifetime == 0 && sp->validtime == 0)
+ continue;
+
+ /* the deletion will occur next time */
+ if ((sp->lifetime
+ && tv.tv_sec - sp->created > sp->lifetime)
+ || (sp->validtime
+ && tv.tv_sec - sp->lastused > sp->validtime)) {
+ sp->state = IPSEC_SPSTATE_DEAD;
+ key_spdexpire(sp);
+ continue;
+ }
}
}
}
@@ -4055,9 +4317,7 @@ key_timehandler(void)
nextsav = LIST_NEXT(sav, chain);
- sav->tick++;
-
- if (key_larval_lifetime < sav->tick) {
+ if (tv.tv_sec - sav->created > key_larval_lifetime) {
key_freesav(sav);
}
}
@@ -4072,8 +4332,6 @@ key_timehandler(void)
nextsav = LIST_NEXT(sav, chain);
- sav->tick++;
-
/* we don't need to check. */
if (sav->lft_s == NULL)
continue;
@@ -4087,9 +4345,9 @@ key_timehandler(void)
continue;
}
- /* compare SOFT lifetime and tick */
+ /* check SOFT lifetime */
if (sav->lft_s->sadb_lifetime_addtime != 0
- && sav->lft_s->sadb_lifetime_addtime < sav->tick) {
+ && tv.tv_sec - sav->created > sav->lft_s->sadb_lifetime_addtime) {
/*
* check SA to be used whether or not.
* when SA hasn't been used, delete it.
@@ -4134,8 +4392,6 @@ key_timehandler(void)
nextsav = LIST_NEXT(sav, chain);
- sav->tick++;
-
/* we don't need to check. */
if (sav->lft_h == NULL)
continue;
@@ -4149,9 +4405,8 @@ key_timehandler(void)
continue;
}
- /* compare HARD lifetime and tick */
if (sav->lft_h->sadb_lifetime_addtime != 0
- && sav->lft_h->sadb_lifetime_addtime < sav->tick) {
+ && tv.tv_sec - sav->created > sav->lft_h->sadb_lifetime_addtime) {
key_sa_chgstate(sav, SADB_SASTATE_DEAD);
key_freesav(sav);
sav = NULL;
@@ -4159,7 +4414,7 @@ key_timehandler(void)
#if 0 /* XXX Should we keep to send expire message until HARD lifetime ? */
else if (sav->lft_s != NULL
&& sav->lft_s->sadb_lifetime_addtime != 0
- && sav->lft_s->sadb_lifetime_addtime < sav->tick) {
+ && tv.tv_sec - sav->created > sav->lft_s->sadb_lifetime_addtime) {
/*
* XXX: should be checked to be
* installed the valid SA.
@@ -4220,9 +4475,8 @@ key_timehandler(void)
nextacq = LIST_NEXT(acq, chain);
- acq->tick++;
-
- if (key_blockacq_lifetime < acq->tick && __LIST_CHAINED(acq)) {
+ if (tv.tv_sec - acq->created > key_blockacq_lifetime
+ && __LIST_CHAINED(acq)) {
LIST_REMOVE(acq, chain);
KFREE(acq);
}
@@ -4240,9 +4494,8 @@ key_timehandler(void)
nextacq = LIST_NEXT(acq, chain);
- acq->tick++;
-
- if (key_blockacq_lifetime < acq->tick && __LIST_CHAINED(acq)) {
+ if (tv.tv_sec - acq->created > key_blockacq_lifetime
+ && __LIST_CHAINED(acq)) {
LIST_REMOVE(acq, chain);
KFREE(acq);
}
@@ -4257,7 +4510,7 @@ key_timehandler(void)
#ifndef IPSEC_DEBUG2
/* do exchange to tick time !! */
- (void)timeout((void *)key_timehandler, (void *)0, 100);
+ (void)timeout((void *)key_timehandler, (void *)0, hz);
#endif /* IPSEC_DEBUG2 */
splx(s);
@@ -4279,19 +4532,41 @@ key_srandom()
return;
}
-/*
- * to initialize a seed for random()
- */
-static u_long
+u_long
key_random()
{
u_long value;
- value = random();
-
+ key_randomfill(&value, sizeof(value));
return value;
}
+void
+key_randomfill(p, l)
+ void *p;
+ size_t l;
+{
+ size_t n;
+ u_long v;
+ static int warn = 1;
+
+ n = 0;
+ n = (size_t)read_random(p, (u_int)l);
+ /* last resort */
+ while (n < l) {
+ v = random();
+ bcopy(&v, (u_int8_t *)p + n,
+ l - n < sizeof(v) ? l - n : sizeof(v));
+ n += sizeof(v);
+
+ if (warn) {
+ printf("WARNING: pseudo-random number generator "
+ "used for IPsec processing\n");
+ warn = 0;
+ }
+ }
+}
+
/*
* map SADB_SATYPE_* to IPPROTO_*.
* if satype == SADB_SATYPE then satype is mapped to ~0.
@@ -4309,11 +4584,9 @@ key_satype2proto(satype)
return IPPROTO_AH;
case SADB_SATYPE_ESP:
return IPPROTO_ESP;
-#if 1 /*nonstandard*/
case SADB_X_SATYPE_IPCOMP:
return IPPROTO_IPCOMP;
break;
-#endif
default:
return 0;
}
@@ -4334,11 +4607,9 @@ key_proto2satype(proto)
return SADB_SATYPE_AH;
case IPPROTO_ESP:
return SADB_SATYPE_ESP;
-#if 1 /*nonstandard*/
case IPPROTO_IPCOMP:
return SADB_X_SATYPE_IPCOMP;
break;
-#endif
default:
return 0;
}
@@ -4481,8 +4752,10 @@ key_getspi(so, m, mhp)
if (mhp->msg->sadb_msg_seq != 0) {
struct secacq *acq;
if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) != NULL) {
- /* reset counter in order to deletion by timehander. */
- acq->tick = key_blockacq_lifetime;
+ /* reset counter in order to deletion by timehandler. */
+ struct timeval tv;
+ microtime(&tv);
+ acq->created = tv.tv_sec;
acq->count = 0;
}
}
@@ -5047,6 +5320,7 @@ key_setident(sah, m, mhp)
KMALLOC(sah->identd, struct sadb_ident *, iddstlen);
if (sah->identd == NULL) {
KFREE(sah->idents);
+ sah->idents = NULL;
#ifdef IPSEC_DEBUG
printf("key_setident: No more memory.\n");
#endif
@@ -5094,6 +5368,9 @@ key_getmsgbuf_x1(m, mhp)
return n;
}
+static int key_delete_all __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *, u_int16_t));
+
/*
* SADB_DELETE processing
* receive
@@ -5130,16 +5407,15 @@ key_delete(so, m, mhp)
return key_senderror(so, m, EINVAL);
}
- if (mhp->ext[SADB_EXT_SA] == NULL ||
- mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL ||
+ if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL ||
mhp->ext[SADB_EXT_ADDRESS_DST] == NULL) {
#ifdef IPSEC_DEBUG
printf("key_delete: invalid message is passed.\n");
#endif
return key_senderror(so, m, EINVAL);
}
- if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) ||
- mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) ||
+
+ if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) ||
mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) {
#ifdef IPSEC_DEBUG
printf("key_delete: invalid message is passed.\n");
@@ -5147,6 +5423,23 @@ key_delete(so, m, mhp)
return key_senderror(so, m, EINVAL);
}
+ if (mhp->ext[SADB_EXT_SA] == NULL) {
+ /*
+ * Caller wants us to delete all non-LARVAL SAs
+ * that match the src/dst. This is used during
+ * IKE INITIAL-CONTACT.
+ */
+#ifdef IPSEC_DEBUG
+ printf("key_delete: doing delete all.\n");
+#endif
+ return key_delete_all(so, m, mhp, proto);
+ } else if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa)) {
+#ifdef IPSEC_DEBUG
+ printf("key_delete: invalid message is passed.\n");
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+
sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA];
src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
@@ -5202,6 +5495,84 @@ key_delete(so, m, mhp)
}
/*
+ * delete all SAs for src/dst. Called from key_delete().
+ */
+static int
+key_delete_all(so, m, mhp, proto)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
+ u_int16_t proto;
+{
+ struct sadb_address *src0, *dst0;
+ struct secasindex saidx;
+ struct secashead *sah;
+ struct secasvar *sav, *nextsav;
+ u_int stateidx, state;
+
+ src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
+ dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
+
+ /* XXX boundary check against sa_len */
+ KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
+
+ LIST_FOREACH(sah, &sahtree, chain) {
+ if (sah->state == SADB_SASTATE_DEAD)
+ continue;
+ if (key_cmpsaidx_withoutmode(&sah->saidx, &saidx) == 0)
+ continue;
+
+ /* Delete all non-LARVAL SAs. */
+ for (stateidx = 0;
+ stateidx < _ARRAYLEN(saorder_state_alive);
+ stateidx++) {
+ state = saorder_state_alive[stateidx];
+ if (state == SADB_SASTATE_LARVAL)
+ continue;
+ for (sav = LIST_FIRST(&sah->savtree[state]);
+ sav != NULL; sav = nextsav) {
+ nextsav = LIST_NEXT(sav, chain);
+ /* sanity check */
+ if (sav->state != state) {
+#ifdef IPSEC_DEBUG
+ printf("key_delete_all: "
+ "invalid sav->state "
+ "(queue: %d SA: %d)\n",
+ state, sav->state);
+#endif
+ continue;
+ }
+
+ key_sa_chgstate(sav, SADB_SASTATE_DEAD);
+ key_freesav(sav);
+ }
+ }
+ }
+ {
+ struct mbuf *n;
+ struct sadb_msg *newmsg;
+
+ /* create new sadb_msg to reply. */
+ n = key_gather_mbuf(m, mhp, 1, 3, SADB_EXT_RESERVED,
+ SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST);
+ if (!n)
+ return key_senderror(so, m, ENOBUFS);
+
+ if (n->m_len < sizeof(struct sadb_msg)) {
+ n = m_pullup(n, sizeof(struct sadb_msg));
+ if (n == NULL)
+ return key_senderror(so, m, ENOBUFS);
+ }
+ newmsg = mtod(n, struct sadb_msg *);
+ newmsg->sadb_msg_errno = 0;
+ newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len);
+
+ m_freem(m);
+ return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
+ }
+}
+
+/*
* SADB_GET processing
* receive
* <base, SA(*), address(SD)>
@@ -5304,17 +5675,32 @@ key_get(so, m, mhp)
}
}
+/* XXX make it sysctl-configurable? */
+static void
+key_getcomb_setlifetime(comb)
+ struct sadb_comb *comb;
+{
+
+ comb->sadb_comb_soft_allocations = 1;
+ comb->sadb_comb_hard_allocations = 1;
+ comb->sadb_comb_soft_bytes = 0;
+ comb->sadb_comb_hard_bytes = 0;
+ comb->sadb_comb_hard_addtime = 86400; /* 1 day */
+ comb->sadb_comb_soft_addtime = comb->sadb_comb_soft_addtime * 80 / 100;
+ comb->sadb_comb_soft_usetime = 28800; /* 8 hours */
+ comb->sadb_comb_hard_usetime = comb->sadb_comb_hard_usetime * 80 / 100;
+}
+
#ifdef IPSEC_ESP
/*
* XXX reorder combinations by preference
* XXX no idea if the user wants ESP authentication or not
- * XXX lifetime - should be in policy?
*/
static struct mbuf *
key_getcomb_esp()
{
struct sadb_comb *comb;
- struct esp_algorithm *algo;
+ const struct esp_algorithm *algo;
struct mbuf *result = NULL, *m, *n;
int encmin;
int i, off, o;
@@ -5322,8 +5708,10 @@ key_getcomb_esp()
const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb));
m = NULL;
- for (i = 1; i < SADB_EALG_MAX; i++) {
- algo = &esp_algorithms[i];
+ for (i = 1; i <= SADB_EALG_MAX; i++) {
+ algo = esp_algorithm_lookup(i);
+ if (!algo)
+ continue;
if (algo->keymax < ipsec_esp_keymin)
continue;
@@ -5365,6 +5753,8 @@ key_getcomb_esp()
goto fail;
}
comb = (struct sadb_comb *)(mtod(n, caddr_t) + o);
+ bzero(comb, sizeof(*comb));
+ key_getcomb_setlifetime(comb);
comb->sadb_comb_encrypt = i;
comb->sadb_comb_encrypt_minbits = encmin;
comb->sadb_comb_encrypt_maxbits = algo->keymax;
@@ -5387,26 +5777,27 @@ key_getcomb_esp()
/*
* XXX reorder combinations by preference
- * XXX lifetime - should be in policy?
*/
static struct mbuf *
key_getcomb_ah()
{
struct sadb_comb *comb;
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
struct mbuf *m;
int min;
int i;
const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb));
m = NULL;
- for (i = 1; i < SADB_AALG_MAX; i++) {
+ for (i = 1; i <= SADB_AALG_MAX; i++) {
#if 1
/* we prefer HMAC algorithms, not old algorithms */
if (i != SADB_AALG_SHA1HMAC && i != SADB_AALG_MD5HMAC)
continue;
#endif
- algo = &ah_algorithms[i];
+ algo = ah_algorithm_lookup(i);
+ if (!algo)
+ continue;
if (algo->keymax < ipsec_ah_keymin)
continue;
@@ -5433,6 +5824,7 @@ key_getcomb_ah()
comb = mtod(m, struct sadb_comb *);
bzero(comb, sizeof(*comb));
+ key_getcomb_setlifetime(comb);
comb->sadb_comb_auth = i;
comb->sadb_comb_auth_minbits = min;
comb->sadb_comb_auth_maxbits = algo->keymax;
@@ -5442,6 +5834,51 @@ key_getcomb_ah()
}
/*
+ * not really an official behavior. discussed in pf_key@inner.net in Sep2000.
+ * XXX reorder combinations by preference
+ */
+static struct mbuf *
+key_getcomb_ipcomp()
+{
+ struct sadb_comb *comb;
+ const struct ipcomp_algorithm *algo;
+ struct mbuf *m;
+ int i;
+ const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb));
+
+ m = NULL;
+ for (i = 1; i <= SADB_X_CALG_MAX; i++) {
+ algo = ipcomp_algorithm_lookup(i);
+ if (!algo)
+ continue;
+
+ if (!m) {
+#ifdef DIAGNOSTIC
+ if (l > MLEN)
+ panic("assumption failed in key_getcomb_ipcomp");
+#endif
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m) {
+ M_ALIGN(m, l);
+ m->m_len = l;
+ m->m_next = NULL;
+ }
+ } else
+ M_PREPEND(m, l, M_DONTWAIT);
+ if (!m)
+ return NULL;
+
+ comb = mtod(m, struct sadb_comb *);
+ bzero(comb, sizeof(*comb));
+ key_getcomb_setlifetime(comb);
+ comb->sadb_comb_encrypt = i;
+ /* what should we set into sadb_comb_*_{min,max}bits? */
+ }
+
+ return m;
+}
+
+/*
* XXX no way to pass mode (transport/tunnel) to userland
* XXX replay checking?
* XXX sysctl interface to ipsec_{ah,esp}_keymin
@@ -5464,6 +5901,9 @@ key_getprop(saidx)
case IPPROTO_AH:
m = key_getcomb_ah();
break;
+ case IPPROTO_IPCOMP:
+ m = key_getcomb_ipcomp();
+ break;
default:
return NULL;
}
@@ -5490,7 +5930,7 @@ key_getprop(saidx)
/*
* SADB_ACQUIRE processing called by key_checkrequest() and key_acquire2().
* send
- * <base, SA, address(SD), (address(P)),
+ * <base, SA, address(SD), (address(P)), x_policy,
* (identity(SD),) (sensitivity,) proposal>
* to KMD, and expect to receive
* <base> with SADB_ACQUIRE if error occured,
@@ -5498,7 +5938,10 @@ key_getprop(saidx)
* <base, src address, dst address, (SPI range)> with SADB_GETSPI
* from KMD by PF_KEY.
*
- * sensitivity is not supported.
+ * XXX x_policy is outside of RFC2367 (KAME extension).
+ * XXX sensitivity is not supported.
+ * XXX for ipcomp, RFC2367 does not define how to fill in proposal.
+ * see comment for key_getcomb_ipcomp().
*
* OUT:
* 0 : succeed
@@ -5639,11 +6082,24 @@ key_acquire(saidx, sp)
/* create proposal/combination extension */
m = key_getprop(saidx);
+#if 0
+ /*
+ * spec conformant: always attach proposal/combination extension,
+ * the problem is that we have no way to attach it for ipcomp,
+ * due to the way sadb_comb is declared in RFC2367.
+ */
if (!m) {
error = ENOBUFS;
goto fail;
}
m_cat(result, m);
+#else
+ /*
+ * outside of spec; make proposal/combination extension optional.
+ */
+ if (m)
+ m_cat(result, m);
+#endif
if ((result->m_flags & M_PKTHDR) == 0) {
error = EINVAL;
@@ -5679,6 +6135,7 @@ key_newacq(saidx)
struct secasindex *saidx;
{
struct secacq *newacq;
+ struct timeval tv;
/* get new entry */
KMALLOC(newacq, struct secacq *, sizeof(struct secacq));
@@ -5693,7 +6150,8 @@ key_newacq(saidx)
/* copy secindex */
bcopy(saidx, &newacq->saidx, sizeof(newacq->saidx));
newacq->seq = (acq_seq == ~0 ? 1 : ++acq_seq);
- newacq->tick = 0;
+ microtime(&tv);
+ newacq->created = tv.tv_sec;
newacq->count = 0;
return newacq;
@@ -5733,6 +6191,7 @@ key_newspacq(spidx)
struct secpolicyindex *spidx;
{
struct secspacq *acq;
+ struct timeval tv;
/* get new entry */
KMALLOC(acq, struct secspacq *, sizeof(struct secspacq));
@@ -5746,7 +6205,8 @@ key_newspacq(spidx)
/* copy secindex */
bcopy(spidx, &acq->spidx, sizeof(acq->spidx));
- acq->tick = 0;
+ microtime(&tv);
+ acq->created = tv.tv_sec;
acq->count = 0;
return acq;
@@ -5778,7 +6238,7 @@ key_getspacq(spidx)
* <base, address(SD), (address(P),) (identity(SD),) (sensitivity,) proposal>
* to the socket.
*
- * m will always e freed.
+ * m will always be freed.
*/
static int
key_acquire2(so, m, mhp)
@@ -5805,6 +6265,7 @@ key_acquire2(so, m, mhp)
if (mhp->msg->sadb_msg_len == PFKEY_UNIT64(sizeof(struct sadb_msg))) {
#ifndef IPSEC_NONBLOCK_ACQUIRE
struct secacq *acq;
+ struct timeval tv;
/* check sequence number */
if (mhp->msg->sadb_msg_seq == 0) {
@@ -5816,16 +6277,17 @@ key_acquire2(so, m, mhp)
}
if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) == NULL) {
-#ifdef IPSEC_DEBUG
- printf("key_acquire2: "
- "invalid sequence number is passed.\n");
-#endif
+ /*
+ * the specified larval SA is already gone, or we got
+ * a bogus sequence number. we can silently ignore it.
+ */
m_freem(m);
return 0;
}
/* reset acq counter in order to deletion by timehander. */
- acq->tick = key_blockacq_lifetime;
+ microtime(&tv);
+ acq->created = tv.tv_sec;
acq->count = 0;
#endif
m_freem(m);
@@ -5906,7 +6368,7 @@ key_acquire2(so, m, mhp)
* to KMD by PF_KEY.
* If socket is detached, must free from regnode.
*
- * m will always e freed.
+ * m will always be freed.
*/
static int
key_register(so, m, mhp)
@@ -5965,13 +6427,21 @@ key_register(so, m, mhp)
struct sadb_alg *alg;
/* create new sadb_msg to reply. */
- alen = sizeof(struct sadb_supported)
- + ((SADB_AALG_MAX - 1) * sizeof(struct sadb_alg));
-#ifdef IPSEC_ESP
- elen = sizeof(struct sadb_supported)
- + ((SADB_EALG_MAX - 1) * sizeof(struct sadb_alg));
-#else
+ alen = 0;
+ for (i = 1; i <= SADB_AALG_MAX; i++) {
+ if (ah_algorithm_lookup(i))
+ alen += sizeof(struct sadb_alg);
+ }
+ if (alen)
+ alen += sizeof(struct sadb_supported);
elen = 0;
+#ifdef IPSEC_ESP
+ for (i = 1; i <= SADB_EALG_MAX; i++) {
+ if (esp_algorithm_lookup(i))
+ elen += sizeof(struct sadb_alg);
+ }
+ if (elen)
+ elen += sizeof(struct sadb_supported);
#endif
len = sizeof(struct sadb_msg) + alen + elen;
@@ -6007,10 +6477,12 @@ key_register(so, m, mhp)
sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH;
off += PFKEY_ALIGN8(sizeof(*sup));
- for (i = 1; i < SADB_AALG_MAX; i++) {
- struct ah_algorithm *aalgo;
+ for (i = 1; i <= SADB_AALG_MAX; i++) {
+ const struct ah_algorithm *aalgo;
- aalgo = &ah_algorithms[i];
+ aalgo = ah_algorithm_lookup(i);
+ if (!aalgo)
+ continue;
alg = (struct sadb_alg *)(mtod(n, caddr_t) + off);
alg->sadb_alg_id = i;
alg->sadb_alg_ivlen = 0;
@@ -6028,10 +6500,12 @@ key_register(so, m, mhp)
sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT;
off += PFKEY_ALIGN8(sizeof(*sup));
- for (i = 1; i < SADB_EALG_MAX; i++) {
- struct esp_algorithm *ealgo;
+ for (i = 1; i <= SADB_EALG_MAX; i++) {
+ const struct esp_algorithm *ealgo;
- ealgo = &esp_algorithms[i];
+ ealgo = esp_algorithm_lookup(i);
+ if (!ealgo)
+ continue;
alg = (struct sadb_alg *)(mtod(n, caddr_t) + off);
alg->sadb_alg_id = i;
if (ealgo && ealgo->ivlen) {
@@ -6039,7 +6513,8 @@ key_register(so, m, mhp)
* give NULL to get the value preferred by
* algorithm XXX SADB_X_EXT_DERIV ?
*/
- alg->sadb_alg_ivlen = (*ealgo->ivlen)(NULL);
+ alg->sadb_alg_ivlen =
+ (*ealgo->ivlen)(ealgo, NULL);
} else
alg->sadb_alg_ivlen = 0;
alg->sadb_alg_minbits = ealgo->keymin;
@@ -6190,13 +6665,17 @@ key_expire(sav)
}
m_cat(result, m);
- if ((result->m_flags & M_PKTHDR) == 0)
+ if ((result->m_flags & M_PKTHDR) == 0) {
+ error = EINVAL;
goto fail;
+ }
if (result->m_len < sizeof(struct sadb_msg)) {
result = m_pullup(result, sizeof(struct sadb_msg));
- if (result == NULL)
+ if (result == NULL) {
+ error = ENOBUFS;
goto fail;
+ }
}
result->m_pkthdr.len = 0;
@@ -6608,9 +7087,7 @@ key_parse(m, so)
break;
case SADB_SATYPE_AH:
case SADB_SATYPE_ESP:
-#if 1 /*nonstandard*/
case SADB_X_SATYPE_IPCOMP:
-#endif
switch (msg->sadb_msg_type) {
case SADB_X_SPDADD:
case SADB_X_SPDDELETE:
@@ -6973,8 +7450,10 @@ key_init()
LIST_INIT(&spacqtree);
/* system default */
+#ifdef INET
ip4_def_policy.policy = IPSEC_POLICY_NONE;
ip4_def_policy.refcnt++; /*never reclaim this*/
+#endif
#ifdef INET6
ip6_def_policy.policy = IPSEC_POLICY_NONE;
ip6_def_policy.refcnt++; /*never reclaim this*/
@@ -7167,6 +7646,16 @@ key_sa_chgstate(sav, state)
LIST_INSERT_HEAD(&sav->sah->savtree[state], sav, chain);
}
+void
+key_sa_stir_iv(sav)
+ struct secasvar *sav;
+{
+
+ if (!sav->iv)
+ panic("key_sa_stir_iv called with sav == NULL");
+ key_randomfill(sav->iv, sav->ivlen);
+}
+
/* XXX too much? */
static struct mbuf *
key_alloc_mbuf(l)
diff --git a/sys/netkey/key.h b/sys/netkey/key.h
index 65a2755..20bcaa0 100644
--- a/sys/netkey/key.h
+++ b/sys/netkey/key.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: key.h,v 1.17 2000/06/12 07:01:13 itojun Exp $ */
+/* $KAME: key.h,v 1.20 2001/03/22 08:09:32 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -47,6 +47,8 @@ struct sadb_msg;
struct sadb_x_policy;
extern struct secpolicy *key_allocsp __P((struct secpolicyindex *, u_int));
+extern struct secpolicy *key_gettunnel __P((struct sockaddr *,
+ struct sockaddr *, struct sockaddr *, struct sockaddr *));
extern int key_checkrequest
__P((struct ipsecrequest *isr, struct secasindex *));
extern struct secasvar *key_allocsa __P((u_int, caddr_t, caddr_t,
@@ -61,6 +63,8 @@ extern struct mbuf *key_sp2msg __P((struct secpolicy *));
extern int key_ismyaddr __P((struct sockaddr *));
extern int key_spdacquire __P((struct secpolicy *));
extern void key_timehandler __P((void));
+extern u_long key_random __P((void));
+extern void key_randomfill __P((void *, size_t));
extern void key_freereg __P((struct socket *));
extern int key_parse __P((struct mbuf *, struct socket *));
extern void key_init __P((void));
@@ -68,6 +72,7 @@ extern int key_checktunnelsanity __P((struct secasvar *, u_int,
caddr_t, caddr_t));
extern void key_sa_recordxfer __P((struct secasvar *, struct mbuf *));
extern void key_sa_routechange __P((struct sockaddr *));
+extern void key_sa_stir_iv __P((struct secasvar *));
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_SECA);
diff --git a/sys/netkey/key_debug.c b/sys/netkey/key_debug.c
index 3e8b12b..76a59f3 100644
--- a/sys/netkey/key_debug.c
+++ b/sys/netkey/key_debug.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: key_debug.c,v 1.23 2000/07/04 04:08:15 itojun Exp $ */
+/* $KAME: key_debug.c,v 1.25 2000/07/24 13:23:12 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -41,17 +41,14 @@
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/mbuf.h>
+#include <sys/queue.h>
#endif
#include <sys/socket.h>
#include <net/route.h>
#include <netkey/key_var.h>
-#ifdef IPSEC_DEBUG
#include <netkey/key_debug.h>
-#else
-#define KEYDEBUG(lev,arg)
-#endif
#include <netinet/in.h>
#include <netinet6/ipsec.h>
diff --git a/sys/netkey/key_debug.h b/sys/netkey/key_debug.h
index 383a0e8..f75a535 100644
--- a/sys/netkey/key_debug.h
+++ b/sys/netkey/key_debug.h
@@ -33,6 +33,8 @@
#ifndef _NETKEY_KEY_DEBUG_H_
#define _NETKEY_KEY_DEBUG_H_
+#if !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG))
+
/* debug flags */
#define KEYDEBUG_STAMP 0x00000001 /* path */
#define KEYDEBUG_DATA 0x00000002 /* data */
@@ -84,5 +86,10 @@ extern void kdebug_sockaddr __P((struct sockaddr *));
extern void ipsec_hexdump __P((caddr_t, int));
extern void ipsec_bindump __P((caddr_t, int));
-#endif /* _NETKEY_KEY_DEBUG_H_ */
+#else
+
+#define KEYDEBUG(lev,arg)
+#endif /*!defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG))*/
+
+#endif /* _NETKEY_KEY_DEBUG_H_ */
diff --git a/sys/netkey/key_var.h b/sys/netkey/key_var.h
index b7a62ba..4043a03 100644
--- a/sys/netkey/key_var.h
+++ b/sys/netkey/key_var.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: key_var.h,v 1.8 2000/05/24 17:28:23 itojun Exp $ */
+/* $KAME: key_var.h,v 1.9 2000/10/04 11:13:57 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -42,7 +42,10 @@
#define KEYCTL_LARVAL_LIFETIME 6
#define KEYCTL_BLOCKACQ_COUNT 7
#define KEYCTL_BLOCKACQ_LIFETIME 8
-#define KEYCTL_MAXID 9
+#define KEYCTL_ESP_KEYMIN 9
+#define KEYCTL_ESP_AUTH 10
+#define KEYCTL_AH_KEYMIN 11
+#define KEYCTL_MAXID 12
#define KEYCTL_NAMES { \
{ 0, 0 }, \
@@ -54,8 +57,40 @@
{ "larval_lifetime", CTLTYPE_INT }, \
{ "blockacq_count", CTLTYPE_INT }, \
{ "blockacq_lifetime", CTLTYPE_INT }, \
+ { "esp_keymin", CTLTYPE_INT }, \
+ { "ah_keymin", CTLTYPE_INT }, \
}
+#ifdef IPSEC_DEBUG
+#define KEYCTL_VARS { \
+ 0, \
+ &key_debug_level, \
+ &key_spi_trycnt, \
+ &key_spi_minval, \
+ &key_spi_maxval, \
+ &key_int_random, \
+ &key_larval_lifetime, \
+ &key_blockacq_count, \
+ &key_blockacq_lifetime, \
+ &ipsec_esp_keymin, \
+ &ipsec_ah_keymin, \
+}
+#else
+#define KEYCTL_VARS { \
+ 0, \
+ 0, \
+ &key_spi_trycnt, \
+ &key_spi_minval, \
+ &key_spi_maxval, \
+ &key_int_random, \
+ &key_larval_lifetime, \
+ &key_blockacq_count, \
+ &key_blockacq_lifetime, \
+ &ipsec_esp_keymin, \
+ &ipsec_ah_keymin, \
+}
+#endif
+
#ifdef _KERNEL
#define _ARRAYLEN(p) (sizeof(p)/sizeof(p[0]))
#define _KEYLEN(key) ((u_int)((key)->sadb_key_bits >> 3))
diff --git a/sys/netkey/keydb.h b/sys/netkey/keydb.h
index fcb478c..1aff5be 100644
--- a/sys/netkey/keydb.h
+++ b/sys/netkey/keydb.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: keydb.h,v 1.11 2000/06/15 12:20:50 sakane Exp $ */
+/* $KAME: keydb.h,v 1.14 2000/08/02 17:58:26 sakane Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -82,14 +82,11 @@ struct secasvar {
struct sadb_key *key_enc; /* Key for Encryption */
caddr_t iv; /* Initilization Vector */
u_int ivlen; /* length of IV */
-#if 0
- caddr_t misc1;
- caddr_t misc2;
- caddr_t misc3;
-#endif
+ void *sched; /* intermediate encryption key */
+ size_t schedlen;
struct secreplay *replay; /* replay prevention */
- u_int32_t tick; /* for lifetime */
+ long created; /* for lifetime */
struct sadb_lifetime *lft_c; /* CURRENT lifetime, it's constant. */
struct sadb_lifetime *lft_h; /* HARD lifetime */
@@ -126,7 +123,7 @@ struct secacq {
struct secasindex saidx;
u_int32_t seq; /* sequence number */
- u_int32_t tick; /* for lifetime */
+ long created; /* for lifetime */
int count; /* for lifetime */
};
#endif
diff --git a/sys/netkey/keysock.c b/sys/netkey/keysock.c
index 68c70c8..5eab147 100644
--- a/sys/netkey/keysock.c
+++ b/sys/netkey/keysock.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: keysock.c,v 1.22 2000/05/23 13:19:21 itojun Exp $ */
+/* $KAME: keysock.c,v 1.24 2000/12/03 00:41:48 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -56,11 +56,7 @@
#include <netkey/keydb.h>
#include <netkey/key.h>
#include <netkey/keysock.h>
-#ifdef IPSEC_DEBUG
#include <netkey/key_debug.h>
-#else
-#define KEYDEBUG(lev,arg)
-#endif
#include <machine/stdarg.h>
@@ -158,6 +154,8 @@ key_sendup0(rp, m, promisc)
struct mbuf *m;
int promisc;
{
+ int error;
+
if (promisc) {
struct sadb_msg *pmsg;
@@ -184,17 +182,18 @@ key_sendup0(rp, m, promisc)
pfkeystat.in_msgtype[pmsg->sadb_msg_type]++;
}
- if (!sbappendaddr(&rp->rcb_socket->so_rcv,
- (struct sockaddr *)&key_src, m, NULL)) {
+ if (!sbappendaddr(&rp->rcb_socket->so_rcv, (struct sockaddr *)&key_src,
+ m, NULL)) {
#ifdef IPSEC_DEBUG
printf("key_sendup0: sbappendaddr failed\n");
#endif
pfkeystat.in_nomem++;
m_freem(m);
- return ENOBUFS;
- }
+ error = ENOBUFS;
+ } else
+ error = 0;
sorwakeup(rp->rcb_socket);
- return 0;
+ return error;
}
/* XXX this interface should be obsoleted. */
diff --git a/sys/netsmb/smb_crypt.c b/sys/netsmb/smb_crypt.c
index e72a385..89b6d9e 100644
--- a/sys/netsmb/smb_crypt.c
+++ b/sys/netsmb/smb_crypt.c
@@ -74,8 +74,8 @@ smb_E(const u_char *key, u_char *data, u_char *dest)
kk[6] = key[5] << 2 | (key[6] >> 6 & 0xfe);
kk[7] = key[6] << 1;
ksp = malloc(sizeof(des_key_schedule), M_SMBTEMP, M_WAITOK);
- des_set_key((C_Block*)kk, *ksp);
- des_ecb_encrypt((C_Block*)data, (C_Block*)dest, *ksp, 1);
+ des_set_key((des_cblock *)kk, *ksp);
+ des_ecb_encrypt((des_cblock *)data, (des_cblock *)dest, *ksp, 1);
free(ksp, M_SMBTEMP);
}
#endif
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index de7a3c9..da23e27 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -228,6 +228,20 @@ struct mbstat {
u_long m_minclsize; /* min length of data to allocate a cluster */
u_long m_mlen; /* length of data in an mbuf */
u_long m_mhlen; /* length of data in a header mbuf */
+
+ u_quad_t m_exthdrget; /* # of calls to IP6_EXTHDR_GET */
+ u_quad_t m_exthdrget0; /* # of calls to IP6_EXTHDR_GET0 */
+ u_quad_t m_pulldowns; /* # of calls to m_pulldown */
+ u_quad_t m_pulldown_copy; /* # of mbuf copies in m_pulldown */
+ u_quad_t m_pulldown_alloc; /* # of mbuf allocs in m_pulldown */
+ u_quad_t m_pullups; /* # of calls to m_pullup */
+ u_quad_t m_pullup_copy; /* # of possible m_pullup copies */
+ u_quad_t m_pullup_alloc; /* # of possible m_pullup mallocs */
+ u_quad_t m_pullup_fail; /* # of possible m_pullup failures */
+ u_quad_t m_pullup2; /* # of calls to m_pullup2 */
+ u_quad_t m_pullup2_copy; /* # of possible m_pullup2 copies */
+ u_quad_t m_pullup2_alloc; /* # of possible m_pullup2 mallocs */
+ u_quad_t m_pullup2_fail; /* # of possible m_pullup2 failures */
};
/* flags to m_get/MGET */
@@ -524,6 +538,10 @@ struct mcntfree_lst {
* MFREE(struct mbuf *m, struct mbuf *n)
* Free a single mbuf and associated external storage.
* Place the successor, if any, in n.
+ *
+ * we do need to check non-first mbuf for m_aux, since some of existing
+ * code does not call M_PREPEND properly.
+ * (example: call to bpf_mtap from drivers)
*/
#define MFREE(m, n) do { \
struct mbuf *_mm = (m); \
@@ -533,6 +551,10 @@ struct mcntfree_lst {
MEXTFREE(_mm); \
mtx_lock(&mbuf_mtx); \
mbtypes[_mm->m_type]--; \
+ if ((_mm->m_flags & M_PKTHDR) != 0 && _mm->m_pkthdr.aux) { \
+ m_freem(_mm->m_pkthdr.aux); \
+ _mm->m_pkthdr.aux = NULL; \
+ } \
_mm->m_type = MT_FREE; \
mbtypes[MT_FREE]++; \
(n) = _mm->m_next; \
@@ -649,6 +671,7 @@ struct mcntfree_lst {
struct mauxtag {
int af;
int type;
+ void* p;
};
extern u_long m_clalloc_wid; /* mbuf cluster wait count */
@@ -672,6 +695,8 @@ extern int nsfbufs;
void m_adj(struct mbuf *, int);
int m_alloc_ref(u_int, int);
+struct mbuf *m_aux_add2 __P((struct mbuf *, int, int, void *));
+struct mbuf *m_aux_find2 __P((struct mbuf *, int, int, void *));
struct mbuf *m_aux_add(struct mbuf *, int, int);
void m_aux_delete(struct mbuf *, struct mbuf *);
struct mbuf *m_aux_find(struct mbuf *, int, int);
diff --git a/sys/sys/protosw.h b/sys/sys/protosw.h
index 6742f7a..00d50ff 100644
--- a/sys/sys/protosw.h
+++ b/sys/sys/protosw.h
@@ -119,6 +119,7 @@ struct protosw {
#define PR_WANTRCVD 0x08 /* want PRU_RCVD calls */
#define PR_RIGHTS 0x10 /* passes capabilities */
#define PR_IMPLOPCL 0x20 /* implied open/close */
+#define PR_LASTHDR 0x40 /* enforce ipsec policy; last header */
/*
* The arguments to usrreq are:
@@ -319,6 +320,7 @@ char *prcorequests[] = {
#ifdef _KERNEL
void pfctlinput __P((int, struct sockaddr *));
+void pfctlinput2 __P((int, struct sockaddr *, void *));
struct protosw *pffindproto __P((int family, int protocol, int type));
struct protosw *pffindtype __P((int family, int type));
#endif
diff --git a/sys/sys/socket.h b/sys/sys/socket.h
index dfa90fa..3673ff6 100644
--- a/sys/sys/socket.h
+++ b/sys/sys/socket.h
@@ -49,6 +49,13 @@
/*
* Data types.
*/
+#include <machine/types.h>
+
+/*
+ * needed for __CMSG_ALIGN
+ */
+#include <machine/param.h>
+
typedef u_char sa_family_t;
#ifdef _BSD_SOCKLEN_T_
typedef _BSD_SOCKLEN_T_ socklen_t;
@@ -373,22 +380,27 @@ struct cmsgcred {
/* given pointer to struct cmsghdr, return pointer to data */
#define CMSG_DATA(cmsg) ((u_char *)(cmsg) + \
- _ALIGN(sizeof(struct cmsghdr)))
+ __CMSG_ALIGN(sizeof(struct cmsghdr)))
+
+#define __CMSG_ALIGN(n) ALIGN(n)
+#ifdef _KERNEL
+#define CMSG_ALIGN(n) __CMSG_ALIGN(n)
+#endif
/* given pointer to struct cmsghdr, return pointer to next cmsghdr */
#define CMSG_NXTHDR(mhdr, cmsg) \
- (((caddr_t)(cmsg) + _ALIGN((cmsg)->cmsg_len) + \
- _ALIGN(sizeof(struct cmsghdr)) > \
+ (((caddr_t)(cmsg) + __CMSG_ALIGN((cmsg)->cmsg_len) + \
+ __CMSG_ALIGN(sizeof(struct cmsghdr)) > \
(caddr_t)(mhdr)->msg_control + (mhdr)->msg_controllen) ? \
(struct cmsghdr *)NULL : \
- (struct cmsghdr *)((caddr_t)(cmsg) + _ALIGN((cmsg)->cmsg_len)))
+ (struct cmsghdr *)((caddr_t)(cmsg) + __CMSG_ALIGN((cmsg)->cmsg_len)))
#define CMSG_FIRSTHDR(mhdr) ((struct cmsghdr *)(mhdr)->msg_control)
/* RFC 2292 additions */
-
-#define CMSG_SPACE(l) (_ALIGN(sizeof(struct cmsghdr)) + _ALIGN(l))
-#define CMSG_LEN(l) (_ALIGN(sizeof(struct cmsghdr)) + (l))
+
+#define CMSG_SPACE(l) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(l))
+#define CMSG_LEN(l) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + (l))
/* "Socket"-level control message types: */
#define SCM_RIGHTS 0x01 /* access rights (array of int) */
diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h
index c107562..74c2a95 100644
--- a/sys/sys/sockio.h
+++ b/sys/sys/sockio.h
@@ -91,6 +91,8 @@
#define SIOCGIFPSRCADDR _IOWR('i', 71, struct ifreq) /* get gif psrc addr */
#define SIOCGIFPDSTADDR _IOWR('i', 72, struct ifreq) /* get gif pdst addr */
#define SIOCDIFPHYADDR _IOW('i', 73, struct ifreq) /* delete gif addrs */
+#define SIOCSLIFPHYADDR _IOW('i', 74, struct if_laddrreq) /* set gif addrs */
+#define SIOCGLIFPHYADDR _IOWR('i', 75, struct if_laddrreq) /* get gif addrs */
#define SIOCSIFGENERIC _IOW('i', 57, struct ifreq) /* generic IF set op */
#define SIOCGIFGENERIC _IOWR('i', 58, struct ifreq) /* generic IF get op */
OpenPOWER on IntegriCloud