diff mbox

[v3] Add rx_bytes64 and tx_bytes64 and use them for RADIUS accounting

Message ID CAGnO3dprqqp97qPE+jzPWzjMd1b5zxekks_CWFEnSPFSKFNO7Q@mail.gmail.com
State Superseded
Headers show

Commit Message

Nick Lowe Feb. 19, 2016, 2:55 p.m. UTC
Add rx_bytes64 and tx_bytes64 and populate them using
 NL80211_STA_INFO_RX_BYTES64 and NL80211_STA_INFO_TX_BYTES64 where support for
 these are available. This resolves the race vulnerable 32-bit value
 wrap/overflow. Rework RADIUS accounting to use these for Acct-Input-Octets,
 Acct-Input-Gigawords, Acct-Output-Octets and Acct-Output-Gigawords, these
 values are often used for billing purposes.

Signed-off-by: Nick Lowe <nick.lowe@lugatech.com>
---
 src/ap/accounting.c          | 75 ++++++++++++++++++++++++++------------------
 src/ap/ctrl_iface_ap.c       |  7 +++--
 src/ap/sta_info.h            | 10 +++---
 src/drivers/driver.h         |  1 +
 src/drivers/driver_hostap.c  | 14 +++++----
 src/drivers/driver_nl80211.c |  6 ++++
 6 files changed, 70 insertions(+), 43 deletions(-)

Comments

