[IPSEC]: Add AF_KEY interface for encapsulation family.
Miika Komu [Fri, 1 Dec 2006 00:41:50 +0000 (16:41 -0800)]
Signed-off-by: Miika Komu <miika@iki.fi>
Signed-off-by: Diego Beltrami <Diego.Beltrami@hiit.fi>
Signed-off-by: Kazunori Miyazawa <miyazawa@linux-ipv6.org>

net/key/af_key.c

index 4e18309..0e1dbfb 100644 (file)
@@ -1767,11 +1767,11 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
 
        /* addresses present only in tunnel mode */
        if (t->mode == XFRM_MODE_TUNNEL) {
-               switch (xp->family) {
+               struct sockaddr *sa;
+               sa = (struct sockaddr *)(rq+1);
+               switch(sa->sa_family) {
                case AF_INET:
-                       sin = (void*)(rq+1);
-                       if (sin->sin_family != AF_INET)
-                               return -EINVAL;
+                       sin = (struct sockaddr_in*)sa;
                        t->saddr.a4 = sin->sin_addr.s_addr;
                        sin++;
                        if (sin->sin_family != AF_INET)
@@ -1780,9 +1780,7 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
                        break;
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
                case AF_INET6:
-                       sin6 = (void *)(rq+1);
-                       if (sin6->sin6_family != AF_INET6)
-                               return -EINVAL;
+                       sin6 = (struct sockaddr_in6*)sa;
                        memcpy(t->saddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr));
                        sin6++;
                        if (sin6->sin6_family != AF_INET6)
@@ -1793,7 +1791,10 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
                default:
                        return -EINVAL;
                }
-       }
+               t->encap_family = sa->sa_family;
+       } else
+               t->encap_family = xp->family;
+
        /* No way to set this via kame pfkey */
        t->aalgos = t->ealgos = t->calgos = ~0;
        xp->xfrm_nr++;
@@ -1830,18 +1831,25 @@ static inline int pfkey_xfrm_policy2sec_ctx_size(struct xfrm_policy *xp)
 
 static int pfkey_xfrm_policy2msg_size(struct xfrm_policy *xp)
 {
+       struct xfrm_tmpl *t;
        int sockaddr_size = pfkey_sockaddr_size(xp->family);
-       int socklen = (xp->family == AF_INET ?
-                      sizeof(struct sockaddr_in) :
-                      sizeof(struct sockaddr_in6));
+       int socklen = 0;
+       int i;
+
+       for (i=0; i<xp->xfrm_nr; i++) {
+               t = xp->xfrm_vec + i;
+               socklen += (t->encap_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) + 
                (sockaddr_size * 2) +
                sizeof(struct sadb_x_policy) +
-               (xp->xfrm_nr * (sizeof(struct sadb_x_ipsecrequest) +
-                               (socklen * 2))) +
+               (xp->xfrm_nr * sizeof(struct sadb_x_ipsecrequest)) +
+               (socklen * 2) +
                pfkey_xfrm_policy2sec_ctx_size(xp);
 }
 
@@ -1999,7 +2007,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 == XFRM_MODE_TUNNEL)
-                       req_size += 2*socklen;
+                       req_size += ((t->encap_family == AF_INET ?
+                                    sizeof(struct sockaddr_in) :
+                                    sizeof(struct sockaddr_in6)) * 2);
                else
                        size -= 2*socklen;
                rq = (void*)skb_put(skb, req_size);
@@ -2015,7 +2025,7 @@ 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 == XFRM_MODE_TUNNEL) {
-                       switch (xp->family) {
+                       switch (t->encap_family) {
                        case AF_INET:
                                sin = (void*)(rq+1);
                                sin->sin_family = AF_INET;