aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb/cdc_mbim.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/usb/cdc_mbim.c')
-rw-r--r--drivers/net/usb/cdc_mbim.c104
1 files changed, 82 insertions, 22 deletions
diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c
index 25ba7eca9a13..c9f3281506af 100644
--- a/drivers/net/usb/cdc_mbim.c
+++ b/drivers/net/usb/cdc_mbim.c
@@ -21,6 +21,8 @@
21#include <linux/usb/usbnet.h> 21#include <linux/usb/usbnet.h>
22#include <linux/usb/cdc-wdm.h> 22#include <linux/usb/cdc-wdm.h>
23#include <linux/usb/cdc_ncm.h> 23#include <linux/usb/cdc_ncm.h>
24#include <net/ipv6.h>
25#include <net/addrconf.h>
24 26
25/* driver specific data - must match cdc_ncm usage */ 27/* driver specific data - must match cdc_ncm usage */
26struct cdc_mbim_state { 28struct cdc_mbim_state {
@@ -42,13 +44,11 @@ static int cdc_mbim_manage_power(struct usbnet *dev, int on)
42 if ((on && atomic_add_return(1, &info->pmcount) == 1) || (!on && atomic_dec_and_test(&info->pmcount))) { 44 if ((on && atomic_add_return(1, &info->pmcount) == 1) || (!on && atomic_dec_and_test(&info->pmcount))) {
43 /* need autopm_get/put here to ensure the usbcore sees the new value */ 45 /* need autopm_get/put here to ensure the usbcore sees the new value */
44 rv = usb_autopm_get_interface(dev->intf); 46 rv = usb_autopm_get_interface(dev->intf);
45 if (rv < 0)
46 goto err;
47 dev->intf->needs_remote_wakeup = on; 47 dev->intf->needs_remote_wakeup = on;
48 usb_autopm_put_interface(dev->intf); 48 if (!rv)
49 usb_autopm_put_interface(dev->intf);
49 } 50 }
50err: 51 return 0;
51 return rv;
52} 52}
53 53
54static int cdc_mbim_wdm_manage_power(struct usb_interface *intf, int status) 54static int cdc_mbim_wdm_manage_power(struct usb_interface *intf, int status)
@@ -173,7 +173,7 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
173 } 173 }
174 174
175 spin_lock_bh(&ctx->mtx); 175 spin_lock_bh(&ctx->mtx);
176 skb_out = cdc_ncm_fill_tx_frame(ctx, skb, sign); 176 skb_out = cdc_ncm_fill_tx_frame(dev, skb, sign);
177 spin_unlock_bh(&ctx->mtx); 177 spin_unlock_bh(&ctx->mtx);
178 return skb_out; 178 return skb_out;
179 179
@@ -184,6 +184,60 @@ error:
184 return NULL; 184 return NULL;
185} 185}
186 186
187/* Some devices are known to send Neigbor Solicitation messages and
188 * require Neigbor Advertisement replies. The IPv6 core will not
189 * respond since IFF_NOARP is set, so we must handle them ourselves.
190 */
191static void do_neigh_solicit(struct usbnet *dev, u8 *buf, u16 tci)
192{
193 struct ipv6hdr *iph = (void *)buf;
194 struct nd_msg *msg = (void *)(iph + 1);
195 struct net_device *netdev;
196 struct inet6_dev *in6_dev;
197 bool is_router;
198
199 /* we'll only respond to requests from unicast addresses to
200 * our solicited node addresses.
201 */
202 if (!ipv6_addr_is_solict_mult(&iph->daddr) ||
203 !(ipv6_addr_type(&iph->saddr) & IPV6_ADDR_UNICAST))
204 return;
205
206 /* need to send the NA on the VLAN dev, if any */
207 if (tci)
208 netdev = __vlan_find_dev_deep(dev->net, htons(ETH_P_8021Q),
209 tci);
210 else
211 netdev = dev->net;
212 if (!netdev)
213 return;
214
215 in6_dev = in6_dev_get(netdev);
216 if (!in6_dev)
217 return;
218 is_router = !!in6_dev->cnf.forwarding;
219 in6_dev_put(in6_dev);
220
221 /* ipv6_stub != NULL if in6_dev_get returned an inet6_dev */
222 ipv6_stub->ndisc_send_na(netdev, NULL, &iph->saddr, &msg->target,
223 is_router /* router */,
224 true /* solicited */,
225 false /* override */,
226 true /* inc_opt */);
227}
228
229static bool is_neigh_solicit(u8 *buf, size_t len)
230{
231 struct ipv6hdr *iph = (void *)buf;
232 struct nd_msg *msg = (void *)(iph + 1);
233
234 return (len >= sizeof(struct ipv6hdr) + sizeof(struct nd_msg) &&
235 iph->nexthdr == IPPROTO_ICMPV6 &&
236 msg->icmph.icmp6_code == 0 &&
237 msg->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION);
238}
239
240
187static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_t len, u16 tci) 241static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_t len, u16 tci)
188{ 242{
189 __be16 proto = htons(ETH_P_802_3); 243 __be16 proto = htons(ETH_P_802_3);
@@ -198,6 +252,8 @@ static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_
198 proto = htons(ETH_P_IP); 252 proto = htons(ETH_P_IP);
199 break; 253 break;
200 case 0x60: 254 case 0x60:
255 if (is_neigh_solicit(buf, len))
256 do_neigh_solicit(dev, buf, tci);
201 proto = htons(ETH_P_IPV6); 257 proto = htons(ETH_P_IPV6);
202 break; 258 break;
203 default: 259 default:
@@ -313,15 +369,13 @@ error:
313 369
314static int cdc_mbim_suspend(struct usb_interface *intf, pm_message_t message) 370static int cdc_mbim_suspend(struct usb_interface *intf, pm_message_t message)
315{ 371{
316 int ret = 0; 372 int ret = -ENODEV;
317 struct usbnet *dev = usb_get_intfdata(intf); 373 struct usbnet *dev = usb_get_intfdata(intf);
318 struct cdc_mbim_state *info = (void *)&dev->data; 374 struct cdc_mbim_state *info = (void *)&dev->data;
319 struct cdc_ncm_ctx *ctx = info->ctx; 375 struct cdc_ncm_ctx *ctx = info->ctx;
320 376
321 if (ctx == NULL) { 377 if (!ctx)
322 ret = -1;
323 goto error; 378 goto error;
324 }
325 379
326 /* 380 /*
327 * Both usbnet_suspend() and subdriver->suspend() MUST return 0 381 * Both usbnet_suspend() and subdriver->suspend() MUST return 0
@@ -354,7 +408,7 @@ static int cdc_mbim_resume(struct usb_interface *intf)
354 if (ret < 0) 408 if (ret < 0)
355 goto err; 409 goto err;
356 ret = usbnet_resume(intf); 410 ret = usbnet_resume(intf);
357 if (ret < 0 && callsub && info->subdriver->suspend) 411 if (ret < 0 && callsub)
358 info->subdriver->suspend(intf, PMSG_SUSPEND); 412 info->subdriver->suspend(intf, PMSG_SUSPEND);
359err: 413err:
360 return ret; 414 return ret;
@@ -371,9 +425,18 @@ static const struct driver_info cdc_mbim_info = {
371}; 425};
372 426
373/* MBIM and NCM devices should not need a ZLP after NTBs with 427/* MBIM and NCM devices should not need a ZLP after NTBs with
374 * dwNtbOutMaxSize length. This driver_info is for the exceptional 428 * dwNtbOutMaxSize length. Nevertheless, a number of devices from
375 * devices requiring it anyway, allowing them to be supported without 429 * different vendor IDs will fail unless we send ZLPs, forcing us
376 * forcing the performance penalty on all the sane devices. 430 * to make this the default.
431 *
432 * This default may cause a performance penalty for spec conforming
433 * devices wanting to take advantage of optimizations possible without
434 * ZLPs. A whitelist is added in an attempt to avoid this for devices
435 * known to conform to the MBIM specification.
436 *
437 * All known devices supporting NCM compatibility mode are also
438 * conforming to the NCM and MBIM specifications. For this reason, the
439 * NCM subclass entry is also in the ZLP whitelist.
377 */ 440 */
378static const struct driver_info cdc_mbim_info_zlp = { 441static const struct driver_info cdc_mbim_info_zlp = {
379 .description = "CDC MBIM", 442 .description = "CDC MBIM",
@@ -396,16 +459,13 @@ static const struct usb_device_id mbim_devs[] = {
396 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), 459 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
397 .driver_info = (unsigned long)&cdc_mbim_info, 460 .driver_info = (unsigned long)&cdc_mbim_info,
398 }, 461 },
399 /* Sierra Wireless MC7710 need ZLPs */ 462 /* ZLP conformance whitelist: All Ericsson MBIM devices */
400 { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68a2, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE), 463 { USB_VENDOR_AND_INTERFACE_INFO(0x0bdb, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
401 .driver_info = (unsigned long)&cdc_mbim_info_zlp, 464 .driver_info = (unsigned long)&cdc_mbim_info,
402 },
403 /* HP hs2434 Mobile Broadband Module needs ZLPs */
404 { USB_DEVICE_AND_INTERFACE_INFO(0x3f0, 0x4b1d, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
405 .driver_info = (unsigned long)&cdc_mbim_info_zlp,
406 }, 465 },
466 /* default entry */
407 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE), 467 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
408 .driver_info = (unsigned long)&cdc_mbim_info, 468 .driver_info = (unsigned long)&cdc_mbim_info_zlp,
409 }, 469 },
410 { 470 {
411 }, 471 },