iwlwifi: Use HW acceleration decryption by default
[safe/jmp/linux-2.6] / drivers / net / wireless / hostap / hostap_80211_tx.c
index 8f39871..921c984 100644 (file)
@@ -1,9 +1,25 @@
+#include "hostap_80211.h"
+#include "hostap_common.h"
+#include "hostap_wlan.h"
+#include "hostap.h"
+#include "hostap_ap.h"
+
+/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
+/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
+static unsigned char rfc1042_header[] =
+{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+static unsigned char bridge_tunnel_header[] =
+{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+/* No encapsulation header if EtherType < 0x600 (=length) */
+
 void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
 {
-       struct hostap_ieee80211_hdr *hdr;
+       struct ieee80211_hdr_4addr *hdr;
        u16 fc;
+       DECLARE_MAC_BUF(mac);
 
-       hdr = (struct hostap_ieee80211_hdr *) skb->data;
+       hdr = (struct ieee80211_hdr_4addr *) skb->data;
 
        printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n",
               name, skb->len, jiffies);
@@ -11,11 +27,11 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
        if (skb->len < 2)
                return;
 
-       fc = le16_to_cpu(hdr->frame_control);
+       fc = le16_to_cpu(hdr->frame_ctl);
        printk(KERN_DEBUG "   FC=0x%04x (type=%d:%d)%s%s",
-              fc, HOSTAP_FC_GET_TYPE(fc), HOSTAP_FC_GET_STYPE(fc),
-              fc & WLAN_FC_TODS ? " [ToDS]" : "",
-              fc & WLAN_FC_FROMDS ? " [FromDS]" : "");
+              fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,
+              fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
+              fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
 
        if (skb->len < IEEE80211_DATA_HDR3_LEN) {
                printk("\n");
@@ -23,12 +39,13 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
        }
 
        printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
-              le16_to_cpu(hdr->seq_ctrl));
+              le16_to_cpu(hdr->seq_ctl));
 
-       printk(KERN_DEBUG "   A1=" MACSTR " A2=" MACSTR " A3=" MACSTR,
-              MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3));
+       printk(KERN_DEBUG "   A1=%s", print_mac(mac, hdr->addr1));
+       printk(" A2=%s", print_mac(mac, hdr->addr2));
+       printk(" A3=%s", print_mac(mac, hdr->addr3));
        if (skb->len >= 30)
-               printk(" A4=" MACSTR, MAC2STR(hdr->addr4));
+               printk(" A4=%s", print_mac(mac, hdr->addr4));
        printk("\n");
 }
 
@@ -41,7 +58,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct hostap_interface *iface;
        local_info_t *local;
        int need_headroom, need_tailroom = 0;
-       struct hostap_ieee80211_hdr hdr;
+       struct ieee80211_hdr_4addr hdr;
        u16 fc, ethertype = 0;
        enum {
                WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME
@@ -115,7 +132,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
                skip_header_bytes -= 2;
        }
 
-       fc = (WLAN_FC_TYPE_DATA << 2) | (WLAN_FC_STYPE_DATA << 4);
+       fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
        hdr_len = IEEE80211_DATA_HDR3_LEN;
 
        if (use_wds != WDS_NO) {
@@ -128,15 +145,16 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
                 * frame format */
 
                if (use_wds == WDS_COMPLIANT_FRAME) {
-                       fc |= WLAN_FC_FROMDS | WLAN_FC_TODS;
+                       fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
                        /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA,
                         * Addr4 = SA */
-                       memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+                       skb_copy_from_linear_data_offset(skb, ETH_ALEN,
+                                                        &hdr.addr4, ETH_ALEN);
                        hdr_len += ETH_ALEN;
                } else {
                        /* bogus 4-addr format to workaround Prism2 station
                         * f/w bug */
-                       fc |= WLAN_FC_TODS;
+                       fc |= IEEE80211_FCTL_TODS;
                        /* From DS: Addr1 = DA (used as RA),
                         * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA),
                         */
@@ -144,7 +162,8 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        /* SA from skb->data + ETH_ALEN will be added after
                         * frame payload; use hdr.addr4 as a temporary buffer
                         */
-                       memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+                       skb_copy_from_linear_data_offset(skb, ETH_ALEN,
+                                                        &hdr.addr4, ETH_ALEN);
                        need_tailroom += ETH_ALEN;
                }
 
@@ -159,28 +178,31 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
                else
                        memcpy(&hdr.addr1, local->bssid, ETH_ALEN);
                memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
-               memcpy(&hdr.addr3, skb->data, ETH_ALEN);
+               skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN);
        } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) {
-               fc |= WLAN_FC_FROMDS;
+               fc |= IEEE80211_FCTL_FROMDS;
                /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */
-               memcpy(&hdr.addr1, skb->data, ETH_ALEN);
+               skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN);
                memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
