Implementation of the upcoming Wireless Mesh standard, 802.11s, on the

net80211 wireless stack. This work is based on the March 2009 D3.0 draft
standard. This standard is expected to become final next year.
This includes two main net80211 modules, ieee80211_mesh.c
which deals with peer link management, link metric calculation,
routing table control and mesh configuration and ieee80211_hwmp.c
which deals with the actually routing process on the mesh network.
HWMP is the mandatory routing protocol on by the mesh standard, but
others, such as RA-OLSR, can be implemented.

Authentication and encryption are not implemented.

There are several scripts under tools/tools/net80211/scripts that can be
used to test different mesh network topologies and they also teach you
how to setup a mesh vap (for the impatient: ifconfig wlan0 create
wlandev ... wlanmode mesh).

A new build option is available: IEEE80211_SUPPORT_MESH and it's enabled
by default on GENERIC kernels for i386, amd64, sparc64 and pc98.

Drivers that support mesh networks right now are: ath, ral and mwl.

More information at: http://wiki.freebsd.org/WifiMesh

Please note that this work is experimental. Also, please note that
bridging a mesh vap with another network interface is not yet supported.

Many thanks to the FreeBSD Foundation for sponsoring this project and to
Sam Leffler for his support.
Also, I would like to thank Gateworks Corporation for sending me a
Cambria board which was used during the development of this project.

Reviewed by:	sam
Approved by:	re (kensmith)
Obtained from:	projects/mesh11s
This commit is contained in:
Rui Paulo 2009-07-11 15:02:45 +00:00
parent 35ea6959ac
commit 59aa14a91d
52 changed files with 6014 additions and 205 deletions

View File

@ -28,7 +28,7 @@
.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
.\" $FreeBSD$
.\"
.Dd June 24, 2009
.Dd July 8, 2009
.Dt IFCONFIG 8
.Os
.Sh NAME
@ -623,6 +623,7 @@ is one of
.Cm hostap ),
.Cm wds ,
.Cm tdma ,
.Cm mesh ,
and
.Cm monitor .
The operating mode of a cloned interface cannot be changed.
@ -1195,6 +1196,9 @@ indicates the address is denied access,
.Ql *
indicates the address is present but the current policy open
(so the ACL is not consulted).
.It Cm list mesh
Displays the mesh routing table, used for forwarding packets on a mesh
network.
.It Cm list regdomain
Display the current regulatory settings including the available channels
and transmit power caps.
@ -1278,6 +1282,8 @@ When operating as an access point display the stations that are
currently associated.
When operating in ad-hoc mode display stations identified as
neighbors in the IBSS.
When operating in mesh mode display stations identified as
neighbors in the MBSS.
When operating in station mode display the access point.
Capabilities advertised by the stations are described under
the
@ -1813,6 +1819,85 @@ as it handles the RADIUS processing
(and marks stations as authorized).
.El
.Pp
The following parameters are related to a wireless interface operating in mesh
mode:
.Bl -tag -width indent
.It Cm meshid Ar meshid
Set the desired Mesh Identifier.
The Mesh ID is a string up to 32 characters in length.
A mesh interface must have a Mesh Identifier specified
to reach an operational state.
.It Cm meshttl Ar ttl
Set the desired ``time to live'' for mesh forwarded packets;
this is the number of hops a packet may be forwarded before
it is discarded.
The default setting for
.Cm meshttl
is 31.
.It Cm meshpeering
Enable or disable peering with neighbor mesh stations.
Stations must peer before any data packets can be exchanged.
By default
.Cm meshpeering
is enabled.
.It Cm meshforward
Enable or disable forwarding packets by a mesh interface.
By default
.Cm meshforward
is enabled.
.It Cm meshmetric Ar protocol
Set the specified
.Ar protocol
as the link metric protocol used on a mesh network.
The default protocol is called
.Ar AIRTIME .
The mesh interface will restart after changing this setting.
.It Cm meshpath Ar protocol
Set the specified
.Ar protocol
as the path selection protocol used on a mesh network.
The only available protocol at the moment is called
.Ar HWMP
(Hybrid Wireless Mesh Protocol).
The mesh interface will restart after changing this setting.
.It Cm hwmprootmode Ar mode
Stations on a mesh network can operate as ``root nodes.''
Root nodes try to find paths to all mesh nodes and advertise themselves
regularly.
When there is a root mesh node on a network, other mesh nodes can setup
paths between themselves faster because they can use the root node
to find the destination.
This path may not be the best, but on-demand
routing will eventually find the best path.
The following modes are recognized:
.Pp
.Bl -tag -width ".Cm PROACTIVE" -compact
.It Cm DISABLED
Disable root mode.
.It Cm NORMAL
Send broadcast path requests every two seconds.
Nodes on the mesh without a path to this root mesh station with try to
discover a path to us.
.It Cm PROACTIVE
Send broadcast path requests every two seconds and every node must reply with
with a path reply even if it already has a path to this root mesh station,
.It Cm RANN
Send broadcast root annoucement (RANN) frames.
Nodes on the mesh without a path to this root mesh station with try to
discover a path to us.
.El
By default
.Cm hwmprootmode
is set to
.Ar DISABLED .
.It Cm hwmpmaxhops Ar cnt
Set the maximum number of hops allowed in an HMWP path to
.Ar cnt .
The default setting for
.Cm hwmpmaxhops
is 31.
.El
.Pp
The following parameters are for compatibility with other systems:
.Bl -tag -width indent
.It Cm nwid Ar ssid

View File

@ -81,6 +81,7 @@
#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>
@ -162,6 +163,7 @@ static void print_channels(int, const struct ieee80211req_chaninfo *,
int allchans, int verbose);
static void regdomain_makechannels(struct ieee80211_regdomain_req *,
const struct ieee80211_devcaps_req *);
static const char *mesh_linkstate_string(uint8_t state);
static struct ieee80211req_chaninfo *chaninfo;
static struct ieee80211_regdomain regdomain;
@ -574,6 +576,20 @@ set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
}
static void
set80211meshid(const char *val, int d, int s, const struct afswtch *rafp)
{
int len;
u_int8_t data[IEEE80211_NWID_LEN];
memset(data, 0, sizeof(data));
len = sizeof(data);
if (get_string(val, NULL, data, &len) == NULL)
exit(1);
set80211(s, IEEE80211_IOC_MESH_ID, 0, len, data);
}
static void
set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
{
@ -1261,6 +1277,66 @@ DECL_CMD_FUNC(set80211maccmd, val, d)
set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
}
static void
set80211meshrtmac(int s, int req, const char *val)
{
char *temp;
struct sockaddr_dl sdl;
temp = malloc(strlen(val) + 2); /* ':' and '\0' */
if (temp == NULL)
errx(1, "malloc failed");
temp[0] = ':';
strcpy(temp + 1, val);
sdl.sdl_len = sizeof(sdl);
link_addr(temp, &sdl);
free(temp);
if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
errx(1, "malformed link-level address");
set80211(s, IEEE80211_IOC_MESH_RTCMD, req,
IEEE80211_ADDR_LEN, LLADDR(&sdl));
}
static
DECL_CMD_FUNC(set80211addmeshrt, val, d)
{
set80211meshrtmac(s, IEEE80211_MESH_RTCMD_ADD, val);
}
static
DECL_CMD_FUNC(set80211delmeshrt, val, d)
{
set80211meshrtmac(s, IEEE80211_MESH_RTCMD_DELETE, val);
}
static
DECL_CMD_FUNC(set80211meshrtcmd, val, d)
{
set80211(s, IEEE80211_IOC_MESH_RTCMD, d, 0, NULL);
}
static
DECL_CMD_FUNC(set80211hwmprootmode, val, d)
{
int mode;
if (strcasecmp(val, "normal") == 0)
mode = IEEE80211_HWMP_ROOTMODE_NORMAL;
else if (strcasecmp(val, "proactive") == 0)
mode = IEEE80211_HWMP_ROOTMODE_PROACTIVE;
else if (strcasecmp(val, "rann") == 0)
mode = IEEE80211_HWMP_ROOTMODE_RANN;
else
mode = IEEE80211_HWMP_ROOTMODE_DISABLED;
set80211(s, IEEE80211_IOC_HWMP_ROOTMODE, mode, 0, NULL);
}
static
DECL_CMD_FUNC(set80211hwmpmaxhops, val, d)
{
set80211(s, IEEE80211_IOC_HWMP_MAXHOPS, atoi(val), 0, NULL);
}
static void
set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
{
@ -1771,6 +1847,42 @@ DECL_CMD_FUNC(set80211tdmabintval, val, d)
set80211(s, IEEE80211_IOC_TDMA_BINTERVAL, atoi(val), 0, NULL);
}
static
DECL_CMD_FUNC(set80211meshttl, val, d)
{
set80211(s, IEEE80211_IOC_MESH_TTL, atoi(val), 0, NULL);
}
static
DECL_CMD_FUNC(set80211meshforward, val, d)
{
set80211(s, IEEE80211_IOC_MESH_FWRD, atoi(val), 0, NULL);
}
static
DECL_CMD_FUNC(set80211meshpeering, val, d)
{
set80211(s, IEEE80211_IOC_MESH_AP, atoi(val), 0, NULL);
}
static
DECL_CMD_FUNC(set80211meshmetric, val, d)
{
char v[12];
memcpy(v, val, sizeof(v));
set80211(s, IEEE80211_IOC_MESH_PR_METRIC, 0, 0, v);
}
static
DECL_CMD_FUNC(set80211meshpath, val, d)
{
char v[12];
memcpy(v, val, sizeof(v));
set80211(s, IEEE80211_IOC_MESH_PR_PATH, 0, 0, v);
}
static int
regdomain_sort(const void *a, const void *b)
{
@ -2498,6 +2610,45 @@ printathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
}
}
static void
printmeshconf(const char *tag, const uint8_t *ie, size_t ielen, int maxlen)
{
#define MATCHOUI(field, oui, string) \
do { \
if (memcmp(field, oui, 4) == 0) \
printf("%s", string); \
} while (0)
printf("%s", tag);
if (verbose) {
const struct ieee80211_meshconf_ie *mconf =
(const struct ieee80211_meshconf_ie *)ie;
const uint8_t null[4] = IEEE80211_MESHCONF_NULL;
const uint8_t hwmp[4] = IEEE80211_MESHCONF_HWMP;
const uint8_t airtime[4] = IEEE80211_MESHCONF_AIRTIME;
const uint8_t ccsig[4] = IEEE80211_MESHCONF_CCSIG;
const uint8_t sae[4] = IEEE80211_MESHCONF_SAE;
const uint8_t neighoff[4] = IEEE80211_MESHCONF_SAE;
printf("<v%d PATH:", mconf->conf_ver);
MATCHOUI(mconf->conf_pselid, hwmp, "HWMP");
printf(" LINK:");
MATCHOUI(mconf->conf_pmetid, airtime, "AIRTIME");
printf(" CONGESTION:");
MATCHOUI(mconf->conf_ccid, ccsig, "SIG");
MATCHOUI(mconf->conf_ccid, null, "NULL");
printf(" SYNC:");
MATCHOUI(mconf->conf_syncid, neighoff, "NEIGHOFF");
MATCHOUI(mconf->conf_syncid, null, "NULL");
printf(" AUTH:");
MATCHOUI(mconf->conf_authid, sae, "SAE");
MATCHOUI(mconf->conf_authid, null, "NULL");
printf(" FORM:0x%x CAPS:0x%x>", mconf->conf_form,
mconf->conf_cap);
}
#undef MATCHOUI
}
static const char *
wpa_cipher(const u_int8_t *sel)
{
@ -2968,6 +3119,13 @@ printies(const u_int8_t *vp, int ielen, int maxcols)
if (verbose)
printhtinfo(" HTINFO", vp, 2+vp[1], maxcols);
break;
case IEEE80211_ELEMID_MESHID:
if (verbose)
printssid(" MESHID", vp, 2+vp[1], maxcols);
break;
case IEEE80211_ELEMID_MESHCONF:
printmeshconf(" MESHCONF", vp, 2+vp[1], maxcols);
break;
default:
if (verbose)
printie(iename(vp[0]), vp, 2+vp[1], maxcols);
@ -2996,7 +3154,7 @@ list_scan(int s)
uint8_t buf[24*1024];
char ssid[IEEE80211_NWID_LEN+1];
const uint8_t *cp;
int len, ssidmax;
int len, ssidmax, idlen;
if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0)
errx(1, "unable to get scan results");
@ -3005,9 +3163,9 @@ list_scan(int s)
getchaninfo(s);
ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
ssidmax = verbose ? IEEE80211_NWID_LEN - 1 : 14;
printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n"
, ssidmax, ssidmax, "SSID"
, ssidmax, ssidmax, "SSID/MESH ID"
, "BSSID"
, "CHAN"
, "RATE"
@ -3018,13 +3176,20 @@ list_scan(int s)
cp = buf;
do {
const struct ieee80211req_scan_result *sr;
const uint8_t *vp;
const uint8_t *vp, *idp;
sr = (const struct ieee80211req_scan_result *) cp;
vp = cp + sr->isr_ie_off;
if (sr->isr_meshid_len) {
idp = vp + sr->isr_ssid_len;
idlen = sr->isr_meshid_len;
} else {
idp = vp;
idlen = sr->isr_ssid_len;
}
printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s"
, ssidmax
, copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
, copy_essid(ssid, ssidmax, idp, idlen)
, ssid
, ether_ntoa((const struct ether_addr *) sr->isr_bssid)
, ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags)
@ -3033,7 +3198,8 @@ list_scan(int s)
, sr->isr_intval
, getcaps(sr->isr_capinfo)
);
printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);
printies(vp + sr->isr_ssid_len + sr->isr_meshid_len,
sr->isr_ie_len, 24);
printf("\n");
cp += sr->isr_len, len -= sr->isr_len;
} while (len >= sizeof(struct ieee80211req_scan_result));
@ -3151,18 +3317,32 @@ list_stations(int s)
getchaninfo(s);
printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %-7s\n"
, "ADDR"
, "AID"
, "CHAN"
, "RATE"
, "RSSI"
, "IDLE"
, "TXSEQ"
, "RXSEQ"
, "CAPS"
, "FLAG"
);
if (opmode == IEEE80211_M_MBSS)
printf("%-17.17s %4s %5s %5s %7s %4s %4s %4s %6s %6s\n"
, "ADDR"
, "CHAN"
, "LOCAL"
, "PEER"
, "STATE"
, "RATE"
, "RSSI"
, "IDLE"
, "TXSEQ"
, "RXSEQ"
);
else
printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %-7s\n"
, "ADDR"
, "AID"
, "CHAN"
, "RATE"
, "RSSI"
, "IDLE"
, "TXSEQ"
, "RXSEQ"
, "CAPS"
, "FLAG"
);
cp = (const uint8_t *) u.req.info;
do {
const struct ieee80211req_sta_info *si;
@ -3170,18 +3350,36 @@ list_stations(int s)
si = (const struct ieee80211req_sta_info *) cp;
if (si->isi_len < sizeof(*si))
break;
printf("%s %4u %4d %3dM %3.1f %4d %6d %6d %-4.4s %-7.7s"
, ether_ntoa((const struct ether_addr*) si->isi_macaddr)
, IEEE80211_AID(si->isi_associd)
, ieee80211_mhz2ieee(si->isi_freq, si->isi_flags)
, si->isi_txmbps/2
, si->isi_rssi/2.
, si->isi_inact
, gettxseq(si)
, getrxseq(si)
, getcaps(si->isi_capinfo)
, getflags(si->isi_state)
);
if (opmode == IEEE80211_M_MBSS)
printf("%s %4d %5x %5x %7.7s %3dM %4.1f %4d %6d %6d"
, ether_ntoa((const struct ether_addr*)
si->isi_macaddr)
, ieee80211_mhz2ieee(si->isi_freq,
si->isi_flags)
, si->isi_localid
, si->isi_peerid
, mesh_linkstate_string(si->isi_peerstate)
, si->isi_txmbps/2
, si->isi_rssi/2.
, si->isi_inact
, gettxseq(si)
, getrxseq(si)
);
else
printf("%s %4u %4d %3dM %4.1f %4d %6d %6d %-4.4s %-7.7s"
, ether_ntoa((const struct ether_addr*)
si->isi_macaddr)
, IEEE80211_AID(si->isi_associd)
, ieee80211_mhz2ieee(si->isi_freq,
si->isi_flags)
, si->isi_txmbps/2
, si->isi_rssi/2.
, si->isi_inact
, gettxseq(si)
, getrxseq(si)
, getcaps(si->isi_capinfo)
, getflags(si->isi_state)
);
printies(cp + si->isi_ie_off, si->isi_ie_len, 24);
printmimo(&si->isi_mimo);
printf("\n");
@ -3189,6 +3387,28 @@ list_stations(int s)
} while (len >= sizeof(struct ieee80211req_sta_info));
}
static const char *
mesh_linkstate_string(uint8_t state)
{
#define N(a) (sizeof(a) / sizeof(a[0]))
static const char *state_names[] = {
[0] = "IDLE",
[1] = "OPEN-TX",
[2] = "OPEN-RX",
[3] = "CONF-RX",
[4] = "ESTAB",
[5] = "HOLDING",
};
if (state >= N(state_names)) {
static char buf[10];
snprintf(buf, sizeof(buf), "#%u", state);
return buf;
} else
return state_names[state];
#undef N
}
static const char *
get_chaninfo(const struct ieee80211_channel *c, int precise,
char buf[], size_t bsize)
@ -3409,9 +3629,9 @@ list_keys(int s)
}
#define IEEE80211_C_BITS \
"\20\1STA\7FF\10TURBOP\11IBSS\12PMGT" \
"\20\1STA\002803ENCAP\7FF\10TURBOP\11IBSS\12PMGT" \
"\13HOSTAP\14AHDEMO\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE" \
"\21MONITOR\22DFS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \
"\21MONITOR\22DFS\23MBSS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \
"\37TXFRAG\40TDMA"
static void
@ -3729,6 +3949,40 @@ list_regdomain(int s, int channelsalso)
print_regdomain(&regdomain, verbose);
}
static void
list_mesh(int s)
{
int i;
struct ieee80211req ireq;
struct ieee80211req_mesh_route routes[128];
(void) memset(&ireq, 0, sizeof(ireq));
(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
ireq.i_type = IEEE80211_IOC_MESH_RTCMD;
ireq.i_val = IEEE80211_MESH_RTCMD_LIST;
ireq.i_data = &routes;
ireq.i_len = sizeof(routes);
if (ioctl(s, SIOCG80211, &ireq) < 0)
err(1, "unable to get the Mesh routing table");
printf("%-17.17s %-17.17s %4s %4s %4s\n"
, "DEST"
, "NEXT HOP"
, "HOPS"
, "METRIC"
, "LIFETIME");
for (i = 0; i < ireq.i_len / sizeof(*routes); i++) {
printf("%s ",
ether_ntoa((const struct ether_addr *)routes[i].imr_dest));
printf("%s %4u %4d %6d\n",
ether_ntoa((const struct ether_addr *)
routes[i].imr_nexthop),
routes[i].imr_nhops, routes[i].imr_metric,
routes[i].imr_lifetime);
}
}
static
DECL_CMD_FUNC(set80211list, arg, d)
{
@ -3762,6 +4016,8 @@ DECL_CMD_FUNC(set80211list, arg, d)
list_regdomain(s, 1);
else if (iseq(arg, "countries"))
list_countries();
else if (iseq(arg, "mesh"))
list_mesh(s);
else
errx(1, "Don't know how to list %s for %s", arg, name);
LINE_BREAK();
@ -3787,6 +4043,8 @@ get80211opmode(int s)
return IEEE80211_M_HOSTAP;
if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
return IEEE80211_M_MONITOR;
if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
return IEEE80211_M_MBSS;
}
return IEEE80211_M_STA;
}
@ -3911,13 +4169,13 @@ printrate(const char *tag, int v, int defrate, int defmcs)
}
static int
getssid(int s, int ix, void *data, size_t len, int *plen)
getid(int s, int ix, void *data, size_t len, int *plen, int mesh)
{
struct ieee80211req ireq;
(void) memset(&ireq, 0, sizeof(ireq));
(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
ireq.i_type = IEEE80211_IOC_SSID;
ireq.i_type = (!mesh) ? IEEE80211_IOC_SSID : IEEE80211_IOC_MESH_ID;
ireq.i_val = ix;
ireq.i_data = data;
ireq.i_len = len;
@ -3938,7 +4196,7 @@ ieee80211_status(int s)
const struct ieee80211_roamparam *rp;
const struct ieee80211_txparam *tp;
if (getssid(s, -1, data, sizeof(data), &len) < 0) {
if (getid(s, -1, data, sizeof(data), &len, 0) < 0) {
/* If we can't get the SSID, this isn't an 802.11 device. */
return;
}
@ -3953,19 +4211,25 @@ ieee80211_status(int s)
gothtconf = 0;
gotregdomain = 0;
if (get80211val(s, IEEE80211_IOC_NUMSSIDS, &num) < 0)
num = 0;
printf("\tssid ");
if (num > 1) {
for (i = 0; i < num; i++) {
if (getssid(s, i, data, sizeof(data), &len) >= 0 && len > 0) {
printf(" %d:", i + 1);
print_string(data, len);
}
}
} else
printf("\t");
if (opmode == IEEE80211_M_MBSS) {
printf("meshid ");
getid(s, 0, data, sizeof(data), &len, 1);
print_string(data, len);
} else {
if (get80211val(s, IEEE80211_IOC_NUMSSIDS, &num) < 0)
num = 0;
printf("ssid ");
if (num > 1) {
for (i = 0; i < num; i++) {
if (getid(s, i, data, sizeof(data), &len, 0) >= 0 && len > 0) {
printf(" %d:", i + 1);
print_string(data, len);
}
}
} else
print_string(data, len);
}
c = getcurchan(s);
if (c->ic_freq != IEEE80211_CHAN_ANY) {
char buf[14];
@ -4515,6 +4779,57 @@ end:
LINE_BREAK();
list_wme(s);
}
if (opmode == IEEE80211_M_MBSS) {
if (get80211val(s, IEEE80211_IOC_MESH_TTL, &val) != -1) {
LINE_CHECK("meshttl %u", val);
}
if (get80211val(s, IEEE80211_IOC_MESH_AP, &val) != -1) {
if (val)
LINE_CHECK("meshpeering");
else
LINE_CHECK("-meshpeering");
}
if (get80211val(s, IEEE80211_IOC_MESH_FWRD, &val) != -1) {
if (val)
LINE_CHECK("meshforward");
else
LINE_CHECK("-meshforward");
}
if (get80211len(s, IEEE80211_IOC_MESH_PR_METRIC, data, 12,
&len) != -1) {
data[len] = '\0';
LINE_CHECK("meshmetric %s", data);
}
if (get80211len(s, IEEE80211_IOC_MESH_PR_PATH, data, 12,
&len) != -1) {
data[len] = '\0';
LINE_CHECK("meshpath %s", data);
}
if (get80211val(s, IEEE80211_IOC_HWMP_ROOTMODE, &val) != -1) {
switch (val) {
case IEEE80211_HWMP_ROOTMODE_DISABLED:
LINE_CHECK("hwmprootmode DISABLED");
break;
case IEEE80211_HWMP_ROOTMODE_NORMAL:
LINE_CHECK("hwmprootmode NORMAL");
break;
case IEEE80211_HWMP_ROOTMODE_PROACTIVE:
LINE_CHECK("hwmprootmode PROACTIVE");
break;
case IEEE80211_HWMP_ROOTMODE_RANN:
LINE_CHECK("hwmprootmode RANN");
break;
default:
LINE_CHECK("hwmprootmode UNKNOWN(%d)", val);
break;
}
}
if (get80211val(s, IEEE80211_IOC_HWMP_MAXHOPS, &val) != -1) {
LINE_CHECK("hwmpmaxhops %u", val);
}
}
LINE_BREAK();
}
@ -4731,7 +5046,9 @@ DECL_CMD_FUNC(set80211clone_wlanmode, arg, d)
else if (iseq(arg, "tdma")) {
params.icp_opmode = IEEE80211_M_AHDEMO;
params.icp_flags |= IEEE80211_CLONE_TDMA;
} else
} else if (iseq(arg, "mesh") || iseq(arg, "mp")) /* mesh point */
params.icp_opmode = IEEE80211_M_MBSS;
else
errx(1, "Don't know to create %s for %s", arg, name);
#undef iseq
}
@ -4767,6 +5084,7 @@ set80211clone_wdslegacy(const char *val, int d, int s, const struct afswtch *raf
static struct cmd ieee80211_cmds[] = {
DEF_CMD_ARG("ssid", set80211ssid),
DEF_CMD_ARG("nwid", set80211ssid),
DEF_CMD_ARG("meshid", set80211meshid),
DEF_CMD_ARG("stationname", set80211stationname),
DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */
DEF_CMD_ARG("channel", set80211channel),
@ -4908,6 +5226,19 @@ static struct cmd ieee80211_cmds[] = {
DEF_CMD_ARG("tdmaslotlen", set80211tdmaslotlen),
DEF_CMD_ARG("tdmabintval", set80211tdmabintval),
DEF_CMD_ARG("meshttl", set80211meshttl),
DEF_CMD("meshforward", 1, set80211meshforward),
DEF_CMD("-meshforward", 0, set80211meshforward),
DEF_CMD("meshpeering", 1, set80211meshpeering),
DEF_CMD("-meshpeering", 0, set80211meshpeering),
DEF_CMD_ARG("meshmetric", set80211meshmetric),
DEF_CMD_ARG("meshpath", set80211meshpath),
DEF_CMD("meshrt:flush", IEEE80211_MESH_RTCMD_FLUSH, set80211meshrtcmd),
DEF_CMD_ARG("meshrt:add", set80211addmeshrt),
DEF_CMD_ARG("meshrt:del", set80211delmeshrt),
DEF_CMD_ARG("hwmprootmode", set80211hwmprootmode),
DEF_CMD_ARG("hwmpmaxhops", set80211hwmpmaxhops),
/* vap cloning support */
DEF_CLONE_CMD_ARG("wlanaddr", set80211clone_wlanaddr),
DEF_CLONE_CMD_ARG("wlanbssid", set80211clone_wlanbssid),

View File

@ -104,7 +104,8 @@ static struct ifmedia_description *get_subtype_desc(int,
#define IFM_OPMODE(x) \
((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \
IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR))
IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR | \
IFM_IEEE80211_MBSS))
#define IFM_IEEE80211_STA 0
static void

View File

@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"/
.Dd March 25, 2009
.Dd July 8, 2009
.Dt ATH 4
.Os
.Sh NAME
@ -61,7 +61,7 @@ These APIs are used by a wide variety of chips; most all chips with
a PCI and/or CardBus interface are supported.
.Pp
Supported features include 802.11 and 802.3 frames, power management, BSS,
IBSS, TDMA, and host-based access point operation modes.
IBSS, MBSS, TDMA, and host-based access point operation modes.
All host/device interaction is via DMA.
.Pp
The
@ -102,6 +102,7 @@ The driver supports
.Cm adhoc ,
.Cm adhoc-demo ,
.Cm hostap ,
.Cm mesh ,
.Cm wds ,
and
.Cm monitor
@ -175,6 +176,12 @@ ifconfig wlan0 inet 192.168.0.10 netmask 0xffffff00 ssid my_ap \e
mode 11g
.Ed
.Pp
Create an 802.11a mesh station:
.Bd -literal -offset indent
ifconfig wlan0 create wlandev ath0 wlanmode mesh
ifconfig wlan0 meshid my_mesh mode 11a inet 192.168.0.10/24
.Ed
.Pp
Create two virtual 802.11a host-based access points, one with
with WEP enabled and one with no security, and bridge them to
the fxp0 (wired) device:

View File

@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"/
.Dd June 9, 2009
.Dd July 8, 2009
.Dt MWL 4
.Os
.Sh NAME
@ -64,7 +64,7 @@ module to work.
Normally this module is loaded on demand by the driver but it may
also be compiled into the kernel.
.Pp
Supported features include 802.11n, power management, BSS,
Supported features include 802.11n, power management, BSS, MBSS,
and host-based access point operation modes.
All host/device interaction is via DMA.
.Pp
@ -83,6 +83,7 @@ AES-CCM, TKIP, and Michael cryptographic operations.
The driver supports
.Cm station ,
.Cm hostap ,
.Cm mesh ,
and
.Cm wds
mode operation.
@ -139,6 +140,12 @@ ifconfig wlan0 inet 192.168.0.10 netmask 0xffffff00 ssid my_ap \e
mode 11g
.Ed
.Pp
Create an 802.11a mesh station:
.Bd -literal -offset indent
ifconfig wlan0 create wlandev mwl0 wlanmode mesh
ifconfig wlan0 meshid my_mesh mode 11a inet 192.168.0.10/24
.Ed
.Pp
Create two virtual 802.11a host-based access points, one with
with WEP enabled and one with no security, and bridge them to
the fxp0 (wired) device:

View File

@ -15,7 +15,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd April 13, 2008
.Dd July 8, 2009
.Os
.Dt RAL 4
.Sh NAME
@ -72,12 +72,15 @@ supports
.Cm station ,
.Cm adhoc ,
.Cm hostap ,
.Cm mesh ,
.Cm wds ,
and
.Cm monitor
mode operation.
Only one
.Cm hostap
or
.Cm mesh
virtual interface may be configured at a time.
Any number of
.Cm wds

View File

@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd May 15, 2009
.Dd July 8, 2009
.Dt WLAN 4
.Os
.Sh NAME
@ -48,7 +48,7 @@ support.
.Nm
supports multi-mode devices capable of
operating in both 2.4GHz and 5GHz bands and supports numerous
802.11 standards: 802.11a, 802.11b, 802.11g, and 802.11n.
802.11 standards: 802.11a, 802.11b, 802.11g, 802.11n, and 802.11s (Draft 3.0).
The WPA, 802.11i, and 802.1x security protocols are supported
through a combination of in-kernel code and user-mode applications.
The WME/WMM multi-media protocols are supported entirely within
@ -83,6 +83,8 @@ A client station in an infrastructure bss
(i.e. one that associates to an access point).
.It Cm hostap
An access point in an infrastructure bss.
.It Cm mesh
A mesh station in an MBSS network.
.It Cm adhoc
A station in an IBSS network.
.It Cm ahdemo
@ -115,8 +117,6 @@ interface that does not send beacon frames before
interfaces may be created.
.El
.Pp
More types are planned to support
802.11s mesh nodes (station and ap).
Note that an interface's type cannot be changed once it is created.
.Pp
.Nm
@ -161,6 +161,12 @@ The module name of
.Nm
was used to be compatible with
.Nx .
.Pp
Mesh stations follow the 802.11s Draft 3.0 specification which is
not ratified and subject to change.
Beware that this specification is incompatible with earlier drafts;
and stations implementing earlier drafts (e.g. Linux)
may not interoperate.
.Sh SEE ALSO
.Xr an 4 ,
.Xr ath 4 ,

View File

@ -258,6 +258,7 @@ device xe # Xircom pccard Ethernet
device wlan # 802.11 support
options IEEE80211_DEBUG # enable debug msgs
options IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's
options IEEE80211_SUPPORT_MESH # enable 802.11s D3.0 support
device wlan_wep # 802.11 WEP support
device wlan_ccmp # 802.11 CCMP support
device wlan_tkip # 802.11 TKIP support

View File

@ -738,6 +738,8 @@ device vlan
device wlan
options IEEE80211_DEBUG #enable debugging msgs
options IEEE80211_AMPDU_AGE #age frames in AMPDU reorder q's
options IEEE80211_SUPPORT_MESH #enable 802.11s D3.0 support
options IEEE80211_SUPPORT_TDMA #enable TDMA support
# The `wlan_wep', `wlan_tkip', and `wlan_ccmp' devices provide
# support for WEP, TKIP, and AES-CCMP crypto protocols optionally

View File

@ -2239,6 +2239,7 @@ net80211/ieee80211_acl.c optional wlan wlan_acl
net80211/ieee80211_action.c optional wlan
net80211/ieee80211_ageq.c optional wlan
net80211/ieee80211_adhoc.c optional wlan
net80211/ieee80211_ageq.c optional wlan
net80211/ieee80211_amrr.c optional wlan wlan_amrr
net80211/ieee80211_crypto.c optional wlan
net80211/ieee80211_crypto_ccmp.c optional wlan wlan_ccmp
@ -2250,8 +2251,10 @@ net80211/ieee80211_dfs.c optional wlan
net80211/ieee80211_freebsd.c optional wlan
net80211/ieee80211_hostap.c optional wlan
net80211/ieee80211_ht.c optional wlan
net80211/ieee80211_hwmp.c optional wlan ieee80211_support_mesh
net80211/ieee80211_input.c optional wlan
net80211/ieee80211_ioctl.c optional wlan
net80211/ieee80211_mesh.c optional wlan ieee80211_support_mesh
net80211/ieee80211_monitor.c optional wlan
net80211/ieee80211_node.c optional wlan
net80211/ieee80211_output.c optional wlan

View File

@ -804,6 +804,7 @@ INTR_FILTER
IEEE80211_DEBUG opt_wlan.h
IEEE80211_DEBUG_REFCNT opt_wlan.h
IEEE80211_AMPDU_AGE opt_wlan.h
IEEE80211_SUPPORT_MESH opt_wlan.h
IEEE80211_SUPPORT_SUPERG opt_wlan.h
IEEE80211_SUPPORT_TDMA opt_wlan.h

View File

@ -578,6 +578,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
| IEEE80211_C_MONITOR /* monitor mode */
| IEEE80211_C_AHDEMO /* adhoc demo mode */
| IEEE80211_C_WDS /* 4-address traffic works */
| IEEE80211_C_MBSS /* mesh point link mode */
| IEEE80211_C_SHPREAMBLE /* short preamble supported */
| IEEE80211_C_SHSLOT /* short slot time supported */
| IEEE80211_C_WPA /* capable of WPA1+WPA2 */
@ -655,6 +656,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
if (ath_hal_hasbursting(ah))
ic->ic_caps |= IEEE80211_C_BURST;
sc->sc_hasbmask = ath_hal_hasbssidmask(ah);
sc->sc_hasbmatch = ath_hal_hasbssidmatch(ah);
sc->sc_hastsfadd = ath_hal_hastsfadjust(ah);
if (ath_hal_hasfastframes(ah))
ic->ic_caps |= IEEE80211_C_FF;
@ -918,6 +920,7 @@ ath_vap_create(struct ieee80211com *ic,
}
break;
case IEEE80211_M_HOSTAP:
case IEEE80211_M_MBSS:
needbeacon = 1;
break;
case IEEE80211_M_WDS:
@ -936,7 +939,6 @@ ath_vap_create(struct ieee80211com *ic,
ic_opmode = IEEE80211_M_HOSTAP;
else
ic_opmode = ic->ic_opmode;
break;
default:
device_printf(sc->sc_dev, "unknown opmode %d\n", opmode);
goto bad;
@ -950,7 +952,7 @@ ath_vap_create(struct ieee80211com *ic,
}
/* STA, AHDEMO? */
if (opmode == IEEE80211_M_HOSTAP) {
if (opmode == IEEE80211_M_HOSTAP || opmode == IEEE80211_M_MBSS) {
assign_address(sc, mac, flags & IEEE80211_CLONE_BSSID);
ath_hal_setbssidmask(sc->sc_ah, sc->sc_hwbssidmask);
}
@ -1042,6 +1044,7 @@ ath_vap_create(struct ieee80211com *ic,
/* fall thru... */
#endif
case IEEE80211_M_HOSTAP:
case IEEE80211_M_MBSS:
sc->sc_opmode = HAL_M_HOSTAP;
break;
case IEEE80211_M_MONITOR:
@ -1129,7 +1132,8 @@ ath_vap_delete(struct ieee80211vap *vap)
sc->sc_nstavaps--;
if (sc->sc_nstavaps == 0 && sc->sc_swbmiss)
sc->sc_swbmiss = 0;
} else if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
} else if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
vap->iv_opmode == IEEE80211_M_MBSS) {
reclaim_address(sc, vap->iv_myaddr);
ath_hal_setbssidmask(ah, sc->sc_hwbssidmask);
}
@ -2330,7 +2334,7 @@ ath_key_update_end(struct ieee80211vap *vap)
* NB: older hal's add rx filter bits out of sight and we need to
* blindly preserve them
* o probe request frames are accepted only when operating in
* hostap, adhoc, or monitor modes
* hostap, adhoc, mesh, or monitor modes
* o enable promiscuous mode
* - when in monitor mode
* - if interface marked PROMISC (assumes bridge setting is filtered)
@ -2343,6 +2347,7 @@ ath_key_update_end(struct ieee80211vap *vap)
* - when doing s/w beacon miss (e.g. for ap+sta)
* - when operating in ap mode in 11g to detect overlapping bss that
* require protection
* - when operating in mesh mode to detect neighbors
* o accept control frames:
* - when in monitor mode
* XXX BAR frames for 11n
@ -2375,6 +2380,13 @@ ath_calcrxfilter(struct ath_softc *sc)
if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
IEEE80211_IS_CHAN_ANYG(ic->ic_curchan))
rfilt |= HAL_RX_FILTER_BEACON;
if (ic->ic_opmode == IEEE80211_M_MBSS) {
rfilt |= HAL_RX_FILTER_BEACON;
if (sc->sc_hasbmatch)
rfilt |= HAL_RX_FILTER_BSSID;
else
rfilt |= HAL_RX_FILTER_PROM;
}
if (ic->ic_opmode == IEEE80211_M_MONITOR)
rfilt |= HAL_RX_FILTER_CONTROL;
DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x, %s if_flags 0x%x\n",
@ -2500,7 +2512,8 @@ ath_updateslot(struct ifnet *ifp)
* immediately. For other operation we defer the change
* until beacon updates have propagated to the stations.
*/
if (ic->ic_opmode == IEEE80211_M_HOSTAP)
if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
ic->ic_opmode == IEEE80211_M_MBSS)
sc->sc_updateslot = UPDATE;
else
ath_setslottime(sc);
@ -2535,7 +2548,8 @@ ath_beaconq_config(struct ath_softc *sc)
HAL_TXQ_INFO qi;
ath_hal_gettxqueueprops(ah, sc->sc_bhalq, &qi);
if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
ic->ic_opmode == IEEE80211_M_MBSS) {
/*
* Always burst out beacon and CAB traffic.
*/
@ -3087,9 +3101,10 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
/* extract tstamp from last beacon and convert to TU */
nexttbtt = TSF_TO_TU(LE_READ_4(ni->ni_tstamp.data + 4),
LE_READ_4(ni->ni_tstamp.data));
if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
ic->ic_opmode == IEEE80211_M_MBSS) {
/*
* For multi-bss ap support beacons are either staggered
* For multi-bss ap/mesh support beacons are either staggered
* evenly over N slots or burst together. For the former
* arrange for the SWBA to be delivered for each slot.
* Slots that are not occupied will generate nothing.
@ -3230,10 +3245,11 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
} while (nexttbtt < tsftu);
}
ath_beaconq_config(sc);
} else if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
} else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
ic->ic_opmode == IEEE80211_M_MBSS) {
/*
* In AP mode we enable the beacon timers and
* SWBA interrupts to prepare beacon frames.
* In AP/mesh mode we enable the beacon timers
* and SWBA interrupts to prepare beacon frames.
*/
intval |= HAL_BEACON_ENA;
sc->sc_imask |= HAL_INT_SWBA; /* beacon prepare */
@ -5602,6 +5618,7 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
#endif
case IEEE80211_M_HOSTAP:
case IEEE80211_M_IBSS:
case IEEE80211_M_MBSS:
/*
* Allocate and setup the beacon frame.
*

View File

@ -235,6 +235,7 @@ struct ath_softc {
sc_outdoor : 1,/* outdoor operation */
sc_dturbo : 1,/* dynamic turbo in use */
sc_hasbmask : 1,/* bssid mask support */
sc_hasbmatch: 1,/* bssid match disable support*/
sc_hastsfadd: 1,/* tsf adjust support */
sc_beacons : 1,/* beacons running */
sc_swbmiss : 1,/* sta mode using sw bmiss */

View File

@ -420,6 +420,7 @@ mwl_attach(uint16_t devid, struct mwl_softc *sc)
| IEEE80211_C_IBSS /* ibss, nee adhoc, mode */
| IEEE80211_C_AHDEMO /* adhoc demo mode */
#endif
| IEEE80211_C_MBSS /* mesh point link mode */
| IEEE80211_C_WDS /* WDS supported */
| IEEE80211_C_SHPREAMBLE /* short preamble supported */
| IEEE80211_C_SHSLOT /* short slot time supported */
@ -615,6 +616,7 @@ mwl_vap_create(struct ieee80211com *ic,
IEEE80211_ADDR_COPY(mac, mac0);
switch (opmode) {
case IEEE80211_M_HOSTAP:
case IEEE80211_M_MBSS:
if ((flags & IEEE80211_CLONE_MACADDR) == 0)
assign_address(sc, mac, flags & IEEE80211_CLONE_BSSID);
hvap = mwl_hal_newvap(mh, MWL_HAL_AP, mac);
@ -686,7 +688,7 @@ mwl_vap_create(struct ieee80211com *ic,
vap->iv_key_delete = mwl_key_delete;
vap->iv_key_set = mwl_key_set;
#ifdef MWL_HOST_PS_SUPPORT
if (opmode == IEEE80211_M_HOSTAP) {
if (opmode == IEEE80211_M_HOSTAP || opmode == IEEE80211_M_MBSS) {
vap->iv_update_ps = mwl_update_ps;
mvp->mv_set_tim = vap->iv_set_tim;
vap->iv_set_tim = mwl_set_tim;
@ -706,12 +708,14 @@ mwl_vap_create(struct ieee80211com *ic,
switch (vap->iv_opmode) {
case IEEE80211_M_HOSTAP:
case IEEE80211_M_MBSS:
case IEEE80211_M_STA:
/*
* Setup sta db entry for local address.
*/
mwl_localstadb(vap);
if (vap->iv_opmode == IEEE80211_M_HOSTAP)
if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
vap->iv_opmode == IEEE80211_M_MBSS)
sc->sc_napvaps++;
else
sc->sc_nstavaps++;
@ -753,11 +757,12 @@ mwl_vap_delete(struct ieee80211vap *vap)
ieee80211_vap_detach(vap);
switch (opmode) {
case IEEE80211_M_HOSTAP:
case IEEE80211_M_MBSS:
case IEEE80211_M_STA:
KASSERT(hvap != NULL, ("no hal vap handle"));
(void) mwl_hal_delstation(hvap, vap->iv_myaddr);
mwl_hal_delvap(hvap);
if (opmode == IEEE80211_M_HOSTAP)
if (opmode == IEEE80211_M_HOSTAP || opmode == IEEE80211_M_MBSS)
sc->sc_napvaps--;
else
sc->sc_nstavaps--;
@ -1281,6 +1286,7 @@ mwl_reset_vap(struct ieee80211vap *vap, int state)
/* re-setup beacons */
if (state == IEEE80211_S_RUN &&
(vap->iv_opmode == IEEE80211_M_HOSTAP ||
vap->iv_opmode == IEEE80211_M_MBSS ||
vap->iv_opmode == IEEE80211_M_IBSS)) {
mwl_setapmode(vap, vap->iv_bss->ni_chan);
mwl_hal_setnprotmode(hvap,
@ -4184,6 +4190,7 @@ mwl_localstadb(struct ieee80211vap *vap)
mwl_setglobalkeys(vap);
break;
case IEEE80211_M_HOSTAP:
case IEEE80211_M_MBSS:
error = mwl_hal_newstation(hvap, vap->iv_myaddr,
0, 0, NULL, vap->iv_flags & IEEE80211_F_WME, 0);
if (error == 0)
@ -4248,7 +4255,8 @@ mwl_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
(void) mwl_peerstadb(ni, 0, 0, NULL);
} else if (nstate == IEEE80211_S_CSA) {
/* XXX move to below? */
if (vap->iv_opmode == IEEE80211_M_HOSTAP)
if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
vap->iv_opmode == IEEE80211_M_MBSS)
mwl_startcsa(vap);
} else if (nstate == IEEE80211_S_CAC) {
/* XXX move to below? */
@ -4282,6 +4290,7 @@ mwl_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
mwl_localstadb(vap);
switch (vap->iv_opmode) {
case IEEE80211_M_HOSTAP:
case IEEE80211_M_MBSS:
if (ostate == IEEE80211_S_CAC) {
/* enable in-service radar detection */
mwl_hal_setradardetection(mh,

View File

@ -285,6 +285,7 @@ rt2560_attach(device_t dev, int id)
| IEEE80211_C_MONITOR /* monitor mode */
| IEEE80211_C_AHDEMO /* adhoc demo mode */
| IEEE80211_C_WDS /* 4-address traffic works */
| IEEE80211_C_MBSS /* mesh point link mode */
| IEEE80211_C_SHPREAMBLE /* short preamble supported */
| IEEE80211_C_SHSLOT /* short slot time supported */
| IEEE80211_C_WPA /* capable of WPA1+WPA2 */
@ -391,6 +392,8 @@ rt2560_vap_create(struct ieee80211com *ic,
case IEEE80211_M_AHDEMO:
case IEEE80211_M_MONITOR:
case IEEE80211_M_HOSTAP:
case IEEE80211_M_MBSS:
/* XXXRP: TBD */
if (!TAILQ_EMPTY(&ic->ic_vaps)) {
if_printf(ifp, "only 1 vap supported\n");
return NULL;
@ -811,7 +814,8 @@ rt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
}
if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
vap->iv_opmode == IEEE80211_M_IBSS) {
vap->iv_opmode == IEEE80211_M_IBSS ||
vap->iv_opmode == IEEE80211_M_MBSS) {
m = ieee80211_beacon_alloc(ni, &rvp->ral_bo);
if (m == NULL) {
if_printf(ifp, "could not allocate beacon\n");
@ -1343,7 +1347,8 @@ rt2560_beacon_expire(struct rt2560_softc *sc)
struct rt2560_tx_data *data;
if (ic->ic_opmode != IEEE80211_M_IBSS &&
ic->ic_opmode != IEEE80211_M_HOSTAP)
ic->ic_opmode != IEEE80211_M_HOSTAP &&
ic->ic_opmode != IEEE80211_M_MBSS)
return;
data = &sc->bcnq.data[sc->bcnq.next];
@ -2690,7 +2695,8 @@ rt2560_init_locked(struct rt2560_softc *sc)
tmp = RT2560_DROP_PHY_ERROR | RT2560_DROP_CRC_ERROR;
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
tmp |= RT2560_DROP_CTL | RT2560_DROP_VERSION_ERROR;
if (ic->ic_opmode != IEEE80211_M_HOSTAP)
if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
ic->ic_opmode != IEEE80211_M_MBSS)
tmp |= RT2560_DROP_TODS;
if (!(ifp->if_flags & IFF_PROMISC))
tmp |= RT2560_DROP_NOT_TO_ME;

View File

@ -287,6 +287,7 @@ rt2661_attach(device_t dev, int id)
| IEEE80211_C_MONITOR /* monitor mode */
| IEEE80211_C_AHDEMO /* adhoc demo mode */
| IEEE80211_C_WDS /* 4-address traffic works */
| IEEE80211_C_MBSS /* mesh point link mode */
| IEEE80211_C_SHPREAMBLE /* short preamble supported */
| IEEE80211_C_SHSLOT /* short slot time supported */
| IEEE80211_C_WPA /* capable of WPA1+WPA2 */
@ -387,6 +388,8 @@ rt2661_vap_create(struct ieee80211com *ic,
case IEEE80211_M_AHDEMO:
case IEEE80211_M_MONITOR:
case IEEE80211_M_HOSTAP:
case IEEE80211_M_MBSS:
/* XXXRP: TBD */
if (!TAILQ_EMPTY(&ic->ic_vaps)) {
if_printf(ifp, "only 1 vap supported\n");
return NULL;
@ -818,7 +821,8 @@ rt2661_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
}
if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
vap->iv_opmode == IEEE80211_M_IBSS) {
vap->iv_opmode == IEEE80211_M_IBSS ||
vap->iv_opmode == IEEE80211_M_MBSS) {
error = rt2661_prepare_beacon(sc, vap);
if (error != 0)
return error;
@ -2428,7 +2432,8 @@ rt2661_init_locked(struct rt2661_softc *sc)
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
tmp |= RT2661_DROP_CTL | RT2661_DROP_VER_ERROR |
RT2661_DROP_ACKCTS;
if (ic->ic_opmode != IEEE80211_M_HOSTAP)
if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
ic->ic_opmode != IEEE80211_M_MBSS)
tmp |= RT2661_DROP_TODS;
if (!(ifp->if_flags & IFF_PROMISC))
tmp |= RT2661_DROP_NOT_TO_ME;

View File

@ -270,6 +270,7 @@ device xe # Xircom pccard Ethernet
device wlan # 802.11 support
options IEEE80211_DEBUG # enable debug msgs
options IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's
options IEEE80211_SUPPORT_MESH # enable 802.11s D3.0 support
device wlan_wep # 802.11 WEP support
device wlan_ccmp # 802.11 CCMP support
device wlan_tkip # 802.11 TKIP support

View File

@ -217,6 +217,7 @@ uint64_t ifmedia_baudrate(int);
#define IFM_IEEE80211_WDS 0x00000800 /* Operate in WDS mode */
#define IFM_IEEE80211_TURBO 0x00001000 /* Operate in turbo mode */
#define IFM_IEEE80211_MONITOR 0x00002000 /* Operate in monitor mode */
#define IFM_IEEE80211_MBSS 0x00004000 /* Operate in MBSS mode */
/* operating mode for multi-mode devices */
#define IFM_IEEE80211_11A 0x00010000 /* 5Ghz, OFDM mode */
@ -509,6 +510,7 @@ struct ifmedia_description {
{ IFM_IEEE80211_WDS, "wds" }, \
{ IFM_IEEE80211_TURBO, "turbo" }, \
{ IFM_IEEE80211_MONITOR, "monitor" }, \
{ IFM_IEEE80211_MBSS, "mesh" }, \
{ 0, NULL }, \
}

View File

@ -83,8 +83,9 @@ enum ieee80211_opmode {
IEEE80211_M_AHDEMO = 3, /* Old lucent compatible adhoc demo */
IEEE80211_M_HOSTAP = 4, /* Software Access Point */
IEEE80211_M_MONITOR = 5, /* Monitor mode */
IEEE80211_M_MBSS = 6, /* MBSS (Mesh Point) link */
};
#define IEEE80211_OPMODE_MAX (IEEE80211_M_MONITOR+1)
#define IEEE80211_OPMODE_MAX (IEEE80211_M_MBSS+1)
/*
* 802.11g/802.11n protection mode.

View File

@ -74,6 +74,9 @@ const int ieee80211_opcap[IEEE80211_OPMODE_MAX] = {
[IEEE80211_M_AHDEMO] = IEEE80211_C_AHDEMO,
[IEEE80211_M_HOSTAP] = IEEE80211_C_HOSTAP,
[IEEE80211_M_MONITOR] = IEEE80211_C_MONITOR,
#ifdef IEEE80211_SUPPORT_MESH
[IEEE80211_M_MBSS] = IEEE80211_C_MBSS,
#endif
};
static const uint8_t ieee80211broadcastaddr[IEEE80211_ADDR_LEN] =
@ -960,6 +963,8 @@ addmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword)
ADD(media, mword, mopt | IFM_IEEE80211_MONITOR);
if (caps & IEEE80211_C_WDS)
ADD(media, mword, mopt | IFM_IEEE80211_WDS);
if (caps & IEEE80211_C_MBSS)
ADD(media, mword, mopt | IFM_IEEE80211_MBSS);
#undef ADD
}
@ -1264,6 +1269,9 @@ media_status(enum ieee80211_opmode opmode, const struct ieee80211_channel *chan)
case IEEE80211_M_WDS:
status |= IFM_IEEE80211_WDS;
break;
case IEEE80211_M_MBSS:
status |= IFM_IEEE80211_MBSS;
break;
}
if (IEEE80211_IS_CHAN_HTA(chan)) {
status |= IFM_IEEE80211_11NA;

View File

@ -185,6 +185,7 @@ struct ieee80211_qosframe_addr4 {
(IEEE80211_SEQ_SUB(b, a+1) < IEEE80211_SEQ_BA_RANGE-1)
#define IEEE80211_NWID_LEN 32
#define IEEE80211_MESHID_LEN 32
#define IEEE80211_QOS_TXOP 0x00ff
/* bit 8 is reserved */
@ -705,6 +706,30 @@ enum {
IEEE80211_ELEMID_TPC = 150,
IEEE80211_ELEMID_CCKM = 156,
IEEE80211_ELEMID_VENDOR = 221, /* vendor private */
/*
* 802.11s IEs based on D3.0 spec and were not assigned by
* ANA. Beware changing them because some of them are being
* kept compatible with Linux.
*/
IEEE80211_ELEMID_MESHCONF = 51,
IEEE80211_ELEMID_MESHID = 52,
IEEE80211_ELEMID_MESHLINK = 35,
IEEE80211_ELEMID_MESHCNGST = 36,
IEEE80211_ELEMID_MESHPEER = 55,
IEEE80211_ELEMID_MESHCSA = 38,
IEEE80211_ELEMID_MESHTIM = 39,
IEEE80211_ELEMID_MESHAWAKEW = 40,
IEEE80211_ELEMID_MESHBEACONT = 41,
IEEE80211_ELEMID_MESHPANN = 48,
IEEE80211_ELEMID_MESHRANN = 49,
IEEE80211_ELEMID_MESHPREQ = 68,
IEEE80211_ELEMID_MESHPREP = 69,
IEEE80211_ELEMID_MESHPERR = 70,
IEEE80211_ELEMID_MESHPU = 53,
IEEE80211_ELEMID_MESHPUC = 54,
IEEE80211_ELEMID_MESHAH = 60, /* Abbreviated Handshake */
IEEE80211_ELEMID_MESHPEERVER = 80, /* Peering Protocol Version */
};
struct ieee80211_tim_ie {
@ -890,6 +915,17 @@ enum {
IEEE80211_REASON_SETUP_NEEDED = 38, /* 11e */
IEEE80211_REASON_TIMEOUT = 39, /* 11e */
/* values not yet allocated by ANA */
IEEE80211_REASON_PEER_LINK_CANCELED = 2, /* 11s */
IEEE80211_REASON_MESH_MAX_PEERS = 3, /* 11s */
IEEE80211_REASON_MESH_CPVIOLATION = 4, /* 11s */
IEEE80211_REASON_MESH_CLOSE_RCVD = 5, /* 11s */
IEEE80211_REASON_MESH_MAX_RETRIES = 6, /* 11s */
IEEE80211_REASON_MESH_CONFIRM_TIMEOUT = 7, /* 11s */
IEEE80211_REASON_MESH_INVALID_GTK = 8, /* 11s */
IEEE80211_REASON_MESH_INCONS_PARAMS = 9, /* 11s */
IEEE80211_REASON_MESH_INVALID_SECURITY = 10, /* 11s */
IEEE80211_STATUS_SUCCESS = 0,
IEEE80211_STATUS_UNSPECIFIED = 1,
IEEE80211_STATUS_CAPINFO = 10,

View File

@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_action.h>
#include <net80211/ieee80211_mesh.h>
static int
send_inval(struct ieee80211_node *ni, int cat, int act, void *sa)
@ -62,8 +63,6 @@ static ieee80211_send_action_func *ht_send_action[8] = {
send_inval, send_inval, send_inval, send_inval,
send_inval, send_inval, send_inval, send_inval,
};
/* NB: temporary until 802.11s support is added */
#ifdef IEEE80211_ACTION_CAT_MESHPEERING
static ieee80211_send_action_func *meshpl_send_action[8] = {
send_inval, send_inval, send_inval, send_inval,
send_inval, send_inval, send_inval, send_inval,
@ -75,7 +74,6 @@ static ieee80211_send_action_func *hwmp_send_action[8] = {
send_inval, send_inval, send_inval, send_inval,
send_inval, send_inval, send_inval, send_inval,
};
#endif
static ieee80211_send_action_func *vendor_send_action[8] = {
send_inval, send_inval, send_inval, send_inval,
send_inval, send_inval, send_inval, send_inval,
@ -96,7 +94,6 @@ ieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f)
break;
ht_send_action[act] = f;
return 0;
#ifdef IEEE80211_ACTION_CAT_MESHPEERING
case IEEE80211_ACTION_CAT_MESHPEERING:
if (act >= N(meshpl_send_action))
break;
@ -112,7 +109,6 @@ ieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f)
break;
hwmp_send_action[act] = f;
return 0;
#endif
case IEEE80211_ACTION_CAT_VENDOR:
if (act >= N(vendor_send_action))
break;
@ -144,7 +140,6 @@ ieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa)
if (act < N(ht_send_action))
f = ht_send_action[act];
break;
#ifdef IEEE80211_ACTION_CAT_MESHPEERING
case IEEE80211_ACTION_CAT_MESHPEERING:
if (act < N(meshpl_send_action))
f = meshpl_send_action[act];
@ -157,7 +152,6 @@ ieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa)
if (act < N(hwmp_send_action))
f = hwmp_send_action[act];
break;
#endif
case IEEE80211_ACTION_CAT_VENDOR:
if (act < N(vendor_send_action))
f = vendor_send_action[act];
@ -182,7 +176,6 @@ static ieee80211_recv_action_func *ht_recv_action[8] = {
recv_inval, recv_inval, recv_inval, recv_inval,
recv_inval, recv_inval, recv_inval, recv_inval,
};
#ifdef IEEE80211_ACTION_CAT_MESHPEERING
static ieee80211_recv_action_func *meshpl_recv_action[8] = {
recv_inval, recv_inval, recv_inval, recv_inval,
recv_inval, recv_inval, recv_inval, recv_inval,
@ -194,7 +187,6 @@ static ieee80211_recv_action_func *hwmp_recv_action[8] = {
recv_inval, recv_inval, recv_inval, recv_inval,
recv_inval, recv_inval, recv_inval, recv_inval,
};
#endif
static ieee80211_recv_action_func *vendor_recv_action[8] = {
recv_inval, recv_inval, recv_inval, recv_inval,
recv_inval, recv_inval, recv_inval, recv_inval,
@ -215,7 +207,6 @@ ieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f)
break;
ht_recv_action[act] = f;
return 0;
#ifdef IEEE80211_ACTION_CAT_MESHPEERING
case IEEE80211_ACTION_CAT_MESHPEERING:
if (act >= N(meshpl_recv_action))
break;
@ -231,7 +222,6 @@ ieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f)
break;
hwmp_recv_action[act] = f;
return 0;
#endif
case IEEE80211_ACTION_CAT_VENDOR:
if (act >= N(vendor_recv_action))
break;
@ -267,7 +257,6 @@ ieee80211_recv_action(struct ieee80211_node *ni,
if (ia->ia_action < N(ht_recv_action))
f = ht_recv_action[ia->ia_action];
break;
#ifdef IEEE80211_ACTION_CAT_MESHPEERING
case IEEE80211_ACTION_CAT_MESHPEERING:
if (ia->ia_action < N(meshpl_recv_action))
f = meshpl_recv_action[ia->ia_action];
@ -280,7 +269,6 @@ ieee80211_recv_action(struct ieee80211_node *ni,
if (ia->ia_action < N(hwmp_recv_action))
f = hwmp_recv_action[ia->ia_action];
break;
#endif
case IEEE80211_ACTION_CAT_VENDOR:
if (ia->ia_action < N(vendor_recv_action))
f = vendor_recv_action[ia->ia_action];

View File

@ -50,6 +50,9 @@ __FBSDID("$FreeBSD$");
#ifdef IEEE80211_SUPPORT_TDMA
#include <net80211/ieee80211_tdma.h>
#endif
#ifdef IEEE80211_SUPPORT_MESH
#include <net80211/ieee80211_mesh.h>
#endif
#include <ddb/ddb.h>
#include <ddb/db_sym.h>
@ -75,7 +78,11 @@ static void _db_show_roamparams(const char *tag, const void *arg,
const struct ieee80211_roamparam *rp);
static void _db_show_txparams(const char *tag, const void *arg,
const struct ieee80211_txparam *tp);
static void _db_show_ageq(const char *tag, const struct ieee80211_ageq *q);
static void _db_show_stats(const struct ieee80211_stats *);
#ifdef IEEE80211_SUPPORT_MESH
static void _db_show_mesh(const struct ieee80211_mesh_state *);
#endif
DB_SHOW_COMMAND(sta, db_show_sta)
{
@ -178,6 +185,20 @@ DB_SHOW_ALL_COMMAND(vaps, db_show_all_vaps)
}
}
#ifdef IEEE80211_SUPPORT_MESH
DB_SHOW_ALL_COMMAND(mesh, db_show_mesh)
{
const struct ieee80211_mesh_state *ms;
if (!have_addr) {
db_printf("usage: show mesh <addr>\n");
return;
}
ms = (const struct ieee80211_mesh_state *) addr;
_db_show_mesh(ms);
}
#endif /* IEEE80211_SUPPORT_MESH */
static void
_db_show_txampdu(const char *sep, int ix, const struct ieee80211_tx_ampdu *tap)
{
@ -283,7 +304,12 @@ _db_show_sta(const struct ieee80211_node *ni)
db_printf("\tinact %u inact_reload %u txrate %u\n",
ni->ni_inact, ni->ni_inact_reload, ni->ni_txrate);
/* XXX wdsq */
#ifdef IEEE80211_SUPPORT_MESH
_db_show_ssid("\tmeshid ", 0, ni->ni_meshidlen, ni->ni_meshid);
db_printf(" mlstate %b mllid 0x%x mlpid 0x%x mlrcnt %u mltval %u\n",
ni->ni_mlstate, IEEE80211_MESH_MLSTATE_BITS,
ni->ni_mllid, ni->ni_mlpid, ni->ni_mlrcnt, ni->ni_mltval);
#endif
}
#ifdef IEEE80211_SUPPORT_TDMA
@ -563,10 +589,13 @@ _db_show_com(const struct ieee80211com *ic, int showvaps, int showsta, int showp
db_printf("\n");
db_printf("\tmax_keyix %d", ic->ic_max_keyix);
db_printf(" hash_key 0x%x", ic->ic_hash_key);
db_printf(" wme %p", &ic->ic_wme);
if (!showsta)
db_printf(" sta %p", &ic->ic_sta);
db_printf("\n");
db_printf("\tstageq@%p:\n", &ic->ic_stageq);
_db_show_ageq("\t", &ic->ic_stageq);
if (showsta)
_db_show_node_table("\t", &ic->ic_sta);
@ -643,16 +672,16 @@ _db_show_node_table(const char *tag, const struct ieee80211_node_table *nt)
int i;
db_printf("%s%s@%p:\n", tag, nt->nt_name, nt);
db_printf("%s nodelock %p", tag, &nt->nt_nodelock);
db_printf("%s nodelock %p", tag, &nt->nt_nodelock);
db_printf(" inact_init %d", nt->nt_inact_init);
db_printf(" scanlock %p", &nt->nt_scanlock);
db_printf(" scangen %u\n", nt->nt_scangen);
db_printf("%s keyixmax %d keyixmap %p\n",
db_printf("%s keyixmax %d keyixmap %p\n",
tag, nt->nt_keyixmax, nt->nt_keyixmap);
for (i = 0; i < nt->nt_keyixmax; i++) {
const struct ieee80211_node *ni = nt->nt_keyixmap[i];
if (ni != NULL)
db_printf("%s [%3u] %p %s\n", tag, i, ni,
db_printf("%s [%3u] %p %s\n", tag, i, ni,
ether_sprintf(ni->ni_macaddr));
}
}
@ -809,8 +838,44 @@ _db_show_txparams(const char *tag, const void *arg,
db_printf(" maxretry %d", tp->maxretry);
}
static void
_db_show_ageq(const char *tag, const struct ieee80211_ageq *q)
{
const struct mbuf *m;
db_printf("%s lock %p len %d maxlen %d drops %d head %p tail %p\n",
tag, &q->aq_lock, q->aq_len, q->aq_maxlen, q->aq_drops,
q->aq_head, q->aq_tail);
for (m = q->aq_head; m != NULL; m = m->m_nextpkt)
db_printf("%s %p (len %d, %b)\n", tag, m, m->m_len,
/* XXX could be either TX or RX but is mostly TX */
m->m_flags, IEEE80211_MBUF_TX_FLAG_BITS);
}
static void
_db_show_stats(const struct ieee80211_stats *is)
{
}
#ifdef IEEE80211_SUPPORT_MESH
static void
_db_show_mesh(const struct ieee80211_mesh_state *ms)
{
struct ieee80211_mesh_route *rt;
int i;
_db_show_ssid(" meshid ", 0, ms->ms_idlen, ms->ms_id);
db_printf("nextseq %u ttl %u flags 0x%x\n", ms->ms_seq,
ms->ms_ttl, ms->ms_flags);
db_printf("routing table:\n");
i = 0;
TAILQ_FOREACH(rt, &ms->ms_routes, rt_next) {
db_printf("entry %d:\tdest: %6D nexthop: %6D metric: %u", i,
rt->rt_dest, ":", rt->rt_nexthop, ":", rt->rt_metric);
db_printf("\tlifetime: %u lastseq: %u priv: %p\n",
rt->rt_lifetime, rt->rt_lastmseq, rt->rt_priv);
i++;
}
}
#endif /* IEEE80211_SUPPORT_MESH */
#endif /* DDB */

View File

@ -209,6 +209,19 @@ struct mbuf *ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen);
#define M_AMPDU_MPDU M_PROTO8 /* A-MPDU re-order done */
#endif
#define M_80211_RX (M_AMPDU|M_WEP|M_AMPDU_MPDU)
#define IEEE80211_MBUF_TX_FLAG_BITS \
"\20\1M_EXT\2M_PKTHDR\3M_EOR\4M_RDONLY\5M_ENCAP\6M_WEP\7M_EAPOL" \
"\10M_PWR_SAV\11M_MORE_DATA\12M_BCAST\13M_MCAST\14M_FRAG\15M_FIRSTFRAG" \
"\16M_LASTFRAG\17M_SKIP_FIREWALL\20M_FREELIST\21M_VLANTAG\22M_PROMISC" \
"\23M_NOFREE\24M_FF\25M_TXCB\26M_AMPDU_MPDU\27M_FLOWID"
#define IEEE80211_MBUF_RX_FLAG_BITS \
"\20\1M_EXT\2M_PKTHDR\3M_EOR\4M_RDONLY\5M_AMPDU\6M_WEP\7M_PROTO3" \
"\10M_PROTO4\11M_PROTO5\12M_BCAST\13M_MCAST\14M_FRAG\15M_FIRSTFRAG" \
"\16M_LASTFRAG\17M_SKIP_FIREWALL\20M_FREELIST\21M_VLANTAG\22M_PROMISC" \
"\23M_NOFREE\24M_PROTO6\25M_PROTO7\26M_AMPDU_MPDU\27M_FLOWID"
/*
* Store WME access control bits in the vlan tag.
* This is safe since it's done after the packet is classified

File diff suppressed because it is too large Load Diff

View File

@ -46,6 +46,9 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_input.h>
#ifdef IEEE80211_SUPPORT_MESH
#include <net80211/ieee80211_mesh.h>
#endif
#include <net/bpf.h>
@ -230,7 +233,16 @@ ieee80211_deliver_data(struct ieee80211vap *vap,
struct mbuf *
ieee80211_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen)
{
struct ieee80211_qosframe_addr4 wh; /* Max size address frames */
#ifdef IEEE80211_SUPPORT_MESH
union {
struct ieee80211_qosframe_addr4 wh4;
uint8_t b[sizeof(struct ieee80211_qosframe_addr4) +
sizeof(struct ieee80211_meshcntl_ae11)];
} whu;
#define wh whu.wh4
#else
struct ieee80211_qosframe_addr4 wh;
#endif
struct ether_header *eh;
struct llc *llc;
@ -327,6 +339,7 @@ ieee80211_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen)
eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
}
return m;
#undef wh
}
/*
@ -484,6 +497,8 @@ ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m,
* [tlv] HT capabilities
* [tlv] HT information
* [tlv] Atheros capabilities
* [tlv] Mesh ID
* [tlv] Mesh Configuration
*/
IEEE80211_VERIFY_LENGTH(efrm - frm, 12,
return (scan->status = IEEE80211_BPARSE_BADIELEN));
@ -559,6 +574,14 @@ ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m,
case IEEE80211_ELEMID_HTINFO:
scan->htinfo = frm;
break;
#ifdef IEEE80211_SUPPORT_TDMA
case IEEE80211_ELEMID_MESHID:
scan->meshid = frm;
break;
case IEEE80211_ELEMID_MESHCONF:
scan->meshconf = frm;
break;
#endif
case IEEE80211_ELEMID_VENDOR:
if (iswpaoui(frm))
scan->wpa = frm;

View File

@ -241,7 +241,8 @@ scan_space(const struct ieee80211_scan_entry *se, int *ielen)
* packet is <3Kbytes so we are sure this doesn't overflow
* 16-bits; if this is a concern we can drop the ie's.
*/
len = sizeof(struct ieee80211req_scan_result) + se->se_ssid[1] + *ielen;
len = sizeof(struct ieee80211req_scan_result) + se->se_ssid[1] +
se->se_meshid[1] + *ielen;
return roundup(len, sizeof(uint32_t));
}
@ -286,14 +287,19 @@ get_scan_result(void *arg, const struct ieee80211_scan_entry *se)
memcpy(sr->isr_rates+nr, se->se_xrates+2, nxr);
sr->isr_nrates = nr + nxr;
/* copy SSID */
sr->isr_ssid_len = se->se_ssid[1];
cp = ((uint8_t *)sr) + sr->isr_ie_off;
memcpy(cp, se->se_ssid+2, sr->isr_ssid_len);
if (ielen) {
cp += sr->isr_ssid_len;
/* copy mesh id */
cp += sr->isr_ssid_len;
sr->isr_meshid_len = se->se_meshid[1];
memcpy(cp, se->se_meshid+2, sr->isr_meshid_len);
cp += sr->isr_meshid_len;
if (ielen)
memcpy(cp, se->se_ies.data, ielen);
}
req->space -= len;
req->sr = (struct ieee80211req_scan_result *)(((uint8_t *)sr) + len);
@ -435,6 +441,9 @@ get_sta_info(void *arg, struct ieee80211_node *ni)
else
si->isi_inact = vap->iv_inact_init;
si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
si->isi_localid = ni->ni_mllid;
si->isi_peerid = ni->ni_mlpid;
si->isi_peerstate = ni->ni_mlstate;
if (ielen) {
cp = ((uint8_t *)si) + si->isi_ie_off;
@ -2847,6 +2856,7 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211r
break;
case IEEE80211_IOC_DTIM_PERIOD:
if (vap->iv_opmode != IEEE80211_M_HOSTAP &&
vap->iv_opmode != IEEE80211_M_MBSS &&
vap->iv_opmode != IEEE80211_M_IBSS)
return EINVAL;
if (IEEE80211_DTIM_MIN <= ireq->i_val &&
@ -2858,6 +2868,7 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211r
break;
case IEEE80211_IOC_BEACON_INTERVAL:
if (vap->iv_opmode != IEEE80211_M_HOSTAP &&
vap->iv_opmode != IEEE80211_M_MBSS &&
vap->iv_opmode != IEEE80211_M_IBSS)
return EINVAL;
if (IEEE80211_BINTVAL_MIN <= ireq->i_val &&

View File

@ -223,6 +223,19 @@ struct ieee80211_stats {
uint32_t is_tx_ctl; /* tx ctrl frames */
uint32_t is_ampdu_rexmt; /* A-MPDU frames rexmt ok */
uint32_t is_ampdu_rexmt_fail; /* A-MPDU frames rexmt fail */
uint32_t is_mesh_wrongmesh; /* dropped 'cuz not mesh sta*/
uint32_t is_mesh_nolink; /* dropped 'cuz link not estab*/
uint32_t is_mesh_fwd_ttl; /* mesh not fwd'd 'cuz ttl 0 */
uint32_t is_mesh_fwd_nobuf; /* mesh not fwd'd 'cuz no mbuf*/
uint32_t is_mesh_fwd_tooshort; /* mesh not fwd'd 'cuz no hdr */
uint32_t is_mesh_fwd_disabled; /* mesh not fwd'd 'cuz disabled */
uint32_t is_mesh_fwd_nopath; /* mesh not fwd'd 'cuz path unknown */
uint32_t is_hwmp_wrongseq; /* wrong hwmp seq no. */
uint32_t is_hwmp_rootreqs; /* root PREQs sent */
uint32_t is_hwmp_rootrann; /* root RANNs sent */
uint32_t is_spare[16];
};
@ -304,6 +317,27 @@ struct ieee80211req_maclist {
uint8_t ml_macaddr[IEEE80211_ADDR_LEN];
} __packed;
/*
* Mesh Routing Table Operations.
*/
enum {
IEEE80211_MESH_RTCMD_LIST = 0, /* list HWMP routing table */
IEEE80211_MESH_RTCMD_FLUSH = 1, /* flush HWMP routing table */
IEEE80211_MESH_RTCMD_ADD = 2, /* add entry to the table */
IEEE80211_MESH_RTCMD_DELETE = 3, /* delete an entry from the table */
};
/*
* HWMP root modes
*/
enum {
IEEE80211_HWMP_ROOTMODE_DISABLED = 0, /* disabled */
IEEE80211_HWMP_ROOTMODE_NORMAL = 1, /* normal PREPs */
IEEE80211_HWMP_ROOTMODE_PROACTIVE = 2, /* proactive PREPS */
IEEE80211_HWMP_ROOTMODE_RANN = 3, /* use RANN elemid */
};
/*
* Set the active channel list by IEEE channel #: each channel
* to be marked active is set in a bit vector. Note this list is
@ -384,6 +418,10 @@ struct ieee80211req_sta_info {
uint16_t isi_pad;
uint32_t isi_jointime; /* time of assoc/join */
struct ieee80211_mimo_info isi_mimo; /* MIMO info for 11n sta's */
/* 11s info */
uint16_t isi_peerid;
uint16_t isi_localid;
uint8_t isi_peerstate;
/* XXX frag state? */
/* variable length IE data */
};
@ -637,6 +675,22 @@ struct ieee80211req {
#define IEEE80211_IOC_GREENFIELD 112 /* Greenfield (on, off) */
#define IEEE80211_IOC_STBC 113 /* STBC Tx/RX (on, off) */
#define IEEE80211_IOC_MESH_ID 170 /* mesh identifier */
#define IEEE80211_IOC_MESH_AP 171 /* accepting peerings */
#define IEEE80211_IOC_MESH_FWRD 172 /* forward frames */
#define IEEE80211_IOC_MESH_PROTO 173 /* mesh protocols */
#define IEEE80211_IOC_MESH_TTL 174 /* mesh TTL */
#define IEEE80211_IOC_MESH_RTCMD 175 /* mesh routing table commands*/
#define IEEE80211_IOC_MESH_PR_METRIC 176 /* mesh metric protocol */
#define IEEE80211_IOC_MESH_PR_PATH 177 /* mesh path protocol */
#define IEEE80211_IOC_MESH_PR_SIG 178 /* mesh sig protocol */
#define IEEE80211_IOC_MESH_PR_CC 179 /* mesh congestion protocol */
#define IEEE80211_IOC_MESH_PR_AUTH 180 /* mesh auth protocol */
#define IEEE80211_IOC_HWMP_ROOTMODE 190 /* HWMP root mode */
#define IEEE80211_IOC_HWMP_MAXHOPS 191 /* number of hops before drop */
#define IEEE80211_IOC_HWMP_TTL 192 /* HWMP TTL */
#define IEEE80211_IOC_TDMA_SLOT 201 /* TDMA: assigned slot */
#define IEEE80211_IOC_TDMA_SLOTCNT 202 /* TDMA: slots in bss */
#define IEEE80211_IOC_TDMA_SLOTLEN 203 /* TDMA: slot length (usecs) */
@ -724,7 +778,9 @@ struct ieee80211req_scan_result {
uint8_t isr_nrates;
uint8_t isr_rates[IEEE80211_RATE_MAXSIZE];
uint8_t isr_ssid_len; /* SSID length */
/* variable length SSID followed by IE data */
uint8_t isr_meshid_len; /* MESH ID length */
/* variable length SSID, followed by variable length MESH ID,
followed by IE data */
};
/*

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,505 @@
/*-
* Copyright (c) 2009 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Rui Paulo under sponsorship from the
* FreeBSD Foundation.
*
* 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$
*/
#ifndef _NET80211_IEEE80211_MESH_H_
#define _NET80211_IEEE80211_MESH_H_
#define IEEE80211_MESH_DEFAULT_TTL 31
/*
* NB: all structures are__packed so sizeof works on arm, et. al.
*/
/*
* 802.11s Information Elements.
*/
/* Mesh Configuration */
struct ieee80211_meshconf_ie {
uint8_t conf_ie; /* IEEE80211_ELEMID_MESHCONF */
uint8_t conf_len;
uint8_t conf_ver;
uint8_t conf_pselid[4]; /* Active Path Sel. Proto. ID */
uint8_t conf_pmetid[4]; /* APS Metric Identifier */
uint8_t conf_ccid[4]; /* Congestion Control Mode ID */
uint8_t conf_syncid[4]; /* Sync. Protocol ID */
uint8_t conf_authid[4]; /* Auth. Protocol ID */
uint8_t conf_form; /* Formation Information */
uint8_t conf_cap;
} __packed;
#define IEEE80211_MESHCONF_VERSION 1
/* Null Protocol */
#define IEEE80211_MESHCONF_NULL_OUI 0x00, 0x0f, 0xac
#define IEEE80211_MESHCONF_NULL_VALUE 0xff
#define IEEE80211_MESHCONF_NULL { IEEE80211_MESHCONF_NULL_OUI, \
IEEE80211_MESHCONF_NULL_VALUE }
/* Hybrid Wireless Mesh Protocol */
#define IEEE80211_MESHCONF_HWMP_OUI 0x00, 0x0f, 0xac
#define IEEE80211_MESHCONF_HWMP_VALUE 0x00
#define IEEE80211_MESHCONF_HWMP { IEEE80211_MESHCONF_HWMP_OUI, \
IEEE80211_MESHCONF_HWMP_VALUE }
/* Airtime Link Metric */
#define IEEE80211_MESHCONF_AIRTIME_OUI 0x00, 0x0f, 0xac
#define IEEE80211_MESHCONF_AIRTIME_VALUE 0x00
#define IEEE80211_MESHCONF_AIRTIME { IEEE80211_MESHCONF_AIRTIME_OUI, \
IEEE80211_MESHCONF_AIRTIME_VALUE }
/* Congestion Control Signaling */
#define IEEE80211_MESHCONF_CCSIG_OUI 0x00, 0x0f, 0xac
#define IEEE80211_MESHCONF_CCSIG_VALUE 0x00
#define IEEE80211_MESHCONF_CCSIG { IEEE80211_MESHCONF_CCSIG_OUI,\
IEEE80211_MESHCONF_CCSIG_VALUE }
/* Neighbour Offset */
#define IEEE80211_MESHCONF_NEIGHOFF_OUI 0x00, 0x0f, 0xac
#define IEEE80211_MESHCONF_NEIGHOFF_VALUE 0x00
#define IEEE80211_MESHCONF_NEIGHOFF { IEEE80211_MESHCONF_NEIGHOFF_OUI, \
IEEE80211_MESHCONF_NEIGHOFF_VALUE }
/* Simultaneous Authenticaction of Equals */
#define IEEE80211_MESHCONF_SAE_OUI 0x00, 0x0f, 0xac
#define IEEE80211_MESHCONF_SAE_VALUE 0x01
#define IEEE80211_MESHCONF_SAE { IEEE80211_MESHCONF_SAE_OUI, \
IEEE80211_MESHCONF_SAE_VALUE }
#define IEEE80211_MESHCONF_FORM_MP 0x01 /* Connected to Portal */
#define IEEE80211_MESHCONF_FORM_NNEIGH_MASK 0x04 /* Number of Neighbours */
#define IEEE80211_MESHCONF_CAP_AP 0x01 /* Accepting Peers */
#define IEEE80211_MESHCONF_CAP_MCCAS 0x02 /* MCCA supported */
#define IEEE80211_MESHCONF_CAP_MCCAE 0x04 /* MCCA enabled */
#define IEEE80211_MESHCONF_CAP_FWRD 0x08 /* forwarding enabled */
#define IEEE80211_MESHCONF_CAP_BTR 0x10 /* Beacon Timing Report Enab */
#define IEEE80211_MESHCONF_CAP_TBTTA 0x20 /* TBTT Adj. Enabled */
#define IEEE80211_MESHCONF_CAP_PSL 0x40 /* Power Save Level */
/* Mesh Identifier */
struct ieee80211_meshid_ie {
uint8_t id_ie; /* IEEE80211_ELEMID_MESHID */
uint8_t id_len;
} __packed;
/* Link Metric Report */
struct ieee80211_meshlmetric_ie {
uint8_t lm_ie; /* IEEE80211_ELEMID_MESHLINK */
uint8_t lm_len;
uint32_t lm_metric;
#define IEEE80211_MESHLMETRIC_INITIALVAL 0
} __packed;
/* Congestion Notification */
struct ieee80211_meshcngst_ie {
uint8_t cngst_ie; /* IEEE80211_ELEMID_MESHCNGST */
uint8_t cngst_len;
uint16_t cngst_timer[4]; /* Expiration Timers: AC_BK,
AC_BE, AC_VI, AC_VO */
} __packed;
/* Peer Version */
struct ieee80211_meshpeerver_ie {
uint8_t peerver_ie; /* IEEE80211_ELEMID_MESHPEERVER */
uint8_t peerver_len;
uint8_t peerver_proto[4];
} __packed;
/* Mesh Peering Management Protocol */
#define IEEE80211_MESHPEERVER_PEER_OUI 0x00, 0x0f, 0xac
#define IEEE80211_MESHPEERVER_PEER_VALUE 0x2a
#define IEEE80211_MESHPEERVER_PEER { IEEE80211_MESHPEERVER_PEER_OUI, \
IEEE80211_MESHPEERVER_PEER_VALUE }
/* Abbreviated Handshake Protocol */
#define IEEE80211_MESHPEERVER_AH_OUI 0x00, 0x0f, 0xac
#define IEEE80211_MESHPEERVER_AH_VALUE 0x2b
#define IEEE80211_MESHPEERVER_AH { IEEE80211_MESHPEERVER_AH_OUI, \
IEEE80211_MESHPEERVER_AH_VALUE }
/* Peer Link Management */
struct ieee80211_meshpeer_ie {
uint8_t peer_ie; /* IEEE80211_ELEMID_MESHPEER */
uint8_t peer_len;
uint8_t peer_subtype;
uint16_t peer_llinkid; /* Local Link ID */
uint16_t peer_linkid; /* Peer Link ID */
uint16_t peer_rcode;
} __packed;
enum {
IEEE80211_MESH_PEER_LINK_OPEN = 0,
IEEE80211_MESH_PEER_LINK_CONFIRM = 1,
IEEE80211_MESH_PEER_LINK_CLOSE = 2,
/* values 3-255 are reserved */
};
#ifdef notyet
/* Mesh Channel Switch Annoucement */
struct ieee80211_meshcsa_ie {
uint8_t csa_ie; /* IEEE80211_ELEMID_MESHCSA */
uint8_t csa_len;
uint8_t csa_mode;
uint8_t csa_newclass; /* New Regulatory Class */
uint8_t csa_newchan;
uint8_t csa_precvalue; /* Precedence Value */
uint8_t csa_count;
} __packed;
/* Mesh TIM */
/* Equal to the non Mesh version */
/* Mesh Awake Window */
struct ieee80211_meshawakew_ie {
uint8_t awakew_ie; /* IEEE80211_ELEMID_MESHAWAKEW */
uint8_t awakew_len;
uint8_t awakew_windowlen; /* in TUs */
} __packed;
/* Mesh Beacon Timing */
struct ieee80211_meshbeacont_ie {
uint8_t beacont_ie; /* IEEE80211_ELEMID_MESHBEACONT */
uint8_t beacont_len;
struct {
uint8_t mp_aid; /* Least Octet of AID */
uint16_t mp_btime; /* Beacon Time */
uint16_t mp_bint; /* Beacon Interval */
} __packed mp[1]; /* NB: variable size */
} __packed;
#endif
/* Portal (MP) Annoucement */
struct ieee80211_meshpann_ie {
uint8_t pann_ie; /* IEEE80211_ELEMID_MESHPANN */
uint8_t pann_len;
uint8_t pann_flags;
uint8_t pann_hopcount;
uint8_t pann_ttl;
uint8_t pann_addr[IEEE80211_ADDR_LEN];
uint8_t pann_seq; /* PANN Sequence Number */
} __packed;
/* Root (MP) Annoucement */
struct ieee80211_meshrann_ie {
uint8_t rann_ie; /* IEEE80211_ELEMID_MESHRANN */
uint8_t rann_len;
uint8_t rann_flags;
#define IEEE80211_MESHRANN_FLAGS_PR 0x01 /* Portal Role */
uint8_t rann_hopcount;
uint8_t rann_ttl;
uint8_t rann_addr[IEEE80211_ADDR_LEN];
uint32_t rann_seq; /* HWMP Sequence Number */
uint32_t rann_metric;
} __packed;
/* Mesh Path Request */
struct ieee80211_meshpreq_ie {
uint8_t preq_ie; /* IEEE80211_ELEMID_MESHPREQ */
uint8_t preq_len;
uint8_t preq_flags;
#define IEEE80211_MESHPREQ_FLAGS_PR 0x01 /* Portal Role */
#define IEEE80211_MESHPREQ_FLAGS_AM 0x02 /* 0 = ucast / 1 = bcast */
#define IEEE80211_MESHPREQ_FLAGS_PP 0x04 /* Proactive PREP */
#define IEEE80211_MESHPREQ_FLAGS_AE 0x40 /* Address Extension */
uint8_t preq_hopcount;
uint8_t preq_ttl;
uint32_t preq_id;
uint8_t preq_origaddr[IEEE80211_ADDR_LEN];
uint32_t preq_origseq; /* HWMP Sequence Number */
/* NB: may have Originator Proxied Address */
uint32_t preq_lifetime;
uint32_t preq_metric;
uint8_t preq_tcount; /* target count */
struct {
uint8_t target_flags;
#define IEEE80211_MESHPREQ_TFLAGS_TO 0x01 /* Target Only */
#define IEEE80211_MESHPREQ_TFLAGS_RF 0x02 /* Reply and Forward */
#define IEEE80211_MESHPREQ_TFLAGS_USN 0x04 /* Unknown HWMP seq number */
uint8_t target_addr[IEEE80211_ADDR_LEN];
uint32_t target_seq; /* HWMP Sequence Number */
} __packed preq_targets[1]; /* NB: variable size */
} __packed;
/* Mesh Path Reply */
struct ieee80211_meshprep_ie {
uint8_t prep_ie; /* IEEE80211_ELEMID_MESHPREP */
uint8_t prep_len;
uint8_t prep_flags;
uint8_t prep_hopcount;
uint8_t prep_ttl;
uint8_t prep_targetaddr[IEEE80211_ADDR_LEN];
uint32_t prep_targetseq;
/* NB: May have Target Proxied Address */
uint32_t prep_lifetime;
uint32_t prep_metric;
uint8_t prep_origaddr[IEEE80211_ADDR_LEN];
uint32_t prep_origseq; /* HWMP Sequence Number */
} __packed;
/* Mesh Path Error */
struct ieee80211_meshperr_ie {
uint8_t perr_ie; /* IEEE80211_ELEMID_MESHPERR */
uint8_t perr_len;
uint8_t perr_mode; /* NB: reserved */
uint8_t perr_ndests; /* Number of Destinations */
struct {
uint8_t dest_addr[IEEE80211_ADDR_LEN];
uint32_t dest_seq; /* HWMP Sequence Number */
} __packed perr_dests[1]; /* NB: variable size */
} __packed;
#ifdef notyet
/* Mesh Proxy Update */
struct ieee80211_meshpu_ie {
uint8_t pu_ie; /* IEEE80211_ELEMID_MESHPU */
uint8_t pu_len;
uint8_t pu_flags;
#define IEEE80211_MESHPU_FLAGS_MASK 0x1
#define IEEE80211_MESHPU_FLAGS_DEL 0x0
#define IEEE80211_MESHPU_FLAGS_ADD 0x1
uint8_t pu_seq; /* PU Sequence Number */
uint8_t pu_addr[IEEE80211_ADDR_LEN];
uint8_t pu_naddr; /* Number of Proxied Addresses */
/* NB: proxied address follows */
} __packed;
/* Mesh Proxy Update Confirmation */
struct ieee80211_meshpuc_ie {
uint8_t puc_ie; /* IEEE80211_ELEMID_MESHPUC */
uint8_t puc_len;
uint8_t puc_flags;
uint8_t puc_seq; /* PU Sequence Number */
uint8_t puc_daddr[IEEE80211_ADDR_LEN];
} __packed;
#endif
/*
* 802.11s Action Frames
*/
#define IEEE80211_ACTION_CAT_MESHPEERING 30 /* XXX Linux */
#define IEEE80211_ACTION_CAT_MESHLMETRIC 13
#define IEEE80211_ACTION_CAT_MESHPATH 32 /* XXX Linux */
#define IEEE80211_ACTION_CAT_INTERWORK 15
#define IEEE80211_ACTION_CAT_RESOURCE 16
#define IEEE80211_ACTION_CAT_PROXY 17
/*
* Mesh Peering Action codes.
*/
enum {
IEEE80211_ACTION_MESHPEERING_OPEN = 0,
IEEE80211_ACTION_MESHPEERING_CONFIRM = 1,
IEEE80211_ACTION_MESHPEERING_CLOSE = 2,
/* 3-255 reserved */
};
/*
* Mesh Path Selection Action codes.
*/
enum {
IEEE80211_ACTION_MESHPATH_REQ = 0,
IEEE80211_ACTION_MESHPATH_REP = 1,
IEEE80211_ACTION_MESHPATH_ERR = 2,
IEEE80211_ACTION_MESHPATH_RANN = 3,
/* 4-255 reserved */
};
/*
* Mesh Link Metric Action codes.
*/
enum {
IEEE80211_ACTION_MESHLMETRIC_REQ = 0, /* Link Metric Request */
IEEE80211_ACTION_MESHLMETRIC_REP = 1, /* Link Metric Report */
/* 2-255 reserved */
};
/*
* Mesh Portal Annoucement Action codes.
*/
enum {
IEEE80211_ACTION_MESHPANN = 0,
/* 1-255 reserved */
};
/*
* Different mesh control structures based on the AE
* (Address Extension) bits.
*/
struct ieee80211_meshcntl {
uint8_t mc_flags; /* Address Extension 00 */
uint8_t mc_ttl; /* TTL */
uint8_t mc_seq[4]; /* Sequence No. */
/* NB: more addresses may follow */
} __packed;
struct ieee80211_meshcntl_ae01 {
uint8_t mc_flags; /* Address Extension 01 */
uint8_t mc_ttl; /* TTL */
uint8_t mc_seq[4]; /* Sequence No. */
uint8_t mc_addr4[IEEE80211_ADDR_LEN];
} __packed;
struct ieee80211_meshcntl_ae10 {
uint8_t mc_flags; /* Address Extension 10 */
uint8_t mc_ttl; /* TTL */
uint8_t mc_seq[4]; /* Sequence No. */
uint8_t mc_addr5[IEEE80211_ADDR_LEN];
uint8_t mc_addr6[IEEE80211_ADDR_LEN];
} __packed;
struct ieee80211_meshcntl_ae11 {
uint8_t mc_flags; /* Address Extension 11 */
uint8_t mc_ttl; /* TTL */
uint8_t mc_seq[4]; /* Sequence No. */
uint8_t mc_addr4[IEEE80211_ADDR_LEN];
uint8_t mc_addr5[IEEE80211_ADDR_LEN];
uint8_t mc_addr6[IEEE80211_ADDR_LEN];
} __packed;
struct ieee80211req_mesh_route {
uint8_t imr_dest[IEEE80211_ADDR_LEN];
uint8_t imr_nexthop[IEEE80211_ADDR_LEN];
uint32_t imr_metric;
uint16_t imr_nhops;
uint32_t imr_lifetime;
};
#ifdef _KERNEL
MALLOC_DECLARE(M_80211_MESH_RT);
struct ieee80211_mesh_route {
TAILQ_ENTRY(ieee80211_mesh_route) rt_next;
uint8_t rt_dest[IEEE80211_ADDR_LEN];
uint8_t rt_nexthop[IEEE80211_ADDR_LEN];
uint32_t rt_metric; /* path metric */
uint16_t rt_nhops; /* number of hops */
uint32_t rt_lifetime;
uint32_t rt_lastmseq; /* last seq# seen dest */
void *rt_priv; /* private data */
};
#define IEEE80211_MESH_ROUTE_PRIV(rt, cast) ((cast *)rt->rt_priv)
#define IEEE80211_MESH_PROTO_DSZ 12 /* description size */
/*
* Mesh Path Selection Protocol.
*/
enum ieee80211_state;
struct ieee80211_mesh_proto_path {
char mpp_descr[IEEE80211_MESH_PROTO_DSZ];
uint8_t mpp_ie[4];
struct ieee80211_node *
(*mpp_discover)(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN],
struct mbuf *);
void (*mpp_peerdown)(struct ieee80211_node *);
void (*mpp_vattach)(struct ieee80211vap *);
void (*mpp_vdetach)(struct ieee80211vap *);
int (*mpp_newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
size_t mpp_privlen; /* size required in the routing table
for private data */
};
/*
* Mesh Link Metric Report Protocol.
*/
struct ieee80211_mesh_proto_metric {
char mpm_descr[IEEE80211_MESH_PROTO_DSZ];
uint8_t mpm_ie[4];
uint32_t (*mpm_metric)(struct ieee80211_node *);
};
#ifdef notyet
/*
* Mesh Authentication Protocol.
*/
struct ieee80211_mesh_proto_auth {
uint8_t mpa_ie[4];
};
struct ieee80211_mesh_proto_congestion {
};
struct ieee80211_mesh_proto_sync {
};
#endif
typedef uint32_t ieee80211_mesh_seq;
#define IEEE80211_MESH_SEQ_LEQ(a, b) ((int32_t)((a)-(b)) <= 0)
#define IEEE80211_MESH_SEQ_GEQ(a, b) ((int32_t)((a)-(b)) >= 0)
struct ieee80211_mesh_state {
int ms_idlen;
uint8_t ms_id[IEEE80211_MESHID_LEN];
ieee80211_mesh_seq ms_seq; /* seq no for meshcntl */
uint16_t ms_neighbors;
uint8_t ms_ttl; /* mesh ttl set in packets */
#define IEEE80211_MESHFLAGS_AP 0x01 /* accept peers */
#define IEEE80211_MESHFLAGS_PORTAL 0x02 /* mesh portal role */
#define IEEE80211_MESHFLAGS_FWD 0x04 /* forward packets */
uint8_t ms_flags;
struct mtx ms_rt_lock;
TAILQ_HEAD(, ieee80211_mesh_route) ms_routes;
struct ieee80211_mesh_proto_metric *ms_pmetric;
struct ieee80211_mesh_proto_path *ms_ppath;
};
void ieee80211_mesh_attach(struct ieee80211com *);
void ieee80211_mesh_detach(struct ieee80211com *);
struct ieee80211_mesh_route *
ieee80211_mesh_rt_find(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN]);
struct ieee80211_mesh_route *
ieee80211_mesh_rt_add(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN]);
void ieee80211_mesh_rt_del(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN]);
void ieee80211_mesh_rt_flush(struct ieee80211vap *);
int ieee80211_mesh_register_proto_path(const
struct ieee80211_mesh_proto_path *);
int ieee80211_mesh_register_proto_metric(const
struct ieee80211_mesh_proto_metric *);
uint8_t * ieee80211_add_meshpeerver(uint8_t *, struct ieee80211vap *);
uint8_t * ieee80211_add_meshid(uint8_t *, struct ieee80211vap *);
uint8_t * ieee80211_add_meshconf(uint8_t *, struct ieee80211vap *);
uint8_t * ieee80211_add_meshpeer(uint8_t *, uint8_t, uint16_t, uint16_t,
uint16_t);
uint8_t * ieee80211_add_meshlmetric(uint8_t *, uint32_t);
void ieee80211_mesh_node_init(struct ieee80211vap *,
struct ieee80211_node *);
void ieee80211_mesh_node_cleanup(struct ieee80211_node *);
void ieee80211_parse_meshid(struct ieee80211_node *,
const uint8_t *);
struct ieee80211_scanparams;
void ieee80211_mesh_init_neighbor(struct ieee80211_node *,
const struct ieee80211_frame *,
const struct ieee80211_scanparams *);
static __inline struct ieee80211_node *
ieee80211_mesh_discover(struct ieee80211vap *vap,
const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m)
{
struct ieee80211_mesh_state *ms = vap->iv_mesh;
return ms->ms_ppath->mpp_discover(vap, dest, m);
}
#endif /* _KERNEL */
#endif /* !_NET80211_IEEE80211_MESH_H_ */

View File

@ -50,9 +50,15 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_tdma.h>
#endif
#include <net80211/ieee80211_wds.h>
#include <net80211/ieee80211_mesh.h>
#include <net/bpf.h>
/*
* IEEE80211_NODE_HASHSIZE must be a power of 2.
*/
CTASSERT((IEEE80211_NODE_HASHSIZE & (IEEE80211_NODE_HASHSIZE-1)) == 0);
/*
* Association id's are managed with a bit vector.
*/
@ -322,7 +328,8 @@ ieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan)
struct ieee80211_node *ni;
IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
"%s: creating ibss on channel %u\n", __func__,
"%s: creating %s on channel %u\n", __func__,
ieee80211_opmode_name[vap->iv_opmode],
ieee80211_chan2ieee(ic, chan));
ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr);
@ -360,6 +367,11 @@ ieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan)
if ((vap->iv_caps & IEEE80211_C_TDMA) == 0)
#endif
memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN);
#ifdef IEEE80211_SUPPORT_MESH
} else if (vap->iv_opmode == IEEE80211_M_MBSS) {
ni->ni_meshidlen = vap->iv_mesh->ms_idlen;
memcpy(ni->ni_meshid, vap->iv_mesh->ms_id, ni->ni_meshidlen);
#endif
}
/*
* Fix the channel and related attributes.
@ -609,6 +621,7 @@ gethtadjustflags(struct ieee80211com *ic)
case IEEE80211_M_AHDEMO:
case IEEE80211_M_HOSTAP:
case IEEE80211_M_IBSS:
case IEEE80211_M_MBSS:
flags |= ieee80211_htchanflags(vap->iv_bss->ni_chan);
break;
default:
@ -784,6 +797,10 @@ ieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan,
ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie);
if (ni->ni_ies.htinfo_ie != NULL)
ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie);
#ifdef IEEE80211_SUPPORT_MESH
if (ni->ni_ies.meshid_ie != NULL)
ieee80211_parse_meshid(ni, ni->ni_ies.meshid_ie);
#endif
#ifdef IEEE80211_SUPPORT_TDMA
if (ni->ni_ies.tdma_ie != NULL)
ieee80211_parse_tdma(ni, ni->ni_ies.tdma_ie);
@ -914,6 +931,11 @@ ieee80211_ies_expand(struct ieee80211_ies *ies)
case IEEE80211_ELEMID_HTCAP:
ies->htcap_ie = ie;
break;
#ifdef IEEE80211_SUPPORT_MESH
case IEEE80211_ELEMID_MESHID:
ies->meshid_ie = ie;
break;
#endif
}
ielen -= 2 + ie[1];
ie += 2 + ie[1];
@ -950,6 +972,13 @@ node_cleanup(struct ieee80211_node *ni)
#ifdef IEEE80211_SUPPORT_SUPERG
else if (ni->ni_ath_flags & IEEE80211_NODE_ATH)
ieee80211_ff_node_cleanup(ni);
#endif
#ifdef IEEE80211_SUPPORT_MESH
/*
* Cleanup any mesh-related state.
*/
if (vap->iv_opmode == IEEE80211_M_MBSS)
ieee80211_mesh_node_cleanup(ni);
#endif
/*
* Clear any staging queue entries.
@ -1078,7 +1107,7 @@ ieee80211_alloc_node(struct ieee80211_node_table *nt,
ether_sprintf(macaddr), nt->nt_name);
IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
hash = IEEE80211_NODE_HASH(macaddr);
hash = IEEE80211_NODE_HASH(ic, macaddr);
ieee80211_node_initref(ni); /* mark referenced */
ni->ni_chan = IEEE80211_CHAN_ANYC;
ni->ni_authmode = IEEE80211_AUTH_OPEN;
@ -1090,7 +1119,10 @@ ieee80211_alloc_node(struct ieee80211_node_table *nt,
ni->ni_inact = ni->ni_inact_reload;
ni->ni_ath_defkeyix = 0x7fff;
ieee80211_psq_init(&ni->ni_psq, "unknown");
#ifdef IEEE80211_SUPPORT_MESH
if (vap->iv_opmode == IEEE80211_M_MBSS)
ieee80211_mesh_node_init(vap, ni);
#endif
IEEE80211_NODE_LOCK(nt);
TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list);
LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash);
@ -1242,7 +1274,7 @@ ieee80211_find_node_locked(struct ieee80211_node_table *nt,
IEEE80211_NODE_LOCK_ASSERT(nt);
hash = IEEE80211_NODE_HASH(macaddr);
hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr);
LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
ieee80211_ref_node(ni); /* mark referenced */
@ -1292,7 +1324,7 @@ ieee80211_find_vap_node_locked(struct ieee80211_node_table *nt,
IEEE80211_NODE_LOCK_ASSERT(nt);
hash = IEEE80211_NODE_HASH(macaddr);
hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr);
LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
if (ni->ni_vap == vap &&
IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
@ -1391,7 +1423,10 @@ ieee80211_init_neighbor(struct ieee80211_node *ni,
ni->ni_fhindex = sp->fhindex;
ni->ni_erp = sp->erp;
ni->ni_timoff = sp->timoff;
#ifdef IEEE80211_SUPPORT_MESH
if (ni->ni_vap->iv_opmode == IEEE80211_M_MBSS)
ieee80211_mesh_init_neighbor(ni, wh, sp);
#endif
if (ieee80211_ies_init(&ni->ni_ies, sp->ies, sp->ies_len)) {
ieee80211_ies_expand(&ni->ni_ies);
if (ni->ni_ies.wme_ie != NULL)
@ -2525,6 +2560,27 @@ get_adhoc_rssi(void *arg, struct ieee80211_node *ni)
}
}
#ifdef IEEE80211_SUPPORT_MESH
static void
get_mesh_rssi(void *arg, struct ieee80211_node *ni)
{
struct rssiinfo *info = arg;
struct ieee80211vap *vap = ni->ni_vap;
int8_t rssi;
if (info->vap != vap)
return;
/* only neighbors that peered successfully */
if (ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
return;
rssi = vap->iv_ic->ic_node_getrssi(ni);
if (rssi != 0) {
info->rssi_samples++;
info->rssi_total += rssi;
}
}
#endif /* IEEE80211_SUPPORT_MESH */
int8_t
ieee80211_getrssi(struct ieee80211vap *vap)
{
@ -2543,6 +2599,11 @@ ieee80211_getrssi(struct ieee80211vap *vap)
case IEEE80211_M_HOSTAP: /* average of all associated stations */
ieee80211_iterate_nodes(&ic->ic_sta, get_hostap_rssi, &info);
break;
#ifdef IEEE80211_SUPPORT_MESH
case IEEE80211_M_MBSS: /* average of all mesh neighbors */
ieee80211_iterate_nodes(&ic->ic_sta, get_mesh_rssi, &info);
break;
#endif
case IEEE80211_M_MONITOR: /* XXX */
case IEEE80211_M_STA: /* use stats from associated ap */
default:

View File

@ -35,7 +35,7 @@
* Each ieee80211com instance has a single timer that fires every
* IEEE80211_INACT_WAIT seconds to handle "inactivity processing".
* This is used to do node inactivity processing when operating
* as an AP or in adhoc mode. For inactivity processing each node
* as an AP, adhoc or mesh mode. For inactivity processing each node
* has a timeout set in it's ni_inact field that is decremented
* on each timeout and the node is reclaimed when the counter goes
* to zero. We use different inactivity timeout values depending
@ -56,9 +56,9 @@
/* threshold for aging overlapping non-ERP bss */
#define IEEE80211_NONERP_PRESENT_AGE msecs_to_ticks(60*1000)
#define IEEE80211_NODE_HASHSIZE 32
#define IEEE80211_NODE_HASHSIZE 32 /* NB: hash size must be pow2 */
/* simple hash is enough for variation of macaddr */
#define IEEE80211_NODE_HASH(addr) \
#define IEEE80211_NODE_HASH(ic, addr) \
(((const uint8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % \
IEEE80211_NODE_HASHSIZE)
@ -81,12 +81,27 @@ struct ieee80211_ies {
uint8_t *htcap_ie; /* captured HTCAP ie */
uint8_t *htinfo_ie; /* captured HTINFO ie */
uint8_t *tdma_ie; /* captured TDMA ie */
uint8_t *meshid_ie; /* captured MESH ID ie */
uint8_t *spare[4];
/* NB: these must be the last members of this structure */
uint8_t *data; /* frame data > 802.11 header */
int len; /* data size in bytes */
};
/*
* 802.11s (Mesh) Peer Link FSM state.
*/
enum ieee80211_mesh_mlstate {
IEEE80211_NODE_MESH_IDLE = 0,
IEEE80211_NODE_MESH_OPENSNT = 1, /* open frame sent */
IEEE80211_NODE_MESH_OPENRCV = 2, /* open frame received */
IEEE80211_NODE_MESH_CONFIRMRCV = 3, /* confirm frame received */
IEEE80211_NODE_MESH_ESTABLISHED = 4, /* link established */
IEEE80211_NODE_MESH_HOLDING = 5, /* link closing */
};
#define IEEE80211_MESH_MLSTATE_BITS \
"\20\1IDLE\2OPENSNT\2OPENRCV\3CONFIRMRCV\4ESTABLISHED\5HOLDING"
/*
* Node specific information. Note that drivers are expected
* to derive from this structure to add device-specific per-node
@ -173,6 +188,16 @@ struct ieee80211_node {
uint8_t ni_dtim_period; /* DTIM period */
uint8_t ni_dtim_count; /* DTIM count for last bcn */
/* 11s state */
uint8_t ni_meshidlen;
uint8_t ni_meshid[IEEE80211_MESHID_LEN];
enum ieee80211_mesh_mlstate ni_mlstate; /* peering management state */
uint16_t ni_mllid; /* link local ID */
uint16_t ni_mlpid; /* link peer ID */
struct callout ni_mltimer; /* link mesh timer */
uint8_t ni_mlrcnt; /* link mesh retry counter */
uint8_t ni_mltval; /* link mesh timer value */
/* 11n state */
uint16_t ni_htcap; /* HT capabilities */
uint8_t ni_htparam; /* HT params */

View File

@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_tdma.h>
#endif
#include <net80211/ieee80211_wds.h>
#include <net80211/ieee80211_mesh.h>
#ifdef INET
#include <netinet/in.h>
@ -71,6 +72,18 @@ __FBSDID("$FreeBSD$");
#define ETHER_HEADER_COPY(dst, src) \
memcpy(dst, src, sizeof(struct ether_header))
/* unalligned little endian access */
#define LE_WRITE_2(p, v) do { \
((uint8_t *)(p))[0] = (v) & 0xff; \
((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \
} while (0)
#define LE_WRITE_4(p, v) do { \
((uint8_t *)(p))[0] = (v) & 0xff; \
((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \
((uint8_t *)(p))[2] = ((v) >> 16) & 0xff; \
((uint8_t *)(p))[3] = ((v) >> 24) & 0xff; \
} while (0)
static int ieee80211_fragment(struct ieee80211vap *, struct mbuf *,
u_int hdrsize, u_int ciphdrsize, u_int mtu);
static void ieee80211_tx_mgt_cb(struct ieee80211_node *, void *, int);
@ -205,25 +218,42 @@ ieee80211_start(struct ifnet *ifp)
ieee80211_dwds_mcast(vap, m);
}
}
ni = ieee80211_find_txnode(vap, eh->ether_dhost);
if (ni == NULL) {
/* NB: ieee80211_find_txnode does stat+msg */
ifp->if_oerrors++;
m_freem(m);
continue;
}
if (ni->ni_associd == 0 &&
(ni->ni_flags & IEEE80211_NODE_ASSOCID)) {
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
eh->ether_dhost, NULL,
"sta not associated (type 0x%04x)",
htons(eh->ether_type));
vap->iv_stats.is_tx_notassoc++;
ifp->if_oerrors++;
m_freem(m);
ieee80211_free_node(ni);
continue;
#ifdef IEEE80211_SUPPORT_MESH
if (vap->iv_opmode != IEEE80211_M_MBSS) {
#endif
ni = ieee80211_find_txnode(vap, eh->ether_dhost);
if (ni == NULL) {
/* NB: ieee80211_find_txnode does stat+msg */
ifp->if_oerrors++;
m_freem(m);
continue;
}
if (ni->ni_associd == 0 &&
(ni->ni_flags & IEEE80211_NODE_ASSOCID)) {
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
eh->ether_dhost, NULL,
"sta not associated (type 0x%04x)",
htons(eh->ether_type));
vap->iv_stats.is_tx_notassoc++;
ifp->if_oerrors++;
m_freem(m);
ieee80211_free_node(ni);
continue;
}
#ifdef IEEE80211_SUPPORT_MESH
} else {
ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m);
if (ni == NULL) {
/*
* NB: ieee80211_mesh_discover function
* holds/disposes frame
* (e.g. queueing on path discovery).
*/
ifp->if_oerrors++;
continue;
}
}
#endif
if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
(m->m_flags & M_PWR_SAV) == 0) {
@ -455,7 +485,7 @@ bad:
* frame. Note this should be called early on in constructing
* a frame as it sets i_fc[1]; other bits can then be or'd in.
*/
static void
void
ieee80211_send_setup(
struct ieee80211_node *ni,
struct mbuf *m,
@ -465,13 +495,12 @@ ieee80211_send_setup(
const uint8_t bssid[IEEE80211_ADDR_LEN])
{
#define WH4(wh) ((struct ieee80211_frame_addr4 *)wh)
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
ieee80211_seq seqno;
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type;
if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
struct ieee80211vap *vap = ni->ni_vap;
switch (vap->iv_opmode) {
case IEEE80211_M_STA:
wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
@ -499,6 +528,25 @@ ieee80211_send_setup(
IEEE80211_ADDR_COPY(wh->i_addr3, da);
IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa);
break;
case IEEE80211_M_MBSS:
#ifdef IEEE80211_SUPPORT_MESH
/* XXX add support for proxied addresses */
if (IEEE80211_IS_MULTICAST(da)) {
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
/* XXX next hop */
IEEE80211_ADDR_COPY(wh->i_addr1, da);
IEEE80211_ADDR_COPY(wh->i_addr2,
vap->iv_myaddr);
} else {
wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
IEEE80211_ADDR_COPY(wh->i_addr1, da);
IEEE80211_ADDR_COPY(wh->i_addr2,
vap->iv_myaddr);
IEEE80211_ADDR_COPY(wh->i_addr3, da);
IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa);
}
#endif
break;
case IEEE80211_M_MONITOR: /* NB: to quiet compiler */
break;
}
@ -506,7 +554,12 @@ ieee80211_send_setup(
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
IEEE80211_ADDR_COPY(wh->i_addr1, da);
IEEE80211_ADDR_COPY(wh->i_addr2, sa);
IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
#ifdef IEEE80211_SUPPORT_MESH
if (vap->iv_opmode == IEEE80211_M_MBSS)
IEEE80211_ADDR_COPY(wh->i_addr3, sa);
else
#endif
IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
}
*(uint16_t *)&wh->i_dur[0] = 0;
@ -932,12 +985,18 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
{
#define WH4(wh) ((struct ieee80211_frame_addr4 *)(wh))
struct ieee80211com *ic = ni->ni_ic;
#ifdef IEEE80211_SUPPORT_MESH
struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211_meshcntl_ae11 *mc;
#endif
struct ether_header eh;
struct ieee80211_frame *wh;
struct ieee80211_key *key;
struct llc *llc;
int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr;
ieee80211_seq seqno;
int meshhdrsize, meshae;
uint8_t *qos;
/*
* Copy existing Ethernet header to a safe place. The
@ -990,17 +1049,56 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
hdrsize = sizeof(struct ieee80211_qosframe);
else
hdrsize = sizeof(struct ieee80211_frame);
/*
* 4-address frames need to be generated for:
* o packets sent through a WDS vap (IEEE80211_M_WDS)
* o packets sent through a vap marked for relaying
* (e.g. a station operating with dynamic WDS)
*/
is4addr = vap->iv_opmode == IEEE80211_M_WDS ||
((vap->iv_flags_ext & IEEE80211_FEXT_4ADDR) &&
!IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr));
if (is4addr)
hdrsize += IEEE80211_ADDR_LEN;
#ifdef IEEE80211_SUPPORT_MESH
if (vap->iv_opmode == IEEE80211_M_MBSS) {
/*
* Mesh data frames are encapsulated according to the
* rules of Section 11B.8.5 (p.139 of D3.0 spec).
* o Group Addressed data (aka multicast) originating
* at the local sta are sent w/ 3-address format and
* address extension mode 00
* o Individually Addressed data (aka unicast) originating
* at the local sta are sent w/ 4-address format and
* address extension mode 00
* o Group Addressed data forwarded from a non-mesh sta are
* sent w/ 3-address format and address extension mode 01
* o Individually Address data from another sta are sent
* w/ 4-address format and address extension mode 10
*/
is4addr = 0; /* NB: don't use, disable */
meshhdrsize = sizeof(struct ieee80211_meshcntl);
/* XXX defines for AE modes */
/* XXX not right, need to check if from non-mesh-sta */
if (IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) {
if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
hdrsize += IEEE80211_ADDR_LEN;
meshae = 0;
} else
meshae = 4; /* NB: pseudo */
} else if (IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
meshae = 1;
meshhdrsize += 2*IEEE80211_ADDR_LEN;
} else {
meshae = 2;
meshhdrsize += 3*IEEE80211_ADDR_LEN;
}
} else {
#endif
/*
* 4-address frames need to be generated for:
* o packets sent through a WDS vap (IEEE80211_M_WDS)
* o packets sent through a vap marked for relaying
* (e.g. a station operating with dynamic WDS)
*/
is4addr = vap->iv_opmode == IEEE80211_M_WDS ||
((vap->iv_flags_ext & IEEE80211_FEXT_4ADDR) &&
!IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr));
if (is4addr)
hdrsize += IEEE80211_ADDR_LEN;
meshhdrsize = meshae = 0;
#ifdef IEEE80211_SUPPORT_MESH
}
#endif
/*
* Honor driver DATAPAD requirement.
*/
@ -1013,7 +1111,7 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
/*
* Normal frame.
*/
m = ieee80211_mbuf_adjust(vap, hdrspace, key, m);
m = ieee80211_mbuf_adjust(vap, hdrspace + meshhdrsize, key, m);
if (m == NULL) {
/* NB: ieee80211_mbuf_adjust handles msgs+statistics */
goto bad;
@ -1032,14 +1130,14 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
/*
* Aggregated frame.
*/
m = ieee80211_ff_encap(vap, m, hdrspace, key);
m = ieee80211_ff_encap(vap, m, hdrspace + meshhdrsize, key);
if (m == NULL)
#endif
goto bad;
}
datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */
M_PREPEND(m, hdrspace, M_DONTWAIT);
M_PREPEND(m, hdrspace + meshhdrsize, M_DONTWAIT);
if (m == NULL) {
vap->iv_stats.is_tx_nobuf++;
goto bad;
@ -1047,6 +1145,7 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
wh = mtod(m, struct ieee80211_frame *);
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
*(uint16_t *)wh->i_dur = 0;
qos = NULL; /* NB: quiet compiler */
if (is4addr) {
wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
@ -1077,19 +1176,73 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid);
IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
break;
case IEEE80211_M_MONITOR:
#ifdef IEEE80211_SUPPORT_MESH
case IEEE80211_M_MBSS:
/* NB: offset by hdrspace to deal with DATAPAD */
mc = (struct ieee80211_meshcntl_ae11 *)
(mtod(m, uint8_t *) + hdrspace);
switch (meshae) {
case 0: /* ucast, no proxy */
wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost);
mc->mc_flags = 0;
qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
break;
case 4: /* mcast, no proxy */
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
mc->mc_flags = 0; /* NB: AE is really 0 */
qos = ((struct ieee80211_qosframe *) wh)->i_qos;
break;
case 1: /* mcast, proxy */
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
/* XXX not right, need MeshSA */
IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
mc->mc_flags = 1;
IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_shost);
qos = ((struct ieee80211_qosframe *) wh)->i_qos;
break;
case 2: /* ucast, proxy */
wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
/* XXX not right, need MeshDA+MeshSA */
IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost);
mc->mc_flags = 2;
IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_shost);
IEEE80211_ADDR_COPY(mc->mc_addr6, eh.ether_shost);
qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
break;
default:
KASSERT(0, ("meshae %d", meshae));
break;
}
mc->mc_ttl = ms->ms_ttl;
ms->ms_seq++;
LE_WRITE_4(mc->mc_seq, ms->ms_seq);
break;
#endif
case IEEE80211_M_WDS: /* NB: is4addr should always be true */
default:
goto bad;
}
if (m->m_flags & M_MORE_DATA)
wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
if (addqos) {
uint8_t *qos;
int ac, tid;
if (is4addr) {
qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
} else
/* NB: mesh case handled earlier */
} else if (vap->iv_opmode != IEEE80211_M_MBSS)
qos = ((struct ieee80211_qosframe *) wh)->i_qos;
ac = M_WME_GETAC(m);
/* map from access class/queue to 11e header priorty value */
@ -1125,6 +1278,7 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
M_SEQNO_SET(m, seqno);
}
/* check if xmit fragmentation is required */
txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold &&
!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
@ -1271,7 +1425,7 @@ bad:
/*
* Add a supported rates element id to a frame.
*/
static uint8_t *
uint8_t *
ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs)
{
int nrates;
@ -1288,7 +1442,7 @@ ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs)
/*
* Add an extended supported rates element id to a frame.
*/
static uint8_t *
uint8_t *
ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs)
{
/*
@ -1343,10 +1497,9 @@ ieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic)
static uint8_t *
ieee80211_add_cfparms(uint8_t *frm, struct ieee80211com *ic)
{
#define ADDSHORT(frm, v) do { \
frm[0] = (v) & 0xff; \
frm[1] = (v) >> 8; \
frm += 2; \
#define ADDSHORT(frm, v) do { \
LE_WRITE_2(frm, v); \
frm += 2; \
} while (0)
*frm++ = IEEE80211_ELEMID_CFPARMS;
*frm++ = 6;
@ -1399,10 +1552,9 @@ static uint8_t *
ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme)
{
#define SM(_v, _f) (((_v) << _f##_S) & _f)
#define ADDSHORT(frm, v) do { \
frm[0] = (v) & 0xff; \
frm[1] = (v) >> 8; \
frm += 2; \
#define ADDSHORT(frm, v) do { \
LE_WRITE_2(frm, v); \
frm += 2; \
} while (0)
/* NB: this works 'cuz a param has an info at the front */
static const struct ieee80211_wme_info param = {
@ -1649,8 +1801,8 @@ ieee80211_send_probereq(struct ieee80211_node *ni,
/*
* Calculate capability information for mgt frames.
*/
static uint16_t
getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan)
uint16_t
ieee80211_getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan)
{
struct ieee80211com *ic = vap->iv_ic;
uint16_t capinfo;
@ -1945,7 +2097,7 @@ ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg)
if (m == NULL)
senderr(ENOMEM, is_tx_nobuf);
capinfo = getcapinfo(vap, bss->ni_chan);
capinfo = ieee80211_getcapinfo(vap, bss->ni_chan);
*(uint16_t *)frm = htole16(capinfo);
frm += 2;
@ -2060,6 +2212,8 @@ ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
* [tlv] Vendor OUI HT information (optional)
* [tlv] Atheros capabilities
* [tlv] AppIE's (optional)
* [tlv] Mesh ID (MBSS)
* [tlv] Mesh Conf (MBSS)
*/
m = ieee80211_getmgtframe(&frm,
ic->ic_headroom + sizeof(struct ieee80211_frame),
@ -2083,6 +2237,10 @@ ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
+ 4 + sizeof(struct ieee80211_ie_htinfo)
#ifdef IEEE80211_SUPPORT_SUPERG
+ sizeof(struct ieee80211_ath_ie)
#endif
#ifdef IEEE80211_SUPPORT_MESH
+ 2 + IEEE80211_MESHID_LEN
+ sizeof(struct ieee80211_meshconf_ie)
#endif
+ (vap->iv_appie_proberesp != NULL ?
vap->iv_appie_proberesp->ie_len : 0)
@ -2096,7 +2254,7 @@ ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
frm += 8;
*(uint16_t *)frm = htole16(bss->ni_intval);
frm += 2;
capinfo = getcapinfo(vap, bss->ni_chan);
capinfo = ieee80211_getcapinfo(vap, bss->ni_chan);
*(uint16_t *)frm = htole16(capinfo);
frm += 2;
@ -2173,6 +2331,12 @@ ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
#endif
if (vap->iv_appie_proberesp != NULL)
frm = add_appie(frm, vap->iv_appie_proberesp);
#ifdef IEEE80211_SUPPORT_MESH
if (vap->iv_opmode == IEEE80211_M_MBSS) {
frm = ieee80211_add_meshid(frm, vap);
frm = ieee80211_add_meshconf(frm, vap);
}
#endif
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
return m;
@ -2365,6 +2529,8 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
* [tlv] Vendor OUI HT information (optional)
* [tlv] Atheros capabilities (optional)
* [tlv] TDMA parameters (optional)
* [tlv] Mesh ID (MBSS)
* [tlv] Mesh Conf (MBSS)
* [tlv] application data (optional)
*/
@ -2374,7 +2540,7 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
frm += 8;
*(uint16_t *)frm = htole16(ni->ni_intval);
frm += 2;
capinfo = getcapinfo(vap, ni->ni_chan);
capinfo = ieee80211_getcapinfo(vap, ni->ni_chan);
bo->bo_caps = (uint16_t *)frm;
*(uint16_t *)frm = htole16(capinfo);
frm += 2;
@ -2401,7 +2567,9 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
*frm++ = 2;
*frm++ = 0; *frm++ = 0; /* TODO: ATIM window */
bo->bo_tim_len = 0;
} else if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
} else if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
vap->iv_opmode == IEEE80211_M_MBSS) {
/* TIM IE is the same for Mesh and Hostap */
struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm;
tie->tim_ie = IEEE80211_ELEMID_TIM;
@ -2471,6 +2639,12 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
bo->bo_appie_len = vap->iv_appie_beacon->ie_len;
frm = add_appie(frm, vap->iv_appie_beacon);
}
#ifdef IEEE80211_SUPPORT_MESH
if (vap->iv_opmode == IEEE80211_M_MBSS) {
frm = ieee80211_add_meshid(frm, vap);
frm = ieee80211_add_meshconf(frm, vap);
}
#endif
bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer;
bo->bo_csa_trailer_len = frm - bo->bo_csa;
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
@ -2515,6 +2689,8 @@ ieee80211_beacon_alloc(struct ieee80211_node *ni,
* [tlv] WPA parameters
* [tlv] WME parameters
* [tlv] TDMA parameters (optional)
* [tlv] Mesh ID (MBSS)
* [tlv] Mesh Conf (MBSS)
* [tlv] application data (optional)
* NB: we allocate the max space required for the TIM bitmap.
* XXX how big is this?
@ -2545,6 +2721,10 @@ ieee80211_beacon_alloc(struct ieee80211_node *ni,
#ifdef IEEE80211_SUPPORT_TDMA
+ (vap->iv_caps & IEEE80211_C_TDMA ? /* TDMA */
sizeof(struct ieee80211_tdma_param) : 0)
#endif
#ifdef IEEE80211_SUPPORT_MESH
+ 2 + ni->ni_meshidlen
+ sizeof(struct ieee80211_meshconf_ie)
#endif
+ IEEE80211_MAX_APPIE
;
@ -2567,7 +2747,13 @@ ieee80211_beacon_alloc(struct ieee80211_node *ni,
*(uint16_t *)wh->i_dur = 0;
IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr);
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
#ifdef IEEE80211_SUPPORT_MESH
if (vap->iv_opmode == IEEE80211_M_MBSS) {
static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
IEEE80211_ADDR_COPY(wh->i_addr3, zerobssid);
} else
#endif
IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
*(uint16_t *)wh->i_seq = 0;
return m;
@ -2616,7 +2802,7 @@ ieee80211_beacon_update(struct ieee80211_node *ni,
}
/* XXX faster to recalculate entirely or just changes? */
capinfo = getcapinfo(vap, ni->ni_chan);
capinfo = ieee80211_getcapinfo(vap, ni->ni_chan);
*bo->bo_caps = htole16(capinfo);
if (vap->iv_flags & IEEE80211_F_WME) {
@ -2672,7 +2858,8 @@ ieee80211_beacon_update(struct ieee80211_node *ni,
ieee80211_tdma_update_beacon(vap, bo);
}
#endif
if (vap->iv_opmode == IEEE80211_M_HOSTAP) { /* NB: no IBSS support*/
if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
vap->iv_opmode == IEEE80211_M_MBSS) { /* NB: no IBSS support*/
struct ieee80211_tim_ie *tie =
(struct ieee80211_tim_ie *) bo->bo_tim;
if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) {

View File

@ -50,6 +50,9 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_sta.h>
#include <net80211/ieee80211_hostap.h>
#include <net80211/ieee80211_wds.h>
#ifdef IEEE80211_SUPPORT_MESH
#include <net80211/ieee80211_mesh.h>
#endif
#include <net80211/ieee80211_monitor.h>
#include <net80211/ieee80211_input.h>
@ -75,7 +78,8 @@ const char *ieee80211_opmode_name[IEEE80211_OPMODE_MAX] = {
"WDS", /* IEEE80211_M_WDS */
"AHDEMO", /* IEEE80211_M_AHDEMO */
"HOSTAP", /* IEEE80211_M_HOSTAP */
"MONITOR" /* IEEE80211_M_MONITOR */
"MONITOR", /* IEEE80211_M_MONITOR */
"MBSS" /* IEEE80211_M_MBSS */
};
const char *ieee80211_state_name[IEEE80211_S_MAX] = {
"INIT", /* IEEE80211_S_INIT */
@ -152,6 +156,9 @@ ieee80211_proto_attach(struct ieee80211com *ic)
ieee80211_sta_attach(ic);
ieee80211_wds_attach(ic);
ieee80211_hostap_attach(ic);
#ifdef IEEE80211_SUPPORT_MESH
ieee80211_mesh_attach(ic);
#endif
ieee80211_monitor_attach(ic);
}
@ -159,6 +166,9 @@ void
ieee80211_proto_detach(struct ieee80211com *ic)
{
ieee80211_monitor_detach(ic);
#ifdef IEEE80211_SUPPORT_MESH
ieee80211_mesh_detach(ic);
#endif
ieee80211_hostap_detach(ic);
ieee80211_wds_detach(ic);
ieee80211_adhoc_detach(ic);
@ -1456,7 +1466,8 @@ ieee80211_csa_startswitch(struct ieee80211com *ic,
ic->ic_flags |= IEEE80211_F_CSAPENDING;
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
vap->iv_opmode == IEEE80211_M_IBSS)
vap->iv_opmode == IEEE80211_M_IBSS ||
vap->iv_opmode == IEEE80211_M_MBSS)
ieee80211_beacon_notify(vap, IEEE80211_BEACON_CSA);
/* switch to CSA state to block outbound traffic */
if (vap->iv_state == IEEE80211_S_RUN)

View File

@ -71,6 +71,9 @@ int ieee80211_raw_xmit(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_bpf_params *);
int ieee80211_output(struct ifnet *, struct mbuf *,
struct sockaddr *, struct route *ro);
void ieee80211_send_setup(struct ieee80211_node *, struct mbuf *, int, int,
const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN],
const uint8_t [IEEE80211_ADDR_LEN]);
void ieee80211_start(struct ifnet *);
int ieee80211_send_nulldata(struct ieee80211_node *);
int ieee80211_classify(struct ieee80211_node *, struct mbuf *m);
@ -102,6 +105,11 @@ struct mbuf *ieee80211_alloc_rts(struct ieee80211com *ic,
struct mbuf *ieee80211_alloc_cts(struct ieee80211com *,
const uint8_t [IEEE80211_ADDR_LEN], uint16_t);
uint8_t *ieee80211_add_rates(uint8_t *, const struct ieee80211_rateset *);
uint8_t *ieee80211_add_xrates(uint8_t *, const struct ieee80211_rateset *);
uint16_t ieee80211_getcapinfo(struct ieee80211vap *,
struct ieee80211_channel *);
void ieee80211_reset_erp(struct ieee80211com *);
void ieee80211_set_shortslottime(struct ieee80211com *, int onoff);
int ieee80211_iserp_rateset(const struct ieee80211_rateset *);

View File

@ -209,6 +209,7 @@ static const char *scan_modnames[IEEE80211_OPMODE_MAX] = {
"wlan_scan_sta", /* IEEE80211_M_AHDEMO */
"wlan_scan_ap", /* IEEE80211_M_HOSTAP */
"wlan_scan_monitor", /* IEEE80211_M_MONITOR */
"wlan_scan_sta", /* IEEE80211_M_MBSS */
};
static const struct ieee80211_scanner *scanners[IEEE80211_OPMODE_MAX];

View File

@ -213,6 +213,8 @@ struct ieee80211_scanparams {
uint8_t *ath;
uint8_t *tdma;
uint8_t *csa;
uint8_t *meshid;
uint8_t *meshconf;
uint8_t *spare[3];
};
@ -242,6 +244,7 @@ struct ieee80211_scan_entry {
int8_t se_rssi; /* avg'd recv ssi */
int8_t se_noise; /* noise floor */
uint8_t se_cc[2]; /* captured country code */
uint8_t se_meshid[2+IEEE80211_MESHID_LEN];
struct ieee80211_ies se_ies; /* captured ie's */
u_int se_age; /* age of entry (0 on create) */
};

View File

@ -48,6 +48,9 @@ __FBSDID("$FreeBSD$");
#ifdef IEEE80211_SUPPORT_TDMA
#include <net80211/ieee80211_tdma.h>
#endif
#ifdef IEEE80211_SUPPORT_MESH
#include <net80211/ieee80211_mesh.h>
#endif
#include <net/bpf.h>
@ -112,21 +115,23 @@ static void sta_flush_table(struct sta_table *);
* contents explains why. The following flags are or'd to to this
* mask and can be used to figure out why the entry was rejected.
*/
#define MATCH_CHANNEL 0x0001 /* channel mismatch */
#define MATCH_CAPINFO 0x0002 /* capabilities mismatch, e.g. no ess */
#define MATCH_PRIVACY 0x0004 /* privacy mismatch */
#define MATCH_RATE 0x0008 /* rate set mismatch */
#define MATCH_SSID 0x0010 /* ssid mismatch */
#define MATCH_BSSID 0x0020 /* bssid mismatch */
#define MATCH_FAILS 0x0040 /* too many failed auth attempts */
#define MATCH_NOTSEEN 0x0080 /* not seen in recent scans */
#define MATCH_RSSI 0x0100 /* rssi deemed too low to use */
#define MATCH_CC 0x0200 /* country code mismatch */
#define MATCH_TDMA_NOIE 0x0400 /* no TDMA ie */
#define MATCH_TDMA_NOTMASTER 0x0800 /* not TDMA master */
#define MATCH_TDMA_NOSLOT 0x1000 /* all TDMA slots occupied */
#define MATCH_TDMA_LOCAL 0x2000 /* local address */
#define MATCH_TDMA_VERSION 0x4000 /* protocol version mismatch */
#define MATCH_CHANNEL 0x00001 /* channel mismatch */
#define MATCH_CAPINFO 0x00002 /* capabilities mismatch, e.g. no ess */
#define MATCH_PRIVACY 0x00004 /* privacy mismatch */
#define MATCH_RATE 0x00008 /* rate set mismatch */
#define MATCH_SSID 0x00010 /* ssid mismatch */
#define MATCH_BSSID 0x00020 /* bssid mismatch */
#define MATCH_FAILS 0x00040 /* too many failed auth attempts */
#define MATCH_NOTSEEN 0x00080 /* not seen in recent scans */
#define MATCH_RSSI 0x00100 /* rssi deemed too low to use */
#define MATCH_CC 0x00200 /* country code mismatch */
#define MATCH_TDMA_NOIE 0x00400 /* no TDMA ie */
#define MATCH_TDMA_NOTMASTER 0x00800 /* not TDMA master */
#define MATCH_TDMA_NOSLOT 0x01000 /* all TDMA slots occupied */
#define MATCH_TDMA_LOCAL 0x02000 /* local address */
#define MATCH_TDMA_VERSION 0x04000 /* protocol version mismatch */
#define MATCH_MESH_NOID 0x10000 /* no MESHID ie */
#define MATCH_MESHID 0x20000 /* meshid mismatch */
static int match_bss(struct ieee80211vap *,
const struct ieee80211_scan_state *, struct sta_entry *, int);
static void adhoc_age(struct ieee80211_scan_state *);
@ -139,6 +144,10 @@ isocmp(const uint8_t cc1[], const uint8_t cc2[])
/* number of references from net80211 layer */
static int nrefs = 0;
/*
* Module glue.
*/
IEEE80211_SCANNER_MODULE(sta, 1);
/*
* Attach prior to any scanning work.
@ -281,6 +290,10 @@ found:
memcpy(ise->se_tstamp.data, sp->tstamp, sizeof(ise->se_tstamp));
ise->se_intval = sp->bintval;
ise->se_capinfo = sp->capinfo;
#ifdef IEEE80211_SUPPORT_MESH
if (sp->meshid != NULL && sp->meshid[1] != 0)
memcpy(ise->se_meshid, sp->meshid, 2+sp->meshid[1]);
#endif
/*
* Beware of overriding se_chan for frames seen
* off-channel; this can cause us to attempt an
@ -895,6 +908,12 @@ back:
#undef RV
}
static __inline int
match_id(const uint8_t *ie, const uint8_t *val, int len)
{
return (ie[1] == len && memcmp(ie+2, val, len) == 0);
}
static int
match_ssid(const uint8_t *ie,
int nssid, const struct ieee80211_scan_ssid ssids[])
@ -902,8 +921,7 @@ match_ssid(const uint8_t *ie,
int i;
for (i = 0; i < nssid; i++) {
if (ie[1] == ssids[i].len &&
memcmp(ie+2, ssids[i].ssid, ie[1]) == 0)
if (match_id(ie, ssids[i].ssid, ssids[i].len))
return 1;
}
return 0;
@ -986,7 +1004,22 @@ match_bss(struct ieee80211vap *vap,
#endif
}
#endif /* IEEE80211_SUPPORT_TDMA */
#ifdef IEEE80211_SUPPORT_MESH
} else if (vap->iv_opmode == IEEE80211_M_MBSS) {
const struct ieee80211_mesh_state *ms = vap->iv_mesh;
/*
* Mesh nodes have IBSS & ESS bits in capinfo turned off
* and two special ie's that must be present.
*/
if (se->se_capinfo & (IEEE80211_CAPINFO_IBSS|IEEE80211_CAPINFO_ESS))
fail |= MATCH_CAPINFO;
else if (se->se_meshid == NULL)
fail |= MATCH_MESH_NOID;
else if (ms->ms_idlen != 0 &&
match_id(se->se_meshid, ms->ms_id, ms->ms_idlen))
fail |= MATCH_MESHID;
} else {
#endif
if ((se->se_capinfo & IEEE80211_CAPINFO_ESS) == 0)
fail |= MATCH_CAPINFO;
/*
@ -1070,6 +1103,7 @@ match_bss(struct ieee80211vap *vap,
fail & MATCH_TDMA_NOSLOT ? 'f' :
fail & MATCH_TDMA_LOCAL ? 'l' :
#endif
fail & MATCH_MESH_NOID ? 'm' :
fail ? '-' : '+', ether_sprintf(se->se_macaddr));
printf(" %s%c", ether_sprintf(se->se_bssid),
fail & MATCH_BSSID ? '!' : ' ');
@ -1087,7 +1121,7 @@ match_bss(struct ieee80211vap *vap,
"wep" : "no",
fail & MATCH_PRIVACY ? '!' : ' ');
ieee80211_print_essid(se->se_ssid+2, se->se_ssid[1]);
printf("%s\n", fail & MATCH_SSID ? "!" : "");
printf("%s\n", fail & (MATCH_SSID | MATCH_MESHID) ? "!" : "");
}
#endif
return fail;
@ -1415,6 +1449,7 @@ static const struct ieee80211_scanner sta_default = {
.scan_assoc_fail = sta_assoc_fail,
.scan_assoc_success = sta_assoc_success,
};
IEEE80211_SCANNER_ALG(sta, IEEE80211_M_STA, sta_default);
/*
* Adhoc mode-specific support.
@ -1514,7 +1549,8 @@ adhoc_pick_bss(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
struct ieee80211_channel *chan;
KASSERT(vap->iv_opmode == IEEE80211_M_IBSS ||
vap->iv_opmode == IEEE80211_M_AHDEMO,
vap->iv_opmode == IEEE80211_M_AHDEMO ||
vap->iv_opmode == IEEE80211_M_MBSS,
("wrong opmode %u", vap->iv_opmode));
if (st->st_newscan) {
@ -1630,6 +1666,8 @@ static const struct ieee80211_scanner adhoc_default = {
.scan_assoc_fail = sta_assoc_fail,
.scan_assoc_success = sta_assoc_success,
};
IEEE80211_SCANNER_ALG(ibss, IEEE80211_M_IBSS, adhoc_default);
IEEE80211_SCANNER_ALG(ahdemo, IEEE80211_M_AHDEMO, adhoc_default);
static void
ap_force_promisc(struct ieee80211com *ic)
@ -1781,12 +1819,108 @@ static const struct ieee80211_scanner ap_default = {
.scan_assoc_success = sta_assoc_success,
.scan_assoc_fail = sta_assoc_fail,
};
/*
* Module glue.
*/
IEEE80211_SCANNER_MODULE(sta, 1);
IEEE80211_SCANNER_ALG(sta, IEEE80211_M_STA, sta_default);
IEEE80211_SCANNER_ALG(ibss, IEEE80211_M_IBSS, adhoc_default);
IEEE80211_SCANNER_ALG(ahdemo, IEEE80211_M_AHDEMO, adhoc_default);
IEEE80211_SCANNER_ALG(ap, IEEE80211_M_HOSTAP, ap_default);
#ifdef IEEE80211_SUPPORT_MESH
/*
* Pick an mbss network to join or find a channel
* to use to start an mbss network.
*/
static int
mesh_pick_bss(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
{
struct sta_table *st = ss->ss_priv;
struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct sta_entry *selbs;
struct ieee80211_channel *chan;
KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
("wrong opmode %u", vap->iv_opmode));
if (st->st_newscan) {
sta_update_notseen(st);
st->st_newscan = 0;
}
if (ss->ss_flags & IEEE80211_SCAN_NOPICK) {
/*
* Manual/background scan, don't select+join the
* bss, just return. The scanning framework will
* handle notification that this has completed.
*/
ss->ss_flags &= ~IEEE80211_SCAN_NOPICK;
return 1;
}
/*
* Automatic sequencing; look for a candidate and
* if found join the network.
*/
/* NB: unlocked read should be ok */
if (TAILQ_FIRST(&st->st_entry) == NULL) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
"%s: no scan candidate\n", __func__);
if (ss->ss_flags & IEEE80211_SCAN_NOJOIN)
return 0;
notfound:
if (ms->ms_idlen != 0) {
/*
* No existing mbss network to join and we have
* a meshid; start one up. If no channel was
* specified, try to select a channel.
*/
if (vap->iv_des_chan == IEEE80211_CHAN_ANYC ||
IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan)) {
struct ieee80211com *ic = vap->iv_ic;
chan = adhoc_pick_channel(ss, 0);
if (chan != NULL)
chan = ieee80211_ht_adjust_channel(ic,
chan, vap->iv_flags_ht);
} else
chan = vap->iv_des_chan;
if (chan != NULL) {
ieee80211_create_ibss(vap, chan);
return 1;
}
}
/*
* If nothing suitable was found decrement
* the failure counts so entries will be
* reconsidered the next time around. We
* really want to do this only for sta's
* where we've previously had some success.
*/
sta_dec_fails(st);
st->st_newscan = 1;
return 0; /* restart scan */
}
selbs = select_bss(ss, vap, IEEE80211_MSG_SCAN);
if (ss->ss_flags & IEEE80211_SCAN_NOJOIN)
return (selbs != NULL);
if (selbs == NULL)
goto notfound;
chan = selbs->base.se_chan;
if (selbs->se_flags & STA_DEMOTE11B)
chan = demote11b(vap, chan);
if (!ieee80211_sta_join(vap, chan, &selbs->base))
goto notfound;
return 1; /* terminate scan */
}
static const struct ieee80211_scanner mesh_default = {
.scan_name = "default",
.scan_attach = sta_attach,
.scan_detach = sta_detach,
.scan_start = adhoc_start,
.scan_restart = sta_restart,
.scan_cancel = sta_cancel,
.scan_end = mesh_pick_bss,
.scan_flush = sta_flush,
.scan_pickchan = adhoc_pick_channel,
.scan_add = sta_add,
.scan_age = adhoc_age,
.scan_iterate = sta_iterate,
.scan_assoc_fail = sta_assoc_fail,
.scan_assoc_success = sta_assoc_success,
};
IEEE80211_SCANNER_ALG(mesh, IEEE80211_M_MBSS, mesh_default);
#endif /* IEEE80211_SUPPORT_MESH */

View File

@ -318,6 +318,8 @@ struct ieee80211com {
struct ieee80211_aclator;
struct ieee80211_tdma_state;
struct ieee80211_mesh_state;
struct ieee80211_hwmp_state;
struct ieee80211vap {
struct ifmedia iv_media; /* interface media config */
@ -432,6 +434,8 @@ struct ieee80211vap {
void *iv_as; /* private aclator state */
struct ieee80211_tdma_state *iv_tdma; /* tdma state */
struct ieee80211_mesh_state *iv_mesh; /* MBSS state */
struct ieee80211_hwmp_state *iv_hwmp; /* HWMP state */
/* operate-mode detach hook */
void (*iv_opdetach)(struct ieee80211vap *);
@ -588,6 +592,7 @@ MALLOC_DECLARE(M_80211_VAP);
#define IEEE80211_C_SHPREAMBLE 0x00008000 /* CAPABILITY: short preamble */
#define IEEE80211_C_MONITOR 0x00010000 /* CAPABILITY: monitor mode */
#define IEEE80211_C_DFS 0x00020000 /* CAPABILITY: DFS/radar avail*/
#define IEEE80211_C_MBSS 0x00040000 /* CAPABILITY: MBSS available */
/* 0x7c0000 available */
#define IEEE80211_C_WPA1 0x00800000 /* CAPABILITY: WPA1 avail */
#define IEEE80211_C_WPA2 0x01000000 /* CAPABILITY: WPA2 avail */
@ -604,12 +609,12 @@ MALLOC_DECLARE(M_80211_VAP);
#define IEEE80211_C_OPMODE \
(IEEE80211_C_STA | IEEE80211_C_IBSS | IEEE80211_C_HOSTAP | \
IEEE80211_C_AHDEMO | IEEE80211_C_MONITOR | IEEE80211_C_WDS | \
IEEE80211_C_TDMA)
IEEE80211_C_TDMA | IEEE80211_C_MBSS)
#define IEEE80211_C_BITS \
"\20\1STA\002803ENCAP\7FF\10TURBOP\11IBSS\12PMGT" \
"\13HOSTAP\14AHDEMO\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE" \
"\21MONITOR\22DFS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \
"\21MONITOR\22DFS\23MBSS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \
"\37TXFRAG\40TDMA"
/*
@ -783,7 +788,7 @@ ieee80211_htchanflags(const struct ieee80211_channel *c)
* program) and/or the msgs generated by net80211. Messages are
* broken into functional classes and can be controlled with the
* wlandebug program. Certain of these msg groups are for facilities
* that are no longer part of net80211 (e.g. IEEE80211_MSG_DOT1X).
* that are no longer part of net80211 (e.g. IEEE80211_MSG_DOT1XSM).
*/
#define IEEE80211_MSG_11N 0x80000000 /* 11n mode debug */
#define IEEE80211_MSG_DEBUG 0x40000000 /* IFF_DEBUG equivalent */
@ -799,7 +804,7 @@ ieee80211_htchanflags(const struct ieee80211_channel *c)
#define IEEE80211_MSG_OUTPUT 0x00100000 /* output handling */
#define IEEE80211_MSG_STATE 0x00080000 /* state machine */
#define IEEE80211_MSG_POWER 0x00040000 /* power save handling */
#define IEEE80211_MSG_DOT1X 0x00020000 /* 802.1x authenticator */
#define IEEE80211_MSG_HWMP 0x00020000 /* hybrid mesh protocol */
#define IEEE80211_MSG_DOT1XSM 0x00010000 /* 802.1x state machine */
#define IEEE80211_MSG_RADIUS 0x00008000 /* 802.1x radius client */
#define IEEE80211_MSG_RADDUMP 0x00004000 /* dump 802.1x radius packets */
@ -821,7 +826,7 @@ ieee80211_htchanflags(const struct ieee80211_channel *c)
#define IEEE80211_MSG_BITS \
"\20\2TDMA\3IOCTL\4WDS\5ACTION\6RATECTL\7ROAM\10INACT\11DOTH\12SUPERG" \
"\13WME\14ACL\15WPA\16RADKEYS\17RADDUMP\20RADIUS\21DOT1XSM\22DOT1X" \
"\13WME\14ACL\15WPA\16RADKEYS\17RADDUMP\20RADIUS\21DOT1XSM\22HWMP" \
"\23POWER\24STATE\25OUTPUT\26SCAN\27AUTH\30ASSOC\31NODE\32ELEMID" \
"\33XRATE\34INPUT\35CRYPTO\36DUPMPKTS\37DEBUG\04011N"

View File

@ -223,6 +223,7 @@ device xe # Xircom pccard Ethernet
#device wlan # 802.11 support
#options IEEE80211_DEBUG # enable debug msgs
#options IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's
#options IEEE80211_SUPPORT_MESH # enable 802.11s D3.0 support
#device wlan_wep # 802.11 WEP support
#device wlan_ccmp # 802.11 CCMP support
#device wlan_tkip # 802.11 TKIP support

View File

@ -201,6 +201,7 @@ device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'')
device wlan # 802.11 support
options IEEE80211_DEBUG # enable debug msgs
options IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's
options IEEE80211_SUPPORT_MESH # enable 802.11s D3.0 support
device wlan_wep # 802.11 WEP support
device wlan_ccmp # 802.11 CCMP support
device wlan_tkip # 802.11 TKIP support

View File

@ -93,6 +93,7 @@ device random # Entropy device
device wlan # 802.11 support
options IEEE80211_DEBUG # enable debugging msgs
options IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's
options IEEE80211_SUPPORT_MESH
options IEEE80211_SUPPORT_TDMA
device wlan_wep # 802.11 WEP support
device wlan_ccmp # 802.11 CCMP support

View File

@ -94,6 +94,7 @@ device random # Entropy device
device wlan # 802.11 support
options IEEE80211_DEBUG # enable debugging msgs
options IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's
options IEEE80211_SUPPORT_MESH
options IEEE80211_SUPPORT_TDMA
device wlan_wep # 802.11 WEP support
device wlan_ccmp # 802.11 CCMP support

View File

@ -49,6 +49,9 @@ test -z "$WPA_PASSPHRASE" && WPA_PASSPHRASE='I am not a geek'
# default ssid for ap vaps
test -z "$SSID" && SSID=freebsd-ap
# default meshid for mesh vaps
test -z "$MESHID" && MESHID=freebsd-mesh
# directory to create files like hostapd.conf
test -z "$TMPDIR" && TMPDIR=.

View File

@ -0,0 +1,13 @@
#! /bin/sh
#
# Common setup.
#
# $FreeBSD$
#
PATH=../:.:$PATH
. config
. config.mesh
WLAN=`ifconfig wlan create wlanmode mesh wlandev $WIRELESS`
ifconfig $WLAN meshid $MESHID channel $CHANNEL mtu 1500
wlandebug -i $WLAN mesh+hwmp+state+scan+assoc

View File

@ -0,0 +1,17 @@
#
# Common configuration settings for mesh test scripts.
#
# $FreeBSD$
#
NODE1_IP=10.0.1.100
NODE2_IP=10.0.1.101
NODE3_IP=10.0.1.102
NODE4_IP=10.0.1.103
NODE5_IP=10.0.1.104
NODE1_MAC=00:0b:6b:2d:dc:d8
NODE2_MAC=00:0b:6b:2d:db:ac
NODE3_MAC=00:0b:6b:2d:dd:17
NODE4_MAC=00:0b:6b:87:1c:f0
NODE5_MAC=00:14:a5:33:33:a7

View File

@ -0,0 +1,13 @@
#! /bin/sh
#
# Script for creating a simple Mesh Point.
# Topology is fully connected if every node is a neighbor of each other.
#
# $FreeBSD$
#
PATH=../:.:$PATH
. config
. config.mesh
. common
ifconfig $WLAN up

View File

@ -0,0 +1,38 @@
#! /bin/sh
#
# Script for creating a mesh in line topology.
#
# node1 <-> node2 <-> node3 <-> node4 <-> node5
#
# $FreeBSD$
#
PATH=../:.:$PATH
. config
. config.mesh
. common
ifconfig $WLAN mac:allow
MAC=`ifconfig $WLAN | grep ether | awk '{ print $2 }'`
case $MAC in
$NODE1_MAC)
ifconfig $WLAN inet $NODE1_IP
ifconfig $WLAN mac:add $NODE2_MAC
;;
$NODE2_MAC)
ifconfig $WLAN inet $NODE2_IP
ifconfig $WLAN mac:add $NODE1_MAC mac:add $NODE3_MAC
;;
$NODE3_MAC)
ifconfig $WLAN inet $NODE3_IP
ifconfig $WLAN mac:add $NODE2_MAC mac:add $NODE4_MAC
;;
$NODE4_MAC)
ifconfig $WLAN inet $NODE4_IP
ifconfig $WLAN mac:add $NODE3_MAC mac:add $NODE5_MAC
;;
$NODE5_MAC)
ifconfig $WLAN inet $NODE5_IP
ifconfig $WLAN mac:add $NODE4_MAC
;;
esac
ifconfig $WLAN up

View File

@ -0,0 +1,40 @@
#! /bin/sh
#
# Script for creating a mesh in ring topology.
#
# node1 - node2 - node3 - node4 - node5
# ^ |
# \-------------------------------
#
# $FreeBSD$
#
PATH=../:.:$PATH
. config
. config.mesh
. common
ifconfig $WLAN mac:allow
MAC=`ifconfig $WLAN | grep ether | awk '{ print $2 }'`
case $MAC in
$NODE1_MAC)
ifconfig $WLAN inet $NODE1_IP
ifconfig $WLAN mac:add $NODE2_MAC mac:add $NODE5_MAC
;;
$NODE2_MAC)
ifconfig $WLAN inet $NODE2_IP
ifconfig $WLAN mac:add $NODE1_MAC mac:add $NODE3_MAC
;;
$NODE3_MAC)
ifconfig $WLAN inet $NODE3_IP
ifconfig $WLAN mac:add $NODE2_MAC mac:add $NODE4_MAC
;;
$NODE4_MAC)
ifconfig $WLAN inet $NODE4_IP
ifconfig $WLAN mac:add $NODE3_MAC mac:add $NODE5_MAC
;;
$NODE5_MAC)
ifconfig $WLAN inet $NODE5_IP
ifconfig $WLAN mac:add $NODE1_MAC mac:add $NODE4_MAC
;;
esac
ifconfig $WLAN up

