1 /* 2 * xfrm6_policy.c: based on xfrm4_policy.c 3 * 4 * Authors: 5 * Mitsuru KANDA @USAGI 6 * Kazunori MIYAZAWA @USAGI 7 * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 8 * IPv6 support 9 * YOSHIFUJI Hideaki 10 * Split up af-specific portion 11 * 12 */ 13 14 #include <linux/compiler.h> 15 #include <linux/netdevice.h> 16 #include <net/addrconf.h> 17 #include <net/xfrm.h> 18 #include <net/ip.h> 19 #include <net/ipv6.h> 20 #include <net/ip6_route.h> 21 22 static struct dst_ops xfrm6_dst_ops; 23 static struct xfrm_policy_afinfo xfrm6_policy_afinfo; 24 25 static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl) 26 { 27 int err = 0; 28 *dst = (struct xfrm_dst*)ip6_route_output(NULL, fl); 29 if (!*dst) 30 err = -ENETUNREACH; 31 return err; 32 } 33 34 static struct dst_entry * 35 __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) 36 { 37 struct dst_entry *dst; 38 39 /* Still not clear if we should set fl->fl6_{src,dst}... */ 40 read_lock_bh(&policy->lock); 41 for (dst = policy->bundles; dst; dst = dst->next) { 42 struct xfrm_dst *xdst = (struct xfrm_dst*)dst; 43 struct in6_addr fl_dst_prefix, fl_src_prefix; 44 45 ipv6_addr_prefix(&fl_dst_prefix, 46 &fl->fl6_dst, 47 xdst->u.rt6.rt6i_dst.plen); 48 ipv6_addr_prefix(&fl_src_prefix, 49 &fl->fl6_src, 50 xdst->u.rt6.rt6i_src.plen); 51 if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && 52 ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && 53 xfrm_bundle_ok(xdst, fl, AF_INET6)) { 54 dst_clone(dst); 55 break; 56 } 57 } 58 read_unlock_bh(&policy->lock); 59 return dst; 60 } 61 62 /* Allocate chain of dst_entry's, attach known xfrm's, calculate 63 * all the metrics... Shortly, bundle a bundle. 64 */ 65 66 static int 67 __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx, 68 struct flowi *fl, struct dst_entry **dst_p) 69 { 70 struct dst_entry *dst, *dst_prev; 71 struct rt6_info *rt0 = (struct rt6_info*)(*dst_p); 72 struct rt6_info *rt = rt0; 73 struct in6_addr *remote = &fl->fl6_dst; 74 struct in6_addr *local = &fl->fl6_src; 75 struct flowi fl_tunnel = { 76 .nl_u = { 77 .ip6_u = { 78 .saddr = *local, 79 .daddr = *remote 80 } 81 } 82 }; 83 int i; 84 int err = 0; 85 int header_len = 0; 86 int trailer_len = 0; 87 88 dst = dst_prev = NULL; 89 dst_hold(&rt->u.dst); 90 91 for (i = 0; i < nx; i++) { 92 struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops); 93 struct xfrm_dst *xdst; 94 int tunnel = 0; 95 96 if (unlikely(dst1 == NULL)) { 97 err = -ENOBUFS; 98 dst_release(&rt->u.dst); 99 goto error; 100 } 101 102 if (!dst) 103 dst = dst1; 104 else { 105 dst_prev->child = dst1; 106 dst1->flags |= DST_NOHASH; 107 dst_clone(dst1); 108 } 109 110 xdst = (struct xfrm_dst *)dst1; 111 xdst->route = &rt->u.dst; 112 if (rt->rt6i_node) 113 xdst->route_cookie = rt->rt6i_node->fn_sernum; 114 115 dst1->next = dst_prev; 116 dst_prev = dst1; 117 if (xfrm[i]->props.mode) { 118 remote = (struct in6_addr*)&xfrm[i]->id.daddr; 119 local = (struct in6_addr*)&xfrm[i]->props.saddr; 120 tunnel = 1; 121 } 122 header_len += xfrm[i]->props.header_len; 123 trailer_len += xfrm[i]->props.trailer_len; 124 125 if (tunnel) { 126 ipv6_addr_copy(&fl_tunnel.fl6_dst, remote); 127 ipv6_addr_copy(&fl_tunnel.fl6_src, local); 128 err = xfrm_dst_lookup((struct xfrm_dst **) &rt, 129 &fl_tunnel, AF_INET6); 130 if (err) 131 goto error; 132 } else 133 dst_hold(&rt->u.dst); 134 } 135 136 dst_prev->child = &rt->u.dst; 137 dst->path = &rt->u.dst; 138 if (rt->rt6i_node) 139 ((struct xfrm_dst *)dst)->path_cookie = rt->rt6i_node->fn_sernum; 140 141 *dst_p = dst; 142 dst = dst_prev; 143 144 dst_prev = *dst_p; 145 i = 0; 146 for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { 147 struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; 148 149 dst_prev->xfrm = xfrm[i++]; 150 dst_prev->dev = rt->u.dst.dev; 151 if (rt->u.dst.dev) 152 dev_hold(rt->u.dst.dev); 153 dst_prev->obsolete = -1; 154 dst_prev->flags |= DST_HOST; 155 dst_prev->lastuse = jiffies; 156 dst_prev->header_len = header_len; 157 dst_prev->trailer_len = trailer_len; 158 memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics)); 159 160 /* Copy neighbour for reachability confirmation */ 161 dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); 162 dst_prev->input = rt->u.dst.input; 163 dst_prev->output = xfrm6_output; 164 /* Sheit... I remember I did this right. Apparently, 165 * it was magically lost, so this code needs audit */ 166 x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL); 167 x->u.rt6.rt6i_metric = rt0->rt6i_metric; 168 x->u.rt6.rt6i_node = rt0->rt6i_node; 169 x->u.rt6.rt6i_gateway = rt0->rt6i_gateway; 170 memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway)); 171 x->u.rt6.rt6i_dst = rt0->rt6i_dst; 172 x->u.rt6.rt6i_src = rt0->rt6i_src; 173 x->u.rt6.rt6i_idev = rt0->rt6i_idev; 174 in6_dev_hold(rt0->rt6i_idev); 175 header_len -= x->u.dst.xfrm->props.header_len; 176 trailer_len -= x->u.dst.xfrm->props.trailer_len; 177 } 178 179 xfrm_init_pmtu(dst); 180 return 0; 181 182 error: 183 if (dst) 184 dst_free(dst); 185 return err; 186 } 187 188 static inline void 189 _decode_session6(struct sk_buff *skb, struct flowi *fl) 190 { 191 u16 offset = skb->h.raw - skb->nh.raw; 192 struct ipv6hdr *hdr = skb->nh.ipv6h; 193 struct ipv6_opt_hdr *exthdr; 194 u8 nexthdr = skb->nh.raw[IP6CB(skb)->nhoff]; 195 196 memset(fl, 0, sizeof(struct flowi)); 197 ipv6_addr_copy(&fl->fl6_dst, &hdr->daddr); 198 ipv6_addr_copy(&fl->fl6_src, &hdr->saddr); 199 200 while (pskb_may_pull(skb, skb->nh.raw + offset + 1 - skb->data)) { 201 exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); 202 203 switch (nexthdr) { 204 case NEXTHDR_ROUTING: 205 case NEXTHDR_HOP: 206 case NEXTHDR_DEST: 207 offset += ipv6_optlen(exthdr); 208 nexthdr = exthdr->nexthdr; 209 exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); 210 break; 211 212 case IPPROTO_UDP: 213 case IPPROTO_TCP: 214 case IPPROTO_SCTP: 215 case IPPROTO_DCCP: 216 if (pskb_may_pull(skb, skb->nh.raw + offset + 4 - skb->data)) { 217 u16 *ports = (u16 *)exthdr; 218 219 fl->fl_ip_sport = ports[0]; 220 fl->fl_ip_dport = ports[1]; 221 } 222 fl->proto = nexthdr; 223 return; 224 225 case IPPROTO_ICMPV6: 226 if (pskb_may_pull(skb, skb->nh.raw + offset + 2 - skb->data)) { 227 u8 *icmp = (u8 *)exthdr; 228 229 fl->fl_icmp_type = icmp[0]; 230 fl->fl_icmp_code = icmp[1]; 231 } 232 fl->proto = nexthdr; 233 return; 234 235 /* XXX Why are there these headers? */ 236 case IPPROTO_AH: 237 case IPPROTO_ESP: 238 case IPPROTO_COMP: 239 default: 240 fl->fl_ipsec_spi = 0; 241 fl->proto = nexthdr; 242 return; 243 }; 244 } 245 } 246 247 static inline int xfrm6_garbage_collect(void) 248 { 249 xfrm6_policy_afinfo.garbage_collect(); 250 return (atomic_read(&xfrm6_dst_ops.entries) > xfrm6_dst_ops.gc_thresh*2); 251 } 252 253 static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) 254 { 255 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 256 struct dst_entry *path = xdst->route; 257 258 path->ops->update_pmtu(path, mtu); 259 } 260 261 static void xfrm6_dst_destroy(struct dst_entry *dst) 262 { 263 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 264 265 if (likely(xdst->u.rt6.rt6i_idev)) 266 in6_dev_put(xdst->u.rt6.rt6i_idev); 267 xfrm_dst_destroy(xdst); 268 } 269 270 static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, 271 int unregister) 272 { 273 struct xfrm_dst *xdst; 274 275 if (!unregister) 276 return; 277 278 xdst = (struct xfrm_dst *)dst; 279 if (xdst->u.rt6.rt6i_idev->dev == dev) { 280 struct inet6_dev *loopback_idev = in6_dev_get(&loopback_dev); 281 BUG_ON(!loopback_idev); 282 283 do { 284 in6_dev_put(xdst->u.rt6.rt6i_idev); 285 xdst->u.rt6.rt6i_idev = loopback_idev; 286 in6_dev_hold(loopback_idev); 287 xdst = (struct xfrm_dst *)xdst->u.dst.child; 288 } while (xdst->u.dst.xfrm); 289 290 __in6_dev_put(loopback_idev); 291 } 292 293 xfrm_dst_ifdown(dst, dev); 294 } 295 296 static struct dst_ops xfrm6_dst_ops = { 297 .family = AF_INET6, 298 .protocol = __constant_htons(ETH_P_IPV6), 299 .gc = xfrm6_garbage_collect, 300 .update_pmtu = xfrm6_update_pmtu, 301 .destroy = xfrm6_dst_destroy, 302 .ifdown = xfrm6_dst_ifdown, 303 .gc_thresh = 1024, 304 .entry_size = sizeof(struct xfrm_dst), 305 }; 306 307 static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { 308 .family = AF_INET6, 309 .dst_ops = &xfrm6_dst_ops, 310 .dst_lookup = xfrm6_dst_lookup, 311 .find_bundle = __xfrm6_find_bundle, 312 .bundle_create = __xfrm6_bundle_create, 313 .decode_session = _decode_session6, 314 }; 315 316 static void __init xfrm6_policy_init(void) 317 { 318 xfrm_policy_register_afinfo(&xfrm6_policy_afinfo); 319 } 320 321 static void xfrm6_policy_fini(void) 322 { 323 xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo); 324 } 325 326 void __init xfrm6_init(void) 327 { 328 xfrm6_policy_init(); 329 xfrm6_state_init(); 330 } 331 332 void xfrm6_fini(void) 333 { 334 //xfrm6_input_fini(); 335 xfrm6_policy_fini(); 336 xfrm6_state_fini(); 337 } 338