diff --git a/include/iwinfo.h b/include/iwinfo.h index 2a841be..c79b939 100644 --- a/include/iwinfo.h +++ b/include/iwinfo.h @@ -409,6 +409,13 @@ struct iwinfo_ops { int (*hardware_name)(const char *, char *); int (*encryption)(const char *, char *); int (*phyname)(const char *, char *); + /* + * assoclist might receive a NULL buf as second element. + * In such case assoclist should only return the length + * of the expected buffer. + * Third element is always set to the size of the buffer. + * assoclist should stop parsing elements if this is reached. + */ int (*assoclist)(const char *, char *, int *); int (*txpwrlist)(const char *, char *, int *); int (*scanlist)(const char *, char *, int *); diff --git a/iwinfo_cli.c b/iwinfo_cli.c index 6f87d98..622d0ba 100644 --- a/iwinfo_cli.c +++ b/iwinfo_cli.c @@ -784,12 +784,12 @@ static void print_freqlist(const struct iwinfo_ops *iw, const char *ifname) static void print_assoclist(const struct iwinfo_ops *iw, const char *ifname) { - int i, len; - char buf[IWINFO_BUFSIZE]; + int i, len = 0; + char *buf = NULL; struct iwinfo_assoclist_entry *e; - if (iw->assoclist(ifname, buf, &len)) - { + /* Call assoclist with NULL buf to get number of element to alloc */ + if (iw->assoclist(ifname, NULL, &len)) { printf("No information available\n"); return; } @@ -799,6 +799,24 @@ static void print_assoclist(const struct iwinfo_ops *iw, const char *ifname) return; } + buf = malloc(len * sizeof(*e)); + if (!buf) { + printf("No space to allocate assoc elements buf\n"); + return; + } + + /* Pass to assoclist the size of buf allocated with len */ + if (iw->assoclist(ifname, buf, &len)) + { + printf("No information available\n"); + goto exit; + } + else if (len <= 0) + { + printf("No station connected\n"); + goto exit; + } + for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry)) { e = (struct iwinfo_assoclist_entry *) &buf[i]; @@ -823,6 +841,9 @@ static void print_assoclist(const struct iwinfo_ops *iw, const char *ifname) printf(" expected throughput: %s\n\n", format_rate(e->thr)); } + +exit: + free(buf); } diff --git a/iwinfo_madwifi.c b/iwinfo_madwifi.c index d27e6c9..18b50fa 100644 --- a/iwinfo_madwifi.c +++ b/iwinfo_madwifi.c @@ -772,6 +772,14 @@ static int madwifi_get_assoclist(const char *ifname, char *buf, int *len) do { si = (struct ieee80211req_sta_info *) cp; + /* If buf is NULL, we only count the station */ + if (!buf) + goto next; + + /* stop parsing more elements as we reached max buf */ + if (bl + sizeof(entry) > *len) + break; + memset(&entry, 0, sizeof(entry)); entry.signal = (si->isi_rssi - 95); @@ -797,6 +805,7 @@ static int madwifi_get_assoclist(const char *ifname, char *buf, int *len) memcpy(&buf[bl], &entry, sizeof(struct iwinfo_assoclist_entry)); +next: bl += sizeof(struct iwinfo_assoclist_entry); cp += si->isi_len; tl -= si->isi_len; diff --git a/iwinfo_nl80211.c b/iwinfo_nl80211.c index dc4ff93..09d76fb 100644 --- a/iwinfo_nl80211.c +++ b/iwinfo_nl80211.c @@ -2254,6 +2254,14 @@ static int nl80211_get_assoclist_cb(struct nl_msg *msg, void *arg) [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, }; + /* With NULL buf, we just count the stations */ + if (!arr->buf) + goto exit; + + /* stop parsing more elements as we reached max buf */ + if (arr->count >= arr->max) + return NL_STOP; + /* advance to end of array */ e += arr->count; memset(e, 0, sizeof(*e)); @@ -2369,6 +2377,8 @@ static int nl80211_get_assoclist_cb(struct nl_msg *msg, void *arg) } e->noise = 0; /* filled in by caller */ + +exit: arr->count++; return NL_SKIP; @@ -2397,6 +2407,13 @@ static int nl80211_get_assoclist(const char *ifname, char *buf, int *len) struct nl80211_array_buf arr = { .buf = buf, .count = 0 }; struct iwinfo_assoclist_entry *e; + /* If len is not set, use IWINFO_BUFSIZE by default */ + if (!*len) + *len = IWINFO_BUFSIZE; + + /* Limit element to the preallocated space */ + arr.max = *len / sizeof(*e); + if ((d = opendir("/sys/class/net")) != NULL) { while ((de = readdir(d)) != NULL) @@ -2412,7 +2429,8 @@ static int nl80211_get_assoclist(const char *ifname, char *buf, int *len) closedir(d); - if (!nl80211_get_noise(ifname, &noise)) + /* Skip setting noise if we are just counting station */ + if (arr.buf && !nl80211_get_noise(ifname, &noise)) for (i = 0, e = arr.buf; i < arr.count; i++, e++) e->noise = noise; diff --git a/iwinfo_nl80211.h b/iwinfo_nl80211.h index 2dff08b..fbbf2f7 100644 --- a/iwinfo_nl80211.h +++ b/iwinfo_nl80211.h @@ -67,6 +67,7 @@ struct nl80211_rssi_rate { struct nl80211_array_buf { void *buf; int count; + int max; }; #endif