Remove unused files.
This commit is contained in:
parent
85afbc31fa
commit
4f95cb6e9c
@ -1,156 +0,0 @@
|
|||||||
#ifndef APPLE80211_H
|
|
||||||
#define APPLE80211_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Apple80211 framework definitions
|
|
||||||
* This is an undocumented interface and the definitions here are based on
|
|
||||||
* information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and
|
|
||||||
* whatever related information can be found with google and experiments ;-).
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct __WirelessRef *WirelessRef;
|
|
||||||
typedef SInt32 WirelessError;
|
|
||||||
#define errWirelessNoError 0
|
|
||||||
|
|
||||||
typedef struct WirelessInfo {
|
|
||||||
UInt16 link_qual;
|
|
||||||
UInt16 comms_qual;
|
|
||||||
UInt16 signal;
|
|
||||||
UInt16 noise;
|
|
||||||
UInt16 port_stat;
|
|
||||||
UInt16 client_mode;
|
|
||||||
UInt16 res1;
|
|
||||||
UInt16 power;
|
|
||||||
UInt16 res2;
|
|
||||||
UInt8 bssID[6];
|
|
||||||
UInt8 ssid[34];
|
|
||||||
} WirelessInfo;
|
|
||||||
|
|
||||||
typedef struct WirelessInfo2 {
|
|
||||||
/* TODO - these are probably not in correct order or complete */
|
|
||||||
WirelessInfo info1;
|
|
||||||
UInt8 macAddress[6];
|
|
||||||
} WirelessInfo2;
|
|
||||||
|
|
||||||
typedef struct WirelessNetworkInfo {
|
|
||||||
UInt16 channel;
|
|
||||||
UInt16 noise;
|
|
||||||
UInt16 signal;
|
|
||||||
UInt8 bssid[6];
|
|
||||||
UInt16 beacon_int;
|
|
||||||
UInt16 capability;
|
|
||||||
UInt16 ssid_len;
|
|
||||||
UInt8 ssid[32];
|
|
||||||
} WirelessNetworkInfo;
|
|
||||||
|
|
||||||
typedef int wirelessKeyType; /* TODO */
|
|
||||||
|
|
||||||
int WirelessIsAvailable(void);
|
|
||||||
WirelessError WirelessAttach(WirelessRef *ref, UInt32 res);
|
|
||||||
WirelessError WirelessDetach(WirelessRef ref);
|
|
||||||
WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes,
|
|
||||||
void *out_ptr, int out_bytes);
|
|
||||||
WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled);
|
|
||||||
WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled);
|
|
||||||
WirelessError WirelessSetPower(WirelessRef ref, UInt8 power);
|
|
||||||
WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power);
|
|
||||||
WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info);
|
|
||||||
WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info);
|
|
||||||
WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results,
|
|
||||||
UInt32 strip_dups);
|
|
||||||
WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results,
|
|
||||||
CFArrayRef *ibss_results, UInt32 strip_dups);
|
|
||||||
WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results,
|
|
||||||
UInt32 strip_dups, CFStringRef ssid);
|
|
||||||
WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid,
|
|
||||||
UInt32 strip_dups, CFArrayRef *results);
|
|
||||||
WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid);
|
|
||||||
WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid,
|
|
||||||
CFStringRef passwd);
|
|
||||||
WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid);
|
|
||||||
/*
|
|
||||||
* Set WEP key
|
|
||||||
* ref: wireless reference from WirelessAttach()
|
|
||||||
* type: ?
|
|
||||||
* key_idx: 0..3
|
|
||||||
* key_len: 13 for WEP-104 or 0 for clearing the key
|
|
||||||
* key: Pointer to the key or %NULL if key_len = 0
|
|
||||||
*/
|
|
||||||
WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type,
|
|
||||||
int key_idx, int key_len,
|
|
||||||
const unsigned char *key);
|
|
||||||
/*
|
|
||||||
* Set WPA key (e.g., PMK for 4-way handshake)
|
|
||||||
* ref: wireless reference from WirelessAttach()
|
|
||||||
* type: 0..4; 1 = PMK
|
|
||||||
* key_len: 16, 32, or 0
|
|
||||||
* key: Pointer to the key or %NULL if key_len = 0
|
|
||||||
*/
|
|
||||||
WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type,
|
|
||||||
int key_len, const unsigned char *key);
|
|
||||||
WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid,
|
|
||||||
CFStringRef key);
|
|
||||||
WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res,
|
|
||||||
CFStringRef key);
|
|
||||||
WirelessError WirelessDisassociate(WirelessRef ref);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get a copy of scan results for the given SSID
|
|
||||||
* The returned dictionary includes following entries:
|
|
||||||
* beaconInterval: CFNumber(kCFNumberSInt32Type)
|
|
||||||
* SSID: CFData buffer of the SSID
|
|
||||||
* isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2
|
|
||||||
* name: Name of the network (SSID string)
|
|
||||||
* BSSID: CFData buffer of the BSSID
|
|
||||||
* channel: CFNumber(kCFNumberSInt32Type)
|
|
||||||
* signal: CFNumber(kCFNumberSInt32Type)
|
|
||||||
* appleIE: CFData
|
|
||||||
* WPSNOPINRequired: CFBoolean
|
|
||||||
* noise: CFNumber(kCFNumberSInt32Type)
|
|
||||||
* capability: CFNumber(kCFNumberSInt32Type)
|
|
||||||
* uniCipher: CFArray of CFNumber(kCFNumberSInt32Type)
|
|
||||||
* appleIE_Version: CFNumber(kCFNumberSInt32Type)
|
|
||||||
* appleIE_Robust: CFBoolean
|
|
||||||
* WPSConfigured: CFBoolean
|
|
||||||
* scanWasDirected: CFBoolean
|
|
||||||
* appleIE_Product: CFNumber(kCFNumberSInt32Type)
|
|
||||||
* authModes: CFArray of CFNumber(kCFNumberSInt32Type)
|
|
||||||
* multiCipher: CFNumber(kCFNumberSInt32Type)
|
|
||||||
*/
|
|
||||||
CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get information about the current association
|
|
||||||
* The returned dictionary includes following entries:
|
|
||||||
* keyData: CFData buffer of the key (e.g., 32-octet PSK)
|
|
||||||
* multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP?
|
|
||||||
* channel: CFNumber(kCFNumberSInt32Type)
|
|
||||||
* isIBSS: CFBoolean
|
|
||||||
* authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open,
|
|
||||||
* 129 = WPA2-Enterprise
|
|
||||||
* isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2
|
|
||||||
* SSID: CFData buffer of the SSID
|
|
||||||
* cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP?
|
|
||||||
*/
|
|
||||||
CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref);
|
|
||||||
|
|
||||||
WirelessError WirelessConfigure(WirelessRef ref);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get ASP information
|
|
||||||
* The returned dictionary includes following entries:
|
|
||||||
* Version: version number (e.g., 3.0)
|
|
||||||
* Channel: channel (e.g., 1)
|
|
||||||
* Vendor: vendor (e.g., 2)
|
|
||||||
*/
|
|
||||||
CFDictionaryRef WirelessGetInfoASP(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get a copy of the interface dictionary
|
|
||||||
* The returned dictionary has a key,value pairs for wireless interfaces.
|
|
||||||
* The key is the interface name and the value is the driver identifier, e.g.,
|
|
||||||
* en1: com.apple.driver.AirPort.Atheros
|
|
||||||
*/
|
|
||||||
CFDictionaryRef WirelessCopyInterfaceDict(void);
|
|
||||||
|
|
||||||
#endif /* APPLE80211_H */
|
|
@ -1,189 +0,0 @@
|
|||||||
#include "includes.h"
|
|
||||||
#include <dlfcn.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
|
||||||
#include "MobileApple80211.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Code for dynamically loading Apple80211 functions from Aeropuerto to avoid
|
|
||||||
* having to link with full Preferences.framework.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void *aeropuerto = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
int _Apple80211Initialized(void)
|
|
||||||
{
|
|
||||||
return aeropuerto ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL;
|
|
||||||
|
|
||||||
int Apple80211Open(Apple80211Ref *ctx)
|
|
||||||
{
|
|
||||||
return __Apple80211Open(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL;
|
|
||||||
|
|
||||||
int Apple80211Close(Apple80211Ref ctx)
|
|
||||||
{
|
|
||||||
return __Apple80211Close(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list)
|
|
||||||
= NULL;
|
|
||||||
|
|
||||||
int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list)
|
|
||||||
{
|
|
||||||
return __Apple80211GetIfListCopy(handle, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int (*__Apple80211BindToInterface)(Apple80211Ref handle,
|
|
||||||
CFStringRef interface) = NULL;
|
|
||||||
|
|
||||||
int Apple80211BindToInterface(Apple80211Ref handle,
|
|
||||||
CFStringRef interface)
|
|
||||||
{
|
|
||||||
return __Apple80211BindToInterface(handle, interface);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle,
|
|
||||||
CFStringRef *name) = NULL;
|
|
||||||
|
|
||||||
int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
|
|
||||||
CFStringRef *name)
|
|
||||||
{
|
|
||||||
return __Apple80211GetInterfaceNameCopy(handle, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle,
|
|
||||||
CFDictionaryRef *info) = NULL;
|
|
||||||
|
|
||||||
int Apple80211GetInfoCopy(Apple80211Ref handle,
|
|
||||||
CFDictionaryRef *info)
|
|
||||||
{
|
|
||||||
return __Apple80211GetInfoCopy(handle, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL;
|
|
||||||
|
|
||||||
int Apple80211GetPower(Apple80211Ref handle, char *pwr)
|
|
||||||
{
|
|
||||||
return __Apple80211GetPower(handle, pwr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL;
|
|
||||||
|
|
||||||
int Apple80211SetPower(Apple80211Ref handle, char pwr)
|
|
||||||
{
|
|
||||||
return __Apple80211SetPower(handle, pwr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list,
|
|
||||||
CFDictionaryRef parameters) = NULL;
|
|
||||||
|
|
||||||
int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
|
|
||||||
CFDictionaryRef parameters)
|
|
||||||
{
|
|
||||||
return __Apple80211Scan(handle, list, parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss,
|
|
||||||
CFStringRef password) = NULL;
|
|
||||||
|
|
||||||
int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
|
|
||||||
CFStringRef password)
|
|
||||||
{
|
|
||||||
return __Apple80211Associate(handle, bss, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle,
|
|
||||||
CFDictionaryRef bss,
|
|
||||||
CFStringRef password,
|
|
||||||
CFDictionaryRef *info) =
|
|
||||||
NULL;
|
|
||||||
|
|
||||||
int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
|
|
||||||
CFStringRef password, CFDictionaryRef *info)
|
|
||||||
{
|
|
||||||
return __Apple80211AssociateAndCopyInfo(handle, bss, password, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field,
|
|
||||||
CFDictionaryRef arg2, void *value) = NULL;
|
|
||||||
|
|
||||||
int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
|
|
||||||
void *value)
|
|
||||||
{
|
|
||||||
return __Apple80211CopyValue(handle, field, arg2, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define DLSYM(s) \
|
|
||||||
do { \
|
|
||||||
__ ## s = dlsym(aeropuerto, #s); \
|
|
||||||
if (__ ## s == NULL) { \
|
|
||||||
wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \
|
|
||||||
"symbol '" #s "' (%s)", dlerror()); \
|
|
||||||
err = 1; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
__attribute__ ((constructor))
|
|
||||||
void _Apple80211_constructor(void)
|
|
||||||
{
|
|
||||||
const char *fname = "/System/Library/SystemConfiguration/"
|
|
||||||
"Aeropuerto.bundle/Aeropuerto";
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
aeropuerto = dlopen(fname, RTLD_LAZY);
|
|
||||||
if (!aeropuerto) {
|
|
||||||
wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s "
|
|
||||||
"for symbols", fname);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DLSYM(Apple80211Open);
|
|
||||||
DLSYM(Apple80211Close);
|
|
||||||
DLSYM(Apple80211GetIfListCopy);
|
|
||||||
DLSYM(Apple80211BindToInterface);
|
|
||||||
DLSYM(Apple80211GetInterfaceNameCopy);
|
|
||||||
DLSYM(Apple80211GetInfoCopy);
|
|
||||||
DLSYM(Apple80211GetPower);
|
|
||||||
DLSYM(Apple80211SetPower);
|
|
||||||
DLSYM(Apple80211Scan);
|
|
||||||
DLSYM(Apple80211Associate);
|
|
||||||
DLSYM(Apple80211AssociateAndCopyInfo);
|
|
||||||
DLSYM(Apple80211CopyValue);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
dlclose(aeropuerto);
|
|
||||||
aeropuerto = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
__attribute__ ((destructor))
|
|
||||||
void _Apple80211_destructor(void)
|
|
||||||
{
|
|
||||||
if (aeropuerto) {
|
|
||||||
dlclose(aeropuerto);
|
|
||||||
aeropuerto = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
#ifndef MOBILEAPPLE80211_H
|
|
||||||
#define MOBILEAPPLE80211_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
* MobileApple80211 interface for iPhone/iPod touch
|
|
||||||
* These functions are available from Aeropuerto.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct Apple80211;
|
|
||||||
typedef struct Apple80211 *Apple80211Ref;
|
|
||||||
|
|
||||||
int Apple80211Open(Apple80211Ref *ctx);
|
|
||||||
int Apple80211Close(Apple80211Ref ctx);
|
|
||||||
int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list);
|
|
||||||
int Apple80211BindToInterface(Apple80211Ref handle,
|
|
||||||
CFStringRef interface);
|
|
||||||
int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
|
|
||||||
CFStringRef *name);
|
|
||||||
int Apple80211GetInfoCopy(Apple80211Ref handle,
|
|
||||||
CFDictionaryRef *info);
|
|
||||||
int Apple80211GetPower(Apple80211Ref handle, char *pwr);
|
|
||||||
int Apple80211SetPower(Apple80211Ref handle, char pwr);
|
|
||||||
|
|
||||||
/* parameters can be NULL; returns scan results in CFArrayRef *list;
|
|
||||||
* caller will need to free with CFRelease() */
|
|
||||||
int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
|
|
||||||
CFDictionaryRef parameters);
|
|
||||||
|
|
||||||
int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
|
|
||||||
CFStringRef password);
|
|
||||||
int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
|
|
||||||
CFStringRef password,
|
|
||||||
CFDictionaryRef *info);
|
|
||||||
|
|
||||||
enum {
|
|
||||||
APPLE80211_VALUE_SSID = 1,
|
|
||||||
APPLE80211_VALUE_BSSID = 9
|
|
||||||
};
|
|
||||||
|
|
||||||
int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
|
|
||||||
void *value);
|
|
||||||
|
|
||||||
#endif /* MOBILEAPPLE80211_H */
|
|
@ -1,506 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - Driver interaction with Atmel Wireless LAN drivers
|
|
||||||
* Copyright (c) 2000-2005, ATMEL Corporation
|
|
||||||
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
Copyright 2000-2001 ATMEL Corporation.
|
|
||||||
|
|
||||||
WPA Supplicant - driver interaction with Atmel Wireless lan drivers.
|
|
||||||
|
|
||||||
This is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Atmel wireless lan drivers; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
#include "wireless_copy.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include "driver.h"
|
|
||||||
#include "driver_wext.h"
|
|
||||||
|
|
||||||
struct wpa_driver_atmel_data {
|
|
||||||
void *wext; /* private data for driver_wext */
|
|
||||||
void *ctx;
|
|
||||||
char ifname[IFNAMSIZ + 1];
|
|
||||||
int sock;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define ATMEL_WPA_IOCTL (SIOCIWFIRSTPRIV + 2)
|
|
||||||
#define ATMEL_WPA_IOCTL_PARAM (SIOCIWFIRSTPRIV + 3)
|
|
||||||
#define ATMEL_WPA_IOCTL_GET_PARAM (SIOCIWFIRSTPRIV + 4)
|
|
||||||
|
|
||||||
|
|
||||||
/* ATMEL_WPA_IOCTL ioctl() cmd: */
|
|
||||||
enum {
|
|
||||||
SET_WPA_ENCRYPTION = 1,
|
|
||||||
SET_CIPHER_SUITES = 2,
|
|
||||||
MLME_STA_DEAUTH = 3,
|
|
||||||
MLME_STA_DISASSOC = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ATMEL_WPA_IOCTL_PARAM ioctl() cmd: */
|
|
||||||
enum {
|
|
||||||
ATMEL_PARAM_WPA = 1,
|
|
||||||
ATMEL_PARAM_PRIVACY_INVOKED = 2,
|
|
||||||
ATMEL_PARAM_WPA_TYPE = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAX_KEY_LENGTH 40
|
|
||||||
|
|
||||||
struct atmel_param{
|
|
||||||
unsigned char sta_addr[6];
|
|
||||||
int cmd;
|
|
||||||
u8 alg;
|
|
||||||
u8 key_idx;
|
|
||||||
u8 set_tx;
|
|
||||||
u8 seq[8];
|
|
||||||
u8 seq_len;
|
|
||||||
u16 key_len;
|
|
||||||
u8 key[MAX_KEY_LENGTH];
|
|
||||||
struct{
|
|
||||||
int reason_code;
|
|
||||||
u8 state;
|
|
||||||
}mlme;
|
|
||||||
u8 pairwise_suite;
|
|
||||||
u8 group_suite;
|
|
||||||
u8 key_mgmt_suite;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int atmel_ioctl(struct wpa_driver_atmel_data *drv,
|
|
||||||
struct atmel_param *param,
|
|
||||||
int len, int show_err)
|
|
||||||
{
|
|
||||||
struct iwreq iwr;
|
|
||||||
|
|
||||||
os_memset(&iwr, 0, sizeof(iwr));
|
|
||||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
iwr.u.data.pointer = (caddr_t) param;
|
|
||||||
iwr.u.data.length = len;
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, ATMEL_WPA_IOCTL, &iwr) < 0) {
|
|
||||||
int ret;
|
|
||||||
ret = errno;
|
|
||||||
if (show_err)
|
|
||||||
perror("ioctl[ATMEL_WPA_IOCTL]");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int atmel2param(struct wpa_driver_atmel_data *drv, int param, int value)
|
|
||||||
{
|
|
||||||
struct iwreq iwr;
|
|
||||||
int *i, ret = 0;
|
|
||||||
|
|
||||||
os_memset(&iwr, 0, sizeof(iwr));
|
|
||||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
i = (int *) iwr.u.name;
|
|
||||||
*i++ = param;
|
|
||||||
*i++ = value;
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, ATMEL_WPA_IOCTL_PARAM, &iwr) < 0) {
|
|
||||||
perror("ioctl[ATMEL_WPA_IOCTL_PARAM]");
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static int wpa_driver_atmel_set_wpa_ie(struct wpa_driver_atmel_data *drv,
|
|
||||||
const char *wpa_ie, size_t wpa_ie_len)
|
|
||||||
{
|
|
||||||
struct atmel_param *param;
|
|
||||||
int res;
|
|
||||||
size_t blen = ATMEL_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
|
|
||||||
if (blen < sizeof(*param))
|
|
||||||
blen = sizeof(*param);
|
|
||||||
|
|
||||||
param = os_zalloc(blen);
|
|
||||||
if (param == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
param->cmd = ATMEL_SET_GENERIC_ELEMENT;
|
|
||||||
param->u.generic_elem.len = wpa_ie_len;
|
|
||||||
os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
|
|
||||||
res = atmel_ioctl(drv, param, blen, 1);
|
|
||||||
|
|
||||||
os_free(param);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_atmel_set_wpa(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_atmel_data *drv = priv;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
printf("wpa_driver_atmel_set_wpa %s\n", drv->ifname);
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (!enabled && wpa_driver_atmel_set_wpa_ie(drv, NULL, 0) < 0)
|
|
||||||
ret = -1;
|
|
||||||
#endif
|
|
||||||
if (atmel2param(drv, ATMEL_PARAM_PRIVACY_INVOKED, enabled) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (atmel2param(drv, ATMEL_PARAM_WPA, enabled) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_atmel_set_key(void *priv, wpa_alg alg,
|
|
||||||
const u8 *addr, int key_idx,
|
|
||||||
int set_tx, const u8 *seq, size_t seq_len,
|
|
||||||
const u8 *key, size_t key_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_atmel_data *drv = priv;
|
|
||||||
int ret = 0;
|
|
||||||
struct atmel_param *param;
|
|
||||||
u8 *buf;
|
|
||||||
u8 alg_type;
|
|
||||||
|
|
||||||
size_t blen;
|
|
||||||
char *alg_name;
|
|
||||||
|
|
||||||
switch (alg) {
|
|
||||||
case WPA_ALG_NONE:
|
|
||||||
alg_name = "none";
|
|
||||||
alg_type = 0;
|
|
||||||
break;
|
|
||||||
case WPA_ALG_WEP:
|
|
||||||
alg_name = "WEP";
|
|
||||||
alg_type = 1;
|
|
||||||
break;
|
|
||||||
case WPA_ALG_TKIP:
|
|
||||||
alg_name = "TKIP";
|
|
||||||
alg_type = 2;
|
|
||||||
break;
|
|
||||||
case WPA_ALG_CCMP:
|
|
||||||
alg_name = "CCMP";
|
|
||||||
alg_type = 3;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
|
|
||||||
"key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
|
|
||||||
(unsigned long) seq_len, (unsigned long) key_len);
|
|
||||||
|
|
||||||
if (seq_len > 8)
|
|
||||||
return -2;
|
|
||||||
|
|
||||||
blen = sizeof(*param) + key_len;
|
|
||||||
buf = os_zalloc(blen);
|
|
||||||
if (buf == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
param = (struct atmel_param *) buf;
|
|
||||||
|
|
||||||
param->cmd = SET_WPA_ENCRYPTION;
|
|
||||||
|
|
||||||
if (addr == NULL)
|
|
||||||
os_memset(param->sta_addr, 0xff, ETH_ALEN);
|
|
||||||
else
|
|
||||||
os_memcpy(param->sta_addr, addr, ETH_ALEN);
|
|
||||||
|
|
||||||
param->alg = alg_type;
|
|
||||||
param->key_idx = key_idx;
|
|
||||||
param->set_tx = set_tx;
|
|
||||||
os_memcpy(param->seq, seq, seq_len);
|
|
||||||
param->seq_len = seq_len;
|
|
||||||
param->key_len = key_len;
|
|
||||||
os_memcpy((u8 *)param->key, key, key_len);
|
|
||||||
|
|
||||||
if (atmel_ioctl(drv, param, blen, 1)) {
|
|
||||||
wpa_printf(MSG_WARNING, "Failed to set encryption.");
|
|
||||||
/* TODO: show key error*/
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
os_free(buf);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_atmel_set_countermeasures(void *priv,
|
|
||||||
int enabled)
|
|
||||||
{
|
|
||||||
/* FIX */
|
|
||||||
printf("wpa_driver_atmel_set_countermeasures - not yet "
|
|
||||||
"implemented\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_atmel_set_drop_unencrypted(void *priv,
|
|
||||||
int enabled)
|
|
||||||
{
|
|
||||||
/* FIX */
|
|
||||||
printf("wpa_driver_atmel_set_drop_unencrypted - not yet "
|
|
||||||
"implemented\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_atmel_mlme(void *priv, const u8 *addr, int cmd,
|
|
||||||
int reason_code)
|
|
||||||
{
|
|
||||||
struct wpa_driver_atmel_data *drv = priv;
|
|
||||||
struct atmel_param param;
|
|
||||||
int ret;
|
|
||||||
int mgmt_error = 0xaa;
|
|
||||||
|
|
||||||
os_memset(¶m, 0, sizeof(param));
|
|
||||||
os_memcpy(param.sta_addr, addr, ETH_ALEN);
|
|
||||||
param.cmd = cmd;
|
|
||||||
param.mlme.reason_code = reason_code;
|
|
||||||
param.mlme.state = mgmt_error;
|
|
||||||
ret = atmel_ioctl(drv, ¶m, sizeof(param), 1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static int wpa_driver_atmel_set_suites(struct wpa_driver_atmel_data *drv,
|
|
||||||
u8 pairwise_suite, u8 group_suite,
|
|
||||||
u8 key_mgmt_suite)
|
|
||||||
{
|
|
||||||
struct atmel_param param;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
os_memset(¶m, 0, sizeof(param));
|
|
||||||
param.cmd = SET_CIPHER_SUITES;
|
|
||||||
param.pairwise_suite = pairwise_suite;
|
|
||||||
param.group_suite = group_suite;
|
|
||||||
param.key_mgmt_suite = key_mgmt_suite;
|
|
||||||
|
|
||||||
ret = atmel_ioctl(drv, ¶m, sizeof(param), 1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_atmel_deauthenticate(void *priv, const u8 *addr,
|
|
||||||
int reason_code)
|
|
||||||
{
|
|
||||||
struct wpa_driver_atmel_data *drv = priv;
|
|
||||||
printf("wpa_driver_atmel_deauthenticate\n");
|
|
||||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
|
||||||
return wpa_driver_atmel_mlme(drv, addr, MLME_STA_DEAUTH,
|
|
||||||
reason_code);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_atmel_disassociate(void *priv, const u8 *addr,
|
|
||||||
int reason_code)
|
|
||||||
{
|
|
||||||
struct wpa_driver_atmel_data *drv = priv;
|
|
||||||
printf("wpa_driver_atmel_disassociate\n");
|
|
||||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
|
||||||
return wpa_driver_atmel_mlme(drv, addr, MLME_STA_DISASSOC,
|
|
||||||
reason_code);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Atmel driver uses specific values for each cipher suite */
|
|
||||||
static int convertSuiteToDriver(wpa_cipher suite)
|
|
||||||
{
|
|
||||||
u8 suite_type;
|
|
||||||
|
|
||||||
switch(suite) {
|
|
||||||
case CIPHER_NONE:
|
|
||||||
suite_type = 0;
|
|
||||||
break;
|
|
||||||
case CIPHER_WEP40:
|
|
||||||
suite_type = 1;
|
|
||||||
break;
|
|
||||||
case CIPHER_TKIP:
|
|
||||||
suite_type = 2;
|
|
||||||
break;
|
|
||||||
case CIPHER_WEP104:
|
|
||||||
suite_type = 5;
|
|
||||||
break;
|
|
||||||
case CIPHER_CCMP:
|
|
||||||
suite_type = 3;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
suite_type = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return suite_type;
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_atmel_associate(void *priv,
|
|
||||||
struct wpa_driver_associate_params *params)
|
|
||||||
{
|
|
||||||
struct wpa_driver_atmel_data *drv = priv;
|
|
||||||
int ret = 0;
|
|
||||||
#if 0
|
|
||||||
u8 pairwise_suite_driver;
|
|
||||||
u8 group_suite_driver;
|
|
||||||
u8 key_mgmt_suite_driver;
|
|
||||||
|
|
||||||
pairwise_suite_driver = convertSuiteToDriver(params->pairwise_suite);
|
|
||||||
group_suite_driver = convertSuiteToDriver(params->group_suite);
|
|
||||||
key_mgmt_suite_driver = convertSuiteToDriver(params->key_mgmt_suite);
|
|
||||||
|
|
||||||
if (wpa_driver_atmel_set_suites(drv, pairwise_suite_driver,
|
|
||||||
group_suite_driver,
|
|
||||||
key_mgmt_suite_driver) < 0){
|
|
||||||
printf("wpa_driver_atmel_set_suites.\n");
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0) {
|
|
||||||
printf("wpa_driver_atmel_set_freq.\n");
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
|
|
||||||
< 0) {
|
|
||||||
printf("FAILED : wpa_driver_atmel_set_ssid.\n");
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0) {
|
|
||||||
printf("FAILED : wpa_driver_atmel_set_bssid.\n");
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_atmel_get_bssid(void *priv, u8 *bssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_atmel_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_bssid(drv->wext, bssid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_atmel_get_ssid(void *priv, u8 *ssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_atmel_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_ssid(drv->wext, ssid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_atmel_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_atmel_data *drv = priv;
|
|
||||||
return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct wpa_scan_results * wpa_driver_atmel_get_scan_results(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_atmel_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_scan_results(drv->wext);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_atmel_set_operstate(void *priv, int state)
|
|
||||||
{
|
|
||||||
struct wpa_driver_atmel_data *drv = priv;
|
|
||||||
return wpa_driver_wext_set_operstate(drv->wext, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void * wpa_driver_atmel_init(void *ctx, const char *ifname)
|
|
||||||
{
|
|
||||||
struct wpa_driver_atmel_data *drv;
|
|
||||||
|
|
||||||
drv = os_zalloc(sizeof(*drv));
|
|
||||||
if (drv == NULL)
|
|
||||||
return NULL;
|
|
||||||
drv->wext = wpa_driver_wext_init(ctx, ifname);
|
|
||||||
if (drv->wext == NULL) {
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
drv->ctx = ctx;
|
|
||||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
|
||||||
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (drv->sock < 0) {
|
|
||||||
wpa_driver_wext_deinit(drv->wext);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_atmel_deinit(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_atmel_data *drv = priv;
|
|
||||||
wpa_driver_wext_deinit(drv->wext);
|
|
||||||
close(drv->sock);
|
|
||||||
os_free(drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const struct wpa_driver_ops wpa_driver_atmel_ops = {
|
|
||||||
.name = "atmel",
|
|
||||||
.desc = "ATMEL AT76C5XXx (USB, PCMCIA)",
|
|
||||||
.get_bssid = wpa_driver_atmel_get_bssid,
|
|
||||||
.get_ssid = wpa_driver_atmel_get_ssid,
|
|
||||||
.set_wpa = wpa_driver_atmel_set_wpa,
|
|
||||||
.set_key = wpa_driver_atmel_set_key,
|
|
||||||
.init = wpa_driver_atmel_init,
|
|
||||||
.deinit = wpa_driver_atmel_deinit,
|
|
||||||
.set_countermeasures = wpa_driver_atmel_set_countermeasures,
|
|
||||||
.set_drop_unencrypted = wpa_driver_atmel_set_drop_unencrypted,
|
|
||||||
.scan = wpa_driver_atmel_scan,
|
|
||||||
.get_scan_results2 = wpa_driver_atmel_get_scan_results,
|
|
||||||
.deauthenticate = wpa_driver_atmel_deauthenticate,
|
|
||||||
.disassociate = wpa_driver_atmel_disassociate,
|
|
||||||
.associate = wpa_driver_atmel_associate,
|
|
||||||
.set_operstate = wpa_driver_atmel_set_operstate,
|
|
||||||
};
|
|
@ -1,604 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - driver interaction with old Broadcom wl.o driver
|
|
||||||
* Copyright (c) 2004, Nikki Chumkov <nikki@gattaca.ru>
|
|
||||||
* Copyright (c) 2004, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*
|
|
||||||
* Please note that the newer Broadcom driver ("hybrid Linux driver") supports
|
|
||||||
* Linux wireless extensions and does not need (or even work) with this old
|
|
||||||
* driver wrapper. Use driver_wext.c with that driver.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
#include <netpacket/packet.h>
|
|
||||||
#include <net/ethernet.h> /* the L2 protocols */
|
|
||||||
#else
|
|
||||||
#include <linux/if_packet.h>
|
|
||||||
#include <linux/if_ether.h> /* The L2 protocols */
|
|
||||||
#endif
|
|
||||||
#include <net/if.h>
|
|
||||||
#include <typedefs.h>
|
|
||||||
|
|
||||||
/* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
|
|
||||||
* WRT54G GPL tarball. */
|
|
||||||
#include <wlioctl.h>
|
|
||||||
|
|
||||||
#include "driver.h"
|
|
||||||
#include "eloop.h"
|
|
||||||
|
|
||||||
struct wpa_driver_broadcom_data {
|
|
||||||
void *ctx;
|
|
||||||
int ioctl_sock;
|
|
||||||
int event_sock;
|
|
||||||
char ifname[IFNAMSIZ + 1];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef WLC_DEAUTHENTICATE
|
|
||||||
#define WLC_DEAUTHENTICATE 143
|
|
||||||
#endif
|
|
||||||
#ifndef WLC_DEAUTHENTICATE_WITH_REASON
|
|
||||||
#define WLC_DEAUTHENTICATE_WITH_REASON 201
|
|
||||||
#endif
|
|
||||||
#ifndef WLC_SET_TKIP_COUNTERMEASURES
|
|
||||||
#define WLC_SET_TKIP_COUNTERMEASURES 202
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(PSK_ENABLED) /* NEW driver interface */
|
|
||||||
#define WL_VERSION 360130
|
|
||||||
/* wireless authentication bit vector */
|
|
||||||
#define WPA_ENABLED 1
|
|
||||||
#define PSK_ENABLED 2
|
|
||||||
|
|
||||||
#define WAUTH_WPA_ENABLED(wauth) ((wauth) & WPA_ENABLED)
|
|
||||||
#define WAUTH_PSK_ENABLED(wauth) ((wauth) & PSK_ENABLED)
|
|
||||||
#define WAUTH_ENABLED(wauth) ((wauth) & (WPA_ENABLED | PSK_ENABLED))
|
|
||||||
|
|
||||||
#define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
|
|
||||||
|
|
||||||
typedef wl_wsec_key_t wsec_key_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32 val;
|
|
||||||
struct ether_addr ea;
|
|
||||||
uint16 res;
|
|
||||||
} wlc_deauth_t;
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
|
|
||||||
void *timeout_ctx);
|
|
||||||
|
|
||||||
static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
|
|
||||||
void *buf, int len)
|
|
||||||
{
|
|
||||||
struct ifreq ifr;
|
|
||||||
wl_ioctl_t ioc;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
|
|
||||||
drv->ifname, cmd, len, buf);
|
|
||||||
/* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
|
|
||||||
|
|
||||||
ioc.cmd = cmd;
|
|
||||||
ioc.buf = buf;
|
|
||||||
ioc.len = len;
|
|
||||||
os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
ifr.ifr_data = (caddr_t) &ioc;
|
|
||||||
if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
|
|
||||||
if (cmd != WLC_GET_MAGIC)
|
|
||||||
perror(ifr.ifr_name);
|
|
||||||
wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
|
|
||||||
cmd, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_broadcom_data *drv = priv;
|
|
||||||
if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
os_memset(bssid, 0, ETH_ALEN);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_broadcom_data *drv = priv;
|
|
||||||
wlc_ssid_t s;
|
|
||||||
|
|
||||||
if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
os_memcpy(ssid, s.SSID, s.SSID_len);
|
|
||||||
return s.SSID_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
|
|
||||||
{
|
|
||||||
struct wpa_driver_broadcom_data *drv = priv;
|
|
||||||
unsigned int wauth, wsec;
|
|
||||||
struct ether_addr ea;
|
|
||||||
|
|
||||||
os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
|
|
||||||
if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
|
|
||||||
-1 ||
|
|
||||||
broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (enable) {
|
|
||||||
wauth = PSK_ENABLED;
|
|
||||||
wsec = TKIP_ENABLED;
|
|
||||||
} else {
|
|
||||||
wauth = 255;
|
|
||||||
wsec &= ~(TKIP_ENABLED | AES_ENABLED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
|
|
||||||
-1 ||
|
|
||||||
broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* FIX: magic number / error handling? */
|
|
||||||
broadcom_ioctl(drv, 122, &ea, sizeof(ea));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wpa_driver_broadcom_set_key(void *priv, wpa_alg alg,
|
|
||||||
const u8 *addr, int key_idx, int set_tx,
|
|
||||||
const u8 *seq, size_t seq_len,
|
|
||||||
const u8 *key, size_t key_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_broadcom_data *drv = priv;
|
|
||||||
int ret;
|
|
||||||
wsec_key_t wkt;
|
|
||||||
|
|
||||||
os_memset(&wkt, 0, sizeof wkt);
|
|
||||||
wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
|
|
||||||
set_tx ? "PRIMARY " : "", key_idx, alg);
|
|
||||||
if (key && key_len > 0)
|
|
||||||
wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
|
|
||||||
|
|
||||||
switch (alg) {
|
|
||||||
case WPA_ALG_NONE:
|
|
||||||
wkt.algo = CRYPTO_ALGO_OFF;
|
|
||||||
break;
|
|
||||||
case WPA_ALG_WEP:
|
|
||||||
wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
|
|
||||||
break;
|
|
||||||
case WPA_ALG_TKIP:
|
|
||||||
wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
|
|
||||||
break;
|
|
||||||
case WPA_ALG_CCMP:
|
|
||||||
wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
|
|
||||||
* AES_OCB_MSDU, AES_OCB_MPDU? */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
wkt.algo = CRYPTO_ALGO_NALG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seq && seq_len > 0)
|
|
||||||
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
|
|
||||||
|
|
||||||
if (addr)
|
|
||||||
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
|
|
||||||
|
|
||||||
wkt.index = key_idx;
|
|
||||||
wkt.len = key_len;
|
|
||||||
if (key && key_len > 0) {
|
|
||||||
os_memcpy(wkt.data, key, key_len);
|
|
||||||
if (key_len == 32) {
|
|
||||||
/* hack hack hack XXX */
|
|
||||||
os_memcpy(&wkt.data[16], &key[24], 8);
|
|
||||||
os_memcpy(&wkt.data[24], &key[16], 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* wkt.algo = CRYPTO_ALGO_...; */
|
|
||||||
wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
|
|
||||||
if (addr && set_tx)
|
|
||||||
os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
|
|
||||||
ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
|
|
||||||
if (addr && set_tx) {
|
|
||||||
/* FIX: magic number / error handling? */
|
|
||||||
broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
|
|
||||||
void *sock_ctx)
|
|
||||||
{
|
|
||||||
char buf[8192];
|
|
||||||
int left;
|
|
||||||
wl_wpa_header_t *wwh;
|
|
||||||
union wpa_event_data data;
|
|
||||||
|
|
||||||
if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
|
|
||||||
|
|
||||||
if ((size_t) left < sizeof(wl_wpa_header_t))
|
|
||||||
return;
|
|
||||||
|
|
||||||
wwh = (wl_wpa_header_t *) buf;
|
|
||||||
|
|
||||||
if (wwh->snap.type != WL_WPA_ETHER_TYPE)
|
|
||||||
return;
|
|
||||||
if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
os_memset(&data, 0, sizeof(data));
|
|
||||||
|
|
||||||
switch (wwh->type) {
|
|
||||||
case WLC_ASSOC_MSG:
|
|
||||||
left -= WL_WPA_HEADER_LEN;
|
|
||||||
wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
|
|
||||||
left);
|
|
||||||
if (left > 0) {
|
|
||||||
data.assoc_info.resp_ies = os_malloc(left);
|
|
||||||
if (data.assoc_info.resp_ies == NULL)
|
|
||||||
return;
|
|
||||||
os_memcpy(data.assoc_info.resp_ies,
|
|
||||||
buf + WL_WPA_HEADER_LEN, left);
|
|
||||||
data.assoc_info.resp_ies_len = left;
|
|
||||||
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: copying %d bytes "
|
|
||||||
"into resp_ies",
|
|
||||||
data.assoc_info.resp_ies, left);
|
|
||||||
}
|
|
||||||
/* data.assoc_info.req_ies = NULL; */
|
|
||||||
/* data.assoc_info.req_ies_len = 0; */
|
|
||||||
|
|
||||||
wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
|
|
||||||
wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
|
|
||||||
break;
|
|
||||||
case WLC_DISASSOC_MSG:
|
|
||||||
wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
|
|
||||||
wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
|
|
||||||
break;
|
|
||||||
case WLC_PTK_MIC_MSG:
|
|
||||||
wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
|
|
||||||
data.michael_mic_failure.unicast = 1;
|
|
||||||
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
|
|
||||||
break;
|
|
||||||
case WLC_GTK_MIC_MSG:
|
|
||||||
wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
|
|
||||||
data.michael_mic_failure.unicast = 0;
|
|
||||||
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
|
|
||||||
wwh->type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
os_free(data.assoc_info.resp_ies);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
|
|
||||||
{
|
|
||||||
int s;
|
|
||||||
struct sockaddr_ll ll;
|
|
||||||
struct wpa_driver_broadcom_data *drv;
|
|
||||||
struct ifreq ifr;
|
|
||||||
|
|
||||||
/* open socket to kernel */
|
|
||||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
||||||
perror("socket");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* do it */
|
|
||||||
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
|
||||||
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
|
|
||||||
perror(ifr.ifr_name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
drv = os_zalloc(sizeof(*drv));
|
|
||||||
if (drv == NULL)
|
|
||||||
return NULL;
|
|
||||||
drv->ctx = ctx;
|
|
||||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
|
||||||
drv->ioctl_sock = s;
|
|
||||||
|
|
||||||
s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
|
|
||||||
if (s < 0) {
|
|
||||||
perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
|
|
||||||
close(drv->ioctl_sock);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_memset(&ll, 0, sizeof(ll));
|
|
||||||
ll.sll_family = AF_PACKET;
|
|
||||||
ll.sll_protocol = ntohs(ETH_P_802_2);
|
|
||||||
ll.sll_ifindex = ifr.ifr_ifindex;
|
|
||||||
ll.sll_hatype = 0;
|
|
||||||
ll.sll_pkttype = PACKET_HOST;
|
|
||||||
ll.sll_halen = 0;
|
|
||||||
|
|
||||||
if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
|
|
||||||
perror("bind(netlink)");
|
|
||||||
close(s);
|
|
||||||
close(drv->ioctl_sock);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
|
|
||||||
NULL);
|
|
||||||
drv->event_sock = s;
|
|
||||||
|
|
||||||
return drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wpa_driver_broadcom_deinit(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_broadcom_data *drv = priv;
|
|
||||||
eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
|
|
||||||
eloop_unregister_read_sock(drv->event_sock);
|
|
||||||
close(drv->event_sock);
|
|
||||||
close(drv->ioctl_sock);
|
|
||||||
os_free(drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wpa_driver_broadcom_set_countermeasures(void *priv,
|
|
||||||
int enabled)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
struct wpa_driver_broadcom_data *drv = priv;
|
|
||||||
/* FIX: ? */
|
|
||||||
return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
|
|
||||||
sizeof(enabled));
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_broadcom_data *drv = priv;
|
|
||||||
/* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
|
|
||||||
int restrict = (enabled ? 1 : 0);
|
|
||||||
|
|
||||||
if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT,
|
|
||||||
&restrict, sizeof(restrict)) < 0 ||
|
|
||||||
broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
|
|
||||||
&restrict, sizeof(restrict)) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
|
|
||||||
void *timeout_ctx)
|
|
||||||
{
|
|
||||||
wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
|
|
||||||
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wpa_driver_broadcom_scan(void *priv, const u8 *ssid,
|
|
||||||
size_t ssid_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_broadcom_data *drv = priv;
|
|
||||||
wlc_ssid_t wst = { 0, "" };
|
|
||||||
|
|
||||||
if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
|
|
||||||
wst.SSID_len = ssid_len;
|
|
||||||
os_memcpy(wst.SSID, ssid, ssid_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
|
|
||||||
eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
|
|
||||||
drv->ctx);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const int frequency_list[] = {
|
|
||||||
2412, 2417, 2422, 2427, 2432, 2437, 2442,
|
|
||||||
2447, 2452, 2457, 2462, 2467, 2472, 2484
|
|
||||||
};
|
|
||||||
|
|
||||||
struct bss_ie_hdr {
|
|
||||||
u8 elem_id;
|
|
||||||
u8 len;
|
|
||||||
u8 oui[3];
|
|
||||||
/* u8 oui_type; */
|
|
||||||
/* u16 version; */
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_broadcom_get_scan_results(void *priv,
|
|
||||||
struct wpa_scan_result *results,
|
|
||||||
size_t max_size)
|
|
||||||
{
|
|
||||||
struct wpa_driver_broadcom_data *drv = priv;
|
|
||||||
char *buf;
|
|
||||||
wl_scan_results_t *wsr;
|
|
||||||
wl_bss_info_t *wbi;
|
|
||||||
size_t ap_num;
|
|
||||||
|
|
||||||
buf = os_malloc(WLC_IOCTL_MAXLEN);
|
|
||||||
if (buf == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
wsr = (wl_scan_results_t *) buf;
|
|
||||||
|
|
||||||
wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
|
|
||||||
wsr->version = 107;
|
|
||||||
wsr->count = 0;
|
|
||||||
|
|
||||||
if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
|
|
||||||
os_free(buf);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
|
|
||||||
|
|
||||||
for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
|
|
||||||
int left;
|
|
||||||
struct bss_ie_hdr *ie;
|
|
||||||
|
|
||||||
os_memcpy(results[ap_num].bssid, &wbi->BSSID, ETH_ALEN);
|
|
||||||
os_memcpy(results[ap_num].ssid, wbi->SSID, wbi->SSID_len);
|
|
||||||
results[ap_num].ssid_len = wbi->SSID_len;
|
|
||||||
results[ap_num].freq = frequency_list[wbi->channel - 1];
|
|
||||||
/* get ie's */
|
|
||||||
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: AP IEs",
|
|
||||||
(u8 *) wbi + sizeof(*wbi), wbi->ie_length);
|
|
||||||
ie = (struct bss_ie_hdr *) ((u8 *) wbi + sizeof(*wbi));
|
|
||||||
for (left = wbi->ie_length; left > 0;
|
|
||||||
left -= (ie->len + 2), ie = (struct bss_ie_hdr *)
|
|
||||||
((u8 *) ie + 2 + ie->len)) {
|
|
||||||
wpa_printf(MSG_MSGDUMP, "BROADCOM: IE: id:%x, len:%d",
|
|
||||||
ie->elem_id, ie->len);
|
|
||||||
if (ie->len >= 3)
|
|
||||||
wpa_printf(MSG_MSGDUMP,
|
|
||||||
"BROADCOM: oui:%02x%02x%02x",
|
|
||||||
ie->oui[0], ie->oui[1], ie->oui[2]);
|
|
||||||
if (ie->elem_id != 0xdd ||
|
|
||||||
ie->len < 6 ||
|
|
||||||
os_memcmp(ie->oui, WPA_OUI, 3) != 0)
|
|
||||||
continue;
|
|
||||||
os_memcpy(results[ap_num].wpa_ie, ie, ie->len + 2);
|
|
||||||
results[ap_num].wpa_ie_len = ie->len + 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
|
|
||||||
"BSSes)",
|
|
||||||
wsr->buflen, (unsigned long) ap_num);
|
|
||||||
|
|
||||||
os_free(buf);
|
|
||||||
return ap_num;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
|
|
||||||
int reason_code)
|
|
||||||
{
|
|
||||||
struct wpa_driver_broadcom_data *drv = priv;
|
|
||||||
wlc_deauth_t wdt;
|
|
||||||
wdt.val = reason_code;
|
|
||||||
os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
|
|
||||||
wdt.res = 0x7fff;
|
|
||||||
return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
|
|
||||||
sizeof(wdt));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
|
|
||||||
int reason_code)
|
|
||||||
{
|
|
||||||
struct wpa_driver_broadcom_data *drv = priv;
|
|
||||||
return broadcom_ioctl(drv, WLC_DISASSOC, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_broadcom_associate(void *priv,
|
|
||||||
struct wpa_driver_associate_params *params)
|
|
||||||
{
|
|
||||||
struct wpa_driver_broadcom_data *drv = priv;
|
|
||||||
wlc_ssid_t s;
|
|
||||||
int infra = 1;
|
|
||||||
int auth = 0;
|
|
||||||
int wsec = 4;
|
|
||||||
int dummy;
|
|
||||||
int wpa_auth;
|
|
||||||
|
|
||||||
s.SSID_len = params->ssid_len;
|
|
||||||
os_memcpy(s.SSID, params->ssid, params->ssid_len);
|
|
||||||
|
|
||||||
switch (params->pairwise_suite) {
|
|
||||||
case CIPHER_WEP40:
|
|
||||||
case CIPHER_WEP104:
|
|
||||||
wsec = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CIPHER_TKIP:
|
|
||||||
wsec = 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CIPHER_CCMP:
|
|
||||||
wsec = 4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
wsec = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (params->key_mgmt_suite) {
|
|
||||||
case KEY_MGMT_802_1X:
|
|
||||||
wpa_auth = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KEY_MGMT_PSK:
|
|
||||||
wpa_auth = 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
wpa_auth = 255;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
|
|
||||||
* group_suite, key_mgmt_suite);
|
|
||||||
* broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
|
|
||||||
* wl join uses wlc_sec_wep here, not wlc_set_wsec */
|
|
||||||
|
|
||||||
if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
|
|
||||||
broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
|
|
||||||
sizeof(wpa_auth)) < 0 ||
|
|
||||||
broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
|
|
||||||
broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
|
|
||||||
broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
|
|
||||||
broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
|
|
||||||
broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct wpa_driver_ops wpa_driver_broadcom_ops = {
|
|
||||||
.name = "broadcom",
|
|
||||||
.desc = "Broadcom wl.o driver",
|
|
||||||
.get_bssid = wpa_driver_broadcom_get_bssid,
|
|
||||||
.get_ssid = wpa_driver_broadcom_get_ssid,
|
|
||||||
.set_wpa = wpa_driver_broadcom_set_wpa,
|
|
||||||
.set_key = wpa_driver_broadcom_set_key,
|
|
||||||
.init = wpa_driver_broadcom_init,
|
|
||||||
.deinit = wpa_driver_broadcom_deinit,
|
|
||||||
.set_countermeasures = wpa_driver_broadcom_set_countermeasures,
|
|
||||||
.set_drop_unencrypted = wpa_driver_broadcom_set_drop_unencrypted,
|
|
||||||
.scan = wpa_driver_broadcom_scan,
|
|
||||||
.get_scan_results = wpa_driver_broadcom_get_scan_results,
|
|
||||||
.deauthenticate = wpa_driver_broadcom_deauthenticate,
|
|
||||||
.disassociate = wpa_driver_broadcom_disassociate,
|
|
||||||
.associate = wpa_driver_broadcom_associate,
|
|
||||||
};
|
|
@ -1,795 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - driver interaction with BSD net80211 layer
|
|
||||||
* Copyright (c) 2004, Sam Leffler <sam@errno.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "driver.h"
|
|
||||||
#include "eloop.h"
|
|
||||||
#include "ieee802_11_defs.h"
|
|
||||||
|
|
||||||
#include <net/if.h>
|
|
||||||
|
|
||||||
#ifdef __NetBSD__
|
|
||||||
#include <net/if_ether.h>
|
|
||||||
#define COMPAT_FREEBSD_NET80211
|
|
||||||
#else
|
|
||||||
#include <net/ethernet.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <net80211/_ieee80211.h>
|
|
||||||
#include <net80211/ieee80211.h>
|
|
||||||
#include <net80211/ieee80211_crypto.h>
|
|
||||||
#include <net80211/ieee80211_ioctl.h>
|
|
||||||
|
|
||||||
struct wpa_driver_bsd_data {
|
|
||||||
int sock; /* open socket for 802.11 ioctls */
|
|
||||||
int route; /* routing socket for events */
|
|
||||||
char ifname[IFNAMSIZ+1]; /* interface name */
|
|
||||||
unsigned int ifindex; /* interface index */
|
|
||||||
void *ctx;
|
|
||||||
int prev_roaming; /* roaming state to restore on deinit */
|
|
||||||
int prev_privacy; /* privacy state to restore on deinit */
|
|
||||||
int prev_wpa; /* wpa state to restore on deinit */
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
set80211var(struct wpa_driver_bsd_data *drv, int op, const void *arg, int arg_len)
|
|
||||||
{
|
|
||||||
struct ieee80211req ireq;
|
|
||||||
|
|
||||||
os_memset(&ireq, 0, sizeof(ireq));
|
|
||||||
os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
|
|
||||||
ireq.i_type = op;
|
|
||||||
ireq.i_len = arg_len;
|
|
||||||
ireq.i_data = (void *) arg;
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
|
|
||||||
fprintf(stderr, "ioctl[SIOCS80211, op %u, len %u]: %s\n",
|
|
||||||
op, arg_len, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
get80211var(struct wpa_driver_bsd_data *drv, int op, void *arg, int arg_len)
|
|
||||||
{
|
|
||||||
struct ieee80211req ireq;
|
|
||||||
|
|
||||||
os_memset(&ireq, 0, sizeof(ireq));
|
|
||||||
os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
|
|
||||||
ireq.i_type = op;
|
|
||||||
ireq.i_len = arg_len;
|
|
||||||
ireq.i_data = arg;
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
|
|
||||||
fprintf(stderr, "ioctl[SIOCG80211, op %u, len %u]: %s\n",
|
|
||||||
op, arg_len, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return ireq.i_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
set80211param(struct wpa_driver_bsd_data *drv, int op, int arg)
|
|
||||||
{
|
|
||||||
struct ieee80211req ireq;
|
|
||||||
|
|
||||||
os_memset(&ireq, 0, sizeof(ireq));
|
|
||||||
os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
|
|
||||||
ireq.i_type = op;
|
|
||||||
ireq.i_val = arg;
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
|
|
||||||
fprintf(stderr, "ioctl[SIOCS80211, op %u, arg 0x%x]: %s\n",
|
|
||||||
op, arg, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
get80211param(struct wpa_driver_bsd_data *drv, int op)
|
|
||||||
{
|
|
||||||
struct ieee80211req ireq;
|
|
||||||
|
|
||||||
os_memset(&ireq, 0, sizeof(ireq));
|
|
||||||
os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
|
|
||||||
ireq.i_type = op;
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
|
|
||||||
fprintf(stderr, "ioctl[SIOCG80211, op %u]: %s\n",
|
|
||||||
op, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return ireq.i_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
getifflags(struct wpa_driver_bsd_data *drv, int *flags)
|
|
||||||
{
|
|
||||||
struct ifreq ifr;
|
|
||||||
|
|
||||||
os_memset(&ifr, 0, sizeof(ifr));
|
|
||||||
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
|
|
||||||
if (ioctl(drv->sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
|
|
||||||
perror("SIOCGIFFLAGS");
|
|
||||||
return errno;
|
|
||||||
}
|
|
||||||
*flags = ifr.ifr_flags & 0xffff;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
setifflags(struct wpa_driver_bsd_data *drv, int flags)
|
|
||||||
{
|
|
||||||
struct ifreq ifr;
|
|
||||||
|
|
||||||
os_memset(&ifr, 0, sizeof(ifr));
|
|
||||||
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
|
|
||||||
ifr.ifr_flags = flags & 0xffff;
|
|
||||||
if (ioctl(drv->sock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
|
|
||||||
perror("SIOCSIFFLAGS");
|
|
||||||
return errno;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
|
|
||||||
return get80211var(drv, IEEE80211_IOC_BSSID,
|
|
||||||
bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_set_bssid(void *priv, const char *bssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
|
|
||||||
return set80211var(drv, IEEE80211_IOC_BSSID,
|
|
||||||
bssid, IEEE80211_ADDR_LEN);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
|
|
||||||
return get80211var(drv, IEEE80211_IOC_SSID,
|
|
||||||
ssid, IEEE80211_NWID_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_set_ssid(void *priv, const u8 *ssid,
|
|
||||||
size_t ssid_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
|
|
||||||
return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_set_wpa_ie(struct wpa_driver_bsd_data *drv,
|
|
||||||
const u8 *wpa_ie, size_t wpa_ie_len)
|
|
||||||
{
|
|
||||||
return set80211var(drv, IEEE80211_IOC_APPIE, wpa_ie, wpa_ie_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
|
|
||||||
__FUNCTION__, wpa, privacy);
|
|
||||||
|
|
||||||
if (!wpa && wpa_driver_bsd_set_wpa_ie(drv, NULL, 0) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (set80211param(drv, IEEE80211_IOC_WPA, wpa) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_set_wpa(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
|
||||||
|
|
||||||
return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_del_key(struct wpa_driver_bsd_data *drv, int key_idx,
|
|
||||||
const unsigned char *addr)
|
|
||||||
{
|
|
||||||
struct ieee80211req_del_key wk;
|
|
||||||
|
|
||||||
os_memset(&wk, 0, sizeof(wk));
|
|
||||||
if (addr != NULL &&
|
|
||||||
bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) != 0) {
|
|
||||||
struct ether_addr ea;
|
|
||||||
|
|
||||||
os_memcpy(&ea, addr, IEEE80211_ADDR_LEN);
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: addr=%s keyidx=%d",
|
|
||||||
__func__, ether_ntoa(&ea), key_idx);
|
|
||||||
os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
|
|
||||||
wk.idk_keyix = (uint8_t) IEEE80211_KEYIX_NONE;
|
|
||||||
} else {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __func__, key_idx);
|
|
||||||
wk.idk_keyix = key_idx;
|
|
||||||
}
|
|
||||||
return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_set_key(void *priv, wpa_alg alg,
|
|
||||||
const unsigned char *addr, int key_idx, int set_tx,
|
|
||||||
const u8 *seq, size_t seq_len,
|
|
||||||
const u8 *key, size_t key_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
struct ieee80211req_key wk;
|
|
||||||
struct ether_addr ea;
|
|
||||||
char *alg_name;
|
|
||||||
u_int8_t cipher;
|
|
||||||
|
|
||||||
if (alg == WPA_ALG_NONE)
|
|
||||||
return wpa_driver_bsd_del_key(drv, key_idx, addr);
|
|
||||||
|
|
||||||
switch (alg) {
|
|
||||||
case WPA_ALG_WEP:
|
|
||||||
alg_name = "WEP";
|
|
||||||
cipher = IEEE80211_CIPHER_WEP;
|
|
||||||
break;
|
|
||||||
case WPA_ALG_TKIP:
|
|
||||||
alg_name = "TKIP";
|
|
||||||
cipher = IEEE80211_CIPHER_TKIP;
|
|
||||||
break;
|
|
||||||
case WPA_ALG_CCMP:
|
|
||||||
alg_name = "CCMP";
|
|
||||||
cipher = IEEE80211_CIPHER_AES_CCM;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
|
|
||||||
__func__, alg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_memcpy(&ea, addr, IEEE80211_ADDR_LEN);
|
|
||||||
wpa_printf(MSG_DEBUG,
|
|
||||||
"%s: alg=%s addr=%s key_idx=%d set_tx=%d seq_len=%zu key_len=%zu",
|
|
||||||
__func__, alg_name, ether_ntoa(&ea), key_idx, set_tx,
|
|
||||||
seq_len, key_len);
|
|
||||||
|
|
||||||
if (seq_len > sizeof(u_int64_t)) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: seq_len %zu too big",
|
|
||||||
__func__, seq_len);
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
if (key_len > sizeof(wk.ik_keydata)) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: key length %zu too big",
|
|
||||||
__func__, key_len);
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_memset(&wk, 0, sizeof(wk));
|
|
||||||
wk.ik_type = cipher;
|
|
||||||
wk.ik_flags = IEEE80211_KEY_RECV;
|
|
||||||
if (set_tx)
|
|
||||||
wk.ik_flags |= IEEE80211_KEY_XMIT;
|
|
||||||
os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
|
|
||||||
/*
|
|
||||||
* Deduce whether group/global or unicast key by checking
|
|
||||||
* the address (yech). Note also that we can only mark global
|
|
||||||
* keys default; doing this for a unicast key is an error.
|
|
||||||
*/
|
|
||||||
if (bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) == 0) {
|
|
||||||
wk.ik_flags |= IEEE80211_KEY_GROUP;
|
|
||||||
wk.ik_keyix = key_idx;
|
|
||||||
} else {
|
|
||||||
wk.ik_keyix = (key_idx == 0 ? IEEE80211_KEYIX_NONE : key_idx);
|
|
||||||
}
|
|
||||||
if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
|
|
||||||
wk.ik_flags |= IEEE80211_KEY_DEFAULT;
|
|
||||||
wk.ik_keylen = key_len;
|
|
||||||
os_memcpy(&wk.ik_keyrsc, seq, seq_len);
|
|
||||||
os_memcpy(wk.ik_keydata, key, key_len);
|
|
||||||
|
|
||||||
return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_set_countermeasures(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
|
|
||||||
return set80211param(drv, IEEE80211_IOC_COUNTERMEASURES, enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
|
|
||||||
return set80211param(drv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
struct ieee80211req_mlme mlme;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s", __func__);
|
|
||||||
os_memset(&mlme, 0, sizeof(mlme));
|
|
||||||
mlme.im_op = IEEE80211_MLME_DEAUTH;
|
|
||||||
mlme.im_reason = reason_code;
|
|
||||||
os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
|
|
||||||
return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
struct ieee80211req_mlme mlme;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s", __func__);
|
|
||||||
os_memset(&mlme, 0, sizeof(mlme));
|
|
||||||
mlme.im_op = IEEE80211_MLME_DISASSOC;
|
|
||||||
mlme.im_reason = reason_code;
|
|
||||||
os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
|
|
||||||
return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
struct ieee80211req_mlme mlme;
|
|
||||||
int privacy;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG,
|
|
||||||
"%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
|
|
||||||
, __func__
|
|
||||||
, params->ssid_len, params->ssid
|
|
||||||
, params->wpa_ie_len
|
|
||||||
, params->pairwise_suite
|
|
||||||
, params->group_suite
|
|
||||||
, params->key_mgmt_suite
|
|
||||||
);
|
|
||||||
|
|
||||||
/* XXX error handling is wrong but unclear what to do... */
|
|
||||||
if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
privacy = !(params->pairwise_suite == CIPHER_NONE &&
|
|
||||||
params->group_suite == CIPHER_NONE &&
|
|
||||||
params->key_mgmt_suite == KEY_MGMT_NONE &&
|
|
||||||
params->wpa_ie_len == 0);
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
|
|
||||||
|
|
||||||
if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (params->wpa_ie_len &&
|
|
||||||
set80211param(drv, IEEE80211_IOC_WPA,
|
|
||||||
params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
os_memset(&mlme, 0, sizeof(mlme));
|
|
||||||
mlme.im_op = IEEE80211_MLME_ASSOC;
|
|
||||||
if (params->ssid != NULL)
|
|
||||||
os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len);
|
|
||||||
mlme.im_ssid_len = params->ssid_len;
|
|
||||||
if (params->bssid != NULL)
|
|
||||||
os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
|
|
||||||
if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
int authmode;
|
|
||||||
|
|
||||||
if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
|
|
||||||
(auth_alg & AUTH_ALG_SHARED_KEY))
|
|
||||||
authmode = IEEE80211_AUTH_AUTO;
|
|
||||||
else if (auth_alg & AUTH_ALG_SHARED_KEY)
|
|
||||||
authmode = IEEE80211_AUTH_SHARED;
|
|
||||||
else
|
|
||||||
authmode = IEEE80211_AUTH_OPEN;
|
|
||||||
|
|
||||||
return set80211param(drv, IEEE80211_IOC_AUTHMODE, authmode);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
/* NB: interface must be marked UP to do a scan */
|
|
||||||
if (getifflags(drv, &flags) != 0 || setifflags(drv, flags | IFF_UP) != 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* set desired ssid before scan */
|
|
||||||
if (wpa_driver_bsd_set_ssid(drv, ssid, ssid_len) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* NB: net80211 delivers a scan complete event so no need to poll */
|
|
||||||
return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <net/route.h>
|
|
||||||
#if __FreeBSD__
|
|
||||||
#include <net80211/ieee80211_freebsd.h>
|
|
||||||
#endif
|
|
||||||
#if __NetBSD__
|
|
||||||
#include <net80211/ieee80211_netbsd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
|
||||||
wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = sock_ctx;
|
|
||||||
char buf[2048];
|
|
||||||
struct if_announcemsghdr *ifan;
|
|
||||||
struct if_msghdr *ifm;
|
|
||||||
struct rt_msghdr *rtm;
|
|
||||||
union wpa_event_data event;
|
|
||||||
struct ieee80211_michael_event *mic;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
n = read(sock, buf, sizeof(buf));
|
|
||||||
if (n < 0) {
|
|
||||||
if (errno != EINTR && errno != EAGAIN)
|
|
||||||
perror("read(PF_ROUTE)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtm = (struct rt_msghdr *) buf;
|
|
||||||
if (rtm->rtm_version != RTM_VERSION) {
|
|
||||||
wpa_printf(MSG_DEBUG, "Routing message version %d not "
|
|
||||||
"understood\n", rtm->rtm_version);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
os_memset(&event, 0, sizeof(event));
|
|
||||||
switch (rtm->rtm_type) {
|
|
||||||
case RTM_IFANNOUNCE:
|
|
||||||
ifan = (struct if_announcemsghdr *) rtm;
|
|
||||||
if (ifan->ifan_index != drv->ifindex)
|
|
||||||
break;
|
|
||||||
strlcpy(event.interface_status.ifname, drv->ifname,
|
|
||||||
sizeof(event.interface_status.ifname));
|
|
||||||
switch (ifan->ifan_what) {
|
|
||||||
case IFAN_DEPARTURE:
|
|
||||||
event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
|
|
||||||
event.interface_status.ifname,
|
|
||||||
ifan->ifan_what == IFAN_DEPARTURE ?
|
|
||||||
"removed" : "added");
|
|
||||||
wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
|
|
||||||
break;
|
|
||||||
case RTM_IEEE80211:
|
|
||||||
ifan = (struct if_announcemsghdr *) rtm;
|
|
||||||
if (ifan->ifan_index != drv->ifindex)
|
|
||||||
break;
|
|
||||||
switch (ifan->ifan_what) {
|
|
||||||
case RTM_IEEE80211_ASSOC:
|
|
||||||
case RTM_IEEE80211_REASSOC:
|
|
||||||
wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
|
|
||||||
break;
|
|
||||||
case RTM_IEEE80211_DISASSOC:
|
|
||||||
wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
|
|
||||||
break;
|
|
||||||
case RTM_IEEE80211_SCAN:
|
|
||||||
wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
|
|
||||||
break;
|
|
||||||
case RTM_IEEE80211_REPLAY:
|
|
||||||
/* ignore */
|
|
||||||
break;
|
|
||||||
case RTM_IEEE80211_MICHAEL:
|
|
||||||
mic = (struct ieee80211_michael_event *) &ifan[1];
|
|
||||||
wpa_printf(MSG_DEBUG,
|
|
||||||
"Michael MIC failure wireless event: "
|
|
||||||
"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
|
|
||||||
MAC2STR(mic->iev_src));
|
|
||||||
|
|
||||||
os_memset(&event, 0, sizeof(event));
|
|
||||||
event.michael_mic_failure.unicast =
|
|
||||||
!IEEE80211_IS_MULTICAST(mic->iev_dst);
|
|
||||||
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE,
|
|
||||||
&event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RTM_IFINFO:
|
|
||||||
ifm = (struct if_msghdr *) rtm;
|
|
||||||
if (ifm->ifm_index != drv->ifindex)
|
|
||||||
break;
|
|
||||||
if ((rtm->rtm_flags & RTF_UP) == 0) {
|
|
||||||
strlcpy(event.interface_status.ifname, drv->ifname,
|
|
||||||
sizeof(event.interface_status.ifname));
|
|
||||||
event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
|
|
||||||
wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
|
|
||||||
event.interface_status.ifname);
|
|
||||||
wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compare function for sorting scan results. Return >0 if @b is consider
|
|
||||||
* better. */
|
|
||||||
static int
|
|
||||||
wpa_scan_result_compar(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
const struct wpa_scan_result *wa = a;
|
|
||||||
const struct wpa_scan_result *wb = b;
|
|
||||||
|
|
||||||
/* WPA/WPA2 support preferred */
|
|
||||||
if ((wb->wpa_ie_len || wb->rsn_ie_len) &&
|
|
||||||
!(wa->wpa_ie_len || wa->rsn_ie_len))
|
|
||||||
return 1;
|
|
||||||
if (!(wb->wpa_ie_len || wb->rsn_ie_len) &&
|
|
||||||
(wa->wpa_ie_len || wa->rsn_ie_len))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* privacy support preferred */
|
|
||||||
if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) &&
|
|
||||||
(wb->caps & IEEE80211_CAPINFO_PRIVACY) == 0)
|
|
||||||
return 1;
|
|
||||||
if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) == 0 &&
|
|
||||||
(wb->caps & IEEE80211_CAPINFO_PRIVACY))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* best/max rate preferred if signal level close enough XXX */
|
|
||||||
if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5)
|
|
||||||
return wb->maxrate - wa->maxrate;
|
|
||||||
|
|
||||||
/* use freq for channel preference */
|
|
||||||
|
|
||||||
/* all things being equal, use signal level */
|
|
||||||
return wb->level - wa->level;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
getmaxrate(uint8_t rates[15], uint8_t nrates)
|
|
||||||
{
|
|
||||||
int i, maxrate = -1;
|
|
||||||
|
|
||||||
for (i = 0; i < nrates; i++) {
|
|
||||||
int rate = rates[i] & IEEE80211_RATE_VAL;
|
|
||||||
if (rate > maxrate)
|
|
||||||
rate = maxrate;
|
|
||||||
}
|
|
||||||
return maxrate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* unalligned little endian access */
|
|
||||||
#define LE_READ_4(p) \
|
|
||||||
((u_int32_t) \
|
|
||||||
((((const u_int8_t *)(p))[0] ) | \
|
|
||||||
(((const u_int8_t *)(p))[1] << 8) | \
|
|
||||||
(((const u_int8_t *)(p))[2] << 16) | \
|
|
||||||
(((const u_int8_t *)(p))[3] << 24)))
|
|
||||||
|
|
||||||
static int __inline
|
|
||||||
iswpaoui(const u_int8_t *frm)
|
|
||||||
{
|
|
||||||
return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_bsd_get_scan_results(void *priv,
|
|
||||||
struct wpa_scan_result *results,
|
|
||||||
size_t max_size)
|
|
||||||
{
|
|
||||||
#define min(a,b) ((a)>(b)?(b):(a))
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
uint8_t buf[24*1024];
|
|
||||||
uint8_t *cp, *vp;
|
|
||||||
struct ieee80211req_scan_result *sr;
|
|
||||||
struct wpa_scan_result *wsr;
|
|
||||||
int len, ielen;
|
|
||||||
|
|
||||||
os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
|
|
||||||
|
|
||||||
len = get80211var(drv, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf));
|
|
||||||
if (len < 0)
|
|
||||||
return -1;
|
|
||||||
cp = buf;
|
|
||||||
wsr = results;
|
|
||||||
while (len >= sizeof(struct ieee80211req_scan_result)) {
|
|
||||||
sr = (struct ieee80211req_scan_result *) cp;
|
|
||||||
os_memcpy(wsr->bssid, sr->isr_bssid, IEEE80211_ADDR_LEN);
|
|
||||||
wsr->ssid_len = sr->isr_ssid_len;
|
|
||||||
wsr->freq = sr->isr_freq;
|
|
||||||
wsr->noise = sr->isr_noise;
|
|
||||||
wsr->qual = sr->isr_rssi;
|
|
||||||
wsr->level = 0; /* XXX? */
|
|
||||||
wsr->caps = sr->isr_capinfo;
|
|
||||||
wsr->maxrate = getmaxrate(sr->isr_rates, sr->isr_nrates);
|
|
||||||
vp = (u_int8_t *)(sr+1);
|
|
||||||
os_memcpy(wsr->ssid, vp, sr->isr_ssid_len);
|
|
||||||
if (sr->isr_ie_len > 0) {
|
|
||||||
vp += sr->isr_ssid_len;
|
|
||||||
ielen = sr->isr_ie_len;
|
|
||||||
while (ielen > 0) {
|
|
||||||
switch (vp[0]) {
|
|
||||||
case IEEE80211_ELEMID_VENDOR:
|
|
||||||
if (!iswpaoui(vp))
|
|
||||||
break;
|
|
||||||
wsr->wpa_ie_len =
|
|
||||||
min(2+vp[1], SSID_MAX_WPA_IE_LEN);
|
|
||||||
os_memcpy(wsr->wpa_ie, vp,
|
|
||||||
wsr->wpa_ie_len);
|
|
||||||
break;
|
|
||||||
case IEEE80211_ELEMID_RSN:
|
|
||||||
wsr->rsn_ie_len =
|
|
||||||
min(2+vp[1], SSID_MAX_WPA_IE_LEN);
|
|
||||||
os_memcpy(wsr->rsn_ie, vp,
|
|
||||||
wsr->rsn_ie_len);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ielen -= 2+vp[1];
|
|
||||||
vp += 2+vp[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cp += sr->isr_len, len -= sr->isr_len;
|
|
||||||
wsr++;
|
|
||||||
}
|
|
||||||
qsort(results, wsr - results, sizeof(struct wpa_scan_result),
|
|
||||||
wpa_scan_result_compar);
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%d BSSes)",
|
|
||||||
len, wsr - results);
|
|
||||||
|
|
||||||
return wsr - results;
|
|
||||||
#undef min
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
|
||||||
wpa_driver_bsd_init(void *ctx, const char *ifname)
|
|
||||||
{
|
|
||||||
#define GETPARAM(drv, param, v) \
|
|
||||||
(((v) = get80211param(drv, param)) != -1)
|
|
||||||
struct wpa_driver_bsd_data *drv;
|
|
||||||
|
|
||||||
drv = os_zalloc(sizeof(*drv));
|
|
||||||
if (drv == NULL)
|
|
||||||
return NULL;
|
|
||||||
/*
|
|
||||||
* NB: We require the interface name be mappable to an index.
|
|
||||||
* This implies we do not support having wpa_supplicant
|
|
||||||
* wait for an interface to appear. This seems ok; that
|
|
||||||
* doesn't belong here; it's really the job of devd.
|
|
||||||
*/
|
|
||||||
drv->ifindex = if_nametoindex(ifname);
|
|
||||||
if (drv->ifindex == 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
|
|
||||||
__func__, ifname);
|
|
||||||
goto fail1;
|
|
||||||
}
|
|
||||||
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (drv->sock < 0)
|
|
||||||
goto fail1;
|
|
||||||
drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
|
|
||||||
if (drv->route < 0)
|
|
||||||
goto fail;
|
|
||||||
eloop_register_read_sock(drv->route,
|
|
||||||
wpa_driver_bsd_event_receive, ctx, drv);
|
|
||||||
|
|
||||||
drv->ctx = ctx;
|
|
||||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
|
||||||
|
|
||||||
if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
|
|
||||||
__func__, strerror(errno));
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s",
|
|
||||||
__func__, strerror(errno));
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s",
|
|
||||||
__func__, strerror(errno));
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (set80211param(drv, IEEE80211_IOC_ROAMING, IEEE80211_ROAMING_MANUAL) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
|
|
||||||
"roaming: %s", __func__, strerror(errno));
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (set80211param(drv, IEEE80211_IOC_WPA, 1+2) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support %s",
|
|
||||||
__func__, strerror(errno));
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
return drv;
|
|
||||||
fail:
|
|
||||||
close(drv->sock);
|
|
||||||
fail1:
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
#undef GETPARAM
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
wpa_driver_bsd_deinit(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_bsd_data *drv = priv;
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
eloop_unregister_read_sock(drv->route);
|
|
||||||
|
|
||||||
/* NB: mark interface down */
|
|
||||||
if (getifflags(drv, &flags) == 0)
|
|
||||||
(void) setifflags(drv, flags &~ IFF_UP);
|
|
||||||
|
|
||||||
wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
|
|
||||||
if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
|
|
||||||
__func__);
|
|
||||||
|
|
||||||
(void) close(drv->route); /* ioctl socket */
|
|
||||||
(void) close(drv->sock); /* event socket */
|
|
||||||
os_free(drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const struct wpa_driver_ops wpa_driver_bsd_ops = {
|
|
||||||
.name = "bsd",
|
|
||||||
.desc = "BSD 802.11 support (Atheros, etc.)",
|
|
||||||
.init = wpa_driver_bsd_init,
|
|
||||||
.deinit = wpa_driver_bsd_deinit,
|
|
||||||
.get_bssid = wpa_driver_bsd_get_bssid,
|
|
||||||
.get_ssid = wpa_driver_bsd_get_ssid,
|
|
||||||
.set_wpa = wpa_driver_bsd_set_wpa,
|
|
||||||
.set_key = wpa_driver_bsd_set_key,
|
|
||||||
.set_countermeasures = wpa_driver_bsd_set_countermeasures,
|
|
||||||
.set_drop_unencrypted = wpa_driver_bsd_set_drop_unencrypted,
|
|
||||||
.scan = wpa_driver_bsd_scan,
|
|
||||||
.get_scan_results = wpa_driver_bsd_get_scan_results,
|
|
||||||
.deauthenticate = wpa_driver_bsd_deauthenticate,
|
|
||||||
.disassociate = wpa_driver_bsd_disassociate,
|
|
||||||
.associate = wpa_driver_bsd_associate,
|
|
||||||
.set_auth_alg = wpa_driver_bsd_set_auth_alg,
|
|
||||||
};
|
|
@ -1,513 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - driver interaction with Linux Host AP driver
|
|
||||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
#include "wireless_copy.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include "driver.h"
|
|
||||||
#include "driver_wext.h"
|
|
||||||
#include "eloop.h"
|
|
||||||
#include "driver_hostap.h"
|
|
||||||
|
|
||||||
|
|
||||||
struct wpa_driver_hostap_data {
|
|
||||||
void *wext; /* private data for driver_wext */
|
|
||||||
void *ctx;
|
|
||||||
char ifname[IFNAMSIZ + 1];
|
|
||||||
int sock;
|
|
||||||
int current_mode; /* infra/adhoc */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static int hostapd_ioctl(struct wpa_driver_hostap_data *drv,
|
|
||||||
struct prism2_hostapd_param *param,
|
|
||||||
int len, int show_err)
|
|
||||||
{
|
|
||||||
struct iwreq iwr;
|
|
||||||
|
|
||||||
os_memset(&iwr, 0, sizeof(iwr));
|
|
||||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
iwr.u.data.pointer = (caddr_t) param;
|
|
||||||
iwr.u.data.length = len;
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
|
|
||||||
int ret = errno;
|
|
||||||
if (show_err)
|
|
||||||
perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data *drv,
|
|
||||||
const u8 *wpa_ie, size_t wpa_ie_len)
|
|
||||||
{
|
|
||||||
struct prism2_hostapd_param *param;
|
|
||||||
int res;
|
|
||||||
size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
|
|
||||||
if (blen < sizeof(*param))
|
|
||||||
blen = sizeof(*param);
|
|
||||||
|
|
||||||
param = os_zalloc(blen);
|
|
||||||
if (param == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
|
|
||||||
param->u.generic_elem.len = wpa_ie_len;
|
|
||||||
os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
|
|
||||||
res = hostapd_ioctl(drv, param, blen, 1);
|
|
||||||
|
|
||||||
os_free(param);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int prism2param(struct wpa_driver_hostap_data *drv, int param,
|
|
||||||
int value)
|
|
||||||
{
|
|
||||||
struct iwreq iwr;
|
|
||||||
int *i, ret = 0;
|
|
||||||
|
|
||||||
os_memset(&iwr, 0, sizeof(iwr));
|
|
||||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
i = (int *) iwr.u.name;
|
|
||||||
*i++ = param;
|
|
||||||
*i++ = value;
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
|
|
||||||
perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_set_wpa(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
|
||||||
|
|
||||||
if (!enabled && wpa_driver_hostap_set_wpa_ie(drv, NULL, 0) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, enabled ? 2 : 0) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (prism2param(drv, PRISM2_PARAM_WPA, enabled) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void show_set_key_error(struct prism2_hostapd_param *param)
|
|
||||||
{
|
|
||||||
switch (param->u.crypt.err) {
|
|
||||||
case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
|
|
||||||
wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
|
|
||||||
param->u.crypt.alg);
|
|
||||||
wpa_printf(MSG_INFO, "You may need to load kernel module to "
|
|
||||||
"register that algorithm.");
|
|
||||||
wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
|
|
||||||
"WEP.");
|
|
||||||
break;
|
|
||||||
case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
|
|
||||||
wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
|
|
||||||
MAC2STR(param->sta_addr));
|
|
||||||
break;
|
|
||||||
case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
|
|
||||||
wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
|
|
||||||
break;
|
|
||||||
case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
|
|
||||||
wpa_printf(MSG_INFO, "Key setting failed.");
|
|
||||||
break;
|
|
||||||
case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
|
|
||||||
wpa_printf(MSG_INFO, "TX key index setting failed.");
|
|
||||||
break;
|
|
||||||
case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
|
|
||||||
wpa_printf(MSG_INFO, "Card configuration failed.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_set_key(void *priv, wpa_alg alg,
|
|
||||||
const u8 *addr, int key_idx,
|
|
||||||
int set_tx, const u8 *seq, size_t seq_len,
|
|
||||||
const u8 *key, size_t key_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
struct prism2_hostapd_param *param;
|
|
||||||
u8 *buf;
|
|
||||||
size_t blen;
|
|
||||||
int ret = 0;
|
|
||||||
char *alg_name;
|
|
||||||
|
|
||||||
switch (alg) {
|
|
||||||
case WPA_ALG_NONE:
|
|
||||||
alg_name = "none";
|
|
||||||
break;
|
|
||||||
case WPA_ALG_WEP:
|
|
||||||
alg_name = "WEP";
|
|
||||||
break;
|
|
||||||
case WPA_ALG_TKIP:
|
|
||||||
alg_name = "TKIP";
|
|
||||||
break;
|
|
||||||
case WPA_ALG_CCMP:
|
|
||||||
alg_name = "CCMP";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
|
|
||||||
"key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
|
|
||||||
(unsigned long) seq_len, (unsigned long) key_len);
|
|
||||||
|
|
||||||
if (seq_len > 8)
|
|
||||||
return -2;
|
|
||||||
|
|
||||||
blen = sizeof(*param) + key_len;
|
|
||||||
buf = os_zalloc(blen);
|
|
||||||
if (buf == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
param = (struct prism2_hostapd_param *) buf;
|
|
||||||
param->cmd = PRISM2_SET_ENCRYPTION;
|
|
||||||
/* TODO: In theory, STA in client mode can use five keys; four default
|
|
||||||
* keys for receiving (with keyidx 0..3) and one individual key for
|
|
||||||
* both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
|
|
||||||
* keyidx 0 is reserved for this unicast use and default keys can only
|
|
||||||
* use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
|
|
||||||
* This should be fine for more or less all cases, but for completeness
|
|
||||||
* sake, the driver could be enhanced to support the missing key. */
|
|
||||||
#if 0
|
|
||||||
if (addr == NULL)
|
|
||||||
os_memset(param->sta_addr, 0xff, ETH_ALEN);
|
|
||||||
else
|
|
||||||
os_memcpy(param->sta_addr, addr, ETH_ALEN);
|
|
||||||
#else
|
|
||||||
os_memset(param->sta_addr, 0xff, ETH_ALEN);
|
|
||||||
#endif
|
|
||||||
os_strlcpy((char *) param->u.crypt.alg, alg_name,
|
|
||||||
HOSTAP_CRYPT_ALG_NAME_LEN);
|
|
||||||
param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
|
|
||||||
param->u.crypt.idx = key_idx;
|
|
||||||
os_memcpy(param->u.crypt.seq, seq, seq_len);
|
|
||||||
param->u.crypt.key_len = key_len;
|
|
||||||
os_memcpy((u8 *) (param + 1), key, key_len);
|
|
||||||
|
|
||||||
if (hostapd_ioctl(drv, param, blen, 1)) {
|
|
||||||
wpa_printf(MSG_WARNING, "Failed to set encryption.");
|
|
||||||
show_set_key_error(param);
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
os_free(buf);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
|
||||||
return prism2param(drv, PRISM2_PARAM_TKIP_COUNTERMEASURES, enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_set_drop_unencrypted(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
|
||||||
return prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED, enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv,
|
|
||||||
int type)
|
|
||||||
{
|
|
||||||
struct iwreq iwr;
|
|
||||||
int *i, ret = 0;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: type=%d", __FUNCTION__, type);
|
|
||||||
|
|
||||||
os_memset(&iwr, 0, sizeof(iwr));
|
|
||||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
i = (int *) iwr.u.name;
|
|
||||||
*i++ = type;
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, PRISM2_IOCTL_RESET, &iwr) < 0) {
|
|
||||||
perror("ioctl[PRISM2_IOCTL_RESET]");
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data *drv,
|
|
||||||
const u8 *addr, int cmd, int reason_code)
|
|
||||||
{
|
|
||||||
struct prism2_hostapd_param param;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* There does not seem to be a better way of deauthenticating or
|
|
||||||
* disassociating with Prism2/2.5/3 than sending the management frame
|
|
||||||
* and then resetting the Port0 to make sure both the AP and the STA
|
|
||||||
* end up in disconnected state. */
|
|
||||||
os_memset(¶m, 0, sizeof(param));
|
|
||||||
param.cmd = PRISM2_HOSTAPD_MLME;
|
|
||||||
os_memcpy(param.sta_addr, addr, ETH_ALEN);
|
|
||||||
param.u.mlme.cmd = cmd;
|
|
||||||
param.u.mlme.reason_code = reason_code;
|
|
||||||
ret = hostapd_ioctl(drv, ¶m, sizeof(param), 1);
|
|
||||||
if (ret == 0) {
|
|
||||||
os_sleep(0, 100000);
|
|
||||||
ret = wpa_driver_hostap_reset(drv, 2);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_deauthenticate(void *priv, const u8 *addr,
|
|
||||||
int reason_code)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
|
||||||
return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DEAUTH,
|
|
||||||
reason_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_disassociate(void *priv, const u8 *addr,
|
|
||||||
int reason_code)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
|
||||||
return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DISASSOC,
|
|
||||||
reason_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_hostap_associate(void *priv,
|
|
||||||
struct wpa_driver_associate_params *params)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
int ret = 0;
|
|
||||||
int allow_unencrypted_eapol;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
|
||||||
|
|
||||||
if (params->mode != drv->current_mode) {
|
|
||||||
/* At the moment, Host AP driver requires host_roaming=2 for
|
|
||||||
* infrastructure mode and host_roaming=0 for adhoc. */
|
|
||||||
if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING,
|
|
||||||
params->mode == IEEE80211_MODE_IBSS ? 0 : 2) <
|
|
||||||
0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: failed to set host_roaming",
|
|
||||||
__func__);
|
|
||||||
}
|
|
||||||
drv->current_mode = params->mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
|
|
||||||
params->key_mgmt_suite != KEY_MGMT_NONE) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (wpa_driver_hostap_set_wpa_ie(drv, params->wpa_ie,
|
|
||||||
params->wpa_ie_len) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (wpa_driver_wext_set_mode(drv->wext, params->mode) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (params->freq &&
|
|
||||||
wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
|
|
||||||
< 0)
|
|
||||||
ret = -1;
|
|
||||||
if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
/* Allow unencrypted EAPOL messages even if pairwise keys are set when
|
|
||||||
* not using WPA. IEEE 802.1X specifies that these frames are not
|
|
||||||
* encrypted, but WPA encrypts them when pairwise keys are in use. */
|
|
||||||
if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
|
|
||||||
params->key_mgmt_suite == KEY_MGMT_PSK)
|
|
||||||
allow_unencrypted_eapol = 0;
|
|
||||||
else
|
|
||||||
allow_unencrypted_eapol = 1;
|
|
||||||
|
|
||||||
if (prism2param(drv, PRISM2_PARAM_IEEE_802_1X,
|
|
||||||
allow_unencrypted_eapol) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "hostap: Failed to configure "
|
|
||||||
"ieee_802_1x param");
|
|
||||||
/* Ignore this error.. driver_hostap.c can also be used with
|
|
||||||
* other drivers that do not support this prism2_param. */
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
struct prism2_hostapd_param param;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (ssid == NULL) {
|
|
||||||
/* Use standard Linux Wireless Extensions ioctl if possible
|
|
||||||
* because some drivers using hostap code in wpa_supplicant
|
|
||||||
* might not support Host AP specific scan request (with SSID
|
|
||||||
* info). */
|
|
||||||
return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ssid_len > 32)
|
|
||||||
ssid_len = 32;
|
|
||||||
|
|
||||||
os_memset(¶m, 0, sizeof(param));
|
|
||||||
param.cmd = PRISM2_HOSTAPD_SCAN_REQ;
|
|
||||||
param.u.scan_req.ssid_len = ssid_len;
|
|
||||||
os_memcpy(param.u.scan_req.ssid, ssid, ssid_len);
|
|
||||||
ret = hostapd_ioctl(drv, ¶m, sizeof(param), 1);
|
|
||||||
|
|
||||||
/* Not all drivers generate "scan completed" wireless event, so try to
|
|
||||||
* read results after a timeout. */
|
|
||||||
eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
|
|
||||||
drv->ctx);
|
|
||||||
eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv->wext,
|
|
||||||
drv->ctx);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
int algs = 0;
|
|
||||||
|
|
||||||
if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
|
|
||||||
algs |= 1;
|
|
||||||
if (auth_alg & AUTH_ALG_SHARED_KEY)
|
|
||||||
algs |= 2;
|
|
||||||
if (auth_alg & AUTH_ALG_LEAP)
|
|
||||||
algs |= 4;
|
|
||||||
if (algs == 0)
|
|
||||||
algs = 1; /* at least one algorithm should be set */
|
|
||||||
|
|
||||||
return prism2param(drv, PRISM2_PARAM_AP_AUTH_ALGS, algs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_get_bssid(void *priv, u8 *bssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_bssid(drv->wext, bssid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_get_ssid(void *priv, u8 *ssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_ssid(drv->wext, ssid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct wpa_scan_results * wpa_driver_hostap_get_scan_results(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_scan_results(drv->wext);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_hostap_set_operstate(void *priv, int state)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
return wpa_driver_wext_set_operstate(drv->wext, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void * wpa_driver_hostap_init(void *ctx, const char *ifname)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv;
|
|
||||||
|
|
||||||
drv = os_zalloc(sizeof(*drv));
|
|
||||||
if (drv == NULL)
|
|
||||||
return NULL;
|
|
||||||
drv->wext = wpa_driver_wext_init(ctx, ifname);
|
|
||||||
if (drv->wext == NULL) {
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
drv->ctx = ctx;
|
|
||||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
|
||||||
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (drv->sock < 0) {
|
|
||||||
perror("socket");
|
|
||||||
wpa_driver_wext_deinit(drv->wext);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (os_strncmp(ifname, "wlan", 4) == 0) {
|
|
||||||
/*
|
|
||||||
* Host AP driver may use both wlan# and wifi# interface in
|
|
||||||
* wireless events.
|
|
||||||
*/
|
|
||||||
char ifname2[IFNAMSIZ + 1];
|
|
||||||
os_strlcpy(ifname2, ifname, sizeof(ifname2));
|
|
||||||
os_memcpy(ifname2, "wifi", 4);
|
|
||||||
wpa_driver_wext_alternative_ifindex(drv->wext, ifname2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_hostap_deinit(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_hostap_data *drv = priv;
|
|
||||||
wpa_driver_wext_deinit(drv->wext);
|
|
||||||
close(drv->sock);
|
|
||||||
os_free(drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const struct wpa_driver_ops wpa_driver_hostap_ops = {
|
|
||||||
.name = "hostap",
|
|
||||||
.desc = "Host AP driver (Intersil Prism2/2.5/3)",
|
|
||||||
.get_bssid = wpa_driver_hostap_get_bssid,
|
|
||||||
.get_ssid = wpa_driver_hostap_get_ssid,
|
|
||||||
.set_wpa = wpa_driver_hostap_set_wpa,
|
|
||||||
.set_key = wpa_driver_hostap_set_key,
|
|
||||||
.set_countermeasures = wpa_driver_hostap_set_countermeasures,
|
|
||||||
.set_drop_unencrypted = wpa_driver_hostap_set_drop_unencrypted,
|
|
||||||
.scan = wpa_driver_hostap_scan,
|
|
||||||
.get_scan_results2 = wpa_driver_hostap_get_scan_results,
|
|
||||||
.deauthenticate = wpa_driver_hostap_deauthenticate,
|
|
||||||
.disassociate = wpa_driver_hostap_disassociate,
|
|
||||||
.associate = wpa_driver_hostap_associate,
|
|
||||||
.set_auth_alg = wpa_driver_hostap_set_auth_alg,
|
|
||||||
.init = wpa_driver_hostap_init,
|
|
||||||
.deinit = wpa_driver_hostap_deinit,
|
|
||||||
.set_operstate = wpa_driver_hostap_set_operstate,
|
|
||||||
};
|
|
@ -1,153 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - driver interaction with Linux Host AP driver
|
|
||||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef HOSTAP_DRIVER_H
|
|
||||||
#define HOSTAP_DRIVER_H
|
|
||||||
|
|
||||||
#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
|
|
||||||
#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
|
|
||||||
#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
|
|
||||||
|
|
||||||
/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
|
|
||||||
enum {
|
|
||||||
/* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
|
|
||||||
PRISM2_PARAM_TXRATECTRL = 2,
|
|
||||||
PRISM2_PARAM_BEACON_INT = 3,
|
|
||||||
PRISM2_PARAM_PSEUDO_IBSS = 4,
|
|
||||||
PRISM2_PARAM_ALC = 5,
|
|
||||||
/* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
|
|
||||||
PRISM2_PARAM_DUMP = 7,
|
|
||||||
PRISM2_PARAM_OTHER_AP_POLICY = 8,
|
|
||||||
PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
|
|
||||||
PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
|
|
||||||
PRISM2_PARAM_DTIM_PERIOD = 11,
|
|
||||||
PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
|
|
||||||
PRISM2_PARAM_MAX_WDS = 13,
|
|
||||||
PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
|
|
||||||
PRISM2_PARAM_AP_AUTH_ALGS = 15,
|
|
||||||
PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
|
|
||||||
PRISM2_PARAM_HOST_ENCRYPT = 17,
|
|
||||||
PRISM2_PARAM_HOST_DECRYPT = 18,
|
|
||||||
PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19,
|
|
||||||
PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20,
|
|
||||||
PRISM2_PARAM_HOST_ROAMING = 21,
|
|
||||||
PRISM2_PARAM_BCRX_STA_KEY = 22,
|
|
||||||
PRISM2_PARAM_IEEE_802_1X = 23,
|
|
||||||
PRISM2_PARAM_ANTSEL_TX = 24,
|
|
||||||
PRISM2_PARAM_ANTSEL_RX = 25,
|
|
||||||
PRISM2_PARAM_MONITOR_TYPE = 26,
|
|
||||||
PRISM2_PARAM_WDS_TYPE = 27,
|
|
||||||
PRISM2_PARAM_HOSTSCAN = 28,
|
|
||||||
PRISM2_PARAM_AP_SCAN = 29,
|
|
||||||
PRISM2_PARAM_ENH_SEC = 30,
|
|
||||||
PRISM2_PARAM_IO_DEBUG = 31,
|
|
||||||
PRISM2_PARAM_BASIC_RATES = 32,
|
|
||||||
PRISM2_PARAM_OPER_RATES = 33,
|
|
||||||
PRISM2_PARAM_HOSTAPD = 34,
|
|
||||||
PRISM2_PARAM_HOSTAPD_STA = 35,
|
|
||||||
PRISM2_PARAM_WPA = 36,
|
|
||||||
PRISM2_PARAM_PRIVACY_INVOKED = 37,
|
|
||||||
PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
|
|
||||||
PRISM2_PARAM_DROP_UNENCRYPTED = 39,
|
|
||||||
PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
|
|
||||||
enum {
|
|
||||||
PRISM2_HOSTAPD_FLUSH = 1,
|
|
||||||
PRISM2_HOSTAPD_ADD_STA = 2,
|
|
||||||
PRISM2_HOSTAPD_REMOVE_STA = 3,
|
|
||||||
PRISM2_HOSTAPD_GET_INFO_STA = 4,
|
|
||||||
/* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
|
|
||||||
PRISM2_SET_ENCRYPTION = 6,
|
|
||||||
PRISM2_GET_ENCRYPTION = 7,
|
|
||||||
PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
|
|
||||||
PRISM2_HOSTAPD_GET_RID = 9,
|
|
||||||
PRISM2_HOSTAPD_SET_RID = 10,
|
|
||||||
PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
|
|
||||||
PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
|
|
||||||
PRISM2_HOSTAPD_MLME = 13,
|
|
||||||
PRISM2_HOSTAPD_SCAN_REQ = 14,
|
|
||||||
PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
|
|
||||||
#define PRISM2_HOSTAPD_RID_HDR_LEN \
|
|
||||||
((size_t) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
|
|
||||||
#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
|
|
||||||
((size_t) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
|
|
||||||
|
|
||||||
/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
|
|
||||||
*/
|
|
||||||
#define HOSTAP_CRYPT_ALG_NAME_LEN 16
|
|
||||||
|
|
||||||
|
|
||||||
struct prism2_hostapd_param {
|
|
||||||
u32 cmd;
|
|
||||||
u8 sta_addr[ETH_ALEN];
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
u16 aid;
|
|
||||||
u16 capability;
|
|
||||||
u8 tx_supp_rates;
|
|
||||||
} add_sta;
|
|
||||||
struct {
|
|
||||||
u32 inactive_sec;
|
|
||||||
} get_info_sta;
|
|
||||||
struct {
|
|
||||||
u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
|
|
||||||
u32 flags;
|
|
||||||
u32 err;
|
|
||||||
u8 idx;
|
|
||||||
u8 seq[8]; /* sequence counter (set: RX, get: TX) */
|
|
||||||
u16 key_len;
|
|
||||||
u8 key[0];
|
|
||||||
} crypt;
|
|
||||||
struct {
|
|
||||||
u32 flags_and;
|
|
||||||
u32 flags_or;
|
|
||||||
} set_flags_sta;
|
|
||||||
struct {
|
|
||||||
u16 rid;
|
|
||||||
u16 len;
|
|
||||||
u8 data[0];
|
|
||||||
} rid;
|
|
||||||
struct {
|
|
||||||
u8 len;
|
|
||||||
u8 data[0];
|
|
||||||
} generic_elem;
|
|
||||||
struct {
|
|
||||||
#define MLME_STA_DEAUTH 0
|
|
||||||
#define MLME_STA_DISASSOC 1
|
|
||||||
u16 cmd;
|
|
||||||
u16 reason_code;
|
|
||||||
} mlme;
|
|
||||||
struct {
|
|
||||||
u8 ssid_len;
|
|
||||||
u8 ssid[32];
|
|
||||||
} scan_req;
|
|
||||||
} u;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define HOSTAP_CRYPT_FLAG_SET_TX_KEY 0x01
|
|
||||||
#define HOSTAP_CRYPT_FLAG_PERMANENT 0x02
|
|
||||||
|
|
||||||
#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
|
|
||||||
#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
|
|
||||||
#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
|
|
||||||
#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
|
|
||||||
#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
|
|
||||||
#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
|
|
||||||
|
|
||||||
#endif /* HOSTAP_DRIVER_H */
|
|
@ -1,466 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
|
|
||||||
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#define Boolean __DummyBoolean
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
|
||||||
#undef Boolean
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "driver.h"
|
|
||||||
#include "eloop.h"
|
|
||||||
#include "ieee802_11_defs.h"
|
|
||||||
|
|
||||||
#include "MobileApple80211.h"
|
|
||||||
|
|
||||||
struct wpa_driver_iphone_data {
|
|
||||||
void *ctx;
|
|
||||||
Apple80211Ref wireless_ctx;
|
|
||||||
CFArrayRef scan_results;
|
|
||||||
int ctrl_power;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
|
|
||||||
{
|
|
||||||
const void *res;
|
|
||||||
CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
|
|
||||||
kCFStringEncodingMacRoman);
|
|
||||||
if (str == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
res = CFDictionaryGetValue(dict, str);
|
|
||||||
CFRelease(str);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_iphone_data *drv = priv;
|
|
||||||
CFDataRef data;
|
|
||||||
int err, len;
|
|
||||||
|
|
||||||
err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
|
|
||||||
&data);
|
|
||||||
if (err != 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
|
|
||||||
"failed: %d", err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = CFDataGetLength(data);
|
|
||||||
if (len > 32) {
|
|
||||||
CFRelease(data);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
os_memcpy(ssid, CFDataGetBytePtr(data), len);
|
|
||||||
CFRelease(data);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_iphone_data *drv = priv;
|
|
||||||
CFStringRef data;
|
|
||||||
int err;
|
|
||||||
int a1, a2, a3, a4, a5, a6;
|
|
||||||
|
|
||||||
err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
|
|
||||||
&data);
|
|
||||||
if (err != 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
|
|
||||||
"failed: %d", err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
|
|
||||||
"%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
|
|
||||||
bssid[0] = a1;
|
|
||||||
bssid[1] = a2;
|
|
||||||
bssid[2] = a3;
|
|
||||||
bssid[3] = a4;
|
|
||||||
bssid[4] = a5;
|
|
||||||
bssid[5] = a6;
|
|
||||||
|
|
||||||
CFRelease(data);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
|
|
||||||
{
|
|
||||||
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_iphone_data *drv = priv;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (drv->scan_results) {
|
|
||||||
CFRelease(drv->scan_results);
|
|
||||||
drv->scan_results = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
|
|
||||||
err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
|
|
||||||
drv->ctx);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_iphone_get_scan_results(void *priv,
|
|
||||||
struct wpa_scan_result *results,
|
|
||||||
size_t max_size)
|
|
||||||
{
|
|
||||||
struct wpa_driver_iphone_data *drv = priv;
|
|
||||||
size_t i, num;
|
|
||||||
|
|
||||||
if (drv->scan_results == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
num = CFArrayGetCount(drv->scan_results);
|
|
||||||
if (num > max_size)
|
|
||||||
num = max_size;
|
|
||||||
os_memset(results, 0, num * sizeof(struct wpa_scan_result));
|
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
struct wpa_scan_result *res = &results[i];
|
|
||||||
CFDictionaryRef dict =
|
|
||||||
CFArrayGetValueAtIndex(drv->scan_results, i);
|
|
||||||
CFDataRef data;
|
|
||||||
CFStringRef str;
|
|
||||||
CFNumberRef num;
|
|
||||||
int val;
|
|
||||||
|
|
||||||
data = cfdict_get_key_str(dict, "SSID");
|
|
||||||
if (data) {
|
|
||||||
res->ssid_len = CFDataGetLength(data);
|
|
||||||
if (res->ssid_len > 32)
|
|
||||||
res->ssid_len = 32;
|
|
||||||
os_memcpy(res->ssid, CFDataGetBytePtr(data),
|
|
||||||
res->ssid_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
str = cfdict_get_key_str(dict, "BSSID");
|
|
||||||
if (str) {
|
|
||||||
int a1, a2, a3, a4, a5, a6;
|
|
||||||
sscanf(CFStringGetCStringPtr(
|
|
||||||
str, kCFStringEncodingMacRoman),
|
|
||||||
"%x:%x:%x:%x:%x:%x",
|
|
||||||
&a1, &a2, &a3, &a4, &a5, &a6);
|
|
||||||
res->bssid[0] = a1;
|
|
||||||
res->bssid[1] = a2;
|
|
||||||
res->bssid[2] = a3;
|
|
||||||
res->bssid[3] = a4;
|
|
||||||
res->bssid[4] = a5;
|
|
||||||
res->bssid[5] = a6;
|
|
||||||
}
|
|
||||||
|
|
||||||
num = cfdict_get_key_str(dict, "CAPABILITIES");
|
|
||||||
if (num) {
|
|
||||||
if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
|
|
||||||
res->caps = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
num = cfdict_get_key_str(dict, "CHANNEL");
|
|
||||||
if (num) {
|
|
||||||
if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
|
|
||||||
res->freq = 2407 + val * 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
num = cfdict_get_key_str(dict, "RSSI");
|
|
||||||
if (num) {
|
|
||||||
if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
|
|
||||||
res->level = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
num = cfdict_get_key_str(dict, "NOISE");
|
|
||||||
if (num) {
|
|
||||||
if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
|
|
||||||
res->noise = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = cfdict_get_key_str(dict, "IE");
|
|
||||||
if (data) {
|
|
||||||
u8 *ptr = (u8 *) CFDataGetBytePtr(data);
|
|
||||||
int len = CFDataGetLength(data);
|
|
||||||
u8 *pos = ptr, *end = ptr + len;
|
|
||||||
|
|
||||||
while (pos + 2 < end) {
|
|
||||||
if (pos + 2 + pos[1] > end)
|
|
||||||
break;
|
|
||||||
if (pos[0] == WLAN_EID_RSN &&
|
|
||||||
pos[1] <= SSID_MAX_WPA_IE_LEN) {
|
|
||||||
os_memcpy(res->rsn_ie, pos,
|
|
||||||
2 + pos[1]);
|
|
||||||
res->rsn_ie_len = 2 + pos[1];
|
|
||||||
}
|
|
||||||
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
|
|
||||||
pos[1] > 4 && pos[2] == 0x00 &&
|
|
||||||
pos[3] == 0x50 && pos[4] == 0xf2 &&
|
|
||||||
pos[5] == 0x01) {
|
|
||||||
os_memcpy(res->wpa_ie, pos,
|
|
||||||
2 + pos[1]);
|
|
||||||
res->wpa_ie_len = 2 + pos[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = pos + 2 + pos[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
|
|
||||||
{
|
|
||||||
struct wpa_driver_iphone_data *drv = eloop_ctx;
|
|
||||||
u8 bssid[ETH_ALEN];
|
|
||||||
|
|
||||||
if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
|
|
||||||
eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
|
|
||||||
drv, drv->ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_iphone_associate(
|
|
||||||
void *priv, struct wpa_driver_associate_params *params)
|
|
||||||
{
|
|
||||||
struct wpa_driver_iphone_data *drv = priv;
|
|
||||||
int i, num, err;
|
|
||||||
size_t ssid_len;
|
|
||||||
CFDictionaryRef bss = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: Consider generating parameters instead of just using an entry
|
|
||||||
* from scan results in order to support ap_scan=2.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (drv->scan_results == NULL) {
|
|
||||||
wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
|
|
||||||
"associate");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
num = CFArrayGetCount(drv->scan_results);
|
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
CFDictionaryRef dict =
|
|
||||||
CFArrayGetValueAtIndex(drv->scan_results, i);
|
|
||||||
CFDataRef data;
|
|
||||||
|
|
||||||
data = cfdict_get_key_str(dict, "SSID");
|
|
||||||
if (data == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ssid_len = CFDataGetLength(data);
|
|
||||||
if (ssid_len != params->ssid_len ||
|
|
||||||
os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
|
|
||||||
!= 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
bss = dict;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bss == NULL) {
|
|
||||||
wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
|
|
||||||
"results - cannot associate");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
|
|
||||||
"from scan results");
|
|
||||||
|
|
||||||
err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
|
|
||||||
"%d", err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Driver is actually already associated; report association from an
|
|
||||||
* eloop callback.
|
|
||||||
*/
|
|
||||||
eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
|
|
||||||
eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
|
|
||||||
drv->ctx);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr,
|
|
||||||
int key_idx, int set_tx, const u8 *seq,
|
|
||||||
size_t seq_len, const u8 *key,
|
|
||||||
size_t key_len)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* TODO: Need to either support configuring PMK for 4-way handshake or
|
|
||||||
* PTK for TKIP/CCMP.
|
|
||||||
*/
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
|
|
||||||
{
|
|
||||||
os_memset(capa, 0, sizeof(*capa));
|
|
||||||
|
|
||||||
capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
|
|
||||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
|
|
||||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
|
|
||||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
|
|
||||||
capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
|
|
||||||
WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
|
|
||||||
capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
|
|
||||||
WPA_DRIVER_AUTH_LEAP;
|
|
||||||
capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
|
|
||||||
{
|
|
||||||
struct wpa_driver_iphone_data *drv;
|
|
||||||
int err;
|
|
||||||
char power;
|
|
||||||
CFStringRef name;
|
|
||||||
CFDictionaryRef dict;
|
|
||||||
|
|
||||||
drv = os_zalloc(sizeof(*drv));
|
|
||||||
if (drv == NULL)
|
|
||||||
return NULL;
|
|
||||||
drv->ctx = ctx;
|
|
||||||
err = Apple80211Open(&drv->wireless_ctx);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
|
|
||||||
err);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
|
|
||||||
kCFStringEncodingISOLatin1);
|
|
||||||
if (name == NULL) {
|
|
||||||
wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
|
|
||||||
Apple80211Close(drv->wireless_ctx);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = Apple80211BindToInterface(drv->wireless_ctx, name);
|
|
||||||
CFRelease(name);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
|
|
||||||
"failed: %d", err);
|
|
||||||
Apple80211Close(drv->wireless_ctx);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = Apple80211GetPower(drv->wireless_ctx, &power);
|
|
||||||
if (err)
|
|
||||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
|
|
||||||
err);
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
|
|
||||||
|
|
||||||
if (!power) {
|
|
||||||
drv->ctrl_power = 1;
|
|
||||||
err = Apple80211SetPower(drv->wireless_ctx, 1);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
|
|
||||||
"failed: %d", err);
|
|
||||||
Apple80211Close(drv->wireless_ctx);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
|
|
||||||
if (err == 0) {
|
|
||||||
CFShow(dict);
|
|
||||||
CFRelease(dict);
|
|
||||||
} else {
|
|
||||||
printf("Apple80211GetInfoCopy: %d\n", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_iphone_deinit(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_iphone_data *drv = priv;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
|
|
||||||
eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
|
|
||||||
|
|
||||||
if (drv->ctrl_power) {
|
|
||||||
wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
|
|
||||||
err = Apple80211SetPower(drv->wireless_ctx, 0);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
|
|
||||||
"failed: %d", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = Apple80211Close(drv->wireless_ctx);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
|
|
||||||
err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drv->scan_results)
|
|
||||||
CFRelease(drv->scan_results);
|
|
||||||
|
|
||||||
os_free(drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const struct wpa_driver_ops wpa_driver_iphone_ops = {
|
|
||||||
.name = "iphone",
|
|
||||||
.desc = "iPhone/iPod touch Apple80211 driver",
|
|
||||||
.get_ssid = wpa_driver_iphone_get_ssid,
|
|
||||||
.get_bssid = wpa_driver_iphone_get_bssid,
|
|
||||||
.init = wpa_driver_iphone_init,
|
|
||||||
.deinit = wpa_driver_iphone_deinit,
|
|
||||||
.scan = wpa_driver_iphone_scan,
|
|
||||||
.get_scan_results = wpa_driver_iphone_get_scan_results,
|
|
||||||
.associate = wpa_driver_iphone_associate,
|
|
||||||
.set_key = wpa_driver_iphone_set_key,
|
|
||||||
.get_capa = wpa_driver_iphone_get_capa,
|
|
||||||
};
|
|
@ -1,463 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - driver interaction with Linux ipw2100/2200 drivers
|
|
||||||
* Copyright (c) 2005 Zhu Yi <yi.zhu@intel.com>
|
|
||||||
* Copyright (c) 2004 Lubomir Gelo <lgelo@cnc.sk>
|
|
||||||
* Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*
|
|
||||||
* Please note that ipw2100/2200 drivers change to use generic Linux wireless
|
|
||||||
* extensions if the kernel includes support for WE-18 or newer (Linux 2.6.13
|
|
||||||
* or newer). driver_wext.c should be used in those cases.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
#include "wireless_copy.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include "driver.h"
|
|
||||||
#include "driver_wext.h"
|
|
||||||
|
|
||||||
struct wpa_driver_ipw_data {
|
|
||||||
void *wext; /* private data for driver_wext */
|
|
||||||
void *ctx;
|
|
||||||
char ifname[IFNAMSIZ + 1];
|
|
||||||
int sock;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* following definitions must be kept in sync with ipw2100.c and ipw2200.c */
|
|
||||||
|
|
||||||
#define IPW_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30
|
|
||||||
|
|
||||||
#define IPW_CMD_SET_WPA_PARAM 1
|
|
||||||
#define IPW_CMD_SET_WPA_IE 2
|
|
||||||
#define IPW_CMD_SET_ENCRYPTION 3
|
|
||||||
#define IPW_CMD_MLME 4
|
|
||||||
|
|
||||||
#define IPW_PARAM_WPA_ENABLED 1
|
|
||||||
#define IPW_PARAM_TKIP_COUNTERMEASURES 2
|
|
||||||
#define IPW_PARAM_DROP_UNENCRYPTED 3
|
|
||||||
#define IPW_PARAM_PRIVACY_INVOKED 4
|
|
||||||
#define IPW_PARAM_AUTH_ALGS 5
|
|
||||||
#define IPW_PARAM_IEEE_802_1X 6
|
|
||||||
|
|
||||||
#define IPW_MLME_STA_DEAUTH 1
|
|
||||||
#define IPW_MLME_STA_DISASSOC 2
|
|
||||||
|
|
||||||
#define IPW_CRYPT_ERR_UNKNOWN_ALG 2
|
|
||||||
#define IPW_CRYPT_ERR_UNKNOWN_ADDR 3
|
|
||||||
#define IPW_CRYPT_ERR_CRYPT_INIT_FAILED 4
|
|
||||||
#define IPW_CRYPT_ERR_KEY_SET_FAILED 5
|
|
||||||
#define IPW_CRYPT_ERR_TX_KEY_SET_FAILED 6
|
|
||||||
#define IPW_CRYPT_ERR_CARD_CONF_FAILED 7
|
|
||||||
|
|
||||||
#define IPW_CRYPT_ALG_NAME_LEN 16
|
|
||||||
|
|
||||||
struct ipw_param {
|
|
||||||
u32 cmd;
|
|
||||||
u8 sta_addr[ETH_ALEN];
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
u8 name;
|
|
||||||
u32 value;
|
|
||||||
} wpa_param;
|
|
||||||
struct {
|
|
||||||
u32 len;
|
|
||||||
u8 reserved[32];
|
|
||||||
u8 data[0];
|
|
||||||
} wpa_ie;
|
|
||||||
struct{
|
|
||||||
u32 command;
|
|
||||||
u32 reason_code;
|
|
||||||
} mlme;
|
|
||||||
struct {
|
|
||||||
u8 alg[IPW_CRYPT_ALG_NAME_LEN];
|
|
||||||
u8 set_tx;
|
|
||||||
u32 err;
|
|
||||||
u8 idx;
|
|
||||||
u8 seq[8];
|
|
||||||
u16 key_len;
|
|
||||||
u8 key[0];
|
|
||||||
} crypt;
|
|
||||||
|
|
||||||
} u;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* end of ipw2100.c and ipw2200.c code */
|
|
||||||
|
|
||||||
static int ipw_ioctl(struct wpa_driver_ipw_data *drv,
|
|
||||||
struct ipw_param *param, int len, int show_err)
|
|
||||||
{
|
|
||||||
struct iwreq iwr;
|
|
||||||
|
|
||||||
os_memset(&iwr, 0, sizeof(iwr));
|
|
||||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
iwr.u.data.pointer = (caddr_t) param;
|
|
||||||
iwr.u.data.length = len;
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, IPW_IOCTL_WPA_SUPPLICANT, &iwr) < 0) {
|
|
||||||
int ret = errno;
|
|
||||||
if (show_err)
|
|
||||||
perror("ioctl[IPW_IOCTL_WPA_SUPPLICANT]");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void ipw_show_set_key_error(struct ipw_param *param)
|
|
||||||
{
|
|
||||||
switch (param->u.crypt.err) {
|
|
||||||
case IPW_CRYPT_ERR_UNKNOWN_ALG:
|
|
||||||
wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
|
|
||||||
param->u.crypt.alg);
|
|
||||||
wpa_printf(MSG_INFO, "You may need to load kernel module to "
|
|
||||||
"register that algorithm.");
|
|
||||||
wpa_printf(MSG_INFO, "E.g., 'modprobe ieee80211_crypt_wep' for"
|
|
||||||
" WEP.");
|
|
||||||
break;
|
|
||||||
case IPW_CRYPT_ERR_UNKNOWN_ADDR:
|
|
||||||
wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
|
|
||||||
MAC2STR(param->sta_addr));
|
|
||||||
break;
|
|
||||||
case IPW_CRYPT_ERR_CRYPT_INIT_FAILED:
|
|
||||||
wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
|
|
||||||
break;
|
|
||||||
case IPW_CRYPT_ERR_KEY_SET_FAILED:
|
|
||||||
wpa_printf(MSG_INFO, "Key setting failed.");
|
|
||||||
break;
|
|
||||||
case IPW_CRYPT_ERR_TX_KEY_SET_FAILED:
|
|
||||||
wpa_printf(MSG_INFO, "TX key index setting failed.");
|
|
||||||
break;
|
|
||||||
case IPW_CRYPT_ERR_CARD_CONF_FAILED:
|
|
||||||
wpa_printf(MSG_INFO, "Card configuration failed.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ipw_set_wpa_ie(struct wpa_driver_ipw_data *drv,
|
|
||||||
const u8 *wpa_ie, size_t wpa_ie_len)
|
|
||||||
{
|
|
||||||
struct ipw_param *param;
|
|
||||||
int ret;
|
|
||||||
size_t blen = sizeof(*param) + wpa_ie_len;
|
|
||||||
|
|
||||||
param = os_zalloc(blen);
|
|
||||||
if (param == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
param->cmd = IPW_CMD_SET_WPA_IE;
|
|
||||||
param->u.wpa_ie.len = wpa_ie_len;
|
|
||||||
os_memcpy(param->u.wpa_ie.data, wpa_ie, wpa_ie_len);
|
|
||||||
|
|
||||||
ret = ipw_ioctl(drv, param, blen, 1);
|
|
||||||
|
|
||||||
os_free(param);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ipw_set_wpa_param(struct wpa_driver_ipw_data *drv, u8 name,
|
|
||||||
u32 value)
|
|
||||||
{
|
|
||||||
struct ipw_param param;
|
|
||||||
|
|
||||||
os_memset(¶m, 0, sizeof(param));
|
|
||||||
param.cmd = IPW_CMD_SET_WPA_PARAM;
|
|
||||||
param.u.wpa_param.name = name;
|
|
||||||
param.u.wpa_param.value = value;
|
|
||||||
|
|
||||||
return ipw_ioctl(drv, ¶m, sizeof(param), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ipw_mlme(struct wpa_driver_ipw_data *drv, const u8 *addr,
|
|
||||||
int cmd, int reason)
|
|
||||||
{
|
|
||||||
struct ipw_param param;
|
|
||||||
|
|
||||||
os_memset(¶m, 0, sizeof(param));
|
|
||||||
os_memcpy(param.sta_addr, addr, ETH_ALEN);
|
|
||||||
param.cmd = IPW_CMD_MLME;
|
|
||||||
param.u.mlme.command = cmd;
|
|
||||||
param.u.mlme.reason_code = reason;
|
|
||||||
|
|
||||||
return ipw_ioctl(drv, ¶m, sizeof(param), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_ipw_set_wpa(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
|
||||||
|
|
||||||
if (!enabled && ipw_set_wpa_ie(drv, NULL, 0) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
if (ipw_set_wpa_param(drv, IPW_PARAM_WPA_ENABLED, enabled) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_ipw_set_key(void *priv, wpa_alg alg,
|
|
||||||
const u8 *addr, int key_idx, int set_tx,
|
|
||||||
const u8 *seq, size_t seq_len,
|
|
||||||
const u8 *key, size_t key_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
struct ipw_param *param;
|
|
||||||
u8 *buf;
|
|
||||||
size_t blen;
|
|
||||||
int ret = 0;
|
|
||||||
char *alg_name;
|
|
||||||
|
|
||||||
switch (alg) {
|
|
||||||
case WPA_ALG_NONE:
|
|
||||||
alg_name = "none";
|
|
||||||
break;
|
|
||||||
case WPA_ALG_WEP:
|
|
||||||
alg_name = "WEP";
|
|
||||||
break;
|
|
||||||
case WPA_ALG_TKIP:
|
|
||||||
alg_name = "TKIP";
|
|
||||||
break;
|
|
||||||
case WPA_ALG_CCMP:
|
|
||||||
alg_name = "CCMP";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
|
|
||||||
"key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
|
|
||||||
(unsigned long) seq_len, (unsigned long) key_len);
|
|
||||||
|
|
||||||
if (seq_len > 8)
|
|
||||||
return -2;
|
|
||||||
|
|
||||||
blen = sizeof(*param) + key_len;
|
|
||||||
buf = os_zalloc(blen);
|
|
||||||
if (buf == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
param = (struct ipw_param *) buf;
|
|
||||||
param->cmd = IPW_CMD_SET_ENCRYPTION;
|
|
||||||
os_memset(param->sta_addr, 0xff, ETH_ALEN);
|
|
||||||
os_strlcpy((char *) param->u.crypt.alg, alg_name,
|
|
||||||
IPW_CRYPT_ALG_NAME_LEN);
|
|
||||||
param->u.crypt.set_tx = set_tx ? 1 : 0;
|
|
||||||
param->u.crypt.idx = key_idx;
|
|
||||||
os_memcpy(param->u.crypt.seq, seq, seq_len);
|
|
||||||
param->u.crypt.key_len = key_len;
|
|
||||||
os_memcpy((u8 *) (param + 1), key, key_len);
|
|
||||||
|
|
||||||
if (ipw_ioctl(drv, param, blen, 1)) {
|
|
||||||
wpa_printf(MSG_WARNING, "Failed to set encryption.");
|
|
||||||
ipw_show_set_key_error(param);
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
os_free(buf);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_ipw_set_countermeasures(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
|
||||||
return ipw_set_wpa_param(drv, IPW_PARAM_TKIP_COUNTERMEASURES,
|
|
||||||
enabled);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_ipw_set_drop_unencrypted(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
|
||||||
return ipw_set_wpa_param(drv, IPW_PARAM_DROP_UNENCRYPTED,
|
|
||||||
enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_ipw_deauthenticate(void *priv, const u8 *addr,
|
|
||||||
int reason_code)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
return ipw_mlme(drv, addr, IPW_MLME_STA_DEAUTH, reason_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_ipw_disassociate(void *priv, const u8 *addr,
|
|
||||||
int reason_code)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
return ipw_mlme(drv, addr, IPW_MLME_STA_DISASSOC, reason_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_ipw_associate(void *priv, struct wpa_driver_associate_params *params)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
int ret = 0;
|
|
||||||
int unencrypted_eapol;
|
|
||||||
|
|
||||||
if (ipw_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
|
|
||||||
params->ssid_len) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
|
|
||||||
params->key_mgmt_suite == KEY_MGMT_PSK)
|
|
||||||
unencrypted_eapol = 0;
|
|
||||||
else
|
|
||||||
unencrypted_eapol = 1;
|
|
||||||
|
|
||||||
if (ipw_set_wpa_param(drv, IPW_PARAM_IEEE_802_1X,
|
|
||||||
unencrypted_eapol) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "ipw: Failed to configure "
|
|
||||||
"ieee_802_1x param");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
int algs = 0;
|
|
||||||
|
|
||||||
if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
|
|
||||||
algs |= 1;
|
|
||||||
if (auth_alg & AUTH_ALG_SHARED_KEY)
|
|
||||||
algs |= 2;
|
|
||||||
if (auth_alg & AUTH_ALG_LEAP)
|
|
||||||
algs |= 4;
|
|
||||||
if (algs == 0)
|
|
||||||
algs = 1; /* at least one algorithm should be set */
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: auth_alg=0x%x", __FUNCTION__, algs);
|
|
||||||
return ipw_set_wpa_param(drv, IPW_PARAM_AUTH_ALGS, algs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_ipw_get_bssid(void *priv, u8 *bssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_bssid(drv->wext, bssid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_ipw_get_ssid(void *priv, u8 *ssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_ssid(drv->wext, ssid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_ipw_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct wpa_scan_results * wpa_driver_ipw_get_scan_results(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_scan_results(drv->wext);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_ipw_set_operstate(void *priv, int state)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
return wpa_driver_wext_set_operstate(drv->wext, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void * wpa_driver_ipw_init(void *ctx, const char *ifname)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv;
|
|
||||||
int ver;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s is called", __FUNCTION__);
|
|
||||||
drv = os_zalloc(sizeof(*drv));
|
|
||||||
if (drv == NULL)
|
|
||||||
return NULL;
|
|
||||||
drv->wext = wpa_driver_wext_init(ctx, ifname);
|
|
||||||
if (drv->wext == NULL) {
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ver = wpa_driver_wext_get_version(drv->wext);
|
|
||||||
if (ver >= 18) {
|
|
||||||
wpa_printf(MSG_WARNING, "Linux wireless extensions version %d "
|
|
||||||
"detected.", ver);
|
|
||||||
wpa_printf(MSG_WARNING, "ipw2x00 driver uses driver_wext "
|
|
||||||
"(-Dwext) instead of driver_ipw.");
|
|
||||||
}
|
|
||||||
|
|
||||||
drv->ctx = ctx;
|
|
||||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
|
||||||
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (drv->sock < 0) {
|
|
||||||
wpa_driver_wext_deinit(drv->wext);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_ipw_deinit(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_ipw_data *drv = priv;
|
|
||||||
wpa_driver_wext_deinit(drv->wext);
|
|
||||||
close(drv->sock);
|
|
||||||
os_free(drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const struct wpa_driver_ops wpa_driver_ipw_ops = {
|
|
||||||
.name = "ipw",
|
|
||||||
.desc = "Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 "
|
|
||||||
"or newer)",
|
|
||||||
.get_bssid = wpa_driver_ipw_get_bssid,
|
|
||||||
.get_ssid = wpa_driver_ipw_get_ssid,
|
|
||||||
.set_wpa = wpa_driver_ipw_set_wpa,
|
|
||||||
.set_key = wpa_driver_ipw_set_key,
|
|
||||||
.set_countermeasures = wpa_driver_ipw_set_countermeasures,
|
|
||||||
.set_drop_unencrypted = wpa_driver_ipw_set_drop_unencrypted,
|
|
||||||
.scan = wpa_driver_ipw_scan,
|
|
||||||
.get_scan_results2 = wpa_driver_ipw_get_scan_results,
|
|
||||||
.deauthenticate = wpa_driver_ipw_deauthenticate,
|
|
||||||
.disassociate = wpa_driver_ipw_disassociate,
|
|
||||||
.associate = wpa_driver_ipw_associate,
|
|
||||||
.set_auth_alg = wpa_driver_ipw_set_auth_alg,
|
|
||||||
.init = wpa_driver_ipw_init,
|
|
||||||
.deinit = wpa_driver_ipw_deinit,
|
|
||||||
.set_operstate = wpa_driver_ipw_set_operstate,
|
|
||||||
};
|
|
@ -1,601 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - driver interaction with MADWIFI 802.11 driver
|
|
||||||
* Copyright (c) 2004, Sam Leffler <sam@errno.com>
|
|
||||||
* Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*
|
|
||||||
* Please note that madwifi supports WPA configuration via Linux wireless
|
|
||||||
* extensions and if the kernel includes support for this, driver_wext.c should
|
|
||||||
* be used instead of this driver wrapper.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "driver.h"
|
|
||||||
#include "driver_wext.h"
|
|
||||||
#include "eloop.h"
|
|
||||||
#include "ieee802_11_defs.h"
|
|
||||||
#include "wireless_copy.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Avoid conflicts with wpa_supplicant definitions by undefining a definition.
|
|
||||||
*/
|
|
||||||
#undef WME_OUI_TYPE
|
|
||||||
|
|
||||||
#include <include/compat.h>
|
|
||||||
#include <net80211/ieee80211.h>
|
|
||||||
#ifdef WME_NUM_AC
|
|
||||||
/* Assume this is built against BSD branch of madwifi driver. */
|
|
||||||
#define MADWIFI_BSD
|
|
||||||
#include <net80211/_ieee80211.h>
|
|
||||||
#endif /* WME_NUM_AC */
|
|
||||||
#include <net80211/ieee80211_crypto.h>
|
|
||||||
#include <net80211/ieee80211_ioctl.h>
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef IEEE80211_IOCTL_SETWMMPARAMS
|
|
||||||
/* Assume this is built against madwifi-ng */
|
|
||||||
#define MADWIFI_NG
|
|
||||||
#endif /* IEEE80211_IOCTL_SETWMMPARAMS */
|
|
||||||
|
|
||||||
struct wpa_driver_madwifi_data {
|
|
||||||
void *wext; /* private data for driver_wext */
|
|
||||||
void *ctx;
|
|
||||||
char ifname[IFNAMSIZ + 1];
|
|
||||||
int sock;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
|
|
||||||
int show_err)
|
|
||||||
{
|
|
||||||
struct iwreq iwr;
|
|
||||||
|
|
||||||
os_memset(&iwr, 0, sizeof(iwr));
|
|
||||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
if (len < IFNAMSIZ &&
|
|
||||||
op != IEEE80211_IOCTL_SET_APPIEBUF) {
|
|
||||||
/*
|
|
||||||
* Argument data fits inline; put it there.
|
|
||||||
*/
|
|
||||||
os_memcpy(iwr.u.name, data, len);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Argument data too big for inline transfer; setup a
|
|
||||||
* parameter block instead; the kernel will transfer
|
|
||||||
* the data for the driver.
|
|
||||||
*/
|
|
||||||
iwr.u.data.pointer = data;
|
|
||||||
iwr.u.data.length = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, op, &iwr) < 0) {
|
|
||||||
if (show_err) {
|
|
||||||
#ifdef MADWIFI_NG
|
|
||||||
int first = IEEE80211_IOCTL_SETPARAM;
|
|
||||||
int last = IEEE80211_IOCTL_KICKMAC;
|
|
||||||
static const char *opnames[] = {
|
|
||||||
"ioctl[IEEE80211_IOCTL_SETPARAM]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_GETPARAM]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_SETMODE]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_GETMODE]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_SETCHANLIST]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_GETCHANLIST]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_CHANSWITCH]",
|
|
||||||
NULL,
|
|
||||||
"ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
|
|
||||||
NULL,
|
|
||||||
"ioctl[IEEE80211_IOCTL_GETCHANINFO]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_SETOPTIE]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_GETOPTIE]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_SETMLME]",
|
|
||||||
NULL,
|
|
||||||
"ioctl[IEEE80211_IOCTL_SETKEY]",
|
|
||||||
NULL,
|
|
||||||
"ioctl[IEEE80211_IOCTL_DELKEY]",
|
|
||||||
NULL,
|
|
||||||
"ioctl[IEEE80211_IOCTL_ADDMAC]",
|
|
||||||
NULL,
|
|
||||||
"ioctl[IEEE80211_IOCTL_DELMAC]",
|
|
||||||
NULL,
|
|
||||||
"ioctl[IEEE80211_IOCTL_WDSMAC]",
|
|
||||||
NULL,
|
|
||||||
"ioctl[IEEE80211_IOCTL_WDSDELMAC]",
|
|
||||||
NULL,
|
|
||||||
"ioctl[IEEE80211_IOCTL_KICKMAC]",
|
|
||||||
};
|
|
||||||
#else /* MADWIFI_NG */
|
|
||||||
int first = IEEE80211_IOCTL_SETPARAM;
|
|
||||||
int last = IEEE80211_IOCTL_CHANLIST;
|
|
||||||
static const char *opnames[] = {
|
|
||||||
"ioctl[IEEE80211_IOCTL_SETPARAM]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_GETPARAM]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_SETKEY]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_GETKEY]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_DELKEY]",
|
|
||||||
NULL,
|
|
||||||
"ioctl[IEEE80211_IOCTL_SETMLME]",
|
|
||||||
NULL,
|
|
||||||
"ioctl[IEEE80211_IOCTL_SETOPTIE]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_GETOPTIE]",
|
|
||||||
"ioctl[IEEE80211_IOCTL_ADDMAC]",
|
|
||||||
NULL,
|
|
||||||
"ioctl[IEEE80211_IOCTL_DELMAC]",
|
|
||||||
NULL,
|
|
||||||
"ioctl[IEEE80211_IOCTL_CHANLIST]",
|
|
||||||
};
|
|
||||||
#endif /* MADWIFI_NG */
|
|
||||||
int idx = op - first;
|
|
||||||
if (first <= op && op <= last &&
|
|
||||||
idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
|
|
||||||
&& opnames[idx])
|
|
||||||
perror(opnames[idx]);
|
|
||||||
else
|
|
||||||
perror("ioctl[unknown???]");
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
|
|
||||||
int show_err)
|
|
||||||
{
|
|
||||||
struct iwreq iwr;
|
|
||||||
|
|
||||||
os_memset(&iwr, 0, sizeof(iwr));
|
|
||||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
iwr.u.mode = op;
|
|
||||||
os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg));
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
|
|
||||||
if (show_err)
|
|
||||||
perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
|
|
||||||
const u8 *wpa_ie, size_t wpa_ie_len)
|
|
||||||
{
|
|
||||||
struct iwreq iwr;
|
|
||||||
|
|
||||||
os_memset(&iwr, 0, sizeof(iwr));
|
|
||||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
/* NB: SETOPTIE is not fixed-size so must not be inlined */
|
|
||||||
iwr.u.data.pointer = (void *) wpa_ie;
|
|
||||||
iwr.u.data.length = wpa_ie_len;
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
|
|
||||||
perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
|
|
||||||
const u8 *addr)
|
|
||||||
{
|
|
||||||
struct ieee80211req_del_key wk;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
|
|
||||||
os_memset(&wk, 0, sizeof(wk));
|
|
||||||
wk.idk_keyix = key_idx;
|
|
||||||
if (addr != NULL)
|
|
||||||
os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
|
|
||||||
|
|
||||||
return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_madwifi_set_key(void *priv, wpa_alg alg,
|
|
||||||
const u8 *addr, int key_idx, int set_tx,
|
|
||||||
const u8 *seq, size_t seq_len,
|
|
||||||
const u8 *key, size_t key_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv = priv;
|
|
||||||
struct ieee80211req_key wk;
|
|
||||||
char *alg_name;
|
|
||||||
u_int8_t cipher;
|
|
||||||
|
|
||||||
if (alg == WPA_ALG_NONE)
|
|
||||||
return wpa_driver_madwifi_del_key(drv, key_idx, addr);
|
|
||||||
|
|
||||||
switch (alg) {
|
|
||||||
case WPA_ALG_WEP:
|
|
||||||
if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
|
|
||||||
ETH_ALEN) == 0) {
|
|
||||||
/*
|
|
||||||
* madwifi did not seem to like static WEP key
|
|
||||||
* configuration with IEEE80211_IOCTL_SETKEY, so use
|
|
||||||
* Linux wireless extensions ioctl for this.
|
|
||||||
*/
|
|
||||||
return wpa_driver_wext_set_key(drv->wext, alg, addr,
|
|
||||||
key_idx, set_tx,
|
|
||||||
seq, seq_len,
|
|
||||||
key, key_len);
|
|
||||||
}
|
|
||||||
alg_name = "WEP";
|
|
||||||
cipher = IEEE80211_CIPHER_WEP;
|
|
||||||
break;
|
|
||||||
case WPA_ALG_TKIP:
|
|
||||||
alg_name = "TKIP";
|
|
||||||
cipher = IEEE80211_CIPHER_TKIP;
|
|
||||||
break;
|
|
||||||
case WPA_ALG_CCMP:
|
|
||||||
alg_name = "CCMP";
|
|
||||||
cipher = IEEE80211_CIPHER_AES_CCM;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
|
|
||||||
__FUNCTION__, alg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
|
|
||||||
"key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
|
|
||||||
(unsigned long) seq_len, (unsigned long) key_len);
|
|
||||||
|
|
||||||
if (seq_len > sizeof(u_int64_t)) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big",
|
|
||||||
__FUNCTION__, (unsigned long) seq_len);
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
if (key_len > sizeof(wk.ik_keydata)) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: key length %lu too big",
|
|
||||||
__FUNCTION__, (unsigned long) key_len);
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_memset(&wk, 0, sizeof(wk));
|
|
||||||
wk.ik_type = cipher;
|
|
||||||
wk.ik_flags = IEEE80211_KEY_RECV;
|
|
||||||
if (addr == NULL ||
|
|
||||||
os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
|
|
||||||
wk.ik_flags |= IEEE80211_KEY_GROUP;
|
|
||||||
if (set_tx) {
|
|
||||||
wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
|
|
||||||
os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
|
|
||||||
} else
|
|
||||||
os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
|
|
||||||
wk.ik_keyix = key_idx;
|
|
||||||
wk.ik_keylen = key_len;
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
|
||||||
#define WPA_KEY_RSC_LEN 8
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
u8 tmp[WPA_KEY_RSC_LEN];
|
|
||||||
os_memset(tmp, 0, sizeof(tmp));
|
|
||||||
for (i = 0; i < seq_len; i++)
|
|
||||||
tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i];
|
|
||||||
os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN);
|
|
||||||
}
|
|
||||||
#else /* WORDS_BIGENDIAN */
|
|
||||||
os_memcpy(&wk.ik_keyrsc, seq, seq_len);
|
|
||||||
#endif /* WORDS_BIGENDIAN */
|
|
||||||
os_memcpy(wk.ik_keydata, key, key_len);
|
|
||||||
|
|
||||||
return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
|
||||||
return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_madwifi_set_drop_unencrypted(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
|
||||||
return set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED, enabled, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv = priv;
|
|
||||||
struct ieee80211req_mlme mlme;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
|
||||||
mlme.im_op = IEEE80211_MLME_DEAUTH;
|
|
||||||
mlme.im_reason = reason_code;
|
|
||||||
os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
|
|
||||||
return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv = priv;
|
|
||||||
struct ieee80211req_mlme mlme;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
|
||||||
mlme.im_op = IEEE80211_MLME_DISASSOC;
|
|
||||||
mlme.im_reason = reason_code;
|
|
||||||
os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
|
|
||||||
return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_madwifi_associate(void *priv,
|
|
||||||
struct wpa_driver_associate_params *params)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv = priv;
|
|
||||||
struct ieee80211req_mlme mlme;
|
|
||||||
int ret = 0, privacy = 1;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NB: Don't need to set the freq or cipher-related state as
|
|
||||||
* this is implied by the bssid which is used to locate
|
|
||||||
* the scanned node state which holds it. The ssid is
|
|
||||||
* needed to disambiguate an AP that broadcasts multiple
|
|
||||||
* ssid's but uses the same bssid.
|
|
||||||
*/
|
|
||||||
/* XXX error handling is wrong but unclear what to do... */
|
|
||||||
if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie,
|
|
||||||
params->wpa_ie_len) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
if (params->pairwise_suite == CIPHER_NONE &&
|
|
||||||
params->group_suite == CIPHER_NONE &&
|
|
||||||
params->key_mgmt_suite == KEY_MGMT_NONE &&
|
|
||||||
params->wpa_ie_len == 0)
|
|
||||||
privacy = 0;
|
|
||||||
|
|
||||||
if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
if (params->wpa_ie_len &&
|
|
||||||
set80211param(drv, IEEE80211_PARAM_WPA,
|
|
||||||
params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
if (params->bssid == NULL) {
|
|
||||||
/* ap_scan=2 mode - driver takes care of AP selection and
|
|
||||||
* roaming */
|
|
||||||
/* FIX: this does not seem to work; would probably need to
|
|
||||||
* change something in the driver */
|
|
||||||
if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
|
|
||||||
params->ssid_len) < 0)
|
|
||||||
ret = -1;
|
|
||||||
} else {
|
|
||||||
if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
|
|
||||||
params->ssid_len) < 0)
|
|
||||||
ret = -1;
|
|
||||||
os_memset(&mlme, 0, sizeof(mlme));
|
|
||||||
mlme.im_op = IEEE80211_MLME_ASSOC;
|
|
||||||
os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
|
|
||||||
if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
|
|
||||||
sizeof(mlme), 1) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed",
|
|
||||||
__func__);
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv = priv;
|
|
||||||
int authmode;
|
|
||||||
|
|
||||||
if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
|
|
||||||
(auth_alg & AUTH_ALG_SHARED_KEY))
|
|
||||||
authmode = IEEE80211_AUTH_AUTO;
|
|
||||||
else if (auth_alg & AUTH_ALG_SHARED_KEY)
|
|
||||||
authmode = IEEE80211_AUTH_SHARED;
|
|
||||||
else
|
|
||||||
authmode = IEEE80211_AUTH_OPEN;
|
|
||||||
|
|
||||||
return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_madwifi_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv = priv;
|
|
||||||
struct iwreq iwr;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
os_memset(&iwr, 0, sizeof(iwr));
|
|
||||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
|
|
||||||
/* set desired ssid before scan */
|
|
||||||
/* FIX: scan should not break the current association, so using
|
|
||||||
* set_ssid may not be the best way of doing this.. */
|
|
||||||
if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
|
|
||||||
perror("ioctl[SIOCSIWSCAN]");
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* madwifi delivers a scan complete event so no need to poll, but
|
|
||||||
* register a backup timeout anyway to make sure that we recover even
|
|
||||||
* if the driver does not send this event for any reason. This timeout
|
|
||||||
* will only be used if the event is not delivered (event handler will
|
|
||||||
* cancel the timeout).
|
|
||||||
*/
|
|
||||||
eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
|
|
||||||
drv->ctx);
|
|
||||||
eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
|
|
||||||
drv->ctx);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_bssid(drv->wext, bssid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_ssid(drv->wext, ssid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct wpa_scan_results *
|
|
||||||
wpa_driver_madwifi_get_scan_results(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_scan_results(drv->wext);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_madwifi_set_operstate(void *priv, int state)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv = priv;
|
|
||||||
return wpa_driver_wext_set_operstate(drv->wext, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
|
|
||||||
size_t ies_len)
|
|
||||||
{
|
|
||||||
struct ieee80211req_getset_appiebuf *probe_req_ie;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len);
|
|
||||||
if (probe_req_ie == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ;
|
|
||||||
probe_req_ie->app_buflen = ies_len;
|
|
||||||
os_memcpy(probe_req_ie->app_buf, ies, ies_len);
|
|
||||||
|
|
||||||
ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie,
|
|
||||||
sizeof(struct ieee80211req_getset_appiebuf) +
|
|
||||||
ies_len, 1);
|
|
||||||
|
|
||||||
os_free(probe_req_ie);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv;
|
|
||||||
|
|
||||||
drv = os_zalloc(sizeof(*drv));
|
|
||||||
if (drv == NULL)
|
|
||||||
return NULL;
|
|
||||||
drv->wext = wpa_driver_wext_init(ctx, ifname);
|
|
||||||
if (drv->wext == NULL)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
drv->ctx = ctx;
|
|
||||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
|
||||||
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (drv->sock < 0)
|
|
||||||
goto fail2;
|
|
||||||
|
|
||||||
if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
|
|
||||||
"roaming", __FUNCTION__);
|
|
||||||
goto fail3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
|
|
||||||
__FUNCTION__);
|
|
||||||
goto fail3;
|
|
||||||
}
|
|
||||||
|
|
||||||
return drv;
|
|
||||||
|
|
||||||
fail3:
|
|
||||||
close(drv->sock);
|
|
||||||
fail2:
|
|
||||||
wpa_driver_wext_deinit(drv->wext);
|
|
||||||
fail:
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_madwifi_deinit(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_madwifi_data *drv = priv;
|
|
||||||
|
|
||||||
if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE",
|
|
||||||
__FUNCTION__);
|
|
||||||
}
|
|
||||||
if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based "
|
|
||||||
"roaming", __FUNCTION__);
|
|
||||||
}
|
|
||||||
if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy "
|
|
||||||
"flag", __FUNCTION__);
|
|
||||||
}
|
|
||||||
if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: failed to disable WPA",
|
|
||||||
__FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_driver_wext_deinit(drv->wext);
|
|
||||||
|
|
||||||
close(drv->sock);
|
|
||||||
os_free(drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const struct wpa_driver_ops wpa_driver_madwifi_ops = {
|
|
||||||
.name = "madwifi",
|
|
||||||
.desc = "MADWIFI 802.11 support (Atheros, etc.)",
|
|
||||||
.get_bssid = wpa_driver_madwifi_get_bssid,
|
|
||||||
.get_ssid = wpa_driver_madwifi_get_ssid,
|
|
||||||
.set_key = wpa_driver_madwifi_set_key,
|
|
||||||
.init = wpa_driver_madwifi_init,
|
|
||||||
.deinit = wpa_driver_madwifi_deinit,
|
|
||||||
.set_countermeasures = wpa_driver_madwifi_set_countermeasures,
|
|
||||||
.set_drop_unencrypted = wpa_driver_madwifi_set_drop_unencrypted,
|
|
||||||
.scan = wpa_driver_madwifi_scan,
|
|
||||||
.get_scan_results2 = wpa_driver_madwifi_get_scan_results,
|
|
||||||
.deauthenticate = wpa_driver_madwifi_deauthenticate,
|
|
||||||
.disassociate = wpa_driver_madwifi_disassociate,
|
|
||||||
.associate = wpa_driver_madwifi_associate,
|
|
||||||
.set_auth_alg = wpa_driver_madwifi_set_auth_alg,
|
|
||||||
.set_operstate = wpa_driver_madwifi_set_operstate,
|
|
||||||
.set_probe_req_ie = wpa_driver_madwifi_set_probe_req_ie,
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load Diff
@ -1,432 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - Mac OS X Apple80211 driver interface
|
|
||||||
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#define Boolean __DummyBoolean
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
|
||||||
#undef Boolean
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "driver.h"
|
|
||||||
#include "eloop.h"
|
|
||||||
|
|
||||||
#include "Apple80211.h"
|
|
||||||
|
|
||||||
struct wpa_driver_osx_data {
|
|
||||||
void *ctx;
|
|
||||||
WirelessRef wireless_ctx;
|
|
||||||
CFArrayRef scan_results;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CONFIG_NO_STDOUT_DEBUG
|
|
||||||
extern int wpa_debug_level;
|
|
||||||
|
|
||||||
static void dump_dict_cb(const void *key, const void *value, void *context)
|
|
||||||
{
|
|
||||||
if (MSG_DEBUG < wpa_debug_level)
|
|
||||||
return;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "Key:");
|
|
||||||
CFShow(key);
|
|
||||||
wpa_printf(MSG_DEBUG, "Value:");
|
|
||||||
CFShow(value);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title)
|
|
||||||
{
|
|
||||||
#ifndef CONFIG_NO_STDOUT_DEBUG
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries",
|
|
||||||
title, (unsigned int) CFDictionaryGetCount(dict));
|
|
||||||
CFDictionaryApplyFunction(dict, dump_dict_cb, NULL);
|
|
||||||
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_osx_data *drv = priv;
|
|
||||||
WirelessError err;
|
|
||||||
WirelessInfo info;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
err = WirelessGetInfo(drv->wireless_ctx, &info);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
|
|
||||||
(int) err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!info.power) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (len = 0; len < 32; len++)
|
|
||||||
if (info.ssid[len] == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
os_memcpy(ssid, info.ssid, len);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_osx_data *drv = priv;
|
|
||||||
WirelessError err;
|
|
||||||
WirelessInfo info;
|
|
||||||
|
|
||||||
err = WirelessGetInfo(drv->wireless_ctx, &info);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
|
|
||||||
(int) err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!info.power) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_memcpy(bssid, info.bssID, ETH_ALEN);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
|
|
||||||
{
|
|
||||||
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_osx_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_osx_data *drv = priv;
|
|
||||||
WirelessError err;
|
|
||||||
|
|
||||||
if (drv->scan_results) {
|
|
||||||
CFRelease(drv->scan_results);
|
|
||||||
drv->scan_results = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ssid) {
|
|
||||||
CFStringRef data;
|
|
||||||
data = CFStringCreateWithBytes(kCFAllocatorDefault,
|
|
||||||
ssid, ssid_len,
|
|
||||||
kCFStringEncodingISOLatin1,
|
|
||||||
FALSE);
|
|
||||||
if (data == NULL) {
|
|
||||||
wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes "
|
|
||||||
"failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = WirelessDirectedScan(drv->wireless_ctx,
|
|
||||||
&drv->scan_results, 0, data);
|
|
||||||
CFRelease(data);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan "
|
|
||||||
"failed: 0x%08x", (unsigned int) err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: "
|
|
||||||
"0x%08x", (unsigned int) err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv,
|
|
||||||
drv->ctx);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_osx_get_scan_results(void *priv,
|
|
||||||
struct wpa_scan_result *results,
|
|
||||||
size_t max_size)
|
|
||||||
{
|
|
||||||
struct wpa_driver_osx_data *drv = priv;
|
|
||||||
size_t i, num;
|
|
||||||
|
|
||||||
if (drv->scan_results == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
num = CFArrayGetCount(drv->scan_results);
|
|
||||||
if (num > max_size)
|
|
||||||
num = max_size;
|
|
||||||
os_memset(results, 0, num * sizeof(struct wpa_scan_result));
|
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
struct wpa_scan_result *res = &results[i];
|
|
||||||
WirelessNetworkInfo *info;
|
|
||||||
info = (WirelessNetworkInfo *)
|
|
||||||
CFDataGetBytePtr(CFArrayGetValueAtIndex(
|
|
||||||
drv->scan_results, i));
|
|
||||||
|
|
||||||
os_memcpy(res->bssid, info->bssid, ETH_ALEN);
|
|
||||||
if (info->ssid_len > 32) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: Invalid SSID length %d in "
|
|
||||||
"scan results", (int) info->ssid_len);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
os_memcpy(res->ssid, info->ssid, info->ssid_len);
|
|
||||||
res->ssid_len = info->ssid_len;
|
|
||||||
res->caps = info->capability;
|
|
||||||
res->freq = 2407 + info->channel * 5;
|
|
||||||
res->level = info->signal;
|
|
||||||
res->noise = info->noise;
|
|
||||||
}
|
|
||||||
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
|
|
||||||
{
|
|
||||||
struct wpa_driver_osx_data *drv = eloop_ctx;
|
|
||||||
u8 bssid[ETH_ALEN];
|
|
||||||
CFDictionaryRef ai;
|
|
||||||
|
|
||||||
if (wpa_driver_osx_get_bssid(drv, bssid) != 0) {
|
|
||||||
eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout,
|
|
||||||
drv, drv->ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ai = WirelessGetAssociationInfo(drv->wireless_ctx);
|
|
||||||
if (ai) {
|
|
||||||
wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo");
|
|
||||||
CFRelease(ai);
|
|
||||||
} else {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: Failed to get association info");
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_osx_associate(void *priv,
|
|
||||||
struct wpa_driver_associate_params *params)
|
|
||||||
{
|
|
||||||
struct wpa_driver_osx_data *drv = priv;
|
|
||||||
WirelessError err;
|
|
||||||
CFDataRef ssid;
|
|
||||||
CFStringRef key;
|
|
||||||
int assoc_type;
|
|
||||||
|
|
||||||
ssid = CFDataCreate(kCFAllocatorDefault, params->ssid,
|
|
||||||
params->ssid_len);
|
|
||||||
if (ssid == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* TODO: support for WEP */
|
|
||||||
if (params->key_mgmt_suite == KEY_MGMT_PSK) {
|
|
||||||
if (params->passphrase == NULL)
|
|
||||||
return -1;
|
|
||||||
key = CFStringCreateWithCString(kCFAllocatorDefault,
|
|
||||||
params->passphrase,
|
|
||||||
kCFStringEncodingISOLatin1);
|
|
||||||
if (key == NULL) {
|
|
||||||
CFRelease(ssid);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
key = NULL;
|
|
||||||
|
|
||||||
if (params->key_mgmt_suite == KEY_MGMT_NONE)
|
|
||||||
assoc_type = 0;
|
|
||||||
else
|
|
||||||
assoc_type = 4;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)",
|
|
||||||
assoc_type, key);
|
|
||||||
err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key);
|
|
||||||
CFRelease(ssid);
|
|
||||||
if (key)
|
|
||||||
CFRelease(key);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x",
|
|
||||||
(unsigned int) err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Driver is actually already associated; report association from an
|
|
||||||
* eloop callback.
|
|
||||||
*/
|
|
||||||
eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
|
|
||||||
eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv,
|
|
||||||
drv->ctx);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_osx_set_key(void *priv, wpa_alg alg, const u8 *addr,
|
|
||||||
int key_idx, int set_tx, const u8 *seq,
|
|
||||||
size_t seq_len, const u8 *key,
|
|
||||||
size_t key_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_osx_data *drv = priv;
|
|
||||||
WirelessError err;
|
|
||||||
|
|
||||||
if (alg == WPA_ALG_WEP) {
|
|
||||||
err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len,
|
|
||||||
key);
|
|
||||||
if (err != 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: "
|
|
||||||
"0x%08x", (unsigned int) err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alg == WPA_ALG_PMK) {
|
|
||||||
err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key);
|
|
||||||
if (err != 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: "
|
|
||||||
"0x%08x", (unsigned int) err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa)
|
|
||||||
{
|
|
||||||
os_memset(capa, 0, sizeof(*capa));
|
|
||||||
|
|
||||||
capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
|
|
||||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
|
|
||||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
|
|
||||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
|
|
||||||
capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
|
|
||||||
WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
|
|
||||||
capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
|
|
||||||
WPA_DRIVER_AUTH_LEAP;
|
|
||||||
capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void * wpa_driver_osx_init(void *ctx, const char *ifname)
|
|
||||||
{
|
|
||||||
struct wpa_driver_osx_data *drv;
|
|
||||||
WirelessError err;
|
|
||||||
u8 enabled, power;
|
|
||||||
|
|
||||||
if (!WirelessIsAvailable()) {
|
|
||||||
wpa_printf(MSG_ERROR, "OSX: No wireless interface available");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
drv = os_zalloc(sizeof(*drv));
|
|
||||||
if (drv == NULL)
|
|
||||||
return NULL;
|
|
||||||
drv->ctx = ctx;
|
|
||||||
err = WirelessAttach(&drv->wireless_ctx, 0);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d",
|
|
||||||
(int) err);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = WirelessGetEnabled(drv->wireless_ctx, &enabled);
|
|
||||||
if (err)
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x",
|
|
||||||
(unsigned int) err);
|
|
||||||
err = WirelessGetPower(drv->wireless_ctx, &power);
|
|
||||||
if (err)
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x",
|
|
||||||
(unsigned int) err);
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power);
|
|
||||||
|
|
||||||
if (!enabled) {
|
|
||||||
err = WirelessSetEnabled(drv->wireless_ctx, 1);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:"
|
|
||||||
" 0x%08x", (unsigned int) err);
|
|
||||||
WirelessDetach(drv->wireless_ctx);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!power) {
|
|
||||||
err = WirelessSetPower(drv->wireless_ctx, 1);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: "
|
|
||||||
"0x%08x", (unsigned int) err);
|
|
||||||
WirelessDetach(drv->wireless_ctx);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_osx_deinit(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_osx_data *drv = priv;
|
|
||||||
WirelessError err;
|
|
||||||
|
|
||||||
eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx);
|
|
||||||
eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
|
|
||||||
|
|
||||||
err = WirelessSetPower(drv->wireless_ctx, 0);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: "
|
|
||||||
"0x%08x", (unsigned int) err);
|
|
||||||
}
|
|
||||||
|
|
||||||
err = WirelessDetach(drv->wireless_ctx);
|
|
||||||
if (err) {
|
|
||||||
wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x",
|
|
||||||
(unsigned int) err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drv->scan_results)
|
|
||||||
CFRelease(drv->scan_results);
|
|
||||||
|
|
||||||
os_free(drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const struct wpa_driver_ops wpa_driver_osx_ops = {
|
|
||||||
.name = "osx",
|
|
||||||
.desc = "Mac OS X Apple80211 driver",
|
|
||||||
.get_ssid = wpa_driver_osx_get_ssid,
|
|
||||||
.get_bssid = wpa_driver_osx_get_bssid,
|
|
||||||
.init = wpa_driver_osx_init,
|
|
||||||
.deinit = wpa_driver_osx_deinit,
|
|
||||||
.scan = wpa_driver_osx_scan,
|
|
||||||
.get_scan_results = wpa_driver_osx_get_scan_results,
|
|
||||||
.associate = wpa_driver_osx_associate,
|
|
||||||
.set_key = wpa_driver_osx_set_key,
|
|
||||||
.get_capa = wpa_driver_osx_get_capa,
|
|
||||||
};
|
|
@ -1,381 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - driver interaction with Linux Prism54.org driver
|
|
||||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
|
||||||
* Copyright (c) 2004, Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
#include "wireless_copy.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include "driver.h"
|
|
||||||
#include "driver_wext.h"
|
|
||||||
#include "driver_hostap.h"
|
|
||||||
|
|
||||||
struct wpa_driver_prism54_data {
|
|
||||||
void *wext; /* private data for driver_wext */
|
|
||||||
void *ctx;
|
|
||||||
char ifname[IFNAMSIZ + 1];
|
|
||||||
int sock;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12
|
|
||||||
#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25
|
|
||||||
#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26
|
|
||||||
|
|
||||||
static void show_set_key_error(struct prism2_hostapd_param *);
|
|
||||||
|
|
||||||
static int hostapd_ioctl_prism54(struct wpa_driver_prism54_data *drv,
|
|
||||||
struct prism2_hostapd_param *param,
|
|
||||||
int len, int show_err)
|
|
||||||
{
|
|
||||||
struct iwreq iwr;
|
|
||||||
|
|
||||||
os_memset(&iwr, 0, sizeof(iwr));
|
|
||||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
iwr.u.data.pointer = (caddr_t) param;
|
|
||||||
iwr.u.data.length = len;
|
|
||||||
|
|
||||||
if (ioctl(drv->sock, PRISM54_HOSTAPD, &iwr) < 0) {
|
|
||||||
int ret = errno;
|
|
||||||
if (show_err)
|
|
||||||
perror("ioctl[PRISM54_HOSTAPD]");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_prism54_set_wpa_ie(struct wpa_driver_prism54_data *drv,
|
|
||||||
const u8 *wpa_ie,
|
|
||||||
size_t wpa_ie_len)
|
|
||||||
{
|
|
||||||
struct prism2_hostapd_param *param;
|
|
||||||
int res;
|
|
||||||
size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
|
|
||||||
if (blen < sizeof(*param))
|
|
||||||
blen = sizeof(*param);
|
|
||||||
|
|
||||||
param = os_zalloc(blen);
|
|
||||||
if (param == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
|
|
||||||
param->u.generic_elem.len = wpa_ie_len;
|
|
||||||
os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
|
|
||||||
res = hostapd_ioctl_prism54(drv, param, blen, 1);
|
|
||||||
|
|
||||||
os_free(param);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* This is called at wpa_supplicant daemon init time */
|
|
||||||
static int wpa_driver_prism54_set_wpa(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_prism54_data *drv = priv;
|
|
||||||
struct prism2_hostapd_param *param;
|
|
||||||
int res;
|
|
||||||
size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
|
|
||||||
if (blen < sizeof(*param))
|
|
||||||
blen = sizeof(*param);
|
|
||||||
|
|
||||||
param = os_zalloc(blen);
|
|
||||||
if (param == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
param->cmd = PRISM54_SET_WPA;
|
|
||||||
param->u.generic_elem.len = 0;
|
|
||||||
res = hostapd_ioctl_prism54(drv, param, blen, 1);
|
|
||||||
|
|
||||||
os_free(param);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_prism54_set_key(void *priv, wpa_alg alg,
|
|
||||||
const u8 *addr, int key_idx, int set_tx,
|
|
||||||
const u8 *seq, size_t seq_len,
|
|
||||||
const u8 *key, size_t key_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_prism54_data *drv = priv;
|
|
||||||
struct prism2_hostapd_param *param;
|
|
||||||
u8 *buf;
|
|
||||||
size_t blen;
|
|
||||||
int ret = 0;
|
|
||||||
char *alg_name;
|
|
||||||
|
|
||||||
switch (alg) {
|
|
||||||
case WPA_ALG_NONE:
|
|
||||||
alg_name = "none";
|
|
||||||
return -1;
|
|
||||||
break;
|
|
||||||
case WPA_ALG_WEP:
|
|
||||||
alg_name = "WEP";
|
|
||||||
return -1;
|
|
||||||
break;
|
|
||||||
case WPA_ALG_TKIP:
|
|
||||||
alg_name = "TKIP";
|
|
||||||
break;
|
|
||||||
case WPA_ALG_CCMP:
|
|
||||||
alg_name = "CCMP";
|
|
||||||
return -1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
|
|
||||||
"key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
|
|
||||||
(unsigned long) seq_len, (unsigned long) key_len);
|
|
||||||
|
|
||||||
if (seq_len > 8)
|
|
||||||
return -2;
|
|
||||||
|
|
||||||
blen = sizeof(*param) + key_len;
|
|
||||||
buf = os_zalloc(blen);
|
|
||||||
if (buf == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
param = (struct prism2_hostapd_param *) buf;
|
|
||||||
param->cmd = PRISM2_SET_ENCRYPTION;
|
|
||||||
/* TODO: In theory, STA in client mode can use five keys; four default
|
|
||||||
* keys for receiving (with keyidx 0..3) and one individual key for
|
|
||||||
* both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
|
|
||||||
* keyidx 0 is reserved for this unicast use and default keys can only
|
|
||||||
* use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
|
|
||||||
* This should be fine for more or less all cases, but for completeness
|
|
||||||
* sake, the driver could be enhanced to support the missing key. */
|
|
||||||
#if 0
|
|
||||||
if (addr == NULL)
|
|
||||||
os_memset(param->sta_addr, 0xff, ETH_ALEN);
|
|
||||||
else
|
|
||||||
os_memcpy(param->sta_addr, addr, ETH_ALEN);
|
|
||||||
#else
|
|
||||||
os_memset(param->sta_addr, 0xff, ETH_ALEN);
|
|
||||||
#endif
|
|
||||||
os_strlcpy((char *) param->u.crypt.alg, alg_name,
|
|
||||||
HOSTAP_CRYPT_ALG_NAME_LEN);
|
|
||||||
param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
|
|
||||||
param->u.crypt.idx = key_idx;
|
|
||||||
os_memcpy(param->u.crypt.seq, seq, seq_len);
|
|
||||||
param->u.crypt.key_len = key_len;
|
|
||||||
os_memcpy((u8 *) (param + 1), key, key_len);
|
|
||||||
|
|
||||||
if (hostapd_ioctl_prism54(drv, param, blen, 1)) {
|
|
||||||
wpa_printf(MSG_WARNING, "Failed to set encryption.");
|
|
||||||
show_set_key_error(param);
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
os_free(buf);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_prism54_set_countermeasures(void *priv,
|
|
||||||
int enabled)
|
|
||||||
{
|
|
||||||
/* FIX */
|
|
||||||
printf("wpa_driver_prism54_set_countermeasures - not yet "
|
|
||||||
"implemented\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_prism54_set_drop_unencrypted(void *priv,
|
|
||||||
int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_prism54_data *drv = priv;
|
|
||||||
struct prism2_hostapd_param *param;
|
|
||||||
int res;
|
|
||||||
size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
|
|
||||||
if (blen < sizeof(*param))
|
|
||||||
blen = sizeof(*param);
|
|
||||||
|
|
||||||
param = os_zalloc(blen);
|
|
||||||
if (param == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
param->cmd = PRISM54_DROP_UNENCRYPTED;
|
|
||||||
param->u.generic_elem.len = 0;
|
|
||||||
res = hostapd_ioctl_prism54(drv, param, blen, 1);
|
|
||||||
|
|
||||||
os_free(param);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_prism54_deauthenticate(void *priv, const u8 *addr,
|
|
||||||
int reason_code)
|
|
||||||
{
|
|
||||||
/* FIX */
|
|
||||||
printf("wpa_driver_prism54_deauthenticate - not yet implemented\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_prism54_disassociate(void *priv, const u8 *addr,
|
|
||||||
int reason_code)
|
|
||||||
{
|
|
||||||
/* FIX */
|
|
||||||
printf("wpa_driver_prism54_disassociate - not yet implemented\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
wpa_driver_prism54_associate(void *priv,
|
|
||||||
struct wpa_driver_associate_params *params)
|
|
||||||
{
|
|
||||||
struct wpa_driver_prism54_data *drv = priv;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (wpa_driver_prism54_set_wpa_ie(drv, params->wpa_ie,
|
|
||||||
params->wpa_ie_len) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
|
|
||||||
params->ssid_len) < 0)
|
|
||||||
ret = -1;
|
|
||||||
if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void show_set_key_error(struct prism2_hostapd_param *param)
|
|
||||||
{
|
|
||||||
switch (param->u.crypt.err) {
|
|
||||||
case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
|
|
||||||
wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
|
|
||||||
param->u.crypt.alg);
|
|
||||||
wpa_printf(MSG_INFO, "You may need to load kernel module to "
|
|
||||||
"register that algorithm.");
|
|
||||||
wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
|
|
||||||
"WEP.");
|
|
||||||
break;
|
|
||||||
case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
|
|
||||||
wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
|
|
||||||
MAC2STR(param->sta_addr));
|
|
||||||
break;
|
|
||||||
case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
|
|
||||||
wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
|
|
||||||
break;
|
|
||||||
case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
|
|
||||||
wpa_printf(MSG_INFO, "Key setting failed.");
|
|
||||||
break;
|
|
||||||
case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
|
|
||||||
wpa_printf(MSG_INFO, "TX key index setting failed.");
|
|
||||||
break;
|
|
||||||
case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
|
|
||||||
wpa_printf(MSG_INFO, "Card configuration failed.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_prism54_get_bssid(void *priv, u8 *bssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_prism54_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_bssid(drv->wext, bssid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_prism54_get_ssid(void *priv, u8 *ssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_prism54_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_ssid(drv->wext, ssid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_prism54_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_prism54_data *drv = priv;
|
|
||||||
return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct wpa_scan_results *
|
|
||||||
wpa_driver_prism54_get_scan_results(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_prism54_data *drv = priv;
|
|
||||||
return wpa_driver_wext_get_scan_results(drv->wext);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_prism54_set_operstate(void *priv, int state)
|
|
||||||
{
|
|
||||||
struct wpa_driver_prism54_data *drv = priv;
|
|
||||||
return wpa_driver_wext_set_operstate(drv->wext, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void * wpa_driver_prism54_init(void *ctx, const char *ifname)
|
|
||||||
{
|
|
||||||
struct wpa_driver_prism54_data *drv;
|
|
||||||
|
|
||||||
drv = os_zalloc(sizeof(*drv));
|
|
||||||
if (drv == NULL)
|
|
||||||
return NULL;
|
|
||||||
drv->wext = wpa_driver_wext_init(ctx, ifname);
|
|
||||||
if (drv->wext == NULL) {
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
drv->ctx = ctx;
|
|
||||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
|
||||||
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (drv->sock < 0) {
|
|
||||||
wpa_driver_wext_deinit(drv->wext);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_prism54_deinit(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_prism54_data *drv = priv;
|
|
||||||
wpa_driver_wext_deinit(drv->wext);
|
|
||||||
close(drv->sock);
|
|
||||||
os_free(drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const struct wpa_driver_ops wpa_driver_prism54_ops = {
|
|
||||||
.name = "prism54",
|
|
||||||
.desc = "Prism54.org driver (Intersil Prism GT/Duette/Indigo)",
|
|
||||||
.get_bssid = wpa_driver_prism54_get_bssid,
|
|
||||||
.get_ssid = wpa_driver_prism54_get_ssid,
|
|
||||||
.set_wpa = wpa_driver_prism54_set_wpa,
|
|
||||||
.set_key = wpa_driver_prism54_set_key,
|
|
||||||
.set_countermeasures = wpa_driver_prism54_set_countermeasures,
|
|
||||||
.set_drop_unencrypted = wpa_driver_prism54_set_drop_unencrypted,
|
|
||||||
.scan = wpa_driver_prism54_scan,
|
|
||||||
.get_scan_results2 = wpa_driver_prism54_get_scan_results,
|
|
||||||
.deauthenticate = wpa_driver_prism54_deauthenticate,
|
|
||||||
.disassociate = wpa_driver_prism54_disassociate,
|
|
||||||
.associate = wpa_driver_prism54_associate,
|
|
||||||
.init = wpa_driver_prism54_init,
|
|
||||||
.deinit = wpa_driver_prism54_deinit,
|
|
||||||
.set_operstate = wpa_driver_prism54_set_operstate,
|
|
||||||
};
|
|
@ -1,820 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - privilege separated driver interface
|
|
||||||
* Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#include <sys/un.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "driver.h"
|
|
||||||
#include "eloop.h"
|
|
||||||
#include "privsep_commands.h"
|
|
||||||
|
|
||||||
|
|
||||||
struct wpa_driver_privsep_data {
|
|
||||||
void *ctx;
|
|
||||||
u8 own_addr[ETH_ALEN];
|
|
||||||
int priv_socket;
|
|
||||||
char *own_socket_path;
|
|
||||||
int cmd_socket;
|
|
||||||
char *own_cmd_path;
|
|
||||||
struct sockaddr_un priv_addr;
|
|
||||||
char ifname[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data *drv, int cmd)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
|
|
||||||
res = sendto(drv->priv_socket, &cmd, sizeof(cmd), 0,
|
|
||||||
(struct sockaddr *) &drv->priv_addr,
|
|
||||||
sizeof(drv->priv_addr));
|
|
||||||
if (res < 0)
|
|
||||||
perror("sendto");
|
|
||||||
return res < 0 ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd,
|
|
||||||
const void *data, size_t data_len,
|
|
||||||
void *reply, size_t *reply_len)
|
|
||||||
{
|
|
||||||
struct msghdr msg;
|
|
||||||
struct iovec io[2];
|
|
||||||
|
|
||||||
io[0].iov_base = &cmd;
|
|
||||||
io[0].iov_len = sizeof(cmd);
|
|
||||||
io[1].iov_base = (u8 *) data;
|
|
||||||
io[1].iov_len = data_len;
|
|
||||||
|
|
||||||
os_memset(&msg, 0, sizeof(msg));
|
|
||||||
msg.msg_iov = io;
|
|
||||||
msg.msg_iovlen = data ? 2 : 1;
|
|
||||||
msg.msg_name = &drv->priv_addr;
|
|
||||||
msg.msg_namelen = sizeof(drv->priv_addr);
|
|
||||||
|
|
||||||
if (sendmsg(drv->cmd_socket, &msg, 0) < 0) {
|
|
||||||
perror("sendmsg(cmd_socket)");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reply) {
|
|
||||||
fd_set rfds;
|
|
||||||
struct timeval tv;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
|
||||||
FD_SET(drv->cmd_socket, &rfds);
|
|
||||||
tv.tv_sec = 5;
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv);
|
|
||||||
if (res < 0 && errno != EINTR) {
|
|
||||||
perror("select");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FD_ISSET(drv->cmd_socket, &rfds)) {
|
|
||||||
res = recv(drv->cmd_socket, reply, *reply_len, 0);
|
|
||||||
if (res < 0) {
|
|
||||||
perror("recv");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
*reply_len = res;
|
|
||||||
} else {
|
|
||||||
wpa_printf(MSG_DEBUG, "PRIVSEP: Timeout while waiting "
|
|
||||||
"for reply (cmd=%d)", cmd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_privsep_set_wpa(void *priv, int enabled)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
|
|
||||||
return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_WPA, &enabled,
|
|
||||||
sizeof(enabled), NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_privsep_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
|
|
||||||
return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len,
|
|
||||||
NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct wpa_scan_results *
|
|
||||||
wpa_driver_privsep_get_scan_results2(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
int res, num;
|
|
||||||
u8 *buf, *pos, *end;
|
|
||||||
size_t reply_len = 60000;
|
|
||||||
struct wpa_scan_results *results;
|
|
||||||
struct wpa_scan_res *r;
|
|
||||||
|
|
||||||
buf = os_malloc(reply_len);
|
|
||||||
if (buf == NULL)
|
|
||||||
return NULL;
|
|
||||||
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SCAN_RESULTS,
|
|
||||||
NULL, 0, buf, &reply_len);
|
|
||||||
if (res < 0) {
|
|
||||||
os_free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "privsep: Received %lu bytes of scan results",
|
|
||||||
(unsigned long) reply_len);
|
|
||||||
if (reply_len < sizeof(int)) {
|
|
||||||
wpa_printf(MSG_DEBUG, "privsep: Invalid scan result len %lu",
|
|
||||||
(unsigned long) reply_len);
|
|
||||||
os_free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = buf;
|
|
||||||
end = buf + reply_len;
|
|
||||||
os_memcpy(&num, pos, sizeof(int));
|
|
||||||
if (num < 0 || num > 1000) {
|
|
||||||
os_free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
pos += sizeof(int);
|
|
||||||
|
|
||||||
results = os_zalloc(sizeof(*results));
|
|
||||||
if (results == NULL) {
|
|
||||||
os_free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
results->res = os_zalloc(num * sizeof(struct wpa_scan_res *));
|
|
||||||
if (results->res == NULL) {
|
|
||||||
os_free(results);
|
|
||||||
os_free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (results->num < (size_t) num && pos + sizeof(int) < end) {
|
|
||||||
int len;
|
|
||||||
os_memcpy(&len, pos, sizeof(int));
|
|
||||||
pos += sizeof(int);
|
|
||||||
if (len < 0 || len > 10000 || pos + len > end)
|
|
||||||
break;
|
|
||||||
|
|
||||||
r = os_malloc(len);
|
|
||||||
if (r == NULL)
|
|
||||||
break;
|
|
||||||
os_memcpy(r, pos, len);
|
|
||||||
pos += len;
|
|
||||||
if (sizeof(*r) + r->ie_len > (size_t) len) {
|
|
||||||
os_free(r);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
results->res[results->num++] = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_free(buf);
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_privsep_set_key(void *priv, wpa_alg alg, const u8 *addr,
|
|
||||||
int key_idx, int set_tx,
|
|
||||||
const u8 *seq, size_t seq_len,
|
|
||||||
const u8 *key, size_t key_len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
struct privsep_cmd_set_key cmd;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
|
|
||||||
__func__, priv, alg, key_idx, set_tx);
|
|
||||||
|
|
||||||
os_memset(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.alg = alg;
|
|
||||||
if (addr)
|
|
||||||
os_memcpy(cmd.addr, addr, ETH_ALEN);
|
|
||||||
else
|
|
||||||
os_memset(cmd.addr, 0xff, ETH_ALEN);
|
|
||||||
cmd.key_idx = key_idx;
|
|
||||||
cmd.set_tx = set_tx;
|
|
||||||
if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) {
|
|
||||||
os_memcpy(cmd.seq, seq, seq_len);
|
|
||||||
cmd.seq_len = seq_len;
|
|
||||||
}
|
|
||||||
if (key && key_len > 0 && key_len < sizeof(cmd.key)) {
|
|
||||||
os_memcpy(cmd.key, key, key_len);
|
|
||||||
cmd.key_len = key_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_KEY, &cmd, sizeof(cmd),
|
|
||||||
NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_privsep_associate(
|
|
||||||
void *priv, struct wpa_driver_associate_params *params)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
struct privsep_cmd_associate *data;
|
|
||||||
int res;
|
|
||||||
size_t buflen;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
|
|
||||||
"group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
|
|
||||||
__func__, priv, params->freq, params->pairwise_suite,
|
|
||||||
params->group_suite, params->key_mgmt_suite,
|
|
||||||
params->auth_alg, params->mode);
|
|
||||||
|
|
||||||
buflen = sizeof(*data) + params->wpa_ie_len;
|
|
||||||
data = os_zalloc(buflen);
|
|
||||||
if (data == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (params->bssid)
|
|
||||||
os_memcpy(data->bssid, params->bssid, ETH_ALEN);
|
|
||||||
os_memcpy(data->ssid, params->ssid, params->ssid_len);
|
|
||||||
data->ssid_len = params->ssid_len;
|
|
||||||
data->freq = params->freq;
|
|
||||||
data->pairwise_suite = params->pairwise_suite;
|
|
||||||
data->group_suite = params->group_suite;
|
|
||||||
data->key_mgmt_suite = params->key_mgmt_suite;
|
|
||||||
data->auth_alg = params->auth_alg;
|
|
||||||
data->mode = params->mode;
|
|
||||||
data->wpa_ie_len = params->wpa_ie_len;
|
|
||||||
if (params->wpa_ie)
|
|
||||||
os_memcpy(data + 1, params->wpa_ie, params->wpa_ie_len);
|
|
||||||
/* TODO: add support for other assoc parameters */
|
|
||||||
|
|
||||||
res = wpa_priv_cmd(drv, PRIVSEP_CMD_ASSOCIATE, data, buflen,
|
|
||||||
NULL, NULL);
|
|
||||||
os_free(data);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_privsep_get_bssid(void *priv, u8 *bssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
int res;
|
|
||||||
size_t len = ETH_ALEN;
|
|
||||||
|
|
||||||
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_BSSID, NULL, 0, bssid, &len);
|
|
||||||
if (res < 0 || len != ETH_ALEN)
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
int res, ssid_len;
|
|
||||||
u8 reply[sizeof(int) + 32];
|
|
||||||
size_t len = sizeof(reply);
|
|
||||||
|
|
||||||
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len);
|
|
||||||
if (res < 0 || len < sizeof(int))
|
|
||||||
return -1;
|
|
||||||
os_memcpy(&ssid_len, reply, sizeof(int));
|
|
||||||
if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) {
|
|
||||||
wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
os_memcpy(ssid, &reply[sizeof(int)], ssid_len);
|
|
||||||
return ssid_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
|
|
||||||
int reason_code)
|
|
||||||
{
|
|
||||||
//struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
|
|
||||||
__func__, MAC2STR(addr), reason_code);
|
|
||||||
wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_privsep_disassociate(void *priv, const u8 *addr,
|
|
||||||
int reason_code)
|
|
||||||
{
|
|
||||||
//struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
|
|
||||||
__func__, MAC2STR(addr), reason_code);
|
|
||||||
wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_privsep_event_assoc(void *ctx, wpa_event_type event,
|
|
||||||
u8 *buf, size_t len)
|
|
||||||
{
|
|
||||||
union wpa_event_data data;
|
|
||||||
int inc_data = 0;
|
|
||||||
u8 *pos, *end;
|
|
||||||
int ie_len;
|
|
||||||
|
|
||||||
os_memset(&data, 0, sizeof(data));
|
|
||||||
|
|
||||||
pos = buf;
|
|
||||||
end = buf + len;
|
|
||||||
|
|
||||||
if (end - pos < (int) sizeof(int))
|
|
||||||
return;
|
|
||||||
os_memcpy(&ie_len, pos, sizeof(int));
|
|
||||||
pos += sizeof(int);
|
|
||||||
if (ie_len < 0 || ie_len > end - pos)
|
|
||||||
return;
|
|
||||||
if (ie_len) {
|
|
||||||
data.assoc_info.req_ies = pos;
|
|
||||||
data.assoc_info.req_ies_len = ie_len;
|
|
||||||
pos += ie_len;
|
|
||||||
inc_data = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_supplicant_event(ctx, event, inc_data ? &data : NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_privsep_event_interface_status(void *ctx, u8 *buf,
|
|
||||||
size_t len)
|
|
||||||
{
|
|
||||||
union wpa_event_data data;
|
|
||||||
int ievent;
|
|
||||||
|
|
||||||
if (len < sizeof(int) ||
|
|
||||||
len - sizeof(int) > sizeof(data.interface_status.ifname))
|
|
||||||
return;
|
|
||||||
|
|
||||||
os_memcpy(&ievent, buf, sizeof(int));
|
|
||||||
|
|
||||||
os_memset(&data, 0, sizeof(data));
|
|
||||||
data.interface_status.ievent = ievent;
|
|
||||||
os_memcpy(data.interface_status.ifname, buf + sizeof(int),
|
|
||||||
len - sizeof(int));
|
|
||||||
wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_privsep_event_michael_mic_failure(
|
|
||||||
void *ctx, u8 *buf, size_t len)
|
|
||||||
{
|
|
||||||
union wpa_event_data data;
|
|
||||||
|
|
||||||
if (len != sizeof(int))
|
|
||||||
return;
|
|
||||||
|
|
||||||
os_memset(&data, 0, sizeof(data));
|
|
||||||
os_memcpy(&data.michael_mic_failure.unicast, buf, sizeof(int));
|
|
||||||
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf,
|
|
||||||
size_t len)
|
|
||||||
{
|
|
||||||
union wpa_event_data data;
|
|
||||||
|
|
||||||
if (len != sizeof(struct pmkid_candidate))
|
|
||||||
return;
|
|
||||||
|
|
||||||
os_memset(&data, 0, sizeof(data));
|
|
||||||
os_memcpy(&data.pmkid_candidate, buf, len);
|
|
||||||
wpa_supplicant_event(ctx, EVENT_PMKID_CANDIDATE, &data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_privsep_event_stkstart(void *ctx, u8 *buf, size_t len)
|
|
||||||
{
|
|
||||||
union wpa_event_data data;
|
|
||||||
|
|
||||||
if (len != ETH_ALEN)
|
|
||||||
return;
|
|
||||||
|
|
||||||
os_memset(&data, 0, sizeof(data));
|
|
||||||
os_memcpy(data.stkstart.peer, buf, ETH_ALEN);
|
|
||||||
wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf,
|
|
||||||
size_t len)
|
|
||||||
{
|
|
||||||
union wpa_event_data data;
|
|
||||||
|
|
||||||
if (len < sizeof(int) + ETH_ALEN)
|
|
||||||
return;
|
|
||||||
|
|
||||||
os_memset(&data, 0, sizeof(data));
|
|
||||||
os_memcpy(&data.ft_ies.ft_action, buf, sizeof(int));
|
|
||||||
os_memcpy(data.ft_ies.target_ap, buf + sizeof(int), ETH_ALEN);
|
|
||||||
data.ft_ies.ies = buf + sizeof(int) + ETH_ALEN;
|
|
||||||
data.ft_ies.ies_len = len - sizeof(int) - ETH_ALEN;
|
|
||||||
wpa_supplicant_event(ctx, EVENT_FT_RESPONSE, &data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_privsep_event_rx_eapol(void *ctx, u8 *buf, size_t len)
|
|
||||||
{
|
|
||||||
if (len < ETH_ALEN)
|
|
||||||
return;
|
|
||||||
|
|
||||||
wpa_supplicant_rx_eapol(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_privsep_event_sta_rx(void *ctx, u8 *buf, size_t len)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_CLIENT_MLME
|
|
||||||
struct ieee80211_rx_status *rx_status;
|
|
||||||
|
|
||||||
if (len < sizeof(*rx_status))
|
|
||||||
return;
|
|
||||||
rx_status = (struct ieee80211_rx_status *) buf;
|
|
||||||
buf += sizeof(*rx_status);
|
|
||||||
len -= sizeof(*rx_status);
|
|
||||||
|
|
||||||
wpa_supplicant_sta_rx(ctx, buf, len, rx_status);
|
|
||||||
#endif /* CONFIG_CLIENT_MLME */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
|
|
||||||
void *sock_ctx)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = eloop_ctx;
|
|
||||||
u8 *buf, *event_buf;
|
|
||||||
size_t event_len;
|
|
||||||
int res, event;
|
|
||||||
enum privsep_event e;
|
|
||||||
struct sockaddr_un from;
|
|
||||||
socklen_t fromlen = sizeof(from);
|
|
||||||
const size_t buflen = 2000;
|
|
||||||
|
|
||||||
buf = os_malloc(buflen);
|
|
||||||
if (buf == NULL)
|
|
||||||
return;
|
|
||||||
res = recvfrom(sock, buf, buflen, 0,
|
|
||||||
(struct sockaddr *) &from, &fromlen);
|
|
||||||
if (res < 0) {
|
|
||||||
perror("recvfrom(priv_socket)");
|
|
||||||
os_free(buf);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "privsep_driver: received %u bytes", res);
|
|
||||||
|
|
||||||
if (res < (int) sizeof(int)) {
|
|
||||||
wpa_printf(MSG_DEBUG, "Too short event message (len=%d)", res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_memcpy(&event, buf, sizeof(int));
|
|
||||||
event_buf = &buf[sizeof(int)];
|
|
||||||
event_len = res - sizeof(int);
|
|
||||||
wpa_printf(MSG_DEBUG, "privsep: Event %d received (len=%lu)",
|
|
||||||
event, (unsigned long) event_len);
|
|
||||||
|
|
||||||
e = event;
|
|
||||||
switch (e) {
|
|
||||||
case PRIVSEP_EVENT_SCAN_RESULTS:
|
|
||||||
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
|
|
||||||
break;
|
|
||||||
case PRIVSEP_EVENT_ASSOC:
|
|
||||||
wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC,
|
|
||||||
event_buf, event_len);
|
|
||||||
break;
|
|
||||||
case PRIVSEP_EVENT_DISASSOC:
|
|
||||||
wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
|
|
||||||
break;
|
|
||||||
case PRIVSEP_EVENT_ASSOCINFO:
|
|
||||||
wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOCINFO,
|
|
||||||
event_buf, event_len);
|
|
||||||
break;
|
|
||||||
case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE:
|
|
||||||
wpa_driver_privsep_event_michael_mic_failure(
|
|
||||||
drv->ctx, event_buf, event_len);
|
|
||||||
break;
|
|
||||||
case PRIVSEP_EVENT_INTERFACE_STATUS:
|
|
||||||
wpa_driver_privsep_event_interface_status(drv->ctx, event_buf,
|
|
||||||
event_len);
|
|
||||||
break;
|
|
||||||
case PRIVSEP_EVENT_PMKID_CANDIDATE:
|
|
||||||
wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf,
|
|
||||||
event_len);
|
|
||||||
break;
|
|
||||||
case PRIVSEP_EVENT_STKSTART:
|
|
||||||
wpa_driver_privsep_event_stkstart(drv->ctx, event_buf,
|
|
||||||
event_len);
|
|
||||||
break;
|
|
||||||
case PRIVSEP_EVENT_FT_RESPONSE:
|
|
||||||
wpa_driver_privsep_event_ft_response(drv->ctx, event_buf,
|
|
||||||
event_len);
|
|
||||||
break;
|
|
||||||
case PRIVSEP_EVENT_RX_EAPOL:
|
|
||||||
wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf,
|
|
||||||
event_len);
|
|
||||||
break;
|
|
||||||
case PRIVSEP_EVENT_STA_RX:
|
|
||||||
wpa_driver_privsep_event_sta_rx(drv->ctx, event_buf,
|
|
||||||
event_len);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_free(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void * wpa_driver_privsep_init(void *ctx, const char *ifname)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv;
|
|
||||||
|
|
||||||
drv = os_zalloc(sizeof(*drv));
|
|
||||||
if (drv == NULL)
|
|
||||||
return NULL;
|
|
||||||
drv->ctx = ctx;
|
|
||||||
drv->priv_socket = -1;
|
|
||||||
drv->cmd_socket = -1;
|
|
||||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
|
||||||
|
|
||||||
return drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_privsep_deinit(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
|
|
||||||
if (drv->priv_socket >= 0) {
|
|
||||||
wpa_priv_reg_cmd(drv, PRIVSEP_CMD_UNREGISTER);
|
|
||||||
eloop_unregister_read_sock(drv->priv_socket);
|
|
||||||
close(drv->priv_socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drv->own_socket_path) {
|
|
||||||
unlink(drv->own_socket_path);
|
|
||||||
os_free(drv->own_socket_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drv->cmd_socket >= 0) {
|
|
||||||
eloop_unregister_read_sock(drv->cmd_socket);
|
|
||||||
close(drv->cmd_socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drv->own_cmd_path) {
|
|
||||||
unlink(drv->own_cmd_path);
|
|
||||||
os_free(drv->own_cmd_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
os_free(drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_privsep_set_param(void *priv, const char *param)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
const char *pos;
|
|
||||||
char *own_dir, *priv_dir;
|
|
||||||
static unsigned int counter = 0;
|
|
||||||
size_t len;
|
|
||||||
struct sockaddr_un addr;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
|
|
||||||
if (param == NULL)
|
|
||||||
pos = NULL;
|
|
||||||
else
|
|
||||||
pos = os_strstr(param, "own_dir=");
|
|
||||||
if (pos) {
|
|
||||||
char *end;
|
|
||||||
own_dir = os_strdup(pos + 8);
|
|
||||||
if (own_dir == NULL)
|
|
||||||
return -1;
|
|
||||||
end = os_strchr(own_dir, ' ');
|
|
||||||
if (end)
|
|
||||||
*end = '\0';
|
|
||||||
} else {
|
|
||||||
own_dir = os_strdup("/tmp");
|
|
||||||
if (own_dir == NULL)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param == NULL)
|
|
||||||
pos = NULL;
|
|
||||||
else
|
|
||||||
pos = os_strstr(param, "priv_dir=");
|
|
||||||
if (pos) {
|
|
||||||
char *end;
|
|
||||||
priv_dir = os_strdup(pos + 9);
|
|
||||||
if (priv_dir == NULL) {
|
|
||||||
os_free(own_dir);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
end = os_strchr(priv_dir, ' ');
|
|
||||||
if (end)
|
|
||||||
*end = '\0';
|
|
||||||
} else {
|
|
||||||
priv_dir = os_strdup("/var/run/wpa_priv");
|
|
||||||
if (priv_dir == NULL) {
|
|
||||||
os_free(own_dir);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
len = os_strlen(own_dir) + 50;
|
|
||||||
drv->own_socket_path = os_malloc(len);
|
|
||||||
if (drv->own_socket_path == NULL) {
|
|
||||||
os_free(priv_dir);
|
|
||||||
os_free(own_dir);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
os_snprintf(drv->own_socket_path, len, "%s/wpa_privsep-%d-%d",
|
|
||||||
own_dir, getpid(), counter++);
|
|
||||||
|
|
||||||
len = os_strlen(own_dir) + 50;
|
|
||||||
drv->own_cmd_path = os_malloc(len);
|
|
||||||
if (drv->own_cmd_path == NULL) {
|
|
||||||
os_free(drv->own_socket_path);
|
|
||||||
drv->own_socket_path = NULL;
|
|
||||||
os_free(priv_dir);
|
|
||||||
os_free(own_dir);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
os_snprintf(drv->own_cmd_path, len, "%s/wpa_privsep-%d-%d",
|
|
||||||
own_dir, getpid(), counter++);
|
|
||||||
|
|
||||||
os_free(own_dir);
|
|
||||||
|
|
||||||
drv->priv_addr.sun_family = AF_UNIX;
|
|
||||||
os_snprintf(drv->priv_addr.sun_path, sizeof(drv->priv_addr.sun_path),
|
|
||||||
"%s/%s", priv_dir, drv->ifname);
|
|
||||||
os_free(priv_dir);
|
|
||||||
|
|
||||||
drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
|
|
||||||
if (drv->priv_socket < 0) {
|
|
||||||
perror("socket(PF_UNIX)");
|
|
||||||
os_free(drv->own_socket_path);
|
|
||||||
drv->own_socket_path = NULL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_memset(&addr, 0, sizeof(addr));
|
|
||||||
addr.sun_family = AF_UNIX;
|
|
||||||
os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
|
|
||||||
if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
|
|
||||||
0) {
|
|
||||||
perror("bind(PF_UNIX)");
|
|
||||||
close(drv->priv_socket);
|
|
||||||
drv->priv_socket = -1;
|
|
||||||
unlink(drv->own_socket_path);
|
|
||||||
os_free(drv->own_socket_path);
|
|
||||||
drv->own_socket_path = NULL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
eloop_register_read_sock(drv->priv_socket, wpa_driver_privsep_receive,
|
|
||||||
drv, NULL);
|
|
||||||
|
|
||||||
drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
|
|
||||||
if (drv->cmd_socket < 0) {
|
|
||||||
perror("socket(PF_UNIX)");
|
|
||||||
os_free(drv->own_cmd_path);
|
|
||||||
drv->own_cmd_path = NULL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_memset(&addr, 0, sizeof(addr));
|
|
||||||
addr.sun_family = AF_UNIX;
|
|
||||||
os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
|
|
||||||
if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
|
|
||||||
{
|
|
||||||
perror("bind(PF_UNIX)");
|
|
||||||
close(drv->cmd_socket);
|
|
||||||
drv->cmd_socket = -1;
|
|
||||||
unlink(drv->own_cmd_path);
|
|
||||||
os_free(drv->own_cmd_path);
|
|
||||||
drv->own_cmd_path = NULL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wpa_priv_reg_cmd(drv, PRIVSEP_CMD_REGISTER) < 0) {
|
|
||||||
wpa_printf(MSG_ERROR, "Failed to register with wpa_priv");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_privsep_get_capa(void *priv,
|
|
||||||
struct wpa_driver_capa *capa)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
int res;
|
|
||||||
size_t len = sizeof(*capa);
|
|
||||||
|
|
||||||
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len);
|
|
||||||
if (res < 0 || len != sizeof(*capa))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const u8 * wpa_driver_privsep_get_mac_addr(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s", __func__);
|
|
||||||
return drv->own_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_privsep_set_mode(void *priv, int mode)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s mode=%d", __func__, mode);
|
|
||||||
return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_MODE, &mode, sizeof(mode),
|
|
||||||
NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_privsep_set_country(void *priv, const char *alpha2)
|
|
||||||
{
|
|
||||||
struct wpa_driver_privsep_data *drv = priv;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s country='%s'", __func__, alpha2);
|
|
||||||
return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_COUNTRY, alpha2,
|
|
||||||
os_strlen(alpha2), NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct wpa_driver_ops wpa_driver_privsep_ops = {
|
|
||||||
"privsep",
|
|
||||||
"wpa_supplicant privilege separated driver",
|
|
||||||
wpa_driver_privsep_get_bssid,
|
|
||||||
wpa_driver_privsep_get_ssid,
|
|
||||||
wpa_driver_privsep_set_wpa,
|
|
||||||
wpa_driver_privsep_set_key,
|
|
||||||
wpa_driver_privsep_init,
|
|
||||||
wpa_driver_privsep_deinit,
|
|
||||||
wpa_driver_privsep_set_param,
|
|
||||||
NULL /* set_countermeasures */,
|
|
||||||
NULL /* set_drop_unencrypted */,
|
|
||||||
wpa_driver_privsep_scan,
|
|
||||||
NULL /* get_scan_results */,
|
|
||||||
wpa_driver_privsep_deauthenticate,
|
|
||||||
wpa_driver_privsep_disassociate,
|
|
||||||
wpa_driver_privsep_associate,
|
|
||||||
NULL /* set_auth_alg */,
|
|
||||||
NULL /* add_pmkid */,
|
|
||||||
NULL /* remove_pmkid */,
|
|
||||||
NULL /* flush_pmkid */,
|
|
||||||
wpa_driver_privsep_get_capa,
|
|
||||||
NULL /* poll */,
|
|
||||||
NULL /* get_ifname */,
|
|
||||||
wpa_driver_privsep_get_mac_addr,
|
|
||||||
NULL /* send_eapol */,
|
|
||||||
NULL /* set_operstate */,
|
|
||||||
NULL /* mlme_setprotection */,
|
|
||||||
NULL /* get_hw_feature_data */,
|
|
||||||
NULL /* set_channel */,
|
|
||||||
NULL /* set_ssid */,
|
|
||||||
NULL /* set_bssid */,
|
|
||||||
NULL /* send_mlme */,
|
|
||||||
NULL /* mlme_add_sta */,
|
|
||||||
NULL /* mlme_remove_sta */,
|
|
||||||
NULL /* update_ft_ies */,
|
|
||||||
NULL /* send_ft_action */,
|
|
||||||
wpa_driver_privsep_get_scan_results2,
|
|
||||||
NULL /* set_probe_req_ie */,
|
|
||||||
wpa_driver_privsep_set_mode,
|
|
||||||
wpa_driver_privsep_set_country,
|
|
||||||
NULL /* global_init */,
|
|
||||||
NULL /* global_deinit */,
|
|
||||||
NULL /* init2 */,
|
|
||||||
NULL /* get_interfaces */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct wpa_driver_ops *wpa_supplicant_drivers[] =
|
|
||||||
{
|
|
||||||
&wpa_driver_privsep_ops,
|
|
||||||
NULL
|
|
||||||
};
|
|
@ -1,186 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - PS3 Linux wireless extension driver interface
|
|
||||||
* Copyright 2007, 2008 Sony Corporation
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include "wireless_copy.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include "wpa_common.h"
|
|
||||||
#include "driver.h"
|
|
||||||
#include "eloop.h"
|
|
||||||
#include "driver_wext.h"
|
|
||||||
#include "ieee802_11_defs.h"
|
|
||||||
|
|
||||||
static int wpa_driver_ps3_set_wpa_key(struct wpa_driver_wext_data *drv,
|
|
||||||
struct wpa_driver_associate_params *params)
|
|
||||||
{
|
|
||||||
int ret, i;
|
|
||||||
struct iwreq iwr;
|
|
||||||
char *buf, *str;
|
|
||||||
|
|
||||||
if (!params->psk && !params->passphrase) {
|
|
||||||
wpa_printf(MSG_INFO, "%s:no PSK error", __func__);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_memset(&iwr, 0, sizeof(iwr));
|
|
||||||
if (params->psk) {
|
|
||||||
/* includes null */
|
|
||||||
iwr.u.data.length = PMK_LEN * 2 + 1;
|
|
||||||
buf = os_malloc(iwr.u.data.length);
|
|
||||||
if (!buf)
|
|
||||||
return -ENOMEM;
|
|
||||||
str = buf;
|
|
||||||
for (i = 0; i < PMK_LEN; i++) {
|
|
||||||
str += snprintf(str, iwr.u.data.length - (str - buf),
|
|
||||||
"%02x", params->psk[i]);
|
|
||||||
}
|
|
||||||
} else if (params->passphrase) {
|
|
||||||
/* including quotations and null */
|
|
||||||
iwr.u.data.length = strlen(params->passphrase) + 3;
|
|
||||||
buf = os_malloc(iwr.u.data.length);
|
|
||||||
if (!buf)
|
|
||||||
return -ENOMEM;
|
|
||||||
buf[0] = '"';
|
|
||||||
os_memcpy(buf + 1, params->passphrase, iwr.u.data.length - 3);
|
|
||||||
buf[iwr.u.data.length - 2] = '"';
|
|
||||||
buf[iwr.u.data.length - 1] = '\0';
|
|
||||||
} else
|
|
||||||
return -EINVAL;
|
|
||||||
iwr.u.data.pointer = (caddr_t) buf;
|
|
||||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
ret = ioctl(drv->ioctl_sock, SIOCIWFIRSTPRIV, &iwr);
|
|
||||||
os_free(buf);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wpa_driver_ps3_set_wep_keys(struct wpa_driver_wext_data *drv,
|
|
||||||
struct wpa_driver_associate_params *params)
|
|
||||||
{
|
|
||||||
int ret, i;
|
|
||||||
struct iwreq iwr;
|
|
||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
os_memset(&iwr, 0, sizeof(iwr));
|
|
||||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
iwr.u.encoding.flags = i + 1;
|
|
||||||
if (params->wep_key_len[i]) {
|
|
||||||
iwr.u.encoding.pointer = (caddr_t) params->wep_key[i];
|
|
||||||
iwr.u.encoding.length = params->wep_key_len[i];
|
|
||||||
} else
|
|
||||||
iwr.u.encoding.flags = IW_ENCODE_NOKEY |
|
|
||||||
IW_ENCODE_DISABLED;
|
|
||||||
|
|
||||||
if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
|
|
||||||
perror("ioctl[SIOCSIWENCODE]");
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wpa_driver_ps3_associate(void *priv,
|
|
||||||
struct wpa_driver_associate_params *params)
|
|
||||||
{
|
|
||||||
struct wpa_driver_wext_data *drv = priv;
|
|
||||||
int ret, value;
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: <-", __func__);
|
|
||||||
|
|
||||||
/* clear BSSID */
|
|
||||||
if (!params->bssid &&
|
|
||||||
wpa_driver_wext_set_bssid(drv, NULL) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
|
|
||||||
value = IW_AUTH_WPA_VERSION_DISABLED;
|
|
||||||
else if (params->wpa_ie[0] == WLAN_EID_RSN)
|
|
||||||
value = IW_AUTH_WPA_VERSION_WPA2;
|
|
||||||
else
|
|
||||||
value = IW_AUTH_WPA_VERSION_WPA;
|
|
||||||
if (wpa_driver_wext_set_auth_param(drv,
|
|
||||||
IW_AUTH_WPA_VERSION, value) < 0)
|
|
||||||
ret = -1;
|
|
||||||
value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
|
|
||||||
if (wpa_driver_wext_set_auth_param(drv,
|
|
||||||
IW_AUTH_CIPHER_PAIRWISE, value) < 0)
|
|
||||||
ret = -1;
|
|
||||||
value = wpa_driver_wext_cipher2wext(params->group_suite);
|
|
||||||
if (wpa_driver_wext_set_auth_param(drv,
|
|
||||||
IW_AUTH_CIPHER_GROUP, value) < 0)
|
|
||||||
ret = -1;
|
|
||||||
value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
|
|
||||||
if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_KEY_MGMT, value) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
/* set selected BSSID */
|
|
||||||
if (params->bssid &&
|
|
||||||
wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
switch (params->group_suite) {
|
|
||||||
case CIPHER_NONE:
|
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
case CIPHER_WEP40:
|
|
||||||
case CIPHER_WEP104:
|
|
||||||
ret = wpa_driver_ps3_set_wep_keys(drv, params);
|
|
||||||
break;
|
|
||||||
case CIPHER_TKIP:
|
|
||||||
case CIPHER_CCMP:
|
|
||||||
ret = wpa_driver_ps3_set_wpa_key(drv, params);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* start to associate */
|
|
||||||
ret = wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len);
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: ->", __func__);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wpa_driver_ps3_get_capa(void *priv, struct wpa_driver_capa *capa)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s:<-", __func__);
|
|
||||||
|
|
||||||
ret = wpa_driver_wext_get_capa(priv, capa);
|
|
||||||
if (ret) {
|
|
||||||
wpa_printf(MSG_INFO, "%s: base wext returns error %d",
|
|
||||||
__func__, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
/* PS3 hypervisor does association and 4way handshake by itself */
|
|
||||||
capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
|
|
||||||
wpa_printf(MSG_DEBUG, "%s:->", __func__);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct wpa_driver_ops wpa_driver_ps3_ops = {
|
|
||||||
.name = "ps3",
|
|
||||||
.desc = "PLAYSTATION3 Linux wireless extension driver",
|
|
||||||
.get_bssid = wpa_driver_wext_get_bssid,
|
|
||||||
.get_ssid = wpa_driver_wext_get_ssid,
|
|
||||||
.scan = wpa_driver_wext_scan,
|
|
||||||
.get_scan_results2 = wpa_driver_wext_get_scan_results,
|
|
||||||
.associate = wpa_driver_ps3_associate, /* PS3 */
|
|
||||||
.init = wpa_driver_wext_init,
|
|
||||||
.deinit = wpa_driver_wext_deinit,
|
|
||||||
.get_capa = wpa_driver_ps3_get_capa, /* PS3 */
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load Diff
@ -1,382 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - driver_ralink exported functions
|
|
||||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
|
||||||
* Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Ralink defined OIDs
|
|
||||||
#if WIRELESS_EXT <= 11
|
|
||||||
#ifndef SIOCDEVPRIVATE
|
|
||||||
#define SIOCDEVPRIVATE 0x8BE0
|
|
||||||
#endif
|
|
||||||
#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define RT_PRIV_IOCTL (SIOCIWFIRSTPRIV + 0x0E)
|
|
||||||
#define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02)
|
|
||||||
|
|
||||||
// IEEE 802.11 OIDs & Ralink defined OIDs ******
|
|
||||||
|
|
||||||
// (RaConfig Set/QueryInform) ==>
|
|
||||||
#define OID_GET_SET_TOGGLE 0x8000
|
|
||||||
|
|
||||||
#define OID_802_11_ADD_WEP 0x0112
|
|
||||||
#define OID_802_11_REMOVE_WEP 0x0113
|
|
||||||
#define OID_802_11_DISASSOCIATE 0x0114
|
|
||||||
#define OID_802_11_PRIVACY_FILTER 0x0118
|
|
||||||
#define OID_802_11_ASSOCIATION_INFORMATION 0x011E
|
|
||||||
#define OID_802_11_BSSID_LIST_SCAN 0x0508
|
|
||||||
#define OID_802_11_SSID 0x0509
|
|
||||||
#define OID_802_11_BSSID 0x050A
|
|
||||||
#define OID_802_11_WEP_STATUS 0x0510
|
|
||||||
#define OID_802_11_AUTHENTICATION_MODE 0x0511
|
|
||||||
#define OID_802_11_INFRASTRUCTURE_MODE 0x0512
|
|
||||||
#define OID_802_11_TX_POWER_LEVEL 0x0517
|
|
||||||
#define OID_802_11_REMOVE_KEY 0x0519
|
|
||||||
#define OID_802_11_ADD_KEY 0x0520
|
|
||||||
#define OID_802_11_DEAUTHENTICATION 0x0526
|
|
||||||
#define OID_802_11_DROP_UNENCRYPTED 0x0527
|
|
||||||
#define OID_802_11_BSSID_LIST 0x0609
|
|
||||||
#define OID_802_3_CURRENT_ADDRESS 0x060A
|
|
||||||
#define OID_SET_COUNTERMEASURES 0x0616
|
|
||||||
#define OID_802_11_SET_IEEE8021X 0x0617 // For IEEE8021x mode
|
|
||||||
#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 // For DynamicWEP in IEEE802.1x mode
|
|
||||||
#define OID_802_11_PMKID 0x0620
|
|
||||||
#define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 // for trigger driver enable/disable wpa_supplicant support
|
|
||||||
#define RT_OID_WE_VERSION_COMPILED 0x0622
|
|
||||||
#define RT_OID_NEW_DRIVER 0x0623
|
|
||||||
|
|
||||||
#define PACKED __attribute__ ((packed))
|
|
||||||
|
|
||||||
//wpa_supplicant event flags
|
|
||||||
#define RT_ASSOC_EVENT_FLAG 0x0101
|
|
||||||
#define RT_DISASSOC_EVENT_FLAG 0x0102
|
|
||||||
#define RT_REQIE_EVENT_FLAG 0x0103
|
|
||||||
#define RT_RESPIE_EVENT_FLAG 0x0104
|
|
||||||
#define RT_ASSOCINFO_EVENT_FLAG 0x0105
|
|
||||||
#define RT_PMKIDCAND_FLAG 0x0106
|
|
||||||
#define RT_INTERFACE_DOWN 0x0107
|
|
||||||
#define RT_REPORT_AP_INFO 0x0108
|
|
||||||
|
|
||||||
//
|
|
||||||
// IEEE 802.11 Structures and definitions
|
|
||||||
//
|
|
||||||
// new types for Media Specific Indications
|
|
||||||
|
|
||||||
#ifndef ULONG
|
|
||||||
#define CHAR char
|
|
||||||
#define INT int
|
|
||||||
#define SHORT int
|
|
||||||
#define UINT u32
|
|
||||||
#undef ULONG
|
|
||||||
//#define ULONG u32
|
|
||||||
#define ULONG unsigned long /* 32-bit in 32-bit CPU or 64-bit in 64-bit CPU */
|
|
||||||
#define USHORT unsigned short
|
|
||||||
#define UCHAR unsigned char
|
|
||||||
|
|
||||||
#define uint32 u32
|
|
||||||
#define uint8 u8
|
|
||||||
|
|
||||||
|
|
||||||
#define BOOLEAN u8
|
|
||||||
//#define LARGE_INTEGER s64
|
|
||||||
#define VOID void
|
|
||||||
#define LONG long
|
|
||||||
#define LONGLONG s64
|
|
||||||
#define ULONGLONG u64
|
|
||||||
typedef VOID *PVOID;
|
|
||||||
typedef CHAR *PCHAR;
|
|
||||||
typedef UCHAR *PUCHAR;
|
|
||||||
typedef USHORT *PUSHORT;
|
|
||||||
typedef LONG *PLONG;
|
|
||||||
typedef ULONG *PULONG;
|
|
||||||
|
|
||||||
typedef union _LARGE_INTEGER {
|
|
||||||
struct {
|
|
||||||
ULONG LowPart;
|
|
||||||
LONG HighPart;
|
|
||||||
}vv;
|
|
||||||
struct {
|
|
||||||
ULONG LowPart;
|
|
||||||
LONG HighPart;
|
|
||||||
} u;
|
|
||||||
s64 QuadPart;
|
|
||||||
} LARGE_INTEGER;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define NDIS_802_11_LENGTH_SSID 32
|
|
||||||
#define NDIS_802_11_LENGTH_RATES 8
|
|
||||||
#define NDIS_802_11_LENGTH_RATES_EX 16
|
|
||||||
#define MAX_LEN_OF_SSID 32
|
|
||||||
#define MAC_ADDR_LEN 6
|
|
||||||
|
|
||||||
typedef UCHAR NDIS_802_11_MAC_ADDRESS[6];
|
|
||||||
|
|
||||||
// mask for authentication/integrity fields
|
|
||||||
#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f
|
|
||||||
|
|
||||||
#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01
|
|
||||||
#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02
|
|
||||||
#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06
|
|
||||||
#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E
|
|
||||||
|
|
||||||
// Added new types for OFDM 5G and 2.4G
|
|
||||||
typedef enum _NDIS_802_11_NETWORK_TYPE
|
|
||||||
{
|
|
||||||
Ndis802_11FH,
|
|
||||||
Ndis802_11DS,
|
|
||||||
Ndis802_11OFDM5,
|
|
||||||
Ndis802_11OFDM24,
|
|
||||||
Ndis802_11Automode,
|
|
||||||
Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound
|
|
||||||
} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Received Signal Strength Indication
|
|
||||||
//
|
|
||||||
typedef LONG NDIS_802_11_RSSI; // in dBm
|
|
||||||
|
|
||||||
typedef struct _NDIS_802_11_CONFIGURATION_FH
|
|
||||||
{
|
|
||||||
ULONG Length; // Length of structure
|
|
||||||
ULONG HopPattern; // As defined by 802.11, MSB set
|
|
||||||
ULONG HopSet; // to one if non-802.11
|
|
||||||
ULONG DwellTime; // units are Kusec
|
|
||||||
} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH;
|
|
||||||
|
|
||||||
typedef struct _NDIS_802_11_CONFIGURATION
|
|
||||||
{
|
|
||||||
ULONG Length; // Length of structure
|
|
||||||
ULONG BeaconPeriod; // units are Kusec
|
|
||||||
ULONG ATIMWindow; // units are Kusec
|
|
||||||
ULONG DSConfig; // Frequency, units are kHz
|
|
||||||
NDIS_802_11_CONFIGURATION_FH FHConfig;
|
|
||||||
} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION;
|
|
||||||
|
|
||||||
typedef ULONG NDIS_802_11_KEY_INDEX;
|
|
||||||
typedef ULONGLONG NDIS_802_11_KEY_RSC;
|
|
||||||
|
|
||||||
// Key mapping keys require a BSSID
|
|
||||||
typedef struct _NDIS_802_11_KEY
|
|
||||||
{
|
|
||||||
UINT Length; // Length of this structure
|
|
||||||
UINT KeyIndex;
|
|
||||||
UINT KeyLength; // length of key in bytes
|
|
||||||
NDIS_802_11_MAC_ADDRESS BSSID;
|
|
||||||
NDIS_802_11_KEY_RSC KeyRSC;
|
|
||||||
UCHAR KeyMaterial[1]; // variable length depending on above field
|
|
||||||
} NDIS_802_11_KEY, *PNDIS_802_11_KEY;
|
|
||||||
|
|
||||||
typedef struct _NDIS_802_11_REMOVE_KEY
|
|
||||||
{
|
|
||||||
UINT Length; // Length of this structure
|
|
||||||
UINT KeyIndex;
|
|
||||||
NDIS_802_11_MAC_ADDRESS BSSID;
|
|
||||||
} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY;
|
|
||||||
|
|
||||||
typedef struct PACKED _NDIS_802_11_WEP
|
|
||||||
{
|
|
||||||
UINT Length; // Length of this structure
|
|
||||||
UINT KeyIndex; // 0 is the per-client key, 1-N are the
|
|
||||||
// global keys
|
|
||||||
UINT KeyLength; // length of key in bytes
|
|
||||||
UCHAR KeyMaterial[1];// variable length depending on above field
|
|
||||||
} NDIS_802_11_WEP, *PNDIS_802_11_WEP;
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE
|
|
||||||
{
|
|
||||||
Ndis802_11IBSS,
|
|
||||||
Ndis802_11Infrastructure,
|
|
||||||
Ndis802_11AutoUnknown,
|
|
||||||
Ndis802_11InfrastructureMax // Not a real value, defined as upper bound
|
|
||||||
} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE;
|
|
||||||
|
|
||||||
// PMKID Structures
|
|
||||||
typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
|
|
||||||
|
|
||||||
typedef struct _BSSID_INFO
|
|
||||||
{
|
|
||||||
NDIS_802_11_MAC_ADDRESS BSSID;
|
|
||||||
NDIS_802_11_PMKID_VALUE PMKID;
|
|
||||||
} BSSID_INFO, *PBSSID_INFO;
|
|
||||||
|
|
||||||
typedef struct _NDIS_802_11_PMKID
|
|
||||||
{
|
|
||||||
ULONG Length;
|
|
||||||
ULONG BSSIDInfoCount;
|
|
||||||
BSSID_INFO BSSIDInfo[1];
|
|
||||||
} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID;
|
|
||||||
|
|
||||||
//Added new types for PMKID Candidate lists.
|
|
||||||
typedef struct _PMKID_CANDIDATE {
|
|
||||||
NDIS_802_11_MAC_ADDRESS BSSID;
|
|
||||||
ULONG Flags;
|
|
||||||
} PMKID_CANDIDATE, *PPMKID_CANDIDATE;
|
|
||||||
|
|
||||||
typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST
|
|
||||||
{
|
|
||||||
ULONG Version; // Version of the structure
|
|
||||||
ULONG NumCandidates; // No. of pmkid candidates
|
|
||||||
PMKID_CANDIDATE CandidateList[1];
|
|
||||||
} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST;
|
|
||||||
|
|
||||||
//Flags for PMKID Candidate list structure
|
|
||||||
#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
|
|
||||||
|
|
||||||
// Add new authentication modes
|
|
||||||
typedef enum _NDIS_802_11_AUTHENTICATION_MODE
|
|
||||||
{
|
|
||||||
Ndis802_11AuthModeOpen,
|
|
||||||
Ndis802_11AuthModeShared,
|
|
||||||
Ndis802_11AuthModeAutoSwitch,
|
|
||||||
Ndis802_11AuthModeWPA,
|
|
||||||
Ndis802_11AuthModeWPAPSK,
|
|
||||||
Ndis802_11AuthModeWPANone,
|
|
||||||
Ndis802_11AuthModeWPA2,
|
|
||||||
Ndis802_11AuthModeWPA2PSK,
|
|
||||||
Ndis802_11AuthModeMax // Not a real mode, defined as upper bound
|
|
||||||
} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE;
|
|
||||||
|
|
||||||
typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates
|
|
||||||
typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates
|
|
||||||
|
|
||||||
typedef struct PACKED _NDIS_802_11_SSID
|
|
||||||
{
|
|
||||||
INT SsidLength; // length of SSID field below, in bytes;
|
|
||||||
// this can be zero.
|
|
||||||
UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field
|
|
||||||
} NDIS_802_11_SSID, *PNDIS_802_11_SSID;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct PACKED _NDIS_WLAN_BSSID
|
|
||||||
{
|
|
||||||
ULONG Length; // Length of this structure
|
|
||||||
NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID
|
|
||||||
UCHAR Reserved[2];
|
|
||||||
NDIS_802_11_SSID Ssid; // SSID
|
|
||||||
ULONG Privacy; // WEP encryption requirement
|
|
||||||
NDIS_802_11_RSSI Rssi; // receive signal
|
|
||||||
// strength in dBm
|
|
||||||
NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
|
|
||||||
NDIS_802_11_CONFIGURATION Configuration;
|
|
||||||
NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
|
|
||||||
NDIS_802_11_RATES SupportedRates;
|
|
||||||
} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID;
|
|
||||||
|
|
||||||
typedef struct PACKED _NDIS_802_11_BSSID_LIST
|
|
||||||
{
|
|
||||||
UINT NumberOfItems; // in list below, at least 1
|
|
||||||
NDIS_WLAN_BSSID Bssid[1];
|
|
||||||
} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST;
|
|
||||||
|
|
||||||
// Added Capabilities, IELength and IEs for each BSSID
|
|
||||||
typedef struct PACKED _NDIS_WLAN_BSSID_EX
|
|
||||||
{
|
|
||||||
ULONG Length; // Length of this structure
|
|
||||||
NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID
|
|
||||||
UCHAR Reserved[2];
|
|
||||||
NDIS_802_11_SSID Ssid; // SSID
|
|
||||||
UINT Privacy; // WEP encryption requirement
|
|
||||||
NDIS_802_11_RSSI Rssi; // receive signal
|
|
||||||
// strength in dBm
|
|
||||||
NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
|
|
||||||
NDIS_802_11_CONFIGURATION Configuration;
|
|
||||||
NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
|
|
||||||
NDIS_802_11_RATES_EX SupportedRates;
|
|
||||||
ULONG IELength;
|
|
||||||
UCHAR IEs[1];
|
|
||||||
} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX;
|
|
||||||
|
|
||||||
typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX
|
|
||||||
{
|
|
||||||
UINT NumberOfItems; // in list below, at least 1
|
|
||||||
NDIS_WLAN_BSSID_EX Bssid[1];
|
|
||||||
} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX;
|
|
||||||
|
|
||||||
typedef struct PACKED _NDIS_802_11_FIXED_IEs
|
|
||||||
{
|
|
||||||
UCHAR Timestamp[8];
|
|
||||||
USHORT BeaconInterval;
|
|
||||||
USHORT Capabilities;
|
|
||||||
} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs;
|
|
||||||
|
|
||||||
// Added new encryption types
|
|
||||||
// Also aliased typedef to new name
|
|
||||||
typedef enum _NDIS_802_11_WEP_STATUS
|
|
||||||
{
|
|
||||||
Ndis802_11WEPEnabled,
|
|
||||||
Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
|
|
||||||
Ndis802_11WEPDisabled,
|
|
||||||
Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
|
|
||||||
Ndis802_11WEPKeyAbsent,
|
|
||||||
Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
|
|
||||||
Ndis802_11WEPNotSupported,
|
|
||||||
Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
|
|
||||||
Ndis802_11Encryption2Enabled,
|
|
||||||
Ndis802_11Encryption2KeyAbsent,
|
|
||||||
Ndis802_11Encryption3Enabled,
|
|
||||||
Ndis802_11Encryption3KeyAbsent
|
|
||||||
} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS,
|
|
||||||
NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS;
|
|
||||||
|
|
||||||
typedef enum _NDIS_802_11_RELOAD_DEFAULTS
|
|
||||||
{
|
|
||||||
Ndis802_11ReloadWEPKeys
|
|
||||||
} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS;
|
|
||||||
|
|
||||||
#define NDIS_802_11_AI_REQFI_CAPABILITIES 1
|
|
||||||
#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2
|
|
||||||
#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4
|
|
||||||
|
|
||||||
#define NDIS_802_11_AI_RESFI_CAPABILITIES 1
|
|
||||||
#define NDIS_802_11_AI_RESFI_STATUSCODE 2
|
|
||||||
#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4
|
|
||||||
|
|
||||||
typedef struct _NDIS_802_11_AI_REQFI
|
|
||||||
{
|
|
||||||
USHORT Capabilities;
|
|
||||||
USHORT ListenInterval;
|
|
||||||
NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
|
|
||||||
} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI;
|
|
||||||
|
|
||||||
typedef struct _NDIS_802_11_AI_RESFI
|
|
||||||
{
|
|
||||||
USHORT Capabilities;
|
|
||||||
USHORT StatusCode;
|
|
||||||
USHORT AssociationId;
|
|
||||||
} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI;
|
|
||||||
|
|
||||||
typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION
|
|
||||||
{
|
|
||||||
ULONG Length;
|
|
||||||
USHORT AvailableRequestFixedIEs;
|
|
||||||
NDIS_802_11_AI_REQFI RequestFixedIEs;
|
|
||||||
ULONG RequestIELength;
|
|
||||||
ULONG OffsetRequestIEs;
|
|
||||||
USHORT AvailableResponseFixedIEs;
|
|
||||||
NDIS_802_11_AI_RESFI ResponseFixedIEs;
|
|
||||||
ULONG ResponseIELength;
|
|
||||||
ULONG OffsetResponseIEs;
|
|
||||||
} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION;
|
|
||||||
|
|
||||||
struct ndis_pmkid_entry {
|
|
||||||
struct ndis_pmkid_entry *next;
|
|
||||||
u8 bssid[ETH_ALEN];
|
|
||||||
u8 pmkid[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _MLME_DEAUTH_REQ_STRUCT {
|
|
||||||
UCHAR Addr[MAC_ADDR_LEN];
|
|
||||||
USHORT Reason;
|
|
||||||
} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT;
|
|
@ -1,476 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - roboswitch driver interface
|
|
||||||
* Copyright (c) 2008-2009 Jouke Witteveen
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <linux/if.h>
|
|
||||||
#include <linux/sockios.h>
|
|
||||||
#include <linux/if_ether.h>
|
|
||||||
#include <linux/mii.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "driver.h"
|
|
||||||
#include "l2_packet/l2_packet.h"
|
|
||||||
|
|
||||||
#ifndef ETH_P_EAPOL
|
|
||||||
#define ETH_P_EAPOL 0x888e
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ROBO_PHY_ADDR 0x1e /* RoboSwitch PHY address */
|
|
||||||
|
|
||||||
/* MII access registers */
|
|
||||||
#define ROBO_MII_PAGE 0x10 /* MII page register */
|
|
||||||
#define ROBO_MII_ADDR 0x11 /* MII address register */
|
|
||||||
#define ROBO_MII_DATA_OFFSET 0x18 /* Start of MII data registers */
|
|
||||||
|
|
||||||
#define ROBO_MII_PAGE_ENABLE 0x01 /* MII page op code */
|
|
||||||
#define ROBO_MII_ADDR_WRITE 0x01 /* MII address write op code */
|
|
||||||
#define ROBO_MII_ADDR_READ 0x02 /* MII address read op code */
|
|
||||||
#define ROBO_MII_DATA_MAX 4 /* Consecutive MII data registers */
|
|
||||||
#define ROBO_MII_RETRY_MAX 10 /* Read attempts before giving up */
|
|
||||||
|
|
||||||
/* Page numbers */
|
|
||||||
#define ROBO_ARLCTRL_PAGE 0x04 /* ARL control page */
|
|
||||||
#define ROBO_VLAN_PAGE 0x34 /* VLAN page */
|
|
||||||
|
|
||||||
/* ARL control page registers */
|
|
||||||
#define ROBO_ARLCTRL_CONF 0x00 /* ARL configuration register */
|
|
||||||
#define ROBO_ARLCTRL_ADDR_1 0x10 /* Multiport address 1 */
|
|
||||||
#define ROBO_ARLCTRL_VEC_1 0x16 /* Multiport vector 1 */
|
|
||||||
#define ROBO_ARLCTRL_ADDR_2 0x20 /* Multiport address 2 */
|
|
||||||
#define ROBO_ARLCTRL_VEC_2 0x26 /* Multiport vector 2 */
|
|
||||||
|
|
||||||
/* VLAN page registers */
|
|
||||||
#define ROBO_VLAN_ACCESS 0x08 /* VLAN table access register */
|
|
||||||
#define ROBO_VLAN_ACCESS_5350 0x06 /* VLAN table access register (5350) */
|
|
||||||
#define ROBO_VLAN_READ 0x0c /* VLAN read register */
|
|
||||||
#define ROBO_VLAN_MAX 0xff /* Maximum number of VLANs */
|
|
||||||
|
|
||||||
|
|
||||||
static const u8 pae_group_addr[ETH_ALEN] =
|
|
||||||
{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
|
|
||||||
|
|
||||||
|
|
||||||
struct wpa_driver_roboswitch_data {
|
|
||||||
void *ctx;
|
|
||||||
struct l2_packet_data *l2;
|
|
||||||
char ifname[IFNAMSIZ + 1];
|
|
||||||
u8 own_addr[ETH_ALEN];
|
|
||||||
struct ifreq ifr;
|
|
||||||
int fd, is_5350;
|
|
||||||
u16 ports;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* Copied from the kernel-only part of mii.h. */
|
|
||||||
static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
|
|
||||||
{
|
|
||||||
return (struct mii_ioctl_data *) &rq->ifr_ifru;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* RoboSwitch uses 16-bit Big Endian addresses.
|
|
||||||
* The ordering of the words is reversed in the MII registers.
|
|
||||||
*/
|
|
||||||
static void wpa_driver_roboswitch_addr_be16(const u8 addr[ETH_ALEN], u16 *be)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < ETH_ALEN; i += 2)
|
|
||||||
be[(ETH_ALEN - i) / 2 - 1] = WPA_GET_BE16(addr + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static u16 wpa_driver_roboswitch_mdio_read(
|
|
||||||
struct wpa_driver_roboswitch_data *drv, u8 reg)
|
|
||||||
{
|
|
||||||
struct mii_ioctl_data *mii = if_mii(&drv->ifr);
|
|
||||||
|
|
||||||
mii->phy_id = ROBO_PHY_ADDR;
|
|
||||||
mii->reg_num = reg;
|
|
||||||
|
|
||||||
if (ioctl(drv->fd, SIOCGMIIREG, &drv->ifr) < 0) {
|
|
||||||
perror("ioctl[SIOCGMIIREG]");
|
|
||||||
return 0x00;
|
|
||||||
}
|
|
||||||
return mii->val_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_roboswitch_mdio_write(
|
|
||||||
struct wpa_driver_roboswitch_data *drv, u8 reg, u16 val)
|
|
||||||
{
|
|
||||||
struct mii_ioctl_data *mii = if_mii(&drv->ifr);
|
|
||||||
|
|
||||||
mii->phy_id = ROBO_PHY_ADDR;
|
|
||||||
mii->reg_num = reg;
|
|
||||||
mii->val_in = val;
|
|
||||||
|
|
||||||
if (ioctl(drv->fd, SIOCSMIIREG, &drv->ifr) < 0) {
|
|
||||||
perror("ioctl[SIOCSMIIREG");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_roboswitch_reg(struct wpa_driver_roboswitch_data *drv,
|
|
||||||
u8 page, u8 reg, u8 op)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* set page number */
|
|
||||||
wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_PAGE,
|
|
||||||
(page << 8) | ROBO_MII_PAGE_ENABLE);
|
|
||||||
/* set register address */
|
|
||||||
wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_ADDR, (reg << 8) | op);
|
|
||||||
|
|
||||||
/* check if operation completed */
|
|
||||||
for (i = 0; i < ROBO_MII_RETRY_MAX; ++i) {
|
|
||||||
if ((wpa_driver_roboswitch_mdio_read(drv, ROBO_MII_ADDR) & 3)
|
|
||||||
== 0)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* timeout */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_roboswitch_read(struct wpa_driver_roboswitch_data *drv,
|
|
||||||
u8 page, u8 reg, u16 *val, int len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (len > ROBO_MII_DATA_MAX ||
|
|
||||||
wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_READ) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
for (i = 0; i < len; ++i) {
|
|
||||||
val[i] = wpa_driver_roboswitch_mdio_read(
|
|
||||||
drv, ROBO_MII_DATA_OFFSET + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_roboswitch_write(struct wpa_driver_roboswitch_data *drv,
|
|
||||||
u8 page, u8 reg, u16 *val, int len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (len > ROBO_MII_DATA_MAX) return -1;
|
|
||||||
for (i = 0; i < len; ++i) {
|
|
||||||
wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_DATA_OFFSET + i,
|
|
||||||
val[i]);
|
|
||||||
}
|
|
||||||
return wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_roboswitch_receive(void *priv, const u8 *src_addr,
|
|
||||||
const u8 *buf, size_t len)
|
|
||||||
{
|
|
||||||
struct wpa_driver_roboswitch_data *drv = priv;
|
|
||||||
|
|
||||||
if (len > 14 && WPA_GET_BE16(buf + 12) == ETH_P_EAPOL &&
|
|
||||||
os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0) {
|
|
||||||
wpa_supplicant_rx_eapol(drv->ctx, src_addr, buf + 14,
|
|
||||||
len - 14);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_roboswitch_get_ssid(void *priv, u8 *ssid)
|
|
||||||
{
|
|
||||||
ssid[0] = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_roboswitch_get_bssid(void *priv, u8 *bssid)
|
|
||||||
{
|
|
||||||
/* Report PAE group address as the "BSSID" for wired connection. */
|
|
||||||
os_memcpy(bssid, pae_group_addr, ETH_ALEN);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_roboswitch_set_param(void *priv, const char *param)
|
|
||||||
{
|
|
||||||
struct wpa_driver_roboswitch_data *drv = priv;
|
|
||||||
char *sep;
|
|
||||||
|
|
||||||
if (param == NULL || os_strstr(param, "multicast_only=1") == NULL) {
|
|
||||||
sep = drv->ifname + os_strlen(drv->ifname);
|
|
||||||
*sep = '.';
|
|
||||||
drv->l2 = l2_packet_init(drv->ifname, NULL, ETH_P_ALL,
|
|
||||||
wpa_driver_roboswitch_receive, drv,
|
|
||||||
1);
|
|
||||||
if (drv->l2 == NULL) {
|
|
||||||
wpa_printf(MSG_INFO, "%s: Unable to listen on %s",
|
|
||||||
__func__, drv->ifname);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
*sep = '\0';
|
|
||||||
l2_packet_get_own_addr(drv->l2, drv->own_addr);
|
|
||||||
} else {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: Ignoring unicast frames", __func__);
|
|
||||||
drv->l2 = NULL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const char * wpa_driver_roboswitch_get_ifname(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_roboswitch_data *drv = priv;
|
|
||||||
return drv->ifname;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_roboswitch_join(struct wpa_driver_roboswitch_data *drv,
|
|
||||||
u16 ports, const u8 *addr)
|
|
||||||
{
|
|
||||||
u16 read1[3], read2[3], addr_be16[3];
|
|
||||||
|
|
||||||
wpa_driver_roboswitch_addr_be16(addr, addr_be16);
|
|
||||||
|
|
||||||
if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_CONF, read1, 1) < 0)
|
|
||||||
return -1;
|
|
||||||
if (!(read1[0] & (1 << 4))) {
|
|
||||||
/* multiport addresses are not yet enabled */
|
|
||||||
read1[0] |= 1 << 4;
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_VEC_1, &ports, 1);
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_ADDR_2, addr_be16, 3);
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_VEC_2, &ports, 1);
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_CONF, read1, 1);
|
|
||||||
} else {
|
|
||||||
/* if both multiport addresses are the same we can add */
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_ADDR_1, read1, 3);
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_ADDR_2, read2, 3);
|
|
||||||
if (os_memcmp(read1, read2, 6) != 0)
|
|
||||||
return -1;
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_VEC_1, read1, 1);
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_VEC_2, read2, 1);
|
|
||||||
if (read1[0] != read2[0])
|
|
||||||
return -1;
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_VEC_1, &ports, 1);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_roboswitch_leave(struct wpa_driver_roboswitch_data *drv,
|
|
||||||
u16 ports, const u8 *addr)
|
|
||||||
{
|
|
||||||
u16 _read, addr_be16[3], addr_read[3], ports_read;
|
|
||||||
|
|
||||||
wpa_driver_roboswitch_addr_be16(addr, addr_be16);
|
|
||||||
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_CONF,
|
|
||||||
&_read, 1);
|
|
||||||
/* If ARL control is disabled, there is nothing to leave. */
|
|
||||||
if (!(_read & (1 << 4))) return -1;
|
|
||||||
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_ADDR_1, addr_read, 3);
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_VEC_1,
|
|
||||||
&ports_read, 1);
|
|
||||||
/* check if we occupy multiport address 1 */
|
|
||||||
if (os_memcmp(addr_read, addr_be16, 6) == 0 && ports_read == ports) {
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_ADDR_2, addr_read, 3);
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_VEC_2, &ports_read, 1);
|
|
||||||
/* and multiport address 2 */
|
|
||||||
if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
|
|
||||||
ports_read == ports) {
|
|
||||||
_read &= ~(1 << 4);
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_CONF, &_read,
|
|
||||||
1);
|
|
||||||
} else {
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_ADDR_1,
|
|
||||||
addr_read, 3);
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_VEC_1,
|
|
||||||
&ports_read, 1);
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_ADDR_2,
|
|
||||||
addr_read, 3);
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_VEC_2,
|
|
||||||
&ports_read, 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_ADDR_2, addr_read, 3);
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_VEC_2, &ports_read, 1);
|
|
||||||
/* or multiport address 2 */
|
|
||||||
if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
|
|
||||||
ports_read == ports) {
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_ADDR_1,
|
|
||||||
addr_read, 3);
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
|
||||||
ROBO_ARLCTRL_VEC_1,
|
|
||||||
&ports_read, 1);
|
|
||||||
} else return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname)
|
|
||||||
{
|
|
||||||
struct wpa_driver_roboswitch_data *drv;
|
|
||||||
char *sep;
|
|
||||||
u16 vlan = 0, _read[2];
|
|
||||||
|
|
||||||
drv = os_zalloc(sizeof(*drv));
|
|
||||||
if (drv == NULL) return NULL;
|
|
||||||
drv->ctx = ctx;
|
|
||||||
drv->own_addr[0] = '\0';
|
|
||||||
|
|
||||||
/* copy ifname and take a pointer to the second to last character */
|
|
||||||
sep = drv->ifname +
|
|
||||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)) - 2;
|
|
||||||
/* find the '.' seperating <interface> and <vlan> */
|
|
||||||
while (sep > drv->ifname && *sep != '.') sep--;
|
|
||||||
if (sep <= drv->ifname) {
|
|
||||||
wpa_printf(MSG_INFO, "%s: No <interface>.<vlan> pair in "
|
|
||||||
"interface name %s", __func__, drv->ifname);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*sep = '\0';
|
|
||||||
while (*++sep) {
|
|
||||||
if (*sep < '0' || *sep > '9') {
|
|
||||||
wpa_printf(MSG_INFO, "%s: Invalid vlan specification "
|
|
||||||
"in interface name %s", __func__, ifname);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
vlan *= 10;
|
|
||||||
vlan += *sep - '0';
|
|
||||||
if (vlan > ROBO_VLAN_MAX) {
|
|
||||||
wpa_printf(MSG_INFO, "%s: VLAN out of range in "
|
|
||||||
"interface name %s", __func__, ifname);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
drv->fd = socket(PF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (drv->fd < 0) {
|
|
||||||
wpa_printf(MSG_INFO, "%s: Unable to create socket", __func__);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_memset(&drv->ifr, 0, sizeof(drv->ifr));
|
|
||||||
os_strlcpy(drv->ifr.ifr_name, drv->ifname, IFNAMSIZ);
|
|
||||||
if (ioctl(drv->fd, SIOCGMIIPHY, &drv->ifr) < 0) {
|
|
||||||
perror("ioctl[SIOCGMIIPHY]");
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR) {
|
|
||||||
wpa_printf(MSG_INFO, "%s: Invalid phy address (not a "
|
|
||||||
"RoboSwitch?)", __func__);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set and read back to see if the register can be used */
|
|
||||||
_read[0] = ROBO_VLAN_MAX;
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
|
|
||||||
_read, 1);
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
|
|
||||||
_read + 1, 1);
|
|
||||||
drv->is_5350 = _read[0] == _read[1];
|
|
||||||
|
|
||||||
/* set the read bit */
|
|
||||||
vlan |= 1 << 13;
|
|
||||||
wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE,
|
|
||||||
drv->is_5350 ? ROBO_VLAN_ACCESS_5350
|
|
||||||
: ROBO_VLAN_ACCESS,
|
|
||||||
&vlan, 1);
|
|
||||||
wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_READ, _read,
|
|
||||||
drv->is_5350 ? 2 : 1);
|
|
||||||
if (!(drv->is_5350 ? _read[1] & (1 << 4) : _read[0] & (1 << 14))) {
|
|
||||||
wpa_printf(MSG_INFO, "%s: Could not get port information for "
|
|
||||||
"VLAN %d", __func__, vlan & ~(1 << 13));
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
drv->ports = _read[0] & 0x001F;
|
|
||||||
/* add the MII port */
|
|
||||||
drv->ports |= 1 << 8;
|
|
||||||
if (wpa_driver_roboswitch_join(drv, drv->ports, pae_group_addr) < 0) {
|
|
||||||
wpa_printf(MSG_INFO, "%s: Unable to join PAE group", __func__);
|
|
||||||
os_free(drv);
|
|
||||||
return NULL;
|
|
||||||
} else {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: Added PAE group address to "
|
|
||||||
"RoboSwitch ARL", __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
return drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wpa_driver_roboswitch_deinit(void *priv)
|
|
||||||
{
|
|
||||||
struct wpa_driver_roboswitch_data *drv = priv;
|
|
||||||
|
|
||||||
if (drv->l2) {
|
|
||||||
l2_packet_deinit(drv->l2);
|
|
||||||
drv->l2 = NULL;
|
|
||||||
}
|
|
||||||
if (wpa_driver_roboswitch_leave(drv, drv->ports, pae_group_addr) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: Unable to leave PAE group",
|
|
||||||
__func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
close(drv->fd);
|
|
||||||
os_free(drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const struct wpa_driver_ops wpa_driver_roboswitch_ops = {
|
|
||||||
.name = "roboswitch",
|
|
||||||
.desc = "wpa_supplicant roboswitch driver",
|
|
||||||
.get_ssid = wpa_driver_roboswitch_get_ssid,
|
|
||||||
.get_bssid = wpa_driver_roboswitch_get_bssid,
|
|
||||||
.init = wpa_driver_roboswitch_init,
|
|
||||||
.deinit = wpa_driver_roboswitch_deinit,
|
|
||||||
.set_param = wpa_driver_roboswitch_set_param,
|
|
||||||
.get_ifname = wpa_driver_roboswitch_get_ifname,
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - driver_wext exported functions
|
|
||||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DRIVER_WEXT_H
|
|
||||||
#define DRIVER_WEXT_H
|
|
||||||
|
|
||||||
#include <net/if.h>
|
|
||||||
|
|
||||||
struct wpa_driver_wext_data {
|
|
||||||
void *ctx;
|
|
||||||
int event_sock;
|
|
||||||
int ioctl_sock;
|
|
||||||
int mlme_sock;
|
|
||||||
char ifname[IFNAMSIZ + 1];
|
|
||||||
int ifindex;
|
|
||||||
int ifindex2;
|
|
||||||
int if_removed;
|
|
||||||
u8 *assoc_req_ies;
|
|
||||||
size_t assoc_req_ies_len;
|
|
||||||
u8 *assoc_resp_ies;
|
|
||||||
size_t assoc_resp_ies_len;
|
|
||||||
struct wpa_driver_capa capa;
|
|
||||||
int has_capability;
|
|
||||||
int we_version_compiled;
|
|
||||||
|
|
||||||
/* for set_auth_alg fallback */
|
|
||||||
int use_crypt;
|
|
||||||
int auth_alg_fallback;
|
|
||||||
|
|
||||||
int operstate;
|
|
||||||
|
|
||||||
char mlmedev[IFNAMSIZ + 1];
|
|
||||||
|
|
||||||
int scan_complete_events;
|
|
||||||
};
|
|
||||||
|
|
||||||
int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags);
|
|
||||||
int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags);
|
|
||||||
int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);
|
|
||||||
int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid);
|
|
||||||
int wpa_driver_wext_get_ssid(void *priv, u8 *ssid);
|
|
||||||
int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len);
|
|
||||||
int wpa_driver_wext_set_freq(void *priv, int freq);
|
|
||||||
int wpa_driver_wext_set_mode(void *priv, int mode);
|
|
||||||
int wpa_driver_wext_set_key(void *priv, wpa_alg alg,
|
|
||||||
const u8 *addr, int key_idx,
|
|
||||||
int set_tx, const u8 *seq, size_t seq_len,
|
|
||||||
const u8 *key, size_t key_len);
|
|
||||||
int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len);
|
|
||||||
struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv);
|
|
||||||
|
|
||||||
void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx);
|
|
||||||
|
|
||||||
int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
|
|
||||||
const char *ifname);
|
|
||||||
|
|
||||||
void * wpa_driver_wext_init(void *ctx, const char *ifname);
|
|
||||||
void wpa_driver_wext_deinit(void *priv);
|
|
||||||
|
|
||||||
int wpa_driver_wext_set_operstate(void *priv, int state);
|
|
||||||
int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv);
|
|
||||||
|
|
||||||
int wpa_driver_wext_associate(void *priv,
|
|
||||||
struct wpa_driver_associate_params *params);
|
|
||||||
int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa);
|
|
||||||
int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
|
|
||||||
int idx, u32 value);
|
|
||||||
int wpa_driver_wext_cipher2wext(int cipher);
|
|
||||||
int wpa_driver_wext_keymgmt2wext(int keymgmt);
|
|
||||||
|
|
||||||
#endif /* DRIVER_WEXT_H */
|
|
@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
* wpa_supplicant - Private copy of Linux netlink/rtnetlink definitions.
|
|
||||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PRIV_NETLINK_H
|
|
||||||
#define PRIV_NETLINK_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This should be replaced with user space header once one is available with C
|
|
||||||
* library, etc..
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef IFF_LOWER_UP
|
|
||||||
#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
|
|
||||||
#endif
|
|
||||||
#ifndef IFF_DORMANT
|
|
||||||
#define IFF_DORMANT 0x20000 /* driver signals dormant */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef IFLA_IFNAME
|
|
||||||
#define IFLA_IFNAME 3
|
|
||||||
#endif
|
|
||||||
#ifndef IFLA_WIRELESS
|
|
||||||
#define IFLA_WIRELESS 11
|
|
||||||
#endif
|
|
||||||
#ifndef IFLA_OPERSTATE
|
|
||||||
#define IFLA_OPERSTATE 16
|
|
||||||
#endif
|
|
||||||
#ifndef IFLA_LINKMODE
|
|
||||||
#define IFLA_LINKMODE 17
|
|
||||||
#define IF_OPER_DORMANT 5
|
|
||||||
#define IF_OPER_UP 6
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define NLM_F_REQUEST 1
|
|
||||||
|
|
||||||
#define NETLINK_ROUTE 0
|
|
||||||
#define RTMGRP_LINK 1
|
|
||||||
#define RTM_BASE 0x10
|
|
||||||
#define RTM_NEWLINK (RTM_BASE + 0)
|
|
||||||
#define RTM_DELLINK (RTM_BASE + 1)
|
|
||||||
#define RTM_SETLINK (RTM_BASE + 3)
|
|
||||||
|
|
||||||
#define NLMSG_ALIGNTO 4
|
|
||||||
#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1))
|
|
||||||
#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr)))
|
|
||||||
#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0)))
|
|
||||||
|
|
||||||
#define RTA_ALIGNTO 4
|
|
||||||
#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1))
|
|
||||||
#define RTA_OK(rta,len) \
|
|
||||||
((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
|
|
||||||
(rta)->rta_len <= (len))
|
|
||||||
#define RTA_NEXT(rta,attrlen) \
|
|
||||||
((attrlen) -= RTA_ALIGN((rta)->rta_len), \
|
|
||||||
(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
|
|
||||||
#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
|
|
||||||
#define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0)))
|
|
||||||
|
|
||||||
|
|
||||||
struct sockaddr_nl
|
|
||||||
{
|
|
||||||
sa_family_t nl_family;
|
|
||||||
unsigned short nl_pad;
|
|
||||||
u32 nl_pid;
|
|
||||||
u32 nl_groups;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nlmsghdr
|
|
||||||
{
|
|
||||||
u32 nlmsg_len;
|
|
||||||
u16 nlmsg_type;
|
|
||||||
u16 nlmsg_flags;
|
|
||||||
u32 nlmsg_seq;
|
|
||||||
u32 nlmsg_pid;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ifinfomsg
|
|
||||||
{
|
|
||||||
unsigned char ifi_family;
|
|
||||||
unsigned char __ifi_pad;
|
|
||||||
unsigned short ifi_type;
|
|
||||||
int ifi_index;
|
|
||||||
unsigned ifi_flags;
|
|
||||||
unsigned ifi_change;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rtattr
|
|
||||||
{
|
|
||||||
unsigned short rta_len;
|
|
||||||
unsigned short rta_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* PRIV_NETLINK_H */
|
|
@ -1,200 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - Layer2 packet handling with Linux packet sockets
|
|
||||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <netpacket/packet.h>
|
|
||||||
#include <net/if.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "eloop.h"
|
|
||||||
#include "l2_packet.h"
|
|
||||||
|
|
||||||
|
|
||||||
struct l2_packet_data {
|
|
||||||
int fd; /* packet socket for EAPOL frames */
|
|
||||||
char ifname[IFNAMSIZ + 1];
|
|
||||||
int ifindex;
|
|
||||||
u8 own_addr[ETH_ALEN];
|
|
||||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
|
||||||
const u8 *buf, size_t len);
|
|
||||||
void *rx_callback_ctx;
|
|
||||||
int l2_hdr; /* whether to include layer 2 (Ethernet) header data
|
|
||||||
* buffers */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
|
|
||||||
{
|
|
||||||
os_memcpy(addr, l2->own_addr, ETH_ALEN);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
|
|
||||||
const u8 *buf, size_t len)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
if (l2 == NULL)
|
|
||||||
return -1;
|
|
||||||
if (l2->l2_hdr) {
|
|
||||||
ret = send(l2->fd, buf, len, 0);
|
|
||||||
if (ret < 0)
|
|
||||||
perror("l2_packet_send - send");
|
|
||||||
} else {
|
|
||||||
struct sockaddr_ll ll;
|
|
||||||
os_memset(&ll, 0, sizeof(ll));
|
|
||||||
ll.sll_family = AF_PACKET;
|
|
||||||
ll.sll_ifindex = l2->ifindex;
|
|
||||||
ll.sll_protocol = htons(proto);
|
|
||||||
ll.sll_halen = ETH_ALEN;
|
|
||||||
os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN);
|
|
||||||
ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll,
|
|
||||||
sizeof(ll));
|
|
||||||
if (ret < 0)
|
|
||||||
perror("l2_packet_send - sendto");
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
|
||||||
{
|
|
||||||
struct l2_packet_data *l2 = eloop_ctx;
|
|
||||||
u8 buf[2300];
|
|
||||||
int res;
|
|
||||||
struct sockaddr_ll ll;
|
|
||||||
socklen_t fromlen;
|
|
||||||
|
|
||||||
os_memset(&ll, 0, sizeof(ll));
|
|
||||||
fromlen = sizeof(ll);
|
|
||||||
res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
|
|
||||||
&fromlen);
|
|
||||||
if (res < 0) {
|
|
||||||
perror("l2_packet_receive - recvfrom");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct l2_packet_data * l2_packet_init(
|
|
||||||
const char *ifname, const u8 *own_addr, unsigned short protocol,
|
|
||||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
|
||||||
const u8 *buf, size_t len),
|
|
||||||
void *rx_callback_ctx, int l2_hdr)
|
|
||||||
{
|
|
||||||
struct l2_packet_data *l2;
|
|
||||||
struct ifreq ifr;
|
|
||||||
struct sockaddr_ll ll;
|
|
||||||
|
|
||||||
l2 = os_zalloc(sizeof(struct l2_packet_data));
|
|
||||||
if (l2 == NULL)
|
|
||||||
return NULL;
|
|
||||||
os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
|
|
||||||
l2->rx_callback = rx_callback;
|
|
||||||
l2->rx_callback_ctx = rx_callback_ctx;
|
|
||||||
l2->l2_hdr = l2_hdr;
|
|
||||||
|
|
||||||
l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
|
|
||||||
htons(protocol));
|
|
||||||
if (l2->fd < 0) {
|
|
||||||
perror("socket(PF_PACKET)");
|
|
||||||
os_free(l2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
os_memset(&ifr, 0, sizeof(ifr));
|
|
||||||
os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
|
|
||||||
if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) {
|
|
||||||
perror("ioctl[SIOCGIFINDEX]");
|
|
||||||
close(l2->fd);
|
|
||||||
os_free(l2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
l2->ifindex = ifr.ifr_ifindex;
|
|
||||||
|
|
||||||
os_memset(&ll, 0, sizeof(ll));
|
|
||||||
ll.sll_family = PF_PACKET;
|
|
||||||
ll.sll_ifindex = ifr.ifr_ifindex;
|
|
||||||
ll.sll_protocol = htons(protocol);
|
|
||||||
if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
|
|
||||||
perror("bind[PF_PACKET]");
|
|
||||||
close(l2->fd);
|
|
||||||
os_free(l2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioctl(l2->fd, SIOCGIFHWADDR, &ifr) < 0) {
|
|
||||||
perror("ioctl[SIOCGIFHWADDR]");
|
|
||||||
close(l2->fd);
|
|
||||||
os_free(l2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
os_memcpy(l2->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
|
|
||||||
|
|
||||||
eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
|
|
||||||
|
|
||||||
return l2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void l2_packet_deinit(struct l2_packet_data *l2)
|
|
||||||
{
|
|
||||||
if (l2 == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (l2->fd >= 0) {
|
|
||||||
eloop_unregister_read_sock(l2->fd);
|
|
||||||
close(l2->fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
os_free(l2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
|
|
||||||
{
|
|
||||||
int s;
|
|
||||||
struct ifreq ifr;
|
|
||||||
struct sockaddr_in *saddr;
|
|
||||||
size_t res;
|
|
||||||
|
|
||||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (s < 0) {
|
|
||||||
perror("socket");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
os_memset(&ifr, 0, sizeof(ifr));
|
|
||||||
os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
|
|
||||||
if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
|
|
||||||
if (errno != EADDRNOTAVAIL)
|
|
||||||
perror("ioctl[SIOCGIFADDR]");
|
|
||||||
close(s);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
close(s);
|
|
||||||
saddr = aliasing_hide_typecast(&ifr.ifr_addr, struct sockaddr_in);
|
|
||||||
if (saddr->sin_family != AF_INET)
|
|
||||||
return -1;
|
|
||||||
res = os_strlcpy(buf, inet_ntoa(saddr->sin_addr), len);
|
|
||||||
if (res >= len)
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void l2_packet_notify_auth_start(struct l2_packet_data *l2)
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,386 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - Layer2 packet handling with libpcap/libdnet and WinPcap
|
|
||||||
* Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#ifndef CONFIG_NATIVE_WINDOWS
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
|
||||||
#include <pcap.h>
|
|
||||||
#ifndef CONFIG_WINPCAP
|
|
||||||
#include <dnet.h>
|
|
||||||
#endif /* CONFIG_WINPCAP */
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "eloop.h"
|
|
||||||
#include "l2_packet.h"
|
|
||||||
|
|
||||||
|
|
||||||
static const u8 pae_group_addr[ETH_ALEN] =
|
|
||||||
{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
|
|
||||||
|
|
||||||
struct l2_packet_data {
|
|
||||||
pcap_t *pcap;
|
|
||||||
#ifdef CONFIG_WINPCAP
|
|
||||||
unsigned int num_fast_poll;
|
|
||||||
#else /* CONFIG_WINPCAP */
|
|
||||||
eth_t *eth;
|
|
||||||
#endif /* CONFIG_WINPCAP */
|
|
||||||
char ifname[100];
|
|
||||||
u8 own_addr[ETH_ALEN];
|
|
||||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
|
||||||
const u8 *buf, size_t len);
|
|
||||||
void *rx_callback_ctx;
|
|
||||||
int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls
|
|
||||||
* to rx_callback */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
|
|
||||||
{
|
|
||||||
os_memcpy(addr, l2->own_addr, ETH_ALEN);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CONFIG_WINPCAP
|
|
||||||
static int l2_packet_init_libdnet(struct l2_packet_data *l2)
|
|
||||||
{
|
|
||||||
eth_addr_t own_addr;
|
|
||||||
|
|
||||||
l2->eth = eth_open(l2->ifname);
|
|
||||||
if (!l2->eth) {
|
|
||||||
printf("Failed to open interface '%s'.\n", l2->ifname);
|
|
||||||
perror("eth_open");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eth_get(l2->eth, &own_addr) < 0) {
|
|
||||||
printf("Failed to get own hw address from interface '%s'.\n",
|
|
||||||
l2->ifname);
|
|
||||||
perror("eth_get");
|
|
||||||
eth_close(l2->eth);
|
|
||||||
l2->eth = NULL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
os_memcpy(l2->own_addr, own_addr.data, ETH_ALEN);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_WINPCAP */
|
|
||||||
|
|
||||||
|
|
||||||
int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
|
|
||||||
const u8 *buf, size_t len)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct l2_ethhdr *eth;
|
|
||||||
|
|
||||||
if (l2 == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (l2->l2_hdr) {
|
|
||||||
#ifdef CONFIG_WINPCAP
|
|
||||||
ret = pcap_sendpacket(l2->pcap, buf, len);
|
|
||||||
#else /* CONFIG_WINPCAP */
|
|
||||||
ret = eth_send(l2->eth, buf, len);
|
|
||||||
#endif /* CONFIG_WINPCAP */
|
|
||||||
} else {
|
|
||||||
size_t mlen = sizeof(*eth) + len;
|
|
||||||
eth = os_malloc(mlen);
|
|
||||||
if (eth == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
|
|
||||||
os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
|
|
||||||
eth->h_proto = htons(proto);
|
|
||||||
os_memcpy(eth + 1, buf, len);
|
|
||||||
|
|
||||||
#ifdef CONFIG_WINPCAP
|
|
||||||
ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen);
|
|
||||||
#else /* CONFIG_WINPCAP */
|
|
||||||
ret = eth_send(l2->eth, (u8 *) eth, mlen);
|
|
||||||
#endif /* CONFIG_WINPCAP */
|
|
||||||
|
|
||||||
os_free(eth);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CONFIG_WINPCAP
|
|
||||||
static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
|
||||||
{
|
|
||||||
struct l2_packet_data *l2 = eloop_ctx;
|
|
||||||
pcap_t *pcap = sock_ctx;
|
|
||||||
struct pcap_pkthdr hdr;
|
|
||||||
const u_char *packet;
|
|
||||||
struct l2_ethhdr *ethhdr;
|
|
||||||
unsigned char *buf;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
packet = pcap_next(pcap, &hdr);
|
|
||||||
|
|
||||||
if (packet == NULL || hdr.caplen < sizeof(*ethhdr))
|
|
||||||
return;
|
|
||||||
|
|
||||||
ethhdr = (struct l2_ethhdr *) packet;
|
|
||||||
if (l2->l2_hdr) {
|
|
||||||
buf = (unsigned char *) ethhdr;
|
|
||||||
len = hdr.caplen;
|
|
||||||
} else {
|
|
||||||
buf = (unsigned char *) (ethhdr + 1);
|
|
||||||
len = hdr.caplen - sizeof(*ethhdr);
|
|
||||||
}
|
|
||||||
l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_WINPCAP */
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_WINPCAP
|
|
||||||
static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr,
|
|
||||||
const u_char *pkt_data)
|
|
||||||
{
|
|
||||||
struct l2_packet_data *l2 = (struct l2_packet_data *) user;
|
|
||||||
struct l2_ethhdr *ethhdr;
|
|
||||||
unsigned char *buf;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr))
|
|
||||||
return;
|
|
||||||
|
|
||||||
ethhdr = (struct l2_ethhdr *) pkt_data;
|
|
||||||
if (l2->l2_hdr) {
|
|
||||||
buf = (unsigned char *) ethhdr;
|
|
||||||
len = hdr->caplen;
|
|
||||||
} else {
|
|
||||||
buf = (unsigned char *) (ethhdr + 1);
|
|
||||||
len = hdr->caplen - sizeof(*ethhdr);
|
|
||||||
}
|
|
||||||
l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
|
|
||||||
/*
|
|
||||||
* Use shorter poll interval for 3 seconds to reduce latency during key
|
|
||||||
* handshake.
|
|
||||||
*/
|
|
||||||
l2->num_fast_poll = 3 * 50;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void l2_packet_receive_timeout(void *eloop_ctx, void *timeout_ctx)
|
|
||||||
{
|
|
||||||
struct l2_packet_data *l2 = eloop_ctx;
|
|
||||||
pcap_t *pcap = timeout_ctx;
|
|
||||||
int timeout;
|
|
||||||
|
|
||||||
if (l2->num_fast_poll > 0) {
|
|
||||||
timeout = 20000;
|
|
||||||
l2->num_fast_poll--;
|
|
||||||
} else
|
|
||||||
timeout = 100000;
|
|
||||||
|
|
||||||
/* Register new timeout before calling l2_packet_receive() since
|
|
||||||
* receive handler may free this l2_packet instance (which will
|
|
||||||
* cancel this timeout). */
|
|
||||||
eloop_register_timeout(0, timeout, l2_packet_receive_timeout,
|
|
||||||
l2, pcap);
|
|
||||||
pcap_dispatch(pcap, 10, l2_packet_receive_cb, (u_char *) l2);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_WINPCAP */
|
|
||||||
|
|
||||||
|
|
||||||
static int l2_packet_init_libpcap(struct l2_packet_data *l2,
|
|
||||||
unsigned short protocol)
|
|
||||||
{
|
|
||||||
bpf_u_int32 pcap_maskp, pcap_netp;
|
|
||||||
char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
|
|
||||||
struct bpf_program pcap_fp;
|
|
||||||
|
|
||||||
#ifdef CONFIG_WINPCAP
|
|
||||||
char ifname[128];
|
|
||||||
os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", l2->ifname);
|
|
||||||
pcap_lookupnet(ifname, &pcap_netp, &pcap_maskp, pcap_err);
|
|
||||||
l2->pcap = pcap_open_live(ifname, 2500, 0, 10, pcap_err);
|
|
||||||
if (l2->pcap == NULL) {
|
|
||||||
fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
|
|
||||||
fprintf(stderr, "ifname='%s'\n", ifname);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (pcap_setnonblock(l2->pcap, 1, pcap_err) < 0)
|
|
||||||
fprintf(stderr, "pcap_setnonblock: %s\n",
|
|
||||||
pcap_geterr(l2->pcap));
|
|
||||||
#else /* CONFIG_WINPCAP */
|
|
||||||
pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
|
|
||||||
l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 10, pcap_err);
|
|
||||||
if (l2->pcap == NULL) {
|
|
||||||
fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
|
|
||||||
fprintf(stderr, "ifname='%s'\n", l2->ifname);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (pcap_datalink(l2->pcap) != DLT_EN10MB &&
|
|
||||||
pcap_set_datalink(l2->pcap, DLT_EN10MB) < 0) {
|
|
||||||
fprintf(stderr, "pcap_set_datalink(DLT_EN10MB): %s\n",
|
|
||||||
pcap_geterr(l2->pcap));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_WINPCAP */
|
|
||||||
os_snprintf(pcap_filter, sizeof(pcap_filter),
|
|
||||||
"not ether src " MACSTR " and "
|
|
||||||
"( ether dst " MACSTR " or ether dst " MACSTR " ) and "
|
|
||||||
"ether proto 0x%x",
|
|
||||||
MAC2STR(l2->own_addr), /* do not receive own packets */
|
|
||||||
MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
|
|
||||||
protocol);
|
|
||||||
if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
|
|
||||||
fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
|
|
||||||
fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pcap_freecode(&pcap_fp);
|
|
||||||
#ifdef BIOCIMMEDIATE
|
|
||||||
/*
|
|
||||||
* When libpcap uses BPF we must enable "immediate mode" to
|
|
||||||
* receive frames right away; otherwise the system may
|
|
||||||
* buffer them for us.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
unsigned int on = 1;
|
|
||||||
if (ioctl(pcap_fileno(l2->pcap), BIOCIMMEDIATE, &on) < 0) {
|
|
||||||
fprintf(stderr, "%s: cannot enable immediate mode on "
|
|
||||||
"interface %s: %s\n",
|
|
||||||
__func__, l2->ifname, strerror(errno));
|
|
||||||
/* XXX should we fail? */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* BIOCIMMEDIATE */
|
|
||||||
|
|
||||||
#ifdef CONFIG_WINPCAP
|
|
||||||
eloop_register_timeout(0, 100000, l2_packet_receive_timeout,
|
|
||||||
l2, l2->pcap);
|
|
||||||
#else /* CONFIG_WINPCAP */
|
|
||||||
eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap),
|
|
||||||
l2_packet_receive, l2, l2->pcap);
|
|
||||||
#endif /* CONFIG_WINPCAP */
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct l2_packet_data * l2_packet_init(
|
|
||||||
const char *ifname, const u8 *own_addr, unsigned short protocol,
|
|
||||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
|
||||||
const u8 *buf, size_t len),
|
|
||||||
void *rx_callback_ctx, int l2_hdr)
|
|
||||||
{
|
|
||||||
struct l2_packet_data *l2;
|
|
||||||
|
|
||||||
l2 = os_zalloc(sizeof(struct l2_packet_data));
|
|
||||||
if (l2 == NULL)
|
|
||||||
return NULL;
|
|
||||||
os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
|
|
||||||
l2->rx_callback = rx_callback;
|
|
||||||
l2->rx_callback_ctx = rx_callback_ctx;
|
|
||||||
l2->l2_hdr = l2_hdr;
|
|
||||||
|
|
||||||
#ifdef CONFIG_WINPCAP
|
|
||||||
if (own_addr)
|
|
||||||
os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
|
|
||||||
#else /* CONFIG_WINPCAP */
|
|
||||||
if (l2_packet_init_libdnet(l2))
|
|
||||||
return NULL;
|
|
||||||
#endif /* CONFIG_WINPCAP */
|
|
||||||
|
|
||||||
if (l2_packet_init_libpcap(l2, protocol)) {
|
|
||||||
#ifndef CONFIG_WINPCAP
|
|
||||||
eth_close(l2->eth);
|
|
||||||
#endif /* CONFIG_WINPCAP */
|
|
||||||
os_free(l2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return l2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void l2_packet_deinit(struct l2_packet_data *l2)
|
|
||||||
{
|
|
||||||
if (l2 == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
#ifdef CONFIG_WINPCAP
|
|
||||||
eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap);
|
|
||||||
#else /* CONFIG_WINPCAP */
|
|
||||||
if (l2->eth)
|
|
||||||
eth_close(l2->eth);
|
|
||||||
eloop_unregister_read_sock(pcap_get_selectable_fd(l2->pcap));
|
|
||||||
#endif /* CONFIG_WINPCAP */
|
|
||||||
if (l2->pcap)
|
|
||||||
pcap_close(l2->pcap);
|
|
||||||
os_free(l2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
|
|
||||||
{
|
|
||||||
pcap_if_t *devs, *dev;
|
|
||||||
struct pcap_addr *addr;
|
|
||||||
struct sockaddr_in *saddr;
|
|
||||||
int found = 0;
|
|
||||||
char err[PCAP_ERRBUF_SIZE + 1];
|
|
||||||
|
|
||||||
if (pcap_findalldevs(&devs, err) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (dev = devs; dev && !found; dev = dev->next) {
|
|
||||||
if (os_strcmp(dev->name, l2->ifname) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
addr = dev->addresses;
|
|
||||||
while (addr) {
|
|
||||||
saddr = (struct sockaddr_in *) addr->addr;
|
|
||||||
if (saddr && saddr->sin_family == AF_INET) {
|
|
||||||
os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
|
|
||||||
len);
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
addr = addr->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pcap_freealldevs(devs);
|
|
||||||
|
|
||||||
return found ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void l2_packet_notify_auth_start(struct l2_packet_data *l2)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_WINPCAP
|
|
||||||
/*
|
|
||||||
* Use shorter poll interval for 3 seconds to reduce latency during key
|
|
||||||
* handshake.
|
|
||||||
*/
|
|
||||||
l2->num_fast_poll = 3 * 50;
|
|
||||||
eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap);
|
|
||||||
eloop_register_timeout(0, 10000, l2_packet_receive_timeout,
|
|
||||||
l2, l2->pcap);
|
|
||||||
#endif /* CONFIG_WINPCAP */
|
|
||||||
}
|
|
@ -1,267 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - Layer2 packet handling with privilege separation
|
|
||||||
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#include <sys/un.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "eloop.h"
|
|
||||||
#include "l2_packet.h"
|
|
||||||
#include "privsep_commands.h"
|
|
||||||
|
|
||||||
|
|
||||||
struct l2_packet_data {
|
|
||||||
int fd; /* UNIX domain socket for privsep access */
|
|
||||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
|
||||||
const u8 *buf, size_t len);
|
|
||||||
void *rx_callback_ctx;
|
|
||||||
u8 own_addr[ETH_ALEN];
|
|
||||||
char *own_socket_path;
|
|
||||||
struct sockaddr_un priv_addr;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static int wpa_priv_cmd(struct l2_packet_data *l2, int cmd,
|
|
||||||
const void *data, size_t data_len)
|
|
||||||
{
|
|
||||||
struct msghdr msg;
|
|
||||||
struct iovec io[2];
|
|
||||||
|
|
||||||
io[0].iov_base = &cmd;
|
|
||||||
io[0].iov_len = sizeof(cmd);
|
|
||||||
io[1].iov_base = (u8 *) data;
|
|
||||||
io[1].iov_len = data_len;
|
|
||||||
|
|
||||||
os_memset(&msg, 0, sizeof(msg));
|
|
||||||
msg.msg_iov = io;
|
|
||||||
msg.msg_iovlen = data ? 2 : 1;
|
|
||||||
msg.msg_name = &l2->priv_addr;
|
|
||||||
msg.msg_namelen = sizeof(l2->priv_addr);
|
|
||||||
|
|
||||||
if (sendmsg(l2->fd, &msg, 0) < 0) {
|
|
||||||
perror("L2: sendmsg(cmd)");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
|
|
||||||
{
|
|
||||||
os_memcpy(addr, l2->own_addr, ETH_ALEN);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
|
|
||||||
const u8 *buf, size_t len)
|
|
||||||
{
|
|
||||||
struct msghdr msg;
|
|
||||||
struct iovec io[4];
|
|
||||||
int cmd = PRIVSEP_CMD_L2_SEND;
|
|
||||||
|
|
||||||
io[0].iov_base = &cmd;
|
|
||||||
io[0].iov_len = sizeof(cmd);
|
|
||||||
io[1].iov_base = &dst_addr;
|
|
||||||
io[1].iov_len = ETH_ALEN;
|
|
||||||
io[2].iov_base = &proto;
|
|
||||||
io[2].iov_len = 2;
|
|
||||||
io[3].iov_base = (u8 *) buf;
|
|
||||||
io[3].iov_len = len;
|
|
||||||
|
|
||||||
os_memset(&msg, 0, sizeof(msg));
|
|
||||||
msg.msg_iov = io;
|
|
||||||
msg.msg_iovlen = 4;
|
|
||||||
msg.msg_name = &l2->priv_addr;
|
|
||||||
msg.msg_namelen = sizeof(l2->priv_addr);
|
|
||||||
|
|
||||||
if (sendmsg(l2->fd, &msg, 0) < 0) {
|
|
||||||
perror("L2: sendmsg(packet_send)");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
|
||||||
{
|
|
||||||
struct l2_packet_data *l2 = eloop_ctx;
|
|
||||||
u8 buf[2300];
|
|
||||||
int res;
|
|
||||||
struct sockaddr_un from;
|
|
||||||
socklen_t fromlen = sizeof(from);
|
|
||||||
|
|
||||||
os_memset(&from, 0, sizeof(from));
|
|
||||||
res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
|
|
||||||
&fromlen);
|
|
||||||
if (res < 0) {
|
|
||||||
perror("l2_packet_receive - recvfrom");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (res < ETH_ALEN) {
|
|
||||||
wpa_printf(MSG_DEBUG, "L2: Too show packet received");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (from.sun_family != AF_UNIX ||
|
|
||||||
os_strncmp(from.sun_path, l2->priv_addr.sun_path,
|
|
||||||
sizeof(from.sun_path)) != 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "L2: Received message from unexpected "
|
|
||||||
"source");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
l2->rx_callback(l2->rx_callback_ctx, buf, buf + ETH_ALEN,
|
|
||||||
res - ETH_ALEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct l2_packet_data * l2_packet_init(
|
|
||||||
const char *ifname, const u8 *own_addr, unsigned short protocol,
|
|
||||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
|
||||||
const u8 *buf, size_t len),
|
|
||||||
void *rx_callback_ctx, int l2_hdr)
|
|
||||||
{
|
|
||||||
struct l2_packet_data *l2;
|
|
||||||
char *own_dir = "/tmp";
|
|
||||||
char *priv_dir = "/var/run/wpa_priv";
|
|
||||||
size_t len;
|
|
||||||
static unsigned int counter = 0;
|
|
||||||
struct sockaddr_un addr;
|
|
||||||
fd_set rfds;
|
|
||||||
struct timeval tv;
|
|
||||||
int res;
|
|
||||||
u8 reply[ETH_ALEN + 1];
|
|
||||||
int reg_cmd[2];
|
|
||||||
|
|
||||||
l2 = os_zalloc(sizeof(struct l2_packet_data));
|
|
||||||
if (l2 == NULL)
|
|
||||||
return NULL;
|
|
||||||
l2->rx_callback = rx_callback;
|
|
||||||
l2->rx_callback_ctx = rx_callback_ctx;
|
|
||||||
|
|
||||||
len = os_strlen(own_dir) + 50;
|
|
||||||
l2->own_socket_path = os_malloc(len);
|
|
||||||
if (l2->own_socket_path == NULL) {
|
|
||||||
os_free(l2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
os_snprintf(l2->own_socket_path, len, "%s/wpa_privsep-l2-%d-%d",
|
|
||||||
own_dir, getpid(), counter++);
|
|
||||||
|
|
||||||
l2->priv_addr.sun_family = AF_UNIX;
|
|
||||||
os_snprintf(l2->priv_addr.sun_path, sizeof(l2->priv_addr.sun_path),
|
|
||||||
"%s/%s", priv_dir, ifname);
|
|
||||||
|
|
||||||
l2->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
|
|
||||||
if (l2->fd < 0) {
|
|
||||||
perror("socket(PF_UNIX)");
|
|
||||||
os_free(l2->own_socket_path);
|
|
||||||
l2->own_socket_path = NULL;
|
|
||||||
os_free(l2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_memset(&addr, 0, sizeof(addr));
|
|
||||||
addr.sun_family = AF_UNIX;
|
|
||||||
os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path));
|
|
||||||
if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
|
||||||
perror("bind(PF_UNIX)");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
reg_cmd[0] = protocol;
|
|
||||||
reg_cmd[1] = l2_hdr;
|
|
||||||
if (wpa_priv_cmd(l2, PRIVSEP_CMD_L2_REGISTER, reg_cmd, sizeof(reg_cmd))
|
|
||||||
< 0) {
|
|
||||||
wpa_printf(MSG_ERROR, "L2: Failed to register with wpa_priv");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
|
||||||
FD_SET(l2->fd, &rfds);
|
|
||||||
tv.tv_sec = 5;
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
res = select(l2->fd + 1, &rfds, NULL, NULL, &tv);
|
|
||||||
if (res < 0 && errno != EINTR) {
|
|
||||||
perror("select");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FD_ISSET(l2->fd, &rfds)) {
|
|
||||||
res = recv(l2->fd, reply, sizeof(reply), 0);
|
|
||||||
if (res < 0) {
|
|
||||||
perror("recv");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
wpa_printf(MSG_DEBUG, "L2: Timeout while waiting for "
|
|
||||||
"registration reply");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res != ETH_ALEN) {
|
|
||||||
wpa_printf(MSG_DEBUG, "L2: Unexpected registration reply "
|
|
||||||
"(len=%d)", res);
|
|
||||||
}
|
|
||||||
os_memcpy(l2->own_addr, reply, ETH_ALEN);
|
|
||||||
|
|
||||||
eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
|
|
||||||
|
|
||||||
return l2;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
close(l2->fd);
|
|
||||||
l2->fd = -1;
|
|
||||||
unlink(l2->own_socket_path);
|
|
||||||
os_free(l2->own_socket_path);
|
|
||||||
l2->own_socket_path = NULL;
|
|
||||||
os_free(l2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void l2_packet_deinit(struct l2_packet_data *l2)
|
|
||||||
{
|
|
||||||
if (l2 == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (l2->fd >= 0) {
|
|
||||||
wpa_priv_cmd(l2, PRIVSEP_CMD_L2_UNREGISTER, NULL, 0);
|
|
||||||
eloop_unregister_read_sock(l2->fd);
|
|
||||||
close(l2->fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (l2->own_socket_path) {
|
|
||||||
unlink(l2->own_socket_path);
|
|
||||||
os_free(l2->own_socket_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
os_free(l2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
|
|
||||||
{
|
|
||||||
/* TODO */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void l2_packet_notify_auth_start(struct l2_packet_data *l2)
|
|
||||||
{
|
|
||||||
wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0);
|
|
||||||
}
|
|
@ -1,341 +0,0 @@
|
|||||||
/*
|
|
||||||
* WPA Supplicant - Layer2 packet handling with WinPcap RX thread
|
|
||||||
* Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Alternatively, this software may be distributed under the terms of BSD
|
|
||||||
* license.
|
|
||||||
*
|
|
||||||
* See README and COPYING for more details.
|
|
||||||
*
|
|
||||||
* This l2_packet implementation is explicitly for WinPcap and Windows events.
|
|
||||||
* l2_packet_pcap.c has support for WinPcap, but it requires polling to receive
|
|
||||||
* frames which means relatively long latency for EAPOL RX processing. The
|
|
||||||
* implementation here uses a separate thread to allow WinPcap to be receiving
|
|
||||||
* all the time to reduce latency for EAPOL receiving from about 100 ms to 3 ms
|
|
||||||
* when comparing l2_packet_pcap.c to l2_packet_winpcap.c. Extra sleep of 50 ms
|
|
||||||
* is added in to receive thread whenever no EAPOL frames has been received for
|
|
||||||
* a while. Whenever an EAPOL handshake is expected, this sleep is removed.
|
|
||||||
*
|
|
||||||
* The RX thread receives a frame and signals main thread through Windows event
|
|
||||||
* about the availability of a new frame. Processing the received frame is
|
|
||||||
* synchronized with pair of Windows events so that no extra buffer or queuing
|
|
||||||
* mechanism is needed. This implementation requires Windows specific event
|
|
||||||
* loop implementation, i.e., eloop_win.c.
|
|
||||||
*
|
|
||||||
* WinPcap has pcap_getevent() that could, in theory at least, be used to
|
|
||||||
* implement this kind of waiting with a simpler single-thread design. However,
|
|
||||||
* that event handle is not really signaled immediately when receiving each
|
|
||||||
* frame, so it does not really work for this kind of use.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
#include <pcap.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "eloop.h"
|
|
||||||
#include "l2_packet.h"
|
|
||||||
|
|
||||||
|
|
||||||
static const u8 pae_group_addr[ETH_ALEN] =
|
|
||||||
{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Number of pcap_dispatch() iterations to do without extra wait after each
|
|
||||||
* received EAPOL packet or authentication notification. This is used to reduce
|
|
||||||
* latency for EAPOL receive.
|
|
||||||
*/
|
|
||||||
static const size_t no_wait_count = 750;
|
|
||||||
|
|
||||||
struct l2_packet_data {
|
|
||||||
pcap_t *pcap;
|
|
||||||
unsigned int num_fast_poll;
|
|
||||||
char ifname[100];
|
|
||||||
u8 own_addr[ETH_ALEN];
|
|
||||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
|
||||||
const u8 *buf, size_t len);
|
|
||||||
void *rx_callback_ctx;
|
|
||||||
int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to
|
|
||||||
* rx_callback and l2_packet_send() */
|
|
||||||
int running;
|
|
||||||
HANDLE rx_avail, rx_done, rx_thread, rx_thread_done, rx_notify;
|
|
||||||
u8 *rx_buf, *rx_src;
|
|
||||||
size_t rx_len;
|
|
||||||
size_t rx_no_wait;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
|
|
||||||
{
|
|
||||||
os_memcpy(addr, l2->own_addr, ETH_ALEN);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
|
|
||||||
const u8 *buf, size_t len)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct l2_ethhdr *eth;
|
|
||||||
|
|
||||||
if (l2 == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (l2->l2_hdr) {
|
|
||||||
ret = pcap_sendpacket(l2->pcap, buf, len);
|
|
||||||
} else {
|
|
||||||
size_t mlen = sizeof(*eth) + len;
|
|
||||||
eth = os_malloc(mlen);
|
|
||||||
if (eth == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
|
|
||||||
os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
|
|
||||||
eth->h_proto = htons(proto);
|
|
||||||
os_memcpy(eth + 1, buf, len);
|
|
||||||
ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen);
|
|
||||||
os_free(eth);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* pcap_dispatch() callback for the RX thread */
|
|
||||||
static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr,
|
|
||||||
const u_char *pkt_data)
|
|
||||||
{
|
|
||||||
struct l2_packet_data *l2 = (struct l2_packet_data *) user;
|
|
||||||
struct l2_ethhdr *ethhdr;
|
|
||||||
|
|
||||||
if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr))
|
|
||||||
return;
|
|
||||||
|
|
||||||
ethhdr = (struct l2_ethhdr *) pkt_data;
|
|
||||||
if (l2->l2_hdr) {
|
|
||||||
l2->rx_buf = (u8 *) ethhdr;
|
|
||||||
l2->rx_len = hdr->caplen;
|
|
||||||
} else {
|
|
||||||
l2->rx_buf = (u8 *) (ethhdr + 1);
|
|
||||||
l2->rx_len = hdr->caplen - sizeof(*ethhdr);
|
|
||||||
}
|
|
||||||
l2->rx_src = ethhdr->h_source;
|
|
||||||
SetEvent(l2->rx_avail);
|
|
||||||
WaitForSingleObject(l2->rx_done, INFINITE);
|
|
||||||
ResetEvent(l2->rx_done);
|
|
||||||
l2->rx_no_wait = no_wait_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* main RX loop that is running in a separate thread */
|
|
||||||
static DWORD WINAPI l2_packet_receive_thread(LPVOID arg)
|
|
||||||
{
|
|
||||||
struct l2_packet_data *l2 = arg;
|
|
||||||
|
|
||||||
while (l2->running) {
|
|
||||||
pcap_dispatch(l2->pcap, 1, l2_packet_receive_cb,
|
|
||||||
(u_char *) l2);
|
|
||||||
if (l2->rx_no_wait > 0)
|
|
||||||
l2->rx_no_wait--;
|
|
||||||
if (WaitForSingleObject(l2->rx_notify,
|
|
||||||
l2->rx_no_wait ? 0 : 50) ==
|
|
||||||
WAIT_OBJECT_0) {
|
|
||||||
l2->rx_no_wait = no_wait_count;
|
|
||||||
ResetEvent(l2->rx_notify);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SetEvent(l2->rx_thread_done);
|
|
||||||
ExitThread(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* main thread RX event handler */
|
|
||||||
static void l2_packet_rx_event(void *eloop_data, void *user_data)
|
|
||||||
{
|
|
||||||
struct l2_packet_data *l2 = eloop_data;
|
|
||||||
l2->rx_callback(l2->rx_callback_ctx, l2->rx_src, l2->rx_buf,
|
|
||||||
l2->rx_len);
|
|
||||||
ResetEvent(l2->rx_avail);
|
|
||||||
SetEvent(l2->rx_done);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int l2_packet_init_libpcap(struct l2_packet_data *l2,
|
|
||||||
unsigned short protocol)
|
|
||||||
{
|
|
||||||
bpf_u_int32 pcap_maskp, pcap_netp;
|
|
||||||
char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
|
|
||||||
struct bpf_program pcap_fp;
|
|
||||||
|
|
||||||
pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
|
|
||||||
l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 1, pcap_err);
|
|
||||||
if (l2->pcap == NULL) {
|
|
||||||
fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
|
|
||||||
fprintf(stderr, "ifname='%s'\n", l2->ifname);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
os_snprintf(pcap_filter, sizeof(pcap_filter),
|
|
||||||
"not ether src " MACSTR " and "
|
|
||||||
"( ether dst " MACSTR " or ether dst " MACSTR " ) and "
|
|
||||||
"ether proto 0x%x",
|
|
||||||
MAC2STR(l2->own_addr), /* do not receive own packets */
|
|
||||||
MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
|
|
||||||
protocol);
|
|
||||||
if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
|
|
||||||
fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
|
|
||||||
fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pcap_freecode(&pcap_fp);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct l2_packet_data * l2_packet_init(
|
|
||||||
const char *ifname, const u8 *own_addr, unsigned short protocol,
|
|
||||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
|
||||||
const u8 *buf, size_t len),
|
|
||||||
void *rx_callback_ctx, int l2_hdr)
|
|
||||||
{
|
|
||||||
struct l2_packet_data *l2;
|
|
||||||
DWORD thread_id;
|
|
||||||
|
|
||||||
l2 = os_zalloc(sizeof(struct l2_packet_data));
|
|
||||||
if (l2 == NULL)
|
|
||||||
return NULL;
|
|
||||||
if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0)
|
|
||||||
os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
|
|
||||||
else
|
|
||||||
os_snprintf(l2->ifname, sizeof(l2->ifname), "\\Device\\NPF_%s",
|
|
||||||
ifname);
|
|
||||||
l2->rx_callback = rx_callback;
|
|
||||||
l2->rx_callback_ctx = rx_callback_ctx;
|
|
||||||
l2->l2_hdr = l2_hdr;
|
|
||||||
|
|
||||||
if (own_addr)
|
|
||||||
os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
|
|
||||||
|
|
||||||
if (l2_packet_init_libpcap(l2, protocol)) {
|
|
||||||
os_free(l2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
l2->rx_done = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
l2->rx_notify = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
if (l2->rx_avail == NULL || l2->rx_done == NULL ||
|
|
||||||
l2->rx_notify == NULL) {
|
|
||||||
CloseHandle(l2->rx_avail);
|
|
||||||
CloseHandle(l2->rx_done);
|
|
||||||
CloseHandle(l2->rx_notify);
|
|
||||||
pcap_close(l2->pcap);
|
|
||||||
os_free(l2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail),
|
|
||||||
l2_packet_rx_event, l2, NULL);
|
|
||||||
|
|
||||||
l2->running = 1;
|
|
||||||
l2->rx_thread = CreateThread(NULL, 0, l2_packet_receive_thread, l2, 0,
|
|
||||||
&thread_id);
|
|
||||||
|
|
||||||
return l2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void l2_packet_deinit_timeout(void *eloop_ctx, void *timeout_ctx)
|
|
||||||
{
|
|
||||||
struct l2_packet_data *l2 = eloop_ctx;
|
|
||||||
|
|
||||||
if (l2->rx_thread_done &&
|
|
||||||
WaitForSingleObject(l2->rx_thread_done, 2000) != WAIT_OBJECT_0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "l2_packet_winpcap: RX thread did not "
|
|
||||||
"exit - kill it\n");
|
|
||||||
TerminateThread(l2->rx_thread, 0);
|
|
||||||
}
|
|
||||||
CloseHandle(l2->rx_thread_done);
|
|
||||||
CloseHandle(l2->rx_thread);
|
|
||||||
if (l2->pcap)
|
|
||||||
pcap_close(l2->pcap);
|
|
||||||
eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
|
|
||||||
CloseHandle(l2->rx_avail);
|
|
||||||
CloseHandle(l2->rx_done);
|
|
||||||
CloseHandle(l2->rx_notify);
|
|
||||||
os_free(l2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void l2_packet_deinit(struct l2_packet_data *l2)
|
|
||||||
{
|
|
||||||
if (l2 == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
l2->rx_thread_done = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
|
|
||||||
l2->running = 0;
|
|
||||||
pcap_breakloop(l2->pcap);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* RX thread may be waiting in l2_packet_receive_cb() for l2->rx_done
|
|
||||||
* event and this event is set in l2_packet_rx_event(). However,
|
|
||||||
* l2_packet_deinit() may end up being called from l2->rx_callback(),
|
|
||||||
* so we need to return from here and complete deinitialization in
|
|
||||||
* a registered timeout to avoid having to forcefully kill the RX
|
|
||||||
* thread.
|
|
||||||
*/
|
|
||||||
eloop_register_timeout(0, 0, l2_packet_deinit_timeout, l2, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
|
|
||||||
{
|
|
||||||
pcap_if_t *devs, *dev;
|
|
||||||
struct pcap_addr *addr;
|
|
||||||
struct sockaddr_in *saddr;
|
|
||||||
int found = 0;
|
|
||||||
char err[PCAP_ERRBUF_SIZE + 1];
|
|
||||||
|
|
||||||
if (pcap_findalldevs(&devs, err) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (dev = devs; dev && !found; dev = dev->next) {
|
|
||||||
if (os_strcmp(dev->name, l2->ifname) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
addr = dev->addresses;
|
|
||||||
while (addr) {
|
|
||||||
saddr = (struct sockaddr_in *) addr->addr;
|
|
||||||
if (saddr && saddr->sin_family == AF_INET) {
|
|
||||||
os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
|
|
||||||
len);
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
addr = addr->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pcap_freealldevs(devs);
|
|
||||||
|
|
||||||
return found ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void l2_packet_notify_auth_start(struct l2_packet_data *l2)
|
|
||||||
{
|
|
||||||
if (l2)
|
|
||||||
SetEvent(l2->rx_notify);
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user