diff options
Diffstat (limited to 'drivers/net/wireless/p54/p54common.c')
-rw-r--r-- | drivers/net/wireless/p54/p54common.c | 60 |
1 files changed, 50 insertions, 10 deletions
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 82354b974a04..34561e6e816b 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c | |||
@@ -138,6 +138,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) | |||
138 | u8 *fw_version = NULL; | 138 | u8 *fw_version = NULL; |
139 | size_t len; | 139 | size_t len; |
140 | int i; | 140 | int i; |
141 | int maxlen; | ||
141 | 142 | ||
142 | if (priv->rx_start) | 143 | if (priv->rx_start) |
143 | return 0; | 144 | return 0; |
@@ -195,6 +196,16 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) | |||
195 | else | 196 | else |
196 | priv->rx_mtu = (size_t) | 197 | priv->rx_mtu = (size_t) |
197 | 0x620 - priv->tx_hdr_len; | 198 | 0x620 - priv->tx_hdr_len; |
199 | maxlen = priv->tx_hdr_len + /* USB devices */ | ||
200 | sizeof(struct p54_rx_data) + | ||
201 | 4 + /* rx alignment */ | ||
202 | IEEE80211_MAX_FRAG_THRESHOLD; | ||
203 | if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) { | ||
204 | printk(KERN_INFO "p54: rx_mtu reduced from %d " | ||
205 | "to %d\n", priv->rx_mtu, | ||
206 | maxlen); | ||
207 | priv->rx_mtu = maxlen; | ||
208 | } | ||
198 | break; | 209 | break; |
199 | } | 210 | } |
200 | case BR_CODE_EXPOSED_IF: | 211 | case BR_CODE_EXPOSED_IF: |
@@ -440,8 +451,8 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) | |||
440 | } | 451 | } |
441 | if (err) | 452 | if (err) |
442 | goto err; | 453 | goto err; |
443 | 454 | } | |
444 | } | 455 | break; |
445 | case PDR_PRISM_ZIF_TX_IQ_CALIBRATION: | 456 | case PDR_PRISM_ZIF_TX_IQ_CALIBRATION: |
446 | priv->iq_autocal = kmalloc(data_len, GFP_KERNEL); | 457 | priv->iq_autocal = kmalloc(data_len, GFP_KERNEL); |
447 | if (!priv->iq_autocal) { | 458 | if (!priv->iq_autocal) { |
@@ -575,6 +586,7 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
575 | u16 freq = le16_to_cpu(hdr->freq); | 586 | u16 freq = le16_to_cpu(hdr->freq); |
576 | size_t header_len = sizeof(*hdr); | 587 | size_t header_len = sizeof(*hdr); |
577 | u32 tsf32; | 588 | u32 tsf32; |
589 | u8 rate = hdr->rate & 0xf; | ||
578 | 590 | ||
579 | /* | 591 | /* |
580 | * If the device is in a unspecified state we have to | 592 | * If the device is in a unspecified state we have to |
@@ -603,8 +615,11 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
603 | rx_status.qual = (100 * hdr->rssi) / 127; | 615 | rx_status.qual = (100 * hdr->rssi) / 127; |
604 | if (hdr->rate & 0x10) | 616 | if (hdr->rate & 0x10) |
605 | rx_status.flag |= RX_FLAG_SHORTPRE; | 617 | rx_status.flag |= RX_FLAG_SHORTPRE; |
606 | rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ? | 618 | if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) |
607 | hdr->rate : (hdr->rate - 4)) & 0xf; | 619 | rx_status.rate_idx = (rate < 4) ? 0 : rate - 4; |
620 | else | ||
621 | rx_status.rate_idx = rate; | ||
622 | |||
608 | rx_status.freq = freq; | 623 | rx_status.freq = freq; |
609 | rx_status.band = dev->conf.channel->band; | 624 | rx_status.band = dev->conf.channel->band; |
610 | rx_status.antenna = hdr->antenna; | 625 | rx_status.antenna = hdr->antenna; |
@@ -730,7 +745,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
730 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); | 745 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); |
731 | struct p54_hdr *entry_hdr; | 746 | struct p54_hdr *entry_hdr; |
732 | struct p54_tx_data *entry_data; | 747 | struct p54_tx_data *entry_data; |
733 | int pad = 0; | 748 | unsigned int pad = 0, frame_len; |
734 | 749 | ||
735 | range = (void *)info->rate_driver_data; | 750 | range = (void *)info->rate_driver_data; |
736 | if (range->start_addr != addr) { | 751 | if (range->start_addr != addr) { |
@@ -753,6 +768,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
753 | __skb_unlink(entry, &priv->tx_queue); | 768 | __skb_unlink(entry, &priv->tx_queue); |
754 | spin_unlock_irqrestore(&priv->tx_queue.lock, flags); | 769 | spin_unlock_irqrestore(&priv->tx_queue.lock, flags); |
755 | 770 | ||
771 | frame_len = entry->len; | ||
756 | entry_hdr = (struct p54_hdr *) entry->data; | 772 | entry_hdr = (struct p54_hdr *) entry->data; |
757 | entry_data = (struct p54_tx_data *) entry_hdr->data; | 773 | entry_data = (struct p54_tx_data *) entry_hdr->data; |
758 | priv->tx_stats[entry_data->hw_queue].len--; | 774 | priv->tx_stats[entry_data->hw_queue].len--; |
@@ -798,6 +814,29 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
798 | info->flags |= IEEE80211_TX_STAT_TX_FILTERED; | 814 | info->flags |= IEEE80211_TX_STAT_TX_FILTERED; |
799 | info->status.ack_signal = p54_rssi_to_dbm(dev, | 815 | info->status.ack_signal = p54_rssi_to_dbm(dev, |
800 | (int)payload->ack_rssi); | 816 | (int)payload->ack_rssi); |
817 | |||
818 | /* Undo all changes to the frame. */ | ||
819 | switch (entry_data->key_type) { | ||
820 | case P54_CRYPTO_TKIPMICHAEL: { | ||
821 | u8 *iv = (u8 *)(entry_data->align + pad + | ||
822 | entry_data->crypt_offset); | ||
823 | |||
824 | /* Restore the original TKIP IV. */ | ||
825 | iv[2] = iv[0]; | ||
826 | iv[0] = iv[1]; | ||
827 | iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */ | ||
828 | |||
829 | frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */ | ||
830 | break; | ||
831 | } | ||
832 | case P54_CRYPTO_AESCCMP: | ||
833 | frame_len -= 8; /* remove CCMP_MIC */ | ||
834 | break; | ||
835 | case P54_CRYPTO_WEP: | ||
836 | frame_len -= 4; /* remove WEP_ICV */ | ||
837 | break; | ||
838 | } | ||
839 | skb_trim(entry, frame_len); | ||
801 | skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); | 840 | skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); |
802 | ieee80211_tx_status_irqsafe(dev, entry); | 841 | ieee80211_tx_status_irqsafe(dev, entry); |
803 | goto out; | 842 | goto out; |
@@ -1122,7 +1161,7 @@ static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, | |||
1122 | 1161 | ||
1123 | skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, | 1162 | skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, |
1124 | sizeof(struct p54_hdr) + sizeof(*tim), | 1163 | sizeof(struct p54_hdr) + sizeof(*tim), |
1125 | P54_CONTROL_TYPE_TIM, GFP_KERNEL); | 1164 | P54_CONTROL_TYPE_TIM, GFP_ATOMIC); |
1126 | if (!skb) | 1165 | if (!skb) |
1127 | return -ENOMEM; | 1166 | return -ENOMEM; |
1128 | 1167 | ||
@@ -1383,7 +1422,6 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
1383 | hdr->tries = ridx; | 1422 | hdr->tries = ridx; |
1384 | txhdr->rts_rate_idx = 0; | 1423 | txhdr->rts_rate_idx = 0; |
1385 | if (info->control.hw_key) { | 1424 | if (info->control.hw_key) { |
1386 | crypt_offset += info->control.hw_key->iv_len; | ||
1387 | txhdr->key_type = p54_convert_algo(info->control.hw_key->alg); | 1425 | txhdr->key_type = p54_convert_algo(info->control.hw_key->alg); |
1388 | txhdr->key_len = min((u8)16, info->control.hw_key->keylen); | 1426 | txhdr->key_len = min((u8)16, info->control.hw_key->keylen); |
1389 | memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len); | 1427 | memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len); |
@@ -1397,6 +1435,8 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
1397 | } | 1435 | } |
1398 | /* reserve some space for ICV */ | 1436 | /* reserve some space for ICV */ |
1399 | len += info->control.hw_key->icv_len; | 1437 | len += info->control.hw_key->icv_len; |
1438 | memset(skb_put(skb, info->control.hw_key->icv_len), 0, | ||
1439 | info->control.hw_key->icv_len); | ||
1400 | } else { | 1440 | } else { |
1401 | txhdr->key_type = 0; | 1441 | txhdr->key_type = 0; |
1402 | txhdr->key_len = 0; | 1442 | txhdr->key_len = 0; |
@@ -1584,7 +1624,7 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell) | |||
1584 | 1624 | ||
1585 | err: | 1625 | err: |
1586 | printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy)); | 1626 | printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy)); |
1587 | kfree_skb(skb); | 1627 | p54_free_skb(dev, skb); |
1588 | return -EINVAL; | 1628 | return -EINVAL; |
1589 | } | 1629 | } |
1590 | 1630 | ||
@@ -1824,7 +1864,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev, | |||
1824 | 1864 | ||
1825 | static int p54_config(struct ieee80211_hw *dev, u32 changed) | 1865 | static int p54_config(struct ieee80211_hw *dev, u32 changed) |
1826 | { | 1866 | { |
1827 | int ret; | 1867 | int ret = 0; |
1828 | struct p54_common *priv = dev->priv; | 1868 | struct p54_common *priv = dev->priv; |
1829 | struct ieee80211_conf *conf = &dev->conf; | 1869 | struct ieee80211_conf *conf = &dev->conf; |
1830 | 1870 | ||
@@ -2051,7 +2091,7 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, | |||
2051 | algo = P54_CRYPTO_AESCCMP; | 2091 | algo = P54_CRYPTO_AESCCMP; |
2052 | break; | 2092 | break; |
2053 | default: | 2093 | default: |
2054 | return -EINVAL; | 2094 | return -EOPNOTSUPP; |
2055 | } | 2095 | } |
2056 | } | 2096 | } |
2057 | 2097 | ||