aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/orinoco/main.c
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2010-05-11 14:24:55 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-05-11 14:24:55 -0400
commitcc755896a4274f11283bca32d1d658203844057a (patch)
tree218970ece71df99f686b9416b7fd88b921690ebb /drivers/net/wireless/orinoco/main.c
parentd250fe91ae129bff0968e685cc9c466d3a5e3482 (diff)
parent9459d59fbf0bc82ff4c804679fa8bc22788eca63 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts: drivers/net/wireless/ath/ar9170/main.c
Diffstat (limited to 'drivers/net/wireless/orinoco/main.c')
-rw-r--r--drivers/net/wireless/orinoco/main.c169
1 files changed, 106 insertions, 63 deletions
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 884a7779fc5f..97e954ee17f8 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -340,18 +340,109 @@ EXPORT_SYMBOL(orinoco_change_mtu);
340/* Tx path */ 340/* Tx path */
341/********************************************************************/ 341/********************************************************************/
342 342
343/* Add encapsulation and MIC to the existing SKB.
344 * The main xmit routine will then send the whole lot to the card.
345 * Need 8 bytes headroom
346 * Need 8 bytes tailroom
347 *
348 * With encapsulated ethernet II frame
349 * --------
350 * 803.3 header (14 bytes)
351 * dst[6]
352 * -------- src[6]
353 * 803.3 header (14 bytes) len[2]
354 * dst[6] 803.2 header (8 bytes)
355 * src[6] encaps[6]
356 * len[2] <- leave alone -> len[2]
357 * -------- -------- <-- 0
358 * Payload Payload
359 * ... ...
360 *
361 * -------- --------
362 * MIC (8 bytes)
363 * --------
364 *
365 * returns 0 on success, -ENOMEM on error.
366 */
367int orinoco_process_xmit_skb(struct sk_buff *skb,
368 struct net_device *dev,
369 struct orinoco_private *priv,
370 int *tx_control,
371 u8 *mic_buf)
372{
373 struct orinoco_tkip_key *key;
374 struct ethhdr *eh;
375 int do_mic;
376
377 key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
378
379 do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
380 (key != NULL));
381
382 if (do_mic)
383 *tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
384 HERMES_TXCTRL_MIC;
385
386 eh = (struct ethhdr *)skb->data;
387
388 /* Encapsulate Ethernet-II frames */
389 if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
390 struct header_struct {
391 struct ethhdr eth; /* 802.3 header */
392 u8 encap[6]; /* 802.2 header */
393 } __attribute__ ((packed)) hdr;
394 int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN);
395
396 if (skb_headroom(skb) < ENCAPS_OVERHEAD) {
397 if (net_ratelimit())
398 printk(KERN_ERR
399 "%s: Not enough headroom for 802.2 headers %d\n",
400 dev->name, skb_headroom(skb));
401 return -ENOMEM;
402 }
403
404 /* Fill in new header */
405 memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
406 hdr.eth.h_proto = htons(len);
407 memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
408
409 /* Make room for the new header, and copy it in */
410 eh = (struct ethhdr *) skb_push(skb, ENCAPS_OVERHEAD);
411 memcpy(eh, &hdr, sizeof(hdr));
412 }
413
414 /* Calculate Michael MIC */
415 if (do_mic) {
416 size_t len = skb->len - ETH_HLEN;
417 u8 *mic = &mic_buf[0];
418
419 /* Have to write to an even address, so copy the spare
420 * byte across */
421 if (skb->len % 2) {
422 *mic = skb->data[skb->len - 1];
423 mic++;
424 }
425
426 orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
427 eh->h_dest, eh->h_source, 0 /* priority */,
428 skb->data + ETH_HLEN,
429 len, mic);
430 }
431
432 return 0;
433}
434EXPORT_SYMBOL(orinoco_process_xmit_skb);
435
343static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev) 436static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
344{ 437{
345 struct orinoco_private *priv = ndev_priv(dev); 438 struct orinoco_private *priv = ndev_priv(dev);
346 struct net_device_stats *stats = &priv->stats; 439 struct net_device_stats *stats = &priv->stats;
347 struct orinoco_tkip_key *key;
348 hermes_t *hw = &priv->hw; 440 hermes_t *hw = &priv->hw;
349 int err = 0; 441 int err = 0;
350 u16 txfid = priv->txfid; 442 u16 txfid = priv->txfid;
351 struct ethhdr *eh;
352 int tx_control; 443 int tx_control;
353 unsigned long flags; 444 unsigned long flags;
354 int do_mic; 445 u8 mic_buf[MICHAEL_MIC_LEN+1];
355 446
356 if (!netif_running(dev)) { 447 if (!netif_running(dev)) {
357 printk(KERN_ERR "%s: Tx on stopped device!\n", 448 printk(KERN_ERR "%s: Tx on stopped device!\n",
@@ -383,16 +474,12 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
383 if (skb->len < ETH_HLEN) 474 if (skb->len < ETH_HLEN)
384 goto drop; 475 goto drop;
385 476
386 key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
387
388 do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
389 (key != NULL));
390
391 tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; 477 tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
392 478
393 if (do_mic) 479 err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
394 tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | 480 &mic_buf[0]);
395 HERMES_TXCTRL_MIC; 481 if (err)
482 goto drop;
396 483
397 if (priv->has_alt_txcntl) { 484 if (priv->has_alt_txcntl) {
398 /* WPA enabled firmwares have tx_cntl at the end of 485 /* WPA enabled firmwares have tx_cntl at the end of
@@ -435,34 +522,6 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
435 HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); 522 HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
436 } 523 }
437 524
438 eh = (struct ethhdr *)skb->data;
439
440 /* Encapsulate Ethernet-II frames */
441 if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
442 struct header_struct {
443 struct ethhdr eth; /* 802.3 header */
444 u8 encap[6]; /* 802.2 header */
445 } __attribute__ ((packed)) hdr;
446
447 /* Strip destination and source from the data */
448 skb_pull(skb, 2 * ETH_ALEN);
449
450 /* And move them to a separate header */
451 memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
452 hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len);
453 memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
454
455 /* Insert the SNAP header */
456 if (skb_headroom(skb) < sizeof(hdr)) {
457 printk(KERN_ERR
458 "%s: Not enough headroom for 802.2 headers %d\n",
459 dev->name, skb_headroom(skb));
460 goto drop;
461 }
462 eh = (struct ethhdr *) skb_push(skb, sizeof(hdr));
463 memcpy(eh, &hdr, sizeof(hdr));
464 }
465
466 err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len, 525 err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len,
467 txfid, HERMES_802_3_OFFSET); 526 txfid, HERMES_802_3_OFFSET);
468 if (err) { 527 if (err) {
@@ -471,32 +530,16 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
471 goto busy; 530 goto busy;
472 } 531 }
473 532
474 /* Calculate Michael MIC */ 533 if (tx_control & HERMES_TXCTRL_MIC) {
475 if (do_mic) { 534 size_t offset = HERMES_802_3_OFFSET + skb->len;
476 u8 mic_buf[MICHAEL_MIC_LEN + 1]; 535 size_t len = MICHAEL_MIC_LEN;
477 u8 *mic;
478 size_t offset;
479 size_t len;
480 536
481 if (skb->len % 2) { 537 if (offset % 2) {
482 /* MIC start is on an odd boundary */ 538 offset--;
483 mic_buf[0] = skb->data[skb->len - 1]; 539 len++;
484 mic = &mic_buf[1];
485 offset = skb->len - 1;
486 len = MICHAEL_MIC_LEN + 1;
487 } else {
488 mic = &mic_buf[0];
489 offset = skb->len;
490 len = MICHAEL_MIC_LEN;
491 } 540 }
492
493 orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
494 eh->h_dest, eh->h_source, 0 /* priority */,
495 skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
496
497 /* Write the MIC */
498 err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len, 541 err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
499 txfid, HERMES_802_3_OFFSET + offset); 542 txfid, offset);
500 if (err) { 543 if (err) {
501 printk(KERN_ERR "%s: Error %d writing MIC to BAP\n", 544 printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
502 dev->name, err); 545 dev->name, err);
@@ -2234,7 +2277,7 @@ int orinoco_if_add(struct orinoco_private *priv,
2234 /* we use the default eth_mac_addr for setting the MAC addr */ 2277 /* we use the default eth_mac_addr for setting the MAC addr */
2235 2278
2236 /* Reserve space in skb for the SNAP header */ 2279 /* Reserve space in skb for the SNAP header */
2237 dev->hard_header_len += ENCAPS_OVERHEAD; 2280 dev->needed_headroom = ENCAPS_OVERHEAD;
2238 2281
2239 netif_carrier_off(dev); 2282 netif_carrier_off(dev);
2240 2283