|
17 | 17 | #include <linux/mutex.h>
|
18 | 18 | #include <linux/if_vlan.h>
|
19 | 19 |
|
| 20 | +#if IS_ENABLED(CONFIG_IPV6) |
| 21 | +#include <linux/icmpv6.h> |
| 22 | +#endif |
| 23 | + |
| 24 | +#include <net/icmp.h> |
| 25 | +#include <net/route.h> |
| 26 | + |
20 | 27 | #include <asm/vio.h>
|
21 | 28 | #include <asm/ldc.h>
|
22 | 29 |
|
@@ -913,8 +920,36 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
913 | 920 | if (unlikely(!skb))
|
914 | 921 | goto out_dropped;
|
915 | 922 |
|
916 |
| - if (skb->len > port->rmtu) |
| 923 | + if (skb->len > port->rmtu) { |
| 924 | + unsigned long localmtu = port->rmtu - ETH_HLEN; |
| 925 | + |
| 926 | + if (vio_version_after_eq(&port->vio, 1, 3)) |
| 927 | + localmtu -= VLAN_HLEN; |
| 928 | + |
| 929 | + if (skb->protocol == htons(ETH_P_IP)) { |
| 930 | + struct flowi4 fl4; |
| 931 | + struct rtable *rt = NULL; |
| 932 | + |
| 933 | + memset(&fl4, 0, sizeof(fl4)); |
| 934 | + fl4.flowi4_oif = dev->ifindex; |
| 935 | + fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); |
| 936 | + fl4.daddr = ip_hdr(skb)->daddr; |
| 937 | + fl4.saddr = ip_hdr(skb)->saddr; |
| 938 | + |
| 939 | + rt = ip_route_output_key(dev_net(dev), &fl4); |
| 940 | + if (!IS_ERR(rt)) { |
| 941 | + skb_dst_set(skb, &rt->dst); |
| 942 | + icmp_send(skb, ICMP_DEST_UNREACH, |
| 943 | + ICMP_FRAG_NEEDED, |
| 944 | + htonl(localmtu)); |
| 945 | + } |
| 946 | + } |
| 947 | +#if IS_ENABLED(CONFIG_IPV6) |
| 948 | + else if (skb->protocol == htons(ETH_P_IPV6)) |
| 949 | + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, localmtu); |
| 950 | +#endif |
917 | 951 | goto out_dropped;
|
| 952 | + } |
918 | 953 |
|
919 | 954 | spin_lock_irqsave(&port->vio.lock, flags);
|
920 | 955 |
|
|
0 commit comments