add nl80211
Subsystems (3)
Johannes Berg
maintainerRFC 1/1 add nl80211
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 :) )
include/net/nl80211.h new file +79 -0
@@ -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 <[email protected]> +*/ + +/** +* 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 */
net/Kconfig +3 -0
@@ -250,6 +250,9 @@ source "net/ieee80211/Kconfig" config WIRELESS_EXT bool +config NETLINK_80211 + tristate + endif # if NET endmenu # Networking
net/Makefile +1 -0
@@ -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/
net/wireless/Makefile new file +4 -0
@@ -0,0 +1,4 @@ +obj-$(CONFIG_NETLINK_80211) += cfg80211.o + +cfg80211-objs := \ + nl80211.o
net/wireless/nl80211.c new file +515 -0
515 lines not on this page · raw message
include/linux/Kbuild +1 -1
@@ -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 \
include/linux/nl80211.h new file +90 -0
90 lines not on this page · raw message
Johannes Berg
maintainernet/wireless/nl80211.c line 331
Quoted 3 lines · Johannes Berg
net/wireless/nl80211.c new file +3
-0+/* 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 ]);
That's what you get for writing code too quickly ;) Both of these should be NL80211_ATTR_WIPHY of course!
johannes
Johannes Berg
maintainernet/wireless/nl80211.c line 109
Quoted 6 lines · Johannes Berg
net/wireless/nl80211.c new file +6
-0+ dev =dev_get_by_index (ifindex); + result =nl80211_drv_by_priv_locked (dev->ieee80211_ptr); +dev_put (dev); +if (result) +return result; + err = -ENODEV ;
Doh, bug (not checking dev != NULL) fixed in my local patch, will submit new ones later.
johannes
include/net/nl80211.h line 45
Quoted 2 lines · Johannes Berg
[...]
include/net/nl80211.h new file +1
-0+int (*add_virtual_intf)(void *priv,char *name);
What about initial interface type? (Hm, maybe it can be fixed to a STA mode, but it should be documented somewhere at least.)
Quoted 9 lines
include/net/nl80211.h new file +9
-0+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.
include/net/nl80211.h line 64
Quoted 10 lines
include/net/nl80211.h new file +10
-0+*/ +}; + +/* +* 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);
Could this function return the allocated wiphy index?
net/wireless/nl80211.c line 28
Quoted 12 lines
[...]
net/wireless/nl80211.c new file +11
-0+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; +};
Hm, most of drivers will need to take rtnl to stay compatible with WE. (Not a reason to take rtnl in nl80211, just a remark.)
Quoted 2 lines
[...]
+static structnl80211_registered_driver*nl80211_drv_by_priv_locked(void *priv)
Please use __ prefix instead of _locked suffix (e.g. __nl80211_drv_by_priv). That's more common convention in the kernel.
Quoted 17 lines
[...]
net/wireless/nl80211.c new file +16
-0+/* 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 ; + }
net/wireless/nl80211.c line 110
Quoted 10 lines
net/wireless/nl80211.c new file +10
-0+ +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 ; + }
If both ifindex and wiphy index are set and they disagree with each other, this should return an error.
net/wireless/nl80211.c line 134
Quoted 7 lines
net/wireless/nl80211.c new file +6
-0+ +return ERR_PTR (err); +} + +static struct nl80211_registered_driver * +nl80211_drv_from_info_with_locking (struct genl_info *info)
nl80211_get_drv_from_info would be better. Also, introduce a nl80211_put_drv function to ease tracking of locks.
net/wireless/nl80211.c line 216
Quoted 4 lines
[...]
net/wireless/nl80211.c new file +3
-0+static int nl80211_dump_wiphys (struct sk_buff *skb,struct netlink_callback *cb) +{ +/* I think need professional netlink help with dumpit calls */
I'm not able to help you here :-(
Looks really good now, I think.
Thanks,
Jiri
Signature · 2 lines
Jiri Benc SUSE Labs
Johannes Berg
maintainerQuoted 4 lines · Jiri Benc
include/net/nl80211.h line 45
Quoted 1 line
include/net/nl80211.h new file +1
-0+int (*add_virtual_intf)(void *priv,char *name);What about initial interface type? (Hm, maybe it can be fixed to a STA mode, but it should be documented somewhere at least.)
Actually, I already changed that.
Quoted 13 lines
Quoted 13 lines
include/net/nl80211.h new file +13
-0+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. +*/ +}; + +/*
Quoted 8 lines
Quoted 6 lines
+ * 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 intnl80211_register(struct nl80211_ops *ops, void *priv);Could this function return the allocated wiphy index?
Ah, yes, I wanted to do that all along. And a negative error code?
Quoted 2 lines
Hm, most of drivers will need to take rtnl to stay compatible with WE. (Not a reason to take rtnl in nl80211, just a remark.)
Not for packet injection or such though, dev_get is enough for that, I think.
Quoted 2 lines
Please use __ prefix instead of
_lockedsuffix (e.g.__nl80211_drv_by_priv). That's more common convention in the kernel.
I used to have a locking version too, which was without the suffix :)
Quoted 2 lines
If both ifindex and wiphy index are set and they disagree with each other, this should return an error.
Ok, I can do that.
johannes
* Johannes Berg <[email protected]> 2006-08-22 15:52
net/wireless/nl80211.c line 50
Quoted 6 lines
net/wireless/nl80211.c new file +6
-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 }, + [NL80211_ATTR_FLAGS ] = { .type =NLA_U32 }, + [NL80211_ATTR_QUEUE ] = { .type =NLA_U32 }, + [NL80211_ATTR_FRAME ] = { .type =NLA_STRING , .len =2500 },
Might want to put this in a header so userspace can see the limit.
Quoted 8 lines
net/wireless/nl80211.c new file +8
-0+ [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, +}; + +static int nl80211_get_commands (struct sk_buff *skb,struct genl_info *info) +{ +struct nl80211_registered_driver *drv; +struct sk_buff *msg; +void *hdr;
net/wireless/nl80211.c line 172
Quoted 10 lines
net/wireless/nl80211.c new file +10
-0+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 );
This isn't wrong in particular but usually we reverse the meaning of the command when sending back answers, i.e. in your case you'd define CMD_GET_COMMAND and CMD_NEW_COMMAND with the following behaviour:
CMD_GET_COMMAND
Search for command specified by the attributes and send back a CMD_NEW_COMMAND message.
CMD_GET_COMMAND with NLM_F_DUMP
Iterate over all commands and send back a CMD_NEW_COMMAND message for each command.
In your case I'd call it GET_CMDLIST and NEW_CMDLIST which means you request a command list with GET_CMDLIST and receive the answer with a CMD_NEWLIST message.
Quoted 8 lines
net/wireless/nl80211.c new file +8
-0+ 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 ;
net/wireless/nl80211.c line 195
Quoted 10 lines
net/wireless/nl80211.c new file +10
-0+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);
I'd just use the command id as attribute type:
NLA_PUT_FLAG(msg, NL80211_CMD_GET_COMMANDS); NLA_PUT_FLAG(msg, NL80211_CMD_GET_WIPHYS); ....
This makes checking avaibility of a command as easy as accessing an array for userspace.
net/wireless/nl80211.c line 199
Quoted 3 lines
net/wireless/nl80211.c new file +3
-0+ err =genlmsg_end (msg, hdr); +if (err) + goto msg_free;
genlmsg_end() can't fail, it just returns skb->len which is only of importance while dumping to see if there is still more to dump or not.
Quoted 4 lines
net/wireless/nl80211.c new file +4
-0+void *nl80211msg_new (struct sk_buff **skb,u32 pid,u32 seq,int flags,u8 cmd) +{ +void *hdr; +
net/wireless/nl80211.c line 482
Quoted 10 lines
net/wireless/nl80211.c new file +10
-0+ *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 ); + }
ENOBUFS
You might want to send out notifications for various events such as the additiona and deletion of virtual interfaces etc.
Johannes Berg
maintainerQuoted 1 line · Thomas Graf
Might want to put this in a header so userspace can see the limit.
Good point, thanks.
Quoted 3 lines
In your case I'd call it
GET_CMDLISTandNEW_CMDLISTwhich means you request a command list withGET_CMDLISTand receive the answer with aCMD_NEWLISTmessage.
Yeah, ok, I think I understood this now :)
Quoted 8 lines
I'd just use the command id as attribute type:
NLA_PUT_FLAG(msg, NL80211_CMD_GET_COMMANDS); NLA_PUT_FLAG(msg, NL80211_CMD_GET_WIPHYS); ....This makes checking avaibility of a command as easy as accessing an array for userspace.
Good point. However, userspace will need to be aware to parse this with the max_cmd instead of max_attr :)
Quoted 7 lines
net/wireless/nl80211.c line 199
Quoted 3 lines
net/wireless/nl80211.c new file +3
-0+ err =genlmsg_end (msg, hdr); +if (err) + goto msg_free;
genlmsg_end()can't fail, it just returnsskb->lenwhich is only of importance while dumping to see if there is still more to dump or not.
Whoops :)
Quoted 2 lines
You might want to send out notifications for various events such as the additiona and deletion of virtual interfaces etc.
Yeah, I'm not sure how to do that yet, maybe have exported functions. Currently, d80211 can also create virtual interfaces via sysfs so...
johannes
Johannes Berg
maintainerThis 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 :) )
include/net/nl80211.h new file +83 -0
@@ -0,0 +1,83 @@ +#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 <[email protected]> +*/ + +/** +* 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, +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 nl80211 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 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 */
net/Kconfig +3 -0
@@ -250,6 +250,9 @@ source "net/ieee80211/Kconfig" config WIRELESS_EXT bool +config NETLINK_80211 + tristate + endif # if NET endmenu # Networking
net/Makefile +1 -0
@@ -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/
net/wireless/Makefile new file +4 -0
@@ -0,0 +1,4 @@ +obj-$(CONFIG_NETLINK_80211) += cfg80211.o + +cfg80211-objs := \ + nl80211.o
net/wireless/nl80211.c new file +583 -0
583 lines not on this page · raw message
include/linux/Kbuild +1 -1
@@ -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 \
include/linux/nl80211.h new file +131 -0
131 lines not on this page · raw message
* Johannes Berg <[email protected]> 2006-08-24 18:07
Quoted 16 lines
net/wireless/nl80211.c new file +16
-0+static int nl80211_get_cmdlist (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_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)) {
net/wireless/nl80211.c line 205
Quoted 10 lines
net/wireless/nl80211.c new file +10
-0+ 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; + data =nla_data (start);
This data variable is now unused.
Quoted 13 lines
net/wireless/nl80211.c new file +13
-0+static int nl80211_get_wiphys (struct sk_buff *skb,struct genl_info *info) +{ +struct sk_buff *msg; +void *hdr; +struct nlattr *start; +u32 *data; +struct nl80211_registered_driver *drv; + + hdr =nl80211msg_new (&msg, info->snd_pid, info->snd_seq,0 , +NL80211_CMD_NEW_WIPHYS ); +if (IS_ERR (hdr)) +return PTR_ERR (hdr); +
net/wireless/nl80211.c line 254
Quoted 10 lines
net/wireless/nl80211.c new file +10
-0+ start =nla_nest_start (msg,NL80211_ATTR_WIPHY ); +if (!start) + goto nla_put_failure; + data =nla_data (start); + +mutex_lock (&nl80211_drv_mutex); +list_for_each_entry (drv, &nl80211_drv_list, list) { +skb_put (msg,sizeof (*data)); + *data++ = drv->wiphy; + }
I'd use normal u32 attributes here as well and simply enumerate their type 1..n.
int idx = 1 list_for_each_entry(drv, &nl80211_drv_list, list) NLA_PUT_U32(msg, idx++, drv->wiphy);
The additional header seems waste but this way you stay flexible and can extend the protocol later on. Attribute lengths are checked with an open end in mind, i.e. you can put more stuff behind that u32 in the future and your old applications will still work.
You also might want to consider returning ifindex and the associated name.
net/wireless/nl80211.c line 279
Quoted 13 lines
net/wireless/nl80211.c new file +13
-0+static int addifidx (void *data,int ifidx) +{ +struct sk_buff *msg = data; +u32 *p; + +if (unlikely (skb_tailroom (msg) <4 )) +return -ENOSPC ; + + p = (u32 *)skb_put (msg,4 ); + *p = ifidx; + +return 0 ; +}
Same here, just use nla_put_u32()
Quoted 13 lines
net/wireless/nl80211.c new file +13
-0+static int nl80211_get_intfs (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_get_drv_from_info (info); +if (IS_ERR (drv)) +return PTR_ERR (drv); +
net/wireless/nl80211.c line 303
Quoted 10 lines
net/wireless/nl80211.c new file +10
-0+ 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_IFINDEX );
Try not to reuse the same attribute type for different purposes, it will force you to duplicate the validation policy for every single command and things become very error prone.
Johannes Berg
maintainerQuoted 7 lines · Thomas Graf
I'd use normal u32 attributes here as well and simply enumerate their type 1..n.
int idx = 1 list_for_each_entry(drv, &nl80211_drv_list, list) NLA_PUT_U32(msg, idx++, drv->wiphy);
Quoted 8 lines
The additional header seems waste but this way you stay flexible and can extend the protocol later on. Attribute lengths are checked with an open end in mind, i.e. you can put more stuff behind that u32 in the future and your old applications will still work.
You also might want to consider returning ifindex and the associated name.
That'd be a list of ifindexes again...
Quoted 5 lines
Quoted 1 line
+static int
nl80211_get_intfs(struct sk_buff *skb, struct genl_info *info)Try not to reuse the same attribute type for different purposes, it will force you to duplicate the validation policy for every single command and things become very error prone.
I completely reworked that now so it will:
* create a nested NL80211_ATTR_INTERFACE_LIST with nested {
* 1..N attributes, with nested {
* ATTR_IFINDEX and
* ATTR_IFNAME
}
}
how does that sound? Maybe I should do the same for the WIPHY list? i.e. create a new type ATTR_WIPHY_LIST and within that nest numbered attributes (array indexes) and in there put ATTR_WIPHY? So possibly I could also put ATTR_INTERFACE_LIST in there as well later?
johannes
* Johannes Berg <[email protected]> 2006-08-25 11:04
Quoted 8 lines
I completely reworked that now so it will:
* create a nestedNL80211_ATTR_INTERFACE_LISTwith nested {
* 1..N attributes, with nested {
*ATTR_IFINDEXand
*ATTR_IFNAME
}
}
Quoted 4 lines
how does that sound? Maybe I should do the same for the WIPHY list? i.e. create a new type
ATTR_WIPHY_LISTand within that nest numbered attributes (array indexes) and in there putATTR_WIPHY? So possibly I could also putATTR_INTERFACE_LISTin there as well later?
That's exactly what I would have done as well.
Johannes Berg
maintainerQuoted 1 line · Thomas Graf
That's exactly what I would have done as well.
Alright. Changing it, then I'll repost. Again :)
johannes
Johannes Berg
maintainerRFC 1/1 add nl80211
In reply to Johannes BergThis 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.
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.
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
include/net/nl80211.h new file +83 -0
@@ -0,0 +1,83 @@ +#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 <[email protected]> +*/ + +/** +* 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, +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 nl80211 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 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 */
net/Kconfig +3 -0
@@ -250,6 +250,9 @@ source "net/ieee80211/Kconfig" config WIRELESS_EXT bool +config NETLINK_80211 + tristate + endif # if NET endmenu # Networking
net/Makefile +1 -0
@@ -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/
net/wireless/Makefile new file +4 -0
@@ -0,0 +1,4 @@ +obj-$(CONFIG_NETLINK_80211) += cfg80211.o + +cfg80211-objs := \ + nl80211.o
net/wireless/nl80211.c new file +604 -0
604 lines not on this page · raw message
include/linux/Kbuild +1 -1
@@ -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 \
include/linux/nl80211.h new file +137 -0
137 lines not on this page · raw message