6 #include <netlink/genl/genl.h>
7 #include <netlink/genl/family.h>
8 #include <netlink/genl/ctrl.h>
9 #include <netlink/msg.h>
10 #include <netlink/attr.h>
17 #define MHZ_TO_KHZ(freq) ((freq) * 1000)
18 #define KHZ_TO_MHZ(freq) ((freq) / 1000)
19 #define DBI_TO_MBI(gain) ((gain) * 100)
20 #define MBI_TO_DBI(gain) ((gain) / 100)
21 #define DBM_TO_MBM(gain) ((gain) * 100)
22 #define MBM_TO_DBM(gain) ((gain) / 100)
24 static bool isalpha_upper(char letter
)
26 if (letter
>= 65 && letter
<= 90)
31 static bool is_alpha2(char *alpha2
)
33 if (isalpha_upper(alpha2
[0]) && isalpha_upper(alpha2
[1]))
38 static bool is_world_regdom(char *alpha2
)
41 if (alpha2
[0] == 48 && alpha2
[1] == 48)
46 char *reg_initiator_to_string(__u8 initiator
)
49 case NL80211_REGDOM_SET_BY_CORE
:
50 return "the wireless core upon initialization";
51 case NL80211_REGDOM_SET_BY_USER
:
53 case NL80211_REGDOM_SET_BY_DRIVER
:
55 case NL80211_REGDOM_SET_BY_COUNTRY_IE
:
56 return "a country IE";
62 static int handle_reg_set(struct nl80211_state
*state
,
65 int argc
, char **argv
,
73 if (!is_alpha2(argv
[0]) && !is_world_regdom(argv
[0])) {
74 fprintf(stderr
, "not a valid ISO/IEC 3166-1 alpha2\n");
75 fprintf(stderr
, "Special non-alpha2 usable entries:\n");
76 fprintf(stderr
, "\t00\tWorld Regulatory domain\n");
80 alpha2
[0] = argv
[0][0];
81 alpha2
[1] = argv
[0][1];
90 NLA_PUT_STRING(msg
, NL80211_ATTR_REG_ALPHA2
, alpha2
);
96 COMMAND(reg
, set
, "<ISO/IEC 3166-1 alpha2>",
97 NL80211_CMD_REQ_SET_REG
, 0, CIB_NONE
, handle_reg_set
,
98 "Notify the kernel about the current regulatory domain.");
100 static int print_reg_handler(struct nl_msg
*msg
, void *arg
)
103 #define PARSE_FLAG(nl_flag, string_value) do { \
104 if ((flags & nl_flag)) { \
105 printf(", %s", string_value); \
108 struct nlattr
*tb_msg
[NL80211_ATTR_MAX
+ 1];
109 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
111 struct nlattr
*nl_rule
;
113 static struct nla_policy reg_rule_policy
[NL80211_FREQUENCY_ATTR_MAX
+ 1] = {
114 [NL80211_ATTR_REG_RULE_FLAGS
] = { .type
= NLA_U32
},
115 [NL80211_ATTR_FREQ_RANGE_START
] = { .type
= NLA_U32
},
116 [NL80211_ATTR_FREQ_RANGE_END
] = { .type
= NLA_U32
},
117 [NL80211_ATTR_FREQ_RANGE_MAX_BW
] = { .type
= NLA_U32
},
118 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN
] = { .type
= NLA_U32
},
119 [NL80211_ATTR_POWER_RULE_MAX_EIRP
] = { .type
= NLA_U32
},
122 nla_parse(tb_msg
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
123 genlmsg_attrlen(gnlh
, 0), NULL
);
125 if (!tb_msg
[NL80211_ATTR_REG_ALPHA2
]) {
126 printf("No alpha2\n");
130 if (!tb_msg
[NL80211_ATTR_REG_RULES
]) {
131 printf("No reg rules\n");
135 alpha2
= nla_data(tb_msg
[NL80211_ATTR_REG_ALPHA2
]);
136 printf("country %c%c:\n", alpha2
[0], alpha2
[1]);
138 nla_for_each_nested(nl_rule
, tb_msg
[NL80211_ATTR_REG_RULES
], rem_rule
) {
139 struct nlattr
*tb_rule
[NL80211_FREQUENCY_ATTR_MAX
+ 1];
140 __u32 flags
, start_freq_khz
, end_freq_khz
, max_bw_khz
, max_ant_gain_mbi
, max_eirp_mbm
;
142 nla_parse(tb_rule
, NL80211_FREQUENCY_ATTR_MAX
, nla_data(nl_rule
), nla_len(nl_rule
), reg_rule_policy
);
144 flags
= nla_get_u32(tb_rule
[NL80211_ATTR_REG_RULE_FLAGS
]);
145 start_freq_khz
= nla_get_u32(tb_rule
[NL80211_ATTR_FREQ_RANGE_START
]);
146 end_freq_khz
= nla_get_u32(tb_rule
[NL80211_ATTR_FREQ_RANGE_END
]);
147 max_bw_khz
= nla_get_u32(tb_rule
[NL80211_ATTR_FREQ_RANGE_MAX_BW
]);
148 max_ant_gain_mbi
= nla_get_u32(tb_rule
[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN
]);
149 max_eirp_mbm
= nla_get_u32(tb_rule
[NL80211_ATTR_POWER_RULE_MAX_EIRP
]);
152 printf("\t(%d - %d @ %d), (",
153 KHZ_TO_MHZ(start_freq_khz
), KHZ_TO_MHZ(end_freq_khz
), KHZ_TO_MHZ(max_bw_khz
));
155 if (MBI_TO_DBI(max_ant_gain_mbi
))
156 printf("%d", MBI_TO_DBI(max_ant_gain_mbi
));
160 printf(", %d)", MBM_TO_DBM(max_eirp_mbm
));
167 /* Sync this output format to match that of dbparse.py from wireless-regdb.git */
168 PARSE_FLAG(NL80211_RRF_NO_OFDM
, "NO-OFDM");
169 PARSE_FLAG(NL80211_RRF_NO_CCK
, "NO-CCK");
170 PARSE_FLAG(NL80211_RRF_NO_INDOOR
, "NO-INDOOR");
171 PARSE_FLAG(NL80211_RRF_NO_OUTDOOR
, "NO-OUTDOOR");
172 PARSE_FLAG(NL80211_RRF_DFS
, "DFS");
173 PARSE_FLAG(NL80211_RRF_PTP_ONLY
, "PTP-ONLY");
174 PARSE_FLAG(NL80211_RRF_PASSIVE_SCAN
, "PASSIVE-SCAN");
175 PARSE_FLAG(NL80211_RRF_NO_IBSS
, "NO-IBSS");
183 static int handle_reg_get(struct nl80211_state
*state
,
186 int argc
, char **argv
,
189 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_reg_handler
, NULL
);
192 COMMAND(reg
, get
, NULL
, NL80211_CMD_GET_REG
, 0, CIB_NONE
, handle_reg_get
,
193 "Print out the kernel's current regulatory domain information.");