aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
authorMasahide NAKAMURA <nakam@linux-ipv6.org>2006-08-23 23:41:00 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 18:08:29 -0400
commitdf0ba92a99ca757039dfa84a929281ea3f7a50e8 (patch)
tree26f1f562c513ad43f813dcf2c58d426a3649625b /net/xfrm
parent2ce4272a699c731b9736d76126dc742353e381db (diff)
[XFRM]: Trace which secpath state is reject factor.
For Mobile IPv6 usage, it is required to trace which secpath state is reject factor in order to notify it to user space (to know the address which cannot be used route optimized communication). Based on MIPL2 kernel patch. This patch was also written by: Henrik Petander <petander@tcs.hut.fi> Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_policy.c55
1 files changed, 48 insertions, 7 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index ad2a5cba1f5b..d125a2649037 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -988,6 +988,23 @@ error:
988} 988}
989EXPORT_SYMBOL(xfrm_lookup); 989EXPORT_SYMBOL(xfrm_lookup);
990 990
991static inline int
992xfrm_secpath_reject(int idx, struct sk_buff *skb, struct flowi *fl)
993{
994 struct xfrm_state *x;
995 int err;
996
997 if (!skb->sp || idx < 0 || idx >= skb->sp->len)
998 return 0;
999 x = skb->sp->xvec[idx];
1000 if (!x->type->reject)
1001 return 0;
1002 xfrm_state_hold(x);
1003 err = x->type->reject(x, skb, fl);
1004 xfrm_state_put(x);
1005 return err;
1006}
1007
991/* When skb is transformed back to its "native" form, we have to 1008/* When skb is transformed back to its "native" form, we have to
992 * check policy restrictions. At the moment we make this in maximally 1009 * check policy restrictions. At the moment we make this in maximally
993 * stupid way. Shame on me. :-) Of course, connected sockets must 1010 * stupid way. Shame on me. :-) Of course, connected sockets must
@@ -1010,6 +1027,13 @@ xfrm_state_ok(struct xfrm_tmpl *tmpl, struct xfrm_state *x,
1010 xfrm_state_addr_cmp(tmpl, x, family)); 1027 xfrm_state_addr_cmp(tmpl, x, family));
1011} 1028}
1012 1029
1030/*
1031 * 0 or more than 0 is returned when validation is succeeded (either bypass
1032 * because of optional transport mode, or next index of the mathced secpath
1033 * state with the template.
1034 * -1 is returned when no matching template is found.
1035 * Otherwise "-2 - errored_index" is returned.
1036 */
1013static inline int 1037static inline int
1014xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, 1038xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start,
1015 unsigned short family) 1039 unsigned short family)
@@ -1024,8 +1048,11 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start,
1024 for (; idx < sp->len; idx++) { 1048 for (; idx < sp->len; idx++) {
1025 if (xfrm_state_ok(tmpl, sp->xvec[idx], family)) 1049 if (xfrm_state_ok(tmpl, sp->xvec[idx], family))
1026 return ++idx; 1050 return ++idx;
1027 if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) 1051 if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) {
1052 if (start == -1)
1053 start = -2-idx;
1028 break; 1054 break;
1055 }
1029 } 1056 }
1030 return start; 1057 return start;
1031} 1058}
@@ -1046,11 +1073,14 @@ xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family
1046} 1073}
1047EXPORT_SYMBOL(xfrm_decode_session); 1074EXPORT_SYMBOL(xfrm_decode_session);
1048 1075
1049static inline int secpath_has_nontransport(struct sec_path *sp, int k) 1076static inline int secpath_has_nontransport(struct sec_path *sp, int k, int *idxp)
1050{ 1077{
1051 for (; k < sp->len; k++) { 1078 for (; k < sp->len; k++) {
1052 if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) 1079 if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) {
1080 if (idxp)
1081 *idxp = k;
1053 return 1; 1082 return 1;
1083 }
1054 } 1084 }
1055 1085
1056 return 0; 1086 return 0;
@@ -1062,6 +1092,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
1062 struct xfrm_policy *pol; 1092 struct xfrm_policy *pol;
1063 struct flowi fl; 1093 struct flowi fl;
1064 u8 fl_dir = policy_to_flow_dir(dir); 1094 u8 fl_dir = policy_to_flow_dir(dir);
1095 int xerr_idx = -1;
1096 int *xerr_idxp = &xerr_idx;
1065 1097
1066 if (xfrm_decode_session(skb, &fl, family) < 0) 1098 if (xfrm_decode_session(skb, &fl, family) < 0)
1067 return 0; 1099 return 0;
@@ -1086,8 +1118,13 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
1086 pol = flow_cache_lookup(&fl, family, fl_dir, 1118 pol = flow_cache_lookup(&fl, family, fl_dir,
1087 xfrm_policy_lookup); 1119 xfrm_policy_lookup);
1088 1120
1089 if (!pol) 1121 if (!pol) {
1090 return !skb->sp || !secpath_has_nontransport(skb->sp, 0); 1122 if (skb->sp && secpath_has_nontransport(skb->sp, 0, xerr_idxp)) {
1123 xfrm_secpath_reject(xerr_idx, skb, &fl);
1124 return 0;
1125 }
1126 return 1;
1127 }
1091 1128
1092 pol->curlft.use_time = (unsigned long)xtime.tv_sec; 1129 pol->curlft.use_time = (unsigned long)xtime.tv_sec;
1093 1130
@@ -1107,11 +1144,14 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
1107 */ 1144 */
1108 for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) { 1145 for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) {
1109 k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family); 1146 k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family);
1110 if (k < 0) 1147 if (k < 0) {
1148 if (k < -1 && xerr_idxp)
1149 *xerr_idxp = -(2+k);
1111 goto reject; 1150 goto reject;
1151 }
1112 } 1152 }
1113 1153
1114 if (secpath_has_nontransport(sp, k)) 1154 if (secpath_has_nontransport(sp, k, xerr_idxp))
1115 goto reject; 1155 goto reject;
1116 1156
1117 xfrm_pol_put(pol); 1157 xfrm_pol_put(pol);
@@ -1119,6 +1159,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
1119 } 1159 }
1120 1160
1121reject: 1161reject:
1162 xfrm_secpath_reject(xerr_idx, skb, &fl);
1122 xfrm_pol_put(pol); 1163 xfrm_pol_put(pol);
1123 return 0; 1164 return 0;
1124} 1165}