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; } /*
_______________________________________________ NetworkManager-list mailing list NetworkManager-list@gnome.org http://mail.gnome.org/mailman/listinfo/networkmanager-list