diff options
-rw-r--r-- | include/net/xfrm.h | 20 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 16 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 38 |
3 files changed, 72 insertions, 2 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 4655ca25f808..d341603e4ba8 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -254,6 +254,8 @@ struct xfrm_state_afinfo { | |||
254 | struct xfrm_state *(*find_acq)(u8 mode, u32 reqid, u8 proto, | 254 | struct xfrm_state *(*find_acq)(u8 mode, u32 reqid, u8 proto, |
255 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 255 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
256 | int create); | 256 | int create); |
257 | int (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n); | ||
258 | int (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n); | ||
257 | }; | 259 | }; |
258 | 260 | ||
259 | extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); | 261 | extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); |
@@ -1002,6 +1004,24 @@ extern int xfrm_state_add(struct xfrm_state *x); | |||
1002 | extern int xfrm_state_update(struct xfrm_state *x); | 1004 | extern int xfrm_state_update(struct xfrm_state *x); |
1003 | extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family); | 1005 | extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family); |
1004 | extern struct xfrm_state *xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family); | 1006 | extern struct xfrm_state *xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family); |
1007 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1008 | extern int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, | ||
1009 | int n, unsigned short family); | ||
1010 | extern int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, | ||
1011 | int n, unsigned short family); | ||
1012 | #else | ||
1013 | static inline int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, | ||
1014 | int n, unsigned short family) | ||
1015 | { | ||
1016 | return -ENOSYS; | ||
1017 | } | ||
1018 | |||
1019 | static inline int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, | ||
1020 | int n, unsigned short family) | ||
1021 | { | ||
1022 | return -ENOSYS; | ||
1023 | } | ||
1024 | #endif | ||
1005 | extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); | 1025 | extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); |
1006 | extern int xfrm_state_delete(struct xfrm_state *x); | 1026 | extern int xfrm_state_delete(struct xfrm_state *x); |
1007 | extern void xfrm_state_flush(u8 proto); | 1027 | extern void xfrm_state_flush(u8 proto); |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 96de6c76ed57..1732159ffd01 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -861,6 +861,8 @@ xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl, | |||
861 | struct xfrm_state **xfrm, | 861 | struct xfrm_state **xfrm, |
862 | unsigned short family) | 862 | unsigned short family) |
863 | { | 863 | { |
864 | struct xfrm_state *tp[XFRM_MAX_DEPTH]; | ||
865 | struct xfrm_state **tpp = (npols > 1) ? tp : xfrm; | ||
864 | int cnx = 0; | 866 | int cnx = 0; |
865 | int error; | 867 | int error; |
866 | int ret; | 868 | int ret; |
@@ -871,7 +873,8 @@ xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl, | |||
871 | error = -ENOBUFS; | 873 | error = -ENOBUFS; |
872 | goto fail; | 874 | goto fail; |
873 | } | 875 | } |
874 | ret = xfrm_tmpl_resolve_one(pols[i], fl, &xfrm[cnx], family); | 876 | |
877 | ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family); | ||
875 | if (ret < 0) { | 878 | if (ret < 0) { |
876 | error = ret; | 879 | error = ret; |
877 | goto fail; | 880 | goto fail; |
@@ -879,11 +882,15 @@ xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl, | |||
879 | cnx += ret; | 882 | cnx += ret; |
880 | } | 883 | } |
881 | 884 | ||
885 | /* found states are sorted for outbound processing */ | ||
886 | if (npols > 1) | ||
887 | xfrm_state_sort(xfrm, tpp, cnx, family); | ||
888 | |||
882 | return cnx; | 889 | return cnx; |
883 | 890 | ||
884 | fail: | 891 | fail: |
885 | for (cnx--; cnx>=0; cnx--) | 892 | for (cnx--; cnx>=0; cnx--) |
886 | xfrm_state_put(xfrm[cnx]); | 893 | xfrm_state_put(tpp[cnx]); |
887 | return error; | 894 | return error; |
888 | 895 | ||
889 | } | 896 | } |
@@ -1280,6 +1287,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1280 | struct sec_path *sp; | 1287 | struct sec_path *sp; |
1281 | static struct sec_path dummy; | 1288 | static struct sec_path dummy; |
1282 | struct xfrm_tmpl *tp[XFRM_MAX_DEPTH]; | 1289 | struct xfrm_tmpl *tp[XFRM_MAX_DEPTH]; |
1290 | struct xfrm_tmpl *stp[XFRM_MAX_DEPTH]; | ||
1283 | struct xfrm_tmpl **tpp = tp; | 1291 | struct xfrm_tmpl **tpp = tp; |
1284 | int ti = 0; | 1292 | int ti = 0; |
1285 | int i, k; | 1293 | int i, k; |
@@ -1297,6 +1305,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1297 | tpp[ti++] = &pols[pi]->xfrm_vec[i]; | 1305 | tpp[ti++] = &pols[pi]->xfrm_vec[i]; |
1298 | } | 1306 | } |
1299 | xfrm_nr = ti; | 1307 | xfrm_nr = ti; |
1308 | if (npols > 1) { | ||
1309 | xfrm_tmpl_sort(stp, tpp, xfrm_nr, family); | ||
1310 | tpp = stp; | ||
1311 | } | ||
1300 | 1312 | ||
1301 | /* For each tunnel xfrm, find the first matching tmpl. | 1313 | /* For each tunnel xfrm, find the first matching tmpl. |
1302 | * For each tmpl before that, find corresponding xfrm. | 1314 | * For each tmpl before that, find corresponding xfrm. |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index a26ef6952c30..622e92a08d0b 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -728,6 +728,44 @@ xfrm_find_acq(u8 mode, u32 reqid, u8 proto, | |||
728 | } | 728 | } |
729 | EXPORT_SYMBOL(xfrm_find_acq); | 729 | EXPORT_SYMBOL(xfrm_find_acq); |
730 | 730 | ||
731 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
732 | int | ||
733 | xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, | ||
734 | unsigned short family) | ||
735 | { | ||
736 | int err = 0; | ||
737 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); | ||
738 | if (!afinfo) | ||
739 | return -EAFNOSUPPORT; | ||
740 | |||
741 | spin_lock_bh(&xfrm_state_lock); | ||
742 | if (afinfo->tmpl_sort) | ||
743 | err = afinfo->tmpl_sort(dst, src, n); | ||
744 | spin_unlock_bh(&xfrm_state_lock); | ||
745 | xfrm_state_put_afinfo(afinfo); | ||
746 | return err; | ||
747 | } | ||
748 | EXPORT_SYMBOL(xfrm_tmpl_sort); | ||
749 | |||
750 | int | ||
751 | xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, | ||
752 | unsigned short family) | ||
753 | { | ||
754 | int err = 0; | ||
755 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); | ||
756 | if (!afinfo) | ||
757 | return -EAFNOSUPPORT; | ||
758 | |||
759 | spin_lock_bh(&xfrm_state_lock); | ||
760 | if (afinfo->state_sort) | ||
761 | err = afinfo->state_sort(dst, src, n); | ||
762 | spin_unlock_bh(&xfrm_state_lock); | ||
763 | xfrm_state_put_afinfo(afinfo); | ||
764 | return err; | ||
765 | } | ||
766 | EXPORT_SYMBOL(xfrm_state_sort); | ||
767 | #endif | ||
768 | |||
731 | /* Silly enough, but I'm lazy to build resolution list */ | 769 | /* Silly enough, but I'm lazy to build resolution list */ |
732 | 770 | ||
733 | static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq) | 771 | static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq) |