Nick Lowe Feb. 19, 2016, 3:28 p.m. UTC | #1
Having a bad day, screwed up in this v3. Sorry. Ignore again. :(

On Fri, Feb 19, 2016 at 2:55 PM, Nick Lowe <nick.lowe@lugatech.com> wrote:
>  Add rx_bytes64 and tx_bytes64 and populate them using
>  NL80211_STA_INFO_RX_BYTES64 and NL80211_STA_INFO_TX_BYTES64 where support for
>  these are available. This resolves the race vulnerable 32-bit value
>  wrap/overflow. Rework RADIUS accounting to use these for Acct-Input-Octets,
>  Acct-Input-Gigawords, Acct-Output-Octets and Acct-Output-Gigawords, these
>  values are often used for billing purposes.
>
> Signed-off-by: Nick Lowe <nick.lowe@lugatech.com>
> ---
>  src/ap/accounting.c          | 75 ++++++++++++++++++++++++++------------------
>  src/ap/ctrl_iface_ap.c       |  7 +++--
>  src/ap/sta_info.h            | 10 +++---
>  src/drivers/driver.h         |  1 +
>  src/drivers/driver_hostap.c  | 14 +++++----
>  src/drivers/driver_nl80211.c |  6 ++++
>  6 files changed, 70 insertions(+), 43 deletions(-)
>
> diff --git a/src/ap/accounting.c b/src/ap/accounting.c
> index f3ce121..ae6d26b 100644
> --- a/src/ap/accounting.c
> +++ b/src/ap/accounting.c
> @@ -167,19 +167,30 @@ static int accounting_sta_update_stats(struct
> hostapd_data *hapd,
>      if (hostapd_drv_read_sta_data(hapd, data, sta->addr))
>          return -1;
>
> -    if (sta->last_rx_bytes > data->rx_bytes)
> -        sta->acct_input_gigawords++;
> -    if (sta->last_tx_bytes > data->tx_bytes)
> -        sta->acct_output_gigawords++;
> -    sta->last_rx_bytes = data->rx_bytes;
> -    sta->last_tx_bytes = data->tx_bytes;
> +    if (sta->last_rx_bytes_lo > data->rx_bytes)
> +        sta->last_rx_bytes_hi++;
> +    sta->last_rx_bytes_lo = data->rx_bytes;
> +
> +    if (sta->last_tx_bytes_lo > data->tx_bytes)
> +        sta->last_tx_bytes_hi++;
> +    sta->last_tx_bytes_lo = data->tx_bytes;
> +
> +    sta->last_rx_bytes64 = data->rx_bytes64;
> +    sta->last_tx_bytes64 = data->tx_bytes64;
>
>      hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
>                 HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
> -               "Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
> -               "Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
> -               sta->last_rx_bytes, sta->acct_input_gigawords,
> -               sta->last_tx_bytes, sta->acct_output_gigawords);
> +               "last_rx_bytes_lo=%lu last_rx_bytes_hi=%lu "
> +               "last_tx_bytes_lo=%lu last_tx_bytes_hi=%lu "
> +               "last_rx_bytes64=%llu "
> +               "last_tx_bytes64=%llu",
> +               (unsigned long)sta->last_rx_bytes_lo,
> +               (unsigned long)(sta->last_rx_bytes_hi >> 32),
> +               (unsigned long)sta->last_tx_bytes_lo,
> +               (unsigned long)(sta->last_tx_bytes_hi >> 32),
> +               (unsigned long long)sta->last_rx_bytes64,
> +               (unsigned long long)sta->last_tx_bytes64
> +              );
>
>      return 0;
>  }
> @@ -224,8 +235,12 @@ void accounting_sta_start(struct hostapd_data
> *hapd, struct sta_info *sta)
>                 (long unsigned int) sta->acct_session_id);
>
>      os_get_reltime(&sta->acct_session_start);
> -    sta->last_rx_bytes = sta->last_tx_bytes = 0;
> -    sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
> +    sta->last_rx_bytes_hi = 0;
> +    sta->last_rx_bytes_lo = 0;
> +    sta->last_tx_bytes_hi = 0;
> +    sta->last_tx_bytes_lo = 0;
> +    sta->last_rx_bytes64 = 0;
> +    sta->last_tx_bytes64 = 0;
>      hostapd_drv_sta_clear_stats(hapd, sta->addr);
>
>      if (!hapd->conf->radius->acct_server)
> @@ -254,7 +269,7 @@ static void accounting_sta_report(struct hostapd_data *hapd,
>      int cause = sta->acct_terminate_cause;
>      struct hostap_sta_driver_data data;
>      struct os_reltime now_r, diff;
> -    u32 gigawords;
> +    unsigned long long bytes;
>
>      if (!hapd->conf->radius->acct_server)
>          return;
> @@ -288,37 +303,35 @@ static void accounting_sta_report(struct
> hostapd_data *hapd,
>              wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
>              goto fail;
>          }
> +        if (data.rx_bytes64 > 0)
> +            bytes = data.rx_bytes64;
> +        else
> +            bytes = ((unsigned long long)sta->last_rx_bytes_hi << 32)
> | data.rx_bytes;
>          if (!radius_msg_add_attr_int32(msg,
>                             RADIUS_ATTR_ACCT_INPUT_OCTETS,
> -                           data.rx_bytes)) {
> +                           (u32)bytes)) {
>              wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets");
>              goto fail;
>          }
> -        gigawords = sta->acct_input_gigawords;
> -#if __WORDSIZE == 64
> -        gigawords += data.rx_bytes >> 32;
> -#endif
> -        if (gigawords &&
> -            !radius_msg_add_attr_int32(
> -                msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
> -                gigawords)) {
> +        if (!radius_msg_add_attr_int32(msg,
> +                           RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
> +                           (u32)(bytes >> 32))) {
>              wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
>              goto fail;
>          }
> +        if (data.tx_bytes64 > 0)
> +            bytes = data.tx_bytes64;
> +        else
> +            bytes = ((unsigned long long)sta->last_tx_bytes_hi << 32)
> | data.tx_bytes;
>          if (!radius_msg_add_attr_int32(msg,
>                             RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
> -                           data.tx_bytes)) {
> +                           (u32)bytes)) {
>              wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets");
>              goto fail;
>          }
> -        gigawords = sta->acct_output_gigawords;
> -#if __WORDSIZE == 64
> -        gigawords += data.tx_bytes >> 32;
> -#endif
> -        if (gigawords &&
> -            !radius_msg_add_attr_int32(
> -                msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
> -                gigawords)) {
> +        if (!radius_msg_add_attr_int32(msg,
> +                           RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
> +                           (u32)(bytes >> 32))) {
>              wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords");
>              goto fail;
>          }
> diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
> index c98978f..bce48a7 100644
> --- a/src/ap/ctrl_iface_ap.c
> +++ b/src/ap/ctrl_iface_ap.c
> @@ -35,9 +35,12 @@ static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
>          return 0;
>
>      ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
> -              "rx_bytes=%lu\ntx_bytes=%lu\n",
> +              "rx_bytes=%lu\ntx_bytes=%lu\n"
> +              "rx_bytes64=%llu\ntx_bytes64=%llu\n",
>                data.rx_packets, data.tx_packets,
> -              data.rx_bytes, data.tx_bytes);
> +              data.rx_bytes, data.tx_bytes,
> +              data.rx_bytes64, data.tx_bytes64
> +            );
>      if (os_snprintf_error(buflen, ret))
>          return 0;
>      return ret;
> diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
> index 359f480..d818afb 100644
> --- a/src/ap/sta_info.h
> +++ b/src/ap/sta_info.h
> @@ -107,10 +107,12 @@ struct sta_info {
>      int acct_terminate_cause; /* Acct-Terminate-Cause */
>      int acct_interim_interval; /* Acct-Interim-Interval */
>
> -    unsigned long last_rx_bytes;
> -    unsigned long last_tx_bytes;
> -    u32 acct_input_gigawords; /* Acct-Input-Gigawords */
> -    u32 acct_output_gigawords; /* Acct-Output-Gigawords */
> +    unsigned long last_rx_bytes_hi;
> +    unsigned long last_rx_bytes_lo;
> +    unsigned long last_tx_bytes_hi;
> +    unsigned long last_tx_bytes_lo;
> +    unsigned long long last_rx_bytes64;
> +    unsigned long long last_tx_bytes64;
>
>      u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
>
> diff --git a/src/drivers/driver.h b/src/drivers/driver.h
> index a4f6704..c2a81fe 100644
> --- a/src/drivers/driver.h
> +++ b/src/drivers/driver.h
> @@ -1377,6 +1377,7 @@ struct hostap_sta_driver_data {
>      unsigned long tx_retry_count;
>      int last_rssi;
>      int last_ack_rssi;
> +    unsigned long long rx_bytes64, tx_bytes64;
>  };
>
>  struct hostapd_sta_add_params {
> diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
> index 517a3bb..e1b7dc9 100644
> --- a/src/drivers/driver_hostap.c
> +++ b/src/drivers/driver_hostap.c
> @@ -579,7 +579,6 @@ static int hostap_read_sta_data(void *priv,
>      struct hostap_driver_data *drv = priv;
>      char buf[1024], line[128], *pos;
>      FILE *f;
> -    unsigned long val;
>
>      memset(data, 0, sizeof(*data));
>      snprintf(buf, sizeof(buf), "/proc/net/hostap/%s/" MACSTR,
> @@ -597,15 +596,18 @@ static int hostap_read_sta_data(void *priv,
>          if (!pos)
>              continue;
>          *pos++ = '\0';
> -        val = strtoul(pos, NULL, 10);
>          if (strcmp(line, "rx_packets") == 0)
> -            data->rx_packets = val;
> +            data->rx_packets = strtoul(pos, NULL, 10);
>          else if (strcmp(line, "tx_packets") == 0)
> -            data->tx_packets = val;
> +            data->tx_packets = strtoul(pos, NULL, 10);
>          else if (strcmp(line, "rx_bytes") == 0)
> -            data->rx_bytes = val;
> +            data->rx_bytes = strtoul(pos, NULL, 10);
>          else if (strcmp(line, "tx_bytes") == 0)
> -            data->tx_bytes = val;
> +            data->tx_bytes = strtoul(pos, NULL, 10);
> +        else if (strcmp(line, "rx_bytes64") == 0)
> +            data->rx_bytes64 = strtoull(pos, NULL, 20);
> +        else if (strcmp(line, "tx_bytes64") == 0)
> +            data->tx_bytes64 = strtoull(pos, NULL, 20);
>      }
>
>      fclose(f);
> diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
> index 0f312a0..9916bc6 100644
> --- a/src/drivers/driver_nl80211.c
> +++ b/src/drivers/driver_nl80211.c
> @@ -5327,6 +5327,8 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
>          [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
>          [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
>          [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
> +        [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
> +        [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
>      };
>
>      nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
> @@ -5365,6 +5367,10 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
>      if (stats[NL80211_STA_INFO_TX_FAILED])
>          data->tx_retry_failed =
>              nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
> +    if (stats[NL80211_STA_INFO_RX_BYTES64])
> +        data->rx_bytes64 = nla_get_u64(stats[NL80211_STA_INFO_RX_BYTES64]);
> +    if (stats[NL80211_STA_INFO_TX_BYTES64])
> +        data->tx_bytes64 = nla_get_u64(stats[NL80211_STA_INFO_TX_BYTES64]);
>
>      return NL_SKIP;
>  }
> --
> 2.7.1
diff mbox

Patch

From 52334b7fbbc58daeb79296841d74c04773ff174b Mon Sep 17 00:00:00 2001
From: Nick Lowe <nick.lowe@lugatech.com>
Date: Fri, 19 Feb 2016 14:50:34 +0000
Subject: [PATCH] Add rx_bytes64 and tx_bytes64 and populate these using
 NL80211_STA_INFO_RX_BYTES64 and NL80211_STA_INFO_TX_BYTES64 where support for
 these are available. This resolves the race vulnerable 32-bit value
 wrap/overflow. Rework RADIUS accounting to use these for Acct-Input-Octets,
 Acct-Input-Gigawords, Acct-Output-Octets and Acct-Output-Gigawords, these
 values are often used for billing purposes.

Signed-off-by: Nick Lowe <nick.lowe@lugatech.com>
---
 src/ap/accounting.c          | 75 ++++++++++++++++++++++++++------------------
 src/ap/ctrl_iface_ap.c       |  7 +++--
 src/ap/sta_info.h            | 10 +++---
 src/drivers/driver.h         |  1 +
 src/drivers/driver_hostap.c  | 14 +++++----
 src/drivers/driver_nl80211.c |  6 ++++
 6 files changed, 70 insertions(+), 43 deletions(-)

diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index f3ce121..ae6d26b 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -167,19 +167,30 @@  static int accounting_sta_update_stats(struct hostapd_data *hapd,
 	if (hostapd_drv_read_sta_data(hapd, data, sta->addr))
 		return -1;
 
-	if (sta->last_rx_bytes > data->rx_bytes)
-		sta->acct_input_gigawords++;
-	if (sta->last_tx_bytes > data->tx_bytes)
-		sta->acct_output_gigawords++;
-	sta->last_rx_bytes = data->rx_bytes;
-	sta->last_tx_bytes = data->tx_bytes;
+	if (sta->last_rx_bytes_lo > data->rx_bytes)
+		sta->last_rx_bytes_hi++;
+	sta->last_rx_bytes_lo = data->rx_bytes;
+
+	if (sta->last_tx_bytes_lo > data->tx_bytes)
+		sta->last_tx_bytes_hi++;
+	sta->last_tx_bytes_lo = data->tx_bytes;
+
+	sta->last_rx_bytes64 = data->rx_bytes64;
+	sta->last_tx_bytes64 = data->tx_bytes64;
 
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
 		       HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
-		       "Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
-		       "Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
-		       sta->last_rx_bytes, sta->acct_input_gigawords,
-		       sta->last_tx_bytes, sta->acct_output_gigawords);
+		       "last_rx_bytes_lo=%lu last_rx_bytes_hi=%lu "
+		       "last_tx_bytes_lo=%lu last_tx_bytes_hi=%lu "
+		       "last_rx_bytes64=%llu "
+		       "last_tx_bytes64=%llu",
+		       (unsigned long)sta->last_rx_bytes_lo,
+		       (unsigned long)(sta->last_rx_bytes_hi >> 32),
+		       (unsigned long)sta->last_tx_bytes_lo,
+		       (unsigned long)(sta->last_tx_bytes_hi >> 32),
+		       (unsigned long long)sta->last_rx_bytes64,
+		       (unsigned long long)sta->last_tx_bytes64
+		      );
 
 	return 0;
 }
@@ -224,8 +235,12 @@  void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
 		       (long unsigned int) sta->acct_session_id);
 
 	os_get_reltime(&sta->acct_session_start);
-	sta->last_rx_bytes = sta->last_tx_bytes = 0;
-	sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
+	sta->last_rx_bytes_hi = 0;
+	sta->last_rx_bytes_lo = 0;
+	sta->last_tx_bytes_hi = 0;
+	sta->last_tx_bytes_lo = 0;
+	sta->last_rx_bytes64 = 0;
+	sta->last_tx_bytes64 = 0;
 	hostapd_drv_sta_clear_stats(hapd, sta->addr);
 
 	if (!hapd->conf->radius->acct_server)
@@ -254,7 +269,7 @@  static void accounting_sta_report(struct hostapd_data *hapd,
 	int cause = sta->acct_terminate_cause;
 	struct hostap_sta_driver_data data;
 	struct os_reltime now_r, diff;
-	u32 gigawords;
+	unsigned long long bytes;
 
 	if (!hapd->conf->radius->acct_server)
 		return;
@@ -288,37 +303,35 @@  static void accounting_sta_report(struct hostapd_data *hapd,
 			wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
 			goto fail;
 		}
+		if (data.rx_bytes64 > 0)
+			bytes = data.rx_bytes64;
+		else
+			bytes = ((unsigned long long)sta->last_rx_bytes_hi << 32) | data.rx_bytes;
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_INPUT_OCTETS,
-					       data.rx_bytes)) {
+					       (u32)bytes)) {
 			wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets");
 			goto fail;
 		}
-		gigawords = sta->acct_input_gigawords;
-#if __WORDSIZE == 64
-		gigawords += data.rx_bytes >> 32;
-#endif
-		if (gigawords &&
-		    !radius_msg_add_attr_int32(
-			    msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
-			    gigawords)) {
+		if (!radius_msg_add_attr_int32(msg,
+					       RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
+					       (u32)(bytes >> 32))) {
 			wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
 			goto fail;
 		}
+		if (data.tx_bytes64 > 0)
+			bytes = data.tx_bytes64;
+		else
+			bytes = ((unsigned long long)sta->last_tx_bytes_hi << 32) | data.tx_bytes;
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
-					       data.tx_bytes)) {
+					       (u32)bytes)) {
 			wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets");
 			goto fail;
 		}
