|
@@ -278,7 +278,6 @@ static void vti6_dev_uninit(struct net_device *dev)
|
|
RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
|
|
RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
|
|
else
|
|
else
|
|
vti6_tnl_unlink(ip6n, t);
|
|
vti6_tnl_unlink(ip6n, t);
|
|
- ip6_tnl_dst_reset(t);
|
|
|
|
dev_put(dev);
|
|
dev_put(dev);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -288,11 +287,8 @@ static int vti6_rcv(struct sk_buff *skb)
|
|
const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
|
|
const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
|
|
|
|
|
|
rcu_read_lock();
|
|
rcu_read_lock();
|
|
-
|
|
|
|
if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
|
|
if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
|
|
&ipv6h->daddr)) != NULL) {
|
|
&ipv6h->daddr)) != NULL) {
|
|
- struct pcpu_sw_netstats *tstats;
|
|
|
|
-
|
|
|
|
if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) {
|
|
if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) {
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
goto discard;
|
|
goto discard;
|
|
@@ -309,27 +305,58 @@ static int vti6_rcv(struct sk_buff *skb)
|
|
goto discard;
|
|
goto discard;
|
|
}
|
|
}
|
|
|
|
|
|
- tstats = this_cpu_ptr(t->dev->tstats);
|
|
|
|
- u64_stats_update_begin(&tstats->syncp);
|
|
|
|
- tstats->rx_packets++;
|
|
|
|
- tstats->rx_bytes += skb->len;
|
|
|
|
- u64_stats_update_end(&tstats->syncp);
|
|
|
|
-
|
|
|
|
- skb->mark = 0;
|
|
|
|
- secpath_reset(skb);
|
|
|
|
- skb->dev = t->dev;
|
|
|
|
|
|
+ XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t;
|
|
|
|
+ skb->mark = be32_to_cpu(t->parms.i_key);
|
|
|
|
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
- return 0;
|
|
|
|
|
|
+
|
|
|
|
+ return xfrm6_rcv(skb);
|
|
}
|
|
}
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
- return 1;
|
|
|
|
-
|
|
|
|
|
|
+ return -EINVAL;
|
|
discard:
|
|
discard:
|
|
kfree_skb(skb);
|
|
kfree_skb(skb);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int vti6_rcv_cb(struct sk_buff *skb, int err)
|
|
|
|
+{
|
|
|
|
+ unsigned short family;
|
|
|
|
+ struct net_device *dev;
|
|
|
|
+ struct pcpu_sw_netstats *tstats;
|
|
|
|
+ struct xfrm_state *x;
|
|
|
|
+ struct ip6_tnl *t = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6;
|
|
|
|
+
|
|
|
|
+ if (!t)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ dev = t->dev;
|
|
|
|
+
|
|
|
|
+ if (err) {
|
|
|
|
+ dev->stats.rx_errors++;
|
|
|
|
+ dev->stats.rx_dropped++;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ x = xfrm_input_state(skb);
|
|
|
|
+ family = x->inner_mode->afinfo->family;
|
|
|
|
+
|
|
|
|
+ if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family))
|
|
|
|
+ return -EPERM;
|
|
|
|
+
|
|
|
|
+ skb_scrub_packet(skb, !net_eq(t->net, dev_net(skb->dev)));
|
|
|
|
+ skb->dev = dev;
|
|
|
|
+
|
|
|
|
+ tstats = this_cpu_ptr(dev->tstats);
|
|
|
|
+ u64_stats_update_begin(&tstats->syncp);
|
|
|
|
+ tstats->rx_packets++;
|
|
|
|
+ tstats->rx_bytes += skb->len;
|
|
|
|
+ u64_stats_update_end(&tstats->syncp);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* vti6_addr_conflict - compare packet addresses to tunnel's own
|
|
* vti6_addr_conflict - compare packet addresses to tunnel's own
|
|
* @t: the outgoing tunnel device
|
|
* @t: the outgoing tunnel device
|
|
@@ -349,44 +376,56 @@ vti6_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
|
|
return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
|
|
return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool vti6_state_check(const struct xfrm_state *x,
|
|
|
|
+ const struct in6_addr *dst,
|
|
|
|
+ const struct in6_addr *src)
|
|
|
|
+{
|
|
|
|
+ xfrm_address_t *daddr = (xfrm_address_t *)dst;
|
|
|
|
+ xfrm_address_t *saddr = (xfrm_address_t *)src;
|
|
|
|
+
|
|
|
|
+ /* if there is no transform then this tunnel is not functional.
|
|
|
|
+ * Or if the xfrm is not mode tunnel.
|
|
|
|
+ */
|
|
|
|
+ if (!x || x->props.mode != XFRM_MODE_TUNNEL ||
|
|
|
|
+ x->props.family != AF_INET6)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ if (ipv6_addr_any(dst))
|
|
|
|
+ return xfrm_addr_equal(saddr, &x->props.saddr, AF_INET6);
|
|
|
|
+
|
|
|
|
+ if (!xfrm_state_addr_check(x, daddr, saddr, AF_INET6))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* vti6_xmit - send a packet
|
|
* vti6_xmit - send a packet
|
|
* @skb: the outgoing socket buffer
|
|
* @skb: the outgoing socket buffer
|
|
* @dev: the outgoing tunnel device
|
|
* @dev: the outgoing tunnel device
|
|
|
|
+ * @fl: the flow informations for the xfrm_lookup
|
|
**/
|
|
**/
|
|
-static int vti6_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
|
|
|
|
+static int
|
|
|
|
+vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
|
|
{
|
|
{
|
|
- struct net *net = dev_net(dev);
|
|
|
|
struct ip6_tnl *t = netdev_priv(dev);
|
|
struct ip6_tnl *t = netdev_priv(dev);
|
|
struct net_device_stats *stats = &t->dev->stats;
|
|
struct net_device_stats *stats = &t->dev->stats;
|
|
- struct dst_entry *dst = NULL, *ndst = NULL;
|
|
|
|
- struct flowi6 fl6;
|
|
|
|
- struct ipv6hdr *ipv6h = ipv6_hdr(skb);
|
|
|
|
|
|
+ struct dst_entry *dst = skb_dst(skb);
|
|
struct net_device *tdev;
|
|
struct net_device *tdev;
|
|
int err = -1;
|
|
int err = -1;
|
|
|
|
|
|
- if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
|
|
|
|
- !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h))
|
|
|
|
- return err;
|
|
|
|
-
|
|
|
|
- dst = ip6_tnl_dst_check(t);
|
|
|
|
- if (!dst) {
|
|
|
|
- memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
|
|
|
|
-
|
|
|
|
- ndst = ip6_route_output(net, NULL, &fl6);
|
|
|
|
|
|
+ if (!dst)
|
|
|
|
+ goto tx_err_link_failure;
|
|
|
|
|
|
- if (ndst->error)
|
|
|
|
- goto tx_err_link_failure;
|
|
|
|
- ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(&fl6), NULL, 0);
|
|
|
|
- if (IS_ERR(ndst)) {
|
|
|
|
- err = PTR_ERR(ndst);
|
|
|
|
- ndst = NULL;
|
|
|
|
- goto tx_err_link_failure;
|
|
|
|
- }
|
|
|
|
- dst = ndst;
|
|
|
|
|
|
+ dst_hold(dst);
|
|
|
|
+ dst = xfrm_lookup(t->net, dst, fl, NULL, 0);
|
|
|
|
+ if (IS_ERR(dst)) {
|
|
|
|
+ err = PTR_ERR(dst);
|
|
|
|
+ dst = NULL;
|
|
|
|
+ goto tx_err_link_failure;
|
|
}
|
|
}
|
|
|
|
|
|
- if (!dst->xfrm || dst->xfrm->props.mode != XFRM_MODE_TUNNEL)
|
|
|
|
|
|
+ if (!vti6_state_check(dst->xfrm, &t->parms.raddr, &t->parms.laddr))
|
|
goto tx_err_link_failure;
|
|
goto tx_err_link_failure;
|
|
|
|
|
|
tdev = dst->dev;
|
|
tdev = dst->dev;
|
|
@@ -398,14 +437,21 @@ static int vti6_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
goto tx_err_dst_release;
|
|
goto tx_err_dst_release;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev)));
|
|
|
|
+ skb_dst_set(skb, dst);
|
|
|
|
+ skb->dev = skb_dst(skb)->dev;
|
|
|
|
|
|
- skb_dst_drop(skb);
|
|
|
|
- skb_dst_set_noref(skb, dst);
|
|
|
|
|
|
+ err = dst_output(skb);
|
|
|
|
+ if (net_xmit_eval(err) == 0) {
|
|
|
|
+ struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
|
|
|
|
|
|
- ip6tunnel_xmit(skb, dev);
|
|
|
|
- if (ndst) {
|
|
|
|
- dev->mtu = dst_mtu(ndst);
|
|
|
|
- ip6_tnl_dst_store(t, ndst);
|
|
|
|
|
|
+ u64_stats_update_begin(&tstats->syncp);
|
|
|
|
+ tstats->tx_bytes += skb->len;
|
|
|
|
+ tstats->tx_packets++;
|
|
|
|
+ u64_stats_update_end(&tstats->syncp);
|
|
|
|
+ } else {
|
|
|
|
+ stats->tx_errors++;
|
|
|
|
+ stats->tx_aborted_errors++;
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -413,7 +459,7 @@ tx_err_link_failure:
|
|
stats->tx_carrier_errors++;
|
|
stats->tx_carrier_errors++;
|
|
dst_link_failure(skb);
|
|
dst_link_failure(skb);
|
|
tx_err_dst_release:
|
|
tx_err_dst_release:
|
|
- dst_release(ndst);
|
|
|
|
|
|
+ dst_release(dst);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -422,16 +468,33 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
{
|
|
{
|
|
struct ip6_tnl *t = netdev_priv(dev);
|
|
struct ip6_tnl *t = netdev_priv(dev);
|
|
struct net_device_stats *stats = &t->dev->stats;
|
|
struct net_device_stats *stats = &t->dev->stats;
|
|
|
|
+ struct ipv6hdr *ipv6h;
|
|
|
|
+ struct flowi fl;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
|
|
+ memset(&fl, 0, sizeof(fl));
|
|
|
|
+ skb->mark = be32_to_cpu(t->parms.o_key);
|
|
|
|
+
|
|
switch (skb->protocol) {
|
|
switch (skb->protocol) {
|
|
case htons(ETH_P_IPV6):
|
|
case htons(ETH_P_IPV6):
|
|
- ret = vti6_xmit(skb, dev);
|
|
|
|
|
|
+ ipv6h = ipv6_hdr(skb);
|
|
|
|
+
|
|
|
|
+ if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
|
|
|
|
+ !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h))
|
|
|
|
+ goto tx_err;
|
|
|
|
+
|
|
|
|
+ xfrm_decode_session(skb, &fl, AF_INET6);
|
|
|
|
+ memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
|
|
|
|
+ break;
|
|
|
|
+ case htons(ETH_P_IP):
|
|
|
|
+ xfrm_decode_session(skb, &fl, AF_INET);
|
|
|
|
+ memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
goto tx_err;
|
|
goto tx_err;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ ret = vti6_xmit(skb, dev, &fl);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
goto tx_err;
|
|
goto tx_err;
|
|
|
|
|
|
@@ -444,24 +507,66 @@ tx_err:
|
|
return NETDEV_TX_OK;
|
|
return NETDEV_TX_OK;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
|
|
|
+ u8 type, u8 code, int offset, __be32 info)
|
|
|
|
+{
|
|
|
|
+ __be32 spi;
|
|
|
|
+ struct xfrm_state *x;
|
|
|
|
+ struct ip6_tnl *t;
|
|
|
|
+ struct ip_esp_hdr *esph;
|
|
|
|
+ struct ip_auth_hdr *ah;
|
|
|
|
+ struct ip_comp_hdr *ipch;
|
|
|
|
+ struct net *net = dev_net(skb->dev);
|
|
|
|
+ const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data;
|
|
|
|
+ int protocol = iph->nexthdr;
|
|
|
|
+
|
|
|
|
+ t = vti6_tnl_lookup(dev_net(skb->dev), &iph->daddr, &iph->saddr);
|
|
|
|
+ if (!t)
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ switch (protocol) {
|
|
|
|
+ case IPPROTO_ESP:
|
|
|
|
+ esph = (struct ip_esp_hdr *)(skb->data + offset);
|
|
|
|
+ spi = esph->spi;
|
|
|
|
+ break;
|
|
|
|
+ case IPPROTO_AH:
|
|
|
|
+ ah = (struct ip_auth_hdr *)(skb->data + offset);
|
|
|
|
+ spi = ah->spi;
|
|
|
|
+ break;
|
|
|
|
+ case IPPROTO_COMP:
|
|
|
|
+ ipch = (struct ip_comp_hdr *)(skb->data + offset);
|
|
|
|
+ spi = htonl(ntohs(ipch->cpi));
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (type != ICMPV6_PKT_TOOBIG &&
|
|
|
|
+ type != NDISC_REDIRECT)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
|
|
|
|
+ spi, protocol, AF_INET6);
|
|
|
|
+ if (!x)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ if (type == NDISC_REDIRECT)
|
|
|
|
+ ip6_redirect(skb, net, skb->dev->ifindex, 0);
|
|
|
|
+ else
|
|
|
|
+ ip6_update_pmtu(skb, net, info, 0, 0);
|
|
|
|
+ xfrm_state_put(x);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static void vti6_link_config(struct ip6_tnl *t)
|
|
static void vti6_link_config(struct ip6_tnl *t)
|
|
{
|
|
{
|
|
- struct dst_entry *dst;
|
|
|
|
struct net_device *dev = t->dev;
|
|
struct net_device *dev = t->dev;
|
|
struct __ip6_tnl_parm *p = &t->parms;
|
|
struct __ip6_tnl_parm *p = &t->parms;
|
|
- struct flowi6 *fl6 = &t->fl.u.ip6;
|
|
|
|
|
|
|
|
memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
|
|
memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
|
|
memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
|
|
memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
|
|
|
|
|
|
- /* Set up flowi template */
|
|
|
|
- fl6->saddr = p->laddr;
|
|
|
|
- fl6->daddr = p->raddr;
|
|
|
|
- fl6->flowi6_oif = p->link;
|
|
|
|
- fl6->flowi6_mark = be32_to_cpu(p->i_key);
|
|
|
|
- fl6->flowi6_proto = p->proto;
|
|
|
|
- fl6->flowlabel = 0;
|
|
|
|
-
|
|
|
|
p->flags &= ~(IP6_TNL_F_CAP_XMIT | IP6_TNL_F_CAP_RCV |
|
|
p->flags &= ~(IP6_TNL_F_CAP_XMIT | IP6_TNL_F_CAP_RCV |
|
|
IP6_TNL_F_CAP_PER_PACKET);
|
|
IP6_TNL_F_CAP_PER_PACKET);
|
|
p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr);
|
|
p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr);
|
|
@@ -472,28 +577,6 @@ static void vti6_link_config(struct ip6_tnl *t)
|
|
dev->flags &= ~IFF_POINTOPOINT;
|
|
dev->flags &= ~IFF_POINTOPOINT;
|
|
|
|
|
|
dev->iflink = p->link;
|
|
dev->iflink = p->link;
|
|
-
|
|
|
|
- if (p->flags & IP6_TNL_F_CAP_XMIT) {
|
|
|
|
-
|
|
|
|
- dst = ip6_route_output(dev_net(dev), NULL, fl6);
|
|
|
|
- if (dst->error)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- dst = xfrm_lookup(dev_net(dev), dst, flowi6_to_flowi(fl6),
|
|
|
|
- NULL, 0);
|
|
|
|
- if (IS_ERR(dst))
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- if (dst->dev) {
|
|
|
|
- dev->hard_header_len = dst->dev->hard_header_len;
|
|
|
|
-
|
|
|
|
- dev->mtu = dst_mtu(dst);
|
|
|
|
-
|
|
|
|
- if (dev->mtu < IPV6_MIN_MTU)
|
|
|
|
- dev->mtu = IPV6_MIN_MTU;
|
|
|
|
- }
|
|
|
|
- dst_release(dst);
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -720,7 +803,6 @@ static void vti6_dev_setup(struct net_device *dev)
|
|
t = netdev_priv(dev);
|
|
t = netdev_priv(dev);
|
|
dev->flags |= IFF_NOARP;
|
|
dev->flags |= IFF_NOARP;
|
|
dev->addr_len = sizeof(struct in6_addr);
|
|
dev->addr_len = sizeof(struct in6_addr);
|
|
- dev->features |= NETIF_F_NETNS_LOCAL;
|
|
|
|
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
|
|
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -908,11 +990,6 @@ static struct rtnl_link_ops vti6_link_ops __read_mostly = {
|
|
.fill_info = vti6_fill_info,
|
|
.fill_info = vti6_fill_info,
|
|
};
|
|
};
|
|
|
|
|
|
-static struct xfrm_tunnel_notifier vti6_handler __read_mostly = {
|
|
|
|
- .handler = vti6_rcv,
|
|
|
|
- .priority = 1,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n)
|
|
static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n)
|
|
{
|
|
{
|
|
int h;
|
|
int h;
|
|
@@ -984,6 +1061,27 @@ static struct pernet_operations vti6_net_ops = {
|
|
.size = sizeof(struct vti6_net),
|
|
.size = sizeof(struct vti6_net),
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static struct xfrm6_protocol vti_esp6_protocol __read_mostly = {
|
|
|
|
+ .handler = vti6_rcv,
|
|
|
|
+ .cb_handler = vti6_rcv_cb,
|
|
|
|
+ .err_handler = vti6_err,
|
|
|
|
+ .priority = 100,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct xfrm6_protocol vti_ah6_protocol __read_mostly = {
|
|
|
|
+ .handler = vti6_rcv,
|
|
|
|
+ .cb_handler = vti6_rcv_cb,
|
|
|
|
+ .err_handler = vti6_err,
|
|
|
|
+ .priority = 100,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct xfrm6_protocol vti_ipcomp6_protocol __read_mostly = {
|
|
|
|
+ .handler = vti6_rcv,
|
|
|
|
+ .cb_handler = vti6_rcv_cb,
|
|
|
|
+ .err_handler = vti6_err,
|
|
|
|
+ .priority = 100,
|
|
|
|
+};
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* vti6_tunnel_init - register protocol and reserve needed resources
|
|
* vti6_tunnel_init - register protocol and reserve needed resources
|
|
*
|
|
*
|
|
@@ -997,11 +1095,33 @@ static int __init vti6_tunnel_init(void)
|
|
if (err < 0)
|
|
if (err < 0)
|
|
goto out_pernet;
|
|
goto out_pernet;
|
|
|
|
|
|
- err = xfrm6_mode_tunnel_input_register(&vti6_handler);
|
|
|
|
|
|
+ err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP);
|
|
if (err < 0) {
|
|
if (err < 0) {
|
|
- pr_err("%s: can't register vti6\n", __func__);
|
|
|
|
|
|
+ unregister_pernet_device(&vti6_net_ops);
|
|
|
|
+ pr_err("%s: can't register vti6 protocol\n", __func__);
|
|
|
|
+
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH);
|
|
|
|
+ if (err < 0) {
|
|
|
|
+ xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
|
|
|
|
+ unregister_pernet_device(&vti6_net_ops);
|
|
|
|
+ pr_err("%s: can't register vti6 protocol\n", __func__);
|
|
|
|
+
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ err = xfrm6_protocol_register(&vti_ipcomp6_protocol, IPPROTO_COMP);
|
|
|
|
+ if (err < 0) {
|
|
|
|
+ xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH);
|
|
|
|
+ xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
|
|
|
|
+ unregister_pernet_device(&vti6_net_ops);
|
|
|
|
+ pr_err("%s: can't register vti6 protocol\n", __func__);
|
|
|
|
+
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
err = rtnl_link_register(&vti6_link_ops);
|
|
err = rtnl_link_register(&vti6_link_ops);
|
|
if (err < 0)
|
|
if (err < 0)
|
|
goto rtnl_link_failed;
|
|
goto rtnl_link_failed;
|
|
@@ -1009,7 +1129,9 @@ static int __init vti6_tunnel_init(void)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
rtnl_link_failed:
|
|
rtnl_link_failed:
|
|
- xfrm6_mode_tunnel_input_deregister(&vti6_handler);
|
|
|
|
|
|
+ xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP);
|
|
|
|
+ xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH);
|
|
|
|
+ xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
|
|
out:
|
|
out:
|
|
unregister_pernet_device(&vti6_net_ops);
|
|
unregister_pernet_device(&vti6_net_ops);
|
|
out_pernet:
|
|
out_pernet:
|
|
@@ -1022,8 +1144,12 @@ out_pernet:
|
|
static void __exit vti6_tunnel_cleanup(void)
|
|
static void __exit vti6_tunnel_cleanup(void)
|
|
{
|
|
{
|
|
rtnl_link_unregister(&vti6_link_ops);
|
|
rtnl_link_unregister(&vti6_link_ops);
|
|
- if (xfrm6_mode_tunnel_input_deregister(&vti6_handler))
|
|
|
|
- pr_info("%s: can't deregister vti6\n", __func__);
|
|
|
|
|
|
+ if (xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP))
|
|
|
|
+ pr_info("%s: can't deregister protocol\n", __func__);
|
|
|
|
+ if (xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH))
|
|
|
|
+ pr_info("%s: can't deregister protocol\n", __func__);
|
|
|
|
+ if (xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP))
|
|
|
|
+ pr_info("%s: can't deregister protocol\n", __func__);
|
|
|
|
|
|
unregister_pernet_device(&vti6_net_ops);
|
|
unregister_pernet_device(&vti6_net_ops);
|
|
}
|
|
}
|