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, write to the Free Software
  18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19 */
  20
  21#include <linux/module.h>
  22#include <linux/init.h>
  23#include <linux/netdevice.h>
  24#include <linux/etherdevice.h>
  25#include <linux/ctype.h>
  26#include <linux/ethtool.h>
  27#include <linux/workqueue.h>
  28#include <linux/mii.h>
  29#include <linux/usb.h>
  30#include <linux/crc32.h>
  31#include <linux/usb/cdc.h>
  32#include <linux/usb/usbnet.h>
  33#include <linux/gfp.h>
  34
  35
  36/*
  37 * This driver is an implementation of the CDC "Ethernet Emulation
  38 * Model" (EEM) specification, which encapsulates Ethernet frames
  39 * for transport over USB using a simpler USB device model than the
  40 * previous CDC "Ethernet Control Model" (ECM, or "CDC Ethernet").
  41 *
  42 * For details, see www.usb.org/developers/devclass_docs/CDC_EEM10.pdf
  43 *
  44 * This version has been tested with GIGAntIC WuaoW SIM Smart Card on 2.6.24,
  45 * 2.6.27 and 2.6.30rc2 kernel.
  46 * It has also been validated on Openmoko Om 2008.12 (based on 2.6.24 kernel).
  47 * build on 23-April-2009
  48 */
  49
  50#define EEM_HEAD        2               /* 2 byte header */
  51
  52/*-------------------------------------------------------------------------*/
  53
  54static void eem_linkcmd_complete(struct urb *urb)
  55{
  56        dev_kfree_skb(urb->context);
  57        usb_free_urb(urb);
  58}
  59
  60static void eem_linkcmd(struct usbnet *dev, struct sk_buff *skb)
  61{
  62        struct urb              *urb;
  63        int                     status;
  64
  65        urb = usb_alloc_urb(0, GFP_ATOMIC);
  66        if (!urb)
  67                goto fail;
  68
  69        usb_fill_bulk_urb(urb, dev->udev, dev->out,
  70                        skb->data, skb->len, eem_linkcmd_complete, skb);
  71
  72        status = usb_submit_urb(urb, GFP_ATOMIC);
  73        if (status) {
  74                usb_free_urb(urb);
  75fail:
  76                dev_kfree_skb(skb);
  77                netdev_warn(dev->net, "link cmd failure\n");
  78                return;
  79        }
  80}
  81
  82static int eem_bind(struct usbnet *dev, struct usb_interface *intf)
  83{
  84        int status = 0;
  85
  86        status = usbnet_get_endpoints(dev, intf);
  87        if (status < 0) {
  88                usb_set_intfdata(intf, NULL);
  89                usb_driver_release_interface(driver_of(intf), intf);
  90                return status;
  91        }
  92
  93        /* no jumbogram (16K) support for now */
  94
  95        dev->net->hard_header_len += EEM_HEAD + ETH_FCS_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                        case 2:         /* Suspend hint */
 248                        case 3:         /* Response hint */
 249                        case 4:         /* Response complete hint */
 250                                continue;
 251
 252                        /*
 253                         * Hosts should never receive host-to-peripheral
 254                         * or reserved command codes; or responses to an
 255                         * echo command we didn't send.
 256                         */
 257                        case 1:         /* Echo response */
 258                        case 5:         /* Tickle */
 259                        default:        /* reserved */
 260                                netdev_warn(dev->net,
 261                                            "unexpected link command %d\n",
 262                                            bmEEMCmd);
 263                                continue;
 264                        }
 265
 266                } else {
 267                        u32     crc, crc2;
 268                        int     is_last;
 269
 270                        /* zero length EEM packet? */
 271                        if (header == 0)
 272                                continue;
 273
 274                        /*
 275                         * EEM data packet header :
 276                         * b0..13:      length of ethernet frame
 277                         * b14:         bmCRC
 278                         * b15:         0 (EEM data)
 279                         */
 280                        len = header & 0x3FFF;
 281
 282                        /* bogus EEM payload? */
 283                        if (skb->len < len)
 284                                return 0;
 285
 286                        /* bogus ethernet frame? */
 287                        if (len < (ETH_HLEN + ETH_FCS_LEN))
 288                                goto next;
 289
 290                        /*
 291                         * Treat the last payload differently: framework
 292                         * code expects our "fixup" to have stripped off
 293                         * headers, so "skb" is a data packet (or error).
 294                         * Else if it's not the last payload, keep "skb"
 295                         * for further processing.
 296                         */
 297                        is_last = (len == skb->len);
 298                        if (is_last)
 299                                skb2 = skb;
 300                        else {
 301                                skb2 = skb_clone(skb, GFP_ATOMIC);
 302                                if (unlikely(!skb2))
 303                                        return 0;
 304                        }
 305
 306                        /*
 307                         * The bmCRC helps to denote when the CRC field in
 308                         * the Ethernet frame contains a calculated CRC:
 309                         *      bmCRC = 1       : CRC is calculated
 310                         *      bmCRC = 0       : CRC = 0xDEADBEEF
 311                         */
 312                        if (header & BIT(14)) {
 313                                crc = get_unaligned_le32(skb2->data
 314                                                + len - ETH_FCS_LEN);
 315                                crc2 = ~crc32_le(~0, skb2->data, skb2->len
 316                                                - ETH_FCS_LEN);
 317                        } else {
 318                                crc = get_unaligned_be32(skb2->data
 319                                                + len - ETH_FCS_LEN);
 320                                crc2 = 0xdeadbeef;
 321                        }
 322                        skb_trim(skb2, len - ETH_FCS_LEN);
 323
 324                        if (is_last)
 325                                return crc == crc2;
 326
 327                        if (unlikely(crc != crc2)) {
 328                                dev->net->stats.rx_errors++;
 329                                dev_kfree_skb_any(skb2);
 330                        } else
 331                                usbnet_skb_return(dev, skb2);
 332                }
 333
 334next:
 335                skb_pull(skb, len);
 336        } while (skb->len);
 337
 338        return 1;
 339}
 340
 341static const struct driver_info eem_info = {
 342        .description =  "CDC EEM Device",
 343        .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
 344        .bind =         eem_bind,
 345        .rx_fixup =     eem_rx_fixup,
 346        .tx_fixup =     eem_tx_fixup,
 347};
 348
 349/*-------------------------------------------------------------------------*/
 350
 351static const struct usb_device_id products[] = {
 352{
 353        USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_EEM,
 354                        USB_CDC_PROTO_EEM),
 355        .driver_info = (unsigned long) &eem_info,
 356},
 357{
 358        /* EMPTY == end of list */
 359},
 360};
 361MODULE_DEVICE_TABLE(usb, products);
 362
 363static struct usb_driver eem_driver = {
 364        .name =         "cdc_eem",
 365        .id_table =     products,
 366        .probe =        usbnet_probe,
 367        .disconnect =   usbnet_disconnect,
 368        .suspend =      usbnet_suspend,
 369        .resume =       usbnet_resume,
 370};
 371
 372module_usb_driver(eem_driver);
 373
 374MODULE_AUTHOR("Omar Laazimani <omar.oberthur@gmail.com>");
 375MODULE_DESCRIPTION("USB CDC EEM");
 376MODULE_LICENSE("GPL");
 377