Re: [PATCH] Use libnl and nl80211 to get bitrate information



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]