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
)
72 if (!is_alpha2(argv
[0]) && !is_world_regdom(argv
[0])) {
73 fprintf(stderr
, "not a valid ISO/IEC 3166-1 alpha2\n");
74 fprintf(stderr
, "Special non-alpha2 usable entries:\n");
75 fprintf(stderr
, "\t00\tWorld Regulatory domain\n");
79 alpha2
[0] = argv
[0][0];
80 alpha2
[1] = argv
[0][1];
89 NLA_PUT_STRING(msg
, NL80211_ATTR_REG_ALPHA2
, alpha2
);
95 COMMAND(reg
, set
, "<ISO/IEC 3166-1 alpha2>",
96 NL80211_CMD_REQ_SET_REG
, 0, CIB_NONE
, handle_reg_set
,
97 "Notify the kernel about the current regulatory domain.");
99 static int print_reg_handler(struct nl_msg
*msg
, void *arg
)
102 #define PARSE_FLAG(nl_flag, string_value) do { \
103 if ((flags & nl_flag)) { \
104 printf(", %s", string_value); \
107 struct nlattr
*tb_msg
[NL80211_ATTR_MAX
+ 1];
108 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
110 struct nlattr
*nl_rule
;
112 static struct nla_policy reg_rule_policy
[NL80211_FREQUENCY_ATTR_MAX
+ 1] = {
113 [NL80211_ATTR_REG_RULE_FLAGS
] = { .type
= NLA_U32
},
114 [NL80211_ATTR_FREQ_RANGE_START
] = { .type
= NLA_U32
},
115 [NL80211_ATTR_FREQ_RANGE_END
] = { .type
= NLA_U32
},
116 [NL80211_ATTR_FREQ_RANGE_MAX_BW
] = { .type
= NLA_U32
},
117 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN
] = { .type
= NLA_U32
},
118 [NL80211_ATTR_POWER_RULE_MAX_EIRP
] = { .type
= NLA_U32
},
121 nla_parse(tb_msg
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
122 genlmsg_attrlen(gnlh
, 0), NULL
);
124 if (!tb_msg
[NL80211_ATTR_REG_ALPHA2
]) {
125 printf("No alpha2\n");
129 if (!tb_msg
[NL80211_ATTR_REG_RULES
]) {
130 printf("No reg rules\n");
134 alpha2
= nla_data(tb_msg
[NL80211_ATTR_REG_ALPHA2
]);
135 printf("country %c%c:\n", alpha2
[0], alpha2
[1]);
137 nla_for_each_nested(nl_rule
, tb_msg
[NL80211_ATTR_REG_RULES
], rem_rule
) {
138 struct nlattr
*tb_rule
[NL80211_FREQUENCY_ATTR_MAX
+ 1];
139 __u32 flags
, start_freq_khz
, end_freq_khz
, max_bw_khz
, max_ant_gain_mbi
, max_eirp_mbm
;
141 nla_parse(tb_rule
, NL80211_FREQUENCY_ATTR_MAX
, nla_data(nl_rule
), nla_len(nl_rule
), reg_rule_policy
);
143 flags
= nla_get_u32(tb_rule
[NL80211_ATTR_REG_RULE_FLAGS
]);
144 start_freq_khz
= nla_get_u32(tb_rule
[NL80211_ATTR_FREQ_RANGE_START
]);
145 end_freq_khz
= nla_get_u32(tb_rule
[NL80211_ATTR_FREQ_RANGE_END
]);
146 max_bw_khz
= nla_get_u32(tb_rule
[NL80211_ATTR_FREQ_RANGE_MAX_BW
]);
147 max_ant_gain_mbi
= nla_get_u32(tb_rule
[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN
]);
148 max_eirp_mbm
= nla_get_u32(tb_rule
[NL80211_ATTR_POWER_RULE_MAX_EIRP
]);
151 printf("\t(%d - %d @ %d), (",
152 KHZ_TO_MHZ(start_freq_khz
), KHZ_TO_MHZ(end_freq_khz
), KHZ_TO_MHZ(max_bw_khz
));
154 if (MBI_TO_DBI(max_ant_gain_mbi
))
155 printf("%d", MBI_TO_DBI(max_ant_gain_mbi
));
159 printf(", %d)", MBM_TO_DBM(max_eirp_mbm
));
166 /* Sync this output format to match that of dbparse.py from wireless-regdb.git */
167 PARSE_FLAG(NL80211_RRF_NO_OFDM
, "NO-OFDM");
168 PARSE_FLAG(NL80211_RRF_NO_CCK
, "NO-CCK");
169 PARSE_FLAG(NL80211_RRF_NO_INDOOR
, "NO-INDOOR");
170 PARSE_FLAG(NL80211_RRF_NO_OUTDOOR
, "NO-OUTDOOR");
171 PARSE_FLAG(NL80211_RRF_DFS
, "DFS");
172 PARSE_FLAG(NL80211_RRF_PTP_ONLY
, "PTP-ONLY");
173 PARSE_FLAG(NL80211_RRF_PASSIVE_SCAN
, "PASSIVE-SCAN");
174 PARSE_FLAG(NL80211_RRF_NO_IBSS
, "NO-IBSS");
182 static int handle_reg_get(struct nl80211_state
*state
,
185 int argc
, char **argv
)
187 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_reg_handler
, NULL
);
190 COMMAND(reg
, get
, NULL
, NL80211_CMD_GET_REG
, 0, CIB_NONE
, handle_reg_get
,
191 "Print out the kernel's current regulatory domain information.");