.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * IPv6 over IPv4 tunnel device - Simple Internet Transition (SIT) |
---|
3 | 4 | * Linux INET6 implementation |
---|
.. | .. |
---|
5 | 6 | * Authors: |
---|
6 | 7 | * Pedro Roque <roque@di.fc.ul.pt> |
---|
7 | 8 | * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> |
---|
8 | | - * |
---|
9 | | - * This program is free software; you can redistribute it and/or |
---|
10 | | - * modify it under the terms of the GNU General Public License |
---|
11 | | - * as published by the Free Software Foundation; either version |
---|
12 | | - * 2 of the License, or (at your option) any later version. |
---|
13 | 9 | * |
---|
14 | 10 | * Changes: |
---|
15 | 11 | * Roger Venning <r.venning@telstra.com>: 6to4 support |
---|
.. | .. |
---|
86 | 82 | |
---|
87 | 83 | struct net_device *fb_tunnel_dev; |
---|
88 | 84 | }; |
---|
| 85 | + |
---|
| 86 | +static inline struct sit_net *dev_to_sit_net(struct net_device *dev) |
---|
| 87 | +{ |
---|
| 88 | + struct ip_tunnel *t = netdev_priv(dev); |
---|
| 89 | + |
---|
| 90 | + return net_generic(t->net, sit_net_id); |
---|
| 91 | +} |
---|
89 | 92 | |
---|
90 | 93 | /* |
---|
91 | 94 | * Must be invoked with rcu_read_lock |
---|
.. | .. |
---|
293 | 296 | |
---|
294 | 297 | } |
---|
295 | 298 | |
---|
296 | | -static int ipip6_tunnel_get_prl(struct ip_tunnel *t, |
---|
297 | | - struct ip_tunnel_prl __user *a) |
---|
| 299 | +static int ipip6_tunnel_get_prl(struct net_device *dev, struct ifreq *ifr) |
---|
298 | 300 | { |
---|
| 301 | + struct ip_tunnel_prl __user *a = ifr->ifr_ifru.ifru_data; |
---|
| 302 | + struct ip_tunnel *t = netdev_priv(dev); |
---|
299 | 303 | struct ip_tunnel_prl kprl, *kp; |
---|
300 | 304 | struct ip_tunnel_prl_entry *prl; |
---|
301 | 305 | unsigned int cmax, c = 0, ca, len; |
---|
302 | 306 | int ret = 0; |
---|
| 307 | + |
---|
| 308 | + if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) |
---|
| 309 | + return -EINVAL; |
---|
303 | 310 | |
---|
304 | 311 | if (copy_from_user(&kprl, a, sizeof(kprl))) |
---|
305 | 312 | return -EFAULT; |
---|
.. | .. |
---|
314 | 321 | kcalloc(cmax, sizeof(*kp), GFP_KERNEL | __GFP_NOWARN) : |
---|
315 | 322 | NULL; |
---|
316 | 323 | |
---|
317 | | - rcu_read_lock(); |
---|
318 | | - |
---|
319 | | - ca = t->prl_count < cmax ? t->prl_count : cmax; |
---|
| 324 | + ca = min(t->prl_count, cmax); |
---|
320 | 325 | |
---|
321 | 326 | if (!kp) { |
---|
322 | 327 | /* We don't try hard to allocate much memory for |
---|
.. | .. |
---|
331 | 336 | } |
---|
332 | 337 | } |
---|
333 | 338 | |
---|
334 | | - c = 0; |
---|
| 339 | + rcu_read_lock(); |
---|
335 | 340 | for_each_prl_rcu(t->prl) { |
---|
336 | 341 | if (c >= cmax) |
---|
337 | 342 | break; |
---|
.. | .. |
---|
343 | 348 | if (kprl.addr != htonl(INADDR_ANY)) |
---|
344 | 349 | break; |
---|
345 | 350 | } |
---|
346 | | -out: |
---|
| 351 | + |
---|
347 | 352 | rcu_read_unlock(); |
---|
348 | 353 | |
---|
349 | 354 | len = sizeof(*kp) * c; |
---|
.. | .. |
---|
352 | 357 | ret = -EFAULT; |
---|
353 | 358 | |
---|
354 | 359 | kfree(kp); |
---|
355 | | - |
---|
| 360 | +out: |
---|
356 | 361 | return ret; |
---|
357 | 362 | } |
---|
358 | 363 | |
---|
.. | .. |
---|
440 | 445 | } |
---|
441 | 446 | } |
---|
442 | 447 | out: |
---|
| 448 | + return err; |
---|
| 449 | +} |
---|
| 450 | + |
---|
| 451 | +static int ipip6_tunnel_prl_ctl(struct net_device *dev, struct ifreq *ifr, |
---|
| 452 | + int cmd) |
---|
| 453 | +{ |
---|
| 454 | + struct ip_tunnel *t = netdev_priv(dev); |
---|
| 455 | + struct ip_tunnel_prl prl; |
---|
| 456 | + int err; |
---|
| 457 | + |
---|
| 458 | + if (!ns_capable(t->net->user_ns, CAP_NET_ADMIN)) |
---|
| 459 | + return -EPERM; |
---|
| 460 | + if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) |
---|
| 461 | + return -EINVAL; |
---|
| 462 | + |
---|
| 463 | + if (copy_from_user(&prl, ifr->ifr_ifru.ifru_data, sizeof(prl))) |
---|
| 464 | + return -EFAULT; |
---|
| 465 | + |
---|
| 466 | + switch (cmd) { |
---|
| 467 | + case SIOCDELPRL: |
---|
| 468 | + err = ipip6_tunnel_del_prl(t, &prl); |
---|
| 469 | + break; |
---|
| 470 | + case SIOCADDPRL: |
---|
| 471 | + case SIOCCHGPRL: |
---|
| 472 | + err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); |
---|
| 473 | + break; |
---|
| 474 | + } |
---|
| 475 | + dst_cache_reset(&t->dst_cache); |
---|
| 476 | + netdev_state_change(dev); |
---|
443 | 477 | return err; |
---|
444 | 478 | } |
---|
445 | 479 | |
---|
.. | .. |
---|
532 | 566 | |
---|
533 | 567 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { |
---|
534 | 568 | ipv4_update_pmtu(skb, dev_net(skb->dev), info, |
---|
535 | | - t->parms.link, 0, iph->protocol, 0); |
---|
| 569 | + t->parms.link, iph->protocol); |
---|
536 | 570 | err = 0; |
---|
537 | 571 | goto out; |
---|
538 | 572 | } |
---|
539 | 573 | if (type == ICMP_REDIRECT) { |
---|
540 | | - ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0, |
---|
541 | | - iph->protocol, 0); |
---|
| 574 | + ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, |
---|
| 575 | + iph->protocol); |
---|
542 | 576 | err = 0; |
---|
543 | 577 | goto out; |
---|
544 | 578 | } |
---|
.. | .. |
---|
902 | 936 | RT_TOS(tos), RT_SCOPE_UNIVERSE, IPPROTO_IPV6, |
---|
903 | 937 | 0, dst, tiph->saddr, 0, 0, |
---|
904 | 938 | sock_net_uid(tunnel->net, NULL)); |
---|
905 | | - rt = ip_route_output_flow(tunnel->net, &fl4, NULL); |
---|
906 | 939 | |
---|
907 | | - if (IS_ERR(rt)) { |
---|
908 | | - dev->stats.tx_carrier_errors++; |
---|
909 | | - goto tx_error_icmp; |
---|
| 940 | + rt = dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr); |
---|
| 941 | + if (!rt) { |
---|
| 942 | + rt = ip_route_output_flow(tunnel->net, &fl4, NULL); |
---|
| 943 | + if (IS_ERR(rt)) { |
---|
| 944 | + dev->stats.tx_carrier_errors++; |
---|
| 945 | + goto tx_error_icmp; |
---|
| 946 | + } |
---|
| 947 | + dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst, fl4.saddr); |
---|
910 | 948 | } |
---|
| 949 | + |
---|
911 | 950 | if (rt->rt_type != RTN_UNICAST) { |
---|
912 | 951 | ip_rt_put(rt); |
---|
913 | 952 | dev->stats.tx_carrier_errors++; |
---|
.. | .. |
---|
944 | 983 | skb_dst_update_pmtu_no_confirm(skb, mtu); |
---|
945 | 984 | |
---|
946 | 985 | if (skb->len > mtu && !skb_is_gso(skb)) { |
---|
947 | | - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
---|
| 986 | + icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
---|
948 | 987 | ip_rt_put(rt); |
---|
949 | 988 | goto tx_error; |
---|
950 | 989 | } |
---|
.. | .. |
---|
1055 | 1094 | |
---|
1056 | 1095 | static void ipip6_tunnel_bind_dev(struct net_device *dev) |
---|
1057 | 1096 | { |
---|
| 1097 | + struct ip_tunnel *tunnel = netdev_priv(dev); |
---|
| 1098 | + int t_hlen = tunnel->hlen + sizeof(struct iphdr); |
---|
1058 | 1099 | struct net_device *tdev = NULL; |
---|
1059 | | - struct ip_tunnel *tunnel; |
---|
| 1100 | + int hlen = LL_MAX_HEADER; |
---|
1060 | 1101 | const struct iphdr *iph; |
---|
1061 | 1102 | struct flowi4 fl4; |
---|
1062 | 1103 | |
---|
1063 | | - tunnel = netdev_priv(dev); |
---|
1064 | 1104 | iph = &tunnel->parms.iph; |
---|
1065 | 1105 | |
---|
1066 | 1106 | if (iph->daddr) { |
---|
.. | .. |
---|
1083 | 1123 | tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link); |
---|
1084 | 1124 | |
---|
1085 | 1125 | if (tdev && !netif_is_l3_master(tdev)) { |
---|
1086 | | - int t_hlen = tunnel->hlen + sizeof(struct iphdr); |
---|
| 1126 | + int mtu; |
---|
1087 | 1127 | |
---|
1088 | | - dev->mtu = tdev->mtu - t_hlen; |
---|
1089 | | - if (dev->mtu < IPV6_MIN_MTU) |
---|
1090 | | - dev->mtu = IPV6_MIN_MTU; |
---|
| 1128 | + mtu = tdev->mtu - t_hlen; |
---|
| 1129 | + if (mtu < IPV6_MIN_MTU) |
---|
| 1130 | + mtu = IPV6_MIN_MTU; |
---|
| 1131 | + WRITE_ONCE(dev->mtu, mtu); |
---|
| 1132 | + hlen = tdev->hard_header_len + tdev->needed_headroom; |
---|
1091 | 1133 | } |
---|
| 1134 | + dev->needed_headroom = t_hlen + hlen; |
---|
1092 | 1135 | } |
---|
1093 | 1136 | |
---|
1094 | 1137 | static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p, |
---|
.. | .. |
---|
1147 | 1190 | netdev_state_change(t->dev); |
---|
1148 | 1191 | return 0; |
---|
1149 | 1192 | } |
---|
1150 | | -#endif |
---|
| 1193 | + |
---|
| 1194 | +static int |
---|
| 1195 | +ipip6_tunnel_get6rd(struct net_device *dev, struct ifreq *ifr) |
---|
| 1196 | +{ |
---|
| 1197 | + struct ip_tunnel *t = netdev_priv(dev); |
---|
| 1198 | + struct ip_tunnel_6rd ip6rd; |
---|
| 1199 | + struct ip_tunnel_parm p; |
---|
| 1200 | + |
---|
| 1201 | + if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) { |
---|
| 1202 | + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) |
---|
| 1203 | + return -EFAULT; |
---|
| 1204 | + t = ipip6_tunnel_locate(t->net, &p, 0); |
---|
| 1205 | + } |
---|
| 1206 | + if (!t) |
---|
| 1207 | + t = netdev_priv(dev); |
---|
| 1208 | + |
---|
| 1209 | + ip6rd.prefix = t->ip6rd.prefix; |
---|
| 1210 | + ip6rd.relay_prefix = t->ip6rd.relay_prefix; |
---|
| 1211 | + ip6rd.prefixlen = t->ip6rd.prefixlen; |
---|
| 1212 | + ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen; |
---|
| 1213 | + if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd, sizeof(ip6rd))) |
---|
| 1214 | + return -EFAULT; |
---|
| 1215 | + return 0; |
---|
| 1216 | +} |
---|
| 1217 | + |
---|
| 1218 | +static int |
---|
| 1219 | +ipip6_tunnel_6rdctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
---|
| 1220 | +{ |
---|
| 1221 | + struct ip_tunnel *t = netdev_priv(dev); |
---|
| 1222 | + struct ip_tunnel_6rd ip6rd; |
---|
| 1223 | + int err; |
---|
| 1224 | + |
---|
| 1225 | + if (!ns_capable(t->net->user_ns, CAP_NET_ADMIN)) |
---|
| 1226 | + return -EPERM; |
---|
| 1227 | + if (copy_from_user(&ip6rd, ifr->ifr_ifru.ifru_data, sizeof(ip6rd))) |
---|
| 1228 | + return -EFAULT; |
---|
| 1229 | + |
---|
| 1230 | + if (cmd != SIOCDEL6RD) { |
---|
| 1231 | + err = ipip6_tunnel_update_6rd(t, &ip6rd); |
---|
| 1232 | + if (err < 0) |
---|
| 1233 | + return err; |
---|
| 1234 | + } else |
---|
| 1235 | + ipip6_tunnel_clone_6rd(dev, dev_to_sit_net(dev)); |
---|
| 1236 | + return 0; |
---|
| 1237 | +} |
---|
| 1238 | + |
---|
| 1239 | +#endif /* CONFIG_IPV6_SIT_6RD */ |
---|
1151 | 1240 | |
---|
1152 | 1241 | static bool ipip6_valid_ip_proto(u8 ipproto) |
---|
1153 | 1242 | { |
---|
.. | .. |
---|
1160 | 1249 | } |
---|
1161 | 1250 | |
---|
1162 | 1251 | static int |
---|
1163 | | -ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
---|
| 1252 | +__ipip6_tunnel_ioctl_validate(struct net *net, struct ip_tunnel_parm *p) |
---|
1164 | 1253 | { |
---|
1165 | | - int err = 0; |
---|
1166 | | - struct ip_tunnel_parm p; |
---|
1167 | | - struct ip_tunnel_prl prl; |
---|
1168 | | - struct ip_tunnel *t = netdev_priv(dev); |
---|
1169 | | - struct net *net = t->net; |
---|
1170 | | - struct sit_net *sitn = net_generic(net, sit_net_id); |
---|
1171 | | -#ifdef CONFIG_IPV6_SIT_6RD |
---|
1172 | | - struct ip_tunnel_6rd ip6rd; |
---|
1173 | | -#endif |
---|
| 1254 | + if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
---|
| 1255 | + return -EPERM; |
---|
1174 | 1256 | |
---|
| 1257 | + if (!ipip6_valid_ip_proto(p->iph.protocol)) |
---|
| 1258 | + return -EINVAL; |
---|
| 1259 | + if (p->iph.version != 4 || |
---|
| 1260 | + p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF))) |
---|
| 1261 | + return -EINVAL; |
---|
| 1262 | + |
---|
| 1263 | + if (p->iph.ttl) |
---|
| 1264 | + p->iph.frag_off |= htons(IP_DF); |
---|
| 1265 | + return 0; |
---|
| 1266 | +} |
---|
| 1267 | + |
---|
| 1268 | +static int |
---|
| 1269 | +ipip6_tunnel_get(struct net_device *dev, struct ip_tunnel_parm *p) |
---|
| 1270 | +{ |
---|
| 1271 | + struct ip_tunnel *t = netdev_priv(dev); |
---|
| 1272 | + |
---|
| 1273 | + if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) |
---|
| 1274 | + t = ipip6_tunnel_locate(t->net, p, 0); |
---|
| 1275 | + if (!t) |
---|
| 1276 | + t = netdev_priv(dev); |
---|
| 1277 | + memcpy(p, &t->parms, sizeof(*p)); |
---|
| 1278 | + return 0; |
---|
| 1279 | +} |
---|
| 1280 | + |
---|
| 1281 | +static int |
---|
| 1282 | +ipip6_tunnel_add(struct net_device *dev, struct ip_tunnel_parm *p) |
---|
| 1283 | +{ |
---|
| 1284 | + struct ip_tunnel *t = netdev_priv(dev); |
---|
| 1285 | + int err; |
---|
| 1286 | + |
---|
| 1287 | + err = __ipip6_tunnel_ioctl_validate(t->net, p); |
---|
| 1288 | + if (err) |
---|
| 1289 | + return err; |
---|
| 1290 | + |
---|
| 1291 | + t = ipip6_tunnel_locate(t->net, p, 1); |
---|
| 1292 | + if (!t) |
---|
| 1293 | + return -ENOBUFS; |
---|
| 1294 | + return 0; |
---|
| 1295 | +} |
---|
| 1296 | + |
---|
| 1297 | +static int |
---|
| 1298 | +ipip6_tunnel_change(struct net_device *dev, struct ip_tunnel_parm *p) |
---|
| 1299 | +{ |
---|
| 1300 | + struct ip_tunnel *t = netdev_priv(dev); |
---|
| 1301 | + int err; |
---|
| 1302 | + |
---|
| 1303 | + err = __ipip6_tunnel_ioctl_validate(t->net, p); |
---|
| 1304 | + if (err) |
---|
| 1305 | + return err; |
---|
| 1306 | + |
---|
| 1307 | + t = ipip6_tunnel_locate(t->net, p, 0); |
---|
| 1308 | + if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) { |
---|
| 1309 | + if (!t) |
---|
| 1310 | + return -ENOENT; |
---|
| 1311 | + } else { |
---|
| 1312 | + if (t) { |
---|
| 1313 | + if (t->dev != dev) |
---|
| 1314 | + return -EEXIST; |
---|
| 1315 | + } else { |
---|
| 1316 | + if (((dev->flags & IFF_POINTOPOINT) && !p->iph.daddr) || |
---|
| 1317 | + (!(dev->flags & IFF_POINTOPOINT) && p->iph.daddr)) |
---|
| 1318 | + return -EINVAL; |
---|
| 1319 | + t = netdev_priv(dev); |
---|
| 1320 | + } |
---|
| 1321 | + |
---|
| 1322 | + ipip6_tunnel_update(t, p, t->fwmark); |
---|
| 1323 | + } |
---|
| 1324 | + |
---|
| 1325 | + return 0; |
---|
| 1326 | +} |
---|
| 1327 | + |
---|
| 1328 | +static int |
---|
| 1329 | +ipip6_tunnel_del(struct net_device *dev, struct ip_tunnel_parm *p) |
---|
| 1330 | +{ |
---|
| 1331 | + struct ip_tunnel *t = netdev_priv(dev); |
---|
| 1332 | + |
---|
| 1333 | + if (!ns_capable(t->net->user_ns, CAP_NET_ADMIN)) |
---|
| 1334 | + return -EPERM; |
---|
| 1335 | + |
---|
| 1336 | + if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) { |
---|
| 1337 | + t = ipip6_tunnel_locate(t->net, p, 0); |
---|
| 1338 | + if (!t) |
---|
| 1339 | + return -ENOENT; |
---|
| 1340 | + if (t == netdev_priv(dev_to_sit_net(dev)->fb_tunnel_dev)) |
---|
| 1341 | + return -EPERM; |
---|
| 1342 | + dev = t->dev; |
---|
| 1343 | + } |
---|
| 1344 | + unregister_netdevice(dev); |
---|
| 1345 | + return 0; |
---|
| 1346 | +} |
---|
| 1347 | + |
---|
| 1348 | +static int |
---|
| 1349 | +ipip6_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd) |
---|
| 1350 | +{ |
---|
1175 | 1351 | switch (cmd) { |
---|
1176 | 1352 | case SIOCGETTUNNEL: |
---|
1177 | | -#ifdef CONFIG_IPV6_SIT_6RD |
---|
1178 | | - case SIOCGET6RD: |
---|
1179 | | -#endif |
---|
1180 | | - if (dev == sitn->fb_tunnel_dev) { |
---|
1181 | | - if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { |
---|
1182 | | - err = -EFAULT; |
---|
1183 | | - break; |
---|
1184 | | - } |
---|
1185 | | - t = ipip6_tunnel_locate(net, &p, 0); |
---|
1186 | | - if (!t) |
---|
1187 | | - t = netdev_priv(dev); |
---|
1188 | | - } |
---|
| 1353 | + return ipip6_tunnel_get(dev, p); |
---|
| 1354 | + case SIOCADDTUNNEL: |
---|
| 1355 | + return ipip6_tunnel_add(dev, p); |
---|
| 1356 | + case SIOCCHGTUNNEL: |
---|
| 1357 | + return ipip6_tunnel_change(dev, p); |
---|
| 1358 | + case SIOCDELTUNNEL: |
---|
| 1359 | + return ipip6_tunnel_del(dev, p); |
---|
| 1360 | + default: |
---|
| 1361 | + return -EINVAL; |
---|
| 1362 | + } |
---|
| 1363 | +} |
---|
1189 | 1364 | |
---|
1190 | | - err = -EFAULT; |
---|
1191 | | - if (cmd == SIOCGETTUNNEL) { |
---|
1192 | | - memcpy(&p, &t->parms, sizeof(p)); |
---|
1193 | | - if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, |
---|
1194 | | - sizeof(p))) |
---|
1195 | | - goto done; |
---|
1196 | | -#ifdef CONFIG_IPV6_SIT_6RD |
---|
1197 | | - } else { |
---|
1198 | | - ip6rd.prefix = t->ip6rd.prefix; |
---|
1199 | | - ip6rd.relay_prefix = t->ip6rd.relay_prefix; |
---|
1200 | | - ip6rd.prefixlen = t->ip6rd.prefixlen; |
---|
1201 | | - ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen; |
---|
1202 | | - if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd, |
---|
1203 | | - sizeof(ip6rd))) |
---|
1204 | | - goto done; |
---|
1205 | | -#endif |
---|
1206 | | - } |
---|
1207 | | - err = 0; |
---|
1208 | | - break; |
---|
1209 | | - |
---|
| 1365 | +static int |
---|
| 1366 | +ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
---|
| 1367 | +{ |
---|
| 1368 | + switch (cmd) { |
---|
| 1369 | + case SIOCGETTUNNEL: |
---|
1210 | 1370 | case SIOCADDTUNNEL: |
---|
1211 | 1371 | case SIOCCHGTUNNEL: |
---|
1212 | | - err = -EPERM; |
---|
1213 | | - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
---|
1214 | | - goto done; |
---|
1215 | | - |
---|
1216 | | - err = -EFAULT; |
---|
1217 | | - if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) |
---|
1218 | | - goto done; |
---|
1219 | | - |
---|
1220 | | - err = -EINVAL; |
---|
1221 | | - if (!ipip6_valid_ip_proto(p.iph.protocol)) |
---|
1222 | | - goto done; |
---|
1223 | | - if (p.iph.version != 4 || |
---|
1224 | | - p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF))) |
---|
1225 | | - goto done; |
---|
1226 | | - if (p.iph.ttl) |
---|
1227 | | - p.iph.frag_off |= htons(IP_DF); |
---|
1228 | | - |
---|
1229 | | - t = ipip6_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL); |
---|
1230 | | - |
---|
1231 | | - if (dev != sitn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { |
---|
1232 | | - if (t) { |
---|
1233 | | - if (t->dev != dev) { |
---|
1234 | | - err = -EEXIST; |
---|
1235 | | - break; |
---|
1236 | | - } |
---|
1237 | | - } else { |
---|
1238 | | - if (((dev->flags&IFF_POINTOPOINT) && !p.iph.daddr) || |
---|
1239 | | - (!(dev->flags&IFF_POINTOPOINT) && p.iph.daddr)) { |
---|
1240 | | - err = -EINVAL; |
---|
1241 | | - break; |
---|
1242 | | - } |
---|
1243 | | - t = netdev_priv(dev); |
---|
1244 | | - } |
---|
1245 | | - |
---|
1246 | | - ipip6_tunnel_update(t, &p, t->fwmark); |
---|
1247 | | - } |
---|
1248 | | - |
---|
1249 | | - if (t) { |
---|
1250 | | - err = 0; |
---|
1251 | | - if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p))) |
---|
1252 | | - err = -EFAULT; |
---|
1253 | | - } else |
---|
1254 | | - err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT); |
---|
1255 | | - break; |
---|
1256 | | - |
---|
1257 | 1372 | case SIOCDELTUNNEL: |
---|
1258 | | - err = -EPERM; |
---|
1259 | | - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
---|
1260 | | - goto done; |
---|
1261 | | - |
---|
1262 | | - if (dev == sitn->fb_tunnel_dev) { |
---|
1263 | | - err = -EFAULT; |
---|
1264 | | - if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) |
---|
1265 | | - goto done; |
---|
1266 | | - err = -ENOENT; |
---|
1267 | | - t = ipip6_tunnel_locate(net, &p, 0); |
---|
1268 | | - if (!t) |
---|
1269 | | - goto done; |
---|
1270 | | - err = -EPERM; |
---|
1271 | | - if (t == netdev_priv(sitn->fb_tunnel_dev)) |
---|
1272 | | - goto done; |
---|
1273 | | - dev = t->dev; |
---|
1274 | | - } |
---|
1275 | | - unregister_netdevice(dev); |
---|
1276 | | - err = 0; |
---|
1277 | | - break; |
---|
1278 | | - |
---|
| 1373 | + return ip_tunnel_ioctl(dev, ifr, cmd); |
---|
1279 | 1374 | case SIOCGETPRL: |
---|
1280 | | - err = -EINVAL; |
---|
1281 | | - if (dev == sitn->fb_tunnel_dev) |
---|
1282 | | - goto done; |
---|
1283 | | - err = ipip6_tunnel_get_prl(t, ifr->ifr_ifru.ifru_data); |
---|
1284 | | - break; |
---|
1285 | | - |
---|
| 1375 | + return ipip6_tunnel_get_prl(dev, ifr); |
---|
1286 | 1376 | case SIOCADDPRL: |
---|
1287 | 1377 | case SIOCDELPRL: |
---|
1288 | 1378 | case SIOCCHGPRL: |
---|
1289 | | - err = -EPERM; |
---|
1290 | | - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
---|
1291 | | - goto done; |
---|
1292 | | - err = -EINVAL; |
---|
1293 | | - if (dev == sitn->fb_tunnel_dev) |
---|
1294 | | - goto done; |
---|
1295 | | - err = -EFAULT; |
---|
1296 | | - if (copy_from_user(&prl, ifr->ifr_ifru.ifru_data, sizeof(prl))) |
---|
1297 | | - goto done; |
---|
1298 | | - |
---|
1299 | | - switch (cmd) { |
---|
1300 | | - case SIOCDELPRL: |
---|
1301 | | - err = ipip6_tunnel_del_prl(t, &prl); |
---|
1302 | | - break; |
---|
1303 | | - case SIOCADDPRL: |
---|
1304 | | - case SIOCCHGPRL: |
---|
1305 | | - err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); |
---|
1306 | | - break; |
---|
1307 | | - } |
---|
1308 | | - dst_cache_reset(&t->dst_cache); |
---|
1309 | | - netdev_state_change(dev); |
---|
1310 | | - break; |
---|
1311 | | - |
---|
| 1379 | + return ipip6_tunnel_prl_ctl(dev, ifr, cmd); |
---|
1312 | 1380 | #ifdef CONFIG_IPV6_SIT_6RD |
---|
| 1381 | + case SIOCGET6RD: |
---|
| 1382 | + return ipip6_tunnel_get6rd(dev, ifr); |
---|
1313 | 1383 | case SIOCADD6RD: |
---|
1314 | 1384 | case SIOCCHG6RD: |
---|
1315 | 1385 | case SIOCDEL6RD: |
---|
1316 | | - err = -EPERM; |
---|
1317 | | - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
---|
1318 | | - goto done; |
---|
1319 | | - |
---|
1320 | | - err = -EFAULT; |
---|
1321 | | - if (copy_from_user(&ip6rd, ifr->ifr_ifru.ifru_data, |
---|
1322 | | - sizeof(ip6rd))) |
---|
1323 | | - goto done; |
---|
1324 | | - |
---|
1325 | | - if (cmd != SIOCDEL6RD) { |
---|
1326 | | - err = ipip6_tunnel_update_6rd(t, &ip6rd); |
---|
1327 | | - if (err < 0) |
---|
1328 | | - goto done; |
---|
1329 | | - } else |
---|
1330 | | - ipip6_tunnel_clone_6rd(dev, sitn); |
---|
1331 | | - |
---|
1332 | | - err = 0; |
---|
1333 | | - break; |
---|
| 1386 | + return ipip6_tunnel_6rdctl(dev, ifr, cmd); |
---|
1334 | 1387 | #endif |
---|
1335 | | - |
---|
1336 | 1388 | default: |
---|
1337 | | - err = -EINVAL; |
---|
| 1389 | + return -EINVAL; |
---|
1338 | 1390 | } |
---|
1339 | | - |
---|
1340 | | -done: |
---|
1341 | | - return err; |
---|
1342 | 1391 | } |
---|
1343 | 1392 | |
---|
1344 | 1393 | static const struct net_device_ops ipip6_netdev_ops = { |
---|
.. | .. |
---|
1348 | 1397 | .ndo_do_ioctl = ipip6_tunnel_ioctl, |
---|
1349 | 1398 | .ndo_get_stats64 = ip_tunnel_get_stats64, |
---|
1350 | 1399 | .ndo_get_iflink = ip_tunnel_get_iflink, |
---|
| 1400 | + .ndo_tunnel_ctl = ipip6_tunnel_ctl, |
---|
1351 | 1401 | }; |
---|
1352 | 1402 | |
---|
1353 | 1403 | static void ipip6_dev_free(struct net_device *dev) |
---|
.. | .. |
---|
1370 | 1420 | int t_hlen = tunnel->hlen + sizeof(struct iphdr); |
---|
1371 | 1421 | |
---|
1372 | 1422 | dev->netdev_ops = &ipip6_netdev_ops; |
---|
| 1423 | + dev->header_ops = &ip_tunnel_header_ops; |
---|
1373 | 1424 | dev->needs_free_netdev = true; |
---|
1374 | 1425 | dev->priv_destructor = ipip6_dev_free; |
---|
1375 | 1426 | |
---|