freebsd pieces of wpa supplicant support

Reviewed by:	brooks
This commit is contained in:
Sam Leffler 2005-06-05 21:18:53 +00:00
parent b9203a8aca
commit cb9aecf05f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=147020
9 changed files with 1401 additions and 0 deletions

5
usr.sbin/wpa/Makefile Normal file
View File

@ -0,0 +1,5 @@
# $FreeBSD$
SUBDIR= wpa_supplicant wpa_cli
.include <bsd.subdir.mk>

View File

@ -0,0 +1,3 @@
# $FreeBSD$
BINDIR?= /usr/sbin

227
usr.sbin/wpa/l2_packet.c Normal file
View File

@ -0,0 +1,227 @@
/*
* WPA Supplicant - Layer2 packet handling
* Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
* Copyright (c) 2005, 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.
*
* $FreeBSD$
*/
/*
* FreeBSD-specific implementation.
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pcap.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include "common.h"
#include "eloop.h"
#include "l2_packet.h"
struct l2_packet_data {
pcap_t *pcap;
char ifname[100];
u8 own_addr[ETH_ALEN];
void (*rx_callback)(void *ctx, unsigned char *src_addr,
unsigned char *buf, size_t len);
void *rx_callback_ctx;
int rx_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)
{
memcpy(addr, l2->own_addr, ETH_ALEN);
return 0;
}
void
l2_packet_set_rx_l2_hdr(struct l2_packet_data *l2, int rx_l2_hdr)
{
l2->rx_l2_hdr = rx_l2_hdr;
}
int
l2_packet_send(struct l2_packet_data *l2, u8 *buf, size_t len)
{
return pcap_inject(l2->pcap, buf, len);
}
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->rx_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);
}
static int
l2_packet_init_libpcap(struct l2_packet_data *l2, unsigned short protocol)
{
bpf_u_int32 pcap_maskp, pcap_netp;
char pcap_filter[100], 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, 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_datalinke(DLT_EN10MB): %s\n",
pcap_geterr(l2->pcap));
return -1;
}
snprintf(pcap_filter, sizeof(pcap_filter),
"ether dst " MACSTR " and ether proto 0x%x",
MAC2STR(l2->own_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);
/*
* 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? */
}
}
eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap),
l2_packet_receive, l2, l2->pcap);
return 0;
}
static int
eth_get(const char *device, u8 ea[ETH_ALEN])
{
struct if_msghdr *ifm;
struct sockaddr_dl *sdl;
u_char *p, *buf;
size_t len;
int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
return -1;
if ((buf = malloc(len)) == NULL)
return -1;
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
free(buf);
return -1;
}
for (p = buf; p < buf + len; p += ifm->ifm_msglen) {
ifm = (struct if_msghdr *)p;
sdl = (struct sockaddr_dl *)(ifm + 1);
if (ifm->ifm_type != RTM_IFINFO ||
(ifm->ifm_addrs & RTA_IFP) == 0)
continue;
if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
memcmp(sdl->sdl_data, device, sdl->sdl_nlen) != 0)
continue;
memcpy(ea, LLADDR(sdl), sdl->sdl_alen);
break;
}
free(buf);
if (p >= buf + len) {
errno = ESRCH;
return -1;
}
return 0;
}
struct l2_packet_data *
l2_packet_init(const char *ifname, const u8 *own_addr, unsigned short protocol,
void (*rx_callback)(void *ctx, unsigned char *src_addr,
unsigned char *buf, size_t len),
void *rx_callback_ctx)
{
struct l2_packet_data *l2;
l2 = malloc(sizeof(struct l2_packet_data));
if (l2 == NULL)
return NULL;
memset(l2, 0, sizeof(*l2));
strncpy(l2->ifname, ifname, sizeof(l2->ifname));
l2->rx_callback = rx_callback;
l2->rx_callback_ctx = rx_callback_ctx;
if (eth_get(l2->ifname, l2->own_addr) < 0) {
fprintf(stderr, "Failed to get link-level address for "
"interface '%s'.\n", l2->ifname);
free(l2);
return NULL;
}
if (l2_packet_init_libpcap(l2, protocol) != 0) {
free(l2);
return NULL;
}
return l2;
}
void
l2_packet_deinit(struct l2_packet_data *l2)
{
if (l2 != NULL) {
if (l2->pcap)
pcap_close(l2->pcap);
free(l2);
}
}

