Partial cleanup of ieee80211 configuration: - Introduces config field in ieee80211_device. - Adds support for switching off software fragmentation. - Fixes MSDU encryption. Signed-off-by: Jiri Benc Signed-off-by: Jirka Bohac Index: netdev/include/net/ieee80211.h =================================================================== --- netdev.orig/include/net/ieee80211.h 2005-09-17 14:47:03.000000000 +0200 +++ netdev/include/net/ieee80211.h 2005-09-17 14:52:22.000000000 +0200 @@ -655,8 +655,25 @@ enum ieee80211_state { #define DEFAULT_MAX_SCAN_AGE (15 * HZ) #define DEFAULT_FTS 2346 -#define CFG_IEEE80211_RESERVE_FCS (1<<0) -#define CFG_IEEE80211_COMPUTE_FCS (1<<1) +/* Flags describing what the driver excpects from the ieee80211 layer: */ +/* compute checksum */ +#define IEEE80211_CFG_COMPUTE_FCS (1 << 0) +/* perform software fragmentation */ +#define IEEE80211_CFG_FRAGMENT (1 << 1) +/* send fragments to hard_start_xmit one by one */ +#define IEEE80211_CFG_SINGLE_FRAGMENTS (1 << 2) +/* hw needs to be reset on WEP keys change */ +#define IEEE80211_CFG_RESET_ON_KEY_CHANGE (1 << 3) +/* sw WEP encryption */ +#define IEEE80211_CFG_ENCRYPT_WEP (1 << 4) +/* sw WEP decryption */ +#define IEEE80211_CFG_DECRYPT_WEP (1 << 5) +/* sw authentication/association */ +#define IEEE80211_CFG_HANDLE_ASSOC (1 << 6) +/* generate probe requests */ +#define IEEE80211_CFG_PROBE_REQ (1 << 7) +/* generate probe responses */ +#define IEEE80211_CFG_PROBE_RESP (1 << 8) struct ieee80211_device { struct net_device *dev; @@ -679,14 +696,13 @@ struct ieee80211_device { int tx_headroom; /* Set to size of any additional room needed at front * of allocated Tx SKBs */ - u32 config; + + u32 config; /* Determines what is done by the layer and what is + * left to the driver */ /* WEP and other encryption related settings at the device level */ int open_wep; /* Set to 1 to allow unencrypted frames */ - int reset_on_keychange; /* Set to 1 if the HW needs to be reset on - * WEP key changes */ - /* If the host performs {en,de}cryption, then set to 1 */ int host_encrypt; int host_decrypt; Index: netdev/net/ieee80211/ieee80211_module.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_module.c 2005-09-17 14:44:44.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_module.c 2005-09-17 14:51:12.000000000 +0200 @@ -129,6 +129,13 @@ struct ieee80211_device *alloc_ieee80211 } ieee80211_networks_initialize(ieee); + /* Set default config values */ + ieee->config = + IEEE80211_CFG_COMPUTE_FCS | + IEEE80211_CFG_FRAGMENT | + IEEE80211_CFG_ENCRYPT_WEP | + IEEE80211_CFG_DECRYPT_WEP; + /* Default fragmentation threshold is maximum payload size */ ieee->fts = DEFAULT_FTS; ieee->scan_age = DEFAULT_MAX_SCAN_AGE; Index: netdev/net/ieee80211/ieee80211_tx.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_tx.c 2005-09-17 14:44:44.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_tx.c 2005-09-17 14:51:12.000000000 +0200 @@ -174,9 +174,6 @@ static inline int ieee80211_encrypt_frag /* To encrypt, frame format is: * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ - // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption. - /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so - * call both MSDU and MPDU encryption functions from here. */ atomic_inc(&crypt->refcnt); res = 0; if (crypt->ops->encrypt_msdu) @@ -195,6 +192,29 @@ static inline int ieee80211_encrypt_frag return 0; } +static inline int ieee80211_encrypt_frame(struct ieee80211_device *ieee, + struct sk_buff *skb, int hdr_len) +{ + struct ieee80211_crypt_data* crypt = ieee->crypt[ieee->tx_keyidx]; + int res; + + if (!crypt || !crypt->ops->encrypt_msdu) + return 0; + atomic_inc(&crypt->refcnt); + res = 0; + if (crypt->ops->encrypt_msdu) + res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv); + atomic_dec(&crypt->refcnt); + if (res < 0) { + printk(KERN_INFO "%s: Encryption failed: len=%d.\n", + ieee80211_dev(ieee)->name, skb->len); + ieee->ieee_stats.tx_discards++; + return -1; + } + + return 0; +} + void ieee80211_txb_free(struct ieee80211_txb *txb) { int i; @@ -291,6 +311,9 @@ int ieee80211_xmit(struct sk_buff *skb, /* Advance the SKB to the start of the payload */ skb_pull(skb, sizeof(struct ethhdr)); + if (encrypt && ieee80211_encrypt_frame(ieee, skb, IEEE80211_3ADDR_LEN) < 0) + goto success; + /* Determine total amount of storage required for TXB packets */ bytes = skb->len + SNAP_SIZE + sizeof(u16); @@ -319,7 +342,8 @@ int ieee80211_xmit(struct sk_buff *skb, /* Determine fragmentation size based on destination (multicast * and broadcast are not fragmented) */ - if (is_multicast_ether_addr(dest) || is_broadcast_ether_addr(dest)) + if (!(ieee->config & IEEE80211_CFG_FRAGMENT) || + is_multicast_ether_addr(dest) || is_broadcast_ether_addr(dest)) frag_size = MAX_FRAG_THRESHOLD; else frag_size = ieee->fts; @@ -328,10 +352,7 @@ int ieee80211_xmit(struct sk_buff *skb, * this stack is providing the full 802.11 header, one will * eventually be affixed to this fragment -- so we must account for * it when determining the amount of payload space. */ - bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN; - if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) - bytes_per_frag -= IEEE80211_FCS_LEN; + bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN - IEEE80211_FCS_LEN; /* Each fragment may need to have room for encryptiong pre/postfix */ if (encrypt) @@ -396,9 +417,9 @@ int ieee80211_xmit(struct sk_buff *skb, * to insert the IV between the header and the payload */ if (encrypt) ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); - if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) - skb_put(skb_frag, 4); + + /* FCS */ + skb_put(skb_frag, 4); } success: Index: netdev/net/ieee80211/ieee80211_wx.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_wx.c 2005-09-17 14:44:44.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_wx.c 2005-09-17 14:51:12.000000000 +0200 @@ -426,7 +426,7 @@ int ieee80211_wx_set_encode(struct ieee8 * with IEEE 802.1X. If your hardware requires a reset after WEP * configuration (for example... Prism2), implement the reset_port in * the callbacks structures used to initialize the 802.11 stack. */ - if (ieee->reset_on_keychange && + if ((ieee->config & IEEE80211_CFG_RESET_ON_KEY_CHANGE) && ieee->iw_mode != IW_MODE_INFRA && ieee->reset_port && ieee->reset_port(ieee)) { printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);