| .. | .. |
|---|
| 22 | 22 | #include <net/ipv6.h> |
|---|
| 23 | 23 | #include <net/ip6_route.h> |
|---|
| 24 | 24 | #include <net/l3mdev.h> |
|---|
| 25 | | -#if IS_ENABLED(CONFIG_IPV6_MIP6) |
|---|
| 26 | | -#include <net/mip6.h> |
|---|
| 27 | | -#endif |
|---|
| 28 | 25 | |
|---|
| 29 | 26 | static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, |
|---|
| 30 | 27 | const xfrm_address_t *saddr, |
|---|
| .. | .. |
|---|
| 71 | 68 | return 0; |
|---|
| 72 | 69 | } |
|---|
| 73 | 70 | |
|---|
| 74 | | -static int xfrm6_get_tos(const struct flowi *fl) |
|---|
| 75 | | -{ |
|---|
| 76 | | - return 0; |
|---|
| 77 | | -} |
|---|
| 78 | | - |
|---|
| 79 | | -static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst, |
|---|
| 80 | | - int nfheader_len) |
|---|
| 81 | | -{ |
|---|
| 82 | | - if (dst->ops->family == AF_INET6) { |
|---|
| 83 | | - struct rt6_info *rt = (struct rt6_info *)dst; |
|---|
| 84 | | - path->path_cookie = rt6_get_cookie(rt); |
|---|
| 85 | | - } |
|---|
| 86 | | - |
|---|
| 87 | | - path->u.rt6.rt6i_nfheader_len = nfheader_len; |
|---|
| 88 | | - |
|---|
| 89 | | - return 0; |
|---|
| 90 | | -} |
|---|
| 91 | | - |
|---|
| 92 | 71 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
|---|
| 93 | 72 | const struct flowi *fl) |
|---|
| 94 | 73 | { |
|---|
| .. | .. |
|---|
| 116 | 95 | atomic_inc(&dev_net(dev)->ipv6.rt6_stats->fib_rt_uncache); |
|---|
| 117 | 96 | |
|---|
| 118 | 97 | return 0; |
|---|
| 119 | | -} |
|---|
| 120 | | - |
|---|
| 121 | | -static inline void |
|---|
| 122 | | -_decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) |
|---|
| 123 | | -{ |
|---|
| 124 | | - struct flowi6 *fl6 = &fl->u.ip6; |
|---|
| 125 | | - int onlyproto = 0; |
|---|
| 126 | | - const struct ipv6hdr *hdr = ipv6_hdr(skb); |
|---|
| 127 | | - u32 offset = sizeof(*hdr); |
|---|
| 128 | | - struct ipv6_opt_hdr *exthdr; |
|---|
| 129 | | - const unsigned char *nh = skb_network_header(skb); |
|---|
| 130 | | - u16 nhoff = IP6CB(skb)->nhoff; |
|---|
| 131 | | - int oif = 0; |
|---|
| 132 | | - u8 nexthdr; |
|---|
| 133 | | - |
|---|
| 134 | | - if (!nhoff) |
|---|
| 135 | | - nhoff = offsetof(struct ipv6hdr, nexthdr); |
|---|
| 136 | | - |
|---|
| 137 | | - nexthdr = nh[nhoff]; |
|---|
| 138 | | - |
|---|
| 139 | | - if (skb_dst(skb)) |
|---|
| 140 | | - oif = skb_dst(skb)->dev->ifindex; |
|---|
| 141 | | - |
|---|
| 142 | | - memset(fl6, 0, sizeof(struct flowi6)); |
|---|
| 143 | | - fl6->flowi6_mark = skb->mark; |
|---|
| 144 | | - fl6->flowi6_oif = reverse ? skb->skb_iif : oif; |
|---|
| 145 | | - |
|---|
| 146 | | - fl6->daddr = reverse ? hdr->saddr : hdr->daddr; |
|---|
| 147 | | - fl6->saddr = reverse ? hdr->daddr : hdr->saddr; |
|---|
| 148 | | - |
|---|
| 149 | | - while (nh + offset + sizeof(*exthdr) < skb->data || |
|---|
| 150 | | - pskb_may_pull(skb, nh + offset + sizeof(*exthdr) - skb->data)) { |
|---|
| 151 | | - nh = skb_network_header(skb); |
|---|
| 152 | | - exthdr = (struct ipv6_opt_hdr *)(nh + offset); |
|---|
| 153 | | - |
|---|
| 154 | | - switch (nexthdr) { |
|---|
| 155 | | - case NEXTHDR_FRAGMENT: |
|---|
| 156 | | - onlyproto = 1; |
|---|
| 157 | | - /* fall through */ |
|---|
| 158 | | - case NEXTHDR_ROUTING: |
|---|
| 159 | | - case NEXTHDR_HOP: |
|---|
| 160 | | - case NEXTHDR_DEST: |
|---|
| 161 | | - offset += ipv6_optlen(exthdr); |
|---|
| 162 | | - nexthdr = exthdr->nexthdr; |
|---|
| 163 | | - exthdr = (struct ipv6_opt_hdr *)(nh + offset); |
|---|
| 164 | | - break; |
|---|
| 165 | | - |
|---|
| 166 | | - case IPPROTO_UDP: |
|---|
| 167 | | - case IPPROTO_UDPLITE: |
|---|
| 168 | | - case IPPROTO_TCP: |
|---|
| 169 | | - case IPPROTO_SCTP: |
|---|
| 170 | | - case IPPROTO_DCCP: |
|---|
| 171 | | - if (!onlyproto && (nh + offset + 4 < skb->data || |
|---|
| 172 | | - pskb_may_pull(skb, nh + offset + 4 - skb->data))) { |
|---|
| 173 | | - __be16 *ports; |
|---|
| 174 | | - |
|---|
| 175 | | - nh = skb_network_header(skb); |
|---|
| 176 | | - ports = (__be16 *)(nh + offset); |
|---|
| 177 | | - fl6->fl6_sport = ports[!!reverse]; |
|---|
| 178 | | - fl6->fl6_dport = ports[!reverse]; |
|---|
| 179 | | - } |
|---|
| 180 | | - fl6->flowi6_proto = nexthdr; |
|---|
| 181 | | - return; |
|---|
| 182 | | - |
|---|
| 183 | | - case IPPROTO_ICMPV6: |
|---|
| 184 | | - if (!onlyproto && (nh + offset + 2 < skb->data || |
|---|
| 185 | | - pskb_may_pull(skb, nh + offset + 2 - skb->data))) { |
|---|
| 186 | | - u8 *icmp; |
|---|
| 187 | | - |
|---|
| 188 | | - nh = skb_network_header(skb); |
|---|
| 189 | | - icmp = (u8 *)(nh + offset); |
|---|
| 190 | | - fl6->fl6_icmp_type = icmp[0]; |
|---|
| 191 | | - fl6->fl6_icmp_code = icmp[1]; |
|---|
| 192 | | - } |
|---|
| 193 | | - fl6->flowi6_proto = nexthdr; |
|---|
| 194 | | - return; |
|---|
| 195 | | - |
|---|
| 196 | | -#if IS_ENABLED(CONFIG_IPV6_MIP6) |
|---|
| 197 | | - case IPPROTO_MH: |
|---|
| 198 | | - offset += ipv6_optlen(exthdr); |
|---|
| 199 | | - if (!onlyproto && (nh + offset + 3 < skb->data || |
|---|
| 200 | | - pskb_may_pull(skb, nh + offset + 3 - skb->data))) { |
|---|
| 201 | | - struct ip6_mh *mh; |
|---|
| 202 | | - |
|---|
| 203 | | - nh = skb_network_header(skb); |
|---|
| 204 | | - mh = (struct ip6_mh *)(nh + offset); |
|---|
| 205 | | - fl6->fl6_mh_type = mh->ip6mh_type; |
|---|
| 206 | | - } |
|---|
| 207 | | - fl6->flowi6_proto = nexthdr; |
|---|
| 208 | | - return; |
|---|
| 209 | | -#endif |
|---|
| 210 | | - |
|---|
| 211 | | - /* XXX Why are there these headers? */ |
|---|
| 212 | | - case IPPROTO_AH: |
|---|
| 213 | | - case IPPROTO_ESP: |
|---|
| 214 | | - case IPPROTO_COMP: |
|---|
| 215 | | - default: |
|---|
| 216 | | - fl6->fl6_ipsec_spi = 0; |
|---|
| 217 | | - fl6->flowi6_proto = nexthdr; |
|---|
| 218 | | - return; |
|---|
| 219 | | - } |
|---|
| 220 | | - } |
|---|
| 221 | 98 | } |
|---|
| 222 | 99 | |
|---|
| 223 | 100 | static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk, |
|---|
| .. | .. |
|---|
| 263 | 140 | if (xdst->u.rt6.rt6i_idev->dev == dev) { |
|---|
| 264 | 141 | struct inet6_dev *loopback_idev = |
|---|
| 265 | 142 | in6_dev_get(dev_net(dev)->loopback_dev); |
|---|
| 266 | | - BUG_ON(!loopback_idev); |
|---|
| 267 | 143 | |
|---|
| 268 | 144 | do { |
|---|
| 269 | 145 | in6_dev_put(xdst->u.rt6.rt6i_idev); |
|---|
| .. | .. |
|---|
| 293 | 169 | .dst_ops = &xfrm6_dst_ops_template, |
|---|
| 294 | 170 | .dst_lookup = xfrm6_dst_lookup, |
|---|
| 295 | 171 | .get_saddr = xfrm6_get_saddr, |
|---|
| 296 | | - .decode_session = _decode_session6, |
|---|
| 297 | | - .get_tos = xfrm6_get_tos, |
|---|
| 298 | | - .init_path = xfrm6_init_path, |
|---|
| 299 | 172 | .fill_dst = xfrm6_fill_dst, |
|---|
| 300 | 173 | .blackhole_route = ip6_blackhole_route, |
|---|
| 301 | 174 | }; |
|---|
| .. | .. |
|---|
| 416 | 289 | if (ret) |
|---|
| 417 | 290 | goto out_state; |
|---|
| 418 | 291 | |
|---|
| 419 | | - register_pernet_subsys(&xfrm6_net_ops); |
|---|
| 292 | + ret = register_pernet_subsys(&xfrm6_net_ops); |
|---|
| 293 | + if (ret) |
|---|
| 294 | + goto out_protocol; |
|---|
| 420 | 295 | out: |
|---|
| 421 | 296 | return ret; |
|---|
| 297 | +out_protocol: |
|---|
| 298 | + xfrm6_protocol_fini(); |
|---|
| 422 | 299 | out_state: |
|---|
| 423 | 300 | xfrm6_state_fini(); |
|---|
| 424 | 301 | out_policy: |
|---|