1151214Swpaul/*- 2151214Swpaul * Copyright (c) 2005 3151214Swpaul * Bill Paul <wpaul@windriver.com>. All rights reserved. 4151214Swpaul * 5151214Swpaul * Redistribution and use in source and binary forms, with or without 6151214Swpaul * modification, are permitted provided that the following conditions 7151214Swpaul * are met: 8151214Swpaul * 1. Redistributions of source code must retain the above copyright 9151214Swpaul * notice, this list of conditions and the following disclaimer. 10151214Swpaul * 2. Redistributions in binary form must reproduce the above copyright 11151214Swpaul * notice, this list of conditions and the following disclaimer in the 12151214Swpaul * documentation and/or other materials provided with the distribution. 13151214Swpaul * 3. All advertising materials mentioning features or use of this software 14151214Swpaul * must display the following acknowledgement: 15151214Swpaul * This product includes software developed by Bill Paul. 16151214Swpaul * 4. Neither the name of the author nor the names of any co-contributors 17151214Swpaul * may be used to endorse or promote products derived from this software 18151214Swpaul * without specific prior written permission. 19151214Swpaul * 20151214Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21151214Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22151214Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23151214Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24151214Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25151214Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26151214Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27151214Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28151214Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29151214Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30151214Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 31151214Swpaul */ 32151214Swpaul 33151214Swpaul#include <sys/cdefs.h> 34151214Swpaul__FBSDID("$FreeBSD: releng/11.0/usr.sbin/wpa/ndis_events/ndis_events.c 281143 2015-04-06 09:42:23Z glebius $"); 35151214Swpaul 36151214Swpaul/* 37151214Swpaul * This program simulates the behavior of the ndis_events utility 38151214Swpaul * supplied with wpa_supplicant for Windows. The original utility 39151214Swpaul * is designed to translate Windows WMI events. We don't have WMI, 40151214Swpaul * but we need to supply certain event info to wpa_supplicant in 41151214Swpaul * order to make WPA2 work correctly, so we fake up the interface. 42151214Swpaul */ 43151214Swpaul 44151214Swpaul#include <sys/types.h> 45151214Swpaul#include <sys/param.h> 46151214Swpaul#include <sys/socket.h> 47151214Swpaul#include <sys/ioctl.h> 48151214Swpaul#include <sys/errno.h> 49151214Swpaul#include <sys/sysctl.h> 50151214Swpaul#include <net/if.h> 51151214Swpaul#include <net/if_dl.h> 52151214Swpaul 53151214Swpaul#include <netinet/in.h> 54151214Swpaul#include <arpa/inet.h> 55151214Swpaul#include <netdb.h> 56151214Swpaul#include <net/route.h> 57151214Swpaul 58151214Swpaul#include <stdio.h> 59151214Swpaul#include <string.h> 60151214Swpaul#include <stdlib.h> 61151214Swpaul#include <unistd.h> 62151214Swpaul#include <err.h> 63151214Swpaul#include <syslog.h> 64151214Swpaul#include <stdarg.h> 65151214Swpaul 66151214Swpaulstatic int verbose = 0; 67151214Swpaulstatic int debug = 0; 68151223Swpaulstatic int all_events = 0; 69151214Swpaul 70151214Swpaul#define PROGNAME "ndis_events" 71151214Swpaul 72151214Swpaul#define WPA_SUPPLICANT_PORT 9876 73151214Swpaul#define NDIS_INDICATION_LEN 2048 74151214Swpaul 75151214Swpaul#define EVENT_CONNECT 0 76151214Swpaul#define EVENT_DISCONNECT 1 77151214Swpaul#define EVENT_MEDIA_SPECIFIC 2 78151214Swpaul 79151214Swpaul#define NDIS_STATUS_MEDIA_CONNECT 0x4001000B 80151214Swpaul#define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000C 81151214Swpaul#define NDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 82151214Swpaul 83151214Swpaulstruct ndis_evt { 84151214Swpaul uint32_t ne_sts; 85151214Swpaul uint32_t ne_len; 86151214Swpaul#ifdef notdef 87151214Swpaul char ne_buf[1]; 88151214Swpaul#endif 89151214Swpaul}; 90151214Swpaul 91151214Swpaulstatic int find_ifname(int, char *); 92151246Swpaulstatic int announce_event(char *, int, struct sockaddr_in *); 93194686Smaximstatic void usage(void); 94151214Swpaul 95151214Swpaulstatic void 96151214Swpauldbgmsg(const char *fmt, ...) 97151214Swpaul{ 98151214Swpaul va_list ap; 99151214Swpaul 100151214Swpaul va_start(ap, fmt); 101151214Swpaul if (debug) 102151214Swpaul vwarnx(fmt, ap); 103151214Swpaul else 104151246Swpaul vsyslog(LOG_ERR, fmt, ap); 105151214Swpaul va_end(ap); 106151214Swpaul 107151214Swpaul return; 108151214Swpaul} 109151214Swpaul 110151214Swpaulstatic int 111151214Swpaulfind_ifname(idx, name) 112151214Swpaul int idx; 113151214Swpaul char *name; 114151214Swpaul{ 115151214Swpaul int mib[6]; 116151214Swpaul size_t needed; 117151214Swpaul struct if_msghdr *ifm; 118151214Swpaul struct sockaddr_dl *sdl; 119151214Swpaul char *buf, *lim, *next; 120151214Swpaul 121151214Swpaul needed = 0; 122151214Swpaul mib[0] = CTL_NET; 123151214Swpaul mib[1] = PF_ROUTE; 124151214Swpaul mib[2] = 0; /* protocol */ 125151214Swpaul mib[3] = 0; /* wildcard address family */ 126151214Swpaul mib[4] = NET_RT_IFLIST; 127151214Swpaul mib[5] = 0; /* no flags */ 128151214Swpaul 129151214Swpaul if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) 130151214Swpaul return(EIO); 131151214Swpaul 132151214Swpaul buf = malloc (needed); 133151214Swpaul if (buf == NULL) 134151214Swpaul return(ENOMEM); 135151214Swpaul 136151214Swpaul if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) { 137151214Swpaul free(buf); 138151214Swpaul return(EIO); 139151214Swpaul } 140151214Swpaul 141151214Swpaul lim = buf + needed; 142151214Swpaul 143151214Swpaul next = buf; 144151214Swpaul while (next < lim) { 145151214Swpaul ifm = (struct if_msghdr *)next; 146151214Swpaul if (ifm->ifm_type == RTM_IFINFO) { 147151214Swpaul sdl = (struct sockaddr_dl *)(ifm + 1); 148151214Swpaul if (ifm->ifm_index == idx) { 149151214Swpaul strncpy(name, sdl->sdl_data, sdl->sdl_nlen); 150151214Swpaul name[sdl->sdl_nlen] = '\0'; 151151214Swpaul free (buf); 152151214Swpaul return (0); 153151214Swpaul } 154151214Swpaul } 155151214Swpaul next += ifm->ifm_msglen; 156151214Swpaul } 157151214Swpaul 158151214Swpaul free (buf); 159151214Swpaul 160151214Swpaul return(ENOENT); 161151214Swpaul} 162151214Swpaul 163151246Swpaulstatic int 164151214Swpaulannounce_event(ifname, sock, dst) 165151214Swpaul char *ifname; 166151214Swpaul int sock; 167151214Swpaul struct sockaddr_in *dst; 168151214Swpaul{ 169151214Swpaul int s; 170151214Swpaul char indication[NDIS_INDICATION_LEN]; 171151214Swpaul struct ifreq ifr; 172151214Swpaul struct ndis_evt *e; 173151214Swpaul char buf[512], *pos, *end; 174151214Swpaul int len, type, _type; 175151214Swpaul 176151214Swpaul s = socket(PF_INET, SOCK_DGRAM, 0); 177151214Swpaul 178151246Swpaul if (s < 0) { 179151246Swpaul dbgmsg("socket creation failed"); 180151246Swpaul return(EINVAL); 181151246Swpaul } 182151214Swpaul 183151214Swpaul bzero((char *)&ifr, sizeof(ifr)); 184151214Swpaul e = (struct ndis_evt *)indication; 185151214Swpaul e->ne_len = NDIS_INDICATION_LEN - sizeof(struct ndis_evt); 186151214Swpaul 187151214Swpaul strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 188151214Swpaul ifr.ifr_data = indication; 189151214Swpaul 190151214Swpaul if (ioctl(s, SIOCGPRIVATE_0, &ifr) < 0) { 191151214Swpaul close(s); 192151541Swpaul if (verbose) { 193151541Swpaul if (errno == ENOENT) 194151541Swpaul dbgmsg("drained all events from %s", 195151541Swpaul ifname, errno); 196151541Swpaul else 197151541Swpaul dbgmsg("failed to read event info from %s: %d", 198151541Swpaul ifname, errno); 199151541Swpaul } 200151246Swpaul return(ENOENT); 201151214Swpaul } 202151214Swpaul 203151214Swpaul if (e->ne_sts == NDIS_STATUS_MEDIA_CONNECT) { 204151214Swpaul type = EVENT_CONNECT; 205151214Swpaul if (verbose) 206151214Swpaul dbgmsg("Received a connect event for %s", ifname); 207151246Swpaul if (!all_events) { 208151246Swpaul close(s); 209151246Swpaul return(0); 210151246Swpaul } 211151214Swpaul } 212151214Swpaul if (e->ne_sts == NDIS_STATUS_MEDIA_DISCONNECT) { 213151214Swpaul type = EVENT_DISCONNECT; 214151214Swpaul if (verbose) 215151214Swpaul dbgmsg("Received a disconnect event for %s", ifname); 216151246Swpaul if (!all_events) { 217151246Swpaul close(s); 218151246Swpaul return(0); 219151246Swpaul } 220151214Swpaul } 221151214Swpaul if (e->ne_sts == NDIS_STATUS_MEDIA_SPECIFIC_INDICATION) { 222151214Swpaul type = EVENT_MEDIA_SPECIFIC; 223151214Swpaul if (verbose) 224151214Swpaul dbgmsg("Received a media-specific event for %s", 225151214Swpaul ifname); 226151214Swpaul } 227151214Swpaul 228151214Swpaul end = buf + sizeof(buf); 229151214Swpaul _type = (int) type; 230151214Swpaul memcpy(buf, &_type, sizeof(_type)); 231151214Swpaul pos = buf + sizeof(_type); 232151214Swpaul 233151214Swpaul len = snprintf(pos + 1, end - pos - 1, "%s", ifname); 234151246Swpaul if (len < 0) { 235151246Swpaul close(s); 236151246Swpaul return(ENOSPC); 237151246Swpaul } 238151214Swpaul if (len > 255) 239151214Swpaul len = 255; 240151214Swpaul *pos = (unsigned char) len; 241151214Swpaul pos += 1 + len; 242151214Swpaul if (e->ne_len) { 243151214Swpaul if (e->ne_len > 255 || 1 + e->ne_len > end - pos) { 244151214Swpaul dbgmsg("Not enough room for send_event data (%d)\n", 245151214Swpaul e->ne_len); 246151246Swpaul close(s); 247151246Swpaul return(ENOSPC); 248151214Swpaul } 249151214Swpaul *pos++ = (unsigned char) e->ne_len; 250151214Swpaul memcpy(pos, (indication) + sizeof(struct ndis_evt), e->ne_len); 251151214Swpaul pos += e->ne_len; 252151214Swpaul } 253151214Swpaul 254151214Swpaul len = sendto(sock, buf, pos - buf, 0, (struct sockaddr *) dst, 255151214Swpaul sizeof(struct sockaddr_in)); 256151214Swpaul 257151214Swpaul close(s); 258151246Swpaul return(0); 259151214Swpaul} 260151214Swpaul 261151214Swpaulstatic void 262194681Smaximusage() 263151214Swpaul{ 264194680Smaxim fprintf(stderr, "Usage: ndis_events [-a] [-d] [-v]\n"); 265151214Swpaul exit(1); 266151214Swpaul} 267151214Swpaul 268151214Swpaulint 269151214Swpaulmain(argc, argv) 270151214Swpaul int argc; 271151214Swpaul char *argv[]; 272151214Swpaul{ 273151214Swpaul int s, r, n; 274151214Swpaul struct sockaddr_in sin; 275151214Swpaul char msg[NDIS_INDICATION_LEN]; 276151214Swpaul struct rt_msghdr *rtm; 277151214Swpaul struct if_msghdr *ifm; 278151214Swpaul char ifname[IFNAMSIZ]; 279151214Swpaul int ch; 280151214Swpaul 281151223Swpaul while ((ch = getopt(argc, argv, "dva")) != -1) { 282151214Swpaul switch(ch) { 283151214Swpaul case 'd': 284151214Swpaul debug++; 285151214Swpaul break; 286151214Swpaul case 'v': 287151214Swpaul verbose++; 288151214Swpaul break; 289151223Swpaul case 'a': 290151223Swpaul all_events++; 291151223Swpaul break; 292151214Swpaul default: 293194686Smaxim usage(); 294151214Swpaul break; 295151214Swpaul } 296151214Swpaul } 297151214Swpaul 298151214Swpaul if (!debug && daemon(0, 0)) 299151214Swpaul err(1, "failed to daemonize ourselves"); 300151214Swpaul 301151214Swpaul if (!debug) 302151214Swpaul openlog(PROGNAME, LOG_PID | LOG_CONS, LOG_DAEMON); 303151214Swpaul 304151214Swpaul bzero((char *)&sin, sizeof(sin)); 305151214Swpaul 306151214Swpaul /* Create a datagram socket. */ 307151214Swpaul 308151214Swpaul s = socket(PF_INET, SOCK_DGRAM, 0); 309151214Swpaul if (s < 0) { 310151214Swpaul dbgmsg("socket creation failed"); 311151214Swpaul exit(1); 312151214Swpaul } 313151214Swpaul 314151214Swpaul sin.sin_family = AF_INET; 315151214Swpaul sin.sin_addr.s_addr = inet_addr("127.0.0.1"); 316151214Swpaul sin.sin_port = htons(WPA_SUPPLICANT_PORT); 317151214Swpaul 318151214Swpaul /* Create a routing socket. */ 319151214Swpaul 320151214Swpaul r = socket (PF_ROUTE, SOCK_RAW, 0); 321151214Swpaul if (r < 0) { 322151214Swpaul dbgmsg("routing socket creation failed"); 323151214Swpaul exit(1); 324151214Swpaul } 325151214Swpaul 326151214Swpaul /* Now sit and spin, waiting for events. */ 327151214Swpaul 328151214Swpaul if (verbose) 329151214Swpaul dbgmsg("Listening for events"); 330151214Swpaul 331151214Swpaul while (1) { 332151214Swpaul n = read(r, msg, NDIS_INDICATION_LEN); 333151214Swpaul rtm = (struct rt_msghdr *)msg; 334151214Swpaul if (rtm->rtm_type != RTM_IFINFO) 335151214Swpaul continue; 336151214Swpaul ifm = (struct if_msghdr *)msg; 337151214Swpaul if (find_ifname(ifm->ifm_index, ifname)) 338151214Swpaul continue; 339151246Swpaul if (strstr(ifname, "ndis")) { 340151246Swpaul while(announce_event(ifname, s, &sin) == 0) 341151246Swpaul ; 342151246Swpaul } else { 343151214Swpaul if (verbose) 344151214Swpaul dbgmsg("Skipping ifinfo message from %s", 345151214Swpaul ifname); 346151214Swpaul } 347151214Swpaul } 348151214Swpaul 349151214Swpaul /* NOTREACHED */ 350151214Swpaul exit(0); 351151214Swpaul} 352