2 * Copyright (c) 2002, 2003 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.
15 * 3. Neither the names of the above-listed copyright holders nor the names
16 * of any contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
19 * Alternatively, this software may be distributed under the terms of the
20 * GNU General Public License ("GPL") version 2 as published by the Free
21 * Software Foundation.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
28 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
29 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34 * THE POSSIBILITY OF SUCH DAMAGES.
40 * Monitor 802.11 events using a routing socket.
41 * Code liberaly swiped from route(8).
43 #include <sys/param.h>
45 #include <sys/socket.h>
46 #include <sys/ioctl.h>
47 #include <sys/sysctl.h>
48 #include <sys/types.h>
51 #include <net/route.h>
52 #include <net/if_dl.h>
53 #include <netinet/in.h>
54 #include <netinet/if_ether.h>
55 #include <netatalk/at.h>
57 #include <net80211/ieee80211_netbsd.h>
59 #include <net80211/ieee80211_freebsd.h>
61 #error "No support for your operating system!"
63 #include <arpa/inet.h>
77 static void print_rtmsg(struct rt_msghdr *rtm, int msglen);
82 main(int argc, char *argv[])
87 s = socket(PF_ROUTE, SOCK_RAW, 0);
89 err(EX_OSERR, "socket");
91 n = read(s, msg, 2048);
92 print_rtmsg((struct rt_msghdr *)msg, n);
108 while ((i = *s++) != 0) {
109 if (b & (1 << (i-1))) {
116 for (; (i = *s) > 32; s++)
127 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
130 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
131 "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
132 "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
133 "\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
135 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
136 "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
137 "\017LINK2\020MULTICAST";
139 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
146 static char line[MAXHOSTNAMELEN + 1];
148 static char domain[MAXHOSTNAMELEN + 1];
149 static int first = 1, n;
153 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
154 (cp = strchr(domain, '.'))) {
155 domain[MAXHOSTNAMELEN] = '\0';
156 (void) strcpy(domain, cp + 1);
162 strcpy(line, "default");
163 else switch (sa->sa_family) {
167 in = ((struct sockaddr_in *)sa)->sin_addr;
170 if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
172 if (cp == 0 && !nflag) {
173 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
176 if ((cp = strchr(hp->h_name, '.')) &&
177 !strcmp(cp + 1, domain))
183 strncpy(line, cp, sizeof(line) - 1);
184 line[sizeof(line) - 1] = '\0';
186 (void) sprintf(line, "%s", inet_ntoa(in));
193 struct sockaddr_in6 sin6; /* use static var for safety */
195 #ifdef NI_WITHSCOPEID
196 niflags = NI_WITHSCOPEID;
199 memset(&sin6, 0, sizeof(sin6));
200 memcpy(&sin6, sa, sa->sa_len);
201 sin6.sin6_len = sizeof(struct sockaddr_in6);
202 sin6.sin6_family = AF_INET6;
204 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
205 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
206 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
207 sin6.sin6_scope_id == 0) {
209 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
210 sin6.sin6_addr.s6_addr[2] = 0;
211 sin6.sin6_addr.s6_addr[3] = 0;
215 niflags |= NI_NUMERICHOST;
216 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
217 line, sizeof(line), NULL, 0, niflags) != 0)
218 strncpy(line, "invalid", sizeof(line));
225 return (link_ntoa((struct sockaddr_dl *)sa));
228 { u_short *s = (u_short *)sa;
229 u_short *slim = s + ((sa->sa_len + 1) >> 1);
230 char *cp = line + sprintf(line, "(%d)", sa->sa_family);
231 char *cpe = line + sizeof(line);
233 while (++s < slim && cp < cpe) /* start with sa->sa_data */
234 if ((n = snprintf(cp, cpe - cp, " %x", *s)) > 0)
246 * This macro returns the size of a struct sockaddr when passed
247 * through a routing socket. Basically we round up sa_len to
248 * a multiple of sizeof(long), with a minimum of sizeof(long).
249 * The check for a NULL pointer is just a convenience, probably never used.
250 * The case sa_len == 0 should only apply to empty structures.
252 #define SA_SIZE(sa) \
253 ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
255 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
259 pmsg_addrs(char *cp, int addrs)
265 (void) putchar('\n');
268 printf("\nsockaddrs: ");
269 bprintf(stdout, addrs, addrnames);
271 for (i = 1; i; i <<= 1)
273 sa = (struct sockaddr *)cp;
274 printf(" %s", routename(sa));
282 ether_sprintf(const uint8_t mac[6])
286 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
287 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
292 print_rtmsg(struct rt_msghdr *rtm, int msglen)
294 struct if_msghdr *ifm;
295 struct if_announcemsghdr *ifan;
297 time_t now = time(NULL);
298 char *cnow = ctime(&now);
300 if (rtm->rtm_version != RTM_VERSION) {
301 (void) printf("routing message version %d not understood\n",
305 switch (rtm->rtm_type) {
307 ifm = (struct if_msghdr *)rtm;
308 printf("%.19s RTM_IFINFO: if# %d, ",
309 cnow, ifm->ifm_index);
310 switch (ifm->ifm_data.ifi_link_state) {
311 case LINK_STATE_DOWN:
321 printf("link: %s, flags:", state);
322 bprintf(stdout, ifm->ifm_flags, ifnetflags);
323 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
326 ifan = (struct if_announcemsghdr *)rtm;
327 printf("%.19s RTM_IFANNOUNCE: if# %d, what: ",
328 cnow, ifan->ifan_index);
329 switch (ifan->ifan_what) {
337 printf("#%d", ifan->ifan_what);
343 #define V(type) ((struct type *)(&ifan[1]))
344 ifan = (struct if_announcemsghdr *)rtm;
345 printf("%.19s RTM_IEEE80211: ", cnow);
346 switch (ifan->ifan_what) {
347 case RTM_IEEE80211_ASSOC:
348 printf("associate with %s",
349 ether_sprintf(V(ieee80211_join_event)->iev_addr));
351 case RTM_IEEE80211_REASSOC:
352 printf("reassociate with %s",
353 ether_sprintf(V(ieee80211_join_event)->iev_addr));
355 case RTM_IEEE80211_DISASSOC:
356 printf("disassociate");
358 case RTM_IEEE80211_JOIN:
359 case RTM_IEEE80211_REJOIN:
360 printf("%s station %sjoin",
361 ether_sprintf(V(ieee80211_join_event)->iev_addr),
362 ifan->ifan_what == RTM_IEEE80211_REJOIN ? "re" : ""
365 case RTM_IEEE80211_LEAVE:
366 printf("%s station leave",
367 ether_sprintf(V(ieee80211_leave_event)->iev_addr));
369 case RTM_IEEE80211_SCAN:
370 printf("scan complete");
372 case RTM_IEEE80211_REPLAY:
373 printf("replay failure: src %s "
374 , ether_sprintf(V(ieee80211_replay_event)->iev_src)
376 printf("dst %s cipher %u keyix %u keyrsc %llu rsc %llu"
377 , ether_sprintf(V(ieee80211_replay_event)->iev_dst)
378 , V(ieee80211_replay_event)->iev_cipher
379 , V(ieee80211_replay_event)->iev_keyix
380 , V(ieee80211_replay_event)->iev_keyrsc
381 , V(ieee80211_replay_event)->iev_rsc
384 case RTM_IEEE80211_MICHAEL:
385 printf("michael failure: src %s "
386 , ether_sprintf(V(ieee80211_michael_event)->iev_src)
388 printf("dst %s cipher %u keyix %u"
389 , ether_sprintf(V(ieee80211_michael_event)->iev_dst)
390 , V(ieee80211_michael_event)->iev_cipher
391 , V(ieee80211_michael_event)->iev_keyix
395 printf("if# %d, what: #%d",
396 ifan->ifan_index, ifan->ifan_what);