source: src/router/libutils/mac80211info.c @ 17428

Last change on this file since 17428 was 17428, checked in by chris, 22 months ago

mac80211info getcaps fix memleak

File size: 22.6 KB
Line 
1/*
2 * mac80211info.c
3 * Copyright (C) 2010 Christian Scheele <chris@dd-wrt.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License version 2.1
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 */
14
15#include <sys/types.h>
16#include <sys/socket.h>
17#include <net/if.h>
18#include <unistd.h>
19#include <stdio.h>
20#include <fcntl.h>
21#include <stdbool.h>
22#include <glob.h>
23
24#include "unl.h"
25#include "mac80211regulatory.h"
26#include "linux/nl80211.h"
27
28#include "wlutils.h"
29
30// some defenitions from hostapd
31typedef uint16_t u16;
32#define BIT(x) (1ULL<<(x))
33#define HT_CAP_INFO_LDPC_CODING_CAP     ((u16) BIT(0))
34#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET  ((u16) BIT(1))
35#define HT_CAP_INFO_SMPS_MASK           ((u16) (BIT(2) | BIT(3)))
36#define HT_CAP_INFO_SMPS_STATIC         ((u16) 0)
37#define HT_CAP_INFO_SMPS_DYNAMIC        ((u16) BIT(2))
38#define HT_CAP_INFO_SMPS_DISABLED       ((u16) (BIT(2) | BIT(3)))
39#define HT_CAP_INFO_GREEN_FIELD         ((u16) BIT(4))
40#define HT_CAP_INFO_SHORT_GI20MHZ       ((u16) BIT(5))
41#define HT_CAP_INFO_SHORT_GI40MHZ       ((u16) BIT(6))
42#define HT_CAP_INFO_TX_STBC         ((u16) BIT(7))
43#define HT_CAP_INFO_RX_STBC_MASK        ((u16) (BIT(8) | BIT(9)))
44#define HT_CAP_INFO_RX_STBC_1           ((u16) BIT(8))
45#define HT_CAP_INFO_RX_STBC_12          ((u16) BIT(9))
46#define HT_CAP_INFO_RX_STBC_123         ((u16) (BIT(8) | BIT(9)))
47#define HT_CAP_INFO_DELAYED_BA          ((u16) BIT(10))
48#define HT_CAP_INFO_MAX_AMSDU_SIZE      ((u16) BIT(11))
49#define HT_CAP_INFO_DSSS_CCK40MHZ       ((u16) BIT(12))
50#define HT_CAP_INFO_PSMP_SUPP           ((u16) BIT(13))
51#define HT_CAP_INFO_40MHZ_INTOLERANT        ((u16) BIT(14))
52#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT   ((u16) BIT(15))
53
54static struct unl unl;
55
56static void print_wifi_clients(struct wifi_client_info *wci);
57void free_wifi_clients(struct wifi_client_info *wci);
58static struct wifi_client_info *add_to_wifi_clients(struct wifi_client_info *list_root);
59static int mac80211_cb_survey(struct nl_msg *msg, void *data);
60
61static void __attribute__((constructor)) mac80211_init(void) {
62        static bool bunl;
63        if (!bunl) {
64                unl_genl_init(&unl, "nl80211");
65                bunl=1;
66        }
67}
68
69static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
70        [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
71        [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
72        [NL80211_SURVEY_INFO_CHANNEL_TIME] = { .type = NLA_U64 },
73        [NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY] = { .type = NLA_U64 },
74};
75
76static int parse_survey(struct nl_msg *msg, struct nlattr **sinfo)
77{
78        struct nlattr *tb[NL80211_ATTR_MAX + 1];
79        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
80
81        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
82                  genlmsg_attrlen(gnlh, 0), NULL);
83
84        if (!tb[NL80211_ATTR_SURVEY_INFO])
85                return -1;
86
87        if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
88                             tb[NL80211_ATTR_SURVEY_INFO],
89                             survey_policy))
90                return -1;
91
92        if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
93                return -1;
94
95        return 0;
96}
97
98
99static int mac80211_cb_survey(struct nl_msg *msg, void *data)
100{
101        struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
102        int freq;
103        struct mac80211_info *mac80211_info = data;
104
105        if (parse_survey(msg, sinfo))
106                goto out;
107
108        freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
109        if (sinfo[NL80211_SURVEY_INFO_IN_USE])
110                {
111
112                if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME] &&
113                        sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
114
115                        mac80211_info->channel_active_time = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
116                        mac80211_info->channel_busy_time = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
117
118                }
119
120                if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
121                        mac80211_info->noise = nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
122                }
123        }
124
125out:
126        return NL_SKIP;
127}
128
129static void getNoise_mac80211_internal(char *interface,struct mac80211_info *mac80211_info) {
130        struct nl_msg *msg;
131        int wdev = if_nametoindex(interface);
132
133        msg = unl_genl_msg(&unl, NL80211_CMD_GET_SURVEY, true);
134        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev);
135        unl_genl_request(&unl, msg, mac80211_cb_survey, mac80211_info);
136        return;
137
138nla_put_failure:
139        nlmsg_free(msg);
140        return;
141}
142
143
144int getNoise_mac80211(char *interface)
145{
146        struct nl_msg *msg;
147        struct mac80211_info mac80211_info;
148        int wdev = if_nametoindex(interface);
149        memset(&mac80211_info, 0, sizeof(mac80211_info));
150
151        msg = unl_genl_msg(&unl, NL80211_CMD_GET_SURVEY, true);
152        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev);
153        unl_genl_request(&unl, msg, mac80211_cb_survey, &mac80211_info);
154        return mac80211_info.noise;
155
156nla_put_failure:
157        nlmsg_free(msg);
158        return(-199);
159}
160
161int mac80211_get_coverageclass(char *interface) {
162        struct nlattr *tb[NL80211_ATTR_MAX + 1];
163        struct nl_msg *msg;
164        struct genlmsghdr *gnlh;
165        int wdev,phy;
166        unsigned char coverage=0;
167
168        wdev = if_nametoindex(interface);
169        phy = unl_nl80211_wdev_to_phy(&unl, wdev);
170
171        msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, true);
172        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
173        if (unl_genl_request_single(&unl, msg, &msg) < 0)
174                return 0;
175        gnlh=nlmsg_data(nlmsg_hdr(msg));
176        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
177                  genlmsg_attrlen(gnlh, 0), NULL);
178        if (tb[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
179                coverage = nla_get_u8(tb[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
180                /* See handle_distance() for an explanation where the '450' comes from */
181                // printf("\tCoverage class: %d (up to %dm)\n", coverage, 450 * coverage);
182        }
183        // printf ("%d\n", coverage);
184        nlmsg_free(msg);
185        return coverage;
186nla_put_failure:
187        nlmsg_free(msg);
188        return 0;
189}
190
191static int mac80211_cb_stations(struct nl_msg *msg,void *data) {
192        // struct nlattr *tb[NL80211_BAND_ATTR_MAX + 1];
193        struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
194        struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
195        struct nlattr *tb[NL80211_ATTR_MAX + 1];
196        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
197        char mac_addr[20], dev[20];
198        struct mac80211_info *mac80211_info = data;
199        mac80211_info->wci = add_to_wifi_clients(mac80211_info->wci);
200        // struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
201    static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
202        [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
203        [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
204        [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
205        [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
206        [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
207        [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
208        [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
209        [NL80211_STA_INFO_RX_BITRATE] = { .type = NLA_NESTED },
210        [NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
211        [NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
212        [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
213        [NL80211_STA_INFO_CONNECTED_TIME] = { .type = NLA_U32 },
214    };
215
216    static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
217        [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
218        [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
219        [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
220        [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
221    };
222        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
223                  genlmsg_attrlen(gnlh, 0), NULL);
224        if (!tb[NL80211_ATTR_STA_INFO]) {
225                fprintf(stderr, "sta stats missing!\n");
226                return NL_SKIP;
227        }
228        if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
229                             tb[NL80211_ATTR_STA_INFO],
230                             stats_policy)) {
231                fprintf(stderr, "failed to parse nested attributes!\n");
232                return NL_SKIP;
233        }
234        ether_etoa(nla_data(tb[NL80211_ATTR_MAC]),mac_addr);
235        if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
236        printf("Station %s (on %s)", mac_addr, dev);
237        strcpy(mac80211_info->wci->mac, mac_addr);
238        strcpy(mac80211_info->wci->ifname, dev);
239        mac80211_info->wci->noise=mac80211_info->noise;
240
241        if (sinfo[NL80211_STA_INFO_INACTIVE_TIME]) {
242                mac80211_info->wci->inactive_time=nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]);
243                printf("\n\tinactive time:\t%u ms",
244                        nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]));
245        }
246        if (sinfo[NL80211_STA_INFO_RX_BYTES]) {
247                mac80211_info->wci->rx_bytes=nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]);
248                printf("\n\trx bytes:\t%u",
249                        nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]));
250        }
251        if (sinfo[NL80211_STA_INFO_RX_PACKETS]) {
252                mac80211_info->wci->rx_packets=nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS]);
253                printf("\n\trx packets:\t%u",
254                        nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS]));
255        }
256        if (sinfo[NL80211_STA_INFO_TX_BYTES]) {
257                mac80211_info->wci->tx_bytes=nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES]);
258                printf("\n\ttx bytes:\t%u",
259                        nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES]));
260        }
261        if (sinfo[NL80211_STA_INFO_TX_PACKETS]) {
262                mac80211_info->wci->tx_packets=nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS]);
263                printf("\n\ttx packets:\t%u",
264                        nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS]));
265        }
266        if (sinfo[NL80211_STA_INFO_SIGNAL]) {
267                mac80211_info->wci->signal=(int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
268                printf("\n\tsignal:  \t%d dBm",
269                        (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]));
270                }
271
272        if (sinfo[NL80211_STA_INFO_CONNECTED_TIME]) {
273                mac80211_info->wci->uptime=nla_get_u32(sinfo[NL80211_STA_INFO_CONNECTED_TIME]);
274                printf("\n\tuptime:\t%u",
275                        nla_get_u32(sinfo[NL80211_STA_INFO_CONNECTED_TIME]));
276        }
277
278        if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
279                if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
280                                     sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy)) {
281                        fprintf(stderr, "failed to parse nested rate attributes!\n");
282                } else {
283                        printf("\n\ttx bitrate:\t");
284                        if (rinfo[NL80211_RATE_INFO_BITRATE]) {
285                                mac80211_info->wci->txrate =nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
286                        }
287
288                        if (rinfo[NL80211_RATE_INFO_MCS]) {
289                                mac80211_info->wci->mcs=nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]);
290                                }
291                        if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH]) {
292                                mac80211_info->wci->is_40mhz=1;
293                                }
294                        if (rinfo[NL80211_RATE_INFO_SHORT_GI]) {
295                                mac80211_info->wci->is_short_gi=1;
296                                }
297                }
298        }
299        if (sinfo[NL80211_STA_INFO_RX_BITRATE]) {
300                if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
301                                     sinfo[NL80211_STA_INFO_RX_BITRATE], rate_policy)) {
302                        fprintf(stderr, "failed to parse nested rate attributes!\n");
303                } else {
304                        printf("\n\trx bitrate:\t");
305                        if (rinfo[NL80211_RATE_INFO_BITRATE]) {
306                                mac80211_info->wci->rxrate =nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
307                        }
308
309                        if (rinfo[NL80211_RATE_INFO_MCS]) {
310                                mac80211_info->wci->rx_mcs=nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]);
311                                }
312                        if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH]) {
313                                mac80211_info->wci->rx_is_40mhz=1;
314                                }
315                        if (rinfo[NL80211_RATE_INFO_SHORT_GI]) {
316                                mac80211_info->wci->rx_is_short_gi=1;
317                                printf(" short GI");
318                                }
319                }
320        }
321return(0);
322}
323
324struct mac80211_info *mac80211_assoclist(char *interface) {
325        struct nl_msg *msg;
326        glob_t globbuf;
327        char globstring[1024];
328        int globresult;
329        struct mac80211_info *mac80211_info = calloc(1, sizeof(struct mac80211_info));
330
331        if (interface)
332                sprintf(globstring, "/sys/class/ieee80211/phy*/device/net/%s*",
333                        interface);
334        else
335                sprintf(globstring, "/sys/class/ieee80211/phy*/device/net/*");
336        globresult = glob(globstring, GLOB_NOSORT, NULL, &globbuf);
337        int i;
338        for (i = 0; i < globbuf.gl_pathc; i++) {
339                char *ifname;
340                ifname = strrchr(globbuf.gl_pathv[i], '/');
341                if (!ifname)
342                        continue;
343                // get noise for the actaul interface
344                getNoise_mac80211_internal(ifname + 1,mac80211_info);
345                msg = unl_genl_msg(&unl, NL80211_CMD_GET_STATION,true);
346                NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(ifname + 1));
347                unl_genl_request(&unl, msg, mac80211_cb_stations,mac80211_info);
348        }
349        // print_wifi_clients(mac80211_info->wci);
350        // free_wifi_clients(mac80211_info->wci);
351        globfree(&globbuf);
352
353
354        return(mac80211_info);
355nla_put_failure:
356        nlmsg_free(msg);
357        return(mac80211_info);
358}
359
360char *mac80211_get_caps(char *interface) {
361        struct nl_msg *msg;
362        struct nlattr *caps, *bands, *band;
363        int rem;
364        u16 cap;
365        char *capstring=NULL;
366        int wdev,phy;
367        wdev = if_nametoindex(interface);
368        phy = unl_nl80211_wdev_to_phy(&unl, wdev);
369
370
371        msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, false);
372        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
373        if (unl_genl_request_single(&unl, msg, &msg) < 0)
374                return "";
375        bands = unl_find_attr(&unl, msg, NL80211_ATTR_WIPHY_BANDS);
376        if (!bands)
377                goto out;
378
379        nla_for_each_nested(band, bands, rem) {
380                caps = nla_find(nla_data(band), nla_len(band), NL80211_BAND_ATTR_HT_CAPA);
381                if (!caps) continue;
382                cap = nla_get_u16(caps);
383                asprintf(&capstring,"%s%s%s%s%s%s%s%s"
384                        ,(cap & HT_CAP_INFO_LDPC_CODING_CAP ? "[LDPC]" : "")
385                        ,(cap & HT_CAP_INFO_SHORT_GI20MHZ ? "[SHORT-GI-20]" : "")
386                        ,(cap & HT_CAP_INFO_SHORT_GI40MHZ ? "[SHORT-GI-40]" : "")
387                        ,(cap & HT_CAP_INFO_TX_STBC ? "[TX-STBC]" : "")
388                        ,(((cap >> 8) & 0x3) == 1 ? "[RX-STBC1]" : "")
389                        ,(((cap >> 8) & 0x3) == 2 ? "[RX-STBC12]" : "")
390                        ,(((cap >> 8) & 0x3) == 3 ? "[RX-STBC123]" : "")
391                        ,(cap & HT_CAP_INFO_DSSS_CCK40MHZ ? "[DSSS_CCK-40]" : "")
392                        );
393        }
394out:
395nla_put_failure:
396        nlmsg_free(msg);
397        if (!capstring)
398                return strdup("");
399        return capstring;
400        }
401
402static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
403        [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
404};
405
406int mac80211_check_band(char *interface,int checkband) {
407        struct nlattr *tb[NL80211_BAND_ATTR_MAX + 1];
408        struct nl_msg *msg;
409        struct nlattr *bands, *band,*freqlist,*freq;
410        int rem, rem2, freq_mhz;
411        int wdev,phy;
412        int bandfound=0;
413        wdev = if_nametoindex(interface);
414        phy = unl_nl80211_wdev_to_phy(&unl, wdev);
415
416
417        msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, false);
418        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
419        if (unl_genl_request_single(&unl, msg, &msg) < 0)
420                return 0;
421        bands = unl_find_attr(&unl, msg, NL80211_ATTR_WIPHY_BANDS);
422        if (!bands)
423                goto out;
424
425        nla_for_each_nested(band, bands, rem) {
426                freqlist = nla_find(nla_data(band), nla_len(band),
427                                    NL80211_BAND_ATTR_FREQS);
428                if (!freqlist)
429                        continue;
430                nla_for_each_nested(freq, freqlist, rem2) {
431                        nla_parse_nested(tb, NL80211_FREQUENCY_ATTR_MAX,
432                                         freq, freq_policy);
433                        if (!tb[NL80211_FREQUENCY_ATTR_FREQ])
434                                continue;
435
436                        if (tb[NL80211_FREQUENCY_ATTR_DISABLED])
437                                continue;
438
439                        freq_mhz = nla_get_u32(tb[NL80211_FREQUENCY_ATTR_FREQ]);
440                        if ((int) (freq_mhz / 1000) == checkband)
441                                bandfound=1;
442                }
443        }
444        nlmsg_free(msg);
445        return bandfound;
446out:
447nla_put_failure:
448        nlmsg_free(msg);
449        return 0;
450}
451
452struct wifi_channels *mac80211_get_channels(char *interface,char *country,int max_bandwidth_khz, unsigned char checkband) {
453        struct nlattr *tb[NL80211_BAND_ATTR_MAX + 1];
454        struct nl_msg *msg;
455        struct nlattr *bands, *band,*freqlist,*freq;
456        struct ieee80211_regdomain *rd;
457        struct ieee80211_freq_range regfreq;
458        struct ieee80211_power_rule regpower;
459        struct wifi_channels *list = NULL;
460        int rem, rem2, freq_mhz,wdev,phy,rrc,startfreq,stopfreq,range,regmaxbw,run;
461        int regfound=0;
462        int htrange=30;
463        int chancount=0;
464        int count=0;
465
466        wdev = if_nametoindex(interface);
467        phy = unl_nl80211_wdev_to_phy(&unl, wdev);
468
469        rd=mac80211_get_regdomain(country);
470
471        msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, false);
472        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
473        if (unl_genl_request_single(&unl, msg, &msg) < 0)
474                return NULL;
475        bands = unl_find_attr(&unl, msg, NL80211_ATTR_WIPHY_BANDS);
476        if (!bands)
477                goto out;
478
479        for (run=0;run <2;run++) {
480                if (run == 1) {
481                        list = (struct wifi_channels *)malloc(sizeof(struct wifi_channels) * (chancount+1));
482                        (void)memset(list, 0, (sizeof(struct wifi_channels)*(chancount+1)));
483                }
484                nla_for_each_nested(band, bands, rem) {
485                        freqlist = nla_find(nla_data(band), nla_len(band),
486                                            NL80211_BAND_ATTR_FREQS);
487                        if (!freqlist)
488                                continue;
489                        nla_for_each_nested(freq, freqlist, rem2) {
490                                nla_parse_nested(tb, NL80211_FREQUENCY_ATTR_MAX,
491                                                 freq, freq_policy);
492                                if (!tb[NL80211_FREQUENCY_ATTR_FREQ])
493                                        continue;
494
495                                if (tb[NL80211_FREQUENCY_ATTR_DISABLED])
496                                        continue;
497                                regfound=0;
498                                if (max_bandwidth_khz == 40)
499                                                range=10;
500                                else
501                                        // for 10/5mhz this should be fine
502                                        range=max_bandwidth_khz/2;
503                                freq_mhz = (int) nla_get_u32(tb[NL80211_FREQUENCY_ATTR_FREQ]);
504                                for (rrc = 0; rrc < rd->n_reg_rules; rrc++) {
505                                        regfreq  = rd->reg_rules[rrc].freq_range;
506                                        startfreq=(int)((float)(regfreq.start_freq_khz)/1000.0);
507                                        stopfreq=(int)((float)(regfreq.end_freq_khz)/1000.0);
508                                        regmaxbw=(int)((float)(regfreq.max_bandwidth_khz)/1000.0);
509                                        if ((freq_mhz - range) >= startfreq && (freq_mhz + range) <= stopfreq) {
510                                                if (run == 1) {
511                                                        regpower = rd->reg_rules[rrc].power_rule;
512                                                        list[count].channel = ieee80211_mhz2ieee(freq_mhz);
513                                                        list[count].freq = freq_mhz;
514                                                        // todo: wenn wir das ueberhaupt noch verwenden
515                                                        list[count].noise = 0;
516                                                        list[count].max_eirp = (int)((float)(regpower.max_eirp)/100.0);
517                                                        if (rd->reg_rules[rrc].flags & RRF_NO_OFDM)
518                                                                list[count].no_ofdm = 1;
519                                                        if (rd->reg_rules[rrc].flags & RRF_NO_CCK)
520                                                                list[count].no_cck = 1;
521                                                        if (rd->reg_rules[rrc].flags & RRF_NO_INDOOR)
522                                                                list[count].no_indoor = 1;
523                                                        if (rd->reg_rules[rrc].flags & RRF_NO_OUTDOOR)
524                                                                list[count].no_outdoor = 1;
525                                                        if (rd->reg_rules[rrc].flags & RRF_DFS)
526                                                                list[count].dfs = 1;
527                                                        if (rd->reg_rules[rrc].flags & RRF_PTP_ONLY)
528                                                                list[count].ptp_only = 1;
529                                                        if (rd->reg_rules[rrc].flags & RRF_PTMP_ONLY)
530                                                                list[count].ptmp_only = 1;
531                                                        if (rd->reg_rules[rrc].flags & RRF_PASSIVE_SCAN)
532                                                                list[count].passive_scan = 1;
533                                                        if (rd->reg_rules[rrc].flags & RRF_NO_IBSS)
534                                                                list[count].no_ibss = 1;
535                                                        if (max_bandwidth_khz == 40) {
536                                                                if ((freq_mhz - htrange) >= startfreq ) {
537                                                                        list[count].ht40minus = 1;
538                                                                }
539                                                                if ((freq_mhz + htrange) <= stopfreq) {
540                                                                        list[count].ht40plus = 1;
541                                                                }
542                                                        }
543                                                        count++;
544                                                }
545                                                if (run == 0) chancount++;
546                                        }
547                                }
548                        }
549                }
550        }
551        list[count].freq=-1;
552        if (rd)
553                free(rd);
554        nlmsg_free(msg);
555        return list;
556out:
557nla_put_failure:
558        nlmsg_free(msg);
559        return NULL;
560}
561
562static struct wifi_client_info *add_to_wifi_clients(struct wifi_client_info *list_root){
563                struct wifi_client_info *new = calloc(1, sizeof(struct wifi_client_info));
564                if (new == NULL) {
565                        fprintf(stderr, "add_wifi_clients: Out of memory!\n");
566                        return(NULL);
567                        }
568                else
569                        {
570                         new->next =  list_root;
571                         return(new);
572                        }
573                }
574
575void free_wifi_clients(struct wifi_client_info *wci) {
576        while (wci) {
577                struct wifi_client_info *next = wci->next;
578                free(wci);
579                wci = next;
580                }
581        }
582
583static int get_max_mcs_index(const __u8 *mcs)
584{
585        unsigned int mcs_bit, prev_bit = -2, prev_cont = 0;
586
587        for (mcs_bit = 0; mcs_bit <= 76; mcs_bit++) {
588                unsigned int mcs_octet = mcs_bit/8;
589                unsigned int MCS_RATE_BIT = 1 << mcs_bit % 8;
590                bool mcs_rate_idx_set;
591
592                mcs_rate_idx_set = !!(mcs[mcs_octet] & MCS_RATE_BIT);
593
594                if (!mcs_rate_idx_set)
595                        continue;
596
597                if (prev_bit != mcs_bit - 1) {
598                        /* if (prev_bit != -2)
599                                printf("%d, ", prev_bit);
600                        else
601                                printf(" ");
602                        printf("%d", mcs_bit); */
603                        prev_cont = 0;
604                } else if (!prev_cont) {
605                        // printf("-");
606                        prev_cont = 1;
607                }
608
609                prev_bit = mcs_bit;
610        }
611
612        if (prev_cont)
613                // printf("%d", prev_bit);
614                return prev_bit;
615        // printf("\n");
616        return 0;
617}
618
619static int get_ht_mcs(const __u8 *mcs)
620{
621        /* As defined in 7.3.2.57.4 Supported MCS Set field */
622        unsigned int tx_max_num_spatial_streams, max_rx_supp_data_rate;
623        bool tx_mcs_set_defined, tx_mcs_set_equal, tx_unequal_modulation;
624
625        max_rx_supp_data_rate = ((mcs[10] >> 8) & ((mcs[11] & 0x3) << 8));
626        tx_mcs_set_defined = !!(mcs[12] & (1 << 0));
627        tx_mcs_set_equal = !(mcs[12] & (1 << 1));
628        tx_max_num_spatial_streams = ((mcs[12] >> 2) & 3) + 1;
629        tx_unequal_modulation = !!(mcs[12] & (1 << 4));
630
631        // if (max_rx_supp_data_rate)
632        //      printf("\t\tHT Max RX data rate: %d Mbps\n", max_rx_supp_data_rate);
633        /* XXX: else see 9.6.0e.5.3 how to get this I think */
634
635        if (tx_mcs_set_defined) {
636                if (tx_mcs_set_equal) {
637                        // printf("\t\tHT TX/RX MCS rate indexes supported:");
638                        return(get_max_mcs_index(mcs));
639                } else {
640                        // printf("\t\tHT RX MCS rate indexes supported:");
641                        return(get_max_mcs_index(mcs));
642
643                        // if (tx_unequal_modulation)
644                                // printf("\t\tTX unequal modulation supported\n");
645                        // else
646                                // printf("\t\tTX unequal modulation not supported\n");
647
648                        // printf("\t\tHT TX Max spatial streams: %d\n",
649                        //      tx_max_num_spatial_streams);
650
651                        // printf("\t\tHT TX MCS rate indexes supported may differ\n");
652                }
653        } else {
654                // printf("\t\tHT RX MCS rate indexes supported:");
655                return(get_max_mcs_index(mcs));
656                // printf("\t\tHT TX MCS rate indexes are undefined\n");
657        }
658}
659
660int mac80211_get_maxrate(char *interface) {
661        struct nlattr *tb[NL80211_BAND_ATTR_MAX + 1];
662        struct nl_msg *msg;
663        struct nlattr *bands, *band,*ratelist,*rate;
664        int rem, rem2;
665        int wdev,phy;
666        int maxrate=0;
667        static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
668                [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
669                [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG },
670        };
671        wdev = if_nametoindex(interface);
672        phy = unl_nl80211_wdev_to_phy(&unl, wdev);
673
674
675        msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, false);
676        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
677        if (unl_genl_request_single(&unl, msg, &msg) < 0)
678                return 0;
679        bands = unl_find_attr(&unl, msg, NL80211_ATTR_WIPHY_BANDS);
680        if (!bands)
681                goto out;
682
683        nla_for_each_nested(band, bands, rem) {
684                ratelist = nla_find(nla_data(band), nla_len(band),
685                                    NL80211_BAND_ATTR_RATES);
686                if (!ratelist)
687                        continue;
688                nla_for_each_nested(rate, ratelist, rem2) {
689                        nla_parse_nested(tb, NL80211_BITRATE_ATTR_MAX,
690                                         rate, rate_policy);
691                        if (!tb[NL80211_BITRATE_ATTR_RATE])
692                                continue;
693                        maxrate=0.1 * nla_get_u32(tb[NL80211_BITRATE_ATTR_RATE]);
694                }
695        }
696        printf("maxrate: %d\n",maxrate);
697        nlmsg_free(msg);
698        return maxrate;
699out:
700nla_put_failure:
701        nlmsg_free(msg);
702        return 0;
703}
704
705int mac80211_get_maxmcs(char *interface) {
706        struct nlattr *tb[NL80211_BAND_ATTR_MAX + 1];
707        struct nl_msg *msg;
708        struct nlattr *bands, *band;
709        int rem;
710        int wdev,phy;
711        int maxmcs=0;
712
713        wdev = if_nametoindex(interface);
714        phy = unl_nl80211_wdev_to_phy(&unl, wdev);
715
716        msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, false);
717        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
718        if (unl_genl_request_single(&unl, msg, &msg) < 0)
719                return 0;
720        bands = unl_find_attr(&unl, msg, NL80211_ATTR_WIPHY_BANDS);
721        if (!bands)
722                goto out;
723
724        nla_for_each_nested(band, bands, rem) {
725        nla_parse(tb, NL80211_BAND_ATTR_MAX, nla_data(band),
726                  nla_len(band), NULL);
727        if (tb[NL80211_BAND_ATTR_HT_MCS_SET] &&
728                nla_len(tb[NL80211_BAND_ATTR_HT_MCS_SET]) == 16)
729                maxmcs=get_ht_mcs(nla_data(tb[NL80211_BAND_ATTR_HT_MCS_SET]));
730        }
731        printf("maxmcs: %d\n",maxmcs);
732        nlmsg_free(msg);
733        return maxmcs;
734out:
735        return 0;
736nla_put_failure:
737        nlmsg_free(msg);
738        return 0;
739}
Note: See TracBrowser for help on using the repository browser.