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