From patchwork Thu Oct 31 14:56:10 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Bj=C3=B8rn_Mork?= X-Patchwork-Id: 287509 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 501C92C00E2 for ; Fri, 1 Nov 2013 02:02:28 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755246Ab3JaPCS (ORCPT ); Thu, 31 Oct 2013 11:02:18 -0400 Received: from canardo.mork.no ([148.122.252.1]:34830 "EHLO canardo.mork.no" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754738Ab3JaPCQ (ORCPT ); Thu, 31 Oct 2013 11:02:16 -0400 Received: from nemi.mork.no (ip6-localhost [IPv6:::1]) by canardo.mork.no (8.14.4/8.14.4) with ESMTP id r9VF25s5027375 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NOT); Thu, 31 Oct 2013 16:02:06 +0100 Received: from bjorn by nemi.mork.no with local (Exim 4.80) (envelope-from ) id 1VbtfW-00027B-7t; Thu, 31 Oct 2013 15:56:18 +0100 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= To: netdev@vger.kernel.org Cc: Alexey Orishko , Greg Suarez , =?UTF-8?q?Bj=C3=B8rn=20Mork?= Subject: [PATCH net-next 1/2] net: cdc_mbim: handle IPv6 Neigbor Solicitations Date: Thu, 31 Oct 2013 15:56:10 +0100 Message-Id: <1383231371-8098-2-git-send-email-bjorn@mork.no> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1383231371-8098-1-git-send-email-bjorn@mork.no> References: <1383231371-8098-1-git-send-email-bjorn@mork.no> MIME-Version: 1.0 X-Spam-Status: No, score=-2.4 required=5.0 tests=ALL_TRUSTED,AWL,BAYES_00 autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on canardo.mork.no X-Virus-Scanned: clamav-milter 0.97.8 at canardo X-Virus-Status: Clean Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org MBIM is a point-to-point protocol transporting raw IP packets with no L2 headers. Only IPv4 and IPv6 are supported. ARP in particular is not, which is quite logical given the lack of L2 headers. The driver still emulates an ethernet interface, dropping all unsupported protocols, and avoiding neigbour resolving by setting the IFF_NOARP flag. The MBIM specification does not explicitly forbid IPv6 Neighbor Discovery, and it seems the other OS support will respond to Neighbor Solicitations on MBIM links. There are therefore buggy devices out there, which despite the pointlessness, still require Neighbor Discovery for IPv6 over MBIM. This is incompatible with the IFF_NOARP flag which disables both ARP and ND. We cannot support ARP in any case, so we have to keep that flag. This patch implements a workaround for the buggy devices, letting the driver respond directly to Neighbor Solicitations from the device. This is not optimal, but will have minimal effect on any sane device. Cc: Greg Suarez Reported-and-tested-by: Thomas Schäfer Signed-off-by: Bjørn Mork --- drivers/net/usb/cdc_mbim.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index 25ba7ec..6533a9f 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include /* driver specific data - must match cdc_ncm usage */ struct cdc_mbim_state { @@ -184,6 +186,60 @@ error: return NULL; } +/* Some devices are known to send Neigbor Solicitation messages and + * require Neigbor Advertisement replies. The IPv6 core will not + * respond since IFF_NOARP is set, so we must handle them ourselves. + */ +static void do_neigh_solicit(struct usbnet *dev, u8 *buf, u16 tci) +{ + struct ipv6hdr *iph = (void *)buf; + struct nd_msg *msg = (void *)(iph + 1); + struct net_device *netdev; + struct inet6_dev *in6_dev; + bool is_router; + + /* we'll only respond to requests from unicast addresses to + * our solicited node addresses. + */ + if (!ipv6_addr_is_solict_mult(&iph->daddr) || + !(ipv6_addr_type(&iph->saddr) & IPV6_ADDR_UNICAST)) + return; + + /* need to send the NA on the VLAN dev, if any */ + if (tci) + netdev = __vlan_find_dev_deep(dev->net, htons(ETH_P_8021Q), + tci); + else + netdev = dev->net; + if (!netdev) + return; + + in6_dev = in6_dev_get(netdev); + if (!in6_dev) + return; + is_router = !!in6_dev->cnf.forwarding; + in6_dev_put(in6_dev); + + /* ipv6_stub != NULL if in6_dev_get returned an inet6_dev */ + ipv6_stub->ndisc_send_na(netdev, NULL, &iph->saddr, &msg->target, + is_router /* router */, + true /* solicited */, + false /* override */, + true /* inc_opt */); +} + +static bool is_neigh_solicit(u8 *buf, size_t len) +{ + struct ipv6hdr *iph = (void *)buf; + struct nd_msg *msg = (void *)(iph + 1); + + return (len >= sizeof(struct ipv6hdr) + sizeof(struct nd_msg) && + iph->nexthdr == IPPROTO_ICMPV6 && + msg->icmph.icmp6_code == 0 && + msg->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION); +} + + static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_t len, u16 tci) { __be16 proto = htons(ETH_P_802_3); @@ -198,6 +254,8 @@ static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_ proto = htons(ETH_P_IP); break; case 0x60: + if (is_neigh_solicit(buf, len)) + do_neigh_solicit(dev, buf, tci); proto = htons(ETH_P_IPV6); break; default: