Add lib80211, a small (but hopefully soon to grow) set of library

routines to interface with net80211.

This is all from the ifconfig program; the duplicate code from ifconfig
will be removed when it starts using this API.

Differential Revision:	https://reviews.freebsd.org/D4290
This commit is contained in:
Adrian Chadd 2015-11-30 04:41:50 +00:00
parent 6035018b9a
commit 127be1a706
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=291464
7 changed files with 1192 additions and 0 deletions

View file

@ -71,6 +71,7 @@ SUBDIR= ${SUBDIR_ORDERED} \
${_libmp} \
libmt \
${_libnandfs} \
lib80211 \
libnetbsd \
${_libnetgraph} \
${_libngatm} \

15
lib/lib80211/Makefile Normal file
View file

@ -0,0 +1,15 @@
# $FreeBSD$
LIB= 80211
SHLIBDIR?= /lib
SHLIB_MAJOR= 1
SRCS= lib80211_regdomain.c lib80211_ioctl.c
INCSDIR= ${INCLUDEDIR}/lib80211/
INCS= lib80211_regdomain.h lib80211_ioctl.h
MAN= lib80211.3
CFLAGS+=-I${.CURDIR}
.include <bsd.lib.mk>

118
lib/lib80211/lib80211.3 Normal file
View file

@ -0,0 +1,118 @@
.\" Copyright (c) 2015 Adrian Chadd.
.\" 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 November 24, 2015
.Dt 80211 3
.Os
.Sh NAME
.Nm lib80211_alloc_regdata ,
.Nm lib80211_free_regdata ,
.Nm lib80211_regdomain_readconfig ,
.Nm lib80211_regdomain_cleanup ,
.Nm lib80211_regdomain_findbysku ,
.Nm lib80211_regdomain_findbyname ,
.Nm lib80211_country_findbycc ,
.Nm lib80211_country_findbyname
.Nd manage net80211 configuration and regulatory database.
.Sh LIBRARY
.Lb lib80211
.Sh SYNOPSIS
.In lib80211/lib80211_regdomain.h
.In lib80211/lib80211_ioctl.h
.Ft struct regdata *
.Fn lib80211_alloc_regdata void
.Ft void
.Fn lib80211_free_regdata "struct regdata *reg"
.Ft int
.Fn lib80211_regdomain_readconfig "struct regdata *reg" "const void *config" "size_t size"
.Ft void
.Fn lib80211_regdomain_cleanup "struct regdata *reg"
.Ft const struct regdomain *
.Fn lib80211_regdomain_findbysku "const struct regdata *reg" "enumRegDomainCode"
.Ft const struct regdomain *
.Fn lib80211_regdomain_findbyname "const struct regdata *reg" "const char *sku"
.Ft const struct country *
.Fn lib80211_country_findbycc "const struct regdata *reg" "enum ISOCountryCode"
.Ft const struct country *
.Fn lib80211_country_findbyname "const struct regdata *reg" "const char *cc"
.Sh DESCRIPTION
The
.Nm lib80211
library is an interface to the
.Xr net80211 4
infrastructure.
It implements wrappers around the
.Xr net80211 4
ioctl command, as well as providing a convenient API to access the regulatory
database.
.Pp
The
.Fn lib80211_alloc_regdata
and
.Fn lib80211_free_regdata
function allocates / frees a regdata structure to store regulatory domain
information in.
.Pp
The
.Fn lib80211_regdomain_readconfig
and
.Fn lib80211_regdomain_cleanup
functions read in the regulatory database XML configuration and free it when
finished.
.Pp
The
.Fn lib80211_regdomain_findbysku
and
.Fn lib80211_regdomain_findbyname
functions lookup a regulatory domain entry by SKU enum and SKU name
respectively.
.Pp
The
.Fn lib80211_country_findbycc
and
.Fn lib80211_country_findbyname
functions lookup a country information entry by ISO country enum and
ISO country code string respectively.
.Sh RETURN VALUES
The
.Fn lib80211_alloc_regdata ,
.Fn lib80211_regdomain_readconfig ,
.Fn lib80211_regdomain_findbysku ,
.Fn lib80211_regdomain_findbyname ,
.Fn lib80211_country_findbycc ,
.Fn lib80211_country_findbyname
return NULL upon error.
.Sh SEE ALSO
.Xr ifconfig 8 ,
.Xr net80211 4
.Sh HISTORY
The
.Nm lib80211
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.An Adrian Chadd

