diff options
-rw-r--r-- | net/key/af_key.c | 40 |
1 files changed, 25 insertions, 15 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c index 4e1830999482..0e1dbfbb9b10 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -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; |