* [RFC 1/3] cfg80211/nl80211 core
2006-09-14 10:46 more nl80211 stuff Johannes Berg
@ 2006-09-14 10:49 ` Johannes Berg
2006-09-22 15:48 ` Jiri Benc
2006-10-06 9:51 ` Johannes Berg
2006-09-14 10:50 ` [RFC 2/3] make d80211 use cfg80211 Johannes Berg
` (2 subsequent siblings)
3 siblings, 2 replies; 14+ messages in thread
From: Johannes Berg @ 2006-09-14 10:49 UTC (permalink / raw)
To: netdev
Cc: John W. Linville, Michael Buesch, Jean Tourrilhes, Jiri Benc,
James P. Ketrenos, Mohamed Abbas, Ulrich Kunitz, Daniel Drake
This patch adds cfg80211/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.
There should be support for notifications, but we need to figure
out if we remove the sysfs based add/remove virtual interface
thing completely or allow the driver to create a notification
through some new API here.
Modulo file renames and a bit of split ups, it is identical to previous
versions.
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 :) )
It also requires the NLA_PUT_FLAG patch I did:
http://marc.theaimsgroup.com/?l=linux-netdev&m=115650333420169&w=2
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
--- wireless-dev.orig/net/Kconfig 2006-09-13 22:05:53.359647141 +0200
+++ wireless-dev/net/Kconfig 2006-09-13 22:06:10.529647141 +0200
@@ -250,6 +250,9 @@ source "net/ieee80211/Kconfig"
config WIRELESS_EXT
bool
+config CFG80211
+ tristate
+
endif # if NET
endmenu # Networking
--- wireless-dev.orig/net/Makefile 2006-09-13 22:05:53.389647141 +0200
+++ wireless-dev/net/Makefile 2006-09-13 22:06:10.529647141 +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_CFG80211) += 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-09-13 22:06:10.529647141 +0200
@@ -0,0 +1,4 @@
+obj-$(CONFIG_CFG80211) += cfg80211.o
+
+cfg80211-objs := \
+ core.o nl80211.o
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/wireless/nl80211.c 2006-09-13 22:06:10.529647141 +0200
@@ -0,0 +1,395 @@
+/*
+ * 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/cfg80211.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include "core.h"
+#include "nl80211.h"
+
+/* the netlink family */
+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,
+};
+
+/* policy for the attributes */
+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 = NL80211_MAX_FRAME_LEN },
+ [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
+ [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
+};
+
+/* netlink command implementations */
+
+#define CHECK_CMD(ptr, cmd) \
+ if (drv->ops->ptr) \
+ NLA_PUT_FLAG(msg, NL80211_CMD_##cmd);
+
+static int nl80211_get_cmdlist(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_driver *drv;
+ struct sk_buff *msg;
+ void *hdr;
+ int err;
+ struct nlattr *start;
+
+ drv = cfg80211_get_drv_from_info(info);
+ if (IS_ERR(drv))
+ return PTR_ERR(drv);
+
+ hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
+ NL80211_CMD_NEW_CMDLIST);
+ if (IS_ERR(hdr)) {
+ err = PTR_ERR(hdr);
+ goto put_drv;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, drv->wiphy);
+
+ start = nla_nest_start(msg, NL80211_ATTR_CMDS);
+ if (!start)
+ goto nla_put_failure;
+
+ /* unconditionally allow some common commands we handle centrally */
+ NLA_PUT_FLAG(msg, NL80211_CMD_GET_CMDLIST);
+ NLA_PUT_FLAG(msg, NL80211_CMD_GET_WIPHYS);
+ NLA_PUT_FLAG(msg, 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);
+
+ genlmsg_end(msg, hdr);
+
+ err = genlmsg_unicast(msg, info->snd_pid);
+ goto put_drv;
+
+ nla_put_failure:
+ err = -ENOBUFS;
+ nlmsg_free(msg);
+ put_drv:
+ cfg80211_put_drv(drv);
+ return err;
+}
+#undef CHECK_CMD
+
+static int nl80211_get_wiphys(struct sk_buff *skb, struct genl_info *info)
+{
+ struct sk_buff *msg;
+ void *hdr;
+ struct nlattr *start, *indexstart;
+ struct cfg80211_registered_driver *drv;
+ int idx = 1;
+
+ hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
+ NL80211_CMD_NEW_WIPHYS);
+ if (IS_ERR(hdr))
+ return PTR_ERR(hdr);
+
+ start = nla_nest_start(msg, NL80211_ATTR_WIPHY_LIST);
+ if (!start)
+ goto nla_outer_nest_failure;
+
+ mutex_lock(&cfg80211_drv_mutex);
+ list_for_each_entry(drv, &cfg80211_drv_list, list) {
+ indexstart = nla_nest_start(msg, idx++);
+ if (!indexstart)
+ goto nla_put_failure;
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, drv->wiphy);
+ nla_nest_end(msg, indexstart);
+ }
+ mutex_unlock(&cfg80211_drv_mutex);
+
+ nla_nest_end(msg, start);
+
+ genlmsg_end(msg, hdr);
+
+ return genlmsg_unicast(msg, info->snd_pid);
+
+ nla_put_failure:
+ mutex_unlock(&cfg80211_drv_mutex);
+ nla_outer_nest_failure:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+struct addifidx_cb {
+ int idx;
+ struct sk_buff *skb;
+};
+
+static int addifidx(void *data, int ifidx)
+{
+ struct addifidx_cb *cb = data;
+ struct net_device *dev = dev_get_by_index(ifidx);
+ int err = -ENOBUFS;
+ struct nlattr *start;
+
+ /* not that this can happen, since the caller
+ * should hold the device open... */
+ if (!dev)
+ return -ENODEV;
+
+ start = nla_nest_start(cb->skb, cb->idx++);
+ if (!start)
+ goto nla_put_failure;
+
+ NLA_PUT_U32(cb->skb, NL80211_ATTR_IFINDEX, ifidx);
+ NLA_PUT_STRING(cb->skb, NL80211_ATTR_IFNAME, dev->name);
+
+ nla_nest_end(cb->skb, start);
+ err = 0;
+
+ nla_put_failure:
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_get_intfs(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_driver *drv;
+ struct sk_buff *msg;
+ void *hdr;
+ int err;
+ struct nlattr *start;
+ struct addifidx_cb cb;
+
+ drv = cfg80211_get_drv_from_info(info);
+ if (IS_ERR(drv))
+ return PTR_ERR(drv);
+
+ hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
+ NL80211_CMD_GET_INTERFACES);
+ if (IS_ERR(hdr)) {
+ err = PTR_ERR(hdr);
+ goto put_drv;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, drv->wiphy);
+
+ start = nla_nest_start(msg, NL80211_ATTR_INTERFACE_LIST);
+ if (!start) {
+ err = -ENOBUFS;
+ goto msg_free;
+ }
+
+ cb.skb = msg;
+ cb.idx = 1;
+ err = drv->ops->list_interfaces(drv->priv, &cb, addifidx);
+ if (err)
+ goto msg_free;
+
+ nla_nest_end(msg, start);
+
+ genlmsg_end(msg, hdr);
+
+ err = genlmsg_unicast(msg, info->snd_pid);
+ goto put_drv;
+
+ nla_put_failure:
+ err = -ENOBUFS;
+ msg_free:
+ nlmsg_free(msg);
+ put_drv:
+ cfg80211_put_drv(drv);
+ return err;
+}
+
+static int nl80211_do_inject(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_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 = cfg80211_get_drv_from_info(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:
+ cfg80211_put_drv(drv);
+ return err;
+}
+
+static int nl80211_add_virt_intf(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_driver *drv;
+ int err;
+ unsigned int type = NL80211_IFTYPE_UNSPECIFIED;
+
+ if (!info->attrs[NL80211_ATTR_IFNAME])
+ return -EINVAL;
+
+ if (info->attrs[NL80211_ATTR_IFTYPE]) {
+ type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
+ if (type > NL80211_IFTYPE_MAX)
+ return -EINVAL;
+ }
+
+ drv = cfg80211_get_drv_from_info(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]), type);
+
+ unlock:
+ cfg80211_put_drv(drv);
+ return err;
+}
+
+static int nl80211_del_virt_intf(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_driver *drv;
+ int ifindex, err;
+
+ if (!info->attrs[NL80211_ATTR_IFINDEX])
+ return -EINVAL;
+
+ ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
+
+ drv = cfg80211_get_drv_from_info(info);
+ if (IS_ERR(drv))
+ return PTR_ERR(drv);
+
+ if (!drv->ops->del_virtual_intf) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ err = drv->ops->del_virtual_intf(drv->priv, ifindex);
+
+ out:
+ cfg80211_put_drv(drv);
+ return err;
+}
+
+static struct genl_ops nl80211_ops[] = {
+ {
+ .cmd = NL80211_CMD_GET_CMDLIST,
+ .doit = nl80211_get_cmdlist,
+ .policy = nl80211_policy,
+ },
+ {
+ .cmd = NL80211_CMD_GET_WIPHYS,
+ .doit = nl80211_get_wiphys,
+ .policy = nl80211_policy,
+ },
+ {
+ .cmd = NL80211_CMD_GET_INTERFACES,
+ .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 */
+
+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);
+ return ERR_PTR(-ENOBUFS);
+ }
+
+ return hdr;
+}
+EXPORT_SYMBOL_GPL(nl80211msg_new);
+
+/* initialisation/exit functions */
+
+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;
+}
+
+void nl80211_exit(void)
+{
+ genl_unregister_family(&nl80211_fam);
+}
--- wireless-dev.orig/include/linux/Kbuild 2006-09-13 22:05:53.569647141 +0200
+++ wireless-dev/include/linux/Kbuild 2006-09-13 22:06:10.529647141 +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-09-13 22:06:10.539647141 +0200
@@ -0,0 +1,137 @@
+#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_CMDLIST,
+
+ /* Supported commands returned */
+ NL80211_CMD_NEW_CMDLIST,
+
+ /* 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 wiphys */
+ NL80211_CMD_NEW_WIPHYS,
+
+ /* get list of all interfaces belonging to a wiphy */
+ NL80211_CMD_GET_INTERFACES,
+
+ /* get list of all interfaces belonging to a wiphy */
+ NL80211_CMD_NEW_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 */
+ NL80211_ATTR_IFNAME,
+
+ /* type of (virtual) interface */
+ NL80211_ATTR_IFTYPE,
+
+ /* interface list */
+ NL80211_ATTR_INTERFACE_LIST,
+
+ /* wiphy list */
+ NL80211_ATTR_WIPHY_LIST,
+
+ /* 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)
+
+/**
+ * maximum length of a frame that can be injected
+ */
+#define NL80211_MAX_FRAME_LEN 2500
+
+/**
+ * &enum nl80211_iftype - (virtual) interface types
+ *
+ * This structure is used with the NL80211_ATTR_IFTYPE
+ * to set the type of an interface.
+ * Note that these are intentionally compatible with
+ * the IW_MODE_* constants except for the removal of
+ * IW_MODE_AUTO.
+ *
+ */
+enum {
+ NL80211_IFTYPE_UNSPECIFIED,
+ NL80211_IFTYPE_ADHOC,
+ NL80211_IFTYPE_STATION,
+ NL80211_IFTYPE_AP,
+ NL80211_IFTYPE_WDS,
+ NL80211_IFTYPE_SECONDARY,
+ NL80211_IFTYPE_MONITOR,
+
+ /* keep last */
+ __NL80211_IFTYPE_AFTER_LAST
+};
+#define NL80211_IFTYPE_MAX (__NL80211_IFTYPE_AFTER_LAST - 1)
+
+#endif /* __LINUX_NL80211_H */
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/include/net/cfg80211.h 2006-09-13 22:06:10.539647141 +0200
@@ -0,0 +1,84 @@
+#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 configuration in-kernel interface
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+
+/**
+ * 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.
+ */
+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);
+
+ /* 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 cfg80211 system
+ * and associate the 'priv' pointer with it.
+ *
+ * Returns a positive 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);
+
+/*
+ * 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);
+
+/* helper functions specific to netlink */
+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 */
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/wireless/core.c 2006-09-13 22:06:10.539647141 +0200
@@ -0,0 +1,233 @@
+/*
+ * This is the new wireless configuration interface.
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include "core.h"
+#include "nl80211.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 nl80211_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;
+}
+
+/* requires cfg80211_drv_mutex to be held! */
+static struct cfg80211_registered_driver *cfg80211_drv_by_wiphy(int wiphy)
+{
+ struct cfg80211_registered_driver *result = NULL, *drv;
+
+ list_for_each_entry(drv, &cfg80211_drv_list, list) {
+ if (drv->wiphy == wiphy) {
+ result = drv;
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* requires cfg80211_drv_mutex to be held! */
+static struct cfg80211_registered_driver *
+__cfg80211_drv_from_info(struct genl_info *info)
+{
+ int ifindex;
+ struct cfg80211_registered_driver *bywiphy = NULL, *byifidx = NULL;
+ struct net_device *dev;
+ int err = -EINVAL;
+
+ if (info->attrs[NL80211_ATTR_WIPHY]) {
+ bywiphy = cfg80211_drv_by_wiphy(
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
+ err = -ENODEV;
+ }
+
+ if (info->attrs[NL80211_ATTR_IFINDEX]) {
+ ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
+ dev = dev_get_by_index(ifindex);
+ if (dev) {
+ byifidx = cfg80211_drv_by_priv(dev->ieee80211_ptr);
+ dev_put(dev);
+ }
+ err = -ENODEV;
+ }
+
+ if (bywiphy && byifidx) {
+ if (bywiphy != byifidx)
+ return ERR_PTR(-EINVAL);
+ else
+ return bywiphy; /* == byifidx */
+ }
+ if (bywiphy)
+ return bywiphy;
+
+ if (byifidx)
+ return byifidx;
+
+ return ERR_PTR(err);
+}
+
+struct cfg80211_registered_driver *
+cfg80211_get_drv_from_info(struct genl_info *info)
+{
+ struct cfg80211_registered_driver *drv;
+
+ mutex_lock(&cfg80211_drv_mutex);
+ drv = __cfg80211_drv_from_info(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(&cfg80211_drv_mutex);
+
+ return drv;
+}
+
+/* wext will need this */
+struct cfg80211_registered_driver *
+cfg80211_get_drv_from_ifindex(int ifindex)
+{
+ struct cfg80211_registered_driver *drv;
+ struct net_device *dev;
+
+ mutex_lock(&cfg80211_drv_mutex);
+ dev = dev_get_by_index(ifindex);
+ if (!dev)
+ return ERR_PTR(-ENODEV);
+ drv = cfg80211_drv_by_priv(dev->ieee80211_ptr);
+ if (drv)
+ mutex_lock(&drv->mtx);
+ dev_put(dev);
+ if (drv)
+ return drv;
+ return ERR_PTR(-ENODEV);
+}
+
+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 nl80211_init();
+}
+
+static void cfg80211_exit(void)
+{
+ /* possibly need to do more later */
+ nl80211_exit();
+}
+
+module_init(cfg80211_init);
+module_exit(cfg80211_exit);
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/wireless/core.h 2006-09-13 22:06:10.539647141 +0200
@@ -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 */
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/wireless/nl80211.h 2006-09-13 22:06:10.539647141 +0200
@@ -0,0 +1,7 @@
+#ifndef __NET_WIRELESS_NL80211_H
+#define __NET_WIRELESS_NL80211_H
+
+extern int nl80211_init(void);
+extern void nl80211_exit(void);
+
+#endif /* __NET_WIRELESS_NL80211_H */
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [RFC 1/3] cfg80211/nl80211 core
2006-09-14 10:49 ` [RFC 1/3] cfg80211/nl80211 core Johannes Berg
@ 2006-09-22 15:48 ` Jiri Benc
2006-09-25 9:05 ` Johannes Berg
2006-10-06 9:51 ` Johannes Berg
1 sibling, 1 reply; 14+ messages in thread
From: Jiri Benc @ 2006-09-22 15:48 UTC (permalink / raw)
To: Johannes Berg
Cc: netdev, John W. Linville, Michael Buesch, Jean Tourrilhes,
James P. Ketrenos, Mohamed Abbas, Ulrich Kunitz, Daniel Drake
On Thu, 14 Sep 2006 12:49:23 +0200, Johannes Berg wrote:
> There should be support for notifications, but we need to figure
> out if we remove the sysfs based add/remove virtual interface
> thing completely or allow the driver to create a notification
> through some new API here.
Feel free to remove it if it makes your work easier.
Jiri
--
Jiri Benc
SUSE Labs
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC 1/3] cfg80211/nl80211 core
2006-09-22 15:48 ` Jiri Benc
@ 2006-09-25 9:05 ` Johannes Berg
0 siblings, 0 replies; 14+ messages in thread
From: Johannes Berg @ 2006-09-25 9:05 UTC (permalink / raw)
To: Jiri Benc
Cc: netdev, John W. Linville, Michael Buesch, Jean Tourrilhes,
James P. Ketrenos, Mohamed Abbas, Ulrich Kunitz, Daniel Drake
On Fri, 2006-09-22 at 17:48 +0200, Jiri Benc wrote:
> On Thu, 14 Sep 2006 12:49:23 +0200, Johannes Berg wrote:
> > There should be support for notifications, but we need to figure
> > out if we remove the sysfs based add/remove virtual interface
> > thing completely or allow the driver to create a notification
> > through some new API here.
>
> Feel free to remove it if it makes your work easier.
It definitely would.
johannes
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC 1/3] cfg80211/nl80211 core
2006-09-14 10:49 ` [RFC 1/3] cfg80211/nl80211 core Johannes Berg
2006-09-22 15:48 ` Jiri Benc
@ 2006-10-06 9:51 ` Johannes Berg
1 sibling, 0 replies; 14+ messages in thread
From: Johannes Berg @ 2006-10-06 9:51 UTC (permalink / raw)
To: netdev
Cc: John W. Linville, Michael Buesch, Jean Tourrilhes, Jiri Benc,
James P. Ketrenos, Mohamed Abbas, Ulrich Kunitz, Daniel Drake
On Thu, 2006-09-14 at 12:49 +0200, Johannes Berg wrote:
> +struct cfg80211_registered_driver *
> +cfg80211_get_drv_from_ifindex(int ifindex)
> +{
> + struct cfg80211_registered_driver *drv;
> + struct net_device *dev;
> +
> + mutex_lock(&cfg80211_drv_mutex);
> + dev = dev_get_by_index(ifindex);
> + if (!dev)
> + return ERR_PTR(-ENODEV);
> + drv = cfg80211_drv_by_priv(dev->ieee80211_ptr);
> + if (drv)
> + mutex_lock(&drv->mtx);
> + dev_put(dev);
> + if (drv)
> + return drv;
> + return ERR_PTR(-ENODEV);
> +}
So... nobody spotted the "obvious" [1] locking problem here ;) fixed,
will update the patches soon and upload somewhere, netdev doesn't like
them and drops my mail (even 0/3 which wasn't that big).
johannes
[1] hint: drv->mtx is supposed to be left locked at the end, but
cfg80211_drv_mutex isn't :) I found out the hard way when testing my WE
backward compat code
^ permalink raw reply [flat|nested] 14+ messages in thread
* [RFC 2/3] make d80211 use cfg80211
2006-09-14 10:46 more nl80211 stuff Johannes Berg
2006-09-14 10:49 ` [RFC 1/3] cfg80211/nl80211 core Johannes Berg
@ 2006-09-14 10:50 ` Johannes Berg
2006-09-14 17:53 ` Simon Barber
2006-09-14 10:53 ` [RFC 3/3] cfg80211 thoughts on configuration Johannes Berg
2006-09-14 13:41 ` more nl80211 stuff Dan Williams
3 siblings, 1 reply; 14+ messages in thread
From: Johannes Berg @ 2006-09-14 10:50 UTC (permalink / raw)
To: netdev
Cc: John W. Linville, Michael Buesch, Jean Tourrilhes, Jiri Benc,
James P. Ketrenos, Mohamed Abbas, Ulrich Kunitz, Daniel Drake
This patch makes d80211 partially configurable using the
infrastructure that nl80211 provides. So far, it allows
packet injection and adding/removing virtual interfaces.
Also identical to previous patches except for the file and Kconfig
renames that nl80211/cfg80211 went through.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
--- wireless-dev.orig/net/d80211/Kconfig 2006-09-13 22:06:09.209647141 +0200
+++ wireless-dev/net/d80211/Kconfig 2006-09-13 22:06:12.559647141 +0200
@@ -3,6 +3,7 @@ config D80211
select CRYPTO
select CRYPTO_ARC4
select CRYPTO_AES
+ select CFG80211
---help---
This option enables the hardware independent IEEE 802.11
networking stack.
--- wireless-dev.orig/net/d80211/Makefile 2006-09-13 22:06:09.219647141 +0200
+++ wireless-dev/net/d80211/Makefile 2006-09-13 22:06:12.559647141 +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-09-13 22:06:09.209647141 +0200
+++ wireless-dev/net/d80211/ieee80211.c 2006-09-13 22:06:12.569647141 +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-09-13 22:06:12.569647141 +0200
@@ -0,0 +1,144 @@
+/*
+ * cfg80211-based configuration for d80211
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+#include <net/cfg80211.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 cfg80211_ops d80211cfg = {
+ .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 cfg80211_register(&d80211cfg, local);
+}
+
+void ieee80211_cfg_exit(struct ieee80211_local *local)
+{
+ cfg80211_unregister(local);
+}
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/d80211/ieee80211_cfg.h 2006-09-13 22:06:12.569647141 +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-09-13 22:06:09.219647141 +0200
+++ wireless-dev/net/d80211/ieee80211_i.h 2006-09-13 22:06:12.569647141 +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-09-13 22:05:52.019647141 +0200
+++ wireless-dev/net/d80211/ieee80211_sta.c 2006-09-13 22:06:12.579647141 +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-09-13 22:05:52.089647141 +0200
+++ wireless-dev/net/d80211/wme.c 2006-09-13 22:06:12.579647141 +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] 14+ messages in thread* RE: [RFC 2/3] make d80211 use cfg80211
2006-09-14 10:50 ` [RFC 2/3] make d80211 use cfg80211 Johannes Berg
@ 2006-09-14 17:53 ` Simon Barber
2006-09-15 6:41 ` Johannes Berg
0 siblings, 1 reply; 14+ messages in thread
From: Simon Barber @ 2006-09-14 17:53 UTC (permalink / raw)
To: Johannes Berg, netdev
Cc: John W. Linville, Michael Buesch, Jean Tourrilhes, Jiri Benc,
James P. Ketrenos, Mohamed Abbas, Ulrich Kunitz, Daniel Drake
Hi Johannes,
Does the packet injection allow hostapd to use nl80211 instead of the
wlan0ap interface to send management frames? Important features for this
include requesting a transmit status - i.e. the ability for
hostapd/wpa_supplicant to know if the frame got acked or not.
Simon
-----Original Message-----
From: netdev-owner@vger.kernel.org [mailto:netdev-owner@vger.kernel.org]
On Behalf Of Johannes Berg
Sent: Thursday, September 14, 2006 3:50 AM
To: netdev@vger.kernel.org
Cc: John W. Linville; Michael Buesch; Jean Tourrilhes; Jiri Benc; James
P. Ketrenos; Mohamed Abbas; Ulrich Kunitz; Daniel Drake
Subject: [RFC 2/3] make d80211 use cfg80211
This patch makes d80211 partially configurable using the infrastructure
that nl80211 provides. So far, it allows packet injection and
adding/removing virtual interfaces.
Also identical to previous patches except for the file and Kconfig
renames that nl80211/cfg80211 went through.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
--- wireless-dev.orig/net/d80211/Kconfig 2006-09-13
22:06:09.209647141 +0200
+++ wireless-dev/net/d80211/Kconfig 2006-09-13 22:06:12.559647141
+0200
@@ -3,6 +3,7 @@ config D80211
select CRYPTO
select CRYPTO_ARC4
select CRYPTO_AES
+ select CFG80211
---help---
This option enables the hardware independent IEEE 802.11
networking stack.
--- wireless-dev.orig/net/d80211/Makefile 2006-09-13
22:06:09.219647141 +0200
+++ wireless-dev/net/d80211/Makefile 2006-09-13 22:06:12.559647141
+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-09-13
22:06:09.209647141 +0200
+++ wireless-dev/net/d80211/ieee80211.c 2006-09-13 22:06:12.569647141
+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-09-13
22:06:12.569647141 +0200
@@ -0,0 +1,144 @@
+/*
+ * cfg80211-based configuration for d80211
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> */
+#include <net/cfg80211.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 cfg80211_ops d80211cfg = {
+ .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 cfg80211_register(&d80211cfg, local); }
+
+void ieee80211_cfg_exit(struct ieee80211_local *local) {
+ cfg80211_unregister(local);
+}
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/d80211/ieee80211_cfg.h 2006-09-13
22:06:12.569647141 +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-09-13
22:06:09.219647141 +0200
+++ wireless-dev/net/d80211/ieee80211_i.h 2006-09-13
22:06:12.569647141 +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-09-13
22:05:52.019647141 +0200
+++ wireless-dev/net/d80211/ieee80211_sta.c 2006-09-13
22:06:12.579647141 +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-09-13 22:05:52.089647141
+0200
+++ wireless-dev/net/d80211/wme.c 2006-09-13 22:06:12.579647141
+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;
}
-
To unsubscribe from this list: send the line "unsubscribe netdev" in the
body of a message to majordomo@vger.kernel.org More majordomo info at
http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 14+ messages in thread* RE: [RFC 2/3] make d80211 use cfg80211
2006-09-14 17:53 ` Simon Barber
@ 2006-09-15 6:41 ` Johannes Berg
0 siblings, 0 replies; 14+ messages in thread
From: Johannes Berg @ 2006-09-15 6:41 UTC (permalink / raw)
To: Simon Barber
Cc: netdev, John W. Linville, Michael Buesch, Jean Tourrilhes,
Jiri Benc, James P. Ketrenos, Mohamed Abbas, Ulrich Kunitz,
Daniel Drake
Simon,
> Does the packet injection allow hostapd to use nl80211 instead of the
> wlan0ap interface to send management frames?
It's intended that it does that, yes.
> Important features for this
> include requesting a transmit status - i.e. the ability for
> hostapd/wpa_supplicant to know if the frame got acked or not.
Yeah, I'm aware of that. I think it can actually request the transmit
status now using the flags (would have to check), but the transmit
status won't get sent over netlink but still over the wlan0ap interface.
I haven't modified that part yet, but it shouldn't be hard to do.
I'll have to look at that closer some time (soon). I think if you
request the transmit status I'll have to save the netlink_pid of the
request and then unicast back the transmit status. That shouldn't be
hard to do at all (obviously requires that hostapd keeps the netlink
socket open but it should do that anyway)
johannes
^ permalink raw reply [flat|nested] 14+ messages in thread
* [RFC 3/3] cfg80211 thoughts on configuration
2006-09-14 10:46 more nl80211 stuff Johannes Berg
2006-09-14 10:49 ` [RFC 1/3] cfg80211/nl80211 core Johannes Berg
2006-09-14 10:50 ` [RFC 2/3] make d80211 use cfg80211 Johannes Berg
@ 2006-09-14 10:53 ` Johannes Berg
2006-09-20 6:33 ` Thomas Graf
2006-09-14 13:41 ` more nl80211 stuff Dan Williams
3 siblings, 1 reply; 14+ messages in thread
From: Johannes Berg @ 2006-09-14 10:53 UTC (permalink / raw)
To: netdev
Cc: John W. Linville, Michael Buesch, Jean Tourrilhes, Jiri Benc,
James P. Ketrenos, Mohamed Abbas, Ulrich Kunitz, Daniel Drake,
Thomas Graf
This is some preliminary code how I'm currently thinking (and that might
change radically :) ) configuration might look like.
It uses the patch I previously posted to make genetlink attributes
custom-definable.
--- wireless-dev.orig/include/linux/nl80211.h 2006-09-13 22:06:10.539647141 +0200
+++ wireless-dev/include/linux/nl80211.h 2006-09-13 22:06:11.919647141 +0200
@@ -45,6 +45,47 @@ enum {
/* get list of all interfaces belonging to a wiphy */
NL80211_CMD_NEW_INTERFACES,
+ /* configure device */
+ NL80211_CMD_CONFIGURE,
+
+ /* request configuration */
+ NL80211_CMD_GET_CONFIG,
+
+ /* configuration sent from kernel */
+ NL80211_CMD_CONFIGURATION,
+
+ /* initiate scan */
+ NL80211_CMD_INITIATE_SCAN,
+
+ /* scan result (kernel -> userspace) */
+ NL80211_CMD_SCAN_RESULT,
+
+ /* change roaming control */
+ NL80211_CMD_SET_ROAMING_CONTROL,
+
+ /* get roaming control setting */
+ NL80211_CMD_GET_ROAMING_CONTROL,
+
+ /* set access point BSSID for userspace roaming */
+ NL80211_CMD_SET_BSSID,
+
+ /* get current association information, if not associated then
+ * the BSSID attribute is not present in response */
+ NL80211_CMD_GET_ASSOCIATION,
+
+ /* association notification/response to GET_BSSID */
+ NL80211_CMD_ASSOCIATION_CHANGED,
+
+ /* disassociate from current AP */
+ NL80211_CMD_DISASSOCIATE,
+
+ /* deauth from current AP */
+ NL80211_CMD_DEAUTH,
+
+ /* re-associate with current settings
+ * (SSID and BSSID if roaming control in userspace) */
+ NL80211_CMD_REASSOCIATE,
+
/* add commands here */
/* used to define NL80211_CMD_MAX below */
@@ -88,6 +129,36 @@ enum {
/* wiphy list */
NL80211_ATTR_WIPHY_LIST,
+ /* attributes used for configuration */
+ /* network ID (pre 802.11 HW) */
+ NL80211_ATTR_NETWORK_ID,
+
+ /* channel, 1-14 are B/G */
+ NL80211_ATTR_CHANNEL,
+
+ /* receiver sensitivity in dBm */
+ NL80211_ATTR_RX_SENSITIVITY,
+
+ /* BSSID to associate to, only used when roaming control
+ * is in userspace */
+ NL80211_ATTR_BSSID,
+
+ /* SSID of ESS to associate to */
+ NL80211_ATTR_SSID,
+
+ /* transmit power in mW */
+ NL80211_ATTR_TRANSMIT_POWER,
+
+ /* fragmentation threshold in bytes */
+ NL80211_ATTR_FRAG_THRESHOLD,
+
+ /* one or more information elements */
+ NL80211_ATTR_INFORMATION_ELEMENT,
+
+ NL80211_ATTR_ROAMING_CONTROL,
+
+ NL80211_ATTR_SCAN_TYPE,
+
/* add attributes here */
/* used to define NL80211_ATTR_MAX below */
@@ -134,4 +205,13 @@ enum {
};
#define NL80211_IFTYPE_MAX (__NL80211_IFTYPE_AFTER_LAST - 1)
+enum {
+ NL80211_ROAMING_CONTROL_KERNEL,
+ NL80211_ROAMING_CONTROL_USERSPACE,
+
+ /* keep last */
+ __NL80211_ROAMING_CONTROL_AFTER_LAST
+};
+#define NL80211_ROAMING_CONTROL_MAX (__NL80211_ROAMING_CONTROL_AFTER_LAST-1)
+
#endif /* __LINUX_NL80211_H */
--- wireless-dev.orig/include/net/cfg80211.h 2006-09-13 22:06:10.539647141 +0200
+++ wireless-dev/include/net/cfg80211.h 2006-09-13 22:06:11.919647141 +0200
@@ -14,6 +14,30 @@
*/
/**
+ * struct cfg80211_config - description of a configuration (request)
+ */
+struct cfg80211_config {
+ /* first fields with 'internal' validity */
+
+ /* SSID to use, valid if not NULL. change forces reassociation */
+ 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 cfg80211_ops - backend description for wireless configuration
*
* This struct is registered by fullmac card drivers and/or wireless stacks
@@ -35,6 +59,26 @@
* @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
+ *
+ * @set_bssid: only valid with userspace roaming control, sets
+ * BSSID to use, forces reassociation if changing
*/
struct cfg80211_ops {
int (*list_interfaces)(void *priv, void *data,
@@ -46,14 +90,24 @@ struct cfg80211_ops {
unsigned int type);
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.
- */
+ 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, TBD);
+ TBD: which channels to scan, passive/active, background, ...?
+ */
+
+ int (*set_roaming)(void *priv, struct net_device *dev,
+ int roaming_control);
+
+ int (*set_bssid)(void *priv, struct net_device *dev, u8 *bssid);
};
/*
--- wireless-dev.orig/net/wireless/nl80211.c 2006-09-13 22:06:10.529647141 +0200
+++ wireless-dev/net/wireless/nl80211.c 2006-09-13 22:06:11.919647141 +0200
@@ -24,6 +24,22 @@ static struct genl_family nl80211_fam =
};
/* policy for the attributes */
+
+static int check_information_element(struct nlattr *nla)
+{
+ int len = nla_len(nla);
+ u8 *data = nla_data(nla);
+ int elementlen;
+
+ while (len >= 2) {
+ /* 1 byte ID, 1 byte len, `len' bytes data */
+ elementlen = *(data+1) + 2;
+ data += elementlen;
+ len -= elementlen;
+ }
+ return len ? -EINVAL : 0;
+}
+
static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
@@ -33,6 +49,17 @@ static struct nla_policy nl80211_policy[
.len = NL80211_MAX_FRAME_LEN },
[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
+ [NL80211_ATTR_NETWORK_ID] = { .type = NLA_U16 },
+ [NL80211_ATTR_CHANNEL] = { .type = NLA_U32 },
+ [NL80211_ATTR_RX_SENSITIVITY] = { .type = NLA_U32 },
+ [NL80211_ATTR_BSSID] = { .len = 6 },
+ [NL80211_ATTR_SSID] = { .type = NLA_STRING, .len = 32 },
+ [NL80211_ATTR_TRANSMIT_POWER] = { .type = NLA_U32 },
+ [NL80211_ATTR_FRAG_THRESHOLD] = { .type = NLA_U32 },
+ [NL80211_ATTR_INFORMATION_ELEMENT] = { .type = NLA_CUSTOM_CHECK,
+ .check = check_information_element },
+ [NL80211_ATTR_ROAMING_CONTROL] = { .type = NLA_U32 },
+ [NL80211_ATTR_SCAN_TYPE] = { .type = NLA_U32 },
};
/* netlink command implementations */
@@ -303,6 +330,77 @@ static int nl80211_del_virt_intf(struct
return err;
}
+static int nl80211_configure(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_driver *drv;
+ int ifindex, err;
+ struct net_device *dev;
+ struct cfg80211_config config;
+ struct nlattr *attr;
+
+ 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;
+
+ drv = cfg80211_get_drv_from_info(info);
+ if (IS_ERR(drv)) {
+ err = PTR_ERR(drv);
+ goto out_nodrv;
+ }
+
+ if (!drv->ops->configure) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ memset(&config, 0, sizeof(config));
+
+ attr = info->attrs[NL80211_ATTR_SSID];
+ if (attr)
+ config.ssid = nla_data(attr);
+
+ attr = info->attrs[NL80211_ATTR_NETWORK_ID];
+ if (attr) {
+ config.valid |= CFG80211_CFG_VALID_NWID;
+ config.network_id = nla_get_u16(attr);
+ }
+
+ attr = info->attrs[NL80211_ATTR_RX_SENSITIVITY];
+ if (attr) {
+ config.valid |= CFG80211_CFG_VALID_RX_SENSITIVITY;
+ config.rx_sensitivity = (s32) nla_get_u32(attr);
+ }
+
+ attr = info->attrs[NL80211_ATTR_TRANSMIT_POWER];
+ if (attr) {
+ config.valid |= CFG80211_CFG_VALID_TRANSMIT_POWER;
+ config.transmit_power = nla_get_u32(attr);
+ }
+
+ attr = info->attrs[NL80211_ATTR_FRAG_THRESHOLD];
+ if (attr) {
+ config.valid |= CFG80211_CFG_VALID_FRAG_THRESHOLD;
+ config.fragmentation_threshold = nla_get_u32(attr);
+ }
+
+ attr = info->attrs[NL80211_ATTR_CHANNEL];
+ if (attr) {
+ config.valid |= CFG80211_CFG_VALID_CHANNEL;
+ config.channel = nla_get_u32(attr);
+ }
+
+ err = drv->ops->configure(drv->priv, dev, &config);
+ out:
+ cfg80211_put_drv(drv);
+ out_nodrv:
+ dev_put(dev);
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_CMDLIST,
@@ -337,6 +435,12 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NL80211_CMD_CONFIGURE,
+ .doit = nl80211_configure,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/wireless/wext-compat.c 2006-09-13 22:06:11.929647141 +0200
@@ -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
+
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [RFC 3/3] cfg80211 thoughts on configuration
2006-09-14 10:53 ` [RFC 3/3] cfg80211 thoughts on configuration Johannes Berg
@ 2006-09-20 6:33 ` Thomas Graf
2006-09-20 7:03 ` Johannes Berg
0 siblings, 1 reply; 14+ messages in thread
From: Thomas Graf @ 2006-09-20 6:33 UTC (permalink / raw)
To: Johannes Berg
Cc: netdev, John W. Linville, Michael Buesch, Jean Tourrilhes,
Jiri Benc, James P. Ketrenos, Mohamed Abbas, Ulrich Kunitz,
Daniel Drake
* Johannes Berg <johannes@sipsolutions.net> 2006-09-14 12:53
> This is some preliminary code how I'm currently thinking (and that might
> change radically :) ) configuration might look like.
>
> It uses the patch I previously posted to make genetlink attributes
> custom-definable.
>
> --- wireless-dev.orig/include/linux/nl80211.h 2006-09-13 22:06:10.539647141 +0200
> +++ wireless-dev/include/linux/nl80211.h 2006-09-13 22:06:11.919647141 +0200
> @@ -45,6 +45,47 @@ enum {
> /* get list of all interfaces belonging to a wiphy */
> NL80211_CMD_NEW_INTERFACES,
>
> + /* configure device */
> + NL80211_CMD_CONFIGURE,
> +
> + /* request configuration */
> + NL80211_CMD_GET_CONFIG,
> +
> + /* configuration sent from kernel */
> + NL80211_CMD_CONFIGURATION,
I think I brought this up already, it's a lot easier to understand
things if you keep it symmetric, i.e. NL80211_CMD_GET_CONFIG triggers
sending a NL80211_CMD_NEW_CONFIG.
> +static int check_information_element(struct nlattr *nla)
> +{
> + int len = nla_len(nla);
> + u8 *data = nla_data(nla);
> + int elementlen;
> +
> + while (len >= 2) {
> + /* 1 byte ID, 1 byte len, `len' bytes data */
> + elementlen = *(data+1) + 2;
> + data += elementlen;
> + len -= elementlen;
> + }
> + return len ? -EINVAL : 0;
> +}
> +
> static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
> [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
> [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
> @@ -33,6 +49,17 @@ static struct nla_policy nl80211_policy[
> .len = NL80211_MAX_FRAME_LEN },
> [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
> [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
> + [NL80211_ATTR_NETWORK_ID] = { .type = NLA_U16 },
> + [NL80211_ATTR_CHANNEL] = { .type = NLA_U32 },
> + [NL80211_ATTR_RX_SENSITIVITY] = { .type = NLA_U32 },
> + [NL80211_ATTR_BSSID] = { .len = 6 },
> + [NL80211_ATTR_SSID] = { .type = NLA_STRING, .len = 32 },
> + [NL80211_ATTR_TRANSMIT_POWER] = { .type = NLA_U32 },
> + [NL80211_ATTR_FRAG_THRESHOLD] = { .type = NLA_U32 },
> + [NL80211_ATTR_INFORMATION_ELEMENT] = { .type = NLA_CUSTOM_CHECK,
> + .check = check_information_element },
Just use a nested attribute here, this new array format you introduce
having 1 byte ID, 1 byte len is equivalent to using a set of nested
attributes with nla_type=id, nla_len=len.
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [RFC 3/3] cfg80211 thoughts on configuration
2006-09-20 6:33 ` Thomas Graf
@ 2006-09-20 7:03 ` Johannes Berg
2006-09-20 7:07 ` Thomas Graf
0 siblings, 1 reply; 14+ messages in thread
From: Johannes Berg @ 2006-09-20 7:03 UTC (permalink / raw)
To: Thomas Graf
Cc: netdev, John W. Linville, Michael Buesch, Jean Tourrilhes,
Jiri Benc, James P. Ketrenos, Mohamed Abbas, Ulrich Kunitz,
Daniel Drake
On Wed, 2006-09-20 at 08:33 +0200, Thomas Graf wrote:
> I think I brought this up already, it's a lot easier to understand
> things if you keep it symmetric, i.e. NL80211_CMD_GET_CONFIG triggers
> sending a NL80211_CMD_NEW_CONFIG.
Yes, I think you did :) I'll do that as soon as I get around to
reworking it (hoping for more comments...)
> Just use a nested attribute here, this new array format you introduce
> having 1 byte ID, 1 byte len is equivalent to using a set of nested
> attributes with nla_type=id, nla_len=len.
No, it is only validated, it is then supposed to be copied verbatim into
some 802.11 frames. I thought validating it would be a good idea to not
send out totally bogus frames, but I didn't want to have to mangle it in
the kernel.
johannes
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC 3/3] cfg80211 thoughts on configuration
2006-09-20 7:03 ` Johannes Berg
@ 2006-09-20 7:07 ` Thomas Graf
0 siblings, 0 replies; 14+ messages in thread
From: Thomas Graf @ 2006-09-20 7:07 UTC (permalink / raw)
To: Johannes Berg
Cc: netdev, John W. Linville, Michael Buesch, Jean Tourrilhes,
Jiri Benc, James P. Ketrenos, Mohamed Abbas, Ulrich Kunitz,
Daniel Drake
* Johannes Berg <johannes@sipsolutions.net> 2006-09-20 09:03
> > Just use a nested attribute here, this new array format you introduce
> > having 1 byte ID, 1 byte len is equivalent to using a set of nested
> > attributes with nla_type=id, nla_len=len.
>
> No, it is only validated, it is then supposed to be copied verbatim into
> some 802.11 frames. I thought validating it would be a good idea to not
> send out totally bogus frames, but I didn't want to have to mangle it in
> the kernel.
I see, fair enough, wasn't able to get that from your code.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: more nl80211 stuff
2006-09-14 10:46 more nl80211 stuff Johannes Berg
` (2 preceding siblings ...)
2006-09-14 10:53 ` [RFC 3/3] cfg80211 thoughts on configuration Johannes Berg
@ 2006-09-14 13:41 ` Dan Williams
2006-09-14 13:55 ` Johannes Berg
3 siblings, 1 reply; 14+ messages in thread
From: Dan Williams @ 2006-09-14 13:41 UTC (permalink / raw)
To: Johannes Berg
Cc: netdev, John W. Linville, Michael Buesch, Jean Tourrilhes,
Jiri Benc, James P. Ketrenos, Mohamed Abbas, Ulrich Kunitz,
Daniel Drake
On Thu, 2006-09-14 at 12:46 +0200, Johannes Berg wrote:
> Hi,
>
> Last night I thought a bit more about configuration handling with
> cfg80211/nl80211 and have refined the original framework to be more
> split into cfg80211 and nl80211 stuff.
Can you describe a bit more what the scope of each of nl80211 and
cfg80211 is? Not sure I entirely understand the split and where the
line is drawn.
Thanks,
Dan
> As a followup, I'll post three patches, the first two are essentially
> the original ones respun, while the third one represents my current
> thoughts (a bit less I guess) on actual configuration and WE
> compatibility.
>
> johannes
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: more nl80211 stuff
2006-09-14 13:41 ` more nl80211 stuff Dan Williams
@ 2006-09-14 13:55 ` Johannes Berg
0 siblings, 0 replies; 14+ messages in thread
From: Johannes Berg @ 2006-09-14 13:55 UTC (permalink / raw)
To: Dan Williams
Cc: netdev, John W. Linville, Michael Buesch, Jean Tourrilhes,
Jiri Benc, James P. Ketrenos, Mohamed Abbas, Ulrich Kunitz,
Daniel Drake
On Thu, 2006-09-14 at 09:41 -0400, Dan Williams wrote:
> Can you describe a bit more what the scope of each of nl80211 and
> cfg80211 is? Not sure I entirely understand the split and where the
> line is drawn.
Basically, I figured that cfg80211 is the kernel-internal interface and
nl80211 is just the primary userspace interface with WE compatibility
being a second one and possibly partial configurability in configfs
later. All drivers need to care about is cfg80211, hence I made the
split explicit.
johannes
^ permalink raw reply [flat|nested] 14+ messages in thread