]> git.neil.brown.name Git - history.git/commitdiff
[IPSEC]: Add ipv6 support infrastructure.
authorKunihiro Ishiguro <kunihiro@ipinfusion.com>
Wed, 12 Feb 2003 17:26:55 +0000 (09:26 -0800)
committerDavid S. Miller <davem@nuts.ninka.net>
Wed, 12 Feb 2003 17:26:55 +0000 (09:26 -0800)
include/net/xfrm.h
net/ipv4/xfrm_state.c
net/ipv6/Makefile
net/ipv6/ipv6_syms.c
net/ipv6/xfrm_policy.c [new file with mode: 0644]
net/key/af_key.c
net/netsyms.c

index 0f331126faa4a443538fa2262c228c20ce3c94af..a783cc75bce5432105d6a48988c6beae832f4b47 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/netdevice.h>
 #include <linux/crypto.h>
 #include <linux/pfkeyv2.h>
+#include <linux/in6.h>
 
 #include <net/dst.h>
 #include <net/route.h>
@@ -424,4 +425,23 @@ extern struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id);
 extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name);
 extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name);
 
+static inline int
+xfrm6_selector_match(struct xfrm_selector *sel, struct flowi *fl)
+{
+      return  !memcmp(fl->fl6_dst, sel->daddr.a6, sizeof(struct in6_addr)) &&
+              !((fl->uli_u.ports.dport^sel->dport)&sel->dport_mask) &&
+              !((fl->uli_u.ports.sport^sel->sport)&sel->sport_mask) &&
+              (fl->proto == sel->proto || !sel->proto) &&
+              (fl->oif == sel->ifindex || !sel->ifindex) &&
+              !memcmp(fl->fl6_src, sel->saddr.a6, sizeof(struct in6_addr));
+}
+
+extern int xfrm6_register_type(struct xfrm_type *type);
+extern int xfrm6_unregister_type(struct xfrm_type *type);
+extern struct xfrm_type *xfrm6_get_type(u8 proto);
+
+extern struct xfrm_state *xfrm6_state_lookup(struct in6_addr *daddr, u32 spi, u8 proto);
+struct xfrm_state * xfrm6_find_acq(u8 mode, u16 reqid, u8 proto, struct in6_addr *daddr, struct in6_addr *saddr, int create);
+void xfrm6_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
+
 #endif /* _NET_XFRM_H */
index 45a2119ce2a2468e24985da3077f2614c5ba58ac..57004ba5766a2d7a25de20ad605fce2eff7adf9f 100644 (file)
@@ -1,6 +1,7 @@
 #include <net/xfrm.h>
 #include <linux/pfkeyv2.h>
 #include <linux/ipsec.h>
