From: Johannes Berg <johannes@sipsolutions.net>
To: netdev <netdev@vger.kernel.org>
Cc: Jiri Benc <jbenc@suse.cz>, "John W. Linville" <linville@tuxdriver.com>
Subject: [RFC] add nl80211
Date: Tue, 22 Aug 2006 15:52:47 +0200 [thread overview]
Message-ID: <1156254768.3825.1.camel@ux156> (raw)
This patch adds nl80211, a netlink based configuration
system for wireless hardware.
It currently features a few helper commands and commands to
add and remove virtual interfaces and to inject packets.
Support for nl80211 in d80211 is in a follow-up patch.
It requires the patches in
http://marc.theaimsgroup.com/?l=linux-netdev&m=115625436628696&w=2
and
http://marc.theaimsgroup.com/?l=linux-netdev&m=115625168405439&w=2
(the latter doesn't apply cleanly against wireless-dev, but you can
safely ignore the pieces that don't, at least for wireless testing :) )
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/include/net/nl80211.h 2006-08-22 15:47:47.000000000 +0200
@@ -0,0 +1,79 @@
+#ifndef __NET_NL80211_H
+#define __NET_NL80211_H
+
+#include <linux/netlink.h>
+#include <linux/nl80211.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/genetlink.h>
+
+/*
+ * 802.11 netlink in-kernel interface
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+
+/**
+ * struct nl80211_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 nl80211_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.
+ */
+struct nl80211_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);
+ int (*del_virtual_intf)(void *priv, int ifindex);
+
+ /* more things to be added...
+ *
+ * for a (*configure)(...) call I'd probably guess that the
+ * best bet would be to have one call that returns all
+ * possible options, one that sets them based on the
+ * struct genl_info *info, and one for that optimised
+ * set-at-once thing.
+ */
+};
+
+/*
+ * register a given method structure with the nl80211 system
+ * and associate the 'priv' pointer with it.
+ * NOTE: for proper operation, this priv pointer MUST also be
+ * assigned to each &struct net_device's @ieee80211_ptr member!
+ */
+extern int nl80211_register(struct nl80211_ops *ops, void *priv);
+/*
+ * 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 nl80211_unregister(void *priv);
+
+/* helper functions */
+extern void *nl80211hdr_put(struct sk_buff *skb, u32 pid,
+ u32 seq, int flags, u8 cmd);
+extern void *nl80211msg_new(struct sk_buff **skb, u32 pid,
+ u32 seq, int flags, u8 cmd);
+
+#endif /* __NET_NL80211_H */
--- wireless-dev.orig/net/Kconfig 2006-08-22 15:47:32.000000000 +0200
+++ wireless-dev/net/Kconfig 2006-08-22 15:47:47.000000000 +0200
@@ -250,6 +250,9 @@ source "net/ieee80211/Kconfig"
config WIRELESS_EXT
bool
+config NETLINK_80211
+ tristate
+
endif # if NET
endmenu # Networking
--- wireless-dev.orig/net/Makefile 2006-08-22 15:47:32.000000000 +0200
+++ wireless-dev/net/Makefile 2006-08-22 15:47:47.000000000 +0200
@@ -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_NETLINK_80211) += wireless/
obj-$(CONFIG_D80211) += d80211/
obj-$(CONFIG_IEEE80211) += ieee80211/
obj-$(CONFIG_TIPC) += tipc/
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/wireless/Makefile 2006-08-22 15:47:47.000000000 +0200
@@ -0,0 +1,4 @@
+obj-$(CONFIG_NETLINK_80211) += cfg80211.o
+
+cfg80211-objs := \
+ nl80211.o
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/wireless/nl80211.c 2006-08-22 15:47:47.000000000 +0200
@@ -0,0 +1,515 @@
+/*
+ * This is the new netlink-based wireless configuration interface.
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include <linux/if.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <net/genetlink.h>
+#include <net/nl80211.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+
+MODULE_AUTHOR("Johannes Berg");
+MODULE_LICENSE("GPL");
+
+struct nl80211_registered_driver {
+ struct nl80211_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;
+};
+
+/* 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 */
+static LIST_HEAD(nl80211_drv_list);
+static DEFINE_MUTEX(nl80211_drv_mutex);
+static unsigned int wiphy_counter;
+
+static struct genl_family nl80211_fam = {
+ .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */
+ .name = "nl80211", /* have users key off the name instead */
+ .hdrsize = 0, /* no private header */
+ .version = 1, /* no particular meaning now */
+ .maxattr = NL80211_ATTR_MAX,
+};
+
+static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
+ [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
+ [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
+ [NL80211_ATTR_FLAGS] = { .type = NLA_U32 },
+ [NL80211_ATTR_QUEUE] = { .type = NLA_U32 },
+ [NL80211_ATTR_FRAME] = { .type = NLA_STRING, .len = 2500 },
+ [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
+};
+
+static struct nl80211_registered_driver *nl80211_drv_by_priv_locked(void *priv)
+{
+ struct nl80211_registered_driver *result = NULL, *drv;
+
+ if (!priv)
+ return NULL;
+
+ list_for_each_entry(drv, &nl80211_drv_list, list) {
+ if (drv->priv == priv) {
+ result = drv;
+ break;
+ }
+ }
+
+ return result;
+}
+
+static struct nl80211_registered_driver *nl80211_drv_by_wiphy_locked(int wiphy)
+{
+ struct nl80211_registered_driver *result = NULL, *drv;
+
+ list_for_each_entry(drv, &nl80211_drv_list, list) {
+ if (drv->wiphy == wiphy) {
+ result = drv;
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* requires nl80211_drv_mutex to be held! */
+static struct nl80211_registered_driver *
+nl80211_drv_from_info_locked(struct genl_info *info)
+{
+ int ifindex;
+ struct nl80211_registered_driver *result = NULL;
+ struct net_device *dev;
+ int err = -EINVAL;
+
+ if (info->attrs[NL80211_ATTR_WIPHY]) {
+ result = nl80211_drv_by_wiphy_locked(
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
+ if (result)
+ return result;
+ err = -ENODEV;
+ }
+
+ if (info->attrs[NL80211_ATTR_IFINDEX]) {
+ ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
+ dev = dev_get_by_index(ifindex);
+ result = nl80211_drv_by_priv_locked(dev->ieee80211_ptr);
+ dev_put(dev);
+ if (result)
+ return result;
+ err = -ENODEV;
+ }
+
+ return ERR_PTR(err);
+}
+
+/*
+ * 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!
+ * DON'T EVER ACQUIRE nl80211_drv_mutex AFTER THIS!
+ *
+ * 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 nl80211_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.
+ */
+static struct nl80211_registered_driver *
+nl80211_drv_from_info_with_locking(struct genl_info *info)
+{
+ struct nl80211_registered_driver *drv;
+
+ mutex_lock(&nl80211_drv_mutex);
+ drv = nl80211_drv_from_info_locked(info);
+
+ /* if it is not an error we grab the lock on
+ * it to assure it won't be going away while
+ * we operate on it */
+ if (!IS_ERR(drv))
+ mutex_lock(&drv->mtx);
+
+ mutex_unlock(&nl80211_drv_mutex);
+
+ return drv;
+}
+
+#define CHECK_CMD(ptr, cmd) \
+ if (drv->ops->ptr) { \
+ skb_put(msg, 1); \
+ *data++ = NL80211_CMD_##cmd; \
+ }
+
+static int nl80211_get_commands(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nl80211_registered_driver *drv;
+ struct sk_buff *msg;
+ void *hdr;
+ int err;
+ struct nlattr *start;
+ u8 *data;
+
+ drv = nl80211_drv_from_info_with_locking(info);
+ if (IS_ERR(drv))
+ return PTR_ERR(drv);
+
+ hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
+ NL80211_CMD_GET_COMMANDS);
+ if (IS_ERR(hdr)) {
+ err = PTR_ERR(hdr);
+ goto unlock;
+ }
+
+ start = nla_nest_start(msg, NL80211_ATTR_CMDS);
+ if (!start)
+ goto nla_nest_failure;
+ data = nla_data(start);
+
+ /* unconditionally allow some common commands we handle centrally */
+ skb_put(msg, 1);
+ *data++ = NL80211_CMD_GET_COMMANDS;
+ skb_put(msg, 1);
+ *data++ = NL80211_CMD_GET_WIPHYS;
+ skb_put(msg, 1);
+ *data++ = NL80211_CMD_GET_INTERFACES;
+
+ CHECK_CMD(inject_packet, INJECT);
+ CHECK_CMD(add_virtual_intf, ADD_VIRTUAL_INTERFACE);
+ CHECK_CMD(del_virtual_intf, DEL_VIRTUAL_INTERFACE);
+
+ nla_nest_end(msg, start);
+
+ err = genlmsg_end(msg, hdr);
+ if (err)
+ goto msg_free;
+
+ err = genlmsg_unicast(msg, info->snd_pid);
+ goto unlock;
+
+ nla_nest_failure:
+ err = genlmsg_cancel(skb, hdr);
+ msg_free:
+ nlmsg_free(skb);
+ unlock:
+ mutex_unlock(&drv->mtx);
+ return err;
+}
+#undef CHECK_CMD
+
+static int nl80211_dump_wiphys(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ /* I think need professional netlink help with dumpit calls */
+ return -ENOSYS;
+}
+
+static int nl80211_dump_intfs(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ /* I think need professional netlink help with dumpit calls */
+ return -ENOSYS;
+}
+
+static int addifidx(void *data, int ifidx)
+{
+ struct sk_buff *skb = data;
+
+ return nla_put_u32(skb, NL80211_ATTR_IFINDEX, ifidx);
+}
+
+static int nl80211_get_intfs(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nl80211_registered_driver *drv;
+ int err;
+
+ drv = nl80211_drv_from_info_with_locking(info);
+ if (IS_ERR(drv))
+ return PTR_ERR(drv);
+
+ err = drv->ops->list_interfaces(drv->priv, skb, addifidx);
+
+ mutex_unlock(&drv->mtx);
+ return err;
+}
+
+static int nl80211_do_inject(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nl80211_registered_driver *drv;
+ u32 flags = 0;
+ int err, queue = -1;
+
+ if (!info->attrs[NL80211_ATTR_FRAME])
+ return -EINVAL;
+ if (info->attrs[NL80211_ATTR_FLAGS])
+ flags = nla_get_u32(info->attrs[NL80211_ATTR_FLAGS]);
+ if (info->attrs[NL80211_ATTR_QUEUE])
+ queue = (int) nla_get_u32(info->attrs[NL80211_ATTR_QUEUE]);
+
+ drv = nl80211_drv_from_info_with_locking(info);
+ if (IS_ERR(drv))
+ return PTR_ERR(drv);
+
+ if (!drv->ops->inject_packet) {
+ err = -ENOSYS;
+ goto unlock;
+ }
+
+ err = drv->ops->inject_packet(drv->priv,
+ nla_data(info->attrs[NL80211_ATTR_FRAME]),
+ nla_len(info->attrs[NL80211_ATTR_FRAME]),
+ flags,
+ queue);
+ unlock:
+ mutex_unlock(&drv->mtx);
+ return err;
+}
+
+static int nl80211_add_virt_intf(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nl80211_registered_driver *drv;
+ int err;
+
+ if (!info->attrs[NL80211_ATTR_IFNAME])
+ return -EINVAL;
+
+ drv = nl80211_drv_from_info_with_locking(info);
+ if (IS_ERR(drv))
+ return PTR_ERR(drv);
+
+ if (!drv->ops->add_virtual_intf) {
+ err = -ENOSYS;
+ goto unlock;
+ }
+
+ err = drv->ops->add_virtual_intf(drv->priv,
+ nla_data(info->attrs[NL80211_ATTR_IFNAME]));
+
+ unlock:
+ mutex_unlock(&drv->mtx);
+ return err;
+}
+
+static int nl80211_del_virt_intf(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nl80211_registered_driver *drv;
+ int ifindex, err, wiphy;
+ struct net_device *dev;
+
+ if (!info->attrs[NL80211_ATTR_IFINDEX])
+ return -EINVAL;
+
+ ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
+
+ dev = dev_get_by_index(ifindex);
+ if (!dev)
+ return -ENODEV;
+
+ /* need to act on that ifindex */
+ mutex_lock(&nl80211_drv_mutex);
+ drv = nl80211_drv_by_priv_locked(dev->ieee80211_ptr);
+ dev_put(dev);
+ if (!drv) {
+ mutex_unlock(&nl80211_drv_mutex);
+ return -EOPNOTSUPP;
+ }
+
+ /* make it complain if wiphy is set and is different or invalid */
+ if (info->attrs[NL80211_ATTR_IFINDEX]) {
+ wiphy = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
+ if (drv != nl80211_drv_by_wiphy_locked(wiphy)) {
+ mutex_unlock(&nl80211_drv_mutex);
+ return -EINVAL;
+ }
+ }
+
+ mutex_lock(&drv->mtx);
+ mutex_unlock(&nl80211_drv_mutex);
+
+ if (!drv->ops->del_virtual_intf) {
+ err = -ENOSYS;
+ goto out;
+ }
+
+ err = drv->ops->del_virtual_intf(drv->priv, ifindex);
+
+ out:
+ mutex_unlock(&drv->mtx);
+ return err;
+}
+
+static struct genl_ops nl80211_ops[] = {
+ {
+ .cmd = NL80211_CMD_GET_COMMANDS,
+ .doit = nl80211_get_commands,
+ .policy = nl80211_policy,
+ },
+ {
+ .cmd = NL80211_CMD_GET_WIPHYS,
+ .dumpit = nl80211_dump_wiphys,
+ .policy = nl80211_policy,
+ },
+ {
+ .cmd = NL80211_CMD_GET_INTERFACES,
+ .dumpit = nl80211_dump_intfs,
+ .doit = nl80211_get_intfs,
+ .policy = nl80211_policy,
+ },
+ {
+ .cmd = NL80211_CMD_INJECT,
+ .doit = nl80211_do_inject,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_ADD_VIRTUAL_INTERFACE,
+ .doit = nl80211_add_virt_intf,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_DEL_VIRTUAL_INTERFACE,
+ .doit = nl80211_del_virt_intf,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+};
+
+
+/* exported functions */
+
+int nl80211_register(struct nl80211_ops *ops, void *priv)
+{
+ struct nl80211_registered_driver *drv;
+ int err;
+
+ if (!priv || !ops->list_interfaces)
+ return -EINVAL;
+
+ mutex_lock(&nl80211_drv_mutex);
+
+ if (nl80211_drv_by_priv_locked(priv)) {
+ err = -EALREADY;
+ goto out_unlock;
+ }
+
+ drv = kzalloc(sizeof(struct nl80211_registered_driver), GFP_KERNEL);
+ if (!drv) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+
+ drv->ops = ops;
+ drv->priv = priv;
+
+ wiphy_counter++;
+ if (unlikely(!wiphy_counter)) {
+ /* ugh, wrapped! */
+ kfree(drv);
+ err = -ENOSPC;
+ goto out_unlock;
+ }
+ mutex_init(&drv->mtx);
+ drv->wiphy = wiphy_counter;
+ list_add(&drv->list, &nl80211_drv_list);
+ err = 0;
+
+ out_unlock:
+ mutex_unlock(&nl80211_drv_mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(nl80211_register);
+
+void nl80211_unregister(void *priv)
+{
+ struct nl80211_registered_driver *drv;
+
+ mutex_lock(&nl80211_drv_mutex);
+ drv = nl80211_drv_by_priv_locked(priv);
+ if (!drv) {
+ printk(KERN_ERR "deregistering nl80211 backend that "
+ " was never registered!\n");
+ mutex_unlock(&nl80211_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(&nl80211_drv_mutex);
+
+ mutex_destroy(&drv->mtx);
+ kfree(drv);
+}
+EXPORT_SYMBOL_GPL(nl80211_unregister);
+
+void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, int flags, u8 cmd)
+{
+ /* since there is no private header just add the generic one */
+ return genlmsg_put(skb, pid, seq, nl80211_fam.id, 0,
+ flags, cmd, nl80211_fam.version);
+}
+EXPORT_SYMBOL_GPL(nl80211hdr_put);
+
+void *nl80211msg_new(struct sk_buff **skb, u32 pid, u32 seq, int flags, u8 cmd)
+{
+ void *hdr;
+
+ *skb = nlmsg_new(NLMSG_GOODSIZE);
+ if (!*skb)
+ return ERR_PTR(-ENOBUFS);
+
+ hdr = nl80211hdr_put(*skb, pid, seq, flags, cmd);
+ if (!hdr) {
+ nlmsg_free(*skb);
+ /* what would be a good error here? */
+ return ERR_PTR(-EINVAL);
+ }
+
+ return hdr;
+}
+EXPORT_SYMBOL_GPL(nl80211msg_new);
+
+/* module initialisation/exit functions */
+
+static int nl80211_init(void)
+{
+ int err, i;
+
+ err = genl_register_family(&nl80211_fam);
+ if (err)
+ return err;
+
+ for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) {
+ err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]);
+ if (err)
+ goto err_out;
+ }
+ return 0;
+ err_out:
+ genl_unregister_family(&nl80211_fam);
+ return err;
+}
+
+static void nl80211_exit(void)
+{
+ genl_unregister_family(&nl80211_fam);
+}
+
+module_init(nl80211_init);
+module_exit(nl80211_exit);
--- wireless-dev.orig/include/linux/Kbuild 2006-08-22 15:47:32.000000000 +0200
+++ wireless-dev/include/linux/Kbuild 2006-08-22 15:47:47.000000000 +0200
@@ -28,7 +28,7 @@ header-y += affs_fs.h affs_hardblocks.h
sound.h stddef.h synclink.h telephony.h termios.h ticable.h \
times.h tiocl.h tipc.h toshiba.h ultrasound.h un.h utime.h \
utsname.h video_decoder.h video_encoder.h videotext.h vt.h \
- wavefront.h wireless.h xattr.h x25.h zorro_ids.h
+ wavefront.h wireless.h xattr.h x25.h zorro_ids.h nl80211.h
unifdef-y += acct.h adb.h adfs_fs.h agpgart.h apm_bios.h atalk.h \
atmarp.h atmdev.h atm.h atm_tcp.h audit.h auto_fs.h binfmts.h \
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/include/linux/nl80211.h 2006-08-22 15:47:47.000000000 +0200
@@ -0,0 +1,90 @@
+#ifndef __LINUX_NL80211_H
+#define __LINUX_NL80211_H
+/*
+ * 802.11 netlink interface public header
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+
+/* currently supported commands
+ * don't change the order or add anything inbetween, this is ABI! */
+enum {
+ /* There's no technical reason to not use command 0 but malformed
+ * zeroed messages may have it and this catches that */
+ NL80211_CMD_UNSPEC,
+
+ /* Get supported commands by ifindex,
+ * uses NL80211_ATTR_CMDS (output) and NL80211_ATTR_IFINDEX (input) */
+ NL80211_CMD_GET_COMMANDS,
+
+ /* Inject a frame using NL80211_ATTR_FLAGS and NL80211_ATTR_FRAME.
+ * If kernel sends this, it's a status notification for the injected
+ * frame. */
+ NL80211_CMD_INJECT,
+
+ /* add a virtual interface to a group that is identified by any
+ * other ifindex in the group of a wiphy index, needs the
+ * NL80211_IF_NAME attribute */
+ NL80211_CMD_ADD_VIRTUAL_INTERFACE,
+
+ /* remove a given (with NL80211_ATTR_IFINDEX) virtual device */
+ NL80211_CMD_DEL_VIRTUAL_INTERFACE,
+
+ /* get list of all wiphys */
+ NL80211_CMD_GET_WIPHYS,
+
+ /* get list of all interfaces belonging to a wiphy */
+ NL80211_CMD_GET_INTERFACES,
+
+ /* add commands here */
+
+ /* used to define NL80211_CMD_MAX below */
+ __NL80211_CMD_AFTER_LAST,
+};
+#define NL80211_CMD_MAX (__NL80211_CMD_AFTER_LAST - 1)
+
+
+/* currently supported attributes.
+ * don't change the order or add anything inbetween, this is ABI! */
+enum {
+ NL80211_ATTR_UNSPEC,
+
+ /* network device (ifindex) to operate on */
+ NL80211_ATTR_IFINDEX,
+
+ /* wiphy index to operate on */
+ NL80211_ATTR_WIPHY,
+
+ /* list of u8 cmds that a given device implements */
+ NL80211_ATTR_CMDS,
+
+ /* flags for injection and other commands, see below */
+ NL80211_ATTR_FLAGS,
+
+ /* which hardware queue to use */
+ NL80211_ATTR_QUEUE,
+
+ /* frame to inject or received frame for mgmt frame subscribers */
+ NL80211_ATTR_FRAME,
+
+ /* interface name for adding a virtual interface */
+ NL80211_ATTR_IFNAME,
+
+ /* add attributes here */
+
+ /* used to define NL80211_ATTR_MAX below */
+ __NL80211_ATTR_AFTER_LAST,
+};
+#define NL80211_ATTR_MAX (__NL80211_ATTR_AFTER_LAST - 1)
+
+/**
+ * NL80211_FLAG_TXSTATUS - send transmit status indication
+ */
+#define NL80211_FLAG_TXSTATUS (1<<00)
+/**
+ * NL80211_FLAG_ENCRYPT - encrypt this packet
+ * Warning: This looks inside the packet header!
+ */
+#define NL80211_FLAG_ENCRYPT (1<<01)
+
+#endif /* __LINUX_NL80211_H */
next reply other threads:[~2006-08-22 13:52 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-08-22 13:52 Johannes Berg [this message]
2006-08-22 15:09 ` [RFC] add nl80211 Johannes Berg
2006-08-23 9:40 ` Johannes Berg
2006-08-24 13:32 ` Jiri Benc
2006-08-24 14:15 ` Johannes Berg
2006-08-24 14:36 ` Thomas Graf
2006-08-24 15:20 ` Johannes Berg
2006-08-24 16:07 ` Johannes Berg
2006-08-24 17:27 ` Thomas Graf
2006-08-25 9:04 ` Johannes Berg
2006-08-25 10:30 ` Thomas Graf
2006-08-25 10:38 ` Johannes Berg
2006-08-25 11:01 ` [RFC take3] " Johannes Berg
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=1156254768.3825.1.camel@ux156 \
--to=johannes@sipsolutions.net \
--cc=jbenc@suse.cz \
--cc=linville@tuxdriver.com \
--cc=netdev@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).