-		gigawords = sta->acct_output_gigawords;
-#if __WORDSIZE == 64
-		gigawords += data.tx_bytes >> 32;
-#endif
-		if (gigawords &&
-		    !radius_msg_add_attr_int32(
-			    msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
-			    gigawords)) {
+		if (!radius_msg_add_attr_int32(msg,
+					       RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
+					       (u32)(bytes >> 32))) {
 			wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords");
 			goto fail;
 		}
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index c98978f..bce48a7 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -35,9 +35,12 @@  static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
 		return 0;
 
 	ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
-			  "rx_bytes=%lu\ntx_bytes=%lu\n",
+			  "rx_bytes=%lu\ntx_bytes=%lu\n"
+			  "rx_bytes64=%llu\ntx_bytes64=%llu\n",
 			  data.rx_packets, data.tx_packets,
-			  data.rx_bytes, data.tx_bytes);
+			  data.rx_bytes, data.tx_bytes,
+			  data.rx_bytes64, data.tx_bytes64
+			);
 	if (os_snprintf_error(buflen, ret))
 		return 0;
 	return ret;
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 359f480..d818afb 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -107,10 +107,12 @@  struct sta_info {
 	int acct_terminate_cause; /* Acct-Terminate-Cause */
 	int acct_interim_interval; /* Acct-Interim-Interval */
 
-	unsigned long last_rx_bytes;
-	unsigned long last_tx_bytes;
-	u32 acct_input_gigawords; /* Acct-Input-Gigawords */
-	u32 acct_output_gigawords; /* Acct-Output-Gigawords */
+	unsigned long last_rx_bytes_hi;
+	unsigned long last_rx_bytes_lo;
+	unsigned long last_tx_bytes_hi;
+	unsigned long last_tx_bytes_lo;
+	unsigned long long last_rx_bytes64;
+	unsigned long long last_tx_bytes64;
 
 	u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
 
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index a4f6704..c2a81fe 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1377,6 +1377,7 @@  struct hostap_sta_driver_data {
 	unsigned long tx_retry_count;
 	int last_rssi;
 	int last_ack_rssi;
+	unsigned long long rx_bytes64, tx_bytes64;
 };
 
 struct hostapd_sta_add_params {
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 517a3bb..e1b7dc9 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -579,7 +579,6 @@  static int hostap_read_sta_data(void *priv,
 	struct hostap_driver_data *drv = priv;
 	char buf[1024], line[128], *pos;
 	FILE *f;
-	unsigned long val;
 
 	memset(data, 0, sizeof(*data));
 	snprintf(buf, sizeof(buf), "/proc/net/hostap/%s/" MACSTR,
@@ -597,15 +596,18 @@  static int hostap_read_sta_data(void *priv,
 		if (!pos)
 			continue;
 		*pos++ = '\0';
-		val = strtoul(pos, NULL, 10);
 		if (strcmp(line, "rx_packets") == 0)
-			data->rx_packets = val;
+			data->rx_packets = strtoul(pos, NULL, 10);
 		else if (strcmp(line, "tx_packets") == 0)
-			data->tx_packets = val;
+			data->tx_packets = strtoul(pos, NULL, 10);
 		else if (strcmp(line, "rx_bytes") == 0)
-			data->rx_bytes = val;
+			data->rx_bytes = strtoul(pos, NULL, 10);
 		else if (strcmp(line, "tx_bytes") == 0)
-			data->tx_bytes = val;
+			data->tx_bytes = strtoul(pos, NULL, 10);
+		else if (strcmp(line, "rx_bytes64") == 0)
+			data->rx_bytes64 = strtoull(pos, NULL, 20);
+		else if (strcmp(line, "tx_bytes64") == 0)
+			data->tx_bytes64 = strtoull(pos, NULL, 20);
 	}
 
 	fclose(f);
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 0f312a0..9916bc6 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5327,6 +5327,8 @@  static int get_sta_handler(struct nl_msg *msg, void *arg)
 		[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
 		[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
 		[NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
+		[NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
+		[NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
 	};
 
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
@@ -5365,6 +5367,10 @@  static int get_sta_handler(struct nl_msg *msg, void *arg)
 	if (stats[NL80211_STA_INFO_TX_FAILED])
 		data->tx_retry_failed =
 			nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
+	if (stats[NL80211_STA_INFO_RX_BYTES64])
+		data->rx_bytes64 = nla_get_u64(stats[NL80211_STA_INFO_RX_BYTES64]);
+	if (stats[NL80211_STA_INFO_TX_BYTES64])
+		data->tx_bytes64 = nla_get_u64(stats[NL80211_STA_INFO_TX_BYTES64]);
 
 	return NL_SKIP;
 }
-- 
2.7.1