View File

@ -0,0 +1,38 @@
#! /bin/sh
#
# Script for creating a mesh in star topology.
# Node 3 will be the center.
#
# $FreeBSD$
#
PATH=../:.:$PATH
. config
. config.mesh
. common
ifconfig $WLAN mac:allow
MAC=`ifconfig $WLAN | grep ether | awk '{ print $2 }'`
case $MAC in
$NODE1_MAC)
ifconfig $WLAN inet $NODE1_IP
ifconfig $WLAN mac:add $NODE3_MAC
;;
$NODE2_MAC)
ifconfig $WLAN inet $NODE2_IP
ifconfig $WLAN mac:add $NODE3_MAC
;;
$NODE3_MAC)
ifconfig $WLAN inet $NODE3_IP
ifconfig $WLAN mac:add $NODE1_MAC mac:add $NODE2_MAC mac:add \
$NODE4_MAC mac:add $NODE5_MAC
;;
$NODE4_MAC)
ifconfig $WLAN inet $NODE4_IP
ifconfig $WLAN mac:add $NODE3_MAC
;;
$NODE5_MAC)
ifconfig $WLAN inet $NODE5_IP
ifconfig $WLAN mac:add $NODE3_MAC
;;
esac
ifconfig $WLAN up

View File

@ -0,0 +1,47 @@
#! /bin/sh
#
# Script for creating a mesh in tree (hirearchical) topology.
#
# node1
# ^
# |
# / \
# v v
# node2 node3
# ^ ^
# | |
# v v
# node4 node5
#
# $FreeBSD$
#
PATH=../:.:$PATH
. config
. config.mesh
. common
ifconfig $WLAN mac:allow
MAC=`ifconfig $WLAN | grep ether | awk '{ print $2 }'`
case $MAC in
$NODE1_MAC)
ifconfig $WLAN inet $NODE1_IP
ifconfig $WLAN mac:add $NODE2_MAC mac:add $NODE3_MAC
;;
$NODE2_MAC)
ifconfig $WLAN inet $NODE2_IP
ifconfig $WLAN mac:add $NODE1_MAC mac:add $NODE4_MAC
;;
$NODE3_MAC)
ifconfig $WLAN inet $NODE3_IP
ifconfig $WLAN mac:add $NODE1_MAC mac:add $NODE5_MAC
;;
$NODE4_MAC)
ifconfig $WLAN inet $NODE4_IP
ifconfig $WLAN mac:add $NODE2_MAC
;;
$NODE5_MAC)
ifconfig $WLAN inet $NODE5_IP
ifconfig $WLAN mac:add $NODE3_MAC
;;
esac
ifconfig $WLAN up