View File

@ -0,0 +1,9 @@
# $FreeBSD$
WPA_SUPPLICANT_DISTDIR?= ${.CURDIR}/../../../contrib/wpa_supplicant
.PATH: ${WPA_SUPPLICANT_DISTDIR}
PROG= wpa_cli
SRCS= wpa_cli.c wpa_ctrl.c
.include <bsd.prog.mk>

View File

@ -0,0 +1,192 @@
.\" Copyright (c) 2005 Sam Leffler <sam@errno.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd June 3, 2005
.Dt WPA_CLI 1
.Os
.Sh NAME
.Nm wpa_cli
.Nd "text-based frontend program for interacting with wpa_supplicant"
.Sh SYNOPSIS
.Nm
.Op commands
.Sh DESCRIPTION
.Nm
is a text-based frontend program for interacting with
.Xr wpa_supplicant 1.
.Nm
is used to query current status,
change configuration,
trigger events,
and
request interactive user input.
.Pp
.Nm
can show the
current authentication status,
selected security
mode, dot11 and dot1x MIBs, etc.
In addition,
.Nm
can configure EAPOL state machine
parameters and trigger events like reassociation
and IEEE 802.1X logoff/logon.
.Nm
provides a user interface to request authentication information,
like username and password, if these are not included in the
configuration.
This can be used to implement,
e.g., one-time-passwords or generic token card
authentication where the authentication is based on a
challenge-response that uses an external device for generating the
response.
.Pp
The control interface of
.Nm wpa_supplicant
can be configured to allow
non-root user access (ctrl_interface_group in the configuration file).
This makes it possible to run
.Nm
with a normal user account.
.Pp
.Nm
supports two modes: interactive and command line.
Both modes share the same command set and the main difference
is in interactive mode providing access to unsolicited messages
(event messages, username/password requests).
.Pp
Interactive mode is started when
.Nm
is executed without with any parameters on the command line.
Commands are then entered from the controlling terminal in
response to the
.Nm
prompt.
In command line mode, the same commands are
entered as command line arguments.
.Sh AUTHENTICATION PARAMETERS
.Pp
When
.Nm wpa_supplicant
needs authentication parameters, such as username and password,
that are not present in the configuration file, it sends a
request message to all attached frontend programs, e.g.,
.Nm
in interactive mode.
.Nm
shows these requests with
"CTRL-REQ-<type>-<id>:<text>" prefix.
<type> is IDENTITY, PASSWORD, or OTP (one-time-password).
<id> is a unique identifier for the current network.
<text> is description of the request.
In case of OTP request, it includes the challenge from
the authentication server.
.Pp
A user must supply
.Nm wpa_supplicant
the needed parameters in response to these requests.
.Pp
For example,
.Bd -literal
CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
> password 1 mysecretpassword
Example request for generic token card challenge-response:
CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
> otp 2 9876
.Ed
.Sh COMMANDS
The following commands may be supplied on the command line
or at a prompt when operating interactively.
.Bl -tag -width indent
.It status
Report the current WPA/EAPOL/EAP status for the current interface.
.It mib
Report MIB variables (dot1x, dot11) for the current interface.
.It help
Show usage help.
.It interface [ Ar ifname ]
Show available interfaces and/or set the current interface
when multiple are available.
.It level <debug level>
Change the debugging level in
.Nm wpa_supplicant .
Larger numbers generate more messages.
.It license
Display the full
.Nm
license for
.Nm .
.It logoff
Send the IEEE 802.1X EAPOL state machine into the logoff state.
.It logon
Send the IEEE 802.1X EAPOL state machine into the logon state.
.It set [ settings ]
Set variables.
When no arguments are supplied the known variables and their settings
are displayed.
.It pmksa
Show the contents of the PMKSA cache.
.It reassociate
Force a reassociation to the current access point.
.It reconfigure
Force
.Nm
to re-read its configuration file.
.It preauthenticate <BSSID>
Force preauthentication of the specified BSSID.
.It identity <network id> <identity>
Configure an identity for an SSID.
.It password <network id> <password>
Configure a password for an SSID.
.It otp <network id> <password>
Configure a one-time-password for an SSID.
.It terminate
Force
.Nm wpa_supplicant
to terminate.
.It quit
Exit
.Nm .
.El
.Sh SEE ALSO
.Xr wpa_supplicant 1 ,
.Xr wpa_supplicant.conf 5
.Sh HISTORY
The
.Nm
utility first appeared in
.Fx 6.0 .
.Sh AUTHORS
The
.Nm
utility was written by
.An Jouni Malinen Aq jkmaline@cc.hut.fi .
This manual page is derived from the README file included in the
.Nm
distribution.
.Sh BUGS

