|
@@ -896,6 +896,59 @@ tx_error:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void ipgre_tunnel_bind_dev(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct net_device *tdev = NULL;
|
|
|
+ struct ip_tunnel *tunnel;
|
|
|
+ struct iphdr *iph;
|
|
|
+ int hlen = LL_MAX_HEADER;
|
|
|
+ int mtu = ETH_DATA_LEN;
|
|
|
+ int addend = sizeof(struct iphdr) + 4;
|
|
|
+
|
|
|
+ tunnel = netdev_priv(dev);
|
|
|
+ iph = &tunnel->parms.iph;
|
|
|
+
|
|
|
+ /* Guess output device to choose reasonable mtu and hard_header_len */
|
|
|
+
|
|
|
+ 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_GRE };
|
|
|
+ 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) {
|
|
|
+ hlen = tdev->hard_header_len;
|
|
|
+ mtu = tdev->mtu;
|
|
|
+ }
|
|
|
+ dev->iflink = tunnel->parms.link;
|
|
|
+
|
|
|
+ /* Precalculate GRE options length */
|
|
|
+ if (tunnel->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) {
|
|
|
+ if (tunnel->parms.o_flags&GRE_CSUM)
|
|
|
+ addend += 4;
|
|
|
+ if (tunnel->parms.o_flags&GRE_KEY)
|
|
|
+ addend += 4;
|
|
|
+ if (tunnel->parms.o_flags&GRE_SEQ)
|
|
|
+ addend += 4;
|
|
|
+ }
|
|
|
+ dev->hard_header_len = hlen + addend;
|
|
|
+ dev->mtu = mtu - addend;
|
|
|
+ tunnel->hlen = addend;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
|
|
|
{
|
|
@@ -983,6 +1036,11 @@ ipgre_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;
|
|
|
+ ipgre_tunnel_bind_dev(dev);
|
|
|
+ netdev_state_change(dev);
|
|
|
+ }
|
|
|
}
|
|
|
if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
|
|
|
err = -EFAULT;
|
|
@@ -1162,12 +1220,8 @@ static void ipgre_tunnel_setup(struct net_device *dev)
|
|
|
|
|
|
static int ipgre_tunnel_init(struct net_device *dev)
|
|
|
{
|
|
|
- struct net_device *tdev = NULL;
|
|
|
struct ip_tunnel *tunnel;
|
|
|
struct iphdr *iph;
|
|
|
- int hlen = LL_MAX_HEADER;
|
|
|
- int mtu = ETH_DATA_LEN;
|
|
|
- int addend = sizeof(struct iphdr) + 4;
|
|
|
|
|
|
tunnel = netdev_priv(dev);
|
|
|
iph = &tunnel->parms.iph;
|
|
@@ -1178,23 +1232,9 @@ static int ipgre_tunnel_init(struct net_device *dev)
|
|
|
memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
|
|
|
memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
|
|
|
|
|
|
- /* Guess output device to choose reasonable mtu and hard_header_len */
|
|
|
+ ipgre_tunnel_bind_dev(dev);
|
|
|
|
|
|
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_GRE };
|
|
|
- struct rtable *rt;
|
|
|
- if (!ip_route_output_key(&rt, &fl)) {
|
|
|
- tdev = rt->u.dst.dev;
|
|
|
- ip_rt_put(rt);
|
|
|
- }
|
|
|
-
|
|
|
- dev->flags |= IFF_POINTOPOINT;
|
|
|
-
|
|
|
#ifdef CONFIG_NET_IPGRE_BROADCAST
|
|
|
if (MULTICAST(iph->daddr)) {
|
|
|
if (!iph->saddr)
|
|
@@ -1205,31 +1245,9 @@ static int ipgre_tunnel_init(struct net_device *dev)
|
|
|
dev->stop = ipgre_close;
|
|
|
}
|
|
|
#endif
|
|
|
- } else {
|
|
|
+ } else
|
|
|
dev->header_ops = &ipgre_header_ops;
|
|
|
- }
|
|
|
-
|
|
|
- if (!tdev && tunnel->parms.link)
|
|
|
- tdev = __dev_get_by_index(&init_net, tunnel->parms.link);
|
|
|
-
|
|
|
- if (tdev) {
|
|
|
- hlen = tdev->hard_header_len;
|
|
|
- mtu = tdev->mtu;
|
|
|
- }
|
|
|
- dev->iflink = tunnel->parms.link;
|
|
|
|
|
|
- /* Precalculate GRE options length */
|
|
|
- if (tunnel->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) {
|
|
|
- if (tunnel->parms.o_flags&GRE_CSUM)
|
|
|
- addend += 4;
|
|
|
- if (tunnel->parms.o_flags&GRE_KEY)
|
|
|
- addend += 4;
|
|
|
- if (tunnel->parms.o_flags&GRE_SEQ)
|
|
|
- addend += 4;
|
|
|
- }
|
|
|
- dev->hard_header_len = hlen + addend;
|
|
|
- dev->mtu = mtu - addend;
|
|
|
- tunnel->hlen = addend;
|
|
|
return 0;
|
|
|
}
|
|
|
|