]>
Commit | Line | Data |
---|---|---|
644fb8c8 JM |
1 | /* |
2 | * wlantest controller | |
3 | * Copyright (c) 2010, Jouni Malinen <j@w1.fi> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * Alternatively, this software may be distributed under the terms of BSD | |
10 | * license. | |
11 | * | |
12 | * See README and COPYING for more details. | |
13 | */ | |
14 | ||
15 | #include "utils/includes.h" | |
16 | #include <sys/un.h> | |
17 | ||
18 | #include "utils/common.h" | |
19 | #include "wlantest_ctrl.h" | |
20 | ||
21 | ||
6f2346c1 JM |
22 | static u8 * attr_get(u8 *buf, size_t buflen, enum wlantest_ctrl_attr attr, |
23 | size_t *len) | |
24 | { | |
25 | u8 *pos = buf; | |
26 | ||
27 | while (pos + 8 <= buf + buflen) { | |
28 | enum wlantest_ctrl_attr a; | |
29 | size_t alen; | |
30 | a = WPA_GET_BE32(pos); | |
31 | pos += 4; | |
32 | alen = WPA_GET_BE32(pos); | |
33 | pos += 4; | |
34 | if (pos + alen > buf + buflen) { | |
35 | printf("Invalid control message attribute\n"); | |
36 | return NULL; | |
37 | } | |
38 | if (a == attr) { | |
39 | *len = alen; | |
40 | return pos; | |
41 | } | |
42 | pos += alen; | |
43 | } | |
44 | ||
45 | return NULL; | |
46 | } | |
47 | ||
48 | ||
49 | static int cmd_send_and_recv(int s, const u8 *cmd, size_t cmd_len, | |
50 | u8 *resp, size_t max_resp_len) | |
644fb8c8 | 51 | { |
644fb8c8 | 52 | int res; |
6f2346c1 | 53 | enum wlantest_ctrl_cmd cmd_resp; |
644fb8c8 | 54 | |
6f2346c1 | 55 | if (send(s, cmd, cmd_len, 0) < 0) |
644fb8c8 | 56 | return -1; |
6f2346c1 | 57 | res = recv(s, resp, max_resp_len, 0); |
644fb8c8 JM |
58 | if (res < 4) |
59 | return -1; | |
60 | ||
6f2346c1 JM |
61 | cmd_resp = WPA_GET_BE32(resp); |
62 | if (cmd_resp == WLANTEST_CTRL_SUCCESS) | |
63 | return res; | |
64 | ||
65 | if (cmd_resp == WLANTEST_CTRL_UNKNOWN_CMD) | |
644fb8c8 | 66 | printf("Unknown command\n"); |
6f2346c1 JM |
67 | else if (cmd_resp == WLANTEST_CTRL_INVALID_CMD) |
68 | printf("Invalid command\n"); | |
644fb8c8 | 69 | |
6f2346c1 JM |
70 | return -1; |
71 | } | |
72 | ||
73 | ||
74 | static int cmd_simple(int s, enum wlantest_ctrl_cmd cmd) | |
75 | { | |
76 | u8 buf[4]; | |
77 | int res; | |
78 | WPA_PUT_BE32(buf, cmd); | |
79 | res = cmd_send_and_recv(s, buf, sizeof(buf), buf, sizeof(buf)); | |
80 | return res < 0 ? -1 : 0; | |
644fb8c8 JM |
81 | } |
82 | ||
83 | ||
84 | static int cmd_ping(int s, int argc, char *argv[]) | |
85 | { | |
6f2346c1 JM |
86 | int res = cmd_simple(s, WLANTEST_CTRL_PING); |
87 | if (res == 0) | |
88 | printf("PONG\n"); | |
89 | return res == 0; | |
644fb8c8 JM |
90 | } |
91 | ||
92 | ||
93 | static int cmd_terminate(int s, int argc, char *argv[]) | |
94 | { | |
95 | return cmd_simple(s, WLANTEST_CTRL_TERMINATE); | |
96 | } | |
97 | ||
98 | ||
6f2346c1 JM |
99 | static int cmd_list_bss(int s, int argc, char *argv[]) |
100 | { | |
101 | u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; | |
102 | u8 buf[4]; | |
103 | u8 *bssid; | |
104 | size_t len; | |
105 | int rlen, i; | |
106 | ||
107 | WPA_PUT_BE32(buf, WLANTEST_CTRL_LIST_BSS); | |
108 | rlen = cmd_send_and_recv(s, buf, sizeof(buf), resp, sizeof(resp)); | |
109 | if (rlen < 0) | |
110 | return -1; | |
111 | ||
112 | bssid = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_BSSID, &len); | |
113 | if (bssid == NULL) | |
114 | return -1; | |
115 | ||
116 | for (i = 0; i < len / ETH_ALEN; i++) | |
117 | printf(MACSTR " ", MAC2STR(bssid + ETH_ALEN * i)); | |
118 | printf("\n"); | |
119 | ||
120 | return 0; | |
121 | } | |
122 | ||
123 | ||
124 | static int cmd_list_sta(int s, int argc, char *argv[]) | |
125 | { | |
126 | u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; | |
127 | u8 buf[100], *pos; | |
128 | u8 *addr; | |
129 | size_t len; | |
130 | int rlen, i; | |
131 | ||
132 | if (argc < 1) { | |
133 | printf("list_sta needs one argument: BSSID\n"); | |
134 | return -1; | |
135 | } | |
136 | ||
137 | pos = buf; | |
138 | WPA_PUT_BE32(pos, WLANTEST_CTRL_LIST_STA); | |
139 | pos += 4; | |
140 | WPA_PUT_BE32(pos, WLANTEST_ATTR_BSSID); | |
141 | pos += 4; | |
142 | WPA_PUT_BE32(pos, ETH_ALEN); | |
143 | pos += 4; | |
144 | if (hwaddr_aton(argv[0], pos) < 0) { | |
145 | printf("Invalid BSSID '%s'\n", argv[0]); | |
146 | return -1; | |
147 | } | |
148 | pos += ETH_ALEN; | |
149 | ||
150 | rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); | |
151 | if (rlen < 0) | |
152 | return -1; | |
153 | ||
154 | addr = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_STA_ADDR, &len); | |
155 | if (addr == NULL) | |
156 | return -1; | |
157 | ||
158 | for (i = 0; i < len / ETH_ALEN; i++) | |
159 | printf(MACSTR " ", MAC2STR(addr + ETH_ALEN * i)); | |
160 | printf("\n"); | |
161 | ||
162 | return 0; | |
163 | } | |
164 | ||
165 | ||
d356bd63 JM |
166 | static int cmd_flush(int s, int argc, char *argv[]) |
167 | { | |
168 | return cmd_simple(s, WLANTEST_CTRL_FLUSH); | |
169 | } | |
170 | ||
171 | ||
644fb8c8 JM |
172 | struct wlantest_cli_cmd { |
173 | const char *cmd; | |
174 | int (*handler)(int s, int argc, char *argv[]); | |
175 | const char *usage; | |
176 | }; | |
177 | ||
178 | static const struct wlantest_cli_cmd wlantest_cli_commands[] = { | |
179 | { "ping", cmd_ping, "= test connection to wlantest" }, | |
180 | { "terminate", cmd_terminate, "= terminate wlantest" }, | |
6f2346c1 JM |
181 | { "list_bss", cmd_list_bss, "= get BSS list" }, |
182 | { "list_sta", cmd_list_sta, "<BSSID> = get STA list" }, | |
d356bd63 | 183 | { "flush", cmd_flush, "= drop all collected BSS data" }, |
644fb8c8 JM |
184 | { NULL, NULL, NULL } |
185 | }; | |
186 | ||
187 | ||
188 | static int ctrl_command(int s, int argc, char *argv[]) | |
189 | { | |
190 | const struct wlantest_cli_cmd *cmd, *match = NULL; | |
191 | int count = 0; | |
192 | int ret = 0; | |
193 | ||
194 | for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) { | |
195 | if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0) | |
196 | { | |
197 | match = cmd; | |
198 | if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { | |
199 | /* exact match */ | |
200 | count = 1; | |
201 | break; | |
202 | } | |
203 | count++; | |
204 | } | |
205 | } | |
206 | ||
207 | if (count > 1) { | |
208 | printf("Ambiguous command '%s'; possible commands:", argv[0]); | |
209 | for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) { | |
210 | if (os_strncasecmp(cmd->cmd, argv[0], | |
211 | os_strlen(argv[0])) == 0) { | |
212 | printf(" %s", cmd->cmd); | |
213 | } | |
644fb8c8 JM |
214 | } |
215 | printf("\n"); | |
216 | ret = 1; | |
217 | } else if (count == 0) { | |
218 | printf("Unknown command '%s'\n", argv[0]); | |
219 | ret = 1; | |
220 | } else { | |
221 | ret = match->handler(s, argc - 1, &argv[1]); | |
222 | } | |
223 | ||
224 | return ret; | |
225 | } | |
226 | ||
227 | ||
228 | int main(int argc, char *argv[]) | |
229 | { | |
230 | int s; | |
231 | struct sockaddr_un addr; | |
232 | int ret = 0; | |
233 | ||
234 | s = socket(AF_UNIX, SOCK_SEQPACKET, 0); | |
235 | if (s < 0) { | |
236 | perror("socket"); | |
237 | return -1; | |
238 | } | |
239 | ||
240 | os_memset(&addr, 0, sizeof(addr)); | |
241 | addr.sun_family = AF_UNIX; | |
242 | os_strlcpy(addr.sun_path + 1, WLANTEST_SOCK_NAME, | |
243 | sizeof(addr.sun_path) - 1); | |
244 | if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { | |
245 | perror("connect"); | |
246 | close(s); | |
247 | return -1; | |
248 | } | |
249 | ||
250 | if (argc > 1) { | |
251 | ret = ctrl_command(s, argc - 1, &argv[1]); | |
252 | if (ret < 0) | |
253 | printf("FAIL\n"); | |
254 | } else { | |
255 | /* TODO: interactive */ | |
256 | } | |
257 | ||
258 | close(s); | |
259 | return ret; | |
260 | } |