2 * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 * redistribution must be conditioned upon including a substantially
14 * similar Disclaimer requirement for further binary redistribution.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGES.
29 * $FreeBSD: src/tools/tools/net80211/wlanwatch/wlanwatch.c,v 1.6 2008/05/19 17:51:00 thompsa Exp $
33 * Monitor 802.11 events using a routing socket.
34 * Code liberaly swiped from route(8).
36 #include <sys/param.h>
38 #include <sys/socket.h>
39 #include <sys/ioctl.h>
40 #include <sys/sysctl.h>
41 #include <sys/types.h>
44 #include <net/route.h>
45 #include <net/if_dl.h>
46 #include <netinet/in.h>
47 #include <netinet/if_ether.h>
48 #include <netproto/802_11/ieee80211_dragonfly.h>
49 #include <arpa/inet.h>
64 enum ieee80211_notify_cac_event {
65 IEEE80211_NOTIFY_CAC_START = 0, /* CAC timer started */
66 IEEE80211_NOTIFY_CAC_STOP = 1, /* CAC intentionally stopped */
67 IEEE80211_NOTIFY_CAC_RADAR = 2, /* CAC stopped due to radar detectio */
68 IEEE80211_NOTIFY_CAC_EXPIRE = 3, /* CAC expired w/o radar */
71 static void print_rtmsg(struct rt_msghdr *rtm, int msglen);
76 main(int argc, char *argv[])
81 s = socket(PF_ROUTE, SOCK_RAW, 0);
83 err(EX_OSERR, "socket");
85 n = read(s, msg, 2048);
86 print_rtmsg((struct rt_msghdr *)msg, n);
92 bprintf(FILE *fp, int b, char *s)
99 while ((i = *s++) != 0) {
100 if (b & (1 << (i-1))) {
107 for (; (i = *s) > 32; s++)
118 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
121 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
122 "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
123 "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
124 "\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
126 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
127 "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
128 "\017LINK2\020MULTICAST";
130 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
133 routename(struct sockaddr *sa)
136 static char line[MAXHOSTNAMELEN + 1];
138 static char domain[MAXHOSTNAMELEN + 1];
139 static int first = 1, n;
143 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
144 (cp = strchr(domain, '.'))) {
145 domain[MAXHOSTNAMELEN] = '\0';
146 (void) strcpy(domain, cp + 1);
152 strcpy(line, "default");
153 else switch (sa->sa_family) {
157 in = ((struct sockaddr_in *)sa)->sin_addr;
160 if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
162 if (cp == NULL && !nflag) {
163 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
166 if ((cp = strchr(hp->h_name, '.')) &&
167 !strcmp(cp + 1, domain))
173 strncpy(line, cp, sizeof(line) - 1);
174 line[sizeof(line) - 1] = '\0';
176 (void) sprintf(line, "%s", inet_ntoa(in));
183 struct sockaddr_in6 sin6; /* use static var for safety */
185 #ifdef NI_WITHSCOPEID
186 niflags = NI_WITHSCOPEID;
189 memset(&sin6, 0, sizeof(sin6));
190 memcpy(&sin6, sa, sa->sa_len);
191 sin6.sin6_len = sizeof(struct sockaddr_in6);
192 sin6.sin6_family = AF_INET6;
194 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
195 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
196 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
197 sin6.sin6_scope_id == 0) {
199 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
200 sin6.sin6_addr.s6_addr[2] = 0;
201 sin6.sin6_addr.s6_addr[3] = 0;
205 niflags |= NI_NUMERICHOST;
206 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
207 line, sizeof(line), NULL, 0, niflags) != 0)
208 strncpy(line, "invalid", sizeof(line));
215 return (link_ntoa((struct sockaddr_dl *)sa));
218 { u_short *s = (u_short *)sa;
219 u_short *slim = s + ((sa->sa_len + 1) >> 1);
220 char *cp = line + sprintf(line, "(%d)", sa->sa_family);
221 char *cpe = line + sizeof(line);
223 while (++s < slim && cp < cpe) /* start with sa->sa_data */
224 if ((n = snprintf(cp, cpe - cp, " %x", *s)) > 0)
235 pmsg_addrs(char *cp, int addrs)
241 (void) putchar('\n');
244 printf("\nsockaddrs: ");
245 bprintf(stdout, addrs, addrnames);
247 for (i = 1; i; i <<= 1)
249 sa = (struct sockaddr *)cp;
250 printf(" %s", routename(sa));
257 ether_sprintf(const uint8_t mac[6])
261 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
262 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
267 print_rtmsg(struct rt_msghdr *rtm, int msglen)
269 struct if_msghdr *ifm;
270 struct if_announcemsghdr *ifan;
271 time_t now = time(NULL);
272 char *cnow = ctime(&now);
274 if (rtm->rtm_version != RTM_VERSION) {
275 (void) printf("routing message version %d not understood\n",
279 switch (rtm->rtm_type) {
281 ifm = (struct if_msghdr *)rtm;
282 printf("%.19s RTM_IFINFO: if# %d, ",
283 cnow, ifm->ifm_index);
284 switch (ifm->ifm_data.ifi_link_state) {
285 case LINK_STATE_DOWN:
286 printf("link: down, flags:");
289 printf("link: up, flags:");
292 printf("link: unknown<%d>, flags:",
293 ifm->ifm_data.ifi_link_state);
296 bprintf(stdout, ifm->ifm_flags, ifnetflags);
297 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
301 ifan = (struct if_announcemsghdr *)rtm;
302 printf("%.19s RTM_IFANNOUNCE: if# %d, what: ",
303 cnow, ifan->ifan_index);
304 switch (ifan->ifan_what) {
312 printf("#%d", ifan->ifan_what);
319 #define V(type) ((struct type *)(&ifan[1]))
320 ifan = (struct if_announcemsghdr *)rtm;
321 printf("%.19s RTM_IEEE80211: if# %d, ", cnow, ifan->ifan_index);
322 switch (ifan->ifan_what) {
323 case RTM_IEEE80211_ASSOC:
324 printf("associate with %s",
325 ether_sprintf(V(ieee80211_join_event)->iev_addr));
327 case RTM_IEEE80211_REASSOC:
328 printf("reassociate with %s",
329 ether_sprintf(V(ieee80211_join_event)->iev_addr));
331 case RTM_IEEE80211_DISASSOC:
332 printf("disassociate");
334 case RTM_IEEE80211_JOIN:
335 case RTM_IEEE80211_REJOIN:
336 printf("%s station %sjoin",
337 ether_sprintf(V(ieee80211_join_event)->iev_addr),
338 ifan->ifan_what == RTM_IEEE80211_REJOIN ? "re" : ""
341 case RTM_IEEE80211_LEAVE:
342 printf("%s station leave",
343 ether_sprintf(V(ieee80211_leave_event)->iev_addr));
345 case RTM_IEEE80211_SCAN:
346 printf("scan complete");
348 case RTM_IEEE80211_REPLAY:
349 printf("replay failure: src %s "
350 , ether_sprintf(V(ieee80211_replay_event)->iev_src)
352 printf("dst %s cipher %u keyix %u keyrsc %llu rsc %llu"
353 , ether_sprintf(V(ieee80211_replay_event)->iev_dst)
354 , V(ieee80211_replay_event)->iev_cipher
355 , V(ieee80211_replay_event)->iev_keyix
356 , V(ieee80211_replay_event)->iev_keyrsc
357 , V(ieee80211_replay_event)->iev_rsc
360 case RTM_IEEE80211_MICHAEL:
361 printf("michael failure: src %s "
362 , ether_sprintf(V(ieee80211_michael_event)->iev_src)
364 printf("dst %s cipher %u keyix %u"
365 , ether_sprintf(V(ieee80211_michael_event)->iev_dst)
366 , V(ieee80211_michael_event)->iev_cipher
367 , V(ieee80211_michael_event)->iev_keyix
370 case RTM_IEEE80211_WDS:
371 printf("%s wds discovery",
372 ether_sprintf(V(ieee80211_wds_event)->iev_addr));
374 case RTM_IEEE80211_CSA:
375 printf("channel switch announcement: channel %u (%u MHz flags 0x%x) mode %d count %d"
376 , V(ieee80211_csa_event)->iev_ieee
377 , V(ieee80211_csa_event)->iev_freq
378 , V(ieee80211_csa_event)->iev_flags
379 , V(ieee80211_csa_event)->iev_mode
380 , V(ieee80211_csa_event)->iev_count
383 case RTM_IEEE80211_CAC:
384 printf("channel availability check "
385 "(channel %u, %u MHz flags 0x%x) "
386 , V(ieee80211_cac_event)->iev_ieee
387 , V(ieee80211_cac_event)->iev_freq
388 , V(ieee80211_cac_event)->iev_flags
390 switch (V(ieee80211_cac_event)->iev_type) {
391 case IEEE80211_NOTIFY_CAC_START:
392 printf("start timer");
394 case IEEE80211_NOTIFY_CAC_STOP:
395 printf("stop timer");
397 case IEEE80211_NOTIFY_CAC_EXPIRE:
398 printf("timer expired");
400 case IEEE80211_NOTIFY_CAC_RADAR:
401 printf("radar detected");
404 printf("unknown type %d",
405 V(ieee80211_cac_event)->iev_type);
409 case RTM_IEEE80211_DEAUTH:
410 printf("%s wds deauth",
411 ether_sprintf(V(ieee80211_deauth_event)->iev_addr));
413 case RTM_IEEE80211_AUTH:
414 printf("%s node authenticate",
415 ether_sprintf(V(ieee80211_auth_event)->iev_addr));
417 case RTM_IEEE80211_COUNTRY:
418 printf("%s adopt country code '%c%c'",
419 ether_sprintf(V(ieee80211_country_event)->iev_addr),
420 V(ieee80211_country_event)->iev_cc[0],
421 V(ieee80211_country_event)->iev_cc[1]);
423 case RTM_IEEE80211_RADIO:
425 V(ieee80211_radio_event)->iev_state ? "ON" : "OFF");
428 printf("what: #%d", ifan->ifan_what);