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