ndis_events.c revision 151214
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: head/usr.sbin/wpa/ndis_events/ndis_events.c 151214 2005-10-10 17:51:12Z wpaul $"); 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/cdefs.h> 46151214Swpaul#include <sys/param.h> 47151214Swpaul#include <sys/socket.h> 48151214Swpaul#include <sys/ioctl.h> 49151214Swpaul#include <sys/socket.h> 50151214Swpaul#include <sys/errno.h> 51151214Swpaul#include <sys/sysctl.h> 52151214Swpaul#include <net/if.h> 53151214Swpaul#include <net/if_dl.h> 54151214Swpaul#include <net/if_var.h> 55151214Swpaul 56151214Swpaul#include <netinet/in.h> 57151214Swpaul#include <arpa/inet.h> 58151214Swpaul#include <netdb.h> 59151214Swpaul#include <net/route.h> 60151214Swpaul 61151214Swpaul#include <stdio.h> 62151214Swpaul#include <string.h> 63151214Swpaul#include <stdlib.h> 64151214Swpaul#include <unistd.h> 65151214Swpaul#include <err.h> 66151214Swpaul#include <syslog.h> 67151214Swpaul#include <stdarg.h> 68151214Swpaul 69151214Swpaulstatic int verbose = 0; 70151214Swpaulstatic int debug = 0; 71151214Swpaul 72151214Swpaul#define PROGNAME "ndis_events" 73151214Swpaul 74151214Swpaul#define WPA_SUPPLICANT_PORT 9876 75151214Swpaul#define NDIS_INDICATION_LEN 2048 76151214Swpaul 77151214Swpaul#define EVENT_CONNECT 0 78151214Swpaul#define EVENT_DISCONNECT 1 79151214Swpaul#define EVENT_MEDIA_SPECIFIC 2 80151214Swpaul 81151214Swpaul#define NDIS_STATUS_MEDIA_CONNECT 0x4001000B 82151214Swpaul#define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000C 83151214Swpaul#define NDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 84151214Swpaul 85151214Swpaulstruct ndis_evt { 86151214Swpaul uint32_t ne_sts; 87151214Swpaul uint32_t ne_len; 88151214Swpaul#ifdef notdef 89151214Swpaul char ne_buf[1]; 90151214Swpaul#endif 91151214Swpaul}; 92151214Swpaul 93151214Swpaulstatic int find_ifname(int, char *); 94151214Swpaulstatic void announce_event(char *, int, struct sockaddr_in *); 95151214Swpaulstatic void usage(char *); 96151214Swpaul 97151214Swpaulstatic void 98151214Swpauldbgmsg(const char *fmt, ...) 99151214Swpaul{ 100151214Swpaul va_list ap; 101151214Swpaul 102151214Swpaul va_start(ap, fmt); 103151214Swpaul if (debug) 104151214Swpaul vwarnx(fmt, ap); 105151214Swpaul else 106151214Swpaul vsyslog(LOG_INFO, fmt, ap); 107151214Swpaul va_end(ap); 108151214Swpaul 109151214Swpaul return; 110151214Swpaul} 111151214Swpaul 112151214Swpaulstatic int 113151214Swpaulfind_ifname(idx, name) 114151214Swpaul int idx; 115151214Swpaul char *name; 116151214Swpaul{ 117151214Swpaul int mib[6]; 118151214Swpaul size_t needed; 119151214Swpaul struct if_msghdr *ifm; 120151214Swpaul struct sockaddr_dl *sdl; 121151214Swpaul char *buf, *lim, *next; 122151214Swpaul 123151214Swpaul needed = 0; 124151214Swpaul mib[0] = CTL_NET; 125151214Swpaul mib[1] = PF_ROUTE; 126151214Swpaul mib[2] = 0; /* protocol */ 127151214Swpaul mib[3] = 0; /* wildcard address family */ 128151214Swpaul mib[4] = NET_RT_IFLIST; 129151214Swpaul mib[5] = 0; /* no flags */ 130151214Swpaul 131151214Swpaul if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) 132151214Swpaul return(EIO); 133151214Swpaul 134151214Swpaul buf = malloc (needed); 135151214Swpaul if (buf == NULL) 136151214Swpaul return(ENOMEM); 137151214Swpaul 138151214Swpaul if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) { 139151214Swpaul free(buf); 140151214Swpaul return(EIO); 141151214Swpaul } 142151214Swpaul 143151214Swpaul lim = buf + needed; 144151214Swpaul 145151214Swpaul next = buf; 146151214Swpaul while (next < lim) { 147151214Swpaul ifm = (struct if_msghdr *)next; 148151214Swpaul if (ifm->ifm_type == RTM_IFINFO) { 149151214Swpaul sdl = (struct sockaddr_dl *)(ifm + 1); 150151214Swpaul if (ifm->ifm_index == idx) { 151151214Swpaul strncpy(name, sdl->sdl_data, sdl->sdl_nlen); 152151214Swpaul name[sdl->sdl_nlen] = '\0'; 153151214Swpaul free (buf); 154151214Swpaul return (0); 155151214Swpaul } 156151214Swpaul } 157151214Swpaul next += ifm->ifm_msglen; 158151214Swpaul } 159151214Swpaul 160151214Swpaul free (buf); 161151214Swpaul 162151214Swpaul return(ENOENT); 163151214Swpaul} 164151214Swpaul 165151214Swpaulstatic void 166151214Swpaulannounce_event(ifname, sock, dst) 167151214Swpaul char *ifname; 168151214Swpaul int sock; 169151214Swpaul struct sockaddr_in *dst; 170151214Swpaul{ 171151214Swpaul int s; 172151214Swpaul char indication[NDIS_INDICATION_LEN]; 173151214Swpaul struct ifreq ifr; 174151214Swpaul struct ndis_evt *e; 175151214Swpaul char buf[512], *pos, *end; 176151214Swpaul int len, type, _type; 177151214Swpaul 178151214Swpaul s = socket(PF_INET, SOCK_DGRAM, 0); 179151214Swpaul 180151214Swpaul if (s < 0) 181151214Swpaul return; 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); 192151214Swpaul dbgmsg("failed to read event info from %s\n", ifname); 193151214Swpaul return; 194151214Swpaul } 195151214Swpaul 196151214Swpaul if (e->ne_sts == NDIS_STATUS_MEDIA_CONNECT) { 197151214Swpaul type = EVENT_CONNECT; 198151214Swpaul if (verbose) 199151214Swpaul dbgmsg("Received a connect event for %s", ifname); 200151214Swpaul } 201151214Swpaul if (e->ne_sts == NDIS_STATUS_MEDIA_DISCONNECT) { 202151214Swpaul type = EVENT_DISCONNECT; 203151214Swpaul if (verbose) 204151214Swpaul dbgmsg("Received a disconnect event for %s", ifname); 205151214Swpaul } 206151214Swpaul if (e->ne_sts == NDIS_STATUS_MEDIA_SPECIFIC_INDICATION) { 207151214Swpaul type = EVENT_MEDIA_SPECIFIC; 208151214Swpaul if (verbose) 209151214Swpaul dbgmsg("Received a media-specific event for %s", 210151214Swpaul ifname); 211151214Swpaul } 212151214Swpaul 213151214Swpaul end = buf + sizeof(buf); 214151214Swpaul _type = (int) type; 215151214Swpaul memcpy(buf, &_type, sizeof(_type)); 216151214Swpaul pos = buf + sizeof(_type); 217151214Swpaul 218151214Swpaul len = snprintf(pos + 1, end - pos - 1, "%s", ifname); 219151214Swpaul if (len < 0) 220151214Swpaul return; 221151214Swpaul if (len > 255) 222151214Swpaul len = 255; 223151214Swpaul *pos = (unsigned char) len; 224151214Swpaul pos += 1 + len; 225151214Swpaul if (e->ne_len) { 226151214Swpaul if (e->ne_len > 255 || 1 + e->ne_len > end - pos) { 227151214Swpaul dbgmsg("Not enough room for send_event data (%d)\n", 228151214Swpaul e->ne_len); 229151214Swpaul return; 230151214Swpaul } 231151214Swpaul *pos++ = (unsigned char) e->ne_len; 232151214Swpaul memcpy(pos, (indication) + sizeof(struct ndis_evt), e->ne_len); 233151214Swpaul pos += e->ne_len; 234151214Swpaul } 235151214Swpaul 236151214Swpaul len = sendto(sock, buf, pos - buf, 0, (struct sockaddr *) dst, 237151214Swpaul sizeof(struct sockaddr_in)); 238151214Swpaul 239151214Swpaul close(s); 240151214Swpaul return; 241151214Swpaul} 242151214Swpaul 243151214Swpaulstatic void 244151214Swpaulusage(progname) 245151214Swpaul char *progname; 246151214Swpaul{ 247151214Swpaul fprintf(stderr, "Usage: ndis_events [-d] [-v]\n", progname); 248151214Swpaul exit(1); 249151214Swpaul} 250151214Swpaul 251151214Swpaulint 252151214Swpaulmain(argc, argv) 253151214Swpaul int argc; 254151214Swpaul char *argv[]; 255151214Swpaul{ 256151214Swpaul int s, r, n; 257151214Swpaul struct sockaddr_in sin; 258151214Swpaul char msg[NDIS_INDICATION_LEN]; 259151214Swpaul struct rt_msghdr *rtm; 260151214Swpaul struct if_msghdr *ifm; 261151214Swpaul char ifname[IFNAMSIZ]; 262151214Swpaul int ch; 263151214Swpaul 264151214Swpaul while ((ch = getopt(argc, argv, "dv")) != -1) { 265151214Swpaul switch(ch) { 266151214Swpaul case 'd': 267151214Swpaul debug++; 268151214Swpaul break; 269151214Swpaul case 'v': 270151214Swpaul verbose++; 271151214Swpaul break; 272151214Swpaul default: 273151214Swpaul usage(PROGNAME); 274151214Swpaul break; 275151214Swpaul } 276151214Swpaul } 277151214Swpaul 278151214Swpaul if (!debug && daemon(0, 0)) 279151214Swpaul err(1, "failed to daemonize ourselves"); 280151214Swpaul 281151214Swpaul if (!debug) 282151214Swpaul openlog(PROGNAME, LOG_PID | LOG_CONS, LOG_DAEMON); 283151214Swpaul 284151214Swpaul bzero((char *)&sin, sizeof(sin)); 285151214Swpaul 286151214Swpaul /* Create a datagram socket. */ 287151214Swpaul 288151214Swpaul s = socket(PF_INET, SOCK_DGRAM, 0); 289151214Swpaul if (s < 0) { 290151214Swpaul dbgmsg("socket creation failed"); 291151214Swpaul exit(1); 292151214Swpaul } 293151214Swpaul 294151214Swpaul sin.sin_family = AF_INET; 295151214Swpaul sin.sin_addr.s_addr = inet_addr("127.0.0.1"); 296151214Swpaul sin.sin_port = htons(WPA_SUPPLICANT_PORT); 297151214Swpaul 298151214Swpaul /* Create a routing socket. */ 299151214Swpaul 300151214Swpaul r = socket (PF_ROUTE, SOCK_RAW, 0); 301151214Swpaul if (r < 0) { 302151214Swpaul dbgmsg("routing socket creation failed"); 303151214Swpaul exit(1); 304151214Swpaul } 305151214Swpaul 306151214Swpaul /* Now sit and spin, waiting for events. */ 307151214Swpaul 308151214Swpaul if (verbose) 309151214Swpaul dbgmsg("Listening for events"); 310151214Swpaul 311151214Swpaul while (1) { 312151214Swpaul n = read(r, msg, NDIS_INDICATION_LEN); 313151214Swpaul rtm = (struct rt_msghdr *)msg; 314151214Swpaul if (rtm->rtm_type != RTM_IFINFO) 315151214Swpaul continue; 316151214Swpaul ifm = (struct if_msghdr *)msg; 317151214Swpaul if (find_ifname(ifm->ifm_index, ifname)) 318151214Swpaul continue; 319151214Swpaul if (strstr(ifname, "ndis")) 320151214Swpaul announce_event(ifname, s, &sin); 321151214Swpaul else { 322151214Swpaul if (verbose) 323151214Swpaul dbgmsg("Skipping ifinfo message from %s", 324151214Swpaul ifname); 325151214Swpaul } 326151214Swpaul } 327151214Swpaul 328151214Swpaul /* NOTREACHED */ 329151214Swpaul exit(0); 330151214Swpaul} 331