|
@@ -17,6 +17,13 @@
|
|
|
#include <linux/mutex.h>
|
|
|
#include <linux/if_vlan.h>
|
|
|
|
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
|
+#include <linux/icmpv6.h>
|
|
|
+#endif
|
|
|
+
|
|
|
+#include <net/icmp.h>
|
|
|
+#include <net/route.h>
|
|
|
+
|
|
|
#include <asm/vio.h>
|
|
|
#include <asm/ldc.h>
|
|
|
|
|
@@ -913,8 +920,36 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
|
if (unlikely(!skb))
|
|
|
goto out_dropped;
|
|
|
|
|
|
- if (skb->len > port->rmtu)
|
|
|
+ if (skb->len > port->rmtu) {
|
|
|
+ unsigned long localmtu = port->rmtu - ETH_HLEN;
|
|
|
+
|
|
|
+ if (vio_version_after_eq(&port->vio, 1, 3))
|
|
|
+ localmtu -= VLAN_HLEN;
|
|
|
+
|
|
|
+ if (skb->protocol == htons(ETH_P_IP)) {
|
|
|
+ struct flowi4 fl4;
|
|
|
+ struct rtable *rt = NULL;
|
|
|
+
|
|
|
+ memset(&fl4, 0, sizeof(fl4));
|
|
|
+ fl4.flowi4_oif = dev->ifindex;
|
|
|
+ fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
|
|
|
+ fl4.daddr = ip_hdr(skb)->daddr;
|
|
|
+ fl4.saddr = ip_hdr(skb)->saddr;
|
|
|
+
|
|
|
+ rt = ip_route_output_key(dev_net(dev), &fl4);
|
|
|
+ if (!IS_ERR(rt)) {
|
|
|
+ skb_dst_set(skb, &rt->dst);
|
|
|
+ icmp_send(skb, ICMP_DEST_UNREACH,
|
|
|
+ ICMP_FRAG_NEEDED,
|
|
|
+ htonl(localmtu));
|
|
|
+ }
|
|
|
+ }
|
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
|
+ else if (skb->protocol == htons(ETH_P_IPV6))
|
|
|
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, localmtu);
|
|
|
+#endif
|
|
|
goto out_dropped;
|
|
|
+ }
|
|
|
|
|
|
spin_lock_irqsave(&port->vio.lock, flags);
|
|
|
|