-               memcpy(&hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
+               skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr3,
+                                                ETH_ALEN);
        } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) {
-               fc |= WLAN_FC_TODS;
+               fc |= IEEE80211_FCTL_TODS;
                /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
                memcpy(&hdr.addr1, to_assoc_ap ?
                       local->assoc_ap_addr : local->bssid, ETH_ALEN);
-               memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
-               memcpy(&hdr.addr3, skb->data, ETH_ALEN);
+               skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2,
+                                                ETH_ALEN);
+               skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN);
        } else if (local->iw_mode == IW_MODE_ADHOC) {
                /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
-               memcpy(&hdr.addr1, skb->data, ETH_ALEN);
-               memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+               skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN);
+               skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2,
+                                                ETH_ALEN);
                memcpy(&hdr.addr3, local->bssid, ETH_ALEN);
        }
 
-       hdr.frame_control = cpu_to_le16(fc);
+       hdr.frame_ctl = cpu_to_le16(fc);
 
        skb_pull(skb, skip_header_bytes);
        need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len;
@@ -222,11 +244,12 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
        iface->stats.tx_packets++;
        iface->stats.tx_bytes += skb->len;
 
-       skb->mac.raw = skb->data;
+       skb_reset_mac_header(skb);
        meta = (struct hostap_skb_tx_data *) skb->cb;
        memset(meta, 0, sizeof(*meta));
        meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
-       meta->wds = use_wds;
+       if (use_wds)
+               meta->flags |= HOSTAP_TX_FLAGS_WDS;
        meta->ethertype = ethertype;
        meta->iface = iface;
 
@@ -243,7 +266,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct hostap_interface *iface;
        local_info_t *local;
        struct hostap_skb_tx_data *meta;
-       struct hostap_ieee80211_hdr *hdr;
+       struct ieee80211_hdr_4addr *hdr;
        u16 fc;
 
        iface = netdev_priv(dev);
@@ -265,10 +288,10 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
        meta->iface = iface;
 
        if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) {
-               hdr = (struct hostap_ieee80211_hdr *) skb->data;
-               fc = le16_to_cpu(hdr->frame_control);
-               if (HOSTAP_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
-                   HOSTAP_FC_GET_STYPE(fc) == WLAN_FC_STYPE_DATA) {
+               hdr = (struct ieee80211_hdr_4addr *) skb->data;
+               fc = le16_to_cpu(hdr->frame_ctl);
+               if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
+                   WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_DATA) {
                        u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN +
                                             sizeof(rfc1042_header)];
                        meta->ethertype = (pos[0] << 8) | pos[1];
@@ -283,14 +306,14 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 
 /* Called only from software IRQ */
-struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
-                                  struct ieee80211_crypt_data *crypt)
+static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
+                                         struct ieee80211_crypt_data *crypt)
 {
        struct hostap_interface *iface;
        local_info_t *local;
-       struct hostap_ieee80211_hdr *hdr;
+       struct ieee80211_hdr_4addr *hdr;
        u16 fc;
-       int hdr_len, res;
+       int prefix_len, postfix_len, hdr_len, res;
 
        iface = netdev_priv(skb->dev);
        local = iface->local;
@@ -301,12 +324,14 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
        }
 
        if (local->tkip_countermeasures &&
-           crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) {
-               hdr = (struct hostap_ieee80211_hdr *) skb->data;
+           strcmp(crypt->ops->name, "TKIP") == 0) {
+               hdr = (struct ieee80211_hdr_4addr *) skb->data;
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
-                              "TX packet to " MACSTR "\n",
-                              local->dev->name, MAC2STR(hdr->addr1));
+                              "TX packet to " MAC_FMT "\n",
+                              local->dev->name,
+                              hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
+                              hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
                }
                kfree_skb(skb);
                return NULL;
@@ -316,16 +341,19 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
        if (skb == NULL)
                return NULL;
 
-       if ((skb_headroom(skb) < crypt->ops->extra_prefix_len ||
-            skb_tailroom(skb) < crypt->ops->extra_postfix_len) &&
-           pskb_expand_head(skb, crypt->ops->extra_prefix_len,
-                            crypt->ops->extra_postfix_len, GFP_ATOMIC)) {
+       prefix_len = crypt->ops->extra_mpdu_prefix_len +
+               crypt->ops->extra_msdu_prefix_len;
+       postfix_len = crypt->ops->extra_mpdu_postfix_len +
+               crypt->ops->extra_msdu_postfix_len;
+       if ((skb_headroom(skb) < prefix_len ||
+            skb_tailroom(skb) < postfix_len) &&
+           pskb_expand_head(skb, prefix_len, postfix_len, GFP_ATOMIC)) {
                kfree_skb(skb);
                return NULL;
        }
 
-       hdr = (struct hostap_ieee80211_hdr *) skb->data;
-       fc = le16_to_cpu(hdr->frame_control);
+       hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
        hdr_len = hostap_80211_get_hdrlen(fc);
 
        /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
@@ -359,7 +387,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
        ap_tx_ret tx_ret;
        struct hostap_skb_tx_data *meta;
        int no_encrypt = 0;
-       struct hostap_ieee80211_hdr *hdr;
+       struct ieee80211_hdr_4addr *hdr;
 
        iface = netdev_priv(dev);
        local = iface->local;
@@ -402,15 +430,16 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
        tx_ret = hostap_handle_sta_tx(local, &tx);
        skb = tx.skb;
        meta = (struct hostap_skb_tx_data *) skb->cb;
-       hdr = (struct hostap_ieee80211_hdr *) skb->data;
-       fc = le16_to_cpu(hdr->frame_control);
+       hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
        switch (tx_ret) {
        case AP_TX_CONTINUE:
                break;
        case AP_TX_CONTINUE_NOT_AUTHORIZED:
                if (local->ieee_802_1x &&
-                   HOSTAP_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
-                   meta->ethertype != ETH_P_PAE && !meta->wds) {
+                   WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
+                   meta->ethertype != ETH_P_PAE &&
+                   !(meta->flags & HOSTAP_TX_FLAGS_WDS)) {
                        printk(KERN_DEBUG "%s: dropped frame to unauthorized "
                               "port (IEEE 802.1X): ethertype=0x%04x\n",
                               dev->name, meta->ethertype);
@@ -437,22 +466,22 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Request TX callback if protocol version is 2 in 802.11 header;
         * this version 2 is a special case used between hostapd and kernel
         * driver */
-       if (((fc & WLAN_FC_PVER) == BIT(1)) &&
+       if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) &&
            local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) {
                meta->tx_cb_idx = local->ap->tx_callback_idx;
 
                /* remove special version from the frame header */
-               fc &= ~WLAN_FC_PVER;
-               hdr->frame_control = cpu_to_le16(fc);
+               fc &= ~IEEE80211_FCTL_VERS;
+               hdr->frame_ctl = cpu_to_le16(fc);
        }
 
-       if (HOSTAP_FC_GET_TYPE(fc) != WLAN_FC_TYPE_DATA) {
+       if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_DATA) {
                no_encrypt = 1;
                tx.crypt = NULL;
        }
 
        if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt &&
-           !(fc & WLAN_FC_ISWEP)) {
+           !(fc & IEEE80211_FCTL_PROTECTED)) {
                no_encrypt = 1;
                PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing "
                       "unencrypted EAPOL frame\n", dev->name);
@@ -464,10 +493,10 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
        else if ((tx.crypt || local->crypt[local->tx_keyidx]) && !no_encrypt) {
                /* Add ISWEP flag both for firmware and host based encryption
                 */
-               fc |= WLAN_FC_ISWEP;
-               hdr->frame_control = cpu_to_le16(fc);
+               fc |= IEEE80211_FCTL_PROTECTED;
+               hdr->frame_ctl = cpu_to_le16(fc);
        } else if (local->drop_unencrypted &&
-                  HOSTAP_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
+                  WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
                   meta->ethertype != ETH_P_PAE) {
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: dropped unencrypted TX data "
@@ -517,6 +546,4 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
 }
 
 
-EXPORT_SYMBOL(hostap_dump_tx_80211);
-EXPORT_SYMBOL(hostap_tx_encrypt);
 EXPORT_SYMBOL(hostap_master_start_xmit);