diff --git a/[refs] b/[refs] index 5c1451820c43..1a5d9d537274 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 8a4cadc708f04a2a463bc3df0f16859b31d4b051 +refs/heads/master: 2ae40ee9872953b4f329a54c82970dfb6854e17e diff --git a/trunk/drivers/net/usb/lg-vl600.c b/trunk/drivers/net/usb/lg-vl600.c index 1d83ccfd7277..1e7221951056 100644 --- a/trunk/drivers/net/usb/lg-vl600.c +++ b/trunk/drivers/net/usb/lg-vl600.c @@ -89,6 +89,8 @@ static int vl600_bind(struct usbnet *dev, struct usb_interface *intf) * addresses have no meaning, the destination and the source of every * packet depend only on whether it is on the IN or OUT endpoint. */ dev->net->flags |= IFF_NOARP; + /* IPv6 NDP relies on multicast. Enable it by default. */ + dev->net->flags |= IFF_MULTICAST; return ret; } @@ -200,6 +202,14 @@ static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } else { memset(ethhdr->h_source, 0, ETH_ALEN); memcpy(ethhdr->h_dest, dev->net->dev_addr, ETH_ALEN); + + /* Inbound IPv6 packets have an IPv4 ethertype (0x800) + * for some reason. Peek at the L3 header to check + * for IPv6 packets, and set the ethertype to IPv6 + * (0x86dd) so Linux can understand it. + */ + if ((buf->data[sizeof(*ethhdr)] & 0xf0) == 0x60) + ethhdr->h_proto = __constant_htons(ETH_P_IPV6); } if (count) { @@ -297,6 +307,15 @@ static struct sk_buff *vl600_tx_fixup(struct usbnet *dev, if (skb->len < full_len) /* Pad */ skb_put(skb, full_len - skb->len); + /* The VL600 wants IPv6 packets to have an IPv4 ethertype + * Check if this is an IPv6 packet, and set the ethertype + * to 0x800 + */ + if ((skb->data[sizeof(struct vl600_pkt_hdr *) + 0x22] & 0xf0) == 0x60) { + skb->data[sizeof(struct vl600_pkt_hdr *) + 0x20] = 0x08; + skb->data[sizeof(struct vl600_pkt_hdr *) + 0x21] = 0; + } + return skb; }