+#include <net/ipv6.h>
 
 /* Each xfrm_state may be linked to two tables:
 
@@ -219,7 +220,8 @@ xfrm_state_find(u32 daddr, u32 saddr, struct flowi *fl, struct xfrm_tmpl *tmpl,
 
        spin_lock_bh(&xfrm_state_lock);
        list_for_each_entry(x, xfrm_state_bydst+h, bydst) {
-               if (daddr == x->id.daddr.xfrm4_addr &&
+               if (x->props.family == AF_INET &&
+                   daddr == x->id.daddr.xfrm4_addr &&
                    x->props.reqid == tmpl->reqid &&
                    (saddr == x->props.saddr.xfrm4_addr || !saddr || !x->props.saddr.xfrm4_addr) &&
                    tmpl->mode == x->props.mode &&
@@ -282,6 +284,7 @@ xfrm_state_find(u32 daddr, u32 saddr, struct flowi *fl, struct xfrm_tmpl *tmpl,
                x->id = tmpl->id;
                if (x->id.daddr.xfrm4_addr == 0)
                        x->id.daddr.xfrm4_addr = daddr;
+               x->props.family = AF_INET;
                x->props.saddr = tmpl->saddr;
                if (x->props.saddr.xfrm4_addr == 0)
                        x->props.saddr.xfrm4_addr = saddr;
@@ -317,7 +320,12 @@ xfrm_state_find(u32 daddr, u32 saddr, struct flowi *fl, struct xfrm_tmpl *tmpl,
 
 void xfrm_state_insert(struct xfrm_state *x)
 {
-       unsigned h = ntohl(x->id.daddr.xfrm4_addr);
+       unsigned h = 0;
+
+       if (x->props.family == AF_INET)
+               h = ntohl(x->id.daddr.xfrm4_addr);
+       else if (x->props.family == AF_INET6)
+               h = ntohl(x->id.daddr.a6[2]^x->id.daddr.a6[3]);
 
        h = (h ^ (h>>16)) % XFRM_DST_HSIZE;
 
@@ -325,7 +333,10 @@ void xfrm_state_insert(struct xfrm_state *x)
        list_add(&x->bydst, xfrm_state_bydst+h);
        atomic_inc(&x->refcnt);
 
-       h = ntohl(x->id.daddr.xfrm4_addr^x->id.spi^x->id.proto);
+       if (x->props.family == AF_INET)
+               h = ntohl(x->id.daddr.xfrm4_addr^x->id.spi^x->id.proto);
+       else
+               h = ntohl(x->id.daddr.a6[2]^x->id.daddr.a6[3]^x->id.spi^x->id.proto);
        h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE;
        list_add(&x->byspi, xfrm_state_byspi+h);
        atomic_inc(&x->refcnt);
@@ -382,7 +393,8 @@ xfrm_state_lookup(u32 daddr, u32 spi, u8 proto)
 
        spin_lock_bh(&xfrm_state_lock);
        list_for_each_entry(x, xfrm_state_byspi+h, byspi) {
-               if (spi == x->id.spi &&
+               if (x->props.family == AF_INET &&
+                   spi == x->id.spi &&
                    daddr == x->id.daddr.xfrm4_addr &&
                    proto == x->id.proto) {
                        atomic_inc(&x->refcnt);
@@ -405,7 +417,8 @@ xfrm_find_acq(u8 mode, u16 reqid, u8 proto, u32 daddr, u32 saddr, int create)
 
        spin_lock_bh(&xfrm_state_lock);
        list_for_each_entry(x, xfrm_state_bydst+h, bydst) {
-               if (daddr == x->id.daddr.xfrm4_addr &&
+               if (x->props.family == AF_INET &&
+                   daddr == x->id.daddr.xfrm4_addr &&
                    mode == x->props.mode &&
                    proto == x->id.proto &&
                    saddr == x->props.saddr.xfrm4_addr &&
@@ -432,6 +445,7 @@ xfrm_find_acq(u8 mode, u16 reqid, u8 proto, u32 daddr, u32 saddr, int create)
                x0->km.state = XFRM_STATE_ACQ;
                x0->id.daddr.xfrm4_addr = daddr;
                x0->id.proto = proto;
+               x0->props.family = AF_INET;
                x0->props.mode = mode;
                x0->props.reqid = reqid;
                x0->lft.hard_add_expires_seconds = ACQ_EXPIRES;
@@ -591,8 +605,14 @@ int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl)
        int i;
 
        for (i=0; i<n; i++) {
-               if (!xfrm4_selector_match(&x[i]->sel, fl))
+               if (x[i]->props.family == AF_INET &&
+                   !xfrm4_selector_match(&x[i]->sel, fl))
+                       return -EINVAL;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               if (x[i]->props.family == AF_INET6 &&
+                   !xfrm6_selector_match(&x[i]->sel, fl))
                        return -EINVAL;
+#endif
        }
        return 0;
 }
@@ -701,3 +721,119 @@ void __init xfrm_state_init(void)
                INIT_LIST_HEAD(&xfrm_state_byspi[i]);
        }
 }
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+struct xfrm_state *
+xfrm6_state_lookup(struct in6_addr *daddr, u32 spi, u8 proto)
+{
+       unsigned h = ntohl(daddr->s6_addr32[2]^daddr->s6_addr32[3]^spi^proto);
+       struct xfrm_state *x;
+
+       h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE;
+
+       spin_lock_bh(&xfrm_state_lock);
+       list_for_each_entry(x, xfrm_state_byspi+h, byspi) {
+               if (x->props.family == AF_INET6 &&
+                   spi == x->id.spi &&
+                   !ipv6_addr_cmp(daddr, (struct in6_addr *)x->id.daddr.a6) &&
+                   proto == x->id.proto) {
+                       atomic_inc(&x->refcnt);
+                       spin_unlock_bh(&xfrm_state_lock);
+                       return x;
+               }
+       }
+       spin_unlock_bh(&xfrm_state_lock);
+       return NULL;
+}
+
+struct xfrm_state *
+xfrm6_find_acq(u8 mode, u16 reqid, u8 proto, struct in6_addr *daddr, struct in6_addr *saddr, int create)
+{
+       struct xfrm_state *x, *x0;
+       unsigned h = ntohl(daddr->s6_addr32[2]^daddr->s6_addr32[3]);
+
+       h = (h ^ (h>>16)) % XFRM_DST_HSIZE;
+       x0 = NULL;
+
+       spin_lock_bh(&xfrm_state_lock);
+       list_for_each_entry(x, xfrm_state_bydst+h, bydst) {
+               if (x->props.family == AF_INET6 &&
+                   !memcmp(daddr, x->id.daddr.a6, sizeof(struct in6_addr)) &&
+                   mode == x->props.mode &&
+                   proto == x->id.proto &&
+                   !memcmp(saddr, x->props.saddr.a6, sizeof(struct in6_addr)) &&
+                   reqid == x->props.reqid &&
+                   x->km.state == XFRM_STATE_ACQ) {
+                           if (!x0)
+                                   x0 = x;
+                           if (x->id.spi)
+                                   continue;
+                           x0 = x;
+                           break;
+                   }
+       }
+       if (x0) {
+               atomic_inc(&x0->refcnt);
+       } else if (create && (x0 = xfrm_state_alloc()) != NULL) {
+               memcpy(x0->sel.daddr.a6, daddr, sizeof(struct in6_addr));
+               memcpy(x0->sel.saddr.a6, saddr, sizeof(struct in6_addr));
+               x0->sel.prefixlen_d = 128;
+               x0->sel.prefixlen_s = 128;
+               memcpy(x0->props.saddr.a6, saddr, sizeof(struct in6_addr));
+               x0->km.state = XFRM_STATE_ACQ;
+               memcpy(x0->id.daddr.a6, daddr, sizeof(struct in6_addr));
+               x0->id.proto = proto;
+               x0->props.family = AF_INET6;
+               x0->props.mode = mode;
+               x0->props.reqid = reqid;
+               x0->lft.hard_add_expires_seconds = ACQ_EXPIRES;
+               atomic_inc(&x0->refcnt);
+               mod_timer(&x0->timer, jiffies + ACQ_EXPIRES*HZ);
+               atomic_inc(&x0->refcnt);
+               list_add_tail(&x0->bydst, xfrm_state_bydst+h);
+               wake_up(&km_waitq);
+       }
+       spin_unlock_bh(&xfrm_state_lock);
+       return x0;
+}
+
+void
+xfrm6_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi)
+{
+       u32 h;
+       struct xfrm_state *x0;
+
+       if (x->id.spi)
+               return;
+
+       if (minspi == maxspi) {
+               x0 = xfrm6_state_lookup((struct in6_addr*)x->id.daddr.a6, minspi, x->id.proto);
+               if (x0) {
+                       xfrm_state_put(x0);
+                       return;
+               }
+               x->id.spi = minspi;
+       } else {
+               u32 spi = 0;
+               minspi = ntohl(minspi);
+               maxspi = ntohl(maxspi);
+               for (h=0; h<maxspi-minspi+1; h++) {
+                       spi = minspi + net_random()%(maxspi-minspi+1);
+                       x0 = xfrm6_state_lookup((struct in6_addr*)x->id.daddr.a6, htonl(spi), x->id.proto);
+                       if (x0 == NULL)
+                               break;
+                       xfrm_state_put(x0);
+               }
+               x->id.spi = htonl(spi);
+       }
+       if (x->id.spi) {
+               spin_lock_bh(&xfrm_state_lock);
+               h = ntohl(x->id.daddr.a6[2]^x->id.daddr.a6[3]^x->id.spi^x->id.proto);
+               h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE;
+               list_add(&x->byspi, xfrm_state_byspi+h);
+               atomic_inc(&x->refcnt);
+               spin_unlock_bh(&xfrm_state_lock);
+               wake_up(&km_waitq);
+       }
+}
+#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */
index db0614ef8156d3fc93a19cc997bf4af9a162ff4d..373dbcef9d2c40d301c48ba619362646a3ad70f5 100644 (file)
@@ -11,3 +11,5 @@ ipv6-objs :=  af_inet6.o ip6_output.o ip6_input.o addrconf.o sit.o \
                ip6_flowlabel.o ipv6_syms.o
 
 obj-$(CONFIG_NETFILTER)        += netfilter/
