The ieee80211 layer, now present in -mm, lacks many important features
(actually it's just a part of the ipw2100/ipw2200 driver; these cards do
a lot of the processing in the hardware/firmware and thus the layer
currently can not be used for simpler devices).
This is the first series of patches that try to convert it to a generic
IEEE 802.11 layer, usable for most of today's wireless cards.
The long term plan is:
- to implement a complete 802.11 stack in the kernel, making it easy to
write drivers for simple (cheap) devices
- to implement all of Ad-Hoc, AP and monitor modes in the layer, so it
will be easy to support them in the drivers
- to integrate Wireless Extensions to unify the kernel-userspace
interface of all the drivers
This means that drivers for "stupid" (simple, cheap) cards should be
very short and easy to write, whereas drivers for "clever" cards will be
longer (but still shorter than they are now).
We have a couple of cards for testing, and we gradually modify the
drivers for ipw2100 and ipw2200 with the development of the layer. When
the layer is mature enough for the "stupid" cards, we will rewrite the
driver for Atheros-based cards to use this layer. We plan to send all
the patches for these drivers to the netdev list. Of course, we are in
close contact with Pavel Machek, who is pushing the ipw2100 driver
upstream.
Any comments and suggestions are appreciated.
Jiri Benc <[email protected]> and Jirka Bohac <[email protected]>
SUSE Labs
Cleanup of unused and duplicated constants and structures in the ieee80211
header.
Signed-off-by: Jiri Benc <[email protected]>
Signed-off-by: Jirka Bohac <[email protected]>
--- orig/include/net/ieee80211.h 2005-05-12 11:36:27.000000000 +0200
+++ new/include/net/ieee80211.h 2005-05-17 15:37:38.000000000 +0200
@@ -93,6 +93,8 @@
u16 length;
} __attribute__ ((packed));
+#define IEEE80211_1ADDR_LEN 10
+#define IEEE80211_2ADDR_LEN 16
#define IEEE80211_3ADDR_LEN 24
#define IEEE80211_4ADDR_LEN 30
#define IEEE80211_FCS_LEN 4
@@ -299,23 +301,6 @@
#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
-/* Information Element IDs */
-#define WLAN_EID_SSID 0
-#define WLAN_EID_SUPP_RATES 1
-#define WLAN_EID_FH_PARAMS 2
-#define WLAN_EID_DS_PARAMS 3
-#define WLAN_EID_CF_PARAMS 4
-#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
-#define IEEE80211_DATA_HDR4_LEN 30
-
-
#define IEEE80211_STATMASK_SIGNAL (1<<0)
#define IEEE80211_STATMASK_RSSI (1<<1)
#define IEEE80211_STATMASK_NOISE (1<<2)
@@ -489,15 +474,6 @@
*/
-struct ieee80211_header_data {
- u16 frame_ctl;
- u16 duration_id;
- u8 addr1[6];
- u8 addr2[6];
- u8 addr3[6];
- u16 seq_ctrl;
-};
-
#define BEACON_PROBE_SSID_ID_POSITION 12
/* Management Frame Information Element Types */
@@ -542,7 +518,7 @@
*/
struct ieee80211_authentication {
- struct ieee80211_header_data header;
+ struct ieee80211_hdr_3addr header;
u16 algorithm;
u16 transaction;
u16 status;
@@ -551,7 +527,7 @@
struct ieee80211_probe_response {
- struct ieee80211_header_data header;
+ struct ieee80211_hdr_3addr header;
u32 time_stamp[2];
u16 beacon_interval;
u16 capability;
@@ -793,21 +769,21 @@
extern inline int ieee80211_get_hdrlen(u16 fc)
{
- int hdrlen = 24;
+ int hdrlen = IEEE80211_3ADDR_LEN;
switch (WLAN_FC_GET_TYPE(fc)) {
case IEEE80211_FTYPE_DATA:
if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
- hdrlen = 30; /* Addr4 */
+ hdrlen = IEEE80211_4ADDR_LEN;
break;
case IEEE80211_FTYPE_CTL:
switch (WLAN_FC_GET_STYPE(fc)) {
case IEEE80211_STYPE_CTS:
case IEEE80211_STYPE_ACK:
- hdrlen = 10;
+ hdrlen = IEEE80211_1ADDR_LEN;
break;
default:
- hdrlen = 16;
+ hdrlen = IEEE80211_2ADDR_LEN;
break;
}
break;
--- orig/net/ieee80211/ieee80211_rx.c 2005-05-12 11:36:29.000000000 +0200
+++ new/net/ieee80211/ieee80211_rx.c 2005-05-17 15:37:38.000000000 +0200
@@ -475,7 +475,7 @@
#endif
/* Data frame - extract src/dst addresses */
- if (skb->len < IEEE80211_DATA_HDR3_LEN)
+ if (skb->len < IEEE80211_3ADDR_LEN)
goto rx_dropped;
switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
@@ -488,7 +488,7 @@
memcpy(src, hdr->addr2, ETH_ALEN);
break;
case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
- if (skb->len < IEEE80211_DATA_HDR4_LEN)
+ if (skb->len < IEEE80211_4ADDR_LEN)
goto rx_dropped;
memcpy(dst, hdr->addr3, ETH_ALEN);
memcpy(src, hdr->addr4, ETH_ALEN);
--
Jiri Benc
SUSE Labs
Changes to the ieee80211 layer:
- fixes a serious alignment problem of the driver's private data
- makes the drivers use the ieee80211_device instead of the net_device where
appropriate (will ease further development of ieee80211 as a self-contained
layer)
Signed-off-by: Jiri Benc <[email protected]>
Signed-off-by: Jirka Bohac <[email protected]>
--- linux-2.6.12-rc2-mm3.01/include/net/ieee80211.h 2005-05-18 10:49:01.000000000 +0200
+++ linux-2.6.12-rc2-mm3.02.0/include/net/ieee80211.h 2005-05-18 12:02:03.000000000 +0200
@@ -704,15 +704,13 @@
int abg_ture; /* ABG flag */
/* Callback functions */
- void (*set_security)(struct net_device *dev,
+ void (*set_security)(struct ieee80211_device *ieee,
struct ieee80211_security *sec);
int (*hard_start_xmit)(struct ieee80211_txb *txb,
- struct net_device *dev);
- int (*reset_port)(struct net_device *dev);
+ struct ieee80211_device *ieee);
+ int (*reset_port)(struct ieee80211_device *ieee);
- /* This must be the last item so that it points to the data
- * allocated beyond this structure by alloc_ieee80211 */
- u8 priv[0];
+ void *priv;
};
#define IEEE_A (1<<0)
@@ -720,9 +718,18 @@
#define IEEE_G (1<<2)
#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G)
-extern inline void *ieee80211_priv(struct net_device *dev)
+static inline void *ieee80211_priv(struct ieee80211_device *ieee)
{
- return ((struct ieee80211_device *)netdev_priv(dev))->priv;
+ return (char *)ieee +
+ ((sizeof(struct ieee80211_device) + NETDEV_ALIGN_CONST)
+ & ~NETDEV_ALIGN_CONST);
+}
+
+static inline struct net_device *ieee80211_dev(struct ieee80211_device *ieee)
+{
+ return (struct net_device *)((char *)ieee -
+ ((sizeof(struct net_device) + NETDEV_ALIGN_CONST)
+ & ~NETDEV_ALIGN_CONST));
}
extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len)
@@ -795,8 +802,8 @@
/* ieee80211.c */
-extern void free_ieee80211(struct net_device *dev);
-extern struct net_device *alloc_ieee80211(int sizeof_priv);
+extern void free_ieee80211(struct ieee80211_device *ieee);
+extern struct ieee80211_device *alloc_ieee80211(int sizeof_priv);
extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
--- linux-2.6.12-rc2-mm3.01/net/ieee80211/ieee80211_module.c 2005-04-19 17:04:43.000000000 +0200
+++ linux-2.6.12-rc2-mm3.02.0/net/ieee80211/ieee80211_module.c 2005-05-18 12:04:30.000000000 +0200
@@ -70,7 +70,7 @@
GFP_KERNEL);
if (!ieee->networks) {
printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
- ieee->dev->name);
+ ieee80211_dev(ieee)->name);
return -ENOMEM;
}
@@ -99,23 +99,28 @@
}
-struct net_device *alloc_ieee80211(int sizeof_priv)
+struct ieee80211_device *alloc_ieee80211(int sizeof_priv)
{
struct ieee80211_device *ieee;
struct net_device *dev;
+ int alloc_size;
int err;
IEEE80211_DEBUG_INFO("Initializing...\n");
- dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
+ alloc_size = ((sizeof(struct ieee80211_device) + NETDEV_ALIGN_CONST)
+ & ~NETDEV_ALIGN_CONST)
+ + sizeof_priv;
+ dev = alloc_etherdev(alloc_size);
if (!dev) {
IEEE80211_ERROR("Unable to network device.\n");
goto failed;
}
ieee = netdev_priv(dev);
- dev->hard_start_xmit = ieee80211_xmit;
-
ieee->dev = dev;
+ ieee->priv = ieee80211_priv(ieee);
+
+ dev->hard_start_xmit = ieee80211_xmit;
err = ieee80211_networks_allocate(ieee);
if (err) {
@@ -148,7 +153,7 @@
ieee->privacy_invoked = 0;
ieee->ieee802_1x = 1;
- return dev;
+ return ieee;
failed:
if (dev)
@@ -157,10 +162,8 @@
}
-void free_ieee80211(struct net_device *dev)
+void free_ieee80211(struct ieee80211_device *ieee)
{
- struct ieee80211_device *ieee = netdev_priv(dev);
-
int i;
del_timer_sync(&ieee->crypt_deinit_timer);
@@ -179,7 +182,7 @@
}
ieee80211_networks_free(ieee);
- free_netdev(dev);
+ free_netdev(ieee80211_dev(ieee));
}
#ifdef CONFIG_IEEE80211_DEBUG
--- linux-2.6.12-rc2-mm3.01/net/ieee80211/ieee80211_rx.c 2005-05-18 10:49:01.000000000 +0200
+++ linux-2.6.12-rc2-mm3.02.0/net/ieee80211/ieee80211_rx.c 2005-05-18 12:24:18.000000000 +0200
@@ -100,7 +100,7 @@
if (frag == 0) {
/* Reserve enough space to fit maximum frame length */
- skb = dev_alloc_skb(ieee->dev->mtu +
+ skb = dev_alloc_skb(ieee80211_dev(ieee)->mtu +
sizeof(struct ieee80211_hdr) +
8 /* LLC */ +
2 /* alignment */ +
@@ -176,7 +176,7 @@
{
if (ieee->iw_mode == IW_MODE_MASTER) {
printk(KERN_DEBUG "%s: Master mode not yet suppported.\n",
- ieee->dev->name);
+ ieee80211_dev(ieee)->name);
return 0;
/*
hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr *)
@@ -234,7 +234,7 @@
static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,
struct sk_buff *skb)
{
- struct net_device *dev = ieee->dev;
+ struct net_device *dev = ieee80211_dev(ieee);
u16 fc, ethertype;
struct ieee80211_hdr *hdr;
u8 *pos;
@@ -290,7 +290,7 @@
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
"received packet from " MAC_FMT "\n",
- ieee->dev->name, MAC_ARG(hdr->addr2));
+ ieee80211_dev(dev)->name, MAC_ARG(hdr->addr2));
}
return -1;
}
@@ -335,7 +335,7 @@
if (res < 0) {
printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
" (SA=" MAC_FMT " keyidx=%d)\n",
- ieee->dev->name, MAC_ARG(hdr->addr2), keyidx);
+ ieee80211_dev(ieee)->name, MAC_ARG(hdr->addr2), keyidx);
return -1;
}
@@ -349,7 +349,7 @@
int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
struct ieee80211_rx_stats *rx_stats)
{
- struct net_device *dev = ieee->dev;
+ struct net_device *dev = ieee80211_dev(ieee);
struct ieee80211_hdr *hdr;
size_t hdrlen;
u16 fc, type, stype, sc;
@@ -1195,7 +1195,7 @@
IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
WLAN_FC_GET_STYPE(header->frame_ctl));
IEEE80211_WARNING("%s: Unknown management packet: %d\n",
- ieee->dev->name,
+ ieee80211_dev(ieee)->name,
WLAN_FC_GET_STYPE(header->frame_ctl));
break;
}
--- linux-2.6.12-rc2-mm3.01/net/ieee80211/ieee80211_tx.c 2005-04-19 17:04:43.000000000 +0200
+++ linux-2.6.12-rc2-mm3.02.0/net/ieee80211/ieee80211_tx.c 2005-05-18 12:20:07.000000000 +0200
@@ -172,7 +172,7 @@
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
"TX packet to " MAC_FMT "\n",
- ieee->dev->name, MAC_ARG(header->addr1));
+ ieee80211_dev(ieee)->name, MAC_ARG(header->addr1));
}
return -1;
}
@@ -193,7 +193,7 @@
atomic_dec(&crypt->refcnt);
if (res < 0) {
printk(KERN_INFO "%s: Encryption failed: len=%d.\n",
- ieee->dev->name, frag->len);
+ ieee80211_dev(ieee)->name, frag->len);
ieee->ieee_stats.tx_discards++;
return -1;
}
@@ -270,13 +270,13 @@
* creating it... */
if (!ieee->hard_start_xmit) {
printk(KERN_WARNING "%s: No xmit handler.\n",
- ieee->dev->name);
+ dev->name);
goto success;
}
if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
printk(KERN_WARNING "%s: skb too small (%d).\n",
- ieee->dev->name, skb->len);
+ dev->name, skb->len);
goto success;
}
@@ -372,7 +372,7 @@
txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC);
if (unlikely(!txb)) {
printk(KERN_WARNING "%s: Could not allocate TXB\n",
- ieee->dev->name);
+ dev->name);
goto failed;
}
txb->encrypted = encrypt;
@@ -427,7 +427,7 @@
dev_kfree_skb_any(skb);
if (txb) {
- if ((*ieee->hard_start_xmit)(txb, dev) == 0) {
+ if ((*ieee->hard_start_xmit)(txb, ieee) == 0) {
stats->tx_packets++;
stats->tx_bytes += txb->payload_size;
return 0;
--- linux-2.6.12-rc2-mm3.01/net/ieee80211/ieee80211_wx.c 2005-04-19 17:04:43.000000000 +0200
+++ linux-2.6.12-rc2-mm3.02.0/net/ieee80211/ieee80211_wx.c 2005-05-18 12:27:28.000000000 +0200
@@ -252,7 +252,7 @@
union iwreq_data *wrqu, char *keybuf)
{
struct iw_point *erq = &(wrqu->encoding);
- struct net_device *dev = ieee->dev;
+ struct net_device *dev = ieee80211_dev(ieee);
struct ieee80211_security sec = {
.flags = 0
};
@@ -402,7 +402,7 @@
sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
if (ieee->set_security)
- ieee->set_security(dev, &sec);
+ ieee->set_security(ieee, &sec);
/* Do not reset port if card is in Managed mode since resetting will
* generate new IEEE 802.11 authentication which may end up in looping
@@ -411,7 +411,7 @@
* the callbacks structures used to initialize the 802.11 stack. */
if (ieee->reset_on_keychange &&
ieee->iw_mode != IW_MODE_INFRA &&
- ieee->reset_port && ieee->reset_port(dev)) {
+ ieee->reset_port && ieee->reset_port(ieee)) {
printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
return -EINVAL;
}
--
Jiri Benc
SUSE Labs
When the hardware header size is a multiple of HH_DATA_MOD, HH_DATA_OFF()
incorrectly returns HH_DATA_MOD (instead of 0).
Signed-off-by: Jiri Benc <[email protected]>
--- linux/include/linux/netdevice.h
+++ work/include/linux/netdevice.h
@@ -204,7 +209,7 @@
/* cached hardware header; allow for machine alignment needs. */
#define HH_DATA_MOD 16
#define HH_DATA_OFF(__len) \
- (HH_DATA_MOD - ((__len) & (HH_DATA_MOD - 1)))
+ (HH_DATA_MOD - (((__len - 1) & (HH_DATA_MOD - 1)) + 1))
#define HH_DATA_ALIGN(__len) \
(((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1))
unsigned long hh_data[HH_DATA_ALIGN(LL_MAX_HEADER) / sizeof(long)];
--
Jiri Benc
SUSE Labs
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 <[email protected]>
Signed-off-by: Jirka Bohac <[email protected]>
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -83,13 +83,18 @@
* 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
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -20,7 +20,6 @@
*/
#ifndef IEEE80211_H
#define IEEE80211_H
-#include <linux/if_ether.h> /* ETH_ALEN */
#include <linux/kernel.h> /* ARRAY_SIZE */
#if WIRELESS_EXT < 17
@@ -42,25 +41,26 @@
WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+#define IEEE80211_ALEN 6
#define IEEE80211_HLEN 30
#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
struct ieee80211_hdr {
u16 frame_ctl;
u16 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];
u16 seq_ctl;
- u8 addr4[ETH_ALEN];
+ u8 addr4[IEEE80211_ALEN];
} __attribute__ ((packed));
struct ieee80211_hdr_3addr {
u16 frame_ctl;
u16 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];
u16 seq_ctl;
} __attribute__ ((packed));
@@ -233,7 +233,7 @@
#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 */
@@ -246,11 +246,29 @@
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)
+#define IEEE80211_SNAP_IS_RFC1042(snap) \
+ ((snap)->oui[0] == 0 && (snap)->oui[1] == 0 && (snap)->oui[2] == 0)
+#define IEEE80211_SNAP_IS_BRIDGE_TUNNEL(snap) \
+ ((snap)->oui[0] == 0 && (snap)->oui[1] == 0 && (snap)->oui[2] == 0xf8)
+
+#define IEEE80211_FC_GET_TODS(hdr) \
+ ((hdr)->frame_ctl & __constant_cpu_to_le16(IEEE80211_FCTL_TODS))
+#define IEEE80211_FC_GET_FROMDS(hdr) \
+ ((hdr)->frame_ctl & __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS))
+#define IEEE80211_GET_DADDR(hdr) \
+ (IEEE80211_FC_GET_TODS(hdr) ? (hdr)->addr3 : (hdr)->addr1)
+#define IEEE80211_GET_SADDR(hdr) \
+ (IEEE80211_FC_GET_FROMDS(hdr) ? \
+ (IEEE80211_FC_GET_TODS(hdr) ? (hdr)->addr4 : (hdr)->addr3) \
+ : (hdr)->addr2)
+/* IEEE80211_GET_xADDR do not work when both TODS and FROMDS are set. */
+
#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
@@ -395,8 +413,8 @@
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 {
@@ -507,7 +525,7 @@
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;
@@ -537,7 +555,7 @@
struct ieee80211_assoc_request_frame {
u16 capability;
u16 listen_interval;
- u8 current_ap[ETH_ALEN];
+ u8 current_ap[IEEE80211_ALEN];
struct ieee80211_info_element info_element;
} __attribute__ ((packed));
@@ -581,7 +599,7 @@
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];
@@ -625,12 +643,12 @@
#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
-extern inline int is_multicast_ether_addr(const u8 *addr)
+extern inline int is_multicast_ieee80211_addr(const u8 *addr)
{
return ((addr[0] != 0xff) && (0x01 & addr[0]));
}
-extern inline int is_broadcast_ether_addr(const u8 *addr)
+extern inline int is_broadcast_ieee80211_addr(const u8 *addr)
{
return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \
(addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff));
@@ -694,7 +712,7 @@
u16 fts; /* Fragmentation Threshold */
/* Association info */
- u8 bssid[ETH_ALEN];
+ u8 bssid[IEEE80211_ALEN];
enum ieee80211_state state;
@@ -774,7 +792,7 @@
return 0;
}
-extern inline int ieee80211_get_hdrlen(u16 fc)
+extern inline int __ieee80211_get_hdrlen(u16 fc)
{
int hdrlen = IEEE80211_3ADDR_LEN;
@@ -798,12 +816,29 @@
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);
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -42,11 +42,10 @@
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 = ieee->dev;
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));
@@ -76,8 +75,8 @@
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 @@
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 @@
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 */
@@ -221,15 +220,6 @@
#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)
@@ -237,7 +227,6 @@
struct net_device *dev = ieee80211_dev(ieee);
u16 fc, ethertype;
struct ieee80211_hdr *hdr;
- u8 *pos;
if (skb->len < 24)
return 0;
@@ -248,12 +237,12 @@
/* 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;
@@ -262,8 +251,7 @@
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;
@@ -282,7 +270,7 @@
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 &&
@@ -327,7 +315,7 @@
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);
@@ -343,6 +331,44 @@
}
+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 &&
+ ((IEEE80211_SNAP_IS_RFC1042(snap) &&
+ snap->type != __constant_htons(ETH_P_AARP) &&
+ snap->type != __constant_htons(ETH_P_IPX)) ||
+ IEEE80211_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_ieee80211_addr(daddr))
+ skb->pkt_type = PACKET_BROADCAST;
+ else if (is_multicast_ieee80211_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). */
@@ -355,8 +381,6 @@
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;
@@ -365,8 +389,8 @@
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;
@@ -384,7 +408,7 @@
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);
#ifdef NOT_YET
#if WIRELESS_EXT > 15
@@ -480,22 +504,23 @@
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;
}
@@ -510,7 +535,7 @@
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);
@@ -668,9 +693,6 @@
/* 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. */
@@ -697,38 +719,6 @@
}
#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;
@@ -754,7 +744,7 @@
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;
@@ -764,7 +754,7 @@
#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 */
@@ -821,7 +811,7 @@
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 = beacon->capability;
network->last_scanned = jiffies;
network->time_stamp[0] = beacon->time_stamp[0];
@@ -849,7 +839,7 @@
while (left >= sizeof(struct ieee80211_info_element_hdr)) {
if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) {
IEEE80211_DEBUG_SCAN("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%d left=%d.\n",
- info_element->len + sizeof(struct ieee80211_info_element),
+ info_element->len + (int)sizeof(struct ieee80211_info_element),
left);
return 1;
}
@@ -1017,7 +1007,7 @@
* 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));
}
--- a/net/ieee80211/ieee80211_module.c
+++ b/net/ieee80211/ieee80211_module.c
@@ -48,7 +48,6 @@
#include <linux/types.h>
#include <linux/version.h>
#include <linux/wireless.h>
-#include <linux/etherdevice.h>
#include <asm/uaccess.h>
#include <net/arp.h>
@@ -99,28 +98,230 @@
}
+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->data;
+
+ 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);
+}
+
+
struct ieee80211_device *alloc_ieee80211(int sizeof_priv)
{
struct ieee80211_device *ieee;
struct net_device *dev;
- int alloc_size;
+ int alloc_size;
int err;
IEEE80211_DEBUG_INFO("Initializing...\n");
- alloc_size = ((sizeof(struct ieee80211_device) + NETDEV_ALIGN_CONST)
- & ~NETDEV_ALIGN_CONST)
- + sizeof_priv;
- dev = alloc_etherdev(alloc_size);
+ alloc_size = ((sizeof(struct ieee80211_device) + NETDEV_ALIGN_CONST)
+ & ~NETDEV_ALIGN_CONST)
+ + sizeof_priv;
+ 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) {
@@ -201,7 +402,7 @@
unsigned long count, void *data)
{
char buf[] = "0x00000000";
- unsigned long len = min(sizeof(buf) - 1, (u32)count);
+ unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
char *p = (char *)buf;
unsigned long val;
@@ -268,4 +469,5 @@
#endif
+EXPORT_SYMBOL(ieee80211_setup);
EXPORT_SYMBOL(alloc_ieee80211);
EXPORT_SYMBOL(free_ieee80211);
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -84,16 +84,6 @@
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.
@@ -104,56 +94,8 @@
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,
@@ -248,19 +190,16 @@
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;
@@ -269,76 +208,48 @@
/* 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;
}
#ifdef CONFIG_IEEE80211_DEBUG
- if (crypt && !encrypt && ether_type == ETH_P_PAE) {
- struct eapol *eap = (struct eapol *)(skb->data +
- sizeof(struct ethhdr) - SNAP_SIZE - sizeof(u16));
+ if (crypt && !encrypt && type == ETH_P_PAE) {
+ struct eapol *eap = (struct eapol *)(skb->data + hdr_len);
IEEE80211_DEBUG_EAP("TX: IEEE 802.11 EAPOL frame: %s\n",
eap_get_type(eap->type));
}
#endif
- /* 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));
-
/* 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_WEP;
- else
- fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
+ fc |= IEEE80211_FCTL_WEP;
- 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) */
- if (is_multicast_ether_addr(dest) ||
- is_broadcast_ether_addr(dest))
+ if (is_multicast_ieee80211_addr(dest) ||
+ is_broadcast_ieee80211_addr(dest))
frag_size = MAX_FRAG_THRESHOLD;
else
frag_size = ieee->fts;
@@ -347,7 +258,7 @@
* 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;
+ bytes_per_frag = frag_size - hdr_len;
if (ieee->config &
(CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
bytes_per_frag -= IEEE80211_FCS_LEN;
@@ -378,6 +289,8 @@
txb->encrypted = encrypt;
txb->payload_size = bytes;
+ skb_pull(skb, hdr_len);
+
for (i = 0; i < nr_frags; i++) {
skb_frag = txb->fragments[i];
@@ -385,7 +298,7 @@
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);
/* If this is not the last fragment, then add the MOREFRAGS
* bit to the frame control */
@@ -398,14 +311,6 @@
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... */
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -53,7 +53,7 @@
/* 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 */
--- a/net/ieee80211/ieee80211_crypt_ccmp.c
+++ b/net/ieee80211/ieee80211_crypt_ccmp.c
@@ -17,7 +17,6 @@
#include <linux/random.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <asm/string.h>
#include <linux/wireless.h>
@@ -156,7 +155,7 @@
* 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;
@@ -173,13 +172,13 @@
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 */
--- a/net/ieee80211/ieee80211_crypt_tkip.c
+++ b/net/ieee80211/ieee80211_crypt_tkip.c
@@ -17,7 +17,6 @@
#include <linux/random.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <asm/string.h>
@@ -461,20 +460,20 @@
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;
}
@@ -521,7 +520,7 @@
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);
--
Jiri Benc
SUSE Labs
Adds sequence numbers to IEEE 802.11 headers.
Signed-off-by: Jiri Benc <[email protected]>
Signed-off-by: Jirka Bohac <[email protected]>
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -711,6 +711,8 @@
unsigned int frag_next_idx;
u16 fts; /* Fragmentation Threshold */
+ u16 seq_number; /* sequence number in transmitted frames */
+
/* Association info */
u8 bssid[IEEE80211_ALEN];
--- a/net/ieee80211/ieee80211_module.c
+++ b/net/ieee80211/ieee80211_module.c
@@ -333,6 +333,7 @@
/* Default fragmentation threshold is maximum payload size */
ieee->fts = DEFAULT_FTS;
+ ieee->seq_number = 0;
ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
ieee->open_wep = 1;
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -277,6 +277,13 @@
else
bytes_last_frag = bytes_per_frag;
+ if (nr_frags > 16) {
+ /* Should never happen */
+ printk(KERN_WARNING "%s: Fragmentation threshold too low\n",
+ dev->name);
+ goto failed;
+ }
+
/* When we allocate the TXB we allocate enough space for the reserve
* and full fragment bytes (bytes_per_frag doesn't include prefix,
* postfix, header, FCS, etc.) */
@@ -300,6 +307,8 @@
frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len);
memcpy(frag_hdr, header, hdr_len);
+ frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_number | i);
+
/* If this is not the last fragment, then add the MOREFRAGS
* bit to the frame control */
if (i != nr_frags - 1) {
@@ -324,7 +333,7 @@
(CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
skb_put(skb_frag, 4);
}
-
+ ieee->seq_number += 0x10;
success:
spin_unlock_irqrestore(&ieee->lock, flags);
--
Jiri Benc
SUSE Labs
Hi!
> The ieee80211 layer, now present in -mm, lacks many important features
> (actually it's just a part of the ipw2100/ipw2200 driver; these cards do
> a lot of the processing in the hardware/firmware and thus the layer
> currently can not be used for simpler devices).
>
> This is the first series of patches that try to convert it to a generic
> IEEE 802.11 layer, usable for most of today's wireless cards.
Are they against -rc4-mm2?
Would it be possible to put agregate patch on the web somewhere (or
git tree?). I would certainly be easier to test....
Pavel
On Tue, 2005-05-24 at 15:07 +0200, Jiri Benc wrote:
> The ieee80211 layer, now present in -mm, lacks many important features
> (actually it's just a part of the ipw2100/ipw2200 driver; these cards do
> a lot of the processing in the hardware/firmware and thus the layer
> currently can not be used for simpler devices).
>
> This is the first series of patches that try to convert it to a generic
> IEEE 802.11 layer, usable for most of today's wireless cards.
>
> The long term plan is:
> - to implement a complete 802.11 stack in the kernel, making it easy to
> write drivers for simple (cheap) devices
> - to implement all of Ad-Hoc, AP and monitor modes in the layer, so it
> will be easy to support them in the drivers
> - to integrate Wireless Extensions to unify the kernel-userspace
> interface of all the drivers
Do you just clean up current ieee80211 code to still do 802.11 <-> 802.3
conversion inside the driver or you plan to handle real 802.11 frames in
the stack like this?
http://oss.sgi.com/archives/netdev/2005-03/msg01405.html
Thanks,
-yi
Jiri Benc wrote:
> When the hardware header size is a multiple of HH_DATA_MOD, HH_DATA_OFF()
> incorrectly returns HH_DATA_MOD (instead of 0).
>
> Signed-off-by: Jiri Benc <[email protected]>
>
> --- linux/include/linux/netdevice.h
> +++ work/include/linux/netdevice.h
> @@ -204,7 +209,7 @@
> /* cached hardware header; allow for machine alignment needs. */
> #define HH_DATA_MOD 16
> #define HH_DATA_OFF(__len) \
> - (HH_DATA_MOD - ((__len) & (HH_DATA_MOD - 1)))
> + (HH_DATA_MOD - (((__len - 1) & (HH_DATA_MOD - 1)) + 1))
> #define HH_DATA_ALIGN(__len) \
> (((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1))
> unsigned long hh_data[HH_DATA_ALIGN(LL_MAX_HEADER) / sizeof(long)];
You'll want to run this one by DaveM. He would be the appropriate one
to merge this, since it affects all ethernet devices (net/ethernet/eth.c
uses HH_DATA_OFF macro).
I'm going over the rest of the ieee80211/ipw patches...
Jeff
Jiri Benc wrote:
> The ieee80211 layer, now present in -mm, lacks many important features
> (actually it's just a part of the ipw2100/ipw2200 driver; these cards do
> a lot of the processing in the hardware/firmware and thus the layer
> currently can not be used for simpler devices).
Agreed.
> This is the first series of patches that try to convert it to a generic
> IEEE 802.11 layer, usable for most of today's wireless cards.
Great!
> The long term plan is:
> - to implement a complete 802.11 stack in the kernel, making it easy to
> write drivers for simple (cheap) devices
> - to implement all of Ad-Hoc, AP and monitor modes in the layer, so it
> will be easy to support them in the drivers
> - to integrate Wireless Extensions to unify the kernel-userspace
> interface of all the drivers
>
> This means that drivers for "stupid" (simple, cheap) cards should be
> very short and easy to write, whereas drivers for "clever" cards will be
> longer (but still shorter than they are now).
>
> We have a couple of cards for testing, and we gradually modify the
> drivers for ipw2100 and ipw2200 with the development of the layer. When
> the layer is mature enough for the "stupid" cards, we will rewrite the
> driver for Atheros-based cards to use this layer. We plan to send all
> the patches for these drivers to the netdev list. Of course, we are in
> close contact with Pavel Machek, who is pushing the ipw2100 driver
> upstream.
I'm interesting in writing a RealTek driver using ieee80211. As the
ieee80211 layer matures, I'll start publishing that code.
Jeff
Comments on the remaining patches in this series:
1) I am not convinced that the subclassing of net_device should be done
in this manner. Read drivers/net/wan/hdlc_generic.c and .../pc300_drv.c
for examples of how hdlc_device is handled.
Comments and thoughts welcome.
2) Please put all the new, protocol-layer functions
ieee80211_type_trans(), ieee80211_change_mtu(), ieee80211_header(), etc.
in their own file.
3) Temporary or not, the following construct is simply not necessary.
Modify the definition rather than repeating this two-call piece of code
in multiple areas:
ieee80211_priv(netdev_priv(dev));
4) A low-level wireless hardware driver should look like other net
drivers, and use the existing driver API. The low level driver should
implement its own dev->hard_start_xmit().
ieee = netdev_priv(dev);
- dev->hard_start_xmit = ieee80211_xmit;
-
ieee->dev = dev;
+ ieee->priv = ieee80211_priv(ieee);
+
+ dev->hard_start_xmit = ieee80211_xmit;
Certainly, the driver will make many calls to generic ieee80211_xxx
functions to get things done.
I understand this was not your change; you simply moved the
dev->hard_start_xmit() assignment down. I just wanted to take this
opportunity to make a point.
5) The wireless code in -mm all sourced directly from my netdev-2.6.git
tree. I strongly encourage everyone who wants to work on wireless to
download git (read http://lkml.org/lkml/2005/5/26/11) and check out
branches 'we18' (wireless ex 18), 'we18-ieee80211' (we18 + ieee80211),
and 'we18-ieee80211-wifi' (we18 + ieee80211 + hostAP) of
rsync://rsync.kernel.org/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git