diff options
author | wpaul <wpaul@FreeBSD.org> | 2005-10-10 17:51:12 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 2005-10-10 17:51:12 +0000 |
commit | ae456864c832178281744e29512afbd33316a0e1 (patch) | |
tree | 52817e3abeffaf644a32f76ca3d79a056723aa83 /usr.sbin/wpa/ndis_events/ndis_events.c | |
parent | 43bfda2ca07bf54cc33547ed02b7b1b654247ace (diff) | |
download | FreeBSD-src-ae456864c832178281744e29512afbd33316a0e1.zip FreeBSD-src-ae456864c832178281744e29512afbd33316a0e1.tar.gz |
Enable -D ndis support in wpa_supplicant and add the ndis_events utility.
This allows wpa_supplicant to work with WPA and WPA2 compliant NDIS
drivers.
Diffstat (limited to 'usr.sbin/wpa/ndis_events/ndis_events.c')
-rw-r--r-- | usr.sbin/wpa/ndis_events/ndis_events.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/usr.sbin/wpa/ndis_events/ndis_events.c b/usr.sbin/wpa/ndis_events/ndis_events.c new file mode 100644 index 0000000..1741a64 --- /dev/null +++ b/usr.sbin/wpa/ndis_events/ndis_events.c @@ -0,0 +1,330 @@ +/*- + * Copyright (c) 2005 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * This program simulates the behavior of the ndis_events utility + * supplied with wpa_supplicant for Windows. The original utility + * is designed to translate Windows WMI events. We don't have WMI, + * but we need to supply certain event info to wpa_supplicant in + * order to make WPA2 work correctly, so we fake up the interface. + */ + +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/sysctl.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_var.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <net/route.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <err.h> +#include <syslog.h> +#include <stdarg.h> + +static int verbose = 0; +static int debug = 0; + +#define PROGNAME "ndis_events" + +#define WPA_SUPPLICANT_PORT 9876 +#define NDIS_INDICATION_LEN 2048 + +#define EVENT_CONNECT 0 +#define EVENT_DISCONNECT 1 +#define EVENT_MEDIA_SPECIFIC 2 + +#define NDIS_STATUS_MEDIA_CONNECT 0x4001000B +#define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000C +#define NDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 + +struct ndis_evt { + uint32_t ne_sts; + uint32_t ne_len; +#ifdef notdef + char ne_buf[1]; +#endif +}; + +static int find_ifname(int, char *); +static void announce_event(char *, int, struct sockaddr_in *); +static void usage(char *); + +static void +dbgmsg(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (debug) + vwarnx(fmt, ap); + else + vsyslog(LOG_INFO, fmt, ap); + va_end(ap); + + return; +} + +static int +find_ifname(idx, name) + int idx; + char *name; +{ + int mib[6]; + size_t needed; + struct if_msghdr *ifm; + struct sockaddr_dl *sdl; + char *buf, *lim, *next; + + needed = 0; + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; /* protocol */ + mib[3] = 0; /* wildcard address family */ + mib[4] = NET_RT_IFLIST; + mib[5] = 0; /* no flags */ + + if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) + return(EIO); + + buf = malloc (needed); + if (buf == NULL) + return(ENOMEM); + + if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) { + free(buf); + return(EIO); + } + + lim = buf + needed; + + next = buf; + while (next < lim) { + ifm = (struct if_msghdr *)next; + if (ifm->ifm_type == RTM_IFINFO) { + sdl = (struct sockaddr_dl *)(ifm + 1); + if (ifm->ifm_index == idx) { + strncpy(name, sdl->sdl_data, sdl->sdl_nlen); + name[sdl->sdl_nlen] = '\0'; + free (buf); + return (0); + } + } + next += ifm->ifm_msglen; + } + + free (buf); + + return(ENOENT); +} + +static void +announce_event(ifname, sock, dst) + char *ifname; + int sock; + struct sockaddr_in *dst; +{ + int s; + char indication[NDIS_INDICATION_LEN]; + struct ifreq ifr; + struct ndis_evt *e; + char buf[512], *pos, *end; + int len, type, _type; + + s = socket(PF_INET, SOCK_DGRAM, 0); + + if (s < 0) + return; + + bzero((char *)&ifr, sizeof(ifr)); + e = (struct ndis_evt *)indication; + e->ne_len = NDIS_INDICATION_LEN - sizeof(struct ndis_evt); + + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + ifr.ifr_data = indication; + + if (ioctl(s, SIOCGPRIVATE_0, &ifr) < 0) { + close(s); + dbgmsg("failed to read event info from %s\n", ifname); + return; + } + + if (e->ne_sts == NDIS_STATUS_MEDIA_CONNECT) { + type = EVENT_CONNECT; + if (verbose) + dbgmsg("Received a connect event for %s", ifname); + } + if (e->ne_sts == NDIS_STATUS_MEDIA_DISCONNECT) { + type = EVENT_DISCONNECT; + if (verbose) + dbgmsg("Received a disconnect event for %s", ifname); + } + if (e->ne_sts == NDIS_STATUS_MEDIA_SPECIFIC_INDICATION) { + type = EVENT_MEDIA_SPECIFIC; + if (verbose) + dbgmsg("Received a media-specific event for %s", + ifname); + } + + end = buf + sizeof(buf); + _type = (int) type; + memcpy(buf, &_type, sizeof(_type)); + pos = buf + sizeof(_type); + + len = snprintf(pos + 1, end - pos - 1, "%s", ifname); + if (len < 0) + return; + if (len > 255) + len = 255; + *pos = (unsigned char) len; + pos += 1 + len; + if (e->ne_len) { + if (e->ne_len > 255 || 1 + e->ne_len > end - pos) { + dbgmsg("Not enough room for send_event data (%d)\n", + e->ne_len); + return; + } + *pos++ = (unsigned char) e->ne_len; + memcpy(pos, (indication) + sizeof(struct ndis_evt), e->ne_len); + pos += e->ne_len; + } + + len = sendto(sock, buf, pos - buf, 0, (struct sockaddr *) dst, + sizeof(struct sockaddr_in)); + + close(s); + return; +} + +static void +usage(progname) + char *progname; +{ + fprintf(stderr, "Usage: ndis_events [-d] [-v]\n", progname); + exit(1); +} + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int s, r, n; + struct sockaddr_in sin; + char msg[NDIS_INDICATION_LEN]; + struct rt_msghdr *rtm; + struct if_msghdr *ifm; + char ifname[IFNAMSIZ]; + int ch; + + while ((ch = getopt(argc, argv, "dv")) != -1) { + switch(ch) { + case 'd': + debug++; + break; + case 'v': + verbose++; + break; + default: + usage(PROGNAME); + break; + } + } + + if (!debug && daemon(0, 0)) + err(1, "failed to daemonize ourselves"); + + if (!debug) + openlog(PROGNAME, LOG_PID | LOG_CONS, LOG_DAEMON); + + bzero((char *)&sin, sizeof(sin)); + + /* Create a datagram socket. */ + + s = socket(PF_INET, SOCK_DGRAM, 0); + if (s < 0) { + dbgmsg("socket creation failed"); + exit(1); + } + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = inet_addr("127.0.0.1"); + sin.sin_port = htons(WPA_SUPPLICANT_PORT); + + /* Create a routing socket. */ + + r = socket (PF_ROUTE, SOCK_RAW, 0); + if (r < 0) { + dbgmsg("routing socket creation failed"); + exit(1); + } + + /* Now sit and spin, waiting for events. */ + + if (verbose) + dbgmsg("Listening for events"); + + while (1) { + n = read(r, msg, NDIS_INDICATION_LEN); + rtm = (struct rt_msghdr *)msg; + if (rtm->rtm_type != RTM_IFINFO) + continue; + ifm = (struct if_msghdr *)msg; + if (find_ifname(ifm->ifm_index, ifname)) + continue; + if (strstr(ifname, "ndis")) + announce_event(ifname, s, &sin); + else { + if (verbose) + dbgmsg("Skipping ifinfo message from %s", + ifname); + } + } + + /* NOTREACHED */ + exit(0); +} |