+
+obj-y += xfrm_policy.o
index ddb235fa1e658902fab7f7c23acda14af6fe1ddd..d7bed96bbfdc8663bf1558861d1f8cc7a5f76082 100644 (file)
@@ -25,3 +25,6 @@ EXPORT_SYMBOL(inet6_getname);
 EXPORT_SYMBOL(inet6_ioctl);
 EXPORT_SYMBOL(ipv6_get_saddr);
 EXPORT_SYMBOL(ipv6_chk_addr);
+EXPORT_SYMBOL(xfrm6_register_type);
+EXPORT_SYMBOL(xfrm6_unregister_type);
+EXPORT_SYMBOL(xfrm6_get_type);
diff --git a/net/ipv6/xfrm_policy.c b/net/ipv6/xfrm_policy.c
new file mode 100644 (file)
index 0000000..208f6aa
--- /dev/null
@@ -0,0 +1,43 @@
+#include <net/xfrm.h>
+#include <net/ip.h>
+
+static struct xfrm_type *xfrm6_type_map[256];
+static rwlock_t xfrm6_type_lock = RW_LOCK_UNLOCKED;
+
+int xfrm6_register_type(struct xfrm_type *type)
+{
+       int err = 0;
+
+       write_lock(&xfrm6_type_lock);
+       if (xfrm6_type_map[type->proto] == NULL)
+               xfrm6_type_map[type->proto] = type;
+       else
+               err = -EEXIST;
+       write_unlock(&xfrm6_type_lock);
+       return err;
+}
+
+int xfrm6_unregister_type(struct xfrm_type *type)
+{
+       int err = 0;
+
+       write_lock(&xfrm6_type_lock);
+       if (xfrm6_type_map[type->proto] != type)
+               err = -ENOENT;
+       else
+               xfrm6_type_map[type->proto] = NULL;
+       write_unlock(&xfrm6_type_lock);
+       return err;
+}
+
+struct xfrm_type *xfrm6_get_type(u8 proto)
+{
+       struct xfrm_type *type;
+
+       read_lock(&xfrm6_type_lock);
+       type = xfrm6_type_map[proto];
+       if (type && !try_module_get(type->owner))
+               type = NULL;
+       read_unlock(&xfrm6_type_lock);
+       return type;
+}
index a15e28066d53061290c9a291e59cd6744c436ac9..adf4cfd776cf9d90ee6e9201512f30bf3eb2fa1a 100644 (file)
@@ -9,6 +9,7 @@
  * Authors:    Maxim Giryaev   <gem@asplinux.ru>
  *             David S. Miller <davem@redhat.com>
  *             Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+ *             Kunihiro Ishiguro <kunihiro@ipinfusion.com>
  */
 
 #include <linux/config.h>
@@ -351,7 +352,9 @@ static int verify_address_len(void *p)
        struct sadb_address *sp = p;
        struct sockaddr *addr = (struct sockaddr *)(sp + 1);
        struct sockaddr_in *sin;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        struct sockaddr_in6 *sin6;
+#endif
        int len;
 
        switch (addr->sa_family) {
@@ -362,7 +365,7 @@ static int verify_address_len(void *p)
                    sp->sadb_address_prefixlen > 32)
                        return -EINVAL;
                break;
-
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        case AF_INET6:
                len  = sizeof(*sp) + sizeof(*sin6) + (sizeof(uint64_t) - 1);
                len /= sizeof(uint64_t);
@@ -370,7 +373,7 @@ static int verify_address_len(void *p)
                    sp->sadb_address_prefixlen > 128)
                        return -EINVAL;
                break;
