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                usb_set_intfdata(intf, NULL);
  88                usb_driver_release_interface(driver_of(intf), intf);
  89                return status;
  90        }
  91
  92        /* no jumbogram (16K) support for now */
  93
  94        dev->net->hard_header_len += EEM_HEAD + ETH_FCS_LEN + VLAN_HLEN;
  95        dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
  96
  97        return 0;
  98}
  99
 100/*
 101 * EEM permits packing multiple Ethernet frames into USB transfers
 102 * (a "bundle"), but for TX we don't try to do that.
 103 */
 104static struct sk_buff *eem_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
 105                                       gfp_t flags)
 106{
 107        struct sk_buff  *skb2 = NULL;
 108        u16             len = skb->len;
 109        u32             crc = 0;
 110        int             padlen = 0;
 111
 112        /* When ((len + EEM_HEAD + ETH_FCS_LEN) % dev->maxpacket) is
 113         * zero, stick two bytes of zero length EEM packet on the end.
 114         * Else the framework would add invalid single byte padding,
 115         * since it can't know whether ZLPs will be handled right by
 116         * all the relevant hardware and software.
 117         */
 118        if (!((len + EEM_HEAD + ETH_FCS_LEN) % dev->maxpacket))
 119                padlen += 2;
 120
 121        if (!skb_cloned(skb)) {
 122                int     headroom = skb_headroom(skb);
 123                int     tailroom = skb_tailroom(skb);
 124
 125                if ((tailroom >= ETH_FCS_LEN + padlen) &&
 126                    (headroom >= EEM_HEAD))
 127                        goto done;
 128
 129                if ((headroom + tailroom)
 130                                > (EEM_HEAD + ETH_FCS_LEN + padlen)) {
 131                        skb->data = memmove(skb->head +
 132                                        EEM_HEAD,
 133                                        skb->data,
 134                                        skb->len);
 135                        skb_set_tail_pointer(skb, len);
 136                        goto done;
 137                }
 138        }
 139
 140        skb2 = skb_copy_expand(skb, EEM_HEAD, ETH_FCS_LEN + padlen, flags);
 141        if (!skb2)
 142                return NULL;
 143
 144        dev_kfree_skb_any(skb);
 145        skb = skb2;
 146
 147done:
 148        /* we don't use the "no Ethernet CRC" option */
 149        crc = crc32_le(~0, skb->data, skb->len);
 150        crc = ~crc;
 151
 152        put_unaligned_le32(crc, skb_put(skb, 4));
 153
 154        /* EEM packet header format:
 155         * b0..13:      length of ethernet frame
 156         * b14:         bmCRC (1 == valid Ethernet CRC)
 157         * b15:         bmType (0 == data)
 158         */
 159        len = skb->len;
 160        put_unaligned_le16(BIT(14) | len, skb_push(skb, 2));
 161
 162        /* Bundle a zero length EEM packet if needed */
 163        if (padlen)
 164                put_unaligned_le16(0, skb_put(skb, 2));
 165
 166        return skb;
 167}
 168
 169static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 170{
 171        /*
 172         * Our task here is to strip off framing, leaving skb with one
 173         * data frame for the usbnet framework code to process.  But we
 174         * may have received multiple EEM payloads, or command payloads.
 175         * So we must process _everything_ as if it's a header, except
 176         * maybe the last data payload
 177         *
 178         * REVISIT the framework needs updating so that when we consume
 179         * all payloads (the last or only message was a command, or a
 180         * zero length EEM packet) that is not accounted as an rx_error.
 181         */
 182        do {
 183                struct sk_buff  *skb2 = NULL;
 184                u16             header;
 185                u16             len = 0;
 186
 187                /* incomplete EEM header? */
 188                if (skb->len < EEM_HEAD)
 189                        return 0;
 190
 191                /*
 192                 * EEM packet header format:
 193                 * b0..14:      EEM type dependent (Data or Command)
 194                 * b15:         bmType
 195                 */
 196                header = get_unaligned_le16(skb->data);
 197                skb_pull(skb, EEM_HEAD);
 198
 199                /*
 200                 * The bmType bit helps to denote when EEM
 201                 * packet is data or command :
 202                 *      bmType = 0      : EEM data payload
 203                 *      bmType = 1      : EEM (link) command
 204                 */
 205                if (header & BIT(15)) {
 206                        u16     bmEEMCmd;
 207
 208                        /*
 209                         * EEM (link) command packet:
 210                         * b0..10:      bmEEMCmdParam
 211                         * b11..13:     bmEEMCmd
 212                         * b14:         bmReserved (must be 0)
 213                         * b15:         1 (EEM command)
 214                         */
 215                        if (header & BIT(14)) {
 216                                netdev_dbg(dev->net, "reserved command %04x\n",
 217                                           header);
 218                                continue;
 219                        }
 220
 221                        bmEEMCmd = (header >> 11) & 0x7;
 222                        switch (bmEEMCmd) {
 223
 224                        /* Responding to echo requests is mandatory. */
 225                        case 0:         /* Echo command */
 226                                len = header & 0x7FF;
 227
 228                                /* bogus command? */
 229                                if (skb->len < len)
 230                                        return 0;
 231
 232                                skb2 = skb_clone(skb, GFP_ATOMIC);
 233                                if (unlikely(!skb2))
 234                                        goto next;
 235                                skb_trim(skb2, len);
 236                                put_unaligned_le16(BIT(15) | (1 << 11) | len,
 237                                                skb_push(skb2, 2));
 238                                eem_linkcmd(dev, skb2);
 239                                break;
 240
 241                        /*
 242                         * Host may choose to ignore hints.
 243                         *  - suspend: peripheral ready to suspend
 244                         *  - response: suggest N millisec polling
 245                         *  - response complete: suggest N sec polling
 246                         *
 247                         * Suspend is reported and maybe heeded.
 248                         */
 249                        case 2:         /* Suspend hint */
 250                                usbnet_device_suggests_idle(dev);
 251                                continue;
 252                        case 3:         /* Response hint */
 253                        case 4:         /* Response complete hint */
 254                                continue;
 255
 256                        /*
 257                         * Hosts should never receive host-to-peripheral
 258                         * or reserved command codes; or responses to an
 259                         * echo command we didn't send.
 260                         */
 261                        case 1:         /* Echo response */
 262                        case 5:         /* Tickle */
 263                        default:        /* reserved */
 264                                netdev_warn(dev->net,
 265                                            "unexpected link command %d\n",
 266                                            bmEEMCmd);
 267                                continue;
 268                        }
 269
 270                } else {
 271                        u32     crc, crc2;
 272                        int     is_last;
 273
 274                        /* zero length EEM packet? */
 275                        if (header == 0)
 276                                continue;
 277
 278                        /*
 279                         * EEM data packet header :
 280                         * b0..13:      length of ethernet frame
 281                         * b14:         bmCRC
 282                         * b15:         0 (EEM data)
 283                         */
 284                        len = header & 0x3FFF;
 285
 286                        /* bogus EEM payload? */
 287                        if (skb->len < len)
 288                                return 0;
 289
 290                        /* bogus ethernet frame? */
 291                        if (len < (ETH_HLEN + ETH_FCS_LEN))
 292                                goto next;
 293
 294                        /*
 295                         * Treat the last payload differently: framework
 296                         * code expects our "fixup" to have stripped off
 297                         * headers, so "skb" is a data packet (or error).
 298                         * Else if it's not the last payload, keep "skb"
 299                         * for further processing.
 300                         */
 301                        is_last = (len == skb->len);
 302                        if (is_last)
 303                                skb2 = skb;
 304                        else {
 305                                skb2 = skb_clone(skb, GFP_ATOMIC);
 306                                if (unlikely(!skb2))
 307                                        return 0;
 308                        }
 309
 310                        /*
 311                         * The bmCRC helps to denote when the CRC field in
 312                         * the Ethernet frame contains a calculated CRC:
 313                         *      bmCRC = 1       : CRC is calculated
 314                         *      bmCRC = 0       : CRC = 0xDEADBEEF
 315                         */
 316                        if (header & BIT(14)) {
 317                                crc = get_unaligned_le32(skb2->data
 318                                                + len - ETH_FCS_LEN);
 319                                crc2 = ~crc32_le(~0, skb2->data, skb2->len
 320                                                - ETH_FCS_LEN);
 321                        } else {
 322                                crc = get_unaligned_be32(skb2->data
 323                                                + len - ETH_FCS_LEN);
 324                                crc2 = 0xdeadbeef;
 325                        }
 326                        skb_trim(skb2, len - ETH_FCS_LEN);
 327
 328                        if (is_last)
 329                                return crc == crc2;
 330
 331                        if (unlikely(crc != crc2)) {
 332                                dev->net->stats.rx_errors++;
 333                                dev_kfree_skb_any(skb2);
 334                        } else
 335                                usbnet_skb_return(dev, skb2);
 336                }
 337
 338next:
 339                skb_pull(skb, len);
 340        } while (skb->len);
 341
 342        return 1;
 343}
 344
 345static const struct driver_info eem_info = {
 346        .description =  "CDC EEM Device",
 347        .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
 348        .bind =         eem_bind,
 349        .rx_fixup =     eem_rx_fixup,
 350        .tx_fixup =     eem_tx_fixup,
 351};
 352
 353/*-------------------------------------------------------------------------*/
 354
 355static const struct usb_device_id products[] = {
 356{
 357        USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_EEM,
 358                        USB_CDC_PROTO_EEM),
 359        .driver_info = (unsigned long) &eem_info,
 360},
 361{
 362        /* EMPTY == end of list */
 363},
 364};
 365MODULE_DEVICE_TABLE(usb, products);
 366
 367static struct usb_driver eem_driver = {
 368        .name =         "cdc_eem",
 369        .id_table =     products,
 370        .probe =        usbnet_probe,
 371        .disconnect =   usbnet_disconnect,
 372        .suspend =      usbnet_suspend,
 373        .resume =       usbnet_resume,
 374        .disable_hub_initiated_lpm = 1,
 375};
 376
 377module_usb_driver(eem_driver);
 378
 379MODULE_AUTHOR("Omar Laazimani <omar.oberthur@gmail.com>");
 380MODULE_DESCRIPTION("USB CDC EEM");
 381MODULE_LICENSE("GPL");
 382