Packet32.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/wpa_supplicant/Packet32.c 330897 2018-03-14 03:19:51Z eadler $"); 37 38/* 39 * This file implements a small portion of the Winpcap API for the 40 * Windows NDIS interface in wpa_supplicant. It provides just enough 41 * routines to fool wpa_supplicant into thinking it's really running 42 * in a Windows environment. 43 */ 44 45#include <sys/types.h> 46#include <sys/param.h> 47#include <sys/socket.h> 48#include <sys/ioctl.h> 49#include <sys/errno.h> 50#include <sys/sysctl.h> 51#include <sys/fcntl.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 <net80211/ieee80211_ioctl.h> 61 62#include <stdio.h> 63#include <string.h> 64#include <stdlib.h> 65#include <unistd.h> 66#include <pcap.h> 67 68#include "Packet32.h" 69 70#define OID_802_11_ADD_KEY 0x0d01011D 71 72typedef ULONGLONG NDIS_802_11_KEY_RSC; 73typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; 74 75typedef struct NDIS_802_11_KEY { 76 ULONG Length; 77 ULONG KeyIndex; 78 ULONG KeyLength; 79 NDIS_802_11_MAC_ADDRESS BSSID; 80 NDIS_802_11_KEY_RSC KeyRSC; 81 UCHAR KeyMaterial[1]; 82} NDIS_802_11_KEY; 83 84typedef struct NDIS_802_11_KEY_COMPAT { 85 ULONG Length; 86 ULONG KeyIndex; 87 ULONG KeyLength; 88 NDIS_802_11_MAC_ADDRESS BSSID; 89 UCHAR Pad[6]; /* Make struct layout match Windows. */ 90 NDIS_802_11_KEY_RSC KeyRSC; 91#ifdef notdef 92 UCHAR KeyMaterial[1]; 93#endif 94} NDIS_802_11_KEY_COMPAT; 95 96#define TRUE 1 97#define FALSE 0 98 99struct adapter { 100 int socket; 101 char name[IFNAMSIZ]; 102 int prev_roaming; 103}; 104 105PCHAR 106PacketGetVersion(void) 107{ 108 return("FreeBSD WinPcap compatibility shim v1.0"); 109} 110 111void * 112PacketOpenAdapter(CHAR *iface) 113{ 114 struct adapter *a; 115 int s; 116 int ifflags; 117 struct ifreq ifr; 118 struct ieee80211req ireq; 119 120 s = socket(PF_INET, SOCK_DGRAM, 0); 121 122 if (s == -1) 123 return(NULL); 124 125 a = malloc(sizeof(struct adapter)); 126 if (a == NULL) 127 return(NULL); 128 129 a->socket = s; 130 if (strncmp(iface, "\\Device\\NPF_", 12) == 0) 131 iface += 12; 132 else if (strncmp(iface, "\\DEVICE\\", 8) == 0) 133 iface += 8; 134 snprintf(a->name, IFNAMSIZ, "%s", iface); 135 136 /* Turn off net80211 roaming */ 137 bzero((char *)&ireq, sizeof(ireq)); 138 strncpy(ireq.i_name, iface, sizeof (ifr.ifr_name)); 139 ireq.i_type = IEEE80211_IOC_ROAMING; 140 if (ioctl(a->socket, SIOCG80211, &ireq) == 0) { 141 a->prev_roaming = ireq.i_val; 142 ireq.i_val = IEEE80211_ROAMING_MANUAL; 143 if (ioctl(a->socket, SIOCS80211, &ireq) < 0) 144 fprintf(stderr, 145 "Could not set IEEE80211_ROAMING_MANUAL\n"); 146 } 147 148 bzero((char *)&ifr, sizeof(ifr)); 149 strncpy(ifr.ifr_name, iface, sizeof (ifr.ifr_name)); 150 if (ioctl(a->socket, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { 151 free(a); 152 close(s); 153 return(NULL); 154 } 155 ifr.ifr_flags |= IFF_UP; 156 if (ioctl(a->socket, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) { 157 free(a); 158 close(s); 159 return(NULL); 160 } 161 162 return(a); 163} 164 165int 166PacketRequest(void *iface, BOOLEAN set, PACKET_OID_DATA *oid) 167{ 168 struct adapter *a; 169 uint32_t retval; 170 struct ifreq ifr; 171 NDIS_802_11_KEY *old; 172 NDIS_802_11_KEY_COMPAT *new; 173 PACKET_OID_DATA *o = NULL; 174 175 if (iface == NULL) 176 return(-1); 177 178 a = iface; 179 bzero((char *)&ifr, sizeof(ifr)); 180 181 /* 182 * This hack is necessary to work around a difference 183 * betwee the GNU C and Microsoft C compilers. The NDIS_802_11_KEY 184 * structure has a uint64_t in it, right after an array of 185 * chars. The Microsoft compiler inserts padding right before 186 * the 64-bit value to align it on a 64-bit boundary, but 187 * GCC only aligns it on a 32-bit boundary. Trying to pass 188 * the GCC-formatted structure to an NDIS binary driver 189 * fails because some of the fields appear to be at the 190 * wrong offsets. 191 * 192 * To get around this, if we detect someone is trying to do 193 * a set operation on OID_802_11_ADD_KEY, we shuffle the data 194 * into a properly padded structure and pass that into the 195 * driver instead. This allows the driver_ndis.c code supplied 196 * with wpa_supplicant to work unmodified. 197 */ 198 199 if (set == TRUE && oid->Oid == OID_802_11_ADD_KEY) { 200 old = (NDIS_802_11_KEY *)&oid->Data; 201 o = malloc(sizeof(PACKET_OID_DATA) + 202 sizeof(NDIS_802_11_KEY_COMPAT) + old->KeyLength); 203 if (o == NULL) 204 return(0); 205 bzero((char *)o, sizeof(PACKET_OID_DATA) + 206 sizeof(NDIS_802_11_KEY_COMPAT) + old->KeyLength); 207 o->Oid = oid->Oid; 208 o->Length = sizeof(NDIS_802_11_KEY_COMPAT) + old->KeyLength; 209 new = (NDIS_802_11_KEY_COMPAT *)&o->Data; 210 new->KeyRSC = old->KeyRSC; 211 new->Length = o->Length; 212 new->KeyIndex = old->KeyIndex; 213 new->KeyLength = old->KeyLength; 214 bcopy(old->BSSID, new->BSSID, sizeof(NDIS_802_11_MAC_ADDRESS)); 215 bcopy(old->KeyMaterial, (char *)new + 216 sizeof(NDIS_802_11_KEY_COMPAT), new->KeyLength); 217 ifr.ifr_data = (caddr_t)o; 218 } else 219 ifr.ifr_data = (caddr_t)oid; 220 221 strlcpy(ifr.ifr_name, a->name, sizeof(ifr.ifr_name)); 222 223 if (set == TRUE) 224 retval = ioctl(a->socket, SIOCSDRVSPEC, &ifr); 225 else 226 retval = ioctl(a->socket, SIOCGDRVSPEC, &ifr); 227 228 if (o != NULL) 229 free(o); 230 231 if (retval) 232 return(0); 233 234 return(1); 235} 236 237int 238PacketGetAdapterNames(CHAR *namelist, ULONG *len) 239{ 240 int mib[6]; 241 size_t needed; 242 struct if_msghdr *ifm; 243 struct sockaddr_dl *sdl; 244 char *buf, *lim, *next; 245 char *plist; 246 int spc; 247 int i, ifcnt = 0; 248 249 plist = namelist; 250 spc = 0; 251 252 bzero(plist, *len); 253 254 needed = 0; 255 mib[0] = CTL_NET; 256 mib[1] = PF_ROUTE; 257 mib[2] = 0; /* protocol */ 258 mib[3] = 0; /* wildcard address family */ 259 mib[4] = NET_RT_IFLIST; 260 mib[5] = 0; /* no flags */ 261 262 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) 263 return(FALSE); 264 265 buf = malloc (needed); 266 if (buf == NULL) 267 return(FALSE); 268 269 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) { 270 free(buf); 271 return(FALSE); 272 } 273 274 lim = buf + needed; 275 276 /* Generate interface name list. */ 277 278 next = buf; 279 while (next < lim) { 280 ifm = (struct if_msghdr *)next; 281 if (ifm->ifm_type == RTM_IFINFO) { 282 sdl = (struct sockaddr_dl *)(ifm + 1); 283 if (strnstr(sdl->sdl_data, "wlan", sdl->sdl_nlen)) { 284 if ((spc + sdl->sdl_nlen) > *len) { 285 free(buf); 286 return(FALSE); 287 } 288 strncpy(plist, sdl->sdl_data, sdl->sdl_nlen); 289 plist += (sdl->sdl_nlen + 1); 290 spc += (sdl->sdl_nlen + 1); 291 ifcnt++; 292 } 293 } 294 next += ifm->ifm_msglen; 295 } 296 297 298 /* Insert an extra "" as a spacer */ 299 300 plist++; 301 spc++; 302 303 /* 304 * Now generate the interface description list. There 305 * must be a unique description for each interface, and 306 * they have to match what the ndis_events program will 307 * feed in later. To keep this simple, we just repeat 308 * the interface list over again. 309 */ 310 311 next = buf; 312 while (next < lim) { 313 ifm = (struct if_msghdr *)next; 314 if (ifm->ifm_type == RTM_IFINFO) { 315 sdl = (struct sockaddr_dl *)(ifm + 1); 316 if (strnstr(sdl->sdl_data, "wlan", sdl->sdl_nlen)) { 317 if ((spc + sdl->sdl_nlen) > *len) { 318 free(buf); 319 return(FALSE); 320 } 321 strncpy(plist, sdl->sdl_data, sdl->sdl_nlen); 322 plist += (sdl->sdl_nlen + 1); 323 spc += (sdl->sdl_nlen + 1); 324 ifcnt++; 325 } 326 } 327 next += ifm->ifm_msglen; 328 } 329 330 free (buf); 331 332 *len = spc + 1; 333 334 return(TRUE); 335} 336 337void 338PacketCloseAdapter(void *iface) 339{ 340 struct adapter *a; 341 struct ifreq ifr; 342 struct ieee80211req ireq; 343 344 if (iface == NULL) 345 return; 346 347 a = iface; 348 349 /* Reset net80211 roaming */ 350 bzero((char *)&ireq, sizeof(ireq)); 351 strncpy(ireq.i_name, a->name, sizeof (ifr.ifr_name)); 352 ireq.i_type = IEEE80211_IOC_ROAMING; 353 ireq.i_val = a->prev_roaming; 354 ioctl(a->socket, SIOCS80211, &ireq); 355 356 bzero((char *)&ifr, sizeof(ifr)); 357 strncpy(ifr.ifr_name, a->name, sizeof (ifr.ifr_name)); 358 ioctl(a->socket, SIOCGIFFLAGS, (caddr_t)&ifr); 359 ifr.ifr_flags &= ~IFF_UP; 360 ioctl(a->socket, SIOCSIFFLAGS, (caddr_t)&ifr); 361 close(a->socket); 362 free(a); 363 364 return; 365} 366 367#if __FreeBSD_version < 600000 368 369/* 370 * The version of libpcap in FreeBSD 5.2.1 doesn't have these routines. 371 * Call me insane if you will, but I still run 5.2.1 on my laptop, and 372 * I'd like to use WPA there. 373 */ 374 375int 376pcap_get_selectable_fd(pcap_t *p) 377{ 378 return(pcap_fileno(p)); 379} 380 381/* 382 * The old version of libpcap opens its BPF descriptor in read-only 383 * mode. We need to temporarily create a new one we can write to. 384 */ 385 386int 387pcap_inject(pcap_t *p, const void *buf, size_t len) 388{ 389 int fd; 390 int res, n = 0; 391 char device[sizeof "/dev/bpf0000000000"]; 392 struct ifreq ifr; 393 394 /* 395 * Go through all the minors and find one that isn't in use. 396 */ 397 do { 398 (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++); 399 fd = open(device, O_RDWR); 400 } while (fd < 0 && errno == EBUSY); 401 402 if (fd == -1) 403 return(-1); 404 405 bzero((char *)&ifr, sizeof(ifr)); 406 ioctl(pcap_fileno(p), BIOCGETIF, (caddr_t)&ifr); 407 ioctl(fd, BIOCSETIF, (caddr_t)&ifr); 408 409 res = write(fd, buf, len); 410 411 close(fd); 412 413 return(res); 414} 415#endif 416