diff -u -r1.90 Makefile --- Makefile 10 May 2004 18:21:09 -0000 1.90 +++ Makefile 20 May 2004 21:13:06 -0000 @@ -40,14 +40,22 @@ # CONFIG_IPW2100_NOWEP=y endif +ifndef CONFIG_IPW2100_NOWEP + # Set up the include path to be able to find hostap_crypt.h # # If CONFIG_HOSTAP is set by the kernel then we use the default kernel # source location in the kernel. Otherwise we check for the existence # of the HOSTAP environment variable. If set, we base the Host AP # include directory from that. If it is not set, we default to looking -# in $(PWD)/hostap-driver-0.1.3 -# +# for it in this order: +# - $(PWD)/../hostap-driver-0.2.1 +# - $(PWD)/hostap-driver-0.2.1 +# - $(BASE)/drivers/net/wireless/hostap-driver-0.2.1 +# - $(PWD)/../hostap +# - $(PWD)/hostap +# - $(BASE)/drivers/net/wireless/hostap + ifneq ($(PATCHLEVEL),6) # 2.4 BASE := $(TOPDIR) else # 2.6 @@ -67,18 +75,26 @@ fi)/driver/modules else export HOSTAP_SRC:=$(shell \ - if [ -d "../hostap-driver-0.1.3" ]; then \ - echo "$(PWD)/../hostap-driver-0.1.3"; \ - elif [ -d "$(PWD)/hostap-driver-0.1.3" ]; then \ - echo "$(PWD)/hostap-driver-0.1.3"; \ - else \ - echo "$(BASE)/drivers/net/wireless/hostap-driver-0.1.3"; \ + if [ -d "$(PWD)/../hostap-driver-0.2.1" ]; then \ + echo "$(PWD)/../hostap-driver-0.2.1"; \ + elif [ -d "$(PWD)/hostap-driver-0.2.1" ]; then \ + echo "$(PWD)/hostap-driver-0.2.1"; \ + elif [ -d "$(BASE)/drivers/net/wireless/hostap-driver-0.2.1" ]; then \ + echo "$(BASE)/drivers/net/wireless/hostap-driver-0.2.1"; \ + elif [ -d "$(PWD)/../hostap" ]; then \ + echo "$(PWD)/../hostap"; \ + elif [ -d "$(PWD)/hostap" ]; then \ + echo "$(PWD)/hostap"; \ + elif [ -d "$(BASE)/drivers/net/wireless/hostap" ]; then \ + echo "$(BASE)/drivers/net/wireless/hostap"; \ fi)/driver/modules -endif -endif +endif #HOSTAP +endif #CONFIG_HOSTAP endif EXTRA_CFLAGS += -I$(HOSTAP_SRC) + +endif #CONFIG_IPW2100_NOWEP list-m := list-$(CONFIG_IPW2100) += ipw2100 Index: ieee80211.c =================================================================== RCS file: /usr/src/repository/wireless/ipw2100/ieee80211.c,v retrieving revision 1.22 diff -u -r1.22 ieee80211.c --- ieee80211.c 10 May 2004 17:51:23 -0000 1.22 +++ ieee80211.c 20 May 2004 21:13:06 -0000 @@ -129,11 +129,21 @@ void ieee80211_deinit(struct ieee80211_device *ieee) { #ifndef CONFIG_IPW2100_NOWEP + int i; + + // PR: FIXME: added this "if" because hostap had it, is it really needed? + if (timer_pending(&ieee->crypt_deinit_timer)) + del_timer(&ieee->crypt_deinit_timer); ieee80211_crypt_deinit_entries(ieee, 1); - if (ieee->crypt && ieee->crypt->ops) { - ieee->crypt->ops->deinit(ieee->crypt->priv); - kfree(ieee->crypt); - ieee->crypt = NULL; + + for (i = 0; i < WEP_KEYS; i++) { + struct ieee80211_crypt_data *crypt = ieee->crypt[i]; + if (crypt) { + if (crypt->ops) + crypt->ops->deinit(crypt->priv); + kfree(crypt); + ieee->crypt[i] = NULL; + } } #endif } Index: ieee80211.h =================================================================== RCS file: /usr/src/repository/wireless/ipw2100/ieee80211.h,v retrieving revision 1.17 diff -u -r1.17 ieee80211.h --- ieee80211.h 6 May 2004 20:27:16 -0000 1.17 +++ ieee80211.h 20 May 2004 21:13:06 -0000 @@ -37,6 +37,8 @@ #define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ #endif /* ETH_P_PAE */ +#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ + #ifndef ETH_P_80211_RAW #define ETH_P_80211_RAW (ETH_P_ECONET + 1) #endif /* CONFIG_IPW2100_PROMISC */ @@ -153,6 +155,8 @@ #define WLAN_EID_TIM 5 #define WLAN_EID_IBSS_PARAMS 6 #define WLAN_EID_CHALLENGE 16 +#define WLAN_EID_RSN 48 +#define WLAN_EID_GENERIC 221 #define IEEE80211_MGMT_HDR_LEN 24 #define IEEE80211_DATA_HDR3_LEN 24 @@ -416,7 +420,8 @@ int ieee_802_1x; /* is IEEE 802.1X used */ struct list_head crypt_deinit_list; - struct ieee80211_crypt_data *crypt; + struct ieee80211_crypt_data *crypt[WEP_KEYS]; + int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ struct timer_list crypt_deinit_timer; int bcrx_sta_key; /* use individual keys to override default keys even Index: ieee80211_rx.c =================================================================== RCS file: /usr/src/repository/wireless/ipw2100/ieee80211_rx.c,v retrieving revision 1.54 diff -u -r1.54 ieee80211_rx.c --- ieee80211_rx.c 18 May 2004 15:07:44 -0000 1.54 +++ ieee80211_rx.c 20 May 2004 21:13:06 -0000 @@ -37,195 +37,22 @@ #include "ieee80211.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) */ - -#ifndef CONFIG_IPW2100_NOWEP -/* Called by ieee80211_rx_frame_decrypt */ -static inline int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, - struct ieee80211_hdr *hdr, u8 *buf, - int len) +static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee, + struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats) { - struct net_device *dev = ieee->dev; - u16 fc, ethertype; - - fc = le16_to_cpu(hdr->frame_control); - - /* check that the frame is unicast frame to us */ - if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_TODS && - memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && - memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { - /* ToDS frame with own addr BSSID and DA */ - } else if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_FROMDS && - memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { - /* FromDS frame with own addr as DA */ - } else - return 0; - - if (len < 8) - return 0; - - /* check for port access entity Ethernet type */ - ethertype = (buf[6] << 8) | buf[7]; - if (ethertype == ETH_P_PAE) - return 1; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + u16 fc = le16_to_cpu(hdr->frame_control); - return 0; + skb->dev = ieee->dev; + skb->mac.raw = skb->data; + skb_pull(skb, ieee80211_get_hdrlen(fc)); + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = __constant_htons(ETH_P_80211_RAW); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); } -/* Called only as a tasklet (software IRQ), by ieee80211_rx */ -static inline int -ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, int iswep, - struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - struct ieee80211_crypt_data *crypt; - void *sta = NULL; - int ret = 0, olen, len, hdrlen; - char *payload; - - hdr = (struct ieee80211_hdr *) skb->data; - hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); - - len = skb->len - hdrlen; - payload = ((char *) (hdr)) + hdrlen; - crypt = ieee->crypt; - sta = NULL; - -#ifdef NOT_YET - /* Use station specific key to override default keys if the receiver - * address is a unicast address ("individual RA"). If bcrx_sta_key - * parameter is set, station specific key is used even with - * broad/multicast targets (this is against IEEE 802.11, but makes it - * easier to use different keys with stations that do not support WEP - * key mapping). */ - if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) - (void) hostap_handle_sta_crypto(local, hdr, &crypt, &sta); -#endif - - /* allow NULL decrypt to indicate an station specific override for - * default encryption */ - if (crypt && (crypt->ops == NULL || crypt->ops->decrypt == NULL)) - crypt = NULL; - - if (!crypt && iswep) { - printk(KERN_DEBUG "%s: WEP decryption failed (not set) (SA=" - MACSTR ")\n", ieee->dev->name, MAC2STR(hdr->addr2)); - ieee->ieee_stats.rx_discards_wep_undecryptable++; - ret = -1; - goto done; - } - - if (!crypt) - goto done; - - if (!iswep) { - if (ieee80211_is_eapol_frame(ieee, hdr, payload, len)) { - /* pass unencrypted EAPOL frames even if encryption is - * configured */ - printk(KERN_DEBUG "%s: RX: IEEE 802.1X - passing " - "unencrypted EAPOL frame\n", ieee->dev->name); - goto done; - } - printk(KERN_DEBUG "%s: encryption configured, but RX frame " - "not encrypted (SA=" MACSTR ")\n", - ieee->dev->name, MAC2STR(hdr->addr2)); - ret = -1; - goto done; - } - - if (iswep) { - /* decrypt WEP part of the frame: IV (4 bytes), encrypted - * payload (including SNAP header), ICV (4 bytes) */ - atomic_inc(&crypt->refcnt); - - olen = crypt->ops->decrypt(payload, len, crypt->priv); - atomic_dec(&crypt->refcnt); - if (olen < 0) { - printk(KERN_DEBUG "%s: WEP decryption failed (SA=" - MACSTR ") len = %d, packet: \n", - ieee->dev->name, MAC2STR(hdr->addr2), - len); - ieee->ieee_stats.rx_discards_wep_undecryptable++; - ret = -1; - goto done; - } - - skb_trim(skb, skb->len - (len - olen)); - } - - done: -#ifdef NOT_YET - if (sta) - hostap_handle_sta_release(sta); -#endif - - return ret; -} -#endif /* CONFIG_IPW2100_NOWEP */ - -#ifdef NOT_YET -/* ieee80211_rx_frame_mgtmt - * - * Responsible for handling management control frames - * - * Called by ieee80211_rx */ -static inline int -ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats, u16 type, - u16 stype) -{ - if (ieee->iw_mode == IW_MODE_MASTER) { - printk(KERN_DEBUG "%s: Master mode not yet suppported.\n", - ieee->dev->name); - return 0; -/* - hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr *) - skb->data);*/ - } - - if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) { - if (stype == WLAN_FC_STYPE_BEACON && - ieee->iw_mode == IW_MODE_MASTER) { - struct sk_buff *skb2; - /* Process beacon frames also in kernel driver to - * update STA(AP) table statistics */ - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2) - hostap_rx(skb2->dev, skb2, rx_stats); - } - - /* send management frames to the user space daemon for - * processing */ - ieee->apdevstats.rx_packets++; - ieee->apdevstats.rx_bytes += skb->len; - prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT); - return 0; - } - - if (ieee->iw_mode == IW_MODE_MASTER) { - if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) { - printk(KERN_DEBUG "%s: unknown management frame " - "(type=0x%02x, stype=0x%02x) dropped\n", - skb->dev->name, type, stype); - return -1; - } - - hostap_rx(skb->dev, skb, rx_stats); - return 0; - } - - printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame " - "received in non-Host AP mode\n", skb->dev->name); - return -1; -} -#endif /* Called only as a tasklet (software IRQ) */ static struct ieee80211_frag_entry * @@ -334,21 +161,184 @@ return 0; } -static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee, - struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats) + +#ifdef NOT_YET +/* ieee80211_rx_frame_mgtmt + * + * Responsible for handling management control frames + * + * Called by ieee80211_rx */ +static inline int +ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats, u16 type, + u16 stype) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - u16 fc = le16_to_cpu(hdr->frame_control); + if (ieee->iw_mode == IW_MODE_MASTER) { + printk(KERN_DEBUG "%s: Master mode not yet suppported.\n", + ieee->dev->name); + return 0; +/* + hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr *) + skb->data);*/ + } - skb->dev = ieee->dev; - skb->mac.raw = skb->data; - skb_pull(skb, ieee80211_get_hdrlen(fc)); - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = __constant_htons(ETH_P_80211_RAW); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); + if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) { + if (stype == WLAN_FC_STYPE_BEACON && + ieee->iw_mode == IW_MODE_MASTER) { + struct sk_buff *skb2; + /* Process beacon frames also in kernel driver to + * update STA(AP) table statistics */ + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) + hostap_rx(skb2->dev, skb2, rx_stats); + } + + /* send management frames to the user space daemon for + * processing */ + ieee->apdevstats.rx_packets++; + ieee->apdevstats.rx_bytes += skb->len; + prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT); + return 0; + } + + if (ieee->iw_mode == IW_MODE_MASTER) { + if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) { + printk(KERN_DEBUG "%s: unknown management frame " + "(type=0x%02x, stype=0x%02x) dropped\n", + skb->dev->name, type, stype); + return -1; + } + + hostap_rx(skb->dev, skb, rx_stats); + return 0; + } + + printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame " + "received in non-Host AP mode\n", skb->dev->name); + return -1; } +#endif + + +/* 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) */ + +#ifndef CONFIG_IPW2100_NOWEP +/* Called by ieee80211_rx_frame_decrypt */ +static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, struct sk_buff *skb) +{ + struct net_device *dev = ieee->dev; + u16 fc, ethertype; + struct ieee80211_hdr *hdr; + u8 *pos; + + if (skb->len < 24) + return 0; + + hdr = (struct ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); + + /* check that the frame is unicast frame to us */ + if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_TODS && + memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && + memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { + /* ToDS frame with own addr BSSID and DA */ + } else if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_FROMDS && + memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { + /* FromDS frame with own addr as DA */ + } else + return 0; + + if (skb->len < 24 + 8) + return 0; + + /* check for port access entity Ethernet type */ + pos = skb->data + 24; + ethertype = (pos[6] << 8) | pos[7]; + if (ethertype == ETH_P_PAE) + return 1; + + return 0; +} + +/* Called only as a tasklet (software IRQ), by ieee80211_rx */ +static inline int +ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb, + struct ieee80211_crypt_data *crypt) +{ + struct ieee80211_hdr *hdr; + int res, hdrlen; + + if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) + return 0; + + hdr = (struct ieee80211_hdr *) skb->data; + hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); + +#ifdef NOT_YET + if (ieee->tkip_countermeasures && + strcmp(crypt->ops->name, "TKIP") == 0) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " + "received packet from " MACSTR "\n", + ieee->dev->name, MAC2STR(hdr->addr2)); + } + return -1; + } +#endif + + atomic_inc(&crypt->refcnt); + res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); + atomic_dec(&crypt->refcnt); + if (res < 0) { + printk(KERN_DEBUG "%s: decryption failed (SA=" MACSTR + ") res=%d\n", + ieee->dev->name, MAC2STR(hdr->addr2), res); + if (res == -2) + printk(KERN_DEBUG "%s: WEP decryption failed ICV mismatch\n", + ieee->dev->name); + ieee->ieee_stats.rx_discards_wep_undecryptable++; + return -1; + } + + return res; +} + + +/* Called only as a tasklet (software IRQ), by ieee80211_rx */ +static inline int +ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct sk_buff *skb, + int keyidx, struct ieee80211_crypt_data *crypt) +{ + struct ieee80211_hdr *hdr; + int res, hdrlen; + + if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) + return 0; + + hdr = (struct ieee80211_hdr *) skb->data; + hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); + + atomic_inc(&crypt->refcnt); + res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); + atomic_dec(&crypt->refcnt); + if (res < 0) { + printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" + " (SA=" MACSTR " keyidx=%d)\n", + ieee->dev->name, MAC2STR(hdr->addr2), keyidx); + return -1; + } + + return 0; +} +#endif /* CONFIG_IPW2100_NOWEP */ + /* All received frames are sent to this function. @skb contains the frame in * IEEE 802.11 format, i.e., in the format it was sent over air. @@ -365,13 +355,19 @@ u8 *payload; u16 ethertype; #ifdef NOT_YET + struct net_device *wds = NULL; struct sk_buff *skb2 = NULL; struct net_device *wds = NULL; int frame_authorized = 0; int from_assoc_ap = 0; + void *sta = NULL; #endif u8 dst[ETH_ALEN]; u8 src[ETH_ALEN]; +#ifndef CONFIG_IPW2100_NOWEP + struct ieee80211_crypt_data *crypt = NULL; + int keyidx = 0; +#endif /* CONFIG_IPW2100_NOWEP */ hdr = (struct ieee80211_hdr *)skb->data; stats = &ieee->stats; @@ -389,7 +385,7 @@ frag = WLAN_GET_SEQ_FRAG(sc); hdrlen = ieee80211_get_hdrlen(fc); -#ifdef NOTYET +#ifdef NOT_YET #if WIRELESS_EXT > 15 /* Put this code here so that we avoid duplicating it in all * Rx paths. - Jean II */ @@ -405,6 +401,7 @@ } #endif /* IW_WIRELESS_SPY */ #endif /* WIRELESS_EXT > 15 */ + hostap_update_rx_stats(local->ap, hdr, rx_stats); #endif #if WIRELESS_EXT > 15 @@ -416,13 +413,55 @@ } #endif -#ifdef NOTYET +#ifndef CONFIG_IPW2100_NOWEP + if (ieee->host_decrypt) { + int idx = 0; + if (skb->len >= hdrlen + 3) + idx = skb->data[hdrlen + 3] >> 6; + crypt = ieee->crypt[idx]; +#ifdef NOT_YET + sta = NULL; + + /* Use station specific key to override default keys if the + * receiver address is a unicast address ("individual RA"). If + * bcrx_sta_key parameter is set, station specific key is used + * even with broad/multicast targets (this is against IEEE + * 802.11, but makes it easier to use different keys with + * stations that do not support WEP key mapping). */ + + if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) + (void) hostap_handle_sta_crypto(local, hdr, &crypt, + &sta); +#endif + + /* allow NULL decrypt to indicate an station specific override + * for default encryption */ + if (crypt && (crypt->ops == NULL || + crypt->ops->decrypt_mpdu == NULL)) + crypt = NULL; + + if (!crypt && (fc & WLAN_FC_ISWEP)) { +#if 0 + /* This seems to be triggered by some (multicast?) + * frames from other than current BSS, so just drop the + * frames silently instead of filling system log with + * these reports. */ + printk(KERN_DEBUG "%s: WEP decryption failed (not set)" + " (SA=" MACSTR ")\n", + ieee->dev->name, MAC2STR(hdr->addr2)); +#endif + ieee->ieee_stats.rx_discards_wep_undecryptable++; + goto rx_dropped; + } + } +#endif /* CONFIG_IPW2100_NOWEP */ + +#ifdef NOT_YET if (type != WLAN_FC_TYPE_DATA) { - if (type == WLAN_FC_TYPE_MGMT && - stype == WLAN_FC_STYPE_AUTH && + if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH && fc & WLAN_FC_ISWEP && ieee->host_decrypt && - ieee80211_rx_frame_decrypt(ieee, fc & WLAN_FC_ISWEP, - skb)) { + (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) + { printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " "from " MACSTR "\n", dev->name, MAC2STR(hdr->addr2)); @@ -501,9 +540,7 @@ case AP_RX_EXIT: goto rx_exit; } - } else if (ieee->iw_mode == IW_MODE_REPEAT || - ieee->wds_type & HOSTAP_WDS_AP_CLIENT) - hostap_update_rx_stats(ieee->ap, hdr, rx_stats); + } #endif /* Nullfunc frames may have PS-bit set, so they must be passed to @@ -513,10 +550,8 @@ stype != WLAN_FC_STYPE_DATA_CFPOLL && stype != WLAN_FC_STYPE_DATA_CFACKPOLL) { if (stype != WLAN_FC_STYPE_NULLFUNC) - printk(KERN_DEBUG - "%s: RX: dropped data frame with no data" - " (type=0x%02x, subtype=0x%02x, len=%d)" - "\n", + printk(KERN_DEBUG "%s: RX: dropped data frame " + "with no data (type=0x%02x, subtype=0x%02x, len=%d)\n", dev->name, type, stype, skb->len); goto rx_dropped; } @@ -524,13 +559,15 @@ /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ #ifndef CONFIG_IPW2100_NOWEP - if (ieee->host_decrypt && - ieee80211_rx_frame_decrypt(ieee, fc & WLAN_FC_ISWEP, skb)) + if (ieee->host_decrypt && (fc & WLAN_FC_ISWEP) && + (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) goto rx_dropped; #endif + hdr = (struct ieee80211_hdr *) skb->data; /* skb: hdr + (possibly fragmented) plaintext payload */ - + // PR: FIXME: hostap has additional conditions in the "if" below: + // ieee->host_decrypt && (fc & WLAN_FC_ISWEP) && if ((frag != 0 || (fc & WLAN_FC_MOREFRAG))) { int flen; struct sk_buff *frag_skb = @@ -584,6 +621,40 @@ ieee80211_frag_cache_invalidate(ieee, hdr); } + /* skb: hdr + (possible reassembled) full MSDU payload; possibly still + * encrypted/authenticated */ +#ifndef CONFIG_IPW2100_NOWEP + if (ieee->host_decrypt && (fc & WLAN_FC_ISWEP) && + ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) + goto rx_dropped; + + hdr = (struct ieee80211_hdr *) skb->data; + if (crypt && !(fc & WLAN_FC_ISWEP) && !ieee->open_wep) { + if (/*ieee->ieee_802_1x &&*/ + ieee80211_is_eapol_frame(ieee, skb)) { + /* pass unencrypted EAPOL frames even if encryption is + * configured */ + printk(KERN_DEBUG "%s: RX: IEEE 802.1X - passing " + "unencrypted EAPOL frame\n", ieee->dev->name); + } else { + printk(KERN_DEBUG "%s: encryption configured, but RX " + "frame not encrypted (SA=" MACSTR ")\n", + ieee->dev->name, MAC2STR(hdr->addr2)); + goto rx_dropped; + } + } + + if (/*ieee->drop_unencrypted*/ crypt && !(fc & WLAN_FC_ISWEP) && !ieee->open_wep && + !ieee80211_is_eapol_frame(ieee, skb)) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: dropped unencrypted RX data " + "frame from " MACSTR " (drop_unencrypted=1)\n", + dev->name, MAC2STR(hdr->addr2)); + } + goto rx_dropped; + } +#endif /* CONFIG_IPW2100_NOWEP */ + /* skb: hdr + (possible reassembled) full plaintext payload */ payload = skb->data + hdrlen; @@ -689,6 +760,10 @@ } rx_exit: +#ifdef NOT_YET + if (sta) + hostap_handle_sta_release(sta); +#endif return 1; rx_dropped: Index: ieee80211_tx.c =================================================================== RCS file: /usr/src/repository/wireless/ipw2100/ieee80211_tx.c,v retrieving revision 1.28 diff -u -r1.28 ieee80211_tx.c --- ieee80211_tx.c 10 May 2004 17:01:54 -0000 1.28 +++ ieee80211_tx.c 20 May 2004 21:13:06 -0000 @@ -131,12 +131,29 @@ u16 fragment, u16 frag_size, struct sk_buff *skb) { - struct ieee80211_crypt_data* crypt = ieee->crypt; + struct ieee80211_crypt_data* crypt = ieee->crypt[ieee->tx_keyidx]; struct sk_buff *wep_skb; - int wep_len, olen; + int wep_len; int in_place = 0; struct ieee80211_hdr *header; + u16 fc; + int hdr_len, res; +#ifdef NOT_YET + if (ieee->tkip_countermeasures && + crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { + hdr = (struct ieee80211_hdr *) skb->data; + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " + "TX packet to " MACSTR "\n", + ieee->dev->name, MAC2STR(hdr->addr1)); + } + // PR: FIXME: use dev_kfree_skb_any(skb); instead? + kfree_skb(skb); + return NULL; + } +#endif + /* SKB visualization * * ,- skb->data @@ -183,9 +200,6 @@ */ in_place = 1; wep_skb = skb; - - /* Set skb->data to the start of where the IV will be. */ - skb_push(wep_skb, crypt->ops->extra_prefix_len); } else { #endif /* There is not enough room in the provided skb. Allocate @@ -209,13 +223,16 @@ if (!ieee->tx_payload_only) { header = (struct ieee80211_hdr *) skb_put(wep_skb, sizeof(struct ieee80211_hdr)); + printk(KERN_DEBUG "%s: TODO -- implement 802.11 " "header construction...\n", ieee->dev->name); + + fc = le16_to_cpu(header->frame_control); + hdr_len = ieee80211_get_hdrlen(fc); + } else { + hdr_len = 0; } - /* Put space at the start of wep_skb for the IV */ - skb_put(wep_skb, crypt->ops->extra_prefix_len); - /* Copy the unencrypted payload into the wep_skb * * NOTE: As of HostAP v0.1.3, the encryption system used @@ -228,20 +245,23 @@ } #endif - /* Advance wep_skb storage to hold the ICV */ - skb_put(wep_skb, crypt->ops->extra_postfix_len); - /* 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); - olen = crypt->ops->encrypt(wep_skb->data, wep_skb->len - - (crypt->ops->extra_prefix_len + - crypt->ops->extra_postfix_len), - crypt->priv); + res = 0; + if (crypt->ops->encrypt_msdu) + res = crypt->ops->encrypt_msdu(wep_skb, hdr_len, crypt->priv); + if (res == 0 && crypt->ops->encrypt_mpdu) + res = crypt->ops->encrypt_mpdu(wep_skb, hdr_len, crypt->priv); + atomic_dec(&crypt->refcnt); - if (olen != wep_skb->len) { - printk(KERN_INFO "%s: Encryption failed: %d vs. %d.\n", - ieee->dev->name, olen, wep_skb->len); + if (res < 0) { + printk(KERN_INFO "%s: Encryption failed: len=%d.\n", + ieee->dev->name, wep_skb->len); if (!in_place) dev_kfree_skb_any(wep_skb); ieee->ieee_stats.tx_discards++; @@ -384,7 +404,7 @@ i = frag_total; #ifndef CONFIG_IPW2100_NOWEP encrypt = (ieee->host_encrypt && ether_type != ETH_P_PAE && - ieee->crypt && ieee->crypt->ops); + ieee->crypt[ieee->tx_keyidx] && ieee->crypt[ieee->tx_keyidx]->ops); #else encrypt = 0; #endif /* CONFIG_IPW2100_NOWEP */ Index: ieee80211_wx.c =================================================================== RCS file: /usr/src/repository/wireless/ipw2100/ieee80211_wx.c,v retrieving revision 1.18 diff -u -r1.18 ieee80211_wx.c --- ieee80211_wx.c 10 May 2004 17:51:23 -0000 1.18 +++ ieee80211_wx.c 20 May 2004 21:13:06 -0000 @@ -67,7 +67,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, struct iw_request_info *info, - union iwreq_data *wrqu, char *key) + union iwreq_data *wrqu, char *keybuf) { struct iw_point *erq = &(wrqu->encoding); #ifdef CONFIG_IPW2100_NOWEP @@ -79,32 +79,43 @@ struct ieee80211_security sec = { .flags = 0 }; - int first = 0; int i; - + struct ieee80211_crypt_data **crypt; + + i = erq->flags & IW_ENCODE_INDEX; + if (i < 1 || i > 4) + i = ieee->tx_keyidx; + else + i--; + if (i < 0 || i >= WEP_KEYS) + return -EINVAL; + + crypt = &ieee->crypt[i]; + if (erq->flags & IW_ENCODE_DISABLED) { - sec.enabled = 0; - sec.flags |= SEC_ENABLED; - ieee80211_crypt_delayed_deinit(ieee, &ieee->crypt); + if (*crypt) { + sec.enabled = 0; + sec.flags |= SEC_ENABLED; + ieee80211_crypt_delayed_deinit(ieee, crypt); + } goto done; } sec.enabled = 1; sec.flags |= SEC_ENABLED; - if (ieee->crypt != NULL && ieee->crypt->ops != NULL && - strcmp(ieee->crypt->ops->name, "WEP") != 0) { + if (*crypt != NULL && (*crypt)->ops != NULL && + strcmp((*crypt)->ops->name, "WEP") != 0) { /* changing to use WEP; deinit previously used algorithm */ - ieee80211_crypt_delayed_deinit(ieee, &ieee->crypt); + ieee80211_crypt_delayed_deinit(ieee, crypt); } - if (ieee->crypt == NULL) { + if (*crypt == NULL) { struct ieee80211_crypt_data *new_crypt; /* take WEP into use */ new_crypt = (struct ieee80211_crypt_data *) - kmalloc(sizeof(struct ieee80211_crypt_data), - GFP_KERNEL); + kmalloc(sizeof(struct ieee80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) return -ENOMEM; memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); @@ -114,7 +125,7 @@ new_crypt->ops = hostap_get_crypto_ops("WEP"); } if (new_crypt->ops) - new_crypt->priv = new_crypt->ops->init(); + new_crypt->priv = new_crypt->ops->init(i); if (!new_crypt->ops || !new_crypt->priv) { kfree(new_crypt); new_crypt = NULL; @@ -124,42 +135,35 @@ dev->name); return -EOPNOTSUPP; } - first = 1; - ieee->crypt = new_crypt; + *crypt = new_crypt; } - i = erq->flags & IW_ENCODE_INDEX; - if (i < 1 || i > 4) - i = ieee->crypt->ops->get_key_idx(ieee->crypt->priv); - else - i--; - if (i < 0 || i >= WEP_KEYS) - return -EINVAL; - if (erq->length > 0) { int len = erq->length <= 5 ? 5 : 13; + int first = 1, j; if (len > erq->length) - memset(key + erq->length, 0, len - erq->length); - - ieee->crypt->ops->set_key(i, key, len, ieee->crypt->priv); - memcpy(sec.keys[i], key, len); + memset(keybuf + erq->length, 0, len - erq->length); + (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv); + memcpy(sec.keys[i], keybuf, len); sec.key_sizes[i] = len; sec.flags |= (1 << i); - - if (first) { - ieee->crypt->ops->set_key_idx(i, ieee->crypt->priv); + for (j = 0; j < WEP_KEYS; j++) { + if (j != i && ieee->crypt[j]) { + first = 0; + break; + } + } + if (first) + ieee->tx_keyidx = i; sec.active_key = i; sec.flags |= SEC_ACTIVE_KEY; - } - - } else if (ieee->crypt->ops->set_key_idx(i, ieee->crypt->priv) < 0) - return -EINVAL; /* keyidx not valid */ - else { + } else { + /* No key data - just set the default TX key index */ + ieee->tx_keyidx = i; sec.active_key = i; sec.flags |= SEC_ACTIVE_KEY; } - done: ieee->open_wep = erq->flags & IW_ENCODE_OPEN; sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; @@ -195,33 +199,33 @@ return 0; #else int i, len; + struct ieee80211_crypt_data *crypt; - if (ieee->crypt == NULL || ieee->crypt->ops == NULL) { + i = erq->flags & IW_ENCODE_INDEX; + if (i < 1 || i > 4) + i = ieee->tx_keyidx; + else + i--; + if (i < 0 || i >= WEP_KEYS) + return -EINVAL; + crypt = ieee->crypt[i]; + erq->flags = i + 1; + + if (crypt == NULL || crypt->ops == NULL) { erq->length = 0; - erq->flags = IW_ENCODE_DISABLED; + erq->flags |= IW_ENCODE_DISABLED; return 0; } - if (strcmp(ieee->crypt->ops->name, "WEP") != 0) { + if (strcmp(crypt->ops->name, "WEP") != 0) { /* only WEP is supported with wireless extensions, so just * report that encryption is used */ erq->length = 0; - erq->flags = IW_ENCODE_ENABLED; + erq->flags |= IW_ENCODE_ENABLED; return 0; } - i = erq->flags & IW_ENCODE_INDEX; - if (i < 1 || i > 4) - i = ieee->crypt->ops->get_key_idx(ieee->crypt->priv); - else - i--; - if (i < 0 || i >= WEP_KEYS) - return -EINVAL; - - erq->flags = i + 1; - - len = ieee->crypt->ops->get_key(i, key, WEP_KEY_LEN, - ieee->crypt->priv); + len = crypt->ops->get_key(key, WEP_KEY_LEN, NULL, crypt->priv); erq->length = (len >= 0 ? len : 0); if (ieee->host_encrypt) Index: ipw2100_main.c =================================================================== RCS file: /usr/src/repository/wireless/ipw2100/ipw2100_main.c,v retrieving revision 1.911 diff -u -r1.911 ipw2100_main.c --- ipw2100_main.c 20 May 2004 21:12:51 -0000 1.911 +++ ipw2100_main.c 20 May 2004 21:13:06 -0000 @@ -3056,7 +3056,8 @@ ether_type = ntohs(*(u16 *)(ether_type_ptr)); encrypt = (priv->ieee.host_encrypt && ether_type != ETH_P_PAE && - priv->ieee.crypt && priv->ieee.crypt->ops); + priv->ieee.crypt[priv->ieee.tx_keyidx] && + priv->ieee.crypt[priv->ieee.tx_keyidx]->ops); if (priv->ieee.host_encrypt && ether_type == ETH_P_PAE) { printk(KERN_DEBUG "%s: TX: IEEE 802.1X - passing " "unencrypted EAPOL frame\n", dev->name); @@ -3682,6 +3683,7 @@ #else " !RFMON" #endif + " HOSTAP_CVS" " ]\n"); len += snprintf(page + len, count - len, @@ -3834,7 +3836,7 @@ DUMP_VAR(connected, d); DUMP_VAR(connected ? get_seconds() - priv->connect_start : 0, lu); - DUMP_VAR(ieee.crypt, p); + DUMP_VAR(ieee.crypt, p); // PR: FIXME: This is no longer a single pointer. Now has WEP_KEYS keys. DUMP_VAR(reset_pending, d); DUMP_VAR(stopped, d); DUMP_VAR(disabled, d); @@ -6562,6 +6564,7 @@ #ifdef CONFIG_IPW2100_NOWEP printk(KERN_INFO DRV_NAME ": Compiled with WEP disabled.\n"); #endif + printk(KERN_INFO DRV_NAME ": Compiled with HOSTAP CVS.\n"); #ifdef CONFIG_IPW2100_LEGACY_FW_LOAD printk(KERN_INFO DRV_NAME ": Compiled with LEGACY FW load.\n");