ndis_events.c revision 330897
1/*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 2005 5 * Bill Paul <wpaul@windriver.com>. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Bill Paul. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 * THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: stable/11/usr.sbin/wpa/ndis_events/ndis_events.c 330897 2018-03-14 03:19:51Z eadler $"); 37 38/* 39 * This program simulates the behavior of the ndis_events utility 40 * supplied with wpa_supplicant for Windows. The original utility 41 * is designed to translate Windows WMI events. We don't have WMI, 42 * but we need to supply certain event info to wpa_supplicant in 43 * order to make WPA2 work correctly, so we fake up the interface. 44 */ 45 46#include <sys/types.h> 47#include <sys/param.h> 48#include <sys/socket.h> 49#include <sys/ioctl.h> 50#include <sys/errno.h> 51#include <sys/sysctl.h> 52#include <net/if.h> 53#include <net/if_dl.h> 54 55#include <netinet/in.h> 56#include <arpa/inet.h> 57#include <netdb.h> 58#include <net/route.h> 59 60#include <stdio.h> 61#include <string.h> 62#include <stdlib.h> 63#include <unistd.h> 64#include <err.h> 65#include <syslog.h> 66#include <stdarg.h> 67 68static int verbose = 0; 69static int debug = 0; 70static int all_events = 0; 71 72#define PROGNAME "ndis_events" 73 74#define WPA_SUPPLICANT_PORT 9876 75#define NDIS_INDICATION_LEN 2048 76 77#define EVENT_CONNECT 0 78#define EVENT_DISCONNECT 1 79#define EVENT_MEDIA_SPECIFIC 2 80 81#define NDIS_STATUS_MEDIA_CONNECT 0x4001000B 82#define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000C 83#define NDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 84 85struct ndis_evt { 86 uint32_t ne_sts; 87 uint32_t ne_len; 88#ifdef notdef 89 char ne_buf[1]; 90#endif 91}; 92 93static int find_ifname(int, char *); 94static int announce_event(char *, int, struct sockaddr_in *); 95static void usage(void); 96 97static void 98dbgmsg(const char *fmt, ...) 99{ 100 va_list ap; 101 102 va_start(ap, fmt); 103 if (debug) 104 vwarnx(fmt, ap); 105 else 106 vsyslog(LOG_ERR, fmt, ap); 107 va_end(ap); 108 109 return; 110} 111 112static int 113find_ifname(idx, name) 114 int idx; 115 char *name; 116{ 117 int mib[6]; 118 size_t needed; 119 struct if_msghdr *ifm; 120 struct sockaddr_dl *sdl; 121 char *buf, *lim, *next; 122 123 needed = 0; 124 mib[0] = CTL_NET; 125 mib[1] = PF_ROUTE; 126 mib[2] = 0; /* protocol */ 127 mib[3] = 0; /* wildcard address family */ 128 mib[4] = NET_RT_IFLIST; 129 mib[5] = 0; /* no flags */ 130 131 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) 132 return(EIO); 133 134 buf = malloc (needed); 135 if (buf == NULL) 136 return(ENOMEM); 137 138 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) { 139 free(buf); 140 return(EIO); 141 } 142 143 lim = buf + needed; 144 145 next = buf; 146 while (next < lim) { 147 ifm = (struct if_msghdr *)next; 148 if (ifm->ifm_type == RTM_IFINFO) { 149 sdl = (struct sockaddr_dl *)(ifm + 1); 150 if (ifm->ifm_index == idx) { 151 strncpy(name, sdl->sdl_data, sdl->sdl_nlen); 152 name[sdl->sdl_nlen] = '\0'; 153 free (buf); 154 return (0); 155 } 156 } 157 next += ifm->ifm_msglen; 158 } 159 160 free (buf); 161 162 return(ENOENT); 163} 164 165static int 166announce_event(ifname, sock, dst) 167 char *ifname; 168 int sock; 169 struct sockaddr_in *dst; 170{ 171 int s; 172 char indication[NDIS_INDICATION_LEN]; 173 struct ifreq ifr; 174 struct ndis_evt *e; 175 char buf[512], *pos, *end; 176 int len, type, _type; 177 178 s = socket(PF_INET, SOCK_DGRAM, 0); 179 180 if (s < 0) { 181 dbgmsg("socket creation failed"); 182 return(EINVAL); 183 } 184 185 bzero((char *)&ifr, sizeof(ifr)); 186 e = (struct ndis_evt *)indication; 187 e->ne_len = NDIS_INDICATION_LEN - sizeof(struct ndis_evt); 188 189 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 190 ifr.ifr_data = indication; 191 192 if (ioctl(s, SIOCGPRIVATE_0, &ifr) < 0) { 193 close(s); 194 if (verbose) { 195 if (errno == ENOENT) 196 dbgmsg("drained all events from %s", 197 ifname, errno); 198 else 199 dbgmsg("failed to read event info from %s: %d", 200 ifname, errno); 201 } 202 return(ENOENT); 203 } 204 205 if (e->ne_sts == NDIS_STATUS_MEDIA_CONNECT) { 206 type = EVENT_CONNECT; 207 if (verbose) 208 dbgmsg("Received a connect event for %s", ifname); 209 if (!all_events) { 210 close(s); 211 return(0); 212 } 213 } 214 if (e->ne_sts == NDIS_STATUS_MEDIA_DISCONNECT) { 215 type = EVENT_DISCONNECT; 216 if (verbose) 217 dbgmsg("Received a disconnect event for %s", ifname); 218 if (!all_events) { 219 close(s); 220 return(0); 221 } 222 } 223 if (e->ne_sts == NDIS_STATUS_MEDIA_SPECIFIC_INDICATION) { 224 type = EVENT_MEDIA_SPECIFIC; 225 if (verbose) 226 dbgmsg("Received a media-specific event for %s", 227 ifname); 228 } 229 230 end = buf + sizeof(buf); 231 _type = (int) type; 232 memcpy(buf, &_type, sizeof(_type)); 233 pos = buf + sizeof(_type); 234 235 len = snprintf(pos + 1, end - pos - 1, "%s", ifname); 236 if (len < 0) { 237 close(s); 238 return(ENOSPC); 239 } 240 if (len > 255) 241 len = 255; 242 *pos = (unsigned char) len; 243 pos += 1 + len; 244 if (e->ne_len) { 245 if (e->ne_len > 255 || 1 + e->ne_len > end - pos) { 246 dbgmsg("Not enough room for send_event data (%d)\n", 247 e->ne_len); 248 close(s); 249 return(ENOSPC); 250 } 251 *pos++ = (unsigned char) e->ne_len; 252 memcpy(pos, (indication) + sizeof(struct ndis_evt), e->ne_len); 253 pos += e->ne_len; 254 } 255 256 len = sendto(sock, buf, pos - buf, 0, (struct sockaddr *) dst, 257 sizeof(struct sockaddr_in)); 258 259 close(s); 260 return(0); 261} 262 263static void 264usage() 265{ 266 fprintf(stderr, "Usage: ndis_events [-a] [-d] [-v]\n"); 267 exit(1); 268} 269 270int 271main(argc, argv) 272 int argc; 273 char *argv[]; 274{ 275 int s, r, n; 276 struct sockaddr_in sin; 277 char msg[NDIS_INDICATION_LEN]; 278 struct rt_msghdr *rtm; 279 struct if_msghdr *ifm; 280 char ifname[IFNAMSIZ]; 281 int ch; 282 283 while ((ch = getopt(argc, argv, "dva")) != -1) { 284 switch(ch) { 285 case 'd': 286 debug++; 287 break; 288 case 'v': 289 verbose++; 290 break; 291 case 'a': 292 all_events++; 293 break; 294 default: 295 usage(); 296 break; 297 } 298 } 299 300 if (!debug && daemon(0, 0)) 301 err(1, "failed to daemonize ourselves"); 302 303 if (!debug) 304 openlog(PROGNAME, LOG_PID | LOG_CONS, LOG_DAEMON); 305 306 bzero((char *)&sin, sizeof(sin)); 307 308 /* Create a datagram socket. */ 309 310 s = socket(PF_INET, SOCK_DGRAM, 0); 311 if (s < 0) { 312 dbgmsg("socket creation failed"); 313 exit(1); 314 } 315 316 sin.sin_family = AF_INET; 317 sin.sin_addr.s_addr = inet_addr("127.0.0.1"); 318 sin.sin_port = htons(WPA_SUPPLICANT_PORT); 319 320 /* Create a routing socket. */ 321 322 r = socket (PF_ROUTE, SOCK_RAW, 0); 323 if (r < 0) { 324 dbgmsg("routing socket creation failed"); 325 exit(1); 326 } 327 328 /* Now sit and spin, waiting for events. */ 329 330 if (verbose) 331 dbgmsg("Listening for events"); 332 333 while (1) { 334 n = read(r, msg, NDIS_INDICATION_LEN); 335 rtm = (struct rt_msghdr *)msg; 336 if (rtm->rtm_type != RTM_IFINFO) 337 continue; 338 ifm = (struct if_msghdr *)msg; 339 if (find_ifname(ifm->ifm_index, ifname)) 340 continue; 341 if (strstr(ifname, "ndis")) { 342 while(announce_event(ifname, s, &sin) == 0) 343 ; 344 } else { 345 if (verbose) 346 dbgmsg("Skipping ifinfo message from %s", 347 ifname); 348 } 349 } 350 351 /* NOTREACHED */ 352 exit(0); 353} 354