This makes hostapd use nl80211 (via libnl) to create/remove interfaces.
Also lays the foundation for using nl80211 in hostapd.
Signed-off-by: Johannes Berg <[email protected]>
---
I have tested this code with the patch to use monitor interfaces instead
of the management interface, but wasn't able to test exactly these code
paths because none of the cards we have drivers for currently allow
multiple BSSes.
hostapd/Makefile | 1
hostapd/defconfig | 5
hostapd/driver_devicescape.c | 221 ++++++++++++++++++++++++-------------------
3 files changed, 133 insertions(+), 94 deletions(-)
--- hostap.orig/hostapd/driver_devicescape.c 2007-08-24 22:34:17.000000000 +0200
+++ hostap/hostapd/driver_devicescape.c 2007-08-24 22:34:19.000000000 +0200
@@ -16,24 +16,22 @@
#include "includes.h"
#include <sys/ioctl.h>
-
-#ifdef USE_KERNEL_HEADERS
-#include <asm/types.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+#include <linux/nl80211.h>
+#include <net/if.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h> /* The L2 protocols */
-#include <linux/if_arp.h>
#include <linux/wireless.h>
-#else /* USE_KERNEL_HEADERS */
#include <net/if_arp.h>
-#include <netpacket/packet.h>
-#include "wireless_copy.h"
-#endif /* USE_KERNEL_HEADERS */
#include "hostapd.h"
#include "driver.h"
#include "ieee802_1x.h"
#include "eloop.h"
-#include "priv_netlink.h"
#include "ieee802_11.h"
#include "sta_info.h"
#include "hw_features.h"
@@ -67,6 +65,9 @@ struct i802_driver_data {
int wext_sock; /* socket for wireless events */
int we_version;
+ struct nl_handle *nl_handle;
+ struct nl_cache *nl_cache;
+ struct genl_family *nl80211;
};
@@ -787,56 +788,103 @@ static int i802_set_tx_queue_params(void
}
-static int i802_bss_add(void *priv, const char *ifname, const u8 *bssid)
+static void nl80211_remove_iface(struct i802_driver_data *drv, int ifidx)
{
- struct i802_driver_data *drv = priv;
- struct prism2_hostapd_param *param;
+ struct nl_msg *msg;
- param = os_zalloc(sizeof(struct prism2_hostapd_param) + ETH_ALEN);
- if (param == NULL)
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_VIRTUAL_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0)
+ nla_put_failure:
+ printf("Failed to remove interface.\n");
+ nlmsg_free(msg);
+}
+
+
+static int nl80211_create_iface(struct i802_driver_data *drv,
+ const char *ifname,
+ enum nl80211_iftype iftype,
+ const u8 *addr)
+{
+ struct nl_msg *msg;
+ int ifidx;
+ struct ifreq ifreq;
+ struct iwreq iwr;
+
+ msg = nlmsg_alloc();
+ if (!msg)
return -1;
- param->cmd = PRISM2_HOSTAPD_ADD_IF;
- param->u.if_info.type = HOSTAP_IF_BSS;
- memcpy(param->u.if_info.data, bssid, ETH_ALEN);
- os_strlcpy((char *) param->u.if_info.name, ifname, IFNAMSIZ);
-
- if (hostapd_ioctl(drv, param,
- sizeof(struct prism2_hostapd_param) + ETH_ALEN)) {
- printf("Could not add bss iface: %s.\n", ifname);
- free(param);
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_ADD_VIRTUAL_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->hapd->conf->iface));
+ NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0) {
+ nla_put_failure:
+ printf("Failed to create interface %s.\n", ifname);
+ nlmsg_free(msg);
return -1;
}
- free(param);
+ nlmsg_free(msg);
- return 0;
+ ifidx = if_nametoindex(ifname);
+
+ if (ifidx <= 0)
+ return -1;
+
+ if (addr) {
+ switch (iftype) {
+ case NL80211_IFTYPE_AP:
+ os_strlcpy(ifreq.ifr_name, ifname, IFNAMSIZ);
+ memcpy(ifreq.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+ ifreq.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifreq)) {
+ nl80211_remove_iface(drv, ifidx);
+ return -1;
+ }
+ break;
+ case NL80211_IFTYPE_WDS:
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ);
+ iwr.u.addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwr.u.addr.sa_data, addr, ETH_ALEN);
+ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr))
+ return -1;
+ break;
+ default:
+ /* nothing */
+ break;
+ }
+ }
+
+ return ifidx;
}
-static int i802_bss_remove(void *priv, const char *ifname)
+static int i802_bss_add(void *priv, const char *ifname, const u8 *bssid)
{
- struct i802_driver_data *drv = priv;
- struct prism2_hostapd_param *param;
- int ret = 0;
-
- param = os_zalloc(sizeof(struct prism2_hostapd_param) + ETH_ALEN);
- if (param == NULL)
+ if (nl80211_create_iface(priv, ifname, NL80211_IFTYPE_AP, bssid) < 0)
return -1;
+ return 0;
+}
- param->cmd = PRISM2_HOSTAPD_REMOVE_IF;
- param->u.if_info.type = HOSTAP_IF_BSS;
- os_strlcpy((char *) param->u.if_info.name, ifname, IFNAMSIZ);
-
- if (hostapd_ioctl(drv, param,
- sizeof(struct prism2_hostapd_param) + ETH_ALEN)) {
- printf("Could not remove iface: %s.\n", ifname);
- ret = -1;
- }
-
- free(param);
- return ret;
+static int i802_bss_remove(void *priv, const char *ifname)
+{
+ nl80211_remove_iface(priv, if_nametoindex(ifname));
+ return 0;
}
@@ -961,13 +1009,13 @@ static int i802_set_short_slot_time(void
}
-static int i802_if_type(enum hostapd_driver_if_type type)
+static enum nl80211_iftype i802_if_type(enum hostapd_driver_if_type type)
{
switch (type) {
case HOSTAPD_IF_VLAN:
- return HOSTAP_IF_VLAN;
+ return NL80211_IFTYPE_AP_VLAN;
case HOSTAPD_IF_WDS:
- return HOSTAP_IF_WDS;
+ return NL80211_IFTYPE_WDS;
}
return -1;
}
@@ -977,32 +1025,8 @@ static int i802_if_add(const char *iface
enum hostapd_driver_if_type type, char *ifname,
const u8 *addr)
{
- struct i802_driver_data *drv = priv;
- struct prism2_hostapd_param *param;
-
- param = malloc(sizeof(struct prism2_hostapd_param) + ETH_ALEN);
- if (!param)
- return -1;
- memset(param, 0, sizeof(param));
-
- param->cmd = PRISM2_HOSTAPD_ADD_IF;
- param->u.if_info.type = i802_if_type(type);
- if (addr)
- memcpy(param->u.if_info.data, addr, ETH_ALEN);
- else
- memset(param->u.if_info.data, 0, ETH_ALEN);
- os_strlcpy((char *) param->u.if_info.name, ifname, IFNAMSIZ);
-
- /* FIX: should the size have + ETH_ALEN ? */
- if (hostapd_ioctl_iface(iface, drv, param,
- sizeof(struct prism2_hostapd_param))) {
- printf("Could not add iface: %s.\n", ifname);
- free(param);
+ if (nl80211_create_iface(priv, ifname, i802_if_type(type), addr) < 0)
return -1;
- }
-
- os_strlcpy(ifname, (char *) param->u.if_info.name, IFNAMSIZ);
- free(param);
return 0;
}
@@ -1018,28 +1042,7 @@ static int i802_if_update(void *priv, en
static int i802_if_remove(void *priv, enum hostapd_driver_if_type type,
const char *ifname, const u8 *addr)
{
- struct i802_driver_data *drv = priv;
- struct prism2_hostapd_param *param;
-
- param = malloc(sizeof(struct prism2_hostapd_param) + ETH_ALEN);
- if (!param)
- return -1;
- memset(param, 0, sizeof(param));
-
- param->cmd = PRISM2_HOSTAPD_REMOVE_IF;
- param->u.if_info.type = i802_if_type(type);
- if (addr)
- memcpy(param->u.if_info.data, addr, ETH_ALEN);
- else
- memset(param->u.if_info.data, 0, ETH_ALEN);
- os_strlcpy((char *) param->u.if_info.name, ifname, IFNAMSIZ);
- if (hostapd_ioctl(drv, param, sizeof(struct prism2_hostapd_param))) {
- printf("Could not remove iface: %s.\n", ifname);
- free(param);
- return -1;
- }
-
- free(param);
+ nl80211_remove_iface(priv, if_nametoindex(ifname));
return 0;
}
@@ -1525,6 +1528,32 @@ static int i802_init_sockets(struct i802
return -1;
}
+ /*
+ * initialise generic netlink and nl80211
+ */
+ drv->nl_handle = nl_handle_alloc();
+ if (!drv->nl_handle) {
+ printf("Failed to allocate netlink handle.\n");
+ return -1;
+ }
+
+ if (genl_connect(drv->nl_handle)) {
+ printf("Failed to connect to generic netlink.\n");
+ return -1;
+ }
+
+ drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
+ if (!drv->nl_cache) {
+ printf("Failed to allocate generic netlink cache.\n");
+ return -1;
+ }
+
+ drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
+ if (!drv->nl80211) {
+ printf("nl80211 not found.\n");
+ return -1;
+ }
+
/* Enable management interface */
if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_MGMT_IF, 1) < 0) {
printf("Failed to enable management interface.\n");
@@ -1952,6 +1981,10 @@ static void i802_deinit(void *priv)
if (drv->ioctl_sock >= 0)
close(drv->ioctl_sock);
+ genl_family_put(drv->nl80211);
+ nl_cache_free(drv->nl_cache);
+ nl_handle_destroy(drv->nl_handle);
+
free(drv);
}
--- hostap.orig/hostapd/Makefile 2007-08-24 22:34:10.000000000 +0200
+++ hostap/hostapd/Makefile 2007-08-24 22:34:19.000000000 +0200
@@ -118,6 +118,7 @@ endif
ifdef CONFIG_DRIVER_DEVICESCAPE
CFLAGS += -DCONFIG_DRIVER_DEVICESCAPE
OBJS += driver_devicescape.o
+LIBS += -lnl
endif
ifdef CONFIG_DRIVER_BSD
--- hostap.orig/hostapd/defconfig 2007-08-24 22:34:10.000000000 +0200
+++ hostap/hostapd/defconfig 2007-08-24 22:34:19.000000000 +0200
@@ -30,6 +30,11 @@ CONFIG_DRIVER_HOSTAP=y
# wireless-dev.git tree).
#WIRELESS_DEV=/usr/src/wireless-dev
#CFLAGS += -I$(WIRELESS_DEV)/net/mac80211
+# driver_devicescape.c requires a rather new libnl, probably not
+# shipped with your distribution yet
+#LIBNL=/usr/src/libnl
+#CFLAGS += -I$(LIBNL)/include
+#LIBS += -L$(LIBNL)/lib
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
On Tue, 2007-09-04 at 19:55 -0700, Jouni Malinen wrote:
> In my particular case, one of the main problems was in svn not working
> after libexpat update on Gentoo.. ;-) This made it a bit difficult to
> fetch the correct version.
Heh :)
> At this point, we are indeed talking about quite bleeding edge stuff,
> but I'm planning on releasing hostapd 0.6.1 at some point soonish and I
> would hope that mainline Linux kernel will get enough stuff for at least
> minimal AP functionality and at that point, I do not really want to
> point people at an svn repository as the only means of getting a
> required library..
What's "soonish"? Realistically, if we keep working at this rate, I
don't expect we'll have AP functionality in before 2.6.26.
johannes
On Tue, Sep 04, 2007 at 04:55:16PM +0200, Johannes Berg wrote:
> Also, since this affects git trees only... To use this you actually have
> to have hostap git, wireless-dev git so what's the big deal with
> requiring libnl svn? :)
In my particular case, one of the main problems was in svn not working
after libexpat update on Gentoo.. ;-) This made it a bit difficult to
fetch the correct version.
At this point, we are indeed talking about quite bleeding edge stuff,
but I'm planning on releasing hostapd 0.6.1 at some point soonish and I
would hope that mainline Linux kernel will get enough stuff for at least
minimal AP functionality and at that point, I do not really want to
point people at an svn repository as the only means of getting a
required library..
--
Jouni Malinen PGP id EFC895FA
On Mon, 2007-09-03 at 18:16 -0700, Jouni Malinen wrote:
> Where are things like NL80211_ATTR_IFNAME and
> NL80211_CMD_ADD_VIRTUAL_INTERFACE defined? I would assume these are from
> linux/nl80211.h, but where should I get the version that includes these?
You have to use the one from wireless-dev as we don't ship it from
mainline yet.
> This is making it a bit difficult to build driver_devicescape.c and same
> goes for the requirement for svn trunk version of libnl.. Any idea how
> much code from libnl is needed here? Would it be major effort to do the
> needed calls without having to rely on libnl at or (or at least not on
> an unreleased svn trunk version)?
There's a whole bunch of code in libnl I use, all the generic netlink
family resolving etc. Maybe Thomas can prerelease a libnl with generic
netlink support?
> This is not good direction to go to.. I would really not like to include
> linux/*.h unless absolutely needed since these header files have been
> very likely to conflict with glibc ones and there is not really that
> much guarantees in people wanting to keep kernel header files suitable
> for inclusion into user space programs.
Actually, the latter point hasn't been true for a long time, ever since
David Woodhouse cleaned up exporting kernel headers to userspace glibc
has happily shipped them.
> I would much rather use these for now and should the /usr/include/linux
> directory in most distributions some day have all the needed stuff, then
> we could move towards using those.
It really ought to have the wireless stuff except for nl80211.h
johannes
On Tue, Sep 04, 2007 at 03:42:15PM +0200, Johannes Berg wrote:
> On Mon, 2007-09-03 at 18:16 -0700, Jouni Malinen wrote:
> > Where are things like NL80211_ATTR_IFNAME and
> > NL80211_CMD_ADD_VIRTUAL_INTERFACE defined? I would assume these are from
> > linux/nl80211.h, but where should I get the version that includes these?
>
> You have to use the one from wireless-dev as we don't ship it from
> mainline yet.
I was trying to use wireless-dev.. Which branch includes the values
shown above? I don't see them in either master or even everything..
(git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-dev.git)
> > This is making it a bit difficult to build driver_devicescape.c and same
> > goes for the requirement for svn trunk version of libnl.. Any idea how
> > much code from libnl is needed here? Would it be major effort to do the
> > needed calls without having to rely on libnl at or (or at least not on
> > an unreleased svn trunk version)?
>
> There's a whole bunch of code in libnl I use, all the generic netlink
> family resolving etc. Maybe Thomas can prerelease a libnl with generic
> netlink support?
OK. If there were a pre-release version, that would likely make this
quite a bit easier. Gentoo actually includes 1.0-pre6 which is the
latest pre-release and as such, I was kind of hoping for it to be new
enough. Then again, once I looked at the release date, I noticed it's
already a year old.. I don't really want to depend on this unless there
is a good likelyhood of there being a proper release with the needed
functionality in somewhat near future.
--
Jouni Malinen PGP id EFC895FA
On Tue, 2007-09-04 at 19:49 -0700, Jouni Malinen wrote:
> On Tue, Sep 04, 2007 at 03:42:15PM +0200, Johannes Berg wrote:
> > On Mon, 2007-09-03 at 18:16 -0700, Jouni Malinen wrote:
> > > Where are things like NL80211_ATTR_IFNAME and
> > > NL80211_CMD_ADD_VIRTUAL_INTERFACE defined? I would assume these are from
> > > linux/nl80211.h, but where should I get the version that includes these?
> >
> > You have to use the one from wireless-dev as we don't ship it from
> > mainline yet.
>
> I was trying to use wireless-dev.. Which branch includes the values
> shown above? I don't see them in either master or even everything..
> (git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-dev.git)
It should be in 'everything' in include/linux/nl80211.h
> OK. If there were a pre-release version, that would likely make this
> quite a bit easier. Gentoo actually includes 1.0-pre6 which is the
> latest pre-release and as such, I was kind of hoping for it to be new
> enough. Then again, once I looked at the release date, I noticed it's
> already a year old.. I don't really want to depend on this unless there
> is a good likelyhood of there being a proper release with the needed
> functionality in somewhat near future.
Up to Thomas, I guess.
johannes
On Wed, 2007-09-05 at 19:38 -0700, Jouni Malinen wrote:
> On Fri, Aug 24, 2007 at 10:37:30PM +0200, Johannes Berg wrote:
> > This makes hostapd use nl80211 (via libnl) to create/remove interfaces.
> > Also lays the foundation for using nl80211 in hostapd.
>
> Thanks, applied.
Great, thanks.
> I haven't had a chance of testing this yet, but at least I'm now back in
> state where I can build everything successfully :-).
Good :)
> I will be traveling
> next couple of weeks at IEEE 802.11 meetings and will be very unlikely
> to test this any time soon (especially so, taken into account where the
> meetings are this time.. getting two meetings on consecutive weeks and
> on two Hawaiian islands is quite a nice combination ;-). Consequently,
> it is probably best to just get this in now and we'll fix multi-BSS
> things later, if needed.
Alright, sounds good. I don't think this breaks anything but I don't
have a mac80211 based driver that allows multiple BSSes and I don't have
all the radius stuff set up for VLANs. That said, I tested the actual
nl80211 interface by hand and it's working fine.
johannes
On Fri, Aug 24, 2007 at 10:37:30PM +0200, Johannes Berg wrote:
> This makes hostapd use nl80211 (via libnl) to create/remove interfaces.
> Also lays the foundation for using nl80211 in hostapd.
Where are things like NL80211_ATTR_IFNAME and
NL80211_CMD_ADD_VIRTUAL_INTERFACE defined? I would assume these are from
linux/nl80211.h, but where should I get the version that includes these?
This is making it a bit difficult to build driver_devicescape.c and same
goes for the requirement for svn trunk version of libnl.. Any idea how
much code from libnl is needed here? Would it be major effort to do the
needed calls without having to rely on libnl at or (or at least not on
an unreleased svn trunk version)?
> -#ifdef USE_KERNEL_HEADERS
> -#include <asm/types.h>
> +#include <netlink/genl/genl.h>
> +#include <netlink/genl/family.h>
> +#include <netlink/genl/ctrl.h>
> +#include <netlink/msg.h>
> +#include <netlink/attr.h>
> +#include <linux/nl80211.h>
> +#include <net/if.h>
> #include <linux/if_packet.h>
> #include <linux/if_ether.h> /* The L2 protocols */
> -#include <linux/if_arp.h>
> #include <linux/wireless.h>
> -#else /* USE_KERNEL_HEADERS */
This is not good direction to go to.. I would really not like to include
linux/*.h unless absolutely needed since these header files have been
very likely to conflict with glibc ones and there is not really that
much guarantees in people wanting to keep kernel header files suitable
for inclusion into user space programs.
> #include <net/if_arp.h>
> -#include <netpacket/packet.h>
> -#include "wireless_copy.h"
> -#include "priv_netlink.h"
I would much rather use these for now and should the /usr/include/linux
directory in most distributions some day have all the needed stuff, then
we could move towards using those.
--
Jouni Malinen PGP id EFC895FA
On Fri, Aug 24, 2007 at 10:37:30PM +0200, Johannes Berg wrote:
> This makes hostapd use nl80211 (via libnl) to create/remove interfaces.
> Also lays the foundation for using nl80211 in hostapd.
Thanks, applied.
> I have tested this code with the patch to use monitor interfaces instead
> of the management interface, but wasn't able to test exactly these code
> paths because none of the cards we have drivers for currently allow
> multiple BSSes.
I haven't had a chance of testing this yet, but at least I'm now back in
state where I can build everything successfully :-). I will be traveling
next couple of weeks at IEEE 802.11 meetings and will be very unlikely
to test this any time soon (especially so, taken into account where the
meetings are this time.. getting two meetings on consecutive weeks and
on two Hawaiian islands is quite a nice combination ;-). Consequently,
it is probably best to just get this in now and we'll fix multi-BSS
things later, if needed.
--
Jouni Malinen PGP id EFC895FA
On Tue, 2007-09-04 at 15:42 +0200, Johannes Berg wrote:
> > This is making it a bit difficult to build driver_devicescape.c and same
> > goes for the requirement for svn trunk version of libnl.. Any idea how
> > much code from libnl is needed here? Would it be major effort to do the
> > needed calls without having to rely on libnl at or (or at least not on
> > an unreleased svn trunk version)?
>
> There's a whole bunch of code in libnl I use, all the generic netlink
> family resolving etc. Maybe Thomas can prerelease a libnl with generic
> netlink support?
Also, since this affects git trees only... To use this you actually have
to have hostap git, wireless-dev git so what's the big deal with
requiring libnl svn? :)
johannes