View File

@ -0,0 +1,40 @@
# $FreeBSD$
WPA_SUPPLICANT_DISTDIR?= ${.CURDIR}/../../../contrib/wpa_supplicant
.PATH: ${.CURDIR}/.. ${WPA_SUPPLICANT_DISTDIR}
PROG= wpa_supplicant
SRCS= config.c eloop.c common.c md5.c rc4.c sha1.c aes_wrap.c \
wpa_supplicant.c wpa.c \
ctrl_iface.c l2_packet.c drivers.c driver_freebsd.c
CFLAGS+= -I${.CURDIR} -I${WPA_SUPPLICANT_DISTDIR}
CFLAGS+= -DCONFIG_DRIVER_BSD
CFLAGS+= -DCONFIG_CTRL_IFACE
CFLAGS+= -g
DPADD+= ${LIBPCAP}
LDADD+= -lpcap
.if defined(ENABLE_WPA_SUPPLICANT_EAPOL)
SRCS+= eapol_sm.c eap.c
CFLAGS+= -DIEEE8021X_EAPOL
.if !defined(NO_CRYPT) && !defined(NO_OPENSSL) && !defined(RELEASE_CRUNCH)
CFLAGS+=-DEAP_TLS -DEAP_PEAP -DEAP_MSCHAPv2 -DEAP_LEAP -DEAP_PSK \
-DEAP_TLV -DEAP_TLS_FUNCS
SRCS+= eap_tls.c eap_peap.c eap_mschapv2.c eap_leap.c eap_psk.c \
eap_tlv.c eap_tls_common.c tls_openssl.c ms_funcs.c crypto.c
# NB: requires patch to openssl
#CFLAGS+= -DEAP_FAST
#SRCS+= eap_fast.c
DPADD+= ${LIBCRYPTO}
LDADD+= -lssl -lcrypto
.else
SRCS+= tls_none.c
.endif
.endif
.include <bsd.prog.mk>

View File

