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$"); 35151214Swpaul 36151214Swpaul/* 37151214Swpaul * This file implements a small portion of the Winpcap API for the 38151214Swpaul * Windows NDIS interface in wpa_supplicant. It provides just enough 39151214Swpaul * routines to fool wpa_supplicant into thinking it's really running 40151214Swpaul * in a Windows environment. 41151214Swpaul */ 42151214Swpaul 43151214Swpaul#include <sys/types.h> 44151214Swpaul#include <sys/param.h> 45151214Swpaul#include <sys/socket.h> 46151214Swpaul#include <sys/ioctl.h> 47151214Swpaul#include <sys/errno.h> 48151214Swpaul#include <sys/sysctl.h> 49151214Swpaul#include <sys/fcntl.h> 50151214Swpaul#include <net/if.h> 51151214Swpaul#include <net/if_dl.h> 52151214Swpaul#include <net/if_var.h> 53151214Swpaul 54151214Swpaul#include <netinet/in.h> 55151214Swpaul#include <arpa/inet.h> 56151214Swpaul#include <netdb.h> 57151214Swpaul#include <net/route.h> 58151214Swpaul 59171371Ssam#include <net80211/ieee80211_ioctl.h> 60171371Ssam 61151214Swpaul#include <stdio.h> 62151214Swpaul#include <string.h> 63151214Swpaul#include <stdlib.h> 64151214Swpaul#include <unistd.h> 65151214Swpaul#include <pcap.h> 66151214Swpaul 67151214Swpaul#include "Packet32.h" 68151214Swpaul 69151214Swpaul#define OID_802_11_ADD_KEY 0x0d01011D 70151214Swpaul 71151214Swpaultypedef ULONGLONG NDIS_802_11_KEY_RSC; 72151214Swpaultypedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; 73151214Swpaul 74151214Swpaultypedef struct NDIS_802_11_KEY { 75151214Swpaul ULONG Length; 76151214Swpaul ULONG KeyIndex; 77151214Swpaul ULONG KeyLength; 78151214Swpaul NDIS_802_11_MAC_ADDRESS BSSID; 79151214Swpaul NDIS_802_11_KEY_RSC KeyRSC; 80151214Swpaul UCHAR KeyMaterial[1]; 81151214Swpaul} NDIS_802_11_KEY; 82151214Swpaul 83151214Swpaultypedef struct NDIS_802_11_KEY_COMPAT { 84151214Swpaul ULONG Length; 85151214Swpaul ULONG KeyIndex; 86151214Swpaul ULONG KeyLength; 87151214Swpaul NDIS_802_11_MAC_ADDRESS BSSID; 88151214Swpaul UCHAR Pad[6]; /* Make struct layout match Windows. */ 89151214Swpaul NDIS_802_11_KEY_RSC KeyRSC; 90151214Swpaul#ifdef notdef 91151214Swpaul UCHAR KeyMaterial[1]; 92151214Swpaul#endif 93151214Swpaul} NDIS_802_11_KEY_COMPAT; 94151214Swpaul 95151214Swpaul#define TRUE 1 96151214Swpaul#define FALSE 0 97151214Swpaul 98151214Swpaulstruct adapter { 99151214Swpaul int socket; 100151214Swpaul char name[IFNAMSIZ]; 101171371Ssam int prev_roaming; 102151214Swpaul}; 103151214Swpaul 104151517SwpaulPCHAR 105151517SwpaulPacketGetVersion(void) 106151517Swpaul{ 107151517Swpaul return("FreeBSD WinPcap compatibility shim v1.0"); 108151517Swpaul} 109151517Swpaul 110151214Swpaulvoid * 111189220SsamPacketOpenAdapter(CHAR *iface) 112151214Swpaul{ 113151214Swpaul struct adapter *a; 114151214Swpaul int s; 115151214Swpaul int ifflags; 116151214Swpaul struct ifreq ifr; 117171371Ssam struct ieee80211req ireq; 118151214Swpaul 119151214Swpaul s = socket(PF_INET, SOCK_DGRAM, 0); 120151214Swpaul 121151214Swpaul if (s == -1) 122151214Swpaul return(NULL); 123151214Swpaul 124151214Swpaul a = malloc(sizeof(struct adapter)); 125151214Swpaul if (a == NULL) 126151214Swpaul return(NULL); 127151214Swpaul 128151214Swpaul a->socket = s; 129171371Ssam if (strncmp(iface, "\\Device\\NPF_", 12) == 0) 130171371Ssam iface += 12; 131171371Ssam else if (strncmp(iface, "\\DEVICE\\", 8) == 0) 132171371Ssam iface += 8; 133151214Swpaul snprintf(a->name, IFNAMSIZ, "%s", iface); 134151214Swpaul 135171371Ssam /* Turn off net80211 roaming */ 136171371Ssam bzero((char *)&ireq, sizeof(ireq)); 137171371Ssam strncpy(ireq.i_name, iface, sizeof (ifr.ifr_name)); 138171371Ssam ireq.i_type = IEEE80211_IOC_ROAMING; 139171371Ssam if (ioctl(a->socket, SIOCG80211, &ireq) == 0) { 140171371Ssam a->prev_roaming = ireq.i_val; 141171371Ssam ireq.i_val = IEEE80211_ROAMING_MANUAL; 142171371Ssam if (ioctl(a->socket, SIOCS80211, &ireq) < 0) 143171371Ssam fprintf(stderr, 144171371Ssam "Could not set IEEE80211_ROAMING_MANUAL\n"); 145171371Ssam } 146171371Ssam 147151214Swpaul bzero((char *)&ifr, sizeof(ifr)); 148151214Swpaul strncpy(ifr.ifr_name, iface, sizeof (ifr.ifr_name)); 149151214Swpaul if (ioctl(a->socket, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { 150151214Swpaul free(a); 151151214Swpaul close(s); 152151214Swpaul return(NULL); 153151214Swpaul } 154151214Swpaul ifr.ifr_flags |= IFF_UP; 155151214Swpaul if (ioctl(a->socket, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) { 156151214Swpaul free(a); 157151214Swpaul close(s); 158151214Swpaul return(NULL); 159151214Swpaul } 160151214Swpaul 161151214Swpaul return(a); 162151214Swpaul} 163151214Swpaul 164151214Swpaulint 165189220SsamPacketRequest(void *iface, BOOLEAN set, PACKET_OID_DATA *oid) 166151214Swpaul{ 167151214Swpaul struct adapter *a; 168151214Swpaul uint32_t retval; 169151214Swpaul struct ifreq ifr; 170151214Swpaul NDIS_802_11_KEY *old; 171151214Swpaul NDIS_802_11_KEY_COMPAT *new; 172151214Swpaul PACKET_OID_DATA *o = NULL; 173151214Swpaul 174151214Swpaul if (iface == NULL) 175151214Swpaul return(-1); 176151214Swpaul 177151214Swpaul a = iface; 178151214Swpaul bzero((char *)&ifr, sizeof(ifr)); 179151214Swpaul 180151214Swpaul /* 181151214Swpaul * This hack is necessary to work around a difference 182151214Swpaul * betwee the GNU C and Microsoft C compilers. The NDIS_802_11_KEY 183151214Swpaul * structure has a uint64_t in it, right after an array of 184151214Swpaul * chars. The Microsoft compiler inserts padding right before 185151214Swpaul * the 64-bit value to align it on a 64-bit boundary, but 186151214Swpaul * GCC only aligns it on a 32-bit boundary. Trying to pass 187151214Swpaul * the GCC-formatted structure to an NDIS binary driver 188151214Swpaul * fails because some of the fields appear to be at the 189151214Swpaul * wrong offsets. 190151214Swpaul * 191151214Swpaul * To get around this, if we detect someone is trying to do 192151214Swpaul * a set operation on OID_802_11_ADD_KEY, we shuffle the data 193151214Swpaul * into a properly padded structure and pass that into the 194151214Swpaul * driver instead. This allows the driver_ndis.c code supplied 195151214Swpaul * with wpa_supplicant to work unmodified. 196151214Swpaul */ 197151214Swpaul 198151214Swpaul if (set == TRUE && oid->Oid == OID_802_11_ADD_KEY) { 199151214Swpaul old = (NDIS_802_11_KEY *)&oid->Data; 200151214Swpaul o = malloc(sizeof(PACKET_OID_DATA) + 201151214Swpaul sizeof(NDIS_802_11_KEY_COMPAT) + old->KeyLength); 202151214Swpaul if (o == NULL) 203151214Swpaul return(0); 204151214Swpaul bzero((char *)o, sizeof(PACKET_OID_DATA) + 205151214Swpaul sizeof(NDIS_802_11_KEY_COMPAT) + old->KeyLength); 206151214Swpaul o->Oid = oid->Oid; 207151214Swpaul o->Length = sizeof(NDIS_802_11_KEY_COMPAT) + old->KeyLength; 208151214Swpaul new = (NDIS_802_11_KEY_COMPAT *)&o->Data; 209151214Swpaul new->KeyRSC = old->KeyRSC; 210151214Swpaul new->Length = o->Length; 211151214Swpaul new->KeyIndex = old->KeyIndex; 212151214Swpaul new->KeyLength = old->KeyLength; 213151214Swpaul bcopy(old->BSSID, new->BSSID, sizeof(NDIS_802_11_MAC_ADDRESS)); 214151214Swpaul bcopy(old->KeyMaterial, (char *)new + 215151214Swpaul sizeof(NDIS_802_11_KEY_COMPAT), new->KeyLength); 216151214Swpaul ifr.ifr_data = (caddr_t)o; 217151214Swpaul } else 218151214Swpaul ifr.ifr_data = (caddr_t)oid; 219151214Swpaul 220151214Swpaul strlcpy(ifr.ifr_name, a->name, sizeof(ifr.ifr_name)); 221151214Swpaul 222151214Swpaul if (set == TRUE) 223151214Swpaul retval = ioctl(a->socket, SIOCSDRVSPEC, &ifr); 224151214Swpaul else 225151214Swpaul retval = ioctl(a->socket, SIOCGDRVSPEC, &ifr); 226151214Swpaul 227151214Swpaul if (o != NULL) 228151214Swpaul free(o); 229151214Swpaul 230151214Swpaul if (retval) 231151214Swpaul return(0); 232151214Swpaul 233151214Swpaul return(1); 234151214Swpaul} 235151214Swpaul 236151214Swpaulint 237189220SsamPacketGetAdapterNames(CHAR *namelist, ULONG *len) 238151214Swpaul{ 239151214Swpaul int mib[6]; 240151214Swpaul size_t needed; 241151214Swpaul struct if_msghdr *ifm; 242151214Swpaul struct sockaddr_dl *sdl; 243151214Swpaul char *buf, *lim, *next; 244151214Swpaul char *plist; 245151214Swpaul int spc; 246151214Swpaul int i, ifcnt = 0; 247151214Swpaul 248151214Swpaul plist = namelist; 249151214Swpaul spc = 0; 250151214Swpaul 251151214Swpaul bzero(plist, *len); 252151214Swpaul 253151214Swpaul needed = 0; 254151214Swpaul mib[0] = CTL_NET; 255151214Swpaul mib[1] = PF_ROUTE; 256151214Swpaul mib[2] = 0; /* protocol */ 257151214Swpaul mib[3] = 0; /* wildcard address family */ 258151214Swpaul mib[4] = NET_RT_IFLIST; 259151214Swpaul mib[5] = 0; /* no flags */ 260151214Swpaul 261151214Swpaul if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) 262157687Ssam return(FALSE); 263151214Swpaul 264151214Swpaul buf = malloc (needed); 265151214Swpaul if (buf == NULL) 266157687Ssam return(FALSE); 267151214Swpaul 268151214Swpaul if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) { 269151214Swpaul free(buf); 270157687Ssam return(FALSE); 271151214Swpaul } 272151214Swpaul 273151214Swpaul lim = buf + needed; 274151214Swpaul 275151214Swpaul /* Generate interface name list. */ 276151214Swpaul 277151214Swpaul next = buf; 278151214Swpaul while (next < lim) { 279151214Swpaul ifm = (struct if_msghdr *)next; 280151214Swpaul if (ifm->ifm_type == RTM_IFINFO) { 281151214Swpaul sdl = (struct sockaddr_dl *)(ifm + 1); 282178358Ssam if (strnstr(sdl->sdl_data, "wlan", sdl->sdl_nlen)) { 283151214Swpaul if ((spc + sdl->sdl_nlen) > *len) { 284151214Swpaul free(buf); 285157687Ssam return(FALSE); 286151214Swpaul } 287151214Swpaul strncpy(plist, sdl->sdl_data, sdl->sdl_nlen); 288151214Swpaul plist += (sdl->sdl_nlen + 1); 289151214Swpaul spc += (sdl->sdl_nlen + 1); 290151214Swpaul ifcnt++; 291151214Swpaul } 292151214Swpaul } 293151214Swpaul next += ifm->ifm_msglen; 294151214Swpaul } 295151214Swpaul 296151214Swpaul 297151214Swpaul /* Insert an extra "" as a spacer */ 298151214Swpaul 299151214Swpaul plist++; 300151214Swpaul spc++; 301151214Swpaul 302151214Swpaul /* 303151214Swpaul * Now generate the interface description list. There 304151214Swpaul * must be a unique description for each interface, and 305151214Swpaul * they have to match what the ndis_events program will 306151214Swpaul * feed in later. To keep this simple, we just repeat 307151214Swpaul * the interface list over again. 308151214Swpaul */ 309151214Swpaul 310151214Swpaul next = buf; 311151214Swpaul while (next < lim) { 312151214Swpaul ifm = (struct if_msghdr *)next; 313151214Swpaul if (ifm->ifm_type == RTM_IFINFO) { 314151214Swpaul sdl = (struct sockaddr_dl *)(ifm + 1); 315178358Ssam if (strnstr(sdl->sdl_data, "wlan", sdl->sdl_nlen)) { 316151214Swpaul if ((spc + sdl->sdl_nlen) > *len) { 317151214Swpaul free(buf); 318157687Ssam return(FALSE); 319151214Swpaul } 320151214Swpaul strncpy(plist, sdl->sdl_data, sdl->sdl_nlen); 321151214Swpaul plist += (sdl->sdl_nlen + 1); 322151214Swpaul spc += (sdl->sdl_nlen + 1); 323151214Swpaul ifcnt++; 324151214Swpaul } 325151214Swpaul } 326151214Swpaul next += ifm->ifm_msglen; 327151214Swpaul } 328151214Swpaul 329151214Swpaul free (buf); 330151214Swpaul 331151214Swpaul *len = spc + 1; 332151214Swpaul 333157687Ssam return(TRUE); 334151214Swpaul} 335151214Swpaul 336151214Swpaulvoid 337189220SsamPacketCloseAdapter(void *iface) 338151214Swpaul{ 339151214Swpaul struct adapter *a; 340151214Swpaul struct ifreq ifr; 341171371Ssam struct ieee80211req ireq; 342151214Swpaul 343151214Swpaul if (iface == NULL) 344151214Swpaul return; 345151214Swpaul 346151214Swpaul a = iface; 347151214Swpaul 348171371Ssam /* Reset net80211 roaming */ 349171371Ssam bzero((char *)&ireq, sizeof(ireq)); 350171371Ssam strncpy(ireq.i_name, a->name, sizeof (ifr.ifr_name)); 351171371Ssam ireq.i_type = IEEE80211_IOC_ROAMING; 352171371Ssam ireq.i_val = a->prev_roaming; 353171371Ssam ioctl(a->socket, SIOCS80211, &ireq); 354171371Ssam 355151214Swpaul bzero((char *)&ifr, sizeof(ifr)); 356151214Swpaul strncpy(ifr.ifr_name, a->name, sizeof (ifr.ifr_name)); 357151214Swpaul ioctl(a->socket, SIOCGIFFLAGS, (caddr_t)&ifr); 358151214Swpaul ifr.ifr_flags &= ~IFF_UP; 359151214Swpaul ioctl(a->socket, SIOCSIFFLAGS, (caddr_t)&ifr); 360151214Swpaul close(a->socket); 361151214Swpaul free(a); 362151214Swpaul 363151214Swpaul return; 364151214Swpaul} 365151214Swpaul 366151214Swpaul#if __FreeBSD_version < 600000 367151214Swpaul 368151214Swpaul/* 369151214Swpaul * The version of libpcap in FreeBSD 5.2.1 doesn't have these routines. 370151214Swpaul * Call me insane if you will, but I still run 5.2.1 on my laptop, and 371151214Swpaul * I'd like to use WPA there. 372151214Swpaul */ 373151214Swpaul 374151214Swpaulint 375151214Swpaulpcap_get_selectable_fd(pcap_t *p) 376151214Swpaul{ 377151214Swpaul return(pcap_fileno(p)); 378151214Swpaul} 379151214Swpaul 380151214Swpaul/* 381151214Swpaul * The old version of libpcap opens its BPF descriptor in read-only 382151214Swpaul * mode. We need to temporarily create a new one we can write to. 383151214Swpaul */ 384151214Swpaul 385151214Swpaulint 386151214Swpaulpcap_inject(pcap_t *p, const void *buf, size_t len) 387151214Swpaul{ 388151214Swpaul int fd; 389151214Swpaul int res, n = 0; 390151214Swpaul char device[sizeof "/dev/bpf0000000000"]; 391151214Swpaul struct ifreq ifr; 392151214Swpaul 393151214Swpaul /* 394151214Swpaul * Go through all the minors and find one that isn't in use. 395151214Swpaul */ 396151214Swpaul do { 397151214Swpaul (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++); 398151214Swpaul fd = open(device, O_RDWR); 399151214Swpaul } while (fd < 0 && errno == EBUSY); 400151214Swpaul 401151214Swpaul if (fd == -1) 402151214Swpaul return(-1); 403151214Swpaul 404151214Swpaul bzero((char *)&ifr, sizeof(ifr)); 405151214Swpaul ioctl(pcap_fileno(p), BIOCGETIF, (caddr_t)&ifr); 406151214Swpaul ioctl(fd, BIOCSETIF, (caddr_t)&ifr); 407151214Swpaul 408151214Swpaul res = write(fd, buf, len); 409151214Swpaul 410151214Swpaul close(fd); 411151214Swpaul 412151214Swpaul return(res); 413151214Swpaul} 414151214Swpaul#endif 415