root/drivers/net/usb/cdc_eem.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. eem_linkcmd_complete
  2. eem_linkcmd
  3. eem_bind
  4. eem_tx_fixup
  5. eem_rx_fixup

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * USB CDC EEM network interface driver
   4  * Copyright (C) 2009 Oberthur Technologies
   5  * by Omar Laazimani, Olivier Condemine
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/netdevice.h>
  10 #include <linux/etherdevice.h>
  11 #include <linux/ctype.h>
  12 #include <linux/ethtool.h>
  13 #include <linux/workqueue.h>
  14 #include <linux/mii.h>
  15 #include <linux/usb.h>
  16 #include <linux/crc32.h>
  17 #include <linux/usb/cdc.h>
  18 #include <linux/usb/usbnet.h>
  19 #include <linux/gfp.h>
  20 #include <linux/if_vlan.h>
  21 
  22 
  23 /*
  24  * This driver is an implementation of the CDC "Ethernet Emulation
  25  * Model" (EEM) specification, which encapsulates Ethernet frames
  26  * for transport over USB using a simpler USB device model than the
  27  * previous CDC "Ethernet Control Model" (ECM, or "CDC Ethernet").
  28  *
  29  * For details, see www.usb.org/developers/devclass_docs/CDC_EEM10.pdf
  30  *
  31  * This version has been tested with GIGAntIC WuaoW SIM Smart Card on 2.6.24,
  32  * 2.6.27 and 2.6.30rc2 kernel.
  33  * It has also been validated on Openmoko Om 2008.12 (based on 2.6.24 kernel).
  34  * build on 23-April-2009
  35  */
  36 
  37 #define EEM_HEAD        2               /* 2 byte header */
  38 
  39 /*-------------------------------------------------------------------------*/
  40 
  41 static void eem_linkcmd_complete(struct urb *urb)
  42 {
  43         dev_kfree_skb(urb->context);
  44         usb_free_urb(urb);
  45 }
  46 
  47 static void eem_linkcmd(struct usbnet *dev, struct sk_buff *skb)
  48 {
  49         struct urb              *urb;
  50         int                     status;
  51 
  52         urb = usb_alloc_urb(0, GFP_ATOMIC);
  53         if (!urb)
  54                 goto fail;
  55 
  56         usb_fill_bulk_urb(urb, dev->udev, dev->out,
  57                         skb->data, skb->len, eem_linkcmd_complete, skb);
  58 
  59         status = usb_submit_urb(urb, GFP_ATOMIC);
  60         if (status) {
  61                 usb_free_urb(urb);
  62 fail:
  63                 dev_kfree_skb(skb);
  64                 netdev_warn(dev->net, "link cmd failure\n");
  65                 return;
  66         }
  67 }
  68 
  69 static int eem_bind(struct usbnet *dev, struct usb_interface *intf)
  70 {
  71         int status = 0;
  72 
  73         status = usbnet_get_endpoints(dev, intf);
  74         if (status < 0)
  75                 return status;
  76 
  77         /* no jumbogram (16K) support for now */
  78 
  79         dev->net->hard_header_len += EEM_HEAD + ETH_FCS_LEN + VLAN_HLEN;
  80         dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
  81 
  82         return 0;
  83 }
  84 
  85 /*
  86  * EEM permits packing multiple Ethernet frames into USB transfers
  87  * (a "bundle"), but for TX we don't try to do that.
  88  */
  89 static struct sk_buff *eem_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
  90                                        gfp_t flags)
  91 {
  92         struct sk_buff  *skb2 = NULL;
  93         u16             len = skb->len;
  94         u32             crc = 0;
  95         int             padlen = 0;
  96 
  97         /* When ((len + EEM_HEAD + ETH_FCS_LEN) % dev->maxpacket) is
  98          * zero, stick two bytes of zero length EEM packet on the end.
  99          * Else the framework would add invalid single byte padding,
 100          * since it can't know whether ZLPs will be handled right by
 101          * all the relevant hardware and software.
 102          */
 103         if (!((len + EEM_HEAD + ETH_FCS_LEN) % dev->maxpacket))
 104                 padlen += 2;
 105 
 106         if (!skb_cloned(skb)) {
 107                 int     headroom = skb_headroom(skb);
 108                 int     tailroom = skb_tailroom(skb);
 109 
 110                 if ((tailroom >= ETH_FCS_LEN + padlen) &&
 111                     (headroom >= EEM_HEAD))
 112                         goto done;
 113 
 114                 if ((headroom + tailroom)
 115                                 > (EEM_HEAD + ETH_FCS_LEN + padlen)) {
 116                         skb->data = memmove(skb->head +
 117                                         EEM_HEAD,
 118                                         skb->data,
 119                                         skb->len);
 120                         skb_set_tail_pointer(skb, len);
 121                         goto done;
 122                 }
 123         }
 124 
 125         skb2 = skb_copy_expand(skb, EEM_HEAD, ETH_FCS_LEN + padlen, flags);
 126         if (!skb2)
 127                 return NULL;
 128 
 129         dev_kfree_skb_any(skb);
 130         skb = skb2;
 131 
 132 done:
 133         /* we don't use the "no Ethernet CRC" option */
 134         crc = crc32_le(~0, skb->data, skb->len);
 135         crc = ~crc;
 136 
 137         put_unaligned_le32(crc, skb_put(skb, 4));
 138 
 139         /* EEM packet header format:
 140          * b0..13:      length of ethernet frame
 141          * b14:         bmCRC (1 == valid Ethernet CRC)
 142          * b15:         bmType (0 == data)
 143          */
 144         len = skb->len;
 145         put_unaligned_le16(BIT(14) | len, skb_push(skb, 2));
 146 
 147         /* Bundle a zero length EEM packet if needed */
 148         if (padlen)
 149                 put_unaligned_le16(0, skb_put(skb, 2));
 150 
 151         return skb;
 152 }
 153 
 154 static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 155 {
 156         /*
 157          * Our task here is to strip off framing, leaving skb with one
 158          * data frame for the usbnet framework code to process.  But we
 159          * may have received multiple EEM payloads, or command payloads.
 160          * So we must process _everything_ as if it's a header, except
 161          * maybe the last data payload
 162          *
 163          * REVISIT the framework needs updating so that when we consume
 164          * all payloads (the last or only message was a command, or a
 165          * zero length EEM packet) that is not accounted as an rx_error.
 166          */
 167         do {
 168                 struct sk_buff  *skb2 = NULL;
 169                 u16             header;
 170                 u16             len = 0;
 171 
 172                 /* incomplete EEM header? */
 173                 if (skb->len < EEM_HEAD)
 174                         return 0;
 175 
 176                 /*
 177                  * EEM packet header format:
 178                  * b0..14:      EEM type dependent (Data or Command)
 179                  * b15:         bmType
 180                  */
 181                 header = get_unaligned_le16(skb->data);
 182                 skb_pull(skb, EEM_HEAD);
 183 
 184                 /*
 185                  * The bmType bit helps to denote when EEM
 186                  * packet is data or command :
 187                  *      bmType = 0      : EEM data payload
 188                  *      bmType = 1      : EEM (link) command
 189                  */
 190                 if (header & BIT(15)) {
 191                         u16     bmEEMCmd;
 192 
 193                         /*
 194                          * EEM (link) command packet:
 195                          * b0..10:      bmEEMCmdParam
 196                          * b11..13:     bmEEMCmd
 197                          * b14:         bmReserved (must be 0)
 198                          * b15:         1 (EEM command)
 199                          */
 200                         if (header & BIT(14)) {
 201                                 netdev_dbg(dev->net, "reserved command %04x\n",
 202                                            header);
 203                                 continue;
 204                         }
 205 
 206                         bmEEMCmd = (header >> 11) & 0x7;
 207                         switch (bmEEMCmd) {
 208 
 209                         /* Responding to echo requests is mandatory. */
 210                         case 0:         /* Echo command */
 211                                 len = header & 0x7FF;
 212 
 213                                 /* bogus command? */
 214                                 if (skb->len < len)
 215                                         return 0;
 216 
 217                                 skb2 = skb_clone(skb, GFP_ATOMIC);
 218                                 if (unlikely(!skb2))
 219                                         goto next;
 220                                 skb_trim(skb2, len);
 221                                 put_unaligned_le16(BIT(15) | (1 << 11) | len,
 222                                                 skb_push(skb2, 2));
 223                                 eem_linkcmd(dev, skb2);
 224                                 break;
 225 
 226                         /*
 227                          * Host may choose to ignore hints.
 228                          *  - suspend: peripheral ready to suspend
 229                          *  - response: suggest N millisec polling
 230                          *  - response complete: suggest N sec polling
 231                          *
 232                          * Suspend is reported and maybe heeded.
 233                          */
 234                         case 2:         /* Suspend hint */
 235                                 usbnet_device_suggests_idle(dev);
 236                                 continue;
 237                         case 3:         /* Response hint */
 238                         case 4:         /* Response complete hint */
 239                                 continue;
 240 
 241                         /*
 242                          * Hosts should never receive host-to-peripheral
 243                          * or reserved command codes; or responses to an
 244                          * echo command we didn't send.
 245                          */
 246                         case 1:         /* Echo response */
 247                         case 5:         /* Tickle */
 248                         default:        /* reserved */
 249                                 netdev_warn(dev->net,
 250                                             "unexpected link command %d\n",
 251                                             bmEEMCmd);
 252                                 continue;
 253                         }
 254 
 255                 } else {
 256                         u32     crc, crc2;
 257                         int     is_last;
 258 
 259                         /* zero length EEM packet? */
 260                         if (header == 0)
 261                                 continue;
 262 
 263                         /*
 264                          * EEM data packet header :
 265                          * b0..13:      length of ethernet frame
 266                          * b14:         bmCRC
 267                          * b15:         0 (EEM data)
 268                          */
 269                         len = header & 0x3FFF;
 270 
 271                         /* bogus EEM payload? */
 272                         if (skb->len < len)
 273                                 return 0;
 274 
 275                         /* bogus ethernet frame? */
 276                         if (len < (ETH_HLEN + ETH_FCS_LEN))
 277                                 goto next;
 278 
 279                         /*
 280                          * Treat the last payload differently: framework
 281                          * code expects our "fixup" to have stripped off
 282                          * headers, so "skb" is a data packet (or error).
 283                          * Else if it's not the last payload, keep "skb"
 284                          * for further processing.
 285                          */
 286                         is_last = (len == skb->len);
 287                         if (is_last)
 288                                 skb2 = skb;
 289                         else {
 290                                 skb2 = skb_clone(skb, GFP_ATOMIC);
 291                                 if (unlikely(!skb2))
 292                                         return 0;
 293                         }
 294 
 295                         /*
 296                          * The bmCRC helps to denote when the CRC field in
 297                          * the Ethernet frame contains a calculated CRC:
 298                          *      bmCRC = 1       : CRC is calculated
 299                          *      bmCRC = 0       : CRC = 0xDEADBEEF
 300                          */
 301                         if (header & BIT(14)) {
 302                                 crc = get_unaligned_le32(skb2->data
 303                                                 + len - ETH_FCS_LEN);
 304                                 crc2 = ~crc32_le(~0, skb2->data, skb2->len
 305                                                 - ETH_FCS_LEN);
 306                         } else {
 307                                 crc = get_unaligned_be32(skb2->data
 308                                                 + len - ETH_FCS_LEN);
 309                                 crc2 = 0xdeadbeef;
 310                         }
 311                         skb_trim(skb2, len - ETH_FCS_LEN);
 312 
 313                         if (is_last)
 314                                 return crc == crc2;
 315 
 316                         if (unlikely(crc != crc2)) {
 317                                 dev->net->stats.rx_errors++;
 318                                 dev_kfree_skb_any(skb2);
 319                         } else
 320                                 usbnet_skb_return(dev, skb2);
 321                 }
 322 
 323 next:
 324                 skb_pull(skb, len);
 325         } while (skb->len);
 326 
 327         return 1;
 328 }
 329 
 330 static const struct driver_info eem_info = {
 331         .description =  "CDC EEM Device",
 332         .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
 333         .bind =         eem_bind,
 334         .rx_fixup =     eem_rx_fixup,
 335         .tx_fixup =     eem_tx_fixup,
 336 };
 337 
 338 /*-------------------------------------------------------------------------*/
 339 
 340 static const struct usb_device_id products[] = {
 341 {
 342         USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_EEM,
 343                         USB_CDC_PROTO_EEM),
 344         .driver_info = (unsigned long) &eem_info,
 345 },
 346 {
 347         /* EMPTY == end of list */
 348 },
 349 };
 350 MODULE_DEVICE_TABLE(usb, products);
 351 
 352 static struct usb_driver eem_driver = {
 353         .name =         "cdc_eem",
 354         .id_table =     products,
 355         .probe =        usbnet_probe,
 356         .disconnect =   usbnet_disconnect,
 357         .suspend =      usbnet_suspend,
 358         .resume =       usbnet_resume,
 359         .disable_hub_initiated_lpm = 1,
 360 };
 361 
 362 module_usb_driver(eem_driver);
 363 
 364 MODULE_AUTHOR("Omar Laazimani <omar.oberthur@gmail.com>");
 365 MODULE_DESCRIPTION("USB CDC EEM");
 366 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */