ndis_events.c revision 151214
1189251Ssam/*- 2189251Ssam * Copyright (c) 2005 3189251Ssam * Bill Paul <wpaul@windriver.com>. All rights reserved. 4189251Ssam * 5252726Srpaulo * Redistribution and use in source and binary forms, with or without 6252726Srpaulo * modification, are permitted provided that the following conditions 7189251Ssam * are met: 8189251Ssam * 1. Redistributions of source code must retain the above copyright 9189251Ssam * notice, this list of conditions and the following disclaimer. 10189251Ssam * 2. Redistributions in binary form must reproduce the above copyright 11189251Ssam * notice, this list of conditions and the following disclaimer in the 12189251Ssam * documentation and/or other materials provided with the distribution. 13189251Ssam * 3. All advertising materials mentioning features or use of this software 14189251Ssam * must display the following acknowledgement: 15189251Ssam * This product includes software developed by Bill Paul. 16189251Ssam * 4. Neither the name of the author nor the names of any co-contributors 17189251Ssam * may be used to endorse or promote products derived from this software 18189251Ssam * without specific prior written permission. 19189251Ssam * 20189251Ssam * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21189251Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22189251Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23189251Ssam * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24189251Ssam * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25189251Ssam * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26189251Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27189251Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28189251Ssam * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29189251Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30189251Ssam * THE POSSIBILITY OF SUCH DAMAGE. 31189251Ssam */ 32189251Ssam 33189251Ssam#include <sys/cdefs.h> 34189251Ssam__FBSDID("$FreeBSD: head/usr.sbin/wpa/ndis_events/ndis_events.c 151214 2005-10-10 17:51:12Z wpaul $"); 35189251Ssam 36189251Ssam/* 37189251Ssam * This program simulates the behavior of the ndis_events utility 38189251Ssam * supplied with wpa_supplicant for Windows. The original utility 39189251Ssam * is designed to translate Windows WMI events. We don't have WMI, 40189251Ssam * but we need to supply certain event info to wpa_supplicant in 41189251Ssam * order to make WPA2 work correctly, so we fake up the interface. 42189251Ssam */ 43189251Ssam 44189251Ssam#include <sys/types.h> 45189251Ssam#include <sys/cdefs.h> 46189251Ssam#include <sys/param.h> 47189251Ssam#include <sys/socket.h> 48189251Ssam#include <sys/ioctl.h> 49189251Ssam#include <sys/socket.h> 50189251Ssam#include <sys/errno.h> 51189251Ssam#include <sys/sysctl.h> 52189251Ssam#include <net/if.h> 53189251Ssam#include <net/if_dl.h> 54189251Ssam#include <net/if_var.h> 55189251Ssam 56189251Ssam#include <netinet/in.h> 57189251Ssam#include <arpa/inet.h> 58189251Ssam#include <netdb.h> 59189251Ssam#include <net/route.h> 60189251Ssam 61189251Ssam#include <stdio.h> 62189251Ssam#include <string.h> 63189251Ssam#include <stdlib.h> 64189251Ssam#include <unistd.h> 65189251Ssam#include <err.h> 66189251Ssam#include <syslog.h> 67189251Ssam#include <stdarg.h> 68189251Ssam 69189251Ssamstatic int verbose = 0; 70189251Ssamstatic int debug = 0; 71189251Ssam 72189251Ssam#define PROGNAME "ndis_events" 73189251Ssam 74189251Ssam#define WPA_SUPPLICANT_PORT 9876 75189251Ssam#define NDIS_INDICATION_LEN 2048 76189251Ssam 77189251Ssam#define EVENT_CONNECT 0 78189251Ssam#define EVENT_DISCONNECT 1 79189251Ssam#define EVENT_MEDIA_SPECIFIC 2 80189251Ssam 81189251Ssam#define NDIS_STATUS_MEDIA_CONNECT 0x4001000B 82189251Ssam#define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000C 83189251Ssam#define NDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 84189251Ssam 85189251Ssamstruct ndis_evt { 86189251Ssam uint32_t ne_sts; 87189251Ssam uint32_t ne_len; 88189251Ssam#ifdef notdef 89189251Ssam char ne_buf[1]; 90189251Ssam#endif 91189251Ssam}; 92189251Ssam 93189251Ssamstatic int find_ifname(int, char *); 94189251Ssamstatic void announce_event(char *, int, struct sockaddr_in *); 95189251Ssamstatic void usage(char *); 96189251Ssam 97189251Ssamstatic void 98189251Ssamdbgmsg(const char *fmt, ...) 99189251Ssam{ 100189251Ssam va_list ap; 101189251Ssam 102189251Ssam va_start(ap, fmt); 103189251Ssam if (debug) 104189251Ssam vwarnx(fmt, ap); 105189251Ssam else 106189251Ssam vsyslog(LOG_INFO, fmt, ap); 107189251Ssam va_end(ap); 108189251Ssam 109189251Ssam return; 110189251Ssam} 111189251Ssam 112189251Ssamstatic int 113189251Ssamfind_ifname(idx, name) 114189251Ssam int idx; 115189251Ssam char *name; 116189251Ssam{ 117189251Ssam int mib[6]; 118189251Ssam size_t needed; 119189251Ssam struct if_msghdr *ifm; 120189251Ssam struct sockaddr_dl *sdl; 121189251Ssam char *buf, *lim, *next; 122189251Ssam 123189251Ssam needed = 0; 124189251Ssam mib[0] = CTL_NET; 125189251Ssam mib[1] = PF_ROUTE; 126189251Ssam mib[2] = 0; /* protocol */ 127189251Ssam mib[3] = 0; /* wildcard address family */ 128189251Ssam mib[4] = NET_RT_IFLIST; 129189251Ssam mib[5] = 0; /* no flags */ 130189251Ssam 131189251Ssam if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) 132189251Ssam return(EIO); 133189251Ssam 134189251Ssam buf = malloc (needed); 135189251Ssam if (buf == NULL) 136189251Ssam return(ENOMEM); 137189251Ssam 138189251Ssam if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) { 139189251Ssam free(buf); 140189251Ssam return(EIO); 141189251Ssam } 142189251Ssam 143189251Ssam lim = buf + needed; 144189251Ssam 145189251Ssam next = buf; 146189251Ssam while (next < lim) { 147189251Ssam ifm = (struct if_msghdr *)next; 148189251Ssam if (ifm->ifm_type == RTM_IFINFO) { 149189251Ssam sdl = (struct sockaddr_dl *)(ifm + 1); 150189251Ssam if (ifm->ifm_index == idx) { 151189251Ssam strncpy(name, sdl->sdl_data, sdl->sdl_nlen); 152189251Ssam name[sdl->sdl_nlen] = '\0'; 153189251Ssam free (buf); 154189251Ssam return (0); 155189251Ssam } 156189251Ssam } 157189251Ssam next += ifm->ifm_msglen; 158189251Ssam } 159189251Ssam 160189251Ssam free (buf); 161189251Ssam 162189251Ssam return(ENOENT); 163189251Ssam} 164189251Ssam 165189251Ssamstatic void 166189251Ssamannounce_event(ifname, sock, dst) 167189251Ssam char *ifname; 168189251Ssam int sock; 169189251Ssam struct sockaddr_in *dst; 170189251Ssam{ 171189251Ssam int s; 172189251Ssam char indication[NDIS_INDICATION_LEN]; 173189251Ssam struct ifreq ifr; 174189251Ssam struct ndis_evt *e; 175189251Ssam char buf[512], *pos, *end; 176189251Ssam int len, type, _type; 177189251Ssam 178189251Ssam s = socket(PF_INET, SOCK_DGRAM, 0); 179189251Ssam 180189251Ssam if (s < 0) 181189251Ssam return; 182189251Ssam 183189251Ssam bzero((char *)&ifr, sizeof(ifr)); 184189251Ssam e = (struct ndis_evt *)indication; 185189251Ssam e->ne_len = NDIS_INDICATION_LEN - sizeof(struct ndis_evt); 186189251Ssam 187189251Ssam strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 188189251Ssam ifr.ifr_data = indication; 189189251Ssam 190189251Ssam if (ioctl(s, SIOCGPRIVATE_0, &ifr) < 0) { 191189251Ssam close(s); 192189251Ssam dbgmsg("failed to read event info from %s\n", ifname); 193189251Ssam return; 194189251Ssam } 195189251Ssam 196189251Ssam if (e->ne_sts == NDIS_STATUS_MEDIA_CONNECT) { 197189251Ssam type = EVENT_CONNECT; 198189251Ssam if (verbose) 199189251Ssam dbgmsg("Received a connect event for %s", ifname); 200189251Ssam } 201189251Ssam if (e->ne_sts == NDIS_STATUS_MEDIA_DISCONNECT) { 202189251Ssam type = EVENT_DISCONNECT; 203189251Ssam if (verbose) 204189251Ssam dbgmsg("Received a disconnect event for %s", ifname); 205189251Ssam } 206189251Ssam if (e->ne_sts == NDIS_STATUS_MEDIA_SPECIFIC_INDICATION) { 207189251Ssam type = EVENT_MEDIA_SPECIFIC; 208189251Ssam if (verbose) 209189251Ssam dbgmsg("Received a media-specific event for %s", 210189251Ssam ifname); 211189251Ssam } 212189251Ssam 213189251Ssam end = buf + sizeof(buf); 214189251Ssam _type = (int) type; 215189251Ssam memcpy(buf, &_type, sizeof(_type)); 216189251Ssam pos = buf + sizeof(_type); 217189251Ssam 218189251Ssam len = snprintf(pos + 1, end - pos - 1, "%s", ifname); 219189251Ssam if (len < 0) 220189251Ssam return; 221189251Ssam if (len > 255) 222189251Ssam len = 255; 223189251Ssam *pos = (unsigned char) len; 224189251Ssam pos += 1 + len; 225189251Ssam if (e->ne_len) { 226189251Ssam if (e->ne_len > 255 || 1 + e->ne_len > end - pos) { 227189251Ssam dbgmsg("Not enough room for send_event data (%d)\n", 228189251Ssam e->ne_len); 229189251Ssam return; 230189251Ssam } 231252726Srpaulo *pos++ = (unsigned char) e->ne_len; 232189251Ssam memcpy(pos, (indication) + sizeof(struct ndis_evt), e->ne_len); 233189251Ssam pos += e->ne_len; 234189251Ssam } 235252726Srpaulo 236189251Ssam len = sendto(sock, buf, pos - buf, 0, (struct sockaddr *) dst, 237189251Ssam sizeof(struct sockaddr_in)); 238189251Ssam 239189251Ssam close(s); 240189251Ssam return; 241189251Ssam} 242189251Ssam 243189251Ssamstatic void 244189251Ssamusage(progname) 245189251Ssam char *progname; 246189251Ssam{ 247189251Ssam fprintf(stderr, "Usage: ndis_events [-d] [-v]\n", progname); 248189251Ssam exit(1); 249189251Ssam} 250189251Ssam 251189251Ssamint 252189251Ssammain(argc, argv) 253189251Ssam int argc; 254189251Ssam char *argv[]; 255189251Ssam{ 256189251Ssam int s, r, n; 257189251Ssam struct sockaddr_in sin; 258189251Ssam char msg[NDIS_INDICATION_LEN]; 259189251Ssam struct rt_msghdr *rtm; 260189251Ssam struct if_msghdr *ifm; 261189251Ssam char ifname[IFNAMSIZ]; 262189251Ssam int ch; 263189251Ssam 264189251Ssam while ((ch = getopt(argc, argv, "dv")) != -1) { 265189251Ssam switch(ch) { 266189251Ssam case 'd': 267189251Ssam debug++; 268189251Ssam break; 269189251Ssam case 'v': 270189251Ssam verbose++; 271189251Ssam break; 272189251Ssam default: 273189251Ssam usage(PROGNAME); 274189251Ssam break; 275189251Ssam } 276189251Ssam } 277189251Ssam 278189251Ssam if (!debug && daemon(0, 0)) 279189251Ssam err(1, "failed to daemonize ourselves"); 280189251Ssam 281189251Ssam if (!debug) 282189251Ssam openlog(PROGNAME, LOG_PID | LOG_CONS, LOG_DAEMON); 283189251Ssam 284189251Ssam bzero((char *)&sin, sizeof(sin)); 285189251Ssam 286189251Ssam /* Create a datagram socket. */ 287189251Ssam 288189251Ssam s = socket(PF_INET, SOCK_DGRAM, 0); 289189251Ssam if (s < 0) { 290189251Ssam dbgmsg("socket creation failed"); 291189251Ssam exit(1); 292189251Ssam } 293189251Ssam 294189251Ssam sin.sin_family = AF_INET; 295189251Ssam sin.sin_addr.s_addr = inet_addr("127.0.0.1"); 296189251Ssam sin.sin_port = htons(WPA_SUPPLICANT_PORT); 297189251Ssam 298189251Ssam /* Create a routing socket. */ 299189251Ssam 300189251Ssam r = socket (PF_ROUTE, SOCK_RAW, 0); 301189251Ssam if (r < 0) { 302189251Ssam dbgmsg("routing socket creation failed"); 303189251Ssam exit(1); 304189251Ssam } 305189251Ssam 306189251Ssam /* Now sit and spin, waiting for events. */ 307189251Ssam 308189251Ssam if (verbose) 309189251Ssam dbgmsg("Listening for events"); 310189251Ssam 311189251Ssam while (1) { 312189251Ssam n = read(r, msg, NDIS_INDICATION_LEN); 313189251Ssam rtm = (struct rt_msghdr *)msg; 314189251Ssam if (rtm->rtm_type != RTM_IFINFO) 315189251Ssam continue; 316189251Ssam ifm = (struct if_msghdr *)msg; 317189251Ssam if (find_ifname(ifm->ifm_index, ifname)) 318189251Ssam continue; 319189251Ssam if (strstr(ifname, "ndis")) 320189251Ssam announce_event(ifname, s, &sin); 321189251Ssam else { 322189251Ssam if (verbose) 323189251Ssam dbgmsg("Skipping ifinfo message from %s", 324189251Ssam ifname); 325189251Ssam } 326189251Ssam } 327189251Ssam 328189251Ssam /* NOTREACHED */ 329189251Ssam exit(0); 330189251Ssam} 331189251Ssam