From: "John W. Linville" <linville@tuxdriver.com>
To: linux-wireless@vger.kernel.org
Cc: johannes@sipsolutions.net
Subject: [RFC PATCH 1/3] wireless: add cfg80211
Date: Tue, 6 Feb 2007 19:47:47 -0500 [thread overview]
Message-ID: <20070207004747.GB23096@tuxdriver.com> (raw)
In-Reply-To: <20070207004626.GA23096@tuxdriver.com>
From: Johannes Berg <johannes@sipsolutions.net>
This patch adds cfg80211, a new configuration system for wireless
hardware.
It currently features a bunch of configuration requests, support for
adding and removing virtual interfaces, the ability to inject packets and
more.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
include/linux/netdevice.h | 1 +
include/net/cfg80211.h | 186 ++++++++++++++++++++++++++++++++++++++++++++
net/Kconfig | 3 +
net/Makefile | 1 +
net/wireless/Makefile | 4 +
net/wireless/core.c | 158 +++++++++++++++++++++++++++++++++++++
net/wireless/core.h | 57 ++++++++++++++
net/wireless/wext-compat.c | 25 ++++++
8 files changed, 435 insertions(+), 0 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index fea0d9d..c1e9962 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -398,6 +398,7 @@ struct net_device
void *ip6_ptr; /* IPv6 specific data */
void *ec_ptr; /* Econet specific data */
void *ax25_ptr; /* AX.25 specific data */
+ void *ieee80211_ptr; /* IEEE 802.11 specific data */
/*
* Cache line mostly used on receive path (including eth_type_trans())
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
new file mode 100644
index 0000000..c0bc9d4
--- /dev/null
+++ b/include/net/cfg80211.h
@@ -0,0 +1,186 @@
+#ifndef __NET_CFG80211_H
+#define __NET_CFG80211_H
+
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/genetlink.h>
+
+/*
+ * 802.11 configuration in-kernel interface
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+
+/**
+ * struct cfg80211_config - description of a configuration (request)
+ */
+struct cfg80211_config {
+ /* first fields with 'internal' validity */
+
+ /* SSID to use, valid if not NULL, ssid_len then
+ * contains the length. change forces reassociation */
+ s8 ssid_len;
+ u8 *ssid;
+
+ /* now fields with explicit validity */
+#define CFG80211_CFG_VALID_NWID (1<<0)
+#define CFG80211_CFG_VALID_RX_SENSITIVITY (1<<1)
+#define CFG80211_CFG_VALID_TRANSMIT_POWER (1<<2)
+#define CFG80211_CFG_VALID_FRAG_THRESHOLD (1<<3)
+#define CFG80211_CFG_VALID_CHANNEL (1<<4)
+ unsigned int valid;
+
+ u16 network_id;
+ s32 rx_sensitivity;
+ u32 transmit_power;
+ u32 fragmentation_threshold;
+ u32 channel;
+};
+
+struct scan_channel {
+ u32 channel;
+ int active;
+};
+
+struct scan_params {
+ /* number of items in 'channels' array
+ * or -1 to indicate scanning all channels
+ * (in that case 'channels' is NULL) */
+ int n_channels;
+
+ /* use only when n_channels is -1 to determine
+ * whether scanning should be active or not */
+ int active;
+
+ /* the channel list if any */
+ struct scan_channel *channels;
+};
+
+/**
+ * struct cfg80211_ops - backend description for wireless configuration
+ *
+ * This struct is registered by fullmac card drivers and/or wireless stacks
+ * in order to handle configuration requests on their interfaces.
+ *
+ * The priv pointer passed to each call is the pointer that was
+ * registered in cfg80211_register_driver().
+ *
+ * All callbacks except where otherwise noted should return 0
+ * on success or a negative error code.
+ *
+ * @list_interfaces: for each interfaces belonging to the wiphy identified
+ * by the priv pointer, call the one() function with the
+ * given data and the ifindex. This callback is required.
+ *
+ * @inject_packet: inject the given frame with the NL80211_FLAG_*
+ * flags onto the given queue.
+ *
+ * @add_virtual_intf: create a new virtual interface with the given name
+ *
+ * @del_virtual_intf: remove the virtual interface determined by ifindex.
+ *
+ * @configure: configure the given interface as requested in the config struct.
+ * must not ignore any configuration item, if something is
+ * is requested that cannot be fulfilled return an error
+ *
+ * @get_config: fill the given config structure with the current configuration
+ *
+ * @reassociate: reassociate with current settings (SSID, BSSID if
+ * userspace roaming is enabled)
+ *
+ * @disassociate: disassociate from current AP
+ *
+ * @deauth: deauth from current AP
+ *
+ * @initiate_scan: ...
+ *
+ * @set_roaming: set who gets to control roaming, the roaming_control
+ * parameter is passed NL80211_ROAMING_CONTROL_* values.
+ *
+ * @get_roaming: return where roaming control currently is done or
+ * a negative error.
+ *
+ * @set_fixed_bssid: set BSSID to use with userspace roaming, forces
+ * reassociation if changing.
+ * @get_fixed_bssid: get BSSID that is used with userspace roaming,
+ * the bssid parameter has space for 6 bytes
+ *
+ * @get_association: get BSSID of the BSS that the device is currently
+ * associated to and return 1, or return 0 if not
+ * associated (or a negative error code)
+ * @get_auth_list: get list of BSSIDs of all BSSs the device has
+ * authenticated with, must call next_bssid for each,
+ * next_bssid returns non-zero on error, the given data
+ * is to be passed to that callback
+ */
+struct cfg80211_ops {
+ int (*list_interfaces)(void *priv, void *data,
+ int (*one)(void *data, int ifindex));
+
+
+ int (*inject_packet)(void *priv, void *frame, int framelen,
+ u32 flags, int queue);
+
+
+ int (*add_virtual_intf)(void *priv, char *name,
+ unsigned int type);
+ int (*del_virtual_intf)(void *priv, int ifindex);
+
+
+ int (*configure)(void *priv, struct net_device *dev,
+ struct cfg80211_config *cfg);
+ void (*get_config)(void *priv, struct net_device *dev,
+ struct cfg80211_config *cfg);
+
+
+ int (*reassociate)(void *priv, struct net_device *dev);
+ int (*disassociate)(void *priv, struct net_device *dev);
+ int (*deauth)(void *priv, struct net_device *dev);
+
+
+ int (*initiate_scan)(void *priv, struct net_device *dev,
+ struct scan_params *params);
+
+
+ int (*set_roaming)(void *priv, struct net_device *dev,
+ int roaming_control);
+ int (*get_roaming)(void *priv, struct net_device *dev);
+ int (*set_fixed_bssid)(void *priv, struct net_device *dev,
+ u8 *bssid);
+ int (*get_fixed_bssid)(void *priv, struct net_device *dev,
+ u8 *bssid);
+
+
+ int (*get_association)(void *priv, struct net_device *dev,
+ u8 *bssid);
+
+ int (*get_auth_list)(void *priv, struct net_device *dev,
+ void *data,
+ int (*next_bssid)(void *data, u8 *bssid));
+};
+
+/**
+ * cfg80211_register - register a wiphy with cfg80211
+ *
+ * register a given method structure with the cfg80211 system
+ * and associate the 'priv' pointer with it.
+ *
+ * Returns a non-negative wiphy index or a negative error code.
+ *
+ * NOTE: for proper operation, this priv pointer MUST also be
+ * assigned to each &struct net_device's @ieee80211_ptr member!
+ */
+extern int cfg80211_register(struct cfg80211_ops *ops, void *priv);
+
+/**
+ * cfg80211_unregister - deregister a wiphy from cfg80211
+ *
+ * unregister a device with the given priv pointer.
+ * After this call, no more requests can be made with this priv
+ * pointer, but the call may sleep to wait for an outstanding
+ * request that is being handled.
+ */
+extern void cfg80211_unregister(void *priv);
+
+#endif /* __NET_CFG80211_H */
diff --git a/net/Kconfig b/net/Kconfig
index 7dfc949..8d121a5 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -226,6 +226,9 @@ config WIRELESS_EXT
config FIB_RULES
bool
+config CFG80211
+ tristate "Improved wireless configuration API"
+
endif # if NET
endmenu # Networking
diff --git a/net/Makefile b/net/Makefile
index ad4d14f..278d6bf 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_ECONET) += econet/
obj-$(CONFIG_VLAN_8021Q) += 8021q/
obj-$(CONFIG_IP_DCCP) += dccp/
obj-$(CONFIG_IP_SCTP) += sctp/
+obj-$(CONFIG_CFG80211) += wireless/
obj-$(CONFIG_IEEE80211) += ieee80211/
obj-$(CONFIG_TIPC) += tipc/
obj-$(CONFIG_NETLABEL) += netlabel/
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
new file mode 100644
index 0000000..4a87dce
--- /dev/null
+++ b/net/wireless/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_CFG80211) += cfg80211.o
+
+cfg80211-objs := \
+ core.o
diff --git a/net/wireless/core.c b/net/wireless/core.c
new file mode 100644
index 0000000..60b280e
--- /dev/null
+++ b/net/wireless/core.c
@@ -0,0 +1,158 @@
+/*
+ * This is the new wireless configuration interface.
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include "core.h"
+#include <linux/if.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <net/genetlink.h>
+#include <net/cfg80211.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+
+MODULE_AUTHOR("Johannes Berg");
+MODULE_LICENSE("GPL");
+
+/* RCU might be appropriate here since we usually
+ * only read the list, and that can happen quite
+ * often because we need to do it for each command */
+LIST_HEAD(cfg80211_drv_list);
+DEFINE_MUTEX(cfg80211_drv_mutex);
+static int wiphy_counter;
+
+/* requires cfg80211_drv_mutex to be held! */
+static struct cfg80211_registered_driver *cfg80211_drv_by_priv(void *priv)
+{
+ struct cfg80211_registered_driver *result = NULL, *drv;
+
+ if (!priv)
+ return NULL;
+
+ list_for_each_entry(drv, &cfg80211_drv_list, list) {
+ if (drv->priv == priv) {
+ result = drv;
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* wext will need this */
+struct cfg80211_registered_driver *
+cfg80211_get_drv_from_ifindex(int ifindex)
+{
+ struct cfg80211_registered_driver *drv = ERR_PTR(-ENODEV);
+ struct net_device *dev;
+
+ mutex_lock(&cfg80211_drv_mutex);
+ dev = dev_get_by_index(ifindex);
+ if (!dev)
+ goto out;
+ drv = cfg80211_drv_by_priv(dev->ieee80211_ptr);
+ if (drv)
+ mutex_lock(&drv->mtx);
+ else
+ drv = ERR_PTR(-ENODEV);
+ dev_put(dev);
+ out:
+ mutex_unlock(&cfg80211_drv_mutex);
+ return drv;
+}
+
+void cfg80211_put_drv(struct cfg80211_registered_driver *drv)
+{
+ BUG_ON(IS_ERR(drv));
+ mutex_unlock(&drv->mtx);
+}
+
+/* exported functions */
+
+int cfg80211_register(struct cfg80211_ops *ops, void *priv)
+{
+ struct cfg80211_registered_driver *drv;
+ int res;
+
+ if (!priv || !ops->list_interfaces)
+ return -EINVAL;
+
+ mutex_lock(&cfg80211_drv_mutex);
+
+ if (cfg80211_drv_by_priv(priv)) {
+ res = -EALREADY;
+ goto out_unlock;
+ }
+
+ drv = kzalloc(sizeof(struct cfg80211_registered_driver), GFP_KERNEL);
+ if (!drv) {
+ res = -ENOMEM;
+ goto out_unlock;
+ }
+
+ drv->ops = ops;
+ drv->priv = priv;
+
+ if (unlikely(wiphy_counter<0)) {
+ /* ugh, wrapped! */
+ kfree(drv);
+ res = -ENOSPC;
+ goto out_unlock;
+ }
+ mutex_init(&drv->mtx);
+ drv->wiphy = wiphy_counter;
+ list_add(&drv->list, &cfg80211_drv_list);
+ /* return wiphy number */
+ res = drv->wiphy;
+
+ /* now increase counter for the next time */
+ wiphy_counter++;
+
+ out_unlock:
+ mutex_unlock(&cfg80211_drv_mutex);
+ return res;
+}
+EXPORT_SYMBOL_GPL(cfg80211_register);
+
+void cfg80211_unregister(void *priv)
+{
+ struct cfg80211_registered_driver *drv;
+
+ mutex_lock(&cfg80211_drv_mutex);
+ drv = cfg80211_drv_by_priv(priv);
+ if (!drv) {
+ printk(KERN_ERR "deregistering cfg80211 backend that "
+ " was never registered!\n");
+ mutex_unlock(&cfg80211_drv_mutex);
+ return;
+ }
+
+ /* hold registered driver mutex during list removal as well
+ * to make sure no commands are in progress at the moment */
+ mutex_lock(&drv->mtx);
+ list_del(&drv->list);
+ mutex_unlock(&drv->mtx);
+
+ mutex_unlock(&cfg80211_drv_mutex);
+
+ mutex_destroy(&drv->mtx);
+ kfree(drv);
+}
+EXPORT_SYMBOL_GPL(cfg80211_unregister);
+
+/* module initialisation/exit functions */
+
+static int cfg80211_init(void)
+{
+ /* possibly need to do more later */
+ return 0;
+}
+
+static void cfg80211_exit(void)
+{
+}
+
+module_init(cfg80211_init);
+module_exit(cfg80211_exit);
diff --git a/net/wireless/core.h b/net/wireless/core.h
new file mode 100644
index 0000000..562c476
--- /dev/null
+++ b/net/wireless/core.h
@@ -0,0 +1,57 @@
+/*
+ * Wireless configuration interface internals.
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+#ifndef __NET_WIRELESS_CORE_H
+#define __NET_WIRELESS_CORE_H
+#include <net/cfg80211.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <net/genetlink.h>
+
+struct cfg80211_registered_driver {
+ struct cfg80211_ops *ops;
+ int wiphy;
+ void *priv;
+ struct list_head list;
+ /* we hold this mutex during any call so that
+ * we cannot do multiple calls at once, and also
+ * to avoid the deregister call to proceed while
+ * any call is in progress */
+ struct mutex mtx;
+};
+
+extern struct mutex cfg80211_drv_mutex;
+extern struct list_head cfg80211_drv_list;
+
+/*
+ * This function returns a pointer to the driver
+ * that the genl_info item that is passed refers to.
+ * If successful, it returns non-NULL and also locks
+ * the driver's mutex!
+ *
+ * This means that you need to call cfg80211_put_drv()
+ * before being allowed to acquire &cfg80211_drv_mutex!
+ *
+ * This is necessary because we need to lock the global
+ * mutex to get an item off the list safely, and then
+ * we lock the drv mutex so it doesn't go away under us.
+ *
+ * We don't want to keep cfg80211_drv_mutex locked
+ * for all the time in order to allow requests on
+ * other interfaces to go through at the same time.
+ *
+ * The result of this can be a PTR_ERR and hence must
+ * be checked with IS_ERR() for errors.
+ */
+extern struct cfg80211_registered_driver *
+cfg80211_get_drv_from_info(struct genl_info *info);
+
+/* identical to cfg80211_get_drv_from_info but only operate on ifindex */
+extern struct cfg80211_registered_driver *
+cfg80211_get_drv_from_ifindex(int ifindex);
+
+extern void cfg80211_put_drv(struct cfg80211_registered_driver *drv);
+
+#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
new file mode 100644
index 0000000..1c7c361
--- /dev/null
+++ b/net/wireless/wext-compat.c
@@ -0,0 +1,25 @@
+/* NOT YET */
+
+To implement compatibility, we add a new field to struct net_device
+that contains the pending configuration structure. This is dynamically
+allocated when needed and freed when committed.
+In a way it replaces the wireless_handlers field in there which is now
+done by dynamic lookup. No worries. No one is going to have thousands
+of wireless devices, and if that changes we can still trivially change
+this assumption :)
+
+Commit is done some time after the last parameter was changed
+(with each parameter change simply (re-)schedule a timer) or
+if explicitly asked for. This is probably not what most people
+would expect, but perfectly fine in the WE API.
+
+compatibility mappings:
+
+SIOCSIWAP
+ -> if bssid is all-ones: set roaming to kernel, reassociate
+ -> if bssid is all-zeroes: set roaming to kernel
+ -> otherwise: set roaming to userspace, set bssid
+
+SIOCGIWAP
+ -> get association parameters and fill return bssid appropriately
+
--
1.4.4.2
--
John W. Linville
linville@tuxdriver.com
next prev parent reply other threads:[~2007-02-07 1:14 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-01-31 1:37 [RFC] cfg80211 merge John W. Linville
2007-01-31 1:38 ` [RFC PATCH 1/3] cfg80211 and nl80211 John W. Linville
2007-01-31 1:39 ` [RFC PATCH 2/3] wireless: move wext to net/wireless/ John W. Linville
2007-01-31 1:41 ` [RFC PATCH 3/3] cfg80211: add wext-compatible client John W. Linville
2007-01-31 14:40 ` [RFC PATCH 2/3] wireless: move wext to net/wireless/ Christoph Hellwig
2007-01-31 19:00 ` Johannes Berg
2007-01-31 2:46 ` [RFC PATCH 1/3] cfg80211 and nl80211 Michael Wu
2007-01-31 17:37 ` Jiri Benc
2007-01-31 20:24 ` Michael Buesch
2007-02-01 10:18 ` Johannes Berg
2007-02-05 17:45 ` Michael Wu
2007-02-05 17:49 ` Johannes Berg
2007-02-05 18:14 ` Michael Wu
2007-02-05 18:14 ` Johannes Berg
2007-02-05 18:29 ` Jiri Benc
2007-02-05 18:29 ` Johannes Berg
2007-02-05 19:13 ` Jouni Malinen
2007-02-05 19:23 ` Michael Wu
2007-02-05 19:24 ` Johannes Berg
2007-02-05 19:55 ` Michael Wu
2007-02-09 16:14 ` Johannes Berg
2007-02-05 18:16 ` Jiri Benc
2007-01-31 2:48 ` [RFC] cfg80211 merge Jouni Malinen
2007-01-31 17:29 ` Jiri Benc
2007-01-31 18:32 ` John W. Linville
2007-01-31 19:25 ` Jiri Benc
2007-01-31 20:07 ` Christoph Hellwig
2007-01-31 20:44 ` John W. Linville
2007-01-31 21:06 ` Johannes Berg
2007-01-31 23:54 ` Tomas Winkler
2007-02-01 13:07 ` Johannes Berg
2007-02-01 14:04 ` Tomas Winkler
2007-02-01 14:11 ` Johannes Berg
2007-02-02 18:18 ` Tomas Winkler
2007-02-03 17:37 ` Johannes Berg
2007-02-01 14:12 ` Jiri Benc
2007-02-07 0:46 ` [RFC v2] " John W. Linville
2007-02-07 0:47 ` John W. Linville [this message]
[not found] ` <20070207004832.GC23096@tuxdriver.com>
2007-02-07 0:49 ` [RFC PATCH 3/3] cfg80211: add wext-compatible client John W. Linville
2007-02-07 7:54 ` Christoph Hellwig
2007-02-08 13:13 ` Johannes Berg
2007-02-08 18:38 ` Luis R. Rodriguez
2007-02-08 18:50 ` John W. Linville
2007-02-08 19:41 ` Luis R. Rodriguez
2007-02-09 15:43 ` Johannes Berg
2007-02-08 19:55 ` Christoph Hellwig
2007-02-08 21:56 ` Luis R. Rodriguez
2007-02-09 2:09 ` Dan Williams
2007-02-07 7:35 ` [RFC PATCH 1/3] wireless: add cfg80211 Christoph Hellwig
2007-02-08 13:12 ` Johannes Berg
2007-02-08 19:17 ` Christoph Hellwig
2007-02-07 14:39 ` [RFC v2] cfg80211 merge John W. Linville
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070207004747.GB23096@tuxdriver.com \
--to=linville@tuxdriver.com \
--cc=johannes@sipsolutions.net \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).