* [RFC] make d80211 use nl80211
@ 2006-08-22 13:53 Johannes Berg
2006-08-24 14:05 ` Jiri Benc
2006-08-24 16:07 ` Johannes Berg
0 siblings, 2 replies; 6+ messages in thread
From: Johannes Berg @ 2006-08-22 13:53 UTC (permalink / raw)
To: netdev; +Cc: Jiri Benc, John W. Linville
This patch makes d80211 partially configurable using the
infrastructure that nl80211 provides. So far, it allows
packet injection and adding/removing virtual interfaces.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
--- wireless-dev.orig/net/d80211/Kconfig 2006-08-22 15:47:46.000000000 +0200
+++ wireless-dev/net/d80211/Kconfig 2006-08-22 15:47:48.000000000 +0200
@@ -3,6 +3,7 @@ config D80211
select CRYPTO
select CRYPTO_ARC4
select CRYPTO_AES
+ select NETLINK_80211
---help---
This option enables the hardware independent IEEE 802.11
networking stack.
--- wireless-dev.orig/net/d80211/Makefile 2006-08-22 15:47:44.000000000 +0200
+++ wireless-dev/net/d80211/Makefile 2006-08-22 15:47:48.000000000 +0200
@@ -8,6 +8,7 @@ obj-$(CONFIG_D80211) += 80211.o rate_con
sta_info.o \
wep.o \
wpa.o \
+ ieee80211_cfg.o \
ieee80211_scan.o \
ieee80211_sta.o \
ieee80211_dev.o \
--- wireless-dev.orig/net/d80211/ieee80211.c 2006-08-22 15:47:46.000000000 +0200
+++ wireless-dev/net/d80211/ieee80211.c 2006-08-22 15:47:48.000000000 +0200
@@ -20,6 +20,7 @@
#include <net/iw_handler.h>
#include <linux/compiler.h>
#include <linux/bitmap.h>
+#include <linux/nl80211.h>
#include <net/d80211.h>
#include <net/d80211_common.h>
@@ -32,6 +33,7 @@
#include "wme.h"
#include "aes_ccm.h"
#include "ieee80211_led.h"
+#include "ieee80211_cfg.h"
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
@@ -348,6 +350,16 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
{
struct rate_control_extra extra;
+ /* FIXME
+ if (tx->dev == tx->local->mdev &&
+ (inject rate set)) {
+ a
+ tx->u.tx.rate = ...
+ etc etc
+ return TXRX_CONTINUE;
+ }
+ */
+
memset(&extra, 0, sizeof(extra));
extra.mgmt_data = tx->sdata &&
tx->sdata->type == IEEE80211_IF_TYPE_MGMT;
@@ -753,6 +765,13 @@ ieee80211_tx_h_misc(struct ieee80211_txr
u16 dur;
struct ieee80211_tx_control *control = tx->u.tx.control;
+ /* FIXME
+ if (tx->dev == tx->local->mdev) {
+ set up retry limit, ...
+ based on injection parameters
+ }
+ */
+
if (!is_multicast_ether_addr(hdr->addr1)) {
if (tx->skb->len + FCS_LEN > tx->local->rts_threshold &&
tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) {
@@ -878,6 +897,9 @@ ieee80211_tx_h_check_assoc(struct ieee80
#endif /* CONFIG_D80211_VERBOSE_DEBUG */
u32 sta_flags;
+ if (unlikely(tx->dev == tx->local->mdev))
+ return TXRX_CONTINUE;
+
if (unlikely(tx->local->sta_scanning != 0) &&
((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
(tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
@@ -981,6 +1003,12 @@ static void purge_old_ps_buffers(struct
static inline ieee80211_txrx_result
ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
{
+ /* FIXME
+ if (unlikely(tx->dev == tx->local->mdev &&
+ (inject flags) & NL80211_FLAG_NOBUFFER))
+ return TXRX_CONTINUE;
+ */
+
/* broadcast/multicast frame */
/* If any of the associated stations is in power save mode,
* the frame is buffered to be sent after DTIM beacon frame */
@@ -1408,11 +1436,12 @@ static int ieee80211_master_start_xmit(s
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.req_tx_status = !!(pkt_data->flags & NL80211_FLAG_TXSTATUS);
+ control.do_not_encrypt = !(pkt_data->flags & NL80211_FLAG_ENCRYPT);
control.pkt_type =
- pkt_data->pkt_probe_resp ? PKT_PROBE_RESP : PKT_NORMAL;
- control.requeue = pkt_data->requeue;
+ (pkt_data->internal_flags & TX_FLAG_PROBERESP) ?
+ PKT_PROBE_RESP : PKT_NORMAL;
+ control.requeue = !!(pkt_data->internal_flags & TX_FLAG_REQUEUE);
control.queue = pkt_data->queue;
ret = ieee80211_tx(odev, skb, &control,
@@ -1588,8 +1617,10 @@ static int ieee80211_subif_start_xmit(st
pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
pkt_data->ifindex = sdata->dev->ifindex;
- pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
- pkt_data->do_not_encrypt = no_encrypt;
+ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->internal_flags |= TX_FLAG_INJECTED;
+ if (!no_encrypt)
+ pkt_data->flags |= NL80211_FLAG_ENCRYPT;
skb->dev = sdata->master;
sdata->stats.tx_packets++;
@@ -1640,11 +1671,12 @@ 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->ifindex = sdata->dev->ifindex;
- pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
+ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->internal_flags |= TX_FLAG_INJECTED;
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
(fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)
- pkt_data->pkt_probe_resp = 1;
+ pkt_data->internal_flags |= TX_FLAG_PROBERESP;
skb->priority = 20; /* use hardcoded priority for mgmt TX queue */
skb->dev = sdata->master;
@@ -1654,12 +1686,13 @@ ieee80211_mgmt_start_xmit(struct sk_buff
* to request TX callback for hostapd. BIT(1) is checked.
*/
if ((fc & BIT(1)) == BIT(1)) {
- pkt_data->req_tx_status = 1;
+ pkt_data->flags |= NL80211_FLAG_TXSTATUS;
fc &= ~BIT(1);
hdr->frame_control = cpu_to_le16(fc);
}
- pkt_data->do_not_encrypt = !(fc & IEEE80211_FCTL_PROTECTED);
+ if (fc & IEEE80211_FCTL_PROTECTED)
+ pkt_data->flags |= NL80211_FLAG_ENCRYPT;
sdata->stats.tx_packets++;
sdata->stats.tx_bytes += skb->len;
@@ -2714,7 +2747,7 @@ static int ap_sta_ps_end(struct net_devi
while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
sent++;
- pkt_data->requeue = 1;
+ pkt_data->internal_flags |= TX_FLAG_REQUEUE;
dev_queue_xmit(skb);
}
while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
@@ -2726,7 +2759,7 @@ static int ap_sta_ps_end(struct net_devi
"since STA not sleeping anymore\n", dev->name,
MAC_ARG(sta->addr), sta->aid);
#endif /* CONFIG_D80211_VERBOSE_PS_DEBUG */
- pkt_data->requeue = 1;
+ pkt_data->internal_flags |= TX_FLAG_REQUEUE;
dev_queue_xmit(skb);
}
@@ -3960,12 +3993,19 @@ 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->flags = 0;
+ pkt_data->internal_flags = 0;
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);
- pkt_data->requeue = control->requeue;
+ if (control->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->internal_flags |= TX_FLAG_INJECTED;
+ if (control->req_tx_status)
+ pkt_data->flags |= NL80211_FLAG_TXSTATUS;
+ if (!control->do_not_encrypt)
+ pkt_data->flags |= NL80211_FLAG_ENCRYPT;
+ if (control->pkt_type == PKT_PROBE_RESP)
+ pkt_data->internal_flags |= TX_FLAG_PROBERESP;
+ if (control->requeue)
+ pkt_data->internal_flags |= TX_FLAG_REQUEUE;
pkt_data->queue = control->queue;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -4323,6 +4363,7 @@ struct net_device *ieee80211_alloc_hw(si
priv_size = ((sizeof(struct ieee80211_sub_if_data) +
NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) +
priv_data_len;
+
mdev = alloc_netdev(priv_size, "wmaster%d", ether_setup);
if (!mdev) {
ieee80211_dev_free(local);
@@ -4426,6 +4467,9 @@ int ieee80211_register_hw(struct net_dev
if (result < 0)
return -1;
+ if (ieee80211_cfg_init(local))
+ goto fail_nl80211;
+
local->class_dev.dev = dev->class_dev.dev;
result = ieee80211_dev_sysfs_add(local);
if (result < 0)
@@ -4512,6 +4556,8 @@ fail_dev:
fail_sta_info:
ieee80211_dev_sysfs_del(local);
fail_sysfs:
+ ieee80211_cfg_exit(local);
+fail_nl80211:
ieee80211_dev_free_index(local);
return result;
}
@@ -4594,6 +4640,8 @@ void ieee80211_unregister_hw(struct net_
&local->class_dev.kobj);
ieee80211_dev_sysfs_del(local);
+ ieee80211_cfg_exit(local);
+
for (i = 0; i < NUM_IEEE80211_MODES; i++) {
kfree(local->supp_rates[i]);
kfree(local->basic_rates[i]);
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/d80211/ieee80211_cfg.c 2006-08-22 15:47:48.000000000 +0200
@@ -0,0 +1,120 @@
+/*
+ * nl80211-based configuration for d80211
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+#include <net/nl80211.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include "ieee80211_cfg.h"
+#include "ieee80211_i.h"
+
+/* copied from ieee80211_sysfs.c for now ... */
+static inline int rtnl_lock_local(struct ieee80211_local *local)
+{
+ rtnl_lock();
+ if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) {
+ rtnl_unlock();
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int d80211_interfaces(void *priv, void *data,
+ int (*one)(void *data, int ifindex))
+{
+ struct ieee80211_local *local = priv;
+ struct ieee80211_sub_if_data *sdata;
+ int err = 0;
+
+ spin_lock_bh(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ err = one(data, sdata->dev->ifindex);
+ if (err)
+ break;
+ }
+ spin_unlock_bh(&local->sub_if_lock);
+ return err;
+}
+
+static int d80211_inject(void *priv, void *frame, int framelen, u32 flags,
+ int queue)
+{
+ struct ieee80211_local *local = priv;
+ struct ieee80211_tx_packet_data *pkt_data;
+ struct sk_buff *pkt;
+ void *pktdata;
+
+ pkt = alloc_skb(framelen, GFP_KERNEL);
+ pktdata = skb_put(pkt, framelen);
+ memcpy(pktdata, frame, framelen);
+
+ pkt_data = (struct ieee80211_tx_packet_data *) pkt->cb;
+ memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
+ pkt_data->ifindex = local->mdev->ifindex;
+ pkt_data->internal_flags = TX_FLAG_INJECTED;
+ pkt_data->flags = flags;
+ /* FIXME: never used, I think? Or could be invalid? */
+ pkt_data->queue = queue;
+
+ /* FIXME */
+ pkt->priority = 20; /* use hardcoded priority for mgmt TX queue */
+
+ pkt->dev = local->mdev;
+ dev_queue_xmit(pkt);
+
+ return 0;
+}
+
+static int d80211_add_virtual_intf(void *priv, char *name)
+{
+ struct ieee80211_local *local = priv;
+ struct net_device *new_dev;
+ int res;
+
+ res = rtnl_lock_local(local);
+ if (res)
+ return res;
+
+ res = ieee80211_if_add(local->mdev, name, 0, &new_dev);
+ if (res == 0)
+ ieee80211_if_set_type(new_dev, IEEE80211_IF_TYPE_STA);
+ rtnl_unlock();
+ return res;
+}
+
+static int d80211_del_virtual_intf(void *priv, int ifindex)
+{
+ struct ieee80211_local *local = priv;
+ int res;
+ struct net_device *dev;
+ char *name;
+
+ res = rtnl_lock_local(local);
+ if (res)
+ return res;
+ dev = dev_get_by_index(ifindex);
+ name = dev->name;
+ dev_put(dev);
+
+ res = ieee80211_if_remove(local->mdev, name, -1);
+ rtnl_unlock();
+ return res;
+}
+
+static struct nl80211_ops d80211nl = {
+ .list_interfaces = d80211_interfaces,
+ .inject_packet = d80211_inject,
+ .add_virtual_intf = d80211_add_virtual_intf,
+ .del_virtual_intf = d80211_del_virtual_intf,
+};
+
+int ieee80211_cfg_init(struct ieee80211_local *local)
+{
+ return nl80211_register(&d80211nl, local);
+}
+
+void ieee80211_cfg_exit(struct ieee80211_local *local)
+{
+ nl80211_unregister(local);
+}
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/d80211/ieee80211_cfg.h 2006-08-22 15:47:48.000000000 +0200
@@ -0,0 +1,9 @@
+#ifndef __IEEE80211_CFG_H
+#define __IEEE80211_CFG_H
+
+#include "ieee80211_i.h"
+
+extern int ieee80211_cfg_init(struct ieee80211_local *local);
+extern void ieee80211_cfg_exit(struct ieee80211_local *local);
+
+#endif /* __IEEE80211_CFG_H */
--- wireless-dev.orig/net/d80211/ieee80211_i.h 2006-08-22 15:47:45.000000000 +0200
+++ wireless-dev/net/d80211/ieee80211_i.h 2006-08-22 15:47:48.000000000 +0200
@@ -153,12 +153,13 @@ struct ieee80211_txrx_data {
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;
+/* we simply re-use NL80211_FLAG_* here */
+ unsigned int flags;
+ unsigned int queue;
+#define TX_FLAG_INJECTED (1<<0)
+#define TX_FLAG_REQUEUE (1<<1)
+#define TX_FLAG_PROBERESP (1<<2)
+ unsigned int internal_flags;
};
struct ieee80211_tx_stored_packet {
--- wireless-dev.orig/net/d80211/ieee80211_sta.c 2006-08-22 15:47:45.000000000 +0200
+++ wireless-dev/net/d80211/ieee80211_sta.c 2006-08-22 15:47:48.000000000 +0200
@@ -21,6 +21,7 @@
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <linux/random.h>
+#include <linux/nl80211.h>
#include <net/iw_handler.h>
#include <asm/types.h>
#include <asm/delay.h>
@@ -396,10 +397,12 @@ 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->ifindex = sdata->dev->ifindex;
- pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
- pkt_data->do_not_encrypt = !encrypt;
+ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->internal_flags |= TX_FLAG_INJECTED;
+ if (encrypt)
+ pkt_data->flags |= NL80211_FLAG_ENCRYPT;
if (probe_resp)
- pkt_data->pkt_probe_resp = 1;
+ pkt_data->internal_flags |= TX_FLAG_PROBERESP;
dev_queue_xmit(skb);
}
--- wireless-dev.orig/net/d80211/wme.c 2006-08-22 15:47:44.000000000 +0200
+++ wireless-dev/net/d80211/wme.c 2006-08-22 15:47:48.000000000 +0200
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/if_arp.h>
#include <linux/types.h>
+#include <linux/nl80211.h>
#include <net/ip.h>
#include <net/pkt_sched.h>
@@ -190,7 +191,8 @@ static inline int classify80211(struct s
return IEEE80211_TX_QUEUE_DATA0;
}
- if (unlikely(pkt_data->mgmt_iface)) {
+ /* FIXME: this needs to be revisited for more generic injection */
+ if (unlikely(pkt_data->internal_flags & TX_FLAG_INJECTED)) {
/* Data frames from hostapd (mainly, EAPOL) use AC_VO
* and they will include QoS control fields if
* the target STA is using WME. */
@@ -236,7 +238,7 @@ static int wme_qdiscop_enqueue(struct sk
struct Qdisc *qdisc;
int err, queue;
- if (pkt_data->requeue) {
+ if (pkt_data->internal_flags & TX_FLAG_REQUEUE) {
skb_queue_tail(&q->requeued[pkt_data->queue], skb);
return 0;
}
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [RFC] make d80211 use nl80211
2006-08-22 13:53 [RFC] make d80211 use nl80211 Johannes Berg
@ 2006-08-24 14:05 ` Jiri Benc
2006-08-24 16:07 ` Johannes Berg
1 sibling, 0 replies; 6+ messages in thread
From: Jiri Benc @ 2006-08-24 14:05 UTC (permalink / raw)
To: Johannes Berg; +Cc: netdev, John W. Linville
On Tue, 22 Aug 2006 15:53:33 +0200, Johannes Berg wrote:
> This patch makes d80211 partially configurable using the
> infrastructure that nl80211 provides. So far, it allows
> packet injection and adding/removing virtual interfaces.
Just minor things:
> [...]
> --- wireless-dev.orig/net/d80211/ieee80211.c 2006-08-22 15:47:46.000000000 +0200
> +++ wireless-dev/net/d80211/ieee80211.c 2006-08-22 15:47:48.000000000 +0200
> [...]
> @@ -4323,6 +4363,7 @@ struct net_device *ieee80211_alloc_hw(si
> priv_size = ((sizeof(struct ieee80211_sub_if_data) +
> NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) +
> priv_data_len;
> +
> mdev = alloc_netdev(priv_size, "wmaster%d", ether_setup);
> if (!mdev) {
> ieee80211_dev_free(local);
Remove this hunk, please.
> [...]
> +static int d80211_interfaces(void *priv, void *data,
> + int (*one)(void *data, int ifindex))
Please use ieee80211_ prefix, not d80211_.
> [...]
> +static int d80211_inject(void *priv, void *frame, int framelen, u32 flags,
> + int queue)
> +{
> + struct ieee80211_local *local = priv;
> + struct ieee80211_tx_packet_data *pkt_data;
> + struct sk_buff *pkt;
> + void *pktdata;
> +
> + pkt = alloc_skb(framelen, GFP_KERNEL);
> + pktdata = skb_put(pkt, framelen);
> + memcpy(pktdata, frame, framelen);
> +
> + pkt_data = (struct ieee80211_tx_packet_data *) pkt->cb;
> + memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
This is not necessary, cb is zeroed in alloc_skb.
Thanks,
Jiri
--
Jiri Benc
SUSE Labs
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [RFC] make d80211 use nl80211
2006-08-22 13:53 [RFC] make d80211 use nl80211 Johannes Berg
2006-08-24 14:05 ` Jiri Benc
@ 2006-08-24 16:07 ` Johannes Berg
2006-08-24 17:09 ` Michael Buesch
2006-08-25 11:02 ` [RFC take3] " Johannes Berg
1 sibling, 2 replies; 6+ messages in thread
From: Johannes Berg @ 2006-08-24 16:07 UTC (permalink / raw)
To: netdev; +Cc: Jiri Benc, John W. Linville
new version of this one too...
--
Subject: d80211: use nl80211
This patch makes d80211 partially configurable using the
infrastructure that nl80211 provides. So far, it allows
packet injection and adding/removing virtual interfaces.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
--- wireless-dev.orig/net/d80211/Kconfig 2006-08-24 18:04:28.000000000 +0200
+++ wireless-dev/net/d80211/Kconfig 2006-08-24 18:04:39.000000000 +0200
@@ -3,6 +3,7 @@ config D80211
select CRYPTO
select CRYPTO_ARC4
select CRYPTO_AES
+ select NETLINK_80211
---help---
This option enables the hardware independent IEEE 802.11
networking stack.
--- wireless-dev.orig/net/d80211/Makefile 2006-08-24 18:04:28.000000000 +0200
+++ wireless-dev/net/d80211/Makefile 2006-08-24 18:04:39.000000000 +0200
@@ -8,6 +8,7 @@ obj-$(CONFIG_D80211) += 80211.o rate_con
sta_info.o \
wep.o \
wpa.o \
+ ieee80211_cfg.o \
ieee80211_scan.o \
ieee80211_sta.o \
ieee80211_dev.o \
--- wireless-dev.orig/net/d80211/ieee80211.c 2006-08-24 18:04:28.000000000 +0200
+++ wireless-dev/net/d80211/ieee80211.c 2006-08-24 18:04:39.000000000 +0200
@@ -20,6 +20,7 @@
#include <net/iw_handler.h>
#include <linux/compiler.h>
#include <linux/bitmap.h>
+#include <linux/nl80211.h>
#include <net/d80211.h>
#include <net/d80211_common.h>
@@ -32,6 +33,7 @@
#include "wme.h"
#include "aes_ccm.h"
#include "ieee80211_led.h"
+#include "ieee80211_cfg.h"
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
@@ -348,6 +350,16 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
{
struct rate_control_extra extra;
+ /* FIXME
+ if (tx->dev == tx->local->mdev &&
+ (inject rate set)) {
+ a
+ tx->u.tx.rate = ...
+ etc etc
+ return TXRX_CONTINUE;
+ }
+ */
+
memset(&extra, 0, sizeof(extra));
extra.mgmt_data = tx->sdata &&
tx->sdata->type == IEEE80211_IF_TYPE_MGMT;
@@ -753,6 +765,13 @@ ieee80211_tx_h_misc(struct ieee80211_txr
u16 dur;
struct ieee80211_tx_control *control = tx->u.tx.control;
+ /* FIXME
+ if (tx->dev == tx->local->mdev) {
+ set up retry limit, ...
+ based on injection parameters
+ }
+ */
+
if (!is_multicast_ether_addr(hdr->addr1)) {
if (tx->skb->len + FCS_LEN > tx->local->rts_threshold &&
tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) {
@@ -878,6 +897,9 @@ ieee80211_tx_h_check_assoc(struct ieee80
#endif /* CONFIG_D80211_VERBOSE_DEBUG */
u32 sta_flags;
+ if (unlikely(tx->dev == tx->local->mdev))
+ return TXRX_CONTINUE;
+
if (unlikely(tx->local->sta_scanning != 0) &&
((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
(tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
@@ -981,6 +1003,12 @@ static void purge_old_ps_buffers(struct
static inline ieee80211_txrx_result
ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
{
+ /* FIXME
+ if (unlikely(tx->dev == tx->local->mdev &&
+ (inject flags) & NL80211_FLAG_NOBUFFER))
+ return TXRX_CONTINUE;
+ */
+
/* broadcast/multicast frame */
/* If any of the associated stations is in power save mode,
* the frame is buffered to be sent after DTIM beacon frame */
@@ -1408,11 +1436,12 @@ static int ieee80211_master_start_xmit(s
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.req_tx_status = !!(pkt_data->flags & NL80211_FLAG_TXSTATUS);
+ control.do_not_encrypt = !(pkt_data->flags & NL80211_FLAG_ENCRYPT);
control.pkt_type =
- pkt_data->pkt_probe_resp ? PKT_PROBE_RESP : PKT_NORMAL;
- control.requeue = pkt_data->requeue;
+ (pkt_data->internal_flags & TX_FLAG_PROBERESP) ?
+ PKT_PROBE_RESP : PKT_NORMAL;
+ control.requeue = !!(pkt_data->internal_flags & TX_FLAG_REQUEUE);
control.queue = pkt_data->queue;
ret = ieee80211_tx(odev, skb, &control,
@@ -1588,8 +1617,10 @@ static int ieee80211_subif_start_xmit(st
pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
pkt_data->ifindex = sdata->dev->ifindex;
- pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
- pkt_data->do_not_encrypt = no_encrypt;
+ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->internal_flags |= TX_FLAG_INJECTED;
+ if (!no_encrypt)
+ pkt_data->flags |= NL80211_FLAG_ENCRYPT;
skb->dev = sdata->master;
sdata->stats.tx_packets++;
@@ -1640,11 +1671,12 @@ 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->ifindex = sdata->dev->ifindex;
- pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
+ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->internal_flags |= TX_FLAG_INJECTED;
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
(fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)
- pkt_data->pkt_probe_resp = 1;
+ pkt_data->internal_flags |= TX_FLAG_PROBERESP;
skb->priority = 20; /* use hardcoded priority for mgmt TX queue */
skb->dev = sdata->master;
@@ -1654,12 +1686,13 @@ ieee80211_mgmt_start_xmit(struct sk_buff
* to request TX callback for hostapd. BIT(1) is checked.
*/
if ((fc & BIT(1)) == BIT(1)) {
- pkt_data->req_tx_status = 1;
+ pkt_data->flags |= NL80211_FLAG_TXSTATUS;
fc &= ~BIT(1);
hdr->frame_control = cpu_to_le16(fc);
}
- pkt_data->do_not_encrypt = !(fc & IEEE80211_FCTL_PROTECTED);
+ if (fc & IEEE80211_FCTL_PROTECTED)
+ pkt_data->flags |= NL80211_FLAG_ENCRYPT;
sdata->stats.tx_packets++;
sdata->stats.tx_bytes += skb->len;
@@ -2713,7 +2746,7 @@ static int ap_sta_ps_end(struct net_devi
while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
sent++;
- pkt_data->requeue = 1;
+ pkt_data->internal_flags |= TX_FLAG_REQUEUE;
dev_queue_xmit(skb);
}
while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
@@ -2725,7 +2758,7 @@ static int ap_sta_ps_end(struct net_devi
"since STA not sleeping anymore\n", dev->name,
MAC_ARG(sta->addr), sta->aid);
#endif /* CONFIG_D80211_VERBOSE_PS_DEBUG */
- pkt_data->requeue = 1;
+ pkt_data->internal_flags |= TX_FLAG_REQUEUE;
dev_queue_xmit(skb);
}
@@ -3959,12 +3992,19 @@ 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->flags = 0;
+ pkt_data->internal_flags = 0;
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);
- pkt_data->requeue = control->requeue;
+ if (control->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->internal_flags |= TX_FLAG_INJECTED;
+ if (control->req_tx_status)
+ pkt_data->flags |= NL80211_FLAG_TXSTATUS;
+ if (!control->do_not_encrypt)
+ pkt_data->flags |= NL80211_FLAG_ENCRYPT;
+ if (control->pkt_type == PKT_PROBE_RESP)
+ pkt_data->internal_flags |= TX_FLAG_PROBERESP;
+ if (control->requeue)
+ pkt_data->internal_flags |= TX_FLAG_REQUEUE;
pkt_data->queue = control->queue;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -4425,6 +4465,9 @@ int ieee80211_register_hw(struct net_dev
if (result < 0)
return -1;
+ if (ieee80211_cfg_init(local) < 0)
+ goto fail_nl80211;
+
local->class_dev.dev = dev->class_dev.dev;
result = ieee80211_dev_sysfs_add(local);
if (result < 0)
@@ -4511,6 +4554,8 @@ fail_dev:
fail_sta_info:
ieee80211_dev_sysfs_del(local);
fail_sysfs:
+ ieee80211_cfg_exit(local);
+fail_nl80211:
ieee80211_dev_free_index(local);
return result;
}
@@ -4593,6 +4638,8 @@ void ieee80211_unregister_hw(struct net_
&local->class_dev.kobj);
ieee80211_dev_sysfs_del(local);
+ ieee80211_cfg_exit(local);
+
for (i = 0; i < NUM_IEEE80211_MODES; i++) {
kfree(local->supp_rates[i]);
kfree(local->basic_rates[i]);
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/d80211/ieee80211_cfg.c 2006-08-24 18:04:39.000000000 +0200
@@ -0,0 +1,143 @@
+/*
+ * nl80211-based configuration for d80211
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+#include <net/nl80211.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include "ieee80211_cfg.h"
+#include "ieee80211_i.h"
+
+/* copied from ieee80211_sysfs.c for now ... */
+static inline int rtnl_lock_local(struct ieee80211_local *local)
+{
+ rtnl_lock();
+ if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) {
+ rtnl_unlock();
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int ieee80211_interfaces(void *priv, void *data,
+ int (*one)(void *data, int ifindex))
+{
+ struct ieee80211_local *local = priv;
+ struct ieee80211_sub_if_data *sdata;
+ int err = 0;
+
+ spin_lock_bh(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ err = one(data, sdata->dev->ifindex);
+ if (err)
+ break;
+ }
+ spin_unlock_bh(&local->sub_if_lock);
+ return err;
+}
+
+static int ieee80211_inject(void *priv, void *frame, int framelen, u32 flags,
+ int queue)
+{
+ struct ieee80211_local *local = priv;
+ struct ieee80211_tx_packet_data *pkt_data;
+ struct sk_buff *pkt;
+ void *pktdata;
+
+ pkt = alloc_skb(framelen, GFP_KERNEL);
+ pktdata = skb_put(pkt, framelen);
+ memcpy(pktdata, frame, framelen);
+
+ pkt_data = (struct ieee80211_tx_packet_data *) pkt->cb;
+ pkt_data->ifindex = local->mdev->ifindex;
+ pkt_data->internal_flags = TX_FLAG_INJECTED;
+ pkt_data->flags = flags;
+ /* FIXME: never used, I think? Or could be invalid? */
+ pkt_data->queue = queue;
+
+ /* FIXME */
+ pkt->priority = 20; /* use hardcoded priority for mgmt TX queue */
+
+ pkt->dev = local->mdev;
+ dev_queue_xmit(pkt);
+
+ return 0;
+}
+
+static int ieee80211_add_virtual_intf(void *priv, char *name,
+ unsigned int type)
+{
+ struct ieee80211_local *local = priv;
+ struct net_device *new_dev;
+ int res, itype;
+
+ switch (type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ itype = IEEE80211_IF_TYPE_STA;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ itype = IEEE80211_IF_TYPE_IBSS;
+ break;
+ case NL80211_IFTYPE_STATION:
+ itype = IEEE80211_IF_TYPE_STA;
+ break;
+ case NL80211_IFTYPE_AP:
+ itype = IEEE80211_IF_TYPE_AP;
+ break;
+ case NL80211_IFTYPE_WDS:
+ itype = IEEE80211_IF_TYPE_WDS;
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ itype = IEEE80211_IF_TYPE_MNTR;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ res = rtnl_lock_local(local);
+ if (res)
+ return res;
+
+ res = ieee80211_if_add(local->mdev, name, 0, &new_dev);
+ if (res == 0)
+ ieee80211_if_set_type(new_dev, itype);
+ rtnl_unlock();
+ return res;
+}
+
+static int ieee80211_del_virtual_intf(void *priv, int ifindex)
+{
+ struct ieee80211_local *local = priv;
+ int res;
+ struct net_device *dev;
+ char *name;
+
+ res = rtnl_lock_local(local);
+ if (res)
+ return res;
+ dev = dev_get_by_index(ifindex);
+ name = dev->name;
+ dev_put(dev);
+
+ res = ieee80211_if_remove(local->mdev, name, -1);
+ rtnl_unlock();
+ return res;
+}
+
+static struct nl80211_ops d80211nl = {
+ .list_interfaces = ieee80211_interfaces,
+ .inject_packet = ieee80211_inject,
+ .add_virtual_intf = ieee80211_add_virtual_intf,
+ .del_virtual_intf = ieee80211_del_virtual_intf,
+};
+
+int ieee80211_cfg_init(struct ieee80211_local *local)
+{
+ return nl80211_register(&d80211nl, local);
+}
+
+void ieee80211_cfg_exit(struct ieee80211_local *local)
+{
+ nl80211_unregister(local);
+}
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/d80211/ieee80211_cfg.h 2006-08-24 18:04:39.000000000 +0200
@@ -0,0 +1,9 @@
+#ifndef __IEEE80211_CFG_H
+#define __IEEE80211_CFG_H
+
+#include "ieee80211_i.h"
+
+extern int ieee80211_cfg_init(struct ieee80211_local *local);
+extern void ieee80211_cfg_exit(struct ieee80211_local *local);
+
+#endif /* __IEEE80211_CFG_H */
--- wireless-dev.orig/net/d80211/ieee80211_i.h 2006-08-24 18:04:29.000000000 +0200
+++ wireless-dev/net/d80211/ieee80211_i.h 2006-08-24 18:04:39.000000000 +0200
@@ -153,12 +153,13 @@ struct ieee80211_txrx_data {
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;
+/* we simply re-use NL80211_FLAG_* here */
+ unsigned int flags;
+ unsigned int queue;
+#define TX_FLAG_INJECTED (1<<0)
+#define TX_FLAG_REQUEUE (1<<1)
+#define TX_FLAG_PROBERESP (1<<2)
+ unsigned int internal_flags;
};
struct ieee80211_tx_stored_packet {
--- wireless-dev.orig/net/d80211/ieee80211_sta.c 2006-08-24 18:04:29.000000000 +0200
+++ wireless-dev/net/d80211/ieee80211_sta.c 2006-08-24 18:04:39.000000000 +0200
@@ -21,6 +21,7 @@
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <linux/random.h>
+#include <linux/nl80211.h>
#include <net/iw_handler.h>
#include <asm/types.h>
#include <asm/delay.h>
@@ -396,10 +397,12 @@ 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->ifindex = sdata->dev->ifindex;
- pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
- pkt_data->do_not_encrypt = !encrypt;
+ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->internal_flags |= TX_FLAG_INJECTED;
+ if (encrypt)
+ pkt_data->flags |= NL80211_FLAG_ENCRYPT;
if (probe_resp)
- pkt_data->pkt_probe_resp = 1;
+ pkt_data->internal_flags |= TX_FLAG_PROBERESP;
dev_queue_xmit(skb);
}
--- wireless-dev.orig/net/d80211/wme.c 2006-08-24 18:04:29.000000000 +0200
+++ wireless-dev/net/d80211/wme.c 2006-08-24 18:04:39.000000000 +0200
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/if_arp.h>
#include <linux/types.h>
+#include <linux/nl80211.h>
#include <net/ip.h>
#include <net/pkt_sched.h>
@@ -190,7 +191,8 @@ static inline int classify80211(struct s
return IEEE80211_TX_QUEUE_DATA0;
}
- if (unlikely(pkt_data->mgmt_iface)) {
+ /* FIXME: this needs to be revisited for more generic injection */
+ if (unlikely(pkt_data->internal_flags & TX_FLAG_INJECTED)) {
/* Data frames from hostapd (mainly, EAPOL) use AC_VO
* and they will include QoS control fields if
* the target STA is using WME. */
@@ -236,7 +238,7 @@ static int wme_qdiscop_enqueue(struct sk
struct Qdisc *qdisc;
int err, queue;
- if (pkt_data->requeue) {
+ if (pkt_data->internal_flags & TX_FLAG_REQUEUE) {
skb_queue_tail(&q->requeued[pkt_data->queue], skb);
return 0;
}
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [RFC] make d80211 use nl80211
2006-08-24 16:07 ` Johannes Berg
@ 2006-08-24 17:09 ` Michael Buesch
2006-08-24 17:36 ` Thomas Graf
2006-08-25 11:02 ` [RFC take3] " Johannes Berg
1 sibling, 1 reply; 6+ messages in thread
From: Michael Buesch @ 2006-08-24 17:09 UTC (permalink / raw)
To: Johannes Berg; +Cc: Jiri Benc, John W. Linville, netdev
On Thursday 24 August 2006 18:07, Johannes Berg wrote:
> new version of this one too...
> --
> Subject: d80211: use nl80211
>
> This patch makes d80211 partially configurable using the
> infrastructure that nl80211 provides. So far, it allows
> packet injection and adding/removing virtual interfaces.
>
> Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
>
> +static int ieee80211_inject(void *priv, void *frame, int framelen, u32 flags,
> + int queue)
> +{
> + struct ieee80211_local *local = priv;
> + struct ieee80211_tx_packet_data *pkt_data;
> + struct sk_buff *pkt;
> + void *pktdata;
> +
> + pkt = alloc_skb(framelen, GFP_KERNEL);
if (!pkt)
return -ENOMEM;
> + pktdata = skb_put(pkt, framelen);
> + memcpy(pktdata, frame, framelen);
having two variables with almost the same name seems
confusing to me. What about removing void *pktdata; and
doing the following instead of the two lines above?
memcpy(skb_put(pkt, framelen), frame, framelen);
That is also how it's done in lots of other networking code.
> + pkt_data = (struct ieee80211_tx_packet_data *) pkt->cb;
> + pkt_data->ifindex = local->mdev->ifindex;
> + pkt_data->internal_flags = TX_FLAG_INJECTED;
> + pkt_data->flags = flags;
> + /* FIXME: never used, I think? Or could be invalid? */
> + pkt_data->queue = queue;
> +
> + /* FIXME */
> + pkt->priority = 20; /* use hardcoded priority for mgmt TX queue */
> +
> + pkt->dev = local->mdev;
> + dev_queue_xmit(pkt);
> +
> + return 0;
> +}
The other code looks fine to me (the add nl80211 patch, too).
--
Greetings Michael.
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [RFC] make d80211 use nl80211
2006-08-24 17:09 ` Michael Buesch
@ 2006-08-24 17:36 ` Thomas Graf
0 siblings, 0 replies; 6+ messages in thread
From: Thomas Graf @ 2006-08-24 17:36 UTC (permalink / raw)
To: Michael Buesch; +Cc: Johannes Berg, Jiri Benc, John W. Linville, netdev
* Michael Buesch <mb@bu3sch.de> 2006-08-24 19:09
> On Thursday 24 August 2006 18:07, Johannes Berg wrote:
> > + pkt = alloc_skb(framelen, GFP_KERNEL);
>
> if (!pkt)
> return -ENOMEM;
>
> > + pktdata = skb_put(pkt, framelen);
> > + memcpy(pktdata, frame, framelen);
>
> having two variables with almost the same name seems
> confusing to me. What about removing void *pktdata; and
> doing the following instead of the two lines above?
>
> memcpy(skb_put(pkt, framelen), frame, framelen);
>
> That is also how it's done in lots of other networking code.
You might want to use 'skb' instead of 'pkt', everyone
has got used to it.
^ permalink raw reply [flat|nested] 6+ messages in thread
* [RFC take3] make d80211 use nl80211
2006-08-24 16:07 ` Johannes Berg
2006-08-24 17:09 ` Michael Buesch
@ 2006-08-25 11:02 ` Johannes Berg
1 sibling, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2006-08-25 11:02 UTC (permalink / raw)
To: netdev; +Cc: Jiri Benc, John W. Linville
This patch makes d80211 partially configurable using the
infrastructure that nl80211 provides. So far, it allows
packet injection and adding/removing virtual interfaces.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
--- wireless-dev.orig/net/d80211/Kconfig 2006-08-25 11:31:01.000000000 +0200
+++ wireless-dev/net/d80211/Kconfig 2006-08-25 11:32:38.000000000 +0200
@@ -3,6 +3,7 @@ config D80211
select CRYPTO
select CRYPTO_ARC4
select CRYPTO_AES
+ select NETLINK_80211
---help---
This option enables the hardware independent IEEE 802.11
networking stack.
--- wireless-dev.orig/net/d80211/Makefile 2006-08-25 11:31:01.000000000 +0200
+++ wireless-dev/net/d80211/Makefile 2006-08-25 11:32:38.000000000 +0200
@@ -8,6 +8,7 @@ obj-$(CONFIG_D80211) += 80211.o rate_con
sta_info.o \
wep.o \
wpa.o \
+ ieee80211_cfg.o \
ieee80211_scan.o \
ieee80211_sta.o \
ieee80211_dev.o \
--- wireless-dev.orig/net/d80211/ieee80211.c 2006-08-25 11:31:01.000000000 +0200
+++ wireless-dev/net/d80211/ieee80211.c 2006-08-25 11:32:38.000000000 +0200
@@ -20,6 +20,7 @@
#include <net/iw_handler.h>
#include <linux/compiler.h>
#include <linux/bitmap.h>
+#include <linux/nl80211.h>
#include <net/d80211.h>
#include <net/d80211_common.h>
@@ -32,6 +33,7 @@
#include "wme.h"
#include "aes_ccm.h"
#include "ieee80211_led.h"
+#include "ieee80211_cfg.h"
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
@@ -354,6 +356,16 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
{
struct rate_control_extra extra;
+ /* FIXME
+ if (tx->dev == tx->local->mdev &&
+ (inject rate set)) {
+ a
+ tx->u.tx.rate = ...
+ etc etc
+ return TXRX_CONTINUE;
+ }
+ */
+
memset(&extra, 0, sizeof(extra));
extra.mgmt_data = tx->sdata &&
tx->sdata->type == IEEE80211_IF_TYPE_MGMT;
@@ -759,6 +771,13 @@ ieee80211_tx_h_misc(struct ieee80211_txr
u16 dur;
struct ieee80211_tx_control *control = tx->u.tx.control;
+ /* FIXME
+ if (tx->dev == tx->local->mdev) {
+ set up retry limit, ...
+ based on injection parameters
+ }
+ */
+
if (!is_multicast_ether_addr(hdr->addr1)) {
if (tx->skb->len + FCS_LEN > tx->local->rts_threshold &&
tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) {
@@ -884,6 +903,9 @@ ieee80211_tx_h_check_assoc(struct ieee80
#endif /* CONFIG_D80211_VERBOSE_DEBUG */
u32 sta_flags;
+ if (unlikely(tx->dev == tx->local->mdev))
+ return TXRX_CONTINUE;
+
if (unlikely(tx->local->sta_scanning != 0) &&
((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
(tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
@@ -987,6 +1009,12 @@ static void purge_old_ps_buffers(struct
static inline ieee80211_txrx_result
ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
{
+ /* FIXME
+ if (unlikely(tx->dev == tx->local->mdev &&
+ (inject flags) & NL80211_FLAG_NOBUFFER))
+ return TXRX_CONTINUE;
+ */
+
/* broadcast/multicast frame */
/* If any of the associated stations is in power save mode,
* the frame is buffered to be sent after DTIM beacon frame */
@@ -1414,11 +1442,12 @@ static int ieee80211_master_start_xmit(s
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.req_tx_status = !!(pkt_data->flags & NL80211_FLAG_TXSTATUS);
+ control.do_not_encrypt = !(pkt_data->flags & NL80211_FLAG_ENCRYPT);
control.pkt_type =
- pkt_data->pkt_probe_resp ? PKT_PROBE_RESP : PKT_NORMAL;
- control.requeue = pkt_data->requeue;
+ (pkt_data->internal_flags & TX_FLAG_PROBERESP) ?
+ PKT_PROBE_RESP : PKT_NORMAL;
+ control.requeue = !!(pkt_data->internal_flags & TX_FLAG_REQUEUE);
control.queue = pkt_data->queue;
ret = ieee80211_tx(odev, skb, &control,
@@ -1594,8 +1623,10 @@ static int ieee80211_subif_start_xmit(st
pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
pkt_data->ifindex = sdata->dev->ifindex;
- pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
- pkt_data->do_not_encrypt = no_encrypt;
+ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->internal_flags |= TX_FLAG_INJECTED;
+ if (!no_encrypt)
+ pkt_data->flags |= NL80211_FLAG_ENCRYPT;
skb->dev = sdata->master;
sdata->stats.tx_packets++;
@@ -1646,11 +1677,12 @@ 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->ifindex = sdata->dev->ifindex;
- pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
+ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->internal_flags |= TX_FLAG_INJECTED;
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
(fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)
- pkt_data->pkt_probe_resp = 1;
+ pkt_data->internal_flags |= TX_FLAG_PROBERESP;
skb->priority = 20; /* use hardcoded priority for mgmt TX queue */
skb->dev = sdata->master;
@@ -1660,12 +1692,13 @@ ieee80211_mgmt_start_xmit(struct sk_buff
* to request TX callback for hostapd. BIT(1) is checked.
*/
if ((fc & BIT(1)) == BIT(1)) {
- pkt_data->req_tx_status = 1;
+ pkt_data->flags |= NL80211_FLAG_TXSTATUS;
fc &= ~BIT(1);
hdr->frame_control = cpu_to_le16(fc);
}
- pkt_data->do_not_encrypt = !(fc & IEEE80211_FCTL_PROTECTED);
+ if (fc & IEEE80211_FCTL_PROTECTED)
+ pkt_data->flags |= NL80211_FLAG_ENCRYPT;
sdata->stats.tx_packets++;
sdata->stats.tx_bytes += skb->len;
@@ -2715,7 +2748,7 @@ static int ap_sta_ps_end(struct net_devi
while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
sent++;
- pkt_data->requeue = 1;
+ pkt_data->internal_flags |= TX_FLAG_REQUEUE;
dev_queue_xmit(skb);
}
while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
@@ -2727,7 +2760,7 @@ static int ap_sta_ps_end(struct net_devi
"since STA not sleeping anymore\n", dev->name,
MAC_ARG(sta->addr), sta->aid);
#endif /* CONFIG_D80211_VERBOSE_PS_DEBUG */
- pkt_data->requeue = 1;
+ pkt_data->internal_flags |= TX_FLAG_REQUEUE;
dev_queue_xmit(skb);
}
@@ -3958,12 +3991,19 @@ 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->flags = 0;
+ pkt_data->internal_flags = 0;
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);
- pkt_data->requeue = control->requeue;
+ if (control->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->internal_flags |= TX_FLAG_INJECTED;
+ if (control->req_tx_status)
+ pkt_data->flags |= NL80211_FLAG_TXSTATUS;
+ if (!control->do_not_encrypt)
+ pkt_data->flags |= NL80211_FLAG_ENCRYPT;
+ if (control->pkt_type == PKT_PROBE_RESP)
+ pkt_data->internal_flags |= TX_FLAG_PROBERESP;
+ if (control->requeue)
+ pkt_data->internal_flags |= TX_FLAG_REQUEUE;
pkt_data->queue = control->queue;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -4422,6 +4462,9 @@ int ieee80211_register_hw(struct net_dev
if (result < 0)
return -1;
+ if (ieee80211_cfg_init(local) < 0)
+ goto fail_nl80211;
+
local->class_dev.dev = dev->class_dev.dev;
result = ieee80211_dev_sysfs_add(local);
if (result < 0)
@@ -4508,6 +4551,8 @@ fail_dev:
fail_sta_info:
ieee80211_dev_sysfs_del(local);
fail_sysfs:
+ ieee80211_cfg_exit(local);
+fail_nl80211:
ieee80211_dev_free_index(local);
return result;
}
@@ -4589,6 +4634,8 @@ void ieee80211_unregister_hw(struct net_
&local->class_dev.kobj);
ieee80211_dev_sysfs_del(local);
+ ieee80211_cfg_exit(local);
+
for (i = 0; i < NUM_IEEE80211_MODES; i++) {
kfree(local->supp_rates[i]);
kfree(local->basic_rates[i]);
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/d80211/ieee80211_cfg.c 2006-08-25 11:32:38.000000000 +0200
@@ -0,0 +1,144 @@
+/*
+ * nl80211-based configuration for d80211
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+#include <net/nl80211.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include "ieee80211_cfg.h"
+#include "ieee80211_i.h"
+
+/* copied from ieee80211_sysfs.c for now ... */
+static inline int rtnl_lock_local(struct ieee80211_local *local)
+{
+ rtnl_lock();
+ if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) {
+ rtnl_unlock();
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int ieee80211_interfaces(void *priv, void *data,
+ int (*one)(void *data, int ifindex))
+{
+ struct ieee80211_local *local = priv;
+ struct ieee80211_sub_if_data *sdata;
+ int err = 0;
+
+ spin_lock_bh(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ err = one(data, sdata->dev->ifindex);
+ if (err)
+ break;
+ }
+ spin_unlock_bh(&local->sub_if_lock);
+ return err;
+}
+
+static int ieee80211_inject(void *priv, void *frame, int framelen, u32 flags,
+ int queue)
+{
+ struct ieee80211_local *local = priv;
+ struct ieee80211_tx_packet_data *pkt_data;
+ struct sk_buff *skb;
+
+ skb = alloc_skb(framelen, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ memcpy(skb_put(skb, framelen), frame, framelen);
+
+ pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ pkt_data->ifindex = local->mdev->ifindex;
+ pkt_data->internal_flags = TX_FLAG_INJECTED;
+ pkt_data->flags = flags;
+ /* FIXME: never used, I think? Or could be invalid? */
+ pkt_data->queue = queue;
+
+ /* FIXME */
+ skb->priority = 20; /* use hardcoded priority for mgmt TX queue */
+
+ skb->dev = local->mdev;
+ dev_queue_xmit(skb);
+
+ return 0;
+}
+
+static int ieee80211_add_virtual_intf(void *priv, char *name,
+ unsigned int type)
+{
+ struct ieee80211_local *local = priv;
+ struct net_device *new_dev;
+ int res, itype;
+
+ switch (type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ itype = IEEE80211_IF_TYPE_STA;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ itype = IEEE80211_IF_TYPE_IBSS;
+ break;
+ case NL80211_IFTYPE_STATION:
+ itype = IEEE80211_IF_TYPE_STA;
+ break;
+ case NL80211_IFTYPE_AP:
+ itype = IEEE80211_IF_TYPE_AP;
+ break;
+ case NL80211_IFTYPE_WDS:
+ itype = IEEE80211_IF_TYPE_WDS;
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ itype = IEEE80211_IF_TYPE_MNTR;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ res = rtnl_lock_local(local);
+ if (res)
+ return res;
+
+ res = ieee80211_if_add(local->mdev, name, 0, &new_dev);
+ if (res == 0)
+ ieee80211_if_set_type(new_dev, itype);
+ rtnl_unlock();
+ return res;
+}
+
+static int ieee80211_del_virtual_intf(void *priv, int ifindex)
+{
+ struct ieee80211_local *local = priv;
+ int res;
+ struct net_device *dev;
+ char *name;
+
+ res = rtnl_lock_local(local);
+ if (res)
+ return res;
+ dev = dev_get_by_index(ifindex);
+ name = dev->name;
+ dev_put(dev);
+
+ res = ieee80211_if_remove(local->mdev, name, -1);
+ rtnl_unlock();
+ return res;
+}
+
+static struct nl80211_ops d80211nl = {
+ .list_interfaces = ieee80211_interfaces,
+ .inject_packet = ieee80211_inject,
+ .add_virtual_intf = ieee80211_add_virtual_intf,
+ .del_virtual_intf = ieee80211_del_virtual_intf,
+};
+
+int ieee80211_cfg_init(struct ieee80211_local *local)
+{
+ return nl80211_register(&d80211nl, local);
+}
+
+void ieee80211_cfg_exit(struct ieee80211_local *local)
+{
+ nl80211_unregister(local);
+}
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/d80211/ieee80211_cfg.h 2006-08-25 11:32:38.000000000 +0200
@@ -0,0 +1,9 @@
+#ifndef __IEEE80211_CFG_H
+#define __IEEE80211_CFG_H
+
+#include "ieee80211_i.h"
+
+extern int ieee80211_cfg_init(struct ieee80211_local *local);
+extern void ieee80211_cfg_exit(struct ieee80211_local *local);
+
+#endif /* __IEEE80211_CFG_H */
--- wireless-dev.orig/net/d80211/ieee80211_i.h 2006-08-25 11:31:01.000000000 +0200
+++ wireless-dev/net/d80211/ieee80211_i.h 2006-08-25 11:32:38.000000000 +0200
@@ -153,12 +153,13 @@ struct ieee80211_txrx_data {
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;
+/* we simply re-use NL80211_FLAG_* here */
+ unsigned int flags;
+ unsigned int queue;
+#define TX_FLAG_INJECTED (1<<0)
+#define TX_FLAG_REQUEUE (1<<1)
+#define TX_FLAG_PROBERESP (1<<2)
+ unsigned int internal_flags;
};
struct ieee80211_tx_stored_packet {
--- wireless-dev.orig/net/d80211/ieee80211_sta.c 2006-08-25 11:29:01.000000000 +0200
+++ wireless-dev/net/d80211/ieee80211_sta.c 2006-08-25 11:32:38.000000000 +0200
@@ -21,6 +21,7 @@
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <linux/random.h>
+#include <linux/nl80211.h>
#include <net/iw_handler.h>
#include <asm/types.h>
#include <asm/delay.h>
@@ -396,10 +397,12 @@ 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->ifindex = sdata->dev->ifindex;
- pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
- pkt_data->do_not_encrypt = !encrypt;
+ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->internal_flags |= TX_FLAG_INJECTED;
+ if (encrypt)
+ pkt_data->flags |= NL80211_FLAG_ENCRYPT;
if (probe_resp)
- pkt_data->pkt_probe_resp = 1;
+ pkt_data->internal_flags |= TX_FLAG_PROBERESP;
dev_queue_xmit(skb);
}
--- wireless-dev.orig/net/d80211/wme.c 2006-08-25 11:29:01.000000000 +0200
+++ wireless-dev/net/d80211/wme.c 2006-08-25 11:32:38.000000000 +0200
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/if_arp.h>
#include <linux/types.h>
+#include <linux/nl80211.h>
#include <net/ip.h>
#include <net/pkt_sched.h>
@@ -190,7 +191,8 @@ static inline int classify80211(struct s
return IEEE80211_TX_QUEUE_DATA0;
}
- if (unlikely(pkt_data->mgmt_iface)) {
+ /* FIXME: this needs to be revisited for more generic injection */
+ if (unlikely(pkt_data->internal_flags & TX_FLAG_INJECTED)) {
/* Data frames from hostapd (mainly, EAPOL) use AC_VO
* and they will include QoS control fields if
* the target STA is using WME. */
@@ -236,7 +238,7 @@ static int wme_qdiscop_enqueue(struct sk
struct Qdisc *qdisc;
int err, queue;
- if (pkt_data->requeue) {
+ if (pkt_data->internal_flags & TX_FLAG_REQUEUE) {
skb_queue_tail(&q->requeued[pkt_data->queue], skb);
return 0;
}
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2006-08-25 11:01 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-08-22 13:53 [RFC] make d80211 use nl80211 Johannes Berg
2006-08-24 14:05 ` Jiri Benc
2006-08-24 16:07 ` Johannes Berg
2006-08-24 17:09 ` Michael Buesch
2006-08-24 17:36 ` Thomas Graf
2006-08-25 11:02 ` [RFC take3] " Johannes Berg
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).