diff options
Diffstat (limited to 'net/ipv6/sit.c')
-rw-r--r-- | net/ipv6/sit.c | 123 |
1 files changed, 107 insertions, 16 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 6163f851dc01..6eab37cf5345 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -812,9 +812,9 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
812 | const struct ipv6hdr *iph6 = ipv6_hdr(skb); | 812 | const struct ipv6hdr *iph6 = ipv6_hdr(skb); |
813 | u8 tos = tunnel->parms.iph.tos; | 813 | u8 tos = tunnel->parms.iph.tos; |
814 | __be16 df = tiph->frag_off; | 814 | __be16 df = tiph->frag_off; |
815 | struct rtable *rt; /* Route to the other host */ | 815 | struct rtable *rt; /* Route to the other host */ |
816 | struct net_device *tdev; /* Device to other host */ | 816 | struct net_device *tdev; /* Device to other host */ |
817 | unsigned int max_headroom; /* The extra header space needed */ | 817 | unsigned int max_headroom; /* The extra header space needed */ |
818 | __be32 dst = tiph->daddr; | 818 | __be32 dst = tiph->daddr; |
819 | struct flowi4 fl4; | 819 | struct flowi4 fl4; |
820 | int mtu; | 820 | int mtu; |
@@ -822,6 +822,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
822 | int addr_type; | 822 | int addr_type; |
823 | u8 ttl; | 823 | u8 ttl; |
824 | int err; | 824 | int err; |
825 | u8 protocol = IPPROTO_IPV6; | ||
826 | int t_hlen = tunnel->hlen + sizeof(struct iphdr); | ||
825 | 827 | ||
826 | if (skb->protocol != htons(ETH_P_IPV6)) | 828 | if (skb->protocol != htons(ETH_P_IPV6)) |
827 | goto tx_error; | 829 | goto tx_error; |
@@ -911,8 +913,14 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
911 | goto tx_error; | 913 | goto tx_error; |
912 | } | 914 | } |
913 | 915 | ||
916 | skb = iptunnel_handle_offloads(skb, false, SKB_GSO_SIT); | ||
917 | if (IS_ERR(skb)) { | ||
918 | ip_rt_put(rt); | ||
919 | goto out; | ||
920 | } | ||
921 | |||
914 | if (df) { | 922 | if (df) { |
915 | mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr); | 923 | mtu = dst_mtu(&rt->dst) - t_hlen; |
916 | 924 | ||
917 | if (mtu < 68) { | 925 | if (mtu < 68) { |
918 | dev->stats.collisions++; | 926 | dev->stats.collisions++; |
@@ -947,7 +955,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
947 | /* | 955 | /* |
948 | * Okay, now see if we can stuff it in the buffer as-is. | 956 | * Okay, now see if we can stuff it in the buffer as-is. |
949 | */ | 957 | */ |
950 | max_headroom = LL_RESERVED_SPACE(tdev)+sizeof(struct iphdr); | 958 | max_headroom = LL_RESERVED_SPACE(tdev) + t_hlen; |
951 | 959 | ||
952 | if (skb_headroom(skb) < max_headroom || skb_shared(skb) || | 960 | if (skb_headroom(skb) < max_headroom || skb_shared(skb) || |
953 | (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { | 961 | (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { |
@@ -969,14 +977,15 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
969 | ttl = iph6->hop_limit; | 977 | ttl = iph6->hop_limit; |
970 | tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); | 978 | tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); |
971 | 979 | ||
972 | skb = iptunnel_handle_offloads(skb, false, SKB_GSO_SIT); | 980 | if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) { |
973 | if (IS_ERR(skb)) { | ||
974 | ip_rt_put(rt); | 981 | ip_rt_put(rt); |
975 | goto out; | 982 | goto tx_error; |
976 | } | 983 | } |
977 | 984 | ||
985 | skb_set_inner_ipproto(skb, IPPROTO_IPV6); | ||
986 | |||
978 | err = iptunnel_xmit(skb->sk, rt, skb, fl4.saddr, fl4.daddr, | 987 | err = iptunnel_xmit(skb->sk, rt, skb, fl4.saddr, fl4.daddr, |
979 | IPPROTO_IPV6, tos, ttl, df, | 988 | protocol, tos, ttl, df, |
980 | !net_eq(tunnel->net, dev_net(dev))); | 989 | !net_eq(tunnel->net, dev_net(dev))); |
981 | iptunnel_xmit_stats(err, &dev->stats, dev->tstats); | 990 | iptunnel_xmit_stats(err, &dev->stats, dev->tstats); |
982 | return NETDEV_TX_OK; | 991 | return NETDEV_TX_OK; |
@@ -999,6 +1008,8 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
999 | if (IS_ERR(skb)) | 1008 | if (IS_ERR(skb)) |
1000 | goto out; | 1009 | goto out; |
1001 | 1010 | ||
1011 | skb_set_inner_ipproto(skb, IPPROTO_IPIP); | ||
1012 | |||
1002 | ip_tunnel_xmit(skb, dev, tiph, IPPROTO_IPIP); | 1013 | ip_tunnel_xmit(skb, dev, tiph, IPPROTO_IPIP); |
1003 | return NETDEV_TX_OK; | 1014 | return NETDEV_TX_OK; |
1004 | out: | 1015 | out: |
@@ -1059,8 +1070,10 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) | |||
1059 | tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link); | 1070 | tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link); |
1060 | 1071 | ||
1061 | if (tdev) { | 1072 | if (tdev) { |
1073 | int t_hlen = tunnel->hlen + sizeof(struct iphdr); | ||
1074 | |||
1062 | dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); | 1075 | dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); |
1063 | dev->mtu = tdev->mtu - sizeof(struct iphdr); | 1076 | dev->mtu = tdev->mtu - t_hlen; |
1064 | if (dev->mtu < IPV6_MIN_MTU) | 1077 | if (dev->mtu < IPV6_MIN_MTU) |
1065 | dev->mtu = IPV6_MIN_MTU; | 1078 | dev->mtu = IPV6_MIN_MTU; |
1066 | } | 1079 | } |
@@ -1123,7 +1136,7 @@ static int ipip6_tunnel_update_6rd(struct ip_tunnel *t, | |||
1123 | #endif | 1136 | #endif |
1124 | 1137 | ||
1125 | static int | 1138 | static int |
1126 | ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | 1139 | ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
1127 | { | 1140 | { |
1128 | int err = 0; | 1141 | int err = 0; |
1129 | struct ip_tunnel_parm p; | 1142 | struct ip_tunnel_parm p; |
@@ -1307,7 +1320,10 @@ done: | |||
1307 | 1320 | ||
1308 | static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu) | 1321 | static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu) |
1309 | { | 1322 | { |
1310 | if (new_mtu < IPV6_MIN_MTU || new_mtu > 0xFFF8 - sizeof(struct iphdr)) | 1323 | struct ip_tunnel *tunnel = netdev_priv(dev); |
1324 | int t_hlen = tunnel->hlen + sizeof(struct iphdr); | ||
1325 | |||
1326 | if (new_mtu < IPV6_MIN_MTU || new_mtu > 0xFFF8 - t_hlen) | ||
1311 | return -EINVAL; | 1327 | return -EINVAL; |
1312 | dev->mtu = new_mtu; | 1328 | dev->mtu = new_mtu; |
1313 | return 0; | 1329 | return 0; |
@@ -1338,14 +1354,17 @@ static void ipip6_dev_free(struct net_device *dev) | |||
1338 | 1354 | ||
1339 | static void ipip6_tunnel_setup(struct net_device *dev) | 1355 | static void ipip6_tunnel_setup(struct net_device *dev) |
1340 | { | 1356 | { |
1357 | struct ip_tunnel *tunnel = netdev_priv(dev); | ||
1358 | int t_hlen = tunnel->hlen + sizeof(struct iphdr); | ||
1359 | |||
1341 | dev->netdev_ops = &ipip6_netdev_ops; | 1360 | dev->netdev_ops = &ipip6_netdev_ops; |
1342 | dev->destructor = ipip6_dev_free; | 1361 | dev->destructor = ipip6_dev_free; |
1343 | 1362 | ||
1344 | dev->type = ARPHRD_SIT; | 1363 | dev->type = ARPHRD_SIT; |
1345 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); | 1364 | dev->hard_header_len = LL_MAX_HEADER + t_hlen; |
1346 | dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr); | 1365 | dev->mtu = ETH_DATA_LEN - t_hlen; |
1347 | dev->flags = IFF_NOARP; | 1366 | dev->flags = IFF_NOARP; |
1348 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | 1367 | netif_keep_dst(dev); |
1349 | dev->iflink = 0; | 1368 | dev->iflink = 0; |
1350 | dev->addr_len = 4; | 1369 | dev->addr_len = 4; |
1351 | dev->features |= NETIF_F_LLTX; | 1370 | dev->features |= NETIF_F_LLTX; |
@@ -1466,6 +1485,40 @@ static void ipip6_netlink_parms(struct nlattr *data[], | |||
1466 | 1485 | ||
1467 | } | 1486 | } |
1468 | 1487 | ||
1488 | /* This function returns true when ENCAP attributes are present in the nl msg */ | ||
1489 | static bool ipip6_netlink_encap_parms(struct nlattr *data[], | ||
1490 | struct ip_tunnel_encap *ipencap) | ||
1491 | { | ||
1492 | bool ret = false; | ||
1493 | |||
1494 | memset(ipencap, 0, sizeof(*ipencap)); | ||
1495 | |||
1496 | if (!data) | ||
1497 | return ret; | ||
1498 | |||
1499 | if (data[IFLA_IPTUN_ENCAP_TYPE]) { | ||
1500 | ret = true; | ||
1501 | ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]); | ||
1502 | } | ||
1503 | |||
1504 | if (data[IFLA_IPTUN_ENCAP_FLAGS]) { | ||
1505 | ret = true; | ||
1506 | ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]); | ||
1507 | } | ||
1508 | |||
1509 | if (data[IFLA_IPTUN_ENCAP_SPORT]) { | ||
1510 | ret = true; | ||
1511 | ipencap->sport = nla_get_u16(data[IFLA_IPTUN_ENCAP_SPORT]); | ||
1512 | } | ||
1513 | |||
1514 | if (data[IFLA_IPTUN_ENCAP_DPORT]) { | ||
1515 | ret = true; | ||
1516 | ipencap->dport = nla_get_u16(data[IFLA_IPTUN_ENCAP_DPORT]); | ||
1517 | } | ||
1518 | |||
1519 | return ret; | ||
1520 | } | ||
1521 | |||
1469 | #ifdef CONFIG_IPV6_SIT_6RD | 1522 | #ifdef CONFIG_IPV6_SIT_6RD |
1470 | /* This function returns true when 6RD attributes are present in the nl msg */ | 1523 | /* This function returns true when 6RD attributes are present in the nl msg */ |
1471 | static bool ipip6_netlink_6rd_parms(struct nlattr *data[], | 1524 | static bool ipip6_netlink_6rd_parms(struct nlattr *data[], |
@@ -1509,12 +1562,20 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev, | |||
1509 | { | 1562 | { |
1510 | struct net *net = dev_net(dev); | 1563 | struct net *net = dev_net(dev); |
1511 | struct ip_tunnel *nt; | 1564 | struct ip_tunnel *nt; |
1565 | struct ip_tunnel_encap ipencap; | ||
1512 | #ifdef CONFIG_IPV6_SIT_6RD | 1566 | #ifdef CONFIG_IPV6_SIT_6RD |
1513 | struct ip_tunnel_6rd ip6rd; | 1567 | struct ip_tunnel_6rd ip6rd; |
1514 | #endif | 1568 | #endif |
1515 | int err; | 1569 | int err; |
1516 | 1570 | ||
1517 | nt = netdev_priv(dev); | 1571 | nt = netdev_priv(dev); |
1572 | |||
1573 | if (ipip6_netlink_encap_parms(data, &ipencap)) { | ||
1574 | err = ip_tunnel_encap_setup(nt, &ipencap); | ||
1575 | if (err < 0) | ||
1576 | return err; | ||
1577 | } | ||
1578 | |||
1518 | ipip6_netlink_parms(data, &nt->parms); | 1579 | ipip6_netlink_parms(data, &nt->parms); |
1519 | 1580 | ||
1520 | if (ipip6_tunnel_locate(net, &nt->parms, 0)) | 1581 | if (ipip6_tunnel_locate(net, &nt->parms, 0)) |
@@ -1537,15 +1598,23 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], | |||
1537 | { | 1598 | { |
1538 | struct ip_tunnel *t = netdev_priv(dev); | 1599 | struct ip_tunnel *t = netdev_priv(dev); |
1539 | struct ip_tunnel_parm p; | 1600 | struct ip_tunnel_parm p; |
1601 | struct ip_tunnel_encap ipencap; | ||
1540 | struct net *net = t->net; | 1602 | struct net *net = t->net; |
1541 | struct sit_net *sitn = net_generic(net, sit_net_id); | 1603 | struct sit_net *sitn = net_generic(net, sit_net_id); |
1542 | #ifdef CONFIG_IPV6_SIT_6RD | 1604 | #ifdef CONFIG_IPV6_SIT_6RD |
1543 | struct ip_tunnel_6rd ip6rd; | 1605 | struct ip_tunnel_6rd ip6rd; |
1544 | #endif | 1606 | #endif |
1607 | int err; | ||
1545 | 1608 | ||
1546 | if (dev == sitn->fb_tunnel_dev) | 1609 | if (dev == sitn->fb_tunnel_dev) |
1547 | return -EINVAL; | 1610 | return -EINVAL; |
1548 | 1611 | ||
1612 | if (ipip6_netlink_encap_parms(data, &ipencap)) { | ||
1613 | err = ip_tunnel_encap_setup(t, &ipencap); | ||
1614 | if (err < 0) | ||
1615 | return err; | ||
1616 | } | ||
1617 | |||
1549 | ipip6_netlink_parms(data, &p); | 1618 | ipip6_netlink_parms(data, &p); |
1550 | 1619 | ||
1551 | if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || | 1620 | if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || |
@@ -1599,6 +1668,14 @@ static size_t ipip6_get_size(const struct net_device *dev) | |||
1599 | /* IFLA_IPTUN_6RD_RELAY_PREFIXLEN */ | 1668 | /* IFLA_IPTUN_6RD_RELAY_PREFIXLEN */ |
1600 | nla_total_size(2) + | 1669 | nla_total_size(2) + |
1601 | #endif | 1670 | #endif |
1671 | /* IFLA_IPTUN_ENCAP_TYPE */ | ||
1672 | nla_total_size(2) + | ||
1673 | /* IFLA_IPTUN_ENCAP_FLAGS */ | ||
1674 | nla_total_size(2) + | ||
1675 | /* IFLA_IPTUN_ENCAP_SPORT */ | ||
1676 | nla_total_size(2) + | ||
1677 | /* IFLA_IPTUN_ENCAP_DPORT */ | ||
1678 | nla_total_size(2) + | ||
1602 | 0; | 1679 | 0; |
1603 | } | 1680 | } |
1604 | 1681 | ||
@@ -1630,6 +1707,16 @@ static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
1630 | goto nla_put_failure; | 1707 | goto nla_put_failure; |
1631 | #endif | 1708 | #endif |
1632 | 1709 | ||
1710 | if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, | ||
1711 | tunnel->encap.type) || | ||
1712 | nla_put_u16(skb, IFLA_IPTUN_ENCAP_SPORT, | ||
1713 | tunnel->encap.sport) || | ||
1714 | nla_put_u16(skb, IFLA_IPTUN_ENCAP_DPORT, | ||
1715 | tunnel->encap.dport) || | ||
1716 | nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, | ||
1717 | tunnel->encap.dport)) | ||
1718 | goto nla_put_failure; | ||
1719 | |||
1633 | return 0; | 1720 | return 0; |
1634 | 1721 | ||
1635 | nla_put_failure: | 1722 | nla_put_failure: |
@@ -1651,6 +1738,10 @@ static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = { | |||
1651 | [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 }, | 1738 | [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 }, |
1652 | [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 }, | 1739 | [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 }, |
1653 | #endif | 1740 | #endif |
1741 | [IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 }, | ||
1742 | [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, | ||
1743 | [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, | ||
1744 | [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, | ||
1654 | }; | 1745 | }; |
1655 | 1746 | ||
1656 | static void ipip6_dellink(struct net_device *dev, struct list_head *head) | 1747 | static void ipip6_dellink(struct net_device *dev, struct list_head *head) |