diff options
Diffstat (limited to 'net/ipv6/ip6_vti.c')
-rw-r--r-- | net/ipv6/ip6_vti.c | 308 |
1 files changed, 217 insertions, 91 deletions
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 864914399391..b7c0f827140b 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c | |||
@@ -278,7 +278,6 @@ static void vti6_dev_uninit(struct net_device *dev) | |||
278 | RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); | 278 | RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); |
279 | else | 279 | else |
280 | vti6_tnl_unlink(ip6n, t); | 280 | vti6_tnl_unlink(ip6n, t); |
281 | ip6_tnl_dst_reset(t); | ||
282 | dev_put(dev); | 281 | dev_put(dev); |
283 | } | 282 | } |
284 | 283 | ||
@@ -288,11 +287,8 @@ static int vti6_rcv(struct sk_buff *skb) | |||
288 | const struct ipv6hdr *ipv6h = ipv6_hdr(skb); | 287 | const struct ipv6hdr *ipv6h = ipv6_hdr(skb); |
289 | 288 | ||
290 | rcu_read_lock(); | 289 | rcu_read_lock(); |
291 | |||
292 | if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, | 290 | if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, |
293 | &ipv6h->daddr)) != NULL) { | 291 | &ipv6h->daddr)) != NULL) { |
294 | struct pcpu_sw_netstats *tstats; | ||
295 | |||
296 | if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) { | 292 | if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) { |
297 | rcu_read_unlock(); | 293 | rcu_read_unlock(); |
298 | goto discard; | 294 | goto discard; |
@@ -309,27 +305,58 @@ static int vti6_rcv(struct sk_buff *skb) | |||
309 | goto discard; | 305 | goto discard; |
310 | } | 306 | } |
311 | 307 | ||
312 | tstats = this_cpu_ptr(t->dev->tstats); | 308 | XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t; |
313 | u64_stats_update_begin(&tstats->syncp); | 309 | skb->mark = be32_to_cpu(t->parms.i_key); |
314 | tstats->rx_packets++; | ||
315 | tstats->rx_bytes += skb->len; | ||
316 | u64_stats_update_end(&tstats->syncp); | ||
317 | |||
318 | skb->mark = 0; | ||
319 | secpath_reset(skb); | ||
320 | skb->dev = t->dev; | ||
321 | 310 | ||
322 | rcu_read_unlock(); | 311 | rcu_read_unlock(); |
323 | return 0; | 312 | |
313 | return xfrm6_rcv(skb); | ||
324 | } | 314 | } |
325 | rcu_read_unlock(); | 315 | rcu_read_unlock(); |
326 | return 1; | 316 | return -EINVAL; |
327 | |||
328 | discard: | 317 | discard: |
329 | kfree_skb(skb); | 318 | kfree_skb(skb); |
330 | return 0; | 319 | return 0; |
331 | } | 320 | } |
332 | 321 | ||
322 | static int vti6_rcv_cb(struct sk_buff *skb, int err) | ||
323 | { | ||
324 | unsigned short family; | ||
325 | struct net_device *dev; | ||
326 | struct pcpu_sw_netstats *tstats; | ||
327 | struct xfrm_state *x; | ||
328 | struct ip6_tnl *t = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6; | ||
329 | |||
330 | if (!t) | ||
331 | return 1; | ||
332 | |||
333 | dev = t->dev; | ||
334 | |||
335 | if (err) { | ||
336 | dev->stats.rx_errors++; | ||
337 | dev->stats.rx_dropped++; | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | x = xfrm_input_state(skb); | ||
343 | family = x->inner_mode->afinfo->family; | ||
344 | |||
345 | if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family)) | ||
346 | return -EPERM; | ||
347 | |||
348 | skb_scrub_packet(skb, !net_eq(t->net, dev_net(skb->dev))); | ||
349 | skb->dev = dev; | ||
350 | |||
351 | tstats = this_cpu_ptr(dev->tstats); | ||
352 | u64_stats_update_begin(&tstats->syncp); | ||
353 | tstats->rx_packets++; | ||
354 | tstats->rx_bytes += skb->len; | ||
355 | u64_stats_update_end(&tstats->syncp); | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
333 | /** | 360 | /** |
334 | * vti6_addr_conflict - compare packet addresses to tunnel's own | 361 | * vti6_addr_conflict - compare packet addresses to tunnel's own |
335 | * @t: the outgoing tunnel device | 362 | * @t: the outgoing tunnel device |
@@ -349,44 +376,56 @@ vti6_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr) | |||
349 | return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); | 376 | return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); |
350 | } | 377 | } |
351 | 378 | ||
379 | static bool vti6_state_check(const struct xfrm_state *x, | ||
380 | const struct in6_addr *dst, | ||
381 | const struct in6_addr *src) | ||
382 | { | ||
383 | xfrm_address_t *daddr = (xfrm_address_t *)dst; | ||
384 | xfrm_address_t *saddr = (xfrm_address_t *)src; | ||
385 | |||
386 | /* if there is no transform then this tunnel is not functional. | ||
387 | * Or if the xfrm is not mode tunnel. | ||
388 | */ | ||
389 | if (!x || x->props.mode != XFRM_MODE_TUNNEL || | ||
390 | x->props.family != AF_INET6) | ||
391 | return false; | ||
392 | |||
393 | if (ipv6_addr_any(dst)) | ||
394 | return xfrm_addr_equal(saddr, &x->props.saddr, AF_INET6); | ||
395 | |||
396 | if (!xfrm_state_addr_check(x, daddr, saddr, AF_INET6)) | ||
397 | return false; | ||
398 | |||
399 | return true; | ||
400 | } | ||
401 | |||
352 | /** | 402 | /** |
353 | * vti6_xmit - send a packet | 403 | * vti6_xmit - send a packet |
354 | * @skb: the outgoing socket buffer | 404 | * @skb: the outgoing socket buffer |
355 | * @dev: the outgoing tunnel device | 405 | * @dev: the outgoing tunnel device |
406 | * @fl: the flow informations for the xfrm_lookup | ||
356 | **/ | 407 | **/ |
357 | static int vti6_xmit(struct sk_buff *skb, struct net_device *dev) | 408 | static int |
409 | vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) | ||
358 | { | 410 | { |
359 | struct net *net = dev_net(dev); | ||
360 | struct ip6_tnl *t = netdev_priv(dev); | 411 | struct ip6_tnl *t = netdev_priv(dev); |
361 | struct net_device_stats *stats = &t->dev->stats; | 412 | struct net_device_stats *stats = &t->dev->stats; |
362 | struct dst_entry *dst = NULL, *ndst = NULL; | 413 | struct dst_entry *dst = skb_dst(skb); |
363 | struct flowi6 fl6; | ||
364 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); | ||
365 | struct net_device *tdev; | 414 | struct net_device *tdev; |
366 | int err = -1; | 415 | int err = -1; |
367 | 416 | ||
368 | if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) || | 417 | if (!dst) |
369 | !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h)) | 418 | goto tx_err_link_failure; |
370 | return err; | ||
371 | |||
372 | dst = ip6_tnl_dst_check(t); | ||
373 | if (!dst) { | ||
374 | memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); | ||
375 | |||
376 | ndst = ip6_route_output(net, NULL, &fl6); | ||
377 | 419 | ||
378 | if (ndst->error) | 420 | dst_hold(dst); |
379 | goto tx_err_link_failure; | 421 | dst = xfrm_lookup(t->net, dst, fl, NULL, 0); |
380 | ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(&fl6), NULL, 0); | 422 | if (IS_ERR(dst)) { |
381 | if (IS_ERR(ndst)) { | 423 | err = PTR_ERR(dst); |
382 | err = PTR_ERR(ndst); | 424 | dst = NULL; |
383 | ndst = NULL; | 425 | goto tx_err_link_failure; |
384 | goto tx_err_link_failure; | ||
385 | } | ||
386 | dst = ndst; | ||
387 | } | 426 | } |
388 | 427 | ||
389 | if (!dst->xfrm || dst->xfrm->props.mode != XFRM_MODE_TUNNEL) | 428 | if (!vti6_state_check(dst->xfrm, &t->parms.raddr, &t->parms.laddr)) |
390 | goto tx_err_link_failure; | 429 | goto tx_err_link_failure; |
391 | 430 | ||
392 | tdev = dst->dev; | 431 | tdev = dst->dev; |
@@ -398,14 +437,21 @@ static int vti6_xmit(struct sk_buff *skb, struct net_device *dev) | |||
398 | goto tx_err_dst_release; | 437 | goto tx_err_dst_release; |
399 | } | 438 | } |
400 | 439 | ||
440 | skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev))); | ||
441 | skb_dst_set(skb, dst); | ||
442 | skb->dev = skb_dst(skb)->dev; | ||
401 | 443 | ||
402 | skb_dst_drop(skb); | 444 | err = dst_output(skb); |
403 | skb_dst_set_noref(skb, dst); | 445 | if (net_xmit_eval(err) == 0) { |
446 | struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats); | ||
404 | 447 | ||
405 | ip6tunnel_xmit(skb, dev); | 448 | u64_stats_update_begin(&tstats->syncp); |
406 | if (ndst) { | 449 | tstats->tx_bytes += skb->len; |
407 | dev->mtu = dst_mtu(ndst); | 450 | tstats->tx_packets++; |
408 | ip6_tnl_dst_store(t, ndst); | 451 | u64_stats_update_end(&tstats->syncp); |
452 | } else { | ||
453 | stats->tx_errors++; | ||
454 | stats->tx_aborted_errors++; | ||
409 | } | 455 | } |
410 | 456 | ||
411 | return 0; | 457 | return 0; |
@@ -413,7 +459,7 @@ tx_err_link_failure: | |||
413 | stats->tx_carrier_errors++; | 459 | stats->tx_carrier_errors++; |
414 | dst_link_failure(skb); | 460 | dst_link_failure(skb); |
415 | tx_err_dst_release: | 461 | tx_err_dst_release: |
416 | dst_release(ndst); | 462 | dst_release(dst); |
417 | return err; | 463 | return err; |
418 | } | 464 | } |
419 | 465 | ||
@@ -422,16 +468,33 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
422 | { | 468 | { |
423 | struct ip6_tnl *t = netdev_priv(dev); | 469 | struct ip6_tnl *t = netdev_priv(dev); |
424 | struct net_device_stats *stats = &t->dev->stats; | 470 | struct net_device_stats *stats = &t->dev->stats; |
471 | struct ipv6hdr *ipv6h; | ||
472 | struct flowi fl; | ||
425 | int ret; | 473 | int ret; |
426 | 474 | ||
475 | memset(&fl, 0, sizeof(fl)); | ||
476 | skb->mark = be32_to_cpu(t->parms.o_key); | ||
477 | |||
427 | switch (skb->protocol) { | 478 | switch (skb->protocol) { |
428 | case htons(ETH_P_IPV6): | 479 | case htons(ETH_P_IPV6): |
429 | ret = vti6_xmit(skb, dev); | 480 | ipv6h = ipv6_hdr(skb); |
481 | |||
482 | if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) || | ||
483 | !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h)) | ||
484 | goto tx_err; | ||
485 | |||
486 | xfrm_decode_session(skb, &fl, AF_INET6); | ||
487 | memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); | ||
488 | break; | ||
489 | case htons(ETH_P_IP): | ||
490 | xfrm_decode_session(skb, &fl, AF_INET); | ||
491 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); | ||
430 | break; | 492 | break; |
431 | default: | 493 | default: |
432 | goto tx_err; | 494 | goto tx_err; |
433 | } | 495 | } |
434 | 496 | ||
497 | ret = vti6_xmit(skb, dev, &fl); | ||
435 | if (ret < 0) | 498 | if (ret < 0) |
436 | goto tx_err; | 499 | goto tx_err; |
437 | 500 | ||
@@ -444,24 +507,66 @@ tx_err: | |||
444 | return NETDEV_TX_OK; | 507 | return NETDEV_TX_OK; |
445 | } | 508 | } |
446 | 509 | ||
510 | static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | ||
511 | u8 type, u8 code, int offset, __be32 info) | ||
512 | { | ||
513 | __be32 spi; | ||
514 | struct xfrm_state *x; | ||
515 | struct ip6_tnl *t; | ||
516 | struct ip_esp_hdr *esph; | ||
517 | struct ip_auth_hdr *ah; | ||
518 | struct ip_comp_hdr *ipch; | ||
519 | struct net *net = dev_net(skb->dev); | ||
520 | const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data; | ||
521 | int protocol = iph->nexthdr; | ||
522 | |||
523 | t = vti6_tnl_lookup(dev_net(skb->dev), &iph->daddr, &iph->saddr); | ||
524 | if (!t) | ||
525 | return -1; | ||
526 | |||
527 | switch (protocol) { | ||
528 | case IPPROTO_ESP: | ||
529 | esph = (struct ip_esp_hdr *)(skb->data + offset); | ||
530 | spi = esph->spi; | ||
531 | break; | ||
532 | case IPPROTO_AH: | ||
533 | ah = (struct ip_auth_hdr *)(skb->data + offset); | ||
534 | spi = ah->spi; | ||
535 | break; | ||
536 | case IPPROTO_COMP: | ||
537 | ipch = (struct ip_comp_hdr *)(skb->data + offset); | ||
538 | spi = htonl(ntohs(ipch->cpi)); | ||
539 | break; | ||
540 | default: | ||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | if (type != ICMPV6_PKT_TOOBIG && | ||
545 | type != NDISC_REDIRECT) | ||
546 | return 0; | ||
547 | |||
548 | x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, | ||
549 | spi, protocol, AF_INET6); | ||
550 | if (!x) | ||
551 | return 0; | ||
552 | |||
553 | if (type == NDISC_REDIRECT) | ||
554 | ip6_redirect(skb, net, skb->dev->ifindex, 0); | ||
555 | else | ||
556 | ip6_update_pmtu(skb, net, info, 0, 0); | ||
557 | xfrm_state_put(x); | ||
558 | |||
559 | return 0; | ||
560 | } | ||
561 | |||
447 | static void vti6_link_config(struct ip6_tnl *t) | 562 | static void vti6_link_config(struct ip6_tnl *t) |
448 | { | 563 | { |
449 | struct dst_entry *dst; | ||
450 | struct net_device *dev = t->dev; | 564 | struct net_device *dev = t->dev; |
451 | struct __ip6_tnl_parm *p = &t->parms; | 565 | struct __ip6_tnl_parm *p = &t->parms; |
452 | struct flowi6 *fl6 = &t->fl.u.ip6; | ||
453 | 566 | ||
454 | memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); | 567 | memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); |
455 | memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); | 568 | memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); |
456 | 569 | ||
457 | /* Set up flowi template */ | ||
458 | fl6->saddr = p->laddr; | ||
459 | fl6->daddr = p->raddr; | ||
460 | fl6->flowi6_oif = p->link; | ||
461 | fl6->flowi6_mark = be32_to_cpu(p->i_key); | ||
462 | fl6->flowi6_proto = p->proto; | ||
463 | fl6->flowlabel = 0; | ||
464 | |||
465 | p->flags &= ~(IP6_TNL_F_CAP_XMIT | IP6_TNL_F_CAP_RCV | | 570 | p->flags &= ~(IP6_TNL_F_CAP_XMIT | IP6_TNL_F_CAP_RCV | |
466 | IP6_TNL_F_CAP_PER_PACKET); | 571 | IP6_TNL_F_CAP_PER_PACKET); |
467 | p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr); | 572 | p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr); |
@@ -472,28 +577,6 @@ static void vti6_link_config(struct ip6_tnl *t) | |||
472 | dev->flags &= ~IFF_POINTOPOINT; | 577 | dev->flags &= ~IFF_POINTOPOINT; |
473 | 578 | ||
474 | dev->iflink = p->link; | 579 | dev->iflink = p->link; |
475 | |||
476 | if (p->flags & IP6_TNL_F_CAP_XMIT) { | ||
477 | |||
478 | dst = ip6_route_output(dev_net(dev), NULL, fl6); | ||
479 | if (dst->error) | ||
480 | return; | ||
481 | |||
482 | dst = xfrm_lookup(dev_net(dev), dst, flowi6_to_flowi(fl6), | ||
483 | NULL, 0); | ||
484 | if (IS_ERR(dst)) | ||
485 | return; | ||
486 | |||
487 | if (dst->dev) { | ||
488 | dev->hard_header_len = dst->dev->hard_header_len; | ||
489 | |||
490 | dev->mtu = dst_mtu(dst); | ||
491 | |||
492 | if (dev->mtu < IPV6_MIN_MTU) | ||
493 | dev->mtu = IPV6_MIN_MTU; | ||
494 | } | ||
495 | dst_release(dst); | ||
496 | } | ||
497 | } | 580 | } |
498 | 581 | ||
499 | /** | 582 | /** |
@@ -720,7 +803,6 @@ static void vti6_dev_setup(struct net_device *dev) | |||
720 | t = netdev_priv(dev); | 803 | t = netdev_priv(dev); |
721 | dev->flags |= IFF_NOARP; | 804 | dev->flags |= IFF_NOARP; |
722 | dev->addr_len = sizeof(struct in6_addr); | 805 | dev->addr_len = sizeof(struct in6_addr); |
723 | dev->features |= NETIF_F_NETNS_LOCAL; | ||
724 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | 806 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; |
725 | } | 807 | } |
726 | 808 | ||
@@ -908,11 +990,6 @@ static struct rtnl_link_ops vti6_link_ops __read_mostly = { | |||
908 | .fill_info = vti6_fill_info, | 990 | .fill_info = vti6_fill_info, |
909 | }; | 991 | }; |
910 | 992 | ||
911 | static struct xfrm_tunnel_notifier vti6_handler __read_mostly = { | ||
912 | .handler = vti6_rcv, | ||
913 | .priority = 1, | ||
914 | }; | ||
915 | |||
916 | static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n) | 993 | static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n) |
917 | { | 994 | { |
918 | int h; | 995 | int h; |
@@ -984,6 +1061,27 @@ static struct pernet_operations vti6_net_ops = { | |||
984 | .size = sizeof(struct vti6_net), | 1061 | .size = sizeof(struct vti6_net), |
985 | }; | 1062 | }; |
986 | 1063 | ||
1064 | static struct xfrm6_protocol vti_esp6_protocol __read_mostly = { | ||
1065 | .handler = vti6_rcv, | ||
1066 | .cb_handler = vti6_rcv_cb, | ||
1067 | .err_handler = vti6_err, | ||
1068 | .priority = 100, | ||
1069 | }; | ||
1070 | |||
1071 | static struct xfrm6_protocol vti_ah6_protocol __read_mostly = { | ||
1072 | .handler = vti6_rcv, | ||
1073 | .cb_handler = vti6_rcv_cb, | ||
1074 | .err_handler = vti6_err, | ||
1075 | .priority = 100, | ||
1076 | }; | ||
1077 | |||
1078 | static struct xfrm6_protocol vti_ipcomp6_protocol __read_mostly = { | ||
1079 | .handler = vti6_rcv, | ||
1080 | .cb_handler = vti6_rcv_cb, | ||
1081 | .err_handler = vti6_err, | ||
1082 | .priority = 100, | ||
1083 | }; | ||
1084 | |||
987 | /** | 1085 | /** |
988 | * vti6_tunnel_init - register protocol and reserve needed resources | 1086 | * vti6_tunnel_init - register protocol and reserve needed resources |
989 | * | 1087 | * |
@@ -997,11 +1095,33 @@ static int __init vti6_tunnel_init(void) | |||
997 | if (err < 0) | 1095 | if (err < 0) |
998 | goto out_pernet; | 1096 | goto out_pernet; |
999 | 1097 | ||
1000 | err = xfrm6_mode_tunnel_input_register(&vti6_handler); | 1098 | err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP); |
1001 | if (err < 0) { | 1099 | if (err < 0) { |
1002 | pr_err("%s: can't register vti6\n", __func__); | 1100 | unregister_pernet_device(&vti6_net_ops); |
1101 | pr_err("%s: can't register vti6 protocol\n", __func__); | ||
1102 | |||
1003 | goto out; | 1103 | goto out; |
1004 | } | 1104 | } |
1105 | |||
1106 | err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH); | ||
1107 | if (err < 0) { | ||
1108 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); | ||
1109 | unregister_pernet_device(&vti6_net_ops); | ||
1110 | pr_err("%s: can't register vti6 protocol\n", __func__); | ||
1111 | |||
1112 | goto out; | ||
1113 | } | ||
1114 | |||
1115 | err = xfrm6_protocol_register(&vti_ipcomp6_protocol, IPPROTO_COMP); | ||
1116 | if (err < 0) { | ||
1117 | xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); | ||
1118 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); | ||
1119 | unregister_pernet_device(&vti6_net_ops); | ||
1120 | pr_err("%s: can't register vti6 protocol\n", __func__); | ||
1121 | |||
1122 | goto out; | ||
1123 | } | ||
1124 | |||
1005 | err = rtnl_link_register(&vti6_link_ops); | 1125 | err = rtnl_link_register(&vti6_link_ops); |
1006 | if (err < 0) | 1126 | if (err < 0) |
1007 | goto rtnl_link_failed; | 1127 | goto rtnl_link_failed; |
@@ -1009,7 +1129,9 @@ static int __init vti6_tunnel_init(void) | |||
1009 | return 0; | 1129 | return 0; |
1010 | 1130 | ||
1011 | rtnl_link_failed: | 1131 | rtnl_link_failed: |
1012 | xfrm6_mode_tunnel_input_deregister(&vti6_handler); | 1132 | xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP); |
1133 | xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); | ||
1134 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); | ||
1013 | out: | 1135 | out: |
1014 | unregister_pernet_device(&vti6_net_ops); | 1136 | unregister_pernet_device(&vti6_net_ops); |
1015 | out_pernet: | 1137 | out_pernet: |
@@ -1022,8 +1144,12 @@ out_pernet: | |||
1022 | static void __exit vti6_tunnel_cleanup(void) | 1144 | static void __exit vti6_tunnel_cleanup(void) |
1023 | { | 1145 | { |
1024 | rtnl_link_unregister(&vti6_link_ops); | 1146 | rtnl_link_unregister(&vti6_link_ops); |
1025 | if (xfrm6_mode_tunnel_input_deregister(&vti6_handler)) | 1147 | if (xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP)) |
1026 | pr_info("%s: can't deregister vti6\n", __func__); | 1148 | pr_info("%s: can't deregister protocol\n", __func__); |
1149 | if (xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH)) | ||
1150 | pr_info("%s: can't deregister protocol\n", __func__); | ||
1151 | if (xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP)) | ||
1152 | pr_info("%s: can't deregister protocol\n", __func__); | ||
1027 | 1153 | ||
1028 | unregister_pernet_device(&vti6_net_ops); | 1154 | unregister_pernet_device(&vti6_net_ops); |
1029 | } | 1155 | } |