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>
15 #define MHZ_TO_KHZ(freq) ((freq) * 1000)
16 #define KHZ_TO_MHZ(freq) ((freq) / 1000)
17 #define DBI_TO_MBI(gain) ((gain) * 100)
18 #define MBI_TO_DBI(gain) ((gain) / 100)
19 #define DBM_TO_MBM(gain) ((gain) * 100)
20 #define MBM_TO_DBM(gain) ((gain) / 100)
22 static bool isalpha_upper(char letter
)
24 if (letter
>= 65 && letter
<= 90)
29 static bool is_alpha2(char *alpha2
)
31 if (isalpha_upper(alpha2
[0]) && isalpha_upper(alpha2
[1]))
36 static bool is_world_regdom(char *alpha2
)
39 if (alpha2
[0] == 48 && alpha2
[1] == 48)
44 char *reg_initiator_to_string(__u8 initiator
)
47 case NL80211_REGDOM_SET_BY_CORE
:
48 return "the wireless core upon initialization";
49 case NL80211_REGDOM_SET_BY_USER
:
51 case NL80211_REGDOM_SET_BY_DRIVER
:
53 case NL80211_REGDOM_SET_BY_COUNTRY_IE
:
54 return "a country IE";
60 static int handle_reg_set(struct nl80211_state
*state
,
63 int argc
, char **argv
)
70 if (!is_alpha2(argv
[0]) && !is_world_regdom(argv
[0])) {
71 fprintf(stderr
, "not a valid ISO/IEC 3166-1 alpha2\n");
72 fprintf(stderr
, "Special non-alpha2 usable entries:\n");
73 fprintf(stderr
, "\t00\tWorld Regulatory domain\n");
77 alpha2
[0] = argv
[0][0];
78 alpha2
[1] = argv
[0][1];
87 NLA_PUT_STRING(msg
, NL80211_ATTR_REG_ALPHA2
, alpha2
);
93 COMMAND(reg
, set
, "<ISO/IEC 3166-1 alpha2>",
94 NL80211_CMD_REQ_SET_REG
, 0, CIB_NONE
, handle_reg_set
);
96 static int print_reg_handler(struct nl_msg
*msg
, void *arg
)
99 #define PARSE_FLAG(nl_flag, string_value) do { \
100 if ((flags & nl_flag)) { \
101 printf(", %s", string_value); \
104 struct nlattr
*tb_msg
[NL80211_ATTR_MAX
+ 1];
105 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
107 struct nlattr
*nl_rule
;
109 static struct nla_policy reg_rule_policy
[NL80211_FREQUENCY_ATTR_MAX
+ 1] = {
110 [NL80211_ATTR_REG_RULE_FLAGS
] = { .type
= NLA_U32
},
111 [NL80211_ATTR_FREQ_RANGE_START
] = { .type
= NLA_U32
},
112 [NL80211_ATTR_FREQ_RANGE_END
] = { .type
= NLA_U32
},
113 [NL80211_ATTR_FREQ_RANGE_MAX_BW
] = { .type
= NLA_U32
},
114 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN
] = { .type
= NLA_U32
},
115 [NL80211_ATTR_POWER_RULE_MAX_EIRP
] = { .type
= NLA_U32
},
118 nla_parse(tb_msg
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
119 genlmsg_attrlen(gnlh
, 0), NULL
);
121 if (!tb_msg
[NL80211_ATTR_REG_ALPHA2
]) {
122 printf("No alpha2\n");
126 if (!tb_msg
[NL80211_ATTR_REG_RULES
]) {
127 printf("No reg rules\n");
131 alpha2
= nla_data(tb_msg
[NL80211_ATTR_REG_ALPHA2
]);
132 printf("country %s:\n", alpha2
);
134 nla_for_each_nested(nl_rule
, tb_msg
[NL80211_ATTR_REG_RULES
], rem_rule
) {
135 struct nlattr
*tb_rule
[NL80211_FREQUENCY_ATTR_MAX
+ 1];
136 __u32 flags
, start_freq_khz
, end_freq_khz
, max_bw_khz
, max_ant_gain_mbi
, max_eirp_mbm
;
138 nla_parse(tb_rule
, NL80211_FREQUENCY_ATTR_MAX
, nla_data(nl_rule
), nla_len(nl_rule
), reg_rule_policy
);
140 flags
= nla_get_u32(tb_rule
[NL80211_ATTR_REG_RULE_FLAGS
]);
141 start_freq_khz
= nla_get_u32(tb_rule
[NL80211_ATTR_FREQ_RANGE_START
]);
142 end_freq_khz
= nla_get_u32(tb_rule
[NL80211_ATTR_FREQ_RANGE_END
]);
143 max_bw_khz
= nla_get_u32(tb_rule
[NL80211_ATTR_FREQ_RANGE_MAX_BW
]);
144 max_ant_gain_mbi
= nla_get_u32(tb_rule
[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN
]);
145 max_eirp_mbm
= nla_get_u32(tb_rule
[NL80211_ATTR_POWER_RULE_MAX_EIRP
]);
148 printf("\t(%d - %d @ %d), (",
149 KHZ_TO_MHZ(start_freq_khz
), KHZ_TO_MHZ(end_freq_khz
), KHZ_TO_MHZ(max_bw_khz
));
151 if (MBI_TO_DBI(max_ant_gain_mbi
))
152 printf("%d", MBI_TO_DBI(max_ant_gain_mbi
));
156 printf(", %d)", MBM_TO_DBM(max_eirp_mbm
));
163 /* Sync this output format to match that of dbparse.py from wireless-regdb.git */
164 PARSE_FLAG(NL80211_RRF_NO_OFDM
, "NO-OFDM");
165 PARSE_FLAG(NL80211_RRF_NO_CCK
, "NO-CCK");
166 PARSE_FLAG(NL80211_RRF_NO_INDOOR
, "NO-INDOOR");
167 PARSE_FLAG(NL80211_RRF_NO_OUTDOOR
, "NO-OUTDOOR");
168 PARSE_FLAG(NL80211_RRF_DFS
, "DFS");
169 PARSE_FLAG(NL80211_RRF_PTP_ONLY
, "PTP-ONLY");
170 PARSE_FLAG(NL80211_RRF_PASSIVE_SCAN
, "PASSIVE-SCAN");
171 PARSE_FLAG(NL80211_RRF_NO_IBSS
, "NO-IBSS");
179 static int handle_reg_get(struct nl80211_state
*state
,
182 int argc
, char **argv
)
184 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_reg_handler
, NULL
);
187 COMMAND(reg
, get
, NULL
, NL80211_CMD_GET_REG
, 0, CIB_NONE
, handle_reg_get
);