1900d495aSAlexey Orishko /* 2900d495aSAlexey Orishko * cdc_ncm.c 3900d495aSAlexey Orishko * 4c84ff1d6SAlexey Orishko * Copyright (C) ST-Ericsson 2010-2012 5900d495aSAlexey Orishko * Contact: Alexey Orishko <alexey.orishko@stericsson.com> 6900d495aSAlexey Orishko * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com> 7900d495aSAlexey Orishko * 8900d495aSAlexey Orishko * USB Host Driver for Network Control Model (NCM) 9900d495aSAlexey Orishko * http://www.usb.org/developers/devclass_docs/NCM10.zip 10900d495aSAlexey Orishko * 11900d495aSAlexey Orishko * The NCM encoding, decoding and initialization logic 12900d495aSAlexey Orishko * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h 13900d495aSAlexey Orishko * 14900d495aSAlexey Orishko * This software is available to you under a choice of one of two 15900d495aSAlexey Orishko * licenses. You may choose this file to be licensed under the terms 16900d495aSAlexey Orishko * of the GNU General Public License (GPL) Version 2 or the 2-clause 17900d495aSAlexey Orishko * BSD license listed below: 18900d495aSAlexey Orishko * 19900d495aSAlexey Orishko * Redistribution and use in source and binary forms, with or without 20900d495aSAlexey Orishko * modification, are permitted provided that the following conditions 21900d495aSAlexey Orishko * are met: 22900d495aSAlexey Orishko * 1. Redistributions of source code must retain the above copyright 23900d495aSAlexey Orishko * notice, this list of conditions and the following disclaimer. 24900d495aSAlexey Orishko * 2. Redistributions in binary form must reproduce the above copyright 25900d495aSAlexey Orishko * notice, this list of conditions and the following disclaimer in the 26900d495aSAlexey Orishko * documentation and/or other materials provided with the distribution. 27900d495aSAlexey Orishko * 28900d495aSAlexey Orishko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 29900d495aSAlexey Orishko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30900d495aSAlexey Orishko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31900d495aSAlexey Orishko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 32900d495aSAlexey Orishko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33900d495aSAlexey Orishko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34900d495aSAlexey Orishko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35900d495aSAlexey Orishko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36900d495aSAlexey Orishko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37900d495aSAlexey Orishko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38900d495aSAlexey Orishko * SUCH DAMAGE. 39900d495aSAlexey Orishko */ 40900d495aSAlexey Orishko 41900d495aSAlexey Orishko #include <linux/module.h> 42900d495aSAlexey Orishko #include <linux/init.h> 43900d495aSAlexey Orishko #include <linux/netdevice.h> 44900d495aSAlexey Orishko #include <linux/ctype.h> 45900d495aSAlexey Orishko #include <linux/ethtool.h> 46900d495aSAlexey Orishko #include <linux/workqueue.h> 47900d495aSAlexey Orishko #include <linux/mii.h> 48900d495aSAlexey Orishko #include <linux/crc32.h> 49900d495aSAlexey Orishko #include <linux/usb.h> 50c84ff1d6SAlexey Orishko #include <linux/hrtimer.h> 51900d495aSAlexey Orishko #include <linux/atomic.h> 52900d495aSAlexey Orishko #include <linux/usb/usbnet.h> 53900d495aSAlexey Orishko #include <linux/usb/cdc.h> 54900d495aSAlexey Orishko 55c84ff1d6SAlexey Orishko #define DRIVER_VERSION "14-Mar-2012" 56900d495aSAlexey Orishko 57900d495aSAlexey Orishko /* CDC NCM subclass 3.2.1 */ 58900d495aSAlexey Orishko #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 59900d495aSAlexey Orishko 60900d495aSAlexey Orishko /* Maximum NTB length */ 613f658cdeSAlexey Orishko #define CDC_NCM_NTB_MAX_SIZE_TX 32768 /* bytes */ 623f658cdeSAlexey Orishko #define CDC_NCM_NTB_MAX_SIZE_RX 32768 /* bytes */ 63900d495aSAlexey Orishko 64900d495aSAlexey Orishko /* Minimum value for MaxDatagramSize, ch. 6.2.9 */ 65900d495aSAlexey Orishko #define CDC_NCM_MIN_DATAGRAM_SIZE 1514 /* bytes */ 66900d495aSAlexey Orishko 672d1c4310SGreg Suarez /* Minimum value for MaxDatagramSize, ch. 8.1.3 */ 682d1c4310SGreg Suarez #define CDC_MBIM_MIN_DATAGRAM_SIZE 2048 /* bytes */ 692d1c4310SGreg Suarez 70900d495aSAlexey Orishko #define CDC_NCM_MIN_TX_PKT 512 /* bytes */ 71900d495aSAlexey Orishko 72900d495aSAlexey Orishko /* Default value for MaxDatagramSize */ 733f658cdeSAlexey Orishko #define CDC_NCM_MAX_DATAGRAM_SIZE 8192 /* bytes */ 74900d495aSAlexey Orishko 75900d495aSAlexey Orishko /* 76900d495aSAlexey Orishko * Maximum amount of datagrams in NCM Datagram Pointer Table, not counting 77d5ddb4a5SAlexey Orishko * the last NULL entry. 78900d495aSAlexey Orishko */ 793f658cdeSAlexey Orishko #define CDC_NCM_DPT_DATAGRAMS_MAX 40 80900d495aSAlexey Orishko 81900d495aSAlexey Orishko /* Restart the timer, if amount of datagrams is less than given value */ 82900d495aSAlexey Orishko #define CDC_NCM_RESTART_TIMER_DATAGRAM_CNT 3 83c84ff1d6SAlexey Orishko #define CDC_NCM_TIMER_PENDING_CNT 2 84c84ff1d6SAlexey Orishko #define CDC_NCM_TIMER_INTERVAL (400UL * NSEC_PER_USEC) 85900d495aSAlexey Orishko 86900d495aSAlexey Orishko /* The following macro defines the minimum header space */ 87900d495aSAlexey Orishko #define CDC_NCM_MIN_HDR_SIZE \ 88900d495aSAlexey Orishko (sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \ 89900d495aSAlexey Orishko (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16)) 90900d495aSAlexey Orishko 91900d495aSAlexey Orishko struct cdc_ncm_data { 92900d495aSAlexey Orishko struct usb_cdc_ncm_nth16 nth16; 93900d495aSAlexey Orishko struct usb_cdc_ncm_ndp16 ndp16; 94900d495aSAlexey Orishko struct usb_cdc_ncm_dpe16 dpe16[CDC_NCM_DPT_DATAGRAMS_MAX + 1]; 95900d495aSAlexey Orishko }; 96900d495aSAlexey Orishko 97900d495aSAlexey Orishko struct cdc_ncm_ctx { 98900d495aSAlexey Orishko struct cdc_ncm_data tx_ncm; 99900d495aSAlexey Orishko struct usb_cdc_ncm_ntb_parameters ncm_parm; 100c84ff1d6SAlexey Orishko struct hrtimer tx_timer; 101c84ff1d6SAlexey Orishko struct tasklet_struct bh; 102900d495aSAlexey Orishko 103900d495aSAlexey Orishko const struct usb_cdc_ncm_desc *func_desc; 1042d1c4310SGreg Suarez const struct usb_cdc_mbim_desc *mbim_desc; 105900d495aSAlexey Orishko const struct usb_cdc_header_desc *header_desc; 106900d495aSAlexey Orishko const struct usb_cdc_union_desc *union_desc; 107900d495aSAlexey Orishko const struct usb_cdc_ether_desc *ether_desc; 108900d495aSAlexey Orishko 109900d495aSAlexey Orishko struct net_device *netdev; 110900d495aSAlexey Orishko struct usb_device *udev; 111900d495aSAlexey Orishko struct usb_host_endpoint *in_ep; 112900d495aSAlexey Orishko struct usb_host_endpoint *out_ep; 113900d495aSAlexey Orishko struct usb_host_endpoint *status_ep; 114900d495aSAlexey Orishko struct usb_interface *intf; 115900d495aSAlexey Orishko struct usb_interface *control; 116900d495aSAlexey Orishko struct usb_interface *data; 117900d495aSAlexey Orishko 118900d495aSAlexey Orishko struct sk_buff *tx_curr_skb; 119900d495aSAlexey Orishko struct sk_buff *tx_rem_skb; 120900d495aSAlexey Orishko 121900d495aSAlexey Orishko spinlock_t mtx; 122c84ff1d6SAlexey Orishko atomic_t stop; 123900d495aSAlexey Orishko 124900d495aSAlexey Orishko u32 tx_timer_pending; 125900d495aSAlexey Orishko u32 tx_curr_offset; 126900d495aSAlexey Orishko u32 tx_curr_last_offset; 127900d495aSAlexey Orishko u32 tx_curr_frame_num; 128900d495aSAlexey Orishko u32 rx_speed; 129900d495aSAlexey Orishko u32 tx_speed; 130900d495aSAlexey Orishko u32 rx_max; 131900d495aSAlexey Orishko u32 tx_max; 132900d495aSAlexey Orishko u32 max_datagram_size; 133900d495aSAlexey Orishko u16 tx_max_datagrams; 134900d495aSAlexey Orishko u16 tx_remainder; 135900d495aSAlexey Orishko u16 tx_modulus; 136900d495aSAlexey Orishko u16 tx_ndp_modulus; 137900d495aSAlexey Orishko u16 tx_seq; 138d5ddb4a5SAlexey Orishko u16 rx_seq; 139900d495aSAlexey Orishko u16 connected; 140900d495aSAlexey Orishko }; 141900d495aSAlexey Orishko 142c84ff1d6SAlexey Orishko static void cdc_ncm_txpath_bh(unsigned long param); 143c84ff1d6SAlexey Orishko static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx); 144c84ff1d6SAlexey Orishko static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer); 145900d495aSAlexey Orishko static struct usb_driver cdc_ncm_driver; 146900d495aSAlexey Orishko 147900d495aSAlexey Orishko static void 148900d495aSAlexey Orishko cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) 149900d495aSAlexey Orishko { 150900d495aSAlexey Orishko struct usbnet *dev = netdev_priv(net); 151900d495aSAlexey Orishko 152900d495aSAlexey Orishko strncpy(info->driver, dev->driver_name, sizeof(info->driver)); 153900d495aSAlexey Orishko strncpy(info->version, DRIVER_VERSION, sizeof(info->version)); 154900d495aSAlexey Orishko strncpy(info->fw_version, dev->driver_info->description, 155900d495aSAlexey Orishko sizeof(info->fw_version)); 156900d495aSAlexey Orishko usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info)); 157900d495aSAlexey Orishko } 158900d495aSAlexey Orishko 159900d495aSAlexey Orishko static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) 160900d495aSAlexey Orishko { 161900d495aSAlexey Orishko u32 val; 162900d495aSAlexey Orishko u8 flags; 163900d495aSAlexey Orishko u8 iface_no; 164900d495aSAlexey Orishko int err; 1652d1c4310SGreg Suarez int eth_hlen; 16684e77a8bSAlexey Orishko u16 ntb_fmt_supported; 1672d1c4310SGreg Suarez u32 min_dgram_size; 1682d1c4310SGreg Suarez u32 min_hdr_size; 169900d495aSAlexey Orishko 170900d495aSAlexey Orishko iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber; 171900d495aSAlexey Orishko 17236c35416SGiuseppe Scrivano err = usb_control_msg(ctx->udev, 17336c35416SGiuseppe Scrivano usb_rcvctrlpipe(ctx->udev, 0), 17436c35416SGiuseppe Scrivano USB_CDC_GET_NTB_PARAMETERS, 17536c35416SGiuseppe Scrivano USB_TYPE_CLASS | USB_DIR_IN 17636c35416SGiuseppe Scrivano | USB_RECIP_INTERFACE, 17736c35416SGiuseppe Scrivano 0, iface_no, &ctx->ncm_parm, 17836c35416SGiuseppe Scrivano sizeof(ctx->ncm_parm), 10000); 17936c35416SGiuseppe Scrivano if (err < 0) { 180900d495aSAlexey Orishko pr_debug("failed GET_NTB_PARAMETERS\n"); 181900d495aSAlexey Orishko return 1; 182900d495aSAlexey Orishko } 183900d495aSAlexey Orishko 184900d495aSAlexey Orishko /* read correct set of parameters according to device mode */ 185900d495aSAlexey Orishko ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize); 186900d495aSAlexey Orishko ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize); 187900d495aSAlexey Orishko ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder); 188900d495aSAlexey Orishko ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor); 189900d495aSAlexey Orishko ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment); 19084e77a8bSAlexey Orishko /* devices prior to NCM Errata shall set this field to zero */ 19184e77a8bSAlexey Orishko ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams); 19284e77a8bSAlexey Orishko ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported); 193900d495aSAlexey Orishko 1942d1c4310SGreg Suarez eth_hlen = ETH_HLEN; 1952d1c4310SGreg Suarez min_dgram_size = CDC_NCM_MIN_DATAGRAM_SIZE; 1962d1c4310SGreg Suarez min_hdr_size = CDC_NCM_MIN_HDR_SIZE; 1972d1c4310SGreg Suarez if (ctx->mbim_desc != NULL) { 1982d1c4310SGreg Suarez flags = ctx->mbim_desc->bmNetworkCapabilities; 1992d1c4310SGreg Suarez eth_hlen = 0; 2002d1c4310SGreg Suarez min_dgram_size = CDC_MBIM_MIN_DATAGRAM_SIZE; 2012d1c4310SGreg Suarez min_hdr_size = 0; 2022d1c4310SGreg Suarez } else if (ctx->func_desc != NULL) { 203900d495aSAlexey Orishko flags = ctx->func_desc->bmNetworkCapabilities; 2042d1c4310SGreg Suarez } else { 205900d495aSAlexey Orishko flags = 0; 2062d1c4310SGreg Suarez } 207900d495aSAlexey Orishko 208900d495aSAlexey Orishko pr_debug("dwNtbInMaxSize=%u dwNtbOutMaxSize=%u " 209900d495aSAlexey Orishko "wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u " 21084e77a8bSAlexey Orishko "wNdpOutAlignment=%u wNtbOutMaxDatagrams=%u flags=0x%x\n", 211900d495aSAlexey Orishko ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus, 21284e77a8bSAlexey Orishko ctx->tx_ndp_modulus, ctx->tx_max_datagrams, flags); 213900d495aSAlexey Orishko 21484e77a8bSAlexey Orishko /* max count of tx datagrams */ 21584e77a8bSAlexey Orishko if ((ctx->tx_max_datagrams == 0) || 21684e77a8bSAlexey Orishko (ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX)) 217900d495aSAlexey Orishko ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX; 218900d495aSAlexey Orishko 219900d495aSAlexey Orishko /* verify maximum size of received NTB in bytes */ 22084e77a8bSAlexey Orishko if (ctx->rx_max < USB_CDC_NCM_NTB_MIN_IN_SIZE) { 22184e77a8bSAlexey Orishko pr_debug("Using min receive length=%d\n", 22284e77a8bSAlexey Orishko USB_CDC_NCM_NTB_MIN_IN_SIZE); 22384e77a8bSAlexey Orishko ctx->rx_max = USB_CDC_NCM_NTB_MIN_IN_SIZE; 22484e77a8bSAlexey Orishko } 22584e77a8bSAlexey Orishko 22684e77a8bSAlexey Orishko if (ctx->rx_max > CDC_NCM_NTB_MAX_SIZE_RX) { 227900d495aSAlexey Orishko pr_debug("Using default maximum receive length=%d\n", 228900d495aSAlexey Orishko CDC_NCM_NTB_MAX_SIZE_RX); 229900d495aSAlexey Orishko ctx->rx_max = CDC_NCM_NTB_MAX_SIZE_RX; 230900d495aSAlexey Orishko } 231900d495aSAlexey Orishko 23284e77a8bSAlexey Orishko /* inform device about NTB input size changes */ 23384e77a8bSAlexey Orishko if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) { 23475bc8ef5SJosh Boyer __le32 *dwNtbInMaxSize; 235dad957d7SBjørn Mork 236dad957d7SBjørn Mork dwNtbInMaxSize = kzalloc(sizeof(*dwNtbInMaxSize), GFP_KERNEL); 23775bc8ef5SJosh Boyer if (!dwNtbInMaxSize) { 23875bc8ef5SJosh Boyer err = -ENOMEM; 23975bc8ef5SJosh Boyer goto size_err; 24075bc8ef5SJosh Boyer } 24175bc8ef5SJosh Boyer *dwNtbInMaxSize = cpu_to_le32(ctx->rx_max); 24275bc8ef5SJosh Boyer err = usb_control_msg(ctx->udev, 24375bc8ef5SJosh Boyer usb_sndctrlpipe(ctx->udev, 0), 24475bc8ef5SJosh Boyer USB_CDC_SET_NTB_INPUT_SIZE, 24575bc8ef5SJosh Boyer USB_TYPE_CLASS | USB_DIR_OUT 24675bc8ef5SJosh Boyer | USB_RECIP_INTERFACE, 24775bc8ef5SJosh Boyer 0, iface_no, dwNtbInMaxSize, 4, 1000); 24875bc8ef5SJosh Boyer kfree(dwNtbInMaxSize); 24975bc8ef5SJosh Boyer size_err: 25036c35416SGiuseppe Scrivano if (err < 0) 25184e77a8bSAlexey Orishko pr_debug("Setting NTB Input Size failed\n"); 25284e77a8bSAlexey Orishko } 25384e77a8bSAlexey Orishko 254900d495aSAlexey Orishko /* verify maximum size of transmitted NTB in bytes */ 255900d495aSAlexey Orishko if ((ctx->tx_max < 2562d1c4310SGreg Suarez (min_hdr_size + min_dgram_size)) || 257900d495aSAlexey Orishko (ctx->tx_max > CDC_NCM_NTB_MAX_SIZE_TX)) { 258900d495aSAlexey Orishko pr_debug("Using default maximum transmit length=%d\n", 259900d495aSAlexey Orishko CDC_NCM_NTB_MAX_SIZE_TX); 260900d495aSAlexey Orishko ctx->tx_max = CDC_NCM_NTB_MAX_SIZE_TX; 261900d495aSAlexey Orishko } 262900d495aSAlexey Orishko 263900d495aSAlexey Orishko /* 264900d495aSAlexey Orishko * verify that the structure alignment is: 265900d495aSAlexey Orishko * - power of two 266900d495aSAlexey Orishko * - not greater than the maximum transmit length 267900d495aSAlexey Orishko * - not less than four bytes 268900d495aSAlexey Orishko */ 269900d495aSAlexey Orishko val = ctx->tx_ndp_modulus; 270900d495aSAlexey Orishko 271900d495aSAlexey Orishko if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) || 272900d495aSAlexey Orishko (val != ((-val) & val)) || (val >= ctx->tx_max)) { 273900d495aSAlexey Orishko pr_debug("Using default alignment: 4 bytes\n"); 274900d495aSAlexey Orishko ctx->tx_ndp_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE; 275900d495aSAlexey Orishko } 276900d495aSAlexey Orishko 277900d495aSAlexey Orishko /* 278900d495aSAlexey Orishko * verify that the payload alignment is: 279900d495aSAlexey Orishko * - power of two 280900d495aSAlexey Orishko * - not greater than the maximum transmit length 281900d495aSAlexey Orishko * - not less than four bytes 282900d495aSAlexey Orishko */ 283900d495aSAlexey Orishko val = ctx->tx_modulus; 284900d495aSAlexey Orishko 285900d495aSAlexey Orishko if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) || 286900d495aSAlexey Orishko (val != ((-val) & val)) || (val >= ctx->tx_max)) { 287900d495aSAlexey Orishko pr_debug("Using default transmit modulus: 4 bytes\n"); 288900d495aSAlexey Orishko ctx->tx_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE; 289900d495aSAlexey Orishko } 290900d495aSAlexey Orishko 291900d495aSAlexey Orishko /* verify the payload remainder */ 292900d495aSAlexey Orishko if (ctx->tx_remainder >= ctx->tx_modulus) { 293900d495aSAlexey Orishko pr_debug("Using default transmit remainder: 0 bytes\n"); 294900d495aSAlexey Orishko ctx->tx_remainder = 0; 295900d495aSAlexey Orishko } 296900d495aSAlexey Orishko 297900d495aSAlexey Orishko /* adjust TX-remainder according to NCM specification. */ 2982d1c4310SGreg Suarez ctx->tx_remainder = ((ctx->tx_remainder - eth_hlen) & 299900d495aSAlexey Orishko (ctx->tx_modulus - 1)); 300900d495aSAlexey Orishko 301900d495aSAlexey Orishko /* additional configuration */ 302900d495aSAlexey Orishko 303900d495aSAlexey Orishko /* set CRC Mode */ 30484e77a8bSAlexey Orishko if (flags & USB_CDC_NCM_NCAP_CRC_MODE) { 30536c35416SGiuseppe Scrivano err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0), 30636c35416SGiuseppe Scrivano USB_CDC_SET_CRC_MODE, 30736c35416SGiuseppe Scrivano USB_TYPE_CLASS | USB_DIR_OUT 30836c35416SGiuseppe Scrivano | USB_RECIP_INTERFACE, 30936c35416SGiuseppe Scrivano USB_CDC_NCM_CRC_NOT_APPENDED, 31036c35416SGiuseppe Scrivano iface_no, NULL, 0, 1000); 31136c35416SGiuseppe Scrivano if (err < 0) 312900d495aSAlexey Orishko pr_debug("Setting CRC mode off failed\n"); 31384e77a8bSAlexey Orishko } 314900d495aSAlexey Orishko 31584e77a8bSAlexey Orishko /* set NTB format, if both formats are supported */ 31684e77a8bSAlexey Orishko if (ntb_fmt_supported & USB_CDC_NCM_NTH32_SIGN) { 31736c35416SGiuseppe Scrivano err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0), 31836c35416SGiuseppe Scrivano USB_CDC_SET_NTB_FORMAT, USB_TYPE_CLASS 31936c35416SGiuseppe Scrivano | USB_DIR_OUT | USB_RECIP_INTERFACE, 32036c35416SGiuseppe Scrivano USB_CDC_NCM_NTB16_FORMAT, 32136c35416SGiuseppe Scrivano iface_no, NULL, 0, 1000); 32236c35416SGiuseppe Scrivano if (err < 0) 323900d495aSAlexey Orishko pr_debug("Setting NTB format to 16-bit failed\n"); 32484e77a8bSAlexey Orishko } 32584e77a8bSAlexey Orishko 3262d1c4310SGreg Suarez ctx->max_datagram_size = min_dgram_size; 327900d495aSAlexey Orishko 328900d495aSAlexey Orishko /* set Max Datagram Size (MTU) */ 32984e77a8bSAlexey Orishko if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) { 33075bc8ef5SJosh Boyer __le16 *max_datagram_size; 3312d1c4310SGreg Suarez u16 eth_max_sz; 3322d1c4310SGreg Suarez if (ctx->ether_desc != NULL) 3332d1c4310SGreg Suarez eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize); 3342d1c4310SGreg Suarez else if (ctx->mbim_desc != NULL) 3352d1c4310SGreg Suarez eth_max_sz = le16_to_cpu(ctx->mbim_desc->wMaxSegmentSize); 3362d1c4310SGreg Suarez else 3372d1c4310SGreg Suarez goto max_dgram_err; 33875bc8ef5SJosh Boyer 33975bc8ef5SJosh Boyer max_datagram_size = kzalloc(sizeof(*max_datagram_size), 34075bc8ef5SJosh Boyer GFP_KERNEL); 34175bc8ef5SJosh Boyer if (!max_datagram_size) { 34275bc8ef5SJosh Boyer err = -ENOMEM; 34375bc8ef5SJosh Boyer goto max_dgram_err; 34475bc8ef5SJosh Boyer } 34575bc8ef5SJosh Boyer 34636c35416SGiuseppe Scrivano err = usb_control_msg(ctx->udev, usb_rcvctrlpipe(ctx->udev, 0), 34736c35416SGiuseppe Scrivano USB_CDC_GET_MAX_DATAGRAM_SIZE, 34836c35416SGiuseppe Scrivano USB_TYPE_CLASS | USB_DIR_IN 34936c35416SGiuseppe Scrivano | USB_RECIP_INTERFACE, 35075bc8ef5SJosh Boyer 0, iface_no, max_datagram_size, 35136c35416SGiuseppe Scrivano 2, 1000); 35236c35416SGiuseppe Scrivano if (err < 0) { 35384e77a8bSAlexey Orishko pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n", 3542d1c4310SGreg Suarez min_dgram_size); 355900d495aSAlexey Orishko } else { 35675bc8ef5SJosh Boyer ctx->max_datagram_size = 35775bc8ef5SJosh Boyer le16_to_cpu(*max_datagram_size); 35884e77a8bSAlexey Orishko /* Check Eth descriptor value */ 35984e77a8bSAlexey Orishko if (ctx->max_datagram_size > eth_max_sz) 36084e77a8bSAlexey Orishko ctx->max_datagram_size = eth_max_sz; 3613f658cdeSAlexey Orishko 3623f658cdeSAlexey Orishko if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE) 3632d1c4310SGreg Suarez ctx->max_datagram_size = CDC_NCM_MAX_DATAGRAM_SIZE; 364900d495aSAlexey Orishko 3652d1c4310SGreg Suarez if (ctx->max_datagram_size < min_dgram_size) 3662d1c4310SGreg Suarez ctx->max_datagram_size = min_dgram_size; 36784e77a8bSAlexey Orishko 36884e77a8bSAlexey Orishko /* if value changed, update device */ 3693f658cdeSAlexey Orishko if (ctx->max_datagram_size != 3703f658cdeSAlexey Orishko le16_to_cpu(*max_datagram_size)) { 37136c35416SGiuseppe Scrivano err = usb_control_msg(ctx->udev, 37236c35416SGiuseppe Scrivano usb_sndctrlpipe(ctx->udev, 0), 37336c35416SGiuseppe Scrivano USB_CDC_SET_MAX_DATAGRAM_SIZE, 37436c35416SGiuseppe Scrivano USB_TYPE_CLASS | USB_DIR_OUT 37536c35416SGiuseppe Scrivano | USB_RECIP_INTERFACE, 37636c35416SGiuseppe Scrivano 0, 37775bc8ef5SJosh Boyer iface_no, max_datagram_size, 37836c35416SGiuseppe Scrivano 2, 1000); 37936c35416SGiuseppe Scrivano if (err < 0) 3803f658cdeSAlexey Orishko pr_debug("SET_MAX_DGRAM_SIZE failed\n"); 3813f658cdeSAlexey Orishko } 3823f658cdeSAlexey Orishko } 3833f658cdeSAlexey Orishko kfree(max_datagram_size); 38484e77a8bSAlexey Orishko } 38584e77a8bSAlexey Orishko 3863f658cdeSAlexey Orishko max_dgram_err: 3872d1c4310SGreg Suarez if (ctx->netdev->mtu != (ctx->max_datagram_size - eth_hlen)) 3882d1c4310SGreg Suarez ctx->netdev->mtu = ctx->max_datagram_size - eth_hlen; 389900d495aSAlexey Orishko 390900d495aSAlexey Orishko return 0; 391900d495aSAlexey Orishko } 392900d495aSAlexey Orishko 393900d495aSAlexey Orishko static void 394900d495aSAlexey Orishko cdc_ncm_find_endpoints(struct cdc_ncm_ctx *ctx, struct usb_interface *intf) 395900d495aSAlexey Orishko { 396900d495aSAlexey Orishko struct usb_host_endpoint *e; 397900d495aSAlexey Orishko u8 ep; 398900d495aSAlexey Orishko 399900d495aSAlexey Orishko for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) { 400900d495aSAlexey Orishko 401900d495aSAlexey Orishko e = intf->cur_altsetting->endpoint + ep; 402900d495aSAlexey Orishko switch (e->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { 403900d495aSAlexey Orishko case USB_ENDPOINT_XFER_INT: 404900d495aSAlexey Orishko if (usb_endpoint_dir_in(&e->desc)) { 405900d495aSAlexey Orishko if (ctx->status_ep == NULL) 406900d495aSAlexey Orishko ctx->status_ep = e; 407900d495aSAlexey Orishko } 408900d495aSAlexey Orishko break; 409900d495aSAlexey Orishko 410900d495aSAlexey Orishko case USB_ENDPOINT_XFER_BULK: 411900d495aSAlexey Orishko if (usb_endpoint_dir_in(&e->desc)) { 412900d495aSAlexey Orishko if (ctx->in_ep == NULL) 413900d495aSAlexey Orishko ctx->in_ep = e; 414900d495aSAlexey Orishko } else { 415900d495aSAlexey Orishko if (ctx->out_ep == NULL) 416900d495aSAlexey Orishko ctx->out_ep = e; 417900d495aSAlexey Orishko } 418900d495aSAlexey Orishko break; 419900d495aSAlexey Orishko 420900d495aSAlexey Orishko default: 421900d495aSAlexey Orishko break; 422900d495aSAlexey Orishko } 423900d495aSAlexey Orishko } 424900d495aSAlexey Orishko } 425900d495aSAlexey Orishko 426900d495aSAlexey Orishko static void cdc_ncm_free(struct cdc_ncm_ctx *ctx) 427900d495aSAlexey Orishko { 428900d495aSAlexey Orishko if (ctx == NULL) 429900d495aSAlexey Orishko return; 430900d495aSAlexey Orishko 431900d495aSAlexey Orishko if (ctx->tx_rem_skb != NULL) { 432900d495aSAlexey Orishko dev_kfree_skb_any(ctx->tx_rem_skb); 433900d495aSAlexey Orishko ctx->tx_rem_skb = NULL; 434900d495aSAlexey Orishko } 435900d495aSAlexey Orishko 436900d495aSAlexey Orishko if (ctx->tx_curr_skb != NULL) { 437900d495aSAlexey Orishko dev_kfree_skb_any(ctx->tx_curr_skb); 438900d495aSAlexey Orishko ctx->tx_curr_skb = NULL; 439900d495aSAlexey Orishko } 440900d495aSAlexey Orishko 441900d495aSAlexey Orishko kfree(ctx); 442900d495aSAlexey Orishko } 443900d495aSAlexey Orishko 444f94898eaSDan Williams static const struct ethtool_ops cdc_ncm_ethtool_ops = { 445f94898eaSDan Williams .get_drvinfo = cdc_ncm_get_drvinfo, 446f94898eaSDan Williams .get_link = usbnet_get_link, 447f94898eaSDan Williams .get_msglevel = usbnet_get_msglevel, 448f94898eaSDan Williams .set_msglevel = usbnet_set_msglevel, 449f94898eaSDan Williams .get_settings = usbnet_get_settings, 450f94898eaSDan Williams .set_settings = usbnet_set_settings, 451f94898eaSDan Williams .nway_reset = usbnet_nway_reset, 452f94898eaSDan Williams }; 453f94898eaSDan Williams 45438396e4cSGreg Suarez static int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting) 455900d495aSAlexey Orishko { 456900d495aSAlexey Orishko struct cdc_ncm_ctx *ctx; 457900d495aSAlexey Orishko struct usb_driver *driver; 458900d495aSAlexey Orishko u8 *buf; 459900d495aSAlexey Orishko int len; 460900d495aSAlexey Orishko int temp; 461900d495aSAlexey Orishko u8 iface_no; 462900d495aSAlexey Orishko 463c796984fSThomas Meyer ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 464900d495aSAlexey Orishko if (ctx == NULL) 46519694ac8SAlexey Orishko return -ENODEV; 466900d495aSAlexey Orishko 467c84ff1d6SAlexey Orishko hrtimer_init(&ctx->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 468c84ff1d6SAlexey Orishko ctx->tx_timer.function = &cdc_ncm_tx_timer_cb; 469c84ff1d6SAlexey Orishko ctx->bh.data = (unsigned long)ctx; 470c84ff1d6SAlexey Orishko ctx->bh.func = cdc_ncm_txpath_bh; 471c84ff1d6SAlexey Orishko atomic_set(&ctx->stop, 0); 472900d495aSAlexey Orishko spin_lock_init(&ctx->mtx); 473900d495aSAlexey Orishko ctx->netdev = dev->net; 474900d495aSAlexey Orishko 475900d495aSAlexey Orishko /* store ctx pointer in device data field */ 476900d495aSAlexey Orishko dev->data[0] = (unsigned long)ctx; 477900d495aSAlexey Orishko 478900d495aSAlexey Orishko /* get some pointers */ 479900d495aSAlexey Orishko driver = driver_of(intf); 480900d495aSAlexey Orishko buf = intf->cur_altsetting->extra; 481900d495aSAlexey Orishko len = intf->cur_altsetting->extralen; 482900d495aSAlexey Orishko 483900d495aSAlexey Orishko ctx->udev = dev->udev; 484900d495aSAlexey Orishko ctx->intf = intf; 485900d495aSAlexey Orishko 486900d495aSAlexey Orishko /* parse through descriptors associated with control interface */ 487900d495aSAlexey Orishko while ((len > 0) && (buf[0] > 2) && (buf[0] <= len)) { 488900d495aSAlexey Orishko 489900d495aSAlexey Orishko if (buf[1] != USB_DT_CS_INTERFACE) 490900d495aSAlexey Orishko goto advance; 491900d495aSAlexey Orishko 492900d495aSAlexey Orishko switch (buf[2]) { 493900d495aSAlexey Orishko case USB_CDC_UNION_TYPE: 494900d495aSAlexey Orishko if (buf[0] < sizeof(*(ctx->union_desc))) 495900d495aSAlexey Orishko break; 496900d495aSAlexey Orishko 497900d495aSAlexey Orishko ctx->union_desc = 498900d495aSAlexey Orishko (const struct usb_cdc_union_desc *)buf; 499900d495aSAlexey Orishko 500900d495aSAlexey Orishko ctx->control = usb_ifnum_to_if(dev->udev, 501900d495aSAlexey Orishko ctx->union_desc->bMasterInterface0); 502900d495aSAlexey Orishko ctx->data = usb_ifnum_to_if(dev->udev, 503900d495aSAlexey Orishko ctx->union_desc->bSlaveInterface0); 504900d495aSAlexey Orishko break; 505900d495aSAlexey Orishko 506900d495aSAlexey Orishko case USB_CDC_ETHERNET_TYPE: 507900d495aSAlexey Orishko if (buf[0] < sizeof(*(ctx->ether_desc))) 508900d495aSAlexey Orishko break; 509900d495aSAlexey Orishko 510900d495aSAlexey Orishko ctx->ether_desc = 511900d495aSAlexey Orishko (const struct usb_cdc_ether_desc *)buf; 512900d495aSAlexey Orishko dev->hard_mtu = 513900d495aSAlexey Orishko le16_to_cpu(ctx->ether_desc->wMaxSegmentSize); 514900d495aSAlexey Orishko 51584e77a8bSAlexey Orishko if (dev->hard_mtu < CDC_NCM_MIN_DATAGRAM_SIZE) 51684e77a8bSAlexey Orishko dev->hard_mtu = CDC_NCM_MIN_DATAGRAM_SIZE; 51784e77a8bSAlexey Orishko else if (dev->hard_mtu > CDC_NCM_MAX_DATAGRAM_SIZE) 51884e77a8bSAlexey Orishko dev->hard_mtu = CDC_NCM_MAX_DATAGRAM_SIZE; 519900d495aSAlexey Orishko break; 520900d495aSAlexey Orishko 521900d495aSAlexey Orishko case USB_CDC_NCM_TYPE: 522900d495aSAlexey Orishko if (buf[0] < sizeof(*(ctx->func_desc))) 523900d495aSAlexey Orishko break; 524900d495aSAlexey Orishko 525900d495aSAlexey Orishko ctx->func_desc = (const struct usb_cdc_ncm_desc *)buf; 526900d495aSAlexey Orishko break; 527900d495aSAlexey Orishko 52838396e4cSGreg Suarez case USB_CDC_MBIM_TYPE: 52938396e4cSGreg Suarez if (buf[0] < sizeof(*(ctx->mbim_desc))) 53038396e4cSGreg Suarez break; 53138396e4cSGreg Suarez 53238396e4cSGreg Suarez ctx->mbim_desc = (const struct usb_cdc_mbim_desc *)buf; 53338396e4cSGreg Suarez break; 53438396e4cSGreg Suarez 535900d495aSAlexey Orishko default: 536900d495aSAlexey Orishko break; 537900d495aSAlexey Orishko } 538900d495aSAlexey Orishko advance: 539900d495aSAlexey Orishko /* advance to next descriptor */ 540900d495aSAlexey Orishko temp = buf[0]; 541900d495aSAlexey Orishko buf += temp; 542900d495aSAlexey Orishko len -= temp; 543900d495aSAlexey Orishko } 544900d495aSAlexey Orishko 545900d495aSAlexey Orishko /* check if we got everything */ 546900d495aSAlexey Orishko if ((ctx->control == NULL) || (ctx->data == NULL) || 54738396e4cSGreg Suarez ((!ctx->mbim_desc) && ((ctx->ether_desc == NULL) || (ctx->control != intf)))) 548900d495aSAlexey Orishko goto error; 549900d495aSAlexey Orishko 550900d495aSAlexey Orishko /* claim interfaces, if any */ 551900d495aSAlexey Orishko temp = usb_driver_claim_interface(driver, ctx->data, dev); 552900d495aSAlexey Orishko if (temp) 553900d495aSAlexey Orishko goto error; 554900d495aSAlexey Orishko 555900d495aSAlexey Orishko iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber; 556900d495aSAlexey Orishko 557900d495aSAlexey Orishko /* reset data interface */ 558900d495aSAlexey Orishko temp = usb_set_interface(dev->udev, iface_no, 0); 559900d495aSAlexey Orishko if (temp) 56019694ac8SAlexey Orishko goto error2; 561900d495aSAlexey Orishko 562900d495aSAlexey Orishko /* initialize data interface */ 563900d495aSAlexey Orishko if (cdc_ncm_setup(ctx)) 56419694ac8SAlexey Orishko goto error2; 565900d495aSAlexey Orishko 566900d495aSAlexey Orishko /* configure data interface */ 56738396e4cSGreg Suarez temp = usb_set_interface(dev->udev, iface_no, data_altsetting); 568900d495aSAlexey Orishko if (temp) 56919694ac8SAlexey Orishko goto error2; 570900d495aSAlexey Orishko 571900d495aSAlexey Orishko cdc_ncm_find_endpoints(ctx, ctx->data); 572900d495aSAlexey Orishko cdc_ncm_find_endpoints(ctx, ctx->control); 573900d495aSAlexey Orishko 574900d495aSAlexey Orishko if ((ctx->in_ep == NULL) || (ctx->out_ep == NULL) || 575900d495aSAlexey Orishko (ctx->status_ep == NULL)) 57619694ac8SAlexey Orishko goto error2; 577900d495aSAlexey Orishko 578900d495aSAlexey Orishko dev->net->ethtool_ops = &cdc_ncm_ethtool_ops; 579900d495aSAlexey Orishko 580900d495aSAlexey Orishko usb_set_intfdata(ctx->data, dev); 581900d495aSAlexey Orishko usb_set_intfdata(ctx->control, dev); 582900d495aSAlexey Orishko usb_set_intfdata(ctx->intf, dev); 583900d495aSAlexey Orishko 58438396e4cSGreg Suarez if (ctx->ether_desc) { 585900d495aSAlexey Orishko temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress); 586900d495aSAlexey Orishko if (temp) 58719694ac8SAlexey Orishko goto error2; 588517cd81cSDanny Kukawka dev_info(&dev->udev->dev, "MAC-Address: %pM\n", dev->net->dev_addr); 58938396e4cSGreg Suarez } 59038396e4cSGreg Suarez 591900d495aSAlexey Orishko 592900d495aSAlexey Orishko dev->in = usb_rcvbulkpipe(dev->udev, 593900d495aSAlexey Orishko ctx->in_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); 594900d495aSAlexey Orishko dev->out = usb_sndbulkpipe(dev->udev, 595900d495aSAlexey Orishko ctx->out_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); 596900d495aSAlexey Orishko dev->status = ctx->status_ep; 597900d495aSAlexey Orishko dev->rx_urb_size = ctx->rx_max; 598900d495aSAlexey Orishko 599900d495aSAlexey Orishko ctx->tx_speed = ctx->rx_speed = 0; 600900d495aSAlexey Orishko return 0; 601900d495aSAlexey Orishko 60219694ac8SAlexey Orishko error2: 60319694ac8SAlexey Orishko usb_set_intfdata(ctx->control, NULL); 60419694ac8SAlexey Orishko usb_set_intfdata(ctx->data, NULL); 60519694ac8SAlexey Orishko usb_driver_release_interface(driver, ctx->data); 606900d495aSAlexey Orishko error: 607900d495aSAlexey Orishko cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]); 608900d495aSAlexey Orishko dev->data[0] = 0; 60919694ac8SAlexey Orishko dev_info(&dev->udev->dev, "bind() failure\n"); 610900d495aSAlexey Orishko return -ENODEV; 611900d495aSAlexey Orishko } 612900d495aSAlexey Orishko 613900d495aSAlexey Orishko static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf) 614900d495aSAlexey Orishko { 615900d495aSAlexey Orishko struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; 61619694ac8SAlexey Orishko struct usb_driver *driver = driver_of(intf); 617900d495aSAlexey Orishko 618900d495aSAlexey Orishko if (ctx == NULL) 619900d495aSAlexey Orishko return; /* no setup */ 620900d495aSAlexey Orishko 621c84ff1d6SAlexey Orishko atomic_set(&ctx->stop, 1); 622c84ff1d6SAlexey Orishko 623c84ff1d6SAlexey Orishko if (hrtimer_active(&ctx->tx_timer)) 624c84ff1d6SAlexey Orishko hrtimer_cancel(&ctx->tx_timer); 625c84ff1d6SAlexey Orishko 626c84ff1d6SAlexey Orishko tasklet_kill(&ctx->bh); 627c84ff1d6SAlexey Orishko 62819694ac8SAlexey Orishko /* disconnect master --> disconnect slave */ 62919694ac8SAlexey Orishko if (intf == ctx->control && ctx->data) { 630900d495aSAlexey Orishko usb_set_intfdata(ctx->data, NULL); 631900d495aSAlexey Orishko usb_driver_release_interface(driver, ctx->data); 63219694ac8SAlexey Orishko ctx->data = NULL; 633900d495aSAlexey Orishko 63419694ac8SAlexey Orishko } else if (intf == ctx->data && ctx->control) { 63519694ac8SAlexey Orishko usb_set_intfdata(ctx->control, NULL); 636900d495aSAlexey Orishko usb_driver_release_interface(driver, ctx->control); 63719694ac8SAlexey Orishko ctx->control = NULL; 638900d495aSAlexey Orishko } 639900d495aSAlexey Orishko 64019694ac8SAlexey Orishko usb_set_intfdata(ctx->intf, NULL); 641900d495aSAlexey Orishko cdc_ncm_free(ctx); 642900d495aSAlexey Orishko } 643900d495aSAlexey Orishko 64438396e4cSGreg Suarez static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) 64538396e4cSGreg Suarez { 64638396e4cSGreg Suarez int ret; 64738396e4cSGreg Suarez 64838396e4cSGreg Suarez /* NCM data altsetting is always 1 */ 64938396e4cSGreg Suarez ret = cdc_ncm_bind_common(dev, intf, 1); 65038396e4cSGreg Suarez 65138396e4cSGreg Suarez /* 65238396e4cSGreg Suarez * We should get an event when network connection is "connected" or 65338396e4cSGreg Suarez * "disconnected". Set network connection in "disconnected" state 65438396e4cSGreg Suarez * (carrier is OFF) during attach, so the IP network stack does not 65538396e4cSGreg Suarez * start IPv6 negotiation and more. 65638396e4cSGreg Suarez */ 65738396e4cSGreg Suarez netif_carrier_off(dev->net); 65838396e4cSGreg Suarez return ret; 65938396e4cSGreg Suarez } 66038396e4cSGreg Suarez 661900d495aSAlexey Orishko static void cdc_ncm_zero_fill(u8 *ptr, u32 first, u32 end, u32 max) 662900d495aSAlexey Orishko { 663900d495aSAlexey Orishko if (first >= max) 664900d495aSAlexey Orishko return; 665900d495aSAlexey Orishko if (first >= end) 666900d495aSAlexey Orishko return; 667900d495aSAlexey Orishko if (end > max) 668900d495aSAlexey Orishko end = max; 669900d495aSAlexey Orishko memset(ptr + first, 0, end - first); 670900d495aSAlexey Orishko } 671900d495aSAlexey Orishko 672900d495aSAlexey Orishko static struct sk_buff * 673900d495aSAlexey Orishko cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) 674900d495aSAlexey Orishko { 675900d495aSAlexey Orishko struct sk_buff *skb_out; 676900d495aSAlexey Orishko u32 rem; 677900d495aSAlexey Orishko u32 offset; 678900d495aSAlexey Orishko u32 last_offset; 67936c35416SGiuseppe Scrivano u16 n = 0, index; 68084e77a8bSAlexey Orishko u8 ready2send = 0; 681900d495aSAlexey Orishko 682900d495aSAlexey Orishko /* if there is a remaining skb, it gets priority */ 683900d495aSAlexey Orishko if (skb != NULL) 684900d495aSAlexey Orishko swap(skb, ctx->tx_rem_skb); 685900d495aSAlexey Orishko else 68684e77a8bSAlexey Orishko ready2send = 1; 687900d495aSAlexey Orishko 688900d495aSAlexey Orishko /* 689900d495aSAlexey Orishko * +----------------+ 690900d495aSAlexey Orishko * | skb_out | 691900d495aSAlexey Orishko * +----------------+ 692900d495aSAlexey Orishko * ^ offset 693900d495aSAlexey Orishko * ^ last_offset 694900d495aSAlexey Orishko */ 695900d495aSAlexey Orishko 696900d495aSAlexey Orishko /* check if we are resuming an OUT skb */ 697900d495aSAlexey Orishko if (ctx->tx_curr_skb != NULL) { 698900d495aSAlexey Orishko /* pop variables */ 699900d495aSAlexey Orishko skb_out = ctx->tx_curr_skb; 700900d495aSAlexey Orishko offset = ctx->tx_curr_offset; 701900d495aSAlexey Orishko last_offset = ctx->tx_curr_last_offset; 702900d495aSAlexey Orishko n = ctx->tx_curr_frame_num; 703900d495aSAlexey Orishko 704900d495aSAlexey Orishko } else { 705900d495aSAlexey Orishko /* reset variables */ 7066c60408eSAlexey Orishko skb_out = alloc_skb((ctx->tx_max + 1), GFP_ATOMIC); 707900d495aSAlexey Orishko if (skb_out == NULL) { 708900d495aSAlexey Orishko if (skb != NULL) { 709900d495aSAlexey Orishko dev_kfree_skb_any(skb); 710900d495aSAlexey Orishko ctx->netdev->stats.tx_dropped++; 711900d495aSAlexey Orishko } 712900d495aSAlexey Orishko goto exit_no_skb; 713900d495aSAlexey Orishko } 714900d495aSAlexey Orishko 715900d495aSAlexey Orishko /* make room for NTH and NDP */ 716900d495aSAlexey Orishko offset = ALIGN(sizeof(struct usb_cdc_ncm_nth16), 717900d495aSAlexey Orishko ctx->tx_ndp_modulus) + 718900d495aSAlexey Orishko sizeof(struct usb_cdc_ncm_ndp16) + 719900d495aSAlexey Orishko (ctx->tx_max_datagrams + 1) * 720900d495aSAlexey Orishko sizeof(struct usb_cdc_ncm_dpe16); 721900d495aSAlexey Orishko 722900d495aSAlexey Orishko /* store last valid offset before alignment */ 723900d495aSAlexey Orishko last_offset = offset; 724900d495aSAlexey Orishko /* align first Datagram offset correctly */ 725900d495aSAlexey Orishko offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder; 726900d495aSAlexey Orishko /* zero buffer till the first IP datagram */ 727900d495aSAlexey Orishko cdc_ncm_zero_fill(skb_out->data, 0, offset, offset); 728900d495aSAlexey Orishko n = 0; 729900d495aSAlexey Orishko ctx->tx_curr_frame_num = 0; 730900d495aSAlexey Orishko } 731900d495aSAlexey Orishko 732900d495aSAlexey Orishko for (; n < ctx->tx_max_datagrams; n++) { 733900d495aSAlexey Orishko /* check if end of transmit buffer is reached */ 73484e77a8bSAlexey Orishko if (offset >= ctx->tx_max) { 73584e77a8bSAlexey Orishko ready2send = 1; 736900d495aSAlexey Orishko break; 73784e77a8bSAlexey Orishko } 738900d495aSAlexey Orishko /* compute maximum buffer size */ 739900d495aSAlexey Orishko rem = ctx->tx_max - offset; 740900d495aSAlexey Orishko 741900d495aSAlexey Orishko if (skb == NULL) { 742900d495aSAlexey Orishko skb = ctx->tx_rem_skb; 743900d495aSAlexey Orishko ctx->tx_rem_skb = NULL; 744900d495aSAlexey Orishko 745900d495aSAlexey Orishko /* check for end of skb */ 746900d495aSAlexey Orishko if (skb == NULL) 747900d495aSAlexey Orishko break; 748900d495aSAlexey Orishko } 749900d495aSAlexey Orishko 750900d495aSAlexey Orishko if (skb->len > rem) { 751900d495aSAlexey Orishko if (n == 0) { 752900d495aSAlexey Orishko /* won't fit, MTU problem? */ 753900d495aSAlexey Orishko dev_kfree_skb_any(skb); 754900d495aSAlexey Orishko skb = NULL; 755900d495aSAlexey Orishko ctx->netdev->stats.tx_dropped++; 756900d495aSAlexey Orishko } else { 757900d495aSAlexey Orishko /* no room for skb - store for later */ 758900d495aSAlexey Orishko if (ctx->tx_rem_skb != NULL) { 759900d495aSAlexey Orishko dev_kfree_skb_any(ctx->tx_rem_skb); 760900d495aSAlexey Orishko ctx->netdev->stats.tx_dropped++; 761900d495aSAlexey Orishko } 762900d495aSAlexey Orishko ctx->tx_rem_skb = skb; 763900d495aSAlexey Orishko skb = NULL; 76484e77a8bSAlexey Orishko ready2send = 1; 765900d495aSAlexey Orishko } 766900d495aSAlexey Orishko break; 767900d495aSAlexey Orishko } 768900d495aSAlexey Orishko 769900d495aSAlexey Orishko memcpy(((u8 *)skb_out->data) + offset, skb->data, skb->len); 770900d495aSAlexey Orishko 771900d495aSAlexey Orishko ctx->tx_ncm.dpe16[n].wDatagramLength = cpu_to_le16(skb->len); 772900d495aSAlexey Orishko ctx->tx_ncm.dpe16[n].wDatagramIndex = cpu_to_le16(offset); 773900d495aSAlexey Orishko 774900d495aSAlexey Orishko /* update offset */ 775900d495aSAlexey Orishko offset += skb->len; 776900d495aSAlexey Orishko 777900d495aSAlexey Orishko /* store last valid offset before alignment */ 778900d495aSAlexey Orishko last_offset = offset; 779900d495aSAlexey Orishko 780900d495aSAlexey Orishko /* align offset correctly */ 781900d495aSAlexey Orishko offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder; 782900d495aSAlexey Orishko 783900d495aSAlexey Orishko /* zero padding */ 784900d495aSAlexey Orishko cdc_ncm_zero_fill(skb_out->data, last_offset, offset, 785900d495aSAlexey Orishko ctx->tx_max); 786900d495aSAlexey Orishko dev_kfree_skb_any(skb); 787900d495aSAlexey Orishko skb = NULL; 788900d495aSAlexey Orishko } 789900d495aSAlexey Orishko 790900d495aSAlexey Orishko /* free up any dangling skb */ 791900d495aSAlexey Orishko if (skb != NULL) { 792900d495aSAlexey Orishko dev_kfree_skb_any(skb); 793900d495aSAlexey Orishko skb = NULL; 794900d495aSAlexey Orishko ctx->netdev->stats.tx_dropped++; 795900d495aSAlexey Orishko } 796900d495aSAlexey Orishko 797900d495aSAlexey Orishko ctx->tx_curr_frame_num = n; 798900d495aSAlexey Orishko 799900d495aSAlexey Orishko if (n == 0) { 800900d495aSAlexey Orishko /* wait for more frames */ 801900d495aSAlexey Orishko /* push variables */ 802900d495aSAlexey Orishko ctx->tx_curr_skb = skb_out; 803900d495aSAlexey Orishko ctx->tx_curr_offset = offset; 804900d495aSAlexey Orishko ctx->tx_curr_last_offset = last_offset; 805900d495aSAlexey Orishko goto exit_no_skb; 806900d495aSAlexey Orishko 80784e77a8bSAlexey Orishko } else if ((n < ctx->tx_max_datagrams) && (ready2send == 0)) { 808900d495aSAlexey Orishko /* wait for more frames */ 809900d495aSAlexey Orishko /* push variables */ 810900d495aSAlexey Orishko ctx->tx_curr_skb = skb_out; 811900d495aSAlexey Orishko ctx->tx_curr_offset = offset; 812900d495aSAlexey Orishko ctx->tx_curr_last_offset = last_offset; 813900d495aSAlexey Orishko /* set the pending count */ 814900d495aSAlexey Orishko if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT) 815c84ff1d6SAlexey Orishko ctx->tx_timer_pending = CDC_NCM_TIMER_PENDING_CNT; 816900d495aSAlexey Orishko goto exit_no_skb; 817900d495aSAlexey Orishko 818900d495aSAlexey Orishko } else { 819900d495aSAlexey Orishko /* frame goes out */ 820900d495aSAlexey Orishko /* variables will be reset at next call */ 821900d495aSAlexey Orishko } 822900d495aSAlexey Orishko 823900d495aSAlexey Orishko /* check for overflow */ 824900d495aSAlexey Orishko if (last_offset > ctx->tx_max) 825900d495aSAlexey Orishko last_offset = ctx->tx_max; 826900d495aSAlexey Orishko 827900d495aSAlexey Orishko /* revert offset */ 828900d495aSAlexey Orishko offset = last_offset; 829900d495aSAlexey Orishko 830900d495aSAlexey Orishko /* 831900d495aSAlexey Orishko * If collected data size is less or equal CDC_NCM_MIN_TX_PKT bytes, 832900d495aSAlexey Orishko * we send buffers as it is. If we get more data, it would be more 833900d495aSAlexey Orishko * efficient for USB HS mobile device with DMA engine to receive a full 834900d495aSAlexey Orishko * size NTB, than canceling DMA transfer and receiving a short packet. 835900d495aSAlexey Orishko */ 836900d495aSAlexey Orishko if (offset > CDC_NCM_MIN_TX_PKT) 837900d495aSAlexey Orishko offset = ctx->tx_max; 838900d495aSAlexey Orishko 839900d495aSAlexey Orishko /* final zero padding */ 840900d495aSAlexey Orishko cdc_ncm_zero_fill(skb_out->data, last_offset, offset, ctx->tx_max); 841900d495aSAlexey Orishko 842900d495aSAlexey Orishko /* store last offset */ 843900d495aSAlexey Orishko last_offset = offset; 844900d495aSAlexey Orishko 8456c60408eSAlexey Orishko if (((last_offset < ctx->tx_max) && ((last_offset % 8466c60408eSAlexey Orishko le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) || 8476c60408eSAlexey Orishko (((last_offset == ctx->tx_max) && ((ctx->tx_max % 8486c60408eSAlexey Orishko le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) && 8496c60408eSAlexey Orishko (ctx->tx_max < le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)))) { 850900d495aSAlexey Orishko /* force short packet */ 851900d495aSAlexey Orishko *(((u8 *)skb_out->data) + last_offset) = 0; 852900d495aSAlexey Orishko last_offset++; 853900d495aSAlexey Orishko } 854900d495aSAlexey Orishko 855900d495aSAlexey Orishko /* zero the rest of the DPEs plus the last NULL entry */ 856900d495aSAlexey Orishko for (; n <= CDC_NCM_DPT_DATAGRAMS_MAX; n++) { 857900d495aSAlexey Orishko ctx->tx_ncm.dpe16[n].wDatagramLength = 0; 858900d495aSAlexey Orishko ctx->tx_ncm.dpe16[n].wDatagramIndex = 0; 859900d495aSAlexey Orishko } 860900d495aSAlexey Orishko 861900d495aSAlexey Orishko /* fill out 16-bit NTB header */ 862900d495aSAlexey Orishko ctx->tx_ncm.nth16.dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN); 863900d495aSAlexey Orishko ctx->tx_ncm.nth16.wHeaderLength = 864900d495aSAlexey Orishko cpu_to_le16(sizeof(ctx->tx_ncm.nth16)); 865900d495aSAlexey Orishko ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq); 866900d495aSAlexey Orishko ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset); 86736c35416SGiuseppe Scrivano index = ALIGN(sizeof(struct usb_cdc_ncm_nth16), ctx->tx_ndp_modulus); 86836c35416SGiuseppe Scrivano ctx->tx_ncm.nth16.wNdpIndex = cpu_to_le16(index); 869900d495aSAlexey Orishko 870900d495aSAlexey Orishko memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16)); 871900d495aSAlexey Orishko ctx->tx_seq++; 872900d495aSAlexey Orishko 873900d495aSAlexey Orishko /* fill out 16-bit NDP table */ 874900d495aSAlexey Orishko ctx->tx_ncm.ndp16.dwSignature = 875900d495aSAlexey Orishko cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN); 876900d495aSAlexey Orishko rem = sizeof(ctx->tx_ncm.ndp16) + ((ctx->tx_curr_frame_num + 1) * 877900d495aSAlexey Orishko sizeof(struct usb_cdc_ncm_dpe16)); 878900d495aSAlexey Orishko ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem); 87984e77a8bSAlexey Orishko ctx->tx_ncm.ndp16.wNextNdpIndex = 0; /* reserved */ 880900d495aSAlexey Orishko 88136c35416SGiuseppe Scrivano memcpy(((u8 *)skb_out->data) + index, 882900d495aSAlexey Orishko &(ctx->tx_ncm.ndp16), 883900d495aSAlexey Orishko sizeof(ctx->tx_ncm.ndp16)); 884900d495aSAlexey Orishko 88536c35416SGiuseppe Scrivano memcpy(((u8 *)skb_out->data) + index + sizeof(ctx->tx_ncm.ndp16), 886900d495aSAlexey Orishko &(ctx->tx_ncm.dpe16), 887900d495aSAlexey Orishko (ctx->tx_curr_frame_num + 1) * 888900d495aSAlexey Orishko sizeof(struct usb_cdc_ncm_dpe16)); 889900d495aSAlexey Orishko 890900d495aSAlexey Orishko /* set frame length */ 891900d495aSAlexey Orishko skb_put(skb_out, last_offset); 892900d495aSAlexey Orishko 893900d495aSAlexey Orishko /* return skb */ 894900d495aSAlexey Orishko ctx->tx_curr_skb = NULL; 895c84ff1d6SAlexey Orishko ctx->netdev->stats.tx_packets += ctx->tx_curr_frame_num; 896900d495aSAlexey Orishko return skb_out; 897900d495aSAlexey Orishko 898900d495aSAlexey Orishko exit_no_skb: 899c84ff1d6SAlexey Orishko /* Start timer, if there is a remaining skb */ 900c84ff1d6SAlexey Orishko if (ctx->tx_curr_skb != NULL) 901c84ff1d6SAlexey Orishko cdc_ncm_tx_timeout_start(ctx); 902900d495aSAlexey Orishko return NULL; 903900d495aSAlexey Orishko } 904900d495aSAlexey Orishko 905900d495aSAlexey Orishko static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx) 906900d495aSAlexey Orishko { 907900d495aSAlexey Orishko /* start timer, if not already started */ 908c84ff1d6SAlexey Orishko if (!(hrtimer_active(&ctx->tx_timer) || atomic_read(&ctx->stop))) 909c84ff1d6SAlexey Orishko hrtimer_start(&ctx->tx_timer, 910c84ff1d6SAlexey Orishko ktime_set(0, CDC_NCM_TIMER_INTERVAL), 911c84ff1d6SAlexey Orishko HRTIMER_MODE_REL); 912900d495aSAlexey Orishko } 913900d495aSAlexey Orishko 914c84ff1d6SAlexey Orishko static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *timer) 915900d495aSAlexey Orishko { 916c84ff1d6SAlexey Orishko struct cdc_ncm_ctx *ctx = 917c84ff1d6SAlexey Orishko container_of(timer, struct cdc_ncm_ctx, tx_timer); 918900d495aSAlexey Orishko 919c84ff1d6SAlexey Orishko if (!atomic_read(&ctx->stop)) 920c84ff1d6SAlexey Orishko tasklet_schedule(&ctx->bh); 921c84ff1d6SAlexey Orishko return HRTIMER_NORESTART; 922c84ff1d6SAlexey Orishko } 923c84ff1d6SAlexey Orishko 924c84ff1d6SAlexey Orishko static void cdc_ncm_txpath_bh(unsigned long param) 925c84ff1d6SAlexey Orishko { 926c84ff1d6SAlexey Orishko struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)param; 927c84ff1d6SAlexey Orishko 928c84ff1d6SAlexey Orishko spin_lock_bh(&ctx->mtx); 929900d495aSAlexey Orishko if (ctx->tx_timer_pending != 0) { 930900d495aSAlexey Orishko ctx->tx_timer_pending--; 931900d495aSAlexey Orishko cdc_ncm_tx_timeout_start(ctx); 932c84ff1d6SAlexey Orishko spin_unlock_bh(&ctx->mtx); 933f742aa8aSAlexey Orishko } else if (ctx->netdev != NULL) { 934c84ff1d6SAlexey Orishko spin_unlock_bh(&ctx->mtx); 935c84ff1d6SAlexey Orishko netif_tx_lock_bh(ctx->netdev); 936900d495aSAlexey Orishko usbnet_start_xmit(NULL, ctx->netdev); 937c84ff1d6SAlexey Orishko netif_tx_unlock_bh(ctx->netdev); 938900d495aSAlexey Orishko } 939f742aa8aSAlexey Orishko } 940900d495aSAlexey Orishko 941900d495aSAlexey Orishko static struct sk_buff * 942900d495aSAlexey Orishko cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) 943900d495aSAlexey Orishko { 944900d495aSAlexey Orishko struct sk_buff *skb_out; 945900d495aSAlexey Orishko struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; 946900d495aSAlexey Orishko 947900d495aSAlexey Orishko /* 948900d495aSAlexey Orishko * The Ethernet API we are using does not support transmitting 949900d495aSAlexey Orishko * multiple Ethernet frames in a single call. This driver will 950900d495aSAlexey Orishko * accumulate multiple Ethernet frames and send out a larger 951900d495aSAlexey Orishko * USB frame when the USB buffer is full or when a single jiffies 952900d495aSAlexey Orishko * timeout happens. 953900d495aSAlexey Orishko */ 954900d495aSAlexey Orishko if (ctx == NULL) 955900d495aSAlexey Orishko goto error; 956900d495aSAlexey Orishko 957c84ff1d6SAlexey Orishko spin_lock_bh(&ctx->mtx); 958900d495aSAlexey Orishko skb_out = cdc_ncm_fill_tx_frame(ctx, skb); 959c84ff1d6SAlexey Orishko spin_unlock_bh(&ctx->mtx); 960900d495aSAlexey Orishko return skb_out; 961900d495aSAlexey Orishko 962900d495aSAlexey Orishko error: 963900d495aSAlexey Orishko if (skb != NULL) 964900d495aSAlexey Orishko dev_kfree_skb_any(skb); 965900d495aSAlexey Orishko 966900d495aSAlexey Orishko return NULL; 967900d495aSAlexey Orishko } 968900d495aSAlexey Orishko 969ff06ab13SBjørn Mork /* verify NTB header and return offset of first NDP, or negative error */ 970ff06ab13SBjørn Mork static int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in) 971900d495aSAlexey Orishko { 972d5ddb4a5SAlexey Orishko struct usb_cdc_ncm_nth16 *nth16; 973ff06ab13SBjørn Mork int len; 974ff06ab13SBjørn Mork int ret = -EINVAL; 975900d495aSAlexey Orishko 976900d495aSAlexey Orishko if (ctx == NULL) 977900d495aSAlexey Orishko goto error; 978900d495aSAlexey Orishko 979d5ddb4a5SAlexey Orishko if (skb_in->len < (sizeof(struct usb_cdc_ncm_nth16) + 980d5ddb4a5SAlexey Orishko sizeof(struct usb_cdc_ncm_ndp16))) { 981900d495aSAlexey Orishko pr_debug("frame too short\n"); 982900d495aSAlexey Orishko goto error; 983900d495aSAlexey Orishko } 984900d495aSAlexey Orishko 985d5ddb4a5SAlexey Orishko nth16 = (struct usb_cdc_ncm_nth16 *)skb_in->data; 986900d495aSAlexey Orishko 987d5ddb4a5SAlexey Orishko if (le32_to_cpu(nth16->dwSignature) != USB_CDC_NCM_NTH16_SIGN) { 988900d495aSAlexey Orishko pr_debug("invalid NTH16 signature <%u>\n", 989d5ddb4a5SAlexey Orishko le32_to_cpu(nth16->dwSignature)); 990900d495aSAlexey Orishko goto error; 991900d495aSAlexey Orishko } 992900d495aSAlexey Orishko 993d5ddb4a5SAlexey Orishko len = le16_to_cpu(nth16->wBlockLength); 994d5ddb4a5SAlexey Orishko if (len > ctx->rx_max) { 995d5ddb4a5SAlexey Orishko pr_debug("unsupported NTB block length %u/%u\n", len, 996d5ddb4a5SAlexey Orishko ctx->rx_max); 997900d495aSAlexey Orishko goto error; 998900d495aSAlexey Orishko } 999900d495aSAlexey Orishko 1000d5ddb4a5SAlexey Orishko if ((ctx->rx_seq + 1) != le16_to_cpu(nth16->wSequence) && 1001d5ddb4a5SAlexey Orishko (ctx->rx_seq || le16_to_cpu(nth16->wSequence)) && 1002d5ddb4a5SAlexey Orishko !((ctx->rx_seq == 0xffff) && !le16_to_cpu(nth16->wSequence))) { 1003d5ddb4a5SAlexey Orishko pr_debug("sequence number glitch prev=%d curr=%d\n", 1004d5ddb4a5SAlexey Orishko ctx->rx_seq, le16_to_cpu(nth16->wSequence)); 1005d5ddb4a5SAlexey Orishko } 1006d5ddb4a5SAlexey Orishko ctx->rx_seq = le16_to_cpu(nth16->wSequence); 1007d5ddb4a5SAlexey Orishko 1008ff06ab13SBjørn Mork ret = le16_to_cpu(nth16->wNdpIndex); 1009ff06ab13SBjørn Mork error: 1010ff06ab13SBjørn Mork return ret; 1011ff06ab13SBjørn Mork } 1012ff06ab13SBjørn Mork 1013ff06ab13SBjørn Mork /* verify NDP header and return number of datagrams, or negative error */ 1014ff06ab13SBjørn Mork static int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset) 1015ff06ab13SBjørn Mork { 1016ff06ab13SBjørn Mork struct usb_cdc_ncm_ndp16 *ndp16; 1017ff06ab13SBjørn Mork int ret = -EINVAL; 1018ff06ab13SBjørn Mork 101975d67d35SBjørn Mork if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) { 102075d67d35SBjørn Mork pr_debug("invalid NDP offset <%u>\n", ndpoffset); 1021900d495aSAlexey Orishko goto error; 1022900d495aSAlexey Orishko } 102375d67d35SBjørn Mork ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset); 1024900d495aSAlexey Orishko 1025ff06ab13SBjørn Mork if (le16_to_cpu(ndp16->wLength) < USB_CDC_NCM_NDP16_LENGTH_MIN) { 1026ff06ab13SBjørn Mork pr_debug("invalid DPT16 length <%u>\n", 1027ff06ab13SBjørn Mork le32_to_cpu(ndp16->dwSignature)); 1028ff06ab13SBjørn Mork goto error; 1029ff06ab13SBjørn Mork } 1030ff06ab13SBjørn Mork 1031ff06ab13SBjørn Mork ret = ((le16_to_cpu(ndp16->wLength) - 1032ff06ab13SBjørn Mork sizeof(struct usb_cdc_ncm_ndp16)) / 1033ff06ab13SBjørn Mork sizeof(struct usb_cdc_ncm_dpe16)); 1034ff06ab13SBjørn Mork ret--; /* we process NDP entries except for the last one */ 1035ff06ab13SBjørn Mork 1036ff06ab13SBjørn Mork if ((sizeof(struct usb_cdc_ncm_ndp16) + ret * (sizeof(struct usb_cdc_ncm_dpe16))) > 1037ff06ab13SBjørn Mork skb_in->len) { 1038ff06ab13SBjørn Mork pr_debug("Invalid nframes = %d\n", ret); 1039ff06ab13SBjørn Mork ret = -EINVAL; 1040ff06ab13SBjørn Mork } 1041ff06ab13SBjørn Mork 1042ff06ab13SBjørn Mork error: 1043ff06ab13SBjørn Mork return ret; 1044ff06ab13SBjørn Mork } 1045ff06ab13SBjørn Mork 1046ff06ab13SBjørn Mork static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) 1047ff06ab13SBjørn Mork { 1048ff06ab13SBjørn Mork struct sk_buff *skb; 1049ff06ab13SBjørn Mork struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; 1050ff06ab13SBjørn Mork int len; 1051ff06ab13SBjørn Mork int nframes; 1052ff06ab13SBjørn Mork int x; 1053ff06ab13SBjørn Mork int offset; 1054ff06ab13SBjørn Mork struct usb_cdc_ncm_ndp16 *ndp16; 1055ff06ab13SBjørn Mork struct usb_cdc_ncm_dpe16 *dpe16; 1056ff06ab13SBjørn Mork int ndpoffset; 1057ff06ab13SBjørn Mork int loopcount = 50; /* arbitrary max preventing infinite loop */ 1058ff06ab13SBjørn Mork 1059ff06ab13SBjørn Mork ndpoffset = cdc_ncm_rx_verify_nth16(ctx, skb_in); 1060ff06ab13SBjørn Mork if (ndpoffset < 0) 1061ff06ab13SBjørn Mork goto error; 1062ff06ab13SBjørn Mork 1063ff06ab13SBjørn Mork next_ndp: 1064ff06ab13SBjørn Mork nframes = cdc_ncm_rx_verify_ndp16(skb_in, ndpoffset); 1065ff06ab13SBjørn Mork if (nframes < 0) 1066ff06ab13SBjørn Mork goto error; 1067ff06ab13SBjørn Mork 1068ff06ab13SBjørn Mork ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset); 1069ff06ab13SBjørn Mork 1070d5ddb4a5SAlexey Orishko if (le32_to_cpu(ndp16->dwSignature) != USB_CDC_NCM_NDP16_NOCRC_SIGN) { 1071900d495aSAlexey Orishko pr_debug("invalid DPT16 signature <%u>\n", 1072d5ddb4a5SAlexey Orishko le32_to_cpu(ndp16->dwSignature)); 107375d67d35SBjørn Mork goto err_ndp; 1074900d495aSAlexey Orishko } 1075ff06ab13SBjørn Mork dpe16 = ndp16->dpe16; 1076900d495aSAlexey Orishko 1077d5ddb4a5SAlexey Orishko for (x = 0; x < nframes; x++, dpe16++) { 1078d5ddb4a5SAlexey Orishko offset = le16_to_cpu(dpe16->wDatagramIndex); 1079d5ddb4a5SAlexey Orishko len = le16_to_cpu(dpe16->wDatagramLength); 1080900d495aSAlexey Orishko 1081900d495aSAlexey Orishko /* 1082900d495aSAlexey Orishko * CDC NCM ch. 3.7 1083900d495aSAlexey Orishko * All entries after first NULL entry are to be ignored 1084900d495aSAlexey Orishko */ 1085d5ddb4a5SAlexey Orishko if ((offset == 0) || (len == 0)) { 1086900d495aSAlexey Orishko if (!x) 108775d67d35SBjørn Mork goto err_ndp; /* empty NTB */ 1088900d495aSAlexey Orishko break; 1089900d495aSAlexey Orishko } 1090900d495aSAlexey Orishko 1091900d495aSAlexey Orishko /* sanity checking */ 1092d5ddb4a5SAlexey Orishko if (((offset + len) > skb_in->len) || 1093d5ddb4a5SAlexey Orishko (len > ctx->rx_max) || (len < ETH_HLEN)) { 1094900d495aSAlexey Orishko pr_debug("invalid frame detected (ignored)" 1095900d495aSAlexey Orishko "offset[%u]=%u, length=%u, skb=%p\n", 1096d5ddb4a5SAlexey Orishko x, offset, len, skb_in); 1097900d495aSAlexey Orishko if (!x) 109875d67d35SBjørn Mork goto err_ndp; 1099900d495aSAlexey Orishko break; 1100900d495aSAlexey Orishko 1101900d495aSAlexey Orishko } else { 1102900d495aSAlexey Orishko skb = skb_clone(skb_in, GFP_ATOMIC); 11039e56790aSJesper Juhl if (!skb) 11049e56790aSJesper Juhl goto error; 1105d5ddb4a5SAlexey Orishko skb->len = len; 1106900d495aSAlexey Orishko skb->data = ((u8 *)skb_in->data) + offset; 1107d5ddb4a5SAlexey Orishko skb_set_tail_pointer(skb, len); 1108900d495aSAlexey Orishko usbnet_skb_return(dev, skb); 1109900d495aSAlexey Orishko } 1110900d495aSAlexey Orishko } 111175d67d35SBjørn Mork err_ndp: 111275d67d35SBjørn Mork /* are there more NDPs to process? */ 111375d67d35SBjørn Mork ndpoffset = le16_to_cpu(ndp16->wNextNdpIndex); 111475d67d35SBjørn Mork if (ndpoffset && loopcount--) 111575d67d35SBjørn Mork goto next_ndp; 111675d67d35SBjørn Mork 1117900d495aSAlexey Orishko return 1; 1118900d495aSAlexey Orishko error: 1119900d495aSAlexey Orishko return 0; 1120900d495aSAlexey Orishko } 1121900d495aSAlexey Orishko 1122900d495aSAlexey Orishko static void 1123900d495aSAlexey Orishko cdc_ncm_speed_change(struct cdc_ncm_ctx *ctx, 112484e77a8bSAlexey Orishko struct usb_cdc_speed_change *data) 1125900d495aSAlexey Orishko { 112684e77a8bSAlexey Orishko uint32_t rx_speed = le32_to_cpu(data->DLBitRRate); 112784e77a8bSAlexey Orishko uint32_t tx_speed = le32_to_cpu(data->ULBitRate); 1128900d495aSAlexey Orishko 1129900d495aSAlexey Orishko /* 1130900d495aSAlexey Orishko * Currently the USB-NET API does not support reporting the actual 1131900d495aSAlexey Orishko * device speed. Do print it instead. 1132900d495aSAlexey Orishko */ 1133900d495aSAlexey Orishko if ((tx_speed != ctx->tx_speed) || (rx_speed != ctx->rx_speed)) { 1134900d495aSAlexey Orishko ctx->tx_speed = tx_speed; 1135900d495aSAlexey Orishko ctx->rx_speed = rx_speed; 1136900d495aSAlexey Orishko 1137900d495aSAlexey Orishko if ((tx_speed > 1000000) && (rx_speed > 1000000)) { 1138900d495aSAlexey Orishko printk(KERN_INFO KBUILD_MODNAME 1139900d495aSAlexey Orishko ": %s: %u mbit/s downlink " 1140900d495aSAlexey Orishko "%u mbit/s uplink\n", 1141900d495aSAlexey Orishko ctx->netdev->name, 1142900d495aSAlexey Orishko (unsigned int)(rx_speed / 1000000U), 1143900d495aSAlexey Orishko (unsigned int)(tx_speed / 1000000U)); 1144900d495aSAlexey Orishko } else { 1145900d495aSAlexey Orishko printk(KERN_INFO KBUILD_MODNAME 1146900d495aSAlexey Orishko ": %s: %u kbit/s downlink " 1147900d495aSAlexey Orishko "%u kbit/s uplink\n", 1148900d495aSAlexey Orishko ctx->netdev->name, 1149900d495aSAlexey Orishko (unsigned int)(rx_speed / 1000U), 1150900d495aSAlexey Orishko (unsigned int)(tx_speed / 1000U)); 1151900d495aSAlexey Orishko } 1152900d495aSAlexey Orishko } 1153900d495aSAlexey Orishko } 1154900d495aSAlexey Orishko 1155900d495aSAlexey Orishko static void cdc_ncm_status(struct usbnet *dev, struct urb *urb) 1156900d495aSAlexey Orishko { 1157900d495aSAlexey Orishko struct cdc_ncm_ctx *ctx; 1158900d495aSAlexey Orishko struct usb_cdc_notification *event; 1159900d495aSAlexey Orishko 1160900d495aSAlexey Orishko ctx = (struct cdc_ncm_ctx *)dev->data[0]; 1161900d495aSAlexey Orishko 1162900d495aSAlexey Orishko if (urb->actual_length < sizeof(*event)) 1163900d495aSAlexey Orishko return; 1164900d495aSAlexey Orishko 1165900d495aSAlexey Orishko /* test for split data in 8-byte chunks */ 1166900d495aSAlexey Orishko if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) { 1167900d495aSAlexey Orishko cdc_ncm_speed_change(ctx, 116884e77a8bSAlexey Orishko (struct usb_cdc_speed_change *)urb->transfer_buffer); 1169900d495aSAlexey Orishko return; 1170900d495aSAlexey Orishko } 1171900d495aSAlexey Orishko 1172900d495aSAlexey Orishko event = urb->transfer_buffer; 1173900d495aSAlexey Orishko 1174900d495aSAlexey Orishko switch (event->bNotificationType) { 1175900d495aSAlexey Orishko case USB_CDC_NOTIFY_NETWORK_CONNECTION: 1176900d495aSAlexey Orishko /* 1177900d495aSAlexey Orishko * According to the CDC NCM specification ch.7.1 1178900d495aSAlexey Orishko * USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be 1179900d495aSAlexey Orishko * sent by device after USB_CDC_NOTIFY_SPEED_CHANGE. 1180900d495aSAlexey Orishko */ 1181900d495aSAlexey Orishko ctx->connected = event->wValue; 1182900d495aSAlexey Orishko 1183900d495aSAlexey Orishko printk(KERN_INFO KBUILD_MODNAME ": %s: network connection:" 1184900d495aSAlexey Orishko " %sconnected\n", 1185900d495aSAlexey Orishko ctx->netdev->name, ctx->connected ? "" : "dis"); 1186900d495aSAlexey Orishko 1187900d495aSAlexey Orishko if (ctx->connected) 1188900d495aSAlexey Orishko netif_carrier_on(dev->net); 1189900d495aSAlexey Orishko else { 1190900d495aSAlexey Orishko netif_carrier_off(dev->net); 1191900d495aSAlexey Orishko ctx->tx_speed = ctx->rx_speed = 0; 1192900d495aSAlexey Orishko } 1193900d495aSAlexey Orishko break; 1194900d495aSAlexey Orishko 1195900d495aSAlexey Orishko case USB_CDC_NOTIFY_SPEED_CHANGE: 119684e77a8bSAlexey Orishko if (urb->actual_length < (sizeof(*event) + 119784e77a8bSAlexey Orishko sizeof(struct usb_cdc_speed_change))) 1198900d495aSAlexey Orishko set_bit(EVENT_STS_SPLIT, &dev->flags); 1199900d495aSAlexey Orishko else 1200900d495aSAlexey Orishko cdc_ncm_speed_change(ctx, 120184e77a8bSAlexey Orishko (struct usb_cdc_speed_change *) &event[1]); 1202900d495aSAlexey Orishko break; 1203900d495aSAlexey Orishko 1204900d495aSAlexey Orishko default: 1205900d495aSAlexey Orishko dev_err(&dev->udev->dev, "NCM: unexpected " 1206900d495aSAlexey Orishko "notification 0x%02x!\n", event->bNotificationType); 1207900d495aSAlexey Orishko break; 1208900d495aSAlexey Orishko } 1209900d495aSAlexey Orishko } 1210900d495aSAlexey Orishko 1211900d495aSAlexey Orishko static int cdc_ncm_check_connect(struct usbnet *dev) 1212900d495aSAlexey Orishko { 1213900d495aSAlexey Orishko struct cdc_ncm_ctx *ctx; 1214900d495aSAlexey Orishko 1215900d495aSAlexey Orishko ctx = (struct cdc_ncm_ctx *)dev->data[0]; 1216900d495aSAlexey Orishko if (ctx == NULL) 1217900d495aSAlexey Orishko return 1; /* disconnected */ 1218900d495aSAlexey Orishko 1219900d495aSAlexey Orishko return !ctx->connected; 1220900d495aSAlexey Orishko } 1221900d495aSAlexey Orishko 1222900d495aSAlexey Orishko static int 1223900d495aSAlexey Orishko cdc_ncm_probe(struct usb_interface *udev, const struct usb_device_id *prod) 1224900d495aSAlexey Orishko { 1225900d495aSAlexey Orishko return usbnet_probe(udev, prod); 1226900d495aSAlexey Orishko } 1227900d495aSAlexey Orishko 1228900d495aSAlexey Orishko static void cdc_ncm_disconnect(struct usb_interface *intf) 1229900d495aSAlexey Orishko { 1230900d495aSAlexey Orishko struct usbnet *dev = usb_get_intfdata(intf); 1231900d495aSAlexey Orishko 1232900d495aSAlexey Orishko if (dev == NULL) 1233900d495aSAlexey Orishko return; /* already disconnected */ 1234900d495aSAlexey Orishko 1235900d495aSAlexey Orishko usbnet_disconnect(intf); 1236900d495aSAlexey Orishko } 1237900d495aSAlexey Orishko 1238900d495aSAlexey Orishko static int cdc_ncm_manage_power(struct usbnet *dev, int status) 1239900d495aSAlexey Orishko { 1240900d495aSAlexey Orishko dev->intf->needs_remote_wakeup = status; 1241900d495aSAlexey Orishko return 0; 1242900d495aSAlexey Orishko } 1243900d495aSAlexey Orishko 1244900d495aSAlexey Orishko static const struct driver_info cdc_ncm_info = { 1245900d495aSAlexey Orishko .description = "CDC NCM", 1246c261344dSArnd Bergmann .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET, 1247900d495aSAlexey Orishko .bind = cdc_ncm_bind, 1248900d495aSAlexey Orishko .unbind = cdc_ncm_unbind, 1249900d495aSAlexey Orishko .check_connect = cdc_ncm_check_connect, 1250900d495aSAlexey Orishko .manage_power = cdc_ncm_manage_power, 1251900d495aSAlexey Orishko .status = cdc_ncm_status, 1252900d495aSAlexey Orishko .rx_fixup = cdc_ncm_rx_fixup, 1253900d495aSAlexey Orishko .tx_fixup = cdc_ncm_tx_fixup, 1254900d495aSAlexey Orishko }; 1255900d495aSAlexey Orishko 1256f94898eaSDan Williams /* Same as cdc_ncm_info, but with FLAG_WWAN */ 1257f94898eaSDan Williams static const struct driver_info wwan_info = { 1258f94898eaSDan Williams .description = "Mobile Broadband Network Device", 1259f94898eaSDan Williams .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET 1260f94898eaSDan Williams | FLAG_WWAN, 1261f94898eaSDan Williams .bind = cdc_ncm_bind, 1262f94898eaSDan Williams .unbind = cdc_ncm_unbind, 1263f94898eaSDan Williams .check_connect = cdc_ncm_check_connect, 1264f94898eaSDan Williams .manage_power = cdc_ncm_manage_power, 1265f94898eaSDan Williams .status = cdc_ncm_status, 1266f94898eaSDan Williams .rx_fixup = cdc_ncm_rx_fixup, 1267f94898eaSDan Williams .tx_fixup = cdc_ncm_tx_fixup, 1268f94898eaSDan Williams }; 1269f94898eaSDan Williams 1270f94898eaSDan Williams static const struct usb_device_id cdc_devs[] = { 1271f94898eaSDan Williams /* Ericsson MBM devices like F5521gw */ 1272f94898eaSDan Williams { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO 1273f94898eaSDan Williams | USB_DEVICE_ID_MATCH_VENDOR, 1274f94898eaSDan Williams .idVendor = 0x0bdb, 1275f94898eaSDan Williams .bInterfaceClass = USB_CLASS_COMM, 1276f94898eaSDan Williams .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM, 1277f94898eaSDan Williams .bInterfaceProtocol = USB_CDC_PROTO_NONE, 1278f94898eaSDan Williams .driver_info = (unsigned long) &wwan_info, 1279f94898eaSDan Williams }, 1280f94898eaSDan Williams 1281f3a1ef9cSPeter Meiser /* Dell branded MBM devices like DW5550 */ 1282f3a1ef9cSPeter Meiser { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO 1283f3a1ef9cSPeter Meiser | USB_DEVICE_ID_MATCH_VENDOR, 1284f3a1ef9cSPeter Meiser .idVendor = 0x413c, 1285f3a1ef9cSPeter Meiser .bInterfaceClass = USB_CLASS_COMM, 1286f3a1ef9cSPeter Meiser .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM, 1287f3a1ef9cSPeter Meiser .bInterfaceProtocol = USB_CDC_PROTO_NONE, 1288f3a1ef9cSPeter Meiser .driver_info = (unsigned long) &wwan_info, 1289f3a1ef9cSPeter Meiser }, 1290f3a1ef9cSPeter Meiser 1291f3a1ef9cSPeter Meiser /* Toshiba branded MBM devices */ 1292f3a1ef9cSPeter Meiser { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO 1293f3a1ef9cSPeter Meiser | USB_DEVICE_ID_MATCH_VENDOR, 1294f3a1ef9cSPeter Meiser .idVendor = 0x0930, 1295f3a1ef9cSPeter Meiser .bInterfaceClass = USB_CLASS_COMM, 1296f3a1ef9cSPeter Meiser .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM, 1297f3a1ef9cSPeter Meiser .bInterfaceProtocol = USB_CDC_PROTO_NONE, 1298f3a1ef9cSPeter Meiser .driver_info = (unsigned long) &wwan_info, 1299f3a1ef9cSPeter Meiser }, 1300f3a1ef9cSPeter Meiser 1301f94898eaSDan Williams /* Generic CDC-NCM devices */ 1302f94898eaSDan Williams { USB_INTERFACE_INFO(USB_CLASS_COMM, 1303f94898eaSDan Williams USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), 1304f94898eaSDan Williams .driver_info = (unsigned long)&cdc_ncm_info, 1305f94898eaSDan Williams }, 1306f94898eaSDan Williams { 1307f94898eaSDan Williams }, 1308f94898eaSDan Williams }; 1309f94898eaSDan Williams MODULE_DEVICE_TABLE(usb, cdc_devs); 1310f94898eaSDan Williams 1311900d495aSAlexey Orishko static struct usb_driver cdc_ncm_driver = { 1312900d495aSAlexey Orishko .name = "cdc_ncm", 1313900d495aSAlexey Orishko .id_table = cdc_devs, 1314900d495aSAlexey Orishko .probe = cdc_ncm_probe, 1315900d495aSAlexey Orishko .disconnect = cdc_ncm_disconnect, 1316900d495aSAlexey Orishko .suspend = usbnet_suspend, 1317900d495aSAlexey Orishko .resume = usbnet_resume, 131885e3c65fSStefan Metzmacher .reset_resume = usbnet_resume, 1319900d495aSAlexey Orishko .supports_autosuspend = 1, 1320e1f12eb6SSarah Sharp .disable_hub_initiated_lpm = 1, 1321900d495aSAlexey Orishko }; 1322900d495aSAlexey Orishko 1323d632eb1bSGreg Kroah-Hartman module_usb_driver(cdc_ncm_driver); 1324900d495aSAlexey Orishko 1325900d495aSAlexey Orishko MODULE_AUTHOR("Hans Petter Selasky"); 1326900d495aSAlexey Orishko MODULE_DESCRIPTION("USB CDC NCM host driver"); 1327900d495aSAlexey Orishko MODULE_LICENSE("Dual BSD/GPL"); 1328