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
;
70 int rem_band
, rem_freq
, rem_rate
, rem_mode
;
73 nla_parse(tb_msg
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
74 genlmsg_attrlen(gnlh
, 0), NULL
);
76 if (!tb_msg
[NL80211_ATTR_WIPHY_BANDS
])
79 if (tb_msg
[NL80211_ATTR_WIPHY_NAME
])
80 printf("Wiphy %s\n", nla_get_string(tb_msg
[NL80211_ATTR_WIPHY_NAME
]));
82 nla_for_each_nested(nl_band
, tb_msg
[NL80211_ATTR_WIPHY_BANDS
], rem_band
) {
83 printf("\tBand %d:\n", bandidx
);
86 nla_parse(tb_band
, NL80211_BAND_ATTR_MAX
, nla_data(nl_band
),
87 nla_len(nl_band
), NULL
);
89 #ifdef NL80211_BAND_ATTR_HT_CAPA
90 if (tb_band
[NL80211_BAND_ATTR_HT_CAPA
]) {
91 unsigned short cap
= nla_get_u16(tb_band
[NL80211_BAND_ATTR_HT_CAPA
]);
92 #define PCOM(fmt, args...) do { printf("\t\t\t* " fmt "\n", ##args); } while (0)
93 #define PBCOM(bit, args...) if (cap & (bit)) PCOM(args)
94 printf("\t\tHT capabilities: 0x%.4x\n", cap
);
95 PBCOM(0x0001, "LPDC coding");
97 PCOM("20/40 MHz operation");
99 PCOM("20 MHz operation");
100 switch ((cap
& 0x000c) >> 2) {
102 PCOM("static SM PS");
105 PCOM("dynamic SM PS");
108 PCOM("reserved SM PS");
111 PCOM("SM PS disabled");
114 PBCOM(0x0010, "HT-greenfield");
115 PBCOM(0x0020, "20 MHz short GI");
116 PBCOM(0x0040, "40 MHz short GI");
117 PBCOM(0x0080, "TX STBC");
119 PCOM("RX STBC %d streams", (cap
& 0x0300) >> 8);
120 PBCOM(0x0400, "HT-delayed block-ack");
121 PCOM("max A-MSDU len %d", 0xeff + ((cap
& 0x0800) << 1));
122 PBCOM(0x1000, "DSSS/CCK 40 MHz");
123 PBCOM(0x2000, "PSMP support");
124 PBCOM(0x4000, "40 MHz intolerant");
125 PBCOM(0x8000, "L-SIG TXOP protection support");
127 if (tb_band
[NL80211_BAND_ATTR_HT_AMPDU_FACTOR
]) {
128 unsigned char factor
= nla_get_u8(tb_band
[NL80211_BAND_ATTR_HT_AMPDU_FACTOR
]);
129 printf("\t\tHT A-MPDU factor: 0x%.4x (%d bytes)\n", factor
, (1<<(13+factor
))-1);
131 if (tb_band
[NL80211_BAND_ATTR_HT_AMPDU_DENSITY
]) {
132 unsigned char dens
= nla_get_u8(tb_band
[NL80211_BAND_ATTR_HT_AMPDU_DENSITY
]);
133 printf("\t\tHT A-MPDU density: 0x%.4x (", dens
);
136 printf("no restriction)\n");
139 printf("1/4 usec)\n");
142 printf("1/2 usec)\n");
145 printf("%d usec)\n", 1<<(dens
- 3));
148 if (tb_band
[NL80211_BAND_ATTR_HT_MCS_SET
] &&
149 nla_len(tb_band
[NL80211_BAND_ATTR_HT_MCS_SET
]) == 16) {
150 /* As defined in 7.3.2.57.4 Supported MCS Set field */
151 unsigned int tx_max_num_spatial_streams
, max_rx_supp_data_rate
;
152 unsigned char *mcs
= nla_data(tb_band
[NL80211_BAND_ATTR_HT_MCS_SET
]);
153 bool tx_mcs_set_defined
, tx_mcs_set_equal
, tx_unequal_modulation
;
155 printf("\t\tHT MCS set: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
156 mcs
[0], mcs
[1], mcs
[2], mcs
[3], mcs
[4], mcs
[5], mcs
[6], mcs
[7],
157 mcs
[8], mcs
[9], mcs
[10], mcs
[11], mcs
[12], mcs
[13], mcs
[14], mcs
[15]);
159 max_rx_supp_data_rate
= ((mcs
[10] >> 8) & ((mcs
[11] & 0x3) << 8));
160 tx_mcs_set_defined
= !!(mcs
[12] & (1 << 0));
161 tx_mcs_set_equal
= !(mcs
[12] & (1 << 1));
162 tx_max_num_spatial_streams
= (mcs
[12] | ((1 << 3) | (1 << 4))) + 1;
163 tx_unequal_modulation
= !!(mcs
[12] & (1 << 5));
165 if (max_rx_supp_data_rate
)
166 printf("\t\tHT Max RX data rate: %d Mbps\n", max_rx_supp_data_rate
);
167 /* XXX: else see 9.6.0e.5.3 how to get this I think */
169 if (tx_mcs_set_defined
) {
170 if (tx_mcs_set_equal
) {
171 printf("\t\tHT TX/RX MCS rate indexes supported:\n");
172 print_mcs_index(&mcs
[0]);
174 printf("\t\tHT RX MCS rate indexes supported:\n");
175 print_mcs_index(&mcs
[0]);
177 if (tx_unequal_modulation
)
178 printf("TX unequal modulation supported\n");
180 printf("TX unequal modulation not supported\n");
182 printf("\t\tHT TX Max spatiel streams: %d\n",
183 tx_max_num_spatial_streams
);
185 printf("\t\tHT TX MCS rate indexes supported may differ\n");
189 printf("\t\tHT RX MCS rate indexes supported:\n");
190 print_mcs_index(&mcs
[0]);
191 printf("\t\tHT TX MCS rates indexes are undefined\n");
197 printf("\t\tFrequencies:\n");
199 nla_for_each_nested(nl_freq
, tb_band
[NL80211_BAND_ATTR_FREQS
], rem_freq
) {
201 nla_parse(tb_freq
, NL80211_FREQUENCY_ATTR_MAX
, nla_data(nl_freq
),
202 nla_len(nl_freq
), freq_policy
);
203 if (!tb_freq
[NL80211_FREQUENCY_ATTR_FREQ
])
205 freq
= nla_get_u32(tb_freq
[NL80211_FREQUENCY_ATTR_FREQ
]);
206 printf("\t\t\t* %d MHz [%d]", freq
, ieee80211_frequency_to_channel(freq
));
208 if (tb_freq
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER
] &&
209 !tb_freq
[NL80211_FREQUENCY_ATTR_DISABLED
])
210 printf(" (%.1f dBm)", 0.01 * nla_get_u32(tb_freq
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER
]));
213 if (tb_freq
[NL80211_FREQUENCY_ATTR_DISABLED
]) {
214 print_flag("disabled", &open
);
217 if (tb_freq
[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN
])
218 print_flag("passive scanning", &open
);
219 if (tb_freq
[NL80211_FREQUENCY_ATTR_NO_IBSS
])
220 print_flag("no IBSS", &open
);
221 if (tb_freq
[NL80211_FREQUENCY_ATTR_RADAR
])
222 print_flag("radar detection", &open
);
229 printf("\t\tBitrates:\n");
231 nla_for_each_nested(nl_rate
, tb_band
[NL80211_BAND_ATTR_RATES
], rem_rate
) {
232 nla_parse(tb_rate
, NL80211_BITRATE_ATTR_MAX
, nla_data(nl_rate
),
233 nla_len(nl_rate
), rate_policy
);
234 if (!tb_rate
[NL80211_BITRATE_ATTR_RATE
])
236 printf("\t\t\t* %2.1f Mbps", 0.1 * nla_get_u32(tb_rate
[NL80211_BITRATE_ATTR_RATE
]));
238 if (tb_rate
[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE
])
239 print_flag("short preamble supported", &open
);
246 if (tb_msg
[NL80211_ATTR_MAX_NUM_SCAN_SSIDS
])
247 printf("\tmax # scan SSIDs: %d\n",
248 nla_get_u8(tb_msg
[NL80211_ATTR_MAX_NUM_SCAN_SSIDS
]));
250 if (!tb_msg
[NL80211_ATTR_SUPPORTED_IFTYPES
])
253 printf("\tSupported interface modes:\n");
254 nla_for_each_nested(nl_mode
, tb_msg
[NL80211_ATTR_SUPPORTED_IFTYPES
], rem_mode
)
255 printf("\t\t * %s\n", iftype_name(nl_mode
->nla_type
));
260 static int handle_info(struct nl80211_state
*state
,
263 int argc
, char **argv
)
265 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_phy_handler
, NULL
);
269 TOPLEVEL(info
, NULL
, NL80211_CMD_GET_WIPHY
, 0, CIB_PHY
, handle_info
,
270 "Show capabilities for the specified wireless device.");
271 TOPLEVEL(list
, NULL
, NL80211_CMD_GET_WIPHY
, NLM_F_DUMP
, CIB_NONE
, handle_info
,
272 "List all wireless devices and their capabilities.");
273 TOPLEVEL(phy
, NULL
, NL80211_CMD_GET_WIPHY
, NLM_F_DUMP
, CIB_NONE
, handle_info
, NULL
);