* Re: [PATCH 16/17] d80211: fix monitor interfaces
From: Johannes Berg @ 2006-04-21 20:52 UTC (permalink / raw)
To: Jiri Benc; +Cc: netdev, John W. Linville
In-Reply-To: <20060421224935.5acd79bf@griffin.suse.cz>
[-- Attachment #1: Type: text/plain, Size: 927 bytes --]
On Fri, 2006-04-21 at 22:49 +0200, Jiri Benc wrote:
>
> "Hard" monitor mode means the card is operating in a true rfmon mode -
> i.e. you get everything on the given channel. "Soft" monitor mode means
> that you will get only frames the device is willing to give you at the
> time - this probably means only frames belonging to your BSS in case of
> fullmac cards.
Ok, thanks for clarifying; this description should be somewhere in the
comments or so IMHO.
> and this will work - independently of the value of monitor_during_oper.
> The difference is that in case of monitor_during_oper == 0, you won't
> probably receive much more frames from mon0 than from sta0. But - you
> will most likely receive beacons on mon0 and also monitoring headers
> (prism2 headers presently).
This I don't understand, doesn't the UI kind of suck as opposed to just
putting the sta0 device into promisc mode?
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 793 bytes --]
^ permalink raw reply
* [PATCH 10/10] d80211: add one default interface
From: Jiri Benc @ 2006-04-21 20:53 UTC (permalink / raw)
To: netdev
In-Reply-To: <20060421225314.048983000.midnight@suse.cz>
The wireless card is useless with master interface (wmasterX) only. Adding
at least one virtual interface is necessity for every user. To save users
a lot of pain (and to maintain backward compatibility) we should add one
virtual interface by default. It is called wlanX (hopefully the name users
are used to) and set to STA mode.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 9 +++++++++
net/d80211/ieee80211_i.h | 2 +-
net/d80211/ieee80211_iface.c | 18 ++++++++++++------
net/d80211/ieee80211_ioctl.c | 8 ++++----
net/d80211/ieee80211_sysfs.c | 2 +-
5 files changed, 27 insertions(+), 12 deletions(-)
a808727dea7cd4e8bf1185246e37a2780fb58292
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 1fd13dd..a03ab09 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -4215,6 +4215,7 @@ struct net_device *ieee80211_alloc_hw(si
int ieee80211_register_hw(struct net_device *dev, struct ieee80211_hw *hw)
{
struct ieee80211_local *local = dev->priv;
+ struct net_device *sta_dev;
int result;
if (!hw)
@@ -4259,6 +4260,14 @@ int ieee80211_register_hw(struct net_dev
ieee80211_wep_init(local);
ieee80211_proc_init_interface(local);
+
+ /* add one default STA interface */
+ rtnl_lock();
+ result = ieee80211_if_add(dev, "wlan%d", 1, &sta_dev);
+ if (result == 0)
+ ieee80211_if_set_type(sta_dev, IEEE80211_IF_TYPE_STA);
+ rtnl_unlock();
+
return 0;
fail_rate:
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 3580d1e..422d198 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -587,7 +587,7 @@ int ieee80211_dev_find_index(struct ieee
/* ieee80211_iface.c */
int ieee80211_if_add(struct net_device *dev, const char *name,
- struct net_device **new_dev);
+ int format, struct net_device **new_dev);
int ieee80211_if_set_type(struct net_device *dev, int type);
void ieee80211_if_reinit(struct net_device *dev);
void __ieee80211_if_del(struct ieee80211_local *local,
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index d71d4f9..4398567 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -26,7 +26,7 @@ void ieee80211_if_sdata_init(struct ieee
/* Must be called with rtnl lock held. */
int ieee80211_if_add(struct net_device *dev, const char *name,
- struct net_device **new_dev)
+ int format, struct net_device **new_dev)
{
struct net_device *ndev, *tmp_dev;
struct ieee80211_local *local = dev->priv;
@@ -54,6 +54,10 @@ int ieee80211_if_add(struct net_device *
break;
dev_put(tmp_dev);
} while (i < 10000);
+ } else if (format) {
+ ret = dev_alloc_name(ndev, name);
+ if (ret)
+ goto fail;
} else {
snprintf(ndev->name, IFNAMSIZ, "%s", name);
}
@@ -75,16 +79,18 @@ int ieee80211_if_add(struct net_device *
ieee80211_if_sdata_init(sdata);
ret = register_netdevice(ndev);
- if (ret) {
- kfree(ndev);
- *new_dev = NULL;
- return ret;
- }
+ if (ret)
+ goto fail;
list_add(&sdata->list, &local->sub_if_list);
ieee80211_proc_init_virtual(ndev);
return 0;
+
+fail:
+ kfree(ndev);
+ *new_dev = NULL;
+ return ret;
}
static int ieee80211_if_add_apdev(struct net_device *dev)
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 1d3f5cf..5d31a8f 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -931,7 +931,7 @@ static int ieee80211_ioctl_add_if(struct
if (left < sizeof(struct hostapd_if_wds))
return -EPROTO;
- res = ieee80211_if_add(dev, param->u.if_info.name, &new_dev);
+ res = ieee80211_if_add(dev, param->u.if_info.name, 0, &new_dev);
if (res)
return res;
ieee80211_if_set_type(new_dev, IEEE80211_IF_TYPE_WDS);
@@ -943,7 +943,7 @@ static int ieee80211_ioctl_add_if(struct
if (left < sizeof(struct hostapd_if_vlan))
return -EPROTO;
- res = ieee80211_if_add(dev, param->u.if_info.name, &new_dev);
+ res = ieee80211_if_add(dev, param->u.if_info.name, 0, &new_dev);
if (res)
return res;
ieee80211_if_set_type(new_dev, IEEE80211_IF_TYPE_VLAN);
@@ -960,7 +960,7 @@ #endif
if (left < sizeof(struct hostapd_if_bss))
return -EPROTO;
- res = ieee80211_if_add(dev, param->u.if_info.name, &new_dev);
+ res = ieee80211_if_add(dev, param->u.if_info.name, 0, &new_dev);
if (res)
return res;
ieee80211_if_set_type(new_dev, IEEE80211_IF_TYPE_AP);
@@ -975,7 +975,7 @@ #endif
if (left < sizeof(struct hostapd_if_sta))
return -EPROTO;
- res = ieee80211_if_add(dev, param->u.if_info.name, &new_dev);
+ res = ieee80211_if_add(dev, param->u.if_info.name, 0, &new_dev);
if (res)
return res;
ieee80211_if_set_type(new_dev, IEEE80211_IF_TYPE_STA);
diff --git a/net/d80211/ieee80211_sysfs.c b/net/d80211/ieee80211_sysfs.c
index 546e2b7..463f9aa 100644
--- a/net/d80211/ieee80211_sysfs.c
+++ b/net/d80211/ieee80211_sysfs.c
@@ -30,7 +30,7 @@ static ssize_t store_add_iface(struct cl
if (len > IFNAMSIZ)
return -EINVAL;
rtnl_lock();
- res = ieee80211_if_add(local->mdev, buf, &new_dev);
+ res = ieee80211_if_add(local->mdev, buf, 0, &new_dev);
if (res == 0)
ieee80211_if_set_type(new_dev, IEEE80211_IF_TYPE_STA);
rtnl_unlock();
--
1.3.0
^ permalink raw reply related
* [PATCH 9/10] d80211: rename master interface
From: Jiri Benc @ 2006-04-21 20:53 UTC (permalink / raw)
To: netdev
In-Reply-To: <20060421225314.048983000.midnight@suse.cz>
Rename master interface to wmasterX to better reflect its purpose.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 2 +-
net/d80211/ieee80211_i.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
784f203467e4421aa0ecac34cb1647f4bdfe51be
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 31f979c..1fd13dd 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -4144,7 +4144,7 @@ struct net_device *ieee80211_alloc_hw(si
((char *) local + ((sizeof(struct ieee80211_local) + 3) & ~3));
ether_setup(mdev);
- memcpy(mdev->name, "wlan%d", 7);
+ memcpy(mdev->name, "wmaster%d", 10);
local->dev_index = -1;
local->mdev = mdev;
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index ea1d9ab..3580d1e 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -318,7 +318,7 @@ #define IEEE80211_SUB_IF_TO_DEV(sub_if)
struct ieee80211_local {
struct ieee80211_hw *hw;
void *hw_priv;
- struct net_device *mdev; /* wlan# - "master" 802.11 device */
+ struct net_device *mdev; /* wmaster# - "master" 802.11 device */
int open_count;
int monitors;
struct ieee80211_conf conf;
--
1.3.0
^ permalink raw reply related
* [PATCH 8/10] d80211: get rid of default management interface
From: Jiri Benc @ 2006-04-21 20:53 UTC (permalink / raw)
To: netdev
In-Reply-To: <20060421225314.048983000.midnight@suse.cz>
Default management interface (wlanXap) confuses users. It is only needed for
AP mode (and only until interfaces are converted to use native 802.11
frames).
This patch removes default management interface. When a new interface is
switched to AP mode, a management interface is created automatically. This
also fixes some problems with multiple AP interfaces - now you have
different management interface for each AP interface.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 204 +++++++++++++++++++++++++-----------------
net/d80211/ieee80211_i.h | 6 +
net/d80211/ieee80211_iface.c | 73 ++++++++++++++-
3 files changed, 193 insertions(+), 90 deletions(-)
726d59fb8b157daf368b097cef7d3d2ed8c61784
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 2386454..31f979c 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -59,6 +59,8 @@ static int rate_control_initialize(struc
static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len);
+static void ieee80211_rx_michael_mic_report(struct ieee80211_txrx_data *rx,
+ struct ieee80211_hdr *hdr);
struct ieee80211_key_conf *
ieee80211_key_data2conf(struct ieee80211_local *local,
@@ -1954,8 +1956,6 @@ static inline int identical_mac_addr_all
{
return (type1 == IEEE80211_IF_TYPE_MNTR ||
type2 == IEEE80211_IF_TYPE_MNTR ||
- type1 == IEEE80211_IF_TYPE_MGMT ||
- type2 == IEEE80211_IF_TYPE_MGMT ||
(type1 == IEEE80211_IF_TYPE_AP &&
type2 == IEEE80211_IF_TYPE_WDS) ||
(type1 == IEEE80211_IF_TYPE_WDS &&
@@ -1990,6 +1990,20 @@ static int ieee80211_master_stop(struct
return 0;
}
+static int ieee80211_ap_open(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (!netif_running(sdata->u.ap.apdev))
+ return -EOPNOTSUPP;
+ return 0;
+}
+
+static int ieee80211_ap_stop(struct net_device *dev)
+{
+ return 0;
+}
+
/* Check if running monitor interfaces should go to a "soft monitor" mode
* and switch them if necessary. */
static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local)
@@ -2032,7 +2046,6 @@ static int ieee80211_open(struct net_dev
struct net_device *ndev = nsdata->dev;
if (ndev != dev && ndev != local->mdev &&
- ndev != local->apdev &&
netif_running(ndev) &&
memcmp(dev->dev_addr, ndev->dev_addr, ETH_ALEN) == 0 &&
!identical_mac_addr_allowed(sdata->type, nsdata->type)) {
@@ -2087,7 +2100,9 @@ static int ieee80211_open(struct net_dev
}
local->open_count++;
- if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+ if (sdata->type == IEEE80211_IF_TYPE_AP)
+ dev_open(sdata->u.ap.apdev);
+ else if (sdata->type == IEEE80211_IF_TYPE_MNTR)
local->monitors++;
netif_start_queue(dev);
@@ -2112,7 +2127,9 @@ static int ieee80211_stop(struct net_dev
netif_stop_queue(dev);
- if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+ if (sdata->type == IEEE80211_IF_TYPE_AP)
+ dev_close(sdata->u.ap.apdev);
+ else if (sdata->type == IEEE80211_IF_TYPE_MNTR)
local->monitors--;
local->open_count--;
@@ -2356,6 +2373,7 @@ ieee80211_get_rate(struct ieee80211_loca
}
+/* If dev is master device, skb will be sent to all AP interfaces. */
void
ieee80211_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
struct ieee80211_rx_status *status, u32 msg_type)
@@ -2363,13 +2381,15 @@ ieee80211_rx_mgmt(struct net_device *dev
struct ieee80211_local *local = dev->priv;
struct ieee80211_frame_info *fi;
size_t hlen;
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata, *apsdata, *prev = NULL;
- if (msg_type != ieee80211_msg_monitor)
- dev = local->apdev;
- skb->dev = dev;
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (msg_type != ieee80211_msg_monitor &&
+ sdata->type != IEEE80211_IF_TYPE_AP && dev != local->mdev) {
+ dev_kfree_skb(skb);
+ return;
+ }
if (skb_headroom(skb) < sizeof(struct ieee80211_frame_info)) {
I802_DEBUG_INC(local->rx_expand_skb_head);
@@ -2443,15 +2463,56 @@ ieee80211_rx_mgmt(struct net_device *dev
fi->ssi_type = htonl(ieee80211_ssi_none);
}
- sdata->stats.rx_packets++;
- sdata->stats.rx_bytes += skb->len;
-
skb->mac.raw = skb->data;
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->pkt_type = PACKET_OTHERHOST;
skb->protocol = __constant_htons(ETH_P_802_2);
memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
+
+ if (msg_type == ieee80211_msg_monitor) {
+ skb->dev = dev;
+ sdata->stats.rx_packets++;
+ sdata->stats.rx_bytes += skb->len;
+ netif_rx(skb);
+ return;
+ }
+
+ if (dev == local->mdev) {
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ if (sdata->type != IEEE80211_IF_TYPE_AP ||
+ sdata->dev == local->mdev)
+ continue;
+ if (prev) {
+ struct sk_buff *skb_new;
+
+ skb_new = skb_copy(skb, GFP_ATOMIC);
+ if (skb_new == NULL) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: failed "
+ "to copy message for %s",
+ dev->name,
+ prev->u.ap.apdev->name);
+ }
+ continue;
+ }
+ skb_new->dev = prev->u.ap.apdev;
+ apsdata = IEEE80211_DEV_TO_SUB_IF(skb_new->dev);
+ apsdata->stats.rx_packets++;
+ apsdata->stats.rx_bytes += skb_new->len;
+ netif_rx(skb_new);
+ }
+ prev = sdata;
+ }
+ sdata = prev;
+ }
+ if (sdata) {
+ skb->dev = sdata->u.ap.apdev;
+ apsdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
+ apsdata->stats.rx_packets++;
+ apsdata->stats.rx_bytes += skb->len;
+ netif_rx(skb);
+ } else
+ dev_kfree_skb(skb);
}
@@ -2839,6 +2900,11 @@ ieee80211_rx_h_check(struct ieee80211_tx
int always_sta_key;
hdr = (struct ieee80211_hdr *) rx->skb->data;
+ if ((rx->u.rx.status->flag & RX_FLAG_MMIC_ERROR)) {
+ ieee80211_rx_michael_mic_report(rx, hdr);
+ return TXRX_QUEUED;
+ }
+
/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
if (unlikely(rx->fc & WLAN_FC_RETRY &&
@@ -3207,10 +3273,8 @@ static u8 * ieee80211_get_bssid(struct i
return NULL;
}
-static void ieee80211_rx_michael_mic_report(struct net_device *dev,
- struct ieee80211_hdr *hdr,
- struct sta_info *sta,
- struct ieee80211_txrx_data *rx)
+static void ieee80211_rx_michael_mic_report(struct ieee80211_txrx_data *rx,
+ struct ieee80211_hdr *hdr)
{
int keyidx, hdrlen;
@@ -3224,22 +3288,22 @@ static void ieee80211_rx_michael_mic_rep
* frames (hw does not verify MIC for them). */
printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC "
"failure from " MACSTR " to " MACSTR " keyidx=%d\n",
- dev->name, MAC2STR(hdr->addr2), MAC2STR(hdr->addr1), keyidx);
+ rx->dev->name, MAC2STR(hdr->addr2), MAC2STR(hdr->addr1), keyidx);
- if (sta == NULL) {
+ if (rx->sta == NULL) {
/* Some hardware versions seem to generate incorrect
* Michael MIC reports; ignore them to avoid triggering
* countermeasures. */
printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
"error for unknown address " MACSTR "\n",
- dev->name, MAC2STR(hdr->addr2));
+ rx->dev->name, MAC2STR(hdr->addr2));
goto ignore;
}
if (!(rx->fc & WLAN_FC_ISWEP)) {
printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
"error for a frame with no ISWEP flag (src "
- MACSTR ")\n", dev->name, MAC2STR(hdr->addr2));
+ MACSTR ")\n", rx->dev->name, MAC2STR(hdr->addr2));
goto ignore;
}
@@ -3253,7 +3317,8 @@ static void ieee80211_rx_michael_mic_rep
if (keyidx) {
printk(KERN_DEBUG "%s: ignored Michael MIC error for "
"a frame with non-zero keyidx (%d) (src " MACSTR
- ")\n", dev->name, keyidx, MAC2STR(hdr->addr2));
+ ")\n", rx->dev->name, keyidx,
+ MAC2STR(hdr->addr2));
goto ignore;
}
}
@@ -3264,7 +3329,7 @@ static void ieee80211_rx_michael_mic_rep
printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
"error for a frame that cannot be encrypted "
"(fc=0x%04x) (src " MACSTR ")\n",
- dev->name, rx->fc, MAC2STR(hdr->addr2));
+ rx->dev->name, rx->fc, MAC2STR(hdr->addr2));
goto ignore;
}
@@ -3355,11 +3420,6 @@ void __ieee80211_rx(struct net_device *d
else
sta = rx.sta = NULL;
- if ((status->flag & RX_FLAG_MMIC_ERROR)) {
- ieee80211_rx_michael_mic_report(dev, hdr, sta, &rx);
- goto end;
- }
-
if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) &&
!local->iff_promiscs && !multicast) {
rx.dev = sta->dev;
@@ -3444,7 +3504,6 @@ void __ieee80211_rx(struct net_device *d
dev_kfree_skb(skb);
}
- end:
if (sta)
sta_info_release(local, sta);
}
@@ -3761,6 +3820,7 @@ void ieee80211_tx_status(struct net_devi
struct sk_buff *skb2;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_local *local = dev->priv;
+ struct net_device *odev;
u16 frag, type;
u32 msg_type;
@@ -3894,7 +3954,21 @@ #endif /* IEEE80211_LEDS */
skb = skb2;
/* Send frame to hostapd */
- ieee80211_rx_mgmt(dev, skb, NULL, msg_type);
+ odev = dev_get_by_index(status->control.ifindex);
+ if (unlikely(odev && !is_ieee80211_device(odev))) {
+ dev_put(odev);
+ odev = NULL;
+ }
+ if (unlikely(!odev)) {
+#ifdef CONFIG_D80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: Discarded tx_status from nonexistent "
+ "device\n", dev->name);
+#endif
+ dev_kfree_skb(skb);
+ return;
+ }
+ ieee80211_rx_mgmt(odev, skb, NULL, msg_type);
+ dev_put(odev);
}
@@ -3998,6 +4072,19 @@ void ieee80211_if_setup(struct net_devic
dev->destructor = ieee80211_if_free;
}
+void ieee80211_if_ap_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+ dev->hard_start_xmit = ieee80211_mgmt_start_xmit;
+ dev->change_mtu = ieee80211_change_mtu_apdev;
+ dev->get_stats = ieee80211_get_stats;
+ dev->open = ieee80211_ap_open;
+ dev->stop = ieee80211_ap_stop;
+ dev->type = ARPHRD_IEEE80211_PRISM;
+ dev->hard_header_parse = header_parse_80211;
+ dev->tx_queue_len = 0;
+ dev->destructor = ieee80211_if_free;
+}
static void ieee80211_precalc_rates(struct ieee80211_hw *hw)
{
@@ -4018,7 +4105,7 @@ static void ieee80211_precalc_rates(stru
struct net_device *ieee80211_alloc_hw(size_t priv_data_len,
void (*setup)(struct net_device *))
{
- struct net_device *apdev, *mdev;
+ struct net_device *mdev;
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
int alloc_size;
@@ -4038,17 +4125,11 @@ struct net_device *ieee80211_alloc_hw(si
* 0b84 *****************
* * hw_priv *
* 1664 *****************
- * * ap net_dev *
- * 17c0 *****************
- * * sub_if *
- * *****************
*/
alloc_size = sizeof(struct net_device) +
sizeof(struct ieee80211_sub_if_data) + 3 +
sizeof(struct ieee80211_local) + 3 +
priv_data_len + 3 +
- sizeof(struct net_device) + 3 +
- sizeof(struct ieee80211_sub_if_data) + 3 +
4096;
mdev = (struct net_device *) kzalloc(alloc_size, GFP_KERNEL);
if (mdev == NULL)
@@ -4061,15 +4142,10 @@ struct net_device *ieee80211_alloc_hw(si
local = mdev->priv;
local->hw_priv = (void *)
((char *) local + ((sizeof(struct ieee80211_local) + 3) & ~3));
- apdev = (struct net_device *)
- ((char *) local->hw_priv + ((priv_data_len + 3) & ~3));
ether_setup(mdev);
memcpy(mdev->name, "wlan%d", 7);
- if (strlen(mdev->name) + 2 >= sizeof(mdev->name))
- goto fail;
-
local->dev_index = -1;
local->mdev = mdev;
local->rx_handlers = ieee80211_rx_handlers;
@@ -4104,28 +4180,6 @@ struct net_device *ieee80211_alloc_hw(si
ieee80211_if_init(mdev);
- apdev = (struct net_device *)
- ((char *) local->hw_priv + ((priv_data_len + 3) & ~3));
- local->apdev = apdev;
- ether_setup(apdev);
- apdev->priv = local;
- apdev->hard_start_xmit = ieee80211_mgmt_start_xmit;
- apdev->change_mtu = ieee80211_change_mtu_apdev;
- apdev->get_stats = ieee80211_get_stats;
- apdev->open = ieee80211_open;
- apdev->stop = ieee80211_stop;
- apdev->type = ARPHRD_IEEE80211_PRISM;
- apdev->hard_header_parse = header_parse_80211;
- apdev->tx_queue_len = 0;
- sprintf(apdev->name, "%sap", mdev->name);
-
- sdata = IEEE80211_DEV_TO_SUB_IF(apdev);
- sdata->type = IEEE80211_IF_TYPE_MGMT;
- sdata->dev = apdev;
- sdata->master = mdev;
- sdata->local = local;
- list_add_tail(&sdata->list, &local->sub_if_list);
-
mdev->hard_start_xmit = ieee80211_master_start_xmit;
mdev->wireless_handlers =
(struct iw_handler_def *) &ieee80211_iw_handler_def;
@@ -4155,10 +4209,6 @@ struct net_device *ieee80211_alloc_hw(si
setup(mdev);
return mdev;
-
- fail:
- ieee80211_free_hw(mdev);
- return NULL;
}
@@ -4192,15 +4242,11 @@ int ieee80211_register_hw(struct net_dev
sta_info_start(local);
- result = register_netdev(local->apdev);
- if (result < 0)
- goto fail_1st_dev;
-
if (hw->fraglist)
dev->features |= NETIF_F_FRAGLIST;
result = register_netdev(dev);
if (result < 0)
- goto fail_2nd_dev;
+ goto fail_dev;
if (rate_control_initialize(local) < 0) {
printk(KERN_DEBUG "%s: Failed to initialize rate control "
@@ -4217,9 +4263,7 @@ int ieee80211_register_hw(struct net_dev
fail_rate:
unregister_netdev(dev);
-fail_2nd_dev:
- unregister_netdev(local->apdev);
-fail_1st_dev:
+fail_dev:
sta_info_stop(local);
ieee80211_unregister_sysfs(local);
fail_sysfs:
@@ -4238,12 +4282,6 @@ int ieee80211_update_hw(struct net_devic
if (hw->queues == 0)
hw->queues = 1;
- memcpy(local->apdev->dev_addr, dev->dev_addr, ETH_ALEN);
- local->apdev->base_addr = dev->base_addr;
- local->apdev->irq = dev->irq;
- local->apdev->mem_start = dev->mem_start;
- local->apdev->mem_end = dev->mem_end;
-
if (!hw->modes || !hw->modes->channels || !hw->modes->rates ||
!hw->modes->num_channels || !hw->modes->num_rates)
return -1;
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 77517c9..ea1d9ab 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -189,6 +189,8 @@ typedef ieee80211_txrx_result (*ieee8021
(struct ieee80211_txrx_data *rx);
struct ieee80211_if_ap {
+ struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
+
u8 *beacon_head, *beacon_tail;
int beacon_head_len, beacon_tail_len;
@@ -317,7 +319,6 @@ struct ieee80211_local {
struct ieee80211_hw *hw;
void *hw_priv;
struct net_device *mdev; /* wlan# - "master" 802.11 device */
- struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
int open_count;
int monitors;
struct ieee80211_conf conf;
@@ -518,6 +519,7 @@ void ieee80211_prepare_rates(struct net_
void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
void ieee80211_if_setup(struct net_device *dev);
+void ieee80211_if_ap_setup(struct net_device *dev);
/* ieee80211_ioctl.c */
int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -586,7 +588,7 @@ int ieee80211_dev_find_index(struct ieee
/* ieee80211_iface.c */
int ieee80211_if_add(struct net_device *dev, const char *name,
struct net_device **new_dev);
-void ieee80211_if_set_type(struct net_device *dev, int type);
+int ieee80211_if_set_type(struct net_device *dev, int type);
void ieee80211_if_reinit(struct net_device *dev);
void __ieee80211_if_del(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 58fd946..d71d4f9 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -87,9 +87,65 @@ int ieee80211_if_add(struct net_device *
return 0;
}
-void ieee80211_if_set_type(struct net_device *dev, int type)
+static int ieee80211_if_add_apdev(struct net_device *dev)
+{
+ struct net_device *ndev;
+ struct ieee80211_local *local = dev->priv;
+ struct ieee80211_sub_if_data *sdata, *nsdata;
+ int alloc_size, ret;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ ASSERT_RTNL();
+ alloc_size = sizeof(struct net_device) + 3 +
+ sizeof(struct ieee80211_sub_if_data) + 3;
+
+ ndev = (struct net_device *) kzalloc(alloc_size, GFP_KERNEL);
+ if (ndev == NULL)
+ return -ENOMEM;
+ snprintf(ndev->name, IFNAMSIZ, "%sap", dev->name);
+
+ ndev->priv = local;
+ memcpy(ndev->dev_addr, dev->dev_addr, ETH_ALEN);
+ ndev->base_addr = dev->base_addr;
+ ndev->irq = dev->irq;
+ ndev->mem_start = dev->mem_start;
+ ndev->mem_end = dev->mem_end;
+ ieee80211_if_ap_setup(ndev);
+
+ nsdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+ nsdata->type = IEEE80211_IF_TYPE_AP;
+ nsdata->master = local->mdev;
+ nsdata->dev = ndev;
+ nsdata->local = local;
+ ieee80211_if_sdata_init(nsdata);
+
+ ret = register_netdevice(ndev);
+ if (ret) {
+ if (ret == -EEXIST)
+ printk(KERN_DEBUG "%s: apdev name %s already exists\n",
+ dev->name, ndev->name);
+ kfree(ndev);
+ return ret;
+ }
+ sdata->u.ap.apdev = ndev;
+ nsdata->u.ap.apdev = dev;
+ return 0;
+}
+
+static void ieee80211_if_del_apdev(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct net_device *apdev;
+
+ ASSERT_RTNL();
+ apdev = sdata->u.ap.apdev;
+ unregister_netdevice(apdev);
+}
+
+int ieee80211_if_set_type(struct net_device *dev, int type)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ int res = 0;
sdata->type = type;
switch (type) {
@@ -104,7 +160,11 @@ void ieee80211_if_set_type(struct net_de
sdata->u.ap.max_ratectrl_rateidx = -1;
skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
sdata->bss = &sdata->u.ap;
- break;
+ res = ieee80211_if_add_apdev(dev);
+ if (!res)
+ break;
+ sdata->type = IEEE80211_IF_TYPE_STA;
+ /* fallback to STA, but keep error value in `res' */
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS: {
struct ieee80211_sub_if_data *msdata;
@@ -131,7 +191,9 @@ void ieee80211_if_set_type(struct net_de
default:
printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
dev->name, __FUNCTION__, type);
+ res = -EINVAL;
}
+ return res;
}
/* Must be called with rtnl lock held. */
@@ -183,6 +245,8 @@ #endif
local->total_ps_buffered--;
dev_kfree_skb(skb);
}
+
+ ieee80211_if_del_apdev(dev);
}
break;
@@ -257,8 +321,7 @@ int ieee80211_if_remove(struct net_devic
list_for_each_entry_safe(sdata, n, &local->sub_if_list, list) {
if ((sdata->type == id || id == -1) &&
strcmp(name, sdata->dev->name) == 0 &&
- sdata->dev != local->mdev &&
- sdata->dev != local->apdev) {
+ sdata->dev != local->mdev) {
__ieee80211_if_del(local, sdata);
return 0;
}
@@ -270,7 +333,7 @@ void ieee80211_if_free(struct net_device
{
struct ieee80211_local *local = dev->priv;
- BUG_ON(dev == local->mdev || dev == local->apdev);
+ BUG_ON(dev == local->mdev);
kfree(dev);
}
--
1.3.0
^ permalink raw reply related
* [PATCH 7/10] d80211: get rid of default AP interface
From: Jiri Benc @ 2006-04-21 20:53 UTC (permalink / raw)
To: netdev
In-Reply-To: <20060421225314.048983000.midnight@suse.cz>
There is no need for default non-removable AP interface (wlanX), it just
confuses users. This patch removes it and renames master interface from
wlanX.11 to wlanX.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 78 +++++++++---------------------------------
net/d80211/ieee80211_i.h | 3 +-
net/d80211/ieee80211_iface.c | 3 +-
net/d80211/ieee80211_ioctl.c | 12 +++---
net/d80211/ieee80211_proc.c | 8 ++--
5 files changed, 27 insertions(+), 77 deletions(-)
11da4bbdb5dd3f83a991f9e8df2d2356606b87b4
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index ad63bab..2386454 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -2032,7 +2032,7 @@ static int ieee80211_open(struct net_dev
struct net_device *ndev = nsdata->dev;
if (ndev != dev && ndev != local->mdev &&
- ndev != local->wdev && ndev != local->apdev &&
+ ndev != local->apdev &&
netif_running(ndev) &&
memcmp(dev->dev_addr, ndev->dev_addr, ETH_ALEN) == 0 &&
!identical_mac_addr_allowed(sdata->type, nsdata->type)) {
@@ -3684,7 +3684,7 @@ static void ieee80211_tasklet_handler(un
break;
default: /* should never get here! */
printk(KERN_ERR "%s: Unknown message type (%d)\n",
- local->wdev->name, skb->pkt_type);
+ local->mdev->name, skb->pkt_type);
dev_kfree_skb(skb);
break;
}
@@ -3979,7 +3979,7 @@ static void ieee80211_if_init(struct net
}
-/* Must not be called for wdev, mdev and apdev */
+/* Must not be called for mdev and apdev */
void ieee80211_if_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -4018,7 +4018,7 @@ static void ieee80211_precalc_rates(stru
struct net_device *ieee80211_alloc_hw(size_t priv_data_len,
void (*setup)(struct net_device *))
{
- struct net_device *dev, *apdev, *mdev;
+ struct net_device *apdev, *mdev;
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
int alloc_size;
@@ -4042,10 +4042,6 @@ struct net_device *ieee80211_alloc_hw(si
* 17c0 *****************
* * sub_if *
* *****************
- * * master net_dev*
- * *****************
- * * sub_if *
- * *****************
*/
alloc_size = sizeof(struct net_device) +
sizeof(struct ieee80211_sub_if_data) + 3 +
@@ -4053,8 +4049,6 @@ struct net_device *ieee80211_alloc_hw(si
priv_data_len + 3 +
sizeof(struct net_device) + 3 +
sizeof(struct ieee80211_sub_if_data) + 3 +
- sizeof(struct net_device) + 3 +
- sizeof(struct ieee80211_sub_if_data) + 3 +
4096;
mdev = (struct net_device *) kzalloc(alloc_size, GFP_KERNEL);
if (mdev == NULL)
@@ -4069,29 +4063,14 @@ struct net_device *ieee80211_alloc_hw(si
((char *) local + ((sizeof(struct ieee80211_local) + 3) & ~3));
apdev = (struct net_device *)
((char *) local->hw_priv + ((priv_data_len + 3) & ~3));
- dev = (struct net_device *)
- ((char *) apdev +
- ((sizeof(struct net_device) + 3) & ~3) +
- ((sizeof(struct ieee80211_sub_if_data) + 3) & ~3));
- dev->priv = local;
- ether_setup(dev);
- memcpy(dev->name, "wlan%d", 7);
+ ether_setup(mdev);
+ memcpy(mdev->name, "wlan%d", 7);
- dev->hard_start_xmit = ieee80211_subif_start_xmit;
- dev->wireless_handlers =
- (struct iw_handler_def *) &ieee80211_iw_handler_def;
- dev->do_ioctl = ieee80211_ioctl;
- dev->change_mtu = ieee80211_change_mtu;
- dev->tx_timeout = ieee80211_tx_timeout;
- dev->get_stats = ieee80211_get_stats;
- dev->open = ieee80211_open;
- dev->stop = ieee80211_stop;
- dev->tx_queue_len = 0;
- dev->set_mac_address = ieee80211_set_mac_address;
+ if (strlen(mdev->name) + 2 >= sizeof(mdev->name))
+ goto fail;
local->dev_index = -1;
- local->wdev = dev;
local->mdev = mdev;
local->rx_handlers = ieee80211_rx_handlers;
local->tx_handlers = ieee80211_tx_handlers;
@@ -4119,22 +4098,11 @@ struct net_device *ieee80211_alloc_hw(si
init_timer(&local->stat_timer);
local->stat_timer.function = ieee80211_stat_refresh;
local->stat_timer.data = (unsigned long) local;
- ieee80211_rx_bss_list_init(dev);
+ ieee80211_rx_bss_list_init(mdev);
sta_info_init(local);
- ieee80211_if_init(dev);
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- sdata->dev = dev;
- sdata->master = mdev;
- sdata->local = local;
- ieee80211_if_sdata_init(sdata);
- ieee80211_if_set_type(dev, IEEE80211_IF_TYPE_AP);
- list_add_tail(&sdata->list, &local->sub_if_list);
-
- if (strlen(dev->name) + 2 >= sizeof(dev->name))
- goto fail;
+ ieee80211_if_init(mdev);
apdev = (struct net_device *)
((char *) local->hw_priv + ((priv_data_len + 3) & ~3));
@@ -4149,7 +4117,7 @@ struct net_device *ieee80211_alloc_hw(si
apdev->type = ARPHRD_IEEE80211_PRISM;
apdev->hard_header_parse = header_parse_80211;
apdev->tx_queue_len = 0;
- sprintf(apdev->name, "%sap", dev->name);
+ sprintf(apdev->name, "%sap", mdev->name);
sdata = IEEE80211_DEV_TO_SUB_IF(apdev);
sdata->type = IEEE80211_IF_TYPE_MGMT;
@@ -4158,7 +4126,6 @@ struct net_device *ieee80211_alloc_hw(si
sdata->local = local;
list_add_tail(&sdata->list, &local->sub_if_list);
- ether_setup(mdev);
mdev->hard_start_xmit = ieee80211_master_start_xmit;
mdev->wireless_handlers =
(struct iw_handler_def *) &ieee80211_iw_handler_def;
@@ -4170,7 +4137,6 @@ struct net_device *ieee80211_alloc_hw(si
mdev->stop = ieee80211_master_stop;
mdev->type = ARPHRD_IEEE80211;
mdev->hard_header_parse = header_parse_80211;
- sprintf(mdev->name, "%s.11", dev->name);
sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
sdata->type = IEEE80211_IF_TYPE_AP;
@@ -4226,19 +4192,15 @@ int ieee80211_register_hw(struct net_dev
sta_info_start(local);
- result = register_netdev(local->wdev);
- if (result < 0)
- goto fail_1st_dev;
-
result = register_netdev(local->apdev);
if (result < 0)
- goto fail_2nd_dev;
+ goto fail_1st_dev;
if (hw->fraglist)
dev->features |= NETIF_F_FRAGLIST;
result = register_netdev(dev);
if (result < 0)
- goto fail_3rd_dev;
+ goto fail_2nd_dev;
if (rate_control_initialize(local) < 0) {
printk(KERN_DEBUG "%s: Failed to initialize rate control "
@@ -4255,10 +4217,8 @@ int ieee80211_register_hw(struct net_dev
fail_rate:
unregister_netdev(dev);
-fail_3rd_dev:
- unregister_netdev(local->apdev);
fail_2nd_dev:
- unregister_netdev(local->wdev);
+ unregister_netdev(local->apdev);
fail_1st_dev:
sta_info_stop(local);
ieee80211_unregister_sysfs(local);
@@ -4284,12 +4244,6 @@ int ieee80211_update_hw(struct net_devic
local->apdev->mem_start = dev->mem_start;
local->apdev->mem_end = dev->mem_end;
- memcpy(local->wdev->dev_addr, dev->dev_addr, ETH_ALEN);
- local->wdev->base_addr = dev->base_addr;
- local->wdev->irq = dev->irq;
- local->wdev->mem_start = dev->mem_start;
- local->wdev->mem_end = dev->mem_end;
-
if (!hw->modes || !hw->modes->channels || !hw->modes->rates ||
!hw->modes->num_channels || !hw->modes->num_rates)
return -1;
@@ -4470,14 +4424,14 @@ static int rate_control_initialize(struc
local->rate_ctrl_priv = rate_control_alloc(local);
if (local->rate_ctrl_priv) {
printk(KERN_DEBUG "%s: Selected rate control "
- "algorithm '%s'\n", local->wdev->name,
+ "algorithm '%s'\n", local->mdev->name,
local->rate_ctrl->name);
return 0;
}
}
printk(KERN_WARNING "%s: Failed to select rate control algorithm\n",
- local->wdev->name);
+ local->mdev->name);
return -1;
}
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 98c30ff..77517c9 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -316,8 +316,7 @@ #define IEEE80211_SUB_IF_TO_DEV(sub_if)
struct ieee80211_local {
struct ieee80211_hw *hw;
void *hw_priv;
- struct net_device *mdev; /* wlan#.11 - "master" 802.11 device */
- struct net_device *wdev; /* wlan# - default Ethernet (data) devide */
+ struct net_device *mdev; /* wlan# - "master" 802.11 device */
struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
int open_count;
int monitors;
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 42ea643..58fd946 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -258,7 +258,6 @@ int ieee80211_if_remove(struct net_devic
if ((sdata->type == id || id == -1) &&
strcmp(name, sdata->dev->name) == 0 &&
sdata->dev != local->mdev &&
- sdata->dev != local->wdev &&
sdata->dev != local->apdev) {
__ieee80211_if_del(local, sdata);
return 0;
@@ -271,7 +270,7 @@ void ieee80211_if_free(struct net_device
{
struct ieee80211_local *local = dev->priv;
- BUG_ON(dev == local->mdev || dev == local->wdev || dev == local->apdev);
+ BUG_ON(dev == local->mdev || dev == local->apdev);
kfree(dev);
}
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 3eaad0a..1d3f5cf 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -499,13 +499,11 @@ static int ieee80211_set_encryption(stru
* must be used. This should be done automatically
* based on configured station devices. For the time
* being, this can be only set at compile time. */
- if (sdata->type == IEEE80211_IF_TYPE_STA) {
- if (0 /* FIX: more than one STA per AP */)
- try_hwaccel = 0;
- } else
- if (sdata->type != IEEE80211_IF_TYPE_AP ||
- dev != local->wdev)
- try_hwaccel = 0;
+ /* FIXME: There is no more anything like "default
+ * interface". We should try hwaccel if there is just one
+ * interface - for now, hwaccel is unconditionaly
+ * disabled. */
+ try_hwaccel = 0;
} else {
set_tx_key = 0;
if (idx != 0) {
diff --git a/net/d80211/ieee80211_proc.c b/net/d80211/ieee80211_proc.c
index a886280..c9f5567 100644
--- a/net/d80211/ieee80211_proc.c
+++ b/net/d80211/ieee80211_proc.c
@@ -702,7 +702,7 @@ void ieee80211_proc_init_interface(struc
if (!ieee80211_proc)
return;
- local->proc = proc_mkdir(local->wdev->name, ieee80211_proc);
+ local->proc = proc_mkdir(local->mdev->name, ieee80211_proc);
if (!local->proc)
return;
@@ -722,7 +722,7 @@ void ieee80211_proc_init_interface(struc
ieee80211_proc_debug_read, local);
create_proc_read_entry("info", 0, local->proc,
ieee80211_proc_info_read, local);
- ieee80211_proc_init_virtual(local->wdev);
+ ieee80211_proc_init_virtual(local->mdev);
}
@@ -731,7 +731,7 @@ void ieee80211_proc_deinit_interface(str
if (!local->proc)
return;
- ieee80211_proc_deinit_virtual(local->wdev);
+ ieee80211_proc_deinit_virtual(local->mdev);
remove_proc_entry("iface", local->proc);
remove_proc_entry("sta", local->proc);
remove_proc_entry("counters", local->proc);
@@ -742,7 +742,7 @@ void ieee80211_proc_deinit_interface(str
remove_proc_entry("multicast", local->proc);
remove_proc_entry("info", local->proc);
local->proc = NULL;
- remove_proc_entry(local->wdev->name, ieee80211_proc);
+ remove_proc_entry(local->mdev->name, ieee80211_proc);
}
--
1.3.0
^ permalink raw reply related
* [PATCH 6/10] d80211: per-interface generic_elem
From: Jiri Benc @ 2006-04-21 20:53 UTC (permalink / raw)
To: netdev
In-Reply-To: <20060421225314.048983000.midnight@suse.cz>
Allow generic element to be set independently for each interface.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
include/net/d80211.h | 12 +++++++-----
net/d80211/ieee80211.c | 6 ++++--
net/d80211/ieee80211_i.h | 2 ++
net/d80211/ieee80211_iface.c | 1 +
net/d80211/ieee80211_ioctl.c | 19 ++++++++++---------
5 files changed, 24 insertions(+), 16 deletions(-)
330ee7fb14673a5c69000a2c31c83830d7c6c456
diff --git a/include/net/d80211.h b/include/net/d80211.h
index 065b34c..4bdbdbe 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -249,11 +249,6 @@ struct ieee80211_conf {
int short_slot_time:1; /* use IEEE 802.11g Short Slot Time */
int ssid_hidden:1; /* do not broadcast the ssid */
- /* these fields are used by low level drivers for hardware
- * that generate beacons independently */
- u8 *generic_elem;
- size_t generic_elem_len;
-
u8 power_level; /* transmit power limit for current
* regulatory domain; in dBm */
u8 antenna_max; /* maximum antenna gain */
@@ -347,6 +342,11 @@ struct ieee80211_if_init_conf {
* config_interface() callback (so copy the value somewhere if you need
* it).
* @ssid_len: length of the @ssid field.
+ * @generic_elem: used (together with @generic_elem_len) by drivers for
+ * hardware that generate beacons independently. The pointer is valid
+ * only during config_interface() callback (so copy the value somewhere
+ * if you need it).
+ * @generic_elem_len: length of the generic element.
*
* This structure is passed to config_interface() callback of
* &struct ieee80211_hw.
@@ -356,6 +356,8 @@ struct ieee80211_if_conf {
u8 *bssid;
u8 *ssid;
size_t ssid_len;
+ u8 *generic_elem;
+ size_t generic_elem_len;
};
typedef enum { ALG_NONE, ALG_WEP, ALG_TKIP, ALG_CCMP, ALG_NULL }
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 984c2b0..ad63bab 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1764,9 +1764,13 @@ int ieee80211_if_config(struct net_devic
conf.bssid = sdata->u.sta.bssid;
conf.ssid = sdata->u.sta.ssid;
conf.ssid_len = sdata->u.sta.ssid_len;
+ conf.generic_elem = sdata->u.sta.extra_ie;
+ conf.generic_elem_len = sdata->u.sta.extra_ie_len;
} else if (sdata->type == IEEE80211_IF_TYPE_AP) {
conf.ssid = sdata->u.ap.ssid;
conf.ssid_len = sdata->u.ap.ssid_len;
+ conf.generic_elem = sdata->u.ap.generic_elem;
+ conf.generic_elem_len = sdata->u.ap.generic_elem_len;
}
return local->hw->config_interface(local->mdev, dev->ifindex, &conf);
}
@@ -4342,8 +4346,6 @@ void ieee80211_unregister_hw(struct net_
kfree(local->basic_rates[i]);
}
- kfree(local->conf.generic_elem);
-
ieee80211_proc_deinit_interface(local);
if (skb_queue_len(&local->skb_queue)
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index e78beb2..98c30ff 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -194,6 +194,8 @@ struct ieee80211_if_ap {
u8 ssid[IEEE80211_MAX_SSID_LEN];
size_t ssid_len;
+ u8 *generic_elem;
+ size_t generic_elem_len;
/* TODO: sta_aid could be replaced by 2008-bit large bitfield of
* that could be used in TIM element generation. This would also
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index dd809c2..42ea643 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -175,6 +175,7 @@ #endif
kfree(sdata->u.ap.beacon_head);
kfree(sdata->u.ap.beacon_tail);
+ kfree(sdata->u.ap.generic_elem);
if (dev != local->mdev) {
struct sk_buff *skb;
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 6b73e27..3eaad0a 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -1137,7 +1137,6 @@ #endif
static int ieee80211_set_gen_ie(struct net_device *dev, u8 *ie, size_t len)
{
- struct ieee80211_local *local = dev->priv;
struct ieee80211_sub_if_data *sdata;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1145,14 +1144,16 @@ static int ieee80211_set_gen_ie(struct n
sdata->type == IEEE80211_IF_TYPE_IBSS)
return ieee80211_sta_set_extra_ie(dev, ie, len);
- kfree(local->conf.generic_elem);
- local->conf.generic_elem = kmalloc(len, GFP_KERNEL);
- if (local->conf.generic_elem == NULL)
- return -ENOMEM;
- memcpy(local->conf.generic_elem, ie, len);
- local->conf.generic_elem_len = len;
-
- return ieee80211_hw_config(dev);
+ if (sdata->type == IEEE80211_IF_TYPE_AP) {
+ kfree(sdata->u.ap.generic_elem);
+ sdata->u.ap.generic_elem = kmalloc(len, GFP_KERNEL);
+ if (sdata->u.ap.generic_elem == NULL)
+ return -ENOMEM;
+ memcpy(sdata->u.ap.generic_elem, ie, len);
+ sdata->u.ap.generic_elem_len = len;
+ return ieee80211_if_config(dev);
+ }
+ return -EOPNOTSUPP;
}
--
1.3.0
^ permalink raw reply related
* [PATCH 5/10] d80211: per-interface SSID
From: Jiri Benc @ 2006-04-21 20:53 UTC (permalink / raw)
To: netdev
In-Reply-To: <20060421225314.048983000.midnight@suse.cz>
Allow SSID to be set independently for each interface.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
include/net/d80211.h | 9 ++++++--
net/d80211/ieee80211.c | 6 ++++-
net/d80211/ieee80211_i.h | 3 +++
net/d80211/ieee80211_ioctl.c | 47 +++++++++++++++++++++++++-----------------
4 files changed, 43 insertions(+), 22 deletions(-)
41fbbdfe8770f3492f888fcd459b2f9d2d615b0b
diff --git a/include/net/d80211.h b/include/net/d80211.h
index 3943e30..065b34c 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -251,8 +251,6 @@ struct ieee80211_conf {
/* these fields are used by low level drivers for hardware
* that generate beacons independently */
- u8 *ssid;
- size_t ssid_len;
u8 *generic_elem;
size_t generic_elem_len;
@@ -344,6 +342,11 @@ struct ieee80211_if_init_conf {
* during the live of the interface; this field is present only for
* convenience.
* @bssid: BSSID of the network we are associated to/creating.
+ * @ssid: used (together with @ssid_len) by drivers for hardware that
+ * generate beacons independently. The pointer is valid only during
+ * config_interface() callback (so copy the value somewhere if you need
+ * it).
+ * @ssid_len: length of the @ssid field.
*
* This structure is passed to config_interface() callback of
* &struct ieee80211_hw.
@@ -351,6 +354,8 @@ struct ieee80211_if_init_conf {
struct ieee80211_if_conf {
int type;
u8 *bssid;
+ u8 *ssid;
+ size_t ssid_len;
};
typedef enum { ALG_NONE, ALG_WEP, ALG_TKIP, ALG_CCMP, ALG_NULL }
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 425bd51..984c2b0 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1762,6 +1762,11 @@ int ieee80211_if_config(struct net_devic
if (sdata->type == IEEE80211_IF_TYPE_STA ||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
conf.bssid = sdata->u.sta.bssid;
+ conf.ssid = sdata->u.sta.ssid;
+ conf.ssid_len = sdata->u.sta.ssid_len;
+ } else if (sdata->type == IEEE80211_IF_TYPE_AP) {
+ conf.ssid = sdata->u.ap.ssid;
+ conf.ssid_len = sdata->u.ap.ssid_len;
}
return local->hw->config_interface(local->mdev, dev->ifindex, &conf);
}
@@ -4337,7 +4342,6 @@ void ieee80211_unregister_hw(struct net_
kfree(local->basic_rates[i]);
}
- kfree(local->conf.ssid);
kfree(local->conf.generic_elem);
ieee80211_proc_deinit_interface(local);
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index b29a5e8..e78beb2 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -192,6 +192,9 @@ struct ieee80211_if_ap {
u8 *beacon_head, *beacon_tail;
int beacon_head_len, beacon_tail_len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ size_t ssid_len;
+
/* TODO: sta_aid could be replaced by 2008-bit large bitfield of
* that could be used in TIM element generation. This would also
* make TIM element generation a bit faster. */
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 792fcf4..6b73e27 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -1746,7 +1746,6 @@ static int ieee80211_ioctl_siwessid(stru
struct iw_request_info *info,
struct iw_point *data, char *ssid)
{
- struct ieee80211_local *local = dev->priv;
struct ieee80211_sub_if_data *sdata;
size_t len = data->length;
@@ -1759,14 +1758,14 @@ static int ieee80211_ioctl_siwessid(stru
sdata->type == IEEE80211_IF_TYPE_IBSS)
return ieee80211_sta_set_ssid(dev, ssid, len);
- kfree(local->conf.ssid);
- local->conf.ssid = kmalloc(len + 1, GFP_KERNEL);
- if (local->conf.ssid == NULL)
- return -ENOMEM;
- memcpy(local->conf.ssid, ssid, len);
- local->conf.ssid[len] = '\0';
- local->conf.ssid_len = len;
- return ieee80211_hw_config(dev);
+ if (sdata->type == IEEE80211_IF_TYPE_AP) {
+ memcpy(sdata->u.ap.ssid, ssid, len);
+ memset(sdata->u.ap.ssid + len, 0,
+ IEEE80211_MAX_SSID_LEN - len);
+ sdata->u.ap.ssid_len = len;
+ return ieee80211_if_config(dev);
+ }
+ return -EOPNOTSUPP;
}
@@ -1774,7 +1773,6 @@ static int ieee80211_ioctl_giwessid(stru
struct iw_request_info *info,
struct iw_point *data, char *ssid)
{
- struct ieee80211_local *local = dev->priv;
size_t len;
struct ieee80211_sub_if_data *sdata;
@@ -1790,13 +1788,16 @@ static int ieee80211_ioctl_giwessid(stru
return res;
}
- len = local->conf.ssid_len;
- if (len > IW_ESSID_MAX_SIZE)
- len = IW_ESSID_MAX_SIZE;
- memcpy(ssid, local->conf.ssid, len);
- data->length = len;
- data->flags = 1;
- return 0;
+ if (sdata->type == IEEE80211_IF_TYPE_AP) {
+ len = sdata->u.ap.ssid_len;
+ if (len > IW_ESSID_MAX_SIZE)
+ len = IW_ESSID_MAX_SIZE;
+ memcpy(ssid, sdata->u.ap.ssid, len);
+ data->length = len;
+ data->flags = 1;
+ return 0;
+ }
+ return -EOPNOTSUPP;
}
@@ -1848,12 +1849,20 @@ static int ieee80211_ioctl_siwscan(struc
struct iw_point *data, char *extra)
{
struct ieee80211_local *local = dev->priv;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
u8 *ssid = NULL;
size_t ssid_len = 0;
if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
- ssid = local->conf.ssid;
- ssid_len = local->conf.ssid_len;
+ if (sdata->type == IEEE80211_IF_TYPE_STA ||
+ sdata->type == IEEE80211_IF_TYPE_IBSS) {
+ ssid = sdata->u.sta.ssid;
+ ssid_len = sdata->u.sta.ssid_len;
+ } else if (sdata == IEEE80211_IF_TYPE_AP) {
+ ssid = sdata->u.ap.ssid;
+ ssid_len = sdata->u.ap.ssid_len;
+ } else
+ return -EINVAL;
}
return ieee80211_sta_req_scan(dev, ssid, ssid_len);
}
--
1.3.0
^ permalink raw reply related
* [PATCH 3/10] d80211: fix Oops caused by packets sent directly to master device
From: Jiri Benc @ 2006-04-21 20:53 UTC (permalink / raw)
To: netdev
In-Reply-To: <20060421225314.048983000.midnight@suse.cz>
Sending packets to master interface directly causes dereferencing of pointer
containing random data. The same problem happens when originating virtual
interface is removed while a packet is queued.
We really shouldn't store pointer to ieee80211_sub_if_data in skb->cb. Store
ifindex there instead.
Also, there is no need for internal ieee80211_tx_packet_data structure to be
declared in d80211.h. As this patch touches this structure anyway, let's
move it to ieee80211_i.h.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
include/net/d80211.h | 11 -----
net/d80211/ieee80211.c | 89 +++++++++++++++++++++++++++++++++++---------
net/d80211/ieee80211_i.h | 12 ++++++
net/d80211/ieee80211_sta.c | 3 +
net/d80211/wme.c | 2 -
5 files changed, 85 insertions(+), 32 deletions(-)
8d3a2dea3e4cefad23f3dad3e2eeeb5bdcff3dbb
diff --git a/include/net/d80211.h b/include/net/d80211.h
index 23bcbfa..e44e21c 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -188,17 +188,6 @@ struct ieee80211_tx_control {
struct ieee80211_sub_if_data *sdata; /* internal */
};
-/* Stored in sk_buff->cb */
-struct ieee80211_tx_packet_data {
- struct ieee80211_sub_if_data *sdata;
- unsigned long jiffies;
- unsigned int req_tx_status:1;
- unsigned int do_not_encrypt:1;
- unsigned int pkt_probe_resp:1;
- unsigned int requeue:1;
- unsigned int queue:4;
-};
-
#define RX_FLAG_MMIC_ERROR 0x1
#define RX_FLAG_DECRYPTED 0x2
#define RX_FLAG_XR_DOUBLE_CHIRP 0x4
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index eb701ac..f768de5 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1051,23 +1051,21 @@ ieee80211_tx_h_ps_buf(struct ieee80211_t
}
-static void inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
- struct sk_buff *skb,
- struct net_device *dev,
- struct ieee80211_tx_control *control)
+static void inline
+__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
+ struct sk_buff *skb,
+ struct net_device *dev,
+ struct ieee80211_tx_control *control)
{
struct ieee80211_local *local = dev->priv;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- struct ieee80211_tx_packet_data *pkt_data;
int hdrlen;
- pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-
memset(tx, 0, sizeof(*tx));
tx->skb = skb;
- tx->dev = pkt_data->sdata->dev; /* use original interface */
+ tx->dev = dev; /* use original interface */
tx->local = local;
- tx->sdata = pkt_data->sdata;
+ tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
tx->sta = sta_info_get(local, hdr->addr1);
tx->fc = le16_to_cpu(hdr->frame_control);
control->power_level = local->conf.power_level;
@@ -1095,6 +1093,37 @@ static void inline ieee80211_tx_prepare(
}
+/* FIXME: This is not nice but currently there doesn't exist more elegant way */
+static int inline is_ieee80211_device(struct net_device *dev)
+{
+ return (dev->wireless_handlers ==
+ (struct iw_handler_def *) &ieee80211_iw_handler_def);
+}
+
+/* Device in tx->dev has a reference added; use dev_put(tx->dev) when
+ * finished with it. */
+static void inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
+ struct sk_buff *skb,
+ struct net_device *mdev,
+ struct ieee80211_tx_control *control)
+{
+ struct ieee80211_tx_packet_data *pkt_data;
+ struct net_device *dev;
+
+ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+ dev = dev_get_by_index(pkt_data->ifindex);
+ if (unlikely(dev && !is_ieee80211_device(dev))) {
+ dev_put(dev);
+ dev = NULL;
+ }
+ if (unlikely(!dev)) {
+ printk(KERN_WARNING "%s: NULL ifindex in pkt_data\n",
+ mdev->name);
+ dev = mdev;
+ dev_hold(dev);
+ }
+ __ieee80211_tx_prepare(tx, skb, dev, control);
+}
static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
struct ieee80211_tx_control *control, int mgmt)
@@ -1111,7 +1140,7 @@ static int ieee80211_tx(struct net_devic
return 0;
}
- ieee80211_tx_prepare(&tx, skb, dev, control);
+ __ieee80211_tx_prepare(&tx, skb, dev, control);
sta = tx.sta;
tx.u.tx.mgmt_interface = mgmt;
@@ -1136,8 +1165,8 @@ static int ieee80211_tx(struct net_devic
return 0;
}
- ieee80211_dump_frame(dev->name, "TX to low-level driver", skb);
- ret = local->hw->tx(dev, skb, control);
+ ieee80211_dump_frame(local->mdev->name, "TX to low-level driver", skb);
+ ret = local->hw->tx(local->mdev, skb, control);
#ifdef IEEE80211_LEDS
if (!ret && local->tx_led_counter++ == 0) {
ieee80211_tx_led(1, dev);
@@ -1177,9 +1206,9 @@ #endif /* IEEE80211_LEDS */
dur = ieee80211_duration(&tx, 0, next_len);
hdr->duration_id = cpu_to_le16(dur);
- ieee80211_dump_frame(dev->name,
+ ieee80211_dump_frame(local->mdev->name,
"TX to low-level driver", skb);
- ret = local->hw->tx(dev, tx.u.tx.extra_frag[i],
+ ret = local->hw->tx(local->mdev, tx.u.tx.extra_frag[i],
control);
if (ret > 0)
goto drop;
@@ -1212,6 +1241,7 @@ static int ieee80211_master_start_xmit(s
{
struct ieee80211_tx_control control;
struct ieee80211_tx_packet_data *pkt_data;
+ struct net_device *odev = NULL;
struct ieee80211_sub_if_data *sdata;
int ret;
@@ -1222,7 +1252,23 @@ static int ieee80211_master_start_xmit(s
*/
pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
memset(&control, 0, sizeof(struct ieee80211_tx_control));
- control.sdata = pkt_data->sdata;
+
+ if (pkt_data->ifindex)
+ odev = dev_get_by_index(pkt_data->ifindex);
+ if (unlikely(odev && !is_ieee80211_device(odev))) {
+ dev_put(odev);
+ odev = NULL;
+ }
+ if (unlikely(!odev)) {
+#ifdef CONFIG_D80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: Discarded packet with nonexistent "
+ "originating device\n", dev->name);
+#endif
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ control.sdata = IEEE80211_DEV_TO_SUB_IF(dev);
control.req_tx_status = pkt_data->req_tx_status;
control.do_not_encrypt = pkt_data->do_not_encrypt;
control.pkt_type =
@@ -1230,8 +1276,9 @@ static int ieee80211_master_start_xmit(s
control.requeue = pkt_data->requeue;
control.queue = pkt_data->queue;
- ret = ieee80211_tx(dev, skb, &control,
+ ret = ieee80211_tx(odev, skb, &control,
control.sdata->type == IEEE80211_IF_TYPE_MGMT);
+ dev_put(odev);
return ret;
}
@@ -1401,7 +1448,8 @@ #endif
pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
- pkt_data->sdata = sdata;
+ pkt_data->ifindex = sdata->dev->ifindex;
+ pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
pkt_data->do_not_encrypt = no_encrypt;
skb->dev = sdata->master;
@@ -1452,7 +1500,8 @@ ieee80211_mgmt_start_xmit(struct sk_buff
pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
- pkt_data->sdata = sdata;
+ pkt_data->ifindex = sdata->dev->ifindex;
+ pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP)
@@ -1680,6 +1729,7 @@ ieee80211_get_buffered_bc(struct net_dev
if (res == TXRX_DROP || res == TXRX_QUEUED)
break;
}
+ dev_put(tx.dev);
if (res == TXRX_DROP) {
I802_DEBUG_INC(local->tx_handlers_drop);
@@ -3644,7 +3694,8 @@ static void ieee80211_remove_tx_extra(st
struct ieee80211_tx_packet_data *pkt_data;
pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- pkt_data->sdata = control->sdata;
+ pkt_data->ifindex = control->sdata->dev->ifindex;
+ pkt_data->mgmt_iface = (control->sdata->type == IEEE80211_IF_TYPE_MGMT);
pkt_data->req_tx_status = control->req_tx_status;
pkt_data->do_not_encrypt = control->do_not_encrypt;
pkt_data->pkt_probe_resp = (control->pkt_type == PKT_PROBE_RESP);
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 400c675..b29a5e8 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -143,6 +143,18 @@ #ifdef CONFIG_HOSTAPD_WPA_TESTING
#endif /* CONFIG_HOSTAPD_WPA_TESTING */
};
+/* Stored in sk_buff->cb */
+struct ieee80211_tx_packet_data {
+ int ifindex;
+ unsigned long jiffies;
+ unsigned int req_tx_status:1;
+ unsigned int do_not_encrypt:1;
+ unsigned int pkt_probe_resp:1;
+ unsigned int requeue:1;
+ unsigned int queue:4;
+ unsigned int mgmt_iface:1;
+};
+
struct ieee80211_passive_scan {
unsigned int in_scan:1; /* this must be cleared before calling
* netif_oper(WAKEUP) */
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index d9c3d67..2720f1d 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -399,7 +399,8 @@ static void ieee80211_sta_tx(struct net_
pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
- pkt_data->sdata = sdata;
+ pkt_data->ifindex = sdata->dev->ifindex;
+ pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
pkt_data->do_not_encrypt = !encrypt;
if (probe_resp)
pkt_data->pkt_probe_resp = 1;
diff --git a/net/d80211/wme.c b/net/d80211/wme.c
index 51a197a..f20d3e0 100644
--- a/net/d80211/wme.c
+++ b/net/d80211/wme.c
@@ -190,7 +190,7 @@ static inline int classify80211(struct s
return IEEE80211_TX_QUEUE_DATA0;
}
- if (unlikely(pkt_data->sdata->type == IEEE80211_IF_TYPE_MGMT)) {
+ if (unlikely(pkt_data->mgmt_iface)) {
/* Data frames from hostapd (mainly, EAPOL) use AC_VO
* and they will include QoS control fields if
* the target STA is using WME. */
--
1.3.0
^ permalink raw reply related
* [PATCH 4/10] d80211: don't use pointer in ieee80211_tx_control
From: Jiri Benc @ 2006-04-21 20:53 UTC (permalink / raw)
To: netdev
In-Reply-To: <20060421225314.048983000.midnight@suse.cz>
A problem similar to the one with ieee80211_sub_if_data and skb->cb happens
to ieee80211_sub_if_data and ieee80211_tx_control. When originating
interface is removed while packet is sent to the driver, bad things will
happen. Use ifindex instead.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
include/net/d80211.h | 3 ++-
net/d80211/ieee80211.c | 12 +++++++-----
2 files changed, 9 insertions(+), 6 deletions(-)
2f1956069a10abdc9a1d4f38ba413ae511428224
diff --git a/include/net/d80211.h b/include/net/d80211.h
index e44e21c..3943e30 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -185,7 +185,8 @@ struct ieee80211_tx_control {
* struct ieee80211_rate). To be used to limit
* packet dropping when probing higher rates, if hw
* supports multiple retry rates. -1 = not used */
- struct ieee80211_sub_if_data *sdata; /* internal */
+ int type; /* internal */
+ int ifindex; /* internal */
};
#define RX_FLAG_MMIC_ERROR 0x1
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index f768de5..425bd51 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1242,7 +1242,7 @@ static int ieee80211_master_start_xmit(s
struct ieee80211_tx_control control;
struct ieee80211_tx_packet_data *pkt_data;
struct net_device *odev = NULL;
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata, *osdata;
int ret;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1267,8 +1267,10 @@ #endif
dev_kfree_skb(skb);
return 0;
}
+ osdata = IEEE80211_DEV_TO_SUB_IF(odev);
- control.sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ control.ifindex = odev->ifindex;
+ control.type = osdata->type;
control.req_tx_status = pkt_data->req_tx_status;
control.do_not_encrypt = pkt_data->do_not_encrypt;
control.pkt_type =
@@ -1277,7 +1279,7 @@ #endif
control.queue = pkt_data->queue;
ret = ieee80211_tx(odev, skb, &control,
- control.sdata->type == IEEE80211_IF_TYPE_MGMT);
+ control.type == IEEE80211_IF_TYPE_MGMT);
dev_put(odev);
return ret;
@@ -3694,8 +3696,8 @@ static void ieee80211_remove_tx_extra(st
struct ieee80211_tx_packet_data *pkt_data;
pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- pkt_data->ifindex = control->sdata->dev->ifindex;
- pkt_data->mgmt_iface = (control->sdata->type == IEEE80211_IF_TYPE_MGMT);
+ pkt_data->ifindex = control->ifindex;
+ pkt_data->mgmt_iface = (control->type == IEEE80211_IF_TYPE_MGMT);
pkt_data->req_tx_status = control->req_tx_status;
pkt_data->do_not_encrypt = control->do_not_encrypt;
pkt_data->pkt_probe_resp = (control->pkt_type == PKT_PROBE_RESP);
--
1.3.0
^ permalink raw reply related
* [PATCH 2/10] d80211: use is_multicast_ether_addr
From: Jiri Benc @ 2006-04-21 20:53 UTC (permalink / raw)
To: netdev
In-Reply-To: <20060421225314.048983000.midnight@suse.cz>
Replace custom MULTICAST_ADDR macro with is_multicast_ether_addr function.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 29 +++++++++++++++--------------
net/d80211/ieee80211_i.h | 2 --
2 files changed, 15 insertions(+), 16 deletions(-)
f01885676fc8b7adb838b110b4f6449cbb17dae5
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 64cc66f..eb701ac 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -731,7 +731,7 @@ ieee80211_tx_h_misc(struct ieee80211_txr
u16 dur;
struct ieee80211_tx_control *control = tx->u.tx.control;
- if (!MULTICAST_ADDR(hdr->addr1)) {
+ if (!is_multicast_ether_addr(hdr->addr1)) {
if (tx->skb->len >= tx->local->rts_threshold &&
tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) {
control->use_rts_cts = 1;
@@ -766,7 +766,7 @@ ieee80211_tx_h_misc(struct ieee80211_txr
/* Setup duration field for the first fragment of the frame. Duration
* for remaining fragments will be updated when they are being sent
* to low-level driver in ieee80211_tx(). */
- dur = ieee80211_duration(tx, MULTICAST_ADDR(hdr->addr1),
+ dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
tx->fragmented ? tx->u.tx.extra_frag[0]->len :
0);
hdr->duration_id = cpu_to_le16(dur);
@@ -1072,8 +1072,8 @@ static void inline ieee80211_tx_prepare(
tx->fc = le16_to_cpu(hdr->frame_control);
control->power_level = local->conf.power_level;
tx->u.tx.control = control;
- tx->u.tx.unicast = !MULTICAST_ADDR(hdr->addr1);
- control->no_ack = MULTICAST_ADDR(hdr->addr1);
+ tx->u.tx.unicast = !is_multicast_ether_addr(hdr->addr1);
+ control->no_ack = is_multicast_ether_addr(hdr->addr1);
tx->fragmented = local->fragmentation_threshold <
IEEE80211_MAX_FRAG_THRESHOLD && tx->u.tx.unicast &&
skb->len + 4 /* FCS */ > local->fragmentation_threshold &&
@@ -2229,7 +2229,7 @@ ieee80211_rx_h_data(struct ieee80211_txr
if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP
|| sdata->type == IEEE80211_IF_TYPE_VLAN)) {
- if (MULTICAST_ADDR(skb->data)) {
+ if (is_multicast_ether_addr(skb->data)) {
/* send multicast frames both to higher layers in
* local net stack and back to the wireless media */
skb2 = skb_copy(skb, GFP_ATOMIC);
@@ -2659,7 +2659,8 @@ ieee80211_rx_h_defragment(struct ieee802
frag = WLAN_GET_SEQ_FRAG(sc);
if (likely((!(rx->fc & WLAN_FC_MOREFRAG) && frag == 0) ||
- (rx->skb)->len < 24 || MULTICAST_ADDR(hdr->addr1))) {
+ (rx->skb)->len < 24 ||
+ is_multicast_ether_addr(hdr->addr1))) {
/* not fragmented */
goto out;
}
@@ -2747,7 +2748,7 @@ ieee80211_rx_h_defragment(struct ieee802
out:
if (rx->sta)
rx->sta->rx_packets++;
- if (MULTICAST_ADDR(hdr->addr1))
+ if (is_multicast_ether_addr(hdr->addr1))
rx->local->dot11MulticastReceivedFrameCount++;
#ifdef IEEE80211_LEDS
else
@@ -2778,7 +2779,7 @@ ieee80211_rx_h_check(struct ieee80211_tx
hdr = (struct ieee80211_hdr *) rx->skb->data;
/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
- if (rx->sta && !MULTICAST_ADDR(hdr->addr1)) {
+ if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
if (unlikely(rx->fc & WLAN_FC_RETRY &&
rx->sta->last_seq_ctrl[rx->u.rx.queue] ==
hdr->seq_ctrl)) {
@@ -2900,7 +2901,7 @@ ieee80211_rx_h_sta_process(struct ieee80
if (memcmp(bssid, rx->sdata->u.sta.bssid, ETH_ALEN) == 0)
sta->last_rx = jiffies;
} else
- if (!MULTICAST_ADDR(hdr->addr1) ||
+ if (!is_multicast_ether_addr(hdr->addr1) ||
rx->sdata->type == IEEE80211_IF_TYPE_STA) {
/* Update last_rx only for unicast frames in order to prevent
* the Probe Request frames (the only broadcast frames from a
@@ -3415,7 +3416,7 @@ ieee80211_tx_h_load_stats(struct ieee802
hdrtime = CHAN_UTIL_HDR_LONG;
load = hdrtime;
- if (!MULTICAST_ADDR(hdr->addr1))
+ if (!is_multicast_ether_addr(hdr->addr1))
load += hdrtime;
if (tx->u.tx.control->use_rts_cts)
@@ -3481,7 +3482,7 @@ ieee80211_rx_h_load_stats(struct ieee802
hdrtime = CHAN_UTIL_HDR_LONG;
load = hdrtime;
- if (!MULTICAST_ADDR(hdr->addr1))
+ if (!is_multicast_ether_addr(hdr->addr1))
load += hdrtime;
load += skb->len * rate->rate_inv;
@@ -3792,7 +3793,7 @@ #endif /* IEEE80211_LEDS */
if (status->ack) {
if (frag == 0) {
local->dot11TransmittedFrameCount++;
- if (MULTICAST_ADDR(hdr->addr1))
+ if (is_multicast_ether_addr(hdr->addr1))
local->dot11MulticastTransmittedFrameCount++;
if (status->retry_count > 0)
local->dot11RetryCount++;
@@ -3804,8 +3805,8 @@ #endif /* IEEE80211_LEDS */
* with an individual address in the address 1 field or an MPDU
* with a multicast address in the address 1 field of type Data
* or Management. */
- if (!MULTICAST_ADDR(hdr->addr1) || type == WLAN_FC_TYPE_DATA ||
- type == WLAN_FC_TYPE_MGMT)
+ if (!is_multicast_ether_addr(hdr->addr1) ||
+ type == WLAN_FC_TYPE_DATA || type == WLAN_FC_TYPE_MGMT)
local->dot11TransmittedFragmentCount++;
} else {
if (frag == 0)
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 2dbb132..400c675 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -50,8 +50,6 @@ #define MAC2STR(a) ((a)[0] & 0xff), ((a)
((a)[3] & 0xff), ((a)[4] & 0xff), ((a)[5] & 0xff)
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MULTICAST_ADDR(a) ((a)[0] & 0x01)
-
/* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent
* reception of at least three fragmented frames. This limit can be increased
--
1.3.0
^ permalink raw reply related
* [PATCH 1/10] d80211: fix SIOCGIWESSID ioctl
From: Jiri Benc @ 2006-04-21 20:53 UTC (permalink / raw)
To: netdev
In-Reply-To: <20060421225314.048983000.midnight@suse.cz>
Flags for SIOCGIWESSID ioctl were not set, thus SSID was never displayed by
iwconfig.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211_ioctl.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
56d18689a4964cc2e906cfb5164b31649735774a
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index dfa0ef7..792fcf4 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -1782,8 +1782,11 @@ static int ieee80211_ioctl_giwessid(stru
if (sdata->type == IEEE80211_IF_TYPE_STA ||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
int res = ieee80211_sta_get_ssid(dev, ssid, &len);
- if (res == 0)
+ if (res == 0) {
data->length = len;
+ data->flags = 1;
+ } else
+ data->flags = 0;
return res;
}
@@ -1792,6 +1795,7 @@ static int ieee80211_ioctl_giwessid(stru
len = IW_ESSID_MAX_SIZE;
memcpy(ssid, local->conf.ssid, len);
data->length = len;
+ data->flags = 1;
return 0;
}
--
1.3.0
^ permalink raw reply related
* [PATCH 0/10] d80211: bugfixes and reducing number of interfaces
From: Jiri Benc @ 2006-04-21 20:53 UTC (permalink / raw)
To: netdev
Following patches can be also obtained from:
git://git.kernel.org/pub/scm/linux/kernel/git/jbenc/dscape.git master
The main purpose of these patches is to reduce the number of network
interfaces presented to userspace; there are also some important bugfixes
among them (mainly 3rd patch).
Jiri Benc:
d80211: fix SIOCGIWESSID ioctl
d80211: use is_multicast_ether_addr
d80211: fix Oops caused by packets sent directly to master device
d80211: don't use pointer in ieee80211_tx_control
d80211: per-interface SSID
d80211: per-interface generic_elem
d80211: get rid of default AP interface
d80211: get rid of default management interface
d80211: rename master interface
d80211: add one default interface
include/net/d80211.h | 35 +--
net/d80211/ieee80211.c | 436 ++++++++++++++++++++++++-------------------
net/d80211/ieee80211_i.h | 34 ++-
net/d80211/ieee80211_iface.c | 96 ++++++++-
net/d80211/ieee80211_ioctl.c | 95 +++++----
net/d80211/ieee80211_proc.c | 9
net/d80211/ieee80211_sta.c | 3
net/d80211/ieee80211_sysfs.c | 3
net/d80211/wme.c | 3
9 files changed, 430 insertions(+), 284 deletions(-)
--
Jiri Benc
SUSE Labs
^ permalink raw reply
* Re: [PATCH 0/17] d80211 patches
From: Jiri Benc @ 2006-04-21 20:52 UTC (permalink / raw)
To: Michael Buesch; +Cc: netdev
In-Reply-To: <200604212252.08325.mb@bu3sch.de>
On Fri, 21 Apr 2006 22:52:08 +0200, Michael Buesch wrote:
> Can you please send your hacky patch for the bcm43xx
> to me, so I can come up with a clean one?
Sure, actually I planned to do it in a few minutes :-)
drivers/net/wireless/bcm43xx-d80211/bcm43xx.h | 1
drivers/net/wireless/bcm43xx-d80211/bcm43xx_main.c | 45 +++++++++++++++++++--
2 files changed, 42 insertions(+), 4 deletions(-)
--- dscape.orig/drivers/net/wireless/bcm43xx-d80211/bcm43xx.h
+++ dscape/drivers/net/wireless/bcm43xx-d80211/bcm43xx.h
@@ -721,6 +721,7 @@ struct bcm43xx_private {
/* Informational stuff. */
char nick[IW_ESSID_MAX_SIZE + 1];
u8 bssid[ETH_ALEN];
+ int interfaces;
/* encryption/decryption */
u16 security_offset;
--- dscape.orig/drivers/net/wireless/bcm43xx-d80211/bcm43xx_main.c
+++ dscape/drivers/net/wireless/bcm43xx-d80211/bcm43xx_main.c
@@ -4029,9 +4029,6 @@ static int bcm43xx_net_config(struct net
if (conf->channel != radio->channel)
bcm43xx_radio_selectchannel(bcm, conf->channel, 0);
- if (conf->mode != bcm->iw_mode)
- bcm43xx_set_iwmode(bcm, conf->mode);
-
if (conf->short_slot_time != bcm->short_slot) {
assert(phy->type == BCM43xx_PHYTYPE_G);
if (conf->short_slot_time)
@@ -4186,8 +4183,13 @@ static void bcm43xx_net_poll_controller(
static int bcm43xx_net_open(struct net_device *net_dev)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+ int res;
- return bcm43xx_init_board(bcm);
+ res = bcm43xx_init_board(bcm);
+ if (!res)
+ return res;
+ bcm43xx_set_iwmode(bcm, bcm->iw_mode);
+ return 0;
}
static int bcm43xx_net_stop(struct net_device *net_dev)
@@ -4202,6 +4204,39 @@ static int bcm43xx_net_stop(struct net_d
return 0;
}
+static int bcm43xx_add_interface(struct net_device *net_dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+
+ if (bcm->interfaces > 0)
+ return -ENOBUFS;
+ if (conf->type == IEEE80211_IF_TYPE_MNTR) {
+ bcm->iw_mode = IW_MODE_MONITOR;
+ } else {
+ if (memcmp(bcm->net_dev->dev_addr, conf->mac_addr, ETH_ALEN) != 0)
+ return -EADDRNOTAVAIL;
+ if (conf->type == IEEE80211_IF_TYPE_STA)
+ bcm->iw_mode = IW_MODE_INFRA;
+ else if (conf->type == IEEE80211_IF_TYPE_IBSS)
+ bcm->iw_mode = IW_MODE_ADHOC;
+ else if (conf->type == IEEE80211_IF_TYPE_AP)
+ bcm->iw_mode = IW_MODE_MASTER;
+ else
+ return -EOPNOTSUPP;
+ }
+ bcm->interfaces++;
+ return 0;
+}
+
+static void bcm43xx_remove_interface(struct net_device *net_dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+
+ bcm->interfaces--;
+}
+
/* Initialization of struct net_device, just after allocation. */
static void bcm43xx_netdev_setup(struct net_device *net_dev)
{
@@ -4276,6 +4311,8 @@ static int __devinit bcm43xx_init_one(st
ieee->tx = bcm43xx_net_hard_start_xmit;
ieee->open = bcm43xx_net_open;
ieee->stop = bcm43xx_net_stop;
+ ieee->add_interface = bcm43xx_add_interface;
+ ieee->remove_interface = bcm43xx_remove_interface;
ieee->reset = bcm43xx_net_reset;
ieee->config = bcm43xx_net_config;
//TODO ieee->set_key = bcm43xx_net_set_key;
--
Jiri Benc
SUSE Labs
^ permalink raw reply
* Re: [PATCH 16/17] d80211: fix monitor interfaces
From: Jiri Benc @ 2006-04-21 20:49 UTC (permalink / raw)
To: Johannes Berg; +Cc: netdev, John W. Linville
In-Reply-To: <1145651369.3897.33.camel@localhost>
On Fri, 21 Apr 2006 22:29:29 +0200, Johannes Berg wrote:
> On Fri, 2006-04-21 at 22:11 +0200, Jiri Benc wrote:
>
> > Also, "soft" and "hard" monitor modes are introduced.
>
> What's the distinction? The code might want some comments about what
> that
>
> > + /* Device is capable of performing full monitor mode even during
> > + * normal operation. */
>
> actually means. I suppose it means that the device will receive control
> frames too, but I don't know if that's right.
Some devices need to be switched to completely different mode to be able
to receive all frames (including control ones) or even load another
firmware. Such devices are not capable to transmit anything while in
monitor mode and their drivers won't set monitor_during_oper.
Another devices are capable to receive all frames while continuing their
normal operation. Driver will probably set monitor_during_oper in that
case.
"Hard" monitor mode means the card is operating in a true rfmon mode -
i.e. you get everything on the given channel. "Soft" monitor mode means
that you will get only frames the device is willing to give you at the
time - this probably means only frames belonging to your BSS in case of
fullmac cards.
So, you can always do
echo -n sta0 > /sys/class/ieee80211/wiphy0/add_iface
echo -n mon0 > /sys/class/ieee80211/wiphy0/add_iface
iwconfig sta0 mode managed
iwconfig mon0 mode monitor
ifconfig sta0 up
ifconfig mon0 up
and this will work - independently of the value of monitor_during_oper.
The difference is that in case of monitor_during_oper == 0, you won't
probably receive much more frames from mon0 than from sta0. But - you
will most likely receive beacons on mon0 and also monitoring headers
(prism2 headers presently).
When monitor_during_oper == 1, you are able to watch all traffic on the
current channel on mon0 without interrupting normal functionality.
--
Jiri Benc
SUSE Labs
^ permalink raw reply
* Re: [PATCH 0/17] d80211 patches
From: Michael Buesch @ 2006-04-21 20:52 UTC (permalink / raw)
To: Jiri Benc; +Cc: netdev, John W. Linville
In-Reply-To: <20060421220951.205579000.midnight@suse.cz>
[-- Attachment #1: Type: text/plain, Size: 290 bytes --]
On Friday 21 April 2006 22:11, you wrote:
> Please note that these changes break d80211 drivers.
Can you please send your hacky patch for the bcm43xx
to me, so I can come up with a clean one?
(I think you already sent it to me, but I lost it :) )
Thanks.
--
Greetings Michael.
[-- Attachment #2: Type: application/pgp-signature, Size: 191 bytes --]
^ permalink raw reply
* Re: e1000_down and tx_timeout worker race cleaning the transmit buffers
From: Andy Gospodarek @ 2006-04-21 20:46 UTC (permalink / raw)
To: Michael Chan
Cc: Herbert Xu, shawvrana, netdev, auke-jan.h.kok, davem, jgarzik
In-Reply-To: <1145646031.3843.5.camel@rh4>
On 4/21/06, Michael Chan <mchan@broadcom.com> wrote:
> On Fri, 2006-04-21 at 16:01 -0400, Andy Gospodarek wrote:
>
> > I just hate to see extra resources used to solve problems that good
> > coding can solve (not that my suggestion is necessarily a 'good' one),
> > so I was trying to think of a way to resolve this without explicitly
> > adding another workqueue.
>
> If you don't want to add another workqueue, then look at tg3, bnx2, and
> one of the smc drivers on how to effectively wait for the driver's
> workqueue task to finish without deadlocking with linkwatch_event.
>
I agree 100%. I just hope others can manage to figure that out too.
^ permalink raw reply
* [RFC] netdev sysfs failure handling
From: Stephen Hemminger @ 2006-04-21 20:42 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev
In case of sysfs failure, don't let device be brought up.
It can be cleared by unregister_netdevice so module can be unloaded
normally.
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
--- sky2-2.6.17.orig/net/core/dev.c 2006-04-21 12:21:45.000000000 -0700
+++ sky2-2.6.17/net/core/dev.c 2006-04-21 12:46:48.000000000 -0700
@@ -3043,10 +3043,17 @@
switch(dev->reg_state) {
case NETREG_REGISTERING:
+ /* Can't do proper error handling here because
+ * this is a delayed call after register_netdevice
+ * so no way to tell device driver what is wrong.
+ */
err = netdev_register_sysfs(dev);
- if (err)
+ if (err) {
printk(KERN_ERR "%s: failed sysfs registration (%d)\n",
dev->name, err);
+ /* Don't let device be brought up */
+ clear_bit(__LINK_STATE_PRESENT, &dev->state);
+ }
dev->reg_state = NETREG_REGISTERED;
break;
^ permalink raw reply
* Re: e1000_down and tx_timeout worker race cleaning the transmit buffers
From: Michael Chan @ 2006-04-21 19:00 UTC (permalink / raw)
To: Andy Gospodarek
Cc: Herbert Xu, shawvrana, netdev, auke-jan.h.kok, davem, jgarzik
In-Reply-To: <bdfc5d6e0604211301k682b35d1r52a52cd3fec80ddc@mail.gmail.com>
On Fri, 2006-04-21 at 16:01 -0400, Andy Gospodarek wrote:
> I just hate to see extra resources used to solve problems that good
> coding can solve (not that my suggestion is necessarily a 'good' one),
> so I was trying to think of a way to resolve this without explicitly
> adding another workqueue.
If you don't want to add another workqueue, then look at tg3, bnx2, and
one of the smc drivers on how to effectively wait for the driver's
workqueue task to finish without deadlocking with linkwatch_event.
^ permalink raw reply
* Re: [PATCH 16/17] d80211: fix monitor interfaces
From: Johannes Berg @ 2006-04-21 20:29 UTC (permalink / raw)
To: Jiri Benc; +Cc: netdev, John W. Linville
In-Reply-To: <20060421201147.D4F76482CF@silver.suse.cz>
[-- Attachment #1: Type: text/plain, Size: 437 bytes --]
On Fri, 2006-04-21 at 22:11 +0200, Jiri Benc wrote:
> Also, "soft" and "hard" monitor modes are introduced.
What's the distinction? The code might want some comments about what
that
> + /* Device is capable of performing full monitor mode even during
> + * normal operation. */
actually means. I suppose it means that the device will receive control
frames too, but I don't know if that's right.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 793 bytes --]
^ permalink raw reply
* [PATCH 17/17] d80211: fix AP interfaces
From: Jiri Benc @ 2006-04-21 20:11 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
In-Reply-To: <20060421220951.205579000.midnight@suse.cz>
This allows interfaces of IEEE80211_IF_TYPE_MGMT type (wlan%dap interfaces)
to be put UP.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
906a789aa674216a18ad5dc13c0635bc5664b793
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index b199b9e..64cc66f 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1893,6 +1893,8 @@ static inline int identical_mac_addr_all
{
return (type1 == IEEE80211_IF_TYPE_MNTR ||
type2 == IEEE80211_IF_TYPE_MNTR ||
+ type1 == IEEE80211_IF_TYPE_MGMT ||
+ type2 == IEEE80211_IF_TYPE_MGMT ||
(type1 == IEEE80211_IF_TYPE_AP &&
type2 == IEEE80211_IF_TYPE_WDS) ||
(type1 == IEEE80211_IF_TYPE_WDS &&
--
1.3.0
^ permalink raw reply related
* [PATCH 16/17] d80211: fix monitor interfaces
From: Jiri Benc @ 2006-04-21 20:11 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
In-Reply-To: <20060421220951.205579000.midnight@suse.cz>
This patch allows monitor interfaces to be set by SIOCSIWMODE and to receive
frames.
Also, "soft" and "hard" monitor modes are introduced.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
include/net/d80211.h | 10 ++++++
net/d80211/ieee80211.c | 67 ++++++++++++++++++++++++++++++++++++++++--
net/d80211/ieee80211_i.h | 1 +
net/d80211/ieee80211_iface.c | 7 ++++
4 files changed, 81 insertions(+), 4 deletions(-)
738241025b5e0091237d8c9d809d9affbdfaee29
diff --git a/include/net/d80211.h b/include/net/d80211.h
index 7bc66b5..23bcbfa 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -330,6 +330,8 @@ enum ieee80211_if_types {
* @if_id: internal interface ID. This number has no particular meaning to
* drivers and the only allowed usage is to pass it to
* ieee80211_beacon_get() and ieee80211_get_buffered_bc() functions.
+ * This field is not valid for monitor interfaces
+ * (interfaces of %IEEE80211_IF_TYPE_MNTR type).
* @type: one of &enum ieee80211_if_types constants. Determines the type of
* added/removed interface.
* @mac_addr: pointer to MAC address of the interface. This pointer is valid
@@ -476,6 +478,10 @@ struct ieee80211_hw {
*/
unsigned int device_strips_mic:1;
+ /* Device is capable of performing full monitor mode even during
+ * normal operation. */
+ unsigned int monitor_during_oper:1;
+
/* 1 = low-level driver supports skb fraglist (NETIF_F_FRAGLIST), i.e.,
* more than one skb per frame */
unsigned int fraglist;
@@ -511,7 +517,9 @@ struct ieee80211_hw {
* more exactly, set UP). If the handler returns zero, the interface
* is added. Driver should perform any initialization it needs prior
* to returning zero. By returning non-zero, adding of the interface
- * is not permitted. The open() handler is called after
+ * is not permitted. Unless monitor_during_oper is set, it is
+ * guaranteed that monitor interfaces and normal interfaces are
+ * mutually exclusive. The open() handler is called after
* add_interface() if this is the first device added. At least one
* of open() and add_interface() handler has to be non-NULL. If
* add_interface() is NULL, one STA interface is permitted only. */
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index e2a42af..b199b9e 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1891,7 +1891,9 @@ static struct net_device_stats *ieee8021
static inline int identical_mac_addr_allowed(int type1, int type2)
{
- return ((type1 == IEEE80211_IF_TYPE_AP &&
+ return (type1 == IEEE80211_IF_TYPE_MNTR ||
+ type2 == IEEE80211_IF_TYPE_MNTR ||
+ (type1 == IEEE80211_IF_TYPE_AP &&
type2 == IEEE80211_IF_TYPE_WDS) ||
(type1 == IEEE80211_IF_TYPE_WDS &&
(type2 == IEEE80211_IF_TYPE_WDS ||
@@ -1925,6 +1927,36 @@ static int ieee80211_master_stop(struct
return 0;
}
+/* Check if running monitor interfaces should go to a "soft monitor" mode
+ * and switch them if necessary. */
+static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local)
+{
+ struct ieee80211_if_init_conf conf;
+
+ if (local->open_count && local->open_count == local->monitors &&
+ !local->hw->monitor_during_oper && local->hw->remove_interface) {
+ conf.if_id = -1;
+ conf.type = IEEE80211_IF_TYPE_MNTR;
+ conf.mac_addr = NULL;
+ local->hw->remove_interface(local->mdev, &conf);
+ }
+}
+
+/* Check if running monitor interfaces should go to a "hard monitor" mode
+ * and switch them if necessary. */
+static void ieee80211_start_hard_monitor(struct ieee80211_local *local)
+{
+ struct ieee80211_if_init_conf conf;
+
+ if (local->open_count && local->open_count == local->monitors &&
+ !local->hw->monitor_during_oper && local->hw->add_interface) {
+ conf.if_id = -1;
+ conf.type = IEEE80211_IF_TYPE_MNTR;
+ conf.mac_addr = NULL;
+ local->hw->add_interface(local->mdev, &conf);
+ }
+}
+
static int ieee80211_open(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata, *nsdata;
@@ -1948,13 +1980,25 @@ static int ieee80211_open(struct net_dev
memcmp(sdata->u.wds.remote_addr, "\0\0\0\0\0\0", ETH_ALEN) == 0)
return -ENOLINK;
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count &&
+ !local->hw->monitor_during_oper) {
+ /* run the interface in a "soft monitor" mode */
+ local->monitors++;
+ local->open_count++;
+ return 0;
+ }
+ ieee80211_start_soft_monitor(local);
+
if (local->hw->add_interface) {
conf.if_id = dev->ifindex;
conf.type = sdata->type;
conf.mac_addr = dev->dev_addr;
res = local->hw->add_interface(sdata->master, &conf);
- if (res)
+ if (res) {
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+ ieee80211_start_hard_monitor(local);
return res;
+ }
} else {
if (sdata->type != IEEE80211_IF_TYPE_STA)
return -EOPNOTSUPP;
@@ -1980,6 +2024,9 @@ static int ieee80211_open(struct net_dev
}
local->open_count++;
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+ local->monitors++;
+
netif_start_queue(dev);
return 0;
}
@@ -1992,8 +2039,19 @@ static int ieee80211_stop(struct net_dev
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR &&
+ local->open_count > 1 && !local->hw->monitor_during_oper) {
+ /* remove "soft monitor" interface */
+ local->open_count--;
+ local->monitors--;
+ return 0;
+ }
+
netif_stop_queue(dev);
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+ local->monitors--;
+
local->open_count--;
if (local->open_count == 0) {
ieee80211_stop_scan(sdata->master);
@@ -2010,6 +2068,8 @@ static int ieee80211_stop(struct net_dev
local->hw->remove_interface(sdata->master, &conf);
}
+ ieee80211_start_hard_monitor(local);
+
return 0;
}
@@ -2242,7 +2302,8 @@ ieee80211_rx_mgmt(struct net_device *dev
size_t hlen;
struct ieee80211_sub_if_data *sdata;
- dev = local->apdev;
+ if (msg_type != ieee80211_msg_monitor)
+ dev = local->apdev;
skb->dev = dev;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 37d533d..2dbb132 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -305,6 +305,7 @@ struct ieee80211_local {
struct net_device *wdev; /* wlan# - default Ethernet (data) devide */
struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
int open_count;
+ int monitors;
struct ieee80211_conf conf;
int dev_index;
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 2151bd9..dd809c2 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -8,6 +8,7 @@
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
+#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
#include <net/d80211.h>
@@ -124,6 +125,9 @@ void ieee80211_if_set_type(struct net_de
sdata->bss = &msdata->u.ap;
break;
}
+ case IEEE80211_IF_TYPE_MNTR:
+ dev->type = ARPHRD_IEEE80211_PRISM;
+ break;
default:
printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
dev->name, __FUNCTION__, type);
@@ -211,6 +215,9 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
}
break;
+ case IEEE80211_IF_TYPE_MNTR:
+ dev->type = ARPHRD_ETHER;
+ break;
}
/* remove all STAs that are bound to this virtual interface */
--
1.3.0
^ permalink raw reply related
* [PATCH 15/17] d80211: fix handling of received frames
From: Jiri Benc @ 2006-04-21 20:11 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
In-Reply-To: <20060421220951.205579000.midnight@suse.cz>
Make sure that every frame reaches every interface it belongs to.
Previously, some packet (most notably multicast ones) were not delivered to
all interface they should be delivered to. This also allows monitor
interfaces to work easily, even together with regular interfaces.
On a typical setup (i.e. one or two interfaces only) this patch shouldn't
have significant impact on performance. However, on a setup with great
number of interfaces, things will probably slow down. This is not a problem
with design of this patch - things can be relatively easily sped up later.
See related comment in 'd80211: remove obsolete stuff' patch.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 338 +++++++++++++++++-------------------------------
1 files changed, 121 insertions(+), 217 deletions(-)
5aa4f5e0b7654f03d39977ac1212356d6b6f3fa7
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index fbca700..e2a42af 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -2020,73 +2020,10 @@ static int header_parse_80211(struct sk_
return ETH_ALEN;
}
-
-static struct net_device *
-ieee80211_get_wds_dev(struct ieee80211_local *local, u8 *addr)
+static inline int ieee80211_bssid_match(u8 *raddr, u8 *addr)
{
- struct list_head *ptr;
-
- list_for_each(ptr, &local->sub_if_list) {
- struct ieee80211_sub_if_data *sdata =
- list_entry(ptr, struct ieee80211_sub_if_data, list);
- if (sdata->type == IEEE80211_IF_TYPE_WDS &&
- memcmp(addr, sdata->u.wds.remote_addr, ETH_ALEN) == 0)
- return sdata->dev;
- }
-
- return NULL;
-}
-
-
-static struct net_device * ieee80211_own_bssid(struct ieee80211_local *local,
- u8 *addr)
-{
- struct net_device *dev = NULL;
- struct ieee80211_sub_if_data *sdata;
-
- spin_lock_bh(&local->sub_if_lock);
- list_for_each_entry(sdata, &local->sub_if_list, list) {
- if (sdata->type == IEEE80211_IF_TYPE_AP &&
- memcmp(addr, sdata->dev->dev_addr, ETH_ALEN) == 0) {
- dev = sdata->dev;
- break;
- }
- }
- spin_unlock_bh(&local->sub_if_lock);
-
- return dev;
-}
-
-
-static struct net_device * ieee80211_sta_bssid(struct ieee80211_local *local,
- u8 *addr, u8 *a1,
- int *sta_multicast)
-{
- struct list_head *ptr;
- int multicast;
-
- multicast = a1[0] & 0x01;
-
- /* Could not find station interface, resort to O(n) lookup. */
- list_for_each(ptr, &local->sub_if_list) {
- struct ieee80211_sub_if_data *sdata =
- list_entry(ptr, struct ieee80211_sub_if_data, list);
- if (sdata->type != IEEE80211_IF_TYPE_STA &&
- sdata->type != IEEE80211_IF_TYPE_IBSS)
- continue;
- if (!multicast &&
- memcmp(a1, sdata->dev->dev_addr, ETH_ALEN) != 0)
- continue;
-
- if (memcmp(addr, sdata->u.sta.bssid, ETH_ALEN) == 0 ||
- (memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0 &&
- sdata->type == IEEE80211_IF_TYPE_IBSS)) {
- *sta_multicast = multicast;
- return sdata->dev;
- }
- }
-
- return NULL;
+ return memcmp(raddr, addr, ETH_ALEN) == 0 ||
+ is_broadcast_ether_addr(raddr);
}
@@ -2128,8 +2065,7 @@ ieee80211_rx_h_data(struct ieee80211_txr
memcpy(dst, hdr->addr3, ETH_ALEN);
memcpy(src, hdr->addr2, ETH_ALEN);
- if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP ||
- !ieee80211_own_bssid(local, hdr->addr1))) {
+ if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP)) {
printk(KERN_DEBUG "%s: dropped ToDS frame (BSSID="
MACSTR " SA=" MACSTR " DA=" MACSTR ")\n",
dev->name, MAC2STR(hdr->addr1),
@@ -2142,8 +2078,7 @@ ieee80211_rx_h_data(struct ieee80211_txr
memcpy(dst, hdr->addr3, ETH_ALEN);
memcpy(src, hdr->addr4, ETH_ALEN);
- dev = ieee80211_get_wds_dev(local, hdr->addr2);
- if (!dev || memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) != 0) {
+ if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) {
printk(KERN_DEBUG "%s: dropped FromDS&ToDS frame (RA="
MACSTR " TA=" MACSTR " DA=" MACSTR " SA="
MACSTR ")\n",
@@ -2158,9 +2093,7 @@ ieee80211_rx_h_data(struct ieee80211_txr
memcpy(dst, hdr->addr1, ETH_ALEN);
memcpy(src, hdr->addr3, ETH_ALEN);
- if (sdata->type != IEEE80211_IF_TYPE_STA ||
- memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0 ||
- memcmp(hdr->addr2, sdata->u.sta.bssid, ETH_ALEN) != 0) {
+ if (sdata->type != IEEE80211_IF_TYPE_STA) {
return TXRX_DROP;
}
break;
@@ -2169,8 +2102,7 @@ ieee80211_rx_h_data(struct ieee80211_txr
memcpy(dst, hdr->addr1, ETH_ALEN);
memcpy(src, hdr->addr2, ETH_ALEN);
- if (sdata->type != IEEE80211_IF_TYPE_IBSS ||
- memcmp(hdr->addr3, sdata->u.sta.bssid, ETH_ALEN) != 0) {
+ if (sdata->type != IEEE80211_IF_TYPE_IBSS) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: dropped IBSS frame (DA="
MACSTR " SA=" MACSTR " BSSID=" MACSTR
@@ -2802,12 +2734,15 @@ ieee80211_rx_h_check(struct ieee80211_tx
return TXRX_DROP;
}
- /* Filter out foreign unicast packets when in promiscuous mode.
- * FIX: Filter out multicast to foreign BSSID. */
- if (rx->sdata->type == IEEE80211_IF_TYPE_STA &&
- !MULTICAST_ADDR(hdr->addr1) &&
- memcmp(rx->dev->dev_addr, hdr->addr1, ETH_ALEN) != 0)
- return TXRX_DROP;
+ if (memcmp(rx->dev->dev_addr, hdr->addr1, ETH_ALEN) == 0)
+ rx->skb->pkt_type = PACKET_HOST;
+ else if (is_multicast_ether_addr(hdr->addr1)) {
+ if (is_broadcast_ether_addr(hdr->addr1))
+ rx->skb->pkt_type = PACKET_BROADCAST;
+ else
+ rx->skb->pkt_type = PACKET_MULTICAST;
+ } else
+ rx->skb->pkt_type = PACKET_OTHERHOST;
/* Drop disallowed frame classes based on STA auth/assoc state;
* IEEE 802.11, Chap 5.5.
@@ -2840,17 +2775,6 @@ ieee80211_rx_h_check(struct ieee80211_tx
if (rx->sta && rx->sta->key && always_sta_key) {
rx->key = rx->sta->key;
} else {
- if (!rx->sdata) {
- printk(KERN_DEBUG "%s: sdata was null in packet!!\n",
- rx->dev->name);
- printk(KERN_DEBUG "%s: Addr1: " MACSTR "\n",
- rx->dev->name, MAC2STR(hdr->addr1));
- printk(KERN_DEBUG "%s: Addr2: " MACSTR "\n",
- rx->dev->name, MAC2STR(hdr->addr2));
- printk(KERN_DEBUG "%s: Addr3: " MACSTR "\n",
- rx->dev->name, MAC2STR(hdr->addr3));
- return TXRX_DROP;
- }
if (rx->sta && rx->sta->key)
rx->key = rx->sta->key;
else
@@ -3158,41 +3082,6 @@ static u8 * ieee80211_get_bssid(struct i
return NULL;
}
-
-static struct net_device * ieee80211_get_rx_dev(struct ieee80211_local *local,
- struct ieee80211_hdr *hdr,
- size_t len, int *sta_broadcast)
-{
- u8 *bssid;
- struct net_device *dev;
- u16 fc;
-
- bssid = ieee80211_get_bssid(hdr, len);
- if (bssid) {
- dev = ieee80211_own_bssid(local, bssid);
- if (!dev)
- dev = ieee80211_sta_bssid(local, bssid, hdr->addr1,
- sta_broadcast);
- if (dev)
- return dev;
- }
-
- if (len >= 30) {
- fc = le16_to_cpu(hdr->frame_control);
- if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
- (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
- (WLAN_FC_TODS | WLAN_FC_FROMDS)) {
- dev = ieee80211_get_wds_dev(local, hdr->addr2);
- if (dev)
- return dev;
- }
- }
-
- /* Default to default device if nothing else matches */
- return local->wdev;
-}
-
-
static void ieee80211_rx_michael_mic_report(struct net_device *dev,
struct ieee80211_hdr *hdr,
struct sta_info *sta,
@@ -3283,63 +3172,31 @@ static void ieee80211_rx_michael_mic_rep
rx->skb = NULL;
}
-
-static void ieee80211_sta_rx_broadcast(struct ieee80211_txrx_data *rx)
+static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local,
+ struct ieee80211_txrx_data *rx,
+ struct sta_info *sta)
{
- struct ieee80211_local *local = rx->dev->priv;
- u8 *_bssid, bssid[ETH_ALEN];
- struct sk_buff *orig_skb = rx->skb, *skb;
- struct ieee80211_hdr *hdr;
ieee80211_rx_handler *handler;
- ieee80211_txrx_result res;
- struct list_head *ptr;
-
- hdr = (struct ieee80211_hdr *) orig_skb->data;
- _bssid = ieee80211_get_bssid(hdr, orig_skb->len);
- if (_bssid == NULL) {
- dev_kfree_skb(orig_skb);
- return;
- }
- memcpy(bssid, _bssid, ETH_ALEN);
-
- list_for_each(ptr, &local->sub_if_list) {
- struct ieee80211_sub_if_data *sdata =
- list_entry(ptr, struct ieee80211_sub_if_data, list);
- if (sdata->type != IEEE80211_IF_TYPE_STA ||
- (memcmp(bssid, sdata->u.sta.bssid, ETH_ALEN) != 0 &&
- !(bssid[0] & 0x01)))
- continue;
+ ieee80211_txrx_result res = TXRX_DROP;
- skb = skb_copy(orig_skb, GFP_ATOMIC);
- if (skb == NULL) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: failed to copy "
- "multicast frame for %s",
- rx->dev->name, sdata->dev->name);
+ for (handler = local->rx_handlers; *handler != NULL; handler++) {
+ res = (*handler)(rx);
+ if (res != TXRX_CONTINUE) {
+ if (res == TXRX_DROP) {
+ I802_DEBUG_INC(local->rx_handlers_drop);
+ if (sta)
+ sta->rx_dropped++;
}
- continue;
- }
-
- hdr = (struct ieee80211_hdr *) skb->data;
- rx->skb = skb;
- rx->dev = sdata->dev;
- rx->sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
-
- res = TXRX_DROP;
- for (handler = local->rx_handlers; *handler != NULL; handler++)
- {
- res = (*handler)(rx);
- if (res == TXRX_DROP || res == TXRX_QUEUED)
- break;
+ if (res == TXRX_QUEUED)
+ I802_DEBUG_INC(local->rx_handlers_queued);
+ break;
}
-
- if (res == TXRX_DROP || *handler == NULL)
- dev_kfree_skb(skb);
}
- dev_kfree_skb(orig_skb);
-}
+ if (res == TXRX_DROP || *handler == NULL)
+ dev_kfree_skb(rx->skb);
+}
/*
* This is the receive path handler. It is called by a low level driver when an
@@ -3349,71 +3206,118 @@ void __ieee80211_rx(struct net_device *d
struct ieee80211_rx_status *status)
{
struct ieee80211_local *local = dev->priv;
+ struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
struct ieee80211_hdr *hdr;
- ieee80211_rx_handler *handler;
struct ieee80211_txrx_data rx;
- ieee80211_txrx_result res = TXRX_DROP;
u16 type;
- int sta_broadcast = 0;
+ int multicast;
hdr = (struct ieee80211_hdr *) skb->data;
memset(&rx, 0, sizeof(rx));
rx.skb = skb;
rx.local = local;
- if (skb->len >= 16)
- sta = rx.sta = sta_info_get(local, hdr->addr2);
- else
- sta = rx.sta = NULL;
- if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS)) {
- rx.dev = sta->dev;
- rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
- } else {
- rx.dev = ieee80211_get_rx_dev(local, hdr, skb->len,
- &sta_broadcast);
- rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
- if (sta == NULL &&
- rx.sdata->type == IEEE80211_IF_TYPE_IBSS) {
- u8 *bssid = ieee80211_get_bssid(hdr, skb->len);
- if (bssid)
- sta = rx.sta =
- ieee80211_ibss_add_sta(dev, skb, bssid,
- hdr->addr2);
- }
- }
rx.u.rx.status = status;
rx.fc = skb->len >= 2 ? le16_to_cpu(hdr->frame_control) : 0;
type = WLAN_FC_GET_TYPE(rx.fc);
if (type == WLAN_FC_TYPE_DATA || type == WLAN_FC_TYPE_MGMT)
local->dot11ReceivedFragmentCount++;
- if (sta_broadcast) {
- ieee80211_sta_rx_broadcast(&rx);
- goto end;
- }
+ multicast = is_multicast_ether_addr(hdr->addr1);
+
+ if (skb->len >= 16)
+ sta = rx.sta = sta_info_get(local, hdr->addr2);
+ else
+ sta = rx.sta = NULL;
if ((status->flag & RX_FLAG_MMIC_ERROR)) {
ieee80211_rx_michael_mic_report(dev, hdr, sta, &rx);
goto end;
}
- for (handler = local->rx_handlers; *handler != NULL; handler++) {
- res = (*handler)(&rx);
- if (res != TXRX_CONTINUE) {
- if (res == TXRX_DROP) {
- I802_DEBUG_INC(local->rx_handlers_drop);
- if (sta)
- sta->rx_dropped++;
+ if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) &&
+ !local->iff_promiscs && !multicast) {
+ rx.dev = sta->dev;
+ rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
+ ieee80211_invoke_rx_handlers(local, &rx, sta);
+ } else {
+ struct ieee80211_sub_if_data *prev = NULL;
+ struct sk_buff *skb_new;
+ u8 *bssid = ieee80211_get_bssid(hdr, skb->len);
+
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ switch (sdata->type) {
+ case IEEE80211_IF_TYPE_STA:
+ if (!bssid || memcmp(sdata->u.sta.bssid,
+ bssid, ETH_ALEN) != 0)
+ continue;
+ if (!multicast && !sdata->promisc &&
+ memcmp(sdata->dev->dev_addr, hdr->addr1,
+ ETH_ALEN) != 0)
+ continue;
+ break;
+ case IEEE80211_IF_TYPE_IBSS:
+ if (!bssid ||
+ !ieee80211_bssid_match(bssid,
+ sdata->u.sta.bssid))
+ continue;
+ if (!multicast && !sdata->promisc &&
+ memcmp(sdata->dev->dev_addr, hdr->addr1,
+ ETH_ALEN) != 0)
+ continue;
+ if (sta == NULL) {
+ sta = rx.sta =
+ ieee80211_ibss_add_sta(dev, skb, bssid,
+ hdr->addr2);
+ /* FIXME: call with sdata->dev */
+ }
+ break;
+ case IEEE80211_IF_TYPE_AP:
+ if (!bssid) {
+ if (memcmp(sdata->dev->dev_addr,
+ hdr->addr1, ETH_ALEN) != 0)
+ continue;
+ } else if (!local->sta_scanning &&
+ !local->scan.in_scan &&
+ !ieee80211_bssid_match(bssid,
+ sdata->dev->dev_addr))
+ continue;
+ break;
+ case IEEE80211_IF_TYPE_WDS:
+ if (bssid ||
+ WLAN_FC_GET_TYPE(rx.fc) != WLAN_FC_TYPE_DATA)
+ continue;
+ if (memcmp(sdata->u.wds.remote_addr,
+ hdr->addr2, ETH_ALEN) != 0)
+ continue;
+ break;
}
- if (res == TXRX_QUEUED)
- I802_DEBUG_INC(local->rx_handlers_queued);
- break;
+
+ if (prev) {
+ skb_new = skb_copy(skb, GFP_ATOMIC);
+ if (skb_new == NULL) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: failed to copy "
+ "multicast frame for %s",
+ dev->name, prev->dev->name);
+ }
+ continue;
+ }
+ rx.skb = skb_new;
+ rx.dev = prev->dev;
+ rx.sdata = prev;
+ ieee80211_invoke_rx_handlers(local, &rx, sta);
+ }
+ prev = sdata;
}
+ if (prev) {
+ rx.skb = skb;
+ rx.dev = prev->dev;
+ rx.sdata = prev;
+ ieee80211_invoke_rx_handlers(local, &rx, sta);
+ } else
+ dev_kfree_skb(skb);
}
- skb = rx.skb; /* handlers are allowed to change skb */
-
- if (res == TXRX_DROP || *handler == NULL)
- dev_kfree_skb(skb);
end:
if (sta)
--
1.3.0
^ permalink raw reply related
* [PATCH 14/17] d80211: set_multicast_list
From: Jiri Benc @ 2006-04-21 20:11 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
In-Reply-To: <20060421220951.205579000.midnight@suse.cz>
Add set_multicast_list callback. The version of set_multicast_list in
struct net_device cannot be used by a driver, because the driver is
interested in cumulative flags and cumulative multicast list from all
interfaces.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
include/net/d80211.h | 24 ++++++++++++++
net/d80211/ieee80211.c | 71 ++++++++++++++++++++++++++++++++++++++++++
net/d80211/ieee80211_i.h | 8 +++++
net/d80211/ieee80211_iface.c | 1 +
4 files changed, 104 insertions(+), 0 deletions(-)
9ada6736d81619ac81ea1ce283f47c365fe3b24f
diff --git a/include/net/d80211.h b/include/net/d80211.h
index 6894745..7bc66b5 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -532,6 +532,13 @@ struct ieee80211_hw {
int (*config_interface)(struct net_device *dev, int if_id,
struct ieee80211_if_conf *conf);
+ /* ieee80211 drivers should use this and not the function in
+ * net_device. dev->flags, dev->mc_count and dev->mc_list must not
+ * be used; use passed parameters and ieee80211_get_mc_list_item()
+ * instead. */
+ void (*set_multicast_list)(struct net_device *dev,
+ unsigned short flags, int mc_count);
+
/* Set TIM bit handler. If the hardware/firmware takes care of beacon
* generation, IEEE 802.11 code uses this function to tell the
* low-level to set (or clear if set==0) TIM bit for the given aid. If
@@ -775,6 +782,23 @@ typedef enum {
} Netif_Oper;
int ieee80211_netif_oper(struct net_device *dev, Netif_Oper op);
+/**
+ * ieee80211_get_mc_list_item - iteration over items in multicast list
+ * @dev: pointer to &struct net_device as obtained from
+ * ieee80211_alloc_hw().
+ * @prev: value returned by previous call to ieee80211_get_mc_list_item() or
+ * NULL to start a new iteration.
+ * @ptr: pointer to buffer of void * type for internal usage of
+ * ieee80211_get_mc_list_item().
+ *
+ * Iterates over items in multicast list of given device. To get the first
+ * item, pass NULL in @prev and in *@ptr. In subsequent calls, pass the
+ * value returned by previous call in @prev. Don't alter *@ptr during
+ * iteration. When there are no more items, NULL is returned.
+ */
+struct dev_mc_list *ieee80211_get_mc_list_item(struct net_device *dev,
+ struct dev_mc_list *prev,
+ void **ptr);
/*
* Function to get hardware configuration information
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index ea71b6c..fbca700 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1812,6 +1812,75 @@ static int ieee80211_set_mac_address(str
return 0;
}
+static void ieee80211_set_multicast_list(struct net_device *dev)
+{
+ struct ieee80211_local *local = dev->priv;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ unsigned short flags;
+
+ if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) {
+ if (sdata->allmulti) {
+ sdata->allmulti = 0;
+ local->iff_allmultis--;
+ } else {
+ sdata->allmulti = 1;
+ local->iff_allmultis++;
+ }
+ }
+ if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) {
+ if (sdata->promisc) {
+ sdata->promisc = 0;
+ local->iff_promiscs--;
+ } else {
+ sdata->promisc = 1;
+ local->iff_promiscs++;
+ }
+ }
+ if (dev->mc_count != sdata->mc_count) {
+ local->mc_count = local->mc_count - sdata->mc_count +
+ dev->mc_count;
+ sdata->mc_count = dev->mc_count;
+ }
+ if (local->hw->set_multicast_list) {
+ flags = sdata->master->flags;
+ if (local->iff_allmultis)
+ flags |= IFF_ALLMULTI;
+ if (local->iff_promiscs)
+ flags |= IFF_PROMISC;
+ local->hw->set_multicast_list(sdata->master, flags,
+ local->mc_count);
+ }
+}
+
+struct dev_mc_list *ieee80211_get_mc_list_item(struct net_device *dev,
+ struct dev_mc_list *prev,
+ void **ptr)
+{
+ struct ieee80211_local *local = dev->priv;
+ struct ieee80211_sub_if_data *sdata = *ptr;
+ struct dev_mc_list *mc;
+
+ if (!prev) {
+ WARN_ON(sdata);
+ sdata = NULL;
+ }
+ if (!prev || !prev->next) {
+ if (sdata)
+ sdata = list_entry(sdata->list.next,
+ struct ieee80211_sub_if_data, list);
+ else
+ sdata = list_entry(local->sub_if_list.next,
+ struct ieee80211_sub_if_data, list);
+ if (&sdata->list != &local->sub_if_list)
+ mc = sdata->dev->mc_list;
+ else
+ mc = NULL;
+ } else
+ mc = prev->next;
+
+ *ptr = sdata;
+ return mc;
+}
static struct net_device_stats *ieee80211_get_stats(struct net_device *dev)
{
@@ -3889,6 +3958,7 @@ void ieee80211_if_setup(struct net_devic
(struct iw_handler_def *) &ieee80211_iw_handler_def;
dev->do_ioctl = ieee80211_ioctl;
dev->set_mac_address = ieee80211_set_mac_address;
+ dev->set_multicast_list = ieee80211_set_multicast_list;
dev->change_mtu = ieee80211_change_mtu;
dev->tx_timeout = ieee80211_tx_timeout;
dev->get_stats = ieee80211_get_stats;
@@ -4449,6 +4519,7 @@ EXPORT_SYMBOL(ieee80211_rate_control_unr
EXPORT_SYMBOL(sta_info_get);
EXPORT_SYMBOL(sta_info_release);
EXPORT_SYMBOL(ieee80211_radar_status);
+EXPORT_SYMBOL(ieee80211_get_mc_list_item);
module_init(ieee80211_init);
module_exit(ieee80211_exit);
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 5116a88..37d533d 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -264,6 +264,10 @@ struct ieee80211_sub_if_data {
struct net_device *master;
struct ieee80211_local *local;
+ int mc_count;
+ unsigned allmulti:1;
+ unsigned promisc:1;
+
struct net_device_stats stats;
int drop_unencrypted;
int eapol; /* 0 = process EAPOL frames as normal data frames,
@@ -327,6 +331,10 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12
struct sta_info *sta_hash[STA_HASH_SIZE];
struct timer_list sta_cleanup;
+ int mc_count; /* total count of multicast entries in all interfaces */
+ int iff_allmultis, iff_promiscs;
+ /* number of interfaces with corresponding IFF_ flags */
+
/* Current rate table. This is a pointer to hw->modes structure. */
struct ieee80211_rate *curr_rates;
int num_curr_rates;
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 917428e..2151bd9 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -62,6 +62,7 @@ int ieee80211_if_add(struct net_device *
ndev->irq = dev->irq;
ndev->mem_start = dev->mem_start;
ndev->mem_end = dev->mem_end;
+ ndev->flags = dev->flags & IFF_MULTICAST;
ieee80211_if_setup(ndev);
sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
--
1.3.0
^ permalink raw reply related
* [PATCH 13/17] d80211: master interface auto up/down
From: Jiri Benc @ 2006-04-21 20:11 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
In-Reply-To: <20060421220951.205579000.midnight@suse.cz>
There is no reason to put master interface to UP/DOWN state manually.
Calling of hw->open and hw->stop callbacks logically belongs to
ieee80211_master_open and ieee80211_master_stop functions, but then we need
to refuse putting master interface to UP state when there is no other
interface running, and similarly, to refuse putting master interface DOWN
when there are other interfaces running. Because the second is not possible,
hw->open and hw->stop need to be called from ieee80211_open/ieee80211_stop.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 57 +++++++++++++++++++++++++++++++++++++-----------
1 files changed, 44 insertions(+), 13 deletions(-)
e5df634b3ae1c945076820434d8dcf897c0eb574
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index c20cb00..ea71b6c 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1829,10 +1829,38 @@ static inline int identical_mac_addr_all
type2 == IEEE80211_IF_TYPE_AP)));
}
+static int ieee80211_master_open(struct net_device *dev)
+{
+ struct ieee80211_local *local = dev->priv;
+ struct ieee80211_sub_if_data *sdata;
+ int res = -EOPNOTSUPP;
+
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ if (sdata->dev != dev && netif_running(sdata->dev)) {
+ res = 0;
+ break;
+ }
+ }
+ return res;
+}
+
+static int ieee80211_master_stop(struct net_device *dev)
+{
+ struct ieee80211_local *local = dev->priv;
+ struct ieee80211_sub_if_data *sdata;
+
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ if (sdata->dev != dev && netif_running(sdata->dev))
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
static int ieee80211_open(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata, *nsdata;
struct ieee80211_local *local = dev->priv;
+ struct ieee80211_if_init_conf conf;
int res;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1852,8 +1880,6 @@ static int ieee80211_open(struct net_dev
return -ENOLINK;
if (local->hw->add_interface) {
- struct ieee80211_if_init_conf conf;
-
conf.if_id = dev->ifindex;
conf.type = sdata->type;
conf.mac_addr = dev->dev_addr;
@@ -1868,10 +1894,18 @@ static int ieee80211_open(struct net_dev
}
if (local->open_count == 0) {
- if (local->hw->open) {
+ res = 0;
+ if (local->hw->open)
res = local->hw->open(sdata->master);
- if (res)
- return res;
+ if (res == 0) {
+ res = dev_open(sdata->master);
+ if (res && local->hw->stop)
+ local->hw->stop(sdata->master);
+ }
+ if (res) {
+ if (local->hw->remove_interface)
+ local->hw->remove_interface(dev, &conf);
+ return res;
}
ieee80211_init_scan(sdata->master);
}
@@ -1886,7 +1920,6 @@ static int ieee80211_stop(struct net_dev
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_local *local = dev->priv;
- int res;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1895,11 +1928,9 @@ static int ieee80211_stop(struct net_dev
local->open_count--;
if (local->open_count == 0) {
ieee80211_stop_scan(sdata->master);
- if (local->hw->stop) {
- res = local->hw->stop(sdata->master);
- if (res)
- return res;
- }
+ dev_close(sdata->master);
+ if (local->hw->stop)
+ local->hw->stop(sdata->master);
}
if (local->hw->remove_interface) {
struct ieee80211_if_init_conf conf;
@@ -4035,8 +4066,8 @@ struct net_device *ieee80211_alloc_hw(si
mdev->change_mtu = ieee80211_change_mtu;
mdev->tx_timeout = ieee80211_tx_timeout;
mdev->get_stats = ieee80211_get_stats;
- mdev->open = ieee80211_open;
- mdev->stop = ieee80211_stop;
+ mdev->open = ieee80211_master_open;
+ mdev->stop = ieee80211_master_stop;
mdev->type = ARPHRD_IEEE80211;
mdev->hard_header_parse = header_parse_80211;
sprintf(mdev->name, "%s.11", dev->name);
--
1.3.0
^ permalink raw reply related
* [PATCH 12/17] d80211: interface types changeable by SIOCSIWMODE
From: Jiri Benc @ 2006-04-21 20:11 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
In-Reply-To: <20060421220951.205579000.midnight@suse.cz>
Allow type of interface to be set by SIOCSIWMODE. All of functions
responsible for adding/removing/initialization of interfaces were moved to
a new file ieee80211_iface.c. Function for removing interface was split into
two parts: one for deinitialization of the interface and one for
deallocation of the interface. That way, it is possible to change the type
of interface just by deinitializing and initializing it.
Also, remove set_mac_address callback to a driver, as it is not needed
anymore (drivers are notified about MAC addresses through add_interface
callback).
Please note, that although after this patch interfaces are fully independent
and driver can correctly control which combination is allowed, not all
multicast frames are received correctly by all respective interfaces. This
is addressed by subsequent patches.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
include/net/d80211.h | 3
net/d80211/Makefile | 1
net/d80211/ieee80211.c | 458 +++++-------------------------------------
net/d80211/ieee80211_i.h | 30 +--
net/d80211/ieee80211_iface.c | 289 +++++++++++++++++++++++++++
net/d80211/ieee80211_ioctl.c | 125 +++++++----
net/d80211/ieee80211_sysfs.c | 12 +
7 files changed, 435 insertions(+), 483 deletions(-)
create mode 100644 net/d80211/ieee80211_iface.c
ef162ee22ef1564f76a9d67b8df647993806e72d
diff --git a/include/net/d80211.h b/include/net/d80211.h
index 2ec31db..6894745 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -585,9 +585,6 @@ struct ieee80211_hw {
/* Configuration of test parameters */
int (*test_param)(struct net_device *dev, int param, int value);
- /* Change MAC address. addr is pointer to struct sockaddr. */
- int (*set_mac_address)(struct net_device *dev, void *addr);
-
/* For devices that generate their own beacons and probe response
* or association responses this updates the state of privacy_invoked
* returns 0 for success or an error number */
diff --git a/net/d80211/Makefile b/net/d80211/Makefile
index 59d1d65..66bfcff 100644
--- a/net/d80211/Makefile
+++ b/net/d80211/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_D80211) += 80211.o rate_con
ieee80211_scan.o \
ieee80211_sta.o \
ieee80211_dev.o \
+ ieee80211_iface.o \
ieee80211_sysfs.o \
michael.o \
tkip.o \
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 16a07d0..c20cb00 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1803,24 +1803,12 @@ static void ieee80211_tx_timeout(struct
static int ieee80211_set_mac_address(struct net_device *dev, void *addr)
{
- struct ieee80211_local *local = dev->priv;
struct sockaddr *a = addr;
- struct list_head *ptr;
- int res;
- if (!local->hw->set_mac_address)
- return -EOPNOTSUPP;
-
- res = local->hw->set_mac_address(dev, addr);
- if (res)
- return res;
-
- list_for_each(ptr, &local->sub_if_list) {
- struct ieee80211_sub_if_data *sdata =
- list_entry(ptr, struct ieee80211_sub_if_data, list);
- memcpy(sdata->dev->dev_addr, a->sa_data, ETH_ALEN);
- }
+ if (netif_running(dev))
+ return -EBUSY;
+ memcpy(dev->dev_addr, a->sa_data, ETH_ALEN);
return 0;
}
@@ -1832,14 +1820,37 @@ static struct net_device_stats *ieee8021
return &(sdata->stats);
}
+static inline int identical_mac_addr_allowed(int type1, int type2)
+{
+ return ((type1 == IEEE80211_IF_TYPE_AP &&
+ type2 == IEEE80211_IF_TYPE_WDS) ||
+ (type1 == IEEE80211_IF_TYPE_WDS &&
+ (type2 == IEEE80211_IF_TYPE_WDS ||
+ type2 == IEEE80211_IF_TYPE_AP)));
+}
static int ieee80211_open(struct net_device *dev)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata, *nsdata;
struct ieee80211_local *local = dev->priv;
int res;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ list_for_each_entry(nsdata, &local->sub_if_list, list) {
+ struct net_device *ndev = nsdata->dev;
+
+ if (ndev != dev && ndev != local->mdev &&
+ ndev != local->wdev && ndev != local->apdev &&
+ netif_running(ndev) &&
+ memcmp(dev->dev_addr, ndev->dev_addr, ETH_ALEN) == 0 &&
+ !identical_mac_addr_allowed(sdata->type, nsdata->type)) {
+ return -ENOTUNIQ;
+ }
+ }
+ if (sdata->type == IEEE80211_IF_TYPE_WDS &&
+ memcmp(sdata->u.wds.remote_addr, "\0\0\0\0\0\0", ETH_ALEN) == 0)
+ return -ENOLINK;
+
if (local->hw->add_interface) {
struct ieee80211_if_init_conf conf;
@@ -1849,6 +1860,11 @@ static int ieee80211_open(struct net_dev
res = local->hw->add_interface(sdata->master, &conf);
if (res)
return res;
+ } else {
+ if (sdata->type != IEEE80211_IF_TYPE_STA)
+ return -EOPNOTSUPP;
+ if (local->open_count > 0)
+ return -ENOBUFS;
}
if (local->open_count == 0) {
@@ -3800,128 +3816,6 @@ static ieee80211_tx_handler ieee80211_tx
};
-static void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
-{
- /* Default values for sub-interface parameters */
- sdata->drop_unencrypted = 0;
- sdata->eapol = 1;
-}
-
-
-static struct net_device *ieee80211_if_add(struct net_device *dev,
- const char *name, int locked)
-{
- struct net_device *wds_dev = NULL, *tmp_dev;
- struct ieee80211_local *local = dev->priv;
- struct ieee80211_sub_if_data *sdata = NULL, *sdata_parent;
- int alloc_size;
- int ret;
- int i;
-
- /* ensure 32-bit alignment of our private data and hw private data */
- alloc_size = sizeof(struct net_device) + 3 +
- sizeof(struct ieee80211_sub_if_data) + 3;
-
- wds_dev = (struct net_device *) kmalloc(alloc_size, GFP_KERNEL);
- if (wds_dev == NULL)
- return NULL;
-
- memset(wds_dev, 0, alloc_size);
- wds_dev->priv = local;
- ether_setup(wds_dev);
- if (strlen(name) == 0) {
- i = 0;
- do {
- sprintf(wds_dev->name, "%s.%d", dev->name, i++);
- tmp_dev = dev_get_by_name(wds_dev->name);
- if (tmp_dev == NULL)
- break;
- dev_put(tmp_dev);
- } while (i < 10000);
- } else {
- snprintf(wds_dev->name, IFNAMSIZ, "%s", name);
- }
-
- memcpy(wds_dev->dev_addr, dev->dev_addr, ETH_ALEN);
- wds_dev->hard_start_xmit = ieee80211_subif_start_xmit;
- wds_dev->wireless_handlers =
- (struct iw_handler_def *) &ieee80211_iw_handler_def;
- wds_dev->do_ioctl = ieee80211_ioctl;
- wds_dev->change_mtu = ieee80211_change_mtu;
- wds_dev->tx_timeout = ieee80211_tx_timeout;
- wds_dev->get_stats = ieee80211_get_stats;
- wds_dev->open = ieee80211_open;
- wds_dev->stop = ieee80211_stop;
- wds_dev->base_addr = dev->base_addr;
- wds_dev->irq = dev->irq;
- wds_dev->mem_start = dev->mem_start;
- wds_dev->mem_end = dev->mem_end;
- wds_dev->tx_queue_len = 0;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(wds_dev);
- sdata->type = IEEE80211_IF_TYPE_AP;
- sdata->master = local->mdev;
- sdata->dev = wds_dev;
- sdata->local = local;
- memset(&sdata->stats, 0, sizeof(struct net_device_stats));
- sdata_parent = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata_parent->type == IEEE80211_IF_TYPE_AP)
- sdata->bss = &sdata_parent->u.ap;
- else {
- printk(KERN_DEBUG "%s: could not set BSS pointer for new "
- "interface %s\n", dev->name, wds_dev->name);
- }
- ieee80211_if_sdata_init(sdata);
-
- if (locked)
- ret = register_netdevice(wds_dev);
- else
- ret = register_netdev(wds_dev);
- if (ret) {
- kfree(wds_dev);
- return NULL;
- }
-
- list_add(&sdata->list, &local->sub_if_list);
-
- return wds_dev;
-}
-
-
-int ieee80211_if_add_wds(struct net_device *dev, const char *name,
- struct ieee80211_if_wds *wds, int locked)
-{
- struct net_device *wds_dev = NULL;
- struct ieee80211_sub_if_data *sdata = NULL;
-
- if (strlen(name) != 0) {
- wds_dev = dev_get_by_name(name);
- if (wds_dev) {
- dev_put(wds_dev);
- return -EEXIST;
- }
- }
-
- wds_dev = ieee80211_if_add(dev, name, locked);
- if (wds_dev == NULL)
- return -ENOANO;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(wds_dev);
- sdata->type = IEEE80211_IF_TYPE_WDS;
- memcpy(&sdata->u.wds, wds, sizeof(struct ieee80211_if_wds));
-
-#ifdef CONFIG_D80211_VERBOSE_DEBUG
- printk(KERN_DEBUG
- "%s: Added WDS Link to " MACSTR "\n",
- wds_dev->name, MAC2STR(sdata->u.wds.remote_addr));
-#endif /* CONFIG_D80211_VERBOSE_DEBUG */
-
- ieee80211_proc_init_virtual(wds_dev);
-
- return 0;
-}
-
-
int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
{
struct ieee80211_local *local = dev->priv;
@@ -3955,274 +3849,22 @@ static void ieee80211_if_init(struct net
}
-int ieee80211_if_add_vlan(struct net_device *dev, const char *name,
- struct ieee80211_if_vlan *vlan, int locked)
-{
- struct net_device *vlan_dev = NULL;
- struct ieee80211_sub_if_data *sdata = NULL;
-
- if (strlen(name) != 0) {
- vlan_dev = dev_get_by_name(name);
- if (vlan_dev) {
- dev_put(vlan_dev);
- return -EEXIST;
- }
- }
-
- vlan_dev = ieee80211_if_add(dev, name, locked);
- if (vlan_dev == NULL)
- return -ENOANO;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(vlan_dev);
- sdata->type = IEEE80211_IF_TYPE_VLAN;
- ieee80211_proc_init_virtual(vlan_dev);
- return 0;
-}
-
-
-static void ieee80211_if_ap_init(struct ieee80211_sub_if_data *sdata)
-{
- sdata->type = IEEE80211_IF_TYPE_AP;
- sdata->u.ap.dtim_period = 2;
- sdata->u.ap.force_unicast_rateidx = -1;
- sdata->u.ap.max_ratectrl_rateidx = -1;
- skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
- sdata->bss = &sdata->u.ap;
-}
-
-
-int ieee80211_if_add_ap(struct net_device *dev, const char *name, u8 *bssid,
- int locked)
-{
- struct net_device *ap_dev = NULL;
- struct ieee80211_sub_if_data *sdata = NULL;
-
- if (strlen(name) != 0) {
- ap_dev = dev_get_by_name(name);
- if (ap_dev) {
- dev_put(ap_dev);
- return -EEXIST;
- }
- }
-
- ap_dev = ieee80211_if_add(dev, name, locked);
- if (ap_dev == NULL)
- return -ENOANO;
-
- memcpy(ap_dev->dev_addr, bssid, ETH_ALEN);
- sdata = IEEE80211_DEV_TO_SUB_IF(ap_dev);
- ieee80211_if_ap_init(sdata);
- ieee80211_proc_init_virtual(ap_dev);
-
- return 0;
-}
-
-
-int ieee80211_if_add_sta(struct net_device *dev, const char *name, int locked)
-{
- struct net_device *sta_dev;
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_if_sta *ifsta;
-
- if (strlen(name) != 0) {
- sta_dev = dev_get_by_name(name);
- if (sta_dev) {
- dev_put(sta_dev);
- return -EEXIST;
- }
- }
-
- sta_dev = ieee80211_if_add(dev, name, locked);
- if (sta_dev == NULL)
- return -ENOANO;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(sta_dev);
- ifsta = &sdata->u.sta;
- sdata->type = IEEE80211_IF_TYPE_STA;
- ieee80211_proc_init_virtual(sta_dev);
-
- init_timer(&ifsta->timer);
- ifsta->timer.data = (unsigned long) sta_dev;
- ifsta->timer.function = ieee80211_sta_timer;
-
- ifsta->capab = WLAN_CAPABILITY_ESS;
- ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
- IEEE80211_AUTH_ALG_SHARED_KEY;
- ifsta->create_ibss = 1;
- ifsta->wmm_enabled = 1;
-
- return 0;
-}
-
-
-static void ieee80211_if_del(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata, int locked)
-{
- struct sta_info *sta;
- u8 addr[ETH_ALEN];
- int i;
- struct list_head *ptr, *n;
-
- memset(addr, 0xff, ETH_ALEN);
- for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
- if (!sdata->keys[i])
- continue;
-#if 0
- /* Low-level driver has probably disabled hw
- * already, so there is not really much point
- * in disabling the keys at this point. */
- if (local->hw->set_key)
- local->hw->set_key(dev, DISABLE_KEY, addr,
- local->keys[i], 0);
-#endif
- ieee80211_key_free(sdata->keys[i]);
- }
-
- switch (sdata->type) {
- case IEEE80211_IF_TYPE_AP:
- /* Remove all virtual interfaces that use this BSS
- * as their sdata->bss */
- list_for_each_safe(ptr, n, &local->sub_if_list) {
- struct ieee80211_sub_if_data *tsdata =
- list_entry(ptr, struct ieee80211_sub_if_data,
- list);
-
- if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
- printk(KERN_DEBUG "%s: removing virtual "
- "interface %s because its BSS interface"
- " is being removed\n",
- sdata->dev->name, tsdata->dev->name);
- ieee80211_if_del(local, tsdata, locked);
- }
- }
-
- kfree(sdata->u.ap.beacon_head);
- kfree(sdata->u.ap.beacon_tail);
-
- if (sdata->dev != local->mdev) {
- struct sk_buff *skb;
- while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
- local->total_ps_buffered--;
- dev_kfree_skb(skb);
- }
- }
-
- break;
- case IEEE80211_IF_TYPE_WDS:
- sta = sta_info_get(local, sdata->u.wds.remote_addr);
- if (sta) {
- sta_info_release(local, sta);
- sta_info_free(local, sta, 0);
- } else {
-#ifdef CONFIG_D80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Someone had deleted my STA "
- "entry for the WDS link\n", local->mdev->name);
-#endif /* CONFIG_D80211_VERBOSE_DEBUG */
- }
- break;
- case IEEE80211_IF_TYPE_STA:
- del_timer_sync(&sdata->u.sta.timer);
- if (local->scan_timer.data == (unsigned long) sdata->dev)
- del_timer_sync(&local->scan_timer);
- kfree(sdata->u.sta.extra_ie);
- sdata->u.sta.extra_ie = NULL;
- kfree(sdata->u.sta.assocreq_ies);
- sdata->u.sta.assocreq_ies = NULL;
- kfree(sdata->u.sta.assocresp_ies);
- sdata->u.sta.assocresp_ies = NULL;
- if (sdata->u.sta.probe_resp) {
- dev_kfree_skb(sdata->u.sta.probe_resp);
- sdata->u.sta.probe_resp = NULL;
- }
-
- break;
- }
-
- /* remove all STAs that are bound to this virtual interface */
- sta_info_flush(local, sdata->dev);
-
- list_del(&sdata->list);
- ieee80211_proc_deinit_virtual(sdata->dev);
- if (locked)
- unregister_netdevice(sdata->dev);
- else
- unregister_netdev(sdata->dev);
- /* Default data device and management device are allocated with the
- * master device. All other devices are separately allocated and will
- * be freed here. */
- if (sdata->dev != local->mdev && sdata->dev != local->wdev &&
- sdata->dev != local->apdev)
- kfree(sdata->dev);
-}
-
-
-static int ieee80211_if_remove(struct net_device *dev, const char *name,
- int id, int locked)
+/* Must not be called for wdev, mdev and apdev */
+void ieee80211_if_setup(struct net_device *dev)
{
- struct ieee80211_local *local = dev->priv;
- struct list_head *ptr, *n;
-
- /* Make sure not to touch sdata->master since it may
- * have already been deleted, etc. */
-
- list_for_each_safe(ptr, n, &local->sub_if_list) {
- struct ieee80211_sub_if_data *sdata =
- list_entry(ptr, struct ieee80211_sub_if_data, list);
-
- if (sdata->type == id && strcmp(name, sdata->dev->name) == 0) {
- ieee80211_if_del(local, sdata, locked);
- break;
- }
- }
-
- return 0;
-}
-
-
-int ieee80211_if_remove_wds(struct net_device *dev, const char *name,
- int locked)
-{
- return ieee80211_if_remove(dev, name, IEEE80211_IF_TYPE_WDS, locked);
-}
-
-
-int ieee80211_if_remove_vlan(struct net_device *dev, const char *name,
- int locked)
-{
- return ieee80211_if_remove(dev, name, IEEE80211_IF_TYPE_VLAN, locked);
-}
-
-
-int ieee80211_if_remove_ap(struct net_device *dev, const char *name,
- int locked)
-{
- return ieee80211_if_remove(dev, name, IEEE80211_IF_TYPE_AP, locked);
-}
-
-
-int ieee80211_if_remove_sta(struct net_device *dev, const char *name,
- int locked)
-{
- return ieee80211_if_remove(dev, name, IEEE80211_IF_TYPE_STA, locked);
-}
-
-
-int ieee80211_if_flush(struct net_device *dev, int locked)
-{
- struct ieee80211_local *local = dev->priv;
- struct list_head *ptr, *n;
-
- list_for_each_safe(ptr, n, &local->sub_if_list) {
- struct ieee80211_sub_if_data *sdata =
- list_entry(ptr, struct ieee80211_sub_if_data, list);
-
- if (sdata->dev != local->mdev &&
- sdata->dev != local->wdev &&
- sdata->dev != local->apdev)
- ieee80211_if_del(local, sdata, locked);
- }
-
- return 0;
+ ether_setup(dev);
+ dev->hard_start_xmit = ieee80211_subif_start_xmit;
+ dev->wireless_handlers =
+ (struct iw_handler_def *) &ieee80211_iw_handler_def;
+ dev->do_ioctl = ieee80211_ioctl;
+ dev->set_mac_address = ieee80211_set_mac_address;
+ dev->change_mtu = ieee80211_change_mtu;
+ dev->tx_timeout = ieee80211_tx_timeout;
+ dev->get_stats = ieee80211_get_stats;
+ dev->open = ieee80211_open;
+ dev->stop = ieee80211_stop;
+ dev->tx_queue_len = 0;
+ dev->destructor = ieee80211_if_free;
}
@@ -4357,7 +3999,7 @@ struct net_device *ieee80211_alloc_hw(si
sdata->master = mdev;
sdata->local = local;
ieee80211_if_sdata_init(sdata);
- ieee80211_if_ap_init(sdata);
+ ieee80211_if_set_type(dev, IEEE80211_IF_TYPE_AP);
list_add_tail(&sdata->list, &local->sub_if_list);
if (strlen(dev->name) + 2 >= sizeof(dev->name))
@@ -4530,6 +4172,8 @@ int ieee80211_update_hw(struct net_devic
local->conf.freq = local->hw->modes[0].channels[0].freq;
local->conf.channel = local->hw->modes[0].channels[0].chan;
local->conf.channel_val = local->hw->modes[0].channels[0].val;
+
+ ieee80211_init_client(dev);
/* FIXME: Invoke config to allow driver to set the channel. */
return 0;
@@ -4556,7 +4200,7 @@ void ieee80211_unregister_hw(struct net_
list_for_each_safe(ptr, n, &local->sub_if_list) {
struct ieee80211_sub_if_data *sdata =
list_entry(ptr, struct ieee80211_sub_if_data, list);
- ieee80211_if_del(local, sdata, 0);
+ ieee80211_if_del(sdata->dev);
}
sta_info_stop(local);
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 8fd0ac4..5116a88 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -493,18 +493,8 @@ void ieee80211_rx_mgmt(struct net_device
struct ieee80211_rx_status *status, u32 msg_type);
void ieee80211_prepare_rates(struct net_device *dev);
void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
-int ieee80211_if_add_wds(struct net_device *dev, const char *name,
- struct ieee80211_if_wds *wds, int locked);
-int ieee80211_if_add_vlan(struct net_device *dev, const char *name,
- struct ieee80211_if_vlan *vlan, int locked);
-int ieee80211_if_add_ap(struct net_device *dev, const char *name, u8 *bssid,
- int locked);
-
-int ieee80211_if_remove_wds(struct net_device *dev, const char *name, int locked);
-int ieee80211_if_remove_vlan(struct net_device *dev, const char *name, int locked);
-int ieee80211_if_remove_ap(struct net_device *dev, const char *name, int locked);
-int ieee80211_if_flush(struct net_device *dev, int locked);
int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
+void ieee80211_if_setup(struct net_device *dev);
/* ieee80211_ioctl.c */
int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -540,13 +530,10 @@ #define CHAN_UTIL_HDR_LONG (202 * CHAN_U
#define CHAN_UTIL_HDR_SHORT (40 * CHAN_UTIL_PER_USEC)
-
-/* ieee80211.c */
-int ieee80211_if_add_sta(struct net_device *dev, const char *name, int locked);
-int ieee80211_if_remove_sta(struct net_device *dev, const char *name, int locked);
/* ieee80211_ioctl.c */
int ieee80211_set_compression(struct ieee80211_local *local,
struct net_device *dev, struct sta_info *sta);
+int ieee80211_init_client(struct net_device *dev);
/* ieee80211_sta.c */
void ieee80211_sta_timer(unsigned long ptr);
void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
@@ -573,6 +560,19 @@ void ieee80211_dev_free_index(struct iee
struct ieee80211_local *ieee80211_dev_find(int index);
int ieee80211_dev_find_index(struct ieee80211_local *local);
+/* ieee80211_iface.c */
+int ieee80211_if_add(struct net_device *dev, const char *name,
+ struct net_device **new_dev);
+void ieee80211_if_set_type(struct net_device *dev, int type);
+void ieee80211_if_reinit(struct net_device *dev);
+void __ieee80211_if_del(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata);
+void ieee80211_if_del(struct net_device *dev);
+int ieee80211_if_remove(struct net_device *dev, const char *name, int id);
+void ieee80211_if_free(struct net_device *dev);
+void ieee80211_if_flush(struct net_device *dev);
+void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
+
/* ieee80211_sysfs.c */
int ieee80211_register_sysfs(struct ieee80211_local *local);
void ieee80211_unregister_sysfs(struct ieee80211_local *local);
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
new file mode 100644
index 0000000..917428e
--- /dev/null
+++ b/net/d80211/ieee80211_iface.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/d80211.h>
+#include <net/d80211_mgmt.h>
+#include "ieee80211_i.h"
+#include "ieee80211_proc.h"
+#include "sta_info.h"
+
+void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
+{
+ /* Default values for sub-interface parameters */
+ sdata->drop_unencrypted = 0;
+ sdata->eapol = 1;
+}
+
+/* Must be called with rtnl lock held. */
+int ieee80211_if_add(struct net_device *dev, const char *name,
+ struct net_device **new_dev)
+{
+ struct net_device *ndev, *tmp_dev;
+ struct ieee80211_local *local = dev->priv;
+ struct ieee80211_sub_if_data *sdata = NULL, *sdata_parent;
+ int alloc_size;
+ int ret;
+ int i;
+
+ ASSERT_RTNL();
+ /* ensure 32-bit alignment of our private data and hw private data */
+ alloc_size = sizeof(struct net_device) + 3 +
+ sizeof(struct ieee80211_sub_if_data) + 3;
+
+ ndev = *new_dev = (struct net_device *) kzalloc(alloc_size, GFP_KERNEL);
+ if (ndev == NULL)
+ return -ENOMEM;
+
+ ndev->priv = local;
+ if (strlen(name) == 0) {
+ i = 0;
+ do {
+ sprintf(ndev->name, "%s.%d", dev->name, i++);
+ tmp_dev = dev_get_by_name(ndev->name);
+ if (tmp_dev == NULL)
+ break;
+ dev_put(tmp_dev);
+ } while (i < 10000);
+ } else {
+ snprintf(ndev->name, IFNAMSIZ, "%s", name);
+ }
+
+ memcpy(ndev->dev_addr, dev->dev_addr, ETH_ALEN);
+ ndev->base_addr = dev->base_addr;
+ ndev->irq = dev->irq;
+ ndev->mem_start = dev->mem_start;
+ ndev->mem_end = dev->mem_end;
+ ieee80211_if_setup(ndev);
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+ sdata->type = IEEE80211_IF_TYPE_AP;
+ sdata->master = local->mdev;
+ sdata->dev = ndev;
+ sdata->local = local;
+ sdata_parent = IEEE80211_DEV_TO_SUB_IF(dev);
+ ieee80211_if_sdata_init(sdata);
+
+ ret = register_netdevice(ndev);
+ if (ret) {
+ kfree(ndev);
+ *new_dev = NULL;
+ return ret;
+ }
+
+ list_add(&sdata->list, &local->sub_if_list);
+ ieee80211_proc_init_virtual(ndev);
+
+ return 0;
+}
+
+void ieee80211_if_set_type(struct net_device *dev, int type)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ sdata->type = type;
+ switch (type) {
+ case IEEE80211_IF_TYPE_WDS:
+ sdata->bss = NULL;
+ break;
+ case IEEE80211_IF_TYPE_VLAN:
+ break;
+ case IEEE80211_IF_TYPE_AP:
+ sdata->u.ap.dtim_period = 2;
+ sdata->u.ap.force_unicast_rateidx = -1;
+ sdata->u.ap.max_ratectrl_rateidx = -1;
+ skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
+ sdata->bss = &sdata->u.ap;
+ break;
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS: {
+ struct ieee80211_sub_if_data *msdata;
+ struct ieee80211_if_sta *ifsta;
+
+ ifsta = &sdata->u.sta;
+ init_timer(&ifsta->timer);
+ ifsta->timer.data = (unsigned long) dev;
+ ifsta->timer.function = ieee80211_sta_timer;
+
+ ifsta->capab = WLAN_CAPABILITY_ESS;
+ ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
+ IEEE80211_AUTH_ALG_SHARED_KEY;
+ ifsta->create_ibss = 1;
+ ifsta->wmm_enabled = 1;
+
+ msdata = IEEE80211_DEV_TO_SUB_IF(sdata->master);
+ sdata->bss = &msdata->u.ap;
+ break;
+ }
+ default:
+ printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
+ dev->name, __FUNCTION__, type);
+ }
+}
+
+/* Must be called with rtnl lock held. */
+void ieee80211_if_reinit(struct net_device *dev)
+{
+ struct ieee80211_local *local = dev->priv;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct sta_info *sta;
+ int i;
+
+ ASSERT_RTNL();
+ for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+ if (!sdata->keys[i])
+ continue;
+#if 0
+ /* The interface is down at the moment, so there is not
+ * really much point in disabling the keys at this point. */
+ memset(addr, 0xff, ETH_ALEN);
+ if (local->hw->set_key)
+ local->hw->set_key(dev, DISABLE_KEY, addr,
+ local->keys[i], 0);
+#endif
+ ieee80211_key_free(sdata->keys[i]);
+ }
+
+ switch (sdata->type) {
+ case IEEE80211_IF_TYPE_AP: {
+ /* Remove all virtual interfaces that use this BSS
+ * as their sdata->bss */
+ struct ieee80211_sub_if_data *tsdata, *n;
+
+ list_for_each_entry_safe(tsdata, n, &local->sub_if_list, list) {
+ if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
+ printk(KERN_DEBUG "%s: removing virtual "
+ "interface %s because its BSS interface"
+ " is being removed\n",
+ sdata->dev->name, tsdata->dev->name);
+ __ieee80211_if_del(local, tsdata);
+ }
+ }
+
+ kfree(sdata->u.ap.beacon_head);
+ kfree(sdata->u.ap.beacon_tail);
+
+ if (dev != local->mdev) {
+ struct sk_buff *skb;
+ while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
+ local->total_ps_buffered--;
+ dev_kfree_skb(skb);
+ }
+ }
+
+ break;
+ }
+ case IEEE80211_IF_TYPE_WDS:
+ sta = sta_info_get(local, sdata->u.wds.remote_addr);
+ if (sta) {
+ sta_info_release(local, sta);
+ sta_info_free(local, sta, 0);
+ } else {
+#ifdef CONFIG_D80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: Someone had deleted my STA "
+ "entry for the WDS link\n", dev->name);
+#endif /* CONFIG_D80211_VERBOSE_DEBUG */
+ }
+ break;
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ del_timer_sync(&sdata->u.sta.timer);
+ if (local->scan_timer.data == (unsigned long) sdata->dev)
+ del_timer_sync(&local->scan_timer);
+ kfree(sdata->u.sta.extra_ie);
+ sdata->u.sta.extra_ie = NULL;
+ kfree(sdata->u.sta.assocreq_ies);
+ sdata->u.sta.assocreq_ies = NULL;
+ kfree(sdata->u.sta.assocresp_ies);
+ sdata->u.sta.assocresp_ies = NULL;
+ if (sdata->u.sta.probe_resp) {
+ dev_kfree_skb(sdata->u.sta.probe_resp);
+ sdata->u.sta.probe_resp = NULL;
+ }
+
+ break;
+ }
+
+ /* remove all STAs that are bound to this virtual interface */
+ sta_info_flush(local, dev);
+
+ memset(&sdata->u, 0, sizeof(sdata->u));
+ ieee80211_if_sdata_init(sdata);
+}
+
+/* Must be called with rtnl lock held. */
+void __ieee80211_if_del(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ struct net_device *dev = sdata->dev;
+
+ ieee80211_if_reinit(dev);
+ list_del(&sdata->list);
+ ieee80211_proc_deinit_virtual(dev);
+ unregister_netdevice(dev);
+ /* Default data device and management device are allocated with the
+ * master device. All other devices are separately allocated and will
+ * be freed by net_device->destructor (i. e. ieee80211_if_free). */
+}
+
+/* Must be called with rtnl lock held. */
+int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
+{
+ struct ieee80211_local *local = dev->priv;
+ struct ieee80211_sub_if_data *sdata, *n;
+
+ ASSERT_RTNL();
+
+ /* Make sure not to touch sdata->master since it may
+ * have already been deleted, etc. */
+
+ list_for_each_entry_safe(sdata, n, &local->sub_if_list, list) {
+ if ((sdata->type == id || id == -1) &&
+ strcmp(name, sdata->dev->name) == 0 &&
+ sdata->dev != local->mdev &&
+ sdata->dev != local->wdev &&
+ sdata->dev != local->apdev) {
+ __ieee80211_if_del(local, sdata);
+ return 0;
+ }
+ }
+ return -ENODEV;
+}
+
+void ieee80211_if_free(struct net_device *dev)
+{
+ struct ieee80211_local *local = dev->priv;
+
+ BUG_ON(dev == local->mdev || dev == local->wdev || dev == local->apdev);
+ kfree(dev);
+}
+
+/* Must be called with rtnl lock held. */
+void ieee80211_if_flush(struct net_device *dev)
+{
+ struct ieee80211_local *local = dev->priv;
+ struct ieee80211_sub_if_data *sdata, *n;
+
+ ASSERT_RTNL();
+ list_for_each_entry_safe(sdata, n, &local->sub_if_list, list) {
+ __ieee80211_if_del(local, sdata);
+ }
+}
+
+void ieee80211_if_del(struct net_device *dev)
+{
+ struct ieee80211_local *local = dev->priv;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ rtnl_lock();
+ __ieee80211_if_del(local, sdata);
+ rtnl_unlock();
+}
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 6279a7a..dfa0ef7 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -922,30 +922,39 @@ static int ieee80211_ioctl_add_if(struct
{
u8 *pos = param->u.if_info.data;
int left = param_len - ((u8 *) pos - (u8 *) param);
+ struct net_device *new_dev;
+ int res;
+ printk(KERN_WARNING "PRISM2_HOSTAPD_ADD_IF ioctl is deprecated!");
if (param->u.if_info.type == HOSTAP_IF_WDS) {
- struct ieee80211_if_wds iwds;
struct hostapd_if_wds *wds =
(struct hostapd_if_wds *) param->u.if_info.data;
- if (left < sizeof(struct ieee80211_if_wds))
+ if (left < sizeof(struct hostapd_if_wds))
return -EPROTO;
- memcpy(iwds.remote_addr, wds->remote_addr, ETH_ALEN);
-
- return ieee80211_if_add_wds(dev, param->u.if_info.name,
- &iwds, 1);
+ res = ieee80211_if_add(dev, param->u.if_info.name, &new_dev);
+ if (res)
+ return res;
+ ieee80211_if_set_type(new_dev, IEEE80211_IF_TYPE_WDS);
+ res = ieee80211_if_update_wds(new_dev, wds->remote_addr);
+ if (res)
+ ieee80211_if_del(new_dev);
+ return res;
} else if (param->u.if_info.type == HOSTAP_IF_VLAN) {
- struct hostapd_if_vlan *vlan = (struct hostapd_if_vlan *) pos;
- struct ieee80211_if_vlan ivlan;
-
if (left < sizeof(struct hostapd_if_vlan))
return -EPROTO;
- ivlan.id = vlan->id;
-
- return ieee80211_if_add_vlan(dev, param->u.if_info.name,
- &ivlan, 1);
+ res = ieee80211_if_add(dev, param->u.if_info.name, &new_dev);
+ if (res)
+ return res;
+ ieee80211_if_set_type(new_dev, IEEE80211_IF_TYPE_VLAN);
+#if 0
+ res = ieee80211_if_update_vlan(new_dev, vlan->id);
+ if (res)
+ ieee80211_if_del(new_dev);
+#endif
+ return res;
} else if (param->u.if_info.type == HOSTAP_IF_BSS) {
struct hostapd_if_bss *bss =
(struct hostapd_if_bss *) param->u.if_info.data;
@@ -953,8 +962,12 @@ static int ieee80211_ioctl_add_if(struct
if (left < sizeof(struct hostapd_if_bss))
return -EPROTO;
- return ieee80211_if_add_ap(dev, param->u.if_info.name,
- bss->bssid, 1);
+ res = ieee80211_if_add(dev, param->u.if_info.name, &new_dev);
+ if (res)
+ return res;
+ ieee80211_if_set_type(new_dev, IEEE80211_IF_TYPE_AP);
+ memcpy(new_dev->dev_addr, bss->bssid, ETH_ALEN);
+ return 0;
} else if (param->u.if_info.type == HOSTAP_IF_STA) {
#if 0
struct hostapd_if_sta *sta =
@@ -964,7 +977,11 @@ #endif
if (left < sizeof(struct hostapd_if_sta))
return -EPROTO;
- return ieee80211_if_add_sta(dev, param->u.if_info.name, 1);
+ res = ieee80211_if_add(dev, param->u.if_info.name, &new_dev);
+ if (res)
+ return res;
+ ieee80211_if_set_type(new_dev, IEEE80211_IF_TYPE_STA);
+ return 0;
} else
return -EINVAL;
@@ -975,17 +992,14 @@ #endif
static int ieee80211_ioctl_remove_if(struct net_device *dev,
struct prism2_hostapd_param *param)
{
- if (param->u.if_info.type == HOSTAP_IF_WDS) {
- return ieee80211_if_remove_wds(dev, param->u.if_info.name, 1);
- } else if (param->u.if_info.type == HOSTAP_IF_VLAN) {
- return ieee80211_if_remove_vlan(dev, param->u.if_info.name, 1);
- } else if (param->u.if_info.type == HOSTAP_IF_BSS) {
- return ieee80211_if_remove_ap(dev, param->u.if_info.name, 1);
- } else if (param->u.if_info.type == HOSTAP_IF_STA) {
- return ieee80211_if_remove_sta(dev, param->u.if_info.name, 1);
- } else {
+ if (param->u.if_info.type != HOSTAP_IF_WDS &&
+ param->u.if_info.type != HOSTAP_IF_VLAN &&
+ param->u.if_info.type != HOSTAP_IF_BSS &&
+ param->u.if_info.type != HOSTAP_IF_STA) {
return -EINVAL;
}
+ return ieee80211_if_remove(dev, param->u.if_info.name,
+ param->u.if_info.type);
}
@@ -1027,7 +1041,8 @@ static int ieee80211_ioctl_update_if(str
static int ieee80211_ioctl_flush_ifs(struct net_device *dev,
struct prism2_hostapd_param *param)
{
- return ieee80211_if_flush(dev, 1);
+ ieee80211_if_flush(dev);
+ return 0;
}
@@ -1575,7 +1590,7 @@ static int ieee80211_unmask_channels(str
}
-static int ieee80211_init_client(struct net_device *dev)
+int ieee80211_init_client(struct net_device *dev)
{
if (ieee80211_regdom == 0x40)
channel_range = ieee80211_mkk_channels;
@@ -1588,35 +1603,39 @@ static int ieee80211_ioctl_siwmode(struc
struct iw_request_info *info,
__u32 *mode, char *extra)
{
-#if 0
- struct ieee80211_local *local = dev->priv;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ int type;
- if (!ieee80211_is_client_mode(local->conf.mode) &&
- ieee80211_is_client_mode(*mode)) {
- ieee80211_init_client(dev);
+ if (sdata->type == IEEE80211_IF_TYPE_VLAN)
+ return -EOPNOTSUPP;
+ if (netif_running(dev))
+ return -EBUSY;
+
+ switch (*mode) {
+ case IW_MODE_MASTER:
+ type = IEEE80211_IF_TYPE_AP;
+ break;
+ case IW_MODE_INFRA:
+ type = IEEE80211_IF_TYPE_STA;
+ break;
+ case IW_MODE_ADHOC:
+ type = IEEE80211_IF_TYPE_IBSS;
+ break;
+ case IW_MODE_MONITOR:
+ type = IEEE80211_IF_TYPE_MNTR;
+ break;
+ case IW_MODE_REPEAT:
+ type = IEEE80211_IF_TYPE_WDS;
+ break;
+ default:
+ return -EINVAL;
}
- if (local->conf.mode != *mode) {
- struct ieee80211_sub_if_data *sdata =
- IEEE80211_DEV_TO_SUB_IF(dev);
- sta_info_flush(local, NULL);
- if (local->conf.mode == IW_MODE_ADHOC &&
- sdata->type == IEEE80211_IF_TYPE_STA) {
- /* Clear drop_unencrypted when leaving adhoc mode since
- * only adhoc mode is using automatic setting for this
- * in 80211.o. */
- sdata->drop_unencrypted = 0;
- }
- if (*mode == IW_MODE_MASTER) {
- /* AP mode does not currently use ACM bits to limit
- * TX, so clear the bitfield here. */
- local->wmm_acm = 0;
- }
+
+ if (type != sdata->type) {
+ ieee80211_if_reinit(dev);
+ ieee80211_if_set_type(dev, type);
}
- local->conf.mode = *mode;
- return ieee80211_hw_config(dev);
-#else
- return -EOPNOTSUPP;
-#endif
+ return 0;
}
diff --git a/net/d80211/ieee80211_sysfs.c b/net/d80211/ieee80211_sysfs.c
index 082404f..546e2b7 100644
--- a/net/d80211/ieee80211_sysfs.c
+++ b/net/d80211/ieee80211_sysfs.c
@@ -22,17 +22,17 @@ static ssize_t store_add_iface(struct cl
const char *buf, size_t len)
{
struct ieee80211_local *local = to_ieee80211_local(dev);
+ struct net_device *new_dev;
int res;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (len > IFNAMSIZ)
return -EINVAL;
- /* Cannot call ieee80211_if_add_sta() with 'locked' parameter equal
- * to zero as it would lead to call to register_netdev() and
- * interpreting '%d' character in an interface name. */
rtnl_lock();
- res = ieee80211_if_add_sta(local->mdev, buf, 1);
+ res = ieee80211_if_add(local->mdev, buf, &new_dev);
+ if (res == 0)
+ ieee80211_if_set_type(new_dev, IEEE80211_IF_TYPE_STA);
rtnl_unlock();
return res < 0 ? res : len;
}
@@ -47,7 +47,9 @@ static ssize_t store_remove_iface(struct
return -EPERM;
if (len > IFNAMSIZ)
return -EINVAL;
- res = ieee80211_if_remove_sta(local->mdev, buf, 0);
+ rtnl_lock();
+ res = ieee80211_if_remove(local->mdev, buf, -1);
+ rtnl_unlock();
return res < 0 ? res : len;
}
--
1.3.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox