1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org>
5 * Copyright (c) 2025 The FreeBSD Foundation
6 *
7 * Portions of this software were developed by Tom Jones <thj@FreeBSD.org>
8 * under sponsorship from the FreeBSD Foundation.
9 */
10
11 #include <sys/param.h>
12 #include <sys/systm.h>
13 #include <net/ethernet.h>
14
15 #include <net80211/ieee80211.h>
16
17 #define le32_to_cpup(_a_) (le32toh(*(const uint32_t *)(_a_)))
18
19 #include <dev/iwx/if_iwxreg.h>
20 #include <dev/iwx/if_iwx_debug.h>
21
22 static int print_codes[][2] = {
23 #if 0
24 for example:
25 IWX_LEGACY_GROUP, IWX_ADD_STA_KEY,
26 IWX_LEGACY_GROUP, IWX_SCD_QUEUE_CONFIG_CMD,
27 IWX_LEGACY_GROUP, IWX_ADD_STA,
28 IWX_LEGACY_GROUP, IWX_REMOVE_STA,
29 #endif
30 };
31
32 struct opcode_label {
33 uint8_t opcode;
34 const char *label;
35 };
36
37 static struct opcode_label command_group[] = {
38 { 0x0, "IWX_LEGACY_GROUP"},
39 { 0x1, "IWX_LONG_GROUP"},
40 { 0x2, "IWX_SYSTEM_GROUP"},
41 { 0x3, "IWX_MAC_CONF_GROUP"},
42 { 0x4, "IWX_PHY_OPS_GROUP"},
43 { 0x5, "IWX_DATA_PATH_GROUP"},
44 { 0xb, "IWX_PROT_OFFLOAD_GROUP"},
45 { 0xc, "IWX_REGULATORY_AND_NVM_GROUP"},
46 { 0, NULL }
47 };
48
49 static struct opcode_label legacy_opcodes[] = {
50 { 0xc0, "IWX_REPLY_RX_PHY_CMD" },
51 { 0xc1, "IWX_REPLY_RX_MPDU_CMD" },
52 { 0xc2, "IWX_BAR_FRAME_RELEASE" },
53 { 0xc3, "IWX_FRAME_RELEASE" },
54 { 0xc5, "IWX_BA_NOTIF" },
55 { 0x62, "IWX_TEMPERATURE_NOTIFICATION" },
56 { 0xc8, "IWX_MCC_UPDATE_CMD" },
57 { 0xc9, "IWX_MCC_CHUB_UPDATE_CMD" },
58 { 0x65, "IWX_CALIBRATION_CFG_CMD" },
59 { 0x66, "IWX_CALIBRATION_RES_NOTIFICATION" },
60 { 0x67, "IWX_CALIBRATION_COMPLETE_NOTIFICATION" },
61 { 0x68, "IWX_RADIO_VERSION_NOTIFICATION" },
62 { 0x00, "IWX_CMD_DTS_MEASUREMENT_TRIGGER_WIDE" },
63 { 0x01, "IWX_SOC_CONFIGURATION_CMD" },
64 { 0x02, "IWX_REPLY_ERROR" },
65 { 0x03, "IWX_CTDP_CONFIG_CMD" },
66 { 0x04, "IWX_INIT_COMPLETE_NOTIF" },
67 { 0x05, "IWX_SESSION_PROTECTION_CMD" },
68 { 0x5d, "IWX_BT_COEX_CI" },
69 { 0x07, "IWX_FW_ERROR_RECOVERY_CMD" },
70 { 0x08, "IWX_RLC_CONFIG_CMD" },
71 { 0xd0, "IWX_MCAST_FILTER_CMD" },
72 { 0xd1, "IWX_REPLY_SF_CFG_CMD" },
73 { 0xd2, "IWX_REPLY_BEACON_FILTERING_CMD" },
74 { 0xd3, "IWX_D3_CONFIG_CMD" },
75 { 0xd4, "IWX_PROT_OFFLOAD_CONFIG_CMD" },
76 { 0xd5, "IWX_OFFLOADS_QUERY_CMD" },
77 { 0xd6, "IWX_REMOTE_WAKE_CONFIG_CMD" },
78 { 0x77, "IWX_POWER_TABLE_CMD" },
79 { 0x78, "IWX_PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION" },
80 { 0xcc, "IWX_BT_COEX_PRIO_TABLE" },
81 { 0xcd, "IWX_BT_COEX_PROT_ENV" },
82 { 0xce, "IWX_BT_PROFILE_NOTIFICATION" },
83 { 0x6a, "IWX_PHY_CONFIGURATION_CMD" },
84 { 0x16, "IWX_RX_BAID_ALLOCATION_CONFIG_CMD" },
85 { 0x17, "IWX_ADD_STA_KEY" },
86 { 0x18, "IWX_ADD_STA" },
87 { 0x19, "IWX_REMOVE_STA" },
88 { 0xe0, "IWX_WOWLAN_PATTERNS" },
89 { 0xe1, "IWX_WOWLAN_CONFIGURATION" },
90 { 0xe2, "IWX_WOWLAN_TSC_RSC_PARAM" },
91 { 0xe3, "IWX_WOWLAN_TKIP_PARAM" },
92 { 0xe4, "IWX_WOWLAN_KEK_KCK_MATERIAL" },
93 { 0xe5, "IWX_WOWLAN_GET_STATUSES" },
94 { 0xe6, "IWX_WOWLAN_TX_POWER_PER_DB" },
95 { 0x0f, "IWX_SCAN_COMPLETE_UMAC" },
96 { 0x88, "IWX_NVM_ACCESS_CMD" },
97 { 0x20, "IWX_WEP_KEY" },
98 { 0xdc, "IWX_CMD_DTS_MEASUREMENT_TRIGGER" },
99 { 0xdd, "IWX_DTS_MEASUREMENT_NOTIFICATION" },
100 { 0x28, "IWX_MAC_CONTEXT_CMD" },
101 { 0x29, "IWX_TIME_EVENT_CMD" },
102 { 0x01, "IWX_ALIVE" },
103 { 0xf0, "IWX_REPLY_DEBUG_CMD" },
104 { 0x90, "IWX_BEACON_NOTIFICATION" },
105 { 0xf5, "IWX_RX_NO_DATA_NOTIF" },
106 { 0x08, "IWX_PHY_CONTEXT_CMD" },
107 { 0x91, "IWX_BEACON_TEMPLATE_CMD" },
108 { 0xf6, "IWX_THERMAL_DUAL_CHAIN_REQUEST" },
109 { 0x09, "IWX_DBG_CFG" },
110 { 0xf7, "IWX_DEBUG_LOG_MSG" },
111 { 0x1c, "IWX_TX_CMD" },
112 { 0x1d, "IWX_SCD_QUEUE_CFG" },
113 { 0x1e, "IWX_TXPATH_FLUSH" },
114 { 0x1f, "IWX_MGMT_MCAST_KEY" },
115 { 0x98, "IWX_TX_ANT_CONFIGURATION_CMD" },
116 { 0xee, "IWX_LTR_CONFIG" },
117 { 0x8e, "IWX_SET_CALIB_DEFAULT_CMD" },
118 { 0xFE, "IWX_CT_KILL_NOTIFICATION" },
119 { 0xFF, "IWX_DTS_MEASUREMENT_NOTIF_WIDE" },
120 { 0x2a, "IWX_TIME_EVENT_NOTIFICATION" },
121 { 0x2b, "IWX_BINDING_CONTEXT_CMD" },
122 { 0x2c, "IWX_TIME_QUOTA_CMD" },
123 { 0x2d, "IWX_NON_QOS_TX_COUNTER_CMD" },
124 { 0xa0, "IWX_CARD_STATE_CMD" },
125 { 0xa1, "IWX_CARD_STATE_NOTIFICATION" },
126 { 0xa2, "IWX_MISSED_BEACONS_NOTIFICATION" },
127 { 0x0c, "IWX_SCAN_CFG_CMD" },
128 { 0x0d, "IWX_SCAN_REQ_UMAC" },
129 { 0xfb, "IWX_SESSION_PROTECTION_NOTIF" },
130 { 0x0e, "IWX_SCAN_ABORT_UMAC" },
131 { 0xfe, "IWX_PNVM_INIT_COMPLETE" },
132 { 0xa9, "IWX_MAC_PM_POWER_TABLE" },
133 { 0xff, "IWX_FSEQ_VER_MISMATCH_NOTIFICATION | IWX_REPLY_MAX" },
134 { 0x9b, "IWX_BT_CONFIG" },
135 { 0x9c, "IWX_STATISTICS_CMD" },
136 { 0x9d, "IWX_STATISTICS_NOTIFICATION" },
137 { 0x9f, "IWX_REDUCE_TX_POWER_CMD" },
138 { 0xb1, "IWX_MFUART_LOAD_NOTIFICATION" },
139 { 0xb5, "IWX_SCAN_ITERATION_COMPLETE_UMAC" },
140 { 0x54, "IWX_NET_DETECT_CONFIG_CMD" },
141 { 0x56, "IWX_NET_DETECT_PROFILES_QUERY_CMD" },
142 { 0x57, "IWX_NET_DETECT_PROFILES_CMD" },
143 { 0x58, "IWX_NET_DETECT_HOTSPOTS_CMD" },
144 { 0x59, "IWX_NET_DETECT_HOTSPOTS_QUERY_CMD" },
145 { 0, NULL }
146 };
147
148 /* SYSTEM_GROUP group subcommand IDs */
149 static struct opcode_label system_opcodes[] = {
150 { 0x00, "IWX_SHARED_MEM_CFG_CMD" },
151 { 0x01, "IWX_SOC_CONFIGURATION_CMD" },
152 { 0x03, "IWX_INIT_EXTENDED_CFG_CMD" },
153 { 0x07, "IWX_FW_ERROR_RECOVERY_CMD" },
154 { 0xff, "IWX_FSEQ_VER_MISMATCH_NOTIFICATION | IWX_REPLY_MAX" },
155 { 0, NULL }
156 };
157
158 /* MAC_CONF group subcommand IDs */
159 static struct opcode_label macconf_opcodes[] = {
160 { 0x05, "IWX_SESSION_PROTECTION_CMD" },
161 { 0xfb, "IWX_SESSION_PROTECTION_NOTIF" },
162 { 0, NULL }
163 };
164
165 /* DATA_PATH group subcommand IDs */
166 static struct opcode_label data_opcodes[] = {
167 { 0x00, "IWX_DQA_ENABLE_CMD" },
168 { 0x08, "IWX_RLC_CONFIG_CMD" },
169 { 0x0f, "IWX_TLC_MNG_CONFIG_CMD" },
170 { 0x16, "IWX_RX_BAID_ALLOCATION_CONFIG_CMD" },
171 { 0x17, "IWX_SCD_QUEUE_CONFIG_CMD" },
172 { 0xf5, "IWX_RX_NO_DATA_NOTIF" },
173 { 0xf6, "IWX_THERMAL_DUAL_CHAIN_REQUEST" },
174 { 0xf7, "IWX_TLC_MNG_UPDATE_NOTIF" },
175 { 0, NULL }
176 };
177
178 /* REGULATORY_AND_NVM group subcommand IDs */
179 static struct opcode_label reg_opcodes[] = {
180 { 0x00, "IWX_NVM_ACCESS_COMPLETE" },
181 { 0x02, "IWX_NVM_GET_INFO " },
182 { 0xfe, "IWX_PNVM_INIT_COMPLETE" },
183 { 0, NULL }
184 };
185
186 /* PHY_OPS subcommand IDs */
187 static struct opcode_label phyops_opcodes[] = {
188 {0x00, "IWX_CMD_DTS_MEASUREMENT_TRIGGER_WIDE"},
189 {0x03, "IWX_CTDP_CONFIG_CMD"},
190 {0x04, "IWX_TEMP_REPORTING_THRESHOLDS_CMD"},
191 {0xFE, "IWX_CT_KILL_NOTIFICATION"},
192 {0xFF, "IWX_DTS_MEASUREMENT_NOTIF_WIDE"},
193 };
194
195 static const char *
get_label(struct opcode_label * table,uint8_t opcode)196 get_label(struct opcode_label *table, uint8_t opcode)
197 {
198 struct opcode_label *op = table;
199 while(op->label != NULL) {
200 if (op->opcode == opcode)
201 return op->label;
202 op++;
203 }
204 return "NOT FOUND IN TABLE";
205 }
206
207 static struct opcode_label *
get_table(uint8_t group)208 get_table(uint8_t group)
209 {
210 switch (group)
211 {
212 case IWX_LEGACY_GROUP:
213 case IWX_LONG_GROUP:
214 return legacy_opcodes;
215 break;
216 case IWX_SYSTEM_GROUP:
217 return system_opcodes;
218 break;
219 case IWX_MAC_CONF_GROUP:
220 return macconf_opcodes;
221 break;
222 case IWX_DATA_PATH_GROUP:
223 return data_opcodes;
224 break;
225 case IWX_REGULATORY_AND_NVM_GROUP:
226 return reg_opcodes;
227 break;
228 case IWX_PHY_OPS_GROUP:
229 return phyops_opcodes;
230 break;
231 case IWX_PROT_OFFLOAD_GROUP:
232 break;
233 }
234 return NULL;
235 }
236
237 void
print_opcode(const char * func,int line,uint32_t code)238 print_opcode(const char *func, int line, uint32_t code)
239 {
240 int print = 0;
241 uint8_t opcode = iwx_cmd_opcode(code);
242 uint8_t group = iwx_cmd_groupid(code);
243
244 struct opcode_label *table = get_table(group);
245 if (table == NULL) {
246 printf("Couldn't find opcode table for 0x%08x", code);
247 return;
248 }
249
250 for (int i = 0; i < nitems(print_codes); i++)
251 if (print_codes[i][0] == group && print_codes[i][1] == opcode)
252 print = 1;
253
254 if (print) {
255 printf("%s:%d \t%s\t%s\t(0x%08x)\n", func, line,
256 get_label(command_group, group),
257 get_label(table, opcode), code);
258 }
259 }
260
261 void
print_ratenflags(const char * func,int line,uint32_t flags,int ver)262 print_ratenflags(const char *func, int line, uint32_t flags, int ver)
263 {
264 printf("%s:%d\n\t flags 0x%08x ", func, line, flags);
265
266 if (ver >= 2) {
267 printf(" rate_n_flags version 2\n");
268
269 uint32_t type = (flags & IWX_RATE_MCS_MOD_TYPE_MSK) >> IWX_RATE_MCS_MOD_TYPE_POS;
270
271 switch(type)
272 {
273 case 0:
274 printf("\t(0) Legacy CCK: ");
275 switch (flags & IWX_RATE_LEGACY_RATE_MSK)
276 {
277 case 0:
278 printf("(0) 0xa - 1 Mbps\n");
279 break;
280 case 1:
281 printf("(1) 0x14 - 2 Mbps\n");
282 break;
283 case 2:
284 printf("(2) 0x37 - 5.5 Mbps\n");
285 break;
286 case 3:
287 printf("(3) 0x6e - 11 nbps\n");
288 break;
289 }
290 break;
291 case 1:
292 printf("\t(1) Legacy OFDM \n");
293 switch (flags & IWX_RATE_LEGACY_RATE_MSK)
294 {
295 case 0:
296 printf("(0) 6 Mbps\n");
297 break;
298 case 1:
299 printf("(1) 9 Mbps\n");
300 break;
301 case 2:
302 printf("(2) 12 Mbps\n");
303 break;
304 case 3:
305 printf("(3) 18 Mbps\n");
306 break;
307 case 4:
308 printf("(4) 24 Mbps\n");
309 break;
310 case 5:
311 printf("(5) 36 Mbps\n");
312 break;
313 case 6:
314 printf("(6) 48 Mbps\n");
315 break;
316 case 7:
317 printf("(7) 54 Mbps\n");
318 break;
319 }
320 break;
321 case 2:
322 printf("\t(2) High-throughput (HT)\n");
323 break;
324 case 3:
325 printf("\t(3) Very High-throughput (VHT) \n");
326 break;
327 case 4:
328 printf("\t(4) High-efficiency (HE)\n");
329 break;
330 case 5:
331 printf("\t(5) Extremely High-throughput (EHT)\n");
332 break;
333 default:
334 printf("invalid\n");
335 }
336
337 /* Not a legacy rate. */
338 if (type > 1) {
339 printf("\tMCS %d ", IWX_RATE_HT_MCS_INDEX(flags));
340 switch((flags & IWX_RATE_MCS_CHAN_WIDTH_MSK) >> IWX_RATE_MCS_CHAN_WIDTH_POS)
341 {
342 case 0:
343 printf("20MHz ");
344 break;
345 case 1:
346 printf("40MHz ");
347 break;
348 case 2:
349 printf("80MHz ");
350 break;
351 case 3:
352 printf("160MHz ");
353 break;
354 case 4:
355 printf("320MHz ");
356 break;
357
358 }
359 printf("antennas: (%s|%s) ",
360 flags & (1 << 14) ? "A" : " ",
361 flags & (1 << 15) ? "B" : " ");
362 if (flags & (1 << 16))
363 printf("ldpc ");
364 printf("\n");
365 }
366 } else {
367 printf("%s:%d rate_n_flags versions other than < 2 not implemented",
368 __func__, __LINE__);
369 }
370 }
371