@ -0,0 +1,636 @@
/*
* 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.
*
* $FreeBSD$
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <errno.h>
#include "common.h"
#include "driver.h"
#include "eloop.h"
#include "wpa_supplicant.h"
#include "l2_packet.h"
#include <sys/socket.h>
#include <net/if.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 */
void *ctx;
};
static int
set80211var(struct wpa_driver_bsd_data *drv, int op, const void *arg, int arg_len)
{
struct ieee80211req ireq;
memset(&ireq, 0, sizeof(ireq));
strncpy(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) {
perror("ioctl[SIOCS80211]");
return -1;
}
return 0;
}
static int
get80211var(struct wpa_driver_bsd_data *drv, int op, void *arg, int arg_len)
{
struct ieee80211req ireq;
memset(&ireq, 0, sizeof(ireq));
strncpy(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) {
perror("ioctl[SIOCG80211]");
return -1;
}
return ireq.i_len;
}
static int
set80211param(struct wpa_driver_bsd_data *drv, int op, int arg)
{
struct ieee80211req ireq;
memset(&ireq, 0, sizeof(ireq));
strncpy(ireq.i_name, drv->ifname, IFNAMSIZ);
ireq.i_type = op;
ireq.i_val = arg;
if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
perror("ioctl[SIOCS80211]");
return -1;
}
return 0;
}
static int
getifflags(struct wpa_driver_bsd_data *drv, int *flags)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(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;
memset(&ifr, 0, sizeof(ifr));
strncpy(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 char *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 char *wpa_ie, size_t wpa_ie_len)
{
return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len);
}
static int
wpa_driver_bsd_set_wpa(void *priv, int enabled)
{
struct wpa_driver_bsd_data *drv = priv;
int ret = 0;
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
if (!enabled && wpa_driver_bsd_set_wpa_ie(drv, NULL, 0) < 0)
ret = -1;
if (set80211param(drv, IEEE80211_IOC_ROAMING, enabled ? 2 : 0) < 0)
ret = -1;
if (set80211param(drv, IEEE80211_IOC_PRIVACY, enabled) < 0)
ret = -1;
if (set80211param(drv, IEEE80211_IOC_WPA, enabled ? 3 : 0) < 0)
ret = -1;
return ret;
}
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;
wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
memset(&wk, 0, sizeof(wk));
wk.idk_keyix = key_idx;
if (addr != NULL)
memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
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;
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",
__FUNCTION__, alg);
return -1;
}
wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%d "
"key_len=%d", __FUNCTION__, alg_name, key_idx, set_tx,
seq_len, key_len);
if (seq_len > sizeof(u_int64_t)) {
wpa_printf(MSG_DEBUG, "%s: seq_len %d too big",
__FUNCTION__, seq_len);
return -2;
}
if (key_len > sizeof(wk.ik_keydata)) {
wpa_printf(MSG_DEBUG, "%s: key length %d too big",
__FUNCTION__, key_len);
return -3;
}
memset(&wk, 0, sizeof(wk));
wk.ik_type = cipher;
wk.ik_flags = IEEE80211_KEY_RECV;
if (set_tx) {
wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
} else
memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
wk.ik_keyix = key_idx;
wk.ik_keylen = key_len;
memcpy(&wk.ik_keyrsc, seq, seq_len);
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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__);
mlme.im_op = IEEE80211_MLME_DEAUTH;
mlme.im_reason = reason_code;
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", __FUNCTION__);
mlme.im_op = IEEE80211_MLME_DISASSOC;
mlme.im_reason = reason_code;
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 ret = 0;
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_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
ret = -1;
if (wpa_driver_bsd_set_ssid(drv, params->ssid, params->ssid_len) < 0)
ret = -1;
memset(&mlme, 0, sizeof(mlme));
mlme.im_op = IEEE80211_MLME_ASSOC;
memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
ret = -1;
return ret;
}
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>
#include <net80211/ieee80211_freebsd.h>
static void
wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
{
char buf[2048];
struct if_announcemsghdr *ifan;
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;
}
ifan = (struct if_announcemsghdr *) rtm;
switch (rtm->rtm_type) {
case RTM_IFANNOUNCE:
memset(&event, 0, sizeof(event));
/* XXX name buffer must be >= IFNAMSIZ */
/* XXX check return value */
if_indextoname(ifan->ifan_index, event.interface_status.ifname);
switch (ifan->ifan_what) {
case IFAN_ARRIVAL:
event.interface_status.ievent = EVENT_INTERFACE_ADDED;
break;
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:
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));
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;
}
}
/* 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;
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;
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);
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);
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);
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)
{
struct wpa_driver_bsd_data *drv;
drv = malloc(sizeof(*drv));
if (drv == NULL)
return NULL;
memset(drv, 0, sizeof(*drv));
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->sock < 0) {
free(drv);
return NULL;
}
drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
if (drv->route < 0) {
close(drv->sock);
free(drv);
return NULL;
}
eloop_register_read_sock(drv->route,
wpa_driver_bsd_event_receive, ctx, NULL);
drv->ctx = ctx;
strncpy(drv->ifname, ifname, sizeof(drv->ifname));
return drv;
}
static void
wpa_driver_bsd_deinit(void *priv)
{
struct wpa_driver_bsd_data *drv = priv;
int flags;
/* NB: mark interface down */
if (getifflags(drv, &flags) == 0)
(void) setifflags(drv, flags &~ IFF_UP);
(void) close(drv->route); /* ioctl socket */
(void) close(drv->sock); /* event socket */
free(drv);
}
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,
};