-
+#endif
        default:
                /* It is user using kernel to keep track of security
                 * associations for another protocol, such as
@@ -400,7 +403,11 @@ static int present_and_same_family(struct sadb_address *src,
        d_addr = (struct sockaddr *)(dst + 1);
        if (s_addr->sa_family != d_addr->sa_family)
                return 0;
-       if (s_addr->sa_family != AF_INET)
+       if (s_addr->sa_family != AF_INET
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+           && s_addr->sa_family != AF_INET6
+#endif
+               )
                return 0;
 
        return 1;
@@ -497,25 +504,27 @@ static uint8_t pfkey_proto_from_xfrm(uint8_t proto)
        return (proto ? proto : IPSEC_PROTO_ANY);
 }
 
-static xfrm_address_t *pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr,
-                                                xfrm_address_t *xaddr)
+int pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr,
+                             xfrm_address_t *xaddr)
 {
        switch (((struct sockaddr*)(addr + 1))->sa_family) {
        case AF_INET:
                xaddr->xfrm4_addr = 
-                       ((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr;
+                       ((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr;
                if (addr->sadb_address_prefixlen)
                        xaddr->xfrm4_mask = htonl(~0 << (32 - addr->sadb_address_prefixlen));
-               break;
+               return AF_INET;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        case AF_INET6:
                memcpy(xaddr->a6, 
-                      &((struct sockaddr_in6*)(addr + 1))->sin6_addr,
-                      sizeof(xaddr->a6));
+                      &((struct sockaddr_in6 *)(addr + 1))->sin6_addr,
+                      sizeof(struct in6_addr));
+               return AF_INET6;
+#endif
        default:
-               return NULL;
+               return 0;
        }
-
-       return xaddr;
+       /* NOTREACHED */
 }
 
 static struct  xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **ext_hdrs)