View file

@ -0,0 +1,159 @@
/*
* Copyright 2001 The Aerospace Corporation. 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.
* 3. The name of The Aerospace Corporation may not be used to endorse or
* promote products derived from this software.
*
* THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``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 AEROSPACE CORPORATION 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$
*/
/*-
* Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/if_media.h>
#include <net/route.h>
#include <net80211/ieee80211_ioctl.h>
#include <net80211/ieee80211_freebsd.h>
#include <net80211/ieee80211_superg.h>
#include <net80211/ieee80211_tdma.h>
#include <net80211/ieee80211_mesh.h>
#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <stddef.h> /* NB: for offsetof */
#include "lib80211_ioctl.h"
/*
* These implement basic net80211 accessor methods to wrap the IOCTL
* calls.
*/
int
lib80211_get80211(int s, const char *name, int type, void *data, int len)
{
struct ieee80211req ireq;
(void) memset(&ireq, 0, sizeof(ireq));
(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
ireq.i_type = type;
ireq.i_data = data;
ireq.i_len = len;
return ioctl(s, SIOCG80211, &ireq);
}
int
lib80211_get80211len(int s, const char *name, int type, void *data, int len, int *plen)
{
struct ieee80211req ireq;
(void) memset(&ireq, 0, sizeof(ireq));
(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
ireq.i_type = type;
ireq.i_len = len;
assert(ireq.i_len == len); /* NB: check for 16-bit truncation */
ireq.i_data = data;
if (ioctl(s, SIOCG80211, &ireq) < 0)
return -1;
*plen = ireq.i_len;
return 0;
}
int
lib80211_get80211val(int s, const char *name, int type, int *val)
{
struct ieee80211req ireq;
(void) memset(&ireq, 0, sizeof(ireq));
(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
ireq.i_type = type;
if (ioctl(s, SIOCG80211, &ireq) < 0)
return -1;
*val = ireq.i_val;
return 0;
}
int
lib80211_set80211(int s, const char *name, int type, int val, int len, void *data)
{
struct ieee80211req ireq;
(void) memset(&ireq, 0, sizeof(ireq));
(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
ireq.i_type = type;
ireq.i_val = val;
ireq.i_len = len;
assert(ireq.i_len == len); /* NB: check for 16-bit truncation */
ireq.i_data = data;
if (ioctl(s, SIOCS80211, &ireq) < 0)
return (-1);
return (0);
}

View file

@ -0,0 +1,71 @@
/*
* Copyright 2001 The Aerospace Corporation. 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.
* 3. The name of The Aerospace Corporation may not be used to endorse or
* promote products derived from this software.
*
* THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``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 AEROSPACE CORPORATION 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$
*/
/*-
* Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#ifndef __LIB80211_IOCTL_H__
#define __LIB80211_IOCTL_H__
extern int lib80211_get80211(int s, const char *name, int type, void *data,
int len);
extern int lib80211_get80211len(int s, const char *name, int type, void *data,
int len, int *plen);
extern int lib80211_get80211val(int s, const char *name, int type, int *val);
extern int lib80211_set80211(int s, const char *name, int type, int val,
int len, void *data);
#endif /* __LIB80211_IOCTL_H__ */

View file

@ -0,0 +1,707 @@
/*-
* Copyright (c) 2008 Sam Leffler, Errno Consulting
* 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 ``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 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.
*/
#ifndef lint
static const char rcsid[] = "$FreeBSD$";
#endif /* not lint */
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/sbuf.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <err.h>
#include <unistd.h>
#include <bsdxml.h>
#include "lib80211_regdomain.h"
#include <net80211/_ieee80211.h>
#define MAXLEVEL 20
struct mystate {
XML_Parser parser;
struct regdata *rdp;
struct regdomain *rd; /* current domain */
struct netband *netband; /* current netband */
struct freqband *freqband; /* current freqband */
struct country *country; /* current country */
netband_head *curband; /* current netband list */
int level;
struct sbuf *sbuf[MAXLEVEL];
int nident;
};
struct ident {
const void *id;
void *p;
enum { DOMAIN, COUNTRY, FREQBAND } type;
};
static void
start_element(void *data, const char *name, const char **attr)
{
#define iseq(a,b) (strcasecmp(a,b) == 0)
struct mystate *mt;
const void *id, *ref, *mode;
int i;
mt = data;
if (++mt->level == MAXLEVEL) {
/* XXX force parser to abort */
return;
}
mt->sbuf[mt->level] = sbuf_new_auto();
id = ref = mode = NULL;
for (i = 0; attr[i] != NULL; i += 2) {
if (iseq(attr[i], "id")) {
id = attr[i+1];
} else if (iseq(attr[i], "ref")) {
ref = attr[i+1];
} else if (iseq(attr[i], "mode")) {
mode = attr[i+1];
} else
printf("%*.*s[%s = %s]\n", mt->level + 1,
mt->level + 1, "", attr[i], attr[i+1]);
}
if (iseq(name, "rd") && mt->rd == NULL) {
if (mt->country == NULL) {
mt->rd = calloc(1, sizeof(struct regdomain));
mt->rd->name = strdup(id);
mt->nident++;
LIST_INSERT_HEAD(&mt->rdp->domains, mt->rd, next);
} else
mt->country->rd = (void *)strdup(ref);
return;
}
if (iseq(name, "defcc") && mt->rd != NULL) {
mt->rd->cc = (void *)strdup(ref);
return;
}
if (iseq(name, "netband") && mt->curband == NULL && mt->rd != NULL) {
if (mode == NULL) {
warnx("no mode for netband at line %ld",
XML_GetCurrentLineNumber(mt->parser));
return;
}
if (iseq(mode, "11b"))
mt->curband = &mt->rd->bands_11b;
else if (iseq(mode, "11g"))
mt->curband = &mt->rd->bands_11g;
else if (iseq(mode, "11a"))
mt->curband = &mt->rd->bands_11a;
else if (iseq(mode, "11ng"))
mt->curband = &mt->rd->bands_11ng;
else if (iseq(mode, "11na"))
mt->curband = &mt->rd->bands_11na;
else
warnx("unknown mode \"%s\" at line %ld",
__DECONST(char *, mode),
XML_GetCurrentLineNumber(mt->parser));
return;
}
if (iseq(name, "band") && mt->netband == NULL) {
if (mt->curband == NULL) {
warnx("band without enclosing netband at line %ld",
XML_GetCurrentLineNumber(mt->parser));
return;
}
mt->netband = calloc(1, sizeof(struct netband));
LIST_INSERT_HEAD(mt->curband, mt->netband, next);
return;
}
if (iseq(name, "freqband") && mt->freqband == NULL && mt->netband != NULL) {
/* XXX handle inlines and merge into table? */
if (mt->netband->band != NULL) {
warnx("duplicate freqband at line %ld ignored",
XML_GetCurrentLineNumber(mt->parser));
/* XXX complain */
} else
mt->netband->band = (void *)strdup(ref);
return;
}
if (iseq(name, "country") && mt->country == NULL) {
mt->country = calloc(1, sizeof(struct country));
mt->country->isoname = strdup(id);
mt->country->code = NO_COUNTRY;
mt->nident++;
LIST_INSERT_HEAD(&mt->rdp->countries, mt->country, next);
return;
}
if (iseq(name, "freqband") && mt->freqband == NULL) {
mt->freqband = calloc(1, sizeof(struct freqband));
mt->freqband->id = strdup(id);
mt->nident++;
LIST_INSERT_HEAD(&mt->rdp->freqbands, mt->freqband, next);
return;
}
#undef iseq
}
static int
decode_flag(struct mystate *mt, const char *p, int len)
{
#define iseq(a,b) (strcasecmp(a,b) == 0)
static const struct {
const char *name;
int len;
uint32_t value;
} flags[] = {
#define FLAG(x) { #x, sizeof(#x)-1, x }
FLAG(IEEE80211_CHAN_A),
FLAG(IEEE80211_CHAN_B),
FLAG(IEEE80211_CHAN_G),
FLAG(IEEE80211_CHAN_HT20),
FLAG(IEEE80211_CHAN_HT40),
FLAG(IEEE80211_CHAN_ST),
FLAG(IEEE80211_CHAN_TURBO),
FLAG(IEEE80211_CHAN_PASSIVE),
FLAG(IEEE80211_CHAN_DFS),
FLAG(IEEE80211_CHAN_CCK),
FLAG(IEEE80211_CHAN_OFDM),
FLAG(IEEE80211_CHAN_2GHZ),
FLAG(IEEE80211_CHAN_5GHZ),
FLAG(IEEE80211_CHAN_DYN),
FLAG(IEEE80211_CHAN_GFSK),
FLAG(IEEE80211_CHAN_GSM),
FLAG(IEEE80211_CHAN_STURBO),
FLAG(IEEE80211_CHAN_HALF),
FLAG(IEEE80211_CHAN_QUARTER),
FLAG(IEEE80211_CHAN_HT40U),
FLAG(IEEE80211_CHAN_HT40D),
FLAG(IEEE80211_CHAN_4MSXMIT),
FLAG(IEEE80211_CHAN_NOADHOC),
FLAG(IEEE80211_CHAN_NOHOSTAP),
FLAG(IEEE80211_CHAN_11D),
FLAG(IEEE80211_CHAN_FHSS),
FLAG(IEEE80211_CHAN_PUREG),
FLAG(IEEE80211_CHAN_108A),
FLAG(IEEE80211_CHAN_108G),
#undef FLAG
{ "ECM", 3, REQ_ECM },
{ "INDOOR", 6, REQ_INDOOR },
{ "OUTDOOR", 7, REQ_OUTDOOR },
};
unsigned int i;
for (i = 0; i < nitems(flags); i++)
if (len == flags[i].len && iseq(p, flags[i].name))
return flags[i].value;
warnx("unknown flag \"%.*s\" at line %ld ignored",
len, p, XML_GetCurrentLineNumber(mt->parser));
return 0;
#undef iseq
}
static void
end_element(void *data, const char *name)
{
#define iseq(a,b) (strcasecmp(a,b) == 0)
struct mystate *mt;
int len;
char *p;
mt = data;
sbuf_finish(mt->sbuf[mt->level]);
p = sbuf_data(mt->sbuf[mt->level]);
len = sbuf_len(mt->sbuf[mt->level]);
/* <freqband>...</freqband> */
if (iseq(name, "freqstart") && mt->freqband != NULL) {
mt->freqband->freqStart = strtoul(p, NULL, 0);
goto done;
}
if (iseq(name, "freqend") && mt->freqband != NULL) {
mt->freqband->freqEnd = strtoul(p, NULL, 0);
goto done;
}
if (iseq(name, "chanwidth") && mt->freqband != NULL) {
mt->freqband->chanWidth = strtoul(p, NULL, 0);
goto done;
}
if (iseq(name, "chansep") && mt->freqband != NULL) {
mt->freqband->chanSep = strtoul(p, NULL, 0);
goto done;
}
if (iseq(name, "flags")) {
if (mt->freqband != NULL)
mt->freqband->flags |= decode_flag(mt, p, len);
else if (mt->netband != NULL)
mt->netband->flags |= decode_flag(mt, p, len);
else {
warnx("flags without freqband or netband at line %ld ignored",
XML_GetCurrentLineNumber(mt->parser));
}
goto done;
}
/* <rd> ... </rd> */
if (iseq(name, "name") && mt->rd != NULL) {
mt->rd->name = strdup(p);
goto done;
}
if (iseq(name, "sku") && mt->rd != NULL) {
mt->rd->sku = strtoul(p, NULL, 0);
goto done;
}
if (iseq(name, "netband") && mt->rd != NULL) {
mt->curband = NULL;
goto done;
}
/* <band> ... </band> */
if (iseq(name, "freqband") && mt->netband != NULL) {
/* XXX handle inline freqbands */
goto done;
}
if (iseq(name, "maxpower") && mt->netband != NULL) {
mt->netband->maxPower = strtoul(p, NULL, 0);
goto done;
}
if (iseq(name, "maxpowerdfs") && mt->netband != NULL) {
mt->netband->maxPowerDFS = strtoul(p, NULL, 0);
goto done;
}
if (iseq(name, "maxantgain") && mt->netband != NULL) {
mt->netband->maxAntGain = strtoul(p, NULL, 0);
goto done;
}
/* <country>...</country> */
if (iseq(name, "isocc") && mt->country != NULL) {
mt->country->code = strtoul(p, NULL, 0);
goto done;
}
if (iseq(name, "name") && mt->country != NULL) {
mt->country->name = strdup(p);
goto done;
}
if (len != 0) {
warnx("unexpected XML token \"%s\" data \"%s\" at line %ld",
name, p, XML_GetCurrentLineNumber(mt->parser));
/* XXX goto done? */
}
/* </freqband> */
if (iseq(name, "freqband") && mt->freqband != NULL) {
/* XXX must have start/end frequencies */
/* XXX must have channel width/sep */
mt->freqband = NULL;
goto done;
}
/* </rd> */
if (iseq(name, "rd") && mt->rd != NULL) {
mt->rd = NULL;
goto done;
}
/* </band> */
if (iseq(name, "band") && mt->netband != NULL) {
if (mt->netband->band == NULL) {
warnx("no freqbands for band at line %ld",
XML_GetCurrentLineNumber(mt->parser));
}
if (mt->netband->maxPower == 0) {
warnx("no maxpower for band at line %ld",
XML_GetCurrentLineNumber(mt->parser));
}
/* default max power w/ DFS to max power */
if (mt->netband->maxPowerDFS == 0)
mt->netband->maxPowerDFS = mt->netband->maxPower;
mt->netband = NULL;
goto done;
}
/* </netband> */
if (iseq(name, "netband") && mt->netband != NULL) {
mt->curband = NULL;
goto done;
}
/* </country> */
if (iseq(name, "country") && mt->country != NULL) {
/* XXX NO_COUNTRY should be in the net80211 country enum */
if ((int) mt->country->code == NO_COUNTRY) {
warnx("no ISO cc for country at line %ld",
XML_GetCurrentLineNumber(mt->parser));
}
if (mt->country->name == NULL) {
warnx("no name for country at line %ld",
XML_GetCurrentLineNumber(mt->parser));
}
if (mt->country->rd == NULL) {
warnx("no regdomain reference for country at line %ld",
XML_GetCurrentLineNumber(mt->parser));
}
mt->country = NULL;
goto done;
}
done:
sbuf_delete(mt->sbuf[mt->level]);
mt->sbuf[mt->level--] = NULL;
#undef iseq
}
static void
char_data(void *data, const XML_Char *s, int len)
{
struct mystate *mt;
const char *b, *e;
mt = data;
b = s;
e = s + len-1;
for (; isspace(*b) && b < e; b++)
;
for (; isspace(*e) && e > b; e++)
;
if (e != b || (*b != '\0' && !isspace(*b)))
sbuf_bcat(mt->sbuf[mt->level], b, e-b+1);
}
static void *
findid(struct regdata *rdp, const void *id, int type)
{
struct ident *ip;
for (ip = rdp->ident; ip->id != NULL; ip++)
if ((int) ip->type == type && strcasecmp(ip->id, id) == 0)
return ip->p;
return NULL;
}
/*
* Parse an regdomain XML configuration and build the internal representation.
*/
int
lib80211_regdomain_readconfig(struct regdata *rdp, const void *p, size_t len)
{
struct mystate *mt;
struct regdomain *dp;
struct country *cp;
struct freqband *fp;
struct netband *nb;
const void *id;
int i, errors;
memset(rdp, 0, sizeof(struct regdata));
mt = calloc(1, sizeof(struct mystate));
if (mt == NULL)
return ENOMEM;
/* parse the XML input */
mt->rdp = rdp;
mt->parser = XML_ParserCreate(NULL);
XML_SetUserData(mt->parser, mt);
XML_SetElementHandler(mt->parser, start_element, end_element);
XML_SetCharacterDataHandler(mt->parser, char_data);
if (XML_Parse(mt->parser, p, len, 1) != XML_STATUS_OK) {
warnx("%s: %s at line %ld", __func__,
XML_ErrorString(XML_GetErrorCode(mt->parser)),
XML_GetCurrentLineNumber(mt->parser));
return -1;
}
XML_ParserFree(mt->parser);
/* setup the identifer table */
rdp->ident = calloc(sizeof(struct ident), mt->nident + 1);
if (rdp->ident == NULL)
return ENOMEM;
free(mt);
errors = 0;
i = 0;
LIST_FOREACH(dp, &rdp->domains, next) {
rdp->ident[i].id = dp->name;
rdp->ident[i].p = dp;
rdp->ident[i].type = DOMAIN;
i++;
}
LIST_FOREACH(fp, &rdp->freqbands, next) {
rdp->ident[i].id = fp->id;
rdp->ident[i].p = fp;
rdp->ident[i].type = FREQBAND;
i++;
}
LIST_FOREACH(cp, &rdp->countries, next) {
rdp->ident[i].id = cp->isoname;
rdp->ident[i].p = cp;
rdp->ident[i].type = COUNTRY;
i++;
}
/* patch references */
LIST_FOREACH(dp, &rdp->domains, next) {
if (dp->cc != NULL) {
id = dp->cc;
dp->cc = findid(rdp, id, COUNTRY);
if (dp->cc == NULL) {
warnx("undefined country \"%s\"",
__DECONST(char *, id));
errors++;
}
free(__DECONST(char *, id));
}
LIST_FOREACH(nb, &dp->bands_11b, next) {
id = findid(rdp, nb->band, FREQBAND);
if (id == NULL) {
warnx("undefined 11b band \"%s\"",
__DECONST(char *, nb->band));
errors++;
}
nb->band = id;
}
LIST_FOREACH(nb, &dp->bands_11g, next) {
id = findid(rdp, nb->band, FREQBAND);
if (id == NULL) {
warnx("undefined 11g band \"%s\"",
__DECONST(char *, nb->band));
errors++;
}
nb->band = id;
}
LIST_FOREACH(nb, &dp->bands_11a, next) {
id = findid(rdp, nb->band, FREQBAND);
if (id == NULL) {
warnx("undefined 11a band \"%s\"",
__DECONST(char *, nb->band));
errors++;
}
nb->band = id;
}
LIST_FOREACH(nb, &dp->bands_11ng, next) {
id = findid(rdp, nb->band, FREQBAND);
if (id == NULL) {
warnx("undefined 11ng band \"%s\"",
__DECONST(char *, nb->band));
errors++;
}
nb->band = id;
}
LIST_FOREACH(nb, &dp->bands_11na, next) {
id = findid(rdp, nb->band, FREQBAND);
if (id == NULL) {
warnx("undefined 11na band \"%s\"",
__DECONST(char *, nb->band));
errors++;
}
nb->band = id;
}
}
LIST_FOREACH(cp, &rdp->countries, next) {
id = cp->rd;
cp->rd = findid(rdp, id, DOMAIN);
if (cp->rd == NULL) {
warnx("undefined country \"%s\"",
__DECONST(char *, id));
errors++;
}
free(__DECONST(char *, id));
}
return errors ? EINVAL : 0;
}
static void
cleanup_bands(netband_head *head)
{
struct netband *nb;
for (;;) {
nb = LIST_FIRST(head);
if (nb == NULL)
break;
free(nb);
}
}
/*
* Cleanup state/resources for a previously parsed regdomain database.
*/
void
lib80211_regdomain_cleanup(struct regdata *rdp)
{
free(rdp->ident);
rdp->ident = NULL;
for (;;) {
struct regdomain *dp = LIST_FIRST(&rdp->domains);
if (dp == NULL)
break;
LIST_REMOVE(dp, next);
cleanup_bands(&dp->bands_11b);
cleanup_bands(&dp->bands_11g);
cleanup_bands(&dp->bands_11a);
cleanup_bands(&dp->bands_11ng);
cleanup_bands(&dp->bands_11na);
if (dp->name != NULL)
free(__DECONST(char *, dp->name));
}
for (;;) {
struct country *cp = LIST_FIRST(&rdp->countries);
if (cp == NULL)
break;
LIST_REMOVE(cp, next);
if (cp->name != NULL)
free(__DECONST(char *, cp->name));
free(cp);
}
for (;;) {
struct freqband *fp = LIST_FIRST(&rdp->freqbands);
if (fp == NULL)
break;
LIST_REMOVE(fp, next);
free(fp);
}
}
struct regdata *
lib80211_alloc_regdata(void)
{
struct regdata *rdp;
struct stat sb;
void *xml;
int fd;
rdp = calloc(1, sizeof(struct regdata));
fd = open(_PATH_REGDOMAIN, O_RDONLY);
if (fd < 0) {
#ifdef DEBUG
warn("%s: open(%s)", __func__, _PATH_REGDOMAIN);
#endif
free(rdp);
return NULL;
}
if (fstat(fd, &sb) < 0) {
#ifdef DEBUG
warn("%s: fstat(%s)", __func__, _PATH_REGDOMAIN);
#endif
close(fd);
free(rdp);
return NULL;
}
xml = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (xml == MAP_FAILED) {
#ifdef DEBUG
warn("%s: mmap", __func__);
#endif
close(fd);
free(rdp);
return NULL;
}
if (lib80211_regdomain_readconfig(rdp, xml, sb.st_size) != 0) {
#ifdef DEBUG
warn("%s: error reading regulatory database", __func__);
#endif
munmap(xml, sb.st_size);
close(fd);
free(rdp);
return NULL;
}
munmap(xml, sb.st_size);
close(fd);
return rdp;
}
void
lib80211_free_regdata(struct regdata *rdp)
{
lib80211_regdomain_cleanup(rdp);
free(rdp);
}
/*
* Lookup a regdomain by SKU.
*/
const struct regdomain *
lib80211_regdomain_findbysku(const struct regdata *rdp, enum RegdomainCode sku)
{
const struct regdomain *dp;
LIST_FOREACH(dp, &rdp->domains, next) {
if (dp->sku == sku)
return dp;
}
return NULL;
}
/*
* Lookup a regdomain by name.
*/
const struct regdomain *
lib80211_regdomain_findbyname(const struct regdata *rdp, const char *name)
{
const struct regdomain *dp;
LIST_FOREACH(dp, &rdp->domains, next) {
if (strcasecmp(dp->name, name) == 0)
return dp;
}
return NULL;
}
/*
* Lookup a country by ISO country code.
*/
const struct country *
lib80211_country_findbycc(const struct regdata *rdp, enum ISOCountryCode cc)
{
const struct country *cp;
LIST_FOREACH(cp, &rdp->countries, next) {
if (cp->code == cc)
return cp;
}
return NULL;
}
/*
* Lookup a country by ISO/long name.
*/
const struct country *
lib80211_country_findbyname(const struct regdata *rdp, const char *name)
{
const struct country *cp;
int len;
len = strlen(name);
LIST_FOREACH(cp, &rdp->countries, next) {
if (strcasecmp(cp->isoname, name) == 0)
return cp;
}
LIST_FOREACH(cp, &rdp->countries, next) {
if (strncasecmp(cp->name, name, len) == 0)
return cp;
}
return NULL;
}

View file

@ -0,0 +1,121 @@
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* 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 ``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 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$
*/
#ifndef _LIB80211_REGDOMAIN_H_
#define _LIB80211_REGDOMAIN_H_
#include <sys/cdefs.h>
#include <sys/queue.h>
#include <net80211/ieee80211_regdomain.h>
__BEGIN_DECLS
struct freqband {
uint16_t freqStart; /* starting frequency (MHz) */
uint16_t freqEnd; /* ending frequency (MHz) */
uint8_t chanWidth; /* channel width (MHz) */
uint8_t chanSep; /* channel sepaaration (MHz) */
uint32_t flags; /* common operational constraints */
const void *id;
LIST_ENTRY(freqband) next;
};
/* private flags, don't pass to os */
#define REQ_ECM 0x1 /* enable if ECM set */
#define REQ_INDOOR 0x2 /* enable only for indoor operation */
#define REQ_OUTDOOR 0x4 /* enable only for outdoor operation */
#define REQ_FLAGS (REQ_ECM|REQ_INDOOR|REQ_OUTDOOR)
struct netband {
const struct freqband *band; /* channel list description */
uint8_t maxPower; /* regulatory cap on tx power (dBm) */
uint8_t maxPowerDFS; /* regulatory cap w/ DFS (dBm) */
uint8_t maxAntGain; /* max allowed antenna gain (.5 dBm) */
uint32_t flags; /* net80211 channel flags */
LIST_ENTRY(netband) next;
};
typedef LIST_HEAD(, netband) netband_head;
struct country;
struct regdomain {
enum RegdomainCode sku; /* regdomain code/SKU */
const char *name; /* printable name */
const struct country *cc; /* country code for 1-1/default map */
netband_head bands_11b; /* 11b operation */
netband_head bands_11g; /* 11g operation */
netband_head bands_11a; /* 11a operation */
netband_head bands_11ng;/* 11ng operation */
netband_head bands_11na;/* 11na operation */
LIST_ENTRY(regdomain) next;
};
struct country {
enum ISOCountryCode code;
#define NO_COUNTRY 0xffff
const struct regdomain *rd;
const char* isoname;
const char* name;
LIST_ENTRY(country) next;
};
struct ident;
struct regdata {
LIST_HEAD(, country) countries; /* country code table */
LIST_HEAD(, regdomain) domains; /* regulatory domains */
LIST_HEAD(, freqband) freqbands; /* frequency band table */
struct ident *ident; /* identifier table */
};
#define _PATH_REGDOMAIN "/etc/regdomain.xml"
struct regdata *lib80211_alloc_regdata(void);
void lib80211_free_regdata(struct regdata *);
int lib80211_regdomain_readconfig(struct regdata *, const void *, size_t);
void lib80211_regdomain_cleanup(struct regdata *);
const struct regdomain *lib80211_regdomain_findbysku(const struct regdata *,
enum RegdomainCode);
const struct regdomain *lib80211_regdomain_findbyname(const struct regdata *,
const char *);
const struct country *lib80211_country_findbycc(const struct regdata *,
enum ISOCountryCode);
const struct country *lib80211_country_findbyname(const struct regdata *,
const char *);
__END_DECLS
#endif /* _LIB80211_REGDOMAIN_H_ */