RFC 4301 requires us to associate each SPD entry with a set of flags to
determine how to assign the selector values when creating a new SAD entry.

Each selector in the new xfrm_state can either be assigned using the
corresponding selector in the xfrm_policy or with the corresponding value
in the flowi.  Prior to this patch, the fields in the flowi were always
used.

Signed-off-by: Tyler Hicks <[EMAIL PROTECTED]>

diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index b58adc5..ce6b1b5 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -362,6 +362,11 @@ struct xfrm_userpolicy_info {
 #define XFRM_POLICY_BLOCK      1
        __u8                            flags;
 #define XFRM_POLICY_LOCALOK    1       /* Allow user to override global policy 
*/
+#define XFRM_POLICY_PFP_SADDR  2
+#define XFRM_POLICY_PFP_DADDR  4
+#define XFRM_POLICY_PFP_PROTO  8
+#define XFRM_POLICY_PFP_SPORT  16
+#define XFRM_POLICY_PFP_DPORT  32
        __u8                            share;
 };
 
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 58dfa82..5a039a2 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -261,9 +261,12 @@ struct xfrm_state_afinfo {
        struct xfrm_type        *type_map[IPPROTO_MAX];
        struct xfrm_mode        *mode_map[XFRM_MODE_MAX];
        int                     (*init_flags)(struct xfrm_state *x);
-       void                    (*init_tempsel)(struct xfrm_state *x, struct 
flowi *fl,
+       void                    (*init_tempsel)(struct xfrm_state *x,
+                                               struct flowi *fl,
                                                struct xfrm_tmpl *tmpl,
-                                               xfrm_address_t *daddr, 
xfrm_address_t *saddr);
+                                               struct xfrm_policy *pol,
+                                               xfrm_address_t *daddr,
+                                               xfrm_address_t *saddr);
        int                     (*tmpl_sort)(struct xfrm_tmpl **dst, struct 
xfrm_tmpl **src, int n);
        int                     (*state_sort)(struct xfrm_state **dst, struct 
xfrm_state **src, int n);
        int                     (*output)(struct sk_buff *skb);
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 13d54a1..0fb1092 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -23,18 +23,39 @@ static int xfrm4_init_flags(struct xfrm_state *x)
 
 static void
 __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl,
-                    struct xfrm_tmpl *tmpl,
+                    struct xfrm_tmpl *tmpl, struct xfrm_policy *pol,
                     xfrm_address_t *daddr, xfrm_address_t *saddr)
 {
-       x->sel.daddr.a4 = fl->fl4_dst;
-       x->sel.saddr.a4 = fl->fl4_src;
-       x->sel.dport = xfrm_flowi_dport(fl);
-       x->sel.dport_mask = htons(0xffff);
-       x->sel.sport = xfrm_flowi_sport(fl);
-       x->sel.sport_mask = htons(0xffff);
-       x->sel.prefixlen_d = 32;
-       x->sel.prefixlen_s = 32;
-       x->sel.proto = fl->proto;
+       if (pol->flags & XFRM_POLICY_PFP_DADDR) {
+               x->sel.daddr.a4 = fl->fl4_dst;
+               x->sel.prefixlen_d = 32;
+       } else {
+               x->sel.daddr.a4 = pol->selector.daddr.a4;
+               x->sel.prefixlen_d = pol->selector.prefixlen_d;
+       }
+       if (pol->flags & XFRM_POLICY_PFP_SADDR) {
+               x->sel.saddr.a4 = fl->fl4_src;
+               x->sel.prefixlen_s = 32;
+       } else {
+               x->sel.saddr.a4 = pol->selector.saddr.a4;
+               x->sel.prefixlen_s = pol->selector.prefixlen_s;
+       }
+       if (pol->flags & XFRM_POLICY_PFP_DPORT) {
+               x->sel.dport = xfrm_flowi_dport(fl);
+               x->sel.dport_mask = htons(0xffff);
+       } else {
+               x->sel.dport = pol->selector.dport;
+               x->sel.dport_mask = pol->selector.dport_mask;
+       }
+       if (pol->flags & XFRM_POLICY_PFP_SPORT) {
+               x->sel.sport = xfrm_flowi_sport(fl);
+               x->sel.sport_mask = htons(0xffff);
+       } else {
+               x->sel.sport = pol->selector.sport;
+               x->sel.sport = pol->selector.sport_mask;
+       }
+       x->sel.proto = pol->flags & XFRM_POLICY_PFP_PROTO ?
+                               fl->proto : pol->selector.proto;
        x->sel.ifindex = fl->oif;
        x->id = tmpl->id;
        if (x->id.daddr.a4 == 0)
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index b392bee..213d92d 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -21,20 +21,43 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo;
 
 static void
 __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl,
-                    struct xfrm_tmpl *tmpl,
+                    struct xfrm_tmpl *tmpl, struct xfrm_policy *pol,
                     xfrm_address_t *daddr, xfrm_address_t *saddr)
 {
        /* Initialize temporary selector matching only
         * to current session. */
-       ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst);
-       ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src);
-       x->sel.dport = xfrm_flowi_dport(fl);
-       x->sel.dport_mask = htons(0xffff);
-       x->sel.sport = xfrm_flowi_sport(fl);
-       x->sel.sport_mask = htons(0xffff);
-       x->sel.prefixlen_d = 128;
-       x->sel.prefixlen_s = 128;
-       x->sel.proto = fl->proto;
+       if (pol->flags & XFRM_POLICY_PFP_DADDR) {
+               ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst);
+               x->sel.prefixlen_d = 128;
+       } else {
+               ipv6_addr_copy((struct in6_addr *)&x->sel.daddr,
+                              (struct in6_addr *)&pol->selector.daddr);
+               x->sel.prefixlen_d = pol->selector.prefixlen_d;
+       }
+       if (pol->flags & XFRM_POLICY_PFP_SADDR) {
+               ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src);
+               x->sel.prefixlen_s = 128;
+       } else {
+               ipv6_addr_copy((struct in6_addr *)&x->sel.saddr,
+                              (struct in6_addr *)&pol->selector.saddr);
+               x->sel.prefixlen_s = pol->selector.prefixlen_s;
+       }
+       if (pol->flags & XFRM_POLICY_PFP_DPORT) {
+               x->sel.dport = xfrm_flowi_dport(fl);
+               x->sel.dport_mask = htons(0xffff);
+       } else {
+               x->sel.dport = pol->selector.dport;
+               x->sel.dport_mask = pol->selector.dport_mask;
+       }
+       if (pol->flags & XFRM_POLICY_PFP_SPORT) {
+               x->sel.sport = xfrm_flowi_sport(fl);
+               x->sel.sport_mask = htons(0xffff);
+       } else {
+               x->sel.sport = pol->selector.sport;
+               x->sel.sport_mask = pol->selector.sport_mask;
+       }
+       x->sel.proto = pol->flags & XFRM_POLICY_PFP_PROTO ?
+                       fl->proto : pol->selector.proto;
        x->sel.ifindex = fl->oif;
        x->id = tmpl->id;
        if (ipv6_addr_any((struct in6_addr*)&x->id.daddr))
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 224b44e..2dab50e 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -654,14 +654,14 @@ EXPORT_SYMBOL(xfrm_sad_getinfo);
 
 static int
 xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
-                 struct xfrm_tmpl *tmpl,
+                 struct xfrm_tmpl *tmpl, struct xfrm_policy *pol,
                  xfrm_address_t *daddr, xfrm_address_t *saddr,
                  unsigned short family)
 {
        struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
        if (!afinfo)
                return -1;
-       afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
+       afinfo->init_tempsel(x, fl, tmpl, pol, daddr, saddr);
        xfrm_state_put_afinfo(afinfo);
        return 0;
 }
@@ -824,7 +824,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t 
*saddr,
                }
                /* Initialize temporary selector matching only
                 * to current session. */
-               xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
+               xfrm_init_tempsel(x, fl, tmpl, pol, daddr, saddr, family);
 
                error = security_xfrm_state_alloc_acquire(x, pol->security, 
fl->secid);
                if (error) {
-- 
1.5.3.4

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to