]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - tools/tools/net80211/wlanwatch/wlanwatch.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / tools / tools / net80211 / wlanwatch / wlanwatch.c
1 /*-
2  * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
15  *
16  * NO WARRANTY
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.
28  *
29  * $FreeBSD$
30  */
31
32 /*
33  * Monitor 802.11 events using a routing socket.
34  * Code liberaly swiped from route(8).
35  */
36 #include <sys/param.h>
37 #include <sys/file.h>
38 #include <sys/socket.h>
39 #include <sys/ioctl.h>
40 #include <sys/sysctl.h>
41 #include <sys/types.h>
42
43 #include <net/if.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 <netatalk/at.h>
49 #ifdef __NetBSD__
50 #include <net80211/ieee80211_netbsd.h>
51 #elif __FreeBSD__
52 #include <net80211/ieee80211_freebsd.h>
53 #else
54 #error  "No support for your operating system!"
55 #endif
56 #include <arpa/inet.h>
57 #include <netdb.h>
58
59 #include <ctype.h>
60 #include <err.h>
61 #include <errno.h>
62 #include <paths.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <sysexits.h>
67 #include <unistd.h>
68 #include <ifaddrs.h>
69
70 /* XXX */
71 enum ieee80211_notify_cac_event {
72         IEEE80211_NOTIFY_CAC_START  = 0, /* CAC timer started */
73         IEEE80211_NOTIFY_CAC_STOP   = 1, /* CAC intentionally stopped */
74         IEEE80211_NOTIFY_CAC_RADAR  = 2, /* CAC stopped due to radar detectio */
75         IEEE80211_NOTIFY_CAC_EXPIRE = 3, /* CAC expired w/o radar */
76 };
77
78 static  void print_rtmsg(struct rt_msghdr *rtm, int msglen);
79
80 int     nflag = 0;
81
82 int
83 main(int argc, char *argv[])
84 {
85         int n, s;
86         char msg[2048];
87
88         s = socket(PF_ROUTE, SOCK_RAW, 0);
89         if (s < 0)
90                 err(EX_OSERR, "socket");
91         for(;;) {
92                 n = read(s, msg, 2048);
93                 print_rtmsg((struct rt_msghdr *)msg, n);
94         }
95         return 0;
96 }
97
98 static void
99 bprintf(FILE *fp, int b, char *s)
100 {
101         int i;
102         int gotsome = 0;
103
104         if (b == 0)
105                 return;
106         while ((i = *s++) != 0) {
107                 if (b & (1 << (i-1))) {
108                         if (gotsome == 0)
109                                 i = '<';
110                         else
111                                 i = ',';
112                         (void) putc(i, fp);
113                         gotsome = 1;
114                         for (; (i = *s) > 32; s++)
115                                 (void) putc(i, fp);
116                 } else
117                         while (*s > 32)
118                                 s++;
119         }
120         if (gotsome)
121                 putc('>', fp);
122 }
123
124 char metricnames[] =
125 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
126 "\1mtu";
127 char routeflags[] =
128 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
129 "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
130 "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
131 "\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
132 char ifnetflags[] =
133 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
134 "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
135 "\017LINK2\020MULTICAST";
136 char addrnames[] =
137 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
138
139 static const char *
140 routename(struct sockaddr *sa)
141 {
142         char *cp;
143         static char line[MAXHOSTNAMELEN + 1];
144         struct hostent *hp;
145         static char domain[MAXHOSTNAMELEN + 1];
146         static int first = 1, n;
147
148         if (first) {
149                 first = 0;
150                 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
151                     (cp = strchr(domain, '.'))) {
152                         domain[MAXHOSTNAMELEN] = '\0';
153                         (void) strcpy(domain, cp + 1);
154                 } else
155                         domain[0] = 0;
156         }
157
158         if (sa->sa_len == 0)
159                 strcpy(line, "default");
160         else switch (sa->sa_family) {
161
162         case AF_INET:
163             {   struct in_addr in;
164                 in = ((struct sockaddr_in *)sa)->sin_addr;
165
166                 cp = 0;
167                 if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
168                         cp = "default";
169                 if (cp == 0 && !nflag) {
170                         hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
171                                 AF_INET);
172                         if (hp) {
173                                 if ((cp = strchr(hp->h_name, '.')) &&
174                                     !strcmp(cp + 1, domain))
175                                         *cp = 0;
176                                 cp = hp->h_name;
177                         }
178                 }
179                 if (cp) {
180                         strncpy(line, cp, sizeof(line) - 1);
181                         line[sizeof(line) - 1] = '\0';
182                 } else
183                         (void) sprintf(line, "%s", inet_ntoa(in));
184                 break;
185             }
186
187 #ifdef INET6
188         case AF_INET6:
189         {
190                 struct sockaddr_in6 sin6; /* use static var for safety */
191                 int niflags = 0;
192 #ifdef NI_WITHSCOPEID
193                 niflags = NI_WITHSCOPEID;
194 #endif
195
196                 memset(&sin6, 0, sizeof(sin6));
197                 memcpy(&sin6, sa, sa->sa_len);
198                 sin6.sin6_len = sizeof(struct sockaddr_in6);
199                 sin6.sin6_family = AF_INET6;
200 #ifdef __KAME__
201                 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
202                     (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
203                      IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
204                     sin6.sin6_scope_id == 0) {
205                         sin6.sin6_scope_id =
206                             ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
207                         sin6.sin6_addr.s6_addr[2] = 0;
208                         sin6.sin6_addr.s6_addr[3] = 0;
209                 }
210 #endif
211                 if (nflag)
212                         niflags |= NI_NUMERICHOST;
213                 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
214                     line, sizeof(line), NULL, 0, niflags) != 0)
215                         strncpy(line, "invalid", sizeof(line));
216
217                 return(line);
218         }
219 #endif
220
221         case AF_LINK:
222                 return (link_ntoa((struct sockaddr_dl *)sa));
223
224         default:
225             {   u_short *s = (u_short *)sa;
226                 u_short *slim = s + ((sa->sa_len + 1) >> 1);
227                 char *cp = line + sprintf(line, "(%d)", sa->sa_family);
228                 char *cpe = line + sizeof(line);
229
230                 while (++s < slim && cp < cpe) /* start with sa->sa_data */
231                         if ((n = snprintf(cp, cpe - cp, " %x", *s)) > 0)
232                                 cp += n;
233                         else
234                                 *cp = '\0';
235                 break;
236             }
237         }
238         return (line);
239 }
240
241 #ifndef SA_SIZE
242 /*
243  * This macro returns the size of a struct sockaddr when passed
244  * through a routing socket. Basically we round up sa_len to
245  * a multiple of sizeof(long), with a minimum of sizeof(long).
246  * The check for a NULL pointer is just a convenience, probably never used.
247  * The case sa_len == 0 should only apply to empty structures.
248  */
249 #define SA_SIZE(sa)                                             \
250     (  (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?      \
251         sizeof(long)            :                               \
252         1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
253 #endif
254
255 static void
256 pmsg_addrs(char *cp, int addrs)
257 {
258         struct sockaddr *sa;
259         int i;
260
261         if (addrs == 0) {
262                 (void) putchar('\n');
263                 return;
264         }
265         printf("\nsockaddrs: ");
266         bprintf(stdout, addrs, addrnames);
267         putchar('\n');
268         for (i = 1; i; i <<= 1)
269                 if (i & addrs) {
270                         sa = (struct sockaddr *)cp;
271                         printf(" %s", routename(sa));
272                         cp += SA_SIZE(sa);
273                 }
274         putchar('\n');
275 }
276
277 static const char *
278 ether_sprintf(const uint8_t mac[6])
279 {
280         static char buf[32];
281
282         snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
283                 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
284         return buf;
285 }
286
287 static void
288 print_rtmsg(struct rt_msghdr *rtm, int msglen)
289 {
290         struct if_msghdr *ifm;
291         struct if_announcemsghdr *ifan;
292         time_t now = time(NULL);
293         char *cnow = ctime(&now);
294
295         if (rtm->rtm_version != RTM_VERSION) {
296                 (void) printf("routing message version %d not understood\n",
297                     rtm->rtm_version);
298                 return;
299         }
300         switch (rtm->rtm_type) {
301         case RTM_IFINFO:
302                 ifm = (struct if_msghdr *)rtm;
303                 printf("%.19s RTM_IFINFO: if# %d, ",
304                         cnow, ifm->ifm_index);
305                 switch (ifm->ifm_data.ifi_link_state) {
306                 case LINK_STATE_DOWN:
307                         printf("link: down, flags:");
308                         break;
309                 case LINK_STATE_UP:
310                         printf("link: up, flags:");
311                         break;
312                 default:
313                         printf("link: unknown<%d>, flags:",
314                             ifm->ifm_data.ifi_link_state);
315                         break;
316                 }
317                 bprintf(stdout, ifm->ifm_flags, ifnetflags);
318                 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
319                 fflush(stdout);
320                 break;
321         case RTM_IFANNOUNCE:
322                 ifan = (struct if_announcemsghdr *)rtm;
323                 printf("%.19s RTM_IFANNOUNCE: if# %d, what: ",
324                         cnow, ifan->ifan_index);
325                 switch (ifan->ifan_what) {
326                 case IFAN_ARRIVAL:
327                         printf("arrival");
328                         break;
329                 case IFAN_DEPARTURE:
330                         printf("departure");
331                         break;
332                 default:
333                         printf("#%d", ifan->ifan_what);
334                         break;
335                 }
336                 printf("\n");
337                 fflush(stdout);
338                 break;
339         case RTM_IEEE80211:
340 #define V(type) ((struct type *)(&ifan[1]))
341                 ifan = (struct if_announcemsghdr *)rtm;
342                 printf("%.19s RTM_IEEE80211: if# %d, ", cnow, ifan->ifan_index);
343                 switch (ifan->ifan_what) {
344                 case RTM_IEEE80211_ASSOC:
345                         printf("associate with %s",
346                             ether_sprintf(V(ieee80211_join_event)->iev_addr));
347                         break;
348                 case RTM_IEEE80211_REASSOC:
349                         printf("reassociate with %s",
350                             ether_sprintf(V(ieee80211_join_event)->iev_addr));
351                         break;
352                 case RTM_IEEE80211_DISASSOC:
353                         printf("disassociate");
354                         break;
355                 case RTM_IEEE80211_JOIN:
356                 case RTM_IEEE80211_REJOIN:
357                         printf("%s station %sjoin",
358                             ether_sprintf(V(ieee80211_join_event)->iev_addr),
359                             ifan->ifan_what == RTM_IEEE80211_REJOIN ? "re" : ""
360                         );
361                         break;
362                 case RTM_IEEE80211_LEAVE:
363                         printf("%s station leave",
364                             ether_sprintf(V(ieee80211_leave_event)->iev_addr));
365                         break;
366                 case RTM_IEEE80211_SCAN:
367                         printf("scan complete");
368                         break;
369                 case RTM_IEEE80211_REPLAY:
370                         printf("replay failure: src %s "
371                             , ether_sprintf(V(ieee80211_replay_event)->iev_src)
372                         );
373                         printf("dst %s cipher %u keyix %u keyrsc %llu rsc %llu"
374                             , ether_sprintf(V(ieee80211_replay_event)->iev_dst)
375                             , V(ieee80211_replay_event)->iev_cipher
376                             , V(ieee80211_replay_event)->iev_keyix
377                             , V(ieee80211_replay_event)->iev_keyrsc
378                             , V(ieee80211_replay_event)->iev_rsc
379                         );
380                         break;
381                 case RTM_IEEE80211_MICHAEL:
382                         printf("michael failure: src %s "
383                             , ether_sprintf(V(ieee80211_michael_event)->iev_src)
384                         );
385                         printf("dst %s cipher %u keyix %u"
386                             , ether_sprintf(V(ieee80211_michael_event)->iev_dst)
387                             , V(ieee80211_michael_event)->iev_cipher
388                             , V(ieee80211_michael_event)->iev_keyix
389                         );
390                         break;
391                 case RTM_IEEE80211_WDS:
392                         printf("%s wds discovery",
393                             ether_sprintf(V(ieee80211_wds_event)->iev_addr));
394                         break;
395                 case RTM_IEEE80211_CSA:
396                         printf("channel switch announcement: channel %u (%u MHz flags 0x%x) mode %d count %d"
397                             , V(ieee80211_csa_event)->iev_ieee
398                             , V(ieee80211_csa_event)->iev_freq
399                             , V(ieee80211_csa_event)->iev_flags
400                             , V(ieee80211_csa_event)->iev_mode
401                             , V(ieee80211_csa_event)->iev_count
402                         );
403                         break;
404                 case RTM_IEEE80211_CAC:
405                         printf("channel availability check "
406                             "(channel %u, %u MHz flags 0x%x) "
407                             , V(ieee80211_cac_event)->iev_ieee
408                             , V(ieee80211_cac_event)->iev_freq
409                             , V(ieee80211_cac_event)->iev_flags
410                         );
411                         switch (V(ieee80211_cac_event)->iev_type) {
412                         case IEEE80211_NOTIFY_CAC_START:
413                                 printf("start timer");
414                                 break;
415                         case IEEE80211_NOTIFY_CAC_STOP:
416                                 printf("stop timer");
417                                 break;
418                         case IEEE80211_NOTIFY_CAC_EXPIRE:
419                                 printf("timer expired");
420                                 break;
421                         case IEEE80211_NOTIFY_CAC_RADAR:
422                                 printf("radar detected");
423                                 break;
424                         default:
425                                 printf("unknown type %d",
426                                    V(ieee80211_cac_event)->iev_type);
427                                 break;
428                         }
429                         break;
430                 case RTM_IEEE80211_DEAUTH:
431                         printf("%s wds deauth",
432                             ether_sprintf(V(ieee80211_deauth_event)->iev_addr));
433                         break;
434                 case RTM_IEEE80211_AUTH:
435                         printf("%s node authenticate",
436                             ether_sprintf(V(ieee80211_auth_event)->iev_addr));
437                         break;
438                 case RTM_IEEE80211_COUNTRY:
439                         printf("%s adopt country code '%c%c'",
440                             ether_sprintf(V(ieee80211_country_event)->iev_addr),
441                             V(ieee80211_country_event)->iev_cc[0],
442                             V(ieee80211_country_event)->iev_cc[1]);
443                         break;
444                 case RTM_IEEE80211_RADIO:
445                         printf("radio %s",
446                             V(ieee80211_radio_event)->iev_state ? "ON" : "OFF");
447                         break;
448                 default:
449                         printf("what: #%d", ifan->ifan_what);
450                         break;
451                 }
452                 printf("\n");
453                 fflush(stdout);
454                 break;
455 #undef V
456         }
457 }