2 * wprobe-test.c: Wireless probe user space test code
3 * Copyright (C) 2008-2009 Felix Fietkau <nbd@openwrt.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <sys/types.h>
17 #include <sys/socket.h>
19 #include <arpa/inet.h>
33 #include <linux/wprobe.h>
36 static bool simple_mode = false;
39 wprobe_dump_value(struct wprobe_attribute *attr)
43 #define HANDLE_TYPE(_type, _format) \
44 case WPROBE_VAL_##_type: \
45 snprintf(buf, sizeof(buf), _format, attr->val._type); \
49 HANDLE_TYPE(S8, "%d");
50 HANDLE_TYPE(S16, "%d");
51 HANDLE_TYPE(S32, "%d");
52 HANDLE_TYPE(S64, "%lld");
53 HANDLE_TYPE(U8, "%d");
54 HANDLE_TYPE(U16, "%d");
55 HANDLE_TYPE(U32, "%d");
56 HANDLE_TYPE(U64, "%lld");
57 case WPROBE_VAL_STRING:
58 /* FIXME: implement this */
60 strncpy(buf, "<unknown>", sizeof(buf));
63 if ((attr->flags & WPROBE_F_KEEPSTAT) &&
65 int len = strlen(buf);
67 snprintf(buf + len, sizeof(buf) - len, ";%.02f;%.02f;%d;%lld;%lld", attr->val.avg, attr->val.stdev, attr->val.n, attr->val.s, attr->val.ss);
69 snprintf(buf + len, sizeof(buf) - len, " (avg: %.02f; stdev: %.02f, n=%d)", attr->val.avg, attr->val.stdev, attr->val.n);
78 wprobe_dump_data(struct wprobe_iface *dev)
80 struct wprobe_attribute *attr;
81 struct wprobe_link *link;
85 fprintf(stdout, "\n");
86 wprobe_request_data(dev, NULL);
87 list_for_each_entry(attr, &dev->global_attr, list) {
90 fprintf(stdout, "[global]\n");
91 fprintf(stdout, "%s=%s\n", attr->name, wprobe_dump_value(attr));
93 fprintf(stdout, (first ?
97 wprobe_dump_value(attr)
103 list_for_each_entry(link, &dev->links, list) {
105 wprobe_request_data(dev, link->addr);
106 list_for_each_entry(attr, &dev->link_attr, list) {
110 "[%02x:%02x:%02x:%02x:%02x:%02x]\n%s=%s\n" :
111 "%02x:%02x:%02x:%02x:%02x:%02x: %s=%s\n"),
112 link->addr[0], link->addr[1], link->addr[2],
113 link->addr[3], link->addr[4], link->addr[5],
115 wprobe_dump_value(attr));
119 (simple_mode ? "%s=%s\n" :
122 wprobe_dump_value(attr));
129 static const char *attr_typestr[] = {
131 [WPROBE_VAL_STRING] = "String",
132 [WPROBE_VAL_U8] = "Unsigned 8 bit",
133 [WPROBE_VAL_U16] = "Unsigned 16 bit",
134 [WPROBE_VAL_U32] = "Unsigned 32 bit",
135 [WPROBE_VAL_U64] = "Unsigned 64 bit",
136 [WPROBE_VAL_S8] = "Signed 8 bit",
137 [WPROBE_VAL_S16] = "Signed 16 bit",
138 [WPROBE_VAL_S32] = "Signed 32 bit",
139 [WPROBE_VAL_S64] = "Signed 64 bit",
142 static int usage(const char *prog)
145 #ifndef NO_LOCAL_ACCESS
146 "Usage: %s <interface>|<host>:<device>|-P [options]\n"
148 "Usage: %s <host>:<device> [options]\n"
152 " -a: Print attributes\n"
153 " -c: Only apply configuration\n"
154 " -d: Delay between measurement dumps (in milliseconds, default: 1000)\n"
155 " A value of 0 (zero) prints once and exits; useful for scripts\n"
156 " -f: Dump contents of layer 2 filter counters during measurement\n"
157 " -F <file>: Apply layer 2 filters from <file>\n"
158 " -h: This help text\n"
159 " -i <interval>: Set measurement interval\n"
160 " -m: Run measurement loop\n"
161 " -p: Set the TCP port for server/client (default: 17990)\n"
162 #ifndef NO_LOCAL_ACCESS
163 " -P: Run in proxy mode (listen on network)\n"
170 static void show_attributes(struct wprobe_iface *dev)
172 struct wprobe_attribute *attr;
175 list_for_each_entry(attr, &dev->global_attr, list) {
176 fprintf(stdout, "Global attribute: '%s' (%s)\n",
177 attr->name, attr_typestr[attr->type]);
179 list_for_each_entry(attr, &dev->link_attr, list) {
180 fprintf(stdout, "Link attribute: '%s' (%s)\n",
181 attr->name, attr_typestr[attr->type]);
185 static void show_filter_simple(void *arg, const char *group, struct wprobe_filter_item *items, int n_items)
189 fprintf(stdout, "[filter:%s]\n", group);
190 for (i = 0; i < n_items; i++) {
191 fprintf(stdout, "%s=%lld;%lld\n",
192 items[i].name, items[i].tx, items[i].rx);
198 static void show_filter(void *arg, const char *group, struct wprobe_filter_item *items, int n_items)
201 fprintf(stdout, "Filter group: '%s' (tx/rx)\n", group);
202 for (i = 0; i < n_items; i++) {
203 fprintf(stdout, " - %s (%lld/%lld)\n",
204 items[i].name, items[i].tx, items[i].rx);
208 static void loop_measurement(struct wprobe_iface *dev, bool print_filters, unsigned long delay)
211 wprobe_update_links(dev);
212 wprobe_dump_data(dev);
214 wprobe_dump_filters(dev, simple_mode ? show_filter_simple : show_filter, NULL);
215 usleep(delay * 1000);
220 static void set_filter(struct wprobe_iface *dev, const char *filename)
222 unsigned char *buf = NULL;
223 unsigned int buflen = 0;
224 unsigned int len = 0;
228 if (filename[0] == 0) {
229 dev->filter_len = -1;
233 fd = open(filename, O_RDONLY);
235 perror("open filter");
248 buf = realloc(buf, buflen);
250 rlen = read(fd, buf + len, buflen - len);
255 } while (len == buflen);
258 dev->filter_len = len;
262 #ifndef NO_LOCAL_ACCESS
264 static void sigchld_handler(int s)
266 while (waitpid(-1, NULL, WNOHANG) > 0);
269 static int run_proxy(int port)
271 struct sockaddr_in sa;
272 struct sigaction sig;
276 s = socket(AF_INET, SOCK_STREAM, 0);
282 sig.sa_handler = sigchld_handler; // Signal Handler fuer Zombie Prozesse
283 sigemptyset(&sig.sa_mask);
284 sig.sa_flags = SA_RESTART;
285 sigaction(SIGCHLD, &sig, NULL);
287 memset(&sa, 0, sizeof(sa));
288 sa.sin_family = AF_INET;
289 sa.sin_addr.s_addr = htonl(INADDR_ANY);
290 sa.sin_port = htons(wprobe_port);
292 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
293 if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
302 unsigned int addrlen = sizeof(struct sockaddr_in);
305 c = accept(s, (struct sockaddr *)&sa, &addrlen);
314 /* close server socket, stdin, stdout, stderr */
320 wprobe_server_init(c);
322 ret = wprobe_server_handle(c);
324 wprobe_server_done();
335 int main(int argc, char **argv)
337 struct wprobe_iface *dev = NULL;
339 const char *prog = argv[0];
347 const char *filter = NULL;
348 bool print_attributes = false;
349 bool print_filters = false;
350 unsigned long delay = 1000;
357 #ifndef NO_LOCAL_ACCESS
358 if (!strcmp(argv[1], "-P")) {
359 while ((ch = getopt(argc - 1, argv + 1, "p:")) != -1) {
363 wprobe_port = strtoul(optarg, NULL, 0);
369 return run_proxy(wprobe_port);
373 if (argv[1][0] == '-')
380 while ((ch = getopt(argc, argv, "acd:fF:hi:msp:")) != -1) {
383 print_attributes = true;
389 delay = strtoul(optarg, NULL, 10);
395 interval = strtoul(optarg, NULL, 10);
398 print_filters = true;
402 fprintf(stderr, "Cannot set multiple filters\n");
412 wprobe_port = strtoul(optarg, NULL, 0);
421 dev = wprobe_get_auto(ifname, &err);
422 if (!dev || (list_empty(&dev->global_attr) &&
423 list_empty(&dev->link_attr))) {
425 fprintf(stdout, "%s\n", err);
427 fprintf(stderr, "Interface '%s' not found\n", ifname);
431 if (filter || interval >= 0) {
433 set_filter(dev, filter);
435 dev->interval = interval;
437 wprobe_apply_config(dev);
440 if (cmd != CMD_CONFIG) {
441 if (print_attributes)
442 show_attributes(dev);
444 if (cmd == CMD_MEASURE)
445 loop_measurement(dev, print_filters, delay);
447 wprobe_free_dev(dev);