diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-05-11 14:24:55 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-05-11 14:24:55 -0400 |
commit | cc755896a4274f11283bca32d1d658203844057a (patch) | |
tree | 218970ece71df99f686b9416b7fd88b921690ebb /drivers/net/wireless/orinoco/main.c | |
parent | d250fe91ae129bff0968e685cc9c466d3a5e3482 (diff) | |
parent | 9459d59fbf0bc82ff4c804679fa8bc22788eca63 (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.c | 169 |
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 | */ | ||
367 | int 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 | } | ||
434 | EXPORT_SYMBOL(orinoco_process_xmit_skb); | ||
435 | |||
343 | static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev) | 436 | static 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 | ||