|
@@ -651,6 +651,40 @@ tx_error:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void ipip_tunnel_bind_dev(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct net_device *tdev = NULL;
|
|
|
+ struct ip_tunnel *tunnel;
|
|
|
+ struct iphdr *iph;
|
|
|
+
|
|
|
+ tunnel = netdev_priv(dev);
|
|
|
+ iph = &tunnel->parms.iph;
|
|
|
+
|
|
|
+ if (iph->daddr) {
|
|
|
+ struct flowi fl = { .oif = tunnel->parms.link,
|
|
|
+ .nl_u = { .ip4_u =
|
|
|
+ { .daddr = iph->daddr,
|
|
|
+ .saddr = iph->saddr,
|
|
|
+ .tos = RT_TOS(iph->tos) } },
|
|
|
+ .proto = IPPROTO_IPIP };
|
|
|
+ struct rtable *rt;
|
|
|
+ if (!ip_route_output_key(&rt, &fl)) {
|
|
|
+ tdev = rt->u.dst.dev;
|
|
|
+ ip_rt_put(rt);
|
|
|
+ }
|
|
|
+ dev->flags |= IFF_POINTOPOINT;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!tdev && tunnel->parms.link)
|
|
|
+ tdev = __dev_get_by_index(&init_net, tunnel->parms.link);
|
|
|
+
|
|
|
+ if (tdev) {
|
|
|
+ dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
|
|
|
+ dev->mtu = tdev->mtu - sizeof(struct iphdr);
|
|
|
+ }
|
|
|
+ dev->iflink = tunnel->parms.link;
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
|
|
|
{
|
|
@@ -723,6 +757,11 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
|
|
|
t->parms.iph.ttl = p.iph.ttl;
|
|
|
t->parms.iph.tos = p.iph.tos;
|
|
|
t->parms.iph.frag_off = p.iph.frag_off;
|
|
|
+ if (t->parms.link != p.link) {
|
|
|
+ t->parms.link = p.link;
|
|
|
+ ipip_tunnel_bind_dev(dev);
|
|
|
+ netdev_state_change(dev);
|
|
|
+ }
|
|
|
}
|
|
|
if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
|
|
|
err = -EFAULT;
|
|
@@ -791,12 +830,9 @@ static void ipip_tunnel_setup(struct net_device *dev)
|
|
|
|
|
|
static int ipip_tunnel_init(struct net_device *dev)
|
|
|
{
|
|
|
- struct net_device *tdev = NULL;
|
|
|
struct ip_tunnel *tunnel;
|
|
|
- struct iphdr *iph;
|
|
|
|
|
|
tunnel = netdev_priv(dev);
|
|
|
- iph = &tunnel->parms.iph;
|
|
|
|
|
|
tunnel->dev = dev;
|
|
|
strcpy(tunnel->parms.name, dev->name);
|
|
@@ -804,29 +840,7 @@ static int ipip_tunnel_init(struct net_device *dev)
|
|
|
memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
|
|
|
memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
|
|
|
|
|
|
- if (iph->daddr) {
|
|
|
- struct flowi fl = { .oif = tunnel->parms.link,
|
|
|
- .nl_u = { .ip4_u =
|
|
|
- { .daddr = iph->daddr,
|
|
|
- .saddr = iph->saddr,
|
|
|
- .tos = RT_TOS(iph->tos) } },
|
|
|
- .proto = IPPROTO_IPIP };
|
|
|
- struct rtable *rt;
|
|
|
- if (!ip_route_output_key(&rt, &fl)) {
|
|
|
- tdev = rt->u.dst.dev;
|
|
|
- ip_rt_put(rt);
|
|
|
- }
|
|
|
- dev->flags |= IFF_POINTOPOINT;
|
|
|
- }
|
|
|
-
|
|
|
- if (!tdev && tunnel->parms.link)
|
|
|
- tdev = __dev_get_by_index(&init_net, tunnel->parms.link);
|
|
|
-
|
|
|
- if (tdev) {
|
|
|
- dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
|
|
|
- dev->mtu = tdev->mtu - sizeof(struct iphdr);
|
|
|
- }
|
|
|
- dev->iflink = tunnel->parms.link;
|
|
|
+ ipip_tunnel_bind_dev(dev);
|
|
|
|
|
|
return 0;
|
|
|
}
|