cdc_mbim.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /*
  2. * Copyright (c) 2012 Smith Micro Software, Inc.
  3. * Copyright (c) 2012 Bjørn Mork <bjorn@mork.no>
  4. *
  5. * This driver is based on and reuse most of cdc_ncm, which is
  6. * Copyright (C) ST-Ericsson 2010-2012
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * version 2 as published by the Free Software Foundation.
  11. */
  12. #include <linux/module.h>
  13. #include <linux/netdevice.h>
  14. #include <linux/ethtool.h>
  15. #include <linux/ip.h>
  16. #include <linux/mii.h>
  17. #include <linux/usb.h>
  18. #include <linux/usb/cdc.h>
  19. #include <linux/usb/usbnet.h>
  20. #include <linux/usb/cdc-wdm.h>
  21. #include <linux/usb/cdc_ncm.h>
  22. /* driver specific data - must match cdc_ncm usage */
  23. struct cdc_mbim_state {
  24. struct cdc_ncm_ctx *ctx;
  25. atomic_t pmcount;
  26. struct usb_driver *subdriver;
  27. struct usb_interface *control;
  28. struct usb_interface *data;
  29. };
  30. /* using a counter to merge subdriver requests with our own into a combined state */
  31. static int cdc_mbim_manage_power(struct usbnet *dev, int on)
  32. {
  33. struct cdc_mbim_state *info = (void *)&dev->data;
  34. int rv = 0;
  35. dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(&info->pmcount), on);
  36. if ((on && atomic_add_return(1, &info->pmcount) == 1) || (!on && atomic_dec_and_test(&info->pmcount))) {
  37. /* need autopm_get/put here to ensure the usbcore sees the new value */
  38. rv = usb_autopm_get_interface(dev->intf);
  39. if (rv < 0)
  40. goto err;
  41. dev->intf->needs_remote_wakeup = on;
  42. usb_autopm_put_interface(dev->intf);
  43. }
  44. err:
  45. return rv;
  46. }
  47. static int cdc_mbim_wdm_manage_power(struct usb_interface *intf, int status)
  48. {
  49. struct usbnet *dev = usb_get_intfdata(intf);
  50. /* can be called while disconnecting */
  51. if (!dev)
  52. return 0;
  53. return cdc_mbim_manage_power(dev, status);
  54. }
  55. static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
  56. {
  57. struct cdc_ncm_ctx *ctx;
  58. struct usb_driver *subdriver = ERR_PTR(-ENODEV);
  59. int ret = -ENODEV;
  60. u8 data_altsetting = CDC_NCM_DATA_ALTSETTING_NCM;
  61. struct cdc_mbim_state *info = (void *)&dev->data;
  62. /* see if interface supports MBIM alternate setting */
  63. if (intf->num_altsetting == 2) {
  64. if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
  65. usb_set_interface(dev->udev,
  66. intf->cur_altsetting->desc.bInterfaceNumber,
  67. CDC_NCM_COMM_ALTSETTING_MBIM);
  68. data_altsetting = CDC_NCM_DATA_ALTSETTING_MBIM;
  69. }
  70. /* Probably NCM, defer for cdc_ncm_bind */
  71. if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
  72. goto err;
  73. ret = cdc_ncm_bind_common(dev, intf, data_altsetting);
  74. if (ret)
  75. goto err;
  76. ctx = info->ctx;
  77. /* The MBIM descriptor and the status endpoint are required */
  78. if (ctx->mbim_desc && dev->status)
  79. subdriver = usb_cdc_wdm_register(ctx->control,
  80. &dev->status->desc,
  81. le16_to_cpu(ctx->mbim_desc->wMaxControlMessage),
  82. cdc_mbim_wdm_manage_power);
  83. if (IS_ERR(subdriver)) {
  84. ret = PTR_ERR(subdriver);
  85. cdc_ncm_unbind(dev, intf);
  86. goto err;
  87. }
  88. /* can't let usbnet use the interrupt endpoint */
  89. dev->status = NULL;
  90. info->subdriver = subdriver;
  91. /* MBIM cannot do ARP */
  92. dev->net->flags |= IFF_NOARP;
  93. err:
  94. return ret;
  95. }
  96. static void cdc_mbim_unbind(struct usbnet *dev, struct usb_interface *intf)
  97. {
  98. struct cdc_mbim_state *info = (void *)&dev->data;
  99. struct cdc_ncm_ctx *ctx = info->ctx;
  100. /* disconnect subdriver from control interface */
  101. if (info->subdriver && info->subdriver->disconnect)
  102. info->subdriver->disconnect(ctx->control);
  103. info->subdriver = NULL;
  104. /* let NCM unbind clean up both control and data interface */
  105. cdc_ncm_unbind(dev, intf);
  106. }
  107. static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
  108. {
  109. struct sk_buff *skb_out;
  110. struct cdc_mbim_state *info = (void *)&dev->data;
  111. struct cdc_ncm_ctx *ctx = info->ctx;
  112. if (!ctx)
  113. goto error;
  114. if (skb) {
  115. if (skb->len <= sizeof(ETH_HLEN))
  116. goto error;
  117. skb_reset_mac_header(skb);
  118. switch (eth_hdr(skb)->h_proto) {
  119. case htons(ETH_P_IP):
  120. case htons(ETH_P_IPV6):
  121. skb_pull(skb, ETH_HLEN);
  122. break;
  123. default:
  124. goto error;
  125. }
  126. }
  127. spin_lock_bh(&ctx->mtx);
  128. skb_out = cdc_ncm_fill_tx_frame(ctx, skb, cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN));
  129. spin_unlock_bh(&ctx->mtx);
  130. return skb_out;
  131. error:
  132. if (skb)
  133. dev_kfree_skb_any(skb);
  134. return NULL;
  135. }
  136. static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_t len)
  137. {
  138. __be16 proto;
  139. struct sk_buff *skb = NULL;
  140. switch (*buf & 0xf0) {
  141. case 0x40:
  142. proto = htons(ETH_P_IP);
  143. break;
  144. case 0x60:
  145. proto = htons(ETH_P_IPV6);
  146. break;
  147. default:
  148. goto err;
  149. }
  150. skb = netdev_alloc_skb_ip_align(dev->net, len + ETH_HLEN);
  151. if (!skb)
  152. goto err;
  153. /* add an ethernet header */
  154. skb_put(skb, ETH_HLEN);
  155. skb_reset_mac_header(skb);
  156. eth_hdr(skb)->h_proto = proto;
  157. memset(eth_hdr(skb)->h_source, 0, ETH_ALEN);
  158. memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN);
  159. /* add datagram */
  160. memcpy(skb_put(skb, len), buf, len);
  161. err:
  162. return skb;
  163. }
  164. static int cdc_mbim_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
  165. {
  166. struct sk_buff *skb;
  167. struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
  168. int len;
  169. int nframes;
  170. int x;
  171. int offset;
  172. struct usb_cdc_ncm_ndp16 *ndp16;
  173. struct usb_cdc_ncm_dpe16 *dpe16;
  174. int ndpoffset;
  175. int loopcount = 50; /* arbitrary max preventing infinite loop */
  176. ndpoffset = cdc_ncm_rx_verify_nth16(ctx, skb_in);
  177. if (ndpoffset < 0)
  178. goto error;
  179. next_ndp:
  180. nframes = cdc_ncm_rx_verify_ndp16(skb_in, ndpoffset);
  181. if (nframes < 0)
  182. goto error;
  183. ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset);
  184. /* only supporting IPS Session #0 for now */
  185. switch (ndp16->dwSignature) {
  186. case cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN):
  187. break;
  188. default:
  189. netif_dbg(dev, rx_err, dev->net,
  190. "unsupported NDP signature <0x%08x>\n",
  191. le32_to_cpu(ndp16->dwSignature));
  192. goto err_ndp;
  193. }
  194. dpe16 = ndp16->dpe16;
  195. for (x = 0; x < nframes; x++, dpe16++) {
  196. offset = le16_to_cpu(dpe16->wDatagramIndex);
  197. len = le16_to_cpu(dpe16->wDatagramLength);
  198. /*
  199. * CDC NCM ch. 3.7
  200. * All entries after first NULL entry are to be ignored
  201. */
  202. if ((offset == 0) || (len == 0)) {
  203. if (!x)
  204. goto err_ndp; /* empty NTB */
  205. break;
  206. }
  207. /* sanity checking */
  208. if (((offset + len) > skb_in->len) || (len > ctx->rx_max) ||
  209. (len < sizeof(struct iphdr))) {
  210. netif_dbg(dev, rx_err, dev->net,
  211. "invalid frame detected (ignored) offset[%u]=%u, length=%u, skb=%p\n",
  212. x, offset, len, skb_in);
  213. if (!x)
  214. goto err_ndp;
  215. break;
  216. } else {
  217. skb = cdc_mbim_process_dgram(dev, skb_in->data + offset, len);
  218. if (!skb)
  219. goto error;
  220. usbnet_skb_return(dev, skb);
  221. }
  222. }
  223. err_ndp:
  224. /* are there more NDPs to process? */
  225. ndpoffset = le16_to_cpu(ndp16->wNextNdpIndex);
  226. if (ndpoffset && loopcount--)
  227. goto next_ndp;
  228. return 1;
  229. error:
  230. return 0;
  231. }
  232. static int cdc_mbim_suspend(struct usb_interface *intf, pm_message_t message)
  233. {
  234. int ret = 0;
  235. struct usbnet *dev = usb_get_intfdata(intf);
  236. struct cdc_mbim_state *info = (void *)&dev->data;
  237. struct cdc_ncm_ctx *ctx = info->ctx;
  238. if (ctx == NULL) {
  239. ret = -1;
  240. goto error;
  241. }
  242. ret = usbnet_suspend(intf, message);
  243. if (ret < 0)
  244. goto error;
  245. if (intf == ctx->control && info->subdriver && info->subdriver->suspend)
  246. ret = info->subdriver->suspend(intf, message);
  247. if (ret < 0)
  248. usbnet_resume(intf);
  249. error:
  250. return ret;
  251. }
  252. static int cdc_mbim_resume(struct usb_interface *intf)
  253. {
  254. int ret = 0;
  255. struct usbnet *dev = usb_get_intfdata(intf);
  256. struct cdc_mbim_state *info = (void *)&dev->data;
  257. struct cdc_ncm_ctx *ctx = info->ctx;
  258. bool callsub = (intf == ctx->control && info->subdriver && info->subdriver->resume);
  259. if (callsub)
  260. ret = info->subdriver->resume(intf);
  261. if (ret < 0)
  262. goto err;
  263. ret = usbnet_resume(intf);
  264. if (ret < 0 && callsub && info->subdriver->suspend)
  265. info->subdriver->suspend(intf, PMSG_SUSPEND);
  266. err:
  267. return ret;
  268. }
  269. static const struct driver_info cdc_mbim_info = {
  270. .description = "CDC MBIM",
  271. .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN,
  272. .bind = cdc_mbim_bind,
  273. .unbind = cdc_mbim_unbind,
  274. .manage_power = cdc_mbim_manage_power,
  275. .rx_fixup = cdc_mbim_rx_fixup,
  276. .tx_fixup = cdc_mbim_tx_fixup,
  277. };
  278. static const struct usb_device_id mbim_devs[] = {
  279. /* This duplicate NCM entry is intentional. MBIM devices can
  280. * be disguised as NCM by default, and this is necessary to
  281. * allow us to bind the correct driver_info to such devices.
  282. *
  283. * bind() will sort out this for us, selecting the correct
  284. * entry and reject the other
  285. */
  286. { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
  287. .driver_info = (unsigned long)&cdc_mbim_info,
  288. },
  289. { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
  290. .driver_info = (unsigned long)&cdc_mbim_info,
  291. },
  292. {
  293. },
  294. };
  295. MODULE_DEVICE_TABLE(usb, mbim_devs);
  296. static struct usb_driver cdc_mbim_driver = {
  297. .name = "cdc_mbim",
  298. .id_table = mbim_devs,
  299. .probe = usbnet_probe,
  300. .disconnect = usbnet_disconnect,
  301. .suspend = cdc_mbim_suspend,
  302. .resume = cdc_mbim_resume,
  303. .reset_resume = cdc_mbim_resume,
  304. .supports_autosuspend = 1,
  305. .disable_hub_initiated_lpm = 1,
  306. };
  307. module_usb_driver(cdc_mbim_driver);
  308. MODULE_AUTHOR("Greg Suarez <gsuarez@smithmicro.com>");
  309. MODULE_AUTHOR("Bjørn Mork <bjorn@mork.no>");
  310. MODULE_DESCRIPTION("USB CDC MBIM host driver");
  311. MODULE_LICENSE("GPL");