View File

@ -0,0 +1,132 @@
.\" Copyright (c) 2005 Sam Leffler <sam@errno.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd June 3, 2005
.Dt WPA_SUPPLICANT 8
.Os
.Sh NAME
.Nm wpa_supplicant
.Nd "WPA/802.11i Supplicant for wireless network devices"
.Sh SYNOPSIS
.Nm
.Op Fl BddehLqqvw
.Fl i Ar ifname
.Fl c Ar config-file
.Op Fl N i Ar ifname Fl c Ar config-file ....
.Sh DESCRIPTION
.Nm
is an implementation of the WPA Supplicant component,
i.e., the part that runs in the client stations.
It implements WPA key negotiation with a WPA Authenticator
and EAP authentication with Authentication Server.
In addition, it controls the roaming and IEEE 802.11
authentication/association of the wlan driver.
.Pp
.Nm
is designed to be a "daemon" program that runs in the
background and acts as the backend component controlling
the wireless connection.
.Nm
supports separate frontend programs such as the
text-based frontend,
.Xr wpa_cli 8
.Pp
The following arguments must be specified on the command line:
.Bl -tag -width indent
.It Fl i Ar ifname
Use the specified wireless interface.
.It Fl c Ar config-file
Use the settings in the specified configuration file when managing
the specified wireless interface.
See
.Xr wpa_supplicant.conf 5
for a description of the configuration file syntax.
.Pp
Changes to the configuration file can be reloaded by sending a
.Nm SIGHUP
to the
.Nm
processor or with the
.Xr wpa_cli
utility, using ``wpa_cli reconfigure''.
.El
.Sh OPTIONS
The options are as follows:
.Bl -tag -width indent
.It Fl d
Enable debugging messages.
If this option is supplied twice more verbose messages are displayed.
.It Fl e
Use an external IEEE 802.1X Supplicant program and disable the
internal Supplicant.
This option is not normally used.
.It Fl h
Show help text.
.It Fl q
Decrease debugging verbosity (i.e. counteract the use of the
.Fl d
flag.
.It Fl v
Display version information on the terminal and exit.
.It Fl w
If the specified interface is not present, wait for it to be
added; e.g. a cardbus device to be inserted.
.It Fl B
Detach from the controlling terminal and run as a daemon process
in the background.
.It Fl K
Include key information in debugging output.
.It Fl L
Display the license for this program on the terminal and exit.
.It Fl N Fl i Ar iface Fl Ar config-file
Specify an additional interface and configuration file.
If multiple interfaces are specified then
.Nm
will manage them all with a single process.
.El
.Sh SEE ALSO
.Xr ath 4 ,
.Xr iwi 4 ,
.Xr ipw 4 ,
.Xr ral 4 ,
.Xr ural 4 ,
.Xr wi 4 ,
.Xr wpa_supplicant.conf 5 ,
.Xr ifconfig 8
.Sh HISTORY
The
.Nm
utility first appeared in
.Fx 6.0 .
.Sh AUTHORS
The
.Nm
utility was written by
.An Jouni Malinen Aq jkmaline@cc.hut.fi .
This manual page is derived from the README file included in the
.Nm
distribution.
.Sh BUGS

View File

@ -0,0 +1,157 @@
.\" Copyright (c) 2005 Sam Leffler <sam@errno.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd June 3, 2005
.Dt WPA_SUPPLICANT.CONF 5
.Os
.Sh NAME
.Nm wpa_supplicant.conf
.Nd "configuration file for wpa_supplicant utility"
.Sh DESCRIPTION
The
.Xr wpa_supplicant 1
program is an implementation of the WPA Supplicant component,
i.e., the part that runs in the client stations.
.Nm wpa_supplicant
implements WPA key negotiation with a WPA Authenticator
and EAP authentication with Authentication Server using
configuration information stored in a text file.
.Pp
The configuration file consists of one or more network blocks, e.g.
one for each used SSID.
.Nm wpa_supplicant
will automatically select the best network based on the order of
the network blocks in the configuration file, network security level
(WPA/WPA2 is preferred), and signal strength.
.Sh CERTIFICATES
.Pp
Some EAP authentication methods require use of certificates.
EAP-TLS uses both server- and client-side certificates,
whereas EAP-PEAP and EAP-TTLS only require a server-side certificate.
When a client certificate is used, a matching private key file must
also be included in configuration.
If the private key uses a passphrase, this
has to be configured in the wpa_supplicant.conf file as "private_key_passwd".
.Pp
.Nm wpa_supplicant
supports X.509 certificates in PEM and DER formats.
User certificate and private key can be included in the same file.
.Pp
If the user certificate and private key is received in PKCS#12/PFX
format, they need to be converted to suitable PEM/DER format for
use by
.Nm wpa_supplicant.
This can be done using the
.Xr openssl 1
program, e.g. with following commands:
.Bd -literal
# convert client certificate and private key to PEM format
openssl pkcs12 -in example.pfx -out user.pem -clcerts
# convert CA certificate (if included in PFX file) to PEM format
openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys
.Be
.Sh EXAMPLES
.Pp
WPA-Personal (PSK) as a home network and WPA-Enterprise with EAP-TLS
as a work network:
.Bd -literal
# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
#
# home network; allow all valid ciphers
network={
ssid="home"
scan_ssid=1
key_mgmt=WPA-PSK
psk="very secret passphrase"
}
#
# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers
network={
ssid="work"
scan_ssid=1
key_mgmt=WPA-EAP
pairwise=CCMP TKIP
group=CCMP TKIP
eap=TLS
identity="user@example.com"
ca_cert="/etc/cert/ca.pem"
client_cert="/etc/cert/user.pem"
private_key="/etc/cert/user.prv"
private_key_passwd="password"
}
.Ed
.Pp
WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that use old peaplabel
(e.g., Funk Odyssey and SBR, Meetinghouse Aegis, Interlink RAD-Series):
.Bd -literal
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
network={
ssid="example"
scan_ssid=1
key_mgmt=WPA-EAP
eap=PEAP
identity="user@example.com"
password="foobar"
ca_cert="/etc/cert/ca.pem"
phase1="peaplabel=0"
phase2="auth=MSCHAPV2"
}
.Ed
.Pp
EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the
unencrypted use. Real identity is sent only within an encrypted TLS tunnel.
.Bd -literal
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
network={
ssid="example"
scan_ssid=1
key_mgmt=WPA-EAP
eap=TTLS
identity="user@example.com"
anonymous_identity="anonymous@example.com"
password="foobar"
ca_cert="/etc/cert/ca.pem"
phase2="auth=MD5"
}
.Ed
.Sh SEE ALSO
.Xr wpa_supplicant 1
.Sh HISTORY
The
.Nm
manual page and
.Nm wpa_supplicant
functionality first appeared in
.Fx 6.0 .
.Sh AUTHORS
This manual page is derived from the README file in the
.Nm wpa_supplicant
distribution provided by
.An Jouni Malinen Aq jkmaline@cc.hut.fi .