nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /*************************************************************************** |
2 | * * |
||
3 | * ########### ########### ########## ########## * |
||
4 | * ############ ############ ############ ############ * |
||
5 | * ## ## ## ## ## ## ## * |
||
6 | * ## ## ## ## ## ## ## * |
||
7 | * ########### #### ###### ## ## ## ## ###### * |
||
8 | * ########### #### # ## ## ## ## # # * |
||
9 | * ## ## ###### ## ## ## ## # # * |
||
10 | * ## ## # ## ## ## ## # # * |
||
11 | * ############ ##### ###### ## ## ## ##### ###### * |
||
12 | * ########### ########### ## ## ## ########## * |
||
13 | * * |
||
14 | * S E C U R E M O B I L E N E T W O R K I N G * |
||
15 | * * |
||
16 | * This file is part of NexMon. * |
||
17 | * * |
||
18 | * Copyright (c) 2016 NexMon Team * |
||
19 | * * |
||
20 | * NexMon is free software: you can redistribute it and/or modify * |
||
21 | * it under the terms of the GNU General Public License as published by * |
||
22 | * the Free Software Foundation, either version 3 of the License, or * |
||
23 | * (at your option) any later version. * |
||
24 | * * |
||
25 | * NexMon is distributed in the hope that it will be useful, * |
||
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
||
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
||
28 | * GNU General Public License for more details. * |
||
29 | * * |
||
30 | * You should have received a copy of the GNU General Public License * |
||
31 | * along with NexMon. If not, see <http://www.gnu.org/licenses/>. * |
||
32 | * * |
||
33 | **************************************************************************/ |
||
34 | |||
35 | #define _XOPEN_SOURCE 700 |
||
36 | |||
37 | #include <stdio.h> |
||
38 | #include <stdlib.h> |
||
39 | #include <argp-extern.h> |
||
40 | #include <string.h> |
||
41 | //#include <byteswap.h> |
||
42 | |||
43 | //#include <types.h> |
||
44 | #include <sys/types.h> |
||
45 | #include <sys/socket.h> |
||
46 | #include <unistd.h> |
||
47 | #include <sys/param.h> // for MIN macro |
||
48 | |||
49 | #include <sys/ioctl.h> |
||
50 | #include <arpa/inet.h> |
||
51 | #ifdef BUILD_ON_RPI |
||
52 | #include <linux/if.h> |
||
53 | #else |
||
54 | #include <net/if.h> |
||
55 | #endif |
||
56 | #include <stdbool.h> |
||
57 | #define TYPEDEF_BOOL |
||
58 | #include <errno.h> |
||
59 | |||
60 | #include <wlcnt.h> |
||
61 | |||
62 | #include <nexioctls.h> |
||
63 | |||
64 | #include <typedefs.h> |
||
65 | #include <bcmwifi_channels.h> |
||
66 | #include <b64.h> |
||
67 | |||
68 | #define HEXDUMP_COLS 16 |
||
69 | |||
70 | #define IPADDR(a,b,c,d) ((d) << 24 | (c) << 16 | (b) << 8 | (a)) |
||
71 | |||
72 | struct nexio { |
||
73 | struct ifreq *ifr; |
||
74 | int sock_rx_ioctl; |
||
75 | int sock_rx_frame; |
||
76 | int sock_tx; |
||
77 | }; |
||
78 | |||
79 | extern int nex_ioctl(struct nexio *nexio, int cmd, void *buf, int len, bool set); |
||
80 | extern struct nexio *nex_init_ioctl(const char *ifname); |
||
81 | extern struct nexio *nex_init_udp(unsigned int securitycookie, unsigned int txip); |
||
82 | extern struct nexio *nex_init_netlink(void); |
||
83 | |||
84 | char *ifname = "en0"; |
||
85 | unsigned char set_monitor = 0; |
||
86 | unsigned char set_monitor_value = 0; |
||
87 | unsigned char get_monitor = 0; |
||
88 | unsigned char set_promisc = 0; |
||
89 | unsigned char set_promisc_value = 0; |
||
90 | unsigned char get_promisc = 0; |
||
91 | unsigned char set_scansuppress = 0; |
||
92 | unsigned char set_scansuppress_value = 0; |
||
93 | unsigned char get_scansuppress = 0; |
||
94 | unsigned char set_securitycookie = 0; |
||
95 | unsigned int set_securitycookie_value = 0; |
||
96 | unsigned char get_securitycookie = 0; |
||
97 | unsigned int use_udp_tunneling = 0; // contains the securtiy cookie |
||
98 | unsigned int txip = IPADDR(192,168,222,255); |
||
99 | unsigned int custom_cmd = 0; |
||
100 | signed char custom_cmd_set = -1; |
||
101 | unsigned int custom_cmd_buf_len = 4; |
||
102 | void *custom_cmd_buf = NULL; |
||
103 | char *custom_cmd_value = NULL; |
||
104 | unsigned char get_chanspec = 0; |
||
105 | unsigned char set_chanspec = 0; |
||
106 | char *set_chanspec_value = NULL; |
||
107 | unsigned char custom_cmd_value_int = false; |
||
108 | unsigned char custom_cmd_value_base64 = false; |
||
109 | unsigned char raw_output = false; |
||
110 | unsigned char base64_output = false; |
||
111 | unsigned int dump_objmem_addr = 0; |
||
112 | unsigned char dump_objmem = false; |
||
113 | unsigned char disassociate = false; |
||
114 | unsigned char dump_wl_cnt = false; |
||
115 | unsigned char revinfo = false; |
||
116 | |||
117 | const char *argp_program_version = "1.0"; |
||
118 | const char *argp_program_bug_address = "<mschulz@seemoo.tu-darmstadt.de>"; |
||
119 | |||
120 | static char doc[] = "nexutil -- a program to control a nexmon firmware for broadcom chips."; |
||
121 | |||
122 | static struct argp_option options[] = { |
||
123 | {"interface-name", 'I', "CHAR", 0, "Set interface name (default: wlan0)"}, |
||
124 | {"monitor", 'm', "INT", OPTION_ARG_OPTIONAL, "Set/Get monitor mode"}, |
||
125 | {"promisc", 'p', "INT", OPTION_ARG_OPTIONAL, "Set/Get promiscuous mode"}, |
||
126 | {"scansuppress", 'c', "INT", OPTION_ARG_OPTIONAL, "Set/Get scan suppress setting to avoid scanning"}, |
||
127 | {"disassociate", 'd', 0, 0, "Disassociate from access point"}, |
||
128 | {"get-custom-cmd", 'g', "INT", 0, "Get custom command, e.g. 107 for WLC_GET_VAR"}, |
||
129 | {"set-custom-cmd", 's', "INT", 0, "Set custom command, e.g. 108 for WLC_SET_VAR"}, |
||
130 | {"custom-cmd-buf-len", 'l', "INT", 0, "Custom command buffer length (default: 4)"}, |
||
131 | {"custom-cmd-value", 'v', "CHAR/INT", 0, "Initialization value for the buffer used by custom command"}, |
||
132 | {"custom-cmd-value-int", 'i', 0, 0, "Define that custom-cmd-value should be interpreted as integer"}, |
||
133 | {"custom-cmd-value-base64", 'b', 0, 0, "Define that custom-cmd-value should be interpreted as base64 string"}, |
||
134 | {"base64-output", 'R', 0, 0, "Write base64 encoded strings to stdout instead of hex dumping"}, |
||
135 | {"raw-output", 'r', 0, 0, "Write raw output to stdout instead of hex dumping"}, |
||
136 | {"dump-wl_cnt", 'w', 0, 0, "Dump WL counters"}, |
||
137 | {"dump-objmem", 'o', "INT", 0, "Dumps objmem at addr INT"}, |
||
138 | {"chanspec", 'k', "CHAR/INT", OPTION_ARG_OPTIONAL, "Set chanspec either as integer (e.g., 0x1001, set -i) or as string (e.g., 64/80)."}, |
||
139 | {"security-cookie", 'x', "INT", OPTION_ARG_OPTIONAL, "Set/Get security cookie"}, |
||
140 | {"use-udp-tunneling", 'X', "INT", 0, "Use UDP tunneling with security cookie INT"}, |
||
141 | {"broadcast-ip", 'B', "CHAR", 0, "Broadcast IP to use for UDP tunneling (default: 192.168.222.255)"}, |
||
142 | {"revinfo", 'V', 0, 0, "Dump revision information of the Wi-Fi chip"}, |
||
143 | { 0 } |
||
144 | }; |
||
145 | |||
146 | static error_t |
||
147 | parse_opt(int key, char *arg, struct argp_state *state) |
||
148 | { |
||
149 | switch (key) { |
||
150 | case 'I': |
||
151 | ifname = arg; |
||
152 | break; |
||
153 | |||
154 | case 'm': |
||
155 | if (arg) { |
||
156 | set_monitor = true; |
||
157 | set_monitor_value = strtol(arg, NULL, 0); |
||
158 | } else { |
||
159 | get_monitor = true; |
||
160 | } |
||
161 | break; |
||
162 | |||
163 | case 'p': |
||
164 | if (arg) { |
||
165 | set_promisc = true; |
||
166 | set_promisc_value = strtol(arg, NULL, 0); |
||
167 | } else { |
||
168 | get_promisc = true; |
||
169 | } |
||
170 | break; |
||
171 | |||
172 | case 'c': |
||
173 | if (arg) { |
||
174 | set_scansuppress = true; |
||
175 | set_scansuppress_value = strtol(arg, NULL, 0); |
||
176 | } else { |
||
177 | get_scansuppress = true; |
||
178 | } |
||
179 | break; |
||
180 | |||
181 | case 'd': |
||
182 | disassociate = true; |
||
183 | break; |
||
184 | |||
185 | case 'g': |
||
186 | custom_cmd_set = false; |
||
187 | custom_cmd = strtol(arg, NULL, 0); |
||
188 | break; |
||
189 | |||
190 | case 's': |
||
191 | custom_cmd_set = true; |
||
192 | custom_cmd = strtol(arg, NULL, 0); |
||
193 | break; |
||
194 | |||
195 | case 'l': |
||
196 | custom_cmd_buf_len = strtol(arg, NULL, 0); |
||
197 | break; |
||
198 | |||
199 | case 'k': |
||
200 | if (arg) { |
||
201 | set_chanspec = true; |
||
202 | set_chanspec_value = arg; |
||
203 | } else { |
||
204 | get_chanspec = true; |
||
205 | } |
||
206 | break; |
||
207 | |||
208 | case 'v': |
||
209 | custom_cmd_value = arg; |
||
210 | break; |
||
211 | |||
212 | case 'i': |
||
213 | if (!custom_cmd_value_base64) |
||
214 | custom_cmd_value_int = true; |
||
215 | else |
||
216 | printf("ERR: you can only either use base64 or integer encoding."); |
||
217 | break; |
||
218 | |||
219 | case 'b': |
||
220 | if (!custom_cmd_value_int) |
||
221 | custom_cmd_value_base64 = true; |
||
222 | else |
||
223 | printf("ERR: you can only either use base64 or integer encoding."); |
||
224 | break; |
||
225 | |||
226 | case 'r': |
||
227 | if (!base64_output) |
||
228 | raw_output = true; |
||
229 | else |
||
230 | printf("ERR: you can only either use base64 or raw output."); |
||
231 | break; |
||
232 | |||
233 | case 'R': |
||
234 | if (!raw_output) |
||
235 | base64_output = true; |
||
236 | else |
||
237 | printf("ERR: you can only either use base64 or raw output."); |
||
238 | break; |
||
239 | |||
240 | case 'o': |
||
241 | dump_objmem_addr = strtol(arg, NULL, 0); |
||
242 | dump_objmem = true; |
||
243 | break; |
||
244 | |||
245 | case 'w': |
||
246 | dump_wl_cnt = true; |
||
247 | break; |
||
248 | |||
249 | case 'x': |
||
250 | if (arg) { |
||
251 | set_securitycookie = true; |
||
252 | set_securitycookie_value = strtol(arg, NULL, 0); |
||
253 | } else { |
||
254 | get_securitycookie = true; |
||
255 | } |
||
256 | break; |
||
257 | |||
258 | case 'X': |
||
259 | if (set_securitycookie == false) { |
||
260 | use_udp_tunneling = strtol(arg, NULL, 0); |
||
261 | if (use_udp_tunneling == 0) |
||
262 | printf("ERR: You need to use a security cookie different from 0."); |
||
263 | } else { |
||
264 | printf("ERR: You cannot use -x in combination with -X."); |
||
265 | } |
||
266 | break; |
||
267 | |||
268 | case 'B': |
||
269 | if (arg) { |
||
270 | txip = inet_addr(arg); |
||
271 | } |
||
272 | break; |
||
273 | |||
274 | case 'V': |
||
275 | revinfo = true; |
||
276 | break; |
||
277 | |||
278 | default: |
||
279 | return ARGP_ERR_UNKNOWN; |
||
280 | } |
||
281 | |||
282 | return 0; |
||
283 | } |
||
284 | |||
285 | static struct argp argp = { options, parse_opt, 0, doc }; |
||
286 | |||
287 | /* source: http://grapsus.net/blog/post/Hexadecimal-dump-in-C */ |
||
288 | void |
||
289 | hexdump(void *mem, unsigned int len) |
||
290 | { |
||
291 | unsigned int i, j; |
||
292 | |||
293 | for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++) { |
||
294 | if (i % HEXDUMP_COLS == 0) { |
||
295 | printf("0x%06x: ", i); |
||
296 | } |
||
297 | |||
298 | if(i < len) { |
||
299 | printf("%02x ", 0xFF & ((char*)mem)[i]); |
||
300 | } else { |
||
301 | printf(" "); |
||
302 | } |
||
303 | |||
304 | if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1)) { |
||
305 | for(j = i - (HEXDUMP_COLS - 1); j <= i; j++) { |
||
306 | if(j >= len) { |
||
307 | putchar(' '); |
||
308 | } else if(isprint(((char*)mem)[j])) { |
||
309 | putchar(0xFF & ((char*)mem)[j]); |
||
310 | } else { |
||
311 | putchar('.'); |
||
312 | } |
||
313 | } |
||
314 | putchar('\n'); |
||
315 | } |
||
316 | } |
||
317 | } |
||
318 | |||
319 | /* Produce a human-readable string for boardrev */ |
||
320 | char * |
||
321 | bcm_brev_str(uint32 brev, char *buf) |
||
322 | { |
||
323 | if (brev < 0x100) |
||
324 | snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); |
||
325 | else |
||
326 | snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff); |
||
327 | |||
328 | return (buf); |
||
329 | } |
||
330 | |||
331 | #define IFNAMSIZ 16 |
||
332 | #pragma pack(4) |
||
333 | struct apple80211req |
||
334 | { |
||
335 | char req_if_name[IFNAMSIZ]; // 16 bytes |
||
336 | int32_t req_type; // 4 bytes |
||
337 | int32_t req_val; // 4 bytes |
||
338 | u_int64_t req_len; // 8 bytes |
||
339 | void *req_data; // 8 bytes |
||
340 | }; |
||
341 | |||
342 | #pragma pack() |
||
343 | |||
344 | #define SIOCSA80211 _IOW( 'i', 200, struct apple80211req ) |
||
345 | #define APPLE80211_IOC_CARD_SPECIFIC 0xffffffff // req_type |
||
346 | |||
347 | //static char ifname2[16] = "en0\0"; |
||
348 | //static int ev_sock = -1; |
||
349 | //static int bpf_fd = -1; |
||
350 | |||
351 | int a80211_getset(uint32_t ioc, uint32_t type, uint32_t valuep, void *data, size_t length) |
||
352 | { |
||
353 | struct apple80211req cmd; |
||
354 | |||
355 | int a80211_sock = socket(AF_INET, SOCK_DGRAM, 0); |
||
356 | if (a80211_sock == -1) { |
||
357 | return -1; |
||
358 | } |
||
359 | |||
360 | bzero(&cmd, sizeof(cmd)); |
||
361 | |||
362 | strncpy(cmd.req_if_name, ifname, 16); |
||
363 | |||
364 | cmd.req_type = type; |
||
365 | cmd.req_val = valuep; |
||
366 | cmd.req_len = (uint32_t) length; |
||
367 | cmd.req_data = data; |
||
368 | |||
369 | int ret = ioctl(a80211_sock, ioc, &cmd, sizeof(cmd)); |
||
370 | |||
371 | valuep = cmd.req_val; |
||
372 | |||
373 | close(a80211_sock); |
||
374 | |||
375 | return ret; |
||
376 | } |
||
377 | |||
378 | int |
||
379 | nex_ioctl(struct nexio *nexio, int cmd, void *buf, int len, bool set) |
||
380 | { |
||
381 | return a80211_getset(SIOCSA80211, APPLE80211_IOC_CARD_SPECIFIC, cmd, buf, len); |
||
382 | } |
||
383 | |||
384 | int |
||
385 | main(int argc, char **argv) |
||
386 | { |
||
387 | struct nexio *nexio; |
||
388 | int ret; |
||
389 | int buf = 0; |
||
390 | |||
391 | argp_parse(&argp, argc, argv, 0, 0, 0); |
||
392 | // get_monitor = true; |
||
393 | //revinfo = true; |
||
394 | |||
395 | // nexio = nex_init_ioctl(ifname); |
||
396 | nexio = 0; |
||
397 | |||
398 | if (set_monitor) { |
||
399 | buf = set_monitor_value; |
||
400 | ret = nex_ioctl(nexio, WLC_SET_MONITOR, &buf, 4, true); |
||
401 | } |
||
402 | |||
403 | if (set_promisc) { |
||
404 | buf = set_promisc_value; |
||
405 | ret = nex_ioctl(nexio, WLC_SET_PROMISC, &buf, 4, true); |
||
406 | } |
||
407 | |||
408 | if (set_scansuppress) { |
||
409 | buf = set_scansuppress_value; |
||
410 | if (set_scansuppress_value) |
||
411 | ret = nex_ioctl(nexio, WLC_SET_SCANSUPPRESS, &buf, 4, true); |
||
412 | else |
||
413 | ret = nex_ioctl(nexio, WLC_SET_SCANSUPPRESS, &buf, 1, true); |
||
414 | } |
||
415 | |||
416 | if (set_securitycookie) { |
||
417 | buf = set_securitycookie_value; |
||
418 | ret = nex_ioctl(nexio, NEX_SET_SECURITYCOOKIE, &buf, 4, true); |
||
419 | } |
||
420 | |||
421 | if (get_monitor) { |
||
422 | ret = nex_ioctl(nexio, WLC_GET_MONITOR, &buf, 4, false); |
||
423 | printf("monitor: %d\n", buf); |
||
424 | } |
||
425 | |||
426 | if (get_promisc) { |
||
427 | ret = nex_ioctl(nexio, WLC_GET_PROMISC, &buf, 4, false); |
||
428 | printf("promisc: %d\n", buf); |
||
429 | } |
||
430 | |||
431 | if (get_scansuppress) { |
||
432 | ret = nex_ioctl(nexio, WLC_GET_SCANSUPPRESS, &buf, 4, false); |
||
433 | printf("scansuppress: %d\n", buf); |
||
434 | } |
||
435 | |||
436 | if (get_securitycookie) { |
||
437 | ret = nex_ioctl(nexio, NEX_GET_SECURITYCOOKIE, &buf, 4, false); |
||
438 | printf("securitycookie: %d\n", buf); |
||
439 | } |
||
440 | |||
441 | if (get_chanspec) { |
||
442 | char charbuf[9] = "chanspec"; |
||
443 | uint16 chanspec = 0; |
||
444 | ret = nex_ioctl(nexio, WLC_GET_VAR, charbuf, 9, false); |
||
445 | chanspec = *(uint16 *) charbuf; |
||
446 | printf("chanspec: 0x%04x, %s\n", chanspec, wf_chspec_ntoa(chanspec, charbuf)); |
||
447 | } |
||
448 | |||
449 | if (set_chanspec) { |
||
450 | char charbuf[13] = "chanspec"; |
||
451 | uint32 *chanspec = (uint32 *) &charbuf[9]; |
||
452 | |||
453 | if (custom_cmd_value_int) |
||
454 | *chanspec = strtoul(set_chanspec_value, NULL, 0); |
||
455 | else |
||
456 | *chanspec = wf_chspec_aton(set_chanspec_value); |
||
457 | |||
458 | if (*chanspec == 0) |
||
459 | printf("invalid chanspec\n"); |
||
460 | else |
||
461 | ret = nex_ioctl(nexio, WLC_SET_VAR, charbuf, 13, true); |
||
462 | } |
||
463 | |||
464 | if (custom_cmd_set != -1) { |
||
465 | custom_cmd_buf = malloc(custom_cmd_buf_len); |
||
466 | if (!custom_cmd_buf) |
||
467 | return -1; |
||
468 | |||
469 | memset(custom_cmd_buf, 0, custom_cmd_buf_len); |
||
470 | |||
471 | if (custom_cmd_set == 1 && raw_output) { // set command using raw input |
||
472 | //freopen(NULL, "rb", stdin); |
||
473 | fread(custom_cmd_buf, 1, custom_cmd_buf_len, stdin); |
||
474 | } else { |
||
475 | if (custom_cmd_value) { |
||
476 | if (custom_cmd_value_int) { |
||
477 | *(uint32 *) custom_cmd_buf = strtoul(custom_cmd_value, NULL, 0); |
||
478 | } else if (custom_cmd_value_base64) { |
||
479 | size_t decoded_len = 0; |
||
480 | unsigned char *decoded = b64_decode_ex(custom_cmd_value, strlen(custom_cmd_value), &decoded_len); |
||
481 | memcpy(custom_cmd_buf, decoded, MIN(decoded_len, custom_cmd_buf_len)); |
||
482 | } else { |
||
483 | strncpy(custom_cmd_buf, custom_cmd_value, custom_cmd_buf_len); |
||
484 | } |
||
485 | } else { |
||
486 | if (custom_cmd_value_int) { |
||
487 | *(uint32 *) custom_cmd_buf = strtoul(custom_cmd_value, NULL, 0); |
||
488 | } |
||
489 | } |
||
490 | } |
||
491 | |||
492 | /* NOTICE: Using SDIO to communicate to the firmware, the maximum CDC message length |
||
493 | * is limited to CDC_MAX_MSG_SIZE = ETHER_MAX_LEN = 1518, however only 1502 bytes |
||
494 | * arrive in the ioctl function, the rest might be used for the ioctl header. |
||
495 | */ |
||
496 | if (custom_cmd_buf_len > 1502 && custom_cmd_set) |
||
497 | fprintf(stderr, "WARN: Using SDIO, the ioctl payload length is limited to 1502 bytes.\n"); |
||
498 | ret = nex_ioctl(nexio, custom_cmd, custom_cmd_buf, custom_cmd_buf_len, custom_cmd_set); |
||
499 | |||
500 | if (custom_cmd_set == false) { |
||
501 | if (raw_output) { |
||
502 | fwrite(custom_cmd_buf, sizeof(char), custom_cmd_buf_len, stdout); |
||
503 | fflush(stdout); |
||
504 | } else if (base64_output) { |
||
505 | char *encoded = b64_encode(custom_cmd_buf, custom_cmd_buf_len); |
||
506 | fwrite(encoded, sizeof(char), strlen(encoded), stdout); |
||
507 | fflush(stdout); |
||
508 | } else { |
||
509 | hexdump(custom_cmd_buf, custom_cmd_buf_len); |
||
510 | } |
||
511 | } |
||
512 | } |
||
513 | |||
514 | if (dump_objmem) { |
||
515 | custom_cmd_buf = malloc(custom_cmd_buf_len); |
||
516 | if (!custom_cmd_buf) |
||
517 | return -1; |
||
518 | |||
519 | memset(custom_cmd_buf, 0, custom_cmd_buf_len); |
||
520 | |||
521 | unsigned int *custom_cmd_buf_pos = (unsigned int *) custom_cmd_buf; |
||
522 | |||
523 | int i = 0; |
||
524 | for (i = 0; i < custom_cmd_buf_len / 0x2000; i++) { |
||
525 | *custom_cmd_buf_pos = dump_objmem_addr + i * 0x2000 / 4; |
||
526 | printf("%08x %08x\n", (int) custom_cmd_buf_pos, *custom_cmd_buf_pos); |
||
527 | ret = nex_ioctl(nexio, 406, custom_cmd_buf_pos, 0x2000, false); |
||
528 | custom_cmd_buf_pos += 0x2000 / 4; |
||
529 | } |
||
530 | if (custom_cmd_buf_len % 0x2000 != 0) { |
||
531 | *(unsigned int *) custom_cmd_buf_pos = dump_objmem_addr + i * 0x2000 / 4; |
||
532 | ret = nex_ioctl(nexio, 406, custom_cmd_buf_pos, custom_cmd_buf_len % 0x2000, false); |
||
533 | } |
||
534 | |||
535 | if (raw_output) { |
||
536 | fwrite(custom_cmd_buf, sizeof(char), custom_cmd_buf_len, stdout); |
||
537 | fflush(stdout); |
||
538 | } else { |
||
539 | hexdump(custom_cmd_buf, custom_cmd_buf_len); |
||
540 | } |
||
541 | } |
||
542 | |||
543 | if (disassociate) { |
||
544 | buf = 1; |
||
545 | ret = nex_ioctl(nexio, WLC_DISASSOC, &buf, 4, true); |
||
546 | } |
||
547 | |||
548 | if (dump_wl_cnt) { |
||
549 | wl_cnt_t cnt; |
||
550 | wl_cnt_t *_cnt = &cnt; |
||
551 | memset(_cnt, 0, sizeof(cnt)); |
||
552 | ret = nex_ioctl(nexio, NEX_GET_WL_CNT, _cnt, sizeof(cnt), false); |
||
553 | unsigned int i; |
||
554 | printf("version: %d\n", _cnt->version); |
||
555 | printf("length: %d\n", _cnt->length); |
||
556 | for (i = 1; i < sizeof(cnt)/4; i++) { |
||
557 | printf("%s: %d (%s)\n", wl_cnt_varname[i], ((uint32 *) _cnt)[i], wl_cnt_description[i]); |
||
558 | } |
||
559 | //hexdump(_cnt, sizeof(_cnt)); |
||
560 | } |
||
561 | |||
562 | if (revinfo) { |
||
563 | typedef struct wlc_rev_info { |
||
564 | uint vendorid; /* PCI vendor id */ |
||
565 | uint deviceid; /* device id of chip */ |
||
566 | uint radiorev; /* radio revision */ |
||
567 | uint chiprev; /* chip revision */ |
||
568 | uint corerev; /* core revision */ |
||
569 | uint boardid; /* board identifier (usu. PCI sub-device id) */ |
||
570 | uint boardvendor; /* board vendor (usu. PCI sub-vendor id) */ |
||
571 | uint boardrev; /* board revision */ |
||
572 | uint driverrev; /* driver version */ |
||
573 | uint ucoderev; /* microcode version */ |
||
574 | uint bus; /* bus type */ |
||
575 | uint chipnum; /* chip number */ |
||
576 | uint phytype; /* phy type */ |
||
577 | uint phyrev; /* phy revision */ |
||
578 | uint anarev; /* anacore rev */ |
||
579 | uint chippkg; /* chip package info */ |
||
580 | uint nvramrev; /* nvram revision number */ |
||
581 | } wlc_rev_info_t; |
||
582 | |||
583 | char b[8]; |
||
584 | char str[17][32] = { {0} }; |
||
585 | wlc_rev_info_t revinfo; |
||
586 | |||
587 | memset(&revinfo, 0, sizeof(revinfo)); |
||
588 | |||
589 | ret = nex_ioctl(nexio, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), false); |
||
590 | |||
591 | snprintf(str[0], sizeof(str[0]), "0x%x", revinfo.vendorid); |
||
592 | snprintf(str[1], sizeof(str[0]), "0x%x", revinfo.deviceid); |
||
593 | snprintf(str[2], sizeof(str[0]), "0x%x", revinfo.radiorev); |
||
594 | snprintf(str[3], sizeof(str[0]), "0x%x", revinfo.chipnum); |
||
595 | snprintf(str[4], sizeof(str[0]), "0x%x", revinfo.chiprev); |
||
596 | snprintf(str[5], sizeof(str[0]), "0x%x", revinfo.chippkg); |
||
597 | snprintf(str[6], sizeof(str[0]), "0x%x", revinfo.corerev); |
||
598 | snprintf(str[7], sizeof(str[0]), "0x%x", revinfo.boardid); |
||
599 | snprintf(str[8], sizeof(str[0]), "0x%x", revinfo.boardvendor); |
||
600 | snprintf(str[9], sizeof(str[0]), "%s", bcm_brev_str(revinfo.boardrev, b)); |
||
601 | snprintf(str[10], sizeof(str[0]), "0x%x", revinfo.driverrev); |
||
602 | snprintf(str[11], sizeof(str[0]), "0x%x", revinfo.ucoderev); |
||
603 | snprintf(str[12], sizeof(str[0]), "0x%x", revinfo.bus); |
||
604 | snprintf(str[13], sizeof(str[0]), "0x%x", revinfo.phytype); |
||
605 | snprintf(str[14], sizeof(str[0]), "0x%x", revinfo.phyrev); |
||
606 | snprintf(str[15], sizeof(str[0]), "0x%x", revinfo.anarev); |
||
607 | snprintf(str[16], sizeof(str[0]), "0x%x", revinfo.nvramrev); |
||
608 | |||
609 | printf("vendorid %s\n", str[0]); |
||
610 | printf("deviceid %s\n", str[1]); |
||
611 | printf("radiorev %s\n", str[2]); |
||
612 | printf("chipnum %s\n", str[3]); |
||
613 | printf("chiprev %s\n", str[4]); |
||
614 | printf("chippackage %s\n", str[5]); |
||
615 | printf("corerev %s\n", str[6]); |
||
616 | printf("boardid %s\n", str[7]); |
||
617 | printf("boardvendor %s\n", str[8]); |
||
618 | printf("boardrev %s\n", str[9]); |
||
619 | printf("driverrev %s\n", str[10]); |
||
620 | printf("ucoderev %s\n", str[11]); |
||
621 | printf("bus %s\n", str[12]); |
||
622 | printf("phytype %s\n", str[13]); |
||
623 | printf("phyrev %s\n", str[14]); |
||
624 | printf("anarev %s\n", str[15]); |
||
625 | printf("nvramrev %s\n", str[16]); |
||
626 | |||
627 | printf("\n"); |
||
628 | printf("vendorid | deviceid | radiorev | chipnum | chiprev | chippackage | corerev | boardid | boardvendor | boardrev | driverrev | ucoderev | bus | phytype | phyrev | anarev | nvramrev\n"); |
||
629 | printf("-------- | -------- | ---------- | ------- | ------- | ----------- | ------- | ------- | ----------- | -------- | --------- | --------- | --- | ------- | ------ | ------ | --------\n"); |
||
630 | printf("%8s | %8s | %10s | %7s | %7s | %11s | %7s | %7s | %11s | %8s | %9s | %9s | %3s | %7s | %6s | %6s | %8s\n", |
||
631 | str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7], str[8], str[9], str[10], str[11], str[12], str[13], str[14], str[15], str[16]); |
||
632 | } |
||
633 | |||
634 | return 0; |
||
635 | } |