Re: [PATCH] Use libnl and nl80211 to get bitrate information
- From: Valmantas Palikša <walmis gmail com>
- To: networkmanager-list gnome org
- Subject: Re: [PATCH] Use libnl and nl80211 to get bitrate information
- Date: Sat, 03 Oct 2009 12:55:46 +0300
I've revised the patch to use system's nl80211.h with ifdefs. If nl80211
is too old the code will not be compiled and wext will be used
On Thu, 2009-09-24 at 18:48 +0300, Valmantas Palikša wrote:
> This patch allows us to see 11n bitrates in nm-applet's connection
> properties.
>
> Comments/suggestions?
> _______________________________________________
> NetworkManager-list mailing list
> NetworkManager-list gnome org
> http://mail.gnome.org/mailman/listinfo/networkmanager-list
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c
index f2c9350..b192325 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -30,6 +30,13 @@
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/socket.h>
+#include <linux/nl80211.h>
+
#include "nm-glib-compat.h"
#include "nm-device.h"
@@ -53,6 +60,7 @@
#include "nm-setting-ip6-config.h"
#include "NetworkManagerSystem.h"
+
static gboolean impl_device_get_access_points (NMDeviceWifi *device,
GPtrArray **aps,
GError **err);
@@ -1561,8 +1569,59 @@ out:
close (sk);
return priv->ssid;
}
+/* this symbol should be defined in recent nl80211.h */
+#ifdef NL80211_ATTR_REASON_CODE
+#define LIBNL_BITRATES
+#endif
+
+#ifdef LIBNL_BITRATES
+static int bitrate_cb(struct nl_msg *msg, void *arg)
+{
+ int *rate = (int*)arg;
+
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
+ struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
+ static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
+ [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
+ };
+ static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
+ [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
+ [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
+ [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
+ [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
+ };
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_STA_INFO]) {
+ *rate = 0;
+ return NL_STOP;
+ }
+ if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
+ tb[NL80211_ATTR_STA_INFO],
+ stats_policy)) {
+ *rate = 0;
+ return NL_STOP;
+ }
+
+ if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
+ if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
+ sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy)) {
+ *rate = 0;
+ } else {
+ if (rinfo[NL80211_RATE_INFO_BITRATE]) {
+ *rate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100;
+ }
+ }
+ }
+ return NL_STOP;
+}
+#endif
/*
* nm_device_wifi_get_bitrate
*
@@ -1573,21 +1632,62 @@ out:
static guint32
nm_device_wifi_get_bitrate (NMDeviceWifi *self)
{
+ NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+ int rate = 0;
+
+#ifdef LIBNL_BITRATES
+ struct nl_handle *sock;
+ struct nl_msg *msg;
+ int family;
+
int err = -1, fd;
struct iwreq wrq;
+#endif
+
g_return_val_if_fail (self != NULL, 0);
- fd = socket (PF_INET, SOCK_DGRAM, 0);
- if (fd < 0)
- return 0;
+#ifdef LIBNL_BITRATES
+
+ sock = nl_handle_alloc();
+ msg = nlmsg_alloc();
+
+ genl_connect(sock);
- memset (&wrq, 0, sizeof (wrq));
- strncpy (wrq.ifr_name, nm_device_get_iface (NM_DEVICE (self)), IFNAMSIZ);
- err = ioctl (fd, SIOCGIWRATE, &wrq);
- close (fd);
+ family = genl_ctrl_resolve(sock, "nl80211");
+
+ genlmsg_put(msg, 0, 0, family, 0, NLM_F_DUMP, NL80211_CMD_GET_STATION, 0);
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, priv->ifindex);
+
+ if(nl_send_auto_complete(sock, msg) < 0)
+ goto cleanup;
- return ((err == 0) ? wrq.u.bitrate.value / 1000 : 0);
+ nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, bitrate_cb, &rate);
+
+ nl_recvmsgs_default(sock);
+
+
+cleanup:
+ nlmsg_free(msg);
+ nl_handle_destroy(sock);
+
+#endif
+
+ /* nl80211 failed to return a valid bitrate, let's try wext */
+ if(rate == 0) {
+
+ fd = socket (PF_INET, SOCK_DGRAM, 0);
+ if (fd < 0)
+ return 0;
+
+ memset (&wrq, 0, sizeof (wrq));
+ strncpy (wrq.ifr_name, nm_device_get_iface (NM_DEVICE (self)), IFNAMSIZ);
+ err = ioctl (fd, SIOCGIWRATE, &wrq);
+ close (fd);
+
+ return ((err == 0) ? wrq.u.bitrate.value / 1000 : 0);
+ }
+ return rate;
}
/*
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]