5 #include <netlink/genl/genl.h>
6 #include <netlink/genl/family.h>
7 #include <netlink/genl/ctrl.h>
8 #include <netlink/msg.h>
9 #include <netlink/attr.h>
14 static void print_flag(const char *name
, int *open
)
24 static void print_mcs_index(unsigned char *mcs
)
28 for (mcs_bit
= 0; mcs_bit
<= 76; mcs_bit
++) {
29 unsigned int mcs_octet
= mcs_bit
/8;
30 unsigned int MCS_RATE_BIT
= 1 << mcs_bit
% 8;
31 bool mcs_rate_idx_set
;
33 mcs_rate_idx_set
= !!(mcs
[mcs_octet
] & MCS_RATE_BIT
);
35 if (!mcs_rate_idx_set
)
38 printf("\t\t\tMCS index %d\n", mcs_bit
);
42 static int print_phy_handler(struct nl_msg
*msg
, void *arg
)
44 struct nlattr
*tb_msg
[NL80211_ATTR_MAX
+ 1];
45 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
47 struct nlattr
*tb_band
[NL80211_BAND_ATTR_MAX
+ 1];
49 struct nlattr
*tb_freq
[NL80211_FREQUENCY_ATTR_MAX
+ 1];
50 static struct nla_policy freq_policy
[NL80211_FREQUENCY_ATTR_MAX
+ 1] = {
51 [NL80211_FREQUENCY_ATTR_FREQ
] = { .type
= NLA_U32
},
52 [NL80211_FREQUENCY_ATTR_DISABLED
] = { .type
= NLA_FLAG
},
53 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN
] = { .type
= NLA_FLAG
},
54 [NL80211_FREQUENCY_ATTR_NO_IBSS
] = { .type
= NLA_FLAG
},
55 [NL80211_FREQUENCY_ATTR_RADAR
] = { .type
= NLA_FLAG
},
56 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER
] = { .type
= NLA_U32
},
59 struct nlattr
*tb_rate
[NL80211_BITRATE_ATTR_MAX
+ 1];
60 static struct nla_policy rate_policy
[NL80211_BITRATE_ATTR_MAX
+ 1] = {
61 [NL80211_BITRATE_ATTR_RATE
] = { .type
= NLA_U32
},
62 [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE
] = { .type
= NLA_FLAG
},
65 struct nlattr
*nl_band
;
66 struct nlattr
*nl_freq
;
67 struct nlattr
*nl_rate
;
68 struct nlattr
*nl_mode
;
69 struct nlattr
*nl_cmd
;
71 int rem_band
, rem_freq
, rem_rate
, rem_mode
, rem_cmd
;
74 nla_parse(tb_msg
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
75 genlmsg_attrlen(gnlh
, 0), NULL
);
77 if (!tb_msg
[NL80211_ATTR_WIPHY_BANDS
])
80 if (tb_msg
[NL80211_ATTR_WIPHY_NAME
])
81 printf("Wiphy %s\n", nla_get_string(tb_msg
[NL80211_ATTR_WIPHY_NAME
]));
83 nla_for_each_nested(nl_band
, tb_msg
[NL80211_ATTR_WIPHY_BANDS
], rem_band
) {
84 printf("\tBand %d:\n", bandidx
);
87 nla_parse(tb_band
, NL80211_BAND_ATTR_MAX
, nla_data(nl_band
),
88 nla_len(nl_band
), NULL
);
90 #ifdef NL80211_BAND_ATTR_HT_CAPA
91 if (tb_band
[NL80211_BAND_ATTR_HT_CAPA
]) {
92 unsigned short cap
= nla_get_u16(tb_band
[NL80211_BAND_ATTR_HT_CAPA
]);
93 #define PCOM(fmt, args...) do { printf("\t\t\t* " fmt "\n", ##args); } while (0)
94 #define PBCOM(bit, args...) if (cap & (bit)) PCOM(args)
95 printf("\t\tHT capabilities: 0x%.4x\n", cap
);
96 PBCOM(0x0001, "LPDC coding");
98 PCOM("20/40 MHz operation");
100 PCOM("20 MHz operation");
101 switch ((cap
& 0x000c) >> 2) {
103 PCOM("static SM PS");
106 PCOM("dynamic SM PS");
109 PCOM("reserved SM PS");
112 PCOM("SM PS disabled");
115 PBCOM(0x0010, "HT-greenfield");
116 PBCOM(0x0020, "20 MHz short GI");
117 PBCOM(0x0040, "40 MHz short GI");
118 PBCOM(0x0080, "TX STBC");
120 PCOM("RX STBC %d streams", (cap
& 0x0300) >> 8);
121 PBCOM(0x0400, "HT-delayed block-ack");
122 PCOM("max A-MSDU len %d", 0xeff + ((cap
& 0x0800) << 1));
123 PBCOM(0x1000, "DSSS/CCK 40 MHz");
124 PBCOM(0x2000, "PSMP support");
125 PBCOM(0x4000, "40 MHz intolerant");
126 PBCOM(0x8000, "L-SIG TXOP protection support");
128 if (tb_band
[NL80211_BAND_ATTR_HT_AMPDU_FACTOR
]) {
129 unsigned char factor
= nla_get_u8(tb_band
[NL80211_BAND_ATTR_HT_AMPDU_FACTOR
]);
130 printf("\t\tHT A-MPDU factor: 0x%.4x (%d bytes)\n", factor
, (1<<(13+factor
))-1);
132 if (tb_band
[NL80211_BAND_ATTR_HT_AMPDU_DENSITY
]) {
133 unsigned char dens
= nla_get_u8(tb_band
[NL80211_BAND_ATTR_HT_AMPDU_DENSITY
]);
134 printf("\t\tHT A-MPDU density: 0x%.4x (", dens
);
137 printf("no restriction)\n");
140 printf("1/4 usec)\n");
143 printf("1/2 usec)\n");
146 printf("%d usec)\n", 1<<(dens
- 3));
149 if (tb_band
[NL80211_BAND_ATTR_HT_MCS_SET
] &&
150 nla_len(tb_band
[NL80211_BAND_ATTR_HT_MCS_SET
]) == 16) {
151 /* As defined in 7.3.2.57.4 Supported MCS Set field */
152 unsigned int tx_max_num_spatial_streams
, max_rx_supp_data_rate
;
153 unsigned char *mcs
= nla_data(tb_band
[NL80211_BAND_ATTR_HT_MCS_SET
]);
154 bool tx_mcs_set_defined
, tx_mcs_set_equal
, tx_unequal_modulation
;
156 printf("\t\tHT MCS set: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
157 mcs
[0], mcs
[1], mcs
[2], mcs
[3], mcs
[4], mcs
[5], mcs
[6], mcs
[7],
158 mcs
[8], mcs
[9], mcs
[10], mcs
[11], mcs
[12], mcs
[13], mcs
[14], mcs
[15]);
160 max_rx_supp_data_rate
= ((mcs
[10] >> 8) & ((mcs
[11] & 0x3) << 8));
161 tx_mcs_set_defined
= !!(mcs
[12] & (1 << 0));
162 tx_mcs_set_equal
= !(mcs
[12] & (1 << 1));
163 tx_max_num_spatial_streams
= (mcs
[12] & ((1 << 2) | (1 << 3))) + 1;
164 tx_unequal_modulation
= !!(mcs
[12] & (1 << 4));
166 if (max_rx_supp_data_rate
)
167 printf("\t\tHT Max RX data rate: %d Mbps\n", max_rx_supp_data_rate
);
168 /* XXX: else see 9.6.0e.5.3 how to get this I think */
170 if (tx_mcs_set_defined
) {
171 if (tx_mcs_set_equal
) {
172 printf("\t\tHT TX/RX MCS rate indexes supported:\n");
173 print_mcs_index(&mcs
[0]);
175 printf("\t\tHT RX MCS rate indexes supported:\n");
176 print_mcs_index(&mcs
[0]);
178 if (tx_unequal_modulation
)
179 printf("TX unequal modulation supported\n");
181 printf("TX unequal modulation not supported\n");
183 printf("\t\tHT TX Max spatiel streams: %d\n",
184 tx_max_num_spatial_streams
);
186 printf("\t\tHT TX MCS rate indexes supported may differ\n");
190 printf("\t\tHT RX MCS rate indexes supported:\n");
191 print_mcs_index(&mcs
[0]);
192 printf("\t\tHT TX MCS rates indexes are undefined\n");
198 printf("\t\tFrequencies:\n");
200 nla_for_each_nested(nl_freq
, tb_band
[NL80211_BAND_ATTR_FREQS
], rem_freq
) {
202 nla_parse(tb_freq
, NL80211_FREQUENCY_ATTR_MAX
, nla_data(nl_freq
),
203 nla_len(nl_freq
), freq_policy
);
204 if (!tb_freq
[NL80211_FREQUENCY_ATTR_FREQ
])
206 freq
= nla_get_u32(tb_freq
[NL80211_FREQUENCY_ATTR_FREQ
]);
207 printf("\t\t\t* %d MHz [%d]", freq
, ieee80211_frequency_to_channel(freq
));
209 if (tb_freq
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER
] &&
210 !tb_freq
[NL80211_FREQUENCY_ATTR_DISABLED
])
211 printf(" (%.1f dBm)", 0.01 * nla_get_u32(tb_freq
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER
]));
214 if (tb_freq
[NL80211_FREQUENCY_ATTR_DISABLED
]) {
215 print_flag("disabled", &open
);
218 if (tb_freq
[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN
])
219 print_flag("passive scanning", &open
);
220 if (tb_freq
[NL80211_FREQUENCY_ATTR_NO_IBSS
])
221 print_flag("no IBSS", &open
);
222 if (tb_freq
[NL80211_FREQUENCY_ATTR_RADAR
])
223 print_flag("radar detection", &open
);
230 printf("\t\tBitrates (non-HT):\n");
232 nla_for_each_nested(nl_rate
, tb_band
[NL80211_BAND_ATTR_RATES
], rem_rate
) {
233 nla_parse(tb_rate
, NL80211_BITRATE_ATTR_MAX
, nla_data(nl_rate
),
234 nla_len(nl_rate
), rate_policy
);
235 if (!tb_rate
[NL80211_BITRATE_ATTR_RATE
])
237 printf("\t\t\t* %2.1f Mbps", 0.1 * nla_get_u32(tb_rate
[NL80211_BITRATE_ATTR_RATE
]));
239 if (tb_rate
[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE
])
240 print_flag("short preamble supported", &open
);
247 if (tb_msg
[NL80211_ATTR_MAX_NUM_SCAN_SSIDS
])
248 printf("\tmax # scan SSIDs: %d\n",
249 nla_get_u8(tb_msg
[NL80211_ATTR_MAX_NUM_SCAN_SSIDS
]));
251 if (tb_msg
[NL80211_ATTR_WIPHY_FRAG_THRESHOLD
]) {
254 frag
= nla_get_u32(tb_msg
[NL80211_ATTR_WIPHY_FRAG_THRESHOLD
]);
255 if (frag
!= (unsigned int)-1)
256 printf("\tFragmentation threshold: %d\n", frag
);
259 if (tb_msg
[NL80211_ATTR_WIPHY_RTS_THRESHOLD
]) {
262 rts
= nla_get_u32(tb_msg
[NL80211_ATTR_WIPHY_RTS_THRESHOLD
]);
263 if (rts
!= (unsigned int)-1)
264 printf("\tRTS threshold: %d\n", rts
);
267 if (!tb_msg
[NL80211_ATTR_SUPPORTED_IFTYPES
])
270 printf("\tSupported interface modes:\n");
271 nla_for_each_nested(nl_mode
, tb_msg
[NL80211_ATTR_SUPPORTED_IFTYPES
], rem_mode
)
272 printf("\t\t * %s\n", iftype_name(nl_mode
->nla_type
));
275 if (!tb_msg
[NL80211_ATTR_SUPPORTED_COMMANDS
])
278 printf("\tSupported commands:\n");
279 nla_for_each_nested(nl_cmd
, tb_msg
[NL80211_ATTR_SUPPORTED_COMMANDS
], rem_cmd
)
280 printf("\t\t * %s\n", command_name(nla_get_u32(nl_cmd
)));
285 static int handle_info(struct nl80211_state
*state
,
288 int argc
, char **argv
)
290 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_phy_handler
, NULL
);
294 __COMMAND(NULL
, info
, "info", NULL
, NL80211_CMD_GET_WIPHY
, 0, 0, CIB_PHY
, handle_info
,
295 "Show capabilities for the specified wireless device.");
296 TOPLEVEL(list
, NULL
, NL80211_CMD_GET_WIPHY
, NLM_F_DUMP
, CIB_NONE
, handle_info
,
297 "List all wireless devices and their capabilities.");
298 TOPLEVEL(phy
, NULL
, NL80211_CMD_GET_WIPHY
, NLM_F_DUMP
, CIB_NONE
, handle_info
, NULL
);