Makes the 802.11 layer independent of ethernet. (The previous implementation had the ethernet headers built by the ethernet layer and then parsed them and rebuilt them into 802.11 headers.) Signed-off-by: Jiri Benc Signed-off-by: Jirka Bohac Index: netdev/include/linux/netdevice.h =================================================================== --- netdev.orig/include/linux/netdevice.h 2005-09-16 11:35:33.000000000 +0200 +++ netdev/include/linux/netdevice.h 2005-09-17 14:52:53.000000000 +0200 @@ -83,13 +83,18 @@ struct netpoll_info; * used. */ -#if !defined(CONFIG_AX25) && !defined(CONFIG_AX25_MODULE) && !defined(CONFIG_TR) +#if !defined(CONFIG_AX25) && !defined(CONFIG_AX25_MODULE) && !defined(CONFIG_TR) \ + && !defined(CONFIG_IEEE80211) #define LL_MAX_HEADER 32 #else #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) #define LL_MAX_HEADER 96 #else +#if defined(CONFIG_TR) #define LL_MAX_HEADER 48 +#else +#define LL_MAX_HEADER 38 +#endif #endif #endif Index: netdev/include/net/ieee80211.h =================================================================== --- netdev.orig/include/net/ieee80211.h 2005-09-17 14:52:41.000000000 +0200 +++ netdev/include/net/ieee80211.h 2005-09-17 14:54:51.000000000 +0200 @@ -33,25 +33,26 @@ represents the 2304 bytes of real data, plus a possible 8 bytes of WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ +#define IEEE80211_ALEN ETH_ALEN #define IEEE80211_HLEN 30 #define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) struct ieee80211_hdr { __le16 frame_ctl; __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; + u8 addr1[IEEE80211_ALEN]; + u8 addr2[IEEE80211_ALEN]; + u8 addr3[IEEE80211_ALEN]; __le16 seq_ctl; - u8 addr4[ETH_ALEN]; + u8 addr4[IEEE80211_ALEN]; } __attribute__ ((packed)); struct ieee80211_hdr_3addr { __le16 frame_ctl; __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; + u8 addr1[IEEE80211_ALEN]; + u8 addr2[IEEE80211_ALEN]; + u8 addr3[IEEE80211_ALEN]; __le16 seq_ctl; } __attribute__ ((packed)); @@ -202,7 +203,7 @@ const char *escape_essid(const char *ess #define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ #ifndef ETH_P_80211_RAW -#define ETH_P_80211_RAW (ETH_P_ECONET + 1) +#define ETH_P_80211_RAW 0x0003 #endif /* IEEE 802.11 defines */ @@ -215,11 +216,34 @@ struct ieee80211_snap_hdr { u8 ssap; /* always 0xAA */ u8 ctrl; /* always 0x03 */ u8 oui[P80211_OUI_LEN]; /* organizational universal id */ + u16 type; /* packet type ID field */ } __attribute__ ((packed)); #define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) +static inline int ieee80211_fc_get_tods(struct ieee80211_hdr *hdr) +{ + return (hdr->frame_ctl & __constant_cpu_to_le16(IEEE80211_FCTL_TODS)); +} + +static inline int ieee80211_fc_get_fromds(struct ieee80211_hdr *hdr) +{ + return (hdr->frame_ctl & __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS)); +} + +static inline u8 *ieee80211_get_daddr(struct ieee80211_hdr *hdr) +{ + return (ieee80211_fc_get_tods(hdr) ? hdr->addr3 : hdr->addr1); +} + +static inline u8 *ieee80211_get_saddr(struct ieee80211_hdr *hdr) +{ + return (ieee80211_fc_get_fromds(hdr) ? + (ieee80211_fc_get_tods(hdr) ? hdr->addr4 : hdr->addr3) + : hdr->addr2); +} + #define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS) #define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) #define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) @@ -398,8 +422,8 @@ struct ieee80211_frag_entry { unsigned int seq; unsigned int last_frag; struct sk_buff *skb; - u8 src_addr[ETH_ALEN]; - u8 dst_addr[ETH_ALEN]; + u8 src_addr[IEEE80211_ALEN]; + u8 dst_addr[IEEE80211_ALEN]; }; struct ieee80211_stats { @@ -518,7 +542,7 @@ struct ieee80211_info_element { u16 auth_sequence; u16 beacon_interval; u16 capability; - u8 current_ap[ETH_ALEN]; + u8 current_ap[IEEE80211_ALEN]; u16 listen_interval; struct { u16 association_id:14, reserved:2; @@ -567,7 +591,7 @@ struct ieee80211_reassoc_request { struct ieee80211_hdr_3addr header; __le16 capability; __le16 listen_interval; - u8 current_ap[ETH_ALEN]; + u8 current_ap[IEEE80211_ALEN]; /* SSID, supported rates, RSN */ struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); @@ -614,7 +638,7 @@ struct ieee80211_txb { struct ieee80211_network { /* These entries are used to identify a unique network */ - u8 bssid[ETH_ALEN]; + u8 bssid[IEEE80211_ALEN]; u8 channel; /* Ensure null-terminated for any debug msgs */ u8 ssid[IW_ESSID_MAX_SIZE + 1]; @@ -732,7 +756,7 @@ struct ieee80211_device { u16 seq_number; /* sequence number in transmitted frames */ /* Association info */ - u8 bssid[ETH_ALEN]; + u8 bssid[IEEE80211_ALEN]; enum ieee80211_state state; @@ -830,7 +854,7 @@ extern inline int ieee80211_is_valid_mod return 0; } -extern inline int ieee80211_get_hdrlen(u16 fc) +extern inline int __ieee80211_get_hdrlen(u16 fc) { int hdrlen = IEEE80211_3ADDR_LEN; @@ -855,9 +879,28 @@ extern inline int ieee80211_get_hdrlen(u return hdrlen; } +#define ieee80211_get_hdrlen(hdr) __ieee80211_get_hdrlen(le16_to_cpu((hdr)->frame_ctl)) + +#define IEEE80211_GET_DATA_HDR_LEN(hdr) \ + ((((hdr)->frame_ctl & \ + __constant_cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) \ + == __constant_cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) \ + ? IEEE80211_4ADDR_LEN : IEEE80211_3ADDR_LEN) +#define IEEE80211_GET_SNAP(hdr) \ + ((struct ieee80211_snap_hdr *) \ + ((u8 *)(hdr) + IEEE80211_GET_DATA_HDR_LEN(hdr))) + +extern inline int ieee80211_get_proto(struct ieee80211_hdr *header) +{ + struct ieee80211_snap_hdr *snap = IEEE80211_GET_SNAP(header); + return (snap->dsap == 0xaa && snap->ssap == 0xaa ? + ntohs(snap->type) : ETH_P_802_2); +} + /* ieee80211.c */ extern void free_ieee80211(struct ieee80211_device *ieee); extern struct ieee80211_device *alloc_ieee80211(int sizeof_priv); +extern void ieee80211_setup(struct net_device *dev); extern int ieee80211_set_encryption(struct ieee80211_device *ieee); Index: netdev/net/ieee80211/ieee80211_rx.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_rx.c 2005-09-17 14:50:39.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_rx.c 2005-09-17 14:55:53.000000000 +0200 @@ -41,11 +41,10 @@ static inline void ieee80211_monitor_rx( struct ieee80211_rx_stats *rx_stats) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - u16 fc = le16_to_cpu(hdr->frame_ctl); skb->dev = ieee80211_dev(ieee); skb->mac.raw = skb->data; - skb_pull(skb, ieee80211_get_hdrlen(fc)); + skb_pull(skb, ieee80211_get_hdrlen(hdr)); skb->pkt_type = PACKET_OTHERHOST; skb->protocol = __constant_htons(ETH_P_80211_RAW); memset(skb->cb, 0, sizeof(skb->cb)); @@ -77,8 +76,8 @@ static struct ieee80211_frag_entry *ieee if (entry->skb != NULL && entry->seq == seq && (entry->last_frag + 1 == frag || frag == -1) && - memcmp(entry->src_addr, src, ETH_ALEN) == 0 && - memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) + memcmp(entry->src_addr, src, IEEE80211_ALEN) == 0 && + memcmp(entry->dst_addr, dst, IEEE80211_ALEN) == 0) return entry; } @@ -104,7 +103,7 @@ static struct sk_buff *ieee80211_frag_ca sizeof(struct ieee80211_hdr) + 8 /* LLC */ + 2 /* alignment */ + - 8 /* WEP */ + ETH_ALEN /* WDS */ ); + 8 /* WEP */ + IEEE80211_ALEN /* WDS */ ); if (skb == NULL) return NULL; @@ -120,8 +119,8 @@ static struct sk_buff *ieee80211_frag_ca entry->seq = seq; entry->last_frag = frag; entry->skb = skb; - memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); - memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); + memcpy(entry->src_addr, hdr->addr2, IEEE80211_ALEN); + memcpy(entry->dst_addr, hdr->addr1, IEEE80211_ALEN); } else { /* received a fragment of a frame for which the head fragment * should have already been received */ @@ -217,15 +216,6 @@ ieee80211_rx_frame_mgmt(struct ieee80211 } #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) */ - /* Called by ieee80211_rx_frame_decrypt */ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, struct sk_buff *skb) @@ -233,7 +223,6 @@ static int ieee80211_is_eapol_frame(stru struct net_device *dev = ieee80211_dev(ieee); u16 fc, ethertype; struct ieee80211_hdr *hdr; - u8 *pos; if (skb->len < 24) return 0; @@ -244,12 +233,12 @@ static int ieee80211_is_eapol_frame(stru /* check that the frame is unicast frame to us */ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_TODS && - memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && - memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { + memcmp(hdr->addr1, dev->dev_addr, IEEE80211_ALEN) == 0 && + memcmp(hdr->addr3, dev->dev_addr, IEEE80211_ALEN) == 0) { /* ToDS frame with own addr BSSID and DA */ } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS && - memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { + memcmp(hdr->addr1, dev->dev_addr, IEEE80211_ALEN) == 0) { /* FromDS frame with own addr as DA */ } else return 0; @@ -258,8 +247,7 @@ static int ieee80211_is_eapol_frame(stru return 0; /* check for port access entity Ethernet type */ - pos = skb->data + 24; - ethertype = (pos[6] << 8) | pos[7]; + ethertype = ieee80211_get_proto(hdr); if (ethertype == ETH_P_PAE) return 1; @@ -278,7 +266,7 @@ ieee80211_rx_frame_decrypt(struct ieee80 return 0; hdr = (struct ieee80211_hdr *)skb->data; - hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + hdrlen = ieee80211_get_hdrlen(hdr); #ifdef CONFIG_IEEE80211_CRYPT_TKIP if (ieee->tkip_countermeasures && strcmp(crypt->ops->name, "TKIP") == 0) { @@ -321,7 +309,7 @@ ieee80211_rx_frame_decrypt_msdu(struct i return 0; hdr = (struct ieee80211_hdr *)skb->data; - hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + hdrlen = ieee80211_get_hdrlen(hdr); atomic_inc(&crypt->refcnt); res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); @@ -336,6 +324,53 @@ ieee80211_rx_frame_decrypt_msdu(struct i return 0; } +static inline int snap_is_rfc1042(struct ieee80211_snap_hdr *snap) +{ + return ((snap)->oui[0] == 0 && (snap)->oui[1] == 0 && (snap)->oui[2] == 0); +} + +static inline int snap_is_bridge_tunnel(struct ieee80211_snap_hdr *snap) +{ + return ((snap)->oui[0] == 0 && (snap)->oui[1] == 0 && (snap)->oui[2] == 0xf8); +} + +unsigned short ieee80211_type_trans(struct sk_buff *skb, + struct ieee80211_device *ieee) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_snap_hdr *snap; + int hdrlen; + u8 *daddr = ieee80211_get_daddr(hdr); + unsigned short type; + + skb->mac.raw = skb->data; + + hdrlen = ieee80211_get_hdrlen(hdr); + snap = (struct ieee80211_snap_hdr *)(skb->data + hdrlen); + if (snap->dsap == 0xaa && snap->ssap == 0xaa && + ((snap_is_rfc1042(snap) && + snap->type != __constant_htons(ETH_P_AARP) && + snap->type != __constant_htons(ETH_P_IPX)) || + snap_is_bridge_tunnel(snap))) { + type = snap->type; + skb_pull(skb, hdrlen + SNAP_SIZE); + } + else { + type = __constant_htons(ETH_P_802_2); + skb_pull(skb, hdrlen); + } + + skb->input_dev = ieee->dev; + if (is_broadcast_ether_addr(daddr)) + skb->pkt_type = PACKET_BROADCAST; + else if (is_multicast_ether_addr(daddr)) + skb->pkt_type = PACKET_MULTICAST; + else if (memcmp(daddr, ieee->dev->dev_addr, IEEE80211_ALEN)) + skb->pkt_type = PACKET_OTHERHOST; + + return type; +} + /* 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. * This function is called only as a tasklet (software IRQ). */ @@ -348,8 +383,6 @@ int ieee80211_rx(struct ieee80211_device u16 fc, type, stype, sc; struct net_device_stats *stats; unsigned int frag; - u8 *payload; - u16 ethertype; #ifdef NOT_YET struct net_device *wds = NULL; struct sk_buff *skb2 = NULL; @@ -358,8 +391,8 @@ int ieee80211_rx(struct ieee80211_device int from_assoc_ap = 0; void *sta = NULL; #endif - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; + u8 dst[IEEE80211_ALEN]; + u8 src[IEEE80211_ALEN]; struct ieee80211_crypt_data *crypt = NULL; int keyidx = 0; @@ -376,7 +409,7 @@ int ieee80211_rx(struct ieee80211_device stype = WLAN_FC_GET_STYPE(fc); sc = le16_to_cpu(hdr->seq_ctl); frag = WLAN_GET_SEQ_FRAG(sc); - hdrlen = ieee80211_get_hdrlen(fc); + hdrlen = __ieee80211_get_hdrlen(fc); /* Put this code here so that we avoid duplicating it in all * Rx paths. - Jean II */ @@ -484,22 +517,23 @@ int ieee80211_rx(struct ieee80211_device switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { case IEEE80211_FCTL_FROMDS: - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr3, ETH_ALEN); + memcpy(dst, hdr->addr1, IEEE80211_ALEN); + memcpy(src, hdr->addr3, IEEE80211_ALEN); break; case IEEE80211_FCTL_TODS: - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); + memcpy(dst, hdr->addr3, IEEE80211_ALEN); + memcpy(src, hdr->addr2, IEEE80211_ALEN); break; case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: if (skb->len < IEEE80211_4ADDR_LEN) goto rx_dropped; - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr4, ETH_ALEN); + memcpy(dst, hdr->addr3, IEEE80211_ALEN); + memcpy(src, hdr->addr4, IEEE80211_ALEN); + /* FIXME: this is wrong */ break; case 0: - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); + memcpy(dst, hdr->addr1, IEEE80211_ALEN); + memcpy(src, hdr->addr2, IEEE80211_ALEN); break; } @@ -514,7 +548,7 @@ int ieee80211_rx(struct ieee80211_device if (ieee->iw_mode == IW_MODE_MASTER && !wds && (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS && ieee->stadev - && memcmp(hdr->addr2, ieee->assoc_ap_addr, ETH_ALEN) == 0) { + && memcmp(hdr->addr2, ieee->assoc_ap_addr, IEEE80211_ALEN) == 0) { /* Frame from BSSID of the AP for which we are a client */ skb->dev = dev = ieee->stadev; stats = hostap_get_stats(dev); @@ -652,9 +686,6 @@ int ieee80211_rx(struct ieee80211_device /* skb: hdr + (possible reassembled) full plaintext payload */ - payload = skb->data + hdrlen; - ethertype = (payload[6] << 8) | payload[7]; - #ifdef NOT_YET /* If IEEE 802.1X is used, check whether the port is authorized to send * the received frame. */ @@ -680,37 +711,6 @@ int ieee80211_rx(struct ieee80211_device } #endif - /* convert hdr + possible LLC headers into Ethernet header */ - if (skb->len - hdrlen >= 8 && - ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 && - ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) { - /* remove RFC1042 or Bridge-Tunnel encapsulation and - * replace EtherType */ - skb_pull(skb, hdrlen + SNAP_SIZE); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } else { - u16 len; - /* Leave Ethernet header part of hdr and full payload */ - skb_pull(skb, hdrlen); - len = htons(skb->len); - memcpy(skb_push(skb, 2), &len, 2); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } - -#ifdef NOT_YET - if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_TODS) && skb->len >= ETH_HLEN + ETH_ALEN) { - /* Non-standard frame: get addr4 from its bogus location after - * the payload */ - memcpy(skb->data + ETH_ALEN, - skb->data + skb->len - ETH_ALEN, ETH_ALEN); - skb_trim(skb, skb->len - ETH_ALEN); - } -#endif - stats->rx_packets++; stats->rx_bytes += skb->len; @@ -735,7 +735,7 @@ int ieee80211_rx(struct ieee80211_device if (skb2 != NULL) { /* send to wireless media */ - skb2->protocol = __constant_htons(ETH_P_802_3); + skb2->protocol = ieee80211_type_trans(skb2, ieee); skb2->mac.raw = skb2->nh.raw = skb2->data; /* skb2->nh.raw = skb2->data + ETH_HLEN; */ skb2->dev = dev; @@ -744,7 +744,7 @@ int ieee80211_rx(struct ieee80211_device #endif if (skb) { - skb->protocol = eth_type_trans(skb, dev); + skb->protocol = ieee80211_type_trans(skb, ieee); memset(skb->cb, 0, sizeof(skb->cb)); skb->dev = dev; skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ @@ -799,7 +799,7 @@ static inline int ieee80211_network_init u8 i; /* Pull out fixed field data */ - memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); + memcpy(network->bssid, beacon->header.addr3, IEEE80211_ALEN); network->capability = le16_to_cpu(beacon->capability); network->last_scanned = jiffies; network->time_stamp[0] = le32_to_cpu(beacon->time_stamp[0]); @@ -830,7 +830,7 @@ static inline int ieee80211_network_init IEEE80211_DEBUG_SCAN ("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%Zd left=%d.\n", info_element->len + - sizeof(struct ieee80211_info_element), left); + (int)sizeof(struct ieee80211_info_element), left); return 1; } @@ -1008,7 +1008,7 @@ static inline int is_same_network(struct * as one network */ return ((src->ssid_len == dst->ssid_len) && (src->channel == dst->channel) && - !memcmp(src->bssid, dst->bssid, ETH_ALEN) && + !memcmp(src->bssid, dst->bssid, IEEE80211_ALEN) && !memcmp(src->ssid, dst->ssid, src->ssid_len)); } Index: netdev/net/ieee80211/ieee80211_module.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_module.c 2005-09-17 14:52:41.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_module.c 2005-09-17 14:52:53.000000000 +0200 @@ -47,7 +47,6 @@ #include #include #include -#include #include #include @@ -111,17 +110,15 @@ struct ieee80211_device *alloc_ieee80211 alloc_size = ((sizeof(struct ieee80211_device) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) + sizeof_priv; - dev = alloc_etherdev(alloc_size); + dev = alloc_netdev(alloc_size, "wlan%d", ieee80211_setup); if (!dev) { - IEEE80211_ERROR("Unable to network device.\n"); + IEEE80211_ERROR("Unable to allocate network device.\n"); goto failed; } ieee = netdev_priv(dev); ieee->dev = dev; ieee->priv = ieee80211_priv(ieee); - dev->hard_start_xmit = ieee80211_xmit; - err = ieee80211_networks_allocate(ieee); if (err) { IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err); Index: netdev/net/ieee80211/ieee80211_tx.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_tx.c 2005-09-17 14:52:41.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_tx.c 2005-09-17 14:58:36.000000000 +0200 @@ -80,16 +80,6 @@ Desc. | IV | Encrypted | ICV | `-----------------------' Total: 8 non-data bytes -802.3 Ethernet Data Frame - - ,-----------------------------------------. -Bytes | 6 | 6 | 2 | Variable | 4 | - |-------|-------|------|-----------|------| -Desc. | Dest. | Source| Type | IP Packet | fcs | - | MAC | MAC | | | | - `-----------------------------------------' -Total: 18 non-data bytes - In the event that fragmentation is required, the incoming payload is split into N parts of size ieee->fts. The first fragment contains the SNAP header and the remaining packets are just data. @@ -100,57 +90,8 @@ So if you have 1500 bytes of payload wit encryption it will take 3 frames. With WEP it will take 4 frames as the payload of each frame is reduced to 492 bytes. -* SKB visualization -* -* ,- skb->data -* | -* | ETHERNET HEADER ,-<-- PAYLOAD -* | | 14 bytes from skb->data -* | 2 bytes for Type --> ,T. | (sizeof ethhdr) -* | | | | -* |,-Dest.--. ,--Src.---. | | | -* | 6 bytes| | 6 bytes | | | | -* v | | | | | | -* 0 | v 1 | v | v 2 -* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 -* ^ | ^ | ^ | -* | | | | | | -* | | | | `T' <---- 2 bytes for Type -* | | | | -* | | '---SNAP--' <-------- 6 bytes for SNAP -* | | -* `-IV--' <-------------------- 4 bytes for IV (WEP) -* -* SNAP HEADER -* */ -static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; -static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; - -static inline int ieee80211_put_snap(u8 * data, u16 h_proto) -{ - struct ieee80211_snap_hdr *snap; - u8 *oui; - - snap = (struct ieee80211_snap_hdr *)data; - snap->dsap = 0xaa; - snap->ssap = 0xaa; - snap->ctrl = 0x03; - - if (h_proto == 0x8137 || h_proto == 0x80f3) - oui = P802_1H_OUI; - else - oui = RFC1042_OUI; - snap->oui[0] = oui[0]; - snap->oui[1] = oui[1]; - snap->oui[2] = oui[2]; - - *(u16 *) (data + SNAP_SIZE) = htons(h_proto); - - return SNAP_SIZE + sizeof(u16); -} - static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, struct sk_buff *frag, int hdr_len) { @@ -260,19 +201,16 @@ static struct ieee80211_txb *ieee80211_a int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_device *ieee = netdev_priv(dev); + struct ieee80211_hdr *header = (struct ieee80211_hdr *)skb->data; struct ieee80211_txb *txb = NULL; struct ieee80211_hdr *frag_hdr; int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; unsigned long flags; struct net_device_stats *stats = &ieee->stats; - int ether_type, encrypt; + int type, encrypt; int bytes, fc, hdr_len; struct sk_buff *skb_frag; - struct ieee80211_hdr header = { /* Ensure zero initialized */ - .duration_id = 0, - .seq_ctl = 0 - }; - u8 dest[ETH_ALEN], src[ETH_ALEN]; + u8 *dest; struct ieee80211_crypt_data *crypt; @@ -281,64 +219,38 @@ int ieee80211_xmit(struct sk_buff *skb, /* If there is no driver handler to take the TXB, dont' bother * creating it... */ if (!ieee->hard_start_xmit) { - printk(KERN_WARNING "%s: No xmit handler.\n", dev->name); + if (printk_ratelimit()) + printk(KERN_WARNING "%s: No xmit handler.\n", + dev->name); goto success; } - if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) { - printk(KERN_WARNING "%s: skb too small (%d).\n", - dev->name, skb->len); - goto success; - } - - ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); + type = ieee80211_get_proto(header); + dest = ieee80211_get_daddr(header); + hdr_len = ieee80211_get_hdrlen(header); crypt = ieee->crypt[ieee->tx_keyidx]; - encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && + encrypt = !(type == ETH_P_PAE && ieee->ieee802_1x) && ieee->host_encrypt && crypt && crypt->ops; if (!encrypt && ieee->ieee802_1x && - ieee->drop_unencrypted && ether_type != ETH_P_PAE) { + ieee->drop_unencrypted && type != ETH_P_PAE) { stats->tx_dropped++; goto success; } - /* Save source and destination addresses */ - memcpy(dest, skb->data, ETH_ALEN); - memcpy(src, skb->data + ETH_ALEN, ETH_ALEN); - - /* 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) + if (encrypt && ieee80211_encrypt_frame(ieee, skb, hdr_len) < 0) goto success; /* Determine total amount of storage required for TXB packets */ - bytes = skb->len + SNAP_SIZE + sizeof(u16); + bytes = skb->len - hdr_len; + fc = le16_to_cpu(header->frame_ctl); if (encrypt) - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | - IEEE80211_FCTL_PROTECTED; - else - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; + fc |= IEEE80211_FCTL_PROTECTED; - if (ieee->iw_mode == IW_MODE_INFRA) { - fc |= IEEE80211_FCTL_TODS; - /* To DS: Addr1 = BSSID, Addr2 = SA, - Addr3 = DA */ - memcpy(header.addr1, ieee->bssid, ETH_ALEN); - memcpy(header.addr2, src, ETH_ALEN); - memcpy(header.addr3, dest, ETH_ALEN); - } else if (ieee->iw_mode == IW_MODE_ADHOC) { - /* not From/To DS: Addr1 = DA, Addr2 = SA, - Addr3 = BSSID */ - memcpy(header.addr1, dest, ETH_ALEN); - memcpy(header.addr2, src, ETH_ALEN); - memcpy(header.addr3, ieee->bssid, ETH_ALEN); - } - header.frame_ctl = cpu_to_le16(fc); - hdr_len = IEEE80211_3ADDR_LEN; + header->frame_ctl = cpu_to_le16(fc); /* Determine fragmentation size based on destination (multicast * and broadcast are not fragmented) */ @@ -352,7 +264,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 - IEEE80211_FCS_LEN; + bytes_per_frag = frag_size - hdr_len - IEEE80211_FCS_LEN; /* Each fragment may need to have room for encryptiong pre/postfix */ if (encrypt) @@ -387,6 +299,8 @@ int ieee80211_xmit(struct sk_buff *skb, txb->encrypted = encrypt; txb->payload_size = bytes; + skb_pull(skb, hdr_len); + for (i = 0; i < nr_frags; i++) { skb_frag = txb->fragments[i]; @@ -394,7 +308,7 @@ int ieee80211_xmit(struct sk_buff *skb, skb_reserve(skb_frag, crypt->ops->extra_prefix_len); frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len); - memcpy(frag_hdr, &header, hdr_len); + memcpy(frag_hdr, header, hdr_len); frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_number | i); @@ -409,14 +323,6 @@ int ieee80211_xmit(struct sk_buff *skb, bytes = bytes_last_frag; } - /* Put a SNAP header on the first fragment */ - if (i == 0) { - ieee80211_put_snap(skb_put - (skb_frag, SNAP_SIZE + sizeof(u16)), - ether_type); - bytes -= SNAP_SIZE + sizeof(u16); - } - memcpy(skb_put(skb_frag, bytes), skb->data, bytes); /* Advance the SKB... */ Index: netdev/net/ieee80211/ieee80211_wx.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_wx.c 2005-09-17 14:51:12.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_wx.c 2005-09-17 14:52:53.000000000 +0200 @@ -54,7 +54,7 @@ static inline char *ipw2100_translate_sc /* First entry *MUST* be the AP MAC address */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); + memcpy(iwe.u.ap_addr.sa_data, network->bssid, IEEE80211_ALEN); start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); /* Remaining entries will be displayed in the order we provide them */ Index: netdev/net/ieee80211/ieee80211_crypt_ccmp.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_crypt_ccmp.c 2005-09-16 13:28:25.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_crypt_ccmp.c 2005-09-17 14:52:53.000000000 +0200 @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -151,7 +150,7 @@ static void ccmp_init_blocks(struct cryp * Dlen */ b0[0] = 0x59; b0[1] = qc; - memcpy(b0 + 2, hdr->addr2, ETH_ALEN); + memcpy(b0 + 2, hdr->addr2, IEEE80211_ALEN); memcpy(b0 + 8, pn, CCMP_PN_LEN); b0[14] = (dlen >> 8) & 0xff; b0[15] = dlen & 0xff; @@ -168,13 +167,13 @@ static void ccmp_init_blocks(struct cryp aad[1] = aad_len & 0xff; aad[2] = pos[0] & 0x8f; aad[3] = pos[1] & 0xc7; - memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN); + memcpy(aad + 4, hdr->addr1, 3 * IEEE80211_ALEN); pos = (u8 *) & hdr->seq_ctl; aad[22] = pos[0] & 0x0f; aad[23] = 0; /* all bits masked */ memset(aad + 24, 0, 8); if (a4_included) - memcpy(aad + 24, hdr->addr4, ETH_ALEN); + memcpy(aad + 24, hdr->addr4, IEEE80211_ALEN); if (qc_included) { aad[a4_included ? 30 : 24] = qc; /* rest of QC masked */ Index: netdev/net/ieee80211/ieee80211_crypt_tkip.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_crypt_tkip.c 2005-09-16 13:28:25.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_crypt_tkip.c 2005-09-17 14:52:53.000000000 +0200 @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -447,20 +446,20 @@ static void michael_mic_hdr(struct sk_bu switch (le16_to_cpu(hdr11->frame_ctl) & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { case IEEE80211_FCTL_TODS: - memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ - memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + memcpy(hdr, hdr11->addr3, IEEE80211_ALEN); /* DA */ + memcpy(hdr + IEEE80211_ALEN, hdr11->addr2, IEEE80211_ALEN); /* SA */ break; case IEEE80211_FCTL_FROMDS: - memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ - memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ + memcpy(hdr, hdr11->addr1, IEEE80211_ALEN); /* DA */ + memcpy(hdr + IEEE80211_ALEN, hdr11->addr3, IEEE80211_ALEN); /* SA */ break; case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: - memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ - memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ + memcpy(hdr, hdr11->addr3, IEEE80211_ALEN); /* DA */ + memcpy(hdr + IEEE80211_ALEN, hdr11->addr4, IEEE80211_ALEN); /* SA */ break; case 0: - memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ - memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + memcpy(hdr, hdr11->addr1, IEEE80211_ALEN); /* DA */ + memcpy(hdr + IEEE80211_ALEN, hdr11->addr2, IEEE80211_ALEN); /* SA */ break; } @@ -505,7 +504,7 @@ static void ieee80211_michael_mic_failur else ev.flags |= IW_MICFAILURE_PAIRWISE; ev.src_addr.sa_family = ARPHRD_ETHER; - memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN); + memcpy(ev.src_addr.sa_data, hdr->addr2, IEEE80211_ALEN); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = sizeof(ev); wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev); Index: netdev/net/ieee80211/Makefile =================================================================== --- netdev.orig/net/ieee80211/Makefile 2005-09-07 11:20:41.000000000 +0200 +++ netdev/net/ieee80211/Makefile 2005-09-17 14:52:53.000000000 +0200 @@ -5,6 +5,7 @@ obj-$(CONFIG_IEEE80211_CRYPT_CCMP) += ie obj-$(CONFIG_IEEE80211_CRYPT_TKIP) += ieee80211_crypt_tkip.o ieee80211-objs := \ ieee80211_module.o \ + ieee80211_proto.o \ ieee80211_tx.o \ ieee80211_rx.o \ ieee80211_wx.o Index: netdev/net/ieee80211/ieee80211_proto.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ netdev/net/ieee80211/ieee80211_proto.c 2005-09-17 14:52:53.000000000 +0200 @@ -0,0 +1,239 @@ +/******************************************************************************* + + Copyright (c) 2005 Jiri Benc and Jirka Bohac + Copyright (c) 2004 Intel Corporation. All rights reserved. + (Contact: James P. Ketrenos ) + + Sponsored by SuSE. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > IEEE80211_DATA_LEN - 8 - SNAP_SIZE)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + + +static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; +static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; + +static inline int __ieee80211_put_snap(u8 *data, u16 h_proto) +{ + struct ieee80211_snap_hdr *snap; + u8 *oui; + + snap = (struct ieee80211_snap_hdr *)data; + snap->dsap = 0xaa; + snap->ssap = 0xaa; + snap->ctrl = 0x03; + + if (h_proto == __constant_htons(ETH_P_IPX) || + h_proto == __constant_htons(ETH_P_AARP)) + oui = P802_1H_OUI; + else + oui = RFC1042_OUI; + snap->oui[0] = oui[0]; + snap->oui[1] = oui[1]; + snap->oui[2] = oui[2]; + + snap->type = h_proto; + + return SNAP_SIZE; +} + +static inline int ieee80211_put_snap(u8 *data, u16 h_proto) +{ + return __ieee80211_put_snap(data, htons(h_proto)); +} + +/* + * Create the IEEE 802.11 MAC header for an arbitrary protocol layer + * + * saddr=NULL means use device source address + * daddr=NULL means leave destination address (eg unresolved arp) + */ +static int ieee80211_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ + struct ieee80211_device *ieee = netdev_priv(dev); + struct ieee80211_hdr *header; + int fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; + int hdr_len = IEEE80211_3ADDR_LEN; + + if (type != ETH_P_802_3 && type != ETH_P_802_2) { + ieee80211_put_snap(skb_push(skb, SNAP_SIZE), type); + hdr_len += SNAP_SIZE; + } + + if (!saddr) saddr = dev->dev_addr; + header = (struct ieee80211_hdr *)skb_push(skb, IEEE80211_3ADDR_LEN); + header->duration_id = header->seq_ctl = 0; + if (ieee->iw_mode == IW_MODE_INFRA) { + fc |= IEEE80211_FCTL_TODS; + /* To DS: Addr1 = BSSID, Addr2 = SA, + Addr3 = DA */ + memcpy(header->addr1, ieee->bssid, IEEE80211_ALEN); + memcpy(header->addr2, saddr, IEEE80211_ALEN); + if (daddr) + memcpy(header->addr3, daddr, IEEE80211_ALEN); + else + memset(header->addr3, 0, IEEE80211_ALEN); + } else if (ieee->iw_mode == IW_MODE_ADHOC) { + /* not From/To DS: Addr1 = DA, Addr2 = SA, + Addr3 = BSSID */ + if (daddr) + memcpy(header->addr1, daddr, IEEE80211_ALEN); + else + memset(header->addr1, 0, IEEE80211_ALEN); + memcpy(header->addr2, saddr, IEEE80211_ALEN); + memcpy(header->addr3, ieee->bssid, IEEE80211_ALEN); + } + header->frame_ctl = cpu_to_le16(fc); + + if (!daddr || (dev->flags & (IFF_LOOPBACK | IFF_NOARP))) + return -hdr_len; + return hdr_len; +} + +static int ieee80211_rebuild_header(struct sk_buff *skb) +{ + struct ieee80211_hdr *header = (struct ieee80211_hdr *)skb->data; + struct net_device *dev = skb->dev; + unsigned short type; + + type = ieee80211_get_proto(header); + + switch (type) { +#ifdef CONFIG_INET + case ETH_P_IP: + return arp_find(ieee80211_get_daddr(header), skb); +#endif + default: + printk(KERN_DEBUG + "%s: unable to resolve type %X addresses.\n", + dev->name, type); + break; + } + + return 0; +} + +static int ieee80211_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + if (netif_running(dev)) + return -EBUSY; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + return 0; +} + +static int ieee80211_header_cache(struct neighbour *neigh, struct hh_cache *hh) +{ + struct net_device *dev = neigh->dev; + struct ieee80211_device *ieee = netdev_priv(dev); + unsigned short type = hh->hh_type; + struct ieee80211_hdr *header; + int fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; + + if (type == __constant_htons(ETH_P_802_3) || + type == __constant_htons(ETH_P_802_2)) + return -1; + + header = (struct ieee80211_hdr *) + (((u8 *)hh->hh_data) + + (HH_DATA_OFF(IEEE80211_3ADDR_LEN + SNAP_SIZE))); + __ieee80211_put_snap((u8 *)header + IEEE80211_3ADDR_LEN, type); + + header->duration_id = header->seq_ctl = 0; + if (ieee->iw_mode == IW_MODE_INFRA) { + fc |= IEEE80211_FCTL_TODS; + /* To DS: Addr1 = BSSID, Addr2 = SA, + Addr3 = DA */ + memcpy(header->addr1, ieee->bssid, IEEE80211_ALEN); + memcpy(header->addr2, dev->dev_addr, IEEE80211_ALEN); + memcpy(header->addr3, neigh->ha, IEEE80211_ALEN); + } else if (ieee->iw_mode == IW_MODE_ADHOC) { + /* not From/To DS: Addr1 = DA, Addr2 = SA, + Addr3 = BSSID */ + memcpy(header->addr1, neigh->ha, IEEE80211_ALEN); + memcpy(header->addr2, dev->dev_addr, IEEE80211_ALEN); + memcpy(header->addr3, ieee->bssid, IEEE80211_ALEN); + } + header->frame_ctl = cpu_to_le16(fc); + + hh->hh_len = IEEE80211_3ADDR_LEN + SNAP_SIZE; + return 0; +} + +static void ieee80211_header_cache_update(struct hh_cache *hh, + struct net_device *dev, unsigned char *haddr) +{ + struct ieee80211_hdr *header; + + header = (struct ieee80211_hdr *) + (((u8 *)hh->hh_data) + + (HH_DATA_OFF(IEEE80211_3ADDR_LEN + SNAP_SIZE))); + memcpy(ieee80211_get_daddr(header), haddr, dev->addr_len); +} + +static int ieee80211_header_parse(struct sk_buff *skb, unsigned char *haddr) +{ + struct ieee80211_hdr *header = (struct ieee80211_hdr *)skb->mac.raw; + + memcpy(haddr, ieee80211_get_saddr(header), IEEE80211_ALEN); + return IEEE80211_ALEN; +} + + +void ieee80211_setup(struct net_device *dev) +{ + dev->change_mtu = ieee80211_change_mtu; + dev->hard_header = ieee80211_header; + dev->rebuild_header = ieee80211_rebuild_header; + dev->set_mac_address = ieee80211_mac_addr; + dev->hard_header_cache = ieee80211_header_cache; + dev->header_cache_update = ieee80211_header_cache_update; + dev->hard_header_parse = ieee80211_header_parse; + + dev->hard_start_xmit = ieee80211_xmit; + + dev->type = ARPHRD_ETHER; + dev->hard_header_len = IEEE80211_3ADDR_LEN + SNAP_SIZE; + dev->mtu = IEEE80211_DATA_LEN - 8 - SNAP_SIZE; + dev->addr_len = IEEE80211_ALEN; + dev->tx_queue_len = 1000; + dev->flags = IFF_BROADCAST | IFF_MULTICAST; + + memset(dev->broadcast, 0xFF, IEEE80211_ALEN); +} + + +EXPORT_SYMBOL(ieee80211_setup);