@@ -540,11 +549,15 @@ static struct  xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **
 
        switch (((struct sockaddr *)(addr + 1))->sa_family) {
        case AF_INET:
-               x = xfrm_state_lookup(((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr,
+               x = xfrm_state_lookup(((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr,
                                      sa->sadb_sa_spi, proto);
                break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        case AF_INET6:
-               /* XXX handle IPv6 */
+               x = xfrm6_state_lookup(&((struct sockaddr_in6 *)(addr + 1))->sin6_addr,
+                                      sa->sadb_sa_spi, proto);
+               break;
+#endif
        default:
                x = NULL;
                break;
@@ -554,6 +567,22 @@ static struct  xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **
 }
 
 #define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1)))
+static int
+pfkey_sockaddr_size(sa_family_t family)
+{
+       switch (family) {
+       case AF_INET:
+               return PFKEY_ALIGN8(sizeof(struct sockaddr_in));
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case AF_INET6:
+               return PFKEY_ALIGN8(sizeof(struct sockaddr_in6));
+#endif
+       default:
+               return 0;
+       }
+       /* NOTREACHED */
+}
+
 static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, int hsc)
 {
        struct sk_buff *skb;
@@ -564,9 +593,18 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
        struct sadb_key *key;
        struct sadb_x_sa2 *sa2;
        struct sockaddr_in *sin;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct sockaddr_in6 *sin6;
+#endif
        int size;
        int auth_key_size = 0;
        int encrypt_key_size = 0;
+       int sockaddr_size;
+
+       /* address family check */
+       sockaddr_size = pfkey_sockaddr_size(x->props.family);
+       if (!sockaddr_size)
+               ERR_PTR(-EINVAL);
 
        /* base, SA, (lifetime (HSC),) address(SD), (address(P),)
           key(AE), (identity(SD),) (sensitivity)> */
@@ -575,13 +613,18 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
                ((hsc & 1) ? sizeof(struct sadb_lifetime) : 0) +
                ((hsc & 2) ? sizeof(struct sadb_lifetime) : 0) +
                        sizeof(struct sadb_address)*2 + 
-                               sizeof(struct sockaddr_in)*2 + /* XXX */
+                               sockaddr_size*2 +
                                        sizeof(struct sadb_x_sa2);
-       /* XXX identity & sensitivity */
+       /* identity & sensitivity */
 
-       if (x->sel.saddr.xfrm4_addr != x->props.saddr.xfrm4_addr)
-               size += sizeof(struct sadb_address) + 
-                       sizeof(struct sockaddr_in); /* XXX */
+       if ((x->props.family == AF_INET &&
+            x->sel.saddr.xfrm4_addr != x->props.saddr.xfrm4_addr) ||
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+           || (x->props.family == AF_INET6 &&
+               memcmp (x->sel.saddr.a6, x->props.saddr.a6, sizeof (struct in6_addr)))
+#endif
+               )
+               size += sizeof(struct sadb_address) + sockaddr_size;
 
        if (add_keys) {
                if (x->aalg && x->aalg->alg_key_len) {
@@ -665,54 +708,113 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
        lifetime->sadb_lifetime_usetime = x->curlft.use_time;
        /* src address */
        addr = (struct sadb_address*) skb_put(skb, 
-                                             sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
+                                             sizeof(struct sadb_address)+sockaddr_size);
        addr->sadb_address_len = 
-               (sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
+               (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
        addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
        /* "if the ports are non-zero, then the sadb_address_proto field, 
           normally zero, MUST be filled in with the transport 
           protocol's number." - RFC2367 */
        addr->sadb_address_proto = 0; 
-       addr->sadb_address_prefixlen = 32; /* XXX */ 
        addr->sadb_address_reserved = 0;
-       sin = (struct sockaddr_in *) (addr + 1);
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = x->props.saddr.xfrm4_addr;
-       sin->sin_port = 0;
-       memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+       if (x->props.family == AF_INET) {
+               addr->sadb_address_prefixlen = 32;
+
+               sin = (struct sockaddr_in *) (addr + 1);
+               sin->sin_family = AF_INET;
+               sin->sin_addr.s_addr = x->props.saddr.xfrm4_addr;
+               sin->sin_port = 0;
+               memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else if (x->props.family == AF_INET6) {
+               addr->sadb_address_prefixlen = 128;
+
+               sin6 = (struct sockaddr_in6 *) (addr + 1);
+               sin6->sin6_family = AF_INET6;
+               sin6->sin6_port = 0;
+               sin6->sin6_flowinfo = 0;
+               memcpy(&sin6->sin6_addr, x->props.saddr.a6,
+                      sizeof(struct in6_addr));
+               sin6->sin6_scope_id = 0;
+       }
+#endif
+       else
+               BUG();
+
        /* dst address */
        addr = (struct sadb_address*) skb_put(skb, 
-                                             sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
+                                             sizeof(struct sadb_address)+sockaddr_size);
        addr->sadb_address_len = 
-               (sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
+               (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
        addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
        addr->sadb_address_proto = 0; 
        addr->sadb_address_prefixlen = 32; /* XXX */ 
        addr->sadb_address_reserved = 0;
-       sin = (struct sockaddr_in *) (addr + 1);
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = x->id.daddr.xfrm4_addr;
-       sin->sin_port = 0;
-       memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
-
-       if (x->sel.saddr.xfrm4_addr != x->props.saddr.xfrm4_addr) {
-               addr = (struct sadb_address*) skb_put(skb, 
-                                                     sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
-               addr->sadb_address_len = 
-                       (sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
-                               sizeof(uint64_t);
-               addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
-               addr->sadb_address_proto = pfkey_proto_from_xfrm(x->sel.proto);
-               addr->sadb_address_prefixlen = x->sel.prefixlen_s;
-               addr->sadb_address_reserved = 0;
-               sin = (struct sockaddr_in*)(addr + 1);
+       if (x->props.family == AF_INET) {
+               sin = (struct sockaddr_in *) (addr + 1);
                sin->sin_family = AF_INET;
-               sin->sin_addr.s_addr = x->sel.saddr.xfrm4_addr;
-               sin->sin_port = x->sel.sport;
+               sin->sin_addr.s_addr = x->id.daddr.xfrm4_addr;
+               sin->sin_port = 0;
                memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+
+               if (x->sel.saddr.xfrm4_addr != x->props.saddr.xfrm4_addr) {
+                       addr = (struct sadb_address*) skb_put(skb, 
+                               sizeof(struct sadb_address)+sockaddr_size);
+                       addr->sadb_address_len = 
+                               (sizeof(struct sadb_address)+sockaddr_size)/
+                               sizeof(uint64_t);
+                       addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
+                       addr->sadb_address_proto =
+                               pfkey_proto_from_xfrm(x->sel.proto);
+                       addr->sadb_address_prefixlen = x->sel.prefixlen_s;
+                       addr->sadb_address_reserved = 0;
+
+                       sin = (struct sockaddr_in *) (addr + 1);
+                       sin->sin_family = AF_INET;
+                       sin->sin_addr.s_addr = x->sel.saddr.xfrm4_addr;
+                       sin->sin_port = x->sel.sport;
+                       memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+               }
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else if (x->props.family == AF_INET6) {
+               addr->sadb_address_prefixlen = 128;
+
+               sin6 = (struct sockaddr_in6 *) (addr + 1);
+               sin6->sin6_family = AF_INET6;
+               sin6->sin6_port = 0;
+               sin6->sin6_flowinfo = 0;
+               memcpy(&sin6->sin6_addr, x->id.daddr.a6, sizeof(struct in6_addr));
+               sin6->sin6_scope_id = 0;
+
+               if (memcmp (x->sel.saddr.a6, x->props.saddr.a6,
+                           sizeof(struct in6_addr))) {
+                       addr = (struct sadb_address *) skb_put(skb, 
+                               sizeof(struct sadb_address)+sockaddr_size);
+                       addr->sadb_address_len = 
+                               (sizeof(struct sadb_address)+sockaddr_size)/
+                               sizeof(uint64_t);
+                       addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
+                       addr->sadb_address_proto =
+                               pfkey_proto_from_xfrm(x->sel.proto);
+                       addr->sadb_address_prefixlen = x->sel.prefixlen_s;
+                       addr->sadb_address_reserved = 0;
+
+                       sin6 = (struct sockaddr_in6 *) (addr + 1);
+                       sin6->sin6_family = AF_INET6;
+                       sin6->sin6_port = x->sel.sport;
+                       sin6->sin6_flowinfo = 0;
+                       memcpy(&sin6->sin6_addr, x->sel.saddr.a6,
+                              sizeof(struct in6_addr));
+                       sin6->sin6_scope_id = 0;
+               }
        }
+#endif
+       else
+               BUG();
 
        /* auth key */
        if (add_keys && auth_key_size) {
@@ -870,8 +972,10 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
        }
        /* x->algo.flags = sa->sadb_sa_flags; */
 
-       pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 
-                                 &x->props.saddr);
+       x->props.family = pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 
+                                                   &x->props.saddr);
+       if (!x->props.family)
+               goto out;
        pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1], 
                                  &x->id.daddr);
 
@@ -891,7 +995,20 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
                x->sel.prefixlen_s = addr->sadb_address_prefixlen;
        }
 
-       x->type = xfrm_get_type(proto);
+       switch (x->props.family) {
+       case AF_INET:
+               x->type = xfrm_get_type(proto);
+               break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case AF_INET6:
+               x->type = xfrm6_get_type(proto);
+               break;
+#endif
+       default:
+               x->type = NULL;
+               break;
+       }
+
        if (x->type == NULL)
                goto out;
        if (x->type->init_state(x, NULL))
@@ -918,8 +1035,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
 {
        struct sk_buff *resp_skb;
        struct sadb_x_sa2 *sa2;
-       struct sadb_address *addr;
-       struct sockaddr_in *saddr, *daddr;
+       struct sadb_address *saddr, *daddr;
        struct sadb_msg *out_hdr;
        struct xfrm_state *x;
        u8 mode;
@@ -942,13 +1058,27 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
                reqid = 0;
        }
 
-       addr = ext_hdrs[SADB_EXT_ADDRESS_SRC-1];
-       saddr = (struct sockaddr_in*)(addr + 1);
-       addr = ext_hdrs[SADB_EXT_ADDRESS_DST-1];
-       daddr = (struct sockaddr_in*)(addr + 1);
+       saddr = ext_hdrs[SADB_EXT_ADDRESS_SRC-1];
+       daddr = ext_hdrs[SADB_EXT_ADDRESS_DST-1];
+
+       switch (((struct sockaddr *)(saddr + 1))->sa_family) {
+       case AF_INET:
+               x = xfrm_find_acq(mode, reqid, proto,
+                                 ((struct sockaddr_in *)(daddr + 1))->sin_addr.s_addr,
+                                 ((struct sockaddr_in *)(saddr + 1))->sin_addr.s_addr, 1);
+               break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case AF_INET6:
+               x = xfrm6_find_acq(mode, reqid, proto,
+                                  &((struct sockaddr_in6 *)(daddr + 1))->sin6_addr,
+                                  &((struct sockaddr_in6 *)(saddr + 1))->sin6_addr, 1);
+               break;
+#endif
+       default:
+               x = NULL;
+               break;
+       }
 
-       x = xfrm_find_acq(mode, reqid, proto, daddr->sin_addr.s_addr,
-                         saddr->sin_addr.s_addr, 1);
        if (x == NULL)
                return -ENOENT;
 
@@ -966,7 +1096,18 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
                        min_spi = htonl(0x100);
                        max_spi = htonl(0x0fffffff);
                }
-               xfrm_alloc_spi(x, min_spi, max_spi);
+               switch (x->props.family) {
+               case AF_INET:
+                       xfrm_alloc_spi(x, min_spi, max_spi);
+                       break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               case AF_INET6:
+                       xfrm6_alloc_spi(x, min_spi, max_spi);
+                       break;
+#endif
+               default:
+                       break;
+               }
                if (x->id.spi)
                        resp_skb = pfkey_xfrm_state2msg(x, 0, 3);
        }
@@ -1034,9 +1175,23 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr,
        /* XXX there is race condition */
        x1 = pfkey_xfrm_state_lookup(hdr, ext_hdrs);
        if (!x1) {
-               x1 = xfrm_find_acq(x->props.mode, x->props.reqid, x->id.proto,
-                                  x->id.daddr.xfrm4_addr,
-                                  x->props.saddr.xfrm4_addr, 0);
+               switch (x->props.family) {
+               case AF_INET:
+                       x1 = xfrm_find_acq(x->props.mode, x->props.reqid, x->id.proto,
+                                          x->id.daddr.xfrm4_addr,
+                                          x->props.saddr.xfrm4_addr, 0);
+                       break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               case AF_INET6:
+                       x1 = xfrm6_find_acq(x->props.mode, x->props.reqid, x->id.proto,
+                                           (struct in6_addr*)x->id.daddr.a6,
+                                           (struct in6_addr*)x->props.saddr.a6, 0);
+                       break;
+#endif
+               default:
+                       x1 = NULL;
+                       break;
+               }
                if (x1 && x1->id.spi != x->id.spi && x1->id.spi) {
                        xfrm_state_put(x1);
                        x1 = NULL;
@@ -1345,7 +1500,10 @@ static int
 parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
 {
        struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr;
-       struct sockaddr_in *addr;
+       struct sockaddr_in *sin;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct sockaddr_in6 *sin6;
+#endif
 
        if (xp->xfrm_nr >= XFRM_MAX_DEPTH)
                return -ELOOP;
@@ -1367,10 +1525,32 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
 
        /* addresses present only in tunnel mode */
        if (t->mode) {
-               addr = (void*)(rq+1);
-               t->saddr.xfrm4_addr = addr->sin_addr.s_addr;
-               addr++;
-               t->id.daddr.xfrm4_addr = addr->sin_addr.s_addr;
+               switch (xp->family) {
+               case AF_INET:
+                       sin = (void*)(rq+1);
+                       if (sin->sin_family != AF_INET)
+                               return -EINVAL;
+                       t->saddr.xfrm4_addr = sin->sin_addr.s_addr;
+                       sin++;
+                       if (sin->sin_family != AF_INET)
+                               return -EINVAL;
+                       t->id.daddr.xfrm4_addr = sin->sin_addr.s_addr;
+                       break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               case AF_INET6:
+                       sin6 = (void *)(rq+1);
+                       if (sin6->sin6_family != AF_INET6)
+                               return -EINVAL;
+                       memcpy(t->saddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr));
+                       sin6++;
+                       if (sin6->sin6_family != AF_INET6)
+                               return -EINVAL;
+                       memcpy(t->id.daddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr));
+                       break;
+#endif
+               default:
+                       return -EINVAL;
+               }
        }
        /* No way to set this via kame pfkey */
        t->aalgos = t->ealgos = t->calgos = ~0;
@@ -1396,13 +1576,18 @@ parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol)
 
 static int pfkey_xfrm_policy2msg_size(struct xfrm_policy *xp)
 {
+       int sockaddr_size = pfkey_sockaddr_size(xp->family);
+       int socklen = (xp->family == AF_INET ?
+                      sizeof(struct sockaddr_in) :
+                      sizeof(struct sockaddr_in6));
+
        return sizeof(struct sadb_msg) +
                (sizeof(struct sadb_lifetime) * 3) +
                (sizeof(struct sadb_address) * 2) + 
-               (sizeof(struct sockaddr_in) * 2) + /* XXX */
+               (sockaddr_size * 2) +
                sizeof(struct sadb_x_policy) +
                (xp->xfrm_nr * (sizeof(struct sadb_x_ipsecrequest) +
-                               (sizeof(struct sockaddr_in) * 2)));
+                               (socklen * 2)));
 }
 
 static struct sk_buff * pfkey_xfrm_policy2msg_prep(struct xfrm_policy *xp)
@@ -1437,35 +1622,66 @@ static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, i
 
        /* src address */
        addr = (struct sadb_address*) skb_put(skb, 
-                                             sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
+                                             sizeof(struct sadb_address)+sockaddr_size);
        addr->sadb_address_len = 
-               (sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
+               (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
        addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
        addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto);
        addr->sadb_address_prefixlen = xp->selector.prefixlen_s;
        addr->sadb_address_reserved = 0;
        /* src address */
-       sin = (struct sockaddr_in*)(addr + 1);
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = xp->selector.saddr.xfrm4_addr;
-       sin->sin_port = xp->selector.sport;
-       memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+       if (xp->family == AF_INET) {
+               sin = (struct sockaddr_in *) (addr + 1);
+               sin->sin_family = AF_INET;
+               sin->sin_addr.s_addr = xp->selector.saddr.xfrm4_addr;
+               sin->sin_port = xp->selector.sport;
+               memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else if (xp->family == AF_INET6) {
+               sin6 = (struct sockaddr_in6 *) (addr + 1);
+               sin6->sin6_family = AF_INET6;
+               sin6->sin6_port = xp->selector.sport;
+               sin6->sin6_flowinfo = 0;
+               memcpy(&sin6->sin6_addr, xp->selector.saddr.a6,
+                      sizeof(struct in6_addr));;
+               sin6->sin6_scope_id = 0;
+       }
+#endif
+       else
+               BUG();
+
        /* dst address */
        addr = (struct sadb_address*) skb_put(skb, 
-                                             sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
+                                             sizeof(struct sadb_address)+sockaddr_size);
        addr->sadb_address_len =
-               (sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
+               (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
        addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
        addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto);
        addr->sadb_address_prefixlen = xp->selector.prefixlen_d; 
        addr->sadb_address_reserved = 0;
-       sin = (struct sockaddr_in*)(addr + 1);
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = xp->selector.daddr.xfrm4_addr;
-       sin->sin_port = xp->selector.dport;
-       memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+       if (xp->family == AF_INET) {
+               sin = (struct sockaddr_in *) (addr + 1);
+               sin->sin_family = AF_INET;
+               sin->sin_addr.s_addr = xp->selector.daddr.xfrm4_addr;
+               sin->sin_port = xp->selector.dport;
+               memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else if (xp->family == AF_INET6) {
+               sin6 = (struct sockaddr_in6 *) (addr + 1);
+               sin6->sin6_family = AF_INET6;
+               sin6->sin6_port = xp->selector.dport;
+               sin6->sin6_flowinfo = 0;
+               memcpy(&sin6->sin6_addr, xp->selector.daddr.a6,
+                      sizeof(struct in6_addr));
+               sin6->sin6_scope_id = 0;
+       }
+#endif
+       else
+               BUG();
 
        /* hard time */
        lifetime = (struct sadb_lifetime *)  skb_put(skb, 
@@ -1518,9 +1734,9 @@ static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, i
 
                req_size = sizeof(struct sadb_x_ipsecrequest);
                if (t->mode)
-                       req_size += 2*sizeof(struct sockaddr_in);
-               else 
-                       size -= 2*sizeof(struct sockaddr_in);
+                       req_size += 2*socklen;
+               else
+                       size -= 2*socklen;
                rq = (void*)skb_put(skb, req_size);
                pol->sadb_x_policy_len += req_size/8;
                rq->sadb_x_ipsecrequest_len = req_size;
@@ -1533,16 +1749,41 @@ static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, i
                        rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE;
                rq->sadb_x_ipsecrequest_reqid = t->reqid;
                if (t->mode) {
-                       sin = (void*)(rq+1);
-                       sin->sin_family = AF_INET;
-                       sin->sin_addr.s_addr = t->saddr.xfrm4_addr;
-                       sin->sin_port = 0;
-                       memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
-                       sin++;
-                       sin->sin_family = AF_INET;
-                       sin->sin_addr.s_addr = t->id.daddr.xfrm4_addr;
-                       sin->sin_port = 0;
-                       memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+                       switch (xp->family) {
+                       case AF_INET:
+                               sin = (void*)(rq+1);
+                               sin->sin_family = AF_INET;
+                               sin->sin_addr.s_addr = t->saddr.xfrm4_addr;
+                               sin->sin_port = 0;
+                               memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+                               sin++;
+                               sin->sin_family = AF_INET;
+                               sin->sin_addr.s_addr = t->id.daddr.xfrm4_addr;
+                               sin->sin_port = 0;
+                               memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+                               break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+                       case AF_INET6:
+                               sin6 = (void*)(rq+1);
+                               sin6->sin6_family = AF_INET6;
+                               sin6->sin6_port = 0;
+                               sin6->sin6_flowinfo = 0;
+                               memcpy(&sin6->sin6_addr, t->saddr.a6,
+                                      sizeof(struct in6_addr));
+                               sin6->sin6_scope_id = 0;
+
+                               sin6++;
+                               sin6->sin6_family = AF_INET6;
+                               sin6->sin6_port = 0;
+                               sin6->sin6_flowinfo = 0;
+                               memcpy(&sin6->sin6_addr, t->id.daddr.a6,
+                                      sizeof(struct in6_addr));
+                               sin6->sin6_scope_id = 0;
+                               break;
+#endif
+                       default:
+                               break;
+                       }
                }
        }
        hdr->sadb_msg_len = size / sizeof(uint64_t);
@@ -1578,10 +1819,14 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
                      XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW);
 
        sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 
-       pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.saddr);
+       xp->family = pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.saddr);
+       if (!xp->family) {
+               err = -EINVAL;
+               goto out;
+       }
        xp->selector.prefixlen_s = sa->sadb_address_prefixlen;
        xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
-       xp->selector.sport = ((struct sockaddr_in*)(sa+1))->sin_port;
+       xp->selector.sport = ((struct sockaddr_in *)(sa+1))->sin_port;
        if (xp->selector.sport)
                xp->selector.sport_mask = ~0;
 
@@ -1594,7 +1839,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
         */
        xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
 
-       xp->selector.dport = ((struct sockaddr_in*)(sa+1))->sin_port;
+       xp->selector.dport = ((struct sockaddr_in *)(sa+1))->sin_port;
        if (xp->selector.dport)
                xp->selector.dport_mask = ~0;
 
@@ -1676,7 +1921,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg
        pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr);
        sel.prefixlen_s = sa->sadb_address_prefixlen;
        sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
-       sel.sport = ((struct sockaddr_in*)(sa+1))->sin_port;
+       sel.sport = ((struct sockaddr_in *)(sa+1))->sin_port;
        if (sel.sport)
                sel.sport_mask = ~0;
 
@@ -1684,7 +1929,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg
        pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr);
        sel.prefixlen_d = sa->sadb_address_prefixlen;
        sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
-       sel.dport = ((struct sockaddr_in*)(sa+1))->sin_port;
+       sel.dport = ((struct sockaddr_in *)(sa+1))->sin_port;
        if (sel.dport)
                sel.dport_mask = ~0;
 
@@ -2049,12 +2294,20 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
        struct sadb_address *addr;
        struct sadb_x_policy *pol;
        struct sockaddr_in *sin;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct sockaddr_in6 *sin6;
+#endif
+       int sockaddr_size;
        int size;
        
+       sockaddr_size = pfkey_sockaddr_size(x->props.family);
+       if (!sockaddr_size)
+               return -EINVAL;
+
        size = sizeof(struct sadb_msg) +
-               sizeof(struct sadb_address)*2 + 
-                       sizeof(struct sockaddr_in)*2 +   /* XXX */
-                               sizeof(struct sadb_x_policy);
+               (sizeof(struct sadb_address) * 2) +
+               (sockaddr_size * 2) +
+               sizeof(struct sadb_x_policy);
        
        if (x->id.proto == IPPROTO_AH)
                size += count_ah_combs(t);
@@ -2077,35 +2330,71 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
 
        /* src address */
        addr = (struct sadb_address*) skb_put(skb, 
-                                             sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
+                                             sizeof(struct sadb_address)+sockaddr_size);
        addr->sadb_address_len = 
-               (sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
+               (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
        addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
        addr->sadb_address_proto = 0;
-       addr->sadb_address_prefixlen = 32;
        addr->sadb_address_reserved = 0;
-       sin = (struct sockaddr_in*)(addr + 1);
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = x->props.saddr.xfrm4_addr;
-       sin->sin_port = 0;
-       memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+       if (x->props.family == AF_INET) {
+               addr->sadb_address_prefixlen = 32;
+
+               sin = (struct sockaddr_in *) (addr + 1);
+               sin->sin_family = AF_INET;
+               sin->sin_addr.s_addr = x->props.saddr.xfrm4_addr;
+               sin->sin_port = 0;
+               memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else if (x->props.family == AF_INET6) {
+               addr->sadb_address_prefixlen = 128;
+
+               sin6 = (struct sockaddr_in6 *) (addr + 1);
+               sin6->sin6_family = AF_INET6;
+               sin6->sin6_port = 0;
+               sin6->sin6_flowinfo = 0;
+               memcpy(&sin6->sin6_addr,
+                      x->props.saddr.a6, sizeof(struct in6_addr));
+               sin6->sin6_scope_id = 0;
+       }
+#endif
+       else
+               BUG();
        
        /* dst address */
        addr = (struct sadb_address*) skb_put(skb, 
-                                             sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
+                                             sizeof(struct sadb_address)+sockaddr_size);
        addr->sadb_address_len =
-               (sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
+               (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
        addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
        addr->sadb_address_proto = 0;
-       addr->sadb_address_prefixlen = 32; 
        addr->sadb_address_reserved = 0;
-       sin = (struct sockaddr_in*)(addr + 1);
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = x->id.daddr.xfrm4_addr;
-       sin->sin_port = 0;
-       memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+       if (x->props.family == AF_INET) {
+               addr->sadb_address_prefixlen = 32; 
+
+               sin = (struct sockaddr_in *) (addr + 1);
+               sin->sin_family = AF_INET;
+               sin->sin_addr.s_addr = x->id.daddr.xfrm4_addr;
+               sin->sin_port = 0;
+               memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else if (x->props.family == AF_INET6) {
+               addr->sadb_address_prefixlen = 128; 
+
+               sin6 = (struct sockaddr_in6 *) (addr + 1);
+               sin6->sin6_family = AF_INET6;
+               sin6->sin6_port = 0;
+               sin6->sin6_flowinfo = 0;
+               memcpy(&sin6->sin6_addr,
+                      x->id.daddr.a6, sizeof(struct in6_addr));
+               sin6->sin6_scope_id = 0;
+       }
+#endif
+       else
+               BUG();
 
        pol = (struct sadb_x_policy *)  skb_put(skb, sizeof(struct sadb_x_policy));
        pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t);
index 2eb67c344256cced8e07eba055998c1ad02f0088..e9e6408db41c3cbcbe8ddd4448668287f176fb80 100644 (file)
@@ -324,6 +324,11 @@ EXPORT_SYMBOL(xfrm_policy_walk);
 EXPORT_SYMBOL(xfrm_policy_flush);
 EXPORT_SYMBOL(xfrm_policy_byid);
 EXPORT_SYMBOL(xfrm_policy_list);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+EXPORT_SYMBOL(xfrm6_state_lookup);
+EXPORT_SYMBOL(xfrm6_find_acq);
+EXPORT_SYMBOL(xfrm6_alloc_spi);
+#endif
 
 EXPORT_SYMBOL_GPL(xfrm_probe_algs);
 EXPORT_SYMBOL_GPL(xfrm_count_auth_supported);