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