diff options
Diffstat (limited to 'net/ipv6/xfrm6_input.c')
| -rw-r--r-- | net/ipv6/xfrm6_input.c | 114 |
1 files changed, 111 insertions, 3 deletions
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 0405d74ff910..5c8b7a568800 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c | |||
| @@ -16,10 +16,10 @@ | |||
| 16 | #include <net/ipv6.h> | 16 | #include <net/ipv6.h> |
| 17 | #include <net/xfrm.h> | 17 | #include <net/xfrm.h> |
| 18 | 18 | ||
| 19 | int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) | 19 | int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi) |
| 20 | { | 20 | { |
| 21 | int err; | 21 | int err; |
| 22 | u32 seq; | 22 | __be32 seq; |
| 23 | struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; | 23 | struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; |
| 24 | struct xfrm_state *x; | 24 | struct xfrm_state *x; |
| 25 | int xfrm_nr = 0; | 25 | int xfrm_nr = 0; |
| @@ -72,7 +72,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) | |||
| 72 | if (x->mode->input(x, skb)) | 72 | if (x->mode->input(x, skb)) |
| 73 | goto drop; | 73 | goto drop; |
| 74 | 74 | ||
| 75 | if (x->props.mode) { /* XXX */ | 75 | if (x->props.mode == XFRM_MODE_TUNNEL) { /* XXX */ |
| 76 | decaps = 1; | 76 | decaps = 1; |
| 77 | break; | 77 | break; |
| 78 | } | 78 | } |
| @@ -138,3 +138,111 @@ int xfrm6_rcv(struct sk_buff **pskb) | |||
| 138 | { | 138 | { |
| 139 | return xfrm6_rcv_spi(*pskb, 0); | 139 | return xfrm6_rcv_spi(*pskb, 0); |
| 140 | } | 140 | } |
| 141 | |||
| 142 | int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, | ||
| 143 | xfrm_address_t *saddr, u8 proto) | ||
| 144 | { | ||
| 145 | struct xfrm_state *x = NULL; | ||
| 146 | int wildcard = 0; | ||
| 147 | struct in6_addr any; | ||
| 148 | xfrm_address_t *xany; | ||
| 149 | struct xfrm_state *xfrm_vec_one = NULL; | ||
| 150 | int nh = 0; | ||
| 151 | int i = 0; | ||
| 152 | |||
| 153 | ipv6_addr_set(&any, 0, 0, 0, 0); | ||
| 154 | xany = (xfrm_address_t *)&any; | ||
| 155 | |||
| 156 | for (i = 0; i < 3; i++) { | ||
| 157 | xfrm_address_t *dst, *src; | ||
| 158 | switch (i) { | ||
| 159 | case 0: | ||
| 160 | dst = daddr; | ||
| 161 | src = saddr; | ||
| 162 | break; | ||
| 163 | case 1: | ||
| 164 | /* lookup state with wild-card source address */ | ||
| 165 | wildcard = 1; | ||
| 166 | dst = daddr; | ||
| 167 | src = xany; | ||
| 168 | break; | ||
| 169 | case 2: | ||
| 170 | default: | ||
| 171 | /* lookup state with wild-card addresses */ | ||
| 172 | wildcard = 1; /* XXX */ | ||
| 173 | dst = xany; | ||
| 174 | src = xany; | ||
| 175 | break; | ||
| 176 | } | ||
| 177 | |||
| 178 | x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6); | ||
| 179 | if (!x) | ||
| 180 | continue; | ||
| 181 | |||
| 182 | spin_lock(&x->lock); | ||
| 183 | |||
| 184 | if (wildcard) { | ||
| 185 | if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) { | ||
| 186 | spin_unlock(&x->lock); | ||
| 187 | xfrm_state_put(x); | ||
| 188 | x = NULL; | ||
| 189 | continue; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | if (unlikely(x->km.state != XFRM_STATE_VALID)) { | ||
| 194 | spin_unlock(&x->lock); | ||
| 195 | xfrm_state_put(x); | ||
| 196 | x = NULL; | ||
| 197 | continue; | ||
| 198 | } | ||
| 199 | if (xfrm_state_check_expire(x)) { | ||
| 200 | spin_unlock(&x->lock); | ||
| 201 | xfrm_state_put(x); | ||
| 202 | x = NULL; | ||
| 203 | continue; | ||
| 204 | } | ||
| 205 | |||
| 206 | nh = x->type->input(x, skb); | ||
| 207 | if (nh <= 0) { | ||
| 208 | spin_unlock(&x->lock); | ||
| 209 | xfrm_state_put(x); | ||
| 210 | x = NULL; | ||
| 211 | continue; | ||
| 212 | } | ||
| 213 | |||
| 214 | x->curlft.bytes += skb->len; | ||
| 215 | x->curlft.packets++; | ||
| 216 | |||
| 217 | spin_unlock(&x->lock); | ||
| 218 | |||
| 219 | xfrm_vec_one = x; | ||
| 220 | break; | ||
| 221 | } | ||
| 222 | |||
| 223 | if (!xfrm_vec_one) | ||
| 224 | goto drop; | ||
| 225 | |||
| 226 | /* Allocate new secpath or COW existing one. */ | ||
| 227 | if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { | ||
| 228 | struct sec_path *sp; | ||
| 229 | sp = secpath_dup(skb->sp); | ||
| 230 | if (!sp) | ||
| 231 | goto drop; | ||
| 232 | if (skb->sp) | ||
| 233 | secpath_put(skb->sp); | ||
| 234 | skb->sp = sp; | ||
| 235 | } | ||
| 236 | |||
| 237 | if (1 + skb->sp->len > XFRM_MAX_DEPTH) | ||
| 238 | goto drop; | ||
| 239 | |||
| 240 | skb->sp->xvec[skb->sp->len] = xfrm_vec_one; | ||
| 241 | skb->sp->len ++; | ||
| 242 | |||
| 243 | return 1; | ||
| 244 | drop: | ||
| 245 | if (xfrm_vec_one) | ||
| 246 | xfrm_state_put(xfrm_vec_one); | ||
| 247 | return -1; | ||
| 248 | } | ||
