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



Latest version

On Sat, 2009-10-03 at 12:55 +0300, Valmantas Palikša wrote:
> 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..1c44f7e 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -30,6 +30,12 @@
 #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"
@@ -1561,8 +1567,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 +1630,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]