diff options
Diffstat (limited to 'drivers/net/usb/lg-vl600.c')
-rw-r--r-- | drivers/net/usb/lg-vl600.c | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c index 1d83ccfd727..9c26c6390d6 100644 --- a/drivers/net/usb/lg-vl600.c +++ b/drivers/net/usb/lg-vl600.c @@ -27,6 +27,7 @@ #include <linux/if_ether.h> #include <linux/if_arp.h> #include <linux/inetdevice.h> +#include <linux/module.h> /* * The device has a CDC ACM port for modem control (it claims to be @@ -89,6 +90,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; } @@ -141,10 +144,11 @@ static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } frame = (struct vl600_frame_hdr *) buf->data; - /* NOTE: Should check that frame->magic == 0x53544448? - * Otherwise if we receive garbage at the beginning of the frame - * we may end up allocating a huge buffer and saving all the - * future incoming data into it. */ + /* Yes, check that frame->magic == 0x53544448 (or 0x44544d48), + * otherwise we may run out of memory w/a bad packet */ + if (ntohl(frame->magic) != 0x53544448 && + ntohl(frame->magic) != 0x44544d48) + goto error; if (buf->len < sizeof(*frame) || buf->len != le32_to_cpup(&frame->len)) { @@ -200,6 +204,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) { @@ -285,6 +297,11 @@ encapsulate: * overwrite the remaining fields. */ packet = (struct vl600_pkt_hdr *) skb->data; + /* The VL600 wants IPv6 packets to have an IPv4 ethertype + * Since this modem only supports IPv4 and IPv6, just set all + * frames to 0x0800 (ETH_P_IP) + */ + packet->h_proto = htons(ETH_P_IP); memset(&packet->dummy, 0, sizeof(packet->dummy)); packet->len = cpu_to_le32(orig_len); @@ -302,7 +319,7 @@ encapsulate: static const struct driver_info vl600_info = { .description = "LG VL600 modem", - .flags = FLAG_ETHER | FLAG_RX_ASSEMBLE, + .flags = FLAG_RX_ASSEMBLE | FLAG_WWAN, .bind = vl600_bind, .unbind = vl600_unbind, .status = usbnet_cdc_status, |