aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@FreeBSD.org>2000-07-04 16:35:15 +0000
committerJun-ichiro itojun Hagino <itojun@FreeBSD.org>2000-07-04 16:35:15 +0000
commit686cdd19b1b182f2257bc158116e78c5fef84980 (patch)
tree22136d6c52358a61b8b21d1cda50d53ec766ab1e
parent2d311b79cdb0da87624d7791e2fc72067edc5217 (diff)
downloadsrc-686cdd19b1b182f2257bc158116e78c5fef84980.tar.gz
src-686cdd19b1b182f2257bc158116e78c5fef84980.zip
sync with kame tree as of july00. tons of bug fixes/improvements.
API changes: - additional IPv6 ioctls - IPsec PF_KEY API was changed, it is mandatory to upgrade setkey(8). (also syntax change)
Notes
Notes: svn path=/head/; revision=62587
-rw-r--r--sys/conf/files12
-rw-r--r--sys/crypto/blowfish/bf_cbc.c5
-rw-r--r--sys/crypto/blowfish/bf_cbc_m.c21
-rw-r--r--sys/crypto/blowfish/bf_enc.c5
-rw-r--r--sys/crypto/blowfish/bf_locl.h37
-rw-r--r--sys/crypto/blowfish/bf_pi.h5
-rw-r--r--sys/crypto/blowfish/bf_skey.c5
-rw-r--r--sys/crypto/blowfish/blowfish.h20
-rw-r--r--sys/crypto/cast128/cast128.c5
-rw-r--r--sys/crypto/cast128/cast128.h9
-rw-r--r--sys/crypto/cast128/cast128_cbc.c19
-rw-r--r--sys/crypto/cast128/cast128_subkey.h97
-rw-r--r--sys/crypto/des/des.h73
-rw-r--r--sys/crypto/des/des_3cbc.c18
-rw-r--r--sys/crypto/des/des_cbc.c21
-rw-r--r--sys/crypto/des/des_ecb.c7
-rw-r--r--sys/crypto/des/des_locl.h69
-rw-r--r--sys/crypto/des/des_setkey.c11
-rw-r--r--sys/crypto/des/podd.h5
-rw-r--r--sys/crypto/des/sk.h5
-rw-r--r--sys/crypto/des/spr.h5
-rw-r--r--sys/crypto/md5.c91
-rw-r--r--sys/crypto/md5.h31
-rw-r--r--sys/crypto/rc5/rc5.c5
-rw-r--r--sys/crypto/rc5/rc5.h57
-rw-r--r--sys/crypto/rc5/rc5_cbc.c18
-rw-r--r--sys/crypto/sha1.c11
-rw-r--r--sys/crypto/sha1.h15
-rw-r--r--sys/kern/uipc_mbuf.c9
-rw-r--r--sys/kern/uipc_mbuf2.c419
-rw-r--r--sys/net/if_ethersubr.c4
-rw-r--r--sys/net/if_gif.c335
-rw-r--r--sys/net/if_gif.h52
-rw-r--r--sys/net/if_loop.c2
-rw-r--r--sys/net/if_stf.c662
-rw-r--r--sys/net/if_stf.h (renamed from sys/crypto/hmac_md5.h)15
-rw-r--r--sys/net/if_types.h1
-rw-r--r--sys/net/net_osdep.c6
-rw-r--r--sys/net/net_osdep.h56
-rw-r--r--sys/net/pfkeyv2.h544
-rw-r--r--sys/netinet/icmp6.h634
-rw-r--r--sys/netinet/in.c1
-rw-r--r--sys/netinet/in.h31
-rw-r--r--sys/netinet/in_gif.c242
-rw-r--r--sys/netinet/in_gif.h19
-rw-r--r--sys/netinet/in_pcb.c4
-rw-r--r--sys/netinet/in_proto.c41
-rw-r--r--sys/netinet/ip6.h280
-rw-r--r--sys/netinet/ip_ecn.c5
-rw-r--r--sys/netinet/ip_ecn.h11
-rw-r--r--sys/netinet/ip_encap.c534
-rw-r--r--sys/netinet/ip_encap.h (renamed from sys/crypto/hmac_md5.c)96
-rw-r--r--sys/netinet/ip_input.c5
-rw-r--r--sys/netinet/ip_output.c45
-rw-r--r--sys/netinet/ip_var.h3
-rw-r--r--sys/netinet/raw_ip.c5
-rw-r--r--sys/netinet/tcp_debug.c2
-rw-r--r--sys/netinet/tcp_input.c18
-rw-r--r--sys/netinet/tcp_output.c41
-rw-r--r--sys/netinet/tcp_reass.c18
-rw-r--r--sys/netinet/tcp_subr.c12
-rw-r--r--sys/netinet/tcp_timewait.c12
-rw-r--r--sys/netinet/udp_usrreq.c12
-rw-r--r--sys/netinet6/README28
-rw-r--r--sys/netinet6/ah.h21
-rw-r--r--sys/netinet6/ah6.h11
-rw-r--r--sys/netinet6/ah_core.c810
-rw-r--r--sys/netinet6/ah_input.c445
-rw-r--r--sys/netinet6/ah_output.c117
-rw-r--r--sys/netinet6/dest6.c24
-rw-r--r--sys/netinet6/esp.h12
-rw-r--r--sys/netinet6/esp6.h9
-rw-r--r--sys/netinet6/esp_core.c360
-rw-r--r--sys/netinet6/esp_input.c613
-rw-r--r--sys/netinet6/esp_output.c169
-rw-r--r--sys/netinet6/frag6.c225
-rw-r--r--sys/netinet6/icmp6.c1432
-rw-r--r--sys/netinet6/icmp6.h617
-rw-r--r--sys/netinet6/in6.c968
-rw-r--r--sys/netinet6/in6.h319
-rw-r--r--sys/netinet6/in6_cksum.c34
-rw-r--r--sys/netinet6/in6_gif.c153
-rw-r--r--sys/netinet6/in6_gif.h19
-rw-r--r--sys/netinet6/in6_ifattach.c1126
-rw-r--r--sys/netinet6/in6_ifattach.h23
-rw-r--r--sys/netinet6/in6_pcb.c220
-rw-r--r--sys/netinet6/in6_pcb.h13
-rw-r--r--sys/netinet6/in6_prefix.c194
-rw-r--r--sys/netinet6/in6_prefix.h70
-rw-r--r--sys/netinet6/in6_proto.c217
-rw-r--r--sys/netinet6/in6_rmx.c32
-rw-r--r--sys/netinet6/in6_src.c550
-rw-r--r--sys/netinet6/in6_var.h432
-rw-r--r--sys/netinet6/ip6.h255
-rw-r--r--sys/netinet6/ip6_ecn.h8
-rw-r--r--sys/netinet6/ip6_forward.c237
-rw-r--r--sys/netinet6/ip6_fw.c41
-rw-r--r--sys/netinet6/ip6_fw.h182
-rw-r--r--sys/netinet6/ip6_input.c586
-rw-r--r--sys/netinet6/ip6_mroute.c332
-rw-r--r--sys/netinet6/ip6_mroute.h281
-rw-r--r--sys/netinet6/ip6_output.c339
-rw-r--r--sys/netinet6/ip6_var.h186
-rw-r--r--sys/netinet6/ip6protosw.h25
-rw-r--r--sys/netinet6/ipcomp.h67
-rw-r--r--sys/netinet6/ipcomp6.h46
-rw-r--r--sys/netinet6/ipcomp_core.c314
-rw-r--r--sys/netinet6/ipcomp_input.c407
-rw-r--r--sys/netinet6/ipcomp_output.c430
-rw-r--r--sys/netinet6/ipsec.c941
-rw-r--r--sys/netinet6/ipsec.h314
-rw-r--r--sys/netinet6/ipsec6.h73
-rw-r--r--sys/netinet6/mld6.c114
-rw-r--r--sys/netinet6/mld6_var.h13
-rw-r--r--sys/netinet6/nd6.c700
-rw-r--r--sys/netinet6/nd6.h323
-rw-r--r--sys/netinet6/nd6_nbr.c392
-rw-r--r--sys/netinet6/nd6_rtr.c581
-rw-r--r--sys/netinet6/pim6.h17
-rw-r--r--sys/netinet6/pim6_var.h35
-rw-r--r--sys/netinet6/raw_ip6.c98
-rw-r--r--sys/netinet6/route6.c98
-rw-r--r--sys/netinet6/scope6.c302
-rw-r--r--sys/netinet6/scope6_var.h46
-rw-r--r--sys/netinet6/tcp6_var.h2
-rw-r--r--sys/netinet6/udp6_output.c285
-rw-r--r--sys/netinet6/udp6_usrreq.c178
-rw-r--r--sys/netinet6/udp6_var.h2
-rw-r--r--sys/netkey/key.c5305
-rw-r--r--sys/netkey/key.h49
-rw-r--r--sys/netkey/key_debug.c184
-rw-r--r--sys/netkey/key_debug.h45
-rw-r--r--sys/netkey/key_var.h68
-rw-r--r--sys/netkey/keydb.c217
-rw-r--r--sys/netkey/keydb.h120
-rw-r--r--sys/netkey/keysock.c589
-rw-r--r--sys/netkey/keysock.h60
-rw-r--r--sys/sys/mbuf.h18
-rw-r--r--sys/sys/sockio.h2
139 files changed, 19651 insertions, 9377 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 1939ca17840a..a4f9d214a335 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -462,6 +462,7 @@ kern/tty_subr.c standard
kern/tty_tty.c standard
kern/uipc_domain.c standard
kern/uipc_mbuf.c standard
+kern/uipc_mbuf2.c standard
kern/uipc_proto.c standard
kern/uipc_socket.c standard
kern/uipc_socket2.c standard
@@ -565,6 +566,7 @@ net/if_mib.c standard
net/if_ppp.c count ppp
net/if_sl.c optional sl
net/if_spppsubr.c optional sppp
+net/if_stf.c count stf
net/if_tun.c optional tun
net/if_vlan.c count vlan
net/intrq.c standard
@@ -580,6 +582,7 @@ net/rtsock.c standard
net/slcompress.c optional ppp
net/slcompress.c optional sl
net/zlib.c optional ppp_deflate
+net/zlib.c optional ipsec
netatalk/aarp.c optional netatalk
netatalk/at_control.c optional netatalk
netatalk/at_proto.c optional netatalk
@@ -715,6 +718,8 @@ netinet/ip_divert.c optional ipdivert
netinet/ip_dummynet.c optional dummynet
netinet/ip_ecn.c optional inet
netinet/ip_ecn.c optional inet6
+netinet/ip_encap.c optional inet
+netinet/ip_encap.c optional inet6
netinet/ip_fil.c optional ipfilter inet
netinet/ip_flow.c optional inet
netinet/ip_frag.c optional ipfilter inet
@@ -753,11 +758,15 @@ netinet6/in6_pcb.c optional inet6
netinet6/in6_prefix.c optional inet6
netinet6/in6_proto.c optional inet6
netinet6/in6_rmx.c optional inet6
+netinet6/in6_src.c optional inet6
netinet6/ip6_forward.c optional inet6
netinet6/ip6_fw.c optional inet6 ipv6firewall
netinet6/ip6_input.c optional inet6
netinet6/ip6_mroute.c optional inet6
netinet6/ip6_output.c optional inet6
+netinet6/ipcomp_core.c optional ipsec
+netinet6/ipcomp_input.c optional ipsec
+netinet6/ipcomp_output.c optional ipsec
netinet6/ipsec.c optional ipsec
netinet6/mld6.c optional inet6
netinet6/nd6.c optional inet6
@@ -765,6 +774,8 @@ netinet6/nd6_nbr.c optional inet6
netinet6/nd6_rtr.c optional inet6
netinet6/raw_ip6.c optional inet6
netinet6/route6.c optional inet6
+netinet6/scope6.c optional inet6
+netinet6/udp6_output.c optional inet6
netinet6/udp6_usrreq.c optional inet6
netipx/ipx.c optional ipx
netipx/ipx_cksum.c optional ipx
@@ -778,6 +789,7 @@ 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/keysock.c optional ipsec
netnatm/natm.c optional natm
diff --git a/sys/crypto/blowfish/bf_cbc.c b/sys/crypto/blowfish/bf_cbc.c
index 47092cb00876..6eb6d3b0c0d2 100644
--- a/sys/crypto/blowfish/bf_cbc.c
+++ b/sys/crypto/blowfish/bf_cbc.c
@@ -1,3 +1,6 @@
+/* $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.
@@ -54,8 +57,6 @@
* 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.]
- *
- * $FreeBSD$
*/
#include <crypto/blowfish/blowfish.h>
diff --git a/sys/crypto/blowfish/bf_cbc_m.c b/sys/crypto/blowfish/bf_cbc_m.c
index 20df977ce78a..088adad1441c 100644
--- a/sys/crypto/blowfish/bf_cbc_m.c
+++ b/sys/crypto/blowfish/bf_cbc_m.c
@@ -1,3 +1,6 @@
+/* $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.
@@ -58,8 +61,6 @@
* 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.]
- *
- * $FreeBSD$
*/
#include <sys/param.h>
@@ -69,9 +70,9 @@
#include <crypto/blowfish/blowfish.h>
#include <crypto/blowfish/bf_locl.h>
-#define panic(x) {printf(x); return;}
+#define panic(x) do { printf(x); return EINVAL; } while (0)
-void BF_cbc_encrypt_m(m0, skip, length, key, iv, mode)
+int BF_cbc_encrypt_m(m0, skip, length, key, iv, mode)
struct mbuf *m0;
int skip;
int length;
@@ -89,19 +90,19 @@ void BF_cbc_encrypt_m(m0, skip, length, key, iv, mode)
/* sanity checks */
if (m0->m_pkthdr.len < skip) {
printf("mbuf length < skip\n");
- return;
+ return EINVAL;
}
if (m0->m_pkthdr.len < length) {
printf("mbuf length < encrypt length\n");
- return;
+ return EINVAL;
}
if (m0->m_pkthdr.len < skip + length) {
printf("mbuf length < skip + encrypt length\n");
- return;
+ return EINVAL;
}
if (length % 8) {
printf("length is not multiple of 8\n");
- return;
+ return EINVAL;
}
m = m0;
@@ -155,7 +156,7 @@ void BF_cbc_encrypt_m(m0, skip, length, key, iv, mode)
while (in - &inbuf[0] < 8) {
if (!p)
panic("mbuf chain?\n");
-
+
*in++ = *p++;
noff++;
if (noff < n->m_len)
@@ -337,4 +338,6 @@ void BF_cbc_encrypt_m(m0, skip, length, key, iv, mode)
length -= 8;
}
}
+
+ return 0;
}
diff --git a/sys/crypto/blowfish/bf_enc.c b/sys/crypto/blowfish/bf_enc.c
index b24e538ae328..6a3bef672295 100644
--- a/sys/crypto/blowfish/bf_enc.c
+++ b/sys/crypto/blowfish/bf_enc.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: bf_enc.c,v 1.3 2000/03/27 04:36:26 sumikawa Exp $ */
+
/* crypto/bf/bf_enc.c */
/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
* All rights reserved.
@@ -54,8 +57,6 @@
* 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.]
- *
- * $FreeBSD$
*/
#include <crypto/blowfish/blowfish.h>
diff --git a/sys/crypto/blowfish/bf_locl.h b/sys/crypto/blowfish/bf_locl.h
index e0b62f1c8e15..07598d2ed255 100644
--- a/sys/crypto/blowfish/bf_locl.h
+++ b/sys/crypto/blowfish/bf_locl.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: bf_locl.h,v 1.3 2000/03/27 04:36:26 sumikawa Exp $ */
+
/* crypto/bf/bf_local.h */
/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
* All rights reserved.
@@ -54,8 +57,6 @@
* 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.]
- *
- * $FreeBSD$
*/
/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
*
@@ -66,14 +67,14 @@
*/
#undef c2l
-#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \
+#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \
l|=((unsigned long)(*((c)++)))<< 8L, \
l|=((unsigned long)(*((c)++)))<<16L, \
l|=((unsigned long)(*((c)++)))<<24L)
/* NOTE - c is not incremented as per c2l */
#undef c2ln
-#define c2ln(c,l1,l2,n) { \
+#define c2ln(c,l1,l2,n) { \
c+=n; \
l1=l2=0; \
switch (n) { \
@@ -89,14 +90,14 @@
}
#undef l2c
-#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
*((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
*((c)++)=(unsigned char)(((l)>>16L)&0xff), \
*((c)++)=(unsigned char)(((l)>>24L)&0xff))
/* NOTE - c is not incremented as per l2c */
#undef l2cn
-#define l2cn(l1,l2,c,n) { \
+#define l2cn(l1,l2,c,n) { \
c+=n; \
switch (n) { \
case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \
@@ -111,7 +112,7 @@
}
/* NOTE - c is not incremented as per n2l */
-#define n2ln(c,l1,l2,n) { \
+#define n2ln(c,l1,l2,n) { \
c+=n; \
l1=l2=0; \
switch (n) { \
@@ -127,7 +128,7 @@
}
/* NOTE - c is not incremented as per l2n */
-#define l2nn(l1,l2,c,n) { \
+#define l2nn(l1,l2,c,n) { \
c+=n; \
switch (n) { \
case 8: *(--(c))=(unsigned char)(((l2) )&0xff); \
@@ -142,13 +143,13 @@
}
#undef n2l
-#define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24L, \
+#define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24L, \
l|=((unsigned long)(*((c)++)))<<16L, \
l|=((unsigned long)(*((c)++)))<< 8L, \
l|=((unsigned long)(*((c)++))))
#undef l2n
-#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
+#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
*((c)++)=(unsigned char)(((l)>>16L)&0xff), \
*((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
*((c)++)=(unsigned char)(((l) )&0xff))
@@ -164,16 +165,16 @@
#undef BF_PTR
#endif
-#define BF_M 0x3fc
-#define BF_0 22L
-#define BF_1 14L
-#define BF_2 6L
-#define BF_3 2L /* left shift */
+#define BF_M 0x3fc
+#define BF_0 22L
+#define BF_1 14L
+#define BF_2 6L
+#define BF_3 2L /* left shift */
#if defined(BF_PTR2)
/* This is basically a special pentium verson */
-#define BF_ENC(LL,R,S,P) \
+#define BF_ENC(LL,R,S,P) \
{ \
BF_LONG t,u,v; \
u=R>>BF_0; \
@@ -196,7 +197,7 @@
/* This is normally very good */
-#define BF_ENC(LL,R,S,P) \
+#define BF_ENC(LL,R,S,P) \
LL^=P; \
LL^= (((*(BF_LONG *)((unsigned char *)&(S[ 0])+((R>>BF_0)&BF_M))+ \
*(BF_LONG *)((unsigned char *)&(S[256])+((R>>BF_1)&BF_M)))^ \
@@ -208,7 +209,7 @@
* on the Alpha it is faster than the pointer versions (both 32 and 64
* versions of BF_LONG) */
-#define BF_ENC(LL,R,S,P) \
+#define BF_ENC(LL,R,S,P) \
LL^=P; \
LL^=((( S[ (R>>24L) ] + \
S[0x0100+((R>>16L)&0xff)])^ \
diff --git a/sys/crypto/blowfish/bf_pi.h b/sys/crypto/blowfish/bf_pi.h
index 1a397e87c044..8982aac4a9c0 100644
--- a/sys/crypto/blowfish/bf_pi.h
+++ b/sys/crypto/blowfish/bf_pi.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: bf_pi.h,v 1.3 2000/03/27 04:36:26 sumikawa Exp $ */
+
/* crypto/bf/bf_pi.h */
/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
* All rights reserved.
@@ -54,8 +57,6 @@
* 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.]
- *
- * $FreeBSD$
*/
static BF_KEY bf_init= {
diff --git a/sys/crypto/blowfish/bf_skey.c b/sys/crypto/blowfish/bf_skey.c
index 04729e1bf0de..5717c3f59547 100644
--- a/sys/crypto/blowfish/bf_skey.c
+++ b/sys/crypto/blowfish/bf_skey.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: bf_skey.c,v 1.3 2000/03/27 04:36:27 sumikawa Exp $ */
+
/* crypto/bf/bf_skey.c */
/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
* All rights reserved.
@@ -54,8 +57,6 @@
* 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.]
- *
- * $FreeBSD$
*/
#include <sys/types.h>
diff --git a/sys/crypto/blowfish/blowfish.h b/sys/crypto/blowfish/blowfish.h
index d8e6d91b261c..c96b4ec08bb0 100644
--- a/sys/crypto/blowfish/blowfish.h
+++ b/sys/crypto/blowfish/blowfish.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: blowfish.h,v 1.4 2000/06/14 10:41:16 itojun Exp $ */
+
/* crypto/bf/blowfish.h */
/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
* All rights reserved.
@@ -54,28 +57,26 @@
* 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.]
- *
- * $FreeBSD$
*/
#ifndef HEADER_BLOWFISH_H
-#define HEADER_BLOWFISH_H
+#define HEADER_BLOWFISH_H
#ifdef __cplusplus
extern "C" {
#endif
-#define BF_ENCRYPT 1
-#define BF_DECRYPT 0
+#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
+#define BF_LONG unsigned long
-#define BF_ROUNDS 16
-#define BF_BLOCK 8
+#define BF_ROUNDS 16
+#define BF_BLOCK 8
typedef struct bf_key_st
{
@@ -99,8 +100,7 @@ char *BF_options(void);
/* added by itojun */
struct mbuf;
-void BF_cbc_encrypt_m(struct mbuf *, int, int, BF_KEY *,
- unsigned char *, int);
+int BF_cbc_encrypt_m(struct mbuf *, int, int, BF_KEY *, unsigned char *, int);
#else
diff --git a/sys/crypto/cast128/cast128.c b/sys/crypto/cast128/cast128.c
index 72ed733201c4..4df1be900f62 100644
--- a/sys/crypto/cast128/cast128.c
+++ b/sys/crypto/cast128/cast128.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: cast128.c,v 1.3 2000/03/27 04:36:29 sumikawa Exp $ */
+
/*
* heavily modified by Tomomi Suzuki <suzuki@grelot.elec.ryukoku.ac.jp>
*/
@@ -31,8 +34,6 @@
* 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.
- *
- * $FreeBSD$
*/
#include <sys/param.h>
diff --git a/sys/crypto/cast128/cast128.h b/sys/crypto/cast128/cast128.h
index 31c0397dac50..019c2de1306d 100644
--- a/sys/crypto/cast128/cast128.h
+++ b/sys/crypto/cast128/cast128.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: cast128.h,v 1.4 2000/06/14 10:41:16 itojun Exp $ */
+
/*
* heavily modified by Tomomi Suzuki <suzuki@grelot.elec.ryukoku.ac.jp>
*/
@@ -31,12 +34,10 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef RFC2144_CAST_128_H
-#define RFC2144_CAST_128_H
+#define RFC2144_CAST_128_H
#include <sys/param.h>
#include <sys/mbuf.h>
@@ -55,7 +56,7 @@ 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 void cast128_cbc_process __P((struct mbuf *, size_t, size_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
index 1dfe2d87b802..e4725a945400 100644
--- a/sys/crypto/cast128/cast128_cbc.c
+++ b/sys/crypto/cast128/cast128_cbc.c
@@ -1,3 +1,6 @@
+/* $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.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
* based on sys/crypto/des/des_cbc.c, rewrote by Tomomi Suzuki
@@ -37,8 +38,9 @@
#include <sys/mbuf.h>
#include <crypto/cast128/cast128.h>
+#define panic(x) do { printf(x); return EINVAL; } while (0)
-void
+int
cast128_cbc_process(m0, skip, length, subkey, iv, keylen, mode)
struct mbuf *m0;
size_t skip;
@@ -55,20 +57,20 @@ cast128_cbc_process(m0, skip, length, subkey, iv, keylen, mode)
/* sanity check */
if (m0->m_pkthdr.len < skip) {
printf("cast128_cbc_process: mbuf length < skip\n");
- return;
+ return EINVAL;
}
if (m0->m_pkthdr.len < length) {
printf("cast128_cbc_process: mbuf length < encrypt length\n");
- return;
+ return EINVAL;
}
if (m0->m_pkthdr.len < skip + length) {
printf("cast128_cbc_process: "
"mbuf length < skip + encrypt length\n");
- return;
+ return EINVAL;
}
if (length % 8) {
printf("cast128_cbc_process: length is not multiple of 8\n");
- return;
+ return EINVAL;
}
m = m0;
@@ -215,5 +217,6 @@ cast128_cbc_process(m0, skip, length, subkey, iv, keylen, mode)
length -= 8;
}
-}
+ return 0;
+}
diff --git a/sys/crypto/cast128/cast128_subkey.h b/sys/crypto/cast128/cast128_subkey.h
index 3fd010311691..fafac45087c9 100644
--- a/sys/crypto/cast128/cast128_subkey.h
+++ b/sys/crypto/cast128/cast128_subkey.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: cast128_subkey.h,v 1.3 2000/03/27 04:36:30 sumikawa Exp $ */
+
/*
* heavily modified by Tomomi Suzuki <suzuki@grelot.elec.ryukoku.ac.jp>
*/
@@ -31,61 +34,59 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef RFC2144_CAST_128_SUBKEY_H
-#define RFC2144_CAST_128_SUBKEY_H
+#define RFC2144_CAST_128_SUBKEY_H
-#define x0x1x2x3 buf[0]
-#define x4x5x6x7 buf[1]
-#define x8x9xAxB buf[2]
-#define xCxDxExF buf[3]
-#define z0z1z2z3 buf[4]
-#define z4z5z6z7 buf[5]
-#define z8z9zAzB buf[6]
-#define zCzDzEzF buf[7]
+#define x0x1x2x3 buf[0]
+#define x4x5x6x7 buf[1]
+#define x8x9xAxB buf[2]
+#define xCxDxExF buf[3]
+#define z0z1z2z3 buf[4]
+#define z4z5z6z7 buf[5]
+#define z8z9zAzB buf[6]
+#define zCzDzEzF buf[7]
-#define byte0(x) (((x) >> 24))
-#define byte1(x) (((x) >> 16) & 0xff)
-#define byte2(x) (((x) >> 8) & 0xff)
-#define byte3(x) (((x)) & 0xff)
+#define byte0(x) (((x) >> 24))
+#define byte1(x) (((x) >> 16) & 0xff)
+#define byte2(x) (((x) >> 8) & 0xff)
+#define byte3(x) (((x)) & 0xff)
-#define x0 byte0(buf[0])
-#define x1 byte1(buf[0])
-#define x2 byte2(buf[0])
-#define x3 byte3(buf[0])
-#define x4 byte0(buf[1])
-#define x5 byte1(buf[1])
-#define x6 byte2(buf[1])
-#define x7 byte3(buf[1])
-#define x8 byte0(buf[2])
-#define x9 byte1(buf[2])
-#define xA byte2(buf[2])
-#define xB byte3(buf[2])
-#define xC byte0(buf[3])
-#define xD byte1(buf[3])
-#define xE byte2(buf[3])
-#define xF byte3(buf[3])
-#define z0 byte0(buf[4])
-#define z1 byte1(buf[4])
-#define z2 byte2(buf[4])
-#define z3 byte3(buf[4])
-#define z4 byte0(buf[5])
-#define z5 byte1(buf[5])
-#define z6 byte2(buf[5])
-#define z7 byte3(buf[5])
-#define z8 byte0(buf[6])
-#define z9 byte1(buf[6])
-#define zA byte2(buf[6])
-#define zB byte3(buf[6])
-#define zC byte0(buf[7])
-#define zD byte1(buf[7])
-#define zE byte2(buf[7])
-#define zF byte3(buf[7])
+#define x0 byte0(buf[0])
+#define x1 byte1(buf[0])
+#define x2 byte2(buf[0])
+#define x3 byte3(buf[0])
+#define x4 byte0(buf[1])
+#define x5 byte1(buf[1])
+#define x6 byte2(buf[1])
+#define x7 byte3(buf[1])
+#define x8 byte0(buf[2])
+#define x9 byte1(buf[2])
+#define xA byte2(buf[2])
+#define xB byte3(buf[2])
+#define xC byte0(buf[3])
+#define xD byte1(buf[3])
+#define xE byte2(buf[3])
+#define xF byte3(buf[3])
+#define z0 byte0(buf[4])
+#define z1 byte1(buf[4])
+#define z2 byte2(buf[4])
+#define z3 byte3(buf[4])
+#define z4 byte0(buf[5])
+#define z5 byte1(buf[5])
+#define z6 byte2(buf[5])
+#define z7 byte3(buf[5])
+#define z8 byte0(buf[6])
+#define z9 byte1(buf[6])
+#define zA byte2(buf[6])
+#define zB byte3(buf[6])
+#define zC byte0(buf[7])
+#define zD byte1(buf[7])
+#define zE byte2(buf[7])
+#define zF byte3(buf[7])
-#define circular_leftshift(x, y) ( ((x) << (y)) | ((x) >> (32-(y))) )
+#define circular_leftshift(x, y) ( ((x) << (y)) | ((x) >> (32-(y))) )
#endif
diff --git a/sys/crypto/des/des.h b/sys/crypto/des/des.h
index 16a8129fea9d..536f0c992f7c 100644
--- a/sys/crypto/des/des.h
+++ b/sys/crypto/des/des.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: des.h,v 1.4 2000/06/14 10:41:17 itojun Exp $ */
+
/* lib/des/des.h */
/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
* All rights reserved.
@@ -43,12 +46,10 @@
* 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.]
- *
- * $FreeBSD$
*/
#ifndef HEADER_DES_H
-#define HEADER_DES_H
+#define HEADER_DES_H
#ifdef __cplusplus
extern "C" {
@@ -57,7 +58,7 @@ extern "C" {
/* 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
+#define DES_LONG unsigned long
#endif
typedef unsigned char des_cblock[8];
@@ -70,54 +71,54 @@ typedef struct des_ks_struct
DES_LONG pad[2];
} ks;
#undef _
-#define _ ks._
+#define _ ks._
} des_key_schedule[16];
-#define DES_KEY_SZ (sizeof(des_cblock))
-#define DES_SCHEDULE_SZ (sizeof(des_key_schedule))
+#define DES_KEY_SZ (sizeof(des_cblock))
+#define DES_SCHEDULE_SZ (sizeof(des_key_schedule))
-#define DES_ENCRYPT 1
-#define DES_DECRYPT 0
+#define DES_ENCRYPT 1
+#define DES_DECRYPT 0
-#define DES_CBC_MODE 0
-#define DES_PCBC_MODE 1
+#define DES_CBC_MODE 0
+#define DES_PCBC_MODE 1
-#define des_ecb2_encrypt(i,o,k1,k2,e) \
+#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) \
+#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) \
+#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) \
+#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
+#define C_Block des_cblock
+#define Key_schedule des_key_schedule
#ifdef KERBEROS
-#define ENCRYPT DES_ENCRYPT
-#define DECRYPT DES_DECRYPT
+#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
+#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
+#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 */
@@ -139,7 +140,7 @@ DES_LONG des_cbc_cksum(des_cblock *input,des_cblock *output,
void des_cbc_encrypt(des_cblock *input,des_cblock *output,long length,
des_key_schedule schedule,des_cblock *ivec,int enc);
*/
-void des_cbc_encrypt(struct mbuf *, size_t, size_t,
+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);
@@ -149,7 +150,7 @@ void des_xcbc_encrypt(des_cblock *input,des_cblock *output,long length,
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 void des_3cbc_process(struct mbuf *, size_t, size_t,
+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);
diff --git a/sys/crypto/des/des_3cbc.c b/sys/crypto/des/des_3cbc.c
index 7ddb06c69876..e6758718963f 100644
--- a/sys/crypto/des/des_3cbc.c
+++ b/sys/crypto/des/des_3cbc.c
@@ -1,3 +1,6 @@
+/* $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.
@@ -25,16 +28,15 @@
* 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.
- *
- * $FreeBSD$
*/
/*
* 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)
-void des_3cbc_process(m0, skip, length, schedule, ivec, mode)
+int des_3cbc_process(m0, skip, length, schedule, ivec, mode)
struct mbuf *m0;
size_t skip;
size_t length;
@@ -55,21 +57,21 @@ void des_3cbc_process(m0, skip, length, schedule, ivec, mode)
/* sanity check */
if (m0->m_pkthdr.len < skip) {
printf("des_3cbc_process: mbuf length < skip\n");
- return;
+ return EINVAL;
}
if (m0->m_pkthdr.len < length) {
printf("des_3cbc_process: mbuf length < encrypt length\n");
- return;
+ return EINVAL;
}
if (m0->m_pkthdr.len < skip + length) {
printf("des_3cbc_process: mbuf length < "
"skip + encrypt length\n");
- return;
+ return EINVAL;
}
if (length % 8) {
printf("des_3cbc_process: length(%lu) is not multiple of 8\n",
(u_long)length);
- return;
+ return EINVAL;
}
m = m0;
@@ -242,5 +244,7 @@ void des_3cbc_process(m0, skip, length, schedule, ivec, mode)
length -= 8;
}
+
+ return 0;
}
diff --git a/sys/crypto/des/des_cbc.c b/sys/crypto/des/des_cbc.c
index 665352a21910..92de8f89fd91 100644
--- a/sys/crypto/des/des_cbc.c
+++ b/sys/crypto/des/des_cbc.c
@@ -1,3 +1,6 @@
+/* $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>,
@@ -48,15 +51,13 @@
* 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.]
- *
- * $FreeBSD$
*/
#include <crypto/des/des_locl.h>
-#define panic(x) {printf(x); return;}
+#define panic(x) do {printf(x); return EINVAL;} while (0)
-void des_cbc_encrypt(m0, skip, length, schedule, ivec, mode)
+int des_cbc_encrypt(m0, skip, length, schedule, ivec, mode)
struct mbuf *m0;
size_t skip;
size_t length;
@@ -75,19 +76,19 @@ void des_cbc_encrypt(m0, skip, length, schedule, ivec, mode)
/* sanity checks */
if (m0->m_pkthdr.len < skip) {
printf("mbuf length < skip\n");
- return;
+ return EINVAL;
}
if (m0->m_pkthdr.len < length) {
printf("mbuf length < encrypt length\n");
- return;
+ return EINVAL;
}
if (m0->m_pkthdr.len < skip + length) {
printf("mbuf length < skip + encrypt length\n");
- return;
+ return EINVAL;
}
if (length % 8) {
printf("length is not multiple of 8\n");
- return;
+ return EINVAL;
}
m = m0;
@@ -142,7 +143,7 @@ void des_cbc_encrypt(m0, skip, length, schedule, ivec, mode)
while (in - &inbuf[0] < 8) {
if (!p)
panic("mbuf chain?\n");
-
+
*in++ = *p++;
noff++;
if (noff < n->m_len)
@@ -325,4 +326,6 @@ void des_cbc_encrypt(m0, skip, length, schedule, ivec, mode)
length -= 8;
}
}
+
+ return 0;
}
diff --git a/sys/crypto/des/des_ecb.c b/sys/crypto/des/des_ecb.c
index 9e74d6ce8308..d828b915afbd 100644
--- a/sys/crypto/des/des_ecb.c
+++ b/sys/crypto/des/des_ecb.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: des_ecb.c,v 1.3 2000/03/27 04:36:33 sumikawa Exp $ */
+
/* crypto/des/ecb_enc.c */
/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
* All rights reserved.
@@ -43,8 +46,6 @@
* 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.]
- *
- * $FreeBSD$
*/
#include <crypto/des/des_locl.h>
@@ -67,7 +68,7 @@ char *des_options()
return("des(idx,long)");
#endif
}
-
+
void des_ecb_encrypt(input, output, ks, encrypt)
des_cblock (*input);
diff --git a/sys/crypto/des/des_locl.h b/sys/crypto/des/des_locl.h
index ff49cc73d6ae..ae6e828dbdec 100644
--- a/sys/crypto/des/des_locl.h
+++ b/sys/crypto/des/des_locl.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: des_locl.h,v 1.4 2000/03/27 04:43:46 sumikawa Exp $ */
+
/* lib/des/des_locl.h */
/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
* All rights reserved.
@@ -43,8 +46,6 @@
* 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.]
- *
- * $FreeBSD$
*/
/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
*
@@ -60,11 +61,11 @@
#include <sys/systm.h>
#ifndef HEADER_DES_LOCL_H
-#define HEADER_DES_LOCL_H
+#define HEADER_DES_LOCL_H
#if defined(WIN32) || defined(WIN16)
#ifndef MSDOS
-#define MSDOS
+#define MSDOS
#endif
#endif
@@ -89,7 +90,7 @@
#include <time.h>
#include <io.h>
#ifndef RAND
-#define RAND
+#define RAND
#endif
#undef NOPROTO
#endif
@@ -105,7 +106,7 @@
#endif
#ifndef RAND
-#define RAND
+#define RAND
#endif
#ifdef linux
@@ -113,13 +114,13 @@
#endif
#ifdef MSDOS
-#define getpid() 2
-#define RAND
+#define getpid() 2
+#define RAND
#undef NOPROTO
#endif
#if defined(NOCONST)
-#define const
+#define const
#endif
#ifdef __STDC__
@@ -127,24 +128,24 @@
#endif
#ifdef RAND
-#define srandom(s) srand(s)
-#define random rand
+#define srandom(s) srand(s)
+#define random rand
#endif
-#define ITERATIONS 16
-#define HALF_ITERATIONS 8
+#define ITERATIONS 16
+#define HALF_ITERATIONS 8
/* used in des_read and des_write */
-#define MAXWRITE (1024*16)
-#define BSIZE (MAXWRITE+4)
+#define MAXWRITE (1024*16)
+#define BSIZE (MAXWRITE+4)
-#define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \
+#define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \
l|=((DES_LONG)(*((c)++)))<< 8L, \
l|=((DES_LONG)(*((c)++)))<<16L, \
l|=((DES_LONG)(*((c)++)))<<24L)
/* NOTE - c is not incremented as per c2l */
-#define c2ln(c,l1,l2,n) { \
+#define c2ln(c,l1,l2,n) { \
c+=n; \
l1=l2=0; \
switch (n) { \
@@ -159,27 +160,27 @@
} \
}
-#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
*((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
*((c)++)=(unsigned char)(((l)>>16L)&0xff), \
*((c)++)=(unsigned char)(((l)>>24L)&0xff))
/* replacements for htonl and ntohl since I have no idea what to do
* when faced with machines with 8 byte longs. */
-#define HDRSIZE 4
+#define HDRSIZE 4
-#define n2l(c,l) (l =((DES_LONG)(*((c)++)))<<24L, \
+#define n2l(c,l) (l =((DES_LONG)(*((c)++)))<<24L, \
l|=((DES_LONG)(*((c)++)))<<16L, \
l|=((DES_LONG)(*((c)++)))<< 8L, \
l|=((DES_LONG)(*((c)++))))
-#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
+#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
*((c)++)=(unsigned char)(((l)>>16L)&0xff), \
*((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
*((c)++)=(unsigned char)(((l) )&0xff))
/* NOTE - c is not incremented as per l2c */
-#define l2cn(l1,l2,c,n) { \
+#define l2cn(l1,l2,c,n) { \
c+=n; \
switch (n) { \
case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \
@@ -207,7 +208,7 @@
* bytes, probably an issue of accessing non-word aligned objects :-( */
#ifdef DES_PTR
-#define D_ENCRYPT(L,R,S) { \
+#define D_ENCRYPT(L,R,S) { \
u=((R^s[S ])<<2); \
t= R^s[S+1]; \
t=ROTATE(t,2); \
@@ -222,7 +223,7 @@
*(DES_LONG *)((unsigned char *)des_SP+0x600+((u>>24)&0xfc))); }
#else /* original version */
#ifdef undef
-#define D_ENCRYPT(L,R,S) \
+#define D_ENCRYPT(L,R,S) \
U.l=R^s[S+1]; \
T.s[0]=((U.s[0]>>4)|(U.s[1]<<12))&0x3f3f; \
T.s[1]=((U.s[1]>>4)|(U.s[0]<<12))&0x3f3f; \
@@ -236,7 +237,7 @@
des_SPtrans[4][(U.c[2])]| \
des_SPtrans[6][(U.c[3])];
#else
-#define D_ENCRYPT(Q,R,S) {\
+#define D_ENCRYPT(Q,R,S) {\
u=(R^s[S ]); \
t=R^s[S+1]; \
t=ROTATE(t,4); \
@@ -288,11 +289,11 @@
I first got ~42 operations without xors. When I remembered
how to use xors :-) I got it to its final state.
*/
-#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
(b)^=(t),\
(a)^=((t)<<(n)))
-#define IP(l,r) \
+#define IP(l,r) \
{ \
register DES_LONG tt; \
PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \
@@ -302,7 +303,7 @@
PERM_OP(r,l,tt, 1,0x55555555L); \
}
-#define FP(l,r) \
+#define FP(l,r) \
{ \
register DES_LONG tt; \
PERM_OP(l,r,tt, 1,0x55555555L); \
@@ -315,10 +316,10 @@
/*
-#define mbuf2char(i_mbuf, i_index, in) \
+#define mbuf2char(i_mbuf, i_index, in) \
{ \
- register int i; \
- struct mbuf *m; \
+ register int i; \
+ struct mbuf *m; \
char *buf; \
m = i_mbuf; \
for (i = 0; i < 8; i ++){ \
@@ -330,10 +331,10 @@
}
-#define char2mbuf(o_mbuf, o_index, out) \
+#define char2mbuf(o_mbuf, o_index, out) \
{ \
- register int i; \
- struct mbuf *m; \
+ register int i; \
+ struct mbuf *m; \
char *buf; \
m = o_mbuf; \
for (i = 0; i < 8; i ++){ \
diff --git a/sys/crypto/des/des_setkey.c b/sys/crypto/des/des_setkey.c
index 9747b524e894..48d13fcecc36 100644
--- a/sys/crypto/des/des_setkey.c
+++ b/sys/crypto/des/des_setkey.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: des_setkey.c,v 1.3 2000/03/27 04:36:33 sumikawa Exp $ */
+
/* crypto/des/set_key.c */
/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
* All rights reserved.
@@ -43,8 +46,6 @@
* 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.]
- *
- * $FreeBSD$
*/
/* set_key.c v 1.4 eay 24/9/91
@@ -97,7 +98,7 @@ des_cblock (*key);
* Many thanks to smb@ulysses.att.com (Steven Bellovin) for the reference
* (and actual cblock values).
*/
-#define NUM_WEAK_KEY 16
+#define NUM_WEAK_KEY 16
static des_cblock weak_keys[NUM_WEAK_KEY]={
/* weak keys */
{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
@@ -142,7 +143,7 @@ des_cblock (*key);
* (a)=((a)^((t)<<(n))))
*/
-#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
+#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
(a)=(a)^(t)^(t>>(16-(n))))
/* return 0 if key parity is odd (correct),
@@ -223,7 +224,7 @@ des_key_schedule schedule;
/* table contained 0213 4657 */
*(k++)=((t<<16L)|(s&0x0000ffffL))&0xffffffffL;
s= ((s>>16L)|(t&0xffff0000L));
-
+
s=(s<<4L)|(s>>28L);
*(k++)=s&0xffffffffL;
}
diff --git a/sys/crypto/des/podd.h b/sys/crypto/des/podd.h
index a0efc55d4186..fb54c39a6dae 100644
--- a/sys/crypto/des/podd.h
+++ b/sys/crypto/des/podd.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: podd.h,v 1.3 2000/03/27 04:36:34 sumikawa Exp $ */
+
/* crypto/des/podd.h */
/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
* All rights reserved.
@@ -43,8 +46,6 @@
* 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.]
- *
- * $FreeBSD$
*/
static const unsigned char odd_parity[256]={
diff --git a/sys/crypto/des/sk.h b/sys/crypto/des/sk.h
index 1a1469c2714b..24bde96dd378 100644
--- a/sys/crypto/des/sk.h
+++ b/sys/crypto/des/sk.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: sk.h,v 1.3 2000/03/27 04:36:34 sumikawa Exp $ */
+
/* crypto/des/sk.h */
/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
* All rights reserved.
@@ -43,8 +46,6 @@
* 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.]
- *
- * $FreeBSD$
*/
static const DES_LONG des_skb[8][64]={
diff --git a/sys/crypto/des/spr.h b/sys/crypto/des/spr.h
index c340f580baeb..606e12b4c5f9 100644
--- a/sys/crypto/des/spr.h
+++ b/sys/crypto/des/spr.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: spr.h,v 1.3 2000/03/27 04:36:35 sumikawa Exp $ */
+
/* crypto/des/spr.h */
/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
* All rights reserved.
@@ -43,8 +46,6 @@
* 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.]
- *
- * $FreeBSD$
*/
static const DES_LONG des_SPtrans[8][64]={
diff --git a/sys/crypto/md5.c b/sys/crypto/md5.c
index 211c89ba0fd0..e82770089174 100644
--- a/sys/crypto/md5.c
+++ b/sys/crypto/md5.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: md5.c,v 1.4 2000/03/27 04:36:22 sumikawa Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
#include <sys/types.h>
@@ -35,61 +36,61 @@
#include <sys/systm.h>
#include <crypto/md5.h>
-#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s))))
+#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s))))
-#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
-#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
-#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
-#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))
+#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
+#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
+#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
+#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))
-#define ROUND1(a, b, c, d, k, s, i) { \
+#define ROUND1(a, b, c, d, k, s, i) { \
(a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
(a) = SHIFT((a), (s)); \
(a) = (b) + (a); \
}
-#define ROUND2(a, b, c, d, k, s, i) { \
+#define ROUND2(a, b, c, d, k, s, i) { \
(a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
(a) = SHIFT((a), (s)); \
(a) = (b) + (a); \
}
-#define ROUND3(a, b, c, d, k, s, i) { \
+#define ROUND3(a, b, c, d, k, s, i) { \
(a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
(a) = SHIFT((a), (s)); \
(a) = (b) + (a); \
}
-#define ROUND4(a, b, c, d, k, s, i) { \
+#define ROUND4(a, b, c, d, k, s, i) { \
(a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
(a) = SHIFT((a), (s)); \
(a) = (b) + (a); \
}
-#define Sa 7
-#define Sb 12
-#define Sc 17
-#define Sd 22
+#define Sa 7
+#define Sb 12
+#define Sc 17
+#define Sd 22
-#define Se 5
-#define Sf 9
-#define Sg 14
-#define Sh 20
+#define Se 5
+#define Sf 9
+#define Sg 14
+#define Sh 20
-#define Si 4
-#define Sj 11
-#define Sk 16
-#define Sl 23
+#define Si 4
+#define Sj 11
+#define Sk 16
+#define Sl 23
-#define Sm 6
-#define Sn 10
-#define So 15
-#define Sp 21
+#define Sm 6
+#define Sn 10
+#define So 15
+#define Sp 21
-#define MD5_A0 0x67452301
-#define MD5_B0 0xefcdab89
-#define MD5_C0 0x98badcfe
-#define MD5_D0 0x10325476
+#define MD5_A0 0x67452301
+#define MD5_B0 0xefcdab89
+#define MD5_C0 0x98badcfe
+#define MD5_D0 0x10325476
/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
static const u_int32_t T[65] = {
@@ -123,7 +124,7 @@ static const u_int8_t md5_paddat[MD5_BUFLEN] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
};
static void md5_calc __P((u_int8_t *, md5_ctxt *));
@@ -158,7 +159,7 @@ void md5_loop(ctxt, input, len)
for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
md5_calc((u_int8_t *)(input + i), ctxt);
}
-
+
ctxt->md5_i = len - i;
bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
} else {
@@ -173,7 +174,7 @@ void md5_pad(ctxt)
{
u_int gap;
- /* Don't count up padding. Keep md5_n. */
+ /* Don't count up padding. Keep md5_n. */
gap = MD5_BUFLEN - ctxt->md5_i;
if (gap > 8) {
bcopy((void *)md5_paddat,
@@ -189,7 +190,7 @@ void md5_pad(ctxt)
MD5_BUFLEN - sizeof(ctxt->md5_n));
}
- /* 8 byte word */
+ /* 8 byte word */
#if BYTE_ORDER == LITTLE_ENDIAN
bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
#endif
@@ -241,7 +242,7 @@ static void md5_calc(b64, ctxt)
u_int32_t D = ctxt->md5_std;
#if BYTE_ORDER == LITTLE_ENDIAN
u_int32_t *X = (u_int32_t *)b64;
-#endif
+#endif
#if BYTE_ORDER == BIG_ENDIAN
/* 4 byte words */
/* what a brute force but fast! */
@@ -272,7 +273,7 @@ static void md5_calc(b64, ctxt)
ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12);
ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14);
ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16);
-
+
ROUND2(A, B, C, D, 1, Se, 17); ROUND2(D, A, B, C, 6, Sf, 18);
ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A, 0, Sh, 20);
ROUND2(A, B, C, D, 5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22);
@@ -290,14 +291,14 @@ static void md5_calc(b64, ctxt)
ROUND3(C, D, A, B, 3, Sk, 43); ROUND3(B, C, D, A, 6, Sl, 44);
ROUND3(A, B, C, D, 9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46);
ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A, 2, Sl, 48);
-
- ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50);
- ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52);
- ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54);
- ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56);
- ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58);
- ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60);
- ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62);
+
+ ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50);
+ ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52);
+ ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54);
+ ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56);
+ ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58);
+ ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60);
+ ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62);
ROUND4(C, D, A, B, 2, So, 63); ROUND4(B, C, D, A, 9, Sp, 64);
ctxt->md5_sta += A;
diff --git a/sys/crypto/md5.h b/sys/crypto/md5.h
index 61eb2acb8d4c..241819985dc9 100644
--- a/sys/crypto/md5.h
+++ b/sys/crypto/md5.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: md5.h,v 1.4 2000/03/27 04:36:22 sumikawa Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,14 +28,12 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _NETINET6_MD5_H_
-#define _NETINET6_MD5_H_
+#define _NETINET6_MD5_H_
-#define MD5_BUFLEN 64
+#define MD5_BUFLEN 64
typedef struct {
union {
@@ -40,18 +41,18 @@ typedef struct {
u_int8_t md5_state8[16];
} md5_st;
-#define md5_sta md5_st.md5_state32[0]
-#define md5_stb md5_st.md5_state32[1]
-#define md5_stc md5_st.md5_state32[2]
-#define md5_std md5_st.md5_state32[3]
-#define md5_st8 md5_st.md5_state8
+#define md5_sta md5_st.md5_state32[0]
+#define md5_stb md5_st.md5_state32[1]
+#define md5_stc md5_st.md5_state32[2]
+#define md5_std md5_st.md5_state32[3]
+#define md5_st8 md5_st.md5_state8
union {
u_int64_t md5_count64;
u_int8_t md5_count8[8];
} md5_count;
-#define md5_n md5_count.md5_count64
-#define md5_n8 md5_count.md5_count8
+#define md5_n md5_count.md5_count64
+#define md5_n8 md5_count.md5_count8
u_int md5_i;
u_int8_t md5_buf[MD5_BUFLEN];
@@ -63,10 +64,10 @@ extern void md5_pad __P((md5_ctxt *));
extern void md5_result __P((u_int8_t *, md5_ctxt *));
/* compatibility */
-#define MD5_CTX md5_ctxt
-#define MD5Init(x) md5_init((x))
-#define MD5Update(x, y, z) md5_loop((x), (y), (z))
-#define MD5Final(x, y) \
+#define MD5_CTX md5_ctxt
+#define MD5Init(x) md5_init((x))
+#define MD5Update(x, y, z) md5_loop((x), (y), (z))
+#define MD5Final(x, y) \
do { \
md5_pad((y)); \
md5_result((x), (y)); \
diff --git a/sys/crypto/rc5/rc5.c b/sys/crypto/rc5/rc5.c
index 52ccdd1ef492..99a8ac6faf91 100644
--- a/sys/crypto/rc5/rc5.c
+++ b/sys/crypto/rc5/rc5.c
@@ -1,3 +1,6 @@
+/* $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.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
#include <crypto/rc5/rc5.h>
diff --git a/sys/crypto/rc5/rc5.h b/sys/crypto/rc5/rc5.h
index 20c235b375b6..ae2339b757a1 100644
--- a/sys/crypto/rc5/rc5.h
+++ b/sys/crypto/rc5/rc5.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: rc5.h,v 1.4 2000/06/14 10:41:17 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,12 +28,10 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _RFC2040_RC5_H_
-#define _RFC2040_RC5_H_
+#define _RFC2040_RC5_H_
#include <sys/param.h>
#include <sys/systm.h>
@@ -41,46 +42,46 @@
*/
typedef u_int32_t RC5_WORD;
-#define W (32)
-#define WW (W / 8)
-#define ROT_MASK (W - 1)
-#define BB ((2 * W) / 8)
+#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 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 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
+#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
+#define Pw P16
+#define Qw Q16
#elif W == 32
-#define Pw P32
-#define Qw Q32
+#define Pw P32
+#define Qw Q32
#elif W == 64
-#define Pw P64
-#define Qw Q64
+#define Pw P64
+#define Qw Q64
#endif
-#define RC5_ENCRYPT 1
-#define RC5_DECRYPT 0
+#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 void rc5_cbc_process __P((struct mbuf *, size_t, size_t, RC5_WORD *,
+extern int rc5_cbc_process __P((struct mbuf *, size_t, size_t, RC5_WORD *,
u_int8_t *, int));
#endif
diff --git a/sys/crypto/rc5/rc5_cbc.c b/sys/crypto/rc5/rc5_cbc.c
index c588eda8bd2d..5972cc61220b 100644
--- a/sys/crypto/rc5/rc5_cbc.c
+++ b/sys/crypto/rc5/rc5_cbc.c
@@ -1,3 +1,6 @@
+/* $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.
@@ -25,16 +28,15 @@
* 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.
- *
- * $FreeBSD$
*/
/*
* 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)
-void
+int
rc5_cbc_process(m0, skip, length, e_key, iv, mode)
struct mbuf *m0;
size_t skip;
@@ -50,21 +52,21 @@ rc5_cbc_process(m0, skip, length, e_key, iv, mode)
/* sanity check */
if (m0->m_pkthdr.len < skip) {
printf("rc5_cbc_process: mbuf length < skip\n");
- return;
+ return EINVAL;
}
if (m0->m_pkthdr.len < length) {
printf("rc5_cbc_process: mbuf length < encrypt length\n");
- return;
+ return EINVAL;
}
if (m0->m_pkthdr.len < skip + length) {
printf("rc5_cbc_process: mbuf length < "
"skip + encrypt length\n");
- return;
+ return EINVAL;
}
if (length % 8) {
printf("rc5_cbc_process: length(%lu)is not multipleof 8\n",
(u_long)length);
- return;
+ return EINVAL;
}
m = m0;
@@ -207,5 +209,7 @@ rc5_cbc_process(m0, skip, length, e_key, iv, mode)
length -= 8;
}
+
+ return 0;
}
diff --git a/sys/crypto/sha1.c b/sys/crypto/sha1.c
index 337f944bf5c4..815bc5a16ca1 100644
--- a/sys/crypto/sha1.c
+++ b/sys/crypto/sha1.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: sha1.c,v 1.4 2000/03/27 04:36:23 sumikawa Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
* FIPS pub 180-1: Secure Hash Algorithm (SHA-1)
@@ -218,16 +219,18 @@ sha1_pad(ctxt)
}
void
-sha1_loop(ctxt, input, len)
+sha1_loop(ctxt, input0, len)
struct sha1_ctxt *ctxt;
- const u_char *input;
+ const caddr_t input0;
size_t len;
{
+ const u_int8_t *input;
size_t gaplen;
size_t gapstart;
size_t off;
size_t copysiz;
+ input = (const u_int8_t *)input0;
off = 0;
while (off < len) {
diff --git a/sys/crypto/sha1.h b/sys/crypto/sha1.h
index dc7966c21a61..2e87f0537e70 100644
--- a/sys/crypto/sha1.h
+++ b/sys/crypto/sha1.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: sha1.h,v 1.5 2000/03/27 04:36:23 sumikawa Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
* FIPS pub 180-1: Secure Hash Algorithm (SHA-1)
@@ -35,7 +36,7 @@
*/
#ifndef _NETINET6_SHA1_H_
-#define _NETINET6_SHA1_H_
+#define _NETINET6_SHA1_H_
struct sha1_ctxt {
union {
@@ -56,14 +57,14 @@ struct sha1_ctxt {
#ifdef _KERNEL
extern void sha1_init __P((struct sha1_ctxt *));
extern void sha1_pad __P((struct sha1_ctxt *));
-extern void sha1_loop __P((struct sha1_ctxt *, const u_char *, size_t));
+extern void sha1_loop __P((struct sha1_ctxt *, const caddr_t, size_t));
extern void sha1_result __P((struct sha1_ctxt *, caddr_t));
/* compatibilty with other SHA1 source codes */
typedef struct sha1_ctxt SHA1_CTX;
-#define SHA1Init(x) sha1_init((x))
-#define SHA1Update(x, y, z) sha1_loop((x), (y), (z))
-#define SHA1Final(x, y) sha1_result((y), (x))
+#define SHA1Init(x) sha1_init((x))
+#define SHA1Update(x, y, z) sha1_loop((x), (y), (z))
+#define SHA1Final(x, y) sha1_result((y), (x))
#endif
#define SHA1_RESULTLEN (160/8)
diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c
index cc38c40e62fe..763e0b4048b7 100644
--- a/sys/kern/uipc_mbuf.c
+++ b/sys/kern/uipc_mbuf.c
@@ -519,6 +519,15 @@ m_freem(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
new file mode 100644
index 000000000000..07ce44244d0a
--- /dev/null
+++ b/sys/kern/uipc_mbuf2.c
@@ -0,0 +1,419 @@
+/* $FreeBSD$ */
+/* $KAME: uipc_mbuf2.c,v 1.15 2000/02/22 14:01:37 itojun Exp $ */
+/* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */
+
+/*
+ * Copyright (C) 1999 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.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1988, 1991, 1993
+ * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
+ */
+
+#define PULLDOWN_STAT
+/*#define PULLDOWN_DEBUG*/
+
+#ifdef PULLDOWN_STAT
+#include "opt_inet.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#if defined(PULLDOWN_STAT) && defined(INET6)
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#endif
+
+/*
+ * ensure that [off, off + len) is contiguous on the mbuf chain "m".
+ * packet chain before "off" is kept untouched.
+ * if offp == NULL, the target will start at <retval, 0> on resulting chain.
+ * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
+ *
+ * on error return (NULL return value), original "m" will be freed.
+ *
+ * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
+ */
+struct mbuf *
+m_pulldown(m, off, len, offp)
+ struct mbuf *m;
+ int off, len;
+ int *offp;
+{
+ struct mbuf *n, *o;
+ int hlen, tlen, olen;
+ int sharedcluster;
+#if defined(PULLDOWN_STAT) && defined(INET6)
+ static struct mbuf *prev = NULL;
+ int prevlen = 0, prevmlen = 0;
+#endif
+
+ /* check invalid arguments. */
+ if (m == NULL)
+ panic("m == NULL in m_pulldown()");
+ if (len > MCLBYTES) {
+ m_freem(m);
+ return NULL; /* impossible */
+ }
+
+#if defined(PULLDOWN_STAT) && defined(INET6)
+ ip6stat.ip6s_pulldown++;
+#endif
+
+#if defined(PULLDOWN_STAT) && defined(INET6)
+ /* statistics for m_pullup */
+ ip6stat.ip6s_pullup++;
+ if (off + len > MHLEN)
+ ip6stat.ip6s_pullup_fail++;
+ else {
+ int dlen, mlen;
+
+ dlen = (prev == m) ? prevlen : m->m_len;
+ mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
+
+ if (dlen >= off + len)
+ ip6stat.ip6s_pullup--; /* call will not be made! */
+ else if ((m->m_flags & M_EXT) != 0) {
+ ip6stat.ip6s_pullup_alloc++;
+ ip6stat.ip6s_pullup_copy++;
+ } else {
+ if (mlen >= off + len)
+ ip6stat.ip6s_pullup_copy++;
+ else {
+ ip6stat.ip6s_pullup_alloc++;
+ ip6stat.ip6s_pullup_copy++;
+ }
+ }
+
+ prevlen = off + len;
+ prevmlen = MHLEN;
+ }
+
+ /* statistics for m_pullup2 */
+ ip6stat.ip6s_pullup2++;
+ if (off + len > MCLBYTES)
+ ip6stat.ip6s_pullup2_fail++;
+ else {
+ int dlen, mlen;
+
+ dlen = (prev == m) ? prevlen : m->m_len;
+ mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
+ prevlen = off + len;
+ prevmlen = mlen;
+
+ if (dlen >= off + len)
+ ip6stat.ip6s_pullup2--; /* call will not be made! */
+ else if ((m->m_flags & M_EXT) != 0) {
+ ip6stat.ip6s_pullup2_alloc++;
+ ip6stat.ip6s_pullup2_copy++;
+ prevmlen = (off + len > MHLEN) ? MCLBYTES : MHLEN;
+ } else {
+ if (mlen >= off + len)
+ ip6stat.ip6s_pullup2_copy++;
+ else {
+ ip6stat.ip6s_pullup2_alloc++;
+ ip6stat.ip6s_pullup2_copy++;
+ prevmlen = (off + len > MHLEN) ? MCLBYTES
+ : MHLEN;
+ }
+ }
+ }
+
+ prev = m;
+#endif
+
+#ifdef PULLDOWN_DEBUG
+ {
+ struct mbuf *t;
+ printf("before:");
+ for (t = m; t; t = t->m_next)
+ printf(" %d", t->m_len);
+ printf("\n");
+ }
+#endif
+ n = m;
+ while (n != NULL && off > 0) {
+ if (n->m_len > off)
+ break;
+ off -= n->m_len;
+ n = n->m_next;
+ }
+ /* be sure to point non-empty mbuf */
+ while (n != NULL && n->m_len == 0)
+ n = n->m_next;
+ if (!n) {
+ m_freem(m);
+ return NULL; /* mbuf chain too short */
+ }
+
+ /*
+ * 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)
+ goto ok;
+
+#if defined(PULLDOWN_STAT) && defined(INET6)
+ ip6stat.ip6s_pulldown_copy++;
+#endif
+
+ /*
+ * 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 (o == NULL) {
+ m_freem(m);
+ return NULL; /* ENOBUFS */
+ }
+ n->m_len = off;
+ o->m_next = n->m_next;
+ n->m_next = o;
+ n = n->m_next;
+ off = 0;
+ goto ok;
+ }
+
+ /*
+ * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
+ * and construct contiguous mbuf with m_len == len.
+ * note that hlen + tlen == len, and tlen > 0.
+ */
+ hlen = n->m_len - off;
+ tlen = len - hlen;
+
+ /*
+ * ensure that we have enough trailing data on mbuf chain.
+ * if not, we can do nothing about the chain.
+ */
+ olen = 0;
+ for (o = n->m_next; o != NULL; o = o->m_next)
+ olen += o->m_len;
+ if (hlen + olen < len) {
+ m_freem(m);
+ return NULL; /* mbuf chain too short */
+ }
+
+ /*
+ * easy cases first.
+ * we need to use m_copydata() to get data from <n->m_next, 0>.
+ */
+ if ((n->m_flags & M_EXT) == 0)
+ sharedcluster = 0;
+ else {
+ if (n->m_ext.ext_free)
+ sharedcluster = 1;
+ else if (mclrefcnt[mtocl(n->m_ext.ext_buf)] > 1)
+ sharedcluster = 1;
+ else
+ sharedcluster = 0;
+ }
+ if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
+ && !sharedcluster) {
+ m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
+ n->m_len += tlen;
+ m_adj(n->m_next, tlen);
+ goto ok;
+ }
+ if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen
+ && !sharedcluster) {
+ n->m_next->m_data -= hlen;
+ n->m_next->m_len += hlen;
+ bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
+ n->m_len -= hlen;
+ n = n->m_next;
+ off = 0;
+ goto ok;
+ }
+
+ /*
+ * now, we need to do the hard way. don't m_copy as there's no room
+ * on both end.
+ */
+#if defined(PULLDOWN_STAT) && defined(INET6)
+ ip6stat.ip6s_pulldown_alloc++;
+#endif
+ MGET(o, M_DONTWAIT, m->m_type);
+ if (o == NULL) {
+ m_freem(m);
+ return NULL; /* ENOBUFS */
+ }
+ if (len > MHLEN) { /* use MHLEN just for safety */
+ MCLGET(o, M_DONTWAIT);
+ if ((o->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ m_free(o);
+ 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);
+ n->m_len -= hlen;
+ /* get tlen from <n->m_next, 0> into <o, hlen> */
+ m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
+ o->m_len += tlen;
+ m_adj(n->m_next, tlen);
+ o->m_next = n->m_next;
+ n->m_next = o;
+ n = o;
+ off = 0;
+
+ok:
+#ifdef PULLDOWN_DEBUG
+ {
+ struct mbuf *t;
+ printf("after:");
+ for (t = m; t; t = t->m_next)
+ printf("%c%d", t == n ? '*' : ' ', t->m_len);
+ printf(" (off=%d)\n", off);
+ }
+#endif
+ if (offp)
+ *offp = off;
+ return n;
+}
+
+/*
+ * pkthdr.aux chain manipulation.
+ * we don't allow clusters at this moment.
+ */
+struct mbuf *
+m_aux_add(m, af, type)
+ struct mbuf *m;
+ int af, type;
+{
+ struct mbuf *n;
+ struct mauxtag *t;
+
+ if ((m->m_flags & M_PKTHDR) == 0)
+ return NULL;
+
+ n = m_aux_find(m, af, type);
+ if (n)
+ return n;
+
+ MGET(n, M_DONTWAIT, m->m_type);
+ if (n == NULL)
+ return NULL;
+
+ t = mtod(n, struct mauxtag *);
+ t->af = af;
+ t->type = type;
+ n->m_data += sizeof(struct mauxtag);
+ n->m_len = 0;
+ n->m_next = m->m_pkthdr.aux;
+ m->m_pkthdr.aux = n;
+ return n;
+}
+
+struct mbuf *
+m_aux_find(m, af, type)
+ struct mbuf *m;
+ int af, type;
+{
+ struct mbuf *n;
+ struct mauxtag *t;
+
+ if ((m->m_flags & M_PKTHDR) == 0)
+ return NULL;
+
+ for (n = m->m_pkthdr.aux; n; n = n->m_next) {
+ t = (struct mauxtag *)n->m_dat;
+ if (t->af == af && t->type == type)
+ return n;
+ }
+ return NULL;
+}
+
+void
+m_aux_delete(m, victim)
+ struct mbuf *m;
+ struct mbuf *victim;
+{
+ struct mbuf *n, *prev, *next;
+ struct mauxtag *t;
+
+ if ((m->m_flags & M_PKTHDR) == 0)
+ return;
+
+ prev = NULL;
+ n = m->m_pkthdr.aux;
+ while (n) {
+ t = (struct mauxtag *)n->m_dat;
+ next = n->m_next;
+ if (n == victim) {
+ if (prev)
+ prev->m_next = n->m_next;
+ else
+ m->m_pkthdr.aux = n->m_next;
+ n->m_next = NULL;
+ m_free(n);
+ } else
+ prev = n;
+ n = next;
+ }
+}
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 74078aa47f5a..b2296127f71e 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -66,7 +66,6 @@
#endif
#ifdef INET6
#include <netinet6/nd6.h>
-#include <netinet6/in6_ifattach.h>
#endif
#ifdef IPX
@@ -669,9 +668,6 @@ ether_ifattach(ifp)
sdl->sdl_type = IFT_ETHER;
sdl->sdl_alen = ifp->if_addrlen;
bcopy((IFP2AC(ifp))->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
-#ifdef INET6
- in6_ifattach_getifid(ifp);
-#endif
if (ng_ether_attach_p != NULL)
(*ng_ether_attach_p)(ifp);
}
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index 0b326574f5f9..0337a61e80fa 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: if_gif.c,v 1.28 2000/06/20 12:30:03 jinmei Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,12 +28,6 @@
* 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.
- *
- * $FreeBSD$
- */
-
-/*
- * gif.c
*/
#include "opt_inet.h"
@@ -46,6 +43,7 @@
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/syslog.h>
+#include <sys/protosw.h>
#include <machine/cpu.h>
#include <net/if.h>
@@ -70,21 +68,47 @@
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/in6_gif.h>
+#include <netinet6/ip6protosw.h>
#endif /* INET6 */
+#include <netinet/ip_encap.h>
#include <net/if_gif.h>
#include "gif.h"
+#include "bpf.h"
+#define NBPFILTER NBPF
#include <net/net_osdep.h>
+#if NGIF > 0
+
void gifattach __P((void *));
+static int gif_encapcheck __P((const struct mbuf *, int, int, void *));
+#ifdef INET
+extern struct protosw in_gif_protosw;
+#endif
+#ifdef INET6
+extern struct ip6protosw in6_gif_protosw;
+#endif
/*
* gif global variable definitions
*/
-int ngif = NGIF + 1; /* number of interfaces. +1 for stf. */
-struct gif_softc *gif = 0;
+static int ngif; /* number of interfaces */
+static struct gif_softc *gif = 0;
+
+#ifndef MAX_GIF_NEST
+/*
+ * This macro controls the upper limitation on nesting of gif tunnels.
+ * Since, setting a large value to this macro with a careless configuration
+ * may introduce system crash, we don't allow any nestings by default.
+ * If you need to configure nested gif tunnels, you can define this macro
+ * in your kernel configuration file. However, if you do so, please be
+ * careful to configure the tunnels so that it won't make a loop.
+ */
+#define MAX_GIF_NEST 1
+#endif
+static int max_gif_nesting = MAX_GIF_NEST;
void
gifattach(dummy)
@@ -93,34 +117,111 @@ gifattach(dummy)
register struct gif_softc *sc;
register int i;
+ ngif = NGIF;
gif = sc = malloc (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAIT);
bzero(sc, ngif * sizeof(struct gif_softc));
- for (i = 0; i < ngif - 1; sc++, i++) { /* leave last one for stf */
+ for (i = 0; i < ngif; sc++, i++) {
sc->gif_if.if_name = "gif";
sc->gif_if.if_unit = i;
+
+ sc->encap_cookie4 = sc->encap_cookie6 = NULL;
+#ifdef INET
+ sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
+ gif_encapcheck, &in_gif_protosw, sc);
+ if (sc->encap_cookie4 == NULL) {
+ printf("%s: attach failed\n", if_name(&sc->gif_if));
+ continue;
+ }
+#endif
+#ifdef INET6
+ sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
+ gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc);
+ if (sc->encap_cookie6 == NULL) {
+ if (sc->encap_cookie4) {
+ encap_detach(sc->encap_cookie4);
+ sc->encap_cookie4 = NULL;
+ }
+ printf("%s: attach failed\n", if_name(&sc->gif_if));
+ continue;
+ }
+#endif
+
sc->gif_if.if_mtu = GIF_MTU;
sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
sc->gif_if.if_ioctl = gif_ioctl;
sc->gif_if.if_output = gif_output;
sc->gif_if.if_type = IFT_GIF;
- sc->gif_if.if_snd.ifq_maxlen = ifqmaxlen;
+ sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
if_attach(&sc->gif_if);
+#if NBPFILTER > 0
+#ifdef HAVE_OLD_BPF
bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
+#else
+ bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL, sizeof(u_int));
+#endif
+#endif
}
- sc->gif_if.if_name = "stf";
- sc->gif_if.if_unit = 0;
- sc->gif_if.if_mtu = GIF_MTU;
- sc->gif_if.if_flags = IFF_MULTICAST;
- sc->gif_if.if_ioctl = gif_ioctl;
- sc->gif_if.if_output = gif_output;
- sc->gif_if.if_type = IFT_GIF;
- sc->gif_if.if_snd.ifq_maxlen = ifqmaxlen;
- if_attach(&sc->gif_if);
- bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
}
PSEUDO_SET(gifattach, if_gif);
+static int
+gif_encapcheck(m, off, proto, arg)
+ const struct mbuf *m;
+ int off;
+ int proto;
+ void *arg;
+{
+ struct ip ip;
+ struct gif_softc *sc;
+
+ sc = (struct gif_softc *)arg;
+ if (sc == NULL)
+ return 0;
+
+ if ((sc->gif_if.if_flags & IFF_UP) == 0)
+ return 0;
+
+ /* no physical address */
+ if (!sc->gif_psrc || !sc->gif_pdst)
+ return 0;
+
+ switch (proto) {
+#ifdef INET
+ case IPPROTO_IPV4:
+ break;
+#endif
+#ifdef INET6
+ case IPPROTO_IPV6:
+ break;
+#endif
+ default:
+ return 0;
+ }
+
+ /* LINTED const cast */
+ m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
+
+ switch (ip.ip_v) {
+#ifdef INET
+ case 4:
+ if (sc->gif_psrc->sa_family != AF_INET ||
+ sc->gif_pdst->sa_family != AF_INET)
+ return 0;
+ return gif_encapcheck4(m, off, proto, arg);
+#endif
+#ifdef INET6
+ case 6:
+ if (sc->gif_psrc->sa_family != AF_INET6 ||
+ sc->gif_pdst->sa_family != AF_INET6)
+ return 0;
+ return gif_encapcheck6(m, off, proto, arg);
+#endif
+ default:
+ return 0;
+ }
+}
+
int
gif_output(ifp, m, dst, rt)
struct ifnet *ifp;
@@ -131,7 +232,6 @@ gif_output(ifp, m, dst, rt)
register struct gif_softc *sc = (struct gif_softc*)ifp;
int error = 0;
static int called = 0; /* XXX: MUTEX */
- int calllimit = 10; /* XXX: adhoc */
/*
* gif may cause infinite recursion calls when misconfigured.
@@ -140,7 +240,7 @@ gif_output(ifp, m, dst, rt)
* mutual exclusion of the variable CALLED, especially if we
* use kernel thread.
*/
- if (++called >= calllimit) {
+ if (++called > max_gif_nesting) {
log(LOG_NOTICE,
"gif_output: recursively called too many times(%d)\n",
called);
@@ -148,6 +248,7 @@ gif_output(ifp, m, dst, rt)
error = EIO; /* is there better errno? */
goto end;
}
+
getmicrotime(&ifp->if_lastchange);
m->m_flags &= ~(M_BCAST|M_MCAST);
if (!(ifp->if_flags & IFF_UP) ||
@@ -157,6 +258,7 @@ gif_output(ifp, m, dst, rt)
goto end;
}
+#if NBPFILTER > 0
if (ifp->if_bpf) {
/*
* We need to prepend the address family as
@@ -171,12 +273,19 @@ gif_output(ifp, m, dst, rt)
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
}
- ifp->if_opackets++;
+#endif
+ ifp->if_opackets++;
ifp->if_obytes += m->m_pkthdr.len;
+ /* XXX should we check if our outer source is legal? */
+
switch (sc->gif_psrc->sa_family) {
#ifdef INET
case AF_INET:
@@ -189,7 +298,7 @@ gif_output(ifp, m, dst, rt)
break;
#endif
default:
- m_freem(m);
+ m_freem(m);
error = ENETDOWN;
}
@@ -214,9 +323,9 @@ gif_input(m, af, gifp)
return;
}
- if (m->m_pkthdr.rcvif)
- m->m_pkthdr.rcvif = gifp;
-
+ m->m_pkthdr.rcvif = gifp;
+
+#if NBPFILTER > 0
if (gifp->if_bpf) {
/*
* We need to prepend the address family as
@@ -227,13 +336,18 @@ gif_input(m, af, gifp)
*/
struct mbuf m0;
u_int af = AF_INET6;
-
+
m0.m_next = m;
m0.m_len = 4;
m0.m_data = (char *)&af;
-
+
+#ifdef HAVE_OLD_BPF
bpf_mtap(gifp, &m0);
+#else
+ bpf_mtap(gifp->if_bpf, &m0);
+#endif
}
+#endif /*NBPFILTER > 0*/
/*
* Put the packet to the network layer input queue according to the
@@ -282,7 +396,7 @@ gif_input(m, af, gifp)
return;
}
-
+/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
int
gif_ioctl(ifp, cmd, data)
struct ifnet *ifp;
@@ -292,12 +406,15 @@ gif_ioctl(ifp, cmd, data)
struct gif_softc *sc = (struct gif_softc*)ifp;
struct ifreq *ifr = (struct ifreq*)data;
int error = 0, size;
- struct sockaddr *sa, *dst, *src;
-
+ struct sockaddr *dst, *src;
+ struct sockaddr *sa;
+ int i;
+ struct gif_softc *sc2;
+
switch (cmd) {
case SIOCSIFADDR:
break;
-
+
case SIOCSIFDSTADDR:
break;
@@ -305,8 +422,10 @@ gif_ioctl(ifp, cmd, data)
case SIOCDELMULTI:
break;
+#ifdef SIOCSIFMTU /* xxx */
case SIOCGIFMTU:
break;
+
case SIOCSIFMTU:
{
u_long mtu;
@@ -317,103 +436,125 @@ gif_ioctl(ifp, cmd, data)
ifp->if_mtu = mtu;
}
break;
+#endif /* SIOCSIFMTU */
case SIOCSIFPHYADDR:
#ifdef INET6
case SIOCSIFPHYADDR_IN6:
#endif /* INET6 */
- switch (ifr->ifr_addr.sa_family) {
-#ifdef INET
- case AF_INET:
+ switch (cmd) {
+ case SIOCSIFPHYADDR:
src = (struct sockaddr *)
&(((struct in_aliasreq *)data)->ifra_addr);
dst = (struct sockaddr *)
&(((struct in_aliasreq *)data)->ifra_dstaddr);
+ break;
+#ifdef INET6
+ case SIOCSIFPHYADDR_IN6:
+ src = (struct sockaddr *)
+ &(((struct in6_aliasreq *)data)->ifra_addr);
+ dst = (struct sockaddr *)
+ &(((struct in6_aliasreq *)data)->ifra_dstaddr);
+ break;
+#endif
+ }
- /* only one gif can have dst = INADDR_ANY */
-#define satosaddr(sa) (((struct sockaddr_in *)(sa))->sin_addr.s_addr)
+ for (i = 0; i < ngif; i++) {
+ sc2 = gif + i;
+ if (sc2 == sc)
+ continue;
+ if (!sc2->gif_pdst || !sc2->gif_psrc)
+ continue;
+ if (sc2->gif_pdst->sa_family != dst->sa_family ||
+ sc2->gif_pdst->sa_len != dst->sa_len ||
+ sc2->gif_psrc->sa_family != src->sa_family ||
+ sc2->gif_psrc->sa_len != src->sa_len)
+ continue;
+ /* can't configure same pair of address onto two gifs */
+ if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
+ bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
+ error = EADDRNOTAVAIL;
+ goto bad;
+ }
+ /* can't configure multiple multi-dest interfaces */
+#define multidest(x) \
+ (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
#ifdef INET6
- if (bcmp(ifp->if_name, "stf", 3) == 0)
- satosaddr(dst) = INADDR_BROADCAST;
+#define multidest6(x) \
+ (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
#endif
-
- if (satosaddr(dst) == INADDR_ANY) {
- int i;
- struct gif_softc *sc2;
-
- for (i = 0, sc2 = gif; i < ngif; i++, sc2++) {
- if (sc2 == sc) continue;
- if (sc2->gif_pdst &&
- satosaddr(sc2->gif_pdst)
- == INADDR_ANY) {
- error = EADDRNOTAVAIL;
- goto bad;
- }
- }
+ if (dst->sa_family == AF_INET &&
+ multidest(dst) && multidest(sc2->gif_pdst)) {
+ error = EADDRNOTAVAIL;
+ goto bad;
}
+#ifdef INET6
+ if (dst->sa_family == AF_INET6 &&
+ multidest6(dst) && multidest6(sc2->gif_pdst)) {
+ error = EADDRNOTAVAIL;
+ goto bad;
+ }
+#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 /* INET */
+#endif
#ifdef INET6
case AF_INET6:
- src = (struct sockaddr *)
- &(((struct in6_aliasreq *)data)->ifra_addr);
- dst = (struct sockaddr *)
- &(((struct in6_aliasreq *)data)->ifra_dstaddr);
-
- /* only one gif can have dst = in6addr_any */
-#define satoin6(sa) (&((struct sockaddr_in6 *)(sa))->sin6_addr)
-
- if (IN6_IS_ADDR_UNSPECIFIED(satoin6(dst))) {
- int i;
- struct gif_softc *sc2;
-
- for (i = 0, sc2 = gif; i < ngif; i++, sc2++) {
- if (sc2 == sc) continue;
- if (sc2->gif_pdst &&
- IN6_IS_ADDR_UNSPECIFIED(
- satoin6(sc2->gif_pdst)
- )) {
- error = EADDRNOTAVAIL;
- goto bad;
- }
- }
- }
size = sizeof(struct sockaddr_in6);
break;
-#endif /* INET6 */
+#endif
default:
- error = EPROTOTYPE;
+ error = EAFNOSUPPORT;
goto bad;
+ }
+ if (src->sa_len != size) {
+ error = EINVAL;
break;
}
- if (sc->gif_psrc != NULL)
- free((caddr_t)sc->gif_psrc, M_IFADDR);
- if (sc->gif_pdst != NULL)
- free((caddr_t)sc->gif_pdst, M_IFADDR);
+ if (sc->gif_psrc)
+ free((caddr_t)sc->gif_psrc, M_IFADDR);
sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK);
- bzero((caddr_t)sa, size);
bcopy((caddr_t)src, (caddr_t)sa, size);
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);
- bzero((caddr_t)sa, size);
bcopy((caddr_t)dst, (caddr_t)sa, size);
sc->gif_pdst = sa;
- ifp->if_flags |= (IFF_UP|IFF_RUNNING);
- {
- int s;
-
- s = splnet();
- if_up(ifp); /* send up RTM_IFINFO */
- splx(s);
- }
+ ifp->if_flags |= IFF_UP;
+ if_up(ifp); /* send up RTM_IFINFO */
+ error = 0;
break;
+#ifdef SIOCDIFPHYADDR
+ case SIOCDIFPHYADDR:
+ if (sc->gif_psrc) {
+ free((caddr_t)sc->gif_psrc, M_IFADDR);
+ sc->gif_psrc = NULL;
+ }
+ if (sc->gif_pdst) {
+ free((caddr_t)sc->gif_pdst, M_IFADDR);
+ sc->gif_pdst = NULL;
+ }
+ /* change the IFF_UP flag as well? */
+ break;
+#endif
+
case SIOCGIFPSRCADDR:
#ifdef INET6
case SIOCGIFPSRCADDR_IN6:
@@ -443,7 +584,7 @@ gif_ioctl(ifp, cmd, data)
}
bcopy((caddr_t)src, (caddr_t)dst, size);
break;
-
+
case SIOCGIFPDSTADDR:
#ifdef INET6
case SIOCGIFPDSTADDR_IN6:
@@ -475,6 +616,7 @@ gif_ioctl(ifp, cmd, data)
break;
case SIOCSIFFLAGS:
+ /* if_ioctl() takes care of it */
break;
default:
@@ -484,3 +626,4 @@ gif_ioctl(ifp, cmd, data)
bad:
return error;
}
+#endif /*NGIF > 0*/
diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h
index cc26938b1951..36992861898e 100644
--- a/sys/net/if_gif.h
+++ b/sys/net/if_gif.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: if_gif.h,v 1.13 2000/06/17 20:34:24 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -36,33 +37,46 @@
#ifndef _NET_IF_GIF_H_
#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? */
+
+struct encaptab;
+
struct gif_softc {
- struct ifnet gif_if; /* common area */
- struct sockaddr *gif_psrc; /* Physical src addr */
- struct sockaddr *gif_pdst; /* Physical dst addr */
+ struct ifnet gif_if; /* common area - must be at the top */
+ struct sockaddr *gif_psrc; /* Physical src addr */
+ struct sockaddr *gif_pdst; /* Physical dst addr */
union {
- struct route gifscr_ro; /* xxx */
- struct route_in6 gifscr_ro6; /* xxx */
+ struct route gifscr_ro; /* xxx */
+#ifdef INET6
+ struct route_in6 gifscr_ro6; /* xxx */
+#endif
} gifsc_gifscr;
- int gif_flags;
+ int gif_flags;
+ const struct encaptab *encap_cookie4;
+ const struct encaptab *encap_cookie6;
};
-#define gif_ro gifsc_gifscr.gifscr_ro
-#define gif_ro6 gifsc_gifscr.gifscr_ro6
+#define gif_ro gifsc_gifscr.gifscr_ro
+#ifdef INET6
+#define gif_ro6 gifsc_gifscr.gifscr_ro6
+#endif
-#define GIFF_INUSE 0x1 /* gif is in use */
-
-#define GIF_MTU (1280) /* Default MTU */
+#define GIF_MTU (1280) /* Default MTU */
#define GIF_MTU_MIN (1280) /* Minimum MTU */
#define GIF_MTU_MAX (8192) /* Maximum MTU */
-extern int ngif;
-extern struct gif_softc *gif;
-
/* Prototypes */
-void gif_input __P((struct mbuf *, int, struct ifnet *));
-int gif_output __P((struct ifnet *, struct mbuf *,
+void gif_input __P((struct mbuf *, int, struct ifnet *));
+int gif_output __P((struct ifnet *, struct mbuf *,
struct sockaddr *, struct rtentry *));
-int gif_ioctl __P((struct ifnet *, u_long, caddr_t));
+int gif_ioctl __P((struct ifnet *, u_long, caddr_t));
#endif /* _NET_IF_GIF_H_ */
diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c
index cf1580e418bf..a3d3a3b128b2 100644
--- a/sys/net/if_loop.c
+++ b/sys/net/if_loop.c
@@ -72,7 +72,7 @@
#include <netinet/in.h>
#endif
#include <netinet6/in6_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#endif
#ifdef NS
diff --git a/sys/net/if_stf.c b/sys/net/if_stf.c
new file mode 100644
index 000000000000..c95aaa54ec0e
--- /dev/null
+++ b/sys/net/if_stf.c
@@ -0,0 +1,662 @@
+/* $FreeBSD$ */
+/* $KAME: if_stf.c,v 1.40 2000/06/20 19:44:42 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.
+ */
+
+/*
+ * 6to4 interface, based on draft-ietf-ngtrans-6to4-06.txt.
+ *
+ * 6to4 interface is NOT capable of link-layer (I mean, IPv4) multicasting.
+ * There is no address mapping defined from IPv6 multicast address to IPv4
+ * address. Therefore, we do not have IFF_MULTICAST on the interface.
+ *
+ * Due to the lack of address mapping for link-local addresses, we cannot
+ * throw packets toward link-local addresses (fe80::x). Also, we cannot throw
+ * packets to link-local multicast addresses (ff02::x).
+ *
+ * Here are interesting symptoms due to the lack of link-local address:
+ *
+ * Unicast routing exchange:
+ * - RIPng: Impossible. Uses link-local multicast packet toward ff02::9,
+ * and link-local addresses as nexthop.
+ * - OSPFv6: Impossible. OSPFv6 assumes that there's link-local address
+ * assigned to the link, and makes use of them. Also, HELLO packets use
+ * link-local multicast addresses (ff02::5 and ff02::6).
+ * - BGP4+: Maybe. You can only use global address as nexthop, and global
+ * address as TCP endpoint address.
+ *
+ * Multicast routing protocols:
+ * - PIM: Hello packet cannot be used to discover adjacent PIM routers.
+ * Adjacent PIM routers must be configured manually (is it really spec-wise
+ * correct thing to do?).
+ *
+ * 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.
+ *
+ * 6to4 interface has security issues. Refer to
+ * http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt
+ * for details. The code tries to filter out some of malicious packets.
+ * Note that there is no way to be 100% secure.
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/errno.h>
+#include <sys/protosw.h>
+#include <sys/kernel.h>
+#include <machine/cpu.h>
+
+#include <sys/malloc.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+#include <net/if_types.h>
+#include <net/if_stf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/in_var.h>
+
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/in6_gif.h>
+#include <netinet6/in6_var.h>
+#include <netinet/ip_ecn.h>
+
+#include <netinet/ip_encap.h>
+
+#include <machine/stdarg.h>
+
+#include <net/net_osdep.h>
+
+#include "bpf.h"
+#define NBPFILTER NBPF
+#include "stf.h"
+#include "gif.h" /*XXX*/
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#if NGIF > 0
+#include <net/if_gif.h>
+#endif
+
+#if NSTF > 0
+#if NSTF != 1
+# error only single stf interface allowed
+#endif
+
+#define IN6_IS_ADDR_6TO4(x) (ntohs((x)->s6_addr16[0]) == 0x2002)
+#define GET_V4(x) ((struct in_addr *)(&(x)->s6_addr16[1]))
+
+struct stf_softc {
+ struct ifnet sc_if; /* common area */
+ union {
+ struct route __sc_ro4;
+ struct route_in6 __sc_ro6; /* just for safety */
+ } __sc_ro46;
+#define sc_ro __sc_ro46.__sc_ro4
+ const struct encaptab *encap_cookie;
+};
+
+static struct stf_softc *stf;
+static int nstf;
+
+#if NGIF > 0
+extern int ip_gif_ttl; /*XXX*/
+#else
+static int ip_gif_ttl = 40; /*XXX*/
+#endif
+
+extern struct protosw in_stf_protosw;
+
+void stfattach __P((void *));
+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 void stf_rtrequest __P((int, struct rtentry *, struct sockaddr *));
+static int stf_ioctl __P((struct ifnet *, u_long, caddr_t));
+
+void
+stfattach(dummy)
+ void *dummy;
+{
+ struct stf_softc *sc;
+ int i;
+ const struct encaptab *p;
+
+ nstf = NSTF;
+ stf = malloc(nstf * sizeof(struct stf_softc), M_DEVBUF, M_WAIT);
+ bzero(stf, nstf * sizeof(struct stf_softc));
+ sc = stf;
+
+ /* XXX just in case... */
+ for (i = 0; i < nstf; i++) {
+ sc = &stf[i];
+ bzero(sc, sizeof(*sc));
+ sc->sc_if.if_name = "stf";
+ sc->sc_if.if_unit = i;
+
+ p = encap_attach_func(AF_INET, IPPROTO_IPV6, stf_encapcheck,
+ &in_stf_protosw, sc);
+ if (p == NULL) {
+ printf("%s: attach failed\n", if_name(&sc->sc_if));
+ continue;
+ }
+ sc->encap_cookie = p;
+
+ sc->sc_if.if_mtu = IPV6_MMTU;
+ sc->sc_if.if_flags = 0;
+ sc->sc_if.if_ioctl = stf_ioctl;
+ sc->sc_if.if_output = stf_output;
+ sc->sc_if.if_type = IFT_STF;
+ sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
+ if_attach(&sc->sc_if);
+#if NBPFILTER > 0
+#ifdef HAVE_OLD_BPF
+ bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
+#else
+ bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_NULL, sizeof(u_int));
+#endif
+#endif
+ }
+}
+
+PSEUDO_SET(stfattach, if_stf);
+
+static int
+stf_encapcheck(m, off, proto, arg)
+ const struct mbuf *m;
+ int off;
+ int proto;
+ void *arg;
+{
+ struct ip ip;
+ struct in6_ifaddr *ia6;
+ struct stf_softc *sc;
+ struct in_addr a, b;
+
+ sc = (struct stf_softc *)arg;
+ if (sc == NULL)
+ return 0;
+
+ if ((sc->sc_if.if_flags & IFF_UP) == 0)
+ return 0;
+
+ if (proto != IPPROTO_IPV6)
+ return 0;
+
+ /* LINTED const cast */
+ m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
+
+ if (ip.ip_v != 4)
+ return 0;
+
+ ia6 = stf_getsrcifa6(&sc->sc_if);
+ if (ia6 == NULL)
+ return 0;
+
+ /*
+ * check if IPv4 dst matches the IPv4 address derived from the
+ * local 6to4 address.
+ * success on: dst = 10.1.1.1, ia6->ia_addr = 2002:0a01:0101:...
+ */
+ if (bcmp(GET_V4(&ia6->ia_addr.sin6_addr), &ip.ip_dst,
+ sizeof(ip.ip_dst)) != 0)
+ return 0;
+
+ /*
+ * check if IPv4 src matches the IPv4 address derived from the
+ * local 6to4 address masked by prefixmask.
+ * success on: src = 10.1.1.1, ia6->ia_addr = 2002:0a00:.../24
+ * fail on: src = 10.1.1.1, ia6->ia_addr = 2002:0b00:.../24
+ */
+ bzero(&a, sizeof(a));
+ a.s_addr = GET_V4(&ia6->ia_addr.sin6_addr)->s_addr;
+ a.s_addr &= GET_V4(&ia6->ia_prefixmask.sin6_addr)->s_addr;
+ b = ip.ip_src;
+ b.s_addr &= GET_V4(&ia6->ia_prefixmask.sin6_addr)->s_addr;
+ if (a.s_addr != b.s_addr)
+ return 0;
+
+ /* stf interface makes single side match only */
+ return 32;
+}
+
+static struct in6_ifaddr *
+stf_getsrcifa6(ifp)
+ struct ifnet *ifp;
+{
+ struct ifaddr *ia;
+ struct in_ifaddr *ia4;
+ struct sockaddr_in6 *sin6;
+ struct in_addr in;
+
+ for (ia = ifp->if_addrlist.tqh_first;
+ ia;
+ ia = ia->ifa_list.tqe_next)
+ {
+ if (ia->ifa_addr == NULL)
+ continue;
+ if (ia->ifa_addr->sa_family != AF_INET6)
+ continue;
+ sin6 = (struct sockaddr_in6 *)ia->ifa_addr;
+ if (!IN6_IS_ADDR_6TO4(&sin6->sin6_addr))
+ continue;
+
+ bcopy(GET_V4(&sin6->sin6_addr), &in, sizeof(in));
+ for (ia4 = TAILQ_FIRST(&in_ifaddrhead);
+ ia4;
+ ia4 = TAILQ_NEXT(ia4, ia_link))
+ {
+ if (ia4->ia_addr.sin_addr.s_addr == in.s_addr)
+ break;
+ }
+ if (ia4 == NULL)
+ continue;
+
+ return (struct in6_ifaddr *)ia;
+ }
+
+ return NULL;
+}
+
+#ifndef offsetof
+#define offsetof(s, e) ((int)&((s *)0)->e)
+#endif
+
+static int
+stf_output(ifp, m, dst, rt)
+ struct ifnet *ifp;
+ struct mbuf *m;
+ struct sockaddr *dst;
+ struct rtentry *rt;
+{
+ struct stf_softc *sc;
+ struct sockaddr_in6 *dst6;
+ struct sockaddr_in *dst4;
+ u_int8_t tos;
+ struct ip *ip;
+ struct ip6_hdr *ip6;
+ struct in6_ifaddr *ia6;
+
+ sc = (struct stf_softc*)ifp;
+ dst6 = (struct sockaddr_in6 *)dst;
+
+ /* just in case */
+ if ((ifp->if_flags & IFF_UP) == 0) {
+ m_freem(m);
+ return ENETDOWN;
+ }
+
+ /*
+ * If we don't have an ip4 address that match my inner ip6 address,
+ * we shouldn't generate output. Without this check, we'll end up
+ * using wrong IPv4 source.
+ */
+ ia6 = stf_getsrcifa6(ifp);
+ if (ia6 == NULL) {
+ m_freem(m);
+ return ENETDOWN;
+ }
+
+ if (m->m_len < sizeof(*ip6)) {
+ m = m_pullup(m, sizeof(*ip6));
+ if (!m)
+ return ENOBUFS;
+ }
+ ip6 = mtod(m, struct ip6_hdr *);
+ tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
+
+ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
+ if (m && m->m_len < sizeof(struct ip))
+ m = m_pullup(m, sizeof(struct ip));
+ if (m == NULL)
+ return ENOBUFS;
+ ip = mtod(m, struct ip *);
+
+ bzero(ip, sizeof(*ip));
+
+ 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));
+ 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);
+
+ dst4 = (struct sockaddr_in *)&sc->sc_ro.ro_dst;
+ if (dst4->sin_family != AF_INET ||
+ bcmp(&dst4->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst)) != 0) {
+ /* cache route doesn't match */
+ dst4->sin_family = AF_INET;
+ dst4->sin_len = sizeof(struct sockaddr_in);
+ bcopy(&ip->ip_dst, &dst4->sin_addr, sizeof(dst4->sin_addr));
+ if (sc->sc_ro.ro_rt) {
+ RTFREE(sc->sc_ro.ro_rt);
+ sc->sc_ro.ro_rt = NULL;
+ }
+ }
+
+ if (sc->sc_ro.ro_rt == NULL) {
+ rtalloc(&sc->sc_ro);
+ if (sc->sc_ro.ro_rt == NULL) {
+ m_freem(m);
+ return ENETUNREACH;
+ }
+ }
+
+ return ip_output(m, NULL, &sc->sc_ro, 0, NULL);
+}
+
+static int
+stf_checkaddr4(in, ifp)
+ struct in_addr *in;
+ struct ifnet *ifp; /* incoming interface */
+{
+ struct in_ifaddr *ia4;
+
+ /*
+ * reject packets with the following address:
+ * 224.0.0.0/4 0.0.0.0/8 127.0.0.0/8 255.0.0.0/8
+ */
+ if (IN_MULTICAST(in->s_addr))
+ return -1;
+ switch ((ntohl(in->s_addr) & 0xff000000) >> 24) {
+ case 0: case 127: case 255:
+ return -1;
+ }
+
+ /*
+ * reject packets with broadcast
+ */
+ for (ia4 = TAILQ_FIRST(&in_ifaddrhead);
+ ia4;
+ ia4 = TAILQ_NEXT(ia4, ia_link))
+ {
+ if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
+ continue;
+ if (in->s_addr == ia4->ia_broadaddr.sin_addr.s_addr)
+ return -1;
+ }
+
+ /*
+ * perform ingress filter
+ */
+ if (ifp) {
+ struct sockaddr_in sin;
+ struct rtentry *rt;
+
+ bzero(&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ 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);
+ return -1;
+ }
+ rtfree(rt);
+ }
+
+ return 0;
+}
+
+static int
+stf_checkaddr6(in6, ifp)
+ struct in6_addr *in6;
+ struct ifnet *ifp; /* incoming interface */
+{
+ /*
+ * check 6to4 addresses
+ */
+ if (IN6_IS_ADDR_6TO4(in6))
+ return stf_checkaddr4(GET_V4(in6), ifp);
+
+ /*
+ * reject anything that look suspicious. the test is implemented
+ * in ip6_input too, but we check here as well to
+ * (1) reject bad packets earlier, and
+ * (2) to be safe against future ip6_input change.
+ */
+ if (IN6_IS_ADDR_V4COMPAT(in6) || IN6_IS_ADDR_V4MAPPED(in6))
+ return -1;
+
+ return 0;
+}
+
+void
+#if __STDC__
+in_stf_input(struct mbuf *m, ...)
+#else
+in_stf_input(m, va_alist)
+ register struct mbuf *m;
+#endif
+{
+ int off, proto;
+ struct stf_softc *sc;
+ struct ip *ip;
+ struct ip6_hdr *ip6;
+ u_int8_t otos, itos;
+ int s, isr;
+ struct ifqueue *ifq = NULL;
+ struct ifnet *ifp;
+ va_list ap;
+
+ va_start(ap, m);
+ off = va_arg(ap, int);
+ proto = va_arg(ap, int);
+ va_end(ap);
+
+ if (proto != IPPROTO_IPV6) {
+ m_freem(m);
+ return;
+ }
+
+ ip = mtod(m, struct ip *);
+
+ sc = (struct stf_softc *)encap_getarg(m);
+
+ if (sc == NULL || (sc->sc_if.if_flags & IFF_UP) == 0) {
+ m_freem(m);
+ return;
+ }
+
+ ifp = &sc->sc_if;
+
+ /*
+ * 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) {
+ m_freem(m);
+ return;
+ }
+
+ otos = ip->ip_tos;
+ m_adj(m, off);
+
+ if (m->m_len < sizeof(*ip6)) {
+ m = m_pullup(m, sizeof(*ip6));
+ if (!m)
+ return;
+ }
+ ip6 = mtod(m, struct ip6_hdr *);
+
+ /*
+ * 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) {
+ m_freem(m);
+ return;
+ }
+
+ itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
+ if ((ifp->if_flags & IFF_LINK1) != 0)
+ ip_ecn_egress(ECN_ALLOWED, &otos, &itos);
+ ip6->ip6_flow &= ~htonl(0xff << 20);
+ ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
+
+ m->m_pkthdr.rcvif = ifp;
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf) {
+ /*
+ * 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).
+ */
+ struct mbuf m0;
+ u_int af = AF_INET6;
+
+ 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 /*NBPFILTER > 0*/
+
+ /*
+ * Put the packet to the network layer input queue according to the
+ * specified address family.
+ * See net/if_gif.c for possible issues with packet processing
+ * reorder due to extra queueing.
+ */
+ ifq = &ip6intrq;
+ isr = NETISR_IPV6;
+
+ s = splimp();
+ if (IF_QFULL(ifq)) {
+ IF_DROP(ifq); /* update statistics */
+ m_freem(m);
+ splx(s);
+ return;
+ }
+ IF_ENQUEUE(ifq, m);
+ schednetisr(isr);
+ ifp->if_ipackets++;
+ ifp->if_ibytes += m->m_pkthdr.len;
+ splx(s);
+}
+
+/* ARGSUSED */
+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)
+ rt->rt_rmx.rmx_mtu = IPV6_MMTU;
+}
+
+static int
+stf_ioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct ifaddr *ifa;
+ struct ifreq *ifr;
+ struct sockaddr_in6 *sin6;
+ int error;
+
+ error = 0;
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifa = (struct ifaddr *)data;
+ if (ifa == NULL || ifa->ifa_addr->sa_family != AF_INET6) {
+ error = EAFNOSUPPORT;
+ break;
+ }
+ sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ if (IN6_IS_ADDR_6TO4(&sin6->sin6_addr)) {
+ ifa->ifa_rtrequest = stf_rtrequest;
+ ifp->if_flags |= IFF_UP;
+ } else
+ error = EINVAL;
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ ifr = (struct ifreq *)data;
+ if (ifr && ifr->ifr_addr.sa_family == AF_INET6)
+ ;
+ else
+ error = EAFNOSUPPORT;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+#endif /* NSTF > 0 */
diff --git a/sys/crypto/hmac_md5.h b/sys/net/if_stf.h
index 86558fc8cd0b..258f3a060aa5 100644
--- a/sys/crypto/hmac_md5.h
+++ b/sys/net/if_stf.h
@@ -1,5 +1,8 @@
+/* $FreeBSD$ */
+/* $KAME: if_stf.h,v 1.3 2000/03/25 07:23:33 sumikawa Exp $ */
+
/*
- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * Copyright (C) 2000 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,13 +28,11 @@
* 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.
- *
- * $FreeBSD$
*/
-#ifndef _NETINET6_HMAC_MD5_H_
-#define _NETINET6_HMAC_MD5_H_
+#ifndef _NET_IF_STF_H_
+#define _NET_IF_STF_H_
-extern void hmac_md5 __P((caddr_t, size_t, caddr_t, size_t, caddr_t));
+void in_stf_input __P((struct mbuf *, ...));
-#endif /* ! _NETINET6_HMAC_MD5_H_*/
+#endif /* _NET_IF_STF_H_ */
diff --git a/sys/net/if_types.h b/sys/net/if_types.h
index 318b35660096..13cdcdd66421 100644
--- a/sys/net/if_types.h
+++ b/sys/net/if_types.h
@@ -99,5 +99,6 @@
#define IFT_PROPMUX 0x36 /* Proprietary Multiplexing */
#define IFT_GIF 0x37
#define IFT_FAITH 0x38
+#define IFT_STF 0x39
#endif
diff --git a/sys/net/net_osdep.c b/sys/net/net_osdep.c
index 03e40f3ad2dd..02000f6d4889 100644
--- a/sys/net/net_osdep.c
+++ b/sys/net/net_osdep.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: net_osdep.c,v 1.4 2000/03/25 07:23:34 sumikawa Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
#include <sys/param.h>
@@ -44,6 +45,7 @@
#include <net/netisr.h>
#include <net/route.h>
#include <net/bpf.h>
+
#include <net/net_osdep.h>
const char *
diff --git a/sys/net/net_osdep.h b/sys/net/net_osdep.h
index 11fc27c3cd41..47f52161f1e7 100644
--- a/sys/net/net_osdep.h
+++ b/sys/net/net_osdep.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: net_osdep.h,v 1.21 2000/07/02 23:34:38 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
* glue for kernel code programming differences.
@@ -35,11 +36,25 @@
/*
* OS dependencies:
*
+ * - 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.
+ *
+ * - 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.
* - privileged process
* NetBSD, FreeBSD 3
* struct proc *p;
* if (p && !suser(p->p_ucred, &p->p_acflag))
* privileged;
+ * FreeBSD 4
+ * struct proc *p;
+ * if (p && !suser(p))
+ * privileged;
* OpenBSD, BSDI [34], FreeBSD 2
* struct socket *so;
* if (so->so_state & SS_PRIV)
@@ -76,7 +91,7 @@
* NetBSD, OpenBSD, BSDI [34], FreeBSD 2
* timeout() is a void function
* FreeBSD 3
- * timeout() is non-void, must keep returned value for untimeuot()
+ * timeout() is non-void, must keep returned value for untimeout()
* - sysctl
* NetBSD, OpenBSD
* foo_sysctl()
@@ -106,16 +121,45 @@
*
* - dtom()
* NEVER USE IT!
+ *
+ * - struct ifnet for loopback interface
+ * BSDI3: struct ifnet loif;
+ * BSDI4: struct ifnet *loifp;
+ * NetBSD, OpenBSD, FreeBSD2: struct ifnet loif[NLOOP];
+ *
+ * odd thing is that many of them refers loif as ifnet *loif,
+ * not loif[NLOOP], from outside of if_loop.c.
+ *
+ * - number of bpf pseudo devices
+ * others: bpfilter.h, NBPFILTER
+ * FreeBSD4: bpf.h, NBPF
+ * solution:
+ * #if defined(__FreeBSD__) && __FreeBSD__ >= 4
+ * #include "bpf.h"
+ * #define NBPFILTER NBPF
+ * #else
+ * #include "bpfilter.h"
+ * #endif
+ *
+ * - protosw for IPv4 (sys/netinet)
+ * FreeBSD4: struct ipprotosw in netinet/ipprotosw.h
+ * others: struct protosw in sys/protosw.h
+ *
+ * - header files with defopt (opt_xx.h)
+ * FreeBSD3: opt_{inet,ipsec,ip6fw,altq}.h
+ * FreeBSD4: opt_{inet,inet6,ipsec,ip6fw,altq}.h
+ * NetBSD: opt_{inet,ipsec,altq}.h
+ * others: does not use defopt
*/
#ifndef __NET_NET_OSDEP_H_DEFINED_
-#define __NET_NET_OSDEP_H_DEFINED_
+#define __NET_NET_OSDEP_H_DEFINED_
#ifdef _KERNEL
struct ifnet;
-extern const char *if_name __P((struct ifnet *));
+extern const char *if_name __P((struct ifnet *));
-#define HAVE_OLD_BPF
+#define HAVE_OLD_BPF
#endif /*_KERNEL*/
#endif /*__NET_NET_OSDEP_H_DEFINED_ */
diff --git a/sys/net/pfkeyv2.h b/sys/net/pfkeyv2.h
index e8831f70df7f..4c41c8072b68 100644
--- a/sys/net/pfkeyv2.h
+++ b/sys/net/pfkeyv2.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: pfkeyv2.h,v 1.17 2000/06/22 08:38:33 sakane Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,12 +28,8 @@
* 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.
- *
- * $FreeBSD$
*/
-/* $Id: keyv2.h,v 1.1.6.1.6.4 1999/06/08 05:33:39 itojun Exp $ */
-
/*
* This file has been derived rfc 2367,
* And added some flags of SADB_KEY_FLAGS_ as SADB_X_EXT_.
@@ -38,7 +37,7 @@
*/
#ifndef _NET_PFKEYV2_H_
-#define _NET_PFKEYV2_H_
+#define _NET_PFKEYV2_H_
/*
This file defines structures and symbols for the PF_KEY Version 2
@@ -47,177 +46,187 @@ Laboratory. This file is in the public domain. The authors ask that
you leave this credit intact on any copies of this file.
*/
#ifndef __PFKEY_V2_H
-#define __PFKEY_V2_H 1
-
-#define PF_KEY_V2 2
-#define PFKEYV2_REVISION 199806L
-
-#define SADB_RESERVED 0
-#define SADB_GETSPI 1
-#define SADB_UPDATE 2
-#define SADB_ADD 3
-#define SADB_DELETE 4
-#define SADB_GET 5
-#define SADB_ACQUIRE 6
-#define SADB_REGISTER 7
-#define SADB_EXPIRE 8
-#define SADB_FLUSH 9
-#define SADB_DUMP 10
-#define SADB_X_PROMISC 11
-#define SADB_X_PCHANGE 12
-
-#define SADB_X_SPDUPDATE 13 /* not yet */
-#define SADB_X_SPDADD 14
-#define SADB_X_SPDDELETE 15
-#define SADB_X_SPDGET 16 /* not yet */
-#define SADB_X_SPDACQUIRE 17 /* not yet */
-#define SADB_X_SPDDUMP 18
-#define SADB_X_SPDFLUSH 19
-#define SADB_MAX 19
+#define __PFKEY_V2_H 1
+
+#define PF_KEY_V2 2
+#define PFKEYV2_REVISION 199806L
+
+#define SADB_RESERVED 0
+#define SADB_GETSPI 1
+#define SADB_UPDATE 2
+#define SADB_ADD 3
+#define SADB_DELETE 4
+#define SADB_GET 5
+#define SADB_ACQUIRE 6
+#define SADB_REGISTER 7
+#define SADB_EXPIRE 8
+#define SADB_FLUSH 9
+#define SADB_DUMP 10
+#define SADB_X_PROMISC 11
+#define SADB_X_PCHANGE 12
+
+#define SADB_X_SPDUPDATE 13
+#define SADB_X_SPDADD 14
+#define SADB_X_SPDDELETE 15 /* by policy index */
+#define SADB_X_SPDGET 16
+#define SADB_X_SPDACQUIRE 17
+#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_SPDDELETE2 22 /* by policy id */
+#define SADB_MAX 22
struct sadb_msg {
- u_int8_t sadb_msg_version;
- u_int8_t sadb_msg_type;
- u_int8_t sadb_msg_errno;
- u_int8_t sadb_msg_satype;
- u_int16_t sadb_msg_len;
- u_int8_t sadb_msg_mode; /* XXX */
- u_int8_t sadb_msg_reserved;
- u_int32_t sadb_msg_seq;
- u_int32_t sadb_msg_pid;
+ u_int8_t sadb_msg_version;
+ u_int8_t sadb_msg_type;
+ u_int8_t sadb_msg_errno;
+ u_int8_t sadb_msg_satype;
+ u_int16_t sadb_msg_len;
+ u_int16_t sadb_msg_reserved;
+ u_int32_t sadb_msg_seq;
+ u_int32_t sadb_msg_pid;
};
struct sadb_ext {
- u_int16_t sadb_ext_len;
- u_int16_t sadb_ext_type;
+ u_int16_t sadb_ext_len;
+ u_int16_t sadb_ext_type;
};
struct sadb_sa {
- u_int16_t sadb_sa_len;
- u_int16_t sadb_sa_exttype;
- u_int32_t sadb_sa_spi;
- u_int8_t sadb_sa_replay;
- u_int8_t sadb_sa_state;
- u_int8_t sadb_sa_auth;
- u_int8_t sadb_sa_encrypt;
- u_int32_t sadb_sa_flags;
+ u_int16_t sadb_sa_len;
+ u_int16_t sadb_sa_exttype;
+ u_int32_t sadb_sa_spi;
+ u_int8_t sadb_sa_replay;
+ u_int8_t sadb_sa_state;
+ u_int8_t sadb_sa_auth;
+ u_int8_t sadb_sa_encrypt;
+ u_int32_t sadb_sa_flags;
};
struct sadb_lifetime {
- u_int16_t sadb_lifetime_len;
- u_int16_t sadb_lifetime_exttype;
- u_int32_t sadb_lifetime_allocations;
- u_int64_t sadb_lifetime_bytes;
- u_int64_t sadb_lifetime_addtime;
- u_int64_t sadb_lifetime_usetime;
+ u_int16_t sadb_lifetime_len;
+ u_int16_t sadb_lifetime_exttype;
+ u_int32_t sadb_lifetime_allocations;
+ u_int64_t sadb_lifetime_bytes;
+ u_int64_t sadb_lifetime_addtime;
+ u_int64_t sadb_lifetime_usetime;
};
struct sadb_address {
- u_int16_t sadb_address_len;
- u_int16_t sadb_address_exttype;
- u_int8_t sadb_address_proto;
- u_int8_t sadb_address_prefixlen;
- u_int16_t sadb_address_reserved;
+ u_int16_t sadb_address_len;
+ u_int16_t sadb_address_exttype;
+ u_int8_t sadb_address_proto;
+ u_int8_t sadb_address_prefixlen;
+ u_int16_t sadb_address_reserved;
};
struct sadb_key {
- u_int16_t sadb_key_len;
- u_int16_t sadb_key_exttype;
- u_int16_t sadb_key_bits;
- u_int16_t sadb_key_reserved;
+ u_int16_t sadb_key_len;
+ u_int16_t sadb_key_exttype;
+ u_int16_t sadb_key_bits;
+ u_int16_t sadb_key_reserved;
};
struct sadb_ident {
- u_int16_t sadb_ident_len;
- u_int16_t sadb_ident_exttype;
- u_int16_t sadb_ident_type;
- u_int16_t sadb_ident_reserved;
- u_int64_t sadb_ident_id;
-};
-/* in order to use to divide sadb_ident.sadb_ident_id */
-union sadb_x_ident_id {
- u_int64_t sadb_x_ident_id;
- struct _sadb_x_ident_id_addr {
- u_int16_t prefix;
- u_int16_t ul_proto;
- u_int32_t reserved;
- } sadb_x_ident_id_addr;
+ u_int16_t sadb_ident_len;
+ u_int16_t sadb_ident_exttype;
+ u_int16_t sadb_ident_type;
+ u_int16_t sadb_ident_reserved;
+ u_int64_t sadb_ident_id;
};
struct sadb_sens {
- u_int16_t sadb_sens_len;
- u_int16_t sadb_sens_exttype;
- u_int32_t sadb_sens_dpd;
- u_int8_t sadb_sens_sens_level;
- u_int8_t sadb_sens_sens_len;
- u_int8_t sadb_sens_integ_level;
- u_int8_t sadb_sens_integ_len;
- u_int32_t sadb_sens_reserved;
+ u_int16_t sadb_sens_len;
+ u_int16_t sadb_sens_exttype;
+ u_int32_t sadb_sens_dpd;
+ u_int8_t sadb_sens_sens_level;
+ u_int8_t sadb_sens_sens_len;
+ u_int8_t sadb_sens_integ_level;
+ u_int8_t sadb_sens_integ_len;
+ u_int32_t sadb_sens_reserved;
};
struct sadb_prop {
- u_int16_t sadb_prop_len;
- u_int16_t sadb_prop_exttype;
- u_int8_t sadb_prop_replay;
- u_int8_t sadb_prop_reserved[3];
+ u_int16_t sadb_prop_len;
+ u_int16_t sadb_prop_exttype;
+ u_int8_t sadb_prop_replay;
+ u_int8_t sadb_prop_reserved[3];
};
struct sadb_comb {
- u_int8_t sadb_comb_auth;
- u_int8_t sadb_comb_encrypt;
- u_int16_t sadb_comb_flags;
- u_int16_t sadb_comb_auth_minbits;
- u_int16_t sadb_comb_auth_maxbits;
- u_int16_t sadb_comb_encrypt_minbits;
- u_int16_t sadb_comb_encrypt_maxbits;
- u_int32_t sadb_comb_reserved;
- u_int32_t sadb_comb_soft_allocations;
- u_int32_t sadb_comb_hard_allocations;
- u_int64_t sadb_comb_soft_bytes;
- u_int64_t sadb_comb_hard_bytes;
- u_int64_t sadb_comb_soft_addtime;
- u_int64_t sadb_comb_hard_addtime;
- u_int64_t sadb_comb_soft_usetime;
- u_int64_t sadb_comb_hard_usetime;
+ u_int8_t sadb_comb_auth;
+ u_int8_t sadb_comb_encrypt;
+ u_int16_t sadb_comb_flags;
+ u_int16_t sadb_comb_auth_minbits;
+ u_int16_t sadb_comb_auth_maxbits;
+ u_int16_t sadb_comb_encrypt_minbits;
+ u_int16_t sadb_comb_encrypt_maxbits;
+ u_int32_t sadb_comb_reserved;
+ u_int32_t sadb_comb_soft_allocations;
+ u_int32_t sadb_comb_hard_allocations;
+ u_int64_t sadb_comb_soft_bytes;
+ u_int64_t sadb_comb_hard_bytes;
+ u_int64_t sadb_comb_soft_addtime;
+ u_int64_t sadb_comb_hard_addtime;
+ u_int64_t sadb_comb_soft_usetime;
+ u_int64_t sadb_comb_hard_usetime;
};
struct sadb_supported {
- u_int16_t sadb_supported_len;
- u_int16_t sadb_supported_exttype;
- u_int32_t sadb_supported_reserved;
+ u_int16_t sadb_supported_len;
+ u_int16_t sadb_supported_exttype;
+ u_int32_t sadb_supported_reserved;
};
struct sadb_alg {
- u_int8_t sadb_alg_id;
- u_int8_t sadb_alg_ivlen;
- u_int16_t sadb_alg_minbits;
- u_int16_t sadb_alg_maxbits;
- u_int16_t sadb_alg_reserved;
+ u_int8_t sadb_alg_id;
+ u_int8_t sadb_alg_ivlen;
+ u_int16_t sadb_alg_minbits;
+ u_int16_t sadb_alg_maxbits;
+ u_int16_t sadb_alg_reserved;
};
struct sadb_spirange {
- u_int16_t sadb_spirange_len;
- u_int16_t sadb_spirange_exttype;
- u_int32_t sadb_spirange_min;
- u_int32_t sadb_spirange_max;
- u_int32_t sadb_spirange_reserved;
+ u_int16_t sadb_spirange_len;
+ u_int16_t sadb_spirange_exttype;
+ u_int32_t sadb_spirange_min;
+ u_int32_t sadb_spirange_max;
+ u_int32_t sadb_spirange_reserved;
};
struct sadb_x_kmprivate {
- u_int16_t sadb_x_kmprivate_len;
- u_int16_t sadb_x_kmprivate_exttype;
- u_int32_t sadb_x_kmprivate_reserved;
+ u_int16_t sadb_x_kmprivate_len;
+ u_int16_t sadb_x_kmprivate_exttype;
+ u_int32_t sadb_x_kmprivate_reserved;
+};
+
+/*
+ * XXX Additional SA Extension.
+ * mode: tunnel or transport
+ * reqid: to make SA unique nevertheless the address pair of SA are same.
+ * Mainly it's for VPN.
+ */
+struct sadb_x_sa2 {
+ u_int16_t sadb_x_sa2_len;
+ u_int16_t sadb_x_sa2_exttype;
+ u_int8_t sadb_x_sa2_mode;
+ u_int8_t sadb_x_sa2_reserved1;
+ u_int16_t sadb_x_sa2_reserved2;
+ u_int32_t sadb_x_sa2_reserved3;
+ u_int32_t sadb_x_sa2_reqid;
};
/* XXX Policy Extension */
-/* sizeof(struct sadb_x_policy) == 8 */
+/* sizeof(struct sadb_x_policy) == 16 */
struct sadb_x_policy {
- u_int16_t sadb_x_policy_len;
- u_int16_t sadb_x_policy_exttype;
- /* See policy type of ipsec.h */
- u_int16_t sadb_x_policy_type;
- u_int8_t sadb_x_policy_dir; /* direction, see ipsec.h */
- u_int8_t sadb_x_policy_reserved;
+ u_int16_t sadb_x_policy_len;
+ u_int16_t sadb_x_policy_exttype;
+ u_int16_t sadb_x_policy_type; /* See policy type of ipsec.h */
+ u_int8_t sadb_x_policy_dir; /* direction, see ipsec.h */
+ u_int8_t sadb_x_policy_reserved;
+ u_int32_t sadb_x_policy_id;
+ u_int32_t sadb_x_policy_reserved2;
};
/*
* When policy_type == IPSEC, it is followed by some of
@@ -231,190 +240,143 @@ struct sadb_x_policy {
* This structure is aligned 8 bytes.
*/
struct sadb_x_ipsecrequest {
- u_int16_t sadb_x_ipsecrequest_len;
- /* structure length aligned to 8 bytes.
- * This value is true length of bytes.
- * Not in units of 64 bits. */
- u_int16_t sadb_x_ipsecrequest_proto; /* See ipsec.h */
- /* See ipsec.h. Not SADB_SATYPE_XX */
- u_int16_t sadb_x_ipsecrequest_mode;
- u_int16_t sadb_x_ipsecrequest_level; /* See ipsec.h */
-
- /*
- * followed by source IP address of SA, and immediately followed by
- * destination IP address of SA. These encoded into two of sockaddr
- * structure without any padding. Must set each sa_len exactly.
- * Each of length of the sockaddr structure are not aligned to 64bits,
- * but sum of x_request and addresses is aligned to 64bits.
- */
+ u_int16_t sadb_x_ipsecrequest_len; /* structure length aligned to 8 bytes.
+ * This value is true length of bytes.
+ * Not in units of 64 bits. */
+ u_int16_t sadb_x_ipsecrequest_proto; /* See ipsec.h */
+ u_int8_t sadb_x_ipsecrequest_mode; /* See IPSEC_MODE_XX in ipsec.h. */
+ u_int8_t sadb_x_ipsecrequest_level; /* See IPSEC_LEVEL_XX in ipsec.h */
+ u_int16_t sadb_x_ipsecrequest_reqid; /* See ipsec.h */
+
+ /*
+ * followed by source IP address of SA, and immediately followed by
+ * destination IP address of SA. These encoded into two of sockaddr
+ * structure without any padding. Must set each sa_len exactly.
+ * Each of length of the sockaddr structure are not aligned to 64bits,
+ * but sum of x_request and addresses is aligned to 64bits.
+ */
};
-#define SADB_EXT_RESERVED 0
-#define SADB_EXT_SA 1
-#define SADB_EXT_LIFETIME_CURRENT 2
-#define SADB_EXT_LIFETIME_HARD 3
-#define SADB_EXT_LIFETIME_SOFT 4
-#define SADB_EXT_ADDRESS_SRC 5
-#define SADB_EXT_ADDRESS_DST 6
-#define SADB_EXT_ADDRESS_PROXY 7
-#define SADB_EXT_KEY_AUTH 8
-#define SADB_EXT_KEY_ENCRYPT 9
-#define SADB_EXT_IDENTITY_SRC 10
-#define SADB_EXT_IDENTITY_DST 11
-#define SADB_EXT_SENSITIVITY 12
-#define SADB_EXT_PROPOSAL 13
-#define SADB_EXT_SUPPORTED_AUTH 14
-#define SADB_EXT_SUPPORTED_ENCRYPT 15
-#define SADB_EXT_SPIRANGE 16
-#define SADB_X_EXT_KMPRIVATE 17
-#define SADB_X_EXT_POLICY 18
-#define SADB_EXT_MAX 18
-
-#define SADB_SATYPE_UNSPEC 0
-#define SADB_SATYPE_AH 2
-#define SADB_SATYPE_ESP 3
-#define SADB_SATYPE_RSVP 5
-#define SADB_SATYPE_OSPFV2 6
-#define SADB_SATYPE_RIPV2 7
-#define SADB_SATYPE_MIP 8
-#define SADB_X_SATYPE_IPCOMP 9
-#define SADB_SATYPE_MAX 9
-
-#define SADB_SASTATE_LARVAL 0
-#define SADB_SASTATE_MATURE 1
-#define SADB_SASTATE_DYING 2
-#define SADB_SASTATE_DEAD 3
-#define SADB_SASTATE_MAX 3
-#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
-
-/*nonstandard */
-#define SADB_X_CALG_NONE 0
-#define SADB_X_CALG_OUI 1
-#define SADB_X_CALG_DEFLATE 2
-#define SADB_X_CALG_LZS 3
-
-#define SADB_IDENTTYPE_RESERVED 0
-#define SADB_IDENTTYPE_PREFIX 1
-#define SADB_IDENTTYPE_FQDN 2
-#define SADB_IDENTTYPE_USERFQDN 3
-#define SADB_X_IDENTTYPE_ADDR 4
-#define SADB_IDENTTYPE_MAX 4
+#define SADB_EXT_RESERVED 0
+#define SADB_EXT_SA 1
+#define SADB_EXT_LIFETIME_CURRENT 2
+#define SADB_EXT_LIFETIME_HARD 3
+#define SADB_EXT_LIFETIME_SOFT 4
+#define SADB_EXT_ADDRESS_SRC 5
+#define SADB_EXT_ADDRESS_DST 6
+#define SADB_EXT_ADDRESS_PROXY 7
+#define SADB_EXT_KEY_AUTH 8
+#define SADB_EXT_KEY_ENCRYPT 9
+#define SADB_EXT_IDENTITY_SRC 10
+#define SADB_EXT_IDENTITY_DST 11
+#define SADB_EXT_SENSITIVITY 12
+#define SADB_EXT_PROPOSAL 13
+#define SADB_EXT_SUPPORTED_AUTH 14
+#define SADB_EXT_SUPPORTED_ENCRYPT 15
+#define SADB_EXT_SPIRANGE 16
+#define SADB_X_EXT_KMPRIVATE 17
+#define SADB_X_EXT_POLICY 18
+#define SADB_X_EXT_SA2 19
+#define SADB_EXT_MAX 19
+
+#define SADB_SATYPE_UNSPEC 0
+#define SADB_SATYPE_AH 2
+#define SADB_SATYPE_ESP 3
+#define SADB_SATYPE_RSVP 5
+#define SADB_SATYPE_OSPFV2 6
+#define SADB_SATYPE_RIPV2 7
+#define SADB_SATYPE_MIP 8
+#define SADB_X_SATYPE_IPCOMP 9
+#define SADB_X_SATYPE_POLICY 10
+#define SADB_SATYPE_MAX 11
+
+#define SADB_SASTATE_LARVAL 0
+#define SADB_SASTATE_MATURE 1
+#define SADB_SASTATE_DYING 2
+#define SADB_SASTATE_DEAD 3
+#define SADB_SASTATE_MAX 3
+
+#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
+
+#if 1 /*nonstandard */
+#define SADB_X_CALG_NONE 0
+#define SADB_X_CALG_OUI 1
+#define SADB_X_CALG_DEFLATE 2
+#define SADB_X_CALG_LZS 3
+#define SADB_X_CALG_MAX 4
+#endif
+
+#define SADB_IDENTTYPE_RESERVED 0
+#define SADB_IDENTTYPE_PREFIX 1
+#define SADB_IDENTTYPE_FQDN 2
+#define SADB_IDENTTYPE_USERFQDN 3
+#define SADB_X_IDENTTYPE_ADDR 4
+#define SADB_IDENTTYPE_MAX 4
/* `flags' in sadb_sa structure holds followings */
-#define SADB_X_EXT_NONE 0x0000 /* i.e. new format. */
-#define SADB_X_EXT_OLD 0x0001 /* old format. */
+#define SADB_X_EXT_NONE 0x0000 /* i.e. new format. */
+#define SADB_X_EXT_OLD 0x0001 /* old format. */
-#define SADB_X_EXT_IV4B 0x0010 /* IV length of 4 bytes in use */
-#define SADB_X_EXT_DERIV 0x0020 /* DES derived */
-#define SADB_X_EXT_CYCSEQ 0x0040 /* allowing to cyclic sequence. */
+#define SADB_X_EXT_IV4B 0x0010 /* IV length of 4 bytes in use */
+#define SADB_X_EXT_DERIV 0x0020 /* DES derived */
+#define SADB_X_EXT_CYCSEQ 0x0040 /* allowing to cyclic sequence. */
/* three of followings are exclusive flags each them */
-#define SADB_X_EXT_PSEQ 0x0000 /* sequencial padding for ESP */
-#define SADB_X_EXT_PRAND 0x0100 /* random padding for ESP */
-#define SADB_X_EXT_PZERO 0x0200 /* zero padding for ESP */
-#define SADB_X_EXT_PMASK 0x0300 /* mask for padding flag */
+#define SADB_X_EXT_PSEQ 0x0000 /* sequencial padding for ESP */
+#define SADB_X_EXT_PRAND 0x0100 /* random padding for ESP */
+#define SADB_X_EXT_PZERO 0x0200 /* zero padding for ESP */
+#define SADB_X_EXT_PMASK 0x0300 /* mask for padding flag */
-#define SADB_X_EXT_RAWCPI 0x0080 /* use well known CPI (IPComp) */
+#if 1
+#define SADB_X_EXT_RAWCPI 0x0080 /* use well known CPI (IPComp) */
+#endif
-#define SADB_KEY_FLAGS_MAX 0x0fff
+#define SADB_KEY_FLAGS_MAX 0x0fff
/* SPI size for PF_KEYv2 */
-#define PFKEY_SPI_SIZE sizeof(u_int32_t)
+#define PFKEY_SPI_SIZE sizeof(u_int32_t)
/* Identifier for menber of lifetime structure */
-#define SADB_X_LIFETIME_ALLOCATIONS 0
-#define SADB_X_LIFETIME_BYTES 1
-#define SADB_X_LIFETIME_ADDTIME 2
-#define SADB_X_LIFETIME_USETIME 3
+#define SADB_X_LIFETIME_ALLOCATIONS 0
+#define SADB_X_LIFETIME_BYTES 1
+#define SADB_X_LIFETIME_ADDTIME 2
+#define SADB_X_LIFETIME_USETIME 3
/* The rate for SOFT lifetime against HARD one. */
-#define PFKEY_SOFT_LIFETIME_RATE 80
+#define PFKEY_SOFT_LIFETIME_RATE 80
/* Utilities */
-#define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1)))
+#define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1)))
#define PFKEY_EXTLEN(msg) \
PFKEY_UNUNIT64(((struct sadb_ext *)(msg))->sadb_ext_len)
-#define PFKEY_ADDR_PREFIX(ext) \
+#define PFKEY_ADDR_PREFIX(ext) \
(((struct sadb_address *)(ext))->sadb_address_prefixlen)
-#define PFKEY_ADDR_PROTO(ext) \
+#define PFKEY_ADDR_PROTO(ext) \
(((struct sadb_address *)(ext))->sadb_address_proto)
-#define PFKEY_ADDR_SADDR(ext) \
+#define PFKEY_ADDR_SADDR(ext) \
((struct sockaddr *)((caddr_t)(ext) + sizeof(struct sadb_address)))
/* in 64bits */
#define PFKEY_UNUNIT64(a) ((a) << 3)
#define PFKEY_UNIT64(a) ((a) >> 3)
-#ifndef _KERNEL
-struct sockaddr;
-
-int ipsec_check_keylen __P((u_int supported, u_int alg_id, u_int keylen));
-int pfkey_align __P((struct sadb_msg *msg, caddr_t *mhp));
-int pfkey_check __P((caddr_t *mhp));
-void pfkey_close __P((int so));
-u_int pfkey_get_softrate __P((u_int type));
-u_int pfkey_set_softrate __P((u_int type, u_int rate));
-int pfkey_open __P((void));
-struct sadb_msg *pfkey_recv __P((int so));
-int pfkey_recv_register __P((int so));
-int pfkey_send_register __P((int so, u_int satype));
-void pfkey_sadump __P((struct sadb_msg *m));
-void pfkey_spdump __P((struct sadb_msg *m));
-int pfkey_send __P((int so, struct sadb_msg *msg, int len));
-int pfkey_send_add __P((int so, u_int satype, u_int mode,
- struct sockaddr *src, struct sockaddr *dst,
- u_int32_t spi, u_int wsize, caddr_t keymat,
- u_int e_type, u_int e_keylen, u_int a_type,
- u_int a_keylen, u_int flags, u_int32_t l_alloc,
- u_int64_t l_bytes, u_int64_t l_addtime,
- u_int64_t l_usetime, u_int32_t seq));
-int pfkey_send_delete __P((int so, u_int satype, u_int mode,
- struct sockaddr *src, struct sockaddr *dst,
- u_int32_t spi));
-int pfkey_send_dump __P((int so, u_int satype));
-int pfkey_send_flush __P((int so, u_int satype));
-int pfkey_send_get __P((int so, u_int satype, u_int mode,
- struct sockaddr *src, struct sockaddr *dst,
- u_int32_t spi));
-int pfkey_send_getspi __P((int so, u_int satype, u_int mode,
- struct sockaddr *src, struct sockaddr *dst,
- u_int32_t min, u_int32_t max, u_int32_t seq));
-int pfkey_send_promisc_toggle __P((int so, int flag));
-int pfkey_send_spdadd __P((int so, struct sockaddr *src, u_int prefs,
- struct sockaddr *dst, u_int prefd, u_int proto,
- caddr_t policy, int policylen, u_int32_t seq));
-int pfkey_send_spddelete __P((int so, struct sockaddr *src, u_int prefs,
- struct sockaddr *dst, u_int prefd,
- u_int proto, u_int32_t seq));
-int pfkey_send_spddump __P((int so));
-int pfkey_send_spdflush __P((int so));
-int pfkey_send_update __P((int so, u_int satype, u_int mode,
- struct sockaddr *src, struct sockaddr *dst,
- u_int32_t spi, u_int wsize, caddr_t keymat,
- u_int e_type, u_int e_keylen, u_int a_type,
- u_int a_keylen, u_int flags, u_int32_t l_alloc,
- u_int64_t l_bytes, u_int64_t l_addtime,
- u_int64_t l_usetime, u_int32_t seq));
-
-#endif /*!_KERNEL*/
-
-#endif /* !__PFKEY_V2_H */
-
-#endif /* !_NET_PFKEYV2_H_ */
+#endif /* __PFKEY_V2_H */
+
+#endif /* _NET_PFKEYV2_H_ */
diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h
index 7a3dbbd8dd8a..3625ee48e41e 100644
--- a/sys/netinet/icmp6.h
+++ b/sys/netinet/icmp6.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: icmp6.h,v 1.18 2000/07/03 02:51:08 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,15 +28,634 @@
* 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.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
*
- * $FreeBSD$
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93
*/
#ifndef _NETINET_ICMP6_H_
-#define _NETINET_ICMP6_H_
+#define _NETINET_ICMP6_H_
+
+#define ICMPV6_PLD_MAXLEN 1232 /* IPV6_MMTU - sizeof(struct ip6_hdr)
+ - sizeof(struct icmp6_hdr) */
+
+struct icmp6_hdr {
+ u_int8_t icmp6_type; /* type field */
+ u_int8_t icmp6_code; /* code field */
+ u_int16_t icmp6_cksum; /* checksum field */
+ union {
+ u_int32_t icmp6_un_data32[1]; /* type-specific field */
+ u_int16_t icmp6_un_data16[2]; /* type-specific field */
+ u_int8_t icmp6_un_data8[4]; /* type-specific field */
+ } icmp6_dataun;
+};
+
+#define icmp6_data32 icmp6_dataun.icmp6_un_data32
+#define icmp6_data16 icmp6_dataun.icmp6_un_data16
+#define icmp6_data8 icmp6_dataun.icmp6_un_data8
+#define icmp6_pptr icmp6_data32[0] /* parameter prob */
+#define icmp6_mtu icmp6_data32[0] /* packet too big */
+#define icmp6_id icmp6_data16[0] /* echo request/reply */
+#define icmp6_seq icmp6_data16[1] /* echo request/reply */
+#define icmp6_maxdelay icmp6_data16[0] /* mcast group membership */
+
+#define ICMP6_DST_UNREACH 1 /* dest unreachable, codes: */
+#define ICMP6_PACKET_TOO_BIG 2 /* packet too big */
+#define ICMP6_TIME_EXCEEDED 3 /* time exceeded, code: */
+#define ICMP6_PARAM_PROB 4 /* ip6 header bad */
+
+#define ICMP6_ECHO_REQUEST 128 /* echo service */
+#define ICMP6_ECHO_REPLY 129 /* echo reply */
+#define ICMP6_MEMBERSHIP_QUERY 130 /* group membership query */
+#define MLD6_LISTENER_QUERY 130 /* multicast listener query */
+#define ICMP6_MEMBERSHIP_REPORT 131 /* group membership report */
+#define MLD6_LISTENER_REPORT 131 /* multicast listener report */
+#define ICMP6_MEMBERSHIP_REDUCTION 132 /* group membership termination */
+#define MLD6_LISTENER_DONE 132 /* multicast listener done */
+
+#define ND_ROUTER_SOLICIT 133 /* router solicitation */
+#define ND_ROUTER_ADVERT 134 /* router advertisment */
+#define ND_NEIGHBOR_SOLICIT 135 /* neighbor solicitation */
+#define ND_NEIGHBOR_ADVERT 136 /* neighbor advertisment */
+#define ND_REDIRECT 137 /* redirect */
+
+#define ICMP6_ROUTER_RENUMBERING 138 /* router renumbering */
+
+#define ICMP6_WRUREQUEST 139 /* who are you request */
+#define ICMP6_WRUREPLY 140 /* who are you reply */
+#define ICMP6_FQDN_QUERY 139 /* FQDN query */
+#define ICMP6_FQDN_REPLY 140 /* FQDN reply */
+#define ICMP6_NI_QUERY 139 /* node information request */
+#define ICMP6_NI_REPLY 140 /* node information reply */
+
+/* The definitions below are experimental. TBA */
+#define MLD6_MTRACE_RESP 141 /* mtrace response(to sender) */
+#define MLD6_MTRACE 142 /* mtrace messages */
+
+#define ICMP6_MAXTYPE 142
+
+#define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */
+#define ICMP6_DST_UNREACH_ADMIN 1 /* administratively prohibited */
+#define ICMP6_DST_UNREACH_NOTNEIGHBOR 2 /* not a neighbor(obsolete) */
+#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 /* beyond scope of source address */
+#define ICMP6_DST_UNREACH_ADDR 3 /* address unreachable */
+#define ICMP6_DST_UNREACH_NOPORT 4 /* port unreachable */
+
+#define ICMP6_TIME_EXCEED_TRANSIT 0 /* ttl==0 in transit */
+#define ICMP6_TIME_EXCEED_REASSEMBLY 1 /* ttl==0 in reass */
+
+#define ICMP6_PARAMPROB_HEADER 0 /* erroneous header field */
+#define ICMP6_PARAMPROB_NEXTHEADER 1 /* unrecognized next header */
+#define ICMP6_PARAMPROB_OPTION 2 /* unrecognized option */
+
+#define ICMP6_INFOMSG_MASK 0x80 /* all informational messages */
+
+#define ICMP6_NI_SUBJ_IPV6 0 /* Query Subject is an IPv6 address */
+#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_REFUSED 1 /* node information request is refused */
+#define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */
+
+#define ICMP6_ROUTER_RENUMBERING_COMMAND 0 /* rr command */
+#define ICMP6_ROUTER_RENUMBERING_RESULT 1 /* rr result */
+#define ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET 255 /* rr seq num reset */
+
+/* Used in kernel only */
+#define ND_REDIRECT_ONLINK 0 /* redirect to an on-link node */
+#define ND_REDIRECT_ROUTER 1 /* redirect to a better router */
+
+/*
+ * Multicast Listener Discovery
+ */
+struct mld6_hdr {
+ struct icmp6_hdr mld6_hdr;
+ struct in6_addr mld6_addr; /* multicast address */
+};
+
+#define mld6_type mld6_hdr.icmp6_type
+#define mld6_code mld6_hdr.icmp6_code
+#define mld6_cksum mld6_hdr.icmp6_cksum
+#define mld6_maxdelay mld6_hdr.icmp6_data16[0]
+#define mld6_reserved mld6_hdr.icmp6_data16[1]
+
+/*
+ * Neighbor Discovery
+ */
+
+struct nd_router_solicit { /* router solicitation */
+ struct icmp6_hdr nd_rs_hdr;
+ /* could be followed by options */
+};
+
+#define nd_rs_type nd_rs_hdr.icmp6_type
+#define nd_rs_code nd_rs_hdr.icmp6_code
+#define nd_rs_cksum nd_rs_hdr.icmp6_cksum
+#define nd_rs_reserved nd_rs_hdr.icmp6_data32[0]
+
+struct nd_router_advert { /* router advertisement */
+ struct icmp6_hdr nd_ra_hdr;
+ u_int32_t nd_ra_reachable; /* reachable time */
+ u_int32_t nd_ra_retransmit; /* retransmit timer */
+ /* could be followed by options */
+};
+
+#define nd_ra_type nd_ra_hdr.icmp6_type
+#define nd_ra_code nd_ra_hdr.icmp6_code
+#define nd_ra_cksum nd_ra_hdr.icmp6_cksum
+#define nd_ra_curhoplimit nd_ra_hdr.icmp6_data8[0]
+#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_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 */
+};
+
+#define nd_ns_type nd_ns_hdr.icmp6_type
+#define nd_ns_code nd_ns_hdr.icmp6_code
+#define nd_ns_cksum nd_ns_hdr.icmp6_cksum
+#define nd_ns_reserved nd_ns_hdr.icmp6_data32[0]
+
+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 */
+};
+
+#define nd_na_type nd_na_hdr.icmp6_type
+#define nd_na_code nd_na_hdr.icmp6_code
+#define nd_na_cksum nd_na_hdr.icmp6_cksum
+#define nd_na_flags_reserved nd_na_hdr.icmp6_data32[0]
+#if BYTE_ORDER == BIG_ENDIAN
+#define ND_NA_FLAG_ROUTER 0x80000000
+#define ND_NA_FLAG_SOLICITED 0x40000000
+#define ND_NA_FLAG_OVERRIDE 0x20000000
+#else
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define ND_NA_FLAG_ROUTER 0x80
+#define ND_NA_FLAG_SOLICITED 0x40
+#define ND_NA_FLAG_OVERRIDE 0x20
+#endif
+#endif
+
+struct nd_redirect { /* redirect */
+ struct icmp6_hdr nd_rd_hdr;
+ struct in6_addr nd_rd_target; /* target address */
+ struct in6_addr nd_rd_dst; /* destination address */
+ /* could be followed by options */
+};
+
+#define nd_rd_type nd_rd_hdr.icmp6_type
+#define nd_rd_code nd_rd_hdr.icmp6_code
+#define nd_rd_cksum nd_rd_hdr.icmp6_cksum
+#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0]
+
+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*/
+};
+
+#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
+
+struct nd_opt_prefix_info { /* prefix information */
+ u_int8_t nd_opt_pi_type;
+ u_int8_t nd_opt_pi_len;
+ u_int8_t nd_opt_pi_prefix_len;
+ u_int8_t nd_opt_pi_flags_reserved;
+ u_int32_t nd_opt_pi_valid_time;
+ u_int32_t nd_opt_pi_preferred_time;
+ u_int32_t nd_opt_pi_reserved2;
+ struct in6_addr nd_opt_pi_prefix;
+};
+
+#define ND_OPT_PI_FLAG_ONLINK 0x80
+#define ND_OPT_PI_FLAG_AUTO 0x40
+
+struct nd_opt_rd_hdr { /* redirected header */
+ u_int8_t nd_opt_rh_type;
+ u_int8_t nd_opt_rh_len;
+ u_int16_t nd_opt_rh_reserved1;
+ u_int32_t nd_opt_rh_reserved2;
+ /* followed by IP header and data */
+};
+
+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;
+};
+
+/*
+ * icmp6 namelookup
+ */
+
+struct icmp6_namelookup {
+ struct icmp6_hdr icmp6_nl_hdr;
+ u_int8_t icmp6_nl_nonce[8];
+ int32_t icmp6_nl_ttl;
+#if 0
+ u_int8_t icmp6_nl_len;
+ u_int8_t icmp6_nl_name[3];
+#endif
+ /* could be followed by options */
+};
+
+/*
+ * icmp6 node information
+ */
+struct icmp6_nodeinfo {
+ struct icmp6_hdr icmp6_ni_hdr;
+ u_int8_t icmp6_ni_nonce[8];
+ /* could be followed by reply data */
+};
+
+#define ni_type icmp6_ni_hdr.icmp6_type
+#define ni_code icmp6_ni_hdr.icmp6_code
+#define ni_cksum icmp6_ni_hdr.icmp6_cksum
+#define ni_qtype icmp6_ni_hdr.icmp6_data16[0]
+#define ni_flags icmp6_ni_hdr.icmp6_data16[1]
+
+#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... */
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define NI_SUPTYPE_FLAG_COMPRESS 0x1
+#define NI_FQDN_FLAG_VALIDTTL 0x1
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define NI_SUPTYPE_FLAG_COMPRESS 0x0100
+#define NI_FQDN_FLAG_VALIDTTL 0x0100
+#endif
+
+#ifdef NAME_LOOKUPS_04
+#if BYTE_ORDER == BIG_ENDIAN
+#define NI_NODEADDR_FLAG_LINKLOCAL 0x1
+#define NI_NODEADDR_FLAG_SITELOCAL 0x2
+#define NI_NODEADDR_FLAG_GLOBAL 0x4
+#define NI_NODEADDR_FLAG_ALL 0x8
+#define NI_NODEADDR_FLAG_TRUNCATE 0x10
+#define NI_NODEADDR_FLAG_ANYCAST 0x20 /* just experimental. not in spec */
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define NI_NODEADDR_FLAG_LINKLOCAL 0x0100
+#define NI_NODEADDR_FLAG_SITELOCAL 0x0200
+#define NI_NODEADDR_FLAG_GLOBAL 0x0400
+#define NI_NODEADDR_FLAG_ALL 0x0800
+#define NI_NODEADDR_FLAG_TRUNCATE 0x1000
+#define NI_NODEADDR_FLAG_ANYCAST 0x2000 /* just experimental. not in spec */
+#endif
+#else /* draft-ietf-ipngwg-icmp-name-lookups-05 (and later?) */
+#if BYTE_ORDER == BIG_ENDIAN
+#define NI_NODEADDR_FLAG_TRUNCATE 0x1
+#define NI_NODEADDR_FLAG_ALL 0x2
+#define NI_NODEADDR_FLAG_COMPAT 0x4
+#define NI_NODEADDR_FLAG_LINKLOCAL 0x8
+#define NI_NODEADDR_FLAG_SITELOCAL 0x10
+#define NI_NODEADDR_FLAG_GLOBAL 0x20
+#define NI_NODEADDR_FLAG_ANYCAST 0x40 /* just experimental. not in spec */
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define NI_NODEADDR_FLAG_TRUNCATE 0x0100
+#define NI_NODEADDR_FLAG_ALL 0x0200
+#define NI_NODEADDR_FLAG_COMPAT 0x0400
+#define NI_NODEADDR_FLAG_LINKLOCAL 0x0800
+#define NI_NODEADDR_FLAG_SITELOCAL 0x1000
+#define NI_NODEADDR_FLAG_GLOBAL 0x2000
+#define NI_NODEADDR_FLAG_ANYCAST 0x4000 /* just experimental. not in spec */
+#endif
+#endif
+
+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 */
+};
+
+/*
+ * Router Renumbering. as router-renum-08.txt
+ */
+struct icmp6_router_renum { /* router renumbering header */
+ struct icmp6_hdr rr_hdr;
+ u_int8_t rr_segnum;
+ 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
+
+#define rr_type rr_hdr.icmp6_type
+#define rr_code rr_hdr.icmp6_code
+#define rr_cksum rr_hdr.icmp6_cksum
+#define rr_seqnum rr_hdr.icmp6_data32[0]
+
+struct rr_pco_match { /* match prefix part */
+ u_int8_t rpm_code;
+ u_int8_t rpm_len;
+ u_int8_t rpm_ordinal;
+ u_int8_t rpm_matchlen;
+ u_int8_t rpm_minlen;
+ u_int8_t rpm_maxlen;
+ u_int16_t rpm_reserved;
+ struct in6_addr rpm_prefix;
+};
+
+#define RPM_PCO_ADD 1
+#define RPM_PCO_CHANGE 2
+#define RPM_PCO_SETGLOBAL 3
+#define RPM_PCO_MAX 4
+
+struct rr_pco_use { /* use prefix part */
+ u_int8_t rpu_uselen;
+ u_int8_t rpu_keeplen;
+ u_int8_t rpu_ramask;
+ u_int8_t rpu_raflags;
+ u_int32_t rpu_vltime;
+ u_int32_t rpu_pltime;
+ u_int32_t rpu_flags;
+ struct in6_addr rpu_prefix;
+};
+#define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x80
+#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x40
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80000000
+#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40000000
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80
+#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40
+#endif
+
+struct rr_result { /* router renumbering result message */
+ u_int16_t rrr_flags;
+ u_int8_t rrr_ordinal;
+ u_int8_t rrr_matchedlen;
+ u_int32_t rrr_ifid;
+ struct in6_addr rrr_prefix;
+};
+#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
+#endif
+
+/*
+ * icmp6 filter structures.
+ */
+
+struct icmp6_filter {
+ u_int32_t icmp6_filt[8];
+};
+
+#ifdef _KERNEL
+#define ICMP6_FILTER_SETPASSALL(filterp) \
+do { \
+ int i; u_char *p; \
+ p = (u_char *)filterp; \
+ for (i = 0; i < sizeof(struct icmp6_filter); i++) \
+ p[i] = 0xff; \
+} while (0)
+#define ICMP6_FILTER_SETBLOCKALL(filterp) \
+ bzero(filterp, sizeof(struct icmp6_filter))
+#else /* _KERNEL */
+#define ICMP6_FILTER_SETPASSALL(filterp) \
+ memset(filterp, 0xff, sizeof(struct icmp6_filter))
+#define ICMP6_FILTER_SETBLOCKALL(filterp) \
+ memset(filterp, 0x00, sizeof(struct icmp6_filter))
+#endif /* _KERNEL */
+
+#define ICMP6_FILTER_SETPASS(type, filterp) \
+ (((filterp)->icmp6_filt[(type) >> 5]) |= (1 << ((type) & 31)))
+#define ICMP6_FILTER_SETBLOCK(type, filterp) \
+ (((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type) & 31)))
+#define ICMP6_FILTER_WILLPASS(type, filterp) \
+ ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) != 0)
+#define ICMP6_FILTER_WILLBLOCK(type, filterp) \
+ ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0)
+
+/*
+ * Variables related to this implementation
+ * of the internet control message protocol version 6.
+ */
+struct icmp6errstat {
+ u_quad_t icp6errs_dst_unreach_noroute;
+ u_quad_t icp6errs_dst_unreach_admin;
+ u_quad_t icp6errs_dst_unreach_beyondscope;
+ u_quad_t icp6errs_dst_unreach_addr;
+ u_quad_t icp6errs_dst_unreach_noport;
+ u_quad_t icp6errs_packet_too_big;
+ u_quad_t icp6errs_time_exceed_transit;
+ u_quad_t icp6errs_time_exceed_reassembly;
+ u_quad_t icp6errs_paramprob_header;
+ u_quad_t icp6errs_paramprob_nextheader;
+ u_quad_t icp6errs_paramprob_option;
+ u_quad_t icp6errs_redirect; /* we regard redirect as an error here */
+ u_quad_t icp6errs_unknown;
+};
+
+struct icmp6stat {
+/* statistics related to icmp6 packets generated */
+ u_quad_t icp6s_error; /* # of calls to icmp6_error */
+ u_quad_t icp6s_canterror; /* no error 'cuz old was icmp */
+ u_quad_t icp6s_toofreq; /* no error 'cuz rate limitation */
+ u_quad_t icp6s_outhist[256];
+/* statistics related to input message processed */
+ u_quad_t icp6s_badcode; /* icmp6_code out of range */
+ u_quad_t icp6s_tooshort; /* packet < sizeof(struct icmp6_hdr) */
+ u_quad_t icp6s_checksum; /* bad checksum */
+ u_quad_t icp6s_badlen; /* calculated bound mismatch */
+ u_quad_t icp6s_reflect; /* number of responses */
+ u_quad_t icp6s_inhist[256];
+ u_quad_t icp6s_nd_toomanyopt; /* too many ND options */
+ struct icmp6errstat icp6s_outerrhist;
+#define icp6s_odst_unreach_noroute \
+ icp6s_outerrhist.icp6errs_dst_unreach_noroute
+#define icp6s_odst_unreach_admin icp6s_outerrhist.icp6errs_dst_unreach_admin
+#define icp6s_odst_unreach_beyondscope \
+ icp6s_outerrhist.icp6errs_dst_unreach_beyondscope
+#define icp6s_odst_unreach_addr icp6s_outerrhist.icp6errs_dst_unreach_addr
+#define icp6s_odst_unreach_noport icp6s_outerrhist.icp6errs_dst_unreach_noport
+#define icp6s_opacket_too_big icp6s_outerrhist.icp6errs_packet_too_big
+#define icp6s_otime_exceed_transit \
+ icp6s_outerrhist.icp6errs_time_exceed_transit
+#define icp6s_otime_exceed_reassembly \
+ icp6s_outerrhist.icp6errs_time_exceed_reassembly
+#define icp6s_oparamprob_header icp6s_outerrhist.icp6errs_paramprob_header
+#define icp6s_oparamprob_nextheader \
+ icp6s_outerrhist.icp6errs_paramprob_nextheader
+#define icp6s_oparamprob_option icp6s_outerrhist.icp6errs_paramprob_option
+#define icp6s_oredirect icp6s_outerrhist.icp6errs_redirect
+#define icp6s_ounknown icp6s_outerrhist.icp6errs_unknown
+};
+
+/*
+ * Names for ICMP sysctl objects
+ */
+#define ICMPV6CTL_STATS 1
+#define ICMPV6CTL_REDIRACCEPT 2 /* accept/process redirects */
+#define ICMPV6CTL_REDIRTIMEOUT 3 /* redirect cache time */
+#define ICMPV6CTL_ERRRATELIMIT 5 /* ICMPv6 error rate limitation */
+#define ICMPV6CTL_ND6_PRUNE 6
+#define ICMPV6CTL_ND6_DELAY 8
+#define ICMPV6CTL_ND6_UMAXTRIES 9
+#define ICMPV6CTL_ND6_MMAXTRIES 10
+#define ICMPV6CTL_ND6_USELOOPBACK 11
+/*#define ICMPV6CTL_ND6_PROXYALL 12 obsoleted, do not reuse here */
+#define ICMPV6CTL_NODEINFO 13
+#define ICMPV6CTL_ERRPPSLIMIT 14 /* ICMPv6 error pps limitation */
+#define ICMPV6CTL_ND6_MAXNUDHINT 15
+#define ICMPV6CTL_MAXID 16
+
+#define ICMPV6CTL_NAMES { \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { "rediraccept", CTLTYPE_INT }, \
+ { "redirtimeout", CTLTYPE_INT }, \
+ { 0, 0 }, \
+ { "errratelimit", CTLTYPE_INT }, \
+ { "nd6_prune", CTLTYPE_INT }, \
+ { 0, 0 }, \
+ { "nd6_delay", CTLTYPE_INT }, \
+ { "nd6_umaxtries", CTLTYPE_INT }, \
+ { "nd6_mmaxtries", CTLTYPE_INT }, \
+ { "nd6_useloopback", CTLTYPE_INT }, \
+ { 0, 0 }, \
+ { "nodeinfo", CTLTYPE_INT }, \
+ { "errppslimit", CTLTYPE_INT }, \
+ { "nd6_maxnudhint", CTLTYPE_INT }, \
+}
+
+#define RTF_PROBEMTU RTF_PROTO1
+
+#ifdef _KERNEL
+# ifdef __STDC__
+struct rtentry;
+struct rttimer;
+struct in6_multi;
+# endif
+void icmp6_init __P((void));
+void icmp6_paramerror __P((struct mbuf *, int));
+void icmp6_error __P((struct mbuf *, int, int, int));
+int icmp6_input __P((struct mbuf **, int *, int));
+void icmp6_fasttimo __P((void));
+void icmp6_reflect __P((struct mbuf *, size_t));
+void icmp6_prepare __P((struct mbuf *));
+void icmp6_redirect_input __P((struct mbuf *, int));
+void icmp6_redirect_output __P((struct mbuf *, struct rtentry *));
+
+/* XXX: is this the right place for these macros? */
+#define icmp6_ifstat_inc(ifp, tag) \
+do { \
+ if ((ifp) && (ifp)->if_index <= if_index \
+ && (ifp)->if_index < icmp6_ifstatmax \
+ && icmp6_ifstat && icmp6_ifstat[(ifp)->if_index]) { \
+ icmp6_ifstat[(ifp)->if_index]->tag++; \
+ } \
+} while (0)
+
+#define icmp6_ifoutstat_inc(ifp, type, code) \
+do { \
+ icmp6_ifstat_inc(ifp, ifs6_out_msg); \
+ if (type < ICMP6_INFOMSG_MASK) \
+ icmp6_ifstat_inc(ifp, ifs6_out_error); \
+ switch(type) { \
+ case ICMP6_DST_UNREACH: \
+ icmp6_ifstat_inc(ifp, ifs6_out_dstunreach); \
+ if (code == ICMP6_DST_UNREACH_ADMIN) \
+ icmp6_ifstat_inc(ifp, ifs6_out_adminprohib); \
+ break; \
+ case ICMP6_PACKET_TOO_BIG: \
+ icmp6_ifstat_inc(ifp, ifs6_out_pkttoobig); \
+ break; \
+ case ICMP6_TIME_EXCEEDED: \
+ icmp6_ifstat_inc(ifp, ifs6_out_timeexceed); \
+ break; \
+ case ICMP6_PARAM_PROB: \
+ icmp6_ifstat_inc(ifp, ifs6_out_paramprob); \
+ break; \
+ case ICMP6_ECHO_REQUEST: \
+ icmp6_ifstat_inc(ifp, ifs6_out_echo); \
+ break; \
+ case ICMP6_ECHO_REPLY: \
+ icmp6_ifstat_inc(ifp, ifs6_out_echoreply); \
+ break; \
+ case MLD6_LISTENER_QUERY: \
+ icmp6_ifstat_inc(ifp, ifs6_out_mldquery); \
+ break; \
+ case MLD6_LISTENER_REPORT: \
+ icmp6_ifstat_inc(ifp, ifs6_out_mldreport); \
+ break; \
+ case MLD6_LISTENER_DONE: \
+ icmp6_ifstat_inc(ifp, ifs6_out_mlddone); \
+ break; \
+ case ND_ROUTER_SOLICIT: \
+ icmp6_ifstat_inc(ifp, ifs6_out_routersolicit); \
+ break; \
+ case ND_ROUTER_ADVERT: \
+ icmp6_ifstat_inc(ifp, ifs6_out_routeradvert); \
+ break; \
+ case ND_NEIGHBOR_SOLICIT: \
+ icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit); \
+ break; \
+ case ND_NEIGHBOR_ADVERT: \
+ icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert); \
+ break; \
+ case ND_REDIRECT: \
+ icmp6_ifstat_inc(ifp, ifs6_out_redirect); \
+ break; \
+ } \
+} while (0)
-#define __KAME_NETINET_ICMP6_H_INCLUDED_
-#include <netinet6/icmp6.h>
-#undef __KAME_NETINET_ICMP6_H_INCLUDED_
+extern int icmp6_rediraccept; /* accept/process redirects */
+extern int icmp6_redirtimeout; /* cache time for redirect routes */
+#endif /* _KERNEL */
-#endif /* !_NETINET_ICMP6_H_ */
+#endif /* not _NETINET_ICMP6_H_ */
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index 1cb01703a1b4..f1bc7f75c59b 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -207,6 +207,7 @@ in_control(so, cmd, data, ifp, p)
if (ifp && ifp->if_type == IFT_GIF) {
switch (cmd) {
case SIOCSIFPHYADDR:
+ case SIOCDIFPHYADDR:
if (p &&
(error = suser(p)) != 0)
return(error);
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index dbff92a1d42c..403c534e8333 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -372,7 +372,7 @@ struct ip_mreq {
* Third level is protocol number.
* Fourth level is desired variable within that protocol.
*/
-#define IPPROTO_MAXID (IPPROTO_ESP + 1) /* don't list to IPPROTO_MAX */
+#define IPPROTO_MAXID (IPPROTO_AH + 1) /* don't list to IPPROTO_MAX */
#define CTL_IPPROTO_NAMES { \
{ "ip", CTLTYPE_NODE }, \
@@ -398,6 +398,35 @@ struct ip_mreq {
{ 0, 0 }, \
{ 0, 0 }, \
{ "idp", CTLTYPE_NODE }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { "ipsec", CTLTYPE_NODE }, \
}
/*
diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c
index 0efa40e07ac8..2335873bbb38 100644
--- a/sys/netinet/in_gif.c
+++ b/sys/netinet/in_gif.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in_gif.c,v 1.43 2000/06/20 19:45:00 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,15 +28,10 @@
* 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.
- *
- * $FreeBSD$
- */
-
-/*
- * in_gif.c
*/
#include "opt_mrouting.h"
+#include "opt_inet.h"
#include "opt_inet6.h"
#include <sys/param.h>
@@ -44,7 +42,8 @@
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
-#include <sys/protosw.h>
+
+#include <sys/malloc.h>
#include <net/if.h>
#include <net/route.h>
@@ -52,21 +51,21 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
-#ifdef INET6
-#include <netinet/ip6.h>
-#endif
#include <netinet/ip_var.h>
#include <netinet/in_gif.h>
+#include <netinet/in_var.h>
+#include <netinet/ip_encap.h>
#include <netinet/ip_ecn.h>
+
#ifdef INET6
-#include <netinet6/ip6_ecn.h>
+#include <netinet/ip6.h>
#endif
#ifdef MROUTING
#include <netinet/ip_mroute.h>
#endif /* MROUTING */
-#include <net/if_gif.h>
+#include <net/if_gif.h>
#include "gif.h"
@@ -79,13 +78,12 @@ int ip_gif_ttl = GIF_TTL;
#else
int ip_gif_ttl = 0;
#endif
-
-SYSCTL_DECL(_net_inet_ip);
SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
&ip_gif_ttl, 0, "");
-#define IN6_IS_ADDR_6TO4(x) (ntohs((x)->s6_addr16[0]) == 0x2002)
-#define GET_V4(x) ((struct in_addr *)(&(x)->s6_addr16[1]))
+#ifndef offsetof
+#define offsetof(s, e) ((int)&((s *)0)->e)
+#endif
int
in_gif_output(ifp, family, m, rt)
@@ -101,9 +99,6 @@ in_gif_output(ifp, family, m, rt)
struct ip iphdr; /* capsule IP header, host byte ordered */
int proto, error;
u_int8_t tos;
-#ifdef INET6
- struct ip6_hdr *ip6 = NULL;
-#endif
if (sin_src == NULL || sin_dst == NULL ||
sin_src->sin_family != AF_INET ||
@@ -113,6 +108,7 @@ in_gif_output(ifp, family, m, rt)
}
switch (family) {
+#ifdef INET
case AF_INET:
{
struct ip *ip;
@@ -127,9 +123,11 @@ in_gif_output(ifp, family, m, rt)
tos = ip->ip_tos;
break;
}
+#endif /*INET*/
#ifdef INET6
case AF_INET6:
{
+ struct ip6_hdr *ip6;
proto = IPPROTO_IPV6;
if (m->m_len < sizeof(*ip6)) {
m = m_pullup(m, sizeof(*ip6));
@@ -142,7 +140,7 @@ in_gif_output(ifp, family, m, rt)
}
#endif /*INET6*/
default:
-#ifdef DIAGNOSTIC
+#ifdef DEBUG
printf("in_gif_output: warning: unknown family %d passed\n",
family);
#endif
@@ -152,37 +150,15 @@ in_gif_output(ifp, family, m, rt)
bzero(&iphdr, sizeof(iphdr));
iphdr.ip_src = sin_src->sin_addr;
-#ifdef INET6
- /* XXX: temporal stf support hack */
- if (bcmp(ifp->if_name, "stf", 3) == 0) {
- if (ip6 == NULL) {
- m_freem(m);
- return ENETUNREACH;
- }
- if (IN6_IS_ADDR_6TO4(&ip6->ip6_dst))
- iphdr.ip_dst = *GET_V4(&ip6->ip6_dst);
- else if (rt && rt->rt_gateway->sa_family == AF_INET6) {
- struct in6_addr *dst6;
-
- dst6 = &((struct sockaddr_in6 *)
- (rt->rt_gateway))->sin6_addr;
- if (IN6_IS_ADDR_6TO4(dst6))
- iphdr.ip_dst = *GET_V4(dst6);
- else {
- m_freem(m);
- return ENETUNREACH;
- }
- } else {
- m_freem(m);
- return ENETUNREACH;
- }
- } else
-#endif
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 {
@@ -213,8 +189,7 @@ in_gif_output(ifp, family, m, rt)
printf("ENOBUFS in in_gif_output %d\n", __LINE__);
return ENOBUFS;
}
-
- *(mtod(m, struct ip *)) = iphdr;
+ bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip));
if (dst->sin_family != sin_dst->sin_family ||
dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) {
@@ -226,6 +201,9 @@ in_gif_output(ifp, family, m, rt)
RTFREE(sc->gif_ro.ro_rt);
sc->gif_ro.ro_rt = NULL;
}
+#if 0
+ sc->gif_if.if_mtu = GIF_MTU;
+#endif
}
if (sc->gif_ro.ro_rt == NULL) {
@@ -234,73 +212,48 @@ in_gif_output(ifp, family, m, rt)
m_freem(m);
return ENETUNREACH;
}
+
+ /* if it constitutes infinite encapsulation, punt. */
+ if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
+ m_freem(m);
+ return ENETUNREACH; /*XXX*/
+ }
+#if 0
+ ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu
+ - sizeof(struct ip);
+#endif
}
- error = ip_output(m, 0, &sc->gif_ro, 0, 0);
+ error = ip_output(m, NULL, &sc->gif_ro, 0, NULL);
return(error);
}
void
-in_gif_input(struct mbuf *m, int off, int proto)
+#if __STDC__
+in_gif_input(struct mbuf *m, ...)
+#else
+in_gif_input(m, va_alist)
+ struct mbuf *m;
+ va_dcl
+#endif
{
- struct gif_softc *sc;
+ int off, proto;
struct ifnet *gifp = NULL;
struct ip *ip;
- int i, af;
+ va_list ap;
+ int af;
u_int8_t otos;
- ip = mtod(m, struct ip *);
-
- /* this code will be soon improved. */
-#define satosin(sa) ((struct sockaddr_in *)(sa))
- for (i = 0, sc = gif; i < ngif; i++, sc++) {
- if (sc->gif_psrc == NULL
- || sc->gif_pdst == NULL
- || sc->gif_psrc->sa_family != AF_INET
- || sc->gif_pdst->sa_family != AF_INET) {
- continue;
- }
-
- if ((sc->gif_if.if_flags & IFF_UP) == 0)
- continue;
-
-#ifdef INET6
- /* XXX: temporal stf support hack */
- if (proto == IPPROTO_IPV6 &&
- bcmp(sc->gif_if.if_name, "stf", 3) == 0 &&
- (satosin(sc->gif_psrc)->sin_addr.s_addr ==
- ip->ip_dst.s_addr ||
- IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) &&
- satosin(sc->gif_pdst)->sin_addr.s_addr ==
- INADDR_BROADCAST) {
- gifp = &sc->gif_if;
- break;
- }
-#endif
+ va_start(ap, m);
+ off = va_arg(ap, int);
+ proto = va_arg(ap, int);
+ va_end(ap);
- if ((sc->gif_if.if_flags & IFF_LINK0)
- && satosin(sc->gif_psrc)->sin_addr.s_addr == ip->ip_dst.s_addr
- && satosin(sc->gif_pdst)->sin_addr.s_addr == INADDR_ANY) {
- gifp = &sc->gif_if;
- continue;
- }
+ ip = mtod(m, struct ip *);
- if (satosin(sc->gif_psrc)->sin_addr.s_addr == ip->ip_dst.s_addr
- && satosin(sc->gif_pdst)->sin_addr.s_addr == ip->ip_src.s_addr)
- {
- gifp = &sc->gif_if;
- break;
- }
- }
+ gifp = (struct ifnet *)encap_getarg(m);
- if (gifp == NULL) {
-#ifdef MROUTING
- /* for backward compatibility */
- if (proto == IPPROTO_IPV4) {
- ipip_input(m, off, proto);
- return;
- }
-#endif /*MROUTING*/
+ if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
m_freem(m);
ipstat.ips_nogif++;
return;
@@ -310,16 +263,10 @@ in_gif_input(struct mbuf *m, int off, int proto)
m_adj(m, off);
switch (proto) {
+#ifdef INET
case IPPROTO_IPV4:
{
struct ip *ip;
-
-#ifdef INET6
- if (bcmp(gifp->if_name, "stf", 3) == 0) {
- m_freem(m);
- return;
- }
-#endif
af = AF_INET;
if (m->m_len < sizeof(*ip)) {
m = m_pullup(m, sizeof(*ip));
@@ -331,6 +278,7 @@ in_gif_input(struct mbuf *m, int off, int proto)
ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos);
break;
}
+#endif
#ifdef INET6
case IPPROTO_IPV6:
{
@@ -359,3 +307,81 @@ in_gif_input(struct mbuf *m, int off, int proto)
gif_input(m, af, gifp);
return;
}
+
+/*
+ * we know that we are in IFF_UP, outer address available, and outer family
+ * matched the physical addr family. see gif_encapcheck().
+ */
+int
+gif_encapcheck4(m, off, proto, arg)
+ const struct mbuf *m;
+ int off;
+ int proto;
+ void *arg;
+{
+ struct ip ip;
+ struct gif_softc *sc;
+ struct sockaddr_in *src, *dst;
+ int addrmatch;
+ struct in_ifaddr *ia4;
+
+ /* sanity check done in caller */
+ sc = (struct gif_softc *)arg;
+ src = (struct sockaddr_in *)sc->gif_psrc;
+ dst = (struct sockaddr_in *)sc->gif_pdst;
+
+ /* LINTED const cast */
+ m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
+
+ /* check for address match */
+ addrmatch = 0;
+ if (src->sin_addr.s_addr == ip.ip_dst.s_addr)
+ 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;
+
+ /* martian filters on outer source - NOT done in ip_input! */
+ if (IN_MULTICAST(ip.ip_src.s_addr))
+ return 0;
+ switch ((ntohl(ip.ip_src.s_addr) & 0xff000000) >> 24) {
+ case 0: case 127: case 255:
+ return 0;
+ }
+ /* reject packets with broadcast on source */
+ for (ia4 = TAILQ_FIRST(&in_ifaddrhead); ia4;
+ ia4 = TAILQ_NEXT(ia4, ia_link))
+ {
+ if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
+ continue;
+ if (ip.ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr)
+ return 0;
+ }
+
+ /* ingress filters on outer source */
+ if ((m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) {
+ struct sockaddr_in sin;
+ struct rtentry *rt;
+
+ bzero(&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ 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);
+ return 0;
+ }
+ rtfree(rt);
+ }
+
+ /* prioritize: IFF_LINK0 mode is less preferred */
+ return (sc->gif_if.if_flags & IFF_LINK0) ? 32 : 32 * 2;
+}
diff --git a/sys/netinet/in_gif.h b/sys/netinet/in_gif.h
index 39d1aba7504b..de03c6ee6842 100644
--- a/sys/netinet/in_gif.h
+++ b/sys/netinet/in_gif.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in_gif.h,v 1.5 2000/04/14 08:36:02 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,23 +28,17 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _NETINET_IN_GIF_H_
-#define _NETINET_IN_GIF_H_
+#define _NETINET_IN_GIF_H_
-#define GIF_TTL 30
+#define GIF_TTL 30
extern int ip_gif_ttl;
-struct mbuf;
-struct ifnet;
-struct rtentry;
-
-void in_gif_input __P((struct mbuf *, int off, int proto));
-int in_gif_output __P((struct ifnet *, int, struct mbuf *,
- struct rtentry *));
+void in_gif_input __P((struct mbuf *, ...));
+int in_gif_output __P((struct ifnet *, int, struct mbuf *, struct rtentry *));
+int gif_encapcheck4 __P((const struct mbuf *, int, int, void *));
#endif /*_NETINET_IN_GIF_H_*/
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 2ed3aa06b202..b8b8278486ec 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -72,7 +72,6 @@
#ifdef IPSEC
#include <netinet6/ipsec.h>
#include <netkey/key.h>
-#include <netkey/key_debug.h>
#endif /* IPSEC */
struct in_addr zeroin_addr;
@@ -534,8 +533,7 @@ in_pcbdetach(inp)
struct inpcbinfo *ipi = inp->inp_pcbinfo;
#ifdef IPSEC
- if (inp->inp_sp != NULL)
- ipsec4_delete_pcbpolicy(inp);
+ ipsec4_delete_pcbpolicy(inp);
#endif /*IPSEC*/
inp->inp_gencnt = ++ipi->ipi_gencnt;
in_pcbremlists(inp);
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index 2fdfddf7a697..f863b4f6b8f4 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -61,6 +61,7 @@
#include <netinet/tcp_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
+#include <netinet/ip_encap.h>
#include <netinet/ipprotosw.h>
@@ -81,6 +82,11 @@
#include <netinet/in_gif.h>
#endif
+#include "stf.h"
+#if NSTF > 0
+#include <net/if_stf.h>
+#endif
+
#ifdef IPXIP
#include <netipx/ipx_ip.h>
#endif
@@ -153,29 +159,20 @@ struct ipprotosw inetsw[] = {
},
#endif
#endif /* IPSEC */
-#if NGIF > 0
{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR,
- in_gif_input, 0, 0, 0,
+ encap4_input, 0, 0, rip_ctloutput,
0,
- 0, 0, 0, 0,
+ encap_init, 0, 0, 0,
&nousrreqs
},
# ifdef INET6
{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR,
- in_gif_input, 0, 0, 0,
+ encap4_input, 0, 0, rip_ctloutput,
0,
0, 0, 0, 0,
&nousrreqs
},
#endif
-#else /*NGIF*/
-{ SOCK_RAW, &inetdomain, IPPROTO_IPIP, PR_ATOMIC|PR_ADDR,
- ipip_input, 0, 0, rip_ctloutput,
- 0,
- 0, 0, 0, 0,
- &rip_usrreqs
-},
-#endif /*NGIF*/
#ifdef IPDIVERT
{ SOCK_RAW, &inetdomain, IPPROTO_DIVERT, PR_ATOMIC|PR_ADDR,
div_input, 0, 0, ip_ctloutput,
@@ -209,6 +206,26 @@ struct ipprotosw inetsw[] = {
},
};
+#if NGIF > 0
+struct ipprotosw in_gif_protosw =
+{ SOCK_RAW, &inetdomain, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR,
+ in_gif_input, rip_output, 0, rip_ctloutput,
+ 0,
+ 0, 0, 0, 0,
+ &rip_usrreqs
+};
+#endif /*NGIF*/
+
+#if NSTF > 0
+struct ipprotosw in_stf_protosw =
+{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR,
+ in_stf_input, rip_output, 0, rip_ctloutput,
+ 0,
+ 0, 0, 0, 0,
+ &rip_usrreqs
+};
+#endif /*NSTF*/
+
extern int in_inithead __P((void **, int));
struct domain inetdomain =
diff --git a/sys/netinet/ip6.h b/sys/netinet/ip6.h
index 2c0297fd7100..c194043d2d5c 100644
--- a/sys/netinet/ip6.h
+++ b/sys/netinet/ip6.h
@@ -1,5 +1,8 @@
+/* $FreeBSD$ */
+/* $KAME: ip6.h,v 1.9 2000/07/02 21:01:32 itojun Exp $ */
+
/*
- * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,10 +28,277 @@
* 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.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)ip.h 8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_IP6_H_
+#define _NETINET_IP6_H_
+
+/*
+ * Definition for internet protocol version 6.
+ * RFC 2460
+ */
+
+struct ip6_hdr {
+ union {
+ struct ip6_hdrctl {
+ u_int32_t ip6_un1_flow; /* 20 bits of flow-ID */
+ u_int16_t ip6_un1_plen; /* payload length */
+ u_int8_t ip6_un1_nxt; /* next header */
+ u_int8_t ip6_un1_hlim; /* hop limit */
+ } ip6_un1;
+ u_int8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */
+ } ip6_ctlun;
+ struct in6_addr ip6_src; /* source address */
+ struct in6_addr ip6_dst; /* destination address */
+};
+
+#define ip6_vfc ip6_ctlun.ip6_un2_vfc
+#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
+#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
+#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
+#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
+#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
+
+#define IPV6_VERSION 0x60
+#define IPV6_VERSION_MASK 0xf0
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define IPV6_FLOWINFO_MASK 0x0fffffff /* flow info (28 bits) */
+#define IPV6_FLOWLABEL_MASK 0x000fffff /* flow label (20 bits) */
+#else
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define IPV6_FLOWINFO_MASK 0xffffff0f /* flow info (28 bits) */
+#define IPV6_FLOWLABEL_MASK 0xffff0f00 /* flow label (20 bits) */
+#endif /* LITTLE_ENDIAN */
+#endif
+/* ECN bits proposed by Sally Floyd */
+#define IP6TOS_CE 0x01 /* congestion experienced */
+#define IP6TOS_ECT 0x02 /* ECN-capable transport */
+
+/*
+ * Extension Headers
+ */
+
+struct ip6_ext {
+ u_char ip6e_nxt;
+ u_char ip6e_len;
+};
+
+/* Hop-by-Hop options header */
+/* XXX should we pad it to force alignment on an 8-byte boundary? */
+struct ip6_hbh {
+ u_int8_t ip6h_nxt; /* next header */
+ u_int8_t ip6h_len; /* length in units of 8 octets */
+ /* followed by options */
+};
+
+/* Destination options header */
+/* XXX should we pad it to force alignment on an 8-byte boundary? */
+struct ip6_dest {
+ u_int8_t ip6d_nxt; /* next header */
+ u_int8_t ip6d_len; /* length in units of 8 octets */
+ /* followed by options */
+};
+
+/* 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_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_TYPE(o) ((o) & 0xC0)
+#define IP6OPT_TYPE_SKIP 0x00
+#define IP6OPT_TYPE_DISCARD 0x40
+#define IP6OPT_TYPE_FORCEICMP 0x80
+#define IP6OPT_TYPE_ICMP 0xC0
+
+#define IP6OPT_MUTABLE 0x20
+
+/* Routing header */
+struct ip6_rthdr {
+ u_int8_t ip6r_nxt; /* next header */
+ u_int8_t ip6r_len; /* length in units of 8 octets */
+ u_int8_t ip6r_type; /* routing type */
+ u_int8_t ip6r_segleft; /* segments left */
+ /* followed by routing type specific data */
+};
+
+/* Type 0 Routing header */
+struct ip6_rthdr0 {
+ u_int8_t ip6r0_nxt; /* next header */
+ u_int8_t ip6r0_len; /* length in units of 8 octets */
+ u_int8_t ip6r0_type; /* always zero */
+ u_int8_t ip6r0_segleft; /* segments left */
+ 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 */
+};
+
+/* Fragment header */
+struct ip6_frag {
+ u_int8_t ip6f_nxt; /* next header */
+ u_int8_t ip6f_reserved; /* reserved field */
+ u_int16_t ip6f_offlg; /* offset, reserved, and flag */
+ u_int32_t ip6f_ident; /* identification */
+};
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */
+#define IP6F_RESERVED_MASK 0x0006 /* reserved bits in ip6f_offlg */
+#define IP6F_MORE_FRAG 0x0001 /* more-fragments flag */
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+#define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */
+#define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */
+#define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+/*
+ * Internet implementation parameters.
+ */
+#define IPV6_MAXHLIM 255 /* maximun hoplimit */
+#define IPV6_DEFHLIM 64 /* default hlim */
+#define IPV6_FRAGTTL 120 /* ttl for fragment packets, in slowtimo tick */
+#define IPV6_HLIMDEC 1 /* subtracted when forwaeding */
+
+#define IPV6_MMTU 1280 /* minimal MTU and reassembly. 1024 + 256 */
+#define IPV6_MAXPACKET 65535 /* ip6 max packet size without Jumbo payload*/
+
+#ifdef _KERNEL
+/*
+ * IP6_EXTHDR_CHECK ensures that region between the IP6 header and the
+ * target header (including IPv6 itself, extension headers and
+ * TCP/UDP/ICMP6 headers) are continuous. KAME requires drivers
+ * to store incoming data into one internal mbuf or one or more external
+ * mbufs(never into two or more internal mbufs). Thus, the third case is
+ * supposed to never be matched but is prepared just in case.
+ */
+
+#ifdef INET6
+#define IP6_EXTHDR_STAT(x) x
+#else
+#define IP6_EXTHDR_STAT(x)
+#endif
+
+#define IP6_EXTHDR_CHECK(m, off, hlen, ret) \
+do { \
+ if ((m)->m_next != NULL) { \
+ if (((m)->m_flags & M_LOOP) && \
+ ((m)->m_len < (off) + (hlen)) && \
+ (((m) = m_pullup((m), (off) + (hlen))) == NULL)) { \
+ IP6_EXTHDR_STAT(ip6stat.ip6s_exthdrtoolong++); \
+ return ret; \
+ } else if ((m)->m_flags & M_EXT) { \
+ if ((m)->m_len < (off) + (hlen)) { \
+ IP6_EXTHDR_STAT(ip6stat.ip6s_exthdrtoolong++); \
+ m_freem(m); \
+ return ret; \
+ } \
+ } else { \
+ if ((m)->m_len < (off) + (hlen)) { \
+ IP6_EXTHDR_STAT(ip6stat.ip6s_exthdrtoolong++); \
+ m_freem(m); \
+ return ret; \
+ } \
+ } \
+ } else { \
+ if ((m)->m_len < (off) + (hlen)) { \
+ IP6_EXTHDR_STAT(ip6stat.ip6s_tooshort++); \
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); \
+ m_freem(m); \
+ return ret; \
+ } \
+ } \
+} while (0)
+
+/*
+ * IP6_EXTHDR_GET ensures that intermediate protocol header (from "off" to
+ * "len") is located in single mbuf, on contiguous memory region.
+ * The pointer to the region will be returned to pointer variable "val",
+ * with type "typ".
+ * IP6_EXTHDR_GET0 does the same, except that it aligns the structure at the
+ * very top of mbuf. GET0 is likely to make memory copy than GET.
*
- * $FreeBSD$
+ * XXX we're now testing this, needs m_pulldown()
*/
+#define IP6_EXTHDR_GET(val, typ, m, off, len) \
+do { \
+ struct mbuf *t; \
+ int tmp; \
+ IP6_EXTHDR_STAT(ip6stat.ip6s_exthdrget++); \
+ if ((m)->m_len >= (off) + (len)) \
+ (val) = (typ)(mtod((m), caddr_t) + (off)); \
+ else { \
+ t = m_pulldown((m), (off), (len), &tmp); \
+ if (t) { \
+ if (t->m_len < tmp + (len)) \
+ panic("m_pulldown malfunction"); \
+ (val) = (typ)(mtod(t, caddr_t) + tmp); \
+ } else { \
+ (val) = (typ)NULL; \
+ (m) = NULL; \
+ } \
+ } \
+} while (0)
+
+#define IP6_EXTHDR_GET0(val, typ, m, off, len) \
+do { \
+ struct mbuf *t; \
+ IP6_EXTHDR_STAT(ip6stat.ip6s_exthdrget0++); \
+ if ((off) == 0) \
+ (val) = (typ)mtod(m, caddr_t); \
+ else { \
+ t = m_pulldown((m), (off), (len), NULL); \
+ if (t) { \
+ if (t->m_len < (len)) \
+ panic("m_pulldown malfunction"); \
+ (val) = (typ)mtod(t, caddr_t); \
+ } else { \
+ (val) = (typ)NULL; \
+ (m) = NULL; \
+ } \
+ } \
+} while (0)
+#endif /*_KERNEL*/
-#define __KAME_NETINET_IP6_H_INCLUDED_
-#include <netinet6/ip6.h>
-#undef __KAME_NETINET_IP6_H_INCLUDED_
+#endif /* not _NETINET_IP6_H_ */
diff --git a/sys/netinet/ip_ecn.c b/sys/netinet/ip_ecn.c
index aeb588e05fe3..047f82e1fb52 100644
--- a/sys/netinet/ip_ecn.c
+++ b/sys/netinet/ip_ecn.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip_ecn.c,v 1.7 2000/05/05 11:00:56 sumikawa Exp $ */
+
/*
* Copyright (C) 1999 WIDE Project.
* All rights reserved.
@@ -26,8 +29,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: ip_ecn.c,v 1.2 1999/07/30 12:17:15 itojun Exp $
- * $FreeBSD$
*/
/*
* ECN consideration on tunnel ingress/egress operation.
diff --git a/sys/netinet/ip_ecn.h b/sys/netinet/ip_ecn.h
index 921ce374eb75..6445d0f8fce7 100644
--- a/sys/netinet/ip_ecn.h
+++ b/sys/netinet/ip_ecn.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip_ecn.h,v 1.5 2000/03/27 04:58:38 sumikawa Exp $ */
+
/*
* Copyright (C) 1999 WIDE Project.
* All rights reserved.
@@ -26,17 +29,15 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: ip_ecn.h,v 1.2 1999/08/19 12:57:44 itojun Exp $
- * $FreeBSD$
*/
/*
* ECN consideration on tunnel ingress/egress operation.
* http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt
*/
-#define ECN_ALLOWED 1 /* ECN allowed */
-#define ECN_FORBIDDEN 0 /* ECN forbidden */
-#define ECN_NOCARE (-1) /* no consideration to ECN */
+#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 *));
diff --git a/sys/netinet/ip_encap.c b/sys/netinet/ip_encap.c
new file mode 100644
index 000000000000..de833344f2f4
--- /dev/null
+++ b/sys/netinet/ip_encap.c
@@ -0,0 +1,534 @@
+/* $FreeBSD$ */
+/* $KAME: ip_encap.c,v 1.36 2000/06/17 20:34:24 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.
+ */
+/*
+ * My grandfather said that there's a devil inside tunnelling technology...
+ *
+ * We have surprisingly many protocols that want packets with IP protocol
+ * #4 or #41. Here's a list of protocols that want protocol #41:
+ * RFC1933 configured tunnel
+ * RFC1933 automatic tunnel
+ * RFC2401 IPsec tunnel
+ * RFC2473 IPv6 generic packet tunnelling
+ * RFC2529 6over4 tunnel
+ * mobile-ip6 (uses RFC2473)
+ * 6to4 tunnel
+ * Here's a list of protocol that want protocol #4:
+ * RFC1853 IPv4-in-IPv4 tunnelling
+ * RFC2003 IPv4 encapsulation within IPv4
+ * RFC2344 reverse tunnelling for mobile-ip4
+ * RFC2401 IPsec tunnel
+ * Well, what can I say. They impose different en/decapsulation mechanism
+ * from each other, so they need separate protocol handler. The only one
+ * we can easily determine by protocol # is IPsec, which always has
+ * AH/ESP/IPComp header right after outer IP header.
+ *
+ * So, clearly good old protosw does not work for protocol #4 and #41.
+ * The code will let you match protocol via src/dst address pair.
+ */
+/* XXX is M_NETADDR correct? */
+
+#include "opt_mrouting.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/errno.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_encap.h>
+#ifdef MROUTING
+#include <netinet/ip_mroute.h>
+#endif /* MROUTING */
+#include <netinet/ipprotosw.h>
+
+#ifdef INET6
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/ip6protosw.h>
+#endif
+
+#include <machine/stdarg.h>
+
+#include <net/net_osdep.h>
+
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure");
+
+static void encap_add __P((struct encaptab *));
+static int mask_match __P((const struct encaptab *, const struct sockaddr *,
+ const struct sockaddr *));
+static void encap_fillarg __P((struct mbuf *, const struct encaptab *));
+
+/* rely upon BSS initialization */
+LIST_HEAD(, encaptab) encaptab;
+
+void
+encap_init()
+{
+#if 0
+ /*
+ * we cannot use LIST_INIT() here, since drivers may want to call
+ * encap_attach(), on driver attach. encap_init() will be called
+ * on AF_INET{,6} initialization, which happens after driver
+ * initialization - using LIST_INIT() here can nuke encap_attach()
+ * from drivers.
+ */
+ LIST_INIT(&encaptab);
+#endif
+}
+
+void
+#if __STDC__
+encap4_input(struct mbuf *m, ...)
+#else
+encap4_input(m, va_alist)
+ struct mbuf *m;
+ va_dcl
+#endif
+{
+ int off, proto;
+ struct ip *ip;
+ struct sockaddr_in s, d;
+ const struct ipprotosw *psw;
+ struct encaptab *ep, *match;
+ va_list ap;
+ int prio, matchprio;
+
+ va_start(ap, m);
+ off = va_arg(ap, int);
+ proto = va_arg(ap, int);
+ va_end(ap);
+
+ ip = mtod(m, struct ip *);
+
+ bzero(&s, sizeof(s));
+ s.sin_family = AF_INET;
+ s.sin_len = sizeof(struct sockaddr_in);
+ s.sin_addr = ip->ip_src;
+ bzero(&d, sizeof(d));
+ d.sin_family = AF_INET;
+ d.sin_len = sizeof(struct sockaddr_in);
+ d.sin_addr = ip->ip_dst;
+
+ match = NULL;
+ matchprio = 0;
+ for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
+ if (ep->af != AF_INET)
+ continue;
+ if (ep->proto >= 0 && ep->proto != proto)
+ continue;
+ if (ep->func)
+ prio = (*ep->func)(m, off, proto, ep->arg);
+ else {
+ /*
+ * it's inbound traffic, we need to match in reverse
+ * order
+ */
+ prio = mask_match(ep, (struct sockaddr *)&d,
+ (struct sockaddr *)&s);
+ }
+
+ /*
+ * We prioritize the matches by using bit length of the
+ * matches. mask_match() and user-supplied matching function
+ * should return the bit length of the matches (for example,
+ * if both src/dst are matched for IPv4, 64 should be returned).
+ * 0 or negative return value means "it did not match".
+ *
+ * The question is, since we have two "mask" portion, we
+ * cannot really define total order between entries.
+ * For example, which of these should be preferred?
+ * mask_match() returns 48 (32 + 16) for both of them.
+ * src=3ffe::/16, dst=3ffe:501::/32
+ * src=3ffe:501::/32, dst=3ffe::/16
+ *
+ * We need to loop through all the possible candidates
+ * to get the best match - the search takes O(n) for
+ * n attachments (i.e. interfaces).
+ */
+ if (prio <= 0)
+ continue;
+ if (prio > matchprio) {
+ matchprio = prio;
+ match = ep;
+ }
+ }
+
+ if (match) {
+ /* found a match, "match" has the best one */
+ psw = (const struct ipprotosw *)match->psw;
+ if (psw && psw->pr_input) {
+ encap_fillarg(m, match);
+ (*psw->pr_input)(m, off, proto);
+ } else
+ m_freem(m);
+ return;
+ }
+
+ /* for backward compatibility */
+# ifdef MROUTING
+# define COMPATFUNC ipip_input
+# endif /*MROUTING*/
+
+#ifdef COMPATFUNC
+ if (proto == IPPROTO_IPV4) {
+ COMPATFUNC(m, off, proto);
+ return;
+ }
+#endif
+
+ /* last resort: inject to raw socket */
+ rip_input(m, off, proto);
+}
+
+#ifdef INET6
+int
+encap6_input(mp, offp, proto)
+ struct mbuf **mp;
+ int *offp;
+ int proto;
+{
+ struct mbuf *m = *mp;
+ struct ip6_hdr *ip6;
+ struct sockaddr_in6 s, d;
+ const struct ip6protosw *psw;
+ struct encaptab *ep, *match;
+ int prio, matchprio;
+
+ ip6 = mtod(m, struct ip6_hdr *);
+
+ bzero(&s, sizeof(s));
+ s.sin6_family = AF_INET6;
+ s.sin6_len = sizeof(struct sockaddr_in6);
+ s.sin6_addr = ip6->ip6_src;
+ bzero(&d, sizeof(d));
+ d.sin6_family = AF_INET6;
+ d.sin6_len = sizeof(struct sockaddr_in6);
+ d.sin6_addr = ip6->ip6_dst;
+
+ match = NULL;
+ matchprio = 0;
+ for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
+ if (ep->af != AF_INET6)
+ continue;
+ if (ep->proto >= 0 && ep->proto != proto)
+ continue;
+ if (ep->func)
+ prio = (*ep->func)(m, *offp, proto, ep->arg);
+ else {
+ /*
+ * it's inbound traffic, we need to match in reverse
+ * order
+ */
+ prio = mask_match(ep, (struct sockaddr *)&d,
+ (struct sockaddr *)&s);
+ }
+
+ /* see encap4_input() for issues here */
+ if (prio <= 0)
+ continue;
+ if (prio > matchprio) {
+ matchprio = prio;
+ match = ep;
+ }
+ }
+
+ if (match) {
+ /* found a match */
+ psw = (const struct ip6protosw *)match->psw;
+ if (psw && psw->pr_input) {
+ encap_fillarg(m, match);
+ return (*psw->pr_input)(mp, offp, proto);
+ } else {
+ m_freem(m);
+ return IPPROTO_DONE;
+ }
+ }
+
+ /* last resort: inject to raw socket */
+ return rip6_input(mp, offp, proto);
+}
+#endif
+
+static void
+encap_add(ep)
+ struct encaptab *ep;
+{
+
+ LIST_INSERT_HEAD(&encaptab, ep, chain);
+}
+
+/*
+ * sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
+ * length of mask (sm and dm) is assumed to be same as sp/dp.
+ * Return value will be necessary as input (cookie) for encap_detach().
+ */
+const struct encaptab *
+encap_attach(af, proto, sp, sm, dp, dm, psw, arg)
+ int af;
+ int proto;
+ const struct sockaddr *sp, *sm;
+ const struct sockaddr *dp, *dm;
+ const struct protosw *psw;
+ void *arg;
+{
+ struct encaptab *ep;
+ int error;
+ int s;
+
+ s = splnet();
+ /* sanity check on args */
+ if (sp->sa_len > sizeof(ep->src) || dp->sa_len > sizeof(ep->dst)) {
+ error = EINVAL;
+ goto fail;
+ }
+ if (sp->sa_len != dp->sa_len) {
+ error = EINVAL;
+ goto fail;
+ }
+ if (af != sp->sa_family || af != dp->sa_family) {
+ error = EINVAL;
+ goto fail;
+ }
+
+ /* check if anyone have already attached with exactly same config */
+ for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
+ if (ep->af != af)
+ continue;
+ if (ep->proto != proto)
+ continue;
+ if (ep->src.ss_len != sp->sa_len ||
+ bcmp(&ep->src, sp, sp->sa_len) != 0 ||
+ bcmp(&ep->srcmask, sm, sp->sa_len) != 0)
+ continue;
+ if (ep->dst.ss_len != dp->sa_len ||
+ bcmp(&ep->dst, dp, dp->sa_len) != 0 ||
+ bcmp(&ep->dstmask, dm, dp->sa_len) != 0)
+ continue;
+
+ error = EEXIST;
+ goto fail;
+ }
+
+ ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/
+ if (ep == NULL) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ bzero(ep, sizeof(*ep));
+
+ ep->af = af;
+ ep->proto = proto;
+ bcopy(sp, &ep->src, sp->sa_len);
+ bcopy(sm, &ep->srcmask, sp->sa_len);
+ bcopy(dp, &ep->dst, dp->sa_len);
+ bcopy(dm, &ep->dstmask, dp->sa_len);
+ ep->psw = psw;
+ ep->arg = arg;
+
+ encap_add(ep);
+
+ error = 0;
+ splx(s);
+ return ep;
+
+fail:
+ splx(s);
+ return NULL;
+}
+
+const struct encaptab *
+encap_attach_func(af, proto, func, psw, arg)
+ int af;
+ int proto;
+ int (*func) __P((const struct mbuf *, int, int, void *));
+ const struct protosw *psw;
+ void *arg;
+{
+ struct encaptab *ep;
+ int error;
+ int s;
+
+ s = splnet();
+ /* sanity check on args */
+ if (!func) {
+ error = EINVAL;
+ goto fail;
+ }
+
+ ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/
+ if (ep == NULL) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ bzero(ep, sizeof(*ep));
+
+ ep->af = af;
+ ep->proto = proto;
+ ep->func = func;
+ ep->psw = psw;
+ ep->arg = arg;
+
+ encap_add(ep);
+
+ error = 0;
+ splx(s);
+ return ep;
+
+fail:
+ splx(s);
+ return NULL;
+}
+
+int
+encap_detach(cookie)
+ const struct encaptab *cookie;
+{
+ const struct encaptab *ep = cookie;
+ struct encaptab *p;
+
+ for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) {
+ if (p == ep) {
+ LIST_REMOVE(p, chain);
+ free(p, M_NETADDR); /*XXX*/
+ return 0;
+ }
+ }
+
+ return EINVAL;
+}
+
+static int
+mask_match(ep, sp, dp)
+ const struct encaptab *ep;
+ const struct sockaddr *sp;
+ const struct sockaddr *dp;
+{
+ struct sockaddr_storage s;
+ struct sockaddr_storage d;
+ int i;
+ const u_int8_t *p, *q;
+ u_int8_t *r;
+ int matchlen;
+
+ if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d))
+ return 0;
+ if (sp->sa_family != ep->af || dp->sa_family != ep->af)
+ return 0;
+ if (sp->sa_len != ep->src.ss_len || dp->sa_len != ep->dst.ss_len)
+ return 0;
+
+ matchlen = 0;
+
+ p = (const u_int8_t *)sp;
+ q = (const u_int8_t *)&ep->srcmask;
+ r = (u_int8_t *)&s;
+ for (i = 0 ; i < sp->sa_len; i++) {
+ r[i] = p[i] & q[i];
+ /* XXX estimate */
+ matchlen += (q[i] ? 8 : 0);
+ }
+
+ p = (const u_int8_t *)dp;
+ q = (const u_int8_t *)&ep->dstmask;
+ r = (u_int8_t *)&d;
+ for (i = 0 ; i < dp->sa_len; i++) {
+ r[i] = p[i] & q[i];
+ /* XXX rough estimate */
+ matchlen += (q[i] ? 8 : 0);
+ }
+
+ /* need to overwrite len/family portion as we don't compare them */
+ s.ss_len = sp->sa_len;
+ s.ss_family = sp->sa_family;
+ d.ss_len = dp->sa_len;
+ d.ss_family = dp->sa_family;
+
+ if (bcmp(&s, &ep->src, ep->src.ss_len) == 0 &&
+ bcmp(&d, &ep->dst, ep->dst.ss_len) == 0) {
+ return matchlen;
+ } else
+ return 0;
+}
+
+static void
+encap_fillarg(m, ep)
+ struct mbuf *m;
+ const struct encaptab *ep;
+{
+#if 0
+ m->m_pkthdr.aux = ep->arg;
+#else
+ struct mbuf *n;
+
+ n = m_aux_add(m, AF_INET, IPPROTO_IPV4);
+ if (n) {
+ *mtod(n, void **) = ep->arg;
+ n->m_len = sizeof(void *);
+ }
+#endif
+}
+
+void *
+encap_getarg(m)
+ struct mbuf *m;
+{
+ void *p;
+#if 0
+ p = m->m_pkthdr.aux;
+ m->m_pkthdr.aux = NULL;
+ return p;
+#else
+ struct mbuf *n;
+
+ p = NULL;
+ n = m_aux_find(m, AF_INET, IPPROTO_IPV4);
+ if (n) {
+ if (n->m_len == sizeof(void *))
+ p = *mtod(n, void **);
+ m_aux_delete(m, n);
+ }
+ return p;
+#endif
+}
diff --git a/sys/crypto/hmac_md5.c b/sys/netinet/ip_encap.h
index 5302dbe11fdf..38df6f94784c 100644
--- a/sys/crypto/hmac_md5.c
+++ b/sys/netinet/ip_encap.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip_encap.h,v 1.7 2000/03/25 07:23:37 sumikawa Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,74 +28,37 @@
* 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.
- *
- * $FreeBSD$
- */
-
-/*
- * Based on sample code appeared on RFC2104.
*/
-#include <sys/types.h>
-#include <sys/cdefs.h>
-#include <sys/time.h>
-#include <sys/systm.h>
-#include <crypto/md5.h>
-
-#include <crypto/hmac_md5.h>
-
-void
-hmac_md5(src0, srclen, key0, keylen, digest)
- caddr_t src0;
- size_t srclen;
- caddr_t key0;
- size_t keylen;
- caddr_t digest;
-{
- u_int8_t *src;
- u_int8_t *key;
- u_int8_t tk[16];
- u_int8_t ipad[65];
- u_int8_t opad[65];
- size_t i;
-
- src = (u_int8_t *)src0;
- key = (u_int8_t *)key0;
-
- /*
- * compress the key into 16bytes, if key is too long.
- */
- if (64 < keylen) {
- md5_init();
- md5_loop(key, keylen);
- md5_pad();
- md5_result(&tk[0]);
- key = &tk[0];
- keylen = 16;
- }
+#ifndef _NETINET_IP_ENCAP_H_
+#define _NETINET_IP_ENCAP_H_
- /*
- *
- */
- bzero(&ipad[0], sizeof ipad);
- bzero(&opad[0], sizeof opad);
- bcopy(key, &ipad[0], keylen);
- bcopy(key, &opad[0], keylen);
+#ifdef _KERNEL
- for (i = 0; i < 64; i++) {
- ipad[i] ^= 0x36;
- opad[i] ^= 0x5c;
- }
+struct encaptab {
+ LIST_ENTRY(encaptab) chain;
+ int af;
+ int proto; /* -1: don't care, I'll check myself */
+ struct sockaddr_storage src; /* my addr */
+ struct sockaddr_storage srcmask;
+ struct sockaddr_storage dst; /* remote addr */
+ struct sockaddr_storage dstmask;
+ int (*func) __P((const struct mbuf *, int, int, void *));
+ const struct protosw *psw; /* only pr_input will be used */
+ void *arg; /* passed via m->m_pkthdr.aux */
+};
- md5_init();
- md5_loop(&ipad[0], 64);
- md5_loop(src, srclen);
- md5_pad();
- md5_result((u_int8_t *)digest);
+void encap_init __P((void));
+void encap4_input __P((struct mbuf *, ...));
+int encap6_input __P((struct mbuf **, int *, int));
+const struct encaptab *encap_attach __P((int, int, const struct sockaddr *,
+ const struct sockaddr *, const struct sockaddr *,
+ const struct sockaddr *, const struct protosw *, void *));
+const struct encaptab *encap_attach_func __P((int, int,
+ int (*) __P((const struct mbuf *, int, int, void *)),
+ const struct protosw *, void *));
+int encap_detach __P((const struct encaptab *));
+void *encap_getarg __P((struct mbuf *));
+#endif
- md5_init();
- md5_loop(&opad[0], 64);
- md5_loop((u_int8_t *)digest, 16);
- md5_pad();
- md5_result((u_int8_t *)digest);
-}
+#endif /*_NETINET_IP_ENCAP_H_*/
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index fc355af05e98..6647622979b1 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -83,11 +83,6 @@
#ifdef IPSEC
#include <netinet6/ipsec.h>
#include <netkey/key.h>
-#ifdef IPSEC_DEBUG
-#include <netkey/key_debug.h>
-#else
-#define KEYDEBUG(lev,arg)
-#endif
#endif
#include "faith.h"
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 2536b632398c..450b0d67a93c 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -152,16 +152,6 @@ ip_output(m0, opt, ro, flags, imo)
divert_cookie = 0;
#endif
- /*
- * NOTE: If IP_SOCKINMRCVIF flag is set, 'socket *' is kept in
- * m->m_pkthdr.rcvif for later IPSEC check. In this case,
- * m->m_pkthdr will be NULL cleared after the contents is saved in
- * 'so'.
- * NULL clearance of rcvif should be natural because the packet should
- * have been sent from my own socket and has no rcvif in this case.
- * It is also necessary because someone might consider it as
- * 'ifnet *', and cause SEGV.
- */
#if defined(IPFIREWALL) && defined(DUMMYNET)
/*
* dummynet packet are prepended a vestigial mbuf with
@@ -184,10 +174,8 @@ ip_output(m0, opt, ro, flags, imo)
m0 = m = m->m_next ;
#ifdef IPSEC
- if ((flags & IP_SOCKINMRCVIF) != 0) {
- so = (struct socket *)m->m_pkthdr.rcvif;
- m->m_pkthdr.rcvif = NULL;
- }
+ so = ipsec_getsocket(m);
+ ipsec_setsocket(m, NULL);
#endif
ip = mtod(m, struct ip *);
hlen = IP_VHL_HL(ip->ip_vhl) << 2 ;
@@ -196,10 +184,8 @@ ip_output(m0, opt, ro, flags, imo)
rule = NULL ;
#endif
#ifdef IPSEC
- if ((flags & IP_SOCKINMRCVIF) != 0) {
- so = (struct socket *)m->m_pkthdr.rcvif;
- m->m_pkthdr.rcvif = NULL;
- }
+ so = ipsec_getsocket(m);
+ ipsec_setsocket(m, NULL);
#endif
#ifdef DIAGNOSTIC
@@ -1051,8 +1037,16 @@ ip_optcopy(ip, jp)
*dp++ = IPOPT_NOP;
optlen = 1;
continue;
- } else
- optlen = cp[IPOPT_OLEN];
+ }
+#ifdef DIAGNOSTIC
+ if (cnt < IPOPT_OLEN + sizeof(*cp))
+ panic("malformed IPv4 option passed to ip_optcopy");
+#endif
+ optlen = cp[IPOPT_OLEN];
+#ifdef DIAGNOSTIC
+ if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt)
+ panic("malformed IPv4 option passed to ip_optcopy");
+#endif
/* bogus lengths should have been caught by ip_dooptions */
if (optlen > cnt)
optlen = cnt;
@@ -1202,6 +1196,7 @@ ip_ctloutput(so, sopt)
case IP_IPSEC_POLICY:
{
caddr_t req;
+ size_t len = 0;
int priv;
struct mbuf *m;
int optname;
@@ -1213,8 +1208,9 @@ ip_ctloutput(so, sopt)
priv = (sopt->sopt_p != NULL &&
suser(sopt->sopt_p) != 0) ? 0 : 1;
req = mtod(m, caddr_t);
+ len = m->m_len;
optname = sopt->sopt_name;
- error = ipsec4_set_policy(inp, optname, req, priv);
+ error = ipsec4_set_policy(inp, optname, req, len, priv);
m_freem(m);
break;
}
@@ -1309,10 +1305,13 @@ ip_ctloutput(so, sopt)
{
struct mbuf *m = NULL;
caddr_t req = NULL;
+ size_t len = 0;
- if (m != 0)
+ if (m != 0) {
req = mtod(m, caddr_t);
- error = ipsec4_get_policy(sotoinpcb(so), req, &m);
+ len = m->m_len;
+ }
+ error = ipsec4_get_policy(sotoinpcb(so), req, len, &m);
if (error == 0)
error = soopt_mcopyout(sopt, m); /* XXX */
if (error == 0)
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index 1610ae2fdaf0..4ddec9356e12 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -131,9 +131,6 @@ struct ipstat {
#define IP_RAWOUTPUT 0x2 /* raw ip header exists */
#define IP_ROUTETOIF SO_DONTROUTE /* bypass routing tables */
#define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */
-#define IP_SOCKINMRCVIF 0x100 /* IPSEC hack;
- * socket pointer in sending
- * packet's m_pkthdr.rcvif */
struct ip;
struct inpcb;
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index 0bf04662df74..5d056cefadf6 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -228,11 +228,10 @@ rip_output(m, so, dst)
}
#ifdef IPSEC
- m->m_pkthdr.rcvif = (struct ifnet *)so; /*XXX*/
+ ipsec_setsocket(m, so);
#endif /*IPSEC*/
- return (ip_output(m, inp->inp_options, &inp->inp_route,
- flags | IP_SOCKINMRCVIF,
+ return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
inp->inp_moptions));
}
diff --git a/sys/netinet/tcp_debug.c b/sys/netinet/tcp_debug.c
index d84c37afe56d..89e9d7cbc94a 100644
--- a/sys/netinet/tcp_debug.c
+++ b/sys/netinet/tcp_debug.c
@@ -59,7 +59,7 @@
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#ifdef INET6
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#endif
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 28fb89e72f03..9cdff6a78bcd 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -60,22 +60,18 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-#ifdef INET6
-#include <netinet/ip6.h>
+#include <netinet/ip_icmp.h> /* for ICMP_BANDLIM */
#include <netinet/in_var.h>
-#include <netinet6/nd6.h>
-#include <netinet/icmp6.h>
-#endif
+#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */
#include <netinet/in_pcb.h>
-#ifdef INET6
-#include <netinet6/in6_pcb.h>
-#endif
#include <netinet/ip_var.h>
#ifdef INET6
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet6/nd6.h>
#include <netinet6/ip6_var.h>
+#include <netinet6/in6_pcb.h>
#endif
-#include <netinet/icmp_var.h>
#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
@@ -157,7 +153,7 @@ do { \
if ((tp) && (tp)->t_inpcb && \
((tp)->t_inpcb->inp_vflag & INP_IPV6) != 0 && \
(tp)->t_inpcb->in6p_route.ro_rt) \
- nd6_nud_hint((tp)->t_inpcb->in6p_route.ro_rt, NULL); \
+ nd6_nud_hint((tp)->t_inpcb->in6p_route.ro_rt, NULL, 0); \
} while (0)
#else
#define ND6_HINT(tp)
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index eb498483bf68..5a3c1bd90657 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -45,6 +45,7 @@
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/mbuf.h>
+#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
@@ -54,15 +55,11 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
-#ifdef INET6
-#include <netinet/ip6.h>
-#endif
#include <netinet/in_pcb.h>
-#ifdef INET6
-#include <netinet6/in6_pcb.h>
-#endif
#include <netinet/ip_var.h>
#ifdef INET6
+#include <netinet6/in6_pcb.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#endif
#include <netinet/tcp.h>
@@ -813,31 +810,38 @@ send:
*/
#ifdef INET6
if (isipv6) {
- /*
+ /*
* we separately set hoplimit for every segment, since the
* user might want to change the value via setsockopt.
* Also, desired default hop limit might be changed via
- * Neighbor Discovery.
- */
- ip6->ip6_hlim = in6_selecthlim(tp->t_inpcb,
- tp->t_inpcb->in6p_route.ro_rt ?
- tp->t_inpcb->in6p_route.ro_rt->rt_ifp
- : NULL);
+ * Neighbor Discovery.
+ */
+ ip6->ip6_hlim = in6_selecthlim(tp->t_inpcb,
+ tp->t_inpcb->in6p_route.ro_rt ?
+ tp->t_inpcb->in6p_route.ro_rt->rt_ifp
+ : NULL);
/* TODO: IPv6 IP6TOS_ECT bit on */
#ifdef IPSEC
- m->m_pkthdr.rcvif = (struct ifnet *)so;
+ ipsec_setsocket(m, so);
#endif /*IPSEC*/
error = ip6_output(m,
tp->t_inpcb->in6p_outputopts,
&tp->t_inpcb->in6p_route,
- (so->so_options & SO_DONTROUTE)|IPV6_SOCKINMRCVIF,
- NULL, NULL);
+ (so->so_options & SO_DONTROUTE), NULL, NULL);
} else
#endif /* INET6 */
{
struct rtentry *rt;
ip->ip_len = m->m_pkthdr.len;
+#ifdef INET6
+ if (INP_CHECK_SOCKAF(so, AF_INET6))
+ ip->ip_ttl = in6_selecthlim(tp->t_inpcb,
+ tp->t_inpcb->in6p_route.ro_rt ?
+ tp->t_inpcb->in6p_route.ro_rt->rt_ifp
+ : NULL);
+ else
+#endif /* INET6 */
ip->ip_ttl = tp->t_inpcb->inp_ip_ttl; /* XXX */
ip->ip_tos = tp->t_inpcb->inp_ip_tos; /* XXX */
/*
@@ -853,8 +857,11 @@ send:
&& !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
ip->ip_off |= IP_DF;
}
+#ifdef IPSEC
+ ipsec_setsocket(m, so);
+#endif /*IPSEC*/
error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
- (so->so_options & SO_DONTROUTE)|IP_SOCKINMRCVIF, 0);
+ (so->so_options & SO_DONTROUTE), 0);
}
if (error) {
out:
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index 28fb89e72f03..9cdff6a78bcd 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -60,22 +60,18 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-#ifdef INET6
-#include <netinet/ip6.h>
+#include <netinet/ip_icmp.h> /* for ICMP_BANDLIM */
#include <netinet/in_var.h>
-#include <netinet6/nd6.h>
-#include <netinet/icmp6.h>
-#endif
+#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */
#include <netinet/in_pcb.h>
-#ifdef INET6
-#include <netinet6/in6_pcb.h>
-#endif
#include <netinet/ip_var.h>
#ifdef INET6
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet6/nd6.h>
#include <netinet6/ip6_var.h>
+#include <netinet6/in6_pcb.h>
#endif
-#include <netinet/icmp_var.h>
#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
@@ -157,7 +153,7 @@ do { \
if ((tp) && (tp)->t_inpcb && \
((tp)->t_inpcb->inp_vflag & INP_IPV6) != 0 && \
(tp)->t_inpcb->in6p_route.ro_rt) \
- nd6_nud_hint((tp)->t_inpcb->in6p_route.ro_rt, NULL); \
+ nd6_nud_hint((tp)->t_inpcb->in6p_route.ro_rt, NULL, 0); \
} while (0)
#else
#define ND6_HINT(tp)
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index aee77e7286ab..68f87aa173b5 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -92,6 +92,9 @@
#ifdef IPSEC
#include <netinet6/ipsec.h>
+#ifdef INET6
+#include <netinet6/ipsec6.h>
+#endif
#endif /*IPSEC*/
#include <machine/in_cksum.h>
@@ -441,14 +444,7 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags)
tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0);
#endif
#ifdef IPSEC
- if (tp != NULL) {
- m->m_pkthdr.rcvif = (struct ifnet *)tp->t_inpcb->inp_socket;
- ipflags |=
-#ifdef INET6
- isipv6 ? IPV6_SOCKINMRCVIF :
-#endif
- IP_SOCKINMRCVIF;
- }
+ ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL);
#endif
#ifdef INET6
if (isipv6) {
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index aee77e7286ab..68f87aa173b5 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -92,6 +92,9 @@
#ifdef IPSEC
#include <netinet6/ipsec.h>
+#ifdef INET6
+#include <netinet6/ipsec6.h>
+#endif
#endif /*IPSEC*/
#include <machine/in_cksum.h>
@@ -441,14 +444,7 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags)
tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0);
#endif
#ifdef IPSEC
- if (tp != NULL) {
- m->m_pkthdr.rcvif = (struct ifnet *)tp->t_inpcb->inp_socket;
- ipflags |=
-#ifdef INET6
- isipv6 ? IPV6_SOCKINMRCVIF :
-#endif
- IP_SOCKINMRCVIF;
- }
+ ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL);
#endif
#ifdef INET6
if (isipv6) {
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 1ec33b2f140b..09b5c96a1c2e 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -188,6 +188,10 @@ udp_input(m, off, proto)
}
uh = (struct udphdr *)((caddr_t)ip + iphlen);
+ /* destination port of 0 is illegal, based on RFC768. */
+ if (uh->uh_dport == 0)
+ goto bad;
+
/*
* Make mbuf data length reflect UDP length.
* If not enough data to reflect UDP length, drop.
@@ -407,7 +411,7 @@ bad:
return;
}
-#if defined(INET6)
+#ifdef INET6
static void
ip_2_ip6_hdr(ip6, ip)
struct ip6_hdr *ip6;
@@ -714,12 +718,10 @@ udp_output(inp, m, addr, control, p)
udpstat.udps_opackets++;
#ifdef IPSEC
- m->m_pkthdr.rcvif = (struct ifnet *)inp->inp_socket;
+ ipsec_setsocket(m, inp->inp_socket);
#endif /*IPSEC*/
-
error = ip_output(m, inp->inp_options, &inp->inp_route,
- (inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST))
- | IP_SOCKINMRCVIF,
+ (inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)),
inp->inp_moptions);
if (addr) {
diff --git a/sys/netinet6/README b/sys/netinet6/README
new file mode 100644
index 000000000000..f144f63bb0f8
--- /dev/null
+++ b/sys/netinet6/README
@@ -0,0 +1,28 @@
+a note to committers about KAME tree
+$FreeBSD$
+KAME project
+
+
+FreeBSD IPv6/IPsec tree is from KAMEproject (http://www.kame.net/).
+To synchronize KAME tree and FreeBSD better today and in the future,
+please understand the following:
+
+- DO NOT MAKE COSTMETIC CHANGES.
+ "Cosmetic changes" here includes tabify, untabify, removal of space at EOL,
+ minor KNF items, and whatever adds more output lines on "diff freebsd kame".
+ To make future synchronization easier. it is critical to preserve certain
+ statements in the code. Also, as KAME tree supports all 4 BSDs (Free, Open,
+ Net, BSD/OS) in single shared tree, it is not always possible to backport
+ FreeBSD changes into KAME tree. So again, please do not make cosmetic
+ changes. Even if you think it a right thing, that will bite KAME guys badly
+ during upgrade attempts, and prevent us from synchronizing two trees.
+ (you don't usually make cosmetic changes against third-party code, do you?)
+
+- REPORT CHANGES/BUGS TO KAME GUYS.
+ It is not always possible for KAME guys to watch all the freebsd mailing
+ list traffic, as the traffic is HUGE. So if possible, please, inform
+ kame guys of changes you made in IPv6/IPsec related portion. Contact
+ path would be snap-users@kame.net or KAME PR database on www.kame.net.
+ (or to core@kame.net if it is necessary to make it confidential)
+
+Thank you for your cooperation and have a happy IPv6 life!
diff --git a/sys/netinet6/ah.h b/sys/netinet6/ah.h
index 1b7e602cf8dd..3c7d0a671ae2 100644
--- a/sys/netinet6/ah.h
+++ b/sys/netinet6/ah.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ah.h,v 1.10 2000/07/02 13:23:33 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -34,7 +35,7 @@
*/
#ifndef _NETINET6_AH_H_
-#define _NETINET6_AH_H_
+#define _NETINET6_AH_H_
struct secasvar;
@@ -65,9 +66,9 @@ struct ah_algorithm {
int (*mature) __P((struct secasvar *));
int keymin; /* in bits */
int keymax; /* in bits */
- void (*init) __P((struct ah_algorithm_state *, struct secasvar *));
- void (*update) __P((struct ah_algorithm_state *, const caddr_t,
- size_t));
+ const char *name;
+ int (*init) __P((struct ah_algorithm_state *, struct secasvar *));
+ void (*update) __P((struct ah_algorithm_state *, caddr_t, size_t));
void (*result) __P((struct ah_algorithm_state *, caddr_t));
};
@@ -80,10 +81,10 @@ extern struct ah_algorithm ah_algorithms[];
extern int ah_hdrlen __P((struct secasvar *));
extern size_t ah_hdrsiz __P((struct ipsecrequest *));
-extern void ah4_input __P((struct mbuf *, int, int));
+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,
- struct ah_algorithm *, struct secasvar *));
-#endif
+extern int ah4_calccksum __P((struct mbuf *, caddr_t, size_t,
+ struct ah_algorithm *, struct secasvar *));
+#endif /*_KERNEL*/
#endif /*_NETINET6_AH_H_*/
diff --git a/sys/netinet6/ah6.h b/sys/netinet6/ah6.h
index b3448f4cfaeb..4010f1335cb8 100644
--- a/sys/netinet6/ah6.h
+++ b/sys/netinet6/ah6.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ah.h,v 1.10 2000/07/02 13:23:33 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -34,7 +35,7 @@
*/
#ifndef _NETINET6_AH6_H_
-#define _NETINET6_AH6_H_
+#define _NETINET6_AH6_H_
#ifdef _KERNEL
struct secasvar;
@@ -42,8 +43,8 @@ struct secasvar;
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,
- struct ah_algorithm *, struct secasvar *));
+extern int ah6_calccksum __P((struct mbuf *, caddr_t, size_t,
+ struct ah_algorithm *, struct secasvar *));
#endif
#endif /*_NETINET6_AH6_H_*/
diff --git a/sys/netinet6/ah_core.c b/sys/netinet6/ah_core.c
index 8ef0f390d240..6dbaee02ec37 100644
--- a/sys/netinet6/ah_core.c
+++ b/sys/netinet6/ah_core.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ah_core.c,v 1.35 2000/06/14 11:14:03 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,14 +28,13 @@
* 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.
- *
- * $FreeBSD$
*/
/*
* RFC1826/2402 authentication header.
*/
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
@@ -46,6 +48,7 @@
#include <sys/socketvar.h>
#include <sys/errno.h>
#include <sys/time.h>
+#include <sys/syslog.h>
#include <net/if.h>
#include <net/route.h>
@@ -54,18 +57,19 @@
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_var.h>
-#include <netinet/in_pcb.h>
#ifdef INET6
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#endif
#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
#ifdef IPSEC_ESP
@@ -75,7 +79,6 @@
#endif
#endif
#include <net/pfkeyv2.h>
-#include <netkey/key_var.h>
#include <netkey/keydb.h>
#include <sys/md5.h>
#include <crypto/sha1.h>
@@ -84,57 +87,54 @@
#define HMACSIZE 16
-#ifdef INET6
-#define ZEROBUFLEN 256
-static char zerobuf[ZEROBUFLEN];
-#endif
-
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 void ah_none_init __P((struct ah_algorithm_state *,
+static int ah_none_init __P((struct ah_algorithm_state *,
struct secasvar *));
-static void ah_none_loop __P((struct ah_algorithm_state *, const caddr_t,
- size_t));
+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 *));
-static void ah_keyed_md5_init __P((struct ah_algorithm_state *,
+static int ah_keyed_md5_init __P((struct ah_algorithm_state *,
struct secasvar *));
-static void ah_keyed_md5_loop __P((struct ah_algorithm_state *, const caddr_t,
+static void ah_keyed_md5_loop __P((struct ah_algorithm_state *, caddr_t,
size_t));
static void ah_keyed_md5_result __P((struct ah_algorithm_state *, caddr_t));
static int ah_keyed_sha1_mature __P((struct secasvar *));
-static void ah_keyed_sha1_init __P((struct ah_algorithm_state *,
+static int ah_keyed_sha1_init __P((struct ah_algorithm_state *,
struct secasvar *));
-static void ah_keyed_sha1_loop __P((struct ah_algorithm_state *, const caddr_t,
+static void ah_keyed_sha1_loop __P((struct ah_algorithm_state *, caddr_t,
size_t));
static void ah_keyed_sha1_result __P((struct ah_algorithm_state *, caddr_t));
static int ah_hmac_md5_mature __P((struct secasvar *));
-static void ah_hmac_md5_init __P((struct ah_algorithm_state *,
+static int ah_hmac_md5_init __P((struct ah_algorithm_state *,
struct secasvar *));
-static void ah_hmac_md5_loop __P((struct ah_algorithm_state *, const caddr_t,
+static void ah_hmac_md5_loop __P((struct ah_algorithm_state *, caddr_t,
size_t));
static void ah_hmac_md5_result __P((struct ah_algorithm_state *, caddr_t));
static int ah_hmac_sha1_mature __P((struct secasvar *));
-static void ah_hmac_sha1_init __P((struct ah_algorithm_state *,
+static int ah_hmac_sha1_init __P((struct ah_algorithm_state *,
struct secasvar *));
-static void ah_hmac_sha1_loop __P((struct ah_algorithm_state *, const caddr_t,
+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 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 netkey/keyv2.h */
+/* 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,
+ { 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,
+ { 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,
+ { 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,
+ { 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,
+ { ah_sumsiz_zero, ah_none_mature, 0, 2048, "none",
ah_none_init, ah_none_loop, ah_none_result, },
};
@@ -164,24 +164,26 @@ ah_none_mature(sav)
struct secasvar *sav;
{
if (sav->sah->saidx.proto == IPPROTO_AH) {
- printf("ah_none_mature: protocol and algorithm mismatch.\n");
+ ipseclog((LOG_ERR,
+ "ah_none_mature: protocol and algorithm mismatch.\n"));
return 1;
}
return 0;
}
-static void
+static int
ah_none_init(state, sav)
struct ah_algorithm_state *state;
struct secasvar *sav;
{
state->foo = NULL;
+ return 0;
}
static void
ah_none_loop(state, addr, len)
struct ah_algorithm_state *state;
- const caddr_t addr;
+ caddr_t addr;
size_t len;
{
}
@@ -201,34 +203,34 @@ ah_keyed_md5_mature(sav)
return 0;
}
-static void
+static int
ah_keyed_md5_init(state, sav)
struct ah_algorithm_state *state;
struct secasvar *sav;
{
+ size_t padlen;
+ size_t keybitlen;
+ u_int8_t buf[32];
+
if (!state)
panic("ah_keyed_md5_init: what?");
state->sav = sav;
state->foo = (void *)malloc(sizeof(MD5_CTX), M_TEMP, M_NOWAIT);
if (state->foo == NULL)
- panic("ah_keyed_md5_init: what?");
+ return ENOBUFS;
+
MD5Init((MD5_CTX *)state->foo);
if (state->sav) {
MD5Update((MD5_CTX *)state->foo,
(u_int8_t *)_KEYBUF(state->sav->key_auth),
(u_int)_KEYLEN(state->sav->key_auth));
- {
/*
* Pad after the key.
* We cannot simply use md5_pad() since the function
* won't update the total length.
*/
- size_t padlen;
- size_t keybitlen;
- u_int8_t buf[32];
-
if (_KEYLEN(state->sav->key_auth) < 56)
padlen = 64 - 8 - _KEYLEN(state->sav->key_auth);
else
@@ -254,14 +256,15 @@ ah_keyed_md5_init(state, sav)
buf[2] = (keybitlen >> 16) & 0xff;
buf[3] = (keybitlen >> 24) & 0xff;
MD5Update((MD5_CTX *)state->foo, buf, 8);
- }
}
+
+ return 0;
}
static void
ah_keyed_md5_loop(state, addr, len)
struct ah_algorithm_state *state;
- const caddr_t addr;
+ caddr_t addr;
size_t len;
{
if (!state)
@@ -297,26 +300,30 @@ ah_keyed_sha1_mature(sav)
struct ah_algorithm *algo;
if (!sav->key_auth) {
- printf("esp_keyed_sha1_mature: no key is given.\n");
+ ipseclog((LOG_ERR, "ah_keyed_sha1_mature: no key is given.\n"));
return 1;
}
algo = &ah_algorithms[sav->alg_auth];
if (sav->key_auth->sadb_key_bits < algo->keymin
|| algo->keymax < sav->key_auth->sadb_key_bits) {
- printf("ah_keyed_sha1_mature: invalid key length %d.\n",
- sav->key_auth->sadb_key_bits);
+ ipseclog((LOG_ERR,
+ "ah_keyed_sha1_mature: invalid key length %d.\n",
+ sav->key_auth->sadb_key_bits));
return 1;
}
return 0;
}
-static void
+static int
ah_keyed_sha1_init(state, sav)
struct ah_algorithm_state *state;
struct secasvar *sav;
{
SHA1_CTX *ctxt;
+ size_t padlen;
+ size_t keybitlen;
+ u_int8_t buf[32];
if (!state)
panic("ah_keyed_sha1_init: what?");
@@ -324,7 +331,7 @@ ah_keyed_sha1_init(state, sav)
state->sav = sav;
state->foo = (void *)malloc(sizeof(SHA1_CTX), M_TEMP, M_NOWAIT);
if (!state->foo)
- panic("ah_keyed_sha1_init: what?");
+ return ENOBUFS;
ctxt = (SHA1_CTX *)state->foo;
SHA1Init(ctxt);
@@ -333,14 +340,9 @@ ah_keyed_sha1_init(state, sav)
SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sav->key_auth),
(u_int)_KEYLEN(state->sav->key_auth));
- {
/*
* Pad after the key.
*/
- size_t padlen;
- size_t keybitlen;
- u_int8_t buf[32];
-
if (_KEYLEN(state->sav->key_auth) < 56)
padlen = 64 - 8 - _KEYLEN(state->sav->key_auth);
else
@@ -366,14 +368,15 @@ ah_keyed_sha1_init(state, sav)
buf[2] = (keybitlen >> 16) & 0xff;
buf[3] = (keybitlen >> 24) & 0xff;
SHA1Update(ctxt, buf, 8);
- }
}
+
+ return 0;
}
static void
ah_keyed_sha1_loop(state, addr, len)
struct ah_algorithm_state *state;
- const caddr_t addr;
+ caddr_t addr;
size_t len;
{
SHA1_CTX *ctxt;
@@ -382,7 +385,7 @@ ah_keyed_sha1_loop(state, addr, len)
panic("ah_keyed_sha1_loop: what?");
ctxt = (SHA1_CTX *)state->foo;
- sha1_loop(ctxt, (caddr_t)addr, (size_t)len);
+ SHA1Update(ctxt, (caddr_t)addr, (size_t)len);
}
static void
@@ -414,21 +417,22 @@ ah_hmac_md5_mature(sav)
struct ah_algorithm *algo;
if (!sav->key_auth) {
- printf("esp_hmac_md5_mature: no key is given.\n");
+ ipseclog((LOG_ERR, "ah_hmac_md5_mature: no key is given.\n"));
return 1;
}
algo = &ah_algorithms[sav->alg_auth];
if (sav->key_auth->sadb_key_bits < algo->keymin
|| algo->keymax < sav->key_auth->sadb_key_bits) {
- printf("ah_hmac_md5_mature: invalid key length %d.\n",
- sav->key_auth->sadb_key_bits);
+ ipseclog((LOG_ERR,
+ "ah_hmac_md5_mature: invalid key length %d.\n",
+ sav->key_auth->sadb_key_bits));
return 1;
}
return 0;
}
-static void
+static int
ah_hmac_md5_init(state, sav)
struct ah_algorithm_state *state;
struct secasvar *sav;
@@ -447,7 +451,7 @@ ah_hmac_md5_init(state, sav)
state->sav = sav;
state->foo = (void *)malloc(64 + 64 + sizeof(MD5_CTX), M_TEMP, M_NOWAIT);
if (!state->foo)
- panic("ah_hmac_md5_init: what?");
+ return ENOBUFS;
ipad = (u_char *)state->foo;
opad = (u_char *)(ipad + 64);
@@ -477,12 +481,14 @@ ah_hmac_md5_init(state, sav)
MD5Init(ctxt);
MD5Update(ctxt, ipad, 64);
+
+ return 0;
}
static void
ah_hmac_md5_loop(state, addr, len)
struct ah_algorithm_state *state;
- const caddr_t addr;
+ caddr_t addr;
size_t len;
{
MD5_CTX *ctxt;
@@ -529,21 +535,22 @@ ah_hmac_sha1_mature(sav)
struct ah_algorithm *algo;
if (!sav->key_auth) {
- printf("esp_hmac_sha1_mature: no key is given.\n");
+ ipseclog((LOG_ERR, "ah_hmac_sha1_mature: no key is given.\n"));
return 1;
}
algo = &ah_algorithms[sav->alg_auth];
if (sav->key_auth->sadb_key_bits < algo->keymin
|| algo->keymax < sav->key_auth->sadb_key_bits) {
- printf("ah_hmac_sha1_mature: invalid key length %d.\n",
- sav->key_auth->sadb_key_bits);
+ ipseclog((LOG_ERR,
+ "ah_hmac_sha1_mature: invalid key length %d.\n",
+ sav->key_auth->sadb_key_bits));
return 1;
}
return 0;
}
-static void
+static int
ah_hmac_sha1_init(state, sav)
struct ah_algorithm_state *state;
struct secasvar *sav;
@@ -563,7 +570,7 @@ ah_hmac_sha1_init(state, sav)
state->foo = (void *)malloc(64 + 64 + sizeof(SHA1_CTX),
M_TEMP, M_NOWAIT);
if (!state->foo)
- panic("ah_hmac_sha1_init: what?");
+ return ENOBUFS;
ipad = (u_char *)state->foo;
opad = (u_char *)(ipad + 64);
@@ -593,12 +600,14 @@ ah_hmac_sha1_init(state, sav)
SHA1Init(ctxt);
SHA1Update(ctxt, ipad, 64);
+
+ return 0;
}
static void
ah_hmac_sha1_loop(state, addr, len)
struct ah_algorithm_state *state;
- const caddr_t addr;
+ caddr_t addr;
size_t len;
{
SHA1_CTX *ctxt;
@@ -644,46 +653,99 @@ ah_hmac_sha1_result(state, addr)
/*
* go generate the checksum.
*/
+static void
+ah_update_mbuf(m, off, len, algo, algos)
+ struct mbuf *m;
+ int off;
+ int len;
+ struct ah_algorithm *algo;
+ struct ah_algorithm_state *algos;
+{
+ struct mbuf *n;
+ int tlen;
+
+ /* easy case first */
+ if (off + len <= m->m_len) {
+ (algo->update)(algos, mtod(m, caddr_t) + off, len);
+ return;
+ }
+
+ for (n = m; n; n = n->m_next) {
+ if (off < n->m_len)
+ break;
+
+ off -= n->m_len;
+ }
+
+ if (!n)
+ panic("ah_update_mbuf: wrong offset specified");
+
+ for (/*nothing*/; n && len > 0; n = n->m_next) {
+ if (n->m_len == 0)
+ continue;
+ if (n->m_len - off < len)
+ tlen = n->m_len - off;
+ else
+ tlen = len;
+
+ (algo->update)(algos, mtod(n, caddr_t) + off, tlen);
+
+ len -= tlen;
+ off = 0;
+ }
+}
+
+/*
+ * Go generate the checksum. This function won't modify the mbuf chain
+ * except AH itself.
+ *
+ * NOTE: the function does not free mbuf on failure.
+ * Don't use m_copy(), it will try to share cluster mbuf by using refcnt.
+ */
int
-ah4_calccksum(m0, ahdat, algo, sav)
- struct mbuf *m0;
+ah4_calccksum(m, ahdat, len, algo, sav)
+ struct mbuf *m;
caddr_t ahdat;
+ size_t len;
struct ah_algorithm *algo;
struct secasvar *sav;
{
- struct mbuf *m;
+ int off;
int hdrtype;
- u_char *p;
size_t advancewidth;
struct ah_algorithm_state algos;
- int tlen;
u_char sumbuf[AH_MAXSUMSIZE];
int error = 0;
+ int ahseen;
+ struct mbuf *n = NULL;
- hdrtype = -1; /*dummy, it is called IPPROTO_IP*/
+ if ((m->m_flags & M_PKTHDR) == 0)
+ return EINVAL;
- m = m0;
+ ahseen = 0;
+ hdrtype = -1; /*dummy, it is called IPPROTO_IP*/
- p = mtod(m, u_char *);
+ off = 0;
- (algo->init)(&algos, sav);
+ error = (algo->init)(&algos, sav);
+ if (error)
+ return error;
advancewidth = 0; /*safety*/
again:
/* gory. */
switch (hdrtype) {
- case -1: /*first one*/
+ case -1: /*first one only*/
{
/*
* copy ip hdr, modify to fit the AH checksum rule,
* then take a checksum.
- * XXX need to care about source routing... jesus.
*/
struct ip iphdr;
size_t hlen;
- bcopy((caddr_t)p, (caddr_t)&iphdr, sizeof(struct ip));
+ m_copydata(m, off, sizeof(iphdr), (caddr_t)&iphdr);
#ifdef _IP_VHL
hlen = IP_VHL_HL(iphdr.ip_vhl) << 2;
#else
@@ -691,22 +753,38 @@ again:
#endif
iphdr.ip_ttl = 0;
iphdr.ip_sum = htons(0);
- if (ip4_ah_cleartos) iphdr.ip_tos = 0;
+ if (ip4_ah_cleartos)
+ iphdr.ip_tos = 0;
iphdr.ip_off = htons(ntohs(iphdr.ip_off) & ip4_ah_offsetmask);
(algo->update)(&algos, (caddr_t)&iphdr, sizeof(struct ip));
if (hlen != sizeof(struct ip)) {
u_char *p;
- int i, j;
- int l, skip;
- u_char dummy[4];
+ int i, l, skip;
+
+ if (hlen > MCLBYTES) {
+ error = EMSGSIZE;
+ goto fail;
+ }
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (n && hlen > MLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_free(n);
+ n = NULL;
+ }
+ }
+ if (n == NULL) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_copydata(m, off, hlen, mtod(n, caddr_t));
/*
* IP options processing.
* See RFC2402 appendix A.
*/
- bzero(dummy, sizeof(dummy));
- p = mtod(m, u_char *);
+ p = mtod(n, u_char *);
i = sizeof(struct ip);
while (i < hlen) {
skip = 1;
@@ -730,23 +808,27 @@ again:
break;
}
if (l <= 0 || hlen - i < l) {
- printf("ah4_input: invalid IP option "
- "(type=%02x len=%02x)\n",
- p[i + IPOPT_OPTVAL],
- p[i + IPOPT_OLEN]);
- break;
+ ipseclog((LOG_ERR,
+ "ah4_calccksum: invalid IP option "
+ "(type=%02x len=%02x)\n",
+ p[i + IPOPT_OPTVAL],
+ p[i + IPOPT_OLEN]));
+ m_free(n);
+ n = NULL;
+ error = EINVAL;
+ goto fail;
}
- if (skip) {
- for (j = 0; j < l / sizeof(dummy); j++)
- (algo->update)(&algos, dummy, sizeof(dummy));
-
- (algo->update)(&algos, dummy, l % sizeof(dummy));
- } else
- (algo->update)(&algos, p + i, l);
+ if (skip)
+ bzero(p + i, l);
if (p[i + IPOPT_OPTVAL] == IPOPT_EOL)
break;
i += l;
}
+ p = mtod(n, u_char *) + sizeof(struct ip);
+ (algo->update)(&algos, p, hlen - sizeof(struct ip));
+
+ m_free(n);
+ n = NULL;
}
hdrtype = (iphdr.ip_p) & 0xff;
@@ -756,370 +838,306 @@ again:
case IPPROTO_AH:
{
- u_char dummy[4];
+ struct ah ah;
int siz;
int hdrsiz;
+ int totlen;
- hdrsiz = (sav->flags & SADB_X_EXT_OLD) ?
- sizeof(struct ah) : sizeof(struct newah);
-
- (algo->update)(&algos, p, hdrsiz);
-
- /* key data region. */
+ m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
+ hdrsiz = (sav->flags & SADB_X_EXT_OLD)
+ ? sizeof(struct ah)
+ : sizeof(struct newah);
siz = (*algo->sumsiz)(sav);
- bzero(&dummy[0], sizeof(dummy));
- while (sizeof(dummy) <= siz) {
- (algo->update)(&algos, dummy, sizeof(dummy));
- siz -= sizeof(dummy);
- }
- /* can't happen, but just in case */
- if (siz)
- (algo->update)(&algos, dummy, siz);
-
- /* padding region, just in case */
- siz = (((struct ah *)p)->ah_len << 2) - (*algo->sumsiz)(sav);
- if ((sav->flags & SADB_X_EXT_OLD) == 0)
- siz -= 4; /* sequence number field */
- if (0 < siz) {
- /* RFC 1826 */
- (algo->update)(&algos, p + hdrsiz + (*algo->sumsiz)(sav),
- siz);
- }
+ totlen = (ah.ah_len + 2) << 2;
- hdrtype = ((struct ah *)p)->ah_nxt;
- advancewidth = hdrsiz;
- advancewidth += ((struct ah *)p)->ah_len << 2;
- if ((sav->flags & SADB_X_EXT_OLD) == 0)
- advancewidth -= 4; /* sequence number field */
+ /*
+ * special treatment is necessary for the first one, not others
+ */
+ if (!ahseen) {
+ if (totlen > m->m_pkthdr.len - off ||
+ totlen > MCLBYTES) {
+ error = EMSGSIZE;
+ goto fail;
+ }
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (n && totlen > MLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_free(n);
+ n = NULL;
+ }
+ }
+ if (n == NULL) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_copydata(m, off, totlen, mtod(n, caddr_t));
+ n->m_len = totlen;
+ bzero(mtod(n, caddr_t) + hdrsiz, siz);
+ (algo->update)(&algos, mtod(n, caddr_t), n->m_len);
+ m_free(n);
+ n = NULL;
+ } else
+ ah_update_mbuf(m, off, totlen, algo, &algos);
+ ahseen++;
+
+ hdrtype = ah.ah_nxt;
+ advancewidth = totlen;
break;
}
default:
- printf("ah4_calccksum: unexpected hdrtype=%x; "
- "treating rest as payload\n", hdrtype);
- /*fall through*/
- case IPPROTO_ICMP:
- case IPPROTO_IGMP:
- case IPPROTO_IPIP:
-#ifdef INET6
- case IPPROTO_IPV6:
- case IPPROTO_ICMPV6:
-#endif
- case IPPROTO_UDP:
- case IPPROTO_TCP:
- case IPPROTO_ESP:
- while (m) {
- tlen = m->m_len - (p - mtod(m, u_char *));
- (algo->update)(&algos, p, tlen);
- m = m->m_next;
- p = m ? mtod(m, u_char *) : NULL;
- }
-
- advancewidth = 0; /*loop finished*/
+ ah_update_mbuf(m, off, m->m_pkthdr.len - off, algo, &algos);
+ advancewidth = m->m_pkthdr.len - off;
break;
}
- if (advancewidth) {
- /* is it safe? */
- while (m && advancewidth) {
- tlen = m->m_len - (p - mtod(m, u_char *));
- if (advancewidth < tlen) {
- p += advancewidth;
- advancewidth = 0;
- } else {
- advancewidth -= tlen;
- m = m->m_next;
- if (m)
- p = mtod(m, u_char *);
- else {
- printf("ERR: hit the end-of-mbuf...\n");
- p = NULL;
- }
- }
- }
+ off += advancewidth;
+ if (off < m->m_pkthdr.len)
+ goto again;
- if (m)
- goto again;
+ if (len < (*algo->sumsiz)(sav)) {
+ error = EINVAL;
+ goto fail;
}
- /* for HMAC algorithms... */
(algo->result)(&algos, &sumbuf[0]);
bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav));
+ if (n)
+ m_free(n);
+ return error;
+
+fail:
+ if (n)
+ m_free(n);
return error;
}
#ifdef INET6
/*
- * go generate the checksum. This function won't modify the mbuf chain
+ * Go generate the checksum. This function won't modify the mbuf chain
* except AH itself.
+ *
+ * NOTE: the function does not free mbuf on failure.
+ * Don't use m_copy(), it will try to share cluster mbuf by using refcnt.
*/
int
-ah6_calccksum(m0, ahdat, algo, sav)
- struct mbuf *m0;
+ah6_calccksum(m, ahdat, len, algo, sav)
+ struct mbuf *m;
caddr_t ahdat;
+ size_t len;
struct ah_algorithm *algo;
struct secasvar *sav;
{
- struct mbuf *m;
- int hdrtype;
- u_char *p;
- size_t advancewidth;
+ int newoff, off;
+ int proto, nxt;
+ struct mbuf *n = NULL;
+ int error;
+ int ahseen;
struct ah_algorithm_state algos;
- int tlen;
- int error = 0;
u_char sumbuf[AH_MAXSUMSIZE];
- int nest;
-
- hdrtype = -1; /*dummy, it is called IPPROTO_IPV6 */
-
- m = m0;
-
- p = mtod(m, u_char *);
- (algo->init)(&algos, sav);
+ if ((m->m_flags & M_PKTHDR) == 0)
+ return EINVAL;
+
+ error = (algo->init)(&algos, sav);
+ if (error)
+ return error;
+
+ off = 0;
+ proto = IPPROTO_IPV6;
+ nxt = -1;
+ ahseen = 0;
+
+ again:
+ newoff = ip6_nexthdr(m, off, proto, &nxt);
+ if (newoff < 0)
+ newoff = m->m_pkthdr.len;
+ else if (newoff <= off) {
+ error = EINVAL;
+ goto fail;
+ }
- advancewidth = 0; /*safety*/
- nest = 0;
+ switch (proto) {
+ case IPPROTO_IPV6:
+ /*
+ * special treatment is necessary for the first one, not others
+ */
+ if (off == 0) {
+ struct ip6_hdr ip6copy;
-again:
- if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
- ip6stat.ip6s_toomanyhdr++;
- error = EINVAL; /*XXX*/
- goto bad;
- }
+ if (newoff - off != sizeof(struct ip6_hdr)) {
+ error = EINVAL;
+ goto fail;
+ }
- /* gory. */
- switch (hdrtype) {
- case -1: /*first one*/
- {
- struct ip6_hdr ip6copy;
-
- bcopy(p, &ip6copy, sizeof(struct ip6_hdr));
- /* RFC2402 */
- ip6copy.ip6_flow = 0;
- ip6copy.ip6_vfc = IPV6_VERSION;
- ip6copy.ip6_hlim = 0;
- if (IN6_IS_ADDR_LINKLOCAL(&ip6copy.ip6_src))
- ip6copy.ip6_src.s6_addr16[1] = 0x0000;
- if (IN6_IS_ADDR_LINKLOCAL(&ip6copy.ip6_dst))
- ip6copy.ip6_dst.s6_addr16[1] = 0x0000;
- (algo->update)(&algos, (caddr_t)&ip6copy,
- sizeof(struct ip6_hdr));
- hdrtype = (((struct ip6_hdr *)p)->ip6_nxt) & 0xff;
- advancewidth = sizeof(struct ip6_hdr);
+ m_copydata(m, off, newoff - off, (caddr_t)&ip6copy);
+ /* RFC2402 */
+ ip6copy.ip6_flow = 0;
+ ip6copy.ip6_vfc &= ~IPV6_VERSION_MASK;
+ ip6copy.ip6_vfc |= IPV6_VERSION;
+ ip6copy.ip6_hlim = 0;
+ if (IN6_IS_ADDR_LINKLOCAL(&ip6copy.ip6_src))
+ ip6copy.ip6_src.s6_addr16[1] = 0x0000;
+ if (IN6_IS_ADDR_LINKLOCAL(&ip6copy.ip6_dst))
+ ip6copy.ip6_dst.s6_addr16[1] = 0x0000;
+ (algo->update)(&algos, (caddr_t)&ip6copy,
+ sizeof(struct ip6_hdr));
+ } else {
+ newoff = m->m_pkthdr.len;
+ ah_update_mbuf(m, off, m->m_pkthdr.len - off, algo,
+ &algos);
+ }
break;
- }
case IPPROTO_AH:
{
- u_char dummy[4];
int siz;
int hdrsiz;
- hdrsiz = (sav->flags & SADB_X_EXT_OLD) ?
- sizeof(struct ah) : sizeof(struct newah);
-
- (algo->update)(&algos, p, hdrsiz);
-
- /* key data region. */
+ hdrsiz = (sav->flags & SADB_X_EXT_OLD)
+ ? sizeof(struct ah)
+ : sizeof(struct newah);
siz = (*algo->sumsiz)(sav);
- bzero(&dummy[0], 4);
- while (4 <= siz) {
- (algo->update)(&algos, dummy, 4);
- siz -= 4;
- }
- /* can't happen, but just in case */
- if (siz)
- (algo->update)(&algos, dummy, siz);
-
- /* padding region, just in case */
- siz = (((struct ah *)p)->ah_len << 2) - (*algo->sumsiz)(sav);
- if ((sav->flags & SADB_X_EXT_OLD) == 0)
- siz -= 4; /* sequence number field */
- if (0 < siz) {
- (algo->update)(&algos, p + hdrsiz + (*algo->sumsiz)(sav),
- siz);
- }
- hdrtype = ((struct ah *)p)->ah_nxt;
- advancewidth = hdrsiz;
- advancewidth += ((struct ah *)p)->ah_len << 2;
- if ((sav->flags & SADB_X_EXT_OLD) == 0)
- advancewidth -= 4; /* sequence number field */
+ /*
+ * special treatment is necessary for the first one, not others
+ */
+ if (!ahseen) {
+ if (newoff - off > MCLBYTES) {
+ error = EMSGSIZE;
+ goto fail;
+ }
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (n && newoff - off > MLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_free(n);
+ n = NULL;
+ }
+ }
+ if (n == NULL) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_copydata(m, off, newoff - off, mtod(n, caddr_t));
+ n->m_len = newoff - off;
+ bzero(mtod(n, caddr_t) + hdrsiz, siz);
+ (algo->update)(&algos, mtod(n, caddr_t), n->m_len);
+ m_free(n);
+ n = NULL;
+ } else
+ ah_update_mbuf(m, off, newoff - off, algo, &algos);
+ ahseen++;
break;
}
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
{
- int hdrlen, optlen;
- u_int8_t *optp, *lastp = p, *optend, opt;
+ struct ip6_ext *ip6e;
+ int hdrlen, optlen;
+ u_int8_t *p, *optend, *optp;
- tlen = m->m_len - (p - mtod(m, u_char *));
- /* We assume all the options is contained in a single mbuf */
- if (tlen < sizeof(struct ip6_ext)) {
- error = EINVAL;
- goto bad;
- }
- hdrlen = (((struct ip6_ext *)p)->ip6e_len + 1) << 3;
- hdrtype = (int)((struct ip6_ext *)p)->ip6e_nxt;
- if (tlen < hdrlen) {
+ if (newoff - off > MCLBYTES) {
+ error = EMSGSIZE;
+ goto fail;
+ }
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (n && newoff - off > MLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_free(n);
+ n = NULL;
+ }
+ }
+ if (n == NULL) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_copydata(m, off, newoff - off, mtod(n, caddr_t));
+ n->m_len = newoff - off;
+
+ ip6e = mtod(n, struct ip6_ext *);
+ hdrlen = (ip6e->ip6e_len + 1) << 3;
+ if (newoff - off < hdrlen) {
error = EINVAL;
- goto bad;
- }
- optend = p + hdrlen;
-
- /*
- * ICV calculation for the options header including all
- * options. This part is a little tricky since there are
- * two type of options; mutable and immutable. Our approach
- * is to calculate ICV for a consecutive immutable options
- * at once. Here is an example. In the following figure,
- * suppose that we've calculated ICV from the top of the
- * header to MutableOpt1, which is a mutable option.
- * lastp points to the end of MutableOpt1. Some immutable
- * options follows MutableOpt1, and we encounter a new
- * mutable option; MutableOpt2. optp points to the head
- * of MutableOpt2. In this situation, uncalculated immutable
- * field is the field from lastp to optp+2 (note that the
- * type and the length fields are considered as immutable
- * even in a mutable option). So we first calculate ICV
- * for the field as immutable, then calculate from optp+2
- * to the end of MutableOpt2, whose length is optlen-2,
- * where optlen is the length of MutableOpt2. Finally,
- * lastp is updated to point to the end of MutableOpt2
- * for further calculation. The updated point is shown as
- * lastp' in the figure.
- * <------ optlen ----->
- * -----------+-------------------+---+---+-----------+
- * MutableOpt1|ImmutableOptions...|typ|len|MutableOpt2|
- * -----------+-------------------+---+---+-----------+
- * ^ ^ ^
- * lastp optp optp+2
- * <---- optp + 2 - lastp -----><-optlen-2->
- * ^
- * lastp'
- */
- for (optp = p + 2; optp < optend; optp += optlen) {
- opt = optp[0];
- if (opt == IP6OPT_PAD1) {
- optlen = 1;
- } else {
- if (optp + 2 > optend) {
- error = EINVAL; /* malformed option */
- goto bad;
- }
- optlen = optp[1] + 2;
- if (opt & IP6OPT_MUTABLE) {
- /*
- * ICV calc. for the (consecutive)
- * immutable field followd by the
- * option.
- */
- (algo->update)(&algos, lastp,
- optp + 2 - lastp);
- if (optlen - 2 > ZEROBUFLEN) {
- error = EINVAL; /* XXX */
- goto bad;
- }
- /*
- * ICV calc. for the mutable
- * option using an all-0 buffer.
- */
- (algo->update)(&algos, zerobuf,
- optlen - 2);
- lastp = optp + optlen;
- }
- }
- }
- /*
- * Wrap up the calulation; compute ICV for the consecutive
- * immutable options at the end of the header(if any).
- */
- (algo->update)(&algos, lastp, p + hdrlen - lastp);
- advancewidth = hdrlen;
- break;
+ m_free(n);
+ n = NULL;
+ goto fail;
+ }
+ p = mtod(n, u_int8_t *);
+ optend = p + hdrlen;
+
+ /*
+ * ICV calculation for the options header including all
+ * options. This part is a little tricky since there are
+ * two type of options; mutable and immutable. We try to
+ * null-out mutable ones here.
+ */
+ optp = p + 2;
+ while (optp < optend) {
+ if (optp[0] == IP6OPT_PAD1)
+ optlen = 1;
+ else {
+ if (optp + 2 > optend) {
+ error = EINVAL;
+ m_free(n);
+ n = NULL;
+ goto fail;
+ }
+ optlen = optp[1] + 2;
+
+ if (optp[0] & IP6OPT_MUTABLE)
+ bzero(optp + 2, optlen - 2);
+ }
+
+ optp += optlen;
+ }
+
+ (algo->update)(&algos, mtod(n, caddr_t), n->m_len);
+ m_free(n);
+ n = NULL;
+ break;
}
+
case IPPROTO_ROUTING:
- {
- /*
- * For an input packet, we can just calculate `as is'.
- * For an output packet, we assume ip6_output have already
- * made packet how it will be received at the final destination.
- * So we'll only check if the header is malformed.
- */
- int hdrlen;
-
- tlen = m->m_len - (p - mtod(m, u_char *));
- /* We assume all the options is contained in a single mbuf */
- if (tlen < sizeof(struct ip6_ext)) {
- error = EINVAL;
- goto bad;
- }
- hdrlen = (((struct ip6_ext *)p)->ip6e_len + 1) << 3;
- hdrtype = (int)((struct ip6_ext *)p)->ip6e_nxt;
- if (tlen < hdrlen) {
- error = EINVAL;
- goto bad;
- }
- advancewidth = hdrlen;
- (algo->update)(&algos, p, hdrlen);
- break;
- }
- default:
- printf("ah6_calccksum: unexpected hdrtype=%x; "
- "treating rest as payload\n", hdrtype);
- /*fall through*/
- case IPPROTO_ICMP:
- case IPPROTO_IGMP:
- case IPPROTO_IPIP: /*?*/
- case IPPROTO_IPV6:
- case IPPROTO_ICMPV6:
- case IPPROTO_UDP:
- case IPPROTO_TCP:
- case IPPROTO_ESP:
- while (m) {
- tlen = m->m_len - (p - mtod(m, u_char *));
- (algo->update)(&algos, p, tlen);
- m = m->m_next;
- p = m ? mtod(m, u_char *) : NULL;
- }
+ /*
+ * For an input packet, we can just calculate `as is'.
+ * For an output packet, we assume ip6_output have already
+ * made packet how it will be received at the final
+ * destination.
+ */
+ /* FALLTHROUGH */
- advancewidth = 0; /*loop finished*/
+ default:
+ ah_update_mbuf(m, off, newoff - off, algo, &algos);
break;
}
- if (advancewidth) {
- /* is it safe? */
- while (m && advancewidth) {
- tlen = m->m_len - (p - mtod(m, u_char *));
- if (advancewidth < tlen) {
- p += advancewidth;
- advancewidth = 0;
- } else {
- advancewidth -= tlen;
- m = m->m_next;
- if (m)
- p = mtod(m, u_char *);
- else {
- printf("ERR: hit the end-of-mbuf...\n");
- p = NULL;
- }
- }
- }
+ if (newoff < m->m_pkthdr.len) {
+ proto = nxt;
+ off = newoff;
+ goto again;
+ }
- if (m)
- goto again;
+ if (len < (*algo->sumsiz)(sav)) {
+ error = EINVAL;
+ goto fail;
}
- /* for HMAC algorithms... */
(algo->result)(&algos, &sumbuf[0]);
bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav));
- return(0);
-
- bad:
- return(error);
+ /* just in case */
+ if (n)
+ m_free(n);
+ return 0;
+fail:
+ /* just in case */
+ if (n)
+ m_free(n);
+ return error;
}
#endif
diff --git a/sys/netinet6/ah_input.c b/sys/netinet6/ah_input.c
index e8aa77e4e661..1f59bf9eaa38 100644
--- a/sys/netinet6/ah_input.c
+++ b/sys/netinet6/ah_input.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ah_input.c,v 1.29 2000/05/29 08:33:53 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -35,7 +36,6 @@
#include "opt_inet.h"
#include "opt_inet6.h"
-#include "opt_ipsec.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -64,15 +64,17 @@
#endif
#ifdef INET6
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#endif
#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>
@@ -83,19 +85,24 @@
#define KEYDEBUG(lev,arg)
#endif
-#include <netinet/ipprotosw.h>
-
#include <machine/stdarg.h>
#include <net/net_osdep.h>
+#define IPLEN_FLIPPED
+
#ifdef INET
+#include <netinet/ipprotosw.h>
extern struct ipprotosw inetsw[];
void
-ah4_input(m, off, proto)
+#if __STDC__
+ah4_input(struct mbuf *m, ...)
+#else
+ah4_input(m, va_alist)
struct mbuf *m;
- int off, proto;
+ va_dcl
+#endif
{
struct ip *ip;
struct ah *ah;
@@ -108,12 +115,20 @@ ah4_input(m, off, proto)
u_int16_t nxt;
size_t hlen;
int s;
+ int off, proto;
+ va_list ap;
+ va_start(ap, m);
+ off = va_arg(ap, int);
+ proto = va_arg(ap, int);
+ va_end(ap);
+
+#ifndef PULLDOWN_TEST
if (m->m_len < off + sizeof(struct newah)) {
m = m_pullup(m, off + sizeof(struct newah));
if (!m) {
- printf("IPv4 AH input: can't pullup;"
- "dropping the packet for simplicity\n");
+ ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
+ "dropping the packet for simplicity\n"));
ipsecstat.in_inval++;
goto fail;
}
@@ -121,6 +136,16 @@ ah4_input(m, off, proto)
ip = mtod(m, struct ip *);
ah = (struct ah *)(((caddr_t)ip) + off);
+#else
+ ip = mtod(m, struct ip *);
+ IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
+ if (ah == NULL) {
+ ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
+ "dropping the packet for simplicity\n"));
+ ipsecstat.in_inval++;
+ goto fail;
+ }
+#endif
nxt = ah->ah_nxt;
#ifdef _IP_VHL
hlen = IP_VHL_HL(ip->ip_vhl) << 2;
@@ -134,9 +159,9 @@ ah4_input(m, off, proto)
if ((sav = key_allocsa(AF_INET,
(caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
IPPROTO_AH, spi)) == 0) {
- printf("IPv4 AH input: no key association found for spi %u;"
- "dropping the packet for simplicity\n",
- (u_int32_t)ntohl(spi));
+ ipseclog((LOG_WARNING,
+ "IPv4 AH input: no key association found for spi %u\n",
+ (u_int32_t)ntohl(spi)));
ipsecstat.in_nosa++;
goto fail;
}
@@ -144,17 +169,16 @@ ah4_input(m, off, proto)
printf("DP ah4_input called to allocate SA:%p\n", sav));
if (sav->state != SADB_SASTATE_MATURE
&& sav->state != SADB_SASTATE_DYING) {
- printf("IPv4 AH input: non-mature/dying SA found for spi %u; "
- "dropping the packet for simplicity\n",
- (u_int32_t)ntohl(spi));
+ ipseclog((LOG_DEBUG,
+ "IPv4 AH input: non-mature/dying SA found for spi %u\n",
+ (u_int32_t)ntohl(spi)));
ipsecstat.in_badspi++;
goto fail;
}
if (sav->alg_auth == SADB_AALG_NONE) {
- printf("IPv4 AH input: unspecified authentication algorithm "
- "for spi %u;"
- "dropping the packet for simplicity\n",
- (u_int32_t)ntohl(spi));
+ ipseclog((LOG_DEBUG, "IPv4 AH input: "
+ "unspecified authentication algorithm for spi %u\n",
+ (u_int32_t)ntohl(spi)));
ipsecstat.in_badspi++;
goto fail;
}
@@ -172,20 +196,49 @@ ah4_input(m, off, proto)
sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
+ /*
+ * Here, we do not do "siz1 == siz". This is because the way
+ * RFC240[34] section 2 is written. They do not require truncation
+ * to 96 bits.
+ * For example, Microsoft IPsec stack attaches 160 bits of
+ * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1,
+ * 32 bits of padding is attached.
+ *
+ * There are two downsides to this specification.
+ * They have no real harm, however, they leave us fuzzy feeling.
+ * - if we attach more than 96 bits of authentication data onto AH,
+ * we will never notice about possible modification by rogue
+ * intermediate nodes.
+ * Since extra bits in AH checksum is never used, this constitutes
+ * no real issue, however, it is wacky.
+ * - even if the peer attaches big authentication data, we will never
+ * notice the difference, since longer authentication data will just
+ * work.
+ *
+ * We may need some clarification in the spec.
+ */
+ if (siz1 < siz) {
+ ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input "
+ "(%lu, should be at least %lu): %s\n",
+ (u_long)siz1, (u_long)siz,
+ ipsec4_logpacketstr(ip, spi)));
+ ipsecstat.in_inval++;
+ goto fail;
+ }
if ((ah->ah_len << 2) - sizoff != siz1) {
- log(LOG_NOTICE, "sum length mismatch in IPv4 AH input "
- "(%d should be %u): %s\n",
- (ah->ah_len << 2) - sizoff, (unsigned int)siz1,
- ipsec4_logpacketstr(ip, spi));
+ ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input "
+ "(%d should be %lu): %s\n",
+ (ah->ah_len << 2) - sizoff, (u_long)siz1,
+ ipsec4_logpacketstr(ip, spi)));
ipsecstat.in_inval++;
goto fail;
}
+#ifndef PULLDOWN_TEST
if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) {
m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1);
if (!m) {
- printf("IPv4 AH input: can't pullup;"
- "dropping the packet for simplicity\n");
+ ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
ipsecstat.in_inval++;
goto fail;
}
@@ -193,6 +246,15 @@ ah4_input(m, off, proto)
ip = mtod(m, struct ip *);
ah = (struct ah *)(((caddr_t)ip) + off);
}
+#else
+ IP6_EXTHDR_GET(ah, struct ah *, m, off,
+ sizeof(struct ah) + sizoff + siz1);
+ if (ah == NULL) {
+ ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
+ ipsecstat.in_inval++;
+ goto fail;
+ }
+#endif
}
/*
@@ -203,9 +265,9 @@ ah4_input(m, off, proto)
; /*okey*/
else {
ipsecstat.in_ahreplay++;
- log(LOG_AUTH, "replay packet in IPv4 AH input: %s %s\n",
- ipsec4_logpacketstr(ip, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING,
+ "replay packet in IPv4 AH input: %s %s\n",
+ ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
goto fail;
}
}
@@ -216,12 +278,14 @@ ah4_input(m, off, proto)
*/
cksum = malloc(siz1, M_TEMP, M_NOWAIT);
if (!cksum) {
- printf("IPv4 AH input: couldn't alloc temporary region for cksum\n");
+ ipseclog((LOG_DEBUG, "IPv4 AH input: "
+ "couldn't alloc temporary region for cksum\n"));
ipsecstat.in_inval++;
goto fail;
}
-
+
{
+#if 1
/*
* some of IP header fields are flipped to the host endian.
* convert them back to network endian. VERY stupid.
@@ -229,18 +293,21 @@ ah4_input(m, off, proto)
ip->ip_len = htons(ip->ip_len + hlen);
ip->ip_id = htons(ip->ip_id);
ip->ip_off = htons(ip->ip_off);
- if (ah4_calccksum(m, (caddr_t)cksum, algo, sav)) {
+#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_id = ntohs(ip->ip_id);
ip->ip_off = ntohs(ip->ip_off);
+#endif
}
{
@@ -255,9 +322,9 @@ ah4_input(m, off, proto)
}
if (bcmp(sumpos, cksum, siz) != 0) {
- log(LOG_AUTH, "checksum mismatch in IPv4 AH input: %s %s\n",
- ipsec4_logpacketstr(ip, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING,
+ "checksum mismatch in IPv4 AH input: %s %s\n",
+ ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
free(cksum, M_TEMP);
ipsecstat.in_ahauthfail++;
goto fail;
@@ -269,23 +336,66 @@ ah4_input(m, off, proto)
m->m_flags |= M_AUTHIPHDR;
m->m_flags |= M_AUTHIPDGM;
- /* M_AUTH related flags might be cleared here in the future */
+#if 0
+ /*
+ * looks okey, but we need more sanity check.
+ * XXX should elaborate.
+ */
+ if (ah->ah_nxt == IPPROTO_IPIP || ah->ah_nxt == IPPROTO_IP) {
+ struct ip *nip;
+ size_t sizoff;
+
+ sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
+
+ if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) {
+ m = m_pullup(m, off + sizeof(struct ah)
+ + sizoff + siz1 + hlen);
+ if (!m) {
+ ipseclog((LOG_DEBUG,
+ "IPv4 AH input: can't pullup\n"));
+ ipsecstat.in_inval++;
+ goto fail;
+ }
+ }
+
+ nip = (struct ip *)((u_char *)(ah + 1) + sizoff + siz1);
+ if (nip->ip_src.s_addr != ip->ip_src.s_addr
+ || nip->ip_dst.s_addr != ip->ip_dst.s_addr) {
+ m->m_flags &= ~M_AUTHIPHDR;
+ m->m_flags &= ~M_AUTHIPDGM;
+ }
+ }
+#ifdef INET6
+ else if (ah->ah_nxt == IPPROTO_IPV6) {
+ m->m_flags &= ~M_AUTHIPHDR;
+ m->m_flags &= ~M_AUTHIPDGM;
+ }
+#endif /*INET6*/
+#endif /*0*/
if (m->m_flags & M_AUTHIPHDR
&& m->m_flags & M_AUTHIPDGM) {
+#if 0
+ ipseclog((LOG_DEBUG,
+ "IPv4 AH input: authentication succeess\n"));
+#endif
ipsecstat.in_ahauthsucc++;
} else {
- log(LOG_AUTH, "authentication failed in IPv4 AH input: %s %s\n",
- ipsec4_logpacketstr(ip, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING,
+ "authentication failed in IPv4 AH input: %s %s\n",
+ ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
ipsecstat.in_ahauthfail++;
+ goto fail;
}
/*
* update sequence number.
*/
if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
- (void)ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav);
+ if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
+ ipsecstat.in_ahreplay++;
+ goto fail;
+ }
}
/* was it transmitted over the IPsec tunnel SA? */
@@ -321,13 +431,22 @@ ah4_input(m, off, proto)
ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
if (!key_checktunnelsanity(sav, AF_INET,
(caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
- log(LOG_NOTICE, "ipsec tunnel address mismatch in IPv4 AH input: %s %s\n",
- ipsec4_logpacketstr(ip, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
+ "in IPv4 AH input: %s %s\n",
+ ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
ipsecstat.in_inval++;
goto fail;
}
+#if 0 /* XXX should we call ipfw rather than ipsec_in_reject? */
+ /* drop it if it does not match the default policy */
+ if (ipsec4_in_reject(m, NULL)) {
+ ipsecstat.in_polvio++;
+ goto fail;
+ }
+#endif
+
+#if 1
/*
* Should the inner packet be considered authentic?
* My current answer is: NO.
@@ -349,6 +468,7 @@ ah4_input(m, off, proto)
*/
m->m_flags &= ~M_AUTHIPHDR;
m->m_flags &= ~M_AUTHIPDGM;
+#endif
key_sa_recordxfer(sav, m);
@@ -365,8 +485,6 @@ ah4_input(m, off, proto)
} else {
/*
* strip off AH.
- * We do deep-copy since KAME requires that
- * the packet is placed in a single external mbuf.
*/
size_t stripsiz = 0;
@@ -379,17 +497,62 @@ ah4_input(m, off, proto)
}
ip = mtod(m, struct ip *);
+#ifndef PULLDOWN_TEST
+ /*
+ * We do deep-copy since KAME requires that
+ * the packet is placed in a single external mbuf.
+ */
ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
m->m_data += stripsiz;
m->m_len -= stripsiz;
m->m_pkthdr.len -= stripsiz;
+#else
+ /*
+ * even in m_pulldown case, we need to strip off AH so that
+ * we can compute checksum for multiple AH correctly.
+ */
+ if (m->m_len >= stripsiz + off) {
+ ovbcopy((caddr_t)ip, ((caddr_t)ip) + stripsiz, off);
+ m->m_data += stripsiz;
+ m->m_len -= stripsiz;
+ m->m_pkthdr.len -= stripsiz;
+ } else {
+ /*
+ * this comes with no copy if the boundary is on
+ * cluster
+ */
+ struct mbuf *n;
+ n = m_split(m, off, M_DONTWAIT);
+ if (n == NULL) {
+ /* m is retained by m_split */
+ goto fail;
+ }
+ m_adj(n, stripsiz);
+ m_cat(m, n);
+ /* m_cat does not update m_pkthdr.len */
+ m->m_pkthdr.len += n->m_pkthdr.len;
+ }
+#endif
+
+ if (m->m_len < sizeof(*ip)) {
+ m = m_pullup(m, sizeof(*ip));
+ if (m == NULL) {
+ ipsecstat.in_inval++;
+ goto fail;
+ }
+ }
ip = mtod(m, struct ip *);
- /*ip_len is in host endian*/
+#ifdef IPLEN_FLIPPED
ip->ip_len = ip->ip_len - stripsiz;
+#else
+ ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
+#endif
ip->ip_p = nxt;
/* forget about IP hdr checksum, the check has already been passed */
+ key_sa_recordxfer(sav, m);
+
if (nxt != IPPROTO_DONE)
(*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
else
@@ -436,18 +599,26 @@ ah6_input(mp, offp, proto)
u_int16_t nxt;
int s;
+#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE);
-
+ ah = (struct ah *)(mtod(m, caddr_t) + off);
+#else
+ 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++;
+ return IPPROTO_DONE;
+ }
+#endif
ip6 = mtod(m, struct ip6_hdr *);
- ah = (struct ah *)(((caddr_t)ip6) + off);
-
nxt = ah->ah_nxt;
/* find the sassoc. */
spi = ah->ah_spi;
if (ntohs(ip6->ip6_plen) == 0) {
- printf("IPv6 AH input: AH with IPv6 jumbogram is not supported.\n");
+ ipseclog((LOG_ERR, "IPv6 AH input: "
+ "AH with IPv6 jumbogram is not supported.\n"));
ipsec6stat.in_inval++;
goto fail;
}
@@ -455,9 +626,9 @@ ah6_input(mp, offp, proto)
if ((sav = key_allocsa(AF_INET6,
(caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
IPPROTO_AH, spi)) == 0) {
- printf("IPv6 AH input: no key association found for spi %u;"
- "dropping the packet for simplicity\n",
- (u_int32_t)ntohl(spi));
+ ipseclog((LOG_WARNING,
+ "IPv6 AH input: no key association found for spi %u\n",
+ (u_int32_t)ntohl(spi)));
ipsec6stat.in_nosa++;
goto fail;
}
@@ -465,17 +636,16 @@ ah6_input(mp, offp, proto)
printf("DP ah6_input called to allocate SA:%p\n", sav));
if (sav->state != SADB_SASTATE_MATURE
&& sav->state != SADB_SASTATE_DYING) {
- printf("IPv6 AH input: non-mature/dying SA found for spi %u; "
- "dropping the packet for simplicity\n",
- (u_int32_t)ntohl(spi));
+ ipseclog((LOG_DEBUG,
+ "IPv6 AH input: non-mature/dying SA found for spi %u; ",
+ (u_int32_t)ntohl(spi)));
ipsec6stat.in_badspi++;
goto fail;
}
if (sav->alg_auth == SADB_AALG_NONE) {
- printf("IPv6 AH input: unspecified authentication algorithm "
- "for spi %u;"
- "dropping the packet for simplicity\n",
- (u_int32_t)ntohl(spi));
+ ipseclog((LOG_DEBUG, "IPv6 AH input: "
+ "unspecified authentication algorithm for spi %u\n",
+ (u_int32_t)ntohl(spi)));
ipsec6stat.in_badspi++;
goto fail;
}
@@ -493,15 +663,38 @@ ah6_input(mp, offp, proto)
sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
+ /*
+ * Here, we do not do "siz1 == siz". See ah4_input() for complete
+ * description.
+ */
+ if (siz1 < siz) {
+ ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input "
+ "(%lu, should be at least %lu): %s\n",
+ (u_long)siz1, (u_long)siz,
+ ipsec6_logpacketstr(ip6, spi)));
+ ipsec6stat.in_inval++;
+ goto fail;
+ }
if ((ah->ah_len << 2) - sizoff != siz1) {
- log(LOG_NOTICE, "sum length mismatch in IPv6 AH input "
- "(%d should be %u): %s\n",
- (ah->ah_len << 2) - sizoff, (unsigned int)siz1,
- ipsec6_logpacketstr(ip6, spi));
+ ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input "
+ "(%d should be %lu): %s\n",
+ (ah->ah_len << 2) - sizoff, (u_long)siz1,
+ ipsec6_logpacketstr(ip6, spi)));
ipsec6stat.in_inval++;
goto fail;
}
+#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, IPPROTO_DONE);
+#else
+ IP6_EXTHDR_GET(ah, struct ah *, m, off,
+ sizeof(struct ah) + sizoff + siz1);
+ if (ah == NULL) {
+ ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part"));
+ ipsecstat.in_inval++;
+ m = NULL;
+ goto fail;
+ }
+#endif
}
/*
@@ -512,9 +705,10 @@ ah6_input(mp, offp, proto)
; /*okey*/
else {
ipsec6stat.in_ahreplay++;
- log(LOG_AUTH, "replay packet in IPv6 AH input: %s %s\n",
- ipsec6_logpacketstr(ip6, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING,
+ "replay packet in IPv6 AH input: %s %s\n",
+ ipsec6_logpacketstr(ip6, spi),
+ ipsec_logsastr(sav)));
goto fail;
}
}
@@ -525,12 +719,13 @@ ah6_input(mp, offp, proto)
*/
cksum = malloc(siz1, M_TEMP, M_NOWAIT);
if (!cksum) {
- printf("IPv6 AH input: couldn't alloc temporary region for cksum\n");
+ ipseclog((LOG_DEBUG, "IPv6 AH input: "
+ "couldn't alloc temporary region for cksum\n"));
ipsec6stat.in_inval++;
goto fail;
}
-
- if (ah6_calccksum(m, (caddr_t)cksum, algo, sav)) {
+
+ if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
free(cksum, M_TEMP);
ipsec6stat.in_inval++;
goto fail;
@@ -549,9 +744,9 @@ ah6_input(mp, offp, proto)
}
if (bcmp(sumpos, cksum, siz) != 0) {
- log(LOG_AUTH, "checksum mismatch in IPv6 AH input: %s %s\n",
- ipsec6_logpacketstr(ip6, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING,
+ "checksum mismatch in IPv6 AH input: %s %s\n",
+ ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
free(cksum, M_TEMP);
ipsec6stat.in_ahauthfail++;
goto fail;
@@ -563,23 +758,58 @@ ah6_input(mp, offp, proto)
m->m_flags |= M_AUTHIPHDR;
m->m_flags |= M_AUTHIPDGM;
- /* M_AUTH related flags might be cleared here in the future */
+#if 0
+ /*
+ * looks okey, but we need more sanity check.
+ * XXX should elaborate.
+ */
+ if (ah->ah_nxt == IPPROTO_IPV6) {
+ struct ip6_hdr *nip6;
+ size_t sizoff;
+
+ sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
+
+ IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1
+ + sizeof(struct ip6_hdr), IPPROTO_DONE);
+
+ nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1);
+ if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src)
+ || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) {
+ m->m_flags &= ~M_AUTHIPHDR;
+ m->m_flags &= ~M_AUTHIPDGM;
+ }
+ } else if (ah->ah_nxt == IPPROTO_IPIP) {
+ m->m_flags &= ~M_AUTHIPHDR;
+ m->m_flags &= ~M_AUTHIPDGM;
+ } else if (ah->ah_nxt == IPPROTO_IP) {
+ m->m_flags &= ~M_AUTHIPHDR;
+ m->m_flags &= ~M_AUTHIPDGM;
+ }
+#endif
if (m->m_flags & M_AUTHIPHDR
&& m->m_flags & M_AUTHIPDGM) {
+#if 0
+ ipseclog((LOG_DEBUG,
+ "IPv6 AH input: authentication succeess\n"));
+#endif
ipsec6stat.in_ahauthsucc++;
} else {
- log(LOG_AUTH, "authentication failed in IPv6 AH input: %s %s\n",
- ipsec6_logpacketstr(ip6, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING,
+ "authentication failed in IPv6 AH input: %s %s\n",
+ ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
ipsec6stat.in_ahauthfail++;
+ goto fail;
}
/*
* update sequence number.
*/
if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
- (void)ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav);
+ if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
+ ipsec6stat.in_ahreplay++;
+ goto fail;
+ }
}
/* was it transmitted over the IPsec tunnel SA? */
@@ -619,19 +849,30 @@ ah6_input(mp, offp, proto)
ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
if (!key_checktunnelsanity(sav, AF_INET6,
(caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
- log(LOG_NOTICE, "ipsec tunnel address mismatch in IPv6 AH input: %s %s\n",
- ipsec6_logpacketstr(ip6, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
+ "in IPv6 AH input: %s %s\n",
+ ipsec6_logpacketstr(ip6, spi),
+ ipsec_logsastr(sav)));
ipsec6stat.in_inval++;
goto fail;
}
+#if 0 /* XXX should we call ipfw rather than ipsec_in_reject? */
+ /* drop it if it does not match the default policy */
+ if (ipsec6_in_reject(m, NULL)) {
+ ipsec6stat.in_polvio++;
+ goto fail;
+ }
+#endif
+
+#if 1
/*
* should the inner packet be considered authentic?
* see comment in ah4_input().
*/
m->m_flags &= ~M_AUTHIPHDR;
m->m_flags &= ~M_AUTHIPDGM;
+#endif
key_sa_recordxfer(sav, m);
@@ -648,8 +889,6 @@ ah6_input(mp, offp, proto)
} else {
/*
* strip off AH.
- * We do deep-copy since KAME requires that
- * the packet is placed in a single mbuf.
*/
size_t stripsiz = 0;
char *prvnxtp;
@@ -671,13 +910,45 @@ ah6_input(mp, offp, proto)
}
ip6 = mtod(m, struct ip6_hdr *);
- ovbcopy((caddr_t)ip6, (caddr_t)(((u_char *)ip6) + stripsiz),
- off);
+#ifndef PULLDOWN_TEST
+ /*
+ * We do deep-copy since KAME requires that
+ * the packet is placed in a single mbuf.
+ */
+ ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
m->m_data += stripsiz;
m->m_len -= stripsiz;
m->m_pkthdr.len -= stripsiz;
+#else
+ /*
+ * even in m_pulldown case, we need to strip off AH so that
+ * we can compute checksum for multiple AH correctly.
+ */
+ if (m->m_len >= stripsiz + off) {
+ ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
+ m->m_data += stripsiz;
+ m->m_len -= stripsiz;
+ m->m_pkthdr.len -= stripsiz;
+ } else {
+ /*
+ * this comes with no copy if the boundary is on
+ * cluster
+ */
+ struct mbuf *n;
+ n = m_split(m, off, M_DONTWAIT);
+ if (n == NULL) {
+ /* m is retained by m_split */
+ goto fail;
+ }
+ m_adj(n, stripsiz);
+ m_cat(m, n);
+ /* m_cat does not update m_pkthdr.len */
+ m->m_pkthdr.len += n->m_pkthdr.len;
+ }
+#endif
ip6 = mtod(m, struct ip6_hdr *);
+ /* XXX jumbogram */
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
key_sa_recordxfer(sav, m);
diff --git a/sys/netinet6/ah_output.c b/sys/netinet6/ah_output.c
index c33dfe867346..477c589534c8 100644
--- a/sys/netinet6/ah_output.c
+++ b/sys/netinet6/ah_output.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ah_output.c,v 1.22 2000/07/03 13:23:28 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,18 +28,14 @@
* 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.
- *
- * $FreeBSD$
*/
/*
* RFC1826/2402 authentication header.
*/
+#include "opt_inet.h"
#include "opt_inet6.h"
-#include "opt_ipsec.h"
-
-#define ahdprintf(x) printf x
#include <sys/param.h>
#include <sys/systm.h>
@@ -57,27 +56,23 @@
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_var.h>
-#include <netinet/in_pcb.h>
#ifdef INET6
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#endif
#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>
#include <netkey/keydb.h>
-#ifdef IPSEC_DEBUG
-#include <netkey/key_debug.h>
-#else
-#define KEYDEBUG(lev,arg)
-#endif
#include <net/net_osdep.h>
@@ -103,15 +98,15 @@ ah_hdrsiz(isr)
panic("unsupported mode passed to ah_hdrsiz");
if (isr->sav == NULL)
- goto contrive;
+ goto estimate;
if (isr->sav->state != SADB_SASTATE_MATURE
&& isr->sav->state != SADB_SASTATE_DYING)
- goto contrive;
+ goto estimate;
/* we need transport mode AH. */
algo = &ah_algorithms[isr->sav->alg_auth];
if (!algo)
- goto contrive;
+ goto estimate;
/*
* XXX
@@ -128,7 +123,7 @@ ah_hdrsiz(isr)
return hdrsiz;
- contrive:
+ estimate:
/* ASSUMING:
* sizeof(struct newah) > sizeof(struct ah).
* 16 = (16 + 3) & ~(4 - 1).
@@ -166,12 +161,11 @@ ah4_output(m, isr)
struct ip *ip;
ip = mtod(m, struct ip *);
- printf("ah4_output: internal error: "
- "sav->replay is null: "
- "%x->%x, SPI=%u\n",
+ ipseclog((LOG_DEBUG, "ah4_output: internal error: "
+ "sav->replay is null: %x->%x, SPI=%u\n",
(u_int32_t)ntohl(ip->ip_src.s_addr),
(u_int32_t)ntohl(ip->ip_dst.s_addr),
- (u_int32_t)ntohl(sav->spi));
+ (u_int32_t)ntohl(sav->spi)));
ipsecstat.out_inval++;
m_freem(m);
return EINVAL;
@@ -209,7 +203,8 @@ ah4_output(m, isr)
struct mbuf *n;
MGET(n, M_DONTWAIT, MT_DATA);
if (!n) {
- printf("ENOBUFS in ah4_output %d\n", __LINE__);
+ ipseclog((LOG_DEBUG, "ENOBUFS in ah4_output %d\n",
+ __LINE__));
m_freem(m);
return ENOBUFS;
}
@@ -249,6 +244,17 @@ ah4_output(m, isr)
ahdr->ah_nxt = ip->ip_p;
ahdr->ah_reserve = htons(0);
ahdr->ah_spi = spi;
+ if (sav->replay->count == ~0) {
+ if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
+ /* XXX Is it noisy ? */
+ ipseclog((LOG_WARNING,
+ "replay counter overflowed. %s\n",
+ ipsec_logsastr(sav)));
+ ipsecstat.out_inval++;
+ m_freem(m);
+ return EINVAL;
+ }
+ }
sav->replay->count++;
/*
* XXX sequence number must not be cycled, if the SA is
@@ -265,7 +271,7 @@ ah4_output(m, isr)
if (ahlen < (IP_MAXPACKET - ntohs(ip->ip_len)))
ip->ip_len = htons(ntohs(ip->ip_len) + ahlen);
else {
- printf("IPv4 AH output: size exceeds limit\n");
+ ipseclog((LOG_ERR, "IPv4 AH output: size exceeds limit\n"));
ipsecstat.out_inval++;
m_freem(m);
return EMSGSIZE;
@@ -288,9 +294,11 @@ ah4_output(m, isr)
* calcurate the checksum, based on security association
* and the algorithm specified.
*/
- error = ah4_calccksum(m, (caddr_t)ahsumpos, algo, sav);
+ error = ah4_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav);
if (error) {
- printf("error after ah4_calccksum, called from ah4_output");
+ ipseclog((LOG_ERR,
+ "error after ah4_calccksum, called from ah4_output"));
+ m_freem(m);
m = NULL;
ipsecstat.out_inval++;
return error;
@@ -314,7 +322,7 @@ ah_hdrlen(sav)
{
struct ah_algorithm *algo;
int plen, ahlen;
-
+
algo = &ah_algorithms[sav->alg_auth];
if (sav->flags & SADB_X_EXT_OLD) {
/* RFC 1826 */
@@ -352,7 +360,7 @@ ah6_output(m, nexthdrp, md, isr)
struct ip6_hdr *ip6;
if (m->m_len < sizeof(struct ip6_hdr)) {
- printf("ah6_output: first mbuf too short\n");
+ ipseclog((LOG_DEBUG, "ah6_output: first mbuf too short\n"));
m_freem(m);
return EINVAL;
}
@@ -364,7 +372,7 @@ ah6_output(m, nexthdrp, md, isr)
for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
;
if (!mprev || mprev->m_next != md) {
- printf("ah6_output: md is not in chain\n");
+ ipseclog((LOG_DEBUG, "ah6_output: md is not in chain\n"));
m_freem(m);
return EINVAL;
}
@@ -389,7 +397,8 @@ ah6_output(m, nexthdrp, md, isr)
/* fix plen */
if (m->m_pkthdr.len - sizeof(struct ip6_hdr) > IPV6_MAXPACKET) {
- printf("ip6_output: AH with IPv6 jumbogram is not supported\n");
+ ipseclog((LOG_ERR,
+ "ip6_output: AH with IPv6 jumbogram is not supported\n"));
m_freem(m);
return EINVAL;
}
@@ -397,11 +406,12 @@ ah6_output(m, nexthdrp, md, isr)
ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {
- printf("ah6_output: internal error: "
+ ipseclog((LOG_DEBUG, "ah6_output: internal error: "
"sav->replay is null: SPI=%u\n",
- (u_int32_t)ntohl(sav->spi));
+ (u_int32_t)ntohl(sav->spi)));
ipsec6stat.out_inval++;
- return 0; /* no change at all */
+ m_freem(m);
+ return EINVAL;
}
algo = &ah_algorithms[sav->alg_auth];
@@ -431,6 +441,17 @@ ah6_output(m, nexthdrp, md, isr)
ahdr->ah_len = (plen >> 2) + 1; /* plus one for seq# */
ahdr->ah_reserve = htons(0);
ahdr->ah_spi = spi;
+ if (sav->replay->count == ~0) {
+ if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
+ /* XXX Is it noisy ? */
+ ipseclog((LOG_WARNING,
+ "replay counter overflowed. %s\n",
+ ipsec_logsastr(sav)));
+ ipsecstat.out_inval++;
+ m_freem(m);
+ return EINVAL;
+ }
+ }
sav->replay->count++;
/*
* XXX sequence number must not be cycled, if the SA is
@@ -444,13 +465,15 @@ ah6_output(m, nexthdrp, md, isr)
* calcurate the checksum, based on security association
* and the algorithm specified.
*/
- error = ah6_calccksum(m, (caddr_t)ahsumpos, algo, sav);
- if (error)
+ error = ah6_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav);
+ if (error) {
ipsec6stat.out_inval++;
- else
+ m_freem(m);
+ } else {
ipsec6stat.out_success++;
+ key_sa_recordxfer(sav, m);
+ }
ipsec6stat.out_ahhist[sav->alg_auth]++;
- key_sa_recordxfer(sav, m);
return(error);
}
@@ -480,7 +503,8 @@ ah4_finaldst(m)
hlen = (ip->ip_hl << 2);
if (m->m_len < hlen) {
- printf("ah4_finaldst: parameter mbuf wrong (not pulled up)\n");
+ ipseclog((LOG_DEBUG,
+ "ah4_finaldst: parameter mbuf wrong (not pulled up)\n"));
return NULL;
}
@@ -489,7 +513,8 @@ ah4_finaldst(m)
optlen = hlen - sizeof(struct ip);
if (optlen < 0) {
- printf("ah4_finaldst: wrong optlen %d\n", optlen);
+ ipseclog((LOG_DEBUG, "ah4_finaldst: wrong optlen %d\n",
+ optlen));
return NULL;
}
@@ -507,9 +532,10 @@ ah4_finaldst(m)
case IPOPT_SSRR:
if (q[i + IPOPT_OLEN] <= 0
|| optlen - i < q[i + IPOPT_OLEN]) {
- printf("ip_finaldst: invalid IP option "
- "(code=%02x len=%02x)\n",
- q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]);
+ ipseclog((LOG_ERR,
+ "ip_finaldst: invalid IP option "
+ "(code=%02x len=%02x)\n",
+ q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]));
return NULL;
}
i += q[i + IPOPT_OLEN] - sizeof(struct in_addr);
@@ -517,9 +543,10 @@ ah4_finaldst(m)
default:
if (q[i + IPOPT_OLEN] <= 0
|| optlen - i < q[i + IPOPT_OLEN]) {
- printf("ip_finaldst: invalid IP option "
- "(code=%02x len=%02x)\n",
- q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]);
+ ipseclog((LOG_ERR,
+ "ip_finaldst: invalid IP option "
+ "(code=%02x len=%02x)\n",
+ q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]));
return NULL;
}
i += q[i + IPOPT_OLEN];
diff --git a/sys/netinet6/dest6.c b/sys/netinet6/dest6.c
index b79a0ad0ab5c..268d8c9b185c 100644
--- a/sys/netinet6/dest6.c
+++ b/sys/netinet6/dest6.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: dest6.c,v 1.12 2000/05/05 11:00:57 sumikawa Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,10 +28,11 @@
* 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.
- *
- * $FreeBSD$
*/
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
@@ -43,9 +47,9 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
/*
* Destination options header processing.
@@ -61,12 +65,24 @@ dest6_input(mp, offp, proto)
u_int8_t *opt;
/* validation of the length of the header */
+#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, sizeof(*dstopts), IPPROTO_DONE);
dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
+#else
+ IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, sizeof(*dstopts));
+ if (dstopts == NULL)
+ return IPPROTO_DONE;
+#endif
dstoptlen = (dstopts->ip6d_len + 1) << 3;
+#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, dstoptlen, IPPROTO_DONE);
dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
+#else
+ IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, dstoptlen);
+ if (dstopts == NULL)
+ return IPPROTO_DONE;
+#endif
off += dstoptlen;
dstoptlen -= sizeof(struct ip6_dest);
opt = (u_int8_t *)dstopts + sizeof(struct ip6_dest);
diff --git a/sys/netinet6/esp.h b/sys/netinet6/esp.h
index b2f62cfd4bd2..95deec32a8ff 100644
--- a/sys/netinet6/esp.h
+++ b/sys/netinet6/esp.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: esp.h,v 1.8 2000/07/02 13:23:33 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -34,7 +35,7 @@
*/
#ifndef _NETINET6_ESP_H_
-#define _NETINET6_ESP_H_
+#define _NETINET6_ESP_H_
struct secasvar;
@@ -77,6 +78,7 @@ struct esp_algorithm {
int (*mature) __P((struct secasvar *));
int keymin; /* in bits */
int keymax; /* in bits */
+ const char *name;
int (*ivlen) __P((struct secasvar *));
int (*decrypt) __P((struct mbuf *, size_t,
struct secasvar *, struct esp_algorithm *, int));
@@ -89,9 +91,9 @@ extern struct esp_algorithm esp_algorithms[];
/* crypt routines */
extern int esp4_output __P((struct mbuf *, struct ipsecrequest *));
-extern void esp4_input __P((struct mbuf *, int, int));
+extern void esp4_input __P((struct mbuf *, ...));
extern size_t esp_hdrsiz __P((struct ipsecrequest *));
-#endif
+#endif /*_KERNEL*/
extern int esp_auth __P((struct mbuf *, size_t, size_t,
struct secasvar *, u_char *));
diff --git a/sys/netinet6/esp6.h b/sys/netinet6/esp6.h
index 0e3ba9bd7ea5..5d2f984b75cd 100644
--- a/sys/netinet6/esp6.h
+++ b/sys/netinet6/esp6.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: esp.h,v 1.8 2000/07/02 13:23:33 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -34,12 +35,12 @@
*/
#ifndef _NETINET6_ESP6_H_
-#define _NETINET6_ESP6_H_
+#define _NETINET6_ESP6_H_
#ifdef _KERNEL
extern int esp6_output __P((struct mbuf *, u_char *, struct mbuf *,
struct ipsecrequest *));
extern int esp6_input __P((struct mbuf **, int *, int));
-#endif
+#endif /*_KERNEL*/
#endif /*_NETINET6_ESP6_H_*/
diff --git a/sys/netinet6/esp_core.c b/sys/netinet6/esp_core.c
index 98b973d936e4..e5f8ec5d2a04 100644
--- a/sys/netinet6/esp_core.c
+++ b/sys/netinet6/esp_core.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: esp_core.c,v 1.15 2000/06/14 10:41:18 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,12 +28,10 @@
* 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.
- *
- * $FreeBSD$
*/
+#include "opt_inet.h"
#include "opt_inet6.h"
-#include "opt_ipsec.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -40,6 +41,7 @@
#include <sys/socket.h>
#include <sys/errno.h>
#include <sys/time.h>
+#include <sys/syslog.h>
#include <net/if.h>
#include <net/route.h>
@@ -47,25 +49,24 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
#ifdef INET6
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#endif
#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
-#ifdef IPSEC_ESP
#include <netinet6/esp.h>
#ifdef INET6
#include <netinet6/esp6.h>
#endif
-#endif
#include <net/pfkeyv2.h>
-#include <netkey/key_var.h>
#include <netkey/keydb.h>
#include <crypto/des/des.h>
#include <crypto/blowfish/blowfish.h>
@@ -113,19 +114,19 @@ 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,
+ { 8, esp_descbc_mature, 64, 64, "des-cbc",
esp_descbc_ivlen, esp_descbc_decrypt, esp_descbc_encrypt, },
- { 8, esp_cbc_mature, 192, 192,
+ { 8, esp_cbc_mature, 192, 192, "3des-cbc",
esp_3descbc_ivlen, esp_3descbc_decrypt, esp_3descbc_encrypt, },
- { 1, esp_null_mature, 0, 2048,
+ { 1, esp_null_mature, 0, 2048, "null",
esp_null_ivlen, esp_null_decrypt, esp_null_encrypt, },
- { 8, esp_cbc_mature, 40, 448,
+ { 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,
+ { 8, esp_cbc_mature, 40, 128, "cast128-cbc",
esp_cast128cbc_ivlen, esp_cast128cbc_decrypt,
esp_cast128cbc_encrypt, },
- { 8, esp_cbc_mature, 40, 2040,
+ { 8, esp_cbc_mature, 40, 2040, "rc5-cbc",
esp_rc5cbc_ivlen, esp_rc5cbc_decrypt, esp_rc5cbc_encrypt, },
};
@@ -179,25 +180,28 @@ esp_descbc_mature(sav)
struct esp_algorithm *algo;
if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) {
- printf("esp_cbc_mature: algorithm incompatible with 4 octets IV length\n");
+ ipseclog((LOG_ERR, "esp_cbc_mature: "
+ "algorithm incompatible with 4 octets IV length\n"));
return 1;
}
if (!sav->key_enc) {
- printf("esp_descbc_mature: no key is given.\n");
+ 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)) {
- printf("esp_descbc_mature: invalid key length %d.\n",
- _KEYBITS(sav->key_enc));
+ ipseclog((LOG_ERR,
+ "esp_descbc_mature: invalid key length %d.\n",
+ _KEYBITS(sav->key_enc)));
return 1;
}
/* weak key check */
if (des_is_weak_key((C_Block *)_KEYBUF(sav->key_enc))) {
- printf("esp_descbc_mature: weak key was passed.\n");
+ ipseclog((LOG_ERR,
+ "esp_descbc_mature: weak key was passed.\n"));
return 1;
}
@@ -231,18 +235,19 @@ esp_descbc_decrypt(m, off, sav, algo, ivlen)
size_t plen;
u_int8_t tiv[8];
int derived;
+ int error;
derived = 0;
/* sanity check */
if (ivlen != sav->ivlen) {
- printf("esp_descbc_decrypt: bad ivlen %d/%d\n",
- 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)) {
- printf("esp_descbc_decrypt: bad keylen %d\n",
- _KEYBITS(sav->key_enc));
+ ipseclog((LOG_ERR, "esp_descbc_decrypt: bad keylen %d\n",
+ _KEYBITS(sav->key_enc)));
return EINVAL;
}
@@ -282,7 +287,8 @@ esp_descbc_decrypt(m, off, sav, algo, ivlen)
iv = &tiv[0];
m_copydata(m, ivoff, 8, &tiv[0]);
} else {
- printf("esp_descbc_decrypt: unsupported ivlen %d\n", ivlen);
+ ipseclog((LOG_ERR, "esp_descbc_decrypt: unsupported ivlen %d\n",
+ ivlen));
return EINVAL;
}
@@ -293,8 +299,8 @@ esp_descbc_decrypt(m, off, sav, algo, ivlen)
plen -= bodyoff;
if (plen % 8) {
- printf("esp_descbc_decrypt: "
- "payload length must be multiple of 8\n");
+ ipseclog((LOG_ERR, "esp_descbc_decrypt: "
+ "payload length must be multiple of 8\n"));
return EINVAL;
}
@@ -304,11 +310,13 @@ esp_descbc_decrypt(m, off, sav, algo, ivlen)
deserr = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks);
if (deserr != 0) {
- printf("esp_descbc_decrypt: key error %d\n", deserr);
+ ipseclog((LOG_ERR,
+ "esp_descbc_decrypt: key error %d\n", deserr));
return EINVAL;
}
- des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv, DES_DECRYPT);
+ error = des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv,
+ DES_DECRYPT);
/* for safety */
bzero(&ks, sizeof(des_key_schedule));
@@ -317,7 +325,7 @@ esp_descbc_decrypt(m, off, sav, algo, ivlen)
/* for safety */
bzero(&tiv[0], sizeof(tiv));
- return 0;
+ return error;
}
static int
@@ -334,24 +342,25 @@ esp_descbc_encrypt(m, off, plen, sav, algo, ivlen)
u_int8_t *iv;
u_int8_t tiv[8];
int derived;
+ int error;
derived = 0;
/* sanity check */
if (plen % 8) {
- printf("esp_descbc_encrypt: "
- "payload length must be multiple of 8\n");
+ ipseclog((LOG_ERR, "esp_descbc_encrypt: "
+ "payload length must be multiple of 8\n"));
return EINVAL;
}
if (sav->ivlen != ivlen) {
- printf("esp_descbc_encrypt: bad ivlen %d/%d\n",
- ivlen, sav->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)) {
- printf("esp_descbc_encrypt: bad keylen %d\n",
- _KEYBITS(sav->key_enc));
+ ipseclog((LOG_ERR, "esp_descbc_encrypt: bad keylen %d\n",
+ _KEYBITS(sav->key_enc)));
return EINVAL;
}
@@ -411,7 +420,8 @@ esp_descbc_encrypt(m, off, plen, sav, algo, ivlen)
} else if (ivlen == 8)
bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen);
else {
- printf("esp_descbc_encrypt: unsupported ivlen %d\n", ivlen);
+ ipseclog((LOG_ERR,
+ "esp_descbc_encrypt: unsupported ivlen %d\n", ivlen));
return EINVAL;
}
@@ -421,11 +431,13 @@ esp_descbc_encrypt(m, off, plen, sav, algo, ivlen)
deserr = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks);
if (deserr != 0) {
- printf("esp_descbc_encrypt: key error %d\n", deserr);
+ ipseclog((LOG_ERR,
+ "esp_descbc_encrypt: key error %d\n", deserr));
return EINVAL;
}
- des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv, DES_ENCRYPT);
+ error = des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv,
+ DES_ENCRYPT);
/* for safety */
bzero(&ks, sizeof(des_key_schedule));
@@ -436,7 +448,7 @@ esp_descbc_encrypt(m, off, plen, sav, algo, ivlen)
/* for safety */
bzero(&tiv[0], sizeof(tiv));
- return 0;
+ return error;
}
static int
@@ -447,23 +459,26 @@ esp_cbc_mature(sav)
struct esp_algorithm *algo;
if (sav->flags & SADB_X_EXT_OLD) {
- printf("esp_cbc_mature: algorithm incompatible with esp-old\n");
+ ipseclog((LOG_ERR,
+ "esp_cbc_mature: algorithm incompatible with esp-old\n"));
return 1;
}
if (sav->flags & SADB_X_EXT_DERIV) {
- printf("esp_cbc_mature: algorithm incompatible with derived\n");
+ ipseclog((LOG_ERR,
+ "esp_cbc_mature: algorithm incompatible with derived\n"));
return 1;
}
if (!sav->key_enc) {
- printf("esp_cbc_mature: no key is given.\n");
+ ipseclog((LOG_ERR,
+ "esp_cbc_mature: no key is given.\n"));
return 1;
}
algo = &esp_algorithms[sav->alg_enc];
keylen = sav->key_enc->sadb_key_bits;
if (keylen < algo->keymin || algo->keymax < keylen) {
- printf("esp_cbc_mature: invalid key length %d.\n",
- sav->key_enc->sadb_key_bits);
+ ipseclog((LOG_ERR, "esp_cbc_mature: invalid key length %d.\n",
+ sav->key_enc->sadb_key_bits));
return 1;
}
switch (sav->alg_enc) {
@@ -472,7 +487,8 @@ esp_cbc_mature(sav)
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))) {
- printf("esp_cbc_mature: weak key was passed.\n");
+ ipseclog((LOG_ERR,
+ "esp_cbc_mature: weak key was passed.\n"));
return 1;
}
break;
@@ -500,27 +516,31 @@ esp_blowfish_cbc_decrypt(m, off, sav, algo, ivlen)
size_t plen;
static BF_KEY key; /* made static to avoid kernel stack overflow */
int s;
+ int error;
/* sanity check */
if (sav->ivlen != ivlen) {
- printf("esp_blowfish_cbc_decrypt: bad ivlen %d/%d\n",
- ivlen, sav->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)) {
- printf("esp_blowfish_cbc_decrypt: unsupported key length %d: "
- "need %d to %d bits\n", _KEYBITS(sav->key_enc),
- algo->keymin, algo->keymax);
+ 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) {
- printf("esp_blowfish_cbc_decrypt: unsupported ESP version\n");
+ ipseclog((LOG_ERR,
+ "esp_blowfish_cbc_decrypt: unsupported ESP version\n"));
return EINVAL;
}
if (ivlen != 8) {
- printf("esp_blowfish_cbc_decrypt: unsupported ivlen %d "
- "(this should never happen)\n", ivlen);
+ ipseclog((LOG_ERR,
+ "esp_blowfish_cbc_decrypt: unsupported ivlen %d\n", ivlen));
return EINVAL;
}
@@ -536,15 +556,19 @@ esp_blowfish_cbc_decrypt(m, off, sav, algo, ivlen)
plen -= bodyoff;
if (plen % 8) {
- printf("esp_blowfish_cbc_decrypt: "
- "payload length must be multiple of 8\n");
+ 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));
- BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_DECRYPT);
+ error = BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_DECRYPT);
/* for safety */
bzero(&key, sizeof(BF_KEY));
@@ -554,7 +578,7 @@ esp_blowfish_cbc_decrypt(m, off, sav, algo, ivlen)
/* for safety */
bzero(&tiv[0], sizeof(tiv));
- return 0;
+ return error;
}
static int
@@ -571,32 +595,36 @@ esp_blowfish_cbc_encrypt(m, off, plen, sav, algo, ivlen)
u_int8_t *iv;
static BF_KEY key; /* made static to avoid kernel stack overflow */
int s;
+ int error;
/* sanity check */
if (plen % 8) {
- printf("esp_blowfish_cbc_encrypt: "
- "payload length must be multiple of 8\n");
+ ipseclog((LOG_ERR, "esp_blowfish_cbc_encrypt: "
+ "payload length must be multiple of 8\n"));
return EINVAL;
}
if (sav->ivlen != ivlen) {
- printf("esp_blowfish_cbc_encrypt: bad ivlen %d/%d\n",
- ivlen, sav->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)) {
- printf("esp_blowfish_cbc_encrypt: unsupported key length %d: "
- "need %d to %d bits\n", _KEYBITS(sav->key_enc),
- algo->keymin, algo->keymax);
+ 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) {
- printf("esp_blowfish_cbc_encrypt: unsupported ESP version\n");
+ ipseclog((LOG_ERR,
+ "esp_blowfish_cbc_encrypt: unsupported ESP version\n"));
return EINVAL;
}
if (ivlen != 8) {
- printf("esp_blowfish_cbc_encrypt: unsupported ivlen %d "
- "(this should never happen)\n", ivlen);
+ ipseclog((LOG_ERR,
+ "esp_blowfish_cbc_encrypt: unsupported ivlen %d\n", ivlen));
return EINVAL;
}
@@ -611,10 +639,14 @@ esp_blowfish_cbc_encrypt(m, off, plen, sav, algo, ivlen)
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));
- BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_ENCRYPT);
+ error = BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_ENCRYPT);
/* for safety */
bzero(&key, sizeof(BF_KEY));
@@ -623,7 +655,7 @@ esp_blowfish_cbc_encrypt(m, off, plen, sav, algo, ivlen)
esp_increment_iv(sav);
- return 0;
+ return error;
}
static int
@@ -652,27 +684,30 @@ esp_cast128cbc_decrypt(m, off, sav, algo, ivlen)
size_t bodyoff;
u_int8_t iv[8];
size_t plen;
+ int error;
/* sanity check */
if (ivlen != sav->ivlen) {
- printf("esp_cast128cbc_decrypt: bad ivlen %d/%d\n",
- 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) {
- printf("esp_cast128cbc_decrypt: unsupported key length %d: "
- "need %d to %d bits\n", _KEYBITS(sav->key_enc),
- algo->keymin, 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) {
- printf("esp_cast128cbc_decrypt: unsupported ESP version\n");
+ ipseclog((LOG_ERR,
+ "esp_cast128cbc_decrypt: unsupported ESP version\n"));
return EINVAL;
}
if (ivlen != 8) {
- printf("esp_cast128cbc_decrypt: unsupported ivlen %d "
- "(this should never happen)\n", ivlen);
+ ipseclog((LOG_ERR,
+ "esp_cast128cbc_decrypt: unsupported ivlen %d\n", ivlen));
return EINVAL;
}
@@ -690,8 +725,8 @@ esp_cast128cbc_decrypt(m, off, sav, algo, ivlen)
plen -= bodyoff;
if (plen % 8) {
- printf("esp_cast128cbc_decrypt: "
- "payload length must be multiple of 8\n");
+ ipseclog((LOG_ERR, "esp_cast128cbc_decrypt: "
+ "payload length must be multiple of 8\n"));
return EINVAL;
}
@@ -704,15 +739,15 @@ esp_cast128cbc_decrypt(m, off, sav, algo, ivlen)
bcopy(_KEYBUF(sav->key_enc), key, _KEYLEN(sav->key_enc));
set_cast128_subkey(subkey, key);
- cast128_cbc_process(m, bodyoff, plen, subkey, iv,
- _KEYBITS(sav->key_enc) / 8, CAST128_DECRYPT);
+ error = cast128_cbc_process(m, bodyoff, plen, subkey, iv,
+ _KEYBITS(sav->key_enc) / 8, CAST128_DECRYPT);
/* for safety */
bzero(subkey, sizeof(subkey));
bzero(key, sizeof(key));
}
- return 0;
+ return error;
}
static int
@@ -727,32 +762,35 @@ esp_cast128cbc_encrypt(m, off, plen, sav, algo, ivlen)
size_t ivoff;
size_t bodyoff;
u_int8_t *iv;
+ int error;
/* sanity check */
if (plen % 8) {
- printf("esp_cast128cbc_encrypt: "
- "payload length must be multiple of 8\n");
+ ipseclog((LOG_ERR, "esp_cast128cbc_encrypt: "
+ "payload length must be multiple of 8\n"));
return EINVAL;
}
if (sav->ivlen != ivlen) {
- printf("esp_cast128cbc_encrypt: bad ivlen %d/%d\n",
- ivlen, sav->ivlen);
+ ipseclog((LOG_ERR, "esp_cast128cbc_encrypt: bad ivlen %d/%d\n",
+ ivlen, sav->ivlen));
return EINVAL;
}
if (_KEYBITS(sav->key_enc) < algo->keymin
|| _KEYBITS(sav->key_enc) > algo->keymax) {
- printf("esp_cast128cbc_encrypt: unsupported key length %d: "
- "needs %d to %d bits\n", _KEYBITS(sav->key_enc),
- algo->keymin, 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) {
- printf("esp_cast128cbc_encrypt: unsupported ESP version\n");
+ ipseclog((LOG_ERR,
+ "esp_cast128cbc_encrypt: unsupported ESP version\n"));
return EINVAL;
}
if (ivlen != 8) {
- printf("esp_cast128cbc_encrypt: unsupported ivlen %d "
- "(this should never happen)\n", ivlen);
+ ipseclog((LOG_ERR,
+ "esp_cast128cbc_encrypt: unsupported ivlen %d\n", ivlen));
return EINVAL;
}
@@ -776,8 +814,8 @@ esp_cast128cbc_encrypt(m, off, plen, sav, algo, ivlen)
bcopy(_KEYBUF(sav->key_enc), key, _KEYLEN(sav->key_enc));
set_cast128_subkey(subkey, key);
- cast128_cbc_process(m, bodyoff, plen, subkey, iv,
- _KEYBITS(sav->key_enc) / 8, CAST128_ENCRYPT);
+ error = cast128_cbc_process(m, bodyoff, plen, subkey, iv,
+ _KEYBITS(sav->key_enc) / 8, CAST128_ENCRYPT);
/* for safety */
bzero(subkey, sizeof(subkey));
@@ -786,7 +824,7 @@ esp_cast128cbc_encrypt(m, off, plen, sav, algo, ivlen)
esp_increment_iv(sav);
- return 0;
+ return error;
}
static int
@@ -812,23 +850,24 @@ esp_3descbc_decrypt(m, off, sav, algo, ivlen)
/* sanity check */
if (ivlen != sav->ivlen) {
- printf("esp_3descbc_decrypt: bad ivlen %d/%d\n",
- ivlen, sav->ivlen);
+ ipseclog((LOG_ERR, "esp_3descbc_decrypt: bad ivlen %d/%d\n",
+ ivlen, sav->ivlen));
return EINVAL;
}
if (_KEYBITS(sav->key_enc) < algo->keymin
|| algo->keymax < _KEYBITS(sav->key_enc)) {
- printf("esp_3descbc_decrypt: bad keylen %d\n",
- _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) {
- printf("esp_3descbc_decrypt: unsupported ESP version\n");
+ ipseclog((LOG_ERR,
+ "esp_3descbc_decrypt: unsupported ESP version\n"));
return EINVAL;
}
if (ivlen != 8) {
- printf("esp_3descbc_decrypt: unsupported ivlen %d "
- "(this should never happen)\n", ivlen);
+ ipseclog((LOG_ERR,
+ "esp_3descbc_decrypt: unsupported ivlen %d\n", ivlen));
return EINVAL;
}
@@ -845,8 +884,8 @@ esp_3descbc_decrypt(m, off, sav, algo, ivlen)
plen -= bodyoff;
if (plen % 8) {
- printf("esp_3descbc_decrypt: "
- "payload length must be multiple of 8\n");
+ ipseclog((LOG_ERR, "esp_3descbc_decrypt: "
+ "payload length must be multiple of 8\n"));
return EINVAL;
}
@@ -859,8 +898,8 @@ esp_3descbc_decrypt(m, off, sav, algo, ivlen)
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)) {
- printf("esp_3descbc_decrypt: key error %d/%d/%d\n",
- deserr[0], deserr[1], deserr[2]);
+ ipseclog((LOG_ERR, "esp_3descbc_decrypt: key error %d/%d/%d\n",
+ deserr[0], deserr[1], deserr[2]));
return EINVAL;
}
@@ -891,28 +930,29 @@ esp_3descbc_encrypt(m, off, plen, sav, algo, ivlen)
/* sanity check */
if (plen % 8) {
- printf("esp_3descbc_encrypt: "
- "payload length must be multiple of 8\n");
+ ipseclog((LOG_ERR, "esp_3descbc_encrypt: "
+ "payload length must be multiple of 8\n"));
return EINVAL;
}
if (sav->ivlen != ivlen) {
- printf("esp_3descbc_encrypt: bad ivlen %d/%d\n",
- ivlen, sav->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)) {
- printf("esp_3descbc_encrypt: bad keylen %d\n",
- _KEYBITS(sav->key_enc));
+ ipseclog((LOG_ERR, "esp_3descbc_encrypt: bad keylen %d\n",
+ _KEYBITS(sav->key_enc)));
return EINVAL;
}
if (sav->flags & SADB_X_EXT_OLD) {
- printf("esp_3descbc_encrypt: unsupported ESP version\n");
+ ipseclog((LOG_ERR,
+ "esp_3descbc_encrypt: unsupported ESP version\n"));
return EINVAL;
}
if (ivlen != 8) {
- printf("esp_3descbc_encrypt: unsupported ivlen %d "
- "(this should never happen)\n", ivlen);
+ ipseclog((LOG_ERR,
+ "esp_3descbc_encrypt: unsupported ivlen %d\n", ivlen));
return EINVAL;
}
@@ -936,8 +976,8 @@ esp_3descbc_encrypt(m, off, plen, sav, algo, ivlen)
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)) {
- printf("esp_3descbc_encrypt: key error %d/%d/%d\n",
- deserr[0], deserr[1], deserr[2]);
+ ipseclog((LOG_ERR, "esp_3descbc_encrypt: key error %d/%d/%d\n",
+ deserr[0], deserr[1], deserr[2]));
return EINVAL;
}
@@ -971,25 +1011,28 @@ esp_rc5cbc_decrypt(m, off, sav, algo, ivlen)
size_t bodyoff;
u_int8_t iv[8];
size_t plen;
+ int error;
/* sanity check */
if (sav->ivlen != ivlen) {
- printf("esp_rc5cbc_decrypt: bad ivlen %d/%d\n",
- ivlen, sav->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)) {
- printf("esp_rc5cbc_decrypt: unsupported key length %d: "
- "need 40 to 2040 bit\n", _KEYBITS(sav->key_enc));
+ 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) {
- printf("esp_rc5cbc_decrypt: unsupported ESP version\n");
+ ipseclog((LOG_ERR,
+ "esp_rc5cbc_decrypt: unsupported ESP version\n"));
return EINVAL;
}
if (ivlen != 8) {
- printf("esp_rc5cbc_decrypt: unsupported ivlen %d "
- "(this should never happen)\n", ivlen);
+ ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: unsupported ivlen %d\n",
+ ivlen));
return EINVAL;
}
@@ -1007,8 +1050,8 @@ esp_rc5cbc_decrypt(m, off, sav, algo, ivlen)
plen -= bodyoff;
if (plen % 8) {
- printf("esp_rc5cbc_decrypt: "
- "payload length must be multiple of 8\n");
+ ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: "
+ "payload length must be multiple of 8\n"));
return EINVAL;
}
@@ -1018,13 +1061,13 @@ esp_rc5cbc_decrypt(m, off, sav, algo, ivlen)
set_rc5_expandkey(e_key, _KEYBUF(sav->key_enc),
_KEYBITS(sav->key_enc) / 8, 16);
- rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_DECRYPT);
+ error = rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_DECRYPT);
/* for safety */
bzero(e_key, sizeof(e_key));
}
- return 0;
+ return error;
}
static int
@@ -1039,32 +1082,35 @@ esp_rc5cbc_encrypt(m, off, plen, sav, algo, ivlen)
size_t ivoff;
size_t bodyoff;
u_int8_t *iv;
+ int error;
/* sanity check */
if (plen % 8) {
- printf("esp_rc5cbc_encrypt: "
- "payload length must be multiple of 8\n");
+ ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: "
+ "payload length must be multiple of 8\n"));
return EINVAL;
}
if (sav->ivlen != ivlen) {
- printf("esp_rc5cbc_encrypt: bad ivlen %d/%d\n",
- ivlen, sav->ivlen);
+ ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: bad ivlen %d/%d\n",
+ ivlen, sav->ivlen));
return EINVAL;
}
if (_KEYBITS(sav->key_enc) < algo->keymin
|| _KEYBITS(sav->key_enc) > algo->keymax) {
- printf("esp_rc5cbc_encrypt: unsupported key length %d: "
- "need %d to %d bits\n", _KEYBITS(sav->key_enc),
- algo->keymin, 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));
return EINVAL;
}
if (sav->flags & SADB_X_EXT_OLD) {
- printf("esp_rc5cbc_encrypt: unsupported ESP version\n");
+ ipseclog((LOG_ERR,
+ "esp_rc5cbc_encrypt: unsupported ESP version\n"));
return EINVAL;
}
if (ivlen != 8) {
- printf("esp_rc5cbc_encrypt: unsupported ivlen %d "
- "(this should never happen)\n", ivlen);
+ ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: unsupported ivlen %d\n",
+ ivlen));
return EINVAL;
}
@@ -1085,7 +1131,7 @@ esp_rc5cbc_encrypt(m, off, plen, sav, algo, ivlen)
set_rc5_expandkey(e_key, _KEYBUF(sav->key_enc),
_KEYBITS(sav->key_enc) / 8, 16);
- rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_ENCRYPT);
+ error = rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_ENCRYPT);
/* for safety */
bzero(e_key, sizeof(e_key));
@@ -1093,7 +1139,7 @@ esp_rc5cbc_encrypt(m, off, plen, sav, algo, ivlen)
esp_increment_iv(sav);
- return 0;
+ return error;
}
/*
@@ -1107,8 +1153,11 @@ esp_increment_iv(sav)
u_int8_t y;
int i;
+#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++) {
@@ -1145,6 +1194,7 @@ mbuf_find_offset(m, off, len)
/*------------------------------------------------------------*/
+/* does not free m0 on error */
int
esp_auth(m0, skip, length, sav, sum)
struct mbuf *m0;
@@ -1159,14 +1209,16 @@ esp_auth(m0, skip, length, sav, sum)
u_char sumbuf[AH_MAXSUMSIZE];
struct ah_algorithm *algo;
size_t siz;
+ int error;
/* sanity checks */
if (m0->m_pkthdr.len < skip) {
- printf("esp_auth: mbuf length < skip\n");
+ ipseclog((LOG_DEBUG, "esp_auth: mbuf length < skip\n"));
return EINVAL;
}
if (m0->m_pkthdr.len < skip + length) {
- printf("esp_auth: mbuf length < skip + length\n");
+ ipseclog((LOG_DEBUG,
+ "esp_auth: mbuf length < skip + length\n"));
return EINVAL;
}
/*
@@ -1174,15 +1226,17 @@ esp_auth(m0, skip, length, sav, sum)
* since nexthdr must be at offset 4n+3.
*/
if (length % 4) {
- printf("esp_auth: length is not multiple of 4\n");
+ ipseclog((LOG_ERR, "esp_auth: length is not multiple of 4\n"));
return EINVAL;
}
if (!sav) {
- printf("esp_auth: NULL SA passed\n");
+ ipseclog((LOG_DEBUG, "esp_auth: NULL SA passed\n"));
return EINVAL;
}
if (!sav->alg_auth) {
- printf("esp_auth: bad ESP auth algorithm passed: %d\n", sav->alg_auth);
+ ipseclog((LOG_ERR,
+ "esp_auth: bad ESP auth algorithm passed: %d\n",
+ sav->alg_auth));
return EINVAL;
}
@@ -1192,8 +1246,9 @@ esp_auth(m0, skip, length, sav, sum)
algo = &ah_algorithms[sav->alg_auth];
siz = (((*algo->sumsiz)(sav) + 3) & ~(4 - 1));
if (sizeof(sumbuf) < siz) {
- printf("esp_auth: AH_MAXSUMSIZE is too small: siz=%lu\n",
- (u_long)siz);
+ ipseclog((LOG_DEBUG,
+ "esp_auth: AH_MAXSUMSIZE is too small: siz=%lu\n",
+ (u_long)siz));
return EINVAL;
}
@@ -1211,7 +1266,10 @@ esp_auth(m0, skip, length, sav, sum)
}
}
- (*algo->init)(&s, sav);
+ error = (*algo->init)(&s, sav);
+ if (error)
+ return error;
+
while (0 < length) {
if (!m)
panic("mbuf chain?");
@@ -1229,6 +1287,6 @@ esp_auth(m0, skip, length, sav, sum)
}
(*algo->result)(&s, sumbuf);
bcopy(sumbuf, sum, siz); /*XXX*/
-
+
return 0;
}
diff --git a/sys/netinet6/esp_input.c b/sys/netinet6/esp_input.c
index ef550697cbb6..48de49c65e53 100644
--- a/sys/netinet6/esp_input.c
+++ b/sys/netinet6/esp_input.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: esp_input.c,v 1.25 2000/05/08 08:04:30 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -35,7 +36,6 @@
#include "opt_inet.h"
#include "opt_inet6.h"
-#include "opt_ipsec.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -63,49 +63,57 @@
#endif
#ifdef INET6
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#endif
#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
-#ifdef IPSEC_ESP
#include <netinet6/esp.h>
#ifdef INET6
#include <netinet6/esp6.h>
#endif
-#endif
#include <netkey/key.h>
#include <netkey/keydb.h>
#ifdef IPSEC_DEBUG
#include <netkey/key_debug.h>
#else
-#define KEYDEBUG(lev,arg)
+#define KEYDEBUG(lev,arg)
#endif
-#include <netinet/ipprotosw.h>
-
#include <machine/stdarg.h>
#include <net/net_osdep.h>
+#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))
+
void
-esp4_input(m, off, proto)
+#if __STDC__
+esp4_input(struct mbuf *m, ...)
+#else
+esp4_input(m, va_alist)
struct mbuf *m;
- int off, proto;
-
+ va_dcl
+#endif
{
struct ip *ip;
struct esp *esp;
- struct esptail *esptail;
+ struct esptail esptail;
u_int32_t spi;
struct secasvar *sav = NULL;
size_t taillen;
@@ -115,19 +123,27 @@ esp4_input(m, off, proto)
size_t hlen;
size_t esplen;
int s;
+ va_list ap;
+ int off, proto;
+
+ va_start(ap, m);
+ off = va_arg(ap, int);
+ proto = va_arg(ap, int);
+ va_end(ap);
/* sanity check for alignment. */
if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) {
- printf("IPv4 ESP input: packet alignment problem "
- "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len);
+ ipseclog((LOG_ERR, "IPv4 ESP input: packet alignment problem "
+ "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len));
ipsecstat.in_inval++;
goto bad;
}
- if (m->m_len < off + sizeof(struct esp)) {
- m = m_pullup(m, off + sizeof(struct esp));
+ if (m->m_len < off + ESPMAXLEN) {
+ m = m_pullup(m, off + ESPMAXLEN);
if (!m) {
- printf("IPv4 ESP input: can't pullup in esp4_input\n");
+ ipseclog((LOG_DEBUG,
+ "IPv4 ESP input: can't pullup in esp4_input\n"));
ipsecstat.in_inval++;
goto bad;
}
@@ -147,9 +163,9 @@ esp4_input(m, off, proto)
if ((sav = key_allocsa(AF_INET,
(caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
IPPROTO_ESP, spi)) == 0) {
- printf("IPv4 ESP input: no key association found for spi %u;"
- "dropping the packet for simplicity\n",
- (u_int32_t)ntohl(spi));
+ ipseclog((LOG_WARNING,
+ "IPv4 ESP input: no key association found for spi %u\n",
+ (u_int32_t)ntohl(spi)));
ipsecstat.in_nosa++;
goto bad;
}
@@ -157,17 +173,16 @@ esp4_input(m, off, proto)
printf("DP esp4_input called to allocate SA:%p\n", sav));
if (sav->state != SADB_SASTATE_MATURE
&& sav->state != SADB_SASTATE_DYING) {
- printf("IPv4 ESP input: non-mature/dying SA found for spi %u; "
- "dropping the packet for simplicity\n",
- (u_int32_t)ntohl(spi));
+ ipseclog((LOG_DEBUG,
+ "IPv4 ESP input: non-mature/dying SA found for spi %u\n",
+ (u_int32_t)ntohl(spi)));
ipsecstat.in_badspi++;
goto bad;
}
if (sav->alg_enc == SADB_EALG_NONE) {
- printf("IPv4 ESP input: unspecified encryption algorithm "
- "for spi %u;"
- "dropping the packet for simplicity\n",
- (u_int32_t)ntohl(spi));
+ ipseclog((LOG_DEBUG, "IPv4 ESP input: "
+ "unspecified encryption algorithm for spi %u\n",
+ (u_int32_t)ntohl(spi)));
ipsecstat.in_badspi++;
goto bad;
}
@@ -177,9 +192,8 @@ esp4_input(m, off, proto)
/* check if we have proper ivlen information */
ivlen = sav->ivlen;
if (ivlen < 0) {
- log(LOG_NOTICE, "inproper ivlen in IPv4 ESP input: %s %s\n",
- ipsec4_logpacketstr(ip, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_ERR, "inproper ivlen in IPv4 ESP input: %s %s\n",
+ ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
ipsecstat.in_inval++;
goto bad;
}
@@ -198,16 +212,14 @@ esp4_input(m, off, proto)
; /*okey*/
else {
ipsecstat.in_espreplay++;
- log(LOG_AUTH, "replay packet in IPv4 ESP input: %s %s\n",
- ipsec4_logpacketstr(ip, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING,
+ "replay packet in IPv4 ESP input: %s %s\n",
+ ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
goto bad;
}
/* check ICV */
{
- struct mbuf *n;
- int len;
u_char sum0[AH_MAXSUMSIZE];
u_char sum[AH_MAXSUMSIZE];
struct ah_algorithm *sumalgo;
@@ -216,49 +228,37 @@ esp4_input(m, off, proto)
sumalgo = &ah_algorithms[sav->alg_auth];
siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1));
if (AH_MAXSUMSIZE < siz) {
- printf("internal error: AH_MAXSUMSIZE must be larger than %lu\n",
- (u_long)siz);
+ ipseclog((LOG_DEBUG,
+ "internal error: AH_MAXSUMSIZE must be larger than %lu\n",
+ (u_long)siz));
ipsecstat.in_inval++;
goto bad;
}
- n = m;
- len = m->m_pkthdr.len;
- len -= siz;
- while (n && 0 < len) {
- if (len < n->m_len)
- break;
- len -= n->m_len;
- n = n->m_next;
- }
- if (!n) {
- printf("mbuf chain problem?\n");
- ipsecstat.in_inval++;
- goto bad;
- }
- m_copydata(n, len, siz, &sum0[0]);
+ m_copydata(m, m->m_pkthdr.len - siz, siz, &sum0[0]);
if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) {
- log(LOG_AUTH, "auth fail in IPv4 ESP input: %s %s\n",
- ipsec4_logpacketstr(ip, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n",
+ ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
ipsecstat.in_espauthfail++;
goto bad;
}
if (bcmp(sum0, sum, siz) != 0) {
- log(LOG_AUTH, "auth fail in IPv4 ESP input: %s %s\n",
- ipsec4_logpacketstr(ip, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n",
+ ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
ipsecstat.in_espauthfail++;
goto bad;
}
- /* strip off */
- m->m_pkthdr.len -= siz;
- n->m_len -= siz;
+ /* strip off the authentication data */
+ m_adj(m, -siz);
ip = mtod(m, struct ip *);
+#ifdef IPLEN_FLIPPED
ip->ip_len = ip->ip_len - siz;
+#else
+ ip->ip_len = htons(ntohs(ip->ip_len) - siz);
+#endif
m->m_flags |= M_AUTHIPDGM;
ipsecstat.in_espauthsucc++;
}
@@ -267,7 +267,10 @@ esp4_input(m, off, proto)
* update sequence number.
*/
if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
- (void)ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav);
+ if (ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) {
+ ipsecstat.in_espreplay++;
+ goto bad;
+ }
}
noreplaycheck:
@@ -284,10 +287,18 @@ noreplaycheck:
esplen = sizeof(struct newesp);
}
+ if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) {
+ ipseclog((LOG_WARNING,
+ "IPv4 ESP input: packet too short\n"));
+ ipsecstat.in_inval++;
+ goto bad;
+ }
+
if (m->m_len < off + esplen + ivlen) {
m = m_pullup(m, off + esplen + ivlen);
if (!m) {
- printf("IPv4 ESP input: can't pullup in esp4_input\n");
+ ipseclog((LOG_DEBUG,
+ "IPv4 ESP input: can't pullup in esp4_input\n"));
ipsecstat.in_inval++;
goto bad;
}
@@ -300,9 +311,8 @@ noreplaycheck:
if (!algo->decrypt)
panic("internal error: no decrypt function");
if ((*algo->decrypt)(m, off, sav, algo, ivlen)) {
- log(LOG_AUTH, "decrypt fail in IPv4 ESP input: %s %s\n",
- ipsec4_logpacketstr(ip, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s %s\n",
+ ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
ipsecstat.in_inval++;
goto bad;
}
@@ -311,145 +321,34 @@ noreplaycheck:
m->m_flags |= M_DECRYPTED;
}
-#ifdef garbled_data_found_on_mbuf_after_packet
- {
- /*
- * For simplicity, we'll trim the packet so that there's no extra
- * part appended after IP packet.
- * This is rare case for some odd drivers, so there should be no
- * performance hit.
- */
-
- /*
- * Note that, in ip_input, ip_len was already flipped and header
- * length was subtracted from ip_len.
- */
- if (m->m_pkthdr.len != hlen + ip->ip_len)
- {
- size_t siz;
- struct mbuf *n;
-
- siz = hlen + ip->ip_len;
-
- /* find the final mbuf */
- for (n = m; n; n = n->m_next) {
- if (n->m_len < siz)
- siz -= n->m_len;
- else
- break;
- }
- if (!n) {
- printf("invalid packet\n");
- ipsecstat.in_inval++;
- goto bad;
- }
-
- /* trim the final mbuf */
- if (n->m_len < siz) {
- printf("invalid size: %d %d\n", n->m_len, siz);
- ipsecstat.in_inval++;
- goto bad;
- }
- n->m_len = siz;
-
- /* dispose the rest of the packet */
- m_freem(n->m_next);
- n->m_next = NULL;
-
- m->m_pkthdr.len = hlen + ip->ip_len;
- }
- }
-#endif
-
- {
/*
* find the trailer of the ESP.
*/
- struct mbuf *n; /*the last mbuf on the mbuf chain, m_len > 0 */
- struct mbuf *o; /*the last mbuf on the mbuf chain */
-
- o = m;
- n = NULL;
- while (o) {
- if (0 < o->m_len)
- n = o;
- o = o->m_next;
- }
- if (!n || n->m_len < sizeof(struct esptail)) {
- printf("IPv4 ESP input: assertion on pad part failed; "
- "dropping the packet\n");
- ipsecstat.in_inval++;
- goto bad;
- }
-
- esptail = (struct esptail *)
- (mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail));
- nxt = esptail->esp_nxt;
- taillen = esptail->esp_padlen + 2;
+ m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail),
+ (caddr_t)&esptail);
+ nxt = esptail.esp_nxt;
+ taillen = esptail.esp_padlen + sizeof(esptail);
if (m->m_pkthdr.len < taillen
|| m->m_pkthdr.len - taillen < hlen) { /*?*/
- log(LOG_NOTICE, "bad pad length in IPv4 ESP input: %s %s\n",
- ipsec4_logpacketstr(ip, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING,
+ "bad pad length in IPv4 ESP input: %s %s\n",
+ ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
ipsecstat.in_inval++;
goto bad;
}
- /*
- * strip off the trailing pad area.
- */
- if (taillen < n->m_len) {
- /* trailing pad data is included in the last mbuf item. */
- n->m_len -= taillen;
- m->m_pkthdr.len -= taillen;
- } else {
- /* trailing pad data spans on multiple mbuf item. */
- size_t siz;
-
- siz = m->m_pkthdr.len;
- if (siz < taillen) {
- log(LOG_NOTICE, "bad packet length in IPv4 ESP input: %s %s\n",
- ipsec4_logpacketstr(ip, spi),
- ipsec_logsastr(sav));
- ipsecstat.in_inval++;
- goto bad;
- }
- siz -= taillen;
-
- /* find the final mbuf */
- for (n = m; n; n = n->m_next) {
- if (n->m_len < siz)
- siz -= n->m_len;
- else
- break;
- }
- if (!n) {
- printf("invalid packet\n");
- ipsecstat.in_inval++;
- goto bad;
- }
-
- /* trim the final mbuf */
- if (n->m_len < siz) {
- printf("invalid size: %d %lu\n", n->m_len, (u_long)siz);
- ipsecstat.in_inval++;
- goto bad;
- }
- n->m_len = siz;
-
- /* dispose the rest of the packet */
- m_freem(n->m_next);
- n->m_next = NULL;
-
- m->m_pkthdr.len -= taillen;
- }
+ /* strip off the trailing pad area. */
+ m_adj(m, -taillen);
+#ifdef IPLEN_FLIPPED
ip->ip_len = ip->ip_len - taillen;
- }
+#else
+ ip->ip_len = htons(ntohs(ip->ip_len) - taillen);
+#endif
/* was it transmitted over the IPsec tunnel SA? */
- if (ipsec4_tunnel_validate(ip, nxt, sav) && nxt == IPPROTO_IPV4) {
+ if (ipsec4_tunnel_validate(ip, nxt, sav)) {
/*
* strip off all the headers that precedes ESP header.
* IP4 xx ESP IP4' payload -> IP4' payload
@@ -457,11 +356,9 @@ noreplaycheck:
* XXX more sanity checks
* XXX relationship with gif?
*/
- struct ip oip; /* for debug */
u_int8_t tos;
tos = ip->ip_tos;
- bcopy(mtod(m, struct ip *), &oip, sizeof(oip)); /* for debug */
m_adj(m, off + esplen + ivlen);
if (m->m_len < sizeof(*ip)) {
m = m_pullup(m, sizeof(*ip));
@@ -475,13 +372,21 @@ noreplaycheck:
ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
if (!key_checktunnelsanity(sav, AF_INET,
(caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
- log(LOG_NOTICE, "ipsec tunnel address mismatch in IPv4 ESP input: %s %s\n",
- ipsec4_logpacketstr(ip, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_ERR, "ipsec tunnel address mismatch "
+ "in IPv4 ESP input: %s %s\n",
+ ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
ipsecstat.in_inval++;
goto bad;
}
+#if 0 /* XXX should call ipfw rather than ipsec_in_reject, shouldn't it ? */
+ /* drop it if it does not match the default policy */
+ if (ipsec4_in_reject(m, NULL)) {
+ ipsecstat.in_polvio++;
+ goto bad;
+ }
+#endif
+
key_sa_recordxfer(sav, m);
s = splimp();
@@ -497,8 +402,8 @@ noreplaycheck:
} else {
/*
* strip off ESP header and IV.
- * We do deep-copy since KAME requires packet to be placed
- * in a single mbuf.
+ * even in m_pulldown case, we need to strip off ESP so that
+ * we can always compute checksum for AH correctly.
*/
size_t stripsiz;
@@ -511,7 +416,11 @@ noreplaycheck:
m->m_pkthdr.len -= stripsiz;
ip = mtod(m, struct ip *);
+#ifdef IPLEN_FLIPPED
ip->ip_len = ip->ip_len - stripsiz;
+#else
+ ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
+#endif
ip->ip_p = nxt;
key_sa_recordxfer(sav, m);
@@ -553,7 +462,7 @@ esp6_input(mp, offp, proto)
int off = *offp;
struct ip6_hdr *ip6;
struct esp *esp;
- struct esptail *esptail;
+ struct esptail esptail;
u_int32_t spi;
struct secasvar *sav = NULL;
size_t taillen;
@@ -565,19 +474,27 @@ esp6_input(mp, offp, proto)
/* sanity check for alignment. */
if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) {
- printf("IPv6 ESP input: packet alignment problem "
- "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len);
+ ipseclog((LOG_ERR, "IPv6 ESP input: packet alignment problem "
+ "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len));
ipsec6stat.in_inval++;
goto bad;
}
- IP6_EXTHDR_CHECK(m, off, sizeof(struct esp), IPPROTO_DONE);
-
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, off, ESPMAXLEN, IPPROTO_DONE);
+ esp = (struct esp *)(mtod(m, caddr_t) + off);
+#else
+ IP6_EXTHDR_GET(esp, struct esp *, m, off, ESPMAXLEN);
+ if (esp == NULL) {
+ ipsec6stat.in_inval++;
+ return IPPROTO_DONE;
+ }
+#endif
ip6 = mtod(m, struct ip6_hdr *);
- esp = (struct esp *)(((u_int8_t *)ip6) + off);
if (ntohs(ip6->ip6_plen) == 0) {
- printf("IPv6 ESP input: ESP with IPv6 jumbogram is not supported.\n");
+ ipseclog((LOG_ERR, "IPv6 ESP input: "
+ "ESP with IPv6 jumbogram is not supported.\n"));
ipsec6stat.in_inval++;
goto bad;
}
@@ -588,9 +505,9 @@ esp6_input(mp, offp, proto)
if ((sav = key_allocsa(AF_INET6,
(caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
IPPROTO_ESP, spi)) == 0) {
- printf("IPv6 ESP input: no key association found for spi %u;"
- "dropping the packet for simplicity\n",
- (u_int32_t)ntohl(spi));
+ ipseclog((LOG_WARNING,
+ "IPv6 ESP input: no key association found for spi %u\n",
+ (u_int32_t)ntohl(spi)));
ipsec6stat.in_nosa++;
goto bad;
}
@@ -598,17 +515,16 @@ esp6_input(mp, offp, proto)
printf("DP esp6_input called to allocate SA:%p\n", sav));
if (sav->state != SADB_SASTATE_MATURE
&& sav->state != SADB_SASTATE_DYING) {
- printf("IPv6 ESP input: non-mature/dying SA found for spi %u; "
- "dropping the packet for simplicity\n",
- (u_int32_t)ntohl(spi));
+ ipseclog((LOG_DEBUG,
+ "IPv6 ESP input: non-mature/dying SA found for spi %u\n",
+ (u_int32_t)ntohl(spi)));
ipsec6stat.in_badspi++;
goto bad;
}
if (sav->alg_enc == SADB_EALG_NONE) {
- printf("IPv6 ESP input: unspecified encryption algorithm "
- "for spi %u;"
- "dropping the packet for simplicity\n",
- (u_int32_t)ntohl(spi));
+ ipseclog((LOG_DEBUG, "IPv6 ESP input: "
+ "unspecified encryption algorithm for spi %u\n",
+ (u_int32_t)ntohl(spi)));
ipsec6stat.in_badspi++;
goto bad;
}
@@ -618,9 +534,8 @@ esp6_input(mp, offp, proto)
/* check if we have proper ivlen information */
ivlen = sav->ivlen;
if (ivlen < 0) {
- log(LOG_NOTICE, "inproper ivlen in IPv6 ESP input: %s %s\n",
- ipsec6_logpacketstr(ip6, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_ERR, "inproper ivlen in IPv6 ESP input: %s %s\n",
+ ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
ipsec6stat.in_badspi++;
goto bad;
}
@@ -639,16 +554,14 @@ esp6_input(mp, offp, proto)
; /*okey*/
else {
ipsec6stat.in_espreplay++;
- log(LOG_AUTH, "replay packet in IPv6 ESP input: %s %s\n",
- ipsec6_logpacketstr(ip6, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING,
+ "replay packet in IPv6 ESP input: %s %s\n",
+ ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
goto bad;
}
/* check ICV */
{
- struct mbuf *n;
- size_t len;
u_char sum0[AH_MAXSUMSIZE];
u_char sum[AH_MAXSUMSIZE];
struct ah_algorithm *sumalgo;
@@ -657,47 +570,31 @@ esp6_input(mp, offp, proto)
sumalgo = &ah_algorithms[sav->alg_auth];
siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1));
if (AH_MAXSUMSIZE < siz) {
- printf("internal error: AH_MAXSUMSIZE must be larger than %lu\n",
- (u_long)siz);
+ ipseclog((LOG_DEBUG,
+ "internal error: AH_MAXSUMSIZE must be larger than %lu\n",
+ (u_long)siz));
ipsec6stat.in_inval++;
goto bad;
}
- n = m;
- len = m->m_pkthdr.len;
- len -= siz; /*XXX*/
- while (n && 0 < len) {
- if (len < n->m_len)
- break;
- len -= n->m_len;
- n = n->m_next;
- }
- if (!n) {
- printf("mbuf chain problem?\n");
- ipsec6stat.in_inval++;
- goto bad;
- }
- m_copydata(n, len, siz, &sum0[0]);
+ m_copydata(m, m->m_pkthdr.len - siz, siz, &sum0[0]);
if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) {
- log(LOG_AUTH, "auth fail in IPv6 ESP input: %s %s\n",
- ipsec6_logpacketstr(ip6, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n",
+ ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
ipsec6stat.in_espauthfail++;
goto bad;
}
if (bcmp(sum0, sum, siz) != 0) {
- log(LOG_AUTH, "auth fail in IPv6 ESP input: %s %s\n",
- ipsec6_logpacketstr(ip6, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n",
+ ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
ipsec6stat.in_espauthfail++;
goto bad;
}
- /* strip off */
- m->m_pkthdr.len -= siz;
- n->m_len -= siz;
+ /* strip off the authentication data */
+ m_adj(m, -siz);
ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - siz);
@@ -709,7 +606,10 @@ esp6_input(mp, offp, proto)
* update sequence number.
*/
if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
- (void)ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav);
+ if (ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) {
+ ipsec6stat.in_espreplay++;
+ goto bad;
+ }
}
noreplaycheck:
@@ -726,7 +626,24 @@ noreplaycheck:
esplen = sizeof(struct newesp);
}
+ if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) {
+ ipseclog((LOG_WARNING,
+ "IPv6 ESP input: packet too short\n"));
+ ipsec6stat.in_inval++;
+ goto bad;
+ }
+
+#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, esplen + ivlen, IPPROTO_DONE); /*XXX*/
+#else
+ IP6_EXTHDR_GET(esp, struct esp *, m, off, esplen + ivlen);
+ if (esp == NULL) {
+ ipsec6stat.in_inval++;
+ m = NULL;
+ goto bad;
+ }
+#endif
+ ip6 = mtod(m, struct ip6_hdr *); /*set it again just in case*/
/*
* decrypt the packet.
@@ -734,9 +651,8 @@ noreplaycheck:
if (!algo->decrypt)
panic("internal error: no decrypt function");
if ((*algo->decrypt)(m, off, sav, algo, ivlen)) {
- log(LOG_AUTH, "decrypt fail in IPv6 ESP input: %s %s\n",
- ipsec6_logpacketstr(ip6, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s %s\n",
+ ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
ipsec6stat.in_inval++;
goto bad;
}
@@ -744,145 +660,30 @@ noreplaycheck:
m->m_flags |= M_DECRYPTED;
-#ifdef garbled_data_found_on_mbuf_after_packet
- {
- /*
- * For simplicity, we'll trim the packet so that there's no extra
- * part appended after IP packet.
- * This is rare case for some odd drivers, so there should be no
- * performance hit.
- */
-
- /*
- * Note that, in ip_input, ip_len was already flipped and header
- * length was subtracted from ip_len.
- */
- if (m->m_pkthdr.len != hlen + ip->ip_len)
- {
- size_t siz;
- struct mbuf *n;
-
- siz = hlen + ip->ip_len;
-
- /* find the final mbuf */
- for (n = m; n; n = n->m_next) {
- if (n->m_len < siz)
- siz -= n->m_len;
- else
- break;
- }
- if (!n) {
- printf("invalid packet\n");
- ipsec6stat.in_inval++;
- goto bad;
- }
-
- /* trim the final mbuf */
- if (n->m_len < siz) {
- printf("invalid size: %d %d\n", n->m_len, siz);
- ipsec6stat.in_inval++;
- goto bad;
- }
- n->m_len = siz;
-
- /* dispose the rest of the packet */
- m_freem(n->m_next);
- n->m_next = NULL;
-
- m->m_pkthdr.len = hlen + ip->ip_len;
- }
- }
-#endif
-
- {
/*
* find the trailer of the ESP.
*/
- struct mbuf *n; /*the last mbuf on the mbuf chain, m_len > 0 */
- struct mbuf *o; /*the last mbuf on the mbuf chain */
-
- o = m;
- n = NULL;
- while (o) {
- if (0 < o->m_len)
- n = o;
- o = o->m_next;
- }
- if (!n || n->m_len < sizeof(struct esptail)) {
- printf("IPv6 ESP input: assertion on pad part failed; "
- "dropping the packet\n");
- ipsec6stat.in_inval++;
- goto bad;
- }
-
- esptail = (struct esptail *)
- (mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail));
- nxt = esptail->esp_nxt;
- taillen = esptail->esp_padlen + 2;
+ m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail),
+ (caddr_t)&esptail);
+ nxt = esptail.esp_nxt;
+ taillen = esptail.esp_padlen + sizeof(esptail);
if (m->m_pkthdr.len < taillen
|| m->m_pkthdr.len - taillen < sizeof(struct ip6_hdr)) { /*?*/
- log(LOG_NOTICE, "bad pad length in IPv6 ESP input: %s %s\n",
- ipsec6_logpacketstr(ip6, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_WARNING,
+ "bad pad length in IPv6 ESP input: %s %s\n",
+ ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
ipsec6stat.in_inval++;
goto bad;
}
- /*
- * XXX strip off the padding.
- */
- if (taillen < n->m_len) {
- /* trailing pad data is included in the last mbuf item. */
- n->m_len -= taillen;
- m->m_pkthdr.len -= taillen;
- } else {
- /* trailing pad data spans on multiple mbuf item. */
- size_t siz;
-
- siz = m->m_pkthdr.len;
- if (siz < taillen) {
- log(LOG_NOTICE, "bad packet length in IPv6 ESP input: %s %s\n",
- ipsec6_logpacketstr(ip6, spi),
- ipsec_logsastr(sav));
- ipsec6stat.in_inval++;
- goto bad;
- }
- siz -= taillen;
-
- /* find the final mbuf */
- for (n = m; n; n = n->m_next) {
- if (n->m_len < siz)
- siz -= n->m_len;
- else
- break;
- }
- if (!n) {
- printf("invalid packet\n");
- ipsec6stat.in_inval++;
- goto bad;
- }
-
- /* trim the final mbuf */
- if (n->m_len < siz) {
- printf("invalid size: %d %lu\n", n->m_len, (u_long)siz);
- ipsec6stat.in_inval++;
- goto bad;
- }
- n->m_len = siz;
-
- /* dispose the rest of the packet */
- m_freem(n->m_next);
- n->m_next = NULL;
-
- m->m_pkthdr.len -= taillen;
- }
+ /* strip off the trailing pad area. */
+ m_adj(m, -taillen);
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - taillen);
- }
/* was it transmitted over the IPsec tunnel SA? */
- if (ipsec6_tunnel_validate(ip6, nxt, sav) && nxt == IPPROTO_IPV6) {
+ if (ipsec6_tunnel_validate(ip6, nxt, sav)) {
/*
* strip off all the headers that precedes ESP header.
* IP6 xx ESP IP6' payload -> IP6' payload
@@ -894,10 +695,14 @@ noreplaycheck:
flowinfo = ip6->ip6_flow;
m_adj(m, off + esplen + ivlen);
if (m->m_len < sizeof(*ip6)) {
+#ifndef PULLDOWN_TEST
/*
* m_pullup is prohibited in KAME IPv6 input processing
* but there's no other way!
*/
+#else
+ /* okay to pullup in m_pulldown style */
+#endif
m = m_pullup(m, sizeof(*ip6));
if (!m) {
ipsec6stat.in_inval++;
@@ -909,13 +714,22 @@ noreplaycheck:
ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
if (!key_checktunnelsanity(sav, AF_INET6,
(caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
- log(LOG_NOTICE, "ipsec tunnel address mismatch in IPv6 ESP input: %s %s\n",
- ipsec6_logpacketstr(ip6, spi),
- ipsec_logsastr(sav));
+ ipseclog((LOG_ERR, "ipsec tunnel address mismatch "
+ "in IPv6 ESP input: %s %s\n",
+ ipsec6_logpacketstr(ip6, spi),
+ ipsec_logsastr(sav)));
ipsec6stat.in_inval++;
goto bad;
}
+#if 0 /* XXX should call ipfw rather than ipsec_in_reject, shouldn't it ? */
+ /* drop it if it does not match the default policy */
+ if (ipsec6_in_reject(m, NULL)) {
+ ipsec6stat.in_polvio++;
+ goto bad;
+ }
+#endif
+
key_sa_recordxfer(sav, m);
s = splimp();
@@ -931,8 +745,8 @@ noreplaycheck:
} else {
/*
* strip off ESP header and IV.
- * We do deep-copy since KAME requires packet to be placed
- * in a single mbuf.
+ * even in m_pulldown case, we need to strip off ESP so that
+ * we can always compute checksum for AH correctly.
*/
size_t stripsiz;
char *prvnxtp;
@@ -946,11 +760,28 @@ noreplaycheck:
stripsiz = esplen + ivlen;
ip6 = mtod(m, struct ip6_hdr *);
- ovbcopy((caddr_t)ip6, (caddr_t)(((u_char *)ip6) + stripsiz),
- off);
- m->m_data += stripsiz;
- m->m_len -= stripsiz;
- m->m_pkthdr.len -= stripsiz;
+ if (m->m_len >= stripsiz + off) {
+ ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
+ m->m_data += stripsiz;
+ m->m_len -= stripsiz;
+ m->m_pkthdr.len -= stripsiz;
+ } else {
+ /*
+ * this comes with no copy if the boundary is on
+ * cluster
+ */
+ struct mbuf *n;
+
+ n = m_split(m, off, M_DONTWAIT);
+ if (n == NULL) {
+ /* m is retained by m_split */
+ goto bad;
+ }
+ m_adj(n, stripsiz);
+ m_cat(m, n);
+ /* m_cat does not update m_pkthdr.len */
+ m->m_pkthdr.len += n->m_pkthdr.len;
+ }
ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
diff --git a/sys/netinet6/esp_output.c b/sys/netinet6/esp_output.c
index fbe0d253ef0a..8d505ae0a72a 100644
--- a/sys/netinet6/esp_output.c
+++ b/sys/netinet6/esp_output.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: esp_output.c,v 1.22 2000/07/03 13:23:28 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,13 +28,10 @@
* 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.
- *
- * $FreeBSD$
*/
#include "opt_inet.h"
#include "opt_inet6.h"
-#include "opt_ipsec.h"
/*
* RFC1827/2406 Encapsulated Security Payload.
@@ -55,33 +55,27 @@
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_var.h>
-#include <netinet/in_pcb.h>
#ifdef INET6
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#endif
#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
-#ifdef IPSEC_ESP
#include <netinet6/esp.h>
#ifdef INET6
#include <netinet6/esp6.h>
#endif
-#endif
#include <netkey/key.h>
#include <netkey/keydb.h>
-#ifdef IPSEC_DEBUG
-#include <netkey/key_debug.h>
-#else
-#define KEYDEBUG(lev,arg)
-#endif
#include <net/net_osdep.h>
@@ -111,18 +105,18 @@ esp_hdrsiz(isr)
panic("unsupported mode passed to esp_hdrsiz");
if (sav == NULL)
- goto contrive;
+ goto estimate;
if (sav->state != SADB_SASTATE_MATURE
&& sav->state != SADB_SASTATE_DYING)
- goto contrive;
+ goto estimate;
/* we need transport mode ESP. */
algo = &esp_algorithms[sav->alg_enc];
if (!algo)
- goto contrive;
+ goto estimate;
ivlen = sav->ivlen;
if (ivlen < 0)
- goto contrive;
+ goto estimate;
/*
* XXX
@@ -145,14 +139,14 @@ esp_hdrsiz(isr)
return hdrsiz;
- contrive:
+ estimate:
/*
* ASSUMING:
* sizeof(struct newesp) > sizeof(struct esp).
* 8 = ivlen for CBC mode (RFC2451).
- * 9 = (maximum padding length without random Padding length)
+ * 9 = (maximum padding length without random padding length)
* + (Pad Length field) + (Next Header field).
- * 16 = maximum ICV we supported.
+ * 16 = maximum ICV we support.
*/
return sizeof(struct newesp) + 8 + 9 + 16;
}
@@ -212,7 +206,7 @@ esp_output(m, nexthdrp, md, isr, af)
break;
#endif
default:
- printf("esp_output: unsupported af %d\n", af);
+ ipseclog((LOG_ERR, "esp_output: unsupported af %d\n", af));
return 0; /* no change at all */
}
@@ -225,12 +219,11 @@ esp_output(m, nexthdrp, md, isr, af)
struct ip *ip;
ip = mtod(m, struct ip *);
- printf("esp4_output: internal error: "
- "sav->replay is null: "
- "%x->%x, SPI=%u\n",
+ ipseclog((LOG_DEBUG, "esp4_output: internal error: "
+ "sav->replay is null: %x->%x, SPI=%u\n",
(u_int32_t)ntohl(ip->ip_src.s_addr),
(u_int32_t)ntohl(ip->ip_dst.s_addr),
- (u_int32_t)ntohl(sav->spi));
+ (u_int32_t)ntohl(sav->spi)));
ipsecstat.out_inval++;
m_freem(m);
return EINVAL;
@@ -242,9 +235,9 @@ esp_output(m, nexthdrp, md, isr, af)
struct ip6_hdr *ip6;
ip6 = mtod(m, struct ip6_hdr *);
- printf("esp6_output: internal error: "
+ ipseclog((LOG_DEBUG, "esp6_output: internal error: "
"sav->replay is null: SPI=%u\n",
- (u_int32_t)ntohl(sav->spi));
+ (u_int32_t)ntohl(sav->spi)));
ipsec6stat.out_inval++;
m_freem(m);
return EINVAL;
@@ -293,7 +286,8 @@ esp_output(m, nexthdrp, md, isr, af)
for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
;
if (mprev == NULL || mprev->m_next != md) {
- printf("esp%d_output: md is not in chain\n", afnumber);
+ ipseclog((LOG_DEBUG, "esp%d_output: md is not in chain\n",
+ afnumber));
m_freem(m);
return EINVAL;
}
@@ -355,7 +349,7 @@ esp_output(m, nexthdrp, md, isr, af)
m->m_pkthdr.len += esphlen;
esp = mtod(md, struct esp *);
}
-
+
nxt = *nexthdrp;
*nexthdrp = IPPROTO_ESP;
switch (af) {
@@ -364,7 +358,8 @@ esp_output(m, nexthdrp, md, isr, af)
if (esphlen < (IP_MAXPACKET - ntohs(ip->ip_len)))
ip->ip_len = htons(ntohs(ip->ip_len) + esphlen);
else {
- printf("IPv4 ESP output: size exceeds limit\n");
+ ipseclog((LOG_ERR,
+ "IPv4 ESP output: size exceeds limit\n"));
ipsecstat.out_inval++;
m_freem(m);
error = EMSGSIZE;
@@ -385,6 +380,17 @@ esp_output(m, nexthdrp, md, isr, af)
if ((sav->flags & SADB_X_EXT_OLD) == 0) {
struct newesp *nesp;
nesp = (struct newesp *)esp;
+ if (sav->replay->count == ~0) {
+ if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
+ /* XXX Is it noisy ? */
+ ipseclog((LOG_WARNING,
+ "replay counter overflowed. %s\n",
+ ipsec_logsastr(sav)));
+ ipsecstat.out_inval++;
+ m_freem(m);
+ return EINVAL;
+ }
+ }
sav->replay->count++;
/*
* XXX sequence number must not be cycled, if the SA is
@@ -402,6 +408,8 @@ esp_output(m, nexthdrp, md, isr, af)
struct ip *ip = NULL;
#endif
size_t padbound;
+ u_char *extend;
+ int i;
if (algo->padbound)
padbound = algo->padbound;
@@ -410,7 +418,7 @@ esp_output(m, nexthdrp, md, isr, af)
/* ESP packet, including nxthdr field, must be length of 4n */
if (padbound < 4)
padbound = 4;
-
+
extendsiz = padbound - (plen % padbound);
if (extendsiz == 1)
extendsiz = padbound + 1;
@@ -424,23 +432,7 @@ esp_output(m, nexthdrp, md, isr, af)
* two consequtive TCP packets.
*/
if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) {
- switch (sav->flags & SADB_X_EXT_PMASK) {
- case SADB_X_EXT_PRAND:
- break;
- case SADB_X_EXT_PZERO:
- bzero((caddr_t)(mtod(n, u_int8_t *) + n->m_len),
- extendsiz);
- break;
- case SADB_X_EXT_PSEQ:
- {
- int i;
- u_char *p;
- p = mtod(n, u_char *) + n->m_len;
- for (i = 0; i < extendsiz; i++)
- p[i] = i + 1;
- break;
- }
- }
+ extend = mtod(n, u_char *) + n->m_len;
n->m_len += extendsiz;
m->m_pkthdr.len += extendsiz;
} else {
@@ -448,33 +440,32 @@ esp_output(m, nexthdrp, md, isr, af)
MGET(nn, M_DONTWAIT, MT_DATA);
if (!nn) {
- printf("esp%d_output: can't alloc mbuf", afnumber);
+ ipseclog((LOG_DEBUG, "esp%d_output: can't alloc mbuf",
+ afnumber));
m_freem(m);
error = ENOBUFS;
goto fail;
}
+ extend = mtod(nn, u_char *);
nn->m_len = extendsiz;
- switch (sav->flags & SADB_X_EXT_PMASK) {
- case SADB_X_EXT_PRAND:
- break;
- case SADB_X_EXT_PZERO:
- bzero(mtod(nn, caddr_t), extendsiz);
- break;
- case SADB_X_EXT_PSEQ:
- {
- int i;
- u_char *p;
- p = mtod(nn, u_char *);
- for (i = 0; i < extendsiz; i++)
- p[i] = i + 1;
- break;
- }
- }
nn->m_next = NULL;
n->m_next = nn;
n = nn;
m->m_pkthdr.len += extendsiz;
}
+ switch (sav->flags & SADB_X_EXT_PMASK) {
+ case SADB_X_EXT_PRAND:
+ for (i = 0; i < extendsiz; i++)
+ extend[i] = random() & 0xff;
+ break;
+ case SADB_X_EXT_PZERO:
+ bzero(extend, extendsiz);
+ break;
+ case SADB_X_EXT_PSEQ:
+ for (i = 0; i < extendsiz; i++)
+ extend[i] = (i + 1) & 0xff;
+ break;
+ }
/* initialize esp trailer. */
esptail = (struct esptail *)
@@ -490,7 +481,8 @@ esp_output(m, nexthdrp, md, isr, af)
if (extendsiz < (IP_MAXPACKET - ntohs(ip->ip_len)))
ip->ip_len = htons(ntohs(ip->ip_len) + extendsiz);
else {
- printf("IPv4 ESP output: size exceeds limit\n");
+ ipseclog((LOG_ERR,
+ "IPv4 ESP output: size exceeds limit\n"));
ipsecstat.out_inval++;
m_freem(m);
error = EMSGSIZE;
@@ -513,7 +505,7 @@ esp_output(m, nexthdrp, md, isr, af)
if (!algo->encrypt)
panic("internal error: no encrypt function");
if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) {
- printf("packet encryption failure\n");
+ ipseclog((LOG_ERR, "packet encryption failure\n"));
m_freem(m);
switch (af) {
#ifdef INET
@@ -551,8 +543,24 @@ esp_output(m, nexthdrp, md, isr, af)
if (AH_MAXSUMSIZE < siz)
panic("assertion failed for AH_MAXSUMSIZE");
- if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf))
- goto noantireplay;
+ if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) {
+ 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
+ }
+ goto fail;
+ }
n = m;
while (n->m_next)
@@ -567,7 +575,8 @@ esp_output(m, nexthdrp, md, isr, af)
MGET(nn, M_DONTWAIT, MT_DATA);
if (!nn) {
- printf("can't alloc mbuf in esp%d_output", afnumber);
+ ipseclog((LOG_DEBUG, "can't alloc mbuf in esp%d_output",
+ afnumber));
m_freem(m);
error = ENOBUFS;
goto fail;
@@ -589,7 +598,8 @@ esp_output(m, nexthdrp, md, isr, af)
if (siz < (IP_MAXPACKET - ntohs(ip->ip_len)))
ip->ip_len = htons(ntohs(ip->ip_len) + siz);
else {
- printf("IPv4 ESP output: size exceeds limit\n");
+ ipseclog((LOG_ERR,
+ "IPv4 ESP output: size exceeds limit\n"));
ipsecstat.out_inval++;
m_freem(m);
error = EMSGSIZE;
@@ -606,9 +616,10 @@ esp_output(m, nexthdrp, md, isr, af)
}
noantireplay:
- if (!m)
- printf("NULL mbuf after encryption in esp%d_output", afnumber);
- else {
+ if (!m) {
+ ipseclog((LOG_ERR,
+ "NULL mbuf after encryption in esp%d_output", afnumber));
+ } else {
switch (af) {
#ifdef INET
case AF_INET:
@@ -653,9 +664,9 @@ esp4_output(m, isr)
{
struct ip *ip;
if (m->m_len < sizeof(struct ip)) {
- printf("esp4_output: first mbuf too short\n");
+ ipseclog((LOG_DEBUG, "esp4_output: first mbuf too short\n"));
m_freem(m);
- return NULL;
+ return 0;
}
ip = mtod(m, struct ip *);
/* XXX assumes that m->m_next points to payload */
@@ -672,9 +683,9 @@ esp6_output(m, nexthdrp, md, isr)
struct ipsecrequest *isr;
{
if (m->m_len < sizeof(struct ip6_hdr)) {
- printf("esp6_output: first mbuf too short\n");
+ ipseclog((LOG_DEBUG, "esp6_output: first mbuf too short\n"));
m_freem(m);
- return NULL;
+ return 0;
}
return esp_output(m, nexthdrp, md, isr, AF_INET6);
}
diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c
index f7cfbc0964db..1bf7e7370612 100644
--- a/sys/netinet6/frag6.c
+++ b/sys/netinet6/frag6.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: frag6.c,v 1.24 2000/03/25 07:23:41 sumikawa Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
#include <sys/param.h>
@@ -46,9 +47,9 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#include <net/net_osdep.h>
@@ -57,20 +58,23 @@
* You will need to perform an extra routing table lookup, per fragment,
* to do it. This may, or may not be, a performance hit.
*/
-#define IN6_IFSTAT_STRICT
+#define IN6_IFSTAT_STRICT
-static void frag6_enq __P((struct ip6asfrag *, struct ip6asfrag *));
-static void frag6_deq __P((struct ip6asfrag *));
-static void frag6_insque __P((struct ip6q *, struct ip6q *));
-static void frag6_remque __P((struct ip6q *));
-static void frag6_freef __P((struct ip6q *));
+static void frag6_enq __P((struct ip6asfrag *, struct ip6asfrag *));
+static void frag6_deq __P((struct ip6asfrag *));
+static void frag6_insque __P((struct ip6q *, struct ip6q *));
+static void frag6_remque __P((struct ip6q *));
+static void frag6_freef __P((struct ip6q *));
-int frag6_doing_reass;
-u_int frag6_nfragpackets;
-struct ip6q ip6q; /* ip6 reassemble queue */
+int frag6_doing_reass;
+u_int frag6_nfragpackets;
+struct ip6q ip6q; /* ip6 reassemble queue */
-#if !defined(M_FTABLE)
+/* FreeBSD tweak */
MALLOC_DEFINE(M_FTABLE, "fragment", "fragment reassembly header");
+
+#ifndef offsetof /* XXX */
+#define offsetof(type, member) ((size_t)(&((type *)0)->member))
#endif
/*
@@ -86,11 +90,40 @@ frag6_init()
* as initialization during bootstrap time occur in fixed order.
*/
microtime(&tv);
- ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q;
ip6_id = random() ^ tv.tv_usec;
+ ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q;
}
/*
+ * In RFC2460, fragment and reassembly rule do not agree with each other,
+ * in terms of next header field handling in fragment header.
+ * While the sender will use the same value for all of the fragmented packets,
+ * receiver is suggested not to check the consistency.
+ *
+ * fragment rule (p20):
+ * (2) A Fragment header containing:
+ * The Next Header value that identifies the first header of
+ * the Fragmentable Part of the original packet.
+ * -> next header field is same for all fragments
+ *
+ * reassembly rule (p21):
+ * The Next Header field of the last header of the Unfragmentable
+ * Part is obtained from the Next Header field of the first
+ * fragment's Fragment header.
+ * -> should grab it from the first fragment only
+ *
+ * The following note also contradicts with fragment rule - noone is going to
+ * send different fragment with different next header field.
+ *
+ * additional note (p22):
+ * The Next Header values in the Fragment headers of different
+ * fragments of the same original packet may differ. Only the value
+ * from the Offset zero fragment packet is used for reassembly.
+ * -> should grab it from the first fragment only
+ *
+ * There is no explicit reason given in the RFC. Historical reason maybe?
+ */
+/*
* Fragment input
*/
int
@@ -102,20 +135,25 @@ frag6_input(mp, offp, proto)
struct ip6_hdr *ip6;
struct ip6_frag *ip6f;
struct ip6q *q6;
- struct ip6asfrag *af6, *ip6af;
+ struct ip6asfrag *af6, *ip6af, *af6dwn;
int offset = *offp, nxt, i, next;
int first_frag = 0;
- u_short fragoff, frgpartlen;
+ int fragoff, frgpartlen; /* must be larger than u_int16_t */
struct ifnet *dstifp;
#ifdef IN6_IFSTAT_STRICT
static struct route_in6 ro;
struct sockaddr_in6 *dst;
#endif
- IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), IPPROTO_DONE);
-
ip6 = mtod(m, struct ip6_hdr *);
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), IPPROTO_DONE);
ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset);
+#else
+ IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f));
+ if (ip6f == NULL)
+ return IPPROTO_DONE;
+#endif
dstifp = NULL;
#ifdef IN6_IFSTAT_STRICT
@@ -159,7 +197,7 @@ frag6_input(mp, offp, proto)
(((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) {
icmp6_error(m, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
- (caddr_t)&ip6->ip6_plen - (caddr_t)ip6);
+ offsetof(struct ip6_hdr, ip6_plen));
in6_ifstat_inc(dstifp, ifs6_reass_fail);
return IPPROTO_DONE;
}
@@ -167,14 +205,8 @@ frag6_input(mp, offp, proto)
ip6stat.ip6s_fragments++;
in6_ifstat_inc(dstifp, ifs6_reass_reqd);
- /*
- * Presence of header sizes in mbufs
- * would confuse code below.
- */
-
+ /* offset now points to data portion */
offset += sizeof(struct ip6_frag);
- m->m_data += offset;
- m->m_len -= offset;
for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next)
if (ip6f->ip6f_ident == q6->ip6q_ident &&
@@ -204,10 +236,15 @@ frag6_input(mp, offp, proto)
M_DONTWAIT);
if (q6 == NULL)
goto dropfrag;
+ bzero(q6, sizeof(*q6));
frag6_insque(q6, &ip6q);
+ /* ip6q_nxt will be filled afterwards, from 1st fragment */
q6->ip6q_down = q6->ip6q_up = (struct ip6asfrag *)q6;
+#ifdef notyet
+ q6->ip6q_nxtp = (u_char *)nxtp;
+#endif
q6->ip6q_ident = ip6f->ip6f_ident;
q6->ip6q_arrive = 0; /* Is it used anywhere? */
q6->ip6q_ttl = IPV6_FRAGTTL;
@@ -232,22 +269,20 @@ frag6_input(mp, offp, proto)
* in size.
* If it would exceed, discard the fragment and return an ICMP error.
*/
- frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset;
+ frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset;
if (q6->ip6q_unfrglen >= 0) {
/* The 1st fragment has already arrived. */
if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) {
- m->m_data -= offset;
- m->m_len += offset;
icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
- offset - sizeof(struct ip6_frag) + 2);
+ offset - sizeof(struct ip6_frag) +
+ offsetof(struct ip6_frag, ip6f_offlg));
return(IPPROTO_DONE);
}
}
else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
- m->m_data -= offset;
- m->m_len += offset;
icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
- offset - sizeof(struct ip6_frag) + 2);
+ offset - sizeof(struct ip6_frag) +
+ offsetof(struct ip6_frag, ip6f_offlg));
return(IPPROTO_DONE);
}
/*
@@ -255,8 +290,6 @@ frag6_input(mp, offp, proto)
* fragment already stored in the reassembly queue.
*/
if (fragoff == 0) {
- struct ip6asfrag *af6dwn;
-
for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
af6 = af6dwn) {
af6dwn = af6->ip6af_down;
@@ -269,10 +302,9 @@ frag6_input(mp, offp, proto)
/* dequeue the fragment. */
frag6_deq(af6);
+ free(af6, M_FTABLE);
/* adjust pointer. */
- merr->m_data -= af6->ip6af_offset;
- merr->m_len += af6->ip6af_offset;
ip6err = mtod(merr, struct ip6_hdr *);
/*
@@ -284,13 +316,21 @@ frag6_input(mp, offp, proto)
icmp6_error(merr, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
- erroff - sizeof(struct ip6_frag) + 2);
+ erroff - sizeof(struct ip6_frag) +
+ offsetof(struct ip6_frag, ip6f_offlg));
}
}
}
- /* Override the IPv6 header */
- ip6af = (struct ip6asfrag *)ip6;
+ ip6af = (struct ip6asfrag *)malloc(sizeof(struct ip6asfrag), M_FTABLE,
+ M_DONTWAIT);
+ if (ip6af == NULL)
+ goto dropfrag;
+ bzero(ip6af, sizeof(*ip6af));
+ ip6af->ip6af_head = ip6->ip6_flow;
+ ip6af->ip6af_len = ip6->ip6_plen;
+ ip6af->ip6af_nxt = ip6->ip6_nxt;
+ ip6af->ip6af_hlim = ip6->ip6_hlim;
ip6af->ip6af_mff = ip6f->ip6f_offlg & IP6F_MORE_FRAG;
ip6af->ip6af_off = fragoff;
ip6af->ip6af_frglen = frgpartlen;
@@ -310,6 +350,42 @@ frag6_input(mp, offp, proto)
if (af6->ip6af_off > ip6af->ip6af_off)
break;
+#if 0
+ /*
+ * If there is a preceding segment, it may provide some of
+ * our data already. If so, drop the data from the incoming
+ * segment. If it provides all of our data, drop us.
+ */
+ if (af6->ip6af_up != (struct ip6asfrag *)q6) {
+ i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
+ - ip6af->ip6af_off;
+ if (i > 0) {
+ if (i >= ip6af->ip6af_frglen)
+ goto dropfrag;
+ m_adj(IP6_REASS_MBUF(ip6af), i);
+ ip6af->ip6af_off += i;
+ ip6af->ip6af_frglen -= i;
+ }
+ }
+
+ /*
+ * While we overlap succeeding segments trim them or,
+ * if they are completely covered, dequeue them.
+ */
+ while (af6 != (struct ip6asfrag *)q6 &&
+ ip6af->ip6af_off + ip6af->ip6af_frglen > af6->ip6af_off) {
+ i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
+ if (i < af6->ip6af_frglen) {
+ af6->ip6af_frglen -= i;
+ af6->ip6af_off += i;
+ m_adj(IP6_REASS_MBUF(af6), i);
+ break;
+ }
+ af6 = af6->ip6af_down;
+ m_freem(IP6_REASS_MBUF(af6->ip6af_up));
+ frag6_deq(af6->ip6af_up);
+ }
+#else
/*
* If the incoming framgent overlaps some existing fragments in
* the reassembly queue, drop it, since it is dangerous to override
@@ -334,6 +410,7 @@ frag6_input(mp, offp, proto)
goto dropfrag;
}
}
+#endif
insert:
@@ -344,6 +421,12 @@ insert:
* the most recently active fragmented packet.
*/
frag6_enq(ip6af, af6->ip6af_up);
+#if 0 /* xxx */
+ if (q6 != ip6q.ip6q_next) {
+ frag6_remque(q6);
+ frag6_insque(q6, &ip6q);
+ }
+#endif
next = 0;
for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
af6 = af6->ip6af_down) {
@@ -361,38 +444,52 @@ insert:
/*
* Reassembly is complete; concatenate fragments.
*/
-
ip6af = q6->ip6q_down;
t = m = IP6_REASS_MBUF(ip6af);
af6 = ip6af->ip6af_down;
+ frag6_deq(ip6af);
while (af6 != (struct ip6asfrag *)q6) {
+ af6dwn = af6->ip6af_down;
+ frag6_deq(af6);
while (t->m_next)
t = t->m_next;
t->m_next = IP6_REASS_MBUF(af6);
- af6 = af6->ip6af_down;
+ m_adj(t->m_next, af6->ip6af_offset);
+ free(af6, M_FTABLE);
+ af6 = af6dwn;
}
/* adjust offset to point where the original next header starts */
offset = ip6af->ip6af_offset - sizeof(struct ip6_frag);
- ip6 = (struct ip6_hdr *)ip6af;
+ free(ip6af, M_FTABLE);
+ ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_plen = htons((u_short)next + offset - sizeof(struct ip6_hdr));
ip6->ip6_src = q6->ip6q_src;
ip6->ip6_dst = q6->ip6q_dst;
nxt = q6->ip6q_nxt;
+#ifdef notyet
+ *q6->ip6q_nxtp = (u_char)(nxt & 0xff);
+#endif
/*
* Delete frag6 header with as a few cost as possible.
*/
-
- if (offset < m->m_len)
+ if (offset < m->m_len) {
ovbcopy((caddr_t)ip6, (caddr_t)ip6 + sizeof(struct ip6_frag),
offset);
- else {
- ovbcopy(mtod(m, caddr_t), (caddr_t)ip6 + offset, m->m_len);
- m->m_data -= sizeof(struct ip6_frag);
+ m->m_data += sizeof(struct ip6_frag);
+ m->m_len -= sizeof(struct ip6_frag);
+ } else {
+ /* this comes with no copy if the boundary is on cluster */
+ if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) {
+ frag6_remque(q6);
+ free(q6, M_FTABLE);
+ frag6_nfragpackets--;
+ goto dropfrag;
+ }
+ m_adj(t, sizeof(struct ip6_frag));
+ m_cat(m, t);
}
- m->m_data -= offset;
- m->m_len += offset;
/*
* Store NXT to the original.
@@ -458,8 +555,6 @@ frag6_freef(q6)
struct ip6_hdr *ip6;
/* adjust pointer */
- m->m_data -= af6->ip6af_offset;
- m->m_len += af6->ip6af_offset;
ip6 = mtod(m, struct ip6_hdr *);
/* restoure source and destination addresses */
@@ -468,9 +563,9 @@ frag6_freef(q6)
icmp6_error(m, ICMP6_TIME_EXCEEDED,
ICMP6_TIME_EXCEED_REASSEMBLY, 0);
- }
- else
+ } else
m_freem(m);
+ free(af6, M_FTABLE);
}
frag6_remque(q6);
free(q6, M_FTABLE);
@@ -530,6 +625,9 @@ 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;
@@ -554,6 +652,23 @@ frag6_slowtimo()
frag6_freef(ip6q.ip6q_prev);
}
frag6_doing_reass = 0;
+
+#if 0
+ /*
+ * Routing changes might produce a better route than we last used;
+ * make sure we notice eventually, even if forwarding only for one
+ * destination and the cache is never replaced.
+ */
+ if (ip6_forward_rt.ro_rt) {
+ RTFREE(ip6_forward_rt.ro_rt);
+ ip6_forward_rt.ro_rt = 0;
+ }
+ if (ipsrcchk_rt.ro_rt) {
+ RTFREE(ipsrcchk_rt.ro_rt);
+ ipsrcchk_rt.ro_rt = 0;
+ }
+#endif
+
splx(s);
}
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 05edc914afac..b017bd8b94bf 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: icmp6.c,v 1.119 2000/07/03 14:16:46 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -64,6 +65,8 @@
* @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
*/
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_ipsec.h"
#include <sys/param.h>
@@ -84,57 +87,62 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#include <netinet6/mld6_var.h>
#include <netinet/in_pcb.h>
+#include <netinet6/in6_pcb.h>
#include <netinet6/nd6.h>
#include <netinet6/in6_ifattach.h>
#include <netinet6/ip6protosw.h>
#ifdef IPSEC
#include <netinet6/ipsec.h>
-#include <netinet6/ah.h>
+#ifdef INET6
#include <netinet6/ipsec6.h>
-#include <netinet6/ah6.h>
+#endif
#include <netkey/key.h>
-#ifdef IPSEC_DEBUG
-#include <netkey/key_debug.h>
-#else
-#define KEYDEBUG(lev,arg)
#endif
-#endif /* IPSEC */
#include "faith.h"
#include <net/net_osdep.h>
-extern struct domain inet6domain;
-extern struct ip6protosw inet6sw[];
-extern u_char ip6_protox[];
-
-struct icmp6stat icmp6stat;
-
-extern struct inpcbhead ripcb;
-extern u_int icmp6errratelim;
-
-static int icmp6_rip6_input __P((struct mbuf **, int));
-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 *));
-static struct mbuf *ni6_input __P((struct mbuf *, int));
-static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *,
- struct ifnet **));
-static int ni6_store_addrs __P((struct icmp6_nodeinfo *,
- struct icmp6_nodeinfo *,
- struct ifnet *, int));
+extern struct domain inet6domain;
+extern struct ip6protosw inet6sw[];
+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;
+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 *));
+#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 **));
+static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
+ struct ifnet *, int));
#ifdef COMPAT_RFC1885
-static struct route_in6 icmp6_reflect_rt;
+static struct route_in6 icmp6_reflect_rt;
#endif
-static struct timeval icmp6_nextsend = {0, 0};
void
icmp6_init()
@@ -142,6 +150,64 @@ icmp6_init()
mld6_init();
}
+static void
+icmp6_errcount(stat, type, code)
+ struct icmp6errstat *stat;
+ int type, code;
+{
+ switch(type) {
+ case ICMP6_DST_UNREACH:
+ switch (code) {
+ case ICMP6_DST_UNREACH_NOROUTE:
+ stat->icp6errs_dst_unreach_noroute++;
+ return;
+ case ICMP6_DST_UNREACH_ADMIN:
+ stat->icp6errs_dst_unreach_admin++;
+ return;
+ case ICMP6_DST_UNREACH_BEYONDSCOPE:
+ stat->icp6errs_dst_unreach_beyondscope++;
+ return;
+ case ICMP6_DST_UNREACH_ADDR:
+ stat->icp6errs_dst_unreach_addr++;
+ return;
+ case ICMP6_DST_UNREACH_NOPORT:
+ stat->icp6errs_dst_unreach_noport++;
+ return;
+ }
+ break;
+ case ICMP6_PACKET_TOO_BIG:
+ stat->icp6errs_packet_too_big++;
+ return;
+ case ICMP6_TIME_EXCEEDED:
+ switch(code) {
+ case ICMP6_TIME_EXCEED_TRANSIT:
+ stat->icp6errs_time_exceed_transit++;
+ return;
+ case ICMP6_TIME_EXCEED_REASSEMBLY:
+ stat->icp6errs_time_exceed_reassembly++;
+ return;
+ }
+ break;
+ case ICMP6_PARAM_PROB:
+ switch(code) {
+ case ICMP6_PARAMPROB_HEADER:
+ stat->icp6errs_paramprob_header++;
+ return;
+ case ICMP6_PARAMPROB_NEXTHEADER:
+ stat->icp6errs_paramprob_nextheader++;
+ return;
+ case ICMP6_PARAMPROB_OPTION:
+ stat->icp6errs_paramprob_option++;
+ return;
+ }
+ break;
+ case ND_REDIRECT:
+ stat->icp6errs_redirect++;
+ return;
+ }
+ stat->icp6errs_unknown++;
+}
+
/*
* Generate an error packet of type error in response to bad IP6 packet.
*/
@@ -152,15 +218,31 @@ icmp6_error(m, type, code, param)
{
struct ip6_hdr *oip6, *nip6;
struct icmp6_hdr *icmp6;
- u_int prep;
+ u_int preplen;
int off;
- u_char nxt;
+ int nxt;
icmp6stat.icp6s_error++;
- if (m->m_flags & M_DECRYPTED)
+ /* count per-type-code statistics */
+ icmp6_errcount(&icmp6stat.icp6s_outerrhist, type, code);
+
+#ifdef M_DECRYPTED /*not openbsd*/
+ if (m->m_flags & M_DECRYPTED) {
+ icmp6stat.icp6s_canterror++;
goto freeit;
+ }
+#endif
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
+#else
+ if (m->m_len < sizeof(struct ip6_hdr)) {
+ m = m_pullup(m, sizeof(struct ip6_hdr));
+ if (m == NULL)
+ return;
+ }
+#endif
oip6 = mtod(m, struct ip6_hdr *);
/*
@@ -181,68 +263,41 @@ icmp6_error(m, type, code, param)
goto freeit;
/*
- * If the erroneous packet is also an ICMP error, discard it.
+ * If we are about to send ICMPv6 against ICMPv6 error/redirect,
+ * don't do it.
*/
- IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
- off = sizeof(struct ip6_hdr);
- nxt = oip6->ip6_nxt;
- while(1) { /* XXX: should avoid inf. loop explicitly? */
- struct ip6_ext *ip6e;
+ nxt = -1;
+ off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
+ if (off >= 0 && nxt == IPPROTO_ICMPV6) {
struct icmp6_hdr *icp;
- switch(nxt) {
- case IPPROTO_IPV6:
- case IPPROTO_IPV4:
- case IPPROTO_UDP:
- case IPPROTO_TCP:
- case IPPROTO_ESP:
- case IPPROTO_FRAGMENT:
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), );
+ icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
+#else
+ IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
+ sizeof(*icp));
+ if (icp == NULL) {
+ icmp6stat.icp6s_tooshort++;
+ return;
+ }
+#endif
+ if (icp->icmp6_type < ICMP6_ECHO_REQUEST ||
+ icp->icmp6_type == ND_REDIRECT) {
/*
- * ICMPv6 error must not be fragmented.
- * XXX: but can we trust the sender?
+ * ICMPv6 error
+ * Special case: for redirect (which is
+ * informational) we must not send icmp6 error.
*/
- default:
- /* What if unknown header followed by ICMP error? */
- goto generate;
- case IPPROTO_ICMPV6:
- IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), );
- icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
- if (icp->icmp6_type < ICMP6_ECHO_REQUEST
- || icp->icmp6_type == ND_REDIRECT) {
- /*
- * ICMPv6 error
- * Special case: for redirect (which is
- * informational) we must not send icmp6 error.
- */
- icmp6stat.icp6s_canterror++;
- goto freeit;
- } else {
- /* ICMPv6 informational */
- goto generate;
- }
- case IPPROTO_HOPOPTS:
- case IPPROTO_DSTOPTS:
- case IPPROTO_ROUTING:
- case IPPROTO_AH:
- IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct ip6_ext), );
- ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off);
- if (nxt == IPPROTO_AH)
- off += (ip6e->ip6e_len + 2) << 2;
- else
- off += (ip6e->ip6e_len + 1) << 3;
- nxt = ip6e->ip6e_nxt;
- break;
+ icmp6stat.icp6s_canterror++;
+ goto freeit;
+ } else {
+ /* ICMPv6 informational - send the error */
}
+ } else {
+ /* non-ICMPv6 - send the error */
}
- freeit:
- /*
- * If we can't tell wheter or not we can generate ICMP6, free it.
- */
- m_freem(m);
- return;
-
- generate:
oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
/* Finally, do rate limitation check. */
@@ -258,10 +313,10 @@ icmp6_error(m, type, code, param)
if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN)
m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
- prep = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
- M_PREPEND(m, prep, M_DONTWAIT);
- if (m && m->m_len < prep)
- m = m_pullup(m, prep);
+ preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
+ M_PREPEND(m, preplen, M_DONTWAIT);
+ if (m && m->m_len < preplen)
+ m = m_pullup(m, preplen);
if (m == NULL) {
printf("ENOBUFS in icmp6_error %d\n", __LINE__);
return;
@@ -283,6 +338,14 @@ icmp6_error(m, type, code, param)
icmp6stat.icp6s_outhist[type]++;
icmp6_reflect(m, sizeof(struct ip6_hdr)); /*header order: IPv6 - ICMPv6*/
+
+ return;
+
+ freeit:
+ /*
+ * If we can't tell wheter or not we can generate ICMP6, free it.
+ */
+ m_freem(m);
}
/*
@@ -301,8 +364,10 @@ icmp6_input(mp, offp, proto)
int code, sum, noff;
struct sockaddr_in6 icmp6src;
+#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE);
/* m might change if M_LOOP. So, call mtod after this */
+#endif
/*
* Locate icmp6 structure in mbuf, and check
@@ -318,8 +383,15 @@ icmp6_input(mp, offp, proto)
/*
* calculate the checksum
*/
-
+#ifndef PULLDOWN_TEST
icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
+#else
+ IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
+ if (icmp6 == NULL) {
+ icmp6stat.icp6s_tooshort++;
+ return IPPROTO_DONE;
+ }
+#endif
code = icmp6->icmp6_code;
if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
@@ -373,12 +445,21 @@ icmp6_input(mp, offp, proto)
break;
case ICMP6_DST_UNREACH_ADMIN:
icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib);
+ code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
+ break;
case ICMP6_DST_UNREACH_ADDR:
- code = PRC_UNREACH_HOST;
+ code = PRC_HOSTDEAD;
break;
+#ifdef COMPAT_RFC1885
case ICMP6_DST_UNREACH_NOTNEIGHBOR:
code = PRC_UNREACH_SRCFAIL;
break;
+#else
+ case ICMP6_DST_UNREACH_BEYONDSCOPE:
+ /* I mean "source address was incorrect." */
+ code = PRC_PARAMPROB;
+ break;
+#endif
case ICMP6_DST_UNREACH_NOPORT:
code = PRC_UNREACH_PORT;
break;
@@ -392,33 +473,14 @@ icmp6_input(mp, offp, proto)
icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig);
if (code != 0)
goto badcode;
- {
- u_int mtu = ntohl(icmp6->icmp6_mtu);
- struct rtentry *rt = NULL;
- struct sockaddr_in6 sin6;
code = PRC_MSGSIZE;
- bzero(&sin6, sizeof(sin6));
- sin6.sin6_family = PF_INET6;
- sin6.sin6_len = sizeof(struct sockaddr_in6);
- sin6.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
- rt = rtalloc1((struct sockaddr *)&sin6, 0,
- RTF_CLONING | RTF_PRCLONING);
- if (rt && (rt->rt_flags & RTF_HOST)
- && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
- if (mtu < IPV6_MMTU) {
- /* xxx */
- rt->rt_rmx.rmx_locks |= RTV_MTU;
- } else if (mtu < rt->rt_ifp->if_mtu &&
- rt->rt_rmx.rmx_mtu > mtu) {
- rt->rt_rmx.rmx_mtu = mtu;
- }
- }
- if (rt)
- RTFREE(rt);
+ /*
+ * Updating the path MTU will be done after examining
+ * intermediate extension headers.
+ */
goto deliver;
- }
break;
case ICMP6_TIME_EXCEEDED:
@@ -458,23 +520,37 @@ icmp6_input(mp, offp, proto)
/* Give up remote */
break;
}
- if (n->m_flags & M_EXT) {
- int gap, move;
+ if ((n->m_flags & M_EXT) != 0
+ || n->m_len < off + sizeof(struct icmp6_hdr)) {
struct mbuf *n0 = n;
+ const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);
/*
* Prepare an internal mbuf. m_pullup() doesn't
* always copy the length we specified.
*/
+ if (maxlen >= MCLBYTES) {
+#ifdef DIAGNOSTIC
+ printf("MCLBYTES too small\n");
+#endif
+ /* Give up remote */
+ m_freem(n0);
+ break;
+ }
MGETHDR(n, M_DONTWAIT, n0->m_type);
+ if (n && maxlen >= MHLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_free(n);
+ n = NULL;
+ }
+ }
if (n == NULL) {
/* Give up remote */
m_freem(n0);
break;
}
M_COPY_PKTHDR(n, n0);
- n0->m_flags &= ~M_PKTHDR;
- n->m_next = n0;
/*
* Copy IPv6 and ICMPv6 only.
*/
@@ -482,16 +558,17 @@ icmp6_input(mp, offp, proto)
bcopy(ip6, nip6, sizeof(struct ip6_hdr));
nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
+ noff = sizeof(struct ip6_hdr);
+ n->m_pkthdr.len = n->m_len =
+ noff + sizeof(struct icmp6_hdr);
/*
- * Adjust mbuf. ip6_plen will be adjusted.
+ * Adjust mbuf. ip6_plen will be adjusted in
+ * ip6_output().
*/
- noff = sizeof(struct ip6_hdr);
- n->m_len = noff + sizeof(struct icmp6_hdr);
- move = off + sizeof(struct icmp6_hdr);
- n0->m_len -= move;
- n0->m_data += move;
- gap = off - noff;
- n->m_pkthdr.len -= gap;
+ m_adj(n0, off + sizeof(struct icmp6_hdr));
+ n->m_pkthdr.len += n0->m_pkthdr.len;
+ n->m_next = n0;
+ n0->m_flags &= ~M_PKTHDR;
} else {
nip6 = mtod(n, struct ip6_hdr *);
nicmp6 = (struct icmp6_hdr *)((caddr_t)nip6 + off);
@@ -520,8 +597,13 @@ icmp6_input(mp, offp, proto)
icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery);
else
icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport);
- IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
- mld6_input(m, off);
+ if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
+ /* give up local */
+ mld6_input(m, off);
+ m = NULL;
+ goto freeit;
+ }
+ mld6_input(n, off);
/* m stays. */
break;
@@ -535,35 +617,63 @@ icmp6_input(mp, offp, proto)
case MLD6_MTRACE:
/* XXX: these two are experimental. not officially defind. */
/* XXX: per-interface statistics? */
- break; /* just pass it to the userland daemon */
+ break; /* just pass it to applications */
case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */
{
enum { WRU, FQDN } mode;
- if (code != 0)
- goto badcode;
+ if (!icmp6_nodeinfo)
+ break;
+
if (icmp6len == sizeof(struct icmp6_hdr) + 4)
mode = WRU;
- else if (icmp6len >= sizeof(struct icmp6_hdr) + 8) /* XXX */
+ else if (icmp6len >= sizeof(struct icmp6_nodeinfo))
mode = FQDN;
else
goto badlen;
#define hostnamelen strlen(hostname)
if (mode == FQDN) {
+#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_nodeinfo),
IPPROTO_DONE);
- n = ni6_input(m, off);
+#endif
+ n = m_copy(m, 0, M_COPYALL);
+ if (n)
+ n = ni6_input(n, off);
+ /* XXX meaningless if n == NULL */
noff = sizeof(struct ip6_hdr);
} else {
u_char *p;
-
+ int maxlen, maxhlen;
+
+ 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;
+ }
MGETHDR(n, M_DONTWAIT, m->m_type);
+ if (n && maxlen > MHLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_free(n);
+ n = NULL;
+ }
+ }
if (n == NULL) {
/* Give up remote */
break;
}
+ n->m_len = 0;
+ maxhlen = M_TRAILINGSPACE(n) - maxlen;
+ if (maxhlen > hostnamelen)
+ maxhlen = hostnamelen;
/*
* Copy IPv6 and ICMPv6 only.
*/
@@ -573,11 +683,11 @@ icmp6_input(mp, offp, proto)
bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
p = (u_char *)(nicmp6 + 1);
bzero(p, 4);
- bcopy(hostname, p + 4, hostnamelen);
+ bcopy(hostname, p + 4, maxhlen); /*meaningless TTL*/
noff = sizeof(struct ip6_hdr);
M_COPY_PKTHDR(n, m); /* just for recvif */
n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
- sizeof(struct icmp6_hdr) + 4 + hostnamelen;
+ sizeof(struct icmp6_hdr) + 4 + maxhlen;
nicmp6->icmp6_type = ICMP6_WRUREPLY;
nicmp6->icmp6_code = 0;
}
@@ -601,8 +711,13 @@ icmp6_input(mp, offp, proto)
goto badcode;
if (icmp6len < sizeof(struct nd_router_solicit))
goto badlen;
- IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
- nd6_rs_input(m, off, icmp6len);
+ if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
+ /* give up local */
+ nd6_rs_input(m, off, icmp6len);
+ m = NULL;
+ goto freeit;
+ }
+ nd6_rs_input(n, off, icmp6len);
/* m stays. */
break;
@@ -612,8 +727,13 @@ icmp6_input(mp, offp, proto)
goto badcode;
if (icmp6len < sizeof(struct nd_router_advert))
goto badlen;
- IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
- nd6_ra_input(m, off, icmp6len);
+ if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
+ /* give up local */
+ nd6_ra_input(m, off, icmp6len);
+ m = NULL;
+ goto freeit;
+ }
+ nd6_ra_input(n, off, icmp6len);
/* m stays. */
break;
@@ -623,8 +743,13 @@ icmp6_input(mp, offp, proto)
goto badcode;
if (icmp6len < sizeof(struct nd_neighbor_solicit))
goto badlen;
- IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
- nd6_ns_input(m, off, icmp6len);
+ if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
+ /* give up local */
+ nd6_ns_input(m, off, icmp6len);
+ m = NULL;
+ goto freeit;
+ }
+ nd6_ns_input(n, off, icmp6len);
/* m stays. */
break;
@@ -634,8 +759,13 @@ icmp6_input(mp, offp, proto)
goto badcode;
if (icmp6len < sizeof(struct nd_neighbor_advert))
goto badlen;
- IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
- nd6_na_input(m, off, icmp6len);
+ if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
+ /* give up local */
+ nd6_na_input(m, off, icmp6len);
+ m = NULL;
+ goto freeit;
+ }
+ nd6_na_input(n, off, icmp6len);
/* m stays. */
break;
@@ -645,7 +775,13 @@ icmp6_input(mp, offp, proto)
goto badcode;
if (icmp6len < sizeof(struct nd_redirect))
goto badlen;
- icmp6_redirect_input(m, off);
+ if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
+ /* give up local */
+ icmp6_redirect_input(m, off);
+ m = NULL;
+ goto freeit;
+ }
+ icmp6_redirect_input(n, off);
/* m stays. */
break;
@@ -675,10 +811,19 @@ icmp6_input(mp, offp, proto)
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);
+#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;
+ }
+#endif
bzero(&icmp6src, sizeof(icmp6src));
icmp6src.sin6_len = sizeof(struct sockaddr_in6);
icmp6src.sin6_family = AF_INET6;
@@ -692,38 +837,153 @@ icmp6_input(mp, offp, proto)
int eoff = off + sizeof(struct icmp6_hdr) +
sizeof(struct ip6_hdr);
struct ip6ctlparam ip6cp;
+ struct in6_addr *finaldst = NULL;
+ int icmp6type = icmp6->icmp6_type;
+ struct ip6_frag *fh;
+ struct ip6_rthdr *rth;
+ struct ip6_rthdr0 *rth0;
+ int rthlen;
while (1) { /* XXX: should avoid inf. loop explicitly? */
struct ip6_ext *eh;
switch(nxt) {
- case IPPROTO_ESP:
- case IPPROTO_NONE:
- goto passit;
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
- case IPPROTO_ROUTING:
case IPPROTO_AH:
- case IPPROTO_FRAGMENT:
+#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, 0, eoff +
sizeof(struct ip6_ext),
IPPROTO_DONE);
eh = (struct ip6_ext *)(mtod(m, caddr_t)
+ eoff);
+#else
+ IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
+ eoff, sizeof(*eh));
+ if (eh == NULL) {
+ icmp6stat.icp6s_tooshort++;
+ return IPPROTO_DONE;
+ }
+#endif
+
if (nxt == IPPROTO_AH)
eoff += (eh->ip6e_len + 2) << 2;
- else if (nxt == IPPROTO_FRAGMENT)
- eoff += sizeof(struct ip6_frag);
else
eoff += (eh->ip6e_len + 1) << 3;
nxt = eh->ip6e_nxt;
break;
+ case IPPROTO_ROUTING:
+ /*
+ * When the erroneous packet contains a
+ * routing header, we should examine the
+ * header to determine the final destination.
+ * Otherwise, we can't properly update
+ * information that depends on the final
+ * destination (e.g. path MTU).
+ */
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth),
+ IPPROTO_DONE);
+ rth = (struct ip6_rthdr *)(mtod(m, caddr_t)
+ + eoff);
+#else
+ IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
+ eoff, sizeof(*rth));
+ if (rth == NULL) {
+ icmp6stat.icp6s_tooshort++;
+ return IPPROTO_DONE;
+ }
+#endif
+ rthlen = (rth->ip6r_len + 1) << 3;
+ /*
+ * XXX: currently there is no
+ * officially defined type other
+ * than type-0.
+ * Note that if the segment left field
+ * is 0, all intermediate hops must
+ * have been passed.
+ */
+ if (rth->ip6r_segleft &&
+ rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
+ int hops;
+
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, 0, eoff + rthlen,
+ IPPROTO_DONE);
+ rth0 = (struct ip6_rthdr0 *)(mtod(m, caddr_t) + eoff);
+#else
+ IP6_EXTHDR_GET(rth0,
+ struct ip6_rthdr0 *, m,
+ eoff, rthlen);
+ if (rth0 == NULL) {
+ icmp6stat.icp6s_tooshort++;
+ return IPPROTO_DONE;
+ }
+#endif
+ /* just ignore a bogus header */
+ if ((rth0->ip6r0_len % 2) == 0 &&
+ (hops = rth0->ip6r0_len/2))
+ finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1);
+ }
+ eoff += rthlen;
+ nxt = rth->ip6r_nxt;
+ break;
+ case IPPROTO_FRAGMENT:
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, 0, eoff +
+ sizeof(struct ip6_frag),
+ IPPROTO_DONE);
+ fh = (struct ip6_frag *)(mtod(m, caddr_t)
+ + eoff);
+#else
+ IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
+ eoff, sizeof(*fh));
+ if (fh == NULL) {
+ icmp6stat.icp6s_tooshort++;
+ return IPPROTO_DONE;
+ }
+#endif
+ /*
+ * Data after a fragment header is meaningless
+ * unless it is the first fragment, but
+ * we'll go to the notify label for path MTU
+ * discovery.
+ */
+ if (fh->ip6f_offlg & IP6F_OFF_MASK)
+ goto notify;
+
+ eoff += sizeof(struct ip6_frag);
+ nxt = fh->ip6f_nxt;
+ break;
default:
+ /*
+ * This case includes ESP and the No Next
+ * Header. In such cases going to the notify
+ * label does not have any meaning
+ * (i.e. ctlfunc will be NULL), but we go
+ * anyway since we might have to update
+ * path MTU information.
+ */
goto 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));
+ if (icmp6 == NULL) {
+ icmp6stat.icp6s_tooshort++;
+ return IPPROTO_DONE;
+ }
+#endif
+ if (icmp6type == ICMP6_PACKET_TOO_BIG) {
+ if (finaldst == NULL)
+ finaldst = &((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
+ icmp6_mtudisc_update(finaldst, icmp6, m);
+ }
+
ctlfunc = (void (*) __P((int, struct sockaddr *, void *)))
(inet6sw[ip6_protox[nxt]].pr_ctlinput);
if (ctlfunc) {
@@ -744,8 +1004,11 @@ icmp6_input(mp, offp, proto)
break;
}
- passit:
+#ifdef HAVE_NRL_INPCB
+ rip6_input(&m, offp, IPPROTO_ICMPV6);
+#else
icmp6_rip6_input(&m, *offp);
+#endif
return IPPROTO_DONE;
freeit:
@@ -753,72 +1016,277 @@ icmp6_input(mp, offp, proto)
return IPPROTO_DONE;
}
+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 */
+{
+ u_int mtu = ntohl(icmp6->icmp6_mtu);
+ struct rtentry *rt = NULL;
+ struct sockaddr_in6 sin6;
+
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = PF_INET6;
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_addr = *dst;
+ /* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */
+ rt = rtalloc1((struct sockaddr *)&sin6, 0,
+ RTF_CLONING | RTF_PRCLONING);
+
+ if (rt && (rt->rt_flags & RTF_HOST)
+ && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
+ if (mtu < IPV6_MMTU) {
+ /* xxx */
+ rt->rt_rmx.rmx_locks |= RTV_MTU;
+ } else if (mtu < rt->rt_ifp->if_mtu &&
+ rt->rt_rmx.rmx_mtu > mtu) {
+ rt->rt_rmx.rmx_mtu = mtu;
+ }
+ }
+ if (rt)
+ RTFREE(rt);
+}
+
/*
- * Process a Node Information Query
+ * Process a Node Information Query packet, (roughly) based on
+ * draft-ietf-ipngwg-icmp-name-lookups-05.
+ *
+ * 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)
+#define hostnamelen strlen(hostname)
#ifndef offsetof /* XXX */
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
#endif
-
static struct mbuf *
ni6_input(m, off)
struct mbuf *m;
int off;
{
- struct icmp6_nodeinfo *ni6 =
- (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off), *nni6;
+ struct icmp6_nodeinfo *ni6, *nni6;
struct mbuf *n = NULL;
- u_int16_t qtype = ntohs(ni6->ni_qtype);
+ u_int16_t qtype;
+ int subjlen;
int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
struct ni_reply_fqdn *fqdn;
int addrs; /* for NI_QTYPE_NODEADDR */
struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */
+ struct sockaddr_in6 sin6;
+ struct ip6_hdr *ip6;
+ int oldfqdn = 0; /* if 1, return pascal string (03 draft) */
+ char *subj;
+
+ ip6 = mtod(m, struct ip6_hdr *);
+#ifndef PULLDOWN_TEST
+ ni6 = (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off);
+#else
+ IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6));
+ if (ni6 == NULL) {
+ /* m is already reclaimed */
+ return NULL;
+ }
+#endif
+
+ /*
+ * 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.
+ */
+ 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*/
+ 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. */
+ 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;
+
+ case NI_QTYPE_FQDN:
+ case NI_QTYPE_NODEADDR:
+ switch (ni6->ni_code) {
+ case ICMP6_NI_SUBJ_IPV6:
+#if ICMP6_NI_SUBJ_IPV6 != 0
+ case 0:
+#endif
+ /*
+ * backward compatibility - try to accept 03 draft
+ * format, where no Subject is present.
+ */
+ if (subjlen == 0) {
+ oldfqdn++;
+ break;
+ }
+
+ if (subjlen != sizeof(sin6.sin6_addr))
+ goto bad;
- 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:
- replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_name) +
- hostnamelen;
- 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;
- replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_name) +
- hostnamelen;
- break;
+ /*
+ * Validate Subject address.
+ *
+ * Not sure what exactly does "address belongs to the
+ * node" mean 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
+ * to the IPv6 destination address; validation for
+ * IPv6 destination address should have done enough
+ * check for us.
+ *
+ * We do not do proxy at this moment.
+ */
+ /* 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];
+ }
+#endif
+ }
+ if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6.sin6_addr))
+ break;
+ /*
+ * XXX if we are to allow other cases, we should really
+ * be careful about scope here.
+ * basically, we should disallow queries toward IPv6
+ * destination X with subject Y, if scope(X) > scope(Y).
+ * if we allow scope(X) > scope(Y), it will result in
+ * information leakage across scope boundary.
+ */
+ goto bad;
+
+ case ICMP6_NI_SUBJ_FQDN:
+ /*
+ * Validate Subject name with gethostname(3).
+ *
+ * The behavior may need some debate, since:
+ * - we are not sure if the node has FQDN as
+ * hostname (returned by gethostname(3)).
+ * - the code does wildcard match for truncated names.
+ * however, we are not sure if we want to perform
+ * wildcard match, if gethostname(3) side has
+ * truncated hostname.
+ */
+ n = ni6_nametodns(hostname, hostnamelen, 0);
+ if (!n || n->m_next || n->m_len == 0)
+ goto bad;
+ IP6_EXTHDR_GET(subj, char *, m,
+ off + sizeof(struct icmp6_nodeinfo), subjlen);
+ if (subj == NULL)
+ goto bad;
+ if (!ni6_dnsmatch(subj, subjlen, mtod(n, const char *),
+ n->m_len)) {
+ goto bad;
+ }
+ m_freem(n);
+ n = NULL;
+ break;
+
+ case ICMP6_NI_SUBJ_IPV4: /* xxx: to be implemented? */
+ default:
+ goto bad;
+ }
+ break;
+
+ default:
+ /* should never be here due to "switch (qtype)" above */
+ goto bad;
}
/* allocate a mbuf to reply. */
MGETHDR(n, M_DONTWAIT, m->m_type);
- if (n == NULL)
+ if (n == NULL) {
+ m_freem(m);
return(NULL);
+ }
M_COPY_PKTHDR(n, m); /* just for recvif */
if (replylen > MHLEN) {
- if (replylen > MCLBYTES)
+ if (replylen > MCLBYTES) {
/*
* XXX: should we try to allocate more? But MCLBYTES is
* probably much larger than IPV6_MMTU...
*/
goto bad;
+ }
MCLGET(n, M_DONTWAIT);
if ((n->m_flags & M_EXT) == 0) {
goto bad;
@@ -829,56 +1297,60 @@ ni6_input(m, off)
/* copy mbuf header and IPv6 + Node Information base headers */
bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr));
nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1);
- bcopy(mtod(m, caddr_t) + off, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo));
+ bcopy((caddr_t)ni6, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo));
/* qtype dependent procedure */
switch (qtype) {
- case NI_QTYPE_NOOP:
- nni6->ni_flags = 0;
- break;
- case NI_QTYPE_SUPTYPES:
- goto bad; /* xxx: to be implemented */
- break;
- case NI_QTYPE_FQDN:
- if (hostnamelen > 255) { /* XXX: rare case, but may happen */
- printf("ni6_input: "
- "hostname length(%d) is too large for reply\n",
- hostnamelen);
- goto bad;
- }
- fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) +
- sizeof(struct ip6_hdr) +
- sizeof(struct icmp6_nodeinfo));
- nni6->ni_flags = 0; /* XXX: meaningless TTL */
- fqdn->ni_fqdn_ttl = 0; /* ditto. */
- fqdn->ni_fqdn_namelen = hostnamelen;
- bcopy(hostname, &fqdn->ni_fqdn_name[0], hostnamelen);
- break;
- case NI_QTYPE_NODEADDR:
- {
- 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);
- copied = ni6_store_addrs(ni6, nni6, ifp, lenlim);
- /* XXX: reset mbuf length */
- n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
- sizeof(struct icmp6_nodeinfo) + copied;
- break;
- }
- default:
- break; /* XXX impossible! */
+ case NI_QTYPE_NOOP:
+ nni6->ni_flags = 0;
+ break;
+ case NI_QTYPE_SUPTYPES:
+ goto bad; /* xxx: to be implemented */
+ break;
+ case NI_QTYPE_FQDN:
+ fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) +
+ sizeof(struct ip6_hdr) +
+ sizeof(struct icmp6_nodeinfo));
+ nni6->ni_flags = 0; /* XXX: meaningless TTL */
+ fqdn->ni_fqdn_ttl = 0; /* ditto. */
+ /*
+ * XXX do we really have FQDN in variable "hostname"?
+ */
+ n->m_next = ni6_nametodns(hostname, hostnamelen, oldfqdn);
+ if (n->m_next == NULL)
+ goto bad;
+ /* XXX we assume that n->m_next is not a chain */
+ if (n->m_next->m_next != NULL)
+ goto bad;
+ n->m_pkthdr.len += n->m_next->m_len;
+ break;
+ case NI_QTYPE_NODEADDR:
+ {
+ 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);
+ copied = ni6_store_addrs(ni6, nni6, ifp, lenlim);
+ /* XXX: reset mbuf length */
+ n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
+ sizeof(struct icmp6_nodeinfo) + copied;
+ break;
+ }
+ default:
+ break; /* XXX impossible! */
}
nni6->ni_type = ICMP6_NI_REPLY;
nni6->ni_code = ICMP6_NI_SUCESS;
+ m_freem(m);
return(n);
bad:
+ m_freem(m);
if (n)
m_freem(n);
return(NULL);
@@ -886,6 +1358,168 @@ ni6_input(m, off)
#undef hostnamelen
/*
+ * make a mbuf with DNS-encoded string. no compression support.
+ *
+ * XXX names with less than 2 dots (like "foo" or "foo.section") will be
+ * treated as truncated name (two \0 at the end). this is a wild guess.
+ */
+static struct mbuf *
+ni6_nametodns(name, namelen, old)
+ const char *name;
+ int namelen;
+ int old; /* return pascal string if non-zero */
+{
+ struct mbuf *m;
+ char *cp, *ep;
+ const char *p, *q;
+ int i, len, nterm;
+
+ if (old)
+ len = namelen + 1;
+ else
+ len = MCLBYTES;
+
+ /* because MAXHOSTNAMELEN is usually 256, we use cluster mbuf */
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m && len > MLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0)
+ goto fail;
+ }
+ if (!m)
+ goto fail;
+ m->m_next = NULL;
+
+ if (old) {
+ m->m_len = len;
+ *mtod(m, char *) = namelen;
+ bcopy(name, mtod(m, char *) + 1, namelen);
+ return m;
+ } else {
+ m->m_len = 0;
+ cp = mtod(m, char *);
+ ep = mtod(m, char *) + M_TRAILINGSPACE(m);
+
+ /* if not certain about my name, return empty buffer */
+ if (namelen == 0)
+ return m;
+
+ /*
+ * guess if it looks like shortened hostname, or FQDN.
+ * shortened hostname needs two trailing "\0".
+ */
+ i = 0;
+ for (p = name; p < name + namelen; p++) {
+ if (*p && *p == '.')
+ i++;
+ }
+ if (i < 2)
+ nterm = 2;
+ else
+ nterm = 1;
+
+ p = name;
+ while (cp < ep && p < name + namelen) {
+ i = 0;
+ for (q = p; q < name + namelen && *q && *q != '.'; q++)
+ i++;
+ /* result does not fit into mbuf */
+ if (cp + i + 1 >= ep)
+ goto fail;
+ /* DNS label length restriction, RFC1035 page 8 */
+ if (i >= 64)
+ goto fail;
+ *cp++ = i;
+ bcopy(p, cp, i);
+ cp += i;
+ p = q;
+ if (p < name + namelen && *p == '.')
+ p++;
+ }
+ /* termination */
+ if (cp + nterm >= ep)
+ goto fail;
+ while (nterm-- > 0)
+ *cp++ = '\0';
+ m->m_len = cp - mtod(m, char *);
+ return m;
+ }
+
+ panic("should not reach here");
+ /*NOTREACHED*/
+
+ fail:
+ if (m)
+ m_freem(m);
+ return NULL;
+}
+
+/*
+ * check if two DNS-encoded string matches. takes care of truncated
+ * form (with \0\0 at the end). no compression support.
+ */
+static int
+ni6_dnsmatch(a, alen, b, blen)
+ const char *a;
+ int alen;
+ const char *b;
+ int blen;
+{
+ const char *a0, *b0;
+ int l;
+
+ /* simplest case - need validation? */
+ if (alen == blen && bcmp(a, b, alen) == 0)
+ return 1;
+
+ a0 = a;
+ b0 = b;
+
+ /* termination is mandatory */
+ if (alen < 2 || blen < 2)
+ return 0;
+ if (a0[alen - 1] != '\0' || b0[blen - 1] != '\0')
+ return 0;
+ alen--;
+ blen--;
+
+ while (a - a0 < alen && b - b0 < blen) {
+ if (a - a0 + 1 > alen || b - b0 + 1 > blen)
+ return 0;
+
+ if ((signed char)a[0] < 0 || (signed char)b[0] < 0)
+ return 0;
+ /* we don't support compression yet */
+ if (a[0] >= 64 || b[0] >= 64)
+ return 0;
+
+ /* truncated case */
+ if (a[0] == 0 && a - a0 == alen - 1)
+ return 1;
+ if (b[0] == 0 && b - b0 == blen - 1)
+ return 1;
+ if (a[0] == 0 || b[0] == 0)
+ return 0;
+
+ if (a[0] != b[0])
+ return 0;
+ l = a[0];
+ if (a - a0 + 1 + l > alen || b - b0 + 1 + l > blen)
+ return 0;
+ if (bcmp(a + 1, b + 1, l) != 0)
+ return 0;
+
+ a += 1 + l;
+ b += 1 + l;
+ }
+
+ if (a - a0 == alen && b - b0 == blen)
+ return 1;
+ else
+ return 0;
+}
+
+/*
* calculate the number of addresses to be returned in the node info reply.
*/
static int
@@ -903,7 +1537,8 @@ ni6_addrs(ni6, m, ifpp)
for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
{
addrsofif = 0;
- TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
+ for (ifa = ifp->if_addrlist.tqh_first; ifa;
+ ifa = ifa->ifa_list.tqe_next)
{
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@@ -914,12 +1549,18 @@ ni6_addrs(ni6, m, ifpp)
&ifa6->ia_addr.sin6_addr))
iffound = 1;
- if (ifa6->ia6_flags & IN6_IFF_ANYCAST) {
- if ((ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST)
- != 0)
- addrsofif++;
+ /*
+ * IPv4-mapped addresses can only be returned by a
+ * Node Information proxy, since they represent
+ * addresses of IPv4-only nodes, which perforce do
+ * not implement this protocol.
+ * [icmp-name-lookups-05]
+ * 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 |
@@ -972,7 +1613,8 @@ ni6_store_addrs(ni6, nni6, ifp0, resid)
for (; ifp; ifp = TAILQ_NEXT(ifp, if_list))
{
- TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
+ for (ifa = ifp->if_addrlist.tqh_first; ifa;
+ ifa = ifa->ifa_list.tqe_next)
{
docopy = 0;
@@ -986,9 +1628,12 @@ ni6_store_addrs(ni6, nni6, ifp0, resid)
docopy = 1;
else
continue;
- } else { /* unicast address */
+ }
+ else { /* unicast address */
if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST)
continue;
+ else
+ docopy = 1;
}
/* What do we have to do about ::1? */
@@ -1052,26 +1697,26 @@ icmp6_rip6_input(mp, off)
struct icmp6_hdr *icmp6;
struct mbuf *opts = NULL;
+#ifndef PULLDOWN_TEST
/* this is assumed to be safe. */
icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
+#else
+ IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
+ if (icmp6 == NULL) {
+ /* m is already reclaimed */
+ return IPPROTO_DONE;
+ }
+#endif
bzero(&rip6src, sizeof(rip6src));
rip6src.sin6_len = sizeof(struct sockaddr_in6);
rip6src.sin6_family = AF_INET6;
- rip6src.sin6_addr = ip6->ip6_src;
- if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
- rip6src.sin6_addr.s6_addr16[1] = 0;
- if (m->m_pkthdr.rcvif) {
- if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
- rip6src.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
- else
- rip6src.sin6_scope_id = 0;
- } else
- rip6src.sin6_scope_id = 0;
+ /* KAME hack: recover scopeid */
+ (void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif);
LIST_FOREACH(in6p, &ripcb, inp_list)
{
- if ((in6p->inp_vflag & INP_IPV6) == 0)
+ if ((in6p->inp_vflag & INP_IPV6) == NULL)
continue;
if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6)
continue;
@@ -1127,22 +1772,18 @@ icmp6_rip6_input(mp, off)
/*
* Reflect the ip6 packet back to the source.
- * The caller MUST check if the destination is multicast or not.
- * This function is usually called with a unicast destination which
- * can be safely the source of the reply packet. But some exceptions
- * exist(e.g. ECHOREPLY, PATCKET_TOOBIG, "10" in OPTION type).
- * ``off'' points to the icmp6 header, counted from the top of the mbuf.
+ * OFF points to the icmp6 header, counted from the top of the mbuf.
*/
void
icmp6_reflect(m, off)
struct mbuf *m;
size_t off;
{
- struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+ struct ip6_hdr *ip6;
struct icmp6_hdr *icmp6;
struct in6_ifaddr *ia;
struct in6_addr t, *src = 0;
- int plen = m->m_pkthdr.len - sizeof(struct ip6_hdr);
+ int plen;
int type, code;
struct ifnet *outif = NULL;
#ifdef COMPAT_RFC1885
@@ -1150,41 +1791,46 @@ icmp6_reflect(m, off)
struct sockaddr_in6 *sin6 = &icmp6_reflect_rt.ro_dst;
#endif
+ /* 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__);
+ goto bad;
+ }
+
/*
* If there are extra headers between IPv6 and ICMPv6, strip
* off that header first.
*/
- if (off != sizeof(struct ip6_hdr)) {
- size_t siz;
-
- /* sanity checks */
- if (off < sizeof(struct ip6_hdr)) {
- printf("sanity fail: off=%x, sizeof(ip6)=%x in %s:%d\n",
- (unsigned int)off,
- (unsigned int)sizeof(struct ip6_hdr),
- __FILE__, __LINE__);
- goto bad;
+#ifdef DIAGNOSTIC
+ if (sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) > MHLEN)
+ panic("assumption failed in icmp6_reflect");
+#endif
+ if (off > sizeof(struct ip6_hdr)) {
+ size_t l;
+ struct ip6_hdr nip6;
+
+ l = off - sizeof(struct ip6_hdr);
+ m_copydata(m, 0, sizeof(nip6), (caddr_t)&nip6);
+ m_adj(m, l);
+ l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
+ if (m->m_len < l) {
+ if ((m = m_pullup(m, l)) == NULL)
+ return;
}
- siz = off - sizeof(struct ip6_hdr);
- if (plen < siz) {
- printf("sanity fail: siz=%x, payloadlen=%x in %s:%d\n",
- (unsigned int)siz, plen, __FILE__, __LINE__);
- goto bad;
+ bcopy((caddr_t)&nip6, mtod(m, caddr_t), sizeof(nip6));
+ } else /* off == sizeof(struct ip6_hdr) */ {
+ size_t l;
+ l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
+ if (m->m_len < l) {
+ if ((m = m_pullup(m, l)) == NULL)
+ return;
}
- IP6_EXTHDR_CHECK(m, 0, off, /*nothing*/);
- IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), /*nothing*/);
-
- ovbcopy((caddr_t)ip6,
- (caddr_t)(mtod(m, u_char *) + siz),
- sizeof(struct ip6_hdr));
- m->m_data += siz;
- m->m_len -= siz;
- m->m_pkthdr.len -= siz;
- ip6 = mtod(m, struct ip6_hdr *);
- ip6->ip6_nxt = IPPROTO_ICMPV6;
- plen -= siz;
}
-
+ plen = m->m_pkthdr.len - sizeof(struct ip6_hdr);
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_nxt = IPPROTO_ICMPV6;
icmp6 = (struct icmp6_hdr *)(ip6 + 1);
type = icmp6->icmp6_type; /* keep type for statistics */
code = icmp6->icmp6_code; /* ditto. */
@@ -1240,10 +1886,13 @@ icmp6_reflect(m, off)
/*
* If the incoming packet was addressed directly to us(i.e. unicast),
* use dst as the src for the reply.
+ * The IN6_IFF_NOTREADY case would be VERY rare, but is possible
+ * (for example) when we encounter an error while forwarding procedure
+ * destined to a duplicated address of ours.
*/
for (ia = in6_ifaddr; ia; ia = ia->ia_next)
if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) &&
- (ia->ia6_flags & IN6_IFF_ANYCAST) == 0) {
+ (ia->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0) {
src = &t;
break;
}
@@ -1257,9 +1906,11 @@ icmp6_reflect(m, off)
if (src == 0)
/*
- * We have not multicast routing yet. So this case matches
- * to our multicast, our anycast or not to our unicast.
- * Select a source address which has the same scope.
+ * 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.
*/
if ((ia = in6_ifawithscope(m->m_pkthdr.rcvif, &t)) != 0)
src = &IA6_SIN6(ia)->sin6_addr;
@@ -1270,7 +1921,8 @@ icmp6_reflect(m, off)
ip6->ip6_src = *src;
ip6->ip6_flow = 0;
- ip6->ip6_vfc = IPV6_VERSION;
+ ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
+ ip6->ip6_vfc |= IPV6_VERSION;
ip6->ip6_nxt = IPPROTO_ICMPV6;
if (m->m_pkthdr.rcvif) {
/* XXX: This may not be the outgoing interface */
@@ -1286,6 +1938,10 @@ icmp6_reflect(m, off)
*/
m->m_flags &= ~(M_BCAST|M_MCAST);
+#ifdef IPSEC
+ /* Don't lookup socket */
+ ipsec_setsocket(m, NULL);
+#endif /*IPSEC*/
#ifdef COMPAT_RFC1885
ip6_output(m, NULL, &icmp6_reflect_rt, 0, NULL, &outif);
@@ -1305,7 +1961,11 @@ icmp6_reflect(m, off)
void
icmp6_fasttimo()
{
+
mld6_fasttimeo();
+
+ /* reset ICMPv6 pps limit */
+ icmp6errpps_count = 0;
}
static const char *
@@ -1327,7 +1987,7 @@ icmp6_redirect_input(m, off)
{
struct ifnet *ifp = m->m_pkthdr.rcvif;
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
- struct nd_redirect *nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off);
+ struct nd_redirect *nd_rd;
int icmp6len = ntohs(ip6->ip6_plen);
char *lladdr = NULL;
int lladdrlen = 0;
@@ -1337,8 +1997,8 @@ icmp6_redirect_input(m, off)
int is_router;
int is_onlink;
struct in6_addr src6 = ip6->ip6_src;
- struct in6_addr redtgt6 = nd_rd->nd_rd_target;
- struct in6_addr reddst6 = nd_rd->nd_rd_dst;
+ struct in6_addr redtgt6;
+ struct in6_addr reddst6;
union nd_opts ndopts;
if (!m || !ifp)
@@ -1346,9 +2006,22 @@ icmp6_redirect_input(m, off)
/* XXX if we are router, we don't update route by icmp6 redirect */
if (ip6_forwarding)
- return;
+ goto freeit;
if (!icmp6_rediraccept)
+ goto freeit;
+
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, off, icmp6len,);
+ nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off);
+#else
+ IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len);
+ if (nd_rd == NULL) {
+ icmp6stat.icp6s_tooshort++;
return;
+ }
+#endif
+ redtgt6 = nd_rd->nd_rd_target;
+ reddst6 = nd_rd->nd_rd_dst;
if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
redtgt6.s6_addr16[1] = htons(ifp->if_index);
@@ -1360,14 +2033,14 @@ icmp6_redirect_input(m, off)
log(LOG_ERR,
"ICMP6 redirect sent from %s rejected; "
"must be from linklocal\n", ip6_sprintf(&src6));
- return;
+ goto freeit;
}
if (ip6->ip6_hlim != 255) {
log(LOG_ERR,
"ICMP6 redirect sent from %s rejected; "
"hlim=%d (must be 255)\n",
ip6_sprintf(&src6), ip6->ip6_hlim);
- return;
+ goto freeit;
}
{
/* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */
@@ -1389,14 +2062,14 @@ icmp6_redirect_input(m, off)
ip6_sprintf(gw6),
icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
RTFREE(rt);
- return;
+ goto freeit;
}
} else {
log(LOG_ERR,
"ICMP6 redirect rejected; "
"no route found for redirect dst: %s\n",
icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
- return;
+ goto freeit;
}
RTFREE(rt);
rt = NULL;
@@ -1406,7 +2079,7 @@ icmp6_redirect_input(m, off)
"ICMP6 redirect rejected; "
"redirect dst must be unicast: %s\n",
icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
- return;
+ goto freeit;
}
is_router = is_onlink = 0;
@@ -1419,7 +2092,7 @@ icmp6_redirect_input(m, off)
"ICMP6 redirect rejected; "
"neither router case nor onlink case: %s\n",
icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
- return;
+ goto freeit;
}
/* validation passed */
@@ -1429,7 +2102,7 @@ icmp6_redirect_input(m, off)
log(LOG_INFO, "icmp6_redirect_input: "
"invalid ND option, rejected: %s\n",
icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
- return;
+ goto freeit;
}
if (ndopts.nd_opts_tgt_lladdr) {
@@ -1487,6 +2160,9 @@ icmp6_redirect_input(m, off)
key_sa_routechange((struct sockaddr *)&sdst);
#endif
}
+
+ freeit:
+ m_freem(m);
}
void
@@ -1504,6 +2180,9 @@ icmp6_redirect_output(m0, rt)
size_t maxlen;
u_char *p;
struct ifnet *outif = NULL;
+ struct sockaddr_in6 src_sa;
+
+ icmp6_errcount(&icmp6stat.icp6s_outerrhist, ND_REDIRECT, 0);
/* if we are not router, we don't send icmp6 redirect */
if (!ip6_forwarding || ip6_accept_rtadv)
@@ -1520,7 +2199,13 @@ icmp6_redirect_output(m0, rt)
* [RFC 2461, sec 8.2]
*/
sip6 = mtod(m0, struct ip6_hdr *);
- if (nd6_is_addr_neighbor(&sip6->ip6_src, ifp) == 0)
+ bzero(&src_sa, sizeof(src_sa));
+ src_sa.sin6_family = AF_INET6;
+ src_sa.sin6_len = sizeof(src_sa);
+ src_sa.sin6_addr = sip6->ip6_src;
+ /* we don't currently use sin6_scope_id, but eventually use it */
+ src_sa.sin6_scope_id = in6_addr2scopeid(ifp, &sip6->ip6_src);
+ if (nd6_is_addr_neighbor(&src_sa, ifp) == 0)
goto fail;
if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst))
goto fail; /* what should we do here? */
@@ -1534,21 +2219,28 @@ icmp6_redirect_output(m0, rt)
* we almost always ask for an mbuf cluster for simplicity.
* (MHLEN < IPV6_MMTU is almost always true)
*/
+#if IPV6_MMTU >= MCLBYTES
+# error assumption failed about IPV6_MMTU and MCLBYTES
+#endif
MGETHDR(m, M_DONTWAIT, MT_HEADER);
+ if (m && IPV6_MMTU >= MHLEN)
+ MCLGET(m, M_DONTWAIT);
if (!m)
goto fail;
- if (MHLEN < IPV6_MMTU)
- MCLGET(m, M_DONTWAIT);
maxlen = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN;
maxlen = min(IPV6_MMTU, maxlen);
/* just for safety */
- if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
+ if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) +
+ ((sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7)) {
goto fail;
+ }
{
/* get ip6 linklocal address for ifp(my outgoing interface). */
- struct in6_ifaddr *ia = in6ifa_ifpforlinklocal(ifp);
- if (ia == NULL)
+ struct in6_ifaddr *ia;
+ if ((ia = in6ifa_ifpforlinklocal(ifp,
+ IN6_IFF_NOTREADY|
+ IN6_IFF_ANYCAST)) == NULL)
goto fail;
ifp_ll6 = &ia->ia_addr.sin6_addr;
}
@@ -1566,7 +2258,8 @@ icmp6_redirect_output(m0, rt)
/* ip6 */
ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_flow = 0;
- ip6->ip6_vfc = IPV6_VERSION;
+ ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
+ ip6->ip6_vfc |= IPV6_VERSION;
/* ip6->ip6_plen will be set later */
ip6->ip6_nxt = IPPROTO_ICMPV6;
ip6->ip6_hlim = 255;
@@ -1614,18 +2307,22 @@ icmp6_redirect_output(m0, rt)
rt_router = nd6_lookup(router_ll6, 0, ifp);
if (!rt_router)
goto nolladdropt;
- if (!(rt_router->rt_flags & RTF_GATEWAY)
- && (rt_router->rt_flags & RTF_LLINFO)
- && (rt_router->rt_gateway->sa_family == AF_LINK)
- && (sdl = (struct sockaddr_dl *)rt_router->rt_gateway)) {
+ len = sizeof(*nd_opt) + ifp->if_addrlen;
+ len = (len + 7) & ~7; /*round by 8*/
+ /* safety check */
+ if (len + (p - (u_char *)ip6) > maxlen)
+ goto nolladdropt;
+ if (!(rt_router->rt_flags & RTF_GATEWAY) &&
+ (rt_router->rt_flags & RTF_LLINFO) &&
+ (rt_router->rt_gateway->sa_family == AF_LINK) &&
+ (sdl = (struct sockaddr_dl *)rt_router->rt_gateway) &&
+ sdl->sdl_alen) {
nd_opt = (struct nd_opt_hdr *)p;
nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
- len = 2 + ifp->if_addrlen;
- len = (len + 7) & ~7; /*round by 8*/
nd_opt->nd_opt_len = len >> 3;
- p += len;
lladdr = (char *)(nd_opt + 1);
bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen);
+ p += len;
}
}
nolladdropt:;
@@ -1633,8 +2330,12 @@ nolladdropt:;
m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
/* just to be safe */
+#ifdef M_DECRYPTED /*not openbsd*/
if (m0->m_flags & M_DECRYPTED)
goto noredhdropt;
+#endif
+ if (p - (u_char *)ip6 > maxlen)
+ goto noredhdropt;
{
/* redirected header option */
@@ -1711,6 +2412,12 @@ noredhdropt:;
sip6->ip6_src.s6_addr16[1] = 0;
if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_dst))
sip6->ip6_dst.s6_addr16[1] = 0;
+#if 0
+ if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src))
+ ip6->ip6_src.s6_addr16[1] = 0;
+ if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
+ ip6->ip6_dst.s6_addr16[1] = 0;
+#endif
if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_target))
nd_rd->nd_rd_target.s6_addr16[1] = 0;
if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_dst))
@@ -1723,6 +2430,10 @@ noredhdropt:;
= in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), ntohs(ip6->ip6_plen));
/* send the packet to outside... */
+#ifdef IPSEC
+ /* Don't lookup socket */
+ ipsec_setsocket(m, NULL);
+#endif /*IPSEC*/
ip6_output(m, NULL, NULL, 0, NULL, &outif);
if (outif) {
icmp6_ifstat_inc(outif, ifs6_out_msg);
@@ -1741,6 +2452,9 @@ fail:
/*
* 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)
@@ -1812,12 +2526,58 @@ icmp6_ctloutput(so, sopt)
return(error);
}
+#ifndef HAVE_RATECHECK
+/*
+ * ratecheck() returns true if it is okay to send. We return
+ * true if it is not okay to send.
+ */
+static int
+ratecheck(last, limit)
+ struct timeval *last;
+ struct timeval *limit;
+{
+ struct timeval tp;
+ struct timeval nextsend;
+
+ microtime(&tp);
+ tp.tv_sec = time_second;
+
+ /* 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;
+ }
+ }
+
+ *last = tp;
+ return 1;
+}
+#endif
+
/*
* Perform rate limit check.
* Returns 0 if it is okay to send the icmp6 packet.
* 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
@@ -1826,29 +2586,21 @@ icmp6_ratelimit(dst, type, code)
const int type; /* not used at this moment */
const int code; /* not used at this moment */
{
- struct timeval tp;
- long sec_diff, usec_diff;
+ int ret;
- /* If we are not doing rate limitation, it is always okay to send */
- if (!icmp6errratelim)
- return 0;
+ ret = 0; /*okay to send*/
- microtime(&tp);
- tp.tv_sec = time_second;
- if (tp.tv_sec < icmp6_nextsend.tv_sec
- || (tp.tv_sec == icmp6_nextsend.tv_sec
- && tp.tv_usec < icmp6_nextsend.tv_usec)) {
- /* The packet is subject to rate limit */
- return 1;
+ /* PPS limit */
+ icmp6errpps_count++;
+ if (icmp6errppslim && icmp6errpps_count > icmp6errppslim / 5) {
+ /* The packet is subject to pps limit */
+ ret++;
}
- sec_diff = icmp6errratelim / 1000000;
- usec_diff = icmp6errratelim % 1000000;
- icmp6_nextsend.tv_sec = tp.tv_sec + sec_diff;
- if ((tp.tv_usec = tp.tv_usec + usec_diff) >= 1000000) {
- icmp6_nextsend.tv_sec++;
- icmp6_nextsend.tv_usec -= 1000000;
+
+ if (!ratecheck(&icmp6errratelim_last, &icmp6errratelim)) {
+ /* The packet is subject to rate limit */
+ ret++;
}
- /* it is okay to send this */
- return 0;
+ return ret;
}
diff --git a/sys/netinet6/icmp6.h b/sys/netinet6/icmp6.h
index 495297f86601..a6414efccb7e 100644
--- a/sys/netinet6/icmp6.h
+++ b/sys/netinet6/icmp6.h
@@ -1,615 +1,4 @@
-/*
- * 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.
- *
- * $FreeBSD$
- */
-
-/*
- * Copyright (c) 1982, 1986, 1993
- * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- *
- * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93
- */
-
-#ifndef _NETINET6_ICMPV6_H_
-#define _NETINET6_ICMPV6_H_
-
-#if !defined(_KERNEL) && !defined(__KAME_NETINET_ICMP6_H_INCLUDED_)
-#error "do not include netinet6/icmp6.h directly, include netinet/icmp6.h"
-#endif
-
-#define ICMPV6_PLD_MAXLEN 1232 /* IPV6_MMTU - sizeof(struct ip6_hdr)
- - sizeof(struct icmp6_hdr) */
-
-struct icmp6_hdr {
- u_int8_t icmp6_type; /* type field */
- u_int8_t icmp6_code; /* code field */
- u_int16_t icmp6_cksum; /* checksum field */
- union {
- u_int32_t icmp6_un_data32[1]; /* type-specific field */
- u_int16_t icmp6_un_data16[2]; /* type-specific field */
- u_int8_t icmp6_un_data8[4]; /* type-specific field */
- } icmp6_dataun;
-};
-
-#define icmp6_data32 icmp6_dataun.icmp6_un_data32
-#define icmp6_data16 icmp6_dataun.icmp6_un_data16
-#define icmp6_data8 icmp6_dataun.icmp6_un_data8
-#define icmp6_pptr icmp6_data32[0] /* parameter prob */
-#define icmp6_mtu icmp6_data32[0] /* packet too big */
-#define icmp6_id icmp6_data16[0] /* echo request/reply */
-#define icmp6_seq icmp6_data16[1] /* echo request/reply */
-#define icmp6_maxdelay icmp6_data16[0] /* mcast group membership */
-
-#define ICMP6_DST_UNREACH 1 /* dest unreachable, codes: */
-#define ICMP6_PACKET_TOO_BIG 2 /* packet too big */
-#define ICMP6_TIME_EXCEEDED 3 /* time exceeded, code: */
-#define ICMP6_PARAM_PROB 4 /* ip6 header bad */
-
-#define ICMP6_ECHO_REQUEST 128 /* echo service */
-#define ICMP6_ECHO_REPLY 129 /* echo reply */
-#define ICMP6_MEMBERSHIP_QUERY 130 /* group membership query */
-#define MLD6_LISTENER_QUERY 130 /* multicast listener query */
-#define ICMP6_MEMBERSHIP_REPORT 131 /* group membership report */
-#define MLD6_LISTENER_REPORT 131 /* multicast listener report */
-#define ICMP6_MEMBERSHIP_REDUCTION 132 /* group membership termination */
-#define MLD6_LISTENER_DONE 132 /* multicast listener done */
-
-#define ND_ROUTER_SOLICIT 133 /* router solicitation */
-#define ND_ROUTER_ADVERT 134 /* router advertisment */
-#define ND_NEIGHBOR_SOLICIT 135 /* neighbor solicitation */
-#define ND_NEIGHBOR_ADVERT 136 /* neighbor advertisment */
-#define ND_REDIRECT 137 /* redirect */
-
-#define ICMP6_ROUTER_RENUMBERING 138 /* router renumbering */
-
-#define ICMP6_WRUREQUEST 139 /* who are you request */
-#define ICMP6_WRUREPLY 140 /* who are you reply */
-#define ICMP6_FQDN_QUERY 139 /* FQDN query */
-#define ICMP6_FQDN_REPLY 140 /* FQDN reply */
-#define ICMP6_NI_QUERY 139 /* node information request */
-#define ICMP6_NI_REPLY 140 /* node information reply */
-
-/* The definitions below are experimental. TBA */
-#define MLD6_MTRACE_RESP 141 /* mtrace response(to sender) */
-#define MLD6_MTRACE 142 /* mtrace messages */
-
-#define ICMP6_MAXTYPE 142
-
-#define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */
-#define ICMP6_DST_UNREACH_ADMIN 1 /* administratively prohibited */
-#define ICMP6_DST_UNREACH_NOTNEIGHBOR 2 /* not a neighbor(obsolete) */
-#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 /* beyond scope of source address */
-#define ICMP6_DST_UNREACH_ADDR 3 /* address unreachable */
-#define ICMP6_DST_UNREACH_NOPORT 4 /* port unreachable */
-
-#define ICMP6_TIME_EXCEED_TRANSIT 0 /* ttl==0 in transit */
-#define ICMP6_TIME_EXCEED_REASSEMBLY 1 /* ttl==0 in reass */
-
-#define ICMP6_PARAMPROB_HEADER 0 /* erroneous header field */
-#define ICMP6_PARAMPROB_NEXTHEADER 1 /* unrecognized next header */
-#define ICMP6_PARAMPROB_OPTION 2 /* unrecognized option */
-
-#define ICMP6_INFOMSG_MASK 0x80 /* all informational messages */
-
-#define ICMP6_NI_SUCESS 0 /* node information successful reply */
-#define ICMP6_NI_REFUSED 1 /* node information request is refused */
-#define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */
-
-#define ICMP6_ROUTER_RENUMBERING_COMMAND 0 /* rr command */
-#define ICMP6_ROUTER_RENUMBERING_RESULT 1 /* rr result */
-#define ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET 255 /* rr seq num reset */
-
-/* Used in kernel only */
-#define ND_REDIRECT_ONLINK 0 /* redirect to an on-link node */
-#define ND_REDIRECT_ROUTER 1 /* redirect to a better router */
-
-/*
- * Multicast Listener Discovery
- */
-struct mld6_hdr {
- struct icmp6_hdr mld6_hdr;
- struct in6_addr mld6_addr; /* multicast address */
-};
-
-#define mld6_type mld6_hdr.icmp6_type
-#define mld6_code mld6_hdr.icmp6_code
-#define mld6_cksum mld6_hdr.icmp6_cksum
-#define mld6_maxdelay mld6_hdr.icmp6_data16[0]
-#define mld6_reserved mld6_hdr.icmp6_data16[1]
-
-/*
- * Neighbor Discovery
- */
-
-struct nd_router_solicit { /* router solicitation */
- struct icmp6_hdr nd_rs_hdr;
- /* could be followed by options */
-};
-
-#define nd_rs_type nd_rs_hdr.icmp6_type
-#define nd_rs_code nd_rs_hdr.icmp6_code
-#define nd_rs_cksum nd_rs_hdr.icmp6_cksum
-#define nd_rs_reserved nd_rs_hdr.icmp6_data32[0]
-
-struct nd_router_advert { /* router advertisement */
- struct icmp6_hdr nd_ra_hdr;
- u_int32_t nd_ra_reachable; /* reachable time */
- u_int32_t nd_ra_retransmit; /* retransmit timer */
- /* could be followed by options */
-};
-
-#define nd_ra_type nd_ra_hdr.icmp6_type
-#define nd_ra_code nd_ra_hdr.icmp6_code
-#define nd_ra_cksum nd_ra_hdr.icmp6_cksum
-#define nd_ra_curhoplimit nd_ra_hdr.icmp6_data8[0]
-#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_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 */
-};
-
-#define nd_ns_type nd_ns_hdr.icmp6_type
-#define nd_ns_code nd_ns_hdr.icmp6_code
-#define nd_ns_cksum nd_ns_hdr.icmp6_cksum
-#define nd_ns_reserved nd_ns_hdr.icmp6_data32[0]
-
-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 */
-};
-
-#define nd_na_type nd_na_hdr.icmp6_type
-#define nd_na_code nd_na_hdr.icmp6_code
-#define nd_na_cksum nd_na_hdr.icmp6_cksum
-#define nd_na_flags_reserved nd_na_hdr.icmp6_data32[0]
-#if BYTE_ORDER == BIG_ENDIAN
-#define ND_NA_FLAG_ROUTER 0x80000000
-#define ND_NA_FLAG_SOLICITED 0x40000000
-#define ND_NA_FLAG_OVERRIDE 0x20000000
-#elif BYTE_ORDER == LITTLE_ENDIAN
-#define ND_NA_FLAG_ROUTER 0x80
-#define ND_NA_FLAG_SOLICITED 0x40
-#define ND_NA_FLAG_OVERRIDE 0x20
-#endif
-
-struct nd_redirect { /* redirect */
- struct icmp6_hdr nd_rd_hdr;
- struct in6_addr nd_rd_target; /* target address */
- struct in6_addr nd_rd_dst; /* destination address */
- /* could be followed by options */
-};
-
-#define nd_rd_type nd_rd_hdr.icmp6_type
-#define nd_rd_code nd_rd_hdr.icmp6_code
-#define nd_rd_cksum nd_rd_hdr.icmp6_cksum
-#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0]
-
-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*/
-};
-
-#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
-
-struct nd_opt_prefix_info { /* prefix information */
- u_int8_t nd_opt_pi_type;
- u_int8_t nd_opt_pi_len;
- u_int8_t nd_opt_pi_prefix_len;
- u_int8_t nd_opt_pi_flags_reserved;
- u_int32_t nd_opt_pi_valid_time;
- u_int32_t nd_opt_pi_preferred_time;
- u_int32_t nd_opt_pi_reserved2;
- struct in6_addr nd_opt_pi_prefix;
-};
-
-#define ND_OPT_PI_FLAG_ONLINK 0x80
-#define ND_OPT_PI_FLAG_AUTO 0x40
-
-struct nd_opt_rd_hdr { /* redirected header */
- u_int8_t nd_opt_rh_type;
- u_int8_t nd_opt_rh_len;
- u_int16_t nd_opt_rh_reserved1;
- u_int32_t nd_opt_rh_reserved2;
- /* followed by IP header and data */
-};
-
-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;
-};
-
-/*
- * icmp6 namelookup
- */
-
-struct icmp6_namelookup {
- struct icmp6_hdr icmp6_nl_hdr;
- u_int64_t icmp6_nl_nonce;
- u_int32_t icmp6_nl_ttl;
- /* could be followed by options */
-};
-
-/*
- * icmp6 node information
- */
-struct icmp6_nodeinfo {
- struct icmp6_hdr icmp6_ni_hdr;
- u_int64_t icmp6_ni_nonce;
- /* could be followed by reply data */
-};
-
-#define ni_type icmp6_ni_hdr.icmp6_type
-#define ni_code icmp6_ni_hdr.icmp6_code
-#define ni_cksum icmp6_ni_hdr.icmp6_cksum
-#define ni_qtype icmp6_ni_hdr.icmp6_data16[0]
-#define ni_flags icmp6_ni_hdr.icmp6_data16[1]
-
-
-#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... */
-
-#if BYTE_ORDER == BIG_ENDIAN
-#define NI_SUPTYPE_FLAG_COMPRESS 0x1
-#define NI_FQDN_FLAG_VALIDTTL 0x1
-#elif BYTE_ORDER == LITTLE_ENDIAN
-#define NI_SUPTYPE_FLAG_COMPRESS 0x0100
-#define NI_FQDN_FLAG_VALIDTTL 0x0100
-#endif
-
-#if BYTE_ORDER == BIG_ENDIAN
-#define NI_NODEADDR_FLAG_TRUNCATE 0x1
-#define NI_NODEADDR_FLAG_ALL 0x2
-#define NI_NODEADDR_FLAG_COMPAT 0x4
-#define NI_NODEADDR_FLAG_LINKLOCAL 0x8
-#define NI_NODEADDR_FLAG_SITELOCAL 0x10
-#define NI_NODEADDR_FLAG_GLOBAL 0x20
-#define NI_NODEADDR_FLAG_ANYCAST 0x40 /* just experimental. not in spec */
-#elif BYTE_ORDER == LITTLE_ENDIAN
-#define NI_NODEADDR_FLAG_TRUNCATE 0x0100
-#define NI_NODEADDR_FLAG_ALL 0x0200
-#define NI_NODEADDR_FLAG_COMPAT 0x0400
-#define NI_NODEADDR_FLAG_LINKLOCAL 0x0800
-#define NI_NODEADDR_FLAG_SITELOCAL 0x1000
-#define NI_NODEADDR_FLAG_GLOBAL 0x2000
-#define NI_NODEADDR_FLAG_ANYCAST 0x4000 /* just experimental. not in spec */
-#endif
-
-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 */
-};
-
-/*
- * Router Renumbering. as router-renum-08.txt
- */
-struct icmp6_router_renum { /* router renumbering header */
- struct icmp6_hdr rr_hdr;
- u_int8_t rr_segnum;
- 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
-
-#define rr_type rr_hdr.icmp6_type
-#define rr_code rr_hdr.icmp6_code
-#define rr_cksum rr_hdr.icmp6_cksum
-#define rr_seqnum rr_hdr.icmp6_data32[0]
-
-struct rr_pco_match { /* match prefix part */
- u_int8_t rpm_code;
- u_int8_t rpm_len;
- u_int8_t rpm_ordinal;
- u_int8_t rpm_matchlen;
- u_int8_t rpm_minlen;
- u_int8_t rpm_maxlen;
- u_int16_t rpm_reserved;
- struct in6_addr rpm_prefix;
-};
-
-#define RPM_PCO_ADD 1
-#define RPM_PCO_CHANGE 2
-#define RPM_PCO_SETGLOBAL 3
-
-struct rr_pco_use { /* use prefix part */
- u_int8_t rpu_uselen;
- u_int8_t rpu_keeplen;
- u_int8_t rpu_ramask;
- u_int8_t rpu_raflags;
- u_int32_t rpu_vltime;
- u_int32_t rpu_pltime;
- u_int32_t rpu_flags;
- struct in6_addr rpu_prefix;
-};
-#define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x80
-#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x40
-
-#if BYTE_ORDER == BIG_ENDIAN
-#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80000000
-#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40000000
-#elif BYTE_ORDER == LITTLE_ENDIAN
-#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80
-#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40
-#endif
-
-struct rr_result { /* router renumbering result message */
- u_int16_t rrr_flags;
- u_int8_t rrr_ordinal;
- u_int8_t rrr_matchedlen;
- u_int32_t rrr_ifid;
- struct in6_addr rrr_prefix;
-};
-#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
-#endif
-
-/*
- * icmp6 filter structures.
- */
-
-struct icmp6_filter {
- u_int32_t icmp6_filter[8];
-};
-
-#ifdef _KERNEL
-#define ICMP6_FILTER_SETPASSALL(filterp) \
- { \
- int i; u_char *p; \
- p = (u_char *)filterp; \
- for (i = 0; i < sizeof(struct icmp6_filter); i++) \
- p[i] = 0xff; \
- }
-#define ICMP6_FILTER_SETBLOCKALL(filterp) \
- bzero(filterp, sizeof(struct icmp6_filter))
-#else /* _KERNEL */
-#define ICMP6_FILTER_SETPASSALL(filterp) \
- memset(filterp, 0xff, sizeof(struct icmp6_filter))
-#define ICMP6_FILTER_SETBLOCKALL(filterp) \
- memset(filterp, 0x00, sizeof(struct icmp6_filter))
-#endif /* _KERNEL */
-
-#define ICMP6_FILTER_SETPASS(type, filterp) \
- (((filterp)->icmp6_filter[(type) >> 5]) |= (1 << ((type) & 31)))
-#define ICMP6_FILTER_SETBLOCK(type, filterp) \
- (((filterp)->icmp6_filter[(type) >> 5]) &= ~(1 << ((type) & 31)))
-#define ICMP6_FILTER_WILLPASS(type, filterp) \
- ((((filterp)->icmp6_filter[(type) >> 5]) & (1 << ((type) & 31))) != 0)
-#define ICMP6_FILTER_WILLBLOCK(type, filterp) \
- ((((filterp)->icmp6_filter[(type) >> 5]) & (1 << ((type) & 31))) == 0)
-
-/*
- * Variables related to this implementation
- * of the internet control message protocol version 6.
- */
-struct icmp6stat {
-/* statistics related to icmp6 packets generated */
- u_long icp6s_error; /* # of calls to icmp6_error */
- u_long icp6s_canterror; /* no error 'cuz old was icmp */
- u_long icp6s_toofreq; /* no error 'cuz rate limitation */
- u_long icp6s_outhist[256];
-/* statistics related to input messages proccesed */
- u_long icp6s_badcode; /* icmp6_code out of range */
- u_long icp6s_tooshort; /* packet < sizeof(struct icmp6_hdr) */
- u_long icp6s_checksum; /* bad checksum */
- u_long icp6s_badlen; /* calculated bound mismatch */
- u_long icp6s_reflect; /* number of responses */
- u_long icp6s_inhist[256];
-};
-
-/*
- * Names for ICMP sysctl objects
- */
-#define ICMPV6CTL_STATS 1
-#define ICMPV6CTL_REDIRACCEPT 2 /* accept/process redirects */
-#define ICMPV6CTL_REDIRTIMEOUT 3 /* redirect cache time */
-#define ICMPV6CTL_ERRRATELIMIT 5 /* ICMPv6 error rate limitation */
-#define ICMPV6CTL_ND6_PRUNE 6
-#define ICMPV6CTL_ND6_DELAY 8
-#define ICMPV6CTL_ND6_UMAXTRIES 9
-#define ICMPV6CTL_ND6_MMAXTRIES 10
-#define ICMPV6CTL_ND6_USELOOPBACK 11
-#define ICMPV6CTL_ND6_PROXYALL 12
-#define ICMPV6CTL_MAXID 13
-
-#define ICMPV6CTL_NAMES { \
- { 0, 0 }, \
- { 0, 0 }, \
- { "rediraccept", CTLTYPE_INT }, \
- { "redirtimeout", CTLTYPE_INT }, \
- { 0, 0 }, \
- { "errratelimit", CTLTYPE_INT }, \
- { "nd6_prune", CTLTYPE_INT }, \
- { 0, 0 }, \
- { "nd6_delay", CTLTYPE_INT }, \
- { "nd6_umaxtries", CTLTYPE_INT }, \
- { "nd6_mmaxtries", CTLTYPE_INT }, \
- { "nd6_useloopback", CTLTYPE_INT }, \
- { "nd6_proxyall", CTLTYPE_INT }, \
-}
-
-#define ICMPV6CTL_VARS { \
- 0, \
- 0, \
- &icmp6_rediraccept, \
- &icmp6_redirtimeout, \
- 0, \
- 0, \
- &icmp6errratelim, \
- &nd6_prune, \
- 0, \
- &nd6_delay, \
- &nd6_umaxtries, \
- &nd6_mmaxtries, \
- &nd6_useloopback, \
- &nd6_proxyall, \
-}
-
-#define RTF_PROBEMTU RTF_PROTO1
-
-#ifdef _KERNEL
-#ifdef SYSCTL_DECL
-SYSCTL_DECL(_net_inet6_icmp6);
-#endif
-# ifdef __STDC__
-struct rtentry;
-struct rttimer;
-struct in6_multi;
-# endif
-void icmp6_init __P((void));
-void icmp6_paramerror __P((struct mbuf *, int));
-void icmp6_error __P((struct mbuf *, int, int, int));
-int icmp6_input __P((struct mbuf **, int *, int));
-void icmp6_fasttimo __P((void));
-void icmp6_reflect __P((struct mbuf *, size_t));
-void icmp6_prepare __P((struct mbuf *));
-void icmp6_redirect_input __P((struct mbuf *, int));
-void icmp6_redirect_output __P((struct mbuf *, struct rtentry *));
-
-/* XXX: is this the right place for these macros? */
-#define icmp6_ifstat_inc(ifp, tag) \
-do { \
- if ((ifp) && (ifp)->if_index <= if_index \
- && (ifp)->if_index < icmp6_ifstatmax \
- && icmp6_ifstat && icmp6_ifstat[(ifp)->if_index]) { \
- icmp6_ifstat[(ifp)->if_index]->tag++; \
- } \
-} while (0)
-
-#define icmp6_ifoutstat_inc(ifp, type, code) \
-do { \
- icmp6_ifstat_inc(ifp, ifs6_out_msg); \
- if (type < ICMP6_INFOMSG_MASK) \
- icmp6_ifstat_inc(ifp, ifs6_out_error); \
- switch(type) { \
- case ICMP6_DST_UNREACH: \
- icmp6_ifstat_inc(ifp, ifs6_out_dstunreach); \
- if (code == ICMP6_DST_UNREACH_ADMIN) \
- icmp6_ifstat_inc(ifp, ifs6_out_adminprohib); \
- break; \
- case ICMP6_PACKET_TOO_BIG: \
- icmp6_ifstat_inc(ifp, ifs6_out_pkttoobig); \
- break; \
- case ICMP6_TIME_EXCEEDED: \
- icmp6_ifstat_inc(ifp, ifs6_out_timeexceed); \
- break; \
- case ICMP6_PARAM_PROB: \
- icmp6_ifstat_inc(ifp, ifs6_out_paramprob); \
- break; \
- case ICMP6_ECHO_REQUEST: \
- icmp6_ifstat_inc(ifp, ifs6_out_echo); \
- break; \
- case ICMP6_ECHO_REPLY: \
- icmp6_ifstat_inc(ifp, ifs6_out_echoreply); \
- break; \
- case MLD6_LISTENER_QUERY: \
- icmp6_ifstat_inc(ifp, ifs6_out_mldquery); \
- break; \
- case MLD6_LISTENER_REPORT: \
- icmp6_ifstat_inc(ifp, ifs6_out_mldreport); \
- break; \
- case MLD6_LISTENER_DONE: \
- icmp6_ifstat_inc(ifp, ifs6_out_mlddone); \
- break; \
- case ND_ROUTER_SOLICIT: \
- icmp6_ifstat_inc(ifp, ifs6_out_routersolicit); \
- break; \
- case ND_ROUTER_ADVERT: \
- icmp6_ifstat_inc(ifp, ifs6_out_routeradvert); \
- break; \
- case ND_NEIGHBOR_SOLICIT: \
- icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit); \
- break; \
- case ND_NEIGHBOR_ADVERT: \
- icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert); \
- break; \
- case ND_REDIRECT: \
- icmp6_ifstat_inc(ifp, ifs6_out_redirect); \
- break; \
- } \
-} while (0)
-
-extern int icmp6_rediraccept; /* accept/process redirects */
-extern int icmp6_redirtimeout; /* cache time for redirect routes */
-#endif /* _KERNEL */
-
-#endif /* not _NETINET6_ICMPV6_H_ */
+/* $FreeBSD$ */
+/* $KAME: icmp6.h,v 1.17 2000/06/11 17:23:40 jinmei Exp $ */
+#error "netinet6/icmp6.h is obsolete. use netinet/icmp6.h"
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 234bd526838b..2d6ce6884096 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6.c,v 1.87 2000/07/03 15:44:21 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -64,6 +65,9 @@
* @(#)in.c 8.2 (Berkeley) 11/15/93
*/
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/malloc.h>
@@ -79,8 +83,6 @@
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
-#include "gif.h"
-
#include <net/if_dl.h>
#include <netinet/in.h>
@@ -88,10 +90,14 @@
#include <netinet/if_ether.h>
#include <netinet6/nd6.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/mld6_var.h>
+#include <netinet6/ip6_mroute.h>
#include <netinet6/in6_ifattach.h>
+#include <netinet6/scope6_var.h>
+
+#include "gif.h"
#if NGIF > 0
#include <net/if_gif.h>
#endif
@@ -103,40 +109,25 @@ MALLOC_DEFINE(M_IPMADDR, "in6_multi", "internet multicast address");
/*
* Definitions of some costant IP6 addresses.
*/
-const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
-const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
-const struct in6_addr in6addr_nodelocal_allnodes =
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+const struct in6_addr in6addr_nodelocal_allnodes =
IN6ADDR_NODELOCAL_ALLNODES_INIT;
-const struct in6_addr in6addr_linklocal_allnodes =
+const struct in6_addr in6addr_linklocal_allnodes =
IN6ADDR_LINKLOCAL_ALLNODES_INIT;
-const struct in6_addr in6addr_linklocal_allrouters =
+const struct in6_addr in6addr_linklocal_allrouters =
IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
-const struct in6_addr in6mask0 = IN6MASK0;
-const struct in6_addr in6mask32 = IN6MASK32;
-const struct in6_addr in6mask64 = IN6MASK64;
-const struct in6_addr in6mask96 = IN6MASK96;
-const struct in6_addr in6mask128 = IN6MASK128;
+const struct in6_addr in6mask0 = IN6MASK0;
+const struct in6_addr in6mask32 = IN6MASK32;
+const struct in6_addr in6mask64 = IN6MASK64;
+const struct in6_addr in6mask96 = IN6MASK96;
+const struct in6_addr in6mask128 = IN6MASK128;
-static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
+static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
struct ifnet *, struct proc *));
-struct in6_multihead in6_multihead; /* XXX BSS initialization */
-/*
- * Determine whether an IP6 address is in a reserved set of addresses
- * that may not be forwarded, or whether datagrams to that destination
- * may be forwarded.
- */
-int
-in6_canforward(src, dst)
- struct in6_addr *src, *dst;
-{
- if (IN6_IS_ADDR_LINKLOCAL(src) ||
- IN6_IS_ADDR_LINKLOCAL(dst) ||
- IN6_IS_ADDR_MULTICAST(dst))
- return(0);
- return(1);
-}
+struct in6_multihead in6_multihead; /* XXX BSS initialization */
/*
* Check if the loopback entry will be automatically generated.
@@ -184,7 +175,11 @@ in6_ifloop_request(int cmd, struct ifaddr *ifa)
lo_sa.sin6_addr = in6addr_loopback;
all1_sa.sin6_addr = in6mask128;
- /* So we add or remove static loopback entry, here. */
+ /*
+ * 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.
+ */
rtrequest(cmd, ifa->ifa_addr,
(struct sockaddr *)&lo_sa,
(struct sockaddr *)&all1_sa,
@@ -198,7 +193,7 @@ in6_ifloop_request(int cmd, struct ifaddr *ifa)
* loopback address.
*/
if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) {
- nrt->rt_ifa->ifa_refcnt--;
+ IFAFREE(nrt->rt_ifa);
ifa->ifa_refcnt++;
nrt->rt_ifa = ifa;
}
@@ -233,10 +228,18 @@ in6_ifaddloop(struct ifaddr *ifa)
static void
in6_ifremloop(struct ifaddr *ifa)
{
- if (!in6_is_ifloop_auto(ifa)) {
- struct in6_ifaddr *ia;
- int ia_count = 0;
+ struct in6_ifaddr *ia;
+ int ia_count = 0;
+ /*
+ * All BSD variants except BSD/OS 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
+ * 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),
@@ -251,90 +254,6 @@ in6_ifremloop(struct ifaddr *ifa)
}
}
-/*
- * Subroutine for in6_ifaddproxy() and in6_ifremproxy().
- * This routine does actual work.
- * call in6_addmulti() when cmd == 1.
- * call in6_delmulti() when cmd == 2.
- */
-static int
-in6_ifproxy_request(int cmd, struct in6_ifaddr *ia)
-{
- int error = 0;
-
- /*
- * If we have an IPv6 dstaddr on adding p2p interface,
- * join dstaddr's solicited multicast on necessary interface.
- */
- if ((ia->ia_ifp->if_flags & IFF_POINTOPOINT) &&
- ia->ia_dstaddr.sin6_family == AF_INET6 &&
- !IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) {
- struct in6_ifaddr *ia_lan;
-
- /*
- * TODO: Join only on some specified interfaces by some
- * configuration.
- * Unsolicited Neighbor Advertisements will be also necessary.
- *
- * Now, join on interfaces which meets following.
- * -IFF_BROADCAST and IFF_MULTICAST
- * (NBMA is out of scope)
- * -the prefix value is same as p2p dstaddr
- */
- for (ia_lan = in6_ifaddr; ia_lan; ia_lan = ia_lan->ia_next) {
- struct in6_addr llsol;
-
- if ((ia_lan->ia_ifp->if_flags &
- (IFF_BROADCAST|IFF_MULTICAST)) !=
- (IFF_BROADCAST|IFF_MULTICAST))
- continue;
- if (!IN6_ARE_MASKED_ADDR_EQUAL(IA6_IN6(ia),
- IA6_IN6(ia_lan),
- IA6_MASKIN6(ia_lan)))
- continue;
- if (ia_lan->ia_ifp == ia->ia_ifp)
- continue;
-
- /* init llsol */
- bzero(&llsol, sizeof(struct in6_addr));
- llsol.s6_addr16[0] = htons(0xff02);
- llsol.s6_addr16[1] = htons(ia_lan->ia_ifp->if_index);
- llsol.s6_addr32[1] = 0;
- llsol.s6_addr32[2] = htonl(1);
- llsol.s6_addr32[3] =
- ia->ia_dstaddr.sin6_addr.s6_addr32[3];
- llsol.s6_addr8[12] = 0xff;
-
- if (cmd == 1)
- (void)in6_addmulti(&llsol,
- ia_lan->ia_ifp,
- &error);
- else if (cmd == 2) {
- struct in6_multi *in6m;
-
- IN6_LOOKUP_MULTI(llsol,
- ia_lan->ia_ifp,
- in6m);
- if (in6m)
- in6_delmulti(in6m);
- }
- }
- }
- return error;
-}
-
-static int
-in6_ifaddproxy(struct in6_ifaddr *ia)
-{
- return(in6_ifproxy_request(1, ia));
-}
-
-static void
-in6_ifremproxy(struct in6_ifaddr *ia)
-{
- in6_ifproxy_request(2, ia);
-}
-
int
in6_ifindex2scopeid(idx)
int idx;
@@ -393,10 +312,8 @@ in6_len2mask(mask, len)
mask->s6_addr8[i] = (0xff00 >> (len % 8)) & 0xff;
}
-int in6_interfaces; /* number of external internet interfaces */
-
#define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa))
-#define ia62ifa(ia6) ((struct ifaddr *)(ia6))
+#define ia62ifa(ia6) (&((ia6)->ia_ifa))
int
in6_control(so, cmd, data, ifp, p)
@@ -407,10 +324,14 @@ in6_control(so, cmd, data, ifp, p)
struct proc *p;
{
struct in6_ifreq *ifr = (struct in6_ifreq *)data;
- struct in6_ifaddr *ia, *oia;
+ struct in6_ifaddr *ia = NULL, *oia;
struct in6_aliasreq *ifra = (struct in6_aliasreq *)data;
- struct sockaddr_in6 oldaddr, net;
- int error = 0, hostIsNew, prefixIsNew;
+ struct sockaddr_in6 oldaddr;
+#ifdef COMPAT_IN6IFIOCTL
+ struct sockaddr_in6 net;
+#endif
+ int error = 0, hostIsNew, prefixIsNew;
+ int newifaddr;
int privileged;
privileged = 0;
@@ -433,14 +354,21 @@ in6_control(so, cmd, data, ifp, p)
}
}
#endif
+ switch (cmd) {
+ case SIOCGETSGCNT_IN6:
+ case SIOCGETMIFCNT_IN6:
+ return (mrt6_ioctl(cmd, data));
+ }
- if (ifp == 0)
+ if (ifp == NULL)
return(EOPNOTSUPP);
switch (cmd) {
case SIOCSNDFLUSH_IN6:
case SIOCSPFXFLUSH_IN6:
case SIOCSRTRFLUSH_IN6:
+ case SIOCSDEFIFACE_IN6:
+ case SIOCSIFINFO_FLAGS:
if (!privileged)
return(EPERM);
/*fall through*/
@@ -448,6 +376,7 @@ in6_control(so, cmd, data, ifp, p)
case SIOCGDRLST_IN6:
case SIOCGPRLST_IN6:
case SIOCGNBRINFO_IN6:
+ case SIOCGDEFIFACE_IN6:
return(nd6_ioctl(cmd, data, ifp));
}
@@ -466,6 +395,20 @@ in6_control(so, cmd, data, ifp, p)
return(in6_prefix_ioctl(so, cmd, data, ifp));
}
+ switch(cmd) {
+ case SIOCSSCOPE6:
+ if (!privileged)
+ return(EPERM);
+ return(scope6_set(ifp, ifr->ifr_ifru.ifru_scope_id));
+ break;
+ case SIOCGSCOPE6:
+ return(scope6_get(ifp, ifr->ifr_ifru.ifru_scope_id));
+ break;
+ case SIOCGSCOPE6DEF:
+ return(scope6_get_default(ifr->ifr_ifru.ifru_scope_id));
+ break;
+ }
+
switch (cmd) {
case SIOCALIFADDR:
case SIOCDLIFADDR:
@@ -479,8 +422,7 @@ in6_control(so, cmd, data, ifp, p)
/*
* Find address for this interface, if it exists.
*/
- {
-
+ if (ifra->ifra_addr.sin6_family == AF_INET6) { /* XXX */
struct sockaddr_in6 *sa6 =
(struct sockaddr_in6 *)&ifra->ifra_addr;
@@ -489,10 +431,10 @@ in6_control(so, cmd, data, ifp, p)
/* interface 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 */
+ } else if (sa6->sin6_addr.s6_addr16[1] !=
+ htons(ifp->if_index)) {
+ return(EINVAL); /* ifid is contradict */
+ }
if (sa6->sin6_scope_id) {
if (sa6->sin6_scope_id !=
(u_int32_t)ifp->if_index)
@@ -500,30 +442,61 @@ in6_control(so, cmd, data, ifp, p)
sa6->sin6_scope_id = 0; /* XXX: good way? */
}
}
+ ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr);
}
- ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr);
switch (cmd) {
case SIOCDIFADDR_IN6:
- if (ia == 0)
+ /*
+ * for IPv4, we look for existing in6_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.
+ */
+ if (ia == NULL)
return(EADDRNOTAVAIL);
/* FALLTHROUGH */
case SIOCAIFADDR_IN6:
case SIOCSIFADDR_IN6:
- case SIOCSIFNETMASK_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.
+ */
+#endif
+ if (ifra->ifra_addr.sin6_family != AF_INET6)
+ return(EAFNOSUPPORT);
if (!privileged)
return(EPERM);
- if (ia == 0) {
+ 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_ifa.ifa_dstaddr
- = (struct sockaddr *)&ia->ia_dstaddr;
+ 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;
@@ -534,11 +507,17 @@ in6_control(so, cmd, data, ifp, p)
oia->ia_next = ia;
} else
in6_ifaddr = ia;
- TAILQ_INSERT_TAIL(&ifp->if_addrlist,
- (struct ifaddr *)ia, ifa_list);
- if ((ifp->if_flags & IFF_LOOPBACK) == 0)
- in6_interfaces++; /*XXX*/
- }
+ /* 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 */
@@ -563,7 +542,7 @@ in6_control(so, cmd, data, ifp, p)
case SIOCGIFDSTADDR_IN6:
case SIOCGIFALIFETIME_IN6:
/* must think again about its semantics */
- if (ia == 0)
+ if (ia == NULL)
return(EADDRNOTAVAIL);
break;
case SIOCSIFALIFETIME_IN6:
@@ -572,7 +551,7 @@ in6_control(so, cmd, data, ifp, p)
if (!privileged)
return(EPERM);
- if (ia == 0)
+ if (ia == NULL)
return(EADDRNOTAVAIL);
/* sanity for overflow - beware unsigned */
lt = &ifr->ifr_ifru.ifru_lifetime;
@@ -597,6 +576,10 @@ in6_control(so, cmd, data, ifp, p)
case SIOCGIFDSTADDR_IN6:
if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
return(EINVAL);
+ /*
+ * XXX: should we check if ifa_dstaddr is NULL and return
+ * an error?
+ */
ifr->ifr_dstaddr = ia->ia_dstaddr;
break;
@@ -633,6 +616,7 @@ 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);
@@ -645,12 +629,11 @@ in6_control(so, cmd, data, ifp, p)
/* 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] !=
+ } else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] !=
htons(ifp->if_index)) {
- ia->ia_dstaddr = oldaddr;
- return(EINVAL); /* ifid is contradict */
- }
+ ia->ia_dstaddr = oldaddr;
+ return(EINVAL); /* ifid is contradict */
+ }
}
if (ifp->if_ioctl && (error = (ifp->if_ioctl)
@@ -658,6 +641,7 @@ in6_control(so, cmd, data, ifp, p)
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);
@@ -667,6 +651,7 @@ in6_control(so, cmd, data, ifp, p)
}
break;
+#endif
case SIOCGIFALIFETIME_IN6:
ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime;
break;
@@ -687,8 +672,41 @@ in6_control(so, cmd, data, ifp, p)
break;
case SIOCSIFADDR_IN6:
- return(in6_ifinit(ifp, ia, &ifr->ifr_addr, 1));
+ error = in6_ifinit(ifp, ia, &ifr->ifr_addr, 1);
+#if 0
+ /*
+ * 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().
+ */
+ 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");
+ }
+ }
+ /* release another refcnt for the link from in6_ifaddr */
+ IFAFREE(&oia->ia_ifa);
+ }
+#endif
+ return error;
+#ifdef COMPAT_IN6IFIOCTL /* XXX should be unused */
case SIOCSIFNETMASK_IN6:
ia->ia_prefixmask = ifr->ifr_addr;
bzero(&net, sizeof(net));
@@ -710,6 +728,7 @@ in6_control(so, cmd, data, ifp, p)
ia->ia_prefixmask.sin6_addr.s6_addr32[3];
ia->ia_net = net;
break;
+#endif
case SIOCAIFADDR_IN6:
prefixIsNew = 0;
@@ -722,6 +741,22 @@ in6_control(so, cmd, data, ifp, p)
&ia->ia_addr.sin6_addr))
hostIsNew = 0;
+ /* 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);
+ /*
+ * The prefixmask must have a family of AF_UNSPEC or AF_INET6.
+ */
+ if (ifra->ifra_prefixmask.sin6_family != AF_INET6 &&
+ ifra->ifra_prefixmask.sin6_family != AF_UNSPEC)
+ return(EAFNOSUPPORT);
+
if (ifra->ifra_prefixmask.sin6_len) {
in6_ifscrub(ifp, ia);
ia->ia_prefixmask = ifra->ifra_prefixmask;
@@ -730,6 +765,7 @@ in6_control(so, cmd, data, ifp, p)
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)) {
@@ -740,20 +776,22 @@ in6_control(so, cmd, data, ifp, p)
*/
ia->ia_dstaddr.sin6_addr.s6_addr16[1]
= htons(ifp->if_index);
- } else
- if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] !=
+ } else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] !=
htons(ifp->if_index)) {
- ia->ia_dstaddr = oldaddr;
- return(EINVAL); /* ifid is contradict */
- }
+ ia->ia_dstaddr = oldaddr;
+ return(EINVAL); /* ifid is contradict */
+ }
}
prefixIsNew = 1; /* We lie; but effect's the same */
}
- if (ifra->ifra_addr.sin6_family == AF_INET6 &&
- (hostIsNew || prefixIsNew))
+ if (hostIsNew || prefixIsNew) {
error = in6_ifinit(ifp, ia, &ifra->ifra_addr, 0);
- if (ifra->ifra_addr.sin6_family == AF_INET6
- && hostIsNew && (ifp->if_flags & IFF_MULTICAST)) {
+#if 0
+ if (error)
+ goto undo;
+#endif
+ }
+ if (hostIsNew && (ifp->if_flags & IFF_MULTICAST)) {
int error_local = 0;
/*
@@ -772,14 +810,6 @@ in6_control(so, cmd, data, ifp, p)
if (error == 0)
error = error_local;
}
- /* Join dstaddr's solicited multicast if necessary. */
- if (nd6_proxyall && hostIsNew) {
- int error_local;
-
- error_local = in6_ifaddproxy(ia);
- if (error == 0)
- error = error_local;
- }
ia->ia6_flags = ifra->ifra_flags;
ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /*safety*/
@@ -806,8 +836,15 @@ in6_control(so, cmd, data, ifp, p)
case IFT_ARCNET:
case IFT_ETHER:
case IFT_FDDI:
- ia->ia6_flags |= IN6_IFF_TENTATIVE;
- nd6_dad_start((struct ifaddr *)ia, NULL);
+#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);
+ }
break;
#ifdef IFT_DUMMY
case IFT_DUMMY:
@@ -833,64 +870,103 @@ in6_control(so, cmd, data, ifp, p)
return(error);
case SIOCDIFADDR_IN6:
- in6_ifscrub(ifp, ia);
-
- 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);
- }
- /* Leave dstaddr's solicited multicast if necessary. */
- if (nd6_proxyall)
- in6_ifremproxy(ia);
-
- TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
- 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");
- }
- {
- int iilen;
-
- iilen = (sizeof(oia->ia_prefixmask.sin6_addr) << 3) -
- in6_mask2len(&oia->ia_prefixmask.sin6_addr);
- in6_prefix_remove_ifid(iilen, oia);
- }
- IFAFREE((&oia->ia_ifa));
+ in6_purgeaddr(&ia->ia_ifa, ifp);
break;
default:
- if (ifp == 0 || ifp->if_ioctl == 0)
+ if (ifp == NULL || ifp->if_ioctl == 0)
return(EOPNOTSUPP);
return((*ifp->if_ioctl)(ifp, cmd, data));
}
return(0);
}
+void
+in6_purgeaddr(ifa, ifp)
+ struct ifaddr *ifa;
+ struct ifnet *ifp;
+{
+ struct in6_ifaddr *oia, *ia = (void *) ifa;
+ int plen;
+
+ in6_ifscrub(ifp, ia);
+
+ 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);
+ }
+
+ 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");
+ }
+ {
+ int iilen;
+
+ plen = in6_mask2len(&oia->ia_prefixmask.sin6_addr);
+ 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.
+ */
+ 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 */
+ }
+ }
+ }
+
+ /* release another refcnt for the link from in6_ifaddr */
+ IFAFREE(&oia->ia_ifa);
+}
+
/*
* SIOC[GAD]LIFADDR.
- * SIOCGLIFADDR: get first address. (?!?)
+ * SIOCGLIFADDR: get first address. (???)
* SIOCGLIFADDR with IFLR_PREFIX:
* get first address that matches the specified prefix.
* SIOCALIFADDR: add the specified address.
@@ -921,6 +997,7 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p)
{
struct if_laddrreq *iflr = (struct if_laddrreq *)data;
struct ifaddr *ifa;
+ struct sockaddr *sa;
/* sanity checks */
if (!data || !ifp) {
@@ -937,20 +1014,25 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p)
case SIOCALIFADDR:
case SIOCDLIFADDR:
/* address must be specified on ADD and DELETE */
- if (iflr->addr.ss_family != AF_INET6)
+ sa = (struct sockaddr *)&iflr->addr;
+ if (sa->sa_family != AF_INET6)
return EINVAL;
- if (iflr->addr.ss_len != sizeof(struct sockaddr_in6))
+ if (sa->sa_len != sizeof(struct sockaddr_in6))
return EINVAL;
/* XXX need improvement */
- if (iflr->dstaddr.ss_family
- && iflr->dstaddr.ss_family != AF_INET6)
+ sa = (struct sockaddr *)&iflr->dstaddr;
+ if (sa->sa_family && sa->sa_family != AF_INET6)
return EINVAL;
- if (iflr->dstaddr.ss_family
- && iflr->dstaddr.ss_len != sizeof(struct sockaddr_in6))
+ if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6))
return EINVAL;
break;
default: /*shouldn't happen*/
+#if 0
+ panic("invalid cmd to in6_lifaddr_ioctl");
+ /*NOTREACHED*/
+#else
return EOPNOTSUPP;
+#endif
}
if (sizeof(struct in6_addr) * 8 < iflr->prefixlen)
return EINVAL;
@@ -970,7 +1052,7 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p)
* address. hostid points to the first link-local
* address attached to the interface.
*/
- ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp);
+ ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);
if (!ifa)
return EADDRNOTAVAIL;
hostid = IFA_IN6(ifa);
@@ -994,7 +1076,8 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p)
bcopy(iflr->iflr_name, ifra.ifra_name,
sizeof(ifra.ifra_name));
- bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.ss_len);
+ bcopy(&iflr->addr, &ifra.ifra_addr,
+ ((struct sockaddr *)&iflr->addr)->sa_len);
if (hostid) {
/* fill in hostid part */
ifra.ifra_addr.sin6_addr.s6_addr32[2] =
@@ -1003,9 +1086,9 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p)
hostid->s6_addr32[3];
}
- if (iflr->dstaddr.ss_family) { /*XXX*/
+ if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /*XXX*/
bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
- iflr->dstaddr.ss_len);
+ ((struct sockaddr *)&iflr->dstaddr)->sa_len);
if (hostid) {
ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] =
hostid->s6_addr32[2];
@@ -1107,6 +1190,9 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p)
if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
ia->ia_dstaddr.sin6_len);
+ } else {
+ bzero(&ifra.ifra_dstaddr,
+ sizeof(ifra.ifra_dstaddr));
}
bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr,
ia->ia_prefixmask.sin6_len);
@@ -1206,6 +1292,9 @@ in6_ifinit(ifp, ia, sin6, 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;
/* Add ownaddr as loopback rtentry, if necessary(ex. on p2p link). */
in6_ifaddloop(&(ia->ia_ifa));
@@ -1305,8 +1394,9 @@ in6_delmulti(in6m)
* Find an IPv6 interface link-local address specific to an interface.
*/
struct in6_ifaddr *
-in6ifa_ifpforlinklocal(ifp)
+in6ifa_ifpforlinklocal(ifp, ignoreflags)
struct ifnet *ifp;
+ int ignoreflags;
{
register struct ifaddr *ifa;
@@ -1316,8 +1406,12 @@ in6ifa_ifpforlinklocal(ifp)
continue; /* just for safety */
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
- if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa)))
+ if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
+ if ((((struct in6_ifaddr *)ifa)->ia6_flags &
+ ignoreflags) != 0)
+ continue;
break;
+ }
}
return((struct in6_ifaddr *)ifa);
@@ -1419,69 +1513,9 @@ in6_localaddr(in6)
}
/*
- * Get a scope of the address. Node-local, link-local, site-local or global.
- */
-int
-in6_addrscope (addr)
-struct in6_addr *addr;
-{
- int scope;
-
- if (addr->s6_addr8[0] == 0xfe) {
- scope = addr->s6_addr8[1] & 0xc0;
-
- switch (scope) {
- case 0x80:
- return IPV6_ADDR_SCOPE_LINKLOCAL;
- break;
- case 0xc0:
- return IPV6_ADDR_SCOPE_SITELOCAL;
- break;
- default:
- return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
- break;
- }
- }
-
-
- if (addr->s6_addr8[0] == 0xff) {
- scope = addr->s6_addr8[1] & 0x0f;
-
- /*
- * due to other scope such as reserved,
- * return scope doesn't work.
- */
- switch (scope) {
- case IPV6_ADDR_SCOPE_NODELOCAL:
- return IPV6_ADDR_SCOPE_NODELOCAL;
- break;
- case IPV6_ADDR_SCOPE_LINKLOCAL:
- return IPV6_ADDR_SCOPE_LINKLOCAL;
- break;
- case IPV6_ADDR_SCOPE_SITELOCAL:
- return IPV6_ADDR_SCOPE_SITELOCAL;
- break;
- default:
- return IPV6_ADDR_SCOPE_GLOBAL;
- break;
- }
- }
-
- if (bcmp(&in6addr_loopback, addr, sizeof(addr) - 1) == 0) {
- if (addr->s6_addr8[15] == 1) /* loopback */
- return IPV6_ADDR_SCOPE_NODELOCAL;
- if (addr->s6_addr8[15] == 0) /* unspecified */
- return IPV6_ADDR_SCOPE_LINKLOCAL;
- }
-
- return IPV6_ADDR_SCOPE_GLOBAL;
-}
-
-/*
* return length of part which dst and src are equal
* hard coding...
*/
-
int
in6_matchlen(src, dst)
struct in6_addr *src, *dst;
@@ -1502,6 +1536,7 @@ struct in6_addr *src, *dst;
return match;
}
+/* XXX: to be scope conscious */
int
in6_are_prefix_equal(p1, p2, len)
struct in6_addr *p1, *p2;
@@ -1555,114 +1590,241 @@ in6_prefixlen2mask(maskp, len)
/*
* return the best address out of the same scope
*/
-
struct in6_ifaddr *
-in6_ifawithscope(ifp, dst)
- register struct ifnet *ifp;
+in6_ifawithscope(oifp, dst)
+ register struct ifnet *oifp;
register struct in6_addr *dst;
{
- int dst_scope = in6_addrscope(dst), blen = -1, tlen;
+ int dst_scope = in6_addrscope(dst), src_scope, best_scope = 0;
+ int blen = -1;
struct ifaddr *ifa;
- struct in6_ifaddr *besta = NULL, *ia;
- struct in6_ifaddr *dep[3]; /*last-resort: deprecated*/
-
- dep[0] = dep[1] = dep[2] = NULL;
+ struct ifnet *ifp;
+ struct in6_ifaddr *ifa_best = NULL;
+
+ if (oifp == NULL) {
+ printf("in6_ifawithscope: output interface is not specified\n");
+ return(NULL);
+ }
/*
- * We first look for addresses in the same scope.
- * If there is one, return it.
- * If two or more, return one which matches the dst longest.
- * If none, return one of global addresses assigned other ifs.
+ * We search for all addresses on all interfaces from the beginning.
+ * Comparing an interface with the outgoing interface will be done
+ * only at the final stage of tiebreaking.
*/
- TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
+ for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
{
- if (ifa->ifa_addr->sa_family != AF_INET6)
- continue;
- if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
- continue; /* XXX: is there any case to allow anycast? */
- if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
- continue; /* don't use this interface */
- if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
- continue;
- if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
- if (ip6_use_deprecated)
- dep[0] = (struct in6_ifaddr *)ifa;
+ /*
+ * We can never take an address that breaks the scope zone
+ * of the destination.
+ */
+ if (in6_addr2scopeid(ifp, dst) != in6_addr2scopeid(oifp, dst))
continue;
- }
- if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
+ {
+ int tlen = -1, dscopecmp, bscopecmp, matchcmp;
+
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+
+ src_scope = in6_addrscope(IFA_IN6(ifa));
+
/*
- * call in6_matchlen() as few as possible
+ * Don't use an address before completing DAD
+ * nor a duplicated address.
*/
- if (besta) {
- if (blen == -1)
- blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
- tlen = in6_matchlen(IFA_IN6(ifa), dst);
- if (tlen > blen) {
- blen = tlen;
- besta = (struct in6_ifaddr *)ifa;
- }
- } else
- besta = (struct in6_ifaddr *)ifa;
- }
- }
- if (besta)
- return besta;
+ if (((struct in6_ifaddr *)ifa)->ia6_flags &
+ IN6_IFF_NOTREADY)
+ continue;
- for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
- if (IPV6_ADDR_SCOPE_GLOBAL !=
- in6_addrscope(&(ia->ia_addr.sin6_addr)))
- continue;
- /* XXX: is there any case to allow anycast? */
- if ((ia->ia6_flags & IN6_IFF_ANYCAST) != 0)
- continue;
- if ((ia->ia6_flags & IN6_IFF_NOTREADY) != 0)
- continue;
- if ((ia->ia6_flags & IN6_IFF_DETACHED) != 0)
- continue;
- if ((ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) {
- if (ip6_use_deprecated)
- dep[1] = (struct in6_ifaddr *)ifa;
- continue;
- }
- return ia;
- }
+ /* XXX: is there any case to allow anycasts? */
+ if (((struct in6_ifaddr *)ifa)->ia6_flags &
+ IN6_IFF_ANYCAST)
+ continue;
- for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
- if (IPV6_ADDR_SCOPE_SITELOCAL !=
- in6_addrscope(&(ia->ia_addr.sin6_addr)))
- continue;
- /* XXX: is there any case to allow anycast? */
- if ((ia->ia6_flags & IN6_IFF_ANYCAST) != 0)
- continue;
- if ((ia->ia6_flags & IN6_IFF_NOTREADY) != 0)
- continue;
- if ((ia->ia6_flags & IN6_IFF_DETACHED) != 0)
- continue;
- if ((ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) {
- if (ip6_use_deprecated)
- dep[2] = (struct in6_ifaddr *)ifa;
- continue;
+ if (((struct in6_ifaddr *)ifa)->ia6_flags &
+ IN6_IFF_DETACHED)
+ continue;
+
+ /*
+ * If this is the first address we find,
+ * keep it anyway.
+ */
+ if (ifa_best == NULL)
+ goto replace;
+
+ /*
+ * ifa_best is never NULL beyond this line except
+ * within the block labeled "replace".
+ */
+
+ /*
+ * If ifa_best has a smaller scope than dst and
+ * the current address has a larger one than
+ * (or equal to) dst, always replace ifa_best.
+ * Also, if the current address has a smaller scope
+ * than dst, ignore it unless ifa_best also has a
+ * smaller scope.
+ */
+ if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0 &&
+ IN6_ARE_SCOPE_CMP(src_scope, dst_scope) >= 0)
+ goto replace;
+ if (IN6_ARE_SCOPE_CMP(src_scope, dst_scope) < 0 &&
+ IN6_ARE_SCOPE_CMP(best_scope, dst_scope) >= 0)
+ continue;
+
+ /*
+ * A deprecated address SHOULD NOT be used in new
+ * communications if an alternate (non-deprecated)
+ * address is available and has sufficient scope.
+ * RFC 2462, Section 5.5.4.
+ */
+ if (((struct in6_ifaddr *)ifa)->ia6_flags &
+ IN6_IFF_DEPRECATED) {
+ /*
+ * Ignore any deprecated addresses if
+ * specified by configuration.
+ */
+ if (!ip6_use_deprecated)
+ continue;
+
+ /*
+ * If we have already found a non-deprecated
+ * candidate, just ignore deprecated addresses.
+ */
+ if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED)
+ == 0)
+ continue;
+ }
+
+ /*
+ * A non-deprecated address is always preferred
+ * to a deprecated one regardless of scopes and
+ * address matching.
+ */
+ if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) &&
+ (((struct in6_ifaddr *)ifa)->ia6_flags &
+ IN6_IFF_DEPRECATED) == 0)
+ goto replace;
+
+ /*
+ * At this point, we have two cases:
+ * 1. we are looking at a non-deprecated address,
+ * and ifa_best is also non-deprecated.
+ * 2. we are looking at a deprecated address,
+ * and ifa_best is also deprecated.
+ * Also, we do not have to consider a case where
+ * the scope of if_best is larger(smaller) than dst and
+ * the scope of the current address is smaller(larger)
+ * than dst. Such a case has already been covered.
+ * Tiebreaking is done according to the following
+ * items:
+ * - the scope comparison between the address and
+ * dst (dscopecmp)
+ * - the scope comparison between the address and
+ * ifa_best (bscopecmp)
+ * - if the address match dst longer than ifa_best
+ * (matchcmp)
+ * - if the address is on the outgoing I/F (outI/F)
+ *
+ * Roughly speaking, the selection policy is
+ * - the most important item is scope. The same scope
+ * is best. Then search for a larger scope.
+ * 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.
+ * - If there is no other reasons to choose one,
+ * addresses on the outgoing I/F are preferred.
+ *
+ * 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 = 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) */
+ goto replace;
+ continue; /* (2) */
+ }
+ if (dscopecmp > 0) {
+ if (bscopecmp > 0) /* (3) */
+ continue;
+ goto replace; /* (4) */
+ }
+ if (dscopecmp < 0) {
+ if (bscopecmp > 0) /* (5) */
+ goto replace;
+ continue; /* (6) */
+ }
+
+ /* 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) */
+
+ replace:
+ ifa_best = (struct in6_ifaddr *)ifa;
+ blen = tlen >= 0 ? tlen :
+ in6_matchlen(IFA_IN6(ifa), dst);
+ best_scope = in6_addrscope(&ifa_best->ia_addr.sin6_addr);
}
- return ia;
}
- /* use the last-resort values, that are, deprecated addresses */
- if (dep[0])
- return dep[0];
- if (dep[1])
- return dep[1];
- if (dep[2])
- return dep[2];
+ /* count statistics for future improvements */
+ if (ifa_best == NULL)
+ ip6stat.ip6s_sources_none++;
+ else {
+ if (oifp == ifa_best->ia_ifp)
+ ip6stat.ip6s_sources_sameif[best_scope]++;
+ else
+ ip6stat.ip6s_sources_otherif[best_scope]++;
+
+ if (best_scope == dst_scope)
+ ip6stat.ip6s_sources_samescope[best_scope]++;
+ else
+ ip6stat.ip6s_sources_otherscope[best_scope]++;
+
+ if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) != 0)
+ ip6stat.ip6s_sources_deprecated[best_scope]++;
+ }
- return NULL;
+ return(ifa_best);
}
/*
* return the best address out of the same scope. if no address was
* found, return the first valid address from designated IF.
*/
-
struct in6_ifaddr *
in6_ifawithifp(ifp, dst)
register struct ifnet *ifp;
@@ -1753,61 +1915,13 @@ in6_if_up(ifp)
{
struct ifaddr *ifa;
struct in6_ifaddr *ia;
- struct sockaddr_dl *sdl;
- int type;
- struct ether_addr ea;
- int off;
int dad_delay; /* delay ticks before DAD output */
- bzero(&ea, sizeof(ea));
- sdl = NULL;
-
- TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
- {
- if (ifa->ifa_addr->sa_family == AF_INET6
- && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) {
- goto dad;
- }
- if (ifa->ifa_addr->sa_family != AF_LINK)
- continue;
- sdl = (struct sockaddr_dl *)ifa->ifa_addr;
- break;
- }
-
- switch (ifp->if_type) {
- case IFT_SLIP:
- case IFT_PPP:
-#ifdef IFT_DUMMY
- case IFT_DUMMY:
-#endif
- case IFT_GIF:
- case IFT_FAITH:
- type = IN6_IFT_P2P;
- in6_ifattach(ifp, type, 0, 1);
- break;
- case IFT_ETHER:
- case IFT_FDDI:
- case IFT_ATM:
- type = IN6_IFT_802;
- if (sdl == NULL)
- break;
- off = sdl->sdl_nlen;
- if (bcmp(&sdl->sdl_data[off], &ea, sizeof(ea)) != 0)
- in6_ifattach(ifp, type, LLADDR(sdl), 0);
- break;
- case IFT_ARCNET:
- type = IN6_IFT_ARCNET;
- if (sdl == NULL)
- break;
- off = sdl->sdl_nlen;
- if (sdl->sdl_data[off] != 0) /* XXX ?: */
- in6_ifattach(ifp, type, LLADDR(sdl), 0);
- break;
- default:
- break;
- }
+ /*
+ * special cases, like 6to4, are handled in in6_ifattach
+ */
+ in6_ifattach(ifp, NULL);
-dad:
dad_delay = 0;
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h
index 424c319bf23c..edcbe6265200 100644
--- a/sys/netinet6/in6.h
+++ b/sys/netinet6/in6.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6.h,v 1.48 2000/06/26 15:55:32 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -60,25 +63,24 @@
* SUCH DAMAGE.
*
* @(#)in.h 8.3 (Berkeley) 1/3/94
- * $FreeBSD$
*/
-#ifndef _NETINET6_IN6_H_
-#define _NETINET6_IN6_H_
-
-#if !defined(_KERNEL) && !defined(__KAME_NETINET_IN_H_INCLUDED_)
+#ifndef __KAME_NETINET_IN_H_INCLUDED_
#error "do not include netinet6/in6.h directly, include netinet/in.h"
#endif
-#if !defined(_XOPEN_SOURCE)
+#ifndef _NETINET6_IN6_H_
+#define _NETINET6_IN6_H_
+
+#ifndef _XOPEN_SOURCE
#include <sys/queue.h>
#endif
/*
* Identification of the network protocol stack
*/
-#define __KAME__
-#define __KAME_VERSION "SNAP 19991101"
+#define __KAME__
+#define __KAME_VERSION "20000701/FreeBSD-current"
/*
* Local port number conventions:
@@ -89,7 +91,7 @@
* When a user does a bind(2) or connect(2) with a port number of zero,
* a non-conflicting local port address is chosen.
*
- * The default range is IPPORT_ANONMIX to IPPORT_ANONMAX, although
+ * The default range is IPPORT_ANONMIN to IPPORT_ANONMAX, although
* that is settable by sysctl(3); net.inet.ip.anonportmin and
* net.inet.ip.anonportmax respectively.
*
@@ -119,33 +121,33 @@
*/
struct in6_addr {
union {
- u_int8_t __u6_addr8[16];
- u_int16_t __u6_addr16[8];
- u_int32_t __u6_addr32[4];
+ u_int8_t __u6_addr8[16];
+ u_int16_t __u6_addr16[8];
+ u_int32_t __u6_addr32[4];
} __u6_addr; /* 128-bit IP6 address */
};
-#define s6_addr __u6_addr.__u6_addr8
+#define s6_addr __u6_addr.__u6_addr8
#ifdef _KERNEL /*XXX nonstandard*/
-#define s6_addr8 __u6_addr.__u6_addr8
-#define s6_addr16 __u6_addr.__u6_addr16
-#define s6_addr32 __u6_addr.__u6_addr32
+#define s6_addr8 __u6_addr.__u6_addr8
+#define s6_addr16 __u6_addr.__u6_addr16
+#define s6_addr32 __u6_addr.__u6_addr32
#endif
-#define INET6_ADDRSTRLEN 46
+#define INET6_ADDRSTRLEN 46
/*
* Socket address for IPv6
*/
-#if !defined(_XOPEN_SOURCE)
-#define SIN6_LEN
+#ifndef _XOPEN_SOURCE
+#define SIN6_LEN
#endif
struct sockaddr_in6 {
- u_char sin6_len; /* length of this struct(sa_family_t)*/
- u_char sin6_family; /* AF_INET6 (sa_family_t) */
+ u_int8_t sin6_len; /* length of this struct(sa_family_t)*/
+ u_int8_t sin6_family; /* AF_INET6 (sa_family_t) */
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 */
+ struct in6_addr sin6_addr; /* IP6 address */
u_int32_t sin6_scope_id; /* intface scope id */
};
@@ -153,14 +155,14 @@ struct sockaddr_in6 {
* Local definition for masks
*/
#ifdef _KERNEL /*XXX nonstandard*/
-#define IN6MASK0 {{{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}}
-#define IN6MASK32 {{{ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, \
+#define IN6MASK0 {{{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}}
+#define IN6MASK32 {{{ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}
-#define IN6MASK64 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+#define IN6MASK64 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}
-#define IN6MASK96 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+#define IN6MASK96 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }}}
-#define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+#define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
#endif
@@ -177,42 +179,42 @@ extern const struct in6_addr in6mask128;
*/
#ifdef _KERNEL /*XXX nonstandard*/
#if BYTE_ORDER == BIG_ENDIAN
-#define IPV6_ADDR_INT32_ONE 1
-#define IPV6_ADDR_INT32_TWO 2
-#define IPV6_ADDR_INT32_MNL 0xff010000
-#define IPV6_ADDR_INT32_MLL 0xff020000
-#define IPV6_ADDR_INT32_SMP 0x0000ffff
-#define IPV6_ADDR_INT16_ULL 0xfe80
-#define IPV6_ADDR_INT16_USL 0xfec0
-#define IPV6_ADDR_INT16_MLL 0xff02
+#define IPV6_ADDR_INT32_ONE 1
+#define IPV6_ADDR_INT32_TWO 2
+#define IPV6_ADDR_INT32_MNL 0xff010000
+#define IPV6_ADDR_INT32_MLL 0xff020000
+#define IPV6_ADDR_INT32_SMP 0x0000ffff
+#define IPV6_ADDR_INT16_ULL 0xfe80
+#define IPV6_ADDR_INT16_USL 0xfec0
+#define IPV6_ADDR_INT16_MLL 0xff02
#elif BYTE_ORDER == LITTLE_ENDIAN
-#define IPV6_ADDR_INT32_ONE 0x01000000
-#define IPV6_ADDR_INT32_TWO 0x02000000
-#define IPV6_ADDR_INT32_MNL 0x000001ff
-#define IPV6_ADDR_INT32_MLL 0x000002ff
-#define IPV6_ADDR_INT32_SMP 0xffff0000
-#define IPV6_ADDR_INT16_ULL 0x80fe
-#define IPV6_ADDR_INT16_USL 0xc0fe
-#define IPV6_ADDR_INT16_MLL 0x02ff
+#define IPV6_ADDR_INT32_ONE 0x01000000
+#define IPV6_ADDR_INT32_TWO 0x02000000
+#define IPV6_ADDR_INT32_MNL 0x000001ff
+#define IPV6_ADDR_INT32_MLL 0x000002ff
+#define IPV6_ADDR_INT32_SMP 0xffff0000
+#define IPV6_ADDR_INT16_ULL 0x80fe
+#define IPV6_ADDR_INT16_USL 0xc0fe
+#define IPV6_ADDR_INT16_MLL 0x02ff
#endif
#endif
/*
* Definition of some useful macros to handle IP6 addresses
*/
-#define IN6ADDR_ANY_INIT \
+#define IN6ADDR_ANY_INIT \
{{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}
-#define IN6ADDR_LOOPBACK_INIT \
+#define IN6ADDR_LOOPBACK_INIT \
{{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
-#define IN6ADDR_NODELOCAL_ALLNODES_INIT \
+#define IN6ADDR_NODELOCAL_ALLNODES_INIT \
{{{ 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
-#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \
+#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
-#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \
+#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
@@ -229,17 +231,17 @@ extern const struct in6_addr in6addr_linklocal_allrouters;
* in ANSI standard.
*/
#ifdef _KERNEL
-#define IN6_ARE_ADDR_EQUAL(a, b) \
- (bcmp((a), (b), sizeof(struct in6_addr)) == 0)
+#define IN6_ARE_ADDR_EQUAL(a, b) \
+ (bcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0)
#else
-#define IN6_ARE_ADDR_EQUAL(a, b) \
- (memcmp((a), (b), sizeof(struct in6_addr)) == 0)
+#define IN6_ARE_ADDR_EQUAL(a, b) \
+ (memcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0)
#endif
/*
* Unspecified
*/
-#define IN6_IS_ADDR_UNSPECIFIED(a) \
+#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) && \
@@ -248,7 +250,7 @@ extern const struct in6_addr in6addr_linklocal_allrouters;
/*
* Loopback
*/
-#define IN6_IS_ADDR_LOOPBACK(a) \
+#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) && \
@@ -257,7 +259,7 @@ extern const struct in6_addr in6addr_linklocal_allrouters;
/*
* IPv4 compatible
*/
-#define IN6_IS_ADDR_V4COMPAT(a) \
+#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) && \
@@ -267,7 +269,7 @@ extern const struct in6_addr in6addr_linklocal_allrouters;
/*
* Mapped
*/
-#define IN6_IS_ADDR_V4MAPPED(a) \
+#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)))
@@ -277,26 +279,26 @@ extern const struct in6_addr in6addr_linklocal_allrouters;
*/
#ifdef _KERNEL /*XXX nonstandard*/
-#define IPV6_ADDR_SCOPE_NODELOCAL 0x01
-#define IPV6_ADDR_SCOPE_LINKLOCAL 0x02
-#define IPV6_ADDR_SCOPE_SITELOCAL 0x05
-#define IPV6_ADDR_SCOPE_ORGLOCAL 0x08 /* just used in this file */
-#define IPV6_ADDR_SCOPE_GLOBAL 0x0e
+#define IPV6_ADDR_SCOPE_NODELOCAL 0x01
+#define IPV6_ADDR_SCOPE_LINKLOCAL 0x02
+#define IPV6_ADDR_SCOPE_SITELOCAL 0x05
+#define IPV6_ADDR_SCOPE_ORGLOCAL 0x08 /* just used in this file */
+#define IPV6_ADDR_SCOPE_GLOBAL 0x0e
#else
-#define __IPV6_ADDR_SCOPE_NODELOCAL 0x01
-#define __IPV6_ADDR_SCOPE_LINKLOCAL 0x02
-#define __IPV6_ADDR_SCOPE_SITELOCAL 0x05
-#define __IPV6_ADDR_SCOPE_ORGLOCAL 0x08 /* just used in this file */
-#define __IPV6_ADDR_SCOPE_GLOBAL 0x0e
+#define __IPV6_ADDR_SCOPE_NODELOCAL 0x01
+#define __IPV6_ADDR_SCOPE_LINKLOCAL 0x02
+#define __IPV6_ADDR_SCOPE_SITELOCAL 0x05
+#define __IPV6_ADDR_SCOPE_ORGLOCAL 0x08 /* just used in this file */
+#define __IPV6_ADDR_SCOPE_GLOBAL 0x0e
#endif
/*
* Unicast Scope
* Note that we must check topmost 10 bits only, not 16 bits (see RFC2373).
*/
-#define IN6_IS_ADDR_LINKLOCAL(a) \
+#define IN6_IS_ADDR_LINKLOCAL(a) \
(((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
-#define IN6_IS_ADDR_SITELOCAL(a) \
+#define IN6_IS_ADDR_SITELOCAL(a) \
(((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
/*
@@ -305,44 +307,44 @@ extern const struct in6_addr in6addr_linklocal_allrouters;
#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xff)
#ifdef _KERNEL /*XXX nonstandard*/
-#define IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f)
+#define IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f)
#else
-#define __IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f)
+#define __IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f)
#endif
/*
* Multicast Scope
*/
#ifdef _KERNEL /*refers nonstandard items */
-#define IN6_IS_ADDR_MC_NODELOCAL(a) \
+#define IN6_IS_ADDR_MC_NODELOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
(IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_NODELOCAL))
-#define IN6_IS_ADDR_MC_LINKLOCAL(a) \
+#define IN6_IS_ADDR_MC_LINKLOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
(IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_LINKLOCAL))
-#define IN6_IS_ADDR_MC_SITELOCAL(a) \
+#define IN6_IS_ADDR_MC_SITELOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
(IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_SITELOCAL))
-#define IN6_IS_ADDR_MC_ORGLOCAL(a) \
+#define IN6_IS_ADDR_MC_ORGLOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
(IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_ORGLOCAL))
-#define IN6_IS_ADDR_MC_GLOBAL(a) \
+#define IN6_IS_ADDR_MC_GLOBAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
(IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_GLOBAL))
#else
-#define IN6_IS_ADDR_MC_NODELOCAL(a) \
+#define IN6_IS_ADDR_MC_NODELOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_NODELOCAL))
-#define IN6_IS_ADDR_MC_LINKLOCAL(a) \
+#define IN6_IS_ADDR_MC_LINKLOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_LINKLOCAL))
-#define IN6_IS_ADDR_MC_SITELOCAL(a) \
+#define IN6_IS_ADDR_MC_SITELOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_SITELOCAL))
-#define IN6_IS_ADDR_MC_ORGLOCAL(a) \
+#define IN6_IS_ADDR_MC_ORGLOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_ORGLOCAL))
-#define IN6_IS_ADDR_MC_GLOBAL(a) \
+#define IN6_IS_ADDR_MC_GLOBAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_GLOBAL))
#endif
@@ -351,7 +353,7 @@ extern const struct in6_addr in6addr_linklocal_allrouters;
* KAME Scope
*/
#ifdef _KERNEL /*nonstandard*/
-#define IN6_IS_SCOPE_LINKLOCAL(a) \
+#define IN6_IS_SCOPE_LINKLOCAL(a) \
((IN6_IS_ADDR_LINKLOCAL(a)) || \
(IN6_IS_ADDR_MC_LINKLOCAL(a)))
#endif
@@ -359,7 +361,7 @@ extern const struct in6_addr in6addr_linklocal_allrouters;
/*
* IP6 route structure
*/
-#if !defined(_XOPEN_SOURCE)
+#ifndef _XOPEN_SOURCE
struct route_in6 {
struct rtentry *ro_rt;
struct sockaddr_in6 ro_dst;
@@ -370,66 +372,68 @@ struct route_in6 {
* Options for use with [gs]etsockopt at the IPV6 level.
* First word of comment is data type; bool is stored in int.
*/
-#define IPV6_OPTIONS 1 /* buf/ip6_opts; set/get IP6 options */
/* no hdrincl */
-#define IPV6_SOCKOPT_RESERVED1 3 /* reserved for future use */
-#define IPV6_UNICAST_HOPS 4 /* int; IP6 hops */
-#define IPV6_RECVOPTS 5 /* bool; receive all IP6 opts w/dgram */
-#define IPV6_RECVRETOPTS 6 /* bool; receive IP6 opts for response */
-#define IPV6_RECVDSTADDR 7 /* bool; receive IP6 dst addr w/dgram */
-#define IPV6_RETOPTS 8 /* ip6_opts; set/get IP6 options */
-#define IPV6_MULTICAST_IF 9 /* u_char; set/get IP6 multicast i/f */
-#define IPV6_MULTICAST_HOPS 10 /* u_char; set/get IP6 multicast hops */
-#define IPV6_MULTICAST_LOOP 11 /* u_char; set/get IP6 multicast loopback */
-#define IPV6_JOIN_GROUP 12 /* ip6_mreq; join a group membership */
-#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 */
-#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 */
+#if 0 /* the followings are relic in IPv4 and hence are disabled */
+#define IPV6_OPTIONS 1 /* buf/ip6_opts; set/get IP6 options */
+#define IPV6_RECVOPTS 5 /* bool; receive all IP6 opts w/dgram */
+#define IPV6_RECVRETOPTS 6 /* bool; receive IP6 opts for response */
+#define IPV6_RECVDSTADDR 7 /* bool; receive IP6 dst addr w/dgram */
+#define IPV6_RETOPTS 8 /* ip6_opts; set/get IP6 options */
+#endif
+#define IPV6_SOCKOPT_RESERVED1 3 /* reserved for future use */
+#define IPV6_UNICAST_HOPS 4 /* int; IP6 hops */
+#define IPV6_MULTICAST_IF 9 /* u_char; set/get IP6 multicast i/f */
+#define IPV6_MULTICAST_HOPS 10 /* u_char; set/get IP6 multicast hops */
+#define IPV6_MULTICAST_LOOP 11 /* u_char; set/get IP6 multicast loopback */
+#define IPV6_JOIN_GROUP 12 /* ip6_mreq; join a group membership */
+#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 */
+#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 */
/* for IPsec */
-#define IPV6_IPSEC_POLICY 28 /* struct; get/set security policy */
-#define IPV6_FAITH 29 /* bool; accept FAITH'ed connections */
+#define IPV6_IPSEC_POLICY 28 /* struct; get/set security policy */
+#define IPV6_FAITH 29 /* bool; accept FAITH'ed connections */
/* for 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 */
+#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 */
-#define IPV6_RTHDR_LOOSE 0 /* this hop need not be a neighbor. XXX old spec */
-#define IPV6_RTHDR_STRICT 1 /* this hop must be a neighbor. XXX old spec */
-#define IPV6_RTHDR_TYPE_0 0 /* IPv6 routing header type 0 */
+#define IPV6_RTHDR_LOOSE 0 /* this hop need not be a neighbor. XXX old spec */
+#define IPV6_RTHDR_STRICT 1 /* this hop must be a neighbor. XXX old spec */
+#define IPV6_RTHDR_TYPE_0 0 /* IPv6 routing header type 0 */
/*
* Defaults and limits for options
*/
-#define IPV6_DEFAULT_MULTICAST_HOPS 1 /* normally limit m'casts to 1 hop */
-#define IPV6_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */
+#define IPV6_DEFAULT_MULTICAST_HOPS 1 /* normally limit m'casts to 1 hop */
+#define IPV6_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */
/*
* Argument structure for IPV6_JOIN_GROUP and IPV6_LEAVE_GROUP.
*/
struct ipv6_mreq {
- struct in6_addr ipv6mr_multiaddr;
- u_int ipv6mr_interface;
+ struct in6_addr ipv6mr_multiaddr;
+ unsigned int ipv6mr_interface;
};
/*
* IPV6_PKTINFO: Packet information(RFC2292 sec 5)
*/
struct in6_pktinfo {
- struct in6_addr ipi6_addr; /* src/dst IPv6 address */
- u_int ipi6_ifindex; /* send/recv interface index */
+ struct in6_addr ipi6_addr; /* src/dst IPv6 address */
+ unsigned int ipi6_ifindex; /* send/recv interface index */
};
/*
@@ -440,16 +444,16 @@ struct in6_pktinfo {
#define IPV6_PORTRANGE_HIGH 1 /* "high" - request firewall bypass */
#define IPV6_PORTRANGE_LOW 2 /* "low" - vouchsafe security */
-#if !defined(_XOPEN_SOURCE)
+#ifndef _XOPEN_SOURCE
/*
* Definitions for inet6 sysctl operations.
*
* Third level is protocol number.
* Fourth level is desired variable within that protocol.
*/
-#define IPV6PROTO_MAXID (IPPROTO_PIM + 1) /* don't list to IPV6PROTO_MAX */
+#define IPV6PROTO_MAXID (IPPROTO_PIM + 1) /* don't list to IPV6PROTO_MAX */
-#define CTL_IPV6PROTO_NAMES { \
+#define CTL_IPV6PROTO_NAMES { \
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \
{ 0, 0 }, \
{ "tcp6", CTLTYPE_NODE }, \
@@ -499,51 +503,50 @@ struct in6_pktinfo {
/*
* Names for IP sysctl objects
*/
-#define IPV6CTL_FORWARDING 1 /* act as router */
-#define IPV6CTL_SENDREDIRECTS 2 /* may send redirects when forwarding*/
-#define IPV6CTL_DEFHLIM 3 /* default Hop-Limit */
+#define IPV6CTL_FORWARDING 1 /* act as router */
+#define IPV6CTL_SENDREDIRECTS 2 /* may send redirects when forwarding*/
+#define IPV6CTL_DEFHLIM 3 /* default Hop-Limit */
#ifdef notyet
-#define IPV6CTL_DEFMTU 4 /* default MTU */
+#define IPV6CTL_DEFMTU 4 /* default MTU */
#endif
-#define IPV6CTL_FORWSRCRT 5 /* forward source-routed dgrams */
-#define IPV6CTL_STATS 6 /* stats */
-#define IPV6CTL_MRTSTATS 7 /* multicast forwarding stats */
-#define IPV6CTL_MRTPROTO 8 /* multicast routing protocol */
-#define IPV6CTL_MAXFRAGPACKETS 9 /* max packets reassembly queue */
-#define IPV6CTL_SOURCECHECK 10 /* verify source route and intf */
-#define IPV6CTL_SOURCECHECK_LOGINT 11 /* minimume logging interval */
-#define IPV6CTL_ACCEPT_RTADV 12
-#define IPV6CTL_KEEPFAITH 13
-#define IPV6CTL_LOG_INTERVAL 14
-#define IPV6CTL_HDRNESTLIMIT 15
-#define IPV6CTL_DAD_COUNT 16
-#define IPV6CTL_AUTO_FLOWLABEL 17
-#define IPV6CTL_DEFMCASTHLIM 18
-#define IPV6CTL_GIF_HLIM 19 /* default HLIM for gif encap packet */
-#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 */
-#define IPV6CTL_MAPPED_ADDR 23
+#define IPV6CTL_FORWSRCRT 5 /* forward source-routed dgrams */
+#define IPV6CTL_STATS 6 /* stats */
+#define IPV6CTL_MRTSTATS 7 /* multicast forwarding stats */
+#define IPV6CTL_MRTPROTO 8 /* multicast routing protocol */
+#define IPV6CTL_MAXFRAGPACKETS 9 /* max packets reassembly queue */
+#define IPV6CTL_SOURCECHECK 10 /* verify source route and intf */
+#define IPV6CTL_SOURCECHECK_LOGINT 11 /* minimume logging interval */
+#define IPV6CTL_ACCEPT_RTADV 12
+#define IPV6CTL_KEEPFAITH 13
+#define IPV6CTL_LOG_INTERVAL 14
+#define IPV6CTL_HDRNESTLIMIT 15
+#define IPV6CTL_DAD_COUNT 16
+#define IPV6CTL_AUTO_FLOWLABEL 17
+#define IPV6CTL_DEFMCASTHLIM 18
+#define IPV6CTL_GIF_HLIM 19 /* default HLIM for gif encap packet */
+#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 */
+#define IPV6CTL_MAPPED_ADDR 23
/* New entries should be added here from current IPV6CTL_MAXID value. */
-#define IPV6CTL_MAXID 24
+#define IPV6CTL_MAXID 24
#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_ANYCAST6 M_PROTO1
+#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;
-int in6_canforward __P((struct in6_addr *, struct in6_addr *));
-int in6_cksum __P((struct mbuf *, u_int8_t, int, int));
+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 *));
@@ -558,9 +561,9 @@ 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
diff --git a/sys/netinet6/in6_cksum.c b/sys/netinet6/in6_cksum.c
index 28af01fa1435..1f2650215f10 100644
--- a/sys/netinet6/in6_cksum.c
+++ b/sys/netinet6/in6_cksum.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6_cksum.c,v 1.6 2000/03/25 07:23:43 sumikawa Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -68,7 +69,7 @@
#include <sys/mbuf.h>
#include <sys/systm.h>
#include <netinet/in.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <net/net_osdep.h>
@@ -79,11 +80,11 @@
* code and should be modified for each CPU to be as fast as possible.
*/
-#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
-#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
+#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
+#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
static union {
- u_int16_t phs[4];
+ u_int16_t phs[4];
struct {
u_int32_t ph_len;
u_int8_t ph_zero[3];
@@ -102,12 +103,15 @@ int
in6_cksum(m, nxt, off, len)
register struct mbuf *m;
u_int8_t nxt;
- register int off, len;
+ u_int32_t off, len;
{
register u_int16_t *w;
register int sum = 0;
register int mlen = 0;
int byte_swapped = 0;
+#if 0
+ int srcifid = 0, dstifid = 0;
+#endif
struct ip6_hdr *ip6;
union {
@@ -129,6 +133,16 @@ in6_cksum(m, nxt, off, len)
* First create IP6 pseudo header and calculate a summary.
*/
ip6 = mtod(m, struct ip6_hdr *);
+#if 0
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
+ srcifid = ip6->ip6_src.s6_addr16[1];
+ ip6->ip6_src.s6_addr16[1] = 0;
+ }
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
+ dstifid = ip6->ip6_dst.s6_addr16[1];
+ ip6->ip6_dst.s6_addr16[1] = 0;
+ }
+#endif
w = (u_int16_t *)&ip6->ip6_src;
uph.ph.ph_len = htonl(len);
uph.ph.ph_nxt = nxt;
@@ -149,6 +163,12 @@ in6_cksum(m, nxt, off, len)
sum += uph.phs[0]; sum += uph.phs[1];
sum += uph.phs[2]; sum += uph.phs[3];
+#if 0
+ if (srcifid)
+ ip6->ip6_src.s6_addr16[1] = srcifid;
+ if (dstifid)
+ ip6->ip6_dst.s6_addr16[1] = dstifid;
+#endif
/*
* Secondly calculate a summary of the first mbuf excluding offset.
*/
diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c
index 35c408840384..e554f5a64f7e 100644
--- a/sys/netinet6/in6_gif.c
+++ b/sys/netinet6/in6_gif.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6_gif.c,v 1.37 2000/06/17 20:34:25 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -34,6 +35,7 @@
*/
#include "opt_inet.h"
+#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -41,7 +43,6 @@
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/errno.h>
-#include <sys/protosw.h>
#include <net/if.h>
#include <net/route.h>
@@ -51,17 +52,26 @@
#ifdef INET
#include <netinet/ip.h>
#endif
-#include <netinet6/ip6.h>
+#include <netinet/ip_encap.h>
+#ifdef INET6
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/in6_gif.h>
-#include <netinet6/ip6.h>
+#include <netinet6/in6_var.h>
+#endif
#include <netinet/ip_ecn.h>
+#ifdef INET6
#include <netinet6/ip6_ecn.h>
+#endif
#include <net/if_gif.h>
#include <net/net_osdep.h>
+#ifndef offsetof
+#define offsetof(s, e) ((int)&((s *)0)->e)
+#endif
+
int
in6_gif_output(ifp, family, m, rt)
struct ifnet *ifp;
@@ -101,6 +111,7 @@ in6_gif_output(ifp, family, m, rt)
break;
}
#endif
+#ifdef INET6
case AF_INET6:
{
struct ip6_hdr *ip6;
@@ -114,15 +125,16 @@ in6_gif_output(ifp, family, m, rt)
itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
break;
}
+#endif
default:
-#ifdef DIAGNOSTIC
+#ifdef DEBUG
printf("in6_gif_output: warning: unknown family %d passed\n",
family);
#endif
m_freem(m);
return EAFNOSUPPORT;
}
-
+
/* prepend new IP header */
M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
if (m && m->m_len < sizeof(struct ip6_hdr))
@@ -134,7 +146,8 @@ in6_gif_output(ifp, family, m, rt)
ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_flow = 0;
- ip6->ip6_vfc = IPV6_VERSION;
+ ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
+ ip6->ip6_vfc |= IPV6_VERSION;
ip6->ip6_plen = htons((u_short)m->m_pkthdr.len);
ip6->ip6_nxt = proto;
ip6->ip6_hlim = ip6_gif_hlim;
@@ -144,6 +157,10 @@ in6_gif_output(ifp, family, m, rt)
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);
@@ -175,6 +192,9 @@ in6_gif_output(ifp, family, m, rt)
RTFREE(sc->gif_ro6.ro_rt);
sc->gif_ro6.ro_rt = NULL;
}
+#if 0
+ sc->gif_if.if_mtu = GIF_MTU;
+#endif
}
if (sc->gif_ro6.ro_rt == NULL) {
@@ -183,9 +203,28 @@ in6_gif_output(ifp, family, m, rt)
m_freem(m);
return ENETUNREACH;
}
- }
+ /* if it constitutes infinite encapsulation, punt. */
+ if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
+ m_freem(m);
+ return ENETUNREACH; /*XXX*/
+ }
+#if 0
+ ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu
+ - sizeof(struct ip6_hdr);
+#endif
+ }
+
+#ifdef IPV6_MINMTU
+ /*
+ * force fragmentation to minimum MTU, to avoid path MTU discovery.
+ * it is too painful to ask for resend of inner packet, to achieve
+ * path MTU discovery for encapsulated packets.
+ */
+ return(ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL));
+#else
return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL));
+#endif
}
int in6_gif_input(mp, offp, proto)
@@ -193,44 +232,21 @@ int in6_gif_input(mp, offp, proto)
int *offp, proto;
{
struct mbuf *m = *mp;
- struct gif_softc *sc;
struct ifnet *gifp = NULL;
struct ip6_hdr *ip6;
- int i;
int af = 0;
u_int32_t otos;
ip6 = mtod(m, struct ip6_hdr *);
-#define satoin6(sa) (((struct sockaddr_in6 *)(sa))->sin6_addr)
- for (i = 0, sc = gif; i < ngif; i++, sc++) {
- if (sc->gif_psrc == NULL ||
- sc->gif_pdst == NULL ||
- sc->gif_psrc->sa_family != AF_INET6 ||
- sc->gif_pdst->sa_family != AF_INET6) {
- continue;
- }
- if ((sc->gif_if.if_flags & IFF_UP) == 0)
- continue;
- if ((sc->gif_if.if_flags & IFF_LINK0) &&
- IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) &&
- IN6_IS_ADDR_UNSPECIFIED(&satoin6(sc->gif_pdst))) {
- gifp = &sc->gif_if;
- continue;
- }
- if (IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) &&
- IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_pdst), &ip6->ip6_src)) {
- gifp = &sc->gif_if;
- break;
- }
- }
+ gifp = (struct ifnet *)encap_getarg(m);
- if (gifp == NULL) {
+ if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
m_freem(m);
ip6stat.ip6s_nogif++;
return IPPROTO_DONE;
}
-
+
otos = ip6->ip6_flow;
m_adj(m, *offp);
@@ -253,6 +269,7 @@ int in6_gif_input(mp, offp, proto)
break;
}
#endif /* INET */
+#ifdef INET6
case IPPROTO_IPV6:
{
struct ip6_hdr *ip6;
@@ -267,12 +284,76 @@ int in6_gif_input(mp, offp, proto)
ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow);
break;
}
+#endif
default:
ip6stat.ip6s_nogif++;
m_freem(m);
return IPPROTO_DONE;
}
-
+
gif_input(m, af, gifp);
return IPPROTO_DONE;
}
+
+/*
+ * we know that we are in IFF_UP, outer address available, and outer family
+ * matched the physical addr family. see gif_encapcheck().
+ */
+int
+gif_encapcheck6(m, off, proto, arg)
+ const struct mbuf *m;
+ int off;
+ int proto;
+ void *arg;
+{
+ struct ip6_hdr ip6;
+ struct gif_softc *sc;
+ struct sockaddr_in6 *src, *dst;
+ int addrmatch;
+
+ /* sanity check done in caller */
+ sc = (struct gif_softc *)arg;
+ src = (struct sockaddr_in6 *)sc->gif_psrc;
+ dst = (struct sockaddr_in6 *)sc->gif_pdst;
+
+ /* LINTED const cast */
+ m_copydata((struct mbuf *)m, 0, sizeof(ip6), (caddr_t)&ip6);
+
+ /* check for address match */
+ addrmatch = 0;
+ if (IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6.ip6_dst))
+ 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) {
+ struct sockaddr_in6 sin6;
+ struct rtentry *rt;
+
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ 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);
+ return 0;
+ }
+ rtfree(rt);
+ }
+
+ /* prioritize: IFF_LINK0 mode is less preferred */
+ return (sc->gif_if.if_flags & IFF_LINK0) ? 128 : 128 * 2;
+}
diff --git a/sys/netinet6/in6_gif.h b/sys/netinet6/in6_gif.h
index 65d76357582c..b1fe10484bf5 100644
--- a/sys/netinet6/in6_gif.h
+++ b/sys/netinet6/in6_gif.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6_gif.h,v 1.5 2000/04/14 08:36:03 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,21 +28,15 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _NETINET6_IN6_GIF_H_
-#define _NETINET6_IN6_GIF_H_
-
-#define GIF_HLIM 30
+#define _NETINET6_IN6_GIF_H_
-struct mbuf;
-struct ifnet;
-struct rtentry;
+#define GIF_HLIM 30
-int in6_gif_input __P((struct mbuf **, int *, int));
-int in6_gif_output __P((struct ifnet *, int, struct mbuf *,
- struct rtentry *));
+int in6_gif_input __P((struct mbuf **, int *, int));
+int in6_gif_output __P((struct ifnet *, int, struct mbuf *, struct rtentry *));
+int gif_encapcheck6 __P((const struct mbuf *, int, int, void *));
#endif /*_NETINET6_IN6_GIF_H_*/
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c
index 7d332eda14bd..39d26f7580ff 100644
--- a/sys/netinet6/in6_ifattach.c
+++ b/sys/netinet6/in6_ifattach.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6_ifattach.c,v 1.61 2000/06/13 08:15:27 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
#include <sys/param.h>
@@ -46,267 +47,657 @@
#include <netinet/in_var.h>
#include <netinet/if_ether.h>
-#include <netinet6/in6.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/in6_ifattach.h>
-#include <netinet6/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
+#include <netinet6/scope6_var.h>
#include <net/net_osdep.h>
-static struct in6_addr llsol;
-
-struct in6_ifstat **in6_ifstat = NULL;
-struct icmp6_ifstat **icmp6_ifstat = NULL;
-size_t in6_ifstatmax = 0;
-size_t icmp6_ifstatmax = 0;
-unsigned long in6_maxmtu = 0;
-
-int found_first_ifid = 0;
-#define IFID_LEN 8
-static char first_ifid[IFID_LEN];
-
-static int laddr_to_eui64 __P((u_int8_t *, u_int8_t *, size_t));
-static int gen_rand_eui64 __P((u_int8_t *));
-
-static int
-laddr_to_eui64(dst, src, len)
- u_int8_t *dst;
- u_int8_t *src;
- size_t len;
-{
- static u_int8_t zero[8];
-
- bzero(zero, sizeof(zero));
-
- switch (len) {
- case 6:
- if (bcmp(zero, src, 6) == 0)
- return EINVAL;
- dst[0] = src[0];
- dst[1] = src[1];
- dst[2] = src[2];
- dst[3] = 0xff;
- dst[4] = 0xfe;
- dst[5] = src[3];
- dst[6] = src[4];
- dst[7] = src[5];
- break;
- case 8:
- if (bcmp(zero, src, 8) == 0)
- return EINVAL;
- bcopy(src, dst, len);
- break;
- default:
- return EINVAL;
- }
-
- return 0;
-}
+struct in6_ifstat **in6_ifstat = NULL;
+struct icmp6_ifstat **icmp6_ifstat = NULL;
+size_t in6_ifstatmax = 0;
+size_t icmp6_ifstatmax = 0;
+unsigned long in6_maxmtu = 0;
+
+static int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
+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
+#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
+#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT)
+#define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6))
+#define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT)
+#define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6))
+
+#define IFID_LOCAL(in6) (!EUI64_LOCAL(in6))
+#define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6))
/*
* Generate a last-resort interface identifier, when the machine has no
* IEEE802/EUI64 address sources.
- * The address should be random, and should not change across reboot.
+ * The goal here is to get an interface identifier that is
+ * (1) random enough and (2) does not change across reboot.
+ * We currently use MD5(hostname) for it.
*/
static int
-gen_rand_eui64(dst)
- u_int8_t *dst;
+get_rand_ifid(ifp, in6)
+ struct ifnet *ifp;
+ struct in6_addr *in6; /*upper 64bits are preserved */
{
MD5_CTX ctxt;
u_int8_t digest[16];
int hostnamelen = strlen(hostname);
- /* generate 8bytes of pseudo-random value. */
+#if 0
+ /* we need at least several letters as seed for ifid */
+ if (hostnamelen < 3)
+ return -1;
+#endif
+
+ /* generate 8 bytes of pseudo-random value. */
bzero(&ctxt, sizeof(ctxt));
MD5Init(&ctxt);
MD5Update(&ctxt, hostname, hostnamelen);
MD5Final(digest, &ctxt);
- /* assumes sizeof(digest) > sizeof(first_ifid) */
- bcopy(digest, dst, 8);
+ /* assumes sizeof(digest) > sizeof(ifid) */
+ bcopy(digest, &in6->s6_addr[8], 8);
/* make sure to set "u" bit to local, and "g" bit to individual. */
- dst[0] &= 0xfe;
- dst[0] |= 0x02; /* EUI64 "local" */
+ in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
+ in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
+
+ /* convert EUI64 into IPv6 interface identifier */
+ EUI64_TO_IFID(in6);
return 0;
}
/*
- * Find first ifid on list of interfaces.
- * This is assumed that ifp0's interface token (for example, IEEE802 MAC)
- * is globally unique. We may need to have a flag parameter in the future.
+ * Get interface identifier for the specified interface.
+ * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
*/
-int
-in6_ifattach_getifid(ifp0)
- struct ifnet *ifp0;
-{
+static int
+get_hw_ifid(ifp, in6)
struct ifnet *ifp;
+ struct in6_addr *in6; /*upper 64bits are preserved */
+{
struct ifaddr *ifa;
- u_int8_t *addr = NULL;
- int addrlen = 0;
struct sockaddr_dl *sdl;
-
- if (found_first_ifid)
- return 0;
-
- TAILQ_FOREACH(ifp, &ifnet, if_list)
+ u_int8_t *addr;
+ size_t addrlen;
+ static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ static u_int8_t allone[8] =
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ for (ifa = ifp->if_addrlist.tqh_first;
+ ifa;
+ ifa = ifa->ifa_list.tqe_next)
{
- if (ifp0 != NULL && ifp0 != ifp)
+ if (ifa->ifa_addr->sa_family != AF_LINK)
continue;
- TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
- {
- if (ifa->ifa_addr->sa_family != AF_LINK)
- continue;
- sdl = (struct sockaddr_dl *)ifa->ifa_addr;
- if (sdl == NULL)
- continue;
- if (sdl->sdl_alen == 0)
- continue;
- switch (ifp->if_type) {
- case IFT_ETHER:
- case IFT_FDDI:
- case IFT_ATM:
- /* IEEE802/EUI64 cases - what others? */
- addr = LLADDR(sdl);
- addrlen = sdl->sdl_alen;
- /*
- * to copy ifid from IEEE802/EUI64 interface,
- * u bit of the source needs to be 0.
- */
- if ((addr[0] & 0x02) != 0)
- break;
- goto found;
- case IFT_ARCNET:
- /*
- * ARCnet interface token cannot be used as
- * globally unique identifier due to its
- * small bitwidth.
- */
- break;
- default:
- break;
- }
- }
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ if (sdl == NULL)
+ continue;
+ if (sdl->sdl_alen == 0)
+ continue;
+
+ goto found;
}
-#ifdef DEBUG
- printf("in6_ifattach_getifid: failed to get EUI64");
-#endif
- return EADDRNOTAVAIL;
+
+ return -1;
found:
- if (laddr_to_eui64(first_ifid, addr, addrlen) == 0)
- found_first_ifid = 1;
-
- if (found_first_ifid) {
- printf("%s: supplying EUI64: "
- "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
- if_name(ifp),
- first_ifid[0] & 0xff, first_ifid[1] & 0xff,
- first_ifid[2] & 0xff, first_ifid[3] & 0xff,
- first_ifid[4] & 0xff, first_ifid[5] & 0xff,
- first_ifid[6] & 0xff, first_ifid[7] & 0xff);
-
- /* invert u bit to convert EUI64 to RFC2373 interface ID. */
- first_ifid[0] ^= 0x02;
-
- return 0;
- } else {
-#ifdef DEBUG
- printf("in6_ifattach_getifid: failed to get EUI64");
+ addr = LLADDR(sdl);
+ addrlen = sdl->sdl_alen;
+
+ /* get EUI64 */
+ switch (ifp->if_type) {
+ case IFT_ETHER:
+ case IFT_FDDI:
+ case IFT_ATM:
+ /* IEEE802/EUI64 cases - what others? */
+
+ /* look at IEEE802/EUI64 only */
+ if (addrlen != 8 && addrlen != 6)
+ return -1;
+
+ /*
+ * check for invalid MAC address - on bsdi, we see it a lot
+ * since wildboar configures all-zero MAC on pccard before
+ * card insertion.
+ */
+ if (bcmp(addr, allzero, addrlen) == 0)
+ return -1;
+ if (bcmp(addr, allone, addrlen) == 0)
+ return -1;
+
+ /* make EUI64 address */
+ if (addrlen == 8)
+ bcopy(addr, &in6->s6_addr[8], 8);
+ else if (addrlen == 6) {
+ in6->s6_addr[8] = addr[0];
+ in6->s6_addr[9] = addr[1];
+ in6->s6_addr[10] = addr[2];
+ in6->s6_addr[11] = 0xff;
+ in6->s6_addr[12] = 0xfe;
+ in6->s6_addr[13] = addr[3];
+ in6->s6_addr[14] = addr[4];
+ in6->s6_addr[15] = addr[5];
+ }
+ break;
+
+ case IFT_ARCNET:
+ if (addrlen != 1)
+ return -1;
+ if (!addr[0])
+ return -1;
+
+ bzero(&in6->s6_addr[8], 8);
+ in6->s6_addr[15] = addr[0];
+
+ /*
+ * due to insufficient bitwidth, we mark it local.
+ */
+ in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
+ in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
+ break;
+
+ case IFT_GIF:
+#ifdef IFT_STF
+ case IFT_STF:
#endif
- return EADDRNOTAVAIL;
+ /*
+ * mech-06 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.
+ */
+ return -1;
+
+ default:
+ return -1;
}
+
+ /* sanity check: g bit must not indicate "group" */
+ if (EUI64_GROUP(in6))
+ return -1;
+
+ /* convert EUI64 into IPv6 interface identifier */
+ EUI64_TO_IFID(in6);
+
+ /*
+ * sanity check: ifid must not be all zero, avoid conflict with
+ * subnet router anycast
+ */
+ if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
+ bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
+ return -1;
+ }
+
+ return 0;
}
/*
- * add link-local address to *pseudo* p2p interfaces.
- * get called when the first MAC address is made available in in6_ifattach().
- *
- * XXX I start considering this loop as a bad idea. (itojun)
+ * Get interface identifier for the specified interface. If it is not
+ * available on ifp0, borrow interface identifier from other information
+ * sources.
*/
-void
-in6_ifattach_p2p()
+static int
+get_ifid(ifp0, altifp, in6)
+ struct ifnet *ifp0;
+ struct ifnet *altifp; /*secondary EUI64 source*/
+ struct in6_addr *in6;
{
struct ifnet *ifp;
- /* prevent infinite loop. just in case. */
- if (found_first_ifid == 0)
- return;
+ /* 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
+ goto success;
+ }
- TAILQ_FOREACH(ifp, &ifnet, if_list)
+ /* 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
+ goto success;
+ }
+
+ /* next, try to get it from some other hardware interface */
+ for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
{
- switch (ifp->if_type) {
- case IFT_GIF:
- /* pseudo interfaces - safe to initialize here */
- in6_ifattach(ifp, IN6_IFT_P2P, 0, 0);
- break;
-#ifdef IFT_DUMMY
- case IFT_DUMMY:
+ if (ifp == ifp0)
+ continue;
+ if (get_hw_ifid(ifp, in6) != 0)
+ continue;
+
+ /*
+ * to borrow ifid from other interface, ifid needs to be
+ * globally unique
+ */
+ if (IFID_UNIVERSAL(in6)) {
+
+#ifdef ND6_DEBUG
+ printf("%s: borrow interface identifier from %s\n",
+ if_name(ifp0), if_name(ifp));
#endif
- case IFT_FAITH:
- /* this mistakingly becomes IFF_UP */
+ 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
+ goto success;
+ }
+
+ printf("%s: failed to get interface identifier", if_name(ifp0));
+ return -1;
+
+success:
+#ifdef ND6_DEBUG
+ printf("%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
+ return 0;
+}
+
+/*
+ * configure IPv6 interface address. XXX code duplicated with in.c
+ */
+static int
+in6_ifattach_addaddr(ifp, ia)
+ struct ifnet *ifp;
+ struct in6_ifaddr *ia;
+{
+ 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);
+ }
+
+ /*
+ * link the interface address to global list
+ */
+ 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++;
+
+ /*
+ * Also link into the IPv6 address chain beginning with in6_ifaddr.
+ * kazu opposed it, but itojun & jinmei wanted.
+ */
+ 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++;
+
+ /*
+ * 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;
- case IFT_SLIP:
- /* IPv6 is not supported */
+ default:
+ printf("%s: SIOCSIFADDR error %d\n", if_name(ifp),
+ error);
break;
- case IFT_PPP:
- /* this is not a pseudo interface, skip it */
+ }
+
+ /* 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;
+ }
+
+ /* 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:
+#endif
+ rtflag = 0;
break;
default:
+ ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
+ ia->ia_ifa.ifa_flags |= RTF_CLONING;
+ rtflag = RTF_CLONING;
break;
}
}
+
+ /* 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;
+
+ if ((rtflag & RTF_CLONING) != 0 &&
+ (ifp->if_flags & IFF_MULTICAST) != 0) {
+ /*
+ * join solicited multicast address
+ */
+ 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 */
+ }
+ }
+
+ return 0;
}
-void
-in6_ifattach(ifp, type, laddr, noloop)
+static int
+in6_ifattach_linklocal(ifp, altifp)
struct ifnet *ifp;
- u_int type;
- caddr_t laddr;
- /* size_t laddrlen; */
- int noloop;
+ 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_ifaddr *ia, *ib, *oia;
- struct ifaddr *ifa;
- int rtflag = 0;
-
- if (type == IN6_IFT_P2P && found_first_ifid == 0) {
- printf("%s: no ifid available for IPv6 link-local address\n",
- if_name(ifp));
- /* last resort */
- if (gen_rand_eui64(first_ifid) == 0) {
- printf("%s: using random value as EUI64: "
- "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
- if_name(ifp),
- first_ifid[0] & 0xff, first_ifid[1] & 0xff,
- first_ifid[2] & 0xff, first_ifid[3] & 0xff,
- first_ifid[4] & 0xff, first_ifid[5] & 0xff,
- first_ifid[6] & 0xff, first_ifid[7] & 0xff);
- /*
- * invert u bit to convert EUI64 to RFC2373 interface
- * ID.
- */
- first_ifid[0] ^= 0x02;
+ /*
+ * configure link-local address
+ */
+ 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;
- found_first_ifid = 1;
+ /* 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;
}
}
+#ifdef SCOPEDROUTING
+ ia->ia_addr.sin6_scope_id = in6_addr2scopeid(ifp,
+ &ia->ia_addr.sin6_addr);
+#endif
- if ((ifp->if_flags & IFF_MULTICAST) == 0) {
- printf("%s: not multicast capable, IPv6 not enabled\n",
- if_name(ifp));
+ ia->ia_ifa.ifa_metric = ifp->if_metric;
+
+ if (in6_ifattach_addaddr(ifp, ia) != 0) {
+ /* ia will be freed on failure */
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+in6_ifattach_loopback(ifp)
+ struct ifnet *ifp; /* must be IFT_LOOP */
+{
+ struct in6_ifaddr *ia;
+
+ /*
+ * configure link-local address
+ */
+ 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;
+
+ /*
+ * 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.
+ */
+ 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;
+
+ 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;
+
+ ia->ia_ifa.ifa_metric = ifp->if_metric;
+
+ if (in6_ifattach_addaddr(ifp, ia) != 0) {
+ /* ia will be freed on failure */
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * compute NI group address, based on the current hostname setting.
+ * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
+ *
+ * when ifp == NULL, the caller is responsible for filling scopeid.
+ */
+static int
+nigroup(ifp, name, namelen, in6)
+ struct ifnet *ifp;
+ const char *name;
+ int namelen;
+ struct in6_addr *in6;
+{
+ const char *p;
+ MD5_CTX ctxt;
+ u_int8_t digest[16];
+ char l;
+
+ if (!namelen || !name)
+ return -1;
+
+ p = name;
+ while (p && *p && *p != '.' && p - name < namelen)
+ p++;
+ if (p - name > 63)
+ return -1; /*label too long*/
+ l = p - name;
+
+ /* 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);
+ MD5Final(digest, &ctxt);
+
+ bzero(in6, sizeof(*in6));
+ in6->s6_addr16[0] = htons(0xff02);
+ if (ifp)
+ in6->s6_addr16[1] = htons(ifp->if_index);
+ in6->s6_addr8[11] = 2;
+ bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
+
+ return 0;
+}
+
+void
+in6_nigroup_attach(name, namelen)
+ const char *name;
+ int namelen;
+{
+ struct ifnet *ifp;
+ struct sockaddr_in6 mltaddr;
+ struct in6_multi *in6m;
+ int error;
+
+ 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)
+ 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);
+ }
+}
+
+void
+in6_nigroup_detach(name, namelen)
+ const char *name;
+ int namelen;
+{
+ struct ifnet *ifp;
+ struct sockaddr_in6 mltaddr;
+ struct in6_multi *in6m;
+
+ 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)
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)
+ in6_delmulti(in6m);
}
+}
+
+/*
+ * XXX multiple loopback interface needs more care. for instance,
+ * nodelocal address needs to be configured onto only one of them.
+ * XXX multiple link-local address case
+ */
+void
+in6_ifattach(ifp, altifp)
+ struct ifnet *ifp;
+ 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);
/*
* We have some arrays that should be indexed by if_index.
@@ -314,8 +705,8 @@ in6_ifattach(ifp, type, laddr, noloop)
* struct in6_ifstat **in6_ifstat
* struct icmp6_ifstat **icmp6_ifstat
*/
- if (in6_ifstat == NULL || icmp6_ifstat == NULL
- || if_index >= if_indexlim) {
+ if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
+ if_index >= if_indexlim) {
size_t n;
caddr_t q;
size_t olim;
@@ -349,144 +740,53 @@ in6_ifattach(ifp, type, laddr, noloop)
icmp6_ifstatmax = if_indexlim;
}
+ /* initialize scope identifiers */
+ scope6_ifattach(ifp);
+
/*
- * To prevent to assign link-local address to PnP network
- * cards multiple times.
- * This is lengthy for P2P and LOOP but works.
+ * quirks based on interface type
*/
- ifa = TAILQ_FIRST(&ifp->if_addrlist);
- if (ifa != NULL) {
- for ( ; ifa; ifa = TAILQ_NEXT(ifa, ifa_list)) {
- if (ifa->ifa_addr->sa_family != AF_INET6)
- continue;
- if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr))
- return;
- }
- } else {
- TAILQ_INIT(&ifp->if_addrlist);
+ switch (ifp->if_type) {
+#ifdef IFT_STF
+ case IFT_STF:
+ /*
+ * 6to4 interface is a very speical kind of beast.
+ * no multicast, no linklocal (based on 03 draft).
+ */
+ goto statinit;
+#endif
+ default:
+ break;
}
/*
- * link-local address
+ * usually, we require multicast capability to the interface
*/
- 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;
- TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
- /*
- * Also link into the IPv6 address chain beginning with in6_ifaddr.
- * kazu opposed it, but itojun & jinmei wanted.
- */
- if ((oia = in6_ifaddr) != NULL) {
- for (; oia->ia_next; oia = oia->ia_next)
- continue;
- oia->ia_next = ia;
- } else
- in6_ifaddr = ia;
-
- ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
- ia->ia_prefixmask.sin6_family = AF_INET6;
- ia->ia_prefixmask.sin6_addr = in6mask64;
-
- bzero(&ia->ia_addr, sizeof(struct sockaddr_in6));
- 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;
-
- switch (type) {
- case IN6_IFT_LOOP:
- ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
- ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
- break;
- case IN6_IFT_802:
- ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
- ia->ia_ifa.ifa_flags |= RTF_CLONING;
- rtflag = RTF_CLONING;
- /* fall through */
- case IN6_IFT_P2P802:
- if (laddr == NULL)
- break;
- /* XXX use laddrlen */
- if (laddr_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8],
- laddr, 6) != 0) {
- break;
- }
- /* invert u bit to convert EUI64 to RFC2373 interface ID. */
- ia->ia_addr.sin6_addr.s6_addr8[8] ^= 0x02;
- if (found_first_ifid == 0) {
- if (in6_ifattach_getifid(ifp) == 0)
- in6_ifattach_p2p();
- }
- break;
- case IN6_IFT_P2P:
- bcopy((caddr_t)first_ifid,
- (caddr_t)&ia->ia_addr.sin6_addr.s6_addr8[8],
- IFID_LEN);
- break;
- case IN6_IFT_ARCNET:
- ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
- ia->ia_ifa.ifa_flags |= RTF_CLONING;
- rtflag = RTF_CLONING;
- if (laddr == NULL)
- break;
-
- /* make non-global IF id out of link-level address */
- bzero(&ia->ia_addr.sin6_addr.s6_addr8[8], 7);
- ia->ia_addr.sin6_addr.s6_addr8[15] = *laddr;
+ if ((ifp->if_flags & IFF_MULTICAST) == 0) {
+ printf("%s: not multicast capable, IPv6 not enabled\n",
+ if_name(ifp));
+ return;
}
- ia->ia_ifa.ifa_metric = ifp->if_metric;
-
- if (ifp->if_ioctl != NULL) {
- int s;
- int error;
-
- /*
- * give the interface a chance to initialize, in case this
- * is the first address to be added.
- */
- s = splimp();
- error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
- splx(s);
+ /*
+ * 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 (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;
- }
+ if (ia == NULL) {
+ printf("%s: failed to add link-local address",
+ if_name(ifp));
- /* undo changes */
- TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
- if (oia)
- oia->ia_next = ia->ia_next;
- else
- in6_ifaddr = ia->ia_next;
- free(ia, M_IFADDR);
- return;
+ /* we can't initialize multicasts without link-local */
+ goto statinit;
}
}
- /* add route to the interface. */
- rtrequest(RTM_ADD,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&ia->ia_prefixmask,
- RTF_UP|rtflag,
- (struct rtentry **)0);
- ia->ia_flags |= IFA_ROUTE;
-
- if (type == IN6_IFT_P2P || type == IN6_IFT_P2P802) {
+ if (ifp->if_flags & IFF_POINTOPOINT) {
/*
* route local address to loopback
*/
@@ -507,45 +807,30 @@ in6_ifattach(ifp, type, laddr, noloop)
}
/*
- * loopback address
+ * assign loopback address for loopback interface
+ * XXX multiple loopback interface case
*/
- ib = (struct in6_ifaddr *)NULL;
- if (type == IN6_IFT_LOOP) {
- ib = (struct in6_ifaddr *)
- malloc(sizeof(*ib), M_IFADDR, M_WAITOK);
- bzero((caddr_t)ib, sizeof(*ib));
- ib->ia_ifa.ifa_addr = (struct sockaddr *)&ib->ia_addr;
- ib->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ib->ia_dstaddr;
- ib->ia_ifa.ifa_netmask = (struct sockaddr *)&ib->ia_prefixmask;
- ib->ia_ifp = ifp;
-
- ia->ia_next = ib;
- TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ib,
- ifa_list);
-
- ib->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
- ib->ia_prefixmask.sin6_family = AF_INET6;
- ib->ia_prefixmask.sin6_addr = in6mask128;
- ib->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
- ib->ia_addr.sin6_family = AF_INET6;
- ib->ia_addr.sin6_addr = in6addr_loopback;
- ib->ia_ifa.ifa_metric = ifp->if_metric;
-
- rtrequest(RTM_ADD,
- (struct sockaddr *)&ib->ia_addr,
- (struct sockaddr *)&ib->ia_addr,
- (struct sockaddr *)&ib->ia_prefixmask,
- RTF_UP|RTF_HOST,
- (struct rtentry **)0);
+ in6 = in6addr_loopback;
+ if (ifp->if_flags & IFF_LOOPBACK) {
+ if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
+ if (in6_ifattach_loopback(ifp) != 0)
+ return;
+ }
+ }
- ib->ia_flags |= IFA_ROUTE;
+#ifdef DIAGNOSTIC
+ if (!ia) {
+ panic("ia == NULL in in6_ifattach");
+ /*NOTREACHED*/
}
+#endif
/*
* join multicast
*/
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);
@@ -560,41 +845,53 @@ in6_ifattach(ifp, type, laddr, noloop)
mltaddr.sin6_family = AF_INET6;
mltaddr.sin6_addr = in6addr_linklocal_allnodes;
mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
- 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 (type == IN6_IFT_LOOP) {
- /*
- * join node-local all-nodes address
- */
- mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
+ IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
+ if (in6m == NULL) {
rtrequest(RTM_ADD,
(struct sockaddr *)&mltaddr,
- (struct sockaddr *)&ib->ia_addr,
+ (struct sockaddr *)&ia->ia_addr,
(struct sockaddr *)&mltmask,
- RTF_UP,
+ RTF_UP|RTF_CLONING, /* xxx */
(struct rtentry **)0);
(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
- } else {
+ }
+
+ /*
+ * 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 solicited multicast address
+ * join node-local all-nodes address, on loopback
*/
- 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);
+ 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);
+ }
}
}
+statinit:;
+
/* update dynamically. */
if (in6_maxmtu < ifp->if_mtu)
in6_maxmtu = ifp->if_mtu;
@@ -612,39 +909,44 @@ in6_ifattach(ifp, type, laddr, noloop)
/* initialize NDP variables */
nd6_ifattach(ifp);
-
- /* mark the address TENTATIVE, if needed. */
- switch (ifp->if_type) {
- case IFT_ARCNET:
- case IFT_ETHER:
- case IFT_FDDI:
- ia->ia6_flags |= IN6_IFF_TENTATIVE;
- /* nd6_dad_start() will be called in in6_if_up */
- break;
-#ifdef IFT_DUMMY
- case IFT_DUMMY:
-#endif
- case IFT_GIF: /*XXX*/
- case IFT_LOOP:
- case IFT_FAITH:
- default:
- break;
- }
-
- return;
}
+/*
+ * NOTE: in6_ifdetach() does not support loopback if at this moment.
+ */
void
in6_ifdetach(ifp)
struct ifnet *ifp;
{
struct in6_ifaddr *ia, *oia;
- struct ifaddr *ifa;
+ struct ifaddr *ifa, *next;
struct rtentry *rt;
short rtflags;
+ struct sockaddr_in6 sin6;
+ struct in6_multi *in6m;
+ struct in6_multi *in6m_next;
- TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
+ /* nuke prefix list. this may try to remove some of ifaddrs as well */
+ in6_purgeprefix(ifp);
+
+ /* remove neighbor management table */
+ nd6_purge(ifp);
+
+ /* nuke any of IPv6 addresses we have */
+ for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
{
+ next = ifa->ifa_list.tqe_next;
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ in6_purgeaddr(ifa, ifp);
+ }
+
+ /* undo everything done by in6_ifattach(), just in case */
+ for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
+ {
+ next = ifa->ifa_list.tqe_next;
+
+
if (ifa->ifa_addr->sa_family != AF_INET6
|| !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
continue;
@@ -666,6 +968,7 @@ in6_ifdetach(ifp)
/* remove from the linked list */
TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
+ IFAFREE(&ia->ia_ifa);
/* also remove from the IPv6 address chain(itojun&jinmei) */
oia = ia;
@@ -676,13 +979,38 @@ in6_ifdetach(ifp)
ia = ia->ia_next;
if (ia->ia_next)
ia->ia_next = oia->ia_next;
-#ifdef DEBUG
+#ifdef ND6_DEBUG
else
printf("%s: didn't unlink in6ifaddr from "
"list\n", if_name(ifp));
#endif
}
- free(ia, M_IFADDR);
+ IFAFREE(&oia->ia_ifa);
+ }
+
+ /* leave from all multicast groups joined */
+ for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) {
+ in6m_next = LIST_NEXT(in6m, in6m_entry);
+ if (in6m->in6m_ifp != ifp)
+ continue;
+ in6_delmulti(in6m);
+ in6m = NULL;
+ }
+
+ /* remove neighbor management table */
+ nd6_purge(ifp);
+
+ /* remove route to link-local allnodes multicast (ff02::1) */
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = in6addr_linklocal_allnodes;
+ sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
+ if ((rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL)) != NULL)
+ {
+ rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
+ rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
+ rtfree(rt);
}
}
diff --git a/sys/netinet6/in6_ifattach.h b/sys/netinet6/in6_ifattach.h
index 03dbac7d02ef..4f82e4153085 100644
--- a/sys/netinet6/in6_ifattach.h
+++ b/sys/netinet6/in6_ifattach.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6_ifattach.h,v 1.10 2000/05/27 02:57:05 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,26 +28,16 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _NETINET6_IN6_IFATTACH_H_
-#define _NETINET6_IN6_IFATTACH_H_
+#define _NETINET6_IN6_IFATTACH_H_
#ifdef _KERNEL
-extern int found_first_ifid;
-
-int in6_ifattach_getifid __P((struct ifnet *));
-void in6_ifattach_p2p __P((void));
-void in6_ifattach __P((struct ifnet *, u_int, caddr_t, int));
-void in6_ifdetach __P((struct ifnet *));
+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 *));
#endif /* _KERNEL */
-#define IN6_IFT_LOOP 1
-#define IN6_IFT_P2P 2
-#define IN6_IFT_802 3
-#define IN6_IFT_P2P802 4
-#define IN6_IFT_ARCNET 5
-
#endif /* _NETINET6_IN6_IFATTACH_H_ */
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 73c169b1baeb..bc7b0cd8c3fe 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6_pcb.c,v 1.8 2000/06/09 00:37:02 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -26,7 +29,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
/*
@@ -62,7 +64,6 @@
* SUCH DAMAGE.
*
* @(#)in_pcb.c 8.2 (Berkeley) 1/4/94
- * $FreeBSD$
*/
#include "opt_ipsec.h"
@@ -90,7 +91,7 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/in_systm.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet/ip_var.h>
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
@@ -105,11 +106,6 @@
#include <netinet6/ipsec6.h>
#include <netinet6/ah6.h>
#include <netkey/key.h>
-#ifdef IPSEC_DEBUG
-#include <netkey/key_debug.h>
-#else
-#define KEYDEBUG(lev,arg)
-#endif /* IPSEC_DEBUG */
#endif /* IPSEC */
struct in6_addr zeroin6_addr;
@@ -121,12 +117,10 @@ in6_pcbbind(inp, nam, p)
struct proc *p;
{
struct socket *so = inp->inp_socket;
- unsigned short *lastport;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL;
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
u_short lport = 0;
int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
- int error;
if (!in6_ifaddr) /* XXX broken! */
return (EADDRNOTAVAIL);
@@ -144,36 +138,11 @@ in6_pcbbind(inp, nam, p)
if (nam->sa_family != AF_INET6)
return(EAFNOSUPPORT);
- /*
- * If the scope of the destination is link-local, embed the
- * interface index in the address.
- */
- if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
- /* XXX boundary check is assumed to be already done. */
- /* XXX sin6_scope_id is weaker than advanced-api. */
- struct in6_pktinfo *pi;
- if (inp->in6p_outputopts &&
- (pi = inp->in6p_outputopts->ip6po_pktinfo) &&
- pi->ipi6_ifindex) {
- sin6->sin6_addr.s6_addr16[1]
- = htons(pi->ipi6_ifindex);
- } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)
- && inp->in6p_moptions
- && inp->in6p_moptions->im6o_multicast_ifp) {
- sin6->sin6_addr.s6_addr16[1] =
- htons(inp->in6p_moptions->im6o_multicast_ifp->if_index);
- } else if (sin6->sin6_scope_id) {
- /* boundary check */
- if (sin6->sin6_scope_id < 0
- || if_index < sin6->sin6_scope_id) {
- return ENXIO; /* XXX EINVAL? */
- }
- sin6->sin6_addr.s6_addr16[1]
- = htons(sin6->sin6_scope_id & 0xffff);/*XXX*/
- /* this must be cleared for ifa_ifwithaddr() */
- sin6->sin6_scope_id = 0;
- }
- }
+ /* KAME hack: embed scopeid */
+ if (in6_embedscope(&sin6->sin6_addr, sin6, inp, NULL) != 0)
+ return EINVAL;
+ /* this must be cleared for ifa_ifwithaddr() */
+ sin6->sin6_scope_id = 0;
lport = sin6->sin6_port;
if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
@@ -224,7 +193,7 @@ in6_pcbbind(inp, nam, p)
(so->so_cred->cr_uid !=
t->inp_socket->so_cred->cr_uid))
return (EADDRINUSE);
- if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0 &&
+ if (ip6_mapped_addr_on != 0 &&
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
@@ -246,7 +215,7 @@ in6_pcbbind(inp, nam, p)
lport, wild);
if (t && (reuseport & t->inp_socket->so_options) == 0)
return(EADDRINUSE);
- if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0 &&
+ if (ip6_mapped_addr_on != 0 &&
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
@@ -266,82 +235,17 @@ in6_pcbbind(inp, nam, p)
inp->in6p_laddr = sin6->sin6_addr;
}
if (lport == 0) {
- ushort first, last;
- int count;
-
- inp->inp_flags |= INP_ANONPORT;
-
- if (inp->inp_flags & INP_HIGHPORT) {
- first = ipport_hifirstauto; /* sysctl */
- last = ipport_hilastauto;
- lastport = &pcbinfo->lasthi;
- } else if (inp->inp_flags & INP_LOWPORT) {
- if (p && (error = suser_xxx(0, p, PRISON_ROOT)))
- return error;
- first = ipport_lowfirstauto; /* 1023 */
- last = ipport_lowlastauto; /* 600 */
- lastport = &pcbinfo->lastlow;
- } else {
- first = ipport_firstauto; /* sysctl */
- last = ipport_lastauto;
- lastport = &pcbinfo->lastport;
- }
- /*
- * Simple check to ensure all ports are not used up causing
- * a deadlock here.
- *
- * We split the two cases (up and down) so that the direction
- * is not being tested on each round of the loop.
- */
- if (first > last) {
- /*
- * counting down
- */
- count = first - last;
-
- do {
- if (count-- < 0) { /* completely used? */
- /*
- * Undo any address bind that may have
- * occurred above.
- */
- inp->in6p_laddr = in6addr_any;
- return (EAGAIN);
- }
- --*lastport;
- if (*lastport > first || *lastport < last)
- *lastport = first;
- lport = htons(*lastport);
- } while (in6_pcblookup_local(pcbinfo,
- &inp->in6p_laddr, lport, wild));
- } else {
- /*
- * counting up
- */
- count = last - first;
-
- do {
- if (count-- < 0) { /* completely used? */
- /*
- * Undo any address bind that may have
- * occurred above.
- */
- inp->in6p_laddr = in6addr_any;
- return (EAGAIN);
- }
- ++*lastport;
- if (*lastport < first || *lastport > last)
- *lastport = first;
- lport = htons(*lastport);
- } while (in6_pcblookup_local(pcbinfo,
- &inp->in6p_laddr, lport, wild));
- }
+ int e;
+ if ((e = in6_pcbsetport(&inp->in6p_laddr, inp, p)) != 0)
+ return(e);
}
- inp->inp_lport = lport;
- if (in_pcbinshash(inp) != 0) {
- inp->in6p_laddr = in6addr_any;
- inp->inp_lport = 0;
- return (EAGAIN);
+ else {
+ inp->inp_lport = lport;
+ if (in_pcbinshash(inp) != 0) {
+ inp->in6p_laddr = in6addr_any;
+ inp->inp_lport = 0;
+ return (EAGAIN);
+ }
}
inp->in6p_flowinfo = sin6 ? sin6->sin6_flowinfo : 0; /*XXX*/
return(0);
@@ -377,35 +281,9 @@ in6_pcbladdr(inp, nam, plocal_addr6)
if (sin6->sin6_port == 0)
return (EADDRNOTAVAIL);
- /*
- * If the scope of the destination is link-local, embed the interface
- * index in the address.
- */
- if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
- /* XXX boundary check is assumed to be already done. */
- /* XXX sin6_scope_id is weaker than advanced-api. */
- if (inp->in6p_outputopts &&
- (pi = inp->in6p_outputopts->ip6po_pktinfo) &&
- pi->ipi6_ifindex) {
- sin6->sin6_addr.s6_addr16[1] = htons(pi->ipi6_ifindex);
- ifp = ifindex2ifnet[pi->ipi6_ifindex];
- } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) &&
- inp->in6p_moptions &&
- inp->in6p_moptions->im6o_multicast_ifp) {
- sin6->sin6_addr.s6_addr16[1] =
- htons(inp->in6p_moptions->im6o_multicast_ifp->if_index);
- ifp = ifindex2ifnet[inp->in6p_moptions->im6o_multicast_ifp->if_index];
- } else if (sin6->sin6_scope_id) {
- /* boundary check */
- if (sin6->sin6_scope_id < 0
- || if_index < sin6->sin6_scope_id) {
- return ENXIO; /* XXX EINVAL? */
- }
- sin6->sin6_addr.s6_addr16[1]
- = htons(sin6->sin6_scope_id & 0xffff);/*XXX*/
- ifp = ifindex2ifnet[sin6->sin6_scope_id];
- }
- }
+ /* KAME hack: embed scopeid */
+ if (in6_embedscope(&sin6->sin6_addr, sin6, inp, &ifp) != 0)
+ return EINVAL;
if (in6_ifaddr) {
/*
@@ -440,8 +318,6 @@ in6_pcbladdr(inp, nam, plocal_addr6)
if (inp->in6p_route.ro_rt)
ifp = inp->in6p_route.ro_rt->rt_ifp;
- inp->in6p_ip6_hlim = (u_int8_t)in6_selecthlim(inp, ifp);
-
return(0);
}
@@ -499,6 +375,7 @@ in6_pcbconnect(inp, nam, p)
return (0);
}
+#if 0
/*
* Return an IPv6 address, which is the most appropriate for given
* destination and user specified options.
@@ -699,6 +576,7 @@ in6_selecthlim(in6p, ifp)
else
return(ip6_defhlim);
}
+#endif
void
in6_pcbdisconnect(inp)
@@ -891,10 +769,11 @@ in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
int cmd;
void (*notify) __P((struct inpcb *, int));
{
- struct inpcb *inp, *oinp;
+ struct inpcb *inp, *ninp;
struct in6_addr faddr6;
u_short fport = fport_arg, lport = lport_arg;
int errno, s;
+ int do_rtchange = (notify == in6_rtchange);
if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6)
return;
@@ -904,8 +783,9 @@ in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
/*
* Redirects go to all references to the destination,
- * and use in_rtchange to invalidate the route cache.
- * Dead host indications: notify all references to the destination.
+ * and use in6_rtchange to invalidate the route cache.
+ * Dead host indications: also use in6_rtchange to invalidate
+ * the cache, and deliver the error to all the sockets.
* Otherwise, if we have knowledge of the local port and address,
* deliver only to that socket.
*/
@@ -913,29 +793,43 @@ in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
fport = 0;
lport = 0;
bzero((caddr_t)laddr6, sizeof(*laddr6));
- if (cmd != PRC_HOSTDEAD)
- notify = in6_rtchange;
+
+ do_rtchange = 1;
}
errno = inet6ctlerrmap[cmd];
s = splnet();
- for (inp = LIST_FIRST(head); inp != NULL;) {
- if ((inp->inp_vflag & INP_IPV6) == 0) {
- inp = LIST_NEXT(inp, inp_list);
+ for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) {
+ ninp = LIST_NEXT(inp, inp_list);
+
+ if ((inp->inp_vflag & INP_IPV6) == NULL)
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)) {
- inp = LIST_NEXT(inp, inp_list);
+ (fport && inp->inp_fport != fport))
continue;
- }
- oinp = inp;
- inp = LIST_NEXT(inp, inp_list);
+
if (notify)
- (*notify)(oinp, errno);
+ (*notify)(inp, errno);
}
splx(s);
}
diff --git a/sys/netinet6/in6_pcb.h b/sys/netinet6/in6_pcb.h
index 6c59574566ad..2ea310728a17 100644
--- a/sys/netinet6/in6_pcb.h
+++ b/sys/netinet6/in6_pcb.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6_pcb.h,v 1.5 2000/07/03 06:19:53 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -26,7 +29,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
/*
@@ -100,9 +102,14 @@ struct in6_addr *in6_selectsrc __P((struct sockaddr_in6 *,
struct ip6_moptions *,
struct route_in6 *,
struct in6_addr *, int *));
-int in6_selecthlim __P((struct inpcb *, struct ifnet *));
-
+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 a32399100a54..b75a72fed1d1 100644
--- a/sys/netinet6/in6_prefix.c
+++ b/sys/netinet6/in6_prefix.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6_prefix.c,v 1.30 2000/06/12 14:53:17 jinmei Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -78,7 +79,7 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/in6_prefix.h>
#include <netinet6/ip6_var.h>
@@ -91,11 +92,10 @@ struct rr_prhead rr_prefix;
static void add_each_addr __P((struct socket *so, struct rr_prefix *rpp,
struct rp_addr *rap));
-static int create_ra_entry __P((struct rp_addr **rapp));
-static int add_each_prefix __P((struct socket *so,
- struct rr_prefix *rpp));
-static void free_rp_entries __P((struct rr_prefix *rpp));
-static int link_stray_ia6s __P((struct rr_prefix *rpp));
+static int create_ra_entry __P((struct rp_addr **rapp));
+static int add_each_prefix __P((struct socket *so, struct rr_prefix *rpp));
+static void free_rp_entries __P((struct rr_prefix *rpp));
+static int link_stray_ia6s __P((struct rr_prefix *rpp));
static void rp_remove __P((struct rr_prefix *rpp));
/*
@@ -155,7 +155,8 @@ in6_prefixwithifp(struct ifnet *ifp, int plen, struct in6_addr *dst)
/* search matched prefix */
for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
- ifpr = TAILQ_NEXT(ifpr, ifpr_list)) {
+ ifpr = TAILQ_NEXT(ifpr, ifpr_list))
+ {
if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
ifpr->ifpr_type != IN6_PREFIX_RR)
continue;
@@ -203,7 +204,8 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr)
return rpp;
for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
- ifpr = TAILQ_NEXT(ifpr, ifpr_list)) {
+ ifpr = TAILQ_NEXT(ifpr, ifpr_list))
+ {
if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
ifpr->ifpr_type != IN6_PREFIX_RR)
continue;
@@ -213,7 +215,7 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr)
}
if (ifpr != NULL)
log(LOG_ERR, "in6_prefix.c: search_matched_prefix: addr %s"
- "has no pointer to prefix %s", ip6_sprintf(IFA_IN6(ifa)),
+ "has no pointer to prefix %s\n", ip6_sprintf(IFA_IN6(ifa)),
ip6_sprintf(IFPR_IN6(ifpr)));
return ifpr2rp(ifpr);
}
@@ -232,7 +234,8 @@ mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr)
/* search matched prefixes */
for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
- ifpr = TAILQ_NEXT(ifpr, ifpr_list)) {
+ ifpr = TAILQ_NEXT(ifpr, ifpr_list))
+ {
if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
ifpr->ifpr_type != IN6_PREFIX_RR)
continue;
@@ -272,7 +275,7 @@ mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr)
} else
log(LOG_WARNING, "in6_prefix.c: mark_matched_prefixes:"
"no back pointer to ifprefix for %s. "
- "ND autoconfigured addr?",
+ "ND autoconfigured addr?\n",
ip6_sprintf(IFA_IN6(ifa)));
}
return matched;
@@ -288,7 +291,8 @@ delmark_global_prefixes(struct ifnet *ifp, struct in6_rrenumreq *irr)
/* search matched prefixes */
for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
- ifpr = TAILQ_NEXT(ifpr, ifpr_list)) {
+ ifpr = TAILQ_NEXT(ifpr, ifpr_list))
+ {
if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
ifpr->ifpr_type != IN6_PREFIX_RR)
continue;
@@ -307,7 +311,8 @@ unmark_prefixes(struct ifnet *ifp)
/* unmark all prefix */
for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
- ifpr = TAILQ_NEXT(ifpr, ifpr_list)) {
+ ifpr = TAILQ_NEXT(ifpr, ifpr_list))
+ {
if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
ifpr->ifpr_type != IN6_PREFIX_RR)
continue;
@@ -320,6 +325,7 @@ unmark_prefixes(struct ifnet *ifp)
static void
init_prefix_ltimes(struct rr_prefix *rpp)
{
+
if (rpp->rp_pltime == RR_INFINITE_LIFETIME ||
rpp->rp_rrf_decrprefd == 0)
rpp->rp_preferred = 0;
@@ -368,15 +374,17 @@ search_ifidwithprefix(struct rr_prefix *rpp, struct in6_addr *ifid)
struct rp_addr *rap;
LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry)
+ {
if (rr_are_ifid_equal(ifid, &rap->ra_ifid,
(sizeof(struct in6_addr) << 3) -
rpp->rp_plen))
break;
+ }
return rap;
}
static int
-assigne_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia)
+assign_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia)
{
int error = 0;
struct rp_addr *rap;
@@ -391,10 +399,10 @@ assigne_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;
- /*
- * Can't point rp2ifpr(rpp) from ia->ia6_ifpr now,
- * because rpp may be on th stack. should fix it?
- */
+ rap->ra_addr->ia_ifa.ifa_refcnt++;
+#if 0 /* Can't do this now, because rpp may be on th stack. should fix it? */
+ ia->ia6_ifpr = rp2ifpr(rpp);
+#endif
s = splnet();
LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
splx(s);
@@ -402,6 +410,10 @@ assigne_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia)
return 0;
}
+/*
+ * add a link-local address to an interface. we will add new interface address
+ * (prefix database + new interface id).
+ */
static int
in6_prefix_add_llifid(int iilen, struct in6_ifaddr *ia)
{
@@ -419,7 +431,14 @@ in6_prefix_add_llifid(int iilen, struct in6_ifaddr *ia)
/* XXX: init dummy so */
bzero(&so, sizeof(so));
/* insert into list */
- LIST_FOREACH(rpp, &rr_prefix, rp_entry) {
+ LIST_FOREACH(rpp, &rr_prefix, rp_entry)
+ {
+ /*
+ * do not attempt to add an address, if ifp does not match
+ */
+ if (rpp->rp_ifp != ia->ia_ifp)
+ continue;
+
s = splnet();
LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
splx(s);
@@ -428,7 +447,10 @@ in6_prefix_add_llifid(int iilen, struct in6_ifaddr *ia)
return 0;
}
-
+/*
+ * add an address to an interface. if the interface id portion is new,
+ * we will add new interface address (prefix database + new interface id).
+ */
int
in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
{
@@ -490,12 +512,13 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
}
rap = search_ifidwithprefix(ifpr2rp(ifpr), IA6_IN6(ia));
if (rap != NULL) {
- if (rap->ra_addr == NULL)
+ if (rap->ra_addr == NULL) {
rap->ra_addr = ia;
- else if (rap->ra_addr != ia) {
+ rap->ra_addr->ia_ifa.ifa_refcnt++;
+ } 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",
+ "has already 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)));
@@ -504,7 +527,7 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
ia->ia6_ifpr = ifpr;
return 0;
}
- error = assigne_ra_entry(ifpr2rp(ifpr), iilen, ia);
+ error = assign_ra_entry(ifpr2rp(ifpr), iilen, ia);
if (error == 0)
ia->ia6_ifpr = ifpr;
return (error);
@@ -522,12 +545,33 @@ in6_prefix_remove_ifid(int iilen, struct in6_ifaddr *ia)
int s = splnet();
LIST_REMOVE(rap, ra_entry);
splx(s);
+ if (rap->ra_addr)
+ IFAFREE(&rap->ra_addr->ia_ifa);
free(rap, M_RR_ADDR);
}
+
if (LIST_EMPTY(&ifpr2rp(ia->ia6_ifpr)->rp_addrhead))
rp_remove(ifpr2rp(ia->ia6_ifpr));
}
+void
+in6_purgeprefix(ifp)
+ struct ifnet *ifp;
+{
+ struct ifprefix *ifpr, *nextifpr;
+
+ /* delete prefixes before ifnet goes away */
+ for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
+ ifpr = nextifpr)
+ {
+ nextifpr = TAILQ_NEXT(ifpr, ifpr_list);
+ if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
+ ifpr->ifpr_type != IN6_PREFIX_RR)
+ continue;
+ (void)delete_each_prefix(ifpr2rp(ifpr), PR_ORIG_KERNEL);
+ }
+}
+
static void
add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap)
{
@@ -559,12 +603,16 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap)
if (ia6 != NULL) {
if (ia6->ia6_ifpr == NULL) {
/* link this addr and the prefix each other */
+ IFAFREE(&rap->ra_addr->ia_ifa);
rap->ra_addr = ia6;
+ rap->ra_addr->ia_ifa.ifa_refcnt++;
ia6->ia6_ifpr = rp2ifpr(rpp);
return;
}
if (ia6->ia6_ifpr == rp2ifpr(rpp)) {
+ IFAFREE(&rap->ra_addr->ia_ifa);
rap->ra_addr = ia6;
+ rap->ra_addr->ia_ifa.ifa_refcnt++;
return;
}
/*
@@ -578,7 +626,7 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap)
* 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",
+ "%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));
@@ -588,10 +636,10 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap)
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);
+ 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",
+ "%s/%d failed because in6_control failed for error %d\n",
ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen,
error);
return;
@@ -612,7 +660,8 @@ rrpr_update(struct socket *so, struct rr_prefix *new)
/* search existing prefix */
for (ifpr = TAILQ_FIRST(&new->rp_ifp->if_prefixhead); ifpr;
- ifpr = TAILQ_NEXT(ifpr, ifpr_list)) {
+ ifpr = TAILQ_NEXT(ifpr, ifpr_list))
+ {
if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
ifpr->ifpr_type != IN6_PREFIX_RR)
continue;
@@ -653,6 +702,8 @@ rrpr_update(struct socket *so, struct rr_prefix *new)
LIST_REMOVE(rap, ra_entry);
if (search_ifidwithprefix(rpp, &rap->ra_ifid)
!= NULL) {
+ if (rap->ra_addr)
+ IFAFREE(&rap->ra_addr->ia_ifa);
free(rap, M_RR_ADDR);
continue;
}
@@ -669,7 +720,7 @@ rrpr_update(struct socket *so, struct rr_prefix *new)
M_NOWAIT);
if (rpp == NULL) {
log(LOG_ERR, "in6_prefix.c: rrpr_update:%d"
- ": ENOBUFS for rr_prefix", __LINE__);
+ ": ENOBUFS for rr_prefix\n", __LINE__);
return(ENOBUFS);
}
/* initilization */
@@ -685,7 +736,7 @@ rrpr_update(struct socket *so, struct rr_prefix *new)
/* let rp_ifpr.ifpr_prefix point rr_prefix. */
rpp->rp_ifpr.ifpr_prefix = (struct sockaddr *)&rpp->rp_prefix;
- /* link rr_prefix entry to if_prefixhead */
+ /* link rr_prefix entry to if_prefixlist */
{
struct ifnet *ifp = rpp->rp_ifp;
struct ifprefix *ifpr;
@@ -715,7 +766,8 @@ rrpr_update(struct socket *so, struct rr_prefix *new)
* If it existed but not pointing to the prefix yet,
* init the prefix pointer.
*/
- LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry) {
+ LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry)
+ {
if (rap->ra_addr != NULL) {
if (rap->ra_addr->ia6_ifpr == NULL)
rap->ra_addr->ia6_ifpr = rp2ifpr(rpp);
@@ -739,7 +791,7 @@ rp_remove(struct rr_prefix *rpp)
int s;
s = splnet();
- /* unlink rp_entry from if_prefixhead */
+ /* unlink rp_entry from if_prefixlist */
{
struct ifnet *ifp = rpp->rp_ifp;
struct ifprefix *ifpr;
@@ -754,8 +806,8 @@ rp_remove(struct rr_prefix *rpp)
if (TAILQ_NEXT(ifpr, ifpr_list))
TAILQ_NEXT(ifpr, ifpr_list) =
TAILQ_NEXT(rp2ifpr(rpp), ifpr_list);
- else
- printf("Couldn't unlink rr_prefix from ifp\n");
+ else
+ printf("Couldn't unlink rr_prefix from ifp\n");
}
}
/* unlink rp_entry from rr_prefix list */
@@ -771,7 +823,7 @@ create_ra_entry(struct rp_addr **rapp)
M_NOWAIT);
if (*rapp == NULL) {
log(LOG_ERR, "in6_prefix.c: init_newprefix:%d: ENOBUFS"
- "for rp_addr", __LINE__);
+ "for rp_addr\n", __LINE__);
return ENOBUFS;
}
bzero(*rapp, sizeof(*(*rapp)));
@@ -803,7 +855,8 @@ init_newprefix(struct in6_rrenumreq *irr, struct ifprefix *ifpr,
irr->irr_u_uselen,
min(ifpr->ifpr_plen - irr->irr_u_uselen,
irr->irr_u_keeplen));
- LIST_FOREACH(orap, &(ifpr2rp(ifpr)->rp_addrhead), ra_entry) {
+ LIST_FOREACH(orap, &(ifpr2rp(ifpr)->rp_addrhead), ra_entry)
+ {
struct rp_addr *rap;
int error = 0;
@@ -841,6 +894,8 @@ free_rp_entries(struct rr_prefix *rpp)
rap = LIST_FIRST(&rpp->rp_addrhead);
LIST_REMOVE(rap, ra_entry);
+ if (rap->ra_addr)
+ IFAFREE(&rap->ra_addr->ia_ifa);
free(rap, M_RR_ADDR);
}
}
@@ -854,7 +909,8 @@ add_useprefixes(struct socket *so, struct ifnet *ifp,
int error = 0;
/* add prefixes to each of marked prefix */
- for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr) {
+ for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr)
+ {
nextifpr = TAILQ_NEXT(ifpr, ifpr_list);
if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
ifpr->ifpr_type != IN6_PREFIX_RR)
@@ -876,7 +932,8 @@ unprefer_prefix(struct rr_prefix *rpp)
{
struct rp_addr *rap;
- LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry) {
+ for (rap = rpp->rp_addrhead.lh_first; rap != NULL;
+ rap = rap->ra_entry.le_next) {
if (rap->ra_addr == NULL)
continue;
rap->ra_addr->ia6_lifetime.ia6t_preferred = time_second;
@@ -885,15 +942,14 @@ unprefer_prefix(struct rr_prefix *rpp)
}
int
-delete_each_prefix(struct socket *so, struct rr_prefix *rpp, u_char origin)
+delete_each_prefix(struct rr_prefix *rpp, u_char origin)
{
- struct in6_aliasreq ifra;
int error = 0;
if (rpp->rp_origin > origin)
return(EPERM);
- while (!LIST_EMPTY(&rpp->rp_addrhead)) {
+ while (rpp->rp_addrhead.lh_first != NULL) {
struct rp_addr *rap;
int s;
@@ -909,22 +965,8 @@ delete_each_prefix(struct socket *so, struct rr_prefix *rpp, u_char origin)
}
rap->ra_addr->ia6_ifpr = NULL;
- bzero(&ifra, sizeof(ifra));
- strncpy(ifra.ifra_name, if_name(rpp->rp_ifp),
- sizeof(ifra.ifra_name));
- ifra.ifra_addr = rap->ra_addr->ia_addr;
- ifra.ifra_dstaddr = rap->ra_addr->ia_dstaddr;
- ifra.ifra_prefixmask = rap->ra_addr->ia_prefixmask;
-
- error = in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra,
- rpp->rp_ifp, curproc);
- if (error != 0)
- log(LOG_ERR, "in6_prefix.c: delete_each_prefix:"
- "deletion of an addr %s/%d failed because"
- "in6_control failed for error %d",
- ip6_sprintf(&ifra.ifra_addr.sin6_addr),
- rpp->rp_plen, error);
-
+ in6_purgeaddr(&rap->ra_addr->ia_ifa, rpp->rp_ifp);
+ IFAFREE(&rap->ra_addr->ia_ifa);
free(rap, M_RR_ADDR);
}
rp_remove(rpp);
@@ -933,18 +975,19 @@ delete_each_prefix(struct socket *so, struct rr_prefix *rpp, u_char origin)
}
static void
-delete_prefixes(struct socket *so, struct ifnet *ifp, u_char origin)
+delete_prefixes(struct ifnet *ifp, u_char origin)
{
struct ifprefix *ifpr, *nextifpr;
/* delete prefixes marked as tobe deleted */
- for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr) {
+ for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr)
+ {
nextifpr = TAILQ_NEXT(ifpr, ifpr_list);
if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
ifpr->ifpr_type != IN6_PREFIX_RR)
continue;
if (ifpr2rp(ifpr)->rp_statef_delmark)
- (void)delete_each_prefix(so, ifpr2rp(ifpr), origin);
+ (void)delete_each_prefix(ifpr2rp(ifpr), origin);
}
}
@@ -953,7 +996,8 @@ link_stray_ia6s(struct rr_prefix *rpp)
{
struct ifaddr *ifa;
- TAILQ_FOREACH(ifa, &rpp->rp_ifp->if_addrlist, ifa_list)
+ for (ifa = rpp->rp_ifp->if_addrlist.tqh_first; ifa;
+ ifa = ifa->ifa_list.tqe_next)
{
struct rp_addr *rap;
struct rr_prefix *orpp;
@@ -970,13 +1014,13 @@ link_stray_ia6s(struct rr_prefix *rpp)
rpp->rp_plen))
log(LOG_ERR, "in6_prefix.c: link_stray_ia6s:"
"addr %s/%d already linked to a prefix"
- "and it matches also %s/%d",
+ "and it matches also %s/%d\n",
ip6_sprintf(IFA_IN6(ifa)), orpp->rp_plen,
ip6_sprintf(RP_IN6(rpp)),
rpp->rp_plen);
continue;
}
- if ((error = assigne_ra_entry(rpp,
+ if ((error = assign_ra_entry(rpp,
(sizeof(rap->ra_ifid) << 3) -
rpp->rp_plen,
(struct in6_ifaddr *)ifa)) != 0)
@@ -985,6 +1029,7 @@ link_stray_ia6s(struct rr_prefix *rpp)
return 0;
}
+/* XXX assumes that permission is already checked by the caller */
int
in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
struct ifnet *ifp)
@@ -1013,7 +1058,7 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
if (irr->irr_pltime > irr->irr_vltime) {
log(LOG_NOTICE,
"in6_prefix_ioctl: preferred lifetime"
- "(%ld) is greater than valid lifetime(%ld)",
+ "(%ld) is greater than valid lifetime(%ld)\n",
(u_long)irr->irr_pltime, (u_long)irr->irr_vltime);
error = EINVAL;
break;
@@ -1024,7 +1069,7 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
!= 0)
goto failed;
if (cmd != SIOCAIFPREFIX_IN6)
- delete_prefixes(so, ifp, irr->irr_origin);
+ delete_prefixes(ifp, irr->irr_origin);
} else
return (EADDRNOTAVAIL);
failed:
@@ -1048,7 +1093,7 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
if (ipr->ipr_pltime > ipr->ipr_vltime) {
log(LOG_NOTICE,
"in6_prefix_ioctl: preferred lifetime"
- "(%ld) is greater than valid lifetime(%ld)",
+ "(%ld) is greater than valid lifetime(%ld)\n",
(u_long)ipr->ipr_pltime, (u_long)ipr->ipr_vltime);
error = EINVAL;
break;
@@ -1069,7 +1114,10 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
free_rp_entries(&rp_tmp);
break;
}
- TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
+ for (ifa = ifp->if_addrlist.tqh_first;
+ ifa;
+ ifa = ifa->ifa_list.tqe_next)
+ {
if (ifa->ifa_addr == NULL)
continue; /* just for safety */
if (ifa->ifa_addr->sa_family != AF_INET6)
@@ -1103,7 +1151,7 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
if (rpp == NULL || ifp != rpp->rp_ifp)
return (EADDRNOTAVAIL);
- error = delete_each_prefix(so, rpp, ipr->ipr_origin);
+ error = delete_each_prefix(rpp, ipr->ipr_origin);
break;
}
bad:
@@ -1124,13 +1172,9 @@ in6_rr_timer(void *ignored_arg)
while (rpp) {
if (rpp->rp_expire && rpp->rp_expire < time_second) {
struct rr_prefix *next_rpp;
- struct socket so;
-
- /* XXX: init dummy so */
- bzero(&so, sizeof(so));
next_rpp = LIST_NEXT(rpp, rp_entry);
- delete_each_prefix(&so, rpp, PR_ORIG_KERNEL);
+ delete_each_prefix(rpp, PR_ORIG_KERNEL);
rpp = next_rpp;
continue;
}
diff --git a/sys/netinet6/in6_prefix.h b/sys/netinet6/in6_prefix.h
index fa5a0e35457f..2ce18db551b3 100644
--- a/sys/netinet6/in6_prefix.h
+++ b/sys/netinet6/in6_prefix.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6_prefix.h,v 1.6 2000/03/25 07:23:45 sumikawa Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, 1998 and 1999 WIDE Project.
* All rights reserved.
@@ -25,64 +28,61 @@
* 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.
- *
- * $FreeBSD$
*/
struct rr_prefix {
- struct ifprefix rp_ifpr;
+ struct ifprefix rp_ifpr;
LIST_ENTRY(rr_prefix) rp_entry;
LIST_HEAD(rp_addrhead, rp_addr) rp_addrhead;
- struct sockaddr_in6 rp_prefix; /* prefix */
- u_int32_t rp_vltime; /* advertised valid lifetime */
- u_int32_t rp_pltime; /* advertised preferred lifetime */
- time_t rp_expire; /* expiration time of the prefix */
- time_t rp_preferred; /* preferred time of the prefix */
- struct in6_prflags rp_flags;
+ struct sockaddr_in6 rp_prefix; /* prefix */
+ u_int32_t rp_vltime; /* advertised valid lifetime */
+ u_int32_t rp_pltime; /* advertised preferred lifetime */
+ time_t rp_expire; /* expiration time of the prefix */
+ time_t rp_preferred; /* preferred time of the prefix */
+ struct in6_prflags rp_flags;
u_char rp_origin; /* from where this prefix info is obtained */
struct rp_stateflags {
/* if some prefix should be added to this prefix */
- u_char addmark : 1;
- u_char delmark : 1; /* if this prefix will be deleted */
+ u_char addmark : 1;
+ u_char delmark : 1; /* if this prefix will be deleted */
} rp_stateflags;
};
-#define rp_type rp_ifpr.ifpr_type
-#define rp_ifp rp_ifpr.ifpr_ifp
-#define rp_plen rp_ifpr.ifpr_plen
+#define rp_type rp_ifpr.ifpr_type
+#define rp_ifp rp_ifpr.ifpr_ifp
+#define rp_plen rp_ifpr.ifpr_plen
-#define rp_raf rp_flags.prf_ra
-#define rp_raf_onlink rp_flags.prf_ra.onlink
-#define rp_raf_auto rp_flags.prf_ra.autonomous
+#define rp_raf rp_flags.prf_ra
+#define rp_raf_onlink rp_flags.prf_ra.onlink
+#define rp_raf_auto rp_flags.prf_ra.autonomous
-#define rp_statef_addmark rp_stateflags.addmark
-#define rp_statef_delmark rp_stateflags.delmark
+#define rp_statef_addmark rp_stateflags.addmark
+#define rp_statef_delmark rp_stateflags.delmark
-#define rp_rrf rp_flags.prf_rr
-#define rp_rrf_decrvalid rp_flags.prf_rr.decrvalid
-#define rp_rrf_decrprefd rp_flags.prf_rr.decrprefd
+#define rp_rrf rp_flags.prf_rr
+#define rp_rrf_decrvalid rp_flags.prf_rr.decrvalid
+#define rp_rrf_decrprefd rp_flags.prf_rr.decrprefd
struct rp_addr {
- LIST_ENTRY(rp_addr) ra_entry;
- struct in6_addr ra_ifid;
- struct in6_ifaddr *ra_addr;
- struct ra_flags {
- u_char anycast : 1;
+ LIST_ENTRY(rp_addr) ra_entry;
+ struct in6_addr ra_ifid;
+ struct in6_ifaddr *ra_addr;
+ struct ra_flags {
+ u_char anycast : 1;
} ra_flags;
};
-#define ifpr2rp(ifpr) ((struct rr_prefix *)(ifpr))
-#define rp2ifpr(rp) ((struct ifprefix *)(rp))
+#define ifpr2rp(ifpr) ((struct rr_prefix *)(ifpr))
+#define rp2ifpr(rp) ((struct ifprefix *)(rp))
-#define RP_IN6(rp) (&(rp)->rp_prefix.sin6_addr)
+#define RP_IN6(rp) (&(rp)->rp_prefix.sin6_addr)
-#define RR_INFINITE_LIFETIME 0xffffffff
+#define RR_INFINITE_LIFETIME 0xffffffff
LIST_HEAD(rr_prhead, rr_prefix);
-extern struct rr_prhead rr_prefix;
+extern struct rr_prhead rr_prefix;
-void in6_rr_timer __P((void *));
-int delete_each_prefix __P((struct socket *so, struct rr_prefix *rpp,
- u_char origin));
+void in6_rr_timer __P((void *));
+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 318dcab9234d..8af642f14889 100644
--- a/sys/netinet6/in6_proto.c
+++ b/sys/netinet6/in6_proto.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6_proto.c,v 1.64 2000/06/20 16:20:27 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -65,6 +66,7 @@
*/
#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_ipsec.h"
#include <sys/param.h>
@@ -84,11 +86,12 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
+#include <netinet/ip_encap.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#include <netinet/tcp.h>
#include <netinet/tcp_timer.h>
@@ -96,6 +99,7 @@
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include <netinet6/tcp6_var.h>
+
#include <netinet6/udp6_var.h>
#include <netinet6/pim6_var.h>
@@ -105,13 +109,15 @@
#ifdef IPSEC
#include <netinet6/ipsec.h>
-#include <netinet6/ah.h>
#include <netinet6/ipsec6.h>
+#include <netinet6/ah.h>
#include <netinet6/ah6.h>
#ifdef IPSEC_ESP
#include <netinet6/esp.h>
#include <netinet6/esp6.h>
#endif
+#include <netinet6/ipcomp.h>
+#include <netinet6/ipcomp6.h>
#endif /*IPSEC*/
#include <netinet6/ip6protosw.h>
@@ -129,8 +135,8 @@
* TCP/IP protocol family: IP6, ICMP6, UDP, TCP.
*/
-extern struct domain inet6domain;
-static struct pr_usrreqs nousrreqs;
+extern struct domain inet6domain;
+static struct pr_usrreqs nousrreqs;
struct ip6protosw inet6sw[] = {
{ 0, &inet6domain, IPPROTO_IPV6, 0,
@@ -151,12 +157,12 @@ struct ip6protosw inet6sw[] = {
#ifdef INET /* don't call timeout routines twice */
tcp_init, 0, 0, tcp_drain,
#else
- tcp_init, 0, tcp_slowtimo, tcp_drain,
+ tcp_init, tcp_fasttimo, tcp_slowtimo, tcp_drain,
#endif
&tcp6_usrreqs,
},
{ SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC | PR_ADDR,
- rip6_input, rip6_output, 0, rip6_ctloutput,
+ rip6_input, rip6_output, rip6_ctlinput, rip6_ctloutput,
0,
0, 0, 0, 0,
&rip6_usrreqs
@@ -169,68 +175,88 @@ struct ip6protosw inet6sw[] = {
},
{ SOCK_RAW, &inet6domain, IPPROTO_DSTOPTS,PR_ATOMIC|PR_ADDR,
dest6_input, 0, 0, 0,
- 0,
+ 0,
0, 0, 0, 0,
&nousrreqs
},
{ SOCK_RAW, &inet6domain, IPPROTO_ROUTING,PR_ATOMIC|PR_ADDR,
route6_input, 0, 0, 0,
- 0,
+ 0,
0, 0, 0, 0,
&nousrreqs
},
{ SOCK_RAW, &inet6domain, IPPROTO_FRAGMENT,PR_ATOMIC|PR_ADDR,
frag6_input, 0, 0, 0,
- 0,
+ 0,
0, 0, 0, 0,
&nousrreqs
},
#ifdef IPSEC
{ SOCK_RAW, &inet6domain, IPPROTO_AH, PR_ATOMIC|PR_ADDR,
ah6_input, 0, 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,
+ 0,
0, 0, 0, 0,
&nousrreqs,
},
#endif
+{ SOCK_RAW, &inet6domain, IPPROTO_IPCOMP, PR_ATOMIC|PR_ADDR,
+ ipcomp6_input, 0, 0, 0,
+ 0,
+ 0, 0, 0, 0,
+ &nousrreqs,
+},
#endif /* IPSEC */
-#if NGIF > 0
+#ifdef INET
{ SOCK_RAW, &inet6domain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR,
- in6_gif_input,0, 0, 0,
- 0,
+ encap6_input, rip6_output, 0, rip6_ctloutput,
+ 0,
0, 0, 0, 0,
- &nousrreqs
+ &rip6_usrreqs
},
+#endif /*INET*/
{ SOCK_RAW, &inet6domain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR,
- in6_gif_input,0, 0, 0,
+ encap6_input, rip6_output, 0, rip6_ctloutput,
0,
+#ifndef INET
+ encap_init, 0, 0, 0,
+#else
0, 0, 0, 0,
- &nousrreqs
+#endif
+ &rip6_usrreqs
},
-#endif /* GIF */
{ SOCK_RAW, &inet6domain, IPPROTO_PIM, PR_ATOMIC|PR_ADDR,
- pim6_input, rip6_output, 0, rip6_ctloutput,
+ pim6_input, rip6_output, 0, rip6_ctloutput,
0,
- 0, 0, 0, 0,
+ 0, 0, 0, 0,
&rip6_usrreqs
},
/* raw wildcard */
{ 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
},
};
-extern int in6_inithead __P((void **, int));
+#if NGIF > 0
+struct ip6protosw in6_gif_protosw =
+{ SOCK_RAW, &inet6domain, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR,
+ in6_gif_input, rip6_output, 0, rip6_ctloutput,
+ 0,
+ 0, 0, 0, 0,
+ &rip6_usrreqs
+};
+#endif /*NGIF*/
+
+extern int in6_inithead __P((void **, int));
struct domain inet6domain =
{ AF_INET6, "internet6", 0, 0, 0,
@@ -266,7 +292,7 @@ int ip6_maxfragpackets = 200;
int ip6_log_interval = 5;
int ip6_hdrnestlimit = 50; /* appropriate? */
int ip6_dad_count = 1; /* DupAddrDetectionTransmits */
-u_int32_t ip6_flow_seq;
+u_int32_t ip6_flow_seq;
int ip6_auto_flowlabel = 1;
#if NGIF > 0
int ip6_gif_hlim = GIF_HLIM;
@@ -288,8 +314,8 @@ time_t ip6_log_time = (time_t)0L;
* XXX: what if we don't define INET? Should we define pmtu6_expire
* or so? (jinmei@kame.net 19990310)
*/
-int pmtu_expire = 60*10;
-int pmtu_probe = 60*2;
+int pmtu_expire = 60*10;
+int pmtu_probe = 60*2;
/* raw IP6 parameters */
/*
@@ -304,7 +330,84 @@ u_long rip6_recvspace = RIPV6RCVQ;
/* ICMPV6 parameters */
int icmp6_rediraccept = 1; /* accept and process redirects */
int icmp6_redirtimeout = 10 * 60; /* 10 minutes */
-u_int icmp6errratelim = 1000; /* 1000usec = 1msec */
+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*/
/* UDP on IP6 parameters */
int udp6_sendspace = 9216; /* really max datagram size */
@@ -344,30 +447,57 @@ sysctl_ip6_forwarding(SYSCTL_HANDLER_ARGS)
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 = LIST_FIRST(&nd_prefix); pr; pr = next) {
- next = LIST_NEXT(pr, ndpr_entry);
+ 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 */
- struct socket so;
-
- /* XXX: init dummy so */
- bzero(&so, sizeof(so));
while(!LIST_EMPTY(&rr_prefix))
- delete_each_prefix(&so, LIST_FIRST(&rr_prefix),
+ delete_each_prefix(LIST_FIRST(&rr_prefix),
PR_ORIG_KERNEL);
}
return (error);
}
+static int
+sysctl_icmp6_ratelimit (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)
+ 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);
+}
+
SYSCTL_OID(_net_inet6_ip6, IPV6CTL_FORWARDING, forwarding,
CTLTYPE_INT|CTLFLAG_RW, &ip6_forwarding, 0, sysctl_ip6_forwarding,
"I", "");
@@ -409,8 +539,9 @@ 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_INT(_net_inet6_icmp6, ICMPV6CTL_ERRRATELIMIT,
- errratelimit, CTLFLAG_RW, &icmp6errratelim, 0, "");
+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,
@@ -421,5 +552,9 @@ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_MMAXTRIES,
nd6_mmaxtries, CTLFLAG_RW, &nd6_mmaxtries, 0, "");
SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_USELOOPBACK,
nd6_useloopback, CTLFLAG_RW, &nd6_useloopback, 0, "");
-SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_PROXYALL,
- nd6_proxyall, CTLFLAG_RW, &nd6_proxyall, 0, "");
+SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_NODEINFO,
+ nodeinfo, CTLFLAG_RW, &icmp6_nodeinfo, 0, "");
+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, "");
diff --git a/sys/netinet6/in6_rmx.c b/sys/netinet6/in6_rmx.c
index 56e9d94af584..cb74a49fa0c9 100644
--- a/sys/netinet6/in6_rmx.c
+++ b/sys/netinet6/in6_rmx.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6_rmx.c,v 1.7 2000/04/06 08:30:43 sumikawa Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -57,7 +58,6 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: in6_rmx.c,v 1.3 1999/08/16 13:42:53 itojun Exp $
*/
/*
@@ -89,10 +89,10 @@
#include <netinet/ip_var.h>
#include <netinet/in_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#include <netinet/tcp.h>
#include <netinet/tcp_seq.h>
@@ -101,14 +101,14 @@
extern int in6_inithead __P((void **head, int off));
-#define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */
+#define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */
/*
* Do what we need to do when inserting a route.
*/
static struct radix_node *
in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
- struct radix_node *treenodes)
+ struct radix_node *treenodes)
{
struct rtentry *rt = (struct rtentry *)treenodes;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt);
@@ -453,6 +453,24 @@ in6_mtutimo(void *rock)
timeout(in6_mtutimo, rock, tvtohz(&atv));
}
+#if 0
+void
+in6_rtqdrain()
+{
+ struct radix_node_head *rnh = rt_tables[AF_INET6];
+ struct rtqk_arg arg;
+ int s;
+ arg.found = arg.killed = 0;
+ arg.rnh = rnh;
+ arg.nextstop = 0;
+ arg.draining = 1;
+ arg.updating = 0;
+ s = splnet();
+ rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
+ splx(s);
+}
+#endif
+
/*
* Initialize our routing tree.
*/
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c
new file mode 100644
index 000000000000..40b0df4fb5b1
--- /dev/null
+++ b/sys/netinet6/in6_src.c
@@ -0,0 +1,550 @@
+/* $FreeBSD$ */
+/* $KAME: in6_src.c,v 1.27 2000/06/21 08:07:13 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.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1991, 1993
+ * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet6/in6_var.h>
+#include <netinet/ip6.h>
+#include <netinet6/in6_pcb.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/nd6.h>
+#ifdef ENABLE_DEFAULT_SCOPE
+#include <netinet6/scope6_var.h>
+#endif
+
+#include <net/net_osdep.h>
+
+#include "loop.h"
+
+/*
+ * Return an IPv6 address, which is the most appropriate for given
+ * destination and user specified options.
+ * If necessary, this function lookups the routing table and return
+ * an entry to the caller for later use.
+ */
+struct in6_addr *
+in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
+ struct sockaddr_in6 *dstsock;
+ struct ip6_pktopts *opts;
+ struct ip6_moptions *mopts;
+ struct route_in6 *ro;
+ struct in6_addr *laddr;
+ int *errorp;
+{
+ struct in6_addr *dst;
+ struct in6_ifaddr *ia6 = 0;
+ struct in6_pktinfo *pi = NULL;
+
+ dst = &dstsock->sin6_addr;
+ *errorp = 0;
+
+ /*
+ * If the source address is explicitly specified by the caller,
+ * use it.
+ */
+ if (opts && (pi = opts->ip6po_pktinfo) &&
+ !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
+ return(&pi->ipi6_addr);
+
+ /*
+ * If the source address is not specified but the socket(if any)
+ * is already bound, use the bound address.
+ */
+ if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
+ return(laddr);
+
+ /*
+ * If the caller doesn't specify the source address but
+ * the outgoing interface, use an address associated with
+ * the interface.
+ */
+ if (pi && pi->ipi6_ifindex) {
+ /* XXX boundary check is assumed to be already done. */
+ ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex],
+ dst);
+ if (ia6 == 0) {
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+
+ /*
+ * If the destination address is a link-local unicast address or
+ * a multicast address, and if the outgoing interface is specified
+ * by the sin6_scope_id filed, use an address associated with the
+ * interface.
+ * XXX: We're now trying to define more specific semantics of
+ * sin6_scope_id field, so this part will be rewritten in
+ * the near future.
+ */
+ if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) &&
+ dstsock->sin6_scope_id) {
+ /*
+ * I'm not sure if boundary check for scope_id is done
+ * somewhere...
+ */
+ if (dstsock->sin6_scope_id < 0 ||
+ if_index < dstsock->sin6_scope_id) {
+ *errorp = ENXIO; /* XXX: better error? */
+ return(0);
+ }
+ ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id],
+ dst);
+ if (ia6 == 0) {
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+
+ /*
+ * If the destination address is a multicast address and
+ * the outgoing interface for the address is specified
+ * by the caller, use an address associated with the interface.
+ * There is a sanity check here; if the destination has node-local
+ * scope, the outgoing interfacde should be a loopback address.
+ * Even if the outgoing interface is not specified, we also
+ * choose a loopback interface as the outgoing interface.
+ */
+ if (IN6_IS_ADDR_MULTICAST(dst)) {
+ struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
+
+ if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) {
+ ifp = &loif[0];
+ }
+
+ if (ifp) {
+ ia6 = in6_ifawithscope(ifp, dst);
+ if (ia6 == 0) {
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+ }
+
+ /*
+ * If the next hop address for the packet is specified
+ * by caller, use an address associated with the route
+ * to the next hop.
+ */
+ {
+ struct sockaddr_in6 *sin6_next;
+ struct rtentry *rt;
+
+ if (opts && opts->ip6po_nexthop) {
+ sin6_next = satosin6(opts->ip6po_nexthop);
+ rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
+ if (rt) {
+ ia6 = in6_ifawithscope(rt->rt_ifp, dst);
+ if (ia6 == 0)
+ ia6 = ifatoia6(rt->rt_ifa);
+ }
+ if (ia6 == 0) {
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+ }
+
+ /*
+ * If route is known or can be allocated now,
+ * our src addr is taken from the i/f, else punt.
+ */
+ if (ro) {
+ if (ro->ro_rt &&
+ !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) {
+ RTFREE(ro->ro_rt);
+ ro->ro_rt = (struct rtentry *)0;
+ }
+ if (ro->ro_rt == (struct rtentry *)0 ||
+ ro->ro_rt->rt_ifp == (struct ifnet *)0) {
+ /* 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;
+ if (IN6_IS_ADDR_MULTICAST(dst)) {
+ ro->ro_rt = rtalloc1(&((struct route *)ro)
+ ->ro_dst, 0, 0UL);
+ } else {
+ rtalloc((struct route *)ro);
+ }
+ }
+
+ /*
+ * in_pcbconnect() checks out IFF_LOOPBACK to skip using
+ * the address. But we don't know why it does so.
+ * It is necessary to ensure the scope even for lo0
+ * so doesn't check out IFF_LOOPBACK.
+ */
+
+ if (ro->ro_rt) {
+ ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
+ if (ia6 == 0) /* xxx scope error ?*/
+ ia6 = ifatoia6(ro->ro_rt->rt_ifa);
+ }
+#if 0
+ /*
+ * xxx The followings are necessary? (kazu)
+ * I don't think so.
+ * It's for SO_DONTROUTE option in IPv4.(jinmei)
+ */
+ if (ia6 == 0) {
+ struct sockaddr_in6 sin6 = {sizeof(sin6), AF_INET6, 0};
+
+ sin6->sin6_addr = *dst;
+
+ ia6 = ifatoia6(ifa_ifwithdstaddr(sin6tosa(&sin6)));
+ if (ia6 == 0)
+ ia6 = ifatoia6(ifa_ifwithnet(sin6tosa(&sin6)));
+ if (ia6 == 0)
+ return(0);
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+#endif /* 0 */
+ if (ia6 == 0) {
+ *errorp = EHOSTUNREACH; /* no route */
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+}
+
+/*
+ * Default hop limit selection. The precedence is as follows:
+ * 1. Hoplimit value specified via ioctl.
+ * 2. (If the outgoing interface is detected) the current
+ * hop limit of the interface specified by router advertisement.
+ * 3. The system default hoplimit.
+*/
+int
+in6_selecthlim(in6p, ifp)
+ struct in6pcb *in6p;
+ struct ifnet *ifp;
+{
+ if (in6p && in6p->in6p_hops >= 0)
+ return(in6p->in6p_hops);
+ else if (ifp)
+ return(nd_ifinfo[ifp->if_index].chlim);
+ else
+ return(ip6_defhlim);
+}
+
+/*
+ * XXX: this is borrowed from in6_pcbbind(). If possible, we should
+ * share this function by all *bsd*...
+ */
+int
+in6_pcbsetport(laddr, inp, p)
+ struct in6_addr *laddr;
+ struct inpcb *inp;
+ struct proc *p;
+{
+ struct socket *so = inp->inp_socket;
+ u_int16_t lport = 0, first, last, *lastport;
+ int count, error = 0, wild = 0;
+ struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
+
+ /* XXX: this is redundant when called from in6_pcbbind */
+ if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
+ wild = INPLOOKUP_WILDCARD;
+
+ inp->inp_flags |= INP_ANONPORT;
+
+ if (inp->inp_flags & INP_HIGHPORT) {
+ first = ipport_hifirstauto; /* sysctl */
+ last = ipport_hilastauto;
+ lastport = &pcbinfo->lasthi;
+ } else if (inp->inp_flags & INP_LOWPORT) {
+ if (p && (error = suser(p)))
+ return error;
+ first = ipport_lowfirstauto; /* 1023 */
+ last = ipport_lowlastauto; /* 600 */
+ lastport = &pcbinfo->lastlow;
+ } else {
+ first = ipport_firstauto; /* sysctl */
+ last = ipport_lastauto;
+ lastport = &pcbinfo->lastport;
+ }
+ /*
+ * Simple check to ensure all ports are not used up causing
+ * a deadlock here.
+ *
+ * We split the two cases (up and down) so that the direction
+ * is not being tested on each round of the loop.
+ */
+ if (first > last) {
+ /*
+ * counting down
+ */
+ count = first - last;
+
+ do {
+ if (count-- < 0) { /* completely used? */
+ /*
+ * Undo any address bind that may have
+ * occurred above.
+ */
+ inp->in6p_laddr = in6addr_any;
+ return (EAGAIN);
+ }
+ --*lastport;
+ if (*lastport > first || *lastport < last)
+ *lastport = first;
+ lport = htons(*lastport);
+ } while (in6_pcblookup_local(pcbinfo,
+ &inp->in6p_laddr, lport, wild));
+ } else {
+ /*
+ * counting up
+ */
+ count = last - first;
+
+ do {
+ if (count-- < 0) { /* completely used? */
+ /*
+ * Undo any address bind that may have
+ * occurred above.
+ */
+ inp->in6p_laddr = in6addr_any;
+ return (EAGAIN);
+ }
+ ++*lastport;
+ if (*lastport < first || *lastport > last)
+ *lastport = first;
+ lport = htons(*lastport);
+ } while (in6_pcblookup_local(pcbinfo,
+ &inp->in6p_laddr, lport, wild));
+ }
+
+ inp->inp_lport = lport;
+ if (in_pcbinshash(inp) != 0) {
+ inp->in6p_laddr = in6addr_any;
+ inp->inp_lport = 0;
+ return (EAGAIN);
+ }
+
+ return(0);
+}
+
+/*
+ * generate kernel-internal form (scopeid embedded into s6_addr16[1]).
+ * If the address scope of is link-local, embed the interface index in the
+ * address. The routine determines our precedence
+ * between advanced API scope/interface specification and basic API
+ * specification.
+ *
+ * this function should be nuked in the future, when we get rid of
+ * embedded scopeid thing.
+ *
+ * XXX actually, it is over-specification to return ifp against sin6_scope_id.
+ * there can be multiple interfaces that belong to a particular scope zone
+ * (in specification, we have 1:N mapping between a scope zone and interfaces).
+ * we may want to change the function to return something other than ifp.
+ */
+int
+in6_embedscope(in6, sin6, in6p, ifpp)
+ struct in6_addr *in6;
+ const struct sockaddr_in6 *sin6;
+#ifdef HAVE_NRL_INPCB
+ struct inpcb *in6p;
+#define in6p_outputopts inp_outputopts6
+#define in6p_moptions inp_moptions6
+#else
+ struct in6pcb *in6p;
+#endif
+ struct ifnet **ifpp;
+{
+ struct ifnet *ifp = NULL;
+ u_int32_t scopeid;
+
+ *in6 = sin6->sin6_addr;
+ scopeid = sin6->sin6_scope_id;
+ if (ifpp)
+ *ifpp = NULL;
+
+ /*
+ * don't try to read sin6->sin6_addr beyond here, since the caller may
+ * ask us to overwrite existing sockaddr_in6
+ */
+
+#ifdef ENABLE_DEFAULT_SCOPE
+ if (scopeid == 0)
+ scopeid = scope6_addr2default(in6);
+#endif
+
+ if (IN6_IS_SCOPE_LINKLOCAL(in6)) {
+ struct in6_pktinfo *pi;
+
+ /*
+ * KAME assumption: link id == interface id
+ */
+
+ if (in6p && in6p->in6p_outputopts &&
+ (pi = in6p->in6p_outputopts->ip6po_pktinfo) &&
+ pi->ipi6_ifindex) {
+ ifp = ifindex2ifnet[pi->ipi6_ifindex];
+ in6->s6_addr16[1] = htons(pi->ipi6_ifindex);
+ } else if (in6p && IN6_IS_ADDR_MULTICAST(in6) &&
+ in6p->in6p_moptions &&
+ in6p->in6p_moptions->im6o_multicast_ifp) {
+ ifp = in6p->in6p_moptions->im6o_multicast_ifp;
+ in6->s6_addr16[1] = htons(ifp->if_index);
+ } else if (scopeid) {
+ /* boundary check */
+ if (scopeid < 0 || if_index < scopeid)
+ return ENXIO; /* XXX EINVAL? */
+ ifp = ifindex2ifnet[scopeid];
+ /*XXX assignment to 16bit from 32bit variable */
+ in6->s6_addr16[1] = htons(scopeid & 0xffff);
+ }
+
+ if (ifpp)
+ *ifpp = ifp;
+ }
+
+ return 0;
+}
+#ifdef HAVE_NRL_INPCB
+#undef in6p_outputopts
+#undef in6p_moptions
+#endif
+
+/*
+ * generate standard sockaddr_in6 from embedded form.
+ * touches sin6_addr and sin6_scope_id only.
+ *
+ * this function should be nuked in the future, when we get rid of
+ * embedded scopeid thing.
+ */
+int
+in6_recoverscope(sin6, in6, ifp)
+ struct sockaddr_in6 *sin6;
+ const struct in6_addr *in6;
+ struct ifnet *ifp;
+{
+ u_int32_t scopeid;
+
+ sin6->sin6_addr = *in6;
+
+ /*
+ * don't try to read *in6 beyond here, since the caller may
+ * ask us to overwrite existing sockaddr_in6
+ */
+
+ sin6->sin6_scope_id = 0;
+ if (IN6_IS_SCOPE_LINKLOCAL(in6)) {
+ /*
+ * KAME assumption: link id == interface id
+ */
+ scopeid = ntohs(sin6->sin6_addr.s6_addr16[1]);
+ if (scopeid) {
+ /* 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;
+ }
+ }
+
+ return 0;
+}
diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h
index 163c1679ccee..511c1b2bdcad 100644
--- a/sys/netinet6/in6_var.h
+++ b/sys/netinet6/in6_var.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6_var.h,v 1.33 2000/05/17 05:07:26 jinmei Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -60,11 +63,10 @@
* SUCH DAMAGE.
*
* @(#)in_var.h 8.1 (Berkeley) 6/10/93
- * $FreeBSD$
*/
-#ifndef _NETINET6_IN6_VAR_H_
-#define _NETINET6_IN6_VAR_H_
+#ifndef _NETINET6_IN6_VAR_H_
+#define _NETINET6_IN6_VAR_H_
/*
* Interface address, Internet version. One of these structures
@@ -82,63 +84,63 @@
* in kernel: modify preferred/expire only
*/
struct in6_addrlifetime {
- time_t ia6t_expire; /* valid lifetime expiration time */
- time_t ia6t_preferred; /* preferred lifetime expiration time */
- u_int32_t ia6t_vltime; /* valid lifetime */
- u_int32_t ia6t_pltime; /* prefix lifetime */
+ time_t ia6t_expire; /* valid lifetime expiration time */
+ time_t ia6t_preferred; /* preferred lifetime expiration time */
+ u_int32_t ia6t_vltime; /* valid lifetime */
+ u_int32_t ia6t_pltime; /* prefix lifetime */
};
struct in6_ifaddr {
struct ifaddr ia_ifa; /* protocol-independent info */
#define ia_ifp ia_ifa.ifa_ifp
-#define ia_flags ia_ifa.ifa_flags
+#define ia_flags ia_ifa.ifa_flags
struct sockaddr_in6 ia_addr; /* interface address */
struct sockaddr_in6 ia_net; /* network number of interface */
struct sockaddr_in6 ia_dstaddr; /* space for destination addr */
struct sockaddr_in6 ia_prefixmask; /* prefix mask */
- u_int32_t ia_plen; /* prefix length */
+ u_int32_t ia_plen; /* prefix length */
struct in6_ifaddr *ia_next; /* next in6 list of IP6 addresses */
int ia6_flags;
- struct in6_addrlifetime ia6_lifetime; /* NULL = infty */
- struct ifprefix *ia6_ifpr; /* back pointer to ifprefix */
+ struct in6_addrlifetime ia6_lifetime; /* NULL = infty */
+ struct ifprefix *ia6_ifpr; /* back pointer to ifprefix */
};
/*
* IPv6 interface statistics, as defined in RFC2465 Ipv6IfStatsEntry (p12).
*/
struct in6_ifstat {
- u_int64_t ifs6_in_receive; /* # of total input datagram */
- u_int64_t ifs6_in_hdrerr; /* # of datagrams with invalid hdr */
- u_int64_t ifs6_in_toobig; /* # of datagrams exceeded MTU */
- u_int64_t ifs6_in_noroute; /* # of datagrams with no route */
- u_int64_t ifs6_in_addrerr; /* # of datagrams with invalid dst */
- u_int64_t ifs6_in_protounknown; /* # of datagrams with unknown proto */
+ u_quad_t ifs6_in_receive; /* # of total input datagram */
+ u_quad_t ifs6_in_hdrerr; /* # of datagrams with invalid hdr */
+ u_quad_t ifs6_in_toobig; /* # of datagrams exceeded MTU */
+ u_quad_t ifs6_in_noroute; /* # of datagrams with no route */
+ u_quad_t ifs6_in_addrerr; /* # of datagrams with invalid dst */
+ u_quad_t ifs6_in_protounknown; /* # of datagrams with unknown proto */
/* NOTE: increment on final dst if */
- u_int64_t ifs6_in_truncated; /* # of truncated datagrams */
- u_int64_t ifs6_in_discard; /* # of discarded datagrams */
+ u_quad_t ifs6_in_truncated; /* # of truncated datagrams */
+ u_quad_t ifs6_in_discard; /* # of discarded datagrams */
/* NOTE: fragment timeout is not here */
- u_int64_t ifs6_in_deliver; /* # of datagrams delivered to ULP */
+ u_quad_t ifs6_in_deliver; /* # of datagrams delivered to ULP */
/* NOTE: increment on final dst if */
- u_int64_t ifs6_out_forward; /* # of datagrams forwarded */
+ u_quad_t ifs6_out_forward; /* # of datagrams forwarded */
/* NOTE: increment on outgoing if */
- u_int64_t ifs6_out_request; /* # of outgoing datagrams from ULP */
+ u_quad_t ifs6_out_request; /* # of outgoing datagrams from ULP */
/* NOTE: does not include forwrads */
- u_int64_t ifs6_out_discard; /* # of discarded datagrams */
- u_int64_t ifs6_out_fragok; /* # of datagrams fragmented */
- u_int64_t ifs6_out_fragfail; /* # of datagrams failed on fragment */
- u_int64_t ifs6_out_fragcreat; /* # of fragment datagrams */
+ u_quad_t ifs6_out_discard; /* # of discarded datagrams */
+ u_quad_t ifs6_out_fragok; /* # of datagrams fragmented */
+ u_quad_t ifs6_out_fragfail; /* # of datagrams failed on fragment */
+ u_quad_t ifs6_out_fragcreat; /* # of fragment datagrams */
/* NOTE: this is # after fragment */
- u_int64_t ifs6_reass_reqd; /* # of incoming fragmented packets */
+ u_quad_t ifs6_reass_reqd; /* # of incoming fragmented packets */
/* NOTE: increment on final dst if */
- u_int64_t ifs6_reass_ok; /* # of reassembled packets */
+ u_quad_t ifs6_reass_ok; /* # of reassembled packets */
/* NOTE: this is # after reass */
/* NOTE: increment on final dst if */
- u_int64_t ifs6_reass_fail; /* # of reass failures */
+ u_quad_t ifs6_reass_fail; /* # of reass failures */
/* NOTE: may not be packet count */
/* NOTE: increment on final dst if */
- u_int64_t ifs6_in_mcast; /* # of inbound multicast datagrams */
- u_int64_t ifs6_out_mcast; /* # of outbound multicast datagrams */
+ u_quad_t ifs6_in_mcast; /* # of inbound multicast datagrams */
+ u_quad_t ifs6_out_mcast; /* # of outbound multicast datagrams */
};
/*
@@ -150,77 +152,77 @@ struct icmp6_ifstat {
* Input statistics
*/
/* ipv6IfIcmpInMsgs, total # of input messages */
- u_int64_t ifs6_in_msg;
+ u_quad_t ifs6_in_msg;
/* ipv6IfIcmpInErrors, # of input error messages */
- u_int64_t ifs6_in_error;
+ u_quad_t ifs6_in_error;
/* ipv6IfIcmpInDestUnreachs, # of input dest unreach errors */
- u_int64_t ifs6_in_dstunreach;
+ u_quad_t ifs6_in_dstunreach;
/* ipv6IfIcmpInAdminProhibs, # of input administratively prohibited errs */
- u_int64_t ifs6_in_adminprohib;
+ u_quad_t ifs6_in_adminprohib;
/* ipv6IfIcmpInTimeExcds, # of input time exceeded errors */
- u_int64_t ifs6_in_timeexceed;
+ u_quad_t ifs6_in_timeexceed;
/* ipv6IfIcmpInParmProblems, # of input parameter problem errors */
- u_int64_t ifs6_in_paramprob;
+ u_quad_t ifs6_in_paramprob;
/* ipv6IfIcmpInPktTooBigs, # of input packet too big errors */
- u_int64_t ifs6_in_pkttoobig;
+ u_quad_t ifs6_in_pkttoobig;
/* ipv6IfIcmpInEchos, # of input echo requests */
- u_int64_t ifs6_in_echo;
+ u_quad_t ifs6_in_echo;
/* ipv6IfIcmpInEchoReplies, # of input echo replies */
- u_int64_t ifs6_in_echoreply;
+ u_quad_t ifs6_in_echoreply;
/* ipv6IfIcmpInRouterSolicits, # of input router solicitations */
- u_int64_t ifs6_in_routersolicit;
+ u_quad_t ifs6_in_routersolicit;
/* ipv6IfIcmpInRouterAdvertisements, # of input router advertisements */
- u_int64_t ifs6_in_routeradvert;
+ u_quad_t ifs6_in_routeradvert;
/* ipv6IfIcmpInNeighborSolicits, # of input neighbor solicitations */
- u_int64_t ifs6_in_neighborsolicit;
+ u_quad_t ifs6_in_neighborsolicit;
/* ipv6IfIcmpInNeighborAdvertisements, # of input neighbor advertisements */
- u_int64_t ifs6_in_neighboradvert;
+ u_quad_t ifs6_in_neighboradvert;
/* ipv6IfIcmpInRedirects, # of input redirects */
- u_int64_t ifs6_in_redirect;
+ u_quad_t ifs6_in_redirect;
/* ipv6IfIcmpInGroupMembQueries, # of input MLD queries */
- u_int64_t ifs6_in_mldquery;
+ u_quad_t ifs6_in_mldquery;
/* ipv6IfIcmpInGroupMembResponses, # of input MLD reports */
- u_int64_t ifs6_in_mldreport;
+ u_quad_t ifs6_in_mldreport;
/* ipv6IfIcmpInGroupMembReductions, # of input MLD done */
- u_int64_t ifs6_in_mlddone;
+ u_quad_t ifs6_in_mlddone;
/*
* Output statistics. We should solve unresolved routing problem...
*/
/* ipv6IfIcmpOutMsgs, total # of output messages */
- u_int64_t ifs6_out_msg;
+ u_quad_t ifs6_out_msg;
/* ipv6IfIcmpOutErrors, # of output error messages */
- u_int64_t ifs6_out_error;
+ u_quad_t ifs6_out_error;
/* ipv6IfIcmpOutDestUnreachs, # of output dest unreach errors */
- u_int64_t ifs6_out_dstunreach;
+ u_quad_t ifs6_out_dstunreach;
/* ipv6IfIcmpOutAdminProhibs, # of output administratively prohibited errs */
- u_int64_t ifs6_out_adminprohib;
+ u_quad_t ifs6_out_adminprohib;
/* ipv6IfIcmpOutTimeExcds, # of output time exceeded errors */
- u_int64_t ifs6_out_timeexceed;
+ u_quad_t ifs6_out_timeexceed;
/* ipv6IfIcmpOutParmProblems, # of output parameter problem errors */
- u_int64_t ifs6_out_paramprob;
+ u_quad_t ifs6_out_paramprob;
/* ipv6IfIcmpOutPktTooBigs, # of output packet too big errors */
- u_int64_t ifs6_out_pkttoobig;
+ u_quad_t ifs6_out_pkttoobig;
/* ipv6IfIcmpOutEchos, # of output echo requests */
- u_int64_t ifs6_out_echo;
+ u_quad_t ifs6_out_echo;
/* ipv6IfIcmpOutEchoReplies, # of output echo replies */
- u_int64_t ifs6_out_echoreply;
+ u_quad_t ifs6_out_echoreply;
/* ipv6IfIcmpOutRouterSolicits, # of output router solicitations */
- u_int64_t ifs6_out_routersolicit;
+ u_quad_t ifs6_out_routersolicit;
/* ipv6IfIcmpOutRouterAdvertisements, # of output router advertisements */
- u_int64_t ifs6_out_routeradvert;
+ u_quad_t ifs6_out_routeradvert;
/* ipv6IfIcmpOutNeighborSolicits, # of output neighbor solicitations */
- u_int64_t ifs6_out_neighborsolicit;
+ u_quad_t ifs6_out_neighborsolicit;
/* ipv6IfIcmpOutNeighborAdvertisements, # of output neighbor advertisements */
- u_int64_t ifs6_out_neighboradvert;
+ u_quad_t ifs6_out_neighboradvert;
/* ipv6IfIcmpOutRedirects, # of output redirects */
- u_int64_t ifs6_out_redirect;
+ u_quad_t ifs6_out_redirect;
/* ipv6IfIcmpOutGroupMembQueries, # of output MLD queries */
- u_int64_t ifs6_out_mldquery;
+ u_quad_t ifs6_out_mldquery;
/* ipv6IfIcmpOutGroupMembResponses, # of output MLD reports */
- u_int64_t ifs6_out_mldreport;
+ u_quad_t ifs6_out_mldreport;
/* ipv6IfIcmpOutGroupMembReductions, # of output MLD done */
- u_int64_t ifs6_out_mlddone;
+ u_quad_t ifs6_out_mlddone;
};
struct in6_ifreq {
@@ -232,9 +234,10 @@ struct in6_ifreq {
int ifru_flags6;
int ifru_metric;
caddr_t ifru_data;
- struct in6_addrlifetime ifru_lifetime;
- struct in6_ifstat ifru_stat;
- struct icmp6_ifstat ifru_icmp6stat;
+ struct in6_addrlifetime ifru_lifetime;
+ struct in6_ifstat ifru_stat;
+ struct icmp6_ifstat ifru_icmp6stat;
+ u_int32_t ifru_scope_id[16];
} ifr_ifru;
};
@@ -244,12 +247,12 @@ struct in6_aliasreq {
struct sockaddr_in6 ifra_dstaddr;
struct sockaddr_in6 ifra_prefixmask;
int ifra_flags;
- struct in6_addrlifetime ifra_lifetime;
+ struct in6_addrlifetime ifra_lifetime;
};
/* prefix type macro */
-#define IN6_PREFIX_ND 1
-#define IN6_PREFIX_RR 2
+#define IN6_PREFIX_ND 1
+#define IN6_PREFIX_RR 2
/*
* prefix related flags passed between kernel(NDP related part) and
@@ -257,44 +260,44 @@ struct in6_aliasreq {
*/
struct in6_prflags {
struct prf_ra {
- u_char onlink : 1;
- u_char autonomous : 1;
- u_char reserved : 6;
+ u_char onlink : 1;
+ u_char autonomous : 1;
+ u_char reserved : 6;
} prf_ra;
- u_char prf_reserved1;
- u_short prf_reserved2;
+ u_char prf_reserved1;
+ u_short prf_reserved2;
/* want to put this on 4byte offset */
struct prf_rr {
- u_char decrvalid : 1;
- u_char decrprefd : 1;
- u_char reserved : 6;
+ u_char decrvalid : 1;
+ u_char decrprefd : 1;
+ u_char reserved : 6;
} prf_rr;
- u_char prf_reserved3;
- u_short prf_reserved4;
+ u_char prf_reserved3;
+ u_short prf_reserved4;
};
struct in6_prefixreq {
char ipr_name[IFNAMSIZ];
u_char ipr_origin;
u_char ipr_plen;
- u_int32_t ipr_vltime;
- u_int32_t ipr_pltime;
- struct in6_prflags ipr_flags;
+ u_int32_t ipr_vltime;
+ u_int32_t ipr_pltime;
+ struct in6_prflags ipr_flags;
struct sockaddr_in6 ipr_prefix;
};
-#define PR_ORIG_RA 0
-#define PR_ORIG_RR 1
-#define PR_ORIG_STATIC 2
-#define PR_ORIG_KERNEL 3
+#define PR_ORIG_RA 0
+#define PR_ORIG_RR 1
+#define PR_ORIG_STATIC 2
+#define PR_ORIG_KERNEL 3
-#define ipr_raf_onlink ipr_flags.prf_ra.onlink
-#define ipr_raf_auto ipr_flags.prf_ra.autonomous
+#define ipr_raf_onlink ipr_flags.prf_ra.onlink
+#define ipr_raf_auto ipr_flags.prf_ra.autonomous
-#define ipr_statef_onlink ipr_flags.prf_state.onlink
+#define ipr_statef_onlink ipr_flags.prf_state.onlink
-#define ipr_rrf_decrvalid ipr_flags.prf_rr.decrvalid
-#define ipr_rrf_decrprefd ipr_flags.prf_rr.decrprefd
+#define ipr_rrf_decrvalid ipr_flags.prf_rr.decrvalid
+#define ipr_rrf_decrprefd ipr_flags.prf_rr.decrprefd
struct in6_rrenumreq {
char irr_name[IFNAMSIZ];
@@ -304,114 +307,136 @@ struct in6_rrenumreq {
u_char irr_m_maxlen; /* maxlen for matching prefix */
u_char irr_u_uselen; /* uselen for adding prefix */
u_char irr_u_keeplen; /* keeplen from matching prefix */
- struct irr_raflagmask {
- u_char onlink : 1;
- u_char autonomous : 1;
- u_char reserved : 6;
+ struct irr_raflagmask {
+ u_char onlink : 1;
+ u_char autonomous : 1;
+ u_char reserved : 6;
} irr_raflagmask;
- u_int32_t irr_vltime;
- u_int32_t irr_pltime;
- struct in6_prflags irr_flags;
+ u_int32_t irr_vltime;
+ u_int32_t irr_pltime;
+ struct in6_prflags irr_flags;
struct sockaddr_in6 irr_matchprefix;
struct sockaddr_in6 irr_useprefix;
};
-#define irr_raf_mask_onlink irr_raflagmask.onlink
-#define irr_raf_mask_auto irr_raflagmask.autonomous
-#define irr_raf_mask_reserved irr_raflagmask.reserved
+#define irr_raf_mask_onlink irr_raflagmask.onlink
+#define irr_raf_mask_auto irr_raflagmask.autonomous
+#define irr_raf_mask_reserved irr_raflagmask.reserved
-#define irr_raf_onlink irr_flags.prf_ra.onlink
-#define irr_raf_auto irr_flags.prf_ra.autonomous
+#define irr_raf_onlink irr_flags.prf_ra.onlink
+#define irr_raf_auto irr_flags.prf_ra.autonomous
-#define irr_statef_onlink irr_flags.prf_state.onlink
+#define irr_statef_onlink irr_flags.prf_state.onlink
-#define irr_rrf irr_flags.prf_rr
-#define irr_rrf_decrvalid irr_flags.prf_rr.decrvalid
-#define irr_rrf_decrprefd irr_flags.prf_rr.decrprefd
+#define irr_rrf irr_flags.prf_rr
+#define irr_rrf_decrvalid irr_flags.prf_rr.decrvalid
+#define irr_rrf_decrprefd irr_flags.prf_rr.decrprefd
/*
* Given a pointer to an in6_ifaddr (ifaddr),
* return a pointer to the addr as a sockaddr_in6
*/
-#define IA6_IN6(ia) (&((ia)->ia_addr.sin6_addr))
-#define IA6_DSTIN6(ia) (&((ia)->ia_dstaddr.sin6_addr))
-#define IA6_MASKIN6(ia) (&((ia)->ia_prefixmask.sin6_addr))
-#define IA6_SIN6(ia) (&((ia)->ia_addr))
-#define IA6_DSTSIN6(ia) (&((ia)->ia_dstaddr))
-#define IFA_IN6(x) (&((struct sockaddr_in6 *)((x)->ifa_addr))->sin6_addr)
-#define IFA_DSTIN6(x) (&((struct sockaddr_in6 *)((x)->ifa_dstaddr))->sin6_addr)
+#define IA6_IN6(ia) (&((ia)->ia_addr.sin6_addr))
+#define IA6_DSTIN6(ia) (&((ia)->ia_dstaddr.sin6_addr))
+#define IA6_MASKIN6(ia) (&((ia)->ia_prefixmask.sin6_addr))
+#define IA6_SIN6(ia) (&((ia)->ia_addr))
+#define IA6_DSTSIN6(ia) (&((ia)->ia_dstaddr))
+#define IFA_IN6(x) (&((struct sockaddr_in6 *)((x)->ifa_addr))->sin6_addr)
+#define IFA_DSTIN6(x) (&((struct sockaddr_in6 *)((x)->ifa_dstaddr))->sin6_addr)
-#define IFPR_IN6(x) (&((struct sockaddr_in6 *)((x)->ifpr_prefix))->sin6_addr)
+#define IFPR_IN6(x) (&((struct sockaddr_in6 *)((x)->ifpr_prefix))->sin6_addr)
#ifdef _KERNEL
-#define IN6_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
+#define IN6_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
(((d)->s6_addr32[0] ^ (a)->s6_addr32[0]) & (m)->s6_addr32[0]) == 0 && \
(((d)->s6_addr32[1] ^ (a)->s6_addr32[1]) & (m)->s6_addr32[1]) == 0 && \
(((d)->s6_addr32[2] ^ (a)->s6_addr32[2]) & (m)->s6_addr32[2]) == 0 && \
(((d)->s6_addr32[3] ^ (a)->s6_addr32[3]) & (m)->s6_addr32[3]) == 0 )
#endif
-#define SIOCSIFADDR_IN6 _IOW('i', 12, struct in6_ifreq)
-#define SIOCGIFADDR_IN6 _IOWR('i', 33, struct in6_ifreq)
-#define SIOCSIFDSTADDR_IN6 _IOW('i', 14, struct in6_ifreq)
-#define SIOCGIFDSTADDR_IN6 _IOWR('i', 34, struct in6_ifreq)
-#define SIOCSIFNETMASK_IN6 _IOW('i', 22, struct in6_ifreq)
-#define SIOCGIFNETMASK_IN6 _IOWR('i', 37, struct in6_ifreq)
+#define SIOCSIFADDR_IN6 _IOW('i', 12, struct in6_ifreq)
+#define SIOCGIFADDR_IN6 _IOWR('i', 33, struct in6_ifreq)
+
+#ifdef _KERNEL
+/*
+ * SIOCSxxx ioctls should be unused (see comments in in6.c), but
+ * we do not shift numbers for binary compatibility.
+ */
+#define SIOCSIFDSTADDR_IN6 _IOW('i', 14, struct in6_ifreq)
+#define SIOCSIFNETMASK_IN6 _IOW('i', 22, struct in6_ifreq)
+#endif
-#define SIOCDIFADDR_IN6 _IOW('i', 25, struct in6_ifreq)
-#define SIOCAIFADDR_IN6 _IOW('i', 26, struct in6_aliasreq)
+#define SIOCGIFDSTADDR_IN6 _IOWR('i', 34, struct in6_ifreq)
+#define SIOCGIFNETMASK_IN6 _IOWR('i', 37, struct in6_ifreq)
-#define SIOCSIFPHYADDR_IN6 _IOW('i', 70, struct in6_aliasreq)
+#define SIOCDIFADDR_IN6 _IOW('i', 25, struct in6_ifreq)
+#define SIOCAIFADDR_IN6 _IOW('i', 26, struct in6_aliasreq)
+
+#define SIOCSIFPHYADDR_IN6 _IOW('i', 70, struct in6_aliasreq)
#define SIOCGIFPSRCADDR_IN6 _IOWR('i', 71, struct in6_ifreq)
#define SIOCGIFPDSTADDR_IN6 _IOWR('i', 72, struct in6_ifreq)
-#define SIOCGIFAFLAG_IN6 _IOWR('i', 73, struct in6_ifreq)
-
-#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)
-#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)
-#define SIOCSRTRFLUSH_IN6 _IOWR('i', 80, struct in6_ifreq)
-
-#define SIOCGIFALIFETIME_IN6 _IOWR('i', 81, struct in6_ifreq)
-#define SIOCSIFALIFETIME_IN6 _IOWR('i', 82, struct in6_ifreq)
-#define SIOCGIFSTAT_IN6 _IOWR('i', 83, struct in6_ifreq)
-#define SIOCGIFSTAT_ICMP6 _IOWR('i', 84, struct in6_ifreq)
-
-#define SIOCSIFPREFIX_IN6 _IOW('i', 100, struct in6_prefixreq) /* set */
-#define SIOCGIFPREFIX_IN6 _IOWR('i', 101, struct in6_prefixreq) /* get */
-#define SIOCDIFPREFIX_IN6 _IOW('i', 102, struct in6_prefixreq) /* del */
-#define SIOCAIFPREFIX_IN6 _IOW('i', 103, struct in6_rrenumreq) /* add */
-#define SIOCCIFPREFIX_IN6 _IOW('i', 104, \
+#define SIOCGIFAFLAG_IN6 _IOWR('i', 73, struct in6_ifreq)
+
+#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)
+#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)
+#define SIOCSRTRFLUSH_IN6 _IOWR('i', 80, struct in6_ifreq)
+
+#define SIOCGIFALIFETIME_IN6 _IOWR('i', 81, struct in6_ifreq)
+#define SIOCSIFALIFETIME_IN6 _IOWR('i', 82, struct in6_ifreq)
+#define SIOCGIFSTAT_IN6 _IOWR('i', 83, struct in6_ifreq)
+#define SIOCGIFSTAT_ICMP6 _IOWR('i', 84, struct in6_ifreq)
+
+#define SIOCSDEFIFACE_IN6 _IOWR('i', 85, struct in6_ndifreq)
+#define SIOCGDEFIFACE_IN6 _IOWR('i', 86, struct in6_ndifreq)
+
+#define SIOCSIFINFO_FLAGS _IOWR('i', 87, struct in6_ndireq) /* XXX */
+
+#define SIOCSSCOPE6 _IOW('i', 88, struct in6_ifreq)
+#define SIOCGSCOPE6 _IOWR('i', 89, struct in6_ifreq)
+#define SIOCGSCOPE6DEF _IOWR('i', 90, struct in6_ifreq)
+
+#define SIOCSIFPREFIX_IN6 _IOW('i', 100, struct in6_prefixreq) /* set */
+#define SIOCGIFPREFIX_IN6 _IOWR('i', 101, struct in6_prefixreq) /* get */
+#define SIOCDIFPREFIX_IN6 _IOW('i', 102, struct in6_prefixreq) /* del */
+#define SIOCAIFPREFIX_IN6 _IOW('i', 103, struct in6_rrenumreq) /* add */
+#define SIOCCIFPREFIX_IN6 _IOW('i', 104, \
struct in6_rrenumreq) /* change */
-#define SIOCSGIFPREFIX_IN6 _IOW('i', 105, \
+#define SIOCSGIFPREFIX_IN6 _IOW('i', 105, \
struct in6_rrenumreq) /* set global */
-#define SIOCGETSGCNT_IN6 _IOWR('u', 106, \
+#define SIOCGETSGCNT_IN6 _IOWR('u', 106, \
struct sioc_sg_req6) /* get s,g pkt cnt */
-#define SIOCGETMIFCNT_IN6 _IOWR('u', 107, \
+#define SIOCGETMIFCNT_IN6 _IOWR('u', 107, \
struct sioc_mif_req6) /* get pkt cnt per if */
-#define IN6_IFF_ANYCAST 0x01 /* anycast address */
-#define IN6_IFF_TENTATIVE 0x02 /* tentative address */
-#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_ANYCAST 0x01 /* anycast address */
+#define IN6_IFF_TENTATIVE 0x02 /* tentative address */
+#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 */
/* do not input/output */
-#define IN6_IFF_NOTREADY (IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED)
+#define IN6_IFF_NOTREADY (IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED)
+
+#ifdef _KERNEL
+#define IN6_ARE_SCOPE_CMP(a,b) ((a)-(b))
+#define IN6_ARE_SCOPE_EQUAL(a,b) ((a)==(b))
+#endif
#ifdef _KERNEL
-extern struct in6_ifaddr *in6_ifaddr;
-
-extern struct in6_ifstat **in6_ifstat;
-extern size_t in6_ifstatmax;
-extern struct icmp6stat icmp6stat;
-extern struct icmp6_ifstat **icmp6_ifstat;
-extern size_t icmp6_ifstatmax;
-#define in6_ifstat_inc(ifp, tag) \
+extern struct in6_ifaddr *in6_ifaddr;
+
+extern struct in6_ifstat **in6_ifstat;
+extern size_t in6_ifstatmax;
+extern struct icmp6stat icmp6stat;
+extern struct icmp6_ifstat **icmp6_ifstat;
+extern size_t icmp6_ifstatmax;
+#define in6_ifstat_inc(ifp, tag) \
do { \
if ((ifp) && (ifp)->if_index <= if_index \
&& (ifp)->if_index < in6_ifstatmax \
@@ -420,24 +445,25 @@ do { \
} \
} while (0)
-extern struct ifqueue ip6intrq; /* IP6 packet input queue */
-extern struct in6_addr zeroin6_addr;
-extern u_char inet6ctlerrmap[];
-extern u_long in6_maxmtu;
+extern struct ifqueue ip6intrq; /* IP6 packet input queue */
+extern struct in6_addr zeroin6_addr;
+extern u_char inet6ctlerrmap[];
+extern unsigned long in6_maxmtu;
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_IPMADDR);
-#endif /* MALLOC_DECLARE */
+#endif
/*
* Macro for finding the internet address structure (in6_ifaddr) corresponding
* to a given interface (ifnet structure).
*/
-#define IFP_TO_IA6(ifp, ia) \
+
+#define IFP_TO_IA6(ifp, ia) \
/* struct ifnet *ifp; */ \
/* struct in6_ifaddr *ia; */ \
do { \
struct ifaddr *ifa; \
- TAILQ_FOREACH(ifa, &(ifp)->if_addrlist, ifa_list) { \
+ for (ifa = (ifp)->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { \
if (!ifa->ifa_addr) \
continue; \
if (ifa->ifa_addr->sa_family == AF_INET6) \
@@ -445,6 +471,7 @@ do { \
} \
(ia) = (struct in6_ifaddr *)ifa; \
} while (0)
+
#endif /* _KERNEL */
/*
@@ -453,11 +480,11 @@ do { \
*/
struct in6_multi_mship {
struct in6_multi *i6mm_maddr; /* Multicast address pointer */
- LIST_ENTRY(in6_multi_mship) i6mm_chain; /* multicast options chain */
+ LIST_ENTRY(in6_multi_mship) i6mm_chain; /* multicast options chain */
};
struct in6_multi {
- LIST_ENTRY(in6_multi) in6m_entry; /* list glue */
+ LIST_ENTRY(in6_multi) in6m_entry; /* list glue */
struct in6_addr in6m_addr; /* IP6 multicast address */
struct ifnet *in6m_ifp; /* back pointer to ifnet */
struct ifmultiaddr *in6m_ifma; /* back pointer to ifmultiaddr */
@@ -467,11 +494,6 @@ struct in6_multi {
};
#ifdef _KERNEL
-
-#ifdef SYSCTL_DECL
-SYSCTL_DECL(_net_inet6_ip6);
-#endif
-
extern LIST_HEAD(in6_multihead, in6_multi) in6_multihead;
/*
@@ -489,7 +511,7 @@ struct in6_multistep {
* returns NLL.
*/
-#define IN6_LOOKUP_MULTI(addr, ifp, in6m) \
+#define IN6_LOOKUP_MULTI(addr, ifp, in6m) \
/* struct in6_addr addr; */ \
/* struct ifnet *ifp; */ \
/* struct in6_multi *in6m; */ \
@@ -512,48 +534,52 @@ do { \
* and get the first record. Both macros return a NULL "in6m" when there
* are no remaining records.
*/
-#define IN6_NEXT_MULTI(step, in6m) \
+#define IN6_NEXT_MULTI(step, in6m) \
/* struct in6_multistep step; */ \
/* struct in6_multi *in6m; */ \
do { \
if (((in6m) = (step).i_in6m) != NULL) \
- (step).i_in6m = LIST_NEXT((step).i_in6m, in6m_entry); \
+ (step).i_in6m = (step).i_in6m->in6m_entry.le_next; \
} while(0)
-#define IN6_FIRST_MULTI(step, in6m) \
+#define IN6_FIRST_MULTI(step, in6m) \
/* struct in6_multistep step; */ \
/* struct in6_multi *in6m */ \
do { \
- (step).i_in6m = LIST_FIRST(&in6_multihead); \
+ (step).i_in6m = in6_multihead.lh_first; \
IN6_NEXT_MULTI((step), (in6m)); \
} while(0)
-int in6_ifinit __P((struct ifnet *,
+int in6_ifinit __P((struct ifnet *,
struct in6_ifaddr *, struct sockaddr_in6 *, int));
-struct in6_multi *in6_addmulti __P((struct in6_addr *, struct ifnet *,
+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 void in6_len2mask __P((struct in6_addr *, int));
-int in6_control __P((struct socket *,
- u_long, caddr_t, struct ifnet *, struct proc *));
-void in6_savemkludge __P((struct in6_ifaddr *));
-void in6_setmaxmtu __P((void));
-void in6_restoremkludge __P((struct in6_ifaddr *, struct ifnet *));
-struct in6_ifaddr *in6ifa_ifpforlinklocal __P((struct ifnet *));
-struct in6_ifaddr *in6ifa_ifpwithaddr __P((struct ifnet *,
+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 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 *));
+void in6_savemkludge __P((struct in6_ifaddr *));
+void in6_setmaxmtu __P((void));
+void in6_restoremkludge __P((struct in6_ifaddr *, struct ifnet *));
+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 *));
-int in6_matchlen __P((struct in6_addr *, struct in6_addr *));
-int in6_are_prefix_equal __P((struct in6_addr *p1, struct in6_addr *p2,
+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,
int len));
-void in6_prefixlen2mask __P((struct in6_addr *maskp, int len));
-int in6_prefix_ioctl __P((struct socket *so, u_long cmd, caddr_t data,
+void in6_prefixlen2mask __P((struct in6_addr *maskp, int len));
+int in6_prefix_ioctl __P((struct socket *so, u_long cmd, caddr_t data,
struct ifnet *ifp));
-int in6_prefix_add_ifid __P((int iilen, struct in6_ifaddr *ia));
-void in6_prefix_remove_ifid __P((int iilen, struct in6_ifaddr *ia));
+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 *));
#endif /* _KERNEL */
#endif /* _NETINET6_IN6_VAR_H_ */
diff --git a/sys/netinet6/ip6.h b/sys/netinet6/ip6.h
index 14ab71d0908b..9eec13fb25ec 100644
--- a/sys/netinet6/ip6.h
+++ b/sys/netinet6/ip6.h
@@ -1,253 +1,4 @@
-/*
- * 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.
- *
- * $FreeBSD$
- */
+/* $FreeBSD$ */
+/* $KAME: ip6.h,v 1.7 2000/03/25 07:23:36 sumikawa Exp $ */
-/*
- * Copyright (c) 1982, 1986, 1993
- * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- *
- * @(#)ip.h 8.1 (Berkeley) 6/10/93
- */
-
-#ifndef _NETINET6_IPV6_H_
-#define _NETINET6_IPV6_H_
-
-#if !defined(_KERNEL) && !defined(__KAME_NETINET_IP6_H_INCLUDED_)
-#error "do not include netinet6/ip6.h directly, include netinet/ip6.h"
-#endif
-
-/*
- * Definition for internet protocol version 6.
- * RFC 2460
- */
-
-struct ip6_hdr {
- union {
- struct ip6_hdrctl {
- u_int32_t ip6_un1_flow; /* 4 bits version,
- * 8 bits traffic
- * class,
- * 20 bits flow-ID */
- u_int16_t ip6_un1_plen; /* payload length */
- u_int8_t ip6_un1_nxt; /* next header */
- u_int8_t ip6_un1_hlim; /* hop limit */
- } ip6_un1;
- u_int8_t ip6_un2_vfc; /* 4 bits version,
- * top 4 bits trafic class */
- } ip6_ctlun;
- struct in6_addr ip6_src; /* source address */
- struct in6_addr ip6_dst; /* destination address */
-};
-
-#define ip6_vfc ip6_ctlun.ip6_un2_vfc
-#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
-#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
-#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
-#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
-#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
-
-#define IPV6_VERSION 0x60
-#define IPV6_VERSION_MASK 0xf0
-
-#if BYTE_ORDER == BIG_ENDIAN
-#define IPV6_FLOWINFO_MASK 0x0fffffff /* flow info (28 bits) */
-#define IPV6_FLOWLABEL_MASK 0x000fffff /* flow label (20 bits) */
-#endif /* BIG_ENDIAN */
-#if BYTE_ORDER == LITTLE_ENDIAN
-#define IPV6_FLOWINFO_MASK 0xffffff0f /* flow info (28 bits) */
-#define IPV6_FLOWLABEL_MASK 0xffff0f00 /* flow label (20 bits) */
-#endif /* LITTLE_ENDIAN */
-/* ECN bits proposed by Sally Floyd */
-#define IP6TOS_CE 0x01 /* congestion experienced */
-#define IP6TOS_ECT 0x02 /* ECN-capable transport */
-
-/*
- * Extension Headers
- */
-
-struct ip6_ext {
- u_char ip6e_nxt;
- u_char ip6e_len;
-};
-
-/* Hop-by-Hop options header */
-/* XXX should we pad it to force alignment on an 8-byte boundary? */
-struct ip6_hbh {
- u_int8_t ip6h_nxt; /* next header */
- u_int8_t ip6h_len; /* length in units of 8 octets */
- /* followed by options */
-};
-
-/* Destination options header */
-/* XXX should we pad it to force alignment on an 8-byte boundary? */
-struct ip6_dest {
- u_int8_t ip6d_nxt; /* next header */
- u_int8_t ip6d_len; /* length in units of 8 octets */
- /* followed by options */
-};
-
-/* 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_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_TYPE(o) ((o) & 0xC0)
-#define IP6OPT_TYPE_SKIP 0x00
-#define IP6OPT_TYPE_DISCARD 0x40
-#define IP6OPT_TYPE_FORCEICMP 0x80
-#define IP6OPT_TYPE_ICMP 0xC0
-
-#define IP6OPT_MUTABLE 0x20
-
-/* Routing header */
-struct ip6_rthdr {
- u_int8_t ip6r_nxt; /* next header */
- u_int8_t ip6r_len; /* length in units of 8 octets */
- u_int8_t ip6r_type; /* routing type */
- u_int8_t ip6r_segleft; /* segments left */
- /* followed by routing type specific data */
-};
-
-/* Type 0 Routing header */
-struct ip6_rthdr0 {
- u_int8_t ip6r0_nxt; /* next header */
- u_int8_t ip6r0_len; /* length in units of 8 octets */
- u_int8_t ip6r0_type; /* always zero */
- u_int8_t ip6r0_segleft; /* segments left */
- 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 */
-};
-
-/* Fragment header */
-struct ip6_frag {
- u_int8_t ip6f_nxt; /* next header */
- u_int8_t ip6f_reserved; /* reserved field */
- u_int16_t ip6f_offlg; /* offset, reserved, and flag */
- u_int32_t ip6f_ident; /* identification */
-};
-
-#if BYTE_ORDER == BIG_ENDIAN
-#define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */
-#define IP6F_RESERVED_MASK 0x0006 /* reserved bits in ip6f_offlg */
-#define IP6F_MORE_FRAG 0x0001 /* more-fragments flag */
-#else /* BYTE_ORDER == LITTLE_ENDIAN */
-#define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */
-#define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */
-#define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */
-#endif /* BYTE_ORDER == LITTLE_ENDIAN */
-
-/*
- * Internet implementation parameters.
- */
-#define IPV6_MAXHLIM 255 /* maximun hoplimit */
-#define IPV6_DEFHLIM 64 /* default hlim */
-#define IPV6_FRAGTTL 120 /* ttl for fragment packets, in slowtimo tick */
-#define IPV6_HLIMDEC 1 /* subtracted when forwaeding */
-
-#define IPV6_MMTU 1280 /* minimal MTU and reassembly. 1024 + 256 */
-#define IPV6_MAXPACKET 65535 /* ip6 max packet size without Jumbo payload*/
-
-/*
- * IP6_EXTHDR_CHECK ensures that region between the IP6 header and the
- * target header (including IPv6 itself, extension headers and
- * TCP/UDP/ICMP6 headers) are continuous. KAME requires drivers
- * to store incoming data into one internal mbuf or one or more external
- * mbufs(never into two or more internal mbufs). Thus, the third case is
- * supposed to never be matched but is prepared just in case.
- */
-
-#define IP6_EXTHDR_CHECK(m, off, hlen, ret) \
-do { \
- if ((m)->m_next != NULL) { \
- if (((m)->m_flags & M_LOOP) && \
- ((m)->m_len < (off) + (hlen)) && \
- (((m) = m_pullup((m), (off) + (hlen))) == NULL)) { \
- ip6stat.ip6s_exthdrtoolong++; \
- return ret; \
- } else if ((m)->m_flags & M_EXT) { \
- if ((m)->m_len < (off) + (hlen)) { \
- ip6stat.ip6s_exthdrtoolong++; \
- m_freem(m); \
- return ret; \
- } \
- } else { \
- if ((m)->m_len < (off) + (hlen)) { \
- ip6stat.ip6s_exthdrtoolong++; \
- m_freem(m); \
- return ret; \
- } \
- } \
- } else { \
- if ((m)->m_len < (off) + (hlen)) { \
- ip6stat.ip6s_tooshort++; \
- in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); \
- m_freem(m); \
- return ret; \
- } \
- } \
-} while (0)
-
-#endif /* not _NETINET_IPV6_H_ */
+#error "netinet6/ip6.h is obsolete. use netinet/ip6.h"
diff --git a/sys/netinet6/ip6_ecn.h b/sys/netinet6/ip6_ecn.h
index ede21bcc9b7e..e8dd11f71107 100644
--- a/sys/netinet6/ip6_ecn.h
+++ b/sys/netinet6/ip6_ecn.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip_ecn.h,v 1.5 2000/03/27 04:58:38 sumikawa Exp $ */
+
/*
* Copyright (C) 1999 WIDE Project.
* All rights reserved.
@@ -26,8 +29,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: ip_ecn.h,v 1.2 1999/08/19 12:57:44 itojun Exp $
- * $FreeBSD$
*/
/*
* ECN consideration on tunnel ingress/egress operation.
@@ -38,6 +39,3 @@
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 *));
#endif
-
-
-
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index 249d38ca54d7..ba9bdad797bb 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip6_forward.c,v 1.39 2000/07/03 13:23:28 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,10 +28,11 @@
* 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.
- *
- * $FreeBSD$
*/
+#include "opt_ip6fw.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_ipsec.h"
#include <sys/param.h>
@@ -46,20 +50,15 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#include <netinet6/nd6.h>
#ifdef IPSEC_IPV6FWD
#include <netinet6/ipsec.h>
-#include <netinet6/ipsec6.h>
#include <netkey/key.h>
-#ifdef IPSEC_DEBUG
-#include <netkey/key_debug.h>
-#else
-#define KEYDEBUG(lev,arg)
-#endif
#endif /* IPSEC_IPV6FWD */
#ifdef IPV6FIREWALL
@@ -92,7 +91,8 @@ ip6_forward(m, srcrt)
register struct sockaddr_in6 *dst;
register struct rtentry *rt;
int error, type = 0, code = 0;
- struct mbuf *mcopy;
+ struct mbuf *mcopy = NULL;
+ struct ifnet *origifp; /* maybe unnecessary */
#ifdef IPSEC_IPV6FWD
struct secpolicy *sp = NULL;
#endif
@@ -112,19 +112,17 @@ ip6_forward(m, srcrt)
}
#endif /*IPSEC_IPV6FWD*/
- if (m->m_flags & (M_BCAST|M_MCAST) ||
- in6_canforward(&ip6->ip6_src, &ip6->ip6_dst) == 0) {
+ if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
+ IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
ip6stat.ip6s_cantforward++;
- ip6stat.ip6s_badscope++;
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
if (ip6_log_time + ip6_log_interval < time_second) {
- char addr[INET6_ADDRSTRLEN];
ip6_log_time = time_second;
- strncpy(addr, ip6_sprintf(&ip6->ip6_src), sizeof(addr));
log(LOG_DEBUG,
"cannot forward "
"from %s to %s nxt %d received on %s\n",
- addr, ip6_sprintf(&ip6->ip6_dst),
+ ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&ip6->ip6_dst),
ip6->ip6_nxt,
if_name(m->m_pkthdr.rcvif));
}
@@ -140,13 +138,30 @@ ip6_forward(m, srcrt)
}
ip6->ip6_hlim -= IPV6_HLIMDEC;
+ /*
+ * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
+ * size of IPv6 + ICMPv6 headers) bytes of the packet in case
+ * we need to generate an ICMP6 message to the src.
+ * Thanks to M_EXT, in most cases copy will not occur.
+ *
+ * It is important to save it before IPsec processing as IPsec
+ * processing may modify the mbuf.
+ */
+ mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
+
#ifdef IPSEC_IPV6FWD
/* get a security policy for this packet */
sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error);
if (sp == NULL) {
ipsec6stat.out_inval++;
ip6stat.ip6s_cantforward++;
- /* XXX: any icmp ? */
+ if (mcopy) {
+#if 0
+ /* XXX: what icmp ? */
+#else
+ m_freem(mcopy);
+#endif
+ }
m_freem(m);
return;
}
@@ -162,7 +177,13 @@ ip6_forward(m, srcrt)
ipsec6stat.out_polvio++;
ip6stat.ip6s_cantforward++;
key_freesp(sp);
- /* XXX: any icmp ? */
+ if (mcopy) {
+#if 0
+ /* XXX: what icmp ? */
+#else
+ m_freem(mcopy);
+#endif
+ }
m_freem(m);
return;
@@ -171,14 +192,20 @@ ip6_forward(m, srcrt)
/* no need to do IPsec. */
key_freesp(sp);
goto skip_ipsec;
-
+
case IPSEC_POLICY_IPSEC:
if (sp->req == NULL) {
/* XXX should be panic ? */
printf("ip6_forward: No IPsec request specified.\n");
ip6stat.ip6s_cantforward++;
key_freesp(sp);
- /* XXX: any icmp ? */
+ if (mcopy) {
+#if 0
+ /* XXX: what icmp ? */
+#else
+ m_freem(mcopy);
+#endif
+ }
m_freem(m);
return;
}
@@ -212,7 +239,10 @@ ip6_forward(m, srcrt)
error = ipsec6_output_tunnel(&state, sp, 0);
m = state.m;
- /* XXX allocate a route (ro, dst) again later */
+#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) {
@@ -232,7 +262,13 @@ ip6_forward(m, srcrt)
break;
}
ip6stat.ip6s_cantforward++;
- /* XXX: any icmp ? */
+ if (mcopy) {
+#if 0
+ /* XXX: what icmp ? */
+#else
+ m_freem(mcopy);
+#endif
+ }
m_freem(m);
return;
}
@@ -255,12 +291,15 @@ 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) */
- icmp6_error(m, ICMP6_DST_UNREACH,
- ICMP6_DST_UNREACH_NOROUTE, 0);
+ if (mcopy) {
+ icmp6_error(mcopy, ICMP6_DST_UNREACH,
+ ICMP6_DST_UNREACH_NOROUTE, 0);
+ }
+ m_freem(m);
return;
}
} else if ((rt = ip6_forward_rt.ro_rt) == 0 ||
@@ -278,26 +317,89 @@ ip6_forward(m, srcrt)
if (ip6_forward_rt.ro_rt == 0) {
ip6stat.ip6s_noroute++;
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
- icmp6_error(m, ICMP6_DST_UNREACH,
- ICMP6_DST_UNREACH_NOROUTE, 0);
+ if (mcopy) {
+ icmp6_error(mcopy, ICMP6_DST_UNREACH,
+ ICMP6_DST_UNREACH_NOROUTE, 0);
+ }
+ m_freem(m);
return;
}
}
rt = ip6_forward_rt.ro_rt;
- if (m->m_pkthdr.len > rt->rt_ifp->if_mtu){
+
+ /*
+ * Scope check: if a packet can't be delivered to its destination
+ * for the reason that the destination is beyond the scope of the
+ * source address, discard the packet and return an icmp6 destination
+ * unreachable error with Code 2 (beyond scope of source address).
+ * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1]
+ */
+ if (in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_src) !=
+ in6_addr2scopeid(rt->rt_ifp, &ip6->ip6_src)) {
+ ip6stat.ip6s_cantforward++;
+ ip6stat.ip6s_badscope++;
+ in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
+
+ if (ip6_log_time + ip6_log_interval < time_second) {
+ ip6_log_time = time_second;
+ log(LOG_DEBUG,
+ "cannot forward "
+ "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
+ ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&ip6->ip6_dst),
+ ip6->ip6_nxt,
+ if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp));
+ }
+ if (mcopy)
+ icmp6_error(mcopy, ICMP6_DST_UNREACH,
+ ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
+ m_freem(m);
+ return;
+ }
+
+ if (m->m_pkthdr.len > rt->rt_ifp->if_mtu) {
in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
- icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, rt->rt_ifp->if_mtu);
+ if (mcopy) {
+ u_long mtu;
+#ifdef IPSEC_IPV6FWD
+ struct secpolicy *sp;
+ int ipsecerror;
+ size_t ipsechdrsiz;
+#endif
+
+ mtu = rt->rt_ifp->if_mtu;
+#ifdef IPSEC_IPV6FWD
+ /*
+ * When we do IPsec tunnel ingress, we need to play
+ * with if_mtu value (decrement IPsec header size
+ * from mtu value). The code is much simpler than v4
+ * case, as we have the outgoing interface for
+ * encapsulated packet as "rt->rt_ifp".
+ */
+ sp = ipsec6_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND,
+ IP_FORWARDING, &ipsecerror);
+ if (sp) {
+ ipsechdrsiz = ipsec6_hdrsiz(mcopy,
+ IPSEC_DIR_OUTBOUND, NULL);
+ if (ipsechdrsiz < mtu)
+ mtu -= ipsechdrsiz;
+ }
+
+ /*
+ * if mtu becomes less than minimum MTU,
+ * tell minimum MTU (and I'll need to fragment it).
+ */
+ if (mtu < IPV6_MMTU)
+ mtu = IPV6_MMTU;
+#endif
+ icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
+ }
+ m_freem(m);
return;
}
if (rt->rt_flags & RTF_GATEWAY)
dst = (struct sockaddr_in6 *)rt->rt_gateway;
- /*
- * Save at most 528 bytes of the packet in case
- * we need to generate an ICMP6 message to the src.
- * Thanks to M_EXT, in most cases copy will not occur.
- */
- mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
/*
* If we are to forward the packet using the same interface
@@ -328,7 +430,66 @@ ip6_forward(m, srcrt)
}
#endif
- error = nd6_output(rt->rt_ifp, m, dst, rt);
+ /*
+ * Fake scoped addresses. Note that even link-local source or
+ * 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.
+ */
+ if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
+ /*
+ * See corresponding comments in ip6_output.
+ * XXX: but is it possible that ip6_forward() sends a packet
+ * to a loopback interface? I don't think so, and thus
+ * I bark here. (jinmei@kame.net)
+ * XXX: it is common to route invalid packets to loopback.
+ * also, the codepath will be visited on use of ::1 in
+ * rthdr. (itojun)
+ */
+#if 1
+ if (0)
+#else
+ if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
+#endif
+ {
+ printf("ip6_forward: outgoing interface is loopback. "
+ "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
+ ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&ip6->ip6_dst),
+ ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
+ 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;
+ }
+ else
+ origifp = rt->rt_ifp;
+#ifndef FAKE_LOOPBACK_IF
+ if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
+#else
+ if (1)
+#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++;
@@ -347,10 +508,12 @@ ip6_forward(m, srcrt)
switch (error) {
case 0:
+#if 1
if (type == ND_REDIRECT) {
icmp6_redirect_output(mcopy, rt);
return;
}
+#endif
goto freecopy;
case EMSGSIZE:
diff --git a/sys/netinet6/ip6_fw.c b/sys/netinet6/ip6_fw.c
index d6b4ca2960ed..1ec33a141ca3 100644
--- a/sys/netinet6/ip6_fw.c
+++ b/sys/netinet6/ip6_fw.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip6_fw.c,v 1.15 2000/07/02 14:17:37 itojun Exp $ */
+
/*
* Copyright (c) 1993 Daniel Boulet
* Copyright (c) 1994 Ugen J.S.Antsilevich
@@ -11,9 +14,6 @@
* but requiring it would be too onerous.
*
* This software is provided ``AS IS'' without any warranties of any kind.
- *
- * $Id: ip6_fw.c,v 1.7 1999/08/31 12:25:57 shin Exp $
- * $FreeBSD$
*/
/*
@@ -21,6 +21,15 @@
*/
#include "opt_ip6fw.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#ifdef IP6DIVERT
+#error "NOT SUPPORTED IPV6 DIVERT"
+#endif
+#ifdef IP6FW_DIVERT_RESTART
+#error "NOT SUPPORTED IPV6 DIVERT"
+#endif
#include <sys/param.h>
#include <sys/systm.h>
@@ -36,10 +45,14 @@
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
-#include <netinet/in_pcb.h>
+
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
#include <netinet6/in6_var.h>
-#include <netinet6/ip6.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
+
+#include <netinet/in_pcb.h>
+
#include <netinet6/ip6_fw.h>
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
@@ -76,11 +89,11 @@ 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, "");
#endif
-#define dprintf(a) if (!fw6_debug); else printf a
+#define dprintf(a) if (!fw6_debug); else printf a
-#define print_ip6(a) printf("[%s]", ip6_sprintf(a))
+#define print_ip6(a) printf("[%s]", ip6_sprintf(a))
-#define dprint_ip6(a) if (!fw6_debug); else print_ip6(a)
+#define dprint_ip6(a) if (!fw6_debug); else print_ip6(a)
static int add_entry6 __P((struct ip6_fw_head *chainptr, struct ip6_fw *frwl));
static int del_entry6 __P((struct ip6_fw_head *chainptr, u_short number));
@@ -131,7 +144,7 @@ static int
tcp6flg_match(struct tcphdr *tcp6, struct ip6_fw *f)
{
u_char flg_set, flg_clr;
-
+
if ((f->fw_tcpf & IPV6_FW_TCPF_ESTAB) &&
(tcp6->th_flags & (IPV6_FW_TCPF_RST | IPV6_FW_TCPF_ACK)))
return 1;
@@ -344,7 +357,7 @@ ip6fw_report(struct ip6_fw *f, struct ip6_hdr *ip6,
case IPV6_FW_F_SKIPTO:
printf("SkipTo %d", f->fw_skipto_rule);
break;
- default:
+ default:
printf("UNKNOWN");
break;
}
@@ -468,7 +481,7 @@ ip6_fw_chk(struct ip6_hdr **pip6,
continue;
}
-#define IN6_ARE_ADDR_MASKEQUAL(x,y,z) (\
+#define IN6_ARE_ADDR_MASKEQUAL(x,y,z) (\
(((x)->s6_addr32[0] & (y)->s6_addr32[0]) == (z)->s6_addr32[0]) && \
(((x)->s6_addr32[1] & (y)->s6_addr32[1]) == (z)->s6_addr32[1]) && \
(((x)->s6_addr32[2] & (y)->s6_addr32[2]) == (z)->s6_addr32[2]) && \
@@ -522,7 +535,7 @@ ip6_fw_chk(struct ip6_hdr **pip6,
if (nxt != f->fw_prot)
continue;
-#define PULLUP_TO(len) do { \
+#define PULLUP_TO(len) do { \
if ((*m)->m_len < (len) \
&& (*m = m_pullup(*m, (len))) == 0) { \
goto dropit; \
@@ -780,7 +793,7 @@ add_entry6(struct ip6_fw_head *chainptr, struct ip6_fw *frwl)
ftmp->fw_pcnt = 0L;
ftmp->fw_bcnt = 0L;
fwc->rule = ftmp;
-
+
s = splnet();
if (!chainptr->lh_first) {
diff --git a/sys/netinet6/ip6_fw.h b/sys/netinet6/ip6_fw.h
index a356ac3cca41..6b4c9221518f 100644
--- a/sys/netinet6/ip6_fw.h
+++ b/sys/netinet6/ip6_fw.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip6_fw.h,v 1.3 2000/04/06 08:30:44 sumikawa Exp $ */
+
/*
* Copyright (c) 1993 Daniel Boulet
* Copyright (c) 1994 Ugen J.S.Antsilevich
@@ -11,8 +14,6 @@
*
* This software is provided ``AS IS'' without any warranties of any kind.
*
- * $Id: ip6_fw.h,v 1.1 1999/08/06 14:10:09 itojun Exp $
- * $FreeBSD$
*/
#ifndef _IP6_FW_H
@@ -34,11 +35,11 @@
*/
union ip6_fw_if {
- struct in6_addr fu_via_ip6; /* Specified by IPv6 address */
- struct { /* Specified by interface name */
+ struct in6_addr fu_via_ip6; /* Specified by IPv6 address */
+ struct { /* Specified by interface name */
#define FW_IFNLEN IFNAMSIZ
- char name[FW_IFNLEN];
- short unit; /* -1 means match any unit */
+ char name[FW_IFNLEN];
+ short unit; /* -1 means match any unit */
} fu_via_if;
};
@@ -52,95 +53,89 @@ union ip6_fw_if {
*/
struct ip6_fw {
- u_long fw_pcnt,fw_bcnt; /* Packet and byte counters */
- struct in6_addr fw_src, fw_dst; /* Source and destination IPv6 addr */
- /* Mask for src and dest IPv6 addr */
- struct in6_addr fw_smsk, fw_dmsk;
- u_short fw_number; /* Rule number */
- u_short fw_flg; /* Flags word */
-#define IPV6_FW_MAX_PORTS 10 /* A reasonable maximum */
- /* Array of port numbers to match */
- u_short fw_pts[IPV6_FW_MAX_PORTS];
- u_char fw_ip6opt,fw_ip6nopt; /* IPv6 options set/unset */
- u_char fw_tcpf,fw_tcpnf; /* TCP flags set/unset */
-#define IPV6_FW_ICMPTYPES_DIM (32 / (sizeof(unsigned) * 8))
- /* ICMP types bitmap */
- unsigned fw_icmp6types[IPV6_FW_ICMPTYPES_DIM];
- long timestamp; /* timestamp (tv_sec) of last match */
- /* Incoming and outgoing interfaces */
- union ip6_fw_if fw_in_if, fw_out_if;
- union {
- u_short fu_divert_port; /* Divert/tee port (options IP6DIVERT) */
- u_short fu_skipto_rule; /* SKIPTO command rule number */
- u_short fu_reject_code; /* REJECT response code */
- } fw_un;
- u_char fw_prot; /* IPv6 protocol */
- u_char fw_nports; /* N'of src ports and # of dst ports */
- /* in ports array (dst ports follow */
- /* src ports; max of 10 ports in all; */
- /* count of 0 means match all ports) */
+ u_long fw_pcnt,fw_bcnt; /* Packet and byte counters */
+ struct in6_addr fw_src, fw_dst; /* Source and destination IPv6 addr */
+ struct in6_addr fw_smsk, fw_dmsk; /* Mask for src and dest IPv6 addr */
+ u_short fw_number; /* Rule number */
+ u_short fw_flg; /* Flags word */
+#define IPV6_FW_MAX_PORTS 10 /* A reasonable maximum */
+ u_short fw_pts[IPV6_FW_MAX_PORTS]; /* Array of port numbers to match */
+ u_char fw_ip6opt,fw_ip6nopt; /* IPv6 options set/unset */
+ u_char fw_tcpf,fw_tcpnf; /* TCP flags set/unset */
+#define IPV6_FW_ICMPTYPES_DIM (32 / (sizeof(unsigned) * 8))
+ unsigned fw_icmp6types[IPV6_FW_ICMPTYPES_DIM]; /* ICMP types bitmap */
+ long timestamp; /* timestamp (tv_sec) of last match */
+ union ip6_fw_if fw_in_if, fw_out_if;/* Incoming and outgoing interfaces */
+ union {
+ u_short fu_divert_port; /* Divert/tee port (options IP6DIVERT) */
+ u_short fu_skipto_rule; /* SKIPTO command rule number */
+ u_short fu_reject_code; /* REJECT response code */
+ } fw_un;
+ u_char fw_prot; /* IPv6 protocol */
+ u_char fw_nports; /* N'of src ports and # of dst ports */
+ /* in ports array (dst ports follow */
+ /* src ports; max of 10 ports in all; */
+ /* count of 0 means match all ports) */
};
-#define IPV6_FW_GETNSRCP(rule) ((rule)->fw_nports & 0x0f)
-#define IPV6_FW_SETNSRCP(rule, n) do { \
+#define IPV6_FW_GETNSRCP(rule) ((rule)->fw_nports & 0x0f)
+#define IPV6_FW_SETNSRCP(rule, n) do { \
(rule)->fw_nports &= ~0x0f; \
(rule)->fw_nports |= (n); \
} while (0)
-#define IPV6_FW_GETNDSTP(rule) ((rule)->fw_nports >> 4)
-#define IPV6_FW_SETNDSTP(rule, n) do { \
+#define IPV6_FW_GETNDSTP(rule) ((rule)->fw_nports >> 4)
+#define IPV6_FW_SETNDSTP(rule, n) do { \
(rule)->fw_nports &= ~0xf0; \
(rule)->fw_nports |= (n) << 4;\
} while (0)
-#define fw_divert_port fw_un.fu_divert_port
-#define fw_skipto_rule fw_un.fu_skipto_rule
-#define fw_reject_code fw_un.fu_reject_code
+#define fw_divert_port fw_un.fu_divert_port
+#define fw_skipto_rule fw_un.fu_skipto_rule
+#define fw_reject_code fw_un.fu_reject_code
-struct ip6_fw_chain {
- LIST_ENTRY(ip6_fw_chain) chain;
- struct ip6_fw *rule;
+struct ip6_fw_chain {
+ LIST_ENTRY(ip6_fw_chain) chain;
+ struct ip6_fw *rule;
};
/*
* Values for "flags" field .
*/
-#define IPV6_FW_F_IN 0x0001 /* Check inbound packets */
-#define IPV6_FW_F_OUT 0x0002 /* Check outbound packets */
-#define IPV6_FW_F_IIFACE 0x0004 /* Apply inbound interface test */
-#define IPV6_FW_F_OIFACE 0x0008 /* Apply outbound interface test */
-
-#define IPV6_FW_F_COMMAND 0x0070 /* Mask for type of chain entry: */
-#define IPV6_FW_F_DENY 0x0000 /* This is a deny rule */
-#define IPV6_FW_F_REJECT 0x0010 /* Deny and send a response packet */
-#define IPV6_FW_F_ACCEPT 0x0020 /* This is an accept rule */
-#define IPV6_FW_F_COUNT 0x0030 /* This is a count rule */
-#define IPV6_FW_F_DIVERT 0x0040 /* This is a divert rule */
-#define IPV6_FW_F_TEE 0x0050 /* This is a tee rule */
-#define IPV6_FW_F_SKIPTO 0x0060 /* This is a skipto rule */
-
-#define IPV6_FW_F_PRN 0x0080 /* Print if this rule matches */
-
-#define IPV6_FW_F_SRNG 0x0100 /* The first two src ports are a min *
- * and max range (stored in host byte *
- * order). */
-
-#define IPV6_FW_F_DRNG 0x0200 /* The first two dst ports are a min *
+#define IPV6_FW_F_IN 0x0001 /* Check inbound packets */
+#define IPV6_FW_F_OUT 0x0002 /* Check outbound packets */
+#define IPV6_FW_F_IIFACE 0x0004 /* Apply inbound interface test */
+#define IPV6_FW_F_OIFACE 0x0008 /* Apply outbound interface test */
+
+#define IPV6_FW_F_COMMAND 0x0070 /* Mask for type of chain entry: */
+#define IPV6_FW_F_DENY 0x0000 /* This is a deny rule */
+#define IPV6_FW_F_REJECT 0x0010 /* Deny and send a response packet */
+#define IPV6_FW_F_ACCEPT 0x0020 /* This is an accept rule */
+#define IPV6_FW_F_COUNT 0x0030 /* This is a count rule */
+#define IPV6_FW_F_DIVERT 0x0040 /* This is a divert rule */
+#define IPV6_FW_F_TEE 0x0050 /* This is a tee rule */
+#define IPV6_FW_F_SKIPTO 0x0060 /* This is a skipto rule */
+
+#define IPV6_FW_F_PRN 0x0080 /* Print if this rule matches */
+
+#define IPV6_FW_F_SRNG 0x0100 /* The first two src ports are a min *
+ * and max range (stored in host byte *
+ * order). */
+
+#define IPV6_FW_F_DRNG 0x0200 /* The first two dst ports are a min *
* and max range (stored in host byte *
* order). */
-/* In interface by name/unit (not IP) */
-#define IPV6_FW_F_IIFNAME 0x0400
-/* Out interface by name/unit (not IP) */
-#define IPV6_FW_F_OIFNAME 0x0800
+#define IPV6_FW_F_IIFNAME 0x0400 /* In interface by name/unit (not IP) */
+#define IPV6_FW_F_OIFNAME 0x0800 /* Out interface by name/unit (not IP) */
-#define IPV6_FW_F_INVSRC 0x1000 /* Invert sense of src check */
-#define IPV6_FW_F_INVDST 0x2000 /* Invert sense of dst check */
+#define IPV6_FW_F_INVSRC 0x1000 /* Invert sense of src check */
+#define IPV6_FW_F_INVDST 0x2000 /* Invert sense of dst check */
-#define IPV6_FW_F_FRAG 0x4000 /* Fragment */
+#define IPV6_FW_F_FRAG 0x4000 /* Fragment */
-#define IPV6_FW_F_ICMPBIT 0x8000 /* ICMP type bitmap is valid */
+#define IPV6_FW_F_ICMPBIT 0x8000 /* ICMP type bitmap is valid */
-#define IPV6_FW_F_MASK 0xFFFF /* All possible flag bits mask */
+#define IPV6_FW_F_MASK 0xFFFF /* All possible flag bits mask */
/*
* For backwards compatibility with rules specifying "via iface" but
@@ -148,36 +143,35 @@ struct ip6_fw_chain {
* of bits to represent this configuration.
*/
-#define IF6_FW_F_VIAHACK (IPV6_FW_F_IN|IPV6_FW_F_OUT|IPV6_FW_F_IIFACE|\
- IPV6_FW_F_OIFACE)
+#define IF6_FW_F_VIAHACK (IPV6_FW_F_IN|IPV6_FW_F_OUT|IPV6_FW_F_IIFACE|IPV6_FW_F_OIFACE)
/*
* Definitions for REJECT response codes.
* Values less than 256 correspond to ICMP unreachable codes.
*/
-#define IPV6_FW_REJECT_RST 0x0100 /* TCP packets: send RST */
+#define IPV6_FW_REJECT_RST 0x0100 /* TCP packets: send RST */
/*
* Definitions for IPv6 option names.
*/
-#define IPV6_FW_IP6OPT_HOPOPT 0x01
-#define IPV6_FW_IP6OPT_ROUTE 0x02
-#define IPV6_FW_IP6OPT_FRAG 0x04
-#define IPV6_FW_IP6OPT_ESP 0x08
-#define IPV6_FW_IP6OPT_AH 0x10
-#define IPV6_FW_IP6OPT_NONXT 0x20
-#define IPV6_FW_IP6OPT_OPTS 0x40
+#define IPV6_FW_IP6OPT_HOPOPT 0x01
+#define IPV6_FW_IP6OPT_ROUTE 0x02
+#define IPV6_FW_IP6OPT_FRAG 0x04
+#define IPV6_FW_IP6OPT_ESP 0x08
+#define IPV6_FW_IP6OPT_AH 0x10
+#define IPV6_FW_IP6OPT_NONXT 0x20
+#define IPV6_FW_IP6OPT_OPTS 0x40
/*
* Definitions for TCP flags.
*/
-#define IPV6_FW_TCPF_FIN TH_FIN
-#define IPV6_FW_TCPF_SYN TH_SYN
-#define IPV6_FW_TCPF_RST TH_RST
-#define IPV6_FW_TCPF_PSH TH_PUSH
-#define IPV6_FW_TCPF_ACK TH_ACK
-#define IPV6_FW_TCPF_URG TH_URG
-#define IPV6_FW_TCPF_ESTAB 0x40
+#define IPV6_FW_TCPF_FIN TH_FIN
+#define IPV6_FW_TCPF_SYN TH_SYN
+#define IPV6_FW_TCPF_RST TH_RST
+#define IPV6_FW_TCPF_PSH TH_PUSH
+#define IPV6_FW_TCPF_ACK TH_ACK
+#define IPV6_FW_TCPF_URG TH_URG
+#define IPV6_FW_TCPF_ESTAB 0x40
/*
* Main firewall chains definitions and global var's definitions.
@@ -187,13 +181,13 @@ struct ip6_fw_chain {
/*
* Function definitions.
*/
-void ip6_fw_init(void);
+void ip6_fw_init(void);
/* Firewall hooks */
-struct ip6_hdr;
-typedef int ip6_fw_chk_t __P((struct ip6_hdr**, struct ifnet*,
+struct ip6_hdr;
+typedef int ip6_fw_chk_t __P((struct ip6_hdr**, struct ifnet*,
u_short *, struct mbuf**));
-typedef int ip6_fw_ctl_t __P((int, struct mbuf**));
+typedef int ip6_fw_ctl_t __P((int, struct mbuf**));
extern ip6_fw_chk_t *ip6_fw_chk_ptr;
extern ip6_fw_ctl_t *ip6_fw_ctl_ptr;
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index 449a4f3afe10..870bdd91ce0f 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip6_input.c,v 1.95 2000/07/02 07:49:37 jinmei Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -64,8 +65,10 @@
* @(#)ip_input.c 8.2 (Berkeley) 1/4/94
*/
-#include "opt_ipsec.h"
#include "opt_ip6fw.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#include "opt_ipsec.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -89,13 +92,15 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
+#ifdef INET
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
-#include <netinet/in_pcb.h>
+#endif /*INET*/
+#include <netinet/ip6.h>
#include <netinet6/in6_var.h>
-#include <netinet6/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/in_pcb.h>
+#include <netinet/icmp6.h>
#include <netinet6/in6_ifattach.h>
#include <netinet6/nd6.h>
#include <netinet6/in6_prefix.h>
@@ -104,50 +109,40 @@
#include <netinet6/ip6_fw.h>
#endif
-#ifdef ALTQ
-#include <netinet/altq_cdnr.h>
-#endif
-
#include <netinet6/ip6protosw.h>
/* we need it for NLOOP. */
#include "loop.h"
-
#include "faith.h"
#include "gif.h"
#include <net/net_osdep.h>
-extern struct domain inet6domain;
-extern struct ip6protosw inet6sw[];
+extern struct domain inet6domain;
+extern struct ip6protosw inet6sw[];
-u_char ip6_protox[IPPROTO_MAX];
-static int ip6qmaxlen = IFQ_MAXLEN;
-struct in6_ifaddr *in6_ifaddr;
+u_char ip6_protox[IPPROTO_MAX];
+static int ip6qmaxlen = IFQ_MAXLEN;
+struct in6_ifaddr *in6_ifaddr;
-int ip6_forward_srcrt; /* XXX */
-int ip6_sourcecheck; /* XXX */
-int ip6_sourcecheck_interval; /* XXX */
-
-const int int6intrq_present = 1;
+int ip6_forward_srcrt; /* XXX */
+int ip6_sourcecheck; /* XXX */
+int ip6_sourcecheck_interval; /* XXX */
+const int int6intrq_present = 1;
#ifdef IPV6FIREWALL
/* firewall hooks */
-ip6_fw_chk_t *ip6_fw_chk_ptr;
-ip6_fw_ctl_t *ip6_fw_ctl_ptr;
+ip6_fw_chk_t *ip6_fw_chk_ptr;
+ip6_fw_ctl_t *ip6_fw_ctl_ptr;
#endif
-struct ip6stat ip6stat;
-
-static void ip6_init2 __P((void *));
+struct ip6stat ip6stat;
-static int ip6_hopopts_input __P((u_int32_t *, u_int32_t *, struct mbuf **, int *));
+static void ip6_init2 __P((void *));
-#if defined(PTR)
-extern int ip6_protocol_tr;
-
-int ptr_in6 __P((struct mbuf *, struct mbuf **));
-extern void ip_forward __P((struct mbuf *, int));
+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
/*
@@ -190,22 +185,12 @@ static void
ip6_init2(dummy)
void *dummy;
{
- int i;
- int ret;
-
- /* get EUI64 from somewhere */
- ret = in6_ifattach_getifid(NULL);
/*
* to route local address of p2p link to loopback,
* assign loopback address first.
*/
- for (i = 0; i < NLOOP; i++)
- in6_ifattach(&loif[i], IN6_IFT_LOOP, NULL, 0);
-
- /* attach pseudo interfaces */
- if (ret == 0)
- in6_ifattach_p2p();
+ in6_ifattach(&loif[0], NULL);
/* nd6_timer_init */
timeout(nd6_timer, (caddr_t)0, hz);
@@ -283,7 +268,10 @@ ip6_input(m)
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive);
ip6stat.ip6s_total++;
+#ifndef PULLDOWN_TEST
+ /* XXX is the line really necessary? */
IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /*nothing*/);
+#endif
if (m->m_len < sizeof(struct ip6_hdr)) {
struct ifnet *inifp;
@@ -322,13 +310,6 @@ ip6_input(m)
}
#endif
-#ifdef ALTQ
- if (altq_input != NULL && (*altq_input)(m, AF_INET6) == 0) {
- /* packet is dropped by traffic conditioner */
- return;
- }
-#endif
-
/*
* Scope check
*/
@@ -338,22 +319,46 @@ ip6_input(m)
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.
+ */
+#if 0
+ /*
+ * Reject packets with IPv4 compatible addresses (auto tunnel).
+ *
+ * The code forbids auto tunnel relay case in RFC1933 (the check is
+ * stronger than RFC1933). We may want to re-enable it if mech-xx
+ * is revised to forbid relaying case.
+ */
+ if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) ||
+ IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) {
+ ip6stat.ip6s_badscope++;
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
+ 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) == 0) {
+ if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) {
+ ours = 1;
+ deliverifp = m->m_pkthdr.rcvif;
+ goto hbhcheck;
+ } else {
ip6stat.ip6s_badscope++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
goto bad;
}
}
- if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) {
- if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) {
- ours = 1;
- deliverifp = m->m_pkthdr.rcvif;
- goto hbhcheck;
- }
- } else {
+#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);
@@ -362,32 +367,20 @@ ip6_input(m)
= htons(m->m_pkthdr.rcvif->if_index);
}
-#if defined(PTR)
/*
- *
+ * 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.
*/
- if (ip6_protocol_tr)
- {
- struct mbuf *m1 = NULL;
-
- switch (ptr_in6(m, &m1))
- {
- case IPPROTO_IP: goto mcastcheck;
- case IPPROTO_IPV4: ip_forward(m1, 0); break;
- case IPPROTO_IPV6: ip6_forward(m1, 0); break;
- case IPPROTO_MAX: /* discard this packet */
- default:
- }
-
- if (m != m1)
- m_freem(m);
-
- return;
+ if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) != 0) {
+ if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) {
+ ours = 1;
+ deliverifp = m->m_pkthdr.rcvif;
+ goto hbhcheck;
+ }
}
- mcastcheck:
-#endif
-
/*
* Multicast check
*/
@@ -415,17 +408,27 @@ ip6_input(m)
/*
* Unicast check
*/
- if (ip6_forward_rt.ro_rt == 0 ||
- !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
- &ip6_forward_rt.ro_dst.sin6_addr)) {
+ 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))
+ ip6stat.ip6s_forward_cachehit++;
+ else {
if (ip6_forward_rt.ro_rt) {
+ /* route is down or destination is different */
+ ip6stat.ip6s_forward_cachemiss++;
RTFREE(ip6_forward_rt.ro_rt);
ip6_forward_rt.ro_rt = 0;
}
+
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;
+#ifdef SCOPEDROUTING
+ ip6_forward_rt.ro_dst.sin6_scope_id =
+ in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_dst);
+#endif
rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING);
}
@@ -444,24 +447,37 @@ ip6_input(m)
if (ip6_forward_rt.ro_rt &&
(ip6_forward_rt.ro_rt->rt_flags &
(RTF_HOST|RTF_GATEWAY)) == RTF_HOST &&
+#if 0
/*
- * The comparison of the destination and the key of the rtentry
- * has already done through looking up the routing table,
- * so no need to do such a comparison here again.
+ * The check below is redundant since the comparison of
+ * the destination and the key of the rtentry has
+ * already done through looking up the routing table.
*/
+ IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
+ &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;
- /* packet to tentative address must not be received */
if (ia6->ia6_flags & IN6_IFF_ANYCAST)
m->m_flags |= M_ANYCAST6;
+ /*
+ * packets to a tentative, duplicated, or somehow invalid
+ * address must not be accepted.
+ */
if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) {
- /* this interface is ready */
+ /* this address is ready */
ours = 1;
deliverifp = ia6->ia_ifp; /* correct? */
goto hbhcheck;
} else {
- /* this interface is not ready, fall through */
+ /* address is not ready, so discard the packet. */
+ log(LOG_INFO,
+ "ip6_input: packet to an unready address %s->%s",
+ ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&ip6->ip6_dst));
+
+ goto bad;
}
}
@@ -498,13 +514,49 @@ ip6_input(m)
*/
plen = (u_int32_t)ntohs(ip6->ip6_plen);
if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
+ struct ip6_hbh *hbh;
+
if (ip6_hopopts_input(&plen, &rtalert, &m, &off)) {
+#if 0 /*touches NULL pointer*/
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
+#endif
return; /* m have already been freed */
}
+
/* adjust pointer */
ip6 = mtod(m, struct ip6_hdr *);
- nxt = ((struct ip6_hbh *)(ip6 + 1))->ip6h_nxt;
+
+ /*
+ * if the payload length field is 0 and the next header field
+ * indicates Hop-by-Hop Options header, then a Jumbo Payload
+ * option MUST be included.
+ */
+ if (ip6->ip6_plen == 0 && plen == 0) {
+ /*
+ * Note that if a valid jumbo payload option is
+ * contained, ip6_hoptops_input() must set a valid
+ * (non-zero) payload length to the variable plen.
+ */
+ ip6stat.ip6s_badoptions++;
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);
+ icmp6_error(m, ICMP6_PARAM_PROB,
+ ICMP6_PARAMPROB_HEADER,
+ (caddr_t)&ip6->ip6_plen - (caddr_t)ip6);
+ return;
+ }
+#ifndef PULLDOWN_TEST
+ /* ip6_hopopts_input() ensures that mbuf is contiguous */
+ hbh = (struct ip6_hbh *)(ip6 + 1);
+#else
+ IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
+ sizeof(struct ip6_hbh));
+ if (hbh == NULL) {
+ ip6stat.ip6s_tooshort++;
+ return;
+ }
+#endif
+ nxt = hbh->ip6h_nxt;
/*
* accept the packet if a router alert option is included
@@ -560,18 +612,27 @@ ip6_input(m)
return;
}
+ ip6 = mtod(m, struct ip6_hdr *);
+
/*
- * Tell launch routine the next header
+ * 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.
+ *
+ * For SIIT end node behavior, you may want to disable the check.
+ * However, you will become vulnerable to attacks using IPv4 mapped
+ * source.
*/
-#if defined(__NetBSD__) && defined(IFA_STATS)
- if (IFA_STATS && deliverifp != NULL) {
- struct in6_ifaddr *ia6;
- ip6 = mtod(m, struct ip6_hdr *);
- ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst);
- if (ia6)
- ia6->ia_ifa.ifa_data.ifad_inbytes += m->m_pkthdr.len;
+ 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;
}
-#endif
+
+ /*
+ * Tell launch routine the next header
+ */
ip6stat.ip6s_delivered++;
in6_ifstat_inc(deliverifp, ifs6_in_deliver);
nest = 0;
@@ -615,12 +676,28 @@ ip6_hopopts_input(plenp, rtalertp, mp, offp)
u_int8_t *opt;
/* validation of the length of the header */
+#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, sizeof(*hbh), -1);
hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off);
hbhlen = (hbh->ip6h_len + 1) << 3;
IP6_EXTHDR_CHECK(m, off, hbhlen, -1);
hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off);
+#else
+ IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
+ sizeof(struct ip6_hdr), sizeof(struct ip6_hbh));
+ if (hbh == NULL) {
+ ip6stat.ip6s_tooshort++;
+ return -1;
+ }
+ hbhlen = (hbh->ip6h_len + 1) << 3;
+ IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
+ hbhlen);
+ if (hbh == NULL) {
+ ip6stat.ip6s_tooshort++;
+ return -1;
+ }
+#endif
off += hbhlen;
hbhlen -= sizeof(struct ip6_hbh);
opt = (u_int8_t *)hbh + sizeof(struct ip6_hbh);
@@ -652,6 +729,7 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
int optlen = 0;
u_int8_t *opt = opthead;
u_int16_t rtalert_val;
+ u_int32_t jumboplen;
for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) {
switch(*opt) {
@@ -680,49 +758,75 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
*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));
- optlen = IP6OPT_JUMBO_LEN;
+ /* 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));
+ optlen = IP6OPT_JUMBO_LEN;
- bcopy(opt + 2, plenp, sizeof(*plenp));
- *plenp = htonl(*plenp);
- if (*plenp <= IPV6_MAXPACKET) {
- /*
- * jumbo payload length must be larger
- * than 65535
- */
- ip6stat.ip6s_badoptions++;
- icmp6_error(m, ICMP6_PARAM_PROB,
- ICMP6_PARAMPROB_HEADER,
- sizeof(struct ip6_hdr) +
- sizeof(struct ip6_hbh) +
- opt + 2 - opthead);
- return(-1);
- }
+ /*
+ * IPv6 packets that have non 0 payload length
+ * must not contain a jumbo paylod 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);
+ return(-1);
+ }
- ip6 = mtod(m, struct ip6_hdr *);
- if (ip6->ip6_plen) {
- /*
- * IPv6 packets that have non 0 payload length
- * must not contain a jumbo paylod option.
- */
- ip6stat.ip6s_badoptions++;
- icmp6_error(m, ICMP6_PARAM_PROB,
- ICMP6_PARAMPROB_HEADER,
- sizeof(struct ip6_hdr) +
- sizeof(struct ip6_hbh) +
- opt - opthead);
- return(-1);
- }
- break;
+ /*
+ * We may see jumbolen in unaligned location, so
+ * we'd need to perform bcopy().
+ */
+ bcopy(opt + 2, &jumboplen, sizeof(jumboplen));
+ jumboplen = (u_int32_t)htonl(jumboplen);
+
+#if 1
+ /*
+ * if there are multiple jumbo payload options,
+ * *plenp will be non-zero and the packet will be
+ * rejected.
+ * the behavior may need some debate in ipngwg -
+ * multiple options does not make sense, however,
+ * there's no explicit mention in specification.
+ */
+ if (*plenp != 0) {
+ ip6stat.ip6s_badoptions++;
+ icmp6_error(m, ICMP6_PARAM_PROB,
+ ICMP6_PARAMPROB_HEADER,
+ sizeof(struct ip6_hdr) +
+ sizeof(struct ip6_hbh) +
+ opt + 2 - opthead);
+ return(-1);
+ }
+#endif
+
+ /*
+ * jumbo payload length must be larger than 65535.
+ */
+ if (jumboplen <= IPV6_MAXPACKET) {
+ ip6stat.ip6s_badoptions++;
+ icmp6_error(m, ICMP6_PARAM_PROB,
+ ICMP6_PARAMPROB_HEADER,
+ sizeof(struct ip6_hdr) +
+ sizeof(struct ip6_hbh) +
+ opt + 2 - opthead);
+ return(-1);
+ }
+ *plenp = jumboplen;
+
+ break;
default: /* unknown option */
if (hbhlen < IP6OPT_MINLEN) {
ip6stat.ip6s_toosmall++;
@@ -786,11 +890,19 @@ ip6_unknown_opt(optp, m, off)
}
/*
- * Create the "control" list for this pcb
+ * Create the "control" list for this pcb.
+ *
+ * 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 inpcb *in6p;
+ register struct in6pcb *in6p;
register struct mbuf **mp;
register struct ip6_hdr *ip6;
register struct mbuf *m;
@@ -811,13 +923,15 @@ ip6_savecontrol(in6p, mp, ip6, m)
if (*mp)
mp = &(*mp)->m_next;
}
- if (in6p->in6p_flags & IN6P_RECVDSTADDR) {
- *mp = sbcreatecontrol((caddr_t) &ip6->ip6_dst,
- sizeof(struct in6_addr), IPV6_RECVDSTADDR,
- IPPROTO_IPV6);
- 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) {
@@ -859,7 +973,27 @@ 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 = (struct ip6_hbh *)(ip6 + 1);
+ struct ip6_hbh *hbh;
+ int hbhlen;
+
+#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) {
+ ip6stat.ip6s_tooshort++;
+ return;
+ }
+ hbhlen = (hbh->ip6h_len + 1) << 3;
+ IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
+ sizeof(struct ip6_hdr), hbhlen);
+ if (hbh == NULL) {
+ ip6stat.ip6s_tooshort++;
+ return;
+ }
+#endif
/*
* XXX: We copy whole the header even if a jumbo
@@ -867,8 +1001,7 @@ ip6_savecontrol(in6p, mp, ip6, m)
* be removed before returning in the RFC 2292.
* But it's too painful operation...
*/
- *mp = sbcreatecontrol((caddr_t)hbh,
- (hbh->ip6h_len + 1) << 3,
+ *mp = sbcreatecontrol((caddr_t)hbh, hbhlen,
IPV6_HOPOPTS, IPPROTO_IPV6);
if (*mp)
mp = &(*mp)->m_next;
@@ -888,8 +1021,32 @@ ip6_savecontrol(in6p, mp, ip6, m)
* the chain of ancillary data.
*/
while(1) { /* is explicit loop prevention necessary? */
- struct ip6_ext *ip6e =
- (struct ip6_ext *)(mtod(m, caddr_t) + off);
+ struct ip6_ext *ip6e;
+ int elen;
+
+#ifndef PULLDOWN_TEST
+ 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;
+#else
+ IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off,
+ sizeof(struct ip6_ext));
+ if (ip6e == NULL) {
+ ip6stat.ip6s_tooshort++;
+ return;
+ }
+ 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) {
+ ip6stat.ip6s_tooshort++;
+ return;
+ }
+#endif
switch(nxt) {
case IPPROTO_DSTOPTS:
@@ -904,8 +1061,7 @@ ip6_savecontrol(in6p, mp, ip6, m)
if (!privileged)
break;
- *mp = sbcreatecontrol((caddr_t)ip6e,
- (ip6e->ip6e_len + 1) << 3,
+ *mp = sbcreatecontrol((caddr_t)ip6e, elen,
IPV6_DSTOPTS,
IPPROTO_IPV6);
if (*mp)
@@ -916,8 +1072,7 @@ ip6_savecontrol(in6p, mp, ip6, m)
if (!in6p->in6p_flags & IN6P_RTHDR)
break;
- *mp = sbcreatecontrol((caddr_t)ip6e,
- (ip6e->ip6e_len + 1) << 3,
+ *mp = sbcreatecontrol((caddr_t)ip6e, elen,
IPV6_RTHDR,
IPPROTO_IPV6);
if (*mp)
@@ -940,10 +1095,7 @@ ip6_savecontrol(in6p, mp, ip6, m)
}
/* proceed with the next header. */
- if (nxt == IPPROTO_AH)
- off += (ip6e->ip6e_len + 2) << 2;
- else
- off += (ip6e->ip6e_len + 1) << 3;
+ off += elen;
nxt = ip6e->ip6e_nxt;
}
loopend:
@@ -955,6 +1107,7 @@ ip6_savecontrol(in6p, mp, ip6, m)
/* to be done */
}
/* IN6P_RTHDR - to be done */
+
}
/*
@@ -1008,6 +1161,115 @@ ip6_get_prevhdr(m, off)
}
/*
+ * get next header offset. m will be retained.
+ */
+int
+ip6_nexthdr(m, off, proto, nxtp)
+ struct mbuf *m;
+ int off;
+ int proto;
+ int *nxtp;
+{
+ struct ip6_hdr ip6;
+ struct ip6_ext ip6e;
+ struct ip6_frag fh;
+
+ /* just in case */
+ if (m == NULL)
+ panic("ip6_nexthdr: m == NULL");
+ if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len < off)
+ return -1;
+
+ switch (proto) {
+ case IPPROTO_IPV6:
+ if (m->m_pkthdr.len < off + sizeof(ip6))
+ return -1;
+ m_copydata(m, off, sizeof(ip6), (caddr_t)&ip6);
+ if (nxtp)
+ *nxtp = ip6.ip6_nxt;
+ off += sizeof(ip6);
+ return off;
+
+ case IPPROTO_FRAGMENT:
+ /*
+ * terminate parsing if it is not the first fragment,
+ * it does not make sense to parse through it.
+ */
+ if (m->m_pkthdr.len < off + sizeof(fh))
+ return -1;
+ m_copydata(m, off, sizeof(fh), (caddr_t)&fh);
+ if ((ntohs(fh.ip6f_offlg) & IP6F_OFF_MASK) != 0)
+ return -1;
+ if (nxtp)
+ *nxtp = fh.ip6f_nxt;
+ off += sizeof(struct ip6_frag);
+ return off;
+
+ case IPPROTO_AH:
+ if (m->m_pkthdr.len < off + sizeof(ip6e))
+ return -1;
+ m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
+ if (nxtp)
+ *nxtp = ip6e.ip6e_nxt;
+ off += (ip6e.ip6e_len + 2) << 2;
+ return off;
+
+ case IPPROTO_HOPOPTS:
+ case IPPROTO_ROUTING:
+ case IPPROTO_DSTOPTS:
+ if (m->m_pkthdr.len < off + sizeof(ip6e))
+ return -1;
+ m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
+ if (nxtp)
+ *nxtp = ip6e.ip6e_nxt;
+ off += (ip6e.ip6e_len + 1) << 3;
+ return off;
+
+ case IPPROTO_NONE:
+ case IPPROTO_ESP:
+ case IPPROTO_IPCOMP:
+ /* give up */
+ return -1;
+
+ default:
+ return -1;
+ }
+
+ return -1;
+}
+
+/*
+ * get offset for the last header in the chain. m will be kept untainted.
+ */
+int
+ip6_lasthdr(m, off, proto, nxtp)
+ struct mbuf *m;
+ int off;
+ int proto;
+ int *nxtp;
+{
+ int newoff;
+ int nxt;
+
+ if (!nxtp) {
+ nxt = -1;
+ nxtp = &nxt;
+ }
+ while (1) {
+ newoff = ip6_nexthdr(m, off, proto, nxtp);
+ if (newoff < 0)
+ return off;
+ else if (newoff < off)
+ return -1; /* invalid */
+ else if (newoff == off)
+ return newoff;
+
+ off = newoff;
+ proto = *nxtp;
+ }
+}
+
+/*
* System control for IP6
*/
diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c
index 5d5c065656d7..6bc7e6be5247 100644
--- a/sys/netinet6/ip6_mroute.c
+++ b/sys/netinet6/ip6_mroute.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip6_mroute.c,v 1.24 2000/05/19 07:37:05 jinmei Exp $ */
+
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/* BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp */
@@ -45,6 +46,7 @@
*/
#include "opt_inet.h"
+#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -57,7 +59,6 @@
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/kernel.h>
-#include <sys/sockio.h>
#include <sys/syslog.h>
#include <net/if.h>
@@ -67,7 +68,7 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/ip6_mroute.h>
#include <netinet6/pim6.h>
@@ -75,45 +76,45 @@
static MALLOC_DEFINE(M_MRTABLE, "mf6c", "multicast forwarding cache entry");
-#define M_HASCL(m) ((m)->m_flags & M_EXT)
+#define M_HASCL(m) ((m)->m_flags & M_EXT)
-static int ip6_mdq __P((struct mbuf *, struct ifnet *, struct mf6c *));
-static void phyint_send __P((struct ip6_hdr *, struct mif6 *,
- struct mbuf *));
+static int ip6_mdq __P((struct mbuf *, struct ifnet *, struct mf6c *));
+static void phyint_send __P((struct ip6_hdr *, struct mif6 *, struct mbuf *));
-static int set_pim6 __P((int *));
-static int socket_send __P((struct socket *, struct mbuf *,
- struct sockaddr_in6 *));
-static int register_send __P((struct ip6_hdr *, struct mif6 *,
- struct mbuf *));
+static int set_pim6 __P((int *));
+static int socket_send __P((struct socket *, struct mbuf *,
+ struct sockaddr_in6 *));
+static int register_send __P((struct ip6_hdr *, struct mif6 *,
+ struct mbuf *));
/*
* Globals. All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static,
* except for netstat or debugging purposes.
*/
-struct socket *ip6_mrouter = NULL;
-int ip6_mrtproto = IPPROTO_PIM; /* for netstat only */
-struct mrt6stat mrt6stat;
+struct socket *ip6_mrouter = NULL;
+int ip6_mrouter_ver = 0;
+int ip6_mrtproto = IPPROTO_PIM; /* for netstat only */
+struct mrt6stat mrt6stat;
-#define NO_RTE_FOUND 0x1
-#define RTE_FOUND 0x2
+#define NO_RTE_FOUND 0x1
+#define RTE_FOUND 0x2
-struct mf6c *mf6ctable[MF6CTBLSIZ];
-u_char nexpire[MF6CTBLSIZ];
-static struct mif6 mif6table[MAXMIFS];
+struct mf6c *mf6ctable[MF6CTBLSIZ];
+u_char nexpire[MF6CTBLSIZ];
+static struct mif6 mif6table[MAXMIFS];
#ifdef MRT6DEBUG
u_int mrt6debug = 0; /* debug level */
-#define DEBUG_MFC 0x02
-#define DEBUG_FORWARD 0x04
-#define DEBUG_EXPIRE 0x08
-#define DEBUG_XMIT 0x10
-#define DEBUG_REG 0x20
-#define DEBUG_PIM 0x40
+#define DEBUG_MFC 0x02
+#define DEBUG_FORWARD 0x04
+#define DEBUG_EXPIRE 0x08
+#define DEBUG_XMIT 0x10
+#define DEBUG_REG 0x20
+#define DEBUG_PIM 0x40
#endif
static void expire_upcalls __P((void *));
-#define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */
-#define UPCALL_EXPIRE 6 /* number of timeouts */
+#define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */
+#define UPCALL_EXPIRE 6 /* number of timeouts */
#ifdef INET
#ifdef MROUTING
@@ -131,7 +132,7 @@ extern struct socket *ip_mrouter;
*/
struct ifnet multicast_register_if;
-#define ENCAP_HOPS 64
+#define ENCAP_HOPS 64
/*
* Private variables.
@@ -151,7 +152,7 @@ static int pim6;
/*
* Hash function for a source, group entry
*/
-#define MF6CHASH(a, g) MF6CHASHMOD((a).s6_addr32[0] ^ (a).s6_addr32[1] ^ \
+#define MF6CHASH(a, g) MF6CHASHMOD((a).s6_addr32[0] ^ (a).s6_addr32[1] ^ \
(a).s6_addr32[2] ^ (a).s6_addr32[3] ^ \
(g).s6_addr32[0] ^ (g).s6_addr32[1] ^ \
(g).s6_addr32[2] ^ (g).s6_addr32[3])
@@ -161,7 +162,7 @@ static int pim6;
* Quality of service parameter to be added in the future!!!
*/
-#define MF6CFIND(o, g, rt) { \
+#define MF6CFIND(o, g, rt) do { \
register struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \
rt = NULL; \
mrt6stat.mrt6s_mfc_lookups++; \
@@ -177,13 +178,13 @@ static int pim6;
if (rt == NULL) { \
mrt6stat.mrt6s_mfc_misses++; \
} \
-}
+} while (0)
/*
* Macros to compute elapsed time efficiently
* Borrowed from Van Jacobson's scheduling code
*/
-#define TV_DELTA(a, b, delta) { \
+#define TV_DELTA(a, b, delta) do { \
register int xxs; \
\
delta = (a).tv_usec - (b).tv_usec; \
@@ -199,20 +200,20 @@ static int pim6;
delta += (1000000 * xxs); \
} \
} \
-}
+} while (0)
-#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
+#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
(a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)
#ifdef UPCALL_TIMING
-#define UPCALL_MAX 50
+#define UPCALL_MAX 50
u_long upcall_data[UPCALL_MAX + 1];
static void collate();
#endif /* UPCALL_TIMING */
static int get_sg_cnt __P((struct sioc_sg_req6 *));
static int get_mif6_cnt __P((struct sioc_mif_req6 *));
-static int ip6_mrouter_init __P((struct socket *, struct mbuf *));
+static int ip6_mrouter_init __P((struct socket *, struct mbuf *, int));
static int add_m6if __P((struct mif6ctl *));
static int del_m6if __P((mifi_t *));
static int add_m6fc __P((struct mf6cctl *));
@@ -239,7 +240,10 @@ ip6_mrouter_set(so, sopt)
switch (sopt->sopt_name) {
case MRT6_INIT:
- error = ip6_mrouter_init(so, m);
+#ifdef MRT6_OINIT
+ case MRT6_OINIT:
+#endif
+ error = ip6_mrouter_init(so, m, sopt->sopt_name);
break;
case MRT6_DONE:
error = ip6_mrouter_done();
@@ -331,6 +335,9 @@ get_sg_cnt(req)
req->wrong_if = rt->mf6c_wrong_if;
} else
return(ESRCH);
+#if 0
+ req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
+#endif
return 0;
}
@@ -371,9 +378,10 @@ set_pim6(i)
* Enable multicast routing
*/
static int
-ip6_mrouter_init(so, m)
+ip6_mrouter_init(so, m, cmd)
struct socket *so;
struct mbuf *m;
+ int cmd;
{
int *v;
@@ -398,6 +406,7 @@ ip6_mrouter_init(so, m)
if (ip6_mrouter != NULL) return EADDRINUSE;
ip6_mrouter = so;
+ ip6_mrouter_ver = cmd;
bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
bzero((caddr_t)nexpire, sizeof(nexpire));
@@ -458,6 +467,10 @@ ip6_mrouter_done()
}
}
}
+#ifdef notyet
+ bzero((caddr_t)qtable, sizeof(qtable));
+ bzero((caddr_t)tbftable, sizeof(tbftable));
+#endif
bzero((caddr_t)mif6table, sizeof(mif6table));
nummifs = 0;
@@ -494,6 +507,7 @@ ip6_mrouter_done()
reg_mif_num = -1;
ip6_mrouter = NULL;
+ ip6_mrouter_ver = 0;
splx(s);
@@ -517,6 +531,9 @@ add_m6if(mifcp)
register struct mif6 *mifp;
struct ifnet *ifp;
int error, s;
+#ifdef notyet
+ struct tbf *m_tbf = tbftable + mifcp->mif6c_mifi;
+#endif
if (mifcp->mif6c_mifi >= MAXMIFS)
return EINVAL;
@@ -553,6 +570,10 @@ add_m6if(mifcp)
s = splnet();
mifp->m6_flags = mifcp->mif6c_flags;
mifp->m6_ifp = ifp;
+#ifdef notyet
+ /* scaling up here allows division by 1024 in critical code */
+ mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000;
+#endif
/* initialize per mif pkt counters */
mifp->m6_pkt_in = 0;
mifp->m6_pkt_out = 0;
@@ -604,6 +625,10 @@ del_m6if(mifip)
if_allmulti(ifp, 0);
}
+#ifdef notyet
+ bzero((caddr_t)qtable[*mifip], sizeof(qtable[*mifip]));
+ bzero((caddr_t)mifp->m6_tbf, sizeof(*(mifp->m6_tbf)));
+#endif
bzero((caddr_t)mifp, sizeof (*mifp));
/* Adjust nummifs down */
@@ -726,7 +751,7 @@ add_m6fc(mfccp)
#endif
for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
-
+
if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
&mfccp->mf6cc_origin.sin6_addr)&&
IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
@@ -753,7 +778,7 @@ add_m6fc(mfccp)
splx(s);
return ENOBUFS;
}
-
+
/* insert new entry at head of hash chain */
rt->mf6c_origin = mfccp->mf6cc_origin;
rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp;
@@ -764,7 +789,7 @@ add_m6fc(mfccp)
rt->mf6c_wrong_if = 0;
rt->mf6c_expire = 0;
rt->mf6c_stall = NULL;
-
+
/* link into table */
rt->mf6c_next = mf6ctable[hash];
mf6ctable[hash] = rt;
@@ -791,11 +816,11 @@ collate(t)
if (TV_LT(*t, tp))
{
TV_DELTA(tp, *t, delta);
-
+
d = delta >> 10;
if (d > UPCALL_MAX)
d = UPCALL_MAX;
-
+
++upcall_data[d];
}
}
@@ -967,7 +992,7 @@ ip6_mforward(ip6, ifp, m)
splx(s);
return ENOBUFS;
}
-
+
/* is there an upcall waiting for this packet? */
hash = MF6CHASH(ip6->ip6_src, ip6->ip6_dst);
for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
@@ -981,6 +1006,9 @@ ip6_mforward(ip6, ifp, m)
if (rt == NULL) {
struct mrt6msg *im;
+#ifdef MRT6_OINIT
+ struct omrt6msg *oim;
+#endif
/* no upcall, so make a new entry */
rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE,
@@ -1009,10 +1037,31 @@ ip6_mforward(ip6, ifp, m)
* Send message to routing daemon
*/
sin6.sin6_addr = ip6->ip6_src;
-
- im = mtod(mm, struct mrt6msg *);
- im->im6_msgtype = MRT6MSG_NOCACHE;
- im->im6_mbz = 0;
+
+ im = NULL;
+#ifdef MRT6_OINIT
+ oim = NULL;
+#endif
+ switch (ip6_mrouter_ver) {
+#ifdef MRT6_OINIT
+ case MRT6_OINIT:
+ oim = mtod(mm, struct omrt6msg *);
+ oim->im6_msgtype = MRT6MSG_NOCACHE;
+ oim->im6_mbz = 0;
+ break;
+#endif
+ case MRT6_INIT:
+ im = mtod(mm, struct mrt6msg *);
+ im->im6_msgtype = MRT6MSG_NOCACHE;
+ im->im6_mbz = 0;
+ break;
+ default:
+ free(rte, M_MRTABLE);
+ m_freem(mb0);
+ free(rt, M_MRTABLE);
+ splx(s);
+ return EINVAL;
+ }
#ifdef MRT6DEBUG
if (mrt6debug & DEBUG_FORWARD)
@@ -1025,7 +1074,16 @@ ip6_mforward(ip6, ifp, m)
mifp++, mifi++)
;
- im->im6_mif = mifi;
+ switch (ip6_mrouter_ver) {
+#ifdef MRT6_OINIT
+ case MRT6_OINIT:
+ oim->im6_mif = mifi;
+ break;
+#endif
+ case MRT6_INIT:
+ im->im6_mif = mifi;
+ break;
+ }
if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
@@ -1144,7 +1202,7 @@ expire_upcalls(unused)
}
splx(s);
expire_upcalls_ch =
- timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);
+ timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);
}
/*
@@ -1167,12 +1225,12 @@ ip6_mdq(m, ifp, rt)
* seperate.
*/
-#define MC6_SEND(ip6,mifp,m) { \
- if ((mifp)->m6_flags & MIFF_REGISTER) \
- register_send((ip6), (mifp), (m)); \
- else \
- phyint_send((ip6), (mifp), (m)); \
-}
+#define MC6_SEND(ip6, mifp, m) do { \
+ if ((mifp)->m6_flags & MIFF_REGISTER) \
+ register_send((ip6), (mifp), (m)); \
+ else \
+ phyint_send((ip6), (mifp), (m)); \
+} while (0)
/*
* Don't forward if it didn't arrive from the parent mif
@@ -1195,55 +1253,82 @@ ip6_mdq(m, ifp, rt)
* packets on this interface, send a message to the
* routing daemon.
*/
- if(mifi < nummifs) /* have to make sure this is a valid mif */
- if(mif6table[mifi].m6_ifp)
-
- if (pim6 && (m->m_flags & M_LOOP) == 0) {
- /*
- * Check the M_LOOP flag to avoid an
- * unnecessary PIM assert.
- * XXX: M_LOOP is an ad-hoc hack...
- */
- static struct sockaddr_in6 sin6 =
- { sizeof(sin6), AF_INET6 };
-
- register struct mbuf *mm;
- struct mrt6msg *im;
-
- mm = m_copy(m, 0,
- sizeof(struct ip6_hdr));
- if (mm &&
- (M_HASCL(mm) ||
- mm->m_len < sizeof(struct ip6_hdr)))
- mm = m_pullup(mm, sizeof(struct ip6_hdr));
- if (mm == NULL)
- return ENOBUFS;
-
- im = mtod(mm, struct mrt6msg *);
- im->im6_msgtype = MRT6MSG_WRONGMIF;
- im->im6_mbz = 0;
+ /* have to make sure this is a valid mif */
+ if (mifi < nummifs && mif6table[mifi].m6_ifp)
+ if (pim6 && (m->m_flags & M_LOOP) == 0) {
+ /*
+ * Check the M_LOOP flag to avoid an
+ * unnecessary PIM assert.
+ * XXX: M_LOOP is an ad-hoc hack...
+ */
+ static struct sockaddr_in6 sin6 =
+ { sizeof(sin6), AF_INET6 };
- for (mifp = mif6table, iif = 0;
- iif < nummifs && mifp &&
- mifp->m6_ifp != ifp;
- mifp++, iif++);
+ register struct mbuf *mm;
+ struct mrt6msg *im;
+#ifdef MRT6_OINIT
+ struct omrt6msg *oim;
+#endif
- im->im6_mif = iif;
+ mm = m_copy(m, 0, sizeof(struct ip6_hdr));
+ if (mm &&
+ (M_HASCL(mm) ||
+ mm->m_len < sizeof(struct ip6_hdr)))
+ mm = m_pullup(mm, sizeof(struct ip6_hdr));
+ if (mm == NULL)
+ return ENOBUFS;
+
+#ifdef MRT6_OINIT
+ oim = NULL;
+#endif
+ im = NULL;
+ switch (ip6_mrouter_ver) {
+#ifdef MRT6_OINIT
+ case MRT6_OINIT:
+ oim = mtod(mm, struct omrt6msg *);
+ oim->im6_msgtype = MRT6MSG_WRONGMIF;
+ oim->im6_mbz = 0;
+ break;
+#endif
+ case MRT6_INIT:
+ im = mtod(mm, struct mrt6msg *);
+ im->im6_msgtype = MRT6MSG_WRONGMIF;
+ break;
+ default:
+ m_freem(mm);
+ return EINVAL;
+ }
+ for (mifp = mif6table, iif = 0;
+ iif < nummifs && mifp &&
+ mifp->m6_ifp != ifp;
+ mifp++, iif++)
+ ;
+
+ switch (ip6_mrouter_ver) {
+#ifdef MRT6_OINIT
+ case MRT6_OINIT:
+ oim->im6_mif = iif;
+ sin6.sin6_addr = oim->im6_src;
+ break;
+#endif
+ case MRT6_INIT:
+ im->im6_mif = iif;
sin6.sin6_addr = im->im6_src;
+ break;
+ }
- mrt6stat.mrt6s_upcalls++;
+ mrt6stat.mrt6s_upcalls++;
- if (socket_send(ip6_mrouter, mm,
- &sin6) < 0) {
+ if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
#ifdef MRT6DEBUG
- if (mrt6debug)
- log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n");
+ if (mrt6debug)
+ log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n");
#endif
- ++mrt6stat.mrt6s_upq_sockfull;
- return ENOBUFS;
- } /* if socket Q full */
- } /* if PIM */
+ ++mrt6stat.mrt6s_upq_sockfull;
+ return ENOBUFS;
+ } /* if socket Q full */
+ } /* if PIM */
return 0;
} /* if wrong iif */
@@ -1265,6 +1350,25 @@ ip6_mdq(m, ifp, rt)
*/
for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++)
if (IF_ISSET(mifi, &rt->mf6c_ifset)) {
+ /*
+ * check if the outgoing packet is going to break
+ * a scope boundary.
+ * XXX For packets through PIM register tunnel
+ * interface, we believe a routing daemon.
+ */
+ if ((mif6table[rt->mf6c_parent].m6_flags &
+ MIFF_REGISTER) == 0 &&
+ (mif6table[mifi].m6_flags & MIFF_REGISTER) == 0 &&
+ (in6_addr2scopeid(ifp, &ip6->ip6_dst) !=
+ in6_addr2scopeid(mif6table[mifi].m6_ifp,
+ &ip6->ip6_dst) ||
+ in6_addr2scopeid(ifp, &ip6->ip6_src) !=
+ in6_addr2scopeid(mif6table[mifi].m6_ifp,
+ &ip6->ip6_src))) {
+ ip6stat.ip6s_badscope++;
+ continue;
+ }
+
mifp->m6_pkt_out++;
mifp->m6_bytes_out += plen;
MC6_SEND(ip6, mifp, m);
@@ -1495,14 +1599,22 @@ pim6_input(mp, offp, proto)
* Make sure that the IP6 and PIM headers in contiguous memory, and
* possibly the PIM REGISTER header
*/
+#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, minlen, IPPROTO_DONE);
/* adjust pointer */
ip6 = mtod(m, struct ip6_hdr *);
/* adjust mbuf to point to the PIM header */
pim = (struct pim *)((caddr_t)ip6 + off);
+#else
+ IP6_EXTHDR_GET(pim, struct pim *, m, off, minlen);
+ if (pim == NULL) {
+ pim6stat.pim6s_rcv_tooshort++;
+ return IPPROTO_DONE;
+ }
+#endif
-#define PIM6_CHECKSUM
+#define PIM6_CHECKSUM
#ifdef PIM6_CHECKSUM
{
int cksumlen;
@@ -1553,7 +1665,7 @@ pim6_input(mp, offp, proto)
struct ip6_hdr *eip6;
u_int32_t *reghdr;
int rc;
-
+
++pim6stat.pim6s_rcv_registers;
if ((reg_mif_num >= nummifs) || (reg_mif_num == (mifi_t) -1)) {
@@ -1566,9 +1678,9 @@ pim6_input(mp, offp, proto)
m_freem(m);
return(IPPROTO_DONE);
}
-
+
reghdr = (u_int32_t *)(pim + 1);
-
+
if ((ntohl(*reghdr) & PIM_NULL_REGISTER))
goto pim6_input_to_daemon;
@@ -1587,9 +1699,9 @@ pim6_input(mp, offp, proto)
m_freem(m);
return(IPPROTO_DONE);
}
-
+
eip6 = (struct ip6_hdr *) (reghdr + 1);
-#ifdef MRT6DEBUG
+#ifdef MRT6DEBUG
if (mrt6debug & DEBUG_PIM)
log(LOG_DEBUG,
"pim6_input[register], eip6: %s -> %s, "
@@ -1598,7 +1710,7 @@ pim6_input(mp, offp, proto)
ip6_sprintf(&eip6->ip6_dst),
ntohs(eip6->ip6_plen));
#endif
-
+
/* verify the inner packet is destined to a mcast group */
if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) {
++pim6stat.pim6s_rcv_badregisters;
@@ -1612,7 +1724,7 @@ pim6_input(mp, offp, proto)
m_freem(m);
return(IPPROTO_DONE);
}
-
+
/*
* make a copy of the whole header to pass to the daemon later.
*/
@@ -1626,7 +1738,7 @@ pim6_input(mp, offp, proto)
m_freem(m);
return(IPPROTO_DONE);
}
-
+
/*
* forward the inner ip6 packet; point m_data at the inner ip6.
*/
@@ -1643,8 +1755,8 @@ 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 112ffbea1a4c..34ec5388940f 100644
--- a/sys/netinet6/ip6_mroute.h
+++ b/sys/netinet6/ip6_mroute.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip6_mroute.h,v 1.10 2000/05/19 02:38:53 itojun Exp $ */
+
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
@@ -25,238 +28,6 @@
* 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.
- *
- * $FreeBSD$
- */
-
-/* BSDI ip_mroute.h,v 2.5 1996/10/11 16:01:48 pjd Exp */
-
-/*
- * Definitions for IP multicast forwarding.
- *
- * Written by David Waitzman, BBN Labs, August 1988.
- * Modified by Steve Deering, Stanford, February 1989.
- * Modified by Ajit Thyagarajan, PARC, August 1993.
- * Modified by Ajit Thyagarajan, PARC, August 1994.
- * Modified by Ahmed Helmy, USC, September 1996.
- *
- * MROUTING Revision: 1.2
- */
-
-#ifndef _NETINET6_IP6_MROUTE_H_
-#define _NETINET6_IP6_MROUTE_H_
-
-/*
- * Multicast Routing set/getsockopt commands.
- */
-#define MRT6_INIT 100 /* initialize forwarder */
-#define MRT6_DONE 101 /* shut down forwarder */
-#define MRT6_ADD_MIF 102 /* add multicast interface */
-#define MRT6_DEL_MIF 103 /* delete multicast interface */
-#define MRT6_ADD_MFC 104 /* insert forwarding cache entry */
-#define MRT6_DEL_MFC 105 /* delete forwarding cache entry */
-#define MRT6_PIM 107 /* enable pim code */
-
-#define GET_TIME(t) microtime(&t)
-
-/*
- * Types and macros for handling bitmaps with one bit per multicast interface.
- */
-typedef u_short mifi_t; /* type of a mif index */
-#define MAXMIFS 64
-
-#ifndef IF_SETSIZE
-#define IF_SETSIZE 256
-#endif
-
-typedef long if_mask;
-#define NIFBITS (sizeof(if_mask) * NBBY) /* bits per mask */
-
-#ifndef howmany
-#define howmany(x, y) (((x) + ((y) - 1)) / (y))
-#endif
-
-typedef struct if_set {
- fd_mask ifs_bits[howmany(IF_SETSIZE, NIFBITS)];
-} if_set;
-
-#define IF_SET(n, p) ((p)->ifs_bits[(n)/NIFBITS] |= (1 << ((n) % NIFBITS)))
-#define IF_CLR(n, p) ((p)->ifs_bits[(n)/NIFBITS] &= ~(1 << ((n) % NIFBITS)))
-#define IF_ISSET(n, p) ((p)->ifs_bits[(n)/NIFBITS] & (1 << ((n) % NIFBITS)))
-#define IF_COPY(f, t) bcopy(f, t, sizeof(*(f)))
-#define IF_ZERO(p) bzero(p, sizeof(*(p)))
-
-/*
- * Argument structure for MRT6_ADD_IF.
- */
-struct mif6ctl {
- mifi_t mif6c_mifi; /* the index of the mif to be added */
- u_char mif6c_flags; /* MIFF_ flags defined below */
- u_short mif6c_pifi; /* the index of the physical IF */
-};
-
-#define MIFF_REGISTER 0x1 /* mif represents a register end-point */
-
-/*
- * Argument structure for MRT6_ADD_MFC and MRT6_DEL_MFC
- */
-struct mf6cctl {
- struct sockaddr_in6 mf6cc_origin; /* IPv6 origin of mcasts */
- struct sockaddr_in6 mf6cc_mcastgrp; /* multicast group associated */
- mifi_t mf6cc_parent; /* incoming ifindex */
- struct if_set mf6cc_ifset; /* set of forwarding ifs */
-};
-
-/*
- * The kernel's multicast routing statistics.
- */
-struct mrt6stat {
- u_quad_t mrt6s_mfc_lookups; /* # forw. cache hash table hits */
- u_quad_t mrt6s_mfc_misses; /* # forw. cache hash table misses */
- u_quad_t mrt6s_upcalls; /* # calls to mrouted */
- u_quad_t mrt6s_no_route; /* no route for packet's origin */
- u_quad_t mrt6s_bad_tunnel; /* malformed tunnel options */
- u_quad_t mrt6s_cant_tunnel; /* no room for tunnel options */
- u_quad_t mrt6s_wrong_if; /* arrived on wrong interface */
- u_quad_t mrt6s_upq_ovflw; /* upcall Q overflow */
- u_quad_t mrt6s_cache_cleanups; /* # entries with no upcalls */
- u_quad_t mrt6s_drop_sel; /* pkts dropped selectively */
- u_quad_t mrt6s_q_overflow; /* pkts dropped - Q overflow */
- u_quad_t mrt6s_pkt2large; /* pkts dropped - size > BKT SIZE */
- u_quad_t mrt6s_upq_sockfull; /* upcalls dropped - socket full */
-};
-
-/*
- * Struct used to communicate from kernel to multicast router
- * note the convenient similarity to an IPv6 header.
- */
-struct mrt6msg {
- u_long unused1;
- u_char im6_msgtype; /* what type of message */
-#define MRT6MSG_NOCACHE 1
-#define MRT6MSG_WRONGMIF 2
-#define MRT6MSG_WHOLEPKT 3 /* used for user level encap*/
- u_char im6_mbz; /* must be zero */
- u_char im6_mif; /* mif rec'd on */
- u_char unused2;
- struct in6_addr im6_src, im6_dst;
-};
-
-/*
- * Argument structure used by multicast routing daemon to get src-grp
- * packet counts
- */
-struct sioc_sg_req6 {
- struct sockaddr_in6 src;
- struct sockaddr_in6 grp;
- u_quad_t pktcnt;
- u_quad_t bytecnt;
- u_quad_t wrong_if;
-};
-
-/*
- * Argument structure used by mrouted to get mif pkt counts
- */
-struct sioc_mif_req6 {
- mifi_t mifi; /* mif number */
- u_quad_t icount; /* Input packet count on mif */
- u_quad_t ocount; /* Output packet count on mif */
- u_quad_t ibytes; /* Input byte count on mif */
- u_quad_t obytes; /* Output byte count on mif */
-};
-
-#if defined(_KERNEL) || defined(KERNEL)
-/*
- * The kernel's multicast-interface structure.
- */
-struct mif6 {
- u_char m6_flags; /* MIFF_ flags defined above */
- u_int m6_rate_limit; /* max rate */
- struct in6_addr m6_lcl_addr; /* local interface address */
- struct ifnet *m6_ifp; /* pointer to interface */
- u_quad_t m6_pkt_in; /* # pkts in on interface */
- u_quad_t m6_pkt_out; /* # pkts out on interface */
- u_quad_t m6_bytes_in; /* # bytes in on interface */
- u_quad_t m6_bytes_out; /* # bytes out on interface */
- struct route_in6 m6_route;/* cached route if this is a tunnel */
-};
-
-/*
- * The kernel's multicast forwarding cache entry structure
- */
-struct mf6c {
- struct sockaddr_in6 mf6c_origin; /* IPv6 origin of mcasts */
- struct sockaddr_in6 mf6c_mcastgrp; /* multicast group associated*/
- mifi_t mf6c_parent; /* incoming IF */
- struct if_set mf6c_ifset; /* set of outgoing IFs */
- u_quad_t mf6c_pkt_cnt; /* pkt count for src-grp */
- u_quad_t mf6c_byte_cnt; /* byte count for src-grp */
- u_quad_t mf6c_wrong_if; /* wrong if for src-grp */
- int mf6c_expire; /* time to clean entry up */
- struct timeval mf6c_last_assert; /* last time I sent an assert*/
- struct rtdetq *mf6c_stall; /* pkts waiting for route */
- struct mf6c *mf6c_next; /* hash table linkage */
-};
-
-#define MF6C_INCOMPLETE_PARENT ((mifi_t)-1)
-
-/*
- * Argument structure used for pkt info. while upcall is made
- */
-#ifndef _NETINET_IP_MROUTE_H_
-struct rtdetq { /* XXX: rtdetq is also defined in ip_mroute.h */
- struct mbuf *m; /* A copy of the packet */
- struct ifnet *ifp; /* Interface pkt came in on */
-#ifdef UPCALL_TIMING
- struct timeval t; /* Timestamp */
-#endif /* UPCALL_TIMING */
- struct rtdetq *next;
-};
-#endif /* _NETINET_IP_MROUTE_H_ */
-
-#define MF6CTBLSIZ 256
-#if (MF6CTBLSIZ & (MF6CTBLSIZ - 1)) == 0 /* from sys:route.h */
-#define MF6CHASHMOD(h) ((h) & (MF6CTBLSIZ - 1))
-#else
-#define MF6CHASHMOD(h) ((h) % MF6CTBLSIZ)
-#endif
-
-#define MAX_UPQ6 4 /* max. no of pkts in upcall Q */
-
-int ip6_mrouter_set __P((struct socket *so, struct sockopt *sopt));
-int ip6_mrouter_get __P((struct socket *so, struct sockopt *sopt));
-int ip6_mrouter_done __P((void));
-int mrt6_ioctl __P((int, caddr_t));
-#endif /* _KERNEL */
-
-#endif /* !_NETINET6_IP6_MROUTE_H_ */
-/*
- * Copyright (C) 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.
*/
/* BSDI ip_mroute.h,v 2.5 1996/10/11 16:01:48 pjd Exp */
@@ -279,15 +50,18 @@ int mrt6_ioctl __P((int, caddr_t));
/*
* Multicast Routing set/getsockopt commands.
*/
-#define MRT6_INIT 100 /* initialize forwarder */
+#ifdef _KERNEL
+#define MRT6_OINIT 100 /* initialize forwarder (omrt6msg) */
+#endif
#define MRT6_DONE 101 /* shut down forwarder */
#define MRT6_ADD_MIF 102 /* add multicast interface */
#define MRT6_DEL_MIF 103 /* delete multicast interface */
#define MRT6_ADD_MFC 104 /* insert forwarding cache entry */
#define MRT6_DEL_MFC 105 /* delete forwarding cache entry */
#define MRT6_PIM 107 /* enable pim code */
+#define MRT6_INIT 108 /* initialize forwarder (mrt6msg) */
-#if BSD >= 199103
+#if BSD >= 199103
#define GET_TIME(t) microtime(&t)
#elif defined(sun)
#define GET_TIME(t) uniqtime(&t)
@@ -365,21 +139,45 @@ struct mrt6stat {
u_quad_t mrt6s_upq_sockfull; /* upcalls dropped - socket full */
};
+#ifdef MRT6_OINIT
/*
* Struct used to communicate from kernel to multicast router
* note the convenient similarity to an IPv6 header.
+ * XXX old version, superseded by mrt6msg.
*/
-struct mrt6msg {
+struct omrt6msg {
u_long unused1;
u_char im6_msgtype; /* what type of message */
-#define MRT6MSG_NOCACHE 1
+#if 0
+#define MRT6MSG_NOCACHE 1
#define MRT6MSG_WRONGMIF 2
#define MRT6MSG_WHOLEPKT 3 /* used for user level encap*/
+#endif
u_char im6_mbz; /* must be zero */
u_char im6_mif; /* mif rec'd on */
u_char unused2;
struct in6_addr im6_src, im6_dst;
};
+#endif
+
+/*
+ * Structure used to communicate from kernel to multicast router.
+ * We'll overlay the structure onto an MLD header (not an IPv6 header
+ * like igmpmsg{} used for IPv4 implementation). This is because this
+ * structure will be passed via an IPv6 raw socket, on which an application
+ * will only receive the payload i.e. the data after the IPv6 header and all
+ * the extension headers. (see Section 3 of draft-ietf-ipngwg-2292bis-01)
+ */
+struct mrt6msg {
+#define MRT6MSG_NOCACHE 1
+#define MRT6MSG_WRONGMIF 2
+#define MRT6MSG_WHOLEPKT 3 /* used for user level encap*/
+ u_char im6_mbz; /* must be zero */
+ u_char im6_msgtype; /* what type of message */
+ u_int16_t im6_mif; /* mif rec'd on */
+ u_int32_t im6_pad; /* padding for 64bit arch */
+ struct in6_addr im6_src, im6_dst;
+};
/*
* Argument structure used by multicast routing daemon to get src-grp
@@ -413,7 +211,7 @@ struct mif6 {
u_int m6_rate_limit; /* max rate */
#ifdef notyet
struct tbf *m6_tbf; /* token bucket structure at intf. */
-#endif
+#endif
struct in6_addr m6_lcl_addr; /* local interface address */
struct ifnet *m6_ifp; /* pointer to interface */
u_quad_t m6_pkt_in; /* # pkts in on interface */
@@ -424,11 +222,11 @@ struct mif6 {
#ifdef notyet
u_int m6_rsvp_on; /* RSVP listening on this vif */
struct socket *m6_rsvpd; /* RSVP daemon socket */
-#endif
+#endif
};
/*
- * The kernel's multicast forwarding cache entry structure
+ * The kernel's multicast forwarding cache entry structure
*/
struct mf6c {
struct sockaddr_in6 mf6c_origin; /* IPv6 origin of mcasts */
@@ -470,13 +268,8 @@ struct rtdetq { /* XXX: rtdetq is also defined in ip_mroute.h */
#define MAX_UPQ6 4 /* max. no of pkts in upcall Q */
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
int ip6_mrouter_set __P((struct socket *so, struct sockopt *sopt));
int ip6_mrouter_get __P((struct socket *so, struct sockopt *sopt));
-#else
-int ip6_mrouter_set __P((int, struct socket *, struct mbuf *));
-int ip6_mrouter_get __P((int, struct socket *, struct mbuf **));
-#endif
int ip6_mrouter_done __P((void));
int mrt6_ioctl __P((int, caddr_t));
#endif /* _KERNEL */
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index eb0474f35e27..e23ba0002236 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip6_output.c,v 1.115 2000/07/03 13:23:28 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -64,8 +65,10 @@
* @(#)ip_output.c 8.3 (Berkeley) 1/21/94
*/
-#include "opt_ipsec.h"
#include "opt_ip6fw.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#include "opt_ipsec.h"
#include <sys/param.h>
#include <sys/malloc.h>
@@ -83,25 +86,20 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
-#include <netinet6/ip6.h>
-#include <netinet6/icmp6.h>
-#include <netinet/in_pcb.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
#include <netinet6/ip6_var.h>
+#include <netinet/in_pcb.h>
#include <netinet6/nd6.h>
#ifdef IPSEC
#include <netinet6/ipsec.h>
+#ifdef INET6
#include <netinet6/ipsec6.h>
-#include <netkey/key.h>
-#ifdef IPSEC_DEBUG
-#include <netkey/key_debug.h>
-#else
-#define KEYDEBUG(lev,arg)
#endif
+#include <netkey/key.h>
#endif /* IPSEC */
-#include "loop.h"
-
#include <net/net_osdep.h>
#ifdef IPV6FIREWALL
@@ -111,22 +109,22 @@
static MALLOC_DEFINE(M_IPMOPTS, "ip6_moptions", "internet multicast options");
struct ip6_exthdrs {
- struct mbuf *ip6e_ip6;
- struct mbuf *ip6e_hbh;
- struct mbuf *ip6e_dest1;
- struct mbuf *ip6e_rthdr;
- struct mbuf *ip6e_dest2;
+ struct mbuf *ip6e_ip6;
+ struct mbuf *ip6e_hbh;
+ struct mbuf *ip6e_dest1;
+ struct mbuf *ip6e_rthdr;
+ struct mbuf *ip6e_dest2;
};
-static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *,
+static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *,
struct socket *, struct sockopt *sopt));
-static int ip6_setmoptions __P((int, struct ip6_moptions **, struct mbuf *));
-static int ip6_getmoptions __P((int, struct ip6_moptions *, struct mbuf **));
-static int ip6_copyexthdr __P((struct mbuf **, caddr_t, int));
-static int ip6_insertfraghdr __P((struct mbuf *, struct mbuf *, int,
+static int ip6_setmoptions __P((int, struct ip6_moptions **, struct mbuf *));
+static int ip6_getmoptions __P((int, struct ip6_moptions *, struct mbuf **));
+static int ip6_copyexthdr __P((struct mbuf **, caddr_t, int));
+static int ip6_insertfraghdr __P((struct mbuf *, struct mbuf *, int,
struct ip6_frag **));
-static int ip6_insert_jumboopt __P((struct ip6_exthdrs *, u_int32_t));
-static int ip6_splithdr __P((struct mbuf *, struct ip6_exthdrs *));
+static int ip6_insert_jumboopt __P((struct ip6_exthdrs *, u_int32_t));
+static int ip6_splithdr __P((struct mbuf *, struct ip6_exthdrs *));
/*
* IP6 output. The packet in mbuf chain m contains a skeletal IP6
@@ -145,7 +143,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
struct ifnet **ifpp; /* XXX: just for statistics */
{
struct ip6_hdr *ip6, *mhip6;
- struct ifnet *ifp;
+ struct ifnet *ifp, *origifp;
struct mbuf *m = m0;
int hlen, tlen, len, off;
struct route_in6 ip6route;
@@ -165,16 +163,13 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
struct secpolicy *sp = NULL;
/* for AH processing. stupid to have "socket" variable in IP layer... */
- if ((flags & IPV6_SOCKINMRCVIF) != 0) {
- so = (struct socket *)m->m_pkthdr.rcvif;
- m->m_pkthdr.rcvif = NULL;
- } else
- so = NULL;
+ so = ipsec_getsocket(m);
+ ipsec_setsocket(m, NULL);
ip6 = mtod(m, struct ip6_hdr *);
#endif /* IPSEC */
-#define MAKE_EXTHDR(hp,mp) \
- { \
+#define MAKE_EXTHDR(hp, mp) \
+ do { \
if (hp) { \
struct ip6_ext *eh = (struct ip6_ext *)(hp); \
error = ip6_copyexthdr((mp), (caddr_t)(hp), \
@@ -182,9 +177,10 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
if (error) \
goto freehdrs; \
} \
- }
-
+ } while (0)
+
bzero(&exthdrs, sizeof(exthdrs));
+
if (opt) {
/* Hop-by-Hop options header */
MAKE_EXTHDR(opt->ip6po_hbh, &exthdrs.ip6e_hbh);
@@ -205,7 +201,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
if (sp == NULL) {
ipsec6stat.out_inval++;
- goto bad;
+ goto freehdrs;
}
error = 0;
@@ -217,7 +213,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
* This packet is just discarded.
*/
ipsec6stat.out_polvio++;
- goto bad;
+ goto freehdrs;
case IPSEC_POLICY_BYPASS:
case IPSEC_POLICY_NONE:
@@ -227,10 +223,9 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
case IPSEC_POLICY_IPSEC:
if (sp->req == NULL) {
- /* XXX should be panic ? */
- printf("ip6_output: No IPsec request specified.\n");
- error = EINVAL;
- goto bad;
+ /* acquire a policy */
+ error = key_spdacquire(sp);
+ goto freehdrs;
}
needipsec = 1;
break;
@@ -321,8 +316,8 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
ip6->ip6_nxt = IPPROTO_DSTOPTS;
}
-#define MAKE_CHAIN(m,mp,p,i)\
- {\
+#define MAKE_CHAIN(m, mp, p, i)\
+ do {\
if (m) {\
if (!hdrsplit) \
panic("assumption failed: hdr not split"); \
@@ -333,7 +328,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
(mp)->m_next = (m);\
(mp) = (m);\
}\
- }
+ } while (0)
/*
* result: IPv6 hbh dest1 rthdr dest2 payload
* m will point to IPv6 header. mprev will point to the
@@ -470,6 +465,11 @@ skip_ipsec2:;
dst->sin6_family = AF_INET6;
dst->sin6_len = sizeof(struct sockaddr_in6);
dst->sin6_addr = ip6->ip6_dst;
+#ifdef SCOPEDROUTING
+ /* XXX: sin6_scope_id should already be fixed at this point */
+ if (IN6_IS_SCOPE_LINKLOCAL(&dst->sin6_addr))
+ dst->sin6_scope_id = ntohs(dst->sin6_addr.s6_addr16[1]);
+#endif
}
#ifdef IPSEC
if (needipsec && needipsectun) {
@@ -520,7 +520,7 @@ skip_ipsec2:;
exthdrs.ip6e_ip6 = m;
}
-#endif /*IPESC*/
+#endif /*IPSEC*/
if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
/* Unicast */
@@ -532,8 +532,13 @@ skip_ipsec2:;
* if an interface is specified from an upper layer,
* ifp must point it.
*/
- if (ro->ro_rt == 0)
+ if (ro->ro_rt == 0) {
+ /*
+ * non-bsdi always clone routes, if parent is
+ * PRF_CLONING.
+ */
rtalloc((struct route *)ro);
+ }
if (ro->ro_rt == 0) {
ip6stat.ip6s_noroute++;
error = EHOSTUNREACH;
@@ -550,11 +555,11 @@ skip_ipsec2:;
in6_ifstat_inc(ifp, ifs6_out_request);
/*
- * Check if there is the outgoing interface conflicts with
- * the interface specified by ifi6_ifindex(if specified).
+ * Check if the outgoing interface conflicts with
+ * the interface specified by ifi6_ifindex (if specified).
* Note that loopback interface is always okay.
- * (this happens when we are sending packet toward my
- * interface)
+ * (this may happen when we are sending a packet to one of
+ * our own addresses.)
*/
if (opt && opt->ip6po_pktinfo
&& opt->ip6po_pktinfo->ipi6_ifindex) {
@@ -676,7 +681,7 @@ skip_ipsec2:;
* if necessary.
*/
if (ip6_mrouter && (flags & IPV6_FORWARDING) == 0) {
- if (ip6_mforward(ip6, ifp, m) != NULL) {
+ if (ip6_mforward(ip6, ifp, m) != 0) {
m_freem(m);
goto done;
}
@@ -746,10 +751,38 @@ skip_ipsec2:;
mtu = nd_ifinfo[ifp->if_index].linkmtu;
}
- /*
- * Fake link-local scope-class addresses
- */
- if ((ifp->if_flags & IFF_LOOPBACK) == 0) {
+ /* Fake scoped addresses */
+ if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
+ /*
+ * If source or destination address is a scoped address, and
+ * the packet is going to be sent to a loopback interface,
+ * we should keep the original interface.
+ */
+
+ /*
+ * XXX: this is a very experimental and temporary solution.
+ * We eventually have sockaddr_in6 and use the sin6_scope_id
+ * 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
+ * future.
+ */
+ 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 = ifp;
+ }
+ else
+ origifp = ifp;
+#ifndef FAKE_LOOPBACK_IF
+ if ((ifp->if_flags & IFF_LOOPBACK) == 0)
+#else
+ if (1)
+#endif
+ {
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
ip6->ip6_src.s6_addr16[1] = 0;
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
@@ -762,6 +795,7 @@ skip_ipsec2:;
*/
if (ip6_fw_chk_ptr) {
u_short port = 0;
+ m->m_pkthdr.rcvif = NULL; /*XXX*/
/* If ipfw says divert, we have to just drop packet */
if ((*ip6_fw_chk_ptr)(&ip6, ifp, &port, &m)) {
m_freem(m);
@@ -827,18 +861,7 @@ skip_ipsec2:;
#endif
)
{
-#if defined(__NetBSD__) && defined(IFA_STATS)
- if (IFA_STATS) {
- struct in6_ifaddr *ia6;
- ip6 = mtod(m, struct ip6_hdr *);
- ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
- if (ia6) {
- ia->ia_ifa.ifa_data.ifad_outbytes +=
- m->m_pkthdr.len;
- }
- }
-#endif
- error = nd6_output(ifp, m, dst, ro->ro_rt);
+ error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
goto done;
} else if (mtu < IPV6_MMTU) {
/*
@@ -954,18 +977,7 @@ sendorfree:
m0 = m->m_nextpkt;
m->m_nextpkt = 0;
if (error == 0) {
-#if defined(__NetBSD__) && defined(IFA_STATS)
- if (IFA_STATS) {
- struct in6_ifaddr *ia6;
- ip6 = mtod(m, struct ip6_hdr *);
- ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
- if (ia6) {
- ia->ia_ifa.ifa_data.ifad_outbytes +=
- m->m_pkthdr.len;
- }
- }
-#endif
- error = nd6_output(ifp, m, dst, ro->ro_rt);
+ error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
} else
m_freem(m);
}
@@ -1124,7 +1136,7 @@ ip6_insertfraghdr(m0, m, hlen, frghdrp)
;
if ((mlast->m_flags & M_EXT) == 0 &&
- M_TRAILINGSPACE(mlast) < sizeof(struct ip6_frag)) {
+ M_TRAILINGSPACE(mlast) >= sizeof(struct ip6_frag)) {
/* use the trailing space of the last mbuf for the fragment hdr */
*frghdrp =
(struct ip6_frag *)(mtod(mlast, caddr_t) + mlast->m_len);
@@ -1198,9 +1210,6 @@ ip6_ctloutput(so, sopt)
}
/* fall through */
case IPV6_UNICAST_HOPS:
- case IPV6_RECVOPTS:
- case IPV6_RECVRETOPTS:
- case IPV6_RECVDSTADDR:
case IPV6_PKTINFO:
case IPV6_HOPLIMIT:
case IPV6_RTHDR:
@@ -1233,18 +1242,6 @@ ip6_ctloutput(so, sopt)
else \
in6p->in6p_flags &= ~bit;
- case IPV6_RECVOPTS:
- OPTSET(IN6P_RECVOPTS);
- break;
-
- case IPV6_RECVRETOPTS:
- OPTSET(IN6P_RECVRETOPTS);
- break;
-
- case IPV6_RECVDSTADDR:
- OPTSET(IN6P_RECVDSTADDR);
- break;
-
case IPV6_PKTINFO:
OPTSET(IN6P_PKTINFO);
break;
@@ -1308,50 +1305,51 @@ ip6_ctloutput(so, sopt)
}
break;
- case IPV6_PORTRANGE:
- error = sooptcopyin(sopt, &optval, sizeof optval,
- sizeof optval);
- if (error)
- break;
+ case IPV6_PORTRANGE:
+ error = sooptcopyin(sopt, &optval,
+ sizeof optval, sizeof optval);
+ if (error)
+ break;
- switch (optval) {
- case IPV6_PORTRANGE_DEFAULT:
- in6p->in6p_flags &= ~(IN6P_LOWPORT);
- in6p->in6p_flags &= ~(IN6P_HIGHPORT);
- break;
+ switch (optval) {
+ case IPV6_PORTRANGE_DEFAULT:
+ in6p->in6p_flags &= ~(IN6P_LOWPORT);
+ in6p->in6p_flags &= ~(IN6P_HIGHPORT);
+ break;
- case IPV6_PORTRANGE_HIGH:
- in6p->in6p_flags &= ~(IN6P_LOWPORT);
- in6p->in6p_flags |= IN6P_HIGHPORT;
- break;
+ case IPV6_PORTRANGE_HIGH:
+ in6p->in6p_flags &= ~(IN6P_LOWPORT);
+ in6p->in6p_flags |= IN6P_HIGHPORT;
+ break;
- case IPV6_PORTRANGE_LOW:
- in6p->in6p_flags &= ~(IN6P_HIGHPORT);
- in6p->in6p_flags |= IN6P_LOWPORT;
- break;
+ case IPV6_PORTRANGE_LOW:
+ in6p->in6p_flags &= ~(IN6P_HIGHPORT);
+ in6p->in6p_flags |= IN6P_LOWPORT;
+ break;
- default:
- error = EINVAL;
+ default:
+ error = EINVAL;
+ break;
+ }
break;
- }
- break;
#ifdef IPSEC
case IPV6_IPSEC_POLICY:
{
caddr_t req = NULL;
+ size_t len = 0;
struct mbuf *m;
- if ((error = soopt_getm(sopt, &m))
- != 0) /* XXX */
+ if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */
break;
- if ((error = soopt_mcopyin(sopt, m))
- != 0) /* XXX */
+ if ((error = soopt_mcopyin(sopt, m)) != 0) /* XXX */
break;
- if (m != 0)
+ if (m) {
req = mtod(m, caddr_t);
+ len = m->m_len;
+ }
error = ipsec6_set_policy(in6p, optname, req,
- privileged);
+ len, privileged);
m_freem(m);
}
break;
@@ -1389,11 +1387,6 @@ ip6_ctloutput(so, sopt)
case SOPT_GET:
switch (optname) {
- case IPV6_OPTIONS:
- case IPV6_RETOPTS:
- error = ENOPROTOOPT;
- break;
-
case IPV6_PKTOPTIONS:
if (in6p->in6p_options) {
error = soopt_mcopyout(sopt,
@@ -1410,9 +1403,6 @@ ip6_ctloutput(so, sopt)
}
/* fall through */
case IPV6_UNICAST_HOPS:
- case IPV6_RECVOPTS:
- case IPV6_RECVRETOPTS:
- case IPV6_RECVDSTADDR:
case IPV6_PKTINFO:
case IPV6_HOPLIMIT:
case IPV6_RTHDR:
@@ -1428,18 +1418,6 @@ ip6_ctloutput(so, sopt)
#define OPTBIT(bit) (in6p->in6p_flags & bit ? 1 : 0)
- case IPV6_RECVOPTS:
- optval = OPTBIT(IN6P_RECVOPTS);
- break;
-
- case IPV6_RECVRETOPTS:
- optval = OPTBIT(IN6P_RECVRETOPTS);
- break;
-
- case IPV6_RECVDSTADDR:
- optval = OPTBIT(IN6P_RECVDSTADDR);
- break;
-
case IPV6_PKTINFO:
optval = OPTBIT(IN6P_PKTINFO);
break;
@@ -1509,17 +1487,25 @@ ip6_ctloutput(so, sopt)
#ifdef IPSEC
case IPV6_IPSEC_POLICY:
{
-
- struct mbuf *m = NULL;
caddr_t req = NULL;
+ size_t len = 0;
+ struct mbuf *m = NULL;
+ struct mbuf **mp = &m;
- if (m != 0)
+ error = soopt_getm(sopt, &m); /* XXX */
+ if (error != NULL)
+ break;
+ error = soopt_mcopyin(sopt, m); /* XXX */
+ if (error != NULL)
+ break;
+ if (m) {
req = mtod(m, caddr_t);
- error = ipsec6_get_policy(in6p, req, &m);
+ len = m->m_len;
+ }
+ error = ipsec6_get_policy(in6p, req, len, mp);
if (error == 0)
error = soopt_mcopyout(sopt, m); /*XXX*/
- if (error == 0)
- m_freem(m);
+ m_freem(m);
break;
}
#endif /* IPSEC */
@@ -1710,7 +1696,8 @@ ip6_setmoptions(optname, im6op, m)
* all multicast addresses. Only super user is allowed
* to do this.
*/
- if (suser(p)) {
+ if (suser(p))
+ {
error = EACCES;
break;
}
@@ -1778,7 +1765,8 @@ ip6_setmoptions(optname, im6op, m)
/*
* See if the membership already exists.
*/
- LIST_FOREACH(imm, &im6o->im6o_memberships, i6mm_chain)
+ for (imm = im6o->im6o_memberships.lh_first;
+ imm != NULL; imm = imm->i6mm_chain.le_next)
if (imm->i6mm_maddr->in6m_ifp == ifp &&
IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
&mreq->ipv6mr_multiaddr))
@@ -1844,7 +1832,8 @@ ip6_setmoptions(optname, im6op, m)
/*
* Find the membership in the membership list.
*/
- LIST_FOREACH(imm, &im6o->im6o_memberships, i6mm_chain) {
+ for (imm = im6o->im6o_memberships.lh_first;
+ imm != NULL; imm = imm->i6mm_chain.le_next) {
if ((ifp == NULL ||
imm->i6mm_maddr->in6m_ifp == ifp) &&
IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
@@ -1876,7 +1865,7 @@ ip6_setmoptions(optname, im6op, m)
if (im6o->im6o_multicast_ifp == NULL &&
im6o->im6o_multicast_hlim == ip6_defmcasthlim &&
im6o->im6o_multicast_loop == IPV6_DEFAULT_MULTICAST_LOOP &&
- LIST_EMPTY(&im6o->im6o_memberships)) {
+ im6o->im6o_memberships.lh_first == NULL) {
free(*im6op, M_IPMOPTS);
*im6op = NULL;
}
@@ -1943,7 +1932,7 @@ ip6_freemoptions(im6o)
if (im6o == NULL)
return;
- while ((imm = LIST_FIRST(&im6o->im6o_memberships)) != NULL) {
+ while ((imm = im6o->im6o_memberships.lh_first) != NULL) {
LIST_REMOVE(imm, i6mm_chain);
if (imm->i6mm_maddr)
in6_delmulti(imm->i6mm_maddr);
@@ -1976,8 +1965,6 @@ 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)) {
cm = mtod(control, struct cmsghdr *);
@@ -2120,12 +2107,46 @@ ip6_mloopback(ifp, m, dst)
register struct mbuf *m;
register struct sockaddr_in6 *dst;
{
- struct mbuf *copym;
+ struct mbuf *copym;
+ struct ip6_hdr *ip6;
copym = m_copy(m, 0, M_COPYALL);
- if (copym != NULL) {
- (void)if_simloop(ifp, copym, dst->sin6_family, 0);
+ if (copym == NULL)
+ return;
+
+ /*
+ * Make sure to deep-copy IPv6 header portion in case the data
+ * is in an mbuf cluster, so that we can safely override the IPv6
+ * header portion later.
+ */
+ if ((copym->m_flags & M_EXT) != 0 ||
+ copym->m_len < sizeof(struct ip6_hdr)) {
+ copym = m_pullup(copym, sizeof(struct ip6_hdr));
+ if (copym == NULL)
+ return;
}
+
+#ifdef DIAGNOSTIC
+ if (copym->m_len < sizeof(*ip6)) {
+ m_freem(copym);
+ return;
+ }
+#endif
+
+#ifndef FAKE_LOOPBACK_IF
+ if ((ifp->if_flags & IFF_LOOPBACK) == 0)
+#else
+ if (1)
+#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);
}
/*
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
index 2e70bcb5aefd..f6f38247ec5f 100644
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -72,35 +73,37 @@
* being reassembled is attached to one of these structures.
*/
struct ip6q {
- u_long ip6q_head;
- u_short ip6q_len;
- u_char ip6q_nxt;
- u_char ip6q_hlim;
- struct ip6asfrag *ip6q_down;
- struct ip6asfrag *ip6q_up;
- u_long ip6q_ident;
- u_char ip6q_arrive;
- u_char ip6q_ttl;
- struct in6_addr ip6q_src, ip6q_dst;
- struct ip6q *ip6q_next;
- struct ip6q *ip6q_prev;
- int ip6q_unfrglen;
+ u_int32_t ip6q_head;
+ u_int16_t ip6q_len;
+ u_int8_t ip6q_nxt; /* ip6f_nxt in first fragment */
+ u_int8_t ip6q_hlim;
+ struct ip6asfrag *ip6q_down;
+ struct ip6asfrag *ip6q_up;
+ u_int32_t ip6q_ident;
+ u_int8_t ip6q_arrive;
+ u_int8_t ip6q_ttl;
+ struct in6_addr ip6q_src, ip6q_dst;
+ struct ip6q *ip6q_next;
+ struct ip6q *ip6q_prev;
+ int ip6q_unfrglen; /* len of unfragmentable part */
+#ifdef notyet
+ u_char *ip6q_nxtp;
+#endif
};
struct ip6asfrag {
- u_long ip6af_head;
- u_short ip6af_len;
- u_char ip6af_nxt;
- u_char ip6af_hlim;
+ u_int32_t ip6af_head;
+ u_int16_t ip6af_len;
+ u_int8_t ip6af_nxt;
+ u_int8_t ip6af_hlim;
/* must not override the above members during reassembling */
- struct ip6asfrag *ip6af_down;
- struct ip6asfrag *ip6af_up;
- u_short ip6af_mff;
- u_short ip6af_off;
- struct mbuf *ip6af_m;
- u_long ip6af_offset; /* offset where next header starts */
- u_short ip6af_frglen; /* fragmentable part length */
- u_char ip6af_x1[10];
+ struct ip6asfrag *ip6af_down;
+ struct ip6asfrag *ip6af_up;
+ struct mbuf *ip6af_m;
+ int ip6af_offset; /* offset in ip6af_m to next header */
+ int ip6af_frglen; /* fragmentable part length */
+ int ip6af_off; /* fragment offset */
+ u_int16_t ip6af_mff; /* more fragment bit in frag off */
};
#define IP6_REASS_MBUF(ip6af) (*(struct mbuf **)&((ip6af)->ip6af_m))
@@ -121,8 +124,8 @@ struct ip6po_rhinfo {
struct ip6_rthdr *ip6po_rhi_rthdr; /* Routing header */
struct route_in6 ip6po_rhi_route; /* Route to the 1st hop */
};
-#define ip6po_rthdr ip6po_rhinfo.ip6po_rhi_rthdr
-#define ip6po_route ip6po_rhinfo.ip6po_rhi_route
+#define ip6po_rthdr ip6po_rhinfo.ip6po_rhi_rthdr
+#define ip6po_route ip6po_rhinfo.ip6po_rhi_route
struct ip6_pktopts {
struct mbuf *ip6po_m; /* Pointer to mbuf storing the data */
@@ -136,49 +139,88 @@ struct ip6_pktopts {
};
struct ip6stat {
- u_long ip6s_total; /* total packets received */
- u_long ip6s_tooshort; /* packet too short */
- u_long ip6s_toosmall; /* not enough data */
- u_long ip6s_fragments; /* fragments received */
- u_long ip6s_fragdropped; /* frags dropped(dups, out of space) */
- u_long ip6s_fragtimeout; /* fragments timed out */
- u_long ip6s_fragoverflow; /* fragments that exceeded limit */
- u_long ip6s_forward; /* packets forwarded */
- u_long ip6s_cantforward; /* packets rcvd for unreachable dest */
- u_long ip6s_redirectsent; /* packets forwarded on same net */
- u_long ip6s_delivered; /* datagrams delivered to upper level*/
- u_long ip6s_localout; /* total ip packets generated here */
- u_long ip6s_odropped; /* lost packets due to nobufs, etc. */
- u_long ip6s_reassembled; /* total packets reassembled ok */
- u_long ip6s_fragmented; /* datagrams sucessfully fragmented */
- u_long ip6s_ofragments; /* output fragments created */
- u_long ip6s_cantfrag; /* don't fragment flag was set, etc. */
- u_long ip6s_badoptions; /* error in option processing */
- u_long ip6s_noroute; /* packets discarded due to no route */
- u_long ip6s_badvers; /* ip6 version != 6 */
- u_long ip6s_rawout; /* total raw ip packets generated */
- u_long ip6s_badscope; /* scope error */
- u_long ip6s_notmember; /* don't join this multicast group */
- u_long ip6s_nxthist[256]; /* next header history */
- u_long ip6s_m1; /* one mbuf */
- u_long ip6s_m2m[32]; /* two or more mbuf */
- u_long ip6s_mext1; /* one ext mbuf */
- u_long ip6s_mext2m; /* two or more ext mbuf */
- u_long ip6s_exthdrtoolong; /* ext hdr are not continuous */
- u_long ip6s_nogif; /* no match gif found */
- u_long ip6s_toomanyhdr; /* discarded due to too many headers */
+ u_quad_t ip6s_total; /* total packets received */
+ u_quad_t ip6s_tooshort; /* packet too short */
+ u_quad_t ip6s_toosmall; /* not enough data */
+ u_quad_t ip6s_fragments; /* fragments received */
+ u_quad_t ip6s_fragdropped; /* frags dropped(dups, out of space) */
+ u_quad_t ip6s_fragtimeout; /* fragments timed out */
+ u_quad_t ip6s_fragoverflow; /* fragments that exceeded limit */
+ u_quad_t ip6s_forward; /* packets forwarded */
+ u_quad_t ip6s_cantforward; /* packets rcvd for unreachable dest */
+ u_quad_t ip6s_redirectsent; /* packets forwarded on same net */
+ u_quad_t ip6s_delivered; /* datagrams delivered to upper level*/
+ u_quad_t ip6s_localout; /* total ip packets generated here */
+ u_quad_t ip6s_odropped; /* lost packets due to nobufs, etc. */
+ u_quad_t ip6s_reassembled; /* total packets reassembled ok */
+ u_quad_t ip6s_fragmented; /* datagrams sucessfully fragmented */
+ u_quad_t ip6s_ofragments; /* output fragments created */
+ u_quad_t ip6s_cantfrag; /* don't fragment flag was set, etc. */
+ u_quad_t ip6s_badoptions; /* error in option processing */
+ u_quad_t ip6s_noroute; /* packets discarded due to no route */
+ u_quad_t ip6s_badvers; /* ip6 version != 6 */
+ u_quad_t ip6s_rawout; /* total raw ip packets generated */
+ u_quad_t ip6s_badscope; /* scope error */
+ u_quad_t ip6s_notmember; /* don't join this multicast group */
+ u_quad_t ip6s_nxthist[256]; /* next header history */
+ u_quad_t ip6s_m1; /* one mbuf */
+ u_quad_t ip6s_m2m[32]; /* two or more mbuf */
+ u_quad_t ip6s_mext1; /* one ext mbuf */
+ u_quad_t ip6s_mext2m; /* two or more ext mbuf */
+ u_quad_t ip6s_exthdrtoolong; /* ext hdr are not continuous */
+ u_quad_t ip6s_nogif; /* no match gif found */
+ u_quad_t ip6s_toomanyhdr; /* discarded due to too many headers */
+ /* XXX the following two items are not really AF_INET6 thing */
+ u_quad_t ip6s_exthdrget; /* # of calls to IP6_EXTHDR_GET */
+ u_quad_t ip6s_exthdrget0; /* # of calls to IP6_EXTHDR_GET0 */
+ u_quad_t ip6s_pulldown; /* # of calls to m_pulldown */
+ u_quad_t ip6s_pulldown_copy; /* # of mbuf copies in m_pulldown */
+ u_quad_t ip6s_pulldown_alloc; /* # of mbuf allocs in m_pulldown */
+ u_quad_t ip6s_pullup; /* # of calls to m_pullup */
+ u_quad_t ip6s_pullup_copy; /* # of possible m_pullup copies */
+ u_quad_t ip6s_pullup_alloc; /* # of possible m_pullup mallocs */
+ u_quad_t ip6s_pullup_fail; /* # of possible m_pullup failures */
+ u_quad_t ip6s_pullup2; /* # of calls to m_pullup2 */
+ u_quad_t ip6s_pullup2_copy; /* # of possible m_pullup2 copies */
+ u_quad_t ip6s_pullup2_alloc; /* # of possible m_pullup2 mallocs */
+ u_quad_t ip6s_pullup2_fail; /* # of possible m_pullup2 failures */
+
+ /*
+ * statistics for improvement of the source address selection
+ * algorithm:
+ * XXX: hardcoded 16 = # of ip6 multicast scope types + 1
+ */
+ /* number of times that address selection fails */
+ u_quad_t ip6s_sources_none;
+ /* number of times that an address on the outgoing I/F is chosen */
+ u_quad_t ip6s_sources_sameif[16];
+ /* number of times that an address on a non-outgoing I/F is chosen */
+ u_quad_t ip6s_sources_otherif[16];
+ /*
+ * number of times that an address that has the same scope
+ * from the destination is chosen.
+ */
+ u_quad_t ip6s_sources_samescope[16];
+ /*
+ * number of times that an address that has a different scope
+ * from the destination is chosen.
+ */
+ u_quad_t ip6s_sources_otherscope[16];
+ /* number of times that an deprecated address is chosen */
+ u_quad_t ip6s_sources_deprecated[16];
+
+ u_quad_t ip6s_forward_cachehit;
+ u_quad_t ip6s_forward_cachemiss;
};
#ifdef _KERNEL
/* flags passed to ip6_output as last parameter */
#define IPV6_DADOUTPUT 0x01 /* DAD */
#define IPV6_FORWARDING 0x02 /* most of IPv6 header exists */
-#define IPV6_SOCKINMRCVIF 0x100 /* IPSEC hack;
- * socket pointer in sending
- * packet's m_pkthdr.rcvif */
+#define IPV6_MINMTU 0x04 /* use minimum MTU (IPV6_USE_MIN_MTU) */
extern struct ip6stat ip6stat; /* statistics */
-extern u_int32_t ip6_id; /* fragment identifier */
+extern u_int32_t ip6_id; /* fragment identifier */
extern int ip6_defhlim; /* default hop limit */
extern int ip6_defmcasthlim; /* default multicast hop limit */
extern int ip6_forwarding; /* act as router? */
@@ -189,7 +231,7 @@ extern int ip6_rr_prune; /* router renumbering prefix
* walk list every 5 sec. */
extern int ip6_mapped_addr_on;
-extern struct socket *ip6_mrouter; /* multicast routing daemon */
+extern struct socket *ip6_mrouter; /* multicast routing daemon */
extern int ip6_sendredirects; /* send IP redirects when forwarding? */
extern int ip6_maxfragpackets; /* Maximum packets in reassembly queue */
extern int ip6_sourcecheck; /* Verify source interface */
@@ -201,12 +243,13 @@ extern time_t ip6_log_time;
extern int ip6_hdrnestlimit; /* upper limit of # of extension headers */
extern int ip6_dad_count; /* DupAddrDetectionTransmits */
-extern u_int32_t ip6_flow_seq;
-extern int ip6_auto_flowlabel;
+extern u_int32_t ip6_flow_seq;
+extern int ip6_auto_flowlabel;
extern struct pr_usrreqs rip6_usrreqs;
-struct sockopt;
-struct inpcb;
+struct sockopt;
+
+struct inpcb;
int icmp6_ctloutput __P((struct socket *, struct sockopt *sopt));
@@ -216,6 +259,8 @@ void ip6_input __P((struct mbuf *));
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 *));
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 *));
@@ -231,6 +276,8 @@ int ip6_output __P((struct mbuf *, struct ip6_pktopts *,
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 ip6_clearpktopts __P((struct ip6_pktopts *, int, int));
+struct ip6_pktopts *ip6_copypktopts __P((struct ip6_pktopts *, int));
int ip6_optlen __P((struct inpcb *));
int route6_input __P((struct mbuf **, int *, int));
@@ -242,6 +289,7 @@ void frag6_drain __P((void));
void rip6_init __P((void));
int rip6_input __P((struct mbuf **mp, int *offp, int proto));
+void rip6_ctlinput __P((int, struct sockaddr *, void *));
int rip6_ctloutput __P((struct socket *so, struct sockopt *sopt));
int rip6_output __P((struct mbuf *, ...));
int rip6_usrreq __P((struct socket *,
diff --git a/sys/netinet6/ip6protosw.h b/sys/netinet6/ip6protosw.h
index 1e1c3c2fdd04..c361219fd46d 100644
--- a/sys/netinet6/ip6protosw.h
+++ b/sys/netinet6/ip6protosw.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip6protosw.h,v 1.10 2000/03/29 22:51:25 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -26,7 +29,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
/* BSDI protosw.h,v 2.3 1996/10/11 16:02:40 pjd Exp */
@@ -74,23 +76,22 @@
* All other definitions should refer to sys/protosw.h
*/
-struct mbuf;
-struct sockaddr;
-struct socket;
-struct sockopt;
-struct domain;
-struct proc;
-struct ip6_hdr;
-struct pr_usrreqs;
+struct mbuf;
+struct sockaddr;
+struct socket;
+struct domain;
+struct proc;
+struct ip6_hdr;
+struct pr_usrreqs;
/*
* argument type for the last arg of pr_ctlinput().
* should be consulted only with AF_INET6 family.
*/
struct ip6ctlparam {
- struct mbuf *ip6c_m; /* start of mbuf chain */
- struct ip6_hdr *ip6c_ip6; /* ip6 header of target packet */
- int ip6c_off; /* offset of the target proto header */
+ struct mbuf *ip6c_m; /* start of mbuf chain */
+ struct ip6_hdr *ip6c_ip6; /* ip6 header of target packet */
+ int ip6c_off; /* offset of the target proto header */
};
struct ip6protosw {
diff --git a/sys/netinet6/ipcomp.h b/sys/netinet6/ipcomp.h
new file mode 100644
index 000000000000..dea5ea8e7097
--- /dev/null
+++ b/sys/netinet6/ipcomp.h
@@ -0,0 +1,67 @@
+/* $FreeBSD$ */
+/* $KAME: ipcomp.h,v 1.7 2000/05/18 12:45:13 sumikawa Exp $ */
+
+/*
+ * Copyright (C) 1999 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.
+ */
+
+/*
+ * RFC2393 IP payload compression protocol (IPComp).
+ */
+
+#ifndef _NETINET6_IPCOMP_H_
+#define _NETINET6_IPCOMP_H_
+
+struct ipcomp {
+ u_int8_t comp_nxt; /* Next Header */
+ u_int8_t comp_flags; /* reserved, must be zero */
+ u_int16_t comp_cpi; /* Compression parameter index */
+};
+
+/* well-known algorithm number (in CPI), from RFC2409 */
+#define IPCOMP_OUI 1 /* vendor specific */
+#define IPCOMP_DEFLATE 2 /* RFC2394 */
+#define IPCOMP_LZS 3 /* RFC2395 */
+#define IPCOMP_MAX 4
+
+#define IPCOMP_CPI_NEGOTIATE_MIN 256
+
+#ifdef _KERNEL
+struct ipcomp_algorithm {
+ int (*compress) __P((struct mbuf *, struct mbuf *, size_t *));
+ int (*decompress) __P((struct mbuf *, struct mbuf *, size_t *));
+ size_t minplen; /* minimum required length for compression */
+};
+
+struct ipsecrequest;
+extern struct ipcomp_algorithm ipcomp_algorithms[];
+extern void ipcomp4_input __P((struct mbuf *, ...));
+extern int ipcomp4_output __P((struct mbuf *, struct ipsecrequest *));
+#endif /*KERNEL*/
+
+#endif /*_NETINET6_IPCOMP_H_*/
diff --git a/sys/netinet6/ipcomp6.h b/sys/netinet6/ipcomp6.h
new file mode 100644
index 000000000000..553c8df7c4f4
--- /dev/null
+++ b/sys/netinet6/ipcomp6.h
@@ -0,0 +1,46 @@
+/* $FreeBSD$ */
+/* $KAME: ipcomp.h,v 1.7 2000/05/18 12:45:13 sumikawa Exp $ */
+
+/*
+ * Copyright (C) 1999 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.
+ */
+
+/*
+ * RFC2393 IP payload compression protocol (IPComp).
+ */
+
+#ifndef _NETINET6_IPCOMP6_H_
+#define _NETINET6_IPCOMP6_H_
+
+#ifdef _KERNEL
+extern int ipcomp6_input __P((struct mbuf **, int *, int));
+extern int ipcomp6_output __P((struct mbuf *, u_char *, struct mbuf *,
+ struct ipsecrequest *));
+#endif /*KERNEL*/
+
+#endif /*_NETINET6_IPCOMP6_H_*/
diff --git a/sys/netinet6/ipcomp_core.c b/sys/netinet6/ipcomp_core.c
new file mode 100644
index 000000000000..1eee2538b968
--- /dev/null
+++ b/sys/netinet6/ipcomp_core.c
@@ -0,0 +1,314 @@
+/* $FreeBSD$ */
+/* $KAME: ipcomp_core.c,v 1.12 2000/05/05 11:01:01 sumikawa Exp $ */
+
+/*
+ * Copyright (C) 1999 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.
+ */
+
+/*
+ * RFC2393 IP payload compression protocol (IPComp).
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#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/syslog.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+#include <net/zlib.h>
+#include <machine/cpu.h>
+
+#include <netinet6/ipcomp.h>
+#ifdef INET6
+#include <netinet6/ipcomp6.h>
+#endif
+#include <netinet6/ipsec.h>
+#ifdef INET6
+#include <netinet6/ipsec6.h>
+#endif
+
+#include <machine/stdarg.h>
+
+#include <net/net_osdep.h>
+
+static void *deflate_alloc __P((void *, u_int, u_int));
+static void deflate_free __P((void *, void *));
+static int deflate_common __P((struct mbuf *, struct mbuf *, size_t *, int));
+static int deflate_compress __P((struct mbuf *, struct mbuf *, size_t *));
+static int deflate_decompress __P((struct mbuf *, struct mbuf *, size_t *));
+
+/*
+ * We need to use default window size (2^15 = 32Kbytes as of writing) for
+ * inbound case. Otherwise we get interop problem.
+ * Use negative value to avoid Adler32 checksum. This is an undocumented
+ * feature in zlib (see ipsec wg mailing list archive in January 2000).
+ */
+static int deflate_policy = Z_DEFAULT_COMPRESSION;
+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 },
+ { deflate_compress, deflate_decompress, 90 },
+ { NULL, NULL, 90 },
+};
+
+static void *
+deflate_alloc(aux, items, siz)
+ void *aux;
+ u_int items;
+ u_int siz;
+{
+ void *ptr;
+ MALLOC(ptr, void *, items * siz, M_TEMP, M_NOWAIT);
+ return ptr;
+}
+
+static void
+deflate_free(aux, ptr)
+ void *aux;
+ void *ptr;
+{
+ FREE(ptr, M_TEMP);
+}
+
+static int
+deflate_common(m, md, lenp, mode)
+ struct mbuf *m;
+ struct mbuf *md;
+ size_t *lenp;
+ int mode; /* 0: compress 1: decompress */
+{
+ struct mbuf *mprev;
+ struct mbuf *p;
+ struct mbuf *n, *n0 = NULL, **np;
+ z_stream zs;
+ int error = 0;
+ int zerror;
+ size_t offset;
+ int firsttime, final, flush;
+
+ for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
+ ;
+ if (!mprev)
+ panic("md is not in m in deflate_common");
+
+ bzero(&zs, sizeof(zs));
+ zs.zalloc = deflate_alloc;
+ zs.zfree = deflate_free;
+
+ zerror = mode ? inflateInit2(&zs, deflate_window_in)
+ : deflateInit2(&zs, deflate_policy, Z_DEFLATED,
+ deflate_window_out, deflate_memlevel,
+ Z_DEFAULT_STRATEGY);
+ if (zerror != Z_OK) {
+ error = ENOBUFS;
+ goto fail;
+ }
+
+ 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);
+ }
+
+ /* 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;
+ }
+ }
+
+ /* 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;
+ }
+
+ /* 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;
+ }
+
+ 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)
+ break;
+ else {
+ ipseclog((LOG_ERR, "ipcomp_%scompress: %sflate: %s\n",
+ mode ? "de" : "", mode ? "in" : "de",
+ zs.msg ? zs.msg : "unknown error"));
+ error = EINVAL;
+ goto fail;
+ }
+ }
+ 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"));
+ error = EINVAL;
+ goto fail;
+ }
+ /* keep the final reply buffer into our chain */
+ if (n) {
+ n->m_len = zs.total_out - offset;
+ offset = zs.total_out;
+ *np = n;
+ np = &n->m_next;
+ }
+
+ /* switch the mbuf to the new one */
+ mprev->m_next = n0;
+ m_freem(md);
+ *lenp = zs.total_out;
+
+ return 0;
+
+fail:
+ if (m)
+ m_freem(m);
+ if (n0)
+ m_freem(n0);
+ return error;
+}
+
+static int
+deflate_compress(m, md, lenp)
+ struct mbuf *m;
+ struct mbuf *md;
+ size_t *lenp;
+{
+ if (!m)
+ panic("m == NULL in deflate_compress");
+ if (!md)
+ panic("md == NULL in deflate_compress");
+ if (!lenp)
+ panic("lenp == NULL in deflate_compress");
+
+ return deflate_common(m, md, lenp, 0);
+}
+
+static int
+deflate_decompress(m, md, lenp)
+ struct mbuf *m;
+ struct mbuf *md;
+ size_t *lenp;
+{
+ if (!m)
+ panic("m == NULL in deflate_decompress");
+ if (!md)
+ panic("md == NULL in deflate_decompress");
+ if (!lenp)
+ panic("lenp == NULL in deflate_decompress");
+
+ return deflate_common(m, md, lenp, 1);
+}
diff --git a/sys/netinet6/ipcomp_input.c b/sys/netinet6/ipcomp_input.c
new file mode 100644
index 000000000000..da0184c82c7a
--- /dev/null
+++ b/sys/netinet6/ipcomp_input.c
@@ -0,0 +1,407 @@
+/* $FreeBSD$ */
+/* $KAME: ipcomp_input.c,v 1.15 2000/07/03 13:23:28 itojun Exp $ */
+
+/*
+ * Copyright (C) 1999 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.
+ */
+
+/*
+ * RFC2393 IP payload compression protocol (IPComp).
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.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/syslog.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+#include <net/zlib.h>
+#include <machine/cpu.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_ecn.h>
+
+#ifdef INET6
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#endif
+#include <netinet6/ipcomp.h>
+#ifdef INET6
+#include <netinet6/ipcomp6.h>
+#endif
+
+#include <netinet6/ipsec.h>
+#ifdef INET6
+#include <netinet6/ipsec6.h>
+#endif
+#include <netkey/key.h>
+#include <netkey/keydb.h>
+
+#include <machine/stdarg.h>
+
+#include <net/net_osdep.h>
+
+#define IPLEN_FLIPPED
+
+#ifdef INET
+#include <netinet/ipprotosw.h>
+extern struct ipprotosw inetsw[];
+
+void
+#if __STDC__
+ipcomp4_input(struct mbuf *m, ...)
+#else
+ipcomp4_input(m, va_alist)
+ struct mbuf *m;
+ va_dcl
+#endif
+{
+ struct ip *ip;
+ struct ipcomp *ipcomp;
+ struct ipcomp_algorithm *algo;
+ u_int16_t cpi; /* host order */
+ u_int16_t nxt;
+ size_t hlen;
+ int error;
+ size_t newlen, olen;
+ struct secasvar *sav = NULL;
+ int off, proto;
+ va_list ap;
+
+ va_start(ap, m);
+ off = va_arg(ap, int);
+ proto = va_arg(ap, int);
+ va_end(ap);
+
+ if (off + sizeof(struct ipcomp) > MHLEN) {
+ /*XXX the restriction should be relaxed*/
+ ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed "
+ "(header too long)\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;
+ }
+
+ 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;
+#else
+ hlen = ip->ip_hl << 2;
+#endif
+
+ cpi = ntohs(ipcomp->comp_cpi);
+
+ if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) {
+ sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src,
+ (caddr_t)&ip->ip_dst, IPPROTO_IPCOMP, htonl(cpi));
+ if (sav != NULL
+ && (sav->state == SADB_SASTATE_MATURE
+ || sav->state == SADB_SASTATE_DYING)) {
+ cpi = sav->alg_enc; /*XXX*/
+ /* other parameters to look at? */
+ }
+ }
+ if (cpi < IPCOMP_MAX && ipcomp_algorithms[cpi].decompress != NULL)
+ algo = &ipcomp_algorithms[cpi];
+ else
+ algo = NULL;
+ if (!algo) {
+ ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n",
+ cpi));
+ ipsecstat.in_nosa++;
+ goto fail;
+ }
+
+ /* chop ipcomp header */
+ ipcomp = NULL;
+ m->m_len -= sizeof(struct ipcomp);
+ m->m_pkthdr.len -= sizeof(struct ipcomp);
+#ifdef IPLEN_FLIPPED
+ ip->ip_len -= sizeof(struct ipcomp);
+#else
+ ip->ip_len = htons(ntohs(ip->ip_len) - sizeof(struct ipcomp));
+#endif
+
+ olen = m->m_pkthdr.len;
+ newlen = m->m_pkthdr.len - off;
+ error = (*algo->decompress)(m, m->m_next, &newlen);
+ if (error != 0) {
+ if (error == EINVAL)
+ ipsecstat.in_inval++;
+ else if (error == ENOBUFS)
+ ipsecstat.in_nomem++;
+ m = NULL;
+ goto fail;
+ }
+ ipsecstat.in_comphist[cpi]++;
+
+ /*
+ * returning decompressed packet onto icmp is meaningless.
+ * mark it decrypted to prevent icmp from attaching original packet.
+ */
+ m->m_flags |= M_DECRYPTED;
+
+ m->m_pkthdr.len = off + newlen;
+ ip = mtod(m, struct ip *);
+ {
+ size_t len;
+#ifdef IPLEN_FLIPPED
+ len = ip->ip_len;
+#else
+ len = ntohs(ip->ip_len);
+#endif
+ /*
+ * be careful about underflow. also, do not assign exact value
+ * as ip_len is manipulated differently on *BSDs.
+ */
+ len += m->m_pkthdr.len;
+ len -= olen;
+ if (len & ~0xffff) {
+ /* packet too big after decompress */
+ ipsecstat.in_inval++;
+ goto fail;
+ }
+#ifdef IPLEN_FLIPPED
+ ip->ip_len = len & 0xffff;
+#else
+ ip->ip_len = htons(len & 0xffff);
+#endif
+ ip->ip_p = nxt;
+ }
+
+ if (sav) {
+ key_sa_recordxfer(sav, m);
+ key_freesav(sav);
+ sav = NULL;
+ }
+
+ if (nxt != IPPROTO_DONE)
+ (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
+ else
+ m_freem(m);
+ m = NULL;
+
+ ipsecstat.in_success++;
+ return;
+
+fail:
+ if (sav)
+ key_freesav(sav);
+ if (m)
+ m_freem(m);
+ return;
+}
+#endif /* INET */
+
+#ifdef INET6
+int
+ipcomp6_input(mp, offp, proto)
+ struct mbuf **mp;
+ int *offp, proto;
+{
+ struct mbuf *m, *md;
+ int off;
+ struct ip6_hdr *ip6;
+ struct mbuf *ipcompm;
+ struct ipcomp *ipcomp;
+ struct ipcomp_algorithm *algo;
+ u_int16_t cpi; /* host order */
+ u_int16_t nxt;
+ int error;
+ size_t newlen;
+ struct secasvar *sav = NULL;
+
+ 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++;
+ goto fail;
+ }
+ 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) {
+ sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src,
+ (caddr_t)&ip6->ip6_dst, IPPROTO_IPCOMP, htonl(cpi));
+ if (sav != NULL
+ && (sav->state == SADB_SASTATE_MATURE
+ || sav->state == SADB_SASTATE_DYING)) {
+ cpi = sav->alg_enc; /*XXX*/
+ /* other parameters to look at? */
+ }
+ }
+ if (cpi < IPCOMP_MAX && ipcomp_algorithms[cpi].decompress != NULL)
+ algo = &ipcomp_algorithms[cpi];
+ else
+ algo = NULL;
+ if (!algo) {
+ ipseclog((LOG_WARNING, "IPv6 IPComp input: unknown cpi %u; "
+ "dropping the packet for simplicity\n", cpi));
+ ipsec6stat.in_nosa++;
+ goto fail;
+ }
+
+ newlen = m->m_pkthdr.len - off - sizeof(struct ipcomp);
+ error = (*algo->decompress)(m, md, &newlen);
+ if (error != 0) {
+ if (error == EINVAL)
+ ipsec6stat.in_inval++;
+ else if (error == ENOBUFS)
+ ipsec6stat.in_nomem++;
+ m = NULL;
+ goto fail;
+ }
+ ipsec6stat.in_comphist[cpi]++;
+ m->m_pkthdr.len = off + sizeof(struct ipcomp) + newlen;
+
+ /*
+ * returning decompressed packet onto icmp is meaningless.
+ * mark it decrypted to prevent icmp from attaching original packet.
+ */
+ m->m_flags |= M_DECRYPTED;
+
+ {
+ char *prvnxtp;
+
+ /* chop IPComp header */
+ 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));
+ }
+
+ if (sav) {
+ key_sa_recordxfer(sav, m);
+ key_freesav(sav);
+ sav = NULL;
+ }
+ *offp = off;
+ *mp = m;
+ ipsec6stat.in_success++;
+ return nxt;
+
+fail:
+ if (m)
+ m_freem(m);
+ if (sav)
+ key_freesav(sav);
+ return IPPROTO_DONE;
+}
+#endif /* INET6 */
diff --git a/sys/netinet6/ipcomp_output.c b/sys/netinet6/ipcomp_output.c
new file mode 100644
index 000000000000..265700ee68af
--- /dev/null
+++ b/sys/netinet6/ipcomp_output.c
@@ -0,0 +1,430 @@
+/* $FreeBSD$ */
+/* $KAME: ipcomp_output.c,v 1.15 2000/07/03 13:23:28 itojun Exp $ */
+
+/*
+ * Copyright (C) 1999 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.
+ */
+
+/*
+ * RFC2393 IP payload compression protocol (IPComp).
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#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/syslog.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+#include <net/zlib.h>
+#include <machine/cpu.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_ecn.h>
+
+#ifdef INET6
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#endif
+#include <netinet6/ipcomp.h>
+#ifdef INET6
+#include <netinet6/ipcomp6.h>
+#endif
+
+#include <netinet6/ipsec.h>
+#ifdef INET6
+#include <netinet6/ipsec6.h>
+#endif
+#include <netkey/key.h>
+#include <netkey/keydb.h>
+
+#include <machine/stdarg.h>
+
+#include <net/net_osdep.h>
+
+static int ipcomp_output __P((struct mbuf *, u_char *, struct mbuf *,
+ struct ipsecrequest *, int));
+
+/*
+ * 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 invocation:
+ * m nexthdrp md
+ * v v v
+ * IP ......... payload
+ * during the encryption:
+ * m nexthdrp mprev md
+ * v v v v
+ * IP ............... ipcomp payload
+ * <-----><----->
+ * complen plen
+ * <-> hlen
+ * <-----------------> compoff
+ */
+static int
+ipcomp_output(m, nexthdrp, md, isr, af)
+ struct mbuf *m;
+ u_char *nexthdrp;
+ struct mbuf *md;
+ struct ipsecrequest *isr;
+ int af;
+{
+ struct mbuf *n;
+ struct mbuf *md0;
+ struct mbuf *mprev;
+ struct ipcomp *ipcomp;
+ struct secasvar *sav = isr->sav;
+ 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;
+
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ afnumber = 4;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ afnumber = 6;
+ break;
+#endif
+ default:
+ ipseclog((LOG_ERR, "ipcomp_output: unsupported af %d\n", af));
+ return 0; /* no change at all */
+ }
+
+ /* grab parameters */
+ if ((ntohl(sav->spi) & ~0xffff) != 0 || sav->alg_enc >= IPCOMP_MAX
+ || ipcomp_algorithms[sav->alg_enc].compress == NULL) {
+ ipsecstat.out_inval++;
+ m_freem(m);
+ return EINVAL;
+ }
+ if ((sav->flags & SADB_X_EXT_RAWCPI) == 0)
+ cpi = sav->alg_enc;
+ else
+ cpi = ntohl(sav->spi) & 0xffff;
+ algo = &ipcomp_algorithms[sav->alg_enc]; /*XXX*/
+
+ /* compute original payload length */
+ plen = 0;
+ for (n = md; n; n = n->m_next)
+ plen += n->m_len;
+
+ /* if the payload is short enough, we don't need to compress */
+ if (plen < algo->minplen)
+ return 0;
+
+ /*
+ * keep the original data packet, so that we can backout
+ * our changes when compression is not necessary.
+ */
+ md0 = m_copym(md, 0, M_COPYALL, M_NOWAIT);
+ if (md0 == NULL) {
+ error = ENOBUFS;
+ return 0;
+ }
+ plen0 = plen;
+
+ /* make the packet over-writable */
+ for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
+ ;
+ 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
+ }
+ m_freem(m);
+ m_freem(md0);
+ return EINVAL;
+ }
+ mprev->m_next = NULL;
+ if ((md = ipsec_copypkt(md)) == NULL) {
+ m_freem(m);
+ m_freem(md0);
+ error = ENOBUFS;
+ goto fail;
+ }
+ mprev->m_next = md;
+
+ /* compress data part */
+ if ((*algo->compress)(m, md, &plen) || mprev->m_next == NULL) {
+ 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
+ }
+ 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
+ }
+ md = mprev->m_next;
+
+ /*
+ * if the packet became bigger, meaningless to use IPComp.
+ * we've only wasted our cpu time.
+ */
+ if (plen0 < plen) {
+ m_freem(md);
+ mprev->m_next = md0;
+ return 0;
+ }
+
+ /* no need to backout change beyond here */
+ m_freem(md0);
+ md0 = NULL;
+ m->m_pkthdr.len -= plen0;
+ m->m_pkthdr.len += plen;
+
+ {
+ /*
+ * insert IPComp header.
+ */
+#ifdef INET
+ struct ip *ip = NULL;
+#endif
+#ifdef INET6
+ struct ip6_hdr *ip6 = NULL;
+#endif
+ size_t hlen = 0; /*ip header len*/
+ size_t complen = sizeof(struct ipcomp);
+
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ ip = mtod(m, struct ip *);
+#ifdef _IP_VHL
+ hlen = IP_VHL_HL(ip->ip_vhl) << 2;
+#else
+ hlen = ip->ip_hl << 2;
+#endif
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ ip6 = mtod(m, struct ip6_hdr *);
+ hlen = sizeof(*ip6);
+ break;
+#endif
+ }
+
+ compoff = m->m_pkthdr.len - plen;
+
+ /*
+ * grow the mbuf to accomodate ipcomp header.
+ * before: IP ... payload
+ * after: IP ... ipcomp payload
+ */
+ if (M_LEADINGSPACE(md) < complen) {
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (!n) {
+ m_freem(m);
+ error = ENOBUFS;
+ goto fail;
+ }
+ n->m_len = complen;
+ mprev->m_next = n;
+ n->m_next = md;
+ m->m_pkthdr.len += complen;
+ ipcomp = mtod(n, struct ipcomp *);
+ } else {
+ md->m_len += complen;
+ md->m_data -= complen;
+ m->m_pkthdr.len += complen;
+ ipcomp = mtod(md, struct ipcomp *);
+ }
+
+ bzero(ipcomp, sizeof(*ipcomp));
+ ipcomp->comp_nxt = *nexthdrp;
+ *nexthdrp = IPPROTO_IPCOMP;
+ ipcomp->comp_cpi = htons(cpi);
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ if (compoff + complen + plen < IP_MAXPACKET)
+ ip->ip_len = htons(compoff + complen + plen);
+ else {
+ ipseclog((LOG_ERR,
+ "IPv4 ESP output: size exceeds limit\n"));
+ ipsecstat.out_inval++;
+ m_freem(m);
+ error = EMSGSIZE;
+ goto fail;
+ }
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ /* total packet length will be computed in ip6_output() */
+ break;
+#endif
+ }
+ }
+
+ if (!m) {
+ 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
+ }
+ }
+#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);
+ return 0;
+
+fail:
+#if 1
+ return error;
+#else
+ panic("something bad in ipcomp_output");
+#endif
+}
+
+#ifdef INET
+int
+ipcomp4_output(m, isr)
+ struct mbuf *m;
+ struct ipsecrequest *isr;
+{
+ struct ip *ip;
+ if (m->m_len < sizeof(struct ip)) {
+ ipseclog((LOG_DEBUG, "ipcomp4_output: first mbuf too short\n"));
+ ipsecstat.out_inval++;
+ m_freem(m);
+ return 0;
+ }
+ ip = mtod(m, struct ip *);
+ /* XXX assumes that m->m_next points to payload */
+ return ipcomp_output(m, &ip->ip_p, m->m_next, isr, AF_INET);
+}
+#endif /*INET*/
+
+#ifdef INET6
+int
+ipcomp6_output(m, nexthdrp, md, isr)
+ struct mbuf *m;
+ u_char *nexthdrp;
+ struct mbuf *md;
+ struct ipsecrequest *isr;
+{
+ if (m->m_len < sizeof(struct ip6_hdr)) {
+ ipseclog((LOG_DEBUG, "ipcomp6_output: first mbuf too short\n"));
+ ipsec6stat.out_inval++;
+ m_freem(m);
+ return 0;
+ }
+ return ipcomp_output(m, nexthdrp, md, isr, AF_INET6);
+}
+#endif /*INET6*/
diff --git a/sys/netinet6/ipsec.c b/sys/netinet6/ipsec.c
index a72fb6a96cdf..2e8a67ee5f65 100644
--- a/sys/netinet6/ipsec.c
+++ b/sys/netinet6/ipsec.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ipsec.c,v 1.66 2000/06/15 04:08:54 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -58,7 +59,6 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
-#include <netinet/in_pcb.h>
#include <netinet/ip_var.h>
#include <netinet/in_var.h>
#include <netinet/udp.h>
@@ -69,16 +69,20 @@
#endif
#ifdef INET6
-#include <netinet6/ip6.h>
-#include <netinet6/in6_pcb.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
-#endif /*INET6*/
+#endif
+#include <netinet/in_pcb.h>
+#ifdef INET6
+#include <netinet/icmp6.h>
+#endif
#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
#ifdef IPSEC_ESP
@@ -87,9 +91,11 @@
#include <netinet6/esp6.h>
#endif
#endif
-
+#include <netinet6/ipcomp.h>
+#ifdef INET6
+#include <netinet6/ipcomp6.h>
+#endif
#include <netkey/key.h>
-#include <netkey/key_var.h>
#include <netkey/keydb.h>
#ifdef IPSEC_DEBUG
#include <netkey/key_debug.h>
@@ -99,8 +105,24 @@
#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
+int ipsec_debug = 0;
+#endif
+
struct ipsecstat ipsecstat;
-int ip4_inbound_call_ike = 0;
int ip4_ah_cleartos = 1;
int ip4_ah_offsetmask = 0; /* maybe IP_DF? */
int ip4_ipsec_dfbit = 0; /* DF bit on encap. 0: clear 1: set 2: copy */
@@ -111,6 +133,11 @@ 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) */
+SYSCTL_DECL(_net_inet_ipsec);
+#ifdef INET6
+SYSCTL_DECL(_net_inet6_ipsec6);
+#endif
+
/* net.inet.ipsec */
SYSCTL_STRUCT(_net_inet_ipsec, IPSECCTL_STATS,
stats, CTLFLAG_RD, &ipsecstat, ipsecstat, "");
@@ -124,8 +151,6 @@ SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev,
CTLFLAG_RW, &ip4_ah_trans_deflev, 0, "");
SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev,
CTLFLAG_RW, &ip4_ah_net_deflev, 0, "");
-SYSCTL_INT(_net_inet_ipsec, IPSECCTL_INBOUND_CALL_IKE,
- inbound_call_ike, CTLFLAG_RW, &ip4_inbound_call_ike, 0, "");
SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS,
ah_cleartos, CTLFLAG_RW, &ip4_ah_cleartos, 0, "");
SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK,
@@ -134,10 +159,11 @@ SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DFBIT,
dfbit, CTLFLAG_RW, &ip4_ipsec_dfbit, 0, "");
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, "");
#ifdef INET6
struct ipsecstat ipsec6stat;
-int ip6_inbound_call_ike = 0;
int ip6_esp_trans_deflev = IPSEC_LEVEL_USE;
int ip6_esp_net_deflev = IPSEC_LEVEL_USE;
int ip6_ah_trans_deflev = IPSEC_LEVEL_USE;
@@ -158,10 +184,10 @@ SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev,
CTLFLAG_RW, &ip6_ah_trans_deflev, 0, "");
SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev,
CTLFLAG_RW, &ip6_ah_net_deflev, 0, "");
-SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_INBOUND_CALL_IKE,
- inbound_call_ike, CTLFLAG_RW, &ip6_inbound_call_ike, 0, "");
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, "");
#endif /* INET6 */
static int ipsec_setspidx_mbuf
@@ -169,13 +195,15 @@ static int ipsec_setspidx_mbuf
static void ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb));
static void ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *));
#ifdef INET6
-static u_int16_t ipsec6_get_ulp __P((struct mbuf *m));
+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 *));
#endif
+static struct inpcbpolicy *ipsec_newpcbpolicy __P((void));
+static void ipsec_delpcbpolicy __P((struct inpcbpolicy *));
static struct secpolicy *ipsec_deepcopy_policy __P((struct secpolicy *src));
static int ipsec_set_policy __P((struct secpolicy **pcb_sp,
- int optname, caddr_t request, int priv));
+ int optname, caddr_t request, size_t len, int priv));
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 *));
@@ -189,11 +217,6 @@ static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *));
static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *));
#endif
-#define KMALLOC(p, t, n) \
- ((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT))
-#define KFREE(p) \
- free((caddr_t)(p), M_SECA);
-
/*
* For OUTBOUND packet having a socket. Searching SPD for packet,
* and return a pointer to SP.
@@ -221,30 +244,27 @@ ipsec4_getpolicybysock(m, dir, so, error)
if (m == NULL || so == NULL || error == NULL)
panic("ipsec4_getpolicybysock: NULL pointer was passed.\n");
- if ((sotoinpcb(so)->inp_vflag & INP_IPV4) != 0) {
+ 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;
- }
+ break;
#ifdef INET6
- else if ((sotoinpcb(so)->inp_vflag & INP_IPV6) != 0) {
+ case AF_INET6:
/* set spidx in pcb */
ipsec6_setspidx_in6pcb(m, sotoin6pcb(so));
pcbsp = sotoin6pcb(so)->in6p_sp;
- }
+ break;
#endif
- else
+ default:
panic("ipsec4_getpolicybysock: unsupported address family\n");
+ }
/* sanity check */
if (pcbsp == NULL)
panic("ipsec4_getpolicybysock: pcbsp is NULL.\n");
- KEYDEBUG(KEYDEBUG_IPSEC_DATA,
- printf("send: priv=%d ", pcbsp->priv);
- if (so->so_cred)
- printf("cr_uid=%d\n", so->so_cred->cr_uid);
- );
switch (dir) {
case IPSEC_DIR_INBOUND:
currsp = pcbsp->sp_in;
@@ -284,24 +304,23 @@ ipsec4_getpolicybysock(m, dir, so, error)
/* no SP found */
if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD
&& ip4_def_policy.policy != IPSEC_POLICY_NONE) {
- printf("fixed system default policy:%d->%d\n",
- ip4_def_policy.policy,
- IPSEC_POLICY_NONE);
+ ipseclog((LOG_INFO,
+ "fixed system default policy: %d->%d\n",
+ ip4_def_policy.policy, IPSEC_POLICY_NONE));
ip4_def_policy.policy = IPSEC_POLICY_NONE;
}
ip4_def_policy.refcnt++;
*error = 0;
return &ip4_def_policy;
-
+
case IPSEC_POLICY_IPSEC:
currsp->refcnt++;
*error = 0;
return currsp;
default:
- printf("ipsec4_getpolicybysock: "
- "Invalid policy for PCB %d\n",
- currsp->policy);
+ ipseclog((LOG_ERR, "ipsec4_getpolicybysock: "
+ "Invalid policy for PCB %d\n", currsp->policy));
*error = EINVAL;
return NULL;
}
@@ -324,18 +343,18 @@ ipsec4_getpolicybysock(m, dir, so, error)
/* no SP found */
switch (currsp->policy) {
case IPSEC_POLICY_BYPASS:
- printf("ipsec4_getpolicybysock: "
+ ipseclog((LOG_ERR, "ipsec4_getpolicybysock: "
"Illegal policy for non-priviliged defined %d\n",
- currsp->policy);
+ currsp->policy));
*error = EINVAL;
return NULL;
case IPSEC_POLICY_ENTRUST:
if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD
&& ip4_def_policy.policy != IPSEC_POLICY_NONE) {
- printf("fixed system default policy:%d->%d\n",
- ip4_def_policy.policy,
- IPSEC_POLICY_NONE);
+ ipseclog((LOG_INFO,
+ "fixed system default policy: %d->%d\n",
+ ip4_def_policy.policy, IPSEC_POLICY_NONE));
ip4_def_policy.policy = IPSEC_POLICY_NONE;
}
ip4_def_policy.refcnt++;
@@ -348,9 +367,8 @@ ipsec4_getpolicybysock(m, dir, so, error)
return currsp;
default:
- printf("ipsec4_getpolicybysock: "
- "Invalid policy for PCB %d\n",
- currsp->policy);
+ ipseclog((LOG_ERR, "ipsec4_getpolicybysock: "
+ "Invalid policy for PCB %d\n", currsp->policy));
*error = EINVAL;
return NULL;
}
@@ -386,13 +404,7 @@ ipsec4_getpolicybyaddr(m, dir, flag, error)
bzero(&spidx, sizeof(spidx));
/* make a index to look for a policy */
- if ((flag & IP_FORWARDING) == IP_FORWARDING) {
- /* Case: IP forwarding */
- *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m);
- } else {
- /* Case: ICMP echo reply */
- *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m);
- }
+ *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m);
if (*error != 0)
return NULL;
@@ -412,9 +424,9 @@ ipsec4_getpolicybyaddr(m, dir, flag, error)
/* no SP found */
if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD
&& ip4_def_policy.policy != IPSEC_POLICY_NONE) {
- printf("fixed system default policy:%d->%d\n",
+ ipseclog((LOG_INFO, "fixed system default policy:%d->%d\n",
ip4_def_policy.policy,
- IPSEC_POLICY_NONE);
+ IPSEC_POLICY_NONE));
ip4_def_policy.policy = IPSEC_POLICY_NONE;
}
ip4_def_policy.refcnt++;
@@ -496,24 +508,23 @@ ipsec6_getpolicybysock(m, dir, so, error)
/* no SP found */
if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD
&& ip6_def_policy.policy != IPSEC_POLICY_NONE) {
- printf("fixed system default policy:%d->%d\n",
- ip6_def_policy.policy,
- IPSEC_POLICY_NONE);
+ ipseclog((LOG_INFO,
+ "fixed system default policy: %d->%d\n",
+ ip6_def_policy.policy, IPSEC_POLICY_NONE));
ip6_def_policy.policy = IPSEC_POLICY_NONE;
}
ip6_def_policy.refcnt++;
*error = 0;
return &ip6_def_policy;
-
+
case IPSEC_POLICY_IPSEC:
currsp->refcnt++;
*error = 0;
return currsp;
default:
- printf("ipsec6_getpolicybysock: "
- "Invalid policy for PCB %d\n",
- currsp->policy);
+ ipseclog((LOG_ERR, "ipsec6_getpolicybysock: "
+ "Invalid policy for PCB %d\n", currsp->policy));
*error = EINVAL;
return NULL;
}
@@ -536,18 +547,18 @@ ipsec6_getpolicybysock(m, dir, so, error)
/* no SP found */
switch (currsp->policy) {
case IPSEC_POLICY_BYPASS:
- printf("ipsec6_getpolicybysock: "
- "Illegal policy for non-priviliged defined %d\n",
- currsp->policy);
+ ipseclog((LOG_ERR, "ipsec6_getpolicybysock: "
+ "Illegal policy for non-priviliged defined %d\n",
+ currsp->policy));
*error = EINVAL;
return NULL;
case IPSEC_POLICY_ENTRUST:
if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD
&& ip6_def_policy.policy != IPSEC_POLICY_NONE) {
- printf("fixed system default policy:%d->%d\n",
- ip6_def_policy.policy,
- IPSEC_POLICY_NONE);
+ ipseclog((LOG_INFO,
+ "fixed system default policy: %d->%d\n",
+ ip6_def_policy.policy, IPSEC_POLICY_NONE));
ip6_def_policy.policy = IPSEC_POLICY_NONE;
}
ip6_def_policy.refcnt++;
@@ -560,9 +571,9 @@ ipsec6_getpolicybysock(m, dir, so, error)
return currsp;
default:
- printf("ipsec6_policybysock: "
- "Invalid policy for PCB %d\n",
- currsp->policy);
+ ipseclog((LOG_ERR,
+ "ipsec6_policybysock: Invalid policy for PCB %d\n",
+ currsp->policy));
*error = EINVAL;
return NULL;
}
@@ -582,7 +593,7 @@ ipsec6_getpolicybysock(m, dir, so, error)
* others : error occured.
*/
#ifndef IP_FORWARDING
-#define IP_FORWARDING 1
+#define IP_FORWARDING 1
#endif
struct secpolicy *
@@ -604,13 +615,7 @@ ipsec6_getpolicybyaddr(m, dir, flag, error)
bzero(&spidx, sizeof(spidx));
/* make a index to look for a policy */
- if ((flag & IP_FORWARDING) == IP_FORWARDING) {
- /* Case: IP forwarding */
- *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m);
- } else {
- /* Case: ICMP echo reply */
- *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m);
- }
+ *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m);
if (*error != 0)
return NULL;
@@ -630,9 +635,8 @@ ipsec6_getpolicybyaddr(m, dir, flag, error)
/* no SP found */
if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD
&& ip6_def_policy.policy != IPSEC_POLICY_NONE) {
- printf("fixed system default policy:%d->%d\n",
- ip6_def_policy.policy,
- IPSEC_POLICY_NONE);
+ ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n",
+ ip6_def_policy.policy, IPSEC_POLICY_NONE));
ip6_def_policy.policy = IPSEC_POLICY_NONE;
}
ip6_def_policy.refcnt++;
@@ -657,6 +661,7 @@ ipsec_setspidx_mbuf(spidx, dir, family, m)
u_int dir, family;
struct mbuf *m;
{
+
/* sanity check */
if (spidx == NULL || m == NULL)
panic("ipsec_setspidx_mbuf: NULL pointer was passed.\n");
@@ -668,9 +673,6 @@ ipsec_setspidx_mbuf(spidx, dir, family, m)
bzero(spidx, sizeof(*spidx));
spidx->dir = dir;
- spidx->src.ss_len = spidx->dst.ss_len = _SALENBYAF(family);
- spidx->src.ss_family = spidx->dst.ss_family = family;
- spidx->prefs = spidx->prefd = _INALENBYAF(family) << 3;
{
/* sanity check for packet length. */
@@ -695,6 +697,7 @@ ipsec_setspidx_mbuf(spidx, dir, family, m)
{
struct ip *ip;
struct ip ipbuf;
+ struct sockaddr_in *sin;
/* sanity check 1 for minimum ip header length */
if (m->m_pkthdr.len < sizeof(struct ip)) {
@@ -717,23 +720,32 @@ ipsec_setspidx_mbuf(spidx, dir, family, m)
ip = &ipbuf;
}
- /* some more checks on IPv4 header. */
- bcopy(&ip->ip_src, _INADDRBYSA(&spidx->src),
- sizeof(ip->ip_src));
- bcopy(&ip->ip_dst, _INADDRBYSA(&spidx->dst),
- sizeof(ip->ip_dst));
+ /* XXX some more checks on IPv4 header. */
+
+ 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;
+
+ 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->prefs = spidx->prefd = sizeof(struct in_addr) << 3;
spidx->ul_proto = ip->ip_p;
- _INPORTBYSA(&spidx->src) = IPSEC_PORT_ANY;
- _INPORTBYSA(&spidx->dst) = IPSEC_PORT_ANY;
break;
}
#ifdef INET6
case AF_INET6:
{
- struct ip6_hdr *ip6_hdr;
+ struct ip6_hdr *ip6;
struct ip6_hdr ip6buf;
+ struct sockaddr_in6 *sin6;
/* sanity check 1 for minimum ip header length */
if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) {
@@ -749,15 +761,15 @@ ipsec_setspidx_mbuf(spidx, dir, family, m)
* get IPv6 header packet. usually the mbuf is contiguous
* and we need no copies.
*/
- if (m->m_len >= sizeof(*ip6_hdr))
- ip6_hdr = mtod(m, struct ip6_hdr *);
+ if (m->m_len >= sizeof(*ip6))
+ ip6 = mtod(m, struct ip6_hdr *);
else {
m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf);
- ip6_hdr = &ip6buf;
+ ip6 = &ip6buf;
}
/* some more checks on IPv4 header. */
- if ((ip6_hdr->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
+ if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
printf("ipsec_setspidx_mbuf: "
"wrong ip version on packet "
@@ -765,14 +777,31 @@ ipsec_setspidx_mbuf(spidx, dir, family, m)
goto bad;
}
- bcopy(&ip6_hdr->ip6_src, _INADDRBYSA(&spidx->src),
- sizeof(ip6_hdr->ip6_src));
- bcopy(&ip6_hdr->ip6_dst, _INADDRBYSA(&spidx->dst),
- sizeof(ip6_hdr->ip6_dst));
+ 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]);
+ }
+
+ 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]);
+ }
+
+ spidx->prefs = spidx->prefd = sizeof(struct in6_addr) << 3;
- spidx->ul_proto = ipsec6_get_ulp(m);
- _INPORTBYSA(&spidx->src) = IPSEC_PORT_ANY;
- _INPORTBYSA(&spidx->dst) = IPSEC_PORT_ANY;
+ ipsec6_get_ulp(m, spidx);
break;
}
#endif /* INET6 */
@@ -794,17 +823,17 @@ ipsec_setspidx_mbuf(spidx, dir, family, m)
#ifdef INET6
/*
- * Get the number of upper layer protocol.
+ * Get upper layer protocol number and port number if there.
* Assumed all extension headers are in single mbuf.
*/
-static u_int16_t
-ipsec6_get_ulp(m)
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+static void
+ipsec6_get_ulp(m, spidx)
struct mbuf *m;
+ struct secpolicyindex *spidx;
{
- struct ip6_hdr *ip6;
- struct ip6_ext *ip6e;
int off, nxt;
- int len;
/* sanity check */
if (m == NULL)
@@ -813,48 +842,45 @@ ipsec6_get_ulp(m)
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m));
- ip6 = mtod(m, struct ip6_hdr *);
- nxt = ip6->ip6_nxt;
- off = sizeof(struct ip6_hdr);
- len = m->m_len;
-
- while (off < len) {
- ip6e = (struct ip6_ext *)((caddr_t) ip6 + off);
- if (m->m_len < off + sizeof(*ip6e)) {
- printf("ipsec6_get_ulp: all exthdr are not "
- "in single mbuf.\n");
- return IPSEC_PORT_ANY;
- }
+ /* 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;
- switch(nxt) {
- case IPPROTO_TCP:
- case IPPROTO_UDP:
- case IPPROTO_ICMPV6:
- return nxt;
- case IPPROTO_FRAGMENT:
- off += sizeof(struct ip6_frag);
- break;
- case IPPROTO_AH:
- off += (ip6e->ip6e_len + 2) << 2;
- break;
- default:
- switch (nxt) {
- case IPPROTO_HOPOPTS:
- case IPPROTO_ROUTING:
- case IPPROTO_ESP:
- case IPPROTO_NONE:
- case IPPROTO_DSTOPTS:
- break;
- default:
- return nxt; /* XXX */
- }
- off += (ip6e->ip6e_len + 1) << 3;
- break;
+ nxt = -1;
+ off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
+ if (off < 0 || m->m_pkthdr.len < off)
+ return;
+
+ switch (nxt) {
+ case IPPROTO_TCP:
+ spidx->ul_proto = nxt;
+ if (off + sizeof(struct tcphdr) <= m->m_pkthdr.len) {
+ struct tcphdr th;
+ 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 (off + sizeof(struct udphdr) <= m->m_pkthdr.len) {
+ struct udphdr uh;
+ 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;
}
- nxt = ip6e->ip6e_nxt;
+ break;
+ case IPPROTO_ICMPV6:
+ spidx->ul_proto = nxt;
+ break;
+ default:
+ break;
}
-
- return IPSEC_PORT_ANY;
}
#endif
@@ -864,6 +890,7 @@ ipsec4_setspidx_inpcb(m, pcb)
struct inpcb *pcb;
{
struct secpolicyindex *spidx;
+ struct sockaddr_in *sin1, *sin2;
/* sanity check */
if (pcb == NULL)
@@ -878,24 +905,28 @@ ipsec4_setspidx_inpcb(m, pcb)
spidx = &pcb->inp_sp->sp_in->spidx;
spidx->dir = IPSEC_DIR_INBOUND;
- spidx->src.ss_len = spidx->dst.ss_len = _SALENBYAF(AF_INET);
- spidx->src.ss_family = spidx->dst.ss_family = AF_INET;
- spidx->prefs = _INALENBYAF(AF_INET) << 3;
- spidx->prefd = _INALENBYAF(AF_INET) << 3;
+ 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;
- _INPORTBYSA(&spidx->src) = pcb->inp_fport;
- _INPORTBYSA(&spidx->dst) = pcb->inp_lport;
+ 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;
- spidx->src.ss_len = spidx->dst.ss_len = _SALENBYAF(AF_INET);
- spidx->src.ss_family = spidx->dst.ss_family = AF_INET;
- spidx->prefs = _INALENBYAF(AF_INET) << 3;
- spidx->prefd = _INALENBYAF(AF_INET) << 3;
+ 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;
- _INPORTBYSA(&spidx->src) = pcb->inp_lport;
- _INPORTBYSA(&spidx->dst) = pcb->inp_fport;
+ sin1->sin_port = pcb->inp_lport;
+ sin2->sin_port = pcb->inp_fport;
ipsec4_setspidx_ipaddr(m, spidx);
return;
@@ -907,10 +938,11 @@ ipsec4_setspidx_ipaddr(m, spidx)
struct secpolicyindex *spidx;
{
struct ip *ip = NULL;
+ struct ip ipbuf;
/* sanity check 1 for minimum ip header length */
if (m == NULL)
- panic("ipsec4_setspidx_in6pcb: m == 0 passed.\n");
+ panic("ipsec4_setspidx_ipaddr: m == 0 passed.\n");
if (m->m_pkthdr.len < sizeof(struct ip)) {
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
@@ -924,14 +956,14 @@ ipsec4_setspidx_ipaddr(m, spidx)
if (m->m_len >= sizeof(*ip))
ip = mtod(m, struct ip *);
else {
- struct ip ipbuf;
-
m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf);
ip = &ipbuf;
}
- bcopy(&ip->ip_src, _INADDRBYSA(&spidx->src), sizeof(ip->ip_src));
- bcopy(&ip->ip_dst, _INADDRBYSA(&spidx->dst), sizeof(ip->ip_dst));
+ 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));
return;
}
@@ -943,6 +975,7 @@ ipsec6_setspidx_in6pcb(m, pcb)
struct in6pcb *pcb;
{
struct secpolicyindex *spidx;
+ struct sockaddr_in6 *sin1, *sin2;
/* sanity check */
if (pcb == NULL)
@@ -957,24 +990,28 @@ ipsec6_setspidx_in6pcb(m, pcb)
spidx = &pcb->in6p_sp->sp_in->spidx;
spidx->dir = IPSEC_DIR_INBOUND;
- spidx->src.ss_len = spidx->dst.ss_len = _SALENBYAF(AF_INET6);
- spidx->src.ss_family = spidx->dst.ss_family = AF_INET6;
- spidx->prefs = _INALENBYAF(AF_INET6) << 3;
- spidx->prefd = _INALENBYAF(AF_INET6) << 3;
+ 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;
- _INPORTBYSA(&spidx->src) = pcb->in6p_fport;
- _INPORTBYSA(&spidx->dst) = pcb->in6p_lport;
+ sin1->sin6_port = pcb->in6p_fport;
+ sin2->sin6_port = pcb->in6p_lport;
ipsec6_setspidx_ipaddr(m, spidx);
spidx = &pcb->in6p_sp->sp_out->spidx;
spidx->dir = IPSEC_DIR_OUTBOUND;
- spidx->src.ss_len = spidx->dst.ss_len = _SALENBYAF(AF_INET6);
- spidx->src.ss_family = spidx->dst.ss_family = AF_INET6;
- spidx->prefs = _INALENBYAF(AF_INET6) << 3;
- spidx->prefd = _INALENBYAF(AF_INET6) << 3;
+ 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;
- _INPORTBYSA(&spidx->src) = pcb->in6p_lport;
- _INPORTBYSA(&spidx->dst) = pcb->in6p_fport;
+ sin1->sin6_port = pcb->in6p_lport;
+ sin2->sin6_port = pcb->in6p_fport;
ipsec6_setspidx_ipaddr(m, spidx);
return;
@@ -985,7 +1022,9 @@ ipsec6_setspidx_ipaddr(m, spidx)
struct mbuf *m;
struct secpolicyindex *spidx;
{
- struct ip6_hdr *ip6_hdr = NULL;
+ struct ip6_hdr *ip6 = NULL;
+ struct ip6_hdr ip6buf;
+ struct sockaddr_in6 *sin6;
/* sanity check 1 for minimum ip header length */
if (m == NULL)
@@ -1000,16 +1039,14 @@ ipsec6_setspidx_ipaddr(m, spidx)
return;
}
- if (m->m_len >= sizeof(*ip6_hdr))
- ip6_hdr = mtod(m, struct ip6_hdr *);
+ if (m->m_len >= sizeof(*ip6))
+ ip6 = mtod(m, struct ip6_hdr *);
else {
- struct ip6_hdr ip6buf;
-
m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf);
- ip6_hdr = &ip6buf;
+ ip6 = &ip6buf;
}
- if ((ip6_hdr->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
+ if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
printf("ipsec_setspidx_mbuf: "
"wrong ip version on packet "
@@ -1017,15 +1054,40 @@ ipsec6_setspidx_ipaddr(m, spidx)
return;
}
- bcopy(&ip6_hdr->ip6_src, _INADDRBYSA(&spidx->src),
- sizeof(ip6_hdr->ip6_src));
- bcopy(&ip6_hdr->ip6_dst, _INADDRBYSA(&spidx->dst),
- sizeof(ip6_hdr->ip6_dst));
+ sin6 = (struct sockaddr_in6 *)&spidx->src;
+ 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]);
+ }
+
+ sin6 = (struct sockaddr_in6 *)&spidx->dst;
+ 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]);
+ }
return;
}
#endif
+static struct inpcbpolicy *
+ipsec_newpcbpolicy()
+{
+ struct inpcbpolicy *p;
+
+ p = (struct inpcbpolicy *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
+ return p;
+}
+
+static void
+ipsec_delpcbpolicy(p)
+ struct inpcbpolicy *p;
+{
+ free(p, M_SECA);
+}
+
/* initialize policy in PCB */
int
ipsec_init_policy(so, pcb_sp)
@@ -1038,9 +1100,9 @@ ipsec_init_policy(so, pcb_sp)
if (so == NULL || pcb_sp == NULL)
panic("ipsec_init_policy: NULL pointer was passed.\n");
- KMALLOC(new, struct inpcbpolicy *, sizeof(*new));
+ new = ipsec_newpcbpolicy();
if (new == NULL) {
- printf("ipsec_init_policy: No more memory.\n");
+ ipseclog((LOG_DEBUG, "ipsec_init_policy: No more memory.\n"));
return ENOBUFS;
}
bzero(new, sizeof(*new));
@@ -1050,16 +1112,8 @@ ipsec_init_policy(so, pcb_sp)
else
new->priv = 0;
- KEYDEBUG(KEYDEBUG_IPSEC_DATA,
- printf("init: priv=%d ", new->priv);
- if (so->so_cred)
- printf("cr_uid=%d\n", so->so_cred->cr_uid);
- else
- printf("so_cred is NULL\n");
- );
-
if ((new->sp_in = key_newsp()) == NULL) {
- KFREE(new);
+ ipsec_delpcbpolicy(new);
return ENOBUFS;
}
new->sp_in->state = IPSEC_SPSTATE_ALIVE;
@@ -1067,7 +1121,7 @@ ipsec_init_policy(so, pcb_sp)
if ((new->sp_out = key_newsp()) == NULL) {
key_freesp(new->sp_in);
- KFREE(new);
+ ipsec_delpcbpolicy(new);
return ENOBUFS;
}
new->sp_out->state = IPSEC_SPSTATE_ALIVE;
@@ -1125,7 +1179,8 @@ ipsec_deepcopy_policy(src)
*/
q = &newchain;
for (p = src->req; p; p = p->next) {
- KMALLOC(*q, struct ipsecrequest *, sizeof(struct ipsecrequest));
+ *q = (struct ipsecrequest *)malloc(sizeof(struct ipsecrequest),
+ M_SECA, M_NOWAIT);
if (*q == NULL)
goto fail;
bzero(*q, sizeof(**q));
@@ -1134,6 +1189,7 @@ ipsec_deepcopy_policy(src)
(*q)->saidx.proto = p->saidx.proto;
(*q)->saidx.mode = p->saidx.mode;
(*q)->level = p->level;
+ (*q)->saidx.reqid = p->saidx.reqid;
bcopy(&p->saidx.src, &(*q)->saidx.src, sizeof((*q)->saidx.src));
bcopy(&p->saidx.dst, &(*q)->saidx.dst, sizeof((*q)->saidx.dst));
@@ -1154,7 +1210,7 @@ ipsec_deepcopy_policy(src)
fail:
for (p = newchain; p; p = r) {
r = p->next;
- KFREE(p);
+ free(p, M_SECA);
p = NULL;
}
return NULL;
@@ -1162,18 +1218,23 @@ fail:
/* set policy and ipsec request if present. */
static int
-ipsec_set_policy(pcb_sp, optname, request, priv)
+ipsec_set_policy(pcb_sp, optname, request, len, priv)
struct secpolicy **pcb_sp;
int optname;
caddr_t request;
+ size_t len;
int priv;
{
- struct sadb_x_policy *xpl = (struct sadb_x_policy *)request;
+ struct sadb_x_policy *xpl;
struct secpolicy *newsp = NULL;
+ int error;
/* sanity check. */
- if (pcb_sp == NULL || *pcb_sp == NULL || xpl == NULL)
+ if (pcb_sp == NULL || *pcb_sp == NULL || request == NULL)
return EINVAL;
+ if (len < sizeof(*xpl))
+ return EINVAL;
+ xpl = (struct sadb_x_policy *)request;
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
printf("ipsec_set_policy: passed policy\n");
@@ -1190,8 +1251,8 @@ ipsec_set_policy(pcb_sp, optname, request, priv)
return EACCES;
/* allocation new SP entry */
- if ((newsp = key_msg2sp(xpl)) == NULL)
- return EINVAL; /* maybe ENOBUFS */
+ if ((newsp = key_msg2sp(xpl, len, &error)) == NULL)
+ return error;
newsp->state = IPSEC_SPSTATE_ALIVE;
@@ -1210,42 +1271,42 @@ ipsec_get_policy(pcb_sp, mp)
struct secpolicy *pcb_sp;
struct mbuf **mp;
{
- struct sadb_x_policy *xpl;
/* sanity check. */
if (pcb_sp == NULL || mp == NULL)
return EINVAL;
- if ((xpl = key_sp2msg(pcb_sp)) == NULL) {
- printf("ipsec_get_policy: No more memory.\n");
+ *mp = key_sp2msg(pcb_sp);
+ if (!*mp) {
+ ipseclog((LOG_DEBUG, "ipsec_get_policy: No more memory.\n"));
return ENOBUFS;
}
- *mp = m_get(M_WAIT, MT_DATA);
- (*mp)->m_len = PFKEY_EXTLEN(xpl);
- m_copyback((*mp), 0, PFKEY_EXTLEN(xpl), (caddr_t)xpl);
+ (*mp)->m_type = MT_DATA;
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
printf("ipsec_get_policy:\n");
kdebug_mbuf(*mp));
- KFREE(xpl);
-
return 0;
}
int
-ipsec4_set_policy(inp, optname, request, priv)
+ipsec4_set_policy(inp, optname, request, len, priv)
struct inpcb *inp;
int optname;
caddr_t request;
+ size_t len;
int priv;
{
- struct sadb_x_policy *xpl = (struct sadb_x_policy *)request;
+ struct sadb_x_policy *xpl;
struct secpolicy **pcb_sp;
/* sanity check. */
if (inp == NULL || request == NULL)
return EINVAL;
+ if (len < sizeof(*xpl))
+ return EINVAL;
+ xpl = (struct sadb_x_policy *)request;
/* select direction */
switch (xpl->sadb_x_policy_dir) {
@@ -1256,26 +1317,32 @@ ipsec4_set_policy(inp, optname, request, priv)
pcb_sp = &inp->inp_sp->sp_out;
break;
default:
- printf("ipsec4_set_policy: invalid direction=%u\n",
- xpl->sadb_x_policy_dir);
+ ipseclog((LOG_ERR, "ipsec4_set_policy: invalid direction=%u\n",
+ xpl->sadb_x_policy_dir));
return EINVAL;
}
- return ipsec_set_policy(pcb_sp, optname, request, priv);
+ return ipsec_set_policy(pcb_sp, optname, request, len, priv);
}
int
-ipsec4_get_policy(inp, request, mp)
+ipsec4_get_policy(inp, request, len, mp)
struct inpcb *inp;
caddr_t request;
+ size_t len;
struct mbuf **mp;
{
- struct sadb_x_policy *xpl = (struct sadb_x_policy *)request;
+ struct sadb_x_policy *xpl;
struct secpolicy *pcb_sp;
/* sanity check. */
if (inp == NULL || request == NULL || mp == NULL)
return EINVAL;
+ if (inp->inp_sp == NULL)
+ panic("policy in PCB is NULL\n");
+ if (len < sizeof(*xpl))
+ return EINVAL;
+ xpl = (struct sadb_x_policy *)request;
/* select direction */
switch (xpl->sadb_x_policy_dir) {
@@ -1286,8 +1353,8 @@ ipsec4_get_policy(inp, request, mp)
pcb_sp = inp->inp_sp->sp_out;
break;
default:
- printf("ipsec6_set_policy: invalid direction=%u\n",
- xpl->sadb_x_policy_dir);
+ ipseclog((LOG_ERR, "ipsec4_set_policy: invalid direction=%u\n",
+ xpl->sadb_x_policy_dir));
return EINVAL;
}
@@ -1303,6 +1370,9 @@ ipsec4_delete_pcbpolicy(inp)
if (inp == NULL)
panic("ipsec4_delete_pcbpolicy: NULL pointer was passed.\n");
+ if (inp->inp_sp == NULL)
+ return 0;
+
if (inp->inp_sp->sp_in != NULL) {
key_freesp(inp->inp_sp->sp_in);
inp->inp_sp->sp_in = NULL;
@@ -1313,7 +1383,7 @@ ipsec4_delete_pcbpolicy(inp)
inp->inp_sp->sp_out = NULL;
}
- KFREE(inp->inp_sp);
+ ipsec_delpcbpolicy(inp->inp_sp);
inp->inp_sp = NULL;
return 0;
@@ -1321,18 +1391,22 @@ ipsec4_delete_pcbpolicy(inp)
#ifdef INET6
int
-ipsec6_set_policy(in6p, optname, request, priv)
+ipsec6_set_policy(in6p, optname, request, len, priv)
struct in6pcb *in6p;
int optname;
caddr_t request;
+ size_t len;
int priv;
{
- struct sadb_x_policy *xpl = (struct sadb_x_policy *)request;
+ struct sadb_x_policy *xpl;
struct secpolicy **pcb_sp;
/* sanity check. */
if (in6p == NULL || request == NULL)
return EINVAL;
+ if (len < sizeof(*xpl))
+ return EINVAL;
+ xpl = (struct sadb_x_policy *)request;
/* select direction */
switch (xpl->sadb_x_policy_dir) {
@@ -1343,26 +1417,32 @@ ipsec6_set_policy(in6p, optname, request, priv)
pcb_sp = &in6p->in6p_sp->sp_out;
break;
default:
- printf("ipsec6_set_policy: invalid direction=%u\n",
- xpl->sadb_x_policy_dir);
+ ipseclog((LOG_ERR, "ipsec6_set_policy: invalid direction=%u\n",
+ xpl->sadb_x_policy_dir));
return EINVAL;
}
- return ipsec_set_policy(pcb_sp, optname, request, priv);
+ return ipsec_set_policy(pcb_sp, optname, request, len, priv);
}
int
-ipsec6_get_policy(in6p, request, mp)
+ipsec6_get_policy(in6p, request, len, mp)
struct in6pcb *in6p;
caddr_t request;
+ size_t len;
struct mbuf **mp;
{
- struct sadb_x_policy *xpl = (struct sadb_x_policy *)request;
+ struct sadb_x_policy *xpl;
struct secpolicy *pcb_sp;
/* sanity check. */
if (in6p == NULL || request == NULL || mp == NULL)
return EINVAL;
+ if (in6p->in6p_sp == NULL)
+ panic("policy in PCB is NULL\n");
+ if (len < sizeof(*xpl))
+ return EINVAL;
+ xpl = (struct sadb_x_policy *)request;
/* select direction */
switch (xpl->sadb_x_policy_dir) {
@@ -1373,8 +1453,8 @@ ipsec6_get_policy(in6p, request, mp)
pcb_sp = in6p->in6p_sp->sp_out;
break;
default:
- printf("ipsec6_set_policy: invalid direction=%u\n",
- xpl->sadb_x_policy_dir);
+ ipseclog((LOG_ERR, "ipsec6_set_policy: invalid direction=%u\n",
+ xpl->sadb_x_policy_dir));
return EINVAL;
}
@@ -1389,6 +1469,9 @@ ipsec6_delete_pcbpolicy(in6p)
if (in6p == NULL)
panic("ipsec6_delete_pcbpolicy: NULL pointer was passed.\n");
+ if (in6p->in6p_sp == NULL)
+ return 0;
+
if (in6p->in6p_sp->sp_in != NULL) {
key_freesp(in6p->in6p_sp->sp_in);
in6p->in6p_sp->sp_in = NULL;
@@ -1399,7 +1482,7 @@ ipsec6_delete_pcbpolicy(in6p)
in6p->in6p_sp->sp_out = NULL;
}
- KFREE(in6p->in6p_sp);
+ ipsec_delpcbpolicy(in6p->in6p_sp);
in6p->in6p_sp = NULL;
return 0;
@@ -1408,7 +1491,7 @@ ipsec6_delete_pcbpolicy(in6p)
/*
* return current level.
- * IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned.
+ * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned.
*/
u_int
ipsec_get_reqlevel(isr)
@@ -1420,17 +1503,24 @@ ipsec_get_reqlevel(isr)
/* sanity check */
if (isr == NULL || isr->sp == NULL)
panic("ipsec_get_reqlevel: NULL pointer is passed.\n");
- if (isr->sp->spidx.src.ss_family != isr->sp->spidx.dst.ss_family)
+ if (((struct sockaddr *)&isr->sp->spidx.src)->sa_family
+ != ((struct sockaddr *)&isr->sp->spidx.dst)->sa_family)
panic("ipsec_get_reqlevel: family mismatched.\n");
-#define IPSEC_CHECK_DEFAULT(lev) \
- (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE) \
- ? (printf("fixed system default level " #lev ":%d->%d\n", \
- (lev), IPSEC_LEVEL_USE), \
- (lev) = IPSEC_LEVEL_USE) : (lev))
+/* XXX note that we have ipseclog() expanded here - code sync issue */
+#define IPSEC_CHECK_DEFAULT(lev) \
+ (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE \
+ && (lev) != IPSEC_LEVEL_UNIQUE) \
+ ? (ipsec_debug \
+ ? log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\
+ (lev), IPSEC_LEVEL_REQUIRE) \
+ : 0), \
+ (lev) = IPSEC_LEVEL_REQUIRE, \
+ (lev) \
+ : (lev))
/* set default level */
- switch (isr->sp->spidx.src.ss_family) {
+ switch (((struct sockaddr *)&isr->sp->spidx.src)->sa_family) {
#ifdef INET
case AF_INET:
esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_trans_deflev);
@@ -1449,10 +1539,10 @@ ipsec_get_reqlevel(isr)
#endif /* INET6 */
default:
panic("key_get_reqlevel: Unknown family. %d\n",
- isr->sp->spidx.src.ss_family);
+ ((struct sockaddr *)&isr->sp->spidx.src)->sa_family);
}
-#undef IPSEC_CHECK_DEFAULT(lev)
+#undef IPSEC_CHECK_DEFAULT
/* set level */
switch (isr->level) {
@@ -1469,6 +1559,13 @@ ipsec_get_reqlevel(isr)
level = ah_net_deflev;
else
level = ah_trans_deflev;
+ case IPPROTO_IPCOMP:
+ /*
+ * we don't really care, as IPcomp document says that
+ * we shouldn't compress small packets
+ */
+ level = IPSEC_LEVEL_USE;
+ break;
default:
panic("ipsec_get_reqlevel: "
"Illegal protocol defined %u\n",
@@ -1480,6 +1577,9 @@ ipsec_get_reqlevel(isr)
case IPSEC_LEVEL_REQUIRE:
level = isr->level;
break;
+ case IPSEC_LEVEL_UNIQUE:
+ level = IPSEC_LEVEL_REQUIRE;
+ break;
default:
panic("ipsec_get_reqlevel: Illegal IPsec level %u\n",
@@ -1515,7 +1615,7 @@ ipsec_in_reject(sp, m)
case IPSEC_POLICY_BYPASS:
case IPSEC_POLICY_NONE:
return 0;
-
+
case IPSEC_POLICY_IPSEC:
break;
@@ -1550,6 +1650,12 @@ ipsec_in_reject(sp, m)
need_icv++;
}
break;
+ case IPPROTO_IPCOMP:
+ /*
+ * we don't really care, as IPcomp document says that
+ * we shouldn't compress small packets
+ */
+ break;
}
}
@@ -1696,7 +1802,7 @@ ipsec_hdrsiz(sp)
case IPSEC_POLICY_BYPASS:
case IPSEC_POLICY_NONE:
return 0;
-
+
case IPSEC_POLICY_IPSEC:
break;
@@ -1722,10 +1828,13 @@ ipsec_hdrsiz(sp)
case IPPROTO_AH:
clen = ah_hdrsiz(isr);
break;
+ case IPPROTO_IPCOMP:
+ clen = sizeof(struct ipcomp);
+ break;
}
if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
- switch (isr->saidx.dst.ss_family) {
+ switch (((struct sockaddr *)&isr->saidx.dst)->sa_family) {
case AF_INET:
clen += sizeof(struct ip);
break;
@@ -1735,9 +1844,9 @@ ipsec_hdrsiz(sp)
break;
#endif
default:
- printf("ipsec_hdrsiz: unknown AF %d "
- "in IPsec tunnel SA\n",
- isr->saidx.dst.ss_family);
+ ipseclog((LOG_ERR, "ipsec_hdrsiz: "
+ "unknown AF %d in IPsec tunnel SA\n",
+ ((struct sockaddr *)&isr->saidx.dst)->sa_family));
break;
}
}
@@ -1842,11 +1951,22 @@ ipsec4_encapsulate(m, sav)
size_t plen;
/* can't tunnel between different AFs */
- if (sav->sah->saidx.src.ss_family != sav->sah->saidx.dst.ss_family
- || sav->sah->saidx.src.ss_family != AF_INET) {
+ if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family
+ != ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family
+ || ((struct sockaddr *)&sav->sah->saidx.src)->sa_family != AF_INET) {
m_freem(m);
return EINVAL;
}
+#if 0
+ /* XXX if the dst is myself, perform nothing. */
+ if (key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) {
+ m_freem(m);
+ return EINVAL;
+ }
+#endif
+
+ if (m->m_len < sizeof(*ip))
+ panic("ipsec4_encapsulate: assumption failed (first mbuf length)");
ip = mtod(m, struct ip *);
#ifdef _IP_VHL
@@ -1855,6 +1975,9 @@ ipsec4_encapsulate(m, sav)
hlen = ip->ip_hl << 2;
#endif
+ if (m->m_len != hlen)
+ panic("ipsec4_encapsulate: assumption failed (first mbuf length)");
+
/* generate header checksum */
ip->ip_sum = 0;
#ifdef _IP_VHL
@@ -1872,8 +1995,6 @@ ipsec4_encapsulate(m, sav)
* grow the mbuf to accomodate the new IPv4 header.
* NOTE: IPv4 options will never be copied.
*/
- if (m->m_len != hlen)
- panic("ipsec4_encapsulate: assumption failed (first mbuf length)");
if (M_LEADINGSPACE(m->m_next) < hlen) {
struct mbuf *n;
MGET(n, M_DONTWAIT, MT_DATA);
@@ -1921,8 +2042,8 @@ ipsec4_encapsulate(m, sav)
if (plen + sizeof(struct ip) < IP_MAXPACKET)
ip->ip_len = htons(plen + sizeof(struct ip));
else {
- printf("IPv4 ipsec: size exceeds limit: "
- "leave ip_len as is (invalid packet)\n");
+ ipseclog((LOG_ERR, "IPv4 ipsec: size exceeds limit: "
+ "leave ip_len as is (invalid packet)\n"));
}
ip->ip_id = htons(ip_id++);
bcopy(&((struct sockaddr_in *)&sav->sah->saidx.src)->sin_addr,
@@ -1947,11 +2068,19 @@ ipsec6_encapsulate(m, sav)
size_t plen;
/* can't tunnel between different AFs */
- if (sav->sah->saidx.src.ss_family != sav->sah->saidx.dst.ss_family
- || sav->sah->saidx.src.ss_family != AF_INET6) {
+ if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family
+ != ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family
+ || ((struct sockaddr *)&sav->sah->saidx.src)->sa_family != AF_INET6) {
m_freem(m);
return EINVAL;
}
+#if 0
+ /* XXX if the dst is myself, perform nothing. */
+ if (key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) {
+ m_freem(m);
+ return EINVAL;
+ }
+#endif
plen = m->m_pkthdr.len;
@@ -2030,7 +2159,7 @@ ipsec_chkreplay(seq, sav)
/* sanity check */
if (sav == NULL)
- printf("ipsec_chkreplay: NULL pointer was passed.\n");
+ panic("ipsec_chkreplay: NULL pointer was passed.\n");
replay = sav->replay;
@@ -2071,6 +2200,11 @@ ipsec_chkreplay(seq, sav)
}
}
+/*
+ * check replay counter whether to update or not.
+ * OUT: 0: OK
+ * 1: NG
+ */
int
ipsec_updatereplay(seq, sav)
u_int32_t seq;
@@ -2084,7 +2218,7 @@ ipsec_updatereplay(seq, sav)
/* sanity check */
if (sav == NULL)
- printf("ipsec_chkreplay: NULL pointer was passed.\n");
+ panic("ipsec_chkreplay: NULL pointer was passed.\n");
replay = sav->replay;
@@ -2097,7 +2231,7 @@ ipsec_updatereplay(seq, sav)
/* sequence number of 0 is invalid */
if (seq == 0)
- return 0;
+ return 1;
/* first time */
if (replay->count == 0) {
@@ -2131,13 +2265,13 @@ ipsec_updatereplay(seq, sav)
/* over range to check, i.e. too old or wrapped */
if (diff >= wsizeb)
- return 0;
+ return 1;
fr = frlast - diff / 8;
/* this packet already seen ? */
if ((replay->bitmap)[fr] & (1 << (diff % 8)))
- return 0;
+ return 1;
/* mark as seen */
(replay->bitmap)[fr] |= (1 << (diff % 8));
@@ -2146,14 +2280,22 @@ ipsec_updatereplay(seq, sav)
}
ok:
- if (replay->count == ~0
- && (sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
- return 1; /* don't increment, no more packets accepted */
+ if (replay->count == ~0) {
+
+ /* set overflow flag */
+ replay->overflow++;
+
+ /* don't increment, no more packets accepted */
+ if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0)
+ return 1;
+
+ ipseclog((LOG_WARNING, "replay counter made %d cycle. %s\n",
+ replay->overflow, ipsec_logsastr(sav)));
}
replay->count++;
- return 1;
+ return 0;
}
/*
@@ -2195,17 +2337,18 @@ ipsec4_logpacketstr(ip, spi)
s = (u_int8_t *)(&ip->ip_src);
d = (u_int8_t *)(&ip->ip_dst);
+ p = buf;
snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi));
- for (p = buf; p && *p; p++)
- ;
+ while (p && *p)
+ p++;
snprintf(p, sizeof(buf) - (p - buf), "src=%d.%d.%d.%d",
s[0], s[1], s[2], s[3]);
- for (/*nothing*/; p && *p; p++)
- ;
+ while (p && *p)
+ p++;
snprintf(p, sizeof(buf) - (p - buf), " dst=%d.%d.%d.%d",
d[0], d[1], d[2], d[3]);
- for (/*nothing*/; p && *p; p++)
- ;
+ while (p && *p)
+ p++;
snprintf(p, sizeof(buf) - (p - buf), ")");
return buf;
@@ -2220,17 +2363,18 @@ ipsec6_logpacketstr(ip6, spi)
static char buf[256];
char *p;
+ p = buf;
snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi));
- for (p = buf; p && *p; p++)
- ;
+ while (p && *p)
+ p++;
snprintf(p, sizeof(buf) - (p - buf), "src=%s",
ip6_sprintf(&ip6->ip6_src));
- for (/*nothing*/; p && *p; p++)
- ;
+ while (p && *p)
+ p++;
snprintf(p, sizeof(buf) - (p - buf), " dst=%s",
ip6_sprintf(&ip6->ip6_dst));
- for (/*nothing*/; p && *p; p++)
- ;
+ while (p && *p)
+ p++;
snprintf(p, sizeof(buf) - (p - buf), ")");
return buf;
@@ -2246,13 +2390,15 @@ ipsec_logsastr(sav)
struct secasindex *saidx = &sav->sah->saidx;
/* validity check */
- if (sav->sah->saidx.src.ss_family != sav->sah->saidx.dst.ss_family)
+ if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family
+ != ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family)
panic("ipsec_logsastr: family mismatched.\n");
+ p = buf;
snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi));
- for (p = buf; p && *p; p++)
- ;
- if (saidx->src.ss_family == AF_INET) {
+ while (p && *p)
+ p++;
+ if (((struct sockaddr *)&saidx->src)->sa_family == AF_INET) {
u_int8_t *s, *d;
s = (u_int8_t *)&((struct sockaddr_in *)&saidx->src)->sin_addr;
d = (u_int8_t *)&((struct sockaddr_in *)&saidx->dst)->sin_addr;
@@ -2261,19 +2407,19 @@ ipsec_logsastr(sav)
s[0], s[1], s[2], s[3], d[0], d[1], d[2], d[3]);
}
#ifdef INET6
- else if (saidx->src.ss_family == AF_INET6) {
+ else if (((struct sockaddr *)&saidx->src)->sa_family == AF_INET6) {
snprintf(p, sizeof(buf) - (p - buf),
"src=%s",
ip6_sprintf(&((struct sockaddr_in6 *)&saidx->src)->sin6_addr));
- for (/*nothing*/; p && *p; p++)
- ;
+ while (p && *p)
+ p++;
snprintf(p, sizeof(buf) - (p - buf),
" dst=%s",
ip6_sprintf(&((struct sockaddr_in6 *)&saidx->dst)->sin6_addr));
}
#endif
- for (/*nothing*/; p && *p; p++)
- ;
+ while (p && *p)
+ p++;
snprintf(p, sizeof(buf) - (p - buf), ")");
return buf;
@@ -2315,12 +2461,14 @@ ipsec4_output(state, sp, flags)
{
struct ip *ip = NULL;
struct ipsecrequest *isr = NULL;
+ struct secasindex saidx;
int s;
int error;
#ifdef IPSEC_SRCSEL
struct in_ifaddr *ia;
#endif
struct sockaddr_in *dst4;
+ struct sockaddr_in *sin;
if (!state)
panic("state == NULL in ipsec4_output");
@@ -2331,15 +2479,44 @@ ipsec4_output(state, sp, flags)
if (!state->dst)
panic("state->dst == NULL in ipsec4_output");
- ip = mtod(state->m, struct ip *);
-
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
printf("ipsec4_output: applyed SP\n");
kdebug_secpolicy(sp));
for (isr = sp->req; isr != NULL; isr = isr->next) {
- if ((error = key_checkrequest(isr)) != 0) {
+#if 0 /* give up to check restriction of transport mode */
+ /* XXX but should be checked somewhere */
+ /*
+ * some of the IPsec operation must be performed only in
+ * originating case.
+ */
+ if (isr->saidx.mode == IPSEC_MODE_TRANSPORT
+ && (flags & IP_FORWARDING))
+ continue;
+#endif
+
+ /* make SA index for search proper SA */
+ ip = mtod(state->m, struct ip *);
+ bcopy(&isr->saidx, &saidx, sizeof(saidx));
+ sin = (struct sockaddr_in *)&saidx.src;
+ if (sin->sin_len == 0) {
+ sin->sin_len = sizeof(*sin);
+ sin->sin_family = AF_INET;
+ sin->sin_port = IPSEC_PORT_ANY;
+ bcopy(&ip->ip_src, &sin->sin_addr,
+ sizeof(sin->sin_addr));
+ }
+ sin = (struct sockaddr_in *)&saidx.dst;
+ if (sin->sin_len == 0) {
+ sin->sin_len = sizeof(*sin);
+ sin->sin_family = AF_INET;
+ sin->sin_port = IPSEC_PORT_ANY;
+ bcopy(&ip->ip_dst, &sin->sin_addr,
+ sizeof(sin->sin_addr));
+ }
+
+ if ((error = key_checkrequest(isr, &saidx)) != 0) {
/*
* IPsec processing is required, but no SA found.
* I assume that key_acquire() had been called
@@ -2362,9 +2539,15 @@ ipsec4_output(state, sp, flags)
}
}
+ /*
+ * If there is no valid SA, we give up to process any
+ * more. In such a case, the SA's status is changed
+ * from DYING to DEAD after allocating. If a packet
+ * send to the receiver by dead SA, the receiver can
+ * not decode a packet because SA has been dead.
+ */
if (isr->sav->state != SADB_SASTATE_MATURE
&& isr->sav->state != SADB_SASTATE_DYING) {
- /* If there is no valid SA, we give up to process. */
ipsecstat.out_nosa++;
error = EINVAL;
goto bad;
@@ -2381,17 +2564,15 @@ ipsec4_output(state, sp, flags)
* build IPsec tunnel.
*/
/* XXX should be processed with other familiy */
- if (isr->sav->sah->saidx.src.ss_family != AF_INET) {
- printf("ipsec4_output: family mismatched "
- "between inner and outer spi=%u\n",
- (u_int32_t)ntohl(isr->sav->spi));
+ if (((struct sockaddr *)&isr->sav->sah->saidx.src)->sa_family != AF_INET) {
+ ipseclog((LOG_ERR, "ipsec4_output: "
+ "family mismatched between inner and outer spi=%u\n",
+ (u_int32_t)ntohl(isr->sav->spi)));
splx(s);
error = EAFNOSUPPORT;
goto bad;
}
- ip = mtod(state->m, struct ip *);
-
state->m = ipsec4_splithdr(state->m);
if (!state->m) {
splx(s);
@@ -2468,9 +2649,16 @@ ipsec4_output(state, sp, flags)
goto bad;
}
break;
+ case IPPROTO_IPCOMP:
+ if ((error = ipcomp4_output(state->m, isr)) != 0) {
+ state->m = NULL;
+ goto bad;
+ }
+ break;
default:
- printf("ipsec4_output: unknown ipsec protocol %d\n",
- isr->saidx.proto);
+ ipseclog((LOG_ERR,
+ "ipsec4_output: unknown ipsec protocol %d\n",
+ isr->saidx.proto));
m_freem(state->m);
state->m = NULL;
error = EINVAL;
@@ -2507,8 +2695,10 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun)
{
struct ip6_hdr *ip6;
struct ipsecrequest *isr = NULL;
+ struct secasindex saidx;
int error = 0;
int plen;
+ struct sockaddr_in6 *sin6;
if (!state)
panic("state == NULL in ipsec6_output");
@@ -2534,7 +2724,37 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun)
break;
}
- if (key_checkrequest(isr) == ENOENT) {
+ /* make SA index for search proper SA */
+ ip6 = mtod(state->m, struct ip6_hdr *);
+ bcopy(&isr->saidx, &saidx, sizeof(saidx));
+ sin6 = (struct sockaddr_in6 *)&saidx.src;
+ if (sin6->sin6_len == 0) {
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = IPSEC_PORT_ANY;
+ bcopy(&ip6->ip6_src, &sin6->sin6_addr,
+ sizeof(ip6->ip6_src));
+ 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]);
+ }
+ }
+ sin6 = (struct sockaddr_in6 *)&saidx.dst;
+ if (sin6->sin6_len == 0) {
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = IPSEC_PORT_ANY;
+ bcopy(&ip6->ip6_dst, &sin6->sin6_addr,
+ sizeof(ip6->ip6_dst));
+ 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]);
+ }
+ }
+
+ if (key_checkrequest(isr, &saidx) == ENOENT) {
/*
* IPsec processing is required, but no SA found.
* I assume that key_acquire() had been called
@@ -2558,9 +2778,12 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun)
}
}
+ /*
+ * If there is no valid SA, we give up to process.
+ * see same place at ipsec4_output().
+ */
if (isr->sav->state != SADB_SASTATE_MATURE
&& isr->sav->state != SADB_SASTATE_DYING) {
- /* If there is no valid SA, we give up to process. */
ipsec6stat.out_nosa++;
error = EINVAL;
goto bad;
@@ -2578,9 +2801,14 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun)
case IPPROTO_AH:
error = ah6_output(state->m, nexthdrp, mprev->m_next, isr);
break;
+ case IPPROTO_IPCOMP:
+ error = ipcomp6_output(state->m, nexthdrp, mprev->m_next, isr);
+ break;
default:
- printf("ipsec6_output_trans: unknown ipsec protocol %d\n", isr->saidx.proto);
+ ipseclog((LOG_ERR, "ipsec6_output_trans: "
+ "unknown ipsec protocol %d\n", isr->saidx.proto));
m_freem(state->m);
+ ipsec6stat.out_inval++;
error = EINVAL;
break;
}
@@ -2590,7 +2818,8 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun)
}
plen = state->m->m_pkthdr.len - sizeof(struct ip6_hdr);
if (plen > IPV6_MAXPACKET) {
- printf("ipsec6_output: IPsec with IPv6 jumbogram is not supported\n");
+ ipseclog((LOG_ERR, "ipsec6_output_trans: "
+ "IPsec with IPv6 jumbogram is not supported\n"));
ipsec6stat.out_inval++;
error = EINVAL; /*XXX*/
goto bad;
@@ -2622,6 +2851,7 @@ ipsec6_output_tunnel(state, sp, flags)
{
struct ip6_hdr *ip6;
struct ipsecrequest *isr = NULL;
+ struct secasindex saidx;
int error = 0;
int plen;
#ifdef IPSEC_SRCSEL
@@ -2651,7 +2881,9 @@ ipsec6_output_tunnel(state, sp, flags)
}
for (/*already initialized*/; isr; isr = isr->next) {
- if (key_checkrequest(isr) == ENOENT) {
+ /* When tunnel mode, SA peers must be specified. */
+ bcopy(&isr->saidx, &saidx, sizeof(saidx));
+ if (key_checkrequest(isr, &saidx) == ENOENT) {
/*
* IPsec processing is required, but no SA found.
* I assume that key_acquire() had been called
@@ -2675,9 +2907,12 @@ ipsec6_output_tunnel(state, sp, flags)
}
}
+ /*
+ * If there is no valid SA, we give up to process.
+ * see same place at ipsec4_output().
+ */
if (isr->sav->state != SADB_SASTATE_MATURE
&& isr->sav->state != SADB_SASTATE_DYING) {
- /* If there is no valid SA, we give up to process. */
ipsec6stat.out_nosa++;
error = EINVAL;
goto bad;
@@ -2694,23 +2929,20 @@ ipsec6_output_tunnel(state, sp, flags)
* build IPsec tunnel.
*/
/* XXX should be processed with other familiy */
- if (isr->sav->sah->saidx.src.ss_family != AF_INET6) {
- printf("ipsec4_output: family mismatched "
- "between inner and outer, spi=%u\n",
- (u_int32_t)ntohl(isr->sav->spi));
- printf("ipsec6_output_tunnel: family mismatched "
- "between inner and outer, spi=%u\n",
- (u_int32_t)ntohl(isr->sav->spi));
+ if (((struct sockaddr *)&isr->sav->sah->saidx.src)->sa_family != AF_INET6) {
+ ipseclog((LOG_ERR, "ipsec6_output_tunnel: "
+ "family mismatched between inner and outer, spi=%u\n",
+ (u_int32_t)ntohl(isr->sav->spi)));
splx(s);
+ ipsec6stat.out_inval++;
error = EAFNOSUPPORT;
goto bad;
}
- ip6 = mtod(state->m, struct ip6_hdr *);
-
state->m = ipsec6_splithdr(state->m);
if (!state->m) {
splx(s);
+ ipsec6stat.out_nomem++;
error = ENOMEM;
goto bad;
}
@@ -2740,9 +2972,16 @@ ipsec6_output_tunnel(state, sp, flags)
}
if (state->ro->ro_rt == 0) {
ip6stat.ip6s_noroute++;
+ ipsec6stat.out_noroute++;
error = EHOSTUNREACH;
goto bad;
}
+#if 0 /* XXX Is the following need ? */
+ if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) {
+ state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway;
+ dst6 = (struct sockaddr_in6 *)state->dst;
+ }
+#endif
#ifdef IPSEC_SRCSEL
/*
* Which address in SA or in routing table should I
@@ -2752,8 +2991,11 @@ ipsec6_output_tunnel(state, sp, flags)
ia6 = in6_selectsrc(dst6, NULL, NULL,
(struct route_in6 *)state->ro,
NULL, &error);
- if (ia6 == NULL)
+ if (ia6 == NULL) {
+ ip6stat.ip6s_noroute++;
+ ipsec6stat.out_noroute++;
goto bad;
+ }
ip6->ip6_src = *ia6;
#endif
} else
@@ -2761,6 +3003,7 @@ ipsec6_output_tunnel(state, sp, flags)
state->m = ipsec6_splithdr(state->m);
if (!state->m) {
+ ipsec6stat.out_nomem++;
error = ENOMEM;
goto bad;
}
@@ -2777,9 +3020,14 @@ ipsec6_output_tunnel(state, sp, flags)
case IPPROTO_AH:
error = ah6_output(state->m, &ip6->ip6_nxt, state->m->m_next, isr);
break;
+ case IPPROTO_IPCOMP:
+ /* XXX code should be here */
+ /*FALLTHROUGH*/
default:
- printf("ipsec6_output_tunnel: unknown ipsec protocol %d\n", isr->saidx.proto);
+ ipseclog((LOG_ERR, "ipsec6_output_tunnel: "
+ "unknown ipsec protocol %d\n", isr->saidx.proto));
m_freem(state->m);
+ ipsec6stat.out_inval++;
error = EINVAL;
break;
}
@@ -2789,7 +3037,8 @@ ipsec6_output_tunnel(state, sp, flags)
}
plen = state->m->m_pkthdr.len - sizeof(struct ip6_hdr);
if (plen > IPV6_MAXPACKET) {
- printf("ipsec6_output_tunnel: IPsec with IPv6 jumbogram is not supported\n");
+ ipseclog((LOG_ERR, "ipsec6_output_tunnel: "
+ "IPsec with IPv6 jumbogram is not supported\n"));
ipsec6stat.out_inval++;
error = EINVAL; /*XXX*/
goto bad;
@@ -2906,7 +3155,7 @@ ipsec4_tunnel_validate(ip, nxt0, sav)
#endif
if (hlen != sizeof(struct ip))
return 0;
- switch (sav->sah->saidx.dst.ss_family) {
+ 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)
@@ -2937,7 +3186,7 @@ ipsec6_tunnel_validate(ip6, nxt0, sav)
if (nxt != IPPROTO_IPV6)
return 0;
- switch (sav->sah->saidx.dst.ss_family) {
+ 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))
@@ -2987,6 +3236,14 @@ ipsec_copypkt(m)
if (mnew == NULL)
goto fail;
mnew->m_pkthdr = n->m_pkthdr;
+#if 0
+ if (n->m_pkthdr.aux) {
+ mnew->m_pkthdr.aux =
+ m_copym(n->m_pkthdr.aux,
+ 0, M_COPYALL, M_DONTWAIT);
+ }
+#endif
+ M_COPY_PKTHDR(mnew, n);
mnew->m_flags = n->m_flags & M_COPYFLAGS;
}
else {
@@ -3059,3 +3316,39 @@ ipsec_copypkt(m)
m_freem(m);
return(NULL);
}
+
+void
+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);
+ }
+}
+
+struct socket *
+ipsec_getsocket(m)
+ struct mbuf *m;
+{
+ struct mbuf *n;
+
+ n = m_aux_find(m, AF_INET, IPPROTO_ESP);
+ if (n && n->m_len >= sizeof(struct socket *))
+ return *mtod(n, struct socket **);
+ else
+ return NULL;
+}
diff --git a/sys/netinet6/ipsec.h b/sys/netinet6/ipsec.h
index df68bd7b88b0..80be10c0312c 100644
--- a/sys/netinet6/ipsec.h
+++ b/sys/netinet6/ipsec.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ipsec.h,v 1.33 2000/06/19 14:31:49 sakane Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -43,59 +44,79 @@
/*
* Security Policy Index
- * NOTE: Encure to be same address family and upper layer protocol.
+ * NOTE: Ensure to be same address family and upper layer protocol.
* NOTE: ul_proto, port number, uid, gid:
* ANY: reserved for waldcard.
* 0 to (~0 - 1): is one of the number of each value.
*/
struct secpolicyindex {
- u_int8_t dir; /* direction of packet flow, see blow */
- struct sockaddr_storage src; /* IP src address for SP */
- struct sockaddr_storage dst; /* IP dst address for SP */
- u_int8_t prefs; /* prefix length in bits for src */
- u_int8_t prefd; /* prefix length in bits for dst */
- u_int16_t ul_proto; /* upper layer Protocol */
+ u_int8_t dir; /* direction of packet flow, see blow */
+ struct sockaddr_storage src; /* IP src address for SP */
+ struct sockaddr_storage dst; /* IP dst address for SP */
+ u_int8_t prefs; /* prefix length in bits for src */
+ u_int8_t prefd; /* prefix length in bits for dst */
+ u_int16_t ul_proto; /* upper layer Protocol */
+#ifdef notyet
+ uid_t uids;
+ uid_t uidd;
+ gid_t gids;
+ gid_t gidd;
+#endif
};
/* Security Policy Data Base */
struct secpolicy {
LIST_ENTRY(secpolicy) chain;
- int refcnt; /* reference count */
+ int refcnt; /* reference count */
struct secpolicyindex spidx; /* selector */
- u_int state; /* 0: dead, others: alive */
-#define IPSEC_SPSTATE_DEAD 0
-#define IPSEC_SPSTATE_ALIVE 1
+ u_int32_t id; /* It's unique number on the system. */
+ u_int state; /* 0: dead, others: alive */
+#define IPSEC_SPSTATE_DEAD 0
+#define IPSEC_SPSTATE_ALIVE 1
- u_int policy; /* DISCARD, NONE or IPSEC, see keyv2.h */
- struct ipsecrequest *req;
+ u_int policy; /* DISCARD, NONE or IPSEC, see keyv2.h */
+ struct ipsecrequest *req;
/* pointer to the ipsec request tree, */
/* if policy == IPSEC else this value == NULL.*/
};
/* Request for IPsec */
struct ipsecrequest {
- struct ipsecrequest *next;
+ struct ipsecrequest *next;
/* pointer to next structure */
/* If NULL, it means the end of chain. */
- struct secasindex saidx;
- u_int level; /* IPsec level defined below. */
+ struct secasindex saidx;/* hint for search proper SA */
+ /* if __ss_len == 0 then no address specified.*/
+ u_int level; /* IPsec level defined below. */
- struct secasvar *sav; /* place holder of SA for use */
- struct secpolicy *sp; /* back pointer to SP */
+ struct secasvar *sav; /* place holder of SA for use */
+ struct secpolicy *sp; /* back pointer to SP */
};
/* security policy in PCB */
struct inpcbpolicy {
- struct secpolicy *sp_in;
- struct secpolicy *sp_out;
- int priv; /* privileged socket ? */
+ struct secpolicy *sp_in;
+ struct secpolicy *sp_out;
+ int priv; /* privileged socket ? */
+};
+
+/* SP acquiring list table. */
+struct secspacq {
+ LIST_ENTRY(secspacq) chain;
+
+ struct secpolicyindex spidx;
+
+ u_int32_t tick; /* for lifetime */
+ int count; /* for lifetime */
+ /* XXX: here is mbuf place holder to be sent ? */
};
#endif /*_KERNEL*/
-#define IPSEC_PORT_ANY 65535
-#define IPSEC_ULPROTO_ANY 255
-#define IPSEC_PROTO_ANY 65535
+/* according to IANA assignment, port 0x0000 and proto 0xff are reserved. */
+#define IPSEC_PORT_ANY 0
+#define IPSEC_ULPROTO_ANY 255
+#define IPSEC_PROTO_ANY 255
/* mode of security protocol */
/* NOTE: DON'T use IPSEC_MODE_ANY at SPD. It's only use in SAD */
@@ -108,11 +129,11 @@ struct inpcbpolicy {
* NOTE: Since INVALID is used just as flag.
* The other are used for loop counter too.
*/
-#define IPSEC_DIR_ANY 0
-#define IPSEC_DIR_INBOUND 1
-#define IPSEC_DIR_OUTBOUND 2
-#define IPSEC_DIR_MAX 3
-#define IPSEC_DIR_INVALID 4
+#define IPSEC_DIR_ANY 0
+#define IPSEC_DIR_INBOUND 1
+#define IPSEC_DIR_OUTBOUND 2
+#define IPSEC_DIR_MAX 3
+#define IPSEC_DIR_INVALID 4
/* Policy level */
/*
@@ -120,11 +141,11 @@ struct inpcbpolicy {
* DISCARD, IPSEC and NONE are allowd for setkey() in SPD.
* DISCARD and NONE are allowd for system default.
*/
-#define IPSEC_POLICY_DISCARD 0 /* discarding packet */
-#define IPSEC_POLICY_NONE 1 /* through IPsec engine */
-#define IPSEC_POLICY_IPSEC 2 /* do IPsec */
-#define IPSEC_POLICY_ENTRUST 3 /* consulting SPD if present. */
-#define IPSEC_POLICY_BYPASS 4 /* only for privileged socket. */
+#define IPSEC_POLICY_DISCARD 0 /* discarding packet */
+#define IPSEC_POLICY_NONE 1 /* through IPsec engine */
+#define IPSEC_POLICY_IPSEC 2 /* do IPsec */
+#define IPSEC_POLICY_ENTRUST 3 /* consulting SPD if present. */
+#define IPSEC_POLICY_BYPASS 4 /* only for privileged socket. */
/* Security protocol level */
#define IPSEC_LEVEL_DEFAULT 0 /* reference to system default */
@@ -132,30 +153,47 @@ struct inpcbpolicy {
#define IPSEC_LEVEL_REQUIRE 2 /* require SA. */
#define IPSEC_LEVEL_UNIQUE 3 /* unique SA. */
+#define IPSEC_MANUAL_REQID_MAX 0x3fff
+ /*
+ * if security policy level == unique, this id
+ * indicate to a relative SA for use, else is
+ * zero.
+ * 1 - 0x3fff are reserved for manual keying.
+ * 0 are reserved for above reason. Others is
+ * for kernel use.
+ * Note that this id doesn't identify SA
+ * by only itself.
+ */
#define IPSEC_REPLAYWSIZE 32
/* statistics for ipsec processing */
struct ipsecstat {
- u_long in_success; /* succeeded inbound process */
- u_long in_polvio; /* security policy violation for inbound process */
- u_long in_nosa; /* inbound SA is unavailable */
- u_long in_inval; /* inbound processing failed due to EINVAL */
- u_long in_badspi; /* failed getting a SPI */
- u_long in_ahreplay; /* AH replay check failed */
- u_long in_espreplay; /* ESP replay check failed */
- u_long in_ahauthsucc; /* AH authentication success */
- u_long in_ahauthfail; /* AH authentication failure */
- u_long in_espauthsucc; /* ESP authentication success */
- u_long in_espauthfail; /* ESP authentication failure */
- u_long in_esphist[SADB_EALG_MAX];
- u_long in_ahhist[SADB_AALG_MAX];
- u_long out_success; /* succeeded outbound process */
- u_long out_polvio; /* security policy violation for outbound process */
- u_long out_nosa; /* outbound SA is unavailable */
- u_long out_inval; /* outbound process failed due to EINVAL */
- u_long out_noroute; /* there is no route */
- u_long out_esphist[SADB_EALG_MAX];
- u_long out_ahhist[SADB_AALG_MAX];
+ u_quad_t in_success; /* succeeded inbound process */
+ u_quad_t in_polvio;
+ /* security policy violation for inbound process */
+ u_quad_t in_nosa; /* inbound SA is unavailable */
+ u_quad_t in_inval; /* inbound processing failed due to EINVAL */
+ u_quad_t in_nomem; /* inbound processing failed due to ENOBUFS */
+ u_quad_t in_badspi; /* failed getting a SPI */
+ u_quad_t in_ahreplay; /* AH replay check failed */
+ u_quad_t in_espreplay; /* ESP replay check failed */
+ u_quad_t in_ahauthsucc; /* AH authentication success */
+ u_quad_t in_ahauthfail; /* AH authentication failure */
+ u_quad_t in_espauthsucc; /* ESP authentication success */
+ u_quad_t in_espauthfail; /* ESP authentication failure */
+ u_quad_t in_esphist[256];
+ u_quad_t in_ahhist[256];
+ u_quad_t in_comphist[256];
+ u_quad_t out_success; /* succeeded outbound process */
+ u_quad_t out_polvio;
+ /* security policy violation for outbound process */
+ u_quad_t out_nosa; /* outbound SA is unavailable */
+ u_quad_t out_inval; /* outbound process failed due to EINVAL */
+ u_quad_t out_nomem; /* inbound processing failed due to ENOBUFS */
+ u_quad_t out_noroute; /* there is no route */
+ u_quad_t out_esphist[256];
+ u_quad_t out_ahhist[256];
+ u_quad_t out_comphist[256];
};
/*
@@ -164,18 +202,21 @@ struct ipsecstat {
/*
* Names for IPsec & Key sysctl objects
*/
-#define IPSECCTL_STATS 1 /* stats */
-#define IPSECCTL_DEF_POLICY 2
-#define IPSECCTL_DEF_ESP_TRANSLEV 3 /* int; ESP transport mode */
-#define IPSECCTL_DEF_ESP_NETLEV 4 /* int; ESP tunnel mode */
-#define IPSECCTL_DEF_AH_TRANSLEV 5 /* int; AH transport mode */
-#define IPSECCTL_DEF_AH_NETLEV 6 /* int; AH tunnel mode */
-#define IPSECCTL_INBOUND_CALL_IKE 7
+#define IPSECCTL_STATS 1 /* stats */
+#define IPSECCTL_DEF_POLICY 2
+#define IPSECCTL_DEF_ESP_TRANSLEV 3 /* int; ESP transport mode */
+#define IPSECCTL_DEF_ESP_NETLEV 4 /* int; ESP tunnel mode */
+#define IPSECCTL_DEF_AH_TRANSLEV 5 /* int; AH transport mode */
+#define IPSECCTL_DEF_AH_NETLEV 6 /* int; AH tunnel mode */
+#if 0 /*obsolete, do not reuse*/
+#define IPSECCTL_INBOUND_CALL_IKE 7
+#endif
#define IPSECCTL_AH_CLEARTOS 8
#define IPSECCTL_AH_OFFSETMASK 9
#define IPSECCTL_DFBIT 10
#define IPSECCTL_ECN 11
-#define IPSECCTL_MAXID 12
+#define IPSECCTL_DEBUG 12
+#define IPSECCTL_MAXID 13
#define IPSECCTL_NAMES { \
{ 0, 0 }, \
@@ -185,11 +226,12 @@ struct ipsecstat {
{ "esp_net_deflev", CTLTYPE_INT }, \
{ "ah_trans_deflev", CTLTYPE_INT }, \
{ "ah_net_deflev", CTLTYPE_INT }, \
- { "inbound_call_ike", CTLTYPE_INT }, \
+ { 0, 0 }, \
{ "ah_cleartos", CTLTYPE_INT }, \
{ "ah_offsetmask", CTLTYPE_INT }, \
{ "dfbit", CTLTYPE_INT }, \
{ "ecn", CTLTYPE_INT }, \
+ { "debug", CTLTYPE_INT }, \
}
#define IPSEC6CTL_NAMES { \
@@ -200,121 +242,83 @@ struct ipsecstat {
{ "esp_net_deflev", CTLTYPE_INT }, \
{ "ah_trans_deflev", CTLTYPE_INT }, \
{ "ah_net_deflev", CTLTYPE_INT }, \
- { "inbound_call_ike", CTLTYPE_INT }, \
+ { 0, 0 }, \
{ 0, 0 }, \
{ 0, 0 }, \
{ 0, 0 }, \
{ "ecn", CTLTYPE_INT }, \
-}
-
-#define IPSECCTL_VARS { \
- 0, \
- 0, \
- &ip4_def_policy.policy, \
- &ip4_esp_trans_deflev, \
- &ip4_esp_net_deflev, \
- &ip4_ah_trans_deflev, \
- &ip4_ah_net_deflev, \
- &ip4_inbound_call_ike, \
- &ip4_ah_cleartos, \
- &ip4_ah_offsetmask, \
- &ip4_ipsec_dfbit, \
- &ip4_ipsec_ecn, \
-}
-
-#define IPSEC6CTL_VARS { \
- 0, \
- 0, \
- &ip6_def_policy.policy, \
- &ip6_esp_trans_deflev, \
- &ip6_esp_net_deflev, \
- &ip6_ah_trans_deflev, \
- &ip6_ah_net_deflev, \
- &ip6_inbound_call_ike, \
- 0, \
- 0, \
- 0, \
- &ip6_ipsec_ecn, \
+ { "debug", CTLTYPE_INT }, \
}
#ifdef _KERNEL
-
-#ifdef SYSCTL_DECL
-SYSCTL_DECL(_net_inet_ipsec);
-#endif
-
struct ipsec_output_state {
- struct mbuf *m;
- struct route *ro;
- struct sockaddr *dst;
+ struct mbuf *m;
+ struct route *ro;
+ struct sockaddr *dst;
};
-extern struct ipsecstat ipsecstat;
-extern struct secpolicy ip4_def_policy;
-extern int ip4_esp_trans_deflev;
-extern int ip4_esp_net_deflev;
-extern int ip4_ah_trans_deflev;
-extern int ip4_ah_net_deflev;
-extern int ip4_inbound_call_ike;
-extern int ip4_ah_cleartos;
-extern int ip4_ah_offsetmask;
-extern int ip4_ipsec_dfbit;
-extern int ip4_ipsec_ecn;
-
-extern struct secpolicy *ipsec4_getpolicybysock
+extern int ipsec_debug;
+
+extern struct ipsecstat ipsecstat;
+extern struct secpolicy ip4_def_policy;
+extern int ip4_esp_trans_deflev;
+extern int ip4_esp_net_deflev;
+extern int ip4_ah_trans_deflev;
+extern int ip4_ah_net_deflev;
+extern int ip4_ah_cleartos;
+extern int ip4_ah_offsetmask;
+extern int ip4_ipsec_dfbit;
+extern int ip4_ipsec_ecn;
+
+#define ipseclog(x) do { if (ipsec_debug) log x; } while (0)
+
+extern struct secpolicy *ipsec4_getpolicybysock
__P((struct mbuf *, u_int, struct socket *, int *));
-extern struct secpolicy *ipsec4_getpolicybyaddr
+extern struct secpolicy *ipsec4_getpolicybyaddr
__P((struct mbuf *, u_int, int, int *));
-struct inpcb;
-
-extern int ipsec_init_policy __P((struct socket *so, struct inpcbpolicy **));
-extern int ipsec_copy_policy
+struct inpcb;
+extern int ipsec_init_policy __P((struct socket *so, struct inpcbpolicy **));
+extern int ipsec_copy_policy
__P((struct inpcbpolicy *, struct inpcbpolicy *));
-extern u_int ipsec_get_reqlevel __P((struct ipsecrequest *));
+extern u_int ipsec_get_reqlevel __P((struct ipsecrequest *));
-extern int ipsec4_set_policy __P((struct inpcb *inp, int optname,
- caddr_t request, int priv));
-extern int ipsec4_get_policy
- __P((struct inpcb *inpcb, caddr_t request, struct mbuf **mp));
-extern int ipsec4_delete_pcbpolicy __P((struct inpcb *));
-extern int ipsec4_in_reject_so __P((struct mbuf *, struct socket *));
-extern int ipsec4_in_reject __P((struct mbuf *, struct inpcb *));
+extern int ipsec4_set_policy __P((struct inpcb *inp, int optname,
+ caddr_t request, size_t len, int priv));
+extern int ipsec4_get_policy __P((struct inpcb *inpcb, caddr_t request,
+ size_t len, struct mbuf **mp));
+extern int ipsec4_delete_pcbpolicy __P((struct inpcb *));
+extern int ipsec4_in_reject_so __P((struct mbuf *, struct socket *));
+extern int ipsec4_in_reject __P((struct mbuf *, struct inpcb *));
-struct secas;
-struct tcpcb;
-struct tcp6cb;
-extern int ipsec_chkreplay __P((u_int32_t, struct secasvar *));
-extern int ipsec_updatereplay __P((u_int32_t, struct secasvar *));
+struct secas;
+struct tcpcb;
+extern int ipsec_chkreplay __P((u_int32_t, struct secasvar *));
+extern int ipsec_updatereplay __P((u_int32_t, struct secasvar *));
-extern size_t ipsec4_hdrsiz __P((struct mbuf *, u_int, struct inpcb *));
-extern size_t ipsec_hdrsiz_tcp __P((struct tcpcb *));
+extern size_t ipsec4_hdrsiz __P((struct mbuf *, u_int, struct inpcb *));
+extern size_t ipsec_hdrsiz_tcp __P((struct tcpcb *));
-struct ip;
+struct ip;
+extern const char *ipsec4_logpacketstr __P((struct ip *, u_int32_t));
+extern const char *ipsec_logsastr __P((struct secasvar *));
-extern const char *ipsec4_logpacketstr __P((struct ip *, u_int32_t));
-extern const char *ipsec_logsastr __P((struct secasvar *));
+extern void ipsec_dumpmbuf __P((struct mbuf *));
-extern void ipsec_dumpmbuf __P((struct mbuf *));
-
-extern int ipsec4_output __P((struct ipsec_output_state *, struct secpolicy *,
+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 struct mbuf *ipsec_copypkt __P((struct mbuf *));
-
+extern int ipsec4_tunnel_validate __P((struct ip *, u_int, struct secasvar *));
+extern struct mbuf *ipsec_copypkt __P((struct mbuf *));
+extern void ipsec_setsocket __P((struct mbuf *, struct socket *));
+extern struct socket *ipsec_getsocket __P((struct mbuf *));
#endif /*_KERNEL*/
#ifndef _KERNEL
+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 caddr_t ipsec_set_policy __P((char *policy, int buflen));
-extern int ipsec_get_policylen __P((caddr_t buf));
-extern char *ipsec_dump_policy __P((caddr_t buf, char *delimiter));
-
-extern char *ipsec_strerror __P((void));
+extern char *ipsec_strerror __P((void));
#endif /*!_KERNEL*/
#endif /*_NETINET6_IPSEC_H_*/
-
diff --git a/sys/netinet6/ipsec6.h b/sys/netinet6/ipsec6.h
index 0572592a6e3d..383c12581995 100644
--- a/sys/netinet6/ipsec6.h
+++ b/sys/netinet6/ipsec6.h
@@ -1,5 +1,8 @@
+/* $FreeBSD$ */
+/* $KAME: ipsec.h,v 1.33 2000/06/19 14:31:49 sakane Exp $ */
+
/*
- * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,57 +28,53 @@
* 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.
- *
- * $FreeBSD$
*/
/*
- * IPsec controller part, only IPv6 related
+ * IPsec controller part.
*/
#ifndef _NETINET6_IPSEC6_H_
#define _NETINET6_IPSEC6_H_
-#ifdef _KERNEL
-
-#ifdef SYSCTL_DECL
-SYSCTL_DECL(_net_inet6_ipsec6);
-#endif
+#include <net/pfkeyv2.h>
+#include <netkey/keydb.h>
-extern struct ipsecstat ipsec6stat;
-extern struct secpolicy ip6_def_policy;
-extern int ip6_esp_trans_deflev;
-extern int ip6_esp_net_deflev;
-extern int ip6_ah_trans_deflev;
-extern int ip6_ah_net_deflev;
-extern int ip6_inbound_call_ike;
-extern int ip6_ipsec_ecn;
+#ifdef _KERNEL
+extern struct ipsecstat ipsec6stat;
+extern struct secpolicy ip6_def_policy;
+extern int ip6_esp_trans_deflev;
+extern int ip6_esp_net_deflev;
+extern int ip6_ah_trans_deflev;
+extern int ip6_ah_net_deflev;
+extern int ip6_ipsec_ecn;
-extern struct secpolicy *ipsec6_getpolicybysock
+extern struct secpolicy *ipsec6_getpolicybysock
__P((struct mbuf *, u_int, struct socket *, int *));
-extern struct secpolicy *ipsec6_getpolicybyaddr
+extern struct secpolicy *ipsec6_getpolicybyaddr
__P((struct mbuf *, u_int, int, int *));
-extern int ipsec6_in_reject_so __P((struct mbuf *, struct socket *));
-extern int ipsec6_delete_pcbpolicy __P((struct inpcb *));
-extern int ipsec6_set_policy __P((struct inpcb *inp, int optname,
- caddr_t request, int priv));
-extern int ipsec6_get_policy
- __P((struct inpcb *inp, caddr_t request, struct mbuf **mp));
-extern int ipsec6_in_reject __P((struct mbuf *, struct inpcb *));
+struct inpcb;
-extern size_t ipsec6_hdrsiz __P((struct mbuf *, u_int, struct inpcb *));
+extern int ipsec6_in_reject_so __P((struct mbuf *, struct socket *));
+extern int ipsec6_delete_pcbpolicy __P((struct inpcb *));
+extern int ipsec6_set_policy __P((struct inpcb *inp, int optname,
+ caddr_t request, size_t len, int priv));
+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 ip6_hdr;
+extern size_t ipsec6_hdrsiz __P((struct mbuf *, u_int, struct inpcb *));
-extern const char *ipsec6_logpacketstr __P((struct ip6_hdr *, u_int32_t));
-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,
- struct secasvar *));
+struct ip6_hdr;
+extern const char *ipsec6_logpacketstr __P((struct ip6_hdr *, u_int32_t));
+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,
+ struct secasvar *));
#endif /*_KERNEL*/
-#endif /* _NETINET6_IPSEC6_H_ */
+
+#endif /*_NETINET6_IPSEC6_H_*/
diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c
index f09b38ac3d35..c655bb5eefb9 100644
--- a/sys/netinet6/mld6.c
+++ b/sys/netinet6/mld6.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: mld6.c,v 1.19 2000/05/05 11:01:03 sumikawa Exp $ */
+
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -68,7 +69,8 @@
* @(#)igmp.c 8.1 (Berkeley) 7/19/93
*/
-#include "opt_ipsec.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -81,10 +83,9 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
-#include <netinet6/in6.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#include <netinet6/mld6_var.h>
#include <net/net_osdep.h>
@@ -94,23 +95,20 @@
*/
/* denotes that the MLD max response delay field specifies time in milliseconds */
-#define MLD6_TIMER_SCALE 1000
+#define MLD6_TIMER_SCALE 1000
/*
* time between repetitions of a node's initial report of interest in a
* multicast address(in seconds)
*/
-#define MLD6_UNSOLICITED_REPORT_INTERVAL 10
+#define MLD6_UNSOLICITED_REPORT_INTERVAL 10
-static struct ip6_pktopts ip6_opts;
-static int mld6_timers_are_running;
+static struct ip6_pktopts ip6_opts;
+static int mld6_timers_are_running;
/* XXX: These are necessary for KAME's link-local hack */
-static struct in6_addr mld6_all_nodes_linklocal =
- IN6ADDR_LINKLOCAL_ALLNODES_INIT;
-static struct in6_addr mld6_all_routers_linklocal =
- IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
+static struct in6_addr mld6_all_nodes_linklocal = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
+static struct in6_addr mld6_all_routers_linklocal = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
-static void mld6_sendpkt __P((struct in6_multi *, int,
- const struct in6_addr *));
+static void mld6_sendpkt __P((struct in6_multi *, int, const struct in6_addr *));
void
mld6_init()
@@ -122,7 +120,7 @@ mld6_init()
mld6_timers_are_running = 0;
/* ip6h_nxt will be fill in later */
- hbh->ip6h_len = 0; /* (8 >> 3) - 1*/
+ hbh->ip6h_len = 0; /* (8 >> 3) - 1 */
/* XXX: grotty hard coding... */
hbh_buf[2] = IP6OPT_PADN; /* 2 byte padding */
@@ -143,7 +141,7 @@ mld6_start_listening(in6m)
int s = splnet();
/*
- * (draft-ietf-ipngwg-mld, page 10)
+ * RFC2710 page 10:
* The node never sends a Report or Done for the link-scope all-nodes
* address.
* MLD messages are never sent for multicast addresses whose scope is 0
@@ -187,7 +185,7 @@ mld6_input(m, off)
int off;
{
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
- struct mld6_hdr *mldh = (struct mld6_hdr *)(mtod(m, caddr_t) + off);
+ struct mld6_hdr *mldh;
struct ifnet *ifp = m->m_pkthdr.rcvif;
struct in6_multi *in6m;
struct in6_ifaddr *ia;
@@ -200,13 +198,25 @@ mld6_input(m, off)
"mld6_input: src %s is not link-local\n",
ip6_sprintf(&ip6->ip6_src));
/*
- * spec(draft-ietf-ipngwg-mld) does not explicitly
+ * 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.
*/
+ 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.
*
@@ -231,25 +241,25 @@ mld6_input(m, off)
htons(ifp->if_index); /* XXX */
/*
- * - Start the timers in all of our membership records
- * that the query applies to for the interface on
- * which the query arrived excl. those that belong
- * to the "all-nodes" group (ff02::1).
- * - Restart any timer that is already running but has
- * A value longer than the requested timeout.
- * - Use the value specified in the query message as
- * the maximum timeout.
- */
+ * - Start the timers in all of our membership records
+ * that the query applies to for the interface on
+ * which the query arrived excl. those that belong
+ * to the "all-nodes" group (ff02::1).
+ * - Restart any timer that is already running but has
+ * A value longer than the requested timeout.
+ * - Use the value specified in the query message as
+ * the maximum timeout.
+ */
IFP_TO_IA6(ifp, ia);
if (ia == NULL)
break;
/*
- * XXX: System timer resolution is too low to handle Max
- * Response Delay, so set 1 to the internal timer even if
- * the calculated value equals to zero when Max Response
- * Delay is positive.
- */
+ * XXX: System timer resolution is too low to handle Max
+ * Response Delay, so set 1 to the internal timer even if
+ * the calculated value equals to zero when Max Response
+ * Delay is positive.
+ */
timer = ntohs(mldh->mld6_maxdelay)*PR_FASTHZ/MLD6_TIMER_SCALE;
if (timer == 0 && mldh->mld6_maxdelay)
timer = 1;
@@ -277,7 +287,8 @@ mld6_input(m, off)
NULL);
in6m->in6m_timer = 0; /* reset timer */
in6m->in6m_state = MLD6_IREPORTEDLAST;
- } else if (in6m->in6m_timer == 0 || /*idle state*/
+ }
+ else if (in6m->in6m_timer == 0 || /*idle state*/
in6m->in6m_timer > timer) {
in6m->in6m_timer =
MLD6_RANDOM_DELAY(timer);
@@ -291,14 +302,14 @@ mld6_input(m, off)
break;
case MLD6_LISTENER_REPORT:
/*
- * For fast leave to work, we have to know that we are the
- * last person to send a report for this group. Reports
- * can potentially get looped back if we are a multicast
- * router, so discard reports sourced by me.
- * Note that it is impossible to check IFF_LOOPBACK flag of
- * ifp for this purpose, since ip6_mloopback pass the physical
- * interface to looutput.
- */
+ * For fast leave to work, we have to know that we are the
+ * last person to send a report for this group. Reports
+ * can potentially get looped back if we are a multicast
+ * router, so discard reports sourced by me.
+ * Note that it is impossible to check IFF_LOOPBACK flag of
+ * ifp for this purpose, since ip6_mloopback pass the physical
+ * interface to looutput.
+ */
if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */
break;
@@ -309,9 +320,9 @@ mld6_input(m, off)
mldh->mld6_addr.s6_addr16[1] =
htons(ifp->if_index); /* XXX */
/*
- * If we belong to the group being reported, stop
- * our timer for that group.
- */
+ * If we belong to the group being reported, stop
+ * our timer for that group.
+ */
IN6_LOOKUP_MULTI(mldh->mld6_addr, ifp, in6m);
if (in6m) {
in6m->in6m_timer = 0; /* transit to idle state */
@@ -325,6 +336,8 @@ mld6_input(m, off)
log(LOG_ERR, "mld6_input: illegal type(%d)", mldh->mld6_type);
break;
}
+
+ m_freem(m);
}
void
@@ -376,7 +389,8 @@ mld6_sendpkt(in6m, type, dst)
* At first, find a link local address on the outgoing interface
* to use as the source address of the MLD packet.
*/
- if ((ia = in6ifa_ifpforlinklocal(ifp)) == NULL)
+ if ((ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST))
+ == NULL)
return;
/*
@@ -393,6 +407,7 @@ mld6_sendpkt(in6m, type, dst)
return;
}
mh->m_next = md;
+
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));
@@ -400,7 +415,8 @@ mld6_sendpkt(in6m, type, dst)
/* fill in the ip6 header */
ip6 = mtod(mh, struct ip6_hdr *);
ip6->ip6_flow = 0;
- ip6->ip6_vfc = IPV6_VERSION;
+ ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
+ ip6->ip6_vfc |= IPV6_VERSION;
/* ip6_plen will be set later */
ip6->ip6_nxt = IPPROTO_ICMPV6;
/* ip6_hlim will be set by im6o.im6o_multicast_hlim */
@@ -431,7 +447,7 @@ mld6_sendpkt(in6m, type, dst)
* Request loopback of the report if we are acting as a multicast
* router, so that the process-level routing daemon can hear it.
*/
- im6o.im6o_multicast_loop = 0;
+ im6o.im6o_multicast_loop = (ip6_mrouter != NULL);
/* increment output statictics */
icmp6stat.icp6s_outhist[type]++;
diff --git a/sys/netinet6/mld6_var.h b/sys/netinet6/mld6_var.h
index ab50c5967b40..e58560e82aa0 100644
--- a/sys/netinet6/mld6_var.h
+++ b/sys/netinet6/mld6_var.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: mld6_var.h,v 1.4 2000/03/25 07:23:54 sumikawa Exp $ */
+
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
@@ -25,22 +28,20 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _NETINET6_MLD6_VAR_H_
-#define _NETINET6_MLD6_VAR_H_
+#define _NETINET6_MLD6_VAR_H_
#ifdef _KERNEL
-#define MLD6_RANDOM_DELAY(X) (random() % (X) + 1)
+#define MLD6_RANDOM_DELAY(X) (random() % (X) + 1)
/*
* States for MLD stop-listening processing
*/
-#define MLD6_OTHERLISTENER 0
-#define MLD6_IREPORTEDLAST 1
+#define MLD6_OTHERLISTENER 0
+#define MLD6_IREPORTEDLAST 1
void mld6_init __P((void));
void mld6_input __P((struct mbuf *, int));
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index 31e975c29093..0a56a9105a46 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: nd6.c,v 1.68 2000/07/02 14:48:02 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -37,6 +38,9 @@
* I left the code mostly as it was in 970310. -- itojun
*/
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -45,6 +49,7 @@
#include <sys/sockio.h>
#include <sys/time.h>
#include <sys/kernel.h>
+#include <sys/protosw.h>
#include <sys/errno.h>
#include <sys/syslog.h>
#include <sys/queue.h>
@@ -59,21 +64,21 @@
#include <netinet/if_ether.h>
#include <netinet/if_fddi.h>
#include <netinet6/in6_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
#include <netinet6/in6_prefix.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#include "loop.h"
#include <net/net_osdep.h>
-#define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */
-#define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */
+#define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */
+#define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */
-#define SIN6(s) ((struct sockaddr_in6 *)s)
-#define SDL(s) ((struct sockaddr_dl *)s)
+#define SIN6(s) ((struct sockaddr_in6 *)s)
+#define SDL(s) ((struct sockaddr_dl *)s)
/* timer values */
int nd6_prune = 1; /* walk list every 1 seconds */
@@ -81,20 +86,25 @@ int nd6_delay = 5; /* delay first probe time 5 second */
int nd6_umaxtries = 3; /* maximum unicast query */
int nd6_mmaxtries = 3; /* maximum multicast query */
int nd6_useloopback = 1; /* use loopback interface for local traffic */
-int nd6_proxyall = 0; /* enable Proxy Neighbor Advertisement */
+
+/* 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 */
/* for debugging? */
-static int nd6_inuse, nd6_allocated;
+static int nd6_inuse, nd6_allocated;
-struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6};
-struct nd_ifinfo *nd_ifinfo = NULL;
-struct nd_drhead nd_defrouter = { 0 };
-struct nd_prhead nd_prefix = { 0 };
+struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6};
+static size_t nd_ifinfo_indexlim = 8;
+struct nd_ifinfo *nd_ifinfo = NULL;
+struct nd_drhead nd_defrouter;
+struct nd_prhead nd_prefix = { 0 };
-int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL;
-static struct sockaddr_in6 all1_sa;
+int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL;
+static struct sockaddr_in6 all1_sa;
-static void nd6_slowtimo __P((void *));
+static void nd6_slowtimo __P((void *));
void
nd6_init()
@@ -112,6 +122,9 @@ nd6_init()
for (i = 0; i < sizeof(all1_sa.sin6_addr); i++)
all1_sa.sin6_addr.s6_addr[i] = 0xff;
+ /* initialization of the default router list */
+ TAILQ_INIT(&nd_defrouter);
+
nd6_init_done = 1;
/* start timer */
@@ -122,21 +135,20 @@ void
nd6_ifattach(ifp)
struct ifnet *ifp;
{
- static size_t if_indexlim = 8;
/*
* We have some arrays that should be indexed by if_index.
* since if_index will grow dynamically, they should grow too.
*/
- if (nd_ifinfo == NULL || if_index >= if_indexlim) {
+ if (nd_ifinfo == NULL || if_index >= nd_ifinfo_indexlim) {
size_t n;
caddr_t q;
- while (if_index >= if_indexlim)
- if_indexlim <<= 1;
+ while (if_index >= nd_ifinfo_indexlim)
+ nd_ifinfo_indexlim <<= 1;
/* grow nd_ifinfo */
- n = if_indexlim * sizeof(struct nd_ifinfo);
+ n = nd_ifinfo_indexlim * sizeof(struct nd_ifinfo);
q = (caddr_t)malloc(n, M_IP6NDP, M_WAITOK);
bzero(q, n);
if (nd_ifinfo) {
@@ -147,12 +159,18 @@ nd6_ifattach(ifp)
}
#define ND nd_ifinfo[ifp->if_index]
+
+ /* don't initialize if called twice */
+ if (ND.linkmtu)
+ return;
+
ND.linkmtu = ifindex2ifnet[ifp->if_index]->if_mtu;
ND.chlim = IPV6_DEFHLIM;
ND.basereachable = REACHABLE_TIME;
ND.reachable = ND_COMPUTE_RTIME(ND.basereachable);
ND.retrans = RETRANS_TIMER;
ND.receivedra = 0;
+ ND.flags = ND6_IFF_PERFORMNUD;
nd6_setmtu(ifp);
#undef ND
}
@@ -330,14 +348,15 @@ nd6_options(ndopts)
* Unknown options must be silently ignored,
* to accomodate future extension to the protocol.
*/
- log(LOG_INFO,
+ log(LOG_DEBUG,
"nd6_options: unsupported option %d - "
"option ignored\n", nd_opt->nd_opt_type);
}
skip1:
i++;
- if (i > 10) {
+ if (i > nd6_maxndopt) {
+ icmp6stat.icp6s_nd_toomanyopt++;
printf("too many loop in nd opt\n");
break;
}
@@ -371,6 +390,8 @@ nd6_timer(ignored_arg)
struct ifnet *ifp;
struct sockaddr_in6 *dst;
struct llinfo_nd6 *next = ln->ln_next;
+ /* XXX: used for the DELAY case only: */
+ struct nd_ifinfo *ndi = NULL;
if ((rt = ln->ln_rt) == NULL) {
ln = next;
@@ -380,6 +401,7 @@ nd6_timer(ignored_arg)
ln = next;
continue;
}
+ ndi = &nd_ifinfo[ifp->if_index];
dst = (struct sockaddr_in6 *)rt_key(rt);
if (ln->ln_expire > time_second) {
@@ -390,6 +412,9 @@ nd6_timer(ignored_arg)
/* sanity check */
if (!rt)
panic("rt=0 in nd6_timer(ln=%p)\n", ln);
+ if (rt->rt_llinfo && (struct llinfo_nd6 *)rt->rt_llinfo != ln)
+ panic("rt_llinfo(%p) is not equal to ln(%p)\n",
+ rt->rt_llinfo, ln);
if (!dst)
panic("dst=0 in nd6_timer(ln=%p)\n", ln);
@@ -422,23 +447,26 @@ nd6_timer(ignored_arg)
}
break;
case ND6_LLINFO_REACHABLE:
- if (ln->ln_expire) {
+ if (ln->ln_expire)
ln->ln_state = ND6_LLINFO_STALE;
- }
break;
/*
* ND6_LLINFO_STALE state requires nothing for timer
* routine.
*/
case ND6_LLINFO_DELAY:
- ln->ln_asked = 1;
- ln->ln_state = ND6_LLINFO_PROBE;
- ln->ln_expire = time_second +
- nd_ifinfo[ifp->if_index].retrans / 1000;
- nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr,
- ln, 0);
+ if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) {
+ /* We need NUD */
+ ln->ln_asked = 1;
+ ln->ln_state = ND6_LLINFO_PROBE;
+ ln->ln_expire = time_second +
+ ndi->retrans / 1000;
+ nd6_ns_output(ifp, &dst->sin6_addr,
+ &dst->sin6_addr,
+ ln, 0);
+ } else
+ ln->ln_state = ND6_LLINFO_STALE; /* XXX */
break;
-
case ND6_LLINFO_PROBE:
if (ln->ln_asked < nd6_umaxtries) {
ln->ln_asked++;
@@ -458,17 +486,18 @@ nd6_timer(ignored_arg)
}
/* expire */
- dr = LIST_FIRST(&nd_defrouter);
+ dr = TAILQ_FIRST(&nd_defrouter);
while (dr) {
if (dr->expire && dr->expire < time_second) {
struct nd_defrouter *t;
- t = LIST_NEXT(dr, dr_entry);
+ t = TAILQ_NEXT(dr, dr_entry);
defrtrlist_del(dr);
dr = t;
- } else
- dr = LIST_NEXT(dr, dr_entry);
+ } else {
+ dr = TAILQ_NEXT(dr, dr_entry);
+ }
}
- pr = LIST_FIRST(&nd_prefix);
+ pr = nd_prefix.lh_first;
while (pr) {
struct in6_ifaddr *ia6;
struct in6_addrlifetime *lt6;
@@ -503,7 +532,7 @@ nd6_timer(ignored_arg)
if (pr->ndpr_expire
&& pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) {
struct nd_prefix *t;
- t = LIST_NEXT(pr, ndpr_entry);
+ t = pr->ndpr_next;
/*
* address expiration and prefix expiration are
@@ -513,11 +542,104 @@ nd6_timer(ignored_arg)
prelist_remove(pr);
pr = t;
} else
- pr = LIST_NEXT(pr, ndpr_entry);
+ pr = pr->ndpr_next;
}
splx(s);
}
+/*
+ * Nuke neighbor cache/prefix/default router management table, right before
+ * ifp goes away.
+ */
+void
+nd6_purge(ifp)
+ struct ifnet *ifp;
+{
+ struct llinfo_nd6 *ln, *nln;
+ struct nd_defrouter *dr, *ndr, drany;
+ struct nd_prefix *pr, *npr;
+
+ /* Nuke default router list entries toward ifp */
+ if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) {
+ /*
+ * The first entry of the list may be stored in
+ * the routing table, so we'll delete it later.
+ */
+ for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = ndr) {
+ ndr = TAILQ_NEXT(dr, dr_entry);
+ if (dr->ifp == ifp)
+ defrtrlist_del(dr);
+ }
+ dr = TAILQ_FIRST(&nd_defrouter);
+ if (dr->ifp == ifp)
+ defrtrlist_del(dr);
+ }
+
+ /* Nuke prefix list entries toward ifp */
+ for (pr = nd_prefix.lh_first; pr; pr = npr) {
+ npr = pr->ndpr_next;
+ if (pr->ndpr_ifp == ifp) {
+ if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
+ in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr);
+ prelist_remove(pr);
+ }
+ }
+
+ /* cancel default outgoing interface setting */
+ if (nd6_defifindex == ifp->if_index)
+ nd6_setdefaultiface(0);
+
+ /* refresh default router list */
+ bzero(&drany, sizeof(drany));
+ defrouter_delreq(&drany, 0);
+ defrouter_select();
+
+ /*
+ * Nuke neighbor cache entries for the ifp.
+ * Note that rt->rt_ifp may not be the same as ifp,
+ * due to KAME goto ours hack. See RTM_RESOLVE case in
+ * nd6_rtrequest(), and ip6_input().
+ */
+ ln = llinfo_nd6.ln_next;
+ while (ln && ln != &llinfo_nd6) {
+ struct rtentry *rt;
+ struct sockaddr_dl *sdl;
+
+ nln = ln->ln_next;
+ rt = ln->ln_rt;
+ if (rt && rt->rt_gateway &&
+ rt->rt_gateway->sa_family == AF_LINK) {
+ sdl = (struct sockaddr_dl *)rt->rt_gateway;
+ if (sdl->sdl_index == ifp->if_index)
+ nd6_free(rt);
+ }
+ ln = nln;
+ }
+
+ /*
+ * Neighbor cache entry for interface route will be retained
+ * with ND6_LLINFO_WAITDELETE state, by nd6_free(). Nuke it.
+ */
+ ln = llinfo_nd6.ln_next;
+ while (ln && ln != &llinfo_nd6) {
+ struct rtentry *rt;
+ struct sockaddr_dl *sdl;
+
+ nln = ln->ln_next;
+ rt = ln->ln_rt;
+ if (rt && rt->rt_gateway &&
+ rt->rt_gateway->sa_family == AF_LINK) {
+ sdl = (struct sockaddr_dl *)rt->rt_gateway;
+ if (sdl->sdl_index == ifp->if_index) {
+ rtrequest(RTM_DELETE, rt_key(rt),
+ (struct sockaddr *)0, rt_mask(rt), 0,
+ (struct rtentry **)0);
+ }
+ }
+ ln = nln;
+ }
+}
+
struct rtentry *
nd6_lookup(addr6, create, ifp)
struct in6_addr *addr6;
@@ -531,6 +653,9 @@ nd6_lookup(addr6, create, ifp)
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_family = AF_INET6;
sin6.sin6_addr = *addr6;
+#ifdef SCOPEDROUTING
+ sin6.sin6_scope_id = in6_addr2scopeid(ifp, addr6);
+#endif
rt = rtalloc1((struct sockaddr *)&sin6, create, 0UL);
if (rt && (rt->rt_flags & RTF_LLINFO) == 0) {
/*
@@ -546,6 +671,8 @@ nd6_lookup(addr6, create, ifp)
}
if (!rt) {
if (create && ifp) {
+ int e;
+
/*
* If no route is available and create is set,
* we allocate a host route for the destination
@@ -564,15 +691,17 @@ nd6_lookup(addr6, create, ifp)
* destination in nd6_rtrequest which will be
* called in rtequest via ifa->ifa_rtrequest.
*/
- if (rtrequest(RTM_ADD, (struct sockaddr *)&sin6,
- ifa->ifa_addr,
- (struct sockaddr *)&all1_sa,
- (ifa->ifa_flags |
- RTF_HOST | RTF_LLINFO) & ~RTF_CLONING,
- &rt))
+ if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6,
+ ifa->ifa_addr,
+ (struct sockaddr *)&all1_sa,
+ (ifa->ifa_flags |
+ RTF_HOST | RTF_LLINFO) &
+ ~RTF_CLONING,
+ &rt)) != 0)
log(LOG_ERR,
"nd6_lookup: failed to add route for a "
- "neighbor(%s)\n", ip6_sprintf(addr6));
+ "neighbor(%s), errno=%d\n",
+ ip6_sprintf(addr6), e);
if (rt == NULL)
return(NULL);
if (rt->rt_llinfo) {
@@ -610,7 +739,7 @@ nd6_lookup(addr6, create, ifp)
*/
int
nd6_is_addr_neighbor(addr, ifp)
- struct in6_addr *addr;
+ struct sockaddr_in6 *addr;
struct ifnet *ifp;
{
register struct ifaddr *ifa;
@@ -619,21 +748,29 @@ nd6_is_addr_neighbor(addr, ifp)
#define IFADDR6(a) ((((struct in6_ifaddr *)(a))->ia_addr).sin6_addr)
#define IFMASK6(a) ((((struct in6_ifaddr *)(a))->ia_prefixmask).sin6_addr)
- /* A link-local address is always a neighbor. */
- if (IN6_IS_ADDR_LINKLOCAL(addr))
+ /*
+ * A link-local address is always a neighbor.
+ * XXX: we should use the sin6_scope_id field rather than the embedded
+ * interface index.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr) &&
+ ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]) == ifp->if_index)
return(1);
/*
* If the address matches one of our addresses,
* it should be a neighbor.
*/
- TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
+ for (ifa = ifp->if_addrlist.tqh_first;
+ ifa;
+ ifa = ifa->ifa_list.tqe_next)
{
if (ifa->ifa_addr->sa_family != AF_INET6)
next: continue;
for (i = 0; i < 4; i++) {
- if ((IFADDR6(ifa).s6_addr32[i] ^ addr->s6_addr32[i]) &
+ if ((IFADDR6(ifa).s6_addr32[i] ^
+ addr->sin6_addr.s6_addr32[i]) &
IFMASK6(ifa).s6_addr32[i])
goto next;
}
@@ -644,7 +781,7 @@ nd6_is_addr_neighbor(addr, ifp)
* Even if the address matches none of our addresses, it might be
* in the neighbor cache.
*/
- if (nd6_lookup(addr, 0, ifp))
+ if (nd6_lookup(&addr->sin6_addr, 0, ifp))
return(1);
return(0);
@@ -661,40 +798,74 @@ nd6_free(rt)
{
struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo;
struct sockaddr_dl *sdl;
+ struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr;
+ struct nd_defrouter *dr;
- if (ln->ln_router) {
- /* remove from default router list */
- struct nd_defrouter *dr;
- struct in6_addr *in6;
- int s;
- in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr;
+ /*
+ * Clear all destination cache entries for the neighbor.
+ * XXX: is it better to restrict this to hosts?
+ */
+ 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,
+ dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
rt->rt_ifp);
- if (dr)
- defrtrlist_del(dr);
- else if (!ip6_forwarding && ip6_accept_rtadv) {
+ if (ln->ln_router || dr) {
+ /*
+ * rt6_flush must be called whether or not the neighbor
+ * is in the Default Router List.
+ * See a corresponding comment in nd6_na_input().
+ */
+ rt6_flush(&in6, rt->rt_ifp);
+ }
+
+ if (dr) {
/*
- * rt6_flush must be called in any case.
- * see the comment in nd6_na_input().
+ * Unreachablity of a router might affect the default
+ * router selection and on-link detection of advertised
+ * prefixes.
*/
- rt6_flush(in6, rt->rt_ifp);
+
+ /*
+ * Temporarily fake the state to choose a new default
+ * router and to perform on-link determination of
+ * prefixes coreectly.
+ * Below the state will be set correctly,
+ * or the entry itself will be deleted.
+ */
+ ln->ln_state = ND6_LLINFO_INCOMPLETE;
+
+ if (dr == TAILQ_FIRST(&nd_defrouter)) {
+ /*
+ * It is used as the current default router,
+ * so we have to move it to the end of the
+ * list and choose a new one.
+ * XXX: it is not very efficient if this is
+ * the only router.
+ */
+ TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
+ TAILQ_INSERT_TAIL(&nd_defrouter, dr, dr_entry);
+
+ defrouter_select();
+ }
+ pfxlist_onlink_check();
}
splx(s);
}
-
+
if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) &&
- sdl->sdl_family == AF_LINK) {
+ sdl->sdl_family == AF_LINK) {
sdl->sdl_alen = 0;
ln->ln_state = ND6_LLINFO_WAITDELETE;
ln->ln_asked = 0;
rt->rt_flags &= ~RTF_REJECT;
return;
}
- rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt),
- 0, (struct rtentry **)0);
+
+ rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0,
+ rt_mask(rt), 0, (struct rtentry **)0);
}
/*
@@ -703,9 +874,10 @@ nd6_free(rt)
* XXX cost-effective metods?
*/
void
-nd6_nud_hint(rt, dst6)
+nd6_nud_hint(rt, dst6, force)
struct rtentry *rt;
struct in6_addr *dst6;
+ int force;
{
struct llinfo_nd6 *ln;
@@ -720,11 +892,10 @@ nd6_nud_hint(rt, dst6)
return;
}
- if ((rt->rt_flags & RTF_GATEWAY)
- || (rt->rt_flags & RTF_LLINFO) == 0
- || !rt->rt_llinfo
- || !rt->rt_gateway
- || rt->rt_gateway->sa_family != AF_LINK) {
+ if ((rt->rt_flags & RTF_GATEWAY) != 0 ||
+ (rt->rt_flags & RTF_LLINFO) == 0 ||
+ !rt->rt_llinfo || !rt->rt_gateway ||
+ rt->rt_gateway->sa_family != AF_LINK) {
/* This is not a host route. */
return;
}
@@ -733,12 +904,117 @@ nd6_nud_hint(rt, dst6)
if (ln->ln_state < ND6_LLINFO_REACHABLE)
return;
+ /*
+ * if we get upper-layer reachability confirmation many times,
+ * it is possible we have false information.
+ */
+ if (!force) {
+ ln->ln_byhint++;
+ if (ln->ln_byhint > nd6_maxnudhint)
+ return;
+ }
+
ln->ln_state = ND6_LLINFO_REACHABLE;
if (ln->ln_expire)
ln->ln_expire = time_second +
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:
+ return(0);
+ }
+ }
+ if (rt && (rt->rt_flags & RTF_LLINFO) != 0)
+ ln = (struct llinfo_nd6 *)rt->rt_llinfo;
+ else {
+ if ((rt = nd6_lookup(&(SIN6(dst)->sin6_addr), 1, ifp)) != NULL)
+ ln = (struct llinfo_nd6 *)rt->rt_llinfo;
+ }
+ if (!ln || !rt) {
+ log(LOG_DEBUG, "nd6_resolve: can't allocate llinfo for %s\n",
+ ip6_sprintf(&(SIN6(dst)->sin6_addr)));
+ m_freem(m);
+ return(0);
+ }
+ sdl = SDL(rt->rt_gateway);
+ /*
+ * Ckeck the address family and length is valid, the address
+ * is resolved; otherwise, try to resolve.
+ */
+ if (ln->ln_state >= ND6_LLINFO_REACHABLE
+ && sdl->sdl_family == AF_LINK
+ && sdl->sdl_alen != 0) {
+ bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
+ if (ln->ln_state == ND6_LLINFO_STALE) {
+ ln->ln_asked = 0;
+ ln->ln_state = ND6_LLINFO_DELAY;
+ ln->ln_expire = time_second + nd6_delay;
+ }
+ return(1);
+ }
+ /*
+ * There is an ndp entry, but no ethernet address
+ * response yet. Replace the held mbuf with this
+ * latest one.
+ *
+ * XXX Does the code conform to rate-limiting rule?
+ * (RFC 2461 7.2.2)
+ */
+ if (ln->ln_state == ND6_LLINFO_WAITDELETE ||
+ ln->ln_state == ND6_LLINFO_NOSTATE)
+ ln->ln_state = ND6_LLINFO_INCOMPLETE;
+ if (ln->ln_hold)
+ m_freem(ln->ln_hold);
+ ln->ln_hold = m;
+ if (ln->ln_expire) {
+ rt->rt_flags &= ~RTF_REJECT;
+ if (ln->ln_asked < nd6_mmaxtries &&
+ ln->ln_expire < time_second) {
+ ln->ln_asked++;
+ ln->ln_expire = time_second +
+ nd_ifinfo[ifp->if_index].retrans / 1000;
+ nd6_ns_output(ifp, NULL, &(SIN6(dst)->sin6_addr),
+ ln, 0);
+ }
+ }
+ return(0);
+}
+#endif /* OLDIP6OUTPUT */
+
void
nd6_rtrequest(req, rt, sa)
int req;
@@ -763,7 +1039,7 @@ nd6_rtrequest(req, rt, sa)
* SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
* rt->rt_flags |= RTF_CLONING;
*/
- if (rt->rt_flags & RTF_CLONING || rt->rt_flags & RTF_LLINFO) {
+ if (rt->rt_flags & (RTF_CLONING | RTF_LLINFO)) {
/*
* Case 1: This route should come from
* a route to interface. RTF_LLINFO flag is set
@@ -777,30 +1053,63 @@ nd6_rtrequest(req, rt, sa)
SDL(gate)->sdl_index = ifp->if_index;
if (ln)
ln->ln_expire = time_second;
+#if 1
if (ln && ln->ln_expire == 0) {
/* cludge for desktops */
+#if 0
+ printf("nd6_request: time.tv_sec is zero; "
+ "treat it as 1\n");
+#endif
ln->ln_expire = 1;
}
+#endif
if (rt->rt_flags & RTF_CLONING)
break;
}
- /* Announce a new entry if requested. */
+ /*
+ * In IPv4 code, we try to annonuce new RTF_ANNOUNCE entry here.
+ * We don't do that here since llinfo is not ready yet.
+ *
+ * There are also couple of other things to be discussed:
+ * - unsolicited NA code needs improvement beforehand
+ * - RFC2461 says we MAY send multicast unsolicited NA
+ * (7.2.6 paragraph 4), however, it also says that we
+ * SHOULD provide a mechanism to prevent multicast NA storm.
+ * we don't have anything like it right now.
+ * note that the mechanism need a mutual agreement
+ * between proxies, which means that we need to implement
+ * a new protocol, or new kludge.
+ * - from RFC2461 6.2.4, host MUST NOT send unsolicited NA.
+ * we need to check ip6forwarding before sending it.
+ * (or should we allow proxy ND configuration only for
+ * routers? there's no mention about proxy ND from hosts)
+ */
+#if 0
+ /* XXX it does not work */
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);
+ &SIN6(rt_key(rt))->sin6_addr,
+ &SIN6(rt_key(rt))->sin6_addr,
+ ip6_forwarding ? ND_NA_FLAG_ROUTER : 0,
+ 1, NULL);
+#endif
/* FALLTHROUGH */
case RTM_RESOLVE:
- if (gate->sa_family != AF_LINK ||
- gate->sa_len < sizeof(null_sdl)) {
- log(LOG_DEBUG, "nd6_rtrequest: bad gateway value\n");
- break;
+ if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
+ /*
+ * Address resolution isn't necessary for a point to
+ * point link, so we can skip this test for a p2p link.
+ */
+ if (gate->sa_family != AF_LINK ||
+ gate->sa_len < sizeof(null_sdl)) {
+ log(LOG_DEBUG,
+ "nd6_rtrequest: bad gateway value\n");
+ break;
+ }
+ SDL(gate)->sdl_type = ifp->if_type;
+ SDL(gate)->sdl_index = ifp->if_index;
}
- SDL(gate)->sdl_type = ifp->if_type;
- SDL(gate)->sdl_index = ifp->if_index;
- if (ln != 0)
+ if (ln != NULL)
break; /* This happens on a route change */
/*
* Case 2: This route may come from cloning, or a manual route
@@ -824,12 +1133,13 @@ nd6_rtrequest(req, rt, sa)
* which is specified by ndp command.
*/
ln->ln_state = ND6_LLINFO_REACHABLE;
+ ln->ln_byhint = 0;
} else {
/*
* When req == RTM_RESOLVE, rt is created and
* initialized in rtrequest(), so rt_expire is 0.
*/
- ln->ln_state = ND6_LLINFO_INCOMPLETE;
+ ln->ln_state = ND6_LLINFO_NOSTATE;
ln->ln_expire = time_second;
}
rt->rt_flags |= RTF_LLINFO;
@@ -848,6 +1158,7 @@ nd6_rtrequest(req, rt, sa)
caddr_t macp = nd6_ifptomac(ifp);
ln->ln_expire = 0;
ln->ln_state = ND6_LLINFO_REACHABLE;
+ ln->ln_byhint = 0;
if (macp) {
Bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen);
SDL(gate)->sdl_alen = ifp->if_addrlen;
@@ -863,17 +1174,56 @@ nd6_rtrequest(req, rt, sa)
* of the loopback address.
*/
if (ifa != rt->rt_ifa) {
- rt->rt_ifa->ifa_refcnt--;
+ IFAFREE(rt->rt_ifa);
ifa->ifa_refcnt++;
rt->rt_ifa = ifa;
}
}
+ } else if (rt->rt_flags & RTF_ANNOUNCE) {
+ ln->ln_expire = 0;
+ ln->ln_state = ND6_LLINFO_REACHABLE;
+ ln->ln_byhint = 0;
+
+ /* join solicited node multicast for proxy ND */
+ if (ifp->if_flags & IFF_MULTICAST) {
+ struct in6_addr llsol;
+ int error;
+
+ llsol = SIN6(rt_key(rt))->sin6_addr;
+ llsol.s6_addr16[0] = htons(0xff02);
+ llsol.s6_addr16[1] = htons(ifp->if_index);
+ llsol.s6_addr32[1] = 0;
+ llsol.s6_addr32[2] = htonl(1);
+ llsol.s6_addr8[12] = 0xff;
+
+ (void)in6_addmulti(&llsol, ifp, &error);
+ if (error)
+ printf(
+"nd6_rtrequest: could not join solicited node multicast (errno=%d)\n", error);
+ }
}
break;
case RTM_DELETE:
if (!ln)
break;
+ /* leave from solicited node multicast for proxy ND */
+ if ((rt->rt_flags & RTF_ANNOUNCE) != 0 &&
+ (ifp->if_flags & IFF_MULTICAST) != 0) {
+ struct in6_addr llsol;
+ struct in6_multi *in6m;
+
+ llsol = SIN6(rt_key(rt))->sin6_addr;
+ llsol.s6_addr16[0] = htons(0xff02);
+ llsol.s6_addr16[1] = htons(ifp->if_index);
+ llsol.s6_addr32[1] = 0;
+ llsol.s6_addr32[2] = htonl(1);
+ llsol.s6_addr8[12] = 0xff;
+
+ IN6_LOOKUP_MULTI(llsol, ifp, in6m);
+ if (in6m)
+ in6_delmulti(in6m);
+ }
nd6_inuse--;
ln->ln_next->ln_prev = ln->ln_prev;
ln->ln_prev->ln_next = ln->ln_next;
@@ -927,7 +1277,7 @@ nd6_p2p_rtrequest(req, rt, sa)
&SIN6(rt_key(rt))->sin6_addr,
&SIN6(rt_key(rt))->sin6_addr,
ip6_forwarding ? ND_NA_FLAG_ROUTER : 0,
- 1);
+ 1, NULL);
/* FALLTHROUGH */
case RTM_RESOLVE:
/*
@@ -955,6 +1305,7 @@ nd6_ioctl(cmd, data, ifp)
struct in6_prlist *prl = (struct in6_prlist *)data;
struct in6_ndireq *ndi = (struct in6_ndireq *)data;
struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data;
+ struct in6_ndifreq *ndif = (struct in6_ndifreq *)data;
struct nd_defrouter *dr, any;
struct nd_prefix *pr;
struct rtentry *rt;
@@ -965,7 +1316,7 @@ nd6_ioctl(cmd, data, ifp)
case SIOCGDRLST_IN6:
bzero(drl, sizeof(*drl));
s = splnet();
- dr = LIST_FIRST(&nd_defrouter);
+ dr = TAILQ_FIRST(&nd_defrouter);
while (dr && i < DRLSTSIZ) {
drl->defrouter[i].rtaddr = dr->rtaddr;
if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) {
@@ -982,14 +1333,19 @@ nd6_ioctl(cmd, data, ifp)
drl->defrouter[i].expire = dr->expire;
drl->defrouter[i].if_index = dr->ifp->if_index;
i++;
- dr = LIST_NEXT(dr, dr_entry);
+ dr = TAILQ_NEXT(dr, dr_entry);
}
splx(s);
break;
case SIOCGPRLST_IN6:
+ /*
+ * XXX meaning of fields, especialy "raflags", is very
+ * differnet between RA prefix list and RR/static prefix list.
+ * how about separating ioctls into two?
+ */
bzero(prl, sizeof(*prl));
s = splnet();
- pr = LIST_FIRST(&nd_prefix);
+ pr = nd_prefix.lh_first;
while (pr && i < PRLSTSIZ) {
struct nd_pfxrouter *pfr;
int j;
@@ -1002,7 +1358,7 @@ nd6_ioctl(cmd, data, ifp)
prl->prefix[i].if_index = pr->ndpr_ifp->if_index;
prl->prefix[i].expire = pr->ndpr_expire;
- pfr = LIST_FIRST(&pr->ndpr_advrtrs);
+ pfr = pr->ndpr_advrtrs.lh_first;
j = 0;
while(pfr) {
if (j < DRLSTSIZ) {
@@ -1020,14 +1376,14 @@ nd6_ioctl(cmd, data, ifp)
#undef RTRADDR
}
j++;
- pfr = LIST_NEXT(pfr, pfr_entry);
+ pfr = pfr->pfr_next;
}
prl->prefix[i].advrtrs = j;
+ prl->prefix[i].origin = PR_ORIG_RA;
i++;
- pr = LIST_NEXT(pr, ndpr_entry);
+ pr = pr->ndpr_next;
}
- splx(s);
{
struct rr_prefix *rpp;
@@ -1043,15 +1399,29 @@ nd6_ioctl(cmd, data, ifp)
prl->prefix[i].if_index = rpp->rp_ifp->if_index;
prl->prefix[i].expire = rpp->rp_expire;
prl->prefix[i].advrtrs = 0;
+ prl->prefix[i].origin = rpp->rp_origin;
i++;
}
}
+ splx(s);
break;
case SIOCGIFINFO_IN6:
+ if (!nd_ifinfo || i >= nd_ifinfo_indexlim) {
+ error = EINVAL;
+ break;
+ }
ndi->ndi = nd_ifinfo[ifp->if_index];
break;
- case SIOCSNDFLUSH_IN6:
+ case SIOCSIFINFO_FLAGS:
+ /* XXX: almost all other fields of ndi->ndi is unused */
+ if (!nd_ifinfo || i >= nd_ifinfo_indexlim) {
+ error = EINVAL;
+ break;
+ }
+ nd_ifinfo[ifp->if_index].flags = ndi->ndi.flags;
+ break;
+ case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */
/* flush default router list */
/*
* xxx sumikawa: should not delete route if default
@@ -1059,6 +1429,7 @@ nd6_ioctl(cmd, data, ifp)
*/
bzero(&any, sizeof(any));
defrouter_delreq(&any, 0);
+ defrouter_select();
/* xxx sumikawa: flush prefix list */
break;
case SIOCSPFXFLUSH_IN6:
@@ -1067,8 +1438,8 @@ nd6_ioctl(cmd, data, ifp)
struct nd_prefix *pr, *next;
s = splnet();
- for (pr = LIST_FIRST(&nd_prefix); pr; pr = next) {
- next = LIST_NEXT(pr, ndpr_entry);
+ 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);
@@ -1082,16 +1453,16 @@ nd6_ioctl(cmd, data, ifp)
struct nd_defrouter *dr, *next;
s = splnet();
- if ((dr = LIST_FIRST(&nd_defrouter)) != NULL) {
+ if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) {
/*
* The first entry of the list may be stored in
* the routing table, so we'll delete it later.
*/
- for (dr = LIST_NEXT(dr, dr_entry); dr; dr = next) {
- next = LIST_NEXT(dr, dr_entry);
+ for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = next) {
+ next = TAILQ_NEXT(dr, dr_entry);
defrtrlist_del(dr);
}
- defrtrlist_del(LIST_FIRST(&nd_defrouter));
+ defrtrlist_del(TAILQ_FIRST(&nd_defrouter));
}
splx(s);
break;
@@ -1116,6 +1487,7 @@ nd6_ioctl(cmd, data, ifp)
s = splnet();
if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL) {
error = EINVAL;
+ splx(s);
break;
}
ln = (struct llinfo_nd6 *)rt->rt_llinfo;
@@ -1127,6 +1499,12 @@ nd6_ioctl(cmd, data, ifp)
break;
}
+ case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */
+ ndif->ifindex = nd6_defifindex;
+ break;
+ case SIOCSDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */
+ return(nd6_setdefaultiface(ndif->ifindex));
+ break;
}
return(error);
}
@@ -1174,6 +1552,12 @@ nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code)
rt = nd6_lookup(from, 0, ifp);
if (!rt) {
+#if 0
+ /* nothing must be done if there's no lladdr */
+ if (!lladdr || !lladdrlen)
+ return NULL;
+#endif
+
rt = nd6_lookup(from, 1, ifp);
is_newentry = 1;
} else
@@ -1248,9 +1632,18 @@ fail:
if (ln->ln_state == ND6_LLINFO_STALE) {
rt->rt_flags &= ~RTF_REJECT;
if (ln->ln_hold) {
- nd6_output(ifp, 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;
}
} else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
@@ -1301,7 +1694,6 @@ fail:
* If the icmp is a redirect to a better router, always set the
* is_router flag. Otherwise, if the entry is newly created,
* clear the flag. [RFC 2461, sec 8.3]
- *
*/
if (code == ND_REDIRECT_ROUTER)
ln->ln_router = 1;
@@ -1338,6 +1730,8 @@ nd6_slowtimo(ignored_arg)
timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz);
for (i = 1; i < if_index + 1; i++) {
+ if (!nd_ifinfo || i >= nd_ifinfo_indexlim)
+ continue;
nd6if = &nd_ifinfo[i];
if (nd6if->basereachable && /* already initialized */
(nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) {
@@ -1356,14 +1750,16 @@ nd6_slowtimo(ignored_arg)
#define senderr(e) { error = (e); goto bad;}
int
-nd6_output(ifp, m0, dst, rt0)
+nd6_output(ifp, origifp, m0, dst, rt0)
register 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 sockaddr_in6 *gw6 = NULL;
struct llinfo_nd6 *ln = NULL;
int error = 0;
@@ -1372,12 +1768,16 @@ nd6_output(ifp, m0, dst, rt0)
/*
* XXX: we currently do not make neighbor cache on any interface
- * other than ARCnet, Ethernet and FDDI.
+ * 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:
goto sendpkt;
@@ -1392,12 +1792,43 @@ nd6_output(ifp, m0, dst, rt0)
NULL)
{
rt->rt_refcnt--;
- if (rt->rt_ifp != ifp)
- return nd6_output(ifp, m0, dst, rt); /* XXX: loop care? */
+ if (rt->rt_ifp != ifp) {
+ /* XXX: loop care? */
+ return nd6_output(ifp, origifp, m0,
+ dst, rt);
+ }
} else
senderr(EHOSTUNREACH);
}
+
if (rt->rt_flags & RTF_GATEWAY) {
+ gw6 = (struct sockaddr_in6 *)rt->rt_gateway;
+
+ /*
+ * We skip link-layer address resolution and NUD
+ * if the gateway is not a neighbor from ND point
+ * of view, regardless the value of the value of
+ * nd_ifinfo.flags.
+ * The second condition is a bit tricky: we skip
+ * if the gateway is our own address, which is
+ * sometimes used to install a route to a p2p link.
+ */
+ if (!nd6_is_addr_neighbor(gw6, ifp) ||
+ in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) {
+ if (rt->rt_flags & RTF_REJECT)
+ senderr(EHOSTDOWN);
+
+ /*
+ * We allow this kind of tricky route only
+ * when the outgoing interface is p2p.
+ * XXX: we may need a more generic rule here.
+ */
+ if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+ senderr(EHOSTUNREACH);
+
+ goto sendpkt;
+ }
+
if (rt->rt_gwroute == 0)
goto lookup;
if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
@@ -1422,16 +1853,32 @@ nd6_output(ifp, m0, dst, rt0)
if (rt && (rt->rt_flags & RTF_LLINFO) != 0)
ln = (struct llinfo_nd6 *)rt->rt_llinfo;
else {
- if ((rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL)
+ /*
+ * Since nd6_is_addr_neighbor() internally calls nd6_lookup(),
+ * the condition below is not very efficient. But we believe
+ * it is tolerable, because this should be a rare case.
+ */
+ if (nd6_is_addr_neighbor(dst, ifp) &&
+ (rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL)
ln = (struct llinfo_nd6 *)rt->rt_llinfo;
}
if (!ln || !rt) {
- log(LOG_DEBUG, "nd6_output: can't allocate llinfo for %s "
- "(ln=%p, rt=%p)\n",
- ip6_sprintf(&dst->sin6_addr), ln, rt);
- senderr(EIO); /* XXX: good error? */
+ if ((ifp->if_flags & IFF_POINTOPOINT) == 0 &&
+ !(nd_ifinfo[ifp->if_index].flags & ND6_IFF_PERFORMNUD)) {
+ log(LOG_DEBUG,
+ "nd6_output: can't allocate llinfo for %s "
+ "(ln=%p, rt=%p)\n",
+ ip6_sprintf(&dst->sin6_addr), ln, rt);
+ senderr(EIO); /* XXX: good error? */
+ }
+
+ goto sendpkt; /* send anyway */
}
+ /* We don't have to do link-layer address resolution on a p2p link. */
+ if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
+ ln->ln_state < ND6_LLINFO_REACHABLE)
+ ln->ln_state = ND6_LLINFO_STALE;
/*
* The first time we send a packet to a neighbor whose entry is
@@ -1481,8 +1928,15 @@ nd6_output(ifp, m0, dst, rt0)
return(0);
sendpkt:
+
+#ifdef FAKE_LOOPBACK_IF
+ if (ifp->if_flags & IFF_LOOPBACK) {
+ return((*ifp->if_output)(origifp, m, (struct sockaddr *)dst,
+ rt));
+ }
+#endif
return((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt));
-
+
bad:
if (m)
m_freem(m);
@@ -1522,8 +1976,12 @@ nd6_storelladdr(ifp, rt, m, dst, desten)
return(0);
}
sdl = SDL(rt->rt_gateway);
- if (sdl->sdl_alen != 0)
- bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
+ if (sdl->sdl_alen == 0) {
+ /* this should be impossible, but we bark here for debugging */
+ printf("nd6_storelladdr: sdl_alen == 0\n");
+ return(0);
+ }
+ bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
return(1);
}
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index 756f49585a3c..be1264d6d8d0 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: nd6.h,v 1.23 2000/06/04 12:54:57 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,12 +28,15 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _NETINET6_ND6_H_
-#define _NETINET6_ND6_H_
+#define _NETINET6_ND6_H_
+
+/* see net/route.h, or net/if_inarp.h */
+#ifndef RTF_ANNOUNCE
+#define RTF_ANNOUNCE RTF_PROTO2
+#endif
#include <sys/queue.h>
@@ -43,128 +49,147 @@ struct llinfo_nd6 {
u_long ln_expire; /* lifetime for NDP state transition */
short ln_state; /* reachability state */
short ln_router; /* 2^0: ND6 router bit */
+ int ln_byhint; /* # of times we made it reachable by UL hint */
};
-#define ND6_LLINFO_NOSTATE -2
-#define ND6_LLINFO_WAITDELETE -1
-#define ND6_LLINFO_INCOMPLETE 0
-#define ND6_LLINFO_REACHABLE 1
-#define ND6_LLINFO_STALE 2
-#define ND6_LLINFO_DELAY 3
-#define ND6_LLINFO_PROBE 4
+#define ND6_LLINFO_NOSTATE -2
+#define ND6_LLINFO_WAITDELETE -1
+#define ND6_LLINFO_INCOMPLETE 0
+#define ND6_LLINFO_REACHABLE 1
+#define ND6_LLINFO_STALE 2
+#define ND6_LLINFO_DELAY 3
+#define ND6_LLINFO_PROBE 4
+
+#define ND6_IS_LLINFO_PROBREACH(n) ((n)->ln_state > ND6_LLINFO_INCOMPLETE)
struct nd_ifinfo {
- 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 */
- int recalctm; /* BaseReacable re-calculation timer */
- u_int8_t chlim; /* CurHopLimit */
- u_int8_t receivedra;
+ 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;
};
+#define ND6_IFF_PERFORMNUD 0x1
+
struct in6_nbrinfo {
- char ifname[IFNAMSIZ]; /* if name, e.g. "en0" */
- struct in6_addr addr; /* IPv6 address of the neighbor */
+ char ifname[IFNAMSIZ]; /* if name, e.g. "en0" */
+ struct in6_addr addr; /* IPv6 address of the neighbor */
long asked; /* number of queries already sent for this addr */
int isrouter; /* if it acts as a router */
int state; /* reachability state */
int expire; /* lifetime for NDP state transition */
};
-#define DRLSTSIZ 10
-#define PRLSTSIZ 10
+#define DRLSTSIZ 10
+#define PRLSTSIZ 10
struct in6_drlist {
- char ifname[IFNAMSIZ];
+ char ifname[IFNAMSIZ];
struct {
struct in6_addr rtaddr;
u_char flags;
u_short rtlifetime;
u_long expire;
- u_short if_index;
+ u_short if_index;
} defrouter[DRLSTSIZ];
};
struct in6_prlist {
- char ifname[IFNAMSIZ];
+ char ifname[IFNAMSIZ];
struct {
struct in6_addr prefix;
- struct prf_ra raflags;
+ struct prf_ra raflags;
u_char prefixlen;
+ u_char origin;
u_long vltime;
u_long pltime;
u_long expire;
- u_short if_index;
- u_short advrtrs; /* number of advertisement routers */
+ u_short if_index;
+ u_short advrtrs; /* number of advertisement routers */
struct in6_addr advrtr[DRLSTSIZ]; /* XXX: explicit limit */
} prefix[PRLSTSIZ];
};
struct in6_ndireq {
- char ifname[IFNAMSIZ];
- struct nd_ifinfo ndi;
+ char ifname[IFNAMSIZ];
+ struct nd_ifinfo ndi;
};
+struct in6_ndifreq {
+ char ifname[IFNAMSIZ];
+ u_long ifindex;
+};
+
+
/* protocol constants */
-#define MAX_RTR_SOLICITATION_DELAY 1 /*1sec*/
-#define RTR_SOLICITATION_INTERVAL 4 /*4sec*/
-#define MAX_RTR_SOLICITATIONS 3
+#define MAX_RTR_SOLICITATION_DELAY 1 /*1sec*/
+#define RTR_SOLICITATION_INTERVAL 4 /*4sec*/
+#define MAX_RTR_SOLICITATIONS 3
-#define ND6_INFINITE_LIFETIME 0xffffffff
+#define ND6_INFINITE_LIFETIME 0xffffffff
#ifdef _KERNEL
/* node constants */
-#define MAX_REACHABLE_TIME 3600000 /* msec */
-#define REACHABLE_TIME 30000 /* msec */
-#define RETRANS_TIMER 1000 /* msec */
-#define MIN_RANDOM_FACTOR 512 /* 1024 * 0.5 */
-#define MAX_RANDOM_FACTOR 1536 /* 1024 * 1.5 */
-#define ND_COMPUTE_RTIME(x) \
+#define MAX_REACHABLE_TIME 3600000 /* msec */
+#define REACHABLE_TIME 30000 /* msec */
+#define RETRANS_TIMER 1000 /* msec */
+#define MIN_RANDOM_FACTOR 512 /* 1024 * 0.5 */
+#define MAX_RANDOM_FACTOR 1536 /* 1024 * 1.5 */
+#define ND_COMPUTE_RTIME(x) \
(((MIN_RANDOM_FACTOR * (x >> 10)) + (random() & \
((MAX_RANDOM_FACTOR - MIN_RANDOM_FACTOR) * (x >> 10)))) /1000)
+TAILQ_HEAD(nd_drhead, nd_defrouter);
struct nd_defrouter {
- LIST_ENTRY(nd_defrouter) dr_entry;
+ TAILQ_ENTRY(nd_defrouter) dr_entry;
struct in6_addr rtaddr;
u_char flags;
u_short rtlifetime;
u_long expire;
- struct ifnet *ifp;
+ u_long advint; /* Mobile IPv6 addition (milliseconds) */
+ u_long advint_expire; /* Mobile IPv6 addition */
+ int advints_lost; /* Mobile IPv6 addition */
+ struct ifnet *ifp;
};
struct nd_prefix {
- struct ifnet *ndpr_ifp;
+ struct ifnet *ndpr_ifp;
LIST_ENTRY(nd_prefix) ndpr_entry;
- struct sockaddr_in6 ndpr_prefix; /* prefix */
- struct in6_addr ndpr_mask; /* netmask derived from the prefix */
- struct in6_addr ndpr_addr; /* address that is derived from the prefix */
- u_int32_t ndpr_vltime; /* advertised valid lifetime */
- u_int32_t ndpr_pltime; /* advertised preferred lifetime */
- time_t ndpr_expire; /* expiration time of the prefix */
- time_t ndpr_preferred; /* preferred time of the prefix */
- struct prf_ra ndpr_flags;
+ struct sockaddr_in6 ndpr_prefix; /* prefix */
+ struct in6_addr ndpr_mask; /* netmask derived from the prefix */
+ struct in6_addr ndpr_addr; /* address that is derived from the prefix */
+ u_int32_t ndpr_vltime; /* advertised valid lifetime */
+ u_int32_t ndpr_pltime; /* advertised preferred lifetime */
+ time_t ndpr_expire; /* expiration time of the prefix */
+ time_t ndpr_preferred; /* preferred time of the prefix */
+ struct prf_ra ndpr_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;
+ u_char onlink : 1;
} ndpr_stateflags;
};
-#define ndpr_raf ndpr_flags
-#define ndpr_raf_onlink ndpr_flags.onlink
-#define ndpr_raf_auto ndpr_flags.autonomous
+#define ndpr_next ndpr_entry.le_next
+
+#define ndpr_raf ndpr_flags
+#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
+#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
*/
-#define NDPR_KEEP_EXPIRED (1800 * 2)
+#define NDPR_KEEP_EXPIRED (1800 * 2)
/*
* Message format for use in obtaining information about prefixes
@@ -174,124 +199,136 @@ struct inet6_ndpr_msghdr {
u_short inpm_msglen; /* to skip over non-understood messages */
u_char inpm_version; /* future binary compatability */
u_char inpm_type; /* message type */
- struct in6_addr inpm_prefix;
+ struct in6_addr inpm_prefix;
u_long prm_vltim;
u_long prm_pltime;
u_long prm_expire;
u_long prm_preferred;
- struct in6_prflags prm_flags;
+ struct in6_prflags prm_flags;
u_short prm_index; /* index for associated ifp */
u_char prm_plen; /* length of prefix in bits */
};
-#define prm_raf_onlink prm_flags.prf_ra.onlink
-#define prm_raf_auto prm_flags.prf_ra.autonomous
+#define prm_raf_onlink prm_flags.prf_ra.onlink
+#define prm_raf_auto prm_flags.prf_ra.autonomous
-#define prm_statef_onlink prm_flags.prf_state.onlink
+#define prm_statef_onlink prm_flags.prf_state.onlink
-#define prm_rrf_decrvalid prm_flags.prf_rr.decrvalid
-#define prm_rrf_decrprefd prm_flags.prf_rr.decrprefd
+#define prm_rrf_decrvalid prm_flags.prf_rr.decrvalid
+#define prm_rrf_decrprefd prm_flags.prf_rr.decrprefd
-#define ifpr2ndpr(ifpr) ((struct nd_prefix *)(ifpr))
-#define ndpr2ifpr(ndpr) ((struct ifprefix *)(ndpr))
+#define ifpr2ndpr(ifpr) ((struct nd_prefix *)(ifpr))
+#define ndpr2ifpr(ndpr) ((struct ifprefix *)(ndpr))
struct nd_pfxrouter {
LIST_ENTRY(nd_pfxrouter) pfr_entry;
- struct nd_defrouter *router;
+#define pfr_next pfr_entry.le_next
+ struct nd_defrouter *router;
};
-LIST_HEAD(nd_drhead, nd_defrouter);
LIST_HEAD(nd_prhead, nd_prefix);
/* nd6.c */
-extern int nd6_prune;
-extern int nd6_delay;
-extern int nd6_umaxtries;
-extern int nd6_mmaxtries;
-extern int nd6_useloopback;
-extern int nd6_proxyall;
-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_prune;
+extern int nd6_delay;
+extern int nd6_umaxtries;
+extern int nd6_mmaxtries;
+extern int nd6_useloopback;
+extern int nd6_maxnudhint;
+extern struct llinfo_nd6 llinfo_nd6;
+extern struct nd_ifinfo *nd_ifinfo;
+extern struct nd_drhead nd_defrouter;
+extern struct nd_prhead nd_prefix;
+
+/* nd6_rtr.c */
+extern int nd6_defifindex;
union nd_opts {
- struct nd_opt_hdr *nd_opt_array[9];
+ struct nd_opt_hdr *nd_opt_array[9]; /*max = home agent info*/
struct {
- struct nd_opt_hdr *zero;
- struct nd_opt_hdr *src_lladdr;
- struct nd_opt_hdr *tgt_lladdr;
- struct nd_opt_prefix_info *pi_beg;/* multiple opts, start */
- struct nd_opt_rd_hdr *rh;
- struct nd_opt_mtu *mtu;
- struct nd_opt_hdr *search; /* multiple opts */
- struct nd_opt_hdr *last; /* multiple opts */
- int done;
- struct nd_opt_prefix_info *pi_end;/* multiple opts, end */
+ struct nd_opt_hdr *zero;
+ struct nd_opt_hdr *src_lladdr;
+ struct nd_opt_hdr *tgt_lladdr;
+ struct nd_opt_prefix_info *pi_beg;/* multiple opts, start */
+ struct nd_opt_rd_hdr *rh;
+ struct nd_opt_mtu *mtu;
+ struct nd_opt_hdr *six;
+ struct nd_opt_advint *adv;
+ struct nd_opt_hai *hai;
+ struct nd_opt_hdr *search; /* multiple opts */
+ struct nd_opt_hdr *last; /* multiple opts */
+ int done;
+ struct nd_opt_prefix_info *pi_end;/* multiple opts, end */
} nd_opt_each;
};
-#define nd_opts_src_lladdr nd_opt_each.src_lladdr
-#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr
-#define nd_opts_pi nd_opt_each.pi_beg
-#define nd_opts_pi_end nd_opt_each.pi_end
-#define nd_opts_rh nd_opt_each.rh
-#define nd_opts_mtu nd_opt_each.mtu
-#define nd_opts_search nd_opt_each.search
-#define nd_opts_last nd_opt_each.last
-#define nd_opts_done nd_opt_each.done
+#define nd_opts_src_lladdr nd_opt_each.src_lladdr
+#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr
+#define nd_opts_pi nd_opt_each.pi_beg
+#define nd_opts_pi_end nd_opt_each.pi_end
+#define nd_opts_rh nd_opt_each.rh
+#define nd_opts_mtu nd_opt_each.mtu
+#define nd_opts_adv nd_opt_each.adv
+#define nd_opts_hai nd_opt_each.hai
+#define nd_opts_search nd_opt_each.search
+#define nd_opts_last nd_opt_each.last
+#define nd_opts_done nd_opt_each.done
/* XXX: need nd6_var.h?? */
/* nd6.c */
-void nd6_init __P((void));
-void nd6_ifattach __P((struct ifnet *));
-int nd6_is_addr_neighbor __P((struct in6_addr *, struct ifnet *));
-void nd6_option_init __P((void *, int, union nd_opts *));
-struct nd_opt_hdr *nd6_option __P((union nd_opts *));
-int nd6_options __P((union nd_opts *));
+void nd6_init __P((void));
+void nd6_ifattach __P((struct ifnet *));
+int nd6_is_addr_neighbor __P((struct sockaddr_in6 *, struct ifnet *));
+void nd6_option_init __P((void *, int, union nd_opts *));
+struct nd_opt_hdr *nd6_option __P((union nd_opts *));
+int nd6_options __P((union nd_opts *));
struct rtentry *nd6_lookup __P((struct in6_addr *, int, struct ifnet *));
-void nd6_setmtu __P((struct ifnet *));
-void nd6_timer __P((void *));
-void nd6_free __P((struct rtentry *));
-void nd6_nud_hint __P((struct rtentry *, struct in6_addr *));
-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));
+void nd6_setmtu __P((struct ifnet *));
+void nd6_timer __P((void *));
+void nd6_purge __P((struct ifnet *));
+void 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 mbuf *, struct sockaddr_in6 *,
- struct rtentry *));
-int nd6_storelladdr __P((struct ifnet *, struct rtentry *, struct mbuf *,
- struct sockaddr *, u_char *));
+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 *));
/* 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));
-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));
-caddr_t nd6_ifptomac __P((struct ifnet *));
-void nd6_dad_start __P((struct ifaddr *, int *));
-void nd6_dad_duplicated __P((struct ifaddr *));
+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_ns_input __P((struct mbuf *, int, int));
+void nd6_ns_output __P((struct ifnet *, struct in6_addr *,
+ 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_duplicated __P((struct ifaddr *));
/* nd6_rtr.c */
-void nd6_rs_input __P((struct mbuf *, int, int));
-void nd6_ra_input __P((struct mbuf *, int, int));
-void prelist_del __P((struct nd_prefix *));
-void defrouter_addreq __P((struct nd_defrouter *));
-void defrouter_delreq __P((struct nd_defrouter *, int));
-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 nd_defrouter *defrouter_lookup __P((struct in6_addr *,
- struct ifnet *));
-int in6_ifdel __P((struct ifnet *, struct in6_addr *));
-int in6_init_prefix_ltimes __P((struct nd_prefix *ndpr));
-void rt6_flush __P((struct in6_addr *, struct ifnet *));
+void nd6_rs_input __P((struct mbuf *, int, int));
+void nd6_ra_input __P((struct mbuf *, int, int));
+void prelist_del __P((struct nd_prefix *));
+void defrouter_addreq __P((struct nd_defrouter *));
+void defrouter_delreq __P((struct nd_defrouter *, int));
+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 *));
+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 *));
+int in6_init_prefix_ltimes __P((struct nd_prefix *ndpr));
+void rt6_flush __P((struct in6_addr *, struct ifnet *));
+int nd6_setdefaultiface __P((int));
#endif /* _KERNEL */
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index 58f0a52dd6d0..d3fa831fa695 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: nd6_nbr.c,v 1.37 2000/06/04 12:46:13 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,10 +28,10 @@
* 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.
- *
- * $FreeBSD$
*/
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_ipsec.h"
#include <sys/param.h>
@@ -51,31 +54,37 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet6/in6_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#ifdef INET6
+#include <netinet6/ipsec6.h>
+#endif
+#endif
#include <net/net_osdep.h>
-#define SDL(s) ((struct sockaddr_dl *)s)
+#define SDL(s) ((struct sockaddr_dl *)s)
-struct dadq;
-static struct dadq *nd6_dad_find __P((struct ifaddr *));
-static void nd6_dad_timer __P((struct ifaddr *));
-static void nd6_dad_ns_input __P((struct ifaddr *));
-static void nd6_dad_na_input __P((struct ifaddr *));
+struct dadq;
+static struct dadq *nd6_dad_find __P((struct ifaddr *));
+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 *));
+static void nd6_dad_na_input __P((struct ifaddr *));
-/* ignore NS in DAD - specwise incorrect, */
-int dad_ignore_ns = 0;
+static int dad_ignore_ns = 0; /* ignore NS in DAD - specwise incorrect*/
+static int dad_maxtry = 15; /* max # of *tries* to transmit DAD packet */
/*
* Input an Neighbor Solicitation Message.
*
* Based on RFC 2461
* Based on RFC 2462 (duplicated address detection)
- *
- * XXX proxy advertisement
*/
void
nd6_ns_input(m, off, icmp6len)
@@ -84,11 +93,10 @@ nd6_ns_input(m, off, icmp6len)
{
struct ifnet *ifp = m->m_pkthdr.rcvif;
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
- struct nd_neighbor_solicit *nd_ns
- = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
+ struct nd_neighbor_solicit *nd_ns;
struct in6_addr saddr6 = ip6->ip6_src;
struct in6_addr daddr6 = ip6->ip6_dst;
- struct in6_addr taddr6 = nd_ns->nd_ns_target;
+ struct in6_addr taddr6;
struct in6_addr myaddr6;
char *lladdr = NULL;
struct ifaddr *ifa;
@@ -96,11 +104,12 @@ nd6_ns_input(m, off, icmp6len)
int anycast = 0, proxy = 0, tentative = 0;
int tlladdr;
union nd_opts ndopts;
+ struct sockaddr_dl *proxydl = NULL;
if (ip6->ip6_hlim != 255) {
log(LOG_ERR,
"nd6_ns_input: invalid hlim %d\n", ip6->ip6_hlim);
- return;
+ goto freeit;
}
if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
@@ -118,6 +127,18 @@ nd6_ns_input(m, off, icmp6len)
}
}
+#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");
goto bad;
@@ -154,6 +175,12 @@ nd6_ns_input(m, off, icmp6len)
* In implementation, we add target link-layer address by default.
* We do not add one in MUST NOT cases.
*/
+#if 0 /* too much! */
+ ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &daddr6);
+ if (ifa && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST))
+ tlladdr = 0;
+ else
+#endif
if (!IN6_IS_ADDR_MULTICAST(&daddr6))
tlladdr = 0;
else
@@ -169,7 +196,7 @@ nd6_ns_input(m, off, icmp6len)
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
/* (2) check. */
- if (!ifa && nd6_proxyall) {
+ if (!ifa) {
struct rtentry *rt;
struct sockaddr_in6 tsin6;
@@ -179,16 +206,20 @@ nd6_ns_input(m, off, icmp6len)
tsin6.sin6_addr = taddr6;
rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0);
- if (rt && rt->rt_ifp != ifp) {
+ if (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
+ rt->rt_gateway->sa_family == AF_LINK) {
/*
- * search link local addr for ifp, and use it for
- * proxy NA.
+ * proxy NDP for single entry
*/
- ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp);
- if (ifa)
+ ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
+ IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
+ if (ifa) {
proxy = 1;
+ proxydl = SDL(rt->rt_gateway);
+ }
}
- rtfree(rt);
+ if (rt)
+ rtfree(rt);
}
if (!ifa) {
/*
@@ -196,13 +227,13 @@ nd6_ns_input(m, off, icmp6len)
* assigned for us. We MUST silently ignore it.
* See RFC2461 7.2.3.
*/
- return;
+ goto freeit;
}
myaddr6 = *IFA_IN6(ifa);
anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
- return;
+ goto freeit;
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
log(LOG_INFO,
@@ -215,7 +246,7 @@ nd6_ns_input(m, off, icmp6len)
log(LOG_INFO,
"nd6_ns_input: duplicate IP6 address %s\n",
ip6_sprintf(&saddr6));
- return;
+ goto freeit;
}
/*
@@ -241,7 +272,7 @@ nd6_ns_input(m, off, icmp6len)
if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
nd6_dad_ns_input(ifa);
- return;
+ goto freeit;
}
/*
@@ -259,8 +290,8 @@ nd6_ns_input(m, off, icmp6len)
((anycast || proxy || !tlladdr)
? 0 : ND_NA_FLAG_OVERRIDE)
| (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
- tlladdr);
- return;
+ tlladdr, (struct sockaddr *)proxydl);
+ goto freeit;
}
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, 0);
@@ -269,14 +300,16 @@ nd6_ns_input(m, off, icmp6len)
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE)
| (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0)
| ND_NA_FLAG_SOLICITED,
- tlladdr);
+ tlladdr, (struct sockaddr *)proxydl);
+ freeit:
+ m_freem(m);
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));
- return;
+ m_freem(m);
}
/*
@@ -301,13 +334,33 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
struct in6_ifaddr *ia = NULL;
struct ip6_moptions im6o;
int icmp6len;
+ int maxlen;
caddr_t mac;
struct ifnet *outif = NULL;
if (IN6_IS_ADDR_MULTICAST(taddr6))
return;
- if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
+ /* estimate the size of message */
+ maxlen = sizeof(*ip6) + sizeof(*nd_ns);
+ maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
+ if (max_linkhdr + maxlen >= MCLBYTES) {
+#ifdef DIAGNOSTIC
+ printf("nd6_ns_output: max_linkhdr + maxlen >= MCLBYTES "
+ "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
+#endif
+ return;
+ }
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m && max_linkhdr + maxlen >= MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_free(m);
+ m = NULL;
+ }
+ }
+ if (m == NULL)
return;
if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) {
@@ -319,12 +372,13 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
icmp6len = sizeof(*nd_ns);
m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len;
- MH_ALIGN(m, m->m_len + 16); /* 1+1+6 is enought. but just in case */
+ m->m_data += max_linkhdr; /*or MH_ALIGN() equivalent?*/
/* fill neighbor solicitation packet */
ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_flow = 0;
- ip6->ip6_vfc = IPV6_VERSION;
+ ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
+ ip6->ip6_vfc |= IPV6_VERSION;
/* ip6->ip6_plen will be set later */
ip6->ip6_nxt = IPPROTO_ICMPV6;
ip6->ip6_hlim = 255;
@@ -339,7 +393,20 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
ip6->ip6_dst.s6_addr8[12] = 0xff;
}
if (!dad) {
- /* spec-wise correct, scope match */
+#if 0 /* KAME way, exact address scope match */
+ /*
+ * Select a source whose scope is the same as that of the dest.
+ * Typically, the dest is link-local solicitation multicast
+ * (i.e. neighbor discovery) or link-local/global unicast
+ * (i.e. neighbor un-reachability detection).
+ */
+ ia = in6_ifawithifp(ifp, &ip6->ip6_dst);
+ if (ia == NULL) {
+ m_freem(m);
+ return;
+ }
+ ip6->ip6_src = ia->ia_addr.sin6_addr;
+#else /* spec-wise correct */
/*
* RFC2461 7.2.2:
* "If the source address of the packet prompting the
@@ -377,6 +444,7 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
}
ip6->ip6_src = ia->ia_addr.sin6_addr;
}
+#endif
} else {
/*
* Source address for DAD packet must always be IPv6
@@ -425,6 +493,10 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
nd_ns->nd_ns_cksum
= in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
+#ifdef IPSEC
+ /* Don't lookup socket */
+ ipsec_setsocket(m, NULL);
+#endif
ip6_output(m, NULL, NULL, dad ? IPV6_DADOUTPUT : 0, &im6o, &outif);
if (outif) {
icmp6_ifstat_inc(outif, ifs6_out_msg);
@@ -438,6 +510,10 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
*
* Based on RFC 2461
* Based on RFC 2462 (duplicated address detection)
+ *
+ * the following items are not implemented yet:
+ * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
+ * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
*/
void
nd6_na_input(m, off, icmp6len)
@@ -446,14 +522,16 @@ nd6_na_input(m, off, icmp6len)
{
struct ifnet *ifp = m->m_pkthdr.rcvif;
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
- struct nd_neighbor_advert *nd_na
- = (struct nd_neighbor_advert *)((caddr_t)ip6 + off);
+ struct nd_neighbor_advert *nd_na;
+#if 0
+ struct in6_addr saddr6 = ip6->ip6_src;
+#endif
struct in6_addr daddr6 = ip6->ip6_dst;
- struct in6_addr taddr6 = nd_na->nd_na_target;
- int flags = nd_na->nd_na_flags_reserved;
- int is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
- int is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
- int is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
+ struct in6_addr taddr6;
+ int flags;
+ int is_router;
+ int is_solicited;
+ int is_override;
char *lladdr = NULL;
int lladdrlen = 0;
struct ifaddr *ifa;
@@ -465,8 +543,24 @@ nd6_na_input(m, off, icmp6len)
if (ip6->ip6_hlim != 255) {
log(LOG_ERR,
"nd6_na_input: invalid hlim %d\n", ip6->ip6_hlim);
+ goto freeit;
+ }
+
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, off, icmp6len,);
+ nd_na = (struct nd_neighbor_advert *)((caddr_t)ip6 + off);
+#else
+ IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len);
+ if (nd_na == NULL) {
+ icmp6stat.icp6s_tooshort++;
return;
}
+#endif
+ taddr6 = nd_na->nd_na_target;
+ flags = nd_na->nd_na_flags_reserved;
+ is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
+ is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
+ is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
if (IN6_IS_SCOPE_LINKLOCAL(&taddr6))
taddr6.s6_addr16[1] = htons(ifp->if_index);
@@ -475,20 +569,20 @@ nd6_na_input(m, off, icmp6len)
log(LOG_ERR,
"nd6_na_input: invalid target address %s\n",
ip6_sprintf(&taddr6));
- return;
+ goto freeit;
}
if (IN6_IS_ADDR_MULTICAST(&daddr6))
if (is_solicited) {
log(LOG_ERR,
"nd6_na_input: a solicited adv is multicasted\n");
- return;
+ goto freeit;
}
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");
- return;
+ goto freeit;
}
if (ndopts.nd_opts_tgt_lladdr) {
@@ -510,7 +604,7 @@ nd6_na_input(m, off, icmp6len)
if (ifa
&& (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
nd6_dad_na_input(ifa);
- return;
+ goto freeit;
}
/* Just for safety, maybe unnecessery. */
@@ -518,7 +612,7 @@ nd6_na_input(m, off, icmp6len)
log(LOG_ERR,
"nd6_na_input: duplicate IP6 address %s\n",
ip6_sprintf(&taddr6));
- return;
+ goto freeit;
}
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
@@ -535,7 +629,7 @@ nd6_na_input(m, off, icmp6len)
if ((rt == NULL) ||
((ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) ||
((sdl = SDL(rt->rt_gateway)) == NULL))
- return;
+ goto freeit;
if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
/*
@@ -543,7 +637,7 @@ nd6_na_input(m, off, icmp6len)
* discard the packet.
*/
if (ifp->if_addrlen && !lladdr)
- return;
+ goto freeit;
/*
* Record link-layer address, and update the state.
@@ -552,6 +646,7 @@ nd6_na_input(m, off, icmp6len)
bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
if (is_solicited) {
ln->ln_state = ND6_LLINFO_REACHABLE;
+ ln->ln_byhint = 0;
if (ln->ln_expire)
ln->ln_expire = time_second +
nd_ifinfo[rt->rt_ifp->if_index].reachable;
@@ -602,7 +697,7 @@ nd6_na_input(m, off, icmp6len)
*/
if (ln->ln_state == ND6_LLINFO_REACHABLE)
ln->ln_state = ND6_LLINFO_STALE;
- return;
+ goto freeit;
} else if (is_override /* (2a) */
|| (!is_override && (lladdr && !llchange)) /* (2b) */
|| !lladdr) { /* (2c) */
@@ -621,6 +716,7 @@ nd6_na_input(m, off, icmp6len)
*/
if (is_solicited) {
ln->ln_state = ND6_LLINFO_REACHABLE;
+ ln->ln_byhint = 0;
if (ln->ln_expire) {
ln->ln_expire = time_second +
nd_ifinfo[ifp->if_index].reachable;
@@ -663,10 +759,21 @@ nd6_na_input(m, off, icmp6len)
rt->rt_flags &= ~RTF_REJECT;
ln->ln_asked = 0;
if (ln->ln_hold) {
- nd6_output(ifp, 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);
}
/*
@@ -674,16 +781,17 @@ nd6_na_input(m, off, icmp6len)
*
* Based on RFC 2461
*
- * XXX NA delay for anycast address is not implemented yet
- * (RFC 2461 7.2.7)
- * XXX proxy advertisement?
+ * the following items are not implemented yet:
+ * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
+ * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
*/
void
-nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr)
+nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
struct ifnet *ifp;
struct in6_addr *daddr6, *taddr6;
u_long flags;
- int tlladdr; /* 1 if include target link-layer address */
+ int tlladdr; /* 1 if include target link-layer address */
+ struct sockaddr *sdl0; /* sockaddr_dl (= proxy NA) or NULL */
{
struct mbuf *m;
struct ip6_hdr *ip6;
@@ -691,10 +799,30 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr)
struct in6_ifaddr *ia = NULL;
struct ip6_moptions im6o;
int icmp6len;
+ int maxlen;
caddr_t mac;
- struct ifnet *outif;
-
- if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
+ struct ifnet *outif = NULL;
+
+ /* estimate the size of message */
+ maxlen = sizeof(*ip6) + sizeof(*nd_na);
+ maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
+ if (max_linkhdr + maxlen >= MCLBYTES) {
+#ifdef DIAGNOSTIC
+ printf("nd6_na_output: max_linkhdr + maxlen >= MCLBYTES "
+ "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
+#endif
+ return;
+ }
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m && max_linkhdr + maxlen >= MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_free(m);
+ m = NULL;
+ }
+ }
+ if (m == NULL)
return;
if (IN6_IS_ADDR_MULTICAST(daddr6)) {
@@ -706,12 +834,13 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr)
icmp6len = sizeof(*nd_na);
m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len;
- MH_ALIGN(m, m->m_len + 16); /* 1+1+6 is enough. but just in case */
+ m->m_data += max_linkhdr; /*or MH_ALIGN() equivalent?*/
/* fill neighbor advertisement packet */
ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_flow = 0;
- ip6->ip6_vfc = IPV6_VERSION;
+ ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
+ ip6->ip6_vfc |= IPV6_VERSION;
ip6->ip6_nxt = IPPROTO_ICMPV6;
ip6->ip6_hlim = 255;
if (IN6_IS_ADDR_UNSPECIFIED(daddr6)) {
@@ -747,7 +876,23 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr)
* Basically, if NS packet is sent to unicast/anycast addr,
* target lladdr option SHOULD NOT be included.
*/
- if (tlladdr && (mac = nd6_ifptomac(ifp))) {
+ if (tlladdr) {
+ mac = NULL;
+ /*
+ * sdl0 != NULL indicates proxy NA. If we do proxy, use
+ * lladdr in sdl0. If we are not proxying (sending NA for
+ * my address) use lladdr configured for the interface.
+ */
+ if (sdl0 == NULL)
+ mac = nd6_ifptomac(ifp);
+ else if (sdl0->sa_family == AF_LINK) {
+ struct sockaddr_dl *sdl;
+ sdl = (struct sockaddr_dl *)sdl0;
+ if (sdl->sdl_alen == ifp->if_addrlen)
+ mac = LLADDR(sdl);
+ }
+ }
+ if (tlladdr && mac) {
int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1);
@@ -771,8 +916,9 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr)
in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);
#ifdef IPSEC
- m->m_pkthdr.rcvif = NULL;
-#endif /*IPSEC*/
+ /* Don't lookup socket */
+ ipsec_setsocket(m, NULL);
+#endif
ip6_output(m, NULL, NULL, 0, &im6o, &outif);
if (outif) {
icmp6_ifstat_inc(outif, ifs6_out_msg);
@@ -801,6 +947,7 @@ struct dadq {
TAILQ_ENTRY(dadq) dad_list;
struct ifaddr *dad_ifa;
int dad_count; /* max NS to send */
+ int dad_ns_tcount; /* # of trials to send NS */
int dad_ns_ocount; /* NS sent so far */
int dad_ns_icount;
int dad_na_icount;
@@ -815,7 +962,7 @@ nd6_dad_find(ifa)
{
struct dadq *dp;
- TAILQ_FOREACH(dp, &dadq, dad_list) {
+ for (dp = dadq.tqh_first; dp; dp = dp->dad_list.tqe_next) {
if (dp->dad_ifa == ifa)
return dp;
}
@@ -846,7 +993,8 @@ nd6_dad_start(ifa, tick)
* - the interface address is anycast
*/
if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) {
- printf("nd6_dad_start: called with non-tentative address "
+ log(LOG_DEBUG,
+ "nd6_dad_start: called with non-tentative address "
"%s(%s)\n",
ip6_sprintf(&ia->ia_addr.sin6_addr),
ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
@@ -871,7 +1019,7 @@ nd6_dad_start(ifa, tick)
dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT);
if (dp == NULL) {
- printf("nd6_dad_start: memory allocation failed for "
+ log(LOG_ERR, "nd6_dad_start: memory allocation failed for "
"%s(%s)\n",
ip6_sprintf(&ia->ia_addr.sin6_addr),
ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
@@ -881,7 +1029,7 @@ nd6_dad_start(ifa, tick)
TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);
#ifdef ND6_DEBUG
- printf("%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
+ log(LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
ip6_sprintf(&ia->ia_addr.sin6_addr));
#endif
@@ -895,11 +1043,9 @@ nd6_dad_start(ifa, tick)
ifa->ifa_refcnt++; /*just for safety*/
dp->dad_count = ip6_dad_count;
dp->dad_ns_icount = dp->dad_na_icount = 0;
- dp->dad_ns_ocount = 0;
+ dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
if (!tick) {
- dp->dad_ns_ocount++;
- nd6_ns_output(ifa->ifa_ifp, NULL, &ia->ia_addr.sin6_addr,
- NULL, 1);
+ 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);
@@ -929,37 +1075,47 @@ nd6_dad_timer(ifa)
/* Sanity check */
if (ia == NULL) {
- printf("nd6_dad_timer: called with null parameter\n");
+ log(LOG_ERR, "nd6_dad_timer: called with null parameter\n");
goto done;
}
dp = nd6_dad_find(ifa);
if (dp == NULL) {
- printf("nd6_dad_timer: DAD structure not found\n");
+ log(LOG_ERR, "nd6_dad_timer: DAD structure not found\n");
goto done;
}
if (ia->ia6_flags & IN6_IFF_DUPLICATED) {
- printf("nd6_dad_timer: called with duplicated address "
+ log(LOG_ERR, "nd6_dad_timer: called with duplicated address "
"%s(%s)\n",
ip6_sprintf(&ia->ia_addr.sin6_addr),
ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
goto done;
}
if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) {
- printf("nd6_dad_timer: called with non-tentative address "
+ log(LOG_ERR, "nd6_dad_timer: called with non-tentative address "
"%s(%s)\n",
ip6_sprintf(&ia->ia_addr.sin6_addr),
ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
goto done;
}
+ /* 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));
+
+ TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
+ free(dp, M_IP6NDP);
+ dp = NULL;
+ IFAFREE(ifa);
+ goto done;
+ }
+
/* Need more checks? */
if (dp->dad_ns_ocount < dp->dad_count) {
/*
* We have more NS to go. Send NS packet for DAD.
*/
- dp->dad_ns_ocount++;
- nd6_ns_output(ifa->ifa_ifp, NULL, &ia->ia_addr.sin6_addr,
- NULL, 1);
+ 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);
@@ -981,8 +1137,33 @@ nd6_dad_timer(ifa)
}
if (dp->dad_ns_icount) {
+#if 0 /*heuristics*/
+ /*
+ * if
+ * - we have sent many(?) DAD NS, and
+ * - the number of NS we sent equals to the
+ * number of NS we've got, and
+ * - we've got no NA
+ * we may have a faulty network card/driver which
+ * loops back multicasts to myself.
+ */
+ if (3 < dp->dad_count
+ && dp->dad_ns_icount == dp->dad_count
+ && dp->dad_na_icount == 0) {
+ log(LOG_INFO, "DAD questionable for %s(%s): "
+ "network card loops back multicast?\n",
+ ip6_sprintf(&ia->ia_addr.sin6_addr),
+ if_name(ifa->ifa_ifp));
+ /* XXX consider it a duplicate or not? */
+ /* duplicate++; */
+ } else {
+ /* We've seen NS, means DAD has failed. */
+ duplicate++;
+ }
+#else
/* We've seen NS, means DAD has failed. */
duplicate++;
+#endif
}
if (duplicate) {
@@ -997,15 +1178,16 @@ nd6_dad_timer(ifa)
ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
#ifdef ND6_DEBUG
- printf("%s: DAD complete for %s - no duplicates "
- "found\n", if_name(ifa->ifa_ifp),
+ log(LOG_INFO,
+ "%s: DAD complete for %s - no duplicates found\n",
+ if_name(ifa->ifa_ifp),
ip6_sprintf(&ia->ia_addr.sin6_addr));
#endif
TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
free(dp, M_IP6NDP);
dp = NULL;
- ifa->ifa_refcnt--;
+ IFAFREE(ifa);
}
}
@@ -1022,7 +1204,7 @@ nd6_dad_duplicated(ifa)
dp = nd6_dad_find(ifa);
if (dp == NULL) {
- printf("nd6_dad_duplicated: DAD structure not found\n");
+ log(LOG_ERR, "nd6_dad_duplicated: DAD structure not found\n");
return;
}
@@ -1036,19 +1218,47 @@ nd6_dad_duplicated(ifa)
/* We are done with DAD, with duplicated address found. (failure) */
untimeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa
- , dp->dad_timer);
+ , dp->dad_timer
+ );
- printf("%s: DAD complete for %s - duplicate found\n",
+ log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n",
if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr));
- printf("%s: manual intervention required\n", if_name(ifa->ifa_ifp));
+ log(LOG_ERR, "%s: manual intervention required\n",
+ if_name(ifa->ifa_ifp));
TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
free(dp, M_IP6NDP);
dp = NULL;
- ifa->ifa_refcnt--;
+ IFAFREE(ifa);
}
-void
+static void
+nd6_dad_ns_output(dp, ifa)
+ struct dadq *dp;
+ struct ifaddr *ifa;
+{
+ struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
+ struct ifnet *ifp = ifa->ifa_ifp;
+
+ dp->dad_ns_tcount++;
+ if ((ifp->if_flags & IFF_UP) == 0) {
+#if 0
+ printf("%s: interface down?\n", if_name(ifp));
+#endif
+ return;
+ }
+ if ((ifp->if_flags & IFF_RUNNING) == 0) {
+#if 0
+ printf("%s: interface not running?\n", if_name(ifp));
+#endif
+ return;
+ }
+
+ dp->dad_ns_ocount++;
+ nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1);
+}
+
+static void
nd6_dad_ns_input(ifa)
struct ifaddr *ifa;
{
@@ -1103,7 +1313,7 @@ nd6_dad_ns_input(ifa)
}
}
-void
+static void
nd6_dad_na_input(ifa)
struct ifaddr *ifa;
{
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
index 2501a2d6bcc3..f4033710da6b 100644
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: nd6_rtr.c,v 1.43 2000/07/02 23:19:59 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,10 +28,11 @@
* 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.
- *
- * $FreeBSD$
*/
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -47,34 +51,44 @@
#include <netinet/in.h>
#include <netinet6/in6_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
+#include <netinet6/scope6_var.h>
#include <net/net_osdep.h>
-#define SDL(s) ((struct sockaddr_dl *)s)
+#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 nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
+ 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 *));
+static void defrouter_addifreq __P((struct ifnet *));
+#ifdef ND6_USE_RTSOCK
+static void defrouter_msg __P((int, struct rtentry *));
+#endif
-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 nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
- struct nd_defrouter *));
-static void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *));
-static void pfxrtr_del __P((struct nd_pfxrouter *));
-static void pfxlist_onlink_check __P((void));
-static void nd6_detach_prefix __P((struct nd_prefix *));
-static void nd6_attach_prefix __P((struct nd_prefix *));
+static void in6_init_address_ltimes __P((struct nd_prefix *ndpr,
+ struct in6_addrlifetime *lt6,
+ int update_vltime));
-static void in6_init_address_ltimes __P((struct nd_prefix *ndpr,
- struct in6_addrlifetime *lt6));
+static int rt6_deleteroute __P((struct radix_node *, void *));
-static int rt6_deleteroute __P((struct radix_node *, void *));
+extern int nd6_recalc_reachtm_interval;
-extern int nd6_recalc_reachtm_interval;
+struct ifnet *nd6_defifp;
+int nd6_defifindex;
/*
* Receive Router Solicitation Message - just for routers.
@@ -90,22 +104,30 @@ nd6_rs_input(m, off, icmp6len)
{
struct ifnet *ifp = m->m_pkthdr.rcvif;
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
- struct nd_router_solicit *nd_rs
- = (struct nd_router_solicit *)((caddr_t)ip6 + off);
+ struct nd_router_solicit *nd_rs;
struct in6_addr saddr6 = ip6->ip6_src;
+#if 0
+ struct in6_addr daddr6 = ip6->ip6_dst;
+#endif
char *lladdr = NULL;
int lladdrlen = 0;
+#if 0
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)NULL;
+ struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL;
+ struct rtentry *rt = NULL;
+ int is_newentry;
+#endif
union nd_opts ndopts;
/* If I'm not a router, ignore it. */
if (ip6_accept_rtadv != 0 || ip6_forwarding != 1)
- return;
+ goto freeit;
/* Sanity checks */
if (ip6->ip6_hlim != 255) {
log(LOG_ERR,
"nd6_rs_input: invalid hlim %d\n", ip6->ip6_hlim);
- return;
+ goto freeit;
}
/*
@@ -113,13 +135,24 @@ nd6_rs_input(m, off, icmp6len)
* This indicates that the src has no IP address assigned yet.
*/
if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
+ goto freeit;
+
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, off, icmp6len,);
+ nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off);
+#else
+ IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len);
+ if (nd_rs == NULL) {
+ icmp6stat.icp6s_tooshort++;
return;
+ }
+#endif
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");
- return;
+ goto freeit;
}
if (ndopts.nd_opts_src_lladdr) {
@@ -135,6 +168,9 @@ nd6_rs_input(m, off, icmp6len)
}
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
+
+ freeit:
+ m_freem(m);
}
/*
@@ -152,33 +188,49 @@ nd6_ra_input(m, off, icmp6len)
struct ifnet *ifp = m->m_pkthdr.rcvif;
struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
- struct nd_router_advert *nd_ra =
- (struct nd_router_advert *)((caddr_t)ip6 + off);
+ struct nd_router_advert *nd_ra;
struct in6_addr saddr6 = ip6->ip6_src;
+#if 0
+ struct in6_addr daddr6 = ip6->ip6_dst;
+ int flags; /* = nd_ra->nd_ra_flags_reserved; */
+ int is_managed = ((flags & ND_RA_FLAG_MANAGED) != 0);
+ int is_other = ((flags & ND_RA_FLAG_OTHER) != 0);
+#endif
union nd_opts ndopts;
struct nd_defrouter *dr;
if (ip6_accept_rtadv == 0)
- return;
+ goto freeit;
if (ip6->ip6_hlim != 255) {
log(LOG_ERR,
"nd6_ra_input: invalid hlim %d\n", ip6->ip6_hlim);
- return;
+ goto freeit;
}
if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
log(LOG_ERR,
"nd6_ra_input: src %s is not link-local\n",
ip6_sprintf(&saddr6));
+ goto freeit;
+ }
+
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, off, icmp6len,);
+ nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off);
+#else
+ IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len);
+ if (nd_ra == NULL) {
+ icmp6stat.icp6s_tooshort++;
return;
}
+#endif
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");
- return;
+ goto freeit;
}
{
@@ -190,6 +242,9 @@ nd6_ra_input(m, off, icmp6len)
dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
dr0.expire = time_second + dr0.rtlifetime;
dr0.ifp = ifp;
+ dr0.advint = 0; /* Mobile IPv6 */
+ dr0.advint_expire = 0; /* Mobile IPv6 */
+ dr0.advints_lost = 0; /* Mobile IPv6 */
/* unspecified or not? (RFC 2461 6.3.4) */
if (advreachable) {
NTOHL(advreachable);
@@ -336,17 +391,47 @@ nd6_ra_input(m, off, icmp6len)
}
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0);
+
+ /*
+ * Installing a link-layer address might change the state of the
+ * router's neighbor cache, which might also affect our on-link
+ * detection of adveritsed prefixes.
+ */
+ pfxlist_onlink_check();
}
+
+freeit:
+ m_freem(m);
}
/*
* 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)
+ int cmd;
+ struct rtentry *rt;
+{
+ struct rt_addrinfo info;
+
+ bzero((caddr_t)&info, sizeof(info));
+ info.rti_info[RTAX_DST] = rt_key(rt);
+ info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
+ info.rti_info[RTAX_NETMASK] = rt_mask(rt);
+
+ rt_missmsg(cmd, &info, rt->rt_flags, 0);
+}
+#endif
+
void
defrouter_addreq(new)
struct nd_defrouter *new;
{
struct sockaddr_in6 def, mask, gate;
+ struct rtentry *newrt = NULL;
int s;
Bzero(&def, sizeof(def));
@@ -361,11 +446,68 @@ defrouter_addreq(new)
s = splnet();
(void)rtrequest(RTM_ADD, (struct sockaddr *)&def,
(struct sockaddr *)&gate, (struct sockaddr *)&mask,
- RTF_GATEWAY, NULL);
+ RTF_GATEWAY, &newrt);
+ if (newrt) {
+#ifdef ND6_USE_RTSOCK
+ defrouter_msg(RTM_ADD, newrt); /* tell user process */
+#endif
+ newrt->rt_refcnt--;
+ }
splx(s);
return;
}
+/* Add a route to a given interface as default */
+void
+defrouter_addifreq(ifp)
+ struct ifnet *ifp;
+{
+ struct sockaddr_in6 def, mask;
+ struct ifaddr *ifa;
+ struct rtentry *newrt = NULL;
+ int error, flags;
+
+ bzero(&def, sizeof(def));
+ bzero(&mask, sizeof(mask));
+
+ def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6);
+ def.sin6_family = mask.sin6_family = AF_INET6;
+
+ /*
+ * Search for an ifaddr beloging to the specified interface.
+ * 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? */
+ "defrouter_addifreq: failed to find an ifaddr "
+ "to install a route to interface %s\n",
+ 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,
+ "defrouter_addifreq: failed to install a route to "
+ "interface %s (errno = %d)\n",
+ 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
+ newrt->rt_refcnt--;
+ }
+ }
+}
+
struct nd_defrouter *
defrouter_lookup(addr, ifp)
struct in6_addr *addr;
@@ -373,9 +515,11 @@ defrouter_lookup(addr, ifp)
{
struct nd_defrouter *dr;
- LIST_FOREACH(dr, &nd_defrouter, dr_entry)
+ for (dr = TAILQ_FIRST(&nd_defrouter); dr;
+ dr = TAILQ_NEXT(dr, dr_entry)) {
if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
return(dr);
+ }
return(NULL); /* search failed */
}
@@ -386,6 +530,7 @@ defrouter_delreq(dr, dofree)
int dofree;
{
struct sockaddr_in6 def, mask, gate;
+ struct rtentry *oldrt = NULL;
Bzero(&def, sizeof(def));
Bzero(&mask, sizeof(mask));
@@ -399,18 +544,18 @@ defrouter_delreq(dr, dofree)
rtrequest(RTM_DELETE, (struct sockaddr *)&def,
(struct sockaddr *)&gate,
(struct sockaddr *)&mask,
- RTF_GATEWAY, (struct rtentry **)0);
+ RTF_GATEWAY, &oldrt);
+ if (oldrt) {
+#ifdef ND6_USE_RTSOCK
+ defrouter_msg(RTM_DELETE, oldrt);
+#endif
+ if (oldrt->rt_refcnt <= 0)
+ oldrt->rt_refcnt++; /* XXX */
+ rtfree(oldrt);
+ }
- if (dofree)
+ if (dofree) /* XXX: necessary? */
free(dr, M_IP6NDP);
-
- if (!LIST_EMPTY(&nd_defrouter))
- defrouter_addreq(LIST_FIRST(&nd_defrouter));
-
- /*
- * xxx update the Destination Cache entries for all
- * destinations using that neighbor as a router (7.2.5)
- */
}
void
@@ -429,15 +574,15 @@ defrtrlist_del(dr)
rt6_flush(&dr->rtaddr, dr->ifp);
}
- if (dr == LIST_FIRST(&nd_defrouter))
+ if (dr == TAILQ_FIRST(&nd_defrouter))
deldr = dr; /* The router is primary. */
- LIST_REMOVE(dr, dr_entry);
+ TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
/*
* Also delete all the pointers to the router in each prefix lists.
*/
- LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
+ for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
struct nd_pfxrouter *pfxrtr;
if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
pfxrtr_del(pfxrtr);
@@ -445,14 +590,96 @@ defrtrlist_del(dr)
pfxlist_onlink_check();
/*
- * If the router is the primary one, delete the default route
- * entry in the routing table.
+ * If the router is the primary one, choose a new one.
+ * Note that defrouter_select() will remove the current gateway
+ * from the routing table.
*/
if (deldr)
- defrouter_delreq(deldr, 0);
+ defrouter_select();
+
free(dr, M_IP6NDP);
}
+/*
+ * Default Router Selection according to Section 6.3.6 of RFC 2461:
+ * 1) Routers that are reachable or probably reachable should be
+ * preferred.
+ * 2) When no routers on the list are known to be reachable or
+ * probably reachable, routers SHOULD be selected in a round-robin
+ * fashion.
+ * 3) If the Default Router List is empty, assume that all
+ * destinations are on-link.
+ */
+void
+defrouter_select()
+{
+ int s = splnet();
+ struct nd_defrouter *dr, anydr;
+ struct rtentry *rt = NULL;
+ struct llinfo_nd6 *ln = NULL;
+
+ /*
+ * Search for a (probably) reachable router from the list.
+ */
+ for (dr = TAILQ_FIRST(&nd_defrouter); dr;
+ dr = TAILQ_NEXT(dr, dr_entry)) {
+ if ((rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
+ (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
+ ND6_IS_LLINFO_PROBREACH(ln)) {
+ /* Got it, and move it to the head */
+ TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
+ TAILQ_INSERT_HEAD(&nd_defrouter, dr, dr_entry);
+ break;
+ }
+ }
+
+ if ((dr = TAILQ_FIRST(&nd_defrouter))) {
+ /*
+ * De-install the previous default gateway and install
+ * a new one.
+ * Note that if there is no reachable router in the list,
+ * the head entry will be used anyway.
+ * XXX: do we have to check the current routing table entry?
+ */
+ bzero(&anydr, sizeof(anydr));
+ defrouter_delreq(&anydr, 0);
+ defrouter_addreq(dr);
+ }
+ else {
+ /*
+ * The Default Router List is empty, so install the default
+ * route to an inteface.
+ * XXX: The specification does not say this mechanism should
+ * be restricted to hosts, but this would be not useful
+ * (even harmful) for routers.
+ */
+ if (!ip6_forwarding) {
+ /*
+ * De-install the current default route
+ * in advance.
+ */
+ bzero(&anydr, sizeof(anydr));
+ defrouter_delreq(&anydr, 0);
+ if (nd6_defifp) {
+ /*
+ * Install a route to the default interface
+ * as default route.
+ */
+ defrouter_addifreq(nd6_defifp);
+ }
+#ifdef ND6_DEBUG
+ else /* noisy log? */
+ log(LOG_INFO, "defrouter_select: "
+ "there's no default router and no default"
+ " interface\n");
+#endif
+ }
+ }
+
+ splx(s);
+ return;
+}
+
static struct nd_defrouter *
defrtrlist_update(new)
struct nd_defrouter *new;
@@ -488,13 +715,15 @@ defrtrlist_update(new)
}
bzero(n, sizeof(*n));
*n = *new;
- if (LIST_EMPTY(&nd_defrouter)) {
- LIST_INSERT_HEAD(&nd_defrouter, n, dr_entry);
- defrouter_addreq(n);
- } else {
- LIST_INSERT_AFTER(LIST_FIRST(&nd_defrouter), n, dr_entry);
- defrouter_addreq(n);
- }
+
+ /*
+ * Insert the new router at the end of the Default Router List.
+ * If there is no other router, install it anyway. Otherwise,
+ * just continue to use the current default router.
+ */
+ TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry);
+ if (TAILQ_FIRST(&nd_defrouter) == n)
+ defrouter_select();
splx(s);
return(n);
@@ -506,8 +735,8 @@ pfxrtr_lookup(pr, dr)
struct nd_defrouter *dr;
{
struct nd_pfxrouter *search;
-
- LIST_FOREACH(search, &pr->ndpr_advrtrs, pfr_entry) {
+
+ for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) {
if (search->router == dr)
break;
}
@@ -547,7 +776,7 @@ prefix_lookup(pr)
{
struct nd_prefix *search;
- LIST_FOREACH(search, &nd_prefix, ndpr_entry) {
+ for (search = nd_prefix.lh_first; search; search = search->ndpr_next) {
if (pr->ndpr_ifp == search->ndpr_ifp &&
pr->ndpr_plen == search->ndpr_plen &&
in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
@@ -591,8 +820,9 @@ prelist_add(pr, dr)
LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
splx(s);
- if (dr)
+ if (dr) {
pfxrtr_add(new, dr);
+ }
return 0;
}
@@ -610,8 +840,8 @@ prelist_remove(pr)
splx(s);
/* free list of routers that adversed the prefix */
- for (pfr = LIST_FIRST(&pr->ndpr_advrtrs); pfr; pfr = next) {
- next = LIST_NEXT(pfr, pfr_entry);
+ for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
+ next = pfr->pfr_next;
free(pfr, M_IP6NDP);
}
@@ -638,6 +868,7 @@ prelist_update(new, dr, m)
int error = 0;
int auth;
struct in6_addrlifetime *lt6;
+ u_char onlink; /* Mobile IPv6 */
auth = 0;
if (m) {
@@ -656,6 +887,7 @@ prelist_update(new, dr, m)
error = EADDRNOTAVAIL;
goto end;
}
+
/* update prefix information */
pr->ndpr_flags = new->ndpr_flags;
pr->ndpr_vltime = new->ndpr_vltime;
@@ -707,9 +939,9 @@ prelist_update(new, dr, m)
/* address lifetime <= prefix lifetime */
lt6->ia6t_vltime = new->ndpr_vltime;
lt6->ia6t_pltime = new->ndpr_pltime;
- in6_init_address_ltimes(new, lt6);
+ in6_init_address_ltimes(new, lt6, 1);
} else {
-#define TWOHOUR (120*60)
+#define TWOHOUR (120*60)
/*
* We have seen the prefix before, and we have added
* interface address in the past. We still have
@@ -722,10 +954,26 @@ prelist_update(new, dr, m)
lt6 = &ia6->ia6_lifetime;
- /*
- * update to RFC 2462 5.5.3 (e) from Jim Bound,
- * (ipng 6712)
- */
+#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++;
+ }
+
+ /* 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;
@@ -737,16 +985,28 @@ prelist_update(new, dr, m)
/* jim bound rule is not imposed for pref lifetime */
lt6->ia6t_pltime = new->ndpr_pltime;
-
- update++;
- if (update)
- in6_init_address_ltimes(new, lt6);
+#endif
+ in6_init_address_ltimes(new, lt6, update);
}
noautoconf1:
+#if 0
+ /* address lifetime expire processing, RFC 2462 5.5.4. */
+ if (pr->ndpr_preferred && pr->ndpr_preferred < time_second) {
+ struct in6_ifaddr *ia6;
+
+ ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
+ if (ia6)
+ ia6->ia6_flags &= ~IN6_IFF_DEPRECATED;
+ }
+#endif
+
+ onlink = pr->ndpr_statef_onlink; /* Mobile IPv6 */
+
if (dr && pfxrtr_lookup(pr, dr) == NULL)
pfxrtr_add(pr, dr);
+
} else {
int error_tmp;
@@ -779,7 +1039,7 @@ prelist_update(new, dr, m)
/* address lifetime <= prefix lifetime */
lt6->ia6t_vltime = new->ndpr_vltime;
lt6->ia6t_pltime = new->ndpr_pltime;
- in6_init_address_ltimes(new, lt6);
+ in6_init_address_ltimes(new, lt6, 1);
noautoconf2:
error_tmp = prelist_add(new, dr);
@@ -792,49 +1052,82 @@ prelist_update(new, dr, m)
}
/*
+ * A supplement function used in the on-link detection below;
+ * detect if a given prefix has a (probably) reachable advertising router.
+ * XXX: lengthy function name...
+ */
+struct nd_pfxrouter *
+find_pfxlist_reachable_router(pr)
+ struct nd_prefix *pr;
+{
+ struct nd_pfxrouter *pfxrtr;
+ struct rtentry *rt;
+ struct llinfo_nd6 *ln;
+
+ for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr;
+ pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) {
+ if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
+ pfxrtr->router->ifp)) &&
+ (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
+ ND6_IS_LLINFO_PROBREACH(ln))
+ break; /* found */
+ }
+
+ return(pfxrtr);
+
+}
+
+/*
* Check if each prefix in the prefix list has at least one available router
- * that advertised the prefix.
- * If the check fails, the prefix may be off-link because, for example,
+ * that advertised the prefix (A router is "available" if its neighbor cache
+ * entry has 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 availble router, we still regards
+ * 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.
*/
-static void
+void
pfxlist_onlink_check()
{
struct nd_prefix *pr;
- LIST_FOREACH(pr, &nd_prefix, ndpr_entry)
- if (!LIST_EMPTY(&pr->ndpr_advrtrs)) /* pr has an available router */
+ /*
+ * 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))
break;
+ }
if (pr) {
/*
- * There is at least one prefix that has a router. First,
- * detach prefixes which has no 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.
+ * 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.
*/
- LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
- if (LIST_EMPTY(&pr->ndpr_advrtrs) &&
+ 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);
}
}
- LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
- if (!LIST_EMPTY(&pr->ndpr_advrtrs) &&
- pr->ndpr_statef_onlink == 0)
+ 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);
}
- } else {
- /* there is no prefix that has a router */
- LIST_FOREACH(pr, &nd_prefix, ndpr_entry)
+ }
+ 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);
}
@@ -904,7 +1197,8 @@ nd6_attach_prefix(pr)
"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);
- } else {
+ }
+ else {
int e;
struct sockaddr_in6 mask6;
@@ -955,12 +1249,20 @@ in6_ifadd(ifp, in6, addr, prefixlen)
in6_len2mask(&mask, prefixlen);
/* find link-local address (will be interface ID) */
- ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp);
+ ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);/* 0 is OK? */
if (ifa)
ib = (struct in6_ifaddr *)ifa;
else
return NULL;
+#if 0 /* don't care link local addr state, and always do DAD */
+ /* if link-local address is not eligible, do not autoconfigure. */
+ if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) {
+ printf("in6_ifadd: link-local address not ready\n");
+ return NULL;
+ }
+#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"
@@ -979,7 +1281,10 @@ in6_ifadd(ifp, in6, addr, prefixlen)
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;
+ 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;
@@ -988,14 +1293,22 @@ in6_ifadd(ifp, in6, addr, prefixlen)
for( ; oia->ia_next; oia = oia->ia_next)
continue;
oia->ia_next = ia;
- } else
+ } 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 */
- if (!TAILQ_EMPTY(&ifp->if_addrlist)) {
- TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia,
- ifa_list);
- }
+ 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);
@@ -1113,6 +1426,7 @@ in6_ifdel(ifp, in6)
}
TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
+ IFAFREE(&ia->ia_ifa);
/* lladdr is never deleted */
oia = ia;
@@ -1163,16 +1477,26 @@ in6_init_prefix_ltimes(struct nd_prefix *ndpr)
}
static void
-in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
+in6_init_address_ltimes(struct nd_prefix *new,
+ struct in6_addrlifetime *lt6,
+ int 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;
+ /* 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_preferred */
if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
lt6->ia6t_preferred = 0;
@@ -1180,10 +1504,7 @@ in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
lt6->ia6t_preferred = time_second;
lt6->ia6t_preferred += lt6->ia6t_pltime;
}
- /* ensure addr lifetime <= prefix lifetime */
- if (new->ndpr_expire && lt6->ia6t_expire &&
- new->ndpr_expire < lt6->ia6t_expire)
- lt6->ia6t_expire = new->ndpr_expire;
+ /* Ensure addr lifetime <= prefix lifetime. */
if (new->ndpr_preferred && lt6->ia6t_preferred
&& new->ndpr_preferred < lt6->ia6t_preferred)
lt6->ia6t_preferred = new->ndpr_preferred;
@@ -1240,3 +1561,41 @@ rt6_deleteroute(rn, arg)
rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0));
#undef SIN6
}
+
+int
+nd6_setdefaultiface(ifindex)
+ int ifindex;
+{
+ int error = 0;
+
+ if (ifindex < 0 || if_index < ifindex)
+ return(EINVAL);
+
+ if (nd6_defifindex != ifindex) {
+ nd6_defifindex = ifindex;
+ if (nd6_defifindex > 0)
+ nd6_defifp = ifindex2ifnet[nd6_defifindex];
+ else
+ nd6_defifp = NULL;
+
+ /*
+ * If the Default Router List is empty, install a route
+ * to the specified interface as default or remove the default
+ * route when the default interface becomes canceled.
+ * The check for the queue is actually redundant, but
+ * we do this here to avoid re-install the default route
+ * if the list is NOT empty.
+ */
+ if (TAILQ_FIRST(&nd_defrouter) == NULL)
+ defrouter_select();
+
+ /*
+ * Our current implementation assumes one-to-one maping between
+ * interfaces and links, so it would be natural to use the
+ * default interface as the default link.
+ */
+ scope6_setdefault(nd6_defifp);
+ }
+
+ return(error);
+}
diff --git a/sys/netinet6/pim6.h b/sys/netinet6/pim6.h
index 1e477857830a..d420db9f0e8b 100644
--- a/sys/netinet6/pim6.h
+++ b/sys/netinet6/pim6.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: pim6.h,v 1.3 2000/03/25 07:23:58 sumikawa Exp $ */
+
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
* Protocol Independent Multicast (PIM) definitions
@@ -39,7 +40,7 @@
/*
* PIM packet header
*/
-#define PIM_VERSION 2
+#define PIM_VERSION 2
struct pim {
#if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
u_char pim_type:4, /* the PIM message type, currently they are:
@@ -52,17 +53,17 @@ struct pim {
u_char pim_ver:4, /* PIM version */
pim_type:4; /* PIM type */
#endif
- u_char pim_rsv; /* Reserved */
+ u_char pim_rsv; /* Reserved */
u_short pim_cksum; /* IP style check sum */
};
-#define PIM_MINLEN 8 /* The header min. length is 8 */
-#define PIM6_REG_MINLEN (PIM_MINLEN+40) /* Register message + inner IP6 header */
+#define PIM_MINLEN 8 /* The header min. length is 8 */
+#define PIM6_REG_MINLEN (PIM_MINLEN+40) /* Register message + inner IP6 header */
/*
* Message types
*/
-#define PIM_REGISTER 1 /* PIM Register type is 1 */
+#define PIM_REGISTER 1 /* PIM Register type is 1 */
/* second bit in reg_head is the null bit */
-#define PIM_NULL_REGISTER 0x40000000
+#define PIM_NULL_REGISTER 0x40000000
diff --git a/sys/netinet6/pim6_var.h b/sys/netinet6/pim6_var.h
index 9423b7fe409b..358a195d2a3c 100644
--- a/sys/netinet6/pim6_var.h
+++ b/sys/netinet6/pim6_var.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: pim6_var.h,v 1.8 2000/06/06 08:07:43 jinmei Exp $ */
+
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
@@ -25,10 +28,7 @@
* 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.
- *
- * $FreeBSD$
*/
-/* $Id: pim6_var.h,v 1.2 1999/08/01 15:58:13 itojun Exp $ */
#ifndef _NETINET6_PIM6_VAR_H_
#define _NETINET6_PIM6_VAR_H_
@@ -42,30 +42,29 @@
*/
struct pim6stat {
- u_int pim6s_rcv_total; /* total PIM messages received */
- u_int pim6s_rcv_tooshort; /* received with too few bytes */
- u_int pim6s_rcv_badsum; /* received with bad checksum */
- u_int pim6s_rcv_badversion; /* received bad PIM version */
- u_int pim6s_rcv_registers; /* received registers */
- u_int pim6s_rcv_badregisters; /* received invalid registers */
- u_int pim6s_snd_registers; /* sent registers */
+ u_quad_t pim6s_rcv_total; /* total PIM messages received */
+ u_quad_t pim6s_rcv_tooshort; /* received with too few bytes */
+ u_quad_t pim6s_rcv_badsum; /* received with bad checksum */
+ u_quad_t pim6s_rcv_badversion; /* received bad PIM version */
+ u_quad_t pim6s_rcv_registers; /* received registers */
+ u_quad_t pim6s_rcv_badregisters; /* received invalid registers */
+ u_quad_t pim6s_snd_registers; /* sent registers */
};
-#ifdef _KERNEL
-extern struct pim6stat pim6stat;
+#if (defined(KERNEL)) || (defined(_KERNEL))
+extern struct pim6stat pim6stat;
-int pim6_input __P((struct mbuf **, int*, int));
-#endif
+int pim6_input __P((struct mbuf **, int*, int));
+#endif /* KERNEL */
/*
* Names for PIM sysctl objects
*/
-#define PIMCTL_STATS 1 /* statistics (read-only) */
-#define PIMCTL_MAXID 2
+#define PIM6CTL_STATS 1 /* statistics (read-only) */
+#define PIM6CTL_MAXID 2
-#define PIMCTL_NAMES { \
+#define PIM6CTL_NAMES { \
{ 0, 0 }, \
{ 0, 0 }, \
}
-
#endif /* _NETINET6_PIM6_VAR_H_ */
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 9fb94d5ffe08..a846b3c4db22 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -85,13 +85,17 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/in_systm.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/ip6_mroute.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#include <netinet/in_pcb.h>
#include <netinet6/in6_pcb.h>
#include <netinet6/nd6.h>
+#include <netinet6/ip6protosw.h>
+#ifdef ENABLE_DEFAULT_SCOPE
+#include <netinet6/scope6_var.h>
+#endif
#ifdef IPSEC
#include <netinet6/ipsec.h>
@@ -209,6 +213,66 @@ rip6_input(mp, offp, proto)
return IPPROTO_DONE;
}
+void
+rip6_ctlinput(cmd, sa, d)
+ int cmd;
+ struct sockaddr *sa;
+ void *d;
+{
+ struct sockaddr_in6 sa6;
+ struct ip6_hdr *ip6;
+ struct mbuf *m;
+ int off = 0;
+ void (*notify) __P((struct inpcb *, int)) = in6_rtchange;
+
+ if (sa->sa_family != AF_INET6 ||
+ sa->sa_len != sizeof(struct sockaddr_in6))
+ return;
+
+ if ((unsigned)cmd >= PRC_NCMDS)
+ return;
+ if (PRC_IS_REDIRECT(cmd))
+ notify = in6_rtchange, d = NULL;
+ else if (cmd == PRC_HOSTDEAD)
+ d = NULL;
+ else if (inet6ctlerrmap[cmd] == 0)
+ return;
+
+ /* if the parameter is from icmp6, decode it. */
+ if (d != NULL) {
+ struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
+ m = ip6cp->ip6c_m;
+ ip6 = ip6cp->ip6c_ip6;
+ off = ip6cp->ip6c_off;
+ } else {
+ m = NULL;
+ ip6 = NULL;
+ }
+
+ /* 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);
+}
+
/*
* Generate IPv6 header and pass packet to ip6_output.
* Tack on options user may have setup with control call.
@@ -371,10 +435,10 @@ rip6_output(m, va_alist)
}
#ifdef IPSEC
- m->m_pkthdr.rcvif = (struct ifnet *)so;
+ ipsec_setsocket(m, so);
#endif /*IPSEC*/
- error = ip6_output(m, optp, &in6p->in6p_route, IPV6_SOCKINMRCVIF,
+ error = ip6_output(m, optp, &in6p->in6p_route, 0,
in6p->in6p_moptions, &oifp);
if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
if (oifp)
@@ -543,6 +607,11 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6)
return EADDRNOTAVAIL;
+#ifdef ENABLE_DEFAULT_SCOPE
+ if (addr->sin6_scope_id == 0) { /* not change if specified */
+ addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr);
+ }
+#endif
if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
(ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)
return EADDRNOTAVAIL;
@@ -563,6 +632,9 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
struct in6_addr *in6a = NULL;
int error = 0;
+#ifdef ENABLE_DEFAULT_SCOPE
+ struct sockaddr_in6 tmp;
+#endif
if (nam->sa_len != sizeof(*addr))
return EINVAL;
@@ -570,7 +642,14 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
return EADDRNOTAVAIL;
if (addr->sin6_family != AF_INET6)
return EAFNOSUPPORT;
-
+#ifdef ENABLE_DEFAULT_SCOPE
+ if (addr->sin6_scope_id == 0) { /* not change if specified */
+ /* avoid overwrites */
+ tmp = *addr;
+ addr = &tmp;
+ addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr);
+ }
+#endif
/* Source address selection. XXX: need pcblookup? */
in6a = in6_selectsrc(addr, inp->in6p_outputopts,
inp->in6p_moptions, &inp->in6p_route,
@@ -598,6 +677,7 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
struct sockaddr_in6 tmp;
struct sockaddr_in6 *dst;
+ /* always copy sockaddr to avoid overwrites */
if (so->so_state & SS_ISCONNECTED) {
if (nam) {
m_freem(m);
@@ -615,8 +695,14 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
m_freem(m);
return ENOTCONN;
}
- dst = (struct sockaddr_in6 *)nam;
+ tmp = *(struct sockaddr_in6 *)nam;
+ dst = &tmp;
+ }
+#ifdef ENABLE_DEFAULT_SCOPE
+ if (dst->sin6_scope_id == 0) { /* not change if specified */
+ dst->sin6_scope_id = scope6_addr2default(&dst->sin6_addr);
}
+#endif
return rip6_output(m, so, dst, control);
}
diff --git a/sys/netinet6/route6.c b/sys/netinet6/route6.c
index d50cf907c412..cbba9db80d91 100644
--- a/sys/netinet6/route6.c
+++ b/sys/netinet6/route6.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: route6.c,v 1.15 2000/06/23 16:18:20 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,25 +28,27 @@
* 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.
- *
- * $FreeBSD$
*/
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
+#include <sys/systm.h>
#include <net/if.h>
#include <netinet/in.h>
-#include <netinet6/in6.h>
#include <netinet6/in6_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet/icmp6.h>
-static int ip6_rthdr0 __P((struct mbuf *, struct ip6_hdr *, struct ip6_rthdr0 *));
+static int ip6_rthdr0 __P((struct mbuf *, struct ip6_hdr *,
+ struct ip6_rthdr0 *));
int
route6_input(mp, offp, proto)
@@ -55,27 +60,57 @@ route6_input(mp, offp, proto)
register struct ip6_rthdr *rh;
int off = *offp, rhlen;
+#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, sizeof(*rh), IPPROTO_DONE);
ip6 = mtod(m, struct ip6_hdr *);
rh = (struct ip6_rthdr *)((caddr_t)ip6 + off);
+#else
+ ip6 = mtod(m, struct ip6_hdr *);
+ IP6_EXTHDR_GET(rh, struct ip6_rthdr *, m, off, sizeof(*rh));
+ if (rh == NULL) {
+ ip6stat.ip6s_tooshort++;
+ return IPPROTO_DONE;
+ }
+#endif
- switch(rh->ip6r_type) {
- case IPV6_RTHDR_TYPE_0:
- rhlen = (rh->ip6r_len + 1) << 3;
- IP6_EXTHDR_CHECK(m, off, rhlen, IPPROTO_DONE);
- if (ip6_rthdr0(m, ip6, (struct ip6_rthdr0 *)rh))
- return(IPPROTO_DONE);
- break;
- default:
- /* unknown routing type */
- if (rh->ip6r_segleft == 0) {
- rhlen = (rh->ip6r_len + 1) << 3;
- break; /* Final dst. Just ignore the header. */
- }
- ip6stat.ip6s_badoptions++;
- icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
- (caddr_t)&rh->ip6r_type - (caddr_t)ip6);
- return(IPPROTO_DONE);
+ switch (rh->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ rhlen = (rh->ip6r_len + 1) << 3;
+#ifndef PULLDOWN_TEST
+ /*
+ * note on option length:
+ * due to IP6_EXTHDR_CHECK assumption, we cannot handle
+ * very big routing header (max rhlen == 2048).
+ */
+ IP6_EXTHDR_CHECK(m, off, rhlen, IPPROTO_DONE);
+#else
+ /*
+ * note on option length:
+ * maximum rhlen: 2048
+ * max mbuf m_pulldown can handle: MCLBYTES == usually 2048
+ * so, here we are assuming that m_pulldown can handle
+ * rhlen == 2048 case. this may not be a good thing to
+ * assume - we may want to avoid pulling it up altogether.
+ */
+ IP6_EXTHDR_GET(rh, struct ip6_rthdr *, m, off, rhlen);
+ if (rh == NULL) {
+ ip6stat.ip6s_tooshort++;
+ return IPPROTO_DONE;
+ }
+#endif
+ if (ip6_rthdr0(m, ip6, (struct ip6_rthdr0 *)rh))
+ return(IPPROTO_DONE);
+ break;
+ default:
+ /* unknown routing type */
+ if (rh->ip6r_segleft == 0) {
+ rhlen = (rh->ip6r_len + 1) << 3;
+ break; /* Final dst. Just ignore the header. */
+ }
+ ip6stat.ip6s_badoptions++;
+ icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
+ (caddr_t)&rh->ip6r_type - (caddr_t)ip6);
+ return(IPPROTO_DONE);
}
*offp += rhlen;
@@ -122,10 +157,25 @@ ip6_rthdr0(m, ip6, rh0)
index = addrs - rh0->ip6r0_segleft;
rh0->ip6r0_segleft--;
- nextaddr = rh0->ip6r0_addr + index;
+ nextaddr = ((struct in6_addr *)(rh0 + 1)) + index;
+ /*
+ * reject invalid addresses. be proactive about malicious use of
+ * IPv4 mapped/compat address.
+ * XXX need more checks?
+ */
if (IN6_IS_ADDR_MULTICAST(nextaddr) ||
- IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
+ IN6_IS_ADDR_UNSPECIFIED(nextaddr) ||
+ IN6_IS_ADDR_V4MAPPED(nextaddr) ||
+ IN6_IS_ADDR_V4COMPAT(nextaddr)) {
+ ip6stat.ip6s_badoptions++;
+ m_freem(m);
+ return(-1);
+ }
+ 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)) {
ip6stat.ip6s_badoptions++;
m_freem(m);
return(-1);
diff --git a/sys/netinet6/scope6.c b/sys/netinet6/scope6.c
new file mode 100644
index 000000000000..43a6fb722afa
--- /dev/null
+++ b/sys/netinet6/scope6.c
@@ -0,0 +1,302 @@
+/* $FreeBSD$ */
+/* $KAME: scope6.c,v 1.9 2000/05/18 15:03:26 jinmei 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.
+ */
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+
+#include <net/route.h>
+#include <net/if.h>
+
+#include <netinet/in.h>
+
+#include <netinet6/in6_var.h>
+#include <netinet6/scope6_var.h>
+
+struct scope6_id {
+ /*
+ * 16 is correspondent to 4bit multicast scope field.
+ * i.e. from node-local to global with some reserved/unassigned types.
+ */
+ u_int32_t s6id_list[16];
+};
+static size_t if_indexlim = 8;
+struct scope6_id *scope6_ids = NULL;
+
+void
+scope6_ifattach(ifp)
+ struct ifnet *ifp;
+{
+ int s = splnet();
+
+ /*
+ * We have some arrays that should be indexed by if_index.
+ * since if_index will grow dynamically, they should grow too.
+ */
+ if (scope6_ids == NULL || if_index >= if_indexlim) {
+ size_t n;
+ caddr_t q;
+
+ while (if_index >= if_indexlim)
+ if_indexlim <<= 1;
+
+ /* grow scope index array */
+ n = if_indexlim * sizeof(struct scope6_id);
+ /* XXX: need new malloc type? */
+ q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
+ bzero(q, n);
+ if (scope6_ids) {
+ bcopy((caddr_t)scope6_ids, q, n/2);
+ free((caddr_t)scope6_ids, M_IFADDR);
+ }
+ scope6_ids = (struct scope6_id *)q;
+ }
+
+#define SID scope6_ids[ifp->if_index]
+
+ /* don't initialize if called twice */
+ if (SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]) {
+ splx(s);
+ return;
+ }
+
+ /*
+ * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
+ * Should we rather hardcode here?
+ */
+ SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index;
+#ifdef MULTI_SCOPE
+ /* by default, we don't care about scope boundary for these scopes. */
+ SID.s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1;
+ SID.s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1;
+#endif
+#undef SID
+
+ splx(s);
+}
+
+int
+scope6_set(ifp, idlist)
+ struct ifnet *ifp;
+ u_int32_t *idlist;
+{
+ int i, s;
+ int error = 0;
+
+ if (scope6_ids == NULL) /* paranoid? */
+ return(EINVAL);
+
+ /*
+ * XXX: We need more consistency checks of the relationship among
+ * scopes (e.g. an organization should be larger than a site).
+ */
+
+ /*
+ * TODO(XXX): after setting, we should reflect the changes to
+ * interface addresses, routing table entries, PCB entries...
+ */
+
+ s = splnet();
+
+ for (i = 0; i < 16; i++) {
+ if (idlist[i] &&
+ idlist[i] != scope6_ids[ifp->if_index].s6id_list[i]) {
+ if (i == IPV6_ADDR_SCOPE_LINKLOCAL &&
+ idlist[i] > if_index) {
+ /*
+ * XXX: theoretically, there should be no
+ * relationship between link IDs and interface
+ * IDs, but we check the consistency for
+ * safety in later use.
+ */
+ splx(s);
+ return(EINVAL);
+ }
+
+ /*
+ * XXX: we must need lots of work in this case,
+ * but we simply set the new value in this initial
+ * implementation.
+ */
+ scope6_ids[ifp->if_index].s6id_list[i] = idlist[i];
+ }
+ }
+ splx(s);
+
+ return(error);
+}
+
+int
+scope6_get(ifp, idlist)
+ struct ifnet *ifp;
+ u_int32_t *idlist;
+{
+ if (scope6_ids == NULL) /* paranoid? */
+ return(EINVAL);
+
+ bcopy(scope6_ids[ifp->if_index].s6id_list, idlist,
+ sizeof(scope6_ids[ifp->if_index].s6id_list));
+
+ return(0);
+}
+
+
+/*
+ * Get a scope of the address. Node-local, link-local, site-local or global.
+ */
+int
+in6_addrscope(addr)
+struct in6_addr *addr;
+{
+ int scope;
+
+ if (addr->s6_addr8[0] == 0xfe) {
+ scope = addr->s6_addr8[1] & 0xc0;
+
+ switch (scope) {
+ case 0x80:
+ return IPV6_ADDR_SCOPE_LINKLOCAL;
+ break;
+ case 0xc0:
+ return IPV6_ADDR_SCOPE_SITELOCAL;
+ break;
+ default:
+ return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
+ break;
+ }
+ }
+
+
+ if (addr->s6_addr8[0] == 0xff) {
+ scope = addr->s6_addr8[1] & 0x0f;
+
+ /*
+ * due to other scope such as reserved,
+ * return scope doesn't work.
+ */
+ switch (scope) {
+ case IPV6_ADDR_SCOPE_NODELOCAL:
+ return IPV6_ADDR_SCOPE_NODELOCAL;
+ break;
+ case IPV6_ADDR_SCOPE_LINKLOCAL:
+ return IPV6_ADDR_SCOPE_LINKLOCAL;
+ break;
+ case IPV6_ADDR_SCOPE_SITELOCAL:
+ return IPV6_ADDR_SCOPE_SITELOCAL;
+ break;
+ default:
+ return IPV6_ADDR_SCOPE_GLOBAL;
+ break;
+ }
+ }
+
+ if (bcmp(&in6addr_loopback, addr, sizeof(addr) - 1) == 0) {
+ if (addr->s6_addr8[15] == 1) /* loopback */
+ return IPV6_ADDR_SCOPE_NODELOCAL;
+ if (addr->s6_addr8[15] == 0) /* unspecified */
+ return IPV6_ADDR_SCOPE_LINKLOCAL;
+ }
+
+ return IPV6_ADDR_SCOPE_GLOBAL;
+}
+
+int
+in6_addr2scopeid(ifp, addr)
+ struct ifnet *ifp; /* must not be NULL */
+ struct in6_addr *addr; /* must not be NULL */
+{
+ int scope = in6_addrscope(addr);
+
+ if (scope6_ids == NULL) /* paranoid? */
+ return(0); /* XXX */
+ if (ifp->if_index >= if_indexlim)
+ return(0); /* XXX */
+
+#define SID scope6_ids[ifp->if_index]
+ switch(scope) {
+ case IPV6_ADDR_SCOPE_NODELOCAL:
+ return(-1); /* XXX: is this an appropriate value? */
+
+ case IPV6_ADDR_SCOPE_LINKLOCAL:
+ return(SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]);
+
+ case IPV6_ADDR_SCOPE_SITELOCAL:
+ return(SID.s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]);
+
+ case IPV6_ADDR_SCOPE_ORGLOCAL:
+ return(SID.s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]);
+
+ default:
+ return(0); /* XXX: treat as global. */
+ }
+#undef SID
+}
+
+void
+scope6_setdefault(ifp)
+ struct ifnet *ifp; /* note that this might be NULL */
+{
+ /*
+ * Currently, this function just set the default "link" according to
+ * the given interface.
+ * We might eventually have to separate the notion of "link" from
+ * "interface" and provide a user interface to set the default.
+ */
+ if (ifp) {
+ scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] =
+ ifp->if_index;
+ }
+ else
+ scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0;
+}
+
+int
+scope6_get_default(idlist)
+ u_int32_t *idlist;
+{
+ if (scope6_ids == NULL) /* paranoid? */
+ return(EINVAL);
+
+ bcopy(scope6_ids[0].s6id_list, idlist,
+ sizeof(scope6_ids[0].s6id_list));
+
+ return(0);
+}
+
+u_int32_t
+scope6_addr2default(addr)
+ struct in6_addr *addr;
+{
+ return(scope6_ids[0].s6id_list[in6_addrscope(addr)]);
+}
diff --git a/sys/netinet6/scope6_var.h b/sys/netinet6/scope6_var.h
new file mode 100644
index 000000000000..6e107d7c1a7e
--- /dev/null
+++ b/sys/netinet6/scope6_var.h
@@ -0,0 +1,46 @@
+/* $FreeBSD$ */
+/* $KAME: scope6_var.h,v 1.4 2000/05/18 15:03:27 jinmei 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 _NETINET6_SCOPE6_VAR_H_
+#define _NETINET6_SCOPE6_VAR_H_
+
+#ifdef _KERNEL
+void scope6_ifattach __P((struct ifnet *));
+int scope6_set __P((struct ifnet *, u_int32_t *));
+int scope6_get __P((struct ifnet *, u_int32_t *));
+void scope6_setdefault __P((struct ifnet *));
+int scope6_get_default __P((u_int32_t *));
+u_int32_t scope6_in6_addrscope __P((struct in6_addr *));
+u_int32_t scope6_addr2default __P((struct in6_addr *));
+#endif /* _KERNEL */
+
+#endif /* _NETINET6_SCOPE6_VAR_H_ */
diff --git a/sys/netinet6/tcp6_var.h b/sys/netinet6/tcp6_var.h
index 820c49be741e..e283212bf88d 100644
--- a/sys/netinet6/tcp6_var.h
+++ b/sys/netinet6/tcp6_var.h
@@ -66,7 +66,7 @@
*/
#ifndef _NETINET_TCP6_VAR_H_
-#define _NETINET_TCP6_VAR_H_
+#define _NETINET_TCP6_VAR_H_
#ifdef _KERNEL
#ifdef SYSCTL_DECL
diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c
new file mode 100644
index 000000000000..c6d831f38f92
--- /dev/null
+++ b/sys/netinet6/udp6_output.c
@@ -0,0 +1,285 @@
+/* $FreeBSD$ */
+/* $KAME: udp6_output.c,v 1.14 2000/06/13 10:31:23 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.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)udp_var.h 8.1 (Berkeley) 6/10/93
+ */
+
+#include "opt_ipsec.h"
+#include "opt_inet.h"
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_types.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/in_pcb.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/in6_pcb.h>
+#include <netinet6/udp6_var.h>
+#include <netinet/icmp6.h>
+#include <netinet6/ip6protosw.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#ifdef INET6
+#include <netinet6/ipsec6.h>
+#endif
+#endif /*IPSEC*/
+
+#include "faith.h"
+
+#include <net/net_osdep.h>
+
+/*
+ * UDP protocol inplementation.
+ * Per RFC 768, August, 1980.
+ */
+
+#define in6pcb inpcb
+#define udp6stat udpstat
+#define udp6s_opackets udps_opackets
+
+int
+udp6_output(in6p, m, addr6, control, p)
+ register struct in6pcb *in6p;
+ register struct mbuf *m;
+ struct mbuf *control;
+ struct sockaddr *addr6;
+ struct proc *p;
+{
+ register 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;
+ u_short fport;
+ int error = 0;
+ struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
+ int priv;
+ int af, hlen;
+ int flags;
+ struct sockaddr_in6 tmp;
+
+ priv = 0;
+ if (p && !suser(p))
+ priv = 1;
+ if (control) {
+ if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
+ goto release;
+ in6p->in6p_outputopts = &opt;
+ }
+
+ if (addr6) {
+ /*
+ * IPv4 version of udp_output calls in_pcbconnect in this case,
+ * which needs splnet and affects performance.
+ * Since we saw no essential reason for calling in_pcbconnect,
+ * we get rid of such kind of logic, and call in6_selectsrc
+ * and in6_pcbsetport in order to fill in the local address
+ * and the local port.
+ */
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr6;
+ if (sin6->sin6_port == 0) {
+ error = EADDRNOTAVAIL;
+ goto release;
+ }
+
+ if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
+ error = EISCONN;
+ goto release;
+ }
+
+ /* protect *sin6 from overwrites */
+ tmp = *sin6;
+ sin6 = &tmp;
+
+ faddr = &sin6->sin6_addr;
+ fport = sin6->sin6_port; /* allow 0 port */
+
+ /* KAME hack: embed scopeid */
+ if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0) {
+ error = EINVAL;
+ goto release;
+ }
+
+ if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
+ laddr = in6_selectsrc(sin6, in6p->in6p_outputopts,
+ in6p->in6p_moptions,
+ &in6p->in6p_route,
+ &in6p->in6p_laddr, &error);
+ } else
+ laddr = &in6p->in6p_laddr; /*XXX*/
+ if (laddr == NULL) {
+ if (error == 0)
+ error = EADDRNOTAVAIL;
+ goto release;
+ }
+ if (in6p->in6p_lport == 0 &&
+ (error = in6_pcbsetport(laddr, in6p, p)) != 0)
+ goto release;
+ } else {
+ if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
+ error = ENOTCONN;
+ goto release;
+ }
+ 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;
+ hlen = sizeof(struct ip);
+ }
+
+ /*
+ * Calculate data length and get a mbuf
+ * for UDP and IP6 headers.
+ */
+ M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT);
+ if (m == 0) {
+ error = ENOBUFS;
+ goto release;
+ }
+
+ /*
+ * Stuff checksum and output datagram.
+ */
+ udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen);
+ udp6->uh_sport = in6p->in6p_lport; /* lport is always set in the PCB */
+ udp6->uh_dport = fport;
+ if (plen <= 0xffff)
+ udp6->uh_ulen = htons((u_short)plen);
+ else
+ udp6->uh_ulen = 0;
+ udp6->uh_sum = 0;
+
+ switch (af) {
+ case AF_INET6:
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
+ ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
+ ip6->ip6_vfc |= IPV6_VERSION;
+#if 0 /* ip6_plen will be filled in ip6_output. */
+ ip6->ip6_plen = htons((u_short)plen);
+#endif
+ ip6->ip6_nxt = IPPROTO_UDP;
+ ip6->ip6_hlim = in6_selecthlim(in6p,
+ in6p->in6p_route.ro_rt ?
+ in6p->in6p_route.ro_rt->rt_ifp : NULL);
+ ip6->ip6_src = *laddr;
+ ip6->ip6_dst = *faddr;
+
+ if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
+ sizeof(struct ip6_hdr), plen)) == 0) {
+ udp6->uh_sum = 0xffff;
+ }
+
+ flags = 0;
+
+ udp6stat.udp6s_opackets++;
+#ifdef IPSEC
+ ipsec_setsocket(m, in6p->in6p_socket);
+#endif /*IPSEC*/
+ error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
+ flags, in6p->in6p_moptions, NULL);
+ break;
+ case AF_INET:
+ error = EAFNOSUPPORT;
+ goto release;
+ }
+ goto releaseopt;
+
+release:
+ m_freem(m);
+
+releaseopt:
+ if (control) {
+ in6p->in6p_outputopts = stickyopt;
+ m_freem(control);
+ }
+ return(error);
+}
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index 99032b914131..beda1e92db09 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: udp6_usrreq.c,v 1.11 2000/06/18 06:23:06 jinmei Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -60,9 +63,10 @@
* SUCH DAMAGE.
*
* @(#)udp_var.h 8.1 (Berkeley) 6/10/93
- * $FreeBSD$
*/
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_ipsec.h"
#include <sys/param.h>
@@ -90,10 +94,10 @@
#include <netinet/ip_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/in6_pcb.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#include <netinet6/udp6_var.h>
#include <netinet6/ip6protosw.h>
@@ -402,15 +406,20 @@ udp6_ctlinput(cmd, sa, d)
struct sockaddr_in6 sa6;
struct ip6_hdr *ip6;
struct mbuf *m;
- int off;
+ int off = 0;
+ void (*notify) __P((struct inpcb *, int)) = udp_notify;
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
return;
- off = 0;
- if (!PRC_IS_REDIRECT(cmd) &&
- ((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0))
+ if ((unsigned)cmd >= PRC_NCMDS)
+ return;
+ if (PRC_IS_REDIRECT(cmd))
+ notify = in6_rtchange, d = NULL;
+ else if (cmd == PRC_HOSTDEAD)
+ d = NULL;
+ else if (inet6ctlerrmap[cmd] == 0)
return;
/* if the parameter is from icmp6, decode it. */
@@ -426,7 +435,7 @@ udp6_ctlinput(cmd, sa, d)
/* translate addresses into internal form */
sa6 = *(struct sockaddr_in6 *)sa;
- if (m != NULL && IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr))
+ 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) {
@@ -452,10 +461,10 @@ udp6_ctlinput(cmd, sa, d)
uhp = (struct udphdr *)(mtod(m, caddr_t) + off);
(void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6,
uhp->uh_dport, &s,
- uhp->uh_sport, cmd, udp_notify);
+ uhp->uh_sport, cmd, notify);
} else
(void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6, 0,
- &zeroin6_addr, 0, cmd, udp_notify);
+ &zeroin6_addr, 0, cmd, notify);
}
static int
@@ -468,6 +477,11 @@ udp6_getcred(SYSCTL_HANDLER_ARGS)
error = suser(req->p);
if (error)
return (error);
+
+ if (req->newlen != sizeof(addrs))
+ return (EINVAL);
+ if (req->oldlen != sizeof(struct ucred))
+ return (EINVAL);
error = SYSCTL_IN(req, addrs, sizeof(addrs));
if (error)
return (error);
@@ -492,121 +506,6 @@ SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
0, 0,
udp6_getcred, "S,ucred", "Get the ucred of a UDP6 connection");
-int
-udp6_output(in6p, m, addr6, control, p)
- register struct inpcb *in6p;
- struct mbuf *m;
- struct sockaddr *addr6;
- struct mbuf *control;
- struct proc *p;
-{
- register int ulen = m->m_pkthdr.len;
- int plen = sizeof(struct udphdr) + ulen;
- struct ip6_hdr *ip6;
- struct udphdr *udp6;
- struct in6_addr laddr6;
- int s = 0, error = 0;
- struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
-
- if (control) {
- if ((error = ip6_setpktoptions(control, &opt, suser(p))) != 0)
- goto release;
- in6p->in6p_outputopts = &opt;
- }
-
- if (addr6) {
- laddr6 = in6p->in6p_laddr;
- if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
- error = EISCONN;
- goto release;
- }
- /*
- * Must block input while temporarily connected.
- */
- s = splnet();
- /*
- * XXX: the user might want to overwrite the local address
- * via an ancillary data.
- */
- bzero(&in6p->in6p_laddr, sizeof(struct in6_addr));
- error = in6_pcbconnect(in6p, addr6, p);
- if (error) {
- splx(s);
- goto release;
- }
- } else {
- if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
- error = ENOTCONN;
- goto release;
- }
- }
- /*
- * Calculate data length and get a mbuf
- * for UDP and IP6 headers.
- */
- M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr),
- M_DONTWAIT);
- if (m == 0) {
- error = ENOBUFS;
- if (addr6)
- splx(s);
- goto release;
- }
-
- /*
- * Stuff checksum and output datagram.
- */
- ip6 = mtod(m, struct ip6_hdr *);
- ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
- (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK);
- ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
- (IPV6_VERSION & IPV6_VERSION_MASK);
- /* ip6_plen will be filled in ip6_output. */
- ip6->ip6_nxt = IPPROTO_UDP;
- ip6->ip6_hlim = in6_selecthlim(in6p,
- in6p->in6p_route.ro_rt ?
- in6p->in6p_route.ro_rt->rt_ifp :
- NULL);
- ip6->ip6_src = in6p->in6p_laddr;
- ip6->ip6_dst = in6p->in6p_faddr;
-
- udp6 = (struct udphdr *)(ip6 + 1);
- udp6->uh_sport = in6p->in6p_lport;
- udp6->uh_dport = in6p->in6p_fport;
- udp6->uh_ulen = htons((u_short)plen);
- udp6->uh_sum = 0;
-
- if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
- sizeof(struct ip6_hdr), plen)) == 0) {
- udp6->uh_sum = 0xffff;
- }
-
- udpstat.udps_opackets++;
-
-#ifdef IPSEC
- m->m_pkthdr.rcvif = (struct ifnet *)in6p->in6p_socket;
-#endif /*IPSEC*/
- error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
- IPV6_SOCKINMRCVIF, in6p->in6p_moptions, NULL);
-
- if (addr6) {
- in6_pcbdisconnect(in6p);
- in6p->in6p_laddr = laddr6;
- splx(s);
- }
- goto releaseopt;
-
-release:
- m_freem(m);
-
-releaseopt:
- if (control) {
- in6p->in6p_outputopts = stickyopt;
- m_freem(control);
- }
- return(error);
-}
-
static int
udp6_abort(struct socket *so)
{
@@ -732,10 +631,16 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
return error;
}
}
+
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
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;
@@ -793,14 +698,26 @@ udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
struct mbuf *control, struct proc *p)
{
struct inpcb *inp;
+ int error = 0;
inp = sotoinpcb(so);
if (inp == 0) {
- m_freem(m);
- return EINVAL;
+ error = EINVAL;
+ goto bad;
}
- if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) {
+ if (addr) {
+ if (addr->sa_len != sizeof(struct sockaddr_in6)) {
+ error = EINVAL;
+ goto bad;
+ }
+ if (addr->sa_family != AF_INET6) {
+ error = EAFNOSUPPORT;
+ goto bad;
+ }
+ }
+
+ if (ip6_mapped_addr_on) {
int hasv4addr;
struct sockaddr_in6 *sin6 = 0;
@@ -813,7 +730,6 @@ udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
}
if (hasv4addr) {
struct pr_usrreqs *pru;
- int error;
if (sin6)
in6_sin6_2_sin_in_sock(addr);
@@ -826,6 +742,10 @@ udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
}
return udp6_output(inp, m, addr, control, p);
+
+ bad:
+ m_freem(m);
+ return(error);
}
struct pr_usrreqs udp6_usrreqs = {
diff --git a/sys/netinet6/udp6_var.h b/sys/netinet6/udp6_var.h
index efadb7ffcf08..5c3efbc61c91 100644
--- a/sys/netinet6/udp6_var.h
+++ b/sys/netinet6/udp6_var.h
@@ -65,7 +65,7 @@
*/
#ifndef _NETINET6_UDP6_VAR_H_
-#define _NETINET6_UDP6_VAR_H_
+#define _NETINET6_UDP6_VAR_H_
#ifdef _KERNEL
SYSCTL_DECL(_net_inet6_udp6);
diff --git a/sys/netkey/key.c b/sys/netkey/key.c
index f00792d00d50..7af4a26ea556 100644
--- a/sys/netkey/key.c
+++ b/sys/netkey/key.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: key.c,v 1.137 2000/06/24 00:47:07 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,12 +28,8 @@
* 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.
- *
- * $FreeBSD$
*/
-/* KAME $Id: key.c,v 1.1.6.5.2.19 1999/07/22 14:09:24 itojun Exp $ */
-
/*
* This code is referd to RFC 2367
*/
@@ -62,16 +61,21 @@
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_var.h>
-#include <netinet/in_pcb.h>
#ifdef INET6
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/in6_var.h>
+#include <netinet6/ip6_var.h>
+#endif /* INET6 */
+
+#ifdef INET
+#include <netinet/in_pcb.h>
+#endif
+#ifdef INET6
#include <netinet6/in6_pcb.h>
#endif /* INET6 */
#include <net/pfkeyv2.h>
-#include <netkey/key_var.h>
#include <netkey/keydb.h>
#include <netkey/key.h>
#include <netkey/keysock.h>
@@ -82,9 +86,11 @@
#endif
#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
#ifdef IPSEC_ESP
@@ -93,15 +99,37 @@
#include <netinet6/esp6.h>
#endif
#endif
+#include <netinet6/ipcomp.h>
-MALLOC_DEFINE(M_SECA, "key mgmt", "security associations, key management");
+#include <machine/stdarg.h>
-#if defined(IPSEC_DEBUG)
+#include <net/net_osdep.h>
+
+#ifndef offsetof
+#define offsetof(type, member) ((size_t)(&((type *)0)->member))
+#endif
+#ifndef satosin
+#define satosin(s) ((struct sockaddr_in *)s)
+#endif
+
+/*
+ * Note on SA reference counting:
+ * - SAs that are not in DEAD state will have (total external reference + 1)
+ * following value in reference count field. they cannot be freed and are
+ * referenced from SA header.
+ * - SAs that are in DEAD state will have (total external reference)
+ * in reference count field. they are ready to be freed. reference from
+ * SA header will be removed in key_delsav(), when the reference count
+ * field hits 0 (= no external reference other than from SA header.
+ */
+
+#ifdef IPSEC_DEBUG
u_int32_t key_debug_level = 0;
-#endif /* defined(IPSEC_DEBUG) */
+#endif
static u_int key_spi_trycnt = 1000;
static u_int32_t key_spi_minval = 0x100;
static u_int32_t key_spi_maxval = 0x0fffffff; /* XXX */
+static u_int32_t policy_id = 0;
static u_int key_int_random = 60; /*interval to initialize randseed,1(m)*/
static u_int key_larval_lifetime = 30; /* interval to expire acquiring, 30(s)*/
static int key_blockacq_count = 10; /* counter for blocking SADB_ACQUIRE.*/
@@ -117,12 +145,17 @@ static LIST_HEAD(_regtree, secreg) regtree[SADB_SATYPE_MAX + 1];
#ifndef IPSEC_NONBLOCK_ACQUIRE
static LIST_HEAD(_acqtree, secacq) acqtree; /* acquiring list */
#endif
+static LIST_HEAD(_spacqtree, secspacq) spacqtree; /* SP acquiring list */
struct key_cb key_cb;
/* search order for SAs */
static u_int saorder_state_valid[] = {
- SADB_SASTATE_MATURE, SADB_SASTATE_DYING
+ SADB_SASTATE_DYING, SADB_SASTATE_MATURE,
+ /*
+ * This order is important because we must select a oldest SA
+ * for outbound processing. For inbound, This is not important.
+ */
};
static u_int saorder_state_alive[] = {
/* except DEAD */
@@ -133,10 +166,59 @@ static u_int saorder_state_any[] = {
SADB_SASTATE_LARVAL, SADB_SASTATE_DEAD
};
-#if defined(IPSEC_DEBUG)
+static const int minsize[] = {
+ sizeof(struct sadb_msg), /* SADB_EXT_RESERVED */
+ sizeof(struct sadb_sa), /* SADB_EXT_SA */
+ sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_CURRENT */
+ sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_HARD */
+ sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_SOFT */
+ sizeof(struct sadb_address), /* SADB_EXT_ADDRESS_SRC */
+ sizeof(struct sadb_address), /* SADB_EXT_ADDRESS_DST */
+ sizeof(struct sadb_address), /* SADB_EXT_ADDRESS_PROXY */
+ sizeof(struct sadb_key), /* SADB_EXT_KEY_AUTH */
+ sizeof(struct sadb_key), /* SADB_EXT_KEY_ENCRYPT */
+ sizeof(struct sadb_ident), /* SADB_EXT_IDENTITY_SRC */
+ sizeof(struct sadb_ident), /* SADB_EXT_IDENTITY_DST */
+ sizeof(struct sadb_sens), /* SADB_EXT_SENSITIVITY */
+ sizeof(struct sadb_prop), /* SADB_EXT_PROPOSAL */
+ sizeof(struct sadb_supported), /* SADB_EXT_SUPPORTED_AUTH */
+ sizeof(struct sadb_supported), /* SADB_EXT_SUPPORTED_ENCRYPT */
+ sizeof(struct sadb_spirange), /* SADB_EXT_SPIRANGE */
+ 0, /* SADB_X_EXT_KMPRIVATE */
+ sizeof(struct sadb_x_policy), /* SADB_X_EXT_POLICY */
+ sizeof(struct sadb_x_sa2), /* SADB_X_SA2 */
+};
+static const int maxsize[] = {
+ sizeof(struct sadb_msg), /* SADB_EXT_RESERVED */
+ sizeof(struct sadb_sa), /* SADB_EXT_SA */
+ sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_CURRENT */
+ sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_HARD */
+ sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_SOFT */
+ 0, /* SADB_EXT_ADDRESS_SRC */
+ 0, /* SADB_EXT_ADDRESS_DST */
+ 0, /* SADB_EXT_ADDRESS_PROXY */
+ 0, /* SADB_EXT_KEY_AUTH */
+ 0, /* SADB_EXT_KEY_ENCRYPT */
+ 0, /* SADB_EXT_IDENTITY_SRC */
+ 0, /* SADB_EXT_IDENTITY_DST */
+ 0, /* SADB_EXT_SENSITIVITY */
+ 0, /* SADB_EXT_PROPOSAL */
+ 0, /* SADB_EXT_SUPPORTED_AUTH */
+ 0, /* SADB_EXT_SUPPORTED_ENCRYPT */
+ sizeof(struct sadb_spirange), /* SADB_EXT_SPIRANGE */
+ 0, /* SADB_X_EXT_KMPRIVATE */
+ 0, /* SADB_X_EXT_POLICY */
+ sizeof(struct sadb_x_sa2), /* SADB_X_SA2 */
+};
+
+#ifdef SYSCTL_DECL
+SYSCTL_DECL(_net_key);
+#endif
+
+#ifdef IPSEC_DEBUG
SYSCTL_INT(_net_key, KEYCTL_DEBUG_LEVEL, debug, CTLFLAG_RW, \
&key_debug_level, 0, "");
-#endif /* defined(IPSEC_DEBUG) */
+#endif
/* max count of trial for the decision of spi value */
SYSCTL_INT(_net_key, KEYCTL_SPI_TRY, spi_trycnt, CTLFLAG_RW, \
@@ -155,7 +237,7 @@ SYSCTL_INT(_net_key, KEYCTL_RANDOM_INT, int_random, CTLFLAG_RW, \
&key_int_random, 0, "");
/* lifetime for larval SA */
-SYSCTL_INT(_net_key, KEYCTL_LARVAL_LIFETIME, larval_lifetime, CTLFLAG_RW, \
+SYSCTL_INT(_net_key, KEYCTL_LARVAL_LIFETIME, larval_lifetime, CTLFLAG_RW, \
&key_larval_lifetime, 0, "");
/* counter for blocking to send SADB_ACQUIRE to IKEd */
@@ -163,43 +245,75 @@ SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_COUNT, blockacq_count, CTLFLAG_RW, \
&key_blockacq_count, 0, "");
/* lifetime for blocking to send SADB_ACQUIRE to IKEd */
-SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \
+SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \
&key_blockacq_lifetime, 0, "");
-#define __LIST_FOREACH(elm, head, field) \
+static const int ipsec_esp_keymin = 256;
+static const int ipsec_esp_auth = 0;
+static const int ipsec_ah_keymin = 128;
+
+#ifndef LIST_FOREACH
+#define LIST_FOREACH(elm, head, field) \
for (elm = LIST_FIRST(head); elm; elm = LIST_NEXT(elm, field))
-#define __LIST_CHAINED(elm) \
+#endif
+#define __LIST_CHAINED(elm) \
(!((elm)->chain.le_next == NULL && (elm)->chain.le_prev == NULL))
+#define LIST_INSERT_TAIL(head, elm, type, field) \
+do {\
+ struct type *curelm = LIST_FIRST(head); \
+ if (curelm == NULL) {\
+ LIST_INSERT_HEAD(head, elm, field); \
+ } else { \
+ while (LIST_NEXT(curelm, field)) \
+ curelm = LIST_NEXT(curelm, field);\
+ LIST_INSERT_AFTER(curelm, elm, field);\
+ }\
+} while (0)
-#define KEY_CHKSASTATE(head, sav, name) { \
+#define KEY_CHKSASTATE(head, sav, name) \
+do { \
if ((head) != (sav)) { \
printf("%s: state mismatched (TREE=%d SA=%d)\n", \
(name), (head), (sav)); \
continue; \
} \
-}
+} while (0)
-#define KEY_CHKSPDIR(head, sp, name) { \
+#define KEY_CHKSPDIR(head, sp, name) \
+do { \
if ((head) != (sp)) { \
printf("%s: direction mismatched (TREE=%d SP=%d), " \
"anyway continue.\n", \
(name), (head), (sp)); \
} \
-}
+} while (0)
-#define KMALLOC(p, t, n) \
+#if 1
+#define KMALLOC(p, t, n) \
((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT))
-#define KFREE(p) \
+#define KFREE(p) \
free((caddr_t)(p), M_SECA);
+#else
+#define KMALLOC(p, t, n) \
+do { \
+ ((p) = (t)malloc((unsigned long)(n), M_SECA, M_NOWAIT)); \
+ printf("%s %d: %p <- KMALLOC(%s, %d)\n", \
+ __FILE__, __LINE__, (p), #t, n); \
+} while (0)
-#define KEY_NEWBUF(dst, t, src, len) \
- ((dst) = (t)key_newbuf((src), (len)))
+#define KFREE(p) \
+ do { \
+ printf("%s %d: %p -> KFREE()\n", __FILE__, __LINE__, (p)); \
+ free((caddr_t)(p), M_SECA); \
+ } while (0)
+#endif
/*
* set parameters into secpolicyindex buffer.
* Must allocate secpolicyindex buffer passed to this function.
*/
-#define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, idx) do { \
+#define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, idx) \
+do { \
bzero((idx), sizeof(struct secpolicyindex)); \
(idx)->dir = (_dir); \
(idx)->prefs = (ps); \
@@ -213,10 +327,12 @@ SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \
* set parameters into secasindex buffer.
* Must allocate secasindex buffer before calling this function.
*/
-#define KEY_SETSECASIDX(p, m, s, d, idx) do { \
+#define KEY_SETSECASIDX(p, m, r, s, d, idx) \
+do { \
bzero((idx), sizeof(struct secasindex)); \
(idx)->proto = (p); \
(idx)->mode = (m); \
+ (idx)->reqid = (r); \
bcopy((s), &(idx)->src, ((struct sockaddr *)(s))->sa_len); \
bcopy((d), &(idx)->dst, ((struct sockaddr *)(d))->sa_len); \
} while (0)
@@ -226,85 +342,139 @@ struct _keystat {
u_long getspi_count; /* the avarage of count to try to get new SPI */
} keystat;
-static struct secasvar *key_allocsa_policy __P((struct ipsecrequest *isr));
-static void key_freesp_so __P((struct secpolicy **sp));
-static struct secasvar *key_do_allocsa_policy __P((struct secashead *sah,
- u_int state));
-static void key_delsp __P((struct secpolicy *sp));
-static struct secpolicy *key_getsp __P((struct secpolicyindex *spidx));
-static struct sadb_msg *key_spdadd __P((caddr_t *mhp));
-static struct sadb_msg *key_spddelete __P((caddr_t *mhp));
-static struct sadb_msg *key_spdflush __P((caddr_t *mhp));
-static int key_spddump __P((caddr_t *mhp, struct socket *so, int target));
-static u_int key_setdumpsp __P((struct sadb_msg *newmsg, struct secpolicy *sp,
- u_int8_t type, u_int32_t seq, u_int32_t pid));
-static u_int key_getspmsglen __P((struct secpolicy *sp));
-static u_int key_getspreqmsglen __P((struct secpolicy *sp));
-static struct secashead *key_newsah __P((struct secasindex *saidx));
-static void key_delsah __P((struct secashead *sah));
-static struct secasvar *key_newsav __P((caddr_t *mhp, struct secashead *sah));
-static void key_delsav __P((struct secasvar *sav));
-static struct secashead *key_getsah __P((struct secasindex *saidx));
-static struct secasvar *key_checkspidup __P((struct secasindex *saidx,
- u_int32_t spi));
-static struct secasvar *key_getsavbyspi __P((struct secashead *sah,
- u_int32_t spi));
-static int key_setsaval __P((struct secasvar *sav, caddr_t *mhp));
-static u_int key_getmsglen __P((struct secasvar *sav));
-static int key_mature __P((struct secasvar *sav));
-static u_int key_setdumpsa __P((struct sadb_msg *newmsg, struct secasvar *sav,
- u_int8_t type, u_int8_t satype,
- u_int32_t seq, u_int32_t pid));
-static caddr_t key_setsadbmsg __P((caddr_t buf, u_int8_t type, int tlen,
- u_int8_t satype, u_int32_t seq, pid_t pid,
- u_int8_t reserved1, u_int8_t reserved2));
-static caddr_t key_setsadbsa __P((caddr_t buf, struct secasvar *sav));
-static caddr_t key_setsadbaddr __P((caddr_t buf, u_int16_t exttype,
- struct sockaddr *saddr, u_int8_t prefixlen, u_int16_t ul_proto));
-static caddr_t key_setsadbident
- __P((caddr_t buf, u_int16_t exttype, u_int16_t idtype,
- caddr_t string, int stringlen, u_int64_t id));
-static caddr_t key_setsadbext __P((caddr_t p, caddr_t ext));
-static void *key_newbuf __P((void *src, u_int len));
+struct sadb_msghdr {
+ struct sadb_msg *msg;
+ struct sadb_ext *ext[SADB_EXT_MAX + 1];
+ int extoff[SADB_EXT_MAX + 1];
+ int extlen[SADB_EXT_MAX + 1];
+};
+
+static struct secasvar *key_allocsa_policy __P((struct secasindex *));
+static void key_freesp_so __P((struct secpolicy **));
+static struct secasvar *key_do_allocsa_policy __P((struct secashead *, u_int));
+static void key_delsp __P((struct secpolicy *));
+static struct secpolicy *key_getsp __P((struct secpolicyindex *));
+static struct secpolicy *key_getspbyid __P((u_int32_t));
+static u_int32_t key_newreqid __P((void));
+static struct mbuf *key_gather_mbuf __P((struct mbuf *,
+ const struct sadb_msghdr *, int, int, ...));
+static int key_spdadd __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+static u_int32_t key_getnewspid __P((void));
+static int key_spddelete __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+static int key_spddelete2 __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+static int key_spdget __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+static int key_spdflush __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+static int key_spddump __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+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 struct secashead *key_newsah __P((struct secasindex *));
+static void key_delsah __P((struct secashead *));
+static struct secasvar *key_newsav __P((struct mbuf *,
+ const struct sadb_msghdr *, struct secashead *, int *));
+static void key_delsav __P((struct secasvar *));
+static struct secashead *key_getsah __P((struct secasindex *));
+static struct secasvar *key_checkspidup __P((struct secasindex *, u_int32_t));
+static struct secasvar *key_getsavbyspi __P((struct secashead *, u_int32_t));
+static int key_setsaval __P((struct secasvar *, struct mbuf *,
+ const struct sadb_msghdr *));
+static int key_mature __P((struct secasvar *));
+static struct mbuf *key_setdumpsa __P((struct secasvar *, u_int8_t,
+ u_int8_t, u_int32_t, u_int32_t));
+static struct mbuf *key_setsadbmsg __P((u_int8_t, u_int16_t, u_int8_t,
+ u_int32_t, pid_t, u_int16_t));
+static struct mbuf *key_setsadbsa __P((struct secasvar *));
+static struct mbuf *key_setsadbaddr __P((u_int16_t,
+ struct sockaddr *, u_int8_t, u_int16_t));
+#if 0
+static struct mbuf *key_setsadbident __P((u_int16_t, u_int16_t, caddr_t,
+ int, u_int64_t));
+#endif
+static struct mbuf *key_setsadbxsa2(u_int8_t, u_int32_t);
+static struct mbuf *key_setsadbxpolicy __P((u_int16_t, u_int8_t,
+ u_int32_t));
+static void *key_newbuf __P((const void *, u_int));
#ifdef INET6
-static int key_ismyaddr6 __P((caddr_t addr));
+static int key_ismyaddr6 __P((struct sockaddr_in6 *));
#endif
static int key_cmpsaidx_exactly
- __P((struct secasindex *saidx0, struct secasindex *saidx1));
+ __P((struct secasindex *, struct secasindex *));
static int key_cmpsaidx_withmode
- __P((struct secasindex *saidx0, struct secasindex *saidx1));
+ __P((struct secasindex *, struct secasindex *));
+static int key_cmpsaidx_withoutmode
+ __P((struct secasindex *, struct secasindex *));
static int key_cmpspidx_exactly
- __P((struct secpolicyindex *spidx0, struct secpolicyindex *spidx1));
+ __P((struct secpolicyindex *, struct secpolicyindex *));
static int key_cmpspidx_withmask
- __P((struct secpolicyindex *spidx0, struct secpolicyindex *spidx1));
-static int key_bbcmp __P((caddr_t p1, caddr_t p2, u_int bits));
-static u_int16_t key_satype2proto __P((u_int8_t satype));
-static u_int8_t key_proto2satype __P((u_int16_t proto));
-
-static struct sadb_msg *key_getspi __P((caddr_t *mhp));
-static u_int32_t key_do_getnewspi __P((struct sadb_spirange *spirange,
- struct secasindex *saidx));
-static struct sadb_msg *key_update __P((caddr_t *mhp));
-static struct secasvar *key_getsavbyseq __P((struct secashead *sah,
- u_int32_t seq));
-static struct sadb_msg *key_add __P((caddr_t *mhp));
-static struct sadb_msg *key_getmsgbuf_x1 __P((caddr_t *mhp));
-static struct sadb_msg *key_delete __P((caddr_t *mhp));
-static struct sadb_msg *key_get __P((caddr_t *mhp));
-static int key_acquire __P((struct secasindex *saidx,
- struct secpolicyindex *spidx));
-static struct secacq *key_newacq __P((struct secasindex *saidx));
-static struct secacq *key_getacq __P((struct secasindex *saidx));
-static struct secacq *key_getacqbyseq __P((u_int32_t seq));
-static struct sadb_msg *key_acquire2 __P((caddr_t *mhp));
-static struct sadb_msg *key_register __P((caddr_t *mhp, struct socket *so));
-static int key_expire __P((struct secasvar *sav));
-static struct sadb_msg *key_flush __P((caddr_t *mhp));
-static int key_dump __P((caddr_t *mhp, struct socket *so, int target));
-static void key_promisc __P((caddr_t *mhp, struct socket *so));
-static int key_sendall __P((struct sadb_msg *msg, u_int len));
-static int key_align __P((struct sadb_msg *msg, caddr_t *mhp));
-static void key_sa_chgstate __P((struct secasvar *sav, u_int8_t state));
+ __P((struct secpolicyindex *, struct secpolicyindex *));
+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));
+
+static int key_getspi __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+static u_int32_t key_do_getnewspi __P((struct sadb_spirange *,
+ struct secasindex *));
+static int key_update __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+#ifdef IPSEC_DOSEQCHECK
+static struct secasvar *key_getsavbyseq __P((struct secashead *, u_int32_t));
+#endif
+static int key_add __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+static int key_setident __P((struct secashead *, struct mbuf *,
+ const struct sadb_msghdr *));
+static struct mbuf *key_getmsgbuf_x1 __P((struct mbuf *,
+ const struct sadb_msghdr *));
+static int key_delete __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+static int key_get __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+
+#ifdef IPSEC_ESP
+static struct mbuf *key_getcomb_esp __P((void));
+#endif
+static struct mbuf *key_getcomb_ah __P((void));
+static struct mbuf *key_getprop __P((const struct secasindex *));
+
+static int key_acquire __P((struct secasindex *, struct secpolicy *));
+#ifndef IPSEC_NONBLOCK_ACQUIRE
+static struct secacq *key_newacq __P((struct secasindex *));
+static struct secacq *key_getacq __P((struct secasindex *));
+static struct secacq *key_getacqbyseq __P((u_int32_t));
+#endif
+static struct secspacq *key_newspacq __P((struct secpolicyindex *));
+static struct secspacq *key_getspacq __P((struct secpolicyindex *));
+static int key_acquire2 __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+static int key_register __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+static int key_expire __P((struct secasvar *));
+static int key_flush __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+static int key_dump __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+static int key_promisc __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+static int key_senderror __P((struct socket *, struct mbuf *, int));
+static int key_validate_ext __P((const struct sadb_ext *, int));
+static int key_align __P((struct mbuf *, struct sadb_msghdr *));
+#if 0
+static const char *key_getfqdn __P((void));
+static const char *key_getuserfqdn __P((void));
+#endif
+static void key_sa_chgstate __P((struct secasvar *, u_int8_t));
+static struct mbuf *key_alloc_mbuf __P((int));
+
/* %%% IPsec policy management */
/*
* allocating a SP for OUTBOUND or INBOUND packet.
@@ -339,7 +509,7 @@ key_allocsp(spidx, dir)
printf("*** objects\n");
kdebug_secpolicyindex(spidx));
- __LIST_FOREACH(sp, &sptree[dir], chain) {
+ LIST_FOREACH(sp, &sptree[dir], chain) {
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
printf("*** in SPD\n");
kdebug_secpolicyindex(&sp->spidx));
@@ -368,23 +538,25 @@ found:
}
/*
+ * allocating a SA entry for a *OUTBOUND* packet.
* checking each request entries in SP, and acquire SA if need.
* OUT: 0: there are valid requests.
* ENOENT: policy may be valid, but SA with REQUIRE is on acquiring.
*/
int
-key_checkrequest(isr)
+key_checkrequest(isr, saidx)
struct ipsecrequest *isr;
+ struct secasindex *saidx;
{
u_int level;
int error;
/* sanity check */
- if (isr == NULL)
+ if (isr == NULL || saidx == NULL)
panic("key_checkrequest: NULL pointer is passed.\n");
/* check mode */
- switch (isr->saidx.mode) {
+ switch (saidx->mode) {
case IPSEC_MODE_TRANSPORT:
case IPSEC_MODE_TUNNEL:
break;
@@ -396,43 +568,60 @@ key_checkrequest(isr)
/* get current level */
level = ipsec_get_reqlevel(isr);
+#if 0
/*
- * We don't allocate new SA if the state of SA in the holder is
- * SADB_SASTATE_MATURE, and if this is newer one.
+ * We do allocate new SA only if the state of SA in the holder is
+ * SADB_SASTATE_DEAD. The SA for outbound must be the oldest.
*/
if (isr->sav != NULL) {
- /*
- * XXX While SA is hanging on policy request(isr), its refcnt
- * can not be zero. So isr->sav->sah is valid pointer if
- * isr->sav != NULL. But that may not be true in fact.
- * There may be missunderstanding by myself. Anyway I set
- * zero to isr->sav->sah when isr->sav is flushed.
- * I must check to have conviction this issue.
- */
- if (isr->sav->sah != NULL
- && isr->sav != (struct secasvar *)LIST_FIRST(
- &isr->sav->sah->savtree[SADB_SASTATE_MATURE])) {
+ if (isr->sav->sah == NULL)
+ panic("key_checkrequest: sah is null.\n");
+ if (isr->sav == (struct secasvar *)LIST_FIRST(
+ &isr->sav->sah->savtree[SADB_SASTATE_DEAD])) {
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
printf("DP checkrequest calls free SA:%p\n",
isr->sav));
key_freesav(isr->sav);
+ isr->sav = NULL;
}
+ }
+#else
+ /*
+ * we free any SA stashed in the IPsec request because a different
+ * SA may be involved each time this request is checked, either
+ * because new SAs are being configured, or this request is
+ * associated with an unconnected datagram socket, or this request
+ * is associated with a system default policy.
+ *
+ * The operation may have negative impact to performance. We may
+ * want to check cached SA carefully, rather than picking new SA
+ * every time.
+ */
+ if (isr->sav != NULL) {
+ key_freesav(isr->sav);
isr->sav = NULL;
}
+#endif
- /* new SA allocation if no SA found. */
+ /*
+ * new SA allocation if no SA found.
+ * key_allocsa_policy should allocate the oldest SA available.
+ * See key_do_allocsa_policy(), and draft-jenkins-ipsec-rekeying-03.txt.
+ */
if (isr->sav == NULL)
- isr->sav = key_allocsa_policy(isr);
+ isr->sav = key_allocsa_policy(saidx);
/* When there is SA. */
if (isr->sav != NULL)
return 0;
/* there is no SA */
- if ((error = key_acquire(&isr->saidx, &isr->sp->spidx)) != 0) {
+ if ((error = key_acquire(saidx, isr->sp)) != 0) {
/* XXX What I do ? */
+#ifdef IPSEC_DEBUG
printf("key_checkrequest: error %d returned "
"from key_acquire.\n", error);
+#endif
return error;
}
@@ -446,17 +635,17 @@ key_checkrequest(isr)
* others: found and return the pointer.
*/
static struct secasvar *
-key_allocsa_policy(isr)
- struct ipsecrequest *isr;
+key_allocsa_policy(saidx)
+ struct secasindex *saidx;
{
struct secashead *sah;
struct secasvar *sav;
u_int stateidx, state;
- __LIST_FOREACH(sah, &sahtree, chain) {
+ LIST_FOREACH(sah, &sahtree, chain) {
if (sah->state == SADB_SASTATE_DEAD)
continue;
- if (key_cmpsaidx_withmode(&sah->saidx, &isr->saidx))
+ if (key_cmpsaidx_withmode(&sah->saidx, saidx))
goto found;
}
@@ -496,7 +685,7 @@ key_do_allocsa_policy(sah, state)
/* initilize */
candidate = NULL;
- __LIST_FOREACH(sav, &sah->savtree[state], chain) {
+ LIST_FOREACH(sav, &sah->savtree[state], chain) {
/* sanity check */
KEY_CHKSASTATE(sav->state, state, "key_do_allocsa_policy");
@@ -510,15 +699,12 @@ key_do_allocsa_policy(sah, state)
/* Which SA is the better ? */
/* sanity check 2 */
- if (candidate->lft_c == NULL || sav->lft_c == NULL) {
- /*XXX do panic ? */
- printf("key_do_allocsa_policy: "
+ if (candidate->lft_c == NULL || sav->lft_c == NULL)
+ panic("key_do_allocsa_policy: "
"lifetime_current is NULL.\n");
- continue;
- }
/* XXX What the best method is to compare ? */
- if (candidate->lft_c->sadb_lifetime_addtime <
+ if (candidate->lft_c->sadb_lifetime_addtime >
sav->lft_c->sadb_lifetime_addtime) {
candidate = sav;
continue;
@@ -540,6 +726,15 @@ key_do_allocsa_policy(sah, state)
* Must call key_freesav() later.
* OUT: positive: pointer to a sav.
* NULL: not found, or error occured.
+ *
+ * In the comparison, source address will be ignored for RFC2401 conformance.
+ * To quote, from section 4.1:
+ * A security association is uniquely identified by a triple consisting
+ * of a Security Parameter Index (SPI), an IP Destination Address, and a
+ * security protocol (AH or ESP) identifier.
+ * Note that, however, we do need to keep source address in IPsec SA.
+ * IKE specification and PF_KEY specification do assume that we
+ * keep source address in IPsec SA. We see a tricky situation here.
*/
struct secasvar *
key_allocsa(family, src, dst, proto, spi)
@@ -550,6 +745,8 @@ key_allocsa(family, src, dst, proto, spi)
struct secashead *sah;
struct secasvar *sav;
u_int stateidx, state;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
int s;
/* sanity check */
@@ -563,30 +760,96 @@ key_allocsa(family, src, dst, proto, spi)
* encrypted so we can't check internal IP header.
*/
s = splnet(); /*called from softclock()*/
- __LIST_FOREACH(sah, &sahtree, chain) {
-
+ LIST_FOREACH(sah, &sahtree, chain) {
/* search valid state */
for (stateidx = 0;
stateidx < _ARRAYLEN(saorder_state_valid);
stateidx++) {
-
state = saorder_state_valid[stateidx];
- __LIST_FOREACH(sav, &sah->savtree[state], chain) {
-
+ LIST_FOREACH(sav, &sah->savtree[state], chain) {
/* sanity check */
KEY_CHKSASTATE(sav->state, state, "key_allocsav");
if (proto != sav->sah->saidx.proto)
continue;
if (spi != sav->spi)
continue;
+ if (family != sav->sah->saidx.src.ss_family ||
+ family != sav->sah->saidx.dst.ss_family)
+ continue;
- if (key_bbcmp(src,
- _INADDRBYSA(&sav->sah->saidx.src),
- _INALENBYAF(sav->sah->saidx.src.ss_family) << 3)
- && key_bbcmp(dst,
- _INADDRBYSA(&sav->sah->saidx.dst),
- _INALENBYAF(sav->sah->saidx.dst.ss_family) << 3))
- goto found;
+#if 0 /* don't check src */
+ /* check src address */
+ switch (family) {
+ case AF_INET:
+ bzero(&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(sin);
+ bcopy(src, &sin.sin_addr,
+ sizeof(sin.sin_addr));
+ if (key_sockaddrcmp((struct sockaddr*)&sin,
+ (struct sockaddr *)&sav->sah->saidx.src, 0) != 0)
+ continue;
+
+ break;
+ case AF_INET6:
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(sin6);
+ bcopy(src, &sin6.sin6_addr,
+ sizeof(sin6.sin6_addr));
+ if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) {
+ /* kame fake scopeid */
+ sin6.sin6_scope_id =
+ ntohs(sin6.sin6_addr.s6_addr16[1]);
+ sin6.sin6_addr.s6_addr16[1] = 0;
+ }
+ if (key_sockaddrcmp((struct sockaddr*)&sin6,
+ (struct sockaddr *)&sav->sah->saidx.src, 0) != 0)
+ continue;
+ break;
+ default:
+ printf("key_allocsa: unknown address family=%d.\n",
+ family);
+ continue;
+ }
+
+#endif
+ /* check dst address */
+ switch (family) {
+ case AF_INET:
+ bzero(&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(sin);
+ bcopy(dst, &sin.sin_addr,
+ sizeof(sin.sin_addr));
+ if (key_sockaddrcmp((struct sockaddr*)&sin,
+ (struct sockaddr *)&sav->sah->saidx.dst, 0) != 0)
+ continue;
+
+ break;
+ case AF_INET6:
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(sin6);
+ bcopy(dst, &sin6.sin6_addr,
+ sizeof(sin6.sin6_addr));
+ if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) {
+ /* kame fake scopeid */
+ sin6.sin6_scope_id =
+ ntohs(sin6.sin6_addr.s6_addr16[1]);
+ sin6.sin6_addr.s6_addr16[1] = 0;
+ }
+ if (key_sockaddrcmp((struct sockaddr*)&sin6,
+ (struct sockaddr *)&sav->sah->saidx.dst, 0) != 0)
+ continue;
+ break;
+ default:
+ printf("key_allocsa: unknown address family=%d.\n",
+ family);
+ continue;
+ }
+
+ goto found;
}
}
}
@@ -656,6 +919,15 @@ key_freeso(so)
#ifdef INET6
case PF_INET6:
{
+#ifdef HAVE_NRL_INPCB
+ struct inpcb *pcb = sotoinpcb(so);
+
+ /* Does it have a PCB ? */
+ if (pcb == NULL)
+ return;
+ key_freesp_so(&pcb->inp_sp->sp_in);
+ key_freesp_so(&pcb->inp_sp->sp_out);
+#else
struct in6pcb *pcb = sotoin6pcb(so);
/* Does it have a PCB ? */
@@ -663,12 +935,15 @@ key_freeso(so)
return;
key_freesp_so(&pcb->in6p_sp->sp_in);
key_freesp_so(&pcb->in6p_sp->sp_out);
+#endif
}
break;
#endif /* INET6 */
default:
+#ifdef IPSEC_DEBUG
printf("key_freeso: unknown address family=%d.\n",
so->so_proto->pr_domain->dom_family);
+#endif
return;
}
@@ -766,7 +1041,7 @@ key_delsp(sp)
}
}
- KFREE(sp);
+ keydb_delsecpolicy(sp);
splx(s);
@@ -788,7 +1063,7 @@ key_getsp(spidx)
if (spidx == NULL)
panic("key_getsp: NULL pointer is passed.\n");
- __LIST_FOREACH(sp, &sptree[spidx->dir], chain) {
+ LIST_FOREACH(sp, &sptree[spidx->dir], chain) {
if (sp->state == IPSEC_SPSTATE_DEAD)
continue;
if (key_cmpspidx_exactly(spidx, &sp->spidx)) {
@@ -800,17 +1075,46 @@ key_getsp(spidx)
return NULL;
}
+/*
+ * get SP by index.
+ * OUT: NULL : not found
+ * others : found, pointer to a SP.
+ */
+static struct secpolicy *
+key_getspbyid(id)
+ u_int32_t id;
+{
+ struct secpolicy *sp;
+
+ LIST_FOREACH(sp, &sptree[IPSEC_DIR_INBOUND], chain) {
+ if (sp->state == IPSEC_SPSTATE_DEAD)
+ continue;
+ if (sp->id == id) {
+ sp->refcnt++;
+ return sp;
+ }
+ }
+
+ LIST_FOREACH(sp, &sptree[IPSEC_DIR_OUTBOUND], chain) {
+ if (sp->state == IPSEC_SPSTATE_DEAD)
+ continue;
+ if (sp->id == id) {
+ sp->refcnt++;
+ return sp;
+ }
+ }
+
+ return NULL;
+}
+
struct secpolicy *
key_newsp()
{
struct secpolicy *newsp = NULL;
- KMALLOC(newsp, struct secpolicy *, sizeof(*newsp));
- if (newsp == NULL) {
- printf("key_newsp: No more memory.\n");
- return NULL;
- }
- bzero(newsp, sizeof(*newsp));
+ newsp = keydb_newsecpolicy();
+ if (!newsp)
+ return newsp;
newsp->refcnt = 1;
newsp->req = NULL;
@@ -824,17 +1128,30 @@ key_newsp()
* so must be set properly later.
*/
struct secpolicy *
-key_msg2sp(xpl0)
+key_msg2sp(xpl0, len, error)
struct sadb_x_policy *xpl0;
+ size_t len;
+ int *error;
{
struct secpolicy *newsp;
/* sanity check */
if (xpl0 == NULL)
panic("key_msg2sp: NULL pointer was passed.\n");
+ if (len < sizeof(*xpl0))
+ panic("key_msg2sp: invalid length.\n");
+ if (len != PFKEY_EXTLEN(xpl0)) {
+#ifdef IPSEC_DEBUG
+ printf("key_msg2sp: Invalid msg length.\n");
+#endif
+ *error = EINVAL;
+ return NULL;
+ }
- if ((newsp = key_newsp()) == NULL)
+ if ((newsp = key_newsp()) == NULL) {
+ *error = ENOBUFS;
return NULL;
+ }
newsp->spidx.dir = xpl0->sadb_x_policy_dir;
newsp->policy = xpl0->sadb_x_policy_type;
@@ -855,9 +1172,12 @@ key_msg2sp(xpl0)
struct ipsecrequest **p_isr = &newsp->req;
/* validity check */
- if (PFKEY_EXTLEN(xpl0) <= sizeof(*xpl0)) {
+ if (PFKEY_EXTLEN(xpl0) < sizeof(*xpl0)) {
+#ifdef IPSEC_DEBUG
printf("key_msg2sp: Invalid msg length.\n");
+#endif
key_freesp(newsp);
+ *error = EINVAL;
return NULL;
}
@@ -868,17 +1188,23 @@ key_msg2sp(xpl0)
/* length check */
if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) {
+#ifdef IPSEC_DEBUG
printf("key_msg2sp: "
"invalid ipsecrequest length.\n");
+#endif
key_freesp(newsp);
+ *error = EINVAL;
return NULL;
}
/* allocate request buffer */
KMALLOC(*p_isr, struct ipsecrequest *, sizeof(**p_isr));
if ((*p_isr) == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_msg2sp: No more memory.\n");
+#endif
key_freesp(newsp);
+ *error = ENOBUFS;
return NULL;
}
bzero(*p_isr, sizeof(**p_isr));
@@ -889,11 +1215,17 @@ key_msg2sp(xpl0)
switch (xisr->sadb_x_ipsecrequest_proto) {
case IPPROTO_ESP:
case IPPROTO_AH:
+#if 1 /*nonstandard*/
+ case IPPROTO_IPCOMP:
+#endif
break;
default:
+#ifdef IPSEC_DEBUG
printf("key_msg2sp: invalid proto type=%u\n",
xisr->sadb_x_ipsecrequest_proto);
+#endif
key_freesp(newsp);
+ *error = EPROTONOSUPPORT;
return NULL;
}
(*p_isr)->saidx.proto = xisr->sadb_x_ipsecrequest_proto;
@@ -904,9 +1236,12 @@ key_msg2sp(xpl0)
break;
case IPSEC_MODE_ANY:
default:
+#ifdef IPSEC_DEBUG
printf("key_msg2sp: invalid mode=%u\n",
xisr->sadb_x_ipsecrequest_mode);
+#endif
key_freesp(newsp);
+ *error = EINVAL;
return NULL;
}
(*p_isr)->saidx.mode = xisr->sadb_x_ipsecrequest_mode;
@@ -916,10 +1251,47 @@ key_msg2sp(xpl0)
case IPSEC_LEVEL_USE:
case IPSEC_LEVEL_REQUIRE:
break;
+ case IPSEC_LEVEL_UNIQUE:
+ /* validity check */
+ /*
+ * If range violation of reqid, kernel will
+ * update it, don't refuse it.
+ */
+ if (xisr->sadb_x_ipsecrequest_reqid
+ > IPSEC_MANUAL_REQID_MAX) {
+#ifdef IPSEC_DEBUG
+ printf("key_msg2sp: reqid=%d "
+ "range violation, "
+ "updated by kernel.\n",
+ xisr->sadb_x_ipsecrequest_reqid);
+#endif
+ xisr->sadb_x_ipsecrequest_reqid = 0;
+ }
+
+ /* allocate new reqid id if reqid is zero. */
+ if (xisr->sadb_x_ipsecrequest_reqid == 0) {
+ u_int32_t reqid;
+ if ((reqid = key_newreqid()) == 0) {
+ key_freesp(newsp);
+ *error = ENOBUFS;
+ return NULL;
+ }
+ (*p_isr)->saidx.reqid = reqid;
+ xisr->sadb_x_ipsecrequest_reqid = reqid;
+ } else {
+ /* set it for manual keying. */
+ (*p_isr)->saidx.reqid =
+ xisr->sadb_x_ipsecrequest_reqid;
+ }
+ break;
+
default:
+#ifdef IPSEC_DEBUG
printf("key_msg2sp: invalid level=%u\n",
xisr->sadb_x_ipsecrequest_level);
+#endif
key_freesp(newsp);
+ *error = EINVAL;
return NULL;
}
(*p_isr)->level = xisr->sadb_x_ipsecrequest_level;
@@ -933,9 +1305,12 @@ key_msg2sp(xpl0)
/* validity check */
if (paddr->sa_len
> sizeof((*p_isr)->saidx.src)) {
+#ifdef IPSEC_DEBUG
printf("key_msg2sp: invalid request "
"address length.\n");
+#endif
key_freesp(newsp);
+ *error = EINVAL;
return NULL;
}
bcopy(paddr, &(*p_isr)->saidx.src,
@@ -947,9 +1322,12 @@ key_msg2sp(xpl0)
/* validity check */
if (paddr->sa_len
> sizeof((*p_isr)->saidx.dst)) {
+#ifdef IPSEC_DEBUG
printf("key_msg2sp: invalid request "
"address length.\n");
+#endif
key_freesp(newsp);
+ *error = EINVAL;
return NULL;
}
bcopy(paddr, &(*p_isr)->saidx.dst,
@@ -965,8 +1343,11 @@ key_msg2sp(xpl0)
/* validity check */
if (tlen < 0) {
+#ifdef IPSEC_DEBUG
printf("key_msg2sp: becoming tlen < 0.\n");
+#endif
key_freesp(newsp);
+ *error = EINVAL;
return NULL;
}
@@ -976,24 +1357,42 @@ key_msg2sp(xpl0)
}
break;
default:
+#ifdef IPSEC_DEBUG
printf("key_msg2sp: invalid policy type.\n");
+#endif
key_freesp(newsp);
+ *error = EINVAL;
return NULL;
}
+ *error = 0;
return newsp;
}
+static u_int32_t
+key_newreqid()
+{
+ static u_int32_t auto_reqid = IPSEC_MANUAL_REQID_MAX + 1;
+
+ auto_reqid = (auto_reqid == ~0
+ ? IPSEC_MANUAL_REQID_MAX + 1 : auto_reqid + 1);
+
+ /* XXX should be unique check */
+
+ return auto_reqid;
+}
+
/*
* copy secpolicy struct to sadb_x_policy structure indicated.
*/
-struct sadb_x_policy *
+struct mbuf *
key_sp2msg(sp)
struct secpolicy *sp;
{
struct sadb_x_policy *xpl;
int tlen;
caddr_t p;
+ struct mbuf *m;
/* sanity check. */
if (sp == NULL)
@@ -1001,17 +1400,23 @@ key_sp2msg(sp)
tlen = key_getspreqmsglen(sp);
- KMALLOC(xpl, struct sadb_x_policy *, tlen);
- if (xpl == NULL) {
- printf("key_sp2msg: No more memory.\n");
+ m = key_alloc_mbuf(tlen);
+ if (!m || m->m_next) { /*XXX*/
+ if (m)
+ m_freem(m);
return NULL;
}
+
+ m->m_len = tlen;
+ m->m_next = NULL;
+ xpl = mtod(m, struct sadb_x_policy *);
bzero(xpl, tlen);
xpl->sadb_x_policy_len = PFKEY_UNIT64(tlen);
xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
xpl->sadb_x_policy_type = sp->policy;
xpl->sadb_x_policy_dir = sp->spidx.dir;
+ xpl->sadb_x_policy_id = sp->id;
p = (caddr_t)xpl + sizeof(*xpl);
/* if is the policy for ipsec ? */
@@ -1026,6 +1431,7 @@ key_sp2msg(sp)
xisr->sadb_x_ipsecrequest_proto = isr->saidx.proto;
xisr->sadb_x_ipsecrequest_mode = isr->saidx.mode;
xisr->sadb_x_ipsecrequest_level = isr->level;
+ xisr->sadb_x_ipsecrequest_reqid = isr->saidx.reqid;
p += sizeof(*xisr);
bcopy(&isr->saidx.src, p, isr->saidx.src.ss_len);
@@ -1040,11 +1446,96 @@ key_sp2msg(sp)
}
}
- return xpl;
+ return m;
+}
+
+/* m will not be freed nor modified */
+static struct mbuf *
+#ifdef __STDC__
+key_gather_mbuf(struct mbuf *m, const struct sadb_msghdr *mhp,
+ int ndeep, int nitem, ...)
+#else
+key_gather_mbuf(m, mhp, ndeep, nitem, va_alist)
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
+ int ndeep;
+ int nitem;
+ va_dcl
+#endif
+{
+ va_list ap;
+ int idx;
+ int i;
+ struct mbuf *result = NULL, *n;
+ int len;
+
+ if (m == NULL || mhp == NULL)
+ panic("null pointer passed to key_gather");
+
+ va_start(ap, nitem);
+ for (i = 0; i < nitem; i++) {
+ idx = va_arg(ap, int);
+ if (idx < 0 || idx > SADB_EXT_MAX)
+ goto fail;
+ /* don't attempt to pull empty extension */
+ if (idx == SADB_EXT_RESERVED && mhp->msg == NULL)
+ continue;
+ if (idx != SADB_EXT_RESERVED &&
+ (mhp->ext[idx] == NULL || mhp->extlen[idx] == 0))
+ continue;
+
+ if (idx == SADB_EXT_RESERVED) {
+ len = PFKEY_ALIGN8(sizeof(struct sadb_msg));
+#ifdef DIAGNOSTIC
+ if (len > MHLEN)
+ panic("assumption failed");
+#endif
+ MGETHDR(n, M_DONTWAIT, MT_DATA);
+ if (!n)
+ goto fail;
+ n->m_len = len;
+ n->m_next = NULL;
+ m_copydata(m, 0, sizeof(struct sadb_msg),
+ mtod(n, caddr_t));
+ } else if (i < ndeep) {
+ len = mhp->extlen[idx];
+ n = key_alloc_mbuf(len);
+ if (!n || n->m_next) { /*XXX*/
+ if (n)
+ m_freem(n);
+ goto fail;
+ }
+ m_copydata(m, mhp->extoff[idx], mhp->extlen[idx],
+ mtod(n, caddr_t));
+ } else {
+ n = m_copym(m, mhp->extoff[idx], mhp->extlen[idx],
+ M_DONTWAIT);
+ }
+ if (n == NULL)
+ goto fail;
+
+ if (result)
+ m_cat(result, n);
+ else
+ result = n;
+ }
+ va_end(ap);
+
+ if ((result->m_flags & M_PKTHDR) != 0) {
+ result->m_pkthdr.len = 0;
+ for (n = result; n; n = n->m_next)
+ result->m_pkthdr.len += n->m_len;
+ }
+
+ return result;
+
+fail:
+ m_freem(result);
+ return NULL;
}
/*
- * SADB_SPDADD processing
+ * SADB_X_SPDADD, SADB_X_SPDSETIDX or SADB_X_SPDUPDATE processing
* add a entry to SP database, when received
* <base, address(SD), policy>
* from the user(?).
@@ -1053,40 +1544,51 @@ key_sp2msg(sp)
* <base, address(SD), policy>
* to the socket which was send.
*
- * IN: mhp: pointer to the pointer to each header.
- * OUT: NULL if fail.
- * other if success, return pointer to the message to send.
+ * SPDADD set a unique policy entry.
+ * SPDSETIDX like SPDADD without a part of policy requests.
+ * SPDUPDATE replace a unique policy entry.
*
+ * m will always be freed.
*/
-static struct sadb_msg *
-key_spdadd(mhp)
- caddr_t *mhp;
+static int
+key_spdadd(so, m, mhp)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
struct sadb_address *src0, *dst0;
- struct sadb_x_policy *xpl0;
+ struct sadb_x_policy *xpl0, *xpl;
struct secpolicyindex spidx;
struct secpolicy *newsp;
+ int error;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_spdadd: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
-
- if (mhp[SADB_EXT_ADDRESS_SRC] == NULL
- || mhp[SADB_EXT_ADDRESS_DST] == NULL
- || mhp[SADB_X_EXT_POLICY] == NULL) {
+ if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL ||
+ mhp->ext[SADB_EXT_ADDRESS_DST] == NULL ||
+ mhp->ext[SADB_X_EXT_POLICY] == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_spdadd: invalid message is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+ if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) ||
+ mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address) ||
+ mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) {
+#ifdef IPSEC_DEBUG
+ printf("key_spdadd: invalid message is passed.\n");
+#endif
+ return key_senderror(so, m, EINVAL);
}
- src0 = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
- dst0 = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
- xpl0 = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
+ src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
+ dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
+ xpl0 = (struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY];
/* make secindex */
+ /* XXX boundary check against sa_len */
KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir,
src0 + 1,
dst0 + 1,
@@ -1101,35 +1603,70 @@ key_spdadd(mhp)
case IPSEC_DIR_OUTBOUND:
break;
default:
+#ifdef IPSEC_DEBUG
printf("key_spdadd: Invalid SP direction.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
- }
-
- /* Is there SP in SPD ? */
- newsp = key_getsp(&spidx);
- if (newsp != NULL) {
- key_freesp(newsp);
- printf("key_spdadd: a SP entry exists already.\n");
- msg0->sadb_msg_errno = EEXIST;
- return NULL;
+#endif
+ mhp->msg->sadb_msg_errno = EINVAL;
+ return 0;
}
/* check policy */
/* key_spdadd() accepts DISCARD, NONE and IPSEC. */
if (xpl0->sadb_x_policy_type == IPSEC_POLICY_ENTRUST
|| xpl0->sadb_x_policy_type == IPSEC_POLICY_BYPASS) {
+#ifdef IPSEC_DEBUG
printf("key_spdadd: Invalid policy type.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+
+ /* policy requests are mandatory when action is ipsec. */
+ if (mhp->msg->sadb_msg_type != SADB_X_SPDSETIDX
+ && xpl0->sadb_x_policy_type == IPSEC_POLICY_IPSEC
+ && mhp->extlen[SADB_X_EXT_POLICY] <= sizeof(*xpl0)) {
+#ifdef IPSEC_DEBUG
+ printf("key_spdadd: some policy requests part required.\n");
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+
+ /*
+ * checking there is SP already or not.
+ * If type is SPDUPDATE and no SP found, then error.
+ * If type is either SPDADD or SPDSETIDX and SP found, then error.
+ */
+ newsp = key_getsp(&spidx);
+ if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) {
+ if (newsp == NULL) {
+#ifdef IPSEC_DEBUG
+ printf("key_spdadd: no SP found.\n");
+#endif
+ return key_senderror(so, m, ENOENT);
+ }
+
+ newsp->state = IPSEC_SPSTATE_DEAD;
+ key_freesp(newsp);
+ } else {
+ if (newsp != NULL) {
+ key_freesp(newsp);
+#ifdef IPSEC_DEBUG
+ printf("key_spdadd: a SP entry exists already.\n");
+#endif
+ return key_senderror(so, m, EEXIST);
+ }
}
/* allocation new SP entry */
- if ((newsp = key_msg2sp(xpl0)) == NULL) {
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
+ if ((newsp = key_msg2sp(xpl0, PFKEY_EXTLEN(xpl0), &error)) == NULL) {
+ return key_senderror(so, m, error);
}
+ if ((newsp->id = key_getnewspid()) == 0) {
+ keydb_delsecpolicy(newsp);
+ return key_senderror(so, m, ENOBUFS);
+ }
+
+ /* XXX boundary check against sa_len */
KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir,
src0 + 1,
dst0 + 1,
@@ -1138,43 +1675,123 @@ key_spdadd(mhp)
src0->sadb_address_proto,
&newsp->spidx);
+ /* sanity check on addr pair */
+ if (((struct sockaddr *)(src0 + 1))->sa_family !=
+ ((struct sockaddr *)(dst0+ 1))->sa_family) {
+ keydb_delsecpolicy(newsp);
+ return key_senderror(so, m, EINVAL);
+ }
+ if (((struct sockaddr *)(src0 + 1))->sa_len !=
+ ((struct sockaddr *)(dst0+ 1))->sa_len) {
+ keydb_delsecpolicy(newsp);
+ return key_senderror(so, m, EINVAL);
+ }
+#if 1
+ if (newsp->req && newsp->req->saidx.src.ss_family) {
+ struct sockaddr *sa;
+ sa = (struct sockaddr *)(src0 + 1);
+ if (sa->sa_family != newsp->req->saidx.src.ss_family) {
+ keydb_delsecpolicy(newsp);
+ return key_senderror(so, m, EINVAL);
+ }
+ }
+ if (newsp->req && newsp->req->saidx.dst.ss_family) {
+ struct sockaddr *sa;
+ sa = (struct sockaddr *)(dst0 + 1);
+ if (sa->sa_family != newsp->req->saidx.dst.ss_family) {
+ keydb_delsecpolicy(newsp);
+ return key_senderror(so, m, EINVAL);
+ }
+ }
+#endif
+
newsp->refcnt = 1; /* do not reclaim until I say I do */
newsp->state = IPSEC_SPSTATE_ALIVE;
- LIST_INSERT_HEAD(&sptree[newsp->spidx.dir], newsp, chain);
+ LIST_INSERT_TAIL(&sptree[newsp->spidx.dir], newsp, secpolicy, chain);
+
+ /* delete the entry in spacqtree */
+ 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;
+ spacq->count = 0;
+ }
+ }
{
+ struct mbuf *n, *mpolicy;
struct sadb_msg *newmsg;
- u_int len;
- caddr_t p;
+ int off;
/* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg)
- + PFKEY_EXTLEN(mhp[SADB_X_EXT_POLICY])
- + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC])
- + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]);
-
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == NULL) {
- printf("key_spdadd: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
- }
- bzero((caddr_t)newmsg, len);
+ 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);
- bcopy((caddr_t)msg0, (caddr_t)newmsg, sizeof(*msg0));
+ if (n->m_len < sizeof(*newmsg)) {
+ n = m_pullup(n, sizeof(*newmsg));
+ if (!n)
+ return key_senderror(so, m, ENOBUFS);
+ }
+ newmsg = mtod(n, struct sadb_msg *);
newmsg->sadb_msg_errno = 0;
- newmsg->sadb_msg_len = PFKEY_UNIT64(len);
- p = (caddr_t)newmsg + sizeof(*msg0);
+ newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len);
- p = key_setsadbext(p, mhp[SADB_X_EXT_POLICY]);
- p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]);
- p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]);
+ off = 0;
+ mpolicy = m_pulldown(n, PFKEY_ALIGN8(sizeof(struct sadb_msg)),
+ sizeof(*xpl), &off);
+ if (mpolicy == NULL) {
+ /* n is already freed */
+ return key_senderror(so, m, ENOBUFS);
+ }
+ xpl = (struct sadb_x_policy *)(mtod(mpolicy, caddr_t) + off);
+ if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) {
+ m_freem(n);
+ return key_senderror(so, m, EINVAL);
+ }
+ xpl->sadb_x_policy_id = newsp->id;
- return newmsg;
+ m_freem(m);
+ return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
}
}
/*
+ * get new policy id.
+ * OUT:
+ * 0: failure.
+ * others: success.
+ */
+static u_int32_t
+key_getnewspid()
+{
+ u_int32_t newid = 0;
+ int count = key_spi_trycnt; /* XXX */
+ struct secpolicy *sp;
+
+ /* when requesting to allocate spi ranged */
+ while (count--) {
+ newid = (policy_id = (policy_id == ~0 ? 1 : ++policy_id));
+
+ if ((sp = key_getspbyid(newid)) == NULL)
+ break;
+
+ key_freesp(sp);
+ }
+
+ if (count == 0 || newid == 0) {
+#ifdef IPSEC_DEBUG
+ printf("key_getnewspid: to allocate policy id is failed.\n");
+#endif
+ return 0;
+ }
+
+ return newid;
+}
+
+/*
* SADB_SPDDELETE processing
* receive
* <base, address(SD), policy(*)>
@@ -1184,39 +1801,46 @@ key_spdadd(mhp)
* to the ikmpd.
* policy(*) including direction of policy.
*
- * IN: mhp: pointer to the pointer to each header.
- * OUT: other if success, return pointer to the message to send.
- * 0 if fail.
+ * m will always be freed.
*/
-static struct sadb_msg *
-key_spddelete(mhp)
- caddr_t *mhp;
+static int
+key_spddelete(so, m, mhp)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
struct sadb_address *src0, *dst0;
struct sadb_x_policy *xpl0;
struct secpolicyindex spidx;
struct secpolicy *sp;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_spddelete: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
-
- if (mhp[SADB_EXT_ADDRESS_SRC] == NULL
- || mhp[SADB_EXT_ADDRESS_DST] == NULL
- || mhp[SADB_X_EXT_POLICY] == NULL) {
+ if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL ||
+ mhp->ext[SADB_EXT_ADDRESS_DST] == NULL ||
+ mhp->ext[SADB_X_EXT_POLICY] == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_spddelete: invalid message is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+ if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) ||
+ mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address) ||
+ mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) {
+#ifdef IPSEC_DEBUG
+ printf("key_spddelete: invalid message is passed.\n");
+#endif
+ return key_senderror(so, m, EINVAL);
}
- src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
- dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
- xpl0 = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
+ src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
+ dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
+ xpl0 = (struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY];
/* make secindex */
+ /* XXX boundary check against sa_len */
KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir,
src0 + 1,
dst0 + 1,
@@ -1231,54 +1855,271 @@ key_spddelete(mhp)
case IPSEC_DIR_OUTBOUND:
break;
default:
+#ifdef IPSEC_DEBUG
printf("key_spddelete: Invalid SP direction.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
}
/* Is there SP in SPD ? */
if ((sp = key_getsp(&spidx)) == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_spddelete: no SP found.\n");
- msg0->sadb_msg_errno = ENOENT;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
}
+ /* save policy id to buffer to be returned. */
+ xpl0->sadb_x_policy_id = sp->id;
+
sp->state = IPSEC_SPSTATE_DEAD;
key_freesp(sp);
{
+ struct mbuf *n;
struct sadb_msg *newmsg;
- u_int len;
- caddr_t p;
/* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg)
- + PFKEY_EXTLEN(mhp[SADB_X_EXT_POLICY])
- + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC])
- + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]);
-
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == NULL) {
- printf("key_spddelete: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
- }
- bzero((caddr_t)newmsg, len);
+ n = key_gather_mbuf(m, mhp, 1, 4, SADB_EXT_RESERVED,
+ SADB_X_EXT_POLICY, SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST);
+ if (!n)
+ return key_senderror(so, m, ENOBUFS);
- bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0));
+ newmsg = mtod(n, struct sadb_msg *);
newmsg->sadb_msg_errno = 0;
- newmsg->sadb_msg_len = PFKEY_UNIT64(len);
- p = (caddr_t)newmsg + sizeof(*msg0);
+ newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len);
+
+ m_freem(m);
+ return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
+ }
+}
+
+/*
+ * SADB_SPDDELETE2 processing
+ * receive
+ * <base, policy(*)>
+ * from the user(?), and set SADB_SASTATE_DEAD,
+ * and send,
+ * <base, policy(*)>
+ * to the ikmpd.
+ * policy(*) including direction of policy.
+ *
+ * m will always be freed.
+ */
+static int
+key_spddelete2(so, m, mhp)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
+{
+ u_int32_t id;
+ struct secpolicy *sp;
+
+ /* sanity check */
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
+ panic("key_spddelete2: NULL pointer is passed.\n");
+
+ if (mhp->ext[SADB_X_EXT_POLICY] == NULL ||
+ mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) {
+#ifdef IPSEC_DEBUG
+ printf("key_spddelete2: invalid message is passed.\n");
+#endif
+ key_senderror(so, m, EINVAL);
+ return 0;
+ }
+
+ id = ((struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY])->sadb_x_policy_id;
+
+ /* Is there SP in SPD ? */
+ if ((sp = key_getspbyid(id)) == NULL) {
+#ifdef IPSEC_DEBUG
+ printf("key_spddelete2: no SP found id:%u.\n", id);
+#endif
+ key_senderror(so, m, EINVAL);
+ }
- p = key_setsadbext(p, mhp[SADB_X_EXT_POLICY]);
- p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]);
- p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]);
+ sp->state = IPSEC_SPSTATE_DEAD;
+ key_freesp(sp);
+
+ {
+ struct mbuf *n, *nn;
+ struct sadb_msg *newmsg;
+ int off, len;
+
+ /* create new sadb_msg to reply. */
+ len = PFKEY_ALIGN8(sizeof(struct sadb_msg));
+
+ if (len > MCLBYTES)
+ return key_senderror(so, m, ENOBUFS);
+ MGETHDR(n, M_DONTWAIT, MT_DATA);
+ if (n && len > MHLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_freem(n);
+ n = NULL;
+ }
+ }
+ if (!n)
+ return key_senderror(so, m, ENOBUFS);
+
+ n->m_len = len;
+ n->m_next = NULL;
+ off = 0;
+
+ m_copydata(m, 0, sizeof(struct sadb_msg), mtod(n, caddr_t) + off);
+ off += PFKEY_ALIGN8(sizeof(struct sadb_msg));
- return newmsg;
+#ifdef DIAGNOSTIC
+ if (off != len)
+ panic("length inconsistency in key_spddelete2");
+#endif
+
+ n->m_next = m_copym(m, mhp->extoff[SADB_X_EXT_POLICY],
+ mhp->extlen[SADB_X_EXT_POLICY], M_DONTWAIT);
+ if (!n->m_next) {
+ m_freem(n);
+ return key_senderror(so, m, ENOBUFS);
+ }
+
+ n->m_pkthdr.len = 0;
+ for (nn = n; nn; nn = nn->m_next)
+ n->m_pkthdr.len += nn->m_len;
+
+ 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_X_GET processing
+ * receive
+ * <base, policy(*)>
+ * from the user(?),
+ * and send,
+ * <base, address(SD), policy>
+ * to the ikmpd.
+ * policy(*) including direction of policy.
+ *
+ * m will always be freed.
+ */
+static int
+key_spdget(so, m, mhp)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
+{
+ u_int32_t id;
+ struct secpolicy *sp;
+ struct mbuf *n;
+
+ /* sanity check */
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
+ panic("key_spdget: NULL pointer is passed.\n");
+
+ if (mhp->ext[SADB_X_EXT_POLICY] == NULL ||
+ mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) {
+#ifdef IPSEC_DEBUG
+ printf("key_spdget: invalid message is passed.\n");
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+
+ id = ((struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY])->sadb_x_policy_id;
+
+ /* Is there SP in SPD ? */
+ if ((sp = key_getspbyid(id)) == NULL) {
+#ifdef IPSEC_DEBUG
+ printf("key_spdget: no SP found id:%u.\n", id);
+#endif
+ return key_senderror(so, m, ENOENT);
+ }
+
+ n = key_setdumpsp(sp, SADB_X_SPDGET, 0, mhp->msg->sadb_msg_pid);
+ if (n != NULL) {
+ m_freem(m);
+ return key_sendup_mbuf(so, n, KEY_SENDUP_ONE);
+ } else
+ return key_senderror(so, m, ENOBUFS);
+}
+
+/*
+ * SADB_X_SPDACQUIRE processing.
+ * Acquire policy and SA(s) for a *OUTBOUND* packet.
+ * send
+ * <base, policy(*)>
+ * to KMD, and expect to receive
+ * <base> with SADB_X_SPDACQUIRE if error occured,
+ * or
+ * <base, policy>
+ * with SADB_X_SPDUPDATE from KMD by PF_KEY.
+ * policy(*) is without policy requests.
+ *
+ * 0 : succeed
+ * others: error number
+ */
+int
+key_spdacquire(sp)
+ struct secpolicy *sp;
+{
+ struct mbuf *result = NULL, *m;
+ struct secspacq *newspacq;
+ int error;
+
+ /* sanity check */
+ if (sp == NULL)
+ panic("key_spdacquire: NULL pointer is passed.\n");
+ if (sp->req != NULL)
+ panic("key_spdacquire: called but there is request.\n");
+ if (sp->policy != IPSEC_POLICY_IPSEC)
+ panic("key_spdacquire: policy mismathed. IPsec is expected.\n");
+
+ /* get a entry to check whether sent message or not. */
+ if ((newspacq = key_getspacq(&sp->spidx)) != NULL) {
+ if (key_blockacq_count < newspacq->count) {
+ /* reset counter and do send message. */
+ newspacq->count = 0;
+ } else {
+ /* increment counter and do nothing. */
+ newspacq->count++;
+ return 0;
+ }
+ } else {
+ /* make new entry for blocking to send SADB_ACQUIRE. */
+ if ((newspacq = key_newspacq(&sp->spidx)) == NULL)
+ return ENOBUFS;
+
+ /* add to acqtree */
+ LIST_INSERT_HEAD(&spacqtree, newspacq, chain);
+ }
+
+ /* create new sadb_msg to reply. */
+ m = key_setsadbmsg(SADB_X_SPDACQUIRE, 0, 0, 0, 0, 0);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ result = m;
+
+ 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, m, KEY_SENDUP_REGISTERED);
+
+fail:
+ if (result)
+ m_freem(result);
+ return error;
+}
+
+/*
* SADB_SPDFLUSH processing
* receive
* <base>
@@ -1288,51 +2129,47 @@ key_spddelete(mhp)
* to the user.
* NOTE: what to do is only marking SADB_SASTATE_DEAD.
*
- * IN: mhp: pointer to the pointer to each header.
- * OUT: other if success, return pointer to the message to send.
- * 0 if fail.
+ * m will always be freed.
*/
-static struct sadb_msg *
-key_spdflush(mhp)
- caddr_t *mhp;
+static int
+key_spdflush(so, m, mhp)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
+ struct sadb_msg *newmsg;
struct secpolicy *sp;
u_int dir;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_spdflush: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
+ if (m->m_len != PFKEY_ALIGN8(sizeof(struct sadb_msg)))
+ return key_senderror(so, m, EINVAL);
for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
- __LIST_FOREACH(sp, &sptree[dir], chain) {
+ LIST_FOREACH(sp, &sptree[dir], chain) {
sp->state = IPSEC_SPSTATE_DEAD;
}
}
- {
- struct sadb_msg *newmsg;
- u_int len;
-
- /* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg);
-
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == NULL) {
+ if (sizeof(struct sadb_msg) > m->m_len + M_TRAILINGSPACE(m)) {
+#ifdef IPSEC_DEBUG
printf("key_spdflush: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
+#endif
+ return key_senderror(so, m, ENOBUFS);
}
- bzero((caddr_t)newmsg, len);
- bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0));
+ if (m->m_next)
+ m_freem(m->m_next);
+ m->m_next = NULL;
+ m->m_pkthdr.len = m->m_len = PFKEY_ALIGN8(sizeof(struct sadb_msg));
+ newmsg = mtod(m, struct sadb_msg *);
newmsg->sadb_msg_errno = 0;
- newmsg->sadb_msg_len = PFKEY_UNIT64(len);
+ newmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len);
- return(newmsg);
- }
+ return key_sendup_mbuf(so, m, KEY_SENDUP_ALL);
}
/*
@@ -1344,134 +2181,102 @@ key_spdflush(mhp)
* <base> .....
* to the ikmpd.
*
- * IN: mhp: pointer to the pointer to each header.
- * OUT: other if success, return pointer to the message to send.
- * 0 if fail.
+ * m will always be freed.
*/
static int
-key_spddump(mhp, so, target)
- caddr_t *mhp;
+key_spddump(so, m, mhp)
struct socket *so;
- int target;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
struct secpolicy *sp;
- int len, cnt, cnt_sanity;
- struct sadb_msg *newmsg;
+ int cnt;
u_int dir;
+ struct mbuf *n;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_spddump: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
-
/* search SPD entry and get buffer size. */
- cnt = cnt_sanity = 0;
+ cnt = 0;
for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
- __LIST_FOREACH(sp, &sptree[dir], chain) {
+ LIST_FOREACH(sp, &sptree[dir], chain) {
cnt++;
}
}
if (cnt == 0)
- return ENOENT;
+ return key_senderror(so, m, ENOENT);
- newmsg = NULL;
for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
- __LIST_FOREACH(sp, &sptree[dir], chain) {
- len = key_getspmsglen(sp);
-
- /* making buffer */
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == NULL) {
- printf("key_spddump: No more memory.\n");
- return ENOBUFS;
- }
- bzero((caddr_t)newmsg, len);
-
+ LIST_FOREACH(sp, &sptree[dir], chain) {
--cnt;
- (void)key_setdumpsp(newmsg, sp, SADB_X_SPDDUMP,
- cnt, msg0->sadb_msg_pid);
+ n = key_setdumpsp(sp, SADB_X_SPDDUMP, cnt,
+ mhp->msg->sadb_msg_pid);
- key_sendup(so, newmsg, len, target);
- KFREE(newmsg);
- newmsg = NULL;
+ if (n)
+ key_sendup_mbuf(so, n, KEY_SENDUP_ONE);
}
}
+ m_freem(m);
return 0;
}
-static u_int
-key_setdumpsp(newmsg, sp, type, seq, pid)
- struct sadb_msg *newmsg;
+static struct mbuf *
+key_setdumpsp(sp, type, seq, pid)
struct secpolicy *sp;
u_int8_t type;
u_int32_t seq, pid;
{
- u_int tlen;
- caddr_t p;
-
- tlen = key_getspmsglen(sp);
-
- p = key_setsadbmsg((caddr_t)newmsg, type, tlen,
- SADB_SATYPE_UNSPEC, seq, pid,
- IPSEC_MODE_ANY, sp->refcnt);
+ struct mbuf *result = NULL, *m;
- p = key_setsadbaddr(p,
- SADB_EXT_ADDRESS_SRC,
- (struct sockaddr *)&sp->spidx.src,
- sp->spidx.prefs,
- sp->spidx.ul_proto);
- p = key_setsadbaddr(p,
- SADB_EXT_ADDRESS_DST,
- (struct sockaddr *)&sp->spidx.dst,
- sp->spidx.prefd,
- sp->spidx.ul_proto);
+ m = key_setsadbmsg(type, 0, SADB_SATYPE_UNSPEC, seq, pid, sp->refcnt);
+ if (!m)
+ goto fail;
+ result = m;
- {
- struct sadb_x_policy *tmp;
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
+ (struct sockaddr *)&sp->spidx.src, sp->spidx.prefs,
+ sp->spidx.ul_proto);
+ if (!m)
+ goto fail;
+ m_cat(result, m);
- if ((tmp = key_sp2msg(sp)) == NULL) {
- printf("key_setdumpsp: No more memory.\n");
- return ENOBUFS;
- }
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,
+ (struct sockaddr *)&sp->spidx.dst, sp->spidx.prefd,
+ sp->spidx.ul_proto);
+ if (!m)
+ goto fail;
+ m_cat(result, m);
- /* validity check */
- if (key_getspreqmsglen(sp) != PFKEY_UNUNIT64(tmp->sadb_x_policy_len))
- panic("key_setdumpsp: length mismatch."
- "sp:%d msg:%d\n",
- key_getspreqmsglen(sp),
- PFKEY_UNUNIT64(tmp->sadb_x_policy_len));
-
- bcopy(tmp, p, PFKEY_UNUNIT64(tmp->sadb_x_policy_len));
- KFREE(tmp);
- }
+ m = key_sp2msg(sp);
+ if (!m)
+ goto fail;
+ m_cat(result, m);
- return tlen;
-}
+ if ((result->m_flags & M_PKTHDR) == 0)
+ goto fail;
-/* get sadb message length for a SP. */
-static u_int
-key_getspmsglen(sp)
- struct secpolicy *sp;
-{
- u_int tlen;
+ if (result->m_len < sizeof(struct sadb_msg)) {
+ result = m_pullup(result, sizeof(struct sadb_msg));
+ if (result == NULL)
+ goto fail;
+ }
- /* sanity check */
- if (sp == NULL)
- panic("key_getspmsglen: NULL pointer is passed.\n");
+ result->m_pkthdr.len = 0;
+ for (m = result; m; m = m->m_next)
+ result->m_pkthdr.len += m->m_len;
- tlen = (sizeof(struct sadb_msg)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(_SALENBYAF(sp->spidx.src.ss_family))
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(_SALENBYAF(sp->spidx.dst.ss_family)));
+ mtod(result, struct sadb_msg *)->sadb_msg_len =
+ PFKEY_UNIT64(result->m_pkthdr.len);
- tlen += key_getspreqmsglen(sp);
+ return result;
- return tlen;
+fail:
+ m_freem(result);
+ return NULL;
}
/*
@@ -1517,26 +2322,17 @@ key_newsah(saidx)
struct secasindex *saidx;
{
struct secashead *newsah;
- u_int stateidx;
/* sanity check */
if (saidx == NULL)
panic("key_newsaidx: NULL pointer is passed.\n");
- KMALLOC(newsah, struct secashead *, sizeof(struct secashead));
- if (newsah == NULL) {
+ newsah = keydb_newsecashead();
+ if (newsah == NULL)
return NULL;
- }
- bzero((caddr_t)newsah, sizeof(struct secashead));
bcopy(saidx, &newsah->saidx, sizeof(newsah->saidx));
- for (stateidx = 0;
- stateidx < _ARRAYLEN(saorder_state_any);
- stateidx++) {
- LIST_INIT(&newsah->savtree[saorder_state_any[stateidx]]);
- }
-
/* add to saidxtree */
newsah->state = SADB_SASTATE_MATURE;
LIST_INSERT_HEAD(&sahtree, newsah, chain);
@@ -1554,6 +2350,7 @@ key_delsah(sah)
struct secasvar *sav, *nextsav;
u_int stateidx, state;
int s;
+ int zombie = 0;
/* sanity check */
if (sah == NULL)
@@ -1561,10 +2358,6 @@ key_delsah(sah)
s = splnet(); /*called from softclock()*/
- /* remove from tree of SA index */
- if (__LIST_CHAINED(sah))
- LIST_REMOVE(sah, chain);
-
/* searching all SA registerd in the secindex. */
for (stateidx = 0;
stateidx < _ARRAYLEN(saorder_state_any);
@@ -1577,27 +2370,38 @@ key_delsah(sah)
nextsav = LIST_NEXT(sav, chain);
+ if (sav->refcnt > 0) {
+ /* give up to delete this sa */
+ zombie++;
+ continue;
+ }
+
/* sanity check */
KEY_CHKSASTATE(state, sav->state, "key_delsah");
+ key_freesav(sav);
+
/* remove back pointer */
sav->sah = NULL;
-
- if (sav->refcnt < 0) {
- printf("key_delsah: why refcnt < 0 ?, "
- "sav->refcnt=%d\n",
- sav->refcnt);
- }
- key_freesav(sav);
sav = NULL;
}
}
+ /* don't delete sah only if there are savs. */
+ if (zombie) {
+ splx(s);
+ return;
+ }
+
if (sah->sa_route.ro_rt) {
RTFREE(sah->sa_route.ro_rt);
sah->sa_route.ro_rt = (struct rtentry *)NULL;
}
+ /* remove from tree of SA index */
+ if (__LIST_CHAINED(sah))
+ LIST_REMOVE(sah, chain);
+
KFREE(sah);
splx(s);
@@ -1613,75 +2417,87 @@ key_delsah(sah)
* not to call key_setsava().
* OUT: NULL : fail
* others : pointer to new secasvar.
+ *
+ * does not modify mbuf. does not free mbuf on error.
*/
static struct secasvar *
-key_newsav(mhp, sah)
- caddr_t *mhp;
+key_newsav(m, mhp, sah, errp)
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
struct secashead *sah;
+ int *errp;
{
struct secasvar *newsav;
- struct sadb_msg *msg0;
+ const struct sadb_sa *xsa;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL || sah == NULL)
+ if (m == NULL || mhp == NULL || mhp->msg == NULL || sah == NULL)
panic("key_newsa: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
-
KMALLOC(newsav, struct secasvar *, sizeof(struct secasvar));
if (newsav == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_newsa: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
+#endif
+ *errp = ENOBUFS;
return NULL;
}
bzero((caddr_t)newsav, sizeof(struct secasvar));
- switch (msg0->sadb_msg_type) {
+ switch (mhp->msg->sadb_msg_type) {
case SADB_GETSPI:
newsav->spi = 0;
+#ifdef IPSEC_DOSEQCHECK
/* sync sequence number */
- if (msg0->sadb_msg_seq == 0)
+ if (mhp->msg->sadb_msg_seq == 0)
newsav->seq =
(acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq));
else
- newsav->seq = msg0->sadb_msg_seq;
+#endif
+ newsav->seq = mhp->msg->sadb_msg_seq;
break;
case SADB_ADD:
/* sanity check */
- if (mhp[SADB_EXT_SA] == NULL) {
+ if (mhp->ext[SADB_EXT_SA] == NULL) {
KFREE(newsav);
+#ifdef IPSEC_DEBUG
printf("key_newsa: invalid message is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
+#endif
+ *errp = EINVAL;
return NULL;
}
- newsav->spi = ((struct sadb_sa *)mhp[SADB_EXT_SA])->sadb_sa_spi;
- newsav->seq = msg0->sadb_msg_seq;
+ xsa = (const struct sadb_sa *)mhp->ext[SADB_EXT_SA];
+ newsav->spi = xsa->sadb_sa_spi;
+ newsav->seq = mhp->msg->sadb_msg_seq;
break;
default:
KFREE(newsav);
- msg0->sadb_msg_errno = EINVAL;
+ *errp = EINVAL;
return NULL;
}
/* copy sav values */
- if (msg0->sadb_msg_type != SADB_GETSPI && key_setsaval(newsav, mhp)) {
- KFREE(newsav);
- /* msg0->sadb_msg_errno is set at key_setsaval. */
- return NULL;
+ if (mhp->msg->sadb_msg_type != SADB_GETSPI) {
+ *errp = key_setsaval(newsav, m, mhp);
+ if (*errp) {
+ KFREE(newsav);
+ return NULL;
+ }
}
/* reset tick */
newsav->tick = 0;
- newsav->pid = msg0->sadb_msg_pid;
+ newsav->pid = mhp->msg->sadb_msg_pid;
/* add to satree */
newsav->sah = sah;
newsav->refcnt = 1;
newsav->state = SADB_SASTATE_LARVAL;
- LIST_INSERT_HEAD(&sah->savtree[SADB_SASTATE_LARVAL], newsav, chain);
+ LIST_INSERT_TAIL(&sah->savtree[SADB_SASTATE_LARVAL], newsav,
+ secasvar, chain);
return newsav;
}
@@ -1697,7 +2513,8 @@ key_delsav(sav)
if (sav == NULL)
panic("key_delsav: NULL pointer is passed.\n");
- if (sav->refcnt > 0) return; /* can't free */
+ if (sav->refcnt > 0)
+ return; /* can't free */
/* remove from SA header */
if (__LIST_CHAINED(sav))
@@ -1707,11 +2524,8 @@ key_delsav(sav)
KFREE(sav->key_auth);
if (sav->key_enc != NULL)
KFREE(sav->key_enc);
- if (sav->replay != NULL) {
- if (sav->replay->bitmap != NULL)
- KFREE(sav->replay->bitmap);
- KFREE(sav->replay);
- }
+ if (sav->replay != NULL)
+ keydb_delsecreplay(sav->replay);
if (sav->lft_c != NULL)
KFREE(sav->lft_c);
if (sav->lft_h != NULL)
@@ -1729,10 +2543,6 @@ key_delsav(sav)
KFREE(sav->misc3);
#endif
- sav->sah = NULL;
- /* XXX for making sure. See key_checkrequest(),
- * Refcnt may be suspicious. */
-
KFREE(sav);
return;
@@ -1750,7 +2560,7 @@ key_getsah(saidx)
{
struct secashead *sah;
- __LIST_FOREACH(sah, &sahtree, chain) {
+ LIST_FOREACH(sah, &sahtree, chain) {
if (sah->state == SADB_SASTATE_DEAD)
continue;
if (key_cmpsaidx_exactly(&sah->saidx, saidx))
@@ -1776,15 +2586,16 @@ key_checkspidup(saidx, spi)
struct secasvar *sav;
/* check address family */
- if (saidx->src.ss_family != saidx->src.ss_family) {
+ if (saidx->src.ss_family != saidx->dst.ss_family) {
+#ifdef IPSEC_DEBUG
printf("key_checkspidup: address family mismatched.\n");
+#endif
return NULL;
}
/* check all SAD */
- __LIST_FOREACH(sah, &sahtree, chain) {
- if (!key_ismyaddr(sah->saidx.dst.ss_family,
- _INADDRBYSA(&sah->saidx.dst)))
+ LIST_FOREACH(sah, &sahtree, chain) {
+ if (!key_ismyaddr((struct sockaddr *)&sah->saidx.dst))
continue;
sav = key_getsavbyspi(sah, spi);
if (sav != NULL)
@@ -1814,14 +2625,16 @@ key_getsavbyspi(sah, spi)
stateidx++) {
state = saorder_state_alive[stateidx];
- __LIST_FOREACH(sav, &sah->savtree[state], chain) {
+ LIST_FOREACH(sav, &sah->savtree[state], chain) {
/* sanity check */
if (sav->state != state) {
+#ifdef IPSEC_DEBUG
printf("key_getsavbyspi: "
"invalid sav->state "
"(queue: %d SA: %d)\n",
state, sav->state);
+#endif
continue;
}
@@ -1837,22 +2650,25 @@ key_getsavbyspi(sah, spi)
* copy SA values from PF_KEY message except *SPI, SEQ, PID, STATE and TYPE*.
* You must update these if need.
* OUT: 0: success.
- * 1: failure. set errno to (mhp[0])->sadb_msg_errno.
+ * !0: failure.
+ *
+ * does not modify mbuf. does not free mbuf on error.
*/
static int
-key_setsaval(sav, mhp)
+key_setsaval(sav, m, mhp)
struct secasvar *sav;
- caddr_t *mhp;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
+#ifdef IPSEC_ESP
+ const struct esp_algorithm *algo;
+#endif
int error = 0;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_setsaval: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
-
/* initialization */
sav->replay = NULL;
sav->key_auth = NULL;
@@ -1861,10 +2677,21 @@ key_setsaval(sav, mhp)
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[SADB_EXT_SA] != NULL) {
- struct sadb_sa *sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA];
+ if (mhp->ext[SADB_EXT_SA] != NULL) {
+ const struct sadb_sa *sa0;
+
+ sa0 = (const struct sadb_sa *)mhp->ext[SADB_EXT_SA];
+ if (mhp->extlen[SADB_EXT_SA] < sizeof(*sa0)) {
+ error = EINVAL;
+ goto fail;
+ }
sav->alg_auth = sa0->sadb_sa_auth;
sav->alg_enc = sa0->sadb_sa_encrypt;
@@ -1872,144 +2699,135 @@ key_setsaval(sav, mhp)
/* replay window */
if ((sa0->sadb_sa_flags & SADB_X_EXT_OLD) == 0) {
- KMALLOC(sav->replay, struct secreplay *,
- sizeof(struct secreplay));
+ sav->replay = keydb_newsecreplay(sa0->sadb_sa_replay);
if (sav->replay == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_setsaval: No more memory.\n");
+#endif
error = ENOBUFS;
- goto err;
- }
- bzero(sav->replay, sizeof(struct secreplay));
-
- if ((sav->replay->wsize = sa0->sadb_sa_replay) != 0) {
- KMALLOC(sav->replay->bitmap, caddr_t,
- sav->replay->wsize);
- if (sav->replay->bitmap == NULL) {
- printf("key_setsaval: "
- "No more memory.\n");
- error = ENOBUFS;
- goto err;
- }
- bzero(sav->replay->bitmap, sa0->sadb_sa_replay);
+ goto fail;
}
}
}
/* Authentication keys */
- if (mhp[SADB_EXT_KEY_AUTH] != NULL) {
- struct sadb_key *key0;
- u_int len;
+ if (mhp->ext[SADB_EXT_KEY_AUTH] != NULL) {
+ const struct sadb_key *key0;
+ int len;
- key0 = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH];
- len = PFKEY_UNUNIT64(key0->sadb_key_len);
+ key0 = (const struct sadb_key *)mhp->ext[SADB_EXT_KEY_AUTH];
+ len = mhp->extlen[SADB_EXT_KEY_AUTH];
error = 0;
- if (len < sizeof(struct sadb_key))
+ if (len < sizeof(*key0)) {
error = EINVAL;
- switch (msg0->sadb_msg_satype) {
+ goto fail;
+ }
+ switch (mhp->msg->sadb_msg_satype) {
case SADB_SATYPE_AH:
case SADB_SATYPE_ESP:
- if (len == sizeof(struct sadb_key)
- && sav->alg_auth != SADB_AALG_NULL) {
+ if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) &&
+ sav->alg_auth != SADB_AALG_NULL)
error = EINVAL;
- }
break;
case SADB_X_SATYPE_IPCOMP:
- error = EINVAL;
- break;
default:
error = EINVAL;
break;
}
if (error) {
+#ifdef IPSEC_DEBUG
printf("key_setsaval: invalid key_auth values.\n");
- goto err;
+#endif
+ goto fail;
}
- KEY_NEWBUF(sav->key_auth, struct sadb_key *, key0, len);
+ sav->key_auth = (struct sadb_key *)key_newbuf(key0, len);
if (sav->key_auth == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_setsaval: No more memory.\n");
+#endif
error = ENOBUFS;
- goto err;
+ goto fail;
}
-
- /* make length shift up for kernel*/
- sav->key_auth->sadb_key_len = len;
}
/* Encryption key */
- if (mhp[SADB_EXT_KEY_ENCRYPT] != NULL) {
- struct sadb_key *key0;
- u_int len;
+ if (mhp->ext[SADB_EXT_KEY_ENCRYPT] != NULL) {
+ const struct sadb_key *key0;
+ int len;
- key0 = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT];
- len = PFKEY_UNUNIT64(key0->sadb_key_len);
+ key0 = (const struct sadb_key *)mhp->ext[SADB_EXT_KEY_ENCRYPT];
+ len = mhp->extlen[SADB_EXT_KEY_ENCRYPT];
error = 0;
- if (len < sizeof(struct sadb_key))
+ if (len < sizeof(*key0)) {
error = EINVAL;
- switch (msg0->sadb_msg_satype) {
+ goto fail;
+ }
+ switch (mhp->msg->sadb_msg_satype) {
case SADB_SATYPE_ESP:
- if (len == sizeof(struct sadb_key)
- && sav->alg_enc != SADB_EALG_NULL) {
+ if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) &&
+ sav->alg_enc != SADB_EALG_NULL)
error = EINVAL;
- }
break;
case SADB_SATYPE_AH:
- error = EINVAL;
- break;
case SADB_X_SATYPE_IPCOMP:
- break;
- default:
error = EINVAL;
break;
}
if (error) {
+#ifdef IPSEC_DEBUG
printf("key_setsatval: invalid key_enc value.\n");
- goto err;
+#endif
+ goto fail;
}
- KEY_NEWBUF(sav->key_enc, struct sadb_key *, key0, len);
+ 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 err;
+ goto fail;
}
-
- /* make length shift up for kernel*/
- sav->key_enc->sadb_key_len = len;
}
/* set iv */
sav->ivlen = 0;
- switch (msg0->sadb_msg_satype) {
+ switch (mhp->msg->sadb_msg_satype) {
case SADB_SATYPE_ESP:
#ifdef IPSEC_ESP
- {
- struct esp_algorithm *algo;
-
algo = &esp_algorithms[sav->alg_enc];
if (algo && algo->ivlen)
sav->ivlen = (*algo->ivlen)(sav);
+ if (sav->ivlen == 0)
+ break;
KMALLOC(sav->iv, caddr_t, sav->ivlen);
if (sav->iv == 0) {
+#ifdef IPSEC_DEBUG
printf("key_setsaval: No more memory.\n");
+#endif
error = ENOBUFS;
- goto err;
+ goto fail;
}
/* initialize ? */
break;
- }
#else
break;
#endif
case SADB_SATYPE_AH:
+#if 1 /*nonstandard*/
+ case SADB_X_SATYPE_IPCOMP:
+#endif
break;
default:
+#ifdef IPSEC_DEBUG
printf("key_setsaval: invalid SA type.\n");
+#endif
error = EINVAL;
- goto err;
+ goto fail;
}
/* reset tick */
@@ -2020,17 +2838,19 @@ key_setsaval(sav, mhp)
struct timeval tv;
KMALLOC(sav->lft_c, struct sadb_lifetime *,
- sizeof(struct sadb_lifetime));
+ sizeof(struct sadb_lifetime));
if (sav->lft_c == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_setsaval: No more memory.\n");
+#endif
error = ENOBUFS;
- goto err;
+ goto fail;
}
microtime(&tv);
sav->lft_c->sadb_lifetime_len =
- PFKEY_UNIT64(sizeof(struct sadb_lifetime));
+ PFKEY_UNIT64(sizeof(struct sadb_lifetime));
sav->lft_c->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
sav->lft_c->sadb_lifetime_allocations = 0;
sav->lft_c->sadb_lifetime_bytes = 0;
@@ -2040,43 +2860,82 @@ key_setsaval(sav, mhp)
/* lifetimes for HARD and SOFT */
{
- struct sadb_lifetime *lft0;
+ const struct sadb_lifetime *lft0;
- lft0 = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
+ lft0 = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_HARD];
if (lft0 != NULL) {
- KEY_NEWBUF(sav->lft_h, struct sadb_lifetime *,
- lft0, sizeof(*lft0));
+ if (mhp->extlen[SADB_EXT_LIFETIME_HARD] < sizeof(*lft0)) {
+ error = EINVAL;
+ goto fail;
+ }
+ sav->lft_h = (struct sadb_lifetime *)key_newbuf(lft0,
+ sizeof(*lft0));
if (sav->lft_h == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_setsaval: No more memory.\n");
+#endif
error = ENOBUFS;
- goto err;
+ goto fail;
}
/* to be initialize ? */
}
- lft0 = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT];
+ lft0 = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_SOFT];
if (lft0 != NULL) {
- KEY_NEWBUF(sav->lft_s, struct sadb_lifetime *,
- lft0, sizeof(*lft0));
+ if (mhp->extlen[SADB_EXT_LIFETIME_SOFT] < sizeof(*lft0)) {
+ error = EINVAL;
+ goto fail;
+ }
+ sav->lft_s = (struct sadb_lifetime *)key_newbuf(lft0,
+ sizeof(*lft0));
if (sav->lft_s == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_setsaval: No more memory.\n");
+#endif
error = ENOBUFS;
- goto err;
+ goto fail;
}
/* to be initialize ? */
}
}
- msg0->sadb_msg_errno = 0;
+#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;
- err:
+ fail:
/* initialization */
- if (sav->replay != NULL) {
- if (sav->replay->bitmap != NULL)
- KFREE(sav->replay->bitmap);
- KFREE(sav->replay);
- }
+ if (sav->replay != NULL)
+ keydb_delsecreplay(sav->replay);
if (sav->key_auth != NULL)
KFREE(sav->key_auth);
if (sav->key_enc != NULL)
@@ -2089,39 +2948,16 @@ key_setsaval(sav, mhp)
KFREE(sav->lft_h);
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
- msg0->sadb_msg_errno = error;
- return 1;
-}
-
-/*
- * get message buffer length.
- */
-static u_int
-key_getmsglen(sav)
- struct secasvar *sav;
-{
- int len = sizeof(struct sadb_msg);
-
- len += sizeof(struct sadb_sa);
- len += (sizeof(struct sadb_address)
- + PFKEY_ALIGN8(_SALENBYAF(sav->sah->saidx.src.ss_family)));
- len += (sizeof(struct sadb_address)
- + PFKEY_ALIGN8(_SALENBYAF(sav->sah->saidx.dst.ss_family)));
-
- if (sav->key_auth != NULL)
- len += sav->key_auth->sadb_key_len;
- if (sav->key_enc != NULL)
- len += sav->key_enc->sadb_key_len;
-
- if (sav->lft_c != NULL)
- len += sizeof(struct sadb_lifetime);
- if (sav->lft_h != NULL)
- len += sizeof(struct sadb_lifetime);
- if (sav->lft_s != NULL)
- len += sizeof(struct sadb_lifetime);
-
- return len;
+ return error;
}
/*
@@ -2141,7 +2977,9 @@ key_mature(sav)
/* check SPI value */
if (ntohl(sav->spi) >= 0 && ntohl(sav->spi) <= 255) {
+#ifdef IPSEC_DEBUG
printf("key_mature: illegal range of SPI %d.\n", sav->spi);
+#endif
return EINVAL;
}
@@ -2151,8 +2989,10 @@ key_mature(sav)
/* check flags */
if ((sav->flags & SADB_X_EXT_OLD)
&& (sav->flags & SADB_X_EXT_DERIV)) {
+#ifdef IPSEC_DEBUG
printf("key_mature: "
"invalid flag (derived) given to old-esp.\n");
+#endif
return EINVAL;
}
checkmask = 3;
@@ -2161,20 +3001,46 @@ key_mature(sav)
case IPPROTO_AH:
/* check flags */
if (sav->flags & SADB_X_EXT_DERIV) {
+#ifdef IPSEC_DEBUG
printf("key_mature: "
"invalid flag (derived) given to AH SA.\n");
+#endif
return EINVAL;
}
if (sav->alg_enc != SADB_EALG_NONE) {
+#ifdef IPSEC_DEBUG
printf("key_mature: "
"protocol and algorithm mismated.\n");
+#endif
return(EINVAL);
}
checkmask = 2;
mustmask = 2;
break;
+#if 1 /*nonstandard*/
+ case IPPROTO_IPCOMP:
+ if (sav->alg_auth != SADB_AALG_NONE) {
+#ifdef IPSEC_DEBUG
+ printf("key_mature: "
+ "protocol and algorithm mismated.\n");
+#endif
+ return(EINVAL);
+ }
+ if ((sav->flags & SADB_X_EXT_RAWCPI) == 0
+ && ntohl(sav->spi) >= 0x10000) {
+#ifdef IPSEC_DEBUG
+ printf("key_mature: invalid cpi for IPComp.\n");
+#endif
+ return(EINVAL);
+ }
+ checkmask = 4;
+ mustmask = 4;
+ break;
+#endif
default:
+#ifdef IPSEC_DEBUG
printf("key_mature: Invalid satype.\n");
+#endif
return EPROTONOSUPPORT;
}
@@ -2193,8 +3059,10 @@ key_mature(sav)
case SADB_AALG_NULL:
break;
default:
+#ifdef IPSEC_DEBUG
printf("key_mature: "
"unknown authentication algorithm.\n");
+#endif
return EINVAL;
}
@@ -2206,9 +3074,11 @@ key_mature(sav)
else
keylen = 0;
if (keylen < algo->keymin || algo->keymax < keylen) {
+#ifdef IPSEC_DEBUG
printf("key_mature: invalid AH key length %d "
"(%d-%d allowed)\n", keylen,
algo->keymin, algo->keymax);
+#endif
return EINVAL;
}
@@ -2220,8 +3090,12 @@ key_mature(sav)
mature = SADB_SATYPE_AH;
}
- if ((mustmask & 2) != 0 && mature != SADB_SATYPE_AH)
+ if ((mustmask & 2) != 0 && mature != SADB_SATYPE_AH) {
+#ifdef IPSEC_DEBUG
+ printf("key_mature: no satisfy algorithm for AH\n");
+#endif
return EINVAL;
+ }
}
/* check encryption algorithm */
@@ -2240,8 +3114,10 @@ key_mature(sav)
case SADB_EALG_RC5CBC:
break;
default:
+#ifdef IPSEC_DEBUG
printf("key_mature: unknown encryption algorithm.\n");
- return(EINVAL);
+#endif
+ return EINVAL;
}
/* algorithm-dependent check */
@@ -2252,9 +3128,11 @@ key_mature(sav)
else
keylen = 0;
if (keylen < algo->keymin || algo->keymax < keylen) {
+#ifdef IPSEC_DEBUG
printf("key_mature: invalid ESP key length %d "
"(%d-%d allowed)\n", keylen,
algo->keymin, algo->keymax);
+#endif
return EINVAL;
}
@@ -2266,14 +3144,49 @@ key_mature(sav)
mature = SADB_SATYPE_ESP;
}
- if ((mustmask & 1) != 0 && mature != SADB_SATYPE_ESP)
+ if ((mustmask & 1) != 0 && mature != SADB_SATYPE_ESP) {
+#ifdef IPSEC_DEBUG
+ printf("key_mature: no satisfy algorithm for ESP\n");
+#endif
return EINVAL;
-#else
+ }
+#else /*IPSEC_ESP*/
+#ifdef IPSEC_DEBUG
printf("key_mature: ESP not supported in this configuration\n");
+#endif
return EINVAL;
#endif
}
+ /* 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;
+ }
+
+ /* algorithm-dependent check */
+ algo = &ipcomp_algorithms[sav->alg_enc];
+
+ if (!(algo->compress && algo->decompress)) {
+#ifdef IPSEC_DEBUG
+ printf("key_mature: "
+ "unsupported compression algorithm.\n");
+#endif
+ return EINVAL;
+ }
+ }
+
key_sa_chgstate(sav, SADB_SASTATE_MATURE);
return 0;
@@ -2281,115 +3194,184 @@ key_mature(sav)
/*
* subroutine for SADB_GET and SADB_DUMP.
- * the buf must be allocated sufficent space.
*/
-static u_int
-key_setdumpsa(newmsg, sav, type, satype, seq, pid)
- struct sadb_msg *newmsg;
+static struct mbuf *
+key_setdumpsa(sav, type, satype, seq, pid)
struct secasvar *sav;
u_int8_t type, satype;
u_int32_t seq, pid;
{
- u_int tlen;
- caddr_t p;
+ struct mbuf *result = NULL, *tres = NULL, *m;
+ int l = 0;
int i;
-
- tlen = key_getmsglen(sav);
-
- p = key_setsadbmsg((caddr_t)newmsg, type, tlen,
- satype, seq, pid,
- sav->sah->saidx.mode, sav->refcnt);
-
- for (i = 1; i <= SADB_EXT_MAX; i++) {
- switch (i) {
+ void *p;
+ int dumporder[] = {
+ SADB_EXT_SA, SADB_X_EXT_SA2,
+ SADB_EXT_LIFETIME_HARD, SADB_EXT_LIFETIME_SOFT,
+ SADB_EXT_LIFETIME_CURRENT, SADB_EXT_ADDRESS_SRC,
+ SADB_EXT_ADDRESS_DST, SADB_EXT_ADDRESS_PROXY, SADB_EXT_KEY_AUTH,
+ SADB_EXT_KEY_ENCRYPT, SADB_EXT_IDENTITY_SRC,
+ SADB_EXT_IDENTITY_DST, SADB_EXT_SENSITIVITY,
+ };
+
+ m = key_setsadbmsg(type, 0, satype, seq, pid, sav->refcnt);
+ if (m == NULL)
+ goto fail;
+ result = m;
+
+ for (i = sizeof(dumporder)/sizeof(dumporder[0]) - 1; i >= 0; i--) {
+ m = NULL;
+ p = NULL;
+ switch (dumporder[i]) {
case SADB_EXT_SA:
- p = key_setsadbsa(p, sav);
+ m = key_setsadbsa(sav);
+ if (!m)
+ goto fail;
+ break;
+
+ case SADB_X_EXT_SA2:
+ m = key_setsadbxsa2(sav->sah->saidx.mode,
+ sav->sah->saidx.reqid);
+ if (!m)
+ goto fail;
break;
case SADB_EXT_ADDRESS_SRC:
- p = key_setsadbaddr(p,
- SADB_EXT_ADDRESS_SRC,
- (struct sockaddr *)&sav->sah->saidx.src,
- _INALENBYAF(sav->sah->saidx.src.ss_family) << 3,
- IPSEC_ULPROTO_ANY);
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
+ (struct sockaddr *)&sav->sah->saidx.src,
+ sav->sah->saidx.src.ss_len << 3, IPSEC_ULPROTO_ANY);
+ if (!m)
+ goto fail;
break;
case SADB_EXT_ADDRESS_DST:
- p = key_setsadbaddr(p,
- SADB_EXT_ADDRESS_DST,
- (struct sockaddr *)&sav->sah->saidx.dst,
- _INALENBYAF(sav->sah->saidx.dst.ss_family) << 3,
- IPSEC_ULPROTO_ANY);
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,
+ (struct sockaddr *)&sav->sah->saidx.dst,
+ sav->sah->saidx.dst.ss_len << 3, IPSEC_ULPROTO_ANY);
+ if (!m)
+ goto fail;
break;
case SADB_EXT_KEY_AUTH:
- {
- u_int len;
- if (sav->key_auth == NULL) break;
- len = sav->key_auth->sadb_key_len; /* real length */
- bcopy((caddr_t)sav->key_auth, p, len);
- ((struct sadb_ext *)p)->sadb_ext_len = PFKEY_UNIT64(len);
- p += len;
- }
+ if (!sav->key_auth)
+ continue;
+ l = PFKEY_UNUNIT64(sav->key_auth->sadb_key_len);
+ p = sav->key_auth;
break;
case SADB_EXT_KEY_ENCRYPT:
- {
- u_int len;
- if (sav->key_enc == NULL) break;
- len = sav->key_enc->sadb_key_len; /* real length */
- bcopy((caddr_t)sav->key_enc, p, len);
- ((struct sadb_ext *)p)->sadb_ext_len = PFKEY_UNIT64(len);
- p += len;
- }
- break;;
+ if (!sav->key_enc)
+ continue;
+ l = PFKEY_UNUNIT64(sav->key_enc->sadb_key_len);
+ p = sav->key_enc;
+ break;
case SADB_EXT_LIFETIME_CURRENT:
- if (sav->lft_c == NULL) break;
- p = key_setsadbext(p, (caddr_t)sav->lft_c);
+ if (!sav->lft_c)
+ continue;
+ l = PFKEY_UNUNIT64(((struct sadb_ext *)sav->lft_c)->sadb_ext_len);
+ p = sav->lft_c;
break;
case SADB_EXT_LIFETIME_HARD:
- if (sav->lft_h == NULL) break;
- p = key_setsadbext(p, (caddr_t)sav->lft_h);
+ if (!sav->lft_h)
+ continue;
+ l = PFKEY_UNUNIT64(((struct sadb_ext *)sav->lft_h)->sadb_ext_len);
+ p = sav->lft_h;
break;
case SADB_EXT_LIFETIME_SOFT:
- if (sav->lft_s == NULL) break;
- p = key_setsadbext(p, (caddr_t)sav->lft_s);
+ if (!sav->lft_s)
+ continue;
+ l = PFKEY_UNUNIT64(((struct sadb_ext *)sav->lft_s)->sadb_ext_len);
+ p = sav->lft_s;
break;
+ case SADB_EXT_ADDRESS_PROXY:
case SADB_EXT_IDENTITY_SRC:
case SADB_EXT_IDENTITY_DST:
/* XXX: should we brought from SPD ? */
case SADB_EXT_SENSITIVITY:
default:
- break;
+ continue;
}
+
+ if ((!m && !p) || (m && p))
+ goto fail;
+ if (p && tres) {
+ M_PREPEND(tres, l, M_DONTWAIT);
+ if (!tres)
+ goto fail;
+ bcopy(p, mtod(tres, caddr_t), l);
+ continue;
+ }
+ if (p) {
+ m = key_alloc_mbuf(l);
+ if (!m)
+ goto fail;
+ m_copyback(m, 0, l, p);
+ }
+
+ if (tres)
+ m_cat(m, tres);
+ tres = m;
}
- return tlen;
+ m_cat(result, tres);
+
+ if (result->m_len < sizeof(struct sadb_msg)) {
+ result = m_pullup(result, sizeof(struct sadb_msg));
+ if (result == NULL)
+ 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 result;
+
+fail:
+ m_freem(result);
+ m_freem(tres);
+ return NULL;
}
/*
* set data into sadb_msg.
- * `buf' must has been allocated sufficiently.
*/
-static caddr_t
-key_setsadbmsg(buf, type, tlen, satype, seq, pid, reserved1, reserved2)
- caddr_t buf;
+static struct mbuf *
+key_setsadbmsg(type, tlen, satype, seq, pid, reserved)
u_int8_t type, satype;
u_int16_t tlen;
u_int32_t seq;
pid_t pid;
- u_int8_t reserved1;
- u_int8_t reserved2;
+ u_int16_t reserved;
{
+ struct mbuf *m;
struct sadb_msg *p;
- u_int len;
+ int len;
+
+ len = PFKEY_ALIGN8(sizeof(struct sadb_msg));
+ if (len > MCLBYTES)
+ return NULL;
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m && len > MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ m = NULL;
+ }
+ }
+ if (!m)
+ return NULL;
+ m->m_pkthdr.len = m->m_len = len;
+ m->m_next = NULL;
- p = (struct sadb_msg *)buf;
- len = sizeof(struct sadb_msg);
+ p = mtod(m, struct sadb_msg *);
bzero(p, len);
p->sadb_msg_version = PF_KEY_V2;
@@ -2397,28 +3379,33 @@ key_setsadbmsg(buf, type, tlen, satype, seq, pid, reserved1, reserved2)
p->sadb_msg_errno = 0;
p->sadb_msg_satype = satype;
p->sadb_msg_len = PFKEY_UNIT64(tlen);
- p->sadb_msg_mode = reserved1;
- p->sadb_msg_reserved = reserved2;
+ p->sadb_msg_reserved = reserved;
p->sadb_msg_seq = seq;
p->sadb_msg_pid = (u_int32_t)pid;
- return(buf + len);
+ return m;
}
/*
* copy secasvar data into sadb_address.
- * `buf' must has been allocated sufficiently.
*/
-static caddr_t
-key_setsadbsa(buf, sav)
- caddr_t buf;
+static struct mbuf *
+key_setsadbsa(sav)
struct secasvar *sav;
{
+ struct mbuf *m;
struct sadb_sa *p;
- u_int len;
+ int len;
- p = (struct sadb_sa *)buf;
- len = sizeof(struct sadb_sa);
+ len = PFKEY_ALIGN8(sizeof(struct sadb_sa));
+ m = key_alloc_mbuf(len);
+ if (!m || m->m_next) { /*XXX*/
+ if (m)
+ m_freem(m);
+ return NULL;
+ }
+
+ p = mtod(m, struct sadb_sa *);
bzero(p, len);
p->sadb_sa_len = PFKEY_UNIT64(len);
@@ -2430,26 +3417,33 @@ key_setsadbsa(buf, sav)
p->sadb_sa_encrypt = sav->alg_enc;
p->sadb_sa_flags = sav->flags;
- return(buf + len);
+ return m;
}
/*
* set data into sadb_address.
- * `buf' must has been allocated sufficiently.
*/
-static caddr_t
-key_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto)
- caddr_t buf;
+static struct mbuf *
+key_setsadbaddr(exttype, saddr, prefixlen, ul_proto)
u_int16_t exttype;
struct sockaddr *saddr;
u_int8_t prefixlen;
u_int16_t ul_proto;
{
+ struct mbuf *m;
struct sadb_address *p;
- u_int len;
+ size_t len;
+
+ len = PFKEY_ALIGN8(sizeof(struct sadb_address)) +
+ PFKEY_ALIGN8(saddr->sa_len);
+ m = key_alloc_mbuf(len);
+ if (!m || m->m_next) { /*XXX*/
+ if (m)
+ m_freem(m);
+ return NULL;
+ }
- p = (struct sadb_address *)buf;
- len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len);
+ p = mtod(m, struct sadb_address *);
bzero(p, len);
p->sadb_address_len = PFKEY_UNIT64(len);
@@ -2458,28 +3452,37 @@ key_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto)
p->sadb_address_prefixlen = prefixlen;
p->sadb_address_reserved = 0;
- bcopy(saddr, p + 1, saddr->sa_len);
+ bcopy(saddr,
+ mtod(m, caddr_t) + PFKEY_ALIGN8(sizeof(struct sadb_address)),
+ saddr->sa_len);
- return(buf + len);
+ return m;
}
+#if 0
/*
* set data into sadb_ident.
- * `buf' must has been allocated sufficiently.
*/
-static caddr_t
-key_setsadbident(buf, exttype, idtype, string, stringlen, id)
- caddr_t buf;
+static struct mbuf *
+key_setsadbident(exttype, idtype, string, stringlen, id)
u_int16_t exttype, idtype;
caddr_t string;
int stringlen;
u_int64_t id;
{
+ struct mbuf *m;
struct sadb_ident *p;
- u_int len;
+ size_t len;
- p = (struct sadb_ident *)buf;
- len = sizeof(struct sadb_ident) + PFKEY_ALIGN8(stringlen);
+ len = PFKEY_ALIGN8(sizeof(struct sadb_ident)) + PFKEY_ALIGN8(stringlen);
+ m = key_alloc_mbuf(len);
+ if (!m || m->m_next) { /*XXX*/
+ if (m)
+ m_freem(m);
+ return NULL;
+ }
+
+ p = mtod(m, struct sadb_ident *);
bzero(p, len);
p->sadb_ident_len = PFKEY_UNIT64(len);
@@ -2488,27 +3491,79 @@ key_setsadbident(buf, exttype, idtype, string, stringlen, id)
p->sadb_ident_reserved = 0;
p->sadb_ident_id = id;
- bcopy(string, p + 1, stringlen);
+ bcopy(string,
+ mtod(m, caddr_t) + PFKEY_ALIGN8(sizeof(struct sadb_ident)),
+ stringlen);
- return(buf + len);
+ return m;
}
+#endif
/*
- * copy buffer of any sadb extension type into sadb_ext.
- * assume that sadb_ext_len shifted down >> 3.
- * i.e. shift length up when setting length of extension.
+ * set data into sadb_x_sa2.
*/
-static caddr_t
-key_setsadbext(p, ext)
- caddr_t p, ext;
+static struct mbuf *
+key_setsadbxsa2(mode, reqid)
+ u_int8_t mode;
+ u_int32_t reqid;
{
- u_int len;
+ struct mbuf *m;
+ struct sadb_x_sa2 *p;
+ size_t len;
+
+ len = PFKEY_ALIGN8(sizeof(struct sadb_x_sa2));
+ m = key_alloc_mbuf(len);
+ if (!m || m->m_next) { /*XXX*/
+ if (m)
+ m_freem(m);
+ return NULL;
+ }
+
+ p = mtod(m, struct sadb_x_sa2 *);
+
+ bzero(p, len);
+ p->sadb_x_sa2_len = PFKEY_UNIT64(len);
+ p->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+ p->sadb_x_sa2_mode = mode;
+ p->sadb_x_sa2_reserved1 = 0;
+ p->sadb_x_sa2_reserved2 = 0;
+ p->sadb_x_sa2_reserved3 = 0;
+ p->sadb_x_sa2_reqid = reqid;
+
+ return m;
+}
+
+/*
+ * set data into sadb_x_policy
+ */
+static struct mbuf *
+key_setsadbxpolicy(type, dir, id)
+ u_int16_t type;
+ u_int8_t dir;
+ u_int32_t id;
+{
+ struct mbuf *m;
+ struct sadb_x_policy *p;
+ size_t len;
+
+ len = PFKEY_ALIGN8(sizeof(struct sadb_x_policy));
+ m = key_alloc_mbuf(len);
+ if (!m || m->m_next) { /*XXX*/
+ if (m)
+ m_freem(m);
+ return NULL;
+ }
- len = PFKEY_UNUNIT64(((struct sadb_ext *)ext)->sadb_ext_len);
+ p = mtod(m, struct sadb_x_policy *);
- bcopy(ext, p, len);
+ bzero(p, len);
+ p->sadb_x_policy_len = PFKEY_UNIT64(len);
+ p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ p->sadb_x_policy_type = type;
+ p->sadb_x_policy_dir = dir;
+ p->sadb_x_policy_id = id;
- return(p + len);
+ return m;
}
/* %%% utilities */
@@ -2517,17 +3572,19 @@ key_setsadbext(p, ext)
*/
static void *
key_newbuf(src, len)
- void *src;
+ const void *src;
u_int len;
{
caddr_t new;
KMALLOC(new, caddr_t, len);
if (new == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_newbuf: No more memory.\n");
+#endif
return NULL;
}
- bcopy((caddr_t)src, new, len);
+ bcopy(src, new, len);
return new;
}
@@ -2537,30 +3594,37 @@ key_newbuf(src, len)
* 0: false
*/
int
-key_ismyaddr(family, addr)
- u_int family;
- caddr_t addr;
+key_ismyaddr(sa)
+ struct sockaddr *sa;
{
+#ifdef INET
+ struct sockaddr_in *sin;
+ struct in_ifaddr *ia;
+#endif
+
/* sanity check */
- if (addr == NULL)
+ if (sa == NULL)
panic("key_ismyaddr: NULL pointer is passed.\n");
- switch (family) {
+ switch (sa->sa_family) {
+#ifdef INET
case AF_INET:
- {
- struct in_ifaddr *ia;
-
+ sin = (struct sockaddr_in *)sa;
for (ia = in_ifaddrhead.tqh_first; ia;
ia = ia->ia_link.tqe_next)
- if (bcmp(addr,
- (caddr_t)&ia->ia_addr.sin_addr,
- _INALENBYAF(family)) == 0)
+ {
+ if (sin->sin_family == ia->ia_addr.sin_family &&
+ sin->sin_len == ia->ia_addr.sin_len &&
+ sin->sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr)
+ {
return 1;
- }
+ }
+ }
break;
+#endif
#ifdef INET6
case AF_INET6:
- return key_ismyaddr6(addr);
+ return key_ismyaddr6((struct sockaddr_in6 *)sa);
#endif
}
@@ -2574,38 +3638,36 @@ key_ismyaddr(family, addr)
* 0: other
* NOTE: derived ip6_input() in KAME. This is necessary to modify more.
*/
-#include <netinet6/in6.h>
#include <netinet6/in6_var.h>
static int
-key_ismyaddr6(addr)
- caddr_t addr;
+key_ismyaddr6(sin6)
+ struct sockaddr_in6 *sin6;
{
- struct in6_addr *a = (struct in6_addr *)addr;
struct in6_ifaddr *ia;
+ struct in6_multi *in6m;
for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
- if (bcmp(addr, (caddr_t)&ia->ia_addr.sin6_addr,
- _INALENBYAF(AF_INET6)) == 0) {
+ if (key_sockaddrcmp((struct sockaddr *)&sin6,
+ (struct sockaddr *)&ia->ia_addr, 0) == 0)
return 1;
- }
- /* XXX Multicast */
- {
- struct in6_multi *in6m = 0;
-
- IN6_LOOKUP_MULTI(*(struct in6_addr *)addr, ia->ia_ifp, in6m);
+ /*
+ * XXX Multicast
+ * XXX why do we care about multlicast here while we don't care
+ * about IPv4 multicast??
+ * XXX scope
+ */
+ in6m = NULL;
+ IN6_LOOKUP_MULTI(sin6->sin6_addr, ia->ia_ifp, in6m);
if (in6m)
return 1;
- }
}
/* loopback, just for safety */
- if (IN6_IS_ADDR_LOOPBACK(a))
+ if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
return 1;
- /* XXX anycast */
-
return 0;
}
#endif /*INET6*/
@@ -2614,7 +3676,7 @@ key_ismyaddr6(addr)
* compare two secasindex structure exactly.
* IN:
* saidx0: source, it can be in SAD.
- * saidx1: object, it can be from SPD.
+ * saidx1: object.
* OUT:
* 1 : equal
* 0 : not equal
@@ -2631,11 +3693,12 @@ key_cmpsaidx_exactly(saidx0, saidx1)
return 0;
if (saidx0->proto != saidx1->proto
- || saidx0->mode != saidx1->mode)
+ || saidx0->mode != saidx1->mode
+ || saidx0->reqid != saidx1->reqid)
return 0;
- if (bcmp(&saidx0->src, &saidx1->src, saidx0->src.ss_len) != 0
- || bcmp(&saidx0->dst, &saidx1->dst, saidx0->dst.ss_len) != 0)
+ if (bcmp(&saidx0->src, &saidx1->src, saidx0->src.ss_len) != 0 ||
+ bcmp(&saidx0->dst, &saidx1->dst, saidx0->dst.ss_len) != 0)
return 0;
return 1;
@@ -2662,22 +3725,63 @@ key_cmpsaidx_withmode(saidx0, saidx1)
if (saidx0 == NULL || saidx1 == NULL)
return 0;
- if (saidx0->proto != saidx1->proto
- || saidx0->src.ss_family != saidx1->src.ss_family
- || saidx0->dst.ss_family != saidx1->dst.ss_family)
+ if (saidx0->proto != saidx1->proto)
return 0;
- if (saidx0->mode != IPSEC_MODE_ANY
- && saidx0->mode != saidx1->mode)
+ /*
+ * 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;
- {
- int sa_len = _INALENBYAF(saidx0->src.ss_family);
+ if (saidx0->mode != IPSEC_MODE_ANY && saidx0->mode != saidx1->mode)
+ return 0;
- if (bcmp(_INADDRBYSA(&saidx0->src), _INADDRBYSA(&saidx1->src), sa_len)
- || bcmp(_INADDRBYSA(&saidx0->dst), _INADDRBYSA(&saidx1->dst), sa_len))
+ 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 mode.
+ * 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_withoutmode(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 (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;
}
@@ -2707,9 +3811,14 @@ key_cmpspidx_exactly(spidx0, spidx1)
|| spidx0->ul_proto != spidx1->ul_proto)
return 0;
- if (bcmp(&spidx0->src, &spidx1->src, spidx0->src.ss_len) != 0
- || bcmp(&spidx0->dst, &spidx1->dst, spidx0->dst.ss_len) != 0)
+ if (key_sockaddrcmp((struct sockaddr *)&spidx0->src,
+ (struct sockaddr *)&spidx1->src, 1) != 0) {
+ return 0;
+ }
+ if (key_sockaddrcmp((struct sockaddr *)&spidx0->dst,
+ (struct sockaddr *)&spidx1->dst, 1) != 0) {
return 0;
+ }
return 1;
}
@@ -2734,8 +3843,10 @@ key_cmpspidx_withmask(spidx0, spidx1)
if (spidx0 == NULL || spidx1 == NULL)
return 0;
- if (spidx0->src.ss_family != spidx1->src.ss_family
- || spidx0->dst.ss_family != spidx1->dst.ss_family)
+ if (spidx0->src.ss_family != spidx1->src.ss_family ||
+ spidx0->dst.ss_family != spidx1->dst.ss_family ||
+ spidx0->src.ss_len != spidx1->src.ss_len ||
+ spidx0->dst.ss_len != spidx1->dst.ss_len)
return 0;
/* if spidx.ul_proto == IPSEC_ULPROTO_ANY, ignore. */
@@ -2743,27 +3854,112 @@ key_cmpspidx_withmask(spidx0, spidx1)
&& spidx0->ul_proto != spidx1->ul_proto)
return 0;
- if (_INPORTBYSA(&spidx0->src) != IPSEC_PORT_ANY
- && _INPORTBYSA(&spidx0->src) != _INPORTBYSA(&spidx1->src))
- return 0;
+ switch (spidx0->src.ss_family) {
+ case AF_INET:
+ if (satosin(&spidx0->src)->sin_port != IPSEC_PORT_ANY
+ && satosin(&spidx0->src)->sin_port !=
+ satosin(&spidx1->src)->sin_port)
+ return 0;
+ if (!key_bbcmp((caddr_t)&satosin(&spidx0->src)->sin_addr,
+ (caddr_t)&satosin(&spidx1->src)->sin_addr, spidx0->prefs))
+ return 0;
+ break;
+ case AF_INET6:
+ if (satosin6(&spidx0->src)->sin6_port != IPSEC_PORT_ANY
+ && satosin6(&spidx0->src)->sin6_port !=
+ satosin6(&spidx1->src)->sin6_port)
+ return 0;
+ if (satosin6(&spidx0->src)->sin6_scope_id !=
+ satosin6(&spidx1->src)->sin6_scope_id)
+ return 0;
+ if (!key_bbcmp((caddr_t)&satosin6(&spidx0->src)->sin6_addr,
+ (caddr_t)&satosin6(&spidx1->src)->sin6_addr, spidx0->prefs))
+ return 0;
+ break;
+ default:
+ /* XXX */
+ if (bcmp(&spidx0->src, &spidx1->src, spidx0->src.ss_len) != 0)
+ return 0;
+ break;
+ }
- if (_INPORTBYSA(&spidx0->dst) != IPSEC_PORT_ANY
- && _INPORTBYSA(&spidx0->dst) != _INPORTBYSA(&spidx1->dst))
- return 0;
+ switch (spidx0->dst.ss_family) {
+ case AF_INET:
+ if (satosin(&spidx0->dst)->sin_port != IPSEC_PORT_ANY
+ && satosin(&spidx0->dst)->sin_port !=
+ satosin(&spidx1->dst)->sin_port)
+ return 0;
+ if (!key_bbcmp((caddr_t)&satosin(&spidx0->dst)->sin_addr,
+ (caddr_t)&satosin(&spidx1->dst)->sin_addr, spidx0->prefd))
+ return 0;
+ break;
+ case AF_INET6:
+ if (satosin6(&spidx0->dst)->sin6_port != IPSEC_PORT_ANY
+ && satosin6(&spidx0->dst)->sin6_port !=
+ satosin6(&spidx1->dst)->sin6_port)
+ return 0;
+ if (satosin6(&spidx0->dst)->sin6_scope_id !=
+ satosin6(&spidx1->dst)->sin6_scope_id)
+ return 0;
+ if (!key_bbcmp((caddr_t)&satosin6(&spidx0->dst)->sin6_addr,
+ (caddr_t)&satosin6(&spidx1->dst)->sin6_addr, spidx0->prefd))
+ return 0;
+ break;
+ default:
+ /* XXX */
+ if (bcmp(&spidx0->dst, &spidx1->dst, spidx0->dst.ss_len) != 0)
+ return 0;
+ break;
+ }
- if (!key_bbcmp(_INADDRBYSA(&spidx0->src),
- _INADDRBYSA(&spidx1->src),
- spidx0->prefs))
- return 0;
+ /* XXX Do we check other field ? e.g. flowinfo */
- if (!key_bbcmp(_INADDRBYSA(&spidx0->dst),
- _INADDRBYSA(&spidx1->dst),
- spidx0->prefd))
- return 0;
+ return 1;
+}
- /* XXX Do we check other field ? e.g. flowinfo, scope_id. */
+/* returns 0 on match */
+static int
+key_sockaddrcmp(sa1, sa2, port)
+ struct sockaddr *sa1;
+ struct sockaddr *sa2;
+ int port;
+{
+ if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len)
+ return 1;
- return 1;
+ switch (sa1->sa_family) {
+ case AF_INET:
+ if (sa1->sa_len != sizeof(struct sockaddr_in))
+ return 1;
+ if (satosin(sa1)->sin_addr.s_addr !=
+ satosin(sa2)->sin_addr.s_addr) {
+ return 1;
+ }
+ if (port && satosin(sa1)->sin_port != satosin(sa2)->sin_port)
+ return 1;
+ break;
+ case AF_INET6:
+ if (sa1->sa_len != sizeof(struct sockaddr_in6))
+ return 1; /*EINVAL*/
+ if (satosin6(sa1)->sin6_scope_id !=
+ satosin6(sa2)->sin6_scope_id) {
+ return 1;
+ }
+ if (!IN6_ARE_ADDR_EQUAL(&satosin6(sa1)->sin6_addr,
+ &satosin6(sa2)->sin6_addr)) {
+ return 1;
+ }
+ if (port &&
+ satosin6(sa1)->sin6_port != satosin6(sa2)->sin6_port) {
+ return 1;
+ }
+ default:
+ if (bcmp(sa1, sa2, sa1->sa_len) != 0)
+ return 1;
+ break;
+ }
+
+ return 0;
}
/*
@@ -2778,8 +3974,8 @@ key_cmpspidx_withmask(spidx0, spidx1)
*/
static int
key_bbcmp(p1, p2, bits)
- register caddr_t p1, p2;
- register u_int bits;
+ caddr_t p1, p2;
+ u_int bits;
{
u_int8_t mask;
@@ -2883,8 +4079,10 @@ key_timehandler(void)
/* sanity check */
if (sav->lft_c == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_timehandler: "
"There is no CURRENT time, why?\n");
+#endif
continue;
}
@@ -2943,8 +4141,10 @@ key_timehandler(void)
/* sanity check */
if (sav->lft_c == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_timehandler: "
"There is no CURRENT time, why?\n");
+#endif
continue;
}
@@ -2955,6 +4155,22 @@ key_timehandler(void)
key_freesav(sav);
sav = NULL;
}
+#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) {
+ /*
+ * XXX: should be checked to be
+ * installed the valid SA.
+ */
+
+ /*
+ * If there is no SA then sending
+ * expire message.
+ */
+ key_expire(sav);
+ }
+#endif
/* check HARD lifetime by bytes */
else if (sav->lft_h->sadb_lifetime_bytes != 0
&& sav->lft_h->sadb_lifetime_bytes < sav->lft_c->sadb_lifetime_bytes) {
@@ -2973,11 +4189,13 @@ key_timehandler(void)
/* sanity check */
if (sav->state != SADB_SASTATE_DEAD) {
+#ifdef IPSEC_DEBUG
printf("key_timehandler: "
"invalid sav->state "
"(queue: %d SA: %d): "
"kill it anyway\n",
SADB_SASTATE_DEAD, sav->state);
+#endif
}
/*
@@ -3011,6 +4229,25 @@ key_timehandler(void)
}
#endif
+ /* SP ACQ tree */
+ {
+ struct secspacq *acq, *nextacq;
+
+ for (acq = LIST_FIRST(&spacqtree);
+ acq != NULL;
+ acq = nextacq) {
+
+ nextacq = LIST_NEXT(acq, chain);
+
+ acq->tick++;
+
+ if (key_blockacq_lifetime < acq->tick && __LIST_CHAINED(acq)) {
+ LIST_REMOVE(acq, chain);
+ KFREE(acq);
+ }
+ }
+ }
+
/* initialize random seed */
if (key_tick_init_random++ > key_int_random) {
key_tick_init_random = 0;
@@ -3029,18 +4266,32 @@ key_timehandler(void)
/*
* to initialize a seed for random()
*/
-void
+static void
key_srandom()
{
struct timeval tv;
microtime(&tv);
+
srandom(tv.tv_usec);
return;
}
/*
+ * to initialize a seed for random()
+ */
+static u_long
+key_random()
+{
+ u_long value;
+
+ value = random();
+
+ return value;
+}
+
+/*
* map SADB_SATYPE_* to IPPROTO_*.
* if satype == SADB_SATYPE then satype is mapped to ~0.
* OUT:
@@ -3057,6 +4308,11 @@ 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;
}
@@ -3077,6 +4333,11 @@ 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;
}
@@ -3086,7 +4347,7 @@ key_proto2satype(proto)
/* %%% PF_KEY */
/*
* SADB_GETSPI processing is to receive
- * <base, src address, dst address, (SPI range)>
+ * <base, (SA2), src address, dst address, (SPI range)>
* from the IKMPd, to assign a unique spi value, to hang on the INBOUND
* tree with the status of LARVAL, and send
* <base, SA(*), address(SD)>
@@ -3096,67 +4357,119 @@ key_proto2satype(proto)
* OUT: NULL if fail.
* other if success, return pointer to the message to send.
*/
-static struct sadb_msg *
-key_getspi(mhp)
- caddr_t *mhp;
+static int
+key_getspi(so, m, mhp)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
struct sadb_address *src0, *dst0;
struct secasindex saidx;
struct secashead *newsah;
struct secasvar *newsav;
u_int8_t proto;
u_int32_t spi;
+ u_int8_t mode;
+ u_int32_t reqid;
+ int error;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_getspi: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
-
- if (mhp[SADB_EXT_ADDRESS_SRC] == NULL
- || mhp[SADB_EXT_ADDRESS_DST] == NULL) {
+ if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL ||
+ mhp->ext[SADB_EXT_ADDRESS_DST] == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_getspi: invalid message is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+ 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_getspi: invalid message is passed.\n");
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+ if (mhp->ext[SADB_X_EXT_SA2] != NULL) {
+ mode = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_mode;
+ reqid = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_reqid;
+ } else {
+ mode = IPSEC_MODE_ANY;
+ reqid = 0;
}
- src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
- dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
+ src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
+ dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
/* map satype to proto */
- if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) {
+ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
+#ifdef IPSEC_DEBUG
printf("key_getspi: invalid satype is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
}
- KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx);
+ /* make sure if port number is zero. */
+ switch (((struct sockaddr *)(src0 + 1))->sa_family) {
+ case AF_INET:
+ if (((struct sockaddr *)(src0 + 1))->sa_len !=
+ sizeof(struct sockaddr_in))
+ return key_senderror(so, m, EINVAL);
+ ((struct sockaddr_in *)(src0 + 1))->sin_port = 0;
+ break;
+ case AF_INET6:
+ if (((struct sockaddr *)(src0 + 1))->sa_len !=
+ sizeof(struct sockaddr_in6))
+ return key_senderror(so, m, EINVAL);
+ ((struct sockaddr_in6 *)(src0 + 1))->sin6_port = 0;
+ break;
+ default:
+ ; /*???*/
+ }
+ switch (((struct sockaddr *)(dst0 + 1))->sa_family) {
+ case AF_INET:
+ if (((struct sockaddr *)(dst0 + 1))->sa_len !=
+ sizeof(struct sockaddr_in))
+ return key_senderror(so, m, EINVAL);
+ ((struct sockaddr_in *)(dst0 + 1))->sin_port = 0;
+ break;
+ case AF_INET6:
+ if (((struct sockaddr *)(dst0 + 1))->sa_len !=
+ sizeof(struct sockaddr_in6))
+ return key_senderror(so, m, EINVAL);
+ ((struct sockaddr_in6 *)(dst0 + 1))->sin6_port = 0;
+ break;
+ default:
+ ; /*???*/
+ }
+
+ /* XXX boundary check against sa_len */
+ KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
/* SPI allocation */
- spi = key_do_getnewspi((struct sadb_spirange *)mhp[SADB_EXT_SPIRANGE],
+ spi = key_do_getnewspi((struct sadb_spirange *)mhp->ext[SADB_EXT_SPIRANGE],
&saidx);
- if (spi == 0) {
- msg0->sadb_msg_errno = EEXIST;
- return NULL;
- }
+ if (spi == 0)
+ return key_senderror(so, m, EINVAL);
/* get a SA index */
if ((newsah = key_getsah(&saidx)) == NULL) {
-
/* create a new SA index */
if ((newsah = key_newsah(&saidx)) == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_getspi: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
+#endif
+ return key_senderror(so, m, ENOBUFS);
}
}
/* get a new SA */
- if ((newsav = key_newsav(mhp, newsah)) == NULL) {
- msg0->sadb_msg_errno = ENOBUFS;
+ /* XXX rewrite */
+ newsav = key_newsav(m, mhp, newsah, &error);
+ if (newsav == NULL) {
/* XXX don't free new SA index allocated in above. */
- return NULL;
+ return key_senderror(so, m, error);
}
/* set spi */
@@ -3164,9 +4477,9 @@ key_getspi(mhp)
#ifndef IPSEC_NONBLOCK_ACQUIRE
/* delete the entry in acqtree */
- if (msg0->sadb_msg_seq != 0) {
+ if (mhp->msg->sadb_msg_seq != 0) {
struct secacq *acq;
- if ((acq = key_getacqbyseq(msg0->sadb_msg_seq)) != NULL) {
+ if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) != NULL) {
/* reset counter in order to deletion by timehander. */
acq->tick = key_blockacq_lifetime;
acq->count = 0;
@@ -3175,43 +4488,70 @@ key_getspi(mhp)
#endif
{
+ struct mbuf *n, *nn;
+ struct sadb_sa *m_sa;
struct sadb_msg *newmsg;
- u_int len;
- caddr_t p;
+ int off, len;
/* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg)
- + sizeof(struct sadb_sa)
- + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC])
- + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]);
-
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == NULL) {
- printf("key_getspi: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
+ len = PFKEY_ALIGN8(sizeof(struct sadb_msg)) +
+ PFKEY_ALIGN8(sizeof(struct sadb_sa));
+ if (len > MCLBYTES)
+ return key_senderror(so, m, ENOBUFS);
+
+ MGETHDR(n, M_DONTWAIT, MT_DATA);
+ if (len > MHLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_freem(n);
+ n = NULL;
+ }
}
- bzero((caddr_t)newmsg, len);
+ if (!n)
+ return key_senderror(so, m, ENOBUFS);
- bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0));
- newmsg->sadb_msg_seq = newsav->seq;
- newmsg->sadb_msg_errno = 0;
- newmsg->sadb_msg_len = PFKEY_UNIT64(len);
- p = (caddr_t)newmsg + sizeof(*msg0);
+ n->m_len = len;
+ n->m_next = NULL;
+ off = 0;
- {
- struct sadb_sa *m_sa;
- m_sa = (struct sadb_sa *)p;
+ m_copydata(m, 0, sizeof(struct sadb_msg), mtod(n, caddr_t) + off);
+ off += PFKEY_ALIGN8(sizeof(struct sadb_msg));
+
+ m_sa = (struct sadb_sa *)(mtod(n, caddr_t) + off);
m_sa->sadb_sa_len = PFKEY_UNIT64(sizeof(struct sadb_sa));
m_sa->sadb_sa_exttype = SADB_EXT_SA;
m_sa->sadb_sa_spi = htonl(spi);
- p += sizeof(struct sadb_sa);
- }
+ off += PFKEY_ALIGN8(sizeof(struct sadb_sa));
+
+#ifdef DIAGNOSTIC
+ if (off != len)
+ panic("length inconsistency in key_getspi");
+#endif
+
+ n->m_next = key_gather_mbuf(m, mhp, 0, 2, SADB_EXT_ADDRESS_SRC,
+ SADB_EXT_ADDRESS_DST);
+ if (!n->m_next) {
+ m_freem(n);
+ return key_senderror(so, m, ENOBUFS);
+ }
- p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]);
- p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]);
+ if (n->m_len < sizeof(struct sadb_msg)) {
+ n = m_pullup(n, sizeof(struct sadb_msg));
+ if (n == NULL)
+ return key_sendup_mbuf(so, m, KEY_SENDUP_ONE);
+ }
+
+ n->m_pkthdr.len = 0;
+ for (nn = n; nn; nn = nn->m_next)
+ n->m_pkthdr.len += nn->m_len;
- return newmsg;
+ newmsg = mtod(n, struct sadb_msg *);
+ newmsg->sadb_msg_seq = newsav->seq;
+ 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_ONE);
}
}
@@ -3239,10 +4579,23 @@ key_do_getnewspi(spirange, saidx)
min = key_spi_minval;
max = key_spi_maxval;
}
+ /* IPCOMP needs 2-byte SPI */
+ if (saidx->proto == IPPROTO_IPCOMP) {
+ u_int32_t t;
+ if (min >= 0x10000)
+ min = 0xffff;
+ if (max >= 0x10000)
+ max = 0xffff;
+ if (min > max) {
+ t = min; min = max; max = t;
+ }
+ }
if (min == max) {
if (key_checkspidup(saidx, min) != NULL) {
+#ifdef IPSEC_DEBUG
printf("key_do_getnewspi: SPI %u exists already.\n", min);
+#endif
return 0;
}
@@ -3257,14 +4610,16 @@ key_do_getnewspi(spirange, saidx)
/* when requesting to allocate spi ranged */
while (count--) {
/* generate pseudo-random SPI value ranged. */
- newspi = min + (random() % ( max - min + 1 ));
+ newspi = min + (key_random() % (max - min + 1));
if (key_checkspidup(saidx, newspi) == NULL)
break;
}
if (count == 0 || newspi == 0) {
+#ifdef IPSEC_DEBUG
printf("key_do_getnewspi: to allocate spi is failed.\n");
+#endif
return 0;
}
}
@@ -3279,130 +4634,171 @@ key_do_getnewspi(spirange, saidx)
/*
* SADB_UPDATE processing
* receive
- * <base, SA, (lifetime(HSC),) address(SD), (address(P),)
+ * <base, SA, (SA2), (lifetime(HSC),) address(SD), (address(P),)
* key(AE), (identity(SD),) (sensitivity)>
* from the ikmpd, and update a secasvar entry whose status is SADB_SASTATE_LARVAL.
* and send
- * <base, SA, (lifetime(HSC),) address(SD), (address(P),)
+ * <base, SA, (SA2), (lifetime(HSC),) address(SD), (address(P),)
* (identity(SD),) (sensitivity)>
* to the ikmpd.
*
- * IN: mhp: pointer to the pointer to each header.
- * OUT: NULL if fail.
- * other if success, return pointer to the message to send.
+ * m will always be freed.
*/
-static struct sadb_msg *
-key_update(mhp)
- caddr_t *mhp;
+static int
+key_update(so, m, mhp)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
struct sadb_sa *sa0;
struct sadb_address *src0, *dst0;
struct secasindex saidx;
struct secashead *sah;
struct secasvar *sav;
u_int16_t proto;
+ u_int8_t mode;
+ u_int32_t reqid;
+ int error;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_update: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
-
/* map satype to proto */
- if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) {
+ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
+#ifdef IPSEC_DEBUG
printf("key_update: invalid satype is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+
+ if (mhp->ext[SADB_EXT_SA] == NULL ||
+ mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL ||
+ mhp->ext[SADB_EXT_ADDRESS_DST] == NULL ||
+ (mhp->msg->sadb_msg_satype == SADB_SATYPE_ESP &&
+ mhp->ext[SADB_EXT_KEY_ENCRYPT] == NULL) ||
+ (mhp->msg->sadb_msg_satype == SADB_SATYPE_AH &&
+ mhp->ext[SADB_EXT_KEY_AUTH] == NULL) ||
+ (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL &&
+ mhp->ext[SADB_EXT_LIFETIME_SOFT] == NULL) ||
+ (mhp->ext[SADB_EXT_LIFETIME_HARD] == NULL &&
+ mhp->ext[SADB_EXT_LIFETIME_SOFT] != NULL)) {
+#ifdef IPSEC_DEBUG
+ printf("key_update: invalid message is passed.\n");
+#endif
+ return key_senderror(so, m, EINVAL);
}
-
- if (mhp[SADB_EXT_SA] == NULL
- || mhp[SADB_EXT_ADDRESS_SRC] == NULL
- || mhp[SADB_EXT_ADDRESS_DST] == NULL
- || (msg0->sadb_msg_satype == SADB_SATYPE_ESP
- && mhp[SADB_EXT_KEY_ENCRYPT] == NULL)
- || (msg0->sadb_msg_satype == SADB_SATYPE_AH
- && mhp[SADB_EXT_KEY_AUTH] == NULL)
- || (mhp[SADB_EXT_LIFETIME_HARD] != NULL
- && mhp[SADB_EXT_LIFETIME_SOFT] == NULL)
- || (mhp[SADB_EXT_LIFETIME_HARD] == NULL
- && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) {
+ if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) ||
+ 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_update: invalid message is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+ if (mhp->ext[SADB_X_EXT_SA2] != NULL) {
+ mode = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_mode;
+ reqid = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_reqid;
+ } else {
+ mode = IPSEC_MODE_ANY;
+ reqid = 0;
}
+ /* XXX boundary checking for other extensions */
- sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA];
- src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
- dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
+ 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]);
- KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx);
+ /* XXX boundary check against sa_len */
+ KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
/* get a SA header */
if ((sah = key_getsah(&saidx)) == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_update: no SA index found.\n");
- msg0->sadb_msg_errno = ENOENT;
- return NULL;
+#endif
+ return key_senderror(so, m, ENOENT);
}
+ /* set spidx if there */
+ /* XXX rewrite */
+ error = key_setident(sah, m, mhp);
+ if (error)
+ return key_senderror(so, m, error);
+
/* find a SA with sequence number. */
- if ((sav = key_getsavbyseq(sah, msg0->sadb_msg_seq)) == NULL) {
+#ifdef IPSEC_DOSEQCHECK
+ if (mhp->msg->sadb_msg_seq != 0
+ && (sav = key_getsavbyseq(sah, mhp->msg->sadb_msg_seq)) == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_update: no larval SA with sequence %u exists.\n",
- msg0->sadb_msg_seq);
- msg0->sadb_msg_errno = ENOENT;
- return NULL;
+ mhp->msg->sadb_msg_seq);
+#endif
+ return key_senderror(so, m, ENOENT);
+ }
+#else
+ if ((sav = key_getsavbyspi(sah, sa0->sadb_sa_spi)) == NULL) {
+#ifdef IPSEC_DEBUG
+ printf("key_update: no such a SA found (spi:%u)\n",
+ (u_int32_t)ntohl(sa0->sadb_sa_spi));
+#endif
+ return key_senderror(so, m, EINVAL);
}
+#endif
/* validity check */
if (sav->sah->saidx.proto != proto) {
+#ifdef IPSEC_DEBUG
printf("key_update: protocol mismatched (DB=%u param=%u)\n",
sav->sah->saidx.proto, proto);
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
}
+#ifdef IPSEC_DOSEQCHECK
if (sav->spi != sa0->sadb_sa_spi) {
+#ifdef IPSEC_DEBUG
printf("key_update: SPI mismatched (DB:%u param:%u)\n",
(u_int32_t)ntohl(sav->spi),
(u_int32_t)ntohl(sa0->sadb_sa_spi));
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
}
- if (sav->pid != msg0->sadb_msg_pid) {
+#endif
+ if (sav->pid != mhp->msg->sadb_msg_pid) {
+#ifdef IPSEC_DEBUG
printf("key_update: pid mismatched (DB:%u param:%u)\n",
- sav->pid, msg0->sadb_msg_pid);
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+ sav->pid, mhp->msg->sadb_msg_pid);
+#endif
+ return key_senderror(so, m, EINVAL);
}
/* copy sav values */
- if (key_setsaval(sav, mhp)) {
+ error = key_setsaval(sav, m, mhp);
+ if (error) {
key_freesav(sav);
- return NULL;
+ return key_senderror(so, m, error);
}
/* check SA values to be mature. */
- if ((msg0->sadb_msg_errno = key_mature(sav)) != 0) {
+ if ((mhp->msg->sadb_msg_errno = key_mature(sav)) != 0) {
key_freesav(sav);
- return NULL;
+ return key_senderror(so, m, 0);
}
- /*
- * we must call key_freesav() whenever we leave a function context,
- * as we did not allocated a new sav (we updated existing sav).
- */
- key_freesav(sav);
- sav = NULL;
-
{
- struct sadb_msg *newmsg;
+ struct mbuf *n;
/* set msg buf from mhp */
- if ((newmsg = key_getmsgbuf_x1(mhp)) == NULL) {
+ n = key_getmsgbuf_x1(m, mhp);
+ if (n == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_update: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
+#endif
+ return key_senderror(so, m, ENOBUFS);
}
- return newmsg;
+
+ m_freem(m);
+ return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
}
}
@@ -3413,6 +4809,7 @@ key_update(mhp)
* NULL : not found
* others : found, pointer to a SA.
*/
+#ifdef IPSEC_DOSEQCHECK
static struct secasvar *
key_getsavbyseq(sah, seq)
struct secashead *sah;
@@ -3424,7 +4821,7 @@ key_getsavbyseq(sah, seq)
state = SADB_SASTATE_LARVAL;
/* search SAD with sequence number ? */
- __LIST_FOREACH(sav, &sah->savtree[state], chain) {
+ LIST_FOREACH(sav, &sah->savtree[state], chain) {
KEY_CHKSASTATE(state, sav->state, "key_getsabyseq");
@@ -3440,96 +4837,126 @@ key_getsavbyseq(sah, seq)
return NULL;
}
+#endif
/*
* SADB_ADD processing
* add a entry to SA database, when received
- * <base, SA, (lifetime(HSC),) address(SD), (address(P),)
+ * <base, SA, (SA2), (lifetime(HSC),) address(SD), (address(P),)
* key(AE), (identity(SD),) (sensitivity)>
* from the ikmpd,
* and send
- * <base, SA, (lifetime(HSC),) address(SD), (address(P),)
+ * <base, SA, (SA2), (lifetime(HSC),) address(SD), (address(P),)
* (identity(SD),) (sensitivity)>
* to the ikmpd.
*
* IGNORE identity and sensitivity messages.
*
- * IN: mhp: pointer to the pointer to each header.
- * OUT: NULL if fail.
- * other if success, return pointer to the message to send.
+ * m will always be freed.
*/
-static struct sadb_msg *
-key_add(mhp)
- caddr_t *mhp;
+static int
+key_add(so, m, mhp)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
struct sadb_sa *sa0;
struct sadb_address *src0, *dst0;
struct secasindex saidx;
struct secashead *newsah;
struct secasvar *newsav;
u_int16_t proto;
+ u_int8_t mode;
+ u_int32_t reqid;
+ int error;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_add: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
-
/* map satype to proto */
- if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) {
+ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
+#ifdef IPSEC_DEBUG
printf("key_add: invalid satype is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+
+ if (mhp->ext[SADB_EXT_SA] == NULL ||
+ mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL ||
+ mhp->ext[SADB_EXT_ADDRESS_DST] == NULL ||
+ (mhp->msg->sadb_msg_satype == SADB_SATYPE_ESP &&
+ mhp->ext[SADB_EXT_KEY_ENCRYPT] == NULL) ||
+ (mhp->msg->sadb_msg_satype == SADB_SATYPE_AH &&
+ mhp->ext[SADB_EXT_KEY_AUTH] == NULL) ||
+ (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL &&
+ mhp->ext[SADB_EXT_LIFETIME_SOFT] == NULL) ||
+ (mhp->ext[SADB_EXT_LIFETIME_HARD] == NULL &&
+ mhp->ext[SADB_EXT_LIFETIME_SOFT] != NULL)) {
+#ifdef IPSEC_DEBUG
+ printf("key_add: invalid message is passed.\n");
+#endif
+ return key_senderror(so, m, EINVAL);
}
-
- if (mhp[SADB_EXT_SA] == NULL
- || mhp[SADB_EXT_ADDRESS_SRC] == NULL
- || mhp[SADB_EXT_ADDRESS_DST] == NULL
- || (msg0->sadb_msg_satype == SADB_SATYPE_ESP
- && mhp[SADB_EXT_KEY_ENCRYPT] == NULL)
- || (msg0->sadb_msg_satype == SADB_SATYPE_AH
- && mhp[SADB_EXT_KEY_AUTH] == NULL)
- || (mhp[SADB_EXT_LIFETIME_HARD] != NULL
- && mhp[SADB_EXT_LIFETIME_SOFT] == NULL)
- || (mhp[SADB_EXT_LIFETIME_HARD] == NULL
- && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) {
+ if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) ||
+ mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) ||
+ mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) {
+ /* XXX need more */
+#ifdef IPSEC_DEBUG
printf("key_add: invalid message is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+ if (mhp->ext[SADB_X_EXT_SA2] != NULL) {
+ mode = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_mode;
+ reqid = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_reqid;
+ } else {
+ mode = IPSEC_MODE_ANY;
+ reqid = 0;
}
- sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA];
- src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
- dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
+ 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];
- KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx);
+ /* XXX boundary check against sa_len */
+ KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
/* get a SA header */
if ((newsah = key_getsah(&saidx)) == NULL) {
-
/* create a new SA header */
if ((newsah = key_newsah(&saidx)) == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_add: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
+#endif
+ return key_senderror(so, m, ENOBUFS);
}
}
+ /* set spidx if there */
+ /* XXX rewrite */
+ error = key_setident(newsah, m, mhp);
+ if (error) {
+ return key_senderror(so, m, error);
+ }
+
/* create new SA entry. */
/* We can create new SA only if SPI is differenct. */
if (key_getsavbyspi(newsah, sa0->sadb_sa_spi)) {
+#ifdef IPSEC_DEBUG
printf("key_add: SA already exists.\n");
- msg0->sadb_msg_errno = EEXIST;
- return NULL;
+#endif
+ return key_senderror(so, m, EEXIST);
+ }
+ newsav = key_newsav(m, mhp, newsah, &error);
+ if (newsav == NULL) {
+ return key_senderror(so, m, error);
}
- if ((newsav = key_newsav(mhp, newsah)) == NULL)
- return NULL;
/* check SA values to be mature. */
- if ((msg0->sadb_msg_errno = key_mature(newsav)) != NULL) {
+ if ((error = key_mature(newsav)) != 0) {
key_freesav(newsav);
- return NULL;
+ return key_senderror(so, m, error);
}
/*
@@ -3538,65 +4965,132 @@ key_add(mhp)
*/
{
- struct sadb_msg *newmsg;
+ struct mbuf *n;
/* set msg buf from mhp */
- if ((newmsg = key_getmsgbuf_x1(mhp)) == NULL) {
- printf("key_add: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
+ n = key_getmsgbuf_x1(m, mhp);
+ if (n == NULL) {
+#ifdef IPSEC_DEBUG
+ printf("key_update: No more memory.\n");
+#endif
+ return key_senderror(so, m, ENOBUFS);
}
- return newmsg;
+ m_freem(m);
+ return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
}
}
-static struct sadb_msg *
-key_getmsgbuf_x1(mhp)
- caddr_t *mhp;
+/* m is retained */
+static int
+key_setident(sah, m, mhp)
+ struct secashead *sah;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
- struct sadb_msg *newmsg;
- u_int len;
- caddr_t p;
+ const struct sadb_ident *idsrc, *iddst;
+ int idsrclen, iddstlen;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
- panic("key_getmsgbuf_x1: NULL pointer is passed.\n");
+ if (sah == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
+ panic("key_setident: NULL pointer is passed.\n");
+
+ /* don't make buffer if not there */
+ if (mhp->ext[SADB_EXT_IDENTITY_SRC] == NULL &&
+ mhp->ext[SADB_EXT_IDENTITY_DST] == NULL) {
+ sah->idents = NULL;
+ sah->identd = NULL;
+ return 0;
+ }
+
+ if (mhp->ext[SADB_EXT_IDENTITY_SRC] == NULL ||
+ mhp->ext[SADB_EXT_IDENTITY_DST] == NULL) {
+#ifdef IPSEC_DEBUG
+ printf("key_setident: invalid identity.\n");
+#endif
+ return EINVAL;
+ }
- msg0 = (struct sadb_msg *)mhp[0];
+ idsrc = (const struct sadb_ident *)mhp->ext[SADB_EXT_IDENTITY_SRC];
+ iddst = (const struct sadb_ident *)mhp->ext[SADB_EXT_IDENTITY_DST];
+ idsrclen = mhp->extlen[SADB_EXT_IDENTITY_SRC];
+ iddstlen = mhp->extlen[SADB_EXT_IDENTITY_DST];
- /* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg)
- + sizeof(struct sadb_sa)
- + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC])
- + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST])
- + (mhp[SADB_EXT_LIFETIME_HARD] == NULL
- ? 0 : sizeof(struct sadb_lifetime))
- + (mhp[SADB_EXT_LIFETIME_SOFT] == NULL
- ? 0 : sizeof(struct sadb_lifetime));
-
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == NULL)
- return NULL;
- bzero((caddr_t)newmsg, len);
+ /* validity check */
+ if (idsrc->sadb_ident_type != iddst->sadb_ident_type) {
+#ifdef IPSEC_DEBUG
+ printf("key_setident: ident type mismatch.\n");
+#endif
+ return EINVAL;
+ }
- bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0));
- newmsg->sadb_msg_errno = 0;
- newmsg->sadb_msg_len = PFKEY_UNIT64(len);
- p = (caddr_t)newmsg + sizeof(*msg0);
+ switch (idsrc->sadb_ident_type) {
+ case SADB_IDENTTYPE_PREFIX:
+ case SADB_IDENTTYPE_FQDN:
+ case SADB_IDENTTYPE_USERFQDN:
+ default:
+ /* XXX do nothing */
+ sah->idents = NULL;
+ sah->identd = NULL;
+ return 0;
+ }
- p = key_setsadbext(p, mhp[SADB_EXT_SA]);
- p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]);
- p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]);
+ /* make structure */
+ KMALLOC(sah->idents, struct sadb_ident *, idsrclen);
+ if (sah->idents == NULL) {
+#ifdef IPSEC_DEBUG
+ printf("key_setident: No more memory.\n");
+#endif
+ return ENOBUFS;
+ }
+ KMALLOC(sah->identd, struct sadb_ident *, iddstlen);
+ if (sah->identd == NULL) {
+ KFREE(sah->idents);
+#ifdef IPSEC_DEBUG
+ printf("key_setident: No more memory.\n");
+#endif
+ return ENOBUFS;
+ }
+ bcopy(idsrc, sah->idents, idsrclen);
+ bcopy(iddst, sah->identd, iddstlen);
+
+ return 0;
+}
+
+/*
+ * m will not be freed on return.
+ * it is caller's responsibility to free the result.
+ */
+static struct mbuf *
+key_getmsgbuf_x1(m, mhp)
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
+{
+ struct mbuf *n;
- if (mhp[SADB_EXT_LIFETIME_HARD] != NULL)
- p = key_setsadbext(p, mhp[SADB_EXT_LIFETIME_HARD]);
+ /* sanity check */
+ if (m == NULL || mhp == NULL || mhp->msg == NULL)
+ panic("key_getmsgbuf_x1: NULL pointer is passed.\n");
+
+ /* create new sadb_msg to reply. */
+ n = key_gather_mbuf(m, mhp, 1, 9, SADB_EXT_RESERVED,
+ SADB_EXT_SA, SADB_X_EXT_SA2,
+ SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST,
+ SADB_EXT_LIFETIME_HARD, SADB_EXT_LIFETIME_SOFT,
+ SADB_EXT_IDENTITY_SRC, SADB_EXT_IDENTITY_DST);
+ if (!n)
+ return NULL;
- if (mhp[SADB_EXT_LIFETIME_SOFT] != NULL)
- p = key_setsadbext(p, mhp[SADB_EXT_LIFETIME_SOFT]);
+ if (n->m_len < sizeof(struct sadb_msg)) {
+ n = m_pullup(n, sizeof(struct sadb_msg));
+ if (n == NULL)
+ return NULL;
+ }
+ mtod(n, struct sadb_msg *)->sadb_msg_errno = 0;
+ mtod(n, struct sadb_msg *)->sadb_msg_len =
+ PFKEY_UNIT64(n->m_pkthdr.len);
- return newmsg;
+ return n;
}
/*
@@ -3608,61 +5102,74 @@ key_getmsgbuf_x1(mhp)
* <base, SA(*), address(SD)>
* to the ikmpd.
*
- * IN: mhp: pointer to the pointer to each header.
- * OUT: NULL if fail.
- * other if success, return pointer to the message to send.
+ * m will always be freed.
*/
-static struct sadb_msg *
-key_delete(mhp)
- caddr_t *mhp;
+static int
+key_delete(so, m, mhp)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
struct sadb_sa *sa0;
struct sadb_address *src0, *dst0;
struct secasindex saidx;
struct secashead *sah;
- struct secasvar *sav;
+ struct secasvar *sav = NULL;
u_int16_t proto;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_delete: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
-
/* map satype to proto */
- if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) {
+ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
+#ifdef IPSEC_DEBUG
printf("key_delete: invalid satype is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
}
- if (mhp[SADB_EXT_SA] == NULL
- || mhp[SADB_EXT_ADDRESS_SRC] == NULL
- || mhp[SADB_EXT_ADDRESS_DST] == NULL) {
+ if (mhp->ext[SADB_EXT_SA] == NULL ||
+ 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");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
}
- sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA];
- src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
- dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
+ if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) ||
+ 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");
+#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]);
- KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx);
+ /* XXX boundary check against sa_len */
+ KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
/* get a SA header */
- if ((sah = key_getsah(&saidx)) == NULL) {
- printf("key_delete: no SA found.\n");
- msg0->sadb_msg_errno = ENOENT;
- return NULL;
- }
+ LIST_FOREACH(sah, &sahtree, chain) {
+ if (sah->state == SADB_SASTATE_DEAD)
+ continue;
+ if (key_cmpsaidx_withoutmode(&sah->saidx, &saidx) == 0)
+ continue;
- /* get a SA with SPI. */
- sav = key_getsavbyspi(sah, sa0->sadb_sa_spi);
- if (sav == NULL) {
- printf("key_delete: no alive SA found.\n");
- msg0->sadb_msg_errno = ENOENT;
- return NULL;
+ /* get a SA with SPI. */
+ sav = key_getsavbyspi(sah, sa0->sadb_sa_spi);
+ if (sav)
+ break;
+ }
+ if (sah == NULL) {
+#ifdef IPSEC_DEBUG
+ printf("key_delete: no SA found.\n");
+#endif
+ return key_senderror(so, m, ENOENT);
}
key_sa_chgstate(sav, SADB_SASTATE_DEAD);
@@ -3670,34 +5177,26 @@ key_delete(mhp)
sav = NULL;
{
+ struct mbuf *n;
struct sadb_msg *newmsg;
- u_int len;
- caddr_t p;
/* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg)
- + sizeof(struct sadb_sa)
- + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC])
- + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]);
-
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == NULL) {
- printf("key_delete: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
- }
- bzero((caddr_t)newmsg, len);
+ n = key_gather_mbuf(m, mhp, 1, 4, SADB_EXT_RESERVED,
+ SADB_EXT_SA, SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST);
+ if (!n)
+ return key_senderror(so, m, ENOBUFS);
- bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0));
+ 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(len);
- p = (caddr_t)newmsg + sizeof(*msg0);
-
- p = key_setsadbext(p, mhp[SADB_EXT_SA]);
- p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]);
- p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]);
+ newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len);
- return newmsg;
+ m_freem(m);
+ return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
}
}
@@ -3711,91 +5210,280 @@ key_delete(mhp)
* (identity(SD),) (sensitivity)>
* to the ikmpd.
*
- * IN: mhp: pointer to the pointer to each header.
- * OUT: NULL if fail.
- * other if success, return pointer to the message to send.
+ * m will always be freed.
*/
-static struct sadb_msg *
-key_get(mhp)
- caddr_t *mhp;
+static int
+key_get(so, m, mhp)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
struct sadb_sa *sa0;
struct sadb_address *src0, *dst0;
struct secasindex saidx;
struct secashead *sah;
- struct secasvar *sav;
+ struct secasvar *sav = NULL;
u_int16_t proto;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_get: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
-
/* map satype to proto */
- if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) {
+ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
+#ifdef IPSEC_DEBUG
printf("key_get: invalid satype is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
}
- if (mhp[SADB_EXT_SA] == NULL
- || mhp[SADB_EXT_ADDRESS_SRC] == NULL
- || mhp[SADB_EXT_ADDRESS_DST] == NULL) {
+ if (mhp->ext[SADB_EXT_SA] == NULL ||
+ mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL ||
+ mhp->ext[SADB_EXT_ADDRESS_DST] == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_get: invalid message is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
}
- sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA];
- src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
- dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
+ if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) ||
+ 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_get: 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];
- KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx);
+ /* XXX boundary check against sa_len */
+ KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
/* get a SA header */
- if ((sah = key_getsah(&saidx)) == NULL) {
- printf("key_get: no SA found.\n");
- msg0->sadb_msg_errno = ENOENT;
- return NULL;
- }
+ LIST_FOREACH(sah, &sahtree, chain) {
+ if (sah->state == SADB_SASTATE_DEAD)
+ continue;
+ if (key_cmpsaidx_withoutmode(&sah->saidx, &saidx) == 0)
+ continue;
- /* get a SA with SPI. */
- sav = key_getsavbyspi(sah, sa0->sadb_sa_spi);
- if (sav == NULL) {
- printf("key_get: no SA with state of mature found.\n");
- msg0->sadb_msg_errno = ENOENT;
- return NULL;
+ /* get a SA with SPI. */
+ sav = key_getsavbyspi(sah, sa0->sadb_sa_spi);
+ if (sav)
+ break;
+ }
+ if (sah == NULL) {
+#ifdef IPSEC_DEBUG
+ printf("key_get: no SA found.\n");
+#endif
+ return key_senderror(so, m, ENOENT);
}
{
- struct sadb_msg *newmsg;
- u_int len;
+ struct mbuf *n;
u_int8_t satype;
/* map proto to satype */
if ((satype = key_proto2satype(sah->saidx.proto)) == 0) {
+#ifdef IPSEC_DEBUG
printf("key_get: there was invalid proto in SAD.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+
+ /* create new sadb_msg to reply. */
+ n = key_setdumpsa(sav, SADB_GET, satype, mhp->msg->sadb_msg_seq,
+ mhp->msg->sadb_msg_pid);
+ if (!n)
+ return key_senderror(so, m, ENOBUFS);
+
+ m_freem(m);
+ return key_sendup_mbuf(so, n, KEY_SENDUP_ONE);
+ }
+}
+
+#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;
+ struct mbuf *result = NULL, *m, *n;
+ int encmin;
+ int i, off, o;
+ int totlen;
+ const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb));
+
+ m = NULL;
+ for (i = 1; i < SADB_EALG_MAX; i++) {
+ algo = &esp_algorithms[i];
+
+ if (algo->keymax < ipsec_esp_keymin)
+ continue;
+ if (algo->keymin < ipsec_esp_keymin)
+ encmin = ipsec_esp_keymin;
+ else
+ encmin = algo->keymin;
+
+ if (ipsec_esp_auth)
+ m = key_getcomb_ah();
+ else {
+#ifdef DIAGNOSTIC
+ if (l > MLEN)
+ panic("assumption failed in key_getcomb_esp");
+#endif
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m) {
+ M_ALIGN(m, l);
+ m->m_len = l;
+ m->m_next = NULL;
+ bzero(mtod(m, caddr_t), m->m_len);
+ }
+ }
+ if (!m)
+ goto fail;
+
+ totlen = 0;
+ for (n = m; n; n = n->m_next)
+ totlen += n->m_len;
+#ifdef DIAGNOSTIC
+ if (totlen % l)
+ panic("assumption failed in key_getcomb_esp");
+#endif
+
+ for (off = 0; off < totlen; off += l) {
+ n = m_pulldown(m, off, l, &o);
+ if (!n) {
+ /* m is already freed */
+ goto fail;
+ }
+ comb = (struct sadb_comb *)(mtod(n, caddr_t) + o);
+ comb->sadb_comb_encrypt = i;
+ comb->sadb_comb_encrypt_minbits = encmin;
+ comb->sadb_comb_encrypt_maxbits = algo->keymax;
+ }
+
+ if (!result)
+ result = m;
+ else
+ m_cat(result, m);
}
- /* calculate a length of message buffer */
- len = key_getmsglen(sav);
+ return result;
+
+ fail:
+ if (result)
+ m_freem(result);
+ return NULL;
+}
+#endif
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == NULL) {
- printf("key_get: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
+/*
+ * 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;
+ 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++) {
+#if 1
+ /* we prefer HMAC algorithms, not old algorithms */
+ if (i != SADB_AALG_SHA1HMAC && i != SADB_AALG_MD5HMAC)
+ continue;
+#endif
+ algo = &ah_algorithms[i];
+
+ if (algo->keymax < ipsec_ah_keymin)
+ continue;
+ if (algo->keymin < ipsec_ah_keymin)
+ min = ipsec_ah_keymin;
+ else
+ min = algo->keymin;
+
+ if (!m) {
+#ifdef DIAGNOSTIC
+ if (l > MLEN)
+ panic("assumption failed in key_getcomb_ah");
+#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));
+ comb->sadb_comb_auth = i;
+ comb->sadb_comb_auth_minbits = min;
+ comb->sadb_comb_auth_maxbits = algo->keymax;
+ }
+
+ return m;
+}
+
+/*
+ * XXX no way to pass mode (transport/tunnel) to userland
+ * XXX replay checking?
+ * XXX sysctl interface to ipsec_{ah,esp}_keymin
+ */
+static struct mbuf *
+key_getprop(saidx)
+ const struct secasindex *saidx;
+{
+ struct sadb_prop *prop;
+ struct mbuf *m, *n;
+ const int l = PFKEY_ALIGN8(sizeof(struct sadb_prop));
+ int totlen;
+
+ switch (saidx->proto) {
+#ifdef IPSEC_ESP
+ case IPPROTO_ESP:
+ m = key_getcomb_esp();
+ break;
+#endif
+ case IPPROTO_AH:
+ m = key_getcomb_ah();
+ break;
+ default:
return NULL;
}
- /* create new sadb_msg to reply. */
- (void)key_setdumpsa(newmsg, sav, SADB_GET,
- satype, msg0->sadb_msg_seq, msg0->sadb_msg_pid);
+ if (!m)
+ return NULL;
+ M_PREPEND(m, l, M_DONTWAIT);
+ if (!m)
+ return NULL;
- return newmsg;
- }
+ totlen = 0;
+ for (n = m; n; n = n->m_next)
+ totlen += n->m_len;
+
+ prop = mtod(m, struct sadb_prop *);
+ bzero(prop, sizeof(*prop));
+ prop->sadb_prop_len = PFKEY_UNIT64(totlen);
+ prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
+ prop->sadb_prop_replay = 32; /* XXX */
+
+ return m;
}
/*
@@ -3816,22 +5504,27 @@ key_get(mhp)
* others: error number
*/
static int
-key_acquire(saidx, spidx)
+key_acquire(saidx, sp)
struct secasindex *saidx;
- struct secpolicyindex *spidx;
+ struct secpolicy *sp;
{
+ struct mbuf *result = NULL, *m;
#ifndef IPSEC_NONBLOCK_ACQUIRE
struct secacq *newacq;
#endif
+ struct secpolicyindex *spidx = NULL;
u_int8_t satype;
- int error;
+ int error = -1;
+ u_int32_t seq;
/* sanity check */
- if (saidx == NULL || spidx == NULL)
+ if (saidx == NULL || sp == NULL)
panic("key_acquire: NULL pointer is passed.\n");
if ((satype = key_proto2satype(saidx->proto)) == 0)
panic("key_acquire: invalid proto is passed.\n");
+ spidx = &sp->spidx;
+
#ifndef IPSEC_NONBLOCK_ACQUIRE
/*
* We never do anything about acquirng SA. There is anather
@@ -3859,119 +5552,125 @@ key_acquire(saidx, spidx)
}
#endif
- {
- struct sadb_msg *newmsg = NULL;
- union sadb_x_ident_id id;
- u_int len;
- caddr_t p;
- /* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(saidx->src.ss_len)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(saidx->dst.ss_len)
- + sizeof(struct sadb_ident)
- + PFKEY_ALIGN8(spidx->src.ss_len)
- + sizeof(struct sadb_ident)
- + PFKEY_ALIGN8(spidx->dst.ss_len)
- + sizeof(struct sadb_prop)
- + sizeof(struct sadb_comb); /* XXX to be multiple */
-
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == 0) {
- printf("key_acquire: No more memory.\n");
- return ENOBUFS;
+#ifndef IPSEC_NONBLOCK_ACQUIRE
+ seq = newacq->seq;
+#else
+ seq = (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq));
+#endif
+ m = key_setsadbmsg(SADB_ACQUIRE, 0, satype, seq, 0, 0);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
}
- bzero((caddr_t)newmsg, len);
+ result = m;
- newmsg->sadb_msg_version = PF_KEY_V2;
- newmsg->sadb_msg_type = SADB_ACQUIRE;
- newmsg->sadb_msg_errno = 0;
- newmsg->sadb_msg_satype = satype;
- newmsg->sadb_msg_len = PFKEY_UNIT64(len);
+ /* set sadb_address for saidx's. */
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
+ (struct sockaddr *)&saidx->src, saidx->src.ss_len << 3,
+ IPSEC_ULPROTO_ANY);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
-#ifndef IPSEC_NONBLOCK_ACQUIRE
- newmsg->sadb_msg_seq = newacq->seq;
-#else
- newmsg->sadb_msg_seq = (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq));
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,
+ (struct sockaddr *)&saidx->dst, saidx->dst.ss_len << 3,
+ IPSEC_ULPROTO_ANY);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
+
+ /* XXX proxy address (optional) */
+
+ /* set sadb_x_policy */
+ m = key_setsadbxpolicy(sp->policy, sp->spidx.dir, sp->id);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
+
+ /* XXX identity (optional) */
+#if 0
+ if (idexttype && fqdn) {
+ /* create identity extension (FQDN) */
+ struct sadb_ident *id;
+ int fqdnlen;
+
+ fqdnlen = strlen(fqdn) + 1; /* +1 for terminating-NUL */
+ id = (struct sadb_ident *)p;
+ bzero(id, sizeof(*id) + PFKEY_ALIGN8(fqdnlen));
+ id->sadb_ident_len = PFKEY_UNIT64(sizeof(*id) + PFKEY_ALIGN8(fqdnlen));
+ id->sadb_ident_exttype = idexttype;
+ id->sadb_ident_type = SADB_IDENTTYPE_FQDN;
+ bcopy(fqdn, id + 1, fqdnlen);
+ p += sizeof(struct sadb_ident) + PFKEY_ALIGN8(fqdnlen);
+ }
+
+ if (idexttype) {
+ /* create identity extension (USERFQDN) */
+ struct sadb_ident *id;
+ int userfqdnlen;
+
+ if (userfqdn) {
+ /* +1 for terminating-NUL */
+ userfqdnlen = strlen(userfqdn) + 1;
+ } else
+ userfqdnlen = 0;
+ id = (struct sadb_ident *)p;
+ bzero(id, sizeof(*id) + PFKEY_ALIGN8(userfqdnlen));
+ id->sadb_ident_len = PFKEY_UNIT64(sizeof(*id) + PFKEY_ALIGN8(userfqdnlen));
+ id->sadb_ident_exttype = idexttype;
+ id->sadb_ident_type = SADB_IDENTTYPE_USERFQDN;
+ /* XXX is it correct? */
+ if (curproc && curproc->p_cred)
+ id->sadb_ident_id = curproc->p_cred->p_ruid;
+ if (userfqdn && userfqdnlen)
+ bcopy(userfqdn, id + 1, userfqdnlen);
+ p += sizeof(struct sadb_ident) + PFKEY_ALIGN8(userfqdnlen);
+ }
#endif
- newmsg->sadb_msg_pid = 0;
- p = (caddr_t)newmsg + sizeof(struct sadb_msg);
+ /* XXX sensitivity (optional) */
- /* set sadb_address for saidx's. */
- p = key_setsadbaddr(p,
- SADB_EXT_ADDRESS_SRC,
- (struct sockaddr *)&saidx->src,
- _INALENBYAF(saidx->src.ss_family) << 3,
- IPSEC_ULPROTO_ANY);
- p = key_setsadbaddr(p,
- SADB_EXT_ADDRESS_DST,
- (struct sockaddr *)&saidx->dst,
- _INALENBYAF(saidx->dst.ss_family) << 3,
- IPSEC_ULPROTO_ANY);
-
- /* set sadb_address for spidx's. */
- id.sadb_x_ident_id_addr.prefix = spidx->prefs;
- id.sadb_x_ident_id_addr.ul_proto = spidx->ul_proto;
- p = key_setsadbident(p,
- SADB_EXT_IDENTITY_SRC,
- SADB_X_IDENTTYPE_ADDR,
- (caddr_t)&spidx->src,
- spidx->src.ss_len,
- *(u_int64_t *)&id);
-
- id.sadb_x_ident_id_addr.prefix = spidx->prefd;
- id.sadb_x_ident_id_addr.ul_proto = spidx->ul_proto;
- p = key_setsadbident(p,
- SADB_EXT_IDENTITY_DST,
- SADB_X_IDENTTYPE_ADDR,
- (caddr_t)&spidx->dst,
- spidx->dst.ss_len,
- *(u_int64_t *)&id);
-
- /* create proposal extension */
- /* set combination extension */
- /* XXX: to be defined by proposal database */
- {
- struct sadb_prop *prop;
- struct sadb_comb *comb;
+ /* create proposal/combination extension */
+ m = key_getprop(saidx);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
- prop = (struct sadb_prop *)p;
- prop->sadb_prop_len = PFKEY_UNIT64(sizeof(*prop) + sizeof(*comb));
- /* XXX to be multiple */
- prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
- prop->sadb_prop_replay = 32; /* XXX be variable ? */
- p += sizeof(struct sadb_prop);
-
- comb = (struct sadb_comb *)p;
- comb->sadb_comb_auth = SADB_AALG_SHA1HMAC; /* XXX ??? */
- comb->sadb_comb_encrypt = SADB_EALG_DESCBC; /* XXX ??? */
- comb->sadb_comb_flags = 0;
- comb->sadb_comb_auth_minbits = 8; /* XXX */
- comb->sadb_comb_auth_maxbits = 1024; /* XXX */
- comb->sadb_comb_encrypt_minbits = 64; /* XXX */
- comb->sadb_comb_encrypt_maxbits = 64; /* XXX */
- comb->sadb_comb_soft_allocations = 0;
- comb->sadb_comb_hard_allocations = 0;
- comb->sadb_comb_soft_bytes = 0;
- comb->sadb_comb_hard_bytes = 0;
- comb->sadb_comb_soft_addtime = 0;
- comb->sadb_comb_hard_addtime = 0;
- comb->sadb_comb_soft_usetime = 0;
- comb->sadb_comb_hard_usetime = 0;
-
- p += sizeof(*comb);
- }
+ if ((result->m_flags & M_PKTHDR) == 0) {
+ error = EINVAL;
+ goto fail;
+ }
- error = key_sendall(newmsg, len);
- if (error != 0)
- printf("key_acquire: key_sendall returned %d\n", error);
- return error;
- }
+ if (result->m_len < sizeof(struct sadb_msg)) {
+ result = m_pullup(result, sizeof(struct sadb_msg));
+ if (result == NULL) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ }
- return 0;
+ 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);
+ return error;
}
#ifndef IPSEC_NONBLOCK_ACQUIRE
@@ -3984,7 +5683,9 @@ key_newacq(saidx)
/* get new entry */
KMALLOC(newacq, struct secacq *, sizeof(struct secacq));
if (newacq == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_newacq: No more memory.\n");
+#endif
return NULL;
}
bzero(newacq, sizeof(*newacq));
@@ -4004,7 +5705,7 @@ key_getacq(saidx)
{
struct secacq *acq;
- __LIST_FOREACH(acq, &acqtree, chain) {
+ LIST_FOREACH(acq, &acqtree, chain) {
if (key_cmpsaidx_exactly(saidx, &acq->saidx))
return acq;
}
@@ -4018,7 +5719,7 @@ key_getacqbyseq(seq)
{
struct secacq *acq;
- __LIST_FOREACH(acq, &acqtree, chain) {
+ LIST_FOREACH(acq, &acqtree, chain) {
if (acq->seq == seq)
return acq;
}
@@ -4027,6 +5728,44 @@ key_getacqbyseq(seq)
}
#endif
+static struct secspacq *
+key_newspacq(spidx)
+ struct secpolicyindex *spidx;
+{
+ struct secspacq *acq;
+
+ /* get new entry */
+ KMALLOC(acq, struct secspacq *, sizeof(struct secspacq));
+ if (acq == NULL) {
+#ifdef IPSEC_DEBUG
+ printf("key_newspacq: No more memory.\n");
+#endif
+ return NULL;
+ }
+ bzero(acq, sizeof(*acq));
+
+ /* copy secindex */
+ bcopy(spidx, &acq->spidx, sizeof(acq->spidx));
+ acq->tick = 0;
+ acq->count = 0;
+
+ return acq;
+}
+
+static struct secspacq *
+key_getspacq(spidx)
+ struct secpolicyindex *spidx;
+{
+ struct secspacq *acq;
+
+ LIST_FOREACH(acq, &spacqtree, chain) {
+ if (key_cmpspidx_exactly(spidx, &acq->spidx))
+ return acq;
+ }
+
+ return NULL;
+}
+
/*
* SADB_ACQUIRE processing,
* in first situation, is receiving
@@ -4039,55 +5778,58 @@ key_getacqbyseq(seq)
* <base, address(SD), (address(P),) (identity(SD),) (sensitivity,) proposal>
* to the socket.
*
- * IN: mhp: pointer to the pointer to each header.
- * OUT: NULL if fail.
- * other if success, return pointer to the message to send.
+ * m will always e freed.
*/
-static struct sadb_msg *
-key_acquire2(mhp)
- caddr_t *mhp;
+static int
+key_acquire2(so, m, mhp)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
- struct sadb_address *src0, *dst0;
+ const struct sadb_address *src0, *dst0;
struct secasindex saidx;
struct secashead *sah;
u_int16_t proto;
+ int error;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_acquire2: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
-
/*
* Error message from KMd.
* We assume that if error was occured in IKEd, the length of PFKEY
* message is equal to the size of sadb_msg structure.
- * We return ~0 even if error occured in this function.
+ * We do not raise error even if error occured in this function.
*/
- if (msg0->sadb_msg_len == PFKEY_UNIT64(sizeof(struct sadb_msg))) {
-
+ if (mhp->msg->sadb_msg_len == PFKEY_UNIT64(sizeof(struct sadb_msg))) {
#ifndef IPSEC_NONBLOCK_ACQUIRE
struct secacq *acq;
/* check sequence number */
- if (msg0->sadb_msg_seq == 0) {
+ if (mhp->msg->sadb_msg_seq == 0) {
+#ifdef IPSEC_DEBUG
printf("key_acquire2: must specify sequence number.\n");
- return (struct sadb_msg *)~0;
+#endif
+ m_freem(m);
+ return 0;
}
- if ((acq = key_getacqbyseq(msg0->sadb_msg_seq)) == NULL) {
+ if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_acquire2: "
"invalid sequence number is passed.\n");
- return (struct sadb_msg *)~0;
+#endif
+ m_freem(m);
+ return 0;
}
/* reset acq counter in order to deletion by timehander. */
acq->tick = key_blockacq_lifetime;
acq->count = 0;
#endif
- return (struct sadb_msg *)~0;
- /* NOTREACHED */
+ m_freem(m);
+ return 0;
}
/*
@@ -4095,59 +5837,62 @@ key_acquire2(mhp)
*/
/* map satype to proto */
- if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) {
+ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
+#ifdef IPSEC_DEBUG
printf("key_acquire2: invalid satype is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
}
- if (mhp[SADB_EXT_ADDRESS_SRC] == NULL
- || mhp[SADB_EXT_ADDRESS_DST] == NULL
- || mhp[SADB_EXT_PROPOSAL] == NULL) {
+ if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL ||
+ mhp->ext[SADB_EXT_ADDRESS_DST] == NULL ||
+ mhp->ext[SADB_EXT_PROPOSAL] == NULL) {
/* error */
+#ifdef IPSEC_DEBUG
printf("key_acquire2: invalid message is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
+ }
+ if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) ||
+ mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address) ||
+ mhp->extlen[SADB_EXT_PROPOSAL] < sizeof(struct sadb_prop)) {
+ /* error */
+#ifdef IPSEC_DEBUG
+ printf("key_acquire2: invalid message is passed.\n");
+#endif
+ return key_senderror(so, m, EINVAL);
}
- src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
- dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
- KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx);
+ 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);
/* get a SA index */
- if ((sah = key_getsah(&saidx)) != NULL) {
+ LIST_FOREACH(sah, &sahtree, chain) {
+ if (sah->state == SADB_SASTATE_DEAD)
+ continue;
+ if (key_cmpsaidx_withmode(&sah->saidx, &saidx))
+ break;
+ }
+ if (sah != NULL) {
+#ifdef IPSEC_DEBUG
printf("key_acquire2: a SA exists already.\n");
- msg0->sadb_msg_errno = EEXIST;
- return NULL;
+#endif
+ return key_senderror(so, m, EEXIST);
}
- msg0->sadb_msg_errno = key_acquire(&saidx, NULL);
- if (msg0->sadb_msg_errno != 0) {
- /* XXX What I do ? */
+ error = key_acquire(&saidx, NULL);
+ if (error != 0) {
+#ifdef IPSEC_DEBUG
printf("key_acquire2: error %d returned "
- "from key_acquire.\n", msg0->sadb_msg_errno);
- return NULL;
- }
-
- {
- struct sadb_msg *newmsg;
- u_int len;
-
- /* create new sadb_msg to reply. */
- len = PFKEY_UNUNIT64(msg0->sadb_msg_len);
-
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == NULL) {
- printf("key_acquire2: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
+ "from key_acquire.\n", mhp->msg->sadb_msg_errno);
+#endif
+ return key_senderror(so, m, error);
}
- bzero((caddr_t)newmsg, len);
-
- bcopy(mhp[0], (caddr_t)newmsg, len);
- return newmsg;
- }
+ return key_sendup_mbuf(so, m, KEY_SENDUP_REGISTERED);
}
/*
@@ -4160,63 +5905,68 @@ key_acquire2(mhp)
* <base, supported>
* to KMD by PF_KEY.
* If socket is detached, must free from regnode.
- * OUT:
- * 0 : succeed
- * others: error number
+ *
+ * m will always e freed.
*/
-static struct sadb_msg *
-key_register(mhp, so)
- caddr_t *mhp;
+static int
+key_register(so, m, mhp)
struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
struct secreg *reg, *newreg = 0;
/* sanity check */
- if (mhp == NULL || so == NULL || mhp[0] == NULL)
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_register: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
+ /* check for invalid register message */
+ if (mhp->msg->sadb_msg_satype >= sizeof(regtree)/sizeof(regtree[0]))
+ return key_senderror(so, m, EINVAL);
/* When SATYPE_UNSPEC is specified, only return sabd_supported. */
- if (msg0->sadb_msg_satype == SADB_SATYPE_UNSPEC)
+ if (mhp->msg->sadb_msg_satype == SADB_SATYPE_UNSPEC)
goto setmsg;
/* check whether existing or not */
- __LIST_FOREACH(reg, &regtree[msg0->sadb_msg_satype], chain) {
+ LIST_FOREACH(reg, &regtree[mhp->msg->sadb_msg_satype], chain) {
if (reg->so == so) {
+#ifdef IPSEC_DEBUG
printf("key_register: socket exists already.\n");
- msg0->sadb_msg_errno = EEXIST;
- return NULL;
+#endif
+ return key_senderror(so, m, EEXIST);
}
}
/* create regnode */
- KMALLOC(newreg, struct secreg *, sizeof(struct secreg));
+ KMALLOC(newreg, struct secreg *, sizeof(*newreg));
if (newreg == NULL) {
+#ifdef IPSEC_DEBUG
printf("key_register: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
+#endif
+ return key_senderror(so, m, ENOBUFS);
}
- bzero((caddr_t)newreg, sizeof(struct secreg));
+ bzero((caddr_t)newreg, sizeof(*newreg));
newreg->so = so;
((struct keycb *)sotorawcb(so))->kp_registered++;
/* add regnode to regtree. */
- LIST_INSERT_HEAD(&regtree[msg0->sadb_msg_satype], newreg, chain);
+ LIST_INSERT_HEAD(&regtree[mhp->msg->sadb_msg_satype], newreg, chain);
setmsg:
- {
+ {
+ struct mbuf *n;
struct sadb_msg *newmsg;
struct sadb_supported *sup;
u_int len, alen, elen;
- caddr_t p;
+ int off;
+ int i;
+ 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));
@@ -4224,79 +5974,89 @@ key_register(mhp, so)
elen = 0;
#endif
- len = sizeof(struct sadb_msg)
- + alen
- + elen;
+ len = sizeof(struct sadb_msg) + alen + elen;
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == NULL) {
- printf("key_register: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
+ if (len > MCLBYTES)
+ return key_senderror(so, m, ENOBUFS);
+
+ MGETHDR(n, M_DONTWAIT, MT_DATA);
+ if (len > MHLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_freem(n);
+ n = NULL;
+ }
}
- bzero((caddr_t)newmsg, len);
+ if (!n)
+ return key_senderror(so, m, ENOBUFS);
- bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0));
+ n->m_pkthdr.len = n->m_len = len;
+ n->m_next = NULL;
+ off = 0;
+
+ m_copydata(m, 0, sizeof(struct sadb_msg), mtod(n, caddr_t) + off);
+ newmsg = mtod(n, struct sadb_msg *);
newmsg->sadb_msg_errno = 0;
newmsg->sadb_msg_len = PFKEY_UNIT64(len);
- p = (caddr_t)newmsg + sizeof(*msg0);
+ off += PFKEY_ALIGN8(sizeof(struct sadb_msg));
/* for authentication algorithm */
- sup = (struct sadb_supported *)p;
- sup->sadb_supported_len = PFKEY_UNIT64(alen);
- sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH;
- p += sizeof(*sup);
-
- {
- int i;
- struct sadb_alg *alg;
- struct ah_algorithm *algo;
-
- for (i = 1; i < SADB_AALG_MAX; i++) {
- algo = &ah_algorithms[i];
- alg = (struct sadb_alg *)p;
- alg->sadb_alg_id = i;
- alg->sadb_alg_ivlen = 0;
- alg->sadb_alg_minbits = algo->keymin;
- alg->sadb_alg_maxbits = algo->keymax;
- p += sizeof(struct sadb_alg);
+ if (alen) {
+ sup = (struct sadb_supported *)(mtod(n, caddr_t) + off);
+ sup->sadb_supported_len = PFKEY_UNIT64(alen);
+ 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;
+
+ aalgo = &ah_algorithms[i];
+ alg = (struct sadb_alg *)(mtod(n, caddr_t) + off);
+ alg->sadb_alg_id = i;
+ alg->sadb_alg_ivlen = 0;
+ alg->sadb_alg_minbits = aalgo->keymin;
+ alg->sadb_alg_maxbits = aalgo->keymax;
+ off += PFKEY_ALIGN8(sizeof(*alg));
+ }
}
- }
#ifdef IPSEC_ESP
/* for encryption algorithm */
- sup = (struct sadb_supported *)p;
- sup->sadb_supported_len = PFKEY_UNIT64(elen);
- sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT;
- p += sizeof(*sup);
-
- {
- int i;
- struct sadb_alg *alg;
- struct esp_algorithm *algo;
-
- for (i = 1; i < SADB_EALG_MAX; i++) {
- algo = &esp_algorithms[i];
-
- alg = (struct sadb_alg *)p;
- alg->sadb_alg_id = i;
- if (algo && algo->ivlen) {
- /*
- * give NULL to get the value preferred by algorithm
- * XXX SADB_X_EXT_DERIV ?
- */
- alg->sadb_alg_ivlen = (*algo->ivlen)(NULL);
- } else
- alg->sadb_alg_ivlen = 0;
- alg->sadb_alg_minbits = algo->keymin;
- alg->sadb_alg_maxbits = algo->keymax;
- p += sizeof(struct sadb_alg);
+ if (elen) {
+ sup = (struct sadb_supported *)(mtod(n, caddr_t) + off);
+ sup->sadb_supported_len = PFKEY_UNIT64(elen);
+ 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;
+
+ ealgo = &esp_algorithms[i];
+ alg = (struct sadb_alg *)(mtod(n, caddr_t) + off);
+ alg->sadb_alg_id = i;
+ if (ealgo && ealgo->ivlen) {
+ /*
+ * give NULL to get the value preferred by
+ * algorithm XXX SADB_X_EXT_DERIV ?
+ */
+ alg->sadb_alg_ivlen = (*ealgo->ivlen)(NULL);
+ } else
+ alg->sadb_alg_ivlen = 0;
+ alg->sadb_alg_minbits = ealgo->keymin;
+ alg->sadb_alg_maxbits = ealgo->keymax;
+ off += PFKEY_ALIGN8(sizeof(struct sadb_alg));
+ }
}
- }
#endif
- return newmsg;
- }
+#ifdef DIGAGNOSTIC
+ if (off != len)
+ panic("length assumption failed in key_register");
+#endif
+
+ m_freem(m);
+ return key_sendup_mbuf(so, n, KEY_SENDUP_REGISTERED);
+ }
}
/*
@@ -4320,7 +6080,7 @@ key_freereg(so)
* one socket is registered to multiple type of SA.
*/
for (i = 0; i <= SADB_SATYPE_MAX; i++) {
- __LIST_FOREACH(reg, &regtree[i], chain) {
+ LIST_FOREACH(reg, &regtree[i], chain) {
if (reg->so == so
&& __LIST_CHAINED(reg)) {
LIST_REMOVE(reg, chain);
@@ -4329,14 +6089,14 @@ key_freereg(so)
}
}
}
-
+
return;
}
/*
* SADB_EXPIRE processing
* send
- * <base, SA, lifetime(C and one of HS), address(SD)>
+ * <base, SA, SA2, lifetime(C and one of HS), address(SD)>
* to KMD by PF_KEY.
* NOTE: We send only soft lifetime extension.
*
@@ -4349,6 +6109,10 @@ key_expire(sav)
{
int s;
int satype;
+ struct mbuf *result = NULL, *m;
+ int len;
+ int error = -1;
+ struct sadb_lifetime *lt;
/* XXX: Why do we lock ? */
s = splnet(); /*called from softclock()*/
@@ -4361,73 +6125,94 @@ key_expire(sav)
if ((satype = key_proto2satype(sav->sah->saidx.proto)) == 0)
panic("key_expire: invalid proto is passed.\n");
- {
- struct sadb_msg *newmsg = NULL;
- u_int len;
- caddr_t p;
- int error;
-
- /* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg)
- + sizeof(struct sadb_sa)
- + sizeof(struct sadb_lifetime)
- + sizeof(struct sadb_lifetime)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(sav->sah->saidx.src.ss_len)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(sav->sah->saidx.dst.ss_len);
-
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == NULL) {
- printf("key_expire: No more memory.\n");
- splx(s);
- return ENOBUFS;
+ /* set msg header */
+ m = key_setsadbmsg(SADB_EXPIRE, 0, satype, sav->seq, 0, sav->refcnt);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
}
- bzero((caddr_t)newmsg, len);
+ result = m;
- /* set msg header */
- p = key_setsadbmsg((caddr_t)newmsg, SADB_EXPIRE, len,
- satype, sav->seq, 0,
- sav->sah->saidx.mode, sav->refcnt);
+ /* create SA extension */
+ m = key_setsadbsa(sav);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
/* create SA extension */
- p = key_setsadbsa(p, sav);
+ m = key_setsadbxsa2(sav->sah->saidx.mode, sav->sah->saidx.reqid);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
- /* create lifetime extension */
- {
- struct sadb_lifetime *m_lt = (struct sadb_lifetime *)p;
-
- m_lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime));
- m_lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
- m_lt->sadb_lifetime_allocations = sav->lft_c->sadb_lifetime_allocations;
- m_lt->sadb_lifetime_bytes = sav->lft_c->sadb_lifetime_bytes;
- m_lt->sadb_lifetime_addtime = sav->lft_c->sadb_lifetime_addtime;
- m_lt->sadb_lifetime_usetime = sav->lft_c->sadb_lifetime_usetime;
- p += sizeof(struct sadb_lifetime);
-
- /* copy SOFT lifetime extension. */
- bcopy(sav->lft_s, p, sizeof(struct sadb_lifetime));
- p += sizeof(struct sadb_lifetime);
- }
+ /* create lifetime extension (current and soft) */
+ 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 = sav->lft_c->sadb_lifetime_allocations;
+ lt->sadb_lifetime_bytes = sav->lft_c->sadb_lifetime_bytes;
+ lt->sadb_lifetime_addtime = sav->lft_c->sadb_lifetime_addtime;
+ lt->sadb_lifetime_usetime = sav->lft_c->sadb_lifetime_usetime;
+ lt = (struct sadb_lifetime *)(mtod(m, caddr_t) + len / 2);
+ bcopy(sav->lft_s, lt, sizeof(*lt));
+ m_cat(result, m);
/* set sadb_address for source */
- p = key_setsadbaddr(p,
- SADB_EXT_ADDRESS_SRC,
- (struct sockaddr *)&sav->sah->saidx.src,
- _INALENBYAF(sav->sah->saidx.src.ss_family) << 3,
- IPSEC_ULPROTO_ANY);
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
+ (struct sockaddr *)&sav->sah->saidx.src,
+ sav->sah->saidx.src.ss_len << 3, IPSEC_ULPROTO_ANY);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
/* set sadb_address for destination */
- p = key_setsadbaddr(p,
- SADB_EXT_ADDRESS_DST,
- (struct sockaddr *)&sav->sah->saidx.dst,
- _INALENBYAF(sav->sah->saidx.dst.ss_family) << 3,
- IPSEC_ULPROTO_ANY);
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,
+ (struct sockaddr *)&sav->sah->saidx.dst,
+ sav->sah->saidx.dst.ss_len << 3, IPSEC_ULPROTO_ANY);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
- error = key_sendall(newmsg, len);
+ if ((result->m_flags & M_PKTHDR) == 0)
+ goto fail;
+
+ if (result->m_len < sizeof(struct sadb_msg)) {
+ result = m_pullup(result, sizeof(struct sadb_msg));
+ if (result == NULL)
+ 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;
- }
}
/*
@@ -4440,15 +6225,15 @@ key_expire(sav)
* to the ikmpd.
* NOTE: to do is only marking SADB_SASTATE_DEAD.
*
- * IN: mhp: pointer to the pointer to each header.
- * OUT: NULL if fail.
- * other if success, return pointer to the message to send.
+ * m will always be freed.
*/
-static struct sadb_msg *
-key_flush(mhp)
- caddr_t *mhp;
+static int
+key_flush(so, m, mhp)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
+ struct sadb_msg *newmsg;
struct secashead *sah, *nextsah;
struct secasvar *sav, *nextsav;
u_int16_t proto;
@@ -4456,33 +6241,30 @@ key_flush(mhp)
u_int stateidx;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (so == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_flush: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
-
/* map satype to proto */
- if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) {
+ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
+#ifdef IPSEC_DEBUG
printf("key_flush: invalid satype is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
}
/* no SATYPE specified, i.e. flushing all SA. */
for (sah = LIST_FIRST(&sahtree);
sah != NULL;
sah = nextsah) {
-
nextsah = LIST_NEXT(sah, chain);
- if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC
+ if (mhp->msg->sadb_msg_satype != SADB_SATYPE_UNSPEC
&& proto != sah->saidx.proto)
continue;
for (stateidx = 0;
stateidx < _ARRAYLEN(saorder_state_alive);
stateidx++) {
-
state = saorder_state_any[stateidx];
for (sav = LIST_FIRST(&sah->savtree[state]);
sav != NULL;
@@ -4491,33 +6273,30 @@ key_flush(mhp)
nextsav = LIST_NEXT(sav, chain);
key_sa_chgstate(sav, SADB_SASTATE_DEAD);
+ key_freesav(sav);
}
}
sah->state = SADB_SASTATE_DEAD;
}
- {
- struct sadb_msg *newmsg;
- u_int len;
-
- /* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg);
-
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == NULL) {
+ if (m->m_len < sizeof(struct sadb_msg) ||
+ sizeof(struct sadb_msg) > m->m_len + M_TRAILINGSPACE(m)) {
+#ifdef IPSEC_DEBUG
printf("key_flush: No more memory.\n");
- msg0->sadb_msg_errno = ENOBUFS;
- return NULL;
+#endif
+ return key_senderror(so, m, ENOBUFS);
}
- bzero((caddr_t)newmsg, len);
- bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0));
+ if (m->m_next)
+ m_freem(m->m_next);
+ m->m_next = NULL;
+ m->m_pkthdr.len = m->m_len = sizeof(struct sadb_msg);
+ newmsg = mtod(m, struct sadb_msg *);
newmsg->sadb_msg_errno = 0;
- newmsg->sadb_msg_len = PFKEY_UNIT64(len);
+ newmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len);
- return newmsg;
- }
+ return key_sendup_mbuf(so, m, KEY_SENDUP_ALL);
}
/*
@@ -4530,206 +6309,171 @@ key_flush(mhp)
* <base> .....
* to the ikmpd.
*
- * IN: mhp: pointer to the pointer to each header.
- * OUT: error code. 0 on success.
+ * m will always be freed.
*/
static int
-key_dump(mhp, so, target)
- caddr_t *mhp;
+key_dump(so, m, mhp)
struct socket *so;
- int target;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
struct secashead *sah;
struct secasvar *sav;
u_int16_t proto;
u_int stateidx;
u_int8_t satype;
u_int8_t state;
- int len, cnt;
+ int cnt;
struct sadb_msg *newmsg;
+ struct mbuf *n;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_dump: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
-
/* map satype to proto */
- if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) {
+ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
+#ifdef IPSEC_DEBUG
printf("key_dump: invalid satype is passed.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
}
/* count sav entries to be sent to the userland. */
cnt = 0;
- __LIST_FOREACH(sah, &sahtree, chain) {
-
- if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC
+ LIST_FOREACH(sah, &sahtree, chain) {
+ if (mhp->msg->sadb_msg_satype != SADB_SATYPE_UNSPEC
&& proto != sah->saidx.proto)
continue;
for (stateidx = 0;
stateidx < _ARRAYLEN(saorder_state_any);
stateidx++) {
-
state = saorder_state_any[stateidx];
- __LIST_FOREACH(sav, &sah->savtree[state], chain) {
+ LIST_FOREACH(sav, &sah->savtree[state], chain) {
cnt++;
}
}
}
if (cnt == 0)
- return ENOENT;
+ return key_senderror(so, m, ENOENT);
/* send this to the userland, one at a time. */
newmsg = NULL;
- __LIST_FOREACH(sah, &sahtree, chain) {
-
- if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC
+ LIST_FOREACH(sah, &sahtree, chain) {
+ if (mhp->msg->sadb_msg_satype != SADB_SATYPE_UNSPEC
&& proto != sah->saidx.proto)
continue;
/* map proto to satype */
if ((satype = key_proto2satype(sah->saidx.proto)) == 0) {
+#ifdef IPSEC_DEBUG
printf("key_dump: there was invalid proto in SAD.\n");
- msg0->sadb_msg_errno = EINVAL;
- return NULL;
+#endif
+ return key_senderror(so, m, EINVAL);
}
for (stateidx = 0;
stateidx < _ARRAYLEN(saorder_state_any);
stateidx++) {
-
state = saorder_state_any[stateidx];
- __LIST_FOREACH(sav, &sah->savtree[state], chain) {
-
- len = key_getmsglen(sav);
- KMALLOC(newmsg, struct sadb_msg *, len);
- if (newmsg == NULL) {
- printf("key_dump: No more memory.\n");
- return ENOBUFS;
- }
- bzero((caddr_t)newmsg, len);
+ LIST_FOREACH(sav, &sah->savtree[state], chain) {
+ n = key_setdumpsa(sav, SADB_DUMP, satype,
+ --cnt, mhp->msg->sadb_msg_pid);
+ if (!n)
+ return key_senderror(so, m, ENOBUFS);
- --cnt;
- (void)key_setdumpsa(newmsg, sav, SADB_DUMP,
- satype, cnt, msg0->sadb_msg_pid);
-
- key_sendup(so, newmsg, len, target);
- KFREE(newmsg);
- newmsg = NULL;
+ key_sendup_mbuf(so, n, KEY_SENDUP_ONE);
}
}
}
+ m_freem(m);
return 0;
}
/*
* SADB_X_PROMISC processing
+ *
+ * m will always be freed.
*/
-static void
-key_promisc(mhp, so)
- caddr_t *mhp;
+static int
+key_promisc(so, m, mhp)
struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
{
- struct sadb_msg *msg0;
int olen;
/* sanity check */
- if (mhp == NULL || mhp[0] == NULL)
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_promisc: NULL pointer is passed.\n");
- msg0 = (struct sadb_msg *)mhp[0];
- olen = PFKEY_UNUNIT64(msg0->sadb_msg_len);
+ olen = PFKEY_UNUNIT64(mhp->msg->sadb_msg_len);
if (olen < sizeof(struct sadb_msg)) {
- return;
+#if 1
+ return key_senderror(so, m, EINVAL);
+#else
+ m_freem(m);
+ return 0;
+#endif
} else if (olen == sizeof(struct sadb_msg)) {
/* enable/disable promisc mode */
struct keycb *kp;
- int target = 0;
-
- target = KEY_SENDUP_ONE;
- if (so == NULL) {
- return;
- }
- if ((kp = (struct keycb *)sotorawcb(so)) == NULL) {
- msg0->sadb_msg_errno = EINVAL;
- goto sendorig;
- }
- msg0->sadb_msg_errno = 0;
- if (msg0->sadb_msg_satype == 1 || msg0->sadb_msg_satype == 0) {
- kp->kp_promisc = msg0->sadb_msg_satype;
- } else {
- msg0->sadb_msg_errno = EINVAL;
- goto sendorig;
+ if ((kp = (struct keycb *)sotorawcb(so)) == NULL)
+ return key_senderror(so, m, EINVAL);
+ mhp->msg->sadb_msg_errno = 0;
+ switch (mhp->msg->sadb_msg_satype) {
+ case 0:
+ case 1:
+ kp->kp_promisc = mhp->msg->sadb_msg_satype;
+ break;
+ default:
+ return key_senderror(so, m, EINVAL);
}
/* send the original message back to everyone */
- msg0->sadb_msg_errno = 0;
- target = KEY_SENDUP_ALL;
-sendorig:
- key_sendup(so, msg0, PFKEY_UNUNIT64(msg0->sadb_msg_len), target);
+ mhp->msg->sadb_msg_errno = 0;
+ return key_sendup_mbuf(so, m, KEY_SENDUP_ALL);
} else {
/* send packet as is */
- struct sadb_msg *msg;
- int len;
- len = olen - sizeof(struct sadb_msg);
- KMALLOC(msg, struct sadb_msg *, len);
- if (msg == NULL) {
- msg0->sadb_msg_errno = ENOBUFS;
- key_sendup(so, msg0, PFKEY_UNUNIT64(msg0->sadb_msg_len),
- KEY_SENDUP_ONE); /*XXX*/
- }
+ m_adj(m, PFKEY_ALIGN8(sizeof(struct sadb_msg)));
- /* XXX if sadb_msg_seq is specified, send to specific pid */
- key_sendup(so, msg, len, KEY_SENDUP_ALL);
- KFREE(msg);
+ /* TODO: if sadb_msg_seq is specified, send to specific pid */
+ return key_sendup_mbuf(so, m, KEY_SENDUP_ALL);
}
}
-/*
- * send message to the socket.
- * OUT:
- * 0 : success
- * others : fail
- */
-static int
-key_sendall(msg, len)
- struct sadb_msg *msg;
- u_int len;
-{
- struct secreg *reg;
- int error = 0;
-
- /* sanity check */
- if (msg == NULL)
- panic("key_sendall: NULL pointer is passed.\n");
-
- /* search table registerd socket to send a message. */
- __LIST_FOREACH(reg, &regtree[msg->sadb_msg_satype], chain) {
- error = key_sendup(reg->so, msg, len, KEY_SENDUP_ONE);
- if (error != 0) {
- if (error == ENOBUFS)
- printf("key_sendall: No more memory.\n");
- else {
- printf("key_sendall: key_sendup returned %d\n",
- error);
- }
- KFREE(msg);
- return error;
- }
- }
-
- KFREE(msg);
- return 0;
-}
+static int (*key_typesw[]) __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *)) = {
+ NULL, /* SADB_RESERVED */
+ key_getspi, /* SADB_GETSPI */
+ key_update, /* SADB_UPDATE */
+ key_add, /* SADB_ADD */
+ key_delete, /* SADB_DELETE */
+ key_get, /* SADB_GET */
+ key_acquire2, /* SADB_ACQUIRE */
+ key_register, /* SADB_REGISTER */
+ NULL, /* SADB_EXPIRE */
+ key_flush, /* SADB_FLUSH */
+ key_dump, /* SADB_DUMP */
+ key_promisc, /* SADB_X_PROMISC */
+ NULL, /* SADB_X_PCHANGE */
+ key_spdadd, /* SADB_X_SPDUPDATE */
+ key_spdadd, /* SADB_X_SPDADD */
+ key_spddelete, /* SADB_X_SPDDELETE */
+ key_spdget, /* SADB_X_SPDGET */
+ NULL, /* SADB_X_SPDACQUIRE */
+ key_spddump, /* SADB_X_SPDDUMP */
+ key_spdflush, /* SADB_X_SPDFLUSH */
+ key_spdadd, /* SADB_X_SPDSETIDX */
+ NULL, /* SADB_X_SPDEXPIRE */
+ key_spddelete2, /* SADB_X_SPDDELETE2 */
+};
/*
* parse sadb_msg buffer to process PFKEYv2,
@@ -4743,49 +6487,103 @@ key_sendall(msg, len)
* length for buffer to send to user process.
*/
int
-key_parse(msgp, so, targetp)
- struct sadb_msg **msgp;
+key_parse(m, so)
+ struct mbuf *m;
struct socket *so;
- int *targetp;
{
- struct sadb_msg *msg = *msgp, *newmsg = NULL;
- caddr_t mhp[SADB_EXT_MAX + 1];
+ struct sadb_msg *msg;
+ struct sadb_msghdr mh;
u_int orglen;
int error;
+ int target;
/* sanity check */
- if (msg == NULL || so == NULL)
+ if (m == NULL || so == NULL)
panic("key_parse: NULL pointer is passed.\n");
+#if 0 /*kdebug_sadb assumes msg in linear buffer*/
KEYDEBUG(KEYDEBUG_KEY_DUMP,
printf("key_parse: passed sadb_msg\n");
kdebug_sadb(msg));
+#endif
+ if (m->m_len < sizeof(struct sadb_msg)) {
+ m = m_pullup(m, sizeof(struct sadb_msg));
+ if (!m)
+ return ENOBUFS;
+ }
+ msg = mtod(m, struct sadb_msg *);
orglen = PFKEY_UNUNIT64(msg->sadb_msg_len);
+ target = KEY_SENDUP_ONE;
- if (targetp)
- *targetp = KEY_SENDUP_ONE;
+ if ((m->m_flags & M_PKTHDR) == 0 ||
+ m->m_pkthdr.len != m->m_pkthdr.len) {
+#ifdef IPSEC_DEBUG
+ printf("key_parse: invalid message length.\n");
+#endif
+ pfkeystat.out_invlen++;
+ error = EINVAL;
+ goto senderror;
+ }
- /* check version */
if (msg->sadb_msg_version != PF_KEY_V2) {
+#ifdef IPSEC_DEBUG
printf("key_parse: PF_KEY version %u is mismatched.\n",
msg->sadb_msg_version);
- return EINVAL;
+#endif
+ pfkeystat.out_invver++;
+ error = EINVAL;
+ goto senderror;
}
- /* check type */
if (msg->sadb_msg_type > SADB_MAX) {
+#ifdef IPSEC_DEBUG
printf("key_parse: invalid type %u is passed.\n",
msg->sadb_msg_type);
- msg->sadb_msg_errno = EINVAL;
- return orglen;
+#endif
+ pfkeystat.out_invmsgtype++;
+ error = EINVAL;
+ goto senderror;
}
- /* align message. */
- if (key_align(msg, mhp) != 0) {
- msg->sadb_msg_errno = EINVAL;
- return orglen;
+ /* for old-fashioned code - should be nuked */
+ if (m->m_pkthdr.len > MCLBYTES) {
+ m_freem(m);
+ return ENOBUFS;
}
+ if (m->m_next) {
+ struct mbuf *n;
+
+ MGETHDR(n, M_DONTWAIT, MT_DATA);
+ if (n && m->m_pkthdr.len > MHLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_free(n);
+ n = NULL;
+ }
+ }
+ if (!n) {
+ m_freem(m);
+ return ENOBUFS;
+ }
+ m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t));
+ n->m_pkthdr.len = n->m_len = m->m_pkthdr.len;
+ n->m_next = NULL;
+ m_freem(m);
+ m = n;
+ }
+
+ /* align the mbuf chain so that extensions are in contiguous region. */
+ error = key_align(m, &mh);
+ if (error)
+ return error;
+
+ if (m->m_next) { /*XXX*/
+ m_freem(m);
+ return ENOBUFS;
+ }
+
+ msg = mh.msg;
/* check SA type */
switch (msg->sadb_msg_satype) {
@@ -4798,87 +6596,150 @@ key_parse(msgp, so, targetp)
case SADB_GET:
case SADB_ACQUIRE:
case SADB_EXPIRE:
+#ifdef IPSEC_DEBUG
printf("key_parse: must specify satype "
"when msg type=%u.\n",
msg->sadb_msg_type);
- msg->sadb_msg_errno = EINVAL;
- return orglen;
+#endif
+ pfkeystat.out_invsatype++;
+ error = EINVAL;
+ goto senderror;
}
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:
case SADB_X_SPDGET:
case SADB_X_SPDDUMP:
case SADB_X_SPDFLUSH:
- printf("key_parse: illegal satype=%u\n", msg->sadb_msg_type);
- msg->sadb_msg_errno = EINVAL;
- return orglen;
+ case SADB_X_SPDSETIDX:
+ case SADB_X_SPDUPDATE:
+ case SADB_X_SPDDELETE2:
+#ifdef IPSEC_DEBUG
+ printf("key_parse: illegal satype=%u\n",
+ msg->sadb_msg_type);
+#endif
+ pfkeystat.out_invsatype++;
+ error = EINVAL;
+ goto senderror;
}
break;
case SADB_SATYPE_RSVP:
case SADB_SATYPE_OSPFV2:
case SADB_SATYPE_RIPV2:
case SADB_SATYPE_MIP:
+#ifdef IPSEC_DEBUG
printf("key_parse: type %u isn't supported.\n",
msg->sadb_msg_satype);
- msg->sadb_msg_errno = EOPNOTSUPP;
- return orglen;
- case 1: /* XXX: What does it do ? */
+#endif
+ pfkeystat.out_invsatype++;
+ error = EOPNOTSUPP;
+ goto senderror;
+ case 1: /* XXX: What does it do? */
if (msg->sadb_msg_type == SADB_X_PROMISC)
break;
/*FALLTHROUGH*/
default:
+#ifdef IPSEC_DEBUG
printf("key_parse: invalid type %u is passed.\n",
msg->sadb_msg_satype);
- msg->sadb_msg_errno = EINVAL;
- return orglen;
+#endif
+ pfkeystat.out_invsatype++;
+ error = EINVAL;
+ goto senderror;
}
/* check field of upper layer protocol and address family */
- if (mhp[SADB_EXT_ADDRESS_SRC] != NULL
- && mhp[SADB_EXT_ADDRESS_DST] != NULL) {
+ if (mh.ext[SADB_EXT_ADDRESS_SRC] != NULL
+ && mh.ext[SADB_EXT_ADDRESS_DST] != NULL) {
struct sadb_address *src0, *dst0;
- u_int prefix;
+ u_int plen;
- src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
- dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
+ src0 = (struct sadb_address *)(mh.ext[SADB_EXT_ADDRESS_SRC]);
+ dst0 = (struct sadb_address *)(mh.ext[SADB_EXT_ADDRESS_DST]);
/* check upper layer protocol */
if (src0->sadb_address_proto != dst0->sadb_address_proto) {
+#ifdef IPSEC_DEBUG
printf("key_parse: upper layer protocol mismatched.\n");
- msg->sadb_msg_errno = EINVAL;
- return orglen;
+#endif
+ pfkeystat.out_invaddr++;
+ error = EINVAL;
+ goto senderror;
}
/* check family */
- if (PFKEY_ADDR_SADDR(src0)->sa_family
- != PFKEY_ADDR_SADDR(dst0)->sa_family) {
+ if (PFKEY_ADDR_SADDR(src0)->sa_family !=
+ PFKEY_ADDR_SADDR(dst0)->sa_family) {
+#ifdef IPSEC_DEBUG
printf("key_parse: address family mismatched.\n");
- msg->sadb_msg_errno = EINVAL;
- return orglen;
+#endif
+ pfkeystat.out_invaddr++;
+ error = EINVAL;
+ goto senderror;
+ }
+ if (PFKEY_ADDR_SADDR(src0)->sa_len !=
+ PFKEY_ADDR_SADDR(dst0)->sa_len) {
+#ifdef IPSEC_DEBUG
+ printf("key_parse: address struct size mismatched.\n");
+#endif
+ pfkeystat.out_invaddr++;
+ error = EINVAL;
+ goto senderror;
}
- prefix = _INALENBYAF(PFKEY_ADDR_SADDR(src0)->sa_family) << 3;
-
- /* check max prefixlen */
- if (prefix < src0->sadb_address_prefixlen
- || prefix < dst0->sadb_address_prefixlen) {
- printf("key_parse: illegal prefixlen.\n");
- msg->sadb_msg_errno = EINVAL;
- return orglen;
+ switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
+ case AF_INET:
+ if (PFKEY_ADDR_SADDR(src0)->sa_len !=
+ sizeof(struct sockaddr_in)) {
+ pfkeystat.out_invaddr++;
+ error = EINVAL;
+ goto senderror;
+ }
+ break;
+ case AF_INET6:
+ if (PFKEY_ADDR_SADDR(src0)->sa_len !=
+ sizeof(struct sockaddr_in6)) {
+ pfkeystat.out_invaddr++;
+ error = EINVAL;
+ goto senderror;
+ }
+ break;
+ default:
+#ifdef IPSEC_DEBUG
+ printf("key_parse: unsupported address family.\n");
+#endif
+ pfkeystat.out_invaddr++;
+ error = EAFNOSUPPORT;
+ goto senderror;
}
switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
break;
default:
- printf("key_parse: invalid address family.\n");
- msg->sadb_msg_errno = EINVAL;
- return orglen;
+ plen = 0; /*fool gcc*/
+ break;
+ }
+
+ /* check max prefix length */
+ if (src0->sadb_address_prefixlen > plen ||
+ dst0->sadb_address_prefixlen > plen) {
+#ifdef IPSEC_DEBUG
+ printf("key_parse: illegal prefixlen.\n");
+#endif
+ pfkeystat.out_invaddr++;
+ error = EINVAL;
+ goto senderror;
}
/*
@@ -4887,196 +6748,85 @@ key_parse(msgp, so, targetp)
*/
}
- switch (msg->sadb_msg_type) {
- case SADB_GETSPI:
- if ((newmsg = key_getspi(mhp)) == NULL)
- return orglen;
- if (targetp)
- *targetp = KEY_SENDUP_ALL;
- break;
-
- case SADB_UPDATE:
- if ((newmsg = key_update(mhp)) == NULL)
- return orglen;
- if (targetp)
- *targetp = KEY_SENDUP_ALL;
- break;
-
- case SADB_ADD:
- if ((newmsg = key_add(mhp)) == NULL)
- return orglen;
- if (targetp)
- *targetp = KEY_SENDUP_ALL;
- break;
-
- case SADB_DELETE:
- if ((newmsg = key_delete(mhp)) == NULL)
- return orglen;
- if (targetp)
- *targetp = KEY_SENDUP_ALL;
- break;
-
- case SADB_GET:
- if ((newmsg = key_get(mhp)) == NULL)
- return orglen;
- break;
-
- case SADB_ACQUIRE:
- if ((newmsg = key_acquire2(mhp)) == NULL)
- return orglen;
-
- if (newmsg == (struct sadb_msg *)~0) {
- /*
- * It's not need to reply because of the message
- * that was reporting an error occured from the KMd.
- */
- KFREE(msg);
- return 0;
- }
- break;
-
- case SADB_REGISTER:
- if ((newmsg = key_register(mhp, so)) == NULL)
- return orglen;
- if (targetp)
- *targetp = KEY_SENDUP_REGISTERED;
- break;
-
- case SADB_EXPIRE:
- printf("key_parse: why is SADB_EXPIRE received ?\n");
- msg->sadb_msg_errno = EINVAL;
- if (targetp)
- *targetp = KEY_SENDUP_ALL;
- return orglen;
-
- case SADB_FLUSH:
- if ((newmsg = key_flush(mhp)) == NULL)
- return orglen;
- if (targetp)
- *targetp = KEY_SENDUP_ALL;
- break;
-
- case SADB_DUMP:
- /* key_dump will call key_sendup() on her own */
- error = key_dump(mhp, so, KEY_SENDUP_ONE);
- if (error) {
- msg->sadb_msg_errno = error;
- return orglen;
- } else {
- KFREE(msg);
- return 0;
- }
- break;
-
- case SADB_X_PROMISC:
- /* everything is handled in key_promisc() */
- key_promisc(mhp, so);
- KFREE(msg);
- return 0; /*nothing to reply*/
-
- case SADB_X_PCHANGE:
- printf("key_parse: SADB_X_PCHANGE isn't supported.\n");
- msg->sadb_msg_errno = EINVAL;
- return orglen;
-
- case SADB_X_SPDADD:
- if ((newmsg = key_spdadd(mhp)) == NULL)
- return orglen;
- if (targetp)
- *targetp = KEY_SENDUP_ALL;
- break;
-
- case SADB_X_SPDDELETE:
- if ((newmsg = key_spddelete(mhp)) == NULL)
- return orglen;
- if (targetp)
- *targetp = KEY_SENDUP_ALL;
- break;
-
- case SADB_X_SPDDUMP:
- /* key_spddump will call key_sendup() on her own */
- error = key_spddump(mhp, so, KEY_SENDUP_ONE);
- if (error) {
- msg->sadb_msg_errno = error;
- return orglen;
- } else {
- KFREE(msg);
- return 0;
- }
- break;
+ if (msg->sadb_msg_type >= sizeof(key_typesw)/sizeof(key_typesw[0]) ||
+ key_typesw[msg->sadb_msg_type] == NULL) {
+ pfkeystat.out_invmsgtype++;
+ error = EINVAL;
+ goto senderror;
+ }
+ return (*key_typesw[msg->sadb_msg_type])(so, m, &mh);
- case SADB_X_SPDFLUSH:
- if ((newmsg = key_spdflush(mhp)) == NULL)
- return orglen;
- if (targetp)
- *targetp = KEY_SENDUP_ALL;
- break;
+senderror:
+ msg->sadb_msg_errno = error;
+ return key_sendup_mbuf(so, m, target);
+}
- default:
- msg->sadb_msg_errno = EOPNOTSUPP;
- return orglen;
- }
+static int
+key_senderror(so, m, code)
+ struct socket *so;
+ struct mbuf *m;
+ int code;
+{
+ struct sadb_msg *msg;
- /* switch from old sadb_msg to new one if success. */
- KFREE(msg);
- *msgp = newmsg;
+ if (m->m_len < sizeof(struct sadb_msg))
+ panic("invalid mbuf passed to key_senderror");
- return PFKEY_UNUNIT64((*msgp)->sadb_msg_len);
+ msg = mtod(m, struct sadb_msg *);
+ msg->sadb_msg_errno = code;
+ return key_sendup_mbuf(so, m, KEY_SENDUP_ONE);
}
/*
* set the pointer to each header into message buffer.
- * IN: msg: pointer to message buffer.
- * mhp: pointer to the buffer allocated like below:
- * caddr_t mhp[SADB_EXT_MAX + 1];
- * OUT: 0:
- * EINVAL:
+ * m will be freed on error.
+ * XXX larger-than-MCLBYTES extension?
*/
static int
-key_align(msg, mhp)
- struct sadb_msg *msg;
- caddr_t *mhp;
+key_align(m, mhp)
+ struct mbuf *m;
+ struct sadb_msghdr *mhp;
{
+ struct mbuf *n;
struct sadb_ext *ext;
- int tlen, extlen;
- int i;
+ size_t off, end;
+ int extlen;
+ int toff;
/* sanity check */
- if (msg == NULL || mhp == NULL)
+ if (m == NULL || mhp == NULL)
panic("key_align: NULL pointer is passed.\n");
+ if (m->m_len < sizeof(struct sadb_msg))
+ panic("invalid mbuf passed to key_align");
/* initialize */
- for (i = 0; i < SADB_EXT_MAX + 1; i++)
- mhp[i] = NULL;
-
- mhp[0] = (caddr_t)msg;
+ bzero(mhp, sizeof(*mhp));
- tlen = PFKEY_UNUNIT64(msg->sadb_msg_len) - sizeof(struct sadb_msg);
- ext = (struct sadb_ext *)((caddr_t)msg + sizeof(struct sadb_msg));
+ mhp->msg = mtod(m, struct sadb_msg *);
+ mhp->ext[0] = (struct sadb_ext *)mhp->msg; /*XXX backward compat */
- while (tlen > 0) {
- /* duplicate check */
- /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/
- if (mhp[ext->sadb_ext_type] != NULL) {
- printf("key_align: duplicate ext_type %u is passed.\n",
- ext->sadb_ext_type);
- return EINVAL;
+ end = PFKEY_UNUNIT64(mhp->msg->sadb_msg_len);
+ extlen = end; /*just in case extlen is not updated*/
+ for (off = sizeof(struct sadb_msg); off < end; off += extlen) {
+ n = m_pulldown(m, off, sizeof(struct sadb_ext), &toff);
+ if (!n) {
+ /* m is already freed */
+ return ENOBUFS;
}
+ ext = (struct sadb_ext *)(mtod(n, caddr_t) + toff);
/* set pointer */
switch (ext->sadb_ext_type) {
case SADB_EXT_SA:
- case SADB_EXT_LIFETIME_CURRENT:
- case SADB_EXT_LIFETIME_HARD:
- case SADB_EXT_LIFETIME_SOFT:
case SADB_EXT_ADDRESS_SRC:
case SADB_EXT_ADDRESS_DST:
case SADB_EXT_ADDRESS_PROXY:
+ case SADB_EXT_LIFETIME_CURRENT:
+ case SADB_EXT_LIFETIME_HARD:
+ case SADB_EXT_LIFETIME_SOFT:
case SADB_EXT_KEY_AUTH:
- /* must to be chek weak keys. */
case SADB_EXT_KEY_ENCRYPT:
- /* must to be chek weak keys. */
case SADB_EXT_IDENTITY_SRC:
case SADB_EXT_IDENTITY_DST:
case SADB_EXT_SENSITIVITY:
@@ -5085,17 +6835,116 @@ key_align(msg, mhp)
case SADB_EXT_SUPPORTED_ENCRYPT:
case SADB_EXT_SPIRANGE:
case SADB_X_EXT_POLICY:
- mhp[ext->sadb_ext_type] = (caddr_t)ext;
+ case SADB_X_EXT_SA2:
+ /* duplicate check */
+ /*
+ * XXX Are there duplication payloads of either
+ * KEY_AUTH or KEY_ENCRYPT ?
+ */
+ if (mhp->ext[ext->sadb_ext_type] != NULL) {
+#ifdef IPSEC_DEBUG
+ printf("key_align: duplicate ext_type %u "
+ "is passed.\n",
+ ext->sadb_ext_type);
+#endif
+ m_freem(m);
+ pfkeystat.out_dupext++;
+ return EINVAL;
+ }
break;
default:
+#ifdef IPSEC_DEBUG
printf("key_align: invalid ext_type %u is passed.\n",
ext->sadb_ext_type);
+#endif
+ m_freem(m);
+ pfkeystat.out_invexttype++;
return EINVAL;
}
extlen = PFKEY_UNUNIT64(ext->sadb_ext_len);
- tlen -= extlen;
- ext = (struct sadb_ext *)((caddr_t)ext + extlen);
+
+ if (key_validate_ext(ext, extlen)) {
+ m_freem(m);
+ pfkeystat.out_invlen++;
+ return EINVAL;
+ }
+
+ n = m_pulldown(m, off, extlen, &toff);
+ if (!n) {
+ /* m is already freed */
+ return ENOBUFS;
+ }
+ ext = (struct sadb_ext *)(mtod(n, caddr_t) + toff);
+
+ mhp->ext[ext->sadb_ext_type] = ext;
+ mhp->extoff[ext->sadb_ext_type] = off;
+ mhp->extlen[ext->sadb_ext_type] = extlen;
+ }
+
+ if (off != end) {
+ m_freem(m);
+ pfkeystat.out_invlen++;
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+key_validate_ext(ext, len)
+ const struct sadb_ext *ext;
+ int len;
+{
+ struct sockaddr *sa;
+ enum { NONE, ADDR } checktype = NONE;
+ int baselen;
+ const int sal = offsetof(struct sockaddr, sa_len) + sizeof(sa->sa_len);
+
+ if (len != PFKEY_UNUNIT64(ext->sadb_ext_len))
+ return EINVAL;
+
+ /* if it does not match minimum/maximum length, bail */
+ if (ext->sadb_ext_type >= sizeof(minsize) / sizeof(minsize[0]) ||
+ ext->sadb_ext_type >= sizeof(maxsize) / sizeof(maxsize[0]))
+ return EINVAL;
+ if (!minsize[ext->sadb_ext_type] || len < minsize[ext->sadb_ext_type])
+ return EINVAL;
+ if (maxsize[ext->sadb_ext_type] && len > maxsize[ext->sadb_ext_type])
+ return EINVAL;
+
+ /* more checks based on sadb_ext_type XXX need more */
+ switch (ext->sadb_ext_type) {
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_ADDRESS_PROXY:
+ baselen = PFKEY_ALIGN8(sizeof(struct sadb_address));
+ checktype = ADDR;
+ break;
+ case SADB_EXT_IDENTITY_SRC:
+ case SADB_EXT_IDENTITY_DST:
+ if (((struct sadb_ident *)ext)->sadb_ident_type ==
+ SADB_X_IDENTTYPE_ADDR) {
+ baselen = PFKEY_ALIGN8(sizeof(struct sadb_ident));
+ checktype = ADDR;
+ } else
+ checktype = NONE;
+ break;
+ default:
+ checktype = NONE;
+ break;
+ }
+
+ switch (checktype) {
+ case NONE:
+ break;
+ case ADDR:
+ sa = (struct sockaddr *)((caddr_t)ext + baselen);
+ if (len < baselen + sal)
+ return EINVAL;
+ if (baselen + PFKEY_ALIGN8(sa->sa_len) != len)
+ return EINVAL;
+ break;
}
return 0;
@@ -5121,6 +6970,7 @@ key_init()
#ifndef IPSEC_NONBLOCK_ACQUIRE
LIST_INIT(&acqtree);
#endif
+ LIST_INIT(&spacqtree);
/* system default */
ip4_def_policy.policy = IPSEC_POLICY_NONE;
@@ -5131,7 +6981,7 @@ key_init()
#endif
#ifndef IPSEC_DEBUG2
- timeout((void *)key_timehandler, (void *)0, 100);
+ timeout((void *)key_timehandler, (void *)0, hz);
#endif /*IPSEC_DEBUG2*/
/* initialize key statistics */
@@ -5167,9 +7017,7 @@ key_checktunnelsanity(sav, family, src, dst)
}
#if 0
-#ifdef __FreeBSD__
-#define hostnamelen strlen(hostname)
-#endif
+#define hostnamelen strlen(hostname)
/*
* Get FQDN for the host.
@@ -5245,6 +7093,10 @@ key_sa_recordxfer(sav, m)
if (!sav->lft_c)
return;
+ /*
+ * XXX Currently, there is a difference of bytes size
+ * between inbound and outbound processing.
+ */
sav->lft_c->sadb_lifetime_bytes += m->m_pkthdr.len;
/* to check bytes lifetime is done in key_timehandler(). */
@@ -5285,7 +7137,7 @@ key_sa_routechange(dst)
struct secashead *sah;
struct route *ro;
- __LIST_FOREACH(sah, &sahtree, chain) {
+ LIST_FOREACH(sah, &sahtree, chain) {
ro = &sah->sa_route;
if (ro->ro_rt && dst->sa_len == ro->ro_dst.sa_len
&& bcmp(dst, &ro->ro_dst, dst->sa_len) == 0) {
@@ -5314,3 +7166,42 @@ key_sa_chgstate(sav, state)
sav->state = state;
LIST_INSERT_HEAD(&sav->sah->savtree[state], sav, chain);
}
+
+/* XXX too much? */
+static struct mbuf *
+key_alloc_mbuf(l)
+ int l;
+{
+ struct mbuf *m = NULL, *n;
+ int len, t;
+
+ len = l;
+ while (len > 0) {
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (n && len > MLEN)
+ MCLGET(n, M_DONTWAIT);
+ if (!n) {
+ m_freem(m);
+ return NULL;
+ }
+
+ n->m_next = NULL;
+ n->m_len = 0;
+ n->m_len = M_TRAILINGSPACE(n);
+ /* use the bottom of mbuf, hoping we can prepend afterwards */
+ if (n->m_len > len) {
+ t = (n->m_len - len) & ~(sizeof(long) - 1);
+ n->m_data += t;
+ n->m_len = len;
+ }
+
+ len -= n->m_len;
+
+ if (m)
+ m_cat(m, n);
+ else
+ m = n;
+ }
+
+ return m;
+}
diff --git a/sys/netkey/key.h b/sys/netkey/key.h
index 2062a24ff014..65a275533093 100644
--- a/sys/netkey/key.h
+++ b/sys/netkey/key.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: key.h,v 1.17 2000/06/12 07:01:13 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,14 +28,10 @@
* 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.
- *
- * $FreeBSD$
*/
-/* $Id: key.h,v 1.1.6.1.6.1 1999/05/17 17:03:14 itojun Exp $ */
-
#ifndef _NETKEY_KEY_H_
-#define _NETKEY_KEY_H_
+#define _NETKEY_KEY_H_
#ifdef _KERNEL
@@ -47,32 +46,32 @@ struct socket;
struct sadb_msg;
struct sadb_x_policy;
-extern struct secpolicy *key_allocsp __P((struct secpolicyindex *spidx,
- u_int dir));
-extern int key_checkrequest __P((struct ipsecrequest *isr));
-extern struct secasvar *key_allocsa __P((u_int family, caddr_t src, caddr_t dst,
- u_int proto, u_int32_t spi));
-extern void key_freesp __P((struct secpolicy *sp));
-extern void key_freeso __P((struct socket *so));
-extern void key_freesav __P((struct secasvar *sav));
+extern struct secpolicy *key_allocsp __P((struct secpolicyindex *, u_int));
+extern int key_checkrequest
+ __P((struct ipsecrequest *isr, struct secasindex *));
+extern struct secasvar *key_allocsa __P((u_int, caddr_t, caddr_t,
+ u_int, u_int32_t));
+extern void key_freesp __P((struct secpolicy *));
+extern void key_freeso __P((struct socket *));
+extern void key_freesav __P((struct secasvar *));
extern struct secpolicy *key_newsp __P((void));
-extern struct secpolicy *key_msg2sp __P((struct sadb_x_policy *xpl0));
-extern struct sadb_x_policy *key_sp2msg __P((struct secpolicy *sp));
-extern int key_ismyaddr __P((u_int family, caddr_t addr));
+extern struct secpolicy *key_msg2sp __P((struct sadb_x_policy *,
+ size_t, int *));
+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 void key_srandom __P((void));
-extern void key_freereg __P((struct socket *so));
-extern int key_parse __P((struct sadb_msg **msgp, struct socket *so,
- int *targetp));
+extern void key_freereg __P((struct socket *));
+extern int key_parse __P((struct mbuf *, struct socket *));
extern void key_init __P((void));
-extern int key_checktunnelsanity __P((struct secasvar *sav, u_int family,
- caddr_t src, caddr_t dst));
-extern void key_sa_recordxfer __P((struct secasvar *sav, struct mbuf *m));
-extern void key_sa_routechange __P((struct sockaddr *dst));
+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 *));
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_SECA);
#endif /* MALLOC_DECLARE */
-#endif /* _KERNEL */
+#endif /* defined(_KERNEL) */
#endif /* _NETKEY_KEY_H_ */
diff --git a/sys/netkey/key_debug.c b/sys/netkey/key_debug.c
index 6b7e77cd8471..b88ace8a83f6 100644
--- a/sys/netkey/key_debug.c
+++ b/sys/netkey/key_debug.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: key_debug.c,v 1.23 2000/07/04 04:08:15 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,15 +28,11 @@
* 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.
- *
- * $FreeBSD$
*/
-/* KAME @(#)$Id: key_debug.c,v 1.1.6.2.4.3 1999/07/06 12:05:13 itojun Exp $ */
-
#ifdef _KERNEL
+#include "opt_inet.h"
#include "opt_inet6.h"
-#include "opt_ipsec.h"
#endif
#include <sys/types.h>
@@ -47,17 +46,20 @@
#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/in6.h>
#include <netinet6/ipsec.h>
#ifndef _KERNEL
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
-#endif
+#endif /* !_KERNEL */
#if !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG))
@@ -68,13 +70,14 @@ static void kdebug_sadb_lifetime __P((struct sadb_ext *));
static void kdebug_sadb_sa __P((struct sadb_ext *));
static void kdebug_sadb_address __P((struct sadb_ext *));
static void kdebug_sadb_key __P((struct sadb_ext *));
+static void kdebug_sadb_x_sa2 __P((struct sadb_ext *));
#ifdef _KERNEL
static void kdebug_secreplay __P((struct secreplay *));
#endif
#ifndef _KERNEL
-#define panic(param) { printf(param); exit(-1); }
+#define panic(param) { printf(param); exit(-1); }
#endif
/* NOTE: host byte order */
@@ -94,9 +97,9 @@ kdebug_sadb(base)
printf("sadb_msg{ version=%u type=%u errno=%u satype=%u\n",
base->sadb_msg_version, base->sadb_msg_type,
base->sadb_msg_errno, base->sadb_msg_satype);
- printf(" len=%u mode=%u reserved=%u seq=%u pid=%u }\n",
- base->sadb_msg_len, base->sadb_msg_mode,
- base->sadb_msg_reserved, base->sadb_msg_seq, base->sadb_msg_pid);
+ printf(" len=%u reserved=%u seq=%u pid=%u\n",
+ base->sadb_msg_len, base->sadb_msg_reserved,
+ base->sadb_msg_seq, base->sadb_msg_pid);
tlen = PFKEY_UNUNIT64(base->sadb_msg_len) - sizeof(struct sadb_msg);
ext = (struct sadb_ext *)((caddr_t)base + sizeof(struct sadb_msg));
@@ -109,6 +112,10 @@ kdebug_sadb(base)
printf("kdebug_sadb: invalid ext_len=0 was passed.\n");
return;
}
+ if (ext->sadb_ext_len > tlen) {
+ printf("kdebug_sadb: ext_len exceeds end of buffer.\n");
+ return;
+ }
switch (ext->sadb_ext_type) {
case SADB_EXT_SA:
@@ -147,6 +154,9 @@ kdebug_sadb(base)
case SADB_X_EXT_POLICY:
kdebug_sadb_x_policy(ext);
break;
+ case SADB_X_EXT_SA2:
+ kdebug_sadb_x_sa2(ext);
+ break;
default:
printf("kdebug_sadb: invalid ext_type %u was passed.\n",
ext->sadb_ext_type);
@@ -225,25 +235,30 @@ kdebug_sadb_identity(ext)
len = PFKEY_UNUNIT64(id->sadb_ident_len) - sizeof(*id);
printf("sadb_ident_%s{",
id->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC ? "src" : "dst");
- printf(" type=%d id=%lu",
- id->sadb_ident_type, (u_long)id->sadb_ident_id);
- if (len) {
+ switch (id->sadb_ident_type) {
+ default:
+ printf(" type=%d id=%lu",
+ id->sadb_ident_type, (u_long)id->sadb_ident_id);
+ if (len) {
#ifdef _KERNEL
- ipsec_hexdump((caddr_t)(id + 1), len); /*XXX cast ?*/
+ ipsec_hexdump((caddr_t)(id + 1), len); /*XXX cast ?*/
#else
- char *p, *ep;
- printf("\n str=\"");
- p = (char *)(id + 1);
- ep = p + len;
- for (/*nothing*/; *p && p < ep; p++) {
- if (isprint(*p))
- printf("%c", *p & 0xff);
- else
- printf("\\%03o", *p & 0xff);
- }
+ char *p, *ep;
+ printf("\n str=\"");
+ p = (char *)(id + 1);
+ ep = p + len;
+ for (/*nothing*/; *p && p < ep; p++) {
+ if (isprint(*p))
+ printf("%c", *p & 0xff);
+ else
+ printf("\\%03o", *p & 0xff);
+ }
#endif
- printf("\"");
+ printf("\"");
+ }
+ break;
}
+
printf(" }\n");
return;
@@ -363,6 +378,25 @@ kdebug_sadb_key(ext)
return;
}
+static void
+kdebug_sadb_x_sa2(ext)
+ struct sadb_ext *ext;
+{
+ struct sadb_x_sa2 *sa2 = (struct sadb_x_sa2 *)ext;
+
+ /* sanity check */
+ if (ext == NULL)
+ panic("kdebug_sadb_x_sa2: NULL pointer was passed.\n");
+
+ printf("sadb_x_sa2{ mode=%u reqid=%u\n",
+ sa2->sadb_x_sa2_mode, sa2->sadb_x_sa2_reqid);
+ printf(" reserved1=%u reserved2=%u reserved3=%u }\n",
+ sa2->sadb_x_sa2_reserved1, sa2->sadb_x_sa2_reserved1,
+ sa2->sadb_x_sa2_reserved1);
+
+ return;
+}
+
void
kdebug_sadb_x_policy(ext)
struct sadb_ext *ext;
@@ -374,9 +408,9 @@ kdebug_sadb_x_policy(ext)
if (ext == NULL)
panic("kdebug_sadb_x_policy: NULL pointer was passed.\n");
- printf("sadb_x_policy{ type=%u dir=%u reserved=%x }\n",
+ printf("sadb_x_policy{ type=%u dir=%u id=%x }\n",
xpl->sadb_x_policy_type, xpl->sadb_x_policy_dir,
- xpl->sadb_x_policy_reserved);
+ xpl->sadb_x_policy_id);
if (xpl->sadb_x_policy_type == IPSEC_POLICY_IPSEC) {
int tlen;
@@ -386,22 +420,33 @@ kdebug_sadb_x_policy(ext)
xisr = (struct sadb_x_ipsecrequest *)(xpl + 1);
while (tlen > 0) {
- printf(" { len=%u proto=%u mode=%u level=%u\n",
+ printf(" { len=%u proto=%u mode=%u level=%u reqid=%u\n",
xisr->sadb_x_ipsecrequest_len,
xisr->sadb_x_ipsecrequest_proto,
xisr->sadb_x_ipsecrequest_mode,
- xisr->sadb_x_ipsecrequest_level);
+ xisr->sadb_x_ipsecrequest_level,
+ xisr->sadb_x_ipsecrequest_reqid);
- addr = (struct sockaddr *)(xisr + 1);
- kdebug_sockaddr(addr);
- addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len);
- kdebug_sockaddr(addr);
+ if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
+ addr = (struct sockaddr *)(xisr + 1);
+ kdebug_sockaddr(addr);
+ addr = (struct sockaddr *)((caddr_t)addr
+ + addr->sa_len);
+ kdebug_sockaddr(addr);
+ }
printf(" }\n");
/* prevent infinite loop */
- if (xisr->sadb_x_ipsecrequest_len <= 0)
- panic("kdebug_sadb_x_policy: wrong policy struct.\n");
+ if (xisr->sadb_x_ipsecrequest_len <= 0) {
+ printf("kdebug_sadb_x_policy: wrong policy struct.\n");
+ return;
+ }
+ /* prevent overflow */
+ if (xisr->sadb_x_ipsecrequest_len > tlen) {
+ printf("invalid ipsec policy length\n");
+ return;
+ }
tlen -= xisr->sadb_x_ipsecrequest_len;
@@ -478,9 +523,11 @@ kdebug_secpolicyindex(spidx)
printf("secpolicyindex{ dir=%u prefs=%u prefd=%u ul_proto=%u\n",
spidx->dir, spidx->prefs, spidx->prefd, spidx->ul_proto);
- ipsec_hexdump((caddr_t)&spidx->src, spidx->src.ss_len);
+ ipsec_hexdump((caddr_t)&spidx->src,
+ ((struct sockaddr *)&spidx->src)->sa_len);
printf("\n");
- ipsec_hexdump((caddr_t)&spidx->dst, spidx->dst.ss_len);
+ ipsec_hexdump((caddr_t)&spidx->dst,
+ ((struct sockaddr *)&spidx->dst)->sa_len);
printf("}\n");
return;
@@ -497,9 +544,11 @@ kdebug_secasindex(saidx)
printf("secasindex{ mode=%u proto=%u\n",
saidx->mode, saidx->proto);
- ipsec_hexdump((caddr_t)&saidx->src, saidx->src.ss_len);
+ ipsec_hexdump((caddr_t)&saidx->src,
+ ((struct sockaddr *)&saidx->src)->sa_len);
printf("\n");
- ipsec_hexdump((caddr_t)&saidx->dst, saidx->dst.ss_len);
+ ipsec_hexdump((caddr_t)&saidx->dst,
+ ((struct sockaddr *)&saidx->dst)->sa_len);
printf("\n");
return;
@@ -540,6 +589,10 @@ kdebug_secasv(sav)
if (sav->lft_s != NULL)
kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_s);
+#if notyet
+ /* XXX: misc[123] ? */
+#endif
+
return;
}
@@ -578,7 +631,7 @@ kdebug_mbufhdr(m)
{
/* sanity check */
if (m == NULL)
- panic("debug_mbufhdr: NULL pointer was passed.\n");
+ return;
printf("mbuf(%p){ m_next:%p m_nextpkt:%p m_data:%p "
"m_len:%d m_type:0x%02x m_flags:0x%02x }\n",
@@ -589,12 +642,14 @@ kdebug_mbufhdr(m)
printf(" m_pkthdr{ len:%d rcvif:%p }\n",
m->m_pkthdr.len, m->m_pkthdr.rcvif);
}
+
if (m->m_flags & M_EXT) {
printf(" m_ext{ ext_buf:%p ext_free:%p "
"ext_size:%u ext_ref:%p }\n",
m->m_ext.ext_buf, m->m_ext.ext_free,
m->m_ext.ext_size, m->m_ext.ext_ref);
}
+
return;
}
@@ -605,19 +660,20 @@ kdebug_mbuf(m0)
struct mbuf *m = m0;
int i, j;
- kdebug_mbufhdr(m);
- printf(" m_data=\n");
for (j = 0; m; m = m->m_next) {
+ kdebug_mbufhdr(m);
+ printf(" m_data:\n");
for (i = 0; i < m->m_len; i++) {
- if (i != 0 && i % 32 == 0) printf("\n");
- if (i % 4 == 0) printf(" ");
+ if (i && i % 32 == 0)
+ printf("\n");
+ if (i % 4 == 0)
+ printf(" ");
printf("%02x", mtod(m, u_char *)[i]);
j++;
}
+ printf("\n");
}
- printf("\n");
-
return;
}
#endif /* _KERNEL */
@@ -626,31 +682,41 @@ void
kdebug_sockaddr(addr)
struct sockaddr *addr;
{
+ struct sockaddr_in *sin;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
+
/* sanity check */
if (addr == NULL)
panic("kdebug_sockaddr: NULL pointer was passed.\n");
/* NOTE: We deal with port number as host byte order. */
- printf("sockaddr{ len=%u family=%u port=%u\n",
- addr->sa_len, addr->sa_family, ntohs(_INPORTBYSA(addr)));
+ printf("sockaddr{ len=%u family=%u", addr->sa_len, addr->sa_family);
+ switch (addr->sa_family) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)addr;
+ printf(" port=%u\n", ntohs(sin->sin_port));
+ ipsec_hexdump((caddr_t)&sin->sin_addr, sizeof(sin->sin_addr));
+ break;
#ifdef INET6
- if (addr->sa_family == PF_INET6) {
- struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)addr;
+ printf(" port=%u\n", ntohs(sin6->sin6_port));
printf(" flowinfo=0x%08x, scope_id=0x%08x\n",
- in6->sin6_flowinfo, in6->sin6_scope_id);
- }
+ sin6->sin6_flowinfo, sin6->sin6_scope_id);
+ ipsec_hexdump((caddr_t)&sin6->sin6_addr,
+ sizeof(sin6->sin6_addr));
+ break;
#endif
-
- ipsec_hexdump(_INADDRBYSA(addr), _INALENBYAF(addr->sa_family));
+ }
printf(" }\n");
return;
}
-#endif /* !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) */
-
void
ipsec_bindump(buf, len)
caddr_t buf;
@@ -677,7 +743,11 @@ ipsec_hexdump(buf, len)
if (i % 4 == 0) printf(" ");
printf("%02x", (unsigned char)buf[i]);
}
+#if 0
+ if (i % 32 != 0) printf("\n");
+#endif
return;
}
+#endif /* !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) */
diff --git a/sys/netkey/key_debug.h b/sys/netkey/key_debug.h
index 53eead8650fa..383a0e8f5341 100644
--- a/sys/netkey/key_debug.h
+++ b/sys/netkey/key_debug.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: key_debug.h,v 1.7 2000/07/04 04:08:16 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,39 +28,35 @@
* 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.
- *
- * $FreeBSD$
*/
-/* $Id: key_debug.h,v 1.1.6.2.6.1 1999/05/17 17:03:16 itojun Exp $ */
-
#ifndef _NETKEY_KEY_DEBUG_H_
-#define _NETKEY_KEY_DEBUG_H_
+#define _NETKEY_KEY_DEBUG_H_
/* debug flags */
-#define KEYDEBUG_STAMP 0x00000001 /* path */
-#define KEYDEBUG_DATA 0x00000002 /* data */
-#define KEYDEBUG_DUMP 0x00000004 /* dump */
+#define KEYDEBUG_STAMP 0x00000001 /* path */
+#define KEYDEBUG_DATA 0x00000002 /* data */
+#define KEYDEBUG_DUMP 0x00000004 /* dump */
-#define KEYDEBUG_KEY 0x00000010 /* key processing */
-#define KEYDEBUG_ALG 0x00000020 /* ciph & auth algorithm */
-#define KEYDEBUG_IPSEC 0x00000040 /* ipsec processing */
+#define KEYDEBUG_KEY 0x00000010 /* key processing */
+#define KEYDEBUG_ALG 0x00000020 /* ciph & auth algorithm */
+#define KEYDEBUG_IPSEC 0x00000040 /* ipsec processing */
-#define KEYDEBUG_KEY_STAMP (KEYDEBUG_KEY | KEYDEBUG_STAMP)
-#define KEYDEBUG_KEY_DATA (KEYDEBUG_KEY | KEYDEBUG_DATA)
-#define KEYDEBUG_KEY_DUMP (KEYDEBUG_KEY | KEYDEBUG_DUMP)
-#define KEYDEBUG_ALG_STAMP (KEYDEBUG_ALG | KEYDEBUG_STAMP)
-#define KEYDEBUG_ALG_DATA (KEYDEBUG_ALG | KEYDEBUG_DATA)
-#define KEYDEBUG_ALG_DUMP (KEYDEBUG_ALG | KEYDEBUG_DUMP)
-#define KEYDEBUG_IPSEC_STAMP (KEYDEBUG_IPSEC | KEYDEBUG_STAMP)
-#define KEYDEBUG_IPSEC_DATA (KEYDEBUG_IPSEC | KEYDEBUG_DATA)
-#define KEYDEBUG_IPSEC_DUMP (KEYDEBUG_IPSEC | KEYDEBUG_DUMP)
+#define KEYDEBUG_KEY_STAMP (KEYDEBUG_KEY | KEYDEBUG_STAMP)
+#define KEYDEBUG_KEY_DATA (KEYDEBUG_KEY | KEYDEBUG_DATA)
+#define KEYDEBUG_KEY_DUMP (KEYDEBUG_KEY | KEYDEBUG_DUMP)
+#define KEYDEBUG_ALG_STAMP (KEYDEBUG_ALG | KEYDEBUG_STAMP)
+#define KEYDEBUG_ALG_DATA (KEYDEBUG_ALG | KEYDEBUG_DATA)
+#define KEYDEBUG_ALG_DUMP (KEYDEBUG_ALG | KEYDEBUG_DUMP)
+#define KEYDEBUG_IPSEC_STAMP (KEYDEBUG_IPSEC | KEYDEBUG_STAMP)
+#define KEYDEBUG_IPSEC_DATA (KEYDEBUG_IPSEC | KEYDEBUG_DATA)
+#define KEYDEBUG_IPSEC_DUMP (KEYDEBUG_IPSEC | KEYDEBUG_DUMP)
-#define KEYDEBUG(lev,arg) if ((key_debug_level & (lev)) == (lev)) { arg; }
+#define KEYDEBUG(lev,arg) if ((key_debug_level & (lev)) == (lev)) { arg; }
#ifdef _KERNEL
extern u_int32_t key_debug_level;
-#endif
+#endif /*_KERNEL*/
struct sadb_msg;
struct sadb_ext;
@@ -77,7 +76,7 @@ extern void kdebug_secasindex __P((struct secasindex *));
extern void kdebug_secasv __P((struct secasvar *));
extern void kdebug_mbufhdr __P((struct mbuf *));
extern void kdebug_mbuf __P((struct mbuf *));
-#endif
+#endif /*_KERNEL*/
struct sockaddr;
extern void kdebug_sockaddr __P((struct sockaddr *));
diff --git a/sys/netkey/key_var.h b/sys/netkey/key_var.h
index 85e4b9222443..b7a62bacb990 100644
--- a/sys/netkey/key_var.h
+++ b/sys/netkey/key_var.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: key_var.h,v 1.8 2000/05/24 17:28:23 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,50 +28,39 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _NETKEY_KEY_VAR_H_
-#define _NETKEY_KEY_VAR_H_
+#define _NETKEY_KEY_VAR_H_
/* sysctl */
-#define KEYCTL_DEBUG_LEVEL 1
-#define KEYCTL_SPI_TRY 2
-#define KEYCTL_SPI_MIN_VALUE 3
-#define KEYCTL_SPI_MAX_VALUE 4
-#define KEYCTL_RANDOM_INT 5
-#define KEYCTL_LARVAL_LIFETIME 6
-#define KEYCTL_BLOCKACQ_COUNT 7
-#define KEYCTL_BLOCKACQ_LIFETIME 8
-#define KEYCTL_MAXID 9
-
-#define _ARRAYLEN(p) (sizeof(p)/sizeof(p[0]))
-#define _KEYLEN(key) ((u_int)((key)->sadb_key_bits >> 3))
-#define _KEYBITS(key) ((u_int)((key)->sadb_key_bits))
-#define _KEYBUF(key) ((caddr_t)((caddr_t)(key) + sizeof(struct sadb_key)))
+#define KEYCTL_DEBUG_LEVEL 1
+#define KEYCTL_SPI_TRY 2
+#define KEYCTL_SPI_MIN_VALUE 3
+#define KEYCTL_SPI_MAX_VALUE 4
+#define KEYCTL_RANDOM_INT 5
+#define KEYCTL_LARVAL_LIFETIME 6
+#define KEYCTL_BLOCKACQ_COUNT 7
+#define KEYCTL_BLOCKACQ_LIFETIME 8
+#define KEYCTL_MAXID 9
-#define _INADDR(in) ((struct sockaddr_in *)(in))
-#define _IN6ADDR(in6) ((struct sockaddr_in6 *)(in6))
-#define _SALENBYAF(family) \
- (((family) == AF_INET) ? \
- (u_int)sizeof(struct sockaddr_in) : \
- (u_int)sizeof(struct sockaddr_in6))
-#define _INALENBYAF(family) \
- (((family) == AF_INET) ? \
- (u_int)sizeof(struct in_addr) : \
- (u_int)sizeof(struct in6_addr))
-#define _INADDRBYSA(saddr) \
- ((((struct sockaddr *)(saddr))->sa_family == AF_INET) ? \
- (caddr_t)&((struct sockaddr_in *)(saddr))->sin_addr : \
- (caddr_t)&((struct sockaddr_in6 *)(saddr))->sin6_addr)
-#define _INPORTBYSA(saddr) \
- ((((struct sockaddr *)(saddr))->sa_family == AF_INET) ? \
- ((struct sockaddr_in *)(saddr))->sin_port : \
- ((struct sockaddr_in6 *)(saddr))->sin6_port)
+#define KEYCTL_NAMES { \
+ { 0, 0 }, \
+ { "debug", CTLTYPE_INT }, \
+ { "spi_try", CTLTYPE_INT }, \
+ { "spi_min_value", CTLTYPE_INT }, \
+ { "spi_max_value", CTLTYPE_INT }, \
+ { "random_int", CTLTYPE_INT }, \
+ { "larval_lifetime", CTLTYPE_INT }, \
+ { "blockacq_count", CTLTYPE_INT }, \
+ { "blockacq_lifetime", CTLTYPE_INT }, \
+}
-#ifdef SYSCTL_DECL
-SYSCTL_DECL(_net_key);
-#endif
+#ifdef _KERNEL
+#define _ARRAYLEN(p) (sizeof(p)/sizeof(p[0]))
+#define _KEYLEN(key) ((u_int)((key)->sadb_key_bits >> 3))
+#define _KEYBITS(key) ((u_int)((key)->sadb_key_bits))
+#define _KEYBUF(key) ((caddr_t)((caddr_t)(key) + sizeof(struct sadb_key)))
+#endif /*_KERNEL*/
#endif /* _NETKEY_KEY_VAR_H_ */
diff --git a/sys/netkey/keydb.c b/sys/netkey/keydb.c
new file mode 100644
index 000000000000..dd1fb17bd579
--- /dev/null
+++ b/sys/netkey/keydb.c
@@ -0,0 +1,217 @@
+/* $FreeBSD$ */
+/* $KAME: keydb.c,v 1.64 2000/05/11 17:02:30 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/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+
+#include <net/pfkeyv2.h>
+#include <netkey/keydb.h>
+#include <netinet6/ipsec.h>
+
+#include <net/net_osdep.h>
+
+MALLOC_DEFINE(M_SECA, "key mgmt", "security associations, key management");
+
+static void keydb_delsecasvar __P((struct secasvar *));
+
+/*
+ * secpolicy management
+ */
+struct secpolicy *
+keydb_newsecpolicy()
+{
+ struct secpolicy *p;
+
+ p = (struct secpolicy *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
+ if (!p)
+ return p;
+ bzero(p, sizeof(*p));
+ return p;
+}
+
+void
+keydb_delsecpolicy(p)
+ struct secpolicy *p;
+{
+
+ free(p, M_SECA);
+}
+
+/*
+ * secashead management
+ */
+struct secashead *
+keydb_newsecashead()
+{
+ struct secashead *p;
+ int i;
+
+ p = (struct secashead *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
+ if (!p)
+ return p;
+ bzero(p, sizeof(*p));
+ for (i = 0; i < sizeof(p->savtree)/sizeof(p->savtree[0]); i++)
+ LIST_INIT(&p->savtree[i]);
+ return p;
+}
+
+void
+keydb_delsecashead(p)
+ struct secashead *p;
+{
+
+ free(p, M_SECA);
+}
+
+/*
+ * secasvar management (reference counted)
+ */
+struct secasvar *
+keydb_newsecasvar()
+{
+ struct secasvar *p;
+
+ p = (struct secasvar *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
+ if (!p)
+ return p;
+ bzero(p, sizeof(*p));
+ p->refcnt = 1;
+ return p;
+}
+
+void
+keydb_refsecasvar(p)
+ struct secasvar *p;
+{
+ int s;
+
+ s = splnet();
+ p->refcnt++;
+ splx(s);
+}
+
+void
+keydb_freesecasvar(p)
+ struct secasvar *p;
+{
+ int s;
+
+ s = splnet();
+ p->refcnt--;
+ /* negative refcnt will cause panic intentionally */
+ if (p->refcnt <= 0)
+ keydb_delsecasvar(p);
+ splx(s);
+}
+
+static void
+keydb_delsecasvar(p)
+ struct secasvar *p;
+{
+
+ if (p->refcnt)
+ panic("keydb_delsecasvar called with refcnt != 0");
+
+ free(p, M_SECA);
+}
+
+/*
+ * secreplay management
+ */
+struct secreplay *
+keydb_newsecreplay(wsize)
+ size_t wsize;
+{
+ struct secreplay *p;
+
+ p = (struct secreplay *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
+ if (!p)
+ return p;
+
+ bzero(p, sizeof(*p));
+ if (wsize != 0) {
+ p->bitmap = (caddr_t)malloc(wsize, M_SECA, M_NOWAIT);
+ if (!p->bitmap) {
+ free(p, M_SECA);
+ return NULL;
+ }
+ bzero(p->bitmap, wsize);
+ }
+ p->wsize = wsize;
+ return p;
+}
+
+void
+keydb_delsecreplay(p)
+ struct secreplay *p;
+{
+
+ if (p->bitmap)
+ free(p->bitmap, M_SECA);
+ free(p, M_SECA);
+}
+
+/*
+ * secreg management
+ */
+struct secreg *
+keydb_newsecreg()
+{
+ struct secreg *p;
+
+ p = (struct secreg *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
+ if (p)
+ bzero(p, sizeof(*p));
+ return p;
+}
+
+void
+keydb_delsecreg(p)
+ struct secreg *p;
+{
+
+ free(p, M_SECA);
+}
diff --git a/sys/netkey/keydb.h b/sys/netkey/keydb.h
index af4b3ba497a2..fcb478c1296d 100644
--- a/sys/netkey/keydb.h
+++ b/sys/netkey/keydb.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: keydb.h,v 1.11 2000/06/15 12:20:50 sakane Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,86 +28,94 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _NETKEY_KEYDB_H_
-#define _NETKEY_KEYDB_H_
+#define _NETKEY_KEYDB_H_
#ifdef _KERNEL
+#include <netkey/key_var.h>
+
/* Security Assocciation Index */
-/* NOTE: Encure to be same address family */
+/* NOTE: Ensure to be same address family */
struct secasindex {
- struct sockaddr_storage src; /* srouce address for SA */
- struct sockaddr_storage dst; /* destination address for SA */
- u_int16_t proto; /* IPPROTO_ESP or IPPROTO_AH */
- u_int8_t mode; /* mode of protocol, see ipsec.h */
+ struct sockaddr_storage src; /* srouce address for SA */
+ struct sockaddr_storage dst; /* destination address for SA */
+ u_int16_t proto; /* IPPROTO_ESP or IPPROTO_AH */
+ u_int8_t mode; /* mode of protocol, see ipsec.h */
+ u_int32_t reqid; /* reqid id who owned this SA */
+ /* see IPSEC_MANUAL_REQID_MAX. */
};
/* Security Association Data Base */
struct secashead {
LIST_ENTRY(secashead) chain;
- struct secasindex saidx;
- struct secpolicyindex *owner; /* Indicate it who owned its SA. */
- /* If NULL then it's shared SA */
+ struct secasindex saidx;
+
+ struct sadb_ident *idents; /* source identity */
+ struct sadb_ident *identd; /* destination identity */
+ /* XXX I don't know how to use them. */
- u_int8_t state; /* MATURE or DEAD. */
+ u_int8_t state; /* MATURE or DEAD. */
LIST_HEAD(_satree, secasvar) savtree[SADB_SASTATE_MAX+1];
/* SA chain */
/* The first of this list is newer SA */
- struct route sa_route; /* XXX */
+ struct route sa_route; /* route cache */
};
/* Security Association */
struct secasvar {
LIST_ENTRY(secasvar) chain;
- int refcnt; /* reference count */
- u_int8_t state; /* Status of this Association */
-
- u_int8_t alg_auth; /* Authentication Algorithm Identifier*/
- u_int8_t alg_enc; /* Cipher Algorithm Identifier */
- u_int32_t spi; /* SPI Value, network byte order */
- u_int32_t flags; /* holder for SADB_KEY_FLAGS */
-
- struct sadb_key *key_auth; /* Key for Authentication */
- /* length has been shifted up to 3. */
- struct sadb_key *key_enc; /* Key for Encryption */
- /* length has been shifted up to 3. */
- caddr_t iv; /* Initilization Vector */
- u_int ivlen; /* length of IV */
+ int refcnt; /* reference count */
+ u_int8_t state; /* Status of this Association */
+
+ u_int8_t alg_auth; /* Authentication Algorithm Identifier*/
+ u_int8_t alg_enc; /* Cipher Algorithm Identifier */
+ u_int32_t spi; /* SPI Value, network byte order */
+ u_int32_t flags; /* holder for SADB_KEY_FLAGS */
+
+ struct sadb_key *key_auth; /* Key for Authentication */
+ 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
- struct secreplay *replay; /* replay prevention */
- u_int32_t tick; /* for lifetime */
+ struct secreplay *replay; /* replay prevention */
+ u_int32_t tick; /* for lifetime */
- struct sadb_lifetime *lft_c; /* CURRENT lifetime, it's constant. */
- struct sadb_lifetime *lft_h; /* HARD lifetime */
- struct sadb_lifetime *lft_s; /* SOFT lifetime */
+ struct sadb_lifetime *lft_c; /* CURRENT lifetime, it's constant. */
+ struct sadb_lifetime *lft_h; /* HARD lifetime */
+ struct sadb_lifetime *lft_s; /* SOFT lifetime */
- u_int32_t seq; /* sequence number */
- pid_t pid; /* message's pid */
+ u_int32_t seq; /* sequence number */
+ pid_t pid; /* message's pid */
- struct secashead *sah; /* back pointer to the secashead */
+ struct secashead *sah; /* back pointer to the secashead */
};
/* replay prevention */
struct secreplay {
- u_int32_t count;
- u_int wsize; /* window size, i.g. 4 bytes */
- u_int32_t seq; /* used by sender */
- u_int32_t lastseq; /* used by receiver */
- caddr_t bitmap; /* used by receiver */
+ u_int32_t count;
+ u_int wsize; /* window size, i.g. 4 bytes */
+ u_int32_t seq; /* used by sender */
+ u_int32_t lastseq; /* used by receiver */
+ caddr_t bitmap; /* used by receiver */
+ int overflow; /* overflow flag */
};
/* socket table due to send PF_KEY messages. */
struct secreg {
LIST_ENTRY(secreg) chain;
- struct socket *so;
+ struct socket *so;
};
#ifndef IPSEC_NONBLOCK_ACQUIRE
@@ -112,24 +123,41 @@ struct secreg {
struct secacq {
LIST_ENTRY(secacq) chain;
- struct secasindex saidx;
+ struct secasindex saidx;
- u_int32_t seq; /* sequence number */
- u_int32_t tick; /* for lifetime */
- int count; /* for lifetime */
+ u_int32_t seq; /* sequence number */
+ u_int32_t tick; /* for lifetime */
+ int count; /* for lifetime */
};
#endif
/* Sensitivity Level Specification */
/* nothing */
-#define SADB_KILL_INTERVAL 600 /* six seconds */
+#define SADB_KILL_INTERVAL 600 /* six seconds */
struct key_cb {
int key_count;
int any_count;
};
+/* secpolicy */
+extern struct secpolicy *keydb_newsecpolicy __P((void));
+extern void keydb_delsecpolicy __P((struct secpolicy *));
+/* secashead */
+extern struct secashead *keydb_newsecashead __P((void));
+extern void keydb_delsecashead __P((struct secashead *));
+/* secasvar */
+extern struct secasvar *keydb_newsecasvar __P((void));
+extern void keydb_refsecasvar __P((struct secasvar *));
+extern void keydb_freesecasvar __P((struct secasvar *));
+/* secreplay */
+extern struct secreplay *keydb_newsecreplay __P((size_t));
+extern void keydb_delsecreplay __P((struct secreplay *));
+/* secreg */
+extern struct secreg *keydb_newsecreg __P((void));
+extern void keydb_delsecreg __P((struct secreg *));
+
#endif /* _KERNEL */
#endif /* _NETKEY_KEYDB_H_ */
diff --git a/sys/netkey/keysock.c b/sys/netkey/keysock.c
index f26e8a5dc85f..92e70235b399 100644
--- a/sys/netkey/keysock.c
+++ b/sys/netkey/keysock.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: keysock.c,v 1.22 2000/05/23 13:19:21 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,16 +28,12 @@
* 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.
- *
- * $FreeBSD$
*/
-/* KAME @(#)$Id: keysock.c,v 1.2 1999/08/16 19:30:36 shin Exp $ */
+#include "opt_ipsec.h"
/* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */
-#include <opt_ipsec.h>
-
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
@@ -65,19 +64,334 @@
#include <machine/stdarg.h>
-static MALLOC_DEFINE(M_SECA, "key mgmt",
- "security associations, key management");
-
struct sockaddr key_dst = { 2, PF_KEY, };
struct sockaddr key_src = { 2, PF_KEY, };
-struct sockproto key_proto = { PF_KEY, PF_KEY_V2 };
static int key_sendup0 __P((struct rawcb *, struct mbuf *, int));
-#define KMALLOC(p, t, n) \
- ((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT))
-#define KFREE(p) \
- free((caddr_t)(p), M_SECA);
+struct pfkeystat pfkeystat;
+
+/*
+ * key_output()
+ */
+int
+#if __STDC__
+key_output(struct mbuf *m, ...)
+#else
+key_output(m, va_alist)
+ struct mbuf *m;
+ va_dcl
+#endif
+{
+ struct sadb_msg *msg;
+ int len, error = 0;
+ int s;
+ struct socket *so;
+ va_list ap;
+
+ va_start(ap, m);
+ so = va_arg(ap, struct socket *);
+ va_end(ap);
+
+ if (m == 0)
+ panic("key_output: NULL pointer was passed.\n");
+
+ pfkeystat.out_total++;
+ pfkeystat.out_bytes += m->m_pkthdr.len;
+
+ len = m->m_pkthdr.len;
+ if (len < sizeof(struct sadb_msg)) {
+#ifdef IPSEC_DEBUG
+ printf("key_output: Invalid message length.\n");
+#endif
+ pfkeystat.out_tooshort++;
+ error = EINVAL;
+ goto end;
+ }
+
+ if (m->m_len < sizeof(struct sadb_msg)) {
+ if ((m = m_pullup(m, sizeof(struct sadb_msg))) == 0) {
+#ifdef IPSEC_DEBUG
+ printf("key_output: can't pullup mbuf\n");
+#endif
+ pfkeystat.out_nomem++;
+ error = ENOBUFS;
+ goto end;
+ }
+ }
+
+ if ((m->m_flags & M_PKTHDR) == 0)
+ panic("key_output: not M_PKTHDR ??");
+
+#ifdef IPSEC_DEBUG
+ KEYDEBUG(KEYDEBUG_KEY_DUMP, kdebug_mbuf(m));
+#endif
+
+ msg = mtod(m, struct sadb_msg *);
+ pfkeystat.out_msgtype[msg->sadb_msg_type]++;
+ if (len != PFKEY_UNUNIT64(msg->sadb_msg_len)) {
+#ifdef IPSEC_DEBUG
+ printf("key_output: Invalid message length.\n");
+#endif
+ pfkeystat.out_invlen++;
+ error = EINVAL;
+ goto end;
+ }
+
+ /*XXX giant lock*/
+ s = splnet();
+ error = key_parse(m, so);
+ m = NULL;
+ splx(s);
+end:
+ if (m)
+ m_freem(m);
+ return error;
+}
+
+/*
+ * send message to the socket.
+ */
+static int
+key_sendup0(rp, m, promisc)
+ struct rawcb *rp;
+ struct mbuf *m;
+ int promisc;
+{
+ if (promisc) {
+ struct sadb_msg *pmsg;
+
+ M_PREPEND(m, sizeof(struct sadb_msg), M_NOWAIT);
+ if (m && m->m_len < sizeof(struct sadb_msg))
+ m = m_pullup(m, sizeof(struct sadb_msg));
+ if (!m) {
+#ifdef IPSEC_DEBUG
+ printf("key_sendup0: cannot pullup\n");
+#endif
+ pfkeystat.in_nomem++;
+ m_freem(m);
+ return ENOBUFS;
+ }
+ m->m_pkthdr.len += sizeof(*pmsg);
+
+ pmsg = mtod(m, struct sadb_msg *);
+ bzero(pmsg, sizeof(*pmsg));
+ pmsg->sadb_msg_version = PF_KEY_V2;
+ pmsg->sadb_msg_type = SADB_X_PROMISC;
+ pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len);
+ /* pid and seq? */
+
+ pfkeystat.in_msgtype[pmsg->sadb_msg_type]++;
+ }
+
+ 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;
+ }
+ sorwakeup(rp->rcb_socket);
+ return 0;
+}
+
+/* XXX this interface should be obsoleted. */
+int
+key_sendup(so, msg, len, target)
+ struct socket *so;
+ struct sadb_msg *msg;
+ u_int len;
+ int target; /*target of the resulting message*/
+{
+ struct mbuf *m, *n, *mprev;
+ int tlen;
+
+ /* sanity check */
+ if (so == 0 || msg == 0)
+ panic("key_sendup: NULL pointer was passed.\n");
+
+ KEYDEBUG(KEYDEBUG_KEY_DUMP,
+ printf("key_sendup: \n");
+ kdebug_sadb(msg));
+
+ /*
+ * we increment statistics here, just in case we have ENOBUFS
+ * in this function.
+ */
+ pfkeystat.in_total++;
+ pfkeystat.in_bytes += len;
+ pfkeystat.in_msgtype[msg->sadb_msg_type]++;
+
+ /*
+ * Get mbuf chain whenever possible (not clusters),
+ * to save socket buffer. We'll be generating many SADB_ACQUIRE
+ * messages to listening key sockets. If we simply allocate clusters,
+ * sbappendaddr() will raise ENOBUFS due to too little sbspace().
+ * sbspace() computes # of actual data bytes AND mbuf region.
+ *
+ * TODO: SADB_ACQUIRE filters should be implemented.
+ */
+ tlen = len;
+ m = mprev = NULL;
+ while (tlen > 0) {
+ if (tlen == len) {
+ MGETHDR(n, M_DONTWAIT, MT_DATA);
+ n->m_len = MHLEN;
+ } else {
+ MGET(n, M_DONTWAIT, MT_DATA);
+ n->m_len = MLEN;
+ }
+ if (!n) {
+ pfkeystat.in_nomem++;
+ return ENOBUFS;
+ }
+ if (tlen >= MCLBYTES) { /*XXX better threshold? */
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_free(n);
+ m_freem(m);
+ pfkeystat.in_nomem++;
+ return ENOBUFS;
+ }
+ n->m_len = MCLBYTES;
+ }
+
+ if (tlen < n->m_len)
+ n->m_len = tlen;
+ n->m_next = NULL;
+ if (m == NULL)
+ m = mprev = n;
+ else {
+ mprev->m_next = n;
+ mprev = n;
+ }
+ tlen -= n->m_len;
+ n = NULL;
+ }
+ m->m_pkthdr.len = len;
+ m->m_pkthdr.rcvif = NULL;
+ m_copyback(m, 0, len, (caddr_t)msg);
+
+ /* avoid duplicated statistics */
+ pfkeystat.in_total--;
+ pfkeystat.in_bytes -= len;
+ pfkeystat.in_msgtype[msg->sadb_msg_type]--;
+
+ return key_sendup_mbuf(so, m, target);
+}
+
+/* so can be NULL if target != KEY_SENDUP_ONE */
+int
+key_sendup_mbuf(so, m, target)
+ struct socket *so;
+ struct mbuf *m;
+ int target;
+{
+ struct mbuf *n;
+ struct keycb *kp;
+ int sendup;
+ struct rawcb *rp;
+ int error = 0;
+
+ if (m == NULL)
+ panic("key_sendup_mbuf: NULL pointer was passed.\n");
+ if (so == NULL && target == KEY_SENDUP_ONE)
+ panic("key_sendup_mbuf: NULL pointer was passed.\n");
+
+ pfkeystat.in_total++;
+ pfkeystat.in_bytes += m->m_pkthdr.len;
+ if (m->m_len < sizeof(struct sadb_msg)) {
+#if 1
+ m = m_pullup(m, sizeof(struct sadb_msg));
+ if (m == NULL) {
+ pfkeystat.in_nomem++;
+ return ENOBUFS;
+ }
+#else
+ /* don't bother pulling it up just for stats */
+#endif
+ }
+ if (m->m_len >= sizeof(struct sadb_msg)) {
+ struct sadb_msg *msg;
+ msg = mtod(m, struct sadb_msg *);
+ pfkeystat.in_msgtype[msg->sadb_msg_type]++;
+ }
+
+ LIST_FOREACH(rp, &rawcb_list, list)
+ {
+ if (rp->rcb_proto.sp_family != PF_KEY)
+ continue;
+ if (rp->rcb_proto.sp_protocol
+ && rp->rcb_proto.sp_protocol != PF_KEY_V2) {
+ continue;
+ }
+
+ kp = (struct keycb *)rp;
+
+ /*
+ * If you are in promiscuous mode, and when you get broadcasted
+ * reply, you'll get two PF_KEY messages.
+ * (based on pf_key@inner.net message on 14 Oct 1998)
+ */
+ if (((struct keycb *)rp)->kp_promisc) {
+ if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
+ (void)key_sendup0(rp, n, 1);
+ n = NULL;
+ }
+ }
+
+ /* the exact target will be processed later */
+ if (so && sotorawcb(so) == rp)
+ continue;
+
+ sendup = 0;
+ switch (target) {
+ case KEY_SENDUP_ONE:
+ /* the statement has no effect */
+ if (so && sotorawcb(so) == rp)
+ sendup++;
+ break;
+ case KEY_SENDUP_ALL:
+ sendup++;
+ break;
+ case KEY_SENDUP_REGISTERED:
+ if (kp->kp_registered)
+ sendup++;
+ break;
+ }
+ pfkeystat.in_msgtarget[target]++;
+
+ if (!sendup)
+ continue;
+
+ if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) {
+#ifdef IPSEC_DEBUG
+ printf("key_sendup: m_copy fail\n");
+#endif
+ m_freem(m);
+ pfkeystat.in_nomem++;
+ return ENOBUFS;
+ }
+
+ if ((error = key_sendup0(rp, n, 0)) != 0) {
+ m_freem(m);
+ return error;
+ }
+
+ n = NULL;
+ }
+
+ if (so) {
+ error = key_sendup0(sotorawcb(so), m, 0);
+ m = NULL;
+ } else {
+ error = 0;
+ m_freem(m);
+ }
+ return error;
+}
/*
* key_abort()
@@ -105,7 +419,7 @@ key_attach(struct socket *so, int proto, struct proc *p)
if (sotorawcb(so) != 0)
return EISCONN; /* XXX panic? */
- MALLOC(kp, struct keycb *, sizeof *kp, M_PCB, M_WAITOK); /* XXX */
+ kp = (struct keycb *)malloc(sizeof *kp, M_PCB, M_WAITOK); /* XXX */
if (kp == 0)
return ENOBUFS;
bzero(kp, sizeof *kp);
@@ -276,253 +590,6 @@ struct pr_usrreqs key_usrreqs = {
key_sockaddr, sosend, soreceive, sopoll
};
-/*
- * key_output()
- */
-int
-key_output(struct mbuf *m, struct socket *so)
-{
- struct sadb_msg *msg = NULL;
- int len, error = 0;
- int s;
- int target;
-
- if (m == 0)
- panic("key_output: NULL pointer was passed.\n");
-
- if (m->m_len < sizeof(long)
- && (m = m_pullup(m, 8)) == 0) {
- printf("key_output: can't pullup mbuf\n");
- error = ENOBUFS;
- goto end;
- }
-
- if ((m->m_flags & M_PKTHDR) == 0)
- panic("key_output: not M_PKTHDR ??");
-
-#if defined(IPSEC_DEBUG)
- KEYDEBUG(KEYDEBUG_KEY_DUMP, kdebug_mbuf(m));
-#endif /* defined(IPSEC_DEBUG) */
-
- len = m->m_pkthdr.len;
- if (len < sizeof(struct sadb_msg)
- || len != PFKEY_UNUNIT64(mtod(m, struct sadb_msg *)->sadb_msg_len)) {
- printf("key_output: Invalid message length.\n");
- error = EINVAL;
- goto end;
- }
-
- /*
- * allocate memory for sadb_msg, and copy to sadb_msg from mbuf
- * XXX: To be processed directly without a copy.
- */
- KMALLOC(msg, struct sadb_msg *, len);
- if (msg == 0) {
- printf("key_output: No more memory.\n");
- error = ENOBUFS;
- goto end;
- /* or do panic ? */
- }
- m_copydata(m, 0, len, (caddr_t)msg);
-
- /*XXX giant lock*/
- s = splnet();
- if ((len = key_parse(&msg, so, &target)) == 0) {
- /* discard. i.e. no need to reply. */
- error = 0;
- splx(s);
- goto end;
- }
-
- /* send up message to the socket */
- error = key_sendup(so, msg, len, target);
- splx(s);
- KFREE(msg);
-end:
- m_freem(m);
- return (error);
-}
-
-/*
- * send message to the socket.
- */
-static int
-key_sendup0(rp, m, promisc)
- struct rawcb *rp;
- struct mbuf *m;
- int promisc;
-{
- if (promisc) {
- struct sadb_msg *pmsg;
-
- M_PREPEND(m, sizeof(struct sadb_msg), M_NOWAIT);
- if (m && m->m_len < sizeof(struct sadb_msg))
- m = m_pullup(m, sizeof(struct sadb_msg));
- if (!m) {
- printf("key_sendup0: cannot pullup\n");
- m_freem(m);
- return ENOBUFS;
- }
- m->m_pkthdr.len += sizeof(*pmsg);
-
- pmsg = mtod(m, struct sadb_msg *);
- bzero(pmsg, sizeof(*pmsg));
- pmsg->sadb_msg_version = PF_KEY_V2;
- pmsg->sadb_msg_type = SADB_X_PROMISC;
- pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len);
- /* pid and seq? */
- }
-
- if (!sbappendaddr(&rp->rcb_socket->so_rcv,
- (struct sockaddr *)&key_src, m, NULL)) {
- printf("key_sendup0: sbappendaddr failed\n");
- m_freem(m);
- return ENOBUFS;
- }
- sorwakeup(rp->rcb_socket);
- return 0;
-}
-
-int
-key_sendup(so, msg, len, target)
- struct socket *so;
- struct sadb_msg *msg;
- u_int len;
- int target; /*target of the resulting message*/
-{
- struct mbuf *m, *n, *mprev;
- struct keycb *kp;
- int sendup;
- struct rawcb *rp;
- int error;
- int tlen;
-
- /* sanity check */
- if (so == 0 || msg == 0)
- panic("key_sendup: NULL pointer was passed.\n");
-
- KEYDEBUG(KEYDEBUG_KEY_DUMP,
- printf("key_sendup: \n");
- kdebug_sadb(msg));
-
- /*
- * Get mbuf chain whenever possible (not clusters),
- * to save socket buffer. We'll be generating many SADB_ACQUIRE
- * messages to listening key sockets. If we simmply allocate clusters,
- * sbappendaddr() will raise ENOBUFS due to too little sbspace().
- * sbspace() computes # of actual data bytes AND mbuf region.
- *
- * TODO: SADB_ACQUIRE filters should be implemented.
- */
- tlen = len;
- m = mprev = NULL;
- while (tlen > 0) {
- if (tlen == len) {
- MGETHDR(n, M_DONTWAIT, MT_DATA);
- if (n == NULL) {
- m_freem(m);
- return ENOBUFS;
- }
- n->m_len = MHLEN;
- } else {
- MGET(n, M_DONTWAIT, MT_DATA);
- if (n == NULL) {
- m_freem(m);
- return ENOBUFS;
- }
- n->m_len = MLEN;
- }
- if (tlen > MCLBYTES) { /*XXX better threshold? */
- MCLGET(n, M_DONTWAIT);
- if ((n->m_flags & M_EXT) == 0) {
- m_free(n);
- m_freem(m);
- return ENOBUFS;
- }
- n->m_len = MCLBYTES;
- }
-
- if (tlen < n->m_len)
- n->m_len = tlen;
- n->m_next = NULL;
- if (m == NULL)
- m = mprev = n;
- else {
- mprev->m_next = n;
- mprev = n;
- }
- tlen -= n->m_len;
- n = NULL;
- }
- m->m_pkthdr.len = len;
- m->m_pkthdr.rcvif = NULL;
- m_copyback(m, 0, len, (caddr_t)msg);
-
- LIST_FOREACH(rp, &rawcb_list, list)
- {
- if (rp->rcb_proto.sp_family != PF_KEY)
- continue;
- if (rp->rcb_proto.sp_protocol
- && rp->rcb_proto.sp_protocol != PF_KEY_V2) {
- continue;
- }
-
- kp = (struct keycb *)rp;
-
- /*
- * If you are in promiscuous mode, and when you get broadcasted
- * reply, you'll get two PF_KEY messages.
- * (based on pf_key@inner.net message on 14 Oct 1998)
- */
- if (((struct keycb *)rp)->kp_promisc) {
- if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
- (void)key_sendup0(rp, n, 1);
- n = NULL;
- }
- }
-
- /* the exact target will be processed later */
- if (sotorawcb(so) == rp)
- continue;
-
- sendup = 0;
- switch (target) {
- case KEY_SENDUP_ONE:
- /* the statement has no effect */
- if (sotorawcb(so) == rp)
- sendup++;
- break;
- case KEY_SENDUP_ALL:
- sendup++;
- break;
- case KEY_SENDUP_REGISTERED:
- if (kp->kp_registered)
- sendup++;
- break;
- }
-
- if (!sendup)
- continue;
-
- if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) {
- printf("key_sendup: m_copy fail\n");
- m_freem(m);
- return ENOBUFS;
- }
-
- if ((error = key_sendup0(rp, n, 0)) != 0) {
- m_freem(m);
- return error;
- }
-
- n = NULL;
- }
-
- error = key_sendup0(sotorawcb(so), m, 0);
- m = NULL;
- return error;
-}
-
/* sysctl */
SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW, 0, "Key Family");
diff --git a/sys/netkey/keysock.h b/sys/netkey/keysock.h
index 97da6f86663f..5eed3ebb457d 100644
--- a/sys/netkey/keysock.h
+++ b/sys/netkey/keysock.h
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: keysock.h,v 1.8 2000/03/27 05:11:06 sumikawa Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,32 +28,55 @@
* 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.
- *
- * $FreeBSD$
*/
-/* $Id: keysock.h,v 1.1.6.3.6.1 1999/05/17 17:03:19 itojun Exp $ */
-
#ifndef _NETKEY_KEYSOCK_H_
-#define _NETKEY_KEYSOCK_H_
+#define _NETKEY_KEYSOCK_H_
+
+/* statistics for pfkey socket */
+struct pfkeystat {
+ /* kernel -> userland */
+ u_quad_t out_total; /* # of total calls */
+ u_quad_t out_bytes; /* total bytecount */
+ u_quad_t out_msgtype[256]; /* message type histogram */
+ u_quad_t out_invlen; /* invalid length field */
+ u_quad_t out_invver; /* invalid version field */
+ u_quad_t out_invmsgtype; /* invalid message type field */
+ u_quad_t out_tooshort; /* msg too short */
+ u_quad_t out_nomem; /* memory allocation failure */
+ u_quad_t out_dupext; /* duplicate extension */
+ u_quad_t out_invexttype; /* invalid extension type */
+ u_quad_t out_invsatype; /* invalid sa type */
+ u_quad_t out_invaddr; /* invalid address extension */
+ /* userland -> kernel */
+ u_quad_t in_total; /* # of total calls */
+ u_quad_t in_bytes; /* total bytecount */
+ u_quad_t in_msgtype[256]; /* message type histogram */
+ u_quad_t in_msgtarget[3]; /* one/all/registered */
+ u_quad_t in_nomem; /* memory allocation failure */
+ /* others */
+ u_quad_t sockerr; /* # of socket related errors */
+};
+
+#define KEY_SENDUP_ONE 0
+#define KEY_SENDUP_ALL 1
+#define KEY_SENDUP_REGISTERED 2
#ifdef _KERNEL
struct keycb {
- struct rawcb kp_raw; /* rawcb */
- int kp_promisc; /* promiscuous mode */
- int kp_registered; /* registered socket */
+ struct rawcb kp_raw; /* rawcb */
+ int kp_promisc; /* promiscuous mode */
+ int kp_registered; /* registered socket */
};
-extern int key_output __P((struct mbuf *, struct socket *));
-extern int key_usrreq __P((struct socket *, int, struct mbuf *,
- struct mbuf *, struct mbuf *));
+extern struct pfkeystat pfkeystat;
-#define KEY_SENDUP_ONE 0
-#define KEY_SENDUP_ALL 1
-#define KEY_SENDUP_REGISTERED 2
+extern int key_output __P((struct mbuf *, ...));
+extern int key_usrreq __P((struct socket *,
+ int, struct mbuf *, struct mbuf *, struct mbuf *));
-extern int key_sendup __P((struct socket *, struct sadb_msg *, u_int,
- int));
+extern int key_sendup __P((struct socket *, struct sadb_msg *, u_int, int));
+extern int key_sendup_mbuf __P((struct socket *, struct mbuf *, int));
#endif /* _KERNEL */
-#endif /* _NETKEY_KEYSOCK_H_ */
+#endif /*_NETKEY_KEYSOCK_H_*/
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index f81a97e86928..98c87fa14e16 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -79,10 +79,11 @@ struct pkthdr {
struct ifnet *rcvif; /* rcv interface */
int len; /* total packet length */
/* variables for ip and tcp reassembly */
- void *header; /* pointer to packet header */
+ caddr_t header; /* pointer to packet header */
/* variables for hardware checksum */
int csum_flags; /* flags regarding checksum */
int csum_data; /* data field used by csum routines */
+ struct mbuf *aux; /* extra data buffer; ipsec/others */
};
/* description of external storage mapped into mbuf, valid if M_EXT set */
@@ -322,6 +323,7 @@ union mcluster {
_mm->m_flags = M_PKTHDR; \
_mm->m_pkthdr.rcvif = NULL; \
_mm->m_pkthdr.csum_flags = 0; \
+ _mm->m_pkthdr.aux = (struct mbuf *)NULL; \
(m) = _mm; \
splx(_ms); \
} else { \
@@ -431,6 +433,7 @@ union mcluster {
/*
* Copy mbuf pkthdr from "from" to "to".
* from must have M_PKTHDR set, and to must be empty.
+ * aux pointer will be moved to `to'.
*/
#define M_COPY_PKTHDR(to, from) do { \
struct mbuf *_mfrom = (from); \
@@ -439,6 +442,7 @@ union mcluster {
_mto->m_data = _mto->m_pktdat; \
_mto->m_flags = _mfrom->m_flags & M_COPYFLAGS; \
_mto->m_pkthdr = _mfrom->m_pkthdr; \
+ _mfrom->m_pkthdr.aux = (struct mbuf *)NULL; \
} while (0)
/*
@@ -516,6 +520,14 @@ union mcluster {
/* compatibility with 4.3 */
#define m_copy(m, o, l) m_copym((m), (o), (l), M_DONTWAIT)
+/*
+ * pkthdr.aux type tags.
+ */
+struct mauxtag {
+ int af;
+ int type;
+};
+
#ifdef _KERNEL
extern u_int m_clalloc_wid; /* mbuf cluster wait count */
extern u_int m_mballoc_wid; /* mbuf wait count */
@@ -552,11 +564,15 @@ struct mbuf *m_gethdr __P((int, int));
int m_mballoc __P((int, int));
struct mbuf *m_mballoc_wait __P((int, int));
struct mbuf *m_prepend __P((struct mbuf *,int,int));
+struct mbuf *m_pulldown __P((struct mbuf *, int, int, int *));
void m_print __P((const struct mbuf *m));
struct mbuf *m_pullup __P((struct mbuf *, int));
struct mbuf *m_retry __P((int, int));
struct mbuf *m_retryhdr __P((int, int));
struct mbuf *m_split __P((struct mbuf *,int,int));
+struct mbuf *m_aux_add __P((struct mbuf *, int, int));
+struct mbuf *m_aux_find __P((struct mbuf *, int, int));
+void m_aux_delete __P((struct mbuf *, struct mbuf *));
#endif /* _KERNEL */
#endif /* !_SYS_MBUF_H_ */
diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h
index efa3cbc89730..c107562eaec3 100644
--- a/sys/sys/sockio.h
+++ b/sys/sys/sockio.h
@@ -90,6 +90,8 @@
#define SIOCSIFPHYADDR _IOW('i', 70, struct ifaliasreq) /* set gif addres */
#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 SIOCSIFGENERIC _IOW('i', 57, struct ifreq) /* generic IF set op */
#define SIOCGIFGENERIC _IOWR('i', 58, struct ifreq) /* generic IF get op */