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

Last change on this file since 18915 was 18915, checked in by BrainSlayer, 14 months ago

disallow ht40 selection if country or regulatory setting does not support these modes

File size: 28.0 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 int phy_lookup_by_number(int idx)
70{
71        char buf[200];
72        int fd, pos;
73
74        snprintf(buf, sizeof(buf), "/sys/class/ieee80211/phy%d/index", idx);
75
76        fd = open(buf, O_RDONLY);
77        if (fd < 0)
78                return -1;
79        pos = read(fd, buf, sizeof(buf) - 1);
80        if (pos < 0) {
81                close(fd);
82                return -1;
83        }
84        buf[pos] = '\0';
85        close(fd);
86        return atoi(buf);
87}
88
89int mac80211_get_phyidx_by_vifname(char *vif) {
90        int phynum=0;
91    if (!sscanf(vif, "ath%d", &phynum)) {
92                return -1;
93                }
94        return(phy_lookup_by_number(get_ath9k_phy_idx(phynum)));
95        }
96
97static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
98        [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
99        [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
100        [NL80211_SURVEY_INFO_CHANNEL_TIME] = { .type = NLA_U64 },
101        [NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY] = { .type = NLA_U64 },
102};
103
104static int parse_survey(struct nl_msg *msg, struct nlattr **sinfo)
105{
106        struct nlattr *tb[NL80211_ATTR_MAX + 1];
107        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
108
109        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
110                  genlmsg_attrlen(gnlh, 0), NULL);
111
112        if (!tb[NL80211_ATTR_SURVEY_INFO])
113                return -1;
114
115        if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
116                             tb[NL80211_ATTR_SURVEY_INFO],
117                             survey_policy))
118                return -1;
119
120        if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
121                return -1;
122
123        return 0;
124}
125
126
127static int mac80211_cb_survey(struct nl_msg *msg, void *data)
128{
129        struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
130        int freq;
131        struct mac80211_info *mac80211_info = data;
132
133        if (parse_survey(msg, sinfo))
134                goto out;
135
136        freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
137        if (sinfo[NL80211_SURVEY_INFO_IN_USE])
138                {
139
140                if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME] &&
141                        sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
142
143                        mac80211_info->channel_active_time = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
144                        mac80211_info->channel_busy_time = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
145
146                }
147
148                if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX])
149                        mac80211_info->channel_receive_time = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
150
151                if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX])
152                        mac80211_info->channel_transmit_time = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
153
154                if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY])
155                        mac80211_info->extension_channel_busy_time = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY]);
156
157                if (sinfo[NL80211_SURVEY_INFO_NOISE])
158                        mac80211_info->noise = nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
159
160                if (sinfo[NL80211_SURVEY_INFO_FREQUENCY])
161                        mac80211_info->frequency = freq;
162        }
163
164out:
165        return NL_SKIP;
166}
167
168static void getNoise_mac80211_internal(char *interface,struct mac80211_info *mac80211_info) {
169        struct nl_msg *msg;
170        int wdev = if_nametoindex(interface);
171
172        msg = unl_genl_msg(&unl, NL80211_CMD_GET_SURVEY, true);
173        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev);
174        unl_genl_request(&unl, msg, mac80211_cb_survey, mac80211_info);
175        return;
176
177nla_put_failure:
178        nlmsg_free(msg);
179        return;
180}
181
182
183int getNoise_mac80211(char *interface)
184{
185        struct nl_msg *msg;
186        struct mac80211_info mac80211_info;
187        int wdev = if_nametoindex(interface);
188        memset(&mac80211_info, 0, sizeof(mac80211_info));
189
190        msg = unl_genl_msg(&unl, NL80211_CMD_GET_SURVEY, true);
191        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev);
192        unl_genl_request(&unl, msg, mac80211_cb_survey, &mac80211_info);
193        return mac80211_info.noise;
194
195nla_put_failure:
196        nlmsg_free(msg);
197        return(-199);
198}
199
200int getFrequency_mac80211(char *interface)
201{
202        struct nl_msg *msg;
203        struct mac80211_info mac80211_info;
204        int wdev = if_nametoindex(interface);
205        memset(&mac80211_info, 0, sizeof(mac80211_info));
206
207        msg = unl_genl_msg(&unl, NL80211_CMD_GET_SURVEY, true);
208        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev);
209        unl_genl_request(&unl, msg, mac80211_cb_survey, &mac80211_info);
210        return mac80211_info.frequency;
211
212nla_put_failure:
213        nlmsg_free(msg);
214        return(0);
215}
216
217int mac80211_get_coverageclass(char *interface) {
218        struct nlattr *tb[NL80211_ATTR_MAX + 1];
219        struct nl_msg *msg;
220        struct genlmsghdr *gnlh;
221        int phy;
222        unsigned char coverage=0;
223
224        phy = mac80211_get_phyidx_by_vifname(interface);
225        if (phy == -1) return 0;
226
227        msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, true);
228        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
229        if (unl_genl_request_single(&unl, msg, &msg) < 0)
230                return 0;
231        if (!msg) return 0;
232        gnlh=nlmsg_data(nlmsg_hdr(msg));
233        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
234                  genlmsg_attrlen(gnlh, 0), NULL);
235        if (tb[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
236                coverage = nla_get_u8(tb[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
237                /* See handle_distance() for an explanation where the '450' comes from */
238                // printf("\tCoverage class: %d (up to %dm)\n", coverage, 450 * coverage);
239        }
240        // printf ("%d\n", coverage);
241        nlmsg_free(msg);
242        return coverage;
243nla_put_failure:
244        nlmsg_free(msg);
245        return 0;
246}
247
248static int mac80211_cb_stations(struct nl_msg *msg,void *data) {
249        // struct nlattr *tb[NL80211_BAND_ATTR_MAX + 1];
250        struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
251        struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
252        struct nlattr *tb[NL80211_ATTR_MAX + 1];
253        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
254        char mac_addr[20], dev[20];
255        struct mac80211_info *mac80211_info = data;
256        mac80211_info->wci = add_to_wifi_clients(mac80211_info->wci);
257        // struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
258    static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
259        [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
260        [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
261        [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
262        [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
263        [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
264        [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
265        [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
266        [NL80211_STA_INFO_RX_BITRATE] = { .type = NLA_NESTED },
267        [NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
268        [NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
269        [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
270        [NL80211_STA_INFO_CONNECTED_TIME] = { .type = NLA_U32 },
271    };
272
273    static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
274        [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
275        [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
276        [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
277        [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
278    };
279        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
280                  genlmsg_attrlen(gnlh, 0), NULL);
281        if (!tb[NL80211_ATTR_STA_INFO]) {
282                fprintf(stderr, "sta stats missing!\n");
283                return NL_SKIP;
284        }
285        if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
286                             tb[NL80211_ATTR_STA_INFO],
287                             stats_policy)) {
288                fprintf(stderr, "failed to parse nested attributes!\n");
289                return NL_SKIP;
290        }
291        ether_etoa(nla_data(tb[NL80211_ATTR_MAC]),mac_addr);
292        if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
293        printf("Station %s (on %s)", mac_addr, dev);
294        strcpy(mac80211_info->wci->mac, mac_addr);
295        strcpy(mac80211_info->wci->ifname, dev);
296        mac80211_info->wci->noise=mac80211_info->noise;
297
298        if (strstr(dev, ".sta"))
299                mac80211_info->wci->is_wds=1;
300
301        if (sinfo[NL80211_STA_INFO_INACTIVE_TIME]) {
302                mac80211_info->wci->inactive_time=nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]);
303                printf("\n\tinactive time:\t%u ms",
304                        nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]));
305        }
306        if (sinfo[NL80211_STA_INFO_RX_BYTES]) {
307                mac80211_info->wci->rx_bytes=nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]);
308                printf("\n\trx bytes:\t%u",
309                        nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]));
310        }
311        if (sinfo[NL80211_STA_INFO_RX_PACKETS]) {
312                mac80211_info->wci->rx_packets=nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS]);
313                printf("\n\trx packets:\t%u",
314                        nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS]));
315        }
316        if (sinfo[NL80211_STA_INFO_TX_BYTES]) {
317                mac80211_info->wci->tx_bytes=nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES]);
318                printf("\n\ttx bytes:\t%u",
319                        nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES]));
320        }
321        if (sinfo[NL80211_STA_INFO_TX_PACKETS]) {
322                mac80211_info->wci->tx_packets=nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS]);
323                printf("\n\ttx packets:\t%u",
324                        nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS]));
325        }
326        if (sinfo[NL80211_STA_INFO_SIGNAL]) {
327                mac80211_info->wci->signal=(int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
328                printf("\n\tsignal:  \t%d dBm",
329                        (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]));
330                }
331
332        if (sinfo[NL80211_STA_INFO_CONNECTED_TIME]) {
333                mac80211_info->wci->uptime=nla_get_u32(sinfo[NL80211_STA_INFO_CONNECTED_TIME]);
334                printf("\n\tuptime:\t%u",
335                        nla_get_u32(sinfo[NL80211_STA_INFO_CONNECTED_TIME]));
336        }
337
338        if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
339                if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
340                                     sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy)) {
341                        fprintf(stderr, "failed to parse nested rate attributes!\n");
342                } else {
343                        printf("\n\ttx bitrate:\t");
344                        if (rinfo[NL80211_RATE_INFO_BITRATE]) {
345                                mac80211_info->wci->txrate =nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
346                        }
347
348                        if (rinfo[NL80211_RATE_INFO_MCS]) {
349                                mac80211_info->wci->mcs=nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]);
350                                }
351                        if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH]) {
352                                mac80211_info->wci->is_40mhz=1;
353                                }
354                        if (rinfo[NL80211_RATE_INFO_SHORT_GI]) {
355                                mac80211_info->wci->is_short_gi=1;
356                                }
357                }
358        }
359        if (sinfo[NL80211_STA_INFO_RX_BITRATE]) {
360                if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
361                                     sinfo[NL80211_STA_INFO_RX_BITRATE], rate_policy)) {
362                        fprintf(stderr, "failed to parse nested rate attributes!\n");
363                } else {
364                        printf("\n\trx bitrate:\t");
365                        if (rinfo[NL80211_RATE_INFO_BITRATE]) {
366                                mac80211_info->wci->rxrate =nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
367                        }
368
369                        if (rinfo[NL80211_RATE_INFO_MCS]) {
370                                mac80211_info->wci->rx_mcs=nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]);
371                                }
372                        if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH]) {
373                                mac80211_info->wci->rx_is_40mhz=1;
374                                }
375                        if (rinfo[NL80211_RATE_INFO_SHORT_GI]) {
376                                mac80211_info->wci->rx_is_short_gi=1;
377                                printf(" short GI");
378                                }
379                }
380        }
381return(0);
382}
383
384struct mac80211_info *mac80211_assoclist(char *interface) {
385        struct nl_msg *msg;
386        glob_t globbuf;
387        char globstring[1024];
388        int globresult;
389        struct mac80211_info *mac80211_info = calloc(1, sizeof(struct mac80211_info));
390
391        if (interface)
392                sprintf(globstring, "/sys/class/ieee80211/phy*/device/net/%s*",
393                        interface);
394        else
395                sprintf(globstring, "/sys/class/ieee80211/phy*/device/net/*");
396        globresult = glob(globstring, GLOB_NOSORT, NULL, &globbuf);
397        int i;
398        for (i = 0; i < globbuf.gl_pathc; i++) {
399                char *ifname;
400                ifname = strrchr(globbuf.gl_pathv[i], '/');
401                if (!ifname)
402                        continue;
403                // get noise for the actaul interface
404                getNoise_mac80211_internal(ifname + 1,mac80211_info);
405                msg = unl_genl_msg(&unl, NL80211_CMD_GET_STATION,true);
406                NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(ifname + 1));
407                unl_genl_request(&unl, msg, mac80211_cb_stations,mac80211_info);
408        }
409        // print_wifi_clients(mac80211_info->wci);
410        // free_wifi_clients(mac80211_info->wci);
411        globfree(&globbuf);
412
413
414        return(mac80211_info);
415nla_put_failure:
416        nlmsg_free(msg);
417        return(mac80211_info);
418}
419
420char *mac80211_get_caps(char *interface) {
421        struct nl_msg *msg;
422        struct nlattr *caps, *bands, *band;
423        int rem;
424        u16 cap;
425        char *capstring=NULL;
426        int phy;
427        phy = mac80211_get_phyidx_by_vifname(interface);
428        if (phy == -1) {
429                return strdup("");
430        }
431        msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, false);
432        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
433        if (unl_genl_request_single(&unl, msg, &msg) < 0)
434                return "";
435        bands = unl_find_attr(&unl, msg, NL80211_ATTR_WIPHY_BANDS);
436        if (!bands)
437                goto out;
438
439        nla_for_each_nested(band, bands, rem) {
440                caps = nla_find(nla_data(band), nla_len(band), NL80211_BAND_ATTR_HT_CAPA);
441                if (!caps) continue;
442                cap = nla_get_u16(caps);
443                asprintf(&capstring,"%s%s%s%s%s%s%s%s"
444                        ,(cap & HT_CAP_INFO_LDPC_CODING_CAP ? "[LDPC]" : "")
445                        ,(cap & HT_CAP_INFO_SHORT_GI20MHZ ? "[SHORT-GI-20]" : "")
446                        ,(cap & HT_CAP_INFO_SHORT_GI40MHZ ? "[SHORT-GI-40]" : "")
447                        ,(cap & HT_CAP_INFO_TX_STBC ? "[TX-STBC]" : "")
448                        ,(((cap >> 8) & 0x3) == 1 ? "[RX-STBC1]" : "")
449                        ,(((cap >> 8) & 0x3) == 2 ? "[RX-STBC12]" : "")
450                        ,(((cap >> 8) & 0x3) == 3 ? "[RX-STBC123]" : "")
451                        ,(cap & HT_CAP_INFO_DSSS_CCK40MHZ ? "[DSSS_CCK-40]" : "")
452                        );
453        }
454out:
455nla_put_failure:
456        nlmsg_free(msg);
457        if (!capstring)
458                return strdup("");
459        return capstring;
460        }
461
462static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
463        [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
464};
465
466int mac80211_check_band(char *interface,int checkband) {
467        struct nlattr *tb[NL80211_BAND_ATTR_MAX + 1];
468        struct nl_msg *msg;
469        struct nlattr *bands, *band,*freqlist,*freq;
470        int rem, rem2, freq_mhz;
471        int phy;
472        int bandfound=0;
473        phy = mac80211_get_phyidx_by_vifname(interface);
474        if (phy == -1) {
475                return 0;
476        }
477
478        msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, false);
479        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
480        if (unl_genl_request_single(&unl, msg, &msg) < 0)
481                return 0;
482        bands = unl_find_attr(&unl, msg, NL80211_ATTR_WIPHY_BANDS);
483        if (!bands)
484                goto out;
485
486        nla_for_each_nested(band, bands, rem) {
487                freqlist = nla_find(nla_data(band), nla_len(band),
488                                    NL80211_BAND_ATTR_FREQS);
489                if (!freqlist)
490                        continue;
491                nla_for_each_nested(freq, freqlist, rem2) {
492                        nla_parse_nested(tb, NL80211_FREQUENCY_ATTR_MAX,
493                                         freq, freq_policy);
494                        if (!tb[NL80211_FREQUENCY_ATTR_FREQ])
495                                continue;
496
497                        if (tb[NL80211_FREQUENCY_ATTR_DISABLED])
498                                continue;
499
500                        freq_mhz = nla_get_u32(tb[NL80211_FREQUENCY_ATTR_FREQ]);
501                        if (checkband == 2 && freq_mhz < 3000 )
502                                bandfound=1;
503                        if (checkband == 5 && freq_mhz > 3000 )
504                                bandfound=1;
505                }
506        }
507        nlmsg_free(msg);
508        return bandfound;
509out:
510nla_put_failure:
511        nlmsg_free(msg);
512        return 0;
513}
514
515struct wifi_channels *mac80211_get_channels(char *interface,char *country,int max_bandwidth_khz, unsigned char checkband) {
516        struct nlattr *tb[NL80211_BAND_ATTR_MAX + 1];
517        struct nl_msg *msg;
518        struct nlattr *bands, *band,*freqlist,*freq;
519        struct ieee80211_regdomain *rd;
520        struct ieee80211_freq_range regfreq;
521        struct ieee80211_power_rule regpower;
522        struct wifi_channels *list = NULL;
523        int rem, rem2, freq_mhz,phy,rrc,startfreq,stopfreq,range,regmaxbw,run;
524        int regfound=0;
525        int htrange=30;
526        int chancount=0;
527        int count=0;
528        char sc[32];
529        int skip=1;
530        int rrdcount=0;
531
532        phy = mac80211_get_phyidx_by_vifname(interface);
533        if (phy == -1) return NULL;
534
535#ifdef HAVE_SUPERCHANNEL
536        sprintf(sc, "%s_regulatory", interface);
537        if (issuperchannel() && atoi(nvram_default_get(sc, "1")) == 0) skip=0;
538#endif
539
540
541        rd=mac80211_get_regdomain(country);
542        // for now just leave
543        if (rd == NULL) return list;
544
545        msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, false);
546        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
547        if (unl_genl_request_single(&unl, msg, &msg) < 0)
548                return NULL;
549        bands = unl_find_attr(&unl, msg, NL80211_ATTR_WIPHY_BANDS);
550        if (!bands)
551                goto out;
552
553        for (run=0;run <2;run++) {
554                if (run == 1) {
555                        list = (struct wifi_channels *)malloc(sizeof(struct wifi_channels) * (chancount+1));
556                        (void)memset(list, 0, (sizeof(struct wifi_channels)*(chancount+1)));
557                }
558                nla_for_each_nested(band, bands, rem) {
559                        freqlist = nla_find(nla_data(band), nla_len(band),
560                                            NL80211_BAND_ATTR_FREQS);
561                        if (!freqlist)
562                                continue;
563                        nla_for_each_nested(freq, freqlist, rem2) {
564                                nla_parse_nested(tb, NL80211_FREQUENCY_ATTR_MAX,
565                                                 freq, freq_policy);
566                                if (!tb[NL80211_FREQUENCY_ATTR_FREQ])
567                                        continue;
568
569                                if (skip && tb[NL80211_FREQUENCY_ATTR_DISABLED])
570                                        continue;
571                                regfound=0;
572                                if (max_bandwidth_khz == 40)
573                                                range=10;
574                                else
575                                        // for 10/5mhz this should be fine
576                                        range=max_bandwidth_khz/2;
577                                freq_mhz = (int) nla_get_u32(tb[NL80211_FREQUENCY_ATTR_FREQ]);
578                                if (skip == 0)
579                                        rrdcount=1;
580                                else
581                                        rrdcount=rd->n_reg_rules;
582                                for (rrc = 0; rrc < rrdcount; rrc++) {
583                                        regfreq  = rd->reg_rules[rrc].freq_range;
584                                        startfreq=(int)((float)(regfreq.start_freq_khz)/1000.0);
585                                        stopfreq=(int)((float)(regfreq.end_freq_khz)/1000.0);
586                                        regmaxbw=(int)((float)(regfreq.max_bandwidth_khz)/1000.0);
587                                        if (!skip)
588                                            regmaxbw = 40;
589                                        else
590                                            regmaxbw=(int)((float)(regfreq.max_bandwidth_khz)/1000.0);
591
592                                        if ( !skip || ( (freq_mhz - range) >= startfreq && (freq_mhz + range) <= stopfreq )) {
593                                                if (run == 1) {
594                                                        regpower = rd->reg_rules[rrc].power_rule;
595#if defined(HAVE_BUFFALO_SA) && defined(HAVE_ATH9K)
596                                                        if( (!strcmp(getUEnv("region"), "AP") || !strcmp(getUEnv("region"), "US"))
597                                                             && ieee80211_mhz2ieee(freq_mhz) > 11 && ieee80211_mhz2ieee(freq_mhz) < 14
598                                                             && nvram_default_match("region", "SA", ""))
599                                                                continue;
600#endif
601                                                        list[count].channel = ieee80211_mhz2ieee(freq_mhz);
602                                                        list[count].freq = freq_mhz;
603                                                        // todo: wenn wir das ueberhaupt noch verwenden
604                                                        list[count].noise = 0;
605                                                        list[count].max_eirp = (int)((float)(regpower.max_eirp)/100.0);
606                                                        if (rd->reg_rules[rrc].flags & RRF_NO_OFDM)
607                                                                list[count].no_ofdm = 1;
608                                                        if (rd->reg_rules[rrc].flags & RRF_NO_CCK)
609                                                                list[count].no_cck = 1;
610                                                        if (rd->reg_rules[rrc].flags & RRF_NO_INDOOR)
611                                                                list[count].no_indoor = 1;
612                                                        if (rd->reg_rules[rrc].flags & RRF_NO_OUTDOOR)
613                                                                list[count].no_outdoor = 1;
614                                                        if (rd->reg_rules[rrc].flags & RRF_DFS)
615                                                                list[count].dfs = 1;
616                                                        if (rd->reg_rules[rrc].flags & RRF_PTP_ONLY)
617                                                                list[count].ptp_only = 1;
618                                                        if (rd->reg_rules[rrc].flags & RRF_PTMP_ONLY)
619                                                                list[count].ptmp_only = 1;
620                                                        if (rd->reg_rules[rrc].flags & RRF_PASSIVE_SCAN)
621                                                                list[count].passive_scan = 1;
622                                                        if (rd->reg_rules[rrc].flags & RRF_NO_IBSS)
623                                                                list[count].no_ibss = 1;
624                                                                if (regmaxbw == 40) {
625                                                                        if ((freq_mhz - htrange) >= startfreq ) {
626                                                                                list[count].ht40minus = 1;
627                                                                        }
628                                                                        if ((freq_mhz + htrange) <= stopfreq) {
629                                                                                list[count].ht40plus = 1;
630                                                                        }
631                                                                }
632                                                        count++;
633                                                }
634                                                if (run == 0) chancount++;
635                                        }
636                                }
637                        }
638                }
639        }
640        list[count].freq=-1;
641        if (rd)
642                free(rd);
643        nlmsg_free(msg);
644        return list;
645out:
646nla_put_failure:
647        nlmsg_free(msg);
648        return NULL;
649}
650
651
652int has_ht40(char *interface) {
653                struct wifi_channels *chan;
654                int found=0;
655                int i=0;
656                char regdomain[32];
657                char *country;
658
659                sprintf(regdomain, "%s_regdomain", interface);
660                country = nvram_default_get(regdomain, "UNITED_STATES");
661
662                chan = mac80211_get_channels(interface, getIsoName(country), 40, 0xff);
663                if (chan != NULL)
664                        while (chan[i].freq != -1) {
665                                if (chan[i].ht40plus || chan[i].ht40minus) {
666                                        free(chan);
667                                        return 1;
668                                }
669                        i++;
670                        }
671                if (chan != NULL)
672                        free(chan);
673                return 0;
674}
675
676
677int mac80211_check_valid_frequency(char *interface, char *country, int freq) {
678                struct wifi_channels *chan;
679                int found=0;
680                int i=0;
681                chan = mac80211_get_channels(interface, country, 40, 0xff);
682                if (chan != NULL)
683                        while (chan[i].freq != -1) {
684                                if (freq == chan[i].freq) {
685                                        found=1;
686                                        break;
687                                }
688                        i++;
689                        }
690                if (chan != NULL)
691                        free(chan);
692                if ( found )
693                        return(freq);
694                else
695                        return(0);
696}
697
698static struct wifi_client_info *add_to_wifi_clients(struct wifi_client_info *list_root){
699                struct wifi_client_info *new = calloc(1, sizeof(struct wifi_client_info));
700                if (new == NULL) {
701                        fprintf(stderr, "add_wifi_clients: Out of memory!\n");
702                        return(NULL);
703                        }
704                else
705                        {
706                         new->next =  list_root;
707                         return(new);
708                        }
709                }
710
711void free_wifi_clients(struct wifi_client_info *wci) {
712        while (wci) {
713                struct wifi_client_info *next = wci->next;
714                free(wci);
715                wci = next;
716                }
717        }
718
719static int get_max_mcs_index(const __u8 *mcs)
720{
721        unsigned int mcs_bit, prev_bit = -2, prev_cont = 0;
722
723        for (mcs_bit = 0; mcs_bit <= 76; mcs_bit++) {
724                unsigned int mcs_octet = mcs_bit/8;
725                unsigned int MCS_RATE_BIT = 1 << mcs_bit % 8;
726                bool mcs_rate_idx_set;
727
728                mcs_rate_idx_set = !!(mcs[mcs_octet] & MCS_RATE_BIT);
729
730                if (!mcs_rate_idx_set)
731                        continue;
732
733                if (prev_bit != mcs_bit - 1) {
734                        /* if (prev_bit != -2)
735                                printf("%d, ", prev_bit);
736                        else
737                                printf(" ");
738                        printf("%d", mcs_bit); */
739                        prev_cont = 0;
740                } else if (!prev_cont) {
741                        // printf("-");
742                        prev_cont = 1;
743                }
744
745                prev_bit = mcs_bit;
746        }
747
748        if (prev_cont)
749                // printf("%d", prev_bit);
750                return prev_bit;
751        // printf("\n");
752        return 0;
753}
754
755static int get_ht_mcs(const __u8 *mcs)
756{
757        /* As defined in 7.3.2.57.4 Supported MCS Set field */
758        unsigned int tx_max_num_spatial_streams, max_rx_supp_data_rate;
759        bool tx_mcs_set_defined, tx_mcs_set_equal, tx_unequal_modulation;
760
761        max_rx_supp_data_rate = ((mcs[10] >> 8) & ((mcs[11] & 0x3) << 8));
762        tx_mcs_set_defined = !!(mcs[12] & (1 << 0));
763        tx_mcs_set_equal = !(mcs[12] & (1 << 1));
764        tx_max_num_spatial_streams = ((mcs[12] >> 2) & 3) + 1;
765        tx_unequal_modulation = !!(mcs[12] & (1 << 4));
766
767        // if (max_rx_supp_data_rate)
768        //      printf("\t\tHT Max RX data rate: %d Mbps\n", max_rx_supp_data_rate);
769        /* XXX: else see 9.6.0e.5.3 how to get this I think */
770
771        if (tx_mcs_set_defined) {
772                if (tx_mcs_set_equal) {
773                        // printf("\t\tHT TX/RX MCS rate indexes supported:");
774                        return(get_max_mcs_index(mcs));
775                } else {
776                        // printf("\t\tHT RX MCS rate indexes supported:");
777                        return(get_max_mcs_index(mcs));
778
779                        // if (tx_unequal_modulation)
780                                // printf("\t\tTX unequal modulation supported\n");
781                        // else
782                                // printf("\t\tTX unequal modulation not supported\n");
783
784                        // printf("\t\tHT TX Max spatial streams: %d\n",
785                        //      tx_max_num_spatial_streams);
786
787                        // printf("\t\tHT TX MCS rate indexes supported may differ\n");
788                }
789        } else {
790                // printf("\t\tHT RX MCS rate indexes supported:");
791                return(get_max_mcs_index(mcs));
792                // printf("\t\tHT TX MCS rate indexes are undefined\n");
793        }
794}
795
796int mac80211_get_maxrate(char *interface) {
797        struct nlattr *tb[NL80211_BAND_ATTR_MAX + 1];
798        struct nl_msg *msg;
799        struct nlattr *bands, *band,*ratelist,*rate;
800        int rem, rem2;
801        int phy;
802        int maxrate=0;
803        static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
804                [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
805                [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG },
806        };
807        phy = mac80211_get_phyidx_by_vifname(interface);
808        if (phy == -1) return 0;
809
810        msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, false);
811        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
812        if (unl_genl_request_single(&unl, msg, &msg) < 0)
813                return 0;
814        bands = unl_find_attr(&unl, msg, NL80211_ATTR_WIPHY_BANDS);
815        if (!bands)
816                goto out;
817
818        nla_for_each_nested(band, bands, rem) {
819                ratelist = nla_find(nla_data(band), nla_len(band),
820                                    NL80211_BAND_ATTR_RATES);
821                if (!ratelist)
822                        continue;
823                nla_for_each_nested(rate, ratelist, rem2) {
824                        nla_parse_nested(tb, NL80211_BITRATE_ATTR_MAX,
825                                         rate, rate_policy);
826                        if (!tb[NL80211_BITRATE_ATTR_RATE])
827                                continue;
828                        maxrate=0.1 * nla_get_u32(tb[NL80211_BITRATE_ATTR_RATE]);
829                }
830        }
831        printf("maxrate: %d\n",maxrate);
832        nlmsg_free(msg);
833        return maxrate;
834out:
835nla_put_failure:
836        nlmsg_free(msg);
837        return 0;
838}
839
840int mac80211_get_maxmcs(char *interface) {
841        struct nlattr *tb[NL80211_BAND_ATTR_MAX + 1];
842        struct nl_msg *msg;
843        struct nlattr *bands, *band;
844        int rem;
845        int phy;
846        int maxmcs=0;
847
848        phy = mac80211_get_phyidx_by_vifname(interface);
849        if (phy == -1) return 0;
850
851        msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, false);
852        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
853        if (unl_genl_request_single(&unl, msg, &msg) < 0)
854                return 0;
855        bands = unl_find_attr(&unl, msg, NL80211_ATTR_WIPHY_BANDS);
856        if (!bands)
857                goto out;
858
859        nla_for_each_nested(band, bands, rem) {
860        nla_parse(tb, NL80211_BAND_ATTR_MAX, nla_data(band),
861                  nla_len(band), NULL);
862        if (tb[NL80211_BAND_ATTR_HT_MCS_SET] &&
863                nla_len(tb[NL80211_BAND_ATTR_HT_MCS_SET]) == 16)
864                maxmcs=get_ht_mcs(nla_data(tb[NL80211_BAND_ATTR_HT_MCS_SET]));
865        }
866        printf("maxmcs: %d\n",maxmcs);
867        nlmsg_free(msg);
868        return maxmcs;
869out:
870        return 0;
871nla_put_failure:
872        nlmsg_free(msg);
873        return 0;
874}
875
876void mac80211_set_antennas(int phy,uint32_t tx_ant,uint32_t rx_ant ) {
877        struct nl_msg *msg;
878
879        msg = unl_genl_msg(&unl, NL80211_CMD_SET_WIPHY, false);
880        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
881        if (isap8x() && tx_ant == 5)
882                tx_ant=3;
883        if (isap8x() && tx_ant == 4)
884                tx_ant=2;
885        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
886        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
887        unl_genl_request(&unl, msg, NULL, NULL);
888        return;
889
890nla_put_failure:
891        nlmsg_free(msg);
892        return;
893}
894
895static int mac80211_get_antennas(int phy,int which,int direction) {
896        struct nlattr *tb[NL80211_ATTR_MAX + 1];
897        struct nl_msg *msg;
898        struct genlmsghdr *gnlh;
899        int ret=0;
900
901        msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, true);
902        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
903        if (unl_genl_request_single(&unl, msg, &msg) < 0)
904                return 0;
905        gnlh=nlmsg_data(nlmsg_hdr(msg));
906        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
907                  genlmsg_attrlen(gnlh, 0), NULL);
908        if (which == 0 && direction == 0) {
909                if (tb[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX])
910                     ret = ((int) nla_get_u32(tb[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX]));
911        }
912
913        if (which == 0 && direction == 1) {
914                if (tb[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX])
915                     ret = ((int) nla_get_u32(tb[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX]));
916        }
917
918        if (which == 1 && direction == 0) {
919                if (tb[NL80211_ATTR_WIPHY_ANTENNA_TX])
920                     ret = ((int) nla_get_u32(tb[NL80211_ATTR_WIPHY_ANTENNA_TX]));
921        }
922
923        if (which == 1 && direction == 1) {
924                if (tb[NL80211_ATTR_WIPHY_ANTENNA_RX])
925                     ret = ((int) nla_get_u32(tb[NL80211_ATTR_WIPHY_ANTENNA_RX]));
926        }
927        nlmsg_free(msg);
928        return ret;
929nla_put_failure:
930        nlmsg_free(msg);
931        return 0;
932}
933
934int mac80211_get_avail_tx_antenna(int phy) {
935        int ret=mac80211_get_antennas(phy,0,0);
936        if (isap8x() && ret == 3)
937                ret=5;
938        return(ret);
939        }
940
941int mac80211_get_avail_rx_antenna(int phy) {
942        return(mac80211_get_antennas(phy,0,1));
943        }
944
945int mac80211_get_configured_tx_antenna(int phy) {
946        int ret=mac80211_get_antennas(phy,1,0);
947        int avail=mac80211_get_antennas(phy,0,0);
948        if (isap8x() && avail == 3 && ret == 3)
949                ret=5;
950        if (isap8x() && avail == 3 && ret == 2)
951                ret=4;
952        return(ret);
953        }
954
955int mac80211_get_configured_rx_antenna(int phy) {
956        return(mac80211_get_antennas(phy,1,1));
957        }
Note: See TracBrowser for help on using the repository browser.