View File

@ -322,7 +322,27 @@ static const struct fmt wlanstats[] = {
{ 4, "ht_downgrade", "ht_downgrade", "HT station downgraded to legacy operation" },
#define S_HT_ASSOC_NORATE AFTER(S_HT_ASSOC_DOWNGRADE)
{ 4, "ht_norate", "ht_norate", "HT station rejected because of HT rate set" },
#define S_INPUT AFTER(S_HT_ASSOC_NORATE)
#define S_MESH_WRONGMESH AFTER(S_HT_ASSOC_NORATE)
{ 4, "mesh_wrong", "mesh_wrong", "frame discarded because sender not a mesh sta" },
#define S_MESH_NOLINK AFTER(S_MESH_WRONGMESH)
{ 4, "mesh_nolink", "mesh_nolink", "frame discarded because link not established" },
#define S_MESH_FWD_TTL AFTER(S_MESH_NOLINK)
{ 4, "mesh_fwd_ttl", "mesh_fwd_ttl", "frame not forwarded because TTL zero" },
#define S_MESH_FWD_NOBUF AFTER(S_MESH_FWD_TTL)
{ 4, "mesh_fwd_nobuf", "mesh_fwd_nobuf", "frame not forwarded because mbuf could not be allocated" },
#define S_MESH_FWD_TOOSHORT AFTER(S_MESH_FWD_NOBUF)
{ 4, "mesh_fwd_tooshort", "mesh_fwd_tooshort", "frame not forwarded because too short to have 802.11 header" },
#define S_MESH_FWD_DISABLED AFTER(S_MESH_FWD_TOOSHORT)
{ 4, "mesh_fwd_disabled", "mesh_fwd_disabled", "frame not forwarded because administratively disabled" },
#define S_MESH_FWD_NOPATH AFTER(S_MESH_FWD_DISABLED)
{ 4, "mesh_fwd_nopath", "mesh_fwd_nopath", "frame not forwarded because no path found to destination" },
#define S_HWMP_WRONGSEQ AFTER(S_MESH_FWD_NOPATH)
{ 4, "hwmp_wrongseq", "hwmp_wrongseq", "frame discarded because mesh sequence number is invalid" },
#define S_HWMP_ROOTREQS AFTER(S_HWMP_WRONGSEQ)
{ 4, "hwmp_rootreqs", "hwmp_rootreqs", "root PREQ frames sent" },
#define S_HWMP_ROOTANN AFTER(S_HWMP_ROOTREQS)
{ 4, "hwmp_rootann", "hwmp_rootann", "root RANN frames received" },
#define S_INPUT AFTER(S_HWMP_ROOTANN)
{ 8, "input", "input", "total data frames received" },
#define S_RX_UCAST AFTER(S_INPUT)
{ 8, "rx_ucast", "rx_ucast", "unicast data frames received" },
@ -766,6 +786,16 @@ wlan_get_curstat(struct statfoo *sf, int s, char b[], size_t bs)
case S_HT_ASSOC_NOHTCAP:STAT(ht_assoc_nohtcap);
case S_HT_ASSOC_DOWNGRADE:STAT(ht_assoc_downgrade);
case S_HT_ASSOC_NORATE: STAT(ht_assoc_norate);
case S_MESH_WRONGMESH: STAT(mesh_wrongmesh);
case S_MESH_NOLINK: STAT(mesh_nolink);
case S_MESH_FWD_TTL: STAT(mesh_fwd_ttl);
case S_MESH_FWD_NOBUF: STAT(mesh_fwd_nobuf);
case S_MESH_FWD_TOOSHORT: STAT(mesh_fwd_tooshort);
case S_MESH_FWD_DISABLED: STAT(mesh_fwd_disabled);
case S_MESH_FWD_NOPATH: STAT(mesh_fwd_nopath);
case S_HWMP_WRONGSEQ: STAT(hwmp_wrongseq);
case S_HWMP_ROOTREQS: STAT(hwmp_rootreqs);
case S_HWMP_ROOTANN: STAT(hwmp_rootrann);
case S_INPUT: NSTAT(rx_data);
case S_OUTPUT: NSTAT(tx_data);
case S_RX_UCAST: NSTAT(rx_ucast);
@ -910,6 +940,16 @@ wlan_get_totstat(struct statfoo *sf, int s, char b[], size_t bs)
case S_HT_ASSOC_NOHTCAP:STAT(ht_assoc_nohtcap);
case S_HT_ASSOC_DOWNGRADE:STAT(ht_assoc_downgrade);
case S_HT_ASSOC_NORATE: STAT(ht_assoc_norate);
case S_MESH_WRONGMESH: STAT(mesh_wrongmesh);
case S_MESH_NOLINK: STAT(mesh_nolink);
case S_MESH_FWD_TTL: STAT(mesh_fwd_ttl);
case S_MESH_FWD_NOBUF: STAT(mesh_fwd_nobuf);
case S_MESH_FWD_TOOSHORT: STAT(mesh_fwd_tooshort);
case S_MESH_FWD_DISABLED: STAT(mesh_fwd_disabled);
case S_MESH_FWD_NOPATH: STAT(mesh_fwd_nopath);
case S_HWMP_WRONGSEQ: STAT(hwmp_wrongseq);
case S_HWMP_ROOTREQS: STAT(hwmp_rootreqs);
case S_HWMP_ROOTANN: STAT(hwmp_rootrann);
case S_INPUT: NSTAT(rx_data);
case S_OUTPUT: NSTAT(tx_data);
case S_RX_UCAST: NSTAT(rx_ucast);